Simplify computation of the invalidation rect for scrolling, and clip
rects for plugins.

BUG=549788
TBR=bbudge@chromium.org,mseaborn@chromium.org

Review URL: https://codereview.chromium.org/1413523007

Cr-Commit-Position: refs/heads/master@{#358262}
diff --git a/chrome/test/data/nacl/ppapi/ppp_instance/ppapi_ppp_instance.cc b/chrome/test/data/nacl/ppapi/ppp_instance/ppapi_ppp_instance.cc
index 9ad5a47..d9e1f80 100644
--- a/chrome/test/data/nacl/ppapi/ppp_instance/ppapi_ppp_instance.cc
+++ b/chrome/test/data/nacl/ppapi/ppp_instance/ppapi_ppp_instance.cc
@@ -45,13 +45,14 @@
 
   PP_Rect clip;
   PPBView()->GetClipRect(view, &clip);
-  EXPECT(clip.point.x == 0 && clip.point.y == 0);
+  EXPECT(clip.point.x == 0 && clip.point.y == -1);
 
   // These are based on embed dimensions.
   PP_Rect position;
   PPBView()->GetRect(view, &position);
+  fprintf(stderr, "clip.size.height: %d\n", clip.size.height);
   EXPECT(position.size.width == 15 && clip.size.width == 15);
-  EXPECT(position.size.height == 20 && clip.size.height == 20);
+  EXPECT(position.size.height == 20 && clip.size.height == 23);
 
   TEST_PASSED;
 }
diff --git a/ppapi/tests/test_view.cc b/ppapi/tests/test_view.cc
index 8239b03..f8c20d8 100644
--- a/ppapi/tests/test_view.cc
+++ b/ppapi/tests/test_view.cc
@@ -142,8 +142,8 @@
 
   // Original clip should be the full frame.
   pp::Rect original_clip = last_view_.GetClipRect();
-  ASSERT_TRUE(original_clip.x() == 0);
-  ASSERT_TRUE(original_clip.y() == 0);
+  ASSERT_TRUE(original_clip.x() == 1);
+  ASSERT_TRUE(original_clip.y() == 1);
   ASSERT_TRUE(original_clip.width() == original_rect.width());
   ASSERT_TRUE(original_clip.height() == original_rect.height());
 
@@ -164,8 +164,9 @@
   instance_->EvalScript(script_stream.str());
 
   pp::Rect desired_clip = original_clip;
-  desired_clip.set_y(clip_amount);
-  desired_clip.set_height(desired_clip.height() - desired_clip.y());
+  desired_clip.set_y(clip_amount + original_clip.y());
+  desired_clip.set_height(
+    desired_clip.height() - desired_clip.y() +  original_clip.y());
 
   while (WaitUntilViewChanged() && last_view_.GetClipRect() != desired_clip) {
   }
diff --git a/third_party/WebKit/LayoutTests/TestExpectations b/third_party/WebKit/LayoutTests/TestExpectations
index f360937..966d1199 100644
--- a/third_party/WebKit/LayoutTests/TestExpectations
+++ b/third_party/WebKit/LayoutTests/TestExpectations
@@ -39,6 +39,8 @@
 
 crbug.com/536138 virtual/spv2/paint/invalidation/repaint-subsequence-on-ancestor-clip-change.html [ Failure ]
 
+crbug.com/549788 plugins/plugin-clip-subframe.html [ NeedsRebaseline ]
+
 crbug.com/537172 [ Mac10.6 XP Win10 ] virtual/spv2/paint/invalidation/spv2/background-image-paint-invalidation.html [ Failure ]
 
 crbug.com/504613 crbug.com/524248 paint/images/image-backgrounds-not-antialiased.html [ Skip ]
