2011-06-01 Jer Noble <jer.noble@apple.com>
authorjer.noble@apple.com <jer.noble@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 3 Jun 2011 18:48:15 +0000 (18:48 +0000)
committerjer.noble@apple.com <jer.noble@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 3 Jun 2011 18:48:15 +0000 (18:48 +0000)
        Reviewed by Simon Fraser.

        Flash of broken page when exiting full screen at jerryseinfeld.com
        https://bugs.webkit.org/show_bug.cgi?id=61897
        <rdar://problem/9522985>

        * fullscreen/full-screen-placeholder-expected.txt: Added.
        * fullscreen/full-screen-placeholder.html: Added.
2011-06-01  Jer Noble  <jer.noble@apple.com>

        Reviewed by Simon Fraser.

        Flash of broken page when exiting full screen at jerryseinfeld.com
        https://bugs.webkit.org/show_bug.cgi?id=61897
        <rdar://problem/9522985>

        Test: fullscreen/full-screen-placeholder.html

        Entering full-screen mode is causing the page layout to change because the full-screen
        element is taken out of the normal flow.  To counteract this effect, insert a placeholder
        block as a parent of the full-screen renderer with the same size and style as the full-screen
        element pre-full-screen.

        Only create a placeholder for block-level elements; the technique required for inline elements
        would be vastly more complicated.

        * dom/Document.cpp:
        (WebCore::Document::webkitWillEnterFullScreenForElement): Create a placeholder
            based on the size and style of the full-screen element.
        (WebCore::Document::setFullScreenRenderer): Persist the placeholder size and
            style across new renderers.
        * rendering/RenderFullScreen.cpp:
        (RenderFullScreen::RenderFullScreen): Added ivar.
        (RenderFullScreen::destroy): Make sure to safely destroy our placeholder.
        (RenderFullScreen::createPlaceholder): Added.
        * rendering/RenderFullScreen.h:
        (WebCore::RenderFullScreen::placeholder): Ivar accessor.

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

LayoutTests/ChangeLog
LayoutTests/fullscreen/full-screen-placeholder-expected.txt [new file with mode: 0644]
LayoutTests/fullscreen/full-screen-placeholder.html [new file with mode: 0644]
Source/WebCore/ChangeLog
Source/WebCore/dom/Document.cpp
Source/WebCore/dom/Document.h
Source/WebCore/dom/NodeRenderingContext.cpp
Source/WebCore/rendering/RenderFullScreen.cpp
Source/WebCore/rendering/RenderFullScreen.h

index 87d84c4..9cedf9d 100644 (file)
@@ -1,3 +1,14 @@
+2011-06-01  Jer Noble  <jer.noble@apple.com>
+
+        Reviewed by Simon Fraser.
+
+        Flash of broken page when exiting full screen at jerryseinfeld.com
+        https://bugs.webkit.org/show_bug.cgi?id=61897
+        <rdar://problem/9522985>
+
+        * fullscreen/full-screen-placeholder-expected.txt: Added.
+        * fullscreen/full-screen-placeholder.html: Added.
+
 2011-06-03  Robert Kroeger  <rjkroege@chromium.org>
 
         Reviewed by Adam Barth.
