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