blob: 3f818a31124d5c881a122462df80868f0ebe78ea [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;
reed@google.comf88d6762011-03-10 15:06:27 +000063 } else if (SkMask::kARGB32_Format == format) {
reed@android.comf2b98d62010-12-20 18:26:13 +000064 rb <<= 2;
reed@google.comf88d6762011-03-10 15:06:27 +000065 } else if (SkMask::kLCD16_Format == format) {
66 rb = SkAlign4(rb << 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +000067 } else {
68 rb = SkAlign4(rb);
69 }
70 return rb;
71 }
reed@google.comd3b13bd2011-01-13 16:33:36 +000072
reed@google.comf88d6762011-03-10 15:06:27 +000073 unsigned rowBytes() const {
74 return ComputeRowBytes(fWidth, (SkMask::Format)fMaskFormat);
75 }
76
reed@android.com8a1c16f2008-12-17 15:59:43 +000077 bool isJustAdvance() const {
78 return MASK_FORMAT_JUST_ADVANCE == fMaskFormat;
79 }
reed@google.comd3b13bd2011-01-13 16:33:36 +000080
reed@android.com8a1c16f2008-12-17 15:59:43 +000081 bool isFullMetrics() const {
82 return MASK_FORMAT_JUST_ADVANCE != fMaskFormat;
83 }
reed@google.comd3b13bd2011-01-13 16:33:36 +000084
reed@android.com8a1c16f2008-12-17 15:59:43 +000085 uint16_t getGlyphID() const {
86 return ID2Code(fID);
87 }
88
89 unsigned getGlyphID(unsigned baseGlyphCount) const {
90 unsigned code = ID2Code(fID);
91 SkASSERT(code >= baseGlyphCount);
92 return code - baseGlyphCount;
93 }
reed@google.comd3b13bd2011-01-13 16:33:36 +000094
reed@android.com8a1c16f2008-12-17 15:59:43 +000095 unsigned getSubX() const {
96 return ID2SubX(fID);
97 }
reed@google.comd3b13bd2011-01-13 16:33:36 +000098
reed@android.com8a1c16f2008-12-17 15:59:43 +000099 SkFixed getSubXFixed() const {
100 return SubToFixed(ID2SubX(fID));
101 }
reed@google.comd3b13bd2011-01-13 16:33:36 +0000102
reed@android.com8a1c16f2008-12-17 15:59:43 +0000103 SkFixed getSubYFixed() const {
104 return SubToFixed(ID2SubY(fID));
105 }
reed@google.comd3b13bd2011-01-13 16:33:36 +0000106
reed@android.com8a1c16f2008-12-17 15:59:43 +0000107 size_t computeImageSize() const;
reed@google.comd3b13bd2011-01-13 16:33:36 +0000108
reed@android.com62900b42009-02-11 15:07:19 +0000109 /** Call this to set all of the metrics fields to 0 (e.g. if the scaler
110 encounters an error measuring a glyph). Note: this does not alter the
111 fImage, fPath, fID, fMaskFormat fields.
112 */
113 void zeroMetrics();
reed@google.comd3b13bd2011-01-13 16:33:36 +0000114
reed@android.com8a1c16f2008-12-17 15:59:43 +0000115 enum {
116 kSubBits = 2,
117 kSubMask = ((1 << kSubBits) - 1),
118 kSubShift = 24, // must be large enough for glyphs and unichars
119 kCodeMask = ((1 << kSubShift) - 1),
120 // relative offsets for X and Y subpixel bits
121 kSubShiftX = kSubBits,
122 kSubShiftY = 0
123 };
124
125 static unsigned ID2Code(uint32_t id) {
126 return id & kCodeMask;
127 }
reed@google.comd3b13bd2011-01-13 16:33:36 +0000128
reed@android.com8a1c16f2008-12-17 15:59:43 +0000129 static unsigned ID2SubX(uint32_t id) {
130 return id >> (kSubShift + kSubShiftX);
131 }
reed@google.comd3b13bd2011-01-13 16:33:36 +0000132
reed@android.com8a1c16f2008-12-17 15:59:43 +0000133 static unsigned ID2SubY(uint32_t id) {
134 return (id >> (kSubShift + kSubShiftY)) & kSubMask;
135 }
reed@google.comd3b13bd2011-01-13 16:33:36 +0000136
reed@android.com8a1c16f2008-12-17 15:59:43 +0000137 static unsigned FixedToSub(SkFixed n) {
138 return (n >> (16 - kSubBits)) & kSubMask;
139 }
reed@google.comd3b13bd2011-01-13 16:33:36 +0000140
reed@android.com8a1c16f2008-12-17 15:59:43 +0000141 static SkFixed SubToFixed(unsigned sub) {
142 SkASSERT(sub <= kSubMask);
143 return sub << (16 - kSubBits);
144 }
reed@google.comd3b13bd2011-01-13 16:33:36 +0000145
reed@android.com8a1c16f2008-12-17 15:59:43 +0000146 static uint32_t MakeID(unsigned code) {
147 return code;
148 }
reed@google.comd3b13bd2011-01-13 16:33:36 +0000149
reed@android.com8a1c16f2008-12-17 15:59:43 +0000150 static uint32_t MakeID(unsigned code, SkFixed x, SkFixed y) {
151 SkASSERT(code <= kCodeMask);
152 x = FixedToSub(x);
153 y = FixedToSub(y);
154 return (x << (kSubShift + kSubShiftX)) |
155 (y << (kSubShift + kSubShiftY)) |
156 code;
157 }
reed@google.comd3b13bd2011-01-13 16:33:36 +0000158
reed@android.com8a1c16f2008-12-17 15:59:43 +0000159 void toMask(SkMask* mask) const;
agl@chromium.org309485b2009-07-21 17:41:32 +0000160
161 /** Given a glyph which is has a mask format of LCD or VerticalLCD, take
162 the A8 plane in fImage and produce a valid LCD plane from it.
163 */
164 void expandA8ToLCD() const;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000165};
166
167class SkScalerContext {
168public:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000169 enum Flags {
170 kFrameAndFill_Flag = 0x01,
171 kDevKernText_Flag = 0x02,
172 kGammaForBlack_Flag = 0x04, // illegal to set both Gamma flags
agl@chromium.org309485b2009-07-21 17:41:32 +0000173 kGammaForWhite_Flag = 0x08, // illegal to set both Gamma flags
174 // together, these two flags resulting in a two bit value which matches
175 // up with the SkPaint::Hinting enum.
reed@android.com36a4c2a2009-07-22 19:52:11 +0000176 kHintingBit1_Flag = 0x10,
177 kHintingBit2_Flag = 0x20,
agl@chromium.org13c85582010-01-04 23:56:43 +0000178 kEmbeddedBitmapText_Flag = 0x40,
senorblanco@chromium.org4526a842010-02-05 23:08:20 +0000179 kEmbolden_Flag = 0x80,
agl@chromium.orga2c71cb2010-06-17 20:49:17 +0000180 kSubpixelPositioning_Flag = 0x100,
181 kAutohinting_Flag = 0x200,
reed@google.com02b53312011-05-18 19:00:53 +0000182 // these should only ever be set if fMaskFormat is LCD
183 kLCD_Vertical_Flag = 0x400, // else Horizontal
184 kLCD_BGROrder_Flag = 0x800, // else RGB order
reed@android.com8a1c16f2008-12-17 15:59:43 +0000185 };
reed@android.come2ca2072009-07-27 16:39:38 +0000186private:
187 enum {
188 kHintingMask = kHintingBit1_Flag | kHintingBit2_Flag
189 };
190public:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000191 struct Rec {
192 uint32_t fFontID;
193 SkScalar fTextSize, fPreScaleX, fPreSkewX;
194 SkScalar fPost2x2[2][2];
195 SkScalar fFrameWidth, fMiterLimit;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000196 uint8_t fMaskFormat;
197 uint8_t fStrokeJoin;
agl@chromium.orga2c71cb2010-06-17 20:49:17 +0000198 uint16_t fFlags;
agl@chromium.org13c85582010-01-04 23:56:43 +0000199 // Warning: when adding members note that the size of this structure
200 // must be a multiple of 4. SkDescriptor requires that its arguments be
201 // multiples of four and this structure is put in an SkDescriptor in
202 // SkPaint::MakeRec.
agl@chromium.org309485b2009-07-21 17:41:32 +0000203
reed@android.com8a1c16f2008-12-17 15:59:43 +0000204 void getMatrixFrom2x2(SkMatrix*) const;
205 void getLocalMatrix(SkMatrix*) const;
206 void getSingleMatrix(SkMatrix*) const;
agl@chromium.org309485b2009-07-21 17:41:32 +0000207
208 SkPaint::Hinting getHinting() const {
reed@android.come2ca2072009-07-27 16:39:38 +0000209 return static_cast<SkPaint::Hinting>((fFlags & kHintingMask) >> 4);
agl@chromium.org309485b2009-07-21 17:41:32 +0000210 }
211
212 void setHinting(SkPaint::Hinting hinting) {
reed@android.come2ca2072009-07-27 16:39:38 +0000213 fFlags = (fFlags & ~kHintingMask) | (hinting << 4);
agl@chromium.org309485b2009-07-21 17:41:32 +0000214 }
reed@android.com36a4c2a2009-07-22 19:52:11 +0000215
216 SkMask::Format getFormat() const {
217 return static_cast<SkMask::Format>(fMaskFormat);
218 }
219
220 bool isLCD() const {
221 return SkMask::FormatIsLCD(this->getFormat());
222 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000223 };
224
225 SkScalerContext(const SkDescriptor* desc);
226 virtual ~SkScalerContext();
227
reed@google.com98539c62011-03-15 15:40:16 +0000228 SkMask::Format getMaskFormat() const {
229 return (SkMask::Format)fRec.fMaskFormat;
230 }
231
reed@android.coma14ea0e2009-03-17 17:59:53 +0000232 // remember our glyph offset/base
reed@android.com8a1c16f2008-12-17 15:59:43 +0000233 void setBaseGlyphCount(unsigned baseGlyphCount) {
234 fBaseGlyphCount = baseGlyphCount;
235 }
236
reed@android.coma14ea0e2009-03-17 17:59:53 +0000237 /** Return the corresponding glyph for the specified unichar. Since contexts
238 may be chained (under the hood), the glyphID that is returned may in
239 fact correspond to a different font/context. In that case, we use the
240 base-glyph-count to know how to translate back into local glyph space.
241 */
reed@android.com8a1c16f2008-12-17 15:59:43 +0000242 uint16_t charToGlyphID(SkUnichar uni);
243
reed@android.com9d3a9852010-01-08 14:07:42 +0000244 /** Map the glyphID to its glyph index, and then to its char code. Unmapped
245 glyphs return zero.
246 */
247 SkUnichar glyphIDToChar(uint16_t glyphID);
248
ctguil@chromium.org0bc7bf52011-03-04 19:04:57 +0000249 unsigned getGlyphCount() { return this->generateGlyphCount(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000250 void getAdvance(SkGlyph*);
251 void getMetrics(SkGlyph*);
252 void getImage(const SkGlyph&);
253 void getPath(const SkGlyph&, SkPath*);
254 void getFontMetrics(SkPaint::FontMetrics* mX,
255 SkPaint::FontMetrics* mY);
256
257 static inline void MakeRec(const SkPaint&, const SkMatrix*, Rec* rec);
258 static SkScalerContext* Create(const SkDescriptor*);
259
260protected:
261 Rec fRec;
262 unsigned fBaseGlyphCount;
263
ctguil@chromium.org0bc7bf52011-03-04 19:04:57 +0000264 virtual unsigned generateGlyphCount() = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000265 virtual uint16_t generateCharToGlyph(SkUnichar) = 0;
266 virtual void generateAdvance(SkGlyph*) = 0;
267 virtual void generateMetrics(SkGlyph*) = 0;
268 virtual void generateImage(const SkGlyph&) = 0;
269 virtual void generatePath(const SkGlyph&, SkPath*) = 0;
270 virtual void generateFontMetrics(SkPaint::FontMetrics* mX,
271 SkPaint::FontMetrics* mY) = 0;
reed@android.com9d3a9852010-01-08 14:07:42 +0000272 // default impl returns 0, indicating failure.
273 virtual SkUnichar generateGlyphToChar(uint16_t);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000274
275private:
276 SkPathEffect* fPathEffect;
277 SkMaskFilter* fMaskFilter;
278 SkRasterizer* fRasterizer;
279 SkScalar fDevFrameWidth;
280
281 void internalGetPath(const SkGlyph& glyph, SkPath* fillPath,
282 SkPath* devPath, SkMatrix* fillToDevMatrix);
283
reed@android.coma14ea0e2009-03-17 17:59:53 +0000284 // return the next context, treating fNextContext as a cache of the answer
285 SkScalerContext* getNextContext();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000286
reed@android.coma14ea0e2009-03-17 17:59:53 +0000287 // returns the right context from our link-list for this glyph. If no match
288 // is found, just returns the original context (this)
289 SkScalerContext* getGlyphContext(const SkGlyph& glyph);
290
291 // link-list of context, to handle missing chars. null-terminated.
292 SkScalerContext* fNextContext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000293};
294
295#define kRec_SkDescriptorTag SkSetFourByteTag('s', 'r', 'e', 'c')
296#define kPathEffect_SkDescriptorTag SkSetFourByteTag('p', 't', 'h', 'e')
297#define kMaskFilter_SkDescriptorTag SkSetFourByteTag('m', 's', 'k', 'f')
298#define kRasterizer_SkDescriptorTag SkSetFourByteTag('r', 'a', 's', 't')
299
300#endif
301