Bug 1319423 - Part 3 - Change the print IPC to not require the content process to create a temporary file; r?bobowen
MozReview-Commit-ID: GLhTbfREk0n
--- a/layout/printing/DrawEventRecorder.cpp
+++ b/layout/printing/DrawEventRecorder.cpp
@@ -13,22 +13,16 @@ DrawEventRecorderPRFileDesc::RecordEvent
{
WriteElement(mOutputStream, aEvent.GetType());
aEvent.RecordToStream(mOutputStream);
Flush();
}
-DrawEventRecorderPRFileDesc::DrawEventRecorderPRFileDesc(const char* aFilename)
-{
- mOutputStream.Open(aFilename);
- WriteHeader(mOutputStream);
-}
-
DrawEventRecorderPRFileDesc::~DrawEventRecorderPRFileDesc()
{
if (IsOpen()) {
Close();
}
}
void
@@ -39,21 +33,21 @@ DrawEventRecorderPRFileDesc::Flush()
bool
DrawEventRecorderPRFileDesc::IsOpen()
{
return mOutputStream.IsOpen();
}
void
-DrawEventRecorderPRFileDesc::OpenNew(const char* aFilename)
+DrawEventRecorderPRFileDesc::OpenFD(PRFileDesc* aFd)
{
MOZ_ASSERT(!IsOpen());
- mOutputStream.Open(aFilename);
+ mOutputStream.OpenFD(aFd);
WriteHeader(mOutputStream);
}
void
DrawEventRecorderPRFileDesc::Close()
{
MOZ_ASSERT(IsOpen());
--- a/layout/printing/DrawEventRecorder.h
+++ b/layout/printing/DrawEventRecorder.h
@@ -12,19 +12,19 @@
namespace mozilla {
namespace layout {
class PRFileDescStream : public mozilla::gfx::EventStream {
public:
PRFileDescStream() : mFd(nullptr), mGood(true) {}
- void Open(const char* aFilename) {
+ void OpenFD(PRFileDesc* aFd) {
MOZ_ASSERT(!IsOpen());
- mFd = PR_Open(aFilename, PR_RDWR | PR_CREATE_FILE, PR_IRUSR | PR_IWUSR);
+ mFd = aFd;
mGood = true;
}
void Close() {
PR_Close(mFd);
mFd = nullptr;
}
@@ -35,16 +35,20 @@ public:
void Flush() {
// We need to be API compatible with std::ostream, and so we silently handle
// flushes on a closed FD.
if (IsOpen()) {
PR_Sync(mFd);
}
}
+ void Seek(PRInt32 aOffset, PRSeekWhence aWhence) {
+ PR_Seek(mFd, aOffset, aWhence);
+ }
+
void write(const char* aData, size_t aSize) {
// See comment in Flush().
if (IsOpen()) {
PR_Write(mFd, static_cast<const void*>(aData), aSize);
}
}
void read(char* aOut, size_t aSize) {
@@ -60,32 +64,30 @@ private:
PRFileDesc* mFd;
bool mGood;
};
class DrawEventRecorderPRFileDesc : public gfx::DrawEventRecorderPrivate
{
public:
MOZ_DECLARE_REFCOUNTED_VIRTUAL_TYPENAME(DrawEventRecorderPRFileDesc, override)
- explicit DrawEventRecorderPRFileDesc(const char* aFilename);
+ explicit DrawEventRecorderPRFileDesc() { };
~DrawEventRecorderPRFileDesc();
void RecordEvent(const gfx::RecordedEvent& aEvent) override;
/**
* Returns whether a recording file is currently open.
*/
bool IsOpen();
/**
- * Opens new file with the provided name. The recorder does NOT forget which
- * objects it has recorded. This can be used with Close, so that a recording
- * can be processed in chunks. The file must not already be open.
+ * Opens the recorder with the provided PRFileDesc *.
*/
- void OpenNew(const char* aFilename);
+ void OpenFD(PRFileDesc* aFd);
/**
* Closes the file so that it can be processed. The recorder does NOT forget
* which objects it has recorded. This can be used with OpenNew, so that a
* recording can be processed in chunks. The file must be open.
*/
void Close();
--- a/layout/printing/ipc/PRemotePrintJob.ipdl
+++ b/layout/printing/ipc/PRemotePrintJob.ipdl
@@ -17,19 +17,19 @@ both:
// Tell either side to abort printing and clean up.
async AbortPrint(nsresult aRv);
parent:
// Initialize the real print device with the given information.
async InitializePrint(nsString aDocumentTitle, nsString aPrintToFile,
int32_t aStartPage, int32_t aEndPage);
- // Translate the stored page recording and play back the events to the real
- // print device.
- async ProcessPage(nsCString aPageFileName);
+ // Translate the page recording writen into |fd| and play back the events to
+ // the real print device.
+ async ProcessPage();
// This informs the real print device that we've finished, so it can trigger
// the actual print.
async FinalizePrint();
// Report a state change to listeners in the parent process.
async StateChange(long aStateFlags,
nsresult aStatus);
@@ -40,19 +40,21 @@ parent:
long aCurTotalProgress,
long aMaxTotalProgress);
// Report a status change to listeners in the parent process.
async StatusChange(nsresult aStatus);
child:
// Inform the child that the print has been initialized in the parent or has
- // failed with result aRv.
- async PrintInitializationResult(nsresult aRv);
+ // failed with result aRv. Includes a file descriptor which the first page
+ // can be written to.
+ async PrintInitializationResult(nsresult aRv, FileDescriptor aFd);
- // Inform the child that the latest page has been processed remotely.
- async PageProcessed();
+ // Inform the child that the latest page has been processed remotely. Inclues
+ // a file descriptor which the next page can be written to.
+ async PageProcessed(FileDescriptor aFd);
async __delete__();
};
} // namespace layout
} // namespace mozilla
--- a/layout/printing/ipc/RemotePrintJobChild.cpp
+++ b/layout/printing/ipc/RemotePrintJobChild.cpp
@@ -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/. */
#include "RemotePrintJobChild.h"
#include "mozilla/Unused.h"
#include "nsPagePrintTimer.h"
#include "nsPrintEngine.h"
+#include "private/pprio.h"
namespace mozilla {
namespace layout {
NS_IMPL_ISUPPORTS(RemotePrintJobChild,
nsIWebProgressListener)
RemotePrintJobChild::RemotePrintJobChild()
@@ -31,36 +32,47 @@ RemotePrintJobChild::InitializePrint(con
Unused << SendInitializePrint(aDocumentTitle, aPrintToFile, aStartPage,
aEndPage);
mozilla::SpinEventLoopUntil([&]() { return mPrintInitialized; });
return mInitializationResult;
}
mozilla::ipc::IPCResult
-RemotePrintJobChild::RecvPrintInitializationResult(const nsresult& aRv)
+RemotePrintJobChild::RecvPrintInitializationResult(const nsresult& aRv,
+ const mozilla::ipc::FileDescriptor& aFd)
{
mPrintInitialized = true;
mInitializationResult = aRv;
+ if (NS_SUCCEEDED(aRv)) {
+ SetNextPageFD(aFd);
+ }
return IPC_OK();
}
+void RemotePrintJobChild::SetNextPageFD(const mozilla::ipc::FileDescriptor& aFd)
+{
+ auto handle = aFd.ClonePlatformHandle();
+ mNextPageFD = PR_ImportFile(PROsfd(handle.release()));
+}
+
void
-RemotePrintJobChild::ProcessPage(const nsCString& aPageFileName)
+RemotePrintJobChild::ProcessPage()
{
MOZ_ASSERT(mPagePrintTimer);
mPagePrintTimer->WaitForRemotePrint();
- Unused << SendProcessPage(aPageFileName);
+ Unused << SendProcessPage();
}
mozilla::ipc::IPCResult
-RemotePrintJobChild::RecvPageProcessed()
+RemotePrintJobChild::RecvPageProcessed(const mozilla::ipc::FileDescriptor& aFd)
{
MOZ_ASSERT(mPagePrintTimer);
+ SetNextPageFD(aFd);
mPagePrintTimer->RemotePrintFinished();
return IPC_OK();
}
mozilla::ipc::IPCResult
RemotePrintJobChild::RecvAbortPrint(const nsresult& aRv)
{
--- a/layout/printing/ipc/RemotePrintJobChild.h
+++ b/layout/printing/ipc/RemotePrintJobChild.h
@@ -29,33 +29,40 @@ public:
void ActorDestroy(ActorDestroyReason aWhy) final;
nsresult InitializePrint(const nsString& aDocumentTitle,
const nsString& aPrintToFile,
const int32_t& aStartPage,
const int32_t& aEndPage);
- mozilla::ipc::IPCResult RecvPrintInitializationResult(const nsresult& aRv) final;
+ mozilla::ipc::IPCResult RecvPrintInitializationResult(const nsresult& aRv,
+ const FileDescriptor& aFd) final;
- void ProcessPage(const nsCString& aPageFileName);
+ void ProcessPage();
- mozilla::ipc::IPCResult RecvPageProcessed() final;
+ mozilla::ipc::IPCResult RecvPageProcessed(const FileDescriptor& aFd) final;
mozilla::ipc::IPCResult RecvAbortPrint(const nsresult& aRv) final;
void SetPagePrintTimer(nsPagePrintTimer* aPagePrintTimer);
void SetPrintEngine(nsPrintEngine* aPrintEngine);
+ PRFileDesc *GetNextPageFD() {
+ return mNextPageFD;
+ }
+
private:
~RemotePrintJobChild() final;
+ void SetNextPageFD(const mozilla::ipc::FileDescriptor& aFd);
bool mPrintInitialized = false;
nsresult mInitializationResult = NS_OK;
RefPtr<nsPagePrintTimer> mPagePrintTimer;
RefPtr<nsPrintEngine> mPrintEngine;
+ PRFileDesc* mNextPageFD;
};
} // namespace layout
} // namespace mozilla
#endif // mozilla_layout_RemotePrintJobChild_h
--- a/layout/printing/ipc/RemotePrintJobParent.cpp
+++ b/layout/printing/ipc/RemotePrintJobParent.cpp
@@ -14,16 +14,18 @@
#include "nsAppDirectoryServiceDefs.h"
#include "nsComponentManagerUtils.h"
#include "nsDirectoryServiceUtils.h"
#include "nsDeviceContext.h"
#include "nsIDeviceContextSpec.h"
#include "nsIPrintSettings.h"
#include "nsIWebProgressListener.h"
#include "PrintTranslator.h"
+#include "private/pprio.h"
+#include "nsAnonymousTemporaryFile.h"
namespace mozilla {
namespace layout {
RemotePrintJobParent::RemotePrintJobParent(nsIPrintSettings* aPrintSettings)
: mPrintSettings(aPrintSettings)
{
MOZ_COUNT_CTOR(RemotePrintJobParent);
@@ -33,24 +35,31 @@ mozilla::ipc::IPCResult
RemotePrintJobParent::RecvInitializePrint(const nsString& aDocumentTitle,
const nsString& aPrintToFile,
const int32_t& aStartPage,
const int32_t& aEndPage)
{
nsresult rv = InitializePrintDevice(aDocumentTitle, aPrintToFile, aStartPage,
aEndPage);
if (NS_FAILED(rv)) {
- Unused << SendPrintInitializationResult(rv);
+ Unused << SendPrintInitializationResult(rv, FileDescriptor());
Unused << Send__delete__(this);
return IPC_OK();
}
mPrintTranslator.reset(new PrintTranslator(mPrintDeviceContext));
- Unused << SendPrintInitializationResult(NS_OK);
+ FileDescriptor fd;
+ rv = PrepareNextPageFD(&fd);
+ if (NS_FAILED(rv)) {
+ Unused << SendPrintInitializationResult(rv, FileDescriptor());
+ Unused << Send__delete__(this);
+ return IPC_OK();
+ }
+ Unused << SendPrintInitializationResult(NS_OK, fd);
return IPC_OK();
}
nsresult
RemotePrintJobParent::InitializePrintDevice(const nsString& aDocumentTitle,
const nsString& aPrintToFile,
const int32_t& aStartPage,
const int32_t& aEndPage)
@@ -77,76 +86,73 @@ RemotePrintJobParent::InitializePrintDev
aStartPage, aEndPage);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
return NS_OK;
}
+nsresult RemotePrintJobParent::PrepareNextPageFD(FileDescriptor* aFd) {
+ PRFileDesc *prFd = nullptr;
+ nsresult rv = NS_OpenAnonymousTemporaryFile(&prFd);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ *aFd = FileDescriptor(
+ FileDescriptor::PlatformHandleType(PR_FileDesc2NativeHandle(prFd)));
+ mCurrentPageStream.OpenFD(prFd);
+ return NS_OK;
+}
+
mozilla::ipc::IPCResult
-RemotePrintJobParent::RecvProcessPage(const nsCString& aPageFileName)
+RemotePrintJobParent::RecvProcessPage()
{
- nsresult rv = PrintPage(aPageFileName);
+ if (!mCurrentPageStream.IsOpen()) {
+ Unused << SendAbortPrint(NS_ERROR_FAILURE);
+ return IPC_OK();
+ }
+ mCurrentPageStream.Seek(0, PR_SEEK_SET);
+ nsresult rv = PrintPage(mCurrentPageStream);
+ mCurrentPageStream.Close();
if (NS_FAILED(rv)) {
Unused << SendAbortPrint(rv);
- } else {
- Unused << SendPageProcessed();
+ return IPC_OK();
}
+ FileDescriptor fd;
+ rv = PrepareNextPageFD(&fd);
+ if (NS_FAILED(rv)) {
+ Unused << SendAbortPrint(rv);
+ return IPC_OK();
+ }
+
+ Unused << SendPageProcessed(fd);
return IPC_OK();
}
nsresult
-RemotePrintJobParent::PrintPage(const nsCString& aPageFileName)
+RemotePrintJobParent::PrintPage(PRFileDescStream& aRecording)
{
MOZ_ASSERT(mPrintDeviceContext);
nsresult rv = mPrintDeviceContext->BeginPage();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
-
- nsCOMPtr<nsIFile> recordingFile;
- rv = NS_GetSpecialDirectory(NS_APP_CONTENT_PROCESS_TEMP_DIR,
- getter_AddRefs(recordingFile));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- rv = recordingFile->AppendNative(aPageFileName);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- nsAutoCString recordingPath;
- rv = recordingFile->GetNativePath(recordingPath);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- PRFileDescStream recording;
- recording.Open(recordingPath.get());
- MOZ_ASSERT(recording.IsOpen());
- if (!mPrintTranslator->TranslateRecording(recording)) {
+ if (!mPrintTranslator->TranslateRecording(aRecording)) {
return NS_ERROR_FAILURE;
}
rv = mPrintDeviceContext->EndPage();
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
- recording.Close();
- rv = recordingFile->Remove(/* recursive= */ false);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
return NS_OK;
}
mozilla::ipc::IPCResult
RemotePrintJobParent::RecvFinalizePrint()
{
// EndDocument is sometimes called in the child even when BeginDocument has
// not been called. See bug 1223332.
--- a/layout/printing/ipc/RemotePrintJobParent.h
+++ b/layout/printing/ipc/RemotePrintJobParent.h
@@ -3,21 +3,23 @@
/* 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_layout_RemotePrintJobParent_h
#define mozilla_layout_RemotePrintJobParent_h
#include "mozilla/layout/PRemotePrintJobParent.h"
+#include "mozilla/layout/printing/DrawEventRecorder.h"
#include "nsCOMArray.h"
#include "nsCOMPtr.h"
#include "mozilla/RefPtr.h"
#include "mozilla/UniquePtr.h"
+#include "mozilla/gfx/RecordedEvent.h"
class nsDeviceContext;
class nsIPrintSettings;
class nsIWebProgressListener;
class PrintTranslator;
namespace mozilla {
namespace layout {
@@ -29,17 +31,17 @@ public:
void ActorDestroy(ActorDestroyReason aWhy) final;
mozilla::ipc::IPCResult RecvInitializePrint(const nsString& aDocumentTitle,
const nsString& aPrintToFile,
const int32_t& aStartPage,
const int32_t& aEndPage) final;
- mozilla::ipc::IPCResult RecvProcessPage(const nsCString& aPageFileName) final;
+ mozilla::ipc::IPCResult RecvProcessPage() final;
mozilla::ipc::IPCResult RecvFinalizePrint() final;
mozilla::ipc::IPCResult RecvAbortPrint(const nsresult& aRv) final;
mozilla::ipc::IPCResult RecvStateChange(const long& aStateFlags,
const nsresult& aStatus) final;
@@ -65,20 +67,23 @@ public:
private:
~RemotePrintJobParent() final;
nsresult InitializePrintDevice(const nsString& aDocumentTitle,
const nsString& aPrintToFile,
const int32_t& aStartPage,
const int32_t& aEndPage);
- nsresult PrintPage(const nsCString& aPageFileName);
+ nsresult PrepareNextPageFD(FileDescriptor* aFd);
+
+ nsresult PrintPage(PRFileDescStream& aRecording);
nsCOMPtr<nsIPrintSettings> mPrintSettings;
RefPtr<nsDeviceContext> mPrintDeviceContext;
UniquePtr<PrintTranslator> mPrintTranslator;
nsCOMArray<nsIWebProgressListener> mPrintProgressListeners;
+ PRFileDescStream mCurrentPageStream;
};
} // namespace layout
} // namespace mozilla
#endif // mozilla_layout_RemotePrintJobParent_h
--- a/layout/printing/nsPagePrintTimer.cpp
+++ b/layout/printing/nsPagePrintTimer.cpp
@@ -151,17 +151,18 @@ nsPagePrintTimer::Notify(nsITimer *timer
if (mWatchDogCount > WATCH_DOG_MAX_COUNT) {
Fail();
return NS_OK;
}
}
if (mDocViewerPrint) {
bool donePrePrint = true;
- if (mPrintEngine) {
+ // Don't start to pre-print if we're waiting on the parent still.
+ if (mPrintEngine && !mWaitingForRemotePrint) {
donePrePrint = mPrintEngine->PrePrintPage();
}
if (donePrePrint && !mWaitingForRemotePrint) {
StopWatchDogTimer();
// Pass nullptr here since name already was set in constructor.
mDocument->Dispatch(TaskCategory::Other, do_AddRef(this));
} else {
--- a/widget/nsDeviceContextSpecProxy.cpp
+++ b/widget/nsDeviceContextSpecProxy.cpp
@@ -14,16 +14,17 @@
#include "mozilla/RefPtr.h"
#include "mozilla/Unused.h"
#include "nsComponentManagerUtils.h"
#include "nsAppDirectoryServiceDefs.h"
#include "nsDirectoryServiceUtils.h"
#include "nsIPrintSession.h"
#include "nsIPrintSettings.h"
#include "nsIUUIDGenerator.h"
+#include "private/pprio.h"
using mozilla::Unused;
using namespace mozilla;
using namespace mozilla::gfx;
NS_IMPL_ISUPPORTS(nsDeviceContextSpecProxy, nsIDeviceContextSpec)
@@ -138,58 +139,22 @@ nsDeviceContextSpecProxy::GetDPI()
float
nsDeviceContextSpecProxy::GetPrintingScale()
{
MOZ_ASSERT(mRealDeviceContextSpec);
return mRealDeviceContextSpec->GetPrintingScale();
}
-nsresult
-nsDeviceContextSpecProxy::CreateUniqueTempPath(nsACString& aFilePath)
-{
- MOZ_ASSERT(mRecordingDir);
- MOZ_ASSERT(mUuidGenerator);
-
- nsID uuid;
- nsresult rv = mUuidGenerator->GenerateUUIDInPlace(&uuid);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- char uuidChars[NSID_LENGTH];
- uuid.ToProvidedString(uuidChars);
- mRecordingFileName.AssignASCII(uuidChars);
-
- nsCOMPtr<nsIFile> recordingFile;
- rv = mRecordingDir->Clone(getter_AddRefs(recordingFile));
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- rv = recordingFile->AppendNative(mRecordingFileName);
- if (NS_WARN_IF(NS_FAILED(rv))) {
- return rv;
- }
-
- return recordingFile->GetNativePath(aFilePath);
-}
-
NS_IMETHODIMP
nsDeviceContextSpecProxy::BeginDocument(const nsAString& aTitle,
const nsAString& aPrintToFileName,
int32_t aStartPage, int32_t aEndPage)
{
- nsAutoCString recordingPath;
- nsresult rv = CreateUniqueTempPath(recordingPath);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- mRecorder = new mozilla::layout::DrawEventRecorderPRFileDesc(recordingPath.get());
+ mRecorder = new mozilla::layout::DrawEventRecorderPRFileDesc();
return mRemotePrintJob->InitializePrint(nsString(aTitle),
nsString(aPrintToFileName),
aStartPage, aEndPage);
}
NS_IMETHODIMP
nsDeviceContextSpecProxy::EndDocument()
{
@@ -202,31 +167,22 @@ nsDeviceContextSpecProxy::AbortDocument(
{
Unused << mRemotePrintJob->SendAbortPrint(NS_OK);
return NS_OK;
}
NS_IMETHODIMP
nsDeviceContextSpecProxy::BeginPage()
{
- // Reopen the file, if necessary, ready for the next page.
- if (!mRecorder->IsOpen()) {
- nsAutoCString recordingPath;
- nsresult rv = CreateUniqueTempPath(recordingPath);
- if (NS_FAILED(rv)) {
- return rv;
- }
-
- mRecorder->OpenNew(recordingPath.get());
- }
+ mRecorder->OpenFD(mRemotePrintJob->GetNextPageFD());
return NS_OK;
}
NS_IMETHODIMP
nsDeviceContextSpecProxy::EndPage()
{
// Send the page recording to the parent.
mRecorder->Close();
- mRemotePrintJob->ProcessPage(mRecordingFileName);
+ mRemotePrintJob->ProcessPage();
return NS_OK;
}