Bug 631682. Make sure to start background image loads for the root element when we compute its style and decide to construct a frame. r+a=dbaron
authorBoris Zbarsky <bzbarsky@mit.edu>
Fri, 04 Feb 2011 22:43:13 -0500
changeset 62083 16cc18d74a8c43eb530479a72b2a3de028df81e4
parent 62082 a02c6f4ffe4a0d3e14e14228f128f885c6acb91a
child 62084 71eb12acc8d3c63fded73c6dbd82e96c2a7a6e22
push idunknown
push userunknown
push dateunknown
bugs631682
milestone2.0b12pre
Bug 631682. Make sure to start background image loads for the root element when we compute its style and decide to construct a frame. r+a=dbaron
layout/base/nsCSSFrameConstructor.cpp
layout/reftests/backgrounds/delay-image-response.sjs
layout/reftests/backgrounds/reftest.list
layout/reftests/backgrounds/root-background-1.html
layout/reftests/backgrounds/root-background-ref.html
layout/style/nsStyleContext.h
--- a/layout/base/nsCSSFrameConstructor.cpp
+++ b/layout/base/nsCSSFrameConstructor.cpp
@@ -2360,16 +2360,19 @@ nsCSSFrameConstructor::ConstructDocEleme
                "Scrollbars should have been propagated to the viewport");
 #endif
 
   if (NS_UNLIKELY(display->mDisplay == NS_STYLE_DISPLAY_NONE)) {
     state.mFrameManager->SetUndisplayedContent(aDocElement, styleContext);
     return NS_OK;
   }
 
+  // Make sure to start any background image loads for the root element now.
+  styleContext->StartBackgroundImageLoads();
+
   nsFrameConstructorSaveState absoluteSaveState;
   if (mHasRootAbsPosContainingBlock) {
     // Push the absolute containing block now so we can absolutely position
     // the root element
     state.PushAbsoluteContainingBlock(mDocElementContainingBlock,
                                       absoluteSaveState);
   }
 
@@ -5455,21 +5458,19 @@ nsCSSFrameConstructor::ConstructFramesFr
         item.IsWhitespace(aState))
       return NS_OK;
 
     return ConstructTextFrame(item.mFCData, aState, item.mContent,
                               adjParentFrame, styleContext,
                               aFrameItems);
   }
 
