Move the 'overflow' event dispatching logic out of RenderLayer
authorjchaffraix@webkit.org <jchaffraix@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 2 Mar 2012 19:24:18 +0000 (19:24 +0000)
committerjchaffraix@webkit.org <jchaffraix@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 2 Mar 2012 19:24:18 +0000 (19:24 +0000)
https://bugs.webkit.org/show_bug.cgi?id=80090

Reviewed by Simon Fraser.

Source/WebCore:

Test: fast/events/overflow-events-writing-mode.html

This moves the 'overflow' event dispatch from RenderLayer to an helper class
OverflowEventDispatcher. For now, the class lives in RenderBlock as it matches
the existing code but it may be moved later to its own class as FrameView could
benefit from it too or if we need to support 'overflow' events on RenderBoxes.

* rendering/RenderBlock.cpp:
(WebCore):
(OverflowEventDispatcher):
(WebCore::OverflowEventDispatcher::OverflowEventDispatcher):
(WebCore::OverflowEventDispatcher::~OverflowEventDispatcher):
(WebCore::OverflowEventDispatcher::computeOverflowStatus):
RAII dispatcher class that stores the information before layout and compare
them after to dispatch the right information.

(WebCore::RenderBlock::layout): Added an instance of OverflowEventDispatcher.

* rendering/RenderBox.h:
(WebCore::RenderBox::hasHorizontalLayoutOverflow):
(WebCore::RenderBox::hasVerticalLayoutOverflow):
Helper method to know if we have an horizontal / vertical layout overflow.

* rendering/RenderLayer.cpp:
(WebCore::RenderLayer::RenderLayer):
(WebCore::RenderLayer::updateScrollInfoAfterLayout):
* rendering/RenderLayer.h:
Removed the scroll tracking logic as we don't need it anymore. This removes
3 booleans from RenderLayer.

LayoutTests:

* fast/events/overflow-events-writing-mode.html: Added.
* fast/events/overflow-events-writing-mode-expected.txt: Added.
Added a test for overflow events in a vertical writing mode.

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@109587 268f45cc-cd09-0410-ab3c-d52691b4dbfc

LayoutTests/ChangeLog
LayoutTests/fast/events/overflow-events-writing-mode-expected.txt [new file with mode: 0644]
LayoutTests/fast/events/overflow-events-writing-mode.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/rendering/RenderBlock.cpp
Source/WebCore/rendering/RenderBox.h
Source/WebCore/rendering/RenderLayer.cpp
Source/WebCore/rendering/RenderLayer.h

index fabff289be208873cf8ba9eab34e14ed18ea1eb1..bca0217e00fceb34e76be05779acce4c930a3d7a 100644 (file)
@@ -1,3 +1,14 @@
+2012-03-02  Julien Chaffraix  <jchaffraix@webkit.org>
+
+        Move the 'overflow' event dispatching logic out of RenderLayer
+        https://bugs.webkit.org/show_bug.cgi?id=80090
+
+        Reviewed by Simon Fraser.
+
+        * fast/events/overflow-events-writing-mode.html: Added.
+        * fast/events/overflow-events-writing-mode-expected.txt: Added.
+        Added a test for overflow events in a vertical writing mode.
+
 2012-03-02  Adam Klein  <adamk@chromium.org>
 
         Rebaseline a test on Leopard after expectation was removed in r109516.
