Bug 1399787 - Part 13. Handle AbortDocument. draft
authorcku <cku@mozilla.com>
Sun, 05 Nov 2017 15:34:54 +0800
changeset 710612 77613816563a39f6a3f9b1ba6e4ee41d0d90172d
parent 710611 85e65df8ddb48b66b9dff482c34aebdf4c51ea25
child 710613 0063ec07d5670260bf50809f8931c8e7db9be90f
push id92855
push usercku@mozilla.com
push dateMon, 11 Dec 2017 02:44:26 +0000
bugs1399787
milestone59.0a1
Bug 1399787 - Part 13. Handle AbortDocument. While aborting conversion, we need to make sure there is no coversion task executing in the PDFium process before destroying it. MozReview-Commit-ID: 3Iqhe8KmYv2
gfx/thebes/PrintTargetEMF.cpp
gfx/thebes/PrintTargetEMF.h
widget/windows/PDFiumParent.cpp
widget/windows/PDFiumParent.h
widget/windows/PDFiumProcessParent.cpp
widget/windows/PDFiumProcessParent.h
--- a/gfx/thebes/PrintTargetEMF.cpp
+++ b/gfx/thebes/PrintTargetEMF.cpp
@@ -17,23 +17,24 @@ 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)
 {
 }
 
 PrintTargetEMF::~PrintTargetEMF()
 {
   if (mPDFiumProcess) {
-    mPDFiumProcess->Delete();
+    mPDFiumProcess->Delete(mWaitingForEMFConversion);
   }
 }
 
 /* static */ already_AddRefed<PrintTargetEMF>
 PrintTargetEMF::CreateOrNull(HDC aDC, const IntSize& aSizeInPoints)
 {
   return do_AddRef(new PrintTargetEMF(aDC, aSizeInPoints));
 }
@@ -121,16 +122,17 @@ PrintTargetEMF::EndPage()
   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,
                                         ::GetDeviceCaps(mPrinterDC, HORZRES),
                                         ::GetDeviceCaps(mPrinterDC, VERTRES));
   PR_Close(prfile);
+  mWaitingForEMFConversion = true;
 
   return NS_OK;
 }
 
 already_AddRefed<DrawTarget>
 PrintTargetEMF::MakeDrawTarget(const IntSize& aSize,
                                DrawEventRecorder* aRecorder)
 {
@@ -153,16 +155,17 @@ PrintTargetEMF::GetReferenceDrawTarget(D
 }
 
 void
 PrintTargetEMF::ConvertToEMFDone(const nsresult& aResult,
                                  mozilla::ipc::Shmem&& aEMF)
 {
   MOZ_ASSERT_IF(NS_FAILED(aResult), aEMF.Size<uint8_t>() == 0);
 
+  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)};
       DebugOnly<bool> ret = emf.Playback(mPrinterDC, printRect);
       MOZ_ASSERT(ret);
--- a/gfx/thebes/PrintTargetEMF.h
+++ b/gfx/thebes/PrintTargetEMF.h
@@ -62,14 +62,15 @@ private:
   ~PrintTargetEMF() override;
 
   nsString mTitle;
   RefPtr<PrintTargetSkPDF> mTargetForCurrentPage;
   nsCOMPtr<nsIFile>        mPDFFileForOnePage;
   RefPtr<PrintTargetSkPDF> mRefTarget;
   PDFiumProcessParent*     mPDFiumProcess;
   HDC mPrinterDC;
+  bool mWaitingForEMFConversion;
 };
 
 } // namespace gfx
 } // namespace mozilla
 
 #endif /* MOZILLA_GFX_PRINTTARGETEMF_H */
