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 | 119 |
1 files changed, 112 insertions, 7 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 0ab4e34249c..5e150bb70f9 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 @@ -11,14 +11,9 @@ #include "third_party/skia/include/core/SkCanvas.h" #include "third_party/skia/include/core/SkData.h" -namespace blink { +#include "third_party/blink/renderer/platform/graphics/logging_canvas.h" -#if DCHECK_IS_ON() -void DrawingDisplayItem::PropertiesAsJSON(JSONObject& json) const { - DisplayItem::PropertiesAsJSON(json); - json.SetBoolean("opaque", known_to_be_opaque_); -} -#endif +namespace blink { static SkBitmap RecordToBitmap(sk_sp<const PaintRecord> record, const IntRect& bounds) { @@ -83,4 +78,114 @@ bool DrawingDisplayItem::Equals(const DisplayItem& other) const { return BitmapsEqual(std::move(record), std::move(other_record), bounds); } +SkColor DrawingDisplayItem::BackgroundColor() const { + if (GetType() != DisplayItem::kBoxDecorationBackground && + GetType() != DisplayItem::kDocumentBackground) + return SK_ColorTRANSPARENT; + + if (!record_) + return SK_ColorTRANSPARENT; + + for (cc::PaintOpBuffer::Iterator it(record_.get()); it; ++it) { + const auto* op = *it; + if (op->GetType() == cc::PaintOpType::DrawRect || + op->GetType() == cc::PaintOpType::DrawRRect) { + const auto& flags = static_cast<const cc::PaintOpWithFlags*>(op)->flags; + // Skip op with looper or shader which may modify the color. + if (!flags.getLooper() && !flags.getShader() && + flags.getStyle() == cc::PaintFlags::kFill_Style) + return flags.getColor(); + } + } + return SK_ColorTRANSPARENT; +} + +// 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( + const PaintRecord* record) const { + if (!record) + return false; + + // This limit keeps the algorithm fast, while allowing check of enough paint + // operations for most blink painted results. + constexpr wtf_size_t kOpCountLimit = 4; + wtf_size_t op_count = 0; + for (cc::PaintOpBuffer::Iterator it(record); it; ++it) { + if (++op_count > kOpCountLimit) + return false; + + const auto* op = *it; + // Deal with the common pattern of clipped bleed avoiding images like: + // Save, ClipRect, Draw..., Restore. + 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; + continue; + } + + if (!op->IsDrawOp()) + return false; + + if (op->GetType() == cc::PaintOpType::DrawRecord) { + return CalculateKnownToBeOpaque( + static_cast<const cc::DrawRecordOp*>(op)->record.get()); + } + + 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; + + 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()) + 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; + } + return false; +} + } // namespace blink |