blob: d966372a769904b6479f4e29ee6e68883422e5c5 [file] [log] [blame]
Chris Craikb565df12015-10-05 13:00:52 -07001/*
2 * Copyright (C) 2015 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 "RecordingCanvas.h"
18
Chris Craikd2dfd8f2015-12-16 14:27:20 -080019#include "DeferredLayerUpdater.h"
Chris Craikb565df12015-10-05 13:00:52 -070020#include "RecordedOp.h"
21#include "RenderNode.h"
Doris Liu766431a2016-02-04 22:17:11 +000022#include "VectorDrawable.h"
Yuqian Liafc221492016-07-18 13:07:42 -040023#include "hwui/MinikinUtils.h"
Chris Craikb565df12015-10-05 13:00:52 -070024
25namespace android {
26namespace uirenderer {
27
28RecordingCanvas::RecordingCanvas(size_t width, size_t height)
29 : mState(*this)
30 , mResourceCache(ResourceCache::getInstance()) {
Derek Sollenberger6f485562015-07-30 10:00:39 -040031 resetRecording(width, height);
Chris Craikb565df12015-10-05 13:00:52 -070032}
33
34RecordingCanvas::~RecordingCanvas() {
Chris Craik003cc3d2015-10-16 10:24:55 -070035 LOG_ALWAYS_FATAL_IF(mDisplayList,
Chris Craikb565df12015-10-05 13:00:52 -070036 "Destroyed a RecordingCanvas during a record!");
37}
38
Stan Ilievc0e7a902016-10-13 17:07:09 -040039void RecordingCanvas::resetRecording(int width, int height, RenderNode* node) {
Chris Craik003cc3d2015-10-16 10:24:55 -070040 LOG_ALWAYS_FATAL_IF(mDisplayList,
Chris Craikb565df12015-10-05 13:00:52 -070041 "prepareDirty called a second time during a recording!");
Chris Craik003cc3d2015-10-16 10:24:55 -070042 mDisplayList = new DisplayList();
Chris Craikb565df12015-10-05 13:00:52 -070043
Chris Craike4db79d2015-12-22 16:32:23 -080044 mState.initializeRecordingSaveStack(width, height);
Chris Craikb565df12015-10-05 13:00:52 -070045
Chris Craik161f54b2015-11-05 11:08:52 -080046 mDeferredBarrierType = DeferredBarrierType::InOrder;
Chris Craikb565df12015-10-05 13:00:52 -070047}
48
Chris Craik003cc3d2015-10-16 10:24:55 -070049DisplayList* RecordingCanvas::finishRecording() {
Chris Craikb87eadd2016-01-06 09:16:05 -080050 restoreToCount(1);
Chris Craikb565df12015-10-05 13:00:52 -070051 mPaintMap.clear();
52 mRegionMap.clear();
53 mPathMap.clear();
Chris Craik003cc3d2015-10-16 10:24:55 -070054 DisplayList* displayList = mDisplayList;
55 mDisplayList = nullptr;
Chris Craikb565df12015-10-05 13:00:52 -070056 mSkiaCanvasProxy.reset(nullptr);
Chris Craik003cc3d2015-10-16 10:24:55 -070057 return displayList;
Chris Craikb565df12015-10-05 13:00:52 -070058}
59
Chris Craikd6456402016-04-11 12:24:23 -070060void RecordingCanvas::insertReorderBarrier(bool enableReorder) {
61 if (enableReorder) {
62 mDeferredBarrierType = DeferredBarrierType::OutOfOrder;
63 mDeferredBarrierClip = getRecordedClip();
64 } else {
65 mDeferredBarrierType = DeferredBarrierType::InOrder;
66 mDeferredBarrierClip = nullptr;
67 }
68}
69
Chris Craikb565df12015-10-05 13:00:52 -070070SkCanvas* RecordingCanvas::asSkCanvas() {
Chris Craik003cc3d2015-10-16 10:24:55 -070071 LOG_ALWAYS_FATAL_IF(!mDisplayList,
Chris Craikb565df12015-10-05 13:00:52 -070072 "attempting to get an SkCanvas when we are not recording!");
73 if (!mSkiaCanvasProxy) {
74 mSkiaCanvasProxy.reset(new SkiaCanvasProxy(this));
75 }
76
77 // SkCanvas instances default to identity transform, but should inherit
78 // the state of this Canvas; if this code was in the SkiaCanvasProxy
79 // constructor, we couldn't cache mSkiaCanvasProxy.
80 SkMatrix parentTransform;
81 getMatrix(&parentTransform);
82 mSkiaCanvasProxy.get()->setMatrix(parentTransform);
83
84 return mSkiaCanvasProxy.get();
85}
86
87// ----------------------------------------------------------------------------
Chris Craik6fe991e52015-10-20 09:39:42 -070088// CanvasStateClient implementation
89// ----------------------------------------------------------------------------
90
91void RecordingCanvas::onViewportInitialized() {
Chris Craik6fe991e52015-10-20 09:39:42 -070092}
93
94void RecordingCanvas::onSnapshotRestored(const Snapshot& removed, const Snapshot& restored) {
95 if (removed.flags & Snapshot::kFlagIsFboLayer) {
John Reck7df9ff22016-02-10 16:08:08 -080096 addOp(alloc().create_trivial<EndLayerOp>());
Chris Craikb87eadd2016-01-06 09:16:05 -080097 } else if (removed.flags & Snapshot::kFlagIsLayer) {
John Reck7df9ff22016-02-10 16:08:08 -080098 addOp(alloc().create_trivial<EndUnclippedLayerOp>());
Chris Craik6fe991e52015-10-20 09:39:42 -070099 }
100}
101
102// ----------------------------------------------------------------------------
Chris Craikb565df12015-10-05 13:00:52 -0700103// android/graphics/Canvas state operations
104// ----------------------------------------------------------------------------
105// Save (layer)
Florin Malitaeecff562015-12-21 10:43:01 -0500106int RecordingCanvas::save(SaveFlags::Flags flags) {
Chris Craikb565df12015-10-05 13:00:52 -0700107 return mState.save((int) flags);
108}
109
110void RecordingCanvas::RecordingCanvas::restore() {
Chris Craikb565df12015-10-05 13:00:52 -0700111 mState.restore();
112}
113
114void RecordingCanvas::restoreToCount(int saveCount) {
Chris Craikb565df12015-10-05 13:00:52 -0700115 mState.restoreToCount(saveCount);
116}
117
Chris Craikb87eadd2016-01-06 09:16:05 -0800118int RecordingCanvas::saveLayer(float left, float top, float right, float bottom,
Florin Malitaeecff562015-12-21 10:43:01 -0500119 const SkPaint* paint, SaveFlags::Flags flags) {
Chris Craik6fe991e52015-10-20 09:39:42 -0700120 // force matrix/clip isolation for layer
Florin Malitaeecff562015-12-21 10:43:01 -0500121 flags |= SaveFlags::MatrixClip;
122 bool clippedLayer = flags & SaveFlags::ClipToLayer;
Chris Craik6fe991e52015-10-20 09:39:42 -0700123
124 const Snapshot& previous = *mState.currentSnapshot();
125
126 // initialize the snapshot as though it almost represents an FBO layer so deferred draw
127 // operations will be able to store and restore the current clip and transform info, and
128 // quick rejection will be correct (for display lists)
129
Chris Craike4f6d962016-06-27 16:30:27 -0700130 Rect unmappedBounds(left, top, right, bottom);
131 unmappedBounds.roundOut();
Chris Craik6fe991e52015-10-20 09:39:42 -0700132
133 // determine clipped bounds relative to previous viewport.
Chris Craikb87eadd2016-01-06 09:16:05 -0800134 Rect visibleBounds = unmappedBounds;
Chris Craik6fe991e52015-10-20 09:39:42 -0700135 previous.transform->mapRect(visibleBounds);
136
Chris Craikb87eadd2016-01-06 09:16:05 -0800137 if (CC_UNLIKELY(!clippedLayer
138 && previous.transform->rectToRect()
139 && visibleBounds.contains(previous.getRenderTargetClip()))) {
140 // unlikely case where an unclipped savelayer is recorded with a clip it can use,
141 // as none of its unaffected/unclipped area is visible
142 clippedLayer = true;
Florin Malitaeecff562015-12-21 10:43:01 -0500143 flags |= SaveFlags::ClipToLayer;
Chris Craikb87eadd2016-01-06 09:16:05 -0800144 }
Chris Craik6fe991e52015-10-20 09:39:42 -0700145
146 visibleBounds.doIntersect(previous.getRenderTargetClip());
147 visibleBounds.snapToPixelBoundaries();
Chris Craikb87eadd2016-01-06 09:16:05 -0800148 visibleBounds.doIntersect(Rect(previous.getViewportWidth(), previous.getViewportHeight()));
Chris Craik6fe991e52015-10-20 09:39:42 -0700149
150 // Map visible bounds back to layer space, and intersect with parameter bounds
151 Rect layerBounds = visibleBounds;
Chris Craik3c53ec512016-08-08 15:15:57 -0700152 if (CC_LIKELY(!layerBounds.isEmpty())) {
153 // if non-empty, can safely map by the inverse transform
154 Matrix4 inverse;
155 inverse.loadInverse(*previous.transform);
156 inverse.mapRect(layerBounds);
157 layerBounds.doIntersect(unmappedBounds);
158 }
Chris Craik6fe991e52015-10-20 09:39:42 -0700159
160 int saveValue = mState.save((int) flags);
161 Snapshot& snapshot = *mState.writableSnapshot();
162
Chris Craikb87eadd2016-01-06 09:16:05 -0800163 // layerBounds is in original bounds space, but clipped by current recording clip
Chris Craik3c53ec512016-08-08 15:15:57 -0700164 if (!layerBounds.isEmpty() && !unmappedBounds.isEmpty()) {
Chris Craikb87eadd2016-01-06 09:16:05 -0800165 if (CC_LIKELY(clippedLayer)) {
Chris Craik3c53ec512016-08-08 15:15:57 -0700166 auto previousClip = getRecordedClip(); // capture before new snapshot clip has changed
167 if (addOp(alloc().create_trivial<BeginLayerOp>(
168 unmappedBounds,
169 *previous.transform, // transform to *draw* with
170 previousClip, // clip to *draw* with
171 refPaint(paint))) >= 0) {
172 snapshot.flags |= Snapshot::kFlagIsLayer | Snapshot::kFlagIsFboLayer;
173 snapshot.initializeViewport(unmappedBounds.getWidth(), unmappedBounds.getHeight());
174 snapshot.transform->loadTranslate(-unmappedBounds.left, -unmappedBounds.top, 0.0f);
175
176 Rect clip = layerBounds;
177 clip.translate(-unmappedBounds.left, -unmappedBounds.top);
178 snapshot.resetClip(clip.left, clip.top, clip.right, clip.bottom);
179 snapshot.roundRectClipState = nullptr;
180 return saveValue;
181 }
182 } else {
183 if (addOp(alloc().create_trivial<BeginUnclippedLayerOp>(
184 unmappedBounds,
185 *mState.currentSnapshot()->transform,
186 getRecordedClip(),
187 refPaint(paint))) >= 0) {
188 snapshot.flags |= Snapshot::kFlagIsLayer;
189 return saveValue;
190 }
Chris Craikb87eadd2016-01-06 09:16:05 -0800191 }
Chris Craik6fe991e52015-10-20 09:39:42 -0700192 }
193
Chris Craik3c53ec512016-08-08 15:15:57 -0700194 // Layer not needed, so skip recording it...
Chris Craikb87eadd2016-01-06 09:16:05 -0800195 if (CC_LIKELY(clippedLayer)) {
Chris Craik3c53ec512016-08-08 15:15:57 -0700196 // ... and set empty clip to reject inner content, if possible
197 snapshot.resetClip(0, 0, 0, 0);
Chris Craikb87eadd2016-01-06 09:16:05 -0800198 }
Chris Craik6fe991e52015-10-20 09:39:42 -0700199 return saveValue;
Chris Craikb565df12015-10-05 13:00:52 -0700200}
201
202// Matrix
203void RecordingCanvas::rotate(float degrees) {
204 if (degrees == 0) return;
205
206 mState.rotate(degrees);
207}
208
209void RecordingCanvas::scale(float sx, float sy) {
210 if (sx == 1 && sy == 1) return;
211
212 mState.scale(sx, sy);
213}
214
215void RecordingCanvas::skew(float sx, float sy) {
216 mState.skew(sx, sy);
217}
218
219void RecordingCanvas::translate(float dx, float dy) {
220 if (dx == 0 && dy == 0) return;
221
222 mState.translate(dx, dy, 0);
223}
224
225// Clip
226bool RecordingCanvas::getClipBounds(SkRect* outRect) const {
Chris Craike29ce6f2015-12-10 16:25:13 -0800227 *outRect = mState.getLocalClipBounds().toSkRect();
Chris Craikb565df12015-10-05 13:00:52 -0700228 return !(outRect->isEmpty());
229}
230bool RecordingCanvas::quickRejectRect(float left, float top, float right, float bottom) const {
231 return mState.quickRejectConservative(left, top, right, bottom);
232}
233bool RecordingCanvas::quickRejectPath(const SkPath& path) const {
234 SkRect bounds = path.getBounds();
235 return mState.quickRejectConservative(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom);
236}
Mike Reed6e49c9f2016-12-02 15:36:59 -0500237bool RecordingCanvas::clipRect(float left, float top, float right, float bottom, SkClipOp op) {
Chris Craikb565df12015-10-05 13:00:52 -0700238 return mState.clipRect(left, top, right, bottom, op);
239}
Mike Reed6e49c9f2016-12-02 15:36:59 -0500240bool RecordingCanvas::clipPath(const SkPath* path, SkClipOp op) {
Chris Craikb565df12015-10-05 13:00:52 -0700241 return mState.clipPath(path, op);
242}
Chris Craikb565df12015-10-05 13:00:52 -0700243
244// ----------------------------------------------------------------------------
245// android/graphics/Canvas draw operations
246// ----------------------------------------------------------------------------
Mike Reed260ab722016-10-07 15:59:20 -0400247void RecordingCanvas::drawColor(int color, SkBlendMode mode) {
Chris Craika2048482016-03-25 14:17:49 -0700248 addOp(alloc().create_trivial<ColorOp>(
249 getRecordedClip(),
250 color,
251 mode));
Chris Craikb565df12015-10-05 13:00:52 -0700252}
253
254void RecordingCanvas::drawPaint(const SkPaint& paint) {
Chris Craik4c3980b2016-03-15 14:20:18 -0700255 SkRect bounds;
256 if (getClipBounds(&bounds)) {
257 drawRect(bounds.fLeft, bounds.fTop, bounds.fRight, bounds.fBottom, paint);
258 }
Chris Craikb565df12015-10-05 13:00:52 -0700259}
260
Chris Craik386aa032015-12-07 17:08:25 -0800261static Rect calcBoundsOfPoints(const float* points, int floatCount) {
262 Rect unmappedBounds(points[0], points[1], points[0], points[1]);
263 for (int i = 2; i < floatCount; i += 2) {
264 unmappedBounds.expandToCover(points[i], points[i + 1]);
265 }
266 return unmappedBounds;
267}
268
Chris Craikb565df12015-10-05 13:00:52 -0700269// Geometry
Chris Craik386aa032015-12-07 17:08:25 -0800270void RecordingCanvas::drawPoints(const float* points, int floatCount, const SkPaint& paint) {
Derek Sollenberger792fb322017-03-03 14:02:09 -0500271 if (CC_UNLIKELY(floatCount < 2 || paint.nothingToDraw())) return;
Chris Craik386aa032015-12-07 17:08:25 -0800272 floatCount &= ~0x1; // round down to nearest two
273
John Reck7df9ff22016-02-10 16:08:08 -0800274 addOp(alloc().create_trivial<PointsOp>(
Chris Craik386aa032015-12-07 17:08:25 -0800275 calcBoundsOfPoints(points, floatCount),
276 *mState.currentSnapshot()->transform,
Chris Craike4db79d2015-12-22 16:32:23 -0800277 getRecordedClip(),
Chris Craik386aa032015-12-07 17:08:25 -0800278 refPaint(&paint), refBuffer<float>(points, floatCount), floatCount));
Chris Craikb565df12015-10-05 13:00:52 -0700279}
Chris Craika1717272015-11-19 13:02:43 -0800280
281void RecordingCanvas::drawLines(const float* points, int floatCount, const SkPaint& paint) {
Derek Sollenberger792fb322017-03-03 14:02:09 -0500282 if (CC_UNLIKELY(floatCount < 4 || paint.nothingToDraw())) return;
Chris Craika1717272015-11-19 13:02:43 -0800283 floatCount &= ~0x3; // round down to nearest four
284
John Reck7df9ff22016-02-10 16:08:08 -0800285 addOp(alloc().create_trivial<LinesOp>(
Chris Craik386aa032015-12-07 17:08:25 -0800286 calcBoundsOfPoints(points, floatCount),
Chris Craika1717272015-11-19 13:02:43 -0800287 *mState.currentSnapshot()->transform,
Chris Craike4db79d2015-12-22 16:32:23 -0800288 getRecordedClip(),
Chris Craika1717272015-11-19 13:02:43 -0800289 refPaint(&paint), refBuffer<float>(points, floatCount), floatCount));
Chris Craikb565df12015-10-05 13:00:52 -0700290}
Chris Craika1717272015-11-19 13:02:43 -0800291
Chris Craikb565df12015-10-05 13:00:52 -0700292void RecordingCanvas::drawRect(float left, float top, float right, float bottom, const SkPaint& paint) {
Derek Sollenberger792fb322017-03-03 14:02:09 -0500293 if (CC_UNLIKELY(paint.nothingToDraw())) return;
Chris Craik814ee6a92016-07-26 16:22:50 -0700294
John Reck7df9ff22016-02-10 16:08:08 -0800295 addOp(alloc().create_trivial<RectOp>(
Chris Craikb565df12015-10-05 13:00:52 -0700296 Rect(left, top, right, bottom),
297 *(mState.currentSnapshot()->transform),
Chris Craike4db79d2015-12-22 16:32:23 -0800298 getRecordedClip(),
Chris Craikb565df12015-10-05 13:00:52 -0700299 refPaint(&paint)));
300}
301
302void RecordingCanvas::drawSimpleRects(const float* rects, int vertexCount, const SkPaint* paint) {
303 if (rects == nullptr) return;
304
Chris Craik7a896002016-02-19 15:51:02 -0800305 Vertex* rectData = (Vertex*) mDisplayList->allocator.create_trivial_array<Vertex>(vertexCount);
Chris Craikb565df12015-10-05 13:00:52 -0700306 Vertex* vertex = rectData;
307
308 float left = FLT_MAX;
309 float top = FLT_MAX;
310 float right = FLT_MIN;
311 float bottom = FLT_MIN;
312 for (int index = 0; index < vertexCount; index += 4) {
313 float l = rects[index + 0];
314 float t = rects[index + 1];
315 float r = rects[index + 2];
316 float b = rects[index + 3];
317
318 Vertex::set(vertex++, l, t);
319 Vertex::set(vertex++, r, t);
320 Vertex::set(vertex++, l, b);
321 Vertex::set(vertex++, r, b);
322
323 left = std::min(left, l);
324 top = std::min(top, t);
325 right = std::max(right, r);
326 bottom = std::max(bottom, b);
327 }
John Reck7df9ff22016-02-10 16:08:08 -0800328 addOp(alloc().create_trivial<SimpleRectsOp>(
Chris Craikb565df12015-10-05 13:00:52 -0700329 Rect(left, top, right, bottom),
330 *(mState.currentSnapshot()->transform),
Chris Craike4db79d2015-12-22 16:32:23 -0800331 getRecordedClip(),
Chris Craikb565df12015-10-05 13:00:52 -0700332 refPaint(paint), rectData, vertexCount));
333}
334
335void RecordingCanvas::drawRegion(const SkRegion& region, const SkPaint& paint) {
Derek Sollenberger792fb322017-03-03 14:02:09 -0500336 if (CC_UNLIKELY(paint.nothingToDraw())) return;
Chris Craik814ee6a92016-07-26 16:22:50 -0700337
Chris Craikb565df12015-10-05 13:00:52 -0700338 if (paint.getStyle() == SkPaint::kFill_Style
339 && (!paint.isAntiAlias() || mState.currentTransform()->isSimple())) {
340 int count = 0;
341 Vector<float> rects;
342 SkRegion::Iterator it(region);
343 while (!it.done()) {
344 const SkIRect& r = it.rect();
345 rects.push(r.fLeft);
346 rects.push(r.fTop);
347 rects.push(r.fRight);
348 rects.push(r.fBottom);
349 count += 4;
350 it.next();
351 }
352 drawSimpleRects(rects.array(), count, &paint);
353 } else {
354 SkRegion::Iterator it(region);
355 while (!it.done()) {
356 const SkIRect& r = it.rect();
357 drawRect(r.fLeft, r.fTop, r.fRight, r.fBottom, paint);
358 it.next();
359 }
360 }
361}
Chris Craik814ee6a92016-07-26 16:22:50 -0700362
Chris Craikb565df12015-10-05 13:00:52 -0700363void RecordingCanvas::drawRoundRect(float left, float top, float right, float bottom,
364 float rx, float ry, const SkPaint& paint) {
Derek Sollenberger792fb322017-03-03 14:02:09 -0500365 if (CC_UNLIKELY(paint.nothingToDraw())) return;
Chris Craik814ee6a92016-07-26 16:22:50 -0700366
Chris Craik2dbb4c42016-03-11 18:58:37 -0800367 if (CC_LIKELY(MathUtils::isPositive(rx) || MathUtils::isPositive(ry))) {
368 addOp(alloc().create_trivial<RoundRectOp>(
369 Rect(left, top, right, bottom),
370 *(mState.currentSnapshot()->transform),
371 getRecordedClip(),
372 refPaint(&paint), rx, ry));
373 } else {
374 drawRect(left, top, right, bottom, paint);
375 }
Chris Craikb565df12015-10-05 13:00:52 -0700376}
Chris Craik386aa032015-12-07 17:08:25 -0800377
Chris Craik268a9c02015-12-09 18:05:12 -0800378void RecordingCanvas::drawRoundRect(
379 CanvasPropertyPrimitive* left, CanvasPropertyPrimitive* top,
380 CanvasPropertyPrimitive* right, CanvasPropertyPrimitive* bottom,
381 CanvasPropertyPrimitive* rx, CanvasPropertyPrimitive* ry,
382 CanvasPropertyPaint* paint) {
383 mDisplayList->ref(left);
384 mDisplayList->ref(top);
385 mDisplayList->ref(right);
386 mDisplayList->ref(bottom);
387 mDisplayList->ref(rx);
388 mDisplayList->ref(ry);
389 mDisplayList->ref(paint);
390 refBitmapsInShader(paint->value.getShader());
John Reck7df9ff22016-02-10 16:08:08 -0800391 addOp(alloc().create_trivial<RoundRectPropsOp>(
Chris Craik268a9c02015-12-09 18:05:12 -0800392 *(mState.currentSnapshot()->transform),
Chris Craike4db79d2015-12-22 16:32:23 -0800393 getRecordedClip(),
Chris Craik268a9c02015-12-09 18:05:12 -0800394 &paint->value,
395 &left->value, &top->value, &right->value, &bottom->value,
396 &rx->value, &ry->value));
397}
398
Chris Craikb565df12015-10-05 13:00:52 -0700399void RecordingCanvas::drawCircle(float x, float y, float radius, const SkPaint& paint) {
Chris Craik268a9c02015-12-09 18:05:12 -0800400 // TODO: move to Canvas.h
Derek Sollenberger792fb322017-03-03 14:02:09 -0500401 if (CC_UNLIKELY(radius <= 0 || paint.nothingToDraw())) return;
Chris Craik814ee6a92016-07-26 16:22:50 -0700402
Chris Craik386aa032015-12-07 17:08:25 -0800403 drawOval(x - radius, y - radius, x + radius, y + radius, paint);
Chris Craikb565df12015-10-05 13:00:52 -0700404}
Chris Craik386aa032015-12-07 17:08:25 -0800405
Chris Craik268a9c02015-12-09 18:05:12 -0800406void RecordingCanvas::drawCircle(
407 CanvasPropertyPrimitive* x, CanvasPropertyPrimitive* y,
408 CanvasPropertyPrimitive* radius, CanvasPropertyPaint* paint) {
409 mDisplayList->ref(x);
410 mDisplayList->ref(y);
411 mDisplayList->ref(radius);
412 mDisplayList->ref(paint);
413 refBitmapsInShader(paint->value.getShader());
John Reck7df9ff22016-02-10 16:08:08 -0800414 addOp(alloc().create_trivial<CirclePropsOp>(
Chris Craik268a9c02015-12-09 18:05:12 -0800415 *(mState.currentSnapshot()->transform),
Chris Craike4db79d2015-12-22 16:32:23 -0800416 getRecordedClip(),
Chris Craik268a9c02015-12-09 18:05:12 -0800417 &paint->value,
418 &x->value, &y->value, &radius->value));
419}
420
Chris Craikb565df12015-10-05 13:00:52 -0700421void RecordingCanvas::drawOval(float left, float top, float right, float bottom, const SkPaint& paint) {
Derek Sollenberger792fb322017-03-03 14:02:09 -0500422 if (CC_UNLIKELY(paint.nothingToDraw())) return;
Chris Craik814ee6a92016-07-26 16:22:50 -0700423
John Reck7df9ff22016-02-10 16:08:08 -0800424 addOp(alloc().create_trivial<OvalOp>(
Chris Craik386aa032015-12-07 17:08:25 -0800425 Rect(left, top, right, bottom),
426 *(mState.currentSnapshot()->transform),
Chris Craike4db79d2015-12-22 16:32:23 -0800427 getRecordedClip(),
Chris Craik386aa032015-12-07 17:08:25 -0800428 refPaint(&paint)));
Chris Craikb565df12015-10-05 13:00:52 -0700429}
Chris Craik386aa032015-12-07 17:08:25 -0800430
Chris Craikb565df12015-10-05 13:00:52 -0700431void RecordingCanvas::drawArc(float left, float top, float right, float bottom,
Chris Craik386aa032015-12-07 17:08:25 -0800432 float startAngle, float sweepAngle, bool useCenter, const SkPaint& paint) {
Derek Sollenberger792fb322017-03-03 14:02:09 -0500433 if (CC_UNLIKELY(paint.nothingToDraw())) return;
Chris Craik814ee6a92016-07-26 16:22:50 -0700434
Chris Craikcaa24182016-02-19 15:20:35 -0800435 if (fabs(sweepAngle) >= 360.0f) {
436 drawOval(left, top, right, bottom, paint);
437 } else {
438 addOp(alloc().create_trivial<ArcOp>(
439 Rect(left, top, right, bottom),
440 *(mState.currentSnapshot()->transform),
441 getRecordedClip(),
442 refPaint(&paint),
443 startAngle, sweepAngle, useCenter));
444 }
Chris Craikb565df12015-10-05 13:00:52 -0700445}
Chris Craik386aa032015-12-07 17:08:25 -0800446
Chris Craikb565df12015-10-05 13:00:52 -0700447void RecordingCanvas::drawPath(const SkPath& path, const SkPaint& paint) {
Derek Sollenberger792fb322017-03-03 14:02:09 -0500448 if (CC_UNLIKELY(paint.nothingToDraw())) return;
Chris Craik814ee6a92016-07-26 16:22:50 -0700449
John Reck7df9ff22016-02-10 16:08:08 -0800450 addOp(alloc().create_trivial<PathOp>(
Chris Craik386aa032015-12-07 17:08:25 -0800451 Rect(path.getBounds()),
452 *(mState.currentSnapshot()->transform),
Chris Craike4db79d2015-12-22 16:32:23 -0800453 getRecordedClip(),
Chris Craik386aa032015-12-07 17:08:25 -0800454 refPaint(&paint), refPath(&path)));
Chris Craikb565df12015-10-05 13:00:52 -0700455}
456
Doris Liu766431a2016-02-04 22:17:11 +0000457void RecordingCanvas::drawVectorDrawable(VectorDrawableRoot* tree) {
458 mDisplayList->ref(tree);
Doris Liu718cd3e2016-05-17 16:50:31 -0700459 mDisplayList->vectorDrawables.push_back(tree);
John Reck7df9ff22016-02-10 16:08:08 -0800460 addOp(alloc().create_trivial<VectorDrawableOp>(
Doris Liu766431a2016-02-04 22:17:11 +0000461 tree,
Doris Liu1d8e1942016-03-02 15:16:28 -0800462 Rect(tree->stagingProperties()->getBounds()),
Doris Liu766431a2016-02-04 22:17:11 +0000463 *(mState.currentSnapshot()->transform),
464 getRecordedClip()));
465}
466
Chris Craikb565df12015-10-05 13:00:52 -0700467// Bitmap-based
sergeyvaed7f582016-10-14 16:30:21 -0700468void RecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) {
Florin Malitaeecff562015-12-21 10:43:01 -0500469 save(SaveFlags::Matrix);
Chris Craikb565df12015-10-05 13:00:52 -0700470 translate(left, top);
sergeyvec4a4b12016-10-20 18:39:04 -0700471 drawBitmap(bitmap, paint);
Chris Craikb565df12015-10-05 13:00:52 -0700472 restore();
473}
474
sergeyvec4a4b12016-10-20 18:39:04 -0700475void RecordingCanvas::drawBitmap(Bitmap& bitmap, const SkMatrix& matrix,
Chris Craikb565df12015-10-05 13:00:52 -0700476 const SkPaint* paint) {
477 if (matrix.isIdentity()) {
sergeyvec4a4b12016-10-20 18:39:04 -0700478 drawBitmap(bitmap, paint);
Chris Craikb565df12015-10-05 13:00:52 -0700479 } else if (!(matrix.getType() & ~(SkMatrix::kScale_Mask | SkMatrix::kTranslate_Mask))
480 && MathUtils::isPositive(matrix.getScaleX())
481 && MathUtils::isPositive(matrix.getScaleY())) {
482 // SkMatrix::isScaleTranslate() not available in L
483 SkRect src;
484 SkRect dst;
485 bitmap.getBounds(&src);
486 matrix.mapRect(&dst, src);
sergeyvec4a4b12016-10-20 18:39:04 -0700487 drawBitmap(bitmap, src.fLeft, src.fTop, src.fRight, src.fBottom,
Chris Craikb565df12015-10-05 13:00:52 -0700488 dst.fLeft, dst.fTop, dst.fRight, dst.fBottom, paint);
489 } else {
Florin Malitaeecff562015-12-21 10:43:01 -0500490 save(SaveFlags::Matrix);
Chris Craikb565df12015-10-05 13:00:52 -0700491 concat(matrix);
sergeyvec4a4b12016-10-20 18:39:04 -0700492 drawBitmap(bitmap, paint);
Chris Craikb565df12015-10-05 13:00:52 -0700493 restore();
494 }
495}
Chris Craik386aa032015-12-07 17:08:25 -0800496
sergeyvec4a4b12016-10-20 18:39:04 -0700497void RecordingCanvas::drawBitmap(Bitmap& bitmap, float srcLeft, float srcTop,
Chris Craikb565df12015-10-05 13:00:52 -0700498 float srcRight, float srcBottom, float dstLeft, float dstTop,
499 float dstRight, float dstBottom, const SkPaint* paint) {
500 if (srcLeft == 0 && srcTop == 0
501 && srcRight == bitmap.width()
502 && srcBottom == bitmap.height()
503 && (srcBottom - srcTop == dstBottom - dstTop)
504 && (srcRight - srcLeft == dstRight - dstLeft)) {
505 // transform simple rect to rect drawing case into position bitmap ops, since they merge
Florin Malitaeecff562015-12-21 10:43:01 -0500506 save(SaveFlags::Matrix);
Chris Craikb565df12015-10-05 13:00:52 -0700507 translate(dstLeft, dstTop);
sergeyvec4a4b12016-10-20 18:39:04 -0700508 drawBitmap(bitmap, paint);
Chris Craikb565df12015-10-05 13:00:52 -0700509 restore();
510 } else {
John Reck7df9ff22016-02-10 16:08:08 -0800511 addOp(alloc().create_trivial<BitmapRectOp>(
Chris Craikf09ff5a2015-12-08 17:21:58 -0800512 Rect(dstLeft, dstTop, dstRight, dstBottom),
513 *(mState.currentSnapshot()->transform),
Chris Craike4db79d2015-12-22 16:32:23 -0800514 getRecordedClip(),
Chris Craikf09ff5a2015-12-08 17:21:58 -0800515 refPaint(paint), refBitmap(bitmap),
516 Rect(srcLeft, srcTop, srcRight, srcBottom)));
Chris Craikb565df12015-10-05 13:00:52 -0700517 }
518}
Chris Craik386aa032015-12-07 17:08:25 -0800519
sergeyvec4a4b12016-10-20 18:39:04 -0700520void RecordingCanvas::drawBitmapMesh(Bitmap& bitmap, int meshWidth, int meshHeight,
Chris Craikb565df12015-10-05 13:00:52 -0700521 const float* vertices, const int* colors, const SkPaint* paint) {
Chris Craikf09ff5a2015-12-08 17:21:58 -0800522 int vertexCount = (meshWidth + 1) * (meshHeight + 1);
John Reck7df9ff22016-02-10 16:08:08 -0800523 addOp(alloc().create_trivial<BitmapMeshOp>(
Chris Craikf09ff5a2015-12-08 17:21:58 -0800524 calcBoundsOfPoints(vertices, vertexCount * 2),
525 *(mState.currentSnapshot()->transform),
Chris Craike4db79d2015-12-22 16:32:23 -0800526 getRecordedClip(),
Chris Craikf09ff5a2015-12-08 17:21:58 -0800527 refPaint(paint), refBitmap(bitmap), meshWidth, meshHeight,
528 refBuffer<float>(vertices, vertexCount * 2), // 2 floats per vertex
529 refBuffer<int>(colors, vertexCount))); // 1 color per vertex
Chris Craikb565df12015-10-05 13:00:52 -0700530}
Chris Craik386aa032015-12-07 17:08:25 -0800531
sergeyvec4a4b12016-10-20 18:39:04 -0700532void RecordingCanvas::drawNinePatch(Bitmap& bitmap, const android::Res_png_9patch& patch,
Chris Craikb565df12015-10-05 13:00:52 -0700533 float dstLeft, float dstTop, float dstRight, float dstBottom,
534 const SkPaint* paint) {
John Reck7df9ff22016-02-10 16:08:08 -0800535 addOp(alloc().create_trivial<PatchOp>(
Chris Craikf09ff5a2015-12-08 17:21:58 -0800536 Rect(dstLeft, dstTop, dstRight, dstBottom),
537 *(mState.currentSnapshot()->transform),
Chris Craike4db79d2015-12-22 16:32:23 -0800538 getRecordedClip(),
Chris Craikf09ff5a2015-12-08 17:21:58 -0800539 refPaint(paint), refBitmap(bitmap), refPatch(&patch)));
Chris Craikb565df12015-10-05 13:00:52 -0700540}
541
542// Text
Stan Iliev0b58d992017-03-30 18:22:27 -0400543void RecordingCanvas::drawGlyphs(ReadGlyphFunc glyphFunc, int glyphCount, const SkPaint& paint,
544 float x, float y, float boundsLeft, float boundsTop, float boundsRight, float boundsBottom,
545 float totalAdvance) {
546 if (glyphCount <= 0 || paint.nothingToDraw()) return;
547 uint16_t* glyphs = (glyph_t*)alloc().alloc<glyph_t>(glyphCount * sizeof(glyph_t));
548 float* positions = (float*)alloc().alloc<float>(2 * glyphCount * sizeof(float));
549 glyphFunc(glyphs, positions);
Chris Craika1717272015-11-19 13:02:43 -0800550
Chris Craik15c3f192015-12-03 12:16:56 -0800551 // TODO: either must account for text shadow in bounds, or record separate ops for text shadows
John Reck7df9ff22016-02-10 16:08:08 -0800552 addOp(alloc().create_trivial<TextOp>(
Chris Craika1717272015-11-19 13:02:43 -0800553 Rect(boundsLeft, boundsTop, boundsRight, boundsBottom),
554 *(mState.currentSnapshot()->transform),
Chris Craike4db79d2015-12-22 16:32:23 -0800555 getRecordedClip(),
Chris Craika1717272015-11-19 13:02:43 -0800556 refPaint(&paint), glyphs, positions, glyphCount, x, y));
557 drawTextDecorations(x, y, totalAdvance, paint);
Chris Craikb565df12015-10-05 13:00:52 -0700558}
Chris Craika1717272015-11-19 13:02:43 -0800559
Yuqian Liafc221492016-07-18 13:07:42 -0400560void RecordingCanvas::drawLayoutOnPath(const minikin::Layout& layout, float hOffset, float vOffset,
561 const SkPaint& paint, const SkPath& path, size_t start, size_t end) {
562 uint16_t glyphs[1];
563 for (size_t i = start; i < end; i++) {
564 glyphs[0] = layout.getGlyphId(i);
565 float x = hOffset + layout.getX(i);
566 float y = vOffset + layout.getY(i);
Derek Sollenberger792fb322017-03-03 14:02:09 -0500567 if (paint.nothingToDraw()) return;
Yuqian Liafc221492016-07-18 13:07:42 -0400568 const uint16_t* tempGlyphs = refBuffer<glyph_t>(glyphs, 1);
569 addOp(alloc().create_trivial<TextOnPathOp>(
570 *(mState.currentSnapshot()->transform),
571 getRecordedClip(),
572 refPaint(&paint), tempGlyphs, 1, refPath(&path), x, y));
573 }
Chris Craikb565df12015-10-05 13:00:52 -0700574}
575
sergeyvec4a4b12016-10-20 18:39:04 -0700576void RecordingCanvas::drawBitmap(Bitmap& bitmap, const SkPaint* paint) {
John Reck7df9ff22016-02-10 16:08:08 -0800577 addOp(alloc().create_trivial<BitmapOp>(
sergeyvec4a4b12016-10-20 18:39:04 -0700578 Rect(bitmap.width(), bitmap.height()),
Chris Craikb565df12015-10-05 13:00:52 -0700579 *(mState.currentSnapshot()->transform),
Chris Craike4db79d2015-12-22 16:32:23 -0800580 getRecordedClip(),
sergeyvec4a4b12016-10-20 18:39:04 -0700581 refPaint(paint), refBitmap(bitmap)));
Chris Craikb565df12015-10-05 13:00:52 -0700582}
Chris Craike29ce6f2015-12-10 16:25:13 -0800583
Chris Craikb565df12015-10-05 13:00:52 -0700584void RecordingCanvas::drawRenderNode(RenderNode* renderNode) {
Chris Craik54fa17f2015-11-25 14:14:53 -0800585 auto&& stagingProps = renderNode->stagingProperties();
John Reck7df9ff22016-02-10 16:08:08 -0800586 RenderNodeOp* op = alloc().create_trivial<RenderNodeOp>(
Chris Craik54fa17f2015-11-25 14:14:53 -0800587 Rect(stagingProps.getWidth(), stagingProps.getHeight()),
Chris Craikb565df12015-10-05 13:00:52 -0700588 *(mState.currentSnapshot()->transform),
Chris Craike4db79d2015-12-22 16:32:23 -0800589 getRecordedClip(),
Chris Craikb565df12015-10-05 13:00:52 -0700590 renderNode);
591 int opIndex = addOp(op);
Chris Craik1367d252016-03-10 15:43:13 -0800592 if (CC_LIKELY(opIndex >= 0)) {
593 int childIndex = mDisplayList->addChild(op);
Chris Craikb565df12015-10-05 13:00:52 -0700594
Chris Craik1367d252016-03-10 15:43:13 -0800595 // update the chunk's child indices
596 DisplayList::Chunk& chunk = mDisplayList->chunks.back();
597 chunk.endChildIndex = childIndex + 1;
Chris Craikb565df12015-10-05 13:00:52 -0700598
Chris Craik1367d252016-03-10 15:43:13 -0800599 if (renderNode->stagingProperties().isProjectionReceiver()) {
600 // use staging property, since recording on UI thread
601 mDisplayList->projectionReceiveIndex = opIndex;
602 }
Chris Craikb565df12015-10-05 13:00:52 -0700603 }
604}
605
Chris Craikd2dfd8f2015-12-16 14:27:20 -0800606void RecordingCanvas::drawLayer(DeferredLayerUpdater* layerHandle) {
607 // We ref the DeferredLayerUpdater due to its thread-safe ref-counting semantics.
608 mDisplayList->ref(layerHandle);
609
sergeyv3e9999b2017-01-19 15:37:02 -0800610 LOG_ALWAYS_FATAL_IF(layerHandle->getBackingLayerApi() != Layer::Api::OpenGL);
John Reck417ed6d2016-03-22 16:01:08 -0700611 // Note that the backing layer has *not* yet been updated, so don't trust
612 // its width, height, transform, etc...!
John Reck7df9ff22016-02-10 16:08:08 -0800613 addOp(alloc().create_trivial<TextureLayerOp>(
John Reck417ed6d2016-03-22 16:01:08 -0700614 Rect(layerHandle->getWidth(), layerHandle->getHeight()),
Chris Craikaafb01d2016-03-25 18:34:11 -0700615 *(mState.currentSnapshot()->transform),
sergeyv3e9999b2017-01-19 15:37:02 -0800616 getRecordedClip(), layerHandle));
Chris Craikd2dfd8f2015-12-16 14:27:20 -0800617}
618
John Reckcd1c3eb2016-04-14 10:38:54 -0700619void RecordingCanvas::callDrawGLFunction(Functor* functor,
620 GlFunctorLifecycleListener* listener) {
621 mDisplayList->functors.push_back({functor, listener});
622 mDisplayList->ref(listener);
John Reck7df9ff22016-02-10 16:08:08 -0800623 addOp(alloc().create_trivial<FunctorOp>(
Chris Craike29ce6f2015-12-10 16:25:13 -0800624 *(mState.currentSnapshot()->transform),
Chris Craik4c3980b2016-03-15 14:20:18 -0700625 getRecordedClip(),
Chris Craike29ce6f2015-12-10 16:25:13 -0800626 functor));
627}
628
Chris Craik3c53ec512016-08-08 15:15:57 -0700629int RecordingCanvas::addOp(RecordedOp* op) {
Chris Craik261725f2016-02-29 12:52:33 -0800630 // skip op with empty clip
631 if (op->localClip && op->localClip->rect.isEmpty()) {
632 // NOTE: this rejection happens after op construction/content ref-ing, so content ref'd
633 // and held by renderthread isn't affected by clip rejection.
634 // Could rewind alloc here if desired, but callers would have to not touch op afterwards.
635 return -1;
636 }
637
Chris Craik003cc3d2015-10-16 10:24:55 -0700638 int insertIndex = mDisplayList->ops.size();
639 mDisplayList->ops.push_back(op);
Chris Craik161f54b2015-11-05 11:08:52 -0800640 if (mDeferredBarrierType != DeferredBarrierType::None) {
Chris Craikb565df12015-10-05 13:00:52 -0700641 // op is first in new chunk
Chris Craik003cc3d2015-10-16 10:24:55 -0700642 mDisplayList->chunks.emplace_back();
643 DisplayList::Chunk& newChunk = mDisplayList->chunks.back();
Chris Craikb565df12015-10-05 13:00:52 -0700644 newChunk.beginOpIndex = insertIndex;
645 newChunk.endOpIndex = insertIndex + 1;
Chris Craik161f54b2015-11-05 11:08:52 -0800646 newChunk.reorderChildren = (mDeferredBarrierType == DeferredBarrierType::OutOfOrder);
Chris Craikd6456402016-04-11 12:24:23 -0700647 newChunk.reorderClip = mDeferredBarrierClip;
Chris Craikb565df12015-10-05 13:00:52 -0700648
Chris Craikb36af872015-10-16 14:23:12 -0700649 int nextChildIndex = mDisplayList->children.size();
Chris Craikb565df12015-10-05 13:00:52 -0700650 newChunk.beginChildIndex = newChunk.endChildIndex = nextChildIndex;
Chris Craik161f54b2015-11-05 11:08:52 -0800651 mDeferredBarrierType = DeferredBarrierType::None;
Chris Craikb565df12015-10-05 13:00:52 -0700652 } else {
653 // standard case - append to existing chunk
Chris Craik003cc3d2015-10-16 10:24:55 -0700654 mDisplayList->chunks.back().endOpIndex = insertIndex + 1;
Chris Craikb565df12015-10-05 13:00:52 -0700655 }
656 return insertIndex;
657}
658
659void RecordingCanvas::refBitmapsInShader(const SkShader* shader) {
660 if (!shader) return;
661
662 // If this paint has an SkShader that has an SkBitmap add
663 // it to the bitmap pile
664 SkBitmap bitmap;
665 SkShader::TileMode xy[2];
Leon Scroggins IIIf35b9892015-07-31 10:38:40 -0400666 if (shader->isABitmap(&bitmap, nullptr, xy)) {
sergeyvec4a4b12016-10-20 18:39:04 -0700667 Bitmap* hwuiBitmap = static_cast<Bitmap*>(bitmap.pixelRef());
668 refBitmap(*hwuiBitmap);
Chris Craikb565df12015-10-05 13:00:52 -0700669 return;
670 }
671 SkShader::ComposeRec rec;
672 if (shader->asACompose(&rec)) {
673 refBitmapsInShader(rec.fShaderA);
674 refBitmapsInShader(rec.fShaderB);
675 return;
676 }
677}
678
679}; // namespace uirenderer
680}; // namespace android