blob: e4a28b90761015427fd4ffa341a2c666be59b9cd [file] [log] [blame]
epoger@google.comec3ed6a2011-07-28 14:26:00 +00001
reed@android.com8a1c16f2008-12-17 15:59:43 +00002/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00003 * Copyright 2006 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00004 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00005 * Use of this source code is governed by a BSD-style license that can be
6 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00007 */
8
epoger@google.comec3ed6a2011-07-28 14:26:00 +00009
reed@android.com8a1c16f2008-12-17 15:59:43 +000010#ifndef SkScalerContext_DEFINED
11#define SkScalerContext_DEFINED
12
13#include "SkMask.h"
14#include "SkMatrix.h"
15#include "SkPaint.h"
16#include "SkPath.h"
17#include "SkPoint.h"
18
reed@google.comce6dbb62012-02-10 22:01:45 +000019//#define SK_USE_COLOR_LUMINANCE
reed@google.comce6dbb62012-02-10 22:01:45 +000020
reed@android.com8a1c16f2008-12-17 15:59:43 +000021class SkDescriptor;
22class SkMaskFilter;
23class SkPathEffect;
24class SkRasterizer;
25
26// needs to be != to any valid SkMask::Format
reed@google.comd3b13bd2011-01-13 16:33:36 +000027#define MASK_FORMAT_UNKNOWN (0xFF)
28#define MASK_FORMAT_JUST_ADVANCE MASK_FORMAT_UNKNOWN
reed@android.com8a1c16f2008-12-17 15:59:43 +000029
scarybeasts@gmail.com17f694b2010-10-18 23:29:36 +000030#define kMaxGlyphWidth (1<<13)
31
reed@android.com8a1c16f2008-12-17 15:59:43 +000032struct SkGlyph {
33 void* fImage;
34 SkPath* fPath;
35 SkFixed fAdvanceX, fAdvanceY;
36
37 uint32_t fID;
38 uint16_t fWidth, fHeight;
39 int16_t fTop, fLeft;
40
41 uint8_t fMaskFormat;
42 int8_t fRsbDelta, fLsbDelta; // used by auto-kerning
reed@android.comf2b98d62010-12-20 18:26:13 +000043
44 void init(uint32_t id) {
45 fID = id;
46 fImage = NULL;
47 fPath = NULL;
reed@google.comd3b13bd2011-01-13 16:33:36 +000048 fMaskFormat = MASK_FORMAT_UNKNOWN;
reed@android.comf2b98d62010-12-20 18:26:13 +000049 }
50
reed@google.comf88d6762011-03-10 15:06:27 +000051 /**
52 * Compute the rowbytes for the specified width and mask-format.
53 */
54 static unsigned ComputeRowBytes(unsigned width, SkMask::Format format) {
55 unsigned rb = width;
56 if (SkMask::kBW_Format == format) {
reed@android.com8a1c16f2008-12-17 15:59:43 +000057 rb = (rb + 7) >> 3;
caryclark@google.com1eeaf0b2011-06-22 13:19:43 +000058 } else if (SkMask::kARGB32_Format == format ||
59 SkMask::kLCD32_Format == format)
60 {
reed@android.comf2b98d62010-12-20 18:26:13 +000061 rb <<= 2;
reed@google.comf88d6762011-03-10 15:06:27 +000062 } else if (SkMask::kLCD16_Format == format) {
63 rb = SkAlign4(rb << 1);
reed@android.com8a1c16f2008-12-17 15:59:43 +000064 } else {
65 rb = SkAlign4(rb);
66 }
67 return rb;
68 }
reed@google.comd3b13bd2011-01-13 16:33:36 +000069
reed@google.comf88d6762011-03-10 15:06:27 +000070 unsigned rowBytes() const {
71 return ComputeRowBytes(fWidth, (SkMask::Format)fMaskFormat);
72 }
73
reed@android.com8a1c16f2008-12-17 15:59:43 +000074 bool isJustAdvance() const {
75 return MASK_FORMAT_JUST_ADVANCE == fMaskFormat;
76 }
reed@google.comd3b13bd2011-01-13 16:33:36 +000077
reed@android.com8a1c16f2008-12-17 15:59:43 +000078 bool isFullMetrics() const {
79 return MASK_FORMAT_JUST_ADVANCE != fMaskFormat;
80 }
reed@google.comd3b13bd2011-01-13 16:33:36 +000081
reed@android.com8a1c16f2008-12-17 15:59:43 +000082 uint16_t getGlyphID() const {
83 return ID2Code(fID);
84 }
85
86 unsigned getGlyphID(unsigned baseGlyphCount) const {
87 unsigned code = ID2Code(fID);
88 SkASSERT(code >= baseGlyphCount);
89 return code - baseGlyphCount;
90 }
reed@google.comd3b13bd2011-01-13 16:33:36 +000091
reed@android.com8a1c16f2008-12-17 15:59:43 +000092 unsigned getSubX() const {
93 return ID2SubX(fID);
94 }
reed@google.comd3b13bd2011-01-13 16:33:36 +000095
reed@android.com8a1c16f2008-12-17 15:59:43 +000096 SkFixed getSubXFixed() const {
97 return SubToFixed(ID2SubX(fID));
98 }
reed@google.comd3b13bd2011-01-13 16:33:36 +000099
reed@android.com8a1c16f2008-12-17 15:59:43 +0000100 SkFixed getSubYFixed() const {
101 return SubToFixed(ID2SubY(fID));
102 }
reed@google.comd3b13bd2011-01-13 16:33:36 +0000103
reed@android.com8a1c16f2008-12-17 15:59:43 +0000104 size_t computeImageSize() const;
reed@google.comd3b13bd2011-01-13 16:33:36 +0000105
reed@android.com62900b42009-02-11 15:07:19 +0000106 /** Call this to set all of the metrics fields to 0 (e.g. if the scaler
107 encounters an error measuring a glyph). Note: this does not alter the
108 fImage, fPath, fID, fMaskFormat fields.
109 */
110 void zeroMetrics();
reed@google.comd3b13bd2011-01-13 16:33:36 +0000111
reed@android.com8a1c16f2008-12-17 15:59:43 +0000112 enum {
113 kSubBits = 2,
114 kSubMask = ((1 << kSubBits) - 1),
115 kSubShift = 24, // must be large enough for glyphs and unichars
116 kCodeMask = ((1 << kSubShift) - 1),
117 // relative offsets for X and Y subpixel bits
118 kSubShiftX = kSubBits,
119 kSubShiftY = 0
120 };
121
122 static unsigned ID2Code(uint32_t id) {
123 return id & kCodeMask;
124 }
reed@google.comd3b13bd2011-01-13 16:33:36 +0000125
reed@android.com8a1c16f2008-12-17 15:59:43 +0000126 static unsigned ID2SubX(uint32_t id) {
127 return id >> (kSubShift + kSubShiftX);
128 }
reed@google.comd3b13bd2011-01-13 16:33:36 +0000129
reed@android.com8a1c16f2008-12-17 15:59:43 +0000130 static unsigned ID2SubY(uint32_t id) {
131 return (id >> (kSubShift + kSubShiftY)) & kSubMask;
132 }
reed@google.comd3b13bd2011-01-13 16:33:36 +0000133
reed@android.com8a1c16f2008-12-17 15:59:43 +0000134 static unsigned FixedToSub(SkFixed n) {
135 return (n >> (16 - kSubBits)) & kSubMask;
136 }
reed@google.comd3b13bd2011-01-13 16:33:36 +0000137
reed@android.com8a1c16f2008-12-17 15:59:43 +0000138 static SkFixed SubToFixed(unsigned sub) {
139 SkASSERT(sub <= kSubMask);
140 return sub << (16 - kSubBits);
141 }
reed@google.comd3b13bd2011-01-13 16:33:36 +0000142
reed@android.com8a1c16f2008-12-17 15:59:43 +0000143 static uint32_t MakeID(unsigned code) {
144 return code;
145 }
reed@google.comd3b13bd2011-01-13 16:33:36 +0000146
reed@android.com8a1c16f2008-12-17 15:59:43 +0000147 static uint32_t MakeID(unsigned code, SkFixed x, SkFixed y) {
148 SkASSERT(code <= kCodeMask);
149 x = FixedToSub(x);
150 y = FixedToSub(y);
151 return (x << (kSubShift + kSubShiftX)) |
152 (y << (kSubShift + kSubShiftY)) |
153 code;
154 }
reed@google.comd3b13bd2011-01-13 16:33:36 +0000155
reed@android.com8a1c16f2008-12-17 15:59:43 +0000156 void toMask(SkMask* mask) const;
157};
158
159class SkScalerContext {
160public:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000161 enum Flags {
reed@google.comb6bb5cb2011-11-21 19:32:29 +0000162 kFrameAndFill_Flag = 0x0001,
163 kDevKernText_Flag = 0x0002,
164 kEmbeddedBitmapText_Flag = 0x0004,
165 kEmbolden_Flag = 0x0008,
166 kSubpixelPositioning_Flag = 0x0010,
167 kAutohinting_Flag = 0x0020,
168 kVertical_Flag = 0x0040,
reed@google.comffe49f52011-11-22 19:42:41 +0000169
agl@chromium.org309485b2009-07-21 17:41:32 +0000170 // together, these two flags resulting in a two bit value which matches
171 // up with the SkPaint::Hinting enum.
reed@google.comffe49f52011-11-22 19:42:41 +0000172 kHinting_Shift = 7, // to shift into the other flags above
reed@google.comb6bb5cb2011-11-21 19:32:29 +0000173 kHintingBit1_Flag = 0x0080,
174 kHintingBit2_Flag = 0x0100,
reed@google.comffe49f52011-11-22 19:42:41 +0000175
reed@google.comeffc5012011-06-27 16:44:46 +0000176 // these should only ever be set if fMaskFormat is LCD16 or LCD32
reed@google.comb6bb5cb2011-11-21 19:32:29 +0000177 kLCD_Vertical_Flag = 0x0200, // else Horizontal
178 kLCD_BGROrder_Flag = 0x0400, // else RGB order
reed@google.comffe49f52011-11-22 19:42:41 +0000179
reed@google.com8351aab2012-01-18 17:06:35 +0000180 // Generate A8 from LCD source (for GDI), only meaningful if fMaskFormat is kA8
181 // Perhaps we can store this (instead) in fMaskFormat, in hight bit?
182 kGenA8FromLCD_Flag = 0x0800,
183
reed@google.comce6dbb62012-02-10 22:01:45 +0000184#ifdef SK_USE_COLOR_LUMINANCE
reed@google.come7a0a162012-02-07 21:25:33 +0000185 kLuminance_Bits = 3,
186#else
reed@google.comffe49f52011-11-22 19:42:41 +0000187 // luminance : 0 for black text, kLuminance_Max for white text
reed@google.com8351aab2012-01-18 17:06:35 +0000188 kLuminance_Shift = 13, // shift to land in the high 3-bits of Flags
reed@google.comffe49f52011-11-22 19:42:41 +0000189 kLuminance_Bits = 3, // ensure Flags doesn't exceed 16bits
reed@google.come7a0a162012-02-07 21:25:33 +0000190#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000191 };
reed@google.comffe49f52011-11-22 19:42:41 +0000192
193 // computed values
reed@android.come2ca2072009-07-27 16:39:38 +0000194 enum {
reed@google.comffe49f52011-11-22 19:42:41 +0000195 kHinting_Mask = kHintingBit1_Flag | kHintingBit2_Flag,
reed@google.comce6dbb62012-02-10 22:01:45 +0000196#ifdef SK_USE_COLOR_LUMINANCE
197#else
reed@google.comffe49f52011-11-22 19:42:41 +0000198 kLuminance_Max = (1 << kLuminance_Bits) - 1,
199 kLuminance_Mask = kLuminance_Max << kLuminance_Shift,
reed@google.come7a0a162012-02-07 21:25:33 +0000200#endif
reed@android.come2ca2072009-07-27 16:39:38 +0000201 };
reed@google.comffe49f52011-11-22 19:42:41 +0000202
reed@android.com8a1c16f2008-12-17 15:59:43 +0000203 struct Rec {
reed@google.com7d26c592011-06-13 13:01:10 +0000204 uint32_t fOrigFontID;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000205 uint32_t fFontID;
206 SkScalar fTextSize, fPreScaleX, fPreSkewX;
207 SkScalar fPost2x2[2][2];
208 SkScalar fFrameWidth, fMiterLimit;
reed@google.comce6dbb62012-02-10 22:01:45 +0000209#ifdef SK_USE_COLOR_LUMINANCE
reed@google.come7a0a162012-02-07 21:25:33 +0000210 uint32_t fLumBits;
211#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000212 uint8_t fMaskFormat;
213 uint8_t fStrokeJoin;
agl@chromium.orga2c71cb2010-06-17 20:49:17 +0000214 uint16_t fFlags;
agl@chromium.org13c85582010-01-04 23:56:43 +0000215 // Warning: when adding members note that the size of this structure
216 // must be a multiple of 4. SkDescriptor requires that its arguments be
217 // multiples of four and this structure is put in an SkDescriptor in
218 // SkPaint::MakeRec.
agl@chromium.org309485b2009-07-21 17:41:32 +0000219
reed@android.com8a1c16f2008-12-17 15:59:43 +0000220 void getMatrixFrom2x2(SkMatrix*) const;
221 void getLocalMatrix(SkMatrix*) const;
222 void getSingleMatrix(SkMatrix*) const;
agl@chromium.org309485b2009-07-21 17:41:32 +0000223
224 SkPaint::Hinting getHinting() const {
reed@google.comffe49f52011-11-22 19:42:41 +0000225 unsigned hint = (fFlags & kHinting_Mask) >> kHinting_Shift;
reed@google.comf788feb2011-11-21 19:46:00 +0000226 return static_cast<SkPaint::Hinting>(hint);
agl@chromium.org309485b2009-07-21 17:41:32 +0000227 }
228
229 void setHinting(SkPaint::Hinting hinting) {
reed@google.comffe49f52011-11-22 19:42:41 +0000230 fFlags = (fFlags & ~kHinting_Mask) | (hinting << kHinting_Shift);
231 }
reed@google.come7a0a162012-02-07 21:25:33 +0000232
233 SkMask::Format getFormat() const {
234 return static_cast<SkMask::Format>(fMaskFormat);
235 }
236
reed@google.comce6dbb62012-02-10 22:01:45 +0000237#ifdef SK_USE_COLOR_LUMINANCE
reed@google.comce6dbb62012-02-10 22:01:45 +0000238 SkColor getLuminanceColor() const {
reed@google.come7a0a162012-02-07 21:25:33 +0000239 return fLumBits;
240 }
241
reed@google.comce6dbb62012-02-10 22:01:45 +0000242 void setLuminanceColor(SkColor c) {
reed@google.comce6dbb62012-02-10 22:01:45 +0000243 fLumBits = c;
reed@google.come7a0a162012-02-07 21:25:33 +0000244 }
245#else
reed@google.comffe49f52011-11-22 19:42:41 +0000246 unsigned getLuminanceBits() const {
247 return (fFlags & kLuminance_Mask) >> kLuminance_Shift;
248 }
249
250 void setLuminanceBits(unsigned lum) {
251 SkASSERT(lum <= kLuminance_Max);
252 fFlags = (fFlags & ~kLuminance_Mask) | (lum << kLuminance_Shift);
253 }
254
255 U8CPU getLuminanceByte() const {
256 SkASSERT(3 == kLuminance_Bits);
257 unsigned lum = this->getLuminanceBits();
258 lum |= (lum << kLuminance_Bits);
259 lum |= (lum << kLuminance_Bits*2);
260 return lum >> (4*kLuminance_Bits - 8);
agl@chromium.org309485b2009-07-21 17:41:32 +0000261 }
reed@google.comce6dbb62012-02-10 22:01:45 +0000262#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000263 };
264
265 SkScalerContext(const SkDescriptor* desc);
266 virtual ~SkScalerContext();
267
reed@google.com98539c62011-03-15 15:40:16 +0000268 SkMask::Format getMaskFormat() const {
269 return (SkMask::Format)fRec.fMaskFormat;
270 }
271
reed@google.comabf00aa2012-01-03 19:43:20 +0000272 bool isSubpixel() const {
273 return SkToBool(fRec.fFlags & kSubpixelPositioning_Flag);
274 }
275
reed@android.coma14ea0e2009-03-17 17:59:53 +0000276 // remember our glyph offset/base
reed@android.com8a1c16f2008-12-17 15:59:43 +0000277 void setBaseGlyphCount(unsigned baseGlyphCount) {
278 fBaseGlyphCount = baseGlyphCount;
279 }
280
reed@android.coma14ea0e2009-03-17 17:59:53 +0000281 /** Return the corresponding glyph for the specified unichar. Since contexts
282 may be chained (under the hood), the glyphID that is returned may in
283 fact correspond to a different font/context. In that case, we use the
284 base-glyph-count to know how to translate back into local glyph space.
285 */
reed@google.comffe49f52011-11-22 19:42:41 +0000286 uint16_t charToGlyphID(SkUnichar uni);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000287
reed@android.com9d3a9852010-01-08 14:07:42 +0000288 /** Map the glyphID to its glyph index, and then to its char code. Unmapped
289 glyphs return zero.
290 */
291 SkUnichar glyphIDToChar(uint16_t glyphID);
292
ctguil@chromium.org0bc7bf52011-03-04 19:04:57 +0000293 unsigned getGlyphCount() { return this->generateGlyphCount(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000294 void getAdvance(SkGlyph*);
295 void getMetrics(SkGlyph*);
296 void getImage(const SkGlyph&);
297 void getPath(const SkGlyph&, SkPath*);
298 void getFontMetrics(SkPaint::FontMetrics* mX,
299 SkPaint::FontMetrics* mY);
300
djsollen@google.com60abb072012-02-15 18:49:15 +0000301#ifdef SK_BUILD_FOR_ANDROID
302 unsigned getBaseGlyphCount(SkUnichar charCode);
303#endif
304
reed@android.com8a1c16f2008-12-17 15:59:43 +0000305 static inline void MakeRec(const SkPaint&, const SkMatrix*, Rec* rec);
306 static SkScalerContext* Create(const SkDescriptor*);
307
308protected:
309 Rec fRec;
310 unsigned fBaseGlyphCount;
311
ctguil@chromium.org0bc7bf52011-03-04 19:04:57 +0000312 virtual unsigned generateGlyphCount() = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000313 virtual uint16_t generateCharToGlyph(SkUnichar) = 0;
314 virtual void generateAdvance(SkGlyph*) = 0;
315 virtual void generateMetrics(SkGlyph*) = 0;
316 virtual void generateImage(const SkGlyph&) = 0;
317 virtual void generatePath(const SkGlyph&, SkPath*) = 0;
318 virtual void generateFontMetrics(SkPaint::FontMetrics* mX,
319 SkPaint::FontMetrics* mY) = 0;
reed@android.com9d3a9852010-01-08 14:07:42 +0000320 // default impl returns 0, indicating failure.
321 virtual SkUnichar generateGlyphToChar(uint16_t);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000322
reed@google.coma767fa02011-08-05 21:40:26 +0000323 void forceGenerateImageFromPath() { fGenerateImageFromPath = true; }
324
reed@android.com8a1c16f2008-12-17 15:59:43 +0000325private:
326 SkPathEffect* fPathEffect;
327 SkMaskFilter* fMaskFilter;
328 SkRasterizer* fRasterizer;
329 SkScalar fDevFrameWidth;
330
reed@google.coma767fa02011-08-05 21:40:26 +0000331 // if this is set, we draw the image from a path, rather than
332 // calling generateImage.
333 bool fGenerateImageFromPath;
334
reed@android.com8a1c16f2008-12-17 15:59:43 +0000335 void internalGetPath(const SkGlyph& glyph, SkPath* fillPath,
336 SkPath* devPath, SkMatrix* fillToDevMatrix);
337
reed@android.coma14ea0e2009-03-17 17:59:53 +0000338 // return the next context, treating fNextContext as a cache of the answer
339 SkScalerContext* getNextContext();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000340
reed@android.coma14ea0e2009-03-17 17:59:53 +0000341 // returns the right context from our link-list for this glyph. If no match
342 // is found, just returns the original context (this)
343 SkScalerContext* getGlyphContext(const SkGlyph& glyph);
344
345 // link-list of context, to handle missing chars. null-terminated.
346 SkScalerContext* fNextContext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000347};
348
349#define kRec_SkDescriptorTag SkSetFourByteTag('s', 'r', 'e', 'c')
350#define kPathEffect_SkDescriptorTag SkSetFourByteTag('p', 't', 'h', 'e')
351#define kMaskFilter_SkDescriptorTag SkSetFourByteTag('m', 's', 'k', 'f')
352#define kRasterizer_SkDescriptorTag SkSetFourByteTag('r', 'a', 's', 't')
353
reed@google.comcb6ccdd2011-08-23 21:30:47 +0000354///////////////////////////////////////////////////////////////////////////////
355
356enum SkAxisAlignment {
357 kNone_SkAxisAlignment,
358 kX_SkAxisAlignment,
359 kY_SkAxisAlignment
360};
361
362/**
363 * Return the axis (if any) that the baseline for horizontal text will land on
364 * after running through the specified matrix.
365 *
366 * As an example, the identity matrix will return kX_SkAxisAlignment
367 */
reed@google.com2e684782011-08-24 15:38:46 +0000368SkAxisAlignment SkComputeAxisAlignmentForHText(const SkMatrix& matrix);
reed@google.comcb6ccdd2011-08-23 21:30:47 +0000369
reed@android.com8a1c16f2008-12-17 15:59:43 +0000370#endif
371