blob: dd01bc68b7f16f4bd4fe62f601cbc969cd4e68de [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
32#define MASK_FORMAT_JUST_ADVANCE (0xFF)
33
34struct SkGlyph {
35 void* fImage;
36 SkPath* fPath;
37 SkFixed fAdvanceX, fAdvanceY;
38
39 uint32_t fID;
40 uint16_t fWidth, fHeight;
41 int16_t fTop, fLeft;
42
43 uint8_t fMaskFormat;
44 int8_t fRsbDelta, fLsbDelta; // used by auto-kerning
45
46 unsigned rowBytes() const {
47 unsigned rb = fWidth;
48 if (SkMask::kBW_Format == fMaskFormat) {
49 rb = (rb + 7) >> 3;
50 } else {
51 rb = SkAlign4(rb);
52 }
53 return rb;
54 }
55
56 bool isJustAdvance() const {
57 return MASK_FORMAT_JUST_ADVANCE == fMaskFormat;
58 }
59
60 bool isFullMetrics() const {
61 return MASK_FORMAT_JUST_ADVANCE != fMaskFormat;
62 }
63
64 uint16_t getGlyphID() const {
65 return ID2Code(fID);
66 }
67
68 unsigned getGlyphID(unsigned baseGlyphCount) const {
69 unsigned code = ID2Code(fID);
70 SkASSERT(code >= baseGlyphCount);
71 return code - baseGlyphCount;
72 }
73
74 unsigned getSubX() const {
75 return ID2SubX(fID);
76 }
77
78 SkFixed getSubXFixed() const {
79 return SubToFixed(ID2SubX(fID));
80 }
81
82 SkFixed getSubYFixed() const {
83 return SubToFixed(ID2SubY(fID));
84 }
85
86 size_t computeImageSize() const;
87
reed@android.com62900b42009-02-11 15:07:19 +000088 /** Call this to set all of the metrics fields to 0 (e.g. if the scaler
89 encounters an error measuring a glyph). Note: this does not alter the
90 fImage, fPath, fID, fMaskFormat fields.
91 */
92 void zeroMetrics();
93
reed@android.com8a1c16f2008-12-17 15:59:43 +000094 enum {
95 kSubBits = 2,
96 kSubMask = ((1 << kSubBits) - 1),
97 kSubShift = 24, // must be large enough for glyphs and unichars
98 kCodeMask = ((1 << kSubShift) - 1),
99 // relative offsets for X and Y subpixel bits
100 kSubShiftX = kSubBits,
101 kSubShiftY = 0
102 };
103
104 static unsigned ID2Code(uint32_t id) {
105 return id & kCodeMask;
106 }
107
108 static unsigned ID2SubX(uint32_t id) {
109 return id >> (kSubShift + kSubShiftX);
110 }
111
112 static unsigned ID2SubY(uint32_t id) {
113 return (id >> (kSubShift + kSubShiftY)) & kSubMask;
114 }
115
116 static unsigned FixedToSub(SkFixed n) {
117 return (n >> (16 - kSubBits)) & kSubMask;
118 }
119
120 static SkFixed SubToFixed(unsigned sub) {
121 SkASSERT(sub <= kSubMask);
122 return sub << (16 - kSubBits);
123 }
124
125 static uint32_t MakeID(unsigned code) {
126 return code;
127 }
128
129 static uint32_t MakeID(unsigned code, SkFixed x, SkFixed y) {
130 SkASSERT(code <= kCodeMask);
131 x = FixedToSub(x);
132 y = FixedToSub(y);
133 return (x << (kSubShift + kSubShiftX)) |
134 (y << (kSubShift + kSubShiftY)) |
135 code;
136 }
137
138 void toMask(SkMask* mask) const;
agl@chromium.org309485b2009-07-21 17:41:32 +0000139
140 /** Given a glyph which is has a mask format of LCD or VerticalLCD, take
141 the A8 plane in fImage and produce a valid LCD plane from it.
142 */
143 void expandA8ToLCD() const;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000144};
145
146class SkScalerContext {
147public:
reed@android.com8a1c16f2008-12-17 15:59:43 +0000148 enum Flags {
149 kFrameAndFill_Flag = 0x01,
150 kDevKernText_Flag = 0x02,
151 kGammaForBlack_Flag = 0x04, // illegal to set both Gamma flags
agl@chromium.org309485b2009-07-21 17:41:32 +0000152 kGammaForWhite_Flag = 0x08, // illegal to set both Gamma flags
153 // together, these two flags resulting in a two bit value which matches
154 // up with the SkPaint::Hinting enum.
reed@android.com36a4c2a2009-07-22 19:52:11 +0000155 kHintingBit1_Flag = 0x10,
156 kHintingBit2_Flag = 0x20,
reed@android.com8a1c16f2008-12-17 15:59:43 +0000157 };
158 struct Rec {
159 uint32_t fFontID;
160 SkScalar fTextSize, fPreScaleX, fPreSkewX;
161 SkScalar fPost2x2[2][2];
162 SkScalar fFrameWidth, fMiterLimit;
agl@chromium.org309485b2009-07-21 17:41:32 +0000163 bool fSubpixelPositioning;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000164 uint8_t fMaskFormat;
165 uint8_t fStrokeJoin;
166 uint8_t fFlags;
agl@chromium.org309485b2009-07-21 17:41:32 +0000167
reed@android.com8a1c16f2008-12-17 15:59:43 +0000168 void getMatrixFrom2x2(SkMatrix*) const;
169 void getLocalMatrix(SkMatrix*) const;
170 void getSingleMatrix(SkMatrix*) const;
agl@chromium.org309485b2009-07-21 17:41:32 +0000171
172 SkPaint::Hinting getHinting() const {
173 return static_cast<SkPaint::Hinting>((fFlags >> 4) & 3);
174 }
175
176 void setHinting(SkPaint::Hinting hinting) {
reed@android.com36a4c2a2009-07-22 19:52:11 +0000177 fFlags = (fFlags & ~(kHintingBit1_Flag | kHintingBit2_Flag)) |
agl@chromium.org309485b2009-07-21 17:41:32 +0000178 (static_cast<int>(hinting) << 4);
179 }
reed@android.com36a4c2a2009-07-22 19:52:11 +0000180
181 SkMask::Format getFormat() const {
182 return static_cast<SkMask::Format>(fMaskFormat);
183 }
184
185 bool isLCD() const {
186 return SkMask::FormatIsLCD(this->getFormat());
187 }
reed@android.com8a1c16f2008-12-17 15:59:43 +0000188 };
189
190 SkScalerContext(const SkDescriptor* desc);
191 virtual ~SkScalerContext();
192
reed@android.coma14ea0e2009-03-17 17:59:53 +0000193 // remember our glyph offset/base
reed@android.com8a1c16f2008-12-17 15:59:43 +0000194 void setBaseGlyphCount(unsigned baseGlyphCount) {
195 fBaseGlyphCount = baseGlyphCount;
196 }
197
reed@android.coma14ea0e2009-03-17 17:59:53 +0000198 /** Return the corresponding glyph for the specified unichar. Since contexts
199 may be chained (under the hood), the glyphID that is returned may in
200 fact correspond to a different font/context. In that case, we use the
201 base-glyph-count to know how to translate back into local glyph space.
202 */
reed@android.com8a1c16f2008-12-17 15:59:43 +0000203 uint16_t charToGlyphID(SkUnichar uni);
204
205 unsigned getGlyphCount() const { return this->generateGlyphCount(); }
206 void getAdvance(SkGlyph*);
207 void getMetrics(SkGlyph*);
208 void getImage(const SkGlyph&);
209 void getPath(const SkGlyph&, SkPath*);
210 void getFontMetrics(SkPaint::FontMetrics* mX,
211 SkPaint::FontMetrics* mY);
212
213 static inline void MakeRec(const SkPaint&, const SkMatrix*, Rec* rec);
214 static SkScalerContext* Create(const SkDescriptor*);
215
216protected:
217 Rec fRec;
218 unsigned fBaseGlyphCount;
219
220 virtual unsigned generateGlyphCount() const = 0;
221 virtual uint16_t generateCharToGlyph(SkUnichar) = 0;
222 virtual void generateAdvance(SkGlyph*) = 0;
223 virtual void generateMetrics(SkGlyph*) = 0;
224 virtual void generateImage(const SkGlyph&) = 0;
225 virtual void generatePath(const SkGlyph&, SkPath*) = 0;
226 virtual void generateFontMetrics(SkPaint::FontMetrics* mX,
227 SkPaint::FontMetrics* mY) = 0;
228
229private:
230 SkPathEffect* fPathEffect;
231 SkMaskFilter* fMaskFilter;
232 SkRasterizer* fRasterizer;
233 SkScalar fDevFrameWidth;
234
235 void internalGetPath(const SkGlyph& glyph, SkPath* fillPath,
236 SkPath* devPath, SkMatrix* fillToDevMatrix);
237
reed@android.coma14ea0e2009-03-17 17:59:53 +0000238 // return the next context, treating fNextContext as a cache of the answer
239 SkScalerContext* getNextContext();
reed@android.com8a1c16f2008-12-17 15:59:43 +0000240
reed@android.coma14ea0e2009-03-17 17:59:53 +0000241 // returns the right context from our link-list for this glyph. If no match
242 // is found, just returns the original context (this)
243 SkScalerContext* getGlyphContext(const SkGlyph& glyph);
244
245 // link-list of context, to handle missing chars. null-terminated.
246 SkScalerContext* fNextContext;
reed@android.com8a1c16f2008-12-17 15:59:43 +0000247};
248
249#define kRec_SkDescriptorTag SkSetFourByteTag('s', 'r', 'e', 'c')
250#define kPathEffect_SkDescriptorTag SkSetFourByteTag('p', 't', 'h', 'e')
251#define kMaskFilter_SkDescriptorTag SkSetFourByteTag('m', 's', 'k', 'f')
252#define kRasterizer_SkDescriptorTag SkSetFourByteTag('r', 'a', 's', 't')
253
254#endif
255