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 #ifndef CC_PAINT_PAINT_OP_BUFFER_H_ | |
6 #define CC_PAINT_PAINT_OP_BUFFER_H_ | |
7 | |
8 #include <stdint.h> | |
9 | |
10 #include "base/logging.h" | |
11 #include "cc/paint/paint_canvas.h" | |
12 #include "cc/paint/paint_export.h" | |
13 #include "cc/paint/paint_flags.h" | |
14 #include "third_party/skia/include/core/SkPicture.h" | |
15 #include "third_party/skia/include/core/SkRect.h" | |
16 #include "third_party/skia/include/core/SkTextBlob.h" | |
17 | |
18 // PaintOpBuffer is a reimplementation of SkLiteDL. | |
19 // See: third_party/skia/src/core/SkLiteDL.h. | |
20 | |
21 namespace cc { | |
22 | |
23 class DisplayItemList; | |
24 | |
25 class CC_PAINT_EXPORT ThreadsafeMatrix : public SkMatrix { | |
26 public: | |
27 explicit ThreadsafeMatrix(const SkMatrix& matrix) : SkMatrix(matrix) { | |
28 (void)getType(); | |
29 } | |
30 }; | |
31 | |
32 class CC_PAINT_EXPORT ThreadsafePath : public SkPath { | |
33 public: | |
34 explicit ThreadsafePath(const SkPath& path) : SkPath(path) { | |
35 updateBoundsCache(); | |
36 } | |
37 }; | |
38 | |
39 enum class PaintOpType : uint8_t { | |
40 Annotate, | |
41 ClipPath, | |
42 ClipRect, | |
43 ClipRRect, | |
44 Concat, | |
45 DrawArc, | |
46 DrawCircle, | |
47 DrawColor, | |
48 DrawDisplayItemList, | |
49 DrawDRRect, | |
50 DrawImage, | |
51 DrawImageRect, | |
52 DrawIRect, | |
53 DrawLine, | |
54 DrawOval, | |
55 DrawPath, | |
56 DrawPosText, | |
57 DrawRecord, | |
58 DrawRect, | |
59 DrawRRect, | |
60 DrawText, | |
61 DrawTextBlob, | |
62 Noop, | |
63 Restore, | |
64 Rotate, | |
65 Save, | |
66 SaveLayer, | |
67 SaveLayerAlpha, | |
68 Scale, | |
69 SetMatrix, | |
70 Translate, | |
71 LastPaintOpType = Translate, | |
72 }; | |
73 | |
74 struct CC_PAINT_EXPORT PaintOp { | |
75 uint32_t type : 8; | |
76 uint32_t skip : 24; | |
77 | |
78 PaintOpType GetType() const { return static_cast<PaintOpType>(type); } | |
79 | |
80 void Raster(SkCanvas* canvas, const SkMatrix& original_ctm) const; | |
81 bool IsDrawOp() const; | |
82 | |
83 // Only valid for draw ops. | |
84 void RasterWithAlpha(SkCanvas* canvas, uint8_t alpha) const; | |
85 | |
86 int CountSlowPaths() const { return 0; } | |
87 | |
88 // Returns the number of bytes used by this op in referenced sub records | |
89 // and display lists. This doesn't count other objects like paths or blobs. | |
90 size_t AdditionalBytesUsed() const { return 0; } | |
91 | |
92 static constexpr bool kIsDrawOp = false; | |
93 // If an op has |kHasPaintFlags| set to true, it must: | |
94 // (1) Provide a PaintFlags member called |flags| | |
95 // (2) Provide a RasterWithFlags function instead of a Raster function. | |
96 static constexpr bool kHasPaintFlags = false; | |
97 static SkRect kUnsetRect; | |
98 }; | |
99 | |
100 struct CC_PAINT_EXPORT PaintOpWithData : PaintOp { | |
101 // Having data is just a helper for ops that have a varying amount of data and | |
102 // want a way to store that inline. This is for ops that pass in a | |
103 // void* and a length. | |
104 explicit PaintOpWithData(size_t bytes) : bytes(bytes) {} | |
105 | |
106 // Get data out by calling paint_op_data. This can't be part of the class | |
107 // because it needs to know the size of the derived type. | |
108 size_t bytes; | |
109 }; | |
110 | |
111 template <typename T> | |
112 const void* paint_op_data(const T* op) { | |
113 static_assert(std::is_convertible<T, PaintOpWithData>::value, | |
114 "T is not a PaintOpWithData"); | |
115 // Arbitrary data for a PaintOp is stored after the PaintOp itself | |
116 // in the PaintOpBuffer. Therefore, to access this data, it's | |
117 // pointer math to increment past the size of T. Accessing the | |
118 // next op in the buffer is ((char*)op) + op->skip, with the data | |
119 // fitting between. | |
120 return op + 1; | |
121 } | |
122 | |
123 template <typename T> | |
124 void* paint_op_data(T* op) { | |
125 static_assert(std::is_convertible<T, PaintOpWithData>::value, | |
126 "T is not a PaintOpWithData"); | |
127 return op + 1; | |
128 } | |
129 | |
130 struct CC_PAINT_EXPORT PaintOpWithDataArrayBase : PaintOpWithData { | |
131 // Helper class for static asserts in push functions. | |
132 using PaintOpWithData::PaintOpWithData; | |
133 }; | |
134 | |
135 template <typename T> | |
136 struct CC_PAINT_EXPORT PaintOpWithDataArray : PaintOpWithDataArrayBase { | |
137 // Paint op that has a T[count] and a char[bytes]. | |
138 PaintOpWithDataArray(size_t bytes, size_t count) | |
139 : PaintOpWithDataArrayBase(bytes), count(count) {} | |
140 // Use paint_op_array to get array data. | |
141 | |
142 size_t count; | |
143 }; | |
144 | |
145 template <typename M, typename T> | |
146 const M* paint_op_array(const T* op) { | |
147 static_assert(std::is_convertible<T, PaintOpWithDataArrayBase>::value, | |
148 "T is not a PaintOpWithDataArray"); | |
149 // See comment in paint_op_data. Array data is stored after | |
150 // any void* data. Memory layout here is: |op|data|array data|next op| | |
151 return SkTAddOffset<const M>(op + 1, op->bytes); | |
152 } | |
153 template <typename M, typename T> | |
154 M* paint_op_array(T* op) { | |
155 static_assert(std::is_convertible<T, PaintOpWithDataArrayBase>::value, | |
156 "T is not a PaintOpWithDataArray"); | |
157 return SkTAddOffset<M>(op + 1, op->bytes); | |
158 } | |
159 | |
160 struct CC_PAINT_EXPORT AnnotateOp final : PaintOp { | |
161 enum class AnnotationType { | |
162 URL, | |
163 LinkToDestination, | |
164 NamedDestination, | |
165 }; | |
166 | |
167 static constexpr PaintOpType kType = PaintOpType::Annotate; | |
168 AnnotateOp(PaintCanvas::AnnotationType annotation_type, | |
169 const SkRect& rect, | |
170 sk_sp<SkData> data); | |
171 ~AnnotateOp(); | |
172 void Raster(SkCanvas* canvas) const; | |
173 | |
174 PaintCanvas::AnnotationType annotation_type; | |
175 SkRect rect; | |
176 sk_sp<SkData> data; | |
177 }; | |
178 | |
179 struct CC_PAINT_EXPORT ClipPathOp final : PaintOp { | |
180 static constexpr PaintOpType kType = PaintOpType::ClipPath; | |
181 ClipPathOp(SkPath path, SkClipOp op, bool antialias) | |
182 : path(path), op(op), antialias(antialias) {} | |
183 void Raster(SkCanvas* canvas) const; | |
184 int CountSlowPaths() const; | |
185 | |
186 ThreadsafePath path; | |
187 SkClipOp op; | |
188 bool antialias; | |
189 }; | |
190 | |
191 struct CC_PAINT_EXPORT ClipRectOp final : PaintOp { | |
192 static constexpr PaintOpType kType = PaintOpType::ClipRect; | |
193 ClipRectOp(const SkRect& rect, SkClipOp op, bool antialias) | |
194 : rect(rect), op(op), antialias(antialias) {} | |
195 void Raster(SkCanvas* canvas) const; | |
196 | |
197 SkRect rect; | |
198 SkClipOp op; | |
199 bool antialias; | |
200 }; | |
201 | |
202 struct CC_PAINT_EXPORT ClipRRectOp final : PaintOp { | |
203 static constexpr PaintOpType kType = PaintOpType::ClipRRect; | |
204 ClipRRectOp(const SkRRect& rrect, SkClipOp op, bool antialias) | |
205 : rrect(rrect), op(op), antialias(antialias) {} | |
206 void Raster(SkCanvas* canvas) const; | |
207 | |
208 SkRRect rrect; | |
209 SkClipOp op; | |
210 bool antialias; | |
211 }; | |
212 | |
213 struct CC_PAINT_EXPORT ConcatOp final : PaintOp { | |
214 static constexpr PaintOpType kType = PaintOpType::Concat; | |
215 explicit ConcatOp(const SkMatrix& matrix) : matrix(matrix) {} | |
216 void Raster(SkCanvas* canvas) const; | |
217 | |
218 ThreadsafeMatrix matrix; | |
219 }; | |
220 | |
221 struct CC_PAINT_EXPORT DrawArcOp final : PaintOp { | |
222 static constexpr PaintOpType kType = PaintOpType::DrawArc; | |
223 static constexpr bool kIsDrawOp = true; | |
224 static constexpr bool kHasPaintFlags = true; | |
225 DrawArcOp(const SkRect& oval, | |
226 SkScalar start_angle, | |
227 SkScalar sweep_angle, | |
228 bool use_center, | |
229 const PaintFlags& flags) | |
230 : oval(oval), | |
231 start_angle(start_angle), | |
232 sweep_angle(sweep_angle), | |
233 use_center(use_center), | |
234 flags(flags) {} | |
235 void RasterWithFlags(SkCanvas* canvas, const PaintFlags& flags) const; | |
236 | |
237 SkRect oval; | |
238 SkScalar start_angle; | |
239 SkScalar sweep_angle; | |
240 bool use_center; | |
241 PaintFlags flags; | |
242 }; | |
243 | |
244 struct CC_PAINT_EXPORT DrawCircleOp final : PaintOp { | |
245 static constexpr PaintOpType kType = PaintOpType::DrawCircle; | |
246 static constexpr bool kIsDrawOp = true; | |
247 static constexpr bool kHasPaintFlags = true; | |
248 DrawCircleOp(SkScalar cx, | |
249 SkScalar cy, | |
250 SkScalar radius, | |
251 const PaintFlags& flags) | |
252 : cx(cx), cy(cy), radius(radius), flags(flags) {} | |
253 void RasterWithFlags(SkCanvas* canvas, const PaintFlags& flags) const; | |
254 | |
255 SkScalar cx; | |
256 SkScalar cy; | |
257 SkScalar radius; | |
258 PaintFlags flags; | |
259 }; | |
260 | |
261 struct CC_PAINT_EXPORT DrawColorOp final : PaintOp { | |
262 static constexpr PaintOpType kType = PaintOpType::DrawColor; | |
263 static constexpr bool kIsDrawOp = true; | |
264 DrawColorOp(SkColor color, SkBlendMode mode) : color(color), mode(mode) {} | |
265 void Raster(SkCanvas* canvas) const; | |
266 | |
267 SkColor color; | |
268 SkBlendMode mode; | |
269 }; | |
270 | |
271 struct CC_PAINT_EXPORT DrawDisplayItemListOp final : PaintOp { | |
272 static constexpr PaintOpType kType = PaintOpType::DrawDisplayItemList; | |
273 static constexpr bool kIsDrawOp = true; | |
274 explicit DrawDisplayItemListOp(scoped_refptr<DisplayItemList> list); | |
275 // Windows wants to generate these when types are exported, so | |
276 // provide them here explicitly so that DisplayItemList doesn't have | |
277 // to be defined in this header. | |
278 DrawDisplayItemListOp(const DrawDisplayItemListOp& op); | |
279 DrawDisplayItemListOp& operator=(const DrawDisplayItemListOp& op); | |
280 ~DrawDisplayItemListOp(); | |
281 void Raster(SkCanvas* canvas) const; | |
282 size_t AdditionalBytesUsed() const; | |
283 // TODO(enne): DisplayItemList should know number of slow paths. | |
284 | |
285 scoped_refptr<DisplayItemList> list; | |
286 }; | |
287 | |
288 struct CC_PAINT_EXPORT DrawDRRectOp final : PaintOp { | |
289 static constexpr PaintOpType kType = PaintOpType::DrawDRRect; | |
290 static constexpr bool kIsDrawOp = true; | |
291 static constexpr bool kHasPaintFlags = true; | |
292 DrawDRRectOp(const SkRRect& outer, | |
293 const SkRRect& inner, | |
294 const PaintFlags& flags) | |
295 : outer(outer), inner(inner), flags(flags) {} | |
296 void RasterWithFlags(SkCanvas* canvas, const PaintFlags& flags) const; | |
297 | |
298 SkRRect outer; | |
299 SkRRect inner; | |
300 PaintFlags flags; | |
301 }; | |
302 | |
303 struct CC_PAINT_EXPORT DrawImageOp final : PaintOp { | |
304 static constexpr PaintOpType kType = PaintOpType::DrawImage; | |
305 static constexpr bool kIsDrawOp = true; | |
306 static constexpr bool kHasPaintFlags = true; | |
307 DrawImageOp(const PaintImage& image, | |
308 SkScalar left, | |
309 SkScalar top, | |
310 const PaintFlags* flags); | |
311 ~DrawImageOp(); | |
312 void RasterWithFlags(SkCanvas* canvas, const PaintFlags& flags) const; | |
313 | |
314 PaintImage image; | |
315 SkScalar left; | |
316 SkScalar top; | |
317 PaintFlags flags; | |
318 }; | |
319 | |
320 struct CC_PAINT_EXPORT DrawImageRectOp final : PaintOp { | |
321 static constexpr PaintOpType kType = PaintOpType::DrawImageRect; | |
322 static constexpr bool kIsDrawOp = true; | |
323 static constexpr bool kHasPaintFlags = true; | |
324 DrawImageRectOp(const PaintImage& image, | |
325 const SkRect& src, | |
326 const SkRect& dst, | |
327 const PaintFlags* flags, | |
328 PaintCanvas::SrcRectConstraint constraint); | |
329 ~DrawImageRectOp(); | |
330 void RasterWithFlags(SkCanvas* canvas, const PaintFlags& flags) const; | |
331 | |
332 PaintImage image; | |
333 PaintFlags flags; | |
334 SkRect src; | |
335 SkRect dst; | |
336 PaintCanvas::SrcRectConstraint constraint; | |
337 }; | |
338 | |
339 struct CC_PAINT_EXPORT DrawIRectOp final : PaintOp { | |
340 static constexpr PaintOpType kType = PaintOpType::DrawIRect; | |
341 static constexpr bool kIsDrawOp = true; | |
342 static constexpr bool kHasPaintFlags = true; | |
343 DrawIRectOp(const SkIRect& rect, const PaintFlags& flags) | |
344 : rect(rect), flags(flags) {} | |
345 void RasterWithFlags(SkCanvas* canvas, const PaintFlags& flags) const; | |
346 | |
347 SkIRect rect; | |
348 PaintFlags flags; | |
349 }; | |
350 | |
351 struct CC_PAINT_EXPORT DrawLineOp final : PaintOp { | |
352 static constexpr PaintOpType kType = PaintOpType::DrawLine; | |
353 static constexpr bool kIsDrawOp = true; | |
354 static constexpr bool kHasPaintFlags = true; | |
355 DrawLineOp(SkScalar x0, | |
356 SkScalar y0, | |
357 SkScalar x1, | |
358 SkScalar y1, | |
359 const PaintFlags& flags) | |
360 : x0(x0), y0(y0), x1(x1), y1(y1), flags(flags) {} | |
361 void RasterWithFlags(SkCanvas* canvas, const PaintFlags& flags) const; | |
362 int CountSlowPaths() const; | |
363 | |
364 SkScalar x0; | |
365 SkScalar y0; | |
366 SkScalar x1; | |
367 SkScalar y1; | |
368 PaintFlags flags; | |
369 }; | |
370 | |
371 struct CC_PAINT_EXPORT DrawOvalOp final : PaintOp { | |
372 static constexpr PaintOpType kType = PaintOpType::DrawOval; | |
373 static constexpr bool kIsDrawOp = true; | |
374 static constexpr bool kHasPaintFlags = true; | |
375 DrawOvalOp(const SkRect& oval, const PaintFlags& flags) | |
376 : oval(oval), flags(flags) {} | |
377 void RasterWithFlags(SkCanvas* canvas, const PaintFlags& flags) const; | |
378 | |
379 SkRect oval; | |
380 PaintFlags flags; | |
381 }; | |
382 | |
383 struct CC_PAINT_EXPORT DrawPathOp final : PaintOp { | |
384 static constexpr PaintOpType kType = PaintOpType::DrawPath; | |
385 static constexpr bool kIsDrawOp = true; | |
386 static constexpr bool kHasPaintFlags = true; | |
387 DrawPathOp(const SkPath& path, const PaintFlags& flags) | |
388 : path(path), flags(flags) {} | |
389 void RasterWithFlags(SkCanvas* canvas, const PaintFlags& flags) const; | |
390 int CountSlowPaths() const; | |
391 | |
392 ThreadsafePath path; | |
393 PaintFlags flags; | |
394 }; | |
395 | |
396 struct CC_PAINT_EXPORT DrawPosTextOp final : PaintOpWithDataArray<SkPoint> { | |
397 static constexpr PaintOpType kType = PaintOpType::DrawPosText; | |
398 static constexpr bool kIsDrawOp = true; | |
399 static constexpr bool kHasPaintFlags = true; | |
400 DrawPosTextOp(size_t bytes, size_t count, const PaintFlags& flags); | |
401 ~DrawPosTextOp(); | |
402 void RasterWithFlags(SkCanvas* canvas, const PaintFlags& flags) const; | |
403 | |
404 PaintFlags flags; | |
405 }; | |
406 | |
407 struct CC_PAINT_EXPORT DrawRecordOp final : PaintOp { | |
408 static constexpr PaintOpType kType = PaintOpType::DrawRecord; | |
409 static constexpr bool kIsDrawOp = true; | |
410 explicit DrawRecordOp(sk_sp<const PaintRecord> record); | |
411 ~DrawRecordOp(); | |
412 void Raster(SkCanvas* canvas) const; | |
413 size_t AdditionalBytesUsed() const; | |
414 | |
415 sk_sp<const PaintRecord> record; | |
416 }; | |
417 | |
418 struct CC_PAINT_EXPORT DrawRectOp final : PaintOp { | |
419 static constexpr PaintOpType kType = PaintOpType::DrawRect; | |
420 static constexpr bool kIsDrawOp = true; | |
421 static constexpr bool kHasPaintFlags = true; | |
422 DrawRectOp(const SkRect& rect, const PaintFlags& flags) | |
423 : rect(rect), flags(flags) {} | |
424 void RasterWithFlags(SkCanvas* canvas, const PaintFlags& flags) const; | |
425 | |
426 SkRect rect; | |
427 PaintFlags flags; | |
428 }; | |
429 | |
430 struct CC_PAINT_EXPORT DrawRRectOp final : PaintOp { | |
431 static constexpr PaintOpType kType = PaintOpType::DrawRRect; | |
432 static constexpr bool kIsDrawOp = true; | |
433 static constexpr bool kHasPaintFlags = true; | |
434 DrawRRectOp(const SkRRect& rrect, const PaintFlags& flags) | |
435 : rrect(rrect), flags(flags) {} | |
436 void RasterWithFlags(SkCanvas* canvas, const PaintFlags& flags) const; | |
437 | |
438 SkRRect rrect; | |
439 PaintFlags flags; | |
440 }; | |
441 | |
442 struct CC_PAINT_EXPORT DrawTextOp final : PaintOpWithData { | |
443 static constexpr PaintOpType kType = PaintOpType::DrawText; | |
444 static constexpr bool kIsDrawOp = true; | |
445 static constexpr bool kHasPaintFlags = true; | |
446 DrawTextOp(size_t bytes, SkScalar x, SkScalar y, const PaintFlags& flags) | |
447 : PaintOpWithData(bytes), x(x), y(y), flags(flags) {} | |
448 void RasterWithFlags(SkCanvas* canvas, const PaintFlags& flags) const; | |
449 | |
450 SkScalar x; | |
451 SkScalar y; | |
452 PaintFlags flags; | |
453 }; | |
454 | |
455 struct CC_PAINT_EXPORT DrawTextBlobOp final : PaintOp { | |
456 static constexpr PaintOpType kType = PaintOpType::DrawTextBlob; | |
457 static constexpr bool kIsDrawOp = true; | |
458 static constexpr bool kHasPaintFlags = true; | |
459 DrawTextBlobOp(sk_sp<SkTextBlob> blob, | |
460 SkScalar x, | |
461 SkScalar y, | |
462 const PaintFlags& flags); | |
463 ~DrawTextBlobOp(); | |
464 void RasterWithFlags(SkCanvas* canvas, const PaintFlags& flags) const; | |
465 | |
466 sk_sp<SkTextBlob> blob; | |
467 SkScalar x; | |
468 SkScalar y; | |
469 PaintFlags flags; | |
470 }; | |
471 | |
472 struct CC_PAINT_EXPORT NoopOp final : PaintOp { | |
473 static constexpr PaintOpType kType = PaintOpType::Noop; | |
474 void Raster(SkCanvas* canvas) const {} | |
475 }; | |
476 | |
477 struct CC_PAINT_EXPORT RestoreOp final : PaintOp { | |
478 static constexpr PaintOpType kType = PaintOpType::Restore; | |
479 void Raster(SkCanvas* canvas) const; | |
480 }; | |
481 | |
482 struct CC_PAINT_EXPORT RotateOp final : PaintOp { | |
483 static constexpr PaintOpType kType = PaintOpType::Rotate; | |
484 explicit RotateOp(SkScalar degrees) : degrees(degrees) {} | |
485 void Raster(SkCanvas* canvas) const; | |
486 | |
487 SkScalar degrees; | |
488 }; | |
489 | |
490 struct CC_PAINT_EXPORT SaveOp final : PaintOp { | |
491 static constexpr PaintOpType kType = PaintOpType::Save; | |
492 void Raster(SkCanvas* canvas) const; | |
493 }; | |
494 | |
495 struct CC_PAINT_EXPORT SaveLayerOp final : PaintOp { | |
496 static constexpr PaintOpType kType = PaintOpType::SaveLayer; | |
497 static constexpr bool kHasPaintFlags = true; | |
498 SaveLayerOp(const SkRect* bounds, const PaintFlags* flags) | |
499 : bounds(bounds ? *bounds : kUnsetRect) { | |
500 if (flags) | |
501 this->flags = *flags; | |
502 } | |
503 void RasterWithFlags(SkCanvas* canvas, const PaintFlags& flags) const; | |
504 | |
505 SkRect bounds; | |
506 PaintFlags flags; | |
507 }; | |
508 | |
509 struct CC_PAINT_EXPORT SaveLayerAlphaOp final : PaintOp { | |
510 static constexpr PaintOpType kType = PaintOpType::SaveLayerAlpha; | |
511 SaveLayerAlphaOp(const SkRect* bounds, uint8_t alpha) | |
512 : bounds(bounds ? *bounds : kUnsetRect), alpha(alpha) {} | |
513 void Raster(SkCanvas* canvas) const; | |
514 | |
515 SkRect bounds; | |
516 uint8_t alpha; | |
517 }; | |
518 | |
519 struct CC_PAINT_EXPORT ScaleOp final : PaintOp { | |
520 static constexpr PaintOpType kType = PaintOpType::Scale; | |
521 ScaleOp(SkScalar sx, SkScalar sy) : sx(sx), sy(sy) {} | |
522 void Raster(SkCanvas* canvas) const; | |
523 | |
524 SkScalar sx; | |
525 SkScalar sy; | |
526 }; | |
527 | |
528 struct CC_PAINT_EXPORT SetMatrixOp final : PaintOp { | |
529 static constexpr PaintOpType kType = PaintOpType::SetMatrix; | |
530 explicit SetMatrixOp(const SkMatrix& matrix) : matrix(matrix) {} | |
531 // This is the only op that needs the original ctm of the SkCanvas | |
532 // used for raster (since SetMatrix is relative to the recording origin and | |
533 // shouldn't clobber the SkCanvas raster origin). | |
534 // | |
535 // TODO(enne): Find some cleaner way to do this, possibly by making | |
536 // all SetMatrix calls Concat?? | |
537 void Raster(SkCanvas* canvas, const SkMatrix& original_ctm) const; | |
538 | |
539 ThreadsafeMatrix matrix; | |
540 }; | |
541 | |
542 struct CC_PAINT_EXPORT TranslateOp final : PaintOp { | |
543 static constexpr PaintOpType kType = PaintOpType::Translate; | |
544 TranslateOp(SkScalar dx, SkScalar dy) : dx(dx), dy(dy) {} | |
545 void Raster(SkCanvas* canvas) const; | |
546 | |
547 SkScalar dx; | |
548 SkScalar dy; | |
549 }; | |
550 | |
551 using LargestPaintOp = DrawDRRectOp; | |
552 | |
553 class CC_PAINT_EXPORT PaintOpBuffer : public SkRefCnt { | |
554 public: | |
555 enum { kInitialBufferSize = 4096 }; | |
556 | |
557 PaintOpBuffer(); | |
558 explicit PaintOpBuffer(const SkRect& cull_rect); | |
559 ~PaintOpBuffer() override; | |
560 | |
561 void Reset(); | |
562 | |
563 void playback(SkCanvas* canvas) const; | |
564 void playback(SkCanvas* canvas, SkPicture::AbortCallback* callback) const; | |
565 | |
566 // TODO(enne): These are no longer approximate. Rename these. | |
567 int approximateOpCount() const { return op_count_; } | |
568 size_t approximateBytesUsed() const { | |
569 return sizeof(*this) + reserved_ + subrecord_bytes_used_; | |
570 } | |
571 int numSlowPaths() const { return num_slow_paths_; } | |
572 | |
573 // Resize the PaintOpBuffer to exactly fit the current amount of used space. | |
574 void ShrinkToFit(); | |
575 | |
576 const SkRect& cullRect() const { return cull_rect_; } | |
577 | |
578 PaintOp* GetFirstOp() const { | |
579 return reinterpret_cast<PaintOp*>(const_cast<char*>(&first_op_[0])); | |
580 } | |
581 | |
582 template <typename T, typename... Args> | |
583 void push(Args&&... args) { | |
584 static_assert(std::is_convertible<T, PaintOp>::value, "T not a PaintOp."); | |
585 static_assert(!std::is_convertible<T, PaintOpWithData>::value, | |
586 "Type needs to use push_with_data"); | |
587 push_internal<T>(0, std::forward<Args>(args)...); | |
588 } | |
589 | |
590 template <typename T, typename... Args> | |
591 void push_with_data(const void* data, size_t bytes, Args&&... args) { | |
592 static_assert(std::is_convertible<T, PaintOpWithData>::value, | |
593 "T is not a PaintOpWithData"); | |
594 #if !defined(OS_CHROMEOS) | |
595 // TODO(enne): non-linux chromeos builds think that DrawTextOp | |
596 // can be converted to a PaintOpWithDataArrayBase. OOPS. | |
597 static_assert(!std::is_convertible<T, PaintOpWithDataArrayBase>::value, | |
598 "Type needs to use push_with_data_array"); | |
599 #endif | |
600 DCHECK_GE(bytes, 0u); | |
601 T* op = push_internal<T>(bytes, bytes, std::forward<Args>(args)...); | |
602 memcpy(paint_op_data(op), data, bytes); | |
603 | |
604 #if DCHECK_IS_ON() | |
605 // Double check the data fits between op and next op and doesn't clobber. | |
606 char* op_start = reinterpret_cast<char*>(op); | |
607 char* op_end = op_start + sizeof(T); | |
608 char* next_op = op_start + op->skip; | |
609 char* data_start = reinterpret_cast<char*>(paint_op_data(op)); | |
610 char* data_end = data_start + bytes; | |
611 DCHECK_GE(data_start, op_end); | |
612 DCHECK_LT(data_start, next_op); | |
613 DCHECK_LE(data_end, next_op); | |
614 #endif | |
615 } | |
616 | |
617 template <typename T, typename M, typename... Args> | |
618 void push_with_data_array(const void* data, | |
619 size_t bytes, | |
620 const M* array, | |
621 size_t count, | |
622 Args&&... args) { | |
623 static_assert(std::is_convertible<T, PaintOpWithDataArray<M>>::value, | |
624 "T is not a PaintOpWithDataArray"); | |
625 DCHECK_GE(bytes, 0u); | |
626 DCHECK_GE(count, 0u); | |
627 size_t array_size = sizeof(M) * count; | |
628 size_t total_size = bytes + array_size; | |
629 T* op = | |
630 push_internal<T>(total_size, bytes, count, std::forward<Args>(args)...); | |
631 memcpy(paint_op_data(op), data, bytes); | |
632 memcpy(paint_op_array<M>(op), array, array_size); | |
633 | |
634 #if DCHECK_IS_ON() | |
635 // Double check data and array don't clobber op, next op, or each other | |
636 char* op_start = reinterpret_cast<char*>(op); | |
637 char* op_end = op_start + sizeof(T); | |
638 char* next_op = op_start + op->skip; | |
639 char* data_start = reinterpret_cast<char*>(paint_op_data(op)); | |
640 char* data_end = data_start + bytes; | |
641 char* array_start = reinterpret_cast<char*>(paint_op_array<M>(op)); | |
642 char* array_end = array_start + array_size; | |
643 DCHECK_GE(data_start, op_end); | |
644 DCHECK_LE(data_start, array_start); | |
645 DCHECK_GE(array_start, data_end); | |
646 DCHECK_LE(array_end, next_op); | |
647 #endif | |
648 } | |
649 | |
650 class Iterator { | |
651 public: | |
652 explicit Iterator(const PaintOpBuffer* buffer) | |
653 : buffer_(buffer), ptr_(buffer_->data_.get()) {} | |
654 | |
655 PaintOp* operator->() const { | |
656 return op_idx_ ? reinterpret_cast<PaintOp*>(ptr_) : buffer_->GetFirstOp(); | |
657 } | |
658 PaintOp* operator*() const { return operator->(); } | |
659 Iterator begin() { return Iterator(buffer_, buffer_->data_.get(), 0); } | |
660 Iterator end() { | |
661 return Iterator(buffer_, buffer_->data_.get() + buffer_->used_, | |
662 buffer_->approximateOpCount()); | |
663 } | |
664 bool operator!=(const Iterator& other) { | |
665 // Not valid to compare iterators on different buffers. | |
666 DCHECK_EQ(other.buffer_, buffer_); | |
667 return other.op_idx_ != op_idx_; | |
668 } | |
669 Iterator& operator++() { | |
670 if (!op_idx_++) | |
671 return *this; | |
672 PaintOp* op = **this; | |
673 uint32_t type = op->type; | |
674 CHECK_LE(type, static_cast<uint32_t>(PaintOpType::LastPaintOpType)); | |
675 ptr_ += op->skip; | |
676 return *this; | |
677 } | |
678 operator bool() const { return op_idx_ < buffer_->approximateOpCount(); } | |
679 | |
680 int op_idx() const { return op_idx_; } | |
681 | |
682 // Return the next op without advancing the iterator, or nullptr if none. | |
683 PaintOp* peek1() const { | |
684 if (op_idx_ + 1 >= buffer_->approximateOpCount()) | |
685 return nullptr; | |
686 if (!op_idx_) | |
687 return reinterpret_cast<PaintOp*>(ptr_); | |
688 return reinterpret_cast<PaintOp*>(ptr_ + (*this)->skip); | |
689 } | |
690 | |
691 // Return the op two ops ahead without advancing the iterator, or nullptr if | |
692 // none. | |
693 PaintOp* peek2() const { | |
694 if (op_idx_ + 2 >= buffer_->approximateOpCount()) | |
695 return nullptr; | |
696 char* next = ptr_ + reinterpret_cast<PaintOp*>(ptr_)->skip; | |
697 PaintOp* next_op = reinterpret_cast<PaintOp*>(next); | |
698 if (!op_idx_) | |
699 return next_op; | |
700 return reinterpret_cast<PaintOp*>(next + next_op->skip); | |
701 } | |
702 | |
703 private: | |
704 Iterator(const PaintOpBuffer* buffer, char* ptr, int op_idx) | |
705 : buffer_(buffer), ptr_(ptr), op_idx_(op_idx) {} | |
706 | |
707 const PaintOpBuffer* buffer_ = nullptr; | |
708 char* ptr_ = nullptr; | |
709 int op_idx_ = 0; | |
710 }; | |
711 | |
712 private: | |
713 template <typename T, bool HasFlags> | |
714 struct CountSlowPathsFromFlags { | |
715 static int Count(const T* op) { return 0; } | |
716 }; | |
717 | |
718 template <typename T> | |
719 struct CountSlowPathsFromFlags<T, true> { | |
720 static int Count(const T* op) { return op->flags.getPathEffect() ? 1 : 0; } | |
721 }; | |
722 | |
723 template <typename T, typename... Args> | |
724 T* push_internal(size_t bytes, Args&&... args) { | |
725 size_t skip = SkAlignPtr(sizeof(T) + bytes); | |
726 DCHECK_LT(skip, static_cast<size_t>(1) << 24); | |
727 if (used_ + skip > reserved_ || !op_count_) { | |
728 if (!op_count_) { | |
729 if (bytes) { | |
730 // Internal first_op buffer doesn't have room for extra data. | |
731 // If the op wants extra bytes, then we'll just store a Noop | |
732 // in the first_op and proceed from there. This seems unlikely | |
733 // to be a common case. | |
734 push<NoopOp>(); | |
735 } else { | |
736 T* op = reinterpret_cast<T*>(&first_op_[0]); | |
737 new (op) T{std::forward<Args>(args)...}; | |
738 op->type = static_cast<uint32_t>(T::kType); | |
739 op->skip = 0; | |
740 op_count_++; | |
741 return op; | |
742 } | |
743 } | |
744 | |
745 // Start reserved_ at kInitialBufferSize and then double. | |
746 // ShrinkToFit can make this smaller afterwards. | |
747 while (used_ + skip > reserved_) | |
748 reserved_ = reserved_ ? reserved_ * 2 : kInitialBufferSize; | |
749 data_.realloc(reserved_); | |
750 } | |
751 DCHECK_LE(used_ + skip, reserved_); | |
752 | |
753 T* op = reinterpret_cast<T*>(data_.get() + used_); | |
754 used_ += skip; | |
755 new (op) T(std::forward<Args>(args)...); | |
756 op->type = static_cast<uint32_t>(T::kType); | |
757 op->skip = skip; | |
758 op_count_++; | |
759 | |
760 num_slow_paths_ += CountSlowPathsFromFlags<T, T::kHasPaintFlags>::Count(op); | |
761 num_slow_paths_ += op->CountSlowPaths(); | |
762 | |
763 subrecord_bytes_used_ += op->AdditionalBytesUsed(); | |
764 | |
765 return op; | |
766 } | |
767 | |
768 // As a performance optimization because n=1 is an extremely common case just | |
769 // store the first op in the PaintOpBuffer itself to avoid an extra alloc. | |
770 char first_op_[sizeof(LargestPaintOp)]; | |
danakj
2017/04/20 17:32:32
This needs to be aligned or parts of the op can fa
| |
771 SkAutoTMalloc<char> data_; | |
772 size_t used_ = 0; | |
773 size_t reserved_ = 0; | |
774 int op_count_ = 0; | |
775 | |
776 // Record paths for veto-to-msaa for gpu raster. | |
777 int num_slow_paths_ = 0; | |
778 // Record additional bytes used by referenced sub-records and display lists. | |
779 size_t subrecord_bytes_used_ = 0; | |
780 SkRect cull_rect_; | |
781 | |
782 DISALLOW_COPY_AND_ASSIGN(PaintOpBuffer); | |
783 }; | |
784 | |
785 } // namespace cc | |
786 | |
787 #endif // CC_PAINT_PAINT_OP_BUFFER_H_ | |
OLD | NEW |