blob: d7b5eece122366469d8c7bf2507e8ce1aadb6a9b [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef SkScalerContext_DEFINED
18#define SkScalerContext_DEFINED
19
20#include "SkMask.h"
21#include "SkMatrix.h"
22#include "SkPaint.h"
23#include "SkPath.h"
24#include "SkPoint.h"
25
26class SkDescriptor;
27class SkMaskFilter;
28class SkPathEffect;
29class SkRasterizer;
30
31// needs to be != to any valid SkMask::Format
reed@google.comd3b13bd2011-01-13 16:33:36 +000032#define MASK_FORMAT_UNKNOWN (0xFF)
33#define MASK_FORMAT_JUST_ADVANCE MASK_FORMAT_UNKNOWN
reed@android.com8a1c16f2008-12-17 15:59:43 +000034
scarybeasts@gmail.com17f694b2010-10-18 23:29:36 +000035#define kMaxGlyphWidth (1<<13)
36
reed@android.com8a1c16f2008-12-17 15:59:43 +000037struct SkGlyph {
38 void* fImage;
39 SkPath* fPath;
40 SkFixed fAdvanceX, fAdvanceY;
41
42 uint32_t fID;
43 uint16_t fWidth, fHeight;
44 int16_t fTop, fLeft;
45
46 uint8_t fMaskFormat;
47 int8_t fRsbDelta, fLsbDelta; // used by auto-kerning
reed@android.comf2b98d62010-12-20 18:26:13 +000048
49 void init(uint32_t id) {
50 fID = id;
51 fImage = NULL;
52 fPath = NULL;
reed@google.comd3b13bd2011-01-13 16:33:36 +000053 fMaskFormat = MASK_FORMAT_UNKNOWN;
reed@android.comf2b98d62010-12-20 18:26:13 +000054 }
55
reed@google.comf88d6762011-03-10 15:06:27 +000056 /**
57 * Compute the rowbytes for the specified width and mask-format.
58 */
59 static unsigned ComputeRowBytes(unsigned width, SkMask::Format format) {
60 unsigned rb = width;
61 if (SkMask::kBW_Format == format) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000062 rb = (rb + 7) >> 3;
caryclark@google.com1eeaf0b2011-06-22 13:19:43 +000063 } else if (SkMask::kARGB32_Format == format ||
64 SkMask::kLCD32_Format == format)
65 {
reed@android.comf2b98d62010-12-20 18:26:13 +000066 rb <<= 2;
reed@google.comf88d6762011-03-10 15:06:27 +000067 } else if (SkMask::kLCD16_Format == format) {
68 rb = SkAlign4(rb << 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +000069 } else {
70 rb = SkAlign4(rb);
71 }
72 return rb;
73 }
reed@google.comd3b13bd2011-01-13 16:33:36 +000074
reed@google.comf88d6762011-03-10 15:06:27 +000075 unsigned rowBytes() const {
76 return ComputeRowBytes(fWidth, (SkMask::Format)fMaskFormat);
77 }
78
reed@android.com8a1c16f2008-12-17 15:59:43 +000079 bool isJustAdvance() const {
80 return MASK_FORMAT_JUST_ADVANCE == fMaskFormat;
81 }
reed@google.comd3b13bd2011-01-13 16:33:36 +000082
reed@android.com8a1c16f2008-12-17 15:59:43 +000083 bool isFullMetrics() const {
84 return MASK_FORMAT_JUST_ADVANCE != fMaskFormat;
85 }
reed@google.comd3b13bd2011-01-13 16:33:36 +000086
reed@android.com8a1c16f2008-12-17 15:59:43 +000087 uint16_t getGlyphID() const {
88 return ID2Code(fID);
89 }
90
91 unsigned getGlyphID(unsigned baseGlyphCount) const {
92 unsigned code = ID2Code(fID);
93 SkASSERT(code >= baseGlyphCount);
94 return code - baseGlyphCount;
95 }
reed@google.comd3b13bd2011-01-13 16:33:36 +000096
reed@android.com8a1c16f2008-12-17 15:59:43 +000097 unsigned getSubX() const {
98 return ID2SubX(fID);
99 }
reed@google.comd3b13bd2011-01-13 16:33:36 +0000100
reed@android.com8a1c16f2008-12-17 15:59:43 +0000101 SkFixed getSubXFixed() const {
102 return SubToFixed(ID2SubX(fID));
103 }
reed@google.comd3b13bd2011-01-13 16:33:36 +0000104
reed@android.com8a1c16f2008-12-17 15:59:43 +0000105 SkFixed getSubYFixed() const {
106 return SubToFixed(ID2SubY(fID));
107 }
reed@google.comd3b13bd2011-01-13 16:33:36 +0000108
reed@android.com8a1c16f2008-12-17 15:59:43 +0000109 size_t computeImageSize() const;
reed@google.comd3b13bd2011-01-13 16:33:36 +0000110
reed@android.com62900b42009-02-11 15:07:19 +0000111 /** Call this to set all of the metrics fields to 0 (e.g. if the scaler
112 encounters an error measuring a glyph). Note: this does not alter the
113 fImage, fPath, fID, fMaskFormat fields.
114 */
115 void zeroMetrics();
reed@google.comd3b13bd2011-01-13 16:33:36 +0000116
reed@android.com8a1c16f2008-12-17 15:59:43 +0000117 enum {
118 kSubBits = 2,
119 kSubMask = ((1 << kSubBits) - 1),
120 kSubShift = 24, // must be large enough for glyphs and unichars
121 kCodeMask = ((1 << kSubShift) - 1),
122 // relative offsets for X and Y subpixel bits
123 kSubShiftX = kSubBits,
124 kSubShiftY = 0
125 };
126
127 static unsigned ID2Code(uint32_t id) {
128 return id & kCodeMask;
129 }
reed@google.comd3b13bd2011-01-13 16:33:36 +0000130
reed@android.com8a1c16f2008-12-17 15:59:43 +0000131 static unsigned ID2SubX(uint32_t id) {
132 return id >> (kSubShift + kSubShiftX);
133 }
reed@google.comd3b13bd2011-01-13 16:33:36 +0000134
reed@android.com8a1c16f2008-12-17 15:59:43 +0000135 static unsigned ID2SubY(uint32_t id) {
136 return (id >> (kSubShift + kSubShiftY)) & kSubMask;
137 }
reed@google.comd3b13bd2011-01-13 16:33:36 +0000138
reed@android.com8a1c16f2008-12-17 15:59:43 +0000139 static unsigned FixedToSub(SkFixed n) {
140 return (n >> (16 - kSubBits)) & kSubMask;
141 }
reed@google.comd3b13bd2011-01-13 16:33:36 +0000142
reed@android.com8a1c16f2008-12-17 15:59:43 +0000143 static SkFixed SubToFixed(unsigned sub) {
144 SkASSERT(sub <= kSubMask);
145 return sub << (16 - kSubBits);
146 }
reed@google.comd3b13bd2011-01-13 16:33:36 +0000147
reed@android.com8a1c16f2008-12-17 15:59:43 +0000148 static uint32_t MakeID(unsigned code) {
149 return code;
150 }
reed@google.comd3b13bd2011-01-13 16:33:36 +0000151
reed@android.com8a1c16f2008-12-17 15:59:43 +0000152 static uint32_t MakeID(unsigned code, SkFixed x, SkFixed y) {
153 SkASSERT(code <= kCodeMask);
154 x = FixedToSub(x);
155 y = FixedToSub(y);
156 return (x << (kSubShift + kSubShiftX)) |
157 (y << (kSubShift + kSubShiftY)) |
158 code;
159 }
reed@google.comd3b13bd2011-01-13 16:33:36 +0000160
reed@android.com8a1c16f2008-12-17 15:59:43 +0000161 void toMask(SkMask* mask) const;
agl@chromium.org309485b2009-07-21 17:41:32 +0000162
163 /** Given a glyph which is has a mask format of LCD or VerticalLCD, take
164 the A8 plane in fImage and produce a valid LCD plane from it.
165 */
166 void expandA8ToLCD() const;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000167};
168
169class SkScalerContext {
170public:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000171 enum Flags {
172 kFrameAndFill_Flag = 0x01,
173 kDevKernText_Flag = 0x02,
174 kGammaForBlack_Flag = 0x04, // illegal to set both Gamma flags
agl@chromium.org309485b2009-07-21 17:41:32 +0000175 kGammaForWhite_Flag = 0x08, // illegal to set both Gamma flags
176 // together, these two flags resulting in a two bit value which matches
177 // up with the SkPaint::Hinting enum.
reed@android.com36a4c2a2009-07-22 19:52:11 +0000178 kHintingBit1_Flag = 0x10,
179 kHintingBit2_Flag = 0x20,
agl@chromium.org13c85582010-01-04 23:56:43 +0000180 kEmbeddedBitmapText_Flag = 0x40,
senorblanco@chromium.org4526a842010-02-05 23:08:20 +0000181 kEmbolden_Flag = 0x80,
agl@chromium.orga2c71cb2010-06-17 20:49:17 +0000182 kSubpixelPositioning_Flag = 0x100,
183 kAutohinting_Flag = 0x200,
reed@google.com02b53312011-05-18 19:00:53 +0000184 // these should only ever be set if fMaskFormat is LCD
185 kLCD_Vertical_Flag = 0x400, // else Horizontal
186 kLCD_BGROrder_Flag = 0x800, // else RGB order
reed@android.com8a1c16f2008-12-17 15:59:43 +0000187 };
reed@android.come2ca2072009-07-27 16:39:38 +0000188private:
189 enum {
190 kHintingMask = kHintingBit1_Flag | kHintingBit2_Flag
191 };
192public:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000193 struct Rec {
reed@google.com7d26c592011-06-13 13:01:10 +0000194 uint32_t fOrigFontID;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000195 uint32_t fFontID;
196 SkScalar fTextSize, fPreScaleX, fPreSkewX;
197 SkScalar fPost2x2[2][2];
198 SkScalar fFrameWidth, fMiterLimit;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000199 uint8_t fMaskFormat;
200 uint8_t fStrokeJoin;
agl@chromium.orga2c71cb2010-06-17 20:49:17 +0000201 uint16_t fFlags;
agl@chromium.org13c85582010-01-04 23:56:43 +0000202 // Warning: when adding members note that the size of this structure
203 // must be a multiple of 4. SkDescriptor requires that its arguments be
204 // multiples of four and this structure is put in an SkDescriptor in
205 // SkPaint::MakeRec.
agl@chromium.org309485b2009-07-21 17:41:32 +0000206
reed@android.com8a1c16f2008-12-17 15:59:43 +0000207 void getMatrixFrom2x2(SkMatrix*) const;
208 void getLocalMatrix(SkMatrix*) const;
209 void getSingleMatrix(SkMatrix*) const;
agl@chromium.org309485b2009-07-21 17:41:32 +0000210
211 SkPaint::Hinting getHinting() const {
reed@android.come2ca2072009-07-27 16:39:38 +0000212 return static_cast<SkPaint::Hinting>((fFlags & kHintingMask) >> 4);
agl@chromium.org309485b2009-07-21 17:41:32 +0000213 }
214
215 void setHinting(SkPaint::Hinting hinting) {
reed@android.come2ca2072009-07-27 16:39:38 +0000216 fFlags = (fFlags & ~kHintingMask) | (hinting << 4);
agl@chromium.org309485b2009-07-21 17:41:32 +0000217 }
reed@android.com36a4c2a2009-07-22 19:52:11 +0000218
219 SkMask::Format getFormat() const {
220 return static_cast<SkMask::Format>(fMaskFormat);
221 }
222
223 bool isLCD() const {
224 return SkMask::FormatIsLCD(this->getFormat());
225 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000226 };
227
228 SkScalerContext(const SkDescriptor* desc);
229 virtual ~SkScalerContext();
230
reed@google.com98539c62011-03-15 15:40:16 +0000231 SkMask::Format getMaskFormat() const {
232 return (SkMask::Format)fRec.fMaskFormat;
233 }
234
reed@android.coma14ea0e2009-03-17 17:59:53 +0000235 // remember our glyph offset/base
reed@android.com8a1c16f2008-12-17 15:59:43 +0000236 void setBaseGlyphCount(unsigned baseGlyphCount) {
237 fBaseGlyphCount = baseGlyphCount;
238 }
239
reed@android.coma14ea0e2009-03-17 17:59:53 +0000240 /** Return the corresponding glyph for the specified unichar. Since contexts
241 may be chained (under the hood), the glyphID that is returned may in
242 fact correspond to a different font/context. In that case, we use the
243 base-glyph-count to know how to translate back into local glyph space.
244 */
reed@android.com8a1c16f2008-12-17 15:59:43 +0000245 uint16_t charToGlyphID(SkUnichar uni);
246
reed@android.com9d3a9852010-01-08 14:07:42 +0000247 /** Map the glyphID to its glyph index, and then to its char code. Unmapped
248 glyphs return zero.
249 */
250 SkUnichar glyphIDToChar(uint16_t glyphID);
251
ctguil@chromium.org0bc7bf52011-03-04 19:04:57 +0000252 unsigned getGlyphCount() { return this->generateGlyphCount(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000253 void getAdvance(SkGlyph*);
254 void getMetrics(SkGlyph*);
255 void getImage(const SkGlyph&);
256 void getPath(const SkGlyph&, SkPath*);
257 void getFontMetrics(SkPaint::FontMetrics* mX,
258 SkPaint::FontMetrics* mY);
259
260 static inline void MakeRec(const SkPaint&, const SkMatrix*, Rec* rec);
261 static SkScalerContext* Create(const SkDescriptor*);
262
263protected:
264 Rec fRec;
265 unsigned fBaseGlyphCount;
266
ctguil@chromium.org0bc7bf52011-03-04 19:04:57 +0000267 virtual unsigned generateGlyphCount() = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000268 virtual uint16_t generateCharToGlyph(SkUnichar) = 0;
269 virtual void generateAdvance(SkGlyph*) = 0;
270 virtual void generateMetrics(SkGlyph*) = 0;
271 virtual void generateImage(const SkGlyph&) = 0;
272 virtual void generatePath(const SkGlyph&, SkPath*) = 0;
273 virtual void generateFontMetrics(SkPaint::FontMetrics* mX,
274 SkPaint::FontMetrics* mY) = 0;
reed@android.com9d3a9852010-01-08 14:07:42 +0000275 // default impl returns 0, indicating failure.
276 virtual SkUnichar generateGlyphToChar(uint16_t);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000277
278private:
279 SkPathEffect* fPathEffect;
280 SkMaskFilter* fMaskFilter;
281 SkRasterizer* fRasterizer;
282 SkScalar fDevFrameWidth;
283
284 void internalGetPath(const SkGlyph& glyph, SkPath* fillPath,
285 SkPath* devPath, SkMatrix* fillToDevMatrix);
286
reed@android.coma14ea0e2009-03-17 17:59:53 +0000287 // return the next context, treating fNextContext as a cache of the answer
288 SkScalerContext* getNextContext();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000289
reed@android.coma14ea0e2009-03-17 17:59:53 +0000290 // returns the right context from our link-list for this glyph. If no match
291 // is found, just returns the original context (this)
292 SkScalerContext* getGlyphContext(const SkGlyph& glyph);
293
294 // link-list of context, to handle missing chars. null-terminated.
295 SkScalerContext* fNextContext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000296};
297
298#define kRec_SkDescriptorTag SkSetFourByteTag('s', 'r', 'e', 'c')
299#define kPathEffect_SkDescriptorTag SkSetFourByteTag('p', 't', 'h', 'e')
300#define kMaskFilter_SkDescriptorTag SkSetFourByteTag('m', 's', 'k', 'f')
301#define kRasterizer_SkDescriptorTag SkSetFourByteTag('r', 'a', 's', 't')
302
303#endif
304