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