зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1106321 - Serialize DEVMODE down to the content process when printing on Windows. r=jimm
--HG-- extra : commitid : IhjNJOOtmms extra : rebase_source : 6b0ba29e866dcf63a3054eb955ece082cbbeda13 extra : amend_source : 70bcf59b1f4b1d7a3a8ec4183b3b9710eedfb5f9
This commit is contained in:
Родитель
a290912621
Коммит
7421d14843
|
@ -76,6 +76,7 @@ struct PrintData {
|
|||
bool isFramesetFrameSelected;
|
||||
bool isIFrameSelected;
|
||||
bool isRangeSelection;
|
||||
uint8_t[] devModeData;
|
||||
|
||||
/**
|
||||
* GTK-specific things. Some of these might look like dupes of the
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <algorithm>
|
||||
|
||||
#include "nsThreadUtils.h"
|
||||
#include "ipc/IPCMessageUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
|
@ -93,9 +94,6 @@ WebBrowserPersistSerializeChild::Write(const char* aBuf, uint32_t aCount,
|
|||
// refcounting.
|
||||
MOZ_RELEASE_ASSERT(NS_IsMainThread(), "Fix this class to be thread-safe.");
|
||||
|
||||
// Limit the size of an individual IPC message.
|
||||
static const uint32_t kMaxWrite = 65536;
|
||||
|
||||
// Work around bug 1181433 by sending multiple messages if
|
||||
// necessary to write the entire aCount bytes, even though
|
||||
// nsIOutputStream.idl says we're allowed to do a short write.
|
||||
|
@ -103,7 +101,7 @@ WebBrowserPersistSerializeChild::Write(const char* aBuf, uint32_t aCount,
|
|||
uint32_t count = aCount;
|
||||
*aWritten = 0;
|
||||
while (count > 0) {
|
||||
uint32_t toWrite = std::min(kMaxWrite, count);
|
||||
uint32_t toWrite = std::min(IPC::MAX_MESSAGE_SIZE, count);
|
||||
nsTArray<uint8_t> arrayBuf;
|
||||
// It would be nice if this extra copy could be avoided.
|
||||
arrayBuf.AppendElements(buf, toWrite);
|
||||
|
|
|
@ -121,6 +121,11 @@ struct OwningSerializedStructuredCloneBuffer : public SerializedStructuredCloneB
|
|||
|
||||
namespace IPC {
|
||||
|
||||
/**
|
||||
* Maximum size, in bytes, of a single IPC message.
|
||||
*/
|
||||
static const uint32_t MAX_MESSAGE_SIZE = 65536;
|
||||
|
||||
/**
|
||||
* Generic enum serializer.
|
||||
*
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
#include "nsGfxCIID.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsIWebBrowserPrint.h"
|
||||
#include "nsWindowsHelpers.h"
|
||||
#include "ipc/IPCMessageUtils.h"
|
||||
|
||||
const char kPrinterEnumeratorContractID[] = "@mozilla.org/gfx/printerenumerator;1";
|
||||
|
||||
|
@ -65,6 +67,38 @@ nsPrintOptionsWin::SerializeToPrintData(nsIPrintSettings* aSettings,
|
|||
free(deviceName);
|
||||
free(driverName);
|
||||
|
||||
// When creating the print dialog on Windows, the parent creates a DEVMODE
|
||||
// which is used to convey print settings to the Windows printing backend.
|
||||
// We don't, therefore, want or care about DEVMODEs sent up from the child.
|
||||
if (XRE_IsParentProcess()) {
|
||||
// A DEVMODE can actually be of arbitrary size. If it turns out that it'll
|
||||
// make our IPC message larger than the limit, then we'll error out.
|
||||
LPDEVMODEW devModeRaw;
|
||||
psWin->GetDevMode(&devModeRaw); // This actually allocates a copy of the
|
||||
// the nsIPrintSettingsWin DEVMODE, so
|
||||
// we're now responsible for deallocating
|
||||
// it. We'll use an nsAutoDevMode helper
|
||||
// to do this.
|
||||
if (devModeRaw) {
|
||||
nsAutoDevMode devMode(devModeRaw);
|
||||
devModeRaw = nullptr;
|
||||
|
||||
size_t devModeTotalSize = devMode->dmSize + devMode->dmDriverExtra;
|
||||
size_t msgTotalSize = sizeof(PrintData) + devModeTotalSize;
|
||||
|
||||
if (msgTotalSize > IPC::MAX_MESSAGE_SIZE) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// Instead of reaching in and manually reading each member, we'll just
|
||||
// copy the bits over.
|
||||
const char* devModeData = reinterpret_cast<const char*>(devMode.get());
|
||||
nsTArray<uint8_t> arrayBuf;
|
||||
arrayBuf.AppendElements(devModeData, devModeTotalSize);
|
||||
data->devModeData().SwapElements(arrayBuf);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -80,19 +114,31 @@ nsPrintOptionsWin::DeserializeToPrintSettings(const PrintData& data,
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
psWin->SetDeviceName(data.deviceName().get());
|
||||
psWin->SetDriverName(data.driverName().get());
|
||||
if (XRE_IsContentProcess()) {
|
||||
psWin->SetDeviceName(data.deviceName().get());
|
||||
psWin->SetDriverName(data.driverName().get());
|
||||
|
||||
// We also need to prepare a DevMode and stuff it into our newly
|
||||
// created nsIPrintSettings...
|
||||
nsXPIDLString printerName;
|
||||
settings->GetPrinterName(getter_Copies(printerName));
|
||||
HGLOBAL gDevMode = CreateGlobalDevModeAndInit(printerName, settings);
|
||||
LPDEVMODEW devMode = (LPDEVMODEW)::GlobalLock(gDevMode);
|
||||
psWin->SetDevMode(devMode);
|
||||
nsXPIDLString printerName;
|
||||
settings->GetPrinterName(getter_Copies(printerName));
|
||||
|
||||
::GlobalUnlock(gDevMode);
|
||||
::GlobalFree(gDevMode);
|
||||
DEVMODEW* devModeRaw = (DEVMODEW*)::HeapAlloc(::GetProcessHeap(), HEAP_ZERO_MEMORY,
|
||||
data.devModeData().Length());
|
||||
if (!devModeRaw) {
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
nsAutoDevMode devMode(devModeRaw);
|
||||
devModeRaw = nullptr;
|
||||
|
||||
// Seems a bit silly to copy the buffer out, just so that SetDevMode can
|
||||
// copy it again. However, if I attempt to just pass
|
||||
// data.devModeData.Elements() casted to an DEVMODEW* to SetDevMode, I get
|
||||
// a "Conversion loses qualifiers" build-time error because
|
||||
// data.devModeData.Elements() is of type const char *.
|
||||
memcpy(devMode.get(), data.devModeData().Elements(), data.devModeData().Length());
|
||||
|
||||
psWin->SetDevMode(devMode); // Copies
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
|
|
@ -120,10 +120,30 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
template<>
|
||||
class nsAutoRefTraits<DEVMODEW*>
|
||||
{
|
||||
public:
|
||||
typedef DEVMODEW* RawRef;
|
||||
static RawRef Void()
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static void Release(RawRef aDevMode)
|
||||
{
|
||||
if (aDevMode != Void()) {
|
||||
::HeapFree(::GetProcessHeap(), 0, aDevMode);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
typedef nsAutoRef<HKEY> nsAutoRegKey;
|
||||
typedef nsAutoRef<SC_HANDLE> nsAutoServiceHandle;
|
||||
typedef nsAutoRef<HANDLE> nsAutoHandle;
|
||||
typedef nsAutoRef<HMODULE> nsModuleHandle;
|
||||
typedef nsAutoRef<DEVMODEW*> nsAutoDevMode;
|
||||
|
||||
namespace {
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче