Remove cullRect() from PaintOpBuffer.

Pass it directly to RecordPaintCanvas and ToSkPicture, and other skia
methods which is where it is used.

This allows us to more easily get rid of cc::DisplayItem and its
subclasses, replacing them with a PaintOpBuffer in DisplayItemList
directly instead. The difficulty I faced with that was that if
DisplayItemList has a single PaintOpBuffer, then it has a single
cull rect. However when painting, each "batch" of PaintOps can
have a different cull rect (corresponding to the PaintOps that
would have been in a single DisplayItem before). So, instead the
cull rect should be a property of recording at the
RecordPaintCanvas level, which is a temporary object. As such,
creators of cc::RecordPaintCanvas (mostly thru cc::PaintRecorder)
need to manage the cull rect themselves to pass to things that
want to use it with the cc::PaintOpBuffer (aka cc::PaintRecord at
this time).

Original code review was done on gerrit:
https://chromium-review.googlesource.com/c/503472

R=chrishtr@chromium.org, enne@chromium.org, pdr@chromium.org
BUG=671433, 646010, 724367
CQ_INCLUDE_TRYBOTS=master.tryserver.blink:linux_trusty_blink_rel;master.tryserver.chromium.linux:linux_layout_tests_slimming_paint_v2

Review-Url: https://codereview.chromium.org/2889653002 .
Cr-Original-Commit-Position: refs/heads/master@{#472917}
Committed: https://chromium.googlesource.com/chromium/src/+/c5f1b6126a7657234b9abc0c4359cbab45850b69
Review-Url: https://codereview.chromium.org/2889653002
Cr-Commit-Position: refs/heads/master@{#473975}
diff --git a/cc/blink/web_display_item_list_impl.cc b/cc/blink/web_display_item_list_impl.cc
index 889566b..c1c47de 100644
--- a/cc/blink/web_display_item_list_impl.cc
+++ b/cc/blink/web_display_item_list_impl.cc
@@ -23,6 +23,7 @@
 #include "third_party/skia/include/core/SkMatrix44.h"
 #include "ui/gfx/geometry/rect_conversions.h"
 #include "ui/gfx/geometry/safe_integer_conversions.h"
+#include "ui/gfx/skia_util.h"
 #include "ui/gfx/transform.h"
 
 namespace cc_blink {
@@ -41,9 +42,10 @@
 
 void WebDisplayItemListImpl::AppendDrawingItem(
     const blink::WebRect& visual_rect,
-    sk_sp<const cc::PaintRecord> record) {
+    sk_sp<const cc::PaintRecord> record,
+    const blink::WebRect& record_bounds) {
   display_item_list_->CreateAndAppendDrawingItem<cc::DrawingDisplayItem>(
-      visual_rect, std::move(record));
+      visual_rect, std::move(record), gfx::RectToSkRect(record_bounds));
 }
 
 void WebDisplayItemListImpl::AppendClipItem(
diff --git a/cc/blink/web_display_item_list_impl.h b/cc/blink/web_display_item_list_impl.h
index b540f1c..e3fa9b8 100644
--- a/cc/blink/web_display_item_list_impl.h
+++ b/cc/blink/web_display_item_list_impl.h
@@ -41,7 +41,8 @@
 
   // blink::WebDisplayItemList implementation.
   void AppendDrawingItem(const blink::WebRect& visual_rect,
-                         sk_sp<const cc::PaintRecord> record) override;
+                         sk_sp<const cc::PaintRecord> record,
+                         const blink::WebRect& record_bounds) override;
   void AppendClipItem(
       const blink::WebRect& clip_rect,
       const blink::WebVector<SkRRect>& rounded_clip_rects) override;
diff --git a/cc/layers/picture_image_layer.cc b/cc/layers/picture_image_layer.cc
index e1f2600..327582e8 100644
--- a/cc/layers/picture_image_layer.cc
+++ b/cc/layers/picture_image_layer.cc
@@ -78,7 +78,8 @@
   canvas->drawImage(image_, 0, 0);
 
   display_list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-      PaintableRegion(), recorder.finishRecordingAsPicture());
+      PaintableRegion(), recorder.finishRecordingAsPicture(),
+      gfx::RectToSkRect(PaintableRegion()));
 
   display_list->Finalize();
   return display_list;
diff --git a/cc/paint/discardable_image_map_unittest.cc b/cc/paint/discardable_image_map_unittest.cc
index 5457d58..756a9c35 100644
--- a/cc/paint/discardable_image_map_unittest.cc
+++ b/cc/paint/discardable_image_map_unittest.cc
@@ -661,7 +661,7 @@
   display_list->CreateAndAppendPairedBeginItem<ClipDisplayItem>(
       gfx::Rect(250, 250), std::vector<SkRRect>(), false);
   display_list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-      gfx::Rect(500, 500), record);
+      gfx::Rect(500, 500), record, SkRect::MakeWH(500, 500));
   display_list->CreateAndAppendPairedEndItem<EndClipDisplayItem>();
   display_list->Finalize();
   display_list->GenerateDiscardableImagesMetadata();
@@ -688,7 +688,7 @@
   list_record->push<DrawImageOp>(discardable_image2, 100.f, 100.f, nullptr);
   scoped_refptr<DisplayItemList> display_list = new DisplayItemList;
   display_list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-      gfx::Rect(100, 100, 100, 100), list_record);
+      gfx::Rect(100, 100, 100, 100), list_record, SkRect::MakeWH(100, 100));
   display_list->Finalize();
 
   PaintOpBuffer buffer;
diff --git a/cc/paint/display_item_list.cc b/cc/paint/display_item_list.cc
index 2837bf74..4161df1 100644
--- a/cc/paint/display_item_list.cc
+++ b/cc/paint/display_item_list.cc
@@ -98,7 +98,7 @@
       break;
     case DisplayItem::DRAWING: {
       const auto& item = static_cast<const DrawingDisplayItem&>(base_item);
-      if (canvas->quickReject(item.picture->cullRect()))
+      if (canvas->quickReject(item.bounds))
         break;
 
       // TODO(enne): Maybe the PaintRecord itself could know whether this
@@ -427,15 +427,15 @@
           state->EndArray();
 
           state->BeginArray("cullRect");
-          state->AppendInteger(item.picture->cullRect().x());
-          state->AppendInteger(item.picture->cullRect().y());
-          state->AppendInteger(item.picture->cullRect().width());
-          state->AppendInteger(item.picture->cullRect().height());
+          state->AppendInteger(item.bounds.x());
+          state->AppendInteger(item.bounds.y());
+          state->AppendInteger(item.bounds.width());
+          state->AppendInteger(item.bounds.height());
           state->EndArray();
 
           std::string b64_picture;
-          PictureDebugUtil::SerializeAsBase64(ToSkPicture(item.picture).get(),
-                                              &b64_picture);
+          PictureDebugUtil::SerializeAsBase64(
+              ToSkPicture(item.picture, item.bounds).get(), &b64_picture);
           state->SetString("skp64", b64_picture);
           state->EndDictionary();
           break;
diff --git a/cc/paint/display_item_list_unittest.cc b/cc/paint/display_item_list_unittest.cc
index 9e91c74..e4682f3 100644
--- a/cc/paint/display_item_list_unittest.cc
+++ b/cc/paint/display_item_list_unittest.cc
@@ -102,12 +102,13 @@
   PaintFlags red_paint;
   red_paint.setColor(SK_ColorRED);
 
-  PaintCanvas* canvas = recorder.beginRecording(SkRect::MakeXYWH(
-      offset.x(), offset.y(), layer_size.width(), layer_size.height()));
+  SkRect bounds = SkRect::MakeXYWH(offset.x(), offset.y(), layer_size.width(),
+                                   layer_size.height());
+  PaintCanvas* canvas = recorder.beginRecording(bounds);
   canvas->translate(offset.x(), offset.y());
   canvas->drawRect(SkRect::MakeWH(4, 4), red_paint);
   list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-      kVisualRect, recorder.finishRecordingAsPicture());
+      kVisualRect, recorder.finishRecordingAsPicture(), bounds);
 }
 
 }  // namespace
@@ -130,7 +131,8 @@
   canvas->drawRect(SkRect::MakeLTRB(0.f, 0.f, 60.f, 60.f), red_paint);
   canvas->drawRect(SkRect::MakeLTRB(50.f, 50.f, 75.f, 75.f), blue_flags);
   list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-      kVisualRect, recorder.finishRecordingAsPicture());
+      kVisualRect, recorder.finishRecordingAsPicture(),
+      gfx::RectFToSkRect(recording_rect));
   list->Finalize();
   DrawDisplayList(pixels, layer_rect, list);
 
@@ -170,7 +172,8 @@
   canvas->translate(first_offset.x(), first_offset.y());
   canvas->drawRect(SkRect::MakeWH(60, 60), red_paint);
   list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-      kVisualRect, recorder.finishRecordingAsPicture());
+      kVisualRect, recorder.finishRecordingAsPicture(),
+      gfx::RectFToSkRect(first_recording_rect));
 
   gfx::Rect clip_rect(60, 60, 10, 10);
   list->CreateAndAppendPairedBeginItem<ClipDisplayItem>(
@@ -183,7 +186,8 @@
   canvas->translate(second_offset.x(), second_offset.y());
   canvas->drawRect(SkRect::MakeLTRB(50.f, 50.f, 75.f, 75.f), blue_flags);
   list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-      kVisualRect, recorder.finishRecordingAsPicture());
+      kVisualRect, recorder.finishRecordingAsPicture(),
+      gfx::RectFToSkRect(second_recording_rect));
 
   list->CreateAndAppendPairedEndItem<EndClipDisplayItem>();
   list->Finalize();
@@ -227,7 +231,8 @@
   canvas->translate(first_offset.x(), first_offset.y());
   canvas->drawRect(SkRect::MakeWH(60, 60), red_paint);
   list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-      kVisualRect, recorder.finishRecordingAsPicture());
+      kVisualRect, recorder.finishRecordingAsPicture(),
+      gfx::RectFToSkRect(first_recording_rect));
 
   gfx::Transform transform;
   transform.Rotate(45.0);
@@ -240,7 +245,8 @@
   canvas->translate(second_offset.x(), second_offset.y());
   canvas->drawRect(SkRect::MakeLTRB(50.f, 50.f, 75.f, 75.f), blue_flags);
   list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-      kVisualRect, recorder.finishRecordingAsPicture());
+      kVisualRect, recorder.finishRecordingAsPicture(),
+      gfx::RectFToSkRect(second_recording_rect));
 
   list->CreateAndAppendPairedEndItem<EndTransformDisplayItem>();
   list->Finalize();
@@ -303,14 +309,16 @@
     PaintFlags red_paint;
     red_paint.setColor(SK_ColorRED);
 
-    PaintCanvas* canvas = recorder.beginRecording(
-        SkRect::MakeXYWH(0, 0, layer_rect.width(), layer_rect.height()));
+    SkRect bounds =
+        SkRect::MakeXYWH(0, 0, layer_rect.width(), layer_rect.height());
+    PaintCanvas* canvas = recorder.beginRecording(bounds);
     canvas->drawRect(
         SkRect::MakeLTRB(filter_bounds.x(), filter_bounds.y(),
                          filter_bounds.right(), filter_bounds.bottom()),
         red_paint);
     list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-        ToNearestRect(filter_bounds), recorder.finishRecordingAsPicture());
+        ToNearestRect(filter_bounds), recorder.finishRecordingAsPicture(),
+        bounds);
   }
 
   list->CreateAndAppendPairedEndItem<EndFilterDisplayItem>();
@@ -348,7 +356,8 @@
   ASSERT_GE(record_size, kNumCommandsInTestSkPicture * sizeof(SkRect));
 
   auto list = make_scoped_refptr(new DisplayItemList);
-  list->CreateAndAppendDrawingItem<DrawingDisplayItem>(kVisualRect, record);
+  list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
+      kVisualRect, record, gfx::RectToSkRect(layer_rect));
   list->Finalize();
   memory_usage = list->ApproximateMemoryUsage();
   EXPECT_GE(memory_usage, record_size);
@@ -408,7 +417,8 @@
   auto list = make_scoped_refptr(new DisplayItemList);
   gfx::Rect drawing_bounds(5, 6, 1, 1);
   list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-      drawing_bounds, CreateRectPicture(drawing_bounds));
+      drawing_bounds, CreateRectPicture(drawing_bounds),
+      gfx::RectToSkRect(drawing_bounds));
   EXPECT_EQ(1u, list->size());
 }
 
@@ -428,7 +438,8 @@
 
   gfx::Rect drawing_bounds(5, 6, 7, 8);
   list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-      drawing_bounds, CreateRectPicture(drawing_bounds));
+      drawing_bounds, CreateRectPicture(drawing_bounds),
+      gfx::RectToSkRect(drawing_bounds));
 
   EXPECT_EQ(1u, list->size());
   EXPECT_RECT_EQ(drawing_bounds, list->VisualRectForTesting(0));
@@ -480,7 +491,8 @@
 
   gfx::Rect drawing_bounds(5, 6, 1, 1);
   list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-      drawing_bounds, CreateRectPicture(drawing_bounds));
+      drawing_bounds, CreateRectPicture(drawing_bounds),
+      gfx::RectToSkRect(drawing_bounds));
 
   list->CreateAndAppendPairedEndItem<EndClipDisplayItem>();
 
@@ -501,7 +513,8 @@
 
   gfx::Rect drawing_bounds(1, 2, 3, 4);
   list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-      drawing_bounds, CreateRectPicture(drawing_bounds));
+      drawing_bounds, CreateRectPicture(drawing_bounds),
+      gfx::RectToSkRect(drawing_bounds));
 
   list->CreateAndAppendPairedEndItem<EndClipDisplayItem>();
 
@@ -520,7 +533,8 @@
 
   gfx::Rect drawing_a_bounds(1, 2, 3, 4);
   list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-      drawing_a_bounds, CreateRectPicture(drawing_a_bounds));
+      drawing_a_bounds, CreateRectPicture(drawing_a_bounds),
+      gfx::RectToSkRect(drawing_a_bounds));
 
   gfx::Rect clip_bounds(5, 6, 7, 8);
   list->CreateAndAppendPairedBeginItem<ClipDisplayItem>(
@@ -528,7 +542,8 @@
 
   gfx::Rect drawing_b_bounds(13, 14, 1, 1);
   list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-      drawing_b_bounds, CreateRectPicture(drawing_b_bounds));
