Bug 1399787 - Part 11.a. Use PrintTargetEMF to print content documents. r=jwatt

Before we introduce PrintTargetEMF, all PrintTargets finish page printing task
before the end of PrintTarget::EndPage(). Unlike others, a page printing
in PrintTargetEMF is done after receiving an async callback from the pdfium
process. So we have both async and sync page printing behavior now. This patch
is trying to make both of them work correctly while priting a content document.

MozReview-Commit-ID: 2PHJToFlvtu

--HG--
extra : rebase_source : 9d2d7cf7330a157a0e5c6a414c75de94ca3fb5a1
extra : source : f61eb00f83acf45511d8448922212dccb12b05aa
This commit is contained in:
cku 2017-11-05 04:36:37 +08:00
Родитель 6f25ba1878
Коммит 3654a24e84
8 изменённых файлов: 95 добавлений и 19 удалений

Просмотреть файл

@ -735,3 +735,24 @@ nsDeviceContext::GetDesktopToDeviceScale()
return DesktopToLayoutDeviceScale(1.0);
}
bool
nsDeviceContext::IsSyncPagePrinting() const
{
MOZ_ASSERT(mPrintTarget);
return mPrintTarget->IsSyncPagePrinting();
}
void
nsDeviceContext::RegisterPageDoneCallback(PrintTarget::PageDoneCallback&& aCallback)
{
MOZ_ASSERT(mPrintTarget && aCallback && !IsSyncPagePrinting());
mPrintTarget->RegisterPageDoneCallback(Move(aCallback));
}
void
nsDeviceContext::UnregisterPageDoneCallback()
{
if (mPrintTarget) {
mPrintTarget->UnregisterPageDoneCallback();
}
}

Просмотреть файл

@ -20,6 +20,7 @@
#include "nscore.h" // for char16_t, nsAString
#include "mozilla/AppUnits.h" // for AppUnits
#include "nsFontMetrics.h" // for nsFontMetrics::Params
#include "mozilla/gfx/PrintTarget.h" // for PrintTarget::PageDoneCallback
class gfxContext;
class gfxTextPerfMetrics;
@ -33,12 +34,6 @@ class nsIScreenManager;
class nsIWidget;
struct nsRect;
namespace mozilla {
namespace gfx {
class PrintTarget;
}
}
class nsDeviceContext final
{
public:
@ -280,6 +275,9 @@ public:
mozilla::DesktopToLayoutDeviceScale GetDesktopToDeviceScale();
bool IsSyncPagePrinting() const;
void RegisterPageDoneCallback(PrintTarget::PageDoneCallback&& aCallback);
void UnregisterPageDoneCallback();
private:
// Private destructor, to discourage deletion outside of Release():
~nsDeviceContext();

Просмотреть файл

@ -229,5 +229,18 @@ PrintTarget::Finish()
cairo_surface_finish(mCairoSurface);
}
void
PrintTarget::RegisterPageDoneCallback(PageDoneCallback&& aCallback)
{
MOZ_ASSERT(aCallback && !IsSyncPagePrinting());
mPageDoneCallback = Move(aCallback);
}
void
PrintTarget::UnregisterPageDoneCallback()
{
mPageDoneCallback = nullptr;
}
} // namespace gfx
} // namespace mozilla

Просмотреть файл

@ -6,6 +6,8 @@
#ifndef MOZILLA_GFX_PRINTTARGET_H
#define MOZILLA_GFX_PRINTTARGET_H
#include <functional>
#include "mozilla/RefPtr.h"
#include "mozilla/gfx/2D.h"
#include "nsISupportsImpl.h"
@ -26,6 +28,7 @@ class DrawEventRecorder;
*/
class PrintTarget {
public:
typedef std::function<void(nsresult)> PageDoneCallback;
NS_INLINE_DECL_REFCOUNTING(PrintTarget);
@ -136,6 +139,17 @@ public:
*/
virtual already_AddRefed<DrawTarget> GetReferenceDrawTarget(DrawEventRecorder* aRecorder);
/**
* If IsSyncPagePrinting returns true, then a user can assume the content of
* a page was already printed after EndPage().
* If IsSyncPagePrinting returns false, then a user should register a
* callback function using RegisterPageDoneCallback to receive page print
* done notifications.
*/
virtual bool IsSyncPagePrinting() const { return true; }
void RegisterPageDoneCallback(PageDoneCallback&& aCallback);
void UnregisterPageDoneCallback();
static void AdjustPrintJobNameForIPP(const nsAString& aJobName,
nsCString& aAdjustedJobName);
static void AdjustPrintJobNameForIPP(const nsAString& aJobName,
@ -169,6 +183,8 @@ protected:
// owned by mRecordingRefDT, so kept alive for our entire lifetime if set:
DrawEventRecorder* mRecorder;
#endif
PageDoneCallback mPageDoneCallback;
};
} // namespace gfx

