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