+      drawing_b_bounds, CreateRectPicture(drawing_b_bounds),
+      gfx::RectToSkRect(drawing_b_bounds));
 
   list->CreateAndAppendPairedEndItem<EndClipDisplayItem>();
 
@@ -550,13 +565,15 @@
 
   gfx::Rect drawing_a_bounds(5, 6, 1, 1);
   list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-      drawing_a_bounds, CreateRectPicture(drawing_a_bounds));
+      drawing_a_bounds, CreateRectPicture(drawing_a_bounds),
+      gfx::RectToSkRect(drawing_a_bounds));
 
   list->CreateAndAppendPairedBeginItem<TransformDisplayItem>(gfx::Transform());
 
   gfx::Rect drawing_b_bounds(7, 8, 1, 1);
   list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-      drawing_b_bounds, CreateRectPicture(drawing_b_bounds));
+      drawing_b_bounds, CreateRectPicture(drawing_b_bounds),
+      gfx::RectToSkRect(drawing_b_bounds));
 
   list->CreateAndAppendPairedEndItem<EndTransformDisplayItem>();
   list->CreateAndAppendPairedEndItem<EndClipDisplayItem>();
@@ -585,13 +602,15 @@
 
   gfx::Rect drawing_a_bounds(5, 6, 1, 1);
   list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-      drawing_a_bounds, CreateRectPicture(drawing_a_bounds));
+      drawing_a_bounds, CreateRectPicture(drawing_a_bounds),
+      gfx::RectToSkRect(drawing_a_bounds));
 
   list->CreateAndAppendPairedBeginItem<TransformDisplayItem>(gfx::Transform());
 
   gfx::Rect drawing_b_bounds(1, 2, 3, 4);
   list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-      drawing_b_bounds, CreateRectPicture(drawing_b_bounds));
+      drawing_b_bounds, CreateRectPicture(drawing_b_bounds),
+      gfx::RectToSkRect(drawing_b_bounds));
 
   list->CreateAndAppendPairedEndItem<EndTransformDisplayItem>();
   list->CreateAndAppendPairedEndItem<EndClipDisplayItem>();
@@ -620,13 +639,15 @@
 
   gfx::Rect drawing_a_bounds(1, 2, 3, 4);
   list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-      drawing_a_bounds, CreateRectPicture(drawing_a_bounds));
+      drawing_a_bounds, CreateRectPicture(drawing_a_bounds),
+      gfx::RectToSkRect(drawing_a_bounds));
 
   list->CreateAndAppendPairedBeginItem<TransformDisplayItem>(gfx::Transform());
 
   gfx::Rect drawing_b_bounds(7, 8, 1, 1);
   list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-      drawing_b_bounds, CreateRectPicture(drawing_b_bounds));
+      drawing_b_bounds, CreateRectPicture(drawing_b_bounds),
+      gfx::RectToSkRect(drawing_b_bounds));
 
   list->CreateAndAppendPairedEndItem<EndTransformDisplayItem>();
   list->CreateAndAppendPairedEndItem<EndClipDisplayItem>();
@@ -655,13 +676,15 @@
 
   gfx::Rect drawing_a_bounds(13, 14, 1, 1);
   list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-      drawing_a_bounds, CreateRectPicture(drawing_a_bounds));
+      drawing_a_bounds, CreateRectPicture(drawing_a_bounds),
+      gfx::RectToSkRect(drawing_a_bounds));
 
   list->CreateAndAppendPairedBeginItem<TransformDisplayItem>(gfx::Transform());
 
   gfx::Rect drawing_b_bounds(1, 2, 3, 4);
   list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-      drawing_b_bounds, CreateRectPicture(drawing_b_bounds));
+      drawing_b_bounds, CreateRectPicture(drawing_b_bounds),
+      gfx::RectToSkRect(drawing_b_bounds));
 
   list->CreateAndAppendPairedEndItem<EndTransformDisplayItem>();
   list->CreateAndAppendPairedEndItem<EndClipDisplayItem>();
@@ -727,7 +750,8 @@
   list->CreateAndAppendPairedBeginItem<CompositingDisplayItem>(
       80, SkBlendMode::kSrcOver, nullptr, nullptr, false);
   list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-      kVisualRect, CreateRectPictureWithAlpha(kVisualRect, 40));
+      kVisualRect, CreateRectPictureWithAlpha(kVisualRect, 40),
+      gfx::RectToSkRect(kVisualRect));
   list->CreateAndAppendPairedEndItem<EndCompositingDisplayItem>();
   list->Finalize();
 
@@ -777,7 +801,8 @@
   list->CreateAndAppendPairedBeginItem<CompositingDisplayItem>(
       80, SkBlendMode::kSrc, nullptr, nullptr, false);
   list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-      kVisualRect, CreateRectPictureWithAlpha(kVisualRect, 40));
+      kVisualRect, CreateRectPictureWithAlpha(kVisualRect, 40),
+      gfx::RectToSkRect(kVisualRect));
   list->CreateAndAppendPairedEndItem<EndCompositingDisplayItem>();
   list->Finalize();
 
@@ -793,10 +818,10 @@
 // The same as SaveDrawRestore, but with too many ops in the PaintRecord.
 TEST(DisplayItemListTest, SaveDrawRestoreFail_TooManyOps) {
   sk_sp<const PaintRecord> record;
+  SkRect bounds = SkRect::MakeWH(kVisualRect.width(), kVisualRect.height());
   {
     PaintRecorder recorder;
-    PaintCanvas* canvas =
-        recorder.beginRecording(kVisualRect.width(), kVisualRect.height());
+    PaintCanvas* canvas = recorder.beginRecording(bounds);
     PaintFlags flags;
     flags.setAlpha(40);
     canvas->drawRect(gfx::RectToSkRect(kVisualRect), flags);
@@ -810,8 +835,8 @@
 
   list->CreateAndAppendPairedBeginItem<CompositingDisplayItem>(
       80, SkBlendMode::kSrcOver, nullptr, nullptr, false);
-  list->CreateAndAppendDrawingItem<DrawingDisplayItem>(kVisualRect,
-                                                       std::move(record));
+  list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
+      kVisualRect, std::move(record), bounds);
   list->CreateAndAppendPairedEndItem<EndCompositingDisplayItem>();
   list->Finalize();
 
diff --git a/cc/paint/drawing_display_item.cc b/cc/paint/drawing_display_item.cc
index f8819c0..5fc920b 100644
--- a/cc/paint/drawing_display_item.cc
+++ b/cc/paint/drawing_display_item.cc
@@ -8,13 +8,15 @@
 
 namespace cc {
 
-DrawingDisplayItem::DrawingDisplayItem() : DisplayItem(DRAWING) {}
+DrawingDisplayItem::DrawingDisplayItem()
+    : DisplayItem(DRAWING), bounds(SkRect::MakeEmpty()) {}
 
-DrawingDisplayItem::DrawingDisplayItem(sk_sp<const PaintRecord> record)
-    : DisplayItem(DRAWING), picture(std::move(record)) {}
+DrawingDisplayItem::DrawingDisplayItem(sk_sp<const PaintRecord> record,
+                                       const SkRect& bounds)
+    : DisplayItem(DRAWING), picture(std::move(record)), bounds(bounds) {}
 
 DrawingDisplayItem::DrawingDisplayItem(const DrawingDisplayItem& item)
-    : DisplayItem(DRAWING), picture(item.picture) {}
+    : DisplayItem(DRAWING), picture(item.picture), bounds(item.bounds) {}
 
 DrawingDisplayItem::~DrawingDisplayItem() = default;
 
diff --git a/cc/paint/drawing_display_item.h b/cc/paint/drawing_display_item.h
index 677d0b6..a746a07 100644
--- a/cc/paint/drawing_display_item.h
+++ b/cc/paint/drawing_display_item.h
@@ -17,7 +17,8 @@
 class CC_PAINT_EXPORT DrawingDisplayItem : public DisplayItem {
  public:
   DrawingDisplayItem();
-  explicit DrawingDisplayItem(sk_sp<const PaintRecord> record);
+  explicit DrawingDisplayItem(sk_sp<const PaintRecord> record,
+                              const SkRect& bounds);
   explicit DrawingDisplayItem(const DrawingDisplayItem& item);
   ~DrawingDisplayItem() override;
 
@@ -25,6 +26,7 @@
   size_t OpCount() const;
 
   const sk_sp<const PaintRecord> picture;
+  SkRect bounds;
 };
 
 }  // namespace cc
diff --git a/cc/paint/paint_op_buffer.cc b/cc/paint/paint_op_buffer.cc
index d6556ab5..e7d8259 100644
--- a/cc/paint/paint_op_buffer.cc
+++ b/cc/paint/paint_op_buffer.cc
@@ -582,9 +582,7 @@
 
 DrawTextBlobOp::~DrawTextBlobOp() = default;
 
-PaintOpBuffer::PaintOpBuffer() : cull_rect_(SkRect::MakeEmpty()) {}
-
-PaintOpBuffer::PaintOpBuffer(const SkRect& cull_rect) : cull_rect_(cull_rect) {}
+PaintOpBuffer::PaintOpBuffer() = default;
 
 PaintOpBuffer::~PaintOpBuffer() {
   Reset();
diff --git a/cc/paint/paint_op_buffer.h b/cc/paint/paint_op_buffer.h
index c400f51..900eaf1e 100644
--- a/cc/paint/paint_op_buffer.h
+++ b/cc/paint/paint_op_buffer.h
@@ -772,7 +772,6 @@
   static constexpr size_t PaintOpAlign = ALIGNOF(DrawDRRectOp);
 
   PaintOpBuffer();
-  explicit PaintOpBuffer(const SkRect& cull_rect);
   ~PaintOpBuffer() override;
 
   void Reset();
@@ -793,8 +792,6 @@
   // Resize the PaintOpBuffer to exactly fit the current amount of used space.
   void ShrinkToFit();
 
-  const SkRect& cullRect() const { return cull_rect_; }
-
   PaintOp* GetFirstOp() const {
     return const_cast<PaintOp*>(first_op_.data_as<PaintOp>());
   }
@@ -949,7 +946,6 @@
   // Record additional bytes used by referenced sub-records and display lists.
   size_t subrecord_bytes_used_ = 0;
   bool has_discardable_images_ = false;
-  SkRect cull_rect_;
 
   DISALLOW_COPY_AND_ASSIGN(PaintOpBuffer);
 };
diff --git a/cc/paint/paint_op_buffer_unittest.cc b/cc/paint/paint_op_buffer_unittest.cc
index 2afcdeda..5ae1c64 100644
--- a/cc/paint/paint_op_buffer_unittest.cc
+++ b/cc/paint/paint_op_buffer_unittest.cc
@@ -429,7 +429,7 @@
 
   scoped_refptr<DisplayItemList> list = new DisplayItemList;
   list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-      gfx::Rect(0, 0, 100, 100), record);
+      gfx::Rect(100, 100), record, SkRect::MakeWH(100, 100));
   list->Finalize();
   PaintOpBuffer new_buffer;
   new_buffer.push<DrawDisplayItemListOp>(list);
diff --git a/cc/paint/paint_record.cc b/cc/paint/paint_record.cc
index 52cb2524..2483006 100644
--- a/cc/paint/paint_record.cc
+++ b/cc/paint/paint_record.cc
@@ -9,16 +9,17 @@
 
 namespace cc {
 
-sk_sp<SkPicture> ToSkPicture(sk_sp<PaintRecord> record) {
+sk_sp<SkPicture> ToSkPicture(sk_sp<PaintRecord> record, const SkRect& bounds) {
   SkPictureRecorder recorder;
-  SkCanvas* canvas = recorder.beginRecording(record->cullRect());
+  SkCanvas* canvas = recorder.beginRecording(bounds);
   record->playback(canvas);
   return recorder.finishRecordingAsPicture();
 }
 
-sk_sp<const SkPicture> ToSkPicture(sk_sp<const PaintRecord> record) {
+sk_sp<const SkPicture> ToSkPicture(sk_sp<const PaintRecord> record,
+                                   const SkRect& bounds) {
   SkPictureRecorder recorder;
-  SkCanvas* canvas = recorder.beginRecording(record->cullRect());
+  SkCanvas* canvas = recorder.beginRecording(bounds);
   record->playback(canvas);
   return recorder.finishRecordingAsPicture();
 }
diff --git a/cc/paint/paint_record.h b/cc/paint/paint_record.h
index daeee004..1509bac 100644
--- a/cc/paint/paint_record.h
+++ b/cc/paint/paint_record.h
@@ -17,10 +17,12 @@
 using PaintRecord = PaintOpBuffer;
 
 // TODO(enne): Remove these if possible, they are really expensive.
-CC_PAINT_EXPORT sk_sp<SkPicture> ToSkPicture(sk_sp<PaintRecord> record);
+CC_PAINT_EXPORT sk_sp<SkPicture> ToSkPicture(sk_sp<PaintRecord> record,
+                                             const SkRect& bounds);
 
 CC_PAINT_EXPORT sk_sp<const SkPicture> ToSkPicture(
-    sk_sp<const PaintRecord> record);
+    sk_sp<const PaintRecord> record,
+    const SkRect& bounds);
 
 }  // namespace cc
 
diff --git a/cc/paint/paint_recorder.cc b/cc/paint/paint_recorder.cc
index 2ed17c74..20f5cac 100644
--- a/cc/paint/paint_recorder.cc
+++ b/cc/paint/paint_recorder.cc
@@ -13,8 +13,8 @@
 PaintRecorder::~PaintRecorder() = default;
 
 PaintCanvas* PaintRecorder::beginRecording(const SkRect& bounds) {
-  buffer_.reset(new PaintOpBuffer(bounds));
-  canvas_.emplace(buffer_.get());
+  buffer_ = sk_make_sp<PaintOpBuffer>();
+  canvas_.emplace(buffer_.get(), bounds);
   return getRecordingCanvas();
 }
 
diff --git a/cc/paint/paint_shader.h b/cc/paint/paint_shader.h
index 6afdaa6..019174443b 100644
--- a/cc/paint/paint_shader.h
+++ b/cc/paint/paint_shader.h
@@ -24,12 +24,12 @@
 }
 
 inline sk_sp<PaintShader> MakePaintShaderRecord(sk_sp<PaintRecord> record,
+                                                const SkRect& tile,
                                                 SkShader::TileMode tx,
                                                 SkShader::TileMode ty,
-                                                const SkMatrix* local_matrix,
-                                                const SkRect* tile) {
-  return SkShader::MakePictureShader(ToSkPicture(record), tx, ty, local_matrix,
-                                     tile);
+                                                const SkMatrix* local_matrix) {
+  return SkShader::MakePictureShader(ToSkPicture(record, tile), tx, ty,
+                                     local_matrix, nullptr);
 }
 
 }  // namespace cc
