Bug 1399787 - Part 15. Detect and handle breakage of the IPC channel.
MozReview-Commit-ID: 6VfIbstJ6WN
--- a/gfx/thebes/PrintTargetEMF.cpp
+++ b/gfx/thebes/PrintTargetEMF.cpp
@@ -18,16 +18,17 @@ using mozilla::ipc::FileDescriptor;
namespace mozilla {
namespace gfx {
PrintTargetEMF::PrintTargetEMF(HDC aDC, const IntSize& aSize)
: PrintTarget(/* not using cairo_surface_t */ nullptr, aSize)
, mPDFiumProcess(nullptr)
, mPrinterDC(aDC)
, mWaitingForEMFConversion(false)
+ , mChannelBroken(false)
{
}
PrintTargetEMF::~PrintTargetEMF()
{
if (mPDFiumProcess) {
mPDFiumProcess->Delete(mWaitingForEMFConversion);
}
@@ -64,36 +65,39 @@ PrintTargetEMF::BeginPrinting(const nsAS
docinfo.lpszDatatype = nullptr;
docinfo.fwType = 0;
::StartDocW(mPrinterDC, &docinfo);
mPDFiumProcess = new PDFiumProcessParent();
NS_ENSURE_TRUE(mPDFiumProcess->Launch(this), NS_ERROR_FAILURE);
+ mChannelBroken = false;
+
return NS_OK;
}
nsresult
PrintTargetEMF::EndPrinting()
{
+ mPDFiumProcess->GetActor()->EndConversion();
return (::EndDoc(mPrinterDC) <= 0) ? NS_ERROR_FAILURE : NS_OK;
}
nsresult
PrintTargetEMF::AbortPrinting()
{
return (::AbortDoc(mPrinterDC) <= 0) ? NS_ERROR_FAILURE : NS_OK;
}
nsresult
PrintTargetEMF::BeginPage()
{
MOZ_ASSERT(!mPDFFileForOnePage && !mTargetForCurrentPage);
-
+ NS_ENSURE_TRUE(!mChannelBroken, NS_ERROR_FAILURE);
NS_ENSURE_TRUE(::StartPage(mPrinterDC) >0, NS_ERROR_FAILURE);
// We create a new file for each page so that we can make sure each new
// mPDFFileForOnePage contains one single page.
nsresult rv =
NS_OpenAnonymousTemporaryNsIFile(getter_AddRefs(mPDFFileForOnePage));
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
@@ -108,39 +112,46 @@ PrintTargetEMF::BeginPage()
mTargetForCurrentPage->BeginPage();
return NS_OK;
}
nsresult
PrintTargetEMF::EndPage()
{
+ NS_ENSURE_TRUE(!mChannelBroken, NS_ERROR_FAILURE);
+
mTargetForCurrentPage->EndPage();
mTargetForCurrentPage->EndPrinting();
mTargetForCurrentPage->Finish();
mTargetForCurrentPage = nullptr;
PRFileDesc* prfile;
nsresult rv = mPDFFileForOnePage->OpenNSPRFileDesc(PR_RDONLY, PR_IRWXU,
&prfile);
NS_ENSURE_SUCCESS(rv, rv);
FileDescriptor descriptor(FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(prfile)));
- mPDFiumProcess->GetActor()->SendConvertToEMF(descriptor,
+ if (!mPDFiumProcess->GetActor()->SendConvertToEMF(descriptor,
::GetDeviceCaps(mPrinterDC, HORZRES),
- ::GetDeviceCaps(mPrinterDC, VERTRES));
+ ::GetDeviceCaps(mPrinterDC, VERTRES)))
+ {
+ return NS_ERROR_FAILURE;
+ }
+
PR_Close(prfile);
mWaitingForEMFConversion = true;
return NS_OK;
}
already_AddRefed<DrawTarget>
PrintTargetEMF::MakeDrawTarget(const IntSize& aSize,
DrawEventRecorder* aRecorder)
{
+ MOZ_ASSERT(!mChannelBroken);
return mTargetForCurrentPage->MakeDrawTarget(aSize, aRecorder);
}
already_AddRefed<DrawTarget>
PrintTargetEMF::GetReferenceDrawTarget(DrawEventRecorder* aRecorder)
{
if (!mRefTarget) {
auto dummy = MakeUnique<SkNullWStream>();
@@ -154,16 +165,18 @@ PrintTargetEMF::GetReferenceDrawTarget(D
return mRefDT.forget();
}
void
PrintTargetEMF::ConvertToEMFDone(const nsresult& aResult,
mozilla::ipc::Shmem&& aEMF)
{
MOZ_ASSERT_IF(NS_FAILED(aResult), aEMF.Size<uint8_t>() == 0);
+ MOZ_ASSERT(!mChannelBroken, "It is not possible to get conversion callback "
+ "after the channel was broken.");
mWaitingForEMFConversion = false;
if (NS_SUCCEEDED(aResult)) {
if (::StartPage(mPrinterDC) > 0) {
mozilla::widget::WindowsEMF emf;
emf.InitFromFileContents(aEMF.get<BYTE>(), aEMF.Size<BYTE>());
RECT printRect = {0, 0, ::GetDeviceCaps(mPrinterDC, HORZRES),
::GetDeviceCaps(mPrinterDC, VERTRES)};
--- a/gfx/thebes/PrintTargetEMF.h
+++ b/gfx/thebes/PrintTargetEMF.h
@@ -51,26 +51,28 @@ public:
MakeDrawTarget(const IntSize& aSize,
DrawEventRecorder* aRecorder = nullptr) final;
already_AddRefed<DrawTarget>
GetReferenceDrawTarget(DrawEventRecorder* aRecorder) final;
void ConvertToEMFDone(const nsresult& aResult, mozilla::ipc::Shmem&& aEMF);
bool IsSyncPagePrinting() const final { return false; }
+ void ChannelIsBroken() { mChannelBroken = true; }
private:
PrintTargetEMF(HDC aDC, const IntSize& aSize);
~PrintTargetEMF() override;
nsString mTitle;
RefPtr<PrintTargetSkPDF> mTargetForCurrentPage;
nsCOMPtr<nsIFile> mPDFFileForOnePage;
RefPtr<PrintTargetSkPDF> mRefTarget;
PDFiumProcessParent* mPDFiumProcess;
HDC mPrinterDC;
bool mWaitingForEMFConversion;
+ bool mChannelBroken;
};
} // namespace gfx
} // namespace mozilla
#endif /* MOZILLA_GFX_PRINTTARGETEMF_H */
--- a/widget/windows/PDFiumParent.cpp
+++ b/widget/windows/PDFiumParent.cpp
@@ -24,16 +24,20 @@ PDFiumParent::Init(IPC::Channel* aChanne
AddRef();
return true;
}
void
PDFiumParent::ActorDestroy(ActorDestroyReason aWhy)
{
+ if (mTarget) {
+ mTarget->ChannelIsBroken();
+ }
+
if (mConversionDoneCallback) {
// Since this printing job was aborted, we do not need to report EMF buffer
// back to mTarget.
mConversionDoneCallback();
}
}
mozilla::ipc::IPCResult
@@ -54,16 +58,22 @@ void
PDFiumParent::AbortConversion(ConversionDoneCallback aCallback)
{
// There is no need to report EMF contents back to mTarget since the print
// job was aborted, unset mTarget.
mTarget = nullptr;
mConversionDoneCallback = aCallback;
}
+void PDFiumParent::EndConversion()
+{
+ // The printing job is finished correctly, mTarget is no longer needed.
+ mTarget = nullptr;
+}
+
void
PDFiumParent::OnChannelConnected(int32_t pid)
{
SetOtherProcessId(pid);
}
void
PDFiumParent::DeallocPPDFiumParent()
--- a/widget/windows/PDFiumParent.h
+++ b/widget/windows/PDFiumParent.h
@@ -25,16 +25,17 @@ class PDFiumParent final : public PPDFiu
typedef mozilla::gfx::PrintTargetEMF PrintTargetEMF;
typedef std::function<void()> ConversionDoneCallback;
explicit PDFiumParent(PrintTargetEMF* aTarget);
bool Init(IPC::Channel* aChannel, base::ProcessId aPid);
void AbortConversion(ConversionDoneCallback aCallback);
+ void EndConversion();
FORWARD_SHMEM_ALLOCATOR_TO(PPDFiumParent)
private:
~PDFiumParent() {}
// PPDFiumParent functions.
void ActorDestroy(ActorDestroyReason aWhy) override;