DisplayListCanvas.cpp revision 003cc3dec8e2a92e51086fbcd5ee1bb236efa701
1/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "DisplayListCanvas.h"
18
19#include "ResourceCache.h"
20#include "DeferredDisplayList.h"
21#include "DeferredLayerUpdater.h"
22#include "DisplayListOp.h"
23#include "RenderNode.h"
24#include "utils/PaintUtils.h"
25
26#include <SkCamera.h>
27#include <SkCanvas.h>
28
29#include <private/hwui/DrawGlInfo.h>
30
31namespace android {
32namespace uirenderer {
33
34DisplayListCanvas::DisplayListCanvas(int width, int height)
35    : mState(*this)
36    , mResourceCache(ResourceCache::getInstance())
37    , mDisplayList(nullptr)
38    , mTranslateX(0.0f)
39    , mTranslateY(0.0f)
40    , mHasDeferredTranslate(false)
41    , mDeferredBarrierType(kBarrier_None)
42    , mHighContrastText(false)
43    , mRestoreSaveCount(-1) {
44    reset(width, height);
45}
46
47DisplayListCanvas::~DisplayListCanvas() {
48    LOG_ALWAYS_FATAL_IF(mDisplayList,
49            "Destroyed a DisplayListCanvas during a record!");
50}
51
52void DisplayListCanvas::reset(int width, int height) {
53    LOG_ALWAYS_FATAL_IF(mDisplayList,
54            "prepareDirty called a second time during a recording!");
55    mDisplayList = new DisplayList();
56
57    mState.initializeSaveStack(width, height,
58            0, 0, width, height, Vector3());
59
60    mDeferredBarrierType = kBarrier_InOrder;
61    mState.setDirtyClip(false);
62    mRestoreSaveCount = -1;
63}
64
65
66///////////////////////////////////////////////////////////////////////////////
67// Operations
68///////////////////////////////////////////////////////////////////////////////
69
70DisplayList* DisplayListCanvas::finishRecording() {
71    flushRestoreToCount();
72    flushTranslate();
73
74    mPaintMap.clear();
75    mRegionMap.clear();
76    mPathMap.clear();
77    DisplayList* displayList = mDisplayList;
78    mDisplayList = nullptr;
79    mSkiaCanvasProxy.reset(nullptr);
80    return displayList;
81}
82
83void DisplayListCanvas::callDrawGLFunction(Functor *functor) {
84    addDrawOp(new (alloc()) DrawFunctorOp(functor));
85    mDisplayList->functors.add(functor);
86}
87
88SkCanvas* DisplayListCanvas::asSkCanvas() {
89    LOG_ALWAYS_FATAL_IF(!mDisplayList,
90            "attempting to get an SkCanvas when we are not recording!");
91    if (!mSkiaCanvasProxy) {
92        mSkiaCanvasProxy.reset(new SkiaCanvasProxy(this));
93    }
94
95    // SkCanvas instances default to identity transform, but should inherit
96    // the state of this Canvas; if this code was in the SkiaCanvasProxy
97    // constructor, we couldn't cache mSkiaCanvasProxy.
98    SkMatrix parentTransform;
99    getMatrix(&parentTransform);
100    mSkiaCanvasProxy.get()->setMatrix(parentTransform);
101
102    return mSkiaCanvasProxy.get();
103}
104
105int DisplayListCanvas::save(SkCanvas::SaveFlags flags) {
106    addStateOp(new (alloc()) SaveOp((int) flags));
107    return mState.save((int) flags);
108}
109
110void DisplayListCanvas::restore() {
111    if (mRestoreSaveCount < 0) {
112        restoreToCount(getSaveCount() - 1);
113        return;
114    }
115
116    mRestoreSaveCount--;
117    flushTranslate();
118    mState.restore();
119}
120
121void DisplayListCanvas::restoreToCount(int saveCount) {
122    mRestoreSaveCount = saveCount;
123    flushTranslate();
124    mState.restoreToCount(saveCount);
125}
126
127int DisplayListCanvas::saveLayer(float left, float top, float right, float bottom,
128        const SkPaint* paint, SkCanvas::SaveFlags flags) {
129    // force matrix/clip isolation for layer
130    flags |= SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag;
131
132    paint = refPaint(paint);
133    addStateOp(new (alloc()) SaveLayerOp(left, top, right, bottom, paint, (int) flags));
134    return mState.save((int) flags);
135}
136
137void DisplayListCanvas::translate(float dx, float dy) {
138    if (dx == 0.0f && dy == 0.0f) return;
139
140    mHasDeferredTranslate = true;
141    mTranslateX += dx;
142    mTranslateY += dy;
143    flushRestoreToCount();
144    mState.translate(dx, dy, 0.0f);
145}
146
147void DisplayListCanvas::rotate(float degrees) {
148    if (degrees == 0.0f) return;
149
150    addStateOp(new (alloc()) RotateOp(degrees));
151    mState.rotate(degrees);
152}
153
154void DisplayListCanvas::scale(float sx, float sy) {
155    if (sx == 1.0f && sy == 1.0f) return;
156
157    addStateOp(new (alloc()) ScaleOp(sx, sy));
158    mState.scale(sx, sy);
159}
160
161void DisplayListCanvas::skew(float sx, float sy) {
162    addStateOp(new (alloc()) SkewOp(sx, sy));
163    mState.skew(sx, sy);
164}
165
166void DisplayListCanvas::setMatrix(const SkMatrix& matrix) {
167    addStateOp(new (alloc()) SetMatrixOp(matrix));
168    mState.setMatrix(matrix);
169}
170
171void DisplayListCanvas::concat(const SkMatrix& matrix) {
172    addStateOp(new (alloc()) ConcatMatrixOp(matrix));
173    mState.concatMatrix(matrix);
174}
175
176bool DisplayListCanvas::getClipBounds(SkRect* outRect) const {
177    Rect bounds = mState.getLocalClipBounds();
178    *outRect = SkRect::MakeLTRB(bounds.left, bounds.top, bounds.right, bounds.bottom);
179    return !(outRect->isEmpty());
180}
181
182bool DisplayListCanvas::quickRejectRect(float left, float top, float right, float bottom) const {
183    return mState.quickRejectConservative(left, top, right, bottom);
184}
185
186bool DisplayListCanvas::quickRejectPath(const SkPath& path) const {
187    SkRect bounds = path.getBounds();
188    return mState.quickRejectConservative(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
189}
190
191
192bool DisplayListCanvas::clipRect(float left, float top, float right, float bottom,
193        SkRegion::Op op) {
194    addStateOp(new (alloc()) ClipRectOp(left, top, right, bottom, op));
195    return mState.clipRect(left, top, right, bottom, op);
196}
197
198bool DisplayListCanvas::clipPath(const SkPath* path, SkRegion::Op op) {
199    path = refPath(path);
200    addStateOp(new (alloc()) ClipPathOp(path, op));
201    return mState.clipPath(path, op);
202}
203
204bool DisplayListCanvas::clipRegion(const SkRegion* region, SkRegion::Op op) {
205    region = refRegion(region);
206    addStateOp(new (alloc()) ClipRegionOp(region, op));
207    return mState.clipRegion(region, op);
208}
209
210void DisplayListCanvas::drawRenderNode(RenderNode* renderNode) {
211    LOG_ALWAYS_FATAL_IF(!renderNode, "missing rendernode");
212    DrawRenderNodeOp* op = new (alloc()) DrawRenderNodeOp(
213            renderNode,
214            *mState.currentTransform(),
215            mState.clipIsSimple());
216    addRenderNodeOp(op);
217}
218
219void DisplayListCanvas::drawLayer(DeferredLayerUpdater* layerHandle) {
220    // We ref the DeferredLayerUpdater due to its thread-safe ref-counting
221    // semantics.
222    mDisplayList->ref(layerHandle);
223    addDrawOp(new (alloc()) DrawLayerOp(layerHandle->backingLayer()));
224}
225
226void DisplayListCanvas::drawBitmap(const SkBitmap* bitmap, const SkPaint* paint) {
227    bitmap = refBitmap(*bitmap);
228    paint = refPaint(paint);
229
230    addDrawOp(new (alloc()) DrawBitmapOp(bitmap, paint));
231}
232
233void DisplayListCanvas::drawBitmap(const SkBitmap& bitmap, float left, float top,
234        const SkPaint* paint) {
235    save(SkCanvas::kMatrix_SaveFlag);
236    translate(left, top);
237    drawBitmap(&bitmap, paint);
238    restore();
239}
240
241void DisplayListCanvas::drawBitmap(const SkBitmap& bitmap, const SkMatrix& matrix,
242        const SkPaint* paint) {
243    if (matrix.isIdentity()) {
244        drawBitmap(&bitmap, paint);
245    } else if (!(matrix.getType() & ~(SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask))
246            && MathUtils::isPositive(matrix.getScaleX())
247            && MathUtils::isPositive(matrix.getScaleY())) {
248        // SkMatrix::isScaleTranslate() not available in L
249        SkRect src;
250        SkRect dst;
251        bitmap.getBounds(&src);
252        matrix.mapRect(&dst, src);
253        drawBitmap(bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom,
254                   dst.fLeft, dst.fTop, dst.fRight, dst.fBottom, paint);
255    } else {
256        save(SkCanvas::kMatrix_SaveFlag);
257        concat(matrix);
258        drawBitmap(&bitmap, paint);
259        restore();
260    }
261}
262
263void DisplayListCanvas::drawBitmap(const SkBitmap& bitmap, float srcLeft, float srcTop,
264        float srcRight, float srcBottom, float dstLeft, float dstTop,
265        float dstRight, float dstBottom, const SkPaint* paint) {
266    if (srcLeft == 0 && srcTop == 0
267            && srcRight == bitmap.width()
268            && srcBottom == bitmap.height()
269            && (srcBottom - srcTop == dstBottom - dstTop)
270            && (srcRight - srcLeft == dstRight - dstLeft)) {
271        // transform simple rect to rect drawing case into position bitmap ops, since they merge
272        save(SkCanvas::kMatrix_SaveFlag);
273        translate(dstLeft, dstTop);
274        drawBitmap(&bitmap, paint);
275        restore();
276    } else {
277        paint = refPaint(paint);
278
279        if (paint && paint->getShader()) {
280            float scaleX = (dstRight - dstLeft) / (srcRight - srcLeft);
281            float scaleY = (dstBottom - dstTop) / (srcBottom - srcTop);
282            if (!MathUtils::areEqual(scaleX, 1.0f) || !MathUtils::areEqual(scaleY, 1.0f)) {
283                // Apply the scale transform on the canvas, so that the shader
284                // effectively calculates positions relative to src rect space
285
286                save(SkCanvas::kMatrix_SaveFlag);
287                translate(dstLeft, dstTop);
288                scale(scaleX, scaleY);
289
290                dstLeft = 0.0f;
291                dstTop = 0.0f;
292                dstRight = srcRight - srcLeft;
293                dstBottom = srcBottom - srcTop;
294
295                addDrawOp(new (alloc()) DrawBitmapRectOp(refBitmap(bitmap),
296                        srcLeft, srcTop, srcRight, srcBottom,
297                        dstLeft, dstTop, dstRight, dstBottom, paint));
298                restore();
299                return;
300            }
301        }
302
303        addDrawOp(new (alloc()) DrawBitmapRectOp(refBitmap(bitmap),
304                srcLeft, srcTop, srcRight, srcBottom,
305                dstLeft, dstTop, dstRight, dstBottom, paint));
306    }
307}
308
309void DisplayListCanvas::drawBitmapMesh(const SkBitmap& bitmap, int meshWidth, int meshHeight,
310        const float* vertices, const int* colors, const SkPaint* paint) {
311    int vertexCount = (meshWidth + 1) * (meshHeight + 1);
312    vertices = refBuffer<float>(vertices, vertexCount * 2); // 2 floats per vertex
313    paint = refPaint(paint);
314    colors = refBuffer<int>(colors, vertexCount); // 1 color per vertex
315
316    addDrawOp(new (alloc()) DrawBitmapMeshOp(refBitmap(bitmap), meshWidth, meshHeight,
317           vertices, colors, paint));
318}
319
320void DisplayListCanvas::drawNinePatch(const SkBitmap& bitmap, const Res_png_9patch& patch,
321        float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) {
322    const SkBitmap* bitmapPtr = refBitmap(bitmap);
323    const Res_png_9patch* patchPtr = refPatch(&patch);
324    paint = refPaint(paint);
325
326    addDrawOp(new (alloc()) DrawPatchOp(bitmapPtr, patchPtr,
327            dstLeft, dstTop, dstRight, dstBottom, paint));
328}
329
330void DisplayListCanvas::drawColor(int color, SkXfermode::Mode mode) {
331    addDrawOp(new (alloc()) DrawColorOp(color, mode));
332}
333
334void DisplayListCanvas::drawPaint(const SkPaint& paint) {
335    SkRect bounds;
336    if (getClipBounds(&bounds)) {
337        drawRect(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, paint);
338    }
339}
340
341
342void DisplayListCanvas::drawRect(float left, float top, float right, float bottom,
343        const SkPaint& paint) {
344    addDrawOp(new (alloc()) DrawRectOp(left, top, right, bottom, refPaint(&paint)));
345}
346
347void DisplayListCanvas::drawRoundRect(float left, float top, float right, float bottom,
348        float rx, float ry, const SkPaint& paint) {
349    addDrawOp(new (alloc()) DrawRoundRectOp(left, top, right, bottom, rx, ry, refPaint(&paint)));
350}
351
352void DisplayListCanvas::drawRoundRect(
353        CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top,
354        CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom,
355        CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry,
356        CanvasPropertyPaint* paint) {
357    mDisplayList->ref(left);
358    mDisplayList->ref(top);
359    mDisplayList->ref(right);
360    mDisplayList->ref(bottom);
361    mDisplayList->ref(rx);
362    mDisplayList->ref(ry);
363    mDisplayList->ref(paint);
364    refBitmapsInShader(paint->value.getShader());
365    addDrawOp(new (alloc()) DrawRoundRectPropsOp(&left->value, &top->value,
366            &right->value, &bottom->value, &rx->value, &ry->value, &paint->value));
367}
368
369void DisplayListCanvas::drawCircle(float x, float y, float radius, const SkPaint& paint) {
370    addDrawOp(new (alloc()) DrawCircleOp(x, y, radius, refPaint(&paint)));
371}
372
373void DisplayListCanvas::drawCircle(CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y,
374        CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) {
375    mDisplayList->ref(x);
376    mDisplayList->ref(y);
377    mDisplayList->ref(radius);
378    mDisplayList->ref(paint);
379    refBitmapsInShader(paint->value.getShader());
380    addDrawOp(new (alloc()) DrawCirclePropsOp(&x->value, &y->value,
381            &radius->value, &paint->value));
382}
383
384void DisplayListCanvas::drawOval(float left, float top, float right, float bottom,
385        const SkPaint& paint) {
386    addDrawOp(new (alloc()) DrawOvalOp(left, top, right, bottom, refPaint(&paint)));
387}
388
389void DisplayListCanvas::drawArc(float left, float top, float right, float bottom,
390        float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) {
391    if (fabs(sweepAngle) >= 360.0f) {
392        drawOval(left, top, right, bottom, paint);
393    } else {
394        addDrawOp(new (alloc()) DrawArcOp(left, top, right, bottom,
395                        startAngle, sweepAngle, useCenter, refPaint(&paint)));
396    }
397}
398
399void DisplayListCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
400    addDrawOp(new (alloc()) DrawPathOp(refPath(&path), refPaint(&paint)));
401}
402
403void DisplayListCanvas::drawLines(const float* points, int count, const SkPaint& paint) {
404    points = refBuffer<float>(points, count);
405
406    addDrawOp(new (alloc()) DrawLinesOp(points, count, refPaint(&paint)));
407}
408
409void DisplayListCanvas::drawPoints(const float* points, int count, const SkPaint& paint) {
410    points = refBuffer<float>(points, count);
411
412    addDrawOp(new (alloc()) DrawPointsOp(points, count, refPaint(&paint)));
413}
414
415void DisplayListCanvas::drawTextOnPath(const uint16_t* glyphs, int count,
416        const SkPath& path, float hOffset, float vOffset, const SkPaint& paint) {
417    if (!glyphs || count <= 0) return;
418
419    int bytesCount = 2 * count;
420    DrawOp* op = new (alloc()) DrawTextOnPathOp(refText((const char*) glyphs, bytesCount),
421            bytesCount, count, refPath(&path),
422            hOffset, vOffset, refPaint(&paint));
423    addDrawOp(op);
424}
425
426void DisplayListCanvas::drawPosText(const uint16_t* text, const float* positions,
427        int count, int posCount, const SkPaint& paint) {
428    if (!text || count <= 0) return;
429
430    int bytesCount = 2 * count;
431    positions = refBuffer<float>(positions, count * 2);
432
433    DrawOp* op = new (alloc()) DrawPosTextOp(refText((const char*) text, bytesCount),
434                                             bytesCount, count, positions, refPaint(&paint));
435    addDrawOp(op);
436}
437
438void DisplayListCanvas::drawText(const uint16_t* glyphs, const float* positions,
439        int count, const SkPaint& paint, float x, float y,
440        float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
441        float totalAdvance) {
442
443    if (!glyphs || count <= 0 || PaintUtils::paintWillNotDrawText(paint)) return;
444
445    int bytesCount = count * 2;
446    const char* text = refText((const char*) glyphs, bytesCount);
447    positions = refBuffer<float>(positions, count * 2);
448    Rect bounds(boundsLeft, boundsTop, boundsRight, boundsBottom);
449
450    DrawOp* op = new (alloc()) DrawTextOp(text, bytesCount, count,
451            x, y, positions, refPaint(&paint), totalAdvance, bounds);
452    addDrawOp(op);
453}
454
455void DisplayListCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
456    if (paint.getStyle() != SkPaint::kFill_Style ||
457            (paint.isAntiAlias() && !mState.currentTransform()->isSimple())) {
458        SkRegion::Iterator it(region);
459        while (!it.done()) {
460            const SkIRect& r = it.rect();
461            drawRect(r.fLeft, r.fTop, r.fRight, r.fBottom, paint);
462            it.next();
463        }
464    } else {
465        int count = 0;
466        Vector<float> rects;
467        SkRegion::Iterator it(region);
468        while (!it.done()) {
469            const SkIRect& r = it.rect();
470            rects.push(r.fLeft);
471            rects.push(r.fTop);
472            rects.push(r.fRight);
473            rects.push(r.fBottom);
474            count += 4;
475            it.next();
476        }
477        drawRects(rects.array(), count, &paint);
478    }
479}
480
481void DisplayListCanvas::drawRects(const float* rects, int count, const SkPaint* paint) {
482    if (count <= 0) return;
483
484    rects = refBuffer<float>(rects, count);
485    paint = refPaint(paint);
486    addDrawOp(new (alloc()) DrawRectsOp(rects, count, paint));
487}
488
489void DisplayListCanvas::setDrawFilter(SkDrawFilter* filter) {
490    mDrawFilter.reset(SkSafeRef(filter));
491}
492
493void DisplayListCanvas::insertReorderBarrier(bool enableReorder) {
494    flushRestoreToCount();
495    flushTranslate();
496    mDeferredBarrierType = enableReorder ? kBarrier_OutOfOrder : kBarrier_InOrder;
497}
498
499void DisplayListCanvas::flushRestoreToCount() {
500    if (mRestoreSaveCount >= 0) {
501        addOpAndUpdateChunk(new (alloc()) RestoreToCountOp(mRestoreSaveCount));
502        mRestoreSaveCount = -1;
503    }
504}
505
506void DisplayListCanvas::flushTranslate() {
507    if (mHasDeferredTranslate) {
508        if (mTranslateX != 0.0f || mTranslateY != 0.0f) {
509            addOpAndUpdateChunk(new (alloc()) TranslateOp(mTranslateX, mTranslateY));
510            mTranslateX = mTranslateY = 0.0f;
511        }
512        mHasDeferredTranslate = false;
513    }
514}
515
516size_t DisplayListCanvas::addOpAndUpdateChunk(DisplayListOp* op) {
517    int insertIndex = mDisplayList->ops.size();
518#if HWUI_NEW_OPS
519    LOG_ALWAYS_FATAL("unsupported");
520#else
521    mDisplayList->ops.push_back(op);
522#endif
523    if (mDeferredBarrierType != kBarrier_None) {
524        // op is first in new chunk
525        mDisplayList->chunks.emplace_back();
526        DisplayList::Chunk& newChunk = mDisplayList->chunks.back();
527        newChunk.beginOpIndex = insertIndex;
528        newChunk.endOpIndex = insertIndex + 1;
529        newChunk.reorderChildren = (mDeferredBarrierType == kBarrier_OutOfOrder);
530
531        int nextChildIndex = mDisplayList->children().size();
532        newChunk.beginChildIndex = newChunk.endChildIndex = nextChildIndex;
533        mDeferredBarrierType = kBarrier_None;
534    } else {
535        // standard case - append to existing chunk
536        mDisplayList->chunks.back().endOpIndex = insertIndex + 1;
537    }
538    return insertIndex;
539}
540
541size_t DisplayListCanvas::flushAndAddOp(DisplayListOp* op) {
542    flushRestoreToCount();
543    flushTranslate();
544    return addOpAndUpdateChunk(op);
545}
546
547size_t DisplayListCanvas::addStateOp(StateOp* op) {
548    return flushAndAddOp(op);
549}
550
551size_t DisplayListCanvas::addDrawOp(DrawOp* op) {
552    Rect localBounds;
553    if (op->getLocalBounds(localBounds)) {
554        bool rejected = quickRejectRect(localBounds.left, localBounds.top,
555                localBounds.right, localBounds.bottom);
556        op->setQuickRejected(rejected);
557    }
558
559    mDisplayList->hasDrawOps = true;
560    return flushAndAddOp(op);
561}
562
563size_t DisplayListCanvas::addRenderNodeOp(DrawRenderNodeOp* op) {
564    int opIndex = addDrawOp(op);
565#if !HWUI_NEW_OPS
566    int childIndex = mDisplayList->addChild(op);
567
568    // update the chunk's child indices
569    DisplayList::Chunk& chunk = mDisplayList->chunks.back();
570    chunk.endChildIndex = childIndex + 1;
571
572    if (op->renderNode->stagingProperties().isProjectionReceiver()) {
573        // use staging property, since recording on UI thread
574        mDisplayList->projectionReceiveIndex = opIndex;
575    }
576#endif
577    return opIndex;
578}
579
580void DisplayListCanvas::refBitmapsInShader(const SkShader* shader) {
581    if (!shader) return;
582
583    // If this paint has an SkShader that has an SkBitmap add
584    // it to the bitmap pile
585    SkBitmap bitmap;
586    SkShader::TileMode xy[2];
587    if (shader->asABitmap(&bitmap, nullptr, xy) == SkShader::kDefault_BitmapType) {
588        refBitmap(bitmap);
589        return;
590    }
591    SkShader::ComposeRec rec;
592    if (shader->asACompose(&rec)) {
593        refBitmapsInShader(rec.fShaderA);
594        refBitmapsInShader(rec.fShaderB);
595        return;
596    }
597}
598
599}; // namespace uirenderer
600}; // namespace android
601