diff --git a/cc/paint/record_paint_canvas.cc b/cc/paint/record_paint_canvas.cc
index 258b571..a635474 100644
--- a/cc/paint/record_paint_canvas.cc
+++ b/cc/paint/record_paint_canvas.cc
@@ -15,7 +15,9 @@
 
 namespace cc {
 
-RecordPaintCanvas::RecordPaintCanvas(PaintOpBuffer* buffer) : buffer_(buffer) {
+RecordPaintCanvas::RecordPaintCanvas(PaintOpBuffer* buffer,
+                                     const SkRect& bounds)
+    : buffer_(buffer), recording_bounds_(bounds) {
   DCHECK(buffer_);
 }
 
@@ -352,20 +354,18 @@
   if (canvas_)
     return &*canvas_;
 
-  SkRect recording_bounds = buffer_->cullRect();
-
   // Size the canvas to be large enough to contain the |recording_bounds|, which
   // may not be positioned at th origin.
-  SkIRect enclosing_rect = recording_bounds.roundOut();
+  SkIRect enclosing_rect = recording_bounds_.roundOut();
   canvas_.emplace(enclosing_rect.right(), enclosing_rect.bottom());
 
   // This is part of the "recording canvases have a size, but why" dance.
   // By creating a canvas of size (right x bottom) and then clipping it,
   // It makes getDeviceClipBounds return the original cull rect, which code
   // in GraphicsContextCanvas on Mac expects.  (Just creating an SkNoDrawCanvas
-  // with the cull_rect makes a canvas of size (width x height) instead
+  // with the recording_bounds_ makes a canvas of size (width x height) instead
   // which is incorrect.  SkRecorder cheats with private resetForNextCanvas.
-  canvas_->clipRect(recording_bounds, SkClipOp::kIntersect, false);
+  canvas_->clipRect(recording_bounds_, SkClipOp::kIntersect, false);
   return &*canvas_;
 }
 
diff --git a/cc/paint/record_paint_canvas.h b/cc/paint/record_paint_canvas.h
index a99b597..4eb391d74 100644
--- a/cc/paint/record_paint_canvas.h
+++ b/cc/paint/record_paint_canvas.h
@@ -24,7 +24,7 @@
 
 class CC_PAINT_EXPORT RecordPaintCanvas final : public PaintCanvas {
  public:
-  explicit RecordPaintCanvas(PaintOpBuffer* buffer);
+  explicit RecordPaintCanvas(PaintOpBuffer* buffer, const SkRect& bounds);
   ~RecordPaintCanvas() override;
 
   SkMetaData& getMetaData() override;
@@ -148,6 +148,7 @@
   // This is mutable so that const functions (e.g. quickReject) that may
   // lazy initialize the canvas can still be const.
   mutable base::Optional<SkNoDrawCanvas> canvas_;
+  SkRect recording_bounds_;
 
   DISALLOW_COPY_AND_ASSIGN(RecordPaintCanvas);
 };
diff --git a/cc/test/fake_content_layer_client.cc b/cc/test/fake_content_layer_client.cc
index ca0541d0..69be32e0 100644
--- a/cc/test/fake_content_layer_client.cc
+++ b/cc/test/fake_content_layer_client.cc
@@ -60,7 +60,8 @@
         recorder.beginRecording(gfx::RectFToSkRect(draw_rect));
     canvas->drawRect(gfx::RectFToSkRect(draw_rect), flags);
     display_list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-        ToEnclosingRect(draw_rect), recorder.finishRecordingAsPicture());
+        ToEnclosingRect(draw_rect), recorder.finishRecordingAsPicture(),
+        gfx::RectFToSkRect(draw_rect));
   }
 
   for (ImageVector::const_iterator it = draw_images_.begin();
@@ -69,11 +70,12 @@
       display_list->CreateAndAppendPairedBeginItem<TransformDisplayItem>(
           it->transform);
     }
-    PaintCanvas* canvas = recorder.beginRecording(
-        it->image.sk_image()->width(), it->image.sk_image()->height());
+    PaintCanvas* canvas =
+        recorder.beginRecording(gfx::RectToSkRect(PaintableRegion()));
     canvas->drawImage(it->image, it->point.x(), it->point.y(), &it->flags);
     display_list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-        PaintableRegion(), recorder.finishRecordingAsPicture());
+        PaintableRegion(), recorder.finishRecordingAsPicture(),
+        gfx::RectToSkRect(PaintableRegion()));
     if (!it->transform.IsIdentity()) {
       display_list->CreateAndAppendPairedEndItem<EndTransformDisplayItem>();
     }
@@ -89,7 +91,8 @@
           recorder.beginRecording(gfx::RectToSkRect(draw_rect));
       canvas->drawIRect(gfx::RectToSkIRect(draw_rect), flags);
       display_list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-          draw_rect, recorder.finishRecordingAsPicture());
+          draw_rect, recorder.finishRecordingAsPicture(),
+          gfx::RectToSkRect(draw_rect));
       draw_rect.Inset(1, 1);
     }
   }
diff --git a/cc/test/solid_color_content_layer_client.cc b/cc/test/solid_color_content_layer_client.cc
index 76eda5d..73e9617 100644
--- a/cc/test/solid_color_content_layer_client.cc
+++ b/cc/test/solid_color_content_layer_client.cc
@@ -49,7 +49,7 @@
 
   auto display_list = make_scoped_refptr(new DisplayItemList);
   display_list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-      clip, recorder.finishRecordingAsPicture());
+      clip, recorder.finishRecordingAsPicture(), gfx::RectToSkRect(clip));
 
   display_list->Finalize();
   return display_list;
diff --git a/cc/trees/layer_tree_host_pixeltest_masks.cc b/cc/trees/layer_tree_host_pixeltest_masks.cc
index 0a0b20f..1d1d70b 100644
--- a/cc/trees/layer_tree_host_pixeltest_masks.cc
+++ b/cc/trees/layer_tree_host_pixeltest_masks.cc
@@ -42,7 +42,7 @@
       PaintingControlSetting picture_control) override {
     PaintRecorder recorder;
     PaintCanvas* canvas =
-        recorder.beginRecording(gfx::RectToSkRect(gfx::Rect(bounds_)));
+        recorder.beginRecording(gfx::RectToSkRect(PaintableRegion()));
 
     PaintFlags flags;
     flags.setStyle(PaintFlags::kStroke_Style);
@@ -62,7 +62,8 @@
 
     auto display_list = make_scoped_refptr(new DisplayItemList);
     display_list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-        PaintableRegion(), recorder.finishRecordingAsPicture());
+        PaintableRegion(), recorder.finishRecordingAsPicture(),
+        gfx::RectToSkRect(PaintableRegion()));
 
     display_list->Finalize();
     return display_list;
@@ -222,7 +223,7 @@
       PaintingControlSetting picture_control) override {
     PaintRecorder recorder;
     PaintCanvas* canvas =
-        recorder.beginRecording(gfx::RectToSkRect(gfx::Rect(bounds_)));
+        recorder.beginRecording(gfx::RectToSkRect(PaintableRegion()));
 
     PaintFlags flags;
     flags.setStyle(PaintFlags::kStroke_Style);
@@ -241,7 +242,8 @@
 
     auto display_list = make_scoped_refptr(new DisplayItemList);
     display_list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-        PaintableRegion(), recorder.finishRecordingAsPicture());
+        PaintableRegion(), recorder.finishRecordingAsPicture(),
+        gfx::RectToSkRect(PaintableRegion()));
 
     display_list->Finalize();
     return display_list;
@@ -265,7 +267,7 @@
       PaintingControlSetting picture_control) override {
     PaintRecorder recorder;
     PaintCanvas* canvas =
-        recorder.beginRecording(gfx::RectToSkRect(gfx::Rect(bounds_)));
+        recorder.beginRecording(gfx::RectToSkRect(PaintableRegion()));
 
     PaintFlags flags;
     flags.setStyle(PaintFlags::kFill_Style);
@@ -276,7 +278,8 @@
 
     auto display_list = make_scoped_refptr(new DisplayItemList);
     display_list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-        PaintableRegion(), recorder.finishRecordingAsPicture());
+        PaintableRegion(), recorder.finishRecordingAsPicture(),
+        gfx::RectToSkRect(PaintableRegion()));
 
     display_list->Finalize();
     return display_list;
diff --git a/cc/trees/layer_tree_host_pixeltest_tiles.cc b/cc/trees/layer_tree_host_pixeltest_tiles.cc
index f0dcb95..e2fc6d64 100644
--- a/cc/trees/layer_tree_host_pixeltest_tiles.cc
+++ b/cc/trees/layer_tree_host_pixeltest_tiles.cc
@@ -113,7 +113,7 @@
 
     PaintRecorder recorder;
     PaintCanvas* canvas =
-        recorder.beginRecording(gfx::RectToSkRect(gfx::Rect(size_)));
+        recorder.beginRecording(gfx::RectToSkRect(PaintableRegion()));
     gfx::Rect top(0, 0, size_.width(), size_.height() / 2);
     gfx::Rect bottom(0, size_.height() / 2, size_.width(), size_.height() / 2);
 
@@ -129,7 +129,8 @@
     canvas->drawRect(gfx::RectToSkRect(yellow_rect), flags);
 
     display_list->CreateAndAppendDrawingItem<DrawingDisplayItem>(
-        PaintableRegion(), recorder.finishRecordingAsPicture());
+        PaintableRegion(), recorder.finishRecordingAsPicture(),
+        gfx::RectToSkRect(PaintableRegion()));
     display_list->Finalize();
     return display_list;
   }
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index cc08c20..dfe2f7f2 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -3085,6 +3085,9 @@
 crbug.com/714166 http/tests/inspector/network/waterfall-images.html [ Skip ]
 crbug.com/708175 external/wpt/IndexedDB/interleaved-cursors.html [ Failure Pass ]
 
+crbug.com/646010 paint/selection/text-selection-newline-rtl-double-linebreak.html [ NeedsRebaseline ]
+crbug.com/646010 virtual/disable-spinvalidation/paint/selection/text-selection-newline-rtl-double-linebreak.html [ NeedsRebaseline ]
+
 crbug.com/715718 external/wpt/media-source/mediasource-activesourcebuffers.html [ Failure Pass ]
 crbug.com/715718 external/wpt/media-source/mediasource-remove.html [ Failure Pass ]
 crbug.com/715718 [ Win ] external/wpt/XMLHttpRequest/FormData-append.html [ Failure Pass ]
diff --git a/third_party/WebKit/Source/core/inspector/InspectorLayerTreeAgent.cpp b/third_party/WebKit/Source/core/inspector/InspectorLayerTreeAgent.cpp
index 6b79c135..7cb99b7 100644
--- a/third_party/WebKit/Source/core/inspector/InspectorLayerTreeAgent.cpp
+++ b/third_party/WebKit/Source/core/inspector/InspectorLayerTreeAgent.cpp
@@ -378,8 +378,8 @@
   GraphicsContext context(layer->GetPaintController());
   context.BeginRecording(interest_rect);
   layer->GetPaintController().GetPaintArtifact().Replay(interest_rect, context);
-  RefPtr<PictureSnapshot> snapshot =
-      AdoptRef(new PictureSnapshot(ToSkPicture(context.EndRecording())));
+  RefPtr<PictureSnapshot> snapshot = AdoptRef(
+      new PictureSnapshot(ToSkPicture(context.EndRecording(), interest_rect)));
 
   *snapshot_id = String::Number(++last_snapshot_id_);
   bool new_entry = snapshot_by_id_.insert(*snapshot_id, snapshot).is_new_entry;
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourcePattern.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourcePattern.cpp
index e07568e..b368fc94 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourcePattern.cpp
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourcePattern.cpp
@@ -122,7 +122,8 @@
 
   std::unique_ptr<PatternData> pattern_data = WTF::WrapUnique(new PatternData);
   pattern_data->pattern = Pattern::CreatePaintRecordPattern(
-      AsPaintRecord(tile_bounds, tile_transform));
+      AsPaintRecord(tile_bounds.Size(), tile_transform),
+      FloatRect(FloatPoint(), tile_bounds.Size()));
 
   // Compute pattern space transformation.
   pattern_data->transform.Translate(tile_bounds.X(), tile_bounds.Y());
@@ -196,7 +197,7 @@
 }
 
 sk_sp<PaintRecord> LayoutSVGResourcePattern::AsPaintRecord(
-    const FloatRect& tile_bounds,
+    const FloatSize& size,
     const AffineTransform& tile_transform) const {
   DCHECK(!should_collect_pattern_attributes_);
 
@@ -205,7 +206,7 @@
       SVGUnitTypes::kSvgUnitTypeObjectboundingbox)
     content_transform = tile_transform;
 
-  FloatRect bounds(FloatPoint(), tile_bounds.Size());
+  FloatRect bounds(FloatPoint(), size);
   const LayoutSVGResourceContainer* pattern_layout_object =
       ResolveContentElement();
   DCHECK(pattern_layout_object);
diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourcePattern.h b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourcePattern.h
index 36ca8d20..c89b299 100644
--- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourcePattern.h
+++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGResourcePattern.h
@@ -32,7 +32,6 @@
 namespace blink {
 
 class AffineTransform;
-class FloatRect;
 class SVGPatternElement;
 struct PatternData;
 
@@ -53,7 +52,7 @@
 
  private:
   std::unique_ptr<PatternData> BuildPatternData(const LayoutObject&);
-  sk_sp<PaintRecord> AsPaintRecord(const FloatRect& tile,
+  sk_sp<PaintRecord> AsPaintRecord(const FloatSize&,
                                    const AffineTransform&) const;
   PatternData* PatternForLayoutObject(const LayoutObject&);
 
diff --git a/third_party/WebKit/Source/core/paint/BoxReflectionUtils.cpp b/third_party/WebKit/Source/core/paint/BoxReflectionUtils.cpp
index caf6483..679508e3 100644
--- a/third_party/WebKit/Source/core/paint/BoxReflectionUtils.cpp
+++ b/third_party/WebKit/Source/core/paint/BoxReflectionUtils.cpp
@@ -51,31 +51,30 @@
       break;
   }
 
-  sk_sp<PaintRecord> mask;
   const NinePieceImage& mask_nine_piece = reflect_style->Mask();
-  if (mask_nine_piece.HasImage()) {
-    LayoutRect mask_rect(LayoutPoint(), frame_layout_rect.Size());
-    LayoutRect mask_bounding_rect(mask_rect);
-    mask_bounding_rect.Expand(style.ImageOutsets(mask_nine_piece));
-    FloatRect mask_bounding_float_rect(mask_bounding_rect);
+  if (!mask_nine_piece.HasImage())
+    return BoxReflection(direction, offset, nullptr, FloatRect());
 
-    // TODO(jbroman): PaintRecordBuilder + DrawingRecorder seems excessive.
-    // If NinePieceImagePainter operated on SkCanvas, we'd only need a
-    // PictureRecorder here.
-    PaintRecordBuilder builder(mask_bounding_float_rect);
-    {
-      GraphicsContext& context = builder.Context();
-      DrawingRecorder drawing_recorder(context, layer.GetLayoutObject(),
-                                       DisplayItem::kReflectionMask,
-                                       mask_bounding_float_rect);
-      NinePieceImagePainter().Paint(builder.Context(), layer.GetLayoutObject(),
-                                    mask_rect, style, mask_nine_piece,
-                                    SkBlendMode::kSrcOver);
-    }
-    mask = builder.EndRecording();
+  LayoutRect mask_rect(LayoutPoint(), frame_layout_rect.Size());
+  LayoutRect mask_bounding_rect(mask_rect);
+  mask_bounding_rect.Expand(style.ImageOutsets(mask_nine_piece));
+  FloatRect mask_bounding_float_rect(mask_bounding_rect);
+
+  // TODO(jbroman): PaintRecordBuilder + DrawingRecorder seems excessive.
+  // If NinePieceImagePainter operated on SkCanvas, we'd only need a
+  // PictureRecorder here.
+  PaintRecordBuilder builder(mask_bounding_float_rect);
+  {
+    GraphicsContext& context = builder.Context();
+    DrawingRecorder drawing_recorder(context, layer.GetLayoutObject(),
+                                     DisplayItem::kReflectionMask,
+                                     mask_bounding_float_rect);
+    NinePieceImagePainter().Paint(builder.Context(), layer.GetLayoutObject(),
+                                  mask_rect, style, mask_nine_piece,
+                                  SkBlendMode::kSrcOver);
   }
-
-  return BoxReflection(direction, offset, std::move(mask));
+  return BoxReflection(direction, offset, builder.EndRecording(),
+                       mask_bounding_float_rect);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/core/paint/ClipPathClipper.cpp b/third_party/WebKit/Source/core/paint/ClipPathClipper.cpp
index 383b3a3..2dcca769 100644
--- a/third_party/WebKit/Source/core/paint/ClipPathClipper.cpp
+++ b/third_party/WebKit/Source/core/paint/ClipPathClipper.cpp
@@ -211,7 +211,7 @@
                                                    content_transform);
       mask_context.GetPaintController().CreateAndAppend<DrawingDisplayItem>(
           layout_object_, DisplayItem::kSVGClip,
-          resource_clipper_->CreatePaintRecord());
+          resource_clipper_->CreatePaintRecord(), target_bounding_box);
     }
   }
 
diff --git a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp
index e98f0be..8ad7c16 100644
--- a/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/InlineTextBoxPainter.cpp
@@ -706,6 +706,9 @@
 
 #if !OS(MACOSX)
 
+static const float kMarkerWidth = 4;
+static const float kMarkerHeight = 2;
+
 sk_sp<PaintRecord> RecordMarker(DocumentMarker::MarkerType marker_type) {
   SkColor color = (marker_type == DocumentMarker::kGrammar)
                       ? SkColorSetRGB(0xC0, 0xC0, 0xC0)
@@ -715,31 +718,28 @@
   //   X o   o X o   o X
   //     o X o   o X o
 
-  static const float kW = 4;
-  static const float kH = 2;
-
   // Adjust the phase such that f' == 0 is "pixel"-centered
   // (for optimal rasterization at native rez).
   SkPath path;
-  path.moveTo(kW * -3 / 8, kH * 3 / 4);
-  path.cubicTo(kW * -1 / 8, kH * 3 / 4,
-               kW * -1 / 8, kH * 1 / 4,
-               kW *  1 / 8, kH * 1 / 4);
-  path.cubicTo(kW * 3 / 8, kH * 1 / 4,
-               kW * 3 / 8, kH * 3 / 4,
-               kW * 5 / 8, kH * 3 / 4);
-  path.cubicTo(kW * 7 / 8, kH * 3 / 4,
-               kW * 7 / 8, kH * 1 / 4,
-               kW * 9 / 8, kH * 1 / 4);
+  path.moveTo(kMarkerWidth * -3 / 8, kMarkerHeight * 3 / 4);
+  path.cubicTo(kMarkerWidth * -1 / 8, kMarkerHeight * 3 / 4,
+               kMarkerWidth * -1 / 8, kMarkerHeight * 1 / 4,
+               kMarkerWidth * 1 / 8, kMarkerHeight * 1 / 4);
+  path.cubicTo(kMarkerWidth * 3 / 8, kMarkerHeight * 1 / 4,
+               kMarkerWidth * 3 / 8, kMarkerHeight * 3 / 4,
+               kMarkerWidth * 5 / 8, kMarkerHeight * 3 / 4);
+  path.cubicTo(kMarkerWidth * 7 / 8, kMarkerHeight * 3 / 4,
+               kMarkerWidth * 7 / 8, kMarkerHeight * 1 / 4,
+               kMarkerWidth * 9 / 8, kMarkerHeight * 1 / 4);
 
   PaintFlags flags;
   flags.setAntiAlias(true);
   flags.setColor(color);
   flags.setStyle(PaintFlags::kStroke_Style);
-  flags.setStrokeWidth(kH * 1 / 2);
+  flags.setStrokeWidth(kMarkerHeight * 1 / 2);
 
   PaintRecorder recorder;
-  recorder.beginRecording(kW, kH);
+  recorder.beginRecording(kMarkerWidth, kMarkerHeight);
   recorder.getRecordingCanvas()->drawPath(path, flags);
 
   return recorder.finishRecordingAsPicture();
@@ -747,14 +747,15 @@
 
 #else  // OS(MACOSX)
 
+static const float kMarkerWidth = 4;
+static const float kMarkerHeight = 3;
+
 sk_sp<PaintRecord> RecordMarker(DocumentMarker::MarkerType marker_type) {
   SkColor color = (marker_type == DocumentMarker::kGrammar)
                       ? SkColorSetRGB(0x6B, 0x6B, 0x6B)
                       : SkColorSetRGB(0xFB, 0x2D, 0x1D);
 
   // Match the artwork used by the Mac.
-  static const float kW = 4;
-  static const float kH = 3;
   static const float kR = 1.5f;
 
   // top->bottom translucent gradient.
@@ -776,7 +777,7 @@
   flags.setShader(SkGradientShader::MakeLinear(
       pts, colors, nullptr, ARRAY_SIZE(colors), SkShader::kClamp_TileMode));
   PaintRecorder recorder;
-  recorder.beginRecording(kW, kH);
+  recorder.beginRecording(kMarkerWidth, kMarkerHeight);
   recorder.getRecordingCanvas()->drawCircle(kR, kR, kR, flags);
 
   return recorder.finishRecordingAsPicture();
@@ -806,20 +807,20 @@
 
 #if OS(MACOSX)
   // Make sure to draw only complete dots, and finish inside the marked text.
-  width -= fmodf(width, marker->cullRect().width() * zoom);
+  width -= fmodf(width, kMarkerWidth * zoom);
 #else
   // Offset it vertically by 1 so that there's some space under the text.
   origin_y += 1;
 #endif
 
-  const auto rect = SkRect::MakeWH(width, marker->cullRect().height() * zoom);
+  const auto rect = SkRect::MakeWH(width, kMarkerHeight * zoom);
   const auto local_matrix = SkMatrix::MakeScale(zoom, zoom);
 
   PaintFlags flags;
   flags.setAntiAlias(true);
   flags.setShader(WrapSkShader(MakePaintShaderRecord(
-      sk_ref_sp(marker), SkShader::kRepeat_TileMode, SkShader::kClamp_TileMode,
-      &local_matrix, nullptr)));
+      sk_ref_sp(marker), FloatRect(0, 0, kMarkerWidth, kMarkerHeight),
+      SkShader::kRepeat_TileMode, SkShader::kClamp_TileMode, &local_matrix)));
 
   // Apply the origin translation as a global transform.  This ensures that the
   // shader local matrix depends solely on zoom => Skia can reuse the same
diff --git a/third_party/WebKit/Source/core/paint/LayoutObjectDrawingRecorderTest.cpp b/third_party/WebKit/Source/core/paint/LayoutObjectDrawingRecorderTest.cpp
index 1fccb2e8..a5e600f2 100644
--- a/third_party/WebKit/Source/core/paint/LayoutObjectDrawingRecorderTest.cpp
+++ b/third_party/WebKit/Source/core/paint/LayoutObjectDrawingRecorderTest.cpp
@@ -119,7 +119,7 @@
   controller.CommitNewDisplayItems();
   const auto& drawing = static_cast<const DrawingDisplayItem&>(
       controller.GetDisplayItemList()[0]);
-  return drawing.GetPaintRecord()->cullRect();
+  return drawing.GetPaintRecordBounds();
 }
 
 TEST_F(LayoutObjectDrawingRecorderTest, CullRectMatchesProvidedClip) {
diff --git a/third_party/WebKit/Source/core/paint/SVGFilterPainter.cpp b/third_party/WebKit/Source/core/paint/SVGFilterPainter.cpp
index 262338d..e435e12d 100644
--- a/third_party/WebKit/Source/core/paint/SVGFilterPainter.cpp
+++ b/third_party/WebKit/Source/core/paint/SVGFilterPainter.cpp
@@ -150,7 +150,7 @@
     DCHECK(filter->GetSourceGraphic());
     sk_sp<PaintRecord> content = recording_context.EndContent(bounds);
     SkiaImageFilterBuilder::BuildSourceGraphic(filter->GetSourceGraphic(),
-                                               std::move(content));
+                                               std::move(content), bounds);
     filter_data->state_ = FilterData::kReadyToPaint;
   }
 
diff --git a/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainterTest.cpp b/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainterTest.cpp
index b2ad3742e..68362a9 100644
--- a/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainterTest.cpp
+++ b/third_party/WebKit/Source/core/paint/SVGInlineTextBoxPainterTest.cpp
@@ -99,11 +99,6 @@
         << ", expected: " << expected.Height();                             \
   } while (false)
 
-static IntRect CullRectFromDrawing(
-    const DrawingDisplayItem& drawing_display_item) {
-  return IntRect(drawing_display_item.GetPaintRecord()->cullRect());
-}
-
 TEST_F(SVGInlineTextBoxPainterTest, TextCullRect_DefaultWritingMode) {
   SetBodyInnerHTML(
       "<svg width='400px' height='400px' font-family='Arial' font-size='30'>"
@@ -115,7 +110,7 @@
       GetDrawingForSVGTextById("target");
   AssertTextDrawingEquals(drawing_display_item, "x");
   EXPECT_RECT_EQ(IntRect(50, 3, 15, 33),
-                 CullRectFromDrawing(*drawing_display_item));
+                 drawing_display_item->GetPaintRecordBounds());
 
   SelectAllText();
   GetDocument().View()->UpdateAllLifecyclePhases();
@@ -123,7 +118,7 @@
   drawing_display_item = GetDrawingForSVGTextById("target");
   AssertTextDrawingEquals(drawing_display_item, "x");
   EXPECT_RECT_EQ(IntRect(50, 3, 15, 33),
-                 CullRectFromDrawing(*drawing_display_item));
+                 drawing_display_item->GetPaintRecordBounds());
 }
 
 TEST_F(SVGInlineTextBoxPainterTest, TextCullRect_WritingModeTopToBottom) {
@@ -137,7 +132,7 @@
       GetDrawingForSVGTextById("target");
   AssertTextDrawingEquals(drawing_display_item, "x");
   EXPECT_RECT_EQ(IntRect(33, 30, 34, 15),
-                 CullRectFromDrawing(*drawing_display_item));
+                 drawing_display_item->GetPaintRecordBounds());
 
   SelectAllText();
   GetDocument().View()->UpdateAllLifecyclePhases();
@@ -148,7 +143,7 @@
   drawing_display_item = GetDrawingForSVGTextById("target");
   AssertTextDrawingEquals(drawing_display_item, "x");
   EXPECT_RECT_EQ(IntRect(33, 30, 34, 16),
-                 CullRectFromDrawing(*drawing_display_item));
+                 drawing_display_item->GetPaintRecordBounds());
 }
 
 TEST_F(SVGInlineTextBoxPainterTest, TextCullRect_TextShadow) {
@@ -163,7 +158,7 @@
       GetDrawingForSVGTextById("target");
   AssertTextDrawingEquals(drawing_display_item, "x");
   EXPECT_RECT_EQ(IntRect(50, 3, 220, 238),
-                 CullRectFromDrawing(*drawing_display_item));
+                 drawing_display_item->GetPaintRecordBounds());
 }
 
 }  // namespace
diff --git a/third_party/WebKit/Source/core/svg/graphics/SVGImage.cpp b/third_party/WebKit/Source/core/svg/graphics/SVGImage.cpp
index 2df17f6..cd9495c 100644
--- a/third_party/WebKit/Source/core/svg/graphics/SVGImage.cpp
+++ b/third_party/WebKit/Source/core/svg/graphics/SVGImage.cpp
@@ -355,9 +355,9 @@
                                  phase.Y() + spaced_tile.Y());
 
   PaintFlags flags;
