blob: 72957db256857673209d2552f18ed7d6de95f73d [file] [log] [blame]
bungeman@google.combbe50132012-07-24 20:33:21 +00001/*
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
herbc71239b2015-07-21 15:36:25 -070011#include "SkChecksum.h"
bungeman@google.combbe50132012-07-24 20:33:21 +000012#include "SkFixed.h"
13#include "SkMask.h"
Herbert Derby9bd83462018-11-30 15:40:55 -050014#include "SkPath.h"
Hal Canaryc640d0d2018-06-13 09:59:02 -040015#include "SkTo.h"
Herb Derby7c5a8062017-01-20 11:59:03 -050016#include "SkTypes.h"
17
Herb Derby82191632018-10-24 14:49:26 -040018class SkArenaAlloc;
herbb69d0e02015-02-25 06:47:06 -080019class SkGlyphCache;
Herb Derbyf4958ce2018-11-27 13:17:02 -050020class SkScalerContext;
bungeman@google.combbe50132012-07-24 20:33:21 +000021
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
Ben Wagner6e9ac122016-11-11 14:31:06 -050028/** (glyph-index or unicode-point) + subpixel-pos */
29struct SkPackedID {
30 static constexpr uint32_t kImpossibleID = ~0;
herbb69d0e02015-02-25 06:47:06 -080031 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
Ben Wagner6e9ac122016-11-11 14:31:06 -050041 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 }
Herb Derbyefbf00c2018-03-14 11:53:40 -040066 bool operator<(SkPackedID that) const {
67 return this->fID < that.fID;
68 }
Ben Wagner6e9ac122016-11-11 14:31:06 -050069
70 uint32_t code() const {
71 return fID & kCodeMask;
72 }
73
Herb Derby82191632018-10-24 14:49:26 -040074 uint32_t value() const {
Herb Derbyefbf00c2018-03-14 11:53:40 -040075 return fID;
76 }
77
Ben Wagner6e9ac122016-11-11 14:31:06 -050078 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
Khushal4010c792018-06-13 09:44:23 -070090 SkString dump() const {
91 SkString str;
92 str.appendf("code: %d, x: %d, y:%d", code(), getSubXFixed(), getSubYFixed());
93 return str;
94 }
95
Ben Wagner6e9ac122016-11-11 14:31:06 -050096private:
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
117struct SkPackedGlyphID : public SkPackedID {
118 SkPackedGlyphID(SkGlyphID code) : SkPackedID(code) { }
119 SkPackedGlyphID(SkGlyphID code, SkFixed x, SkFixed y) : SkPackedID(code, x, y) { }
Herb Derbyd2fec232018-08-23 18:44:45 -0400120 SkPackedGlyphID(SkGlyphID code, SkIPoint pt) : SkPackedID(code, pt.x(), pt.y()) { }
Herb Derby82191632018-10-24 14:49:26 -0400121 constexpr SkPackedGlyphID() = default;
Ben Wagner6e9ac122016-11-11 14:31:06 -0500122 SkGlyphID code() const {
123 return SkTo<SkGlyphID>(SkPackedID::code());
124 }
125};
126
127struct SkPackedUnicharID : public SkPackedID {
128 SkPackedUnicharID(SkUnichar code) : SkPackedID(code) { }
129 SkPackedUnicharID(SkUnichar code, SkFixed x, SkFixed y) : SkPackedID(code, x, y) { }
Herb Derby82191632018-10-24 14:49:26 -0400130 constexpr SkPackedUnicharID() = default;
Ben Wagner6e9ac122016-11-11 14:31:06 -0500131 SkUnichar code() const {
132 return SkTo<SkUnichar>(SkPackedID::code());
133 }
134};
135
Ben Wagner6e9ac122016-11-11 14:31:06 -0500136class SkGlyph {
Herb Derby82191632018-10-24 14:49:26 -0400137 struct PathData;
138
139public:
Herb Derby811a6722019-01-10 13:58:05 -0500140 constexpr explicit SkGlyph(SkPackedGlyphID id) : fID{id} {}
Herb Derby82191632018-10-24 14:49:26 -0400141 static constexpr SkFixed kSubpixelRound = SK_FixedHalf >> SkPackedID::kSubBits;
142
143 bool isEmpty() const { return fWidth == 0 || fHeight == 0; }
144 bool isJustAdvance() const { return MASK_FORMAT_JUST_ADVANCE == fMaskFormat; }
145 bool isFullMetrics() const { return MASK_FORMAT_JUST_ADVANCE != fMaskFormat; }
146 SkGlyphID getGlyphID() const { return fID.code(); }
147 SkPackedGlyphID getPackedID() const { return fID; }
148 SkFixed getSubXFixed() const { return fID.getSubXFixed(); }
149 SkFixed getSubYFixed() const { return fID.getSubYFixed(); }
150
Herb Derby82191632018-10-24 14:49:26 -0400151 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
Herb Derbyf4958ce2018-11-27 13:17:02 -0500164 SkPath* addPath(SkScalerContext*, SkArenaAlloc*);
165
Herbert Derby7218f1f2018-11-30 11:15:46 -0500166 SkPath* path() const {
Herbert Derby9bd83462018-11-30 15:40:55 -0500167 return fPathData != nullptr && fPathData->fHasPath ? &fPathData->fPath : nullptr;
Herbert Derby7218f1f2018-11-30 11:15:46 -0500168 }
169
Herb Derby82191632018-10-24 14:49:26 -0400170 // Returns the size allocated on the arena.
171 size_t copyImageData(const SkGlyph& from, SkArenaAlloc* alloc);
172
Herb Derby82191632018-10-24 14:49:26 -0400173 void* fImage = nullptr;
Herb Derbyf4958ce2018-11-27 13:17:02 -0500174
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.
Herb Derby82191632018-10-24 14:49:26 -0400178 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.
Herb Derbyf6fca262019-01-09 15:13:54 -0500198 uint8_t fMaskFormat = MASK_FORMAT_UNKNOWN;
Herb Derby82191632018-10-24 14:49:26 -0400199
200private:
Herb Derbyf6fca262019-01-09 15:13:54 -0500201
caryclark0449bcf2016-02-09 13:25:45 -0800202 // 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 {
Herbert Derby9bd83462018-11-30 15:40:55 -0500214 Intercept* fIntercept{nullptr};
215 SkPath fPath;
216 bool fHasPath{false};
caryclark0449bcf2016-02-09 13:25:45 -0800217 };
218
herbb69d0e02015-02-25 06:47:06 -0800219 // TODO(herb) remove friend statement after SkGlyphCache cleanup.
220 friend class SkGlyphCache;
Ben Wagner6e9ac122016-11-11 14:31:06 -0500221 SkPackedGlyphID fID;
bungeman@google.combbe50132012-07-24 20:33:21 +0000222};
bungeman@google.combbe50132012-07-24 20:33:21 +0000223
224#endif