Bug 489224 - Printing doesn't print text field values, r+sr=roc
authorOlli Pettay <Olli.Pettay@helsinki.fi>
Wed, 22 Apr 2009 12:35:45 +0300
changeset 27606 44d20da1741200c94bb97b04c2cf4ab580b01415
parent 27605 09df6a15e620067f9963c681439bf24985b4c0a6
child 27607 81273d925ba9dbb7ee480467ac38ed4be14fc8b8
push idunknown
push userunknown
push dateunknown
bugs489224
milestone1.9.2a1pre
Bug 489224 - Printing doesn't print text field values, r+sr=roc
layout/base/nsIPresShell.h
layout/base/nsPresShell.cpp
layout/base/tests/test_printpreview.html
layout/forms/nsTextControlFrame.h
--- a/layout/base/nsIPresShell.h
+++ b/layout/base/nsIPresShell.h
@@ -96,20 +96,20 @@ class nsWeakFrame;
 class nsIScrollableFrame;
 class gfxASurface;
 class gfxContext;
 class nsPIDOMEventTarget;
 
 typedef short SelectionType;
 typedef PRUint32 nsFrameState;
 
-// fa7f090d-b19a-4ef8-9552-82992a3b4a83
+// b8ace28a-d3fa-46d8-a5a0-d7c35c12fd41
 #define NS_IPRESSHELL_IID \
-{ 0xfa7f090d, 0xb19a, 0x4ef8, \
-  { 0x95, 0x52, 0x82, 0x99, 0x2a, 0x3b, 0x4a, 0x83 } }
+{ 0xb8ace28a, 0xd3fa, 0x46d8, \
+  { 0xa5, 0xa0, 0xd7, 0xc3, 0x5c, 0x12, 0xfd, 0x41 } }
 
 // Constants for ScrollContentIntoView() function
 #define NS_PRESSHELL_SCROLL_TOP      0
 #define NS_PRESSHELL_SCROLL_BOTTOM   100
 #define NS_PRESSHELL_SCROLL_LEFT     0
 #define NS_PRESSHELL_SCROLL_RIGHT    100
 #define NS_PRESSHELL_SCROLL_CENTER   50
 #define NS_PRESSHELL_SCROLL_ANYWHERE -1
@@ -788,16 +788,25 @@ public:
    * This color is composited on top of the user's default background
    * color whenever we need to provide an "ultimate" background color.
    * See PresShell::Paint, PresShell::PaintDefaultBackground, and
    * nsDocShell::SetupNewViewer; bug 476557 and other bugs mentioned there.
    */
   void SetCanvasBackground(nscolor aColor) { mCanvasBackgroundColor = aColor; }
   nscolor GetCanvasBackground() { return mCanvasBackgroundColor; }
 
+  void ObserveNativeAnonMutationsForPrint(PRBool aObserve)
+  {
+    mObservesMutationsForPrint = aObserve;
+  }
+  PRBool ObservesNativeAnonMutationsForPrint()
+  {
+    return mObservesMutationsForPrint;
+  }
+
 protected:
   // IMPORTANT: The ownership implicit in the following member variables
   // has been explicitly checked.  If you add any members to this class,
   // please make the ownership explicit (pinkerton, scc).
 
   // these are the same Document and PresContext owned by the DocViewer.
   // we must share ownership.
   nsIDocument*              mDocument;      // [STRONG]
@@ -824,16 +833,18 @@ protected:
    */
   void InvalidateAccessibleSubtree(nsIContent *aContent);
 #endif
 
   // Set to true when the accessibility service is being used to mirror
   // the dom/layout trees
   PRPackedBool              mIsAccessibilityActive;
 
