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