DisplayListOp.h revision 3b748a44c6bd2ea05fe16839caf73dbe50bd7ae9
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#define MATRIX_STRING "[%.2f %.2f %.2f] [%.2f %.2f %.2f] [%.2f %.2f %.2f]"
41#define MATRIX_ARGS(m) \
42    m->get(0), m->get(1), m->get(2), \
43    m->get(3), m->get(4), m->get(5), \
44    m->get(6), m->get(7), m->get(8)
45#define RECT_STRING "%.2f %.2f %.2f %.2f"
46#define RECT_ARGS(r) \
47    r.left, r.top, r.right, r.bottom
48
49// Use OP_LOG for logging with arglist, OP_LOGS if just printing char*
50#define OP_LOGS(s) OP_LOG("%s", s)
51#define OP_LOG(s, ...) ALOGD( "%*s" s, level * 2, "", __VA_ARGS__ )
52
53namespace android {
54namespace uirenderer {
55
56/**
57 * Structure for storing canvas operations when they are recorded into a DisplayList, so that they
58 * may be replayed to an OpenGLRenderer.
59 *
60 * To avoid individual memory allocations, DisplayListOps may only be allocated into a
61 * LinearAllocator's managed memory buffers.  Each pointer held by a DisplayListOp is either a
62 * pointer into memory also allocated in the LinearAllocator (mostly for text and float buffers) or
63 * references a externally refcounted object (Sk... and Skia... objects). ~DisplayListOp() is
64 * never called as LinearAllocators are simply discarded, so no memory management should be done in
65 * this class.
66 */
67class DisplayListOp {
68public:
69    // These objects should always be allocated with a LinearAllocator, and never destroyed/deleted.
70    // standard new() intentionally not implemented, and delete/deconstructor should never be used.
71    virtual ~DisplayListOp() { CRASH(); }
72    static void operator delete(void* ptr) { CRASH(); }
73    /** static void* operator new(size_t size); PURPOSELY OMITTED **/
74    static void* operator new(size_t size, LinearAllocator& allocator) {
75        return allocator.alloc(size);
76    }
77
78    enum OpLogFlag {
79        kOpLogFlag_Recurse = 0x1,
80        kOpLogFlag_JSON = 0x2 // TODO: add?
81    };
82
83    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
84            bool useQuickReject) = 0;
85
86    virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level,
87            bool useQuickReject) = 0;
88
89    virtual void output(int level, uint32_t logFlags = 0) = 0;
90
91    // NOTE: it would be nice to declare constants and overriding the implementation in each op to
92    // point at the constants, but that seems to require a .cpp file
93    virtual const char* name() = 0;
94
95    /**
96     * Stores the relevant canvas state of the object between deferral and replay (if the canvas
97     * state supports being stored) See OpenGLRenderer::simpleClipAndState()
98     *
99     * TODO: don't reserve space for StateOps that won't be deferred
100     */
101    DeferredDisplayState state;
102
103};
104
105class StateOp : public DisplayListOp {
106public:
107    StateOp() {};
108
109    virtual ~StateOp() {}
110
111    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
112            bool useQuickReject) {
113        // default behavior only affects immediate, deferrable state, issue directly to renderer
114        applyState(deferStruct.mRenderer, saveCount);
115    }
116
117    /**
118     * State operations are applied directly to the renderer, but can cause the deferred drawing op
119     * list to flush
120     */
121    virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level,
122            bool useQuickReject) {
123        applyState(replayStruct.mRenderer, saveCount);
124    }
125
126    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const = 0;
127};
128
129class DrawOp : public DisplayListOp {
130friend class MergingDrawBatch;
131public:
132    DrawOp(SkPaint* paint)
133            : mPaint(paint), mQuickRejected(false) {}
134
135    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
136            bool useQuickReject) {
137        if (mQuickRejected && CC_LIKELY(useQuickReject)) {
138            return;
139        }
140
141        if (!getLocalBounds(state.mBounds)) {
142            // empty bounds signify bounds can't be calculated
143            state.mBounds.setEmpty();
144        }
145
146        deferStruct.mDeferredList.addDrawOp(deferStruct.mRenderer, this);
147    }
148
149    virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level,
150            bool useQuickReject) {
151        if (mQuickRejected && CC_LIKELY(useQuickReject)) {
152            return;
153        }
154
155        replayStruct.mDrawGlStatus |= applyDraw(replayStruct.mRenderer, replayStruct.mDirty);
156    }
157
158    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) = 0;
159
160    /**
161     * Draw multiple instances of an operation, must be overidden for operations that merge
162     *
163     * Currently guarantees certain similarities between ops (see MergingDrawBatch::canMergeWith),
164     * and pure translation transformations. Other guarantees of similarity should be enforced by
165     * reducing which operations are tagged as mergeable.
166     */
167    virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
168            const Vector<DrawOp*>& ops, const Rect& bounds) {
169        status_t status = DrawGlInfo::kStatusDone;
170        for (unsigned int i = 0; i < ops.size(); i++) {
171            renderer.restoreDisplayState(ops[i]->state);
172            status |= ops[i]->applyDraw(renderer, dirty);
173        }
174        return status;
175    }
176
177    /*
178     * When this method is invoked the state field is initialized to have the
179     * final rendering state. We can thus use it to process data as it will be
180     * used at draw time.
181     *
182     * Additionally, this method allows subclasses to provide defer-time preferences for batching
183     * and merging.
184     *
185     * Return true if the op can merge with others of its kind (such subclasses should implement
186     * multiDraw)
187     */
188    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
189        return false;
190    }
191
192    // returns true if bounds exist
193    virtual bool getLocalBounds(Rect& localBounds) { return false; }
194
195    // TODO: better refine localbounds usage
196    void setQuickRejected(bool quickRejected) { mQuickRejected = quickRejected; }
197    bool getQuickRejected() { return mQuickRejected; }
198
199    inline int getPaintAlpha() {
200        return OpenGLRenderer::getAlphaDirect(mPaint);
201    }
202
203    inline float strokeWidthOutset() {
204        float width = mPaint->getStrokeWidth();
205        if (width == 0) return 0.5f; // account for hairline
206        return width * 0.5f;
207    }
208
209protected:
210    SkPaint* getPaint(OpenGLRenderer& renderer) {
211        return renderer.filterPaint(mPaint);
212    }
213
214    SkPaint* mPaint; // should be accessed via getPaint() when applying
215    bool mQuickRejected;
216};
217
218class DrawBoundedOp : public DrawOp {
219public:
220    DrawBoundedOp(float left, float top, float right, float bottom, SkPaint* paint)
221            : DrawOp(paint), mLocalBounds(left, top, right, bottom) {}
222
223    // Calculates bounds as smallest rect encompassing all points
224    // NOTE: requires at least 1 vertex, and doesn't account for stroke size (should be handled in
225    // subclass' constructor)
226    DrawBoundedOp(const float* points, int count, SkPaint* paint)
227            : DrawOp(paint), mLocalBounds(points[0], points[1], points[0], points[1]) {
228        for (int i = 2; i < count; i += 2) {
229            mLocalBounds.left = fminf(mLocalBounds.left, points[i]);
230            mLocalBounds.right = fmaxf(mLocalBounds.right, points[i]);
231            mLocalBounds.top = fminf(mLocalBounds.top, points[i + 1]);
232            mLocalBounds.bottom = fmaxf(mLocalBounds.bottom, points[i + 1]);
233        }
234    }
235
236    // default empty constructor for bounds, to be overridden in child constructor body
237    DrawBoundedOp(SkPaint* paint)
238            : DrawOp(paint) {}
239
240    bool getLocalBounds(Rect& localBounds) {
241        localBounds.set(mLocalBounds);
242        return true;
243    }
244
245    bool mergeAllowed() {
246        if (!state.mMatrix.isPureTranslate()) return false;
247
248        // checks that we're unclipped, and srcover
249        const Rect& opBounds = state.mBounds;
250        return fabs(opBounds.getWidth() - mLocalBounds.getWidth()) < 0.1 &&
251                fabs(opBounds.getHeight() - mLocalBounds.getHeight()) < 0.1 &&
252                (OpenGLRenderer::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode);
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 {
265    friend class DisplayList; // give DisplayList private constructor/reinit access
266public:
267    SaveOp(int flags)
268            : mFlags(flags) {}
269
270    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
271            bool useQuickReject) {
272        int newSaveCount = deferStruct.mRenderer.save(mFlags);
273        deferStruct.mDeferredList.addSave(deferStruct.mRenderer, this, newSaveCount);
274    }
275
276    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
277        renderer.save(mFlags);
278    }
279
280    virtual void output(int level, uint32_t logFlags) {
281        OP_LOG("Save flags %x", mFlags);
282    }
283
284    virtual const char* name() { return "Save"; }
285
286    int getFlags() const { return mFlags; }
287private:
288    SaveOp() {}
289    DisplayListOp* reinit(int flags) {
290        mFlags = flags;
291        return this;
292    }
293
294    int mFlags;
295};
296
297class RestoreToCountOp : public StateOp {
298    friend class DisplayList; // give DisplayList private constructor/reinit access
299public:
300    RestoreToCountOp(int count)
301            : mCount(count) {}
302
303    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
304            bool useQuickReject) {
305        deferStruct.mDeferredList.addRestoreToCount(deferStruct.mRenderer,
306                this, saveCount + mCount);
307        deferStruct.mRenderer.restoreToCount(saveCount + mCount);
308    }
309
310    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
311        renderer.restoreToCount(saveCount + mCount);
312    }
313
314    virtual void output(int level, uint32_t logFlags) {
315        OP_LOG("Restore to count %d", mCount);
316    }
317
318    virtual const char* name() { return "RestoreToCount"; }
319
320private:
321    RestoreToCountOp() {}
322    DisplayListOp* reinit(int count) {
323        mCount = count;
324        return this;
325    }
326
327    int mCount;
328};
329
330class SaveLayerOp : public StateOp {
331    friend class DisplayList; // give DisplayList private constructor/reinit access
332public:
333    SaveLayerOp(float left, float top, float right, float bottom,
334            int alpha, SkXfermode::Mode mode, int flags)
335            : mArea(left, top, right, bottom), mAlpha(alpha), mMode(mode), mFlags(flags) {}
336
337    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
338            bool useQuickReject) {
339        // NOTE: don't bother with actual saveLayer, instead issuing it at flush time
340        int newSaveCount = deferStruct.mRenderer.getSaveCount();
341        deferStruct.mDeferredList.addSaveLayer(deferStruct.mRenderer, this, newSaveCount);
342
343        // NOTE: don't issue full saveLayer, since that has side effects/is costly. instead just
344        // setup the snapshot for deferral, and re-issue the op at flush time
345        deferStruct.mRenderer.saveLayerDeferred(mArea.left, mArea.top, mArea.right, mArea.bottom,
346                mAlpha, mMode, mFlags);
347    }
348
349    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
350        renderer.saveLayer(mArea.left, mArea.top, mArea.right, mArea.bottom, mAlpha, mMode, mFlags);
351    }
352
353    virtual void output(int level, uint32_t logFlags) {
354        OP_LOG("SaveLayer%s of area " RECT_STRING,
355                (isSaveLayerAlpha() ? "Alpha" : ""),RECT_ARGS(mArea));
356    }
357
358    virtual const char* name() { return isSaveLayerAlpha() ? "SaveLayerAlpha" : "SaveLayer"; }
359
360    int getFlags() { return mFlags; }
361
362private:
363    // Special case, reserved for direct DisplayList usage
364    SaveLayerOp() {}
365    DisplayListOp* reinit(float left, float top, float right, float bottom,
366            int alpha, SkXfermode::Mode mode, int flags) {
367        mArea.set(left, top, right, bottom);
368        mAlpha = alpha;
369        mMode = mode;
370        mFlags = flags;
371        return this;
372    }
373
374    bool isSaveLayerAlpha() { return mAlpha < 255 && mMode == SkXfermode::kSrcOver_Mode; }
375    Rect mArea;
376    int mAlpha;
377    SkXfermode::Mode mMode;
378    int mFlags;
379};
380
381class TranslateOp : public StateOp {
382public:
383    TranslateOp(float dx, float dy)
384            : mDx(dx), mDy(dy) {}
385
386    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
387        renderer.translate(mDx, mDy);
388    }
389
390    virtual void output(int level, uint32_t logFlags) {
391        OP_LOG("Translate by %f %f", mDx, mDy);
392    }
393
394    virtual const char* name() { return "Translate"; }
395
396private:
397    float mDx;
398    float mDy;
399};
400
401class RotateOp : public StateOp {
402public:
403    RotateOp(float degrees)
404            : mDegrees(degrees) {}
405
406    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
407        renderer.rotate(mDegrees);
408    }
409
410    virtual void output(int level, uint32_t logFlags) {
411        OP_LOG("Rotate by %f degrees", mDegrees);
412    }
413
414    virtual const char* name() { return "Rotate"; }
415
416private:
417    float mDegrees;
418};
419
420class ScaleOp : public StateOp {
421public:
422    ScaleOp(float sx, float sy)
423            : mSx(sx), mSy(sy) {}
424
425    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
426        renderer.scale(mSx, mSy);
427    }
428
429    virtual void output(int level, uint32_t logFlags) {
430        OP_LOG("Scale by %f %f", mSx, mSy);
431    }
432
433    virtual const char* name() { return "Scale"; }
434
435private:
436    float mSx;
437    float mSy;
438};
439
440class SkewOp : public StateOp {
441public:
442    SkewOp(float sx, float sy)
443            : mSx(sx), mSy(sy) {}
444
445    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
446        renderer.skew(mSx, mSy);
447    }
448
449    virtual void output(int level, uint32_t logFlags) {
450        OP_LOG("Skew by %f %f", mSx, mSy);
451    }
452
453    virtual const char* name() { return "Skew"; }
454
455private:
456    float mSx;
457    float mSy;
458};
459
460class SetMatrixOp : public StateOp {
461public:
462    SetMatrixOp(SkMatrix* matrix)
463            : mMatrix(matrix) {}
464
465    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
466        renderer.setMatrix(mMatrix);
467    }
468
469    virtual void output(int level, uint32_t logFlags) {
470        OP_LOG("SetMatrix " MATRIX_STRING, MATRIX_ARGS(mMatrix));
471    }
472
473    virtual const char* name() { return "SetMatrix"; }
474
475private:
476    SkMatrix* mMatrix;
477};
478
479class ConcatMatrixOp : public StateOp {
480public:
481    ConcatMatrixOp(SkMatrix* matrix)
482            : mMatrix(matrix) {}
483
484    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
485        renderer.concatMatrix(mMatrix);
486    }
487
488    virtual void output(int level, uint32_t logFlags) {
489        OP_LOG("ConcatMatrix " MATRIX_STRING, MATRIX_ARGS(mMatrix));
490    }
491
492    virtual const char* name() { return "ConcatMatrix"; }
493
494private:
495    SkMatrix* mMatrix;
496};
497
498class ClipOp : public StateOp {
499public:
500    ClipOp(SkRegion::Op op) : mOp(op) {}
501
502    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
503            bool useQuickReject) {
504        // NOTE: must defer op BEFORE applying state, since it may read clip
505        deferStruct.mDeferredList.addClip(deferStruct.mRenderer, this);
506
507        // TODO: Can we avoid applying complex clips at defer time?
508        applyState(deferStruct.mRenderer, saveCount);
509    }
510
511    bool canCauseComplexClip() {
512        return ((mOp != SkRegion::kIntersect_Op) && (mOp != SkRegion::kReplace_Op)) || !isRect();
513    }
514
515protected:
516    ClipOp() {}
517    virtual bool isRect() { return false; }
518
519    SkRegion::Op mOp;
520};
521
522class ClipRectOp : public ClipOp {
523    friend class DisplayList; // give DisplayList private constructor/reinit access
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) {
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) {
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) {
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    SkRegion::Op mOp;
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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) {
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), mAtlasEntry(NULL) {
735    }
736
737    DrawBitmapOp(SkBitmap* bitmap, float left, float top, SkPaint* paint,
738            const AssetAtlas::Entry* entry)
739            : DrawBoundedOp(left, top, left + bitmap->width(), top + bitmap->height(), paint),
740            mBitmap(bitmap), mAtlasEntry(entry) {
741        if (entry) mUvMapper = entry->uvMapper;
742    }
743
744    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
745        return renderer.drawBitmap(mBitmap, mLocalBounds.left, mLocalBounds.top,
746                getPaint(renderer));
747    }
748
749#define SET_TEXTURE(ptr, posRect, offsetRect, texCoordsRect, xDim, yDim) \
750    TextureVertex::set(ptr++, posRect.xDim - offsetRect.left, posRect.yDim - offsetRect.top, \
751            texCoordsRect.xDim, texCoordsRect.yDim)
752
753    virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
754            const Vector<DrawOp*>& ops, const Rect& bounds) {
755        renderer.restoreDisplayState(state, true); // restore all but the clip
756        renderer.setFullScreenClip(); // ensure merged ops aren't clipped
757        TextureVertex vertices[6 * ops.size()];
758        TextureVertex* vertex = &vertices[0];
759
760        // TODO: manually handle rect clip for bitmaps by adjusting texCoords per op,
761        // and allowing them to be merged in getBatchId()
762        for (unsigned int i = 0; i < ops.size(); i++) {
763            const Rect& opBounds = ops[i]->state.mBounds;
764
765            Rect texCoords(0, 0, 1, 1);
766            ((DrawBitmapOp*) ops[i])->mUvMapper.map(texCoords);
767
768            SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, top);
769            SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, top);
770            SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, bottom);
771
772            SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, bottom);
773            SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, top);
774            SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, bottom);
775        }
776
777        return renderer.drawBitmaps(mBitmap, ops.size(), &vertices[0], bounds, mPaint);
778    }
779
780    virtual void output(int level, uint32_t logFlags) {
781        OP_LOG("Draw bitmap %p at %f %f", mBitmap, mLocalBounds.left, mLocalBounds.top);
782    }
783
784    virtual const char* name() { return "DrawBitmap"; }
785
786    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
787        *batchId = DeferredDisplayList::kOpBatch_Bitmap;
788        *mergeId = mAtlasEntry ? (mergeid_t) &mAtlasEntry->atlas : (mergeid_t) mBitmap;
789
790        // don't merge A8 bitmaps - the paint's color isn't compared by mergeId, or in
791        // MergingDrawBatch::canMergeWith
792        return mergeAllowed() && (mBitmap->getConfig() != SkBitmap::kA8_Config);
793    }
794
795    const SkBitmap* bitmap() { return mBitmap; }
796protected:
797    SkBitmap* mBitmap;
798    const AssetAtlas::Entry* mAtlasEntry;
799    UvMapper mUvMapper;
800};
801
802class DrawBitmapMatrixOp : public DrawBoundedOp {
803public:
804    DrawBitmapMatrixOp(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint)
805            : DrawBoundedOp(paint), mBitmap(bitmap), mMatrix(matrix) {
806        mLocalBounds.set(0, 0, bitmap->width(), bitmap->height());
807        const mat4 transform(*matrix);
808        transform.mapRect(mLocalBounds);
809    }
810
811    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
812        return renderer.drawBitmap(mBitmap, mMatrix, getPaint(renderer));
813    }
814
815    virtual void output(int level, uint32_t logFlags) {
816        OP_LOG("Draw bitmap %p matrix " MATRIX_STRING, mBitmap, MATRIX_ARGS(mMatrix));
817    }
818
819    virtual const char* name() { return "DrawBitmapMatrix"; }
820
821    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
822        *batchId = DeferredDisplayList::kOpBatch_Bitmap;
823        return false;
824    }
825
826private:
827    SkBitmap* mBitmap;
828    SkMatrix* mMatrix;
829};
830
831class DrawBitmapRectOp : public DrawBoundedOp {
832public:
833    DrawBitmapRectOp(SkBitmap* bitmap, float srcLeft, float srcTop, float srcRight, float srcBottom,
834            float dstLeft, float dstTop, float dstRight, float dstBottom, SkPaint* paint)
835            : DrawBoundedOp(dstLeft, dstTop, dstRight, dstBottom, paint),
836            mBitmap(bitmap), mSrc(srcLeft, srcTop, srcRight, srcBottom) {}
837
838    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
839        return renderer.drawBitmap(mBitmap, mSrc.left, mSrc.top, mSrc.right, mSrc.bottom,
840                mLocalBounds.left, mLocalBounds.top, mLocalBounds.right, mLocalBounds.bottom,
841                getPaint(renderer));
842    }
843
844    virtual void output(int level, uint32_t logFlags) {
845        OP_LOG("Draw bitmap %p src="RECT_STRING", dst="RECT_STRING,
846                mBitmap, RECT_ARGS(mSrc), RECT_ARGS(mLocalBounds));
847    }
848
849    virtual const char* name() { return "DrawBitmapRect"; }
850
851    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
852        *batchId = DeferredDisplayList::kOpBatch_Bitmap;
853        return false;
854    }
855
856private:
857    SkBitmap* mBitmap;
858    Rect mSrc;
859};
860
861class DrawBitmapDataOp : public DrawBitmapOp {
862public:
863    DrawBitmapDataOp(SkBitmap* bitmap, float left, float top, SkPaint* paint)
864            : DrawBitmapOp(bitmap, left, top, paint) {}
865
866    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
867        return renderer.drawBitmapData(mBitmap, mLocalBounds.left,
868                mLocalBounds.top, getPaint(renderer));
869    }
870
871    virtual void output(int level, uint32_t logFlags) {
872        OP_LOG("Draw bitmap %p", mBitmap);
873    }
874
875    virtual const char* name() { return "DrawBitmapData"; }
876
877    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
878        *batchId = DeferredDisplayList::kOpBatch_Bitmap;
879        return false;
880    }
881};
882
883class DrawBitmapMeshOp : public DrawBoundedOp {
884public:
885    DrawBitmapMeshOp(SkBitmap* bitmap, int meshWidth, int meshHeight,
886            float* vertices, int* colors, SkPaint* paint)
887            : DrawBoundedOp(vertices, 2 * (meshWidth + 1) * (meshHeight + 1), paint),
888            mBitmap(bitmap), mMeshWidth(meshWidth), mMeshHeight(meshHeight),
889            mVertices(vertices), mColors(colors) {}
890
891    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
892        return renderer.drawBitmapMesh(mBitmap, mMeshWidth, mMeshHeight,
893                mVertices, mColors, getPaint(renderer));
894    }
895
896    virtual void output(int level, uint32_t logFlags) {
897        OP_LOG("Draw bitmap %p mesh %d x %d", mBitmap, mMeshWidth, mMeshHeight);
898    }
899
900    virtual const char* name() { return "DrawBitmapMesh"; }
901
902    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
903        *batchId = DeferredDisplayList::kOpBatch_Bitmap;
904        return false;
905    }
906
907private:
908    SkBitmap* mBitmap;
909    int mMeshWidth;
910    int mMeshHeight;
911    float* mVertices;
912    int* mColors;
913};
914
915class DrawPatchOp : public DrawBoundedOp {
916public:
917    DrawPatchOp(SkBitmap* bitmap, Res_png_9patch* patch,
918            float left, float top, float right, float bottom, int alpha, SkXfermode::Mode mode)
919            : DrawBoundedOp(left, top, right, bottom, 0),
920            mBitmap(bitmap), mPatch(patch), mAlpha(alpha), mMode(mode) {
921        mEntry = Caches::getInstance().assetAtlas.getEntry(bitmap);
922    };
923
924    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
925        // NOTE: not calling the virtual method, which takes a paint
926        return renderer.drawPatch(mBitmap, mPatch, mEntry, mLocalBounds.left, mLocalBounds.top,
927                mLocalBounds.right, mLocalBounds.bottom, mAlpha, mMode);
928    }
929
930    virtual void output(int level, uint32_t logFlags) {
931        OP_LOG("Draw patch "RECT_STRING, RECT_ARGS(mLocalBounds));
932    }
933
934    virtual const char* name() { return "DrawPatch"; }
935
936    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
937        *batchId = DeferredDisplayList::kOpBatch_Patch;
938        *mergeId = (mergeid_t) mBitmap;
939        return true;
940    }
941
942private:
943    SkBitmap* mBitmap;
944    Res_png_9patch* mPatch;
945    int mAlpha;
946    SkXfermode::Mode mMode;
947    AssetAtlas::Entry* mEntry;
948};
949
950class DrawColorOp : public DrawOp {
951public:
952    DrawColorOp(int color, SkXfermode::Mode mode)
953            : DrawOp(0), mColor(color), mMode(mode) {};
954
955    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
956        return renderer.drawColor(mColor, mMode);
957    }
958
959    virtual void output(int level, uint32_t logFlags) {
960        OP_LOG("Draw color %#x, mode %d", mColor, mMode);
961    }
962
963    virtual const char* name() { return "DrawColor"; }
964
965private:
966    int mColor;
967    SkXfermode::Mode mMode;
968};
969
970class DrawStrokableOp : public DrawBoundedOp {
971public:
972    DrawStrokableOp(float left, float top, float right, float bottom, SkPaint* paint)
973            : DrawBoundedOp(left, top, right, bottom, paint) {};
974
975    bool getLocalBounds(Rect& localBounds) {
976        localBounds.set(mLocalBounds);
977        if (mPaint && mPaint->getStyle() != SkPaint::kFill_Style) {
978            localBounds.outset(strokeWidthOutset());
979        }
980        return true;
981    }
982
983    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
984        if (mPaint->getPathEffect()) {
985            *batchId = DeferredDisplayList::kOpBatch_AlphaMaskTexture;
986        } else {
987            *batchId = mPaint->isAntiAlias() ?
988                    DeferredDisplayList::kOpBatch_AlphaVertices :
989                    DeferredDisplayList::kOpBatch_Vertices;
990        }
991        return false;
992    }
993};
994
995class DrawRectOp : public DrawStrokableOp {
996public:
997    DrawRectOp(float left, float top, float right, float bottom, SkPaint* paint)
998            : DrawStrokableOp(left, top, right, bottom, paint) {}
999
1000    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1001        return renderer.drawRect(mLocalBounds.left, mLocalBounds.top,
1002                mLocalBounds.right, mLocalBounds.bottom, getPaint(renderer));
1003    }
1004
1005    virtual void output(int level, uint32_t logFlags) {
1006        OP_LOG("Draw Rect "RECT_STRING, RECT_ARGS(mLocalBounds));
1007    }
1008
1009    virtual const char* name() { return "DrawRect"; }
1010};
1011
1012class DrawRectsOp : public DrawBoundedOp {
1013public:
1014    DrawRectsOp(const float* rects, int count, SkPaint* paint)
1015            : DrawBoundedOp(rects, count, paint),
1016            mRects(rects), mCount(count) {}
1017
1018    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1019        return renderer.drawRects(mRects, mCount, getPaint(renderer));
1020    }
1021
1022    virtual void output(int level, uint32_t logFlags) {
1023        OP_LOG("Draw Rects count %d", mCount);
1024    }
1025
1026    virtual const char* name() { return "DrawRects"; }
1027
1028    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
1029        *batchId = DeferredDisplayList::kOpBatch_Vertices;
1030        return false;
1031    }
1032
1033private:
1034    const float* mRects;
1035    int mCount;
1036};
1037
1038class DrawRoundRectOp : public DrawStrokableOp {
1039public:
1040    DrawRoundRectOp(float left, float top, float right, float bottom,
1041            float rx, float ry, SkPaint* paint)
1042            : DrawStrokableOp(left, top, right, bottom, paint), mRx(rx), mRy(ry) {}
1043
1044    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1045        return renderer.drawRoundRect(mLocalBounds.left, mLocalBounds.top,
1046                mLocalBounds.right, mLocalBounds.bottom, mRx, mRy, getPaint(renderer));
1047    }
1048
1049    virtual void output(int level, uint32_t logFlags) {
1050        OP_LOG("Draw RoundRect "RECT_STRING", rx %f, ry %f", RECT_ARGS(mLocalBounds), mRx, mRy);
1051    }
1052
1053    virtual const char* name() { return "DrawRoundRect"; }
1054
1055private:
1056    float mRx;
1057    float mRy;
1058};
1059
1060class DrawCircleOp : public DrawStrokableOp {
1061public:
1062    DrawCircleOp(float x, float y, float radius, SkPaint* paint)
1063            : DrawStrokableOp(x - radius, y - radius, x + radius, y + radius, paint),
1064            mX(x), mY(y), mRadius(radius) {}
1065
1066    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1067        return renderer.drawCircle(mX, mY, mRadius, getPaint(renderer));
1068    }
1069
1070    virtual void output(int level, uint32_t logFlags) {
1071        OP_LOG("Draw Circle x %f, y %f, r %f", mX, mY, mRadius);
1072    }
1073
1074    virtual const char* name() { return "DrawCircle"; }
1075
1076private:
1077    float mX;
1078    float mY;
1079    float mRadius;
1080};
1081
1082class DrawOvalOp : public DrawStrokableOp {
1083public:
1084    DrawOvalOp(float left, float top, float right, float bottom, SkPaint* paint)
1085            : DrawStrokableOp(left, top, right, bottom, paint) {}
1086
1087    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1088        return renderer.drawOval(mLocalBounds.left, mLocalBounds.top,
1089                mLocalBounds.right, mLocalBounds.bottom, getPaint(renderer));
1090    }
1091
1092    virtual void output(int level, uint32_t logFlags) {
1093        OP_LOG("Draw Oval "RECT_STRING, RECT_ARGS(mLocalBounds));
1094    }
1095
1096    virtual const char* name() { return "DrawOval"; }
1097};
1098
1099class DrawArcOp : public DrawStrokableOp {
1100public:
1101    DrawArcOp(float left, float top, float right, float bottom,
1102            float startAngle, float sweepAngle, bool useCenter, SkPaint* paint)
1103            : DrawStrokableOp(left, top, right, bottom, paint),
1104            mStartAngle(startAngle), mSweepAngle(sweepAngle), mUseCenter(useCenter) {}
1105
1106    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1107        return renderer.drawArc(mLocalBounds.left, mLocalBounds.top,
1108                mLocalBounds.right, mLocalBounds.bottom,
1109                mStartAngle, mSweepAngle, mUseCenter, getPaint(renderer));
1110    }
1111
1112    virtual void output(int level, uint32_t logFlags) {
1113        OP_LOG("Draw Arc "RECT_STRING", start %f, sweep %f, useCenter %d",
1114                RECT_ARGS(mLocalBounds), mStartAngle, mSweepAngle, mUseCenter);
1115    }
1116
1117    virtual const char* name() { return "DrawArc"; }
1118
1119private:
1120    float mStartAngle;
1121    float mSweepAngle;
1122    bool mUseCenter;
1123};
1124
1125class DrawPathOp : public DrawBoundedOp {
1126public:
1127    DrawPathOp(SkPath* path, SkPaint* paint)
1128            : DrawBoundedOp(paint), mPath(path) {
1129        float left, top, offset;
1130        uint32_t width, height;
1131        PathCache::computePathBounds(path, paint, left, top, offset, width, height);
1132        left -= offset;
1133        top -= offset;
1134        mLocalBounds.set(left, top, left + width, top + height);
1135    }
1136
1137    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1138        return renderer.drawPath(mPath, getPaint(renderer));
1139    }
1140
1141    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
1142        SkPaint* paint = getPaint(renderer);
1143        renderer.getCaches().pathCache.precache(mPath, paint);
1144
1145        *batchId = DeferredDisplayList::kOpBatch_AlphaMaskTexture;
1146        return false;
1147    }
1148
1149    virtual void output(int level, uint32_t logFlags) {
1150        OP_LOG("Draw Path %p in "RECT_STRING, mPath, RECT_ARGS(mLocalBounds));
1151    }
1152
1153    virtual const char* name() { return "DrawPath"; }
1154
1155private:
1156    SkPath* mPath;
1157};
1158
1159class DrawLinesOp : public DrawBoundedOp {
1160public:
1161    DrawLinesOp(float* points, int count, SkPaint* paint)
1162            : DrawBoundedOp(points, count, paint),
1163            mPoints(points), mCount(count) {
1164        mLocalBounds.outset(strokeWidthOutset());
1165    }
1166
1167    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1168        return renderer.drawLines(mPoints, mCount, getPaint(renderer));
1169    }
1170
1171    virtual void output(int level, uint32_t logFlags) {
1172        OP_LOG("Draw Lines count %d", mCount);
1173    }
1174
1175    virtual const char* name() { return "DrawLines"; }
1176
1177    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
1178        *batchId = mPaint->isAntiAlias() ?
1179                DeferredDisplayList::kOpBatch_AlphaVertices :
1180                DeferredDisplayList::kOpBatch_Vertices;
1181        return false;
1182    }
1183
1184protected:
1185    float* mPoints;
1186    int mCount;
1187};
1188
1189class DrawPointsOp : public DrawLinesOp {
1190public:
1191    DrawPointsOp(float* points, int count, SkPaint* paint)
1192            : DrawLinesOp(points, count, paint) {}
1193
1194    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1195        return renderer.drawPoints(mPoints, mCount, getPaint(renderer));
1196    }
1197
1198    virtual void output(int level, uint32_t logFlags) {
1199        OP_LOG("Draw Points count %d", mCount);
1200    }
1201
1202    virtual const char* name() { return "DrawPoints"; }
1203};
1204
1205class DrawSomeTextOp : public DrawOp {
1206public:
1207    DrawSomeTextOp(const char* text, int bytesCount, int count, SkPaint* paint)
1208            : DrawOp(paint), mText(text), mBytesCount(bytesCount), mCount(count) {};
1209
1210    virtual void output(int level, uint32_t logFlags) {
1211        OP_LOG("Draw some text, %d bytes", mBytesCount);
1212    }
1213
1214    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
1215        SkPaint* paint = getPaint(renderer);
1216        FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(paint);
1217        fontRenderer.precache(paint, mText, mCount, mat4::identity());
1218
1219        *batchId = mPaint->getColor() == 0xff000000 ?
1220                DeferredDisplayList::kOpBatch_Text :
1221                DeferredDisplayList::kOpBatch_ColorText;
1222
1223        return false;
1224    }
1225
1226protected:
1227    const char* mText;
1228    int mBytesCount;
1229    int mCount;
1230};
1231
1232class DrawTextOnPathOp : public DrawSomeTextOp {
1233public:
1234    DrawTextOnPathOp(const char* text, int bytesCount, int count,
1235            SkPath* path, float hOffset, float vOffset, SkPaint* paint)
1236            : DrawSomeTextOp(text, bytesCount, count, paint),
1237            mPath(path), mHOffset(hOffset), mVOffset(vOffset) {
1238        /* TODO: inherit from DrawBounded and init mLocalBounds */
1239    }
1240
1241    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1242        return renderer.drawTextOnPath(mText, mBytesCount, mCount, mPath,
1243                mHOffset, mVOffset, getPaint(renderer));
1244    }
1245
1246    virtual const char* name() { return "DrawTextOnPath"; }
1247
1248private:
1249    SkPath* mPath;
1250    float mHOffset;
1251    float mVOffset;
1252};
1253
1254class DrawPosTextOp : public DrawSomeTextOp {
1255public:
1256    DrawPosTextOp(const char* text, int bytesCount, int count,
1257            const float* positions, SkPaint* paint)
1258            : DrawSomeTextOp(text, bytesCount, count, paint), mPositions(positions) {
1259        /* TODO: inherit from DrawBounded and init mLocalBounds */
1260    }
1261
1262    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1263        return renderer.drawPosText(mText, mBytesCount, mCount, mPositions, getPaint(renderer));
1264    }
1265
1266    virtual const char* name() { return "DrawPosText"; }
1267
1268private:
1269    const float* mPositions;
1270};
1271
1272class DrawTextOp : public DrawBoundedOp {
1273public:
1274    DrawTextOp(const char* text, int bytesCount, int count, float x, float y,
1275            const float* positions, SkPaint* paint, float length)
1276            : DrawBoundedOp(paint), mText(text), mBytesCount(bytesCount), mCount(count),
1277            mX(x), mY(y), mPositions(positions), mLength(length) {
1278        // duplicates bounds calculation from OpenGLRenderer::drawText, but doesn't alter mX
1279        SkPaint::FontMetrics metrics;
1280        paint->getFontMetrics(&metrics, 0.0f);
1281        switch (paint->getTextAlign()) {
1282        case SkPaint::kCenter_Align:
1283            x -= length / 2.0f;
1284            break;
1285        case SkPaint::kRight_Align:
1286            x -= length;
1287            break;
1288        default:
1289            break;
1290        }
1291        mLocalBounds.set(x, mY + metrics.fTop, x + length, mY + metrics.fBottom);
1292        memset(&mPrecacheTransform.data[0], 0xff, 16 * sizeof(float));
1293    }
1294
1295    virtual bool onDefer(OpenGLRenderer& renderer, int* batchId, mergeid_t* mergeId) {
1296        SkPaint* paint = getPaint(renderer);
1297        FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(paint);
1298        const mat4& transform = renderer.findBestFontTransform(state.mMatrix);
1299        if (mPrecacheTransform != transform) {
1300            fontRenderer.precache(paint, mText, mCount, transform);
1301            mPrecacheTransform = transform;
1302        }
1303        *batchId = mPaint->getColor() == 0xff000000 ?
1304                DeferredDisplayList::kOpBatch_Text :
1305                DeferredDisplayList::kOpBatch_ColorText;
1306
1307        *mergeId = (mergeid_t)mPaint->getColor();
1308
1309        // don't merge decorated text - the decorations won't draw in order
1310        bool noDecorations = !(mPaint->getFlags() & (SkPaint::kUnderlineText_Flag |
1311                        SkPaint::kStrikeThruText_Flag));
1312        return mergeAllowed() && noDecorations;
1313    }
1314
1315    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1316        return renderer.drawText(mText, mBytesCount, mCount, mX, mY,
1317                mPositions, getPaint(renderer), mLength);
1318    }
1319
1320    virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
1321            const Vector<DrawOp*>& ops, const Rect& bounds) {
1322        status_t status = DrawGlInfo::kStatusDone;
1323        renderer.setFullScreenClip(); // ensure merged ops aren't clipped
1324        for (unsigned int i = 0; i < ops.size(); i++) {
1325            DrawOpMode drawOpMode = (i == ops.size() - 1) ? kDrawOpMode_Flush : kDrawOpMode_Defer;
1326            renderer.restoreDisplayState(ops[i]->state, true); // restore all but the clip
1327
1328            DrawTextOp& op = *((DrawTextOp*)ops[i]);
1329            status |= renderer.drawText(op.mText, op.mBytesCount, op.mCount, op.mX, op.mY,
1330                    op.mPositions, op.getPaint(renderer), op.mLength, drawOpMode);
1331        }
1332        return status;
1333    }
1334
1335    virtual void output(int level, uint32_t logFlags) {
1336        OP_LOG("Draw Text of count %d, bytes %d", mCount, mBytesCount);
1337    }
1338
1339    virtual const char* name() { return "DrawText"; }
1340
1341private:
1342    const char* mText;
1343    int mBytesCount;
1344    int mCount;
1345    float mX;
1346    float mY;
1347    const float* mPositions;
1348    float mLength;
1349    mat4 mPrecacheTransform;
1350};
1351
1352///////////////////////////////////////////////////////////////////////////////
1353// SPECIAL DRAW OPERATIONS
1354///////////////////////////////////////////////////////////////////////////////
1355
1356class DrawFunctorOp : public DrawOp {
1357public:
1358    DrawFunctorOp(Functor* functor)
1359            : DrawOp(0), mFunctor(functor) {}
1360
1361    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1362        renderer.startMark("GL functor");
1363        status_t ret = renderer.callDrawGLFunction(mFunctor, dirty);
1364        renderer.endMark();
1365        return ret;
1366    }
1367
1368    virtual void output(int level, uint32_t logFlags) {
1369        OP_LOG("Draw Functor %p", mFunctor);
1370    }
1371
1372    virtual const char* name() { return "DrawFunctor"; }
1373
1374private:
1375    Functor* mFunctor;
1376};
1377
1378class DrawDisplayListOp : public DrawBoundedOp {
1379public:
1380    DrawDisplayListOp(DisplayList* displayList, int flags)
1381            : DrawBoundedOp(0, 0, displayList->getWidth(), displayList->getHeight(), 0),
1382            mDisplayList(displayList), mFlags(flags) {}
1383
1384    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
1385            bool useQuickReject) {
1386        if (mDisplayList && mDisplayList->isRenderable()) {
1387            mDisplayList->defer(deferStruct, level + 1);
1388        }
1389    }
1390    virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level,
1391            bool useQuickReject) {
1392        if (mDisplayList && mDisplayList->isRenderable()) {
1393            mDisplayList->replay(replayStruct, level + 1);
1394        }
1395    }
1396
1397    // NOT USED since replay() is overridden
1398    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1399        return DrawGlInfo::kStatusDone;
1400    }
1401
1402    virtual void output(int level, uint32_t logFlags) {
1403        OP_LOG("Draw Display List %p, flags %#x", mDisplayList, mFlags);
1404        if (mDisplayList && (logFlags & kOpLogFlag_Recurse)) {
1405            mDisplayList->output(level + 1);
1406        }
1407    }
1408
1409    virtual const char* name() { return "DrawDisplayList"; }
1410
1411private:
1412    DisplayList* mDisplayList;
1413    int mFlags;
1414};
1415
1416class DrawLayerOp : public DrawOp {
1417public:
1418    DrawLayerOp(Layer* layer, float x, float y)
1419            : DrawOp(0), mLayer(layer), mX(x), mY(y) {}
1420
1421    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1422        return renderer.drawLayer(mLayer, mX, mY);
1423    }
1424
1425    virtual void output(int level, uint32_t logFlags) {
1426        OP_LOG("Draw Layer %p at %f %f", mLayer, mX, mY);
1427    }
1428
1429    virtual const char* name() { return "DrawLayer"; }
1430
1431private:
1432    Layer* mLayer;
1433    float mX;
1434    float mY;
1435};
1436
1437}; // namespace uirenderer
1438}; // namespace android
1439
1440#endif // ANDROID_HWUI_DISPLAY_OPERATION_H
1441