Bug 468568. Main patch: support downloading fonts in printing and print preview. r=smaug

--HG--
extra : rebase_source : 2fbaef2896d218e6900449c9510fc867419eac30
This commit is contained in:
Julian Viereck 2012-09-04 16:29:27 +03:00
parent c8bef43a8a
commit d3cd6b36b2
6 changed files with 455 additions and 168 deletions

View File

@ -62,8 +62,11 @@ nsDataDocumentContentPolicy::ShouldLoad(uint32_t aContentType,
// Nothing else is OK to load for data documents
if (doc->IsLoadedAsData()) {
*aDecision = nsIContentPolicy::REJECT_TYPE;
return NS_OK;
// ...but let static (print/print preview) documents to load fonts.
if (!doc->IsStaticDocument() || aContentType != nsIContentPolicy::TYPE_FONT) {
*aDecision = nsIContentPolicy::REJECT_TYPE;
return NS_OK;
}
}
if (doc->IsBeingUsedAsImage()) {

View File

@ -127,6 +127,7 @@
#include "nsContentPolicyUtils.h"
#include "nsICategoryManager.h"
#include "nsIDocumentLoaderFactory.h"
#include "nsIDocumentLoader.h"
#include "nsIContentViewer.h"
#include "nsIXMLContentSink.h"
#include "nsIXULDocument.h"
@ -7628,8 +7629,15 @@ nsDocument::CloneDocHelper(nsDocument* clone) const
clone->mDocumentBaseURI = mDocumentBaseURI;
if (mCreatingStaticClone) {
nsCOMPtr<nsILoadGroup> loadGroup;
// |mDocumentContainer| is the container of the document that is being
// created and not the original container. See CreateStaticClone function().
nsCOMPtr<nsIDocumentLoader> docLoader = do_QueryReferent(mDocumentContainer);
if (docLoader) {
docLoader->GetLoadGroup(getter_AddRefs(loadGroup));
}
nsCOMPtr<nsIChannel> channel = GetChannel();
nsCOMPtr<nsILoadGroup> loadGroup = GetDocumentLoadGroup();
if (channel && loadGroup) {
clone->Reset(channel, loadGroup);
} else {

View File

@ -433,7 +433,7 @@ protected:
nsCOMPtr<nsIPrintSettings> mCachedPrintSettings;
nsCOMPtr<nsIWebProgressListener> mCachedPrintWebProgressListner;
nsCOMPtr<nsPrintEngine> mPrintEngine;
nsRefPtr<nsPrintEngine> mPrintEngine;
float mOriginalPrintPreviewScale;
float mPrintPreviewZoom;
nsAutoPtr<nsPrintEventDispatcher> mBeforeAndAfterPrint;

View File

@ -37,6 +37,7 @@ include $(topsrcdir)/config/rules.mk
LOCAL_INCLUDES += \
-I$(srcdir)/../base \
-I$(srcdir)/../../content/base/src \
-I$(srcdir)/../../view/src \
$(NULL)
DEFINES += -D_IMPL_NS_LAYOUT

View File

@ -18,6 +18,9 @@
#include "nsITextToSubURI.h"
#include "nsError.h"
#include "nsView.h"
#include "nsAsyncDOMEvent.h"
// Print Options
#include "nsIPrintSettings.h"
#include "nsIPrintSettingsService.h"
@ -209,7 +212,8 @@ protected:
// Class IDs
static NS_DEFINE_CID(kViewManagerCID, NS_VIEW_MANAGER_CID);
NS_IMPL_ISUPPORTS1(nsPrintEngine, nsIObserver)
NS_IMPL_ISUPPORTS3(nsPrintEngine, nsIWebProgressListener,
nsISupportsWeakReference, nsIObserver)
//---------------------------------------------------
//-- nsPrintEngine Class Impl
@ -225,7 +229,9 @@ nsPrintEngine::nsPrintEngine() :
mPageSeqFrame(nullptr),
mPrtPreview(nullptr),
mOldPrtPreview(nullptr),
mDebugFile(nullptr)
mDebugFile(nullptr),
mLoadCounter(0),
mDidLoadDataForPrinting(false)
{
}
@ -672,6 +678,23 @@ nsPrintEngine::DoCommonPrint(bool aIsPrintPreview,
}
}
if (mPrt->mPrintFrameType == nsIPrintSettings::kEachFrameSep) {
CheckForChildFrameSets(mPrt->mPrintObject);
}
if (NS_FAILED(EnablePOsForPrinting())) {
return NS_ERROR_FAILURE;
}
// Attach progressListener to catch network requests.
nsCOMPtr<nsIWebProgress> webProgress = do_QueryInterface(mPrt->mPrintObject->mDocShell);
webProgress->AddProgressListener(
static_cast<nsIWebProgressListener*>(this),
nsIWebProgress::NOTIFY_STATE_REQUEST);
mLoadCounter = 0;
mDidLoadDataForPrinting = false;
if (aIsPrintPreview) {
bool notifyOnInit = false;
ShowPrintProgress(false, notifyOnInit);
@ -680,19 +703,19 @@ nsPrintEngine::DoCommonPrint(bool aIsPrintPreview,
TurnScriptingOn(false);
if (!notifyOnInit) {
rv = FinishPrintPreview();
InstallPrintPreviewListener();
rv = InitPrintDocConstruction(false);
} else {
rv = NS_OK;
}
NS_ENSURE_SUCCESS(rv, rv);
} else {
bool doNotify;
ShowPrintProgress(true, doNotify);
if (!doNotify) {
// Print listener setup...
mPrt->OnStartPrinting();
rv = DocumentReadyForPrinting();
NS_ENSURE_SUCCESS(rv, rv);
rv = InitPrintDocConstruction(false);
}
}
@ -804,10 +827,19 @@ nsPrintEngine::GetPrintPreviewNumPages(int32_t *aPrintPreviewNumPages)
{
NS_ENSURE_ARG_POINTER(aPrintPreviewNumPages);
nsPrintData* prt = nullptr;
nsIFrame* seqFrame = nullptr;
*aPrintPreviewNumPages = 0;
if (!mPrtPreview ||
NS_FAILED(GetSeqFrameAndCountPagesInternal(mPrtPreview->mPrintObject, seqFrame, *aPrintPreviewNumPages))) {
// When calling this function, the FinishPrintPreview() function might not
// been called as there are still some
if (mPrtPreview) {
prt = mPrtPreview;
} else {
prt = mPrt;
}
if ((!prt) ||
NS_FAILED(GetSeqFrameAndCountPagesInternal(prt->mPrintObject, seqFrame, *aPrintPreviewNumPages))) {
return NS_ERROR_FAILURE;
}
return NS_OK;
@ -1598,39 +1630,81 @@ nsPrintEngine::ShowPrintErrorDialog(nsresult aPrintError, bool aIsPrinting)
//-- Section: Reflow Methods
//-----------------------------------------------------------------
nsresult
nsPrintEngine::ReconstructAndReflow(bool doSetPixelScale)
{
#if (defined(XP_WIN) || defined(XP_OS2)) && defined(EXTENDED_DEBUG_PRINTING)
// We need to clear all the output files here
// because they will be re-created with second reflow of the docs
if (kPrintingLogMod && kPrintingLogMod->level == DUMP_LAYOUT_LEVEL) {
RemoveFilesInDir(".\\");
gDumpFileNameCnt = 0;
gDumpLOFileNameCnt = 0;
}
#endif
for (uint32_t i = 0; i < mPrt->mPrintDocList.Length(); ++i) {
nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i);
NS_ASSERTION(po, "nsPrintObject can't be null!");
if (po->mDontPrint || po->mInvisible) {
continue;
}
UpdateZoomRatio(po, doSetPixelScale);
po->mPresContext->SetPageScale(po->mZoomRatio);
// Calculate scale factor from printer to screen
float printDPI = float(mPrt->mPrintDC->AppUnitsPerCSSInch()) /
float(mPrt->mPrintDC->AppUnitsPerDevPixel());
po->mPresContext->SetPrintPreviewScale(mScreenDPI / printDPI);
po->mPresShell->ReconstructFrames();
// For all views except the first one, setup the root view.
// ??? Can there be multiple po for the top-level-document?
bool documentIsTopLevel = true;
if (i != 0) {
nsSize adjSize;
bool doReturn;
nsresult rv = SetRootView(po, doReturn, documentIsTopLevel, adjSize);
MOZ_ASSERT(!documentIsTopLevel, "How could this happen?");
if (NS_FAILED(rv) || doReturn) {
return rv;
}
}
po->mPresShell->FlushPendingNotifications(Flush_Layout);
nsresult rv = UpdateSelectionAndShrinkPrintObject(po, documentIsTopLevel);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
//-------------------------------------------------------
nsresult
nsPrintEngine::SetupToPrintContent()
{
// In this step we figure out which documents should be printed
// i.e. if we are printing the selection then only enable that nsPrintObject
// for printing
if (NS_FAILED(EnablePOsForPrinting())) {
return NS_ERROR_FAILURE;
}
DUMP_DOC_LIST("\nAfter Enable------------------------------------------");
nsresult rv;
// This is an Optimization
// If we are in PP then we already know all the shrinkage information
// so just transfer it to the PrintData and we will skip the extra shrinkage reflow
//
// doSetPixelScale tells Reflow whether to set the shrinkage value into the DC
// The first time we do not want to do this, the second time through we do
bool doSetPixelScale = false;
bool ppIsShrinkToFit = mPrtPreview && mPrtPreview->mShrinkToFit;
if (ppIsShrinkToFit) {
mPrt->mShrinkRatio = mPrtPreview->mShrinkRatio;
doSetPixelScale = true;
bool didReconstruction = false;
// If some new content got loaded since the initial reflow rebuild
// everything.
if (mDidLoadDataForPrinting) {
rv = ReconstructAndReflow(DoSetPixelScale());
didReconstruction = true;
NS_ENSURE_SUCCESS(rv, rv);
}
// Here we reflow all the PrintObjects
nsresult rv = ReflowDocList(mPrt->mPrintObject, doSetPixelScale);
if (NS_FAILED(rv)) {
return NS_ERROR_FAILURE;
}
// Here is where we do the extra reflow for shrinking the content
// Here is where we figure out if extra reflow for shrinking the content
// is required.
// But skip this step if we are in PrintPreview
bool ppIsShrinkToFit = mPrtPreview && mPrtPreview->mShrinkToFit;
if (mPrt->mShrinkToFit && !ppIsShrinkToFit) {
// Now look for the PO that has the smallest percent for shrink to fit
if (mPrt->mPrintDocList.Length() > 1 && mPrt->mPrintObject->mFrameType == eFrameSet) {
@ -1645,54 +1719,37 @@ nsPrintEngine::SetupToPrintContent()
mPrt->mShrinkRatio = mPrt->mPrintObject->mShrinkRatio;
}
// Only Shrink if we are smaller
if (mPrt->mShrinkRatio < 0.998f) {
for (uint32_t i=0;i<mPrt->mPrintDocList.Length();i++) {
nsPrintObject* po = mPrt->mPrintDocList.ElementAt(i);
NS_ASSERTION(po, "nsPrintObject can't be null!");
// Wipe out the presentation before we reflow
po->DestroyPresentation();
}
#if (defined(XP_WIN) || defined(XP_OS2)) && defined(EXTENDED_DEBUG_PRINTING)
// We need to clear all the output files here
// because they will be re-created with second reflow of the docs
if (kPrintingLogMod && kPrintingLogMod->level == DUMP_LAYOUT_LEVEL) {
RemoveFilesInDir(".\\");
gDumpFileNameCnt = 0;
gDumpLOFileNameCnt = 0;
}
#endif
// Here we reflow all the PrintObjects a second time
// this time using the shrinkage values
// The last param here tells reflow to NOT calc the shrinkage values
if (NS_FAILED(ReflowDocList(mPrt->mPrintObject, true))) {
return NS_ERROR_FAILURE;
}
rv = ReconstructAndReflow(true);
didReconstruction = true;
NS_ENSURE_SUCCESS(rv, rv);
}
#ifdef PR_LOGGING
{
float calcRatio = 0.0f;
if (mPrt->mPrintDocList.Length() > 1 && mPrt->mPrintObject->mFrameType == eFrameSet) {
nsPrintObject* smallestPO = FindSmallestSTF();
NS_ASSERTION(smallestPO, "There must always be an XMost PO!");
if (smallestPO) {
// Calc the shrinkage based on the entire content area
calcRatio = smallestPO->mShrinkRatio;
}
} else {
// Single document so use the Shrink as calculated for the PO
calcRatio = mPrt->mPrintObject->mShrinkRatio;
float calcRatio = 0.0f;
if (mPrt->mPrintDocList.Length() > 1 && mPrt->mPrintObject->mFrameType == eFrameSet) {
nsPrintObject* smallestPO = FindSmallestSTF();
NS_ASSERTION(smallestPO, "There must always be an XMost PO!");
if (smallestPO) {
// Calc the shrinkage based on the entire content area
calcRatio = smallestPO->mShrinkRatio;
}
PR_PL(("**************************************************************************\n"));
PR_PL(("STF Ratio is: %8.5f Effective Ratio: %8.5f Diff: %8.5f\n", mPrt->mShrinkRatio, calcRatio, mPrt->mShrinkRatio-calcRatio));
PR_PL(("**************************************************************************\n"));
} else {
// Single document so use the Shrink as calculated for the PO
calcRatio = mPrt->mPrintObject->mShrinkRatio;
}
PR_PL(("**************************************************************************\n"));
PR_PL(("STF Ratio is: %8.5f Effective Ratio: %8.5f Diff: %8.5f\n", mPrt->mShrinkRatio, calcRatio, mPrt->mShrinkRatio-calcRatio));
PR_PL(("**************************************************************************\n"));
#endif
}
// If the frames got reconstructed and reflowed the number of pages might
// has changed.
if (didReconstruction) {
FirePrintPreviewUpdateEvent();
}
DUMP_DOC_LIST(("\nAfter Reflow------------------------------------------"));
PR_PL(("\n"));
PR_PL(("-------------------------------------------------------\n"));
@ -1792,21 +1849,7 @@ nsPrintEngine::ReflowDocList(nsPrintObject* aPO, bool aSetPixelScale)
}
}
// Here is where we set the shrinkage value into the DC
// and this is what actually makes it shrink
if (aSetPixelScale && aPO->mFrameType != eIFrame) {
float ratio;
if (mPrt->mPrintFrameType == nsIPrintSettings::kFramesAsIs || mPrt->mPrintFrameType == nsIPrintSettings::kNoFrames) {
ratio = mPrt->mShrinkRatio - 0.005f; // round down
} else {
ratio = aPO->mShrinkRatio - 0.005f; // round down
}
aPO->mZoomRatio = ratio;
} else if (!mPrt->mShrinkToFit) {
double scaling;
mPrt->mPrintSettings->GetScaling(&scaling);
aPO->mZoomRatio = float(scaling);
}
UpdateZoomRatio(aPO, aSetPixelScale);
nsresult rv;
// Reflow the PO
@ -1821,28 +1864,248 @@ nsPrintEngine::ReflowDocList(nsPrintObject* aPO, bool aSetPixelScale)
return NS_OK;
}
//-------------------------------------------------------
// Reflow a nsPrintObject
nsresult
nsPrintEngine::ReflowPrintObject(nsPrintObject * aPO)
void
nsPrintEngine::FirePrintPreviewUpdateEvent()
{
NS_ASSERTION(aPO, "Pointer is null!");
if (!aPO) return NS_ERROR_FAILURE;
// Dispatch the event only while in PrintPreview. When printing, there is no
// listener bound to this event and therefore no need to dispatch it.
if (mIsDoingPrintPreview && !mIsDoingPrinting) {
nsCOMPtr<nsIContentViewer> cv = do_QueryInterface(mDocViewerPrint);
(new nsAsyncDOMEvent(
cv->GetDocument(), NS_LITERAL_STRING("printPreviewUpdate"), true, true)
)->RunDOMEventWhenSafe();
}
}
nsSize adjSize;
bool documentIsTopLevel;
if (!aPO->IsPrintable())
nsresult
nsPrintEngine::InitPrintDocConstruction(bool aHandleError)
{
nsresult rv;
rv = ReflowDocList(mPrt->mPrintObject, DoSetPixelScale());
NS_ENSURE_SUCCESS(rv, rv);
FirePrintPreviewUpdateEvent();
if (mLoadCounter == 0) {
AfterNetworkPrint(aHandleError);
}
return rv;
}
nsresult
nsPrintEngine::AfterNetworkPrint(bool aHandleError)
{
nsCOMPtr<nsIWebProgress> webProgress = do_QueryInterface(mPrt->mPrintObject->mDocShell);
webProgress->RemoveProgressListener(
static_cast<nsIWebProgressListener*>(this));
nsresult rv;
if (mIsDoingPrinting) {
rv = DocumentReadyForPrinting();
} else {
rv = FinishPrintPreview();
}
/* cleaup on failure + notify user */
if (aHandleError && NS_FAILED(rv)) {
CleanupOnFailure(rv, !mIsDoingPrinting);
}
return rv;
}
////////////////////////////////////////////////////////////////////////////////
// nsIWebProgressListener
NS_IMETHODIMP
nsPrintEngine::OnStateChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
uint32_t aStateFlags,
nsresult aStatus)
{
nsAutoCString name;
aRequest->GetName(name);
if (name.Equals("about:document-onload-blocker")) {
return NS_OK;
}
if (aStateFlags & STATE_START) {
nsCOMPtr<nsIChannel> channel = do_QueryInterface(aRequest);
++mLoadCounter;
} else if (aStateFlags & STATE_STOP) {
mDidLoadDataForPrinting = true;
--mLoadCounter;
// If all resources are loaded, then do a small timeout and if there
// are still no new requests, then another reflow.
if (mLoadCounter == 0) {
AfterNetworkPrint(true);
}
}
return NS_OK;
}
NS_IMETHODIMP
nsPrintEngine::OnProgressChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
int32_t aCurSelfProgress,
int32_t aMaxSelfProgress,
int32_t aCurTotalProgress,
int32_t aMaxTotalProgress)
{
NS_NOTREACHED("notification excluded in AddProgressListener(...)");
return NS_OK;
}
NS_IMETHODIMP
nsPrintEngine::OnLocationChange(nsIWebProgress* aWebProgress,
nsIRequest* aRequest,
nsIURI* aLocation,
uint32_t aFlags)
{
NS_NOTREACHED("notification excluded in AddProgressListener(...)");
return NS_OK;
}
NS_IMETHODIMP
nsPrintEngine::OnStatusChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest,
nsresult aStatus,
const PRUnichar *aMessage)
{
NS_NOTREACHED("notification excluded in AddProgressListener(...)");
return NS_OK;
}
NS_IMETHODIMP
nsPrintEngine::OnSecurityChange(nsIWebProgress *aWebProgress,
nsIRequest *aRequest,
uint32_t aState)
{
NS_NOTREACHED("notification excluded in AddProgressListener(...)");
return NS_OK;
}
//-------------------------------------------------------
void
nsPrintEngine::UpdateZoomRatio(nsPrintObject* aPO, bool aSetPixelScale)
{
// Here is where we set the shrinkage value into the DC
// and this is what actually makes it shrink
if (aSetPixelScale && aPO->mFrameType != eIFrame) {
float ratio;
if (mPrt->mPrintFrameType == nsIPrintSettings::kFramesAsIs || mPrt->mPrintFrameType == nsIPrintSettings::kNoFrames) {
ratio = mPrt->mShrinkRatio - 0.005f; // round down
} else {
ratio = aPO->mShrinkRatio - 0.005f; // round down
}
aPO->mZoomRatio = ratio;
} else if (!mPrt->mShrinkToFit) {
double scaling;
mPrt->mPrintSettings->GetScaling(&scaling);
aPO->mZoomRatio = float(scaling);
}
}
nsresult
nsPrintEngine::UpdateSelectionAndShrinkPrintObject(nsPrintObject* aPO,
bool aDocumentIsTopLevel)
{
nsCOMPtr<nsIPresShell> displayShell;
aPO->mDocShell->GetPresShell(getter_AddRefs(displayShell));
// Transfer Selection Ranges to the new Print PresShell
nsCOMPtr<nsISelection> selection, selectionPS;
// It's okay if there is no display shell, just skip copying the selection
if (displayShell) {
selection = displayShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
}
selectionPS = aPO->mPresShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
// Reset all existing selection ranges that might have been added by calling
// this function before.
if (selectionPS) {
selectionPS->RemoveAllRanges();
}
if (selection && selectionPS) {
int32_t cnt;
selection->GetRangeCount(&cnt);
int32_t inx;
for (inx = 0; inx < cnt; ++inx) {
nsCOMPtr<nsIDOMRange> range;
if (NS_SUCCEEDED(selection->GetRangeAt(inx, getter_AddRefs(range))))
selectionPS->AddRange(range);
}
}
// If we are trying to shrink the contents to fit on the page
// we must first locate the "pageContent" frame
// Then we walk the frame tree and look for the "xmost" frame
// this is the frame where the right-hand side of the frame extends
// the furthest
if (mPrt->mShrinkToFit && aDocumentIsTopLevel) {
nsIPageSequenceFrame* pageSequence = aPO->mPresShell->GetPageSequenceFrame();
NS_ENSURE_STATE(pageSequence);
pageSequence->GetSTFPercent(aPO->mShrinkRatio);
}
return NS_OK;
}
bool
nsPrintEngine::DoSetPixelScale()
{
// This is an Optimization
// If we are in PP then we already know all the shrinkage information
// so just transfer it to the PrintData and we will skip the extra shrinkage reflow
//
// doSetPixelScale tells Reflow whether to set the shrinkage value into the DC
// The first time we do not want to do this, the second time through we do
bool doSetPixelScale = false;
bool ppIsShrinkToFit = mPrtPreview && mPrtPreview->mShrinkToFit;
if (ppIsShrinkToFit) {
mPrt->mShrinkRatio = mPrtPreview->mShrinkRatio;
doSetPixelScale = true;
}
return doSetPixelScale;
}
nsIView*
nsPrintEngine::GetParentViewForRoot()
{
if (mIsCreatingPrintPreview) {
nsCOMPtr<nsIContentViewer> cv = do_QueryInterface(mDocViewerPrint);
if (cv) {
return cv->FindContainerView();
}
}
return nullptr;
}
nsresult
nsPrintEngine::SetRootView(
nsPrintObject* aPO,
bool& doReturn,
bool& documentIsTopLevel,
nsSize& adjSize
)
{
bool canCreateScrollbars = true;
nsIView* rootView;
nsIView* parentView = nullptr;
doReturn = false;
if (aPO->mParent && aPO->mParent->IsPrintable()) {
nsIFrame* frame = aPO->mContent ? aPO->mContent->GetPrimaryFrame() : nullptr;
// Without a frame, this document can't be displayed; therefore, there is no
// point to reflowing it
if (!frame) {
SetPrintPO(aPO, false);
doReturn = true;
return NS_OK;
}
@ -1867,21 +2130,51 @@ nsPrintEngine::ReflowPrintObject(nsPrintObject * aPO)
mPrt->mPrintDC->GetDeviceSurfaceDimensions(pageWidth, pageHeight);
adjSize = nsSize(pageWidth, pageHeight);
documentIsTopLevel = true;
if (mIsCreatingPrintPreview) {
nsCOMPtr<nsIContentViewer> cv = do_QueryInterface(mDocViewerPrint);
if (cv) {
parentView = cv->FindContainerView();
}
}
parentView = GetParentViewForRoot();
}
if (aPO->mPresShell->GetViewManager()->GetRootView()) {
// Reuse the root view that is already on the root frame.
rootView = aPO->mPresShell->GetRootFrame()->GetView();
reinterpret_cast<nsView*>(rootView)->SetParent(reinterpret_cast<nsView*>(parentView));
} else {
// Create a child window of the parent that is our "root view/window"
nsRect tbounds = nsRect(nsPoint(0, 0), adjSize);
rootView = aPO->mViewManager->CreateView(tbounds, parentView);
NS_ENSURE_TRUE(rootView, NS_ERROR_OUT_OF_MEMORY);
}
if (mIsCreatingPrintPreview && documentIsTopLevel) {
aPO->mPresContext->SetPaginatedScrolling(canCreateScrollbars);
}
// Setup hierarchical relationship in view manager
aPO->mViewManager->SetRootView(rootView);
return NS_OK;
}
// Reflow a nsPrintObject
nsresult
nsPrintEngine::ReflowPrintObject(nsPrintObject * aPO)
{
NS_ENSURE_STATE(aPO);
if (!aPO->IsPrintable()) {
return NS_OK;
}
NS_ASSERTION(!aPO->mPresContext, "Recreating prescontext");
// create the PresContext
aPO->mPresContext = new nsPresContext(aPO->mDocument,
mIsCreatingPrintPreview ? nsPresContext::eContext_PrintPreview:
nsPresContext::eContext_Print);
nsPresContext::nsPresContextType type =
mIsCreatingPrintPreview ? nsPresContext::eContext_PrintPreview:
nsPresContext::eContext_Print;
nsIView* parentView =
aPO->mParent && aPO->mParent->IsPrintable() ? nullptr : GetParentViewForRoot();
aPO->mPresContext = parentView ?
new nsPresContext(aPO->mDocument, type) :
new nsRootPresContext(aPO->mDocument, type);
NS_ENSURE_TRUE(aPO->mPresContext, NS_ERROR_OUT_OF_MEMORY);
aPO->mPresContext->SetPrintSettings(mPrt->mPrintSettings);
@ -1917,20 +2210,20 @@ nsPrintEngine::ReflowPrintObject(nsPrintObject * aPO)
// The pres shell now owns the style set object.
PR_PL(("In DV::ReflowPrintObject PO: %p (%9s) Setting w,h to %d,%d\n", aPO,
gFrameTypesStr[aPO->mFrameType], adjSize.width, adjSize.height));
// Create a child window of the parent that is our "root view/window"
nsRect tbounds = nsRect(nsPoint(0, 0), adjSize);
nsIView* rootView = aPO->mViewManager->CreateView(tbounds, parentView);
NS_ENSURE_TRUE(rootView, NS_ERROR_OUT_OF_MEMORY);
bool doReturn = false;;
bool documentIsTopLevel = false;
nsSize adjSize;
if (mIsCreatingPrintPreview && documentIsTopLevel) {
aPO->mPresContext->SetPaginatedScrolling(canCreateScrollbars);
rv = SetRootView(aPO, doReturn, documentIsTopLevel, adjSize);
if (NS_FAILED(rv) || doReturn) {
return rv;
}
// Setup hierarchical relationship in view manager
aPO->mViewManager->SetRootView(rootView);
PR_PL(("In DV::ReflowPrintObject PO: %p pS: %p (%9s) Setting w,h to %d,%d\n", aPO, aPO->mPresShell.get(),
gFrameTypesStr[aPO->mFrameType], adjSize.width, adjSize.height));
// This docshell stuff is weird; will go away when we stop having multiple
// presentations per document
@ -1961,36 +2254,8 @@ nsPrintEngine::ReflowPrintObject(nsPrintObject * aPO)
// Process the reflow event Initialize posted
aPO->mPresShell->FlushPendingNotifications(Flush_Layout);
nsCOMPtr<nsIPresShell> displayShell;
aPO->mDocShell->GetPresShell(getter_AddRefs(displayShell));
// Transfer Selection Ranges to the new Print PresShell
nsCOMPtr<nsISelection> selection, selectionPS;
// It's okay if there is no display shell, just skip copying the selection
if (displayShell) {
selection = displayShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
}
selectionPS = aPO->mPresShell->GetCurrentSelection(nsISelectionController::SELECTION_NORMAL);
if (selection && selectionPS) {
int32_t cnt;
selection->GetRangeCount(&cnt);
int32_t inx;
for (inx=0;inx<cnt;inx++) {
nsCOMPtr<nsIDOMRange> range;
if (NS_SUCCEEDED(selection->GetRangeAt(inx, getter_AddRefs(range))))
selectionPS->AddRange(range);
}
}
// If we are trying to shrink the contents to fit on the page
// we must first locate the "pageContent" frame
// Then we walk the frame tree and look for the "xmost" frame
// this is the frame where the right-hand side of the frame extends
// the furthest
if (mPrt->mShrinkToFit && documentIsTopLevel) {
nsIPageSequenceFrame* pageSequence = aPO->mPresShell->GetPageSequenceFrame();
NS_ENSURE_STATE(pageSequence);
pageSequence->GetSTFPercent(aPO->mShrinkRatio);
}
rv = UpdateSelectionAndShrinkPrintObject(aPO, documentIsTopLevel);
NS_ENSURE_SUCCESS(rv, rv);
#ifdef EXTENDED_DEBUG_PRINTING
if (kPrintingLogMod && kPrintingLogMod->level == DUMP_LAYOUT_LEVEL) {
@ -3309,7 +3574,6 @@ nsPrintEngine::FinishPrintPreview()
mOldPrtPreview = nullptr;
}
InstallPrintPreviewListener();
mPrt->OnEndPrinting();
@ -3352,22 +3616,9 @@ nsPrintEngine::Observe(nsISupports *aSubject, const char *aTopic, const PRUnicha
{
nsresult rv = NS_ERROR_FAILURE;
if (mIsDoingPrinting) {
rv = DocumentReadyForPrinting();
/* cleaup on failure + notify user */
if (NS_FAILED(rv)) {
CleanupOnFailure(rv, true);
}
} else {
rv = FinishPrintPreview();
if (NS_FAILED(rv)) {
CleanupOnFailure(rv, false);
}
if (mPrtPreview) {
rv = InitPrintDocConstruction(true);
if (!mIsDoingPrinting && mPrtPreview) {
mPrtPreview->OnEndPrinting();
}
rv = NS_OK;
}
return rv;

View File

@ -13,7 +13,10 @@
#include "nsPrintData.h"
#include "nsFrameList.h"
#include "mozilla/Attributes.h"
#include "nsIWebProgress.h"
#include "nsHTMLCanvasElement.h"
#include "nsIWebProgressListener.h"
#include "nsWeakReference.h"
// Interfaces
#include "nsIDocument.h"
@ -34,7 +37,9 @@ class nsIWeakReference;
// nsPrintEngine Class
//
//------------------------------------------------------------------------
class nsPrintEngine MOZ_FINAL : public nsIObserver
class nsPrintEngine MOZ_FINAL : public nsIObserver,
public nsIWebProgressListener,
public nsSupportsWeakReference
{
public:
// nsISupports interface...
@ -43,6 +48,8 @@ public:
// nsIObserver
NS_DECL_NSIOBSERVER
NS_DECL_NSIWEBPROGRESSLISTENER
// Old nsIWebBrowserPrint methods; not cleaned up yet
NS_IMETHOD Print(nsIPrintSettings* aPrintSettings,
nsIWebProgressListener* aWebProgressListener);
@ -271,6 +278,23 @@ protected:
FILE* mDebugFile;
int32_t mLoadCounter;
bool mDidLoadDataForPrinting;
nsresult AfterNetworkPrint(bool aHandleError);
nsresult SetRootView(nsPrintObject* aPO,
bool& aDoReturn,
bool& aDocumentIsTopLevel,
nsSize& aAdjSize);
nsIView* GetParentViewForRoot();
bool DoSetPixelScale();
void UpdateZoomRatio(nsPrintObject* aPO, bool aSetPixelScale);
nsresult ReconstructAndReflow(bool aDoSetPixelScale);
nsresult UpdateSelectionAndShrinkPrintObject(nsPrintObject* aPO,
bool aDocumentIsTopLevel);
nsresult InitPrintDocConstruction(bool aHandleError);
void FirePrintPreviewUpdateEvent();
private:
nsPrintEngine& operator=(const nsPrintEngine& aOther) MOZ_DELETE;
};