mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-30 08:12:05 +00:00
Bug 1279699: Use temporary files instead of shared memory to store the page recordings when printing via parent. r=bas, r=froydnj, r=jimm
This commit is contained in:
parent
f22cf0451c
commit
8565d5695d
@ -36,7 +36,7 @@ DrawEventRecorderPrivate::RecordEvent(const RecordedEvent &aEvent)
|
||||
}
|
||||
|
||||
DrawEventRecorderFile::DrawEventRecorderFile(const char *aFilename)
|
||||
: DrawEventRecorderPrivate(nullptr)
|
||||
: DrawEventRecorderPrivate(nullptr)
|
||||
, mOutputFile(aFilename, ofstream::binary)
|
||||
{
|
||||
mOutputStream = &mOutputFile;
|
||||
@ -55,6 +55,29 @@ DrawEventRecorderFile::Flush()
|
||||
mOutputFile.flush();
|
||||
}
|
||||
|
||||
bool
|
||||
DrawEventRecorderFile::IsOpen()
|
||||
{
|
||||
return mOutputFile.is_open();
|
||||
}
|
||||
|
||||
void
|
||||
DrawEventRecorderFile::OpenNew(const char *aFilename)
|
||||
{
|
||||
MOZ_ASSERT(!mOutputFile.is_open());
|
||||
|
||||
mOutputFile.open(aFilename, ofstream::binary);
|
||||
WriteHeader();
|
||||
}
|
||||
|
||||
void
|
||||
DrawEventRecorderFile::Close()
|
||||
{
|
||||
MOZ_ASSERT(mOutputFile.is_open());
|
||||
|
||||
mOutputFile.close();
|
||||
}
|
||||
|
||||
DrawEventRecorderMemory::DrawEventRecorderMemory()
|
||||
: DrawEventRecorderPrivate(nullptr)
|
||||
{
|
||||
|
@ -78,6 +78,25 @@ public:
|
||||
explicit DrawEventRecorderFile(const char *aFilename);
|
||||
~DrawEventRecorderFile();
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
void OpenNew(const char *aFilename);
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
private:
|
||||
virtual void Flush();
|
||||
|
||||
|
@ -24,8 +24,7 @@ parent:
|
||||
|
||||
// Translate the stored page recording and play back the events to the real
|
||||
// print device.
|
||||
// This will always deallocate the shared memory.
|
||||
async ProcessPage(Shmem aStoredPage);
|
||||
async ProcessPage(nsCString aPageFileName);
|
||||
|
||||
// This informs the real print device that we've finished, so it can trigger
|
||||
// the actual print.
|
||||
|
@ -47,12 +47,12 @@ RemotePrintJobChild::RecvPrintInitializationResult(const nsresult& aRv)
|
||||
}
|
||||
|
||||
void
|
||||
RemotePrintJobChild::ProcessPage(Shmem& aStoredPage)
|
||||
RemotePrintJobChild::ProcessPage(const nsCString& aPageFileName)
|
||||
{
|
||||
MOZ_ASSERT(mPagePrintTimer);
|
||||
|
||||
mPagePrintTimer->WaitForRemotePrint();
|
||||
Unused << SendProcessPage(aStoredPage);
|
||||
Unused << SendProcessPage(aPageFileName);
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
|
@ -36,7 +36,7 @@ public:
|
||||
|
||||
mozilla::ipc::IPCResult RecvPrintInitializationResult(const nsresult& aRv) final;
|
||||
|
||||
void ProcessPage(Shmem& aStoredPage);
|
||||
void ProcessPage(const nsCString& aPageFileName);
|
||||
|
||||
mozilla::ipc::IPCResult RecvPageProcessed() final;
|
||||
|
||||
|
@ -6,12 +6,14 @@
|
||||
|
||||
#include "RemotePrintJobParent.h"
|
||||
|
||||
#include <istream>
|
||||
#include <fstream>
|
||||
|
||||
#include "gfxContext.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "nsAppDirectoryServiceDefs.h"
|
||||
#include "nsComponentManagerUtils.h"
|
||||
#include "nsDirectoryServiceUtils.h"
|
||||
#include "nsDeviceContext.h"
|
||||
#include "nsIDeviceContextSpec.h"
|
||||
#include "nsIPrintSettings.h"
|
||||
@ -81,15 +83,9 @@ RemotePrintJobParent::InitializePrintDevice(const nsString& aDocumentTitle,
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
RemotePrintJobParent::RecvProcessPage(Shmem&& aStoredPage)
|
||||
RemotePrintJobParent::RecvProcessPage(const nsCString& aPageFileName)
|
||||
{
|
||||
nsresult rv = PrintPage(aStoredPage);
|
||||
|
||||
// Always deallocate the shared memory no matter what the result.
|
||||
if (!DeallocShmem(aStoredPage)) {
|
||||
NS_WARNING("Failed to deallocated shared memory, remote print will abort.");
|
||||
rv = NS_ERROR_FAILURE;
|
||||
}
|
||||
nsresult rv = PrintPage(aPageFileName);
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
Unused << SendAbortPrint(rv);
|
||||
@ -101,7 +97,7 @@ RemotePrintJobParent::RecvProcessPage(Shmem&& aStoredPage)
|
||||
}
|
||||
|
||||
nsresult
|
||||
RemotePrintJobParent::PrintPage(const Shmem& aStoredPage)
|
||||
RemotePrintJobParent::PrintPage(const nsCString& aPageFileName)
|
||||
{
|
||||
MOZ_ASSERT(mPrintDeviceContext);
|
||||
|
||||
@ -110,8 +106,25 @@ RemotePrintJobParent::PrintPage(const Shmem& aStoredPage)
|
||||
return rv;
|
||||
}
|
||||
|
||||
std::istringstream recording(std::string(aStoredPage.get<char>(),
|
||||
aStoredPage.Size<char>()));
|
||||
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;
|
||||
}
|
||||
|
||||
std::ifstream recording(recordingPath.get(), std::ifstream::binary);
|
||||
if (!mPrintTranslator->TranslateRecording(recording)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@ -121,6 +134,12 @@ RemotePrintJobParent::PrintPage(const Shmem& aStoredPage)
|
||||
return rv;
|
||||
}
|
||||
|
||||
recording.close();
|
||||
rv = recordingFile->Remove(/* recursive= */ false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ public:
|
||||
const int32_t& aStartPage,
|
||||
const int32_t& aEndPage) final;
|
||||
|
||||
mozilla::ipc::IPCResult RecvProcessPage(Shmem&& aStoredPage) final;
|
||||
mozilla::ipc::IPCResult RecvProcessPage(const nsCString& aPageFileName) final;
|
||||
|
||||
mozilla::ipc::IPCResult RecvFinalizePrint() final;
|
||||
|
||||
@ -70,7 +70,7 @@ private:
|
||||
const int32_t& aStartPage,
|
||||
const int32_t& aEndPage);
|
||||
|
||||
nsresult PrintPage(const Shmem& aStoredPage);
|
||||
nsresult PrintPage(const nsCString& aPageFileName);
|
||||
|
||||
nsCOMPtr<nsIPrintSettings> mPrintSettings;
|
||||
RefPtr<nsDeviceContext> mPrintDeviceContext;
|
||||
|
@ -14,8 +14,11 @@
|
||||
#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"
|
||||
|
||||
using mozilla::Unused;
|
||||
|
||||
@ -62,6 +65,17 @@ nsDeviceContextSpecProxy::Init(nsIWidget* aWidget,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
rv = NS_GetSpecialDirectory(NS_APP_CONTENT_PROCESS_TEMP_DIR,
|
||||
getter_AddRefs(mRecordingDir));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mUuidGenerator = do_GetService("@mozilla.org/uuid-generator;1", &rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -129,12 +143,48 @@ nsDeviceContextSpecProxy::GetPrintingScale()
|
||||
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)
|
||||
{
|
||||
mRecorder = new mozilla::gfx::DrawEventRecorderMemory();
|
||||
nsAutoCString recordingPath;
|
||||
nsresult rv = CreateUniqueTempPath(recordingPath);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mRecorder = new mozilla::gfx::DrawEventRecorderFile(recordingPath.get());
|
||||
return mRemotePrintJob->InitializePrint(nsString(aTitle),
|
||||
nsString(aPrintToFileName),
|
||||
aStartPage, aEndPage);
|
||||
@ -157,34 +207,26 @@ nsDeviceContextSpecProxy::AbortDocument()
|
||||
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());
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDeviceContextSpecProxy::EndPage()
|
||||
{
|
||||
// Save the current page recording to shared memory.
|
||||
mozilla::ipc::Shmem storedPage;
|
||||
size_t recordingSize = mRecorder->RecordingSize();
|
||||
if (!mRemotePrintJob->AllocShmem(recordingSize,
|
||||
mozilla::ipc::SharedMemory::TYPE_BASIC,
|
||||
&storedPage)) {
|
||||
NS_WARNING("Failed to create shared memory for remote printing.");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
bool success = mRecorder->CopyRecording(storedPage.get<char>(), recordingSize);
|
||||
if (!success) {
|
||||
NS_WARNING("Copying recording to shared memory was not succesful.");
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Wipe the recording to free memory. The recorder does not forget which data
|
||||
// backed objects that it has stored.
|
||||
mRecorder->WipeRecording();
|
||||
|
||||
// Send the page recording to the parent.
|
||||
mRemotePrintJob->ProcessPage(storedPage);
|
||||
mRecorder->Close();
|
||||
mRemotePrintJob->ProcessPage(mRecordingFileName);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -9,12 +9,15 @@
|
||||
|
||||
#include "nsIDeviceContextSpec.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
|
||||
class nsIFile;
|
||||
class nsIPrintSession;
|
||||
class nsIUUIDGenerator;
|
||||
|
||||
namespace mozilla {
|
||||
namespace gfx {
|
||||
class DrawEventRecorderMemory;
|
||||
class DrawEventRecorderFile;
|
||||
}
|
||||
|
||||
namespace layout {
|
||||
@ -38,6 +41,7 @@ public:
|
||||
|
||||
float GetPrintingScale() final;
|
||||
|
||||
|
||||
NS_IMETHOD BeginDocument(const nsAString& aTitle,
|
||||
const nsAString& aPrintToFileName,
|
||||
int32_t aStartPage, int32_t aEndPage) final;
|
||||
@ -53,11 +57,16 @@ public:
|
||||
private:
|
||||
~nsDeviceContextSpecProxy() {}
|
||||
|
||||
nsresult CreateUniqueTempPath(nsACString& aFilePath);
|
||||
|
||||
nsCOMPtr<nsIPrintSettings> mPrintSettings;
|
||||
nsCOMPtr<nsIPrintSession> mPrintSession;
|
||||
nsCOMPtr<nsIDeviceContextSpec> mRealDeviceContextSpec;
|
||||
RefPtr<mozilla::layout::RemotePrintJobChild> mRemotePrintJob;
|
||||
RefPtr<mozilla::gfx::DrawEventRecorderMemory> mRecorder;
|
||||
RefPtr<mozilla::gfx::DrawEventRecorderFile> mRecorder;
|
||||
nsCOMPtr<nsIFile> mRecordingDir;
|
||||
nsCOMPtr<nsIUUIDGenerator> mUuidGenerator;
|
||||
nsCString mRecordingFileName;
|
||||
};
|
||||
|
||||
#endif // nsDeviceContextSpecProxy_h
|
||||
|
@ -110,6 +110,9 @@
|
||||
// NS_APP_CONTENT_PROCESS_TEMP_DIR, but that should not be relied upon.
|
||||
//
|
||||
#define NS_APP_CONTENT_PROCESS_TEMP_DIR "ContentTmpD"
|
||||
#else
|
||||
// Otherwise NS_APP_CONTENT_PROCESS_TEMP_DIR must match NS_OS_TEMP_DIR.
|
||||
#define NS_APP_CONTENT_PROCESS_TEMP_DIR "TmpD"
|
||||
#endif // (defined(XP_WIN) || defined(XP_MACOSX)) && defined(MOZ_CONTENT_SANDBOX)
|
||||
|
||||
#endif // nsAppDirectoryServiceDefs_h___
|
||||
|
Loading…
Reference in New Issue
Block a user