WebCore:
authormitz@apple.com <mitz@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 4 Dec 2007 00:25:38 +0000 (00:25 +0000)
committermitz@apple.com <mitz@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 4 Dec 2007 00:25:38 +0000 (00:25 +0000)
        Reviewed by Dave Hyatt.

        - fix <rdar://problem/5346452> Resize event doesn't fire on body element inside a frame

        Test: fast/events/resize-subframe.html

        * page/FrameView.cpp:
        (WebCore::FrameViewPrivate::FrameViewPrivate): Added a timer used when
        deferring tasks that need to be done after layout.
        (WebCore::FrameViewPrivate::reset):
        (WebCore::FrameView::~FrameView):
        (WebCore::FrameView::layout): Moved the updating of widget positions,
        loading plug-ins and sending events queued up during layout into
        performPostLayoutTasks(). performPostLayoutTasks() is called after
        layout unless the layout was triggered by a previous layout's post-
        layout tasks. In the latter case, performPostLayoutTasks() is scheduled
        to run later.
        (WebCore::FrameView::performPostLayoutTasks): Performs work that needs
        to be done after layout but which can result in arbitrary code
        execution and therefore may re-invalidate the layout. This includes
        updating widget positions, loading plug-ins, and dispatching layout-
        related DOM events (scroll, overflow and resize).
        (WebCore::FrameView::postLayoutTimerFired):
        (WebCore::FrameView::dispatchScheduledEvents):
        * page/FrameView.h:
        * page/mac/WebCoreFrameBridge.h:
        * page/mac/WebCoreFrameBridge.mm: Removed -sendResizeEvent since this
        is handled by FrameView now.

WebKit/gtk:

        Reviewed by Dave Hyatt.

        - fix <rdar://problem/5346452> Resize event doesn't fire on body element inside a frame

        * WebView/webkitwebview.cpp: Remove the call to sendResizeEvent() since
        FrameView sends it now.

WebKit/mac:

        Reviewed by Dave Hyatt.

        - fix <rdar://problem/5346452> Resize event doesn't fire on body element inside a frame

        * WebView/WebHTMLView.mm:
        (-[WebHTMLView layoutToMinimumPageWidth:maximumPageWidth:adjustingViewSize:]): Removed the code
        that checked if the view had resized and sent the resize event, since
        FrameView sends resize events now.
        * WebView/WebHTMLViewInternal.h:

WebKit/win:

        Reviewed by Dave Hyatt.

        - fix <rdar://problem/5346452> Resize event doesn't fire on body element inside a frame

        * WebView.cpp:
        (WebViewWndProc): Removed call to sendResizeEvent() since FrameView
        sends them now.

LayoutTests:

        Reviewed by Dave Hyatt.

        - test for <rdar://problem/5346452> Resize event doesn't fire on body element inside a frame

        * fast/events/resize-subframe-expected.txt: Added.
        * fast/events/resize-subframe.html: Added.

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

15 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/events/resize-subframe-expected.txt [new file with mode: 0644]
LayoutTests/fast/events/resize-subframe.html [new file with mode: 0644]
WebCore/ChangeLog
WebCore/page/FrameView.cpp
WebCore/page/FrameView.h
WebCore/page/mac/WebCoreFrameBridge.h
WebCore/page/mac/WebCoreFrameBridge.mm
WebKit/gtk/ChangeLog
WebKit/gtk/WebView/webkitwebview.cpp
WebKit/mac/ChangeLog
WebKit/mac/WebView/WebHTMLView.mm
WebKit/mac/WebView/WebHTMLViewInternal.h
WebKit/win/ChangeLog
WebKit/win/WebView.cpp

index c417949..c430817 100644 (file)
@@ -1,3 +1,12 @@
+2007-12-03  Dan Bernstein  <mitz@apple.com>
+
+        Reviewed by Dave Hyatt.
+
+        - test for <rdar://problem/5346452> Resize event doesn't fire on body element inside a frame
+
+        * fast/events/resize-subframe-expected.txt: Added.
+        * fast/events/resize-subframe.html: Added.
+
 2007-12-03  Darin Adler  <darin@apple.com>
 
         Reviewed by Geoff.
