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 "SkChecksum.h" 12 #include "SkFixed.h" 13 #include "SkMask.h" 14 #include "SkPath.h" 15 #include "SkTo.h" 16 #include "SkTypes.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 #define kMaxGlyphWidth (1<<13) 27 28 /** (glyph-index or unicode-point) + subpixel-pos */ 29 struct SkPackedID { 30 static constexpr uint32_t kImpossibleID = ~0; 31 enum { 32 kSubBits = 2, 33 kSubMask = ((1 << kSubBits) - 1), 34 kSubShift = 24, // must be large enough for glyphs and unichars 35 kCodeMask = ((1 << kSubShift) - 1), 36 // relative offsets for X and Y subpixel bits 37 kSubShiftX = kSubBits, 38 kSubShiftY = 0 39 }; 40 SkPackedIDSkPackedID41 SkPackedID(uint32_t code) { 42 SkASSERT(code <= kCodeMask); 43 SkASSERT(code != kImpossibleID); 44 fID = code; 45 } 46 SkPackedIDSkPackedID47 SkPackedID(uint32_t code, SkFixed x, SkFixed y) { 48 SkASSERT(code <= kCodeMask); 49 x = FixedToSub(x); 50 y = FixedToSub(y); 51 uint32_t ID = (x << (kSubShift + kSubShiftX)) | 52 (y << (kSubShift + kSubShiftY)) | 53 code; 54 SkASSERT(ID != kImpossibleID); 55 fID = ID; 56 } 57 SkPackedIDSkPackedID58 constexpr SkPackedID() : fID(kImpossibleID) {} 59 60 bool operator==(const SkPackedID& that) const { 61 return fID == that.fID; 62 } 63 bool operator!=(const SkPackedID& that) const { 64 return !(*this == that); 65 } 66 bool operator<(SkPackedID that) const { 67 return this->fID < that.fID; 68 } 69 codeSkPackedID70 uint32_t code() const { 71 return fID & kCodeMask; 72 } 73 valueSkPackedID74 uint32_t value() const { 75 return fID; 76 } 77 getSubXFixedSkPackedID78 SkFixed getSubXFixed() const { 79 return SubToFixed(ID2SubX(fID)); 80 } 81 getSubYFixedSkPackedID82 SkFixed getSubYFixed() const { 83 return SubToFixed(ID2SubY(fID)); 84 } 85 hashSkPackedID86 uint32_t hash() const { 87 return SkChecksum::CheapMix(fID); 88 } 89 dumpSkPackedID90 SkString dump() const { 91 SkString str; 92 str.appendf("code: %d, x: %d, y:%d", code(), getSubXFixed(), getSubYFixed()); 93 return str; 94 } 95 96 private: ID2SubXSkPackedID97 static unsigned ID2SubX(uint32_t id) { 98 return id >> (kSubShift + kSubShiftX); 99 } 100 ID2SubYSkPackedID101 static unsigned ID2SubY(uint32_t id) { 102 return (id >> (kSubShift + kSubShiftY)) & kSubMask; 103 } 104 FixedToSubSkPackedID105 static unsigned FixedToSub(SkFixed n) { 106 return (n >> (16 - kSubBits)) & kSubMask; 107 } 108 SubToFixedSkPackedID109 static SkFixed SubToFixed(unsigned sub) { 110 SkASSERT(sub <= kSubMask); 111 return sub << (16 - kSubBits); 112 } 113 114 uint32_t fID; 115 }; 116 117 struct SkPackedGlyphID : public SkPackedID { SkPackedGlyphIDSkPackedGlyphID118 SkPackedGlyphID(SkGlyphID code) : SkPackedID(code) { } SkPackedGlyphIDSkPackedGlyphID119 SkPackedGlyphID(SkGlyphID code, SkFixed x, SkFixed y) : SkPackedID(code, x, y) { } SkPackedGlyphIDSkPackedGlyphID120 SkPackedGlyphID(SkGlyphID code, SkIPoint pt) : SkPackedID(code, pt.x(), pt.y()) { } 121 constexpr SkPackedGlyphID() = default; codeSkPackedGlyphID122 SkGlyphID code() const { 123 return SkTo<SkGlyphID>(SkPackedID::code()); 124 } 125 }; 126 127 struct SkPackedUnicharID : public SkPackedID { SkPackedUnicharIDSkPackedUnicharID128 SkPackedUnicharID(SkUnichar code) : SkPackedID(code) { } SkPackedUnicharIDSkPackedUnicharID129 SkPackedUnicharID(SkUnichar code, SkFixed x, SkFixed y) : SkPackedID(code, x, y) { } 130 constexpr SkPackedUnicharID() = default; codeSkPackedUnicharID131 SkUnichar code() const { 132 return SkTo<SkUnichar>(SkPackedID::code()); 133 } 134 }; 135 136 class SkGlyph { 137 struct PathData; 138 139 public: SkGlyph(SkPackedGlyphID id)140 constexpr explicit SkGlyph(SkPackedGlyphID id) : fID{id} {} 141 static constexpr SkFixed kSubpixelRound = SK_FixedHalf >> SkPackedID::kSubBits; 142 isEmpty()143 bool isEmpty() const { return fWidth == 0 || fHeight == 0; } isJustAdvance()144 bool isJustAdvance() const { return MASK_FORMAT_JUST_ADVANCE == fMaskFormat; } isFullMetrics()145 bool isFullMetrics() const { return MASK_FORMAT_JUST_ADVANCE != fMaskFormat; } getGlyphID()146 SkGlyphID getGlyphID() const { return fID.code(); } getPackedID()147 SkPackedGlyphID getPackedID() const { return fID; } getSubXFixed()148 SkFixed getSubXFixed() const { return fID.getSubXFixed(); } getSubYFixed()149 SkFixed getSubYFixed() const { return fID.getSubYFixed(); } 150 151 size_t formatAlignment() const; 152 size_t allocImage(SkArenaAlloc* alloc); 153 size_t rowBytes() const; 154 size_t computeImageSize() const; 155 size_t rowBytesUsingFormat(SkMask::Format format) const; 156 157 // Call this to set all of the metrics fields to 0 (e.g. if the scaler 158 // encounters an error measuring a glyph). Note: this does not alter the 159 // fImage, fPath, fID, fMaskFormat fields. 160 void zeroMetrics(); 161 162 void toMask(SkMask* mask) const; 163 164 SkPath* addPath(SkScalerContext*, SkArenaAlloc*); 165 path()166 SkPath* path() const { 167 return fPathData != nullptr && fPathData->fHasPath ? &fPathData->fPath : nullptr; 168 } 169 170 // Returns the size allocated on the arena. 171 size_t copyImageData(const SkGlyph& from, SkArenaAlloc* alloc); 172 173 void* fImage = nullptr; 174 175 // Path data has tricky state. If the glyph isEmpty, then fPathData should always be nullptr, 176 // else if fPathData is not null, then a path has been requested. The fPath field of fPathData 177 // may still be null after the request meaning that there is no path for this glyph. 178 PathData* fPathData = nullptr; 179 180 // The advance for this glyph. 181 float fAdvanceX = 0, 182 fAdvanceY = 0; 183 184 // The width and height of the glyph mask. 185 uint16_t fWidth = 0, 186 fHeight = 0; 187 188 // The offset from the glyphs origin on the baseline to the top left of the glyph mask. 189 int16_t fTop = 0, 190 fLeft = 0; 191 192 // Used by the GDI scaler to track state. 193 int8_t fForceBW = 0; 194 195 // This is a combination of SkMask::Format and SkGlyph state. The SkGlyph can be in one of two 196 // states, just the advances have been calculated, and all the metrics are available. The 197 // illegal mask format is used to signal that only the advances are available. 198 uint8_t fMaskFormat = MASK_FORMAT_UNKNOWN; 199 200 private: 201 202 // Support horizontal and vertical skipping strike-through / underlines. 203 // The caller walks the linked list looking for a match. For a horizontal underline, 204 // the fBounds contains the top and bottom of the underline. The fInterval pair contains the 205 // beginning and end of of the intersection of the bounds and the glyph's path. 206 // If interval[0] >= interval[1], no intesection was found. 207 struct Intercept { 208 Intercept* fNext; 209 SkScalar fBounds[2]; // for horz underlines, the boundaries in Y 210 SkScalar fInterval[2]; // the outside intersections of the axis and the glyph 211 }; 212 213 struct PathData { 214 Intercept* fIntercept{nullptr}; 215 SkPath fPath; 216 bool fHasPath{false}; 217 }; 218 219 // TODO(herb) remove friend statement after SkStrike cleanup. 220 friend class SkStrike; 221 SkPackedGlyphID fID; 222 }; 223 224 #endif 225