diff --git a/LayoutTests/fast/events/overflow-events-writing-mode-expected.txt b/LayoutTests/fast/events/overflow-events-writing-mode-expected.txt
new file mode 100644 (file)
index 0000000..1ea4693
--- /dev/null
@@ -0,0 +1,2 @@
+This tests that overflowchanged events are fired correctly on nodes with writing-mode: vertical-lr. If the test is successful, the text "SUCCESS" should be shown below.
+SUCCESS
diff --git a/LayoutTests/fast/events/overflow-events-writing-mode.html b/LayoutTests/fast/events/overflow-events-writing-mode.html
new file mode 100644 (file)
index 0000000..44c2898
--- /dev/null
@@ -0,0 +1,90 @@
+<html>
+<head>
+  <script>
+    var longInlineBlockDirectionText = "longlonglonglonglongtext<br>longlonglonglonglongtext<br>longlonglonglonglongtext<br>longlonglonglonglongtext<br>longlonglonglonglongtext<br>longlonglonglonglongtext<br>";
+    var longInlineBaseDirectionText = "longlonglonglonglongtext";
+    var longBlockFlowDirectionText="long<br>long<br>long<br>long<br>long<br>long<br>long<br>";
+    var shortText = "l";
+    function setupTest() {
+        // horizontal overflow.
+        var horizontalOverflow = testResults[currentTest][1];
+        var verticalOverflow = testResults[currentTest][2];
+
+        if (horizontalOverflow && verticalOverflow) {
+            document.getElementById('child').innerHTML = longInlineBlockDirectionText;
+        } else if (horizontalOverflow) {
+            document.getElementById('child').innerHTML = longBlockFlowDirectionText;
+        } else if (verticalOverflow) {
+            document.getElementById('child').innerHTML = longInlineBaseDirectionText;
+        } else {
+            document.getElementById('child').innerHTML = shortText;
+        }
+    }
+
+    function finished(result)
+    {
+        document.getElementById('result').innerHTML = result;
+        document.getElementById('child').innerHTML = "";
+
+        if (window.layoutTestController)
+            layoutTestController.notifyDone();
+    }
+
+    function nextTest() {
+        if (currentTest == testResults.length) {
+            finished("SUCCESS");
+            return;
+        }
+
+        forceLayout();
+        setupTest();
+        forceLayout();
+        forceLayout();
+    }
+
+    function overflowChanged(event) {
+        var result = [event.orient, event.horizontalOverflow, event.verticalOverflow];
+
+        if ('' + result == testResults[currentTest]) {
+            currentTest++;
+            nextTest();
+        } else
+            finished("FAILURE: expected " + testResults[currentTest] + " got " + result);
+    }
+
+    function forceLayout() {
+        document.body.offsetTop;
+    }
+
+    function runTest() {
+        if (window.layoutTestController) {
+            layoutTestController.dumpAsText();
+            layoutTestController.waitUntilDone();
+        }
+
+        testResults = [[OverflowEvent.HORIZONTAL, true, false],
+                       [OverflowEvent.HORIZONTAL, false, false],
+                       [OverflowEvent.VERTICAL, false, true],
+                       [OverflowEvent.VERTICAL, false, false],
+                       [OverflowEvent.BOTH, true, true],
+                       [OverflowEvent.BOTH, false, false],
+                       [OverflowEvent.VERTICAL, false, true],
+                       [OverflowEvent.BOTH, true, false],
+                       [OverflowEvent.BOTH, false, true]];
+
+        currentTest = 0;
+
+        var c = document.getElementById('container');
+        c.addEventListener('overflowchanged', overflowChanged, false);
+        nextTest();
+    }
+  </script>
+</head>
+<body onload="runTest()">
+    <div id="container" style="width:100; height:100px; border: solid red 2px; overflow: hidden">
+        <div id="child" style="margin-top: 30px; margin-left: 30px; font-family: Ahem; border: solid blue 2px; -webkit-writing-mode: vertical-lr;"></div>
+    </div>
+    This tests that overflowchanged events are fired correctly on nodes with writing-mode: vertical-lr. If the test is successful, the text "SUCCESS" should be shown below.
+    <div id="result">FAILURE</div>
+</body>
+</html>
index 6a536e270d8880acc8019028520f35534252c135..70f15e508ff2e142ed14c14cb6a9079005cbb28b 100644 (file)
@@ -1,3 +1,40 @@
+2012-03-02  Julien Chaffraix  <jchaffraix@webkit.org>
+
+        Move the 'overflow' event dispatching logic out of RenderLayer
+        https://bugs.webkit.org/show_bug.cgi?id=80090
+
+        Reviewed by Simon Fraser.
+
+        Test: fast/events/overflow-events-writing-mode.html
+
+        This moves the 'overflow' event dispatch from RenderLayer to an helper class
+        OverflowEventDispatcher. For now, the class lives in RenderBlock as it matches
+        the existing code but it may be moved later to its own class as FrameView could
+        benefit from it too or if we need to support 'overflow' events on RenderBoxes.
+
+        * rendering/RenderBlock.cpp:
+        (WebCore):
+        (OverflowEventDispatcher):
+        (WebCore::OverflowEventDispatcher::OverflowEventDispatcher):
+        (WebCore::OverflowEventDispatcher::~OverflowEventDispatcher):
+        (WebCore::OverflowEventDispatcher::computeOverflowStatus):
+        RAII dispatcher class that stores the information before layout and compare
+        them after to dispatch the right information.
+
+        (WebCore::RenderBlock::layout): Added an instance of OverflowEventDispatcher.
+
+        * rendering/RenderBox.h:
+        (WebCore::RenderBox::hasHorizontalLayoutOverflow):
+        (WebCore::RenderBox::hasVerticalLayoutOverflow):
+        Helper method to know if we have an horizontal / vertical layout overflow.
+
+        * rendering/RenderLayer.cpp:
+        (WebCore::RenderLayer::RenderLayer):
+        (WebCore::RenderLayer::updateScrollInfoAfterLayout):
+        * rendering/RenderLayer.h:
+        Removed the scroll tracking logic as we don't need it anymore. This removes
+        3 booleans from RenderLayer.
+
 2012-03-02  Caio Marcelo de Oliveira Filho  <caio.oliveira@openbossa.org>
 
         Create a method in Element to compare attributes with other Element
