summaryrefslogtreecommitdiff
path: root/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.cc
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.cc')
-rw-r--r--chromium/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.cc208
1 files changed, 154 insertions, 54 deletions
diff --git a/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.cc b/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.cc
index 756ae7f21df..bffc3a96f40 100644
--- a/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.cc
+++ b/chromium/third_party/blink/renderer/platform/graphics/paint/drawing_display_item.cc
@@ -119,21 +119,36 @@ SkColor DrawingDisplayItem::BackgroundColor(float& area) const {
return SK_ColorTRANSPARENT;
}
+IntRect DrawingDisplayItem::CalculateRectKnownToBeOpaque() const {
+ IntRect rect = CalculateRectKnownToBeOpaqueForRecord(record_.get());
+ if (rect.IsEmpty()) {
+ SetOpaqueness(Opaqueness::kNone);
+ } else if (rect == VisualRect()) {
+ SetOpaqueness(Opaqueness::kFull);
+ } else {
+ DCHECK(VisualRect().Contains(rect));
+ DCHECK_EQ(GetOpaqueness(), Opaqueness::kOther);
+ }
+ return rect;
+}
+
// This is not a PaintRecord method because it's not a general opaqueness
// detection algorithm (which might be more complex and slower), but works well
// and fast for most blink painted results.
-bool DrawingDisplayItem::CalculateKnownToBeOpaque(
+IntRect DrawingDisplayItem::CalculateRectKnownToBeOpaqueForRecord(
const PaintRecord* record) const {
if (!record)
- return false;
+ return IntRect();
// This limit keeps the algorithm fast, while allowing check of enough paint
// operations for most blink painted results.
- constexpr wtf_size_t kOpCountLimit = 4;
+ constexpr wtf_size_t kOpCountLimit = 8;
+ IntRect opaque_rect;
wtf_size_t op_count = 0;
+ IntRect clip_rect = VisualRect();
for (cc::PaintOpBuffer::Iterator it(record); it; ++it) {
if (++op_count > kOpCountLimit)
- return false;
+ break;
const auto* op = *it;
// Deal with the common pattern of clipped bleed avoiding images like:
@@ -141,70 +156,155 @@ bool DrawingDisplayItem::CalculateKnownToBeOpaque(
if (op->GetType() == cc::PaintOpType::Save)
continue;
if (op->GetType() == cc::PaintOpType::ClipRect) {
- const auto* clip_rect_op = static_cast<const cc::ClipRectOp*>(op);
- if (!EnclosedIntRect(clip_rect_op->rect).Contains(VisualRect()))
- return false;
+ clip_rect.Intersect(
+ EnclosedIntRect(static_cast<const cc::ClipRectOp*>(op)->rect));
continue;
}
if (!op->IsDrawOp())
- return false;
+ break;
+ IntRect op_opaque_rect;
if (op->GetType() == cc::PaintOpType::DrawRecord) {
- return CalculateKnownToBeOpaque(
+ op_opaque_rect = CalculateRectKnownToBeOpaqueForRecord(
static_cast<const cc::DrawRecordOp*>(op)->record.get());
- }
-
- if (!op->IsPaintOpWithFlags())
- continue;
+ } else {
+ if (!op->IsPaintOpWithFlags())
+ continue;
- const auto& flags = static_cast<const cc::PaintOpWithFlags*>(op)->flags;
- if (flags.getStyle() != cc::PaintFlags::kFill_Style || flags.getLooper() ||
- (flags.getBlendMode() != SkBlendMode::kSrc &&
- flags.getBlendMode() != SkBlendMode::kSrcOver) ||
- flags.getMaskFilter() || flags.getColorFilter() ||
- flags.getImageFilter() || flags.getAlpha() != SK_AlphaOPAQUE ||
- (flags.getShader() && !flags.getShader()->IsOpaque()))
- continue;
+ const auto& flags = static_cast<const cc::PaintOpWithFlags*>(op)->flags;
+ if (flags.getStyle() != cc::PaintFlags::kFill_Style ||
+ flags.getLooper() ||
+ (flags.getBlendMode() != SkBlendMode::kSrc &&
+ flags.getBlendMode() != SkBlendMode::kSrcOver) ||
+ flags.getMaskFilter() || flags.getColorFilter() ||
+ flags.getImageFilter() || flags.getAlpha() != SK_AlphaOPAQUE ||
+ (flags.getShader() && !flags.getShader()->IsOpaque()))
+ continue;
- IntRect opaque_rect;
- switch (op->GetType()) {
- case cc::PaintOpType::DrawRect:
- opaque_rect =
- EnclosedIntRect(static_cast<const cc::DrawRectOp*>(op)->rect);
- break;
- case cc::PaintOpType::DrawIRect:
- opaque_rect = IntRect(static_cast<const cc::DrawIRectOp*>(op)->rect);
- break;
- case cc::PaintOpType::DrawImage: {
- const auto* draw_image_op = static_cast<const cc::DrawImageOp*>(op);
- const auto& image = draw_image_op->image;
- if (!image.IsOpaque())
+ switch (op->GetType()) {
+ case cc::PaintOpType::DrawRect:
+ op_opaque_rect =
+ EnclosedIntRect(static_cast<const cc::DrawRectOp*>(op)->rect);
+ break;
+ case cc::PaintOpType::DrawIRect:
+ op_opaque_rect =
+ IntRect(static_cast<const cc::DrawIRectOp*>(op)->rect);
+ break;
+ case cc::PaintOpType::DrawImage: {
+ const auto* draw_image_op = static_cast<const cc::DrawImageOp*>(op);
+ const auto& image = draw_image_op->image;
+ if (!image.IsOpaque())
+ continue;
+ op_opaque_rect = IntRect(draw_image_op->left, draw_image_op->top,
+ image.width(), image.height());
+ break;
+ }
+ case cc::PaintOpType::DrawImageRect: {
+ const auto* draw_image_rect_op =
+ static_cast<const cc::DrawImageRectOp*>(op);
+ const auto& image = draw_image_rect_op->image;
+ DCHECK(SkRect::MakeWH(image.width(), image.height())
+ .contains(draw_image_rect_op->src));
+ if (!image.IsOpaque())
+ continue;
+ op_opaque_rect = EnclosedIntRect(draw_image_rect_op->dst);
+ break;
+ }
+ default:
continue;
- opaque_rect = IntRect(draw_image_op->left, draw_image_op->top,
- image.width(), image.height());
- break;
- }
- case cc::PaintOpType::DrawImageRect: {
- const auto* draw_image_rect_op =
- static_cast<const cc::DrawImageRectOp*>(op);
- const auto& image = draw_image_rect_op->image;
- DCHECK(SkRect::MakeWH(image.width(), image.height())
- .contains(draw_image_rect_op->src));
- if (!image.IsOpaque())
- continue;
- opaque_rect = EnclosedIntRect(draw_image_rect_op->dst);
- break;
}
- default:
- continue;
}
- // We should never paint outside of the visual rect.
- if (opaque_rect.Contains(VisualRect()))
- return true;
+ opaque_rect = MaximumCoveredRect(opaque_rect, op_opaque_rect);
+ opaque_rect.Intersect(clip_rect);
+ if (opaque_rect == VisualRect())
+ break;
}
- return false;
+ DCHECK(VisualRect().Contains(opaque_rect) || opaque_rect.IsEmpty());
+ return opaque_rect;
+}
+
+IntRect DrawingDisplayItem::TightenVisualRect(
+ const IntRect& visual_rect,
+ sk_sp<const PaintRecord>& record) {
+ DCHECK(ShouldTightenVisualRect(record));
+
+ const auto* op = record->GetFirstOp();
+ if (!op->IsPaintOpWithFlags())
+ return visual_rect;
+
+ const auto& flags = static_cast<const cc::PaintOpWithFlags*>(op)->flags;
+ // The following can cause the painted output to be outside the paint op rect.
+ if (flags.getStyle() != cc::PaintFlags::kFill_Style || flags.getLooper() ||
+ flags.getMaskFilter() || flags.getImageFilter() || flags.getShader()) {
+ return visual_rect;
+ }
+
+ // TODO(pdr): Consider using |PaintOp::GetBounds| which is a more complete
+ // implementation of the logic below.
+
+ IntRect item_rect;
+ switch (op->GetType()) {
+ case cc::PaintOpType::DrawRect:
+ item_rect =
+ EnclosingIntRect(static_cast<const cc::DrawRectOp*>(op)->rect);
+ break;
+ case cc::PaintOpType::DrawIRect:
+ item_rect = IntRect(static_cast<const cc::DrawIRectOp*>(op)->rect);
+ break;
+ case cc::PaintOpType::DrawRRect:
+ item_rect = EnclosingIntRect(
+ static_cast<const cc::DrawRRectOp*>(op)->rrect.rect());
+ break;
+ // TODO(pdr): Support image PaintOpTypes such as DrawImage{Rect}.
+ // TODO(pdr): Consider checking PaintOpType::DrawTextBlob too.
+ default:
+ return visual_rect;
+ }
+
+ // TODO(pdr): Enable this DCHECK which enforces that the original visual rect
+ // was correct and fully contains the recording.
+ // DCHECK(visual_rect.Contains(item_rect));
+ return item_rect;
+}
+
+bool DrawingDisplayItem::IsSolidColor() const {
+ if (!record_)
+ return false;
+
+ // TODO(pdr): We could use SolidColorAnalyzer::DetermineIfSolidColor instead
+ // of special-casing just single-op drawrect solid colors.
+ if (record_->size() != 1)
+ return false;
+
+ const auto* op = record_->GetFirstOp();
+ if (!op->IsPaintOpWithFlags())
+ return false;
+
+ const auto& flags = static_cast<const cc::PaintOpWithFlags*>(op)->flags;
+ // The following can cause the painted output to be outside the paint op rect.
+ if (flags.getStyle() != cc::PaintFlags::kFill_Style || flags.getLooper() ||
+ flags.getMaskFilter() || flags.getImageFilter() || flags.getShader()) {
+ return false;
+ }
+
+ FloatRect solid_color_rect;
+ switch (op->GetType()) {
+ case cc::PaintOpType::DrawRect:
+ solid_color_rect =
+ FloatRect(static_cast<const cc::DrawRectOp*>(op)->rect);
+ break;
+ case cc::PaintOpType::DrawIRect:
+ solid_color_rect =
+ FloatRect(IntRect(static_cast<const cc::DrawIRectOp*>(op)->rect));
+ break;
+ default:
+ return false;
+ }
+
+ // The solid color must fully cover the visual rect.
+ return solid_color_rect.Contains(VisualRect());
}
} // namespace blink