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