diff --git a/LayoutTests/fast/events/resize-subframe-expected.txt b/LayoutTests/fast/events/resize-subframe-expected.txt
new file mode 100644 (file)
index 0000000..9c70321
--- /dev/null
@@ -0,0 +1,2 @@
+ALERT: PASS
+
diff --git a/LayoutTests/fast/events/resize-subframe.html b/LayoutTests/fast/events/resize-subframe.html
new file mode 100644 (file)
index 0000000..57b4729
--- /dev/null
@@ -0,0 +1,26 @@
+<script>
+    function test()
+    {
+        if (window.layoutTestController)
+            layoutTestController.dumpAsText();
+
+        document.body.offsetTop;
+        document.getElementById("iframe").style.height = "100px";
+    }
+</script>
+<body onload="test()">
+    <iframe id="iframe" style="height: 200px;" src="data:text/html,
+        <head>
+            <script>
+                function resized()
+                {
+                    if (window.layoutTestController)
+                        alert('PASS');
+                    else
+                        document.body.appendChild(document.createTextNode('PASS'));
+                }
+            </script>
+        </head>
+        <body onresize='resized()'></body>
+    "></iframe>
+</body>
index 03fd8b1..e91e18f 100644 (file)
@@ -1,3 +1,34 @@
+2007-12-03  Dan Bernstein  <mitz@apple.com>
+
+        Reviewed by Dave Hyatt.
+
+        - fix <rdar://problem/5346452> Resize event doesn't fire on body element inside a frame
+
+        Test: fast/events/resize-subframe.html
+
+        * page/FrameView.cpp:
+        (WebCore::FrameViewPrivate::FrameViewPrivate): Added a timer used when
+        deferring tasks that need to be done after layout.
+        (WebCore::FrameViewPrivate::reset):
+        (WebCore::FrameView::~FrameView):
+        (WebCore::FrameView::layout): Moved the updating of widget positions,
+        loading plug-ins and sending events queued up during layout into
+        performPostLayoutTasks(). performPostLayoutTasks() is called after
+        layout unless the layout was triggered by a previous layout's post-
+        layout tasks. In the latter case, performPostLayoutTasks() is scheduled
+        to run later.
+        (WebCore::FrameView::performPostLayoutTasks): Performs work that needs
+        to be done after layout but which can result in arbitrary code
+        execution and therefore may re-invalidate the layout. This includes
+        updating widget positions, loading plug-ins, and dispatching layout-
+        related DOM events (scroll, overflow and resize).
+        (WebCore::FrameView::postLayoutTimerFired):
+        (WebCore::FrameView::dispatchScheduledEvents):
+        * page/FrameView.h:
+        * page/mac/WebCoreFrameBridge.h:
+        * page/mac/WebCoreFrameBridge.mm: Removed -sendResizeEvent since this
+        is handled by FrameView now.
+
 2007-12-03  Rob Buis  <buis@kde.org>
 
         Reviewed by Darin.
index c6849fd..381d432 100644 (file)
@@ -58,6 +58,7 @@ public:
         : m_slowRepaintObjectCount(0)
         , layoutTimer(view, &FrameView::layoutTimerFired)
         , layoutRoot(0)
+        , postLayoutTasksTimer(view, &FrameView::postLayoutTimerFired)
         , m_mediaType("screen")
         , m_enqueueEvents(0)
         , m_overflowStatusDirty(true)
@@ -84,9 +85,11 @@ public:
         midLayout = false;
         layoutCount = 0;
         nestedLayoutCount = 0;
+        postLayoutTasksTimer.stop();
         firstLayout = true;
         repaintRects.clear();
         m_wasScrolledByUser = false;
+        lastLayoutSize = IntSize();
     }
 
     bool doFullRepaint;
@@ -106,11 +109,13 @@ public:
     bool midLayout;
     int layoutCount;
     unsigned nestedLayoutCount;
+    Timer<FrameView> postLayoutTasksTimer;
 
     bool firstLayout;
     bool needToInitScrollbars;
     bool isTransparent;
     Color baseBackgroundColor;
+    IntSize lastLayoutSize;
 
     // Used by objects during layout to communicate repaints that need to take place only
     // after all layout has been completed.
