Line data Source code
1 : /*
2 : * Copyright 2006 The Android Open Source Project
3 : *
4 : * Use of this source code is governed by a BSD-style license that can be
5 : * found in the LICENSE file.
6 : */
7 :
8 : #ifndef SkGlyph_DEFINED
9 : #define SkGlyph_DEFINED
10 :
11 : #include "SkArenaAlloc.h"
12 : #include "SkChecksum.h"
13 : #include "SkFixed.h"
14 : #include "SkMask.h"
15 : #include "SkTypes.h"
16 :
17 :
18 : class SkPath;
19 : class SkGlyphCache;
20 :
21 : // needs to be != to any valid SkMask::Format
22 : #define MASK_FORMAT_UNKNOWN (0xFF)
23 : #define MASK_FORMAT_JUST_ADVANCE MASK_FORMAT_UNKNOWN
24 :
25 : #define kMaxGlyphWidth (1<<13)
26 :
27 : /** (glyph-index or unicode-point) + subpixel-pos */
28 : struct SkPackedID {
29 : static constexpr uint32_t kImpossibleID = ~0;
30 : enum {
31 : kSubBits = 2,
32 : kSubMask = ((1 << kSubBits) - 1),
33 : kSubShift = 24, // must be large enough for glyphs and unichars
34 : kCodeMask = ((1 << kSubShift) - 1),
35 : // relative offsets for X and Y subpixel bits
36 : kSubShiftX = kSubBits,
37 : kSubShiftY = 0
38 : };
39 :
40 448 : SkPackedID(uint32_t code) {
41 448 : SkASSERT(code <= kCodeMask);
42 448 : SkASSERT(code != kImpossibleID);
43 448 : fID = code;
44 448 : }
45 :
46 0 : SkPackedID(uint32_t code, SkFixed x, SkFixed y) {
47 0 : SkASSERT(code <= kCodeMask);
48 0 : x = FixedToSub(x);
49 0 : y = FixedToSub(y);
50 0 : uint32_t ID = (x << (kSubShift + kSubShiftX)) |
51 0 : (y << (kSubShift + kSubShiftY)) |
52 0 : code;
53 0 : SkASSERT(ID != kImpossibleID);
54 0 : fID = ID;
55 0 : }
56 :
57 362 : constexpr SkPackedID() : fID(kImpossibleID) {}
58 :
59 448 : bool operator==(const SkPackedID& that) const {
60 448 : return fID == that.fID;
61 : }
62 60 : bool operator!=(const SkPackedID& that) const {
63 60 : return !(*this == that);
64 : }
65 :
66 118 : uint32_t code() const {
67 118 : return fID & kCodeMask;
68 : }
69 :
70 0 : SkFixed getSubXFixed() const {
71 0 : return SubToFixed(ID2SubX(fID));
72 : }
73 :
74 0 : SkFixed getSubYFixed() const {
75 0 : return SubToFixed(ID2SubY(fID));
76 : }
77 :
78 574 : uint32_t hash() const {
79 574 : return SkChecksum::CheapMix(fID);
80 : }
81 :
82 : // FIXME - This is needed because the Android framework directly accesses fID.
83 : // Remove when fID accesses are cleaned up.
84 : #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
85 : operator uint32_t() const { return fID; }
86 : #endif
87 :
88 : private:
89 0 : static unsigned ID2SubX(uint32_t id) {
90 0 : return id >> (kSubShift + kSubShiftX);
91 : }
92 :
93 0 : static unsigned ID2SubY(uint32_t id) {
94 0 : return (id >> (kSubShift + kSubShiftY)) & kSubMask;
95 : }
96 :
97 0 : static unsigned FixedToSub(SkFixed n) {
98 0 : return (n >> (16 - kSubBits)) & kSubMask;
99 : }
100 :
101 0 : static SkFixed SubToFixed(unsigned sub) {
102 0 : SkASSERT(sub <= kSubMask);
103 0 : return sub << (16 - kSubBits);
104 : }
105 :
106 : uint32_t fID;
107 : };
108 :
109 : struct SkPackedGlyphID : public SkPackedID {
110 448 : SkPackedGlyphID(SkGlyphID code) : SkPackedID(code) { }
111 0 : SkPackedGlyphID(SkGlyphID code, SkFixed x, SkFixed y) : SkPackedID(code, x, y) { }
112 362 : SkPackedGlyphID() : SkPackedID() { }
113 118 : SkGlyphID code() const {
114 118 : return SkTo<SkGlyphID>(SkPackedID::code());
115 : }
116 : };
117 :
118 : struct SkPackedUnicharID : public SkPackedID {
119 0 : SkPackedUnicharID(SkUnichar code) : SkPackedID(code) { }
120 0 : SkPackedUnicharID(SkUnichar code, SkFixed x, SkFixed y) : SkPackedID(code, x, y) { }
121 0 : SkPackedUnicharID() : SkPackedID() { }
122 : SkUnichar code() const {
123 : return SkTo<SkUnichar>(SkPackedID::code());
124 : }
125 : };
126 :
127 : SK_BEGIN_REQUIRE_DENSE
128 302 : class SkGlyph {
129 : // Support horizontal and vertical skipping strike-through / underlines.
130 : // The caller walks the linked list looking for a match. For a horizontal underline,
131 : // the fBounds contains the top and bottom of the underline. The fInterval pair contains the
132 : // beginning and end of of the intersection of the bounds and the glyph's path.
133 : // If interval[0] >= interval[1], no intesection was found.
134 : struct Intercept {
135 : Intercept* fNext;
136 : SkScalar fBounds[2]; // for horz underlines, the boundaries in Y
137 : SkScalar fInterval[2]; // the outside intersections of the axis and the glyph
138 : };
139 :
140 : struct PathData {
141 : Intercept* fIntercept;
142 : SkPath* fPath;
143 : };
144 :
145 : public:
146 : static const SkFixed kSubpixelRound = SK_FixedHalf >> SkPackedID::kSubBits;
147 : void* fImage;
148 : PathData* fPathData;
149 : float fAdvanceX, fAdvanceY;
150 :
151 : uint16_t fWidth, fHeight;
152 : int16_t fTop, fLeft;
153 :
154 : uint8_t fMaskFormat;
155 : int8_t fRsbDelta, fLsbDelta; // used by auto-kerning
156 : int8_t fForceBW;
157 :
158 60 : void initWithGlyphID(SkPackedGlyphID glyph_id) {
159 60 : fID = glyph_id;
160 60 : fImage = nullptr;
161 60 : fPathData = nullptr;
162 60 : fMaskFormat = MASK_FORMAT_UNKNOWN;
163 60 : fForceBW = 0;
164 60 : }
165 :
166 0 : static size_t BitsToBytes(size_t bits) {
167 0 : return (bits + 7) >> 3;
168 : }
169 :
170 : /**
171 : * Compute the rowbytes for the specified width and mask-format.
172 : */
173 387 : static unsigned ComputeRowBytes(unsigned width, SkMask::Format format) {
174 387 : unsigned rb = width;
175 387 : if (SkMask::kBW_Format == format) {
176 0 : rb = BitsToBytes(rb);
177 387 : } else if (SkMask::kARGB32_Format == format) {
178 0 : rb <<= 2;
179 387 : } else if (SkMask::kLCD16_Format == format) {
180 387 : rb = SkAlign4(rb << 1);
181 : } else {
182 0 : rb = SkAlign4(rb);
183 : }
184 387 : return rb;
185 : }
186 :
187 58 : size_t allocImage(SkArenaAlloc* alloc) {
188 : size_t allocSize;
189 58 : if (SkMask::kBW_Format == fMaskFormat) {
190 0 : allocSize = BitsToBytes(fWidth) * fHeight;
191 0 : fImage = alloc->makeArrayDefault<char>(allocSize);
192 58 : } else if (SkMask::kARGB32_Format == fMaskFormat) {
193 0 : allocSize = fWidth * fHeight;
194 0 : fImage = alloc->makeArrayDefault<uint32_t>(fWidth * fHeight);
195 0 : allocSize *= sizeof(uint32_t);
196 58 : } else if (SkMask::kLCD16_Format == fMaskFormat) {
197 58 : allocSize = SkAlign2(fWidth) * fHeight;
198 58 : fImage = alloc->makeArrayDefault<uint16_t>(allocSize);
199 58 : allocSize *= sizeof(uint16_t);
200 : } else {
201 0 : allocSize = SkAlign4(fWidth) * fHeight;
202 0 : fImage = alloc->makeArrayDefault<char>(allocSize);
203 : }
204 58 : return allocSize;
205 : }
206 :
207 387 : unsigned rowBytes() const {
208 387 : return ComputeRowBytes(fWidth, (SkMask::Format)fMaskFormat);
209 : }
210 :
211 388 : bool isJustAdvance() const {
212 388 : return MASK_FORMAT_JUST_ADVANCE == fMaskFormat;
213 : }
214 :
215 : bool isFullMetrics() const {
216 : return MASK_FORMAT_JUST_ADVANCE != fMaskFormat;
217 : }
218 :
219 118 : SkGlyphID getGlyphID() const {
220 118 : return fID.code();
221 : }
222 :
223 0 : SkPackedGlyphID getPackedID() const {
224 0 : return fID;
225 : }
226 :
227 0 : SkFixed getSubXFixed() const {
228 0 : return fID.getSubXFixed();
229 : }
230 :
231 0 : SkFixed getSubYFixed() const {
232 0 : return fID.getSubYFixed();
233 : }
234 :
235 : size_t computeImageSize() const;
236 :
237 : /** Call this to set all of the metrics fields to 0 (e.g. if the scaler
238 : encounters an error measuring a glyph). Note: this does not alter the
239 : fImage, fPath, fID, fMaskFormat fields.
240 : */
241 : void zeroMetrics();
242 :
243 : void toMask(SkMask* mask) const;
244 :
245 : class HashTraits {
246 : public:
247 514 : static SkPackedGlyphID GetKey(const SkGlyph& glyph) {
248 514 : return glyph.fID;
249 : }
250 574 : static uint32_t Hash(SkPackedGlyphID glyphId) {
251 574 : return glyphId.hash();
252 : }
253 : };
254 :
255 : private:
256 : // TODO(herb) remove friend statement after SkGlyphCache cleanup.
257 : friend class SkGlyphCache;
258 :
259 : // FIXME - This is needed because the Android frame work directly accesses fID.
260 : // Remove when fID accesses are cleaned up.
261 : #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
262 : public:
263 : #endif
264 : SkPackedGlyphID fID;
265 : };
266 : SK_END_REQUIRE_DENSE
267 :
268 : #endif
|