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 "include/private/SkVx.h" 17 #include "src/core/SkMask.h" 18 19 class SkArenaAlloc; 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 kSubPixelX = 0u, 36 kGlyphID = kSubPixelPosLen, 37 kSubPixelY = 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 50 static constexpr SkScalar kSubpixelRound = 1.f / (1u << (SkPackedGlyphID::kSubPixelPosLen + 1)); 51 52 static constexpr SkIPoint kXYFieldMask{kSubPixelPosMask << kSubPixelX, 53 kSubPixelPosMask << kSubPixelY}; 54 SkPackedGlyphIDSkPackedGlyphID55 constexpr explicit SkPackedGlyphID(SkGlyphID glyphID) 56 : fID{(uint32_t)glyphID << kGlyphID} { } 57 SkPackedGlyphIDSkPackedGlyphID58 constexpr SkPackedGlyphID(SkGlyphID glyphID, SkFixed x, SkFixed y) 59 : fID {PackIDXY(glyphID, x, y)} { } 60 SkPackedGlyphIDSkPackedGlyphID61 constexpr SkPackedGlyphID(SkGlyphID glyphID, uint32_t x, uint32_t y) 62 : fID {PackIDSubXSubY(glyphID, x, y)} { } 63 SkPackedGlyphIDSkPackedGlyphID64 SkPackedGlyphID(SkGlyphID glyphID, SkPoint pt, SkIPoint mask) 65 : fID{PackIDSkPoint(glyphID, pt, mask)} { } 66 SkPackedGlyphIDSkPackedGlyphID67 constexpr explicit SkPackedGlyphID(uint32_t v) : fID{v & kMaskAll} { } 68 SkPackedGlyphIDSkPackedGlyphID69 constexpr SkPackedGlyphID() : fID{kImpossibleID} {} 70 71 bool operator==(const SkPackedGlyphID& that) const { 72 return fID == that.fID; 73 } 74 bool operator!=(const SkPackedGlyphID& that) const { 75 return !(*this == that); 76 } 77 bool operator<(SkPackedGlyphID that) const { 78 return this->fID < that.fID; 79 } 80 glyphIDSkPackedGlyphID81 SkGlyphID glyphID() const { 82 return (fID >> kGlyphID) & kGlyphIDMask; 83 } 84 valueSkPackedGlyphID85 uint32_t value() const { 86 return fID; 87 } 88 getSubXFixedSkPackedGlyphID89 SkFixed getSubXFixed() const { 90 return this->subToFixed(kSubPixelX); 91 } 92 getSubYFixedSkPackedGlyphID93 SkFixed getSubYFixed() const { 94 return this->subToFixed(kSubPixelY); 95 } 96 hashSkPackedGlyphID97 uint32_t hash() const { 98 return SkChecksum::CheapMix(fID); 99 } 100 dumpSkPackedGlyphID101 SkString dump() const { 102 SkString str; 103 str.appendf("glyphID: %d, x: %d, y:%d", glyphID(), getSubXFixed(), getSubYFixed()); 104 return str; 105 } 106 107 private: PackIDSubXSubYSkPackedGlyphID108 static constexpr uint32_t PackIDSubXSubY(SkGlyphID glyphID, uint32_t x, uint32_t y) { 109 SkASSERT(x < (1u << kSubPixelPosLen)); 110 SkASSERT(y < (1u << kSubPixelPosLen)); 111 112 return (x << kSubPixelX) | (y << kSubPixelY) | (glyphID << kGlyphID); 113 } 114 115 // Assumptions: pt is properly rounded. mask is set for the x or y fields. 116 // 117 // A sub-pixel field is a number on the interval [2^kSubPixel, 2^(kSubPixel + kSubPixelPosLen)). 118 // Where kSubPixel is either kSubPixelX or kSubPixelY. Given a number x on [0, 1) we can 119 // generate a sub-pixel field using: 120 // sub-pixel-field = x * 2^(kSubPixel + kSubPixelPosLen) 121 // 122 // We can generate the integer sub-pixel field by &-ing the integer part of sub-filed with the 123 // sub-pixel field mask. 124 // int-sub-pixel-field = int(sub-pixel-field) & (kSubPixelPosMask << kSubPixel) 125 // 126 // The last trick is to extend the range from [0, 1) to [0, 2). The extend range is 127 // necessary because the modulo 1 calculation (pt - floor(pt)) generates numbers on [-1, 1). 128 // This does not round (floor) properly when converting to integer. Adding one to the range 129 // causes truncation and floor to be the same. Coincidentally, masking to produce the field also 130 // removes the +1. PackIDSkPointSkPackedGlyphID131 static uint32_t PackIDSkPoint(SkGlyphID glyphID, SkPoint pt, SkIPoint mask) { 132 #if 0 133 // TODO: why does this code not work on GCC 8.3 x86 Debug builds? 134 using namespace skvx; 135 using XY = Vec<2, float>; 136 using SubXY = Vec<2, int>; 137 138 const XY magic = {1.f * (1u << (kSubPixelPosLen + kSubPixelX)), 139 1.f * (1u << (kSubPixelPosLen + kSubPixelY))}; 140 XY pos{pt.x(), pt.y()}; 141 XY subPos = (pos - floor(pos)) + 1.0f; 142 SubXY sub = cast<int>(subPos * magic) & SubXY{mask.x(), mask.y()}; 143 #else 144 const float magicX = 1.f * (1u << (kSubPixelPosLen + kSubPixelX)), 145 magicY = 1.f * (1u << (kSubPixelPosLen + kSubPixelY)); 146 147 float x = pt.x(), 148 y = pt.y(); 149 x = (x - floorf(x)) + 1.0f; 150 y = (y - floorf(y)) + 1.0f; 151 int sub[] = { 152 (int)(x * magicX) & mask.x(), 153 (int)(y * magicY) & mask.y(), 154 }; 155 #endif 156 157 SkASSERT(sub[0] / (1u << kSubPixelX) < (1u << kSubPixelPosLen)); 158 SkASSERT(sub[1] / (1u << kSubPixelY) < (1u << kSubPixelPosLen)); 159 return (glyphID << kGlyphID) | sub[0] | sub[1]; 160 } 161 PackIDXYSkPackedGlyphID162 static constexpr uint32_t PackIDXY(SkGlyphID glyphID, SkFixed x, SkFixed y) { 163 return PackIDSubXSubY(glyphID, FixedToSub(x), FixedToSub(y)); 164 } 165 FixedToSubSkPackedGlyphID166 static constexpr uint32_t FixedToSub(SkFixed n) { 167 return ((uint32_t)n >> kFixedPointSubPixelPosBits) & kSubPixelPosMask; 168 } 169 subToFixedSkPackedGlyphID170 constexpr SkFixed subToFixed(uint32_t subPixelPosBit) const { 171 uint32_t subPixelPosition = (fID >> subPixelPosBit) & kSubPixelPosMask; 172 return subPixelPosition << kFixedPointSubPixelPosBits; 173 } 174 175 uint32_t fID; 176 }; 177 178 struct SkGlyphPrototype; 179 180 class SkGlyph { 181 public: 182 // SkGlyph() is used for testing. SkGlyph()183 constexpr SkGlyph() : fID{SkPackedGlyphID()} { } SkGlyph(SkPackedGlyphID id)184 constexpr explicit SkGlyph(SkPackedGlyphID id) : fID{id} { } 185 advanceVector()186 SkVector advanceVector() const { return SkVector{fAdvanceX, fAdvanceY}; } advanceX()187 SkScalar advanceX() const { return fAdvanceX; } advanceY()188 SkScalar advanceY() const { return fAdvanceY; } 189 getGlyphID()190 SkGlyphID getGlyphID() const { return fID.glyphID(); } getPackedID()191 SkPackedGlyphID getPackedID() const { return fID; } getSubXFixed()192 SkFixed getSubXFixed() const { return fID.getSubXFixed(); } getSubYFixed()193 SkFixed getSubYFixed() const { return fID.getSubYFixed(); } 194 195 size_t rowBytes() const; 196 size_t rowBytesUsingFormat(SkMask::Format format) const; 197 198 // Call this to set all of the metrics fields to 0 (e.g. if the scaler 199 // encounters an error measuring a glyph). Note: this does not alter the 200 // fImage, fPath, fID, fMaskFormat fields. 201 void zeroMetrics(); 202 203 SkMask mask() const; 204 205 SkMask mask(SkPoint position) const; 206 207 // Image 208 // If we haven't already tried to associate an image with this glyph 209 // (i.e. setImageHasBeenCalled() returns false), then use the 210 // SkScalerContext or const void* argument to set the image. 211 bool setImage(SkArenaAlloc* alloc, SkScalerContext* scalerContext); 212 bool setImage(SkArenaAlloc* alloc, const void* image); 213 214 // Merge the from glyph into this glyph using alloc to allocate image data. Return true if 215 // image data was allocated. If the image for this glyph has not been initialized, then copy 216 // the width, height, top, left, format, and image into this glyph making a copy of the image 217 // using the alloc. 218 bool setMetricsAndImage(SkArenaAlloc* alloc, const SkGlyph& from); 219 220 // Returns true if the image has been set. setImageHasBeenCalled()221 bool setImageHasBeenCalled() const { 222 return fImage != nullptr || this->isEmpty() || this->imageTooLarge(); 223 } 224 225 // Return a pointer to the path if the image exists, otherwise return nullptr. image()226 const void* image() const { SkASSERT(this->setImageHasBeenCalled()); return fImage; } 227 228 // Return the size of the image. 229 size_t imageSize() const; 230 231 // Path 232 // If we haven't already tried to associate a path to this glyph 233 // (i.e. setPathHasBeenCalled() returns false), then use the 234 // SkScalerContext or SkPath argument to try to do so. N.B. this 235 // may still result in no path being associated with this glyph, 236 // e.g. if you pass a null SkPath or the typeface is bitmap-only. 237 // 238 // This setPath() call is sticky... once you call it, the glyph 239 // stays in its state permanently, ignoring any future calls. 240 // 241 // Returns true if this is the first time you called setPath() 242 // and there actually is a path; call path() to get it. 243 bool setPath(SkArenaAlloc* alloc, SkScalerContext* scalerContext); 244 bool setPath(SkArenaAlloc* alloc, const SkPath* path); 245 246 // Returns true if that path has been set. setPathHasBeenCalled()247 bool setPathHasBeenCalled() const { return fPathData != nullptr; } 248 249 // Return a pointer to the path if it exists, otherwise return nullptr. Only works if the 250 // path was previously set. 251 const SkPath* path() const; 252 253 // Format isColor()254 bool isColor() const { return fMaskFormat == SkMask::kARGB32_Format; } maskFormat()255 SkMask::Format maskFormat() const { return static_cast<SkMask::Format>(fMaskFormat); } 256 size_t formatAlignment() const; 257 258 // Bounds maxDimension()259 int maxDimension() const { return std::max(fWidth, fHeight); } iRect()260 SkIRect iRect() const { return SkIRect::MakeXYWH(fLeft, fTop, fWidth, fHeight); } rect()261 SkRect rect() const { return SkRect::MakeXYWH(fLeft, fTop, fWidth, fHeight); } left()262 int left() const { return fLeft; } top()263 int top() const { return fTop; } width()264 int width() const { return fWidth; } height()265 int height() const { return fHeight; } isEmpty()266 bool isEmpty() const { 267 // fHeight == 0 -> fWidth == 0; 268 SkASSERT(fHeight != 0 || fWidth == 0); 269 return fWidth == 0; 270 } imageTooLarge()271 bool imageTooLarge() const { return fWidth >= kMaxGlyphWidth; } 272 273 // Make sure that the intercept information is on the glyph and return it, or return it if it 274 // already exists. 275 // * bounds - either end of the gap for the character. 276 // * scale, xPos - information about how wide the gap is. 277 // * array - accumulated gaps for many characters if not null. 278 // * count - the number of gaps. 279 void ensureIntercepts(const SkScalar bounds[2], SkScalar scale, SkScalar xPos, 280 SkScalar* array, int* count, SkArenaAlloc* alloc); 281 282 private: 283 // There are two sides to an SkGlyph, the scaler side (things that create glyph data) have 284 // access to all the fields. Scalers are assumed to maintain all the SkGlyph invariants. The 285 // consumer side has a tighter interface. 286 friend class RandomScalerContext; 287 friend class SkScalerContext; 288 friend class SkScalerContextProxy; 289 friend class SkScalerContext_Empty; 290 friend class SkScalerContext_FreeType; 291 friend class SkScalerContext_FreeType_Base; 292 friend class SkScalerContext_DW; 293 friend class SkScalerContext_GDI; 294 friend class SkScalerContext_Mac; 295 friend class SkStrikeClient; 296 friend class SkStrikeServer; 297 friend class SkTestScalerContext; 298 friend class SkTestSVGScalerContext; 299 friend class TestSVGTypeface; 300 friend class TestTypeface; 301 302 static constexpr uint16_t kMaxGlyphWidth = 1u << 13u; 303 304 // Support horizontal and vertical skipping strike-through / underlines. 305 // The caller walks the linked list looking for a match. For a horizontal underline, 306 // the fBounds contains the top and bottom of the underline. The fInterval pair contains the 307 // beginning and end of of the intersection of the bounds and the glyph's path. 308 // If interval[0] >= interval[1], no intersection was found. 309 struct Intercept { 310 Intercept* fNext; 311 SkScalar fBounds[2]; // for horz underlines, the boundaries in Y 312 SkScalar fInterval[2]; // the outside intersections of the axis and the glyph 313 }; 314 315 struct PathData { 316 Intercept* fIntercept{nullptr}; 317 SkPath fPath; 318 bool fHasPath{false}; 319 }; 320 321 size_t allocImage(SkArenaAlloc* alloc); 322 323 // path == nullptr indicates that there is no path. 324 void installPath(SkArenaAlloc* alloc, const SkPath* path); 325 326 // The width and height of the glyph mask. 327 uint16_t fWidth = 0, 328 fHeight = 0; 329 330 // The offset from the glyphs origin on the baseline to the top left of the glyph mask. 331 int16_t fTop = 0, 332 fLeft = 0; 333 334 // fImage must remain null if the glyph is empty or if width > kMaxGlyphWidth. 335 void* fImage = nullptr; 336 337 // Path data has tricky state. If the glyph isEmpty, then fPathData should always be nullptr, 338 // else if fPathData is not null, then a path has been requested. The fPath field of fPathData 339 // may still be null after the request meaning that there is no path for this glyph. 340 PathData* fPathData = nullptr; 341 342 // The advance for this glyph. 343 float fAdvanceX = 0, 344 fAdvanceY = 0; 345 346 // This is a combination of SkMask::Format and SkGlyph state. The SkGlyph can be in one of two 347 // states, just the advances have been calculated, and all the metrics are available. The 348 // illegal mask format is used to signal that only the advances are available. 349 uint8_t fMaskFormat = MASK_FORMAT_UNKNOWN; 350 351 // Used by the DirectWrite scaler to track state. 352 int8_t fForceBW = 0; 353 354 const SkPackedGlyphID fID; 355 }; 356 357 #endif 358