DisplayListOp.h revision 76d3a1b8d035d27bc80b0f2fc480a903bd001514
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(const 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    const 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    const 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, const SkPaint* paint)
222            : DrawOp(paint), mLocalBounds(left, top, right, bottom) {}
223
224    DrawBoundedOp(const Rect& localBounds, const 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, const 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(const 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 {
265public:
266    SaveOp(int flags)
267            : mFlags(flags) {}
268
269    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
270            bool useQuickReject) {
271        int newSaveCount = deferStruct.mRenderer.save(mFlags);
272        deferStruct.mDeferredList.addSave(deferStruct.mRenderer, this, newSaveCount);
273    }
274
275    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
276        renderer.save(mFlags);
277    }
278
279    virtual void output(int level, uint32_t logFlags) const {
280        OP_LOG("Save flags %x", mFlags);
281    }
282
283    virtual const char* name() { return "Save"; }
284
285    int getFlags() const { return mFlags; }
286private:
287    SaveOp() {}
288    DisplayListOp* reinit(int flags) {
289        mFlags = flags;
290        return this;
291    }
292
293    int mFlags;
294};
295
296class RestoreToCountOp : public StateOp {
297public:
298    RestoreToCountOp(int count)
299            : mCount(count) {}
300
301    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
302            bool useQuickReject) {
303        deferStruct.mDeferredList.addRestoreToCount(deferStruct.mRenderer,
304                this, saveCount + mCount);
305        deferStruct.mRenderer.restoreToCount(saveCount + mCount);
306    }
307
308    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
309        renderer.restoreToCount(saveCount + mCount);
310    }
311
312    virtual void output(int level, uint32_t logFlags) const {
313        OP_LOG("Restore to count %d", mCount);
314    }
315
316    virtual const char* name() { return "RestoreToCount"; }
317
318private:
319    RestoreToCountOp() {}
320    DisplayListOp* reinit(int count) {
321        mCount = count;
322        return this;
323    }
324
325    int mCount;
326};
327
328class SaveLayerOp : public StateOp {
329public:
330    SaveLayerOp(float left, float top, float right, float bottom, int alpha, int flags)
331            : mArea(left, top, right, bottom), mPaint(&mCachedPaint), mFlags(flags) {
332        mCachedPaint.setAlpha(alpha);
333    }
334
335    SaveLayerOp(float left, float top, float right, float bottom, const SkPaint* paint, int flags)
336            : mArea(left, top, right, bottom), mPaint(paint), mFlags(flags) {}
337
338    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
339            bool useQuickReject) {
340        // NOTE: don't bother with actual saveLayer, instead issuing it at flush time
341        int newSaveCount = deferStruct.mRenderer.getSaveCount();
342        deferStruct.mDeferredList.addSaveLayer(deferStruct.mRenderer, this, newSaveCount);
343
344        // NOTE: don't issue full saveLayer, since that has side effects/is costly. instead just
345        // setup the snapshot for deferral, and re-issue the op at flush time
346        deferStruct.mRenderer.saveLayerDeferred(mArea.left, mArea.top, mArea.right, mArea.bottom,
347                mPaint, mFlags);
348    }
349
350    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
351        renderer.saveLayer(mArea.left, mArea.top, mArea.right, mArea.bottom, mPaint, mFlags);
352    }
353
354    virtual void output(int level, uint32_t logFlags) const {
355        OP_LOG("SaveLayer%s of area " RECT_STRING,
356                (isSaveLayerAlpha() ? "Alpha" : ""),RECT_ARGS(mArea));
357    }
358
359    virtual const char* name() { return isSaveLayerAlpha() ? "SaveLayerAlpha" : "SaveLayer"; }
360
361    int getFlags() { return mFlags; }
362
363private:
364    bool isSaveLayerAlpha() const {
365        SkXfermode::Mode mode = OpenGLRenderer::getXfermodeDirect(mPaint);
366        int alpha = OpenGLRenderer::getAlphaDirect(mPaint);
367        return alpha < 255 && mode == SkXfermode::kSrcOver_Mode;
368    }
369
370    Rect mArea;
371    const SkPaint* mPaint;
372    SkPaint mCachedPaint;
373    int mFlags;
374};
375
376class TranslateOp : public StateOp {
377public:
378    TranslateOp(float dx, float dy)
379            : mDx(dx), mDy(dy) {}
380
381    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
382        renderer.translate(mDx, mDy);
383    }
384
385    virtual void output(int level, uint32_t logFlags) const {
386        OP_LOG("Translate by %f %f", mDx, mDy);
387    }
388
389    virtual const char* name() { return "Translate"; }
390
391private:
392    float mDx;
393    float mDy;
394};
395
396class RotateOp : public StateOp {
397public:
398    RotateOp(float degrees)
399            : mDegrees(degrees) {}
400
401    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
402        renderer.rotate(mDegrees);
403    }
404
405    virtual void output(int level, uint32_t logFlags) const {
406        OP_LOG("Rotate by %f degrees", mDegrees);
407    }
408
409    virtual const char* name() { return "Rotate"; }
410
411private:
412    float mDegrees;
413};
414
415class ScaleOp : public StateOp {
416public:
417    ScaleOp(float sx, float sy)
418            : mSx(sx), mSy(sy) {}
419
420    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
421        renderer.scale(mSx, mSy);
422    }
423
424    virtual void output(int level, uint32_t logFlags) const {
425        OP_LOG("Scale by %f %f", mSx, mSy);
426    }
427
428    virtual const char* name() { return "Scale"; }
429
430private:
431    float mSx;
432    float mSy;
433};
434
435class SkewOp : public StateOp {
436public:
437    SkewOp(float sx, float sy)
438            : mSx(sx), mSy(sy) {}
439
440    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
441        renderer.skew(mSx, mSy);
442    }
443
444    virtual void output(int level, uint32_t logFlags) const {
445        OP_LOG("Skew by %f %f", mSx, mSy);
446    }
447
448    virtual const char* name() { return "Skew"; }
449
450private:
451    float mSx;
452    float mSy;
453};
454
455class SetMatrixOp : public StateOp {
456public:
457    SetMatrixOp(const SkMatrix* matrix)
458            : mMatrix(matrix) {}
459
460    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
461        renderer.setMatrix(mMatrix);
462    }
463
464    virtual void output(int level, uint32_t logFlags) const {
465        if (mMatrix) {
466            OP_LOG("SetMatrix " SK_MATRIX_STRING, SK_MATRIX_ARGS(mMatrix));
467        } else {
468            OP_LOGS("SetMatrix (reset)");
469        }
470    }
471
472    virtual const char* name() { return "SetMatrix"; }
473
474private:
475    const SkMatrix* mMatrix;
476};
477
478class ConcatMatrixOp : public StateOp {
479public:
480    ConcatMatrixOp(const SkMatrix* matrix)
481            : mMatrix(matrix) {}
482
483    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
484        renderer.concatMatrix(mMatrix);
485    }
486
487    virtual void output(int level, uint32_t logFlags) const {
488        OP_LOG("ConcatMatrix " SK_MATRIX_STRING, SK_MATRIX_ARGS(mMatrix));
489    }
490
491    virtual const char* name() { return "ConcatMatrix"; }
492
493private:
494    const SkMatrix* mMatrix;
495};
496
497class ClipOp : public StateOp {
498public:
499    ClipOp(SkRegion::Op op) : mOp(op) {}
500
501    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
502            bool useQuickReject) {
503        // NOTE: must defer op BEFORE applying state, since it may read clip
504        deferStruct.mDeferredList.addClip(deferStruct.mRenderer, this);
505
506        // TODO: Can we avoid applying complex clips at defer time?
507        applyState(deferStruct.mRenderer, saveCount);
508    }
509
510    bool canCauseComplexClip() {
511        return ((mOp != SkRegion::kIntersect_Op) && (mOp != SkRegion::kReplace_Op)) || !isRect();
512    }
513
514protected:
515    ClipOp() {}
516    virtual bool isRect() { return false; }
517
518    SkRegion::Op mOp;
519};
520
521class ClipRectOp : public ClipOp {
522public:
523    ClipRectOp(float left, float top, float right, float bottom, SkRegion::Op op)
524            : ClipOp(op), mArea(left, top, right, bottom) {}
525
526    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
527        renderer.clipRect(mArea.left, mArea.top, mArea.right, mArea.bottom, mOp);
528    }
529
530    virtual void output(int level, uint32_t logFlags) const {
531        OP_LOG("ClipRect " RECT_STRING, RECT_ARGS(mArea));
532    }
533
534    virtual const char* name() { return "ClipRect"; }
535
536protected:
537    virtual bool isRect() { return true; }
538
539private:
540    ClipRectOp() {}
541    DisplayListOp* reinit(float left, float top, float right, float bottom, SkRegion::Op op) {
542        mOp = op;
543        mArea.set(left, top, right, bottom);
544        return this;
545    }
546
547    Rect mArea;
548};
549
550class ClipPathOp : public ClipOp {
551public:
552    ClipPathOp(const SkPath* path, SkRegion::Op op)
553            : ClipOp(op), mPath(path) {}
554
555    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
556        renderer.clipPath(mPath, mOp);
557    }
558
559    virtual void output(int level, uint32_t logFlags) const {
560        SkRect bounds = mPath->getBounds();
561        OP_LOG("ClipPath bounds " RECT_STRING,
562                bounds.left(), bounds.top(), bounds.right(), bounds.bottom());
563    }
564
565    virtual const char* name() { return "ClipPath"; }
566
567private:
568    const SkPath* mPath;
569};
570
571class ClipRegionOp : public ClipOp {
572public:
573    ClipRegionOp(const SkRegion* region, SkRegion::Op op)
574            : ClipOp(op), mRegion(region) {}
575
576    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
577        renderer.clipRegion(mRegion, mOp);
578    }
579
580    virtual void output(int level, uint32_t logFlags) const {
581        SkIRect bounds = mRegion->getBounds();
582        OP_LOG("ClipRegion bounds %d %d %d %d",
583                bounds.left(), bounds.top(), bounds.right(), bounds.bottom());
584    }
585
586    virtual const char* name() { return "ClipRegion"; }
587
588private:
589    const SkRegion* mRegion;
590};
591
592class ResetShaderOp : public StateOp {
593public:
594    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
595        renderer.resetShader();
596    }
597
598    virtual void output(int level, uint32_t logFlags) const {
599        OP_LOGS("ResetShader");
600    }
601
602    virtual const char* name() { return "ResetShader"; }
603};
604
605class SetupShaderOp : public StateOp {
606public:
607    SetupShaderOp(SkiaShader* shader)
608            : mShader(shader) {}
609    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
610        renderer.setupShader(mShader);
611    }
612
613    virtual void output(int level, uint32_t logFlags) const {
614        OP_LOG("SetupShader, shader %p", mShader);
615    }
616
617    virtual const char* name() { return "SetupShader"; }
618
619private:
620    SkiaShader* mShader;
621};
622
623class ResetShadowOp : public StateOp {
624public:
625    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
626        renderer.resetShadow();
627    }
628
629    virtual void output(int level, uint32_t logFlags) const {
630        OP_LOGS("ResetShadow");
631    }
632
633    virtual const char* name() { return "ResetShadow"; }
634};
635
636class SetupShadowOp : public StateOp {
637public:
638    SetupShadowOp(float radius, float dx, float dy, int color)
639            : mRadius(radius), mDx(dx), mDy(dy), mColor(color) {}
640
641    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
642        renderer.setupShadow(mRadius, mDx, mDy, mColor);
643    }
644
645    virtual void output(int level, uint32_t logFlags) const {
646        OP_LOG("SetupShadow, radius %f, %f, %f, color %#x", mRadius, mDx, mDy, mColor);
647    }
648
649    virtual const char* name() { return "SetupShadow"; }
650
651private:
652    float mRadius;
653    float mDx;
654    float mDy;
655    int mColor;
656};
657
658class ResetPaintFilterOp : public StateOp {
659public:
660    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
661        renderer.resetPaintFilter();
662    }
663
664    virtual void output(int level, uint32_t logFlags) const {
665        OP_LOGS("ResetPaintFilter");
666    }
667
668    virtual const char* name() { return "ResetPaintFilter"; }
669};
670
671class SetupPaintFilterOp : public StateOp {
672public:
673    SetupPaintFilterOp(int clearBits, int setBits)
674            : mClearBits(clearBits), mSetBits(setBits) {}
675
676    virtual void applyState(OpenGLRenderer& renderer, int saveCount) const {
677        renderer.setupPaintFilter(mClearBits, mSetBits);
678    }
679
680    virtual void output(int level, uint32_t logFlags) const {
681        OP_LOG("SetupPaintFilter, clear %#x, set %#x", mClearBits, mSetBits);
682    }
683
684    virtual const char* name() { return "SetupPaintFilter"; }
685
686private:
687    int mClearBits;
688    int mSetBits;
689};
690
691///////////////////////////////////////////////////////////////////////////////
692// DRAW OPERATIONS - these are operations that can draw to the canvas's device
693///////////////////////////////////////////////////////////////////////////////
694
695class DrawBitmapOp : public DrawBoundedOp {
696public:
697    DrawBitmapOp(const SkBitmap* bitmap, float left, float top, const SkPaint* paint)
698            : DrawBoundedOp(left, top, left + bitmap->width(), top + bitmap->height(), paint),
699            mBitmap(bitmap), mAtlas(Caches::getInstance().assetAtlas) {
700        mEntry = mAtlas.getEntry(bitmap);
701        if (mEntry) {
702            mEntryGenerationId = mAtlas.getGenerationId();
703            mUvMapper = mEntry->uvMapper;
704        }
705    }
706
707    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
708        return renderer.drawBitmap(mBitmap, mLocalBounds.left, mLocalBounds.top,
709                getPaint(renderer));
710    }
711
712    AssetAtlas::Entry* getAtlasEntry() {
713        // The atlas entry is stale, let's get a new one
714        if (mEntry && mEntryGenerationId != mAtlas.getGenerationId()) {
715            mEntryGenerationId = mAtlas.getGenerationId();
716            mEntry = mAtlas.getEntry(mBitmap);
717            mUvMapper = mEntry->uvMapper;
718        }
719        return mEntry;
720    }
721
722#define SET_TEXTURE(ptr, posRect, offsetRect, texCoordsRect, xDim, yDim) \
723    TextureVertex::set(ptr++, posRect.xDim - offsetRect.left, posRect.yDim - offsetRect.top, \
724            texCoordsRect.xDim, texCoordsRect.yDim)
725
726    /**
727     * This multi-draw operation builds a mesh on the stack by generating a quad
728     * for each bitmap in the batch. This method is also responsible for dirtying
729     * the current layer, if any.
730     */
731    virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
732            const Vector<OpStatePair>& ops, const Rect& bounds) {
733        const DeferredDisplayState& firstState = *(ops[0].state);
734        renderer.restoreDisplayState(firstState, true); // restore all but the clip
735
736        TextureVertex vertices[6 * ops.size()];
737        TextureVertex* vertex = &vertices[0];
738
739        const bool hasLayer = renderer.hasLayer();
740        bool pureTranslate = true;
741
742        // TODO: manually handle rect clip for bitmaps by adjusting texCoords per op,
743        // and allowing them to be merged in getBatchId()
744        for (unsigned int i = 0; i < ops.size(); i++) {
745            const DeferredDisplayState& state = *(ops[i].state);
746            const Rect& opBounds = state.mBounds;
747            // When we reach multiDraw(), the matrix can be either
748            // pureTranslate or simple (translate and/or scale).
749            // If the matrix is not pureTranslate, then we have a scale
750            pureTranslate &= state.mMatrix.isPureTranslate();
751
752            Rect texCoords(0, 0, 1, 1);
753            ((DrawBitmapOp*) ops[i].op)->mUvMapper.map(texCoords);
754
755            SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, top);
756            SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, top);
757            SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, bottom);
758
759            SET_TEXTURE(vertex, opBounds, bounds, texCoords, left, bottom);
760            SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, top);
761            SET_TEXTURE(vertex, opBounds, bounds, texCoords, right, bottom);
762
763            if (hasLayer) {
764                renderer.dirtyLayer(opBounds.left, opBounds.top, opBounds.right, opBounds.bottom);
765            }
766        }
767
768        return renderer.drawBitmaps(mBitmap, mEntry, ops.size(), &vertices[0],
769                pureTranslate, bounds, mPaint);
770    }
771
772    virtual void output(int level, uint32_t logFlags) const {
773        OP_LOG("Draw bitmap %p at %f %f", mBitmap, mLocalBounds.left, mLocalBounds.top);
774    }
775
776    virtual const char* name() { return "DrawBitmap"; }
777
778    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
779            const DeferredDisplayState& state) {
780        deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
781        deferInfo.mergeId = getAtlasEntry() ?
782                (mergeid_t) mEntry->getMergeId() : (mergeid_t) mBitmap;
783
784        // Don't merge non-simply transformed or neg scale ops, SET_TEXTURE doesn't handle rotation
785        // Don't merge A8 bitmaps - the paint's color isn't compared by mergeId, or in
786        // MergingDrawBatch::canMergeWith()
787        // TODO: support clipped bitmaps by handling them in SET_TEXTURE
788        deferInfo.mergeable = state.mMatrix.isSimple() && state.mMatrix.positiveScale() &&
789                !state.mClipSideFlags &&
790                OpenGLRenderer::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode &&
791                (mBitmap->getConfig() != SkBitmap::kA8_Config);
792    }
793
794    const SkBitmap* bitmap() { return mBitmap; }
795protected:
796    const SkBitmap* mBitmap;
797    const AssetAtlas& mAtlas;
798    uint32_t mEntryGenerationId;
799    AssetAtlas::Entry* mEntry;
800    UvMapper mUvMapper;
801};
802
803class DrawBitmapMatrixOp : public DrawBoundedOp {
804public:
805    DrawBitmapMatrixOp(const SkBitmap* bitmap, const SkMatrix* matrix, const SkPaint* paint)
806            : DrawBoundedOp(paint), mBitmap(bitmap), mMatrix(matrix) {
807        mLocalBounds.set(0, 0, bitmap->width(), bitmap->height());
808        const mat4 transform(*matrix);
809        transform.mapRect(mLocalBounds);
810    }
811
812    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
813        return renderer.drawBitmap(mBitmap, mMatrix, getPaint(renderer));
814    }
815
816    virtual void output(int level, uint32_t logFlags) const {
817        OP_LOG("Draw bitmap %p matrix " SK_MATRIX_STRING, mBitmap, SK_MATRIX_ARGS(mMatrix));
818    }
819
820    virtual const char* name() { return "DrawBitmapMatrix"; }
821
822    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
823            const DeferredDisplayState& state) {
824        deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
825    }
826
827private:
828    const SkBitmap* mBitmap;
829    const SkMatrix* mMatrix;
830};
831
832class DrawBitmapRectOp : public DrawBoundedOp {
833public:
834    DrawBitmapRectOp(const SkBitmap* bitmap,
835            float srcLeft, float srcTop, float srcRight, float srcBottom,
836            float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint)
837            : DrawBoundedOp(dstLeft, dstTop, dstRight, dstBottom, paint),
838            mBitmap(bitmap), mSrc(srcLeft, srcTop, srcRight, srcBottom) {}
839
840    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
841        return renderer.drawBitmap(mBitmap, mSrc.left, mSrc.top, mSrc.right, mSrc.bottom,
842                mLocalBounds.left, mLocalBounds.top, mLocalBounds.right, mLocalBounds.bottom,
843                getPaint(renderer));
844    }
845
846    virtual void output(int level, uint32_t logFlags) const {
847        OP_LOG("Draw bitmap %p src="RECT_STRING", dst="RECT_STRING,
848                mBitmap, RECT_ARGS(mSrc), RECT_ARGS(mLocalBounds));
849    }
850
851    virtual const char* name() { return "DrawBitmapRect"; }
852
853    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
854            const DeferredDisplayState& state) {
855        deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
856    }
857
858private:
859    const SkBitmap* mBitmap;
860    Rect mSrc;
861};
862
863class DrawBitmapDataOp : public DrawBitmapOp {
864public:
865    DrawBitmapDataOp(const SkBitmap* bitmap, float left, float top, const SkPaint* paint)
866            : DrawBitmapOp(bitmap, left, top, paint) {}
867
868    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
869        return renderer.drawBitmapData(mBitmap, mLocalBounds.left,
870                mLocalBounds.top, getPaint(renderer));
871    }
872
873    virtual void output(int level, uint32_t logFlags) const {
874        OP_LOG("Draw bitmap %p", mBitmap);
875    }
876
877    virtual const char* name() { return "DrawBitmapData"; }
878
879    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
880            const DeferredDisplayState& state) {
881        deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
882    }
883};
884
885class DrawBitmapMeshOp : public DrawBoundedOp {
886public:
887    DrawBitmapMeshOp(const SkBitmap* bitmap, int meshWidth, int meshHeight,
888            const float* vertices, const int* colors, const SkPaint* paint)
889            : DrawBoundedOp(vertices, 2 * (meshWidth + 1) * (meshHeight + 1), paint),
890            mBitmap(bitmap), mMeshWidth(meshWidth), mMeshHeight(meshHeight),
891            mVertices(vertices), mColors(colors) {}
892
893    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
894        return renderer.drawBitmapMesh(mBitmap, mMeshWidth, mMeshHeight,
895                mVertices, mColors, getPaint(renderer));
896    }
897
898    virtual void output(int level, uint32_t logFlags) const {
899        OP_LOG("Draw bitmap %p mesh %d x %d", mBitmap, mMeshWidth, mMeshHeight);
900    }
901
902    virtual const char* name() { return "DrawBitmapMesh"; }
903
904    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
905            const DeferredDisplayState& state) {
906        deferInfo.batchId = DeferredDisplayList::kOpBatch_Bitmap;
907    }
908
909private:
910    const SkBitmap* mBitmap;
911    int mMeshWidth;
912    int mMeshHeight;
913    const float* mVertices;
914    const int* mColors;
915};
916
917class DrawPatchOp : public DrawBoundedOp {
918public:
919    DrawPatchOp(const SkBitmap* bitmap, const Res_png_9patch* patch,
920            float left, float top, float right, float bottom, const SkPaint* paint)
921            : DrawBoundedOp(left, top, right, bottom, paint),
922            mBitmap(bitmap), mPatch(patch), mGenerationId(0), mMesh(NULL),
923            mAtlas(Caches::getInstance().assetAtlas) {
924        mEntry = mAtlas.getEntry(bitmap);
925        if (mEntry) {
926            mEntryGenerationId = mAtlas.getGenerationId();
927        }
928    };
929
930    AssetAtlas::Entry* getAtlasEntry() {
931        // The atlas entry is stale, let's get a new one
932        if (mEntry && mEntryGenerationId != mAtlas.getGenerationId()) {
933            mEntryGenerationId = mAtlas.getGenerationId();
934            mEntry = mAtlas.getEntry(mBitmap);
935        }
936        return mEntry;
937    }
938
939    const Patch* getMesh(OpenGLRenderer& renderer) {
940        if (!mMesh || renderer.getCaches().patchCache.getGenerationId() != mGenerationId) {
941            PatchCache& cache = renderer.getCaches().patchCache;
942            mMesh = cache.get(getAtlasEntry(), mBitmap->width(), mBitmap->height(),
943                    mLocalBounds.getWidth(), mLocalBounds.getHeight(), mPatch);
944            mGenerationId = cache.getGenerationId();
945        }
946        return mMesh;
947    }
948
949    /**
950     * This multi-draw operation builds an indexed mesh on the stack by copying
951     * and transforming the vertices of each 9-patch in the batch. This method
952     * is also responsible for dirtying the current layer, if any.
953     */
954    virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
955            const Vector<OpStatePair>& ops, const Rect& bounds) {
956        const DeferredDisplayState& firstState = *(ops[0].state);
957        renderer.restoreDisplayState(firstState, true); // restore all but the clip
958
959        // Batches will usually contain a small number of items so it's
960        // worth performing a first iteration to count the exact number
961        // of vertices we need in the new mesh
962        uint32_t totalVertices = 0;
963        for (unsigned int i = 0; i < ops.size(); i++) {
964            totalVertices += ((DrawPatchOp*) ops[i].op)->getMesh(renderer)->verticesCount;
965        }
966
967        const bool hasLayer = renderer.hasLayer();
968
969        uint32_t indexCount = 0;
970
971        TextureVertex vertices[totalVertices];
972        TextureVertex* vertex = &vertices[0];
973
974        // Create a mesh that contains the transformed vertices for all the
975        // 9-patch objects that are part of the batch. Note that onDefer()
976        // enforces ops drawn by this function to have a pure translate or
977        // identity matrix
978        for (unsigned int i = 0; i < ops.size(); i++) {
979            DrawPatchOp* patchOp = (DrawPatchOp*) ops[i].op;
980            const DeferredDisplayState* state = ops[i].state;
981            const Patch* opMesh = patchOp->getMesh(renderer);
982            uint32_t vertexCount = opMesh->verticesCount;
983            if (vertexCount == 0) continue;
984
985            // We use the bounds to know where to translate our vertices
986            // Using patchOp->state.mBounds wouldn't work because these
987            // bounds are clipped
988            const float tx = (int) floorf(state->mMatrix.getTranslateX() +
989                    patchOp->mLocalBounds.left + 0.5f);
990            const float ty = (int) floorf(state->mMatrix.getTranslateY() +
991                    patchOp->mLocalBounds.top + 0.5f);
992
993            // Copy & transform all the vertices for the current operation
994            TextureVertex* opVertices = opMesh->vertices;
995            for (uint32_t j = 0; j < vertexCount; j++, opVertices++) {
996                TextureVertex::set(vertex++,
997                        opVertices->x + tx, opVertices->y + ty,
998                        opVertices->u, opVertices->v);
999            }
1000
1001            // Dirty the current layer if possible. When the 9-patch does not
1002            // contain empty quads we can take a shortcut and simply set the
1003            // dirty rect to the object's bounds.
1004            if (hasLayer) {
1005                if (!opMesh->hasEmptyQuads) {
1006                    renderer.dirtyLayer(tx, ty,
1007                            tx + patchOp->mLocalBounds.getWidth(),
1008                            ty + patchOp->mLocalBounds.getHeight());
1009                } else {
1010                    const size_t count = opMesh->quads.size();
1011                    for (size_t i = 0; i < count; i++) {
1012                        const Rect& quadBounds = opMesh->quads[i];
1013                        const float x = tx + quadBounds.left;
1014                        const float y = ty + quadBounds.top;
1015                        renderer.dirtyLayer(x, y,
1016                                x + quadBounds.getWidth(), y + quadBounds.getHeight());
1017                    }
1018                }
1019            }
1020
1021            indexCount += opMesh->indexCount;
1022        }
1023
1024        return renderer.drawPatches(mBitmap, getAtlasEntry(),
1025                &vertices[0], indexCount, getPaint(renderer));
1026    }
1027
1028    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1029        // We're not calling the public variant of drawPatch() here
1030        // This method won't perform the quickReject() since we've already done it at this point
1031        return renderer.drawPatch(mBitmap, getMesh(renderer), getAtlasEntry(),
1032                mLocalBounds.left, mLocalBounds.top, mLocalBounds.right, mLocalBounds.bottom,
1033                getPaint(renderer));
1034    }
1035
1036    virtual void output(int level, uint32_t logFlags) const {
1037        OP_LOG("Draw patch "RECT_STRING, RECT_ARGS(mLocalBounds));
1038    }
1039
1040    virtual const char* name() { return "DrawPatch"; }
1041
1042    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
1043            const DeferredDisplayState& state) {
1044        deferInfo.batchId = DeferredDisplayList::kOpBatch_Patch;
1045        deferInfo.mergeId = getAtlasEntry() ? (mergeid_t) mEntry->getMergeId() : (mergeid_t) mBitmap;
1046        deferInfo.mergeable = state.mMatrix.isPureTranslate() &&
1047                OpenGLRenderer::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode;
1048        deferInfo.opaqueOverBounds = isOpaqueOverBounds(state) && mBitmap->isOpaque();
1049    }
1050
1051private:
1052    const SkBitmap* mBitmap;
1053    const Res_png_9patch* mPatch;
1054
1055    uint32_t mGenerationId;
1056    const Patch* mMesh;
1057
1058    const AssetAtlas& mAtlas;
1059    uint32_t mEntryGenerationId;
1060    AssetAtlas::Entry* mEntry;
1061};
1062
1063class DrawColorOp : public DrawOp {
1064public:
1065    DrawColorOp(int color, SkXfermode::Mode mode)
1066            : DrawOp(NULL), mColor(color), mMode(mode) {};
1067
1068    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1069        return renderer.drawColor(mColor, mMode);
1070    }
1071
1072    virtual void output(int level, uint32_t logFlags) const {
1073        OP_LOG("Draw color %#x, mode %d", mColor, mMode);
1074    }
1075
1076    virtual const char* name() { return "DrawColor"; }
1077
1078private:
1079    int mColor;
1080    SkXfermode::Mode mMode;
1081};
1082
1083class DrawStrokableOp : public DrawBoundedOp {
1084public:
1085    DrawStrokableOp(float left, float top, float right, float bottom, const SkPaint* paint)
1086            : DrawBoundedOp(left, top, right, bottom, paint) {};
1087
1088    bool getLocalBounds(const DrawModifiers& drawModifiers, Rect& localBounds) {
1089        localBounds.set(mLocalBounds);
1090        if (mPaint && mPaint->getStyle() != SkPaint::kFill_Style) {
1091            localBounds.outset(strokeWidthOutset());
1092        }
1093        return true;
1094    }
1095
1096    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
1097            const DeferredDisplayState& state) {
1098        if (mPaint->getPathEffect()) {
1099            deferInfo.batchId = DeferredDisplayList::kOpBatch_AlphaMaskTexture;
1100        } else {
1101            deferInfo.batchId = mPaint->isAntiAlias() ?
1102                    DeferredDisplayList::kOpBatch_AlphaVertices :
1103                    DeferredDisplayList::kOpBatch_Vertices;
1104        }
1105    }
1106};
1107
1108class DrawRectOp : public DrawStrokableOp {
1109public:
1110    DrawRectOp(float left, float top, float right, float bottom, const SkPaint* paint)
1111            : DrawStrokableOp(left, top, right, bottom, paint) {}
1112
1113    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1114        return renderer.drawRect(mLocalBounds.left, mLocalBounds.top,
1115                mLocalBounds.right, mLocalBounds.bottom, getPaint(renderer));
1116    }
1117
1118    virtual void output(int level, uint32_t logFlags) const {
1119        OP_LOG("Draw Rect "RECT_STRING, RECT_ARGS(mLocalBounds));
1120    }
1121
1122    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
1123            const DeferredDisplayState& state) {
1124        DrawStrokableOp::onDefer(renderer, deferInfo, state);
1125        deferInfo.opaqueOverBounds = isOpaqueOverBounds(state) &&
1126                mPaint->getStyle() == SkPaint::kFill_Style;
1127    }
1128
1129    virtual const char* name() { return "DrawRect"; }
1130};
1131
1132class DrawRectsOp : public DrawBoundedOp {
1133public:
1134    DrawRectsOp(const float* rects, int count, const SkPaint* paint)
1135            : DrawBoundedOp(rects, count, paint),
1136            mRects(rects), mCount(count) {}
1137
1138    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1139        return renderer.drawRects(mRects, mCount, getPaint(renderer));
1140    }
1141
1142    virtual void output(int level, uint32_t logFlags) const {
1143        OP_LOG("Draw Rects count %d", mCount);
1144    }
1145
1146    virtual const char* name() { return "DrawRects"; }
1147
1148    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
1149            const DeferredDisplayState& state) {
1150        deferInfo.batchId = DeferredDisplayList::kOpBatch_Vertices;
1151    }
1152
1153private:
1154    const float* mRects;
1155    int mCount;
1156};
1157
1158class DrawRoundRectOp : public DrawStrokableOp {
1159public:
1160    DrawRoundRectOp(float left, float top, float right, float bottom,
1161            float rx, float ry, const SkPaint* paint)
1162            : DrawStrokableOp(left, top, right, bottom, paint), mRx(rx), mRy(ry) {}
1163
1164    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1165        return renderer.drawRoundRect(mLocalBounds.left, mLocalBounds.top,
1166                mLocalBounds.right, mLocalBounds.bottom, mRx, mRy, getPaint(renderer));
1167    }
1168
1169    virtual void output(int level, uint32_t logFlags) const {
1170        OP_LOG("Draw RoundRect "RECT_STRING", rx %f, ry %f", RECT_ARGS(mLocalBounds), mRx, mRy);
1171    }
1172
1173    virtual const char* name() { return "DrawRoundRect"; }
1174
1175private:
1176    float mRx;
1177    float mRy;
1178};
1179
1180class DrawCircleOp : public DrawStrokableOp {
1181public:
1182    DrawCircleOp(float x, float y, float radius, const SkPaint* paint)
1183            : DrawStrokableOp(x - radius, y - radius, x + radius, y + radius, paint),
1184            mX(x), mY(y), mRadius(radius) {}
1185
1186    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1187        return renderer.drawCircle(mX, mY, mRadius, getPaint(renderer));
1188    }
1189
1190    virtual void output(int level, uint32_t logFlags) const {
1191        OP_LOG("Draw Circle x %f, y %f, r %f", mX, mY, mRadius);
1192    }
1193
1194    virtual const char* name() { return "DrawCircle"; }
1195
1196private:
1197    float mX;
1198    float mY;
1199    float mRadius;
1200};
1201
1202class DrawOvalOp : public DrawStrokableOp {
1203public:
1204    DrawOvalOp(float left, float top, float right, float bottom, const SkPaint* paint)
1205            : DrawStrokableOp(left, top, right, bottom, paint) {}
1206
1207    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1208        return renderer.drawOval(mLocalBounds.left, mLocalBounds.top,
1209                mLocalBounds.right, mLocalBounds.bottom, getPaint(renderer));
1210    }
1211
1212    virtual void output(int level, uint32_t logFlags) const {
1213        OP_LOG("Draw Oval "RECT_STRING, RECT_ARGS(mLocalBounds));
1214    }
1215
1216    virtual const char* name() { return "DrawOval"; }
1217};
1218
1219class DrawArcOp : public DrawStrokableOp {
1220public:
1221    DrawArcOp(float left, float top, float right, float bottom,
1222            float startAngle, float sweepAngle, bool useCenter, const SkPaint* paint)
1223            : DrawStrokableOp(left, top, right, bottom, paint),
1224            mStartAngle(startAngle), mSweepAngle(sweepAngle), mUseCenter(useCenter) {}
1225
1226    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1227        return renderer.drawArc(mLocalBounds.left, mLocalBounds.top,
1228                mLocalBounds.right, mLocalBounds.bottom,
1229                mStartAngle, mSweepAngle, mUseCenter, getPaint(renderer));
1230    }
1231
1232    virtual void output(int level, uint32_t logFlags) const {
1233        OP_LOG("Draw Arc "RECT_STRING", start %f, sweep %f, useCenter %d",
1234                RECT_ARGS(mLocalBounds), mStartAngle, mSweepAngle, mUseCenter);
1235    }
1236
1237    virtual const char* name() { return "DrawArc"; }
1238
1239private:
1240    float mStartAngle;
1241    float mSweepAngle;
1242    bool mUseCenter;
1243};
1244
1245class DrawPathOp : public DrawBoundedOp {
1246public:
1247    DrawPathOp(const SkPath* path, const SkPaint* paint)
1248            : DrawBoundedOp(paint), mPath(path) {
1249        float left, top, offset;
1250        uint32_t width, height;
1251        PathCache::computePathBounds(path, paint, left, top, offset, width, height);
1252        left -= offset;
1253        top -= offset;
1254        mLocalBounds.set(left, top, left + width, top + height);
1255    }
1256
1257    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1258        return renderer.drawPath(mPath, getPaint(renderer));
1259    }
1260
1261    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
1262            const DeferredDisplayState& state) {
1263        const SkPaint* paint = getPaint(renderer);
1264        renderer.getCaches().pathCache.precache(mPath, paint);
1265
1266        deferInfo.batchId = DeferredDisplayList::kOpBatch_AlphaMaskTexture;
1267    }
1268
1269    virtual void output(int level, uint32_t logFlags) const {
1270        OP_LOG("Draw Path %p in "RECT_STRING, mPath, RECT_ARGS(mLocalBounds));
1271    }
1272
1273    virtual const char* name() { return "DrawPath"; }
1274
1275private:
1276    const SkPath* mPath;
1277};
1278
1279class DrawLinesOp : public DrawBoundedOp {
1280public:
1281    DrawLinesOp(const float* points, int count, const SkPaint* paint)
1282            : DrawBoundedOp(points, count, paint),
1283            mPoints(points), mCount(count) {
1284        mLocalBounds.outset(strokeWidthOutset());
1285    }
1286
1287    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1288        return renderer.drawLines(mPoints, mCount, getPaint(renderer));
1289    }
1290
1291    virtual void output(int level, uint32_t logFlags) const {
1292        OP_LOG("Draw Lines count %d", mCount);
1293    }
1294
1295    virtual const char* name() { return "DrawLines"; }
1296
1297    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
1298            const DeferredDisplayState& state) {
1299        deferInfo.batchId = mPaint->isAntiAlias() ?
1300                DeferredDisplayList::kOpBatch_AlphaVertices :
1301                DeferredDisplayList::kOpBatch_Vertices;
1302    }
1303
1304protected:
1305    const float* mPoints;
1306    int mCount;
1307};
1308
1309class DrawPointsOp : public DrawLinesOp {
1310public:
1311    DrawPointsOp(const float* points, int count, const SkPaint* paint)
1312            : DrawLinesOp(points, count, paint) {}
1313
1314    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1315        return renderer.drawPoints(mPoints, mCount, getPaint(renderer));
1316    }
1317
1318    virtual void output(int level, uint32_t logFlags) const {
1319        OP_LOG("Draw Points count %d", mCount);
1320    }
1321
1322    virtual const char* name() { return "DrawPoints"; }
1323};
1324
1325class DrawSomeTextOp : public DrawOp {
1326public:
1327    DrawSomeTextOp(const char* text, int bytesCount, int count, const SkPaint* paint)
1328            : DrawOp(paint), mText(text), mBytesCount(bytesCount), mCount(count) {};
1329
1330    virtual void output(int level, uint32_t logFlags) const {
1331        OP_LOG("Draw some text, %d bytes", mBytesCount);
1332    }
1333
1334    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
1335            const DeferredDisplayState& state) {
1336        const SkPaint* paint = getPaint(renderer);
1337        FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(paint);
1338        fontRenderer.precache(paint, mText, mCount, mat4::identity());
1339
1340        deferInfo.batchId = mPaint->getColor() == 0xff000000 ?
1341                DeferredDisplayList::kOpBatch_Text :
1342                DeferredDisplayList::kOpBatch_ColorText;
1343    }
1344
1345protected:
1346    const char* mText;
1347    int mBytesCount;
1348    int mCount;
1349};
1350
1351class DrawTextOnPathOp : public DrawSomeTextOp {
1352public:
1353    DrawTextOnPathOp(const char* text, int bytesCount, int count,
1354            const SkPath* path, float hOffset, float vOffset, const SkPaint* paint)
1355            : DrawSomeTextOp(text, bytesCount, count, paint),
1356            mPath(path), mHOffset(hOffset), mVOffset(vOffset) {
1357        /* TODO: inherit from DrawBounded and init mLocalBounds */
1358    }
1359
1360    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1361        return renderer.drawTextOnPath(mText, mBytesCount, mCount, mPath,
1362                mHOffset, mVOffset, getPaint(renderer));
1363    }
1364
1365    virtual const char* name() { return "DrawTextOnPath"; }
1366
1367private:
1368    const SkPath* mPath;
1369    float mHOffset;
1370    float mVOffset;
1371};
1372
1373class DrawPosTextOp : public DrawSomeTextOp {
1374public:
1375    DrawPosTextOp(const char* text, int bytesCount, int count,
1376            const float* positions, const SkPaint* paint)
1377            : DrawSomeTextOp(text, bytesCount, count, paint), mPositions(positions) {
1378        /* TODO: inherit from DrawBounded and init mLocalBounds */
1379    }
1380
1381    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1382        return renderer.drawPosText(mText, mBytesCount, mCount, mPositions, getPaint(renderer));
1383    }
1384
1385    virtual const char* name() { return "DrawPosText"; }
1386
1387private:
1388    const float* mPositions;
1389};
1390
1391class DrawTextOp : public DrawBoundedOp {
1392public:
1393    DrawTextOp(const char* text, int bytesCount, int count, float x, float y,
1394            const float* positions, const SkPaint* paint, float totalAdvance, const Rect& bounds)
1395            : DrawBoundedOp(bounds, paint), mText(text), mBytesCount(bytesCount), mCount(count),
1396            mX(x), mY(y), mPositions(positions), mTotalAdvance(totalAdvance) {
1397        memset(&mPrecacheTransform.data[0], 0xff, 16 * sizeof(float));
1398    }
1399
1400    virtual void onDefer(OpenGLRenderer& renderer, DeferInfo& deferInfo,
1401            const DeferredDisplayState& state) {
1402        const SkPaint* paint = getPaint(renderer);
1403        FontRenderer& fontRenderer = renderer.getCaches().fontRenderer->getFontRenderer(paint);
1404        const mat4& transform = renderer.findBestFontTransform(state.mMatrix);
1405        if (mPrecacheTransform != transform) {
1406            fontRenderer.precache(paint, mText, mCount, transform);
1407            mPrecacheTransform = transform;
1408        }
1409        deferInfo.batchId = mPaint->getColor() == 0xff000000 ?
1410                DeferredDisplayList::kOpBatch_Text :
1411                DeferredDisplayList::kOpBatch_ColorText;
1412
1413        deferInfo.mergeId = (mergeid_t)mPaint->getColor();
1414
1415        // don't merge decorated text - the decorations won't draw in order
1416        bool noDecorations = !(mPaint->getFlags() & (SkPaint::kUnderlineText_Flag |
1417                        SkPaint::kStrikeThruText_Flag));
1418        deferInfo.mergeable = state.mMatrix.isPureTranslate() && noDecorations &&
1419                OpenGLRenderer::getXfermodeDirect(mPaint) == SkXfermode::kSrcOver_Mode;
1420    }
1421
1422    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1423        Rect bounds;
1424        getLocalBounds(renderer.getDrawModifiers(), bounds);
1425        return renderer.drawText(mText, mBytesCount, mCount, mX, mY,
1426                mPositions, getPaint(renderer), mTotalAdvance, bounds);
1427    }
1428
1429    virtual status_t multiDraw(OpenGLRenderer& renderer, Rect& dirty,
1430            const Vector<OpStatePair>& ops, const Rect& bounds) {
1431        status_t status = DrawGlInfo::kStatusDone;
1432        for (unsigned int i = 0; i < ops.size(); i++) {
1433            const DeferredDisplayState& state = *(ops[i].state);
1434            DrawOpMode drawOpMode = (i == ops.size() - 1) ? kDrawOpMode_Flush : kDrawOpMode_Defer;
1435            renderer.restoreDisplayState(state, true); // restore all but the clip
1436
1437            DrawTextOp& op = *((DrawTextOp*)ops[i].op);
1438            // quickReject() will not occure in drawText() so we can use mLocalBounds
1439            // directly, we do not need to account for shadow by calling getLocalBounds()
1440            status |= renderer.drawText(op.mText, op.mBytesCount, op.mCount, op.mX, op.mY,
1441                    op.mPositions, op.getPaint(renderer), op.mTotalAdvance, op.mLocalBounds,
1442                    drawOpMode);
1443        }
1444        return status;
1445    }
1446
1447    virtual void output(int level, uint32_t logFlags) const {
1448        OP_LOG("Draw Text of count %d, bytes %d", mCount, mBytesCount);
1449    }
1450
1451    virtual const char* name() { return "DrawText"; }
1452
1453private:
1454    const char* mText;
1455    int mBytesCount;
1456    int mCount;
1457    float mX;
1458    float mY;
1459    const float* mPositions;
1460    float mTotalAdvance;
1461    mat4 mPrecacheTransform;
1462};
1463
1464///////////////////////////////////////////////////////////////////////////////
1465// SPECIAL DRAW OPERATIONS
1466///////////////////////////////////////////////////////////////////////////////
1467
1468class DrawFunctorOp : public DrawOp {
1469public:
1470    DrawFunctorOp(Functor* functor)
1471            : DrawOp(NULL), mFunctor(functor) {}
1472
1473    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1474        renderer.startMark("GL functor");
1475        status_t ret = renderer.callDrawGLFunction(mFunctor, dirty);
1476        renderer.endMark();
1477        return ret;
1478    }
1479
1480    virtual void output(int level, uint32_t logFlags) const {
1481        OP_LOG("Draw Functor %p", mFunctor);
1482    }
1483
1484    virtual const char* name() { return "DrawFunctor"; }
1485
1486private:
1487    Functor* mFunctor;
1488};
1489
1490class DrawDisplayListOp : public DrawBoundedOp {
1491    friend class DisplayList; // grant DisplayList access to info of child
1492public:
1493    DrawDisplayListOp(DisplayList* displayList, int flags, const mat4& transformFromParent)
1494            : DrawBoundedOp(0, 0, displayList->getWidth(), displayList->getHeight(), 0),
1495            mDisplayList(displayList), mFlags(flags), mTransformFromParent(transformFromParent) {}
1496
1497    virtual void defer(DeferStateStruct& deferStruct, int saveCount, int level,
1498            bool useQuickReject) {
1499        if (mDisplayList && mDisplayList->isRenderable() && !mSkipInOrderDraw) {
1500            mDisplayList->defer(deferStruct, level + 1);
1501        }
1502    }
1503    virtual void replay(ReplayStateStruct& replayStruct, int saveCount, int level,
1504            bool useQuickReject) {
1505        if (mDisplayList && mDisplayList->isRenderable() && !mSkipInOrderDraw) {
1506            mDisplayList->replay(replayStruct, level + 1);
1507        }
1508    }
1509
1510    // NOT USED since replay() is overridden
1511    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1512        return DrawGlInfo::kStatusDone;
1513    }
1514
1515    virtual void output(int level, uint32_t logFlags) const {
1516        OP_LOG("Draw Display List %p, flags %#x", mDisplayList, mFlags);
1517        if (mDisplayList && (logFlags & kOpLogFlag_Recurse)) {
1518            mDisplayList->output(level + 1);
1519        }
1520    }
1521
1522    virtual const char* name() { return "DrawDisplayList"; }
1523
1524private:
1525    DisplayList* mDisplayList;
1526    const int mFlags;
1527
1528    ///////////////////////////
1529    // Properties below are used by DisplayList::computeOrderingImpl() and iterate()
1530    ///////////////////////////
1531    /**
1532     * Records transform vs parent, used for computing total transform without rerunning DL contents
1533     */
1534    const mat4 mTransformFromParent;
1535
1536    /**
1537     * Holds the transformation between the 3d root OR projection surface ViewGroup and this
1538     * DisplayList drawing instance. Represents any translations / transformations done within the
1539     * drawing of the compositing ancestor ViewGroup's draw, before the draw of the View represented
1540     * by this DisplayList draw instance.
1541     *
1542     * Note: doesn't include any transformation recorded within the DisplayList and its properties.
1543     */
1544    mat4 mTransformFromCompositingAncestor;
1545    bool mSkipInOrderDraw;
1546};
1547
1548/**
1549 * Not a canvas operation, used only by 3d / z ordering logic in DisplayList::iterate()
1550 */
1551class DrawShadowOp : public DrawOp {
1552public:
1553    DrawShadowOp(const mat4& transform, float alpha, const SkPath* outline,
1554            float fallbackWidth, float fallbackHeight)
1555            : DrawOp(NULL), mTransform(transform), mAlpha(alpha), mOutline(outline),
1556            mFallbackWidth(fallbackWidth), mFallbackHeight(fallbackHeight) {}
1557
1558    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1559        if (!mOutline->isEmpty()) {
1560            return renderer.drawShadow(mTransform, mAlpha, mOutline);
1561        }
1562
1563        SkPath fakeOutline;
1564        fakeOutline.addRect(0, 0, mFallbackWidth, mFallbackHeight);
1565        return renderer.drawShadow(mTransform, mAlpha, &fakeOutline);
1566    }
1567
1568    virtual void output(int level, uint32_t logFlags) const {
1569        OP_LOG("DrawShadow of outline %p", mOutline);
1570    }
1571
1572    virtual const char* name() { return "DrawShadow"; }
1573
1574private:
1575    const mat4 mTransform;
1576    const float mAlpha;
1577    const SkPath* mOutline;
1578    const float mFallbackWidth;
1579    const float mFallbackHeight;
1580};
1581
1582class DrawLayerOp : public DrawOp {
1583public:
1584    DrawLayerOp(Layer* layer, float x, float y)
1585            : DrawOp(NULL), mLayer(layer), mX(x), mY(y) {}
1586
1587    virtual status_t applyDraw(OpenGLRenderer& renderer, Rect& dirty) {
1588        return renderer.drawLayer(mLayer, mX, mY);
1589    }
1590
1591    virtual void output(int level, uint32_t logFlags) const {
1592        OP_LOG("Draw Layer %p at %f %f", mLayer, mX, mY);
1593    }
1594
1595    virtual const char* name() { return "DrawLayer"; }
1596
1597private:
1598    Layer* mLayer;
1599    float mX;
1600    float mY;
1601};
1602
1603}; // namespace uirenderer
1604}; // namespace android
1605
1606#endif // ANDROID_HWUI_DISPLAY_OPERATION_H
1607