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