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