Bug 1399787 - Part 15. Detect and handle breakage of the IPC channel. draft
authorcku <cku@mozilla.com>
Mon, 06 Nov 2017 22:12:31 +0800
changeset 710614 119c57ef1da3657d98331c8b052c102abbe91855
parent 710613 0063ec07d5670260bf50809f8931c8e7db9be90f
child 710615 b7475eb2f7fc47ef2d69ddc37fff23864a483479
push id92855
push usercku@mozilla.com
push dateMon, 11 Dec 2017 02:44:26 +0000
bugs1399787
milestone59.0a1
Bug 1399787 - Part 15. Detect and handle breakage of the IPC channel. MozReview-Commit-ID: 6VfIbstJ6WN
gfx/thebes/PrintTargetEMF.cpp
gfx/thebes/PrintTargetEMF.h
widget/windows/PDFiumParent.cpp
widget/windows/PDFiumParent.h
--- 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;