blob: 085e31d9590a311b790cea66b869d2c7c4b2d047 [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"
bungeman@google.com97efada2012-07-30 20:40:50 +000012#include "SkMaskGamma.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000013#include "SkMatrix.h"
14#include "SkPaint.h"
reed@android.com8a1c16f2008-12-17 15:59:43 +000015
bungeman@google.com6e502fe2012-07-24 21:18:54 +000016#ifdef SK_BUILD_FOR_ANDROID
bungeman@google.com97efada2012-07-30 20:40:50 +000017 //For SkFontID
18 #include "SkTypeface.h"
bungeman@google.com6e502fe2012-07-24 21:18:54 +000019#endif
20
bungeman@google.combbe50132012-07-24 20:33:21 +000021struct SkGlyph;
reed@android.com8a1c16f2008-12-17 15:59:43 +000022class SkDescriptor;
23class SkMaskFilter;
24class SkPathEffect;
25class SkRasterizer;
26
reed@google.coma9d4e842012-08-14 19:13:55 +000027/*
28 * To allow this to be forward-declared, it must be its own typename, rather
29 * than a nested struct inside SkScalerContext (where it started).
30 */
31struct SkScalerContextRec {
32 uint32_t fOrigFontID;
33 uint32_t fFontID;
34 SkScalar fTextSize, fPreScaleX, fPreSkewX;
35 SkScalar fPost2x2[2][2];
36 SkScalar fFrameWidth, fMiterLimit;
rmistry@google.comfbfcd562012-08-23 18:09:54 +000037
reed@google.coma9d4e842012-08-14 19:13:55 +000038 //These describe the parameters to create (uniquely identify) the pre-blend.
39 uint32_t fLumBits;
40 uint8_t fDeviceGamma; //2.6, (0.0, 4.0) gamma, 0.0 for sRGB
41 uint8_t fPaintGamma; //2.6, (0.0, 4.0) gamma, 0.0 for sRGB
42 uint8_t fContrast; //0.8+1, [0.0, 1.0] artificial contrast
43 uint8_t fReservedAlign;
rmistry@google.comfbfcd562012-08-23 18:09:54 +000044
reed@google.coma9d4e842012-08-14 19:13:55 +000045 SkScalar getDeviceGamma() const {
46 return SkIntToScalar(fDeviceGamma) / (1 << 6);
47 }
48 void setDeviceGamma(SkScalar dg) {
49 SkASSERT(0 <= dg && dg < SkIntToScalar(4));
50 fDeviceGamma = SkScalarFloorToInt(dg * (1 << 6));
51 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +000052
reed@google.coma9d4e842012-08-14 19:13:55 +000053 SkScalar getPaintGamma() const {
54 return SkIntToScalar(fPaintGamma) / (1 << 6);
55 }
56 void setPaintGamma(SkScalar pg) {
57 SkASSERT(0 <= pg && pg < SkIntToScalar(4));
58 fPaintGamma = SkScalarFloorToInt(pg * (1 << 6));
59 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +000060
reed@google.coma9d4e842012-08-14 19:13:55 +000061 SkScalar getContrast() const {
62 return SkIntToScalar(fContrast) / ((1 << 8) - 1);
63 }
64 void setContrast(SkScalar c) {
65 SkASSERT(0 <= c && c <= SK_Scalar1);
66 fContrast = SkScalarRoundToInt(c * ((1 << 8) - 1));
67 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +000068
reed@google.coma9d4e842012-08-14 19:13:55 +000069 /**
70 * Causes the luminance color and contrast to be ignored, and the
71 * paint and device gamma to be effectively 1.0.
72 */
73 void ignorePreBlend() {
74 setLuminanceColor(0x00000000);
75 setPaintGamma(SK_Scalar1);
76 setDeviceGamma(SK_Scalar1);
77 setContrast(0);
78 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +000079
reed@google.coma9d4e842012-08-14 19:13:55 +000080 uint8_t fMaskFormat;
81 uint8_t fStrokeJoin;
82 uint16_t fFlags;
83 // Warning: when adding members note that the size of this structure
84 // must be a multiple of 4. SkDescriptor requires that its arguments be
85 // multiples of four and this structure is put in an SkDescriptor in
86 // SkPaint::MakeRec.
rmistry@google.comfbfcd562012-08-23 18:09:54 +000087
reed@google.coma9d4e842012-08-14 19:13:55 +000088 void getMatrixFrom2x2(SkMatrix*) const;
89 void getLocalMatrix(SkMatrix*) const;
90 void getSingleMatrix(SkMatrix*) const;
rmistry@google.comfbfcd562012-08-23 18:09:54 +000091
reed@google.coma9d4e842012-08-14 19:13:55 +000092 inline SkPaint::Hinting getHinting() const;
93 inline void setHinting(SkPaint::Hinting);
rmistry@google.comfbfcd562012-08-23 18:09:54 +000094
reed@google.coma9d4e842012-08-14 19:13:55 +000095 SkMask::Format getFormat() const {
96 return static_cast<SkMask::Format>(fMaskFormat);
97 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +000098
reed@google.coma9d4e842012-08-14 19:13:55 +000099 SkColor getLuminanceColor() const {
100 return fLumBits;
101 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000102
reed@google.coma9d4e842012-08-14 19:13:55 +0000103 void setLuminanceColor(SkColor c) {
104 fLumBits = c;
105 }
106};
107
bungeman@google.com97efada2012-07-30 20:40:50 +0000108//The following typedef hides from the rest of the implementation the number of
109//most significant bits to consider when creating mask gamma tables. Two bits
110//per channel was chosen as a balance between fidelity (more bits) and cache
111//sizes (fewer bits).
112typedef SkTMaskGamma<2, 2, 2> SkMaskGamma;
113
reed@android.com8a1c16f2008-12-17 15:59:43 +0000114class SkScalerContext {
115public:
reed@google.coma9d4e842012-08-14 19:13:55 +0000116 typedef SkScalerContextRec Rec;
117
reed@android.com8a1c16f2008-12-17 15:59:43 +0000118 enum Flags {
reed@google.comb6bb5cb2011-11-21 19:32:29 +0000119 kFrameAndFill_Flag = 0x0001,
120 kDevKernText_Flag = 0x0002,
121 kEmbeddedBitmapText_Flag = 0x0004,
122 kEmbolden_Flag = 0x0008,
123 kSubpixelPositioning_Flag = 0x0010,
124 kAutohinting_Flag = 0x0020,
125 kVertical_Flag = 0x0040,
reed@google.comffe49f52011-11-22 19:42:41 +0000126
agl@chromium.org309485b2009-07-21 17:41:32 +0000127 // together, these two flags resulting in a two bit value which matches
128 // up with the SkPaint::Hinting enum.
reed@google.comffe49f52011-11-22 19:42:41 +0000129 kHinting_Shift = 7, // to shift into the other flags above
reed@google.comb6bb5cb2011-11-21 19:32:29 +0000130 kHintingBit1_Flag = 0x0080,
131 kHintingBit2_Flag = 0x0100,
reed@google.comffe49f52011-11-22 19:42:41 +0000132
reed@google.comeffc5012011-06-27 16:44:46 +0000133 // these should only ever be set if fMaskFormat is LCD16 or LCD32
reed@google.comb6bb5cb2011-11-21 19:32:29 +0000134 kLCD_Vertical_Flag = 0x0200, // else Horizontal
135 kLCD_BGROrder_Flag = 0x0400, // else RGB order
reed@google.comffe49f52011-11-22 19:42:41 +0000136
reed@google.com8351aab2012-01-18 17:06:35 +0000137 // Generate A8 from LCD source (for GDI), only meaningful if fMaskFormat is kA8
138 // Perhaps we can store this (instead) in fMaskFormat, in hight bit?
139 kGenA8FromLCD_Flag = 0x0800,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000140 };
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000141
reed@google.comffe49f52011-11-22 19:42:41 +0000142 // computed values
reed@android.come2ca2072009-07-27 16:39:38 +0000143 enum {
reed@google.comffe49f52011-11-22 19:42:41 +0000144 kHinting_Mask = kHintingBit1_Flag | kHintingBit2_Flag,
reed@android.come2ca2072009-07-27 16:39:38 +0000145 };
reed@google.comffe49f52011-11-22 19:42:41 +0000146
reed@android.com8a1c16f2008-12-17 15:59:43 +0000147
148 SkScalerContext(const SkDescriptor* desc);
149 virtual ~SkScalerContext();
150
reed@google.com98539c62011-03-15 15:40:16 +0000151 SkMask::Format getMaskFormat() const {
152 return (SkMask::Format)fRec.fMaskFormat;
153 }
154
reed@google.comabf00aa2012-01-03 19:43:20 +0000155 bool isSubpixel() const {
156 return SkToBool(fRec.fFlags & kSubpixelPositioning_Flag);
157 }
rmistry@google.comfbfcd562012-08-23 18:09:54 +0000158
reed@android.coma14ea0e2009-03-17 17:59:53 +0000159 // remember our glyph offset/base
reed@android.com8a1c16f2008-12-17 15:59:43 +0000160 void setBaseGlyphCount(unsigned baseGlyphCount) {
161 fBaseGlyphCount = baseGlyphCount;
162 }
163
reed@android.coma14ea0e2009-03-17 17:59:53 +0000164 /** Return the corresponding glyph for the specified unichar. Since contexts
165 may be chained (under the hood), the glyphID that is returned may in
166 fact correspond to a different font/context. In that case, we use the
167 base-glyph-count to know how to translate back into local glyph space.
168 */
reed@google.comffe49f52011-11-22 19:42:41 +0000169 uint16_t charToGlyphID(SkUnichar uni);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000170
reed@android.com9d3a9852010-01-08 14:07:42 +0000171 /** Map the glyphID to its glyph index, and then to its char code. Unmapped
172 glyphs return zero.
173 */
174 SkUnichar glyphIDToChar(uint16_t glyphID);
175
ctguil@chromium.org0bc7bf52011-03-04 19:04:57 +0000176 unsigned getGlyphCount() { return this->generateGlyphCount(); }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000177 void getAdvance(SkGlyph*);
178 void getMetrics(SkGlyph*);
179 void getImage(const SkGlyph&);
180 void getPath(const SkGlyph&, SkPath*);
181 void getFontMetrics(SkPaint::FontMetrics* mX,
182 SkPaint::FontMetrics* mY);
183
djsollen@google.com60abb072012-02-15 18:49:15 +0000184#ifdef SK_BUILD_FOR_ANDROID
185 unsigned getBaseGlyphCount(SkUnichar charCode);
djsollen@google.com15eeca02012-06-01 12:52:26 +0000186
187 // This function must be public for SkTypeface_android.h, but should not be
188 // called by other callers
189 SkFontID findTypefaceIdForChar(SkUnichar uni) {
190 SkScalerContext* ctx = this;
191 while (NULL != ctx) {
192 if (ctx->generateCharToGlyph(uni)) {
193 return ctx->fRec.fFontID;
194 }
195 ctx = ctx->getNextContext();
196 }
197 return 0;
198 }
djsollen@google.com60abb072012-02-15 18:49:15 +0000199#endif
200
reed@android.com8a1c16f2008-12-17 15:59:43 +0000201 static inline void MakeRec(const SkPaint&, const SkMatrix*, Rec* rec);
bungeman@google.com97efada2012-07-30 20:40:50 +0000202 static inline void PostMakeRec(const SkPaint&, Rec*);
reed@google.com10d2d4d2012-03-01 22:32:51 +0000203
reed@android.com8a1c16f2008-12-17 15:59:43 +0000204 static SkScalerContext* Create(const SkDescriptor*);
bungeman@google.com97efada2012-07-30 20:40:50 +0000205 static SkMaskGamma::PreBlend GetMaskPreBlend(const Rec& rec);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000206
207protected:
208 Rec fRec;
209 unsigned fBaseGlyphCount;
210
ctguil@chromium.org0bc7bf52011-03-04 19:04:57 +0000211 virtual unsigned generateGlyphCount() = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000212 virtual uint16_t generateCharToGlyph(SkUnichar) = 0;
213 virtual void generateAdvance(SkGlyph*) = 0;
214 virtual void generateMetrics(SkGlyph*) = 0;
bungeman@google.com97efada2012-07-30 20:40:50 +0000215 virtual void generateImage(const SkGlyph&, SkMaskGamma::PreBlend* maskPreBlend) = 0;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000216 virtual void generatePath(const SkGlyph&, SkPath*) = 0;
217 virtual void generateFontMetrics(SkPaint::FontMetrics* mX,
218 SkPaint::FontMetrics* mY) = 0;
reed@android.com9d3a9852010-01-08 14:07:42 +0000219 // default impl returns 0, indicating failure.
220 virtual SkUnichar generateGlyphToChar(uint16_t);
reed@android.com8a1c16f2008-12-17 15:59:43 +0000221
reed@google.coma767fa02011-08-05 21:40:26 +0000222 void forceGenerateImageFromPath() { fGenerateImageFromPath = true; }
223
reed@android.com8a1c16f2008-12-17 15:59:43 +0000224private:
225 SkPathEffect* fPathEffect;
226 SkMaskFilter* fMaskFilter;
227 SkRasterizer* fRasterizer;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000228
reed@google.coma767fa02011-08-05 21:40:26 +0000229 // if this is set, we draw the image from a path, rather than
230 // calling generateImage.
231 bool fGenerateImageFromPath;
232
reed@android.com8a1c16f2008-12-17 15:59:43 +0000233 void internalGetPath(const SkGlyph& glyph, SkPath* fillPath,
234 SkPath* devPath, SkMatrix* fillToDevMatrix);
235
reed@android.coma14ea0e2009-03-17 17:59:53 +0000236 // return the next context, treating fNextContext as a cache of the answer
237 SkScalerContext* getNextContext();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000238
reed@android.coma14ea0e2009-03-17 17:59:53 +0000239 // returns the right context from our link-list for this glyph. If no match
240 // is found, just returns the original context (this)
241 SkScalerContext* getGlyphContext(const SkGlyph& glyph);
242
243 // link-list of context, to handle missing chars. null-terminated.
244 SkScalerContext* fNextContext;
bungeman@google.com97efada2012-07-30 20:40:50 +0000245
246 // converts linear masks to gamma correcting masks.
247 SkMaskGamma::PreBlend fMaskPreBlend;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000248};
249
250#define kRec_SkDescriptorTag SkSetFourByteTag('s', 'r', 'e', 'c')
251#define kPathEffect_SkDescriptorTag SkSetFourByteTag('p', 't', 'h', 'e')
252#define kMaskFilter_SkDescriptorTag SkSetFourByteTag('m', 's', 'k', 'f')
253#define kRasterizer_SkDescriptorTag SkSetFourByteTag('r', 'a', 's', 't')
254
reed@google.comcb6ccdd2011-08-23 21:30:47 +0000255///////////////////////////////////////////////////////////////////////////////
256
257enum SkAxisAlignment {
258 kNone_SkAxisAlignment,
259 kX_SkAxisAlignment,
260 kY_SkAxisAlignment
261};
262
263/**
264 * Return the axis (if any) that the baseline for horizontal text will land on
265 * after running through the specified matrix.
266 *
267 * As an example, the identity matrix will return kX_SkAxisAlignment
268 */
reed@google.com2e684782011-08-24 15:38:46 +0000269SkAxisAlignment SkComputeAxisAlignmentForHText(const SkMatrix& matrix);
reed@google.comcb6ccdd2011-08-23 21:30:47 +0000270
reed@google.coma9d4e842012-08-14 19:13:55 +0000271///////////////////////////////////////////////////////////////////////////////
272
273SkPaint::Hinting SkScalerContextRec::getHinting() const {
274 unsigned hint = (fFlags & SkScalerContext::kHinting_Mask) >>
275 SkScalerContext::kHinting_Shift;
276 return static_cast<SkPaint::Hinting>(hint);
277}
278
279void SkScalerContextRec::setHinting(SkPaint::Hinting hinting) {
280 fFlags = (fFlags & ~SkScalerContext::kHinting_Mask) |
281 (hinting << SkScalerContext::kHinting_Shift);
282}
283
284
reed@android.com8a1c16f2008-12-17 15:59:43 +0000285#endif
286