index c363ef241cb7bc95e0bbbc45c6e2af801fa5a1a7..58dbda7ecb285f2ed721517a240c22f85e3a4100 100755 (executable)
@@ -38,6 +38,7 @@
 #include "InlineIterator.h"
 #include "InlineTextBox.h"
 #include "LayoutRepainter.h"
+#include "OverflowEvent.h"
 #include "PODFreeListArena.h"
 #include "Page.h"
 #include "PaintInfo.h"
@@ -85,6 +86,50 @@ static DelayedUpdateScrollInfoSet* gDelayedUpdateScrollInfoSet = 0;
 
 bool RenderBlock::s_canPropagateFloatIntoSibling = false;
 
+// This class helps dispatching the 'overflow' event on layout change. overflow can be set on RenderBoxes, yet the existing code
+// only works on RenderBlocks. If this change, this class should be shared with other RenderBoxes.
+class OverflowEventDispatcher {
+    WTF_MAKE_NONCOPYABLE(OverflowEventDispatcher);
+public:
+    OverflowEventDispatcher(const RenderBlock* block)
+        : m_block(block)
+        , m_hadHorizontalLayoutOverflow(false)
+        , m_hadVerticalLayoutOverflow(false)
+    {
+        m_shouldDispatchEvent = !m_block->isAnonymous() && m_block->hasOverflowClip() && m_block->document()->hasListenerType(Document::OVERFLOWCHANGED_LISTENER);
+        if (m_shouldDispatchEvent) {
+            m_hadHorizontalLayoutOverflow = m_block->hasHorizontalLayoutOverflow();
+            m_hadVerticalLayoutOverflow = m_block->hasVerticalLayoutOverflow();
+        }
+    }
+
+    ~OverflowEventDispatcher()
+    {
+        if (!m_shouldDispatchEvent)
+            return;
+
+        bool hasHorizontalLayoutOverflow = m_block->hasHorizontalLayoutOverflow();
+        bool hasVerticalLayoutOverflow = m_block->hasVerticalLayoutOverflow();
+
+        bool horizontalLayoutOverflowChanged = hasHorizontalLayoutOverflow != m_hadHorizontalLayoutOverflow;
+        bool verticalLayoutOverflowChanged = hasVerticalLayoutOverflow != m_hadVerticalLayoutOverflow;
+        if (horizontalLayoutOverflowChanged || verticalLayoutOverflowChanged) {
+            if (FrameView* frameView = m_block->document()->view())
+                frameView->scheduleEvent(OverflowEvent::create(horizontalLayoutOverflowChanged, hasHorizontalLayoutOverflow, verticalLayoutOverflowChanged, hasVerticalLayoutOverflow), m_block->node());
+        }
+    }
+
+private:
+    void computeOverflowStatus(bool& hasHorizontalLayoutOverflow, bool& hasVerticalLayoutOverflow)
+    {
+    }
+
+    const RenderBlock* m_block;
+    bool m_shouldDispatchEvent;
+    bool m_hadHorizontalLayoutOverflow;
+    bool m_hadVerticalLayoutOverflow;
+};
+
 // Our MarginInfo state used when laying out block children.
 RenderBlock::MarginInfo::MarginInfo(RenderBlock* block, LayoutUnit beforeBorderPadding, LayoutUnit afterBorderPadding)
     : m_atBeforeSideOfBlock(true)
