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