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