DisplayListOp.h revision 51d6a3db97bdd5315f1a17a4b447d10a92217b98
1/*
2 * Copyright (C) 2013 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#ifndef ANDROID_HWUI_DISPLAY_OPERATION_H
18#define ANDROID_HWUI_DISPLAY_OPERATION_H
19
20#include <SkColor.h>
21#include <SkPath.h>
22#include <SkPathOps.h>
23#include <SkXfermode.h>
24
25#include <private/hwui/DrawGlInfo.h>
26
27#include "OpenGLRenderer.h"
28#include "AssetAtlas.h"
29#include "DeferredDisplayList.h"
30#include "DisplayListRenderer.h"
31#include "GammaFontRenderer.h"
32#include "Patch.h"
33#include "RenderNode.h"
34#include "RenderState.h"
35#include "UvMapper.h"
36#include "utils/LinearAllocator.h"
37
38// Use OP_LOG for logging with arglist, OP_LOGS if just printing char*
39#define OP_LOGS(s) OP_LOG("%s", (s))
40#define OP_LOG(s, ...) ALOGD( "%*s" s, level * 2, "", __VA_ARGS__ )
41
42namespace android {
43namespace uirenderer {
44
45/**
46 * Structure for storing canvas operations when they are recorded into a DisplayList, so that they
47 * may be replayed to an OpenGLRenderer.
48 *
49 * To avoid individual memory allocations, DisplayListOps may only be allocated into a
50 * LinearAllocator's managed memory buffers.  Each pointer held by a DisplayListOp is either a
51 * pointer into memory also allocated in the LinearAllocator (mostly for text and float buffers) or
52 * references a externally refcounted object (Sk... and Skia... objects). ~DisplayListOp() is
53 * never called as LinearAllocators are simply discarded, so no memory management should be done in
54 * this class.
55 */
56class DisplayListOp {
57public:
58    // These objects should always be allocated with a LinearAllocator, and never destroyed/deleted.
59    // standard new() intentionally not implemented, and delete/deconstructor should never be used.
60    virtual ~DisplayListOp() { LOG_ALWAYS_FATAL("Destructor not supported"); }
61    static void operator delete(void* ptr) { LOG_ALWAYS_FATAL("delete not supported"); }
62    static void* operator new(size_t size) = delete; /** PURPOSELY OMITTED **/
63    static void* operator new(size_t size, LinearAllocator& allocator) {
64        return allocator.alloc(size);
65    }
66
67    enum OpLogFlag {
68        kOpLogFlag_Recurse = 0x1,
69        kOpLogFlag_JSON = 0x2 // TODO: add?
70    };
71
72    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
73            bool useQuickReject) = 0;
74
75    virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level,
76            bool useQuickReject) = 0;
77
78    virtual void output(int level, uint32_t logFlags = 0) const = 0;
79
80    // NOTE: it would be nice to declare constants and overriding the implementation in each op to
81    // point at the constants, but that seems to require a .cpp file
82    virtual const char* name() = 0;
83};
84
85class StateOp : public DisplayListOp {
86public:
87    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
88            bool useQuickReject) {
89        // default behavior only affects immediate, deferrable state, issue directly to renderer
90        applyState(deferStruct.mRenderer, saveCount);
91    }
92
93    /**
94     * State operations are applied directly to the renderer, but can cause the deferred drawing op
95     * list to flush
96     */
97    virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level,
98            bool useQuickReject) {
99        applyState(replayStruct.mRenderer, saveCount);
100    }
101
102    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const = 0;
103};
104
105class DrawOp : public DisplayListOp {
106friend class MergingDrawBatch;
107public:
108    DrawOp(const SkPaint* paint)
109            : mPaint(paint), mQuickRejected(false) {}
110
111    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
112            bool useQuickReject) {
113        if (mQuickRejected && CC_LIKELY(useQuickReject)) {
114            return;
115        }
116
117        deferStruct.mDeferredList.addDrawOp(deferStruct.mRenderer, this);
118    }
119
120    virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level,
121            bool useQuickReject) {
122        if (mQuickRejected && CC_LIKELY(useQuickReject)) {
123            return;
124        }
125
126        applyDraw(replayStruct.mRenderer, replayStruct.mDirty);
127    }
128
129    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) = 0;
130
131    /**
132     * Draw multiple instances of an operation, must be overidden for operations that merge
133     *
134     * Currently guarantees certain similarities between ops (see MergingDrawBatch::canMergeWith),
135     * and pure translation transformations. Other guarantees of similarity should be enforced by
136     * reducing which operations are tagged as mergeable.
137     */
138    virtual void multiDraw(OpenGLRenderer& renderer, Rect& dirty,
139            const Vector<OpStatePair>& ops, const Rect& bounds) {
140        for (unsigned int i = 0; i < ops.size(); i++) {
141            renderer.restoreDisplayState(*(ops[i].state), true);
142            ops[i].op->applyDraw(renderer, dirty);
143        }
144    }
145
146    /**
147     * When this method is invoked the state field is initialized to have the
148     * final rendering state. We can thus use it to process data as it will be
149     * used at draw time.
150     *
151     * Additionally, this method allows subclasses to provide defer-time preferences for batching
152     * and merging.
153     *
154     * if a subclass can set deferInfo.mergeable to true, it should implement multiDraw()
155     */
156    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
157            const DeferredDisplayState& state) {}
158
159    /**
160     * Query the conservative, local bounds (unmapped) bounds of the op.
161     *
162     * returns true if bounds exist
163     */
164    virtual bool getLocalBounds(Rect& localBounds) {
165        return false;
166    }
167
168    // TODO: better refine localbounds usage
169    void setQuickRejected(bool quickRejected) { mQuickRejected = quickRejected; }
170    bool getQuickRejected() { return mQuickRejected; }
171
172    inline int getPaintAlpha() const {
173        return OpenGLRenderer::getAlphaDirect(mPaint);
174    }
175
176    virtual bool hasTextShadow() const {
177        return false;
178    }
179
180    inline float strokeWidthOutset() {
181        // since anything AA stroke with less than 1.0 pixel width is drawn with an alpha-reduced
182        // 1.0 stroke, treat 1.0 as minimum.
183
184        // TODO: it would be nice if this could take scale into account, but scale isn't stable
185        // since higher levels of the view hierarchy can change scale out from underneath it.
186        return fmaxf(mPaint->getStrokeWidth(), 1) * 0.5f;
187    }
188
189protected:
190    // Helper method for determining op opaqueness. Assumes op fills its bounds in local
191    // coordinates, and that paint's alpha is used
192    inline bool isOpaqueOverBounds(const DeferredDisplayState& state) {
193        // ensure that local bounds cover mapped bounds
194        if (!state.mMatrix.isSimple()) return false;
195
196        if (state.mRoundRectClipState) return false;
197
198        // check state/paint for transparency
199        if (mPaint) {
200            if (mPaint->getAlpha() != 0xFF) {
201                return false;
202            }
203            if (mPaint->getShader() && !mPaint->getShader()->isOpaque()) {
204                return false;
205            }
206            if (Renderer::isBlendedColorFilter(mPaint->getColorFilter())) {
207                return false;
208            }
209        }
210
211        if (state.mAlpha != 1.0f) return false;
212
213        SkXfermode::Mode mode = OpenGLRenderer::getXfermodeDirect(mPaint);
214        return (mode == SkXfermode::kSrcOver_Mode ||
215                mode == SkXfermode::kSrc_Mode);
216
217    }
218
219    const SkPaint* mPaint;
220    bool mQuickRejected;
221};
222
223class DrawBoundedOp : public DrawOp {
224public:
225    DrawBoundedOp(float left, float top, float right, float bottom, const SkPaint* paint)
226            : DrawOp(paint), mLocalBounds(left, top, right, bottom) {}
227
228    DrawBoundedOp(const Rect& localBounds, const SkPaint* paint)
229            : DrawOp(paint), mLocalBounds(localBounds) {}
230
231    // Calculates bounds as smallest rect encompassing all points
232    // NOTE: requires at least 1 vertex, and doesn't account for stroke size (should be handled in
233    // subclass' constructor)
234    DrawBoundedOp(const float* points, int count, const SkPaint* paint)
235            : DrawOp(paint), mLocalBounds(points[0], points[1], points[0], points[1]) {
236        for (int i = 2; i < count; i += 2) {
237            mLocalBounds.left = fminf(mLocalBounds.left, points[i]);
238            mLocalBounds.right = fmaxf(mLocalBounds.right, points[i]);
239            mLocalBounds.top = fminf(mLocalBounds.top, points[i + 1]);
240            mLocalBounds.bottom = fmaxf(mLocalBounds.bottom, points[i + 1]);
241        }
242    }
243
244    // default empty constructor for bounds, to be overridden in child constructor body
245    DrawBoundedOp(const SkPaint* paint): DrawOp(paint) { }
246
247    virtual bool getLocalBounds(Rect& localBounds) {
248        localBounds.set(mLocalBounds);
249        OpenGLRenderer::TextShadow textShadow;
250        if (OpenGLRenderer::getTextShadow(mPaint, &textShadow)) {
251            Rect shadow(mLocalBounds);
252            shadow.translate(textShadow.dx, textShadow.dx);
253            shadow.outset(textShadow.radius);
254            localBounds.unionWith(shadow);
255        }
256        return true;
257    }
258
259protected:
260    Rect mLocalBounds; // displayed area in LOCAL coord. doesn't incorporate stroke, so check paint
261};
262
263///////////////////////////////////////////////////////////////////////////////
264// STATE OPERATIONS - these may affect the state of the canvas/renderer, but do
265//         not directly draw or alter output
266///////////////////////////////////////////////////////////////////////////////
267
268class SaveOp : public StateOp {
269public:
270    SaveOp(int flags)
271            : mFlags(flags) {}
272
273    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
274            bool useQuickReject) {
275        int newSaveCount = deferStruct.mRenderer.save(mFlags);
276        deferStruct.mDeferredList.addSave(deferStruct.mRenderer, this, newSaveCount);
277    }
278
279    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
280        renderer.save(mFlags);
281    }
282
283    virtual void output(int level, uint32_t logFlags) const {
284        OP_LOG("Save flags %x", mFlags);
285    }
286
287    virtual const char* name() { return "Save"; }
288
289    int getFlags() const { return mFlags; }
290private:
291    int mFlags;
292};
293
294class RestoreToCountOp : public StateOp {
295public:
296    RestoreToCountOp(int count)
297            : mCount(count) {}
298
299    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
300            bool useQuickReject) {
301        deferStruct.mDeferredList.addRestoreToCount(deferStruct.mRenderer,
302                this, saveCount + mCount);
303        deferStruct.mRenderer.restoreToCount(saveCount + mCount);
304    }
305
306    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
307        renderer.restoreToCount(saveCount + mCount);
308    }
309
310    virtual void output(int level, uint32_t logFlags) const {
311        OP_LOG("Restore to count %d", mCount);
312    }
313
314    virtual const char* name() { return "RestoreToCount"; }
315
316private:
317    int mCount;
318};
319
320class SaveLayerOp : public StateOp {
321public:
322    SaveLayerOp(float left, float top, float right, float bottom, int alpha, int flags)
323            : mArea(left, top, right, bottom)
324            , mPaint(&mCachedPaint)
325            , mFlags(flags)
326            , mConvexMask(NULL) {
327        mCachedPaint.setAlpha(alpha);
328    }
329
330    SaveLayerOp(float left, float top, float right, float bottom, const SkPaint* paint, int flags)
331            : mArea(left, top, right, bottom)
332            , mPaint(paint)
333            , mFlags(flags)
334            , mConvexMask(NULL)
335    {}
336
337    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
338            bool useQuickReject) {
339        // NOTE: don't bother with actual saveLayer, instead issuing it at flush time
340        int newSaveCount = deferStruct.mRenderer.getSaveCount();
341        deferStruct.mDeferredList.addSaveLayer(deferStruct.mRenderer, this, newSaveCount);
342
343        // NOTE: don't issue full saveLayer, since that has side effects/is costly. instead just
344        // setup the snapshot for deferral, and re-issue the op at flush time
345        deferStruct.mRenderer.saveLayerDeferred(mArea.left, mArea.top, mArea.right, mArea.bottom,
346                mPaint, mFlags);
347    }
348
349    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
350        renderer.saveLayer(mArea.left, mArea.top, mArea.right, mArea.bottom,
351                mPaint, mFlags, mConvexMask);
352    }
353
354    virtual void output(int level, uint32_t logFlags) const {
355        OP_LOG("SaveLayer%s of area " RECT_STRING,
356                (isSaveLayerAlpha() ? "Alpha" : ""),RECT_ARGS(mArea));
357    }
358
359    virtual const char* name() { return isSaveLayerAlpha() ? "SaveLayerAlpha" : "SaveLayer"; }
360
361    int getFlags() { return mFlags; }
362
363    // Called to make SaveLayerOp clip to the provided mask when drawing back/restored
364    void setMask(const SkPath* convexMask) {
365        mConvexMask = convexMask;
366    }
367
368private:
369    bool isSaveLayerAlpha() const {
370        SkXfermode::Mode mode = OpenGLRenderer::getXfermodeDirect(mPaint);
371        int alpha = OpenGLRenderer::getAlphaDirect(mPaint);
372        return alpha < 255 && mode == SkXfermode::kSrcOver_Mode;
373    }
374
375    Rect mArea;
376    const SkPaint* mPaint;
377    SkPaint mCachedPaint;
378    int mFlags;
379
380    // Convex path, points at data in RenderNode, valid for the duration of the frame only
381    // Only used for masking the SaveLayer which wraps projected RenderNodes
382    const SkPath* mConvexMask;
383};
384
385class TranslateOp : public StateOp {
386public:
387    TranslateOp(float dx, float dy)
388            : mDx(dx), mDy(dy) {}
389
390    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
391        renderer.translate(mDx, mDy);
392    }
393
394    virtual void output(int level, uint32_t logFlags) const {
395        OP_LOG("Translate by %f %f", mDx, mDy);
396    }
397
398    virtual const char* name() { return "Translate"; }
399
400private:
401    float mDx;
402    float mDy;
403};
404
405class RotateOp : public StateOp {
406public:
407    RotateOp(float degrees)
408            : mDegrees(degrees) {}
409
410    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
411        renderer.rotate(mDegrees);
412    }
413
414    virtual void output(int level, uint32_t logFlags) const {
415        OP_LOG("Rotate by %f degrees", mDegrees);
416    }
417
418    virtual const char* name() { return "Rotate"; }
419
420private:
421    float mDegrees;
422};
423
424class ScaleOp : public StateOp {
425public:
426    ScaleOp(float sx, float sy)
427            : mSx(sx), mSy(sy) {}
428
429    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
430        renderer.scale(mSx, mSy);
431    }
432
433    virtual void output(int level, uint32_t logFlags) const {
434        OP_LOG("Scale by %f %f", mSx, mSy);
435    }
436
437    virtual const char* name() { return "Scale"; }
438
439private:
440    float mSx;
441    float mSy;
442};
443
444class SkewOp : public StateOp {
445public:
446    SkewOp(float sx, float sy)
447            : mSx(sx), mSy(sy) {}
448
449    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
450        renderer.skew(mSx, mSy);
451    }
452
453    virtual void output(int level, uint32_t logFlags) const {
454        OP_LOG("Skew by %f %f", mSx, mSy);
455    }
456
457    virtual const char* name() { return "Skew"; }
458
459private:
460    float mSx;
461    float mSy;
462};
463
464class SetMatrixOp : public StateOp {
465public:
466    SetMatrixOp(const SkMatrix& matrix)
467            : mMatrix(matrix) {}
468
469    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
470        renderer.setMatrix(mMatrix);
471    }
472
473    virtual void output(int level, uint32_t logFlags) const {
474        if (mMatrix.isIdentity()) {
475            OP_LOGS("SetMatrix (reset)");
476        } else {
477            OP_LOG("SetMatrix " SK_MATRIX_STRING, SK_MATRIX_ARGS(&mMatrix));
478        }
479    }
480
481    virtual const char* name() { return "SetMatrix"; }
482
483private:
484    const SkMatrix mMatrix;
485};
486
487class ConcatMatrixOp : public StateOp {
488public:
489    ConcatMatrixOp(const SkMatrix& matrix)
490            : mMatrix(matrix) {}
491
492    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
493        renderer.concatMatrix(mMatrix);
494    }
495
496    virtual void output(int level, uint32_t logFlags) const {
497        OP_LOG("ConcatMatrix " SK_MATRIX_STRING, SK_MATRIX_ARGS(&mMatrix));
498    }
499
500    virtual const char* name() { return "ConcatMatrix"; }
501
502private:
503    const SkMatrix mMatrix;
504};
505
506class ClipOp : public StateOp {
507public:
508    ClipOp(SkRegion::Op op) : mOp(op) {}
509
510    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
511            bool useQuickReject) {
512        // NOTE: must defer op BEFORE applying state, since it may read clip
513        deferStruct.mDeferredList.addClip(deferStruct.mRenderer, this);
514
515        // TODO: Can we avoid applying complex clips at defer time?
516        applyState(deferStruct.mRenderer, saveCount);
517    }
518
519    bool canCauseComplexClip() {
520        return ((mOp != SkRegion::kIntersect_Op) && (mOp != SkRegion::kReplace_Op)) || !isRect();
521    }
522
523protected:
524    virtual bool isRect() { return false; }
525
526    SkRegion::Op mOp;
527};
528
529class ClipRectOp : public ClipOp {
530public:
531    ClipRectOp(float left, float top, float right, float bottom, SkRegion::Op op)
532            : ClipOp(op), mArea(left, top, right, bottom) {}
533
534    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
535        renderer.clipRect(mArea.left, mArea.top, mArea.right, mArea.bottom, mOp);
536    }
537
538    virtual void output(int level, uint32_t logFlags) const {
539        OP_LOG("ClipRect " RECT_STRING, RECT_ARGS(mArea));
540    }
541
542    virtual const char* name() { return "ClipRect"; }
543
544protected:
545    virtual bool isRect() { return true; }
546
547private:
548    Rect mArea;
549};
550
551class ClipPathOp : public ClipOp {
552public:
553    ClipPathOp(const SkPath* path, SkRegion::Op op)
554            : ClipOp(op), mPath(path) {}
555
556    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
557        renderer.clipPath(mPath, mOp);
558    }
559
560    virtual void output(int level, uint32_t logFlags) const {
561        SkRect bounds = mPath->getBounds();
562        OP_LOG("ClipPath bounds " RECT_STRING,
563                bounds.left(), bounds.top(), bounds.right(), bounds.bottom());
564    }
565
566    virtual const char* name() { return "ClipPath"; }
567
568private:
569    const SkPath* mPath;
570};
571
572class ClipRegionOp : public ClipOp {
573public:
574    ClipRegionOp(const SkRegion* region, SkRegion::Op op)
575            : ClipOp(op), mRegion(region) {}
576
577    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
578        renderer.clipRegion(mRegion, mOp);
579    }
580
581    virtual void output(int level, uint32_t logFlags) const {
582        SkIRect bounds = mRegion->getBounds();
583        OP_LOG("ClipRegion bounds %d %d %d %d",
584                bounds.left(), bounds.top(), bounds.right(), bounds.bottom());
585    }
586
587    virtual const char* name() { return "ClipRegion"; }
588
589private:
590    const SkRegion* mRegion;
591};
592
593///////////////////////////////////////////////////////////////////////////////
594// DRAW OPERATIONS - these are operations that can draw to the canvas's device
595///////////////////////////////////////////////////////////////////////////////
596
597class DrawBitmapOp : public DrawBoundedOp {
598public:
599    DrawBitmapOp(const SkBitmap* bitmap, const SkPaint* paint)
600            : DrawBoundedOp(0, 0, bitmap->width(), bitmap->height(), paint)
601            , mBitmap(bitmap)
602            , mEntryValid(false), mEntry(NULL) {
603    }
604
605    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
606        renderer.drawBitmap(mBitmap, mPaint);
607    }
608
609    AssetAtlas::Entry* getAtlasEntry(OpenGLRenderer& renderer) {
610        if (!mEntryValid) {
611            mEntryValid = true;
612            mEntry = renderer.renderState().assetAtlas().getEntry(mBitmap);
613        }
614        return mEntry;
615    }
616
617#define SET_TEXTURE(ptr, posRect, offsetRect, texCoordsRect, xDim, yDim) \
618    TextureVertex::set(ptr++, posRect.xDim - offsetRect.left, posRect.yDim - offsetRect.top, \
619            texCoordsRect.xDim, texCoordsRect.yDim)
620
621    /**
622     * This multi-draw operation builds a mesh on the stack by generating a quad
623     * for each bitmap in the batch. This method is also responsible for dirtying
624     * the current layer, if any.
625     */
626    virtual void multiDraw(OpenGLRenderer& renderer, Rect& dirty,
627            const Vector<OpStatePair>& ops, const Rect& bounds) {
628        const DeferredDisplayState& firstState = *(ops[0].state);
629        renderer.restoreDisplayState(firstState, true); // restore all but the clip
630
631        TextureVertex vertices[6 * ops.size()];
632        TextureVertex* vertex = &vertices[0];
633
634        const bool hasLayer = renderer.hasLayer();
635        bool pureTranslate = true;
636
637        // TODO: manually handle rect clip for bitmaps by adjusting texCoords per op,
638        // and allowing them to be merged in getBatchId()
639        for (unsigned int i = 0; i < ops.size(); i++) {
640            const DeferredDisplayState& state = *(ops[i].state);
641            const Rect& opBounds = state.mBounds;
642            // When we reach multiDraw(), the matrix can be either
643            // pureTranslate or simple (translate and/or scale).
644            // If the matrix is not pureTranslate, then we have a scale
645            pureTranslate &= state.mMatrix.isPureTranslate();
646
647            Rect texCoords(0, 0, 1, 1);
648            ((DrawBitmapOp*) ops[i].op)->uvMap(renderer, texCoords);
649
650            SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, top);
651            SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, top);
652            SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, bottom);
653
654            SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, bottom);
655            SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, top);
656            SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, bottom);
657
658            if (hasLayer) {
659                renderer.dirtyLayer(opBounds.left, opBounds.top, opBounds.right, opBounds.bottom);
660            }
661        }
662
663        renderer.drawBitmaps(mBitmap, mEntry, ops.size(), &vertices[0],
664                pureTranslate, bounds, mPaint);
665    }
666
667    virtual void output(int level, uint32_t logFlags) const {
668        OP_LOG("Draw bitmap %p at %f %f%s", mBitmap, mLocalBounds.left, mLocalBounds.top,
669                mEntry ? " using AssetAtlas" : "");
670    }
671
672    virtual const char* name() { return "DrawBitmap"; }
673
674    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
675            const DeferredDisplayState& state) {
676        deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
677        deferInfo.mergeId = getAtlasEntry(renderer) ?
678                (mergeid_t) mEntry->getMergeId() : (mergeid_t) mBitmap;
679
680        // Don't merge non-simply transformed or neg scale ops, SET_TEXTURE doesn't handle rotation
681        // Don't merge A8 bitmaps - the paint's color isn't compared by mergeId, or in
682        // MergingDrawBatch::canMergeWith()
683        // TODO: support clipped bitmaps by handling them in SET_TEXTURE
684        deferInfo.mergeable = state.mMatrix.isSimple() && state.mMatrix.positiveScale() &&
685                !state.mClipSideFlags &&
686                OpenGLRenderer::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode &&
687                (mBitmap->colorType() != kAlpha_8_SkColorType);
688    }
689
690    void uvMap(OpenGLRenderer& renderer, Rect& texCoords) {
691        if (getAtlasEntry(renderer)) {
692            mEntry->uvMapper.map(texCoords);
693        }
694    }
695
696    const SkBitmap* bitmap() { return mBitmap; }
697protected:
698    const SkBitmap* mBitmap;
699    bool mEntryValid;
700    AssetAtlas::Entry* mEntry;
701};
702
703class DrawBitmapRectOp : public DrawBoundedOp {
704public:
705    DrawBitmapRectOp(const SkBitmap* bitmap,
706            float srcLeft, float srcTop, float srcRight, float srcBottom,
707            float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint)
708            : DrawBoundedOp(dstLeft, dstTop, dstRight, dstBottom, paint),
709            mBitmap(bitmap), mSrc(srcLeft, srcTop, srcRight, srcBottom) {}
710
711    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
712        renderer.drawBitmap(mBitmap, mSrc.left, mSrc.top, mSrc.right, mSrc.bottom,
713                mLocalBounds.left, mLocalBounds.top, mLocalBounds.right, mLocalBounds.bottom,
714                mPaint);
715    }
716
717    virtual void output(int level, uint32_t logFlags) const {
718        OP_LOG("Draw bitmap %p src=" RECT_STRING ", dst=" RECT_STRING,
719                mBitmap, RECT_ARGS(mSrc), RECT_ARGS(mLocalBounds));
720    }
721
722    virtual const char* name() { return "DrawBitmapRect"; }
723
724    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
725            const DeferredDisplayState& state) {
726        deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
727    }
728
729private:
730    const SkBitmap* mBitmap;
731    Rect mSrc;
732};
733
734class DrawBitmapDataOp : public DrawBitmapOp {
735public:
736    DrawBitmapDataOp(const SkBitmap* bitmap, const SkPaint* paint)
737            : DrawBitmapOp(bitmap, paint) {}
738
739    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
740        renderer.drawBitmapData(mBitmap, mPaint);
741    }
742
743    virtual void output(int level, uint32_t logFlags) const {
744        OP_LOG("Draw bitmap %p", mBitmap);
745    }
746
747    virtual const char* name() { return "DrawBitmapData"; }
748
749    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
750            const DeferredDisplayState& state) {
751        deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
752    }
753};
754
755class DrawBitmapMeshOp : public DrawBoundedOp {
756public:
757    DrawBitmapMeshOp(const SkBitmap* bitmap, int meshWidth, int meshHeight,
758            const float* vertices, const int* colors, const SkPaint* paint)
759            : DrawBoundedOp(vertices, 2 * (meshWidth + 1) * (meshHeight + 1), paint),
760            mBitmap(bitmap), mMeshWidth(meshWidth), mMeshHeight(meshHeight),
761            mVertices(vertices), mColors(colors) {}
762
763    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
764        renderer.drawBitmapMesh(mBitmap, mMeshWidth, mMeshHeight,
765                mVertices, mColors, mPaint);
766    }
767
768    virtual void output(int level, uint32_t logFlags) const {
769        OP_LOG("Draw bitmap %p mesh %d x %d", mBitmap, mMeshWidth, mMeshHeight);
770    }
771
772    virtual const char* name() { return "DrawBitmapMesh"; }
773
774    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
775            const DeferredDisplayState& state) {
776        deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
777    }
778
779private:
780    const SkBitmap* mBitmap;
781    int mMeshWidth;
782    int mMeshHeight;
783    const float* mVertices;
784    const int* mColors;
785};
786
787class DrawPatchOp : public DrawBoundedOp {
788public:
789    DrawPatchOp(const SkBitmap* bitmap, const Res_png_9patch* patch,
790            float left, float top, float right, float bottom, const SkPaint* paint)
791            : DrawBoundedOp(left, top, right, bottom, paint),
792            mBitmap(bitmap), mPatch(patch), mGenerationId(0), mMesh(NULL),
793            mEntryValid(false), mEntry(NULL) {
794    };
795
796    AssetAtlas::Entry* getAtlasEntry(OpenGLRenderer& renderer) {
797        if (!mEntryValid) {
798            mEntryValid = true;
799            mEntry = renderer.renderState().assetAtlas().getEntry(mBitmap);
800        }
801        return mEntry;
802    }
803
804    const Patch* getMesh(OpenGLRenderer& renderer) {
805        if (!mMesh || renderer.getCaches().patchCache.getGenerationId() != mGenerationId) {
806            PatchCache& cache = renderer.getCaches().patchCache;
807            mMesh = cache.get(getAtlasEntry(renderer), mBitmap->width(), mBitmap->height(),
808                    mLocalBounds.getWidth(), mLocalBounds.getHeight(), mPatch);
809            mGenerationId = cache.getGenerationId();
810        }
811        return mMesh;
812    }
813
814    /**
815     * This multi-draw operation builds an indexed mesh on the stack by copying
816     * and transforming the vertices of each 9-patch in the batch. This method
817     * is also responsible for dirtying the current layer, if any.
818     */
819    virtual void multiDraw(OpenGLRenderer& renderer, Rect& dirty,
820            const Vector<OpStatePair>& ops, const Rect& bounds) {
821        const DeferredDisplayState& firstState = *(ops[0].state);
822        renderer.restoreDisplayState(firstState, true); // restore all but the clip
823
824        // Batches will usually contain a small number of items so it's
825        // worth performing a first iteration to count the exact number
826        // of vertices we need in the new mesh
827        uint32_t totalVertices = 0;
828        for (unsigned int i = 0; i < ops.size(); i++) {
829            totalVertices += ((DrawPatchOp*) ops[i].op)->getMesh(renderer)->verticesCount;
830        }
831
832        const bool hasLayer = renderer.hasLayer();
833
834        uint32_t indexCount = 0;
835
836        TextureVertex vertices[totalVertices];
837        TextureVertex* vertex = &vertices[0];
838
839        // Create a mesh that contains the transformed vertices for all the
840        // 9-patch objects that are part of the batch. Note that onDefer()
841        // enforces ops drawn by this function to have a pure translate or
842        // identity matrix
843        for (unsigned int i = 0; i < ops.size(); i++) {
844            DrawPatchOp* patchOp = (DrawPatchOp*) ops[i].op;
845            const DeferredDisplayState* state = ops[i].state;
846            const Patch* opMesh = patchOp->getMesh(renderer);
847            uint32_t vertexCount = opMesh->verticesCount;
848            if (vertexCount == 0) continue;
849
850            // We use the bounds to know where to translate our vertices
851            // Using patchOp->state.mBounds wouldn't work because these
852            // bounds are clipped
853            const float tx = (int) floorf(state->mMatrix.getTranslateX() +
854                    patchOp->mLocalBounds.left + 0.5f);
855            const float ty = (int) floorf(state->mMatrix.getTranslateY() +
856                    patchOp->mLocalBounds.top + 0.5f);
857
858            // Copy & transform all the vertices for the current operation
859            TextureVertex* opVertices = opMesh->vertices.get();
860            for (uint32_t j = 0; j < vertexCount; j++, opVertices++) {
861                TextureVertex::set(vertex++,
862                        opVertices->x + tx, opVertices->y + ty,
863                        opVertices->u, opVertices->v);
864            }
865
866            // Dirty the current layer if possible. When the 9-patch does not
867            // contain empty quads we can take a shortcut and simply set the
868            // dirty rect to the object's bounds.
869            if (hasLayer) {
870                if (!opMesh->hasEmptyQuads) {
871                    renderer.dirtyLayer(tx, ty,
872                            tx + patchOp->mLocalBounds.getWidth(),
873                            ty + patchOp->mLocalBounds.getHeight());
874                } else {
875                    const size_t count = opMesh->quads.size();
876                    for (size_t i = 0; i < count; i++) {
877                        const Rect& quadBounds = opMesh->quads[i];
878                        const float x = tx + quadBounds.left;
879                        const float y = ty + quadBounds.top;
880                        renderer.dirtyLayer(x, y,
881                                x + quadBounds.getWidth(), y + quadBounds.getHeight());
882                    }
883                }
884            }
885
886            indexCount += opMesh->indexCount;
887        }
888
889        renderer.drawPatches(mBitmap, getAtlasEntry(renderer),
890                &vertices[0], indexCount, mPaint);
891    }
892
893    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
894        // We're not calling the public variant of drawPatch() here
895        // This method won't perform the quickReject() since we've already done it at this point
896        renderer.drawPatch(mBitmap, getMesh(renderer), getAtlasEntry(renderer),
897                mLocalBounds.left, mLocalBounds.top, mLocalBounds.right, mLocalBounds.bottom,
898                mPaint);
899    }
900
901    virtual void output(int level, uint32_t logFlags) const {
902        OP_LOG("Draw patch " RECT_STRING "%s", RECT_ARGS(mLocalBounds),
903                mEntry ? " with AssetAtlas" : "");
904    }
905
906    virtual const char* name() { return "DrawPatch"; }
907
908    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
909            const DeferredDisplayState& state) {
910        deferInfo.batchId = DeferredDisplayList::kOpBatch_Patch;
911        deferInfo.mergeId = getAtlasEntry(renderer) ? (mergeid_t) mEntry->getMergeId() : (mergeid_t) mBitmap;
912        deferInfo.mergeable = state.mMatrix.isPureTranslate() &&
913                OpenGLRenderer::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode;
914        deferInfo.opaqueOverBounds = isOpaqueOverBounds(state) && mBitmap->isOpaque();
915    }
916
917private:
918    const SkBitmap* mBitmap;
919    const Res_png_9patch* mPatch;
920
921    uint32_t mGenerationId;
922    const Patch* mMesh;
923
924    bool mEntryValid;
925    AssetAtlas::Entry* mEntry;
926};
927
928class DrawColorOp : public DrawOp {
929public:
930    DrawColorOp(int color, SkXfermode::Mode mode)
931            : DrawOp(NULL), mColor(color), mMode(mode) {};
932
933    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
934        renderer.drawColor(mColor, mMode);
935    }
936
937    virtual void output(int level, uint32_t logFlags) const {
938        OP_LOG("Draw color %#x, mode %d", mColor, mMode);
939    }
940
941    virtual const char* name() { return "DrawColor"; }
942
943private:
944    int mColor;
945    SkXfermode::Mode mMode;
946};
947
948class DrawStrokableOp : public DrawBoundedOp {
949public:
950    DrawStrokableOp(float left, float top, float right, float bottom, const SkPaint* paint)
951            : DrawBoundedOp(left, top, right, bottom, paint) {};
952    DrawStrokableOp(const Rect& localBounds, const SkPaint* paint)
953            : DrawBoundedOp(localBounds, paint) {};
954
955    virtual bool getLocalBounds(Rect& localBounds) {
956        localBounds.set(mLocalBounds);
957        if (mPaint && mPaint->getStyle() != SkPaint::kFill_Style) {
958            localBounds.outset(strokeWidthOutset());
959        }
960        return true;
961    }
962
963    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
964            const DeferredDisplayState& state) {
965        if (mPaint->getPathEffect()) {
966            deferInfo.batchId = DeferredDisplayList::kOpBatch_AlphaMaskTexture;
967        } else {
968            deferInfo.batchId = mPaint->isAntiAlias() ?
969                    DeferredDisplayList::kOpBatch_AlphaVertices :
970                    DeferredDisplayList::kOpBatch_Vertices;
971        }
972    }
973};
974
975class DrawRectOp : public DrawStrokableOp {
976public:
977    DrawRectOp(float left, float top, float right, float bottom, const SkPaint* paint)
978            : DrawStrokableOp(left, top, right, bottom, paint) {}
979
980    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
981        renderer.drawRect(mLocalBounds.left, mLocalBounds.top,
982                mLocalBounds.right, mLocalBounds.bottom, mPaint);
983    }
984
985    virtual void output(int level, uint32_t logFlags) const {
986        OP_LOG("Draw Rect " RECT_STRING, RECT_ARGS(mLocalBounds));
987    }
988
989    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
990            const DeferredDisplayState& state) {
991        DrawStrokableOp::onDefer(renderer, deferInfo, state);
992        deferInfo.opaqueOverBounds = isOpaqueOverBounds(state) &&
993                mPaint->getStyle() == SkPaint::kFill_Style;
994    }
995
996    virtual const char* name() { return "DrawRect"; }
997};
998
999class DrawRectsOp : public DrawBoundedOp {
1000public:
1001    DrawRectsOp(const float* rects, int count, const SkPaint* paint)
1002            : DrawBoundedOp(rects, count, paint),
1003            mRects(rects), mCount(count) {}
1004
1005    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1006        renderer.drawRects(mRects, mCount, mPaint);
1007    }
1008
1009    virtual void output(int level, uint32_t logFlags) const {
1010        OP_LOG("Draw Rects count %d", mCount);
1011    }
1012
1013    virtual const char* name() { return "DrawRects"; }
1014
1015    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
1016            const DeferredDisplayState& state) {
1017        deferInfo.batchId = DeferredDisplayList::kOpBatch_Vertices;
1018    }
1019
1020private:
1021    const float* mRects;
1022    int mCount;
1023};
1024
1025class DrawRoundRectOp : public DrawStrokableOp {
1026public:
1027    DrawRoundRectOp(float left, float top, float right, float bottom,
1028            float rx, float ry, const SkPaint* paint)
1029            : DrawStrokableOp(left, top, right, bottom, paint), mRx(rx), mRy(ry) {}
1030
1031    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1032        renderer.drawRoundRect(mLocalBounds.left, mLocalBounds.top,
1033                mLocalBounds.right, mLocalBounds.bottom, mRx, mRy, mPaint);
1034    }
1035
1036    virtual void output(int level, uint32_t logFlags) const {
1037        OP_LOG("Draw RoundRect " RECT_STRING ", rx %f, ry %f", RECT_ARGS(mLocalBounds), mRx, mRy);
1038    }
1039
1040    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
1041            const DeferredDisplayState& state) {
1042        DrawStrokableOp::onDefer(renderer, deferInfo, state);
1043        if (!mPaint->getPathEffect()) {
1044            renderer.getCaches().tessellationCache.precacheRoundRect(state.mMatrix, *mPaint,
1045                    mLocalBounds.getWidth(), mLocalBounds.getHeight(), mRx, mRy);
1046        }
1047    }
1048
1049    virtual const char* name() { return "DrawRoundRect"; }
1050
1051private:
1052    float mRx;
1053    float mRy;
1054};
1055
1056class DrawRoundRectPropsOp : public DrawOp {
1057public:
1058    DrawRoundRectPropsOp(float* left, float* top, float* right, float* bottom,
1059            float *rx, float *ry, const SkPaint* paint)
1060            : DrawOp(paint), mLeft(left), mTop(top), mRight(right), mBottom(bottom),
1061            mRx(rx), mRy(ry) {}
1062
1063    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1064        renderer.drawRoundRect(*mLeft, *mTop, *mRight, *mBottom,
1065                *mRx, *mRy, mPaint);
1066    }
1067
1068    virtual void output(int level, uint32_t logFlags) const {
1069        OP_LOG("Draw RoundRect Props " RECT_STRING ", rx %f, ry %f",
1070                *mLeft, *mTop, *mRight, *mBottom, *mRx, *mRy);
1071    }
1072
1073    virtual const char* name() { return "DrawRoundRectProps"; }
1074
1075private:
1076    float* mLeft;
1077    float* mTop;
1078    float* mRight;
1079    float* mBottom;
1080    float* mRx;
1081    float* mRy;
1082};
1083
1084class DrawCircleOp : public DrawStrokableOp {
1085public:
1086    DrawCircleOp(float x, float y, float radius, const SkPaint* paint)
1087            : DrawStrokableOp(x - radius, y - radius, x + radius, y + radius, paint),
1088            mX(x), mY(y), mRadius(radius) {}
1089
1090    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1091        renderer.drawCircle(mX, mY, mRadius, mPaint);
1092    }
1093
1094    virtual void output(int level, uint32_t logFlags) const {
1095        OP_LOG("Draw Circle x %f, y %f, r %f", mX, mY, mRadius);
1096    }
1097
1098    virtual const char* name() { return "DrawCircle"; }
1099
1100private:
1101    float mX;
1102    float mY;
1103    float mRadius;
1104};
1105
1106class DrawCirclePropsOp : public DrawOp {
1107public:
1108    DrawCirclePropsOp(float* x, float* y, float* radius, const SkPaint* paint)
1109            : DrawOp(paint), mX(x), mY(y), mRadius(radius) {}
1110
1111    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1112        renderer.drawCircle(*mX, *mY, *mRadius, mPaint);
1113    }
1114
1115    virtual void output(int level, uint32_t logFlags) const {
1116        OP_LOG("Draw Circle Props x %p, y %p, r %p", mX, mY, mRadius);
1117    }
1118
1119    virtual const char* name() { return "DrawCircleProps"; }
1120
1121private:
1122    float* mX;
1123    float* mY;
1124    float* mRadius;
1125};
1126
1127class DrawOvalOp : public DrawStrokableOp {
1128public:
1129    DrawOvalOp(float left, float top, float right, float bottom, const SkPaint* paint)
1130            : DrawStrokableOp(left, top, right, bottom, paint) {}
1131
1132    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1133        renderer.drawOval(mLocalBounds.left, mLocalBounds.top,
1134                mLocalBounds.right, mLocalBounds.bottom, mPaint);
1135    }
1136
1137    virtual void output(int level, uint32_t logFlags) const {
1138        OP_LOG("Draw Oval " RECT_STRING, RECT_ARGS(mLocalBounds));
1139    }
1140
1141    virtual const char* name() { return "DrawOval"; }
1142};
1143
1144class DrawArcOp : public DrawStrokableOp {
1145public:
1146    DrawArcOp(float left, float top, float right, float bottom,
1147            float startAngle, float sweepAngle, bool useCenter, const SkPaint* paint)
1148            : DrawStrokableOp(left, top, right, bottom, paint),
1149            mStartAngle(startAngle), mSweepAngle(sweepAngle), mUseCenter(useCenter) {}
1150
1151    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1152        renderer.drawArc(mLocalBounds.left, mLocalBounds.top,
1153                mLocalBounds.right, mLocalBounds.bottom,
1154                mStartAngle, mSweepAngle, mUseCenter, mPaint);
1155    }
1156
1157    virtual void output(int level, uint32_t logFlags) const {
1158        OP_LOG("Draw Arc " RECT_STRING ", start %f, sweep %f, useCenter %d",
1159                RECT_ARGS(mLocalBounds), mStartAngle, mSweepAngle, mUseCenter);
1160    }
1161
1162    virtual const char* name() { return "DrawArc"; }
1163
1164private:
1165    float mStartAngle;
1166    float mSweepAngle;
1167    bool mUseCenter;
1168};
1169
1170class DrawPathOp : public DrawBoundedOp {
1171public:
1172    DrawPathOp(const SkPath* path, const SkPaint* paint)
1173            : DrawBoundedOp(paint), mPath(path) {
1174        float left, top, offset;
1175        uint32_t width, height;
1176        PathCache::computePathBounds(path, paint, left, top, offset, width, height);
1177        left -= offset;
1178        top -= offset;
1179        mLocalBounds.set(left, top, left + width, top + height);
1180    }
1181
1182    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1183        renderer.drawPath(mPath, mPaint);
1184    }
1185
1186    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
1187            const DeferredDisplayState& state) {
1188        renderer.getCaches().pathCache.precache(mPath, mPaint);
1189
1190        deferInfo.batchId = DeferredDisplayList::kOpBatch_AlphaMaskTexture;
1191    }
1192
1193    virtual void output(int level, uint32_t logFlags) const {
1194        OP_LOG("Draw Path %p in " RECT_STRING, mPath, RECT_ARGS(mLocalBounds));
1195    }
1196
1197    virtual const char* name() { return "DrawPath"; }
1198
1199private:
1200    const SkPath* mPath;
1201};
1202
1203class DrawLinesOp : public DrawBoundedOp {
1204public:
1205    DrawLinesOp(const float* points, int count, const SkPaint* paint)
1206            : DrawBoundedOp(points, count, paint),
1207            mPoints(points), mCount(count) {
1208        mLocalBounds.outset(strokeWidthOutset());
1209    }
1210
1211    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1212        renderer.drawLines(mPoints, mCount, mPaint);
1213    }
1214
1215    virtual void output(int level, uint32_t logFlags) const {
1216        OP_LOG("Draw Lines count %d", mCount);
1217    }
1218
1219    virtual const char* name() { return "DrawLines"; }
1220
1221    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
1222            const DeferredDisplayState& state) {
1223        deferInfo.batchId = mPaint->isAntiAlias() ?
1224                DeferredDisplayList::kOpBatch_AlphaVertices :
1225                DeferredDisplayList::kOpBatch_Vertices;
1226    }
1227
1228protected:
1229    const float* mPoints;
1230    int mCount;
1231};
1232
1233class DrawPointsOp : public DrawLinesOp {
1234public:
1235    DrawPointsOp(const float* points, int count, const SkPaint* paint)
1236            : DrawLinesOp(points, count, paint) {}
1237
1238    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1239        renderer.drawPoints(mPoints, mCount, mPaint);
1240    }
1241
1242    virtual void output(int level, uint32_t logFlags) const {
1243        OP_LOG("Draw Points count %d", mCount);
1244    }
1245
1246    virtual const char* name() { return "DrawPoints"; }
1247};
1248
1249class DrawSomeTextOp : public DrawOp {
1250public:
1251    DrawSomeTextOp(const char* text, int bytesCount, int count, const SkPaint* paint)
1252            : DrawOp(paint), mText(text), mBytesCount(bytesCount), mCount(count) {};
1253
1254    virtual void output(int level, uint32_t logFlags) const {
1255        OP_LOG("Draw some text, %d bytes", mBytesCount);
1256    }
1257
1258    virtual bool hasTextShadow() const {
1259        return OpenGLRenderer::hasTextShadow(mPaint);
1260    }
1261
1262    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
1263            const DeferredDisplayState& state) {
1264        FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(mPaint);
1265        fontRenderer.precache(mPaint, mText, mCount, SkMatrix::I());
1266
1267        deferInfo.batchId = mPaint->getColor() == SK_ColorBLACK ?
1268                DeferredDisplayList::kOpBatch_Text :
1269                DeferredDisplayList::kOpBatch_ColorText;
1270    }
1271
1272protected:
1273    const char* mText;
1274    int mBytesCount;
1275    int mCount;
1276};
1277
1278class DrawTextOnPathOp : public DrawSomeTextOp {
1279public:
1280    DrawTextOnPathOp(const char* text, int bytesCount, int count,
1281            const SkPath* path, float hOffset, float vOffset, const SkPaint* paint)
1282            : DrawSomeTextOp(text, bytesCount, count, paint),
1283            mPath(path), mHOffset(hOffset), mVOffset(vOffset) {
1284        /* TODO: inherit from DrawBounded and init mLocalBounds */
1285    }
1286
1287    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1288        renderer.drawTextOnPath(mText, mBytesCount, mCount, mPath,
1289                mHOffset, mVOffset, mPaint);
1290    }
1291
1292    virtual const char* name() { return "DrawTextOnPath"; }
1293
1294private:
1295    const SkPath* mPath;
1296    float mHOffset;
1297    float mVOffset;
1298};
1299
1300class DrawPosTextOp : public DrawSomeTextOp {
1301public:
1302    DrawPosTextOp(const char* text, int bytesCount, int count,
1303            const float* positions, const SkPaint* paint)
1304            : DrawSomeTextOp(text, bytesCount, count, paint), mPositions(positions) {
1305        /* TODO: inherit from DrawBounded and init mLocalBounds */
1306    }
1307
1308    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1309        renderer.drawPosText(mText, mBytesCount, mCount, mPositions, mPaint);
1310    }
1311
1312    virtual const char* name() { return "DrawPosText"; }
1313
1314private:
1315    const float* mPositions;
1316};
1317
1318class DrawTextOp : public DrawStrokableOp {
1319public:
1320    DrawTextOp(const char* text, int bytesCount, int count, float x, float y,
1321            const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds)
1322            : DrawStrokableOp(bounds, paint), mText(text), mBytesCount(bytesCount), mCount(count),
1323            mX(x), mY(y), mPositions(positions), mTotalAdvance(totalAdvance) {
1324        mPrecacheTransform = SkMatrix::InvalidMatrix();
1325    }
1326
1327    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
1328            const DeferredDisplayState& state) {
1329        FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(mPaint);
1330        SkMatrix transform;
1331        renderer.findBestFontTransform(state.mMatrix, &transform);
1332        if (mPrecacheTransform != transform) {
1333            fontRenderer.precache(mPaint, mText, mCount, transform);
1334            mPrecacheTransform = transform;
1335        }
1336        deferInfo.batchId = mPaint->getColor() == SK_ColorBLACK ?
1337                DeferredDisplayList::kOpBatch_Text :
1338                DeferredDisplayList::kOpBatch_ColorText;
1339
1340        deferInfo.mergeId = reinterpret_cast<mergeid_t>(mPaint->getColor());
1341
1342        // don't merge decorated text - the decorations won't draw in order
1343        bool hasDecorations = mPaint->getFlags()
1344                & (SkPaint::kUnderlineText_Flag | SkPaint::kStrikeThruText_Flag);
1345
1346        deferInfo.mergeable = state.mMatrix.isPureTranslate()
1347                && !hasDecorations
1348                && OpenGLRenderer::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode;
1349    }
1350
1351    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1352        Rect bounds;
1353        getLocalBounds(bounds);
1354        renderer.drawText(mText, mBytesCount, mCount, mX, mY,
1355                mPositions, mPaint, mTotalAdvance, bounds);
1356    }
1357
1358    virtual void multiDraw(OpenGLRenderer& renderer, Rect& dirty,
1359            const Vector<OpStatePair>& ops, const Rect& bounds) {
1360        for (unsigned int i = 0; i < ops.size(); i++) {
1361            const DeferredDisplayState& state = *(ops[i].state);
1362            DrawOpMode drawOpMode = (i == ops.size() - 1) ? kDrawOpMode_Flush : kDrawOpMode_Defer;
1363            renderer.restoreDisplayState(state, true); // restore all but the clip
1364
1365            DrawTextOp& op = *((DrawTextOp*)ops[i].op);
1366            // quickReject() will not occure in drawText() so we can use mLocalBounds
1367            // directly, we do not need to account for shadow by calling getLocalBounds()
1368            renderer.drawText(op.mText, op.mBytesCount, op.mCount, op.mX, op.mY,
1369                    op.mPositions, op.mPaint, op.mTotalAdvance, op.mLocalBounds,
1370                    drawOpMode);
1371        }
1372    }
1373
1374    virtual void output(int level, uint32_t logFlags) const {
1375        OP_LOG("Draw Text of count %d, bytes %d", mCount, mBytesCount);
1376    }
1377
1378    virtual const char* name() { return "DrawText"; }
1379
1380private:
1381    const char* mText;
1382    int mBytesCount;
1383    int mCount;
1384    float mX;
1385    float mY;
1386    const float* mPositions;
1387    float mTotalAdvance;
1388    SkMatrix mPrecacheTransform;
1389};
1390
1391///////////////////////////////////////////////////////////////////////////////
1392// SPECIAL DRAW OPERATIONS
1393///////////////////////////////////////////////////////////////////////////////
1394
1395class DrawFunctorOp : public DrawOp {
1396public:
1397    DrawFunctorOp(Functor* functor)
1398            : DrawOp(NULL), mFunctor(functor) {}
1399
1400    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1401        renderer.startMark("GL functor");
1402        renderer.callDrawGLFunction(mFunctor, dirty);
1403        renderer.endMark();
1404    }
1405
1406    virtual void output(int level, uint32_t logFlags) const {
1407        OP_LOG("Draw Functor %p", mFunctor);
1408    }
1409
1410    virtual const char* name() { return "DrawFunctor"; }
1411
1412private:
1413    Functor* mFunctor;
1414};
1415
1416class DrawRenderNodeOp : public DrawBoundedOp {
1417    friend class RenderNode; // grant RenderNode access to info of child
1418    friend class DisplayListData; // grant DisplayListData access to info of child
1419public:
1420    DrawRenderNodeOp(RenderNode* renderNode, int flags, const mat4& transformFromParent)
1421            : DrawBoundedOp(0, 0, renderNode->getWidth(), renderNode->getHeight(), 0),
1422            mRenderNode(renderNode), mFlags(flags), mTransformFromParent(transformFromParent) {}
1423
1424    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
1425            bool useQuickReject) {
1426        if (mRenderNode->isRenderable() && !mSkipInOrderDraw) {
1427            mRenderNode->defer(deferStruct, level + 1);
1428        }
1429    }
1430
1431    virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level,
1432            bool useQuickReject) {
1433        if (mRenderNode->isRenderable() && !mSkipInOrderDraw) {
1434            mRenderNode->replay(replayStruct, level + 1);
1435        }
1436    }
1437
1438    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1439        LOG_ALWAYS_FATAL("should not be called, because replay() is overridden");
1440    }
1441
1442    virtual void output(int level, uint32_t logFlags) const {
1443        OP_LOG("Draw RenderNode %p %s, flags %#x", mRenderNode, mRenderNode->getName(), mFlags);
1444        if (mRenderNode && (logFlags & kOpLogFlag_Recurse)) {
1445            mRenderNode->output(level + 1);
1446        }
1447    }
1448
1449    virtual const char* name() { return "DrawRenderNode"; }
1450
1451    RenderNode* renderNode() { return mRenderNode; }
1452
1453private:
1454    RenderNode* mRenderNode;
1455    const int mFlags;
1456
1457    ///////////////////////////
1458    // Properties below are used by RenderNode::computeOrderingImpl() and issueOperations()
1459    ///////////////////////////
1460    /**
1461     * Records transform vs parent, used for computing total transform without rerunning DL contents
1462     */
1463    const mat4 mTransformFromParent;
1464
1465    /**
1466     * Holds the transformation between the projection surface ViewGroup and this RenderNode
1467     * drawing instance. Represents any translations / transformations done within the drawing of
1468     * the compositing ancestor ViewGroup's draw, before the draw of the View represented by this
1469     * DisplayList draw instance.
1470     *
1471     * Note: doesn't include transformation within the RenderNode, or its properties.
1472     */
1473    mat4 mTransformFromCompositingAncestor;
1474    bool mSkipInOrderDraw;
1475};
1476
1477/**
1478 * Not a canvas operation, used only by 3d / z ordering logic in RenderNode::iterate()
1479 */
1480class DrawShadowOp : public DrawOp {
1481public:
1482    DrawShadowOp(const mat4& transformXY, const mat4& transformZ,
1483            float casterAlpha, const SkPath* casterOutline)
1484        : DrawOp(NULL)
1485        , mTransformXY(transformXY)
1486        , mTransformZ(transformZ)
1487        , mCasterAlpha(casterAlpha)
1488        , mCasterOutline(casterOutline) {
1489    }
1490
1491    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
1492            const DeferredDisplayState& state) {
1493        renderer.getCaches().tessellationCache.precacheShadows(&state.mMatrix,
1494                renderer.getLocalClipBounds(), isCasterOpaque(), mCasterOutline,
1495                &mTransformXY, &mTransformZ, renderer.getLightCenter(), renderer.getLightRadius());
1496    }
1497
1498    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1499        TessellationCache::vertexBuffer_pair_t buffers;
1500        Matrix4 drawTransform(*(renderer.currentTransform()));
1501        renderer.getCaches().tessellationCache.getShadowBuffers(&drawTransform,
1502                renderer.getLocalClipBounds(), isCasterOpaque(), mCasterOutline,
1503                &mTransformXY, &mTransformZ, renderer.getLightCenter(), renderer.getLightRadius(),
1504                buffers);
1505
1506        renderer.drawShadow(mCasterAlpha, buffers.first, buffers.second);
1507    }
1508
1509    virtual void output(int level, uint32_t logFlags) const {
1510        OP_LOGS("DrawShadow");
1511    }
1512
1513    virtual const char* name() { return "DrawShadow"; }
1514
1515private:
1516    bool isCasterOpaque() { return mCasterAlpha >= 1.0f; }
1517
1518    const mat4 mTransformXY;
1519    const mat4 mTransformZ;
1520    const float mCasterAlpha;
1521    const SkPath* mCasterOutline;
1522};
1523
1524class DrawLayerOp : public DrawOp {
1525public:
1526    DrawLayerOp(Layer* layer, float x, float y)
1527            : DrawOp(NULL), mLayer(layer), mX(x), mY(y) {}
1528
1529    virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1530        renderer.drawLayer(mLayer, mX, mY);
1531    }
1532
1533    virtual void output(int level, uint32_t logFlags) const {
1534        OP_LOG("Draw Layer %p at %f %f", mLayer, mX, mY);
1535    }
1536
1537    virtual const char* name() { return "DrawLayer"; }
1538
1539private:
1540    Layer* mLayer;
1541    float mX;
1542    float mY;
1543};
1544
1545}; // namespace uirenderer
1546}; // namespace android
1547
1548#endif // ANDROID_HWUI_DISPLAY_OPERATION_H
1549