1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/*
2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2017 Google Inc.
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#include "SkThreadedBMPDevice.h"
9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkPath.h"
11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkRectPriv.h"
12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkTaskGroup.h"
13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkVertices.h"
14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkThreadedBMPDevice::DrawQueue::reset() {
16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (fTasks) {
17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fTasks->finish();
18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fSize = 0;
21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // using TaskGroup2D = SkSpinningTaskGroup2D;
23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    using TaskGroup2D = SkFlexibleTaskGroup2D;
24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    auto draw2D = [this](int row, int column){
25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkThreadedBMPDevice::DrawElement& element = fElements[column];
26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (!SkIRect::Intersects(fDevice->fTileBounds[row], element.fDrawBounds)) {
27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return;
28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        element.fDrawFn(nullptr, element.fDS, fDevice->fTileBounds[row]);
30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    };
31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fTasks.reset(new TaskGroup2D(draw2D, fDevice->fTileCnt, fDevice->fExecutor,
32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                 fDevice->fThreadCnt));
33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fTasks->start();
34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkThreadedBMPDevice::SkThreadedBMPDevice(const SkBitmap& bitmap,
37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                         int tiles,
38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                         int threads,
39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                         SkExecutor* executor)
40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        : INHERITED(bitmap)
41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        , fTileCnt(tiles)
42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        , fThreadCnt(threads <= 0 ? tiles : threads)
43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        , fQueue(this)
44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot{
45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (executor == nullptr) {
46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fInternalExecutor = SkExecutor::MakeFIFOThreadPool(fThreadCnt);
47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        executor = fInternalExecutor.get();
48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fExecutor = executor;
50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // Tiling using stripes for now; we'll explore better tiling in the future.
52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int h = (bitmap.height() + fTileCnt - 1) / SkTMax(fTileCnt, 1);
53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int w = bitmap.width();
54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int top = 0;
55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for(int tid = 0; tid < fTileCnt; ++tid, top += h) {
56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fTileBounds.push_back(SkIRect::MakeLTRB(0, top, w, top + h));
57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fQueue.reset();
59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkThreadedBMPDevice::flush() {
62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fQueue.reset();
63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkThreadedBMPDevice::DrawState::DrawState(SkThreadedBMPDevice* dev) {
66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // we need fDst to be set, and if we're actually drawing, to dirty the genID
67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (!dev->accessPixels(&fDst)) {
68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        // NoDrawDevice uses us (why?) so we have to catch this case w/ no pixels
69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        fDst.reset(dev->imageInfo(), nullptr, 0);
70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fMatrix = dev->ctm();
72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fRC = dev->fRCStack.rc();
73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkIRect SkThreadedBMPDevice::transformDrawBounds(const SkRect& drawBounds) const {
76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (drawBounds == SkRectPriv::MakeLargest()) {
77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return SkRectPriv::MakeILarge();
78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkRect transformedBounds;
80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->ctm().mapRect(&transformedBounds, drawBounds);
81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return transformedBounds.roundOut();
82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkDraw SkThreadedBMPDevice::DrawState::getDraw() const {
85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDraw draw;
86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    draw.fDst = fDst;
87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    draw.fMatrix = &fMatrix;
88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    draw.fRC = &fRC;
89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return draw;
90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotSkThreadedBMPDevice::TileDraw::TileDraw(const DrawState& ds, const SkIRect& tileBounds)
93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        : fTileRC(ds.fRC) {
94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fDst = ds.fDst;
95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fMatrix = &ds.fMatrix;
96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fTileRC.op(tileBounds, SkRegion::kIntersect_Op);
97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fRC = &fTileRC;
98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic inline SkRect get_fast_bounds(const SkRect& r, const SkPaint& p) {
101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkRect result;
102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    if (p.canComputeFastBounds()) {
103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        result = p.computeFastBounds(r, &result);
104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    } else {
105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        result = SkRectPriv::MakeLargest();
106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return result;
108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkThreadedBMPDevice::drawPaint(const SkPaint& paint) {
111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkRect drawBounds = SkRectPriv::MakeLargest();
112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        TileDraw(ds, tileBounds).drawPaint(paint);
114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    });
115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkThreadedBMPDevice::drawPoints(SkCanvas::PointMode mode, size_t count,
118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkPoint pts[], const SkPaint& paint) {
119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkRect drawBounds = SkRectPriv::MakeLargest(); // TODO tighter drawBounds
120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        TileDraw(ds, tileBounds).drawPoints(mode, count, pts, paint, nullptr);
122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    });
123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkThreadedBMPDevice::drawRect(const SkRect& r, const SkPaint& paint) {
126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkRect drawBounds = get_fast_bounds(r, paint);
127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        TileDraw(ds, tileBounds).drawRect(r, paint);
129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    });
130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkThreadedBMPDevice::drawRRect(const SkRRect& rrect, const SkPaint& paint) {
133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#ifdef SK_IGNORE_BLURRED_RRECT_OPT
134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkPath  path;
135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    path.addRRect(rrect);
137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // call the VIRTUAL version, so any subclasses who do handle drawPath aren't
138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    // required to override drawRRect.
139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    this->drawPath(path, paint, nullptr, false);
140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#else
141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkRect drawBounds = get_fast_bounds(rrect.getBounds(), paint);
142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        TileDraw(ds, tileBounds).drawRRect(rrect, paint);
144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    });
145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#endif
146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
148fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkThreadedBMPDevice::drawPath(const SkPath& path, const SkPaint& paint,
149fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkMatrix* prePathMatrix, bool pathIsMutable) {
150fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkRect drawBounds = path.isInverseFillType() ? SkRectPriv::MakeLargest()
151fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                                 : get_fast_bounds(path.getBounds(), paint);
152fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds) {
153fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        TileDraw(ds, tileBounds).drawPath(path, paint, prePathMatrix, false);
154fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    });
155fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
156fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
157fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkThreadedBMPDevice::drawBitmap(const SkBitmap& bitmap, SkScalar x, SkScalar y,
158fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkPaint& paint) {
159fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkMatrix matrix = SkMatrix::MakeTrans(x, y);
160fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    LogDrawScaleFactor(SkMatrix::Concat(this->ctm(), matrix), paint.getFilterQuality());
161fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkRect drawBounds = SkRect::MakeWH(bitmap.width(), bitmap.height());
162fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    matrix.mapRect(&drawBounds);
163fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
164fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        TileDraw(ds, tileBounds).drawBitmap(bitmap, matrix, nullptr, paint);
165fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    });
166fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
167fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
168fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkThreadedBMPDevice::drawSprite(const SkBitmap& bitmap, int x, int y, const SkPaint& paint) {
169fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkRect drawBounds = SkRect::MakeXYWH(x, y, bitmap.width(), bitmap.height());
170fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
171fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        TileDraw(ds, tileBounds).drawSprite(bitmap, x, y, paint);
172fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    });
173fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
174fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
175fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkThreadedBMPDevice::drawText(const void* text, size_t len, SkScalar x, SkScalar y,
176fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkPaint& paint) {
177fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkRect drawBounds = SkRectPriv::MakeLargest(); // TODO tighter drawBounds
178fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
179fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        TileDraw(ds, tileBounds).drawText((const char*)text, len, x, y, paint,
180fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                          &this->surfaceProps());
181fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    });
182fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
183fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
184fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkThreadedBMPDevice::drawPosText(const void* text, size_t len, const SkScalar xpos[],
185fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        int scalarsPerPos, const SkPoint& offset, const SkPaint& paint) {
186fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkRect drawBounds = SkRectPriv::MakeLargest(); // TODO tighter drawBounds
187fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
188fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        TileDraw(ds, tileBounds).drawPosText((const char*)text, len, xpos, scalarsPerPos, offset,
189fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                             paint, &surfaceProps());
190fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    });
191fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
192fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
193fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkThreadedBMPDevice::drawVertices(const SkVertices* vertices, SkBlendMode bmode,
194fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const SkPaint& paint) {
195fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkRect drawBounds = SkRectPriv::MakeLargest(); // TODO tighter drawBounds
196fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
197fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        TileDraw(ds, tileBounds).drawVertices(vertices->mode(), vertices->vertexCount(),
198fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                              vertices->positions(), vertices->texCoords(),
199fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                              vertices->colors(), bmode, vertices->indices(),
200fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                              vertices->indexCount(), paint);
201fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    });
202fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
203fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
204fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotvoid SkThreadedBMPDevice::drawDevice(SkBaseDevice* device, int x, int y, const SkPaint& paint) {
205fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkASSERT(!paint.getImageFilter());
206fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkRect drawBounds = SkRect::MakeXYWH(x, y, device->width(), device->height());
207fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    fQueue.push(drawBounds, [=](SkArenaAlloc*, const DrawState& ds, const SkIRect& tileBounds){
208fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        TileDraw(ds, tileBounds).drawSprite(static_cast<SkBitmapDevice*>(device)->fBitmap,
209fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                                            x, y, paint);
210fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    });
211fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
212