-  flags.setShader(MakePaintShaderRecord(record, SkShader::kRepeat_TileMode,
-                                        SkShader::kRepeat_TileMode,
-                                        &pattern_transform, nullptr));
+  flags.setShader(
+      MakePaintShaderRecord(record, spaced_tile, SkShader::kRepeat_TileMode,
+                            SkShader::kRepeat_TileMode, &pattern_transform));
   // If the shader could not be instantiated (e.g. non-invertible matrix),
   // draw transparent.
   // Note: we can't simply bail, because of arbitrary blend mode.
@@ -383,7 +383,7 @@
                    container_rect, container_rect, url);
 
   return SkImage::MakeFromPicture(
-      ToSkPicture(recorder.finishRecordingAsPicture()),
+      ToSkPicture(recorder.finishRecordingAsPicture(), container_rect),
       SkISize::Make(container_size.Width(), container_size.Height()), nullptr,
       nullptr, SkImage::BitDepth::kU8, SkColorSpace::MakeSRGB());
 }
@@ -397,16 +397,15 @@
 bool SVGImage::ApplyShaderInternal(PaintFlags& flags,
                                    const SkMatrix& local_matrix,
                                    const KURL& url) {
-  const FloatSize size(ContainerSize());
+  const IntSize size(ContainerSize());
   if (size.IsEmpty())
     return false;
 
-  FloatRect float_bounds(FloatPoint(), size);
-  const SkRect bounds(float_bounds);
+  IntRect bounds(IntPoint(), size);
 
   flags.setShader(MakePaintShaderRecord(
-      PaintRecordForCurrentFrame(float_bounds, url), SkShader::kRepeat_TileMode,
-      SkShader::kRepeat_TileMode, &local_matrix, &bounds));
+      PaintRecordForCurrentFrame(bounds, url), bounds,
+      SkShader::kRepeat_TileMode, SkShader::kRepeat_TileMode, &local_matrix));
 
   // Animation is normally refreshed in draw() impls, which we don't reach when
   // painting via shaders.
@@ -451,7 +450,7 @@
                should_respect_image_orientation, clamp_mode, KURL());
 }
 
-sk_sp<PaintRecord> SVGImage::PaintRecordForCurrentFrame(const FloatRect& bounds,
+sk_sp<PaintRecord> SVGImage::PaintRecordForCurrentFrame(const IntRect& bounds,
                                                         const KURL& url,
                                                         PaintCanvas* canvas) {
   DCHECK(page_);
@@ -469,12 +468,10 @@
   // avoid setting timers from the latter.
   FlushPendingTimelineRewind();
 
-  IntRect int_bounds(EnclosingIntRect(bounds));
-  PaintRecordBuilder builder(int_bounds, nullptr, nullptr,
-                             paint_controller_.get());
+  PaintRecordBuilder builder(bounds, nullptr, nullptr, paint_controller_.get());
 
   view->UpdateAllLifecyclePhasesExceptPaint();
-  view->Paint(builder.Context(), CullRect(int_bounds));
+  view->Paint(builder.Context(), CullRect(bounds));
   DCHECK(!view->NeedsLayout());
 
   if (canvas) {
@@ -512,7 +509,7 @@
     canvas->save();
     canvas->clipRect(EnclosingIntRect(dst_rect));
     canvas->concat(AffineTransformToSkMatrix(transform));
-    PaintRecordForCurrentFrame(src_rect, url, canvas);
+    PaintRecordForCurrentFrame(EnclosingIntRect(src_rect), url, canvas);
     canvas->restore();
   }
 
diff --git a/third_party/WebKit/Source/core/svg/graphics/SVGImage.h b/third_party/WebKit/Source/core/svg/graphics/SVGImage.h
index 345bcef..05996b5a 100644
--- a/third_party/WebKit/Source/core/svg/graphics/SVGImage.h
+++ b/third_party/WebKit/Source/core/svg/graphics/SVGImage.h
@@ -155,7 +155,7 @@
   // Paints the current frame. If a PaintCanvas is passed, paints into that
   // canvas and returns nullptr.
   // Otherwise returns a pointer to the new PaintRecord.
-  sk_sp<PaintRecord> PaintRecordForCurrentFrame(const FloatRect& bounds,
+  sk_sp<PaintRecord> PaintRecordForCurrentFrame(const IntRect& bounds,
                                                 const KURL&,
                                                 PaintCanvas* = nullptr);
 
diff --git a/third_party/WebKit/Source/core/svg/graphics/filters/SVGFEImage.cpp b/third_party/WebKit/Source/core/svg/graphics/filters/SVGFEImage.cpp
index 4e285a7..384f6938 100644
--- a/third_party/WebKit/Source/core/svg/graphics/filters/SVGFEImage.cpp
+++ b/third_party/WebKit/Source/core/svg/graphics/filters/SVGFEImage.cpp
@@ -191,7 +191,7 @@
   builder.EndRecording(*canvas);
 
   return SkPictureImageFilter::Make(
-      ToSkPicture(paint_recorder.finishRecordingAsPicture()), dst_rect);
+      ToSkPicture(paint_recorder.finishRecordingAsPicture(), dst_rect));
 }
 
 sk_sp<SkImageFilter> FEImage::CreateImageFilter() {
diff --git a/third_party/WebKit/Source/platform/graphics/BoxReflection.h b/third_party/WebKit/Source/platform/graphics/BoxReflection.h
index 7a4a5b2b..3a18ee9 100644
--- a/third_party/WebKit/Source/platform/graphics/BoxReflection.h
+++ b/third_party/WebKit/Source/platform/graphics/BoxReflection.h
@@ -6,6 +6,7 @@
 #define BoxReflection_h
 
 #include "platform/PlatformExport.h"
+#include "platform/geometry/FloatRect.h"
 #include "platform/graphics/paint/PaintRecord.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
 
@@ -13,8 +14,6 @@
 
 namespace blink {
 
-class FloatRect;
-
 // A reflection, as created by -webkit-box-reflect. Consists of:
 // * a direction (either vertical or horizontal)
 // * an offset to be applied to the reflection after flipping about the
@@ -30,14 +29,22 @@
     kHorizontalReflection,
   };
 
+  BoxReflection(ReflectionDirection direction, float offset)
+      : BoxReflection(direction, offset, nullptr, FloatRect()) {}
+
   BoxReflection(ReflectionDirection direction,
                 float offset,
-                sk_sp<PaintRecord> mask = nullptr)
-      : direction_(direction), offset_(offset), mask_(std::move(mask)) {}
+                sk_sp<PaintRecord> mask,
+                const FloatRect& mask_bounds)
+      : direction_(direction),
+        offset_(offset),
+        mask_(std::move(mask)),
+        mask_bounds_(mask_bounds) {}
 
   ReflectionDirection Direction() const { return direction_; }
   float Offset() const { return offset_; }
   const sk_sp<PaintRecord>& Mask() const { return mask_; }
+  const FloatRect& MaskBounds() const { return mask_bounds_; }
 
   // Returns a matrix which maps points between the original content and its
   // reflection. Reflections are self-inverse, so this matrix can be used to
@@ -54,11 +61,12 @@
   ReflectionDirection direction_;
   float offset_;
   sk_sp<PaintRecord> mask_;
+  FloatRect mask_bounds_;
 };
 
 inline bool operator==(const BoxReflection& a, const BoxReflection& b) {
   return a.Direction() == b.Direction() && a.Offset() == b.Offset() &&
-         a.Mask() == b.Mask();
+         a.Mask() == b.Mask() && a.MaskBounds() == b.MaskBounds();
 }
 
 inline bool operator!=(const BoxReflection& a, const BoxReflection& b) {
diff --git a/third_party/WebKit/Source/platform/graphics/GeneratedImage.cpp b/third_party/WebKit/Source/platform/graphics/GeneratedImage.cpp
index befad95..d3dc986 100644
--- a/third_party/WebKit/Source/platform/graphics/GeneratedImage.cpp
+++ b/third_party/WebKit/Source/platform/graphics/GeneratedImage.cpp
@@ -59,7 +59,7 @@
   pattern_matrix.preTranslate(tile_rect.X(), tile_rect.Y());
 
   RefPtr<Pattern> pattern =
-      Pattern::CreatePaintRecordPattern(std::move(record));
+      Pattern::CreatePaintRecordPattern(std::move(record), tile_rect);
 
   PaintFlags fill_flags = dest_context.FillFlags();
   pattern->ApplyToFlags(fill_flags, pattern_matrix);
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp
index 174f1ac..9b76631 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsContext.cpp
@@ -298,7 +298,7 @@
 }
 
 void GraphicsContext::DrawRecord(sk_sp<const PaintRecord> record) {
-  if (ContextDisabled() || !record || record->cullRect().isEmpty())
+  if (ContextDisabled() || !record || !record->size())
     return;
 
   DCHECK(canvas_);
@@ -322,7 +322,7 @@
   transform.setRectToRect(source_bounds, sk_bounds, SkMatrix::kFill_ScaleToFit);
   canvas_->concat(transform);
   flags.setImageFilter(SkPictureImageFilter::MakeForLocalSpace(
-      ToSkPicture(record), source_bounds,
+      ToSkPicture(record, source_bounds), source_bounds,
       static_cast<SkFilterQuality>(ImageInterpolationQuality())));
   canvas_->saveLayer(&source_bounds, &flags);
   canvas_->restore();
diff --git a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
index ebb192b..690e5ac6 100644
--- a/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
+++ b/third_party/WebKit/Source/platform/graphics/GraphicsLayer.cpp
@@ -1207,6 +1207,11 @@
          PixelComponentsDiffer(SkColorGetB(p1), SkColorGetB(p2));
 }
 
+// This method is used to graphically verify any under invalidation when
+// RuntimeEnabledFeatures::paintUnderInvalidationCheckingEnabled is being
+// used. It compares the last recording made by GraphicsLayer::Paint against
+// |new_record|, by rastering both into bitmaps. Any differences are colored
+// as dark red.
 void GraphicsLayer::CheckPaintUnderInvalidations(
     sk_sp<PaintRecord> new_record) {
   if (!DrawsContent())
@@ -1283,7 +1288,7 @@
   recorder.getRecordingCanvas()->drawBitmap(new_bitmap, rect.X(), rect.Y());
   sk_sp<PaintRecord> record = recorder.finishRecordingAsPicture();
   GetPaintController().AppendDebugDrawingAfterCommit(
-      *this, record, OffsetFromLayoutObjectWithSubpixelAccumulation());
+      *this, record, rect, OffsetFromLayoutObjectWithSubpixelAccumulation());
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/Image.cpp b/third_party/WebKit/Source/platform/graphics/Image.cpp
index be2a1d15..f4bb7ec 100644
--- a/third_party/WebKit/Source/platform/graphics/Image.cpp
+++ b/third_party/WebKit/Source/platform/graphics/Image.cpp
@@ -246,8 +246,8 @@
   PaintCanvas* canvas = recorder.beginRecording(tile_rect);
   canvas->drawImage(image, 0, 0, &paint);
 
-  return MakePaintShaderRecord(recorder.finishRecordingAsPicture(), tmx, tmy,
-                               &shader_matrix, nullptr);
+  return MakePaintShaderRecord(recorder.finishRecordingAsPicture(), tile_rect,
+                               tmx, tmy, &shader_matrix);
 }
 
 SkShader::TileMode ComputeTileMode(float left,
diff --git a/third_party/WebKit/Source/platform/graphics/LoggingCanvas.cpp b/third_party/WebKit/Source/platform/graphics/LoggingCanvas.cpp
index fb4eebcc..926fe40 100644
--- a/third_party/WebKit/Source/platform/graphics/LoggingCanvas.cpp
+++ b/third_party/WebKit/Source/platform/graphics/LoggingCanvas.cpp
@@ -905,18 +905,18 @@
 }
 
 #ifndef NDEBUG
-String RecordAsDebugString(const PaintRecord* record) {
-  const SkIRect bounds = record->cullRect().roundOut();
-  LoggingCanvas canvas(bounds.width(), bounds.height());
+String RecordAsDebugString(const PaintRecord* record, const SkRect& bounds) {
+  const SkIRect enclosing_bounds = bounds.roundOut();
+  LoggingCanvas canvas(enclosing_bounds.width(), enclosing_bounds.height());
   record->playback(&canvas);
   std::unique_ptr<JSONObject> record_as_json = JSONObject::Create();
-  record_as_json->SetObject("cullRect", ObjectForSkRect(record->cullRect()));
+  record_as_json->SetObject("cullRect", ObjectForSkRect(bounds));
   record_as_json->SetArray("operations", canvas.Log());
   return record_as_json->ToPrettyJSONString();
 }
 
-void ShowPaintRecord(const PaintRecord* record) {
-  WTFLogAlways("%s\n", RecordAsDebugString(record).Utf8().data());
+void ShowPaintRecord(const PaintRecord* record, const SkRect& bounds) {
+  WTFLogAlways("%s\n", RecordAsDebugString(record, bounds).Utf8().data());
 }
 #endif
 
diff --git a/third_party/WebKit/Source/platform/graphics/LoggingCanvas.h b/third_party/WebKit/Source/platform/graphics/LoggingCanvas.h
index ec46b81c..31b545d 100644
--- a/third_party/WebKit/Source/platform/graphics/LoggingCanvas.h
+++ b/third_party/WebKit/Source/platform/graphics/LoggingCanvas.h
@@ -120,8 +120,8 @@
 };
 
 #ifndef NDEBUG
-String RecordAsDebugString(const PaintRecord*);
-void ShowPaintRecord(const PaintRecord*);
+String RecordAsDebugString(const PaintRecord*, const SkRect& bounds);
+void ShowPaintRecord(const PaintRecord*, const SkRect& bounds);
 #endif
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/PaintGeneratedImage.cpp b/third_party/WebKit/Source/platform/graphics/PaintGeneratedImage.cpp
index b6f9bf67..f89ba935 100644
--- a/third_party/WebKit/Source/platform/graphics/PaintGeneratedImage.cpp
+++ b/third_party/WebKit/Source/platform/graphics/PaintGeneratedImage.cpp
@@ -23,7 +23,7 @@
     canvas->scale(dest_rect.Width() / src_rect.Width(),
                   dest_rect.Height() / src_rect.Height());
   canvas->translate(-src_rect.X(), -src_rect.Y());
-  SkRect bounds = record_->cullRect();
+  SkRect bounds = dest_rect;
   canvas->saveLayer(&bounds, &flags);
   canvas->drawPicture(record_);
 }