diff --git a/LayoutTests/fullscreen/full-screen-placeholder-expected.txt b/LayoutTests/fullscreen/full-screen-placeholder-expected.txt
new file mode 100644 (file)
index 0000000..2243077
--- /dev/null
@@ -0,0 +1,17 @@
+This layout test checks that the offset positions of the blue and green divs does not change when the red div enters full-screen mode. Press go full-screen to begin.
+One
+Two
+EVENT(webkitfullscreenchange)
+EXPECTED (document.webkitCurrentFullScreenElement == '[object HTMLDivElement]') OK
+EXPECTED (one.offsetLeft == '68') OK
+EXPECTED (one.offsetTop == '48') OK
+EXPECTED (two.offsetLeft == '8') OK
+EXPECTED (two.offsetTop == '108') OK
+EVENT(webkitfullscreenchange)
+EXPECTED (document.webkitCurrentFullScreenElement == 'null') OK
+EXPECTED (one.offsetLeft == '68') OK
+EXPECTED (one.offsetTop == '48') OK
+EXPECTED (two.offsetLeft == '8') OK
+EXPECTED (two.offsetTop == '108') OK
+END OF TEST
+
diff --git a/LayoutTests/fullscreen/full-screen-placeholder.html b/LayoutTests/fullscreen/full-screen-placeholder.html
new file mode 100644 (file)
index 0000000..60a1c5f
--- /dev/null
@@ -0,0 +1,73 @@
+<script src="full-screen-test.js"></script>
+<style>
+#float { 
+    margin: 10px 0 0 10px;
+    height: 50px;
+    width: 50px;
+    float: left;
+    background-color: red;
+}
+#clear {
+    clear:left;
+}
+#one { 
+    background-color: lightblue; 
+    float: left;
+}
+#two { 
+    background-color: lightgreen;
+}
+</style>
+<body>
+<div>This layout test checks that the offset positions of the blue and green divs does not change when the red div enters full-screen mode.  Press <button onclick="document.getElementById('float').webkitRequestFullScreen()">go full-screen</a> to begin.</div>
+<div id="float"></div>
+<div id="one">One</div>
+<div id="clear" />
+<span id="two">Two</span>
+<script>
+    var one = document.getElementById('one');
+    var two = document.getElementById('two');
+
+    // Bail out early if the full screen API is not enabled or is missing:
+    if (Element.prototype.webkitRequestFullScreen == undefined) {
+        logResult(false, "Element.prototype.webkitRequestFullScreen == undefined");
+        endTest();
+    } else {
+        var oneState = {'offsetLeft': one.offsetLeft, 'offsetTop': one.offsetTop };
+        var twoState = {'offsetLeft': two.offsetLeft, 'offsetTop': two.offsetTop };
+
+
+        var callback;
+        var fullscreenChanged = function(event)
+        {
+            if (callback)
+                callback(event)
+        };
+        waitForEvent(document, 'webkitfullscreenchange', fullscreenChanged);
+    
+        var div = document.getElementById('float');
+
+        var divEnteredFullScreen = function() {
+            testExpected("document.webkitCurrentFullScreenElement", div);
+            testExpected("one.offsetLeft", oneState.offsetLeft);
+            testExpected("one.offsetTop", oneState.offsetTop);
+            testExpected("two.offsetLeft", twoState.offsetLeft);
+            testExpected("two.offsetTop", twoState.offsetTop);
+            callback = cancelledFullScreen;
+            runWithKeyDown(function(){document.webkitCancelFullScreen()});
+        };
+    
+        var cancelledFullScreen = function() {
+            testExpected("document.webkitCurrentFullScreenElement", null);
+            testExpected("one.offsetLeft", oneState.offsetLeft);
+            testExpected("one.offsetTop", oneState.offsetTop);
+            testExpected("two.offsetLeft", twoState.offsetLeft);
+            testExpected("two.offsetTop", twoState.offsetTop);
+            callback = null;
+            endTest();
+        };
+
+        callback = divEnteredFullScreen;
+        runWithKeyDown(function(){div.webkitRequestFullScreen()});
+    }
+</script>
index bfe39e0..839b7ba 100644 (file)
@@ -1,3 +1,33 @@
+2011-06-01  Jer Noble  <jer.noble@apple.com>
+
+        Reviewed by Simon Fraser.
+
+        Flash of broken page when exiting full screen at jerryseinfeld.com
+        https://bugs.webkit.org/show_bug.cgi?id=61897
+        <rdar://problem/9522985>
+
+        Test: fullscreen/full-screen-placeholder.html
+
+        Entering full-screen mode is causing the page layout to change because the full-screen
+        element is taken out of the normal flow.  To counteract this effect, insert a placeholder
+        block as a parent of the full-screen renderer with the same size and style as the full-screen
+        element pre-full-screen.
+
+        Only create a placeholder for block-level elements; the technique required for inline elements
+        would be vastly more complicated.
+
+        * dom/Document.cpp:
+        (WebCore::Document::webkitWillEnterFullScreenForElement): Create a placeholder
+            based on the size and style of the full-screen element.
+        (WebCore::Document::setFullScreenRenderer): Persist the placeholder size and 
+            style across new renderers.
+        * rendering/RenderFullScreen.cpp:
+        (RenderFullScreen::RenderFullScreen): Added ivar.
+        (RenderFullScreen::destroy): Make sure to safely destroy our placeholder.
+        (RenderFullScreen::createPlaceholder): Added.
+        * rendering/RenderFullScreen.h:
+        (WebCore::RenderFullScreen::placeholder): Ivar accessor.
+
 2011-06-03  Levi Weintraub  <leviw@chromium.org>
 
         Reviewed by Eric Seidel.
index 1c7d6dc..58d1c99 100644 (file)
@@ -4784,7 +4784,18 @@ void Document::webkitWillEnterFullScreenForElement(Element* element)
     ASSERT(page() && page()->settings()->fullScreenEnabled());
 
     m_fullScreenElement = element;
-    
+
+    // Create a placeholder block for a the full-screen element, to keep the page from reflowing
+    // when the element is removed from the normal flow.  Only do this for a RenderBox, as only 
+    // a box will have a frameRect.  The placeholder will be created in setFullScreenRenderer()
+    // during layout.
+    RenderObject* renderer = m_fullScreenElement->renderer();
+    bool shouldCreatePlaceholder = m_fullScreenElement->renderer()->isBox();
+    if (shouldCreatePlaceholder) {
+        m_savedPlaceholderFrameRect = toRenderBox(renderer)->frameRect();
+        m_savedPlaceholderRenderStyle = RenderStyle::clone(renderer->style());
+    }
+
     if (m_fullScreenElement != documentElement())
         m_fullScreenElement->detach();
 
@@ -4861,6 +4872,13 @@ void Document::setFullScreenRenderer(RenderFullScreen* renderer)
     if (renderer == m_fullScreenRenderer)
         return;
 
