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