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.cc119
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