diff --git a/third_party/WebKit/Source/core/frame/FrameView.cpp b/third_party/WebKit/Source/core/frame/FrameView.cpp
index 8e5a9be6..597e7c8 100644
--- a/third_party/WebKit/Source/core/frame/FrameView.cpp
+++ b/third_party/WebKit/Source/core/frame/FrameView.cpp
@@ -2035,54 +2035,9 @@
 {
     ASSERT(m_frame->view() == this);
 
-    // Set our clip rect to be our contents.
-    IntRect clipRect = contentsToRootFrame(visibleContentRect(scrollbarInclusion));
-    if (!m_frame->deprecatedLocalOwner())
-        return clipRect;
-
-    // Take our owner element and get its clip rect.
-    // FIXME: Do we need to do this for remote frames?
-    HTMLFrameOwnerElement* ownerElement = m_frame->deprecatedLocalOwner();
-    FrameView* parentView = ownerElement->document().view();
-    if (parentView)
-        clipRect.intersect(parentView->clipRectsForFrameOwner(ownerElement, nullptr));
-    return clipRect;
-}
-
-IntRect FrameView::clipRectsForFrameOwner(const HTMLFrameOwnerElement* ownerElement, IntRect* unobscuredRect) const
-{
-    ASSERT(ownerElement);
-
-    if (unobscuredRect)
-        *unobscuredRect = IntRect();
-
-    // The layoutObject can sometimes be null when style="display:none" interacts
-    // with external content and plugins.
-    if (!ownerElement->layoutObject())
-        return windowClipRect();
-
-    // If we have no layer, just return our window clip rect.
-    const PaintLayer* enclosingLayer = ownerElement->layoutObject()->enclosingLayer();
-    if (!enclosingLayer)
-        return windowClipRect();
-
-    // FIXME: childrenClipRect relies on compositingState, which is not necessarily up to date.
-    // https://code.google.com/p/chromium/issues/detail?id=343769
-    DisableCompositingQueryAsserts disabler;
-
-    // Apply the clip from the layer.
-    IntRect elementRect = contentsToRootFrame(pixelSnappedIntRect(enclosingLayer->clipper().childrenClipRect()));
-
-    if (unobscuredRect) {
-        *unobscuredRect = elementRect;
-
-        // If element is not in root frame, clip to the local frame.
-        // FIXME: Do we need to do this for remote frames?
-        if (m_frame->deprecatedLocalOwner())
-            unobscuredRect->intersect(contentsToRootFrame(visibleContentRect()));
-    }
-
-    return intersection(elementRect, windowClipRect());
+    LayoutRect clipRect(LayoutPoint(), LayoutSize(visibleContentSize(scrollbarInclusion)));
+    layoutView()->mapRectToPaintInvalidationBacking(layoutView()->containerForPaintInvalidation(), clipRect, nullptr);
+    return enclosingIntRect(clipRect);
 }
 
 bool FrameView::shouldUseIntegerScrollOffset() const
diff --git a/third_party/WebKit/Source/core/frame/FrameView.h b/third_party/WebKit/Source/core/frame/FrameView.h
index 4b049e70..e6884a7 100644
--- a/third_party/WebKit/Source/core/frame/FrameView.h
+++ b/third_party/WebKit/Source/core/frame/FrameView.h
@@ -167,9 +167,6 @@
 
     void adjustViewSize();
 
-    // |unobscuredRect| receives the clip rect that is not clipped to the root window. It may be nullptr.
-    IntRect clipRectsForFrameOwner(const HTMLFrameOwnerElement*, IntRect* unobscuredRect) const;
-
     // Scale used to convert incoming input events.
     float inputEventsScaleFactor() const;
 
@@ -367,6 +364,7 @@
     bool isScrollCornerVisible() const override;
     bool userInputScrollable(ScrollbarOrientation) const override;
     bool shouldPlaceVerticalScrollbarOnLeft() const override;
+
     LayoutRect scrollIntoView(
         const LayoutRect& rectInContent,
         const ScrollAlignment& alignX,
diff --git a/third_party/WebKit/Source/core/layout/LayoutPart.cpp b/third_party/WebKit/Source/core/layout/LayoutPart.cpp
index c22e254d..4741abc 100644
--- a/third_party/WebKit/Source/core/layout/LayoutPart.cpp
+++ b/third_party/WebKit/Source/core/layout/LayoutPart.cpp
@@ -315,7 +315,7 @@
         contentBox.setLocation(absoluteContentBox.location());
         return setWidgetGeometry(contentBox);
     }
-
+    // TODO(chrishtr): why are these widgets using an absolute rect for their frameRect?
     return setWidgetGeometry(absoluteContentBox);
 }
 
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp b/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp
index 989dc1c..7bb1bae 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp
+++ b/third_party/WebKit/Source/core/paint/PaintLayerClipper.cpp
@@ -170,18 +170,6 @@
     }
 }
 
