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 "SkArenaAlloc.h" 12 #include "SkChecksum.h" 13 #include "SkFixed.h" 14 #include "SkMask.h" 15 #include "SkTypes.h" 16 17 18 class SkPath; 19 class SkGlyphCache; 20 21 // needs to be != to any valid SkMask::Format 22 #define MASK_FORMAT_UNKNOWN (0xFF) 23 #define MASK_FORMAT_JUST_ADVANCE MASK_FORMAT_UNKNOWN 24 25 #define kMaxGlyphWidth (1<<13) 26 27 /** (glyph-index or unicode-point) + subpixel-pos */ 28 struct SkPackedID { 29 static constexpr uint32_t kImpossibleID = ~0; 30 enum { 31 kSubBits = 2, 32 kSubMask = ((1 << kSubBits) - 1), 33 kSubShift = 24, // must be large enough for glyphs and unichars 34 kCodeMask = ((1 << kSubShift) - 1), 35 // relative offsets for X and Y subpixel bits 36 kSubShiftX = kSubBits, 37 kSubShiftY = 0 38 }; 39 SkPackedIDSkPackedID40 SkPackedID(uint32_t code) { 41 SkASSERT(code <= kCodeMask); 42 SkASSERT(code != kImpossibleID); 43 fID = code; 44 } 45 SkPackedIDSkPackedID46 SkPackedID(uint32_t code, SkFixed x, SkFixed y) { 47 SkASSERT(code <= kCodeMask); 48 x = FixedToSub(x); 49 y = FixedToSub(y); 50 uint32_t ID = (x << (kSubShift + kSubShiftX)) | 51 (y << (kSubShift + kSubShiftY)) | 52 code; 53 SkASSERT(ID != kImpossibleID); 54 fID = ID; 55 } 56 SkPackedIDSkPackedID57 constexpr SkPackedID() : fID(kImpossibleID) {} 58 59 bool operator==(const SkPackedID& that) const { 60 return fID == that.fID; 61 } 62 bool operator!=(const SkPackedID& that) const { 63 return !(*this == that); 64 } 65 codeSkPackedID66 uint32_t code() const { 67 return fID & kCodeMask; 68 } 69 getSubXFixedSkPackedID70 SkFixed getSubXFixed() const { 71 return SubToFixed(ID2SubX(fID)); 72 } 73 getSubYFixedSkPackedID74 SkFixed getSubYFixed() const { 75 return SubToFixed(ID2SubY(fID)); 76 } 77 hashSkPackedID78 uint32_t hash() const { 79 return SkChecksum::CheapMix(fID); 80 } 81 82 // FIXME - This is needed because the Android framework directly accesses fID. 83 // Remove when fID accesses are cleaned up. 84 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK uint32_tSkPackedID85 operator uint32_t() const { return fID; } 86 #endif 87 88 private: ID2SubXSkPackedID89 static unsigned ID2SubX(uint32_t id) { 90 return id >> (kSubShift + kSubShiftX); 91 } 92 ID2SubYSkPackedID93 static unsigned ID2SubY(uint32_t id) { 94 return (id >> (kSubShift + kSubShiftY)) & kSubMask; 95 } 96 FixedToSubSkPackedID97 static unsigned FixedToSub(SkFixed n) { 98 return (n >> (16 - kSubBits)) & kSubMask; 99 } 100 SubToFixedSkPackedID101 static SkFixed SubToFixed(unsigned sub) { 102 SkASSERT(sub <= kSubMask); 103 return sub << (16 - kSubBits); 104 } 105 106 uint32_t fID; 107 }; 108 109 struct SkPackedGlyphID : public SkPackedID { SkPackedGlyphIDSkPackedGlyphID110 SkPackedGlyphID(SkGlyphID code) : SkPackedID(code) { } SkPackedGlyphIDSkPackedGlyphID111 SkPackedGlyphID(SkGlyphID code, SkFixed x, SkFixed y) : SkPackedID(code, x, y) { } SkPackedGlyphIDSkPackedGlyphID112 SkPackedGlyphID() : SkPackedID() { } codeSkPackedGlyphID113 SkGlyphID code() const { 114 return SkTo<SkGlyphID>(SkPackedID::code()); 115 } 116 }; 117 118 struct SkPackedUnicharID : public SkPackedID { SkPackedUnicharIDSkPackedUnicharID119 SkPackedUnicharID(SkUnichar code) : SkPackedID(code) { } SkPackedUnicharIDSkPackedUnicharID120 SkPackedUnicharID(SkUnichar code, SkFixed x, SkFixed y) : SkPackedID(code, x, y) { } SkPackedUnicharIDSkPackedUnicharID121 SkPackedUnicharID() : SkPackedID() { } codeSkPackedUnicharID122 SkUnichar code() const { 123 return SkTo<SkUnichar>(SkPackedID::code()); 124 } 125 }; 126 127 SK_BEGIN_REQUIRE_DENSE 128 class SkGlyph { 129 // Support horizontal and vertical skipping strike-through / underlines. 130 // The caller walks the linked list looking for a match. For a horizontal underline, 131 // the fBounds contains the top and bottom of the underline. The fInterval pair contains the 132 // beginning and end of of the intersection of the bounds and the glyph's path. 133 // If interval[0] >= interval[1], no intesection was found. 134 struct Intercept { 135 Intercept* fNext; 136 SkScalar fBounds[2]; // for horz underlines, the boundaries in Y 137 SkScalar fInterval[2]; // the outside intersections of the axis and the glyph 138 }; 139 140 struct PathData { 141 Intercept* fIntercept; 142 SkPath* fPath; 143 }; 144 145 public: 146 static const SkFixed kSubpixelRound = SK_FixedHalf >> SkPackedID::kSubBits; 147 void* fImage; 148 PathData* fPathData; 149 float fAdvanceX, fAdvanceY; 150 151 uint16_t fWidth, fHeight; 152 int16_t fTop, fLeft; 153 154 uint8_t fMaskFormat; 155 int8_t fRsbDelta, fLsbDelta; // used by auto-kerning 156 int8_t fForceBW; 157 initWithGlyphID(SkPackedGlyphID glyph_id)158 void initWithGlyphID(SkPackedGlyphID glyph_id) { 159 fID = glyph_id; 160 fImage = nullptr; 161 fPathData = nullptr; 162 fMaskFormat = MASK_FORMAT_UNKNOWN; 163 fForceBW = 0; 164 } 165 BitsToBytes(size_t bits)166 static size_t BitsToBytes(size_t bits) { 167 return (bits + 7) >> 3; 168 } 169 170 /** 171 * Compute the rowbytes for the specified width and mask-format. 172 */ ComputeRowBytes(unsigned width,SkMask::Format format)173 static unsigned ComputeRowBytes(unsigned width, SkMask::Format format) { 174 unsigned rb = width; 175 if (SkMask::kBW_Format == format) { 176 rb = BitsToBytes(rb); 177 } else if (SkMask::kARGB32_Format == format) { 178 rb <<= 2; 179 } else if (SkMask::kLCD16_Format == format) { 180 rb = SkAlign4(rb << 1); 181 } else { 182 rb = SkAlign4(rb); 183 } 184 return rb; 185 } 186 allocImage(SkArenaAlloc * alloc)187 size_t allocImage(SkArenaAlloc* alloc) { 188 size_t allocSize; 189 if (SkMask::kBW_Format == fMaskFormat) { 190 allocSize = BitsToBytes(fWidth) * fHeight; 191 fImage = alloc->makeArrayDefault<char>(allocSize); 192 } else if (SkMask::kARGB32_Format == fMaskFormat) { 193 allocSize = fWidth * fHeight; 194 fImage = alloc->makeArrayDefault<uint32_t>(fWidth * fHeight); 195 allocSize *= sizeof(uint32_t); 196 } else if (SkMask::kLCD16_Format == fMaskFormat) { 197 allocSize = SkAlign2(fWidth) * fHeight; 198 fImage = alloc->makeArrayDefault<uint16_t>(allocSize); 199 allocSize *= sizeof(uint16_t); 200 } else { 201 allocSize = SkAlign4(fWidth) * fHeight; 202 fImage = alloc->makeArrayDefault<char>(allocSize); 203 } 204 return allocSize; 205 } 206 rowBytes()207 unsigned rowBytes() const { 208 return ComputeRowBytes(fWidth, (SkMask::Format)fMaskFormat); 209 } 210 isJustAdvance()211 bool isJustAdvance() const { 212 return MASK_FORMAT_JUST_ADVANCE == fMaskFormat; 213 } 214 isFullMetrics()215 bool isFullMetrics() const { 216 return MASK_FORMAT_JUST_ADVANCE != fMaskFormat; 217 } 218 getGlyphID()219 SkGlyphID getGlyphID() const { 220 return fID.code(); 221 } 222 getPackedID()223 SkPackedGlyphID getPackedID() const { 224 return fID; 225 } 226 getSubXFixed()227 SkFixed getSubXFixed() const { 228 return fID.getSubXFixed(); 229 } 230 getSubYFixed()231 SkFixed getSubYFixed() const { 232 return fID.getSubYFixed(); 233 } 234 235 size_t computeImageSize() const; 236 237 /** Call this to set all of the metrics fields to 0 (e.g. if the scaler 238 encounters an error measuring a glyph). Note: this does not alter the 239 fImage, fPath, fID, fMaskFormat fields. 240 */ 241 void zeroMetrics(); 242 243 void toMask(SkMask* mask) const; 244 245 class HashTraits { 246 public: GetKey(const SkGlyph & glyph)247 static SkPackedGlyphID GetKey(const SkGlyph& glyph) { 248 return glyph.fID; 249 } Hash(SkPackedGlyphID glyphId)250 static uint32_t Hash(SkPackedGlyphID glyphId) { 251 return glyphId.hash(); 252 } 253 }; 254 255 private: 256 // TODO(herb) remove friend statement after SkGlyphCache cleanup. 257 friend class SkGlyphCache; 258 259 // FIXME - This is needed because the Android frame work directly accesses fID. 260 // Remove when fID accesses are cleaned up. 261 #ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 262 public: 263 #endif 264 SkPackedGlyphID fID; 265 }; 266 SK_END_REQUIRE_DENSE 267 268 #endif 269