blob: ccc4fa954115cb40f7a195f7537e18bc99ff8a12 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2006 The Android Open Source Project
reed@android.com8a1c16f2008-12-17 15:59:43 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com8a1c16f2008-12-17 15:59:43 +00006 */
7
8#ifndef SkScalerContext_DEFINED
9#define SkScalerContext_DEFINED
10
11#include "SkMask.h"
12#include "SkMatrix.h"
13#include "SkPaint.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000014
bungeman@google.com6e502fe2012-07-24 21:18:54 +000015#ifdef SK_BUILD_FOR_ANDROID
16 //For SkFontID
17 #include "SkTypeface.h"
18#endif
19
reed@google.comce6dbb62012-02-10 22:01:45 +000020//#define SK_USE_COLOR_LUMINANCE
reed@google.comce6dbb62012-02-10 22:01:45 +000021
bungeman@google.combbe50132012-07-24 20:33:21 +000022struct SkGlyph;
reed@android.com8a1c16f2008-12-17 15:59:43 +000023class SkDescriptor;
24class SkMaskFilter;
25class SkPathEffect;
26class SkRasterizer;
27
reed@android.com8a1c16f2008-12-17 15:59:43 +000028class SkScalerContext {
29public:
reed@android.com8a1c16f2008-12-17 15:59:43 +000030 enum Flags {
reed@google.comb6bb5cb2011-11-21 19:32:29 +000031 kFrameAndFill_Flag = 0x0001,
32 kDevKernText_Flag = 0x0002,
33 kEmbeddedBitmapText_Flag = 0x0004,
34 kEmbolden_Flag = 0x0008,
35 kSubpixelPositioning_Flag = 0x0010,
36 kAutohinting_Flag = 0x0020,
37 kVertical_Flag = 0x0040,
reed@google.comffe49f52011-11-22 19:42:41 +000038
agl@chromium.org309485b2009-07-21 17:41:32 +000039 // together, these two flags resulting in a two bit value which matches
40 // up with the SkPaint::Hinting enum.
reed@google.comffe49f52011-11-22 19:42:41 +000041 kHinting_Shift = 7, // to shift into the other flags above
reed@google.comb6bb5cb2011-11-21 19:32:29 +000042 kHintingBit1_Flag = 0x0080,
43 kHintingBit2_Flag = 0x0100,
reed@google.comffe49f52011-11-22 19:42:41 +000044
reed@google.comeffc5012011-06-27 16:44:46 +000045 // these should only ever be set if fMaskFormat is LCD16 or LCD32
reed@google.comb6bb5cb2011-11-21 19:32:29 +000046 kLCD_Vertical_Flag = 0x0200, // else Horizontal
47 kLCD_BGROrder_Flag = 0x0400, // else RGB order
reed@google.comffe49f52011-11-22 19:42:41 +000048
reed@google.com8351aab2012-01-18 17:06:35 +000049 // Generate A8 from LCD source (for GDI), only meaningful if fMaskFormat is kA8
50 // Perhaps we can store this (instead) in fMaskFormat, in hight bit?
51 kGenA8FromLCD_Flag = 0x0800,
52
reed@google.comce6dbb62012-02-10 22:01:45 +000053#ifdef SK_USE_COLOR_LUMINANCE
tomhudson@google.com1f902872012-06-01 13:15:47 +000054 kLuminance_Bits = 3
reed@google.come7a0a162012-02-07 21:25:33 +000055#else
reed@google.comffe49f52011-11-22 19:42:41 +000056 // luminance : 0 for black text, kLuminance_Max for white text
reed@google.com8351aab2012-01-18 17:06:35 +000057 kLuminance_Shift = 13, // shift to land in the high 3-bits of Flags
tomhudson@google.com1f902872012-06-01 13:15:47 +000058 kLuminance_Bits = 3 // ensure Flags doesn't exceed 16bits
reed@google.come7a0a162012-02-07 21:25:33 +000059#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000060 };
reed@google.comffe49f52011-11-22 19:42:41 +000061
62 // computed values
reed@android.come2ca2072009-07-27 16:39:38 +000063 enum {
reed@google.comffe49f52011-11-22 19:42:41 +000064 kHinting_Mask = kHintingBit1_Flag | kHintingBit2_Flag,
reed@google.comce6dbb62012-02-10 22:01:45 +000065#ifdef SK_USE_COLOR_LUMINANCE
66#else
reed@google.comffe49f52011-11-22 19:42:41 +000067 kLuminance_Max = (1 << kLuminance_Bits) - 1,
tomhudson@google.com1f902872012-06-01 13:15:47 +000068 kLuminance_Mask = kLuminance_Max << kLuminance_Shift
reed@google.come7a0a162012-02-07 21:25:33 +000069#endif
reed@android.come2ca2072009-07-27 16:39:38 +000070 };
reed@google.comffe49f52011-11-22 19:42:41 +000071
reed@android.com8a1c16f2008-12-17 15:59:43 +000072 struct Rec {
reed@google.com7d26c592011-06-13 13:01:10 +000073 uint32_t fOrigFontID;
reed@android.com8a1c16f2008-12-17 15:59:43 +000074 uint32_t fFontID;
75 SkScalar fTextSize, fPreScaleX, fPreSkewX;
76 SkScalar fPost2x2[2][2];
77 SkScalar fFrameWidth, fMiterLimit;
reed@google.comce6dbb62012-02-10 22:01:45 +000078#ifdef SK_USE_COLOR_LUMINANCE
reed@google.come7a0a162012-02-07 21:25:33 +000079 uint32_t fLumBits;
80#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +000081 uint8_t fMaskFormat;
82 uint8_t fStrokeJoin;
agl@chromium.orga2c71cb2010-06-17 20:49:17 +000083 uint16_t fFlags;
agl@chromium.org13c85582010-01-04 23:56:43 +000084 // Warning: when adding members note that the size of this structure
85 // must be a multiple of 4. SkDescriptor requires that its arguments be
86 // multiples of four and this structure is put in an SkDescriptor in
87 // SkPaint::MakeRec.
agl@chromium.org309485b2009-07-21 17:41:32 +000088
reed@android.com8a1c16f2008-12-17 15:59:43 +000089 void getMatrixFrom2x2(SkMatrix*) const;
90 void getLocalMatrix(SkMatrix*) const;
91 void getSingleMatrix(SkMatrix*) const;
agl@chromium.org309485b2009-07-21 17:41:32 +000092
93 SkPaint::Hinting getHinting() const {
reed@google.comffe49f52011-11-22 19:42:41 +000094 unsigned hint = (fFlags & kHinting_Mask) >> kHinting_Shift;
reed@google.comf788feb2011-11-21 19:46:00 +000095 return static_cast<SkPaint::Hinting>(hint);
agl@chromium.org309485b2009-07-21 17:41:32 +000096 }
97
98 void setHinting(SkPaint::Hinting hinting) {
reed@google.comffe49f52011-11-22 19:42:41 +000099 fFlags = (fFlags & ~kHinting_Mask) | (hinting << kHinting_Shift);
100 }
reed@google.come7a0a162012-02-07 21:25:33 +0000101
102 SkMask::Format getFormat() const {
103 return static_cast<SkMask::Format>(fMaskFormat);
104 }
105
reed@google.comce6dbb62012-02-10 22:01:45 +0000106#ifdef SK_USE_COLOR_LUMINANCE
reed@google.comce6dbb62012-02-10 22:01:45 +0000107 SkColor getLuminanceColor() const {
reed@google.come7a0a162012-02-07 21:25:33 +0000108 return fLumBits;
109 }
110
reed@google.comce6dbb62012-02-10 22:01:45 +0000111 void setLuminanceColor(SkColor c) {
reed@google.comce6dbb62012-02-10 22:01:45 +0000112 fLumBits = c;
reed@google.come7a0a162012-02-07 21:25:33 +0000113 }
114#else
reed@google.comffe49f52011-11-22 19:42:41 +0000115 unsigned getLuminanceBits() const {
116 return (fFlags & kLuminance_Mask) >> kLuminance_Shift;
117 }
118
119 void setLuminanceBits(unsigned lum) {
120 SkASSERT(lum <= kLuminance_Max);
121 fFlags = (fFlags & ~kLuminance_Mask) | (lum << kLuminance_Shift);
122 }
123
124 U8CPU getLuminanceByte() const {
125 SkASSERT(3 == kLuminance_Bits);
126 unsigned lum = this->getLuminanceBits();
127 lum |= (lum << kLuminance_Bits);
128 lum |= (lum << kLuminance_Bits*2);
129 return lum >> (4*kLuminance_Bits - 8);
agl@chromium.org309485b2009-07-21 17:41:32 +0000130 }
reed@google.comce6dbb62012-02-10 22:01:45 +0000131#endif
reed@android.com8a1c16f2008-12-17 15:59:43 +0000132 };
133
134 SkScalerContext(const SkDescriptor* desc);
135 virtual ~SkScalerContext();
136
reed@google.com98539c62011-03-15 15:40:16 +0000137 SkMask::Format getMaskFormat() const {
138 return (SkMask::Format)fRec.fMaskFormat;
139 }
140
reed@google.comabf00aa2012-01-03 19:43:20 +0000141 bool isSubpixel() const {
142 return SkToBool(fRec.fFlags & kSubpixelPositioning_Flag);
143 }
144
reed@android.coma14ea0e2009-03-17 17:59:53 +0000145 // remember our glyph offset/base
reed@android.com8a1c16f2008-12-17 15:59:43 +0000146 void setBaseGlyphCount(unsigned baseGlyphCount) {
147 fBaseGlyphCount = baseGlyphCount;
148 }
149
reed@android.coma14ea0e2009-03-17 17:59:53 +0000150 /** Return the corresponding glyph for the specified unichar. Since contexts
151 may be chained (under the hood), the glyphID that is returned may in
152 fact correspond to a different font/context. In that case, we use the
153 base-glyph-count to know how to translate back into local glyph space.
154 */
reed@google.comffe49f52011-11-22 19:42:41 +0000155 uint16_t charToGlyphID(SkUnichar uni);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000156
reed@android.com9d3a9852010-01-08 14:07:42 +0000157 /** Map the glyphID to its glyph index, and then to its char code. Unmapped
158 glyphs return zero.
159 */
160 SkUnichar glyphIDToChar(uint16_t glyphID);
161
ctguil@chromium.org0bc7bf52011-03-04 19:04:57 +0000162 unsigned getGlyphCount() { return this->generateGlyphCount(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000163 void getAdvance(SkGlyph*);
164 void getMetrics(SkGlyph*);
165 void getImage(const SkGlyph&);
166 void getPath(const SkGlyph&, SkPath*);
167 void getFontMetrics(SkPaint::FontMetrics* mX,
168 SkPaint::FontMetrics* mY);
169
djsollen@google.com60abb072012-02-15 18:49:15 +0000170#ifdef SK_BUILD_FOR_ANDROID
171 unsigned getBaseGlyphCount(SkUnichar charCode);
djsollen@google.com15eeca02012-06-01 12:52:26 +0000172
173 // This function must be public for SkTypeface_android.h, but should not be
174 // called by other callers
175 SkFontID findTypefaceIdForChar(SkUnichar uni) {
176 SkScalerContext* ctx = this;
177 while (NULL != ctx) {
178 if (ctx->generateCharToGlyph(uni)) {
179 return ctx->fRec.fFontID;
180 }
181 ctx = ctx->getNextContext();
182 }
183 return 0;
184 }
djsollen@google.com60abb072012-02-15 18:49:15 +0000185#endif
186
reed@android.com8a1c16f2008-12-17 15:59:43 +0000187 static inline void MakeRec(const SkPaint&, const SkMatrix*, Rec* rec);
reed@google.com10d2d4d2012-03-01 22:32:51 +0000188 static inline void PostMakeRec(Rec*);
189
reed@android.com8a1c16f2008-12-17 15:59:43 +0000190 static SkScalerContext* Create(const SkDescriptor*);
191
192protected:
193 Rec fRec;
194 unsigned fBaseGlyphCount;
195
ctguil@chromium.org0bc7bf52011-03-04 19:04:57 +0000196 virtual unsigned generateGlyphCount() = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000197 virtual uint16_t generateCharToGlyph(SkUnichar) = 0;
198 virtual void generateAdvance(SkGlyph*) = 0;
199 virtual void generateMetrics(SkGlyph*) = 0;
200 virtual void generateImage(const SkGlyph&) = 0;
201 virtual void generatePath(const SkGlyph&, SkPath*) = 0;
202 virtual void generateFontMetrics(SkPaint::FontMetrics* mX,
203 SkPaint::FontMetrics* mY) = 0;
reed@android.com9d3a9852010-01-08 14:07:42 +0000204 // default impl returns 0, indicating failure.
205 virtual SkUnichar generateGlyphToChar(uint16_t);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000206
reed@google.coma767fa02011-08-05 21:40:26 +0000207 void forceGenerateImageFromPath() { fGenerateImageFromPath = true; }
208
reed@android.com8a1c16f2008-12-17 15:59:43 +0000209private:
210 SkPathEffect* fPathEffect;
211 SkMaskFilter* fMaskFilter;
212 SkRasterizer* fRasterizer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000213
reed@google.coma767fa02011-08-05 21:40:26 +0000214 // if this is set, we draw the image from a path, rather than
215 // calling generateImage.
216 bool fGenerateImageFromPath;
217
reed@android.com8a1c16f2008-12-17 15:59:43 +0000218 void internalGetPath(const SkGlyph& glyph, SkPath* fillPath,
219 SkPath* devPath, SkMatrix* fillToDevMatrix);
220
reed@android.coma14ea0e2009-03-17 17:59:53 +0000221 // return the next context, treating fNextContext as a cache of the answer
222 SkScalerContext* getNextContext();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000223
reed@android.coma14ea0e2009-03-17 17:59:53 +0000224 // returns the right context from our link-list for this glyph. If no match
225 // is found, just returns the original context (this)
226 SkScalerContext* getGlyphContext(const SkGlyph& glyph);
227
228 // link-list of context, to handle missing chars. null-terminated.
229 SkScalerContext* fNextContext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000230};
231
232#define kRec_SkDescriptorTag SkSetFourByteTag('s', 'r', 'e', 'c')
233#define kPathEffect_SkDescriptorTag SkSetFourByteTag('p', 't', 'h', 'e')
234#define kMaskFilter_SkDescriptorTag SkSetFourByteTag('m', 's', 'k', 'f')
235#define kRasterizer_SkDescriptorTag SkSetFourByteTag('r', 'a', 's', 't')
236
reed@google.comcb6ccdd2011-08-23 21:30:47 +0000237///////////////////////////////////////////////////////////////////////////////
238
239enum SkAxisAlignment {
240 kNone_SkAxisAlignment,
241 kX_SkAxisAlignment,
242 kY_SkAxisAlignment
243};
244
245/**
246 * Return the axis (if any) that the baseline for horizontal text will land on
247 * after running through the specified matrix.
248 *
249 * As an example, the identity matrix will return kX_SkAxisAlignment
250 */
reed@google.com2e684782011-08-24 15:38:46 +0000251SkAxisAlignment SkComputeAxisAlignmentForHText(const SkMatrix& matrix);
reed@google.comcb6ccdd2011-08-23 21:30:47 +0000252
reed@android.com8a1c16f2008-12-17 15:59:43 +0000253#endif
254