OLD | NEW |
| (Empty) |
1 // Copyright 2017 The Chromium Authors. All rights reserved. | |
2 // Use of this source code is governed by a BSD-style license that can be | |
3 // found in the LICENSE file. | |
4 | |
5 #include "cc/paint/record_paint_canvas.h" | |
6 | |
7 #include "base/memory/ptr_util.h" | |
8 #include "cc/paint/display_item_list.h" | |
9 #include "cc/paint/paint_op_buffer.h" | |
10 #include "cc/paint/paint_record.h" | |
11 #include "cc/paint/paint_recorder.h" | |
12 #include "third_party/skia/include/core/SkAnnotation.h" | |
13 #include "third_party/skia/include/core/SkMetaData.h" | |
14 #include "third_party/skia/include/utils/SkNWayCanvas.h" | |
15 | |
16 namespace cc { | |
17 | |
18 RecordPaintCanvas::RecordPaintCanvas(PaintOpBuffer* buffer, | |
19 const SkRect& cull_rect) | |
20 : buffer_(buffer), | |
21 canvas_(static_cast<int>(std::ceil(cull_rect.right())), | |
22 static_cast<int>(std::ceil(cull_rect.bottom()))) { | |
23 DCHECK(buffer_); | |
24 | |
25 // This is part of the "recording canvases have a size, but why" dance. | |
26 // By creating a canvas of size (right x bottom) and then clipping it, | |
27 // It makes getDeviceClipBounds return the original cull rect, which code | |
28 // in GraphicsContextCanvas on Mac expects. (Just creating an SkNoDrawCanvas | |
29 // with the cull_rect makes a canvas of size (width x height) instead | |
30 // which is incorrect. SkRecorder cheats with private resetForNextCanvas. | |
31 canvas_.clipRect(SkRect::Make(cull_rect.roundOut()), SkClipOp::kIntersect, | |
32 false); | |
33 } | |
34 | |
35 RecordPaintCanvas::~RecordPaintCanvas() = default; | |
36 | |
37 SkMetaData& RecordPaintCanvas::getMetaData() { | |
38 // This could just be SkMetaData owned by RecordPaintCanvas, but since | |
39 // SkCanvas already has one, we might as well use it directly. | |
40 return canvas_.getMetaData(); | |
41 } | |
42 | |
43 SkImageInfo RecordPaintCanvas::imageInfo() const { | |
44 return canvas_.imageInfo(); | |
45 } | |
46 | |
47 void RecordPaintCanvas::flush() { | |
48 // This is a noop when recording. | |
49 } | |
50 | |
51 SkISize RecordPaintCanvas::getBaseLayerSize() const { | |
52 return canvas_.getBaseLayerSize(); | |
53 } | |
54 | |
55 bool RecordPaintCanvas::writePixels(const SkImageInfo& info, | |
56 const void* pixels, | |
57 size_t row_bytes, | |
58 int x, | |
59 int y) { | |
60 NOTREACHED(); | |
61 return false; | |
62 } | |
63 | |
64 int RecordPaintCanvas::save() { | |
65 buffer_->push<SaveOp>(); | |
66 return canvas_.save(); | |
67 } | |
68 | |
69 int RecordPaintCanvas::saveLayer(const SkRect* bounds, | |
70 const PaintFlags* flags) { | |
71 if (flags) { | |
72 if (flags->IsSimpleOpacity()) { | |
73 // TODO(enne): maybe more callers should know this and call | |
74 // saveLayerAlpha instead of needing to check here. | |
75 uint8_t alpha = SkColorGetA(flags->getColor()); | |
76 return saveLayerAlpha(bounds, alpha); | |
77 } | |
78 | |
79 // TODO(enne): it appears that image filters affect matrices and color | |
80 // matrices affect transparent flags on SkCanvas layers, but it's not clear | |
81 // whether those are actually needed and we could just skip ToSkPaint here. | |
82 buffer_->push<SaveLayerOp>(bounds, flags); | |
83 const SkPaint& paint = ToSkPaint(*flags); | |
84 return canvas_.saveLayer(bounds, &paint); | |
85 } | |
86 buffer_->push<SaveLayerOp>(bounds, flags); | |
87 return canvas_.saveLayer(bounds, nullptr); | |
88 } | |
89 | |
90 int RecordPaintCanvas::saveLayerAlpha(const SkRect* bounds, uint8_t alpha) { | |
91 buffer_->push<SaveLayerAlphaOp>(bounds, alpha); | |
92 return canvas_.saveLayerAlpha(bounds, alpha); | |
93 } | |
94 | |
95 void RecordPaintCanvas::restore() { | |
96 buffer_->push<RestoreOp>(); | |
97 canvas_.restore(); | |
98 } | |
99 | |
100 int RecordPaintCanvas::getSaveCount() const { | |
101 return canvas_.getSaveCount(); | |
102 } | |
103 | |
104 void RecordPaintCanvas::restoreToCount(int save_count) { | |
105 DCHECK_GE(save_count, 1); | |
106 int diff = canvas_.getSaveCount() - save_count; | |
107 DCHECK_GE(diff, 0); | |
108 for (int i = 0; i < diff; ++i) | |
109 restore(); | |
110 } | |
111 | |
112 void RecordPaintCanvas::translate(SkScalar dx, SkScalar dy) { | |
113 buffer_->push<TranslateOp>(dx, dy); | |
114 canvas_.translate(dx, dy); | |
115 } | |
116 | |
117 void RecordPaintCanvas::scale(SkScalar sx, SkScalar sy) { | |
118 buffer_->push<ScaleOp>(sx, sy); | |
119 canvas_.scale(sx, sy); | |
120 } | |
121 | |
122 void RecordPaintCanvas::rotate(SkScalar degrees) { | |
123 buffer_->push<RotateOp>(degrees); | |
124 canvas_.rotate(degrees); | |
125 } | |
126 | |
127 void RecordPaintCanvas::concat(const SkMatrix& matrix) { | |
128 buffer_->push<ConcatOp>(matrix); | |
129 canvas_.concat(matrix); | |
130 } | |
131 | |
132 void RecordPaintCanvas::setMatrix(const SkMatrix& matrix) { | |
133 buffer_->push<SetMatrixOp>(matrix); | |
134 canvas_.setMatrix(matrix); | |
135 } | |
136 | |
137 void RecordPaintCanvas::clipRect(const SkRect& rect, | |
138 SkClipOp op, | |
139 bool antialias) { | |
140 buffer_->push<ClipRectOp>(rect, op, antialias); | |
141 canvas_.clipRect(rect, op, antialias); | |
142 } | |
143 | |
144 void RecordPaintCanvas::clipRRect(const SkRRect& rrect, | |
145 SkClipOp op, | |
146 bool antialias) { | |
147 // TODO(enne): does this happen? Should the caller know this? | |
148 if (rrect.isRect()) { | |
149 clipRect(rrect.getBounds(), op, antialias); | |
150 return; | |
151 } | |
152 buffer_->push<ClipRRectOp>(rrect, op, antialias); | |
153 canvas_.clipRRect(rrect, op, antialias); | |
154 } | |
155 | |
156 void RecordPaintCanvas::clipPath(const SkPath& path, | |
157 SkClipOp op, | |
158 bool antialias) { | |
159 if (!path.isInverseFillType() && canvas_.getTotalMatrix().rectStaysRect()) { | |
160 // TODO(enne): do these cases happen? should the caller know that this isn't | |
161 // a path? | |
162 SkRect rect; | |
163 if (path.isRect(&rect)) { | |
164 clipRect(rect, op, antialias); | |
165 return; | |
166 } | |
167 SkRRect rrect; | |
168 if (path.isOval(&rect)) { | |
169 rrect.setOval(rect); | |
170 clipRRect(rrect, op, antialias); | |
171 return; | |
172 } | |
173 if (path.isRRect(&rrect)) { | |
174 clipRRect(rrect, op, antialias); | |
175 return; | |
176 } | |
177 } | |
178 | |
179 buffer_->push<ClipPathOp>(path, op, antialias); | |
180 canvas_.clipPath(path, op, antialias); | |
181 return; | |
182 } | |
183 | |
184 bool RecordPaintCanvas::quickReject(const SkRect& rect) const { | |
185 return canvas_.quickReject(rect); | |
186 } | |
187 | |
188 bool RecordPaintCanvas::quickReject(const SkPath& path) const { | |
189 return canvas_.quickReject(path); | |
190 } | |
191 | |
192 SkRect RecordPaintCanvas::getLocalClipBounds() const { | |
193 return canvas_.getLocalClipBounds(); | |
194 } | |
195 | |
196 bool RecordPaintCanvas::getLocalClipBounds(SkRect* bounds) const { | |
197 return canvas_.getLocalClipBounds(bounds); | |
198 } | |
199 | |
200 SkIRect RecordPaintCanvas::getDeviceClipBounds() const { | |
201 return canvas_.getDeviceClipBounds(); | |
202 } | |
203 | |
204 bool RecordPaintCanvas::getDeviceClipBounds(SkIRect* bounds) const { | |
205 return canvas_.getDeviceClipBounds(bounds); | |
206 } | |
207 | |
208 void RecordPaintCanvas::drawColor(SkColor color, SkBlendMode mode) { | |
209 buffer_->push<DrawColorOp>(color, mode); | |
210 } | |
211 | |
212 void RecordPaintCanvas::clear(SkColor color) { | |
213 buffer_->push<DrawColorOp>(color, SkBlendMode::kSrc); | |
214 } | |
215 | |
216 void RecordPaintCanvas::drawLine(SkScalar x0, | |
217 SkScalar y0, | |
218 SkScalar x1, | |
219 SkScalar y1, | |
220 const PaintFlags& flags) { | |
221 buffer_->push<DrawLineOp>(x0, y0, x1, y1, flags); | |
222 } | |
223 | |
224 void RecordPaintCanvas::drawRect(const SkRect& rect, const PaintFlags& flags) { | |
225 buffer_->push<DrawRectOp>(rect, flags); | |
226 } | |
227 | |
228 void RecordPaintCanvas::drawIRect(const SkIRect& rect, | |
229 const PaintFlags& flags) { | |
230 buffer_->push<DrawIRectOp>(rect, flags); | |
231 } | |
232 | |
233 void RecordPaintCanvas::drawOval(const SkRect& oval, const PaintFlags& flags) { | |
234 buffer_->push<DrawOvalOp>(oval, flags); | |
235 } | |
236 | |
237 void RecordPaintCanvas::drawRRect(const SkRRect& rrect, | |
238 const PaintFlags& flags) { | |
239 buffer_->push<DrawRRectOp>(rrect, flags); | |
240 } | |
241 | |
242 void RecordPaintCanvas::drawDRRect(const SkRRect& outer, | |
243 const SkRRect& inner, | |
244 const PaintFlags& flags) { | |
245 if (outer.isEmpty()) | |
246 return; | |
247 if (inner.isEmpty()) { | |
248 drawRRect(outer, flags); | |
249 return; | |
250 } | |
251 buffer_->push<DrawDRRectOp>(outer, inner, flags); | |
252 } | |
253 | |
254 void RecordPaintCanvas::drawCircle(SkScalar cx, | |
255 SkScalar cy, | |
256 SkScalar radius, | |
257 const PaintFlags& flags) { | |
258 buffer_->push<DrawCircleOp>(cx, cy, radius, flags); | |
259 } | |
260 | |
261 void RecordPaintCanvas::drawArc(const SkRect& oval, | |
262 SkScalar start_angle, | |
263 SkScalar sweep_angle, | |
264 bool use_center, | |
265 const PaintFlags& flags) { | |
266 buffer_->push<DrawArcOp>(oval, start_angle, sweep_angle, use_center, flags); | |
267 } | |
268 | |
269 void RecordPaintCanvas::drawRoundRect(const SkRect& rect, | |
270 SkScalar rx, | |
271 SkScalar ry, | |
272 const PaintFlags& flags) { | |
273 // TODO(enne): move this into base class? | |
274 if (rx > 0 && ry > 0) { | |
275 SkRRect rrect; | |
276 rrect.setRectXY(rect, rx, ry); | |
277 drawRRect(rrect, flags); | |
278 } else { | |
279 drawRect(rect, flags); | |
280 } | |
281 } | |
282 | |
283 void RecordPaintCanvas::drawPath(const SkPath& path, const PaintFlags& flags) { | |
284 buffer_->push<DrawPathOp>(path, flags); | |
285 } | |
286 | |
287 void RecordPaintCanvas::drawImage(const PaintImage& image, | |
288 SkScalar left, | |
289 SkScalar top, | |
290 const PaintFlags* flags) { | |
291 buffer_->push<DrawImageOp>(image, left, top, flags); | |
292 } | |
293 | |
294 void RecordPaintCanvas::drawImageRect(const PaintImage& image, | |
295 const SkRect& src, | |
296 const SkRect& dst, | |
297 const PaintFlags* flags, | |
298 SrcRectConstraint constraint) { | |
299 buffer_->push<DrawImageRectOp>(image, src, dst, flags, constraint); | |
300 } | |
301 | |
302 void RecordPaintCanvas::drawBitmap(const SkBitmap& bitmap, | |
303 SkScalar left, | |
304 SkScalar top, | |
305 const PaintFlags* flags) { | |
306 // TODO(enne): Move into base class? | |
307 if (bitmap.drawsNothing()) | |
308 return; | |
309 drawImage(PaintImage(SkImage::MakeFromBitmap(bitmap), | |
310 PaintImage::AnimationType::UNKNOWN, | |
311 PaintImage::CompletionState::UNKNOWN), | |
312 left, top, flags); | |
313 } | |
314 | |
315 void RecordPaintCanvas::drawText(const void* text, | |
316 size_t byte_length, | |
317 SkScalar x, | |
318 SkScalar y, | |
319 const PaintFlags& flags) { | |
320 buffer_->push_with_data<DrawTextOp>(text, byte_length, x, y, flags); | |
321 } | |
322 | |
323 void RecordPaintCanvas::drawPosText(const void* text, | |
324 size_t byte_length, | |
325 const SkPoint pos[], | |
326 const PaintFlags& flags) { | |
327 size_t count = ToSkPaint(flags).countText(text, byte_length); | |
328 buffer_->push_with_data_array<DrawPosTextOp>(text, byte_length, pos, count, | |
329 flags); | |
330 } | |
331 | |
332 void RecordPaintCanvas::drawTextBlob(sk_sp<SkTextBlob> blob, | |
333 SkScalar x, | |
334 SkScalar y, | |
335 const PaintFlags& flags) { | |
336 buffer_->push<DrawTextBlobOp>(blob, x, y, flags); | |
337 } | |
338 | |
339 void RecordPaintCanvas::drawDisplayItemList( | |
340 scoped_refptr<DisplayItemList> list) { | |
341 buffer_->push<DrawDisplayItemListOp>(list); | |
342 } | |
343 | |
344 void RecordPaintCanvas::drawPicture(sk_sp<const PaintRecord> record) { | |
345 // TODO(enne): If this is small, maybe flatten it? | |
346 buffer_->push<DrawRecordOp>(record); | |
347 } | |
348 | |
349 bool RecordPaintCanvas::isClipEmpty() const { | |
350 return canvas_.isClipEmpty(); | |
351 } | |
352 | |
353 bool RecordPaintCanvas::isClipRect() const { | |
354 return canvas_.isClipRect(); | |
355 } | |
356 | |
357 const SkMatrix& RecordPaintCanvas::getTotalMatrix() const { | |
358 return canvas_.getTotalMatrix(); | |
359 } | |
360 | |
361 void RecordPaintCanvas::temporary_internal_describeTopLayer( | |
362 SkMatrix* matrix, | |
363 SkIRect* clip_bounds) { | |
364 return canvas_.temporary_internal_describeTopLayer(matrix, clip_bounds); | |
365 } | |
366 | |
367 bool RecordPaintCanvas::ToPixmap(SkPixmap* output) { | |
368 // TODO(enne): It'd be nice to make this NOTREACHED() or remove this from | |
369 // RecordPaintCanvas, but this is used by GraphicsContextCanvas for knowing | |
370 // whether or not it can raster directly into pixels with Cg. | |
371 return false; | |
372 } | |
373 | |
374 void RecordPaintCanvas::Annotate(AnnotationType type, | |
375 const SkRect& rect, | |
376 sk_sp<SkData> data) { | |
377 buffer_->push<AnnotateOp>(type, rect, data); | |
378 } | |
379 | |
380 void RecordPaintCanvas::PlaybackPaintRecord(sk_sp<const PaintRecord> record) { | |
381 drawPicture(record); | |
382 } | |
383 | |
384 } // namespace cc | |
OLD | NEW |