-  // Start background loads during frame construction. This is just
-  // a hint; the paint code will do the right thing in any case.
-  {
-    styleContext->GetStyleBackground();
-  }
+  // Start background loads during frame construction so that we're
+  // guaranteed that they will be started before onload fires.
+  styleContext->StartBackgroundImageLoads();
 
   nsFrameState savedStateBits = aState.mAdditionalStateBits;
   if (item.mIsGeneratedContent) {
     // Ensure that frames created here are all tagged with
     // NS_FRAME_GENERATED_CONTENT.
     aState.mAdditionalStateBits |= NS_FRAME_GENERATED_CONTENT;
 
     // Note that we're not necessarily setting this property on the primary
new file mode 100644
--- /dev/null
+++ b/layout/reftests/backgrounds/delay-image-response.sjs
@@ -0,0 +1,55 @@
+const BinaryOutputStream = Components.Constructor("@mozilla.org/binaryoutputstream;1", "nsIBinaryOutputStream", "setOutputStream");
+/* This data is picked from modules/libpr0n/test/reftest/generic/check-header.sjs */
+const IMAGE_DATA =
+  [
+   0x89,  0x50,  0x4E,  0x47,  0x0D,  0x0A,  0x1A,  0x0A,  0x00,  0x00,  0x00,
+   0x0D,  0x49,  0x48,  0x44,  0x52,  0x00,  0x00,  0x00,  0x64,  0x00,  0x00,
+   0x00,  0x64,  0x08,  0x02,  0x00,  0x00,  0x00,  0xFF,  0x80,  0x02,  0x03,
+   0x00,  0x00,  0x00,  0x01,  0x73,  0x52,  0x47,  0x42,  0x00,  0xAE,  0xCE,
+   0x1C,  0xE9,  0x00,  0x00,  0x00,  0x9E,  0x49,  0x44,  0x41,  0x54,  0x78,
+   0xDA,  0xED,  0xD0,  0x31,  0x01,  0x00,  0x00,  0x08,  0x03,  0xA0,  0x69,
+   0xFF,  0xCE,  0x5A,  0xC1,  0xCF,  0x07,  0x22,  0x50,  0x99,  0x70,  0xD4,
+   0x0A,  0x64,  0xC9,  0x92,  0x25,  0x4B,  0x96,  0x2C,  0x05,  0xB2,  0x64,
+   0xC9,  0x92,  0x25,  0x4B,  0x96,  0x02,  0x59,  0xB2,  0x64,  0xC9,  0x92,
+   0x25,  0x4B,  0x81,  0x2C,  0x59,  0xB2,  0x64,  0xC9,  0x92,  0xA5,  0x40,
+   0x96,  0x2C,  0x59,  0xB2,  0x64,  0xC9,  0x52,  0x20,  0x4B,  0x96,  0x2C,
+   0x59,  0xB2,  0x64,  0x29,  0x90,  0x25,  0x4B,  0x96,  0x2C,  0x59,  0xB2,
+   0x14,  0xC8,  0x92,  0x25,  0x4B,  0x96,  0x2C,  0x59,  0x0A,  0x64,  0xC9,
+   0x92,  0x25,  0x4B,  0x96,  0x2C,  0x05,  0xB2,  0x64,  0xC9,  0x92,  0x25,
+   0x4B,  0x96,  0x02,  0x59,  0xB2,  0x64,  0xC9,  0x92,  0x25,  0x4B,  0x81,
+   0x2C,  0x59,  0xB2,  0x64,  0xC9,  0x92,  0xA5,  0x40,  0x96,  0x2C,  0x59,
+   0xB2,  0x64,  0xC9,  0x52,  0x20,  0x4B,  0x96,  0x2C,  0x59,  0xB2,  0x64,
+   0x29,  0x90,  0x25,  0x4B,  0x96,  0x2C,  0x59,  0xB2,  0x14,  0xC8,  0x92,
+   0x25,  0x4B,  0x96,  0x2C,  0x59,  0x0A,  0x64,  0xC9,  0xFA,  0xB6,  0x89,
+   0x5F,  0x01,  0xC7,  0x24,  0x83,  0xB2,  0x0C,  0x00,  0x00,  0x00,  0x00,
+   0x49,  0x45,  0x4E,  0x44,  0xAE,  0x42,  0x60,  0x82,
+  ];
+
+function handleRequest(request, response) {
+  var query = {};
+  request.queryString.split('&').forEach(function (val) {
+    var [name, value] = val.split('=');
+    query[name] = unescape(value);
+  });
+
+  response.setStatusLine(request.httpVersion, 200, "OK");
+  response.setHeader("Content-Type", "image/png", false);
+
+  function imageWrite() {
+    var stream = new BinaryOutputStream(response.bodyOutputStream);
+    stream.writeByteArray(IMAGE_DATA, IMAGE_DATA.length);
+  }
+
+  if ("delay" in query) {
+    response.processAsync();
+    const nsITimer = Components.interfaces.nsITimer;
+
+    var timer = Components.classes["@mozilla.org/timer;1"].createInstance(nsITimer);
+    timer.initWithCallback(function() {
+      imageWrite();
+      response.finish();
+    }, query["delay"], nsITimer.TYPE_ONE_SHOT);
+  } else {
+    imageWrite();
+  }
+}
--- a/layout/reftests/backgrounds/reftest.list
+++ b/layout/reftests/backgrounds/reftest.list
@@ -102,8 +102,11 @@
 fails == background-size-zoom-repeat.html background-size-zoom-repeat-ref.html
 
 # background-size affects images without intrinsic dimensions specially; we may
 # not support such image formats right now, but when we do, we want
 # background-size to be changed accordingly, and hopefully these tests should
 # start failing when we do.
 fails == background-size-no-intrinsic-width-image.html background-size-no-intrinsic-width-image-ref.html
 fails == background-size-no-intrinsic-height-image.html background-size-no-intrinsic-height-image-ref.html
+
+HTTP == root-background-1.html root-background-ref.html
+HTTP != root-background-1.html about:blank
new file mode 100644
--- /dev/null
+++ b/layout/reftests/backgrounds/root-background-1.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<html style="visibility: hidden; background: url('delay-image-response.sjs?delay=200')">
+  <body onload="document.documentElement.style.visibility = ''">
+  </body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/backgrounds/root-background-ref.html
@@ -0,0 +1,5 @@
+<!DOCTYPE html>
+<html>
+  <body style="background: url('delay-image-response.sjs?delay=0')">
+  </body>
+</html>
--- a/layout/style/nsStyleContext.h
+++ b/layout/style/nsStyleContext.h
@@ -317,16 +317,24 @@ public:
    * overhead of making a doubly-linked list or other structure to
    * support it).
    *
    * WARNING: Memory allocated using this method cannot be stored in the
    * rule tree, since rule nodes may outlive the style context.
    */
   void* Alloc(size_t aSize);
 
+  /**
+   * Start the background image loads for this style context.
+   */
+  void StartBackgroundImageLoads() {
+    // Just get our background struct; that should do the trick
+    GetStyleBackground();
+  }
+
 #ifdef DEBUG
   void List(FILE* out, PRInt32 aIndent);
 #endif
 
 protected:
   void AddChild(nsStyleContext* aChild);
   void RemoveChild(nsStyleContext* aChild);