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