Bug 1399787 - Part 2.a. Add functions to load the content of a PDF from a FileDescriptor. r=jwatt
authorcku <cku@mozilla.com>
Wed, 01 Nov 2017 21:33:28 +0800
changeset 396003 f0df14d5edab03bf2f00b0ffe401713f85f5f100
parent 396002 b6b78f4aa40fc67b891fef7c6fb995e3e380379f
child 396004 6354e568837e2c879492446c864da0388cd15e18
push id33067
push usertoros@mozilla.com
push dateMon, 11 Dec 2017 09:54:39 +0000
treeherdermozilla-central@6d926a50dcf5 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjwatt
bugs1399787
milestone59.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1399787 - Part 2.a. Add functions to load the content of a PDF from a FileDescriptor. r=jwatt All the functions added in Part 2 are utilities for sharing EMF/PDF contents between processes. MozReview-Commit-ID: 3qKosXH56kY
modules/pdfium/pdfium.def
widget/windows/PDFViaEMFPrintHelper.cpp
widget/windows/PDFViaEMFPrintHelper.h
widget/windows/PDFiumEngineShim.cpp
widget/windows/PDFiumEngineShim.h
widget/windows/gtest/moz.build
--- a/modules/pdfium/pdfium.def
+++ b/modules/pdfium/pdfium.def
@@ -2,13 +2,14 @@
 ; License, v. 2.0. If a copy of the MPL was not distributed with this
 ; file, You can obtain one at http://mozilla.org/MPL/2.0/.
 
 LIBRARY pdfium
 EXPORTS
     FPDF_InitLibrary
     FPDF_DestroyLibrary
     FPDF_LoadDocument
+    FPDF_LoadCustomDocument
     FPDF_CloseDocument
     FPDF_GetPageCount
     FPDF_LoadPage
     FPDF_ClosePage
     FPDF_RenderPage
--- a/widget/windows/PDFViaEMFPrintHelper.cpp
+++ b/widget/windows/PDFViaEMFPrintHelper.cpp
@@ -20,16 +20,17 @@ float ComputeScaleFactor(int aDCWidth, i
 
   return (aDCWidth >= aPageWidth && aDCHeight >= aPageHeight)
     ? 1.0 /* If page fits DC - no scaling needed. */
     : std::min(static_cast<float>(aDCWidth) / static_cast<float>(aPageWidth),         static_cast<float>(aDCHeight) / static_cast<float>(aPageHeight));
 }
 
 PDFViaEMFPrintHelper::PDFViaEMFPrintHelper()
   : mPDFDoc(nullptr)
+  , mPrfile(nullptr)
 {
 }
 
 PDFViaEMFPrintHelper::~PDFViaEMFPrintHelper()
 {
   CloseDocument();
 }
 
@@ -70,16 +71,48 @@ PDFViaEMFPrintHelper::OpenDocument(const
   NS_ENSURE_TRUE(CreatePDFiumEngineIfNeed(), NS_ERROR_FAILURE);
 
   mPDFDoc = mPDFiumEngine->LoadDocument(aFileName, nullptr);
   NS_ENSURE_TRUE(mPDFDoc, NS_ERROR_FAILURE);
 
   return NS_OK;
 }
 
