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 "Layer.h"
20 #include "RenderNode.h"
21 #include "LayerDrawable.h"
22 #include "NinePatchUtils.h"
23 #include "pipeline/skia/AnimatedDrawables.h"
24 #include <SkImagePriv.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, uirenderer::CanvasPropertyPrimitive* right,
63         uirenderer::CanvasPropertyPrimitive* bottom, uirenderer::CanvasPropertyPrimitive* rx,
64         uirenderer::CanvasPropertyPrimitive* ry, uirenderer::CanvasPropertyPaint* paint) {
65     drawDrawable(mDisplayList->allocateDrawable<AnimatedRoundRect>(left, top, right, bottom,
66             rx, ry, paint));
67 }
68 
drawCircle(uirenderer::CanvasPropertyPrimitive * x,uirenderer::CanvasPropertyPrimitive * y,uirenderer::CanvasPropertyPrimitive * radius,uirenderer::CanvasPropertyPaint * paint)69 void SkiaRecordingCanvas::drawCircle(uirenderer::CanvasPropertyPrimitive* x,
70         uirenderer::CanvasPropertyPrimitive* y, uirenderer::CanvasPropertyPrimitive* radius,
71         uirenderer::CanvasPropertyPaint* paint) {
72     drawDrawable(mDisplayList->allocateDrawable<AnimatedCircle>(x, y, radius, paint));
73 }
74 
insertReorderBarrier(bool enableReorder)75 void SkiaRecordingCanvas::insertReorderBarrier(bool enableReorder) {
76     if (nullptr != mCurrentBarrier) {
77         // finish off the existing chunk
78         SkDrawable* drawable =
79                 mDisplayList->allocateDrawable<EndReorderBarrierDrawable>(
80                 mCurrentBarrier);
81         mCurrentBarrier = nullptr;
82         drawDrawable(drawable);
83     }
84     if (enableReorder) {
85         mCurrentBarrier = (StartReorderBarrierDrawable*)
86                 mDisplayList->allocateDrawable<StartReorderBarrierDrawable>(
87                 mDisplayList.get());
88         drawDrawable(mCurrentBarrier);
89     }
90 }
91 
drawLayer(uirenderer::DeferredLayerUpdater * layerUpdater)92 void SkiaRecordingCanvas::drawLayer(uirenderer::DeferredLayerUpdater* layerUpdater) {
93     if (layerUpdater != nullptr && layerUpdater->backingLayer() != nullptr) {
94         uirenderer::Layer* layer = layerUpdater->backingLayer();
95         sk_sp<SkDrawable> drawable(new LayerDrawable(layer));
96         drawDrawable(drawable.get());
97     }
98 }
99 
drawRenderNode(uirenderer::RenderNode * renderNode)100 void SkiaRecordingCanvas::drawRenderNode(uirenderer::RenderNode* renderNode) {
101     // record the child node
102     mDisplayList->mChildNodes.emplace_back(renderNode, asSkCanvas(), true, mCurrentBarrier);
103     auto& renderNodeDrawable = mDisplayList->mChildNodes.back();
104     drawDrawable(&renderNodeDrawable);
105 
106     // use staging property, since recording on UI thread
107     if (renderNode->stagingProperties().isProjectionReceiver()) {
108         mDisplayList->mProjectionReceiver = &renderNodeDrawable;
109         // set projectionReceiveIndex so that RenderNode.hasProjectionReceiver returns true
110         mDisplayList->projectionReceiveIndex = mDisplayList->mChildNodes.size() - 1;
111     }
112 }
113 
callDrawGLFunction(Functor * functor,uirenderer::GlFunctorLifecycleListener * listener)114 void SkiaRecordingCanvas::callDrawGLFunction(Functor* functor,
115         uirenderer::GlFunctorLifecycleListener* listener) {
116     mDisplayList->mChildFunctors.emplace_back(functor, listener, asSkCanvas());
117     drawDrawable(&mDisplayList->mChildFunctors.back());
118 }
119 
120 class VectorDrawable : public SkDrawable {
121  public:
VectorDrawable(VectorDrawableRoot * tree)122     VectorDrawable(VectorDrawableRoot* tree) : mRoot(tree) {}
123 
124  protected:
onGetBounds()125      virtual SkRect onGetBounds() override {
126          return SkRect::MakeLargest();
127      }
onDraw(SkCanvas * canvas)128      virtual void onDraw(SkCanvas* canvas) override {
129          Bitmap& hwuiBitmap = mRoot->getBitmapUpdateIfDirty();
130          SkBitmap bitmap;
131          hwuiBitmap.getSkBitmap(&bitmap);
132          SkPaint* paint = mRoot->getPaint();
133          canvas->drawBitmapRect(bitmap, mRoot->mutateProperties()->getBounds(), paint);
134          /*
135           * TODO we can draw this directly but need to address the following...
136           *
137           * 1) Add drawDirect(SkCanvas*) to VectorDrawableRoot
138           * 2) fix VectorDrawable.cpp's Path::draw to not make a temporary path
139           *    so that we don't break caching
140           * 3) figure out how to set path's as volatile during animation
141           * 4) if mRoot->getPaint() != null either promote to layer (during
142           *    animation) or cache in SkSurface (for static content)
143           *
144           */
145      }
146 
147  private:
148     sp<VectorDrawableRoot> mRoot;
149 };
150 
drawVectorDrawable(VectorDrawableRoot * tree)151 void SkiaRecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
152     drawDrawable(mDisplayList->allocateDrawable<VectorDrawable>(tree));
153     mDisplayList->mVectorDrawables.push_back(tree);
154 }
155 
156 // ----------------------------------------------------------------------------
157 // Recording Canvas draw operations: Bitmaps
158 // ----------------------------------------------------------------------------
159 
nonAAPaint(const SkPaint * origPaint,SkPaint * tmpPaint)160 inline static const SkPaint* nonAAPaint(const SkPaint* origPaint, SkPaint* tmpPaint) {
161     if (origPaint && origPaint->isAntiAlias()) {
162         *tmpPaint = *origPaint;
163         tmpPaint->setAntiAlias(false);
164         return tmpPaint;
165     } else {
166         return origPaint;
167     }
168 }
169 
drawBitmap(Bitmap & bitmap,float left,float top,const SkPaint * paint)170 void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) {
171     SkBitmap skBitmap;
172     bitmap.getSkBitmap(&skBitmap);
173 
174     sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(skBitmap, kNever_SkCopyPixelsMode);
175     if (!skBitmap.isImmutable()) {
176         mDisplayList->mMutableImages.push_back(image.get());
177     }
178     SkPaint tmpPaint;
179     mRecorder.drawImage(image, left, top, nonAAPaint(paint, &tmpPaint));
180 }
181 
drawBitmap(Bitmap & hwuiBitmap,const SkMatrix & matrix,const SkPaint * paint)182 void SkiaRecordingCanvas::drawBitmap(Bitmap& hwuiBitmap, const SkMatrix& matrix,
183         const SkPaint* paint) {
184     SkBitmap bitmap;
185     hwuiBitmap.getSkBitmap(&bitmap);
186     SkAutoCanvasRestore acr(&mRecorder, true);
187     concat(matrix);
188     sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
189     if (!bitmap.isImmutable()) {
190         mDisplayList->mMutableImages.push_back(image.get());
191     }
192     SkPaint tmpPaint;
193     mRecorder.drawImage(image, 0, 0, nonAAPaint(paint, &tmpPaint));
194 }
195 
drawBitmap(Bitmap & hwuiBitmap,float srcLeft,float srcTop,float srcRight,float srcBottom,float dstLeft,float dstTop,float dstRight,float dstBottom,const SkPaint * paint)196 void SkiaRecordingCanvas::drawBitmap(Bitmap& hwuiBitmap, float srcLeft, float srcTop,
197         float srcRight, float srcBottom, float dstLeft, float dstTop, float dstRight,
198         float dstBottom, const SkPaint* paint) {
199     SkBitmap bitmap;
200     hwuiBitmap.getSkBitmap(&bitmap);
201     SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
202     SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
203     sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
204     if (!bitmap.isImmutable()) {
205         mDisplayList->mMutableImages.push_back(image.get());
206     }
207     SkPaint tmpPaint;
208     mRecorder.drawImageRect(image, srcRect, dstRect, nonAAPaint(paint, &tmpPaint));
209 }
210 
drawNinePatch(Bitmap & hwuiBitmap,const Res_png_9patch & chunk,float dstLeft,float dstTop,float dstRight,float dstBottom,const SkPaint * paint)211 void SkiaRecordingCanvas::drawNinePatch(Bitmap& hwuiBitmap, const Res_png_9patch& chunk,
212         float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) {
213     SkBitmap bitmap;
214     hwuiBitmap.getSkBitmap(&bitmap);
215 
216     SkCanvas::Lattice lattice;
217     NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height());
218 
219     lattice.fFlags = nullptr;
220     int numFlags = 0;
221     if (chunk.numColors > 0 && chunk.numColors == NinePatchUtils::NumDistinctRects(lattice)) {
222         // We can expect the framework to give us a color for every distinct rect.
223         // Skia requires placeholder flags for degenerate rects.
224         numFlags = (lattice.fXCount + 1) * (lattice.fYCount + 1);
225     }
226 
227     SkAutoSTMalloc<25, SkCanvas::Lattice::Flags> flags(numFlags);
228     if (numFlags > 0) {
229         NinePatchUtils::SetLatticeFlags(&lattice, flags.get(), numFlags, chunk);
230     }
231 
232     lattice.fBounds = nullptr;
233     SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
234     sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
235     if (!bitmap.isImmutable()) {
236         mDisplayList->mMutableImages.push_back(image.get());
237     }
238 
239     SkPaint tmpPaint;
240     mRecorder.drawImageLattice(image.get(), lattice, dst, nonAAPaint(paint, &tmpPaint));
241 }
242 
243 }; // namespace skiapipeline
244 }; // namespace uirenderer
245 }; // namespace android
246