DisplayListOp.h revision f0a590781b2c3e34132b2011d3956135add73ae0
1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef ANDROID_HWUI_DISPLAY_OPERATION_H
18#define ANDROID_HWUI_DISPLAY_OPERATION_H
19
20#ifndef LOG_TAG
21    #define LOG_TAG "OpenGLRenderer"
22#endif
23
24#include <SkXfermode.h>
25
26#include <private/hwui/DrawGlInfo.h>
27
28#include "OpenGLRenderer.h"
29#include "AssetAtlas.h"
30#include "DeferredDisplayList.h"
31#include "DisplayListRenderer.h"
32#include "UvMapper.h"
33#include "utils/LinearAllocator.h"
34
35#define CRASH() do { \
36    *(int *)(uintptr_t) 0xbbadbeef = 0; \
37    ((void(*)())0)(); /* More reliable, but doesn't say BBADBEEF */ \
38} while(false)
39
40// Use OP_LOG for logging with arglist, OP_LOGS if just printing char*
41#define OP_LOGS(s) OP_LOG("%s", (s))
42#define OP_LOG(s, ...) ALOGD( "%*s" s, level * 2, "", __VA_ARGS__ )
43
44namespace android {
45namespace uirenderer {
46
47/**
48 * Structure for storing canvas operations when they are recorded into a DisplayList, so that they
49 * may be replayed to an OpenGLRenderer.
50 *
51 * To avoid individual memory allocations, DisplayListOps may only be allocated into a
52 * LinearAllocator's managed memory buffers.  Each pointer held by a DisplayListOp is either a
53 * pointer into memory also allocated in the LinearAllocator (mostly for text and float buffers) or
54 * references a externally refcounted object (Sk... and Skia... objects). ~DisplayListOp() is
55 * never called as LinearAllocators are simply discarded, so no memory management should be done in
56 * this class.
57 */
58class DisplayListOp {
59public:
60    // These objects should always be allocated with a LinearAllocator, and never destroyed/deleted.
61    // standard new() intentionally not implemented, and delete/deconstructor should never be used.
62    virtual ~DisplayListOp() { CRASH(); }
63    static void operator delete(void* ptr) { CRASH(); }
64    /** static void* operator new(size_t size); PURPOSELY OMITTED **/
65    static void* operator new(size_t size, LinearAllocator& allocator) {
66        return allocator.alloc(size);
67    }
68
69    enum OpLogFlag {
70        kOpLogFlag_Recurse = 0x1,
71        kOpLogFlag_JSON = 0x2 // TODO: add?
72    };
73
74    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
75            bool useQuickReject) = 0;
76
77    virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level,
78            bool useQuickReject) = 0;
79
80    virtual void output(int level, uint32_t logFlags = 0) const = 0;
81
82    // NOTE: it would be nice to declare constants and overriding the implementation in each op to
83    // point at the constants, but that seems to require a .cpp file
84    virtual const char* name() = 0;
85};
86
87class StateOp : public DisplayListOp {
88public:
89    StateOp() {};
90
91    virtual ~StateOp() {}
92
93    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
94            bool useQuickReject) {
95        // default behavior only affects immediate, deferrable state, issue directly to renderer
96        applyState(deferStruct.mRenderer, saveCount);
97    }
98
99    /**
100     * State operations are applied directly to the renderer, but can cause the deferred drawing op
101     * list to flush
102     */
103    virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level,
104            bool useQuickReject) {
105        applyState(replayStruct.mRenderer, saveCount);
106    }
107
108    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const = 0;
109};
110
111class DrawOp : public DisplayListOp {
112friend class MergingDrawBatch;
113public:
114    DrawOp(SkPaint* paint)
115            : mPaint(paint), mQuickRejected(false) {}
116
117    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
118            bool useQuickReject) {
119        if (mQuickRejected && CC_LIKELY(useQuickReject)) {
120            return;
121        }
122
123        deferStruct.mDeferredList.addDrawOp(deferStruct.mRenderer, this);
124    }
125
126    virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level,
127            bool useQuickReject) {
128        if (mQuickRejected && CC_LIKELY(useQuickReject)) {
129            return;
130        }
131
132        replayStruct.mDrawGlStatus |= applyDraw(replayStruct.mRenderer, replayStruct.mDirty);
133    }
134
135    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) = 0;
136
137    /**
138     * Draw multiple instances of an operation, must be overidden for operations that merge
139     *
140     * Currently guarantees certain similarities between ops (see MergingDrawBatch::canMergeWith),
141     * and pure translation transformations. Other guarantees of similarity should be enforced by
142     * reducing which operations are tagged as mergeable.
143     */
144    virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
145            const Vector<OpStatePair>& ops, const Rect& bounds) {
146        status_t status = DrawGlInfo::kStatusDone;
147        for (unsigned int i = 0; i < ops.size(); i++) {
148            renderer.restoreDisplayState(*(ops[i].state), true);
149            status |= ops[i].op->applyDraw(renderer, dirty);
150        }
151        return status;
152    }
153
154    /**
155     * When this method is invoked the state field is initialized to have the
156     * final rendering state. We can thus use it to process data as it will be
157     * used at draw time.
158     *
159     * Additionally, this method allows subclasses to provide defer-time preferences for batching
160     * and merging.
161     *
162     * if a subclass can set deferInfo.mergeable to true, it should implement multiDraw()
163     */
164    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
165            const DeferredDisplayState& state) {}
166
167    /**
168     * Query the conservative, local bounds (unmapped) bounds of the op.
169     *
170     * returns true if bounds exist
171     */
172    virtual bool getLocalBounds(const DrawModifiers& drawModifiers, Rect& localBounds) {
173        return false;
174    }
175
176    // TODO: better refine localbounds usage
177    void setQuickRejected(bool quickRejected) { mQuickRejected = quickRejected; }
178    bool getQuickRejected() { return mQuickRejected; }
179
180    inline int getPaintAlpha() const {
181        return OpenGLRenderer::getAlphaDirect(mPaint);
182    }
183
184    inline float strokeWidthOutset() {
185        // since anything AA stroke with less than 1.0 pixel width is drawn with an alpha-reduced
186        // 1.0 stroke, treat 1.0 as minimum.
187
188        // TODO: it would be nice if this could take scale into account, but scale isn't stable
189        // since higher levels of the view hierarchy can change scale out from underneath it.
190        return fmaxf(mPaint->getStrokeWidth(), 1) * 0.5f;
191    }
192
193protected:
194    SkPaint* getPaint(OpenGLRenderer& renderer) {
195        return renderer.filterPaint(mPaint);
196    }
197
198    // Helper method for determining op opaqueness. Assumes op fills its bounds in local
199    // coordinates, and that paint's alpha is used
200    inline bool isOpaqueOverBounds(const DeferredDisplayState& state) {
201        // ensure that local bounds cover mapped bounds
202        if (!state.mMatrix.isSimple()) return false;
203
204        // check state/paint for transparency
205        if (state.mDrawModifiers.mShader ||
206                state.mAlpha != 1.0f ||
207                (mPaint && mPaint->getAlpha() != 0xFF)) return false;
208
209        SkXfermode::Mode mode = OpenGLRenderer::getXfermodeDirect(mPaint);
210        return (mode == SkXfermode::kSrcOver_Mode ||
211                mode == SkXfermode::kSrc_Mode);
212
213    }
214
215    SkPaint* mPaint; // should be accessed via getPaint() when applying
216    bool mQuickRejected;
217};
218
219class DrawBoundedOp : public DrawOp {
220public:
221    DrawBoundedOp(float left, float top, float right, float bottom, SkPaint* paint)
222            : DrawOp(paint), mLocalBounds(left, top, right, bottom) {}
223
224    DrawBoundedOp(const Rect& localBounds, SkPaint* paint)
225            : DrawOp(paint), mLocalBounds(localBounds) {}
226
227    // Calculates bounds as smallest rect encompassing all points
228    // NOTE: requires at least 1 vertex, and doesn't account for stroke size (should be handled in
229    // subclass' constructor)
230    DrawBoundedOp(const float* points, int count, SkPaint* paint)
231            : DrawOp(paint), mLocalBounds(points[0], points[1], points[0], points[1]) {
232        for (int i = 2; i < count; i += 2) {
233            mLocalBounds.left = fminf(mLocalBounds.left, points[i]);
234            mLocalBounds.right = fmaxf(mLocalBounds.right, points[i]);
235            mLocalBounds.top = fminf(mLocalBounds.top, points[i + 1]);
236            mLocalBounds.bottom = fmaxf(mLocalBounds.bottom, points[i + 1]);
237        }
238    }
239
240    // default empty constructor for bounds, to be overridden in child constructor body
241    DrawBoundedOp(SkPaint* paint): DrawOp(paint) { }
242
243    bool getLocalBounds(const DrawModifiers& drawModifiers, Rect& localBounds) {
244        localBounds.set(mLocalBounds);
245        if (drawModifiers.mHasShadow) {
246            // TODO: inspect paint's looper directly
247            Rect shadow(mLocalBounds);
248            shadow.translate(drawModifiers.mShadowDx, drawModifiers.mShadowDy);
249            shadow.outset(drawModifiers.mShadowRadius);
250            localBounds.unionWith(shadow);
251        }
252        return true;
253    }
254
255protected:
256    Rect mLocalBounds; // displayed area in LOCAL coord. doesn't incorporate stroke, so check paint
257};
258
259///////////////////////////////////////////////////////////////////////////////
260// STATE OPERATIONS - these may affect the state of the canvas/renderer, but do
261//         not directly draw or alter output
262///////////////////////////////////////////////////////////////////////////////
263
264class SaveOp : public StateOp {
265    friend class DisplayList; // give DisplayList private constructor/reinit access
266public:
267    SaveOp(int flags)
268            : mFlags(flags) {}
269
270    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
271            bool useQuickReject) {
272        int newSaveCount = deferStruct.mRenderer.save(mFlags);
273        deferStruct.mDeferredList.addSave(deferStruct.mRenderer, this, newSaveCount);
274    }
275
276    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
277        renderer.save(mFlags);
278    }
279
280    virtual void output(int level, uint32_t logFlags) const {
281        OP_LOG("Save flags %x", mFlags);
282    }
283
284    virtual const char* name() { return "Save"; }
285
286    int getFlags() const { return mFlags; }
287private:
288    SaveOp() {}
289    DisplayListOp* reinit(int flags) {
290        mFlags = flags;
291        return this;
292    }
293
294    int mFlags;
295};
296
297class RestoreToCountOp : public StateOp {
298    friend class DisplayList; // give DisplayList private constructor/reinit access
299public:
300    RestoreToCountOp(int count)
301            : mCount(count) {}
302
303    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
304            bool useQuickReject) {
305        deferStruct.mDeferredList.addRestoreToCount(deferStruct.mRenderer,
306                this, saveCount + mCount);
307        deferStruct.mRenderer.restoreToCount(saveCount + mCount);
308    }
309
310    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
311        renderer.restoreToCount(saveCount + mCount);
312    }
313
314    virtual void output(int level, uint32_t logFlags) const {
315        OP_LOG("Restore to count %d", mCount);
316    }
317
318    virtual const char* name() { return "RestoreToCount"; }
319
320private:
321    RestoreToCountOp() {}
322    DisplayListOp* reinit(int count) {
323        mCount = count;
324        return this;
325    }
326
327    int mCount;
328};
329
330class SaveLayerOp : public StateOp {
331    friend class DisplayList; // give DisplayList private constructor/reinit access
332public:
333    SaveLayerOp(float left, float top, float right, float bottom,
334            int alpha, SkXfermode::Mode mode, int flags)
335            : mArea(left, top, right, bottom), mAlpha(alpha), mMode(mode), mFlags(flags) {}
336
337    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
338            bool useQuickReject) {
339        // NOTE: don't bother with actual saveLayer, instead issuing it at flush time
340        int newSaveCount = deferStruct.mRenderer.getSaveCount();
341        deferStruct.mDeferredList.addSaveLayer(deferStruct.mRenderer, this, newSaveCount);
342
343        // NOTE: don't issue full saveLayer, since that has side effects/is costly. instead just
344        // setup the snapshot for deferral, and re-issue the op at flush time
345        deferStruct.mRenderer.saveLayerDeferred(mArea.left, mArea.top, mArea.right, mArea.bottom,
346                mAlpha, mMode, mFlags);
347    }
348
349    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
350        renderer.saveLayer(mArea.left, mArea.top, mArea.right, mArea.bottom, mAlpha, mMode, mFlags);
351    }
352
353    virtual void output(int level, uint32_t logFlags) const {
354        OP_LOG("SaveLayer%s of area " RECT_STRING,
355                (isSaveLayerAlpha() ? "Alpha" : ""),RECT_ARGS(mArea));
356    }
357
358    virtual const char* name() { return isSaveLayerAlpha() ? "SaveLayerAlpha" : "SaveLayer"; }
359
360    int getFlags() { return mFlags; }
361
362private:
363    // Special case, reserved for direct DisplayList usage
364    SaveLayerOp() {}
365    DisplayListOp* reinit(float left, float top, float right, float bottom,
366            int alpha, SkXfermode::Mode mode, int flags) {
367        mArea.set(left, top, right, bottom);
368        mAlpha = alpha;
369        mMode = mode;
370        mFlags = flags;
371        return this;
372    }
373
374    bool isSaveLayerAlpha() const { return mAlpha < 255 && mMode == SkXfermode::kSrcOver_Mode; }
375    Rect mArea;
376    int mAlpha;
377    SkXfermode::Mode mMode;
378    int mFlags;
379};
380
381class TranslateOp : public StateOp {
382public:
383    TranslateOp(float dx, float dy)
384            : mDx(dx), mDy(dy) {}
385
386    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
387        renderer.translate(mDx, mDy);
388    }
389
390    virtual void output(int level, uint32_t logFlags) const {
391        OP_LOG("Translate by %f %f", mDx, mDy);
392    }
393
394    virtual const char* name() { return "Translate"; }
395
396private:
397    float mDx;
398    float mDy;
399};
400
401class RotateOp : public StateOp {
402public:
403    RotateOp(float degrees)
404            : mDegrees(degrees) {}
405
406    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
407        renderer.rotate(mDegrees);
408    }
409
410    virtual void output(int level, uint32_t logFlags) const {
411        OP_LOG("Rotate by %f degrees", mDegrees);
412    }
413
414    virtual const char* name() { return "Rotate"; }
415
416private:
417    float mDegrees;
418};
419
420class ScaleOp : public StateOp {
421public:
422    ScaleOp(float sx, float sy)
423            : mSx(sx), mSy(sy) {}
424
425    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
426        renderer.scale(mSx, mSy);
427    }
428
429    virtual void output(int level, uint32_t logFlags) const {
430        OP_LOG("Scale by %f %f", mSx, mSy);
431    }
432
433    virtual const char* name() { return "Scale"; }
434
435private:
436    float mSx;
437    float mSy;
438};
439
440class SkewOp : public StateOp {
441public:
442    SkewOp(float sx, float sy)
443            : mSx(sx), mSy(sy) {}
444
445    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
446        renderer.skew(mSx, mSy);
447    }
448
449    virtual void output(int level, uint32_t logFlags) const {
450        OP_LOG("Skew by %f %f", mSx, mSy);
451    }
452
453    virtual const char* name() { return "Skew"; }
454
455private:
456    float mSx;
457    float mSy;
458};
459
460class SetMatrixOp : public StateOp {
461public:
462    SetMatrixOp(SkMatrix* matrix)
463            : mMatrix(matrix) {}
464
465    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
466        renderer.setMatrix(mMatrix);
467    }
468
469    virtual void output(int level, uint32_t logFlags) const {
470        if (mMatrix) {
471            OP_LOG("SetMatrix " MATRIX_STRING, MATRIX_ARGS(mMatrix));
472        } else {
473            OP_LOGS("SetMatrix (reset)");
474        }
475    }
476
477    virtual const char* name() { return "SetMatrix"; }
478
479private:
480    SkMatrix* mMatrix;
481};
482
483class ConcatMatrixOp : public StateOp {
484public:
485    ConcatMatrixOp(SkMatrix* matrix)
486            : mMatrix(matrix) {}
487
488    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
489        renderer.concatMatrix(mMatrix);
490    }
491
492    virtual void output(int level, uint32_t logFlags) const {
493        OP_LOG("ConcatMatrix " MATRIX_STRING, MATRIX_ARGS(mMatrix));
494    }
495
496    virtual const char* name() { return "ConcatMatrix"; }
497
498private:
499    SkMatrix* mMatrix;
500};
501
502class ClipOp : public StateOp {
503public:
504    ClipOp(SkRegion::Op op) : mOp(op) {}
505
506    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
507            bool useQuickReject) {
508        // NOTE: must defer op BEFORE applying state, since it may read clip
509        deferStruct.mDeferredList.addClip(deferStruct.mRenderer, this);
510
511        // TODO: Can we avoid applying complex clips at defer time?
512        applyState(deferStruct.mRenderer, saveCount);
513    }
514
515    bool canCauseComplexClip() {
516        return ((mOp != SkRegion::kIntersect_Op) && (mOp != SkRegion::kReplace_Op)) || !isRect();
517    }
518
519protected:
520    ClipOp() {}
521    virtual bool isRect() { return false; }
522
523    SkRegion::Op mOp;
524};
525
526class ClipRectOp : public ClipOp {
527    friend class DisplayList; // give DisplayList private constructor/reinit access
528public:
529    ClipRectOp(float left, float top, float right, float bottom, SkRegion::Op op)
530            : ClipOp(op), mArea(left, top, right, bottom) {}
531
532    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
533        renderer.clipRect(mArea.left, mArea.top, mArea.right, mArea.bottom, mOp);
534    }
535
536    virtual void output(int level, uint32_t logFlags) const {
537        OP_LOG("ClipRect " RECT_STRING, RECT_ARGS(mArea));
538    }
539
540    virtual const char* name() { return "ClipRect"; }
541
542protected:
543    virtual bool isRect() { return true; }
544
545private:
546    ClipRectOp() {}
547    DisplayListOp* reinit(float left, float top, float right, float bottom, SkRegion::Op op) {
548        mOp = op;
549        mArea.set(left, top, right, bottom);
550        return this;
551    }
552
553    Rect mArea;
554};
555
556class ClipPathOp : public ClipOp {
557public:
558    ClipPathOp(SkPath* path, SkRegion::Op op)
559            : ClipOp(op), mPath(path) {}
560
561    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
562        renderer.clipPath(mPath, mOp);
563    }
564
565    virtual void output(int level, uint32_t logFlags) const {
566        SkRect bounds = mPath->getBounds();
567        OP_LOG("ClipPath bounds " RECT_STRING,
568                bounds.left(), bounds.top(), bounds.right(), bounds.bottom());
569    }
570
571    virtual const char* name() { return "ClipPath"; }
572
573private:
574    SkPath* mPath;
575};
576
577class ClipRegionOp : public ClipOp {
578public:
579    ClipRegionOp(SkRegion* region, SkRegion::Op op)
580            : ClipOp(op), mRegion(region) {}
581
582    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
583        renderer.clipRegion(mRegion, mOp);
584    }
585
586    virtual void output(int level, uint32_t logFlags) const {
587        SkIRect bounds = mRegion->getBounds();
588        OP_LOG("ClipRegion bounds %d %d %d %d",
589                bounds.left(), bounds.top(), bounds.right(), bounds.bottom());
590    }
591
592    virtual const char* name() { return "ClipRegion"; }
593
594private:
595    SkRegion* mRegion;
596};
597
598class ResetShaderOp : public StateOp {
599public:
600    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
601        renderer.resetShader();
602    }
603
604    virtual void output(int level, uint32_t logFlags) const {
605        OP_LOGS("ResetShader");
606    }
607
608    virtual const char* name() { return "ResetShader"; }
609};
610
611class SetupShaderOp : public StateOp {
612public:
613    SetupShaderOp(SkiaShader* shader)
614            : mShader(shader) {}
615    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
616        renderer.setupShader(mShader);
617    }
618
619    virtual void output(int level, uint32_t logFlags) const {
620        OP_LOG("SetupShader, shader %p", mShader);
621    }
622
623    virtual const char* name() { return "SetupShader"; }
624
625private:
626    SkiaShader* mShader;
627};
628
629class ResetColorFilterOp : public StateOp {
630public:
631    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
632        renderer.resetColorFilter();
633    }
634
635    virtual void output(int level, uint32_t logFlags) const {
636        OP_LOGS("ResetColorFilter");
637    }
638
639    virtual const char* name() { return "ResetColorFilter"; }
640};
641
642class SetupColorFilterOp : public StateOp {
643public:
644    SetupColorFilterOp(SkiaColorFilter* colorFilter)
645            : mColorFilter(colorFilter) {}
646
647    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
648        renderer.setupColorFilter(mColorFilter);
649    }
650
651    virtual void output(int level, uint32_t logFlags) const {
652        OP_LOG("SetupColorFilter, filter %p", mColorFilter);
653    }
654
655    virtual const char* name() { return "SetupColorFilter"; }
656
657private:
658    SkiaColorFilter* mColorFilter;
659};
660
661class ResetShadowOp : public StateOp {
662public:
663    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
664        renderer.resetShadow();
665    }
666
667    virtual void output(int level, uint32_t logFlags) const {
668        OP_LOGS("ResetShadow");
669    }
670
671    virtual const char* name() { return "ResetShadow"; }
672};
673
674class SetupShadowOp : public StateOp {
675public:
676    SetupShadowOp(float radius, float dx, float dy, int color)
677            : mRadius(radius), mDx(dx), mDy(dy), mColor(color) {}
678
679    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
680        renderer.setupShadow(mRadius, mDx, mDy, mColor);
681    }
682
683    virtual void output(int level, uint32_t logFlags) const {
684        OP_LOG("SetupShadow, radius %f, %f, %f, color %#x", mRadius, mDx, mDy, mColor);
685    }
686
687    virtual const char* name() { return "SetupShadow"; }
688
689private:
690    float mRadius;
691    float mDx;
692    float mDy;
693    int mColor;
694};
695
696class ResetPaintFilterOp : public StateOp {
697public:
698    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
699        renderer.resetPaintFilter();
700    }
701
702    virtual void output(int level, uint32_t logFlags) const {
703        OP_LOGS("ResetPaintFilter");
704    }
705
706    virtual const char* name() { return "ResetPaintFilter"; }
707};
708
709class SetupPaintFilterOp : public StateOp {
710public:
711    SetupPaintFilterOp(int clearBits, int setBits)
712            : mClearBits(clearBits), mSetBits(setBits) {}
713
714    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
715        renderer.setupPaintFilter(mClearBits, mSetBits);
716    }
717
718    virtual void output(int level, uint32_t logFlags) const {
719        OP_LOG("SetupPaintFilter, clear %#x, set %#x", mClearBits, mSetBits);
720    }
721
722    virtual const char* name() { return "SetupPaintFilter"; }
723
724private:
725    int mClearBits;
726    int mSetBits;
727};
728
729///////////////////////////////////////////////////////////////////////////////
730// DRAW OPERATIONS - these are operations that can draw to the canvas's device
731///////////////////////////////////////////////////////////////////////////////
732
733class DrawBitmapOp : public DrawBoundedOp {
734public:
735    DrawBitmapOp(SkBitmap* bitmap, float left, float top, SkPaint* paint)
736            : DrawBoundedOp(left, top, left + bitmap->width(), top + bitmap->height(), paint),
737            mBitmap(bitmap), mAtlas(Caches::getInstance().assetAtlas) {
738        mEntry = mAtlas.getEntry(bitmap);
739        if (mEntry) {
740            mEntryGenerationId = mAtlas.getGenerationId();
741            mUvMapper = mEntry->uvMapper;
742        }
743    }
744
745    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
746        return renderer.drawBitmap(mBitmap, mLocalBounds.left, mLocalBounds.top,
747                getPaint(renderer));
748    }
749
750    AssetAtlas::Entry* getAtlasEntry() {
751        // The atlas entry is stale, let's get a new one
752        if (mEntry && mEntryGenerationId != mAtlas.getGenerationId()) {
753            mEntryGenerationId = mAtlas.getGenerationId();
754            mEntry = mAtlas.getEntry(mBitmap);
755            mUvMapper = mEntry->uvMapper;
756        }
757        return mEntry;
758    }
759
760#define SET_TEXTURE(ptr, posRect, offsetRect, texCoordsRect, xDim, yDim) \
761    TextureVertex::set(ptr++, posRect.xDim - offsetRect.left, posRect.yDim - offsetRect.top, \
762            texCoordsRect.xDim, texCoordsRect.yDim)
763
764    /**
765     * This multi-draw operation builds a mesh on the stack by generating a quad
766     * for each bitmap in the batch. This method is also responsible for dirtying
767     * the current layer, if any.
768     */
769    virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
770            const Vector<OpStatePair>& ops, const Rect& bounds) {
771        const DeferredDisplayState& firstState = *(ops[0].state);
772        renderer.restoreDisplayState(firstState, true); // restore all but the clip
773
774        TextureVertex vertices[6 * ops.size()];
775        TextureVertex* vertex = &vertices[0];
776
777        const bool hasLayer = renderer.hasLayer();
778        bool pureTranslate = true;
779
780        // TODO: manually handle rect clip for bitmaps by adjusting texCoords per op,
781        // and allowing them to be merged in getBatchId()
782        for (unsigned int i = 0; i < ops.size(); i++) {
783            const DeferredDisplayState& state = *(ops[i].state);
784            const Rect& opBounds = state.mBounds;
785            // When we reach multiDraw(), the matrix can be either
786            // pureTranslate or simple (translate and/or scale).
787            // If the matrix is not pureTranslate, then we have a scale
788            pureTranslate &= state.mMatrix.isPureTranslate();
789
790            Rect texCoords(0, 0, 1, 1);
791            ((DrawBitmapOp*) ops[i].op)->mUvMapper.map(texCoords);
792
793            SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, top);
794            SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, top);
795            SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, bottom);
796
797            SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, bottom);
798            SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, top);
799            SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, bottom);
800
801            if (hasLayer) {
802                renderer.dirtyLayer(opBounds.left, opBounds.top, opBounds.right, opBounds.bottom);
803            }
804        }
805
806        return renderer.drawBitmaps(mBitmap, mEntry, ops.size(), &vertices[0],
807                pureTranslate, bounds, mPaint);
808    }
809
810    virtual void output(int level, uint32_t logFlags) const {
811        OP_LOG("Draw bitmap %p at %f %f", mBitmap, mLocalBounds.left, mLocalBounds.top);
812    }
813
814    virtual const char* name() { return "DrawBitmap"; }
815
816    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
817            const DeferredDisplayState& state) {
818        deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
819        deferInfo.mergeId = getAtlasEntry() ?
820                (mergeid_t) mEntry->getMergeId() : (mergeid_t) mBitmap;
821
822        // Don't merge non-simply transformed or neg scale ops, SET_TEXTURE doesn't handle rotation
823        // Don't merge A8 bitmaps - the paint's color isn't compared by mergeId, or in
824        // MergingDrawBatch::canMergeWith()
825        // TODO: support clipped bitmaps by handling them in SET_TEXTURE
826        deferInfo.mergeable = state.mMatrix.isSimple() && state.mMatrix.positiveScale() &&
827                !state.mClipSideFlags &&
828                OpenGLRenderer::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode &&
829                (mBitmap->getConfig() != SkBitmap::kA8_Config);
830    }
831
832    const SkBitmap* bitmap() { return mBitmap; }
833protected:
834    SkBitmap* mBitmap;
835    const AssetAtlas& mAtlas;
836    uint32_t mEntryGenerationId;
837    AssetAtlas::Entry* mEntry;
838    UvMapper mUvMapper;
839};
840
841class DrawBitmapMatrixOp : public DrawBoundedOp {
842public:
843    DrawBitmapMatrixOp(SkBitmap* bitmap, SkMatrix* matrix, SkPaint* paint)
844            : DrawBoundedOp(paint), mBitmap(bitmap), mMatrix(matrix) {
845        mLocalBounds.set(0, 0, bitmap->width(), bitmap->height());
846        const mat4 transform(*matrix);
847        transform.mapRect(mLocalBounds);
848    }
849
850    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
851        return renderer.drawBitmap(mBitmap, mMatrix, getPaint(renderer));
852    }
853
854    virtual void output(int level, uint32_t logFlags) const {
855        OP_LOG("Draw bitmap %p matrix " MATRIX_STRING, mBitmap, MATRIX_ARGS(mMatrix));
856    }
857
858    virtual const char* name() { return "DrawBitmapMatrix"; }
859
860    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
861            const DeferredDisplayState& state) {
862        deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
863    }
864
865private:
866    SkBitmap* mBitmap;
867    SkMatrix* mMatrix;
868};
869
870class DrawBitmapRectOp : public DrawBoundedOp {
871public:
872    DrawBitmapRectOp(SkBitmap* bitmap, float srcLeft, float srcTop, float srcRight, float srcBottom,
873            float dstLeft, float dstTop, float dstRight, float dstBottom, SkPaint* paint)
874            : DrawBoundedOp(dstLeft, dstTop, dstRight, dstBottom, paint),
875            mBitmap(bitmap), mSrc(srcLeft, srcTop, srcRight, srcBottom) {}
876
877    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
878        return renderer.drawBitmap(mBitmap, mSrc.left, mSrc.top, mSrc.right, mSrc.bottom,
879                mLocalBounds.left, mLocalBounds.top, mLocalBounds.right, mLocalBounds.bottom,
880                getPaint(renderer));
881    }
882
883    virtual void output(int level, uint32_t logFlags) const {
884        OP_LOG("Draw bitmap %p src="RECT_STRING", dst="RECT_STRING,
885                mBitmap, RECT_ARGS(mSrc), RECT_ARGS(mLocalBounds));
886    }
887
888    virtual const char* name() { return "DrawBitmapRect"; }
889
890    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
891            const DeferredDisplayState& state) {
892        deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
893    }
894
895private:
896    SkBitmap* mBitmap;
897    Rect mSrc;
898};
899
900class DrawBitmapDataOp : public DrawBitmapOp {
901public:
902    DrawBitmapDataOp(SkBitmap* bitmap, float left, float top, SkPaint* paint)
903            : DrawBitmapOp(bitmap, left, top, paint) {}
904
905    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
906        return renderer.drawBitmapData(mBitmap, mLocalBounds.left,
907                mLocalBounds.top, getPaint(renderer));
908    }
909
910    virtual void output(int level, uint32_t logFlags) const {
911        OP_LOG("Draw bitmap %p", mBitmap);
912    }
913
914    virtual const char* name() { return "DrawBitmapData"; }
915
916    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
917            const DeferredDisplayState& state) {
918        deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
919    }
920};
921
922class DrawBitmapMeshOp : public DrawBoundedOp {
923public:
924    DrawBitmapMeshOp(SkBitmap* bitmap, int meshWidth, int meshHeight,
925            float* vertices, int* colors, SkPaint* paint)
926            : DrawBoundedOp(vertices, 2 * (meshWidth + 1) * (meshHeight + 1), paint),
927            mBitmap(bitmap), mMeshWidth(meshWidth), mMeshHeight(meshHeight),
928            mVertices(vertices), mColors(colors) {}
929
930    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
931        return renderer.drawBitmapMesh(mBitmap, mMeshWidth, mMeshHeight,
932                mVertices, mColors, getPaint(renderer));
933    }
934
935    virtual void output(int level, uint32_t logFlags) const {
936        OP_LOG("Draw bitmap %p mesh %d x %d", mBitmap, mMeshWidth, mMeshHeight);
937    }
938
939    virtual const char* name() { return "DrawBitmapMesh"; }
940
941    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
942            const DeferredDisplayState& state) {
943        deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
944    }
945
946private:
947    SkBitmap* mBitmap;
948    int mMeshWidth;
949    int mMeshHeight;
950    float* mVertices;
951    int* mColors;
952};
953
954class DrawPatchOp : public DrawBoundedOp {
955public:
956    DrawPatchOp(SkBitmap* bitmap, Res_png_9patch* patch,
957            float left, float top, float right, float bottom, SkPaint* paint)
958            : DrawBoundedOp(left, top, right, bottom, paint),
959            mBitmap(bitmap), mPatch(patch), mGenerationId(0), mMesh(NULL),
960            mAtlas(Caches::getInstance().assetAtlas) {
961        mEntry = mAtlas.getEntry(bitmap);
962        if (mEntry) {
963            mEntryGenerationId = mAtlas.getGenerationId();
964        }
965    };
966
967    AssetAtlas::Entry* getAtlasEntry() {
968        // The atlas entry is stale, let's get a new one
969        if (mEntry && mEntryGenerationId != mAtlas.getGenerationId()) {
970            mEntryGenerationId = mAtlas.getGenerationId();
971            mEntry = mAtlas.getEntry(mBitmap);
972        }
973        return mEntry;
974    }
975
976    const Patch* getMesh(OpenGLRenderer& renderer) {
977        if (!mMesh || renderer.getCaches().patchCache.getGenerationId() != mGenerationId) {
978            PatchCache& cache = renderer.getCaches().patchCache;
979            mMesh = cache.get(getAtlasEntry(), mBitmap->width(), mBitmap->height(),
980                    mLocalBounds.getWidth(), mLocalBounds.getHeight(), mPatch);
981            mGenerationId = cache.getGenerationId();
982        }
983        return mMesh;
984    }
985
986    /**
987     * This multi-draw operation builds an indexed mesh on the stack by copying
988     * and transforming the vertices of each 9-patch in the batch. This method
989     * is also responsible for dirtying the current layer, if any.
990     */
991    virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
992            const Vector<OpStatePair>& ops, const Rect& bounds) {
993        const DeferredDisplayState& firstState = *(ops[0].state);
994        renderer.restoreDisplayState(firstState, true); // restore all but the clip
995
996        // Batches will usually contain a small number of items so it's
997        // worth performing a first iteration to count the exact number
998        // of vertices we need in the new mesh
999        uint32_t totalVertices = 0;
1000        for (unsigned int i = 0; i < ops.size(); i++) {
1001            totalVertices += ((DrawPatchOp*) ops[i].op)->getMesh(renderer)->verticesCount;
1002        }
1003
1004        const bool hasLayer = renderer.hasLayer();
1005
1006        uint32_t indexCount = 0;
1007
1008        TextureVertex vertices[totalVertices];
1009        TextureVertex* vertex = &vertices[0];
1010
1011        // Create a mesh that contains the transformed vertices for all the
1012        // 9-patch objects that are part of the batch. Note that onDefer()
1013        // enforces ops drawn by this function to have a pure translate or
1014        // identity matrix
1015        for (unsigned int i = 0; i < ops.size(); i++) {
1016            DrawPatchOp* patchOp = (DrawPatchOp*) ops[i].op;
1017            const DeferredDisplayState* state = ops[i].state;
1018            const Patch* opMesh = patchOp->getMesh(renderer);
1019            uint32_t vertexCount = opMesh->verticesCount;
1020            if (vertexCount == 0) continue;
1021
1022            // We use the bounds to know where to translate our vertices
1023            // Using patchOp->state.mBounds wouldn't work because these
1024            // bounds are clipped
1025            const float tx = (int) floorf(state->mMatrix.getTranslateX() +
1026                    patchOp->mLocalBounds.left + 0.5f);
1027            const float ty = (int) floorf(state->mMatrix.getTranslateY() +
1028                    patchOp->mLocalBounds.top + 0.5f);
1029
1030            // Copy & transform all the vertices for the current operation
1031            TextureVertex* opVertices = opMesh->vertices;
1032            for (uint32_t j = 0; j < vertexCount; j++, opVertices++) {
1033                TextureVertex::set(vertex++,
1034                        opVertices->x + tx, opVertices->y + ty,
1035                        opVertices->u, opVertices->v);
1036            }
1037
1038            // Dirty the current layer if possible. When the 9-patch does not
1039            // contain empty quads we can take a shortcut and simply set the
1040            // dirty rect to the object's bounds.
1041            if (hasLayer) {
1042                if (!opMesh->hasEmptyQuads) {
1043                    renderer.dirtyLayer(tx, ty,
1044                            tx + patchOp->mLocalBounds.getWidth(),
1045                            ty + patchOp->mLocalBounds.getHeight());
1046                } else {
1047                    const size_t count = opMesh->quads.size();
1048                    for (size_t i = 0; i < count; i++) {
1049                        const Rect& quadBounds = opMesh->quads[i];
1050                        const float x = tx + quadBounds.left;
1051                        const float y = ty + quadBounds.top;
1052                        renderer.dirtyLayer(x, y,
1053                                x + quadBounds.getWidth(), y + quadBounds.getHeight());
1054                    }
1055                }
1056            }
1057
1058            indexCount += opMesh->indexCount;
1059        }
1060
1061        return renderer.drawPatches(mBitmap, getAtlasEntry(),
1062                &vertices[0], indexCount, getPaint(renderer));
1063    }
1064
1065    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1066        // We're not calling the public variant of drawPatch() here
1067        // This method won't perform the quickReject() since we've already done it at this point
1068        return renderer.drawPatch(mBitmap, getMesh(renderer), getAtlasEntry(),
1069                mLocalBounds.left, mLocalBounds.top, mLocalBounds.right, mLocalBounds.bottom,
1070                getPaint(renderer));
1071    }
1072
1073    virtual void output(int level, uint32_t logFlags) const {
1074        OP_LOG("Draw patch "RECT_STRING, RECT_ARGS(mLocalBounds));
1075    }
1076
1077    virtual const char* name() { return "DrawPatch"; }
1078
1079    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
1080            const DeferredDisplayState& state) {
1081        deferInfo.batchId = DeferredDisplayList::kOpBatch_Patch;
1082        deferInfo.mergeId = getAtlasEntry() ? (mergeid_t) mEntry->getMergeId() : (mergeid_t) mBitmap;
1083        deferInfo.mergeable = state.mMatrix.isPureTranslate() &&
1084                OpenGLRenderer::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode;
1085        deferInfo.opaqueOverBounds = isOpaqueOverBounds(state) && mBitmap->isOpaque();
1086    }
1087
1088private:
1089    SkBitmap* mBitmap;
1090    Res_png_9patch* mPatch;
1091
1092    uint32_t mGenerationId;
1093    const Patch* mMesh;
1094
1095    const AssetAtlas& mAtlas;
1096    uint32_t mEntryGenerationId;
1097    AssetAtlas::Entry* mEntry;
1098};
1099
1100class DrawColorOp : public DrawOp {
1101public:
1102    DrawColorOp(int color, SkXfermode::Mode mode)
1103            : DrawOp(0), mColor(color), mMode(mode) {};
1104
1105    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1106        return renderer.drawColor(mColor, mMode);
1107    }
1108
1109    virtual void output(int level, uint32_t logFlags) const {
1110        OP_LOG("Draw color %#x, mode %d", mColor, mMode);
1111    }
1112
1113    virtual const char* name() { return "DrawColor"; }
1114
1115private:
1116    int mColor;
1117    SkXfermode::Mode mMode;
1118};
1119
1120class DrawStrokableOp : public DrawBoundedOp {
1121public:
1122    DrawStrokableOp(float left, float top, float right, float bottom, SkPaint* paint)
1123            : DrawBoundedOp(left, top, right, bottom, paint) {};
1124
1125    bool getLocalBounds(const DrawModifiers& drawModifiers, Rect& localBounds) {
1126        localBounds.set(mLocalBounds);
1127        if (mPaint && mPaint->getStyle() != SkPaint::kFill_Style) {
1128            localBounds.outset(strokeWidthOutset());
1129        }
1130        return true;
1131    }
1132
1133    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
1134            const DeferredDisplayState& state) {
1135        if (mPaint->getPathEffect()) {
1136            deferInfo.batchId = DeferredDisplayList::kOpBatch_AlphaMaskTexture;
1137        } else {
1138            deferInfo.batchId = mPaint->isAntiAlias() ?
1139                    DeferredDisplayList::kOpBatch_AlphaVertices :
1140                    DeferredDisplayList::kOpBatch_Vertices;
1141        }
1142    }
1143};
1144
1145class DrawRectOp : public DrawStrokableOp {
1146public:
1147    DrawRectOp(float left, float top, float right, float bottom, SkPaint* paint)
1148            : DrawStrokableOp(left, top, right, bottom, paint) {}
1149
1150    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1151        return renderer.drawRect(mLocalBounds.left, mLocalBounds.top,
1152                mLocalBounds.right, mLocalBounds.bottom, getPaint(renderer));
1153    }
1154
1155    virtual void output(int level, uint32_t logFlags) const {
1156        OP_LOG("Draw Rect "RECT_STRING, RECT_ARGS(mLocalBounds));
1157    }
1158
1159    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
1160            const DeferredDisplayState& state) {
1161        DrawStrokableOp::onDefer(renderer, deferInfo, state);
1162        deferInfo.opaqueOverBounds = isOpaqueOverBounds(state) &&
1163                mPaint->getStyle() == SkPaint::kFill_Style;
1164    }
1165
1166    virtual const char* name() { return "DrawRect"; }
1167};
1168
1169class DrawRectsOp : public DrawBoundedOp {
1170public:
1171    DrawRectsOp(const float* rects, int count, SkPaint* paint)
1172            : DrawBoundedOp(rects, count, paint),
1173            mRects(rects), mCount(count) {}
1174
1175    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1176        return renderer.drawRects(mRects, mCount, getPaint(renderer));
1177    }
1178
1179    virtual void output(int level, uint32_t logFlags) const {
1180        OP_LOG("Draw Rects count %d", mCount);
1181    }
1182
1183    virtual const char* name() { return "DrawRects"; }
1184
1185    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
1186            const DeferredDisplayState& state) {
1187        deferInfo.batchId = DeferredDisplayList::kOpBatch_Vertices;
1188    }
1189
1190private:
1191    const float* mRects;
1192    int mCount;
1193};
1194
1195class DrawRoundRectOp : public DrawStrokableOp {
1196public:
1197    DrawRoundRectOp(float left, float top, float right, float bottom,
1198            float rx, float ry, SkPaint* paint)
1199            : DrawStrokableOp(left, top, right, bottom, paint), mRx(rx), mRy(ry) {}
1200
1201    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1202        return renderer.drawRoundRect(mLocalBounds.left, mLocalBounds.top,
1203                mLocalBounds.right, mLocalBounds.bottom, mRx, mRy, getPaint(renderer));
1204    }
1205
1206    virtual void output(int level, uint32_t logFlags) const {
1207        OP_LOG("Draw RoundRect "RECT_STRING", rx %f, ry %f", RECT_ARGS(mLocalBounds), mRx, mRy);
1208    }
1209
1210    virtual const char* name() { return "DrawRoundRect"; }
1211
1212private:
1213    float mRx;
1214    float mRy;
1215};
1216
1217class DrawCircleOp : public DrawStrokableOp {
1218public:
1219    DrawCircleOp(float x, float y, float radius, SkPaint* paint)
1220            : DrawStrokableOp(x - radius, y - radius, x + radius, y + radius, paint),
1221            mX(x), mY(y), mRadius(radius) {}
1222
1223    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1224        return renderer.drawCircle(mX, mY, mRadius, getPaint(renderer));
1225    }
1226
1227    virtual void output(int level, uint32_t logFlags) const {
1228        OP_LOG("Draw Circle x %f, y %f, r %f", mX, mY, mRadius);
1229    }
1230
1231    virtual const char* name() { return "DrawCircle"; }
1232
1233private:
1234    float mX;
1235    float mY;
1236    float mRadius;
1237};
1238
1239class DrawOvalOp : public DrawStrokableOp {
1240public:
1241    DrawOvalOp(float left, float top, float right, float bottom, SkPaint* paint)
1242            : DrawStrokableOp(left, top, right, bottom, paint) {}
1243
1244    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1245        return renderer.drawOval(mLocalBounds.left, mLocalBounds.top,
1246                mLocalBounds.right, mLocalBounds.bottom, getPaint(renderer));
1247    }
1248
1249    virtual void output(int level, uint32_t logFlags) const {
1250        OP_LOG("Draw Oval "RECT_STRING, RECT_ARGS(mLocalBounds));
1251    }
1252
1253    virtual const char* name() { return "DrawOval"; }
1254};
1255
1256class DrawArcOp : public DrawStrokableOp {
1257public:
1258    DrawArcOp(float left, float top, float right, float bottom,
1259            float startAngle, float sweepAngle, bool useCenter, SkPaint* paint)
1260            : DrawStrokableOp(left, top, right, bottom, paint),
1261            mStartAngle(startAngle), mSweepAngle(sweepAngle), mUseCenter(useCenter) {}
1262
1263    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1264        return renderer.drawArc(mLocalBounds.left, mLocalBounds.top,
1265                mLocalBounds.right, mLocalBounds.bottom,
1266                mStartAngle, mSweepAngle, mUseCenter, getPaint(renderer));
1267    }
1268
1269    virtual void output(int level, uint32_t logFlags) const {
1270        OP_LOG("Draw Arc "RECT_STRING", start %f, sweep %f, useCenter %d",
1271                RECT_ARGS(mLocalBounds), mStartAngle, mSweepAngle, mUseCenter);
1272    }
1273
1274    virtual const char* name() { return "DrawArc"; }
1275
1276private:
1277    float mStartAngle;
1278    float mSweepAngle;
1279    bool mUseCenter;
1280};
1281
1282class DrawPathOp : public DrawBoundedOp {
1283public:
1284    DrawPathOp(SkPath* path, SkPaint* paint)
1285            : DrawBoundedOp(paint), mPath(path) {
1286        float left, top, offset;
1287        uint32_t width, height;
1288        PathCache::computePathBounds(path, paint, left, top, offset, width, height);
1289        left -= offset;
1290        top -= offset;
1291        mLocalBounds.set(left, top, left + width, top + height);
1292    }
1293
1294    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1295        return renderer.drawPath(mPath, getPaint(renderer));
1296    }
1297
1298    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
1299            const DeferredDisplayState& state) {
1300        SkPaint* paint = getPaint(renderer);
1301        renderer.getCaches().pathCache.precache(mPath, paint);
1302
1303        deferInfo.batchId = DeferredDisplayList::kOpBatch_AlphaMaskTexture;
1304    }
1305
1306    virtual void output(int level, uint32_t logFlags) const {
1307        OP_LOG("Draw Path %p in "RECT_STRING, mPath, RECT_ARGS(mLocalBounds));
1308    }
1309
1310    virtual const char* name() { return "DrawPath"; }
1311
1312private:
1313    SkPath* mPath;
1314};
1315
1316class DrawLinesOp : public DrawBoundedOp {
1317public:
1318    DrawLinesOp(float* points, int count, SkPaint* paint)
1319            : DrawBoundedOp(points, count, paint),
1320            mPoints(points), mCount(count) {
1321        mLocalBounds.outset(strokeWidthOutset());
1322    }
1323
1324    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1325        return renderer.drawLines(mPoints, mCount, getPaint(renderer));
1326    }
1327
1328    virtual void output(int level, uint32_t logFlags) const {
1329        OP_LOG("Draw Lines count %d", mCount);
1330    }
1331
1332    virtual const char* name() { return "DrawLines"; }
1333
1334    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
1335            const DeferredDisplayState& state) {
1336        deferInfo.batchId = mPaint->isAntiAlias() ?
1337                DeferredDisplayList::kOpBatch_AlphaVertices :
1338                DeferredDisplayList::kOpBatch_Vertices;
1339    }
1340
1341protected:
1342    float* mPoints;
1343    int mCount;
1344};
1345
1346class DrawPointsOp : public DrawLinesOp {
1347public:
1348    DrawPointsOp(float* points, int count, SkPaint* paint)
1349            : DrawLinesOp(points, count, paint) {}
1350
1351    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1352        return renderer.drawPoints(mPoints, mCount, getPaint(renderer));
1353    }
1354
1355    virtual void output(int level, uint32_t logFlags) const {
1356        OP_LOG("Draw Points count %d", mCount);
1357    }
1358
1359    virtual const char* name() { return "DrawPoints"; }
1360};
1361
1362class DrawSomeTextOp : public DrawOp {
1363public:
1364    DrawSomeTextOp(const char* text, int bytesCount, int count, SkPaint* paint)
1365            : DrawOp(paint), mText(text), mBytesCount(bytesCount), mCount(count) {};
1366
1367    virtual void output(int level, uint32_t logFlags) const {
1368        OP_LOG("Draw some text, %d bytes", mBytesCount);
1369    }
1370
1371    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
1372            const DeferredDisplayState& state) {
1373        SkPaint* paint = getPaint(renderer);
1374        FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(paint);
1375        fontRenderer.precache(paint, mText, mCount, mat4::identity());
1376
1377        deferInfo.batchId = mPaint->getColor() == 0xff000000 ?
1378                DeferredDisplayList::kOpBatch_Text :
1379                DeferredDisplayList::kOpBatch_ColorText;
1380    }
1381
1382protected:
1383    const char* mText;
1384    int mBytesCount;
1385    int mCount;
1386};
1387
1388class DrawTextOnPathOp : public DrawSomeTextOp {
1389public:
1390    DrawTextOnPathOp(const char* text, int bytesCount, int count,
1391            SkPath* path, float hOffset, float vOffset, SkPaint* paint)
1392            : DrawSomeTextOp(text, bytesCount, count, paint),
1393            mPath(path), mHOffset(hOffset), mVOffset(vOffset) {
1394        /* TODO: inherit from DrawBounded and init mLocalBounds */
1395    }
1396
1397    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1398        return renderer.drawTextOnPath(mText, mBytesCount, mCount, mPath,
1399                mHOffset, mVOffset, getPaint(renderer));
1400    }
1401
1402    virtual const char* name() { return "DrawTextOnPath"; }
1403
1404private:
1405    SkPath* mPath;
1406    float mHOffset;
1407    float mVOffset;
1408};
1409
1410class DrawPosTextOp : public DrawSomeTextOp {
1411public:
1412    DrawPosTextOp(const char* text, int bytesCount, int count,
1413            const float* positions, SkPaint* paint)
1414            : DrawSomeTextOp(text, bytesCount, count, paint), mPositions(positions) {
1415        /* TODO: inherit from DrawBounded and init mLocalBounds */
1416    }
1417
1418    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1419        return renderer.drawPosText(mText, mBytesCount, mCount, mPositions, getPaint(renderer));
1420    }
1421
1422    virtual const char* name() { return "DrawPosText"; }
1423
1424private:
1425    const float* mPositions;
1426};
1427
1428class DrawTextOp : public DrawBoundedOp {
1429public:
1430    DrawTextOp(const char* text, int bytesCount, int count, float x, float y,
1431            const float* positions, SkPaint* paint, float totalAdvance, const Rect& bounds)
1432            : DrawBoundedOp(bounds, paint), mText(text), mBytesCount(bytesCount), mCount(count),
1433            mX(x), mY(y), mPositions(positions), mTotalAdvance(totalAdvance) {
1434        memset(&mPrecacheTransform.data[0], 0xff, 16 * sizeof(float));
1435    }
1436
1437    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
1438            const DeferredDisplayState& state) {
1439        SkPaint* paint = getPaint(renderer);
1440        FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(paint);
1441        const mat4& transform = renderer.findBestFontTransform(state.mMatrix);
1442        if (mPrecacheTransform != transform) {
1443            fontRenderer.precache(paint, mText, mCount, transform);
1444            mPrecacheTransform = transform;
1445        }
1446        deferInfo.batchId = mPaint->getColor() == 0xff000000 ?
1447                DeferredDisplayList::kOpBatch_Text :
1448                DeferredDisplayList::kOpBatch_ColorText;
1449
1450        deferInfo.mergeId = (mergeid_t)mPaint->getColor();
1451
1452        // don't merge decorated text - the decorations won't draw in order
1453        bool noDecorations = !(mPaint->getFlags() & (SkPaint::kUnderlineText_Flag |
1454                        SkPaint::kStrikeThruText_Flag));
1455        deferInfo.mergeable = state.mMatrix.isPureTranslate() && noDecorations &&
1456                OpenGLRenderer::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode;
1457    }
1458
1459    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1460        Rect bounds;
1461        getLocalBounds(renderer.getDrawModifiers(), bounds);
1462        return renderer.drawText(mText, mBytesCount, mCount, mX, mY,
1463                mPositions, getPaint(renderer), mTotalAdvance, bounds);
1464    }
1465
1466    virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
1467            const Vector<OpStatePair>& ops, const Rect& bounds) {
1468        status_t status = DrawGlInfo::kStatusDone;
1469        for (unsigned int i = 0; i < ops.size(); i++) {
1470            const DeferredDisplayState& state = *(ops[i].state);
1471            DrawOpMode drawOpMode = (i == ops.size() - 1) ? kDrawOpMode_Flush : kDrawOpMode_Defer;
1472            renderer.restoreDisplayState(state, true); // restore all but the clip
1473
1474            DrawTextOp& op = *((DrawTextOp*)ops[i].op);
1475            // quickReject() will not occure in drawText() so we can use mLocalBounds
1476            // directly, we do not need to account for shadow by calling getLocalBounds()
1477            status |= renderer.drawText(op.mText, op.mBytesCount, op.mCount, op.mX, op.mY,
1478                    op.mPositions, op.getPaint(renderer), op.mTotalAdvance, op.mLocalBounds,
1479                    drawOpMode);
1480        }
1481        return status;
1482    }
1483
1484    virtual void output(int level, uint32_t logFlags) const {
1485        OP_LOG("Draw Text of count %d, bytes %d", mCount, mBytesCount);
1486    }
1487
1488    virtual const char* name() { return "DrawText"; }
1489
1490private:
1491    const char* mText;
1492    int mBytesCount;
1493    int mCount;
1494    float mX;
1495    float mY;
1496    const float* mPositions;
1497    float mTotalAdvance;
1498    mat4 mPrecacheTransform;
1499};
1500
1501///////////////////////////////////////////////////////////////////////////////
1502// SPECIAL DRAW OPERATIONS
1503///////////////////////////////////////////////////////////////////////////////
1504
1505class DrawFunctorOp : public DrawOp {
1506public:
1507    DrawFunctorOp(Functor* functor)
1508            : DrawOp(0), mFunctor(functor) {}
1509
1510    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1511        renderer.startMark("GL functor");
1512        status_t ret = renderer.callDrawGLFunction(mFunctor, dirty);
1513        renderer.endMark();
1514        return ret;
1515    }
1516
1517    virtual void output(int level, uint32_t logFlags) const {
1518        OP_LOG("Draw Functor %p", mFunctor);
1519    }
1520
1521    virtual const char* name() { return "DrawFunctor"; }
1522
1523private:
1524    Functor* mFunctor;
1525};
1526
1527class DrawDisplayListOp : public DrawBoundedOp {
1528public:
1529    DrawDisplayListOp(DisplayList* displayList, int flags)
1530            : DrawBoundedOp(0, 0, displayList->getWidth(), displayList->getHeight(), 0),
1531            mDisplayList(displayList), mFlags(flags) {}
1532
1533    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
1534            bool useQuickReject) {
1535        if (mDisplayList && mDisplayList->isRenderable()) {
1536            mDisplayList->defer(deferStruct, level + 1);
1537        }
1538    }
1539    virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level,
1540            bool useQuickReject) {
1541        if (mDisplayList && mDisplayList->isRenderable()) {
1542            mDisplayList->replay(replayStruct, level + 1);
1543        }
1544    }
1545
1546    // NOT USED since replay() is overridden
1547    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1548        return DrawGlInfo::kStatusDone;
1549    }
1550
1551    virtual void output(int level, uint32_t logFlags) const {
1552        OP_LOG("Draw Display List %p, flags %#x", mDisplayList, mFlags);
1553        if (mDisplayList && (logFlags & kOpLogFlag_Recurse)) {
1554            mDisplayList->output(level + 1);
1555        }
1556    }
1557
1558    virtual const char* name() { return "DrawDisplayList"; }
1559
1560private:
1561    DisplayList* mDisplayList;
1562    int mFlags;
1563};
1564
1565class DrawLayerOp : public DrawOp {
1566public:
1567    DrawLayerOp(Layer* layer, float x, float y)
1568            : DrawOp(0), mLayer(layer), mX(x), mY(y) {}
1569
1570    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1571        return renderer.drawLayer(mLayer, mX, mY);
1572    }
1573
1574    virtual void output(int level, uint32_t logFlags) const {
1575        OP_LOG("Draw Layer %p at %f %f", mLayer, mX, mY);
1576    }
1577
1578    virtual const char* name() { return "DrawLayer"; }
1579
1580private:
1581    Layer* mLayer;
1582    float mX;
1583    float mY;
1584};
1585
1586}; // namespace uirenderer
1587}; // namespace android
1588
1589#endif // ANDROID_HWUI_DISPLAY_OPERATION_H
1590