• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2016 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 #include "SkiaRecordingCanvas.h"
18 
19 #include <SkImagePriv.h>
20 #include "Layer.h"
21 #include "LayerDrawable.h"
22 #include "NinePatchUtils.h"
23 #include "RenderNode.h"
24 #include "pipeline/skia/AnimatedDrawables.h"
25 
26 namespace android {
27 namespace uirenderer {
28 namespace skiapipeline {
29 
30 // ----------------------------------------------------------------------------
31 // Recording Canvas Setup
32 // ----------------------------------------------------------------------------
33 
initDisplayList(uirenderer::RenderNode * renderNode,int width,int height)34 void SkiaRecordingCanvas::initDisplayList(uirenderer::RenderNode* renderNode, int width,
35                                           int height) {
36     mCurrentBarrier = nullptr;
37     SkASSERT(mDisplayList.get() == nullptr);
38 
39     if (renderNode) {
40         mDisplayList = renderNode->detachAvailableList();
41     }
42     if (!mDisplayList) {
43         mDisplayList.reset(new SkiaDisplayList());
44     }
45 
46     mDisplayList->attachRecorder(&mRecorder, SkIRect::MakeWH(width, height));
47     SkiaCanvas::reset(&mRecorder);
48 }
49 
finishRecording()50 uirenderer::DisplayList* SkiaRecordingCanvas::finishRecording() {
51     // close any existing chunks if necessary
52     insertReorderBarrier(false);
53     mRecorder.restoreToCount(1);
54     return mDisplayList.release();
55 }
56 
57 // ----------------------------------------------------------------------------
58 // Recording Canvas draw operations: View System
59 // ----------------------------------------------------------------------------
60 
drawRoundRect(uirenderer::CanvasPropertyPrimitive * left,uirenderer::CanvasPropertyPrimitive * top,uirenderer::CanvasPropertyPrimitive * right,uirenderer::CanvasPropertyPrimitive * bottom,uirenderer::CanvasPropertyPrimitive * rx,uirenderer::CanvasPropertyPrimitive * ry,uirenderer::CanvasPropertyPaint * paint)61 void SkiaRecordingCanvas::drawRoundRect(uirenderer::CanvasPropertyPrimitive* left,
62                                         uirenderer::CanvasPropertyPrimitive* top,
63                                         uirenderer::CanvasPropertyPrimitive* right,
64                                         uirenderer::CanvasPropertyPrimitive* bottom,
65                                         uirenderer::CanvasPropertyPrimitive* rx,
66                                         uirenderer::CanvasPropertyPrimitive* ry,
67                                         uirenderer::CanvasPropertyPaint* paint) {
68     // Destructor of drawables created with allocateDrawable, will be invoked by ~LinearAllocator.
69     drawDrawable(mDisplayList->allocateDrawable<AnimatedRoundRect>(left, top, right, bottom, rx, ry,
70                                                                    paint));
71 }
72 
drawCircle(uirenderer::CanvasPropertyPrimitive * x,uirenderer::CanvasPropertyPrimitive * y,uirenderer::CanvasPropertyPrimitive * radius,uirenderer::CanvasPropertyPaint * paint)73 void SkiaRecordingCanvas::drawCircle(uirenderer::CanvasPropertyPrimitive* x,
74                                      uirenderer::CanvasPropertyPrimitive* y,
75                                      uirenderer::CanvasPropertyPrimitive* radius,
76                                      uirenderer::CanvasPropertyPaint* paint) {
77     drawDrawable(mDisplayList->allocateDrawable<AnimatedCircle>(x, y, radius, paint));
78 }
79 
insertReorderBarrier(bool enableReorder)80 void SkiaRecordingCanvas::insertReorderBarrier(bool enableReorder) {
81     if (nullptr != mCurrentBarrier) {
82         // finish off the existing chunk
83         SkDrawable* drawable =
84                 mDisplayList->allocateDrawable<EndReorderBarrierDrawable>(mCurrentBarrier);
85         mCurrentBarrier = nullptr;
86         drawDrawable(drawable);
87     }
88     if (enableReorder) {
89         mCurrentBarrier = (StartReorderBarrierDrawable*)
90                                   mDisplayList->allocateDrawable<StartReorderBarrierDrawable>(
91                                           mDisplayList.get());
92         drawDrawable(mCurrentBarrier);
93     }
94 }
95 
drawLayer(uirenderer::DeferredLayerUpdater * layerUpdater)96 void SkiaRecordingCanvas::drawLayer(uirenderer::DeferredLayerUpdater* layerUpdater) {
97     if (layerUpdater != nullptr) {
98         // Create a ref-counted drawable, which is kept alive by sk_sp in SkLiteDL.
99         sk_sp<SkDrawable> drawable(new LayerDrawable(layerUpdater));
100         drawDrawable(drawable.get());
101     }
102 }
103 
drawRenderNode(uirenderer::RenderNode * renderNode)104 void SkiaRecordingCanvas::drawRenderNode(uirenderer::RenderNode* renderNode) {
105     // Record the child node. Drawable dtor will be invoked when mChildNodes deque is cleared.
106     mDisplayList->mChildNodes.emplace_back(renderNode, asSkCanvas(), true, mCurrentBarrier);
107     auto& renderNodeDrawable = mDisplayList->mChildNodes.back();
108     drawDrawable(&renderNodeDrawable);
109 
110     // use staging property, since recording on UI thread
111     if (renderNode->stagingProperties().isProjectionReceiver()) {
112         mDisplayList->mProjectionReceiver = &renderNodeDrawable;
113         // set projectionReceiveIndex so that RenderNode.hasProjectionReceiver returns true
114         mDisplayList->projectionReceiveIndex = mDisplayList->mChildNodes.size() - 1;
115     }
116 }
117 
callDrawGLFunction(Functor * functor,uirenderer::GlFunctorLifecycleListener * listener)118 void SkiaRecordingCanvas::callDrawGLFunction(Functor* functor,
119                                              uirenderer::GlFunctorLifecycleListener* listener) {
120     // Drawable dtor will be invoked when mChildFunctors deque is cleared.
121     mDisplayList->mChildFunctors.emplace_back(functor, listener, asSkCanvas());
122     drawDrawable(&mDisplayList->mChildFunctors.back());
123 }
124 
125 class VectorDrawable : public SkDrawable {
126 public:
VectorDrawable(VectorDrawableRoot * tree)127     VectorDrawable(VectorDrawableRoot* tree)
128             : mRoot(tree)
129             , mBounds(tree->stagingProperties()->getBounds()) {}
130 
131 protected:
onGetBounds()132     virtual SkRect onGetBounds() override { return mBounds; }
onDraw(SkCanvas * canvas)133     virtual void onDraw(SkCanvas* canvas) override {
134         mRoot->draw(canvas, mBounds);
135     }
136 
137 private:
138     sp<VectorDrawableRoot> mRoot;
139     SkRect mBounds;
140 };
141 
drawVectorDrawable(VectorDrawableRoot * tree)142 void SkiaRecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
143     drawDrawable(mDisplayList->allocateDrawable<VectorDrawable>(tree));
144     mDisplayList->mVectorDrawables.push_back(tree);
145 }
146 
147 // ----------------------------------------------------------------------------
148 // Recording Canvas draw operations: Bitmaps
149 // ----------------------------------------------------------------------------
150 
151 
drawBitmap(Bitmap & bitmap,float left,float top,const SkPaint * paint)152 void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) {
153     SkPaint tmpPaint;
154     sk_sp<SkColorFilter> colorFilter;
155     sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
156     mRecorder.drawImage(image, left, top, bitmapPaint(paint, &tmpPaint, colorFilter));
157     // if image->unique() is true, then mRecorder.drawImage failed for some reason. It also means
158     // it is not safe to store a raw SkImage pointer, because the image object will be destroyed
159     // when this function ends.
160     if (!bitmap.isImmutable() && image.get() && !image->unique()) {
161         mDisplayList->mMutableImages.push_back(image.get());
162     }
163 }
164 
drawBitmap(Bitmap & bitmap,const SkMatrix & matrix,const SkPaint * paint)165 void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) {
166     SkAutoCanvasRestore acr(&mRecorder, true);
167     concat(matrix);
168 
169     SkPaint tmpPaint;
170     sk_sp<SkColorFilter> colorFilter;
171     sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
172     mRecorder.drawImage(image, 0, 0, bitmapPaint(paint, &tmpPaint, colorFilter));
173     if (!bitmap.isImmutable() && image.get() && !image->unique()) {
174         mDisplayList->mMutableImages.push_back(image.get());
175     }
176 }
177 
drawBitmap(Bitmap & bitmap,float srcLeft,float srcTop,float srcRight,float srcBottom,float dstLeft,float dstTop,float dstRight,float dstBottom,const SkPaint * paint)178 void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight,
179                                      float srcBottom, float dstLeft, float dstTop, float dstRight,
180                                      float dstBottom, const SkPaint* paint) {
181     SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
182     SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
183 
184     SkPaint tmpPaint;
185     sk_sp<SkColorFilter> colorFilter;
186     sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
187     mRecorder.drawImageRect(image, srcRect, dstRect, bitmapPaint(paint, &tmpPaint, colorFilter),
188                             SkCanvas::kFast_SrcRectConstraint);
189     if (!bitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty() &&
190         !dstRect.isEmpty()) {
191         mDisplayList->mMutableImages.push_back(image.get());
192     }
193 }
194 
drawNinePatch(Bitmap & bitmap,const Res_png_9patch & chunk,float dstLeft,float dstTop,float dstRight,float dstBottom,const SkPaint * paint)195 void SkiaRecordingCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk, float dstLeft,
196                                         float dstTop, float dstRight, float dstBottom,
197                                         const SkPaint* paint) {
198     SkCanvas::Lattice lattice;
199     NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height());
200 
201     lattice.fRectTypes = nullptr;
202     lattice.fColors = nullptr;
203     int numFlags = 0;
204     if (chunk.numColors > 0 && chunk.numColors == NinePatchUtils::NumDistinctRects(lattice)) {
205         // We can expect the framework to give us a color for every distinct rect.
206         // Skia requires placeholder flags for degenerate rects.
207         numFlags = (lattice.fXCount + 1) * (lattice.fYCount + 1);
208     }
209 
210     SkAutoSTMalloc<25, SkCanvas::Lattice::RectType> flags(numFlags);
211     SkAutoSTMalloc<25, SkColor> colors(numFlags);
212     if (numFlags > 0) {
213         NinePatchUtils::SetLatticeFlags(&lattice, flags.get(), numFlags, chunk, colors.get());
214     }
215 
216     lattice.fBounds = nullptr;
217     SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
218 
219     SkPaint tmpPaint;
220     sk_sp<SkColorFilter> colorFilter;
221     sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
222     const SkPaint* filteredPaint = bitmapPaint(paint, &tmpPaint, colorFilter);
223     // Besides kNone, the other three SkFilterQualities are treated the same. And Android's
224     // Java API only supports kLow and kNone anyway.
225     if (!filteredPaint || filteredPaint->getFilterQuality() == kNone_SkFilterQuality) {
226         if (filteredPaint != &tmpPaint) {
227             if (paint) {
228                 tmpPaint = *paint;
229             }
230             filteredPaint = &tmpPaint;
231         }
232         tmpPaint.setFilterQuality(kLow_SkFilterQuality);
233     }
234 
235     mRecorder.drawImageLattice(image.get(), lattice, dst, filteredPaint);
236     if (!bitmap.isImmutable() && image.get() && !image->unique() && !dst.isEmpty()) {
237         mDisplayList->mMutableImages.push_back(image.get());
238     }
239 }
240 
drawAnimatedImage(AnimatedImageDrawable * animatedImage)241 double SkiaRecordingCanvas::drawAnimatedImage(AnimatedImageDrawable* animatedImage) {
242     drawDrawable(animatedImage);
243     mDisplayList->mAnimatedImages.push_back(animatedImage);
244     return 0;
245 }
246 
247 };  // namespace skiapipeline
248 };  // namespace uirenderer
249 };  // namespace android
250