/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 0 -*- * * The contents of this file are subject to the Netscape Public * License Version 1.1 (the "License"); you may not use this file * except in compliance with the License. You may obtain a copy of * the License at http://www.mozilla.org/NPL/ * * Software distributed under the License is distributed on an "AS * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or * implied. See the License for the specific language governing * rights and limitations under the License. * * The Original Code is Mozilla Communicator client code. * * The Initial Developer of the Original Code is Netscape Communications * Corporation. Portions created by Netscape are * Copyright (C) 1998 Netscape Communications Corporation. All * Rights Reserved. * * Contributor(s): * Dan Rosen */ #include "nslayout.h" #include "nsCOMPtr.h" #include "nsCRT.h" #include "nsString.h" #include "nsISupports.h" #include "nsIContent.h" #include "nsIContentViewerContainer.h" #include "nsIDocumentViewer.h" #include "nsIDOMWindowInternal.h" #include "nsIImageGroup.h" #include "nsIImageObserver.h" #include "nsIDocument.h" #include "nsIPresContext.h" #include "nsIPresShell.h" #include "nsIStyleSet.h" #include "nsIStyleSheet.h" #include "nsICSSStyleSheet.h" #include "nsIStyleContext.h" #include "nsIFrame.h" #include "nsIScriptGlobalObjectOwner.h" #include "nsIScriptGlobalObject.h" #include "nsILinkHandler.h" #include "nsIDOMDocument.h" #include "nsISelectionListener.h" #include "nsISelectionPrivate.h" #include "nsIDOMHTMLDocument.h" #include "nsIDOMHTMLElement.h" #include "nsIDOMRange.h" #include "nsContentCID.h" #include "nsLayoutCID.h" #include "nsHTMLParts.h" #include "nsViewsCID.h" #include "nsWidgetsCID.h" #include "nsGfxCIID.h" #include "nsIDeviceContext.h" #include "nsIDeviceContextSpec.h" #include "nsIDeviceContextSpecFactory.h" #include "nsIViewManager.h" #include "nsIView.h" #include "nsIPref.h" #include "nsIPageSequenceFrame.h" #include "nsIURL.h" #include "nsIWebShell.h" #include "nsIContentViewerEdit.h" #include "nsIContentViewerFile.h" #include "nsIMarkupDocumentViewer.h" #include "nsIInterfaceRequestor.h" #include "nsIDocShellTreeItem.h" #include "nsIDocShellTreeNode.h" #include "nsIDocShellTreeOwner.h" #include "nsIDocShell.h" #include "nsIFrameDebug.h" #include "nsILayoutHistoryState.h" #include "nsLayoutAtoms.h" #include "nsIFrameManager.h" #include "nsIParser.h" #include "nsIPrintContext.h" #include "nsIDOMHTMLAnchorElement.h" #include "nsIDOMHTMLImageElement.h" #include "nsIChromeRegistry.h" #include "nsIEventQueueService.h" #include "nsIEventQueue.h" // Timer Includes #include "nsITimer.h" #include "nsITimerCallback.h" #include "nsPIDOMWindow.h" #include "nsIFocusController.h" // Print Options #include "nsIPrintOptions.h" #include "nsGfxCIID.h" #include "nsIServiceManager.h" static NS_DEFINE_CID(kPrintOptionsCID, NS_PRINTOPTIONS_CID); #include "nsHTMLAtoms.h" // XXX until atoms get factored into nsLayoutAtoms // Printing Events #include "nsIEventQueue.h" #include "nsIEventQueueService.h" static NS_DEFINE_CID(kEventQueueServiceCID, NS_EVENTQUEUESERVICE_CID); // Printing #include "nsIDOMHTMLFrameElement.h" #include "nsIDOMHTMLFrameSetElement.h" #include "nsIDOMHTMLIFrameElement.h" // FrameSet #include "nsINodeInfo.h" #include "nsIDocument.h" #include "nsHTMLAtoms.h" #include "nsIHTMLContent.h" #include "nsINameSpaceManager.h" #include "nsIWebShell.h" //focus #include "nsIDOMEventReceiver.h" #include "nsIDOMFocusListener.h" #include "nsISelectionController.h" #include "nsITransformMediator.h" #ifdef IBMBIDI #include "nsIUBidiUtils.h" #endif static NS_DEFINE_CID(kEventQueueService, NS_EVENTQUEUESERVICE_CID); static NS_DEFINE_CID(kPresShellCID, NS_PRESSHELL_CID); static NS_DEFINE_CID(kGalleyContextCID, NS_GALLEYCONTEXT_CID); static NS_DEFINE_CID(kPrintContextCID, NS_PRINTCONTEXT_CID); static NS_DEFINE_CID(kStyleSetCID, NS_STYLESET_CID); #ifdef NS_DEBUG #undef NOISY_VIEWER #else #undef NOISY_VIEWER #endif #if defined(DEBUG_rods) || defined(DEBUG_dcone) #define DEBUG_PRINTING #endif #ifdef DEBUG_PRINTING // XXX NOTE: I am including a header from the layout directory // merely to set up a file pointer for debug logging. This is // fragile and may break in the future, which means it can be // removed if necessary #if defined(XP_PC) #include "../../../layout/html/base/src/nsSimplePageSequence.h" #endif #define PRT_YESNO(_p) ((_p)?"YES":"NO") const char * gFrameTypesStr[] = {"eDoc", "eFrame", "eIFrame", "eFrameSet"}; const char * gPrintFrameTypeStr[] = {"kNoFrames", "kFramesAsIs", "kSelectedFrame", "kEachFrameSep"}; const char * gFrameHowToEnableStr[] = {"kFrameEnableNone", "kFrameEnableAll", "kFrameEnableAsIsAndEach"}; const char * gPrintRangeStr[] = {"kRangeAllPages", "kRangeSpecifiedPageRange", "kRangeSelection", "kRangeFocusFrame"}; #define PRINT_DEBUG_MSG1(_msg1) fprintf(mPrt->mDebugFD, (_msg1)); #define PRINT_DEBUG_MSG2(_msg1, _msg2) fprintf(mPrt->mDebugFD, (_msg1), (_msg2)); #define PRINT_DEBUG_MSG3(_msg1, _msg2, _msg3) fprintf(mPrt->mDebugFD, (_msg1), (_msg2), (_msg3)); #define PRINT_DEBUG_MSG4(_msg1, _msg2, _msg3, _msg4) fprintf(mPrt->mDebugFD, (_msg1), (_msg2), (_msg3), (_msg4)); #define PRINT_DEBUG_MSG5(_msg1, _msg2, _msg3, _msg4, _msg5) fprintf(mPrt->mDebugFD, (_msg1), (_msg2), (_msg3), (_msg4), (_msg5)); #define PRINT_DEBUG_FLUSH fflush(mPrt->mDebugFD); #else //-------------- #define PRT_YESNO(_p) #define PRINT_DEBUG_MSG1(_msg) #define PRINT_DEBUG_MSG2(_msg1, _msg2) #define PRINT_DEBUG_MSG3(_msg1, _msg2, _msg3) #define PRINT_DEBUG_MSG4(_msg1, _msg2, _msg3, _msg4) #define PRINT_DEBUG_MSG5(_msg1, _msg2, _msg3, _msg4, _msg5) #define PRINT_DEBUG_FLUSH #endif enum PrintObjectType {eDoc = 0, eFrame = 1, eIFrame = 2, eFrameSet = 3}; class DocumentViewerImpl; class nsPagePrintTimer; // a small delegate class used to avoid circular references #ifdef XP_MAC #pragma mark ** nsDocViewerSelectionListener ** #endif class nsDocViewerSelectionListener : public nsISelectionListener { public: // nsISupports interface... NS_DECL_ISUPPORTS // nsISelectionListerner interface NS_DECL_NSISELECTIONLISTENER nsDocViewerSelectionListener() : mDocViewer(NULL) , mGotSelectionState(PR_FALSE) , mSelectionWasCollapsed(PR_FALSE) { NS_INIT_REFCNT(); } virtual ~nsDocViewerSelectionListener() {} nsresult Init(DocumentViewerImpl *aDocViewer); protected: DocumentViewerImpl* mDocViewer; PRPackedBool mGotSelectionState; PRPackedBool mSelectionWasCollapsed; }; /** editor Implementation of the FocusListener interface */ class nsDocViewerFocusListener : public nsIDOMFocusListener { public: /** default constructor */ nsDocViewerFocusListener(); /** default destructor */ virtual ~nsDocViewerFocusListener(); /*interfaces for addref and release and queryinterface*/ NS_DECL_ISUPPORTS /*BEGIN implementations of focus event handler interface*/ virtual nsresult HandleEvent(nsIDOMEvent* aEvent); virtual nsresult Focus(nsIDOMEvent* aEvent); virtual nsresult Blur(nsIDOMEvent* aEvent); /*END implementations of focus event handler interface*/ nsresult Init(DocumentViewerImpl *aDocViewer); private: DocumentViewerImpl* mDocViewer; }; #ifdef XP_MAC #pragma mark ** DocumentViewerImpl ** #endif //--------------------------------------------------- //-- PrintObject Class //--------------------------------------------------- struct PrintObject { public: PrintObject(); virtual ~PrintObject(); // Methods PRBool IsPrintable() { return !mDontPrint; } nsIWebShell *mWebShell; PrintObjectType mFrameType; nsIPresContext *mPresContext; nsIStyleSet *mStyleSet; nsIPresShell *mPresShell; nsIViewManager *mViewManager; nsIView *mView; nsIView *mRootView; nsIContent *mContent; nsIFrame *mSeqFrame; nsIFrame *mPageFrame; PRInt32 mPageNum; nsRect mRect; nsRect mReflowRect; nsVoidArray mKids; PrintObject* mParent; PRPackedBool mHasBeenPrinted; PRPackedBool mDontPrint; PRPackedBool mPrintAsIs; PRPackedBool mSkippedPageEject; nsRect mClipRect; }; //--------------------------------------------------- //-- PrintData Class //--------------------------------------------------- struct PrintData { public: PrintData(); virtual ~PrintData(); // Listener Helper Methods void OnEndPrinting(nsresult aResult); void OnStartPrinting(); nsIDeviceContext *mPrintDC; nsIPresContext *mPrintPC; nsIStyleSet *mPrintSS; nsIPresShell *mPrintPS; nsIViewManager *mPrintVM; nsIView *mPrintView; FILE *mFilePointer; // a file where information can go to when printing PrintObject * mPrintObject; PrintObject * mSelectedPO; nsCOMPtr mPrintListener; // An observer for printing... nsVoidArray* mPrintDocList; nsCOMPtr mPrintDocDC; nsCOMPtr mPrintDocDW; PRPackedBool mIsIFrameSelected; PRPackedBool mIsParentAFrameSet; PRPackedBool mPrintingAsIsSubDoc; PRInt16 mPrintFrameType; PRPackedBool mOnStartSent; PRInt32 mNumPrintableDocs; PRInt32 mNumDocsPrinted; PRInt32 mNumPrintablePages; PRInt32 mNumPagesPrinted; #ifdef DEBUG_PRINTING FILE * mDebugFD; #endif }; //------------------------------------------------------------- class DocumentViewerImpl : public nsIDocumentViewer, public nsIContentViewerEdit, public nsIContentViewerFile, public nsIMarkupDocumentViewer, public nsIImageGroupObserver { friend class nsDocViewerSelectionListener; public: DocumentViewerImpl(); DocumentViewerImpl(nsIPresContext* aPresContext); NS_DECL_AND_IMPL_ZEROING_OPERATOR_NEW // nsISupports interface... NS_DECL_ISUPPORTS // nsIContentViewer interface... NS_IMETHOD Init(nsIWidget* aParentWidget, nsIDeviceContext* aDeviceContext, const nsRect& aBounds); NS_IMETHOD BindToDocument(nsISupports* aDoc, const char* aCommand); NS_IMETHOD SetContainer(nsISupports* aContainer); NS_IMETHOD GetContainer(nsISupports** aContainerResult); NS_IMETHOD LoadComplete(nsresult aStatus); NS_IMETHOD Destroy(void); NS_IMETHOD Stop(void); NS_IMETHOD GetDOMDocument(nsIDOMDocument **aResult); NS_IMETHOD SetDOMDocument(nsIDOMDocument *aDocument); NS_IMETHOD GetBounds(nsRect& aResult); NS_IMETHOD SetBounds(const nsRect& aBounds); NS_IMETHOD GetPreviousViewer(nsIContentViewer** aResult); NS_IMETHOD SetPreviousViewer(nsIContentViewer* aViewer); NS_IMETHOD Move(PRInt32 aX, PRInt32 aY); NS_IMETHOD Show(); NS_IMETHOD Hide(); NS_IMETHOD Validate(); NS_IMETHOD SetEnableRendering(PRBool aOn); NS_IMETHOD GetEnableRendering(PRBool* aResult); // nsIDocumentViewer interface... NS_IMETHOD SetUAStyleSheet(nsIStyleSheet* aUAStyleSheet); NS_IMETHOD GetDocument(nsIDocument*& aResult); NS_IMETHOD GetPresShell(nsIPresShell*& aResult); NS_IMETHOD GetPresContext(nsIPresContext*& aResult); NS_IMETHOD CreateDocumentViewerUsing(nsIPresContext* aPresContext, nsIDocumentViewer*& aResult); NS_IMETHOD SetTransformMediator(nsITransformMediator* aMediator); // nsIContentViewerEdit NS_DECL_NSICONTENTVIEWEREDIT // nsIContentViewerFile NS_DECL_NSICONTENTVIEWERFILE // nsIMarkupDocumentViewer NS_DECL_NSIMARKUPDOCUMENTVIEWER typedef void (*CallChildFunc)(nsIMarkupDocumentViewer* aViewer, void* aClosure); nsresult CallChildren(CallChildFunc aFunc, void* aClosure); // nsIImageGroupObserver interface virtual void Notify(nsIImageGroup *aImageGroup, nsImageGroupNotification aNotificationType); // Printing Methods PRBool PrintPage(nsIPresContext* aPresContext, nsIPrintOptions* aPrintOptions, PrintObject* aPOect); PRBool DonePrintingPages(PrintObject* aPO); protected: virtual ~DocumentViewerImpl(); private: void ForceRefresh(void); nsresult CreateStyleSet(nsIDocument* aDocument, nsIStyleSet** aStyleSet); nsresult MakeWindow(nsIWidget* aParentWidget, const nsRect& aBounds); nsresult GetDocumentSelection(nsISelection **aSelection, nsIPresShell * aPresShell = nsnull); nsresult FindFrameSetWithIID(nsIContent * aParentContent, const nsIID& aIID); PRBool IsThereARangeSelection(nsIDOMWindowInternal * aDOMWin); PRBool IsParentAFrameSet(nsIWebShell * aParent); PRBool IsWebShellAFrameSet(nsIWebShell * aParent); PRBool IsThereAnIFrameSelected(nsIWebShell* aWebShell, nsIDOMWindowInternal * aDOMWin, PRPackedBool& aDoesContainFrameset); PRBool IsWindowsInOurSubTree(nsIDOMWindowInternal * aDOMWindow); nsresult GetPopupNode(nsIDOMNode** aNode); nsresult GetPopupLinkNode(nsIDOMNode** aNode); nsresult GetPopupImageNode(nsIDOMNode** aNode); //--------------------------------------------------------------------- void BuildDocTree(nsIDocShellTreeNode * aParentNode, nsVoidArray * aDocList, PrintObject * aPO); nsresult ReflowDocList(PrintObject * aPO); void SetClipRect(PrintObject* aPO, const nsRect& aClipRect, nscoord aOffsetX, nscoord aOffsetY, PRBool aDoingSetClip); nsresult ReflowPrintObject(PrintObject * aPO); void CalcPageFrameLocation(nsIPresShell * aPresShell, PrintObject* aPO); PrintObject * FindPrintObjectByWS(PrintObject* aPO, nsIWebShell * aWebShell); void MapContentForPO(PrintObject* aRootObject, nsIPresShell* aPresShell, nsIContent* aContent); void MapContentToWebShells(PrintObject* aRootPO, PrintObject* aPO); void MapSubDocFrameLocations(PrintObject* aPO); PrintObject* FindPrintObjectByDOMWin(PrintObject* aParentObject, nsIDOMWindowInternal * aDOMWin); void GetPresShellAndRootContent(nsIWebShell * aWebShell, nsIPresShell** aPresShell, nsIContent** aContent); void CalcNumPrintableDocsAndPages(PRInt32& aNumDocs, PRInt32& aNumPages); void DoProgressForAsIsFrames(); void DoProgressForSeparateFrames(); // get the currently infocus frame for the document viewer nsIDOMWindowInternal * FindFocusedDOMWindowInternal(); // get the DOMWindow for a given WebShell nsIDOMWindowInternal * GetDOMWinForWebShell(nsIWebShell* aWebShell); // // The following three methods are used for printing... // nsresult DocumentReadyForPrinting(); //nsresult PrintSelection(nsIDeviceContextSpec * aDevSpec); nsresult GetSelectionDocument(nsIDeviceContextSpec * aDevSpec, nsIDocument ** aNewDoc); void GetWebShellTitleAndURL(nsIWebShell * aWebShell, PRUnichar** aTitle, PRUnichar** aURLStr); static void PR_CALLBACK HandlePLEvent(PLEvent* aEvent); static void PR_CALLBACK DestroyPLEvent(PLEvent* aEvent); nsresult SetupToPrintContent(nsIWebShell* aParent, nsIDeviceContext* aDContext, nsIDOMWindowInternal* aCurrentFocusedDOMWin); nsresult EnablePOsForPrinting(); PRBool PrintDocContent(PrintObject* aPO, nsresult& aStatus); nsresult DoPrint(PrintObject * aPO, PRBool aDoSyncPrinting, PRBool& aDonePrinting); void SetPrintAsIs(PrintObject* aPO, PRBool aAsIs = PR_TRUE); void SetPrintPO(PrintObject* aPO, PRBool aPrint); // Timer Methods nsresult StartPagePrintTimer(nsIPresContext * aPresContext, nsIPrintOptions* aPrintOptions, PrintObject* aPOect, PRUint32 aDelay); void StopPagePrintTimer(); protected: // IMPORTANT: The ownership implicit in the following member // variables has been explicitly checked and set using nsCOMPtr // for owning pointers and raw COM interface pointers for weak // (ie, non owning) references. If you add any members to this // class, please make the ownership explicit (pinkerton, scc). nsISupports* mContainer; // [WEAK] it owns me! nsCOMPtr mDeviceContext; // ??? can't hurt, but... nsIView* mView; // [WEAK] cleaned up by view mgr // the following seven items are explicitly in this order // so they will be destroyed in the reverse order (pinkerton, scc) nsCOMPtr mTransformMediator; nsCOMPtr mDocument; nsCOMPtr mWindow; // ??? should we really own it? nsCOMPtr mViewManager; nsCOMPtr mPresContext; nsCOMPtr mPresShell; nsCOMPtr mUAStyleSheet; nsCOMPtr mSelectionListener; nsCOMPtr mFocusListener; nsCOMPtr mPreviousViewer; PRBool mEnableRendering; PRBool mStopped; PRBool mLoaded; PRInt16 mNumURLStarts; nsIPageSequenceFrame* mPageSeqFrame; PRBool mIsPrinting; PrintData* mPrt; nsPagePrintTimer* mPagePrintTimer; // document management data // these items are specific to markup documents (html and xml) // may consider splitting these out into a subclass PRBool mAllowPlugins; /* character set member data */ nsString mDefaultCharacterSet; nsString mHintCharset; nsCharsetSource mHintCharsetSource; nsString mForceCharacterSet; }; //--------------------------------------------------- //-- Page Timer Class //--------------------------------------------------- class nsPagePrintTimer : public nsITimerCallback { public: NS_DECL_ISUPPORTS nsPagePrintTimer() : mDocViewer(nsnull), mPresContext(nsnull), mPrintOptions(nsnull), mDelay(0) { NS_INIT_ISUPPORTS(); } virtual ~nsPagePrintTimer() { if (mTimer) { mTimer->Cancel(); } } nsresult StartTimer() { nsresult result; mTimer = do_CreateInstance("@mozilla.org/timer;1", &result); if (NS_FAILED(result)) { NS_WARNING("unable to start the timer"); } else { mTimer->Init(this, mDelay, NS_PRIORITY_NORMAL, NS_TYPE_ONE_SHOT); } return result; } // nsITimerCallback NS_IMETHOD_(void) Notify(nsITimer *timer) { if (mPresContext && mDocViewer) { PRPackedBool initNewTimer = PR_TRUE; // Check to see if we are done // donePrinting will be true if it completed successfully or // if the printing was cancelled PRBool donePrinting = mDocViewer->PrintPage(mPresContext, mPrintOptions, mPrintObj); if (donePrinting) { // now clean up print or print the next webshell if (mDocViewer->DonePrintingPages(mPrintObj)) { initNewTimer = PR_FALSE; } } Stop(); if (initNewTimer) { nsresult result = StartTimer(); if (NS_FAILED(result)) { donePrinting = PR_TRUE; // had a failure.. we are finished.. } } } } void Init(DocumentViewerImpl* aDocViewerImpl, nsIPresContext* aPresContext, nsIPrintOptions* aPrintOptions, PrintObject* aPO, PRUint32 aDelay) { mDocViewer = aDocViewerImpl; mPresContext = aPresContext; mPrintOptions = aPrintOptions; mPrintObj = aPO; mDelay = aDelay; } nsresult Start(DocumentViewerImpl* aDocViewerImpl, nsIPresContext* aPresContext, nsIPrintOptions* aPrintOptions, PrintObject* aPO, PRUint32 aDelay) { Init(aDocViewerImpl, aPresContext, aPrintOptions, aPO, aDelay); return StartTimer(); } void Stop() { if (mTimer) mTimer->Cancel(); } private: DocumentViewerImpl* mDocViewer; nsIPresContext* mPresContext; nsIPrintOptions* mPrintOptions; nsCOMPtr mTimer; PRUint32 mDelay; PrintObject * mPrintObj; }; NS_IMPL_ADDREF(nsPagePrintTimer) NS_IMPL_RELEASE(nsPagePrintTimer) NS_IMPL_QUERY_INTERFACE1(nsPagePrintTimer, nsITimerCallback) nsresult NS_NewUpdateTimer(nsPagePrintTimer **aResult) { if (!aResult) return NS_ERROR_NULL_POINTER; *aResult = (nsPagePrintTimer*) new nsPagePrintTimer; if (!aResult) return NS_ERROR_OUT_OF_MEMORY; NS_ADDREF(*aResult); return NS_OK; } //--------------------------------------------------- //-- PrintData Class Impl //--------------------------------------------------- PrintData::PrintData() : mPrintDC(nsnull), mPrintPC(nsnull), mPrintSS(nsnull), mPrintPS(nsnull), mPrintVM(nsnull), mPrintView(nsnull), mFilePointer(nsnull), mPrintObject(nsnull), mSelectedPO(nsnull), mPrintDocList(nsnull), mIsIFrameSelected(PR_FALSE), mIsParentAFrameSet(PR_FALSE), mPrintingAsIsSubDoc(PR_FALSE), mPrintFrameType(nsIPrintOptions::kFramesAsIs), mOnStartSent(PR_FALSE), mNumPrintableDocs(0), mNumDocsPrinted(0), mNumPrintablePages(0), mNumPagesPrinted(0) { #ifdef DEBUG_PRINTING mDebugFD = fopen("printing.log", "w"); #endif } PrintData::~PrintData() { // printing is complete, clean up now if (mPrintPS) { mPrintPS->EndObservingDocument(); } OnEndPrinting(NS_OK); // removes listener if (mPrintPS) { mPrintDC->EndDocument(); #ifdef DEBUG_PRINTING fprintf(mDebugFD, "****************** End Document ************************\n"); #endif } delete mPrintObject; mPrintDocList->Clear(); delete mPrintDocList; NS_IF_RELEASE(mPrintPS); NS_IF_RELEASE(mPrintVM); NS_IF_RELEASE(mPrintSS); NS_IF_RELEASE(mPrintDC); NS_IF_RELEASE(mPrintPC); #ifdef DEBUG_PRINTING fclose(mDebugFD); #endif } void PrintData::OnStartPrinting() { if (mPrintListener) { if (!mOnStartSent) { mPrintListener->OnStartPrinting(); } mOnStartSent = PR_TRUE; } } void PrintData::OnEndPrinting(nsresult aResult) { if (mPrintListener) { if (!mOnStartSent) { mPrintListener->OnStartPrinting(); } mPrintListener->OnEndPrinting(aResult); // clear the lister so the destructor doesn't send the mPrintListener = do_QueryInterface(nsnull); } } //--------------------------------------------------- //-- PrintObject Class Impl //--------------------------------------------------- PrintObject::PrintObject() : mWebShell(nsnull), mFrameType(eFrame), mPresContext(nsnull), mStyleSet(nsnull), mPresShell(nsnull), mViewManager(nsnull), mView(nsnull), mRootView(nsnull), mContent(nsnull), mSeqFrame(nsnull), mPageFrame(nsnull), mPageNum(-1), mRect(0,0,0,0), mReflowRect(0,0,0,0), mParent(nsnull), mHasBeenPrinted(PR_FALSE), mDontPrint(PR_TRUE), mPrintAsIs(PR_FALSE), mSkippedPageEject(PR_FALSE), mClipRect(-1,-1, -1, -1) { } PrintObject::~PrintObject() { NS_IF_RELEASE(mPresShell); NS_IF_RELEASE(mStyleSet); NS_IF_RELEASE(mViewManager); NS_IF_RELEASE(mPresContext); for (PRInt32 i=0;iQueryInterface(NS_GET_IID(nsIDocumentViewer), (void**) aResult); } // Note: operator new zeros our memory DocumentViewerImpl::DocumentViewerImpl() { NS_INIT_ISUPPORTS(); mEnableRendering = PR_TRUE; mStopped = PR_FALSE; mLoaded = PR_FALSE; mPrt = nsnull; mIsPrinting = PR_FALSE; } DocumentViewerImpl::DocumentViewerImpl(nsIPresContext* aPresContext) : mPresContext(dont_QueryInterface(aPresContext)) { NS_INIT_ISUPPORTS(); mHintCharsetSource = kCharsetUninitialized; mAllowPlugins = PR_TRUE; mEnableRendering = PR_TRUE; mPrt = nsnull; mIsPrinting = PR_FALSE; } NS_IMPL_ISUPPORTS5(DocumentViewerImpl, nsIContentViewer, nsIDocumentViewer, nsIMarkupDocumentViewer, nsIContentViewerFile, nsIContentViewerEdit) DocumentViewerImpl::~DocumentViewerImpl() { if (mPagePrintTimer != nsnull) { mPagePrintTimer->Stop(); delete mPagePrintTimer; } if (mPrt != nsnull) { mPrt->OnEndPrinting(NS_ERROR_FAILURE); delete mPrt; } // Revoke pending invalidate events NS_ASSERTION(!mDocument, "User did not call nsIContentViewer::Destroy"); if (mDocument) Destroy(); // clear weak references before we go away if (mPresContext) { mPresContext->SetContainer(nsnull); mPresContext->SetLinkHandler(nsnull); // XXX This is only needed because bg images have not been // converted to the new image lib. Once pav does this, we // can just remove this code. Right now it is only here // for background images. // stop everything but the chrome. mPresContext->Stop(); } // Avoid leaking the old viewer. if (mPreviousViewer) SetPreviousViewer(nsnull); } /* * This method is called by the Document Loader once a document has * been created for a particular data stream... The content viewer * must cache this document for later use when Init(...) is called. */ NS_IMETHODIMP DocumentViewerImpl::BindToDocument(nsISupports *aDoc, const char *aCommand) { NS_PRECONDITION(!mDocument, "Viewer is already bound to a document!"); #ifdef NOISY_VIEWER printf("DocumentViewerImpl::BindToDocument\n"); #endif nsresult rv; mDocument = do_QueryInterface(aDoc,&rv); return rv; } NS_IMETHODIMP DocumentViewerImpl::SetContainer(nsISupports* aContainer) { mContainer = aContainer; if (mPresContext) { mPresContext->SetContainer(aContainer); } return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::GetContainer(nsISupports** aResult) { NS_ENSURE_ARG_POINTER(aResult); *aResult = mContainer; NS_IF_ADDREF(*aResult); return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::Init(nsIWidget* aParentWidget, nsIDeviceContext* aDeviceContext, const nsRect& aBounds) { nsresult rv; NS_ENSURE_TRUE(mDocument, NS_ERROR_NULL_POINTER); mDeviceContext = dont_QueryInterface(aDeviceContext); PRBool makeCX = PR_FALSE; if (!mPresContext) { // Create presentation context #if 1 mPresContext = do_CreateInstance(kGalleyContextCID,&rv); #else // turn on print preview for debugging until print preview is fixed rv = NS_NewPrintPreviewContext(getter_AddRefs(mPresContext)); #endif if (NS_FAILED(rv)) return rv; mPresContext->Init(aDeviceContext); makeCX = PR_TRUE; } nsCOMPtr requestor(do_QueryInterface(mContainer)); if (requestor) { nsCOMPtr linkHandler; requestor->GetInterface(NS_GET_IID(nsILinkHandler), getter_AddRefs(linkHandler)); mPresContext->SetContainer(mContainer); mPresContext->SetLinkHandler(linkHandler); // Set script-context-owner in the document nsCOMPtr owner; requestor->GetInterface(NS_GET_IID(nsIScriptGlobalObjectOwner), getter_AddRefs(owner)); if (nsnull != owner) { nsCOMPtr global; rv = owner->GetScriptGlobalObject(getter_AddRefs(global)); if (NS_SUCCEEDED(rv) && (nsnull != global)) { mDocument->SetScriptGlobalObject(global); nsCOMPtr domdoc(do_QueryInterface(mDocument)); if (nsnull != domdoc) { global->SetNewDocument(domdoc); } } } } // Create the ViewManager and Root View... rv = MakeWindow(aParentWidget, aBounds); Hide(); if (NS_FAILED(rv)) return rv; // Create the style set... nsIStyleSet* styleSet; rv = CreateStyleSet(mDocument, &styleSet); if (NS_FAILED(rv)) return rv; // Now make the shell for the document rv = mDocument->CreateShell(mPresContext, mViewManager, styleSet, getter_AddRefs(mPresShell)); NS_RELEASE(styleSet); if (NS_FAILED(rv)) return rv; mPresShell->BeginObservingDocument(); // Initialize our view manager nsRect bounds; mWindow->GetBounds(bounds); nscoord width = bounds.width; nscoord height = bounds.height; float p2t; mPresContext->GetPixelsToTwips(&p2t); width = NSIntPixelsToTwips(width, p2t); height = NSIntPixelsToTwips(height, p2t); mViewManager->DisableRefresh(); mViewManager->SetWindowDimensions(width, height); if (!makeCX) { // Make shell an observer for next time // XXX - we observe the docuement always, see above after preshell is created // mPresShell->BeginObservingDocument(); //XXX I don't think this should be done *here*; and why paint nothing //(which turns out to cause black flashes!)??? // Resize-reflow this time mPresShell->InitialReflow(width, height); // Now trigger a refresh if (mEnableRendering) { mViewManager->EnableRefresh(NS_VMREFRESH_IMMEDIATE); } } // now register ourselves as a selection listener, so that we get called // when the selection changes in the window nsDocViewerSelectionListener *selectionListener; NS_NEWXPCOM(selectionListener, nsDocViewerSelectionListener); if (!selectionListener) return NS_ERROR_OUT_OF_MEMORY; selectionListener->Init(this); // this is the owning reference. The nsCOMPtr will take care of releasing // our ref to the listener on destruction. NS_ADDREF(selectionListener); rv = selectionListener->QueryInterface(NS_GET_IID(nsISelectionListener), getter_AddRefs(mSelectionListener)); NS_RELEASE(selectionListener); if (NS_FAILED(rv)) return rv; nsCOMPtr selection; rv = GetDocumentSelection(getter_AddRefs(selection)); if (NS_FAILED(rv)) return rv; nsCOMPtr selPrivate(do_QueryInterface(selection)); rv = selPrivate->AddSelectionListener(mSelectionListener); if (NS_FAILED(rv)) return rv; //focus listener // now register ourselves as a focus listener, so that we get called // when the focus changes in the window nsDocViewerFocusListener *focusListener; NS_NEWXPCOM(focusListener, nsDocViewerFocusListener); if (!focusListener) return NS_ERROR_OUT_OF_MEMORY; focusListener->Init(this); // this is the owning reference. The nsCOMPtr will take care of releasing // our ref to the listener on destruction. NS_ADDREF(focusListener); rv = focusListener->QueryInterface(NS_GET_IID(nsIDOMFocusListener), getter_AddRefs(mFocusListener)); NS_RELEASE(focusListener); if (NS_FAILED(rv)) return rv; if(mDocument) { // get the DOM event receiver nsCOMPtr erP; rv = mDocument->QueryInterface(NS_GET_IID(nsIDOMEventReceiver), getter_AddRefs(erP)); if(NS_FAILED(rv) || !erP) return rv?rv:NS_ERROR_FAILURE; rv = erP->AddEventListenerByIID(mFocusListener, NS_GET_IID(nsIDOMFocusListener)); NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register focus listener"); } return rv; } // // LoadComplete(aStatus) // // aStatus - The status returned from loading the document. // // This method is called by the container when the document has been // completely loaded. // NS_IMETHODIMP DocumentViewerImpl::LoadComplete(nsresult aStatus) { nsresult rv = NS_OK; NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE); nsCOMPtr global; // First, get the script global object from the document... rv = mDocument->GetScriptGlobalObject(getter_AddRefs(global)); // Fail if no ScriptGlobalObject is available... NS_ASSERTION(global, "nsIScriptGlobalObject not set for document!"); if (!global) return NS_ERROR_NULL_POINTER; mLoaded = PR_TRUE; // Now, fire either an OnLoad or OnError event to the document... if(NS_SUCCEEDED(aStatus)) { nsEventStatus status = nsEventStatus_eIgnore; nsEvent event; event.eventStructType = NS_EVENT; event.message = NS_PAGE_LOAD; rv = global->HandleDOMEvent(mPresContext, &event, nsnull, NS_EVENT_FLAG_INIT, &status); } else { // XXX: Should fire error event to the document... } // Now that the document has loaded, we can tell the presshell // to unsuppress painting. if (mPresShell && !mStopped) mPresShell->UnsuppressPainting(); return rv; } NS_IMETHODIMP DocumentViewerImpl::Destroy() { // All callers are supposed to call destroy to break circular // references. If we do this stuff in the destructor, the // destructor might never be called (especially if we're being // used from JS. nsresult rv; if (mDocument) { // Break global object circular reference on the document created // in the DocViewer Init nsCOMPtr globalObject; mDocument->GetScriptGlobalObject(getter_AddRefs(globalObject)); if (globalObject) { globalObject->SetNewDocument(nsnull); } // out of band cleanup of webshell mDocument->SetScriptGlobalObject(nsnull); if (mFocusListener) { // get the DOM event receiver nsCOMPtr erP; rv = mDocument->QueryInterface(NS_GET_IID(nsIDOMEventReceiver), getter_AddRefs(erP)); if(NS_SUCCEEDED(rv) && erP) erP->RemoveEventListenerByIID(mFocusListener, NS_GET_IID(nsIDOMFocusListener)); } } if (mDeviceContext) mDeviceContext->FlushFontCache(); if (mPresShell) { // Break circular reference (or something) mPresShell->EndObservingDocument(); nsCOMPtr selection; rv = GetDocumentSelection(getter_AddRefs(selection)); nsCOMPtr selPrivate(do_QueryInterface(selection)); if (NS_SUCCEEDED(rv) && selPrivate && mSelectionListener) selPrivate->RemoveSelectionListener(mSelectionListener); } mDocument = nsnull; return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::Stop(void) { NS_ASSERTION(mDocument, "Stop called too early or too late"); if (mDocument) { mDocument->StopDocumentLoad(); } mStopped = PR_TRUE; if (!mLoaded && mPresShell) { // Well, we might as well paint what we have so far. mPresShell->UnsuppressPainting(); if (mPresContext) { // XXX This is only needed because bg images have not been // converted to the new image lib. Once pav does this, we // can just remove this code. Right now it is only here // for background images. // stop everything but the chrome. mPresContext->Stop(PR_FALSE); } } return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::GetDOMDocument(nsIDOMDocument **aResult) { NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE); return CallQueryInterface(mDocument.get(), aResult); } NS_IMETHODIMP DocumentViewerImpl::SetDOMDocument(nsIDOMDocument *aDocument) { // Assumptions: // // 1) this document viewer has been initialized with a call to Init(). // 2) the stylesheets associated with the document have been added to the document. // XXX Right now, this method assumes that the layout of the current document // hasn't started yet. More cleanup will probably be necessary to make this // method work for the case when layout *has* occurred for the current document. // That work can happen when and if it is needed. nsresult rv; if (nsnull == aDocument) return NS_ERROR_NULL_POINTER; nsCOMPtr newDoc = do_QueryInterface(aDocument, &rv); if (NS_FAILED(rv)) return rv; // 0) Replace the old document with the new one mDocument = newDoc; // 1) Set the script global object on the new document nsCOMPtr requestor(do_QueryInterface(mContainer)); if (requestor) { nsCOMPtr owner; requestor->GetInterface(NS_GET_IID(nsIScriptGlobalObjectOwner), getter_AddRefs(owner)); if (nsnull != owner) { nsCOMPtr global; rv = owner->GetScriptGlobalObject(getter_AddRefs(global)); if (NS_SUCCEEDED(rv) && (nsnull != global)) { mDocument->SetScriptGlobalObject(global); global->SetNewDocument(aDocument); } } } // 2) Create a new style set for the document nsCOMPtr styleSet; rv = CreateStyleSet(mDocument, getter_AddRefs(styleSet)); if (NS_FAILED(rv)) return rv; // 3) Replace the current pres shell with a new shell for the new document mPresShell->EndObservingDocument(); mPresShell = nsnull; rv = newDoc->CreateShell(mPresContext, mViewManager, styleSet, getter_AddRefs(mPresShell)); if (NS_FAILED(rv)) return rv; mPresShell->BeginObservingDocument(); // 4) Register the focus listener on the new document if(mDocument) { nsCOMPtr erP; rv = mDocument->QueryInterface(NS_GET_IID(nsIDOMEventReceiver), getter_AddRefs(erP)); if(NS_FAILED(rv) || !erP) return rv ? rv : NS_ERROR_FAILURE; rv = erP->AddEventListenerByIID(mFocusListener, NS_GET_IID(nsIDOMFocusListener)); NS_ASSERTION(NS_SUCCEEDED(rv), "failed to register focus listener"); } return rv; } NS_IMETHODIMP DocumentViewerImpl::SetUAStyleSheet(nsIStyleSheet* aUAStyleSheet) { mUAStyleSheet = dont_QueryInterface(aUAStyleSheet); return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::GetDocument(nsIDocument*& aResult) { aResult = mDocument; NS_IF_ADDREF(aResult); return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::GetPresShell(nsIPresShell*& aResult) { aResult = mPresShell; NS_IF_ADDREF(aResult); return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::GetPresContext(nsIPresContext*& aResult) { aResult = mPresContext; NS_IF_ADDREF(aResult); return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::GetBounds(nsRect& aResult) { NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE); NS_PRECONDITION(mWindow, "null window"); if (mWindow) { mWindow->GetBounds(aResult); } else { aResult.SetRect(0, 0, 0, 0); } return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::GetPreviousViewer(nsIContentViewer** aViewer) { *aViewer = mPreviousViewer; NS_IF_ADDREF(*aViewer); return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::SetPreviousViewer(nsIContentViewer* aViewer) { if (!aViewer) { // Clearing it out. mPreviousViewer = nsnull; // Now we can show, but only if we aren't dead already (which // can occasionally happen when one page moves to another during the onload // handler.) if (mDocument) Show(); } else { // In a multiple chaining situation (which occurs when running a thrashing // test like i-bench or jrgm's tests with no delay), we can build up a // whole chain of viewers. In order to avoid this, we always set our previous // viewer to the MOST previous viewer in the chain, and then dump the intermediate // link from the chain. This ensures that at most only 2 documents are alive // and undestroyed at any given time (the one that is showing and the one that // is loading with painting suppressed). aViewer->Validate(); nsCOMPtr prevViewer; aViewer->GetPreviousViewer(getter_AddRefs(prevViewer)); if (prevViewer) { SetPreviousViewer(prevViewer); prevViewer->SetPreviousViewer(nsnull); return NS_OK; } } mPreviousViewer = aViewer; return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::SetBounds(const nsRect& aBounds) { NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE); NS_PRECONDITION(mWindow, "null window"); if (mWindow) { // Don't have the widget repaint. Layout will generate repaint requests // during reflow mWindow->Resize(aBounds.x, aBounds.y, aBounds.width, aBounds.height, PR_FALSE); } return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::Move(PRInt32 aX, PRInt32 aY) { NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE); NS_PRECONDITION(mWindow, "null window"); if (mWindow) { mWindow->Move(aX, aY); } return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::Show(void) { NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE); NS_PRECONDITION(mWindow, "null window"); if (mWindow) { mWindow->Show(PR_TRUE); } return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::Hide(void) { NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE); NS_PRECONDITION(mWindow, "null window"); if (mWindow) { mWindow->Show(PR_FALSE); } return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::Validate(void) { NS_PRECONDITION(mWindow, "null window"); if (mWindow) mWindow->Validate(); return NS_OK; } nsresult DocumentViewerImpl::FindFrameSetWithIID(nsIContent * aParentContent, const nsIID& aIID) { PRInt32 numChildren; aParentContent->ChildCount(numChildren); // do a breadth search across all siblings PRInt32 inx; for (inx=0;inx child; if (NS_SUCCEEDED(aParentContent->ChildAt(inx, *getter_AddRefs(child))) && child) { nsCOMPtr temp; if (NS_SUCCEEDED(child->QueryInterface(aIID, (void**)getter_AddRefs(temp)))) { return NS_OK; } } } return NS_ERROR_FAILURE; } /** --------------------------------------------------- * Helper function */ static nsIPresShell* GetPresShellFor(nsIDocShell* aDocShell) { nsIPresShell* shell = nsnull; if (nsnull != aDocShell) { nsIContentViewer* cv = nsnull; aDocShell->GetContentViewer(&cv); if (nsnull != cv) { nsIDocumentViewer* docv = nsnull; cv->QueryInterface(NS_GET_IID(nsIDocumentViewer), (void**) &docv); if (nsnull != docv) { nsIPresContext* cx; docv->GetPresContext(cx); if (nsnull != cx) { cx->GetShell(&shell); NS_RELEASE(cx); } NS_RELEASE(docv); } NS_RELEASE(cv); } } return shell; } //--------------------------------------------------------------- //--------------------------------------------------------------- //-- Debug helper routines //--------------------------------------------------------------- //--------------------------------------------------------------- #ifdef DEBUG_PRINTING /** --------------------------------------------------- * Dumps Frames for Printing */ static void DumpFrames(FILE* out, nsIPresContext* aPresContext, nsIRenderingContext * aRendContext, nsIFrame * aFrame, PRInt32 aLevel) { NS_ASSERTION(out, "Pointer is null!"); NS_ASSERTION(aPresContext, "Pointer is null!"); NS_ASSERTION(aRendContext, "Pointer is null!"); NS_ASSERTION(aFrame, "Pointer is null!"); nsIFrame * child; aFrame->FirstChild(aPresContext, nsnull, &child); while (child != nsnull) { for (PRInt32 i=0;iQueryInterface(NS_GET_IID(nsIFrameDebug), (void**)&frameDebug))) { frameDebug->GetFrameName(tmp); } fputs(tmp, out); nsFrameState state; child->GetFrameState(&state); PRBool isSelected; if (NS_SUCCEEDED(child->IsVisibleForPainting(aPresContext, *aRendContext, PR_TRUE, &isSelected))) { fprintf(out, " %p %s", child, isSelected?"VIS":"UVS"); nsRect rect; child->GetRect(rect); fprintf(out, "[%d,%d,%d,%d] ", rect.x, rect.y, rect.width, rect.height); nsIView * view; child->GetView(aPresContext, &view); fprintf(out, "v: %p ", view); fprintf(out, "\n"); DumpFrames(out, aPresContext, aRendContext, child, aLevel+1); child->GetNextSibling(&child); } } } /** --------------------------------------------------- * Dumps the Views from the DocShell */ static void DumpViews(nsIDocShell* aDocShell, FILE* out) { NS_ASSERTION(aDocShell, "Pointer is null!"); NS_ASSERTION(out, "Pointer is null!"); if (nsnull != aDocShell) { fprintf(out, "docshell=%p \n", aDocShell); nsIPresShell* shell = GetPresShellFor(aDocShell); if (nsnull != shell) { nsCOMPtr vm; shell->GetViewManager(getter_AddRefs(vm)); if (vm) { nsIView* root; vm->GetRootView(root); if (nsnull != root) { root->List(out); } } NS_RELEASE(shell); } else { fputs("null pres shell\n", out); } // dump the views of the sub documents PRInt32 i, n; nsCOMPtr docShellAsNode(do_QueryInterface(aDocShell)); docShellAsNode->GetChildCount(&n); for (i = 0; i < n; i++) { nsCOMPtr child; docShellAsNode->GetChildAt(i, getter_AddRefs(child)); nsCOMPtr childAsShell(do_QueryInterface(child)); if (childAsShell) { DumpViews(childAsShell, out); } } } } /** --------------------------------------------------- * Dumps the Views and Frames */ void DumpLayoutData(nsIPresContext* aPresContext, nsIDeviceContext * aDC, nsIFrame * aRootFrame, nsIWebShell * aWebShell, FILE* aFD = nsnull) { if (aPresContext == nsnull || aDC == nsnull) { return; } NS_ASSERTION(aRootFrame, "Pointer is null!"); NS_ASSERTION(aWebShell, "Pointer is null!"); // Dump all the frames and view to a a file FILE * fd = aFD?aFD:fopen("dump.txt", "w"); if (fd) { fprintf(fd, "--------------- Frames ----------------\n"); nsCOMPtr renderingContext; aDC->CreateRenderingContext(*getter_AddRefs(renderingContext)); DumpFrames(fd, aPresContext, renderingContext, aRootFrame, 0); fprintf(fd, "---------------------------------------\n\n"); fprintf(fd, "--------------- Views From Root Frame----------------\n"); nsIView * v; aRootFrame->GetView(aPresContext, &v); if (v) { v->List(fd); } else { printf("View is null!\n"); } nsCOMPtr docShell(do_QueryInterface(aWebShell)); if (docShell) { fprintf(fd, "--------------- All Views ----------------\n"); DumpViews(docShell, fd); fprintf(fd, "---------------------------------------\n\n"); } if (aFD == nsnull) { fclose(fd); } } } static void DumpPrintObjectsList(nsVoidArray * aDocList, FILE* aFD = nsnull) { NS_ASSERTION(aDocList, "Pointer is null!"); FILE * fd = aFD?aFD:stdout; char * types[] = {"DC", "FR", "IF", "FS"}; fprintf(fd, "Doc List\n***************************************************\n"); fprintf(fd, "T P A H PO WebShell Seq Page Root Page# Rect\n"); PRInt32 cnt = aDocList->Count(); for (PRInt32 i=0;iElementAt(i); NS_ASSERTION(po, "PrintObject can't be null!"); nsIFrame* rootFrame = nsnull; if (po->mPresShell) { po->mPresShell->GetRootFrame(&rootFrame); while (rootFrame != nsnull) { nsIPageSequenceFrame * sqf = nsnull; if (NS_SUCCEEDED(rootFrame->QueryInterface(NS_GET_IID(nsIPageSequenceFrame), (void**)&sqf)) && sqf) { break; } rootFrame->FirstChild(po->mPresContext, nsnull, &rootFrame); } } fprintf(fd, "%s %d %d %d %p %p %p %p %p %d %d,%d,%d,%d\n", types[po->mFrameType], po->IsPrintable(), po->mPrintAsIs, po->mHasBeenPrinted, po, po->mWebShell, po->mSeqFrame, po->mPageFrame, rootFrame, po->mPageNum, po->mRect.x, po->mRect.y, po->mRect.width, po->mRect.height); if (fd != nsnull && fd != stdout) { fprintf(stdout, "%s %d %d %d %p %p %p %p %p %d %d,%d,%d,%d\n", types[po->mFrameType], po->IsPrintable(), po->mPrintAsIs, po->mHasBeenPrinted, po, po->mWebShell, po->mSeqFrame, po->mPageFrame, rootFrame, po->mPageNum, po->mRect.x, po->mRect.y, po->mRect.width, po->mRect.height); } } } static void DumpPrintObjectsTree(PrintObject * aPO, int aLevel= 0, FILE* aFD = nsnull) { NS_ASSERTION(aPO, "Pointer is null!"); FILE * fd = aFD?aFD:stdout; char * types[] = {"DC", "FR", "IF", "FS"}; if (aLevel == 0) { fprintf(fd, "DocTree\n***************************************************\n"); fprintf(fd, "T PO WebShell Seq Page Page# Rect\n"); } PRInt32 cnt = aPO->mKids.Count(); for (PRInt32 i=0;imKids.ElementAt(i); NS_ASSERTION(po, "PrintObject can't be null!"); for (PRInt32 k=0;kmFrameType], po, po->mWebShell, po->mSeqFrame, po->mPageFrame, po->mPageNum, po->mRect.x, po->mRect.y, po->mRect.width, po->mRect.height); } } static void DumpPrintObjectsTreeLayout(PrintObject * aPO, nsIDeviceContext * aDC, int aLevel= 0, FILE * aFD = nsnull) { NS_ASSERTION(aPO, "Pointer is null!"); NS_ASSERTION(aDC, "Pointer is null!"); char * types[] = {"DC", "FR", "IF", "FS"}; FILE * fd = nsnull; if (aLevel == 0) { fd = fopen("tree_layout.txt", "w"); fprintf(fd, "DocTree\n***************************************************\n"); fprintf(fd, "***************************************************\n"); fprintf(fd, "T PO WebShell Seq Page Page# Rect\n"); } else { fd = aFD; } if (fd) { nsIFrame* rootFrame = nsnull; if (aPO->mPresShell != nsnull) { aPO->mPresShell->GetRootFrame(&rootFrame); } for (PRInt32 k=0;kmFrameType], aPO, aPO->mWebShell, aPO->mSeqFrame, aPO->mPageFrame, aPO->mPageNum, aPO->mRect.x, aPO->mRect.y, aPO->mRect.width, aPO->mRect.height); DumpLayoutData(aPO->mPresContext, aDC, rootFrame, aPO->mWebShell, fd); fprintf(fd, "<***************************************************>\n"); PRInt32 cnt = aPO->mKids.Count(); for (PRInt32 i=0;imKids.ElementAt(i); NS_ASSERTION(po, "PrintObject can't be null!"); DumpPrintObjectsTreeLayout(po, aDC, aLevel+1, fd); } } if (aLevel == 0 && fd) { fclose(fd); } } static void DumpPrintObjectsListStart(char * aStr, nsVoidArray * aDocList, FILE* aFD = nsnull) { NS_ASSERTION(aStr, "Pointer is null!"); NS_ASSERTION(aDocList, "Pointer is null!"); FILE * fd = aFD?aFD:stdout; fprintf(fd, "%s\n", aStr); DumpPrintObjectsList(aDocList, aFD); } #define DUMP_DOC_LIST(_title) DumpPrintObjectsListStart((_title), mPrt->mPrintDocList, mPrt->mDebugFD); #define DUMP_DOC_TREE DumpPrintObjectsTree(mPrt->mPrintObject); #define DUMP_DOC_TREELAYOUT DumpPrintObjectsTreeLayout(mPrt->mPrintObject, mPrt->mPrintDC); #else #define DUMP_DOC_LIST #define DUMP_DOC_TREE #define DUMP_DOC_TREELAYOUT #endif //--------------------------------------------------------------- //--------------------------------------------------------------- //-- End of debug helper routines //--------------------------------------------------------------- //--------------------------------------------------------------- /** --------------------------------------------------- * Giving a child frame it searches "up" the tree until it * finds a "Page" frame. */ static nsIFrame * GetPageFrame(nsIFrame * aFrame) { nsIFrame * frame = aFrame; while (frame != nsnull) { nsCOMPtr type; frame->GetFrameType(getter_AddRefs(type)); if (type.get() == nsLayoutAtoms::pageFrame) { return frame; } frame->GetParent(&frame); } return nsnull; } /** --------------------------------------------------- * Find by checking content's tag type */ static nsIFrame * FindFrameByType(nsIPresContext* aPresContext, nsIFrame * aParentFrame, nsIAtom * aType, nsRect& aRect, nsRect& aChildRect) { NS_ASSERTION(aPresContext, "Pointer is null!"); NS_ASSERTION(aParentFrame, "Pointer is null!"); NS_ASSERTION(aType, "Pointer is null!"); nsIFrame * child; nsRect rect; aParentFrame->GetRect(rect); aRect.x += rect.x; aRect.y += rect.y; aParentFrame->FirstChild(aPresContext, nsnull, &child); while (child != nsnull) { nsCOMPtr content; child->GetContent(getter_AddRefs(content)); if (content) { nsCOMPtr type; content->GetTag(*getter_AddRefs(type)); if (type.get() == aType) { nsRect r; child->GetRect(r); aChildRect.SetRect(aRect.x + r.x, aRect.y + r.y, r.width, r.height); aRect.x -= rect.x; aRect.y -= rect.y; return child; } } nsIFrame * fndFrame = FindFrameByType(aPresContext, child, aType, aRect, aChildRect); if (fndFrame != nsnull) { return fndFrame; } child->GetNextSibling(&child); } aRect.x -= rect.x; aRect.y -= rect.y; return nsnull; } /** --------------------------------------------------- * Find by checking frames type */ static nsresult FindSelectionBounds(nsIPresContext* aPresContext, nsIRenderingContext& aRC, nsIFrame * aParentFrame, nsRect& aRect, nsIFrame *& aStartFrame, nsRect& aStartRect, nsIFrame *& aEndFrame, nsRect& aEndRect) { NS_ASSERTION(aPresContext, "Pointer is null!"); NS_ASSERTION(aParentFrame, "Pointer is null!"); nsIFrame * child; aParentFrame->FirstChild(aPresContext, nsnull, &child); nsRect rect; aParentFrame->GetRect(rect); aRect.x += rect.x; aRect.y += rect.y; while (child != nsnull) { nsFrameState state; child->GetFrameState(&state); // only leaf frames have this bit flipped // then check the hard way PRBool isSelected = (state & NS_FRAME_SELECTED_CONTENT) == NS_FRAME_SELECTED_CONTENT; if (isSelected) { if (NS_FAILED(child->IsVisibleForPainting(aPresContext, aRC, PR_TRUE, &isSelected))) { return NS_ERROR_FAILURE; } } if (isSelected) { nsRect r; child->GetRect(r); if (aStartFrame == nsnull) { aStartFrame = child; aStartRect.SetRect(aRect.x + r.x, aRect.y + r.y, r.width, r.height); } else { child->GetRect(r); aEndFrame = child; aEndRect.SetRect(aRect.x + r.x, aRect.y + r.y, r.width, r.height); } } FindSelectionBounds(aPresContext, aRC, child, aRect, aStartFrame, aStartRect, aEndFrame, aEndRect); child->GetNextSibling(&child); } aRect.x -= rect.x; aRect.y -= rect.y; return NS_OK; } /** --------------------------------------------------- * This method finds the starting and ending page numbers * of the selection and also returns rect for each where * the x,y of the rect is relative to the very top of the * frame tree (absolutely positioned) */ static nsresult GetPageRangeForSelection(nsIPresShell * aPresShell, nsIPresContext* aPresContext, nsIRenderingContext& aRC, nsISelection* aSelection, nsIPageSequenceFrame* aPageSeqFrame, nsIFrame** aStartFrame, PRInt32& aStartPageNum, nsRect& aStartRect, nsIFrame** aEndFrame, PRInt32& aEndPageNum, nsRect& aEndRect) { NS_ASSERTION(aPresShell, "Pointer is null!"); NS_ASSERTION(aPresContext, "Pointer is null!"); NS_ASSERTION(aSelection, "Pointer is null!"); NS_ASSERTION(aPageSeqFrame, "Pointer is null!"); NS_ASSERTION(aStartFrame, "Pointer is null!"); NS_ASSERTION(aEndFrame, "Pointer is null!"); nsIFrame * seqFrame; if (NS_FAILED(aPageSeqFrame->QueryInterface(NS_GET_IID(nsIFrame), (void **)&seqFrame))) { return NS_ERROR_FAILURE; } nsIFrame * startFrame = nsnull; nsIFrame * endFrame = nsnull; nsRect rect; seqFrame->GetRect(rect); // start out with the sequence frame and search the entire frame tree // capturing the the starting and ending child frames of the selection // and their rects FindSelectionBounds(aPresContext, aRC, seqFrame, rect, startFrame, aStartRect, endFrame, aEndRect); #ifdef DEBUG_rodsX printf("Start Frame: %p\n", startFrame); printf("End Frame: %p\n", endFrame); #endif // initial the page numbers here // in case we don't find and frames aStartPageNum = -1; aEndPageNum = -1; nsIFrame * startPageFrame; nsIFrame * endPageFrame; // check to make sure we found a starting frame if (startFrame != nsnull) { // Now search up the tree to find what page the // start/ending selections frames are on // // Check to see if start should be same as end if // the end frame comes back null if (endFrame == nsnull) { // XXX the "GetPageFrame" step could be integrated into // the FindSelectionBounds step, but walking up to find // the parent of a child frame isn't expensive and it makes // FindSelectionBounds a little easier to understand startPageFrame = GetPageFrame(startFrame); endPageFrame = startPageFrame; aEndRect = aStartRect; } else { startPageFrame = GetPageFrame(startFrame); endPageFrame = GetPageFrame(endFrame); } } else { return NS_ERROR_FAILURE; } #ifdef DEBUG_rodsX printf("Start Page: %p\n", startPageFrame); printf("End Page: %p\n", endPageFrame); // dump all the pages and their pointers { PRInt32 pageNum = 1; nsIFrame * child; seqFrame->FirstChild(aPresContext, nsnull, &child); while (child != nsnull) { printf("Page: %d - %p\n", pageNum, child); pageNum++; child->GetNextSibling(&child); } } #endif // Now that we have the page frames // find out what the page numbers are for each frame PRInt32 pageNum = 1; nsIFrame * page; seqFrame->FirstChild(aPresContext, nsnull, &page); while (page != nsnull) { if (page == startPageFrame) { aStartPageNum = pageNum; } if (page == endPageFrame) { aEndPageNum = pageNum; } pageNum++; page->GetNextSibling(&page); } #ifdef DEBUG_rodsX printf("Start Page No: %d\n", aStartPageNum); printf("End Page No: %d\n", aEndPageNum); #endif *aStartFrame = startPageFrame; *aEndFrame = endPageFrame; return NS_OK; } //------------------------------------------------------- PRBool DocumentViewerImpl::IsParentAFrameSet(nsIWebShell * aParent) { NS_ASSERTION(aParent, "Pointer is null!"); // See if 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 // 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 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 nsCOMPtr shell; mPresContext->GetShell(getter_AddRefs(shell)); if (shell) { nsCOMPtr doc; shell->GetDocument(getter_AddRefs(doc)); if (doc) { nsCOMPtr rootContent = getter_AddRefs(doc->GetRootContent()); if (rootContent) { if (NS_SUCCEEDED(FindFrameSetWithIID(rootContent, NS_GET_IID(nsIDOMHTMLFrameSetElement)))) { isFrameSet = PR_TRUE; } } } } return isFrameSet; } //------------------------------------------------------- PRBool DocumentViewerImpl::IsWebShellAFrameSet(nsIWebShell * aWebShell) { NS_ASSERTION(aWebShell, "Pointer is null!"); PRBool doesContainFrameSet = PR_FALSE; nsCOMPtr presShell; nsCOMPtr rootContent; GetPresShellAndRootContent(aWebShell, getter_AddRefs(presShell), getter_AddRefs(rootContent)); if (rootContent) { if (NS_SUCCEEDED(FindFrameSetWithIID(rootContent, NS_GET_IID(nsIDOMHTMLFrameSetElement)))) { doesContainFrameSet = PR_TRUE; } } return doesContainFrameSet; } //------------------------------------------------------- void DocumentViewerImpl::GetWebShellTitleAndURL(nsIWebShell * aWebShell, PRUnichar** aTitle, PRUnichar** aURLStr) { NS_ASSERTION(aWebShell, "Pointer is null!"); NS_ASSERTION(aTitle, "Pointer is null!"); NS_ASSERTION(aURLStr, "Pointer is null!"); *aTitle = nsnull; *aURLStr = nsnull; nsCOMPtr docShell(do_QueryInterface(aWebShell)); if (docShell) { nsCOMPtr presShell; docShell->GetPresShell(getter_AddRefs(presShell)); if (presShell) { nsCOMPtr doc; presShell->GetDocument(getter_AddRefs(doc)); if (doc) { const nsString* docTitle = doc->GetDocumentTitle(); if (docTitle != nsnull) { nsAutoString title(docTitle->get()); if (title.Length() > 0) { *aTitle = title.ToNewUnicode(); } } nsCOMPtr url(getter_AddRefs(doc->GetDocumentURL())); if (url) { char * urlCStr; url->GetSpec(&urlCStr); if (urlCStr) { nsAutoString urlStr; urlStr.AssignWithConversion(urlCStr); *aURLStr = urlStr.ToNewUnicode(); nsMemory::Free(urlCStr); } } } } } } //------------------------------------------------------- PRBool DocumentViewerImpl::DonePrintingPages(PrintObject* aPO) { //NS_ASSERTION(aPO, "Pointer is null!"); PRINT_DEBUG_MSG3("****** In DV::DonePrintingPages PO: %p (%s)\n", aPO, gFrameTypesStr[aPO->mFrameType]); if (aPO != nsnull) { aPO->mHasBeenPrinted = PR_TRUE; nsresult rv; PRBool didPrint = PrintDocContent(mPrt->mPrintObject, rv); if (NS_SUCCEEDED(rv) && didPrint) { PRINT_DEBUG_MSG4("****** In DV::DonePrintingPages PO: %p (%s) didPrint:%s (Not Done Printing)\n", aPO, gFrameTypesStr[aPO->mFrameType], PRT_YESNO(didPrint)); return PR_FALSE; } } DoProgressForAsIsFrames(); DoProgressForSeparateFrames(); delete mPrt; mPrt = nsnull; return PR_TRUE; } //------------------------------------------------------- PRBool DocumentViewerImpl::PrintPage(nsIPresContext* aPresContext, nsIPrintOptions* aPrintOptions, PrintObject* aPO) { NS_ASSERTION(aPresContext, "Pointer is null!"); NS_ASSERTION(aPrintOptions, "Pointer is null!"); NS_ASSERTION(aPO, "Pointer is null!"); PRINT_DEBUG_MSG1("-----------------------------------\n"); PRINT_DEBUG_MSG3("------ In DV::PrintPage PO: %p (%s)\n", aPO, gFrameTypesStr[aPO->mFrameType]); nsresult rv; NS_WITH_SERVICE(nsIPrintOptions, printService, kPrintOptionsCID, &rv); if (NS_SUCCEEDED(rv) && printService) { PRBool isCancelled; printService->GetIsCancelled(&isCancelled); // DO NOT allow the print job to be cancelled if it is Print FrameAsIs // because it is only printing one page. if (isCancelled && mPrt->mPrintFrameType != nsIPrintOptions::kFramesAsIs) { printService->SetIsCancelled(PR_FALSE); return PR_TRUE; } } PRInt32 pageNum; PRInt32 curPage; PRInt32 endPage; mPageSeqFrame->GetCurrentPageNum(&pageNum); PRBool donePrinting = PR_FALSE; PRBool isDoingPrintRange; mPageSeqFrame->IsDoingPrintRange(&isDoingPrintRange); if (isDoingPrintRange) { PRInt32 fromPage; PRInt32 toPage; PRInt32 numPages; mPageSeqFrame->GetPrintRange(&fromPage, &toPage); mPageSeqFrame->GetNumPages(&numPages); if (fromPage > numPages) { return PR_TRUE; } if (toPage > numPages) { toPage = numPages; } PRINT_DEBUG_MSG4("****** Printing Page %d printing from %d to page %d\n", pageNum, fromPage, toPage); donePrinting = pageNum >= toPage; curPage = pageNum - fromPage; endPage = toPage - fromPage; } else { PRInt32 numPages; mPageSeqFrame->GetNumPages(&numPages); PRINT_DEBUG_MSG3("****** Printing Page %d of %d page(s)\n", pageNum, numPages); donePrinting = pageNum >= numPages; curPage = pageNum; endPage = numPages; } // NOTE: mPrt->mPrintFrameType gets set to "kFramesAsIs" when a // plain document contains IFrames, so we need to override that case here if (mPrt->mPrintListener) { if (mPrt->mPrintFrameType == nsIPrintOptions::kEachFrameSep) { DoProgressForSeparateFrames(); } else if (mPrt->mPrintFrameType != nsIPrintOptions::kFramesAsIs || mPrt->mPrintObject->mFrameType == eDoc && aPO == mPrt->mPrintObject) { // Make sure the Listener gets a "zero" progress at the beginning // so it can initialize it's state if (curPage == 1) { mPrt->mPrintListener->OnProgressPrinting(0, endPage); } mPrt->mPrintListener->OnProgressPrinting(curPage, endPage); } } // Set Clip when Printing "AsIs" or // when printing an IFrame for SelectedFrame or EachFrame PRBool setClip = PR_FALSE; switch (mPrt->mPrintFrameType) { case nsIPrintOptions::kFramesAsIs: setClip = PR_TRUE; break; case nsIPrintOptions::kSelectedFrame: if (aPO->mPrintAsIs) { if (aPO->mFrameType == eIFrame) { setClip = aPO != mPrt->mSelectedPO; } } break; case nsIPrintOptions::kEachFrameSep: if (aPO->mPrintAsIs) { if (aPO->mFrameType == eIFrame) { setClip = PR_TRUE; } } break; } //switch if (setClip) { mPageSeqFrame->SetClipRect(aPO->mPresContext, &aPO->mClipRect); } // Print the Page mPageSeqFrame->PrintNextPage(aPresContext, aPrintOptions); // Now see if any of the SubDocs are on this page if (aPO->mPrintAsIs) { nsIPageSequenceFrame * curPageSeq = mPageSeqFrame; aPO->mHasBeenPrinted = PR_TRUE; PRInt32 cnt = aPO->mKids.Count(); for (PRInt32 i=0;imKids[i]; NS_ASSERTION(po, "PrintObject can't be null!"); // Now verify that SubDoc's PageNum matches the // page num of it's parent doc curPageSeq->GetCurrentPageNum(&pageNum); nsIFrame* fr; curPageSeq->QueryInterface(NS_GET_IID(nsIFrame), (void**)&fr); if (fr == po->mSeqFrame && pageNum == po->mPageNum) { PRBool donePrintingSubDoc; DoPrint(po, PR_TRUE, donePrintingSubDoc); // synchronous printing, it changes the value mPageSeqFrame po->mHasBeenPrinted = PR_TRUE; } } // while mPageSeqFrame = curPageSeq; if (aPO->mParent == nsnull || (aPO->mParent != nsnull && !aPO->mParent->mPrintAsIs && aPO->mPrintAsIs)) { mPageSeqFrame->DoPageEnd(aPresContext); } // XXX this is because PrintAsIs for FrameSets reflows to two pages // not sure why, but this needs to be fixed. if (aPO->mFrameType == eFrameSet && mPrt->mPrintFrameType == nsIPrintOptions::kFramesAsIs) { return PR_TRUE; } } return donePrinting; } //------------------------------------------------------- // Recursively finds a PrintObject that has the aWebShell PrintObject * DocumentViewerImpl::FindPrintObjectByWS(PrintObject* aPO, nsIWebShell * aWebShell) { NS_ASSERTION(aPO, "Pointer is null!"); NS_ASSERTION(aWebShell, "Pointer is null!"); if (aPO->mWebShell == aWebShell) { return aPO; } PRInt32 cnt = aPO->mKids.Count(); for (PRInt32 i=0;imKids.ElementAt(i); NS_ASSERTION(kid, "PrintObject can't be null!"); PrintObject* po = FindPrintObjectByWS(kid, aWebShell); if (po != nsnull) { return po; } } return nsnull; } //------------------------------------------------------- // Recursively build a list of of sub documents to be printed // that mirrors the document tree void DocumentViewerImpl::BuildDocTree(nsIDocShellTreeNode * aParentNode, nsVoidArray * aDocList, PrintObject * aPO) { NS_ASSERTION(aParentNode, "Pointer is null!"); NS_ASSERTION(aDocList, "Pointer is null!"); NS_ASSERTION(aPO, "Pointer is null!"); PRInt32 childWebshellCount; aParentNode->GetChildCount(&childWebshellCount); if (childWebshellCount > 0) { for (PRInt32 i=0;i child; aParentNode->GetChildAt(i, getter_AddRefs(child)); nsCOMPtr childAsShell(do_QueryInterface(child)); nsCOMPtr viewer; childAsShell->GetContentViewer(getter_AddRefs(viewer)); if (viewer) { nsCOMPtr viewerFile(do_QueryInterface(viewer)); if (viewerFile) { nsCOMPtr childWebShell(do_QueryInterface(child)); nsCOMPtr childNode(do_QueryInterface(child)); PrintObject * po = new PrintObject; po->mWebShell = childWebShell; po->mParent = aPO; aPO->mKids.AppendElement(po); aDocList->AppendElement(po); BuildDocTree(childNode, aDocList, po); } } } } } //------------------------------------------------------- // Recursively sets the PO items to be printed "As Is" // from the given item down into the tree void DocumentViewerImpl::SetPrintAsIs(PrintObject* aPO, PRBool aAsIs) { NS_ASSERTION(aPO, "Pointer is null!"); aPO->mPrintAsIs = aAsIs; for (PRInt32 i=0;imKids.Count();i++) { SetPrintAsIs((PrintObject*)aPO->mKids[i], aAsIs); } } //------------------------------------------------------- // Recursively sets all the PO items to be printed // from the given item down into the tree void DocumentViewerImpl::SetPrintPO(PrintObject* aPO, PRBool aPrint) { NS_ASSERTION(aPO, "Pointer is null!"); aPO->mDontPrint = !aPrint; for (PRInt32 i=0;imKids.Count();i++) { SetPrintPO((PrintObject*)aPO->mKids[i], aPrint); } } //------------------------------------------------------- // Finds the Page Frame and the absolute location on the page // for a Sub document. // // NOTE: This MUST be done after the sub-doc has been laid out // This is called by "MapSubDocFrameLocations" // void DocumentViewerImpl::CalcPageFrameLocation(nsIPresShell * aPresShell, PrintObject* aPO) { NS_ASSERTION(aPresShell, "Pointer is null!"); NS_ASSERTION(aPO, "Pointer is null!"); if (aPO != nsnull && aPO->mContent != nsnull) { // Find that frame for the sub-doc's content element // in the parent document nsIFrame * frame; aPresShell->GetPrimaryFrameFor(aPO->mContent, &frame); NS_ASSERTION(frame, "Frame shouldn't be null!"); nsMargin borderPadding(0, 0, 0, 0); frame->CalcBorderPadding(borderPadding); // Calc absolute position of the frame all the way up // to the SimpleSeq frame nsRect rect; frame->GetRect(rect); rect.Deflate(borderPadding); rect.x = 0; rect.y = 0; nsIFrame * parent = frame; nsIFrame * pageFrame = nsnull; nsIFrame * seqFrame = nsnull; while (parent != nsnull) { nsRect rr; parent->GetRect(rr); rect.x += rr.x; rect.y += rr.y; nsIFrame * temp = parent; temp->GetParent(&parent); // Keep a pointer to the Seq and Page frames nsIPageSequenceFrame * sqf = nsnull; if (parent != nsnull && NS_SUCCEEDED(parent->QueryInterface(NS_GET_IID(nsIPageSequenceFrame), (void**)&sqf)) && sqf) { pageFrame = temp; seqFrame = parent; } } NS_ASSERTION(seqFrame, "The sequencer frame can't be null!"); NS_ASSERTION(pageFrame, "The page frame can't be null!"); // The PageFrame or Seq frame has the margins set // these need to be removed nsresult rv; NS_WITH_SERVICE(nsIPrintOptions, printService, kPrintOptionsCID, &rv); if (NS_SUCCEEDED(rv) && printService) { nsMargin margin(0,0,0,0); printService->GetMarginInTwips(margin); rect.x -= margin.left; rect.y -= margin.top; } // Remember the Frame location information for later aPO->mRect = rect; aPO->mSeqFrame = seqFrame; aPO->mPageFrame = pageFrame; // Calc the Page No it is on PRInt32 pageNum = 1; nsIFrame * child; seqFrame->FirstChild(aPO->mPresContext, nsnull, &child); while (child != nsnull) { if (pageFrame == child) { aPO->mPageNum = pageNum; break; } pageNum++; child->GetNextSibling(&child); } // while } } //------------------------------------------------------- // This recusively walks the PO tree calculating the // the page location and the absolute frame location for // a sub-doc. // // NOTE: This MUST be done after the sub-doc has been laid out // This is called by "ReflowDocList" // void DocumentViewerImpl::MapSubDocFrameLocations(PrintObject* aPO) { NS_ASSERTION(aPO, "Pointer is null!"); if (aPO->mParent != nsnull && aPO->mParent->mPresShell) { CalcPageFrameLocation(aPO->mParent->mPresShell, aPO); } if (aPO->mPresShell != nsnull) { for (PRInt32 i=0;imKids.Count();i++) { MapSubDocFrameLocations((PrintObject*)aPO->mKids[i]); } } } //------------------------------------------------------- // This method is key to the entire print mechanism. // // This "maps" or figures out which sub-doc represents a // given Frame or IFrame in it's parent sub-doc. // // So the Mcontent pointer in the child sub-doc points to the // content in the it's 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 it's 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 DocumentViewerImpl::MapContentForPO(PrintObject* aRootObject, nsIPresShell* aPresShell, nsIContent* aContent) { NS_ASSERTION(aRootObject, "Pointer is null!"); NS_ASSERTION(aPresShell, "Pointer is null!"); NS_ASSERTION(aContent, "Pointer is null!"); nsCOMPtr supps; aPresShell->GetSubShellFor(aContent, getter_AddRefs(supps)); if (supps) { nsCOMPtr webShell(do_QueryInterface(supps)); if (webShell) { PrintObject * po = FindPrintObjectByWS(aRootObject, webShell); NS_ASSERTION(po, "PO can't be null!"); if (po != nsnull) { po->mContent = aContent; // Now, "type" the PO nsCOMPtr frameSet(do_QueryInterface(aContent)); if (frameSet) { po->mFrameType = eFrameSet; } else { nsCOMPtr frame(do_QueryInterface(aContent)); if (frame) { po->mFrameType = eFrame; } else { nsCOMPtr iFrame(do_QueryInterface(aContent)); if (iFrame) { po->mFrameType = eIFrame; po->mPrintAsIs = PR_TRUE; if (po->mParent) { po->mParent->mPrintAsIs = PR_TRUE; } } } } } } } // walk children content PRInt32 count; aContent->ChildCount(count); for (PRInt32 i=0;iChildAt(i, child); MapContentForPO(aRootObject, aPresShell, 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. void DocumentViewerImpl::MapContentToWebShells(PrintObject* aRootPO, PrintObject* aPO) { NS_ASSERTION(aRootPO, "Pointer is null!"); NS_ASSERTION(aPO, "Pointer is null!"); // Recursively walk the content from the root item nsCOMPtr presShell; nsCOMPtr rootContent; GetPresShellAndRootContent(aPO->mWebShell, getter_AddRefs(presShell), getter_AddRefs(rootContent)); if (presShell && rootContent) { MapContentForPO(aRootPO, presShell, rootContent); } // Continue recursively walking the chilren of this PO for (PRInt32 i=0;imKids.Count();i++) { MapContentToWebShells(aRootPO, (PrintObject*)aPO->mKids[i]); } } //------------------------------------------------------- // This gets ref counted copies of the PresShell and Root Content // for a given nsIWebShell void DocumentViewerImpl::GetPresShellAndRootContent(nsIWebShell * aWebShell, nsIPresShell** aPresShell, nsIContent** aContent) { NS_ASSERTION(aWebShell, "Pointer is null!"); NS_ASSERTION(aPresShell, "Pointer is null!"); NS_ASSERTION(aContent, "Pointer is null!"); *aContent = nsnull; *aPresShell = nsnull; nsCOMPtr docShell(do_QueryInterface(aWebShell)); nsCOMPtr presShell(getter_AddRefs(GetPresShellFor(docShell))); if (!presShell) return; nsCOMPtr presContext; presShell->GetPresContext(getter_AddRefs(presContext)); if (!presContext) return; nsCOMPtr doc; presShell->GetDocument(getter_AddRefs(doc)); if (!doc) return; *aContent = doc->GetRootContent(); // this addrefs *aPresShell = presShell.get(); NS_ADDREF(*aPresShell); } //------------------------------------------------------- // Recursively sets the clip rect on all thchildren void DocumentViewerImpl::SetClipRect(PrintObject* aPO, const nsRect& aClipRect, nscoord aOffsetX, nscoord aOffsetY, PRBool aDoingSetClip) { NS_ASSERTION(aPO, "Pointer is null!"); nsRect clipRect = aClipRect; if (aDoingSetClip) { nscoord width = (aPO->mRect.x+aPO->mRect.width) > aClipRect.width?aClipRect.width-aPO->mRect.x:aPO->mRect.width; nscoord height = (aPO->mRect.y+aPO->mRect.height) > aClipRect.height?aClipRect.height-aPO->mRect.y:aPO->mRect.height; aPO->mClipRect.SetRect(aPO->mRect.x, aPO->mRect.y, width, height); } PRBool doClip = aDoingSetClip; if (aPO->mFrameType == eFrame) { if (aDoingSetClip) { aPO->mClipRect.SetRect(aOffsetX, aOffsetY, aPO->mClipRect.width, aPO->mClipRect.height); clipRect = aPO->mClipRect; } else if (mPrt->mPrintFrameType == nsIPrintOptions::kFramesAsIs) { aPO->mClipRect.SetRect(aOffsetX, aOffsetY, aPO->mRect.width, aPO->mRect.height); clipRect = aPO->mClipRect; doClip = PR_TRUE; } } else if (aPO->mFrameType == eIFrame) { if (aDoingSetClip) { aPO->mClipRect.SetRect(aOffsetX, aOffsetY, aPO->mClipRect.width, aPO->mClipRect.height); clipRect = aPO->mClipRect; } else { if (mPrt->mPrintFrameType == nsIPrintOptions::kSelectedFrame) { if (aPO->mParent && aPO->mParent == mPrt->mSelectedPO) { aPO->mClipRect.SetRect(aOffsetX, aOffsetY, aPO->mRect.width, aPO->mRect.height); clipRect = aPO->mClipRect; doClip = PR_TRUE; } } else { aPO->mClipRect.SetRect(aOffsetX, aOffsetY, aPO->mRect.width, aPO->mRect.height); clipRect = aPO->mClipRect; doClip = PR_TRUE; } } } PRINT_DEBUG_MSG3("In DV::SetClipRect PO: %p (%9s) ", aPO, gFrameTypesStr[aPO->mFrameType]); PRINT_DEBUG_MSG5("%5d,%5d,%5d,%5d\n", aPO->mClipRect.x, aPO->mClipRect.y,aPO->mClipRect.width, aPO->mClipRect.height); PRInt32 cnt = aPO->mKids.Count(); for (PRInt32 i=0;imKids[i], clipRect, aOffsetX+aPO->mRect.x, aOffsetY+aPO->mRect.y, doClip); } } //------------------------------------------------------- // Recursively reflow each sub-doc and then calc // all the frame locations of the sub-docs nsresult DocumentViewerImpl::ReflowDocList(PrintObject* aPO) { NS_ASSERTION(aPO, "Pointer is null!"); // Reflow the PO if (NS_FAILED(ReflowPrintObject(aPO))) { return NS_ERROR_FAILURE; } // Calc the absolute poistion of the frames MapSubDocFrameLocations(aPO); PRInt32 cnt = aPO->mKids.Count(); for (PRInt32 i=0;imKids[i]))) { return NS_ERROR_FAILURE; } } return NS_OK; } //------------------------------------------------------- // Reflow a PrintObject nsresult DocumentViewerImpl::ReflowPrintObject(PrintObject * aPO) { NS_ASSERTION(aPO, "Pointer is null!"); // Now locate the nsIDocument for the WebShell nsCOMPtr docShell(do_QueryInterface(aPO->mWebShell)); NS_ASSERTION(docShell, "The DocShell can't be NULL!"); nsCOMPtr wsPresShell; docShell->GetPresShell(getter_AddRefs(wsPresShell)); NS_ASSERTION(wsPresShell, "The PresShell can't be NULL!"); nsCOMPtr document; wsPresShell->GetDocument(getter_AddRefs(document)); // create the PresContext nsresult rv; nsCOMPtr printcon(do_CreateInstance(kPrintContextCID, &rv)); if (NS_FAILED(rv)) { return rv; } else { rv = printcon->QueryInterface(NS_GET_IID(nsIPresContext), (void**)&aPO->mPresContext); if (NS_FAILED(rv)) { return rv; } } // init it with the DC (aPO->mPresContext)->Init(mPrt->mPrintDocDC); CreateStyleSet(document, &aPO->mStyleSet); rv = nsComponentManager::CreateInstance(kPresShellCID,nsnull, NS_GET_IID(nsIPresShell),(void **)&aPO->mPresShell); if (NS_FAILED(rv)) { return rv; } rv = nsComponentManager::CreateInstance(kViewManagerCID,nsnull, NS_GET_IID(nsIViewManager),(void **)&aPO->mViewManager); if (NS_FAILED(rv)) { return rv; } rv = aPO->mViewManager->Init(mPrt->mPrintDocDC); if (NS_FAILED(rv)) { return rv; } PRInt32 pageWidth, pageHeight; mPrt->mPrintDocDC->GetDeviceSurfaceDimensions(pageWidth, pageHeight); PRInt32 width, height; if (aPO->mContent == nsnull || !aPO->mPrintAsIs || (aPO->mPrintAsIs && aPO->mParent != nsnull && !aPO->mParent->mPrintAsIs) || (aPO->mFrameType == eIFrame && aPO == mPrt->mSelectedPO)) { width = pageWidth; height = pageHeight; } else { width = aPO->mRect.width; height = aPO->mRect.height; } PRINT_DEBUG_MSG5("In DV::ReflowPrintObject PO: %p (%9s) Setting w,h to %d,%d\n", aPO, gFrameTypesStr[aPO->mFrameType], width, height); nsCOMPtr domWinIntl(do_QueryInterface(mPrt->mPrintDocDW)); // XXX - Hack Alert // OK, so ther eis a selection, we will print the entire selection // on one page and then crop the page. // This means you can never print any selection that is longer than one page // put it keeps it from page breaking in the middle of your print of the selection // (see also nsSimplePageSequence.cpp) PRInt16 printRangeType = nsIPrintOptions::kRangeAllPages; NS_WITH_SERVICE(nsIPrintOptions, printService, kPrintOptionsCID, &rv); if (NS_SUCCEEDED(rv)) { printService->GetPrintRange(&printRangeType); } if (printRangeType == nsIPrintOptions::kRangeSelection && IsThereARangeSelection(domWinIntl)) { height = 0x0FFFFFFF; } nsRect tbounds = nsRect(0, 0, width, height); // Create a child window of the parent that is our "root view/window" rv = nsComponentManager::CreateInstance(kViewCID, nsnull, NS_GET_IID(nsIView), (void **)&(aPO->mRootView)); if (NS_FAILED(rv)) { return rv; } rv = (aPO->mRootView)->Init(aPO->mViewManager, tbounds, nsnull); if (NS_FAILED(rv)) { return rv; } // Setup hierarchical relationship in view manager aPO->mViewManager->SetRootView(aPO->mRootView); aPO->mPresShell->Init(document, aPO->mPresContext, aPO->mViewManager,aPO->mStyleSet); nsCompatibility mode; mPresContext->GetCompatibilityMode(&mode); aPO->mPresContext->SetCompatibilityMode(mode); aPO->mPresContext->SetContainer(aPO->mWebShell); // get the old history nsCOMPtr presShell; nsCOMPtr layoutState; NS_ENSURE_SUCCESS(GetPresShell(*(getter_AddRefs(presShell))), NS_ERROR_FAILURE); presShell->CaptureHistoryState(getter_AddRefs(layoutState),PR_TRUE); aPO->mPresShell->BeginObservingDocument(); nsMargin margin(0,0,0,0); if (printService) { printService->GetMarginInTwips(margin); } // initialize it with the default/generic case nsRect adjRect(aPO->mRect.x != 0?margin.left:0, aPO->mRect.y != 0?margin.top:0, width, height); // XXX This is an arbitray height, // but reflow somethimes gets upset when using max int // basically, we want to reflow a single page that is large // enough to fit any atomic object like an IFrame const PRInt32 kHundredPagesHigh = 100; // now, change the value for special cases if (mPrt->mPrintFrameType == nsIPrintOptions::kEachFrameSep) { if (aPO->mFrameType == eFrame) { adjRect.SetRect(0, 0, width, height); } else if (aPO->mFrameType == eIFrame) { height = pageHeight*kHundredPagesHigh; adjRect.SetRect(aPO->mRect.x != 0?margin.left:0, aPO->mRect.y != 0?margin.top:0, width, height); } } else if (mPrt->mPrintFrameType == nsIPrintOptions::kFramesAsIs) { if (aPO->mFrameType == eFrame || aPO->mFrameType == eIFrame) { height = pageHeight*kHundredPagesHigh; adjRect.SetRect(aPO->mRect.x != 0?margin.left:0, aPO->mRect.y != 0?margin.top:0, width, height); } } else if (mPrt->mPrintFrameType == nsIPrintOptions::kSelectedFrame) { if (aPO->mFrameType == eIFrame) { if (aPO == mPrt->mSelectedPO) { adjRect.x = 0; adjRect.y = 0; } else { height = pageHeight*kHundredPagesHigh; adjRect.SetRect(aPO->mRect.x != 0?margin.left:0, aPO->mRect.y != 0?margin.top:0, width, height); } } } aPO->mPresContext->SetPageDim(&adjRect); rv = aPO->mPresShell->InitialReflow(width, height); if (NS_SUCCEEDED(rv)) { // Transfer Selection Ranges to the new Print PresShell nsCOMPtr selection; nsCOMPtr selectionPS; nsresult rvv = GetDocumentSelection(getter_AddRefs(selection), wsPresShell); if (NS_SUCCEEDED(rvv) && selection) { rvv = GetDocumentSelection(getter_AddRefs(selectionPS), aPO->mPresShell); if (NS_SUCCEEDED(rvv) && selectionPS) { PRInt32 cnt; selection->GetRangeCount(&cnt); PRInt32 inx; for (inx=0;inx range; if (NS_SUCCEEDED(selection->GetRangeAt(inx, getter_AddRefs(range)))) { selectionPS->AddRange(range); } } } } // update the history from the old presentation shell nsCOMPtr fm; rv = aPO->mPresShell->GetFrameManager(getter_AddRefs(fm)); if(NS_SUCCEEDED(rv) && fm) { nsIFrame* root; aPO->mPresShell->GetRootFrame(&root); fm->RestoreFrameState(aPO->mPresContext, root, layoutState); } } aPO->mPresShell->EndObservingDocument(); return rv; } //------------------------------------------------------- // Given a DOMWindow it recursively finds the PO object that matches PrintObject* DocumentViewerImpl::FindPrintObjectByDOMWin(PrintObject* aPO, nsIDOMWindowInternal * 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 == nsnull) { return nsnull; } nsCOMPtr domWin(GetDOMWinForWebShell(aPO->mWebShell)); if (domWin != nsnull && domWin.get() == aDOMWin) { return aPO; } PRInt32 cnt = aPO->mKids.Count(); for (PRInt32 i=0;imKids[i], aDOMWin); if (po != nsnull) { return po; } } return nsnull; } //------------------------------------------------------- nsresult DocumentViewerImpl::PrintContent(nsIWebShell * aParent, nsIDeviceContext * aDContext, nsIDOMWindow * aDOMWin, PRBool aIsSubDoc) { // XXX Once we get printing for plugins going we will // have to revist this method. NS_ASSERTION(0, "Still may be needed for plugins"); return NS_ERROR_FAILURE; } //------------------------------------------------------- // return the DOMWindowInternal for a WebShell nsIDOMWindowInternal * DocumentViewerImpl::GetDOMWinForWebShell(nsIWebShell* aWebShell) { NS_ASSERTION(aWebShell, "Pointer is null!"); nsCOMPtr docShell(do_QueryInterface(aWebShell)); NS_ASSERTION(docShell, "The DocShell can't be NULL!"); if (!docShell) return nsnull; nsCOMPtr presShell; docShell->GetPresShell(getter_AddRefs(presShell)); NS_ASSERTION(presShell, "The PresShell can't be NULL!"); if (!presShell) return nsnull; nsCOMPtr document; presShell->GetDocument(getter_AddRefs(document)); if (!document) return nsnull; nsCOMPtr scriptGlobalObject; document->GetScriptGlobalObject(getter_AddRefs(scriptGlobalObject)); if (!scriptGlobalObject) return nsnull; nsCOMPtr domWin = do_QueryInterface(scriptGlobalObject); if (!domWin) return nsnull; nsIDOMWindowInternal * dw = domWin.get(); NS_ADDREF(dw); return dw; } //------------------------------------------------------- nsresult DocumentViewerImpl::EnablePOsForPrinting() { // NOTE: All POs have been "turned off" for printing // this is where we decided which POs get printed. mPrt->mSelectedPO = nsnull; nsresult rv; NS_WITH_SERVICE(nsIPrintOptions, printService, kPrintOptionsCID, &rv); if (NS_FAILED(rv)) { return rv; } mPrt->mPrintFrameType = nsIPrintOptions::kNoFrames; printService->GetPrintFrameType(&mPrt->mPrintFrameType); PRInt16 printHowEnable = nsIPrintOptions::kFrameEnableNone; printService->GetHowToEnableFrameUI(&printHowEnable); PRInt16 printRangeType = nsIPrintOptions::kRangeAllPages; printService->GetPrintRange(&printRangeType); PRINT_DEBUG_MSG1("\n********* DocumentViewerImpl::EnablePOsForPrinting *********\n"); PRINT_DEBUG_MSG2("PrintFrameType: %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType]); PRINT_DEBUG_MSG2("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable]); PRINT_DEBUG_MSG2("PrintRange: %s \n", gPrintRangeStr[printRangeType]); PRINT_DEBUG_MSG1("----\n"); PRINT_DEBUG_FLUSH // Get the currently selected DOMWindow nsCOMPtr curFocusDOMWin = getter_AddRefs(FindFocusedDOMWindowInternal()); // ***** This is the ultimate override ***** // if we are printing the selection (either an IFrame or selection range) // then set the mPrintFrameType as if it were the selected frame if (printRangeType == nsIPrintOptions::kRangeSelection) { mPrt->mPrintFrameType = nsIPrintOptions::kSelectedFrame; printHowEnable = nsIPrintOptions::kFrameEnableNone; } // This tells us that the "Frame" UI has turned off, // so therefore there are no FrameSets/Frames/IFrames to be printed // // This means there are not FrameSets, // but the document could contain an IFrame if (printHowEnable == nsIPrintOptions::kFrameEnableNone) { // Print all the pages or a sub range of pages if (printRangeType == nsIPrintOptions::kRangeAllPages || printRangeType == nsIPrintOptions::kRangeSpecifiedPageRange) { SetPrintPO(mPrt->mPrintObject, PR_TRUE); // Set the children so they are PrinAsIs // In this case, the children are probably IFrames if (mPrt->mPrintObject->mKids.Count() > 0) { for (PRInt32 i=0;imPrintObject->mKids.Count();i++) { PrintObject* po = (PrintObject*)mPrt->mPrintObject->mKids[i]; NS_ASSERTION(po, "PrintObject can't be null!"); SetPrintAsIs(po); } // ***** Another override ***** mPrt->mPrintFrameType = nsIPrintOptions::kFramesAsIs; } PRINT_DEBUG_MSG2("PrintFrameType: %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType]); PRINT_DEBUG_MSG2("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable]); PRINT_DEBUG_MSG2("PrintRange: %s \n", gPrintRangeStr[printRangeType]); return NS_OK; } // This means we are either printed a selected IFrame or // we are printing the current selection if (printRangeType == nsIPrintOptions::kRangeSelection) { // If the currentFocusDOMWin can'r be null if something is selected if (curFocusDOMWin) { // Find the selected IFrame PrintObject * po = FindPrintObjectByDOMWin(mPrt->mPrintObject, curFocusDOMWin); if (po != nsnull) { mPrt->mSelectedPO = po; // Makes sure all of its children are be printed "AsIs" SetPrintAsIs(po); // Now, only enable this POs (the selected PO) and all of its children SetPrintPO(po, PR_TRUE); // 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 = getter_AddRefs(GetDOMWinForWebShell(po->mWebShell)); if (!IsThereARangeSelection(domWin)) { printRangeType = nsIPrintOptions::kRangeAllPages; printService->SetPrintRange(printRangeType); } PRINT_DEBUG_MSG2("PrintFrameType: %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType]); PRINT_DEBUG_MSG2("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable]); PRINT_DEBUG_MSG2("PrintRange: %s \n", gPrintRangeStr[printRangeType]); return NS_OK; } } else { for (PRInt32 i=0;imPrintDocList->Count();i++) { PrintObject* po = (PrintObject*)mPrt->mPrintDocList->ElementAt(i); NS_ASSERTION(po, "PrintObject can't be null!"); nsCOMPtr domWin = getter_AddRefs(GetDOMWinForWebShell(po->mWebShell)); if (IsThereARangeSelection(domWin)) { SetPrintPO(po, PR_TRUE); break; } } return NS_OK; } } } // check to see if there is a selection when a FrameSet is present if (printRangeType == nsIPrintOptions::kRangeSelection) { // If the currentFocusDOMWin can'r be null if something is selected if (curFocusDOMWin) { // Find the selected IFrame PrintObject * po = FindPrintObjectByDOMWin(mPrt->mPrintObject, curFocusDOMWin); if (po != nsnull) { mPrt->mSelectedPO = po; // Makes sure all of its children are be printed "AsIs" SetPrintAsIs(po); // Now, only enable this POs (the selected PO) and all of its children SetPrintPO(po, PR_TRUE); // 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 = getter_AddRefs(GetDOMWinForWebShell(po->mWebShell)); if (!IsThereARangeSelection(domWin)) { printRangeType = nsIPrintOptions::kRangeAllPages; printService->SetPrintRange(printRangeType); } PRINT_DEBUG_MSG2("PrintFrameType: %s \n", gPrintFrameTypeStr[mPrt->mPrintFrameType]); PRINT_DEBUG_MSG2("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable]); PRINT_DEBUG_MSG2("PrintRange: %s \n", gPrintRangeStr[printRangeType]); return NS_OK; } } } // If we are printing "AsIs" then sets all the POs to be printed as is if (mPrt->mPrintFrameType == nsIPrintOptions::kFramesAsIs) { SetPrintAsIs(mPrt->mPrintObject); SetPrintPO(mPrt->mPrintObject, PR_TRUE); return NS_OK; } // If we are printing the selected Frame then // find that PO for that selected DOMWin and set it all of its // children to be printed if (mPrt->mPrintFrameType == nsIPrintOptions::kSelectedFrame) { if ((mPrt->mIsParentAFrameSet && curFocusDOMWin) || mPrt->mIsIFrameSelected) { PrintObject * po = FindPrintObjectByDOMWin(mPrt->mPrintObject, curFocusDOMWin); if (po != nsnull) { mPrt->mSelectedPO = po; // Makes sure all of its children are be printed "AsIs" SetPrintAsIs(po); // Now, only enable this POs (the selected PO) and all of its children SetPrintPO(po, PR_TRUE); } } return NS_OK; } // If we are print each subdoc separately, // then don't print any of the FraneSet Docs if (mPrt->mPrintFrameType == nsIPrintOptions::kEachFrameSep) { SetPrintPO(mPrt->mPrintObject, PR_TRUE); PRInt32 cnt = mPrt->mPrintDocList->Count(); for (PRInt32 i=0;imPrintDocList->ElementAt(i); NS_ASSERTION(po, "PrintObject can't be null!"); if (po->mFrameType == eFrameSet) { po->mDontPrint = PR_TRUE; } } } return NS_OK; } //------------------------------------------------------- nsresult DocumentViewerImpl::SetupToPrintContent(nsIWebShell* aParent, nsIDeviceContext* aDContext, nsIDOMWindowInternal* aCurrentFocusedDOMWin) { NS_ENSURE_ARG_POINTER(aParent); NS_ENSURE_ARG_POINTER(aDContext); // NOTE: aCurrentFocusedDOMWin may be null (which is OK) mPrt->mPrintDocDC = aDContext; // In this step we figure out which documents should be printed // i.e. if we are printing the selection then only enable that PrintObject // for printing if (NS_FAILED(EnablePOsForPrinting())) { return NS_ERROR_FAILURE; } DUMP_DOC_LIST("\nAfter Enable------------------------------------------"); // Here we reflow all the PrintObjects if (NS_FAILED(ReflowDocList(mPrt->mPrintObject))) { return NS_ERROR_FAILURE; } DUMP_DOC_LIST("\nAfter Reflow------------------------------------------"); PRINT_DEBUG_MSG1("\n-------------------------------------------------------\n\n"); // Set up the clipping rectangle for all documents // When frames are being printed as part of a frame set and also IFrames, // they are reflowed with a very large page height. We need to setup the // clipping so they do not rpint over top of anything else PRINT_DEBUG_MSG1("SetClipRect-------------------------------------------------------\n"); nsRect clipRect(-1,-1,-1, -1); SetClipRect(mPrt->mPrintObject, clipRect, 0, 0, PR_FALSE); CalcNumPrintableDocsAndPages(mPrt->mNumPrintableDocs, mPrt->mNumPrintablePages); PRINT_DEBUG_MSG3("--- Printing %d docs and %d pages\n", mPrt->mNumPrintableDocs, mPrt->mNumPrintablePages); DUMP_DOC_TREELAYOUT; PRINT_DEBUG_FLUSH; #ifdef DEBUG_PRINTING #if defined(XP_PC) for (PRInt32 i=0;imPrintDocList->Count();i++) { PrintObject* po = (PrintObject*)mPrt->mPrintDocList->ElementAt(i); NS_ASSERTION(po, "PrintObject can't be null!"); if (po->mPresShell) { nsIPageSequenceFrame* pageSequence; po->mPresShell->GetPageSequenceFrame(&pageSequence); if (pageSequence != nsnull) { // install the debugging file pointer nsSimplePageSequenceFrame * sf = NS_STATIC_CAST(nsSimplePageSequenceFrame*, pageSequence); sf->SetDebugFD(mPrt->mDebugFD); } } } #endif #endif mPrt->mPrintDocDC = aDContext; mPrt->mPrintDocDW = aCurrentFocusedDOMWin; // This will print the webshell document // when it completes asynchronously in the DonePrintingPages method // it will check to see if there are more webshells to be printed and // then PrintDocContent will be called again. nsCOMPtr webContainer(do_QueryInterface(mContainer)); PRUnichar * docTitleStr; PRUnichar * docURLStr; GetWebShellTitleAndURL(webContainer, &docTitleStr, &docURLStr); if (!docTitleStr) { if (docURLStr) { docTitleStr = docURLStr; docURLStr = nsnull; } else { nsAutoString docStr(NS_LITERAL_STRING("Document")); docTitleStr = docStr.ToNewUnicode(); } } // BeginDocument may pass back a FAILURE code // i.e. On Windows, if you are printing to a file and hit "Cancel" // to the "File Name" dialog, this comes back as an error nsresult rv = mPrt->mPrintDC->BeginDocument(docTitleStr); PRINT_DEBUG_MSG1("****************** Begin Document ************************\n"); if (docTitleStr != nsnull) { nsMemory::Free(docTitleStr); } if (docURLStr != nsnull) { nsMemory::Free(docURLStr); } if (NS_FAILED(rv)) { return rv; } PrintDocContent(mPrt->mPrintObject, rv); // ignore return value return rv; } //------------------------------------------------------- nsresult DocumentViewerImpl::DoPrint(PrintObject * aPO, PRBool aDoSyncPrinting, PRBool& aDonePrinting) { NS_ASSERTION(mPrt->mPrintDocList, "Pointer is null!"); PRINT_DEBUG_MSG2("\n**************************** %s ****************************\n", gFrameTypesStr[aPO->mFrameType]); PRINT_DEBUG_MSG3("****** In DV::DoPrint PO: %p aDoSyncPrinting: %s \n", aPO, PRT_YESNO(aDoSyncPrinting)); nsIWebShell* webShell = aPO->mWebShell; nsIPresShell* poPresShell = aPO->mPresShell; nsIPresContext* poPresContext = aPO->mPresContext; nsIView* poRootView = aPO->mRootView; //nsIStyleSet* poStyleSet = aPO->mStyleSet; //nsIViewManager* poViewManager = aPO->mViewManager; //nsIView* poView = aPO->mView; nsCOMPtr webContainer(do_QueryInterface(mContainer)); NS_ASSERTION(webShell, "The WebShell can't be NULL!"); if (webShell != nsnull) { PRInt16 printRangeType = nsIPrintOptions::kRangeAllPages; nsresult rv; NS_WITH_SERVICE(nsIPrintOptions, printService, kPrintOptionsCID, &rv); if (NS_SUCCEEDED(rv) && printService) { printService->GetPrintRange(&printRangeType); } // Ask the page sequence frame to print all the pages nsIPageSequenceFrame* pageSequence; poPresShell->GetPageSequenceFrame(&pageSequence); NS_ASSERTION(nsnull != pageSequence, "no page sequence frame"); // Now, depending how we are printing and what type of doc we are printing // we must configure the sequencer correctly. // so we are about to be very explicit about the whole process PRBool skipPageEjectOnly = PR_FALSE; PRBool skipAllPageAdjustments = PR_FALSE; PRBool doOffsetting = PR_FALSE; PRBool doAddInParentsOffset = PR_TRUE; PRBool skipSetTitle = PR_FALSE; if (aPO->mFrameType == eFrame) { switch (mPrt->mPrintFrameType) { case nsIPrintOptions::kFramesAsIs: skipAllPageAdjustments = PR_TRUE; doOffsetting = PR_TRUE; break; case nsIPrintOptions::kSelectedFrame: if (aPO->mKids.Count() > 0) { skipPageEjectOnly = PR_TRUE; } break; case nsIPrintOptions::kEachFrameSep: if (aPO->mKids.Count() > 0) { skipPageEjectOnly = PR_TRUE; } break; } // switch } else if (aPO->mFrameType == eIFrame) { switch (mPrt->mPrintFrameType) { case nsIPrintOptions::kFramesAsIs: skipAllPageAdjustments = PR_TRUE; doOffsetting = PR_TRUE; skipSetTitle = PR_TRUE; break; case nsIPrintOptions::kSelectedFrame: if (aPO != mPrt->mSelectedPO) { skipAllPageAdjustments = PR_TRUE; doOffsetting = PR_TRUE; doAddInParentsOffset = aPO->mParent != nsnull && aPO->mParent->mFrameType == eIFrame && aPO->mParent != mPrt->mSelectedPO; skipSetTitle = PR_TRUE; } else { skipPageEjectOnly = aPO->mKids.Count() > 0; } break; case nsIPrintOptions::kEachFrameSep: skipAllPageAdjustments = PR_TRUE; doOffsetting = PR_TRUE; doAddInParentsOffset = aPO->mParent != nsnull && aPO->mParent->mFrameType == eIFrame; skipSetTitle = PR_TRUE; break; } // switch } else { // FrameSets skip page eject only if printing AsIs skipPageEjectOnly = aPO->mPrintAsIs; } // That we are all configured, // let's set everything up to print if (skipPageEjectOnly) { pageSequence->SkipPageEnd(); aPO->mSkippedPageEject = PR_TRUE; } else { if (skipAllPageAdjustments) { pageSequence->SuppressHeadersAndFooters(PR_TRUE); pageSequence->SkipPageBegin(); pageSequence->SkipPageEnd(); aPO->mSkippedPageEject = PR_TRUE; } else { aPO->mSkippedPageEject = PR_FALSE; } if (doOffsetting) { nscoord x = 0; nscoord y = 0; PrintObject * po = aPO; while (po != nsnull) { //if (mPrt->mPrintFrameType != nsIPrintOptions::kSelectedFrame || po != aPO->mParent) { PRBool isParent = po == aPO->mParent; if (!isParent || (isParent && doAddInParentsOffset)) { x += po->mRect.x; y += po->mRect.y; } po = po->mParent; } pageSequence->SetOffset(x, y); } } PRINT_DEBUG_MSG5("*** skipPageEjectOnly: %s skipAllPageAdjustments: %s doOffsetting: %s doAddInParentsOffset: %s\n", PRT_YESNO(skipPageEjectOnly), PRT_YESNO(skipAllPageAdjustments), PRT_YESNO(doOffsetting), PRT_YESNO(doAddInParentsOffset)); if (nsnull != mPrt->mFilePointer) { // output the regression test nsIFrameDebug* fdbg; nsIFrame* root; poPresShell->GetRootFrame(&root); if (NS_SUCCEEDED(root->QueryInterface(NS_GET_IID(nsIFrameDebug), (void**) &fdbg))) { fdbg->DumpRegressionData(poPresContext, mPrt->mFilePointer, 0, PR_TRUE); } fclose(mPrt->mFilePointer); } else { nsIFrame* rootFrame; poPresShell->GetRootFrame(&rootFrame); #if defined(DEBUG_rodsX) || defined(DEBUG_dconeX) DumpLayoutData(poPresContext, mPrt->mPrintDocDC, rootFrame, webShell); #endif if (printService) { if (!skipSetTitle) { PRUnichar * docTitleStr; PRUnichar * docURLStr; GetWebShellTitleAndURL(webShell, &docTitleStr, &docURLStr); if (docTitleStr) { printService->SetTitle(docTitleStr); nsMemory::Free(docTitleStr); } if (docURLStr) { printService->SetDocURL(docURLStr); nsMemory::Free(docURLStr); } } if (nsIPrintOptions::kRangeSelection == printRangeType) { poPresContext->SetIsRenderingOnlySelection(PR_TRUE); // temporarily creating rendering context // which is needed to dinf the selection frames nsCOMPtr rc; mPrt->mPrintDocDC->CreateRenderingContext(*getter_AddRefs(rc)); // find the starting and ending page numbers // via the selection nsIFrame* startFrame; nsIFrame* endFrame; PRInt32 startPageNum; PRInt32 endPageNum; nsRect startRect; nsRect endRect; nsCOMPtr selectionPS; nsresult rvv = GetDocumentSelection(getter_AddRefs(selectionPS), poPresShell); if (NS_SUCCEEDED(rvv) && selectionPS) { } rv = GetPageRangeForSelection(poPresShell, poPresContext, *rc, selectionPS, pageSequence, &startFrame, startPageNum, startRect, &endFrame, endPageNum, endRect); if (NS_SUCCEEDED(rv)) { printService->SetStartPageRange(startPageNum); printService->SetEndPageRange(endPageNum); nsMargin margin(0,0,0,0); printService->GetMarginInTwips(margin); if (startPageNum == endPageNum) { nsIFrame * seqFrame; if (NS_FAILED(pageSequence->QueryInterface(NS_GET_IID(nsIFrame), (void **)&seqFrame))) { return NS_ERROR_FAILURE; } nsRect rect(0,0,0,0); nsRect areaRect; nsIFrame * areaFrame = FindFrameByType(poPresContext, startFrame, nsHTMLAtoms::body, rect, areaRect); if (areaFrame) { areaRect.y -= startRect.y; areaRect.x -= margin.left; areaFrame->SetRect(poPresContext, areaRect); } } } } nsIFrame * seqFrame; if (NS_FAILED(pageSequence->QueryInterface(NS_GET_IID(nsIFrame), (void **)&seqFrame))) { return NS_ERROR_FAILURE; } nsRect srect; seqFrame->GetRect(srect); nsRect r; poRootView->GetBounds(r); r.height = srect.height; poRootView->SetBounds(r); rootFrame->GetRect(r); r.height = srect.height; rootFrame->SetRect(poPresContext, r); mPageSeqFrame = pageSequence; mPageSeqFrame->StartPrint(poPresContext, printService); if (!aDoSyncPrinting) { // Get the delay time in between the printing of each page // this gives the user more time to press cancel PRInt32 printPageDelay = 500; printService->GetPrintPageDelay(&printPageDelay); // Schedule Page to Print PRINT_DEBUG_MSG3("Scheduling Print of PO: %p (%s) \n", aPO, gFrameTypesStr[aPO->mFrameType]); StartPagePrintTimer(poPresContext, printService, aPO, printPageDelay); } else { DoProgressForAsIsFrames(); // Print the page synchronously PRINT_DEBUG_MSG3("Async Print of PO: %p (%s) \n", aPO, gFrameTypesStr[aPO->mFrameType]); aDonePrinting = PrintPage(poPresContext, printService, aPO); } } else { // not sure what to do here! return NS_ERROR_FAILURE; } } } else { aPO->mDontPrint = PR_TRUE; aDonePrinting = PR_FALSE; } return NS_OK; } //------------------------------------------------------- // Figure out how many documents and how many total pages we are printing void DocumentViewerImpl::CalcNumPrintableDocsAndPages(PRInt32& aNumDocs, PRInt32& aNumPages) { aNumPages = 0; // Count the number of printable documents // and printable pages PRInt32 numOfPrintableDocs = 0; PRInt32 i; for (i=0;imPrintDocList->Count();i++) { PrintObject* po = (PrintObject*)mPrt->mPrintDocList->ElementAt(i); NS_ASSERTION(po, "PrintObject can't be null!"); if (po->IsPrintable()) { if (po->mPresShell != nsnull && (po->mFrameType != eIFrame && po->mFrameType != eFrameSet)) { nsIPageSequenceFrame* pageSequence; po->mPresShell->GetPageSequenceFrame(&pageSequence); nsIFrame * seqFrame; if (NS_SUCCEEDED(pageSequence->QueryInterface(NS_GET_IID(nsIFrame), (void **)&seqFrame))) { nsIFrame* frame; seqFrame->FirstChild(po->mPresContext, nsnull, &frame); while (frame) { aNumPages++; frame->GetNextSibling(&frame); } } } numOfPrintableDocs++; } } } //------------------------------------------------------- void DocumentViewerImpl::DoProgressForAsIsFrames() { if (mPrt->mPrintListener) { // mPrintFrameType is set to kFramesAsIs event though the Doc Type maybe eDoc // this is done to make the printing of embedded IFrames easier // NOTE: we don't want to advance the progress in that case, it is down elsewhere if (mPrt->mPrintFrameType == nsIPrintOptions::kFramesAsIs && mPrt->mPrintObject->mFrameType != eDoc) { mPrt->mNumDocsPrinted++; // notify the listener of printed docs if (mPrt->mNumDocsPrinted == 1) { mPrt->mPrintListener->OnProgressPrinting(0, mPrt->mNumPrintableDocs); } mPrt->mPrintListener->OnProgressPrinting(mPrt->mNumDocsPrinted, mPrt->mNumPrintableDocs); } } } //------------------------------------------------------- void DocumentViewerImpl::DoProgressForSeparateFrames() { if (mPrt->mPrintListener) { if (mPrt->mPrintFrameType == nsIPrintOptions::kEachFrameSep) { mPrt->mNumPagesPrinted++; // notify the listener of printed docs if (mPrt->mNumPagesPrinted == 1) { mPrt->mPrintListener->OnProgressPrinting(0, mPrt->mNumPrintablePages); } mPrt->mPrintListener->OnProgressPrinting(mPrt->mNumPagesPrinted, mPrt->mNumPrintablePages); } } } //------------------------------------------------------- // Called for each WebShell that needs to be printed PRBool DocumentViewerImpl::PrintDocContent(PrintObject* aPO, nsresult& aStatus) { NS_ASSERTION(aPO, "Pointer is null!"); nsresult rv = NS_ERROR_FAILURE; if (!aPO->mHasBeenPrinted && aPO->IsPrintable()) { PRBool donePrinting; // donePrinting is only valid when when doing synchronous printing aStatus = DoPrint(aPO, PR_FALSE, donePrinting); if (donePrinting) { return PR_TRUE; } } for (PRInt32 i=0;imKids.Count();i++) { PrintObject* po = (PrintObject*)aPO->mKids[i]; PRBool printed = PrintDocContent(po, aStatus); if (printed || NS_FAILED(aStatus)) { return PR_TRUE; } } return PR_FALSE; } //------------------------------------------------------- void DocumentViewerImpl::Notify(nsIImageGroup *aImageGroup, nsImageGroupNotification aNotificationType) { // // Image are being loaded... Set the flag to delay printing until // all images are loaded. // if (aNotificationType == nsImageGroupNotification_kStartedLoading) { mIsPrinting = PR_TRUE; } // // All the images have been loaded, so the document is ready to print. // // However, at this point we are unable to release the resources that // were allocated for printing... This is because ImgLib resources will // be deleted and *this* is an ImgLib notification routine. So, fire an // event to do the actual printing. // else if(aNotificationType == nsImageGroupNotification_kFinishedLoading) { nsresult rv; nsCOMPtr eventQ; // Get the event queue of the current thread... NS_WITH_SERVICE(nsIEventQueueService, eventQService, kEventQueueService, &rv); if (NS_FAILED(rv)) return; rv = eventQService->GetThreadEventQueue(NS_CURRENT_THREAD, getter_AddRefs(eventQ)); if (NS_FAILED(rv)) return; PRStatus status; PLEvent *event = new PLEvent; if (!event) return; // // AddRef this because it is being placed in the PLEvent struct. // It will be Released when DestroyPLEvent is called... // NS_ADDREF_THIS(); PL_InitEvent(event, this, (PLHandleEventProc) DocumentViewerImpl::HandlePLEvent, (PLDestroyEventProc) DocumentViewerImpl::DestroyPLEvent); status = eventQ->PostEvent(event); } } NS_IMETHODIMP DocumentViewerImpl::SetEnableRendering(PRBool aOn) { NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE); mEnableRendering = aOn; if (mViewManager) { if (aOn) { mViewManager->EnableRefresh(NS_VMREFRESH_IMMEDIATE); nsIView* view; mViewManager->GetRootView(view); // views are not refCounted if (view) { mViewManager->UpdateView(view, NS_VMREFRESH_IMMEDIATE); } } else { mViewManager->DisableRefresh(); } } return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::GetEnableRendering(PRBool* aResult) { NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE); NS_PRECONDITION(nsnull != aResult, "null OUT ptr"); if (aResult) { *aResult = mEnableRendering; } return NS_OK; } void DocumentViewerImpl::ForceRefresh() { mWindow->Invalidate(PR_TRUE); } nsresult DocumentViewerImpl::CreateStyleSet(nsIDocument* aDocument, nsIStyleSet** aStyleSet) { // this should eventually get expanded to allow for creating // different sets for different media nsresult rv; if (!mUAStyleSheet) { NS_WARNING("unable to load UA style sheet"); } rv = nsComponentManager::CreateInstance(kStyleSetCID,nsnull,NS_GET_IID(nsIStyleSet),(void**)aStyleSet); if (NS_OK == rv) { PRInt32 index = aDocument->GetNumberOfStyleSheets(); while (0 < index--) { nsCOMPtr sheet(getter_AddRefs(aDocument->GetStyleSheetAt(index))); /* * GetStyleSheetAt will return all style sheets in the document but * we're only interested in the ones that are enabled. */ PRBool styleEnabled; sheet->GetEnabled(styleEnabled); if (styleEnabled) { (*aStyleSet)->AddDocStyleSheet(sheet, aDocument); } } NS_WITH_SERVICE(nsIChromeRegistry, chromeRegistry, "@mozilla.org/chrome/chrome-registry;1", &rv); if (NS_SUCCEEDED(rv) && chromeRegistry) { nsCOMPtr sheets; // Now handle the user sheets. nsCOMPtr docShell(do_QueryInterface(mContainer)); PRInt32 shellType; docShell->GetItemType(&shellType); PRBool isChrome = (shellType == nsIDocShellTreeItem::typeChrome); sheets = nsnull; chromeRegistry->GetUserSheets(isChrome, getter_AddRefs(sheets)); if(sheets){ nsCOMPtr sheet; PRUint32 count; sheets->Count(&count); for(PRUint32 i=0; iGetElementAt(i, getter_AddRefs(sheet)); // XXX For now, append as backstop until we figure out something // better to do. (*aStyleSet)->AppendBackstopStyleSheet(sheet); } } // Append chrome sheets (scrollbars + forms). nsCOMPtr ds(do_QueryInterface(mContainer)); chromeRegistry->GetBackstopSheets(ds, getter_AddRefs(sheets)); if(sheets){ nsCOMPtr sheet; PRUint32 count; sheets->Count(&count); for(PRUint32 i=0; iGetElementAt(i, getter_AddRefs(sheet)); (*aStyleSet)->AppendBackstopStyleSheet(sheet); } } } if (mUAStyleSheet) { (*aStyleSet)->AppendBackstopStyleSheet(mUAStyleSheet); } } return NS_OK; } nsresult DocumentViewerImpl::MakeWindow(nsIWidget* aParentWidget, const nsRect& aBounds) { nsresult rv; rv = nsComponentManager::CreateInstance(kViewManagerCID, nsnull, NS_GET_IID(nsIViewManager), getter_AddRefs(mViewManager)); nsCOMPtr dx; mPresContext->GetDeviceContext(getter_AddRefs(dx)); nsRect tbounds = aBounds; float p2t; mPresContext->GetPixelsToTwips(&p2t); tbounds *= p2t; // Initialize the view manager with an offset. This allows the viewmanager // to manage a coordinate space offset from (0,0) if ((NS_OK != rv) || (NS_OK != mViewManager->Init(dx, tbounds.x, tbounds.y))) { return rv; } // Reset the bounds offset so the root view is set to 0,0. The offset is // specified in nsIViewManager::Init above. // Besides, layout will reset the root view to (0,0) during reflow, // so changing it to 0,0 eliminates placing // the root view in the wrong place initially. tbounds.x = 0; tbounds.y = 0; // Create a child window of the parent that is our "root view/window" // Create a view rv = nsComponentManager::CreateInstance(kViewCID, nsnull, NS_GET_IID(nsIView), (void**)&mView); if ((NS_OK != rv) || (NS_OK != mView->Init(mViewManager, tbounds, nsnull))) { return rv; } rv = mView->CreateWidget(kWidgetCID, nsnull, aParentWidget->GetNativeData(NS_NATIVE_WIDGET)); if (rv != NS_OK) return rv; // Setup hierarchical relationship in view manager mViewManager->SetRootView(mView); mView->GetWidget(*getter_AddRefs(mWindow)); // This SetFocus is necessary so the Arrow Key and Page Key events // go to the scrolled view as soon as the Window is created instead of going to // the browser window (this enables keyboard scrolling of the document) // mWindow->SetFocus(); return rv; } nsresult DocumentViewerImpl::GetDocumentSelection(nsISelection **aSelection, nsIPresShell * aPresShell) { if (aPresShell == nsnull) { if (!mPresShell) { return NS_ERROR_NOT_INITIALIZED; } aPresShell = mPresShell; } if (!aSelection) return NS_ERROR_NULL_POINTER; if (!aPresShell) return NS_ERROR_NULL_POINTER; nsCOMPtr selcon; selcon = do_QueryInterface(aPresShell); if (selcon) return selcon->GetSelection(nsISelectionController::SELECTION_NORMAL, aSelection); return NS_ERROR_FAILURE; } NS_IMETHODIMP DocumentViewerImpl::CreateDocumentViewerUsing(nsIPresContext* aPresContext, nsIDocumentViewer*& aResult) { if (!mDocument) { // XXX better error return NS_ERROR_NULL_POINTER; } if (nsnull == aPresContext) { return NS_ERROR_NULL_POINTER; } // Create new viewer DocumentViewerImpl* viewer = new DocumentViewerImpl(aPresContext); if (nsnull == viewer) { return NS_ERROR_OUT_OF_MEMORY; } NS_ADDREF(viewer); // XXX make sure the ua style sheet is used (for now; need to be // able to specify an alternate) viewer->SetUAStyleSheet(mUAStyleSheet); // Bind the new viewer to the old document nsresult rv = viewer->BindToDocument(mDocument, "create");/* XXX verb? */ aResult = viewer; return rv; } void PR_CALLBACK DocumentViewerImpl::HandlePLEvent(PLEvent* aEvent) { DocumentViewerImpl *viewer; viewer = (DocumentViewerImpl*)PL_GetEventOwner(aEvent); NS_ASSERTION(viewer, "The event owner is null."); if (viewer) { viewer->DocumentReadyForPrinting(); } } void PR_CALLBACK DocumentViewerImpl::DestroyPLEvent(PLEvent* aEvent) { DocumentViewerImpl *viewer; viewer = (DocumentViewerImpl*)PL_GetEventOwner(aEvent); NS_IF_RELEASE(viewer); delete aEvent; } nsresult DocumentViewerImpl::DocumentReadyForPrinting() { nsresult rv = NS_ERROR_FAILURE; nsCOMPtr webContainer; webContainer = do_QueryInterface(mContainer); if(webContainer) { // // Remove ourselves as an image group observer... // nsCOMPtr imageGroup; mPrt->mPrintPC->GetImageGroup(getter_AddRefs(imageGroup)); if (imageGroup) { imageGroup->RemoveObserver(this); } // get the focused DOMWindow nsCOMPtr curFocusDOMWin = getter_AddRefs(FindFocusedDOMWindowInternal()); // // Send the document to the printer... // rv = SetupToPrintContent(webContainer, mPrt->mPrintDC, curFocusDOMWin); if (NS_FAILED(rv)) { // The print job was canceled or there was a problem // So remove all other documents from the print list DonePrintingPages(nsnull); } } return rv; } NS_IMETHODIMP DocumentViewerImpl::SetTransformMediator(nsITransformMediator* aMediator) { NS_ASSERTION(nsnull == mTransformMediator, "nsXMLDocument::SetTransformMediator(): \ Cannot set a second transform mediator\n"); mTransformMediator = aMediator; return NS_OK; } #ifdef XP_MAC #pragma mark - #endif /* ======================================================================================== * nsIContentViewerEdit * ======================================================================================== */ NS_IMETHODIMP DocumentViewerImpl::Search() { NS_ASSERTION(0, "NOT IMPLEMENTED"); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP DocumentViewerImpl::GetSearchable(PRBool *aSearchable) { NS_ASSERTION(0, "NOT IMPLEMENTED"); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP DocumentViewerImpl::ClearSelection() { NS_ASSERTION(0, "NOT IMPLEMENTED"); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP DocumentViewerImpl::SelectAll() { // XXX this is a temporary implementation copied from nsWebShell // for now. I think nsDocument and friends should have some helper // functions to make this easier. nsCOMPtr selection; nsresult rv; rv = GetDocumentSelection(getter_AddRefs(selection)); if (NS_FAILED(rv)) return rv; nsCOMPtr htmldoc = do_QueryInterface(mDocument); nsCOMPtr bodyNode; if (htmldoc) { nsCOMPtrbodyElement; rv = htmldoc->GetBody(getter_AddRefs(bodyElement)); if (NS_FAILED(rv) || !bodyElement) return rv; bodyNode = do_QueryInterface(bodyElement); } else if (mDocument) { nsCOMPtr rootContent = getter_AddRefs(mDocument->GetRootContent()); bodyNode = do_QueryInterface(rootContent); } if (!bodyNode) return NS_ERROR_FAILURE; rv = selection->RemoveAllRanges(); if (NS_FAILED(rv)) return rv; static NS_DEFINE_CID(kCDOMRangeCID, NS_RANGE_CID); nsCOMPtr range; rv = nsComponentManager::CreateInstance(kCDOMRangeCID, nsnull, NS_GET_IID(nsIDOMRange), getter_AddRefs(range)); rv = range->SelectNodeContents(bodyNode); if (NS_FAILED(rv)) return rv; rv = selection->AddRange(range); return rv; } NS_IMETHODIMP DocumentViewerImpl::CopySelection() { NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED); return mPresShell->DoCopy(); } NS_IMETHODIMP DocumentViewerImpl::CopyLinkLocation() { NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED); nsCOMPtr node; nsresult rv = GetPopupLinkNode(getter_AddRefs(node)); // make noise if we're not in a link NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_TRUE(node, NS_ERROR_FAILURE); return mPresShell->DoCopyLinkLocation(node); } NS_IMETHODIMP DocumentViewerImpl::CopyImageLocation() { NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED); nsCOMPtr node; nsresult rv = GetPopupImageNode(getter_AddRefs(node)); // make noise if we're not in an image NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_TRUE(node, NS_ERROR_FAILURE); return mPresShell->DoCopyImageLocation(node); } NS_IMETHODIMP DocumentViewerImpl::CopyImageContents() { NS_ENSURE_TRUE(mPresShell, NS_ERROR_NOT_INITIALIZED); nsCOMPtr node; nsresult rv = GetPopupImageNode(getter_AddRefs(node)); // make noise if we're not in an image NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_TRUE(node, NS_ERROR_FAILURE); return mPresShell->DoCopyImageContents(node); } NS_IMETHODIMP DocumentViewerImpl::GetCopyable(PRBool *aCopyable) { nsCOMPtr selection; nsresult rv; rv = GetDocumentSelection(getter_AddRefs(selection)); if (NS_FAILED(rv)) return rv; PRBool isCollapsed; selection->GetIsCollapsed(&isCollapsed); *aCopyable = !isCollapsed; return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::CutSelection() { NS_ASSERTION(0, "NOT IMPLEMENTED"); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP DocumentViewerImpl::GetCutable(PRBool *aCutable) { *aCutable = PR_FALSE; // mm, will this ever be called for an editable document? return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::Paste() { NS_ASSERTION(0, "NOT IMPLEMENTED"); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP DocumentViewerImpl::GetPasteable(PRBool *aPasteable) { *aPasteable = PR_FALSE; return NS_OK; } #ifdef XP_MAC #pragma mark - #endif /* ======================================================================================== * nsIContentViewerFile * ======================================================================================== */ NS_IMETHODIMP DocumentViewerImpl::Save() { NS_ASSERTION(0, "NOT IMPLEMENTED"); return NS_ERROR_NOT_IMPLEMENTED; } NS_IMETHODIMP DocumentViewerImpl::GetSaveable(PRBool *aSaveable) { NS_ASSERTION(0, "NOT IMPLEMENTED"); return NS_ERROR_NOT_IMPLEMENTED; } static NS_DEFINE_IID(kDeviceContextSpecFactoryCID, NS_DEVICE_CONTEXT_SPEC_FACTORY_CID); nsresult DocumentViewerImpl::GetSelectionDocument(nsIDeviceContextSpec * aDevSpec, nsIDocument ** aNewDoc) { //NS_ENSURE_ARG_POINTER(*aDevSpec); NS_ENSURE_ARG_POINTER(aNewDoc); // create document nsCOMPtr doc; nsresult rv = NS_NewHTMLDocument(getter_AddRefs(doc)); if (NS_FAILED(rv)) { return rv; } if (!doc) { return NS_ERROR_NULL_POINTER; } nsCOMPtr nimgr; rv = doc->GetNodeInfoManager(*getter_AddRefs(nimgr)); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr nodeInfo; nimgr->GetNodeInfo(nsHTMLAtoms::html, nsnull, kNameSpaceID_None, *getter_AddRefs(nodeInfo)); // create document content nsCOMPtr htmlElement; nsCOMPtr headElement; nsCOMPtr bodyElement; // create the root rv = NS_NewHTMLHtmlElement(getter_AddRefs(htmlElement), nodeInfo); if (NS_FAILED(rv)) { return rv; } if (!htmlElement) { return NS_ERROR_NULL_POINTER; } // create the head nimgr->GetNodeInfo(NS_LITERAL_STRING("head"), nsnull, kNameSpaceID_None, *getter_AddRefs(nodeInfo)); rv = NS_NewHTMLHeadElement(getter_AddRefs(headElement), nodeInfo); if (NS_FAILED(rv)) { return rv; } if (!headElement) { return NS_ERROR_NULL_POINTER; } headElement->SetDocument(doc, PR_FALSE, PR_TRUE); // create the body nimgr->GetNodeInfo(nsHTMLAtoms::body, nsnull, kNameSpaceID_None, *getter_AddRefs(nodeInfo)); rv = NS_NewHTMLBodyElement(getter_AddRefs(bodyElement), nodeInfo); if (NS_FAILED(rv)) { return rv; } if (!bodyElement) { return NS_ERROR_NULL_POINTER; } bodyElement->SetDocument(doc, PR_FALSE, PR_TRUE); // put the head and body into the root rv = htmlElement->AppendChildTo(headElement, PR_FALSE, PR_FALSE); if (NS_FAILED(rv)) { return rv; } rv = htmlElement->AppendChildTo(bodyElement, PR_FALSE, PR_FALSE); if (NS_FAILED(rv)) { return rv; } // load the document into the docshell nsCOMPtr domDoc = do_QueryInterface(doc); if (!domDoc) { return NS_ERROR_NULL_POINTER; } nsCOMPtr htmlDOMElement = do_QueryInterface(htmlElement); if (!htmlDOMElement) { return NS_ERROR_NULL_POINTER; } //nsCOMPtr rootContent(do_QueryInterface(htmlElement)); //doc->SetRootContent(rootContent); *aNewDoc = doc.get(); NS_ADDREF(*aNewDoc); return rv; } //------------------------------------------------------ PRBool DocumentViewerImpl::IsThereAnIFrameSelected(nsIWebShell* aWebShell, nsIDOMWindowInternal * aDOMWin, PRPackedBool& aIsParentFrameSet) { aIsParentFrameSet = IsParentAFrameSet(aWebShell); PRBool iFrameIsSelected = PR_FALSE; #if 1 PrintObject* po = FindPrintObjectByDOMWin(mPrt->mPrintObject, aDOMWin); iFrameIsSelected = po && po->mFrameType == eIFrame; #else // First, check to see if we are a frameset if (!aIsParentFrameSet) { // Check to see if there is a currenlt focused frame // if so, it means the selected frame is either the main webshell // or an IFRAME if (aDOMWin != nsnull) { // Get the main webshell's DOMWin to see if it matches // the frame that is selected nsCOMPtr domWin = getter_AddRefs(GetDOMWinForWebShell(aWebShell)); if (aDOMWin != nsnull && domWin != aDOMWin) { iFrameIsSelected = PR_TRUE; // we have a selected IFRAME } } } #endif return iFrameIsSelected; } //------------------------------------------------------ PRBool DocumentViewerImpl::IsThereARangeSelection(nsIDOMWindowInternal * aDOMWin) { nsCOMPtr presShell; if (aDOMWin != nsnull) { nsCOMPtr scriptObj(do_QueryInterface(aDOMWin)); nsCOMPtr docShell; scriptObj->GetDocShell(getter_AddRefs(docShell)); docShell->GetPresShell(getter_AddRefs(presShell)); } // check here to see if there is a range selection // so we know whether to turn on the "Selection" radio button nsCOMPtr selection; GetDocumentSelection(getter_AddRefs(selection), presShell); if (selection) { PRInt32 count; selection->GetRangeCount(&count); if (count == 1) { nsCOMPtr range; if (NS_SUCCEEDED(selection->GetRangeAt(0, getter_AddRefs(range)))) { // check to make sure it isn't an insertion selection PRBool isCollapsed; selection->GetIsCollapsed(&isCollapsed); return !isCollapsed; } } } return PR_FALSE; } /** --------------------------------------------------- * See documentation above in the nsIContentViewerfile class definition * @update 01/24/00 dwc */ NS_IMETHODIMP DocumentViewerImpl::Print(PRBool aSilent,FILE *aFile, nsIPrintListener *aPrintListener) { mPrt = new PrintData(); if (mPrt == nsnull) { return NS_ERROR_OUT_OF_MEMORY; } if (aPrintListener) { mPrt->mPrintListener = aPrintListener; } // first check to see if there is a "regular" selection nsCOMPtr curFocusDOMWin = getter_AddRefs(FindFocusedDOMWindowInternal()); PRBool isSelection = IsThereARangeSelection(curFocusDOMWin); // Create a list for storing the WebShells that need to be printed if (mPrt->mPrintDocList == nsnull) { mPrt->mPrintDocList = new nsVoidArray(); if (mPrt->mPrintDocList == nsnull) { return NS_ERROR_FAILURE; } } else { mPrt->mPrintDocList->Clear(); } // Get the webshell for this documentviewer nsCOMPtr webContainer(do_QueryInterface(mContainer)); // Add Root Doc to Tree and List mPrt->mPrintObject = new PrintObject; mPrt->mPrintObject->mWebShell = webContainer; mPrt->mPrintDocList->AppendElement(mPrt->mPrintObject); mPrt->mIsParentAFrameSet = IsParentAFrameSet(webContainer); mPrt->mPrintObject->mFrameType = mPrt->mIsParentAFrameSet?eFrameSet:eDoc; // Build the "tree" of PrintObjects nsCOMPtr parentAsNode(do_QueryInterface(webContainer)); BuildDocTree(parentAsNode, mPrt->mPrintDocList, mPrt->mPrintObject); // Create the linkage from the suv-docs back to the content element // in the parent document MapContentToWebShells(mPrt->mPrintObject, mPrt->mPrintObject); // Get whether the doc contains a frameset // Also, check to see if the currently focus webshell // is a child of this webshell mPrt->mIsIFrameSelected = IsThereAnIFrameSelected(webContainer, curFocusDOMWin, mPrt->mIsParentAFrameSet); DUMP_DOC_LIST("\nAfter Mapping------------------------------------------"); // Setup print options for UI nsresult rv = NS_ERROR_FAILURE; NS_WITH_SERVICE(nsIPrintOptions, printService, kPrintOptionsCID, &rv); if (NS_SUCCEEDED(rv) && printService) { if (mPrt->mIsParentAFrameSet) { if (curFocusDOMWin) { printService->SetHowToEnableFrameUI(nsIPrintOptions::kFrameEnableAll); } else { printService->SetHowToEnableFrameUI(nsIPrintOptions::kFrameEnableAsIsAndEach); } } else { printService->SetHowToEnableFrameUI(nsIPrintOptions::kFrameEnableNone); } // Now determine how to set up the Frame print UI printService->SetPrintOptions(nsIPrintOptions::kPrintOptionsEnableSelectionRB, isSelection || mPrt->mIsIFrameSelected); } #ifdef DEBUG_PRINTING if (printService) { PRInt16 printHowEnable = nsIPrintOptions::kFrameEnableNone; printService->GetHowToEnableFrameUI(&printHowEnable); PRBool val; printService->GetPrintOptions(nsIPrintOptions::kPrintOptionsEnableSelectionRB, &val); PRINT_DEBUG_MSG1("********* DocumentViewerImpl::Print *********\n"); PRINT_DEBUG_MSG2("IsParentAFrameSet: %s \n", PRT_YESNO(mPrt->mIsParentAFrameSet)); PRINT_DEBUG_MSG2("IsFrameSelected: %s \n", PRT_YESNO(mPrt->mIsIFrameSelected)); PRINT_DEBUG_MSG2("Main Doc Frame Type: %s \n", gFrameTypesStr[mPrt->mPrintObject->mFrameType]); PRINT_DEBUG_MSG2("HowToEnableFrameUI: %s \n", gFrameHowToEnableStr[printHowEnable]); PRINT_DEBUG_MSG2("EnableSelectionRB: %s \n", PRT_YESNO(val)); PRINT_DEBUG_MSG1("*********************************************\n"); PRINT_DEBUG_FLUSH } #endif nsCOMPtr factory; nsComponentManager::CreateInstance(kDeviceContextSpecFactoryCID, nsnull, NS_GET_IID(nsIDeviceContextSpecFactory), (void **)getter_AddRefs(factory)); if (factory) { #ifdef DEBUG_dcone printf("PRINT JOB STARTING\n"); #endif nsIDeviceContextSpec *devspec = nsnull; nsCOMPtr dx; mPrt->mPrintDC = nsnull; mPrt->mFilePointer = aFile; factory->CreateDeviceContextSpec(mWindow, devspec, aSilent); if (nsnull != devspec) { mPresContext->GetDeviceContext(getter_AddRefs(dx)); rv = dx->GetDeviceContextFor(devspec, mPrt->mPrintDC); if (NS_SUCCEEDED(rv)) { NS_RELEASE(devspec); if(webContainer) { // load the document and do the initial reflow on the entire document nsCOMPtr printcon(do_CreateInstance(kPrintContextCID,&rv)); if (NS_FAILED(rv)) { return rv; } else { rv = printcon->QueryInterface(NS_GET_IID(nsIPresContext), (void**)&mPrt->mPrintPC); if (NS_FAILED(rv)) { return rv; } } PRInt32 width, height; mPrt->mPrintDC->GetDeviceSurfaceDimensions(width,height); // XXX - Hack Alert // OK, so ther eis a selection, we will print the entire selection // on one page and then crop the page. // This means you can never print any selection that is longer than one page // put it keeps it from page breaking in the middle of your print of the selection if (isSelection) { //height = 0x0FFFFFFF; } mPrt->mPrintPC->Init(mPrt->mPrintDC); mPrt->mPrintPC->SetContainer(webContainer); CreateStyleSet(mDocument,&mPrt->mPrintSS); rv = nsComponentManager::CreateInstance(kPresShellCID, nsnull, NS_GET_IID(nsIPresShell),(void**)&mPrt->mPrintPS); if(NS_FAILED(rv)){ return rv; } rv = nsComponentManager::CreateInstance(kViewManagerCID, nsnull, NS_GET_IID(nsIViewManager),(void**)&mPrt->mPrintVM); if(NS_FAILED(rv)) { return rv; } rv = mPrt->mPrintVM->Init(mPrt->mPrintDC); if(NS_FAILED(rv)) { return rv; } rv = nsComponentManager::CreateInstance(kViewCID, nsnull, NS_GET_IID(nsIView),(void**)&mPrt->mPrintView); if(NS_FAILED(rv)) { return rv; } nsRect tbounds = nsRect(0,0,width,height); rv = mPrt->mPrintView->Init(mPrt->mPrintVM,tbounds,nsnull); if(NS_FAILED(rv)) { return rv; } // setup hierarchical relationship in view manager mPrt->mPrintVM->SetRootView(mPrt->mPrintView); mPrt->mPrintPS->Init(mDocument,mPrt->mPrintPC,mPrt->mPrintVM,mPrt->mPrintSS); nsCOMPtr imageGroup; mPrt->mPrintPC->GetImageGroup(getter_AddRefs(imageGroup)); if (imageGroup) { imageGroup->AddObserver(this); } mPrt->mPrintPS->InitialReflow(width,height); #ifdef DEBUG_dcone float a1,a2; PRInt32 i1,i2; printf("CRITICAL PRINTING INFORMATION\n"); printf("PRESSHELL(%x) PRESCONTEXT(%x)\nVIEWMANAGER(%x) VIEW(%x)\n", mPrt->mPrintPS, mPrt->mPrintPC,mPrt->mPrintDC,mPrt->mPrintVM,mPrt->mPrintView); // DEVICE CONTEXT INFORMATION from PresContext printf("DeviceContext of Presentation Context(%x)\n",dx); dx->GetDevUnitsToTwips(a1); dx->GetTwipsToDevUnits(a2); printf(" DevToTwips = %f TwipToDev = %f\n",a1,a2); dx->GetAppUnitsToDevUnits(a1); dx->GetDevUnitsToAppUnits(a2); printf(" AppUnitsToDev = %f DevUnitsToApp = %f\n",a1,a2); dx->GetCanonicalPixelScale(a1); printf(" GetCanonicalPixelScale = %f\n",a1); dx->GetScrollBarDimensions(a1, a2); printf(" ScrollBar x = %f y = %f\n",a1,a2); dx->GetZoom(a1); printf(" Zoom = %f\n",a1); dx->GetDepth((PRUint32&)i1); printf(" Depth = %d\n",i1); dx->GetDeviceSurfaceDimensions(i1,i2); printf(" DeviceDimension w = %d h = %d\n",i1,i2); // DEVICE CONTEXT INFORMATION printf("DeviceContext created for print(%x)\n",mPrt->mPrintDC); mPrt->mPrintDC->GetDevUnitsToTwips(a1); mPrt->mPrintDC->GetTwipsToDevUnits(a2); printf(" DevToTwips = %f TwipToDev = %f\n",a1,a2); mPrt->mPrintDC->GetAppUnitsToDevUnits(a1); mPrt->mPrintDC->GetDevUnitsToAppUnits(a2); printf(" AppUnitsToDev = %f DevUnitsToApp = %f\n",a1,a2); mPrt->mPrintDC->GetCanonicalPixelScale(a1); printf(" GetCanonicalPixelScale = %f\n",a1); mPrt->mPrintDC->GetScrollBarDimensions(a1, a2); printf(" ScrollBar x = %f y = %f\n",a1,a2); mPrt->mPrintDC->GetZoom(a1); printf(" Zoom = %f\n",a1); mPrt->mPrintDC->GetDepth((PRUint32&)i1); printf(" Depth = %d\n",i1); mPrt->mPrintDC->GetDeviceSurfaceDimensions(i1,i2); printf(" DeviceDimension w = %d h = %d\n",i1,i2); #endif // Print listener setup... if (mPrt != nsnull) { mPrt->OnStartPrinting(); } // // The mIsPrinting flag is set when the ImageGroup observer is // notified that images must be loaded as a result of the // InitialReflow... // if(!mIsPrinting){ rv = DocumentReadyForPrinting(); #ifdef DEBUG_dcone printf("PRINT JOB ENDING, OBSERVER WAS NOT CALLED\n"); #endif } else { // use the observer mechanism to finish the printing #ifdef DEBUG_dcone printf("PRINTING OBSERVER STARTED\n"); #endif } } } } else { if (mPagePrintTimer != nsnull) { mPagePrintTimer->Stop(); delete mPagePrintTimer; mPagePrintTimer = nsnull; } mPrt->OnEndPrinting(NS_ERROR_FAILURE); delete mPrt; mPrt = nsnull; rv = NS_ERROR_FAILURE; } } return rv; } NS_IMETHODIMP DocumentViewerImpl::GetPrintable(PRBool *aPrintable) { NS_ENSURE_ARG_POINTER(aPrintable); *aPrintable = PR_TRUE; return NS_OK; } #ifdef XP_MAC #pragma mark - #endif //***************************************************************************** // nsIMarkupDocumentViewer //***************************************************************************** NS_IMETHODIMP DocumentViewerImpl::ScrollToNode(nsIDOMNode* aNode) { NS_ENSURE_ARG(aNode); NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE); nsCOMPtr presShell; NS_ENSURE_SUCCESS(GetPresShell(*(getter_AddRefs(presShell))), NS_ERROR_FAILURE); // Get the nsIContent interface, because that's what we need to // get the primary frame nsCOMPtr content(do_QueryInterface(aNode)); NS_ENSURE_TRUE(content, NS_ERROR_FAILURE); // Get the primary frame nsIFrame* frame; // Remember Frames aren't ref-counted. They are in their // own special little world. NS_ENSURE_SUCCESS(presShell->GetPrimaryFrameFor(content, &frame), NS_ERROR_FAILURE); // tell the pres shell to scroll to the frame NS_ENSURE_SUCCESS(presShell->ScrollFrameIntoView(frame, NS_PRESSHELL_SCROLL_TOP, NS_PRESSHELL_SCROLL_ANYWHERE), NS_ERROR_FAILURE); return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::GetAllowPlugins(PRBool* aAllowPlugins) { NS_ENSURE_ARG_POINTER(aAllowPlugins); *aAllowPlugins = mAllowPlugins; return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::SetAllowPlugins(PRBool aAllowPlugins) { mAllowPlugins = aAllowPlugins; return NS_OK; } nsresult DocumentViewerImpl::CallChildren(CallChildFunc aFunc, void* aClosure) { nsCOMPtr docShellNode(do_QueryInterface(mContainer)); if (docShellNode) { PRInt32 i; PRInt32 n; docShellNode->GetChildCount(&n); for (i=0; i < n; i++) { nsCOMPtr child; docShellNode->GetChildAt(i, getter_AddRefs(child)); nsCOMPtr childAsShell(do_QueryInterface(child)); NS_ASSERTION(childAsShell, "null child in docshell"); if (childAsShell) { nsCOMPtr childCV; childAsShell->GetContentViewer(getter_AddRefs(childCV)); if (childCV) { nsCOMPtr markupCV = do_QueryInterface(childCV); if (markupCV) { (*aFunc)(markupCV, aClosure); } } } } } return NS_OK; } struct TextZoomInfo { float mTextZoom; }; static void SetChildTextZoom(nsIMarkupDocumentViewer* aChild, void* aClosure) { struct TextZoomInfo* textZoomInfo = (struct TextZoomInfo*) aClosure; aChild->SetTextZoom(textZoomInfo->mTextZoom); } NS_IMETHODIMP DocumentViewerImpl::SetTextZoom(float aTextZoom) { if (mDeviceContext) { mDeviceContext->SetTextZoom(aTextZoom); if (mPresContext) { mPresContext->RemapStyleAndReflow(); } } // now set the text zoom on all children of mContainer struct TextZoomInfo textZoomInfo = { aTextZoom }; return CallChildren(SetChildTextZoom, &textZoomInfo); } NS_IMETHODIMP DocumentViewerImpl::GetTextZoom(float* aTextZoom) { NS_ENSURE_ARG_POINTER(aTextZoom); if (mDeviceContext) { return mDeviceContext->GetTextZoom(*aTextZoom); } *aTextZoom = 1.0; return NS_OK; } // XXX: SEMANTIC CHANGE! // returns a copy of the string. Caller is responsible for freeing result // using Recycle(aDefaultCharacterSet) NS_IMETHODIMP DocumentViewerImpl::GetDefaultCharacterSet(PRUnichar** aDefaultCharacterSet) { NS_ENSURE_ARG_POINTER(aDefaultCharacterSet); NS_ENSURE_STATE(mContainer); static PRUnichar *gDefCharset = nsnull; // XXX: memory leak! if (0 == mDefaultCharacterSet.Length()) { if ((nsnull == gDefCharset) || (nsnull == *gDefCharset)) { nsCOMPtr webShell; webShell = do_QueryInterface(mContainer); if (webShell) { nsCOMPtr prefs(do_GetService(NS_PREF_CONTRACTID)); if(prefs) prefs->GetLocalizedUnicharPref("intl.charset.default", &gDefCharset); } } if ((nsnull == gDefCharset) || (nsnull == *gDefCharset)) mDefaultCharacterSet.AssignWithConversion("ISO-8859-1"); else mDefaultCharacterSet.Assign(gDefCharset); } *aDefaultCharacterSet = mDefaultCharacterSet.ToNewUnicode(); return NS_OK; } static void SetChildDefaultCharacterSet(nsIMarkupDocumentViewer* aChild, void* aClosure) { aChild->SetDefaultCharacterSet((PRUnichar*) aClosure); } NS_IMETHODIMP DocumentViewerImpl::SetDefaultCharacterSet(const PRUnichar* aDefaultCharacterSet) { mDefaultCharacterSet = aDefaultCharacterSet; // this does a copy of aDefaultCharacterSet // now set the default char set on all children of mContainer return CallChildren(SetChildDefaultCharacterSet, (void*) aDefaultCharacterSet); } // XXX: SEMANTIC CHANGE! // returns a copy of the string. Caller is responsible for freeing result // using Recycle(aForceCharacterSet) NS_IMETHODIMP DocumentViewerImpl::GetForceCharacterSet(PRUnichar** aForceCharacterSet) { NS_ENSURE_ARG_POINTER(aForceCharacterSet); nsAutoString emptyStr; if (mForceCharacterSet.Equals(emptyStr)) { *aForceCharacterSet = nsnull; } else { *aForceCharacterSet = mForceCharacterSet.ToNewUnicode(); } return NS_OK; } static void SetChildForceCharacterSet(nsIMarkupDocumentViewer* aChild, void* aClosure) { aChild->SetForceCharacterSet((PRUnichar*) aClosure); } NS_IMETHODIMP DocumentViewerImpl::SetForceCharacterSet(const PRUnichar* aForceCharacterSet) { mForceCharacterSet = aForceCharacterSet; // now set the force char set on all children of mContainer return CallChildren(SetChildForceCharacterSet, (void*) aForceCharacterSet); } // XXX: SEMANTIC CHANGE! // returns a copy of the string. Caller is responsible for freeing result // using Recycle(aHintCharacterSet) NS_IMETHODIMP DocumentViewerImpl::GetHintCharacterSet(PRUnichar * *aHintCharacterSet) { NS_ENSURE_ARG_POINTER(aHintCharacterSet); if(kCharsetUninitialized == mHintCharsetSource) { *aHintCharacterSet = nsnull; } else { *aHintCharacterSet = mHintCharset.ToNewUnicode(); // this can't possibly be right. we can't set a value just because somebody got a related value! //mHintCharsetSource = kCharsetUninitialized; } return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::GetHintCharacterSetSource(PRInt32 *aHintCharacterSetSource) { NS_ENSURE_ARG_POINTER(aHintCharacterSetSource); *aHintCharacterSetSource = mHintCharsetSource; return NS_OK; } static void SetChildHintCharacterSetSource(nsIMarkupDocumentViewer* aChild, void* aClosure) { aChild->SetHintCharacterSetSource((PRInt32) aClosure); } NS_IMETHODIMP DocumentViewerImpl::SetHintCharacterSetSource(PRInt32 aHintCharacterSetSource) { mHintCharsetSource = (nsCharsetSource)aHintCharacterSetSource; // now set the hint char set source on all children of mContainer return CallChildren(SetChildHintCharacterSetSource, (void*) aHintCharacterSetSource); } static void SetChildHintCharacterSet(nsIMarkupDocumentViewer* aChild, void* aClosure) { aChild->SetHintCharacterSet((PRUnichar*) aClosure); } NS_IMETHODIMP DocumentViewerImpl::SetHintCharacterSet(const PRUnichar* aHintCharacterSet) { mHintCharset = aHintCharacterSet; // now set the hint char set on all children of mContainer return CallChildren(SetChildHintCharacterSet, (void*) aHintCharacterSet); } #ifdef IBMBIDI static void SetChildBidiOptions(nsIMarkupDocumentViewer* aChild, void* aClosure) { aChild->SetBidiOptions((PRUint32)aClosure); } #endif // IBMBIDI NS_IMETHODIMP DocumentViewerImpl::SetBidiTextDirection(PRUint8 aTextDirection) { #ifdef IBMBIDI PRUint32 bidiOptions; GetBidiOptions(&bidiOptions); SET_BIDI_OPTION_DIRECTION(bidiOptions, aTextDirection); SetBidiOptions(bidiOptions); #endif return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::GetBidiTextDirection(PRUint8* aTextDirection) { #ifdef IBMBIDI PRUint32 bidiOptions; if (aTextDirection) { GetBidiOptions(&bidiOptions); *aTextDirection = GET_BIDI_OPTION_DIRECTION(bidiOptions); } #endif return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::SetBidiTextType(PRUint8 aTextType) { #ifdef IBMBIDI PRUint32 bidiOptions; GetBidiOptions(&bidiOptions); SET_BIDI_OPTION_TEXTTYPE(bidiOptions, aTextType); SetBidiOptions(bidiOptions); #endif return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::GetBidiTextType(PRUint8* aTextType) { #ifdef IBMBIDI PRUint32 bidiOptions; if (aTextType) { GetBidiOptions(&bidiOptions); *aTextType = GET_BIDI_OPTION_TEXTTYPE(bidiOptions); } #endif return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::SetBidiControlsTextMode(PRUint8 aControlsTextMode) { #ifdef IBMBIDI PRUint32 bidiOptions; GetBidiOptions(&bidiOptions); SET_BIDI_OPTION_CONTROLSTEXTMODE(bidiOptions, aControlsTextMode); SetBidiOptions(bidiOptions); #endif return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::GetBidiControlsTextMode(PRUint8* aControlsTextMode) { #ifdef IBMBIDI PRUint32 bidiOptions; if (aControlsTextMode) { GetBidiOptions(&bidiOptions); *aControlsTextMode = GET_BIDI_OPTION_CONTROLSTEXTMODE(bidiOptions); } #endif return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::SetBidiClipboardTextMode(PRUint8 aClipboardTextMode) { #ifdef IBMBIDI PRUint32 bidiOptions; GetBidiOptions(&bidiOptions); SET_BIDI_OPTION_CLIPBOARDTEXTMODE(bidiOptions, aClipboardTextMode); SetBidiOptions(bidiOptions); #endif return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::GetBidiClipboardTextMode(PRUint8* aClipboardTextMode) { #ifdef IBMBIDI PRUint32 bidiOptions; if (aClipboardTextMode) { GetBidiOptions(&bidiOptions); *aClipboardTextMode = GET_BIDI_OPTION_CLIPBOARDTEXTMODE(bidiOptions); } #endif return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::SetBidiNumeral(PRUint8 aNumeral) { #ifdef IBMBIDI PRUint32 bidiOptions; GetBidiOptions(&bidiOptions); SET_BIDI_OPTION_NUMERAL(bidiOptions, aNumeral); SetBidiOptions(bidiOptions); #endif return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::GetBidiNumeral(PRUint8* aNumeral) { #ifdef IBMBIDI PRUint32 bidiOptions; if (aNumeral) { GetBidiOptions(&bidiOptions); *aNumeral = GET_BIDI_OPTION_NUMERAL(bidiOptions); } #endif return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::SetBidiSupport(PRUint8 aSupport) { #ifdef IBMBIDI PRUint32 bidiOptions; GetBidiOptions(&bidiOptions); SET_BIDI_OPTION_SUPPORT(bidiOptions, aSupport); SetBidiOptions(bidiOptions); #endif return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::GetBidiSupport(PRUint8* aSupport) { #ifdef IBMBIDI PRUint32 bidiOptions; if (aSupport) { GetBidiOptions(&bidiOptions); *aSupport = GET_BIDI_OPTION_SUPPORT(bidiOptions); } #endif return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::SetBidiCharacterSet(PRUint8 aCharacterSet) { #ifdef IBMBIDI PRUint32 bidiOptions; GetBidiOptions(&bidiOptions); SET_BIDI_OPTION_CHARACTERSET(bidiOptions, aCharacterSet); SetBidiOptions(bidiOptions); #endif return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::GetBidiCharacterSet(PRUint8* aCharacterSet) { #ifdef IBMBIDI PRUint32 bidiOptions; if (aCharacterSet) { GetBidiOptions(&bidiOptions); *aCharacterSet = GET_BIDI_OPTION_CHARACTERSET(bidiOptions); } #endif return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::SetBidiOptions(PRUint32 aBidiOptions) { #ifdef IBMBIDI if (mPresContext) { mPresContext->SetBidi(aBidiOptions, PR_TRUE); // force reflow } // now set bidi on all children of mContainer CallChildren(SetChildBidiOptions, (void*) aBidiOptions); #endif // IBMBIDI return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::GetBidiOptions(PRUint32* aBidiOptions) { #ifdef IBMBIDI if (aBidiOptions) { if (mPresContext) { mPresContext->GetBidi(aBidiOptions); } else *aBidiOptions = IBMBIDI_DEFAULT_BIDI_OPTIONS; } #endif // IBMBIDI return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::SizeToContent() { NS_ENSURE_TRUE(mDocument, NS_ERROR_NOT_AVAILABLE); nsCOMPtr docShellAsItem(do_QueryInterface(mContainer)); NS_ENSURE_TRUE(docShellAsItem, NS_ERROR_FAILURE); nsCOMPtr docShellParent; docShellAsItem->GetSameTypeParent(getter_AddRefs(docShellParent)); // It's only valid to access this from a top frame. Doesn't work from // sub-frames. NS_ENSURE_TRUE(!docShellParent, NS_ERROR_FAILURE); nsCOMPtr presShell; GetPresShell(*getter_AddRefs(presShell)); NS_ENSURE_TRUE(presShell, NS_ERROR_FAILURE); NS_ENSURE_SUCCESS(presShell->ResizeReflow(NS_UNCONSTRAINEDSIZE, NS_UNCONSTRAINEDSIZE), NS_ERROR_FAILURE); nsCOMPtr presContext; GetPresContext(*getter_AddRefs(presContext)); NS_ENSURE_TRUE(presContext, NS_ERROR_FAILURE); nsRect shellArea; PRInt32 width, height; float pixelScale; // so how big is it? presContext->GetVisibleArea(shellArea); presContext->GetTwipsToPixels(&pixelScale); width = PRInt32((float)shellArea.width*pixelScale); height = PRInt32((float)shellArea.height*pixelScale); nsCOMPtr treeOwner; docShellAsItem->GetTreeOwner(getter_AddRefs(treeOwner)); NS_ENSURE_TRUE(treeOwner, NS_ERROR_FAILURE); NS_ENSURE_SUCCESS(treeOwner->SizeShellTo(docShellAsItem, width, height), NS_ERROR_FAILURE); return NS_OK; } #ifdef XP_MAC #pragma mark - #endif NS_IMPL_ISUPPORTS(nsDocViewerSelectionListener, NS_GET_IID(nsISelectionListener)); nsresult nsDocViewerSelectionListener::Init(DocumentViewerImpl *aDocViewer) { mDocViewer = aDocViewer; return NS_OK; } /* * GetPopupNode, GetPopupLinkNode and GetPopupImageNode are helpers * for the cmd_copyLink / cmd_copyImageLocation / cmd_copyImageContents family * of commands. The focus controller stores the popup node, these retrieve * them and munge appropriately. Note that we have to store the popup node * rather than retrieving it from EventStateManager::GetFocusedContent because * not all content (images included) can receive focus. */ nsresult DocumentViewerImpl::GetPopupNode(nsIDOMNode** aNode) { NS_ENSURE_ARG_POINTER(aNode); nsresult rv; // get the document nsCOMPtr document; rv = GetDocument(*getter_AddRefs(document)); NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_TRUE(document, NS_ERROR_FAILURE); // get the script global object nsCOMPtr global; rv = document->GetScriptGlobalObject(getter_AddRefs(global)); NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_TRUE(global, NS_ERROR_FAILURE); // get the internal dom window nsCOMPtr internalWin(do_QueryInterface(global, &rv)); NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_TRUE(internalWin, NS_ERROR_FAILURE); // get the private dom window nsCOMPtr privateWin(do_QueryInterface(internalWin, &rv)); NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_TRUE(privateWin, NS_ERROR_FAILURE); // get the focus controller nsCOMPtr focusController; rv = privateWin->GetRootFocusController(getter_AddRefs(focusController)); NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_TRUE(focusController, NS_ERROR_FAILURE); // get the popup node rv = focusController->GetPopupNode(aNode); // addref happens here NS_ENSURE_SUCCESS(rv, rv); return rv; } /* * XXX dr * ------ * Note: the args to these two methods are DOM nodes and not specifically * HTML anchor or image nodes because a link can also be an xlink, and an * image can also be an object... The impls are broken right now to just * think about HTML anchors and images but consumers of these methods should * do their own checking. */ // GetPopupLinkNode: return popup link node or fail nsresult DocumentViewerImpl::GetPopupLinkNode(nsIDOMNode** aNode) { NS_ENSURE_ARG_POINTER(aNode); // you get null unless i say so *aNode = nsnull; // find popup node nsCOMPtr node; nsresult rv = GetPopupNode(getter_AddRefs(node)); NS_ENSURE_SUCCESS(rv, rv); // find out if we have an anchor in our ancestry. this really ought // to look for xlinks also, but this is good enough for now. while (node) { // are we an anchor? nsCOMPtr anchor(do_QueryInterface(node, &rv)); if (NS_SUCCEEDED(rv) && anchor) { *aNode = node; NS_IF_ADDREF(*aNode); // addref return NS_OK; } else { // if not, get our parent and keep trying... nsCOMPtr parentNode; node->GetParentNode(getter_AddRefs(parentNode)); node = parentNode; } } // if we have no node, fail return NS_ERROR_FAILURE; } // GetPopupLinkNode: return popup image node or fail nsresult DocumentViewerImpl::GetPopupImageNode(nsIDOMNode** aNode) { NS_ENSURE_ARG_POINTER(aNode); // you get null unless i say so *aNode = nsnull; // find popup node nsCOMPtr node; nsresult rv = GetPopupNode(getter_AddRefs(node)); NS_ENSURE_SUCCESS(rv, rv); // find out if we're an image. this really ought to look for objects // with type "image/...", but this is good enough for now. nsCOMPtr img(do_QueryInterface(node, &rv)); if (NS_FAILED(rv)) return rv; NS_ENSURE_TRUE(img, NS_ERROR_FAILURE); // if we made it here, we're an image. *aNode = node; NS_IF_ADDREF(*aNode); // addref return NS_OK; } /* * XXX dr * ------ * These two functions -- GetInLink and GetInImage -- are kind of annoying * in that they only get called from the controller (in * nsDOMWindowController::IsCommandEnabled). The actual construction of the * context menus in communicator (nsContextMenu.js) has its own, redundant * tests. No big deal, but good to keep in mind if we ever clean context * menus. */ NS_IMETHODIMP DocumentViewerImpl::GetInLink(PRBool* aInLink) { #ifdef DEBUG_dr printf("dr :: DocumentViewerImpl::GetInLink\n"); #endif NS_ENSURE_ARG_POINTER(aInLink); // we're not in a link unless i say so *aInLink = PR_FALSE; // get the popup link nsCOMPtr node; nsresult rv = GetPopupLinkNode(getter_AddRefs(node)); if (NS_FAILED(rv)) return rv; NS_ENSURE_TRUE(node, NS_ERROR_FAILURE); // if we made it here, we're in a link *aInLink = PR_TRUE; return NS_OK; } NS_IMETHODIMP DocumentViewerImpl::GetInImage(PRBool* aInImage) { #ifdef DEBUG_dr printf("dr :: DocumentViewerImpl::GetInImage\n"); #endif NS_ENSURE_ARG_POINTER(aInImage); // we're not in an image unless i say so *aInImage = PR_FALSE; // get the popup image nsCOMPtr node; nsresult rv = GetPopupImageNode(getter_AddRefs(node)); if (NS_FAILED(rv)) return rv; NS_ENSURE_TRUE(node, NS_ERROR_FAILURE); // if we made it here, we're in an image *aInImage = PR_TRUE; return NS_OK; } NS_IMETHODIMP nsDocViewerSelectionListener::NotifySelectionChanged(nsIDOMDocument *, nsISelection *, short) { NS_ASSERTION(mDocViewer, "Should have doc viewer!"); // get the selection state nsCOMPtr selection; nsresult rv = mDocViewer->GetDocumentSelection(getter_AddRefs(selection)); if (NS_FAILED(rv)) return rv; PRBool selectionCollapsed; selection->GetIsCollapsed(&selectionCollapsed); // we only call UpdateCommands when the selection changes from collapsed // to non-collapsed or vice versa. We might need another update string // for simple selection changes, but that would be expenseive. if (!mGotSelectionState || mSelectionWasCollapsed != selectionCollapsed) { nsCOMPtr theDoc; mDocViewer->GetDocument(*getter_AddRefs(theDoc)); if (!theDoc) return NS_ERROR_FAILURE; nsCOMPtr scriptGlobalObject; theDoc->GetScriptGlobalObject(getter_AddRefs(scriptGlobalObject)); nsCOMPtr domWindow = do_QueryInterface(scriptGlobalObject); if (!domWindow) return NS_ERROR_FAILURE; domWindow->UpdateCommands(NS_LITERAL_STRING("select")); mGotSelectionState = PR_TRUE; mSelectionWasCollapsed = selectionCollapsed; } return NS_OK; } //nsDocViewerFocusListener NS_IMPL_ISUPPORTS(nsDocViewerFocusListener, NS_GET_IID(nsIDOMFocusListener)); nsDocViewerFocusListener::nsDocViewerFocusListener() :mDocViewer(nsnull) { NS_INIT_REFCNT(); } nsDocViewerFocusListener::~nsDocViewerFocusListener(){} nsresult nsDocViewerFocusListener::HandleEvent(nsIDOMEvent* aEvent) { return NS_OK; } nsresult nsDocViewerFocusListener::Focus(nsIDOMEvent* aEvent) { nsCOMPtr shell; if(!mDocViewer) return NS_ERROR_FAILURE; nsresult result = mDocViewer->GetPresShell(*getter_AddRefs(shell));//deref once cause it take a ptr ref if(NS_FAILED(result) || !shell) return result?result:NS_ERROR_FAILURE; nsCOMPtr selCon; selCon = do_QueryInterface(shell); PRInt16 selectionStatus; selCon->GetDisplaySelection( &selectionStatus); //if selection was nsISelectionController::SELECTION_OFF, do nothing //otherwise re-enable it. if(selectionStatus == nsISelectionController::SELECTION_DISABLED || selectionStatus == nsISelectionController::SELECTION_HIDDEN) { selCon->SetDisplaySelection(nsISelectionController::SELECTION_ON); selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL); } return result; } nsresult nsDocViewerFocusListener::Blur(nsIDOMEvent* aEvent) { nsCOMPtr shell; if(!mDocViewer) return NS_ERROR_FAILURE; nsresult result = mDocViewer->GetPresShell(*getter_AddRefs(shell));//deref once cause it take a ptr ref if(NS_FAILED(result) || !shell) return result?result:NS_ERROR_FAILURE; nsCOMPtr selCon; selCon = do_QueryInterface(shell); PRInt16 selectionStatus; selCon->GetDisplaySelection(&selectionStatus); //if selection was nsISelectionController::SELECTION_OFF, do nothing //otherwise re-enable it. if(selectionStatus == nsISelectionController::SELECTION_ON) { selCon->SetDisplaySelection(nsISelectionController::SELECTION_DISABLED); selCon->RepaintSelection(nsISelectionController::SELECTION_NORMAL); } return result; } nsresult nsDocViewerFocusListener::Init(DocumentViewerImpl *aDocViewer) { mDocViewer = aDocViewer; return NS_OK; } PRBool DocumentViewerImpl::IsWindowsInOurSubTree(nsIDOMWindowInternal * aDOMWindow) { PRBool found = PR_FALSE; if(aDOMWindow) { // now check to make sure it is in "our" tree of webshells nsCOMPtr scriptObj(do_QueryInterface(aDOMWindow)); if (scriptObj) { nsCOMPtr docShell; scriptObj->GetDocShell(getter_AddRefs(docShell)); if (docShell) { nsCOMPtr docShellAsItem(do_QueryInterface(docShell)); if (docShellAsItem) { // get this DocViewer webshell nsCOMPtr thisDVWebShell(do_QueryInterface(mContainer)); while (!found) { nsCOMPtr docShellParent; docShellAsItem->GetSameTypeParent(getter_AddRefs(docShellParent)); if (docShellParent) { nsCOMPtr parentWebshell(do_QueryInterface(docShellParent)); if (parentWebshell) { if (parentWebshell.get() == thisDVWebShell.get()) { found = PR_TRUE; break; } } } else { break; // at top of tree } docShellAsItem = docShellParent; } // while } } // docshell } // scriptobj } // domWindow return found; } /** --------------------------------------------------- * Get the Focused Frame for a documentviewer * */ nsIDOMWindowInternal* DocumentViewerImpl::FindFocusedDOMWindowInternal() { nsCOMPtr theDOMWin; nsCOMPtr theDoc; nsCOMPtr theSGO; nsCOMPtr focusController; nsIDOMWindowInternal * domWin = nsnull; this->GetDocument(*getter_AddRefs(theDoc)); if(theDoc){ theDoc->GetScriptGlobalObject(getter_AddRefs(theSGO)); if(theSGO){ nsCOMPtr theDOMWindow = do_QueryInterface(theSGO); if(theDOMWindow){ theDOMWindow->GetRootFocusController(getter_AddRefs(focusController)); if(focusController){ focusController->GetFocusedWindow(getter_AddRefs(theDOMWin)); domWin = theDOMWin.get(); if(domWin != nsnull) { if (IsWindowsInOurSubTree(domWin)){ NS_ADDREF(domWin); } else { domWin = nsnull; } } } } } } return domWin; } /*=============== Timer Related Code ======================*/ nsresult DocumentViewerImpl::StartPagePrintTimer(nsIPresContext * aPresContext, nsIPrintOptions* aPrintOptions, PrintObject* aPOect, PRUint32 aDelay) { nsresult result; if (!mPagePrintTimer) { result = NS_NewUpdateTimer(&mPagePrintTimer); if (NS_FAILED(result)) return result; } return mPagePrintTimer->Start(this, aPresContext, aPrintOptions, aPOect, aDelay); } inline void DocumentViewerImpl::StopPagePrintTimer() { if (mPagePrintTimer) { mPagePrintTimer->Stop(); } }