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