@@ -141,6 +146,12 @@ FrameView::FrameView(Frame* frame)
 
 FrameView::~FrameView()
 {
+    if (d->postLayoutTasksTimer.isActive()) {
+        d->postLayoutTasksTimer.stop();
+        d->m_scheduledEvents.clear();
+        d->m_enqueueEvents = 0;
+    }
+
     resetScrollbars();
 
     ASSERT(m_refCount == 0);
@@ -329,6 +340,13 @@ void FrameView::layout(bool allowSubtree)
 
     d->layoutSchedulingEnabled = false;
 
+    if (!d->nestedLayoutCount && d->postLayoutTasksTimer.isActive()) {
+        // This is a new top-level layout. If there are any remaining tasks from the previous
+        // layout, finish them now.
+        d->postLayoutTasksTimer.stop();
+        performPostLayoutTasks();
+    }
+
     // Always ensure our style info is up-to-date.  This can happen in situations where
     // the layout beats any sort of style recalc update that needs to occur.
     if (document->hasChangedChild())
@@ -337,7 +355,7 @@ void FrameView::layout(bool allowSubtree)
     bool subtree = d->layoutRoot;
 
     // If there is only one ref to this view left, then its going to be destroyed as soon as we exit, 
-    // so there's no point to continuiing to layout
+    // so there's no point to continuing to layout
     if (protector->hasOneRef())
         return;
 
@@ -352,7 +370,7 @@ void FrameView::layout(bool allowSubtree)
 
     ScrollbarMode hMode = d->hmode;
     ScrollbarMode vMode = d->vmode;
-    
+
     if (!subtree) {
         RenderObject* rootRenderer = document->documentElement() ? document->documentElement()->renderer() : 0;
         if (document->isHTMLDocument()) {
@@ -395,6 +413,7 @@ void FrameView::layout(bool allowSubtree)
             if (d->firstLayout) {
                 d->firstLayout = false;
                 didFirstLayout = true;
+                d->lastLayoutSize = IntSize(width(), height());
                 
                 // Set the initial vMode to AlwaysOn if we're auto.
                 if (vMode == ScrollbarAuto)
@@ -423,8 +442,9 @@ void FrameView::layout(bool allowSubtree)
     }
     
     RenderLayer* layer = root->enclosingLayer();
-     
-    pauseScheduledEvents();
+
+    if (!d->postLayoutTasksTimer.isActive())
+        pauseScheduledEvents();
 
     if (subtree)
         root->view()->pushLayoutState(root);
@@ -437,7 +457,7 @@ void FrameView::layout(bool allowSubtree)
 
     m_frame->invalidateSelection();
    
-    d->layoutSchedulingEnabled=true;
+    d->layoutSchedulingEnabled = true;
 
     if (!subtree && !static_cast<RenderView*>(root)->printing())
         adjustViewSize();
@@ -445,10 +465,6 @@ void FrameView::layout(bool allowSubtree)
     // Now update the positions of all layers.
     layer->updateLayerPositions(d->doFullRepaint);
 
-    // We update our widget positions right after doing a layout.
-    if (!subtree)
-        static_cast<RenderView*>(root)->updateWidgetPositions();
-    
     // FIXME: Could optimize this and have objects removed from this list
     // if they ever do full repaints.
     Vector<RenderObject::RepaintInfo>::iterator end = d->repaintRects.end();
@@ -475,25 +491,20 @@ void FrameView::layout(bool allowSubtree)
         updateOverflowStatus(visibleWidth() < contentsWidth(),
                              visibleHeight() < contentsHeight());
 
-    if (m_widgetUpdateSet && d->nestedLayoutCount == 1) {
-        Vector<RenderPartObject*> objectVector;
-        copyToVector(*m_widgetUpdateSet, objectVector);
-        size_t size = objectVector.size();
-        for (size_t i = 0; i < size; ++i) {
-            RenderPartObject* object = objectVector[i];
-            object->updateWidget(false);
-
-            // updateWidget() can destroy the RenderPartObject, so we need to make sure it's
-            // alive by checking if it's still in m_widgetUpdateSet.
-            if (m_widgetUpdateSet->contains(object))
-                object->updateWidgetPosition();
+    if (!d->postLayoutTasksTimer.isActive()) {
+        // Calls resumeScheduledEvents()
+        performPostLayoutTasks();
+
+        if (needsLayout()) {
+            // Post-layout widget updates or an event handler made us need layout again.
+            // Lay out again, but this time defer widget updates and event dispatch until after
+            // we return.
+            d->postLayoutTasksTimer.startOneShot(0);
+            pauseScheduledEvents();
+            layout();
         }
-        m_widgetUpdateSet->clear();
     }
 
-    // Allow events scheduled during layout to fire
-    resumeScheduledEvents();
-
     d->nestedLayoutCount--;
 }
 
@@ -846,6 +857,43 @@ void FrameView::resumeScheduledEvents()
     ASSERT(d->m_scheduledEvents.isEmpty() || d->m_enqueueEvents);
 }
 
+void FrameView::performPostLayoutTasks()
+{
+    RenderView* root = static_cast<RenderView*>(m_frame->document()->renderer());
+
+    root->updateWidgetPositions();
+    if (m_widgetUpdateSet && d->nestedLayoutCount <= 1) {
+        Vector<RenderPartObject*> objectVector;
+        copyToVector(*m_widgetUpdateSet, objectVector);
+        size_t size = objectVector.size();
+        for (size_t i = 0; i < size; ++i) {
+            RenderPartObject* object = objectVector[i];
+            object->updateWidget(false);
+
+            // updateWidget() can destroy the RenderPartObject, so we need to make sure it's
+            // alive by checking if it's still in m_widgetUpdateSet.
+            if (m_widgetUpdateSet->contains(object))
+                object->updateWidgetPosition();
+        }
+        m_widgetUpdateSet->clear();
+    }
+
+    resumeScheduledEvents();
+
+    if (!root->printing()) {
+        IntSize currentSize = IntSize(width(), height());
+        bool resized = !d->firstLayout && currentSize != d->lastLayoutSize;
+        d->lastLayoutSize = currentSize;
+        if (resized)
+            m_frame->sendResizeEvent();
+    }
+}
+
+void FrameView::postLayoutTimerFired(Timer<FrameView>*)
+{
+    performPostLayoutTasks();
+}
+
 void FrameView::updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow)
 {
     if (!d->m_viewportRenderer)
@@ -876,7 +924,7 @@ void FrameView::dispatchScheduledEvents()
 {
     if (d->m_scheduledEvents.isEmpty())
         return;
-    
+
     Vector<ScheduledEvent*> scheduledEventsCopy = d->m_scheduledEvents;
     d->m_scheduledEvents.clear();
     
@@ -892,7 +940,7 @@ void FrameView::dispatchScheduledEvents()
                 ec, scheduledEvent->m_tempEvent);
         
         delete scheduledEvent;
-    }    
+    }
 }
 
 IntRect FrameView::windowClipRect() const
