diff options
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.cc | 208 |
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 |