+  PRPackedBool              mObservesMutationsForPrint;
+
   // A list of weak frames. This is a pointer to the last item in the list.
   nsWeakFrame*              mWeakFrames;
 
   // Most recent canvas background color.
   nscolor                   mCanvasBackgroundColor;
 };
 
 /**
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -761,129 +761,16 @@ FrameArena::FreeFrame(size_t aSize, void
 }
 
 struct nsCallbackEventRequest
 {
   nsIReflowCallback* callback;
   nsCallbackEventRequest* next;
 };
 
-
-class nsDocumentObserverForNonDynamicPresContext : public nsStubDocumentObserver
-{
-public:
-  nsDocumentObserverForNonDynamicPresContext(nsIDocumentObserver* aBaseObserver)
-  : mBaseObserver(aBaseObserver)
-  {
-    NS_ASSERTION(aBaseObserver, "Null document observer!");
-  }
-
-  NS_DECL_ISUPPORTS
-
-  virtual void BeginUpdate(nsIDocument* aDocument, nsUpdateType aUpdateType)
-  {
-    mBaseObserver->BeginUpdate(aDocument, aUpdateType);
-  }
-  virtual void EndUpdate(nsIDocument* aDocument, nsUpdateType aUpdateType)
-  {
-    mBaseObserver->EndUpdate(aDocument, aUpdateType);
-  }
-  virtual void BeginLoad(nsIDocument* aDocument)
-  {
-    mBaseObserver->BeginLoad(aDocument);
-  }
-  virtual void EndLoad(nsIDocument* aDocument)
-  {
-    mBaseObserver->EndLoad(aDocument);
-  }
-  virtual void ContentStatesChanged(nsIDocument* aDocument,
-                                    nsIContent* aContent1,
-                                    nsIContent* aContent2,
-                                    PRInt32 aStateMask)
-  {
-    if ((!aContent1 || IsInRootScrollbar(aContent1)) &&
-        (!aContent2 || IsInRootScrollbar(aContent2))) {
-      mBaseObserver->ContentStatesChanged(aDocument, aContent1, aContent2,
-                                          aStateMask);
-    }
-  }
-
-  // nsIMutationObserver
-  virtual void CharacterDataChanged(nsIDocument* aDocument,
-                                    nsIContent* aContent,
-                                    CharacterDataChangeInfo* aInfo)
-  {
-    if (IsInRootScrollbar(aContent)) {
-      mBaseObserver->CharacterDataChanged(aDocument, aContent, aInfo);
-    }
-  }
-  virtual void AttributeChanged(nsIDocument* aDocument,
-                                nsIContent* aContent,
-                                PRInt32 aNameSpaceID,
-                                nsIAtom* aAttribute,
-                                PRInt32 aModType,
-                                PRUint32 aStateMask)
-  {
-    if (IsInRootScrollbar(aContent)) {
-      mBaseObserver->AttributeChanged(aDocument, aContent, aNameSpaceID,
-                                      aAttribute, aModType, aStateMask);
-    }
-  }
-  virtual void ContentAppended(nsIDocument* aDocument,
-                               nsIContent* aContainer,
-                               PRInt32 aNewIndexInContainer)
-  {
-    if (IsInRootScrollbar(aContainer)) {
-      mBaseObserver->ContentAppended(aDocument, aContainer,
-                                     aNewIndexInContainer);
-    }
-  }
-  virtual void ContentInserted(nsIDocument* aDocument,
-                               nsIContent* aContainer,
-                               nsIContent* aChild,
-                               PRInt32 aIndexInContainer)
-  {
-    if (IsInRootScrollbar(aContainer)) {
-      mBaseObserver->ContentInserted(aDocument, aContainer, aChild,
-                                     aIndexInContainer);
-    }
-  }
-  virtual void ContentRemoved(nsIDocument* aDocument,
-                              nsIContent* aContainer,
-                              nsIContent* aChild,
-                              PRInt32 aIndexInContainer)
-  {
-    if (IsInRootScrollbar(aContainer)) {
-      mBaseObserver->ContentRemoved(aDocument, aContainer, aChild, 
-                                    aIndexInContainer);
-    }
-  }
-
-  PRBool IsInRootScrollbar(nsIContent* aContent) {
-    if(aContent && aContent->IsInDoc()) {
-       nsIContent* root = aContent->GetCurrentDoc()->GetRootContent();
-       while (aContent && aContent->IsInNativeAnonymousSubtree()) {
-         nsIContent* parent = aContent->GetParent();
-         if (parent == root && aContent->IsNodeOfType(nsINode::eXUL)) {
-           nsIAtom* tag = aContent->Tag();
-           return tag == nsGkAtoms::scrollbar || tag == nsGkAtoms::scrollcorner;
-         }
-         aContent = parent;
-       }
-    }
-    return PR_FALSE;
-  }
-protected:
-  nsCOMPtr<nsIDocumentObserver> mBaseObserver;
-};
-
-NS_IMPL_ISUPPORTS2(nsDocumentObserverForNonDynamicPresContext,
-                   nsIDocumentObserver,
-                   nsIMutationObserver)
-
 // ----------------------------------------------------------------------------
 class nsPresShellEventCB;
 
 class PresShell : public nsIPresShell, public nsIViewObserver,
                   public nsStubDocumentObserver,
                   public nsISelectionController, public nsIObserver,
                   public nsSupportsWeakReference
 {
@@ -1384,16 +1271,133 @@ public:
                            &aVisitor.mEventStatus);
       }
     }
   }
 
   nsRefPtr<PresShell> mPresShell;
 };
 
+class nsDocumentObserverForNonDynamicPresContext : public nsStubDocumentObserver
+{
+public:
+  nsDocumentObserverForNonDynamicPresContext(PresShell* aBaseObserver)
+  : mBaseObserver(aBaseObserver)
+  {
+    NS_ASSERTION(aBaseObserver, "Null document observer!");
+  }
+
+  NS_DECL_ISUPPORTS
+
+  virtual void BeginUpdate(nsIDocument* aDocument, nsUpdateType aUpdateType)
+  {
+    mBaseObserver->BeginUpdate(aDocument, aUpdateType);
+  }
+  virtual void EndUpdate(nsIDocument* aDocument, nsUpdateType aUpdateType)
+  {
+    mBaseObserver->EndUpdate(aDocument, aUpdateType);
+  }
+  virtual void BeginLoad(nsIDocument* aDocument)
+  {
+    mBaseObserver->BeginLoad(aDocument);
+  }
+  virtual void EndLoad(nsIDocument* aDocument)
+  {
+    mBaseObserver->EndLoad(aDocument);
+  }
+  virtual void ContentStatesChanged(nsIDocument* aDocument,
+                                    nsIContent* aContent1,
+                                    nsIContent* aContent2,
+                                    PRInt32 aStateMask)
+  {
+    if ((!aContent1 || AllowMutation(aContent1)) &&
+        (!aContent2 || AllowMutation(aContent2))) {
+      mBaseObserver->ContentStatesChanged(aDocument, aContent1, aContent2,
+                                          aStateMask);
+    }
+  }
+
+  // nsIMutationObserver
+  virtual void CharacterDataChanged(nsIDocument* aDocument,
+                                    nsIContent* aContent,
+                                    CharacterDataChangeInfo* aInfo)
+  {
+    if (AllowMutation(aContent)) {
+      mBaseObserver->CharacterDataChanged(aDocument, aContent, aInfo);
+    }
+  }
+  virtual void AttributeChanged(nsIDocument* aDocument,
+                                nsIContent* aContent,
+                                PRInt32 aNameSpaceID,
+                                nsIAtom* aAttribute,
+                                PRInt32 aModType,
+                                PRUint32 aStateMask)
+  {
+    if (AllowMutation(aContent)) {
+      mBaseObserver->AttributeChanged(aDocument, aContent, aNameSpaceID,
+                                      aAttribute, aModType, aStateMask);
+    }
+  }
+  virtual void ContentAppended(nsIDocument* aDocument,
+                               nsIContent* aContainer,
+                               PRInt32 aNewIndexInContainer)
+  {
+    if (AllowMutation(aContainer)) {
+      mBaseObserver->ContentAppended(aDocument, aContainer,
+                                     aNewIndexInContainer);
+    }
+  }
+  virtual void ContentInserted(nsIDocument* aDocument,
+                               nsIContent* aContainer,
+                               nsIContent* aChild,
+                               PRInt32 aIndexInContainer)
+  {
+    if (AllowMutation(aContainer)) {
+      mBaseObserver->ContentInserted(aDocument, aContainer, aChild,
+                                     aIndexInContainer);
+    }
+  }
+  virtual void ContentRemoved(nsIDocument* aDocument,
+                              nsIContent* aContainer,
+                              nsIContent* aChild,
+                              PRInt32 aIndexInContainer)
+  {
+    if (AllowMutation(aContainer)) {
+      mBaseObserver->ContentRemoved(aDocument, aContainer, aChild, 
+                                    aIndexInContainer);
+    }
+  }
+
+  PRBool AllowMutation(nsIContent* aContent) {
+    if(aContent && aContent->IsInDoc()) {
+       if (mBaseObserver->ObservesNativeAnonMutationsForPrint() &&
+           aContent->IsInNativeAnonymousSubtree()) {
+         return PR_TRUE;
+       }
+       // Changes to scrollbar are always ok.
+       nsIContent* root = aContent->GetCurrentDoc()->GetRootContent();
+       while (aContent && aContent->IsInNativeAnonymousSubtree()) {
+         nsIContent* parent = aContent->GetParent();
+         if (parent == root && aContent->IsNodeOfType(nsINode::eXUL)) {
+           nsIAtom* tag = aContent->Tag();
+           return tag == nsGkAtoms::scrollbar || tag == nsGkAtoms::scrollcorner;
+         }
+         aContent = parent;
+       }
+    }
+    return PR_FALSE;
+  }
+protected:
+  nsRefPtr<PresShell> mBaseObserver;
+};
+
+NS_IMPL_ISUPPORTS2(nsDocumentObserverForNonDynamicPresContext,
+                   nsIDocumentObserver,
+                   nsIMutationObserver)
+
 PRBool PresShell::sDisableNonTestMouseEvents = PR_FALSE;
 
 #ifdef PR_LOGGING
 PRLogModuleInfo* PresShell::gLog;
 #endif
 
 #ifdef NS_DEBUG
 static void
--- a/layout/base/tests/test_printpreview.html
+++ b/layout/base/tests/test_printpreview.html
@@ -141,25 +141,92 @@ function finalizeTest1() {
   setTimeout(runTest2, 1000);
 }
 
 function runTest2() {
   isnot(window.frames[0].document.body.firstChild.nextSibling.textContent, "0 timers", "Timers should have run!");
   isnot(window.frames[0].counter, 0, "Timers should have run!");
   counter = window.frames[0].counter;
   window.frames[0].counterTimeout = "";
+  setTimeout(runTest3, 0);
+}
+
+var elementIndex = 0;
+var compareEmptyElement = true;
+var emptyFormElements =
+  ["<input type='text'>",
+   "<input type='password'>",
+   "<input type='file'>",
+   "<input type='button'>",
+   "<input type='submit'>",
+   "<input type='reset'>",
+   "<input type='checkbox'>",
+   "<input type='radio'>",
+   "<select></select>",
+   "<select size='5'></select>",
+   "<textarea></textarea>"];
+
+var formElements =
+  ["<input type='text' value='text'>",
+   "<input type='password' value='password'>",
+   "<input type='file' value='file'>",
+   "<input type='button' value='button'>",
+   "<input type='submit' value='submit button'>",
+   "<input type='reset' value='reset button'>",
+   "<input type='checkbox' checked>",
+   "<input type='radio' checked>",
+   "<select><option>option1</option></select>",
+   "<select size='5'><option>1</option><option>2</option><option>3</option></select>",
+   "<textarea value='textarea'>textarea</textarea>"];
+
+function runTest3() {
+  if (compareEmptyElement) {
+    var currentIndex = elementIndex;
+    ++elementIndex;
+    if (elementIndex >= emptyFormElements.length) {
+      elementIndex = 0;
+      compareEmptyElement = false;
+    }
+    compareFormElementPrint(emptyFormElements[currentIndex], emptyFormElements[currentIndex], true);
+    return;
+  } else if (elementIndex < emptyFormElements.length) {
+    var currentIndex = elementIndex;
+    ++elementIndex;
+    compareFormElementPrint(emptyFormElements[currentIndex], formElements[currentIndex], false);
+    return;
+  }
+
   SimpleTest.finish();
 }
 
+function compareFormElementPrint(el1, el2, equals) {
+  netscape.security.PrivilegeManager.enablePrivilege('UniversalXPConnect');
+  window.frames[0].document.body.innerHTML = el1;
+  window.frames[0].document.body.firstChild.value =
+    window.frames[0].document.body.firstChild.getAttribute('value');
+  printpreview();
+  ctx1.drawWindow(window.frames[0], 0, 0, 300, 300, "rgb(256,256,256)");
+  exitprintpreview();
+  window.frames[0].document.body.innerHTML = el2;
+  window.frames[0].document.body.firstChild.value =
+    window.frames[0].document.body.firstChild.getAttribute('value');
+  printpreview();
+  ctx2.drawWindow(window.frames[0], 0, 0, 300, 300, "rgb(256,256,256)");
+  exitprintpreview();
+  is(compareCanvases(), equals,
+     "Comparing print preview didn't succeed [" + el1 + " : " + el2 + "]");
+  setTimeout(runTest3, 100);
+}
+
 SimpleTest.waitForExplicitFinish();
 
 </script>
 <iframe height="200" width="600"></iframe>
 <table>
-<tr><th>Print preview canvas before mutations</th><th>Print preview canvas after mutations</th></tr>
+<tr><th>Print preview canvas 1</th><th>Print preview canvas 2</th></tr>
 <tr>
 <td><canvas height="300" width="300"></canvas></td>
 <td><canvas height="300" width="300"></canvas></td>
 </tr></table>
 </canvas>
 </pre>
 </body>
 </html>
--- a/layout/forms/nsTextControlFrame.h
+++ b/layout/forms/nsTextControlFrame.h
@@ -218,17 +218,22 @@ protected:
   class EditorInitializer : public nsRunnable {
   public:
     EditorInitializer(nsTextControlFrame* aFrame) :
       mWeakFrame(aFrame),
       mFrame(aFrame) {}
 
     NS_IMETHOD Run() {
       if (mWeakFrame) {
+        nsCOMPtr<nsIPresShell> shell =
+          mWeakFrame.GetFrame()->PresContext()->GetPresShell();
+        PRBool observes = shell->ObservesNativeAnonMutationsForPrint();
+        shell->ObserveNativeAnonMutationsForPrint(PR_TRUE);
         mFrame->DelayedEditorInit();
+        shell->ObserveNativeAnonMutationsForPrint(observes);
       }
       return NS_OK;
     }
 
   private:
     nsWeakFrame mWeakFrame;
     nsTextControlFrame* mFrame;
   };