index e794c3d..ddc328b 100644 (file)
@@ -123,6 +123,7 @@ public:
     void scheduleEvent(PassRefPtr<Event>, PassRefPtr<EventTargetNode>, bool tempEvent);
     void pauseScheduledEvents();
     void resumeScheduledEvents();
+    void postLayoutTimerFired(Timer<FrameView>*);
 
     bool wasScrolledByUser() const;
     void setWasScrolledByUser(bool);
@@ -150,6 +151,7 @@ private:
     void updateOverflowStatus(bool horizontalOverflow, bool verticalOverflow);
 
     void dispatchScheduledEvents();
+    void performPostLayoutTasks();
 
     unsigned m_refCount;
     IntSize m_size;
index 6251bab..fcade9d 100644 (file)
@@ -118,7 +118,6 @@ enum WebScrollGranularity {
 - (void)reapplyStylesForDeviceType:(WebCoreDeviceType)deviceType;
 - (void)forceLayoutAdjustingViewSize:(BOOL)adjustSizeFlag;
 - (void)forceLayoutWithMinimumPageWidth:(float)minPageWidth maximumPageWidth:(float)maxPageWidth adjustingViewSize:(BOOL)adjustSizeFlag;
-- (void)sendResizeEvent;
 - (void)sendScrollEvent;
 - (BOOL)needsLayout;
 - (void)setNeedsLayout;
index 010a6fd..b0fc5e8 100644 (file)
@@ -409,11 +409,6 @@ static inline WebCoreFrameBridge *bridge(Frame *frame)
     m_frame->forceLayoutWithPageWidthRange(minPageWidth, maxPageWidth, flag);
 }
 
