2010-11-01 MORITA Hajime <morrita@google.com>
authormorrita@google.com <morrita@google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 19 Nov 2010 06:25:28 +0000 (06:25 +0000)
committermorrita@google.com <morrita@google.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 19 Nov 2010 06:25:28 +0000 (06:25 +0000)
        Reviewed by David Hyatt.

        Navigating dark background websites results in blinding white flashes between pages.
        https://bugs.webkit.org/show_bug.cgi?id=45640

        This FOUC is caused by an early layout request before the <body> is ready,
        and the page's background style given for <body>, instead of <html>.
        So many sites have such stylesheets that we should care them.

        - Some DOM operation such as 'element.offsetLeft' causes page layout.
        - The page layout results page repaint
        - The page page repaint makes a white screen. because there is nothing to paint
          before <body> is available.

        This change:
        - extracted existing FOUC check on RenderBlock and RenderLayer to
          Document::mayCauseFlashOfUnstyledContent(),
        - checked non-<head> element availability on mayCauseFlashOfUnstyledContent(), and
        - added FOUC guards before requesting reapint on FrameView.

        Note that non-<head> document root children are typically <body>, but possibly
        some other type of elements in the case of non-HTML documents.

        No new tests. The data loading speed matters and it cannot be
        captured by DRT.

        * dom/Document.cpp:
        (hasHeadSibling): Added.
        (WebCore::Document::mayCauseFlashOfUnstyledContent): Added.
        * dom/Document.h:
        * page/FrameView.cpp:
        (WebCore::FrameView::invalidateRect): Added a guard.
        (WebCore::FrameView::repaintContentRectangle): Added a guard.
        (WebCore::FrameView::doDeferredRepaints): Added a guard.
        (WebCore::FrameView::shouldUpdate): Added.
        * page/FrameView.h:
        * rendering/RenderBlock.cpp:
        (WebCore::RenderBlock::paintContents): Replaced FOUC check to use mayCauseFlashOfUnstyledContent
        * rendering/RenderLayer.cpp:
        (WebCore::RenderLayer::paintLayer): Replaced FOUC check to use mayCauseFlashOfUnstyledContent

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

WebCore/ChangeLog
WebCore/dom/Document.cpp
WebCore/dom/Document.h
WebCore/page/FrameView.cpp
WebCore/page/FrameView.h
WebCore/rendering/RenderBlock.cpp
WebCore/rendering/RenderLayer.cpp

index 125e756..9aef4ce 100644 (file)
@@ -1,3 +1,46 @@
+2010-11-01  MORITA Hajime  <morrita@google.com>
+
+        Reviewed by David Hyatt.
+
+        Navigating dark background websites results in blinding white flashes between pages. 
+        https://bugs.webkit.org/show_bug.cgi?id=45640
+
+        This FOUC is caused by an early layout request before the <body> is ready, 
+        and the page's background style given for <body>, instead of <html>.
+        So many sites have such stylesheets that we should care them.
+        
+        - Some DOM operation such as 'element.offsetLeft' causes page layout.
+        - The page layout results page repaint
+        - The page page repaint makes a white screen. because there is nothing to paint
+          before <body> is available.
+        
+        This change:
+        - extracted existing FOUC check on RenderBlock and RenderLayer to 
+          Document::mayCauseFlashOfUnstyledContent(),
+        - checked non-<head> element availability on mayCauseFlashOfUnstyledContent(), and
+        - added FOUC guards before requesting reapint on FrameView.
+        
+        Note that non-<head> document root children are typically <body>, but possibly
+        some other type of elements in the case of non-HTML documents.
+        
+        No new tests. The data loading speed matters and it cannot be
+        captured by DRT.
+
+        * dom/Document.cpp:
+        (hasHeadSibling): Added.
+        (WebCore::Document::mayCauseFlashOfUnstyledContent): Added.
+        * dom/Document.h:
+        * page/FrameView.cpp:
+        (WebCore::FrameView::invalidateRect): Added a guard.
+        (WebCore::FrameView::repaintContentRectangle): Added a guard.
+        (WebCore::FrameView::doDeferredRepaints): Added a guard.
+        (WebCore::FrameView::shouldUpdate): Added.
+        * page/FrameView.h:
+        * rendering/RenderBlock.cpp:
+        (WebCore::RenderBlock::paintContents): Replaced FOUC check to use mayCauseFlashOfUnstyledContent
+        * rendering/RenderLayer.cpp:
+        (WebCore::RenderLayer::paintLayer): Replaced FOUC check to use mayCauseFlashOfUnstyledContent
+
 2010-11-18  Kent Tamura  <tkent@chromium.org>
 
         Reviewed by Tony Chang.
index 9ad956f..40f078f 100644 (file)
@@ -4868,4 +4868,34 @@ PassRefPtr<TouchList> Document::createTouchList(ExceptionCode&) const
 }
 #endif
 
