1 /* libs/graphics/sgl/SkDraw.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 "SkDraw.h"
19 #include "SkBlitter.h"
20 #include "SkBounder.h"
21 #include "SkCanvas.h"
22 #include "SkColorPriv.h"
23 #include "SkDevice.h"
24 #include "SkMaskFilter.h"
25 #include "SkPaint.h"
26 #include "SkPathEffect.h"
27 #include "SkRasterizer.h"
28 #include "SkScan.h"
29 #include "SkShader.h"
30 #include "SkStroke.h"
31 #include "SkTemplatesPriv.h"
32 #include "SkUtils.h"
33
34 #include "SkAutoKern.h"
35 #include "SkBitmapProcShader.h"
36 #include "SkDrawProcs.h"
37
38 //#define TRACE_BITMAP_DRAWS
39
40 class SkAutoRestoreBounder : SkNoncopyable {
41 public:
42 // note: initializing fBounder is done only to fix a warning
SkAutoRestoreBounder()43 SkAutoRestoreBounder() : fDraw(NULL), fBounder(NULL) {}
~SkAutoRestoreBounder()44 ~SkAutoRestoreBounder() {
45 if (fDraw) {
46 fDraw->fBounder = fBounder;
47 }
48 }
49
clearBounder(const SkDraw * draw)50 void clearBounder(const SkDraw* draw) {
51 fDraw = const_cast<SkDraw*>(draw);
52 fBounder = draw->fBounder;
53 fDraw->fBounder = NULL;
54 }
55
56 private:
57 SkDraw* fDraw;
58 SkBounder* fBounder;
59 };
60
rect_points(SkRect & r,int index)61 static SkPoint* rect_points(SkRect& r, int index) {
62 SkASSERT((unsigned)index < 2);
63 return &((SkPoint*)(void*)&r)[index];
64 }
65
66 /** Helper for allocating small blitters on the stack.
67 */
68
69 #define kBlitterStorageLongCount (sizeof(SkBitmapProcShader) >> 2)
70
71 class SkAutoBlitterChoose {
72 public:
SkAutoBlitterChoose(const SkBitmap & device,const SkMatrix & matrix,const SkPaint & paint)73 SkAutoBlitterChoose(const SkBitmap& device, const SkMatrix& matrix,
74 const SkPaint& paint) {
75 fBlitter = SkBlitter::Choose(device, matrix, paint,
76 fStorage, sizeof(fStorage));
77 }
78 ~SkAutoBlitterChoose();
79
operator ->()80 SkBlitter* operator->() { return fBlitter; }
get() const81 SkBlitter* get() const { return fBlitter; }
82
83 private:
84 SkBlitter* fBlitter;
85 uint32_t fStorage[kBlitterStorageLongCount];
86 };
87
~SkAutoBlitterChoose()88 SkAutoBlitterChoose::~SkAutoBlitterChoose() {
89 if ((void*)fBlitter == (void*)fStorage) {
90 fBlitter->~SkBlitter();
91 } else {
92 SkDELETE(fBlitter);
93 }
94 }
95
96 class SkAutoBitmapShaderInstall {
97 public:
SkAutoBitmapShaderInstall(const SkBitmap & src,const SkPaint * paint)98 SkAutoBitmapShaderInstall(const SkBitmap& src, const SkPaint* paint)
99 : fPaint((SkPaint*)paint) {
100 fPrevShader = paint->getShader();
101 fPrevShader->safeRef();
102 fPaint->setShader(SkShader::CreateBitmapShader( src,
103 SkShader::kClamp_TileMode, SkShader::kClamp_TileMode,
104 fStorage, sizeof(fStorage)));
105 }
~SkAutoBitmapShaderInstall()106 ~SkAutoBitmapShaderInstall() {
107 SkShader* shader = fPaint->getShader();
108
109 fPaint->setShader(fPrevShader);
110 fPrevShader->safeUnref();
111
112 if ((void*)shader == (void*)fStorage) {
113 shader->~SkShader();
114 } else {
115 SkDELETE(shader);
116 }
117 }
118 private:
119 SkPaint* fPaint;
120 SkShader* fPrevShader;
121 uint32_t fStorage[kBlitterStorageLongCount];
122 };
123
124 class SkAutoPaintStyleRestore {
125 public:
SkAutoPaintStyleRestore(const SkPaint & paint,SkPaint::Style style)126 SkAutoPaintStyleRestore(const SkPaint& paint, SkPaint::Style style)
127 : fPaint((SkPaint&)paint) {
128 fStyle = paint.getStyle(); // record the old
129 fPaint.setStyle(style); // change it to the specified style
130 }
~SkAutoPaintStyleRestore()131 ~SkAutoPaintStyleRestore() {
132 fPaint.setStyle(fStyle); // restore the old
133 }
134 private:
135 SkPaint& fPaint;
136 SkPaint::Style fStyle;
137
138 // illegal
139 SkAutoPaintStyleRestore(const SkAutoPaintStyleRestore&);
140 SkAutoPaintStyleRestore& operator=(const SkAutoPaintStyleRestore&);
141 };
142
143 ///////////////////////////////////////////////////////////////////////////////
144
SkDraw(const SkDraw & src)145 SkDraw::SkDraw(const SkDraw& src) {
146 memcpy(this, &src, sizeof(*this));
147 }
148
149 ///////////////////////////////////////////////////////////////////////////////
150
151 typedef void (*BitmapXferProc)(void* pixels, size_t bytes, uint32_t data);
152
D_Clear_BitmapXferProc(void * pixels,size_t bytes,uint32_t)153 static void D_Clear_BitmapXferProc(void* pixels, size_t bytes, uint32_t) {
154 sk_bzero(pixels, bytes);
155 }
156
D_Dst_BitmapXferProc(void *,size_t,uint32_t data)157 static void D_Dst_BitmapXferProc(void*, size_t, uint32_t data) {}
158
D32_Src_BitmapXferProc(void * pixels,size_t bytes,uint32_t data)159 static void D32_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) {
160 sk_memset32((uint32_t*)pixels, data, bytes >> 2);
161 }
162
D16_Src_BitmapXferProc(void * pixels,size_t bytes,uint32_t data)163 static void D16_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) {
164 sk_memset16((uint16_t*)pixels, data, bytes >> 1);
165 }
166
DA8_Src_BitmapXferProc(void * pixels,size_t bytes,uint32_t data)167 static void DA8_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) {
168 memset(pixels, data, bytes);
169 }
170
ChooseBitmapXferProc(const SkBitmap & bitmap,const SkPaint & paint,uint32_t * data)171 static BitmapXferProc ChooseBitmapXferProc(const SkBitmap& bitmap,
172 const SkPaint& paint,
173 uint32_t* data) {
174 // todo: we can apply colorfilter up front if no shader, so we wouldn't
175 // need to abort this fastpath
176 if (paint.getShader() || paint.getColorFilter()) {
177 return NULL;
178 }
179
180 SkXfermode::Mode mode;
181 if (!SkXfermode::IsMode(paint.getXfermode(), &mode)) {
182 return NULL;
183 }
184
185 SkColor color = paint.getColor();
186
187 // collaps modes based on color...
188 if (SkXfermode::kSrcOver_Mode == mode) {
189 unsigned alpha = SkColorGetA(color);
190 if (0 == alpha) {
191 mode = SkXfermode::kDst_Mode;
192 } else if (0xFF == alpha) {
193 mode = SkXfermode::kSrc_Mode;
194 }
195 }
196
197 switch (mode) {
198 case SkXfermode::kClear_Mode:
199 // SkDebugf("--- D_Clear_BitmapXferProc\n");
200 return D_Clear_BitmapXferProc; // ignore data
201 case SkXfermode::kDst_Mode:
202 // SkDebugf("--- D_Dst_BitmapXferProc\n");
203 return D_Dst_BitmapXferProc; // ignore data
204 case SkXfermode::kSrc_Mode: {
205 /*
206 should I worry about dithering for the lower depths?
207 */
208 SkPMColor pmc = SkPreMultiplyColor(color);
209 switch (bitmap.config()) {
210 case SkBitmap::kARGB_8888_Config:
211 if (data) {
212 *data = pmc;
213 }
214 // SkDebugf("--- D32_Src_BitmapXferProc\n");
215 return D32_Src_BitmapXferProc;
216 case SkBitmap::kARGB_4444_Config:
217 if (data) {
218 *data = SkPixel32ToPixel4444(pmc);
219 }
220 // SkDebugf("--- D16_Src_BitmapXferProc\n");
221 return D16_Src_BitmapXferProc;
222 case SkBitmap::kRGB_565_Config:
223 if (data) {
224 *data = SkPixel32ToPixel16(pmc);
225 }
226 // SkDebugf("--- D16_Src_BitmapXferProc\n");
227 return D16_Src_BitmapXferProc;
228 case SkBitmap::kA8_Config:
229 if (data) {
230 *data = SkGetPackedA32(pmc);
231 }
232 // SkDebugf("--- DA8_Src_BitmapXferProc\n");
233 return DA8_Src_BitmapXferProc;
234 default:
235 break;
236 }
237 break;
238 }
239 default:
240 break;
241 }
242 return NULL;
243 }
244
CallBitmapXferProc(const SkBitmap & bitmap,const SkIRect & rect,BitmapXferProc proc,uint32_t procData)245 static void CallBitmapXferProc(const SkBitmap& bitmap, const SkIRect& rect,
246 BitmapXferProc proc, uint32_t procData) {
247 int shiftPerPixel;
248 switch (bitmap.config()) {
249 case SkBitmap::kARGB_8888_Config:
250 shiftPerPixel = 2;
251 break;
252 case SkBitmap::kARGB_4444_Config:
253 case SkBitmap::kRGB_565_Config:
254 shiftPerPixel = 1;
255 break;
256 case SkBitmap::kA8_Config:
257 shiftPerPixel = 0;
258 break;
259 default:
260 SkASSERT(!"Can't use xferproc on this config");
261 return;
262 }
263
264 uint8_t* pixels = (uint8_t*)bitmap.getPixels();
265 SkASSERT(pixels);
266 const size_t rowBytes = bitmap.rowBytes();
267 const int widthBytes = rect.width() << shiftPerPixel;
268
269 // skip down to the first scanline and X position
270 pixels += rect.fTop * rowBytes + (rect.fLeft << shiftPerPixel);
271 for (int scans = rect.height() - 1; scans >= 0; --scans) {
272 proc(pixels, widthBytes, procData);
273 pixels += rowBytes;
274 }
275 }
276
drawPaint(const SkPaint & paint) const277 void SkDraw::drawPaint(const SkPaint& paint) const {
278 SkDEBUGCODE(this->validate();)
279
280 if (fClip->isEmpty()) {
281 return;
282 }
283
284 SkIRect devRect;
285 devRect.set(0, 0, fBitmap->width(), fBitmap->height());
286 if (fBounder && !fBounder->doIRect(devRect)) {
287 return;
288 }
289
290 /* If we don't have a shader (i.e. we're just a solid color) we may
291 be faster to operate directly on the device bitmap, rather than invoking
292 a blitter. Esp. true for xfermodes, which require a colorshader to be
293 present, which is just redundant work. Since we're drawing everywhere
294 in the clip, we don't have to worry about antialiasing.
295 */
296 uint32_t procData = 0; // to avoid the warning
297 BitmapXferProc proc = ChooseBitmapXferProc(*fBitmap, paint, &procData);
298 if (proc) {
299 if (D_Dst_BitmapXferProc == proc) { // nothing to do
300 return;
301 }
302
303 SkRegion::Iterator iter(*fClip);
304 while (!iter.done()) {
305 CallBitmapXferProc(*fBitmap, iter.rect(), proc, procData);
306 iter.next();
307 }
308 } else {
309 // normal case: use a blitter
310 SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint);
311 SkScan::FillIRect(devRect, fClip, blitter.get());
312 }
313 }
314
315 ///////////////////////////////////////////////////////////////////////////////
316
317 struct PtProcRec {
318 SkCanvas::PointMode fMode;
319 const SkPaint* fPaint;
320 const SkRegion* fClip;
321
322 // computed values
323 SkFixed fRadius;
324
325 typedef void (*Proc)(const PtProcRec&, const SkPoint devPts[], int count,
326 SkBlitter*);
327
328 bool init(SkCanvas::PointMode, const SkPaint&, const SkMatrix* matrix,
329 const SkRegion* clip);
330 Proc chooseProc(SkBlitter* blitter);
331 };
332
bw_pt_rect_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)333 static void bw_pt_rect_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
334 int count, SkBlitter* blitter) {
335 SkASSERT(rec.fClip->isRect());
336 const SkIRect& r = rec.fClip->getBounds();
337
338 for (int i = 0; i < count; i++) {
339 int x = SkScalarFloor(devPts[i].fX);
340 int y = SkScalarFloor(devPts[i].fY);
341 if (r.contains(x, y)) {
342 blitter->blitH(x, y, 1);
343 }
344 }
345 }
346
bw_pt_rect_16_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)347 static void bw_pt_rect_16_hair_proc(const PtProcRec& rec,
348 const SkPoint devPts[], int count,
349 SkBlitter* blitter) {
350 SkASSERT(rec.fClip->isRect());
351 const SkIRect& r = rec.fClip->getBounds();
352 uint32_t value;
353 const SkBitmap* bitmap = blitter->justAnOpaqueColor(&value);
354 SkASSERT(bitmap);
355
356 uint16_t* addr = bitmap->getAddr16(0, 0);
357 int rb = bitmap->rowBytes();
358
359 for (int i = 0; i < count; i++) {
360 int x = SkScalarFloor(devPts[i].fX);
361 int y = SkScalarFloor(devPts[i].fY);
362 if (r.contains(x, y)) {
363 // *bitmap->getAddr16(x, y) = SkToU16(value);
364 ((uint16_t*)((char*)addr + y * rb))[x] = SkToU16(value);
365 }
366 }
367 }
368
bw_pt_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)369 static void bw_pt_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
370 int count, SkBlitter* blitter) {
371 for (int i = 0; i < count; i++) {
372 int x = SkScalarFloor(devPts[i].fX);
373 int y = SkScalarFloor(devPts[i].fY);
374 if (rec.fClip->contains(x, y)) {
375 blitter->blitH(x, y, 1);
376 }
377 }
378 }
379
bw_line_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)380 static void bw_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
381 int count, SkBlitter* blitter) {
382 for (int i = 0; i < count; i += 2) {
383 SkScan::HairLine(devPts[i], devPts[i+1], rec.fClip, blitter);
384 }
385 }
386
bw_poly_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)387 static void bw_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
388 int count, SkBlitter* blitter) {
389 for (int i = 0; i < count - 1; i++) {
390 SkScan::HairLine(devPts[i], devPts[i+1], rec.fClip, blitter);
391 }
392 }
393
394 // aa versions
395
aa_line_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)396 static void aa_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
397 int count, SkBlitter* blitter) {
398 for (int i = 0; i < count; i += 2) {
399 SkScan::AntiHairLine(devPts[i], devPts[i+1], rec.fClip, blitter);
400 }
401 }
402
aa_poly_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)403 static void aa_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
404 int count, SkBlitter* blitter) {
405 for (int i = 0; i < count - 1; i++) {
406 SkScan::AntiHairLine(devPts[i], devPts[i+1], rec.fClip, blitter);
407 }
408 }
409
410 // square procs (strokeWidth > 0 but matrix is square-scale (sx == sy)
411
bw_square_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)412 static void bw_square_proc(const PtProcRec& rec, const SkPoint devPts[],
413 int count, SkBlitter* blitter) {
414 const SkFixed radius = rec.fRadius;
415 for (int i = 0; i < count; i++) {
416 SkFixed x = SkScalarToFixed(devPts[i].fX);
417 SkFixed y = SkScalarToFixed(devPts[i].fY);
418
419 SkXRect r;
420 r.fLeft = x - radius;
421 r.fTop = y - radius;
422 r.fRight = x + radius;
423 r.fBottom = y + radius;
424
425 SkScan::FillXRect(r, rec.fClip, blitter);
426 }
427 }
428
aa_square_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)429 static void aa_square_proc(const PtProcRec& rec, const SkPoint devPts[],
430 int count, SkBlitter* blitter) {
431 const SkFixed radius = rec.fRadius;
432 for (int i = 0; i < count; i++) {
433 SkFixed x = SkScalarToFixed(devPts[i].fX);
434 SkFixed y = SkScalarToFixed(devPts[i].fY);
435
436 SkXRect r;
437 r.fLeft = x - radius;
438 r.fTop = y - radius;
439 r.fRight = x + radius;
440 r.fBottom = y + radius;
441
442 SkScan::AntiFillXRect(r, rec.fClip, blitter);
443 }
444 }
445
446 // If this guy returns true, then chooseProc() must return a valid proc
init(SkCanvas::PointMode mode,const SkPaint & paint,const SkMatrix * matrix,const SkRegion * clip)447 bool PtProcRec::init(SkCanvas::PointMode mode, const SkPaint& paint,
448 const SkMatrix* matrix, const SkRegion* clip) {
449 if (paint.getPathEffect()) {
450 return false;
451 }
452 SkScalar width = paint.getStrokeWidth();
453 if (0 == width) {
454 fMode = mode;
455 fPaint = &paint;
456 fClip = clip;
457 fRadius = SK_Fixed1 >> 1;
458 return true;
459 }
460 if (paint.getStrokeCap() != SkPaint::kRound_Cap &&
461 matrix->rectStaysRect() && SkCanvas::kPoints_PointMode == mode) {
462 SkScalar sx = matrix->get(SkMatrix::kMScaleX);
463 SkScalar sy = matrix->get(SkMatrix::kMScaleY);
464 if (SkScalarNearlyZero(sx - sy)) {
465 if (sx < 0) {
466 sx = -sx;
467 }
468
469 fMode = mode;
470 fPaint = &paint;
471 fClip = clip;
472 fRadius = SkScalarToFixed(SkScalarMul(width, sx)) >> 1;
473 return true;
474 }
475 }
476 return false;
477 }
478
chooseProc(SkBlitter * blitter)479 PtProcRec::Proc PtProcRec::chooseProc(SkBlitter* blitter) {
480 Proc proc = NULL;
481
482 // for our arrays
483 SkASSERT(0 == SkCanvas::kPoints_PointMode);
484 SkASSERT(1 == SkCanvas::kLines_PointMode);
485 SkASSERT(2 == SkCanvas::kPolygon_PointMode);
486 SkASSERT((unsigned)fMode <= (unsigned)SkCanvas::kPolygon_PointMode);
487
488 // first check for hairlines
489 if (0 == fPaint->getStrokeWidth()) {
490 if (fPaint->isAntiAlias()) {
491 static const Proc gAAProcs[] = {
492 aa_square_proc, aa_line_hair_proc, aa_poly_hair_proc
493 };
494 proc = gAAProcs[fMode];
495 } else {
496 if (SkCanvas::kPoints_PointMode == fMode && fClip->isRect()) {
497 uint32_t value;
498 const SkBitmap* bm = blitter->justAnOpaqueColor(&value);
499 if (bm && bm->config() == SkBitmap::kRGB_565_Config) {
500 proc = bw_pt_rect_16_hair_proc;
501 } else {
502 proc = bw_pt_rect_hair_proc;
503 }
504 } else {
505 static Proc gBWProcs[] = {
506 bw_pt_hair_proc, bw_line_hair_proc, bw_poly_hair_proc
507 };
508 proc = gBWProcs[fMode];
509 }
510 }
511 } else if (fPaint->getStrokeCap() != SkPaint::kRound_Cap) {
512 SkASSERT(SkCanvas::kPoints_PointMode == fMode);
513 if (fPaint->isAntiAlias()) {
514 proc = aa_square_proc;
515 } else {
516 proc = bw_square_proc;
517 }
518 }
519 return proc;
520 }
521
bounder_points(SkBounder * bounder,SkCanvas::PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint,const SkMatrix & matrix)522 static bool bounder_points(SkBounder* bounder, SkCanvas::PointMode mode,
523 size_t count, const SkPoint pts[],
524 const SkPaint& paint, const SkMatrix& matrix) {
525 SkIRect ibounds;
526 SkRect bounds;
527 SkScalar inset = paint.getStrokeWidth();
528
529 bounds.set(pts, count);
530 bounds.inset(-inset, -inset);
531 matrix.mapRect(&bounds);
532
533 bounds.roundOut(&ibounds);
534 return bounder->doIRect(ibounds);
535 }
536
537 // each of these costs 8-bytes of stack space, so don't make it too large
538 // must be even for lines/polygon to work
539 #define MAX_DEV_PTS 32
540
drawPoints(SkCanvas::PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint) const541 void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count,
542 const SkPoint pts[], const SkPaint& paint) const {
543 // if we're in lines mode, force count to be even
544 if (SkCanvas::kLines_PointMode == mode) {
545 count &= ~(size_t)1;
546 }
547
548 if ((long)count <= 0) {
549 return;
550 }
551
552 SkAutoRestoreBounder arb;
553
554 if (fBounder) {
555 if (!bounder_points(fBounder, mode, count, pts, paint, *fMatrix)) {
556 return;
557 }
558 // clear the bounder for the rest of this function, so we don't call it
559 // again later if we happen to call ourselves for drawRect, drawPath,
560 // etc.
561 arb.clearBounder(this);
562 }
563
564 SkASSERT(pts != NULL);
565 SkDEBUGCODE(this->validate();)
566
567 // nothing to draw
568 if (fClip->isEmpty() ||
569 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
570 return;
571 }
572
573 PtProcRec rec;
574 if (rec.init(mode, paint, fMatrix, fClip)) {
575 SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint);
576
577 SkPoint devPts[MAX_DEV_PTS];
578 const SkMatrix* matrix = fMatrix;
579 SkBlitter* bltr = blitter.get();
580 PtProcRec::Proc proc = rec.chooseProc(bltr);
581 // we have to back up subsequent passes if we're in polygon mode
582 const size_t backup = (SkCanvas::kPolygon_PointMode == mode);
583
584 do {
585 size_t n = count;
586 if (n > MAX_DEV_PTS) {
587 n = MAX_DEV_PTS;
588 }
589 matrix->mapPoints(devPts, pts, n);
590 proc(rec, devPts, n, bltr);
591 pts += n - backup;
592 SkASSERT(count >= n);
593 count -= n;
594 if (count > 0) {
595 count += backup;
596 }
597 } while (count != 0);
598 } else {
599 switch (mode) {
600 case SkCanvas::kPoints_PointMode: {
601 // temporarily mark the paint as filling.
602 SkAutoPaintStyleRestore restore(paint, SkPaint::kFill_Style);
603
604 SkScalar width = paint.getStrokeWidth();
605 SkScalar radius = SkScalarHalf(width);
606
607 if (paint.getStrokeCap() == SkPaint::kRound_Cap) {
608 SkPath path;
609 SkMatrix preMatrix;
610
611 path.addCircle(0, 0, radius);
612 for (size_t i = 0; i < count; i++) {
613 preMatrix.setTranslate(pts[i].fX, pts[i].fY);
614 // pass true for the last point, since we can modify
615 // then path then
616 this->drawPath(path, paint, &preMatrix, (count-1) == i);
617 }
618 } else {
619 SkRect r;
620
621 for (size_t i = 0; i < count; i++) {
622 r.fLeft = pts[i].fX - radius;
623 r.fTop = pts[i].fY - radius;
624 r.fRight = r.fLeft + width;
625 r.fBottom = r.fTop + width;
626 this->drawRect(r, paint);
627 }
628 }
629 break;
630 }
631 case SkCanvas::kLines_PointMode:
632 case SkCanvas::kPolygon_PointMode: {
633 count -= 1;
634 SkPath path;
635 SkPaint p(paint);
636 p.setStyle(SkPaint::kStroke_Style);
637 size_t inc = (SkCanvas::kLines_PointMode == mode) ? 2 : 1;
638 for (size_t i = 0; i < count; i += inc) {
639 path.moveTo(pts[i]);
640 path.lineTo(pts[i+1]);
641 this->drawPath(path, p, NULL, true);
642 path.rewind();
643 }
644 break;
645 }
646 }
647 }
648 }
649
as_lefttop(SkRect * r)650 static inline SkPoint* as_lefttop(SkRect* r) {
651 return (SkPoint*)(void*)r;
652 }
653
as_rightbottom(SkRect * r)654 static inline SkPoint* as_rightbottom(SkRect* r) {
655 return ((SkPoint*)(void*)r) + 1;
656 }
657
drawRect(const SkRect & rect,const SkPaint & paint) const658 void SkDraw::drawRect(const SkRect& rect, const SkPaint& paint) const {
659 SkDEBUGCODE(this->validate();)
660
661 // nothing to draw
662 if (fClip->isEmpty() ||
663 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
664 return;
665 }
666
667 // complex enough to draw as a path
668 if (paint.getPathEffect() || paint.getMaskFilter() ||
669 paint.getRasterizer() || !fMatrix->rectStaysRect() ||
670 (paint.getStyle() != SkPaint::kFill_Style &&
671 SkScalarHalf(paint.getStrokeWidth()) > 0)) {
672 SkPath tmp;
673 tmp.addRect(rect);
674 tmp.setFillType(SkPath::kWinding_FillType);
675 this->drawPath(tmp, paint, NULL, true);
676 return;
677 }
678
679 const SkMatrix& matrix = *fMatrix;
680 SkRect devRect;
681
682 // transform rect into devRect
683 {
684 matrix.mapXY(rect.fLeft, rect.fTop, rect_points(devRect, 0));
685 matrix.mapXY(rect.fRight, rect.fBottom, rect_points(devRect, 1));
686 devRect.sort();
687 }
688
689 if (fBounder && !fBounder->doRect(devRect, paint)) {
690 return;
691 }
692
693 // look for the quick exit, before we build a blitter
694 {
695 SkIRect ir;
696 devRect.roundOut(&ir);
697 if (fClip->quickReject(ir))
698 return;
699 }
700
701 SkAutoBlitterChoose blitterStorage(*fBitmap, matrix, paint);
702 SkBlitter* blitter = blitterStorage.get();
703 const SkRegion* clip = fClip;
704
705 if (paint.getStyle() == SkPaint::kFill_Style) {
706 if (paint.isAntiAlias()) {
707 SkScan::AntiFillRect(devRect, clip, blitter);
708 } else {
709 SkScan::FillRect(devRect, clip, blitter);
710 }
711 } else {
712 if (paint.isAntiAlias()) {
713 SkScan::AntiHairRect(devRect, clip, blitter);
714 } else {
715 SkScan::HairRect(devRect, clip, blitter);
716 }
717 }
718 }
719
drawDevMask(const SkMask & srcM,const SkPaint & paint) const720 void SkDraw::drawDevMask(const SkMask& srcM, const SkPaint& paint) const {
721 if (srcM.fBounds.isEmpty()) {
722 return;
723 }
724
725 SkMask dstM;
726 const SkMask* mask = &srcM;
727
728 dstM.fImage = NULL;
729 SkAutoMaskImage ami(&dstM, false);
730
731 if (paint.getMaskFilter() &&
732 paint.getMaskFilter()->filterMask(&dstM, srcM, *fMatrix, NULL)) {
733 mask = &dstM;
734 }
735
736 if (fBounder && !fBounder->doIRect(mask->fBounds)) {
737 return;
738 }
739
740 SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint);
741
742 blitter->blitMaskRegion(*mask, *fClip);
743 }
744
745 class SkAutoPaintRestoreColorStrokeWidth {
746 public:
SkAutoPaintRestoreColorStrokeWidth(const SkPaint & paint)747 SkAutoPaintRestoreColorStrokeWidth(const SkPaint& paint) {
748 fPaint = (SkPaint*)&paint;
749 fColor = paint.getColor();
750 fWidth = paint.getStrokeWidth();
751 }
~SkAutoPaintRestoreColorStrokeWidth()752 ~SkAutoPaintRestoreColorStrokeWidth() {
753 fPaint->setColor(fColor);
754 fPaint->setStrokeWidth(fWidth);
755 }
756
757 private:
758 SkPaint* fPaint;
759 SkColor fColor;
760 SkScalar fWidth;
761 };
762
fast_len(const SkVector & vec)763 static SkScalar fast_len(const SkVector& vec) {
764 SkScalar x = SkScalarAbs(vec.fX);
765 SkScalar y = SkScalarAbs(vec.fY);
766 if (x < y) {
767 SkTSwap(x, y);
768 }
769 return x + SkScalarHalf(y);
770 }
771
772 // our idea is to return true if there is no appreciable skew or non-square scale
773 // for that we'll transform (0,1) and (1,0), and check that the resulting dot-prod
774 // is nearly one
map_radius(const SkMatrix & matrix,SkScalar * value)775 static bool map_radius(const SkMatrix& matrix, SkScalar* value) {
776 if (matrix.getType() & SkMatrix::kPerspective_Mask) {
777 return false;
778 }
779 SkVector src[2], dst[2];
780 src[0].set(*value, 0);
781 src[1].set(0, *value);
782 matrix.mapVectors(dst, src, 2);
783 SkScalar len0 = fast_len(dst[0]);
784 SkScalar len1 = fast_len(dst[1]);
785 if (len0 < SK_Scalar1 && len1 < SK_Scalar1) {
786 *value = SkScalarAve(len0, len1);
787 return true;
788 }
789 return false;
790 }
791
drawPath(const SkPath & origSrcPath,const SkPaint & paint,const SkMatrix * prePathMatrix,bool pathIsMutable) const792 void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& paint,
793 const SkMatrix* prePathMatrix, bool pathIsMutable) const {
794 SkDEBUGCODE(this->validate();)
795
796 // nothing to draw
797 if (fClip->isEmpty() ||
798 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
799 return;
800 }
801
802 SkPath* pathPtr = (SkPath*)&origSrcPath;
803 bool doFill = true;
804 SkPath tmpPath;
805 SkMatrix tmpMatrix;
806 const SkMatrix* matrix = fMatrix;
807
808 if (prePathMatrix) {
809 if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style ||
810 paint.getRasterizer()) {
811 SkPath* result = pathPtr;
812
813 if (!pathIsMutable) {
814 result = &tmpPath;
815 pathIsMutable = true;
816 }
817 pathPtr->transform(*prePathMatrix, result);
818 pathPtr = result;
819 } else {
820 if (!tmpMatrix.setConcat(*matrix, *prePathMatrix)) {
821 // overflow
822 return;
823 }
824 matrix = &tmpMatrix;
825 }
826 }
827 // at this point we're done with prePathMatrix
828 SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
829
830 /*
831 If the device thickness < 1.0, then make it a hairline, and
832 modulate alpha if the thickness is even smaller (e.g. thickness == 0.5
833 should modulate the alpha by 1/2)
834 */
835
836 SkAutoPaintRestoreColorStrokeWidth aprc(paint);
837
838 // can we approximate a thin (but not hairline) stroke with an alpha-modulated
839 // hairline? Only if the matrix scales evenly in X and Y, and the device-width is
840 // less than a pixel
841 if (paint.getStyle() == SkPaint::kStroke_Style && paint.getXfermode() == NULL) {
842 SkScalar width = paint.getStrokeWidth();
843 if (width > 0 && map_radius(*matrix, &width)) {
844 int scale = (int)SkScalarMul(width, 256);
845 int alpha = paint.getAlpha() * scale >> 8;
846
847 // pretend to be a hairline, with a modulated alpha
848 ((SkPaint*)&paint)->setAlpha(alpha);
849 ((SkPaint*)&paint)->setStrokeWidth(0);
850 }
851 }
852
853 if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) {
854 doFill = paint.getFillPath(*pathPtr, &tmpPath);
855 pathPtr = &tmpPath;
856 }
857
858 if (paint.getRasterizer()) {
859 SkMask mask;
860 if (paint.getRasterizer()->rasterize(*pathPtr, *matrix,
861 &fClip->getBounds(), paint.getMaskFilter(), &mask,
862 SkMask::kComputeBoundsAndRenderImage_CreateMode)) {
863 this->drawDevMask(mask, paint);
864 SkMask::FreeImage(mask.fImage);
865 }
866 return;
867 }
868
869 // avoid possibly allocating a new path in transform if we can
870 SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
871
872 // transform the path into device space
873 pathPtr->transform(*matrix, devPathPtr);
874
875 SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint);
876
877 // how does filterPath() know to fill or hairline the path??? <mrr>
878 if (paint.getMaskFilter() &&
879 paint.getMaskFilter()->filterPath(*devPathPtr, *fMatrix, *fClip,
880 fBounder, blitter.get())) {
881 return; // filterPath() called the blitter, so we're done
882 }
883
884 if (fBounder && !fBounder->doPath(*devPathPtr, paint, doFill)) {
885 return;
886 }
887
888 if (doFill) {
889 if (paint.isAntiAlias()) {
890 SkScan::AntiFillPath(*devPathPtr, *fClip, blitter.get());
891 } else {
892 SkScan::FillPath(*devPathPtr, *fClip, blitter.get());
893 }
894 } else { // hairline
895 if (paint.isAntiAlias()) {
896 SkScan::AntiHairPath(*devPathPtr, fClip, blitter.get());
897 } else {
898 SkScan::HairPath(*devPathPtr, fClip, blitter.get());
899 }
900 }
901 }
902
903 /** For the purposes of drawing bitmaps, if a matrix is "almost" translate
904 go ahead and treat it as if it were, so that subsequent code can go fast.
905 */
just_translate(const SkMatrix & matrix,const SkBitmap & bitmap)906 static bool just_translate(const SkMatrix& matrix, const SkBitmap& bitmap) {
907 SkMatrix::TypeMask mask = matrix.getType();
908
909 if (mask & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)) {
910 return false;
911 }
912 if (mask & SkMatrix::kScale_Mask) {
913 SkScalar sx = matrix[SkMatrix::kMScaleX];
914 SkScalar sy = matrix[SkMatrix::kMScaleY];
915 int w = bitmap.width();
916 int h = bitmap.height();
917 int sw = SkScalarRound(SkScalarMul(sx, SkIntToScalar(w)));
918 int sh = SkScalarRound(SkScalarMul(sy, SkIntToScalar(h)));
919 return sw == w && sh == h;
920 }
921 // if we got here, we're either kTranslate_Mask or identity
922 return true;
923 }
924
drawBitmapAsMask(const SkBitmap & bitmap,const SkPaint & paint) const925 void SkDraw::drawBitmapAsMask(const SkBitmap& bitmap,
926 const SkPaint& paint) const {
927 SkASSERT(bitmap.getConfig() == SkBitmap::kA8_Config);
928
929 if (just_translate(*fMatrix, bitmap)) {
930 int ix = SkScalarRound(fMatrix->getTranslateX());
931 int iy = SkScalarRound(fMatrix->getTranslateY());
932
933 SkMask mask;
934 mask.fBounds.set(ix, iy, ix + bitmap.width(), iy + bitmap.height());
935 mask.fFormat = SkMask::kA8_Format;
936 mask.fRowBytes = bitmap.rowBytes();
937 mask.fImage = bitmap.getAddr8(0, 0);
938
939 this->drawDevMask(mask, paint);
940 } else { // need to xform the bitmap first
941 SkRect r;
942 SkMask mask;
943
944 r.set(0, 0,
945 SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height()));
946 fMatrix->mapRect(&r);
947 r.round(&mask.fBounds);
948
949 // set the mask's bounds to the transformed bitmap-bounds,
950 // clipped to the actual device
951 {
952 SkIRect devBounds;
953 devBounds.set(0, 0, fBitmap->width(), fBitmap->height());
954 // need intersect(l, t, r, b) on irect
955 if (!mask.fBounds.intersect(devBounds)) {
956 return;
957 }
958 }
959
960 mask.fFormat = SkMask::kA8_Format;
961 mask.fRowBytes = SkAlign4(mask.fBounds.width());
962 size_t size = mask.computeImageSize();
963 if (0 == size) {
964 // the mask is too big to allocated, draw nothing
965 return;
966 }
967
968 // allocate (and clear) our temp buffer to hold the transformed bitmap
969 SkAutoMalloc storage(size);
970 mask.fImage = (uint8_t*)storage.get();
971 memset(mask.fImage, 0, size);
972
973 // now draw our bitmap(src) into mask(dst), transformed by the matrix
974 {
975 SkBitmap device;
976 device.setConfig(SkBitmap::kA8_Config, mask.fBounds.width(),
977 mask.fBounds.height(), mask.fRowBytes);
978 device.setPixels(mask.fImage);
979
980 SkCanvas c(device);
981 // need the unclipped top/left for the translate
982 c.translate(-SkIntToScalar(mask.fBounds.fLeft),
983 -SkIntToScalar(mask.fBounds.fTop));
984 c.concat(*fMatrix);
985
986 // We can't call drawBitmap, or we'll infinitely recurse. Instead
987 // we manually build a shader and draw that into our new mask
988 SkPaint tmpPaint;
989 tmpPaint.setFlags(paint.getFlags());
990 SkAutoBitmapShaderInstall install(bitmap, &tmpPaint);
991 SkRect rr;
992 rr.set(0, 0, SkIntToScalar(bitmap.width()),
993 SkIntToScalar(bitmap.height()));
994 c.drawRect(rr, tmpPaint);
995 }
996 this->drawDevMask(mask, paint);
997 }
998 }
999
clipped_out(const SkMatrix & m,const SkRegion & c,const SkRect & srcR)1000 static bool clipped_out(const SkMatrix& m, const SkRegion& c,
1001 const SkRect& srcR) {
1002 SkRect dstR;
1003 SkIRect devIR;
1004
1005 m.mapRect(&dstR, srcR);
1006 dstR.roundOut(&devIR);
1007 return c.quickReject(devIR);
1008 }
1009
clipped_out(const SkMatrix & matrix,const SkRegion & clip,int width,int height)1010 static bool clipped_out(const SkMatrix& matrix, const SkRegion& clip,
1011 int width, int height) {
1012 SkRect r;
1013 r.set(0, 0, SkIntToScalar(width), SkIntToScalar(height));
1014 return clipped_out(matrix, clip, r);
1015 }
1016
drawBitmap(const SkBitmap & bitmap,const SkMatrix & prematrix,const SkPaint & paint) const1017 void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix,
1018 const SkPaint& paint) const {
1019 SkDEBUGCODE(this->validate();)
1020
1021 // nothing to draw
1022 if (fClip->isEmpty() ||
1023 bitmap.width() == 0 || bitmap.height() == 0 ||
1024 bitmap.getConfig() == SkBitmap::kNo_Config ||
1025 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
1026 return;
1027 }
1028
1029 // run away on too-big bitmaps for now (exceed 16.16)
1030 if (bitmap.width() > 32767 || bitmap.height() > 32767) {
1031 return;
1032 }
1033
1034 SkAutoPaintStyleRestore restore(paint, SkPaint::kFill_Style);
1035
1036 SkMatrix matrix;
1037 if (!matrix.setConcat(*fMatrix, prematrix)) {
1038 return;
1039 }
1040
1041 // do I need to call the bounder first???
1042 if (clipped_out(matrix, *fClip, bitmap.width(), bitmap.height())) {
1043 return;
1044 }
1045
1046 // only lock the pixels if we passed the clip test
1047 SkAutoLockPixels alp(bitmap);
1048 // after the lock, check if we are valid
1049 if (!bitmap.readyToDraw()) {
1050 return;
1051 }
1052
1053 if (bitmap.getConfig() != SkBitmap::kA8_Config &&
1054 just_translate(matrix, bitmap)) {
1055 int ix = SkScalarRound(matrix.getTranslateX());
1056 int iy = SkScalarRound(matrix.getTranslateY());
1057 uint32_t storage[kBlitterStorageLongCount];
1058 SkBlitter* blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap,
1059 ix, iy, storage, sizeof(storage));
1060 if (blitter) {
1061 SkAutoTPlacementDelete<SkBlitter> ad(blitter, storage);
1062
1063 SkIRect ir;
1064 ir.set(ix, iy, ix + bitmap.width(), iy + bitmap.height());
1065
1066 if (fBounder && !fBounder->doIRect(ir)) {
1067 return;
1068 }
1069
1070 SkRegion::Cliperator iter(*fClip, ir);
1071 const SkIRect& cr = iter.rect();
1072
1073 for (; !iter.done(); iter.next()) {
1074 SkASSERT(!cr.isEmpty());
1075 blitter->blitRect(cr.fLeft, cr.fTop, cr.width(), cr.height());
1076 }
1077 return;
1078 }
1079 #if 0
1080 SkDebugf("---- MISSING sprite case: config=%d [%d %d], device=%d, xfer=%p, alpha=0x%X colorFilter=%p\n",
1081 bitmap.config(), bitmap.width(), bitmap.height(), fBitmap->config(),
1082 paint.getXfermode(), paint.getAlpha(), paint.getColorFilter());
1083 #endif
1084 }
1085
1086 // now make a temp draw on the stack, and use it
1087 //
1088 SkDraw draw(*this);
1089 draw.fMatrix = &matrix;
1090
1091 if (bitmap.getConfig() == SkBitmap::kA8_Config) {
1092 draw.drawBitmapAsMask(bitmap, paint);
1093 } else {
1094 SkAutoBitmapShaderInstall install(bitmap, &paint);
1095
1096 SkRect r;
1097 r.set(0, 0, SkIntToScalar(bitmap.width()),
1098 SkIntToScalar(bitmap.height()));
1099 // is this ok if paint has a rasterizer?
1100 draw.drawRect(r, paint);
1101 }
1102 }
1103
drawSprite(const SkBitmap & bitmap,int x,int y,const SkPaint & paint) const1104 void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y,
1105 const SkPaint& paint) const {
1106 SkDEBUGCODE(this->validate();)
1107
1108 // nothing to draw
1109 if (fClip->isEmpty() ||
1110 bitmap.width() == 0 || bitmap.height() == 0 ||
1111 bitmap.getConfig() == SkBitmap::kNo_Config ||
1112 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
1113 return;
1114 }
1115
1116 SkIRect bounds;
1117 bounds.set(x, y, x + bitmap.width(), y + bitmap.height());
1118
1119 if (fClip->quickReject(bounds)) {
1120 return; // nothing to draw
1121 }
1122
1123 SkAutoPaintStyleRestore restore(paint, SkPaint::kFill_Style);
1124
1125 if (NULL == paint.getColorFilter()) {
1126 uint32_t storage[kBlitterStorageLongCount];
1127 SkBlitter* blitter = SkBlitter::ChooseSprite(*fBitmap, paint, bitmap,
1128 x, y, storage, sizeof(storage));
1129
1130 if (blitter) {
1131 SkAutoTPlacementDelete<SkBlitter> ad(blitter, storage);
1132
1133 if (fBounder && !fBounder->doIRect(bounds)) {
1134 return;
1135 }
1136
1137 SkRegion::Cliperator iter(*fClip, bounds);
1138 const SkIRect& cr = iter.rect();
1139
1140 for (; !iter.done(); iter.next()) {
1141 SkASSERT(!cr.isEmpty());
1142 blitter->blitRect(cr.fLeft, cr.fTop, cr.width(), cr.height());
1143 }
1144 return;
1145 }
1146 }
1147
1148 SkAutoBitmapShaderInstall install(bitmap, &paint);
1149
1150 SkMatrix matrix;
1151 SkRect r;
1152
1153 // get a scalar version of our rect
1154 r.set(bounds);
1155
1156 // tell the shader our offset
1157 matrix.setTranslate(r.fLeft, r.fTop);
1158 paint.getShader()->setLocalMatrix(matrix);
1159
1160 SkDraw draw(*this);
1161 matrix.reset();
1162 draw.fMatrix = &matrix;
1163 // call ourself with a rect
1164 // is this OK if paint has a rasterizer?
1165 draw.drawRect(r, paint);
1166 }
1167
1168 ///////////////////////////////////////////////////////////////////////////////
1169
1170 #include "SkScalerContext.h"
1171 #include "SkGlyphCache.h"
1172 #include "SkUtils.h"
1173
measure_text(SkGlyphCache * cache,SkDrawCacheProc glyphCacheProc,const char text[],size_t byteLength,SkVector * stopVector)1174 static void measure_text(SkGlyphCache* cache, SkDrawCacheProc glyphCacheProc,
1175 const char text[], size_t byteLength, SkVector* stopVector) {
1176 SkFixed x = 0, y = 0;
1177 const char* stop = text + byteLength;
1178
1179 SkAutoKern autokern;
1180
1181 while (text < stop) {
1182 // don't need x, y here, since all subpixel variants will have the
1183 // same advance
1184 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
1185
1186 x += autokern.adjust(glyph) + glyph.fAdvanceX;
1187 y += glyph.fAdvanceY;
1188 }
1189 stopVector->set(SkFixedToScalar(x), SkFixedToScalar(y));
1190
1191 SkASSERT(text == stop);
1192 }
1193
drawText_asPaths(const char text[],size_t byteLength,SkScalar x,SkScalar y,const SkPaint & paint) const1194 void SkDraw::drawText_asPaths(const char text[], size_t byteLength,
1195 SkScalar x, SkScalar y,
1196 const SkPaint& paint) const {
1197 SkDEBUGCODE(this->validate();)
1198
1199 SkTextToPathIter iter(text, byteLength, paint, true, true);
1200
1201 SkMatrix matrix;
1202 matrix.setScale(iter.getPathScale(), iter.getPathScale());
1203 matrix.postTranslate(x, y);
1204
1205 const SkPath* iterPath;
1206 SkScalar xpos, prevXPos = 0;
1207
1208 while ((iterPath = iter.next(&xpos)) != NULL) {
1209 matrix.postTranslate(xpos - prevXPos, 0);
1210 this->drawPath(*iterPath, iter.getPaint(), &matrix, false);
1211 prevXPos = xpos;
1212 }
1213 }
1214
1215 #define kStdStrikeThru_Offset (-SK_Scalar1 * 6 / 21)
1216 #define kStdUnderline_Offset (SK_Scalar1 / 9)
1217 #define kStdUnderline_Thickness (SK_Scalar1 / 18)
1218
draw_paint_rect(const SkDraw * draw,const SkPaint & paint,const SkRect & r,SkScalar textSize)1219 static void draw_paint_rect(const SkDraw* draw, const SkPaint& paint,
1220 const SkRect& r, SkScalar textSize) {
1221 if (paint.getStyle() == SkPaint::kFill_Style) {
1222 draw->drawRect(r, paint);
1223 } else {
1224 SkPaint p(paint);
1225 p.setStrokeWidth(SkScalarMul(textSize, paint.getStrokeWidth()));
1226 draw->drawRect(r, p);
1227 }
1228 }
1229
handle_aftertext(const SkDraw * draw,const SkPaint & paint,SkScalar width,const SkPoint & start)1230 static void handle_aftertext(const SkDraw* draw, const SkPaint& paint,
1231 SkScalar width, const SkPoint& start) {
1232 uint32_t flags = paint.getFlags();
1233
1234 if (flags & (SkPaint::kUnderlineText_Flag |
1235 SkPaint::kStrikeThruText_Flag)) {
1236 SkScalar textSize = paint.getTextSize();
1237 SkScalar height = SkScalarMul(textSize, kStdUnderline_Thickness);
1238 SkRect r;
1239
1240 r.fLeft = start.fX;
1241 r.fRight = start.fX + width;
1242
1243 if (flags & SkPaint::kUnderlineText_Flag) {
1244 SkScalar offset = SkScalarMulAdd(textSize, kStdUnderline_Offset,
1245 start.fY);
1246 r.fTop = offset;
1247 r.fBottom = offset + height;
1248 draw_paint_rect(draw, paint, r, textSize);
1249 }
1250 if (flags & SkPaint::kStrikeThruText_Flag) {
1251 SkScalar offset = SkScalarMulAdd(textSize, kStdStrikeThru_Offset,
1252 start.fY);
1253 r.fTop = offset;
1254 r.fBottom = offset + height;
1255 draw_paint_rect(draw, paint, r, textSize);
1256 }
1257 }
1258 }
1259
1260 // disable warning : local variable used without having been initialized
1261 #if defined _WIN32 && _MSC_VER >= 1300
1262 #pragma warning ( push )
1263 #pragma warning ( disable : 4701 )
1264 #endif
1265
1266 //////////////////////////////////////////////////////////////////////////////
1267
D1G_NoBounder_RectClip(const SkDraw1Glyph & state,const SkGlyph & glyph,int left,int top)1268 static void D1G_NoBounder_RectClip(const SkDraw1Glyph& state,
1269 const SkGlyph& glyph, int left, int top) {
1270 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1271 SkASSERT(state.fClip->isRect());
1272 SkASSERT(NULL == state.fBounder);
1273 SkASSERT(state.fClipBounds == state.fClip->getBounds());
1274
1275 left += glyph.fLeft;
1276 top += glyph.fTop;
1277
1278 int right = left + glyph.fWidth;
1279 int bottom = top + glyph.fHeight;
1280
1281 SkMask mask;
1282 SkIRect storage;
1283 SkIRect* bounds = &mask.fBounds;
1284
1285 mask.fBounds.set(left, top, right, bottom);
1286
1287 // this extra test is worth it, assuming that most of the time it succeeds
1288 // since we can avoid writing to storage
1289 if (!state.fClipBounds.containsNoEmptyCheck(left, top, right, bottom)) {
1290 if (!storage.intersectNoEmptyCheck(mask.fBounds, state.fClipBounds))
1291 return;
1292 bounds = &storage;
1293 }
1294
1295 uint8_t* aa = (uint8_t*)glyph.fImage;
1296 if (NULL == aa) {
1297 aa = (uint8_t*)state.fCache->findImage(glyph);
1298 if (NULL == aa) {
1299 return; // can't rasterize glyph
1300 }
1301 }
1302
1303 mask.fRowBytes = glyph.rowBytes();
1304 mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
1305 mask.fImage = aa;
1306 state.fBlitter->blitMask(mask, *bounds);
1307 }
1308
D1G_NoBounder_RgnClip(const SkDraw1Glyph & state,const SkGlyph & glyph,int left,int top)1309 static void D1G_NoBounder_RgnClip(const SkDraw1Glyph& state,
1310 const SkGlyph& glyph, int left, int top) {
1311 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1312 SkASSERT(!state.fClip->isRect());
1313 SkASSERT(NULL == state.fBounder);
1314
1315 SkMask mask;
1316
1317 left += glyph.fLeft;
1318 top += glyph.fTop;
1319
1320 mask.fBounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight);
1321 SkRegion::Cliperator clipper(*state.fClip, mask.fBounds);
1322
1323 if (!clipper.done()) {
1324 const SkIRect& cr = clipper.rect();
1325 const uint8_t* aa = (const uint8_t*)glyph.fImage;
1326 if (NULL == aa) {
1327 aa = (uint8_t*)state.fCache->findImage(glyph);
1328 if (NULL == aa) {
1329 return;
1330 }
1331 }
1332
1333 mask.fRowBytes = glyph.rowBytes();
1334 mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
1335 mask.fImage = (uint8_t*)aa;
1336 do {
1337 state.fBlitter->blitMask(mask, cr);
1338 clipper.next();
1339 } while (!clipper.done());
1340 }
1341 }
1342
D1G_Bounder(const SkDraw1Glyph & state,const SkGlyph & glyph,int left,int top)1343 static void D1G_Bounder(const SkDraw1Glyph& state,
1344 const SkGlyph& glyph, int left, int top) {
1345 SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1346
1347 SkMask mask;
1348
1349 left += glyph.fLeft;
1350 top += glyph.fTop;
1351
1352 mask.fBounds.set(left, top, left + glyph.fWidth, top + glyph.fHeight);
1353 SkRegion::Cliperator clipper(*state.fClip, mask.fBounds);
1354
1355 if (!clipper.done()) {
1356 const SkIRect& cr = clipper.rect();
1357 const uint8_t* aa = (const uint8_t*)glyph.fImage;
1358 if (NULL == aa) {
1359 aa = (uint8_t*)state.fCache->findImage(glyph);
1360 if (NULL == aa) {
1361 return;
1362 }
1363 }
1364
1365 if (state.fBounder->doIRect(cr)) {
1366 mask.fRowBytes = glyph.rowBytes();
1367 mask.fFormat = static_cast<SkMask::Format>(glyph.fMaskFormat);
1368 mask.fImage = (uint8_t*)aa;
1369 do {
1370 state.fBlitter->blitMask(mask, cr);
1371 clipper.next();
1372 } while (!clipper.done());
1373 }
1374 }
1375 }
1376
init(const SkDraw * draw,SkBlitter * blitter,SkGlyphCache * cache)1377 SkDraw1Glyph::Proc SkDraw1Glyph::init(const SkDraw* draw, SkBlitter* blitter,
1378 SkGlyphCache* cache) {
1379 fDraw = draw;
1380 fBounder = draw->fBounder;
1381 fClip = draw->fClip;
1382 fClipBounds = fClip->getBounds();
1383 fBlitter = blitter;
1384 fCache = cache;
1385
1386 if (draw->fProcs && draw->fProcs->fD1GProc) {
1387 return draw->fProcs->fD1GProc;
1388 }
1389
1390 if (NULL == fBounder) {
1391 if (fClip->isRect()) {
1392 return D1G_NoBounder_RectClip;
1393 } else {
1394 return D1G_NoBounder_RgnClip;
1395 }
1396 } else {
1397 return D1G_Bounder;
1398 }
1399 }
1400
1401 enum RoundBaseline {
1402 kDont_Round_Baseline,
1403 kRound_X_Baseline,
1404 kRound_Y_Baseline
1405 };
1406
computeRoundBaseline(const SkMatrix & mat)1407 static RoundBaseline computeRoundBaseline(const SkMatrix& mat) {
1408 if (mat[1] == 0 && mat[3] == 0) {
1409 // we're 0 or 180 degrees, round the y coordinate of the baseline
1410 return kRound_Y_Baseline;
1411 } else if (mat[0] == 0 && mat[4] == 0) {
1412 // we're 90 or 270 degrees, round the x coordinate of the baseline
1413 return kRound_X_Baseline;
1414 } else {
1415 return kDont_Round_Baseline;
1416 }
1417 }
1418
1419 ///////////////////////////////////////////////////////////////////////////////
1420
drawText(const char text[],size_t byteLength,SkScalar x,SkScalar y,const SkPaint & paint) const1421 void SkDraw::drawText(const char text[], size_t byteLength,
1422 SkScalar x, SkScalar y, const SkPaint& paint) const {
1423 SkASSERT(byteLength == 0 || text != NULL);
1424
1425 SkDEBUGCODE(this->validate();)
1426
1427 // nothing to draw
1428 if (text == NULL || byteLength == 0 ||
1429 fClip->isEmpty() ||
1430 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
1431 return;
1432 }
1433
1434 SkScalar underlineWidth = 0;
1435 SkPoint underlineStart;
1436
1437 underlineStart.set(0, 0); // to avoid warning
1438 if (paint.getFlags() & (SkPaint::kUnderlineText_Flag |
1439 SkPaint::kStrikeThruText_Flag)) {
1440 underlineWidth = paint.measureText(text, byteLength);
1441
1442 SkScalar offsetX = 0;
1443 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
1444 offsetX = SkScalarHalf(underlineWidth);
1445 } else if (paint.getTextAlign() == SkPaint::kRight_Align) {
1446 offsetX = underlineWidth;
1447 }
1448 underlineStart.set(x - offsetX, y);
1449 }
1450
1451 if (/*paint.isLinearText() ||*/
1452 (fMatrix->getType() & SkMatrix::kPerspective_Mask)) {
1453 this->drawText_asPaths(text, byteLength, x, y, paint);
1454 handle_aftertext(this, paint, underlineWidth, underlineStart);
1455 return;
1456 }
1457
1458 SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc();
1459
1460 SkAutoGlyphCache autoCache(paint, fMatrix);
1461 SkGlyphCache* cache = autoCache.getCache();
1462 SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint);
1463
1464 // transform our starting point
1465 {
1466 SkPoint loc;
1467 fMatrix->mapXY(x, y, &loc);
1468 x = loc.fX;
1469 y = loc.fY;
1470 }
1471
1472 // need to measure first
1473 if (paint.getTextAlign() != SkPaint::kLeft_Align) {
1474 SkVector stop;
1475
1476 measure_text(cache, glyphCacheProc, text, byteLength, &stop);
1477
1478 SkScalar stopX = stop.fX;
1479 SkScalar stopY = stop.fY;
1480
1481 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
1482 stopX = SkScalarHalf(stopX);
1483 stopY = SkScalarHalf(stopY);
1484 }
1485 x -= stopX;
1486 y -= stopY;
1487 }
1488
1489 SkFixed fx = SkScalarToFixed(x);
1490 SkFixed fy = SkScalarToFixed(y);
1491 const char* stop = text + byteLength;
1492
1493 if (paint.isSubpixelText()) {
1494 RoundBaseline roundBaseline = computeRoundBaseline(*fMatrix);
1495 if (kRound_Y_Baseline == roundBaseline) {
1496 fy = (fy + 0x8000) & ~0xFFFF;
1497 } else if (kRound_X_Baseline == roundBaseline) {
1498 fx = (fx + 0x8000) & ~0xFFFF;
1499 }
1500 } else {
1501 // apply the bias here, so we don't have to add 1/2 in the loop
1502 fx += SK_Fixed1/2;
1503 fy += SK_Fixed1/2;
1504 }
1505
1506 SkAutoKern autokern;
1507 SkDraw1Glyph d1g;
1508 SkDraw1Glyph::Proc proc = d1g.init(this, blitter.get(), cache);
1509
1510 while (text < stop) {
1511 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx, fy);
1512
1513 fx += autokern.adjust(glyph);
1514
1515 if (glyph.fWidth) {
1516 proc(d1g, glyph, SkFixedFloor(fx), SkFixedFloor(fy));
1517 }
1518 fx += glyph.fAdvanceX;
1519 fy += glyph.fAdvanceY;
1520 }
1521
1522 if (underlineWidth) {
1523 autoCache.release(); // release this now to free up the RAM
1524 handle_aftertext(this, paint, underlineWidth, underlineStart);
1525 }
1526 }
1527
1528 // last parameter is interpreted as SkFixed [x, y]
1529 // return the fixed position, which may be rounded or not by the caller
1530 // e.g. subpixel doesn't round
1531 typedef void (*AlignProc)(const SkPoint&, const SkGlyph&, SkIPoint*);
1532
leftAlignProc(const SkPoint & loc,const SkGlyph & glyph,SkIPoint * dst)1533 static void leftAlignProc(const SkPoint& loc, const SkGlyph& glyph,
1534 SkIPoint* dst) {
1535 dst->set(SkScalarToFixed(loc.fX), SkScalarToFixed(loc.fY));
1536 }
1537
centerAlignProc(const SkPoint & loc,const SkGlyph & glyph,SkIPoint * dst)1538 static void centerAlignProc(const SkPoint& loc, const SkGlyph& glyph,
1539 SkIPoint* dst) {
1540 dst->set(SkScalarToFixed(loc.fX) - (glyph.fAdvanceX >> 1),
1541 SkScalarToFixed(loc.fY) - (glyph.fAdvanceY >> 1));
1542 }
1543
rightAlignProc(const SkPoint & loc,const SkGlyph & glyph,SkIPoint * dst)1544 static void rightAlignProc(const SkPoint& loc, const SkGlyph& glyph,
1545 SkIPoint* dst) {
1546 dst->set(SkScalarToFixed(loc.fX) - glyph.fAdvanceX,
1547 SkScalarToFixed(loc.fY) - glyph.fAdvanceY);
1548 }
1549
pick_align_proc(SkPaint::Align align)1550 static AlignProc pick_align_proc(SkPaint::Align align) {
1551 static const AlignProc gProcs[] = {
1552 leftAlignProc, centerAlignProc, rightAlignProc
1553 };
1554
1555 SkASSERT((unsigned)align < SK_ARRAY_COUNT(gProcs));
1556
1557 return gProcs[align];
1558 }
1559
1560 class TextMapState {
1561 public:
1562 mutable SkPoint fLoc;
1563
TextMapState(const SkMatrix & matrix,SkScalar y)1564 TextMapState(const SkMatrix& matrix, SkScalar y)
1565 : fMatrix(matrix), fProc(matrix.getMapXYProc()), fY(y) {}
1566
1567 typedef void (*Proc)(const TextMapState&, const SkScalar pos[]);
1568
1569 Proc pickProc(int scalarsPerPosition);
1570
1571 private:
1572 const SkMatrix& fMatrix;
1573 SkMatrix::MapXYProc fProc;
1574 SkScalar fY; // ignored by MapXYProc
1575 // these are only used by Only... procs
1576 SkScalar fScaleX, fTransX, fTransformedY;
1577
MapXProc(const TextMapState & state,const SkScalar pos[])1578 static void MapXProc(const TextMapState& state, const SkScalar pos[]) {
1579 state.fProc(state.fMatrix, *pos, state.fY, &state.fLoc);
1580 }
1581
MapXYProc(const TextMapState & state,const SkScalar pos[])1582 static void MapXYProc(const TextMapState& state, const SkScalar pos[]) {
1583 state.fProc(state.fMatrix, pos[0], pos[1], &state.fLoc);
1584 }
1585
MapOnlyScaleXProc(const TextMapState & state,const SkScalar pos[])1586 static void MapOnlyScaleXProc(const TextMapState& state,
1587 const SkScalar pos[]) {
1588 state.fLoc.set(SkScalarMul(state.fScaleX, *pos) + state.fTransX,
1589 state.fTransformedY);
1590 }
1591
MapOnlyTransXProc(const TextMapState & state,const SkScalar pos[])1592 static void MapOnlyTransXProc(const TextMapState& state,
1593 const SkScalar pos[]) {
1594 state.fLoc.set(*pos + state.fTransX, state.fTransformedY);
1595 }
1596 };
1597
pickProc(int scalarsPerPosition)1598 TextMapState::Proc TextMapState::pickProc(int scalarsPerPosition) {
1599 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
1600
1601 if (1 == scalarsPerPosition) {
1602 unsigned mtype = fMatrix.getType();
1603 if (mtype & (SkMatrix::kAffine_Mask | SkMatrix::kPerspective_Mask)) {
1604 return MapXProc;
1605 } else {
1606 fScaleX = fMatrix.getScaleX();
1607 fTransX = fMatrix.getTranslateX();
1608 fTransformedY = SkScalarMul(fY, fMatrix.getScaleY()) +
1609 fMatrix.getTranslateY();
1610 return (mtype & SkMatrix::kScale_Mask) ?
1611 MapOnlyScaleXProc : MapOnlyTransXProc;
1612 }
1613 } else {
1614 return MapXYProc;
1615 }
1616 }
1617
1618 //////////////////////////////////////////////////////////////////////////////
1619
drawPosText(const char text[],size_t byteLength,const SkScalar pos[],SkScalar constY,int scalarsPerPosition,const SkPaint & paint) const1620 void SkDraw::drawPosText(const char text[], size_t byteLength,
1621 const SkScalar pos[], SkScalar constY,
1622 int scalarsPerPosition, const SkPaint& paint) const {
1623 SkASSERT(byteLength == 0 || text != NULL);
1624 SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
1625
1626 SkDEBUGCODE(this->validate();)
1627
1628 // nothing to draw
1629 if (text == NULL || byteLength == 0 ||
1630 fClip->isEmpty() ||
1631 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
1632 return;
1633 }
1634
1635 if (/*paint.isLinearText() ||*/
1636 (fMatrix->getType() & SkMatrix::kPerspective_Mask)) {
1637 // TODO !!!!
1638 // this->drawText_asPaths(text, byteLength, x, y, paint);
1639 return;
1640 }
1641
1642 SkDrawCacheProc glyphCacheProc = paint.getDrawCacheProc();
1643 SkAutoGlyphCache autoCache(paint, fMatrix);
1644 SkGlyphCache* cache = autoCache.getCache();
1645 SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, paint);
1646
1647 const char* stop = text + byteLength;
1648 AlignProc alignProc = pick_align_proc(paint.getTextAlign());
1649 SkDraw1Glyph d1g;
1650 SkDraw1Glyph::Proc proc = d1g.init(this, blitter.get(), cache);
1651 TextMapState tms(*fMatrix, constY);
1652 TextMapState::Proc tmsProc = tms.pickProc(scalarsPerPosition);
1653
1654 if (paint.isSubpixelText()) {
1655 // maybe we should skip the rounding if linearText is set
1656 RoundBaseline roundBaseline = computeRoundBaseline(*fMatrix);
1657
1658 if (SkPaint::kLeft_Align == paint.getTextAlign()) {
1659 while (text < stop) {
1660 tmsProc(tms, pos);
1661
1662 SkFixed fx = SkScalarToFixed(tms.fLoc.fX);
1663 SkFixed fy = SkScalarToFixed(tms.fLoc.fY);
1664
1665 if (kRound_Y_Baseline == roundBaseline) {
1666 fy = (fy + 0x8000) & ~0xFFFF;
1667 } else if (kRound_X_Baseline == roundBaseline) {
1668 fx = (fx + 0x8000) & ~0xFFFF;
1669 }
1670
1671 const SkGlyph& glyph = glyphCacheProc(cache, &text, fx, fy);
1672
1673 if (glyph.fWidth) {
1674 proc(d1g, glyph, SkFixedFloor(fx), SkFixedFloor(fy));
1675 }
1676 pos += scalarsPerPosition;
1677 }
1678 } else {
1679 while (text < stop) {
1680 const SkGlyph* glyph = &glyphCacheProc(cache, &text, 0, 0);
1681
1682 if (glyph->fWidth) {
1683 SkDEBUGCODE(SkFixed prevAdvX = glyph->fAdvanceX;)
1684 SkDEBUGCODE(SkFixed prevAdvY = glyph->fAdvanceY;)
1685
1686 SkFixed fx, fy;
1687 tmsProc(tms, pos);
1688
1689 {
1690 SkIPoint fixedLoc;
1691 alignProc(tms.fLoc, *glyph, &fixedLoc);
1692 fx = fixedLoc.fX;
1693 fy = fixedLoc.fY;
1694
1695 if (kRound_Y_Baseline == roundBaseline) {
1696 fy = (fy + 0x8000) & ~0xFFFF;
1697 } else if (kRound_X_Baseline == roundBaseline) {
1698 fx = (fx + 0x8000) & ~0xFFFF;
1699 }
1700 }
1701
1702 // have to call again, now that we've been "aligned"
1703 glyph = &glyphCacheProc(cache, &text, fx, fy);
1704 // the assumption is that the advance hasn't changed
1705 SkASSERT(prevAdvX == glyph->fAdvanceX);
1706 SkASSERT(prevAdvY == glyph->fAdvanceY);
1707
1708 proc(d1g, *glyph, SkFixedFloor(fx), SkFixedFloor(fy));
1709 }
1710 pos += scalarsPerPosition;
1711 }
1712 }
1713 } else { // not subpixel
1714 while (text < stop) {
1715 // the last 2 parameters are ignored
1716 const SkGlyph& glyph = glyphCacheProc(cache, &text, 0, 0);
1717
1718 if (glyph.fWidth) {
1719 tmsProc(tms, pos);
1720
1721 SkIPoint fixedLoc;
1722 alignProc(tms.fLoc, glyph, &fixedLoc);
1723
1724 proc(d1g, glyph,
1725 SkFixedRound(fixedLoc.fX), SkFixedRound(fixedLoc.fY));
1726 }
1727 pos += scalarsPerPosition;
1728 }
1729 }
1730 }
1731
1732 #if defined _WIN32 && _MSC_VER >= 1300
1733 #pragma warning ( pop )
1734 #endif
1735
1736 ///////////////////////////////////////////////////////////////////////////////
1737
1738 #include "SkPathMeasure.h"
1739
morphpoints(SkPoint dst[],const SkPoint src[],int count,SkPathMeasure & meas,const SkMatrix & matrix)1740 static void morphpoints(SkPoint dst[], const SkPoint src[], int count,
1741 SkPathMeasure& meas, const SkMatrix& matrix) {
1742 SkMatrix::MapXYProc proc = matrix.getMapXYProc();
1743
1744 for (int i = 0; i < count; i++) {
1745 SkPoint pos;
1746 SkVector tangent;
1747
1748 proc(matrix, src[i].fX, src[i].fY, &pos);
1749 SkScalar sx = pos.fX;
1750 SkScalar sy = pos.fY;
1751
1752 meas.getPosTan(sx, &pos, &tangent);
1753
1754 /* This is the old way (that explains our approach but is way too slow
1755 SkMatrix matrix;
1756 SkPoint pt;
1757
1758 pt.set(sx, sy);
1759 matrix.setSinCos(tangent.fY, tangent.fX);
1760 matrix.preTranslate(-sx, 0);
1761 matrix.postTranslate(pos.fX, pos.fY);
1762 matrix.mapPoints(&dst[i], &pt, 1);
1763 */
1764 dst[i].set(pos.fX - SkScalarMul(tangent.fY, sy),
1765 pos.fY + SkScalarMul(tangent.fX, sy));
1766 }
1767 }
1768
1769 /* TODO
1770
1771 Need differentially more subdivisions when the follow-path is curvy. Not sure how to
1772 determine that, but we need it. I guess a cheap answer is let the caller tell us,
1773 but that seems like a cop-out. Another answer is to get Rob Johnson to figure it out.
1774 */
morphpath(SkPath * dst,const SkPath & src,SkPathMeasure & meas,const SkMatrix & matrix)1775 static void morphpath(SkPath* dst, const SkPath& src, SkPathMeasure& meas,
1776 const SkMatrix& matrix) {
1777 SkPath::Iter iter(src, false);
1778 SkPoint srcP[4], dstP[3];
1779 SkPath::Verb verb;
1780
1781 while ((verb = iter.next(srcP)) != SkPath::kDone_Verb) {
1782 switch (verb) {
1783 case SkPath::kMove_Verb:
1784 morphpoints(dstP, srcP, 1, meas, matrix);
1785 dst->moveTo(dstP[0]);
1786 break;
1787 case SkPath::kLine_Verb:
1788 // turn lines into quads to look bendy
1789 srcP[0].fX = SkScalarAve(srcP[0].fX, srcP[1].fX);
1790 srcP[0].fY = SkScalarAve(srcP[0].fY, srcP[1].fY);
1791 morphpoints(dstP, srcP, 2, meas, matrix);
1792 dst->quadTo(dstP[0], dstP[1]);
1793 break;
1794 case SkPath::kQuad_Verb:
1795 morphpoints(dstP, &srcP[1], 2, meas, matrix);
1796 dst->quadTo(dstP[0], dstP[1]);
1797 break;
1798 case SkPath::kCubic_Verb:
1799 morphpoints(dstP, &srcP[1], 3, meas, matrix);
1800 dst->cubicTo(dstP[0], dstP[1], dstP[2]);
1801 break;
1802 case SkPath::kClose_Verb:
1803 dst->close();
1804 break;
1805 default:
1806 SkASSERT(!"unknown verb");
1807 break;
1808 }
1809 }
1810 }
1811
drawTextOnPath(const char text[],size_t byteLength,const SkPath & follow,const SkMatrix * matrix,const SkPaint & paint) const1812 void SkDraw::drawTextOnPath(const char text[], size_t byteLength,
1813 const SkPath& follow, const SkMatrix* matrix,
1814 const SkPaint& paint) const {
1815 SkASSERT(byteLength == 0 || text != NULL);
1816
1817 // nothing to draw
1818 if (text == NULL || byteLength == 0 ||
1819 fClip->isEmpty() ||
1820 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
1821 return;
1822 }
1823
1824 SkTextToPathIter iter(text, byteLength, paint, true, true);
1825 SkPathMeasure meas(follow, false);
1826 SkScalar hOffset = 0;
1827
1828 // need to measure first
1829 if (paint.getTextAlign() != SkPaint::kLeft_Align) {
1830 SkScalar pathLen = meas.getLength();
1831 if (paint.getTextAlign() == SkPaint::kCenter_Align) {
1832 pathLen = SkScalarHalf(pathLen);
1833 }
1834 hOffset += pathLen;
1835 }
1836
1837 const SkPath* iterPath;
1838 SkScalar xpos;
1839 SkMatrix scaledMatrix;
1840 SkScalar scale = iter.getPathScale();
1841
1842 scaledMatrix.setScale(scale, scale);
1843
1844 while ((iterPath = iter.next(&xpos)) != NULL) {
1845 SkPath tmp;
1846 SkMatrix m(scaledMatrix);
1847
1848 m.postTranslate(xpos + hOffset, 0);
1849 if (matrix) {
1850 m.postConcat(*matrix);
1851 }
1852 morphpath(&tmp, *iterPath, meas, m);
1853 this->drawPath(tmp, iter.getPaint());
1854 }
1855 }
1856
1857 ///////////////////////////////////////////////////////////////////////////////
1858
1859 struct VertState {
1860 int f0, f1, f2;
1861
VertStateVertState1862 VertState(int vCount, const uint16_t indices[], int indexCount)
1863 : fIndices(indices) {
1864 fCurrIndex = 0;
1865 if (indices) {
1866 fCount = indexCount;
1867 } else {
1868 fCount = vCount;
1869 }
1870 }
1871
1872 typedef bool (*Proc)(VertState*);
1873 Proc chooseProc(SkCanvas::VertexMode mode);
1874
1875 private:
1876 int fCount;
1877 int fCurrIndex;
1878 const uint16_t* fIndices;
1879
1880 static bool Triangles(VertState*);
1881 static bool TrianglesX(VertState*);
1882 static bool TriangleStrip(VertState*);
1883 static bool TriangleStripX(VertState*);
1884 static bool TriangleFan(VertState*);
1885 static bool TriangleFanX(VertState*);
1886 };
1887
Triangles(VertState * state)1888 bool VertState::Triangles(VertState* state) {
1889 int index = state->fCurrIndex;
1890 if (index + 3 > state->fCount) {
1891 return false;
1892 }
1893 state->f0 = index + 0;
1894 state->f1 = index + 1;
1895 state->f2 = index + 2;
1896 state->fCurrIndex = index + 3;
1897 return true;
1898 }
1899
TrianglesX(VertState * state)1900 bool VertState::TrianglesX(VertState* state) {
1901 const uint16_t* indices = state->fIndices;
1902 int index = state->fCurrIndex;
1903 if (index + 3 > state->fCount) {
1904 return false;
1905 }
1906 state->f0 = indices[index + 0];
1907 state->f1 = indices[index + 1];
1908 state->f2 = indices[index + 2];
1909 state->fCurrIndex = index + 3;
1910 return true;
1911 }
1912
TriangleStrip(VertState * state)1913 bool VertState::TriangleStrip(VertState* state) {
1914 int index = state->fCurrIndex;
1915 if (index + 3 > state->fCount) {
1916 return false;
1917 }
1918 state->f2 = index + 2;
1919 if (index & 1) {
1920 state->f0 = index + 1;
1921 state->f1 = index + 0;
1922 } else {
1923 state->f0 = index + 0;
1924 state->f1 = index + 1;
1925 }
1926 state->fCurrIndex = index + 1;
1927 return true;
1928 }
1929
TriangleStripX(VertState * state)1930 bool VertState::TriangleStripX(VertState* state) {
1931 const uint16_t* indices = state->fIndices;
1932 int index = state->fCurrIndex;
1933 if (index + 3 > state->fCount) {
1934 return false;
1935 }
1936 state->f2 = indices[index + 2];
1937 if (index & 1) {
1938 state->f0 = indices[index + 1];
1939 state->f1 = indices[index + 0];
1940 } else {
1941 state->f0 = indices[index + 0];
1942 state->f1 = indices[index + 1];
1943 }
1944 state->fCurrIndex = index + 1;
1945 return true;
1946 }
1947
TriangleFan(VertState * state)1948 bool VertState::TriangleFan(VertState* state) {
1949 int index = state->fCurrIndex;
1950 if (index + 3 > state->fCount) {
1951 return false;
1952 }
1953 state->f0 = 0;
1954 state->f1 = index + 1;
1955 state->f2 = index + 2;
1956 state->fCurrIndex = index + 1;
1957 return true;
1958 }
1959
TriangleFanX(VertState * state)1960 bool VertState::TriangleFanX(VertState* state) {
1961 const uint16_t* indices = state->fIndices;
1962 int index = state->fCurrIndex;
1963 if (index + 3 > state->fCount) {
1964 return false;
1965 }
1966 state->f0 = indices[0];
1967 state->f1 = indices[index + 1];
1968 state->f2 = indices[index + 2];
1969 state->fCurrIndex = index + 1;
1970 return true;
1971 }
1972
chooseProc(SkCanvas::VertexMode mode)1973 VertState::Proc VertState::chooseProc(SkCanvas::VertexMode mode) {
1974 switch (mode) {
1975 case SkCanvas::kTriangles_VertexMode:
1976 return fIndices ? TrianglesX : Triangles;
1977 case SkCanvas::kTriangleStrip_VertexMode:
1978 return fIndices ? TriangleStripX : TriangleStrip;
1979 case SkCanvas::kTriangleFan_VertexMode:
1980 return fIndices ? TriangleFanX : TriangleFan;
1981 default:
1982 return NULL;
1983 }
1984 }
1985
1986 typedef void (*HairProc)(const SkPoint&, const SkPoint&, const SkRegion*,
1987 SkBlitter*);
1988
ChooseHairProc(bool doAntiAlias)1989 static HairProc ChooseHairProc(bool doAntiAlias) {
1990 return doAntiAlias ? SkScan::AntiHairLine : SkScan::HairLine;
1991 }
1992
texture_to_matrix(const VertState & state,const SkPoint verts[],const SkPoint texs[],SkMatrix * matrix)1993 static bool texture_to_matrix(const VertState& state, const SkPoint verts[],
1994 const SkPoint texs[], SkMatrix* matrix) {
1995 SkPoint src[3], dst[3];
1996
1997 src[0] = texs[state.f0];
1998 src[1] = texs[state.f1];
1999 src[2] = texs[state.f2];
2000 dst[0] = verts[state.f0];
2001 dst[1] = verts[state.f1];
2002 dst[2] = verts[state.f2];
2003 return matrix->setPolyToPoly(src, dst, 3);
2004 }
2005
2006 class SkTriColorShader : public SkShader {
2007 public:
SkTriColorShader()2008 SkTriColorShader() {}
2009
2010 bool setup(const SkPoint pts[], const SkColor colors[], int, int, int);
2011
2012 virtual void shadeSpan(int x, int y, SkPMColor dstC[], int count);
2013
2014 protected:
SkTriColorShader(SkFlattenableReadBuffer & buffer)2015 SkTriColorShader(SkFlattenableReadBuffer& buffer) : SkShader(buffer) {}
2016
getFactory()2017 virtual Factory getFactory() { return CreateProc; }
2018
2019 private:
2020 SkMatrix fDstToUnit;
2021 SkPMColor fColors[3];
2022
CreateProc(SkFlattenableReadBuffer & buffer)2023 static SkFlattenable* CreateProc(SkFlattenableReadBuffer& buffer) {
2024 return SkNEW_ARGS(SkTriColorShader, (buffer));
2025 }
2026 typedef SkShader INHERITED;
2027 };
2028
setup(const SkPoint pts[],const SkColor colors[],int index0,int index1,int index2)2029 bool SkTriColorShader::setup(const SkPoint pts[], const SkColor colors[],
2030 int index0, int index1, int index2) {
2031
2032 fColors[0] = SkPreMultiplyColor(colors[index0]);
2033 fColors[1] = SkPreMultiplyColor(colors[index1]);
2034 fColors[2] = SkPreMultiplyColor(colors[index2]);
2035
2036 SkMatrix m, im;
2037 m.reset();
2038 m.set(0, pts[index1].fX - pts[index0].fX);
2039 m.set(1, pts[index2].fX - pts[index0].fX);
2040 m.set(2, pts[index0].fX);
2041 m.set(3, pts[index1].fY - pts[index0].fY);
2042 m.set(4, pts[index2].fY - pts[index0].fY);
2043 m.set(5, pts[index0].fY);
2044 if (!m.invert(&im)) {
2045 return false;
2046 }
2047 return fDstToUnit.setConcat(im, this->getTotalInverse());
2048 }
2049
2050 #include "SkColorPriv.h"
2051 #include "SkComposeShader.h"
2052
ScalarTo256(SkScalar v)2053 static int ScalarTo256(SkScalar v) {
2054 int scale = SkScalarToFixed(v) >> 8;
2055 if (scale < 0) {
2056 scale = 0;
2057 }
2058 if (scale > 255) {
2059 scale = 255;
2060 }
2061 return SkAlpha255To256(scale);
2062 }
2063
shadeSpan(int x,int y,SkPMColor dstC[],int count)2064 void SkTriColorShader::shadeSpan(int x, int y, SkPMColor dstC[], int count) {
2065 SkPoint src;
2066
2067 for (int i = 0; i < count; i++) {
2068 fDstToUnit.mapXY(SkIntToScalar(x), SkIntToScalar(y), &src);
2069 x += 1;
2070
2071 int scale1 = ScalarTo256(src.fX);
2072 int scale2 = ScalarTo256(src.fY);
2073 int scale0 = 256 - scale1 - scale2;
2074 if (scale0 < 0) {
2075 if (scale1 > scale2) {
2076 scale2 = 256 - scale1;
2077 } else {
2078 scale1 = 256 - scale2;
2079 }
2080 scale0 = 0;
2081 }
2082
2083 dstC[i] = SkAlphaMulQ(fColors[0], scale0) +
2084 SkAlphaMulQ(fColors[1], scale1) +
2085 SkAlphaMulQ(fColors[2], scale2);
2086 }
2087 }
2088
drawVertices(SkCanvas::VertexMode vmode,int count,const SkPoint vertices[],const SkPoint textures[],const SkColor colors[],SkXfermode * xmode,const uint16_t indices[],int indexCount,const SkPaint & paint) const2089 void SkDraw::drawVertices(SkCanvas::VertexMode vmode, int count,
2090 const SkPoint vertices[], const SkPoint textures[],
2091 const SkColor colors[], SkXfermode* xmode,
2092 const uint16_t indices[], int indexCount,
2093 const SkPaint& paint) const {
2094 SkASSERT(0 == count || NULL != vertices);
2095
2096 // abort early if there is nothing to draw
2097 if (count < 3 || (indices && indexCount < 3) || fClip->isEmpty() ||
2098 (paint.getAlpha() == 0 && paint.getXfermode() == NULL)) {
2099 return;
2100 }
2101
2102 // transform out vertices into device coordinates
2103 SkAutoSTMalloc<16, SkPoint> storage(count);
2104 SkPoint* devVerts = storage.get();
2105 fMatrix->mapPoints(devVerts, vertices, count);
2106
2107 if (fBounder) {
2108 SkRect bounds;
2109 bounds.set(devVerts, count);
2110 if (!fBounder->doRect(bounds, paint)) {
2111 return;
2112 }
2113 }
2114
2115 /*
2116 We can draw the vertices in 1 of 4 ways:
2117
2118 - solid color (no shader/texture[], no colors[])
2119 - just colors (no shader/texture[], has colors[])
2120 - just texture (has shader/texture[], no colors[])
2121 - colors * texture (has shader/texture[], has colors[])
2122
2123 Thus for texture drawing, we need both texture[] and a shader.
2124 */
2125
2126 SkTriColorShader triShader; // must be above declaration of p
2127 SkPaint p(paint);
2128
2129 SkShader* shader = p.getShader();
2130 if (NULL == shader) {
2131 // if we have no shader, we ignore the texture coordinates
2132 textures = NULL;
2133 } else if (NULL == textures) {
2134 // if we don't have texture coordinates, ignore the shader
2135 p.setShader(NULL);
2136 shader = NULL;
2137 }
2138
2139 // setup the custom shader (if needed)
2140 if (NULL != colors) {
2141 if (NULL == textures) {
2142 // just colors (no texture)
2143 p.setShader(&triShader);
2144 } else {
2145 // colors * texture
2146 SkASSERT(shader);
2147 bool releaseMode = false;
2148 if (NULL == xmode) {
2149 xmode = SkXfermode::Create(SkXfermode::kMultiply_Mode);
2150 releaseMode = true;
2151 }
2152 SkShader* compose = SkNEW_ARGS(SkComposeShader,
2153 (&triShader, shader, xmode));
2154 p.setShader(compose)->unref();
2155 if (releaseMode) {
2156 xmode->unref();
2157 }
2158 }
2159 }
2160
2161 SkAutoBlitterChoose blitter(*fBitmap, *fMatrix, p);
2162 // setup our state and function pointer for iterating triangles
2163 VertState state(count, indices, indexCount);
2164 VertState::Proc vertProc = state.chooseProc(vmode);
2165
2166 if (NULL != textures || NULL != colors) {
2167 SkMatrix localM, tempM;
2168 bool hasLocalM = shader && shader->getLocalMatrix(&localM);
2169
2170 if (NULL != colors) {
2171 if (!triShader.setContext(*fBitmap, p, *fMatrix)) {
2172 colors = NULL;
2173 }
2174 }
2175
2176 while (vertProc(&state)) {
2177 if (NULL != textures) {
2178 if (texture_to_matrix(state, vertices, textures, &tempM)) {
2179 if (hasLocalM) {
2180 tempM.postConcat(localM);
2181 }
2182 shader->setLocalMatrix(tempM);
2183 // need to recal setContext since we changed the local matrix
2184 if (!shader->setContext(*fBitmap, p, *fMatrix)) {
2185 continue;
2186 }
2187 }
2188 }
2189 if (NULL != colors) {
2190 if (!triShader.setup(vertices, colors,
2191 state.f0, state.f1, state.f2)) {
2192 continue;
2193 }
2194 }
2195 SkScan::FillTriangle(devVerts[state.f0], devVerts[state.f1],
2196 devVerts[state.f2], fClip, blitter.get());
2197 }
2198 // now restore the shader's original local matrix
2199 if (NULL != shader) {
2200 if (hasLocalM) {
2201 shader->setLocalMatrix(localM);
2202 } else {
2203 shader->resetLocalMatrix();
2204 }
2205 }
2206 } else {
2207 // no colors[] and no texture
2208 HairProc hairProc = ChooseHairProc(paint.isAntiAlias());
2209 while (vertProc(&state)) {
2210 hairProc(devVerts[state.f0], devVerts[state.f1], fClip, blitter.get());
2211 hairProc(devVerts[state.f1], devVerts[state.f2], fClip, blitter.get());
2212 hairProc(devVerts[state.f2], devVerts[state.f0], fClip, blitter.get());
2213 }
2214 }
2215 }
2216
2217 ////////////////////////////////////////////////////////////////////////////////////////
2218 ////////////////////////////////////////////////////////////////////////////////////////
2219
2220 #ifdef SK_DEBUG
2221
validate() const2222 void SkDraw::validate() const {
2223 SkASSERT(fBitmap != NULL);
2224 SkASSERT(fMatrix != NULL);
2225 SkASSERT(fClip != NULL);
2226
2227 const SkIRect& cr = fClip->getBounds();
2228 SkIRect br;
2229
2230 br.set(0, 0, fBitmap->width(), fBitmap->height());
2231 SkASSERT(cr.isEmpty() || br.contains(cr));
2232 }
2233
2234 #endif
2235
2236 //////////////////////////////////////////////////////////////////////////////////////////
2237
doIRect(const SkIRect & r)2238 bool SkBounder::doIRect(const SkIRect& r) {
2239 SkIRect rr;
2240 return rr.intersect(fClip->getBounds(), r) && this->onIRect(rr);
2241 }
2242
doHairline(const SkPoint & pt0,const SkPoint & pt1,const SkPaint & paint)2243 bool SkBounder::doHairline(const SkPoint& pt0, const SkPoint& pt1,
2244 const SkPaint& paint) {
2245 SkIRect r;
2246 SkScalar v0, v1;
2247
2248 v0 = pt0.fX;
2249 v1 = pt1.fX;
2250 if (v0 > v1) {
2251 SkTSwap<SkScalar>(v0, v1);
2252 }
2253 r.fLeft = SkScalarFloor(v0);
2254 r.fRight = SkScalarCeil(v1);
2255
2256 v0 = pt0.fY;
2257 v1 = pt1.fY;
2258 if (v0 > v1) {
2259 SkTSwap<SkScalar>(v0, v1);
2260 }
2261 r.fTop = SkScalarFloor(v0);
2262 r.fBottom = SkScalarCeil(v1);
2263
2264 if (paint.isAntiAlias()) {
2265 r.inset(-1, -1);
2266 }
2267 return this->doIRect(r);
2268 }
2269
doRect(const SkRect & rect,const SkPaint & paint)2270 bool SkBounder::doRect(const SkRect& rect, const SkPaint& paint) {
2271 SkIRect r;
2272
2273 if (paint.getStyle() == SkPaint::kFill_Style) {
2274 rect.round(&r);
2275 } else {
2276 int rad = -1;
2277 rect.roundOut(&r);
2278 if (paint.isAntiAlias()) {
2279 rad = -2;
2280 }
2281 r.inset(rad, rad);
2282 }
2283 return this->doIRect(r);
2284 }
2285
doPath(const SkPath & path,const SkPaint & paint,bool doFill)2286 bool SkBounder::doPath(const SkPath& path, const SkPaint& paint, bool doFill) {
2287 SkIRect r;
2288 const SkRect& bounds = path.getBounds();
2289
2290 if (doFill) {
2291 bounds.round(&r);
2292 } else { // hairline
2293 bounds.roundOut(&r);
2294 }
2295
2296 if (paint.isAntiAlias()) {
2297 r.inset(-1, -1);
2298 }
2299 return this->doIRect(r);
2300 }
2301
commit()2302 void SkBounder::commit() {
2303 // override in subclass
2304 }
2305
2306 ////////////////////////////////////////////////////////////////////////////////////////////////
2307
2308 #include "SkPath.h"
2309 #include "SkDraw.h"
2310 #include "SkRegion.h"
2311 #include "SkBlitter.h"
2312
compute_bounds(const SkPath & devPath,const SkIRect * clipBounds,SkMaskFilter * filter,const SkMatrix * filterMatrix,SkIRect * bounds)2313 static bool compute_bounds(const SkPath& devPath, const SkIRect* clipBounds,
2314 SkMaskFilter* filter, const SkMatrix* filterMatrix,
2315 SkIRect* bounds) {
2316 if (devPath.isEmpty()) {
2317 return false;
2318 }
2319
2320 SkIPoint margin;
2321 margin.set(0, 0);
2322
2323 // init our bounds from the path
2324 {
2325 SkRect pathBounds = devPath.getBounds();
2326 pathBounds.inset(-SK_ScalarHalf, -SK_ScalarHalf);
2327 pathBounds.roundOut(bounds);
2328 }
2329
2330 if (filter) {
2331 SkASSERT(filterMatrix);
2332
2333 SkMask srcM, dstM;
2334
2335 srcM.fBounds = *bounds;
2336 srcM.fFormat = SkMask::kA8_Format;
2337 srcM.fImage = NULL;
2338 if (!filter->filterMask(&dstM, srcM, *filterMatrix, &margin)) {
2339 return false;
2340 }
2341 *bounds = dstM.fBounds;
2342 }
2343
2344 if (clipBounds && !SkIRect::Intersects(*clipBounds, *bounds)) {
2345 return false;
2346 }
2347
2348 // (possibly) trim the srcM bounds to reflect the clip
2349 // (plus whatever slop the filter needs)
2350 if (clipBounds && !clipBounds->contains(*bounds)) {
2351 SkIRect tmp = *bounds;
2352 (void)tmp.intersect(*clipBounds);
2353 // Ugh. Guard against gigantic margins from wacky filters. Without this
2354 // check we can request arbitrary amounts of slop beyond our visible
2355 // clip, and bring down the renderer (at least on finite RAM machines
2356 // like handsets, etc.). Need to balance this invented value between
2357 // quality of large filters like blurs, and the corresponding memory
2358 // requests.
2359 static const int MAX_MARGIN = 128;
2360 tmp.inset(-SkMin32(margin.fX, MAX_MARGIN),
2361 -SkMin32(margin.fY, MAX_MARGIN));
2362 (void)bounds->intersect(tmp);
2363 }
2364
2365 return true;
2366 }
2367
draw_into_mask(const SkMask & mask,const SkPath & devPath)2368 static void draw_into_mask(const SkMask& mask, const SkPath& devPath) {
2369 SkBitmap bm;
2370 SkDraw draw;
2371 SkRegion clipRgn;
2372 SkMatrix matrix;
2373 SkPaint paint;
2374
2375 bm.setConfig(SkBitmap::kA8_Config, mask.fBounds.width(), mask.fBounds.height(), mask.fRowBytes);
2376 bm.setPixels(mask.fImage);
2377
2378 clipRgn.setRect(0, 0, mask.fBounds.width(), mask.fBounds.height());
2379 matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft),
2380 -SkIntToScalar(mask.fBounds.fTop));
2381
2382 draw.fBitmap = &bm;
2383 draw.fClip = &clipRgn;
2384 draw.fMatrix = &matrix;
2385 draw.fBounder = NULL;
2386 paint.setAntiAlias(true);
2387 draw.drawPath(devPath, paint);
2388 }
2389
DrawToMask(const SkPath & devPath,const SkIRect * clipBounds,SkMaskFilter * filter,const SkMatrix * filterMatrix,SkMask * mask,SkMask::CreateMode mode)2390 bool SkDraw::DrawToMask(const SkPath& devPath, const SkIRect* clipBounds,
2391 SkMaskFilter* filter, const SkMatrix* filterMatrix,
2392 SkMask* mask, SkMask::CreateMode mode) {
2393 if (SkMask::kJustRenderImage_CreateMode != mode) {
2394 if (!compute_bounds(devPath, clipBounds, filter, filterMatrix, &mask->fBounds))
2395 return false;
2396 }
2397
2398 if (SkMask::kComputeBoundsAndRenderImage_CreateMode == mode) {
2399 mask->fFormat = SkMask::kA8_Format;
2400 mask->fRowBytes = mask->fBounds.width();
2401 size_t size = mask->computeImageSize();
2402 if (0 == size) {
2403 // we're too big to allocate the mask, abort
2404 return false;
2405 }
2406 mask->fImage = SkMask::AllocImage(size);
2407 memset(mask->fImage, 0, mask->computeImageSize());
2408 }
2409
2410 if (SkMask::kJustComputeBounds_CreateMode != mode) {
2411 draw_into_mask(*mask, devPath);
2412 }
2413
2414 return true;
2415 }
2416