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