+    if (renderer && m_savedPlaceholderRenderStyle) 
+        renderer->createPlaceholder(m_savedPlaceholderRenderStyle.release(), m_savedPlaceholderFrameRect);
+    else if (renderer && m_fullScreenRenderer && m_fullScreenRenderer->placeholder()) {
+        RenderBlock* placeholder = m_fullScreenRenderer->placeholder();
+        renderer->createPlaceholder(RenderStyle::clone(placeholder->style()), placeholder->frameRect());
+    }
+
     if (m_fullScreenRenderer)
         m_fullScreenRenderer->destroy();
     ASSERT(!m_fullScreenRenderer);
index 0e51479..927b465 100644 (file)
@@ -34,6 +34,7 @@
 #include "DOMTimeStamp.h"
 #include "DocumentTiming.h"
 #include "IconURL.h"
+#include "IntRect.h"
 #include "PageVisibilityState.h"
 #include "QualifiedName.h"
 #include "ScriptExecutionContext.h"
@@ -1371,6 +1372,8 @@ private:
     Timer<Document> m_fullScreenChangeDelayTimer;
     Deque<RefPtr<Element> > m_fullScreenChangeEventTargetQueue;
     bool m_isAnimatingFullScreen;
+    IntRect m_savedPlaceholderFrameRect;
+    RefPtr<RenderStyle> m_savedPlaceholderRenderStyle;
 #endif
 
     int m_loadEventDelayCount;
index 85aa751..693fe52 100644 (file)
@@ -228,7 +228,7 @@ RenderObject* NodeRendererFactory::createRendererAndStyle()
 }
 
 #if ENABLE(FULLSCREEN_API)
-static RenderFullScreen* wrapWithRenderFullScreen(RenderObject* object, Document* document)
+static RenderObject* wrapWithRenderFullScreen(RenderObject* object, Document* document)
 {
     RenderFullScreen* fullscreenRenderer = new (document->renderArena()) RenderFullScreen(document);
     fullscreenRenderer->setStyle(RenderFullScreen::createFullScreenStyle());
@@ -237,6 +237,8 @@ static RenderFullScreen* wrapWithRenderFullScreen(RenderObject* object, Document
     if (object)
         fullscreenRenderer->addChild(object);
     document->setFullScreenRenderer(fullscreenRenderer);
+    if (fullscreenRenderer->placeholder())
+        return fullscreenRenderer->placeholder();
     return fullscreenRenderer;
 }
 #endif
index 9688ba0..0e8c821 100644 (file)
 
 using namespace WebCore;
 
+RenderFullScreen::RenderFullScreen(Node* node) 
+    : RenderFlexibleBox(node) 
+    , m_placeholder(0)
+{ 
+    setReplaced(false); 
+}
+
 void RenderFullScreen::destroy()
 {
+    if (m_placeholder) {
+        remove();
+        if (!m_placeholder->beingDestroyed())
+            m_placeholder->destroy();
+        m_placeholder = 0;
+    }
+
     // RenderObjects are unretained, so notify the document (which holds a pointer to a RenderFullScreen)
     // if it's RenderFullScreen is destroyed.
     if (document() && document()->fullScreenRenderer() == this)
@@ -72,4 +86,24 @@ PassRefPtr<RenderStyle> RenderFullScreen::createFullScreenStyle()
     return fullscreenStyle.release();
 }
 
+void RenderFullScreen::createPlaceholder(PassRefPtr<RenderStyle> style, const IntRect& frameRect)
+{
+    if (style->width().isAuto())
+        style->setWidth(Length(frameRect.width(), Fixed));
+    if (style->height().isAuto())
+        style->setHeight(Length(frameRect.height(), Fixed));
+
+    if (!m_placeholder) {
+        m_placeholder = new (document()->renderArena()) RenderBlock(document());
+        m_placeholder->setStyle(style);
+        m_placeholder->setIsAnonymous(false);
+        if (parent()) {
+            parent()->addChild(m_placeholder, this);
+            remove();
+        }
+        m_placeholder->addChild(this);
+    } else
+        m_placeholder->setStyle(style);
+}
+
 #endif
index 9ba17a7..0a8718c 100644 (file)
@@ -33,15 +33,18 @@ namespace WebCore {
 
 class RenderFullScreen : public RenderFlexibleBox {
 public:
-    RenderFullScreen(Node* node) : RenderFlexibleBox(node) { setReplaced(false); }
+    RenderFullScreen(Node*);
     virtual void destroy();
     virtual bool isRenderFullScreen() const { return true; }
     virtual const char* renderName() const { return "RenderFullScreen"; }
-    
+
+    RenderBlock* placeholder() { return m_placeholder; }
+    void createPlaceholder(PassRefPtr<RenderStyle>, const IntRect& frameRect);
+
     static PassRefPtr<RenderStyle> createFullScreenStyle();
     
 protected:
-    bool m_isAnimating;
+    RenderBlock* m_placeholder;
 };
     
 inline RenderFullScreen* toRenderFullScreen(RenderObject* object)