Просмотреть файл

@ -176,7 +176,9 @@ PrintTargetEMF::ConvertToEMFDone(const nsresult& aResult,
mPDFFileForOnePage->Remove(/* aRecursive */ false);
mPDFFileForOnePage = nullptr;
// TBD: We should call RemotePrintJobChild::SendPageProcessed here.
if (mPageDoneCallback) {
mPageDoneCallback(aResult);
}
}
} // namespace gfx

Просмотреть файл

@ -55,6 +55,7 @@ public:
GetReferenceDrawTarget(DrawEventRecorder* aRecorder) final;
void ConvertToEMFDone(const nsresult& aResult, mozilla::ipc::Shmem&& aEMF);
bool IsSyncPagePrinting() const final { return false; }
private:
PrintTargetEMF(HDC aDC, const IntSize& aSize);

Просмотреть файл

@ -88,6 +88,10 @@ RemotePrintJobParent::InitializePrintDevice(const nsString& aDocumentTitle,
return rv;
}
if (!mPrintDeviceContext->IsSyncPagePrinting()) {
mPrintDeviceContext->RegisterPageDoneCallback([this](nsresult aResult) { PageDone(aResult); });
}
return NS_OK;
}
@ -116,19 +120,10 @@ RemotePrintJobParent::RecvProcessPage()
nsresult rv = PrintPage(mCurrentPageStream);
mCurrentPageStream.Close();
if (NS_FAILED(rv)) {
Unused << SendAbortPrint(rv);
return IPC_OK();
if (mPrintDeviceContext->IsSyncPagePrinting()) {
PageDone(rv);
}
FileDescriptor fd;
rv = PrepareNextPageFD(&fd);
if (NS_FAILED(rv)) {
Unused << SendAbortPrint(rv);
return IPC_OK();
}
Unused << SendPageProcessed(fd);
return IPC_OK();
}
@ -153,6 +148,22 @@ RemotePrintJobParent::PrintPage(PRFileDescStream& aRecording)
return NS_OK;
}
void
RemotePrintJobParent::PageDone(nsresult aResult)
{
if (NS_FAILED(aResult)) {
Unused << SendAbortPrint(aResult);
} else {
FileDescriptor fd;
aResult = PrepareNextPageFD(&fd);
if (NS_FAILED(aResult)) {
Unused << SendAbortPrint(aResult);
}
Unused << SendPageProcessed(fd);
}
}
mozilla::ipc::IPCResult
RemotePrintJobParent::RecvFinalizePrint()
{
@ -163,8 +174,12 @@ RemotePrintJobParent::RecvFinalizePrint()
// Too late to abort the child just log.
NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "EndDocument failed");
}
// Since RecvFinalizePrint is called after all page printed, there should
// be no more page-done callbacks after that, in theory. Unregistering
// page-done callback is not must have, but we still do this for safety.
mPrintDeviceContext->UnregisterPageDoneCallback();
}
Unused << Send__delete__(this);
return IPC_OK();
@ -175,6 +190,7 @@ RemotePrintJobParent::RecvAbortPrint(const nsresult& aRv)
{
if (mPrintDeviceContext) {
Unused << mPrintDeviceContext->AbortDocument();
mPrintDeviceContext->UnregisterPageDoneCallback();
}
Unused << Send__delete__(this);
@ -246,6 +262,9 @@ RemotePrintJobParent::~RemotePrintJobParent()
void
RemotePrintJobParent::ActorDestroy(ActorDestroyReason aWhy)
{
if (mPrintDeviceContext) {
mPrintDeviceContext->UnregisterPageDoneCallback();
}
}
} // namespace layout

Просмотреть файл

@ -76,6 +76,12 @@ private:
nsresult PrintPage(PRFileDescStream& aRecording);
/**
* Called to notify our corresponding RemotePrintJobChild once we've
* finished printing a page.
*/
void PageDone(nsresult aResult);
nsCOMPtr<nsIPrintSettings> mPrintSettings;
RefPtr<nsDeviceContext> mPrintDeviceContext;
UniquePtr<PrintTranslator> mPrintTranslator;