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