DisplayListOp.h revision d90144db52c7297879b950cbbc85137ed123ab5b
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 "DeferredDisplayList.h"
30#include "DisplayListRenderer.h"
31#include "utils/LinearAllocator.h"
32
33#define CRASH() do { \
34    *(int *)(uintptr_t)0xbbadbeef = 0; \
35    ((void(*)())0)(); /* More reliable, but doesn't say BBADBEEF */ \
36} while(false)
37
38#define MATRIX_STRING "[%.2f %.2f %.2f] [%.2f %.2f %.2f] [%.2f %.2f %.2f]"
39#define MATRIX_ARGS(m) \
40    m->get(0), m->get(1), m->get(2), \
41    m->get(3), m->get(4), m->get(5), \
42    m->get(6), m->get(7), m->get(8)
43#define RECT_STRING "%.2f %.2f %.2f %.2f"
44#define RECT_ARGS(r) \
45    r.left, r.top, r.right, r.bottom
46
47// Use OP_LOG for logging with arglist, OP_LOGS if just printing char*
48#define OP_LOGS(s) OP_LOG("%s", s)
49#define OP_LOG(s, ...) ALOGD( "%*s" s, level * 2, "", __VA_ARGS__ )
50
51namespace android {
52namespace uirenderer {
53
54/**
55 * Structure for storing canvas operations when they are recorded into a DisplayList, so that they
56 * may be replayed to an OpenGLRenderer.
57 *
58 * To avoid individual memory allocations, DisplayListOps may only be allocated into a
59 * LinearAllocator's managed memory buffers.  Each pointer held by a DisplayListOp is either a
60 * pointer into memory also allocated in the LinearAllocator (mostly for text and float buffers) or
61 * references a externally refcounted object (Sk... and Skia... objects). ~DisplayListOp() is
62 * never called as LinearAllocators are simply discarded, so no memory management should be done in
63 * this class.
64 */
65class DisplayListOp {
66public:
67    // These objects should always be allocated with a LinearAllocator, and never destroyed/deleted.
68    // standard new() intentionally not implemented, and delete/deconstructor should never be used.
69    virtual ~DisplayListOp() { CRASH(); }
70    static void operator delete(void* ptr) { CRASH(); }
71    /** static void* operator new(size_t size); PURPOSELY OMITTED **/
72    static void* operator new(size_t size, LinearAllocator& allocator) {
73        return allocator.alloc(size);
74    }
75
76    enum OpLogFlag {
77        kOpLogFlag_Recurse = 0x1,
78        kOpLogFlag_JSON = 0x2 // TODO: add?
79    };
80
81    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level) = 0;
82
83    virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level) = 0;
84
85    virtual void output(int level, uint32_t logFlags = 0) = 0;
86
87    // NOTE: it would be nice to declare constants and overriding the implementation in each op to
88    // point at the constants, but that seems to require a .cpp file
89    virtual const char* name() = 0;
90
91    /**
92     * Stores the relevant canvas state of the object between deferral and replay (if the canvas
93     * state supports being stored) See OpenGLRenderer::simpleClipAndState()
94     *
95     * TODO: don't reserve space for StateOps that won't be deferred
96     */
97    DeferredDisplayState state;
98
99};
100
101class StateOp : public DisplayListOp {
102public:
103    StateOp() {};
104
105    virtual ~StateOp() {}
106
107    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level) {
108        // default behavior only affects immediate, deferrable state, issue directly to renderer
109        applyState(deferStruct.mRenderer, saveCount);
110    }
111
112    /**
113     * State operations are applied directly to the renderer, but can cause the deferred drawing op
114     * list to flush
115     */
116    virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level) {
117        applyState(replayStruct.mRenderer, saveCount);
118    }
119
120    virtual void applyState(OpenGLRenderer& renderer, int saveCount) = 0;
121};
122
123class DrawOp : public DisplayListOp {
124public:
125    DrawOp(SkPaint* paint)
126            : mPaint(paint), mQuickRejected(false) {}
127
128    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level) {
129        if (mQuickRejected &&
130                CC_LIKELY(deferStruct.mReplayFlags & DisplayList::kReplayFlag_ClipChildren)) {
131            return;
132        }
133
134        if (!getLocalBounds(state.mBounds)) {
135            // empty bounds signify bounds can't be calculated
136            state.mBounds.setEmpty();
137        }
138
139        deferStruct.mDeferredList.addDrawOp(deferStruct.mRenderer, this);
140    }
141
142    virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level) {
143        if (mQuickRejected &&
144                CC_LIKELY(replayStruct.mReplayFlags & DisplayList::kReplayFlag_ClipChildren)) {
145            return;
146        }
147
148        replayStruct.mDrawGlStatus |= applyDraw(replayStruct.mRenderer, replayStruct.mDirty, level);
149    }
150
151    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) = 0;
152
153    virtual void onDrawOpDeferred(OpenGLRenderer& renderer) {
154    }
155
156    // returns true if bounds exist
157    virtual bool getLocalBounds(Rect& localBounds) { return false; }
158
159    // TODO: better refine localbounds usage
160    void setQuickRejected(bool quickRejected) { mQuickRejected = quickRejected; }
161    bool getQuickRejected() { return mQuickRejected; }
162
163    /** Batching disabled by default, turned on for individual ops */
164    virtual DeferredDisplayList::OpBatchId getBatchId() {
165        return DeferredDisplayList::kOpBatch_None;
166    }
167
168    float strokeWidthOutset() { return mPaint->getStrokeWidth() * 0.5f; }
169
170protected:
171    SkPaint* getPaint(OpenGLRenderer& renderer) {
172        return renderer.filterPaint(mPaint);
173    }
174
175    SkPaint* mPaint; // should be accessed via getPaint() when applying
176    bool mQuickRejected;
177};
178
179class DrawBoundedOp : public DrawOp {
180public:
181    DrawBoundedOp(float left, float top, float right, float bottom, SkPaint* paint)
182            : DrawOp(paint), mLocalBounds(left, top, right, bottom) {}
183
184    // Calculates bounds as smallest rect encompassing all points
185    // NOTE: requires at least 1 vertex, and doesn't account for stroke size (should be handled in
186    // subclass' constructor)
187    DrawBoundedOp(const float* points, int count, SkPaint* paint)
188            : DrawOp(paint), mLocalBounds(points[0], points[1], points[0], points[1]) {
189        for (int i = 2; i < count; i += 2) {
190            mLocalBounds.left = fminf(mLocalBounds.left, points[i]);
191            mLocalBounds.right = fmaxf(mLocalBounds.right, points[i]);
192            mLocalBounds.top = fminf(mLocalBounds.top, points[i + 1]);
193            mLocalBounds.bottom = fmaxf(mLocalBounds.bottom, points[i + 1]);
194        }
195    }
196
197    // default empty constructor for bounds, to be overridden in child constructor body
198    DrawBoundedOp(SkPaint* paint)
199            : DrawOp(paint) {}
200
201    bool getLocalBounds(Rect& localBounds) {
202        localBounds.set(mLocalBounds);
203        return true;
204    }
205
206protected:
207    Rect mLocalBounds; // displayed area in LOCAL coord. doesn't incorporate stroke, so check paint
208};
209
210///////////////////////////////////////////////////////////////////////////////
211// STATE OPERATIONS - these may affect the state of the canvas/renderer, but do
212//         not directly draw or alter output
213///////////////////////////////////////////////////////////////////////////////
214
215class SaveOp : public StateOp {
216    friend class DisplayList; // give DisplayList private constructor/reinit access
217public:
218    SaveOp(int flags)
219            : mFlags(flags) {}
220
221    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level) {
222        int newSaveCount = deferStruct.mRenderer.save(mFlags);
223        deferStruct.mDeferredList.addSave(deferStruct.mRenderer, this, newSaveCount);
224    }
225
226    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
227        renderer.save(mFlags);
228    }
229
230    virtual void output(int level, uint32_t logFlags) {
231        OP_LOG("Save flags %x", mFlags);
232    }
233
234    virtual const char* name() { return "Save"; }
235
236    int getFlags() const { return mFlags; }
237private:
238    SaveOp() {}
239    DisplayListOp* reinit(int flags) {
240        mFlags = flags;
241        return this;
242    }
243
244    int mFlags;
245};
246
247class RestoreToCountOp : public StateOp {
248    friend class DisplayList; // give DisplayList private constructor/reinit access
249public:
250    RestoreToCountOp(int count)
251            : mCount(count) {}
252
253    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level) {
254        deferStruct.mDeferredList.addRestoreToCount(deferStruct.mRenderer, saveCount + mCount);
255        deferStruct.mRenderer.restoreToCount(saveCount + mCount);
256    }
257
258    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
259        renderer.restoreToCount(saveCount + mCount);
260    }
261
262    virtual void output(int level, uint32_t logFlags) {
263        OP_LOG("Restore to count %d", mCount);
264    }
265
266    virtual const char* name() { return "RestoreToCount"; }
267
268private:
269    RestoreToCountOp() {}
270    DisplayListOp* reinit(int count) {
271        mCount = count;
272        return this;
273    }
274
275    int mCount;
276};
277
278class SaveLayerOp : public StateOp {
279    friend class DisplayList; // give DisplayList private constructor/reinit access
280public:
281    SaveLayerOp(float left, float top, float right, float bottom,
282            int alpha, SkXfermode::Mode mode, int flags)
283            : mArea(left, top, right, bottom), mAlpha(alpha), mMode(mode), mFlags(flags) {}
284
285    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level) {
286        // NOTE: don't bother with actual saveLayer, instead issuing it at flush time
287        int newSaveCount = deferStruct.mRenderer.getSaveCount();
288        deferStruct.mDeferredList.addSaveLayer(deferStruct.mRenderer, this, newSaveCount);
289
290        // NOTE: don't issue full saveLayer, since that has side effects/is costly. instead just
291        // setup the snapshot for deferral, and re-issue the op at flush time
292        deferStruct.mRenderer.saveLayerDeferred(mArea.left, mArea.top, mArea.right, mArea.bottom,
293                mAlpha, mMode, mFlags);
294    }
295
296    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
297        renderer.saveLayer(mArea.left, mArea.top, mArea.right, mArea.bottom, mAlpha, mMode, mFlags);
298    }
299
300    virtual void output(int level, uint32_t logFlags) {
301        OP_LOG("SaveLayer%s of area " RECT_STRING,
302                (isSaveLayerAlpha() ? "Alpha" : ""),RECT_ARGS(mArea));
303    }
304
305    virtual const char* name() { return isSaveLayerAlpha() ? "SaveLayerAlpha" : "SaveLayer"; }
306
307    int getFlags() { return mFlags; }
308
309private:
310    // Special case, reserved for direct DisplayList usage
311    SaveLayerOp() {}
312    DisplayListOp* reinit(float left, float top, float right, float bottom,
313            int alpha, SkXfermode::Mode mode, int flags) {
314        mArea.set(left, top, right, bottom);
315        mAlpha = alpha;
316        mMode = mode;
317        mFlags = flags;
318        return this;
319    }
320
321    bool isSaveLayerAlpha() { return mAlpha < 255 && mMode == SkXfermode::kSrcOver_Mode; }
322    Rect mArea;
323    int mAlpha;
324    SkXfermode::Mode mMode;
325    int mFlags;
326};
327
328class TranslateOp : public StateOp {
329public:
330    TranslateOp(float dx, float dy)
331            : mDx(dx), mDy(dy) {}
332
333    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
334        renderer.translate(mDx, mDy);
335    }
336
337    virtual void output(int level, uint32_t logFlags) {
338        OP_LOG("Translate by %f %f", mDx, mDy);
339    }
340
341    virtual const char* name() { return "Translate"; }
342
343private:
344    float mDx;
345    float mDy;
346};
347
348class RotateOp : public StateOp {
349public:
350    RotateOp(float degrees)
351            : mDegrees(degrees) {}
352
353    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
354        renderer.rotate(mDegrees);
355    }
356
357    virtual void output(int level, uint32_t logFlags) {
358        OP_LOG("Rotate by %f degrees", mDegrees);
359    }
360
361    virtual const char* name() { return "Rotate"; }
362
363private:
364    float mDegrees;
365};
366
367class ScaleOp : public StateOp {
368public:
369    ScaleOp(float sx, float sy)
370            : mSx(sx), mSy(sy) {}
371
372    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
373        renderer.scale(mSx, mSy);
374    }
375
376    virtual void output(int level, uint32_t logFlags) {
377        OP_LOG("Scale by %f %f", mSx, mSy);
378    }
379
380    virtual const char* name() { return "Scale"; }
381
382private:
383    float mSx;
384    float mSy;
385};
386
387class SkewOp : public StateOp {
388public:
389    SkewOp(float sx, float sy)
390            : mSx(sx), mSy(sy) {}
391
392    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
393        renderer.skew(mSx, mSy);
394    }
395
396    virtual void output(int level, uint32_t logFlags) {
397        OP_LOG("Skew by %f %f", mSx, mSy);
398    }
399
400    virtual const char* name() { return "Skew"; }
401
402private:
403    float mSx;
404    float mSy;
405};
406
407class SetMatrixOp : public StateOp {
408public:
409    SetMatrixOp(SkMatrix* matrix)
410            : mMatrix(matrix) {}
411
412    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
413        renderer.setMatrix(mMatrix);
414    }
415
416    virtual void output(int level, uint32_t logFlags) {
417        OP_LOG("SetMatrix " MATRIX_STRING, MATRIX_ARGS(mMatrix));
418    }
419
420    virtual const char* name() { return "SetMatrix"; }
421
422private:
423    SkMatrix* mMatrix;
424};
425
426class ConcatMatrixOp : public StateOp {
427public:
428    ConcatMatrixOp(SkMatrix* matrix)
429            : mMatrix(matrix) {}
430
431    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
432        renderer.concatMatrix(mMatrix);
433    }
434
435    virtual void output(int level, uint32_t logFlags) {
436        OP_LOG("ConcatMatrix " MATRIX_STRING, MATRIX_ARGS(mMatrix));
437    }
438
439    virtual const char* name() { return "ConcatMatrix"; }
440
441private:
442    SkMatrix* mMatrix;
443};
444
445class ClipOp : public StateOp {
446public:
447    ClipOp(SkRegion::Op op) : mOp(op) {}
448
449    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level) {
450        // NOTE: must defer op BEFORE applying state, since it may read clip
451        deferStruct.mDeferredList.addClip(deferStruct.mRenderer, this);
452
453        // TODO: Can we avoid applying complex clips at defer time?
454        applyState(deferStruct.mRenderer, saveCount);
455    }
456
457    bool canCauseComplexClip() {
458        return ((mOp != SkRegion::kIntersect_Op) && (mOp != SkRegion::kReplace_Op)) || !isRect();
459    }
460
461protected:
462    ClipOp() {}
463    virtual bool isRect() { return false; }
464
465    SkRegion::Op mOp;
466};
467
468class ClipRectOp : public ClipOp {
469    friend class DisplayList; // give DisplayList private constructor/reinit access
470public:
471    ClipRectOp(float left, float top, float right, float bottom, SkRegion::Op op)
472            : ClipOp(op), mArea(left, top, right, bottom) {}
473
474    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
475        renderer.clipRect(mArea.left, mArea.top, mArea.right, mArea.bottom, mOp);
476    }
477
478    virtual void output(int level, uint32_t logFlags) {
479        OP_LOG("ClipRect " RECT_STRING, RECT_ARGS(mArea));
480    }
481
482    virtual const char* name() { return "ClipRect"; }
483
484protected:
485    virtual bool isRect() { return true; }
486
487private:
488    ClipRectOp() {}
489    DisplayListOp* reinit(float left, float top, float right, float bottom, SkRegion::Op op) {
490        mOp = op;
491        mArea.set(left, top, right, bottom);
492        return this;
493    }
494
495    Rect mArea;
496};
497
498class ClipPathOp : public ClipOp {
499public:
500    ClipPathOp(SkPath* path, SkRegion::Op op)
501            : ClipOp(op), mPath(path) {}
502
503    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
504        renderer.clipPath(mPath, mOp);
505    }
506
507    virtual void output(int level, uint32_t logFlags) {
508        SkRect bounds = mPath->getBounds();
509        OP_LOG("ClipPath bounds " RECT_STRING,
510                bounds.left(), bounds.top(), bounds.right(), bounds.bottom());
511    }
512
513    virtual const char* name() { return "ClipPath"; }
514
515private:
516    SkPath* mPath;
517};
518
519class ClipRegionOp : public ClipOp {
520public:
521    ClipRegionOp(SkRegion* region, SkRegion::Op op)
522            : ClipOp(op), mRegion(region) {}
523
524    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
525        renderer.clipRegion(mRegion, mOp);
526    }
527
528    virtual void output(int level, uint32_t logFlags) {
529        SkIRect bounds = mRegion->getBounds();
530        OP_LOG("ClipRegion bounds %d %d %d %d",
531                bounds.left(), bounds.top(), bounds.right(), bounds.bottom());
532    }
533
534    virtual const char* name() { return "ClipRegion"; }
535
536private:
537    SkRegion* mRegion;
538    SkRegion::Op mOp;
539};
540
541class ResetShaderOp : public StateOp {
542public:
543    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
544        renderer.resetShader();
545    }
546
547    virtual void output(int level, uint32_t logFlags) {
548        OP_LOGS("ResetShader");
549    }
550
551    virtual const char* name() { return "ResetShader"; }
552};
553
554class SetupShaderOp : public StateOp {
555public:
556    SetupShaderOp(SkiaShader* shader)
557            : mShader(shader) {}
558    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
559        renderer.setupShader(mShader);
560    }
561
562    virtual void output(int level, uint32_t logFlags) {
563        OP_LOG("SetupShader, shader %p", mShader);
564    }
565
566    virtual const char* name() { return "SetupShader"; }
567
568private:
569    SkiaShader* mShader;
570};
571
572class ResetColorFilterOp : public StateOp {
573public:
574    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
575        renderer.resetColorFilter();
576    }
577
578    virtual void output(int level, uint32_t logFlags) {
579        OP_LOGS("ResetColorFilter");
580    }
581
582    virtual const char* name() { return "ResetColorFilter"; }
583};
584
585class SetupColorFilterOp : public StateOp {
586public:
587    SetupColorFilterOp(SkiaColorFilter* colorFilter)
588            : mColorFilter(colorFilter) {}
589
590    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
591        renderer.setupColorFilter(mColorFilter);
592    }
593
594    virtual void output(int level, uint32_t logFlags) {
595        OP_LOG("SetupColorFilter, filter %p", mColorFilter);
596    }
597
598    virtual const char* name() { return "SetupColorFilter"; }
599
600private:
601    SkiaColorFilter* mColorFilter;
602};
603
604class ResetShadowOp : public StateOp {
605public:
606    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
607        renderer.resetShadow();
608    }
609
610    virtual void output(int level, uint32_t logFlags) {
611        OP_LOGS("ResetShadow");
612    }
613
614    virtual const char* name() { return "ResetShadow"; }
615};
616
617class SetupShadowOp : public StateOp {
618public:
619    SetupShadowOp(float radius, float dx, float dy, int color)
620            : mRadius(radius), mDx(dx), mDy(dy), mColor(color) {}
621
622    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
623        renderer.setupShadow(mRadius, mDx, mDy, mColor);
624    }
625
626    virtual void output(int level, uint32_t logFlags) {
627        OP_LOG("SetupShadow, radius %f, %f, %f, color %#x", mRadius, mDx, mDy, mColor);
628    }
629
630    virtual const char* name() { return "SetupShadow"; }
631
632private:
633    float mRadius;
634    float mDx;
635    float mDy;
636    int mColor;
637};
638
639class ResetPaintFilterOp : public StateOp {
640public:
641    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
642        renderer.resetPaintFilter();
643    }
644
645    virtual void output(int level, uint32_t logFlags) {
646        OP_LOGS("ResetPaintFilter");
647    }
648
649    virtual const char* name() { return "ResetPaintFilter"; }
650};
651
652class SetupPaintFilterOp : public StateOp {
653public:
654    SetupPaintFilterOp(int clearBits, int setBits)
655            : mClearBits(clearBits), mSetBits(setBits) {}
656
657    virtual void applyState(OpenGLRenderer& renderer, int saveCount) {
658        renderer.setupPaintFilter(mClearBits, mSetBits);
659    }
660
661    virtual void output(int level, uint32_t logFlags) {
662        OP_LOG("SetupPaintFilter, clear %#x, set %#x", mClearBits, mSetBits);
663    }
664
665    virtual const char* name() { return "SetupPaintFilter"; }
666
667private:
668    int mClearBits;
669    int mSetBits;
670};
671
672
673///////////////////////////////////////////////////////////////////////////////
674// DRAW OPERATIONS - these are operations that can draw to the canvas's device
675///////////////////////////////////////////////////////////////////////////////
676
677class DrawBitmapOp : public DrawBoundedOp {
678public:
679    DrawBitmapOp(SkBitmap* bitmap, float left, float top, SkPaint* paint)
680            : DrawBoundedOp(left, top, left + bitmap->width(), top + bitmap->height(),
681                    paint),
682            mBitmap(bitmap) {}
683
684    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
685        return renderer.drawBitmap(mBitmap, mLocalBounds.left, mLocalBounds.top,
686                getPaint(renderer));
687    }
688
689    virtual void output(int level, uint32_t logFlags) {
690        OP_LOG("Draw bitmap %p at %f %f", mBitmap, mLocalBounds.left, mLocalBounds.top);
691    }
692
693    virtual const char* name() { return "DrawBitmap"; }
694    virtual DeferredDisplayList::OpBatchId getBatchId() {
695        return DeferredDisplayList::kOpBatch_Bitmap;
696    }
697
698protected:
699    SkBitmap* mBitmap;
700};
701
702class DrawBitmapMatrixOp : public DrawBoundedOp {
703public:
704    DrawBitmapMatrixOp(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint)
705            : DrawBoundedOp(paint), mBitmap(bitmap), mMatrix(matrix) {
706        mLocalBounds.set(0, 0, bitmap->width(), bitmap->height());
707        const mat4 transform(*matrix);
708        transform.mapRect(mLocalBounds);
709    }
710
711    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
712        return renderer.drawBitmap(mBitmap, mMatrix, getPaint(renderer));
713    }
714
715    virtual void output(int level, uint32_t logFlags) {
716        OP_LOG("Draw bitmap %p matrix " MATRIX_STRING, mBitmap, MATRIX_ARGS(mMatrix));
717    }
718
719    virtual const char* name() { return "DrawBitmap"; }
720    virtual DeferredDisplayList::OpBatchId getBatchId() {
721        return DeferredDisplayList::kOpBatch_Bitmap;
722    }
723
724private:
725    SkBitmap* mBitmap;
726    SkMatrix* mMatrix;
727};
728
729class DrawBitmapRectOp : public DrawBoundedOp {
730public:
731    DrawBitmapRectOp(SkBitmap* bitmap, float srcLeft, float srcTop, float srcRight, float srcBottom,
732            float dstLeft, float dstTop, float dstRight, float dstBottom, SkPaint* paint)
733            : DrawBoundedOp(dstLeft, dstTop, dstRight, dstBottom, paint),
734            mBitmap(bitmap), mSrc(srcLeft, srcTop, srcRight, srcBottom) {}
735
736    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
737        return renderer.drawBitmap(mBitmap, mSrc.left, mSrc.top, mSrc.right, mSrc.bottom,
738                mLocalBounds.left, mLocalBounds.top, mLocalBounds.right, mLocalBounds.bottom,
739                getPaint(renderer));
740    }
741
742    virtual void output(int level, uint32_t logFlags) {
743        OP_LOG("Draw bitmap %p src="RECT_STRING", dst="RECT_STRING,
744                mBitmap, RECT_ARGS(mSrc), RECT_ARGS(mLocalBounds));
745    }
746
747    virtual const char* name() { return "DrawBitmapRect"; }
748    virtual DeferredDisplayList::OpBatchId getBatchId() {
749        return DeferredDisplayList::kOpBatch_Bitmap;
750    }
751
752private:
753    SkBitmap* mBitmap;
754    Rect mSrc;
755};
756
757class DrawBitmapDataOp : public DrawBitmapOp {
758public:
759    DrawBitmapDataOp(SkBitmap* bitmap, float left, float top, SkPaint* paint)
760            : DrawBitmapOp(bitmap, left, top, paint) {}
761
762    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
763        return renderer.drawBitmapData(mBitmap, mLocalBounds.left,
764                mLocalBounds.top, getPaint(renderer));
765    }
766
767    virtual void output(int level, uint32_t logFlags) {
768        OP_LOG("Draw bitmap %p", mBitmap);
769    }
770
771    virtual const char* name() { return "DrawBitmapData"; }
772    virtual DeferredDisplayList::OpBatchId getBatchId() {
773        return DeferredDisplayList::kOpBatch_Bitmap;
774    }
775};
776
777class DrawBitmapMeshOp : public DrawBoundedOp {
778public:
779    DrawBitmapMeshOp(SkBitmap* bitmap, int meshWidth, int meshHeight,
780            float* vertices, int* colors, SkPaint* paint)
781            : DrawBoundedOp(vertices, 2 * (meshWidth + 1) * (meshHeight + 1), paint),
782            mBitmap(bitmap), mMeshWidth(meshWidth), mMeshHeight(meshHeight),
783            mVertices(vertices), mColors(colors) {}
784
785    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
786        return renderer.drawBitmapMesh(mBitmap, mMeshWidth, mMeshHeight,
787                mVertices, mColors, getPaint(renderer));
788    }
789
790    virtual void output(int level, uint32_t logFlags) {
791        OP_LOG("Draw bitmap %p mesh %d x %d", mBitmap, mMeshWidth, mMeshHeight);
792    }
793
794    virtual const char* name() { return "DrawBitmapMesh"; }
795    virtual DeferredDisplayList::OpBatchId getBatchId() {
796        return DeferredDisplayList::kOpBatch_Bitmap;
797    }
798
799private:
800    SkBitmap* mBitmap;
801    int mMeshWidth;
802    int mMeshHeight;
803    float* mVertices;
804    int* mColors;
805};
806
807class DrawPatchOp : public DrawBoundedOp {
808public:
809    DrawPatchOp(SkBitmap* bitmap, const int32_t* xDivs,
810            const int32_t* yDivs, const uint32_t* colors, uint32_t width, uint32_t height,
811            int8_t numColors, float left, float top, float right, float bottom,
812            int alpha, SkXfermode::Mode mode)
813            : DrawBoundedOp(left, top, right, bottom, 0),
814            mBitmap(bitmap), mxDivs(xDivs), myDivs(yDivs),
815            mColors(colors), mxDivsCount(width), myDivsCount(height),
816            mNumColors(numColors), mAlpha(alpha), mMode(mode) {};
817
818    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
819        // NOTE: not calling the virtual method, which takes a paint
820        return renderer.drawPatch(mBitmap, mxDivs, myDivs, mColors,
821                mxDivsCount, myDivsCount, mNumColors,
822                mLocalBounds.left, mLocalBounds.top,
823                mLocalBounds.right, mLocalBounds.bottom, mAlpha, mMode);
824    }
825
826    virtual void output(int level, uint32_t logFlags) {
827        OP_LOG("Draw patch "RECT_STRING, RECT_ARGS(mLocalBounds));
828    }
829
830    virtual const char* name() { return "DrawPatch"; }
831    virtual DeferredDisplayList::OpBatchId getBatchId() {
832        return DeferredDisplayList::kOpBatch_Patch;
833    }
834
835private:
836    SkBitmap* mBitmap;
837    const int32_t* mxDivs;
838    const int32_t* myDivs;
839    const uint32_t* mColors;
840    uint32_t mxDivsCount;
841    uint32_t myDivsCount;
842    int8_t mNumColors;
843    int mAlpha;
844    SkXfermode::Mode mMode;
845};
846
847class DrawColorOp : public DrawOp {
848public:
849    DrawColorOp(int color, SkXfermode::Mode mode)
850            : DrawOp(0), mColor(color), mMode(mode) {};
851
852    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
853        return renderer.drawColor(mColor, mMode);
854    }
855
856    virtual void output(int level, uint32_t logFlags) {
857        OP_LOG("Draw color %#x, mode %d", mColor, mMode);
858    }
859
860    virtual const char* name() { return "DrawColor"; }
861
862private:
863    int mColor;
864    SkXfermode::Mode mMode;
865};
866
867class DrawStrokableOp : public DrawBoundedOp {
868public:
869    DrawStrokableOp(float left, float top, float right, float bottom, SkPaint* paint)
870            : DrawBoundedOp(left, top, right, bottom, paint) {};
871
872    bool getLocalBounds(Rect& localBounds) {
873        localBounds.set(mLocalBounds);
874        if (mPaint && mPaint->getStyle() != SkPaint::kFill_Style) {
875            localBounds.outset(strokeWidthOutset());
876        }
877        return true;
878    }
879
880    virtual DeferredDisplayList::OpBatchId getBatchId() {
881        if (mPaint->getPathEffect()) {
882            return DeferredDisplayList::kOpBatch_AlphaMaskTexture;
883        }
884        return mPaint->isAntiAlias() ?
885                DeferredDisplayList::kOpBatch_AlphaVertices :
886                DeferredDisplayList::kOpBatch_Vertices;
887    }
888};
889
890class DrawRectOp : public DrawStrokableOp {
891public:
892    DrawRectOp(float left, float top, float right, float bottom, SkPaint* paint)
893            : DrawStrokableOp(left, top, right, bottom, paint) {}
894
895    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
896        return renderer.drawRect(mLocalBounds.left, mLocalBounds.top,
897                mLocalBounds.right, mLocalBounds.bottom, getPaint(renderer));
898    }
899
900    virtual void output(int level, uint32_t logFlags) {
901        OP_LOG("Draw Rect "RECT_STRING, RECT_ARGS(mLocalBounds));
902    }
903
904    virtual const char* name() { return "DrawRect"; }
905};
906
907class DrawRectsOp : public DrawBoundedOp {
908public:
909    DrawRectsOp(const float* rects, int count, SkPaint* paint)
910            : DrawBoundedOp(rects, count, paint),
911            mRects(rects), mCount(count) {}
912
913    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
914        return renderer.drawRects(mRects, mCount, getPaint(renderer));
915    }
916
917    virtual void output(int level, uint32_t logFlags) {
918        OP_LOG("Draw Rects count %d", mCount);
919    }
920
921    virtual const char* name() { return "DrawRects"; }
922
923    virtual DeferredDisplayList::OpBatchId getBatchId() {
924        return DeferredDisplayList::kOpBatch_Vertices;
925    }
926
927private:
928    const float* mRects;
929    int mCount;
930};
931
932class DrawRoundRectOp : public DrawStrokableOp {
933public:
934    DrawRoundRectOp(float left, float top, float right, float bottom,
935            float rx, float ry, SkPaint* paint)
936            : DrawStrokableOp(left, top, right, bottom, paint), mRx(rx), mRy(ry) {}
937
938    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
939        return renderer.drawRoundRect(mLocalBounds.left, mLocalBounds.top,
940                mLocalBounds.right, mLocalBounds.bottom, mRx, mRy, getPaint(renderer));
941    }
942
943    virtual void output(int level, uint32_t logFlags) {
944        OP_LOG("Draw RoundRect "RECT_STRING", rx %f, ry %f", RECT_ARGS(mLocalBounds), mRx, mRy);
945    }
946
947    virtual const char* name() { return "DrawRoundRect"; }
948
949private:
950    float mRx;
951    float mRy;
952};
953
954class DrawCircleOp : public DrawStrokableOp {
955public:
956    DrawCircleOp(float x, float y, float radius, SkPaint* paint)
957            : DrawStrokableOp(x - radius, y - radius, x + radius, y + radius, paint),
958            mX(x), mY(y), mRadius(radius) {}
959
960    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
961        return renderer.drawCircle(mX, mY, mRadius, getPaint(renderer));
962    }
963
964    virtual void output(int level, uint32_t logFlags) {
965        OP_LOG("Draw Circle x %f, y %f, r %f", mX, mY, mRadius);
966    }
967
968    virtual const char* name() { return "DrawCircle"; }
969
970private:
971    float mX;
972    float mY;
973    float mRadius;
974};
975
976class DrawOvalOp : public DrawStrokableOp {
977public:
978    DrawOvalOp(float left, float top, float right, float bottom, SkPaint* paint)
979            : DrawStrokableOp(left, top, right, bottom, paint) {}
980
981    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
982        return renderer.drawOval(mLocalBounds.left, mLocalBounds.top,
983                mLocalBounds.right, mLocalBounds.bottom, getPaint(renderer));
984    }
985
986    virtual void output(int level, uint32_t logFlags) {
987        OP_LOG("Draw Oval "RECT_STRING, RECT_ARGS(mLocalBounds));
988    }
989
990    virtual const char* name() { return "DrawOval"; }
991};
992
993class DrawArcOp : public DrawStrokableOp {
994public:
995    DrawArcOp(float left, float top, float right, float bottom,
996            float startAngle, float sweepAngle, bool useCenter, SkPaint* paint)
997            : DrawStrokableOp(left, top, right, bottom, paint),
998            mStartAngle(startAngle), mSweepAngle(sweepAngle), mUseCenter(useCenter) {}
999
1000    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
1001        return renderer.drawArc(mLocalBounds.left, mLocalBounds.top,
1002                mLocalBounds.right, mLocalBounds.bottom,
1003                mStartAngle, mSweepAngle, mUseCenter, getPaint(renderer));
1004    }
1005
1006    virtual void output(int level, uint32_t logFlags) {
1007        OP_LOG("Draw Arc "RECT_STRING", start %f, sweep %f, useCenter %d",
1008                RECT_ARGS(mLocalBounds), mStartAngle, mSweepAngle, mUseCenter);
1009    }
1010
1011    virtual const char* name() { return "DrawArc"; }
1012
1013private:
1014    float mStartAngle;
1015    float mSweepAngle;
1016    bool mUseCenter;
1017};
1018
1019class DrawPathOp : public DrawBoundedOp {
1020public:
1021    DrawPathOp(SkPath* path, SkPaint* paint)
1022            : DrawBoundedOp(paint), mPath(path) {
1023        float left, top, offset;
1024        uint32_t width, height;
1025        PathCache::computePathBounds(path, paint, left, top, offset, width, height);
1026        left -= offset;
1027        top -= offset;
1028        mLocalBounds.set(left, top, left + width, top + height);
1029    }
1030
1031    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
1032        return renderer.drawPath(mPath, getPaint(renderer));
1033    }
1034
1035    virtual void onDrawOpDeferred(OpenGLRenderer& renderer) {
1036        SkPaint* paint = getPaint(renderer);
1037        renderer.getCaches().pathCache.precache(mPath, paint);
1038    }
1039
1040    virtual void output(int level, uint32_t logFlags) {
1041        OP_LOG("Draw Path %p in "RECT_STRING, mPath, RECT_ARGS(mLocalBounds));
1042    }
1043
1044    virtual const char* name() { return "DrawPath"; }
1045
1046    virtual DeferredDisplayList::OpBatchId getBatchId() {
1047        return DeferredDisplayList::kOpBatch_AlphaMaskTexture;
1048    }
1049private:
1050    SkPath* mPath;
1051};
1052
1053class DrawLinesOp : public DrawBoundedOp {
1054public:
1055    DrawLinesOp(float* points, int count, SkPaint* paint)
1056            : DrawBoundedOp(points, count, paint),
1057            mPoints(points), mCount(count) {
1058        mLocalBounds.outset(strokeWidthOutset());
1059    }
1060
1061    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
1062        return renderer.drawLines(mPoints, mCount, getPaint(renderer));
1063    }
1064
1065    virtual void output(int level, uint32_t logFlags) {
1066        OP_LOG("Draw Lines count %d", mCount);
1067    }
1068
1069    virtual const char* name() { return "DrawLines"; }
1070
1071    virtual DeferredDisplayList::OpBatchId getBatchId() {
1072        return mPaint->isAntiAlias() ?
1073                DeferredDisplayList::kOpBatch_AlphaVertices :
1074                DeferredDisplayList::kOpBatch_Vertices;
1075    }
1076
1077protected:
1078    float* mPoints;
1079    int mCount;
1080};
1081
1082class DrawPointsOp : public DrawLinesOp {
1083public:
1084    DrawPointsOp(float* points, int count, SkPaint* paint)
1085            : DrawLinesOp(points, count, paint) {}
1086
1087    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
1088        return renderer.drawPoints(mPoints, mCount, getPaint(renderer));
1089    }
1090
1091    virtual void output(int level, uint32_t logFlags) {
1092        OP_LOG("Draw Points count %d", mCount);
1093    }
1094
1095    virtual const char* name() { return "DrawPoints"; }
1096};
1097
1098class DrawSomeTextOp : public DrawOp {
1099public:
1100    DrawSomeTextOp(const char* text, int bytesCount, int count, SkPaint* paint)
1101            : DrawOp(paint), mText(text), mBytesCount(bytesCount), mCount(count) {};
1102
1103    virtual void output(int level, uint32_t logFlags) {
1104        OP_LOG("Draw some text, %d bytes", mBytesCount);
1105    }
1106
1107    virtual void onDrawOpDeferred(OpenGLRenderer& renderer) {
1108        SkPaint* paint = getPaint(renderer);
1109        FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(paint);
1110        fontRenderer.precache(paint, mText, mCount, mat4::identity());
1111    }
1112
1113    virtual DeferredDisplayList::OpBatchId getBatchId() {
1114        return mPaint->getColor() == 0xff000000 ?
1115                DeferredDisplayList::kOpBatch_Text :
1116                DeferredDisplayList::kOpBatch_ColorText;
1117    }
1118protected:
1119    const char* mText;
1120    int mBytesCount;
1121    int mCount;
1122};
1123
1124class DrawTextOnPathOp : public DrawSomeTextOp {
1125public:
1126    DrawTextOnPathOp(const char* text, int bytesCount, int count,
1127            SkPath* path, float hOffset, float vOffset, SkPaint* paint)
1128            : DrawSomeTextOp(text, bytesCount, count, paint),
1129            mPath(path), mHOffset(hOffset), mVOffset(vOffset) {
1130        /* TODO: inherit from DrawBounded and init mLocalBounds */
1131    }
1132
1133    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
1134        return renderer.drawTextOnPath(mText, mBytesCount, mCount, mPath,
1135                mHOffset, mVOffset, getPaint(renderer));
1136    }
1137
1138    virtual const char* name() { return "DrawTextOnPath"; }
1139
1140private:
1141    SkPath* mPath;
1142    float mHOffset;
1143    float mVOffset;
1144};
1145
1146class DrawPosTextOp : public DrawSomeTextOp {
1147public:
1148    DrawPosTextOp(const char* text, int bytesCount, int count,
1149            const float* positions, SkPaint* paint)
1150            : DrawSomeTextOp(text, bytesCount, count, paint), mPositions(positions) {
1151        /* TODO: inherit from DrawBounded and init mLocalBounds */
1152    }
1153
1154    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
1155        return renderer.drawPosText(mText, mBytesCount, mCount, mPositions, getPaint(renderer));
1156    }
1157
1158    virtual const char* name() { return "DrawPosText"; }
1159
1160private:
1161    const float* mPositions;
1162};
1163
1164class DrawTextOp : public DrawBoundedOp {
1165public:
1166    DrawTextOp(const char* text, int bytesCount, int count, float x, float y,
1167            const float* positions, SkPaint* paint, float length)
1168            : DrawBoundedOp(paint), mText(text), mBytesCount(bytesCount), mCount(count),
1169            mX(x), mY(y), mPositions(positions), mLength(length) {
1170        // duplicates bounds calculation from OpenGLRenderer::drawText, but doesn't alter mX
1171        SkPaint::FontMetrics metrics;
1172        paint->getFontMetrics(&metrics, 0.0f);
1173        switch (paint->getTextAlign()) {
1174        case SkPaint::kCenter_Align:
1175            x -= length / 2.0f;
1176            break;
1177        case SkPaint::kRight_Align:
1178            x -= length;
1179            break;
1180        default:
1181            break;
1182        }
1183        mLocalBounds.set(x, mY + metrics.fTop, x + length, mY + metrics.fBottom);
1184        memset(&mPrecacheTransform.data[0], 0xff, 16 * sizeof(float));
1185    }
1186
1187    /*
1188     * When this method is invoked the state field  is initialized to have the
1189     * final rendering state. We can thus use it to process data as it will be
1190     * used at draw time.
1191     */
1192    virtual void onDrawOpDeferred(OpenGLRenderer& renderer) {
1193        SkPaint* paint = getPaint(renderer);
1194        FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(paint);
1195        const mat4& transform = renderer.findBestFontTransform(state.mMatrix);
1196        if (mPrecacheTransform != transform) {
1197            fontRenderer.precache(paint, mText, mCount, transform);
1198            mPrecacheTransform = transform;
1199        }
1200    }
1201
1202    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
1203        return renderer.drawText(mText, mBytesCount, mCount, mX, mY,
1204                mPositions, getPaint(renderer), mLength);
1205    }
1206
1207    virtual void output(int level, uint32_t logFlags) {
1208        OP_LOG("Draw Text of count %d, bytes %d", mCount, mBytesCount);
1209    }
1210
1211    virtual const char* name() { return "DrawText"; }
1212
1213    virtual DeferredDisplayList::OpBatchId getBatchId() {
1214        return mPaint->getColor() == 0xff000000 ?
1215                DeferredDisplayList::kOpBatch_Text :
1216                DeferredDisplayList::kOpBatch_ColorText;
1217    }
1218
1219private:
1220    const char* mText;
1221    int mBytesCount;
1222    int mCount;
1223    float mX;
1224    float mY;
1225    const float* mPositions;
1226    float mLength;
1227    mat4 mPrecacheTransform;
1228};
1229
1230///////////////////////////////////////////////////////////////////////////////
1231// SPECIAL DRAW OPERATIONS
1232///////////////////////////////////////////////////////////////////////////////
1233
1234class DrawFunctorOp : public DrawOp {
1235public:
1236    DrawFunctorOp(Functor* functor)
1237            : DrawOp(0), mFunctor(functor) {}
1238
1239    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
1240        renderer.startMark("GL functor");
1241        status_t ret = renderer.callDrawGLFunction(mFunctor, dirty);
1242        renderer.endMark();
1243        return ret;
1244    }
1245
1246    virtual void output(int level, uint32_t logFlags) {
1247        OP_LOG("Draw Functor %p", mFunctor);
1248    }
1249
1250    virtual const char* name() { return "DrawFunctor"; }
1251
1252private:
1253    Functor* mFunctor;
1254};
1255
1256class DrawDisplayListOp : public DrawBoundedOp {
1257public:
1258    DrawDisplayListOp(DisplayList* displayList, int flags)
1259            : DrawBoundedOp(0, 0, displayList->getWidth(), displayList->getHeight(), 0),
1260            mDisplayList(displayList), mFlags(flags) {}
1261
1262    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level) {
1263        if (mDisplayList && mDisplayList->isRenderable()) {
1264            mDisplayList->defer(deferStruct, level + 1);
1265        }
1266    }
1267virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level) {
1268        if (mDisplayList && mDisplayList->isRenderable()) {
1269            mDisplayList->replay(replayStruct, level + 1);
1270        }
1271    }
1272
1273    // NOT USED since replay() is overridden
1274    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
1275        return DrawGlInfo::kStatusDone;
1276    }
1277
1278    virtual void output(int level, uint32_t logFlags) {
1279        OP_LOG("Draw Display List %p, flags %#x", mDisplayList, mFlags);
1280        if (mDisplayList && (logFlags & kOpLogFlag_Recurse)) {
1281            mDisplayList->output(level + 1);
1282        }
1283    }
1284
1285    virtual const char* name() { return "DrawDisplayList"; }
1286
1287private:
1288    DisplayList* mDisplayList;
1289    int mFlags;
1290};
1291
1292class DrawLayerOp : public DrawOp {
1293public:
1294    DrawLayerOp(Layer* layer, float x, float y)
1295            : DrawOp(0), mLayer(layer), mX(x), mY(y) {}
1296
1297    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty, int level) {
1298        return renderer.drawLayer(mLayer, mX, mY);
1299    }
1300
1301    virtual void output(int level, uint32_t logFlags) {
1302        OP_LOG("Draw Layer %p at %f %f", mLayer, mX, mY);
1303    }
1304
1305    virtual const char* name() { return "DrawLayer"; }
1306
1307private:
1308    Layer* mLayer;
1309    float mX;
1310    float mY;
1311};
1312
1313}; // namespace uirenderer
1314}; // namespace android
1315
1316#endif // ANDROID_HWUI_DISPLAY_OPERATION_H
1317