@@ -1321,6 +1366,8 @@ void RenderBlock::updateScrollInfoAfterLayout()
 
 void RenderBlock::layout()
 {
+    OverflowEventDispatcher dispatcher(this);
+
     // Update our first letter info now.
     updateFirstLetter();
 
index 5a36d802ea229ce610564e0a6bff225a20c1cf5d..014e5bc2e5703410541a68000c8c72d00c34a49e 100644 (file)
@@ -452,6 +452,28 @@ public:
 
     virtual bool hasRelativeDimensions() const;
 
+    bool hasHorizontalLayoutOverflow() const
+    {
+        if (RenderOverflow* overflow = hasRenderOverflow()) {
+            LayoutRect layoutOverflowRect = overflow->layoutOverflowRect();
+            flipForWritingMode(layoutOverflowRect);
+            return layoutOverflowRect.x() < x() || layoutOverflowRect.maxX() > x() + logicalWidth();
+        }
+
+        return false;
+    }
+
+    bool hasVerticalLayoutOverflow() const
+    {
+        if (RenderOverflow* overflow = hasRenderOverflow()) {
+            LayoutRect layoutOverflowRect = overflow->layoutOverflowRect();
+            flipForWritingMode(layoutOverflowRect);
+            return layoutOverflowRect.y() < y() || layoutOverflowRect.maxY() > y() + logicalHeight();
+        }
+
+        return false;
+    }
+
 protected:
     virtual void willBeDestroyed();
 
index cbd4f706038b68fe6a4c616516941d14f6b22166..351aebb991e0027696d0efdc89935c404d68b962 100644 (file)
@@ -153,7 +153,6 @@ RenderLayer::RenderLayer(RenderBoxModelObject* renderer)
     , m_paintingInsideReflection(false)
     , m_inOverflowRelayout(false)
     , m_repaintStatus(NeedsNormalRepaint)
-    , m_overflowStatusDirty(true)
     , m_visibleContentStatusDirty(true)
     , m_hasVisibleContent(false)
     , m_visibleDescendantStatusDirty(false)
@@ -2318,29 +2317,6 @@ void RenderLayer::computeScrollDimensions(bool* needHBar, bool* needVBar)
         *needVBar = pixelSnappedScrollHeight() > box->pixelSnappedClientHeight();
 }
 
-void RenderLayer::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow)
-{
-    if (m_overflowStatusDirty) {
-        m_horizontalOverflow = horizontalOverflow;
-        m_verticalOverflow = verticalOverflow;
-        m_overflowStatusDirty = false;
-        return;
-    }
-    
-    bool horizontalOverflowChanged = (m_horizontalOverflow != horizontalOverflow);
-    bool verticalOverflowChanged = (m_verticalOverflow != verticalOverflow);
-    
-    if (horizontalOverflowChanged || verticalOverflowChanged) {
-        m_horizontalOverflow = horizontalOverflow;
-        m_verticalOverflow = verticalOverflow;
-        
-        if (FrameView* frameView = renderer()->document()->view()) {
-            frameView->scheduleEvent(OverflowEvent::create(horizontalOverflowChanged, horizontalOverflow, verticalOverflowChanged, verticalOverflow),
-                renderer()->node());
-        }
-    }
-}
-
 void RenderLayer::updateScrollInfoAfterLayout()
 {
     RenderBox* box = renderBox();
@@ -2434,9 +2410,6 @@ void RenderLayer::updateScrollInfoAfterLayout()
 
     if (scrollOffsetOriginal != scrollOffset())
         scrollToOffsetWithoutAnimation(LayoutPoint(scrollXOffset(), scrollYOffset()));
-
-    if (renderer()->node() && renderer()->document()->hasListenerType(Document::OVERFLOWCHANGED_LISTENER))
-        updateOverflowStatus(horizontalOverflow, verticalOverflow);
 }
 
 void RenderLayer::paintOverflowControls(GraphicsContext* context, const IntPoint& paintOffset, const IntRect& damageRect, bool paintingOverlayControls)
index bbc72e0030da26a4c5e9ed71e76e939ff8b0fc5e..c8656ce76610b740528e1c8b9d95cc2b351fc585 100644 (file)
@@ -680,8 +680,6 @@ private:
 
     IntSize scrollbarOffset(const Scrollbar*) const;
     
-    void updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow);
-
     void childVisibilityChanged(bool newVisibility);
     void dirtyVisibleDescendantStatus();
     void updateVisibilityStatus();
@@ -776,9 +774,6 @@ protected:
     bool m_inOverflowRelayout : 1;
     unsigned m_repaintStatus : 2; // RepaintStatus
 
-    bool m_overflowStatusDirty : 1;
-    bool m_horizontalOverflow : 1;
-    bool m_verticalOverflow : 1;
     bool m_visibleContentStatusDirty : 1;
     bool m_hasVisibleContent : 1;
     bool m_visibleDescendantStatusDirty : 1;