bungeman@google.com | bbe5013 | 2012-07-24 20:33:21 +0000 | [diff] [blame] | 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 | |
Mike Klein | c0bd9f9 | 2019-04-23 12:05:21 -0500 | [diff] [blame] | 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" |
Herb Derby | 7c5a806 | 2017-01-20 11:59:03 -0500 | [diff] [blame] | 17 | |
Herb Derby | 8219163 | 2018-10-24 14:49:26 -0400 | [diff] [blame] | 18 | class SkArenaAlloc; |
Herb Derby | 5fd955e | 2019-01-16 11:23:29 -0500 | [diff] [blame] | 19 | class SkStrike; |
Herb Derby | f4958ce | 2018-11-27 13:17:02 -0500 | [diff] [blame] | 20 | class SkScalerContext; |
bungeman@google.com | bbe5013 | 2012-07-24 20:33:21 +0000 | [diff] [blame] | 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 | |
Herb Derby | 8207b64 | 2019-05-23 11:35:56 -0400 | [diff] [blame] | 26 | /** SkGlyphID + subpixel-pos */ |
| 27 | struct SkPackedGlyphID { |
| 28 | static constexpr uint32_t kImpossibleID = ~0u; |
herb | b69d0e0 | 2015-02-25 06:47:06 -0800 | [diff] [blame] | 29 | enum { |
Herb Derby | 8207b64 | 2019-05-23 11:35:56 -0400 | [diff] [blame] | 30 | kSubBits = 2u, |
| 31 | kSubMask = ((1u << kSubBits) - 1), |
| 32 | kSubShift = 24u, // must be large enough for glyphs and unichars |
| 33 | kCodeMask = ((1u << kSubShift) - 1), |
herb | b69d0e0 | 2015-02-25 06:47:06 -0800 | [diff] [blame] | 34 | // relative offsets for X and Y subpixel bits |
| 35 | kSubShiftX = kSubBits, |
| 36 | kSubShiftY = 0 |
| 37 | }; |
| 38 | |
Herb Derby | 8207b64 | 2019-05-23 11:35:56 -0400 | [diff] [blame] | 39 | constexpr explicit SkPackedGlyphID(SkGlyphID glyphID) |
| 40 | : fID{glyphID} { } |
| 41 | |
| 42 | constexpr SkPackedGlyphID(SkGlyphID glyphID, SkFixed x, SkFixed y) |
| 43 | : fID {PackIDXY(glyphID, x, y)} { |
| 44 | SkASSERT(fID != kImpossibleID); |
Ben Wagner | 6e9ac12 | 2016-11-11 14:31:06 -0500 | [diff] [blame] | 45 | } |
| 46 | |
Herb Derby | 8207b64 | 2019-05-23 11:35:56 -0400 | [diff] [blame] | 47 | constexpr SkPackedGlyphID(SkGlyphID code, SkIPoint pt) |
| 48 | : SkPackedGlyphID(code, pt.fX, pt.fY) { } |
Ben Wagner | 6e9ac12 | 2016-11-11 14:31:06 -0500 | [diff] [blame] | 49 | |
Herb Derby | 8207b64 | 2019-05-23 11:35:56 -0400 | [diff] [blame] | 50 | constexpr SkPackedGlyphID() : fID{kImpossibleID} {} |
Ben Wagner | 6e9ac12 | 2016-11-11 14:31:06 -0500 | [diff] [blame] | 51 | |
Herb Derby | 8207b64 | 2019-05-23 11:35:56 -0400 | [diff] [blame] | 52 | bool operator==(const SkPackedGlyphID& that) const { |
Ben Wagner | 6e9ac12 | 2016-11-11 14:31:06 -0500 | [diff] [blame] | 53 | return fID == that.fID; |
| 54 | } |
Herb Derby | 8207b64 | 2019-05-23 11:35:56 -0400 | [diff] [blame] | 55 | bool operator!=(const SkPackedGlyphID& that) const { |
Ben Wagner | 6e9ac12 | 2016-11-11 14:31:06 -0500 | [diff] [blame] | 56 | return !(*this == that); |
| 57 | } |
Herb Derby | 8207b64 | 2019-05-23 11:35:56 -0400 | [diff] [blame] | 58 | bool operator<(SkPackedGlyphID that) const { |
Herb Derby | efbf00c | 2018-03-14 11:53:40 -0400 | [diff] [blame] | 59 | return this->fID < that.fID; |
| 60 | } |
Ben Wagner | 6e9ac12 | 2016-11-11 14:31:06 -0500 | [diff] [blame] | 61 | |
| 62 | uint32_t code() const { |
| 63 | return fID & kCodeMask; |
| 64 | } |
| 65 | |
Herb Derby | 8219163 | 2018-10-24 14:49:26 -0400 | [diff] [blame] | 66 | uint32_t value() const { |
Herb Derby | efbf00c | 2018-03-14 11:53:40 -0400 | [diff] [blame] | 67 | return fID; |
| 68 | } |
| 69 | |
Ben Wagner | 6e9ac12 | 2016-11-11 14:31:06 -0500 | [diff] [blame] | 70 | SkFixed getSubXFixed() const { |
| 71 | return SubToFixed(ID2SubX(fID)); |
| 72 | } |
| 73 | |
| 74 | SkFixed getSubYFixed() const { |
| 75 | return SubToFixed(ID2SubY(fID)); |
| 76 | } |
| 77 | |
| 78 | uint32_t hash() const { |
| 79 | return SkChecksum::CheapMix(fID); |
| 80 | } |
| 81 | |
Khushal | 4010c79 | 2018-06-13 09:44:23 -0700 | [diff] [blame] | 82 | SkString dump() const { |
| 83 | SkString str; |
| 84 | str.appendf("code: %d, x: %d, y:%d", code(), getSubXFixed(), getSubYFixed()); |
| 85 | return str; |
| 86 | } |
| 87 | |
Ben Wagner | 6e9ac12 | 2016-11-11 14:31:06 -0500 | [diff] [blame] | 88 | private: |
Herb Derby | 8207b64 | 2019-05-23 11:35:56 -0400 | [diff] [blame] | 89 | 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 | |
| 95 | static constexpr unsigned ID2SubX(uint32_t id) { |
Ben Wagner | 6e9ac12 | 2016-11-11 14:31:06 -0500 | [diff] [blame] | 96 | return id >> (kSubShift + kSubShiftX); |
| 97 | } |
| 98 | |
Herb Derby | 8207b64 | 2019-05-23 11:35:56 -0400 | [diff] [blame] | 99 | static constexpr unsigned ID2SubY(uint32_t id) { |
Ben Wagner | 6e9ac12 | 2016-11-11 14:31:06 -0500 | [diff] [blame] | 100 | return (id >> (kSubShift + kSubShiftY)) & kSubMask; |
| 101 | } |
| 102 | |
Herb Derby | 8207b64 | 2019-05-23 11:35:56 -0400 | [diff] [blame] | 103 | static constexpr unsigned FixedToSub(SkFixed n) { |
Ben Wagner | 6e9ac12 | 2016-11-11 14:31:06 -0500 | [diff] [blame] | 104 | return (n >> (16 - kSubBits)) & kSubMask; |
| 105 | } |
| 106 | |
Herb Derby | 8207b64 | 2019-05-23 11:35:56 -0400 | [diff] [blame] | 107 | static constexpr SkFixed SubToFixed(uint32_t sub) { |
Ben Wagner | 6e9ac12 | 2016-11-11 14:31:06 -0500 | [diff] [blame] | 108 | SkASSERT(sub <= kSubMask); |
Herb Derby | 8207b64 | 2019-05-23 11:35:56 -0400 | [diff] [blame] | 109 | return sub << (16u - kSubBits); |
Ben Wagner | 6e9ac12 | 2016-11-11 14:31:06 -0500 | [diff] [blame] | 110 | } |
| 111 | |
| 112 | uint32_t fID; |
| 113 | }; |
| 114 | |
Herb Derby | 3721688 | 2019-06-13 17:24:24 -0400 | [diff] [blame] | 115 | struct SkGlyphPrototype; |
Herb Derby | 8219163 | 2018-10-24 14:49:26 -0400 | [diff] [blame] | 116 | |
Herb Derby | 3721688 | 2019-06-13 17:24:24 -0400 | [diff] [blame] | 117 | class SkGlyph { |
Herb Derby | 8219163 | 2018-10-24 14:49:26 -0400 | [diff] [blame] | 118 | public: |
Herb Derby | 8207b64 | 2019-05-23 11:35:56 -0400 | [diff] [blame] | 119 | static constexpr SkFixed kSubpixelRound = SK_FixedHalf >> SkPackedGlyphID::kSubBits; |
Herb Derby | 8219163 | 2018-10-24 14:49:26 -0400 | [diff] [blame] | 120 | |
Herb Derby | 793818b | 2019-06-25 17:10:11 -0400 | [diff] [blame^] | 121 | constexpr explicit SkGlyph(SkPackedGlyphID id) : fID{id} { } |
Herb Derby | 3721688 | 2019-06-13 17:24:24 -0400 | [diff] [blame] | 122 | explicit SkGlyph(const SkGlyphPrototype& p); |
| 123 | |
Herb Derby | e713a3c | 2019-06-11 14:32:06 -0400 | [diff] [blame] | 124 | SkVector advanceVector() const { return SkVector{fAdvanceX, fAdvanceY}; } |
| 125 | SkScalar advanceX() const { return fAdvanceX; } |
| 126 | SkScalar advanceY() const { return fAdvanceY; } |
| 127 | |
Herb Derby | 8219163 | 2018-10-24 14:49:26 -0400 | [diff] [blame] | 128 | SkGlyphID getGlyphID() const { return fID.code(); } |
| 129 | SkPackedGlyphID getPackedID() const { return fID; } |
| 130 | SkFixed getSubXFixed() const { return fID.getSubXFixed(); } |
| 131 | SkFixed getSubYFixed() const { return fID.getSubYFixed(); } |
| 132 | |
Herb Derby | 8219163 | 2018-10-24 14:49:26 -0400 | [diff] [blame] | 133 | size_t rowBytes() const; |
Herb Derby | 8219163 | 2018-10-24 14:49:26 -0400 | [diff] [blame] | 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 | |
Herb Derby | 990bfc7 | 2019-04-12 15:48:56 -0400 | [diff] [blame] | 141 | SkMask mask() const; |
Herb Derby | 8219163 | 2018-10-24 14:49:26 -0400 | [diff] [blame] | 142 | |
Herb Derby | c48879e | 2019-04-11 15:22:38 -0400 | [diff] [blame] | 143 | SkMask mask(SkPoint position) const; |
| 144 | |
Herb Derby | 9b06f21 | 2019-06-21 14:25:47 -0400 | [diff] [blame] | 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 | |
Herb Derby | 7019060 | 2019-06-24 14:53:59 -0400 | [diff] [blame] | 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 | |
Herb Derby | 9b06f21 | 2019-06-21 14:25:47 -0400 | [diff] [blame] | 158 | // Returns true if the image has been set. |
| 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. |
| 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 |
Herb Derby | f0e7581 | 2019-06-12 11:14:50 -0400 | [diff] [blame] | 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); |
Herb Derby | f4958ce | 2018-11-27 13:17:02 -0500 | [diff] [blame] | 183 | |
Herb Derby | f0e7581 | 2019-06-12 11:14:50 -0400 | [diff] [blame] | 184 | // Returns true if that path has been set. |
| 185 | bool setPathHasBeenCalled() const { return fPathData != nullptr; } |
Herbert Derby | 7218f1f | 2018-11-30 11:15:46 -0500 | [diff] [blame] | 186 | |
Herb Derby | f0e7581 | 2019-06-12 11:14:50 -0400 | [diff] [blame] | 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; |
Herb Derby | 5dd7f84 | 2019-04-16 11:20:38 -0400 | [diff] [blame] | 190 | |
Herb Derby | 3721688 | 2019-06-13 17:24:24 -0400 | [diff] [blame] | 191 | // Format |
| 192 | bool isColor() const { return fMaskFormat == SkMask::kARGB32_Format; } |
| 193 | SkMask::Format maskFormat() const { return static_cast<SkMask::Format>(fMaskFormat); } |
Herb Derby | 9b06f21 | 2019-06-21 14:25:47 -0400 | [diff] [blame] | 194 | size_t formatAlignment() const; |
Herb Derby | 3721688 | 2019-06-13 17:24:24 -0400 | [diff] [blame] | 195 | |
Herb Derby | 71f2eb7 | 2019-06-19 15:57:39 -0400 | [diff] [blame] | 196 | // Bounds |
| 197 | int maxDimension() const { return std::max(fWidth, fHeight); } |
| 198 | SkIRect iRect() const { return SkIRect::MakeXYWH(fLeft, fTop, fWidth, fHeight); } |
| 199 | SkRect rect() const { return SkRect::MakeXYWH(fLeft, fTop, fWidth, fHeight); } |
| 200 | int left() const { return fLeft; } |
| 201 | int top() const { return fTop; } |
| 202 | int width() const { return fWidth; } |
| 203 | int height() const { return fHeight; } |
| 204 | bool isEmpty() const { |
| 205 | // fHeight == 0 -> fWidth == 0; |
| 206 | SkASSERT(fHeight != 0 || fWidth == 0); |
| 207 | return fWidth == 0; |
Herb Derby | a519999 | 2019-04-09 14:15:14 +0000 | [diff] [blame] | 208 | } |
Herb Derby | 9b06f21 | 2019-06-21 14:25:47 -0400 | [diff] [blame] | 209 | bool imageTooLarge() const { return fWidth >= kMaxGlyphWidth; } |
Herb Derby | a519999 | 2019-04-09 14:15:14 +0000 | [diff] [blame] | 210 | |
Herb Derby | 11697dc | 2019-06-06 11:50:42 -0400 | [diff] [blame] | 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 | |
Herb Derby | 8219163 | 2018-10-24 14:49:26 -0400 | [diff] [blame] | 220 | private: |
Herb Derby | e713a3c | 2019-06-11 14:32:06 -0400 | [diff] [blame] | 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. |
Herb Derby | 3721688 | 2019-06-13 17:24:24 -0400 | [diff] [blame] | 224 | friend class RandomScalerContext; |
| 225 | friend class SkScalerContext; |
| 226 | friend class SkScalerContextProxy; |
| 227 | friend class SkScalerContext_Empty; |
Herb Derby | e713a3c | 2019-06-11 14:32:06 -0400 | [diff] [blame] | 228 | friend class SkScalerContext_FreeType; |
Herb Derby | 3721688 | 2019-06-13 17:24:24 -0400 | [diff] [blame] | 229 | friend class SkScalerContext_FreeType_Base; |
Herb Derby | cc5dc01 | 2019-06-11 13:48:41 -0400 | [diff] [blame] | 230 | friend class SkScalerContext_DW; |
Herb Derby | e713a3c | 2019-06-11 14:32:06 -0400 | [diff] [blame] | 231 | friend class SkScalerContext_GDI; |
| 232 | friend class SkScalerContext_Mac; |
| 233 | friend class SkStrikeClient; |
Herb Derby | 3721688 | 2019-06-13 17:24:24 -0400 | [diff] [blame] | 234 | friend class SkStrikeServer; |
Herb Derby | e713a3c | 2019-06-11 14:32:06 -0400 | [diff] [blame] | 235 | friend class SkTestScalerContext; |
| 236 | friend class SkTestSVGScalerContext; |
| 237 | friend class TestSVGTypeface; |
| 238 | friend class TestTypeface; |
Herb Derby | f6fca26 | 2019-01-09 15:13:54 -0500 | [diff] [blame] | 239 | |
Herb Derby | 9b06f21 | 2019-06-21 14:25:47 -0400 | [diff] [blame] | 240 | static constexpr uint16_t kMaxGlyphWidth = 1u << 13u; |
| 241 | |
caryclark | 0449bcf | 2016-02-09 13:25:45 -0800 | [diff] [blame] | 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. |
Herb Derby | 3721688 | 2019-06-13 17:24:24 -0400 | [diff] [blame] | 246 | // If interval[0] >= interval[1], no intersection was found. |
caryclark | 0449bcf | 2016-02-09 13:25:45 -0800 | [diff] [blame] | 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 { |
Herbert Derby | 9bd8346 | 2018-11-30 15:40:55 -0500 | [diff] [blame] | 254 | Intercept* fIntercept{nullptr}; |
| 255 | SkPath fPath; |
| 256 | bool fHasPath{false}; |
caryclark | 0449bcf | 2016-02-09 13:25:45 -0800 | [diff] [blame] | 257 | }; |
| 258 | |
Herb Derby | 793818b | 2019-06-25 17:10:11 -0400 | [diff] [blame^] | 259 | size_t allocImage(SkArenaAlloc* alloc); |
| 260 | |
| 261 | // path == nullptr indicates that there is no path. |
Herb Derby | f0e7581 | 2019-06-12 11:14:50 -0400 | [diff] [blame] | 262 | void installPath(SkArenaAlloc* alloc, const SkPath* path); |
| 263 | |
Herb Derby | 793818b | 2019-06-25 17:10:11 -0400 | [diff] [blame^] | 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 | |
Herb Derby | f0e7581 | 2019-06-12 11:14:50 -0400 | [diff] [blame] | 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 | |
Herb Derby | e713a3c | 2019-06-11 14:32:06 -0400 | [diff] [blame] | 280 | // The advance for this glyph. |
| 281 | float fAdvanceX = 0, |
| 282 | fAdvanceY = 0; |
| 283 | |
Herb Derby | 3721688 | 2019-06-13 17:24:24 -0400 | [diff] [blame] | 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 | |
Herb Derby | cc5dc01 | 2019-06-11 13:48:41 -0400 | [diff] [blame] | 289 | // Used by the DirectWrite scaler to track state. |
| 290 | int8_t fForceBW = 0; |
| 291 | |
Herb Derby | 793818b | 2019-06-25 17:10:11 -0400 | [diff] [blame^] | 292 | const SkPackedGlyphID fID; |
bungeman@google.com | bbe5013 | 2012-07-24 20:33:21 +0000 | [diff] [blame] | 293 | }; |
bungeman@google.com | bbe5013 | 2012-07-24 20:33:21 +0000 | [diff] [blame] | 294 | |
Herb Derby | 3721688 | 2019-06-13 17:24:24 -0400 | [diff] [blame] | 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 | |
Herb Derby | 9b06f21 | 2019-06-21 14:25:47 -0400 | [diff] [blame] | 311 | bool forceBW = false; |
Herb Derby | 3721688 | 2019-06-13 17:24:24 -0400 | [diff] [blame] | 312 | }; |
| 313 | |
bungeman@google.com | bbe5013 | 2012-07-24 20:33:21 +0000 | [diff] [blame] | 314 | #endif |