• 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         if (SkMask::kBW_Format == format) {
176             rb = BitsToBytes(rb);
177         } else if (SkMask::kARGB32_Format == format) {
178             rb <<= 2;
179         } else if (SkMask::kLCD16_Format == format) {
180             rb = SkAlign4(rb << 1);
181         } else {
182             rb = SkAlign4(rb);
183         }
184         return rb;
185     }
186 
allocImage(SkArenaAlloc * alloc)187     size_t allocImage(SkArenaAlloc* alloc) {
188         size_t allocSize;
189         if (SkMask::kBW_Format == fMaskFormat) {
190             allocSize = BitsToBytes(fWidth) * fHeight;
191             fImage = alloc->makeArrayDefault<char>(allocSize);
192         } else if (SkMask::kARGB32_Format == fMaskFormat) {
193             allocSize = fWidth * fHeight;
194             fImage = alloc->makeArrayDefault<uint32_t>(fWidth * fHeight);
195             allocSize *= sizeof(uint32_t);
196         } else if (SkMask::kLCD16_Format == fMaskFormat) {
197             allocSize = SkAlign2(fWidth) * fHeight;
198             fImage = alloc->makeArrayDefault<uint16_t>(allocSize);
199             allocSize *= sizeof(uint16_t);
200         } else {
201             allocSize = SkAlign4(fWidth) * fHeight;
202             fImage = alloc->makeArrayDefault<char>(allocSize);
203         }
204         return allocSize;
205     }
206 
rowBytes()207     unsigned rowBytes() const {
208         return ComputeRowBytes(fWidth, (SkMask::Format)fMaskFormat);
209     }
210 
isJustAdvance()211     bool isJustAdvance() const {
212         return MASK_FORMAT_JUST_ADVANCE == fMaskFormat;
213     }
214 
isFullMetrics()215     bool isFullMetrics() const {
216         return MASK_FORMAT_JUST_ADVANCE != fMaskFormat;
217     }
218 
getGlyphID()219     SkGlyphID getGlyphID() const {
220         return fID.code();
221     }
222 
getPackedID()223     SkPackedGlyphID getPackedID() const {
224         return fID;
225     }
226 
getSubXFixed()227     SkFixed getSubXFixed() const {
228         return fID.getSubXFixed();
229     }
230 
getSubYFixed()231     SkFixed getSubYFixed() const {
232         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:
GetKey(const SkGlyph & glyph)247         static SkPackedGlyphID GetKey(const SkGlyph& glyph) {
248             return glyph.fID;
249         }
Hash(SkPackedGlyphID glyphId)250         static uint32_t Hash(SkPackedGlyphID glyphId) {
251             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
269