Home | History | Annotate | Download | only in core
      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 
     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 
     51 SkDraw::SkDraw() {
     52     sk_bzero(this, sizeof(*this));
     53 }
     54 
     55 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 
     76 static void D_Clear_BitmapXferProc(void* pixels, size_t bytes, uint32_t) {
     77     sk_bzero(pixels, bytes);
     78 }
     79 
     80 static void D_Dst_BitmapXferProc(void*, size_t, uint32_t data) {}
     81 
     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 
     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 
     90 static void DA8_Src_BitmapXferProc(void* pixels, size_t bytes, uint32_t data) {
     91     memset(pixels, data, bytes);
     92 }
     93 
     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 
    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 
    188 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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    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
    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 
    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 
    473 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 
    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 
    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 
    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 
    716 static const SkPoint* rect_points(const SkRect& r) {
    717     return SkTCast<const SkPoint*>(&r);
    718 }
    719 
    720 static SkPoint* rect_points(SkRect& r) {
    721     return SkTCast<SkPoint*>(&r);
    722 }
    723 
    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 
    734 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 
    836 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 
    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 
    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 
    899 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 
    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 
    953 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 
   1036 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 
   1117 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 
   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 
   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 
   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 
   1214 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 
   1280 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 
   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 
   1354 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:
   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 
   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:
   1451     static bool UsingRegionToDraw(const SkRasterClip* rClip) {
   1452         return rClip->isBW() && !rClip->isRect();
   1453     }
   1454 
   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 
   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 
   1476     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 
   1500 SkScalerContextFlags SkDraw::scalerContextFlags() const {
   1501     SkScalerContextFlags flags = SkScalerContextFlags::kBoostContrast;
   1502     if (!fDst.colorSpace()) {
   1503         flags = kFakeGammaAndBoostContrast;
   1504     }
   1505     return flags;
   1506 }
   1507 
   1508 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 
   1540 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 
   1586 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 
   1625 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 
   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 
   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 
   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