Home | History | Annotate | Download | only in core
      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 
     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 
     88 private:
     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 
    109 struct 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 
    118 struct 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 
    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 
    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 };
    289 SK_END_REQUIRE_DENSE
    290 
    291 #endif
    292