diff --git a/third_party/WebKit/Source/platform/graphics/PaintRecordPattern.cpp b/third_party/WebKit/Source/platform/graphics/PaintRecordPattern.cpp
index 2b0bdb5..1a9250f 100644
--- a/third_party/WebKit/Source/platform/graphics/PaintRecordPattern.cpp
+++ b/third_party/WebKit/Source/platform/graphics/PaintRecordPattern.cpp
@@ -13,13 +13,18 @@
 
 PassRefPtr<PaintRecordPattern> PaintRecordPattern::Create(
     sk_sp<PaintRecord> record,
+    const FloatRect& record_bounds,
     RepeatMode repeat_mode) {
-  return AdoptRef(new PaintRecordPattern(std::move(record), repeat_mode));
+  return AdoptRef(
+      new PaintRecordPattern(std::move(record), record_bounds, repeat_mode));
 }
 
 PaintRecordPattern::PaintRecordPattern(sk_sp<PaintRecord> record,
+                                       const FloatRect& record_bounds,
                                        RepeatMode mode)
-    : Pattern(mode), tile_record_(std::move(record)) {
+    : Pattern(mode),
+      tile_record_(std::move(record)),
+      tile_record_bounds_(record_bounds) {
   // All current clients use RepeatModeXY, so we only support this mode for now.
   DCHECK(IsRepeatXY());
 
@@ -30,11 +35,9 @@
 
 sk_sp<PaintShader> PaintRecordPattern::CreateShader(
     const SkMatrix& local_matrix) {
-  SkRect tile_bounds = tile_record_->cullRect();
-
-  return MakePaintShaderRecord(tile_record_, SkShader::kRepeat_TileMode,
-                               SkShader::kRepeat_TileMode, &local_matrix,
-                               &tile_bounds);
+  return MakePaintShaderRecord(tile_record_, tile_record_bounds_,
+                               SkShader::kRepeat_TileMode,
+                               SkShader::kRepeat_TileMode, &local_matrix);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/PaintRecordPattern.h b/third_party/WebKit/Source/platform/graphics/PaintRecordPattern.h
index d987801..fe3d95d 100644
--- a/third_party/WebKit/Source/platform/graphics/PaintRecordPattern.h
+++ b/third_party/WebKit/Source/platform/graphics/PaintRecordPattern.h
@@ -5,6 +5,7 @@
 #ifndef PaintRecordPattern_h
 #define PaintRecordPattern_h
 
+#include "platform/geometry/FloatRect.h"
 #include "platform/graphics/Pattern.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
 
@@ -13,7 +14,9 @@
 // TODO(enne): rename this
 class PLATFORM_EXPORT PaintRecordPattern final : public Pattern {
  public:
-  static PassRefPtr<PaintRecordPattern> Create(sk_sp<PaintRecord>, RepeatMode);
+  static PassRefPtr<PaintRecordPattern> Create(sk_sp<PaintRecord>,
+                                               const FloatRect& record_bounds,
+                                               RepeatMode);
 
   ~PaintRecordPattern() override;
 
@@ -21,9 +24,12 @@
   sk_sp<PaintShader> CreateShader(const SkMatrix&) override;
 
  private:
-  PaintRecordPattern(sk_sp<PaintRecord>, RepeatMode);
+  PaintRecordPattern(sk_sp<PaintRecord>,
+                     const FloatRect& record_bounds,
+                     RepeatMode);
 
   sk_sp<PaintRecord> tile_record_;
+  FloatRect tile_record_bounds_;
 };
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/Pattern.cpp b/third_party/WebKit/Source/platform/graphics/Pattern.cpp
index c169fbc..dc1c2f6 100644
--- a/third_party/WebKit/Source/platform/graphics/Pattern.cpp
+++ b/third_party/WebKit/Source/platform/graphics/Pattern.cpp
@@ -42,9 +42,12 @@
   return ImagePattern::Create(std::move(tile_image), repeat_mode);
 }
 
-PassRefPtr<Pattern> Pattern::CreatePaintRecordPattern(sk_sp<PaintRecord> record,
-                                                      RepeatMode repeat_mode) {
-  return PaintRecordPattern::Create(std::move(record), repeat_mode);
+PassRefPtr<Pattern> Pattern::CreatePaintRecordPattern(
+    sk_sp<PaintRecord> record,
+    const FloatRect& record_bounds,
+    RepeatMode repeat_mode) {
+  return PaintRecordPattern::Create(std::move(record), record_bounds,
+                                    repeat_mode);
 }
 
 Pattern::Pattern(RepeatMode repeat_mode) : repeat_mode_(repeat_mode) {}
diff --git a/third_party/WebKit/Source/platform/graphics/Pattern.h b/third_party/WebKit/Source/platform/graphics/Pattern.h
index 3784107..1db8d22 100644
--- a/third_party/WebKit/Source/platform/graphics/Pattern.h
+++ b/third_party/WebKit/Source/platform/graphics/Pattern.h
@@ -59,6 +59,7 @@
                                                 RepeatMode = kRepeatModeXY);
   static PassRefPtr<Pattern> CreatePaintRecordPattern(
       sk_sp<PaintRecord>,
+      const FloatRect& record_bounds,
       RepeatMode = kRepeatModeXY);
   virtual ~Pattern();
 
diff --git a/third_party/WebKit/Source/platform/graphics/PlaceholderImage.cpp b/third_party/WebKit/Source/platform/graphics/PlaceholderImage.cpp
index 75682744..9023571e 100644
--- a/third_party/WebKit/Source/platform/graphics/PlaceholderImage.cpp
+++ b/third_party/WebKit/Source/platform/graphics/PlaceholderImage.cpp
@@ -35,7 +35,7 @@
        dest_rect, kDoNotRespectImageOrientation, kClampImageToSourceRect);
 
   image_for_current_frame_ = SkImage::MakeFromPicture(
-      ToSkPicture(paint_recorder.finishRecordingAsPicture()),
+      ToSkPicture(paint_recorder.finishRecordingAsPicture(), dest_rect),
       SkISize::Make(size_.Width(), size_.Height()), nullptr, nullptr,
       SkImage::BitDepth::kU8, SkColorSpace::MakeSRGB());
 
diff --git a/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.cpp b/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.cpp
index dbb45173..bd39881 100644
--- a/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.cpp
+++ b/third_party/WebKit/Source/platform/graphics/compositing/PaintChunksToCcLayer.cpp
@@ -183,18 +183,20 @@
     cc::DisplayItemList* list) {
   DCHECK(DisplayItem::IsDrawingType(display_item.GetType()));
   if (DisplayItem::IsDrawingType(display_item.GetType())) {
-    sk_sp<const PaintRecord> record =
-        static_cast<const DrawingDisplayItem&>(display_item).GetPaintRecord();
+    const auto& drawing_display_item =
+        static_cast<const DrawingDisplayItem&>(display_item);
+    sk_sp<const PaintRecord> record = drawing_display_item.GetPaintRecord();
     if (!record)
       return;
+    SkRect record_bounds = drawing_display_item.GetPaintRecordBounds();
     // In theory we would pass the bounds of the record, previously done as:
     // gfx::Rect bounds = gfx::SkIRectToRect(record->cullRect().roundOut());
     // or use the visual rect directly. However, clip content layers attempt
     // to raster in a different space than that of the visual rects. We'll be
     // reworking visual rects further for SPv2, so for now we just pass a
     // visual rect large enough to make sure items raster.
-    list->CreateAndAppendDrawingItem<cc::DrawingDisplayItem>(g_large_rect,
-                                                             std::move(record));
+    list->CreateAndAppendDrawingItem<cc::DrawingDisplayItem>(
+        g_large_rect, std::move(record), record_bounds);
   }
 }
 
