blob: eabe2e87fc4911a7f63bf0798743c75e6ba475a8 [file] [log] [blame]
Stan Iliev021693b2016-10-17 16:26:15 -04001/*
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
John Reck1bcacfd2017-11-03 10:12:19 -070019#include <SkImagePriv.h>
Stan Iliev021693b2016-10-17 16:26:15 -040020#include "Layer.h"
Stan Iliev021693b2016-10-17 16:26:15 -040021#include "LayerDrawable.h"
22#include "NinePatchUtils.h"
John Reck1bcacfd2017-11-03 10:12:19 -070023#include "RenderNode.h"
Stan Iliev021693b2016-10-17 16:26:15 -040024#include "pipeline/skia/AnimatedDrawables.h"
25
26namespace android {
27namespace uirenderer {
28namespace skiapipeline {
29
30// ----------------------------------------------------------------------------
31// Recording Canvas Setup
32// ----------------------------------------------------------------------------
33
34void SkiaRecordingCanvas::initDisplayList(uirenderer::RenderNode* renderNode, int width,
John Reck1bcacfd2017-11-03 10:12:19 -070035 int height) {
Stan Iliev021693b2016-10-17 16:26:15 -040036 mCurrentBarrier = nullptr;
37 SkASSERT(mDisplayList.get() == nullptr);
38
39 if (renderNode) {
40 mDisplayList = renderNode->detachAvailableList();
41 }
Derek Sollenbergerea1fe9b2017-03-01 13:02:43 -050042 if (!mDisplayList) {
43 mDisplayList.reset(new SkiaDisplayList());
Stan Iliev021693b2016-10-17 16:26:15 -040044 }
45
Derek Sollenbergerea1fe9b2017-03-01 13:02:43 -050046 mDisplayList->attachRecorder(&mRecorder, SkIRect::MakeWH(width, height));
Stan Iliev021693b2016-10-17 16:26:15 -040047 SkiaCanvas::reset(&mRecorder);
48}
49
50uirenderer::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
61void SkiaRecordingCanvas::drawRoundRect(uirenderer::CanvasPropertyPrimitive* left,
John Reck1bcacfd2017-11-03 10:12:19 -070062 uirenderer::CanvasPropertyPrimitive* top,
63 uirenderer::CanvasPropertyPrimitive* right,
64 uirenderer::CanvasPropertyPrimitive* bottom,
65 uirenderer::CanvasPropertyPrimitive* rx,
66 uirenderer::CanvasPropertyPrimitive* ry,
67 uirenderer::CanvasPropertyPaint* paint) {
Stan Ilievf7aa6cd2017-03-29 18:25:12 -040068 // Destructor of drawables created with allocateDrawable, will be invoked by ~LinearAllocator.
John Reck1bcacfd2017-11-03 10:12:19 -070069 drawDrawable(mDisplayList->allocateDrawable<AnimatedRoundRect>(left, top, right, bottom, rx, ry,
70 paint));
Stan Iliev021693b2016-10-17 16:26:15 -040071}
72
73void SkiaRecordingCanvas::drawCircle(uirenderer::CanvasPropertyPrimitive* x,
John Reck1bcacfd2017-11-03 10:12:19 -070074 uirenderer::CanvasPropertyPrimitive* y,
75 uirenderer::CanvasPropertyPrimitive* radius,
76 uirenderer::CanvasPropertyPaint* paint) {
Stan Iliev021693b2016-10-17 16:26:15 -040077 drawDrawable(mDisplayList->allocateDrawable<AnimatedCircle>(x, y, radius, paint));
78}
79
80void SkiaRecordingCanvas::insertReorderBarrier(bool enableReorder) {
Stan Iliev021693b2016-10-17 16:26:15 -040081 if (nullptr != mCurrentBarrier) {
82 // finish off the existing chunk
83 SkDrawable* drawable =
John Reck1bcacfd2017-11-03 10:12:19 -070084 mDisplayList->allocateDrawable<EndReorderBarrierDrawable>(mCurrentBarrier);
Stan Iliev021693b2016-10-17 16:26:15 -040085 mCurrentBarrier = nullptr;
86 drawDrawable(drawable);
87 }
Stan Iliev88e08912016-11-22 18:19:29 -050088 if (enableReorder) {
89 mCurrentBarrier = (StartReorderBarrierDrawable*)
John Reck1bcacfd2017-11-03 10:12:19 -070090 mDisplayList->allocateDrawable<StartReorderBarrierDrawable>(
91 mDisplayList.get());
Stan Iliev88e08912016-11-22 18:19:29 -050092 drawDrawable(mCurrentBarrier);
93 }
Stan Iliev021693b2016-10-17 16:26:15 -040094}
95
96void SkiaRecordingCanvas::drawLayer(uirenderer::DeferredLayerUpdater* layerUpdater) {
Derek Sollenbergerf5a370e2017-06-15 13:50:08 -040097 if (layerUpdater != nullptr) {
Stan Ilievf7aa6cd2017-03-29 18:25:12 -040098 // Create a ref-counted drawable, which is kept alive by sk_sp in SkLiteDL.
Derek Sollenbergerf5a370e2017-06-15 13:50:08 -040099 sk_sp<SkDrawable> drawable(new LayerDrawable(layerUpdater));
Stan Iliev021693b2016-10-17 16:26:15 -0400100 drawDrawable(drawable.get());
101 }
102}
103
104void SkiaRecordingCanvas::drawRenderNode(uirenderer::RenderNode* renderNode) {
Stan Ilievf7aa6cd2017-03-29 18:25:12 -0400105 // Record the child node. Drawable dtor will be invoked when mChildNodes deque is cleared.
Stan Iliev2f06e8a2016-11-02 15:29:03 -0400106 mDisplayList->mChildNodes.emplace_back(renderNode, asSkCanvas(), true, mCurrentBarrier);
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500107 auto& renderNodeDrawable = mDisplayList->mChildNodes.back();
108 drawDrawable(&renderNodeDrawable);
Stan Iliev021693b2016-10-17 16:26:15 -0400109
110 // use staging property, since recording on UI thread
111 if (renderNode->stagingProperties().isProjectionReceiver()) {
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500112 mDisplayList->mProjectionReceiver = &renderNodeDrawable;
Stan Iliev021693b2016-10-17 16:26:15 -0400113 // set projectionReceiveIndex so that RenderNode.hasProjectionReceiver returns true
114 mDisplayList->projectionReceiveIndex = mDisplayList->mChildNodes.size() - 1;
115 }
116}
117
118void SkiaRecordingCanvas::callDrawGLFunction(Functor* functor,
John Reck1bcacfd2017-11-03 10:12:19 -0700119 uirenderer::GlFunctorLifecycleListener* listener) {
Stan Ilievf7aa6cd2017-03-29 18:25:12 -0400120 // Drawable dtor will be invoked when mChildFunctors deque is cleared.
Stan Iliev021693b2016-10-17 16:26:15 -0400121 mDisplayList->mChildFunctors.emplace_back(functor, listener, asSkCanvas());
122 drawDrawable(&mDisplayList->mChildFunctors.back());
123}
124
125class VectorDrawable : public SkDrawable {
John Reck1bcacfd2017-11-03 10:12:19 -0700126public:
Stan Iliev021693b2016-10-17 16:26:15 -0400127 VectorDrawable(VectorDrawableRoot* tree) : mRoot(tree) {}
128
John Reck1bcacfd2017-11-03 10:12:19 -0700129protected:
130 virtual SkRect onGetBounds() override { return SkRect::MakeLargest(); }
131 virtual void onDraw(SkCanvas* canvas) override { mRoot->draw(canvas); }
Stan Iliev021693b2016-10-17 16:26:15 -0400132
John Reck1bcacfd2017-11-03 10:12:19 -0700133private:
Stan Iliev021693b2016-10-17 16:26:15 -0400134 sp<VectorDrawableRoot> mRoot;
135};
136
137void SkiaRecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
138 drawDrawable(mDisplayList->allocateDrawable<VectorDrawable>(tree));
139 mDisplayList->mVectorDrawables.push_back(tree);
140}
141
142// ----------------------------------------------------------------------------
143// Recording Canvas draw operations: Bitmaps
144// ----------------------------------------------------------------------------
145
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -0400146inline static const SkPaint* bitmapPaint(const SkPaint* origPaint, SkPaint* tmpPaint,
Derek Sollenberger4eb21442017-11-09 12:31:36 -0500147 sk_sp<SkColorFilter> colorSpaceFilter) {
148 if ((origPaint && origPaint->isAntiAlias()) || colorSpaceFilter) {
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -0400149 if (origPaint) {
150 *tmpPaint = *origPaint;
151 }
Derek Sollenbergerfa3e3402017-08-04 08:35:10 -0400152
Derek Sollenberger4eb21442017-11-09 12:31:36 -0500153 if (colorSpaceFilter) {
154 if (tmpPaint->getColorFilter()) {
155 tmpPaint->setColorFilter(
156 SkColorFilter::MakeComposeFilter(tmpPaint->refColorFilter(), colorSpaceFilter));
157 } else {
158 tmpPaint->setColorFilter(colorSpaceFilter);
159 }
160 LOG_ALWAYS_FATAL_IF(!tmpPaint->getColorFilter());
Derek Sollenbergerfa3e3402017-08-04 08:35:10 -0400161 }
162
Derek Sollenberger4eb21442017-11-09 12:31:36 -0500163
164 // disabling AA on bitmap draws matches legacy HWUI behavior
Stan Iliev021693b2016-10-17 16:26:15 -0400165 tmpPaint->setAntiAlias(false);
166 return tmpPaint;
167 } else {
168 return origPaint;
169 }
170}
171
172void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) {
Stan Iliev021693b2016-10-17 16:26:15 -0400173 SkPaint tmpPaint;
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -0400174 sk_sp<SkColorFilter> colorFilter;
175 sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
176 mRecorder.drawImage(image, left, top, bitmapPaint(paint, &tmpPaint, colorFilter));
Stan Iliev0cc4e362017-05-18 14:21:23 -0400177 // if image->unique() is true, then mRecorder.drawImage failed for some reason. It also means
178 // it is not safe to store a raw SkImage pointer, because the image object will be destroyed
179 // when this function ends.
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400180 if (!bitmap.isImmutable() && image.get() && !image->unique()) {
Stan Iliev0cc4e362017-05-18 14:21:23 -0400181 mDisplayList->mMutableImages.push_back(image.get());
182 }
Stan Iliev021693b2016-10-17 16:26:15 -0400183}
184
John Reck1bcacfd2017-11-03 10:12:19 -0700185void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const SkPaint* paint) {
Stan Iliev021693b2016-10-17 16:26:15 -0400186 SkAutoCanvasRestore acr(&mRecorder, true);
187 concat(matrix);
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -0400188
Stan Iliev021693b2016-10-17 16:26:15 -0400189 SkPaint tmpPaint;
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -0400190 sk_sp<SkColorFilter> colorFilter;
191 sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
192 mRecorder.drawImage(image, 0, 0, bitmapPaint(paint, &tmpPaint, colorFilter));
193 if (!bitmap.isImmutable() && image.get() && !image->unique()) {
Stan Iliev0cc4e362017-05-18 14:21:23 -0400194 mDisplayList->mMutableImages.push_back(image.get());
195 }
Stan Iliev021693b2016-10-17 16:26:15 -0400196}
197
John Reck1bcacfd2017-11-03 10:12:19 -0700198void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight,
199 float srcBottom, float dstLeft, float dstTop, float dstRight,
200 float dstBottom, const SkPaint* paint) {
Stan Iliev021693b2016-10-17 16:26:15 -0400201 SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
202 SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -0400203
Stan Iliev021693b2016-10-17 16:26:15 -0400204 SkPaint tmpPaint;
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -0400205 sk_sp<SkColorFilter> colorFilter;
206 sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
Derek Sollenberger6c2a9e22017-08-15 16:23:01 -0400207 mRecorder.drawImageRect(image, srcRect, dstRect, bitmapPaint(paint, &tmpPaint, colorFilter),
John Reck1bcacfd2017-11-03 10:12:19 -0700208 SkCanvas::kFast_SrcRectConstraint);
209 if (!bitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty() &&
210 !dstRect.isEmpty()) {
Stan Iliev0cc4e362017-05-18 14:21:23 -0400211 mDisplayList->mMutableImages.push_back(image.get());
212 }
Stan Iliev021693b2016-10-17 16:26:15 -0400213}
214
John Reck1bcacfd2017-11-03 10:12:19 -0700215void SkiaRecordingCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk, float dstLeft,
216 float dstTop, float dstRight, float dstBottom,
217 const SkPaint* paint) {
Stan Iliev021693b2016-10-17 16:26:15 -0400218 SkCanvas::Lattice lattice;
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -0400219 NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height());
Stan Iliev021693b2016-10-17 16:26:15 -0400220
Stan Ilieve12d7312017-12-04 14:48:27 -0500221 lattice.fRectTypes = nullptr;
222 lattice.fColors = nullptr;
Stan Iliev021693b2016-10-17 16:26:15 -0400223 int numFlags = 0;
224 if (chunk.numColors > 0 && chunk.numColors == NinePatchUtils::NumDistinctRects(lattice)) {
225 // We can expect the framework to give us a color for every distinct rect.
226 // Skia requires placeholder flags for degenerate rects.
227 numFlags = (lattice.fXCount + 1) * (lattice.fYCount + 1);
228 }
229
Stan Ilieve12d7312017-12-04 14:48:27 -0500230 SkAutoSTMalloc<25, SkCanvas::Lattice::RectType> flags(numFlags);
231 SkAutoSTMalloc<25, SkColor> colors(numFlags);
Stan Iliev021693b2016-10-17 16:26:15 -0400232 if (numFlags > 0) {
Stan Ilieve12d7312017-12-04 14:48:27 -0500233 NinePatchUtils::SetLatticeFlags(&lattice, flags.get(), numFlags, chunk, colors.get());
Stan Iliev021693b2016-10-17 16:26:15 -0400234 }
235
236 lattice.fBounds = nullptr;
237 SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
Stan Iliev021693b2016-10-17 16:26:15 -0400238
239 SkPaint tmpPaint;
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -0400240 sk_sp<SkColorFilter> colorFilter;
241 sk_sp<SkImage> image = bitmap.makeImage(&colorFilter);
242 mRecorder.drawImageLattice(image.get(), lattice, dst,
John Reck1bcacfd2017-11-03 10:12:19 -0700243 bitmapPaint(paint, &tmpPaint, colorFilter));
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -0400244 if (!bitmap.isImmutable() && image.get() && !image->unique() && !dst.isEmpty()) {
Stan Iliev0cc4e362017-05-18 14:21:23 -0400245 mDisplayList->mMutableImages.push_back(image.get());
246 }
Stan Iliev021693b2016-10-17 16:26:15 -0400247}
248
Derek Sollenberger2d142132018-01-22 10:25:26 -0500249double SkiaRecordingCanvas::drawAnimatedImage(AnimatedImageDrawable* animatedImage) {
250 drawDrawable(animatedImage);
251 mDisplayList->mAnimatedImages.push_back(animatedImage);
252 return 0;
253}
254
John Reck1bcacfd2017-11-03 10:12:19 -0700255}; // namespace skiapipeline
256}; // namespace uirenderer
257}; // namespace android