-- (void)sendResizeEvent
-{
-    m_frame->sendResizeEvent();
-}
-
 - (void)sendScrollEvent
 {
     m_frame->sendScrollEvent();
index 22ef2d4..6e7d83b 100644 (file)
@@ -1,3 +1,12 @@
+2007-12-03  Dan Bernstein  <mitz@apple.com>
+
+        Reviewed by Dave Hyatt.
+
+        - fix <rdar://problem/5346452> Resize event doesn't fire on body element inside a frame
+
+        * WebView/webkitwebview.cpp: Remove the call to sendResizeEvent() since
+        FrameView sends it now.
+
 2007-12-03  Alp Toker  <alp@atoker.com>
 
         globalObject() GTK+ build fix.
index 9a957e1..f3b1274 100644 (file)
@@ -168,7 +168,6 @@ static void webkit_web_view_size_allocate(GtkWidget* widget, GtkAllocation* allo
     frame->view()->resize(allocation->width, allocation->height);
     frame->forceLayout();
     frame->view()->adjustViewSize();
-    frame->sendResizeEvent();
 }
 
 static void webkit_web_view_realize(GtkWidget* widget)
index ca0b5ce..52208ed 100644 (file)
@@ -1,3 +1,15 @@
+2007-12-03  Dan Bernstein  <mitz@apple.com>
+
+        Reviewed by Dave Hyatt.
+
+        - fix <rdar://problem/5346452> Resize event doesn't fire on body element inside a frame
+
+        * WebView/WebHTMLView.mm:
+        (-[WebHTMLView layoutToMinimumPageWidth:maximumPageWidth:adjustingViewSize:]): Removed the code
+        that checked if the view had resized and sent the resize event, since
+        FrameView sends resize events now.
+        * WebView/WebHTMLViewInternal.h:
+
 2007-12-03  Timothy Hatcher  <timothy@apple.com>
 
         Reviewed by Darin.
index b4277dd..8cad0c7 100644 (file)
@@ -2726,20 +2726,8 @@ static void _updateActiveStateTimerCallback(CFRunLoopTimerRef timer, void *info)
     }
     _private->needsLayout = NO;
     
-    if (!_private->printing) {
-        // get size of the containing dynamic scrollview, so
-        // appearance and disappearance of scrollbars will not show up
-        // as a size change
-        NSSize newLayoutFrameSize = [[[self superview] superview] frame].size;
-        if (_private->laidOutAtLeastOnce && !NSEqualSizes(_private->lastLayoutFrameSize, newLayoutFrameSize)) {
-            [[self _bridge] sendResizeEvent];
-            if ([[self _bridge] needsLayout])
-                [[self _bridge] forceLayoutAdjustingViewSize:NO];
-        }
-        _private->laidOutAtLeastOnce = YES;
+    if (!_private->printing)
         _private->lastLayoutSize = [(NSClipView *)[self superview] documentVisibleRect].size;
-        _private->lastLayoutFrameSize = newLayoutFrameSize;
-    }
 
 #ifdef _KWQ_TIMING        
     double thisTime = CFAbsoluteTimeGetCurrent() - start;
index 369931b..443e4b7 100644 (file)
@@ -59,8 +59,6 @@ struct WebHTMLViewInterpretKeyEventsParameters;
     NSEvent *keyDownEvent; // Kept after handling the event.
     
     NSSize lastLayoutSize;
-    NSSize lastLayoutFrameSize;
-    BOOL laidOutAtLeastOnce;
     
     NSPoint lastScrollPosition;
 
index fad346d..72e743f 100644 (file)
@@ -1,3 +1,13 @@
+2007-12-03  Dan Bernstein  <mitz@apple.com>
+
+        Reviewed by Dave Hyatt.
+
+        - fix <rdar://problem/5346452> Resize event doesn't fire on body element inside a frame
+
+        * WebView.cpp:
+        (WebViewWndProc): Removed call to sendResizeEvent() since FrameView
+        sends them now.
+
 2007-12-03  Kevin McCullough  <kmccullough@apple.com>
 
         Reviewed by Adam.
index 941677d..9e0c6d2 100644 (file)
@@ -1582,12 +1582,8 @@ static LRESULT CALLBACK WebViewWndProc(HWND hWnd, UINT message, WPARAM wParam, L
 
             if (lParam != 0) {
                 webView->deleteBackingStore();
-                if (Frame* coreFrame = core(mainFrameImpl)) {
+                if (Frame* coreFrame = core(mainFrameImpl))
                     coreFrame->view()->resize(LOWORD(lParam), HIWORD(lParam));
-
-                    if (!coreFrame->loader()->isLoading())
-                        coreFrame->sendResizeEvent();
-                }
             }
             break;
         case WM_SHOWWINDOW: