|
1 |
|
2 /* |
|
3 * Copyright 2006 The Android Open Source Project |
|
4 * |
|
5 * Use of this source code is governed by a BSD-style license that can be |
|
6 * found in the LICENSE file. |
|
7 */ |
|
8 |
|
9 #include "SkPaint.h" |
|
10 #include "SkAnnotation.h" |
|
11 #include "SkAutoKern.h" |
|
12 #include "SkColorFilter.h" |
|
13 #include "SkData.h" |
|
14 #include "SkDeviceProperties.h" |
|
15 #include "SkFontDescriptor.h" |
|
16 #include "SkFontHost.h" |
|
17 #include "SkGlyphCache.h" |
|
18 #include "SkImageFilter.h" |
|
19 #include "SkMaskFilter.h" |
|
20 #include "SkMaskGamma.h" |
|
21 #include "SkReadBuffer.h" |
|
22 #include "SkWriteBuffer.h" |
|
23 #include "SkPaintDefaults.h" |
|
24 #include "SkPaintOptionsAndroid.h" |
|
25 #include "SkPathEffect.h" |
|
26 #include "SkRasterizer.h" |
|
27 #include "SkScalar.h" |
|
28 #include "SkScalerContext.h" |
|
29 #include "SkShader.h" |
|
30 #include "SkStringUtils.h" |
|
31 #include "SkStroke.h" |
|
32 #include "SkTextFormatParams.h" |
|
33 #include "SkTextToPathIter.h" |
|
34 #include "SkTLazy.h" |
|
35 #include "SkTypeface.h" |
|
36 #include "SkXfermode.h" |
|
37 |
|
38 enum { |
|
39 kColor_DirtyBit = 1 << 0, |
|
40 kBitfields_DirtyBit = 1 << 1, |
|
41 kTextSize_DirtyBit = 1 << 2, |
|
42 kTextScaleX_DirtyBit = 1 << 3, |
|
43 kTextSkewX_DirtyBit = 1 << 4, |
|
44 kStrokeWidth_DirtyBit = 1 << 5, |
|
45 kStrokeMiter_DirtyBit = 1 << 6, |
|
46 kPathEffect_DirtyBit = 1 << 7, |
|
47 kShader_DirtyBit = 1 << 8, |
|
48 kXfermode_DirtyBit = 1 << 9, |
|
49 kMaskFilter_DirtyBit = 1 << 10, |
|
50 kColorFilter_DirtyBit = 1 << 11, |
|
51 kRasterizer_DirtyBit = 1 << 12, |
|
52 kLooper_DirtyBit = 1 << 13, |
|
53 kImageFilter_DirtyBit = 1 << 14, |
|
54 kTypeface_DirtyBit = 1 << 15, |
|
55 kAnnotation_DirtyBit = 1 << 16, |
|
56 kPaintOptionsAndroid_DirtyBit = 1 << 17, |
|
57 }; |
|
58 |
|
59 // define this to get a printf for out-of-range parameter in setters |
|
60 // e.g. setTextSize(-1) |
|
61 //#define SK_REPORT_API_RANGE_CHECK |
|
62 |
|
63 #ifdef SK_BUILD_FOR_ANDROID |
|
64 #define GEN_ID_INC fGenerationID++ |
|
65 #define GEN_ID_INC_EVAL(expression) if (expression) { fGenerationID++; } |
|
66 #else |
|
67 #define GEN_ID_INC |
|
68 #define GEN_ID_INC_EVAL(expression) |
|
69 #endif |
|
70 |
|
71 SkPaint::SkPaint() { |
|
72 // since we may have padding, we zero everything so that our memcmp() call |
|
73 // in operator== will work correctly. |
|
74 // with this, we can skip 0 and null individual initializations |
|
75 sk_bzero(this, sizeof(*this)); |
|
76 |
|
77 #if 0 // not needed with the bzero call above |
|
78 fTypeface = NULL; |
|
79 fTextSkewX = 0; |
|
80 fPathEffect = NULL; |
|
81 fShader = NULL; |
|
82 fXfermode = NULL; |
|
83 fMaskFilter = NULL; |
|
84 fColorFilter = NULL; |
|
85 fRasterizer = NULL; |
|
86 fLooper = NULL; |
|
87 fImageFilter = NULL; |
|
88 fAnnotation = NULL; |
|
89 fWidth = 0; |
|
90 fDirtyBits = 0; |
|
91 #endif |
|
92 |
|
93 fTextSize = SkPaintDefaults_TextSize; |
|
94 fTextScaleX = SK_Scalar1; |
|
95 fColor = SK_ColorBLACK; |
|
96 fMiterLimit = SkPaintDefaults_MiterLimit; |
|
97 fFlags = SkPaintDefaults_Flags; |
|
98 fCapType = kDefault_Cap; |
|
99 fJoinType = kDefault_Join; |
|
100 fTextAlign = kLeft_Align; |
|
101 fStyle = kFill_Style; |
|
102 fTextEncoding = kUTF8_TextEncoding; |
|
103 fHinting = SkPaintDefaults_Hinting; |
|
104 #ifdef SK_BUILD_FOR_ANDROID |
|
105 new (&fPaintOptionsAndroid) SkPaintOptionsAndroid; |
|
106 fGenerationID = 0; |
|
107 #endif |
|
108 } |
|
109 |
|
110 SkPaint::SkPaint(const SkPaint& src) { |
|
111 memcpy(this, &src, sizeof(src)); |
|
112 |
|
113 SkSafeRef(fTypeface); |
|
114 SkSafeRef(fPathEffect); |
|
115 SkSafeRef(fShader); |
|
116 SkSafeRef(fXfermode); |
|
117 SkSafeRef(fMaskFilter); |
|
118 SkSafeRef(fColorFilter); |
|
119 SkSafeRef(fRasterizer); |
|
120 SkSafeRef(fLooper); |
|
121 SkSafeRef(fImageFilter); |
|
122 SkSafeRef(fAnnotation); |
|
123 |
|
124 #ifdef SK_BUILD_FOR_ANDROID |
|
125 new (&fPaintOptionsAndroid) SkPaintOptionsAndroid(src.fPaintOptionsAndroid); |
|
126 #endif |
|
127 } |
|
128 |
|
129 SkPaint::~SkPaint() { |
|
130 SkSafeUnref(fTypeface); |
|
131 SkSafeUnref(fPathEffect); |
|
132 SkSafeUnref(fShader); |
|
133 SkSafeUnref(fXfermode); |
|
134 SkSafeUnref(fMaskFilter); |
|
135 SkSafeUnref(fColorFilter); |
|
136 SkSafeUnref(fRasterizer); |
|
137 SkSafeUnref(fLooper); |
|
138 SkSafeUnref(fImageFilter); |
|
139 SkSafeUnref(fAnnotation); |
|
140 } |
|
141 |
|
142 SkPaint& SkPaint::operator=(const SkPaint& src) { |
|
143 SkASSERT(&src); |
|
144 |
|
145 SkSafeRef(src.fTypeface); |
|
146 SkSafeRef(src.fPathEffect); |
|
147 SkSafeRef(src.fShader); |
|
148 SkSafeRef(src.fXfermode); |
|
149 SkSafeRef(src.fMaskFilter); |
|
150 SkSafeRef(src.fColorFilter); |
|
151 SkSafeRef(src.fRasterizer); |
|
152 SkSafeRef(src.fLooper); |
|
153 SkSafeRef(src.fImageFilter); |
|
154 SkSafeRef(src.fAnnotation); |
|
155 |
|
156 SkSafeUnref(fTypeface); |
|
157 SkSafeUnref(fPathEffect); |
|
158 SkSafeUnref(fShader); |
|
159 SkSafeUnref(fXfermode); |
|
160 SkSafeUnref(fMaskFilter); |
|
161 SkSafeUnref(fColorFilter); |
|
162 SkSafeUnref(fRasterizer); |
|
163 SkSafeUnref(fLooper); |
|
164 SkSafeUnref(fImageFilter); |
|
165 SkSafeUnref(fAnnotation); |
|
166 |
|
167 #ifdef SK_BUILD_FOR_ANDROID |
|
168 fPaintOptionsAndroid.~SkPaintOptionsAndroid(); |
|
169 |
|
170 uint32_t oldGenerationID = fGenerationID; |
|
171 #endif |
|
172 memcpy(this, &src, sizeof(src)); |
|
173 #ifdef SK_BUILD_FOR_ANDROID |
|
174 fGenerationID = oldGenerationID + 1; |
|
175 |
|
176 new (&fPaintOptionsAndroid) SkPaintOptionsAndroid(src.fPaintOptionsAndroid); |
|
177 #endif |
|
178 |
|
179 return *this; |
|
180 } |
|
181 |
|
182 bool operator==(const SkPaint& a, const SkPaint& b) { |
|
183 #ifdef SK_BUILD_FOR_ANDROID |
|
184 //assumes that fGenerationID is the last field in the struct |
|
185 return !memcmp(&a, &b, SK_OFFSETOF(SkPaint, fGenerationID)); |
|
186 #else |
|
187 return !memcmp(&a, &b, sizeof(a)); |
|
188 #endif |
|
189 } |
|
190 |
|
191 void SkPaint::reset() { |
|
192 SkPaint init; |
|
193 |
|
194 #ifdef SK_BUILD_FOR_ANDROID |
|
195 uint32_t oldGenerationID = fGenerationID; |
|
196 #endif |
|
197 *this = init; |
|
198 #ifdef SK_BUILD_FOR_ANDROID |
|
199 fGenerationID = oldGenerationID + 1; |
|
200 #endif |
|
201 } |
|
202 |
|
203 #ifdef SK_BUILD_FOR_ANDROID |
|
204 uint32_t SkPaint::getGenerationID() const { |
|
205 return fGenerationID; |
|
206 } |
|
207 |
|
208 void SkPaint::setGenerationID(uint32_t generationID) { |
|
209 fGenerationID = generationID; |
|
210 } |
|
211 |
|
212 unsigned SkPaint::getBaseGlyphCount(SkUnichar text) const { |
|
213 SkAutoGlyphCache autoCache(*this, NULL, NULL); |
|
214 SkGlyphCache* cache = autoCache.getCache(); |
|
215 return cache->getBaseGlyphCount(text); |
|
216 } |
|
217 |
|
218 void SkPaint::setPaintOptionsAndroid(const SkPaintOptionsAndroid& options) { |
|
219 if (options != fPaintOptionsAndroid) { |
|
220 fPaintOptionsAndroid = options; |
|
221 GEN_ID_INC; |
|
222 fDirtyBits |= kPaintOptionsAndroid_DirtyBit; |
|
223 } |
|
224 } |
|
225 #endif |
|
226 |
|
227 SkPaint::FilterLevel SkPaint::getFilterLevel() const { |
|
228 int level = 0; |
|
229 if (fFlags & kFilterBitmap_Flag) { |
|
230 level |= 1; |
|
231 } |
|
232 if (fFlags & kHighQualityFilterBitmap_Flag) { |
|
233 level |= 2; |
|
234 } |
|
235 return (FilterLevel)level; |
|
236 } |
|
237 |
|
238 void SkPaint::setFilterLevel(FilterLevel level) { |
|
239 unsigned mask = kFilterBitmap_Flag | kHighQualityFilterBitmap_Flag; |
|
240 unsigned flags = 0; |
|
241 if (level & 1) { |
|
242 flags |= kFilterBitmap_Flag; |
|
243 } |
|
244 if (level & 2) { |
|
245 flags |= kHighQualityFilterBitmap_Flag; |
|
246 } |
|
247 this->setFlags((fFlags & ~mask) | flags); |
|
248 } |
|
249 |
|
250 void SkPaint::setHinting(Hinting hintingLevel) { |
|
251 GEN_ID_INC_EVAL((unsigned) hintingLevel != fHinting); |
|
252 fHinting = hintingLevel; |
|
253 fDirtyBits |= kBitfields_DirtyBit; |
|
254 } |
|
255 |
|
256 void SkPaint::setFlags(uint32_t flags) { |
|
257 GEN_ID_INC_EVAL(fFlags != flags); |
|
258 fFlags = flags; |
|
259 fDirtyBits |= kBitfields_DirtyBit; |
|
260 } |
|
261 |
|
262 void SkPaint::setAntiAlias(bool doAA) { |
|
263 this->setFlags(SkSetClearMask(fFlags, doAA, kAntiAlias_Flag)); |
|
264 } |
|
265 |
|
266 void SkPaint::setDither(bool doDither) { |
|
267 this->setFlags(SkSetClearMask(fFlags, doDither, kDither_Flag)); |
|
268 } |
|
269 |
|
270 void SkPaint::setSubpixelText(bool doSubpixel) { |
|
271 this->setFlags(SkSetClearMask(fFlags, doSubpixel, kSubpixelText_Flag)); |
|
272 } |
|
273 |
|
274 void SkPaint::setLCDRenderText(bool doLCDRender) { |
|
275 this->setFlags(SkSetClearMask(fFlags, doLCDRender, kLCDRenderText_Flag)); |
|
276 } |
|
277 |
|
278 void SkPaint::setEmbeddedBitmapText(bool doEmbeddedBitmapText) { |
|
279 this->setFlags(SkSetClearMask(fFlags, doEmbeddedBitmapText, kEmbeddedBitmapText_Flag)); |
|
280 } |
|
281 |
|
282 void SkPaint::setAutohinted(bool useAutohinter) { |
|
283 this->setFlags(SkSetClearMask(fFlags, useAutohinter, kAutoHinting_Flag)); |
|
284 } |
|
285 |
|
286 void SkPaint::setLinearText(bool doLinearText) { |
|
287 this->setFlags(SkSetClearMask(fFlags, doLinearText, kLinearText_Flag)); |
|
288 } |
|
289 |
|
290 void SkPaint::setVerticalText(bool doVertical) { |
|
291 this->setFlags(SkSetClearMask(fFlags, doVertical, kVerticalText_Flag)); |
|
292 } |
|
293 |
|
294 void SkPaint::setUnderlineText(bool doUnderline) { |
|
295 this->setFlags(SkSetClearMask(fFlags, doUnderline, kUnderlineText_Flag)); |
|
296 } |
|
297 |
|
298 void SkPaint::setStrikeThruText(bool doStrikeThru) { |
|
299 this->setFlags(SkSetClearMask(fFlags, doStrikeThru, kStrikeThruText_Flag)); |
|
300 } |
|
301 |
|
302 void SkPaint::setFakeBoldText(bool doFakeBold) { |
|
303 this->setFlags(SkSetClearMask(fFlags, doFakeBold, kFakeBoldText_Flag)); |
|
304 } |
|
305 |
|
306 void SkPaint::setDevKernText(bool doDevKern) { |
|
307 this->setFlags(SkSetClearMask(fFlags, doDevKern, kDevKernText_Flag)); |
|
308 } |
|
309 |
|
310 void SkPaint::setDistanceFieldTextTEMP(bool doDistanceFieldText) { |
|
311 this->setFlags(SkSetClearMask(fFlags, doDistanceFieldText, kDistanceFieldTextTEMP_Flag)); |
|
312 } |
|
313 |
|
314 void SkPaint::setStyle(Style style) { |
|
315 if ((unsigned)style < kStyleCount) { |
|
316 GEN_ID_INC_EVAL((unsigned)style != fStyle); |
|
317 fStyle = style; |
|
318 fDirtyBits |= kBitfields_DirtyBit; |
|
319 } else { |
|
320 #ifdef SK_REPORT_API_RANGE_CHECK |
|
321 SkDebugf("SkPaint::setStyle(%d) out of range\n", style); |
|
322 #endif |
|
323 } |
|
324 } |
|
325 |
|
326 void SkPaint::setColor(SkColor color) { |
|
327 GEN_ID_INC_EVAL(color != fColor); |
|
328 fColor = color; |
|
329 fDirtyBits |= kColor_DirtyBit; |
|
330 } |
|
331 |
|
332 void SkPaint::setAlpha(U8CPU a) { |
|
333 this->setColor(SkColorSetARGB(a, SkColorGetR(fColor), |
|
334 SkColorGetG(fColor), SkColorGetB(fColor))); |
|
335 } |
|
336 |
|
337 void SkPaint::setARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b) { |
|
338 this->setColor(SkColorSetARGB(a, r, g, b)); |
|
339 } |
|
340 |
|
341 void SkPaint::setStrokeWidth(SkScalar width) { |
|
342 if (width >= 0) { |
|
343 GEN_ID_INC_EVAL(width != fWidth); |
|
344 fWidth = width; |
|
345 fDirtyBits |= kStrokeWidth_DirtyBit; |
|
346 } else { |
|
347 #ifdef SK_REPORT_API_RANGE_CHECK |
|
348 SkDebugf("SkPaint::setStrokeWidth() called with negative value\n"); |
|
349 #endif |
|
350 } |
|
351 } |
|
352 |
|
353 void SkPaint::setStrokeMiter(SkScalar limit) { |
|
354 if (limit >= 0) { |
|
355 GEN_ID_INC_EVAL(limit != fMiterLimit); |
|
356 fMiterLimit = limit; |
|
357 fDirtyBits |= kStrokeMiter_DirtyBit; |
|
358 } else { |
|
359 #ifdef SK_REPORT_API_RANGE_CHECK |
|
360 SkDebugf("SkPaint::setStrokeMiter() called with negative value\n"); |
|
361 #endif |
|
362 } |
|
363 } |
|
364 |
|
365 void SkPaint::setStrokeCap(Cap ct) { |
|
366 if ((unsigned)ct < kCapCount) { |
|
367 GEN_ID_INC_EVAL((unsigned)ct != fCapType); |
|
368 fCapType = SkToU8(ct); |
|
369 fDirtyBits |= kBitfields_DirtyBit; |
|
370 } else { |
|
371 #ifdef SK_REPORT_API_RANGE_CHECK |
|
372 SkDebugf("SkPaint::setStrokeCap(%d) out of range\n", ct); |
|
373 #endif |
|
374 } |
|
375 } |
|
376 |
|
377 void SkPaint::setStrokeJoin(Join jt) { |
|
378 if ((unsigned)jt < kJoinCount) { |
|
379 GEN_ID_INC_EVAL((unsigned)jt != fJoinType); |
|
380 fJoinType = SkToU8(jt); |
|
381 fDirtyBits |= kBitfields_DirtyBit; |
|
382 } else { |
|
383 #ifdef SK_REPORT_API_RANGE_CHECK |
|
384 SkDebugf("SkPaint::setStrokeJoin(%d) out of range\n", jt); |
|
385 #endif |
|
386 } |
|
387 } |
|
388 |
|
389 /////////////////////////////////////////////////////////////////////////////// |
|
390 |
|
391 void SkPaint::setTextAlign(Align align) { |
|
392 if ((unsigned)align < kAlignCount) { |
|
393 GEN_ID_INC_EVAL((unsigned)align != fTextAlign); |
|
394 fTextAlign = SkToU8(align); |
|
395 fDirtyBits |= kBitfields_DirtyBit; |
|
396 } else { |
|
397 #ifdef SK_REPORT_API_RANGE_CHECK |
|
398 SkDebugf("SkPaint::setTextAlign(%d) out of range\n", align); |
|
399 #endif |
|
400 } |
|
401 } |
|
402 |
|
403 void SkPaint::setTextSize(SkScalar ts) { |
|
404 if (ts >= 0) { |
|
405 GEN_ID_INC_EVAL(ts != fTextSize); |
|
406 fTextSize = ts; |
|
407 fDirtyBits |= kTextSize_DirtyBit; |
|
408 } else { |
|
409 #ifdef SK_REPORT_API_RANGE_CHECK |
|
410 SkDebugf("SkPaint::setTextSize() called with negative value\n"); |
|
411 #endif |
|
412 } |
|
413 } |
|
414 |
|
415 void SkPaint::setTextScaleX(SkScalar scaleX) { |
|
416 GEN_ID_INC_EVAL(scaleX != fTextScaleX); |
|
417 fTextScaleX = scaleX; |
|
418 fDirtyBits |= kTextScaleX_DirtyBit; |
|
419 } |
|
420 |
|
421 void SkPaint::setTextSkewX(SkScalar skewX) { |
|
422 GEN_ID_INC_EVAL(skewX != fTextSkewX); |
|
423 fTextSkewX = skewX; |
|
424 fDirtyBits |= kTextSkewX_DirtyBit; |
|
425 } |
|
426 |
|
427 void SkPaint::setTextEncoding(TextEncoding encoding) { |
|
428 if ((unsigned)encoding <= kGlyphID_TextEncoding) { |
|
429 GEN_ID_INC_EVAL((unsigned)encoding != fTextEncoding); |
|
430 fTextEncoding = encoding; |
|
431 fDirtyBits |= kBitfields_DirtyBit; |
|
432 } else { |
|
433 #ifdef SK_REPORT_API_RANGE_CHECK |
|
434 SkDebugf("SkPaint::setTextEncoding(%d) out of range\n", encoding); |
|
435 #endif |
|
436 } |
|
437 } |
|
438 |
|
439 /////////////////////////////////////////////////////////////////////////////// |
|
440 |
|
441 // Returns dst with the given bitmask enabled or disabled, depending on value. |
|
442 inline static uint32_t set_mask(uint32_t dst, uint32_t bitmask, bool value) { |
|
443 return value ? (dst | bitmask) : (dst & ~bitmask); |
|
444 } |
|
445 |
|
446 SkTypeface* SkPaint::setTypeface(SkTypeface* font) { |
|
447 SkRefCnt_SafeAssign(fTypeface, font); |
|
448 GEN_ID_INC; |
|
449 fDirtyBits = set_mask(fDirtyBits, kTypeface_DirtyBit, font != NULL); |
|
450 return font; |
|
451 } |
|
452 |
|
453 SkRasterizer* SkPaint::setRasterizer(SkRasterizer* r) { |
|
454 SkRefCnt_SafeAssign(fRasterizer, r); |
|
455 GEN_ID_INC; |
|
456 fDirtyBits = set_mask(fDirtyBits, kRasterizer_DirtyBit, r != NULL); |
|
457 return r; |
|
458 } |
|
459 |
|
460 SkDrawLooper* SkPaint::setLooper(SkDrawLooper* looper) { |
|
461 SkRefCnt_SafeAssign(fLooper, looper); |
|
462 GEN_ID_INC; |
|
463 fDirtyBits = set_mask(fDirtyBits, kLooper_DirtyBit, looper != NULL); |
|
464 return looper; |
|
465 } |
|
466 |
|
467 SkImageFilter* SkPaint::setImageFilter(SkImageFilter* imageFilter) { |
|
468 SkRefCnt_SafeAssign(fImageFilter, imageFilter); |
|
469 GEN_ID_INC; |
|
470 fDirtyBits = set_mask(fDirtyBits, kImageFilter_DirtyBit, imageFilter != NULL); |
|
471 return imageFilter; |
|
472 } |
|
473 |
|
474 SkAnnotation* SkPaint::setAnnotation(SkAnnotation* annotation) { |
|
475 SkRefCnt_SafeAssign(fAnnotation, annotation); |
|
476 GEN_ID_INC; |
|
477 fDirtyBits = set_mask(fDirtyBits, kAnnotation_DirtyBit, annotation != NULL); |
|
478 return annotation; |
|
479 } |
|
480 |
|
481 /////////////////////////////////////////////////////////////////////////////// |
|
482 |
|
483 static SkScalar mag2(SkScalar x, SkScalar y) { |
|
484 return x * x + y * y; |
|
485 } |
|
486 |
|
487 static bool tooBig(const SkMatrix& m, SkScalar ma2max) { |
|
488 return mag2(m[SkMatrix::kMScaleX], m[SkMatrix::kMSkewY]) > ma2max |
|
489 || |
|
490 mag2(m[SkMatrix::kMSkewX], m[SkMatrix::kMScaleY]) > ma2max; |
|
491 } |
|
492 |
|
493 bool SkPaint::TooBigToUseCache(const SkMatrix& ctm, const SkMatrix& textM) { |
|
494 SkASSERT(!ctm.hasPerspective()); |
|
495 SkASSERT(!textM.hasPerspective()); |
|
496 |
|
497 SkMatrix matrix; |
|
498 matrix.setConcat(ctm, textM); |
|
499 return tooBig(matrix, MaxCacheSize2()); |
|
500 } |
|
501 |
|
502 bool SkPaint::tooBigToUseCache(const SkMatrix& ctm) const { |
|
503 SkMatrix textM; |
|
504 return TooBigToUseCache(ctm, *this->setTextMatrix(&textM)); |
|
505 } |
|
506 |
|
507 bool SkPaint::tooBigToUseCache() const { |
|
508 SkMatrix textM; |
|
509 return tooBig(*this->setTextMatrix(&textM), MaxCacheSize2()); |
|
510 } |
|
511 |
|
512 /////////////////////////////////////////////////////////////////////////////// |
|
513 |
|
514 #include "SkGlyphCache.h" |
|
515 #include "SkUtils.h" |
|
516 |
|
517 static void DetachDescProc(SkTypeface* typeface, const SkDescriptor* desc, |
|
518 void* context) { |
|
519 *((SkGlyphCache**)context) = SkGlyphCache::DetachCache(typeface, desc); |
|
520 } |
|
521 |
|
522 int SkPaint::textToGlyphs(const void* textData, size_t byteLength, |
|
523 uint16_t glyphs[]) const { |
|
524 if (byteLength == 0) { |
|
525 return 0; |
|
526 } |
|
527 |
|
528 SkASSERT(textData != NULL); |
|
529 |
|
530 if (NULL == glyphs) { |
|
531 switch (this->getTextEncoding()) { |
|
532 case kUTF8_TextEncoding: |
|
533 return SkUTF8_CountUnichars((const char*)textData, byteLength); |
|
534 case kUTF16_TextEncoding: |
|
535 return SkUTF16_CountUnichars((const uint16_t*)textData, |
|
536 byteLength >> 1); |
|
537 case kUTF32_TextEncoding: |
|
538 return byteLength >> 2; |
|
539 case kGlyphID_TextEncoding: |
|
540 return byteLength >> 1; |
|
541 default: |
|
542 SkDEBUGFAIL("unknown text encoding"); |
|
543 } |
|
544 return 0; |
|
545 } |
|
546 |
|
547 // if we get here, we have a valid glyphs[] array, so time to fill it in |
|
548 |
|
549 // handle this encoding before the setup for the glyphcache |
|
550 if (this->getTextEncoding() == kGlyphID_TextEncoding) { |
|
551 // we want to ignore the low bit of byteLength |
|
552 memcpy(glyphs, textData, byteLength >> 1 << 1); |
|
553 return byteLength >> 1; |
|
554 } |
|
555 |
|
556 SkAutoGlyphCache autoCache(*this, NULL, NULL); |
|
557 SkGlyphCache* cache = autoCache.getCache(); |
|
558 |
|
559 const char* text = (const char*)textData; |
|
560 const char* stop = text + byteLength; |
|
561 uint16_t* gptr = glyphs; |
|
562 |
|
563 switch (this->getTextEncoding()) { |
|
564 case SkPaint::kUTF8_TextEncoding: |
|
565 while (text < stop) { |
|
566 *gptr++ = cache->unicharToGlyph(SkUTF8_NextUnichar(&text)); |
|
567 } |
|
568 break; |
|
569 case SkPaint::kUTF16_TextEncoding: { |
|
570 const uint16_t* text16 = (const uint16_t*)text; |
|
571 const uint16_t* stop16 = (const uint16_t*)stop; |
|
572 while (text16 < stop16) { |
|
573 *gptr++ = cache->unicharToGlyph(SkUTF16_NextUnichar(&text16)); |
|
574 } |
|
575 break; |
|
576 } |
|
577 case kUTF32_TextEncoding: { |
|
578 const int32_t* text32 = (const int32_t*)text; |
|
579 const int32_t* stop32 = (const int32_t*)stop; |
|
580 while (text32 < stop32) { |
|
581 *gptr++ = cache->unicharToGlyph(*text32++); |
|
582 } |
|
583 break; |
|
584 } |
|
585 default: |
|
586 SkDEBUGFAIL("unknown text encoding"); |
|
587 } |
|
588 return gptr - glyphs; |
|
589 } |
|
590 |
|
591 bool SkPaint::containsText(const void* textData, size_t byteLength) const { |
|
592 if (0 == byteLength) { |
|
593 return true; |
|
594 } |
|
595 |
|
596 SkASSERT(textData != NULL); |
|
597 |
|
598 // handle this encoding before the setup for the glyphcache |
|
599 if (this->getTextEncoding() == kGlyphID_TextEncoding) { |
|
600 const uint16_t* glyphID = static_cast<const uint16_t*>(textData); |
|
601 size_t count = byteLength >> 1; |
|
602 for (size_t i = 0; i < count; i++) { |
|
603 if (0 == glyphID[i]) { |
|
604 return false; |
|
605 } |
|
606 } |
|
607 return true; |
|
608 } |
|
609 |
|
610 SkAutoGlyphCache autoCache(*this, NULL, NULL); |
|
611 SkGlyphCache* cache = autoCache.getCache(); |
|
612 |
|
613 switch (this->getTextEncoding()) { |
|
614 case SkPaint::kUTF8_TextEncoding: { |
|
615 const char* text = static_cast<const char*>(textData); |
|
616 const char* stop = text + byteLength; |
|
617 while (text < stop) { |
|
618 if (0 == cache->unicharToGlyph(SkUTF8_NextUnichar(&text))) { |
|
619 return false; |
|
620 } |
|
621 } |
|
622 break; |
|
623 } |
|
624 case SkPaint::kUTF16_TextEncoding: { |
|
625 const uint16_t* text = static_cast<const uint16_t*>(textData); |
|
626 const uint16_t* stop = text + (byteLength >> 1); |
|
627 while (text < stop) { |
|
628 if (0 == cache->unicharToGlyph(SkUTF16_NextUnichar(&text))) { |
|
629 return false; |
|
630 } |
|
631 } |
|
632 break; |
|
633 } |
|
634 case SkPaint::kUTF32_TextEncoding: { |
|
635 const int32_t* text = static_cast<const int32_t*>(textData); |
|
636 const int32_t* stop = text + (byteLength >> 2); |
|
637 while (text < stop) { |
|
638 if (0 == cache->unicharToGlyph(*text++)) { |
|
639 return false; |
|
640 } |
|
641 } |
|
642 break; |
|
643 } |
|
644 default: |
|
645 SkDEBUGFAIL("unknown text encoding"); |
|
646 return false; |
|
647 } |
|
648 return true; |
|
649 } |
|
650 |
|
651 void SkPaint::glyphsToUnichars(const uint16_t glyphs[], int count, |
|
652 SkUnichar textData[]) const { |
|
653 if (count <= 0) { |
|
654 return; |
|
655 } |
|
656 |
|
657 SkASSERT(glyphs != NULL); |
|
658 SkASSERT(textData != NULL); |
|
659 |
|
660 SkAutoGlyphCache autoCache(*this, NULL, NULL); |
|
661 SkGlyphCache* cache = autoCache.getCache(); |
|
662 |
|
663 for (int index = 0; index < count; index++) { |
|
664 textData[index] = cache->glyphToUnichar(glyphs[index]); |
|
665 } |
|
666 } |
|
667 |
|
668 /////////////////////////////////////////////////////////////////////////////// |
|
669 |
|
670 static const SkGlyph& sk_getMetrics_utf8_next(SkGlyphCache* cache, |
|
671 const char** text) { |
|
672 SkASSERT(cache != NULL); |
|
673 SkASSERT(text != NULL); |
|
674 |
|
675 return cache->getUnicharMetrics(SkUTF8_NextUnichar(text)); |
|
676 } |
|
677 |
|
678 static const SkGlyph& sk_getMetrics_utf8_prev(SkGlyphCache* cache, |
|
679 const char** text) { |
|
680 SkASSERT(cache != NULL); |
|
681 SkASSERT(text != NULL); |
|
682 |
|
683 return cache->getUnicharMetrics(SkUTF8_PrevUnichar(text)); |
|
684 } |
|
685 |
|
686 static const SkGlyph& sk_getMetrics_utf16_next(SkGlyphCache* cache, |
|
687 const char** text) { |
|
688 SkASSERT(cache != NULL); |
|
689 SkASSERT(text != NULL); |
|
690 |
|
691 return cache->getUnicharMetrics(SkUTF16_NextUnichar((const uint16_t**)text)); |
|
692 } |
|
693 |
|
694 static const SkGlyph& sk_getMetrics_utf16_prev(SkGlyphCache* cache, |
|
695 const char** text) { |
|
696 SkASSERT(cache != NULL); |
|
697 SkASSERT(text != NULL); |
|
698 |
|
699 return cache->getUnicharMetrics(SkUTF16_PrevUnichar((const uint16_t**)text)); |
|
700 } |
|
701 |
|
702 static const SkGlyph& sk_getMetrics_utf32_next(SkGlyphCache* cache, |
|
703 const char** text) { |
|
704 SkASSERT(cache != NULL); |
|
705 SkASSERT(text != NULL); |
|
706 |
|
707 const int32_t* ptr = *(const int32_t**)text; |
|
708 SkUnichar uni = *ptr++; |
|
709 *text = (const char*)ptr; |
|
710 return cache->getUnicharMetrics(uni); |
|
711 } |
|
712 |
|
713 static const SkGlyph& sk_getMetrics_utf32_prev(SkGlyphCache* cache, |
|
714 const char** text) { |
|
715 SkASSERT(cache != NULL); |
|
716 SkASSERT(text != NULL); |
|
717 |
|
718 const int32_t* ptr = *(const int32_t**)text; |
|
719 SkUnichar uni = *--ptr; |
|
720 *text = (const char*)ptr; |
|
721 return cache->getUnicharMetrics(uni); |
|
722 } |
|
723 |
|
724 static const SkGlyph& sk_getMetrics_glyph_next(SkGlyphCache* cache, |
|
725 const char** text) { |
|
726 SkASSERT(cache != NULL); |
|
727 SkASSERT(text != NULL); |
|
728 |
|
729 const uint16_t* ptr = *(const uint16_t**)text; |
|
730 unsigned glyphID = *ptr; |
|
731 ptr += 1; |
|
732 *text = (const char*)ptr; |
|
733 return cache->getGlyphIDMetrics(glyphID); |
|
734 } |
|
735 |
|
736 static const SkGlyph& sk_getMetrics_glyph_prev(SkGlyphCache* cache, |
|
737 const char** text) { |
|
738 SkASSERT(cache != NULL); |
|
739 SkASSERT(text != NULL); |
|
740 |
|
741 const uint16_t* ptr = *(const uint16_t**)text; |
|
742 ptr -= 1; |
|
743 unsigned glyphID = *ptr; |
|
744 *text = (const char*)ptr; |
|
745 return cache->getGlyphIDMetrics(glyphID); |
|
746 } |
|
747 |
|
748 static const SkGlyph& sk_getAdvance_utf8_next(SkGlyphCache* cache, |
|
749 const char** text) { |
|
750 SkASSERT(cache != NULL); |
|
751 SkASSERT(text != NULL); |
|
752 |
|
753 return cache->getUnicharAdvance(SkUTF8_NextUnichar(text)); |
|
754 } |
|
755 |
|
756 static const SkGlyph& sk_getAdvance_utf8_prev(SkGlyphCache* cache, |
|
757 const char** text) { |
|
758 SkASSERT(cache != NULL); |
|
759 SkASSERT(text != NULL); |
|
760 |
|
761 return cache->getUnicharAdvance(SkUTF8_PrevUnichar(text)); |
|
762 } |
|
763 |
|
764 static const SkGlyph& sk_getAdvance_utf16_next(SkGlyphCache* cache, |
|
765 const char** text) { |
|
766 SkASSERT(cache != NULL); |
|
767 SkASSERT(text != NULL); |
|
768 |
|
769 return cache->getUnicharAdvance(SkUTF16_NextUnichar((const uint16_t**)text)); |
|
770 } |
|
771 |
|
772 static const SkGlyph& sk_getAdvance_utf16_prev(SkGlyphCache* cache, |
|
773 const char** text) { |
|
774 SkASSERT(cache != NULL); |
|
775 SkASSERT(text != NULL); |
|
776 |
|
777 return cache->getUnicharAdvance(SkUTF16_PrevUnichar((const uint16_t**)text)); |
|
778 } |
|
779 |
|
780 static const SkGlyph& sk_getAdvance_utf32_next(SkGlyphCache* cache, |
|
781 const char** text) { |
|
782 SkASSERT(cache != NULL); |
|
783 SkASSERT(text != NULL); |
|
784 |
|
785 const int32_t* ptr = *(const int32_t**)text; |
|
786 SkUnichar uni = *ptr++; |
|
787 *text = (const char*)ptr; |
|
788 return cache->getUnicharAdvance(uni); |
|
789 } |
|
790 |
|
791 static const SkGlyph& sk_getAdvance_utf32_prev(SkGlyphCache* cache, |
|
792 const char** text) { |
|
793 SkASSERT(cache != NULL); |
|
794 SkASSERT(text != NULL); |
|
795 |
|
796 const int32_t* ptr = *(const int32_t**)text; |
|
797 SkUnichar uni = *--ptr; |
|
798 *text = (const char*)ptr; |
|
799 return cache->getUnicharAdvance(uni); |
|
800 } |
|
801 |
|
802 static const SkGlyph& sk_getAdvance_glyph_next(SkGlyphCache* cache, |
|
803 const char** text) { |
|
804 SkASSERT(cache != NULL); |
|
805 SkASSERT(text != NULL); |
|
806 |
|
807 const uint16_t* ptr = *(const uint16_t**)text; |
|
808 unsigned glyphID = *ptr; |
|
809 ptr += 1; |
|
810 *text = (const char*)ptr; |
|
811 return cache->getGlyphIDAdvance(glyphID); |
|
812 } |
|
813 |
|
814 static const SkGlyph& sk_getAdvance_glyph_prev(SkGlyphCache* cache, |
|
815 const char** text) { |
|
816 SkASSERT(cache != NULL); |
|
817 SkASSERT(text != NULL); |
|
818 |
|
819 const uint16_t* ptr = *(const uint16_t**)text; |
|
820 ptr -= 1; |
|
821 unsigned glyphID = *ptr; |
|
822 *text = (const char*)ptr; |
|
823 return cache->getGlyphIDAdvance(glyphID); |
|
824 } |
|
825 |
|
826 SkMeasureCacheProc SkPaint::getMeasureCacheProc(TextBufferDirection tbd, |
|
827 bool needFullMetrics) const { |
|
828 static const SkMeasureCacheProc gMeasureCacheProcs[] = { |
|
829 sk_getMetrics_utf8_next, |
|
830 sk_getMetrics_utf16_next, |
|
831 sk_getMetrics_utf32_next, |
|
832 sk_getMetrics_glyph_next, |
|
833 |
|
834 sk_getMetrics_utf8_prev, |
|
835 sk_getMetrics_utf16_prev, |
|
836 sk_getMetrics_utf32_prev, |
|
837 sk_getMetrics_glyph_prev, |
|
838 |
|
839 sk_getAdvance_utf8_next, |
|
840 sk_getAdvance_utf16_next, |
|
841 sk_getAdvance_utf32_next, |
|
842 sk_getAdvance_glyph_next, |
|
843 |
|
844 sk_getAdvance_utf8_prev, |
|
845 sk_getAdvance_utf16_prev, |
|
846 sk_getAdvance_utf32_prev, |
|
847 sk_getAdvance_glyph_prev |
|
848 }; |
|
849 |
|
850 unsigned index = this->getTextEncoding(); |
|
851 |
|
852 if (kBackward_TextBufferDirection == tbd) { |
|
853 index += 4; |
|
854 } |
|
855 if (!needFullMetrics && !this->isDevKernText()) { |
|
856 index += 8; |
|
857 } |
|
858 |
|
859 SkASSERT(index < SK_ARRAY_COUNT(gMeasureCacheProcs)); |
|
860 return gMeasureCacheProcs[index]; |
|
861 } |
|
862 |
|
863 /////////////////////////////////////////////////////////////////////////////// |
|
864 |
|
865 static const SkGlyph& sk_getMetrics_utf8_00(SkGlyphCache* cache, |
|
866 const char** text, SkFixed, SkFixed) { |
|
867 SkASSERT(cache != NULL); |
|
868 SkASSERT(text != NULL); |
|
869 |
|
870 return cache->getUnicharMetrics(SkUTF8_NextUnichar(text)); |
|
871 } |
|
872 |
|
873 static const SkGlyph& sk_getMetrics_utf8_xy(SkGlyphCache* cache, |
|
874 const char** text, SkFixed x, SkFixed y) { |
|
875 SkASSERT(cache != NULL); |
|
876 SkASSERT(text != NULL); |
|
877 |
|
878 return cache->getUnicharMetrics(SkUTF8_NextUnichar(text), x, y); |
|
879 } |
|
880 |
|
881 static const SkGlyph& sk_getMetrics_utf16_00(SkGlyphCache* cache, |
|
882 const char** text, SkFixed, SkFixed) { |
|
883 SkASSERT(cache != NULL); |
|
884 SkASSERT(text != NULL); |
|
885 |
|
886 return cache->getUnicharMetrics(SkUTF16_NextUnichar((const uint16_t**)text)); |
|
887 } |
|
888 |
|
889 static const SkGlyph& sk_getMetrics_utf16_xy(SkGlyphCache* cache, |
|
890 const char** text, SkFixed x, SkFixed y) { |
|
891 SkASSERT(cache != NULL); |
|
892 SkASSERT(text != NULL); |
|
893 |
|
894 return cache->getUnicharMetrics(SkUTF16_NextUnichar((const uint16_t**)text), |
|
895 x, y); |
|
896 } |
|
897 |
|
898 static const SkGlyph& sk_getMetrics_utf32_00(SkGlyphCache* cache, |
|
899 const char** text, SkFixed, SkFixed) { |
|
900 SkASSERT(cache != NULL); |
|
901 SkASSERT(text != NULL); |
|
902 |
|
903 const int32_t* ptr = *(const int32_t**)text; |
|
904 SkUnichar uni = *ptr++; |
|
905 *text = (const char*)ptr; |
|
906 return cache->getUnicharMetrics(uni); |
|
907 } |
|
908 |
|
909 static const SkGlyph& sk_getMetrics_utf32_xy(SkGlyphCache* cache, |
|
910 const char** text, SkFixed x, SkFixed y) { |
|
911 SkASSERT(cache != NULL); |
|
912 SkASSERT(text != NULL); |
|
913 |
|
914 const int32_t* ptr = *(const int32_t**)text; |
|
915 SkUnichar uni = *--ptr; |
|
916 *text = (const char*)ptr; |
|
917 return cache->getUnicharMetrics(uni, x, y); |
|
918 } |
|
919 |
|
920 static const SkGlyph& sk_getMetrics_glyph_00(SkGlyphCache* cache, |
|
921 const char** text, SkFixed, SkFixed) { |
|
922 SkASSERT(cache != NULL); |
|
923 SkASSERT(text != NULL); |
|
924 |
|
925 const uint16_t* ptr = *(const uint16_t**)text; |
|
926 unsigned glyphID = *ptr; |
|
927 ptr += 1; |
|
928 *text = (const char*)ptr; |
|
929 return cache->getGlyphIDMetrics(glyphID); |
|
930 } |
|
931 |
|
932 static const SkGlyph& sk_getMetrics_glyph_xy(SkGlyphCache* cache, |
|
933 const char** text, SkFixed x, SkFixed y) { |
|
934 SkASSERT(cache != NULL); |
|
935 SkASSERT(text != NULL); |
|
936 |
|
937 const uint16_t* ptr = *(const uint16_t**)text; |
|
938 unsigned glyphID = *ptr; |
|
939 ptr += 1; |
|
940 *text = (const char*)ptr; |
|
941 return cache->getGlyphIDMetrics(glyphID, x, y); |
|
942 } |
|
943 |
|
944 SkDrawCacheProc SkPaint::getDrawCacheProc() const { |
|
945 static const SkDrawCacheProc gDrawCacheProcs[] = { |
|
946 sk_getMetrics_utf8_00, |
|
947 sk_getMetrics_utf16_00, |
|
948 sk_getMetrics_utf32_00, |
|
949 sk_getMetrics_glyph_00, |
|
950 |
|
951 sk_getMetrics_utf8_xy, |
|
952 sk_getMetrics_utf16_xy, |
|
953 sk_getMetrics_utf32_xy, |
|
954 sk_getMetrics_glyph_xy |
|
955 }; |
|
956 |
|
957 unsigned index = this->getTextEncoding(); |
|
958 if (fFlags & kSubpixelText_Flag) { |
|
959 index += 4; |
|
960 } |
|
961 |
|
962 SkASSERT(index < SK_ARRAY_COUNT(gDrawCacheProcs)); |
|
963 return gDrawCacheProcs[index]; |
|
964 } |
|
965 |
|
966 /////////////////////////////////////////////////////////////////////////////// |
|
967 |
|
968 #define TEXT_AS_PATHS_PAINT_FLAGS_TO_IGNORE ( \ |
|
969 SkPaint::kDevKernText_Flag | \ |
|
970 SkPaint::kLinearText_Flag | \ |
|
971 SkPaint::kLCDRenderText_Flag | \ |
|
972 SkPaint::kEmbeddedBitmapText_Flag | \ |
|
973 SkPaint::kAutoHinting_Flag | \ |
|
974 SkPaint::kGenA8FromLCD_Flag ) |
|
975 |
|
976 SkScalar SkPaint::setupForAsPaths() { |
|
977 uint32_t flags = this->getFlags(); |
|
978 // clear the flags we don't care about |
|
979 flags &= ~TEXT_AS_PATHS_PAINT_FLAGS_TO_IGNORE; |
|
980 // set the flags we do care about |
|
981 flags |= SkPaint::kSubpixelText_Flag; |
|
982 |
|
983 this->setFlags(flags); |
|
984 this->setHinting(SkPaint::kNo_Hinting); |
|
985 |
|
986 SkScalar textSize = fTextSize; |
|
987 this->setTextSize(kCanonicalTextSizeForPaths); |
|
988 return textSize / kCanonicalTextSizeForPaths; |
|
989 } |
|
990 |
|
991 class SkCanonicalizePaint { |
|
992 public: |
|
993 SkCanonicalizePaint(const SkPaint& paint) : fPaint(&paint), fScale(0) { |
|
994 if (paint.isLinearText() || paint.tooBigToUseCache()) { |
|
995 SkPaint* p = fLazy.set(paint); |
|
996 fScale = p->setupForAsPaths(); |
|
997 fPaint = p; |
|
998 } |
|
999 } |
|
1000 |
|
1001 const SkPaint& getPaint() const { return *fPaint; } |
|
1002 |
|
1003 /** |
|
1004 * Returns 0 if the paint was unmodified, or the scale factor need to |
|
1005 * the original textSize |
|
1006 */ |
|
1007 SkScalar getScale() const { return fScale; } |
|
1008 |
|
1009 private: |
|
1010 const SkPaint* fPaint; |
|
1011 SkScalar fScale; |
|
1012 SkTLazy<SkPaint> fLazy; |
|
1013 }; |
|
1014 |
|
1015 static void set_bounds(const SkGlyph& g, SkRect* bounds) { |
|
1016 bounds->set(SkIntToScalar(g.fLeft), |
|
1017 SkIntToScalar(g.fTop), |
|
1018 SkIntToScalar(g.fLeft + g.fWidth), |
|
1019 SkIntToScalar(g.fTop + g.fHeight)); |
|
1020 } |
|
1021 |
|
1022 // 64bits wide, with a 16bit bias. Useful when accumulating lots of 16.16 so |
|
1023 // we don't overflow along the way |
|
1024 typedef int64_t Sk48Dot16; |
|
1025 |
|
1026 static inline float Sk48Dot16ToScalar(Sk48Dot16 x) { |
|
1027 return (float) (x * 1.5258789e-5); // x * (1 / 65536.0f) |
|
1028 } |
|
1029 |
|
1030 static void join_bounds_x(const SkGlyph& g, SkRect* bounds, Sk48Dot16 dx) { |
|
1031 SkScalar sx = Sk48Dot16ToScalar(dx); |
|
1032 bounds->join(SkIntToScalar(g.fLeft) + sx, |
|
1033 SkIntToScalar(g.fTop), |
|
1034 SkIntToScalar(g.fLeft + g.fWidth) + sx, |
|
1035 SkIntToScalar(g.fTop + g.fHeight)); |
|
1036 } |
|
1037 |
|
1038 static void join_bounds_y(const SkGlyph& g, SkRect* bounds, Sk48Dot16 dy) { |
|
1039 SkScalar sy = Sk48Dot16ToScalar(dy); |
|
1040 bounds->join(SkIntToScalar(g.fLeft), |
|
1041 SkIntToScalar(g.fTop) + sy, |
|
1042 SkIntToScalar(g.fLeft + g.fWidth), |
|
1043 SkIntToScalar(g.fTop + g.fHeight) + sy); |
|
1044 } |
|
1045 |
|
1046 typedef void (*JoinBoundsProc)(const SkGlyph&, SkRect*, Sk48Dot16); |
|
1047 |
|
1048 // xyIndex is 0 for fAdvanceX or 1 for fAdvanceY |
|
1049 static SkFixed advance(const SkGlyph& glyph, int xyIndex) { |
|
1050 SkASSERT(0 == xyIndex || 1 == xyIndex); |
|
1051 return (&glyph.fAdvanceX)[xyIndex]; |
|
1052 } |
|
1053 |
|
1054 SkScalar SkPaint::measure_text(SkGlyphCache* cache, |
|
1055 const char* text, size_t byteLength, |
|
1056 int* count, SkRect* bounds) const { |
|
1057 SkASSERT(count); |
|
1058 if (byteLength == 0) { |
|
1059 *count = 0; |
|
1060 if (bounds) { |
|
1061 bounds->setEmpty(); |
|
1062 } |
|
1063 return 0; |
|
1064 } |
|
1065 |
|
1066 SkMeasureCacheProc glyphCacheProc; |
|
1067 glyphCacheProc = this->getMeasureCacheProc(kForward_TextBufferDirection, |
|
1068 NULL != bounds); |
|
1069 |
|
1070 int xyIndex; |
|
1071 JoinBoundsProc joinBoundsProc; |
|
1072 if (this->isVerticalText()) { |
|
1073 xyIndex = 1; |
|
1074 joinBoundsProc = join_bounds_y; |
|
1075 } else { |
|
1076 xyIndex = 0; |
|
1077 joinBoundsProc = join_bounds_x; |
|
1078 } |
|
1079 |
|
1080 int n = 1; |
|
1081 const char* stop = (const char*)text + byteLength; |
|
1082 const SkGlyph* g = &glyphCacheProc(cache, &text); |
|
1083 // our accumulated fixed-point advances might overflow 16.16, so we use |
|
1084 // a 48.16 (64bit) accumulator, and then convert that to scalar at the |
|
1085 // very end. |
|
1086 Sk48Dot16 x = advance(*g, xyIndex); |
|
1087 |
|
1088 SkAutoKern autokern; |
|
1089 |
|
1090 if (NULL == bounds) { |
|
1091 if (this->isDevKernText()) { |
|
1092 int rsb; |
|
1093 for (; text < stop; n++) { |
|
1094 rsb = g->fRsbDelta; |
|
1095 g = &glyphCacheProc(cache, &text); |
|
1096 x += SkAutoKern_AdjustF(rsb, g->fLsbDelta) + advance(*g, xyIndex); |
|
1097 } |
|
1098 } else { |
|
1099 for (; text < stop; n++) { |
|
1100 x += advance(glyphCacheProc(cache, &text), xyIndex); |
|
1101 } |
|
1102 } |
|
1103 } else { |
|
1104 set_bounds(*g, bounds); |
|
1105 if (this->isDevKernText()) { |
|
1106 int rsb; |
|
1107 for (; text < stop; n++) { |
|
1108 rsb = g->fRsbDelta; |
|
1109 g = &glyphCacheProc(cache, &text); |
|
1110 x += SkAutoKern_AdjustF(rsb, g->fLsbDelta); |
|
1111 joinBoundsProc(*g, bounds, x); |
|
1112 x += advance(*g, xyIndex); |
|
1113 } |
|
1114 } else { |
|
1115 for (; text < stop; n++) { |
|
1116 g = &glyphCacheProc(cache, &text); |
|
1117 joinBoundsProc(*g, bounds, x); |
|
1118 x += advance(*g, xyIndex); |
|
1119 } |
|
1120 } |
|
1121 } |
|
1122 SkASSERT(text == stop); |
|
1123 |
|
1124 *count = n; |
|
1125 return Sk48Dot16ToScalar(x); |
|
1126 } |
|
1127 |
|
1128 SkScalar SkPaint::measureText(const void* textData, size_t length, |
|
1129 SkRect* bounds, SkScalar zoom) const { |
|
1130 const char* text = (const char*)textData; |
|
1131 SkASSERT(text != NULL || length == 0); |
|
1132 |
|
1133 SkCanonicalizePaint canon(*this); |
|
1134 const SkPaint& paint = canon.getPaint(); |
|
1135 SkScalar scale = canon.getScale(); |
|
1136 |
|
1137 SkMatrix zoomMatrix, *zoomPtr = NULL; |
|
1138 if (zoom) { |
|
1139 zoomMatrix.setScale(zoom, zoom); |
|
1140 zoomPtr = &zoomMatrix; |
|
1141 } |
|
1142 |
|
1143 SkAutoGlyphCache autoCache(paint, NULL, zoomPtr); |
|
1144 SkGlyphCache* cache = autoCache.getCache(); |
|
1145 |
|
1146 SkScalar width = 0; |
|
1147 |
|
1148 if (length > 0) { |
|
1149 int tempCount; |
|
1150 |
|
1151 width = paint.measure_text(cache, text, length, &tempCount, bounds); |
|
1152 if (scale) { |
|
1153 width = SkScalarMul(width, scale); |
|
1154 if (bounds) { |
|
1155 bounds->fLeft = SkScalarMul(bounds->fLeft, scale); |
|
1156 bounds->fTop = SkScalarMul(bounds->fTop, scale); |
|
1157 bounds->fRight = SkScalarMul(bounds->fRight, scale); |
|
1158 bounds->fBottom = SkScalarMul(bounds->fBottom, scale); |
|
1159 } |
|
1160 } |
|
1161 } else if (bounds) { |
|
1162 // ensure that even if we don't measure_text we still update the bounds |
|
1163 bounds->setEmpty(); |
|
1164 } |
|
1165 return width; |
|
1166 } |
|
1167 |
|
1168 typedef bool (*SkTextBufferPred)(const char* text, const char* stop); |
|
1169 |
|
1170 static bool forward_textBufferPred(const char* text, const char* stop) { |
|
1171 return text < stop; |
|
1172 } |
|
1173 |
|
1174 static bool backward_textBufferPred(const char* text, const char* stop) { |
|
1175 return text > stop; |
|
1176 } |
|
1177 |
|
1178 static SkTextBufferPred chooseTextBufferPred(SkPaint::TextBufferDirection tbd, |
|
1179 const char** text, size_t length, |
|
1180 const char** stop) { |
|
1181 if (SkPaint::kForward_TextBufferDirection == tbd) { |
|
1182 *stop = *text + length; |
|
1183 return forward_textBufferPred; |
|
1184 } else { |
|
1185 // text should point to the end of the buffer, and stop to the beginning |
|
1186 *stop = *text; |
|
1187 *text += length; |
|
1188 return backward_textBufferPred; |
|
1189 } |
|
1190 } |
|
1191 |
|
1192 size_t SkPaint::breakText(const void* textD, size_t length, SkScalar maxWidth, |
|
1193 SkScalar* measuredWidth, |
|
1194 TextBufferDirection tbd) const { |
|
1195 if (0 == length || 0 >= maxWidth) { |
|
1196 if (measuredWidth) { |
|
1197 *measuredWidth = 0; |
|
1198 } |
|
1199 return 0; |
|
1200 } |
|
1201 |
|
1202 if (0 == fTextSize) { |
|
1203 if (measuredWidth) { |
|
1204 *measuredWidth = 0; |
|
1205 } |
|
1206 return length; |
|
1207 } |
|
1208 |
|
1209 SkASSERT(textD != NULL); |
|
1210 const char* text = (const char*)textD; |
|
1211 |
|
1212 SkCanonicalizePaint canon(*this); |
|
1213 const SkPaint& paint = canon.getPaint(); |
|
1214 SkScalar scale = canon.getScale(); |
|
1215 |
|
1216 // adjust max in case we changed the textSize in paint |
|
1217 if (scale) { |
|
1218 maxWidth /= scale; |
|
1219 } |
|
1220 |
|
1221 SkAutoGlyphCache autoCache(paint, NULL, NULL); |
|
1222 SkGlyphCache* cache = autoCache.getCache(); |
|
1223 |
|
1224 SkMeasureCacheProc glyphCacheProc = paint.getMeasureCacheProc(tbd, false); |
|
1225 const char* stop; |
|
1226 SkTextBufferPred pred = chooseTextBufferPred(tbd, &text, length, &stop); |
|
1227 const int xyIndex = paint.isVerticalText() ? 1 : 0; |
|
1228 // use 64bits for our accumulator, to avoid overflowing 16.16 |
|
1229 Sk48Dot16 max = SkScalarToFixed(maxWidth); |
|
1230 Sk48Dot16 width = 0; |
|
1231 |
|
1232 SkAutoKern autokern; |
|
1233 |
|
1234 if (this->isDevKernText()) { |
|
1235 int rsb = 0; |
|
1236 while (pred(text, stop)) { |
|
1237 const char* curr = text; |
|
1238 const SkGlyph& g = glyphCacheProc(cache, &text); |
|
1239 SkFixed x = SkAutoKern_AdjustF(rsb, g.fLsbDelta) + advance(g, xyIndex); |
|
1240 if ((width += x) > max) { |
|
1241 width -= x; |
|
1242 text = curr; |
|
1243 break; |
|
1244 } |
|
1245 rsb = g.fRsbDelta; |
|
1246 } |
|
1247 } else { |
|
1248 while (pred(text, stop)) { |
|
1249 const char* curr = text; |
|
1250 SkFixed x = advance(glyphCacheProc(cache, &text), xyIndex); |
|
1251 if ((width += x) > max) { |
|
1252 width -= x; |
|
1253 text = curr; |
|
1254 break; |
|
1255 } |
|
1256 } |
|
1257 } |
|
1258 |
|
1259 if (measuredWidth) { |
|
1260 SkScalar scalarWidth = Sk48Dot16ToScalar(width); |
|
1261 if (scale) { |
|
1262 scalarWidth = SkScalarMul(scalarWidth, scale); |
|
1263 } |
|
1264 *measuredWidth = scalarWidth; |
|
1265 } |
|
1266 |
|
1267 // return the number of bytes measured |
|
1268 return (kForward_TextBufferDirection == tbd) ? |
|
1269 text - stop + length : stop - text + length; |
|
1270 } |
|
1271 |
|
1272 /////////////////////////////////////////////////////////////////////////////// |
|
1273 |
|
1274 static bool FontMetricsCacheProc(const SkGlyphCache* cache, void* context) { |
|
1275 *(SkPaint::FontMetrics*)context = cache->getFontMetrics(); |
|
1276 return false; // don't detach the cache |
|
1277 } |
|
1278 |
|
1279 static void FontMetricsDescProc(SkTypeface* typeface, const SkDescriptor* desc, |
|
1280 void* context) { |
|
1281 SkGlyphCache::VisitCache(typeface, desc, FontMetricsCacheProc, context); |
|
1282 } |
|
1283 |
|
1284 SkScalar SkPaint::getFontMetrics(FontMetrics* metrics, SkScalar zoom) const { |
|
1285 SkCanonicalizePaint canon(*this); |
|
1286 const SkPaint& paint = canon.getPaint(); |
|
1287 SkScalar scale = canon.getScale(); |
|
1288 |
|
1289 SkMatrix zoomMatrix, *zoomPtr = NULL; |
|
1290 if (zoom) { |
|
1291 zoomMatrix.setScale(zoom, zoom); |
|
1292 zoomPtr = &zoomMatrix; |
|
1293 } |
|
1294 |
|
1295 FontMetrics storage; |
|
1296 if (NULL == metrics) { |
|
1297 metrics = &storage; |
|
1298 } |
|
1299 |
|
1300 paint.descriptorProc(NULL, zoomPtr, FontMetricsDescProc, metrics, true); |
|
1301 |
|
1302 if (scale) { |
|
1303 metrics->fTop = SkScalarMul(metrics->fTop, scale); |
|
1304 metrics->fAscent = SkScalarMul(metrics->fAscent, scale); |
|
1305 metrics->fDescent = SkScalarMul(metrics->fDescent, scale); |
|
1306 metrics->fBottom = SkScalarMul(metrics->fBottom, scale); |
|
1307 metrics->fLeading = SkScalarMul(metrics->fLeading, scale); |
|
1308 metrics->fAvgCharWidth = SkScalarMul(metrics->fAvgCharWidth, scale); |
|
1309 metrics->fXMin = SkScalarMul(metrics->fXMin, scale); |
|
1310 metrics->fXMax = SkScalarMul(metrics->fXMax, scale); |
|
1311 metrics->fXHeight = SkScalarMul(metrics->fXHeight, scale); |
|
1312 metrics->fUnderlineThickness = SkScalarMul(metrics->fUnderlineThickness, scale); |
|
1313 metrics->fUnderlinePosition = SkScalarMul(metrics->fUnderlinePosition, scale); |
|
1314 } |
|
1315 return metrics->fDescent - metrics->fAscent + metrics->fLeading; |
|
1316 } |
|
1317 |
|
1318 /////////////////////////////////////////////////////////////////////////////// |
|
1319 |
|
1320 static void set_bounds(const SkGlyph& g, SkRect* bounds, SkScalar scale) { |
|
1321 bounds->set(g.fLeft * scale, |
|
1322 g.fTop * scale, |
|
1323 (g.fLeft + g.fWidth) * scale, |
|
1324 (g.fTop + g.fHeight) * scale); |
|
1325 } |
|
1326 |
|
1327 int SkPaint::getTextWidths(const void* textData, size_t byteLength, |
|
1328 SkScalar widths[], SkRect bounds[]) const { |
|
1329 if (0 == byteLength) { |
|
1330 return 0; |
|
1331 } |
|
1332 |
|
1333 SkASSERT(NULL != textData); |
|
1334 |
|
1335 if (NULL == widths && NULL == bounds) { |
|
1336 return this->countText(textData, byteLength); |
|
1337 } |
|
1338 |
|
1339 SkCanonicalizePaint canon(*this); |
|
1340 const SkPaint& paint = canon.getPaint(); |
|
1341 SkScalar scale = canon.getScale(); |
|
1342 |
|
1343 SkAutoGlyphCache autoCache(paint, NULL, NULL); |
|
1344 SkGlyphCache* cache = autoCache.getCache(); |
|
1345 SkMeasureCacheProc glyphCacheProc; |
|
1346 glyphCacheProc = paint.getMeasureCacheProc(kForward_TextBufferDirection, |
|
1347 NULL != bounds); |
|
1348 |
|
1349 const char* text = (const char*)textData; |
|
1350 const char* stop = text + byteLength; |
|
1351 int count = 0; |
|
1352 const int xyIndex = paint.isVerticalText() ? 1 : 0; |
|
1353 |
|
1354 if (this->isDevKernText()) { |
|
1355 // we adjust the widths returned here through auto-kerning |
|
1356 SkAutoKern autokern; |
|
1357 SkFixed prevWidth = 0; |
|
1358 |
|
1359 if (scale) { |
|
1360 while (text < stop) { |
|
1361 const SkGlyph& g = glyphCacheProc(cache, &text); |
|
1362 if (widths) { |
|
1363 SkFixed adjust = autokern.adjust(g); |
|
1364 |
|
1365 if (count > 0) { |
|
1366 SkScalar w = SkFixedToScalar(prevWidth + adjust); |
|
1367 *widths++ = SkScalarMul(w, scale); |
|
1368 } |
|
1369 prevWidth = advance(g, xyIndex); |
|
1370 } |
|
1371 if (bounds) { |
|
1372 set_bounds(g, bounds++, scale); |
|
1373 } |
|
1374 ++count; |
|
1375 } |
|
1376 if (count > 0 && widths) { |
|
1377 *widths = SkScalarMul(SkFixedToScalar(prevWidth), scale); |
|
1378 } |
|
1379 } else { |
|
1380 while (text < stop) { |
|
1381 const SkGlyph& g = glyphCacheProc(cache, &text); |
|
1382 if (widths) { |
|
1383 SkFixed adjust = autokern.adjust(g); |
|
1384 |
|
1385 if (count > 0) { |
|
1386 *widths++ = SkFixedToScalar(prevWidth + adjust); |
|
1387 } |
|
1388 prevWidth = advance(g, xyIndex); |
|
1389 } |
|
1390 if (bounds) { |
|
1391 set_bounds(g, bounds++); |
|
1392 } |
|
1393 ++count; |
|
1394 } |
|
1395 if (count > 0 && widths) { |
|
1396 *widths = SkFixedToScalar(prevWidth); |
|
1397 } |
|
1398 } |
|
1399 } else { // no devkern |
|
1400 if (scale) { |
|
1401 while (text < stop) { |
|
1402 const SkGlyph& g = glyphCacheProc(cache, &text); |
|
1403 if (widths) { |
|
1404 *widths++ = SkScalarMul(SkFixedToScalar(advance(g, xyIndex)), |
|
1405 scale); |
|
1406 } |
|
1407 if (bounds) { |
|
1408 set_bounds(g, bounds++, scale); |
|
1409 } |
|
1410 ++count; |
|
1411 } |
|
1412 } else { |
|
1413 while (text < stop) { |
|
1414 const SkGlyph& g = glyphCacheProc(cache, &text); |
|
1415 if (widths) { |
|
1416 *widths++ = SkFixedToScalar(advance(g, xyIndex)); |
|
1417 } |
|
1418 if (bounds) { |
|
1419 set_bounds(g, bounds++); |
|
1420 } |
|
1421 ++count; |
|
1422 } |
|
1423 } |
|
1424 } |
|
1425 |
|
1426 SkASSERT(text == stop); |
|
1427 return count; |
|
1428 } |
|
1429 |
|
1430 /////////////////////////////////////////////////////////////////////////////// |
|
1431 |
|
1432 #include "SkDraw.h" |
|
1433 |
|
1434 void SkPaint::getTextPath(const void* textData, size_t length, |
|
1435 SkScalar x, SkScalar y, SkPath* path) const { |
|
1436 SkASSERT(length == 0 || textData != NULL); |
|
1437 |
|
1438 const char* text = (const char*)textData; |
|
1439 if (text == NULL || length == 0 || path == NULL) { |
|
1440 return; |
|
1441 } |
|
1442 |
|
1443 SkTextToPathIter iter(text, length, *this, false); |
|
1444 SkMatrix matrix; |
|
1445 SkScalar prevXPos = 0; |
|
1446 |
|
1447 matrix.setScale(iter.getPathScale(), iter.getPathScale()); |
|
1448 matrix.postTranslate(x, y); |
|
1449 path->reset(); |
|
1450 |
|
1451 SkScalar xpos; |
|
1452 const SkPath* iterPath; |
|
1453 while (iter.next(&iterPath, &xpos)) { |
|
1454 matrix.postTranslate(xpos - prevXPos, 0); |
|
1455 if (iterPath) { |
|
1456 path->addPath(*iterPath, matrix); |
|
1457 } |
|
1458 prevXPos = xpos; |
|
1459 } |
|
1460 } |
|
1461 |
|
1462 void SkPaint::getPosTextPath(const void* textData, size_t length, |
|
1463 const SkPoint pos[], SkPath* path) const { |
|
1464 SkASSERT(length == 0 || textData != NULL); |
|
1465 |
|
1466 const char* text = (const char*)textData; |
|
1467 if (text == NULL || length == 0 || path == NULL) { |
|
1468 return; |
|
1469 } |
|
1470 |
|
1471 SkTextToPathIter iter(text, length, *this, false); |
|
1472 SkMatrix matrix; |
|
1473 SkPoint prevPos; |
|
1474 prevPos.set(0, 0); |
|
1475 |
|
1476 matrix.setScale(iter.getPathScale(), iter.getPathScale()); |
|
1477 path->reset(); |
|
1478 |
|
1479 unsigned int i = 0; |
|
1480 const SkPath* iterPath; |
|
1481 while (iter.next(&iterPath, NULL)) { |
|
1482 matrix.postTranslate(pos[i].fX - prevPos.fX, pos[i].fY - prevPos.fY); |
|
1483 if (iterPath) { |
|
1484 path->addPath(*iterPath, matrix); |
|
1485 } |
|
1486 prevPos = pos[i]; |
|
1487 i++; |
|
1488 } |
|
1489 } |
|
1490 |
|
1491 static void add_flattenable(SkDescriptor* desc, uint32_t tag, |
|
1492 SkWriteBuffer* buffer) { |
|
1493 buffer->writeToMemory(desc->addEntry(tag, buffer->bytesWritten(), NULL)); |
|
1494 } |
|
1495 |
|
1496 // SkFontHost can override this choice in FilterRec() |
|
1497 static SkMask::Format computeMaskFormat(const SkPaint& paint) { |
|
1498 uint32_t flags = paint.getFlags(); |
|
1499 |
|
1500 // Antialiasing being disabled trumps all other settings. |
|
1501 if (!(flags & SkPaint::kAntiAlias_Flag)) { |
|
1502 return SkMask::kBW_Format; |
|
1503 } |
|
1504 |
|
1505 if (flags & SkPaint::kLCDRenderText_Flag) { |
|
1506 return SkMask::kLCD16_Format; |
|
1507 } |
|
1508 |
|
1509 return SkMask::kA8_Format; |
|
1510 } |
|
1511 |
|
1512 // if linear-text is on, then we force hinting to be off (since that's sort of |
|
1513 // the point of linear-text. |
|
1514 static SkPaint::Hinting computeHinting(const SkPaint& paint) { |
|
1515 SkPaint::Hinting h = paint.getHinting(); |
|
1516 if (paint.isLinearText()) { |
|
1517 h = SkPaint::kNo_Hinting; |
|
1518 } |
|
1519 return h; |
|
1520 } |
|
1521 |
|
1522 // return true if the paint is just a single color (i.e. not a shader). If its |
|
1523 // a shader, then we can't compute a const luminance for it :( |
|
1524 static bool justAColor(const SkPaint& paint, SkColor* color) { |
|
1525 if (paint.getShader()) { |
|
1526 return false; |
|
1527 } |
|
1528 SkColor c = paint.getColor(); |
|
1529 if (paint.getColorFilter()) { |
|
1530 c = paint.getColorFilter()->filterColor(c); |
|
1531 } |
|
1532 if (color) { |
|
1533 *color = c; |
|
1534 } |
|
1535 return true; |
|
1536 } |
|
1537 |
|
1538 static SkColor computeLuminanceColor(const SkPaint& paint) { |
|
1539 SkColor c; |
|
1540 if (!justAColor(paint, &c)) { |
|
1541 c = SkColorSetRGB(0x7F, 0x80, 0x7F); |
|
1542 } |
|
1543 return c; |
|
1544 } |
|
1545 |
|
1546 #define assert_byte(x) SkASSERT(0 == ((x) >> 8)) |
|
1547 |
|
1548 // Beyond this size, LCD doesn't appreciably improve quality, but it always |
|
1549 // cost more RAM and draws slower, so we set a cap. |
|
1550 #ifndef SK_MAX_SIZE_FOR_LCDTEXT |
|
1551 #define SK_MAX_SIZE_FOR_LCDTEXT 48 |
|
1552 #endif |
|
1553 |
|
1554 static bool tooBigForLCD(const SkScalerContext::Rec& rec) { |
|
1555 SkScalar area = rec.fPost2x2[0][0] * rec.fPost2x2[1][1] - |
|
1556 rec.fPost2x2[1][0] * rec.fPost2x2[0][1]; |
|
1557 SkScalar size = SkScalarSqrt(SkScalarAbs(area)) * rec.fTextSize; |
|
1558 return size > SkIntToScalar(SK_MAX_SIZE_FOR_LCDTEXT); |
|
1559 } |
|
1560 |
|
1561 /* |
|
1562 * Return the scalar with only limited fractional precision. Used to consolidate matrices |
|
1563 * that vary only slightly when we create our key into the font cache, since the font scaler |
|
1564 * typically returns the same looking resuts for tiny changes in the matrix. |
|
1565 */ |
|
1566 static SkScalar sk_relax(SkScalar x) { |
|
1567 int n = sk_float_round2int(x * 1024); |
|
1568 return n / 1024.0f; |
|
1569 } |
|
1570 |
|
1571 void SkScalerContext::MakeRec(const SkPaint& paint, |
|
1572 const SkDeviceProperties* deviceProperties, |
|
1573 const SkMatrix* deviceMatrix, |
|
1574 Rec* rec) { |
|
1575 SkASSERT(deviceMatrix == NULL || !deviceMatrix->hasPerspective()); |
|
1576 |
|
1577 SkTypeface* typeface = paint.getTypeface(); |
|
1578 if (NULL == typeface) { |
|
1579 typeface = SkTypeface::GetDefaultTypeface(); |
|
1580 } |
|
1581 rec->fOrigFontID = typeface->uniqueID(); |
|
1582 rec->fFontID = rec->fOrigFontID; |
|
1583 rec->fTextSize = paint.getTextSize(); |
|
1584 rec->fPreScaleX = paint.getTextScaleX(); |
|
1585 rec->fPreSkewX = paint.getTextSkewX(); |
|
1586 |
|
1587 if (deviceMatrix) { |
|
1588 rec->fPost2x2[0][0] = sk_relax(deviceMatrix->getScaleX()); |
|
1589 rec->fPost2x2[0][1] = sk_relax(deviceMatrix->getSkewX()); |
|
1590 rec->fPost2x2[1][0] = sk_relax(deviceMatrix->getSkewY()); |
|
1591 rec->fPost2x2[1][1] = sk_relax(deviceMatrix->getScaleY()); |
|
1592 } else { |
|
1593 rec->fPost2x2[0][0] = rec->fPost2x2[1][1] = SK_Scalar1; |
|
1594 rec->fPost2x2[0][1] = rec->fPost2x2[1][0] = 0; |
|
1595 } |
|
1596 |
|
1597 SkPaint::Style style = paint.getStyle(); |
|
1598 SkScalar strokeWidth = paint.getStrokeWidth(); |
|
1599 |
|
1600 unsigned flags = 0; |
|
1601 |
|
1602 if (paint.isFakeBoldText()) { |
|
1603 #ifdef SK_USE_FREETYPE_EMBOLDEN |
|
1604 flags |= SkScalerContext::kEmbolden_Flag; |
|
1605 #else |
|
1606 SkScalar fakeBoldScale = SkScalarInterpFunc(paint.getTextSize(), |
|
1607 kStdFakeBoldInterpKeys, |
|
1608 kStdFakeBoldInterpValues, |
|
1609 kStdFakeBoldInterpLength); |
|
1610 SkScalar extra = SkScalarMul(paint.getTextSize(), fakeBoldScale); |
|
1611 |
|
1612 if (style == SkPaint::kFill_Style) { |
|
1613 style = SkPaint::kStrokeAndFill_Style; |
|
1614 strokeWidth = extra; // ignore paint's strokeWidth if it was "fill" |
|
1615 } else { |
|
1616 strokeWidth += extra; |
|
1617 } |
|
1618 #endif |
|
1619 } |
|
1620 |
|
1621 if (paint.isDevKernText()) { |
|
1622 flags |= SkScalerContext::kDevKernText_Flag; |
|
1623 } |
|
1624 |
|
1625 if (style != SkPaint::kFill_Style && strokeWidth > 0) { |
|
1626 rec->fFrameWidth = strokeWidth; |
|
1627 rec->fMiterLimit = paint.getStrokeMiter(); |
|
1628 rec->fStrokeJoin = SkToU8(paint.getStrokeJoin()); |
|
1629 |
|
1630 if (style == SkPaint::kStrokeAndFill_Style) { |
|
1631 flags |= SkScalerContext::kFrameAndFill_Flag; |
|
1632 } |
|
1633 } else { |
|
1634 rec->fFrameWidth = 0; |
|
1635 rec->fMiterLimit = 0; |
|
1636 rec->fStrokeJoin = 0; |
|
1637 } |
|
1638 |
|
1639 rec->fMaskFormat = SkToU8(computeMaskFormat(paint)); |
|
1640 |
|
1641 SkDeviceProperties::Geometry geometry = deviceProperties |
|
1642 ? deviceProperties->fGeometry |
|
1643 : SkDeviceProperties::Geometry::MakeDefault(); |
|
1644 if (SkMask::kLCD16_Format == rec->fMaskFormat || SkMask::kLCD32_Format == rec->fMaskFormat) { |
|
1645 if (!geometry.isOrientationKnown() || !geometry.isLayoutKnown() || tooBigForLCD(*rec)) { |
|
1646 // eeek, can't support LCD |
|
1647 rec->fMaskFormat = SkMask::kA8_Format; |
|
1648 } else { |
|
1649 if (SkDeviceProperties::Geometry::kVertical_Orientation == geometry.getOrientation()) { |
|
1650 flags |= SkScalerContext::kLCD_Vertical_Flag; |
|
1651 } |
|
1652 if (SkDeviceProperties::Geometry::kBGR_Layout == geometry.getLayout()) { |
|
1653 flags |= SkScalerContext::kLCD_BGROrder_Flag; |
|
1654 } |
|
1655 } |
|
1656 } |
|
1657 |
|
1658 if (paint.isEmbeddedBitmapText()) { |
|
1659 flags |= SkScalerContext::kEmbeddedBitmapText_Flag; |
|
1660 } |
|
1661 if (paint.isSubpixelText()) { |
|
1662 flags |= SkScalerContext::kSubpixelPositioning_Flag; |
|
1663 } |
|
1664 if (paint.isAutohinted()) { |
|
1665 flags |= SkScalerContext::kForceAutohinting_Flag; |
|
1666 } |
|
1667 if (paint.isVerticalText()) { |
|
1668 flags |= SkScalerContext::kVertical_Flag; |
|
1669 } |
|
1670 if (paint.getFlags() & SkPaint::kGenA8FromLCD_Flag) { |
|
1671 flags |= SkScalerContext::kGenA8FromLCD_Flag; |
|
1672 } |
|
1673 rec->fFlags = SkToU16(flags); |
|
1674 |
|
1675 // these modify fFlags, so do them after assigning fFlags |
|
1676 rec->setHinting(computeHinting(paint)); |
|
1677 |
|
1678 rec->setLuminanceColor(computeLuminanceColor(paint)); |
|
1679 |
|
1680 if (NULL == deviceProperties) { |
|
1681 rec->setDeviceGamma(SK_GAMMA_EXPONENT); |
|
1682 rec->setPaintGamma(SK_GAMMA_EXPONENT); |
|
1683 } else { |
|
1684 rec->setDeviceGamma(deviceProperties->fGamma); |
|
1685 |
|
1686 //For now always set the paint gamma equal to the device gamma. |
|
1687 //The math in SkMaskGamma can handle them being different, |
|
1688 //but it requires superluminous masks when |
|
1689 //Ex : deviceGamma(x) < paintGamma(x) and x is sufficiently large. |
|
1690 rec->setPaintGamma(deviceProperties->fGamma); |
|
1691 } |
|
1692 |
|
1693 #ifdef SK_GAMMA_CONTRAST |
|
1694 rec->setContrast(SK_GAMMA_CONTRAST); |
|
1695 #else |
|
1696 /** |
|
1697 * A value of 0.5 for SK_GAMMA_CONTRAST appears to be a good compromise. |
|
1698 * With lower values small text appears washed out (though correctly so). |
|
1699 * With higher values lcd fringing is worse and the smoothing effect of |
|
1700 * partial coverage is diminished. |
|
1701 */ |
|
1702 rec->setContrast(0.5f); |
|
1703 #endif |
|
1704 |
|
1705 rec->fReservedAlign = 0; |
|
1706 |
|
1707 /* Allow the fonthost to modify our rec before we use it as a key into the |
|
1708 cache. This way if we're asking for something that they will ignore, |
|
1709 they can modify our rec up front, so we don't create duplicate cache |
|
1710 entries. |
|
1711 */ |
|
1712 typeface->onFilterRec(rec); |
|
1713 |
|
1714 // be sure to call PostMakeRec(rec) before you actually use it! |
|
1715 } |
|
1716 |
|
1717 /** |
|
1718 * In order to call cachedDeviceLuminance, cachedPaintLuminance, or |
|
1719 * cachedMaskGamma the caller must hold the gMaskGammaCacheMutex and continue |
|
1720 * to hold it until the returned pointer is refed or forgotten. |
|
1721 */ |
|
1722 SK_DECLARE_STATIC_MUTEX(gMaskGammaCacheMutex); |
|
1723 |
|
1724 static SkMaskGamma* gLinearMaskGamma = NULL; |
|
1725 static SkMaskGamma* gMaskGamma = NULL; |
|
1726 static SkScalar gContrast = SK_ScalarMin; |
|
1727 static SkScalar gPaintGamma = SK_ScalarMin; |
|
1728 static SkScalar gDeviceGamma = SK_ScalarMin; |
|
1729 /** |
|
1730 * The caller must hold the gMaskGammaCacheMutex and continue to hold it until |
|
1731 * the returned SkMaskGamma pointer is refed or forgotten. |
|
1732 */ |
|
1733 static const SkMaskGamma& cachedMaskGamma(SkScalar contrast, SkScalar paintGamma, SkScalar deviceGamma) { |
|
1734 if (0 == contrast && SK_Scalar1 == paintGamma && SK_Scalar1 == deviceGamma) { |
|
1735 if (NULL == gLinearMaskGamma) { |
|
1736 gLinearMaskGamma = SkNEW(SkMaskGamma); |
|
1737 } |
|
1738 return *gLinearMaskGamma; |
|
1739 } |
|
1740 if (gContrast != contrast || gPaintGamma != paintGamma || gDeviceGamma != deviceGamma) { |
|
1741 SkSafeUnref(gMaskGamma); |
|
1742 gMaskGamma = SkNEW_ARGS(SkMaskGamma, (contrast, paintGamma, deviceGamma)); |
|
1743 gContrast = contrast; |
|
1744 gPaintGamma = paintGamma; |
|
1745 gDeviceGamma = deviceGamma; |
|
1746 } |
|
1747 return *gMaskGamma; |
|
1748 } |
|
1749 |
|
1750 /*static*/ void SkPaint::Term() { |
|
1751 SkAutoMutexAcquire ama(gMaskGammaCacheMutex); |
|
1752 |
|
1753 SkSafeUnref(gLinearMaskGamma); |
|
1754 gLinearMaskGamma = NULL; |
|
1755 SkSafeUnref(gMaskGamma); |
|
1756 gMaskGamma = NULL; |
|
1757 SkDEBUGCODE(gContrast = SK_ScalarMin;) |
|
1758 SkDEBUGCODE(gPaintGamma = SK_ScalarMin;) |
|
1759 SkDEBUGCODE(gDeviceGamma = SK_ScalarMin;) |
|
1760 } |
|
1761 |
|
1762 /** |
|
1763 * We ensure that the rec is self-consistent and efficient (where possible) |
|
1764 */ |
|
1765 void SkScalerContext::PostMakeRec(const SkPaint&, SkScalerContext::Rec* rec) { |
|
1766 /** |
|
1767 * If we're asking for A8, we force the colorlum to be gray, since that |
|
1768 * limits the number of unique entries, and the scaler will only look at |
|
1769 * the lum of one of them. |
|
1770 */ |
|
1771 switch (rec->fMaskFormat) { |
|
1772 case SkMask::kLCD16_Format: |
|
1773 case SkMask::kLCD32_Format: { |
|
1774 // filter down the luminance color to a finite number of bits |
|
1775 SkColor color = rec->getLuminanceColor(); |
|
1776 rec->setLuminanceColor(SkMaskGamma::CanonicalColor(color)); |
|
1777 break; |
|
1778 } |
|
1779 case SkMask::kA8_Format: { |
|
1780 // filter down the luminance to a single component, since A8 can't |
|
1781 // use per-component information |
|
1782 |
|
1783 SkColor color = rec->getLuminanceColor(); |
|
1784 U8CPU lum = SkColorSpaceLuminance::computeLuminance(rec->getPaintGamma(), color); |
|
1785 //If we are asked to look like LCD, look like LCD. |
|
1786 if (!(rec->fFlags & SkScalerContext::kGenA8FromLCD_Flag)) { |
|
1787 // HACK: Prevents green from being pre-blended as white. |
|
1788 lum -= ((255 - lum) * lum) / 255; |
|
1789 } |
|
1790 |
|
1791 // reduce to our finite number of bits |
|
1792 color = SkColorSetRGB(lum, lum, lum); |
|
1793 rec->setLuminanceColor(SkMaskGamma::CanonicalColor(color)); |
|
1794 break; |
|
1795 } |
|
1796 case SkMask::kBW_Format: |
|
1797 // No need to differentiate gamma if we're BW |
|
1798 rec->ignorePreBlend(); |
|
1799 break; |
|
1800 } |
|
1801 } |
|
1802 |
|
1803 #define MIN_SIZE_FOR_EFFECT_BUFFER 1024 |
|
1804 |
|
1805 #ifdef SK_DEBUG |
|
1806 #define TEST_DESC |
|
1807 #endif |
|
1808 |
|
1809 /* |
|
1810 * ignoreGamma tells us that the caller just wants metrics that are unaffected |
|
1811 * by gamma correction, so we jam the luminance field to 0 (most common value |
|
1812 * for black text) in hopes that we get a cache hit easier. A better solution |
|
1813 * would be for the fontcache lookup to know to ignore the luminance field |
|
1814 * entirely, but not sure how to do that and keep it fast. |
|
1815 */ |
|
1816 void SkPaint::descriptorProc(const SkDeviceProperties* deviceProperties, |
|
1817 const SkMatrix* deviceMatrix, |
|
1818 void (*proc)(SkTypeface*, const SkDescriptor*, void*), |
|
1819 void* context, bool ignoreGamma) const { |
|
1820 SkScalerContext::Rec rec; |
|
1821 |
|
1822 SkScalerContext::MakeRec(*this, deviceProperties, deviceMatrix, &rec); |
|
1823 if (ignoreGamma) { |
|
1824 rec.setLuminanceColor(0); |
|
1825 } |
|
1826 |
|
1827 size_t descSize = sizeof(rec); |
|
1828 int entryCount = 1; |
|
1829 SkPathEffect* pe = this->getPathEffect(); |
|
1830 SkMaskFilter* mf = this->getMaskFilter(); |
|
1831 SkRasterizer* ra = this->getRasterizer(); |
|
1832 |
|
1833 SkWriteBuffer peBuffer, mfBuffer, raBuffer; |
|
1834 |
|
1835 if (pe) { |
|
1836 peBuffer.writeFlattenable(pe); |
|
1837 descSize += peBuffer.bytesWritten(); |
|
1838 entryCount += 1; |
|
1839 rec.fMaskFormat = SkMask::kA8_Format; // force antialiasing when we do the scan conversion |
|
1840 // seems like we could support kLCD as well at this point... |
|
1841 } |
|
1842 if (mf) { |
|
1843 mfBuffer.writeFlattenable(mf); |
|
1844 descSize += mfBuffer.bytesWritten(); |
|
1845 entryCount += 1; |
|
1846 rec.fMaskFormat = SkMask::kA8_Format; // force antialiasing with maskfilters |
|
1847 /* Pre-blend is not currently applied to filtered text. |
|
1848 The primary filter is blur, for which contrast makes no sense, |
|
1849 and for which the destination guess error is more visible. |
|
1850 Also, all existing users of blur have calibrated for linear. */ |
|
1851 rec.ignorePreBlend(); |
|
1852 } |
|
1853 if (ra) { |
|
1854 raBuffer.writeFlattenable(ra); |
|
1855 descSize += raBuffer.bytesWritten(); |
|
1856 entryCount += 1; |
|
1857 rec.fMaskFormat = SkMask::kA8_Format; // force antialiasing when we do the scan conversion |
|
1858 } |
|
1859 |
|
1860 #ifdef SK_BUILD_FOR_ANDROID |
|
1861 SkWriteBuffer androidBuffer; |
|
1862 fPaintOptionsAndroid.flatten(androidBuffer); |
|
1863 descSize += androidBuffer.bytesWritten(); |
|
1864 entryCount += 1; |
|
1865 #endif |
|
1866 |
|
1867 /////////////////////////////////////////////////////////////////////////// |
|
1868 // Now that we're done tweaking the rec, call the PostMakeRec cleanup |
|
1869 SkScalerContext::PostMakeRec(*this, &rec); |
|
1870 |
|
1871 descSize += SkDescriptor::ComputeOverhead(entryCount); |
|
1872 |
|
1873 SkAutoDescriptor ad(descSize); |
|
1874 SkDescriptor* desc = ad.getDesc(); |
|
1875 |
|
1876 desc->init(); |
|
1877 desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); |
|
1878 |
|
1879 #ifdef SK_BUILD_FOR_ANDROID |
|
1880 add_flattenable(desc, kAndroidOpts_SkDescriptorTag, &androidBuffer); |
|
1881 #endif |
|
1882 |
|
1883 if (pe) { |
|
1884 add_flattenable(desc, kPathEffect_SkDescriptorTag, &peBuffer); |
|
1885 } |
|
1886 if (mf) { |
|
1887 add_flattenable(desc, kMaskFilter_SkDescriptorTag, &mfBuffer); |
|
1888 } |
|
1889 if (ra) { |
|
1890 add_flattenable(desc, kRasterizer_SkDescriptorTag, &raBuffer); |
|
1891 } |
|
1892 |
|
1893 SkASSERT(descSize == desc->getLength()); |
|
1894 desc->computeChecksum(); |
|
1895 |
|
1896 #ifdef TEST_DESC |
|
1897 { |
|
1898 // Check that we completely write the bytes in desc (our key), and that |
|
1899 // there are no uninitialized bytes. If there were, then we would get |
|
1900 // false-misses (or worse, false-hits) in our fontcache. |
|
1901 // |
|
1902 // We do this buy filling 2 others, one with 0s and the other with 1s |
|
1903 // and create those, and then check that all 3 are identical. |
|
1904 SkAutoDescriptor ad1(descSize); |
|
1905 SkAutoDescriptor ad2(descSize); |
|
1906 SkDescriptor* desc1 = ad1.getDesc(); |
|
1907 SkDescriptor* desc2 = ad2.getDesc(); |
|
1908 |
|
1909 memset(desc1, 0x00, descSize); |
|
1910 memset(desc2, 0xFF, descSize); |
|
1911 |
|
1912 desc1->init(); |
|
1913 desc2->init(); |
|
1914 desc1->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); |
|
1915 desc2->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec); |
|
1916 |
|
1917 #ifdef SK_BUILD_FOR_ANDROID |
|
1918 add_flattenable(desc1, kAndroidOpts_SkDescriptorTag, &androidBuffer); |
|
1919 add_flattenable(desc2, kAndroidOpts_SkDescriptorTag, &androidBuffer); |
|
1920 #endif |
|
1921 |
|
1922 if (pe) { |
|
1923 add_flattenable(desc1, kPathEffect_SkDescriptorTag, &peBuffer); |
|
1924 add_flattenable(desc2, kPathEffect_SkDescriptorTag, &peBuffer); |
|
1925 } |
|
1926 if (mf) { |
|
1927 add_flattenable(desc1, kMaskFilter_SkDescriptorTag, &mfBuffer); |
|
1928 add_flattenable(desc2, kMaskFilter_SkDescriptorTag, &mfBuffer); |
|
1929 } |
|
1930 if (ra) { |
|
1931 add_flattenable(desc1, kRasterizer_SkDescriptorTag, &raBuffer); |
|
1932 add_flattenable(desc2, kRasterizer_SkDescriptorTag, &raBuffer); |
|
1933 } |
|
1934 |
|
1935 SkASSERT(descSize == desc1->getLength()); |
|
1936 SkASSERT(descSize == desc2->getLength()); |
|
1937 desc1->computeChecksum(); |
|
1938 desc2->computeChecksum(); |
|
1939 SkASSERT(!memcmp(desc, desc1, descSize)); |
|
1940 SkASSERT(!memcmp(desc, desc2, descSize)); |
|
1941 } |
|
1942 #endif |
|
1943 |
|
1944 proc(fTypeface, desc, context); |
|
1945 } |
|
1946 |
|
1947 SkGlyphCache* SkPaint::detachCache(const SkDeviceProperties* deviceProperties, |
|
1948 const SkMatrix* deviceMatrix) const { |
|
1949 SkGlyphCache* cache; |
|
1950 this->descriptorProc(deviceProperties, deviceMatrix, DetachDescProc, &cache, false); |
|
1951 return cache; |
|
1952 } |
|
1953 |
|
1954 /** |
|
1955 * Expands fDeviceGamma, fPaintGamma, fContrast, and fLumBits into a mask pre-blend. |
|
1956 */ |
|
1957 //static |
|
1958 SkMaskGamma::PreBlend SkScalerContext::GetMaskPreBlend(const SkScalerContext::Rec& rec) { |
|
1959 SkAutoMutexAcquire ama(gMaskGammaCacheMutex); |
|
1960 const SkMaskGamma& maskGamma = cachedMaskGamma(rec.getContrast(), |
|
1961 rec.getPaintGamma(), |
|
1962 rec.getDeviceGamma()); |
|
1963 return maskGamma.preBlend(rec.getLuminanceColor()); |
|
1964 } |
|
1965 |
|
1966 /////////////////////////////////////////////////////////////////////////////// |
|
1967 |
|
1968 #include "SkStream.h" |
|
1969 |
|
1970 static uintptr_t asint(const void* p) { |
|
1971 return reinterpret_cast<uintptr_t>(p); |
|
1972 } |
|
1973 |
|
1974 union Scalar32 { |
|
1975 SkScalar fScalar; |
|
1976 uint32_t f32; |
|
1977 }; |
|
1978 |
|
1979 static uint32_t* write_scalar(uint32_t* ptr, SkScalar value) { |
|
1980 SkASSERT(sizeof(SkScalar) == sizeof(uint32_t)); |
|
1981 Scalar32 tmp; |
|
1982 tmp.fScalar = value; |
|
1983 *ptr = tmp.f32; |
|
1984 return ptr + 1; |
|
1985 } |
|
1986 |
|
1987 static SkScalar read_scalar(const uint32_t*& ptr) { |
|
1988 SkASSERT(sizeof(SkScalar) == sizeof(uint32_t)); |
|
1989 Scalar32 tmp; |
|
1990 tmp.f32 = *ptr++; |
|
1991 return tmp.fScalar; |
|
1992 } |
|
1993 |
|
1994 static uint32_t pack_4(unsigned a, unsigned b, unsigned c, unsigned d) { |
|
1995 SkASSERT(a == (uint8_t)a); |
|
1996 SkASSERT(b == (uint8_t)b); |
|
1997 SkASSERT(c == (uint8_t)c); |
|
1998 SkASSERT(d == (uint8_t)d); |
|
1999 return (a << 24) | (b << 16) | (c << 8) | d; |
|
2000 } |
|
2001 |
|
2002 enum FlatFlags { |
|
2003 kHasTypeface_FlatFlag = 0x01, |
|
2004 kHasEffects_FlatFlag = 0x02, |
|
2005 kHasNonDefaultPaintOptionsAndroid_FlatFlag = 0x04, |
|
2006 }; |
|
2007 |
|
2008 // The size of a flat paint's POD fields |
|
2009 static const uint32_t kPODPaintSize = 5 * sizeof(SkScalar) + |
|
2010 1 * sizeof(SkColor) + |
|
2011 1 * sizeof(uint16_t) + |
|
2012 6 * sizeof(uint8_t); |
|
2013 |
|
2014 /* To save space/time, we analyze the paint, and write a truncated version of |
|
2015 it if there are not tricky elements like shaders, etc. |
|
2016 */ |
|
2017 void SkPaint::flatten(SkWriteBuffer& buffer) const { |
|
2018 uint8_t flatFlags = 0; |
|
2019 if (this->getTypeface()) { |
|
2020 flatFlags |= kHasTypeface_FlatFlag; |
|
2021 } |
|
2022 if (asint(this->getPathEffect()) | |
|
2023 asint(this->getShader()) | |
|
2024 asint(this->getXfermode()) | |
|
2025 asint(this->getMaskFilter()) | |
|
2026 asint(this->getColorFilter()) | |
|
2027 asint(this->getRasterizer()) | |
|
2028 asint(this->getLooper()) | |
|
2029 asint(this->getAnnotation()) | |
|
2030 asint(this->getImageFilter())) { |
|
2031 flatFlags |= kHasEffects_FlatFlag; |
|
2032 } |
|
2033 #ifdef SK_BUILD_FOR_ANDROID |
|
2034 if (this->getPaintOptionsAndroid() != SkPaintOptionsAndroid()) { |
|
2035 flatFlags |= kHasNonDefaultPaintOptionsAndroid_FlatFlag; |
|
2036 } |
|
2037 #endif |
|
2038 |
|
2039 SkASSERT(SkAlign4(kPODPaintSize) == kPODPaintSize); |
|
2040 uint32_t* ptr = buffer.reserve(kPODPaintSize); |
|
2041 |
|
2042 ptr = write_scalar(ptr, this->getTextSize()); |
|
2043 ptr = write_scalar(ptr, this->getTextScaleX()); |
|
2044 ptr = write_scalar(ptr, this->getTextSkewX()); |
|
2045 ptr = write_scalar(ptr, this->getStrokeWidth()); |
|
2046 ptr = write_scalar(ptr, this->getStrokeMiter()); |
|
2047 *ptr++ = this->getColor(); |
|
2048 // previously flags:16, textAlign:8, flatFlags:8 |
|
2049 // now flags:16, hinting:4, textAlign:4, flatFlags:8 |
|
2050 *ptr++ = (this->getFlags() << 16) | |
|
2051 // hinting added later. 0 in this nibble means use the default. |
|
2052 ((this->getHinting()+1) << 12) | |
|
2053 (this->getTextAlign() << 8) | |
|
2054 flatFlags; |
|
2055 *ptr++ = pack_4(this->getStrokeCap(), this->getStrokeJoin(), |
|
2056 this->getStyle(), this->getTextEncoding()); |
|
2057 |
|
2058 // now we're done with ptr and the (pre)reserved space. If we need to write |
|
2059 // additional fields, use the buffer directly |
|
2060 if (flatFlags & kHasTypeface_FlatFlag) { |
|
2061 buffer.writeTypeface(this->getTypeface()); |
|
2062 } |
|
2063 if (flatFlags & kHasEffects_FlatFlag) { |
|
2064 buffer.writeFlattenable(this->getPathEffect()); |
|
2065 buffer.writeFlattenable(this->getShader()); |
|
2066 buffer.writeFlattenable(this->getXfermode()); |
|
2067 buffer.writeFlattenable(this->getMaskFilter()); |
|
2068 buffer.writeFlattenable(this->getColorFilter()); |
|
2069 buffer.writeFlattenable(this->getRasterizer()); |
|
2070 buffer.writeFlattenable(this->getLooper()); |
|
2071 buffer.writeFlattenable(this->getImageFilter()); |
|
2072 |
|
2073 if (fAnnotation) { |
|
2074 buffer.writeBool(true); |
|
2075 fAnnotation->writeToBuffer(buffer); |
|
2076 } else { |
|
2077 buffer.writeBool(false); |
|
2078 } |
|
2079 } |
|
2080 #ifdef SK_BUILD_FOR_ANDROID |
|
2081 if (flatFlags & kHasNonDefaultPaintOptionsAndroid_FlatFlag) { |
|
2082 this->getPaintOptionsAndroid().flatten(buffer); |
|
2083 } |
|
2084 #endif |
|
2085 } |
|
2086 |
|
2087 void SkPaint::unflatten(SkReadBuffer& buffer) { |
|
2088 uint8_t flatFlags = 0; |
|
2089 SkASSERT(SkAlign4(kPODPaintSize) == kPODPaintSize); |
|
2090 const void* podData = buffer.skip(kPODPaintSize); |
|
2091 const uint32_t* pod = reinterpret_cast<const uint32_t*>(podData); |
|
2092 |
|
2093 // the order we read must match the order we wrote in flatten() |
|
2094 this->setTextSize(read_scalar(pod)); |
|
2095 this->setTextScaleX(read_scalar(pod)); |
|
2096 this->setTextSkewX(read_scalar(pod)); |
|
2097 this->setStrokeWidth(read_scalar(pod)); |
|
2098 this->setStrokeMiter(read_scalar(pod)); |
|
2099 this->setColor(*pod++); |
|
2100 |
|
2101 // previously flags:16, textAlign:8, flatFlags:8 |
|
2102 // now flags:16, hinting:4, textAlign:4, flatFlags:8 |
|
2103 uint32_t tmp = *pod++; |
|
2104 this->setFlags(tmp >> 16); |
|
2105 |
|
2106 // hinting added later. 0 in this nibble means use the default. |
|
2107 uint32_t hinting = (tmp >> 12) & 0xF; |
|
2108 this->setHinting(0 == hinting ? kNormal_Hinting : static_cast<Hinting>(hinting-1)); |
|
2109 |
|
2110 this->setTextAlign(static_cast<Align>((tmp >> 8) & 0xF)); |
|
2111 |
|
2112 flatFlags = tmp & 0xFF; |
|
2113 |
|
2114 tmp = *pod++; |
|
2115 this->setStrokeCap(static_cast<Cap>((tmp >> 24) & 0xFF)); |
|
2116 this->setStrokeJoin(static_cast<Join>((tmp >> 16) & 0xFF)); |
|
2117 this->setStyle(static_cast<Style>((tmp >> 8) & 0xFF)); |
|
2118 this->setTextEncoding(static_cast<TextEncoding>((tmp >> 0) & 0xFF)); |
|
2119 |
|
2120 if (flatFlags & kHasTypeface_FlatFlag) { |
|
2121 this->setTypeface(buffer.readTypeface()); |
|
2122 } else { |
|
2123 this->setTypeface(NULL); |
|
2124 } |
|
2125 |
|
2126 if (flatFlags & kHasEffects_FlatFlag) { |
|
2127 SkSafeUnref(this->setPathEffect(buffer.readPathEffect())); |
|
2128 SkSafeUnref(this->setShader(buffer.readShader())); |
|
2129 SkSafeUnref(this->setXfermode(buffer.readXfermode())); |
|
2130 SkSafeUnref(this->setMaskFilter(buffer.readMaskFilter())); |
|
2131 SkSafeUnref(this->setColorFilter(buffer.readColorFilter())); |
|
2132 SkSafeUnref(this->setRasterizer(buffer.readRasterizer())); |
|
2133 SkSafeUnref(this->setLooper(buffer.readDrawLooper())); |
|
2134 SkSafeUnref(this->setImageFilter(buffer.readImageFilter())); |
|
2135 |
|
2136 if (buffer.readBool()) { |
|
2137 this->setAnnotation(SkAnnotation::Create(buffer))->unref(); |
|
2138 } |
|
2139 } else { |
|
2140 this->setPathEffect(NULL); |
|
2141 this->setShader(NULL); |
|
2142 this->setXfermode(NULL); |
|
2143 this->setMaskFilter(NULL); |
|
2144 this->setColorFilter(NULL); |
|
2145 this->setRasterizer(NULL); |
|
2146 this->setLooper(NULL); |
|
2147 this->setImageFilter(NULL); |
|
2148 } |
|
2149 |
|
2150 #ifdef SK_BUILD_FOR_ANDROID |
|
2151 this->setPaintOptionsAndroid(SkPaintOptionsAndroid()); |
|
2152 #endif |
|
2153 if (flatFlags & kHasNonDefaultPaintOptionsAndroid_FlatFlag) { |
|
2154 SkPaintOptionsAndroid options; |
|
2155 options.unflatten(buffer); |
|
2156 #ifdef SK_BUILD_FOR_ANDROID |
|
2157 this->setPaintOptionsAndroid(options); |
|
2158 #endif |
|
2159 } |
|
2160 } |
|
2161 |
|
2162 /////////////////////////////////////////////////////////////////////////////// |
|
2163 |
|
2164 SkShader* SkPaint::setShader(SkShader* shader) { |
|
2165 GEN_ID_INC_EVAL(shader != fShader); |
|
2166 SkRefCnt_SafeAssign(fShader, shader); |
|
2167 fDirtyBits = set_mask(fDirtyBits, kShader_DirtyBit, shader != NULL); |
|
2168 return shader; |
|
2169 } |
|
2170 |
|
2171 SkColorFilter* SkPaint::setColorFilter(SkColorFilter* filter) { |
|
2172 GEN_ID_INC_EVAL(filter != fColorFilter); |
|
2173 SkRefCnt_SafeAssign(fColorFilter, filter); |
|
2174 fDirtyBits = set_mask(fDirtyBits, kColorFilter_DirtyBit, filter != NULL); |
|
2175 return filter; |
|
2176 } |
|
2177 |
|
2178 SkXfermode* SkPaint::setXfermode(SkXfermode* mode) { |
|
2179 GEN_ID_INC_EVAL(mode != fXfermode); |
|
2180 SkRefCnt_SafeAssign(fXfermode, mode); |
|
2181 fDirtyBits = set_mask(fDirtyBits, kXfermode_DirtyBit, mode != NULL); |
|
2182 return mode; |
|
2183 } |
|
2184 |
|
2185 SkXfermode* SkPaint::setXfermodeMode(SkXfermode::Mode mode) { |
|
2186 SkSafeUnref(fXfermode); |
|
2187 fXfermode = SkXfermode::Create(mode); |
|
2188 GEN_ID_INC; |
|
2189 fDirtyBits = set_mask(fDirtyBits, kXfermode_DirtyBit, fXfermode != NULL); |
|
2190 return fXfermode; |
|
2191 } |
|
2192 |
|
2193 SkPathEffect* SkPaint::setPathEffect(SkPathEffect* effect) { |
|
2194 GEN_ID_INC_EVAL(effect != fPathEffect); |
|
2195 SkRefCnt_SafeAssign(fPathEffect, effect); |
|
2196 fDirtyBits = set_mask(fDirtyBits, kPathEffect_DirtyBit, effect != NULL); |
|
2197 return effect; |
|
2198 } |
|
2199 |
|
2200 SkMaskFilter* SkPaint::setMaskFilter(SkMaskFilter* filter) { |
|
2201 GEN_ID_INC_EVAL(filter != fMaskFilter); |
|
2202 SkRefCnt_SafeAssign(fMaskFilter, filter); |
|
2203 fDirtyBits = set_mask(fDirtyBits, kMaskFilter_DirtyBit, filter != NULL); |
|
2204 return filter; |
|
2205 } |
|
2206 |
|
2207 /////////////////////////////////////////////////////////////////////////////// |
|
2208 |
|
2209 bool SkPaint::getFillPath(const SkPath& src, SkPath* dst, |
|
2210 const SkRect* cullRect) const { |
|
2211 SkStrokeRec rec(*this); |
|
2212 |
|
2213 const SkPath* srcPtr = &src; |
|
2214 SkPath tmpPath; |
|
2215 |
|
2216 if (fPathEffect && fPathEffect->filterPath(&tmpPath, src, &rec, cullRect)) { |
|
2217 srcPtr = &tmpPath; |
|
2218 } |
|
2219 |
|
2220 if (!rec.applyToPath(dst, *srcPtr)) { |
|
2221 if (srcPtr == &tmpPath) { |
|
2222 // If path's were copy-on-write, this trick would not be needed. |
|
2223 // As it is, we want to save making a deep-copy from tmpPath -> dst |
|
2224 // since we know we're just going to delete tmpPath when we return, |
|
2225 // so the swap saves that copy. |
|
2226 dst->swap(tmpPath); |
|
2227 } else { |
|
2228 *dst = *srcPtr; |
|
2229 } |
|
2230 } |
|
2231 return !rec.isHairlineStyle(); |
|
2232 } |
|
2233 |
|
2234 const SkRect& SkPaint::doComputeFastBounds(const SkRect& origSrc, |
|
2235 SkRect* storage, |
|
2236 Style style) const { |
|
2237 SkASSERT(storage); |
|
2238 |
|
2239 const SkRect* src = &origSrc; |
|
2240 |
|
2241 if (this->getLooper()) { |
|
2242 SkASSERT(this->getLooper()->canComputeFastBounds(*this)); |
|
2243 this->getLooper()->computeFastBounds(*this, *src, storage); |
|
2244 return *storage; |
|
2245 } |
|
2246 |
|
2247 SkRect tmpSrc; |
|
2248 if (this->getPathEffect()) { |
|
2249 this->getPathEffect()->computeFastBounds(&tmpSrc, origSrc); |
|
2250 src = &tmpSrc; |
|
2251 } |
|
2252 |
|
2253 if (kFill_Style != style) { |
|
2254 // since we're stroked, outset the rect by the radius (and join type) |
|
2255 SkScalar radius = SkScalarHalf(this->getStrokeWidth()); |
|
2256 if (0 == radius) { // hairline |
|
2257 radius = SK_Scalar1; |
|
2258 } else if (this->getStrokeJoin() == SkPaint::kMiter_Join) { |
|
2259 SkScalar scale = this->getStrokeMiter(); |
|
2260 if (scale > SK_Scalar1) { |
|
2261 radius = SkScalarMul(radius, scale); |
|
2262 } |
|
2263 } |
|
2264 storage->set(src->fLeft - radius, src->fTop - radius, |
|
2265 src->fRight + radius, src->fBottom + radius); |
|
2266 } else { |
|
2267 *storage = *src; |
|
2268 } |
|
2269 |
|
2270 if (this->getMaskFilter()) { |
|
2271 this->getMaskFilter()->computeFastBounds(*storage, storage); |
|
2272 } |
|
2273 |
|
2274 if (this->getImageFilter()) { |
|
2275 this->getImageFilter()->computeFastBounds(*storage, storage); |
|
2276 } |
|
2277 |
|
2278 return *storage; |
|
2279 } |
|
2280 |
|
2281 #ifndef SK_IGNORE_TO_STRING |
|
2282 void SkPaint::toString(SkString* str) const { |
|
2283 str->append("<dl><dt>SkPaint:</dt><dd><dl>"); |
|
2284 |
|
2285 SkTypeface* typeface = this->getTypeface(); |
|
2286 if (NULL != typeface) { |
|
2287 SkDynamicMemoryWStream ostream; |
|
2288 typeface->serialize(&ostream); |
|
2289 SkAutoTUnref<SkData> data(ostream.copyToData()); |
|
2290 |
|
2291 SkMemoryStream stream(data); |
|
2292 SkFontDescriptor descriptor(&stream); |
|
2293 |
|
2294 str->append("<dt>Font Family Name:</dt><dd>"); |
|
2295 str->append(descriptor.getFamilyName()); |
|
2296 str->append("</dd><dt>Font Full Name:</dt><dd>"); |
|
2297 str->append(descriptor.getFullName()); |
|
2298 str->append("</dd><dt>Font PS Name:</dt><dd>"); |
|
2299 str->append(descriptor.getPostscriptName()); |
|
2300 str->append("</dd><dt>Font File Name:</dt><dd>"); |
|
2301 str->append(descriptor.getFontFileName()); |
|
2302 str->append("</dd>"); |
|
2303 } |
|
2304 |
|
2305 str->append("<dt>TextSize:</dt><dd>"); |
|
2306 str->appendScalar(this->getTextSize()); |
|
2307 str->append("</dd>"); |
|
2308 |
|
2309 str->append("<dt>TextScaleX:</dt><dd>"); |
|
2310 str->appendScalar(this->getTextScaleX()); |
|
2311 str->append("</dd>"); |
|
2312 |
|
2313 str->append("<dt>TextSkewX:</dt><dd>"); |
|
2314 str->appendScalar(this->getTextSkewX()); |
|
2315 str->append("</dd>"); |
|
2316 |
|
2317 SkPathEffect* pathEffect = this->getPathEffect(); |
|
2318 if (NULL != pathEffect) { |
|
2319 str->append("<dt>PathEffect:</dt><dd>"); |
|
2320 str->append("</dd>"); |
|
2321 } |
|
2322 |
|
2323 SkShader* shader = this->getShader(); |
|
2324 if (NULL != shader) { |
|
2325 str->append("<dt>Shader:</dt><dd>"); |
|
2326 shader->toString(str); |
|
2327 str->append("</dd>"); |
|
2328 } |
|
2329 |
|
2330 SkXfermode* xfer = this->getXfermode(); |
|
2331 if (NULL != xfer) { |
|
2332 str->append("<dt>Xfermode:</dt><dd>"); |
|
2333 xfer->toString(str); |
|
2334 str->append("</dd>"); |
|
2335 } |
|
2336 |
|
2337 SkMaskFilter* maskFilter = this->getMaskFilter(); |
|
2338 if (NULL != maskFilter) { |
|
2339 str->append("<dt>MaskFilter:</dt><dd>"); |
|
2340 maskFilter->toString(str); |
|
2341 str->append("</dd>"); |
|
2342 } |
|
2343 |
|
2344 SkColorFilter* colorFilter = this->getColorFilter(); |
|
2345 if (NULL != colorFilter) { |
|
2346 str->append("<dt>ColorFilter:</dt><dd>"); |
|
2347 colorFilter->toString(str); |
|
2348 str->append("</dd>"); |
|
2349 } |
|
2350 |
|
2351 SkRasterizer* rasterizer = this->getRasterizer(); |
|
2352 if (NULL != rasterizer) { |
|
2353 str->append("<dt>Rasterizer:</dt><dd>"); |
|
2354 str->append("</dd>"); |
|
2355 } |
|
2356 |
|
2357 SkDrawLooper* looper = this->getLooper(); |
|
2358 if (NULL != looper) { |
|
2359 str->append("<dt>DrawLooper:</dt><dd>"); |
|
2360 looper->toString(str); |
|
2361 str->append("</dd>"); |
|
2362 } |
|
2363 |
|
2364 SkImageFilter* imageFilter = this->getImageFilter(); |
|
2365 if (NULL != imageFilter) { |
|
2366 str->append("<dt>ImageFilter:</dt><dd>"); |
|
2367 str->append("</dd>"); |
|
2368 } |
|
2369 |
|
2370 SkAnnotation* annotation = this->getAnnotation(); |
|
2371 if (NULL != annotation) { |
|
2372 str->append("<dt>Annotation:</dt><dd>"); |
|
2373 str->append("</dd>"); |
|
2374 } |
|
2375 |
|
2376 str->append("<dt>Color:</dt><dd>0x"); |
|
2377 SkColor color = this->getColor(); |
|
2378 str->appendHex(color); |
|
2379 str->append("</dd>"); |
|
2380 |
|
2381 str->append("<dt>Stroke Width:</dt><dd>"); |
|
2382 str->appendScalar(this->getStrokeWidth()); |
|
2383 str->append("</dd>"); |
|
2384 |
|
2385 str->append("<dt>Stroke Miter:</dt><dd>"); |
|
2386 str->appendScalar(this->getStrokeMiter()); |
|
2387 str->append("</dd>"); |
|
2388 |
|
2389 str->append("<dt>Flags:</dt><dd>("); |
|
2390 if (this->getFlags()) { |
|
2391 bool needSeparator = false; |
|
2392 SkAddFlagToString(str, this->isAntiAlias(), "AntiAlias", &needSeparator); |
|
2393 SkAddFlagToString(str, this->isDither(), "Dither", &needSeparator); |
|
2394 SkAddFlagToString(str, this->isUnderlineText(), "UnderlineText", &needSeparator); |
|
2395 SkAddFlagToString(str, this->isStrikeThruText(), "StrikeThruText", &needSeparator); |
|
2396 SkAddFlagToString(str, this->isFakeBoldText(), "FakeBoldText", &needSeparator); |
|
2397 SkAddFlagToString(str, this->isLinearText(), "LinearText", &needSeparator); |
|
2398 SkAddFlagToString(str, this->isSubpixelText(), "SubpixelText", &needSeparator); |
|
2399 SkAddFlagToString(str, this->isDevKernText(), "DevKernText", &needSeparator); |
|
2400 SkAddFlagToString(str, this->isLCDRenderText(), "LCDRenderText", &needSeparator); |
|
2401 SkAddFlagToString(str, this->isEmbeddedBitmapText(), |
|
2402 "EmbeddedBitmapText", &needSeparator); |
|
2403 SkAddFlagToString(str, this->isAutohinted(), "Autohinted", &needSeparator); |
|
2404 SkAddFlagToString(str, this->isVerticalText(), "VerticalText", &needSeparator); |
|
2405 SkAddFlagToString(str, SkToBool(this->getFlags() & SkPaint::kGenA8FromLCD_Flag), |
|
2406 "GenA8FromLCD", &needSeparator); |
|
2407 } else { |
|
2408 str->append("None"); |
|
2409 } |
|
2410 str->append(")</dd>"); |
|
2411 |
|
2412 str->append("<dt>FilterLevel:</dt><dd>"); |
|
2413 static const char* gFilterLevelStrings[] = { "None", "Low", "Medium", "High" }; |
|
2414 str->append(gFilterLevelStrings[this->getFilterLevel()]); |
|
2415 str->append("</dd>"); |
|
2416 |
|
2417 str->append("<dt>TextAlign:</dt><dd>"); |
|
2418 static const char* gTextAlignStrings[SkPaint::kAlignCount] = { "Left", "Center", "Right" }; |
|
2419 str->append(gTextAlignStrings[this->getTextAlign()]); |
|
2420 str->append("</dd>"); |
|
2421 |
|
2422 str->append("<dt>CapType:</dt><dd>"); |
|
2423 static const char* gStrokeCapStrings[SkPaint::kCapCount] = { "Butt", "Round", "Square" }; |
|
2424 str->append(gStrokeCapStrings[this->getStrokeCap()]); |
|
2425 str->append("</dd>"); |
|
2426 |
|
2427 str->append("<dt>JoinType:</dt><dd>"); |
|
2428 static const char* gJoinStrings[SkPaint::kJoinCount] = { "Miter", "Round", "Bevel" }; |
|
2429 str->append(gJoinStrings[this->getStrokeJoin()]); |
|
2430 str->append("</dd>"); |
|
2431 |
|
2432 str->append("<dt>Style:</dt><dd>"); |
|
2433 static const char* gStyleStrings[SkPaint::kStyleCount] = { "Fill", "Stroke", "StrokeAndFill" }; |
|
2434 str->append(gStyleStrings[this->getStyle()]); |
|
2435 str->append("</dd>"); |
|
2436 |
|
2437 str->append("<dt>TextEncoding:</dt><dd>"); |
|
2438 static const char* gTextEncodingStrings[] = { "UTF8", "UTF16", "UTF32", "GlyphID" }; |
|
2439 str->append(gTextEncodingStrings[this->getTextEncoding()]); |
|
2440 str->append("</dd>"); |
|
2441 |
|
2442 str->append("<dt>Hinting:</dt><dd>"); |
|
2443 static const char* gHintingStrings[] = { "None", "Slight", "Normal", "Full" }; |
|
2444 str->append(gHintingStrings[this->getHinting()]); |
|
2445 str->append("</dd>"); |
|
2446 |
|
2447 str->append("</dd></dl></dl>"); |
|
2448 } |
|
2449 #endif |
|
2450 |
|
2451 /////////////////////////////////////////////////////////////////////////////// |
|
2452 |
|
2453 static bool has_thick_frame(const SkPaint& paint) { |
|
2454 return paint.getStrokeWidth() > 0 && |
|
2455 paint.getStyle() != SkPaint::kFill_Style; |
|
2456 } |
|
2457 |
|
2458 SkTextToPathIter::SkTextToPathIter( const char text[], size_t length, |
|
2459 const SkPaint& paint, |
|
2460 bool applyStrokeAndPathEffects) |
|
2461 : fPaint(paint) { |
|
2462 fGlyphCacheProc = paint.getMeasureCacheProc(SkPaint::kForward_TextBufferDirection, |
|
2463 true); |
|
2464 |
|
2465 fPaint.setLinearText(true); |
|
2466 fPaint.setMaskFilter(NULL); // don't want this affecting our path-cache lookup |
|
2467 |
|
2468 if (fPaint.getPathEffect() == NULL && !has_thick_frame(fPaint)) { |
|
2469 applyStrokeAndPathEffects = false; |
|
2470 } |
|
2471 |
|
2472 // can't use our canonical size if we need to apply patheffects |
|
2473 if (fPaint.getPathEffect() == NULL) { |
|
2474 fPaint.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPaths)); |
|
2475 fScale = paint.getTextSize() / SkPaint::kCanonicalTextSizeForPaths; |
|
2476 if (has_thick_frame(fPaint)) { |
|
2477 fPaint.setStrokeWidth(SkScalarDiv(fPaint.getStrokeWidth(), fScale)); |
|
2478 } |
|
2479 } else { |
|
2480 fScale = SK_Scalar1; |
|
2481 } |
|
2482 |
|
2483 if (!applyStrokeAndPathEffects) { |
|
2484 fPaint.setStyle(SkPaint::kFill_Style); |
|
2485 fPaint.setPathEffect(NULL); |
|
2486 } |
|
2487 |
|
2488 fCache = fPaint.detachCache(NULL, NULL); |
|
2489 |
|
2490 SkPaint::Style style = SkPaint::kFill_Style; |
|
2491 SkPathEffect* pe = NULL; |
|
2492 |
|
2493 if (!applyStrokeAndPathEffects) { |
|
2494 style = paint.getStyle(); // restore |
|
2495 pe = paint.getPathEffect(); // restore |
|
2496 } |
|
2497 fPaint.setStyle(style); |
|
2498 fPaint.setPathEffect(pe); |
|
2499 fPaint.setMaskFilter(paint.getMaskFilter()); // restore |
|
2500 |
|
2501 // now compute fXOffset if needed |
|
2502 |
|
2503 SkScalar xOffset = 0; |
|
2504 if (paint.getTextAlign() != SkPaint::kLeft_Align) { // need to measure first |
|
2505 int count; |
|
2506 SkScalar width = SkScalarMul(fPaint.measure_text(fCache, text, length, |
|
2507 &count, NULL), fScale); |
|
2508 if (paint.getTextAlign() == SkPaint::kCenter_Align) { |
|
2509 width = SkScalarHalf(width); |
|
2510 } |
|
2511 xOffset = -width; |
|
2512 } |
|
2513 fXPos = xOffset; |
|
2514 fPrevAdvance = 0; |
|
2515 |
|
2516 fText = text; |
|
2517 fStop = text + length; |
|
2518 |
|
2519 fXYIndex = paint.isVerticalText() ? 1 : 0; |
|
2520 } |
|
2521 |
|
2522 SkTextToPathIter::~SkTextToPathIter() { |
|
2523 SkGlyphCache::AttachCache(fCache); |
|
2524 } |
|
2525 |
|
2526 bool SkTextToPathIter::next(const SkPath** path, SkScalar* xpos) { |
|
2527 if (fText < fStop) { |
|
2528 const SkGlyph& glyph = fGlyphCacheProc(fCache, &fText); |
|
2529 |
|
2530 fXPos += SkScalarMul(SkFixedToScalar(fPrevAdvance + fAutoKern.adjust(glyph)), fScale); |
|
2531 fPrevAdvance = advance(glyph, fXYIndex); // + fPaint.getTextTracking(); |
|
2532 |
|
2533 if (glyph.fWidth) { |
|
2534 if (path) { |
|
2535 *path = fCache->findPath(glyph); |
|
2536 } |
|
2537 } else { |
|
2538 if (path) { |
|
2539 *path = NULL; |
|
2540 } |
|
2541 } |
|
2542 if (xpos) { |
|
2543 *xpos = fXPos; |
|
2544 } |
|
2545 return true; |
|
2546 } |
|
2547 return false; |
|
2548 } |
|
2549 |
|
2550 /////////////////////////////////////////////////////////////////////////////// |
|
2551 |
|
2552 bool SkPaint::nothingToDraw() const { |
|
2553 if (fLooper) { |
|
2554 return false; |
|
2555 } |
|
2556 SkXfermode::Mode mode; |
|
2557 if (SkXfermode::AsMode(fXfermode, &mode)) { |
|
2558 switch (mode) { |
|
2559 case SkXfermode::kSrcOver_Mode: |
|
2560 case SkXfermode::kSrcATop_Mode: |
|
2561 case SkXfermode::kDstOut_Mode: |
|
2562 case SkXfermode::kDstOver_Mode: |
|
2563 case SkXfermode::kPlus_Mode: |
|
2564 return 0 == this->getAlpha(); |
|
2565 case SkXfermode::kDst_Mode: |
|
2566 return true; |
|
2567 default: |
|
2568 break; |
|
2569 } |
|
2570 } |
|
2571 return false; |
|
2572 } |
|
2573 |
|
2574 void SkPaint::setBitfields(uint32_t bitfields) { |
|
2575 fBitfields = bitfields; |
|
2576 fDirtyBits |= kBitfields_DirtyBit; |
|
2577 } |
|
2578 |
|
2579 inline static unsigned popcount(uint8_t x) { |
|
2580 // As in Hacker's delight, adapted for just 8 bits. |
|
2581 x = (x & 0x55) + ((x >> 1) & 0x55); // a b c d w x y z -> a+b c+d w+x y+z |
|
2582 x = (x & 0x33) + ((x >> 2) & 0x33); // a+b c+d w+x y+z -> a+b+c+d w+x+y+z |
|
2583 x = (x & 0x0F) + ((x >> 4) & 0x0F); // a+b+c+d w+x+y+z -> a+b+c+d+w+x+y+z |
|
2584 return x; |
|
2585 } |
|
2586 |
|
2587 void SkPaint::FlatteningTraits::Flatten(SkWriteBuffer& buffer, const SkPaint& paint) { |
|
2588 const uint32_t dirty = paint.fDirtyBits; |
|
2589 |
|
2590 // Each of the low 7 dirty bits corresponds to a 4-byte flat value, plus one for the dirty bits. |
|
2591 const size_t flatBytes = 4 * (popcount(dirty & 127) + 1); |
|
2592 SkASSERT(flatBytes <= 32); |
|
2593 uint32_t* u32 = buffer.reserve(flatBytes); |
|
2594 *u32++ = dirty; |
|
2595 if (dirty == 0) { |
|
2596 return; |
|
2597 } |
|
2598 |
|
2599 #define F(dst, field) if (dirty & k##field##_DirtyBit) *dst++ = paint.get##field() |
|
2600 F(u32, Color); |
|
2601 F(u32, Bitfields); |
|
2602 SkScalar* f32 = reinterpret_cast<SkScalar*>(u32); |
|
2603 F(f32, TextSize); |
|
2604 F(f32, TextScaleX); |
|
2605 F(f32, TextSkewX); |
|
2606 F(f32, StrokeWidth); |
|
2607 F(f32, StrokeMiter); |
|
2608 #undef F |
|
2609 #define F(field) if (dirty & k##field##_DirtyBit) buffer.writeFlattenable(paint.get##field()) |
|
2610 F(PathEffect); |
|
2611 F(Shader); |
|
2612 F(Xfermode); |
|
2613 F(MaskFilter); |
|
2614 F(ColorFilter); |
|
2615 F(Rasterizer); |
|
2616 F(Looper); |
|
2617 F(ImageFilter); |
|
2618 #undef F |
|
2619 if (dirty & kTypeface_DirtyBit) buffer.writeTypeface(paint.getTypeface()); |
|
2620 if (dirty & kAnnotation_DirtyBit) paint.getAnnotation()->writeToBuffer(buffer); |
|
2621 #ifdef SK_BUILD_FOR_ANDROID |
|
2622 if (dirty & kPaintOptionsAndroid_DirtyBit) paint.getPaintOptionsAndroid().flatten(buffer); |
|
2623 #endif |
|
2624 } |
|
2625 |
|
2626 void SkPaint::FlatteningTraits::Unflatten(SkReadBuffer& buffer, SkPaint* paint) { |
|
2627 const uint32_t dirty = buffer.readUInt(); |
|
2628 if (dirty == 0) { |
|
2629 return; |
|
2630 } |
|
2631 #define F(field, reader) if (dirty & k##field##_DirtyBit) paint->set##field(buffer.reader()) |
|
2632 // Same function, except it unrefs the object newly set on the paint: |
|
2633 #define F_UNREF(field, reader) \ |
|
2634 if (dirty & k##field##_DirtyBit) \ |
|
2635 paint->set##field(buffer.reader())->unref() |
|
2636 |
|
2637 F(Color, readUInt); |
|
2638 F(Bitfields, readUInt); |
|
2639 F(TextSize, readScalar); |
|
2640 F(TextScaleX, readScalar); |
|
2641 F(TextSkewX, readScalar); |
|
2642 F(StrokeWidth, readScalar); |
|
2643 F(StrokeMiter, readScalar); |
|
2644 F_UNREF(PathEffect, readPathEffect); |
|
2645 F_UNREF(Shader, readShader); |
|
2646 F_UNREF(Xfermode, readXfermode); |
|
2647 F_UNREF(MaskFilter, readMaskFilter); |
|
2648 F_UNREF(ColorFilter, readColorFilter); |
|
2649 F_UNREF(Rasterizer, readRasterizer); |
|
2650 F_UNREF(Looper, readDrawLooper); |
|
2651 F_UNREF(ImageFilter, readImageFilter); |
|
2652 F(Typeface, readTypeface); |
|
2653 #undef F |
|
2654 #undef F_UNREF |
|
2655 if (dirty & kAnnotation_DirtyBit) { |
|
2656 paint->setAnnotation(SkAnnotation::Create(buffer))->unref(); |
|
2657 } |
|
2658 #ifdef SK_BUILD_FOR_ANDROID |
|
2659 if (dirty & kPaintOptionsAndroid_DirtyBit) { |
|
2660 SkPaintOptionsAndroid options; |
|
2661 options.unflatten(buffer); |
|
2662 paint->setPaintOptionsAndroid(options); |
|
2663 } |
|
2664 #endif |
|
2665 SkASSERT(dirty == paint->fDirtyBits); |
|
2666 } |