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. ~DisplayListOp()63 virtual ~DisplayListOp() { LOG_ALWAYS_FATAL("Destructor not supported"); } delete(void * ptr)64 static void operator delete(void* ptr) { LOG_ALWAYS_FATAL("delete not supported"); } 65 static void* operator new(size_t size) = delete; /** PURPOSELY OMITTED **/ new(size_t size,LinearAllocator & allocator)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: defer(DeferStateStruct & deferStruct,int saveCount,int level,bool useQuickReject)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 */ replay(ReplayStateStruct & replayStruct,int saveCount,int level,bool useQuickReject)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: DrawOp(const SkPaint * paint)111 DrawOp(const SkPaint* paint) 112 : mPaint(paint), mQuickRejected(false) {} 113 defer(DeferStateStruct & deferStruct,int saveCount,int level,bool useQuickReject)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 replay(ReplayStateStruct & replayStruct,int saveCount,int level,bool useQuickReject)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 */ multiDraw(OpenGLRenderer & renderer,Rect & dirty,const Vector<OpStatePair> & ops,const Rect & bounds)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 */ onDefer(OpenGLRenderer & renderer,DeferInfo & deferInfo,const DeferredDisplayState & state)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 */ getLocalBounds(Rect & localBounds)167 virtual bool getLocalBounds(Rect& localBounds) { 168 return false; 169 } 170 171 // TODO: better refine localbounds usage setQuickRejected(bool quickRejected)172 void setQuickRejected(bool quickRejected) { mQuickRejected = quickRejected; } getQuickRejected()173 bool getQuickRejected() { return mQuickRejected; } 174 getPaintAlpha()175 inline int getPaintAlpha() const { 176 return OpenGLRenderer::getAlphaDirect(mPaint); 177 } 178 hasTextShadow()179 virtual bool hasTextShadow() const { 180 return false; 181 } 182 strokeWidthOutset()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 isOpaqueOverBounds(const DeferredDisplayState & state)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: DrawBoundedOp(float left,float top,float right,float bottom,const SkPaint * paint)228 DrawBoundedOp(float left, float top, float right, float bottom, const SkPaint* paint) 229 : DrawOp(paint), mLocalBounds(left, top, right, bottom) {} 230 DrawBoundedOp(const Rect & localBounds,const SkPaint * paint)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) DrawBoundedOp(const float * points,int count,const SkPaint * paint)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 DrawBoundedOp(const SkPaint * paint)248 DrawBoundedOp(const SkPaint* paint): DrawOp(paint) { } 249 getLocalBounds(Rect & localBounds)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: SaveOp(int flags)273 SaveOp(int flags) 274 : mFlags(flags) {} 275 defer(DeferStateStruct & deferStruct,int saveCount,int level,bool useQuickReject)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 applyState(OpenGLRenderer & renderer,int saveCount)282 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { 283 renderer.save(mFlags); 284 } 285 output(int level,uint32_t logFlags)286 virtual void output(int level, uint32_t logFlags) const override { 287 OP_LOG("Save flags %x", mFlags); 288 } 289 name()290 virtual const char* name() override { return "Save"; } 291 getFlags()292 int getFlags() const { return mFlags; } 293 private: 294 int mFlags; 295 }; 296 297 class RestoreToCountOp : public StateOp { 298 public: RestoreToCountOp(int count)299 RestoreToCountOp(int count) 300 : mCount(count) {} 301 defer(DeferStateStruct & deferStruct,int saveCount,int level,bool useQuickReject)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 applyState(OpenGLRenderer & renderer,int saveCount)309 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { 310 renderer.restoreToCount(saveCount + mCount); 311 } 312 output(int level,uint32_t logFlags)313 virtual void output(int level, uint32_t logFlags) const override { 314 OP_LOG("Restore to count %d", mCount); 315 } 316 name()317 virtual const char* name() override { return "RestoreToCount"; } 318 319 private: 320 int mCount; 321 }; 322 323 class SaveLayerOp : public StateOp { 324 public: SaveLayerOp(float left,float top,float right,float bottom,int alpha,int flags)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 SaveLayerOp(float left,float top,float right,float bottom,const SkPaint * paint,int flags)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 defer(DeferStateStruct & deferStruct,int saveCount,int level,bool useQuickReject)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 applyState(OpenGLRenderer & renderer,int saveCount)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 output(int level,uint32_t logFlags)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 name()362 virtual const char* name() override { 363 return isSaveLayerAlpha() ? "SaveLayerAlpha" : "SaveLayer"; 364 } 365 getFlags()366 int getFlags() { return mFlags; } 367 368 // Called to make SaveLayerOp clip to the provided mask when drawing back/restored setMask(const SkPath * convexMask)369 void setMask(const SkPath* convexMask) { 370 mConvexMask = convexMask; 371 } 372 373 private: isSaveLayerAlpha()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: TranslateOp(float dx,float dy)392 TranslateOp(float dx, float dy) 393 : mDx(dx), mDy(dy) {} 394 applyState(OpenGLRenderer & renderer,int saveCount)395 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { 396 renderer.translate(mDx, mDy); 397 } 398 output(int level,uint32_t logFlags)399 virtual void output(int level, uint32_t logFlags) const override { 400 OP_LOG("Translate by %f %f", mDx, mDy); 401 } 402 name()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: RotateOp(float degrees)412 RotateOp(float degrees) 413 : mDegrees(degrees) {} 414 applyState(OpenGLRenderer & renderer,int saveCount)415 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { 416 renderer.rotate(mDegrees); 417 } 418 output(int level,uint32_t logFlags)419 virtual void output(int level, uint32_t logFlags) const override { 420 OP_LOG("Rotate by %f degrees", mDegrees); 421 } 422 name()423 virtual const char* name() override { return "Rotate"; } 424 425 private: 426 float mDegrees; 427 }; 428 429 class ScaleOp : public StateOp { 430 public: ScaleOp(float sx,float sy)431 ScaleOp(float sx, float sy) 432 : mSx(sx), mSy(sy) {} 433 applyState(OpenGLRenderer & renderer,int saveCount)434 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { 435 renderer.scale(mSx, mSy); 436 } 437 output(int level,uint32_t logFlags)438 virtual void output(int level, uint32_t logFlags) const override { 439 OP_LOG("Scale by %f %f", mSx, mSy); 440 } 441 name()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: SkewOp(float sx,float sy)451 SkewOp(float sx, float sy) 452 : mSx(sx), mSy(sy) {} 453 applyState(OpenGLRenderer & renderer,int saveCount)454 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { 455 renderer.skew(mSx, mSy); 456 } 457 output(int level,uint32_t logFlags)458 virtual void output(int level, uint32_t logFlags) const override { 459 OP_LOG("Skew by %f %f", mSx, mSy); 460 } 461 name()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: SetMatrixOp(const SkMatrix & matrix)471 SetMatrixOp(const SkMatrix& matrix) 472 : mMatrix(matrix) {} 473 applyState(OpenGLRenderer & renderer,int saveCount)474 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { 475 renderer.setMatrix(mMatrix); 476 } 477 output(int level,uint32_t logFlags)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 name()486 virtual const char* name() override { return "SetMatrix"; } 487 488 private: 489 const SkMatrix mMatrix; 490 }; 491 492 class SetLocalMatrixOp : public StateOp { 493 public: SetLocalMatrixOp(const SkMatrix & matrix)494 SetLocalMatrixOp(const SkMatrix& matrix) 495 : mMatrix(matrix) {} 496 applyState(OpenGLRenderer & renderer,int saveCount)497 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { 498 renderer.setLocalMatrix(mMatrix); 499 } 500 output(int level,uint32_t logFlags)501 virtual void output(int level, uint32_t logFlags) const override { 502 OP_LOG("SetLocalMatrix " SK_MATRIX_STRING, SK_MATRIX_ARGS(&mMatrix)); 503 } 504 name()505 virtual const char* name() override { return "SetLocalMatrix"; } 506 507 private: 508 const SkMatrix mMatrix; 509 }; 510 511 class ConcatMatrixOp : public StateOp { 512 public: ConcatMatrixOp(const SkMatrix & matrix)513 ConcatMatrixOp(const SkMatrix& matrix) 514 : mMatrix(matrix) {} 515 applyState(OpenGLRenderer & renderer,int saveCount)516 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { 517 renderer.concatMatrix(mMatrix); 518 } 519 output(int level,uint32_t logFlags)520 virtual void output(int level, uint32_t logFlags) const override { 521 OP_LOG("ConcatMatrix " SK_MATRIX_STRING, SK_MATRIX_ARGS(&mMatrix)); 522 } 523 name()524 virtual const char* name() override { return "ConcatMatrix"; } 525 526 private: 527 const SkMatrix mMatrix; 528 }; 529 530 class ClipOp : public StateOp { 531 public: ClipOp(SkRegion::Op op)532 ClipOp(SkRegion::Op op) : mOp(op) {} 533 defer(DeferStateStruct & deferStruct,int saveCount,int level,bool useQuickReject)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 canCauseComplexClip()543 bool canCauseComplexClip() { 544 return ((mOp != SkRegion::kIntersect_Op) && (mOp != SkRegion::kReplace_Op)) || !isRect(); 545 } 546 547 protected: isRect()548 virtual bool isRect() { return false; } 549 550 SkRegion::Op mOp; 551 }; 552 553 class ClipRectOp : public ClipOp { 554 public: ClipRectOp(float left,float top,float right,float bottom,SkRegion::Op op)555 ClipRectOp(float left, float top, float right, float bottom, SkRegion::Op op) 556 : ClipOp(op), mArea(left, top, right, bottom) {} 557 applyState(OpenGLRenderer & renderer,int saveCount)558 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { 559 renderer.clipRect(mArea.left, mArea.top, mArea.right, mArea.bottom, mOp); 560 } 561 output(int level,uint32_t logFlags)562 virtual void output(int level, uint32_t logFlags) const override { 563 OP_LOG("ClipRect " RECT_STRING, RECT_ARGS(mArea)); 564 } 565 name()566 virtual const char* name() override { return "ClipRect"; } 567 568 protected: isRect()569 virtual bool isRect() override { return true; } 570 571 private: 572 Rect mArea; 573 }; 574 575 class ClipPathOp : public ClipOp { 576 public: ClipPathOp(const SkPath * path,SkRegion::Op op)577 ClipPathOp(const SkPath* path, SkRegion::Op op) 578 : ClipOp(op), mPath(path) {} 579 applyState(OpenGLRenderer & renderer,int saveCount)580 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { 581 renderer.clipPath(mPath, mOp); 582 } 583 output(int level,uint32_t logFlags)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 name()590 virtual const char* name() override { return "ClipPath"; } 591 592 private: 593 const SkPath* mPath; 594 }; 595 596 class ClipRegionOp : public ClipOp { 597 public: ClipRegionOp(const SkRegion * region,SkRegion::Op op)598 ClipRegionOp(const SkRegion* region, SkRegion::Op op) 599 : ClipOp(op), mRegion(region) {} 600 applyState(OpenGLRenderer & renderer,int saveCount)601 virtual void applyState(OpenGLRenderer& renderer, int saveCount) const override { 602 renderer.clipRegion(mRegion, mOp); 603 } 604 output(int level,uint32_t logFlags)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 name()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: DrawBitmapOp(const SkBitmap * bitmap,const SkPaint * paint)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 applyDraw(OpenGLRenderer & renderer,Rect & dirty)629 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { 630 renderer.drawBitmap(mBitmap, mPaint); 631 } 632 getAtlasEntry(OpenGLRenderer & renderer)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 */ multiDraw(OpenGLRenderer & renderer,Rect & dirty,const Vector<OpStatePair> & ops,const Rect & bounds)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 output(int level,uint32_t logFlags)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 name()697 virtual const char* name() override { return "DrawBitmap"; } 698 onDefer(OpenGLRenderer & renderer,DeferInfo & deferInfo,const DeferredDisplayState & state)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 uvMap(OpenGLRenderer & renderer,Rect & texCoords)715 void uvMap(OpenGLRenderer& renderer, Rect& texCoords) { 716 if (getAtlasEntry(renderer)) { 717 mEntry->uvMapper.map(texCoords); 718 } 719 } 720 bitmap()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: DrawBitmapRectOp(const SkBitmap * bitmap,float srcLeft,float srcTop,float srcRight,float srcBottom,float dstLeft,float dstTop,float dstRight,float dstBottom,const SkPaint * paint)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 applyDraw(OpenGLRenderer & renderer,Rect & dirty)736 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { 737 renderer.drawBitmap(mBitmap, mSrc, mLocalBounds, mPaint); 738 } 739 output(int level,uint32_t logFlags)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 name()745 virtual const char* name() override { return "DrawBitmapRect"; } 746 onDefer(OpenGLRenderer & renderer,DeferInfo & deferInfo,const DeferredDisplayState & state)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: DrawBitmapMeshOp(const SkBitmap * bitmap,int meshWidth,int meshHeight,const float * vertices,const int * colors,const SkPaint * paint)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 applyDraw(OpenGLRenderer & renderer,Rect & dirty)765 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { 766 renderer.drawBitmapMesh(mBitmap, mMeshWidth, mMeshHeight, 767 mVertices, mColors, mPaint); 768 } 769 output(int level,uint32_t logFlags)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 name()774 virtual const char* name() override { return "DrawBitmapMesh"; } 775 onDefer(OpenGLRenderer & renderer,DeferInfo & deferInfo,const DeferredDisplayState & state)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: DrawPatchOp(const SkBitmap * bitmap,const Res_png_9patch * patch,float left,float top,float right,float bottom,const SkPaint * paint)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 getAtlasEntry(OpenGLRenderer & renderer)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 getMesh(OpenGLRenderer & renderer)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 */ multiDraw(OpenGLRenderer & renderer,Rect & dirty,const Vector<OpStatePair> & ops,const Rect & bounds)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 applyDraw(OpenGLRenderer & renderer,Rect & dirty)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 output(int level,uint32_t logFlags)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 name()908 virtual const char* name() override { return "DrawPatch"; } 909 onDefer(OpenGLRenderer & renderer,DeferInfo & deferInfo,const DeferredDisplayState & state)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: DrawColorOp(int color,SkXfermode::Mode mode)932 DrawColorOp(int color, SkXfermode::Mode mode) 933 : DrawOp(nullptr), mColor(color), mMode(mode) {}; 934 applyDraw(OpenGLRenderer & renderer,Rect & dirty)935 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { 936 renderer.drawColor(mColor, mMode); 937 } 938 output(int level,uint32_t logFlags)939 virtual void output(int level, uint32_t logFlags) const override { 940 OP_LOG("Draw color %#x, mode %d", mColor, mMode); 941 } 942 name()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: DrawStrokableOp(float left,float top,float right,float bottom,const SkPaint * paint)952 DrawStrokableOp(float left, float top, float right, float bottom, const SkPaint* paint) 953 : DrawBoundedOp(left, top, right, bottom, paint) {}; DrawStrokableOp(const Rect & localBounds,const SkPaint * paint)954 DrawStrokableOp(const Rect& localBounds, const SkPaint* paint) 955 : DrawBoundedOp(localBounds, paint) {}; 956 getLocalBounds(Rect & localBounds)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 onDefer(OpenGLRenderer & renderer,DeferInfo & deferInfo,const DeferredDisplayState & state)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: DrawRectOp(float left,float top,float right,float bottom,const SkPaint * paint)979 DrawRectOp(float left, float top, float right, float bottom, const SkPaint* paint) 980 : DrawStrokableOp(left, top, right, bottom, paint) {} 981 applyDraw(OpenGLRenderer & renderer,Rect & dirty)982 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { 983 renderer.drawRect(mLocalBounds.left, mLocalBounds.top, 984 mLocalBounds.right, mLocalBounds.bottom, mPaint); 985 } 986 output(int level,uint32_t logFlags)987 virtual void output(int level, uint32_t logFlags) const override { 988 OP_LOG("Draw Rect " RECT_STRING, RECT_ARGS(mLocalBounds)); 989 } 990 onDefer(OpenGLRenderer & renderer,DeferInfo & deferInfo,const DeferredDisplayState & state)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 name()998 virtual const char* name() override { return "DrawRect"; } 999 }; 1000 1001 class DrawRectsOp : public DrawBoundedOp { 1002 public: DrawRectsOp(const float * rects,int count,const SkPaint * paint)1003 DrawRectsOp(const float* rects, int count, const SkPaint* paint) 1004 : DrawBoundedOp(rects, count, paint), 1005 mRects(rects), mCount(count) {} 1006 applyDraw(OpenGLRenderer & renderer,Rect & dirty)1007 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { 1008 renderer.drawRects(mRects, mCount, mPaint); 1009 } 1010 output(int level,uint32_t logFlags)1011 virtual void output(int level, uint32_t logFlags) const override { 1012 OP_LOG("Draw Rects count %d", mCount); 1013 } 1014 name()1015 virtual const char* name() override { return "DrawRects"; } 1016 onDefer(OpenGLRenderer & renderer,DeferInfo & deferInfo,const DeferredDisplayState & state)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: DrawRoundRectOp(float left,float top,float right,float bottom,float rx,float ry,const SkPaint * paint)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 applyDraw(OpenGLRenderer & renderer,Rect & dirty)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 output(int level,uint32_t logFlags)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 onDefer(OpenGLRenderer & renderer,DeferInfo & deferInfo,const DeferredDisplayState & state)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 name()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: DrawRoundRectPropsOp(float * left,float * top,float * right,float * bottom,float * rx,float * ry,const SkPaint * paint)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 applyDraw(OpenGLRenderer & renderer,Rect & dirty)1065 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { 1066 renderer.drawRoundRect(*mLeft, *mTop, *mRight, *mBottom, 1067 *mRx, *mRy, mPaint); 1068 } 1069 output(int level,uint32_t logFlags)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 name()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: DrawCircleOp(float x,float y,float radius,const SkPaint * paint)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 applyDraw(OpenGLRenderer & renderer,Rect & dirty)1092 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { 1093 renderer.drawCircle(mX, mY, mRadius, mPaint); 1094 } 1095 output(int level,uint32_t logFlags)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 name()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: DrawCirclePropsOp(float * x,float * y,float * radius,const SkPaint * paint)1110 DrawCirclePropsOp(float* x, float* y, float* radius, const SkPaint* paint) 1111 : DrawOp(paint), mX(x), mY(y), mRadius(radius) {} 1112 applyDraw(OpenGLRenderer & renderer,Rect & dirty)1113 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { 1114 renderer.drawCircle(*mX, *mY, *mRadius, mPaint); 1115 } 1116 output(int level,uint32_t logFlags)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 name()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: DrawOvalOp(float left,float top,float right,float bottom,const SkPaint * paint)1131 DrawOvalOp(float left, float top, float right, float bottom, const SkPaint* paint) 1132 : DrawStrokableOp(left, top, right, bottom, paint) {} 1133 applyDraw(OpenGLRenderer & renderer,Rect & dirty)1134 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { 1135 renderer.drawOval(mLocalBounds.left, mLocalBounds.top, 1136 mLocalBounds.right, mLocalBounds.bottom, mPaint); 1137 } 1138 output(int level,uint32_t logFlags)1139 virtual void output(int level, uint32_t logFlags) const override { 1140 OP_LOG("Draw Oval " RECT_STRING, RECT_ARGS(mLocalBounds)); 1141 } 1142 name()1143 virtual const char* name() override { return "DrawOval"; } 1144 }; 1145 1146 class DrawArcOp : public DrawStrokableOp { 1147 public: DrawArcOp(float left,float top,float right,float bottom,float startAngle,float sweepAngle,bool useCenter,const SkPaint * paint)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 applyDraw(OpenGLRenderer & renderer,Rect & dirty)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 output(int level,uint32_t logFlags)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 name()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: DrawPathOp(const SkPath * path,const SkPaint * paint)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 applyDraw(OpenGLRenderer & renderer,Rect & dirty)1184 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { 1185 renderer.drawPath(mPath, mPaint); 1186 } 1187 onDefer(OpenGLRenderer & renderer,DeferInfo & deferInfo,const DeferredDisplayState & state)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 output(int level,uint32_t logFlags)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 name()1199 virtual const char* name() override { return "DrawPath"; } 1200 1201 private: 1202 const SkPath* mPath; 1203 }; 1204 1205 class DrawLinesOp : public DrawBoundedOp { 1206 public: DrawLinesOp(const float * points,int count,const SkPaint * paint)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 applyDraw(OpenGLRenderer & renderer,Rect & dirty)1213 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { 1214 renderer.drawLines(mPoints, mCount, mPaint); 1215 } 1216 output(int level,uint32_t logFlags)1217 virtual void output(int level, uint32_t logFlags) const override { 1218 OP_LOG("Draw Lines count %d", mCount); 1219 } 1220 name()1221 virtual const char* name() override { return "DrawLines"; } 1222 onDefer(OpenGLRenderer & renderer,DeferInfo & deferInfo,const DeferredDisplayState & state)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: DrawPointsOp(const float * points,int count,const SkPaint * paint)1237 DrawPointsOp(const float* points, int count, const SkPaint* paint) 1238 : DrawLinesOp(points, count, paint) {} 1239 applyDraw(OpenGLRenderer & renderer,Rect & dirty)1240 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { 1241 renderer.drawPoints(mPoints, mCount, mPaint); 1242 } 1243 output(int level,uint32_t logFlags)1244 virtual void output(int level, uint32_t logFlags) const override { 1245 OP_LOG("Draw Points count %d", mCount); 1246 } 1247 name()1248 virtual const char* name() override { return "DrawPoints"; } 1249 }; 1250 1251 class DrawSomeTextOp : public DrawOp { 1252 public: DrawSomeTextOp(const char * text,int bytesCount,int count,const SkPaint * paint)1253 DrawSomeTextOp(const char* text, int bytesCount, int count, const SkPaint* paint) 1254 : DrawOp(paint), mText(text), mBytesCount(bytesCount), mCount(count) {}; 1255 output(int level,uint32_t logFlags)1256 virtual void output(int level, uint32_t logFlags) const override { 1257 OP_LOG("Draw some text, %d bytes", mBytesCount); 1258 } 1259 hasTextShadow()1260 virtual bool hasTextShadow() const override { 1261 return OpenGLRenderer::hasTextShadow(mPaint); 1262 } 1263 onDefer(OpenGLRenderer & renderer,DeferInfo & deferInfo,const DeferredDisplayState & state)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: DrawTextOnPathOp(const char * text,int bytesCount,int count,const SkPath * path,float hOffset,float vOffset,const SkPaint * paint)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 applyDraw(OpenGLRenderer & renderer,Rect & dirty)1289 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { 1290 renderer.drawTextOnPath(mText, mBytesCount, mCount, mPath, 1291 mHOffset, mVOffset, mPaint); 1292 } 1293 name()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: DrawPosTextOp(const char * text,int bytesCount,int count,const float * positions,const SkPaint * paint)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 applyDraw(OpenGLRenderer & renderer,Rect & dirty)1310 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { 1311 renderer.drawPosText(mText, mBytesCount, mCount, mPositions, mPaint); 1312 } 1313 name()1314 virtual const char* name() override { return "DrawPosText"; } 1315 1316 private: 1317 const float* mPositions; 1318 }; 1319 1320 class DrawTextOp : public DrawStrokableOp { 1321 public: DrawTextOp(const char * text,int bytesCount,int count,float x,float y,const float * positions,const SkPaint * paint,float totalAdvance,const Rect & bounds)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 onDefer(OpenGLRenderer & renderer,DeferInfo & deferInfo,const DeferredDisplayState & state)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 applyDraw(OpenGLRenderer & renderer,Rect & dirty)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 multiDraw(OpenGLRenderer & renderer,Rect & dirty,const Vector<OpStatePair> & ops,const Rect & bounds)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 output(int level,uint32_t logFlags)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 name()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: DrawFunctorOp(Functor * functor)1399 DrawFunctorOp(Functor* functor) 1400 : DrawOp(nullptr), mFunctor(functor) {} 1401 applyDraw(OpenGLRenderer & renderer,Rect & dirty)1402 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { 1403 renderer.startMark("GL functor"); 1404 renderer.callDrawGLFunction(mFunctor, dirty); 1405 renderer.endMark(); 1406 } 1407 output(int level,uint32_t logFlags)1408 virtual void output(int level, uint32_t logFlags) const override { 1409 OP_LOG("Draw Functor %p", mFunctor); 1410 } 1411 name()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: DrawRenderNodeOp(RenderNode * renderNode,const mat4 & transformFromParent,bool clipIsSimple)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 defer(DeferStateStruct & deferStruct,int saveCount,int level,bool useQuickReject)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 replay(ReplayStateStruct & replayStruct,int saveCount,int level,bool useQuickReject)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 applyDraw(OpenGLRenderer & renderer,Rect & dirty)1443 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { 1444 LOG_ALWAYS_FATAL("should not be called, because replay() is overridden"); 1445 } 1446 output(int level,uint32_t logFlags)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 name()1454 virtual const char* name() override { return "DrawRenderNode"; } 1455 renderNode()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: DrawShadowOp(const mat4 & transformXY,const mat4 & transformZ,float casterAlpha,const SkPath * casterOutline)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 onDefer(OpenGLRenderer & renderer,DeferInfo & deferInfo,const DeferredDisplayState & state)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 applyDraw(OpenGLRenderer & renderer,Rect & dirty)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 output(int level,uint32_t logFlags)1527 virtual void output(int level, uint32_t logFlags) const override { 1528 OP_LOGS("DrawShadow"); 1529 } 1530 name()1531 virtual const char* name() override { return "DrawShadow"; } 1532 1533 private: isCasterOpaque()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: DrawLayerOp(Layer * layer,float x,float y)1544 DrawLayerOp(Layer* layer, float x, float y) 1545 : DrawOp(nullptr), mLayer(layer), mX(x), mY(y) {} 1546 applyDraw(OpenGLRenderer & renderer,Rect & dirty)1547 virtual void applyDraw(OpenGLRenderer& renderer, Rect& dirty) override { 1548 renderer.drawLayer(mLayer, mX, mY); 1549 } 1550 output(int level,uint32_t logFlags)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 name()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