Bug 1399787 - Part 6. Implement the bulk of a new PrintTargetEMF. draft
authorcku <cku@mozilla.com>
Sun, 05 Nov 2017 02:05:25 +0800
changeset 710602 353fb3919b056e20ffc75f05ef9f5073fc65fa4a
parent 710601 f57b0d7977317c8338cdd874deb6539cec433f0e
child 710603 b27ad0e0ab569b7a6e68f4e783f14d53833a0b82
push id92855
push usercku@mozilla.com
push dateMon, 11 Dec 2017 02:44:26 +0000
bugs1399787
milestone59.0a1
Bug 1399787 - Part 6. Implement the bulk of a new PrintTargetEMF. A new subclass of PrintTarget. 1. It uses PrintTargetSkPDF to generate one PDF FileDescriptor for one page. 2. In a later patch, it then passes that FD to PDFium process for converting a PDF page to EMF contents. Implementation of integration with PDFium actor is added the subsequent patches. MozReview-Commit-ID: EcuBJHRW8Wk
gfx/thebes/PrintTargetEMF.cpp
gfx/thebes/PrintTargetEMF.h
gfx/thebes/moz.build
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/PrintTargetEMF.cpp
@@ -0,0 +1,137 @@
+/* -*- 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 "PrintTargetEMF.h"
+#include "nsAnonymousTemporaryFile.h"
+#include "nsIFile.h"
+
+using mozilla::gfx::DrawTarget;
+
+namespace mozilla {
+namespace gfx {
+
+PrintTargetEMF::PrintTargetEMF(HDC aDC, const IntSize& aSize)
+  : PrintTarget(/* not using cairo_surface_t */ nullptr, aSize)
+  , mPrinterDC(aDC)
+{
+}
+
+/* static */ already_AddRefed<PrintTargetEMF>
+PrintTargetEMF::CreateOrNull(HDC aDC, const IntSize& aSizeInPoints)
+{
+  return do_AddRef(new PrintTargetEMF(aDC, aSizeInPoints));
+}
+
+nsresult
+PrintTargetEMF::BeginPrinting(const nsAString& aTitle,
+                              const nsAString& aPrintToFileName,
+                              int32_t aStartPage,
+                              int32_t aEndPage)
+{
+  mTitle = aTitle;
+
+  const uint32_t DOC_TITLE_LENGTH = MAX_PATH - 1;
+
+  DOCINFOW docinfo;
+
+  nsString titleStr(aTitle);
+  if (titleStr.Length() > DOC_TITLE_LENGTH) {
+    titleStr.SetLength(DOC_TITLE_LENGTH - 3);
+    titleStr.AppendLiteral("...");
+  }
+
+  nsString docName(aPrintToFileName);
+  docinfo.cbSize = sizeof(docinfo);
+  docinfo.lpszDocName = titleStr.Length() > 0 ? titleStr.get() : L"Mozilla Document";
+  docinfo.lpszOutput = docName.Length() > 0 ? docName.get() : nullptr;
+  docinfo.lpszDatatype = nullptr;
+  docinfo.fwType = 0;
+
+  ::StartDocW(mPrinterDC, &docinfo);
+
+  return NS_OK;
+}
+
+nsresult
+PrintTargetEMF::EndPrinting()
+{
+  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(::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);
+
+  nsAutoCString filePath;
+  mPDFFileForOnePage->GetNativePath(filePath);
+  auto  stream = MakeUnique<SkFILEWStream>(filePath.get());
+
+  // Creating a new PrintTargetSkPDF for each page so that we can convert each
+  // of them into EMF contents individually by the PDFium processes.
+  mTargetForCurrentPage = PrintTargetSkPDF::CreateOrNull(Move(stream), mSize);
+  mTargetForCurrentPage->BeginPrinting(mTitle, NS_LITERAL_STRING(""), 0, 0);
+  mTargetForCurrentPage->BeginPage();
+
+  return NS_OK;
+}
+
+nsresult
+PrintTargetEMF::EndPage()
+{
+  mTargetForCurrentPage->EndPage();
+  mTargetForCurrentPage->EndPrinting();
+  mTargetForCurrentPage->Finish();
+  mTargetForCurrentPage = nullptr;
+
+  // TODO: pass mPDFFileForOnePage to the PDFium process.
+
+  mPDFFileForOnePage->Remove(/* aRecursive */ false);
+  mPDFFileForOnePage = nullptr;
+
+  // TODO: we should call EndPage(mPrinterDC), but not here. We should call it
+  // after the PDFium process calls Send ConvertToEMFDone.
+
+  return NS_OK;
+}
+
+already_AddRefed<DrawTarget>
+PrintTargetEMF::MakeDrawTarget(const IntSize& aSize,
+                               DrawEventRecorder* aRecorder)
+{
+  return mTargetForCurrentPage->MakeDrawTarget(aSize, aRecorder);
+}
+
+already_AddRefed<DrawTarget>
+PrintTargetEMF::GetReferenceDrawTarget(DrawEventRecorder* aRecorder)
+{
+  if (!mRefTarget) {
+    auto dummy = MakeUnique<SkNullWStream>();
+    mRefTarget = PrintTargetSkPDF::CreateOrNull(Move(dummy), mSize);
+  }
+
+  if (!mRefDT) {
+    mRefDT = mRefTarget->GetReferenceDrawTarget(aRecorder);
+  }
+
+  return mRefDT.forget();
+}
+
+} // namespace gfx
+} // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/gfx/thebes/PrintTargetEMF.h
@@ -0,0 +1,62 @@
+/* -*- 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/. */
+
+#ifndef MOZILLA_GFX_PRINTTARGETEMF_H
+#define MOZILLA_GFX_PRINTTARGETEMF_H
+
+#include "PrintTargetSkPDF.h"
+
+/* include windows.h for the HDC definitions that we need. */
+#include <windows.h>
+
+namespace mozilla {
+namespace gfx {
+
+/**
+ * A new subclass of PrintTarget.
+ * 1. It uses PrintTargetSkPDF to generate one PDF file for one page.
+ * 2. It then passes the FileDescriptor of that generated PDF file to the
+ *    PDFium process for EMF conversion.
+ * 3. After getting the converted EMF contents from the PDFium process, it then
+ *    draws it onto the printer DC to finish one page printing task.
+ */
+class PrintTargetEMF final : public mozilla::gfx::PrintTarget
+{
+public:
+  typedef gfx::IntSize IntSize;
+
+  static already_AddRefed<PrintTargetEMF>
+  CreateOrNull(HDC aDC, const IntSize& aSizeInPoints);
+
+  nsresult BeginPrinting(const nsAString& aTitle,
+                                 const nsAString& aPrintToFileName,
+                                 int32_t aStartPage,
+                                 int32_t aEndPage) final;
+  nsresult EndPrinting() final;
+  nsresult AbortPrinting() final;
+  nsresult BeginPage() final;
+  nsresult EndPage() final;
+
+  already_AddRefed<DrawTarget>
+  MakeDrawTarget(const IntSize& aSize,
+                 DrawEventRecorder* aRecorder = nullptr) final;
+
+  already_AddRefed<DrawTarget>
+  GetReferenceDrawTarget(DrawEventRecorder* aRecorder) final;
+
+private:
+  PrintTargetEMF(HDC aDC, const IntSize& aSize);
+
+  nsString mTitle;
+  RefPtr<PrintTargetSkPDF> mTargetForCurrentPage;
+  nsCOMPtr<nsIFile>        mPDFFileForOnePage;
+  RefPtr<PrintTargetSkPDF> mRefTarget;
+  HDC mPrinterDC;
+};
+
+} // namespace gfx
+} // namespace mozilla
+
+#endif /* MOZILLA_GFX_PRINTTARGETEMF_H */
--- a/gfx/thebes/moz.build
+++ b/gfx/thebes/moz.build
@@ -215,16 +215,17 @@ UNIFIED_SOURCES += [
 if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
     UNIFIED_SOURCES += [
         'gfxMacPlatformFontList.mm',
     ]
 elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
     UNIFIED_SOURCES += [
         'D3D11Checks.cpp',
         'DeviceManagerDx.cpp',
+        'PrintTargetEMF.cpp',
     ]
 
 if CONFIG['MOZ_ENABLE_SKIA_PDF']:
     EXPORTS.mozilla.gfx += [
         'PrintTargetSkPDF.h',
     ]
     SOURCES += [
         'PrintTargetSkPDF.cpp',