1cb93a386Sopenharmony_ci/*
2cb93a386Sopenharmony_ci * Copyright 2019 Google Inc.
3cb93a386Sopenharmony_ci *
4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be
5cb93a386Sopenharmony_ci * found in the LICENSE file.
6cb93a386Sopenharmony_ci */
7cb93a386Sopenharmony_ci
8cb93a386Sopenharmony_ci#include "include/private/SkTFitsIn.h"
9cb93a386Sopenharmony_ci#include "src/utils/SkCharToGlyphCache.h"
10cb93a386Sopenharmony_ci
11cb93a386Sopenharmony_ciSkCharToGlyphCache::SkCharToGlyphCache() {
12cb93a386Sopenharmony_ci    this->reset();
13cb93a386Sopenharmony_ci}
14cb93a386Sopenharmony_ci
15cb93a386Sopenharmony_ciSkCharToGlyphCache::~SkCharToGlyphCache() {}
16cb93a386Sopenharmony_ci
17cb93a386Sopenharmony_civoid SkCharToGlyphCache::reset() {
18cb93a386Sopenharmony_ci    fK32.reset();
19cb93a386Sopenharmony_ci    fV16.reset();
20cb93a386Sopenharmony_ci
21cb93a386Sopenharmony_ci    // Add sentinels so we can always rely on these to stop linear searches (in either direction)
22cb93a386Sopenharmony_ci    // Neither is a legal unichar, so we don't care what glyphID we use.
23cb93a386Sopenharmony_ci    //
24cb93a386Sopenharmony_ci    *fK32.append() = 0x80000000;    *fV16.append() = 0;
25cb93a386Sopenharmony_ci    *fK32.append() = 0x7FFFFFFF;    *fV16.append() = 0;
26cb93a386Sopenharmony_ci
27cb93a386Sopenharmony_ci    fDenom = 0;
28cb93a386Sopenharmony_ci}
29cb93a386Sopenharmony_ci
30cb93a386Sopenharmony_ci// Determined experimentally. For N much larger, the slope technique is faster.
31cb93a386Sopenharmony_ci// For N much smaller, a simple search is faster.
32cb93a386Sopenharmony_ci//
33cb93a386Sopenharmony_ciconstexpr int kSmallCountLimit = 16;
34cb93a386Sopenharmony_ci
35cb93a386Sopenharmony_ci// To use slope technique we need at least 2 real entries (+2 sentinels) hence the min of 4
36cb93a386Sopenharmony_ci//
37cb93a386Sopenharmony_ciconstexpr int kMinCountForSlope = 4;
38cb93a386Sopenharmony_ci
39cb93a386Sopenharmony_cistatic int find_simple(const SkUnichar base[], int count, SkUnichar value) {
40cb93a386Sopenharmony_ci    int index;
41cb93a386Sopenharmony_ci    for (index = 0;; ++index) {
42cb93a386Sopenharmony_ci        if (value <= base[index]) {
43cb93a386Sopenharmony_ci            if (value < base[index]) {
44cb93a386Sopenharmony_ci                index = ~index; // not found
45cb93a386Sopenharmony_ci            }
46cb93a386Sopenharmony_ci            break;
47cb93a386Sopenharmony_ci        }
48cb93a386Sopenharmony_ci    }
49cb93a386Sopenharmony_ci    return index;
50cb93a386Sopenharmony_ci}
51cb93a386Sopenharmony_ci
52cb93a386Sopenharmony_cistatic int find_with_slope(const SkUnichar base[], int count, SkUnichar value, double denom) {
53cb93a386Sopenharmony_ci    SkASSERT(count >= kMinCountForSlope);
54cb93a386Sopenharmony_ci
55cb93a386Sopenharmony_ci    int index;
56cb93a386Sopenharmony_ci    if (value <= base[1]) {
57cb93a386Sopenharmony_ci        index = 1;
58cb93a386Sopenharmony_ci        if (value < base[index]) {
59cb93a386Sopenharmony_ci            index = ~index;
60cb93a386Sopenharmony_ci        }
61cb93a386Sopenharmony_ci    } else if (value >= base[count - 2]) {
62cb93a386Sopenharmony_ci        index = count - 2;
63cb93a386Sopenharmony_ci        if (value > base[index]) {
64cb93a386Sopenharmony_ci            index = ~(index + 1);
65cb93a386Sopenharmony_ci        }
66cb93a386Sopenharmony_ci    } else {
67cb93a386Sopenharmony_ci        // make our guess based on the "slope" of the current values
68cb93a386Sopenharmony_ci//        index = 1 + (int64_t)(count - 2) * (value - base[1]) / (base[count - 2] - base[1]);
69cb93a386Sopenharmony_ci        index = 1 + (int)(denom * (count - 2) * (value - base[1]));
70cb93a386Sopenharmony_ci        SkASSERT(index >= 1 && index <= count - 2);
71cb93a386Sopenharmony_ci
72cb93a386Sopenharmony_ci        if (value >= base[index]) {
73cb93a386Sopenharmony_ci            for (;; ++index) {
74cb93a386Sopenharmony_ci                if (value <= base[index]) {
75cb93a386Sopenharmony_ci                    if (value < base[index]) {
76cb93a386Sopenharmony_ci                        index = ~index; // not found
77cb93a386Sopenharmony_ci                    }
78cb93a386Sopenharmony_ci                    break;
79cb93a386Sopenharmony_ci                }
80cb93a386Sopenharmony_ci            }
81cb93a386Sopenharmony_ci        } else {
82cb93a386Sopenharmony_ci            for (--index;; --index) {
83cb93a386Sopenharmony_ci                SkASSERT(index >= 0);
84cb93a386Sopenharmony_ci                if (value >= base[index]) {
85cb93a386Sopenharmony_ci                    if (value > base[index]) {
86cb93a386Sopenharmony_ci                        index = ~(index + 1);
87cb93a386Sopenharmony_ci                    }
88cb93a386Sopenharmony_ci                    break;
89cb93a386Sopenharmony_ci                }
90cb93a386Sopenharmony_ci            }
91cb93a386Sopenharmony_ci        }
92cb93a386Sopenharmony_ci    }
93cb93a386Sopenharmony_ci    return index;
94cb93a386Sopenharmony_ci}
95cb93a386Sopenharmony_ci
96cb93a386Sopenharmony_ciint SkCharToGlyphCache::findGlyphIndex(SkUnichar unichar) const {
97cb93a386Sopenharmony_ci    const int count = fK32.count();
98cb93a386Sopenharmony_ci    int index;
99cb93a386Sopenharmony_ci    if (count <= kSmallCountLimit) {
100cb93a386Sopenharmony_ci        index = find_simple(fK32.begin(), count, unichar);
101cb93a386Sopenharmony_ci    } else {
102cb93a386Sopenharmony_ci        index = find_with_slope(fK32.begin(), count, unichar, fDenom);
103cb93a386Sopenharmony_ci    }
104cb93a386Sopenharmony_ci    if (index >= 0) {
105cb93a386Sopenharmony_ci        return fV16[index];
106cb93a386Sopenharmony_ci    }
107cb93a386Sopenharmony_ci    return index;
108cb93a386Sopenharmony_ci}
109cb93a386Sopenharmony_ci
110cb93a386Sopenharmony_civoid SkCharToGlyphCache::insertCharAndGlyph(int index, SkUnichar unichar, SkGlyphID glyph) {
111cb93a386Sopenharmony_ci    SkASSERT(fK32.size() == fV16.size());
112cb93a386Sopenharmony_ci    SkASSERT((unsigned)index < fK32.size());
113cb93a386Sopenharmony_ci    SkASSERT(unichar < fK32[index]);
114cb93a386Sopenharmony_ci
115cb93a386Sopenharmony_ci    *fK32.insert(index) = unichar;
116cb93a386Sopenharmony_ci    *fV16.insert(index) = glyph;
117cb93a386Sopenharmony_ci
118cb93a386Sopenharmony_ci    // if we've changed the first [1] or last [count-2] entry, recompute our slope
119cb93a386Sopenharmony_ci    const int count = fK32.count();
120cb93a386Sopenharmony_ci    if (count >= kMinCountForSlope && (index == 1 || index == count - 2)) {
121cb93a386Sopenharmony_ci        SkASSERT(index >= 1 && index <= count - 2);
122cb93a386Sopenharmony_ci        fDenom = 1.0 / ((double)fK32[count - 2] - fK32[1]);
123cb93a386Sopenharmony_ci    }
124cb93a386Sopenharmony_ci
125cb93a386Sopenharmony_ci#ifdef SK_DEBUG
126cb93a386Sopenharmony_ci    for (int i = 1; i < fK32.count(); ++i) {
127cb93a386Sopenharmony_ci        SkASSERT(fK32[i-1] < fK32[i]);
128cb93a386Sopenharmony_ci    }
129cb93a386Sopenharmony_ci#endif
130cb93a386Sopenharmony_ci}
131