• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2006 The Android Open Source Project
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #define __STDC_LIMIT_MACROS
9 
10 #include "SkArenaAlloc.h"
11 #include "SkAutoBlitterChoose.h"
12 #include "SkBlendModePriv.h"
13 #include "SkBlitter.h"
14 #include "SkCanvas.h"
15 #include "SkColorData.h"
16 #include "SkDevice.h"
17 #include "SkDeviceLooper.h"
18 #include "SkDraw.h"
19 #include "SkDrawProcs.h"
20 #include "SkFindAndPlaceGlyph.h"
21 #include "SkMaskFilterBase.h"
22 #include "SkMatrix.h"
23 #include "SkMatrixUtils.h"
24 #include "SkPaint.h"
25 #include "SkPathEffect.h"
26 #include "SkRasterClip.h"
27 #include "SkRectPriv.h"
28 #include "SkRRect.h"
29 #include "SkScalerContext.h"
30 #include "SkScan.h"
31 #include "SkShader.h"
32 #include "SkString.h"
33 #include "SkStroke.h"
34 #include "SkStrokeRec.h"
35 #include "SkTemplates.h"
36 #include "SkTextMapStateProc.h"
37 #include "SkTLazy.h"
38 #include "SkUtils.h"
39 
make_paint_with_image(const SkPaint & origPaint,const SkBitmap & bitmap,SkMatrix * matrix=nullptr)40 static SkPaint make_paint_with_image(
41     const SkPaint& origPaint, const SkBitmap& bitmap, SkMatrix* matrix = nullptr) {
42     SkPaint paint(origPaint);
43     paint.setShader(SkMakeBitmapShader(bitmap, SkShader::kClamp_TileMode,
44                                        SkShader::kClamp_TileMode, matrix,
45                                        kNever_SkCopyPixelsMode));
46     return paint;
47 }
48 
49 ///////////////////////////////////////////////////////////////////////////////
50 
SkDraw()51 SkDraw::SkDraw() {
52     sk_bzero(this, sizeof(*this));
53 }
54 
computeConservativeLocalClipBounds(SkRect * localBounds) const55 bool SkDraw::computeConservativeLocalClipBounds(SkRect* localBounds) const {
56     if (fRC->isEmpty()) {
57         return false;
58     }
59 
60     SkMatrix inverse;
61     if (!fMatrix->invert(&inverse)) {
62         return false;
63     }
64 
65     SkIRect devBounds = fRC->getBounds();
66     // outset to have slop for antialasing and hairlines
67     devBounds.outset(1, 1);
68     inverse.mapRect(localBounds, SkRect::Make(devBounds));
69     return true;
70 }
71 
72 ///////////////////////////////////////////////////////////////////////////////
73 
74 typedef void (*BitmapXferProc)(void* pixels, size_t bytes, uint32_t data);
75 
D_Clear_BitmapXferProc(void * pixels,size_t bytes,uint32_t)76 static void D_Clear_BitmapXferProc(void* pixels, size_t bytes, uint32_t) {
77     sk_bzero(pixels, bytes);
78 }
79 
D_Dst_BitmapXferProc(void *,size_t,uint32_t data)80 static void D_Dst_BitmapXferProc(void*, size_t, uint32_t data) {}
81 
D32_Src_BitmapXferProc(void * pixels,size_t bytes,uint32_t data)82 static void D32_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) {
83     sk_memset32((uint32_t*)pixels, data, SkToInt(bytes >> 2));
84 }
85 
D16_Src_BitmapXferProc(void * pixels,size_t bytes,uint32_t data)86 static void D16_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) {
87     sk_memset16((uint16_t*)pixels, data, SkToInt(bytes >> 1));
88 }
89 
DA8_Src_BitmapXferProc(void * pixels,size_t bytes,uint32_t data)90 static void DA8_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) {
91     memset(pixels, data, bytes);
92 }
93 
ChooseBitmapXferProc(const SkPixmap & dst,const SkPaint & paint,uint32_t * data)94 static BitmapXferProc ChooseBitmapXferProc(const SkPixmap& dst, const SkPaint& paint,
95                                            uint32_t* data) {
96     // todo: we can apply colorfilter up front if no shader, so we wouldn't
97     // need to abort this fastpath
98     if (paint.getShader() || paint.getColorFilter() || dst.colorSpace()) {
99         return nullptr;
100     }
101 
102     SkBlendMode mode = paint.getBlendMode();
103     SkColor color = paint.getColor();
104 
105     // collaps modes based on color...
106     if (SkBlendMode::kSrcOver == mode) {
107         unsigned alpha = SkColorGetA(color);
108         if (0 == alpha) {
109             mode = SkBlendMode::kDst;
110         } else if (0xFF == alpha) {
111             mode = SkBlendMode::kSrc;
112         }
113     }
114 
115     switch (mode) {
116         case SkBlendMode::kClear:
117 //            SkDebugf("--- D_Clear_BitmapXferProc\n");
118             return D_Clear_BitmapXferProc;  // ignore data
119         case SkBlendMode::kDst:
120 //            SkDebugf("--- D_Dst_BitmapXferProc\n");
121             return D_Dst_BitmapXferProc;    // ignore data
122         case SkBlendMode::kSrc: {
123             /*
124                 should I worry about dithering for the lower depths?
125             */
126             SkPMColor pmc = SkPreMultiplyColor(color);
127             switch (dst.colorType()) {
128                 case kN32_SkColorType:
129                     if (data) {
130                         *data = pmc;
131                     }
132 //                    SkDebugf("--- D32_Src_BitmapXferProc\n");
133                     return D32_Src_BitmapXferProc;
134                 case kRGB_565_SkColorType:
135                     if (data) {
136                         *data = SkPixel32ToPixel16(pmc);
137                     }
138 //                    SkDebugf("--- D16_Src_BitmapXferProc\n");
139                     return D16_Src_BitmapXferProc;
140                 case kAlpha_8_SkColorType:
141                     if (data) {
142                         *data = SkGetPackedA32(pmc);
143                     }
144 //                    SkDebugf("--- DA8_Src_BitmapXferProc\n");
145                     return DA8_Src_BitmapXferProc;
146                 default:
147                     break;
148             }
149             break;
150         }
151         default:
152             break;
153     }
154     return nullptr;
155 }
156 
CallBitmapXferProc(const SkPixmap & dst,const SkIRect & rect,BitmapXferProc proc,uint32_t procData)157 static void CallBitmapXferProc(const SkPixmap& dst, const SkIRect& rect, BitmapXferProc proc,
158                                uint32_t procData) {
159     int shiftPerPixel;
160     switch (dst.colorType()) {
161         case kN32_SkColorType:
162             shiftPerPixel = 2;
163             break;
164         case kRGB_565_SkColorType:
165             shiftPerPixel = 1;
166             break;
167         case kAlpha_8_SkColorType:
168             shiftPerPixel = 0;
169             break;
170         default:
171             SkDEBUGFAIL("Can't use xferproc on this config");
172             return;
173     }
174 
175     uint8_t* pixels = (uint8_t*)dst.writable_addr();
176     SkASSERT(pixels);
177     const size_t rowBytes = dst.rowBytes();
178     const int widthBytes = rect.width() << shiftPerPixel;
179 
180     // skip down to the first scanline and X position
181     pixels += rect.fTop * rowBytes + (rect.fLeft << shiftPerPixel);
182     for (int scans = rect.height() - 1; scans >= 0; --scans) {
183         proc(pixels, widthBytes, procData);
184         pixels += rowBytes;
185     }
186 }
187 
drawPaint(const SkPaint & paint) const188 void SkDraw::drawPaint(const SkPaint& paint) const {
189     SkDEBUGCODE(this->validate();)
190 
191     if (fRC->isEmpty()) {
192         return;
193     }
194 
195     SkIRect    devRect;
196     devRect.set(0, 0, fDst.width(), fDst.height());
197 
198     if (fRC->isBW()) {
199         /*  If we don't have a shader (i.e. we're just a solid color) we may
200             be faster to operate directly on the device bitmap, rather than invoking
201             a blitter. Esp. true for xfermodes, which require a colorshader to be
202             present, which is just redundant work. Since we're drawing everywhere
203             in the clip, we don't have to worry about antialiasing.
204         */
205         uint32_t procData = 0;  // to avoid the warning
206         BitmapXferProc proc = ChooseBitmapXferProc(fDst, paint, &procData);
207         if (proc) {
208             if (D_Dst_BitmapXferProc == proc) { // nothing to do
209                 return;
210             }
211 
212             SkRegion::Iterator iter(fRC->bwRgn());
213             while (!iter.done()) {
214                 CallBitmapXferProc(fDst, iter.rect(), proc, procData);
215                 iter.next();
216             }
217             return;
218         }
219     }
220 
221     // normal case: use a blitter
222     SkAutoBlitterChoose blitter(fDst, *fMatrix, paint);
223     SkScan::FillIRect(devRect, *fRC, blitter.get());
224 }
225 
226 ///////////////////////////////////////////////////////////////////////////////
227 
228 struct PtProcRec {
229     SkCanvas::PointMode fMode;
230     const SkPaint*  fPaint;
231     const SkRegion* fClip;
232     const SkRasterClip* fRC;
233 
234     // computed values
235     SkFixed fRadius;
236 
237     typedef void (*Proc)(const PtProcRec&, const SkPoint devPts[], int count,
238                          SkBlitter*);
239 
240     bool init(SkCanvas::PointMode, const SkPaint&, const SkMatrix* matrix,
241               const SkRasterClip*);
242     Proc chooseProc(SkBlitter** blitter);
243 
244 private:
245     SkAAClipBlitterWrapper fWrapper;
246 };
247 
bw_pt_rect_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)248 static void bw_pt_rect_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
249                                  int count, SkBlitter* blitter) {
250     SkASSERT(rec.fClip->isRect());
251     const SkIRect& r = rec.fClip->getBounds();
252 
253     for (int i = 0; i < count; i++) {
254         int x = SkScalarFloorToInt(devPts[i].fX);
255         int y = SkScalarFloorToInt(devPts[i].fY);
256         if (r.contains(x, y)) {
257             blitter->blitH(x, y, 1);
258         }
259     }
260 }
261 
bw_pt_rect_16_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)262 static void bw_pt_rect_16_hair_proc(const PtProcRec& rec,
263                                     const SkPoint devPts[], int count,
264                                     SkBlitter* blitter) {
265     SkASSERT(rec.fRC->isRect());
266     const SkIRect& r = rec.fRC->getBounds();
267     uint32_t value;
268     const SkPixmap* dst = blitter->justAnOpaqueColor(&value);
269     SkASSERT(dst);
270 
271     uint16_t* addr = dst->writable_addr16(0, 0);
272     size_t    rb = dst->rowBytes();
273 
274     for (int i = 0; i < count; i++) {
275         int x = SkScalarFloorToInt(devPts[i].fX);
276         int y = SkScalarFloorToInt(devPts[i].fY);
277         if (r.contains(x, y)) {
278             ((uint16_t*)((char*)addr + y * rb))[x] = SkToU16(value);
279         }
280     }
281 }
282 
bw_pt_rect_32_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)283 static void bw_pt_rect_32_hair_proc(const PtProcRec& rec,
284                                     const SkPoint devPts[], int count,
285                                     SkBlitter* blitter) {
286     SkASSERT(rec.fRC->isRect());
287     const SkIRect& r = rec.fRC->getBounds();
288     uint32_t value;
289     const SkPixmap* dst = blitter->justAnOpaqueColor(&value);
290     SkASSERT(dst);
291 
292     SkPMColor* addr = dst->writable_addr32(0, 0);
293     size_t     rb = dst->rowBytes();
294 
295     for (int i = 0; i < count; i++) {
296         int x = SkScalarFloorToInt(devPts[i].fX);
297         int y = SkScalarFloorToInt(devPts[i].fY);
298         if (r.contains(x, y)) {
299             ((SkPMColor*)((char*)addr + y * rb))[x] = value;
300         }
301     }
302 }
303 
bw_pt_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)304 static void bw_pt_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
305                             int count, SkBlitter* blitter) {
306     for (int i = 0; i < count; i++) {
307         int x = SkScalarFloorToInt(devPts[i].fX);
308         int y = SkScalarFloorToInt(devPts[i].fY);
309         if (rec.fClip->contains(x, y)) {
310             blitter->blitH(x, y, 1);
311         }
312     }
313 }
314 
bw_line_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)315 static void bw_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
316                               int count, SkBlitter* blitter) {
317     for (int i = 0; i < count; i += 2) {
318         SkScan::HairLine(&devPts[i], 2, *rec.fRC, blitter);
319     }
320 }
321 
bw_poly_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)322 static void bw_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
323                               int count, SkBlitter* blitter) {
324     SkScan::HairLine(devPts, count, *rec.fRC, blitter);
325 }
326 
327 // aa versions
328 
aa_line_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)329 static void aa_line_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
330                               int count, SkBlitter* blitter) {
331     for (int i = 0; i < count; i += 2) {
332         SkScan::AntiHairLine(&devPts[i], 2, *rec.fRC, blitter);
333     }
334 }
335 
aa_poly_hair_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)336 static void aa_poly_hair_proc(const PtProcRec& rec, const SkPoint devPts[],
337                               int count, SkBlitter* blitter) {
338     SkScan::AntiHairLine(devPts, count, *rec.fRC, blitter);
339 }
340 
341 // square procs (strokeWidth > 0 but matrix is square-scale (sx == sy)
342 
bw_square_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)343 static void bw_square_proc(const PtProcRec& rec, const SkPoint devPts[],
344                            int count, SkBlitter* blitter) {
345     const SkFixed radius = rec.fRadius;
346     for (int i = 0; i < count; i++) {
347         SkFixed x = SkScalarToFixed(devPts[i].fX);
348         SkFixed y = SkScalarToFixed(devPts[i].fY);
349 
350         SkXRect r;
351         r.fLeft = x - radius;
352         r.fTop = y - radius;
353         r.fRight = x + radius;
354         r.fBottom = y + radius;
355 
356         SkScan::FillXRect(r, *rec.fRC, blitter);
357     }
358 }
359 
aa_square_proc(const PtProcRec & rec,const SkPoint devPts[],int count,SkBlitter * blitter)360 static void aa_square_proc(const PtProcRec& rec, const SkPoint devPts[],
361                            int count, SkBlitter* blitter) {
362     const SkFixed radius = rec.fRadius;
363     for (int i = 0; i < count; i++) {
364         SkFixed x = SkScalarToFixed(devPts[i].fX);
365         SkFixed y = SkScalarToFixed(devPts[i].fY);
366 
367         SkXRect r;
368         r.fLeft = x - radius;
369         r.fTop = y - radius;
370         r.fRight = x + radius;
371         r.fBottom = y + radius;
372 
373         SkScan::AntiFillXRect(r, *rec.fRC, blitter);
374     }
375 }
376 
377 // If this guy returns true, then chooseProc() must return a valid proc
init(SkCanvas::PointMode mode,const SkPaint & paint,const SkMatrix * matrix,const SkRasterClip * rc)378 bool PtProcRec::init(SkCanvas::PointMode mode, const SkPaint& paint,
379                      const SkMatrix* matrix, const SkRasterClip* rc) {
380     if ((unsigned)mode > (unsigned)SkCanvas::kPolygon_PointMode) {
381         return false;
382     }
383     if (paint.getPathEffect()) {
384         return false;
385     }
386     SkScalar width = paint.getStrokeWidth();
387     SkScalar radius = -1;   // sentinel value, a "valid" value must be > 0
388 
389     if (0 == width) {
390         radius = 0.5f;
391     } else if (paint.getStrokeCap() != SkPaint::kRound_Cap &&
392                matrix->isScaleTranslate() && SkCanvas::kPoints_PointMode == mode) {
393         SkScalar sx = matrix->get(SkMatrix::kMScaleX);
394         SkScalar sy = matrix->get(SkMatrix::kMScaleY);
395         if (SkScalarNearlyZero(sx - sy)) {
396             radius = SkScalarHalf(width * SkScalarAbs(sx));
397         }
398     }
399     if (radius > 0) {
400         // if we return true, the caller may assume that the constructed shapes can be represented
401         // using SkFixed, so we preflight that here, looking at the radius and clip-bounds
402         if (!SkRectPriv::FitsInFixed(SkRect::Make(rc->getBounds()).makeOutset(radius, radius))) {
403             return false;
404         }
405         fMode = mode;
406         fPaint = &paint;
407         fClip = nullptr;
408         fRC = rc;
409         fRadius = SkScalarToFixed(radius);
410         return true;
411     }
412     return false;
413 }
414 
chooseProc(SkBlitter ** blitterPtr)415 PtProcRec::Proc PtProcRec::chooseProc(SkBlitter** blitterPtr) {
416     Proc proc = nullptr;
417 
418     SkBlitter* blitter = *blitterPtr;
419     if (fRC->isBW()) {
420         fClip = &fRC->bwRgn();
421     } else {
422         fWrapper.init(*fRC, blitter);
423         fClip = &fWrapper.getRgn();
424         blitter = fWrapper.getBlitter();
425         *blitterPtr = blitter;
426     }
427 
428     // for our arrays
429     SkASSERT(0 == SkCanvas::kPoints_PointMode);
430     SkASSERT(1 == SkCanvas::kLines_PointMode);
431     SkASSERT(2 == SkCanvas::kPolygon_PointMode);
432     SkASSERT((unsigned)fMode <= (unsigned)SkCanvas::kPolygon_PointMode);
433 
434     if (fPaint->isAntiAlias()) {
435         if (0 == fPaint->getStrokeWidth()) {
436             static const Proc gAAProcs[] = {
437                 aa_square_proc, aa_line_hair_proc, aa_poly_hair_proc
438             };
439             proc = gAAProcs[fMode];
440         } else if (fPaint->getStrokeCap() != SkPaint::kRound_Cap) {
441             SkASSERT(SkCanvas::kPoints_PointMode == fMode);
442             proc = aa_square_proc;
443         }
444     } else {    // BW
445         if (fRadius <= SK_FixedHalf) {    // small radii and hairline
446             if (SkCanvas::kPoints_PointMode == fMode && fClip->isRect()) {
447                 uint32_t value;
448                 const SkPixmap* bm = blitter->justAnOpaqueColor(&value);
449                 if (bm && kRGB_565_SkColorType == bm->colorType()) {
450                     proc = bw_pt_rect_16_hair_proc;
451                 } else if (bm && kN32_SkColorType == bm->colorType()) {
452                     proc = bw_pt_rect_32_hair_proc;
453                 } else {
454                     proc = bw_pt_rect_hair_proc;
455                 }
456             } else {
457                 static Proc gBWProcs[] = {
458                     bw_pt_hair_proc, bw_line_hair_proc, bw_poly_hair_proc
459                 };
460                 proc = gBWProcs[fMode];
461             }
462         } else {
463             proc = bw_square_proc;
464         }
465     }
466     return proc;
467 }
468 
469 // each of these costs 8-bytes of stack space, so don't make it too large
470 // must be even for lines/polygon to work
471 #define MAX_DEV_PTS     32
472 
drawPoints(SkCanvas::PointMode mode,size_t count,const SkPoint pts[],const SkPaint & paint,SkBaseDevice * device) const473 void SkDraw::drawPoints(SkCanvas::PointMode mode, size_t count,
474                         const SkPoint pts[], const SkPaint& paint,
475                         SkBaseDevice* device) const {
476     // if we're in lines mode, force count to be even
477     if (SkCanvas::kLines_PointMode == mode) {
478         count &= ~(size_t)1;
479     }
480 
481     if ((long)count <= 0) {
482         return;
483     }
484 
485     SkASSERT(pts != nullptr);
486     SkDEBUGCODE(this->validate();)
487 
488      // nothing to draw
489     if (fRC->isEmpty()) {
490         return;
491     }
492 
493     PtProcRec rec;
494     if (!device && rec.init(mode, paint, fMatrix, fRC)) {
495         SkAutoBlitterChoose blitter(fDst, *fMatrix, paint);
496 
497         SkPoint             devPts[MAX_DEV_PTS];
498         const SkMatrix*     matrix = fMatrix;
499         SkBlitter*          bltr = blitter.get();
500         PtProcRec::Proc     proc = rec.chooseProc(&bltr);
501         // we have to back up subsequent passes if we're in polygon mode
502         const size_t backup = (SkCanvas::kPolygon_PointMode == mode);
503 
504         do {
505             int n = SkToInt(count);
506             if (n > MAX_DEV_PTS) {
507                 n = MAX_DEV_PTS;
508             }
509             matrix->mapPoints(devPts, pts, n);
510             proc(rec, devPts, n, bltr);
511             pts += n - backup;
512             SkASSERT(SkToInt(count) >= n);
513             count -= n;
514             if (count > 0) {
515                 count += backup;
516             }
517         } while (count != 0);
518     } else {
519         switch (mode) {
520             case SkCanvas::kPoints_PointMode: {
521                 // temporarily mark the paint as filling.
522                 SkPaint newPaint(paint);
523                 newPaint.setStyle(SkPaint::kFill_Style);
524 
525                 SkScalar width = newPaint.getStrokeWidth();
526                 SkScalar radius = SkScalarHalf(width);
527 
528                 if (newPaint.getStrokeCap() == SkPaint::kRound_Cap) {
529                     SkPath      path;
530                     SkMatrix    preMatrix;
531 
532                     path.addCircle(0, 0, radius);
533                     for (size_t i = 0; i < count; i++) {
534                         preMatrix.setTranslate(pts[i].fX, pts[i].fY);
535                         // pass true for the last point, since we can modify
536                         // then path then
537                         path.setIsVolatile((count-1) == i);
538                         if (device) {
539                             device->drawPath(path, newPaint, &preMatrix, (count-1) == i);
540                         } else {
541                             this->drawPath(path, newPaint, &preMatrix, (count-1) == i);
542                         }
543                     }
544                 } else {
545                     SkRect  r;
546 
547                     for (size_t i = 0; i < count; i++) {
548                         r.fLeft = pts[i].fX - radius;
549                         r.fTop = pts[i].fY - radius;
550                         r.fRight = r.fLeft + width;
551                         r.fBottom = r.fTop + width;
552                         if (device) {
553                             device->drawRect(r, newPaint);
554                         } else {
555                             this->drawRect(r, newPaint);
556                         }
557                     }
558                 }
559                 break;
560             }
561             case SkCanvas::kLines_PointMode:
562                 if (2 == count && paint.getPathEffect()) {
563                     // most likely a dashed line - see if it is one of the ones
564                     // we can accelerate
565                     SkStrokeRec rec(paint);
566                     SkPathEffect::PointData pointData;
567 
568                     SkPath path;
569                     path.moveTo(pts[0]);
570                     path.lineTo(pts[1]);
571 
572                     SkRect cullRect = SkRect::Make(fRC->getBounds());
573 
574                     if (paint.getPathEffect()->asPoints(&pointData, path, rec,
575                                                         *fMatrix, &cullRect)) {
576                         // 'asPoints' managed to find some fast path
577 
578                         SkPaint newP(paint);
579                         newP.setPathEffect(nullptr);
580                         newP.setStyle(SkPaint::kFill_Style);
581 
582                         if (!pointData.fFirst.isEmpty()) {
583                             if (device) {
584                                 device->drawPath(pointData.fFirst, newP);
585                             } else {
586                                 this->drawPath(pointData.fFirst, newP);
587                             }
588                         }
589 
590                         if (!pointData.fLast.isEmpty()) {
591                             if (device) {
592                                 device->drawPath(pointData.fLast, newP);
593                             } else {
594                                 this->drawPath(pointData.fLast, newP);
595                             }
596                         }
597 
598                         if (pointData.fSize.fX == pointData.fSize.fY) {
599                             // The rest of the dashed line can just be drawn as points
600                             SkASSERT(pointData.fSize.fX == SkScalarHalf(newP.getStrokeWidth()));
601 
602                             if (SkPathEffect::PointData::kCircles_PointFlag & pointData.fFlags) {
603                                 newP.setStrokeCap(SkPaint::kRound_Cap);
604                             } else {
605                                 newP.setStrokeCap(SkPaint::kButt_Cap);
606                             }
607 
608                             if (device) {
609                                 device->drawPoints(SkCanvas::kPoints_PointMode,
610                                                    pointData.fNumPoints,
611                                                    pointData.fPoints,
612                                                    newP);
613                             } else {
614                                 this->drawPoints(SkCanvas::kPoints_PointMode,
615                                                  pointData.fNumPoints,
616                                                  pointData.fPoints,
617                                                  newP,
618                                                  device);
619                             }
620                             break;
621                         } else {
622                             // The rest of the dashed line must be drawn as rects
623                             SkASSERT(!(SkPathEffect::PointData::kCircles_PointFlag &
624                                       pointData.fFlags));
625 
626                             SkRect r;
627 
628                             for (int i = 0; i < pointData.fNumPoints; ++i) {
629                                 r.set(pointData.fPoints[i].fX - pointData.fSize.fX,
630                                       pointData.fPoints[i].fY - pointData.fSize.fY,
631                                       pointData.fPoints[i].fX + pointData.fSize.fX,
632                                       pointData.fPoints[i].fY + pointData.fSize.fY);
633                                 if (device) {
634                                     device->drawRect(r, newP);
635                                 } else {
636                                     this->drawRect(r, newP);
637                                 }
638                             }
639                         }
640 
641                         break;
642                     }
643                 }
644                 // couldn't take fast path so fall through!
645             case SkCanvas::kPolygon_PointMode: {
646                 count -= 1;
647                 SkPath path;
648                 SkPaint p(paint);
649                 p.setStyle(SkPaint::kStroke_Style);
650                 size_t inc = (SkCanvas::kLines_PointMode == mode) ? 2 : 1;
651                 path.setIsVolatile(true);
652                 for (size_t i = 0; i < count; i += inc) {
653                     path.moveTo(pts[i]);
654                     path.lineTo(pts[i+1]);
655                     if (device) {
656                         device->drawPath(path, p, nullptr, true);
657                     } else {
658                         this->drawPath(path, p, nullptr, true);
659                     }
660                     path.rewind();
661                 }
662                 break;
663             }
664         }
665     }
666 }
667 
compute_stroke_size(const SkPaint & paint,const SkMatrix & matrix)668 static inline SkPoint compute_stroke_size(const SkPaint& paint, const SkMatrix& matrix) {
669     SkASSERT(matrix.rectStaysRect());
670     SkASSERT(SkPaint::kFill_Style != paint.getStyle());
671 
672     SkVector size;
673     SkPoint pt = { paint.getStrokeWidth(), paint.getStrokeWidth() };
674     matrix.mapVectors(&size, &pt, 1);
675     return SkPoint::Make(SkScalarAbs(size.fX), SkScalarAbs(size.fY));
676 }
677 
easy_rect_join(const SkPaint & paint,const SkMatrix & matrix,SkPoint * strokeSize)678 static bool easy_rect_join(const SkPaint& paint, const SkMatrix& matrix,
679                            SkPoint* strokeSize) {
680     if (SkPaint::kMiter_Join != paint.getStrokeJoin() ||
681         paint.getStrokeMiter() < SK_ScalarSqrt2) {
682         return false;
683     }
684 
685     *strokeSize = compute_stroke_size(paint, matrix);
686     return true;
687 }
688 
ComputeRectType(const SkPaint & paint,const SkMatrix & matrix,SkPoint * strokeSize)689 SkDraw::RectType SkDraw::ComputeRectType(const SkPaint& paint,
690                                          const SkMatrix& matrix,
691                                          SkPoint* strokeSize) {
692     RectType rtype;
693     const SkScalar width = paint.getStrokeWidth();
694     const bool zeroWidth = (0 == width);
695     SkPaint::Style style = paint.getStyle();
696 
697     if ((SkPaint::kStrokeAndFill_Style == style) && zeroWidth) {
698         style = SkPaint::kFill_Style;
699     }
700 
701     if (paint.getPathEffect() || paint.getMaskFilter() ||
702         !matrix.rectStaysRect() || SkPaint::kStrokeAndFill_Style == style) {
703         rtype = kPath_RectType;
704     } else if (SkPaint::kFill_Style == style) {
705         rtype = kFill_RectType;
706     } else if (zeroWidth) {
707         rtype = kHair_RectType;
708     } else if (easy_rect_join(paint, matrix, strokeSize)) {
709         rtype = kStroke_RectType;
710     } else {
711         rtype = kPath_RectType;
712     }
713     return rtype;
714 }
715 
rect_points(const SkRect & r)716 static const SkPoint* rect_points(const SkRect& r) {
717     return SkTCast<const SkPoint*>(&r);
718 }
719 
rect_points(SkRect & r)720 static SkPoint* rect_points(SkRect& r) {
721     return SkTCast<SkPoint*>(&r);
722 }
723 
draw_rect_as_path(const SkDraw & orig,const SkRect & prePaintRect,const SkPaint & paint,const SkMatrix * matrix)724 static void draw_rect_as_path(const SkDraw& orig, const SkRect& prePaintRect,
725                               const SkPaint& paint, const SkMatrix* matrix) {
726     SkDraw draw(orig);
727     draw.fMatrix = matrix;
728     SkPath  tmp;
729     tmp.addRect(prePaintRect);
730     tmp.setFillType(SkPath::kWinding_FillType);
731     draw.drawPath(tmp, paint, nullptr, true);
732 }
733 
drawRect(const SkRect & prePaintRect,const SkPaint & paint,const SkMatrix * paintMatrix,const SkRect * postPaintRect) const734 void SkDraw::drawRect(const SkRect& prePaintRect, const SkPaint& paint,
735                       const SkMatrix* paintMatrix, const SkRect* postPaintRect) const {
736     SkDEBUGCODE(this->validate();)
737 
738     // nothing to draw
739     if (fRC->isEmpty()) {
740         return;
741     }
742 
743     const SkMatrix* matrix;
744     SkMatrix combinedMatrixStorage;
745     if (paintMatrix) {
746         SkASSERT(postPaintRect);
747         combinedMatrixStorage.setConcat(*fMatrix, *paintMatrix);
748         matrix = &combinedMatrixStorage;
749     } else {
750         SkASSERT(!postPaintRect);
751         matrix = fMatrix;
752     }
753 
754     SkPoint strokeSize;
755     RectType rtype = ComputeRectType(paint, *fMatrix, &strokeSize);
756 
757     if (kPath_RectType == rtype) {
758         draw_rect_as_path(*this, prePaintRect, paint, matrix);
759         return;
760     }
761 
762     SkRect devRect;
763     const SkRect& paintRect = paintMatrix ? *postPaintRect : prePaintRect;
764     // skip the paintMatrix when transforming the rect by the CTM
765     fMatrix->mapPoints(rect_points(devRect), rect_points(paintRect), 2);
766     devRect.sort();
767 
768     // look for the quick exit, before we build a blitter
769     SkRect bbox = devRect;
770     if (paint.getStyle() != SkPaint::kFill_Style) {
771         // extra space for hairlines
772         if (paint.getStrokeWidth() == 0) {
773             bbox.outset(1, 1);
774         } else {
775             // For kStroke_RectType, strokeSize is already computed.
776             const SkPoint& ssize = (kStroke_RectType == rtype)
777                 ? strokeSize
778                 : compute_stroke_size(paint, *fMatrix);
779             bbox.outset(SkScalarHalf(ssize.x()), SkScalarHalf(ssize.y()));
780         }
781     }
782 
783     if (!SkRectPriv::MakeLargeS32().contains(bbox)) {
784         // bbox.roundOut() is undefined; use slow path.
785         draw_rect_as_path(*this, prePaintRect, paint, matrix);
786         return;
787     }
788 
789     SkIRect ir = bbox.roundOut();
790     if (fRC->quickReject(ir)) {
791         return;
792     }
793 
794     SkDeviceLooper looper(fDst, *fRC, ir, paint.isAntiAlias());
795     while (looper.next()) {
796         SkRect localDevRect;
797         looper.mapRect(&localDevRect, devRect);
798         SkMatrix localMatrix;
799         looper.mapMatrix(&localMatrix, *matrix);
800 
801         SkAutoBlitterChoose blitterStorage(looper.getPixmap(), localMatrix, paint);
802         const SkRasterClip& clip = looper.getRC();
803         SkBlitter*          blitter = blitterStorage.get();
804 
805         // we want to "fill" if we are kFill or kStrokeAndFill, since in the latter
806         // case we are also hairline (if we've gotten to here), which devolves to
807         // effectively just kFill
808         switch (rtype) {
809             case kFill_RectType:
810                 if (paint.isAntiAlias()) {
811                     SkScan::AntiFillRect(localDevRect, clip, blitter);
812                 } else {
813                     SkScan::FillRect(localDevRect, clip, blitter);
814                 }
815                 break;
816             case kStroke_RectType:
817                 if (paint.isAntiAlias()) {
818                     SkScan::AntiFrameRect(localDevRect, strokeSize, clip, blitter);
819                 } else {
820                     SkScan::FrameRect(localDevRect, strokeSize, clip, blitter);
821                 }
822                 break;
823             case kHair_RectType:
824                 if (paint.isAntiAlias()) {
825                     SkScan::AntiHairRect(localDevRect, clip, blitter);
826                 } else {
827                     SkScan::HairRect(localDevRect, clip, blitter);
828                 }
829                 break;
830             default:
831                 SkDEBUGFAIL("bad rtype");
832         }
833     }
834 }
835 
drawDevMask(const SkMask & srcM,const SkPaint & paint) const836 void SkDraw::drawDevMask(const SkMask& srcM, const SkPaint& paint) const {
837     if (srcM.fBounds.isEmpty()) {
838         return;
839     }
840 
841     const SkMask* mask = &srcM;
842 
843     SkMask dstM;
844     if (paint.getMaskFilter() &&
845         as_MFB(paint.getMaskFilter())->filterMask(&dstM, srcM, *fMatrix, nullptr)) {
846         mask = &dstM;
847     }
848     SkAutoMaskFreeImage ami(dstM.fImage);
849 
850     SkAutoBlitterChoose blitterChooser(fDst, *fMatrix, paint);
851     SkBlitter* blitter = blitterChooser.get();
852 
853     SkAAClipBlitterWrapper wrapper;
854     const SkRegion* clipRgn;
855 
856     if (fRC->isBW()) {
857         clipRgn = &fRC->bwRgn();
858     } else {
859         wrapper.init(*fRC, blitter);
860         clipRgn = &wrapper.getRgn();
861         blitter = wrapper.getBlitter();
862     }
863     blitter->blitMaskRegion(*mask, *clipRgn);
864 }
865 
fast_len(const SkVector & vec)866 static SkScalar fast_len(const SkVector& vec) {
867     SkScalar x = SkScalarAbs(vec.fX);
868     SkScalar y = SkScalarAbs(vec.fY);
869     if (x < y) {
870         SkTSwap(x, y);
871     }
872     return x + SkScalarHalf(y);
873 }
874 
SkDrawTreatAAStrokeAsHairline(SkScalar strokeWidth,const SkMatrix & matrix,SkScalar * coverage)875 bool SkDrawTreatAAStrokeAsHairline(SkScalar strokeWidth, const SkMatrix& matrix,
876                                    SkScalar* coverage) {
877     SkASSERT(strokeWidth > 0);
878     // We need to try to fake a thick-stroke with a modulated hairline.
879 
880     if (matrix.hasPerspective()) {
881         return false;
882     }
883 
884     SkVector src[2], dst[2];
885     src[0].set(strokeWidth, 0);
886     src[1].set(0, strokeWidth);
887     matrix.mapVectors(dst, src, 2);
888     SkScalar len0 = fast_len(dst[0]);
889     SkScalar len1 = fast_len(dst[1]);
890     if (len0 <= SK_Scalar1 && len1 <= SK_Scalar1) {
891         if (coverage) {
892             *coverage = SkScalarAve(len0, len1);
893         }
894         return true;
895     }
896     return false;
897 }
898 
drawRRect(const SkRRect & rrect,const SkPaint & paint) const899 void SkDraw::drawRRect(const SkRRect& rrect, const SkPaint& paint) const {
900     SkDEBUGCODE(this->validate());
901 
902     if (fRC->isEmpty()) {
903         return;
904     }
905 
906     {
907         // TODO: Investigate optimizing these options. They are in the same
908         // order as SkDraw::drawPath, which handles each case. It may be
909         // that there is no way to optimize for these using the SkRRect path.
910         SkScalar coverage;
911         if (SkDrawTreatAsHairline(paint, *fMatrix, &coverage)) {
912             goto DRAW_PATH;
913         }
914 
915         if (paint.getPathEffect() || paint.getStyle() != SkPaint::kFill_Style) {
916             goto DRAW_PATH;
917         }
918     }
919 
920     if (paint.getMaskFilter()) {
921         // Transform the rrect into device space.
922         SkRRect devRRect;
923         if (rrect.transform(*fMatrix, &devRRect)) {
924             SkAutoBlitterChoose blitter(fDst, *fMatrix, paint);
925             if (as_MFB(paint.getMaskFilter())->filterRRect(devRRect, *fMatrix,
926                                                            *fRC, blitter.get())) {
927                 return; // filterRRect() called the blitter, so we're done
928             }
929         }
930     }
931 
932 DRAW_PATH:
933     // Now fall back to the default case of using a path.
934     SkPath path;
935     path.addRRect(rrect);
936     this->drawPath(path, paint, nullptr, true);
937 }
938 
ComputeResScaleForStroking(const SkMatrix & matrix)939 SkScalar SkDraw::ComputeResScaleForStroking(const SkMatrix& matrix) {
940     if (!matrix.hasPerspective()) {
941         SkScalar sx = SkPoint::Length(matrix[SkMatrix::kMScaleX], matrix[SkMatrix::kMSkewY]);
942         SkScalar sy = SkPoint::Length(matrix[SkMatrix::kMSkewX],  matrix[SkMatrix::kMScaleY]);
943         if (SkScalarsAreFinite(sx, sy)) {
944             SkScalar scale = SkTMax(sx, sy);
945             if (scale > 0) {
946                 return scale;
947             }
948         }
949     }
950     return 1;
951 }
952 
drawDevPath(const SkPath & devPath,const SkPaint & paint,bool drawCoverage,SkBlitter * customBlitter,bool doFill) const953 void SkDraw::drawDevPath(const SkPath& devPath, const SkPaint& paint, bool drawCoverage,
954                          SkBlitter* customBlitter, bool doFill) const {
955     // Do a conservative quick-reject test, since a looper or other modifier may have moved us
956     // out of range.
957     if (!devPath.isInverseFillType()) {
958         // If we're a H or V line, our bounds will be empty. So we bloat here just so we don't
959         // appear empty to the intersects call. This also gives us slop in case we're antialiasing
960         SkRect pathBounds = devPath.getBounds().makeOutset(1, 1);
961 
962         if (paint.getMaskFilter()) {
963             as_MFB(paint.getMaskFilter())->computeFastBounds(pathBounds, &pathBounds);
964 
965             // Need to outset the path to work-around a bug in blurmaskfilter. When that is fixed
966             // we can remove this hack. See skbug.com/5542
967             pathBounds.outset(7, 7);
968         }
969 
970         // Now compare against the clip's bounds
971         if (!SkRect::Make(fRC->getBounds()).intersects(pathBounds)) {
972             return;
973         }
974     }
975 
976     SkBlitter* blitter = nullptr;
977     SkAutoBlitterChoose blitterStorage;
978     if (nullptr == customBlitter) {
979         blitterStorage.choose(fDst, *fMatrix, paint, drawCoverage);
980         blitter = blitterStorage.get();
981     } else {
982         blitter = customBlitter;
983     }
984 
985     if (paint.getMaskFilter()) {
986         SkStrokeRec::InitStyle style = doFill ? SkStrokeRec::kFill_InitStyle
987         : SkStrokeRec::kHairline_InitStyle;
988         if (as_MFB(paint.getMaskFilter())->filterPath(devPath, *fMatrix, *fRC, blitter, style)) {
989             return; // filterPath() called the blitter, so we're done
990         }
991     }
992 
993     void (*proc)(const SkPath&, const SkRasterClip&, SkBlitter*);
994     if (doFill) {
995         if (paint.isAntiAlias()) {
996             proc = SkScan::AntiFillPath;
997         } else {
998             proc = SkScan::FillPath;
999         }
1000     } else {    // hairline
1001         if (paint.isAntiAlias()) {
1002             switch (paint.getStrokeCap()) {
1003                 case SkPaint::kButt_Cap:
1004                     proc = SkScan::AntiHairPath;
1005                     break;
1006                 case SkPaint::kSquare_Cap:
1007                     proc = SkScan::AntiHairSquarePath;
1008                     break;
1009                 case SkPaint::kRound_Cap:
1010                     proc = SkScan::AntiHairRoundPath;
1011                     break;
1012                 default:
1013                     proc SK_INIT_TO_AVOID_WARNING;
1014                     SkDEBUGFAIL("unknown paint cap type");
1015             }
1016         } else {
1017             switch (paint.getStrokeCap()) {
1018                 case SkPaint::kButt_Cap:
1019                     proc = SkScan::HairPath;
1020                     break;
1021                 case SkPaint::kSquare_Cap:
1022                     proc = SkScan::HairSquarePath;
1023                     break;
1024                 case SkPaint::kRound_Cap:
1025                     proc = SkScan::HairRoundPath;
1026                     break;
1027                 default:
1028                     proc SK_INIT_TO_AVOID_WARNING;
1029                     SkDEBUGFAIL("unknown paint cap type");
1030             }
1031         }
1032     }
1033     proc(devPath, *fRC, blitter);
1034 }
1035 
drawPath(const SkPath & origSrcPath,const SkPaint & origPaint,const SkMatrix * prePathMatrix,bool pathIsMutable,bool drawCoverage,SkBlitter * customBlitter) const1036 void SkDraw::drawPath(const SkPath& origSrcPath, const SkPaint& origPaint,
1037                       const SkMatrix* prePathMatrix, bool pathIsMutable,
1038                       bool drawCoverage, SkBlitter* customBlitter) const {
1039     SkDEBUGCODE(this->validate();)
1040 
1041     // nothing to draw
1042     if (fRC->isEmpty()) {
1043         return;
1044     }
1045 
1046     SkPath*         pathPtr = (SkPath*)&origSrcPath;
1047     bool            doFill = true;
1048     SkPath          tmpPath;
1049     SkMatrix        tmpMatrix;
1050     const SkMatrix* matrix = fMatrix;
1051     tmpPath.setIsVolatile(true);
1052 
1053     if (prePathMatrix) {
1054         if (origPaint.getPathEffect() || origPaint.getStyle() != SkPaint::kFill_Style) {
1055             SkPath* result = pathPtr;
1056 
1057             if (!pathIsMutable) {
1058                 result = &tmpPath;
1059                 pathIsMutable = true;
1060             }
1061             pathPtr->transform(*prePathMatrix, result);
1062             pathPtr = result;
1063         } else {
1064             tmpMatrix.setConcat(*matrix, *prePathMatrix);
1065             matrix = &tmpMatrix;
1066         }
1067     }
1068     // at this point we're done with prePathMatrix
1069     SkDEBUGCODE(prePathMatrix = (const SkMatrix*)0x50FF8001;)
1070 
1071     SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
1072 
1073     {
1074         SkScalar coverage;
1075         if (SkDrawTreatAsHairline(origPaint, *matrix, &coverage)) {
1076             if (SK_Scalar1 == coverage) {
1077                 paint.writable()->setStrokeWidth(0);
1078             } else if (SkBlendMode_SupportsCoverageAsAlpha(origPaint.getBlendMode())) {
1079                 U8CPU newAlpha;
1080 #if 0
1081                 newAlpha = SkToU8(SkScalarRoundToInt(coverage *
1082                                                      origPaint.getAlpha()));
1083 #else
1084                 // this is the old technique, which we preserve for now so
1085                 // we don't change previous results (testing)
1086                 // the new way seems fine, its just (a tiny bit) different
1087                 int scale = (int)(coverage * 256);
1088                 newAlpha = origPaint.getAlpha() * scale >> 8;
1089 #endif
1090                 SkPaint* writablePaint = paint.writable();
1091                 writablePaint->setStrokeWidth(0);
1092                 writablePaint->setAlpha(newAlpha);
1093             }
1094         }
1095     }
1096 
1097     if (paint->getPathEffect() || paint->getStyle() != SkPaint::kFill_Style) {
1098         SkRect cullRect;
1099         const SkRect* cullRectPtr = nullptr;
1100         if (this->computeConservativeLocalClipBounds(&cullRect)) {
1101             cullRectPtr = &cullRect;
1102         }
1103         doFill = paint->getFillPath(*pathPtr, &tmpPath, cullRectPtr,
1104                                     ComputeResScaleForStroking(*fMatrix));
1105         pathPtr = &tmpPath;
1106     }
1107 
1108     // avoid possibly allocating a new path in transform if we can
1109     SkPath* devPathPtr = pathIsMutable ? pathPtr : &tmpPath;
1110 
1111     // transform the path into device space
1112     pathPtr->transform(*matrix, devPathPtr);
1113 
1114     this->drawDevPath(*devPathPtr, *paint, drawCoverage, customBlitter, doFill);
1115 }
1116 
drawBitmapAsMask(const SkBitmap & bitmap,const SkPaint & paint) const1117 void SkDraw::drawBitmapAsMask(const SkBitmap& bitmap, const SkPaint& paint) const {
1118     SkASSERT(bitmap.colorType() == kAlpha_8_SkColorType);
1119 
1120     if (SkTreatAsSprite(*fMatrix, bitmap.dimensions(), paint)) {
1121         int ix = SkScalarRoundToInt(fMatrix->getTranslateX());
1122         int iy = SkScalarRoundToInt(fMatrix->getTranslateY());
1123 
1124         SkPixmap pmap;
1125         if (!bitmap.peekPixels(&pmap)) {
1126             return;
1127         }
1128         SkMask  mask;
1129         mask.fBounds.set(ix, iy, ix + pmap.width(), iy + pmap.height());
1130         mask.fFormat = SkMask::kA8_Format;
1131         mask.fRowBytes = SkToU32(pmap.rowBytes());
1132         // fImage is typed as writable, but in this case it is used read-only
1133         mask.fImage = (uint8_t*)pmap.addr8(0, 0);
1134 
1135         this->drawDevMask(mask, paint);
1136     } else {    // need to xform the bitmap first
1137         SkRect  r;
1138         SkMask  mask;
1139 
1140         r.set(0, 0,
1141               SkIntToScalar(bitmap.width()), SkIntToScalar(bitmap.height()));
1142         fMatrix->mapRect(&r);
1143         r.round(&mask.fBounds);
1144 
1145         // set the mask's bounds to the transformed bitmap-bounds,
1146         // clipped to the actual device
1147         {
1148             SkIRect    devBounds;
1149             devBounds.set(0, 0, fDst.width(), fDst.height());
1150             // need intersect(l, t, r, b) on irect
1151             if (!mask.fBounds.intersect(devBounds)) {
1152                 return;
1153             }
1154         }
1155 
1156         mask.fFormat = SkMask::kA8_Format;
1157         mask.fRowBytes = SkAlign4(mask.fBounds.width());
1158         size_t size = mask.computeImageSize();
1159         if (0 == size) {
1160             // the mask is too big to allocated, draw nothing
1161             return;
1162         }
1163 
1164         // allocate (and clear) our temp buffer to hold the transformed bitmap
1165         SkAutoTMalloc<uint8_t> storage(size);
1166         mask.fImage = storage.get();
1167         memset(mask.fImage, 0, size);
1168 
1169         // now draw our bitmap(src) into mask(dst), transformed by the matrix
1170         {
1171             SkBitmap    device;
1172             device.installPixels(SkImageInfo::MakeA8(mask.fBounds.width(), mask.fBounds.height()),
1173                                  mask.fImage, mask.fRowBytes);
1174 
1175             SkCanvas c(device);
1176             // need the unclipped top/left for the translate
1177             c.translate(-SkIntToScalar(mask.fBounds.fLeft),
1178                         -SkIntToScalar(mask.fBounds.fTop));
1179             c.concat(*fMatrix);
1180 
1181             // We can't call drawBitmap, or we'll infinitely recurse. Instead
1182             // we manually build a shader and draw that into our new mask
1183             SkPaint tmpPaint;
1184             tmpPaint.setFlags(paint.getFlags());
1185             tmpPaint.setFilterQuality(paint.getFilterQuality());
1186             SkPaint paintWithShader = make_paint_with_image(tmpPaint, bitmap);
1187             SkRect rr;
1188             rr.set(0, 0, SkIntToScalar(bitmap.width()),
1189                    SkIntToScalar(bitmap.height()));
1190             c.drawRect(rr, paintWithShader);
1191         }
1192         this->drawDevMask(mask, paint);
1193     }
1194 }
1195 
clipped_out(const SkMatrix & m,const SkRasterClip & c,const SkRect & srcR)1196 static bool clipped_out(const SkMatrix& m, const SkRasterClip& c,
1197                         const SkRect& srcR) {
1198     SkRect  dstR;
1199     m.mapRect(&dstR, srcR);
1200     return c.quickReject(dstR.roundOut());
1201 }
1202 
clipped_out(const SkMatrix & matrix,const SkRasterClip & clip,int width,int height)1203 static bool clipped_out(const SkMatrix& matrix, const SkRasterClip& clip,
1204                         int width, int height) {
1205     SkRect  r;
1206     r.set(0, 0, SkIntToScalar(width), SkIntToScalar(height));
1207     return clipped_out(matrix, clip, r);
1208 }
1209 
clipHandlesSprite(const SkRasterClip & clip,int x,int y,const SkPixmap & pmap)1210 static bool clipHandlesSprite(const SkRasterClip& clip, int x, int y, const SkPixmap& pmap) {
1211     return clip.isBW() || clip.quickContains(x, y, x + pmap.width(), y + pmap.height());
1212 }
1213 
drawBitmap(const SkBitmap & bitmap,const SkMatrix & prematrix,const SkRect * dstBounds,const SkPaint & origPaint) const1214 void SkDraw::drawBitmap(const SkBitmap& bitmap, const SkMatrix& prematrix,
1215                         const SkRect* dstBounds, const SkPaint& origPaint) const {
1216     SkDEBUGCODE(this->validate();)
1217 
1218     // nothing to draw
1219     if (fRC->isEmpty() ||
1220             bitmap.width() == 0 || bitmap.height() == 0 ||
1221             bitmap.colorType() == kUnknown_SkColorType) {
1222         return;
1223     }
1224 
1225     SkTCopyOnFirstWrite<SkPaint> paint(origPaint);
1226     if (origPaint.getStyle() != SkPaint::kFill_Style) {
1227         paint.writable()->setStyle(SkPaint::kFill_Style);
1228     }
1229 
1230     SkMatrix matrix;
1231     matrix.setConcat(*fMatrix, prematrix);
1232 
1233     if (clipped_out(matrix, *fRC, bitmap.width(), bitmap.height())) {
1234         return;
1235     }
1236 
1237     if (bitmap.colorType() != kAlpha_8_SkColorType
1238         && SkTreatAsSprite(matrix, bitmap.dimensions(), *paint)) {
1239         //
1240         // It is safe to call lock pixels now, since we know the matrix is
1241         // (more or less) identity.
1242         //
1243         SkPixmap pmap;
1244         if (!bitmap.peekPixels(&pmap)) {
1245             return;
1246         }
1247         int ix = SkScalarRoundToInt(matrix.getTranslateX());
1248         int iy = SkScalarRoundToInt(matrix.getTranslateY());
1249         if (clipHandlesSprite(*fRC, ix, iy, pmap)) {
1250             SkSTArenaAlloc<kSkBlitterContextSize> allocator;
1251             // blitter will be owned by the allocator.
1252             SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, *paint, pmap, ix, iy, &allocator);
1253             if (blitter) {
1254                 SkScan::FillIRect(SkIRect::MakeXYWH(ix, iy, pmap.width(), pmap.height()),
1255                                   *fRC, blitter);
1256                 return;
1257             }
1258             // if !blitter, then we fall-through to the slower case
1259         }
1260     }
1261 
1262     // now make a temp draw on the stack, and use it
1263     //
1264     SkDraw draw(*this);
1265     draw.fMatrix = &matrix;
1266 
1267     if (bitmap.colorType() == kAlpha_8_SkColorType && !paint->getColorFilter()) {
1268         draw.drawBitmapAsMask(bitmap, *paint);
1269     } else {
1270         SkPaint paintWithShader = make_paint_with_image(*paint, bitmap);
1271         const SkRect srcBounds = SkRect::MakeIWH(bitmap.width(), bitmap.height());
1272         if (dstBounds) {
1273             this->drawRect(srcBounds, paintWithShader, &prematrix, dstBounds);
1274         } else {
1275             draw.drawRect(srcBounds, paintWithShader);
1276         }
1277     }
1278 }
1279 
drawSprite(const SkBitmap & bitmap,int x,int y,const SkPaint & origPaint) const1280 void SkDraw::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& origPaint) const {
1281     SkDEBUGCODE(this->validate();)
1282 
1283     // nothing to draw
1284     if (fRC->isEmpty() ||
1285             bitmap.width() == 0 || bitmap.height() == 0 ||
1286             bitmap.colorType() == kUnknown_SkColorType) {
1287         return;
1288     }
1289 
1290     const SkIRect bounds = SkIRect::MakeXYWH(x, y, bitmap.width(), bitmap.height());
1291 
1292     if (fRC->quickReject(bounds)) {
1293         return; // nothing to draw
1294     }
1295 
1296     SkPaint paint(origPaint);
1297     paint.setStyle(SkPaint::kFill_Style);
1298 
1299     SkPixmap pmap;
1300     if (!bitmap.peekPixels(&pmap)) {
1301         return;
1302     }
1303 
1304     if (nullptr == paint.getColorFilter() && clipHandlesSprite(*fRC, x, y, pmap)) {
1305         // blitter will be owned by the allocator.
1306         SkSTArenaAlloc<kSkBlitterContextSize> allocator;
1307         SkBlitter* blitter = SkBlitter::ChooseSprite(fDst, paint, pmap, x, y, &allocator);
1308         if (blitter) {
1309             SkScan::FillIRect(bounds, *fRC, blitter);
1310             return;
1311         }
1312     }
1313 
1314     SkMatrix        matrix;
1315     SkRect          r;
1316 
1317     // get a scalar version of our rect
1318     r.set(bounds);
1319 
1320     // create shader with offset
1321     matrix.setTranslate(r.fLeft, r.fTop);
1322     SkPaint paintWithShader = make_paint_with_image(paint, bitmap, &matrix);
1323     SkDraw draw(*this);
1324     matrix.reset();
1325     draw.fMatrix = &matrix;
1326     // call ourself with a rect
1327     draw.drawRect(r, paintWithShader);
1328 }
1329 
1330 ///////////////////////////////////////////////////////////////////////////////
1331 
1332 #include "SkPaintPriv.h"
1333 #include "SkScalerContext.h"
1334 #include "SkGlyphCache.h"
1335 #include "SkTextToPathIter.h"
1336 #include "SkUtils.h"
1337 
ShouldDrawTextAsPaths(const SkPaint & paint,const SkMatrix & ctm,SkScalar sizeLimit)1338 bool SkDraw::ShouldDrawTextAsPaths(const SkPaint& paint, const SkMatrix& ctm, SkScalar sizeLimit) {
1339     // hairline glyphs are fast enough so we don't need to cache them
1340     if (SkPaint::kStroke_Style == paint.getStyle() && 0 == paint.getStrokeWidth()) {
1341         return true;
1342     }
1343 
1344     // we don't cache perspective
1345     if (ctm.hasPerspective()) {
1346         return true;
1347     }
1348 
1349     SkMatrix textM;
1350     SkPaintPriv::MakeTextMatrix(&textM, paint);
1351     return SkPaint::TooBigToUseCache(ctm, textM, sizeLimit);
1352 }
1353 
drawText_asPaths(const char text[],size_t byteLength,SkScalar x,SkScalar y,const SkPaint & paint) const1354 void SkDraw::drawText_asPaths(const char text[], size_t byteLength, SkScalar x, SkScalar y,
1355                               const SkPaint& paint) const {
1356     SkDEBUGCODE(this->validate();)
1357 
1358     SkTextToPathIter iter(text, byteLength, paint, true);
1359 
1360     SkMatrix    matrix;
1361     matrix.setScale(iter.getPathScale(), iter.getPathScale());
1362     matrix.postTranslate(x, y);
1363 
1364     const SkPath* iterPath;
1365     SkScalar xpos, prevXPos = 0;
1366 
1367     while (iter.next(&iterPath, &xpos)) {
1368         matrix.postTranslate(xpos - prevXPos, 0);
1369         if (iterPath) {
1370             this->drawPath(*iterPath, iter.getPaint(), &matrix, false);
1371         }
1372         prevXPos = xpos;
1373     }
1374 }
1375 
1376 // disable warning : local variable used without having been initialized
1377 #if defined _WIN32
1378 #pragma warning ( push )
1379 #pragma warning ( disable : 4701 )
1380 #endif
1381 
1382 ////////////////////////////////////////////////////////////////////////////////////////////////////
1383 
1384 class DrawOneGlyph {
1385 public:
DrawOneGlyph(const SkDraw & draw,const SkPaint & paint,SkGlyphCache * cache,SkBlitter * blitter)1386     DrawOneGlyph(const SkDraw& draw, const SkPaint& paint, SkGlyphCache* cache, SkBlitter* blitter)
1387         : fUseRegionToDraw(UsingRegionToDraw(draw.fRC))
1388         , fGlyphCache(cache)
1389         , fBlitter(blitter)
1390         , fClip(fUseRegionToDraw ? &draw.fRC->bwRgn() : nullptr)
1391         , fDraw(draw)
1392         , fPaint(paint)
1393         , fClipBounds(PickClipBounds(draw)) { }
1394 
operator ()(const SkGlyph & glyph,SkPoint position,SkPoint rounding)1395     void operator()(const SkGlyph& glyph, SkPoint position, SkPoint rounding) {
1396         position += rounding;
1397         // Prevent glyphs from being drawn outside of or straddling the edge of device space.
1398         // Comparisons written a little weirdly so that NaN coordinates are treated safely.
1399         auto gt = [](float a, int b) { return !(a <= (float)b); };
1400         auto lt = [](float a, int b) { return !(a >= (float)b); };
1401         if (gt(position.fX, INT_MAX - (INT16_MAX + UINT16_MAX)) ||
1402             lt(position.fX, INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/)) ||
1403             gt(position.fY, INT_MAX - (INT16_MAX + UINT16_MAX)) ||
1404             lt(position.fY, INT_MIN - (INT16_MIN + 0 /*UINT16_MIN*/))) {
1405             return;
1406         }
1407 
1408         int left = SkScalarFloorToInt(position.fX);
1409         int top  = SkScalarFloorToInt(position.fY);
1410         SkASSERT(glyph.fWidth > 0 && glyph.fHeight > 0);
1411 
1412         left += glyph.fLeft;
1413         top  += glyph.fTop;
1414 
1415         int right   = left + glyph.fWidth;
1416         int bottom  = top  + glyph.fHeight;
1417 
1418         SkMask mask;
1419         mask.fBounds.set(left, top, right, bottom);
1420         SkASSERT(!mask.fBounds.isEmpty());
1421 
1422         if (fUseRegionToDraw) {
1423             SkRegion::Cliperator clipper(*fClip, mask.fBounds);
1424 
1425             if (!clipper.done() && this->getImageData(glyph, &mask)) {
1426                 const SkIRect& cr = clipper.rect();
1427                 do {
1428                     this->blitMask(mask, cr);
1429                     clipper.next();
1430                 } while (!clipper.done());
1431             }
1432         } else {
1433             SkIRect  storage;
1434             SkIRect* bounds = &mask.fBounds;
1435 
1436             // this extra test is worth it, assuming that most of the time it succeeds
1437             // since we can avoid writing to storage
1438             if (!fClipBounds.containsNoEmptyCheck(mask.fBounds)) {
1439                 if (!storage.intersectNoEmptyCheck(mask.fBounds, fClipBounds))
1440                     return;
1441                 bounds = &storage;
1442             }
1443 
1444             if (this->getImageData(glyph, &mask)) {
1445                 this->blitMask(mask, *bounds);
1446             }
1447         }
1448     }
1449 
1450 private:
UsingRegionToDraw(const SkRasterClip * rClip)1451     static bool UsingRegionToDraw(const SkRasterClip* rClip) {
1452         return rClip->isBW() && !rClip->isRect();
1453     }
1454 
PickClipBounds(const SkDraw & draw)1455     static SkIRect PickClipBounds(const SkDraw& draw) {
1456         const SkRasterClip& rasterClip = *draw.fRC;
1457 
1458         if (rasterClip.isBW()) {
1459             return rasterClip.bwRgn().getBounds();
1460         } else {
1461             return rasterClip.aaRgn().getBounds();
1462         }
1463     }
1464 
getImageData(const SkGlyph & glyph,SkMask * mask)1465     bool getImageData(const SkGlyph& glyph, SkMask* mask) {
1466         uint8_t* bits = (uint8_t*)(fGlyphCache->findImage(glyph));
1467         if (nullptr == bits) {
1468             return false;  // can't rasterize glyph
1469         }
1470         mask->fImage    = bits;
1471         mask->fRowBytes = glyph.rowBytes();
1472         mask->fFormat   = static_cast<SkMask::Format>(glyph.fMaskFormat);
1473         return true;
1474     }
1475 
blitMask(const SkMask & mask,const SkIRect & clip) const1476     void blitMask(const SkMask& mask, const SkIRect& clip) const {
1477         if (SkMask::kARGB32_Format == mask.fFormat) {
1478             SkBitmap bm;
1479             bm.installPixels(
1480                 SkImageInfo::MakeN32Premul(mask.fBounds.width(), mask.fBounds.height()),
1481                 (SkPMColor*)mask.fImage, mask.fRowBytes);
1482 
1483             fDraw.drawSprite(bm, mask.fBounds.x(), mask.fBounds.y(), fPaint);
1484         } else {
1485             fBlitter->blitMask(mask, clip);
1486         }
1487     }
1488 
1489     const bool            fUseRegionToDraw;
1490     SkGlyphCache  * const fGlyphCache;
1491     SkBlitter     * const fBlitter;
1492     const SkRegion* const fClip;
1493     const SkDraw&         fDraw;
1494     const SkPaint&        fPaint;
1495     const SkIRect         fClipBounds;
1496 };
1497 
1498 ////////////////////////////////////////////////////////////////////////////////////////////////////
1499 
scalerContextFlags() const1500 SkScalerContextFlags SkDraw::scalerContextFlags() const {
1501     SkScalerContextFlags flags = SkScalerContextFlags::kBoostContrast;
1502     if (!fDst.colorSpace()) {
1503         flags = kFakeGammaAndBoostContrast;
1504     }
1505     return flags;
1506 }
1507 
drawText(const char text[],size_t byteLength,SkScalar x,SkScalar y,const SkPaint & paint,const SkSurfaceProps * props) const1508 void SkDraw::drawText(const char text[], size_t byteLength, SkScalar x, SkScalar y,
1509                       const SkPaint& paint, const SkSurfaceProps* props) const {
1510     SkASSERT(byteLength == 0 || text != nullptr);
1511 
1512     SkDEBUGCODE(this->validate();)
1513 
1514     // nothing to draw
1515     if (text == nullptr || byteLength == 0 || fRC->isEmpty()) {
1516         return;
1517     }
1518 
1519     // SkScalarRec doesn't currently have a way of representing hairline stroke and
1520     // will fill if its frame-width is 0.
1521     if (ShouldDrawTextAsPaths(paint, *fMatrix)) {
1522         this->drawText_asPaths(text, byteLength, x, y, paint);
1523         return;
1524     }
1525 
1526     SkAutoGlyphCache cache(paint, props, this->scalerContextFlags(), fMatrix);
1527 
1528     // The Blitter Choose needs to be live while using the blitter below.
1529     SkAutoBlitterChoose    blitterChooser(fDst, *fMatrix, paint);
1530     SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get());
1531     DrawOneGlyph           drawOneGlyph(*this, paint, cache.get(), wrapper.getBlitter());
1532 
1533     SkFindAndPlaceGlyph::ProcessText(
1534         paint.getTextEncoding(), text, byteLength,
1535         {x, y}, *fMatrix, paint.getTextAlign(), cache.get(), drawOneGlyph);
1536 }
1537 
1538 //////////////////////////////////////////////////////////////////////////////
1539 
drawPosText_asPaths(const char text[],size_t byteLength,const SkScalar pos[],int scalarsPerPosition,const SkPoint & offset,const SkPaint & origPaint,const SkSurfaceProps * props) const1540 void SkDraw::drawPosText_asPaths(const char text[], size_t byteLength, const SkScalar pos[],
1541                                  int scalarsPerPosition, const SkPoint& offset,
1542                                  const SkPaint& origPaint, const SkSurfaceProps* props) const {
1543     // setup our std paint, in hopes of getting hits in the cache
1544     SkPaint paint(origPaint);
1545     SkScalar matrixScale = paint.setupForAsPaths();
1546 
1547     SkMatrix matrix;
1548     matrix.setScale(matrixScale, matrixScale);
1549 
1550     // Temporarily jam in kFill, so we only ever ask for the raw outline from the cache.
1551     paint.setStyle(SkPaint::kFill_Style);
1552     paint.setPathEffect(nullptr);
1553 
1554     SkPaint::GlyphCacheProc glyphCacheProc = SkPaint::GetGlyphCacheProc(paint.getTextEncoding(),
1555                                                                         paint.isDevKernText(),
1556                                                                         true);
1557     SkAutoGlyphCache cache(paint, props, this->scalerContextFlags(), nullptr);
1558 
1559     const char*        stop = text + byteLength;
1560     SkTextAlignProc    alignProc(paint.getTextAlign());
1561     SkTextMapStateProc tmsProc(SkMatrix::I(), offset, scalarsPerPosition);
1562 
1563     // Now restore the original settings, so we "draw" with whatever style/stroking.
1564     paint.setStyle(origPaint.getStyle());
1565     paint.setPathEffect(origPaint.refPathEffect());
1566 
1567     while (text < stop) {
1568         const SkGlyph& glyph = glyphCacheProc(cache.get(), &text);
1569         if (glyph.fWidth) {
1570             const SkPath* path = cache->findPath(glyph);
1571             if (path) {
1572                 SkPoint tmsLoc;
1573                 tmsProc(pos, &tmsLoc);
1574                 SkPoint loc;
1575                 alignProc(tmsLoc, glyph, &loc);
1576 
1577                 matrix[SkMatrix::kMTransX] = loc.fX;
1578                 matrix[SkMatrix::kMTransY] = loc.fY;
1579                 this->drawPath(*path, paint, &matrix, false);
1580             }
1581         }
1582         pos += scalarsPerPosition;
1583     }
1584 }
1585 
drawPosText(const char text[],size_t byteLength,const SkScalar pos[],int scalarsPerPosition,const SkPoint & offset,const SkPaint & paint,const SkSurfaceProps * props) const1586 void SkDraw::drawPosText(const char text[], size_t byteLength, const SkScalar pos[],
1587                          int scalarsPerPosition, const SkPoint& offset, const SkPaint& paint,
1588                          const SkSurfaceProps* props) const {
1589     SkASSERT(byteLength == 0 || text != nullptr);
1590     SkASSERT(1 == scalarsPerPosition || 2 == scalarsPerPosition);
1591 
1592     SkDEBUGCODE(this->validate();)
1593 
1594     // nothing to draw
1595     if (text == nullptr || byteLength == 0 || fRC->isEmpty()) {
1596         return;
1597     }
1598 
1599     if (ShouldDrawTextAsPaths(paint, *fMatrix)) {
1600         this->drawPosText_asPaths(text, byteLength, pos, scalarsPerPosition, offset, paint, props);
1601         return;
1602     }
1603 
1604     SkAutoGlyphCache cache(paint, props, this->scalerContextFlags(), fMatrix);
1605 
1606     // The Blitter Choose needs to be live while using the blitter below.
1607     SkAutoBlitterChoose    blitterChooser(fDst, *fMatrix, paint);
1608     SkAAClipBlitterWrapper wrapper(*fRC, blitterChooser.get());
1609     DrawOneGlyph           drawOneGlyph(*this, paint, cache.get(), wrapper.getBlitter());
1610     SkPaint::Align         textAlignment = paint.getTextAlign();
1611 
1612     SkFindAndPlaceGlyph::ProcessPosText(
1613         paint.getTextEncoding(), text, byteLength,
1614         offset, *fMatrix, pos, scalarsPerPosition, textAlignment, cache.get(), drawOneGlyph);
1615 }
1616 
1617 #if defined _WIN32
1618 #pragma warning ( pop )
1619 #endif
1620 
1621 ////////////////////////////////////////////////////////////////////////////////////////////////
1622 
1623 #ifdef SK_DEBUG
1624 
validate() const1625 void SkDraw::validate() const {
1626     SkASSERT(fMatrix != nullptr);
1627     SkASSERT(fRC != nullptr);
1628 
1629     const SkIRect&  cr = fRC->getBounds();
1630     SkIRect         br;
1631 
1632     br.set(0, 0, fDst.width(), fDst.height());
1633     SkASSERT(cr.isEmpty() || br.contains(cr));
1634 }
1635 
1636 #endif
1637 
1638 ////////////////////////////////////////////////////////////////////////////////////////////////
1639 
1640 #include "SkPath.h"
1641 #include "SkDraw.h"
1642 #include "SkRegion.h"
1643 #include "SkBlitter.h"
1644 
compute_bounds(const SkPath & devPath,const SkIRect * clipBounds,const SkMaskFilter * filter,const SkMatrix * filterMatrix,SkIRect * bounds)1645 static bool compute_bounds(const SkPath& devPath, const SkIRect* clipBounds,
1646                            const SkMaskFilter* filter, const SkMatrix* filterMatrix,
1647                            SkIRect* bounds) {
1648     if (devPath.isEmpty()) {
1649         return false;
1650     }
1651 
1652     //  init our bounds from the path
1653     *bounds = devPath.getBounds().makeOutset(SK_ScalarHalf, SK_ScalarHalf).roundOut();
1654 
1655     SkIPoint margin = SkIPoint::Make(0, 0);
1656     if (filter) {
1657         SkASSERT(filterMatrix);
1658 
1659         SkMask srcM, dstM;
1660 
1661         srcM.fBounds = *bounds;
1662         srcM.fFormat = SkMask::kA8_Format;
1663         if (!as_MFB(filter)->filterMask(&dstM, srcM, *filterMatrix, &margin)) {
1664             return false;
1665         }
1666     }
1667 
1668     // (possibly) trim the bounds to reflect the clip
1669     // (plus whatever slop the filter needs)
1670     if (clipBounds) {
1671         // Ugh. Guard against gigantic margins from wacky filters. Without this
1672         // check we can request arbitrary amounts of slop beyond our visible
1673         // clip, and bring down the renderer (at least on finite RAM machines
1674         // like handsets, etc.). Need to balance this invented value between
1675         // quality of large filters like blurs, and the corresponding memory
1676         // requests.
1677         static const int MAX_MARGIN = 128;
1678         if (!bounds->intersect(clipBounds->makeOutset(SkMin32(margin.fX, MAX_MARGIN),
1679                                                       SkMin32(margin.fY, MAX_MARGIN)))) {
1680             return false;
1681         }
1682     }
1683 
1684     return true;
1685 }
1686 
draw_into_mask(const SkMask & mask,const SkPath & devPath,SkStrokeRec::InitStyle style)1687 static void draw_into_mask(const SkMask& mask, const SkPath& devPath,
1688                            SkStrokeRec::InitStyle style) {
1689     SkDraw draw;
1690     if (!draw.fDst.reset(mask)) {
1691         return;
1692     }
1693 
1694     SkRasterClip    clip;
1695     SkMatrix        matrix;
1696     SkPaint         paint;
1697 
1698     clip.setRect(SkIRect::MakeWH(mask.fBounds.width(), mask.fBounds.height()));
1699     matrix.setTranslate(-SkIntToScalar(mask.fBounds.fLeft),
1700                         -SkIntToScalar(mask.fBounds.fTop));
1701 
1702     draw.fRC        = &clip;
1703     draw.fMatrix    = &matrix;
1704     paint.setAntiAlias(true);
1705     switch (style) {
1706         case SkStrokeRec::kHairline_InitStyle:
1707             SkASSERT(!paint.getStrokeWidth());
1708             paint.setStyle(SkPaint::kStroke_Style);
1709             break;
1710         case SkStrokeRec::kFill_InitStyle:
1711             SkASSERT(paint.getStyle() == SkPaint::kFill_Style);
1712             break;
1713 
1714     }
1715     draw.drawPath(devPath, paint);
1716 }
1717 
DrawToMask(const SkPath & devPath,const SkIRect * clipBounds,const SkMaskFilter * filter,const SkMatrix * filterMatrix,SkMask * mask,SkMask::CreateMode mode,SkStrokeRec::InitStyle style)1718 bool SkDraw::DrawToMask(const SkPath& devPath, const SkIRect* clipBounds,
1719                         const SkMaskFilter* filter, const SkMatrix* filterMatrix,
1720                         SkMask* mask, SkMask::CreateMode mode,
1721                         SkStrokeRec::InitStyle style) {
1722     if (SkMask::kJustRenderImage_CreateMode != mode) {
1723         if (!compute_bounds(devPath, clipBounds, filter, filterMatrix, &mask->fBounds))
1724             return false;
1725     }
1726 
1727     if (SkMask::kComputeBoundsAndRenderImage_CreateMode == mode) {
1728         mask->fFormat = SkMask::kA8_Format;
1729         mask->fRowBytes = mask->fBounds.width();
1730         size_t size = mask->computeImageSize();
1731         if (0 == size) {
1732             // we're too big to allocate the mask, abort
1733             return false;
1734         }
1735         mask->fImage = SkMask::AllocImage(size, SkMask::kZeroInit_Alloc);
1736     }
1737 
1738     if (SkMask::kJustComputeBounds_CreateMode != mode) {
1739         draw_into_mask(*mask, devPath, style);
1740     }
1741 
1742     return true;
1743 }
1744