• 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 "include/core/SkPath.h"
12 #include "include/core/SkTypes.h"
13 #include "include/private/SkChecksum.h"
14 #include "include/private/SkFixed.h"
15 #include "include/private/SkTo.h"
16 #include "src/core/SkMask.h"
17 
18 class SkArenaAlloc;
19 class SkStrike;
20 class SkScalerContext;
21 
22 // needs to be != to any valid SkMask::Format
23 #define MASK_FORMAT_UNKNOWN         (0xFF)
24 #define MASK_FORMAT_JUST_ADVANCE    MASK_FORMAT_UNKNOWN
25 
26 /** SkGlyphID + subpixel-pos */
27 struct SkPackedGlyphID {
28     static constexpr uint32_t kImpossibleID = ~0u;
29     enum {
30         kSubBits = 2u,
31         kSubMask = ((1u << kSubBits) - 1),
32         kSubShift = 24u, // must be large enough for glyphs and unichars
33         kCodeMask = ((1u << kSubShift) - 1),
34         // relative offsets for X and Y subpixel bits
35         kSubShiftX = kSubBits,
36         kSubShiftY = 0
37     };
38 
SkPackedGlyphIDSkPackedGlyphID39     constexpr explicit SkPackedGlyphID(SkGlyphID glyphID)
40             : fID{glyphID} { }
41 
SkPackedGlyphIDSkPackedGlyphID42     constexpr SkPackedGlyphID(SkGlyphID glyphID, SkFixed x, SkFixed y)
43             : fID {PackIDXY(glyphID, x, y)} {
44         SkASSERT(fID != kImpossibleID);
45     }
46 
SkPackedGlyphIDSkPackedGlyphID47     constexpr SkPackedGlyphID(SkGlyphID code, SkIPoint pt)
48         : SkPackedGlyphID(code, pt.fX, pt.fY) { }
49 
SkPackedGlyphIDSkPackedGlyphID50     constexpr SkPackedGlyphID() : fID{kImpossibleID} {}
51 
52     bool operator==(const SkPackedGlyphID& that) const {
53         return fID == that.fID;
54     }
55     bool operator!=(const SkPackedGlyphID& that) const {
56         return !(*this == that);
57     }
58     bool operator<(SkPackedGlyphID that) const {
59         return this->fID < that.fID;
60     }
61 
codeSkPackedGlyphID62     uint32_t code() const {
63         return fID & kCodeMask;
64     }
65 
valueSkPackedGlyphID66     uint32_t value() const {
67         return fID;
68     }
69 
getSubXFixedSkPackedGlyphID70     SkFixed getSubXFixed() const {
71         return SubToFixed(ID2SubX(fID));
72     }
73 
getSubYFixedSkPackedGlyphID74     SkFixed getSubYFixed() const {
75         return SubToFixed(ID2SubY(fID));
76     }
77 
hashSkPackedGlyphID78     uint32_t hash() const {
79         return SkChecksum::CheapMix(fID);
80     }
81 
dumpSkPackedGlyphID82     SkString dump() const {
83         SkString str;
84         str.appendf("code: %d, x: %d, y:%d", code(), getSubXFixed(), getSubYFixed());
85         return str;
86     }
87 
88 private:
PackIDXYSkPackedGlyphID89     static constexpr uint32_t PackIDXY(SkGlyphID glyphID, SkFixed x, SkFixed y) {
90         return (FixedToSub(x) << (kSubShift + kSubShiftX))
91              | (FixedToSub(y) << (kSubShift + kSubShiftY))
92              | glyphID;
93     }
94 
ID2SubXSkPackedGlyphID95     static constexpr unsigned ID2SubX(uint32_t id) {
96         return id >> (kSubShift + kSubShiftX);
97     }
98 
ID2SubYSkPackedGlyphID99     static constexpr unsigned ID2SubY(uint32_t id) {
100         return (id >> (kSubShift + kSubShiftY)) & kSubMask;
101     }
102 
FixedToSubSkPackedGlyphID103     static constexpr unsigned FixedToSub(SkFixed n) {
104         return (n >> (16 - kSubBits)) & kSubMask;
105     }
106 
SubToFixedSkPackedGlyphID107     static constexpr SkFixed SubToFixed(uint32_t sub) {
108         SkASSERT(sub <= kSubMask);
109         return sub << (16u - kSubBits);
110     }
111 
112     uint32_t fID;
113 };
114 
115 struct SkGlyphPrototype;
116 
117 class SkGlyph {
118 public:
119     static constexpr SkFixed kSubpixelRound = SK_FixedHalf >> SkPackedGlyphID::kSubBits;
120 
SkGlyph(SkPackedGlyphID id)121     constexpr explicit SkGlyph(SkPackedGlyphID id) : fID{id} { }
122     explicit SkGlyph(const SkGlyphPrototype& p);
123 
advanceVector()124     SkVector advanceVector() const { return SkVector{fAdvanceX, fAdvanceY}; }
advanceX()125     SkScalar advanceX() const { return fAdvanceX; }
advanceY()126     SkScalar advanceY() const { return fAdvanceY; }
127 
getGlyphID()128     SkGlyphID getGlyphID() const { return fID.code(); }
getPackedID()129     SkPackedGlyphID getPackedID() const { return fID; }
getSubXFixed()130     SkFixed getSubXFixed() const { return fID.getSubXFixed(); }
getSubYFixed()131     SkFixed getSubYFixed() const { return fID.getSubYFixed(); }
132 
133     size_t rowBytes() const;
134     size_t rowBytesUsingFormat(SkMask::Format format) const;
135 
136     // Call this to set all of the metrics fields to 0 (e.g. if the scaler
137     // encounters an error measuring a glyph). Note: this does not alter the
138     // fImage, fPath, fID, fMaskFormat fields.
139     void zeroMetrics();
140 
141     SkMask mask() const;
142 
143     SkMask mask(SkPoint position) const;
144 
145     // Image
146     // If we haven't already tried to associate an image with this glyph
147     // (i.e. setImageHasBeenCalled() returns false), then use the
148     // SkScalerContext or const void* argument to set the image.
149     bool setImage(SkArenaAlloc* alloc, SkScalerContext* scalerContext);
150     bool setImage(SkArenaAlloc* alloc, const void* image);
151 
152     // Merge the from glyph into this glyph using alloc to allocate image data. Return true if
153     // image data was allocated. If the image for this glyph has not been initialized, then copy
154     // the width, height, top, left, format, and image into this glyph making a copy of the image
155     // using the alloc.
156     bool setMetricsAndImage(SkArenaAlloc* alloc, const SkGlyph& from);
157 
158     // Returns true if the image has been set.
setImageHasBeenCalled()159     bool setImageHasBeenCalled() const {
160         return fImage != nullptr || this->isEmpty() || this->imageTooLarge();
161     }
162 
163     // Return a pointer to the path if the image exists, otherwise return nullptr.
image()164     const void* image() const { SkASSERT(this->setImageHasBeenCalled()); return fImage; }
165 
166     // Return the size of the image.
167     size_t imageSize() const;
168 
169     // Path
170     // If we haven't already tried to associate a path to this glyph
171     // (i.e. setPathHasBeenCalled() returns false), then use the
172     // SkScalerContext or SkPath argument to try to do so.  N.B. this
173     // may still result in no path being associated with this glyph,
174     // e.g. if you pass a null SkPath or the typeface is bitmap-only.
175     //
176     // This setPath() call is sticky... once you call it, the glyph
177     // stays in its state permanently, ignoring any future calls.
178     //
179     // Returns true if this is the first time you called setPath()
180     // and there actually is a path; call path() to get it.
181     bool setPath(SkArenaAlloc* alloc, SkScalerContext* scalerContext);
182     bool setPath(SkArenaAlloc* alloc, const SkPath* path);
183 
184     // Returns true if that path has been set.
setPathHasBeenCalled()185     bool setPathHasBeenCalled() const { return fPathData != nullptr; }
186 
187     // Return a pointer to the path if it exists, otherwise return nullptr. Only works if the
188     // path was previously set.
189     const SkPath* path() const;
190 
191     // Format
isColor()192     bool isColor() const { return fMaskFormat == SkMask::kARGB32_Format; }
maskFormat()193     SkMask::Format maskFormat() const { return static_cast<SkMask::Format>(fMaskFormat); }
194     size_t formatAlignment() const;
195 
196     // Bounds
maxDimension()197     int maxDimension() const { return std::max(fWidth, fHeight); }
iRect()198     SkIRect iRect() const { return SkIRect::MakeXYWH(fLeft, fTop, fWidth, fHeight); }
rect()199     SkRect rect()   const { return SkRect::MakeXYWH(fLeft, fTop, fWidth, fHeight);  }
left()200     int left()   const { return fLeft;   }
top()201     int top()    const { return fTop;    }
width()202     int width()  const { return fWidth;  }
height()203     int height() const { return fHeight; }
isEmpty()204     bool isEmpty() const {
205         // fHeight == 0 -> fWidth == 0;
206         SkASSERT(fHeight != 0 || fWidth == 0);
207         return fWidth == 0;
208     }
imageTooLarge()209     bool imageTooLarge() const { return fWidth >= kMaxGlyphWidth; }
210 
211     // Make sure that the intercept information is on the glyph and return it, or return it if it
212     // already exists.
213     // * bounds - either end of the gap for the character.
214     // * scale, xPos - information about how wide the gap is.
215     // * array - accumulated gaps for many characters if not null.
216     // * count - the number of gaps.
217     void ensureIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos,
218                           SkScalar* array, int* count, SkArenaAlloc* alloc);
219 
220 private:
221     // There are two sides to an SkGlyph, the scaler side (things that create glyph data) have
222     // access to all the fields. Scalers are assumed to maintain all the SkGlyph invariants. The
223     // consumer side has a tighter interface.
224     friend class RandomScalerContext;
225     friend class SkScalerContext;
226     friend class SkScalerContextProxy;
227     friend class SkScalerContext_Empty;
228     friend class SkScalerContext_FreeType;
229     friend class SkScalerContext_FreeType_Base;
230     friend class SkScalerContext_DW;
231     friend class SkScalerContext_GDI;
232     friend class SkScalerContext_Mac;
233     friend class SkStrikeClient;
234     friend class SkStrikeServer;
235     friend class SkTestScalerContext;
236     friend class SkTestSVGScalerContext;
237     friend class TestSVGTypeface;
238     friend class TestTypeface;
239 
240     static constexpr uint16_t kMaxGlyphWidth = 1u << 13u;
241 
242     // Support horizontal and vertical skipping strike-through / underlines.
243     // The caller walks the linked list looking for a match. For a horizontal underline,
244     // the fBounds contains the top and bottom of the underline. The fInterval pair contains the
245     // beginning and end of of the intersection of the bounds and the glyph's path.
246     // If interval[0] >= interval[1], no intersection was found.
247     struct Intercept {
248         Intercept* fNext;
249         SkScalar   fBounds[2];    // for horz underlines, the boundaries in Y
250         SkScalar   fInterval[2];  // the outside intersections of the axis and the glyph
251     };
252 
253     struct PathData {
254         Intercept* fIntercept{nullptr};
255         SkPath     fPath;
256         bool       fHasPath{false};
257     };
258 
259     size_t allocImage(SkArenaAlloc* alloc);
260 
261     // path == nullptr indicates that there is no path.
262     void installPath(SkArenaAlloc* alloc, const SkPath* path);
263 
264     // The width and height of the glyph mask.
265     uint16_t  fWidth  = 0,
266               fHeight = 0;
267 
268     // The offset from the glyphs origin on the baseline to the top left of the glyph mask.
269     int16_t   fTop  = 0,
270               fLeft = 0;
271 
272     // fImage must remain null if the glyph is empty or if width > kMaxGlyphWidth.
273     void*     fImage    = nullptr;
274 
275     // Path data has tricky state. If the glyph isEmpty, then fPathData should always be nullptr,
276     // else if fPathData is not null, then a path has been requested. The fPath field of fPathData
277     // may still be null after the request meaning that there is no path for this glyph.
278     PathData* fPathData = nullptr;
279 
280     // The advance for this glyph.
281     float     fAdvanceX = 0,
282               fAdvanceY = 0;
283 
284     // This is a combination of SkMask::Format and SkGlyph state. The SkGlyph can be in one of two
285     // states, just the advances have been calculated, and all the metrics are available. The
286     // illegal mask format is used to signal that only the advances are available.
287     uint8_t   fMaskFormat = MASK_FORMAT_UNKNOWN;
288 
289     // Used by the DirectWrite scaler to track state.
290     int8_t    fForceBW = 0;
291 
292     const SkPackedGlyphID fID;
293 };
294 
295 struct SkGlyphPrototype {
296     SkPackedGlyphID id;
297 
298     float           advanceX = 0,
299                     advanceY = 0;
300 
301     // The width and height of the glyph mask.
302     uint16_t        width  = 0,
303                     height = 0;
304 
305     // The offset from the glyphs origin on the baseline to the top left of the glyph mask.
306     int16_t         left = 0,
307                     top  = 0;
308 
309     SkMask::Format  maskFormat = SkMask::kBW_Format;
310 
311     bool            forceBW = false;
312 };
313 
314 #endif
315