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