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 18class SkPath; 19class 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 */ 28struct 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 40 SkPackedID(uint32_t code) { 41 SkASSERT(code <= kCodeMask); 42 SkASSERT(code != kImpossibleID); 43 fID = code; 44 } 45 46 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 57 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 66 uint32_t code() const { 67 return fID & kCodeMask; 68 } 69 70 SkFixed getSubXFixed() const { 71 return SubToFixed(ID2SubX(fID)); 72 } 73 74 SkFixed getSubYFixed() const { 75 return SubToFixed(ID2SubY(fID)); 76 } 77 78 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 85 operator uint32_t() const { return fID; } 86#endif 87 88private: 89 static unsigned ID2SubX(uint32_t id) { 90 return id >> (kSubShift + kSubShiftX); 91 } 92 93 static unsigned ID2SubY(uint32_t id) { 94 return (id >> (kSubShift + kSubShiftY)) & kSubMask; 95 } 96 97 static unsigned FixedToSub(SkFixed n) { 98 return (n >> (16 - kSubBits)) & kSubMask; 99 } 100 101 static SkFixed SubToFixed(unsigned sub) { 102 SkASSERT(sub <= kSubMask); 103 return sub << (16 - kSubBits); 104 } 105 106 uint32_t fID; 107}; 108 109struct SkPackedGlyphID : public SkPackedID { 110 SkPackedGlyphID(SkGlyphID code) : SkPackedID(code) { } 111 SkPackedGlyphID(SkGlyphID code, SkFixed x, SkFixed y) : SkPackedID(code, x, y) { } 112 SkPackedGlyphID() : SkPackedID() { } 113 SkGlyphID code() const { 114 return SkTo<SkGlyphID>(SkPackedID::code()); 115 } 116}; 117 118struct SkPackedUnicharID : public SkPackedID { 119 SkPackedUnicharID(SkUnichar code) : SkPackedID(code) { } 120 SkPackedUnicharID(SkUnichar code, SkFixed x, SkFixed y) : SkPackedID(code, x, y) { } 121 SkPackedUnicharID() : SkPackedID() { } 122 SkUnichar code() const { 123 return SkTo<SkUnichar>(SkPackedID::code()); 124 } 125}; 126 127SK_BEGIN_REQUIRE_DENSE 128class 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 145public: 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 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 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 */ 173 static unsigned ComputeRowBytes(unsigned width, SkMask::Format format) { 174 unsigned rb = width; 175 switch (format) { 176 case SkMask::kBW_Format: 177 rb = BitsToBytes(rb); 178 break; 179 case SkMask::kA8_Format: 180 rb = SkAlign4(rb); 181 break; 182 case SkMask::k3D_Format: 183 rb = SkAlign4(rb); 184 break; 185 case SkMask::kARGB32_Format: 186 rb <<= 2; 187 break; 188 case SkMask::kLCD16_Format: 189 rb = SkAlign4(rb << 1); 190 break; 191 default: 192 SK_ABORT("Unknown mask format."); 193 break; 194 } 195 return rb; 196 } 197 198 size_t allocImage(SkArenaAlloc* alloc) { 199 size_t allocSize; 200 switch (static_cast<SkMask::Format>(fMaskFormat)) { 201 case SkMask::kBW_Format: 202 allocSize = BitsToBytes(fWidth) * fHeight; 203 fImage = alloc->makeArrayDefault<char>(allocSize); 204 break; 205 case SkMask::kA8_Format: 206 allocSize = SkAlign4(fWidth) * fHeight; 207 fImage = alloc->makeArrayDefault<char>(allocSize); 208 break; 209 case SkMask::k3D_Format: 210 allocSize = SkAlign4(fWidth) * fHeight * 3; 211 fImage = alloc->makeArrayDefault<char>(allocSize); 212 break; 213 case SkMask::kARGB32_Format: 214 allocSize = fWidth * fHeight; 215 fImage = alloc->makeArrayDefault<uint32_t>(fWidth * fHeight); 216 allocSize *= sizeof(uint32_t); 217 break; 218 case SkMask::kLCD16_Format: 219 allocSize = SkAlign2(fWidth) * fHeight; 220 fImage = alloc->makeArrayDefault<uint16_t>(allocSize); 221 allocSize *= sizeof(uint16_t); 222 break; 223 default: 224 SK_ABORT("Unknown mask format."); 225 break; 226 } 227 return allocSize; 228 } 229 230 unsigned rowBytes() const { 231 return ComputeRowBytes(fWidth, (SkMask::Format)fMaskFormat); 232 } 233 234 bool isJustAdvance() const { 235 return MASK_FORMAT_JUST_ADVANCE == fMaskFormat; 236 } 237 238 bool isFullMetrics() const { 239 return MASK_FORMAT_JUST_ADVANCE != fMaskFormat; 240 } 241 242 SkGlyphID getGlyphID() const { 243 return fID.code(); 244 } 245 246 SkPackedGlyphID getPackedID() const { 247 return fID; 248 } 249 250 SkFixed getSubXFixed() const { 251 return fID.getSubXFixed(); 252 } 253 254 SkFixed getSubYFixed() const { 255 return fID.getSubYFixed(); 256 } 257 258 size_t computeImageSize() const; 259 260 /** Call this to set all of the metrics fields to 0 (e.g. if the scaler 261 encounters an error measuring a glyph). Note: this does not alter the 262 fImage, fPath, fID, fMaskFormat fields. 263 */ 264 void zeroMetrics(); 265 266 void toMask(SkMask* mask) const; 267 268 class HashTraits { 269 public: 270 static SkPackedGlyphID GetKey(const SkGlyph& glyph) { 271 return glyph.fID; 272 } 273 static uint32_t Hash(SkPackedGlyphID glyphId) { 274 return glyphId.hash(); 275 } 276 }; 277 278 private: 279 // TODO(herb) remove friend statement after SkGlyphCache cleanup. 280 friend class SkGlyphCache; 281 282// FIXME - This is needed because the Android frame work directly accesses fID. 283// Remove when fID accesses are cleaned up. 284#ifdef SK_BUILD_FOR_ANDROID_FRAMEWORK 285 public: 286#endif 287 SkPackedGlyphID fID; 288}; 289SK_END_REQUIRE_DENSE 290 291#endif 292