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