diff --git a/content/base/public/nsIDocument.h b/content/base/public/nsIDocument.h --- a/content/base/public/nsIDocument.h +++ b/content/base/public/nsIDocument.h @@ -1143,16 +1143,23 @@ public: * @param aFireEvents If PR_TRUE, delayed events (focus/blur) will be fired * asynchronously. */ virtual void UnsuppressEventHandlingAndFireEvents(PRBool aFireEvents) = 0; PRUint32 EventHandlingSuppressed() const { return mEventsSuppressed; } PRBool IsDNSPrefetchAllowed() const { return mAllowDNSPrefetch; } + + PRBool IsPrintDocument() { return mIsPrintDocument; } + + virtual already_AddRefed + CloneForPrint(nsISupports* aCloneContainer); + + nsIDocument* GetOriginalDocument() { return mOriginalDocument; } protected: ~nsIDocument() { // XXX The cleanup of mNodeInfoManager (calling DropDocumentReference and // releasing it) happens in the nsDocument destructor. We'd prefer to // do it here but nsNodeInfoManager is a concrete class that we don't // want to expose to users of the nsIDocument API outside of Gecko. } @@ -1228,17 +1235,23 @@ protected: PRPackedBool mHaveFiredTitleChange; // True iff IsShowing() should be returning true PRPackedBool mIsShowing; // True iff DNS prefetch is allowed for this document. Note that if the // document has no window, DNS prefetch won't be performed no matter what. PRPackedBool mAllowDNSPrefetch; - + + PRPackedBool mIsPrintDocument; + + PRPackedBool mCloningForPrint; + + nsCOMPtr mOriginalDocument; + // The bidi options for this document. What this bitfield means is // defined in nsBidiUtils.h PRUint32 mBidiOptions; nsCString mContentLanguage; nsCString mContentType; // The document's security info diff --git a/content/base/src/nsDocument.cpp b/content/base/src/nsDocument.cpp --- a/content/base/src/nsDocument.cpp +++ b/content/base/src/nsDocument.cpp @@ -2990,16 +2990,19 @@ nsDocument::doCreateShell(nsPresContext* } rv = shell->Init(this, aContext, aViewManager, aStyleSet, aCompatMode); NS_ENSURE_SUCCESS(rv, rv); // Note: we don't hold a ref to the shell (it holds a ref to us) NS_ENSURE_TRUE(mPresShells.AppendElementUnlessExists(shell), NS_ERROR_OUT_OF_MEMORY); + + NS_WARN_IF_FALSE(mPresShells.Length() == 1, "More than one presshell!"); + shell.swap(*aInstancePtrResult); return NS_OK; } PRBool nsDocument::DeleteShell(nsIPresShell* aShell) { @@ -7376,26 +7379,43 @@ nsDocument::QuerySelectorAll(const nsASt nsIDOMNodeList **aReturn) { return nsGenericElement::doQuerySelectorAll(this, aSelector, aReturn); } nsresult nsDocument::CloneDocHelper(nsDocument* clone) const { + clone->mIsPrintDocument = mCloningForPrint; + // Init document nsresult rv = clone->Init(); NS_ENSURE_SUCCESS(rv, rv); // Set URI/principal clone->nsDocument::SetDocumentURI(nsIDocument::GetDocumentURI()); // Must set the principal first, since SetBaseURI checks it. clone->SetPrincipal(NodePrincipal()); clone->mDocumentBaseURI = mDocumentBaseURI; + if (mCloningForPrint) { + nsCOMPtr channel = GetChannel(); + nsCOMPtr loadGroup = GetDocumentLoadGroup(); + if (channel && loadGroup) { + clone->Reset(channel, loadGroup); + } else { + nsIURI* uri = static_cast(this)->GetDocumentURI(); + if (uri) { + clone->ResetToURI(uri, loadGroup, NodePrincipal()); + } + } + nsCOMPtr container = GetContainer(); + clone->SetContainer(container); + } + // Set scripting object PRBool hasHadScriptObject = PR_TRUE; nsIScriptGlobalObject* scriptObject = GetScriptHandlingObject(hasHadScriptObject); NS_ENSURE_STATE(scriptObject || !hasHadScriptObject); clone->SetScriptHandlingObject(scriptObject); // Make the clone a data document @@ -7576,8 +7596,72 @@ void nsIDocument::EnumerateFreezableElements(FreezableElementEnumerator aEnumerator, void* aData) { if (!mFreezableElements) return; EnumerateFreezablesData data = { aEnumerator, aData }; mFreezableElements->EnumerateEntries(EnumerateFreezables, &data); } + +already_AddRefed +nsIDocument::CloneForPrint(nsISupports* aCloneContainer) +{ + nsCOMPtr domDoc = do_QueryInterface(this); + NS_ENSURE_TRUE(domDoc, nsnull); + mCloningForPrint = PR_TRUE; + + // Make document to use different container during cloning. + nsCOMPtr originalContainer = GetContainer(); + SetContainer(aCloneContainer); + nsCOMPtr clonedNode; + nsresult rv = domDoc->CloneNode(PR_TRUE, getter_AddRefs(clonedNode)); + SetContainer(originalContainer); + + nsCOMPtr clonedDoc; + if (NS_SUCCEEDED(rv)) { + clonedDoc = do_QueryInterface(clonedNode); + nsCOMPtr clonedDOMDoc = do_QueryInterface(clonedDoc); + if (clonedDOMDoc) { + clonedDoc->mOriginalDocument = this; + PRInt32 sheetsCount = GetNumberOfStyleSheets(); + for (PRInt32 i = 0; i < sheetsCount; ++i) { + nsCOMPtr sheet = + do_QueryInterface(GetStyleSheetAt(i)); + if (sheet) { + PRBool applicable = PR_TRUE; + sheet->GetApplicable(applicable); + if (applicable) { + nsCOMPtr clonedSheet; + sheet->Clone(nsnull, nsnull, clonedDoc, nsnull, + getter_AddRefs(clonedSheet)); + NS_WARN_IF_FALSE(clonedSheet, "Cloning a stylesheet didn't work!"); + if (clonedSheet) { + clonedDoc->AddStyleSheet(clonedSheet); + } + } + } + } + + sheetsCount = GetNumberOfCatalogStyleSheets(); + for (PRInt32 i = 0; i < sheetsCount; ++i) { + nsCOMPtr sheet = + do_QueryInterface(GetCatalogStyleSheetAt(i)); + if (sheet) { + PRBool applicable = PR_TRUE; + sheet->GetApplicable(applicable); + if (applicable) { + nsCOMPtr clonedSheet; + sheet->Clone(nsnull, nsnull, clonedDoc, nsnull, + getter_AddRefs(clonedSheet)); + NS_WARN_IF_FALSE(clonedSheet, "Cloning a stylesheet didn't work!"); + if (clonedSheet) { + clonedDoc->AddCatalogStyleSheet(clonedSheet); + } + } + } + } + } + } + mCloningForPrint = PR_FALSE; + return clonedDoc.forget(); +} + diff --git a/content/base/src/nsFrameLoader.cpp b/content/base/src/nsFrameLoader.cpp --- a/content/base/src/nsFrameLoader.cpp +++ b/content/base/src/nsFrameLoader.cpp @@ -78,16 +78,18 @@ #include "nsIURI.h" #include "nsIURL.h" #include "nsNetUtil.h" #include "nsGkAtoms.h" #include "nsINameSpaceManager.h" #include "nsThreadUtils.h" +#include "nsICSSStyleSheet.h" +#include "nsIContentViewer.h" class nsAsyncDocShellDestroyer : public nsRunnable { public: nsAsyncDocShellDestroyer(nsIDocShell* aDocShell) : mDocShell(aDocShell) { } @@ -140,17 +142,17 @@ nsFrameLoader::LoadFrame() src.Trim(" \t\n\r"); if (src.IsEmpty()) { src.AssignLiteral("about:blank"); } nsIDocument* doc = mOwnerContent->GetOwnerDoc(); - if (!doc) { + if (!doc || doc->IsPrintDocument()) { return NS_OK; } nsCOMPtr base_uri = mOwnerContent->GetBaseURI(); const nsAFlatCString &doc_charset = doc->GetDocumentCharacterSet(); const char *charset = doc_charset.IsEmpty() ? nsnull : doc_charset.get(); nsCOMPtr uri; @@ -410,17 +412,21 @@ AddTreeItemToTreeOwner(nsIDocShellTreeIt // chrome, we'll be chrome. If it is content, we'll be // content. aItem->SetItemType(aParentType); } // Now that we have our type set, add ourselves to the parent, as needed. if (aParentNode) { - aParentNode->AddChild(aItem); + nsCOMPtr d = do_QueryInterface(aParentNode); + nsresult rv = aParentNode->AddChild(aItem); + PRInt32 childWebshellCount; + aParentNode->GetChildCount(&childWebshellCount); + NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Adding a child didn't succeed \n"); } PRBool retval = PR_FALSE; if (aParentType == nsIDocShellTreeItem::typeChrome && isContent) { retval = PR_TRUE; PRBool is_primary = value.LowerCaseEqualsLiteral("content-primary"); @@ -789,28 +795,29 @@ nsFrameLoader::EnsureDocShell() if (mDocShell) { return NS_OK; } NS_ENSURE_STATE(!mDestroyCalled); // Get our parent docshell off the document of mOwnerContent // XXXbz this is such a total hack.... We really need to have a // better setup for doing this. - nsIDocument* doc = mOwnerContent->GetDocument(); - if (!doc) { + nsIDocument* doc = mOwnerContent->GetOwnerDoc(); + if (!doc || !(doc->IsPrintDocument() || mOwnerContent->IsInDoc())) { return NS_ERROR_UNEXPECTED; } if (doc->GetDisplayDocument()) { // Don't allow subframe loads in external reference documents return NS_ERROR_NOT_AVAILABLE; } - nsCOMPtr parentAsWebNav = - do_GetInterface(doc->GetScriptGlobalObject()); + nsCOMPtr container = + doc->GetContainer(); + nsCOMPtr parentAsWebNav = do_QueryInterface(container); // Create the docshell... mDocShell = do_CreateInstance("@mozilla.org/docshell;1"); NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE); // Get the frame name and tell the docshell about it. nsCOMPtr docShellAsItem(do_QueryInterface(mDocShell)); NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE); @@ -1002,8 +1009,32 @@ nsFrameLoader::CheckForRecursiveLoad(nsI } nsCOMPtr temp; temp.swap(parentAsItem); temp->GetSameTypeParent(getter_AddRefs(parentAsItem)); } return NS_OK; } + +nsresult +nsFrameLoader::CloneForPrint(nsIFrameLoader* aOriginal) +{ + EnsureDocShell(); + NS_ENSURE_STATE(mDocShell); + + nsCOMPtr dummy = do_GetInterface(mDocShell); + nsCOMPtr viewer; + mDocShell->GetContentViewer(getter_AddRefs(viewer)); + NS_ENSURE_STATE(viewer); + + nsCOMPtr origDocShell; + aOriginal->GetDocShell(getter_AddRefs(origDocShell)); + nsCOMPtr domDoc = do_GetInterface(origDocShell); + + nsCOMPtr doc = do_QueryInterface(domDoc); + NS_ENSURE_STATE(doc); + nsCOMPtr clonedDoc = doc->CloneForPrint(mDocShell); + nsCOMPtr clonedDOMDoc = do_QueryInterface(clonedDoc); + + viewer->SetDOMDocument(clonedDOMDoc); + return NS_OK; +} diff --git a/content/base/src/nsFrameLoader.h b/content/base/src/nsFrameLoader.h --- a/content/base/src/nsFrameLoader.h +++ b/content/base/src/nsFrameLoader.h @@ -72,16 +72,18 @@ public: NS_DECL_CYCLE_COLLECTING_ISUPPORTS NS_DECL_CYCLE_COLLECTION_CLASS(nsFrameLoader) NS_DECL_NSIFRAMELOADER NS_HIDDEN_(nsresult) CheckForRecursiveLoad(nsIURI* aURI); nsresult ReallyStartLoading(); void Finalize(); nsIDocShell* GetExistingDocShell() { return mDocShell; } + nsresult CloneForPrint(nsIFrameLoader* aOriginal); + // The guts of an nsIFrameLoaderOwner::SwapFrameLoader implementation. A // frame loader owner needs to call this, and pass in the two references to // nsRefPtrs for frame loaders that need to be swapped. nsresult SwapWithOtherLoader(nsFrameLoader* aOther, nsRefPtr& aFirstToSwap, nsRefPtr& aSecondToSwap); private: diff --git a/content/base/src/nsGkAtomList.h b/content/base/src/nsGkAtomList.h --- a/content/base/src/nsGkAtomList.h +++ b/content/base/src/nsGkAtomList.h @@ -195,17 +195,16 @@ GK_ATOM(circle, "circle") GK_ATOM(cite, "cite") GK_ATOM(_class, "class") GK_ATOM(classid, "classid") GK_ATOM(clear, "clear") GK_ATOM(click, "click") GK_ATOM(clickcount, "clickcount") GK_ATOM(movetoclick, "movetoclick") GK_ATOM(clip, "clip") -GK_ATOM(clonedTextForPrint, "clonedTextForPrint") GK_ATOM(close, "close") GK_ATOM(closed, "closed") GK_ATOM(closemenu, "closemenu") GK_ATOM(coalesceduplicatearcs, "coalesceduplicatearcs") GK_ATOM(code, "code") GK_ATOM(codebase, "codebase") GK_ATOM(codetype, "codetype") GK_ATOM(col, "col") diff --git a/content/base/src/nsImageLoadingContent.h b/content/base/src/nsImageLoadingContent.h --- a/content/base/src/nsImageLoadingContent.h +++ b/content/base/src/nsImageLoadingContent.h @@ -149,17 +149,17 @@ protected: * which cannot happen once the derived class destructor has started * calling the base class destructors. */ void DestroyImageLoadingContent(); void ClearBrokenState() { mBroken = PR_FALSE; } PRBool LoadingEnabled() { return mLoadingEnabled; } -private: + /** * Struct used to manage the image observers. */ struct ImageObserver { ImageObserver(imgIDecoderObserver* aObserver) : mObserver(aObserver), mNext(nsnull) { @@ -244,17 +244,16 @@ private: friend class Event; /* MEMBERS */ protected: nsCOMPtr mCurrentRequest; nsCOMPtr mPendingRequest; nsCOMPtr mCurrentURI; -private: /** * Typically we will have only one observer (our frame in the screen * prescontext), so we want to only make space for one and to * heap-allocate anything past that (saves memory and malloc churn * in the common case). The storage is a linked list, we just * happen to actually hold the first observer instead of a pointer * to it. */ diff --git a/content/base/src/nsTextFragment.cpp b/content/base/src/nsTextFragment.cpp --- a/content/base/src/nsTextFragment.cpp +++ b/content/base/src/nsTextFragment.cpp @@ -101,17 +101,16 @@ nsTextFragment::Shutdown() sSpaceSharedString[i] = nsnull; sTabSharedString[i] = nsnull; } } nsTextFragment::~nsTextFragment() { ReleaseText(); - MOZ_COUNT_DTOR(nsTextFragment); } void nsTextFragment::ReleaseText() { if (mState.mLength && m1b && mState.mInHeap) { nsMemory::Free(m2b); // m1b == m2b as far as nsMemory is concerned } diff --git a/content/base/src/nsTextFragment.h b/content/base/src/nsTextFragment.h --- a/content/base/src/nsTextFragment.h +++ b/content/base/src/nsTextFragment.h @@ -40,17 +40,16 @@ * node); if only codepoints below 256 are used, the text is stored as * a char*; otherwise the text is stored as a PRUnichar* */ #ifndef nsTextFragment_h___ #define nsTextFragment_h___ #include "nsAString.h" -#include "nsTraceRefcnt.h" class nsString; class nsCString; // XXX should this normalize the code to keep a \u0000 at the end? // XXX nsTextFragmentPool? // XXX these need I18N spankage @@ -84,17 +83,16 @@ public: static void Shutdown(); /** * Default constructor. Initialize the fragment to be empty. */ nsTextFragment() : m1b(nsnull), mAllBits(0) { - MOZ_COUNT_CTOR(nsTextFragment); NS_ASSERTION(sizeof(FragmentBits) == 4, "Bad field packing!"); } ~nsTextFragment(); /** * Change the contents of this fragment to be a copy of the * the argument fragment. diff --git a/content/html/content/public/nsHTMLMediaElement.h b/content/html/content/public/nsHTMLMediaElement.h --- a/content/html/content/public/nsHTMLMediaElement.h +++ b/content/html/content/public/nsHTMLMediaElement.h @@ -255,18 +255,19 @@ public: * XXX XBL2 issue. */ already_AddRefed GetDocumentLoadGroup(); /** * Returns PR_TRUE if the media has played or completed a seek. * Used by video frame to determine whether to paint the poster. */ - PRBool GetPlayedOrSeeked() { return mHasPlayedOrSeeked; } + PRBool GetPlayedOrSeeked() const { return mHasPlayedOrSeeked; } + nsresult CopyInnerTo(nsGenericElement* aDest) const; protected: class MediaLoadListener; class LoadNextSourceEvent; class SelectResourceEvent; /** * Changes mHasPlayedOrSeeked to aValue. If mHasPlayedOrSeeked changes * we'll force a reflow so that the video frame gets reflowed to reflect @@ -481,9 +482,11 @@ protected: // PR_TRUE if we are allowed to suspend the decoder because we were paused, // autobuffer and autoplay were not set, and we loaded the first frame. PRPackedBool mAllowSuspendAfterFirstFrame; // PR_TRUE if we've played or completed a seek. We use this to determine // when the poster frame should be shown. PRPackedBool mHasPlayedOrSeeked; + + nsRefPtr mPrintSurface; }; diff --git a/content/html/content/src/Makefile.in b/content/html/content/src/Makefile.in --- a/content/html/content/src/Makefile.in +++ b/content/html/content/src/Makefile.in @@ -151,13 +151,15 @@ FORCE_STATIC_LIB = 1 include $(topsrcdir)/config/rules.mk INCLUDES += \ -I$(srcdir)/../../../base/src \ -I$(srcdir)/../../../events/src \ -I$(srcdir)/../../../xbl/src \ -I$(srcdir)/../../../../layout/style \ -I$(srcdir)/../../../../layout/tables \ + -I$(srcdir)/../../../../layout/xul/base/src \ + -I$(srcdir)/../../../../layout/generic \ -I$(srcdir)/../../../../dom/base \ -I$(srcdir) \ $(NULL) DEFINES += -D_IMPL_NS_LAYOUT diff --git a/content/html/content/src/nsGenericHTMLElement.cpp b/content/html/content/src/nsGenericHTMLElement.cpp --- a/content/html/content/src/nsGenericHTMLElement.cpp +++ b/content/html/content/src/nsGenericHTMLElement.cpp @@ -2895,16 +2895,35 @@ nsGenericHTMLFrameElement::DestroyConten if (mFrameLoader) { mFrameLoader->Destroy(); mFrameLoader = nsnull; } nsGenericHTMLElement::DestroyContent(); } +nsresult +nsGenericHTMLFrameElement::CopyInnerTo(nsGenericElement* aDest) const +{ + nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest); + NS_ENSURE_SUCCESS(rv, rv); + + nsIDocument* doc = aDest->GetOwnerDoc(); + if (doc->IsPrintDocument() && mFrameLoader) { + nsGenericHTMLFrameElement* dest = + static_cast(aDest); + nsFrameLoader* fl = new nsFrameLoader(dest); + NS_ENSURE_TRUE(fl, NS_ERROR_OUT_OF_MEMORY); + dest->mFrameLoader = fl; + rv = fl->CloneForPrint(mFrameLoader); + } + + return rv; +} + //---------------------------------------------------------------------- nsresult nsGenericHTMLElement::Blur() { if (!ShouldBlur(this)) return NS_OK; diff --git a/content/html/content/src/nsGenericHTMLElement.h b/content/html/content/src/nsGenericHTMLElement.h --- a/content/html/content/src/nsGenericHTMLElement.h +++ b/content/html/content/src/nsGenericHTMLElement.h @@ -913,16 +913,18 @@ public: { return SetAttr(aNameSpaceID, aName, nsnull, aValue, aNotify); } virtual nsresult SetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, nsIAtom* aPrefix, const nsAString& aValue, PRBool aNotify); virtual void DestroyContent(); + nsresult CopyInnerTo(nsGenericElement* aDest) const; + // nsIDOMNSHTMLElement NS_IMETHOD GetTabIndex(PRInt32 *aTabIndex); NS_IMETHOD SetTabIndex(PRInt32 aTabIndex); NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsGenericHTMLFrameElement, nsGenericHTMLElement) protected: diff --git a/content/html/content/src/nsHTMLImageElement.cpp b/content/html/content/src/nsHTMLImageElement.cpp --- a/content/html/content/src/nsHTMLImageElement.cpp +++ b/content/html/content/src/nsHTMLImageElement.cpp @@ -143,16 +143,18 @@ public: virtual nsresult BindToTree(nsIDocument* aDocument, nsIContent* aParent, nsIContent* aBindingParent, PRBool aCompileEventHandlers); virtual PRInt32 IntrinsicState() const; virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const; + nsresult CopyInnerTo(nsGenericElement* aDest) const; + void MaybeLoadImage(); protected: nsPoint GetXY(); nsSize GetWidthHeight(); }; nsGenericHTMLElement* NS_NewHTMLImageElement(nsINodeInfo *aNodeInfo, PRBool aFromParser) @@ -648,9 +650,26 @@ nsHTMLImageElement::GetNaturalWidth(PRIn if (!image) { return NS_OK; } image->GetWidth(aNaturalWidth); return NS_OK; } - +nsresult +nsHTMLImageElement::CopyInnerTo(nsGenericElement* aDest) const +{ + if (aDest->GetOwnerDoc()->IsPrintDocument()) { + nsHTMLImageElement* dest = static_cast(aDest); + dest->mCurrentRequest = mCurrentRequest; + dest->mForcedImageState = mForcedImageState; + dest->mImageBlockingStatus = mImageBlockingStatus; + dest->mLoadingEnabled = mLoadingEnabled; + dest->mStartingLoad = mStartingLoad; + dest->mIsImageStateForced = mIsImageStateForced; + dest->mLoading = mLoading; + dest->mBroken = mBroken; + dest->mUserDisabled = mUserDisabled; + dest->mSuppressed = mSuppressed; + } + return nsGenericHTMLElement::CopyInnerTo(aDest); +} diff --git a/content/html/content/src/nsHTMLMediaElement.cpp b/content/html/content/src/nsHTMLMediaElement.cpp --- a/content/html/content/src/nsHTMLMediaElement.cpp +++ b/content/html/content/src/nsHTMLMediaElement.cpp @@ -71,16 +71,18 @@ #include "nsICategoryManager.h" #include "nsCommaSeparatedTokenizer.h" #include "nsIContentPolicy.h" #include "nsContentPolicyUtils.h" #include "nsContentErrors.h" #include "nsCrossSiteListenerProxy.h" #include "nsCycleCollectionParticipant.h" +#include "nsLayoutUtils.h" +#include "nsVideoFrame.h" #ifdef MOZ_OGG #include "nsOggDecoder.h" #endif #ifdef MOZ_WAVE #include "nsWaveDecoder.h" #endif @@ -933,17 +935,17 @@ static PRBool IsAutoplayEnabled() return nsContentUtils::GetBoolPref("media.autoplay.enabled"); } nsresult nsHTMLMediaElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent, nsIContent* aBindingParent, PRBool aCompileEventHandlers) { mIsBindingToTree = PR_TRUE; - mAutoplayEnabled = IsAutoplayEnabled(); + mAutoplayEnabled = IsAutoplayEnabled() && !aDocument->IsPrintDocument(); nsresult rv = nsGenericHTMLElement::BindToTree(aDocument, aParent, aBindingParent, aCompileEventHandlers); if (NS_SUCCEEDED(rv) && mIsDoneAddingChildren && mNetworkState == nsIDOMHTMLMediaElement::NETWORK_EMPTY) { @@ -1484,17 +1486,33 @@ void nsHTMLMediaElement::NotifyAutoplayD DispatchAsyncSimpleEvent(NS_LITERAL_STRING("play")); } } void nsHTMLMediaElement::Paint(gfxContext* aContext, gfxPattern::GraphicsFilter aFilter, const gfxRect& aRect) { - if (mDecoder) + if (mPrintSurface) { + printf("Print paint 1\n"); + nsRefPtr pat = new gfxPattern(mPrintSurface); + if (!pat) + return; + // Make the source image fill the rectangle completely + pat->SetMatrix(gfxMatrix().Scale(mMediaSize.width/aRect.Width(), mMediaSize.height/aRect.Height())); + + pat->SetFilter(aFilter); + + /* Draw RGB surface onto frame */ + aContext->NewPath(); + aContext->PixelSnappedRectangleAndSetPattern(aRect, pat); + aContext->Fill(); + + printf("Print paint 2\n"); + } else if (mDecoder) mDecoder->Paint(aContext, aFilter, aRect); } nsresult nsHTMLMediaElement::DispatchSimpleEvent(const nsAString& aName) { return nsContentUtils::DispatchTrustedEvent(GetOwnerDoc(), static_cast(this), aName, @@ -1729,8 +1747,40 @@ void nsHTMLMediaElement::ChangeDelayLoad } } already_AddRefed nsHTMLMediaElement::GetDocumentLoadGroup() { nsIDocument* doc = GetOwnerDoc(); return doc ? doc->GetDocumentLoadGroup() : nsnull; } + +nsresult +nsHTMLMediaElement::CopyInnerTo(nsGenericElement* aDest) const +{ + nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest); + NS_ENSURE_SUCCESS(rv, rv); + if (aDest->GetOwnerDoc()->IsPrintDocument()) { + nsHTMLMediaElement* dest = static_cast(aDest); + if (mPrintSurface) { + dest->mPrintSurface = mPrintSurface; + dest->mMediaSize = mMediaSize; + } else { + nsIFrame* frame = + GetPrimaryFrameFor(const_cast(this), + GetOwnerDoc()); + nsCOMPtr elem; + if (frame && frame->GetType() == nsGkAtoms::HTMLVideoFrame && + static_cast(frame)->ShouldDisplayPoster()) { + elem = do_QueryInterface(static_cast(frame)-> + GetPosterImage()); + } else { + elem = do_QueryInterface(const_cast(this)); + } + + nsLayoutUtils::SurfaceFromElementResult res = + nsLayoutUtils::SurfaceFromElement(elem, nsLayoutUtils::SFE_WANT_NEW_SURFACE); + dest->mPrintSurface = res.mSurface; + dest->mMediaSize = nsIntSize(res.mSize.width, res.mSize.height); + } + } + return rv; +} diff --git a/content/html/content/src/nsHTMLOptionElement.cpp b/content/html/content/src/nsHTMLOptionElement.cpp --- a/content/html/content/src/nsHTMLOptionElement.cpp +++ b/content/html/content/src/nsHTMLOptionElement.cpp @@ -115,16 +115,18 @@ public: // nsIOptionElement NS_IMETHOD SetSelectedInternal(PRBool aValue, PRBool aNotify); // nsIContent virtual PRInt32 IntrinsicState() const; virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const; + nsresult CopyInnerTo(nsGenericElement* aDest) const; + protected: /** * Get the select content element that contains this option, this * intentionally does not return nsresult, all we care about is if * there's a select associated with this option or not. * @param aSelectElement the select element (out param) */ nsIContent* GetSelect(); @@ -527,8 +529,23 @@ nsHTMLOptionElement::Initialize(nsISuppo return SetSelected(selected); } } } } return result; } + +nsresult +nsHTMLOptionElement::CopyInnerTo(nsGenericElement* aDest) const +{ + nsresult rv = nsGenericHTMLElement::CopyInnerTo(aDest); + NS_ENSURE_SUCCESS(rv, rv); + + if (aDest->GetOwnerDoc()->IsPrintDocument()) { + PRBool selected = PR_FALSE; + const_cast(this)->GetSelected(&selected); + static_cast(aDest)->SetSelected(selected); + } + return NS_OK; +} + diff --git a/content/html/content/src/nsHTMLTextAreaElement.cpp b/content/html/content/src/nsHTMLTextAreaElement.cpp --- a/content/html/content/src/nsHTMLTextAreaElement.cpp +++ b/content/html/content/src/nsHTMLTextAreaElement.cpp @@ -145,16 +145,18 @@ public: virtual PRBool IsHTMLFocusable(PRBool *aIsFocusable, PRInt32 *aTabIndex); virtual nsresult DoneAddingChildren(PRBool aHaveNotified); virtual PRBool IsDoneAddingChildren(); virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const; + nsresult CopyInnerTo(nsGenericElement* aDest) const; + /** * Called when an attribute is about to be changed */ virtual nsresult BeforeSetAttr(PRInt32 aNameSpaceID, nsIAtom* aName, const nsAString* aValue, PRBool aNotify); // nsIMutationObserver virtual void CharacterDataChanged(nsIDocument* aDocument, @@ -970,8 +972,23 @@ nsHTMLTextAreaElement::AfterSetAttr(PRIn document->ContentStatesChanged(this, nsnull, NS_EVENT_STATE_MOZ_READONLY | NS_EVENT_STATE_MOZ_READWRITE); } } return nsGenericHTMLFormElement::AfterSetAttr(aNameSpaceID, aName, aValue, aNotify); } + +nsresult +nsHTMLTextAreaElement::CopyInnerTo(nsGenericElement* aDest) const +{ + nsresult rv = nsGenericHTMLFormElement::CopyInnerTo(aDest); + NS_ENSURE_SUCCESS(rv, rv); + + if (aDest->GetOwnerDoc()->IsPrintDocument()) { + nsAutoString value; + const_cast(this)->GetValue(value); + static_cast(aDest)->SetValue(value); + } + return NS_OK; +} + diff --git a/embedding/browser/webBrowser/nsIWebBrowserPrint.idl b/embedding/browser/webBrowser/nsIWebBrowserPrint.idl --- a/embedding/browser/webBrowser/nsIWebBrowserPrint.idl +++ b/embedding/browser/webBrowser/nsIWebBrowserPrint.idl @@ -139,17 +139,17 @@ interface nsIWebBrowserPrint : nsISuppor void print(in nsIPrintSettings aThePrintSettings, in nsIWebProgressListener aWPListener); /** * Print Preview the specified DOM window * * @param aThePrintSettings - Printer Settings for the print preview, if aThePrintSettings is null * then the global PS will be used. - * @param aChildDOMWin - DOM Window of the child document to be PP (FrameSet frames) + * @param aChildDOMWin - DOM Window to be print previewed. * @param aWPListener - is updated during the printpreview * @return void */ void printPreview(in nsIPrintSettings aThePrintSettings, in nsIDOMWindow aChildDOMWin, in nsIWebProgressListener aWPListener); /** diff --git a/layout/base/nsCSSFrameConstructor.cpp b/layout/base/nsCSSFrameConstructor.cpp --- a/layout/base/nsCSSFrameConstructor.cpp +++ b/layout/base/nsCSSFrameConstructor.cpp @@ -11615,18 +11615,17 @@ nsCSSFrameConstructor::RebuildAllStyleDa NS_ASSERTION(!(aExtraHint & nsChangeHint_ReconstructFrame), "Should not reconstruct the root of the frame tree. " "Use ReconstructDocElementHierarchy instead."); mRebuildAllStyleData = PR_FALSE; NS_UpdateHint(aExtraHint, mRebuildAllExtraHint); mRebuildAllExtraHint = nsChangeHint(0); - if (!mPresShell || !mPresShell->GetRootFrame() || - !mPresShell->GetPresContext()->IsDynamic()) + if (!mPresShell || !mPresShell->GetRootFrame()) return; nsAutoScriptBlocker scriptBlocker; // Make sure that the viewmanager will outlive the presshell nsIViewManager::UpdateViewBatch batch(mPresShell->GetViewManager()); // Processing the style changes could cause a flush that propagates to diff --git a/layout/base/nsDocumentViewer.cpp b/layout/base/nsDocumentViewer.cpp --- a/layout/base/nsDocumentViewer.cpp +++ b/layout/base/nsDocumentViewer.cpp @@ -684,16 +684,20 @@ DocumentViewerImpl::Init(nsIWidget* aPar NS_ENSURE_SUCCESS(rv, rv); return InitInternal(aParentWidget, nsnull, aBounds, PR_TRUE, PR_FALSE); } nsresult DocumentViewerImpl::InitPresentationStuff(PRBool aDoInitialReflow, PRBool aReenableRefresh) { + if (GetIsPrintPreview() || + (mDocument && mDocument->IsPrintDocument())) + return NS_OK; + NS_ASSERTION(!mPresShell, "Someone should have destroyed the presshell!"); // Create the style set... nsStyleSet *styleSet; nsresult rv = CreateStyleSet(mDocument, &styleSet); NS_ENSURE_SUCCESS(rv, rv); @@ -1625,24 +1629,26 @@ DocumentViewerImpl::SetDOMDocument(nsIDO // Set the script global object on the new document nsCOMPtr window = do_GetInterface(container); if (window) { window->SetNewDocument(newDoc, nsnull, PR_TRUE); } // Clear the list of old child docshells. CChild docshells for the new // document will be constructed as frames are created. - nsCOMPtr node = do_QueryInterface(container); - if (node) { - PRInt32 count; - node->GetChildCount(&count); - for (PRInt32 i = 0; i < count; ++i) { - nsCOMPtr child; - node->GetChildAt(0, getter_AddRefs(child)); - node->RemoveChild(child); + if (!newDoc->IsPrintDocument()) { + nsCOMPtr node = do_QueryInterface(container); + if (node) { + PRInt32 count; + node->GetChildCount(&count); + for (PRInt32 i = 0; i < count; ++i) { + nsCOMPtr child; + node->GetChildAt(0, getter_AddRefs(child)); + node->RemoveChild(child); + } } } } rv = SyncParentSubDocMap(); NS_ENSURE_SUCCESS(rv, rv); // Replace the current pres shell with a new shell for the new document @@ -1690,47 +1696,29 @@ DocumentViewerImpl::GetDocument(nsIDocum NS_IF_ADDREF(*aResult = mDocument); return NS_OK; } nsIPresShell* DocumentViewerImpl::GetPresShell() { - if (!GetIsPrintPreview()) { - return mPresShell; - } - NS_ENSURE_TRUE(mDocument, nsnull); - nsCOMPtr shell; - nsCOMPtr currentShell; - nsPresShellIterator iter(mDocument); - while ((shell = iter.GetNextShell())) { - currentShell.swap(shell); - } - return currentShell.get(); + return mPresShell; } nsPresContext* DocumentViewerImpl::GetPresContext() { - if (!GetIsPrintPreview()) { - return mPresContext; - } - nsIPresShell* shell = GetPresShell(); - return shell ? shell->GetPresContext() : nsnull; + return mPresContext; } nsIViewManager* DocumentViewerImpl::GetViewManager() { - if (!GetIsPrintPreview()) { - return mViewManager; - } - nsIPresShell* shell = GetPresShell(); - return shell ? shell->GetViewManager() : nsnull; + return mViewManager; } NS_IMETHODIMP DocumentViewerImpl::GetPresShell(nsIPresShell** aResult) { nsIPresShell* shell = GetPresShell(); NS_IF_ADDREF(*aResult = shell); return NS_OK; @@ -1936,27 +1924,28 @@ DocumentViewerImpl::Show(void) rv = InitPresentationStuff(mDocument->MayStartLayout(), mDocument->MayStartLayout()); } // If we get here the document load has already started and the // window is shown because some JS on the page caused it to be // shown... - nsCOMPtr shellDeathGrip(mPresShell); // bug 378682 - mPresShell->UnsuppressPainting(); + if (mPresShell) { + nsCOMPtr shellDeathGrip(mPresShell); // bug 378682 + mPresShell->UnsuppressPainting(); + } } return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::Hide(void) { - NS_PRECONDITION(mWindow, "null window"); if (mWindow) { mWindow->Show(PR_FALSE); } if (!mPresShell) return NS_OK; NS_ASSERTION(mPresContext, "Can't have a presshell and no prescontext!"); @@ -2211,18 +2200,21 @@ DocumentViewerImpl::ClearHistoryEntry() return NS_OK; } //------------------------------------------------------- nsresult DocumentViewerImpl::MakeWindow(const nsSize& aSize) { - nsresult rv; - + if (GetIsPrintPreview() || + (mDocument && mDocument->IsPrintDocument())) + return NS_OK; + + nsresult rv; mViewManager = do_CreateInstance(kViewManagerCID, &rv); if (NS_FAILED(rv)) return rv; nsIDeviceContext *dx = mPresContext->DeviceContext(); rv = mViewManager->Init(dx); if (NS_FAILED(rv)) @@ -3663,20 +3655,24 @@ DocumentViewerImpl::PrintPreview(nsIPrin nsCOMPtr presShell; docShell->GetPresShell(getter_AddRefs(presShell)); if (!presShell || !mDocument || !mDeviceContext || !mParentWidget) { PR_PL(("Can't Print Preview without pres shell, document etc")); return NS_ERROR_FAILURE; } if (!mPrintEngine) { + nsCOMPtr domDoc; + aChildDOMWin->GetDocument(getter_AddRefs(domDoc)); + nsCOMPtr doc = do_QueryInterface(domDoc); + mPrintEngine = new nsPrintEngine(); NS_ENSURE_TRUE(mPrintEngine, NS_ERROR_OUT_OF_MEMORY); - rv = mPrintEngine->Initialize(this, docShell, mDocument, + rv = mPrintEngine->Initialize(this, docShell, doc, mDeviceContext, mParentWidget, #ifdef NS_DEBUG mDebugFile #else nsnull #endif ); if (NS_FAILED(rv)) { @@ -4075,16 +4071,22 @@ DocumentViewerImpl::SetIsPrintPreview(PR // Set all the docShells in the docshell tree to be printing. // that way if anyone of them tries to "navigate" it can't if (mContainer) { nsCOMPtr docShellTreeNode(do_QueryReferent(mContainer)); NS_ASSERTION(docShellTreeNode, "mContainer has to be a nsIDocShellTreeNode"); SetIsPrintingInDocShellTree(docShellTreeNode, aIsPrintPreview, PR_TRUE); } #endif + if (!aIsPrintPreview) { + mWindow = nsnull; + mViewManager = nsnull; + mPresContext = nsnull; + mPresShell = nsnull; + } } //---------------------------------------------------------------------------------- // nsIDocumentViewerPrint IFace //---------------------------------------------------------------------------------- //------------------------------------------------------------ void @@ -4107,17 +4109,19 @@ DocumentViewerImpl::ReturnToGalleyPresen } SetIsPrintPreview(PR_FALSE); mPrintEngine->TurnScriptingOn(PR_TRUE); mPrintEngine->Destroy(); mPrintEngine = nsnull; - mViewManager->EnableRefresh(NS_VMREFRESH_DEFERRED); + if (mViewManager) { + mViewManager->EnableRefresh(NS_VMREFRESH_DEFERRED); + } nsCOMPtr docShell(do_QueryReferent(mContainer)); ResetFocusState(docShell); if (mPresContext) mPresContext->RestoreImageAnimationMode(); SetTextZoom(mTextZoom); @@ -4256,8 +4260,24 @@ DocumentViewerImpl::DestroyPresShell() nsCOMPtr selPrivate = do_QueryInterface(selection); if (selPrivate && mSelectionListener) selPrivate->RemoveSelectionListener(mSelectionListener); nsAutoScriptBlocker scriptBlocker; mPresShell->Destroy(); mPresShell = nsnull; } + +void +DocumentViewerImpl::SetPrintPreviewPresentation(nsIWidget* aWidget, + nsIViewManager* aViewManager, + nsPresContext* aPresContext, + nsIPresShell* aPresShell) +{ + if (mPresShell) { + DestroyPresShell(); + } + + mWindow = aWidget; + mViewManager = aViewManager; + mPresContext = aPresContext; + mPresShell = aPresShell; +} diff --git a/layout/base/nsIDocumentViewerPrint.h b/layout/base/nsIDocumentViewerPrint.h --- a/layout/base/nsIDocumentViewerPrint.h +++ b/layout/base/nsIDocumentViewerPrint.h @@ -36,20 +36,25 @@ * ***** END LICENSE BLOCK ***** */ #ifndef nsIDocumentViewerPrint_h___ #define nsIDocumentViewerPrint_h___ #include "nsISupports.h" class nsIDocument; class nsStyleSet; +class nsIPresShell; +class nsPresContext; +class nsIWidget; +class nsIViewManager; -// {D0B7F354-D575-43fd-903D-5AA35A193EDA} +// {b1c7bb4f-4739-4600-82cb-20e50ec86bb4} #define NS_IDOCUMENT_VIEWER_PRINT_IID \ - { 0xd0b7f354, 0xd575, 0x43fd, { 0x90, 0x3d, 0x5a, 0xa3, 0x5a, 0x19, 0x3e, 0xda } } +{ 0xb1c7bb4f, 0x4739, 0x4600, \ + { 0x82, 0xcb, 0x20, 0xe5, 0x0e, 0xc8, 0x6b, 0xb4 } } /** * A DocumentViewerPrint is an INTERNAL Interface used for interaction * between the DocumentViewer and the PrintEngine */ class nsIDocumentViewerPrint : public nsISupports { public: @@ -67,25 +72,33 @@ public: virtual nsresult CreateStyleSet(nsIDocument* aDocument, nsStyleSet** aStyleSet) = 0; virtual void IncrementDestroyRefCount() = 0; virtual void ReturnToGalleyPresentation() = 0; virtual void OnDonePrinting() = 0; + virtual void SetPrintPreviewPresentation(nsIWidget* aWidget, + nsIViewManager* aViewManager, + nsPresContext* aPresContext, + nsIPresShell* aPresShell) = 0; }; NS_DEFINE_STATIC_IID_ACCESSOR(nsIDocumentViewerPrint, NS_IDOCUMENT_VIEWER_PRINT_IID) /* Use this macro when declaring classes that implement this interface. */ #define NS_DECL_NSIDOCUMENTVIEWERPRINT \ virtual void SetIsPrinting(PRBool aIsPrinting); \ virtual PRBool GetIsPrinting(); \ virtual void SetIsPrintPreview(PRBool aIsPrintPreview); \ virtual PRBool GetIsPrintPreview(); \ virtual nsresult CreateStyleSet(nsIDocument* aDocument, nsStyleSet** aStyleSet); \ virtual void IncrementDestroyRefCount(); \ virtual void ReturnToGalleyPresentation(); \ - virtual void OnDonePrinting(); + virtual void OnDonePrinting(); \ + virtual void SetPrintPreviewPresentation(nsIWidget* aWidget, \ + nsIViewManager* aViewManager, \ + nsPresContext* aPresContext, \ + nsIPresShell* aPresShell); #endif /* nsIDocumentViewerPrint_h___ */ diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -75,17 +75,16 @@ #include "nsIBaseWindow.h" #include "nsIDocShell.h" #include "nsIDocShellTreeItem.h" #include "nsIWidget.h" #include "gfxMatrix.h" #include "gfxTypes.h" #include "gfxUserFontSet.h" #include "nsTArray.h" -#include "nsTextFragment.h" #include "nsICanvasElement.h" #include "nsICanvasRenderingContextInternal.h" #include "gfxPlatform.h" #ifdef MOZ_MEDIA #include "nsHTMLVideoElement.h" #endif #include "imgIRequest.h" #include "imgIContainer.h" @@ -3244,58 +3243,16 @@ nsLayoutUtils::IsReallyFixedPos(nsIFrame NS_STYLE_POSITION_FIXED, "IsReallyFixedPos called on non-'position:fixed' frame"); nsIAtom *parentType = aFrame->GetParent()->GetType(); return parentType == nsGkAtoms::viewportFrame || parentType == nsGkAtoms::pageContentFrame; } -static void DeleteTextFragment(void* aObject, nsIAtom* aPropertyName, - void* aPropertyValue, void* aData) -{ - delete static_cast(aPropertyValue); -} - -/* static */ nsTextFragment* -nsLayoutUtils::GetTextFragmentForPrinting(const nsIFrame* aFrame) -{ - nsPresContext* presContext = aFrame->PresContext(); - NS_PRECONDITION(!presContext->IsDynamic(), - "Shouldn't call this with dynamic PresContext"); -#ifdef MOZ_SVG - NS_PRECONDITION(aFrame->GetType() == nsGkAtoms::textFrame || - aFrame->GetType() == nsGkAtoms::svgGlyphFrame, - "Wrong frame type!"); -#else - NS_PRECONDITION(aFrame->GetType() == nsGkAtoms::textFrame, - "Wrong frame type!"); -#endif // MOZ_SVG - - nsIContent* content = aFrame->GetContent(); - nsTextFragment* frag = - static_cast(presContext->PropertyTable()-> - GetProperty(content, nsGkAtoms::clonedTextForPrint)); - - if (!frag) { - frag = new nsTextFragment(); - NS_ENSURE_TRUE(frag, nsnull); - *frag = *content->GetText(); - nsresult rv = presContext->PropertyTable()-> - SetProperty(content, nsGkAtoms::clonedTextForPrint, frag, - DeleteTextFragment, nsnull); - if (NS_FAILED(rv)) { - delete frag; - return nsnull; - } - } - - return frag; -} - nsLayoutUtils::SurfaceFromElementResult nsLayoutUtils::SurfaceFromElement(nsIDOMElement *aElement, PRUint32 aSurfaceFlags) { SurfaceFromElementResult result; nsresult rv; nsCOMPtr node = do_QueryInterface(aElement); diff --git a/layout/base/nsLayoutUtils.h b/layout/base/nsLayoutUtils.h --- a/layout/base/nsLayoutUtils.h +++ b/layout/base/nsLayoutUtils.h @@ -59,17 +59,16 @@ class nsIFontMetrics; #include "nsIView.h" #include "nsIFrame.h" #include "nsThreadUtils.h" #include "nsIPresShell.h" #include "nsIPrincipal.h" #include "gfxPattern.h" class nsBlockFrame; -class nsTextFragment; /** * nsLayoutUtils is a namespace class used for various helper * functions that are useful in multiple places in layout. The goal * is not to define multiple copies of the same static helper. */ class nsLayoutUtils { @@ -999,22 +998,16 @@ public: /** * Indicates if the nsIFrame::GetUsedXXX assertions in nsFrame.cpp should * disabled. */ static PRBool sDisableGetUsedXAssertions; /** - * Returns the text fragment, which aFrame should use for printing. - * @param aFrame The nsIFrame object, which uses text fragment data. - */ - static nsTextFragment* GetTextFragmentForPrinting(const nsIFrame* aFrame); - - /** * Return whether aFrame is an inline frame in the first part of an {ib} * split. */ static PRBool FrameIsInFirstPartOfIBSplit(const nsIFrame* aFrame) { return (aFrame->GetStateBits() & NS_FRAME_IS_SPECIAL) && !aFrame->GetFirstContinuation()-> GetProperty(nsGkAtoms::IBSplitSpecialPrevSibling); } diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp --- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp @@ -1208,17 +1208,17 @@ nsPresContext::GetDefaultFont(PRUint8 aF break; } return font; } void nsPresContext::SetFullZoom(float aZoom) { - if (!mShell || mFullZoom == aZoom || !IsDynamic()) { + if (!mShell || mFullZoom == aZoom) { return; } // Re-fetch the view manager's window dimensions in case there's a deferred // resize which hasn't affected our mVisibleArea yet nscoord oldWidthAppUnits, oldHeightAppUnits; mShell->GetViewManager()->GetWindowDimensions(&oldWidthAppUnits, &oldHeightAppUnits); float oldWidthDevPixels = oldWidthAppUnits / float(mCurAppUnitsPerDevPixel); float oldHeightDevPixels = oldHeightAppUnits / float(mCurAppUnitsPerDevPixel); diff --git a/layout/base/nsPresShell.cpp b/layout/base/nsPresShell.cpp --- a/layout/base/nsPresShell.cpp +++ b/layout/base/nsPresShell.cpp @@ -1332,19 +1332,16 @@ protected: MOZ_TIMER_DECLARE(mFrameCreationWatch) // Used for measuring time spent in frame creation #ifdef MOZ_REFLOW_PERF ReflowCountMgr * mReflowCountMgr; #endif static PRBool sDisableNonTestMouseEvents; - - nsCOMPtr mDocumentObserverForNonDynamicContext; - // false if a check should be done for key/ime events that should be // retargeted to the currently focused presshell static PRBool sDontRetargetEvents; private: PRBool InZombieDocument(nsIContent *aContent); nsresult RetargetEventToParent(nsGUIEvent* aEvent, @@ -1445,133 +1442,16 @@ public: &aVisitor.mEventStatus); } } } nsRefPtr 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 mBaseObserver; -}; - -NS_IMPL_ISUPPORTS2(nsDocumentObserverForNonDynamicPresContext, - nsIDocumentObserver, - nsIMutationObserver) - PRBool PresShell::sDisableNonTestMouseEvents = PR_FALSE; PRBool PresShell::sDontRetargetEvents = PR_FALSE; #ifdef PR_LOGGING PRLogModuleInfo* PresShell::gLog; #endif #ifdef NS_DEBUG @@ -2573,24 +2453,17 @@ PresShell::RepaintSelection(SelectionTyp return mSelection->RepaintSelection(aType); } // Make shell be a document observer NS_IMETHODIMP PresShell::BeginObservingDocument() { if (mDocument && !mIsDestroying) { - if (mPresContext->IsDynamic()) { - mDocument->AddObserver(this); - } else { - mDocumentObserverForNonDynamicContext = - new nsDocumentObserverForNonDynamicPresContext(this); - NS_ENSURE_TRUE(mDocumentObserverForNonDynamicContext, NS_ERROR_OUT_OF_MEMORY); - mDocument->AddObserver(mDocumentObserverForNonDynamicContext); - } + mDocument->AddObserver(this); if (mIsDocumentGone) { NS_WARNING("Adding a presshell that was disconnected from the document " "as a document observer? Sounds wrong..."); mIsDocumentGone = PR_FALSE; } } return NS_OK; } @@ -2598,20 +2471,17 @@ PresShell::BeginObservingDocument() // Make shell stop being a document observer NS_IMETHODIMP PresShell::EndObservingDocument() { // XXXbz do we need to tell the frame constructor that the document // is gone, perhaps? Except for printing it's NOT gone, sometimes. mIsDocumentGone = PR_TRUE; if (mDocument) { - mDocument->RemoveObserver(mDocumentObserverForNonDynamicContext ? - mDocumentObserverForNonDynamicContext.get() : - this); - mDocumentObserverForNonDynamicContext = nsnull; + mDocument->RemoveObserver(this); } return NS_OK; } #ifdef DEBUG_kipp char* nsPresShell_ReflowStackPointerTop; #endif @@ -3643,20 +3513,16 @@ PresShell::RecreateFramesFor(nsIContent* { NS_ENSURE_TRUE(mPresContext, NS_ERROR_FAILURE); if (!mDidInitialReflow) { // Nothing to do here. In fact, if we proceed and aContent is the // root we will crash. return NS_OK; } - if (!mPresContext->IsDynamic()) { - return NS_OK; - } - // Don't call RecreateFramesForContent since that is not exported and we want // to keep the number of entrypoints down. NS_ASSERTION(mViewManager, "Should have view manager"); nsIViewManager::UpdateViewBatch batch(mViewManager); // Have to make sure that the content notifications are flushed before we // start messing with the frame model; otherwise we can get content doubling. @@ -5069,19 +4935,16 @@ PresShell::ContentRemoved(nsIDocument *a &didReconstruct); VERIFY_STYLE_TREE; } nsresult PresShell::ReconstructFrames(void) { - if (!mPresContext || !mPresContext->IsDynamic()) { - return NS_OK; - } nsAutoCauseReflowNotifier crNotifier(this); mFrameConstructor->BeginUpdate(); nsresult rv = mFrameConstructor->ReconstructDocElementHierarchy(); VERIFY_STYLE_TREE; mFrameConstructor->EndUpdate(); return rv; } diff --git a/layout/generic/nsTextFrame.h b/layout/generic/nsTextFrame.h --- a/layout/generic/nsTextFrame.h +++ b/layout/generic/nsTextFrame.h @@ -54,20 +54,16 @@ #include "nsLineBox.h" #include "gfxFont.h" #include "gfxSkipChars.h" #include "gfxContext.h" class nsTextPaintStyle; class PropertyProvider; -// This bit is set while the frame is registered as a blinking frame or if -// frame is within a non-dynamic PresContext. -#define TEXT_BLINK_ON_OR_PRINTING 0x20000000 - // This state bit is set on frames that have some non-collapsed characters after // reflow #define TEXT_HAS_NONCOLLAPSED_CHARACTERS 0x80000000 class nsTextFrame : public nsFrame { public: friend class nsContinuingTextFrame; @@ -353,27 +349,19 @@ public: struct TrimmedOffsets { PRInt32 mStart; PRInt32 mLength; PRInt32 GetEnd() { return mStart + mLength; } }; TrimmedOffsets GetTrimmedOffsets(const nsTextFragment* aFrag, PRBool aTrimAfter); - const nsTextFragment* GetFragment() const - { - return !(GetStateBits() & TEXT_BLINK_ON_OR_PRINTING) ? - mContent->GetText() : GetFragmentInternal(); - } - protected: virtual ~nsTextFrame(); - const nsTextFragment* GetFragmentInternal() const; - nsIFrame* mNextContinuation; // The key invariant here is that mContentOffset never decreases along // a next-continuation chain. And of course mContentOffset is always <= the // the text node's content length, and the mContentOffset for the first frame // is always 0. Furthermore the text mapped by a frame is determined by // GetContentOffset() and GetContentLength()/GetContentEnd(), which get // the length from the difference between this frame's offset and the next // frame's offset, or the text length if there is no next frame. This means diff --git a/layout/generic/nsTextFrameThebes.cpp b/layout/generic/nsTextFrameThebes.cpp --- a/layout/generic/nsTextFrameThebes.cpp +++ b/layout/generic/nsTextFrameThebes.cpp @@ -159,19 +159,18 @@ // Cache bits for IsEmpty(). // Set this bit if the textframe is known to be only collapsible whitespace. #define TEXT_IS_ONLY_WHITESPACE 0x08000000 // Set this bit if the textframe is known to be not only collapsible whitespace. #define TEXT_ISNOT_ONLY_WHITESPACE 0x10000000 #define TEXT_WHITESPACE_FLAGS 0x18000000 - -// nsTextFrame.h has -// #define TEXT_BLINK_ON_OR_PRINTING 0x20000000 +// This bit is set while the frame is registered as a blinking frame. +#define TEXT_BLINK_ON 0x20000000 // Set when this text frame is mentioned in the userdata for a textrun #define TEXT_IN_TEXTRUN_USER_DATA 0x40000000 // nsTextFrame.h has // #define TEXT_HAS_NONCOLLAPSED_CHARACTERS 0x80000000 /* @@ -478,33 +477,33 @@ nsTextFrameTextRunCache::Init() { void nsTextFrameTextRunCache::Shutdown() { delete gTextRuns; gTextRuns = nsnull; } PRInt32 nsTextFrame::GetContentEnd() const { nsTextFrame* next = static_cast(GetNextContinuation()); - return next ? next->GetContentOffset() : GetFragment()->GetLength(); + return next ? next->GetContentOffset() : mContent->GetText()->GetLength(); } PRInt32 nsTextFrame::GetInFlowContentLength() { #ifdef IBMBIDI nsTextFrame* nextBidi = nsnull; PRInt32 start = -1, end; if (mState & NS_FRAME_IS_BIDI) { nextBidi = static_cast(GetLastInFlow()->GetNextContinuation()); if (nextBidi) { nextBidi->GetOffsets(start, end); return start - mContentOffset; } } #endif //IBMBIDI - return GetFragment()->GetLength() - mContentOffset; + return mContent->TextLength() - mContentOffset; } // Smarter versions of XP_IS_SPACE. // Unicode is really annoying; sometimes a space character isn't whitespace --- // when it combines with another character // So we have several versions of IsSpace for use in different contexts. static PRBool IsSpaceCombiningSequenceTail(const nsTextFragment* aFrag, PRUint32 aPos) @@ -723,17 +722,17 @@ public: // ancestor of the elements containing the characters is the one whose // CSS 'white-space' property governs. So this records the nearest common // ancestor of mStartFrame and the previous text frame, or null if there // was no previous text frame on this line. nsIFrame* mAncestorControllingInitialBreak; PRInt32 GetContentEnd() { return mEndFrame ? mEndFrame->GetContentOffset() - : mStartFrame->GetFragment()->GetLength(); + : mStartFrame->GetContent()->GetText()->GetLength(); } }; class BreakSink : public nsILineBreakSink { public: BreakSink(gfxTextRun* aTextRun, gfxContext* aContext, PRUint32 aOffsetIntoTextRun, PRBool aExistingTextRun) : mTextRun(aTextRun), mContext(aContext), @@ -929,17 +928,17 @@ BuildTextRunsScanner::FindBoundaries(nsI aState->mLastTextFrame = textFrame; } if (aFrame == aState->mStopAtFrame) return FB_STOPPED_AT_STOP_FRAME; if (textFrame) { if (!aState->mSeenSpaceForLineBreakingOnThisLine) { - const nsTextFragment* frag = textFrame->GetFragment(); + const nsTextFragment* frag = textFrame->GetContent()->GetText(); PRUint32 start = textFrame->GetContentOffset(); const void* text = frag->Is2b() ? static_cast(frag->Get2b() + start) : static_cast(frag->Get1b() + start); if (TextContainsLineBreakerWhiteSpace(text, textFrame->GetContentLength(), frag->Is2b())) { aState->mSeenSpaceForLineBreakingOnThisLine = PR_TRUE; if (aState->mSeenTextRunBoundaryOnLaterLine) @@ -1254,17 +1253,17 @@ void BuildTextRunsScanner::FlushLineBrea } mTextRunsToDelete.Clear(); } void BuildTextRunsScanner::AccumulateRunInfo(nsTextFrame* aFrame) { NS_ASSERTION(mMaxTextLength <= mMaxTextLength + aFrame->GetContentLength(), "integer overflow"); mMaxTextLength += aFrame->GetContentLength(); - mDoubleByteText |= aFrame->GetFragment()->Is2b(); + mDoubleByteText |= aFrame->GetContent()->GetText()->Is2b(); mLastFrame = aFrame; mCommonAncestorWithLastFrame = aFrame->GetParent(); MappedFlow* mappedFlow = &mMappedFlows[mMappedFlows.Length() - 1]; NS_ASSERTION(mappedFlow->mStartFrame == aFrame || mappedFlow->GetContentEnd() == aFrame->GetContentOffset(), "Overlapping or discontiguous frames => BAD"); mappedFlow->mEndFrame = static_cast(aFrame->GetNextContinuation()); @@ -1287,17 +1286,17 @@ static nscoord StyleToCoord(const nsStyl } } static PRBool HasTerminalNewline(const nsTextFrame* aFrame) { if (aFrame->GetContentLength() == 0) return PR_FALSE; - const nsTextFragment* frag = aFrame->GetFragment(); + const nsTextFragment* frag = aFrame->GetContent()->GetText(); return frag->CharAt(aFrame->GetContentEnd() - 1) == '\n'; } PRBool BuildTextRunsScanner::ContinueTextRunAcrossFrames(nsTextFrame* aFrame1, nsTextFrame* aFrame2) { if (mBidiEnabled && NS_GET_EMBEDDING_LEVEL(aFrame1) != NS_GET_EMBEDDING_LEVEL(aFrame2)) @@ -1614,17 +1613,17 @@ BuildTextRunsScanner::BuildTextRunForFra } fontStyle = f->GetStyleFont(); if (NS_STYLE_FONT_VARIANT_SMALL_CAPS == fontStyle->mFont.variant) { anySmallcapsStyle = PR_TRUE; } // Figure out what content is included in this flow. nsIContent* content = f->GetContent(); - const nsTextFragment* frag = f->GetFragment(); + const nsTextFragment* frag = content->GetText(); PRInt32 contentStart = mappedFlow->mStartFrame->GetContentOffset(); PRInt32 contentEnd = mappedFlow->GetContentEnd(); PRInt32 contentLength = contentEnd - contentStart; TextRunMappedFlow* newFlow = &userData->mMappedFlows[i]; newFlow->mStartFrame = mappedFlow->mStartFrame; newFlow->mDOMOffsetToBeforeTransformOffset = builder.GetCharCount() - mappedFlow->mStartFrame->GetContentOffset(); @@ -1860,17 +1859,17 @@ HasCompressedLeadingWhitespace(nsTextFra PRInt32 aContentEndOffset, const gfxSkipCharsIterator& aIterator) { if (!aIterator.IsOriginalCharSkipped()) return PR_FALSE; gfxSkipCharsIterator iter = aIterator; PRInt32 frameContentOffset = aFrame->GetContentOffset(); - const nsTextFragment* frag = aFrame->GetFragment(); + const nsTextFragment* frag = aFrame->GetContent()->GetText(); while (frameContentOffset < aContentEndOffset && iter.IsOriginalCharSkipped()) { if (IsTrimmableSpace(frag, frameContentOffset, aStyleText)) return PR_TRUE; ++frameContentOffset; iter.AdvanceOriginal(1); } return PR_FALSE; } @@ -2232,17 +2231,17 @@ public: /** * Use this constructor after the frame has been reflowed and we don't * have other data around. Gets everything from the frame. EnsureTextRun * *must* be called before this!!! */ PropertyProvider(nsTextFrame* aFrame, const gfxSkipCharsIterator& aStart) : mTextRun(aFrame->GetTextRun()), mFontGroup(nsnull), mTextStyle(aFrame->GetStyleText()), - mFrag(aFrame->GetFragment()), + mFrag(aFrame->GetContent()->GetText()), mLineContainer(nsnull), mFrame(aFrame), mStart(aStart), mTempIterator(aStart), mTabWidths(nsnull), mLength(aFrame->GetContentLength()), mWordSpacing(mTextStyle->mWordSpacing), mLetterSpacing(StyleToCoord(mTextStyle->mLetterSpacing)), mJustificationSpacing(0), mHyphenWidth(-1), @@ -3405,21 +3404,16 @@ NS_IMETHODIMP nsTextFrame::GetAccessible NS_IMETHODIMP nsTextFrame::Init(nsIContent* aContent, nsIFrame* aParent, nsIFrame* aPrevInFlow) { NS_ASSERTION(!aPrevInFlow, "Can't be a continuation!"); NS_PRECONDITION(aContent->IsNodeOfType(nsINode::eTEXT), "Bogus content!"); - - if (!PresContext()->IsDynamic()) { - AddStateBits(TEXT_BLINK_ON_OR_PRINTING); - } - // Since our content has a frame now, this flag is no longer needed. aContent->UnsetFlags(NS_CREATE_FRAME_IF_NON_WHITESPACE); // We're not a continuing frame. // mContentOffset = 0; not necessary since we get zeroed out at init return nsFrame::Init(aContent, aParent, aPrevInFlow); } void @@ -3492,34 +3486,29 @@ protected: }; NS_IMETHODIMP nsContinuingTextFrame::Init(nsIContent* aContent, nsIFrame* aParent, nsIFrame* aPrevInFlow) { NS_ASSERTION(aPrevInFlow, "Must be a continuation!"); - - if (!PresContext()->IsDynamic()) { - AddStateBits(TEXT_BLINK_ON_OR_PRINTING); - } - // NOTE: bypassing nsTextFrame::Init!!! nsresult rv = nsFrame::Init(aContent, aParent, aPrevInFlow); #ifdef IBMBIDI nsTextFrame* nextContinuation = static_cast(aPrevInFlow->GetNextContinuation()); #endif // IBMBIDI // Hook the frame into the flow SetPrevInFlow(aPrevInFlow); aPrevInFlow->SetNextInFlow(this); nsTextFrame* prev = static_cast(aPrevInFlow); mContentOffset = prev->GetContentOffset() + prev->GetContentLengthHint(); - NS_ASSERTION(mContentOffset < PRInt32(GetFragment()->GetLength()), + NS_ASSERTION(mContentOffset < PRInt32(aContent->GetText()->GetLength()), "Creating ContinuingTextFrame, but there is no more content"); if (prev->GetStyleContext() != GetStyleContext()) { // We're taking part of prev's text, and its style may be different // so clear its textrun which may no longer be valid (and don't set ours) prev->ClearTextRun(); } else { mTextRun = prev->GetTextRun(); } @@ -3694,17 +3683,17 @@ NS_NewTextFrame(nsIPresShell* aPresShell nsIFrame* NS_NewContinuingTextFrame(nsIPresShell* aPresShell, nsStyleContext* aContext) { return new (aPresShell) nsContinuingTextFrame(aContext); } nsTextFrame::~nsTextFrame() { - if (0 != (mState & TEXT_BLINK_ON_OR_PRINTING) && PresContext()->IsDynamic()) + if (0 != (mState & TEXT_BLINK_ON)) { nsBlinkTimer::RemoveBlinkFrame(this); } } NS_IMETHODIMP nsTextFrame::GetCursor(const nsPoint& aPoint, nsIFrame::Cursor& aCursor) @@ -3878,17 +3867,17 @@ nsTextFrame::BuildDisplayList(nsDisplayL const nsRect& aDirtyRect, const nsDisplayListSet& aLists) { if (!IsVisibleForPainting(aBuilder)) return NS_OK; DO_GLOBAL_REFLOW_COUNT_DSP("nsTextFrame"); - if ((0 != (mState & TEXT_BLINK_ON_OR_PRINTING)) && nsBlinkTimer::GetBlinkIsOff() && + if ((0 != (mState & TEXT_BLINK_ON)) && nsBlinkTimer::GetBlinkIsOff() && PresContext()->IsDynamic() && !aBuilder->IsForEventDelivery()) return NS_OK; return aLists.Content()->AppendNewToTop(new (aBuilder) nsDisplayText(this)); } static nsIFrame* GetGeneratedContentOwner(nsIFrame* aFrame, PRBool* aIsBefore) @@ -5202,17 +5191,17 @@ PRBool nsTextFrame::PeekOffsetNoAmount(PRBool aForward, PRInt32* aOffset) { NS_ASSERTION(aOffset && *aOffset <= GetContentLength(), "aOffset out of range"); gfxSkipCharsIterator iter = EnsureTextRun(); if (!mTextRun) return PR_FALSE; - TrimmedOffsets trimmed = GetTrimmedOffsets(GetFragment(), PR_TRUE); + TrimmedOffsets trimmed = GetTrimmedOffsets(mContent->GetText(), PR_TRUE); // Check whether there are nonskipped characters in the trimmmed range return iter.ConvertOriginalToSkipped(trimmed.GetEnd()) > iter.ConvertOriginalToSkipped(trimmed.mStart); } /** * This class iterates through the clusters before or after the given * aPosition (which is a content offset). You can test each cluster @@ -5269,17 +5258,17 @@ nsTextFrame::PeekOffsetCharacter(PRBool IsSelectable(&selectable, &selectStyle); if (selectStyle == NS_STYLE_USER_SELECT_ALL) return PR_FALSE; gfxSkipCharsIterator iter = EnsureTextRun(); if (!mTextRun) return PR_FALSE; - TrimmedOffsets trimmed = GetTrimmedOffsets(GetFragment(), PR_FALSE); + TrimmedOffsets trimmed = GetTrimmedOffsets(mContent->GetText(), PR_FALSE); // A negative offset means "end of frame". PRInt32 startOffset = GetContentOffset() + (*aOffset < 0 ? contentLength : *aOffset); if (!aForward) { PRInt32 i; for (i = PR_MIN(trimmed.GetEnd(), startOffset) - 1; i >= trimmed.mStart; --i) { @@ -5384,17 +5373,17 @@ ClusterIterator::ClusterIterator(nsTextF if (!aTextFrame->GetTextRun()) { mDirection = 0; // signal failure return; } mIterator.SetOriginalOffset(aPosition); mCategories = do_GetService(NS_UNICHARCATEGORY_CONTRACTID); - mFrag = aTextFrame->GetFragment(); + mFrag = aTextFrame->GetContent()->GetText(); mTrimmed = aTextFrame->GetTrimmedOffsets(mFrag, PR_TRUE); PRInt32 textOffset = aTextFrame->GetContentOffset(); PRInt32 textLen = aTextFrame->GetContentLength(); if (!mWordBreaks.AppendElements(textLen + 1)) { mDirection = 0; // signal failure return; } @@ -5625,17 +5614,17 @@ nsTextFrame::AddInlineMinWidthForFlow(ns gfxSkipCharsIterator iter = EnsureTextRun(ctx, aData->lineContainer, aData->line, &flowEndInTextRun); if (!mTextRun) return; // Pass null for the line container. This will disable tab spacing, but that's // OK since we can't really handle tabs for intrinsic sizing anyway. const nsStyleText* textStyle = GetStyleText(); - const nsTextFragment* frag = GetFragment(); + const nsTextFragment* frag = mContent->GetText(); PropertyProvider provider(mTextRun, textStyle, frag, this, iter, PR_INT32_MAX, nsnull, 0); PRBool collapseWhitespace = !textStyle->WhiteSpaceIsSignificant(); PRBool preformatNewlines = textStyle->NewlineIsSignificant(); PRBool preformatTabs = textStyle->WhiteSpaceIsSignificant(); gfxFloat tabWidth = -1; PRUint32 start = @@ -5753,17 +5742,17 @@ nsTextFrame::AddInlinePrefWidthForFlow(n EnsureTextRun(ctx, aData->lineContainer, aData->line, &flowEndInTextRun); if (!mTextRun) return; // Pass null for the line container. This will disable tab spacing, but that's // OK since we can't really handle tabs for intrinsic sizing anyway. const nsStyleText* textStyle = GetStyleText(); - const nsTextFragment* frag = GetFragment(); + const nsTextFragment* frag = mContent->GetText(); PropertyProvider provider(mTextRun, textStyle, frag, this, iter, PR_INT32_MAX, nsnull, 0); PRBool collapseWhitespace = !textStyle->WhiteSpaceIsSignificant(); PRBool preformatNewlines = textStyle->NewlineIsSignificant(); PRBool preformatTabs = textStyle->WhiteSpaceIsSignificant(); gfxFloat tabWidth = -1; PRUint32 start = @@ -5991,18 +5980,18 @@ nsTextFrame::Reflow(nsPresContext* aReflowState.availableWidth, aReflowState.availableHeight); #endif ///////////////////////////////////////////////////////////////////// // Set up flags and clear out state ///////////////////////////////////////////////////////////////////// // Clear out the reflow state flags in mState (without destroying - // the TEXT_BLINK_ON_OR_PRINTING bit). We also clear the whitespace flags - // because this can change whether the frame maps whitespace-only text or not. + // the TEXT_BLINK_ON bit). We also clear the whitespace flags because this + // can change whether the frame maps whitespace-only text or not. RemoveStateBits(TEXT_REFLOW_FLAGS | TEXT_WHITESPACE_FLAGS); // Temporarily map all possible content while we construct our new textrun. // so that when doing reflow our styles prevail over any part of the // textrun we look at. Note that next-in-flows may be mapping the same // content; gfxTextRun construction logic will ensure that we take priority. PRInt32 maxContentLength = GetInFlowContentLength(); @@ -6014,39 +6003,39 @@ nsTextFrame::Reflow(nsPresContext* ClearMetrics(aMetrics); aStatus = NS_FRAME_COMPLETE; return NS_OK; } nsLineLayout& lineLayout = *aReflowState.mLineLayout; if (aReflowState.mFlags.mBlinks) { - if (0 == (mState & TEXT_BLINK_ON_OR_PRINTING) && PresContext()->IsDynamic()) { - mState |= TEXT_BLINK_ON_OR_PRINTING; + if (0 == (mState & TEXT_BLINK_ON)) { + mState |= TEXT_BLINK_ON; nsBlinkTimer::AddBlinkFrame(aPresContext, this); } } else { - if (0 != (mState & TEXT_BLINK_ON_OR_PRINTING) && PresContext()->IsDynamic()) { - mState &= ~TEXT_BLINK_ON_OR_PRINTING; + if (0 != (mState & TEXT_BLINK_ON)) { + mState &= ~TEXT_BLINK_ON; nsBlinkTimer::RemoveBlinkFrame(this); } } const nsStyleText* textStyle = GetStyleText(); PRBool atStartOfLine = lineLayout.LineIsEmpty(); if (atStartOfLine) { AddStateBits(TEXT_START_OF_LINE); } PRUint32 flowEndInTextRun; nsIFrame* lineContainer = lineLayout.GetLineContainerFrame(); gfxContext* ctx = aReflowState.rendContext->ThebesContext(); - const nsTextFragment* frag = GetFragment(); + const nsTextFragment* frag = mContent->GetText(); // DOM offsets of the text range we need to measure, after trimming // whitespace, restricting to first-letter, and restricting preformatted text // to nearest newline PRInt32 length = maxContentLength; PRInt32 offset = GetContentOffset(); // Restrict preformatted text to the nearest newline @@ -6446,17 +6435,17 @@ nsTextFrame::TrimTrailingWhiteSpace(nsIR return result; gfxContext* ctx = aRC->ThebesContext(); gfxSkipCharsIterator start = EnsureTextRun(ctx); NS_ENSURE_TRUE(mTextRun, result); PRUint32 trimmedStart = start.GetSkippedOffset(); - const nsTextFragment* frag = GetFragment(); + const nsTextFragment* frag = mContent->GetText(); TrimmedOffsets trimmed = GetTrimmedOffsets(frag, PR_TRUE); gfxSkipCharsIterator trimmedEndIter = start; const nsStyleText* textStyle = GetStyleText(); gfxFloat delta = 0; PRUint32 trimmedEnd = trimmedEndIter.ConvertOriginalToSkipped(trimmed.GetEnd()); if (GetStateBits() & TEXT_TRIMMED_TRAILING_WHITESPACE) { // We pre-trimmed this frame, so the last character is justifiable @@ -6583,17 +6572,17 @@ nsresult nsTextFrame::GetRenderedText(ns gfxSkipChars* aSkipChars, gfxSkipCharsIterator* aSkipIter, PRUint32 aSkippedStartOffset, PRUint32 aSkippedMaxLength) { // The handling of aSkippedStartOffset and aSkippedMaxLength could be more efficient... gfxSkipCharsBuilder skipCharsBuilder; nsTextFrame* textFrame; - const nsTextFragment* textFrag = GetFragment(); + const nsTextFragment* textFrag = mContent->GetText(); PRUint32 keptCharsLength = 0; PRUint32 validCharsLength = 0; // Build skipChars and copy text, for each text frame in this continuation block for (textFrame = this; textFrame; textFrame = static_cast(textFrame->GetNextContinuation())) { // For each text frame continuation in this block ... @@ -6649,17 +6638,17 @@ nsresult nsTextFrame::GetRenderedText(ns } #ifdef DEBUG // Translate the mapped content into a string that's printable void nsTextFrame::ToCString(nsCString& aBuf, PRInt32* aTotalContentLength) const { // Get the frames text content - const nsTextFragment* frag = GetFragment(); + const nsTextFragment* frag = mContent->GetText(); if (!frag) { return; } // Compute the total length of the text content. *aTotalContentLength = frag->GetLength(); PRInt32 contentLength = GetContentLength(); @@ -6709,17 +6698,17 @@ nsTextFrame::IsEmpty() if (mState & TEXT_ISNOT_ONLY_WHITESPACE) { return PR_FALSE; } if (mState & TEXT_IS_ONLY_WHITESPACE) { return PR_TRUE; } - PRBool isEmpty = IsAllWhitespace(GetFragment(), + PRBool isEmpty = IsAllWhitespace(mContent->GetText(), textStyle->mWhiteSpace != NS_STYLE_WHITESPACE_PRE_LINE); mState |= (isEmpty ? TEXT_IS_ONLY_WHITESPACE : TEXT_ISNOT_ONLY_WHITESPACE); return isEmpty; } #ifdef DEBUG NS_IMETHODIMP nsTextFrame::GetFrameName(nsAString& aResult) const @@ -6846,15 +6835,8 @@ nsTextFrame::HasTerminalNewline() const return ::HasTerminalNewline(this); } PRBool nsTextFrame::IsAtEndOfLine() const { return (GetStateBits() & TEXT_END_OF_LINE) != 0; } - -const nsTextFragment* -nsTextFrame::GetFragmentInternal() const -{ - return PresContext()->IsDynamic() ? mContent->GetText() : - nsLayoutUtils::GetTextFragmentForPrinting(this); -} diff --git a/layout/generic/nsVideoFrame.cpp b/layout/generic/nsVideoFrame.cpp --- a/layout/generic/nsVideoFrame.cpp +++ b/layout/generic/nsVideoFrame.cpp @@ -215,37 +215,37 @@ nsVideoFrame::Reflow(nsPresContext* // Reflow the child frames. We may have up to two, an image frame // which is the poster, and a box frame, which is the video controls. for (nsIFrame *child = mFrames.FirstChild(); child; child = child->GetNextSibling()) { if (child->GetType() == nsGkAtoms::imageFrame) { // Reflow the poster frame. nsImageFrame* imageFrame = static_cast(child); - nsHTMLReflowMetrics kidDesiredSize; - nsSize availableSize = nsSize(aReflowState.availableWidth, - aReflowState.availableHeight); - nsHTMLReflowState kidReflowState(aPresContext, - aReflowState, - imageFrame, - availableSize, - aMetrics.width, - aMetrics.height); - if (ShouldDisplayPoster()) { - kidReflowState.SetComputedWidth(aReflowState.ComputedWidth()); - kidReflowState.SetComputedHeight(aReflowState.ComputedHeight()); - } else { - kidReflowState.SetComputedWidth(0); - kidReflowState.SetComputedHeight(0); - } - ReflowChild(imageFrame, aPresContext, kidDesiredSize, kidReflowState, - mBorderPadding.left, mBorderPadding.top, 0, aStatus); - FinishReflowChild(imageFrame, aPresContext, - &kidReflowState, kidDesiredSize, - mBorderPadding.left, mBorderPadding.top, 0); + nsHTMLReflowMetrics kidDesiredSize; + nsSize availableSize = nsSize(aReflowState.availableWidth, + aReflowState.availableHeight); + nsHTMLReflowState kidReflowState(aPresContext, + aReflowState, + imageFrame, + availableSize, + aMetrics.width, + aMetrics.height); + if (ShouldDisplayPoster()) { + kidReflowState.SetComputedWidth(aReflowState.ComputedWidth()); + kidReflowState.SetComputedHeight(aReflowState.ComputedHeight()); + } else { + kidReflowState.SetComputedWidth(0); + kidReflowState.SetComputedHeight(0); + } + ReflowChild(imageFrame, aPresContext, kidDesiredSize, kidReflowState, + mBorderPadding.left, mBorderPadding.top, 0, aStatus); + FinishReflowChild(imageFrame, aPresContext, + &kidReflowState, kidDesiredSize, + mBorderPadding.left, mBorderPadding.top, 0); } else if (child->GetType() == nsGkAtoms::boxFrame) { // Reflow the video controls frame. nsBoxLayoutState boxState(PresContext(), aReflowState.rendContext); nsBoxFrame::LayoutChildAt(boxState, child, nsRect(mBorderPadding.left, mBorderPadding.top, aReflowState.ComputedWidth(), @@ -427,19 +427,19 @@ nsSize nsVideoFrame::GetIntrinsicSize(ns nsIntSize size(300,150); if (ShouldDisplayPoster()) { // Use the poster image frame's size. nsIFrame *child = mFrames.FirstChild(); if (child && child->GetType() == nsGkAtoms::imageFrame) { nsImageFrame* imageFrame = static_cast(child); nsSize imgsize; - imageFrame->GetIntrinsicImageSize(imgsize); - return imgsize; - } + imageFrame->GetIntrinsicImageSize(imgsize); + return imgsize; + } } if (!HasVideoData()) { if (!aRenderingContext || !mFrames.FirstChild()) { // We just want our intrinsic ratio, but audio elements need no // intrinsic ratio, so just return "no ratio". Also, if there's // no controls frame, we prefer to be zero-sized. return nsSize(0, 0); diff --git a/layout/generic/nsVideoFrame.h b/layout/generic/nsVideoFrame.h --- a/layout/generic/nsVideoFrame.h +++ b/layout/generic/nsVideoFrame.h @@ -95,34 +95,36 @@ public: virtual PRBool IsFrameOfType(PRUint32 aFlags) const { return nsSplittableFrame::IsFrameOfType(aFlags & ~(nsIFrame::eReplaced)); } virtual nsresult CreateAnonymousContent(nsTArray& aElements); + nsIContent* GetPosterImage() { return mPosterImage; } + + // Returns PR_TRUE if we should display the poster. Note that once we show + // a video frame, the poster will never be displayed again. + PRBool ShouldDisplayPoster(); + #ifdef DEBUG NS_IMETHOD GetFrameName(nsAString& aResult) const; #endif protected: // Returns PR_TRUE if we're rendering for a video element. We still create // nsVideoFrame to render controls for an audio element. PRBool HasVideoElement(); // Returns PR_TRUE if there is video data to render. Can return false // when we're the frame for an audio element, or we've created a video // element for a media which is audio-only. PRBool HasVideoData(); - - // Returns PR_TRUE if we should display the poster. Note that once we show - // a video frame, the poster will never be displayed again. - PRBool ShouldDisplayPoster(); // Sets the mPosterImage's src attribute to be the video's poster attribute, // if we're the frame for a video element. Only call on frames for video // elements, not for frames for audio elements. nsresult UpdatePosterSource(PRBool aNotify); virtual ~nsVideoFrame(); diff --git a/layout/printing/nsPrintEngine.cpp b/layout/printing/nsPrintEngine.cpp --- a/layout/printing/nsPrintEngine.cpp +++ b/layout/printing/nsPrintEngine.cpp @@ -154,17 +154,17 @@ static const char kPrintingPromptService #include "nsIDOMHTMLLinkElement.h" #include "nsIDOMHTMLImageElement.h" #include "nsIContentViewerContainer.h" #include "nsIContentViewer.h" #include "nsIDocumentViewerPrint.h" #include "nsPIDOMWindow.h" #include "nsFocusManager.h" - +#include "nsRange.h" #include "nsCDefaultURIFixup.h" #include "nsIURIFixup.h" //----------------------------------------------------- // PR LOGGING #ifdef MOZ_LOGGING #define FORCE_PR_LOG /* Allow logging in the release build */ #endif @@ -437,19 +437,20 @@ static void DumpLayoutData(char* aTitleS nsIDocShell * aDocShell, FILE* aFD); #endif //-------------------------------------------------------------------------------- nsresult nsPrintEngine::CommonPrint(PRBool aIsPrintPreview, nsIPrintSettings* aPrintSettings, - nsIWebProgressListener* aWebProgressListener) { + nsIWebProgressListener* aWebProgressListener, + nsIDOMDocument* aDoc) { nsresult rv = DoCommonPrint(aIsPrintPreview, aPrintSettings, - aWebProgressListener); + aWebProgressListener, aDoc); if (NS_FAILED(rv)) { if (aIsPrintPreview) { SetIsCreatingPrintPreview(PR_FALSE); SetIsPrintPreview(PR_FALSE); } else { SetIsPrinting(PR_FALSE); } if (mProgressDialogIsShown) @@ -461,17 +462,18 @@ nsPrintEngine::CommonPrint(PRBool } return rv; } nsresult nsPrintEngine::DoCommonPrint(PRBool aIsPrintPreview, nsIPrintSettings* aPrintSettings, - nsIWebProgressListener* aWebProgressListener) + nsIWebProgressListener* aWebProgressListener, + nsIDOMDocument* aDoc) { nsresult rv; if (aIsPrintPreview) { // The WebProgressListener can be QI'ed to nsIPrintingPromptService // then that means the progress dialog is already being shown. nsCOMPtr pps(do_QueryInterface(aWebProgressListener)); mProgressDialogIsShown = pps != nsnull; @@ -538,27 +540,28 @@ nsPrintEngine::DoCommonPrint(PRBool PRBool isSelection = IsThereARangeSelection(mPrt->mCurrentFocusWin); // Get the docshell for this documentviewer nsCOMPtr webContainer(do_QueryInterface(mContainer, &rv)); NS_ENSURE_SUCCESS(rv, rv); mPrt->mPrintObject = new nsPrintObject(); NS_ENSURE_TRUE(mPrt->mPrintObject, NS_ERROR_OUT_OF_MEMORY); - rv = mPrt->mPrintObject->Init(webContainer); + rv = mPrt->mPrintObject->Init(webContainer, aDoc, aIsPrintPreview); NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_TRUE(mPrt->mPrintDocList.AppendElement(mPrt->mPrintObject), NS_ERROR_OUT_OF_MEMORY); mPrt->mIsParentAFrameSet = IsParentAFrameSet(webContainer); mPrt->mPrintObject->mFrameType = mPrt->mIsParentAFrameSet ? eFrameSet : eDoc; // Build the "tree" of PrintObjects - nsCOMPtr parentAsNode(do_QueryInterface(webContainer)); + nsCOMPtr parentAsNode = + do_QueryInterface(mPrt->mPrintObject->mDocShell); BuildDocTree(parentAsNode, &mPrt->mPrintDocList, mPrt->mPrintObject); // XXX This isn't really correct... if (!mPrt->mPrintObject->mDocument->GetRootContent()) return NS_ERROR_GFX_PRINTER_STARTDOC; // Create the linkage from the sub-docs back to the content element // in the parent document @@ -747,17 +750,18 @@ nsPrintEngine::DoCommonPrint(PRBool return NS_OK; } //--------------------------------------------------------------------------------- NS_IMETHODIMP nsPrintEngine::Print(nsIPrintSettings* aPrintSettings, nsIWebProgressListener* aWebProgressListener) { - return CommonPrint(PR_FALSE, aPrintSettings, aWebProgressListener); + nsCOMPtr doc = do_QueryInterface(mDocument); + return CommonPrint(PR_FALSE, aPrintSettings, aWebProgressListener, doc); } NS_IMETHODIMP nsPrintEngine::PrintPreview(nsIPrintSettings* aPrintSettings, nsIDOMWindow *aChildDOMWin, nsIWebProgressListener* aWebProgressListener) { // Get the DocShell and see if it is busy @@ -768,18 +772,23 @@ nsPrintEngine::PrintPreview(nsIPrintSett PRUint32 busyFlags = nsIDocShell::BUSY_FLAGS_NONE; if (NS_FAILED(docShell->GetBusyFlags(&busyFlags)) || busyFlags != nsIDocShell::BUSY_FLAGS_NONE) { CloseProgressDialog(aWebProgressListener); ShowPrintErrorDialog(NS_ERROR_GFX_PRINTER_DOC_IS_BUSY_PP, PR_FALSE); return NS_ERROR_FAILURE; } + NS_ENSURE_STATE(aChildDOMWin); + nsCOMPtr doc; + aChildDOMWin->GetDocument(getter_AddRefs(doc)); + NS_ENSURE_STATE(doc); + // Document is not busy -- go ahead with the Print Preview - return CommonPrint(PR_TRUE, aPrintSettings, aWebProgressListener); + return CommonPrint(PR_TRUE, aPrintSettings, aWebProgressListener, doc); } //---------------------------------------------------------------------------------- /* readonly attribute boolean isFramesetDocument; */ NS_IMETHODIMP nsPrintEngine::GetIsFramesetDocument(PRBool *aIsFramesetDocument) { nsCOMPtr webContainer(do_QueryInterface(mContainer)); @@ -1087,22 +1096,16 @@ nsPrintEngine::IsThereARangeSelection(ns } return PR_FALSE; } //--------------------------------------------------------------------- PRBool nsPrintEngine::IsParentAFrameSet(nsIDocShell * aParent) { - NS_ASSERTION(aParent, "Pointer is null!"); - - nsCOMPtr shell; - aParent->GetPresShell(getter_AddRefs(shell)); - NS_ASSERTION(shell, "shell can't be null"); - // See if the incoming doc is the root document nsCOMPtr parentAsItem(do_QueryInterface(aParent)); if (!parentAsItem) return PR_FALSE; // When it is the top level document we need to check // to see if it contains a frameset. If it does, then // we only want to print the doc's children and not the document itself // For anything else we always print all the children and the document @@ -1112,23 +1115,22 @@ nsPrintEngine::IsParentAFrameSet(nsIDocS // XXX we really need to search the frame tree, and not the content // but there is no way to distinguish between IFRAMEs and FRAMEs // with the GetFrameType call. // Bug 53459 has been files so we can eventually distinguish // between IFRAME frames and FRAME frames PRBool isFrameSet = PR_FALSE; // only check to see if there is a frameset if there is // NO parent doc for this doc. meaning this parent is the root doc - if (shell) { - nsIDocument *doc = shell->GetDocument(); - if (doc) { - nsIContent *rootContent = doc->GetRootContent(); - if (rootContent) { - isFrameSet = HasFramesetChild(rootContent); - } + nsCOMPtr domDoc = do_GetInterface(aParent); + nsCOMPtr doc = do_QueryInterface(domDoc); + if (doc) { + nsIContent *rootContent = doc->GetRootContent(); + if (rootContent) { + isFrameSet = HasFramesetChild(rootContent); } } return isFrameSet; } //--------------------------------------------------------------------- // Recursively build a list of sub documents to be printed @@ -1152,21 +1154,22 @@ nsPrintEngine::BuildDocTree(nsIDocShellT nsCOMPtr viewer; childAsShell->GetContentViewer(getter_AddRefs(viewer)); if (viewer) { nsCOMPtr viewerFile(do_QueryInterface(viewer)); if (viewerFile) { nsCOMPtr childDocShell(do_QueryInterface(child)); nsCOMPtr childNode(do_QueryInterface(child)); + nsCOMPtr doc = do_GetInterface(childDocShell); nsPrintObject * po = new nsPrintObject(); - nsresult rv = po->Init(childDocShell); + po->mParent = aPO; + nsresult rv = po->Init(childDocShell, doc, aPO->mPrintPreview); if (NS_FAILED(rv)) NS_NOTREACHED("Init failed?"); - po->mParent = aPO; aPO->mKids.AppendElement(po); aDocList->AppendElement(po); BuildDocTree(childNode, aDocList, po); } } } } } @@ -1218,17 +1221,26 @@ nsPrintEngine::MapContentToWebShells(nsP nsPrintObject* aPO) { NS_ASSERTION(aRootPO, "Pointer is null!"); NS_ASSERTION(aPO, "Pointer is null!"); // Recursively walk the content from the root item // XXX Would be faster to enumerate the subdocuments, although right now // nsIDocument doesn't expose quite what would be needed. - nsIContent *rootContent = aPO->mDocument->GetRootContent(); + nsCOMPtr viewer; + aPO->mDocShell->GetContentViewer(getter_AddRefs(viewer)); + if (!viewer) return; + + nsCOMPtr domDoc; + viewer->GetDOMDocument(getter_AddRefs(domDoc)); + nsCOMPtr doc = do_QueryInterface(domDoc); + if (!doc) return; + + nsIContent *rootContent = doc->GetRootContent(); if (rootContent) { MapContentForPO(aPO, rootContent); } else { NS_WARNING("Null root content on (sub)document."); } // Continue recursively walking the chilren of this PO for (PRUint32 i=0;imKids.Length();i++) { @@ -1311,17 +1323,16 @@ nsPrintEngine::MapContentForPO(nsPrintOb po = kid; break; } } // XXX If a subdocument has no onscreen presentation, there will be no PO // This is even if there should be a print presentation if (po) { - po->mContent = aContent; nsCOMPtr frame(do_QueryInterface(aContent)); // "frame" elements not in a frameset context should be treated // as iframes if (frame && po->mParent->mFrameType == eFrameSet) { po->mFrameType = eFrame; } else { // Assume something iframe-like, i.e. iframe, object, or embed @@ -1909,16 +1920,18 @@ nsPrintEngine::ReflowPrintObject(nsPrint nsIView* view = frame->GetView(); NS_ENSURE_TRUE(view, NS_ERROR_FAILURE); view = view->GetFirstChild(); NS_ENSURE_TRUE(view, NS_ERROR_FAILURE); parentView = view; canCreateScrollbars = PR_FALSE; } + NS_ASSERTION(!aPO->mPresContext, "Recreating prescontext"); + // create the PresContext aPO->mPresContext = new nsPresContext(aPO->mDocument, mIsCreatingPrintPreview ? nsPresContext::eContext_PrintPreview: nsPresContext::eContext_Print); NS_ENSURE_TRUE(aPO->mPresContext, NS_ERROR_OUT_OF_MEMORY); aPO->mPresContext->SetPrintSettings(mPrt->mPrintSettings); @@ -1992,16 +2005,23 @@ nsPrintEngine::ReflowPrintObject(nsPrint aPO->mPresContext->SetPageScale(aPO->mZoomRatio); // Calculate scale factor from printer to screen float printDPI = float(mPrt->mPrintDC->AppUnitsPerInch()) / float(mPrt->mPrintDC->AppUnitsPerDevPixel()); float screenDPI = float(mDeviceContext->AppUnitsPerInch()) / float(mDeviceContext->AppUnitsPerDevPixel()); aPO->mPresContext->SetPrintPreviewScale(screenDPI / printDPI); + if (mIsCreatingPrintPreview && documentIsTopLevel) { + mDocViewerPrint->SetPrintPreviewPresentation(aPO->mWindow, + aPO->mViewManager, + aPO->mPresContext, + aPO->mPresShell); + } + rv = aPO->mPresShell->InitialReflow(adjSize.width, adjSize.height); NS_ENSURE_SUCCESS(rv, rv); NS_ASSERTION(aPO->mPresShell, "Presshell should still be here"); // Process the reflow event InitialReflow posted aPO->mPresShell->FlushPendingNotifications(Flush_Layout); @@ -2133,16 +2153,110 @@ nsPrintEngine::PrintDocContent(nsPrintOb if (printed || NS_FAILED(aStatus)) { return PR_TRUE; } } } return PR_FALSE; } +static already_AddRefed +GetEqualNodeInCloneTree(nsIDOMNode* aNode, nsIDocument* aDoc) +{ + nsCOMPtr content = do_QueryInterface(aNode); + // Selections in anonymous subtrees aren't supported. + if (content && content->IsInAnonymousSubtree()) { + return nsnull; + } + + nsCOMPtr node = do_QueryInterface(aNode); + NS_ENSURE_TRUE(node, nsnull); + + nsTArray indexArray; + nsINode* current = node; + NS_ENSURE_TRUE(current, nsnull); + while (current) { + nsINode* parent = current->GetNodeParent(); + if (!parent) { + break; + } + PRInt32 index = parent->IndexOf(current); + NS_ENSURE_TRUE(index >= 0, nsnull); + indexArray.AppendElement(index); + current = parent; + } + NS_ENSURE_TRUE(current->IsNodeOfType(nsINode::eDOCUMENT), nsnull); + + current = aDoc; + for (PRInt32 i = indexArray.Length() - 1; i >= 0; --i) { + current = current->GetChildAt(indexArray[i]); + NS_ENSURE_TRUE(current, nsnull); + } + nsCOMPtr result = do_QueryInterface(current); + return result.forget(); +} + +static nsresult CloneRangeToSelection(nsIDOMRange* aRange, + nsIDocument* aDoc, + nsISelection* aSelection) +{ + PRBool collapsed = PR_FALSE; + aRange->GetCollapsed(&collapsed); + if (collapsed) { + return NS_OK; + } + + nsCOMPtr startContainer, endContainer; + PRInt32 startOffset = -1, endOffset = -1; + aRange->GetStartContainer(getter_AddRefs(startContainer)); + aRange->GetStartOffset(&startOffset); + aRange->GetEndContainer(getter_AddRefs(endContainer)); + aRange->GetEndOffset(&endOffset); + NS_ENSURE_STATE(startContainer && endContainer); + + nsCOMPtr newStart = GetEqualNodeInCloneTree(startContainer, aDoc); + nsCOMPtr newEnd = GetEqualNodeInCloneTree(endContainer, aDoc); + NS_ENSURE_STATE(newStart && newEnd); + + nsCOMPtr range; + NS_NewRange(getter_AddRefs(range)); + NS_ENSURE_TRUE(range, NS_ERROR_OUT_OF_MEMORY); + + nsresult rv = range->SetStart(newStart, startOffset); + NS_ENSURE_SUCCESS(rv, rv); + rv = range->SetEnd(newEnd, endOffset); + NS_ENSURE_SUCCESS(rv, rv); + + return aSelection->AddRange(range); +} + +static nsresult CloneSelection(nsIDocument* aOrigDoc, nsIDocument* aDoc) +{ + nsIPresShell* origShell = aOrigDoc->GetPrimaryShell(); + nsIPresShell* shell = aDoc->GetPrimaryShell(); + NS_ENSURE_STATE(origShell && shell); + + nsCOMPtr origSelection = + origShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL); + nsCOMPtr selection = + shell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL); + NS_ENSURE_STATE(origSelection && selection); + + PRInt32 rangeCount = 0; + origSelection->GetRangeCount(&rangeCount); + for (PRInt32 i = 0; i < rangeCount; ++i) { + nsCOMPtr range; + origSelection->GetRangeAt(i, getter_AddRefs(range)); + if (range) { + CloneRangeToSelection(range, aDoc, selection); + } + } + return NS_OK; +} + //------------------------------------------------------- nsresult nsPrintEngine::DoPrint(nsPrintObject * aPO) { PR_PL(("\n")); PR_PL(("**************************** %s ****************************\n", gFrameTypesStr[aPO->mFrameType])); PR_PL(("****** In DV::DoPrint PO: %p \n", aPO)); @@ -2199,16 +2313,18 @@ nsPrintEngine::DoPrint(nsPrintObject * a if (mPrt->mPrintSettings) { PRUnichar * docTitleStr = nsnull; PRUnichar * docURLStr = nsnull; GetDisplayTitleAndURL(aPO, &docTitleStr, &docURLStr, eDocTitleDefBlank); if (nsIPrintSettings::kRangeSelection == printRangeType) { + CloneSelection(aPO->mDocument->GetOriginalDocument(), aPO->mDocument); + poPresContext->SetIsRenderingOnlySelection(PR_TRUE); // temporarily creating rendering context // which is needed to dinf the selection frames nsCOMPtr rc; mPrt->mPrintDC->CreateRenderingContext(*getter_AddRefs(rc)); // find the starting and ending page numbers // via the selection @@ -2800,18 +2916,20 @@ nsPrintEngine::FindPrintObjectByDOMWin(n NS_ASSERTION(aPO, "Pointer is null!"); // Often the CurFocused DOMWindow is passed in // andit is valid for it to be null, so short circut if (!aDOMWin) { return nsnull; } - nsCOMPtr domWin(do_GetInterface(aPO->mDocShell)); - if (domWin && domWin == aDOMWin) { + nsCOMPtr domDoc; + aDOMWin->GetDocument(getter_AddRefs(domDoc)); + nsCOMPtr doc = do_QueryInterface(domDoc); + if (aPO->mDocument && aPO->mDocument->GetOriginalDocument() == doc) { return aPO; } PRInt32 cnt = aPO->mKids.Length(); for (PRInt32 i = 0; i < cnt; ++i) { nsPrintObject* po = FindPrintObjectByDOMWin(aPO->mKids[i], aDOMWin); if (po) { return po; @@ -2905,17 +3023,18 @@ nsPrintEngine::EnablePOsForPrinting() // check to see if we have a range selection, // as oppose to a insert selection // this means if the user just clicked on the IFrame then // there will not be a selection so we want the entire page to print // // XXX this is sort of a hack right here to make the page // not try to reposition itself when printing selection - nsCOMPtr domWin = do_GetInterface(po->mDocShell); + nsCOMPtr domWin = + do_QueryInterface(po->mDocument->GetOriginalDocument()->GetWindow()); if (!IsThereARangeSelection(domWin)) { printRangeType = nsIPrintSettings::kRangeAllPages; mPrt->mPrintSettings->SetPrintRange(printRangeType); } PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType])); PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable])); PR_PL(("PrintRange: %s \n", gPrintRangeStr[printRangeType])); return NS_OK; @@ -2952,17 +3071,18 @@ nsPrintEngine::EnablePOsForPrinting() // check to see if we have a range selection, // as oppose to a insert selection // this means if the user just clicked on the IFrame then // there will not be a selection so we want the entire page to print // // XXX this is sort of a hack right here to make the page // not try to reposition itself when printing selection - nsCOMPtr domWin = do_GetInterface(po->mDocShell); + nsCOMPtr domWin = + do_QueryInterface(po->mDocument->GetOriginalDocument()->GetWindow()); if (!IsThereARangeSelection(domWin)) { printRangeType = nsIPrintSettings::kRangeAllPages; mPrt->mPrintSettings->SetPrintRange(printRangeType); } PR_PL(("PrintFrameType: %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType])); PR_PL(("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable])); PR_PL(("PrintRange: %s \n", gPrintRangeStr[printRangeType])); return NS_OK; diff --git a/layout/printing/nsPrintEngine.h b/layout/printing/nsPrintEngine.h --- a/layout/printing/nsPrintEngine.h +++ b/layout/printing/nsPrintEngine.h @@ -222,20 +222,22 @@ public: PRBool GetIsCreatingPrintPreview() { return mIsCreatingPrintPreview; } protected: nsresult CommonPrint(PRBool aIsPrintPreview, nsIPrintSettings* aPrintSettings, - nsIWebProgressListener* aWebProgressListener); + nsIWebProgressListener* aWebProgressListener, + nsIDOMDocument* aDoc); nsresult DoCommonPrint(PRBool aIsPrintPreview, nsIPrintSettings* aPrintSettings, - nsIWebProgressListener* aWebProgressListener); + nsIWebProgressListener* aWebProgressListener, + nsIDOMDocument* aDoc); void FirePrintCompletionEvent(); static nsresult GetSeqFrameAndCountPagesInternal(nsPrintObject* aPO, nsIFrame*& aSeqFrame, PRInt32& aCount); static nsresult FindSelectionBoundsWithList(nsPresContext* aPresContext, nsIRenderingContext& aRC, diff --git a/layout/printing/nsPrintObject.cpp b/layout/printing/nsPrintObject.cpp --- a/layout/printing/nsPrintObject.cpp +++ b/layout/printing/nsPrintObject.cpp @@ -34,16 +34,22 @@ * the terms of any one of the MPL, the GPL or the LGPL. * * ***** END LICENSE BLOCK ***** */ #include "nsPrintObject.h" #include "nsIContentViewer.h" #include "nsIDOMDocument.h" #include "nsContentUtils.h" +#include "nsIInterfaceRequestorUtils.h" +#include "nsPIDOMWindow.h" +#include "nsGkAtoms.h" +#include "nsComponentManagerUtils.h" +#include "nsIDocShellTreeOwner.h" +#include "nsIDocShellTreeItem.h" //--------------------------------------------------- //-- nsPrintObject Class Impl //--------------------------------------------------- nsPrintObject::nsPrintObject() : mContent(nsnull), mFrameType(eFrame), mParent(nsnull), mHasBeenPrinted(PR_FALSE), mDontPrint(PR_TRUE), mPrintAsIs(PR_FALSE), mSharedPresShell(PR_FALSE), mInvisible(PR_FALSE), @@ -60,33 +66,59 @@ nsPrintObject::~nsPrintObject() } DestroyPresentation(); } //------------------------------------------------------------------ // Resets PO by destroying the presentation nsresult -nsPrintObject::Init(nsIDocShell* aDocShell) +nsPrintObject::Init(nsIDocShell* aDocShell, nsIDOMDocument* aDoc, + PRBool aPrintPreview) { - mDocShell = aDocShell; + mPrintPreview = aPrintPreview; + + if (mPrintPreview || mParent) { + mDocShell = aDocShell; + } else { + nsCOMPtr owner = do_GetInterface(aDocShell); + nsCOMPtr item = do_QueryInterface(aDocShell); + PRInt32 itemType = 0; + item->GetItemType(&itemType); + // Create a container docshell for printing. + mDocShell = do_CreateInstance("@mozilla.org/docshell;1"); + NS_ENSURE_TRUE(mDocShell, NS_ERROR_OUT_OF_MEMORY); + nsCOMPtr newItem = do_QueryInterface(mDocShell); + newItem->SetItemType(itemType); + newItem->SetTreeOwner(owner); + } NS_ENSURE_TRUE(mDocShell, NS_ERROR_FAILURE); - - nsresult rv; + + nsCOMPtr dummy = do_GetInterface(mDocShell); nsCOMPtr viewer; - rv = mDocShell->GetContentViewer(getter_AddRefs(viewer)); - NS_ENSURE_SUCCESS(rv, rv); - - nsCOMPtr doc; - viewer->GetDOMDocument(getter_AddRefs(doc)); - NS_ENSURE_SUCCESS(rv, rv); - - mDocument = do_QueryInterface(doc); - NS_ENSURE_TRUE(mDocument, NS_ERROR_FAILURE); + mDocShell->GetContentViewer(getter_AddRefs(viewer)); + NS_ENSURE_STATE(viewer); + nsCOMPtr doc = do_QueryInterface(aDoc); + NS_ENSURE_STATE(doc); + + if (mParent) { + nsCOMPtr window = doc->GetWindow(); + if (window) { + mContent = do_QueryInterface(window->GetFrameElementInternal()); + } + mDocument = doc; + return NS_OK; + } + + nsCOMPtr clonedDoc = doc->CloneForPrint(mDocShell); + nsCOMPtr clonedDOMDoc = do_QueryInterface(clonedDoc); + + mDocument = clonedDoc; + viewer->SetDOMDocument(clonedDOMDoc); return NS_OK; } //------------------------------------------------------------------ // Resets PO by destroying the presentation void nsPrintObject::DestroyPresentation() { diff --git a/layout/printing/nsPrintObject.h b/layout/printing/nsPrintObject.h --- a/layout/printing/nsPrintObject.h +++ b/layout/printing/nsPrintObject.h @@ -57,41 +57,42 @@ enum PrintObjectType {eDoc = 0, eFrame class nsPrintObject { public: nsPrintObject(); ~nsPrintObject(); // non-virtual // Methods - nsresult Init(nsIDocShell* aDocShell); + nsresult Init(nsIDocShell* aDocShell, nsIDOMDocument* aDoc, + PRBool aPrintPreview); PRBool IsPrintable() { return !mDontPrint; } void DestroyPresentation(); // Data Members nsCOMPtr mDocShell; nsCOMPtr mDocument; nsCOMPtr mPresContext; nsCOMPtr mPresShell; nsCOMPtr mViewManager; nsCOMPtr mWindow; - nsIContent* mContent; + nsCOMPtr mContent; PrintObjectType mFrameType; nsTArray mKids; nsPrintObject* mParent; PRPackedBool mHasBeenPrinted; PRPackedBool mDontPrint; PRPackedBool mPrintAsIs; PRPackedBool mSharedPresShell; PRPackedBool mInvisible; // Indicates PO is set to not visible by CSS - + PRPackedBool mPrintPreview; float mShrinkRatio; float mZoomRatio; private: nsPrintObject& operator=(const nsPrintObject& aOther); // not implemented }; diff --git a/layout/svg/base/src/nsSVGGlyphFrame.cpp b/layout/svg/base/src/nsSVGGlyphFrame.cpp --- a/layout/svg/base/src/nsSVGGlyphFrame.cpp +++ b/layout/svg/base/src/nsSVGGlyphFrame.cpp @@ -49,17 +49,16 @@ #include "nsSVGPathElement.h" #include "nsSVGPoint.h" #include "nsSVGRect.h" #include "nsDOMError.h" #include "gfxContext.h" #include "gfxMatrix.h" #include "gfxPlatform.h" #include "gfxTextRunWordCache.h" -#include "nsTextFrame.h" struct CharacterPosition { gfxPoint pos; gfxFloat angle; PRBool draw; }; /** @@ -295,20 +294,16 @@ nsSVGGlyphFrame::Init(nsIContent* aConte nsSVGTextContainerFrame *metrics = do_QueryFrame(ancestorFrame); NS_ASSERTION(metrics, "trying to construct an SVGGlyphFrame for an invalid container"); NS_ASSERTION(aContent->IsNodeOfType(nsINode::eTEXT), "trying to construct an SVGGlyphFrame for wrong content element"); #endif /* DEBUG */ - if (!PresContext()->IsDynamic()) { - AddStateBits(NS_STATE_SVG_PRINTING); - } - return nsSVGGlyphFrameBase::Init(aContent, aParent, aPrevInFlow); } nsIAtom * nsSVGGlyphFrame::GetType() const { return nsGkAtoms::svgGlyphFrame; } @@ -635,17 +630,17 @@ nsSVGGlyphFrame::GetCanvasTM() //---------------------------------------------------------------------- // nsSVGGlyphFrame methods: PRBool nsSVGGlyphFrame::GetCharacterData(nsAString & aCharacterData) { nsAutoString characterData; - GetFragment()->AppendTo(characterData); + mContent->AppendTextTo(characterData); if (mWhitespaceHandling & COMPRESS_WHITESPACE) { PRBool trimLeadingWhitespace, trimTrailingWhitespace; trimLeadingWhitespace = ((mWhitespaceHandling & TRIM_LEADING_WHITESPACE) != 0); trimTrailingWhitespace = ((mWhitespaceHandling & TRIM_TRAILING_WHITESPACE) != 0); characterData.CompressWhitespace(trimLeadingWhitespace, trimTrailingWhitespace); } else { @@ -839,17 +834,17 @@ nsSVGGlyphFrame::GetHighlight(PRUint32 * NS_ERROR("nsSVGGlyphFrame::GetHighlight() called by renderer when there is no highlight"); return NS_ERROR_FAILURE; } nsPresContext *presContext = PresContext(); // The selection ranges are relative to the uncompressed text in // the content element. We'll need the text fragment: - const nsTextFragment* fragment = GetFragment(); + const nsTextFragment *fragment = mContent->GetText(); NS_ASSERTION(fragment, "no text"); // get the selection details SelectionDetails *details = nsnull; { nsCOMPtr frameSelection; { nsCOMPtr controller; @@ -1120,17 +1115,17 @@ nsSVGGlyphFrame::IsAbsolutelyPositioned( //---------------------------------------------------------------------- // nsISVGGlyphFragmentNode interface: PRUint32 nsSVGGlyphFrame::GetNumberOfChars() { if (mWhitespaceHandling == PRESERVE_WHITESPACE) - return GetFragment()->GetLength(); + return mContent->TextLength(); nsAutoString text; GetCharacterData(text); return text.Length(); } float nsSVGGlyphFrame::GetComputedTextLength() diff --git a/layout/svg/base/src/nsSVGGlyphFrame.h b/layout/svg/base/src/nsSVGGlyphFrame.h --- a/layout/svg/base/src/nsSVGGlyphFrame.h +++ b/layout/svg/base/src/nsSVGGlyphFrame.h @@ -207,21 +207,16 @@ protected: void NotifyGlyphMetricsChange(); PRBool ContainsPoint(const nsPoint &aPoint); PRBool GetGlobalTransform(gfxMatrix *aMatrix); void SetupGlobalTransform(gfxContext *aContext); nsresult GetHighlight(PRUint32 *charnum, PRUint32 *nchars, nscolor *foreground, nscolor *background); float GetSubStringAdvance(PRUint32 charnum, PRUint32 fragmentChars); gfxFloat GetBaselineOffset(PRBool aForceGlobalTransform); - const nsTextFragment* GetFragment() const - { - return !(GetStateBits() & NS_STATE_SVG_PRINTING) ? - mContent->GetText() : nsLayoutUtils::GetTextFragmentForPrinting(this); - } // Used to support GetBBoxContribution by making GetConvasTM use this as the // parent transform instead of the real CanvasTM. nsCOMPtr mOverrideCanvasTM; // Owning pointer, must call gfxTextRunWordCache::RemoveTextRun before deleting gfxTextRun *mTextRun; gfxPoint mPosition; diff --git a/layout/svg/base/src/nsSVGUtils.h b/layout/svg/base/src/nsSVGUtils.h --- a/layout/svg/base/src/nsSVGUtils.h +++ b/layout/svg/base/src/nsSVGUtils.h @@ -89,19 +89,16 @@ class nsSVGDisplayContainerFrame; #define NS_STATE_SVG_DIRTY 0x00200000 /* are we the child of a non-display container? */ #define NS_STATE_SVG_NONDISPLAY_CHILD 0x00400000 #define NS_STATE_SVG_PROPAGATE_TRANSFORM 0x00800000 -// nsSVGGlyphFrame uses this when the frame is within a non-dynamic PresContext. -#define NS_STATE_SVG_PRINTING 0x01000000 - /** * Byte offsets of channels in a native packed gfxColor or cairo image surface. */ #ifdef IS_BIG_ENDIAN #define GFX_ARGB32_OFFSET_A 0 #define GFX_ARGB32_OFFSET_R 1 #define GFX_ARGB32_OFFSET_G 2 #define GFX_ARGB32_OFFSET_B 3 diff --git a/toolkit/components/printing/content/printPreviewBindings.xml b/toolkit/components/printing/content/printPreviewBindings.xml --- a/toolkit/components/printing/content/printPreviewBindings.xml +++ b/toolkit/components/printing/content/printPreviewBindings.xml @@ -158,17 +158,17 @@