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 41 SkPackedID(uint32_t code) { 42 SkASSERT(code <= kCodeMask); 43 SkASSERT(code != kImpossibleID); 44 fID = code; 45 } 46 47 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 58 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 70 uint32_t code() const { 71 return fID & kCodeMask; 72 } 73 74 uint32_t value() const { 75 return fID; 76 } 77 78 SkFixed getSubXFixed() const { 79 return SubToFixed(ID2SubX(fID)); 80 } 81 82 SkFixed getSubYFixed() const { 83 return SubToFixed(ID2SubY(fID)); 84 } 85 86 uint32_t hash() const { 87 return SkChecksum::CheapMix(fID); 88 } 89 90 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: 97 static unsigned ID2SubX(uint32_t id) { 98 return id >> (kSubShift + kSubShiftX); 99 } 100 101 static unsigned ID2SubY(uint32_t id) { 102 return (id >> (kSubShift + kSubShiftY)) & kSubMask; 103 } 104 105 static unsigned FixedToSub(SkFixed n) { 106 return (n >> (16 - kSubBits)) & kSubMask; 107 } 108 109 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 { 118 SkPackedGlyphID(SkGlyphID code) : SkPackedID(code) { } 119 SkPackedGlyphID(SkGlyphID code, SkFixed x, SkFixed y) : SkPackedID(code, x, y) { } 120 SkPackedGlyphID(SkGlyphID code, SkIPoint pt) : SkPackedID(code, pt.x(), pt.y()) { } 121 constexpr SkPackedGlyphID() = default; 122 SkGlyphID code() const { 123 return SkTo<SkGlyphID>(SkPackedID::code()); 124 } 125 }; 126 127 class SkGlyph { 128 struct PathData; 129 130 public: 131 constexpr explicit SkGlyph(SkPackedGlyphID id) : fID{id} {} 132 static constexpr SkFixed kSubpixelRound = SK_FixedHalf >> SkPackedID::kSubBits; 133 134 bool isEmpty() const { return fWidth == 0 || fHeight == 0; } 135 bool isJustAdvance() const { return MASK_FORMAT_JUST_ADVANCE == fMaskFormat; } 136 bool isFullMetrics() const { return MASK_FORMAT_JUST_ADVANCE != fMaskFormat; } 137 SkGlyphID getGlyphID() const { return fID.code(); } 138 SkPackedGlyphID getPackedID() const { return fID; } 139 SkFixed getSubXFixed() const { return fID.getSubXFixed(); } 140 SkFixed getSubYFixed() const { return fID.getSubYFixed(); } 141 142 size_t formatAlignment() const; 143 size_t allocImage(SkArenaAlloc* alloc); 144 size_t rowBytes() const; 145 size_t computeImageSize() const; 146 size_t rowBytesUsingFormat(SkMask::Format format) const; 147 148 // Call this to set all of the metrics fields to 0 (e.g. if the scaler 149 // encounters an error measuring a glyph). Note: this does not alter the 150 // fImage, fPath, fID, fMaskFormat fields. 151 void zeroMetrics(); 152 153 void toMask(SkMask* mask) const; 154 155 SkPath* addPath(SkScalerContext*, SkArenaAlloc*); 156 157 SkPath* path() const { 158 return fPathData != nullptr && fPathData->fHasPath ? &fPathData->fPath : nullptr; 159 } 160 161 // Returns the size allocated on the arena. 162 size_t copyImageData(const SkGlyph& from, SkArenaAlloc* alloc); 163 164 void* fImage = nullptr; 165 166 // Path data has tricky state. If the glyph isEmpty, then fPathData should always be nullptr, 167 // else if fPathData is not null, then a path has been requested. The fPath field of fPathData 168 // may still be null after the request meaning that there is no path for this glyph. 169 PathData* fPathData = nullptr; 170 171 // The advance for this glyph. 172 float fAdvanceX = 0, 173 fAdvanceY = 0; 174 175 // The width and height of the glyph mask. 176 uint16_t fWidth = 0, 177 fHeight = 0; 178 179 // The offset from the glyphs origin on the baseline to the top left of the glyph mask. 180 int16_t fTop = 0, 181 fLeft = 0; 182 183 // Used by the GDI scaler to track state. 184 int8_t fForceBW = 0; 185 186 // This is a combination of SkMask::Format and SkGlyph state. The SkGlyph can be in one of two 187 // states, just the advances have been calculated, and all the metrics are available. The 188 // illegal mask format is used to signal that only the advances are available. 189 uint8_t fMaskFormat = MASK_FORMAT_UNKNOWN; 190 191 private: 192 193 // Support horizontal and vertical skipping strike-through / underlines. 194 // The caller walks the linked list looking for a match. For a horizontal underline, 195 // the fBounds contains the top and bottom of the underline. The fInterval pair contains the 196 // beginning and end of of the intersection of the bounds and the glyph's path. 197 // If interval[0] >= interval[1], no intesection was found. 198 struct Intercept { 199 Intercept* fNext; 200 SkScalar fBounds[2]; // for horz underlines, the boundaries in Y 201 SkScalar fInterval[2]; // the outside intersections of the axis and the glyph 202 }; 203 204 struct PathData { 205 Intercept* fIntercept{nullptr}; 206 SkPath fPath; 207 bool fHasPath{false}; 208 }; 209 210 // TODO(herb) remove friend statement after SkStrike cleanup. 211 friend class SkStrike; 212 SkPackedGlyphID fID; 213 }; 214 215 #endif 216