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/paint_op_buffer.h" |
| 6 |
| 7 #include "cc/paint/display_item_list.h" |
| 8 #include "cc/paint/paint_record.h" |
| 9 #include "third_party/skia/include/core/SkAnnotation.h" |
| 10 |
| 11 namespace cc { |
| 12 |
| 13 #define TYPES(M) \ |
| 14 M(AnnotateOp) \ |
| 15 M(ClipPathOp) \ |
| 16 M(ClipRectOp) \ |
| 17 M(ClipRRectOp) \ |
| 18 M(ConcatOp) \ |
| 19 M(DrawArcOp) \ |
| 20 M(DrawCircleOp) \ |
| 21 M(DrawColorOp) \ |
| 22 M(DrawDisplayItemListOp) \ |
| 23 M(DrawDRRectOp) \ |
| 24 M(DrawImageOp) \ |
| 25 M(DrawImageRectOp) \ |
| 26 M(DrawIRectOp) \ |
| 27 M(DrawLineOp) \ |
| 28 M(DrawOvalOp) \ |
| 29 M(DrawPathOp) \ |
| 30 M(DrawPosTextOp) \ |
| 31 M(DrawRecordOp) \ |
| 32 M(DrawRectOp) \ |
| 33 M(DrawRRectOp) \ |
| 34 M(DrawTextOp) \ |
| 35 M(DrawTextBlobOp) \ |
| 36 M(NoopOp) \ |
| 37 M(RestoreOp) \ |
| 38 M(RotateOp) \ |
| 39 M(SaveOp) \ |
| 40 M(SaveLayerOp) \ |
| 41 M(SaveLayerAlphaOp) \ |
| 42 M(ScaleOp) \ |
| 43 M(SetMatrixOp) \ |
| 44 M(TranslateOp) |
| 45 |
| 46 // Helper template to share common code for RasterWithAlpha when paint ops |
| 47 // have or don't have PaintFlags. |
| 48 template <typename T, bool HasFlags> |
| 49 struct Rasterizer { |
| 50 static void Raster(const T* op, |
| 51 SkCanvas* canvas, |
| 52 const SkMatrix& original_ctm) { |
| 53 // Paint ops with kHasPaintFlags need to declare RasterWithPaintFlags |
| 54 // otherwise, the paint op needs its own Raster function. Without its |
| 55 // own, this becomes an infinite loop as PaintOp::Raster calls itself. |
| 56 static_assert( |
| 57 !std::is_same<decltype(&PaintOp::Raster), decltype(&T::Raster)>::value, |
| 58 "No Raster function"); |
| 59 |
| 60 op->Raster(canvas); |
| 61 } |
| 62 static void RasterWithAlpha(const T* op, SkCanvas* canvas, uint8_t alpha) { |
| 63 DCHECK(T::kIsDrawOp); |
| 64 // TODO(enne): is it ok to just drop the bounds here? |
| 65 canvas->saveLayerAlpha(nullptr, alpha); |
| 66 op->Raster(canvas); |
| 67 canvas->restore(); |
| 68 } |
| 69 }; |
| 70 |
| 71 template <typename T> |
| 72 struct Rasterizer<T, true> { |
| 73 static void Raster(const T* op, |
| 74 SkCanvas* canvas, |
| 75 const SkMatrix& original_ctm) { |
| 76 op->RasterWithFlags(canvas, op->flags); |
| 77 } |
| 78 static void RasterWithAlpha(const T* op, SkCanvas* canvas, uint8_t alpha) { |
| 79 DCHECK(T::kIsDrawOp); |
| 80 SkMatrix unused_matrix; |
| 81 if (alpha == 255) { |
| 82 Raster(op, canvas, unused_matrix); |
| 83 } else if (op->flags.SupportsFoldingAlpha()) { |
| 84 PaintFlags flags = op->flags; |
| 85 flags.setAlpha(SkMulDiv255Round(flags.getAlpha(), alpha)); |
| 86 op->RasterWithFlags(canvas, flags); |
| 87 } else { |
| 88 canvas->saveLayerAlpha(nullptr, alpha); |
| 89 op->RasterWithFlags(canvas, op->flags); |
| 90 canvas->restore(); |
| 91 } |
| 92 } |
| 93 }; |
| 94 |
| 95 template <> |
| 96 struct Rasterizer<SetMatrixOp, false> { |
| 97 static void Raster(const SetMatrixOp* op, |
| 98 SkCanvas* canvas, |
| 99 const SkMatrix& original_ctm) { |
| 100 op->Raster(canvas, original_ctm); |
| 101 } |
| 102 static void RasterWithAlpha(const SetMatrixOp* op, |
| 103 SkCanvas* canvas, |
| 104 uint8_t alpha) { |
| 105 NOTREACHED(); |
| 106 } |
| 107 }; |
| 108 |
| 109 template <> |
| 110 struct Rasterizer<DrawRecordOp, false> { |
| 111 static void Raster(const DrawRecordOp* op, |
| 112 SkCanvas* canvas, |
| 113 const SkMatrix& original_ctm) { |
| 114 op->Raster(canvas); |
| 115 } |
| 116 static void RasterWithAlpha(const DrawRecordOp* op, |
| 117 SkCanvas* canvas, |
| 118 uint8_t alpha) { |
| 119 // This "looking into records" optimization is done here instead of |
| 120 // in the PaintOpBuffer::Raster function as DisplayItemList calls |
| 121 // into RasterWithAlpha directly. |
| 122 if (op->record->approximateOpCount() == 1) { |
| 123 PaintOp* single_op = op->record->GetFirstOp(); |
| 124 // RasterWithAlpha only supported for draw ops. |
| 125 if (single_op->IsDrawOp()) { |
| 126 single_op->RasterWithAlpha(canvas, alpha); |
| 127 return; |
| 128 } |
| 129 } |
| 130 |
| 131 canvas->saveLayerAlpha(nullptr, alpha); |
| 132 op->Raster(canvas); |
| 133 canvas->restore(); |
| 134 } |
| 135 }; |
| 136 |
| 137 // TODO(enne): partially specialize RasterWithAlpha for draw color? |
| 138 |
| 139 static constexpr size_t kNumOpTypes = |
| 140 static_cast<size_t>(PaintOpType::LastPaintOpType) + 1; |
| 141 |
| 142 // Verify that every op is in the TYPES macro. |
| 143 #define M(T) +1 |
| 144 static_assert(kNumOpTypes == TYPES(M), "Missing op in list"); |
| 145 #undef M |
| 146 |
| 147 using RasterFunction = void (*)(const PaintOp* op, |
| 148 SkCanvas* canvas, |
| 149 const SkMatrix& original_ctm); |
| 150 #define M(T) \ |
| 151 [](const PaintOp* op, SkCanvas* canvas, const SkMatrix& original_ctm) { \ |
| 152 Rasterizer<T, T::kHasPaintFlags>::Raster(static_cast<const T*>(op), \ |
| 153 canvas, original_ctm); \ |
| 154 }, |
| 155 static const RasterFunction g_raster_functions[kNumOpTypes] = {TYPES(M)}; |
| 156 #undef M |
| 157 |
| 158 using RasterAlphaFunction = void (*)(const PaintOp* op, |
| 159 SkCanvas* canvas, |
| 160 uint8_t alpha); |
| 161 #define M(T) \ |
| 162 T::kIsDrawOp ? \ |
| 163 [](const PaintOp* op, SkCanvas* canvas, uint8_t alpha) { \ |
| 164 Rasterizer<T, T::kHasPaintFlags>::RasterWithAlpha( \ |
| 165 static_cast<const T*>(op), canvas, alpha); \ |
| 166 } : static_cast<RasterAlphaFunction>(nullptr), |
| 167 static const RasterAlphaFunction g_raster_alpha_functions[kNumOpTypes] = { |
| 168 TYPES(M)}; |
| 169 #undef M |
| 170 |
| 171 // Most state ops (matrix, clip, save, restore) have a trivial destructor. |
| 172 // TODO(enne): evaluate if we need the nullptr optimization or if |
| 173 // we even need to differentiate trivial destructors here. |
| 174 using VoidFunction = void (*)(PaintOp* op); |
| 175 #define M(T) \ |
| 176 !std::is_trivially_destructible<T>::value \ |
| 177 ? [](PaintOp* op) { static_cast<T*>(op)->~T(); } \ |
| 178 : static_cast<VoidFunction>(nullptr), |
| 179 static const VoidFunction g_destructor_functions[kNumOpTypes] = {TYPES(M)}; |
| 180 #undef M |
| 181 |
| 182 #define M(T) T::kIsDrawOp, |
| 183 static bool g_is_draw_op[kNumOpTypes] = {TYPES(M)}; |
| 184 #undef M |
| 185 |
| 186 #define M(T) \ |
| 187 static_assert(sizeof(T) <= sizeof(LargestPaintOp), \ |
| 188 #T " must be no bigger than LargestPaintOp"); |
| 189 TYPES(M); |
| 190 #undef M |
| 191 |
| 192 #define M(T) \ |
| 193 static_assert(ALIGNOF(T) <= PaintOpBuffer::PaintOpAlign, \ |
| 194 #T " must have alignment no bigger than PaintOpAlign"); |
| 195 TYPES(M); |
| 196 #undef M |
| 197 |
| 198 #undef TYPES |
| 199 |
| 200 SkRect PaintOp::kUnsetRect = {SK_ScalarInfinity, 0, 0, 0}; |
| 201 |
| 202 void AnnotateOp::Raster(SkCanvas* canvas) const { |
| 203 switch (annotation_type) { |
| 204 case PaintCanvas::AnnotationType::URL: |
| 205 SkAnnotateRectWithURL(canvas, rect, data.get()); |
| 206 break; |
| 207 case PaintCanvas::AnnotationType::LINK_TO_DESTINATION: |
| 208 SkAnnotateLinkToDestination(canvas, rect, data.get()); |
| 209 break; |
| 210 case PaintCanvas::AnnotationType::NAMED_DESTINATION: { |
| 211 SkPoint point = SkPoint::Make(rect.x(), rect.y()); |
| 212 SkAnnotateNamedDestination(canvas, point, data.get()); |
| 213 break; |
| 214 } |
| 215 } |
| 216 } |
| 217 |
| 218 void ClipPathOp::Raster(SkCanvas* canvas) const { |
| 219 canvas->clipPath(path, op, antialias); |
| 220 } |
| 221 |
| 222 void ClipRectOp::Raster(SkCanvas* canvas) const { |
| 223 canvas->clipRect(rect, op, antialias); |
| 224 } |
| 225 |
| 226 void ClipRRectOp::Raster(SkCanvas* canvas) const { |
| 227 canvas->clipRRect(rrect, op, antialias); |
| 228 } |
| 229 |
| 230 void ConcatOp::Raster(SkCanvas* canvas) const { |
| 231 canvas->concat(matrix); |
| 232 } |
| 233 |
| 234 void DrawArcOp::RasterWithFlags(SkCanvas* canvas, |
| 235 const PaintFlags& flags) const { |
| 236 canvas->drawArc(oval, start_angle, sweep_angle, use_center, ToSkPaint(flags)); |
| 237 } |
| 238 |
| 239 void DrawCircleOp::RasterWithFlags(SkCanvas* canvas, |
| 240 const PaintFlags& flags) const { |
| 241 canvas->drawCircle(cx, cy, radius, ToSkPaint(flags)); |
| 242 } |
| 243 |
| 244 void DrawColorOp::Raster(SkCanvas* canvas) const { |
| 245 canvas->drawColor(color, mode); |
| 246 } |
| 247 |
| 248 void DrawDisplayItemListOp::Raster(SkCanvas* canvas) const { |
| 249 list->Raster(canvas, nullptr); |
| 250 } |
| 251 |
| 252 void DrawDRRectOp::RasterWithFlags(SkCanvas* canvas, |
| 253 const PaintFlags& flags) const { |
| 254 canvas->drawDRRect(outer, inner, ToSkPaint(flags)); |
| 255 } |
| 256 |
| 257 void DrawImageOp::RasterWithFlags(SkCanvas* canvas, |
| 258 const PaintFlags& flags) const { |
| 259 canvas->drawImage(image.sk_image().get(), left, top, ToSkPaint(&flags)); |
| 260 } |
| 261 |
| 262 void DrawImageRectOp::RasterWithFlags(SkCanvas* canvas, |
| 263 const PaintFlags& flags) const { |
| 264 // TODO(enne): Probably PaintCanvas should just use the skia enum directly. |
| 265 SkCanvas::SrcRectConstraint skconstraint = |
| 266 static_cast<SkCanvas::SrcRectConstraint>(constraint); |
| 267 canvas->drawImageRect(image.sk_image().get(), src, dst, ToSkPaint(&flags), |
| 268 skconstraint); |
| 269 } |
| 270 |
| 271 void DrawIRectOp::RasterWithFlags(SkCanvas* canvas, |
| 272 const PaintFlags& flags) const { |
| 273 canvas->drawIRect(rect, ToSkPaint(flags)); |
| 274 } |
| 275 |
| 276 void DrawLineOp::RasterWithFlags(SkCanvas* canvas, |
| 277 const PaintFlags& flags) const { |
| 278 canvas->drawLine(x0, y0, x1, y1, ToSkPaint(flags)); |
| 279 } |
| 280 |
| 281 void DrawOvalOp::RasterWithFlags(SkCanvas* canvas, |
| 282 const PaintFlags& flags) const { |
| 283 canvas->drawOval(oval, ToSkPaint(flags)); |
| 284 } |
| 285 |
| 286 void DrawPathOp::RasterWithFlags(SkCanvas* canvas, |
| 287 const PaintFlags& flags) const { |
| 288 canvas->drawPath(path, ToSkPaint(flags)); |
| 289 } |
| 290 |
| 291 void DrawPosTextOp::RasterWithFlags(SkCanvas* canvas, |
| 292 const PaintFlags& flags) const { |
| 293 canvas->drawPosText(GetData(), bytes, GetArray(), ToSkPaint(flags)); |
| 294 } |
| 295 |
| 296 void DrawRecordOp::Raster(SkCanvas* canvas) const { |
| 297 record->playback(canvas); |
| 298 } |
| 299 |
| 300 void DrawRectOp::RasterWithFlags(SkCanvas* canvas, |
| 301 const PaintFlags& flags) const { |
| 302 canvas->drawRect(rect, ToSkPaint(flags)); |
| 303 } |
| 304 |
| 305 void DrawRRectOp::RasterWithFlags(SkCanvas* canvas, |
| 306 const PaintFlags& flags) const { |
| 307 canvas->drawRRect(rrect, ToSkPaint(flags)); |
| 308 } |
| 309 |
| 310 void DrawTextOp::RasterWithFlags(SkCanvas* canvas, |
| 311 const PaintFlags& flags) const { |
| 312 canvas->drawText(GetData(), bytes, x, y, ToSkPaint(flags)); |
| 313 } |
| 314 |
| 315 void DrawTextBlobOp::RasterWithFlags(SkCanvas* canvas, |
| 316 const PaintFlags& flags) const { |
| 317 canvas->drawTextBlob(blob.get(), x, y, ToSkPaint(flags)); |
| 318 } |
| 319 |
| 320 void RestoreOp::Raster(SkCanvas* canvas) const { |
| 321 canvas->restore(); |
| 322 } |
| 323 |
| 324 void RotateOp::Raster(SkCanvas* canvas) const { |
| 325 canvas->rotate(degrees); |
| 326 } |
| 327 |
| 328 void SaveOp::Raster(SkCanvas* canvas) const { |
| 329 canvas->save(); |
| 330 } |
| 331 |
| 332 void SaveLayerOp::RasterWithFlags(SkCanvas* canvas, |
| 333 const PaintFlags& flags) const { |
| 334 // See PaintOp::kUnsetRect |
| 335 bool unset = bounds.left() == SK_ScalarInfinity; |
| 336 |
| 337 canvas->saveLayer(unset ? nullptr : &bounds, ToSkPaint(&flags)); |
| 338 } |
| 339 |
| 340 void SaveLayerAlphaOp::Raster(SkCanvas* canvas) const { |
| 341 // See PaintOp::kUnsetRect |
| 342 bool unset = bounds.left() == SK_ScalarInfinity; |
| 343 canvas->saveLayerAlpha(unset ? nullptr : &bounds, alpha); |
| 344 } |
| 345 |
| 346 void ScaleOp::Raster(SkCanvas* canvas) const { |
| 347 canvas->scale(sx, sy); |
| 348 } |
| 349 |
| 350 void SetMatrixOp::Raster(SkCanvas* canvas, const SkMatrix& original_ctm) const { |
| 351 canvas->setMatrix(SkMatrix::Concat(original_ctm, matrix)); |
| 352 } |
| 353 |
| 354 void TranslateOp::Raster(SkCanvas* canvas) const { |
| 355 canvas->translate(dx, dy); |
| 356 } |
| 357 |
| 358 bool PaintOp::IsDrawOp() const { |
| 359 return g_is_draw_op[type]; |
| 360 } |
| 361 |
| 362 void PaintOp::Raster(SkCanvas* canvas, const SkMatrix& original_ctm) const { |
| 363 g_raster_functions[type](this, canvas, original_ctm); |
| 364 } |
| 365 |
| 366 void PaintOp::RasterWithAlpha(SkCanvas* canvas, uint8_t alpha) const { |
| 367 g_raster_alpha_functions[type](this, canvas, alpha); |
| 368 } |
| 369 |
| 370 int ClipPathOp::CountSlowPaths() const { |
| 371 return antialias && !path.isConvex() ? 1 : 0; |
| 372 } |
| 373 |
| 374 int DrawLineOp::CountSlowPaths() const { |
| 375 if (const SkPathEffect* effect = flags.getPathEffect()) { |
| 376 SkPathEffect::DashInfo info; |
| 377 SkPathEffect::DashType dashType = effect->asADash(&info); |
| 378 if (flags.getStrokeCap() != PaintFlags::kRound_Cap && |
| 379 dashType == SkPathEffect::kDash_DashType && info.fCount == 2) { |
| 380 // The PaintFlags will count this as 1, so uncount that here as |
| 381 // this kind of line is special cased and not slow. |
| 382 return -1; |
| 383 } |
| 384 } |
| 385 return 0; |
| 386 } |
| 387 |
| 388 int DrawPathOp::CountSlowPaths() const { |
| 389 // This logic is copied from SkPathCounter instead of attempting to expose |
| 390 // that from Skia. |
| 391 if (!flags.isAntiAlias() || path.isConvex()) |
| 392 return 0; |
| 393 |
| 394 PaintFlags::Style paintStyle = flags.getStyle(); |
| 395 const SkRect& pathBounds = path.getBounds(); |
| 396 if (paintStyle == PaintFlags::kStroke_Style && flags.getStrokeWidth() == 0) { |
| 397 // AA hairline concave path is not slow. |
| 398 return 0; |
| 399 } else if (paintStyle == PaintFlags::kFill_Style && |
| 400 pathBounds.width() < 64.f && pathBounds.height() < 64.f && |
| 401 !path.isVolatile()) { |
| 402 // AADF eligible concave path is not slow. |
| 403 return 0; |
| 404 } else { |
| 405 return 1; |
| 406 } |
| 407 } |
| 408 |
| 409 AnnotateOp::AnnotateOp(PaintCanvas::AnnotationType annotation_type, |
| 410 const SkRect& rect, |
| 411 sk_sp<SkData> data) |
| 412 : annotation_type(annotation_type), rect(rect), data(std::move(data)) {} |
| 413 |
| 414 AnnotateOp::~AnnotateOp() = default; |
| 415 |
| 416 DrawDisplayItemListOp::DrawDisplayItemListOp( |
| 417 scoped_refptr<DisplayItemList> list) |
| 418 : list(list) {} |
| 419 |
| 420 size_t DrawDisplayItemListOp::AdditionalBytesUsed() const { |
| 421 return list->ApproximateMemoryUsage(); |
| 422 } |
| 423 |
| 424 DrawDisplayItemListOp::DrawDisplayItemListOp(const DrawDisplayItemListOp& op) = |
| 425 default; |
| 426 |
| 427 DrawDisplayItemListOp& DrawDisplayItemListOp::operator=( |
| 428 const DrawDisplayItemListOp& op) = default; |
| 429 |
| 430 DrawDisplayItemListOp::~DrawDisplayItemListOp() = default; |
| 431 |
| 432 DrawImageOp::DrawImageOp(const PaintImage& image, |
| 433 SkScalar left, |
| 434 SkScalar top, |
| 435 const PaintFlags* flags) |
| 436 : image(image), |
| 437 left(left), |
| 438 top(top), |
| 439 flags(flags ? *flags : PaintFlags()) {} |
| 440 |
| 441 DrawImageOp::~DrawImageOp() = default; |
| 442 |
| 443 DrawImageRectOp::DrawImageRectOp(const PaintImage& image, |
| 444 const SkRect& src, |
| 445 const SkRect& dst, |
| 446 const PaintFlags* flags, |
| 447 PaintCanvas::SrcRectConstraint constraint) |
| 448 : image(image), |
| 449 flags(flags ? *flags : PaintFlags()), |
| 450 src(src), |
| 451 dst(dst), |
| 452 constraint(constraint) {} |
| 453 |
| 454 DrawImageRectOp::~DrawImageRectOp() = default; |
| 455 |
| 456 DrawPosTextOp::DrawPosTextOp(size_t bytes, |
| 457 size_t count, |
| 458 const PaintFlags& flags) |
| 459 : PaintOpWithArray(bytes, count), flags(flags) {} |
| 460 |
| 461 DrawPosTextOp::~DrawPosTextOp() = default; |
| 462 |
| 463 DrawRecordOp::DrawRecordOp(sk_sp<const PaintRecord> record) |
| 464 : record(std::move(record)) {} |
| 465 |
| 466 DrawRecordOp::~DrawRecordOp() = default; |
| 467 |
| 468 size_t DrawRecordOp::AdditionalBytesUsed() const { |
| 469 return record->approximateBytesUsed(); |
| 470 } |
| 471 |
| 472 DrawTextBlobOp::DrawTextBlobOp(sk_sp<SkTextBlob> blob, |
| 473 SkScalar x, |
| 474 SkScalar y, |
| 475 const PaintFlags& flags) |
| 476 : blob(std::move(blob)), x(x), y(y), flags(flags) {} |
| 477 |
| 478 DrawTextBlobOp::~DrawTextBlobOp() = default; |
| 479 |
| 480 PaintOpBuffer::PaintOpBuffer() : cull_rect_(SkRect::MakeEmpty()) {} |
| 481 |
| 482 PaintOpBuffer::PaintOpBuffer(const SkRect& cull_rect) : cull_rect_(cull_rect) {} |
| 483 |
| 484 PaintOpBuffer::~PaintOpBuffer() { |
| 485 Reset(); |
| 486 } |
| 487 |
| 488 void PaintOpBuffer::Reset() { |
| 489 for (auto* op : Iterator(this)) { |
| 490 auto func = g_destructor_functions[op->type]; |
| 491 if (func) |
| 492 func(op); |
| 493 } |
| 494 |
| 495 // Leave data_ allocated, reserved_ unchanged. |
| 496 used_ = 0; |
| 497 op_count_ = 0; |
| 498 num_slow_paths_ = 0; |
| 499 } |
| 500 |
| 501 void PaintOpBuffer::playback(SkCanvas* canvas) const { |
| 502 // TODO(enne): a PaintRecord that contains a SetMatrix assumes that the |
| 503 // SetMatrix is local to that PaintRecord itself. Said differently, if you |
| 504 // translate(x, y), then draw a paint record with a SetMatrix(identity), |
| 505 // the translation should be preserved instead of clobbering the top level |
| 506 // transform. This could probably be done more efficiently. |
| 507 SkMatrix original = canvas->getTotalMatrix(); |
| 508 |
| 509 for (Iterator iter(this); iter; ++iter) { |
| 510 // Optimize out save/restores or save/draw/restore that can be a single |
| 511 // draw. See also: similar code in SkRecordOpts and cc's DisplayItemList. |
| 512 // TODO(enne): consider making this recursive? |
| 513 const PaintOp* op = *iter; |
| 514 if (op->GetType() == PaintOpType::SaveLayerAlpha) { |
| 515 const PaintOp* second = iter.peek1(); |
| 516 if (second) { |
| 517 if (second->GetType() == PaintOpType::Restore) { |
| 518 ++iter; |
| 519 continue; |
| 520 } |
| 521 if (second->IsDrawOp()) { |
| 522 const PaintOp* third = iter.peek2(); |
| 523 if (third && third->GetType() == PaintOpType::Restore) { |
| 524 const SaveLayerAlphaOp* save_op = |
| 525 static_cast<const SaveLayerAlphaOp*>(op); |
| 526 second->RasterWithAlpha(canvas, save_op->alpha); |
| 527 ++iter; |
| 528 ++iter; |
| 529 continue; |
| 530 } |
| 531 } |
| 532 } |
| 533 } |
| 534 // TODO(enne): skip SaveLayer followed by restore with nothing in |
| 535 // between, however SaveLayer with image filters on it (or maybe |
| 536 // other PaintFlags options) are not a noop. Figure out what these |
| 537 // are so we can skip them correctly. |
| 538 |
| 539 op->Raster(canvas, original); |
| 540 } |
| 541 } |
| 542 |
| 543 void PaintOpBuffer::playback(SkCanvas* canvas, |
| 544 SkPicture::AbortCallback* callback) const { |
| 545 // The abort callback is only used for analysis, in general, so |
| 546 // this playback code can be more straightforward and not do the |
| 547 // optimizations in the other function. |
| 548 if (!callback) { |
| 549 playback(canvas); |
| 550 return; |
| 551 } |
| 552 |
| 553 SkMatrix original = canvas->getTotalMatrix(); |
| 554 |
| 555 // TODO(enne): ideally callers would just iterate themselves and we |
| 556 // can remove the entire notion of an abort callback. |
| 557 for (auto* op : Iterator(this)) { |
| 558 op->Raster(canvas, original); |
| 559 if (callback && callback->abort()) |
| 560 return; |
| 561 } |
| 562 } |
| 563 |
| 564 void PaintOpBuffer::ReallocBuffer(size_t new_size) { |
| 565 DCHECK_GE(new_size, used_); |
| 566 std::unique_ptr<char, base::AlignedFreeDeleter> new_data( |
| 567 static_cast<char*>(base::AlignedAlloc(new_size, PaintOpAlign))); |
| 568 memcpy(new_data.get(), data_.get(), used_); |
| 569 data_ = std::move(new_data); |
| 570 reserved_ = new_size; |
| 571 } |
| 572 |
| 573 void PaintOpBuffer::ShrinkToFit() { |
| 574 if (!used_ || used_ == reserved_) |
| 575 return; |
| 576 ReallocBuffer(used_); |
| 577 } |
| 578 |
| 579 } // namespace cc |
OLD | NEW |