blob: 0db5133037b0483df9d0ea52a39a7a575a7ff1c8 [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"
Mike Reedc2dbc032019-07-25 12:28:29 -040018#include "hwui/Paint.h"
John Reck1bcacfd2017-11-03 10:12:19 -070019#include <SkImagePriv.h>
John Reck9ce2bf72018-07-02 18:33:32 -070020#include "CanvasTransform.h"
Fedor Kudasov86bd2142019-06-18 15:51:57 +010021#ifdef __ANDROID__ // Layoutlib does not support Layers
Stan Iliev021693b2016-10-17 16:26:15 -040022#include "Layer.h"
Stan Iliev021693b2016-10-17 16:26:15 -040023#include "LayerDrawable.h"
Fedor Kudasov86bd2142019-06-18 15:51:57 +010024#endif
Stan Iliev021693b2016-10-17 16:26:15 -040025#include "NinePatchUtils.h"
John Reck1bcacfd2017-11-03 10:12:19 -070026#include "RenderNode.h"
Stan Iliev021693b2016-10-17 16:26:15 -040027#include "pipeline/skia/AnimatedDrawables.h"
Fedor Kudasov86bd2142019-06-18 15:51:57 +010028#ifdef __ANDROID__ // Layoutlib does not support GL, Vulcan etc.
Stan Iliev11606ff2018-09-17 14:01:16 -040029#include "pipeline/skia/GLFunctorDrawable.h"
Chris Blume41423392018-11-06 11:47:03 -080030#include "pipeline/skia/VkFunctorDrawable.h"
John Reck283bb462018-12-13 16:40:14 -080031#include "pipeline/skia/VkInteropFunctorDrawable.h"
Fedor Kudasov86bd2142019-06-18 15:51:57 +010032#endif
Stan Iliev021693b2016-10-17 16:26:15 -040033
34namespace android {
35namespace uirenderer {
36namespace skiapipeline {
37
38// ----------------------------------------------------------------------------
39// Recording Canvas Setup
40// ----------------------------------------------------------------------------
41
42void SkiaRecordingCanvas::initDisplayList(uirenderer::RenderNode* renderNode, int width,
John Reck1bcacfd2017-11-03 10:12:19 -070043 int height) {
Stan Iliev021693b2016-10-17 16:26:15 -040044 mCurrentBarrier = nullptr;
45 SkASSERT(mDisplayList.get() == nullptr);
46
47 if (renderNode) {
48 mDisplayList = renderNode->detachAvailableList();
49 }
Derek Sollenbergerea1fe9b2017-03-01 13:02:43 -050050 if (!mDisplayList) {
51 mDisplayList.reset(new SkiaDisplayList());
Stan Iliev021693b2016-10-17 16:26:15 -040052 }
53
Derek Sollenbergerea1fe9b2017-03-01 13:02:43 -050054 mDisplayList->attachRecorder(&mRecorder, SkIRect::MakeWH(width, height));
John Reck8f45d4a2018-08-15 10:17:12 -070055 SkiaCanvas::reset(&mRecorder);
Stan Iliev021693b2016-10-17 16:26:15 -040056}
57
58uirenderer::DisplayList* SkiaRecordingCanvas::finishRecording() {
59 // close any existing chunks if necessary
60 insertReorderBarrier(false);
61 mRecorder.restoreToCount(1);
62 return mDisplayList.release();
63}
64
65// ----------------------------------------------------------------------------
66// Recording Canvas draw operations: View System
67// ----------------------------------------------------------------------------
68
69void SkiaRecordingCanvas::drawRoundRect(uirenderer::CanvasPropertyPrimitive* left,
John Reck1bcacfd2017-11-03 10:12:19 -070070 uirenderer::CanvasPropertyPrimitive* top,
71 uirenderer::CanvasPropertyPrimitive* right,
72 uirenderer::CanvasPropertyPrimitive* bottom,
73 uirenderer::CanvasPropertyPrimitive* rx,
74 uirenderer::CanvasPropertyPrimitive* ry,
75 uirenderer::CanvasPropertyPaint* paint) {
Stan Ilievf7aa6cd2017-03-29 18:25:12 -040076 // Destructor of drawables created with allocateDrawable, will be invoked by ~LinearAllocator.
John Reck1bcacfd2017-11-03 10:12:19 -070077 drawDrawable(mDisplayList->allocateDrawable<AnimatedRoundRect>(left, top, right, bottom, rx, ry,
78 paint));
Stan Iliev021693b2016-10-17 16:26:15 -040079}
80
81void SkiaRecordingCanvas::drawCircle(uirenderer::CanvasPropertyPrimitive* x,
John Reck1bcacfd2017-11-03 10:12:19 -070082 uirenderer::CanvasPropertyPrimitive* y,
83 uirenderer::CanvasPropertyPrimitive* radius,
84 uirenderer::CanvasPropertyPaint* paint) {
Stan Iliev021693b2016-10-17 16:26:15 -040085 drawDrawable(mDisplayList->allocateDrawable<AnimatedCircle>(x, y, radius, paint));
86}
87
88void SkiaRecordingCanvas::insertReorderBarrier(bool enableReorder) {
John Reckddeaa482018-10-30 10:47:43 -070089 if (mCurrentBarrier && enableReorder) {
90 // Already in a re-order section, nothing to do
91 return;
92 }
93
Stan Iliev021693b2016-10-17 16:26:15 -040094 if (nullptr != mCurrentBarrier) {
95 // finish off the existing chunk
96 SkDrawable* drawable =
John Reck1bcacfd2017-11-03 10:12:19 -070097 mDisplayList->allocateDrawable<EndReorderBarrierDrawable>(mCurrentBarrier);
Stan Iliev021693b2016-10-17 16:26:15 -040098 mCurrentBarrier = nullptr;
99 drawDrawable(drawable);
100 }
Stan Iliev88e08912016-11-22 18:19:29 -0500101 if (enableReorder) {
John Reck283bb462018-12-13 16:40:14 -0800102 mCurrentBarrier =
103 mDisplayList->allocateDrawable<StartReorderBarrierDrawable>(mDisplayList.get());
Stan Iliev88e08912016-11-22 18:19:29 -0500104 drawDrawable(mCurrentBarrier);
105 }
Stan Iliev021693b2016-10-17 16:26:15 -0400106}
107
108void SkiaRecordingCanvas::drawLayer(uirenderer::DeferredLayerUpdater* layerUpdater) {
Fedor Kudasov86bd2142019-06-18 15:51:57 +0100109#ifdef __ANDROID__ // Layoutlib does not support Layers
Derek Sollenbergerf5a370e2017-06-15 13:50:08 -0400110 if (layerUpdater != nullptr) {
Stan Ilievf7aa6cd2017-03-29 18:25:12 -0400111 // Create a ref-counted drawable, which is kept alive by sk_sp in SkLiteDL.
Derek Sollenbergerf5a370e2017-06-15 13:50:08 -0400112 sk_sp<SkDrawable> drawable(new LayerDrawable(layerUpdater));
Stan Iliev021693b2016-10-17 16:26:15 -0400113 drawDrawable(drawable.get());
114 }
Fedor Kudasov86bd2142019-06-18 15:51:57 +0100115#endif
Stan Iliev021693b2016-10-17 16:26:15 -0400116}
117
Fedor Kudasov86bd2142019-06-18 15:51:57 +0100118
Stan Iliev021693b2016-10-17 16:26:15 -0400119void SkiaRecordingCanvas::drawRenderNode(uirenderer::RenderNode* renderNode) {
Stan Ilievf7aa6cd2017-03-29 18:25:12 -0400120 // Record the child node. Drawable dtor will be invoked when mChildNodes deque is cleared.
Stan Iliev2f06e8a2016-11-02 15:29:03 -0400121 mDisplayList->mChildNodes.emplace_back(renderNode, asSkCanvas(), true, mCurrentBarrier);
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500122 auto& renderNodeDrawable = mDisplayList->mChildNodes.back();
Stan Ilievf09ee582018-11-06 17:35:50 -0500123 if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
124 // Put Vulkan WebViews with non-rectangular clips in a HW layer
125 renderNode->mutateStagingProperties().setClipMayBeComplex(mRecorder.isClipMayBeComplex());
126 }
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500127 drawDrawable(&renderNodeDrawable);
Stan Iliev021693b2016-10-17 16:26:15 -0400128
129 // use staging property, since recording on UI thread
130 if (renderNode->stagingProperties().isProjectionReceiver()) {
Stan Ilievdb45a4b2016-11-08 14:18:31 -0500131 mDisplayList->mProjectionReceiver = &renderNodeDrawable;
Stan Iliev021693b2016-10-17 16:26:15 -0400132 }
133}
134
Fedor Kudasov86bd2142019-06-18 15:51:57 +0100135
Stan Iliev021693b2016-10-17 16:26:15 -0400136void SkiaRecordingCanvas::callDrawGLFunction(Functor* functor,
John Reck1bcacfd2017-11-03 10:12:19 -0700137 uirenderer::GlFunctorLifecycleListener* listener) {
Fedor Kudasov86bd2142019-06-18 15:51:57 +0100138#ifdef __ANDROID__ // Layoutlib does not support GL, Vulcan etc.
Stan Iliev11606ff2018-09-17 14:01:16 -0400139 FunctorDrawable* functorDrawable;
140 if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
John Reck283bb462018-12-13 16:40:14 -0800141 functorDrawable = mDisplayList->allocateDrawable<VkInteropFunctorDrawable>(
142 functor, listener, asSkCanvas());
Stan Iliev11606ff2018-09-17 14:01:16 -0400143 } else {
John Reck283bb462018-12-13 16:40:14 -0800144 functorDrawable =
145 mDisplayList->allocateDrawable<GLFunctorDrawable>(functor, listener, asSkCanvas());
146 }
147 mDisplayList->mChildFunctors.push_back(functorDrawable);
148 drawDrawable(functorDrawable);
Fedor Kudasov86bd2142019-06-18 15:51:57 +0100149#endif
John Reck283bb462018-12-13 16:40:14 -0800150}
151
152void SkiaRecordingCanvas::drawWebViewFunctor(int functor) {
Fedor Kudasov86bd2142019-06-18 15:51:57 +0100153#ifdef __ANDROID__ // Layoutlib does not support GL, Vulcan etc.
John Reck283bb462018-12-13 16:40:14 -0800154 FunctorDrawable* functorDrawable;
155 if (Properties::getRenderPipelineType() == RenderPipelineType::SkiaVulkan) {
John Reck0fa0cbc2019-04-05 16:57:46 -0700156 functorDrawable = mDisplayList->allocateDrawable<VkFunctorDrawable>(functor, asSkCanvas());
John Reck283bb462018-12-13 16:40:14 -0800157 } else {
158 functorDrawable = mDisplayList->allocateDrawable<GLFunctorDrawable>(functor, asSkCanvas());
Stan Iliev11606ff2018-09-17 14:01:16 -0400159 }
160 mDisplayList->mChildFunctors.push_back(functorDrawable);
161 drawDrawable(functorDrawable);
Fedor Kudasov86bd2142019-06-18 15:51:57 +0100162#endif
Stan Iliev021693b2016-10-17 16:26:15 -0400163}
164
Stan Iliev021693b2016-10-17 16:26:15 -0400165void SkiaRecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
John Reck08ee8152018-09-20 16:27:46 -0700166 mRecorder.drawVectorDrawable(tree);
Leon Scroggins III6c5864c2019-04-03 15:09:25 -0400167 SkMatrix mat;
168 this->getMatrix(&mat);
169 mDisplayList->appendVD(tree, mat);
Stan Iliev021693b2016-10-17 16:26:15 -0400170}
171
172// ----------------------------------------------------------------------------
173// Recording Canvas draw operations: Bitmaps
174// ----------------------------------------------------------------------------
175
Nader Jawadf9f964d2019-05-24 10:33:55 -0700176SkiaCanvas::PaintCoW&& SkiaRecordingCanvas::filterBitmap(PaintCoW&& paint) {
Ben Wagner0ed10be2018-06-28 17:08:16 -0400177 bool fixBlending = false;
178 bool fixAA = false;
179 if (paint) {
180 // kClear blend mode is drawn as kDstOut on HW for compatibility with Android O and
181 // older.
182 fixBlending = sApiLevel <= 27 && paint->getBlendMode() == SkBlendMode::kClear;
183 fixAA = paint->isAntiAlias();
184 }
185
Nader Jawadf9f964d2019-05-24 10:33:55 -0700186 if (fixBlending || fixAA) {
Ben Wagner0ed10be2018-06-28 17:08:16 -0400187 SkPaint& tmpPaint = paint.writeable();
188
189 if (fixBlending) {
190 tmpPaint.setBlendMode(SkBlendMode::kDstOut);
191 }
192
Ben Wagner0ed10be2018-06-28 17:08:16 -0400193 // disabling AA on bitmap draws matches legacy HWUI behavior
194 tmpPaint.setAntiAlias(false);
195 }
196
197 return filterPaint(std::move(paint));
198}
Stan Iliev021693b2016-10-17 16:26:15 -0400199
Mike Reedc2dbc032019-07-25 12:28:29 -0400200static SkDrawLooper* get_looper(const Paint* paint) {
201 return paint ? paint->getLooper() : nullptr;
202}
203
204template <typename Proc>
205void applyLooper(SkDrawLooper* looper, const SkPaint& paint, Proc proc) {
206 if (looper) {
207 SkSTArenaAlloc<256> alloc;
208 SkDrawLooper::Context* ctx = looper->makeContext(&alloc);
209 if (ctx) {
210 SkDrawLooper::Context::Info info;
211 for (;;) {
212 SkPaint p = paint;
213 if (!ctx->next(&info, &p)) {
214 break;
215 }
216 proc(info.fTranslate.fX, info.fTranslate.fY, p);
217 }
218 }
219 } else {
220 proc(0, 0, paint);
221 }
222}
223
224void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const Paint* paint) {
Derek Sollenbergerd01b5912018-10-19 15:55:33 -0400225 sk_sp<SkImage> image = bitmap.makeImage();
Mike Reedc2dbc032019-07-25 12:28:29 -0400226
227 applyLooper(get_looper(paint), *filterBitmap(paint), [&](SkScalar x, SkScalar y, const SkPaint& p) {
228 mRecorder.drawImage(image, left + x, top + y, &p, bitmap.palette());
229 });
230
Stan Iliev0cc4e362017-05-18 14:21:23 -0400231 // if image->unique() is true, then mRecorder.drawImage failed for some reason. It also means
232 // it is not safe to store a raw SkImage pointer, because the image object will be destroyed
233 // when this function ends.
Stan Iliev7bc3bc62017-05-24 13:28:36 -0400234 if (!bitmap.isImmutable() && image.get() && !image->unique()) {
Stan Iliev0cc4e362017-05-18 14:21:23 -0400235 mDisplayList->mMutableImages.push_back(image.get());
236 }
Stan Iliev021693b2016-10-17 16:26:15 -0400237}
238
Mike Reedc2dbc032019-07-25 12:28:29 -0400239void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix, const Paint* paint) {
Stan Iliev021693b2016-10-17 16:26:15 -0400240 SkAutoCanvasRestore acr(&mRecorder, true);
241 concat(matrix);
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -0400242
Derek Sollenbergerd01b5912018-10-19 15:55:33 -0400243 sk_sp<SkImage> image = bitmap.makeImage();
Mike Reedc2dbc032019-07-25 12:28:29 -0400244
245 applyLooper(get_looper(paint), *filterBitmap(paint), [&](SkScalar x, SkScalar y, const SkPaint& p) {
246 mRecorder.drawImage(image, x, y, &p, bitmap.palette());
247 });
248
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -0400249 if (!bitmap.isImmutable() && image.get() && !image->unique()) {
Stan Iliev0cc4e362017-05-18 14:21:23 -0400250 mDisplayList->mMutableImages.push_back(image.get());
251 }
Stan Iliev021693b2016-10-17 16:26:15 -0400252}
253
John Reck1bcacfd2017-11-03 10:12:19 -0700254void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop, float srcRight,
255 float srcBottom, float dstLeft, float dstTop, float dstRight,
Mike Reedc2dbc032019-07-25 12:28:29 -0400256 float dstBottom, const Paint* paint) {
Stan Iliev021693b2016-10-17 16:26:15 -0400257 SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
258 SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -0400259
Derek Sollenbergerd01b5912018-10-19 15:55:33 -0400260 sk_sp<SkImage> image = bitmap.makeImage();
Mike Reedc2dbc032019-07-25 12:28:29 -0400261
262 applyLooper(get_looper(paint), *filterBitmap(paint), [&](SkScalar x, SkScalar y, const SkPaint& p) {
263 mRecorder.drawImageRect(image, srcRect, dstRect.makeOffset(x, y), &p,
264 SkCanvas::kFast_SrcRectConstraint, bitmap.palette());
265 });
266
John Reck1bcacfd2017-11-03 10:12:19 -0700267 if (!bitmap.isImmutable() && image.get() && !image->unique() && !srcRect.isEmpty() &&
268 !dstRect.isEmpty()) {
Stan Iliev0cc4e362017-05-18 14:21:23 -0400269 mDisplayList->mMutableImages.push_back(image.get());
270 }
Stan Iliev021693b2016-10-17 16:26:15 -0400271}
272
John Reck1bcacfd2017-11-03 10:12:19 -0700273void SkiaRecordingCanvas::drawNinePatch(Bitmap& bitmap, const Res_png_9patch& chunk, float dstLeft,
274 float dstTop, float dstRight, float dstBottom,
Mike Reedc2dbc032019-07-25 12:28:29 -0400275 const Paint* paint) {
Stan Iliev021693b2016-10-17 16:26:15 -0400276 SkCanvas::Lattice lattice;
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -0400277 NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height());
Stan Iliev021693b2016-10-17 16:26:15 -0400278
Stan Ilieve12d7312017-12-04 14:48:27 -0500279 lattice.fRectTypes = nullptr;
280 lattice.fColors = nullptr;
Stan Iliev021693b2016-10-17 16:26:15 -0400281 int numFlags = 0;
282 if (chunk.numColors > 0 && chunk.numColors == NinePatchUtils::NumDistinctRects(lattice)) {
283 // We can expect the framework to give us a color for every distinct rect.
284 // Skia requires placeholder flags for degenerate rects.
285 numFlags = (lattice.fXCount + 1) * (lattice.fYCount + 1);
286 }
287
Stan Ilieve12d7312017-12-04 14:48:27 -0500288 SkAutoSTMalloc<25, SkCanvas::Lattice::RectType> flags(numFlags);
289 SkAutoSTMalloc<25, SkColor> colors(numFlags);
Stan Iliev021693b2016-10-17 16:26:15 -0400290 if (numFlags > 0) {
Stan Ilieve12d7312017-12-04 14:48:27 -0500291 NinePatchUtils::SetLatticeFlags(&lattice, flags.get(), numFlags, chunk, colors.get());
Stan Iliev021693b2016-10-17 16:26:15 -0400292 }
293
294 lattice.fBounds = nullptr;
295 SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
Stan Iliev021693b2016-10-17 16:26:15 -0400296
Ben Wagner0ed10be2018-06-28 17:08:16 -0400297 PaintCoW filteredPaint(paint);
Stan Iliev038fc372018-07-30 18:31:46 -0400298 // HWUI always draws 9-patches with bilinear filtering, regardless of what is set in the Paint.
299 if (!filteredPaint || filteredPaint->getFilterQuality() != kLow_SkFilterQuality) {
Ben Wagner0ed10be2018-06-28 17:08:16 -0400300 filteredPaint.writeable().setFilterQuality(kLow_SkFilterQuality);
Leon Scroggins III5a663762018-04-23 11:15:00 -0400301 }
Derek Sollenbergerd01b5912018-10-19 15:55:33 -0400302 sk_sp<SkImage> image = bitmap.makeImage();
Mike Reedc2dbc032019-07-25 12:28:29 -0400303
304 applyLooper(get_looper(paint), *filterBitmap(paint), [&](SkScalar x, SkScalar y, const SkPaint& p) {
305 mRecorder.drawImageLattice(image, lattice, dst.makeOffset(x, y), &p, bitmap.palette());
306 });
307
Derek Sollenbergerfb0c8fc2017-07-26 13:53:27 -0400308 if (!bitmap.isImmutable() && image.get() && !image->unique() && !dst.isEmpty()) {
Stan Iliev0cc4e362017-05-18 14:21:23 -0400309 mDisplayList->mMutableImages.push_back(image.get());
310 }
Stan Iliev021693b2016-10-17 16:26:15 -0400311}
312
Derek Sollenberger2d142132018-01-22 10:25:26 -0500313double SkiaRecordingCanvas::drawAnimatedImage(AnimatedImageDrawable* animatedImage) {
314 drawDrawable(animatedImage);
315 mDisplayList->mAnimatedImages.push_back(animatedImage);
316 return 0;
317}
318
Chris Blume7b8a8082018-11-30 15:51:58 -0800319} // namespace skiapipeline
320} // namespace uirenderer
321} // namespace android