diff --git a/layout/printing/nsPrintJob.cpp b/layout/printing/nsPrintJob.cpp index 97b3e1afd600..83ec247352f3 100644 --- a/layout/printing/nsPrintJob.cpp +++ b/layout/printing/nsPrintJob.cpp @@ -207,6 +207,276 @@ protected: bool mSuppressed; }; +// ------------------------------------------------------- +// Helpers +// ------------------------------------------------------- + +static bool +HasFramesetChild(nsIContent* aContent) +{ + if (!aContent) { + return false; + } + + // do a breadth search across all siblings + for (nsIContent* child = aContent->GetFirstChild(); + child; + child = child->GetNextSibling()) { + if (child->IsHTMLElement(nsGkAtoms::frameset)) { + return true; + } + } + + return false; +} + +static bool +IsParentAFrameSet(nsIDocShell* aParent) +{ + // See if the incoming doc is the root document + if (!aParent) return 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 + // for example, if the doc contains an IFRAME we eant to print the child + // document (the IFRAME) and then the rest of the document. + // + // 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 + bool isFrameSet = 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 + nsCOMPtr doc = aParent->GetDocument(); + if (doc) { + nsIContent *rootElement = doc->GetRootElement(); + if (rootElement) { + isFrameSet = HasFramesetChild(rootElement); + } + } + return isFrameSet; +} + +static nsPrintObject* +FindPrintObjectByDOMWin(nsPrintObject* aPO, + nsPIDOMWindowOuter* aDOMWin) +{ + 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 nullptr; + } + + nsCOMPtr doc = aDOMWin->GetDoc(); + if (aPO->mDocument && aPO->mDocument->GetOriginalDocument() == doc) { + return aPO; + } + + for (const UniquePtr& kid : aPO->mKids) { + nsPrintObject* po = FindPrintObjectByDOMWin(kid.get(), aDOMWin); + if (po) { + return po; + } + } + + return nullptr; +} + +static void +GetDocumentTitleAndURL(nsIDocument* aDoc, + nsAString& aTitle, + nsAString& aURLStr) +{ + NS_ASSERTION(aDoc, "Pointer is null!"); + + aTitle.Truncate(); + aURLStr.Truncate(); + + nsCOMPtr doc = do_QueryInterface(aDoc); + doc->GetTitle(aTitle); + + nsIURI* url = aDoc->GetDocumentURI(); + if (!url) return; + + nsCOMPtr urifixup(do_GetService(NS_URIFIXUP_CONTRACTID)); + if (!urifixup) return; + + nsCOMPtr exposableURI; + urifixup->CreateExposableURI(url, getter_AddRefs(exposableURI)); + + if (!exposableURI) return; + + nsAutoCString urlCStr; + nsresult rv = exposableURI->GetSpec(urlCStr); + if (NS_FAILED(rv)) return; + + nsCOMPtr textToSubURI = + do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv); + if (NS_FAILED(rv)) return; + + textToSubURI->UnEscapeURIForUI(NS_LITERAL_CSTRING("UTF-8"), + urlCStr, aURLStr); +} + +static nsresult +GetSeqFrameAndCountPagesInternal(const UniquePtr& aPO, + nsIFrame*& aSeqFrame, + int32_t& aCount) +{ + NS_ENSURE_ARG_POINTER(aPO); + + // This is sometimes incorrectly called before the pres shell has been created + // (bug 1141756). MOZ_DIAGNOSTIC_ASSERT so we'll still see the crash in + // Nightly/Aurora in case the other patch fixes this. + if (!aPO->mPresShell) { + MOZ_DIAGNOSTIC_ASSERT(false, + "GetSeqFrameAndCountPages needs a non-null pres shell"); + return NS_ERROR_FAILURE; + } + + // Finds the SimplePageSequencer frame + nsIPageSequenceFrame* seqFrame = aPO->mPresShell->GetPageSequenceFrame(); + aSeqFrame = do_QueryFrame(seqFrame); + if (!aSeqFrame) { + return NS_ERROR_FAILURE; + } + + // count the total number of pages + aCount = aSeqFrame->PrincipalChildList().GetLength(); + + return NS_OK; +} + +/** + * Recursively sets the PO items to be printed "As Is" + * from the given item down into the treei + */ +static void +SetPrintAsIs(nsPrintObject* aPO, bool aAsIs = true) +{ + NS_ASSERTION(aPO, "Pointer is null!"); + + aPO->mPrintAsIs = aAsIs; + for (const UniquePtr& kid : aPO->mKids) { + SetPrintAsIs(kid.get(), aAsIs); + } +} + +/** + * This method is key to the entire print mechanism. + * + * This "maps" or figures out which sub-doc represents a + * given Frame or IFrame in its parent sub-doc. + * + * So the Mcontent pointer in the child sub-doc points to the + * content in the its parent document, that caused it to be printed. + * This is used later to (after reflow) to find the absolute location + * of the sub-doc on its parent's page frame so it can be + * printed in the correct location. + * + * This method recursvely "walks" the content for a document finding + * all the Frames and IFrames, then sets the "mFrameType" data member + * which tells us what type of PO we have + */ +static void +MapContentForPO(const UniquePtr& aPO, + nsIContent* aContent) +{ + NS_PRECONDITION(aPO && aContent, "Null argument"); + + nsIDocument* doc = aContent->GetComposedDoc(); + + NS_ASSERTION(doc, "Content without a document from a document tree?"); + + nsIDocument* subDoc = doc->GetSubDocumentFor(aContent); + + if (subDoc) { + nsCOMPtr docShell(subDoc->GetDocShell()); + + if (docShell) { + nsPrintObject * po = nullptr; + for (const UniquePtr& kid : aPO->mKids) { + if (kid->mDocument == subDoc) { + po = kid.get(); + 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) { + // "frame" elements not in a frameset context should be treated + // as iframes + if (aContent->IsHTMLElement(nsGkAtoms::frame) && po->mParent->mFrameType == eFrameSet) { + po->mFrameType = eFrame; + } else { + // Assume something iframe-like, i.e. iframe, object, or embed + po->mFrameType = eIFrame; + SetPrintAsIs(po, true); + NS_ASSERTION(po->mParent, "The root must be a parent"); + po->mParent->mPrintAsIs = true; + } + } + } + } + + // walk children content + for (nsIContent* child = aContent->GetFirstChild(); + child; + child = child->GetNextSibling()) { + MapContentForPO(aPO, child); + } +} + +/** + * The walks the PO tree and for each document it walks the content + * tree looking for any content that are sub-shells + * + * It then sets the mContent pointer in the "found" PO object back to the + * the document that contained it. + */ +static void +MapContentToWebShells(const UniquePtr& aRootPO, + const UniquePtr& 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. + 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; + + Element* rootElement = doc->GetRootElement(); + if (rootElement) { + MapContentForPO(aPO, rootElement); + } else { + NS_WARNING("Null root content on (sub)document."); + } + + // Continue recursively walking the chilren of this PO + for (const UniquePtr& kid : aPO->mKids) { + MapContentToWebShells(aRootPO, kid); + } + +} + + +//------------------------------------------------------- + NS_IMPL_ISUPPORTS(nsPrintJob, nsIWebProgressListener, nsISupportsWeakReference, nsIObserver) @@ -307,36 +577,6 @@ nsPrintJob::InstallPrintPreviewListener() } } -//---------------------------------------------------------------------- -nsresult -nsPrintJob::GetSeqFrameAndCountPagesInternal(const UniquePtr& aPO, - nsIFrame*& aSeqFrame, - int32_t& aCount) -{ - NS_ENSURE_ARG_POINTER(aPO); - - // This is sometimes incorrectly called before the pres shell has been created - // (bug 1141756). MOZ_DIAGNOSTIC_ASSERT so we'll still see the crash in - // Nightly/Aurora in case the other patch fixes this. - if (!aPO->mPresShell) { - MOZ_DIAGNOSTIC_ASSERT(false, - "GetSeqFrameAndCountPages needs a non-null pres shell"); - return NS_ERROR_FAILURE; - } - - // Finds the SimplePageSequencer frame - nsIPageSequenceFrame* seqFrame = aPO->mPresShell->GetPageSequenceFrame(); - aSeqFrame = do_QueryFrame(seqFrame); - if (!aSeqFrame) { - return NS_ERROR_FAILURE; - } - - // count the total number of pages - aCount = aSeqFrame->PrincipalChildList().GetLength(); - - return NS_OK; -} - //----------------------------------------------------------------- nsresult nsPrintJob::GetSeqFrameAndCountPages(nsIFrame*& aSeqFrame, int32_t& aCount) @@ -1140,39 +1380,6 @@ nsPrintJob::IsThereARangeSelection(nsPIDOMWindowOuter* aDOMWin) return selection->GetRangeAt(0) && !selection->IsCollapsed(); } -//--------------------------------------------------------------------- -bool -nsPrintJob::IsParentAFrameSet(nsIDocShell* aParent) -{ - // See if the incoming doc is the root document - if (!aParent) return 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 - // for example, if the doc contains an IFRAME we eant to print the child - // document (the IFRAME) and then the rest of the document. - // - // 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 - bool isFrameSet = 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 - nsCOMPtr doc = aParent->GetDocument(); - if (doc) { - nsIContent *rootElement = doc->GetRootElement(); - if (rootElement) { - isFrameSet = HasFramesetChild(rootElement); - } - } - return isFrameSet; -} - - //--------------------------------------------------------------------- // Recursively build a list of sub documents to be printed // that mirrors the document tree @@ -1210,82 +1417,6 @@ nsPrintJob::BuildDocTree(nsIDocShell* aParentNode, } } -//--------------------------------------------------------------------- -void -nsPrintJob::GetDocumentTitleAndURL(nsIDocument* aDoc, - nsAString& aTitle, - nsAString& aURLStr) -{ - NS_ASSERTION(aDoc, "Pointer is null!"); - - aTitle.Truncate(); - aURLStr.Truncate(); - - nsCOMPtr doc = do_QueryInterface(aDoc); - doc->GetTitle(aTitle); - - nsIURI* url = aDoc->GetDocumentURI(); - if (!url) return; - - nsCOMPtr urifixup(do_GetService(NS_URIFIXUP_CONTRACTID)); - if (!urifixup) return; - - nsCOMPtr exposableURI; - urifixup->CreateExposableURI(url, getter_AddRefs(exposableURI)); - - if (!exposableURI) return; - - nsAutoCString urlCStr; - nsresult rv = exposableURI->GetSpec(urlCStr); - if (NS_FAILED(rv)) return; - - nsCOMPtr textToSubURI = - do_GetService(NS_ITEXTTOSUBURI_CONTRACTID, &rv); - if (NS_FAILED(rv)) return; - - textToSubURI->UnEscapeURIForUI(NS_LITERAL_CSTRING("UTF-8"), - urlCStr, aURLStr); -} - -//--------------------------------------------------------------------- -// The walks the PO tree and for each document it walks the content -// tree looking for any content that are sub-shells -// -// It then sets the mContent pointer in the "found" PO object back to the -// the document that contained it. -void -nsPrintJob::MapContentToWebShells(const UniquePtr& aRootPO, - const UniquePtr& 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. - 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; - - Element* rootElement = doc->GetRootElement(); - if (rootElement) { - MapContentForPO(aPO, rootElement); - } else { - NS_WARNING("Null root content on (sub)document."); - } - - // Continue recursively walking the chilren of this PO - for (const UniquePtr& kid : aPO->mKids) { - MapContentToWebShells(aRootPO, kid); - } - -} - //------------------------------------------------------- // A Frame's sub-doc may contain content or a FrameSet // When it contains a FrameSet the mFrameType for the PrintObject @@ -1319,71 +1450,6 @@ nsPrintJob::CheckForChildFrameSets(const UniquePtr& aPO) } } -//--------------------------------------------------------------------- -// This method is key to the entire print mechanism. -// -// This "maps" or figures out which sub-doc represents a -// given Frame or IFrame in its parent sub-doc. -// -// So the Mcontent pointer in the child sub-doc points to the -// content in the its parent document, that caused it to be printed. -// This is used later to (after reflow) to find the absolute location -// of the sub-doc on its parent's page frame so it can be -// printed in the correct location. -// -// This method recursvely "walks" the content for a document finding -// all the Frames and IFrames, then sets the "mFrameType" data member -// which tells us what type of PO we have -void -nsPrintJob::MapContentForPO(const UniquePtr& aPO, - nsIContent* aContent) -{ - NS_PRECONDITION(aPO && aContent, "Null argument"); - - nsIDocument* doc = aContent->GetComposedDoc(); - - NS_ASSERTION(doc, "Content without a document from a document tree?"); - - nsIDocument* subDoc = doc->GetSubDocumentFor(aContent); - - if (subDoc) { - nsCOMPtr docShell(subDoc->GetDocShell()); - - if (docShell) { - nsPrintObject * po = nullptr; - for (const UniquePtr& kid : aPO->mKids) { - if (kid->mDocument == subDoc) { - po = kid.get(); - 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) { - // "frame" elements not in a frameset context should be treated - // as iframes - if (aContent->IsHTMLElement(nsGkAtoms::frame) && po->mParent->mFrameType == eFrameSet) { - po->mFrameType = eFrame; - } else { - // Assume something iframe-like, i.e. iframe, object, or embed - po->mFrameType = eIFrame; - SetPrintAsIs(po, true); - NS_ASSERTION(po->mParent, "The root must be a parent"); - po->mParent->mPrintAsIs = true; - } - } - } - } - - // walk children content - for (nsIContent* child = aContent->GetFirstChild(); - child; - child = child->GetNextSibling()) { - MapContentForPO(aPO, child); - } -} - //--------------------------------------------------------------------- bool nsPrintJob::IsThereAnIFrameSelected(nsIDocShell* aDocShell, @@ -2919,29 +2985,6 @@ nsPrintJob::CleanupDocTitleArray(char16_t**& aArray, int32_t& aCount) aCount = 0; } -//--------------------------------------------------------------------- -// static -bool -nsPrintJob::HasFramesetChild(nsIContent* aContent) -{ - if (!aContent) { - return false; - } - - // do a breadth search across all siblings - for (nsIContent* child = aContent->GetFirstChild(); - child; - child = child->GetNextSibling()) { - if (child->IsHTMLElement(nsGkAtoms::frameset)) { - return true; - } - } - - return false; -} - - - /** --------------------------------------------------- * Get the Focused Frame for a documentviewer */ @@ -3050,49 +3093,6 @@ nsPrintJob::DonePrintingPages(nsPrintObject* aPO, nsresult aResult) return true; } -//------------------------------------------------------- -// Recursively sets the PO items to be printed "As Is" -// from the given item down into the tree -void -nsPrintJob::SetPrintAsIs(nsPrintObject* aPO, bool aAsIs) -{ - NS_ASSERTION(aPO, "Pointer is null!"); - - aPO->mPrintAsIs = aAsIs; - for (const UniquePtr& kid : aPO->mKids) { - SetPrintAsIs(kid.get(), aAsIs); - } -} - -//------------------------------------------------------- -// Given a DOMWindow it recursively finds the PO object that matches -nsPrintObject* -nsPrintJob::FindPrintObjectByDOMWin(nsPrintObject* aPO, - nsPIDOMWindowOuter* aDOMWin) -{ - 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 nullptr; - } - - nsCOMPtr doc = aDOMWin->GetDoc(); - if (aPO->mDocument && aPO->mDocument->GetOriginalDocument() == doc) { - return aPO; - } - - for (const UniquePtr& kid : aPO->mKids) { - nsPrintObject* po = FindPrintObjectByDOMWin(kid.get(), aDOMWin); - if (po) { - return po; - } - } - - return nullptr; -} - //------------------------------------------------------- nsresult nsPrintJob::EnablePOsForPrinting() diff --git a/layout/printing/nsPrintJob.h b/layout/printing/nsPrintJob.h index 4abed19f2f3e..2edd99537b15 100644 --- a/layout/printing/nsPrintJob.h +++ b/layout/printing/nsPrintJob.h @@ -41,6 +41,9 @@ class nsPrintJob final : public nsIObserver , public nsSupportsWeakReference { public: + static nsresult GetGlobalPrintSettings(nsIPrintSettings** aPrintSettings); + static void CloseProgressDialog(nsIWebProgressListener* aWebProgressListener); + nsPrintJob() = default; // nsISupports interface... @@ -63,7 +66,6 @@ public: NS_IMETHOD GetIsFramesetFrameSelected(bool *aIsFramesetFrameSelected); NS_IMETHOD GetPrintPreviewNumPages(int32_t *aPrintPreviewNumPages); NS_IMETHOD EnumerateDocumentNames(uint32_t* aCount, char16_t*** aResult); - static nsresult GetGlobalPrintSettings(nsIPrintSettings** aPrintSettings); NS_IMETHOD GetDoingPrint(bool *aDoingPrint); NS_IMETHOD GetDoingPrintPreview(bool *aDoingPrintPreview); NS_IMETHOD GetCurrentPrintSettings(nsIPrintSettings **aCurrentPrintSettings); @@ -130,7 +132,6 @@ public: // If FinishPrintPreview() fails, caller may need to reset the state of the // object, for example by calling CleanupOnFailure(). nsresult FinishPrintPreview(); - static void CloseProgressDialog(nsIWebProgressListener* aWebProgressListener); void SetDocAndURLIntoProgress(const mozilla::UniquePtr& aPO, nsIPrintProgressParams* aParams); void EllipseLongString(nsAString& aStr, const uint32_t aLen, bool aDoFront); @@ -147,27 +148,18 @@ public: nsresult StartPagePrintTimer(const mozilla::UniquePtr& aPO); bool IsWindowsInOurSubTree(nsPIDOMWindowOuter* aDOMWindow); - static bool IsParentAFrameSet(nsIDocShell * aParent); bool IsThereAnIFrameSelected(nsIDocShell* aDocShell, nsPIDOMWindowOuter* aDOMWin, bool& aIsParentFrameSet); - static nsPrintObject* FindPrintObjectByDOMWin(nsPrintObject* aParentObject, - nsPIDOMWindowOuter* aDOMWin); - // get the currently infocus frame for the document viewer already_AddRefed FindFocusedDOMWindow(); - static void GetDocumentTitleAndURL(nsIDocument* aDoc, - nsAString& aTitle, - nsAString& aURLStr); void GetDisplayTitleAndURL(const mozilla::UniquePtr& aPO, nsAString& aTitle, nsAString& aURLStr, eDocTitleDefault aDefType); - static bool HasFramesetChild(nsIContent* aContent); - bool CheckBeforeDestroy(); nsresult Cancelled(); @@ -176,8 +168,6 @@ public: float GetPrintPreviewScale() { return mPrtPreview->mPrintObject-> mPresContext->GetPrintPreviewScale(); } - static nsIPresShell* GetPresShellFor(nsIDocShell* aDocShell); - // These calls also update the DocViewer void SetIsPrinting(bool aIsPrinting); bool GetIsPrinting() @@ -213,17 +203,6 @@ private: nsIDOMDocument* aDoc); void FirePrintCompletionEvent(); - static nsresult GetSeqFrameAndCountPagesInternal(const mozilla::UniquePtr& aPO, - nsIFrame*& aSeqFrame, - int32_t& aCount); - - static void MapContentForPO(const mozilla::UniquePtr& aPO, - nsIContent* aContent); - - static void MapContentToWebShells(const mozilla::UniquePtr& aRootPO, - const mozilla::UniquePtr& aPO); - - static void SetPrintAsIs(nsPrintObject* aPO, bool aAsIs = true); void DisconnectPagePrintTimer();