diff --git a/third_party/WebKit/Source/platform/graphics/filters/SkiaImageFilterBuilder.cpp b/third_party/WebKit/Source/platform/graphics/filters/SkiaImageFilterBuilder.cpp
index ad855b3..2325bb9 100644
--- a/third_party/WebKit/Source/platform/graphics/filters/SkiaImageFilterBuilder.cpp
+++ b/third_party/WebKit/Source/platform/graphics/filters/SkiaImageFilterBuilder.cpp
@@ -110,11 +110,11 @@
 }
 
 void BuildSourceGraphic(FilterEffect* source_graphic,
-                        sk_sp<PaintRecord> record) {
+                        sk_sp<PaintRecord> record,
+                        const FloatRect& record_bounds) {
   DCHECK(record);
-  SkRect cull_rect = record->cullRect();
   sk_sp<SkImageFilter> filter =
-      SkPictureImageFilter::Make(ToSkPicture(record), cull_rect);
+      SkPictureImageFilter::Make(ToSkPicture(record, record_bounds));
   PopulateSourceGraphicImageFilters(
       source_graphic, std::move(filter),
       source_graphic->OperatingInterpolationSpace());
@@ -131,34 +131,35 @@
     // raster the mask to a bitmap, then encode it in an SkImageSource, which
     // can be serialized.
     SkBitmap bitmap;
-    const SkRect cull_rect = mask_record->cullRect();
-    if (static_cast<float>(cull_rect.width()) *
-            static_cast<float>(cull_rect.height()) <
+    const SkRect mask_record_bounds = reflection.MaskBounds();
+    if (mask_record_bounds.width() * mask_record_bounds.height() <
         kMaxMaskBufferSize) {
-      bitmap.allocPixels(
-          SkImageInfo::MakeN32Premul(cull_rect.width(), cull_rect.height()));
+      bitmap.allocPixels(SkImageInfo::MakeN32Premul(
+          mask_record_bounds.width(), mask_record_bounds.height()));
       SkiaPaintCanvas canvas(bitmap);
       canvas.clear(SK_ColorTRANSPARENT);
-      canvas.translate(-cull_rect.x(), -cull_rect.y());
+      canvas.translate(-mask_record_bounds.x(), -mask_record_bounds.y());
       canvas.drawPicture(mask_record);
       sk_sp<SkImage> image = SkImage::MakeFromBitmap(bitmap);
 
       // SkXfermodeImageFilter can choose an excessively large size if the
       // mask is smaller than the filtered contents (due to overflow).
       // http://skbug.com/5210
-      SkImageFilter::CropRect crop_rect(mask_record->cullRect());
+      SkImageFilter::CropRect crop_rect(mask_record_bounds);
       masked_input = SkXfermodeImageFilter::Make(
           SkBlendMode::kSrcIn,
-          SkOffsetImageFilter::Make(cull_rect.x(), cull_rect.y(),
+          SkOffsetImageFilter::Make(mask_record_bounds.x(),
+                                    mask_record_bounds.y(),
                                     SkImageSource::Make(image)),
           input, &crop_rect);
     } else {
       // If the buffer is excessively big, give up and make an
       // SkPictureImageFilter anyway, even if it might not render.
-      SkImageFilter::CropRect crop_rect(mask_record->cullRect());
+      SkImageFilter::CropRect crop_rect(mask_record_bounds);
       masked_input = SkXfermodeImageFilter::Make(
           SkBlendMode::kSrcOver,
-          SkPictureImageFilter::Make(ToSkPicture(std::move(mask_record))),
+          SkPictureImageFilter::Make(
+              ToSkPicture(std::move(mask_record), mask_record_bounds)),
           input, &crop_rect);
     }
   } else {
diff --git a/third_party/WebKit/Source/platform/graphics/filters/SkiaImageFilterBuilder.h b/third_party/WebKit/Source/platform/graphics/filters/SkiaImageFilterBuilder.h
index 6e0e6f4..9b557da5 100644
--- a/third_party/WebKit/Source/platform/graphics/filters/SkiaImageFilterBuilder.h
+++ b/third_party/WebKit/Source/platform/graphics/filters/SkiaImageFilterBuilder.h
@@ -37,6 +37,7 @@
 
 class BoxReflection;
 class FilterEffect;
+class FloatRect;
 
 namespace SkiaImageFilterBuilder {
 
@@ -54,7 +55,9 @@
     FilterEffect* source_graphic,
     sk_sp<SkImageFilter> input,
     InterpolationSpace input_interpolation_space);
-PLATFORM_EXPORT void BuildSourceGraphic(FilterEffect*, sk_sp<PaintRecord>);
+PLATFORM_EXPORT void BuildSourceGraphic(FilterEffect*,
+                                        sk_sp<PaintRecord>,
+                                        const FloatRect& record_bounds);
 
 PLATFORM_EXPORT sk_sp<SkImageFilter> BuildBoxReflectFilter(
     const BoxReflection&,
diff --git a/third_party/WebKit/Source/platform/graphics/paint/DisplayItemList.cpp b/third_party/WebKit/Source/platform/graphics/paint/DisplayItemList.cpp
index 694762a..1f78695 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/DisplayItemList.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/DisplayItemList.cpp
@@ -93,7 +93,8 @@
         const DrawingDisplayItem& item =
             static_cast<const DrawingDisplayItem&>(display_item);
         if (const PaintRecord* record = item.GetPaintRecord().get()) {
-          json->SetString("record", RecordAsDebugString(record));
+          json->SetString("record", RecordAsDebugString(
+                                        record, item.GetPaintRecordBounds()));
         }
       }
 #endif
diff --git a/third_party/WebKit/Source/platform/graphics/paint/DisplayItemListTest.cpp b/third_party/WebKit/Source/platform/graphics/paint/DisplayItemListTest.cpp
index 9101c18..a665238 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/DisplayItemListTest.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/DisplayItemListTest.cpp
@@ -48,7 +48,7 @@
   IntRect drawing_bounds(5, 6, 7, 8);
   list_.AllocateAndConstruct<DrawingDisplayItem>(
       client_, DisplayItem::Type::kDocumentBackground,
-      CreateRectRecord(drawing_bounds), true);
+      CreateRectRecord(drawing_bounds), drawing_bounds, true);
   list_.AppendVisualRect(drawing_bounds);
 
   EXPECT_EQ(static_cast<size_t>(1), list_.size());
@@ -64,7 +64,7 @@
   IntRect drawing_bounds(5, 6, 1, 1);
   list_.AllocateAndConstruct<DrawingDisplayItem>(
       client_, DisplayItem::Type::kDocumentBackground,
-      CreateRectRecord(drawing_bounds), true);
+      CreateRectRecord(drawing_bounds), drawing_bounds, true);
   list_.AppendVisualRect(drawing_bounds);
 
   EXPECT_EQ(static_cast<size_t>(1), list_.size());
diff --git a/third_party/WebKit/Source/platform/graphics/paint/DrawingDisplayItem.cpp b/third_party/WebKit/Source/platform/graphics/paint/DrawingDisplayItem.cpp
index 55b511a..602a906 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/DrawingDisplayItem.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/DrawingDisplayItem.cpp
@@ -21,8 +21,10 @@
 void DrawingDisplayItem::AppendToWebDisplayItemList(
     const IntRect& visual_rect,
     WebDisplayItemList* list) const {
-  if (record_)
-    list->AppendDrawingItem(visual_rect, record_);
+  if (record_) {
+    list->AppendDrawingItem(visual_rect, record_,
+                            EnclosingIntRect(record_bounds_));
+  }
 }
 
 bool DrawingDisplayItem::DrawsContent() const {
@@ -38,48 +40,47 @@
     StringBuilder& string_builder) const {
   DisplayItem::DumpPropertiesAsDebugString(string_builder);
   if (record_) {
-    string_builder.Append(
-        String::Format(", rect: [%f,%f %fx%f]", record_->cullRect().x(),
-                       record_->cullRect().y(), record_->cullRect().width(),
-                       record_->cullRect().height()));
+    string_builder.Append(String::Format(
+        ", rect: [%f,%f %fx%f]", record_bounds_.X(), record_bounds_.Y(),
+        record_bounds_.Width(), record_bounds_.Height()));
   }
 }
 #endif
 
 static bool RecordsEqual(sk_sp<const PaintRecord> record1,
-                         sk_sp<const PaintRecord> record2) {
+                         sk_sp<const PaintRecord> record2,
+                         const FloatRect& bounds) {
   if (record1->size() != record2->size())
     return false;
 
   // TODO(enne): PaintRecord should have an operator==
-  sk_sp<SkData> data1 = ToSkPicture(record1)->serialize();
-  sk_sp<SkData> data2 = ToSkPicture(record2)->serialize();
+  sk_sp<SkData> data1 = ToSkPicture(record1, bounds)->serialize();
+  sk_sp<SkData> data2 = ToSkPicture(record2, bounds)->serialize();
   return data1->equals(data2.get());
 }
 
-static SkBitmap RecordToBitmap(sk_sp<const PaintRecord> record) {
+static SkBitmap RecordToBitmap(sk_sp<const PaintRecord> record,
+                               const FloatRect& bounds) {
   SkBitmap bitmap;
-  SkRect rect = record->cullRect();
-  bitmap.allocPixels(SkImageInfo::MakeN32Premul(rect.width(), rect.height()));
+  bitmap.allocPixels(
+      SkImageInfo::MakeN32Premul(bounds.Width(), bounds.Height()));
   SkiaPaintCanvas canvas(bitmap);
   canvas.clear(SK_ColorTRANSPARENT);
-  canvas.translate(-rect.x(), -rect.y());
+  canvas.translate(-bounds.X(), -bounds.Y());
   canvas.drawPicture(std::move(record));
   return bitmap;
 }
 
 static bool BitmapsEqual(sk_sp<const PaintRecord> record1,
-                         sk_sp<const PaintRecord> record2) {
-  SkRect rect = record1->cullRect();
-  if (rect != record2->cullRect())
-    return false;
-
-  SkBitmap bitmap1 = RecordToBitmap(record1);
-  SkBitmap bitmap2 = RecordToBitmap(record2);
+                         sk_sp<const PaintRecord> record2,
+                         const FloatRect& bounds) {
+  SkBitmap bitmap1 = RecordToBitmap(record1, bounds);
+  SkBitmap bitmap2 = RecordToBitmap(record2, bounds);
   int mismatch_count = 0;
   const int kMaxMismatches = 10;
-  for (int y = 0; y < rect.height() && mismatch_count < kMaxMismatches; ++y) {
-    for (int x = 0; x < rect.width() && mismatch_count < kMaxMismatches; ++x) {
+  for (int y = 0; y < bounds.Height() && mismatch_count < kMaxMismatches; ++y) {
+    for (int x = 0; x < bounds.Width() && mismatch_count < kMaxMismatches;
+         ++x) {
       SkColor pixel1 = bitmap1.getColor(x, y);
       SkColor pixel2 = bitmap2.getColor(x, y);
       if (pixel1 != pixel2) {
@@ -97,20 +98,25 @@
     return false;
 
   const sk_sp<const PaintRecord>& record = this->GetPaintRecord();
+  const FloatRect& bounds = this->GetPaintRecordBounds();
   const sk_sp<const PaintRecord>& other_record =
       static_cast<const DrawingDisplayItem&>(other).GetPaintRecord();
+  const FloatRect& other_bounds =
+      static_cast<const DrawingDisplayItem&>(other).GetPaintRecordBounds();
 
   if (!record && !other_record)
     return true;
   if (!record || !other_record)
     return false;
+  if (bounds != other_bounds)
+    return false;
 
-  if (RecordsEqual(record, other_record))
+  if (RecordsEqual(record, other_record, bounds))
     return true;
 
   // Sometimes the client may produce different records for the same visual
   // result, which should be treated as equal.
-  return BitmapsEqual(std::move(record), std::move(other_record));
+  return BitmapsEqual(std::move(record), std::move(other_record), bounds);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/paint/DrawingDisplayItem.h b/third_party/WebKit/Source/platform/graphics/paint/DrawingDisplayItem.h
index ccfb009..c5d8974 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/DrawingDisplayItem.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/DrawingDisplayItem.h
@@ -8,32 +8,48 @@
 #include "base/compiler_specific.h"
 #include "platform/PlatformExport.h"
 #include "platform/RuntimeEnabledFeatures.h"
-#include "platform/geometry/FloatPoint.h"
+#include "platform/geometry/FloatRect.h"
 #include "platform/graphics/paint/DisplayItem.h"
 #include "platform/graphics/paint/PaintRecord.h"
 #include "third_party/skia/include/core/SkRefCnt.h"
 
 namespace blink {
 
+// DrawingDisplayItem contains recorded painting operations which can be
+// replayed to produce a rastered output.
+//
+// This class has two notions of the bounds around the content that was recorded
+// and will be produced by the item. The first is the |record_bounds| which
+// describes the bounds of all content in the |record| in the space of the
+// record. The second is the |visual_rect| which should describe the same thing,
+// but takes into account transforms and clips that would apply to the
+// PaintRecord, and is in the space of the DisplayItemList. This allows the
+// visual_rect to be compared between DrawingDisplayItems, and to give bounds
+// around what the user can actually see from the PaintRecord.
 class PLATFORM_EXPORT DrawingDisplayItem final : public DisplayItem {
  public:
   DISABLE_CFI_PERF
   DrawingDisplayItem(const DisplayItemClient& client,
                      Type type,
                      sk_sp<const PaintRecord> record,
+                     const FloatRect& record_bounds,
                      bool known_to_be_opaque = false)
       : DisplayItem(client, type, sizeof(*this)),
         record_(record && record->size() ? std::move(record) : nullptr),
+        record_bounds_(record_bounds),
         known_to_be_opaque_(known_to_be_opaque) {
     DCHECK(IsDrawingType(type));
   }
 
   void Replay(GraphicsContext&) const override;
-  void AppendToWebDisplayItemList(const IntRect&,
+  void AppendToWebDisplayItemList(const IntRect& visual_rect,
                                   WebDisplayItemList*) const override;
   bool DrawsContent() const override;
 
   const sk_sp<const PaintRecord>& GetPaintRecord() const { return record_; }
+  // This rect is described in the coordinate space relative to the PaintRecord
+  // whose bounds it describes.
+  FloatRect GetPaintRecordBounds() const { return record_bounds_; }
 
   bool KnownToBeOpaque() const {
     DCHECK(RuntimeEnabledFeatures::slimmingPaintV2Enabled());
@@ -49,6 +65,7 @@
   bool Equals(const DisplayItem& other) const final;
 
   sk_sp<const PaintRecord> record_;
+  FloatRect record_bounds_;
 
   // True if there are no transparent areas. Only used for SlimmingPaintV2.
   const bool known_to_be_opaque_;
diff --git a/third_party/WebKit/Source/platform/graphics/paint/DrawingDisplayItemTest.cpp b/third_party/WebKit/Source/platform/graphics/paint/DrawingDisplayItemTest.cpp
new file mode 100644
index 0000000..b4c9577
--- /dev/null
+++ b/third_party/WebKit/Source/platform/graphics/paint/DrawingDisplayItemTest.cpp
@@ -0,0 +1,69 @@
+// Copyright 2017 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "platform/graphics/paint/DrawingDisplayItem.h"
+
+#include "SkTypes.h"
+#include "platform/graphics/paint/PaintRecorder.h"
+#include "platform/graphics/skia/SkiaUtils.h"
+#include "platform/testing/FakeDisplayItemClient.h"
+#include "public/platform/WebDisplayItemList.h"
+#include "testing/gmock/include/gmock/gmock.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+namespace blink {
+namespace {
+
+using testing::_;
+
+class DrawingDisplayItemTest : public ::testing::Test {
+ protected:
+  FakeDisplayItemClient client_;
+};
+
+class MockWebDisplayItemList : public WebDisplayItemList {
+ public:
+  MOCK_METHOD3(AppendDrawingItem,
+               void(const WebRect& visual_rect,
+                    sk_sp<const cc::PaintRecord>,
+                    const WebRect& record_bounds));
+};
+
+static sk_sp<PaintRecord> CreateRectRecord(const FloatRect& record_bounds) {
+  PaintRecorder recorder;
+  PaintCanvas* canvas =
+      recorder.beginRecording(record_bounds.Width(), record_bounds.Height());
+  canvas->drawRect(record_bounds, PaintFlags());
+  return recorder.finishRecordingAsPicture();
+}
+
+TEST_F(DrawingDisplayItemTest, VisualRectAndDrawingBounds) {
+  FloatRect record_bounds(5.5, 6.6, 7.7, 8.8);
+  LayoutRect drawing_bounds(record_bounds);
+  client_.SetVisualRect(drawing_bounds);
+
+  DrawingDisplayItem item(client_, DisplayItem::Type::kDocumentBackground,
+                          CreateRectRecord(record_bounds), record_bounds);
+  EXPECT_EQ(drawing_bounds, item.VisualRect());
+
+  MockWebDisplayItemList list1;
+  WebRect expected_rect = EnclosingIntRect(drawing_bounds);
+  WebRect expected_record_rect = EnclosingIntRect(record_bounds);
+  EXPECT_CALL(list1, AppendDrawingItem(expected_rect, _, expected_record_rect))
+      .Times(1);
+  item.AppendToWebDisplayItemList(LayoutSize(), &list1);
+
+  LayoutSize offset(LayoutUnit(2.1), LayoutUnit(3.6));
+  LayoutRect visual_rect_with_offset = drawing_bounds;
+  visual_rect_with_offset.Move(-offset);
+  WebRect expected_visual_rect = EnclosingIntRect(visual_rect_with_offset);
+  MockWebDisplayItemList list2;
+  EXPECT_CALL(list2,
+              AppendDrawingItem(expected_visual_rect, _, expected_record_rect))
+      .Times(1);
+  item.AppendToWebDisplayItemList(offset, &list2);
+}
+
+}  // namespace
+}  // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/paint/DrawingRecorder.cpp b/third_party/WebKit/Source/platform/graphics/paint/DrawingRecorder.cpp
index cfefdac..a2bac310 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/DrawingRecorder.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/DrawingRecorder.cpp
@@ -51,8 +51,8 @@
   // bounds of the object during painting. Potentially expanding the cull rect
   // by a pixel or two also does not affect correctness, and is very unlikely to
   // matter for performance.
-  IntRect cull_rect = EnclosingIntRect(float_cull_rect);
-  context.BeginRecording(cull_rect);
+  recording_bounds_ = EnclosingIntRect(float_cull_rect);
+  context.BeginRecording(recording_bounds_);
 
 #if DCHECK_IS_ON()
   if (RuntimeEnabledFeatures::slimmingPaintStrictCullRectClippingEnabled()) {
@@ -66,8 +66,9 @@
     // TODO(schenney) This is not the best place to do this. Ideally, we would
     // expand by one pixel in device (pixel) space, but to do that we would need
     // to add the verification mode to Skia.
-    cull_rect.Inflate(1);
-    context.ClipRect(cull_rect, kNotAntiAliased, SkClipOp::kIntersect);
+    IntRect clip_rect = recording_bounds_;
+    clip_rect.Inflate(1);
+    context.ClipRect(clip_rect, kNotAntiAliased, SkClipOp::kIntersect);
   }
 #endif
 }
@@ -99,7 +100,8 @@
 #endif
 
   context_.GetPaintController().CreateAndAppend<DrawingDisplayItem>(
-      display_item_client_, display_item_type_, picture, known_to_be_opaque_);
+      display_item_client_, display_item_type_, picture, recording_bounds_,
+      known_to_be_opaque_);
 }
 
 }  // namespace blink
diff --git a/third_party/WebKit/Source/platform/graphics/paint/DrawingRecorder.h b/third_party/WebKit/Source/platform/graphics/paint/DrawingRecorder.h
index ac40d09..3407d31b 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/DrawingRecorder.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/DrawingRecorder.h
@@ -53,6 +53,8 @@
 
   // True if there are no transparent areas. Only used for SlimmingPaintV2.
   bool known_to_be_opaque_;
+  // The bounds of the area being recorded.
+  IntRect recording_bounds_;
 
 #if DCHECK_IS_ON()
   // Ensures the list size does not change during the recorder's scope.
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintArtifact.cpp b/third_party/WebKit/Source/platform/graphics/paint/PaintArtifact.cpp
index 119f912f..ec6345e 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintArtifact.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintArtifact.cpp
@@ -28,16 +28,14 @@
       if (!item.IsDrawing())
         continue;
       const auto& drawing = static_cast<const DrawingDisplayItem&>(item);
-      if (const PaintRecord* record = drawing.GetPaintRecord().get()) {
-        if (drawing.KnownToBeOpaque()) {
-          // TODO(pdr): It may be too conservative to round in to the
-          // enclosedIntRect.
-          SkIRect conservative_rounded_rect;
-          const SkRect& cull_rect = record->cullRect();
-          cull_rect.roundIn(&conservative_rounded_rect);
-          known_to_be_opaque_region.op(conservative_rounded_rect,
-                                       SkRegion::kUnion_Op);
-        }
+      if (drawing.GetPaintRecord() && drawing.KnownToBeOpaque()) {
+        // TODO(pdr): It may be too conservative to round in to the
+        // EnclosedIntRect.
+        SkIRect conservative_rounded_rect;
+        const SkRect& record_bounds = drawing.GetPaintRecordBounds();
+        record_bounds.roundIn(&conservative_rounded_rect);
+        known_to_be_opaque_region.op(conservative_rounded_rect,
+                                     SkRegion::kUnion_Op);
       }
     }
     chunk.bounds = bounds;
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp b/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp
index 9d79a3a..99229a0 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintController.cpp
@@ -676,13 +676,14 @@
 void PaintController::AppendDebugDrawingAfterCommit(
     const DisplayItemClient& display_item_client,
     sk_sp<PaintRecord> record,
+    const FloatRect& record_bounds,
     const LayoutSize& offset_from_layout_object) {
   DCHECK(new_display_item_list_.IsEmpty());
   DrawingDisplayItem& display_item =
       current_paint_artifact_.GetDisplayItemList()
-          .AllocateAndConstruct<DrawingDisplayItem>(display_item_client,
-                                                    DisplayItem::kDebugDrawing,
-                                                    std::move(record));
+          .AllocateAndConstruct<DrawingDisplayItem>(
+              display_item_client, DisplayItem::kDebugDrawing,
+              std::move(record), record_bounds);
   display_item.SetSkippedCache();
   // TODO(wkorman): Only compute and append visual rect for drawings.
   current_paint_artifact_.GetDisplayItemList().AppendVisualRect(
@@ -859,20 +860,28 @@
 
 #ifndef NDEBUG
   const PaintRecord* new_record = nullptr;
+  SkRect new_bounds;
   if (new_item.IsDrawing()) {
     new_record =
         static_cast<const DrawingDisplayItem&>(new_item).GetPaintRecord().get();
+    new_bounds =
+        static_cast<const DrawingDisplayItem&>(new_item).GetPaintRecordBounds();
   }
   const PaintRecord* old_record = nullptr;
+  SkRect old_bounds;
   if (old_item->IsDrawing()) {
     old_record = static_cast<const DrawingDisplayItem*>(old_item)
                      ->GetPaintRecord()
                      .get();
+    old_bounds =
+        static_cast<const DrawingDisplayItem&>(new_item).GetPaintRecordBounds();
   }
   LOG(INFO) << "new record:\n"
-            << (new_record ? RecordAsDebugString(new_record) : "None");
+            << (new_record ? RecordAsDebugString(new_record, new_bounds)
+                           : "None");
   LOG(INFO) << "old record:\n"
-            << (old_record ? RecordAsDebugString(old_record) : "None");
+            << (old_record ? RecordAsDebugString(old_record, old_bounds)
+                           : "None");
 
   ShowDebugData();
 #endif  // NDEBUG
diff --git a/third_party/WebKit/Source/platform/graphics/paint/PaintController.h b/third_party/WebKit/Source/platform/graphics/paint/PaintController.h
index 6258ba0..3ebb855e 100644
--- a/third_party/WebKit/Source/platform/graphics/paint/PaintController.h
+++ b/third_party/WebKit/Source/platform/graphics/paint/PaintController.h
@@ -188,6 +188,7 @@
   void AppendDebugDrawingAfterCommit(
       const DisplayItemClient&,
       sk_sp<PaintRecord>,
+      const FloatRect& record_bounds,
       const LayoutSize& offset_from_layout_object);
 
   void ShowDebugData() const { ShowDebugDataInternal(false); }
diff --git a/third_party/WebKit/Source/platform/testing/TestPaintArtifact.cpp b/third_party/WebKit/Source/platform/testing/TestPaintArtifact.cpp
index 49a30bc..c7bb1a3 100644
--- a/third_party/WebKit/Source/platform/testing/TestPaintArtifact.cpp
+++ b/third_party/WebKit/Source/platform/testing/TestPaintArtifact.cpp
@@ -73,7 +73,7 @@
   std::unique_ptr<DummyRectClient> client =
       WTF::MakeUnique<DummyRectClient>(bounds, color);
   display_item_list_.AllocateAndConstruct<DrawingDisplayItem>(
-      *client, DisplayItem::kDrawingFirst, client->MakeRecord());
+      *client, DisplayItem::kDrawingFirst, client->MakeRecord(), bounds);
   dummy_clients_.push_back(std::move(client));
   return *this;
 }
diff --git a/third_party/WebKit/Source/web/LinkHighlightImpl.cpp b/third_party/WebKit/Source/web/LinkHighlightImpl.cpp
index 9d1d9c23..a4b0a7a 100644
--- a/third_party/WebKit/Source/web/LinkHighlightImpl.cpp
+++ b/third_party/WebKit/Source/web/LinkHighlightImpl.cpp
@@ -278,9 +278,9 @@
     return;
 
   PaintRecorder recorder;
-  gfx::Rect visual_rect = PaintableRegion();
+  gfx::Rect record_bounds = PaintableRegion();
   PaintCanvas* canvas =
-      recorder.beginRecording(visual_rect.width(), visual_rect.height());
+      recorder.beginRecording(record_bounds.width(), record_bounds.height());
 
   PaintFlags flags;
   flags.setStyle(PaintFlags::kFill_Style);
@@ -289,9 +289,11 @@
   canvas->drawPath(path_.GetSkPath(), flags);
 
   web_display_item_list->AppendDrawingItem(
-      WebRect(visual_rect.x(), visual_rect.y(), visual_rect.width(),
-              visual_rect.height()),
-      recorder.finishRecordingAsPicture());
+      WebRect(record_bounds.x(), record_bounds.y(), record_bounds.width(),
+              record_bounds.height()),
+      recorder.finishRecordingAsPicture(),
+      WebRect(record_bounds.x(), record_bounds.y(), record_bounds.width(),
+              record_bounds.height()));
 }
 
 void LinkHighlightImpl::StartHighlightAnimationIfNeeded() {
diff --git a/third_party/WebKit/Source/web/tests/scheduler/FrameThrottlingTest.cpp b/third_party/WebKit/Source/web/tests/scheduler/FrameThrottlingTest.cpp
index 2ca9084..7b110bb 100644
--- a/third_party/WebKit/Source/web/tests/scheduler/FrameThrottlingTest.cpp
+++ b/third_party/WebKit/Source/web/tests/scheduler/FrameThrottlingTest.cpp
@@ -45,8 +45,10 @@
  public:
   ~MockWebDisplayItemList() override {}
 
-  MOCK_METHOD2(AppendDrawingItem,
-               void(const WebRect&, sk_sp<const PaintRecord>));
+  MOCK_METHOD3(AppendDrawingItem,
+               void(const WebRect& visual_rect,
+                    sk_sp<const cc::PaintRecord>,
+                    const WebRect& record_bounds));
 };
 
 void PaintRecursively(GraphicsLayer* layer, WebDisplayItemList* display_items) {
@@ -836,7 +838,7 @@
 
   // Before the iframe is throttled, we should create all drawing items.
   MockWebDisplayItemList display_items_not_throttled;
-  EXPECT_CALL(display_items_not_throttled, AppendDrawingItem(_, _)).Times(3);
+  EXPECT_CALL(display_items_not_throttled, AppendDrawingItem(_, _, _)).Times(3);
   PaintRecursively(WebView().RootGraphicsLayer(), &display_items_not_throttled);
 
   // Move the frame offscreen to throttle it and make sure it is backed by a
@@ -853,7 +855,7 @@
   // If painting of the iframe is throttled, we should only receive two
   // drawing items.
   MockWebDisplayItemList display_items_throttled;
-  EXPECT_CALL(display_items_throttled, AppendDrawingItem(_, _)).Times(2);
+  EXPECT_CALL(display_items_throttled, AppendDrawingItem(_, _, _)).Times(2);
   PaintRecursively(WebView().RootGraphicsLayer(), &display_items_throttled);
 }
 
@@ -880,7 +882,7 @@
 
   // Before the iframe is throttled, we should create all drawing items.
   MockWebDisplayItemList display_items_not_throttled;
-  EXPECT_CALL(display_items_not_throttled, AppendDrawingItem(_, _)).Times(4);
+  EXPECT_CALL(display_items_not_throttled, AppendDrawingItem(_, _, _)).Times(4);
   PaintRecursively(WebView().RootGraphicsLayer(), &display_items_not_throttled);
 
   // Move the frame offscreen to throttle it.
@@ -896,7 +898,7 @@
   // If painting of the iframe is throttled, we should only receive two
   // drawing items.
   MockWebDisplayItemList display_items_throttled;
-  EXPECT_CALL(display_items_throttled, AppendDrawingItem(_, _)).Times(2);
+  EXPECT_CALL(display_items_throttled, AppendDrawingItem(_, _, _)).Times(2);
   PaintRecursively(WebView().RootGraphicsLayer(), &display_items_throttled);
 
   // Remove compositing trigger of inner_div.
@@ -920,7 +922,7 @@
   }
 
   MockWebDisplayItemList display_items_throttled1;
-  EXPECT_CALL(display_items_throttled1, AppendDrawingItem(_, _)).Times(2);
+  EXPECT_CALL(display_items_throttled1, AppendDrawingItem(_, _, _)).Times(2);
   PaintRecursively(WebView().RootGraphicsLayer(), &display_items_throttled1);
 
   // Move the frame back on screen.
@@ -935,7 +937,7 @@
 
   // After the iframe is unthrottled, we should create all drawing items.
   MockWebDisplayItemList display_items_not_throttled1;
-  EXPECT_CALL(display_items_not_throttled1, AppendDrawingItem(_, _))
+  EXPECT_CALL(display_items_not_throttled1, AppendDrawingItem(_, _, _))
       .Times(4);
   PaintRecursively(WebView().RootGraphicsLayer(),
                    &display_items_not_throttled1);
diff --git a/third_party/WebKit/Source/web/tests/sim/SimDisplayItemList.cpp b/third_party/WebKit/Source/web/tests/sim/SimDisplayItemList.cpp
index c4361e0f..5c584de 100644
--- a/third_party/WebKit/Source/web/tests/sim/SimDisplayItemList.cpp
+++ b/third_party/WebKit/Source/web/tests/sim/SimDisplayItemList.cpp
@@ -13,10 +13,10 @@
 
 SimDisplayItemList::SimDisplayItemList() {}
 
-void SimDisplayItemList::AppendDrawingItem(const WebRect&,
-                                           sk_sp<const PaintRecord> record) {
-  SkIRect bounds = record->cullRect().roundOut();
-  SimCanvas canvas(bounds.width(), bounds.height());
+void SimDisplayItemList::AppendDrawingItem(const WebRect& visual_rect,
+                                           sk_sp<const PaintRecord> record,
+                                           const WebRect& record_bounds) {
+  SimCanvas canvas(record_bounds.width, record_bounds.height);
   record->playback(&canvas);
   commands_.Append(canvas.Commands().data(), canvas.Commands().size());
 }
diff --git a/third_party/WebKit/Source/web/tests/sim/SimDisplayItemList.h b/third_party/WebKit/Source/web/tests/sim/SimDisplayItemList.h
index 63ef32f6..d9d5498 100644
--- a/third_party/WebKit/Source/web/tests/sim/SimDisplayItemList.h
+++ b/third_party/WebKit/Source/web/tests/sim/SimDisplayItemList.h
@@ -16,7 +16,9 @@
  public:
   SimDisplayItemList();
 
-  void AppendDrawingItem(const WebRect&, sk_sp<const PaintRecord>) override;
+  void AppendDrawingItem(const WebRect& visual_rect,
+                         sk_sp<const PaintRecord>,
+                         const WebRect& record_bounds) override;
 
   int DrawCount() const { return commands_.size(); }
 
diff --git a/third_party/WebKit/public/platform/WebDisplayItemList.h b/third_party/WebKit/public/platform/WebDisplayItemList.h
index 9c0dbaa..351e962a 100644
--- a/third_party/WebKit/public/platform/WebDisplayItemList.h
+++ b/third_party/WebKit/public/platform/WebDisplayItemList.h
@@ -37,7 +37,8 @@
   virtual ~WebDisplayItemList() {}
 
   virtual void AppendDrawingItem(const WebRect& visual_rect,
-                                 sk_sp<const cc::PaintRecord>) {}
+                                 sk_sp<const cc::PaintRecord>,
+                                 const WebRect& record_bounds) {}
 
   virtual void AppendClipItem(const WebRect& clip_rect,
                               const WebVector<SkRRect>& rounded_clip_rects) {}
diff --git a/ui/compositor/paint_recorder.cc b/ui/compositor/paint_recorder.cc
index f93d700..97d2b5c 100644
--- a/ui/compositor/paint_recorder.cc
+++ b/ui/compositor/paint_recorder.cc
@@ -25,7 +25,7 @@
                   gfx::RectToSkRect(gfx::Rect(recording_size))),
               context.device_scale_factor_),
       cache_(cache),
-      bounds_in_layer_(context.ToLayerSpaceBounds(recording_size)) {
+      recording_size_(recording_size) {
 #if DCHECK_IS_ON()
   DCHECK(!context.inside_paint_recorder_);
   context.inside_paint_recorder_ = true;
@@ -41,9 +41,11 @@
 #if DCHECK_IS_ON()
   context_.inside_paint_recorder_ = false;
 #endif
+  gfx::Rect bounds_in_layer = context_.ToLayerSpaceBounds(recording_size_);
   const auto& item =
       context_.list_->CreateAndAppendDrawingItem<cc::DrawingDisplayItem>(
-          bounds_in_layer_, context_.recorder_->finishRecordingAsPicture());
+          bounds_in_layer, context_.recorder_->finishRecordingAsPicture(),
+          gfx::RectToSkRect(gfx::Rect(recording_size_)));
   if (cache_)
     cache_->SetCache(item);
 }
diff --git a/ui/compositor/paint_recorder.h b/ui/compositor/paint_recorder.h
index 12a5e9f..c52c3f83 100644
--- a/ui/compositor/paint_recorder.h
+++ b/ui/compositor/paint_recorder.h
@@ -41,7 +41,7 @@
   const PaintContext& context_;
   gfx::Canvas canvas_;
   PaintCache* cache_;
-  gfx::Rect bounds_in_layer_;
+  gfx::Size recording_size_;
 
   DISALLOW_COPY_AND_ASSIGN(PaintRecorder);
 };