-LayoutRect PaintLayerClipper::childrenClipRect() const
-{
-    // FIXME: border-radius not accounted for.
-    // FIXME: Flow thread based columns not accounted for.
-    PaintLayer* clippingRootLayer = clippingRootForPainting();
-    LayoutRect layerBounds;
-    ClipRect backgroundRect, foregroundRect;
-    // Need to use uncached clip rects, because the value of 'dontClipToOverflow' may be different from the painting path (<rdar://problem/11844909>).
-    ClipRectsContext context(clippingRootLayer, UncachedClipRects);
-    calculateRects(context, LayoutRect(m_layoutObject.view()->unscaledDocumentRect()), layerBounds, backgroundRect, foregroundRect);
-    return LayoutRect(clippingRootLayer->layoutObject()->localToAbsoluteQuad(FloatQuad(FloatRect(foregroundRect.rect()))).enclosingBoundingBox());
-}
 
 LayoutRect PaintLayerClipper::localClipRect(const PaintLayer* clippingRootLayer) const
 {
@@ -326,30 +314,6 @@
         calculateClipRects(context, clipRects);
 }
 
-PaintLayer* PaintLayerClipper::clippingRootForPainting() const
-{
-    const PaintLayer* current = m_layoutObject.layer();
-    // FIXME: getting rid of current->hasCompositedLayerMapping() here breaks the
-    // compositing/backing/no-backing-for-clip.html layout test, because there is a
-    // "composited but paints into ancestor" layer involved. However, it doesn't make sense that
-    // that check would be appropriate here but not inside the while loop below.
-    if (current->isPaintInvalidationContainer() || current->hasCompositedLayerMapping())
-        return const_cast<PaintLayer*>(current);
-
-    while (current) {
-        if (current->isRootLayer())
-            return const_cast<PaintLayer*>(current);
-
-        current = current->compositingContainer();
-        ASSERT(current);
-        if (current->transform() || current->isPaintInvalidationContainer())
-            return const_cast<PaintLayer*>(current);
-    }
-
-    ASSERT_NOT_REACHED();
-    return 0;
-}
-
 bool PaintLayerClipper::shouldRespectOverflowClip(const ClipRectsContext& context) const
 {
     PaintLayer* layer = m_layoutObject.layer();
diff --git a/third_party/WebKit/Source/core/paint/PaintLayerClipper.h b/third_party/WebKit/Source/core/paint/PaintLayerClipper.h
index 2092d7f9..0c04bea8 100644
--- a/third_party/WebKit/Source/core/paint/PaintLayerClipper.h
+++ b/third_party/WebKit/Source/core/paint/PaintLayerClipper.h
@@ -147,7 +147,7 @@
 // #container and #fixed are siblings in the paint tree but #container does
 // clip #fixed. This is the reason why we compute the painting clip rects during
 // a layout tree walk and cache them for painting.
-class PaintLayerClipper {
+class CORE_EXPORT PaintLayerClipper {
     DISALLOW_NEW();
     WTF_MAKE_NONCOPYABLE(PaintLayerClipper);
 public:
@@ -156,8 +156,6 @@
     void clearClipRectsIncludingDescendants();
     void clearClipRectsIncludingDescendants(ClipRectsCacheSlot);
 
-    LayoutRect childrenClipRect() const; // Returns the foreground clip rect of the layer in the document's coordinate space.
-
     // Returns the background clip rect of the layer in the local coordinate space. Only looks for clips up to the given ancestor.
     LayoutRect localClipRect(const PaintLayer* ancestorLayer) const;
 
@@ -184,8 +182,6 @@
     }
     void getOrCalculateClipRects(const ClipRectsContext&, ClipRects&) const;
 
-    PaintLayer* clippingRootForPainting() const;
-
     ClipRectsCache& cache() const
     {
         if (!m_cache)
diff --git a/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp b/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp
index 7be53ac..5c9b8a4 100644
--- a/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp
+++ b/third_party/WebKit/Source/web/WebPluginContainerImpl.cpp
@@ -55,6 +55,7 @@
 #include "core/layout/HitTestResult.h"
 #include "core/layout/LayoutBox.h"
 #include "core/layout/LayoutPart.h"
+#include "core/layout/LayoutView.h"
 #include "core/loader/FrameLoadRequest.h"
 #include "core/page/FocusController.h"
 #include "core/page/Page.h"
@@ -420,7 +421,6 @@
     IntRect windowRect, clipRect, unobscuredRect;
     Vector<IntRect> cutOutRects;
     calculateGeometry(windowRect, clipRect, unobscuredRect, cutOutRects);
-
     m_webPlugin->updateGeometry(windowRect, clipRect, unobscuredRect, cutOutRects, isVisible());
 }
 
@@ -944,33 +944,55 @@
     m_pendingInvalidationRect = IntRect();
 }
 
+void WebPluginContainerImpl::computeClipRectsForPlugin(
+    const HTMLFrameOwnerElement* ownerElement, IntRect& windowRect, IntRect& clippedLocalRect, IntRect& unclippedIntLocalRect) const
+{
+    ASSERT(ownerElement);
+
+    if (!ownerElement->layoutObject()) {
+        clippedLocalRect = IntRect();
+        unclippedIntLocalRect = IntRect();
+        return;
+    }
+
+    LayoutView* rootView = m_element->document().view()->layoutView();
+    while (rootView->frame()->ownerLayoutObject())
+        rootView = rootView->frame()->ownerLayoutObject()->view();
+
+    LayoutBox* box = toLayoutBox(ownerElement->layoutObject());
+
+    // Plugin frameRects are in absolute screen space.
+    IntRect frameRectInOwnerElementSpace = box->absoluteToLocalQuad(FloatRect(frameRect()), UseTransforms).enclosingBoundingBox();
+
+    LayoutRect unclippedAbsoluteRect(frameRectInOwnerElementSpace);
+    box->mapRectToPaintInvalidationBacking(rootView, unclippedAbsoluteRect, nullptr);
+
+    // The frameRect is already in absolute space.
+    windowRect = frameRect();
+
+    clippedLocalRect = enclosingIntRect(unclippedAbsoluteRect);
+    unclippedIntLocalRect = clippedLocalRect;
+    clippedLocalRect.intersect(rootView->frameView()->visibleContentRect());
+
+    // TODO(chrishtr): intentionally ignore transform, because the positioning of frameRect() does also. This is probably wrong.
+    unclippedIntLocalRect = box->absoluteToLocalQuad(FloatRect(unclippedIntLocalRect)).enclosingBoundingBox();
+    clippedLocalRect = box->absoluteToLocalQuad(FloatRect(clippedLocalRect)).enclosingBoundingBox();
+}
+
 void WebPluginContainerImpl::calculateGeometry(IntRect& windowRect, IntRect& clipRect, IntRect& unobscuredRect, Vector<IntRect>& cutOutRects)
 {
-    windowRect = toFrameView(parent())->contentsToRootFrame(frameRect());
-
-    // Calculate a clip-rect so that we don't overlap the scrollbars, etc.
-    clipRect = convertToContainingWindow(IntRect(0, 0, width(), height()));
-    unobscuredRect = clipRect;
-
     // document().layoutView() can be 0 when we receive messages from the
     // plugins while we are destroying a frame.
     // FIXME: Can we just check m_element->document().isActive() ?
     if (m_element->layoutObject()->document().layoutView()) {
         // Take our element and get the clip rect from the enclosing layer and
         // frame view.
-        IntRect elementUnobscuredRect;
-        IntRect elementWindowClipRect = m_element->document().view()->clipRectsForFrameOwner(m_element, &elementUnobscuredRect);
-        clipRect.intersect(elementWindowClipRect);
-        unobscuredRect.intersect(elementUnobscuredRect);
+        computeClipRectsForPlugin(m_element, windowRect, clipRect, unobscuredRect);
     }
-
-    clipRect.move(-windowRect.x(), -windowRect.y());
-    unobscuredRect.move(-windowRect.x(), -windowRect.y());
-
     getPluginOcclusions(m_element, this->parent(), frameRect(), cutOutRects);
     // Convert to the plugin position.
     for (size_t i = 0; i < cutOutRects.size(); i++)
         cutOutRects[i].move(-frameRect().x(), -frameRect().y());
 }
 
-} // namespace blink
+} // namespace blinkf
diff --git a/third_party/WebKit/Source/web/WebPluginContainerImpl.h b/third_party/WebKit/Source/web/WebPluginContainerImpl.h
index 131eb18..eaff5bd 100644
--- a/third_party/WebKit/Source/web/WebPluginContainerImpl.h
+++ b/third_party/WebKit/Source/web/WebPluginContainerImpl.h
@@ -165,6 +165,12 @@
 #endif
 
 private:
+    // Sets |windowRect| to the content rect of the plugin in screen space.
+    // Sets |clippedAbsoluteRect| to the visible rect for the plugin, clipped to the visible screen of the root frame, in local space of the plugin.
+    // Sets |unclippedAbsoluteRect| to the visible rect for the plugin (but without also clipping to the screen), in local space of the plugin.
+    void computeClipRectsForPlugin(
+        const HTMLFrameOwnerElement* pluginOwnerElement, IntRect& windowRect, IntRect& clippedLocalRect, IntRect& unclippedIntLocalRect) const;
+
     WebPluginContainerImpl(HTMLPlugInElement*, WebPlugin*);
     ~WebPluginContainerImpl() override;