blob: 95448c959a12ace18eb1c29c1a4441878dc1e927 [file] [log] [blame]
reed@android.com8a1c16f2008-12-17 15:59:43 +00001/* libs/graphics/sgl/SkPaint.cpp
2**
3** Copyright 2006, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#include "SkPaint.h"
19#include "SkColorFilter.h"
20#include "SkDrawLooper.h"
21#include "SkFontHost.h"
22#include "SkMaskFilter.h"
23#include "SkPathEffect.h"
24#include "SkRasterizer.h"
25#include "SkShader.h"
26#include "SkScalerContext.h"
27#include "SkStroke.h"
28#include "SkTypeface.h"
29#include "SkXfermode.h"
30#include "SkAutoKern.h"
31
32#define SK_DefaultTextSize SkIntToScalar(12)
33
34#define SK_DefaultFlags 0 //(kNativeHintsText_Flag)
35
36SkPaint::SkPaint()
37{
38 fTypeface = NULL;
39 fTextSize = SK_DefaultTextSize;
40 fTextScaleX = SK_Scalar1;
41 fTextSkewX = 0;
42
43 fPathEffect = NULL;
44 fShader = NULL;
45 fXfermode = NULL;
46 fMaskFilter = NULL;
47 fColorFilter = NULL;
48 fRasterizer = NULL;
49 fLooper = NULL;
50
51 fColor = SK_ColorBLACK;
52 fWidth = 0;
53 fMiterLimit = SK_DefaultMiterLimit;
54 fFlags = SK_DefaultFlags;
55 fCapType = kDefault_Cap;
56 fJoinType = kDefault_Join;
57 fTextAlign = kLeft_Align;
58 fStyle = kFill_Style;
59 fTextEncoding = kUTF8_TextEncoding;
agl@chromium.org309485b2009-07-21 17:41:32 +000060 fHinting = kNormal_Hinting;
reed@android.com8a1c16f2008-12-17 15:59:43 +000061}
62
63SkPaint::SkPaint(const SkPaint& src)
64{
65 memcpy(this, &src, sizeof(src));
66
67 fTypeface->safeRef();
68 fPathEffect->safeRef();
69 fShader->safeRef();
70 fXfermode->safeRef();
71 fMaskFilter->safeRef();
72 fColorFilter->safeRef();
73 fRasterizer->safeRef();
74 fLooper->safeRef();
75}
76
77SkPaint::~SkPaint()
78{
79 fTypeface->safeUnref();
80 fPathEffect->safeUnref();
81 fShader->safeUnref();
82 fXfermode->safeUnref();
83 fMaskFilter->safeUnref();
84 fColorFilter->safeUnref();
85 fRasterizer->safeUnref();
86 fLooper->safeUnref();
87}
88
89SkPaint& SkPaint::operator=(const SkPaint& src)
90{
91 SkASSERT(&src);
92
93 src.fTypeface->safeRef();
94 src.fPathEffect->safeRef();
95 src.fShader->safeRef();
96 src.fXfermode->safeRef();
97 src.fMaskFilter->safeRef();
98 src.fColorFilter->safeRef();
99 src.fRasterizer->safeRef();
100 src.fLooper->safeRef();
101
102 fTypeface->safeUnref();
103 fPathEffect->safeUnref();
104 fShader->safeUnref();
105 fXfermode->safeUnref();
106 fMaskFilter->safeUnref();
107 fColorFilter->safeUnref();
108 fRasterizer->safeUnref();
109 fLooper->safeUnref();
110
111 memcpy(this, &src, sizeof(src));
112
113 return *this;
114}
115
116int operator==(const SkPaint& a, const SkPaint& b)
117{
118 return memcmp(&a, &b, sizeof(a)) == 0;
119}
120
121void SkPaint::reset()
122{
123 SkPaint init;
124
125 *this = init;
126}
127
128void SkPaint::setFlags(uint32_t flags)
129{
130 fFlags = flags;
131}
132
133void SkPaint::setAntiAlias(bool doAA)
134{
135 this->setFlags(SkSetClearMask(fFlags, doAA, kAntiAlias_Flag));
136}
137
138void SkPaint::setDither(bool doDither)
139{
140 this->setFlags(SkSetClearMask(fFlags, doDither, kDither_Flag));
141}
142
143void SkPaint::setSubpixelText(bool doSubpixel)
144{
145 this->setFlags(SkSetClearMask(fFlags, doSubpixel, kSubpixelText_Flag));
146}
147
agl@chromium.org309485b2009-07-21 17:41:32 +0000148void SkPaint::setLCDRenderText(bool doLCDRender)
149{
150 this->setFlags(SkSetClearMask(fFlags, doLCDRender, kLCDRenderText_Flag));
151}
152
reed@android.com8a1c16f2008-12-17 15:59:43 +0000153void SkPaint::setLinearText(bool doLinearText)
154{
155 this->setFlags(SkSetClearMask(fFlags, doLinearText, kLinearText_Flag));
156}
157
158void SkPaint::setUnderlineText(bool doUnderline)
159{
160 this->setFlags(SkSetClearMask(fFlags, doUnderline, kUnderlineText_Flag));
161}
162
163void SkPaint::setStrikeThruText(bool doStrikeThru)
164{
165 this->setFlags(SkSetClearMask(fFlags, doStrikeThru, kStrikeThruText_Flag));
166}
167
168void SkPaint::setFakeBoldText(bool doFakeBold)
169{
170 this->setFlags(SkSetClearMask(fFlags, doFakeBold, kFakeBoldText_Flag));
171}
172
173void SkPaint::setDevKernText(bool doDevKern)
174{
175 this->setFlags(SkSetClearMask(fFlags, doDevKern, kDevKernText_Flag));
176}
177
178void SkPaint::setFilterBitmap(bool doFilter)
179{
180 this->setFlags(SkSetClearMask(fFlags, doFilter, kFilterBitmap_Flag));
181}
182
183void SkPaint::setStyle(Style style)
184{
185 if ((unsigned)style < kStyleCount)
186 fStyle = style;
187#ifdef SK_DEBUG
188 else
189 SkDebugf("SkPaint::setStyle(%d) out of range\n", style);
190#endif
191}
192
193void SkPaint::setColor(SkColor color)
194{
195 fColor = color;
196}
197
198void SkPaint::setAlpha(U8CPU a)
199{
200 fColor = SkColorSetARGB(a, SkColorGetR(fColor), SkColorGetG(fColor), SkColorGetB(fColor));
201}
202
203void SkPaint::setARGB(U8CPU a, U8CPU r, U8CPU g, U8CPU b)
204{
205 fColor = SkColorSetARGB(a, r, g, b);
206}
207
208void SkPaint::setStrokeWidth(SkScalar width)
209{
210 if (width >= 0)
211 fWidth = width;
212#ifdef SK_DEBUG
213 else
214 SkDebugf("SkPaint::setStrokeWidth() called with negative value\n");
215#endif
216}
217
218void SkPaint::setStrokeMiter(SkScalar limit)
219{
220 if (limit >= 0)
221 fMiterLimit = limit;
222#ifdef SK_DEBUG
223 else
224 SkDebugf("SkPaint::setStrokeMiter() called with negative value\n");
225#endif
226}
227
228void SkPaint::setStrokeCap(Cap ct)
229{
230 if ((unsigned)ct < kCapCount)
231 fCapType = SkToU8(ct);
232#ifdef SK_DEBUG
233 else
234 SkDebugf("SkPaint::setStrokeCap(%d) out of range\n", ct);
235#endif
236}
237
238void SkPaint::setStrokeJoin(Join jt)
239{
240 if ((unsigned)jt < kJoinCount)
241 fJoinType = SkToU8(jt);
242#ifdef SK_DEBUG
243 else
244 SkDebugf("SkPaint::setStrokeJoin(%d) out of range\n", jt);
245#endif
246}
247
248//////////////////////////////////////////////////////////////////
249
250void SkPaint::setTextAlign(Align align)
251{
252 if ((unsigned)align < kAlignCount)
253 fTextAlign = SkToU8(align);
254#ifdef SK_DEBUG
255 else
256 SkDebugf("SkPaint::setTextAlign(%d) out of range\n", align);
257#endif
258}
259
260void SkPaint::setTextSize(SkScalar ts)
261{
262 if (ts > 0)
263 fTextSize = ts;
264#ifdef SK_DEBUG
265 else
266 SkDebugf("SkPaint::setTextSize() called with non-positive value\n");
267#endif
268}
269
270void SkPaint::setTextScaleX(SkScalar scaleX)
271{
272 fTextScaleX = scaleX;
273}
274
275void SkPaint::setTextSkewX(SkScalar skewX)
276{
277 fTextSkewX = skewX;
278}
279
280void SkPaint::setTextEncoding(TextEncoding encoding)
281{
282 if ((unsigned)encoding <= kGlyphID_TextEncoding)
283 fTextEncoding = encoding;
284#ifdef SK_DEBUG
285 else
286 SkDebugf("SkPaint::setTextEncoding(%d) out of range\n", encoding);
287#endif
288}
289
290///////////////////////////////////////////////////////////////////////////////////////
291
292SkTypeface* SkPaint::setTypeface(SkTypeface* font)
293{
294 SkRefCnt_SafeAssign(fTypeface, font);
295 return font;
296}
297
298SkRasterizer* SkPaint::setRasterizer(SkRasterizer* r)
299{
300 SkRefCnt_SafeAssign(fRasterizer, r);
301 return r;
302}
303
304SkDrawLooper* SkPaint::setLooper(SkDrawLooper* looper)
305{
306 SkRefCnt_SafeAssign(fLooper, looper);
307 return looper;
308}
309
310///////////////////////////////////////////////////////////////////////////////
311
312#include "SkGlyphCache.h"
313#include "SkUtils.h"
314
315int SkPaint::textToGlyphs(const void* textData, size_t byteLength,
316 uint16_t glyphs[]) const {
317 if (byteLength == 0) {
318 return 0;
319 }
320
321 SkASSERT(textData != NULL);
322
323 if (NULL == glyphs) {
324 switch (this->getTextEncoding()) {
325 case kUTF8_TextEncoding:
326 return SkUTF8_CountUnichars((const char*)textData, byteLength);
327 case kUTF16_TextEncoding:
328 return SkUTF16_CountUnichars((const uint16_t*)textData,
329 byteLength >> 1);
330 case kGlyphID_TextEncoding:
331 return byteLength >> 1;
332 default:
333 SkASSERT(!"unknown text encoding");
334 }
335 return 0;
336 }
337
338 // if we get here, we have a valid glyphs[] array, so time to fill it in
339
340 // handle this encoding before the setup for the glyphcache
341 if (this->getTextEncoding() == kGlyphID_TextEncoding) {
342 // we want to ignore the low bit of byteLength
343 memcpy(glyphs, textData, byteLength >> 1 << 1);
344 return byteLength >> 1;
345 }
346
347 SkAutoGlyphCache autoCache(*this, NULL);
348 SkGlyphCache* cache = autoCache.getCache();
349
350 const char* text = (const char*)textData;
351 const char* stop = text + byteLength;
352 uint16_t* gptr = glyphs;
353
354 switch (this->getTextEncoding()) {
355 case SkPaint::kUTF8_TextEncoding:
356 while (text < stop) {
357 *gptr++ = cache->unicharToGlyph(SkUTF8_NextUnichar(&text));
358 }
359 break;
360 case SkPaint::kUTF16_TextEncoding: {
361 const uint16_t* text16 = (const uint16_t*)text;
362 const uint16_t* stop16 = (const uint16_t*)stop;
363 while (text16 < stop16) {
364 *gptr++ = cache->unicharToGlyph(SkUTF16_NextUnichar(&text16));
365 }
366 break;
367 }
368 default:
369 SkASSERT(!"unknown text encoding");
370 }
371 return gptr - glyphs;
372}
373
374///////////////////////////////////////////////////////////////////////////////
375
reed@android.com8a1c16f2008-12-17 15:59:43 +0000376static const SkGlyph& sk_getMetrics_utf8_next(SkGlyphCache* cache, const char** text)
377{
378 SkASSERT(cache != NULL);
379 SkASSERT(text != NULL);
380
381 return cache->getUnicharMetrics(SkUTF8_NextUnichar(text));
382}
383
384static const SkGlyph& sk_getMetrics_utf8_prev(SkGlyphCache* cache, const char** text)
385{
386 SkASSERT(cache != NULL);
387 SkASSERT(text != NULL);
388
389 return cache->getUnicharMetrics(SkUTF8_PrevUnichar(text));
390}
391
392static const SkGlyph& sk_getMetrics_utf16_next(SkGlyphCache* cache, const char** text)
393{
394 SkASSERT(cache != NULL);
395 SkASSERT(text != NULL);
396
397 return cache->getUnicharMetrics(SkUTF16_NextUnichar((const uint16_t**)text));
398}
399
400static const SkGlyph& sk_getMetrics_utf16_prev(SkGlyphCache* cache, const char** text)
401{
402 SkASSERT(cache != NULL);
403 SkASSERT(text != NULL);
404
405 return cache->getUnicharMetrics(SkUTF16_PrevUnichar((const uint16_t**)text));
406}
407
408static const SkGlyph& sk_getMetrics_glyph_next(SkGlyphCache* cache, const char** text)
409{
410 SkASSERT(cache != NULL);
411 SkASSERT(text != NULL);
412
413 const uint16_t* ptr = *(const uint16_t**)text;
414 unsigned glyphID = *ptr;
415 ptr += 1;
416 *text = (const char*)ptr;
417 return cache->getGlyphIDMetrics(glyphID);
418}
419
420static const SkGlyph& sk_getMetrics_glyph_prev(SkGlyphCache* cache, const char** text)
421{
422 SkASSERT(cache != NULL);
423 SkASSERT(text != NULL);
424
425 const uint16_t* ptr = *(const uint16_t**)text;
426 ptr -= 1;
427 unsigned glyphID = *ptr;
428 *text = (const char*)ptr;
429 return cache->getGlyphIDMetrics(glyphID);
430}
431
432///
433
434static const SkGlyph& sk_getAdvance_utf8_next(SkGlyphCache* cache, const char** text)
435{
436 SkASSERT(cache != NULL);
437 SkASSERT(text != NULL);
438
439 return cache->getUnicharAdvance(SkUTF8_NextUnichar(text));
440}
441
442static const SkGlyph& sk_getAdvance_utf8_prev(SkGlyphCache* cache, const char** text)
443{
444 SkASSERT(cache != NULL);
445 SkASSERT(text != NULL);
446
447 return cache->getUnicharAdvance(SkUTF8_PrevUnichar(text));
448}
449
450static const SkGlyph& sk_getAdvance_utf16_next(SkGlyphCache* cache, const char** text)
451{
452 SkASSERT(cache != NULL);
453 SkASSERT(text != NULL);
454
455 return cache->getUnicharAdvance(SkUTF16_NextUnichar((const uint16_t**)text));
456}
457
458static const SkGlyph& sk_getAdvance_utf16_prev(SkGlyphCache* cache, const char** text)
459{
460 SkASSERT(cache != NULL);
461 SkASSERT(text != NULL);
462
463 return cache->getUnicharAdvance(SkUTF16_PrevUnichar((const uint16_t**)text));
464}
465
466static const SkGlyph& sk_getAdvance_glyph_next(SkGlyphCache* cache, const char** text)
467{
468 SkASSERT(cache != NULL);
469 SkASSERT(text != NULL);
470
471 const uint16_t* ptr = *(const uint16_t**)text;
472 unsigned glyphID = *ptr;
473 ptr += 1;
474 *text = (const char*)ptr;
475 return cache->getGlyphIDAdvance(glyphID);
476}
477
478static const SkGlyph& sk_getAdvance_glyph_prev(SkGlyphCache* cache, const char** text)
479{
480 SkASSERT(cache != NULL);
481 SkASSERT(text != NULL);
482
483 const uint16_t* ptr = *(const uint16_t**)text;
484 ptr -= 1;
485 unsigned glyphID = *ptr;
486 *text = (const char*)ptr;
487 return cache->getGlyphIDAdvance(glyphID);
488}
489
490SkMeasureCacheProc SkPaint::getMeasureCacheProc(TextBufferDirection tbd,
491 bool needFullMetrics) const
492{
493 static const SkMeasureCacheProc gMeasureCacheProcs[] = {
494 sk_getMetrics_utf8_next,
495 sk_getMetrics_utf16_next,
496 sk_getMetrics_glyph_next,
497
498 sk_getMetrics_utf8_prev,
499 sk_getMetrics_utf16_prev,
500 sk_getMetrics_glyph_prev,
501
502 sk_getAdvance_utf8_next,
503 sk_getAdvance_utf16_next,
504 sk_getAdvance_glyph_next,
505
506 sk_getAdvance_utf8_prev,
507 sk_getAdvance_utf16_prev,
508 sk_getAdvance_glyph_prev
509 };
510
511 unsigned index = this->getTextEncoding();
512
513 if (kBackward_TextBufferDirection == tbd)
514 index += 3;
515 if (!needFullMetrics && !this->isDevKernText())
516 index += 6;
517
518 SkASSERT(index < SK_ARRAY_COUNT(gMeasureCacheProcs));
519 return gMeasureCacheProcs[index];
520}
521
522///////////////////////////////////////////////////////////////////////////////
523
524static const SkGlyph& sk_getMetrics_utf8_00(SkGlyphCache* cache,
525 const char** text, SkFixed, SkFixed)
526{
527 SkASSERT(cache != NULL);
528 SkASSERT(text != NULL);
529
530 return cache->getUnicharMetrics(SkUTF8_NextUnichar(text));
531}
532
533static const SkGlyph& sk_getMetrics_utf8_xy(SkGlyphCache* cache,
534 const char** text, SkFixed x, SkFixed y)
535{
536 SkASSERT(cache != NULL);
537 SkASSERT(text != NULL);
538
539 return cache->getUnicharMetrics(SkUTF8_NextUnichar(text), x, y);
540}
541
542static const SkGlyph& sk_getMetrics_utf16_00(SkGlyphCache* cache, const char** text,
543 SkFixed, SkFixed)
544{
545 SkASSERT(cache != NULL);
546 SkASSERT(text != NULL);
547
548 return cache->getUnicharMetrics(SkUTF16_NextUnichar((const uint16_t**)text));
549}
550
551static const SkGlyph& sk_getMetrics_utf16_xy(SkGlyphCache* cache,
552 const char** text, SkFixed x, SkFixed y)
553{
554 SkASSERT(cache != NULL);
555 SkASSERT(text != NULL);
556
557 return cache->getUnicharMetrics(SkUTF16_NextUnichar((const uint16_t**)text),
558 x, y);
559}
560
561static const SkGlyph& sk_getMetrics_glyph_00(SkGlyphCache* cache, const char** text,
562 SkFixed, SkFixed)
563{
564 SkASSERT(cache != NULL);
565 SkASSERT(text != NULL);
566
567 const uint16_t* ptr = *(const uint16_t**)text;
568 unsigned glyphID = *ptr;
569 ptr += 1;
570 *text = (const char*)ptr;
571 return cache->getGlyphIDMetrics(glyphID);
572}
573
574static const SkGlyph& sk_getMetrics_glyph_xy(SkGlyphCache* cache,
575 const char** text, SkFixed x, SkFixed y)
576{
577 SkASSERT(cache != NULL);
578 SkASSERT(text != NULL);
579
580 const uint16_t* ptr = *(const uint16_t**)text;
581 unsigned glyphID = *ptr;
582 ptr += 1;
583 *text = (const char*)ptr;
584 return cache->getGlyphIDMetrics(glyphID, x, y);
585}
586
587SkDrawCacheProc SkPaint::getDrawCacheProc() const
588{
589 static const SkDrawCacheProc gDrawCacheProcs[] = {
590 sk_getMetrics_utf8_00,
591 sk_getMetrics_utf16_00,
592 sk_getMetrics_glyph_00,
593
594 sk_getMetrics_utf8_xy,
595 sk_getMetrics_utf16_xy,
596 sk_getMetrics_glyph_xy
597 };
598
599 unsigned index = this->getTextEncoding();
600 if (fFlags & kSubpixelText_Flag)
601 index += 3;
602
603 SkASSERT(index < SK_ARRAY_COUNT(gDrawCacheProcs));
604 return gDrawCacheProcs[index];
605}
606
607///////////////////////////////////////////////////////////////////////////////
608
609class SkAutoRestorePaintTextSizeAndFrame {
610public:
611 SkAutoRestorePaintTextSizeAndFrame(const SkPaint* paint) : fPaint((SkPaint*)paint)
612 {
613 fTextSize = paint->getTextSize();
614 fStyle = paint->getStyle();
615 fPaint->setStyle(SkPaint::kFill_Style);
616 }
617 ~SkAutoRestorePaintTextSizeAndFrame()
618 {
619 fPaint->setStyle(fStyle);
620 fPaint->setTextSize(fTextSize);
621 }
622
623private:
624 SkPaint* fPaint;
625 SkScalar fTextSize;
626 SkPaint::Style fStyle;
627};
628
629static void set_bounds(const SkGlyph& g, SkRect* bounds)
630{
631 bounds->set(SkIntToScalar(g.fLeft),
632 SkIntToScalar(g.fTop),
633 SkIntToScalar(g.fLeft + g.fWidth),
634 SkIntToScalar(g.fTop + g.fHeight));
635}
636
637static void join_bounds(const SkGlyph& g, SkRect* bounds, SkFixed dx)
638{
639 SkScalar sx = SkFixedToScalar(dx);
640 bounds->join(SkIntToScalar(g.fLeft) + sx,
641 SkIntToScalar(g.fTop),
642 SkIntToScalar(g.fLeft + g.fWidth) + sx,
643 SkIntToScalar(g.fTop + g.fHeight));
644}
645
646SkScalar SkPaint::measure_text(SkGlyphCache* cache,
647 const char* text, size_t byteLength,
648 int* count, SkRect* bounds) const
649{
650 SkASSERT(count);
651 if (byteLength == 0)
652 {
653 *count = 0;
654 if (bounds)
655 bounds->setEmpty();
656 return 0;
657 }
658
659 SkMeasureCacheProc glyphCacheProc;
660 glyphCacheProc = this->getMeasureCacheProc(kForward_TextBufferDirection,
661 NULL != bounds);
662
663 int n = 1;
664 const char* stop = (const char*)text + byteLength;
665 const SkGlyph* g = &glyphCacheProc(cache, &text);
666 SkFixed x = g->fAdvanceX;
667
668 SkAutoKern autokern;
669
670 if (NULL == bounds)
671 {
672 if (this->isDevKernText())
673 {
674 int rsb;
675 for (; text < stop; n++) {
676 rsb = g->fRsbDelta;
677 g = &glyphCacheProc(cache, &text);
678 x += SkAutoKern_AdjustF(rsb, g->fLsbDelta) + g->fAdvanceX;
679 }
680 }
681 else
682 {
683 for (; text < stop; n++) {
684 x += glyphCacheProc(cache, &text).fAdvanceX;
685 }
686 }
687 }
688 else
689 {
690 set_bounds(*g, bounds);
691 if (this->isDevKernText())
692 {
693 int rsb;
694 for (; text < stop; n++) {
695 rsb = g->fRsbDelta;
696 g = &glyphCacheProc(cache, &text);
697 x += SkAutoKern_AdjustF(rsb, g->fLsbDelta);
698 join_bounds(*g, bounds, x);
699 x += g->fAdvanceX;
700 }
701 }
702 else
703 {
704 for (; text < stop; n++) {
705 g = &glyphCacheProc(cache, &text);
706 join_bounds(*g, bounds, x);
707 x += g->fAdvanceX;
708 }
709 }
710 }
711 SkASSERT(text == stop);
712
713 *count = n;
714 return SkFixedToScalar(x);
715}
716
717SkScalar SkPaint::measureText(const void* textData, size_t length,
718 SkRect* bounds, SkScalar zoom) const
719{
720 const char* text = (const char*)textData;
721 SkASSERT(text != NULL || length == 0);
722
723 SkScalar scale = 0;
724 SkAutoRestorePaintTextSizeAndFrame restore(this);
725
726 if (this->isLinearText())
727 {
728 scale = fTextSize / kCanonicalTextSizeForPaths;
729 // this gets restored by restore
730 ((SkPaint*)this)->setTextSize(SkIntToScalar(kCanonicalTextSizeForPaths));
731 }
732
733 SkMatrix zoomMatrix, *zoomPtr = NULL;
734 if (zoom)
735 {
736 zoomMatrix.setScale(zoom, zoom);
737 zoomPtr = &zoomMatrix;
738 }
739
740 SkAutoGlyphCache autoCache(*this, zoomPtr);
741 SkGlyphCache* cache = autoCache.getCache();
742
743 SkScalar width = 0;
744
745 if (length > 0)
746 {
747 int tempCount;
748
749 width = this->measure_text(cache, text, length, &tempCount, bounds);
750 if (scale)
751 {
752 width = SkScalarMul(width, scale);
753 if (bounds)
754 {
755 bounds->fLeft = SkScalarMul(bounds->fLeft, scale);
756 bounds->fTop = SkScalarMul(bounds->fTop, scale);
757 bounds->fRight = SkScalarMul(bounds->fRight, scale);
758 bounds->fBottom = SkScalarMul(bounds->fBottom, scale);
759 }
760 }
761 }
762 return width;
763}
764
765typedef bool (*SkTextBufferPred)(const char* text, const char* stop);
766
767static bool forward_textBufferPred(const char* text, const char* stop)
768{
769 return text < stop;
770}
771
772static bool backward_textBufferPred(const char* text, const char* stop)
773{
774 return text > stop;
775}
776
777static SkTextBufferPred chooseTextBufferPred(SkPaint::TextBufferDirection tbd,
778 const char** text, size_t length, const char** stop)
779{
780 if (SkPaint::kForward_TextBufferDirection == tbd)
781 {
782 *stop = *text + length;
783 return forward_textBufferPred;
784 }
785 else
786 {
787 // text should point to the end of the buffer, and stop to the beginning
788 *stop = *text;
789 *text += length;
790 return backward_textBufferPred;
791 }
792}
793
794size_t SkPaint::breakText(const void* textD, size_t length, SkScalar maxWidth,
795 SkScalar* measuredWidth,
796 TextBufferDirection tbd) const
797{
798 if (0 == length || 0 >= maxWidth)
799 {
800 if (measuredWidth)
801 *measuredWidth = 0;
802 return 0;
803 }
804
805 SkASSERT(textD != NULL);
806 const char* text = (const char*)textD;
807
808 SkScalar scale = 0;
809 SkAutoRestorePaintTextSizeAndFrame restore(this);
810
811 if (this->isLinearText())
812 {
813 scale = fTextSize / kCanonicalTextSizeForPaths;
814 // this gets restored by restore
815 ((SkPaint*)this)->setTextSize(SkIntToScalar(kCanonicalTextSizeForPaths));
816 }
817
818 SkAutoGlyphCache autoCache(*this, NULL);
819 SkGlyphCache* cache = autoCache.getCache();
820
821 SkMeasureCacheProc glyphCacheProc = this->getMeasureCacheProc(tbd, false);
822 const char* stop;
823 SkTextBufferPred pred = chooseTextBufferPred(tbd, &text, length, &stop);
824 SkFixed max = SkScalarToFixed(maxWidth);
825 SkFixed width = 0;
826
827 SkAutoKern autokern;
828
829 if (this->isDevKernText())
830 {
831 int rsb = 0;
832 while (pred(text, stop))
833 {
834 const char* curr = text;
835 const SkGlyph& g = glyphCacheProc(cache, &text);
836 SkFixed x = SkAutoKern_AdjustF(rsb, g.fLsbDelta) + g.fAdvanceX;
837 if ((width += x) > max)
838 {
839 width -= x;
840 text = curr;
841 break;
842 }
843 rsb = g.fRsbDelta;
844 }
845 }
846 else
847 {
848 while (pred(text, stop))
849 {
850 const char* curr = text;
851 SkFixed x = glyphCacheProc(cache, &text).fAdvanceX;
852 if ((width += x) > max)
853 {
854 width -= x;
855 text = curr;
856 break;
857 }
858 }
859 }
860
861 if (measuredWidth)
862 {
863
864 SkScalar scalarWidth = SkFixedToScalar(width);
865 if (scale)
866 scalarWidth = SkScalarMul(scalarWidth, scale);
867 *measuredWidth = scalarWidth;
868 }
869
870 // return the number of bytes measured
871 return (kForward_TextBufferDirection == tbd) ?
872 text - stop + length : stop - text + length;
873}
874
875///////////////////////////////////////////////////////////////////////////////
876
877static bool FontMetricsCacheProc(const SkGlyphCache* cache, void* context)
878{
879 *(SkPaint::FontMetrics*)context = cache->getFontMetricsY();
880 return false; // don't detach the cache
881}
882
883static void FontMetricsDescProc(const SkDescriptor* desc, void* context)
884{
885 SkGlyphCache::VisitCache(desc, FontMetricsCacheProc, context);
886}
887
888SkScalar SkPaint::getFontMetrics(FontMetrics* metrics, SkScalar zoom) const
889{
890 SkScalar scale = 0;
891 SkAutoRestorePaintTextSizeAndFrame restore(this);
892
893 if (this->isLinearText())
894 {
895 scale = fTextSize / kCanonicalTextSizeForPaths;
896 // this gets restored by restore
897 ((SkPaint*)this)->setTextSize(SkIntToScalar(kCanonicalTextSizeForPaths));
898 }
899
900 SkMatrix zoomMatrix, *zoomPtr = NULL;
901 if (zoom)
902 {
903 zoomMatrix.setScale(zoom, zoom);
904 zoomPtr = &zoomMatrix;
905 }
906
907#if 0
908 SkAutoGlyphCache autoCache(*this, zoomPtr);
909 SkGlyphCache* cache = autoCache.getCache();
910 const FontMetrics& my = cache->getFontMetricsY();
911#endif
912 FontMetrics storage;
913 if (NULL == metrics)
914 metrics = &storage;
915
916 this->descriptorProc(zoomPtr, FontMetricsDescProc, metrics);
917
918 if (scale)
919 {
920 metrics->fTop = SkScalarMul(metrics->fTop, scale);
921 metrics->fAscent = SkScalarMul(metrics->fAscent, scale);
922 metrics->fDescent = SkScalarMul(metrics->fDescent, scale);
923 metrics->fBottom = SkScalarMul(metrics->fBottom, scale);
924 metrics->fLeading = SkScalarMul(metrics->fLeading, scale);
925 }
926 return metrics->fDescent - metrics->fAscent + metrics->fLeading;
927}
928
929////////////////////////////////////////////////////////////////////////////////////////////
930
931static void set_bounds(const SkGlyph& g, SkRect* bounds, SkScalar scale)
932{
933 bounds->set(g.fLeft * scale,
934 g.fTop * scale,
935 (g.fLeft + g.fWidth) * scale,
936 (g.fTop + g.fHeight) * scale);
937}
938
939int SkPaint::getTextWidths(const void* textData, size_t byteLength, SkScalar widths[],
940 SkRect bounds[]) const
941{
942 if (0 == byteLength)
943 return 0;
944
945 SkASSERT(NULL != textData);
946
947 if (NULL == widths && NULL == bounds)
948 return this->countText(textData, byteLength);
949
950 SkAutoRestorePaintTextSizeAndFrame restore(this);
951 SkScalar scale = 0;
952
953 if (this->isLinearText())
954 {
955 scale = fTextSize / kCanonicalTextSizeForPaths;
956 // this gets restored by restore
957 ((SkPaint*)this)->setTextSize(SkIntToScalar(kCanonicalTextSizeForPaths));
958 }
959
960 SkAutoGlyphCache autoCache(*this, NULL);
961 SkGlyphCache* cache = autoCache.getCache();
962 SkMeasureCacheProc glyphCacheProc;
963 glyphCacheProc = this->getMeasureCacheProc(kForward_TextBufferDirection,
964 NULL != bounds);
965
966 const char* text = (const char*)textData;
967 const char* stop = text + byteLength;
968 int count = 0;
969
970 if (this->isDevKernText())
971 {
972 // we adjust the widths returned here through auto-kerning
973 SkAutoKern autokern;
974 SkFixed prevWidth = 0;
975
976 if (scale) {
977 while (text < stop) {
978 const SkGlyph& g = glyphCacheProc(cache, &text);
979 if (widths) {
980 SkFixed adjust = autokern.adjust(g);
981
982 if (count > 0) {
983 SkScalar w = SkFixedToScalar(prevWidth + adjust);
984 *widths++ = SkScalarMul(w, scale);
985 }
986 prevWidth = g.fAdvanceX;
987 }
988 if (bounds) {
989 set_bounds(g, bounds++, scale);
990 }
991 ++count;
992 }
993 if (count > 0 && widths) {
994 *widths = SkScalarMul(SkFixedToScalar(prevWidth), scale);
995 }
996 } else {
997 while (text < stop) {
998 const SkGlyph& g = glyphCacheProc(cache, &text);
999 if (widths) {
1000 SkFixed adjust = autokern.adjust(g);
1001
1002 if (count > 0) {
1003 *widths++ = SkFixedToScalar(prevWidth + adjust);
1004 }
1005 prevWidth = g.fAdvanceX;
1006 }
1007 if (bounds) {
1008 set_bounds(g, bounds++);
1009 }
1010 ++count;
1011 }
1012 if (count > 0 && widths) {
1013 *widths = SkFixedToScalar(prevWidth);
1014 }
1015 }
1016 } else { // no devkern
1017 if (scale) {
1018 while (text < stop) {
1019 const SkGlyph& g = glyphCacheProc(cache, &text);
1020 if (widths) {
1021 *widths++ = SkScalarMul(SkFixedToScalar(g.fAdvanceX),
1022 scale);
1023 }
1024 if (bounds) {
1025 set_bounds(g, bounds++, scale);
1026 }
1027 ++count;
1028 }
1029 } else {
1030 while (text < stop) {
1031 const SkGlyph& g = glyphCacheProc(cache, &text);
1032 if (widths) {
1033 *widths++ = SkFixedToScalar(g.fAdvanceX);
1034 }
1035 if (bounds) {
1036 set_bounds(g, bounds++);
1037 }
1038 ++count;
1039 }
1040 }
1041 }
1042
1043 SkASSERT(text == stop);
1044 return count;
1045}
1046
1047////////////////////////////////////////////////////////////////////////////////////////////
1048
1049#include "SkDraw.h"
1050
1051void SkPaint::getTextPath(const void* textData, size_t length, SkScalar x, SkScalar y, SkPath* path) const
1052{
1053 const char* text = (const char*)textData;
1054 SkASSERT(length == 0 || text != NULL);
1055 if (text == NULL || length == 0 || path == NULL)
1056 return;
1057
1058 SkTextToPathIter iter(text, length, *this, false, true);
1059 SkMatrix matrix;
1060 SkScalar prevXPos = 0;
1061
1062 matrix.setScale(iter.getPathScale(), iter.getPathScale());
1063 matrix.postTranslate(x, y);
1064 path->reset();
1065
1066 SkScalar xpos;
1067 const SkPath* iterPath;
1068 while ((iterPath = iter.next(&xpos)) != NULL)
1069 {
1070 matrix.postTranslate(xpos - prevXPos, 0);
1071 path->addPath(*iterPath, matrix);
1072 prevXPos = xpos;
1073 }
1074}
1075
1076static void add_flattenable(SkDescriptor* desc, uint32_t tag,
1077 SkFlattenableWriteBuffer* buffer) {
1078 buffer->flatten(desc->addEntry(tag, buffer->size(), NULL));
1079}
1080
1081/*
1082 * interpolates to find the right value for key, in the function represented by the 'length' number of pairs: (keys[i], values[i])
1083 inspired by a desire to change the multiplier for thickness in fakebold
1084 therefore, i assumed number of pairs (length) will be small, so a linear search is sufficient
1085 repeated keys are allowed for discontinuous functions (so long as keys is monotonically increasing), and if
1086 key is the value of a repeated scalar in keys, the first one will be used
1087 - this may change if a binary search is used
1088 - also, this ensures that there is no divide by zero (an assert also checks for that)
1089*/
1090static SkScalar interpolate(SkScalar key, const SkScalar keys[], const SkScalar values[], int length)
1091{
1092
1093 SkASSERT(length > 0);
1094 SkASSERT(keys != NULL);
1095 SkASSERT(values != NULL);
1096#ifdef SK_DEBUG
1097 for (int i = 1; i < length; i++)
1098 SkASSERT(keys[i] >= keys[i-1]);
1099#endif
1100 int right = 0;
1101 while (right < length && key > keys[right])
1102 right++;
1103 //could use sentinal values to eliminate conditionals
1104 //i assume i am not in control of input values, so i want to make it simple
1105 if (length == right)
1106 return values[length-1];
1107 if (0 == right)
1108 return values[0];
1109 //otherwise, we interpolate between right-1 and right
1110 SkScalar rVal = values[right];
1111 SkScalar lVal = values[right-1];
1112 SkScalar rightKey = keys[right];
1113 SkScalar leftKey = keys[right-1];
1114 SkASSERT(rightKey != leftKey);
1115 //fractional amount which we will multiply by the difference in the left value and right value
1116 SkScalar fract = SkScalarDiv(key-leftKey,rightKey-leftKey);
1117 return lVal + SkScalarMul(fract, rVal-lVal);
1118}
1119
1120//used for interpolating in fakeBold
1121static const SkScalar pointSizes[] = { SkIntToScalar(9), SkIntToScalar(36) };
1122static const SkScalar multipliers[] = { SK_Scalar1/24, SK_Scalar1/32 };
1123
1124static SkMask::Format computeMaskFormat(const SkPaint& paint)
1125{
1126 uint32_t flags = paint.getFlags();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001127
agl@chromium.org309485b2009-07-21 17:41:32 +00001128 if (flags & SkPaint::kLCDRenderText_Flag)
1129#if defined(SK_BUILD_SUBPIXEL)
1130 return SkFontHost::GetSubpixelOrientation() == SkFontHost::kHorizontal_LCDOrientation ?
1131 SkMask::kHorizontalLCD_Format : SkMask::kVerticalLCD_Format;
1132#else
1133 return SkMask::kA8_Format;
1134#endif
1135 if (flags & SkPaint::kAntiAlias_Flag)
1136 return SkMask::kA8_Format;
1137 return SkMask::kBW_Format;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001138}
1139
1140void SkScalerContext::MakeRec(const SkPaint& paint, const SkMatrix* deviceMatrix, Rec* rec)
1141{
1142 SkASSERT(deviceMatrix == NULL || (deviceMatrix->getType() & SkMatrix::kPerspective_Mask) == 0);
1143
1144 rec->fFontID = SkTypeface::UniqueID(paint.getTypeface());
1145 rec->fTextSize = paint.getTextSize();
1146 rec->fPreScaleX = paint.getTextScaleX();
1147 rec->fPreSkewX = paint.getTextSkewX();
1148
1149 if (deviceMatrix)
1150 {
1151 rec->fPost2x2[0][0] = deviceMatrix->getScaleX();
1152 rec->fPost2x2[0][1] = deviceMatrix->getSkewX();
1153 rec->fPost2x2[1][0] = deviceMatrix->getSkewY();
1154 rec->fPost2x2[1][1] = deviceMatrix->getScaleY();
1155 }
1156 else
1157 {
1158 rec->fPost2x2[0][0] = rec->fPost2x2[1][1] = SK_Scalar1;
1159 rec->fPost2x2[0][1] = rec->fPost2x2[1][0] = 0;
1160 }
1161
1162 SkPaint::Style style = paint.getStyle();
1163 SkScalar strokeWidth = paint.getStrokeWidth();
1164
1165 if (paint.isFakeBoldText())
1166 {
1167 SkScalar fakeBoldScale = interpolate(paint.getTextSize(), pointSizes, multipliers, 2);
1168 SkScalar extra = SkScalarMul(paint.getTextSize(), fakeBoldScale);
1169
1170 if (style == SkPaint::kFill_Style)
1171 {
1172 style = SkPaint::kStrokeAndFill_Style;
1173 strokeWidth = extra; // ignore paint's strokeWidth if it was "fill"
1174 }
1175 else
1176 strokeWidth += extra;
1177 }
1178
1179 unsigned flags = SkFontHost::ComputeGammaFlag(paint);
1180
1181 if (paint.isDevKernText())
1182 flags |= SkScalerContext::kDevKernText_Flag;
1183
1184 if (style != SkPaint::kFill_Style && strokeWidth > 0)
1185 {
1186 rec->fFrameWidth = strokeWidth;
1187 rec->fMiterLimit = paint.getStrokeMiter();
1188 rec->fStrokeJoin = SkToU8(paint.getStrokeJoin());
1189
1190 if (style == SkPaint::kStrokeAndFill_Style)
1191 flags |= SkScalerContext::kFrameAndFill_Flag;
1192 }
1193 else
1194 {
1195 rec->fFrameWidth = 0;
1196 rec->fMiterLimit = 0;
1197 rec->fStrokeJoin = 0;
1198 }
1199
agl@chromium.org309485b2009-07-21 17:41:32 +00001200 rec->fSubpixelPositioning = paint.isSubpixelText();
reed@android.com8a1c16f2008-12-17 15:59:43 +00001201 rec->fMaskFormat = SkToU8(computeMaskFormat(paint));
1202 rec->fFlags = SkToU8(flags);
agl@chromium.org309485b2009-07-21 17:41:32 +00001203 rec->setHinting(paint.getHinting());
reed@android.com8a1c16f2008-12-17 15:59:43 +00001204}
1205
1206#define MIN_SIZE_FOR_EFFECT_BUFFER 1024
1207
1208void SkPaint::descriptorProc(const SkMatrix* deviceMatrix,
1209 void (*proc)(const SkDescriptor*, void*),
1210 void* context) const
1211{
1212 SkScalerContext::Rec rec;
1213
1214 SkScalerContext::MakeRec(*this, deviceMatrix, &rec);
1215
1216 size_t descSize = sizeof(rec);
1217 int entryCount = 1;
1218 SkPathEffect* pe = this->getPathEffect();
1219 SkMaskFilter* mf = this->getMaskFilter();
1220 SkRasterizer* ra = this->getRasterizer();
1221
1222 SkFlattenableWriteBuffer peBuffer(MIN_SIZE_FOR_EFFECT_BUFFER);
1223 SkFlattenableWriteBuffer mfBuffer(MIN_SIZE_FOR_EFFECT_BUFFER);
1224 SkFlattenableWriteBuffer raBuffer(MIN_SIZE_FOR_EFFECT_BUFFER);
1225
1226 if (pe) {
1227 peBuffer.writeFlattenable(pe);
1228 descSize += peBuffer.size();
1229 entryCount += 1;
1230 rec.fMaskFormat = SkMask::kA8_Format; // force antialiasing when we do the scan conversion
1231 // seems like we could support kLCD as well at this point...
1232 }
1233 if (mf) {
1234 mfBuffer.writeFlattenable(mf);
1235 descSize += mfBuffer.size();
1236 entryCount += 1;
1237 rec.fMaskFormat = SkMask::kA8_Format; // force antialiasing with maskfilters
1238 }
1239 if (ra) {
1240 raBuffer.writeFlattenable(ra);
1241 descSize += raBuffer.size();
1242 entryCount += 1;
1243 rec.fMaskFormat = SkMask::kA8_Format; // force antialiasing when we do the scan conversion
1244 }
1245 descSize += SkDescriptor::ComputeOverhead(entryCount);
1246
1247 SkAutoDescriptor ad(descSize);
1248 SkDescriptor* desc = ad.getDesc();
1249
1250 desc->init();
1251 desc->addEntry(kRec_SkDescriptorTag, sizeof(rec), &rec);
1252
1253 if (pe) {
1254 add_flattenable(desc, kPathEffect_SkDescriptorTag, &peBuffer);
1255 }
1256 if (mf) {
1257 add_flattenable(desc, kMaskFilter_SkDescriptorTag, &mfBuffer);
1258 }
1259 if (ra) {
1260 add_flattenable(desc, kRasterizer_SkDescriptorTag, &raBuffer);
1261 }
1262
1263 SkASSERT(descSize == desc->getLength());
1264 desc->computeChecksum();
1265
1266 proc(desc, context);
1267}
1268
1269static void DetachDescProc(const SkDescriptor* desc, void* context)
1270{
1271 *((SkGlyphCache**)context) = SkGlyphCache::DetachCache(desc);
1272}
1273
1274SkGlyphCache* SkPaint::detachCache(const SkMatrix* deviceMatrix) const
1275{
1276 SkGlyphCache* cache;
1277 this->descriptorProc(deviceMatrix, DetachDescProc, &cache);
1278 return cache;
1279}
1280
1281///////////////////////////////////////////////////////////////////////////////
1282
1283#include "SkStream.h"
1284
reed@android.comaefd2bc2009-03-30 21:02:14 +00001285static uintptr_t asint(const void* p) {
1286 return reinterpret_cast<uintptr_t>(p);
1287}
1288
1289union Scalar32 {
1290 SkScalar fScalar;
1291 uint32_t f32;
1292};
1293
1294static uint32_t* write_scalar(uint32_t* ptr, SkScalar value) {
1295 SkASSERT(sizeof(SkScalar) == sizeof(uint32_t));
1296 Scalar32 tmp;
1297 tmp.fScalar = value;
1298 *ptr = tmp.f32;
1299 return ptr + 1;
1300}
1301
1302static SkScalar read_scalar(const uint32_t*& ptr) {
1303 SkASSERT(sizeof(SkScalar) == sizeof(uint32_t));
1304 Scalar32 tmp;
1305 tmp.f32 = *ptr++;
1306 return tmp.fScalar;
1307}
1308
1309static uint32_t pack_4(unsigned a, unsigned b, unsigned c, unsigned d) {
1310 SkASSERT(a == (uint8_t)a);
1311 SkASSERT(b == (uint8_t)b);
1312 SkASSERT(c == (uint8_t)c);
1313 SkASSERT(d == (uint8_t)d);
1314 return (a << 24) | (b << 16) | (c << 8) | d;
1315}
1316
1317enum FlatFlags {
1318 kHasTypeface_FlatFlag = 0x01,
1319 kHasEffects_FlatFlag = 0x02
1320};
1321
1322// The size of a flat paint's POD fields
1323static const uint32_t kPODPaintSize = 5 * sizeof(SkScalar) +
1324 1 * sizeof(SkColor) +
1325 1 * sizeof(uint16_t) +
1326 6 * sizeof(uint8_t);
1327
1328/* To save space/time, we analyze the paint, and write a truncated version of
1329 it if there are not tricky elements like shaders, etc.
1330 */
reed@android.com8a1c16f2008-12-17 15:59:43 +00001331void SkPaint::flatten(SkFlattenableWriteBuffer& buffer) const {
reed@android.comaefd2bc2009-03-30 21:02:14 +00001332 uint8_t flatFlags = 0;
1333 if (this->getTypeface()) {
1334 flatFlags |= kHasTypeface_FlatFlag;
1335 }
1336 if (asint(this->getPathEffect()) |
1337 asint(this->getShader()) |
1338 asint(this->getXfermode()) |
1339 asint(this->getMaskFilter()) |
1340 asint(this->getColorFilter()) |
1341 asint(this->getRasterizer()) |
1342 asint(this->getLooper())) {
1343 flatFlags |= kHasEffects_FlatFlag;
1344 }
1345
1346 SkASSERT(SkAlign4(kPODPaintSize) == kPODPaintSize);
1347 uint32_t* ptr = buffer.reserve(kPODPaintSize);
1348
1349 ptr = write_scalar(ptr, this->getTextSize());
1350 ptr = write_scalar(ptr, this->getTextScaleX());
1351 ptr = write_scalar(ptr, this->getTextSkewX());
1352 ptr = write_scalar(ptr, this->getStrokeWidth());
1353 ptr = write_scalar(ptr, this->getStrokeMiter());
1354 *ptr++ = this->getColor();
1355 *ptr++ = (this->getFlags() << 16) | (this->getTextAlign() << 8) | flatFlags;
1356 *ptr++ = pack_4(this->getStrokeCap(), this->getStrokeJoin(),
1357 this->getStyle(), this->getTextEncoding());
1358
1359 // now we're done with ptr and the (pre)reserved space. If we need to write
1360 // additional fields, use the buffer directly
1361 if (flatFlags & kHasTypeface_FlatFlag) {
1362 buffer.writeTypeface(this->getTypeface());
1363 }
1364 if (flatFlags & kHasEffects_FlatFlag) {
1365 buffer.writeFlattenable(this->getPathEffect());
1366 buffer.writeFlattenable(this->getShader());
1367 buffer.writeFlattenable(this->getXfermode());
1368 buffer.writeFlattenable(this->getMaskFilter());
1369 buffer.writeFlattenable(this->getColorFilter());
1370 buffer.writeFlattenable(this->getRasterizer());
1371 buffer.writeFlattenable(this->getLooper());
1372 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001373}
1374
1375void SkPaint::unflatten(SkFlattenableReadBuffer& buffer) {
reed@android.comaefd2bc2009-03-30 21:02:14 +00001376 SkASSERT(SkAlign4(kPODPaintSize) == kPODPaintSize);
1377 const void* podData = buffer.skip(kPODPaintSize);
1378 const uint32_t* pod = reinterpret_cast<const uint32_t*>(podData);
1379
1380 // the order we read must match the order we wrote in flatten()
1381 this->setTextSize(read_scalar(pod));
1382 this->setTextScaleX(read_scalar(pod));
1383 this->setTextSkewX(read_scalar(pod));
1384 this->setStrokeWidth(read_scalar(pod));
1385 this->setStrokeMiter(read_scalar(pod));
1386 this->setColor(*pod++);
1387
1388 uint32_t tmp = *pod++;
1389 this->setFlags(tmp >> 16);
1390 this->setTextAlign(static_cast<Align>((tmp >> 8) & 0xFF));
1391 uint8_t flatFlags = tmp & 0xFF;
1392
1393 tmp = *pod++;
1394 this->setStrokeCap(static_cast<Cap>((tmp >> 24) & 0xFF));
1395 this->setStrokeJoin(static_cast<Join>((tmp >> 16) & 0xFF));
1396 this->setStyle(static_cast<Style>((tmp >> 8) & 0xFF));
1397 this->setTextEncoding(static_cast<TextEncoding>((tmp >> 0) & 0xFF));
1398
1399 if (flatFlags & kHasTypeface_FlatFlag) {
1400 this->setTypeface(buffer.readTypeface());
1401 } else {
1402 this->setTypeface(NULL);
1403 }
1404
1405 if (flatFlags & kHasEffects_FlatFlag) {
1406 this->setPathEffect((SkPathEffect*) buffer.readFlattenable())->safeUnref();
1407 this->setShader((SkShader*) buffer.readFlattenable())->safeUnref();
1408 this->setXfermode((SkXfermode*) buffer.readFlattenable())->safeUnref();
1409 this->setMaskFilter((SkMaskFilter*) buffer.readFlattenable())->safeUnref();
1410 this->setColorFilter((SkColorFilter*) buffer.readFlattenable())->safeUnref();
1411 this->setRasterizer((SkRasterizer*) buffer.readFlattenable())->safeUnref();
1412 this->setLooper((SkDrawLooper*) buffer.readFlattenable())->safeUnref();
1413 } else {
1414 this->setPathEffect(NULL);
1415 this->setShader(NULL);
1416 this->setXfermode(NULL);
1417 this->setMaskFilter(NULL);
1418 this->setColorFilter(NULL);
1419 this->setRasterizer(NULL);
1420 this->setLooper(NULL);
1421 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001422}
1423
1424///////////////////////////////////////////////////////////////////////////////
1425
1426SkShader* SkPaint::setShader(SkShader* shader)
1427{
1428 SkRefCnt_SafeAssign(fShader, shader);
1429 return shader;
1430}
1431
1432SkColorFilter* SkPaint::setColorFilter(SkColorFilter* filter)
1433{
1434 SkRefCnt_SafeAssign(fColorFilter, filter);
1435 return filter;
1436}
1437
1438SkXfermode* SkPaint::setXfermode(SkXfermode* mode)
1439{
1440 SkRefCnt_SafeAssign(fXfermode, mode);
1441 return mode;
1442}
1443
reed@android.com0baf1932009-06-24 12:41:42 +00001444SkXfermode* SkPaint::setXfermodeMode(SkXfermode::Mode mode) {
reed@android.comd66eef72009-06-24 12:29:16 +00001445 SkSafeUnref(fXfermode);
1446 fXfermode = SkXfermode::Create(mode);
1447 return fXfermode;
1448}
1449
reed@android.com8a1c16f2008-12-17 15:59:43 +00001450SkPathEffect* SkPaint::setPathEffect(SkPathEffect* effect)
1451{
1452 SkRefCnt_SafeAssign(fPathEffect, effect);
1453 return effect;
1454}
1455
1456SkMaskFilter* SkPaint::setMaskFilter(SkMaskFilter* filter)
1457{
1458 SkRefCnt_SafeAssign(fMaskFilter, filter);
1459 return filter;
1460}
1461
1462////////////////////////////////////////////////////////////////////////////////////////
1463
1464bool SkPaint::getFillPath(const SkPath& src, SkPath* dst) const
1465{
1466 SkPath effectPath, strokePath;
1467 const SkPath* path = &src;
1468
1469 SkScalar width = this->getStrokeWidth();
1470
1471 switch (this->getStyle()) {
1472 case SkPaint::kFill_Style:
1473 width = -1; // mark it as no-stroke
1474 break;
1475 case SkPaint::kStrokeAndFill_Style:
1476 if (width == 0)
1477 width = -1; // mark it as no-stroke
1478 break;
1479 case SkPaint::kStroke_Style:
1480 break;
1481 default:
1482 SkASSERT(!"unknown paint style");
1483 }
1484
1485 if (this->getPathEffect())
1486 {
1487 // lie to the pathEffect if our style is strokeandfill, so that it treats us as just fill
1488 if (this->getStyle() == SkPaint::kStrokeAndFill_Style)
1489 width = -1; // mark it as no-stroke
1490
1491 if (this->getPathEffect()->filterPath(&effectPath, src, &width))
1492 path = &effectPath;
1493
1494 // restore the width if we earlier had to lie, and if we're still set to no-stroke
1495 // note: if we're now stroke (width >= 0), then the pathEffect asked for that change
1496 // and we want to respect that (i.e. don't overwrite their setting for width)
1497 if (this->getStyle() == SkPaint::kStrokeAndFill_Style && width < 0)
1498 {
1499 width = this->getStrokeWidth();
1500 if (width == 0)
1501 width = -1;
1502 }
1503 }
1504
1505 if (width > 0 && !path->isEmpty())
1506 {
1507 SkStroke stroker(*this, width);
1508 stroker.strokePath(*path, &strokePath);
1509 path = &strokePath;
1510 }
1511
1512 if (path == &src)
1513 *dst = src;
1514 else
1515 {
1516 SkASSERT(path == &effectPath || path == &strokePath);
1517 dst->swap(*(SkPath*)path);
1518 }
1519
1520 return width != 0; // return true if we're filled, or false if we're hairline (width == 0)
1521}
1522
reed@android.comd252db02009-04-01 18:31:44 +00001523const SkRect& SkPaint::computeStrokeFastBounds(const SkRect& src,
1524 SkRect* storage) const {
reed@android.com8a1c16f2008-12-17 15:59:43 +00001525 SkASSERT(storage);
reed@android.comd252db02009-04-01 18:31:44 +00001526 SkASSERT(this->getStyle() != SkPaint::kFill_Style);
1527
1528 // since we're stroked, outset the rect by the radius (and join type)
1529 SkScalar radius = SkScalarHalf(this->getStrokeWidth());
1530 if (0 == radius) { // hairline
1531 radius = SK_Scalar1;
1532 } else if (this->getStrokeJoin() == SkPaint::kMiter_Join) {
1533 SkScalar scale = this->getStrokeMiter();
1534 if (scale > SK_Scalar1) {
1535 radius = SkScalarMul(radius, scale);
reed@android.com8a1c16f2008-12-17 15:59:43 +00001536 }
reed@android.com8a1c16f2008-12-17 15:59:43 +00001537 }
reed@android.comd252db02009-04-01 18:31:44 +00001538 storage->set(src.fLeft - radius, src.fTop - radius,
1539 src.fRight + radius, src.fBottom + radius);
1540 return *storage;
reed@android.com8a1c16f2008-12-17 15:59:43 +00001541}
1542
1543////////////////////////////////////////////////////////////////////////////////////////
1544
1545static bool has_thick_frame(const SkPaint& paint)
1546{
1547 return paint.getStrokeWidth() > 0 && paint.getStyle() != SkPaint::kFill_Style;
1548}
1549
1550SkTextToPathIter::SkTextToPathIter( const char text[], size_t length,
1551 const SkPaint& paint,
1552 bool applyStrokeAndPathEffects,
1553 bool forceLinearTextOn)
1554 : fPaint(paint) /* make a copy of the paint */
1555{
1556 fGlyphCacheProc = paint.getMeasureCacheProc(SkPaint::kForward_TextBufferDirection,
1557 true);
1558
1559 if (forceLinearTextOn)
1560 fPaint.setLinearText(true);
1561 fPaint.setMaskFilter(NULL); // don't want this affecting our path-cache lookup
1562
1563 if (fPaint.getPathEffect() == NULL && !has_thick_frame(fPaint))
1564 applyStrokeAndPathEffects = false;
1565
1566 // can't use our canonical size if we need to apply patheffects/strokes
1567 if (fPaint.isLinearText() && !applyStrokeAndPathEffects)
1568 {
1569 fPaint.setTextSize(SkIntToScalar(SkPaint::kCanonicalTextSizeForPaths));
1570 fScale = paint.getTextSize() / SkPaint::kCanonicalTextSizeForPaths;
1571 }
1572 else
1573 fScale = SK_Scalar1;
1574
1575 if (!applyStrokeAndPathEffects)
1576 {
1577 fPaint.setStyle(SkPaint::kFill_Style);
1578 fPaint.setPathEffect(NULL);
1579 }
1580
1581 fCache = fPaint.detachCache(NULL);
1582
1583 SkPaint::Style style = SkPaint::kFill_Style;
1584 SkPathEffect* pe = NULL;
1585
1586 if (!applyStrokeAndPathEffects)
1587 {
1588 style = paint.getStyle(); // restore
1589 pe = paint.getPathEffect(); // restore
1590 }
1591 fPaint.setStyle(style);
1592 fPaint.setPathEffect(pe);
1593 fPaint.setMaskFilter(paint.getMaskFilter()); // restore
1594
1595 // now compute fXOffset if needed
1596
1597 SkScalar xOffset = 0;
1598 if (paint.getTextAlign() != SkPaint::kLeft_Align) // need to measure first
1599 {
1600 int count;
1601 SkScalar width = SkScalarMul(fPaint.measure_text(fCache, text, length, &count, NULL), fScale);
1602 if (paint.getTextAlign() == SkPaint::kCenter_Align)
1603 width = SkScalarHalf(width);
1604 xOffset = -width;
1605 }
1606 fXPos = xOffset;
1607 fPrevAdvance = 0;
1608
1609 fText = text;
1610 fStop = text + length;
1611}
1612
1613SkTextToPathIter::~SkTextToPathIter()
1614{
1615 SkGlyphCache::AttachCache(fCache);
1616}
1617
1618const SkPath* SkTextToPathIter::next(SkScalar* xpos)
1619{
1620 while (fText < fStop)
1621 {
1622 const SkGlyph& glyph = fGlyphCacheProc(fCache, &fText);
1623
1624 fXPos += SkScalarMul(SkFixedToScalar(fPrevAdvance + fAutoKern.adjust(glyph)), fScale);
1625 fPrevAdvance = glyph.fAdvanceX; // + fPaint.getTextTracking();
1626
1627 if (glyph.fWidth)
1628 {
1629 if (xpos)
1630 *xpos = fXPos;
1631 return fCache->findPath(glyph);
1632 }
1633 }
1634 return NULL;
1635}