• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
SkPackedIDSkPackedID40     SkPackedID(uint32_t code) {
41         SkASSERT(code <= kCodeMask);
42         SkASSERT(code != kImpossibleID);
43         fID = code;
44     }
45 
SkPackedIDSkPackedID46     SkPackedID(uint32_t code, SkFixed x, SkFixed y) {
47         SkASSERT(code <= kCodeMask);
48         x = FixedToSub(x);
49         y = FixedToSub(y);
50         uint32_t ID = (x << (kSubShift + kSubShiftX)) |
51                       (y << (kSubShift + kSubShiftY)) |
52                       code;
53         SkASSERT(ID != kImpossibleID);
54         fID = ID;
55     }
56 
SkPackedIDSkPackedID57     constexpr SkPackedID() : fID(kImpossibleID) {}
58 
59     bool operator==(const SkPackedID& that) const {
60         return fID == that.fID;
61     }
62     bool operator!=(const SkPackedID& that) const {
63         return !(*this == that);
64     }
65 
codeSkPackedID66     uint32_t code() const {
67         return fID & kCodeMask;
68     }
69 
getSubXFixedSkPackedID70     SkFixed getSubXFixed() const {
71         return SubToFixed(ID2SubX(fID));
72     }
73 
getSubYFixedSkPackedID74     SkFixed getSubYFixed() const {
75         return SubToFixed(ID2SubY(fID));
76     }
77 
hashSkPackedID78     uint32_t hash() const {
79         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
uint32_tSkPackedID85     operator uint32_t() const { return fID; }
86 #endif
87 
88 private:
ID2SubXSkPackedID89     static unsigned ID2SubX(uint32_t id) {
90         return id >> (kSubShift + kSubShiftX);
91     }
92 
ID2SubYSkPackedID93     static unsigned ID2SubY(uint32_t id) {
94         return (id >> (kSubShift + kSubShiftY)) & kSubMask;
95     }
96 
FixedToSubSkPackedID97     static unsigned FixedToSub(SkFixed n) {
98         return (n >> (16 - kSubBits)) & kSubMask;
99     }
100 
SubToFixedSkPackedID101     static SkFixed SubToFixed(unsigned sub) {
102         SkASSERT(sub <= kSubMask);
103         return sub << (16 - kSubBits);
104     }
105 
106     uint32_t fID;
107 };
108 
109 struct SkPackedGlyphID : public SkPackedID {
SkPackedGlyphIDSkPackedGlyphID110     SkPackedGlyphID(SkGlyphID code) : SkPackedID(code) { }
SkPackedGlyphIDSkPackedGlyphID111     SkPackedGlyphID(SkGlyphID code, SkFixed x, SkFixed y) : SkPackedID(code, x, y) { }
SkPackedGlyphIDSkPackedGlyphID112     SkPackedGlyphID() : SkPackedID() { }
codeSkPackedGlyphID113     SkGlyphID code() const {
114         return SkTo<SkGlyphID>(SkPackedID::code());
115     }
116 };
117 
118 struct SkPackedUnicharID : public SkPackedID {
SkPackedUnicharIDSkPackedUnicharID119     SkPackedUnicharID(SkUnichar code) : SkPackedID(code) { }
SkPackedUnicharIDSkPackedUnicharID120     SkPackedUnicharID(SkUnichar code, SkFixed x, SkFixed y) : SkPackedID(code, x, y) { }
SkPackedUnicharIDSkPackedUnicharID121     SkPackedUnicharID() : SkPackedID() { }
codeSkPackedUnicharID122     SkUnichar code() const {
123         return SkTo<SkUnichar>(SkPackedID::code());
124     }
125 };
126 
127 SK_BEGIN_REQUIRE_DENSE
128 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 
initWithGlyphID(SkPackedGlyphID glyph_id)158     void initWithGlyphID(SkPackedGlyphID glyph_id) {
159         fID             = glyph_id;
160         fImage          = nullptr;
161         fPathData       = nullptr;
162         fMaskFormat     = MASK_FORMAT_UNKNOWN;
163         fForceBW        = 0;
164     }
165 
BitsToBytes(size_t bits)166     static size_t BitsToBytes(size_t bits) {
167         return (bits + 7) >> 3;
168     }
169 
170     /**
171      *  Compute the rowbytes for the specified width and mask-format.
172      */
ComputeRowBytes(unsigned width,SkMask::Format format)173     static unsigned ComputeRowBytes(unsigned width, SkMask::Format format) {
174         unsigned rb = width;
175         switch (format) {
176         case SkMask::kBW_Format:
177             rb = BitsToBytes(rb);
178             break;
179         case SkMask::kA8_Format:
180             rb = SkAlign4(rb);
181             break;
182         case SkMask::k3D_Format:
183             rb = SkAlign4(rb);
184             break;
185         case SkMask::kARGB32_Format:
186             rb <<= 2;
187             break;
188         case SkMask::kLCD16_Format:
189             rb = SkAlign4(rb << 1);
190             break;
191         default:
192             SK_ABORT("Unknown mask format.");
193             break;
194         }
195         return rb;
196     }
197 
allocImage(SkArenaAlloc * alloc)198     size_t allocImage(SkArenaAlloc* alloc) {
199         size_t allocSize;
200         switch (static_cast<SkMask::Format>(fMaskFormat)) {
201         case SkMask::kBW_Format:
202             allocSize = BitsToBytes(fWidth) * fHeight;
203             fImage = alloc->makeArrayDefault<char>(allocSize);
204             break;
205         case SkMask::kA8_Format:
206             allocSize = SkAlign4(fWidth) * fHeight;
207             fImage = alloc->makeArrayDefault<char>(allocSize);
208             break;
209         case SkMask::k3D_Format:
210             allocSize = SkAlign4(fWidth) * fHeight * 3;
211             fImage = alloc->makeArrayDefault<char>(allocSize);
212             break;
213         case SkMask::kARGB32_Format:
214             allocSize = fWidth * fHeight;
215             fImage = alloc->makeArrayDefault<uint32_t>(fWidth * fHeight);
216             allocSize *= sizeof(uint32_t);
217             break;
218         case SkMask::kLCD16_Format:
219             allocSize = SkAlign2(fWidth) * fHeight;
220             fImage = alloc->makeArrayDefault<uint16_t>(allocSize);
221             allocSize *= sizeof(uint16_t);
222             break;
223         default:
224             SK_ABORT("Unknown mask format.");
225             break;
226         }
227         return allocSize;
228     }
229 
rowBytes()230     unsigned rowBytes() const {
231         return ComputeRowBytes(fWidth, (SkMask::Format)fMaskFormat);
232     }
233 
isJustAdvance()234     bool isJustAdvance() const {
235         return MASK_FORMAT_JUST_ADVANCE == fMaskFormat;
236     }
237 
isFullMetrics()238     bool isFullMetrics() const {
239         return MASK_FORMAT_JUST_ADVANCE != fMaskFormat;
240     }
241 
getGlyphID()242     SkGlyphID getGlyphID() const {
243         return fID.code();
244     }
245 
getPackedID()246     SkPackedGlyphID getPackedID() const {
247         return fID;
248     }
249 
getSubXFixed()250     SkFixed getSubXFixed() const {
251         return fID.getSubXFixed();
252     }
253 
getSubYFixed()254     SkFixed getSubYFixed() const {
255         return fID.getSubYFixed();
256     }
257 
258     size_t computeImageSize() const;
259 
260     /** Call this to set all of the metrics fields to 0 (e.g. if the scaler
261         encounters an error measuring a glyph). Note: this does not alter the
262         fImage, fPath, fID, fMaskFormat fields.
263      */
264     void zeroMetrics();
265 
266     void toMask(SkMask* mask) const;
267 
268     class HashTraits {
269     public:
GetKey(const SkGlyph & glyph)270         static SkPackedGlyphID GetKey(const SkGlyph& glyph) {
271             return glyph.fID;
272         }
Hash(SkPackedGlyphID glyphId)273         static uint32_t Hash(SkPackedGlyphID glyphId) {
274             return glyphId.hash();
275         }
276     };
277 
278  private:
279     // TODO(herb) remove friend statement after SkGlyphCache cleanup.
280     friend class SkGlyphCache;
281 
282 // FIXME - This is needed because the Android frame work directly accesses fID.
283 // Remove when fID accesses are cleaned up.
284 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK
285   public:
286 #endif
287     SkPackedGlyphID fID;
288 };
289 SK_END_REQUIRE_DENSE
290 
291 #endif
292