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