--- a/widget/windows/PDFiumParent.cpp
+++ b/widget/windows/PDFiumParent.cpp
@@ -24,29 +24,47 @@ PDFiumParent::Init(IPC::Channel* aChanne
 
   AddRef();
   return true;
 }
 
 void
 PDFiumParent::ActorDestroy(ActorDestroyReason aWhy)
 {
+  if (mConversionDoneCallback) {
+    // Since this printing job was aborted, we do not need to report EMF buffer
+    // back to mTarget.
+    mConversionDoneCallback();
+  }
 }
 
 mozilla::ipc::IPCResult
 PDFiumParent::RecvConvertToEMFDone(const nsresult& aResult,
                                    mozilla::ipc::Shmem&& aEMFContents)
 {
   MOZ_ASSERT(aEMFContents.IsReadable());
-  mTarget->ConvertToEMFDone(aResult, Move(aEMFContents));
+
+  if (mTarget) {
+    MOZ_ASSERT(!mConversionDoneCallback);
+    mTarget->ConvertToEMFDone(aResult, Move(aEMFContents));
+  }
 
   return IPC_OK();
 }
 
 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::OnChannelConnected(int32_t pid)
 {
   SetOtherProcessId(pid);
 }
 
 void
 PDFiumParent::DeallocPPDFiumParent()
 {
--- a/widget/windows/PDFiumParent.h
+++ b/widget/windows/PDFiumParent.h
@@ -18,32 +18,36 @@ namespace mozilla {
 namespace widget {
 
 class PDFiumParent final : public PPDFiumParent,
                            public mozilla::ipc::IShmemAllocator
 {
   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(PDFiumParent)
 
   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);
+
   FORWARD_SHMEM_ALLOCATOR_TO(PPDFiumParent)
 private:
   ~PDFiumParent() {}
 
   // PPDFiumParent functions.
   void ActorDestroy(ActorDestroyReason aWhy) override;
 
   mozilla::ipc::IPCResult RecvConvertToEMFDone(const nsresult& aResult,
                                                mozilla::ipc::Shmem&& aEMFContents) override;
   void OnChannelConnected(int32_t pid) override;
   void DeallocPPDFiumParent() override;
 
   PrintTargetEMF* mTarget;
+  ConversionDoneCallback mConversionDoneCallback;
 };
 
 } // namespace widget
 } // namespace mozilla
 
 #endif // PDFIUMPARENT_H_
--- a/widget/windows/PDFiumProcessParent.cpp
+++ b/widget/windows/PDFiumProcessParent.cpp
@@ -44,30 +44,39 @@ PDFiumProcessParent::Launch(PrintTargetE
   // Open the top level protocol for PDFium process.
   MOZ_ASSERT(!mPDFiumParentActor);
   mPDFiumParentActor = new PDFiumParent(aTarget);
   return mPDFiumParentActor->Init(GetChannel(),
                             base::GetProcId(GetChildProcessHandle()));
 }
 
 void
-PDFiumProcessParent::Delete()
+PDFiumProcessParent::Delete(bool aWaitingForEMFConversion)
 {
+  if (aWaitingForEMFConversion) {
+    // Can not kill the PDFium process yet since we are still waiting for a
+    // EMF conversion response.
+    mPDFiumParentActor->AbortConversion([this]() { Delete(false); });
+    mPDFiumParentActor->Close();
+    return;
+  }
+
   // PDFiumProcessParent::Launch is not called, protocol is not created.
   // It is safe to destroy this object on any thread.
   if (!mLaunchThread) {
     delete this;
     return;
   }
 
   if (mLaunchThread == NS_GetCurrentThread()) {
     delete this;
     return;
   }
 
   mLaunchThread->Dispatch(
-    NewNonOwningRunnableMethod("PDFiumProcessParent::Delete",
-                               this,
-                               &PDFiumProcessParent::Delete));
+    NewNonOwningRunnableMethod<bool>("PDFiumProcessParent::Delete",
+                                     this,
+                                     &PDFiumProcessParent::Delete,
+                                     false));
 }
 
 } // namespace widget
 } // namespace mozilla
--- a/widget/windows/PDFiumProcessParent.h
+++ b/widget/windows/PDFiumProcessParent.h
@@ -32,17 +32,17 @@ class PDFiumProcessParent final : public
 public:
   typedef mozilla::gfx::PrintTargetEMF PrintTargetEMF;
 
   PDFiumProcessParent();
   ~PDFiumProcessParent();
 
   bool Launch(PrintTargetEMF* aTarget);
 
-  void Delete();
+  void Delete(bool aWaitingForEMFConversion);
 
   bool CanShutdown() override { return true; }
 
   PDFiumParent* GetActor() const { return mPDFiumParentActor; }
 private:
 
   DISALLOW_COPY_AND_ASSIGN(PDFiumProcessParent);