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