+nsresult
+PDFViaEMFPrintHelper::OpenDocument(const FileDescriptor& aFD)
+{
+  MOZ_ASSERT(!mPrfile, "Forget to call CloseDocument?");
+
+  if (mPDFDoc) {
+    MOZ_ASSERT_UNREACHABLE("We can only open one PDF at a time, "
+                           "Use CloseDocument() to close the opened file "
+                           "before calling OpenDocument()");
+    return NS_ERROR_FAILURE;
+  }
+
+  NS_ENSURE_TRUE(CreatePDFiumEngineIfNeed(), NS_ERROR_FAILURE);
+
+  auto rawFD = aFD.ClonePlatformHandle();
+  PRFileDesc* prfile = PR_ImportFile(PROsfd(rawFD.release()));
+  NS_ENSURE_TRUE(prfile, NS_ERROR_FAILURE);
+
+  mPDFDoc = mPDFiumEngine->LoadDocument(prfile, nullptr);
+  if (!mPDFDoc) {
+    PR_Close(prfile);
+    return NS_ERROR_FAILURE;
+  }
+
+  // mPDFiumEngine keeps using this handle until we close mPDFDoc. Instead of
+  // closing this HANDLE here, we close it in
+  // PDFViaEMFPrintHelper::CloseDocument.
+  mPrfile = prfile;
+
+  return NS_OK;
+}
+
 bool
 PDFViaEMFPrintHelper::RenderPageToDC(HDC aDC, unsigned int aPageIndex,
                                      int aPageWidth, int aPageHeight)
 {
   MOZ_ASSERT(aDC && mPDFDoc);
   MOZ_ASSERT(static_cast<int>(aPageIndex) <
              mPDFiumEngine->GetPageCount(mPDFDoc));
 
@@ -171,16 +204,21 @@ PDFViaEMFPrintHelper::DrawPageToFile(con
 
 void
 PDFViaEMFPrintHelper::CloseDocument()
 {
   if (mPDFDoc) {
     mPDFiumEngine->CloseDocument(mPDFDoc);
     mPDFDoc = nullptr;
   }
+
+  if (mPrfile) {
+    PR_Close(mPrfile);
+    mPrfile = nullptr;
+  }
 }
 
 bool
 PDFViaEMFPrintHelper::CreatePDFiumEngineIfNeed()
 {
   if (!mPDFiumEngine) {
     mPDFiumEngine = PDFiumEngineShim::GetInstanceOrNull();
   }
--- a/widget/windows/PDFViaEMFPrintHelper.h
+++ b/widget/windows/PDFViaEMFPrintHelper.h
@@ -4,16 +4,17 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef PDFVIAEMFPRINTHELPER_H_
 #define PDFVIAEMFPRINTHELPER_H_
 
 #include "nsCOMPtr.h"
 #include "PDFiumEngineShim.h"
 #include "mozilla/Vector.h"
+#include "mozilla/ipc/FileDescriptor.h"
 
 /* include windows.h for the HDC definitions that we need. */
 #include <windows.h>
 
 class nsIFile;
 class nsFileInputStream;
 
 namespace mozilla {
@@ -23,22 +24,25 @@ namespace widget {
  * This class helps draw a PDF file to a given Windows DC.
  * To do that it first converts the PDF file to EMF.
  * Windows EMF:
  * https://msdn.microsoft.com/en-us/windows/hardware/drivers/print/emf-data-type
  */
 class PDFViaEMFPrintHelper
 {
 public:
+  typedef mozilla::ipc::FileDescriptor FileDescriptor;
+
   PDFViaEMFPrintHelper();
   virtual ~PDFViaEMFPrintHelper();
 
   /** Loads the specified PDF file. */
   NS_IMETHOD OpenDocument(nsIFile *aFile);
   NS_IMETHOD OpenDocument(const char* aFileName);
+  NS_IMETHOD OpenDocument(const FileDescriptor& aFD);
 
   /** Releases document buffer. */
   void CloseDocument();
 
   int GetPageCount() const { return mPDFiumEngine->GetPageCount(mPDFDoc); }
 
   /** Convert specified PDF page to EMF and draw the EMF onto the given DC. */
   bool DrawPage(HDC aPrinterDC, unsigned int aPageIndex,
@@ -50,14 +54,15 @@ public:
 
 protected:
   virtual bool CreatePDFiumEngineIfNeed();
   bool RenderPageToDC(HDC aDC, unsigned int aPageIndex,
                       int aPageWidth, int aPageHeight);
 
   RefPtr<PDFiumEngineShim>    mPDFiumEngine;
   FPDF_DOCUMENT               mPDFDoc;
+  PRFileDesc*                 mPrfile;
 };
 
 } // namespace widget
 } // namespace mozilla
 
 #endif /* PDFVIAEMFPRINTHELPER_H_ */
--- a/widget/windows/PDFiumEngineShim.cpp
+++ b/widget/windows/PDFiumEngineShim.cpp
@@ -1,15 +1,15 @@
 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  * This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "PDFiumEngineShim.h"
-
+#include "private/pprio.h"
 
 namespace mozilla {
 namespace widget {
 
 static PDFiumEngineShim* sPDFiumEngineShim;
 
 /* static */
 already_AddRefed<PDFiumEngineShim>
@@ -82,16 +82,20 @@ PDFiumEngineShim::Init(const nsCString& 
   mFPDF_DestroyLibrary = (FPDF_DestroyLibrary_Pfn)PR_FindFunctionSymbol(
     mPRLibrary, "FPDF_DestroyLibrary");
   NS_ENSURE_TRUE(mFPDF_DestroyLibrary, false);
 
   mFPDF_LoadDocument = (FPDF_LoadDocument_Pfn)PR_FindFunctionSymbol(
     mPRLibrary, "FPDF_LoadDocument");
   NS_ENSURE_TRUE(mFPDF_LoadDocument, false);
 
+  mFPDF_LoadCustomDocument = (FPDF_LoadCustomDocument_Pfn)PR_FindFunctionSymbol(
+    mPRLibrary, "FPDF_LoadCustomDocument");
+  NS_ENSURE_TRUE(mFPDF_LoadCustomDocument, false);
+
   mFPDF_CloseDocument = (FPDF_CloseDocument_Pfn)PR_FindFunctionSymbol(
     mPRLibrary, "FPDF_CloseDocument");
   NS_ENSURE_TRUE(mFPDF_CloseDocument, false);
 
   mFPDF_GetPageCount = (FPDF_GetPageCount_Pfn)PR_FindFunctionSymbol(
     mPRLibrary, "FPDF_GetPageCount");
   NS_ENSURE_TRUE(mFPDF_GetPageCount, false);
 
@@ -115,16 +119,50 @@ PDFiumEngineShim::Init(const nsCString& 
 FPDF_DOCUMENT
 PDFiumEngineShim::LoadDocument(FPDF_STRING file_path,
                                FPDF_BYTESTRING aPassword)
 {
   MOZ_ASSERT(mInitialized);
   return mFPDF_LoadDocument(file_path, aPassword);
 }
 
+FPDF_DOCUMENT
+PDFiumEngineShim::LoadDocument(PRFileDesc* aPrfile,
+                               FPDF_BYTESTRING aPassword)
+{
+  MOZ_ASSERT(mInitialized && aPrfile);
+
+  PROffset32 fileLength = PR_Seek64(aPrfile, 0, PR_SEEK_END);
+  if (fileLength == -1) {
+    NS_WARNING("Failed to access the given FD.");
+    return nullptr;
+  }
+
+  FPDF_FILEACCESS fileAccess;
+  fileAccess.m_FileLen = static_cast<unsigned long>(fileLength);
+  fileAccess.m_Param = reinterpret_cast<void*>(aPrfile);
+  fileAccess.m_GetBlock =
+    [](void* param, unsigned long pos, unsigned char* buf, unsigned long size)
+    {
+      PRFileDesc* prfile = reinterpret_cast<PRFileDesc*>(param);
+
+      if (PR_Seek64(prfile, pos, PR_SEEK_SET) != pos) {
+        return 0;
+      }
+
+      if (PR_Read(prfile, buf, size) <= 0) {
+        return 0;
+      }
+
+      return 1;
+    };
+
+  return mFPDF_LoadCustomDocument(&fileAccess, aPassword);
+}
+
 void
 PDFiumEngineShim::CloseDocument(FPDF_DOCUMENT aDocument)
 {
   MOZ_ASSERT(mInitialized);
   mFPDF_CloseDocument(aDocument);
 }
 
 int
--- a/widget/windows/PDFiumEngineShim.h
+++ b/widget/windows/PDFiumEngineShim.h
@@ -6,26 +6,28 @@
 #ifndef PDFIUMENGINESHIM_H
 #define PDFIUMENGINESHIM_H
 
 #include "prlink.h"
 #include "fpdfview.h"
 
 /* include windows.h for the HDC definitions that we need. */
 #include <windows.h>
+#include "private/pprio.h"
 
 namespace mozilla {
 namespace widget {
 
 typedef void (STDCALL *FPDF_InitLibrary_Pfn)();
 typedef void (STDCALL *FPDF_DestroyLibrary_Pfn)();
 
 typedef FPDF_DOCUMENT (STDCALL *FPDF_LoadDocument_Pfn)(FPDF_STRING file_path,
                                                       FPDF_BYTESTRING password);
-
+typedef FPDF_DOCUMENT (STDCALL *FPDF_LoadCustomDocument_Pfn)(FPDF_FILEACCESS* pFileAccess,
+                                                             FPDF_BYTESTRING password);
 typedef void(STDCALL *FPDF_CloseDocument_Pfn)(FPDF_DOCUMENT aDocument);
 
 typedef int (STDCALL *FPDF_GetPageCount_Pfn)(FPDF_DOCUMENT aDocument);
 
 typedef FPDF_PAGE (STDCALL *FPDF_LoadPage_Pfn)(FPDF_DOCUMENT aDocument,
                                                int aPageIndex);
 typedef void (STDCALL *FPDF_ClosePage_Pfn)(FPDF_PAGE aPage);
 typedef void (STDCALL *FPDF_RenderPage_Pfn)(HDC aDC,
@@ -50,16 +52,18 @@ public:
   static already_AddRefed<PDFiumEngineShim> GetInstanceOrNull();
   // This function is used for testing purpose only, do not call it in regular
   // code.
   static already_AddRefed<PDFiumEngineShim>
   GetInstanceOrNull(const nsCString& aLibrary);
 
   FPDF_DOCUMENT LoadDocument(FPDF_STRING file_path,
                              FPDF_BYTESTRING aPassword);
+  FPDF_DOCUMENT LoadDocument(PRFileDesc* aPrfile,
+                             FPDF_BYTESTRING aPassword);
   void CloseDocument(FPDF_DOCUMENT aDocument);
   int GetPageCount(FPDF_DOCUMENT aDocument);
   int GetPageSizeByIndex(FPDF_DOCUMENT aDocument, int aPageIndex,
                          double* aWidth, double* aHeight);
 
   FPDF_PAGE LoadPage(FPDF_DOCUMENT aDocument, int aPageIndex);
   void ClosePage(FPDF_PAGE aPage);
   void RenderPage(HDC aDC, FPDF_PAGE aPage,
@@ -72,16 +76,17 @@ private:
   ~PDFiumEngineShim();
   bool Init(const nsCString& aLibrary);
 
   bool        mInitialized ;
 
   FPDF_InitLibrary_Pfn        mFPDF_InitLibrary;
   FPDF_DestroyLibrary_Pfn     mFPDF_DestroyLibrary;
   FPDF_LoadDocument_Pfn       mFPDF_LoadDocument;
+  FPDF_LoadCustomDocument_Pfn mFPDF_LoadCustomDocument;
   FPDF_CloseDocument_Pfn      mFPDF_CloseDocument;
   FPDF_GetPageCount_Pfn       mFPDF_GetPageCount;
   FPDF_LoadPage_Pfn           mFPDF_LoadPage;
   FPDF_ClosePage_Pfn          mFPDF_ClosePage;
   FPDF_RenderPage_Pfn         mFPDF_RenderPage;
 
   PRLibrary*  mPRLibrary;
 };
--- a/widget/windows/gtest/moz.build
+++ b/widget/windows/gtest/moz.build
@@ -4,16 +4,17 @@
 # License, v. 2.0. If a copy of the MPL was not distributed with this
 # file, you can obtain one at http://mozilla.org/MPL/2.0/.
 
 UNIFIED_SOURCES = [
     'TestEMFConversion.cpp',
 ]
 
 LOCAL_INCLUDES += [
+    '/ipc/chromium/src',
     '/modules/pdfium/pdfium/public',
     '/widget/windows',
 ]
 
 TEST_HARNESS_FILES.gtest += [
     'pdfium_ref_x64.dll',
     'pdfium_ref_x86.dll',
     'PrinterTestPage.pdf',