gecko-dev/gfx/thebes/PrintTargetEMF.cpp
cku bfe3b297fb Bug 1399787 - Part 11.a. Use PrintTargetEMF to print content documents. r=jwatt
Before we introduce PrintTargetEMF, all PrintTargets finish page printing task
before the end of PrintTarget::EndPage(). Unlike others, a page printing
in PrintTargetEMF is done after receiving an async callback from the pdfium
process. So we have both async and sync page printing behavior now. This patch
is trying to make both of them work correctly while priting a content document.

MozReview-Commit-ID: 2PHJToFlvtu

--HG--
extra : rebase_source : 3531dd6a100e9518d8cb9904326250a8318cdad2
extra : source : f61eb00f83acf45511d8448922212dccb12b05aa
2017-11-05 04:36:37 +08:00

181 lines
5.1 KiB
C++

/* -*- 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"
#include "mozilla/widget/PDFiumProcessParent.h"
#include "mozilla/widget/PDFiumParent.h"
#include "mozilla/widget/WindowsEMF.h"
#include "mozilla/ipc/FileDescriptor.h"
#include "private/pprio.h"
using mozilla::gfx::DrawTarget;
using mozilla::ipc::FileDescriptor;
namespace mozilla {
namespace gfx {
PrintTargetEMF::PrintTargetEMF(HDC aDC, const IntSize& aSize)
: PrintTarget(/* not using cairo_surface_t */ nullptr, aSize)
, mPrinterDC(aDC)
{
}
PrintTargetEMF::~PrintTargetEMF()
{
if (mPDFiumProcess) {
mPDFiumProcess->Delete();
}
}
/* 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);
mPDFiumProcess = new PDFiumProcessParent();
NS_ENSURE_TRUE(mPDFiumProcess->Launch(this), NS_ERROR_FAILURE);
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;
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,
::GetDeviceCaps(mPrinterDC, HORZRES),
::GetDeviceCaps(mPrinterDC, VERTRES));
PR_Close(prfile);
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();
}
void
PrintTargetEMF::ConvertToEMFDone(const nsresult& aResult,
mozilla::ipc::Shmem&& aEMF)
{
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);
::EndPage(mPrinterDC);
}
mPDFiumProcess->GetActor()->DeallocShmem(aEMF);
mPDFFileForOnePage->Remove(/* aRecursive */ false);
mPDFFileForOnePage = nullptr;
if (mPageDoneCallback) {
mPageDoneCallback(aResult);
}
}
} // namespace gfx
} // namespace mozilla