+static bool hasHeadSibling(const Document* document)
+{
+    Node* de = document->documentElement();
+    if (!de)
+        return false;
+
+    for (Node* i = de->firstChild(); i; i = i->nextSibling()) {
+        // A child of the document element which is rather than <head> is
+        // typically visible and FOUC safe. So we return true here.
+        if (!i->hasTagName(headTag))
+            return true;
+    }
+
+    return false;
+}
+
+bool Document::mayCauseFlashOfUnstyledContent() const
+{
+    // Some kind of FOUC is caused by a repaint request before page's <body> arrival
+    // because page authors often give background styles to <body>, not to <html>.
+    // (And these styles are unavailable before <style> or <link> is given.)
+    // This functions is used for checking such possibility of FOUCs.
+    // Note that the implementation considers only empty or <head> only contents as a FOUC cause
+    // rather than missing <body>, because non-HTML document like SVG and arbitrary XML from foreign namespace 
+    // should be painted even if there is no <body>.
+    if (didLayoutWithPendingStylesheets())
+        return true;
+    return !hasHeadSibling(this);
+}
+
 } // namespace WebCore
index 83445e0..1e89820 100644 (file)
@@ -1055,6 +1055,8 @@ public:
 
     const DocumentTiming* timing() const { return &m_documentTiming; }
 
+    bool mayCauseFlashOfUnstyledContent() const;
+
 protected:
     Document(Frame*, const KURL& url, bool isXHTML, bool isHTML, const KURL& baseURL = KURL());
 
index fe0be6a..13cbefb 100644 (file)
@@ -303,7 +303,7 @@ bool FrameView::didFirstLayout() const
 void FrameView::invalidateRect(const IntRect& rect)
 {
     if (!parent()) {
-        if (hostWindow())
+        if (hostWindow() && shouldUpdate())
             hostWindow()->invalidateContentsAndWindow(rect, false /*immediate*/);
         return;
     }
@@ -1322,7 +1322,7 @@ void FrameView::repaintContentRectangle(const IntRect& r, bool immediate)
         return;
     }
     
-    if (!immediate && isOffscreen() && !shouldUpdateWhileOffscreen())
+    if (!shouldUpdate(immediate))
         return;
 
 #if ENABLE(TILED_BACKING_STORE)
@@ -1396,7 +1396,7 @@ void FrameView::checkStopDelayingDeferredRepaints()
 void FrameView::doDeferredRepaints()
 {
     ASSERT(!m_deferringRepaints);
-    if (isOffscreen() && !shouldUpdateWhileOffscreen()) {
+    if (!shouldUpdate()) {
         m_repaintRects.clear();
         m_repaintCount = 0;
         return;
@@ -1635,6 +1635,15 @@ void FrameView::setShouldUpdateWhileOffscreen(bool shouldUpdateWhileOffscreen)
     m_shouldUpdateWhileOffscreen = shouldUpdateWhileOffscreen;
 }
 
+bool FrameView::shouldUpdate(bool immediateRequested) const
+{
+    if (!immediateRequested && isOffscreen() && !shouldUpdateWhileOffscreen())
+        return false;
+    if (!m_frame || !m_frame->document() || m_frame->document()->mayCauseFlashOfUnstyledContent())
+        return false;
+    return true;
+}
+
 void FrameView::scheduleEvent(PassRefPtr<Event> event, PassRefPtr<Node> eventTarget)
 {
     if (!m_enqueueEvents) {
index 8a1a071..bde1b79 100644 (file)
@@ -137,6 +137,7 @@ public:
 
     bool shouldUpdateWhileOffscreen() const;
     void setShouldUpdateWhileOffscreen(bool);
+    bool shouldUpdate(bool = false) const;
 
     void adjustViewSize();
     
index cc40465..d3ea2e0 100644 (file)
@@ -2216,7 +2216,7 @@ void RenderBlock::paintContents(PaintInfo& paintInfo, int tx, int ty)
     // Avoid painting descendants of the root element when stylesheets haven't loaded.  This eliminates FOUC.
     // It's ok not to draw, because later on, when all the stylesheets do load, updateStyleSelector on the Document
     // will do a full repaint().
-    if (document()->didLayoutWithPendingStylesheets() && !isRenderView())
+    if (document()->mayCauseFlashOfUnstyledContent() && !isRenderView())
         return;
 
     if (childrenInline())
index 7b9000c..5af951c 100644 (file)
@@ -2356,7 +2356,7 @@ void RenderLayer::paintLayer(RenderLayer* rootLayer, GraphicsContext* p,
     // Avoid painting layers when stylesheets haven't loaded.  This eliminates FOUC.
     // It's ok not to draw, because later on, when all the stylesheets do load, updateStyleSelector on the Document
     // will do a full repaint().
-    if (renderer()->document()->didLayoutWithPendingStylesheets() && !renderer()->isRenderView() && !renderer()->isRoot())
+    if (renderer()->document()->mayCauseFlashOfUnstyledContent() && !renderer()->isRenderView() && !renderer()->isRoot())
         return;
     
     // If this layer is totally invisible then there is nothing to paint.