Bug 1106321 - Printing Page Setup Settings Disobeyed Under e10s
Looks like Black and White and a few other settings aren't being serialized correctly.
The problem is that the DEVMODE that's created on the parent side isn't
being fully serialized. We used to be able to get away with that,
because the DEVMODE was still stored and used to communicate to the OS /
printer driver. Because we're serializing and using the DEVMODE in the
child, we can't really get away with that. We
have
to serialize the things in the DEVMODE.
Looks like there are already two nsIPrintSettings <-> DEVMODE methods already. Those are:
DEVMODE -> nsIPrintSettings
nsDeviceContextSpecWin::SetPrintSettingsFromDevMode
and
static SetupDevModeFromSettings
So it looks like DEVMODE's are shared between printer drivers and like… display drivers or something.
I only care about members that printers use on this struct. What are they?
typedef
struct
_devicemode {
TCHAR dmDeviceName[CCHDEVICENAME];
WORD dmSpecVersion;
WORD dmDriverVersion;
WORD dmSize;
WORD dmDriverExtra;
DWORD dmFields;
union {
struct {
short dmOrientation;
short dmPaperSize;
short dmPaperLength;
short dmPaperWidth;
short dmScale;
short dmCopies;
short dmDefaultSource;
short dmPrintQuality;
};
struct {
POINTL dmPosition;
DWORD dmDisplayOrientation;
DWORD dmDisplayFixedOutput;
};
};
short dmColor;
short dmDuplex;
short dmYResolution;
short dmTTOption;
short dmCollate;
TCHAR dmFormName[CCHFORMNAME];
WORD dmLogPixels;
DWORD dmBitsPerPel;
DWORD dmPelsWidth;
DWORD dmPelsHeight;
union {
DWORD dmDisplayFlags;
DWORD dmNup;
};
DWORD dmDisplayFrequency;
# if (WINVER >= 0x0400)
DWORD dmICMMethod;
DWORD dmICMIntent;
DWORD dmMediaType;
DWORD dmDitherType;
DWORD dmReserved1;
DWORD dmReserved2;
# if (WINVER >= 0x0500) || (_WIN32_WINNT >= 0x0400)
DWORD dmPanningWidth;
DWORD dmPanningHeight;
#endif
#endif
} DEVMODE, *PDEVMODE, *LPDEVMODE;
TCHAR dmDeviceName[CCHDEVICENAME];
WORD dmSpecVersion;
WORD dmDriverVersion;
WORD dmSize;
WORD dmDriverExtra;
DWORD dmFields;
union {
struct {
short dmOrientation;
short dmPaperSize;
short dmPaperLength;
short dmPaperWidth;
short dmScale;
short dmCopies;
short dmDefaultSource;
short dmPrintQuality;
};
struct {
POINTL dmPosition;
DWORD dmDisplayOrientation;
DWORD dmDisplayFixedOutput;
};
};
short dmColor;
short dmDuplex;
short dmYResolution;
short dmTTOption;
short dmCollate;
TCHAR dmFormName[CCHFORMNAME];
WORD dmLogPixels;
DWORD dmBitsPerPel;
DWORD dmPelsWidth;
DWORD dmPelsHeight;
union {
DWORD dmDisplayFlags;
DWORD dmNup;
};
DWORD dmDisplayFrequency;
# if (WINVER >= 0x0400)
DWORD dmICMMethod;
DWORD dmICMIntent;
DWORD dmMediaType;
DWORD dmDitherType;
DWORD dmReserved1;
DWORD dmReserved2;
# if (WINVER >= 0x0500) || (_WIN32_WINNT >= 0x0400)
DWORD dmPanningWidth;
DWORD dmPanningHeight;
#endif
#endif
} DEVMODE, *PDEVMODE, *LPDEVMODE;
Huh… dmDriverExtra sounds interesting. I guess it's possible that a
printer driver might jam some extra data after the struct? Sheeeit.
So, uh, I guess I just need to add something to PrintData to carry those bytes? Yeah, probably.
2:55 PM
<
&
billm
> mconley: oh, I see. we save a copy of the devmode here:
http://mxr.mozilla.org/mozilla-central/source/widget/windows/nsPrintSettingsWin.cpp#78
2:58 PM
<
mconley
> billm: okie dokie. Do we have example code anywhere where we
do this kind of wholesale bit transfer? I used memcpy. Once. a looooong
time ago.
2:58 PM
<
mconley
> and I have no idea if that's appropriate for our IPC stuff, or if there's a better way.
2:59 PM
<
&
billm
> mconley: jld's save document patch did something like that:
https://hg.mozilla.org/integration/mozilla-inbound/rev/d19a0d92455b#l28.103
3:00 PM
<
&
billm
> mconley: the memcpy call in the code I pasted is probably similar to what you'll need
A device driver's private data follows the public portion of the
DEVMODE
structure. The size of the public data can vary for different versions of the structure. The
dmSize
member specifies the number of bytes of public data, and the
dmDriverExtra
member specifies the number of bytes of private data.
FUCK. So I have to like… maybe send an arbitrarily large message across IPC. JESUS.
Ok. Keep calm. How would that work?
Well, the easiest thing would be to flat out fail if the DEVMODE size
exceeds the message limit. I wonder how far that would get us?
Maybe it'd be far enough. Because if it turns out we don't need the
private data with bobowen's stuff, then we can just hold on to the dev
mode until the child is ready to roll.
I'm starting to like that.
SO, plan of action:
Add a devModeData member to the PrintData struct
When serializing to PrintData, if we're in the parent process, serialize the devmode.
If the PrintData struct size, plus dmSize and dmDriverExtra size exceeds 65536 bytes, return NS_ERROR_ something.
When deserializing to nsIPrintSettings, if we're in the content process, deserialize the devmode.
Is it necessary for the child to have created a DEVMODE in the first place?
Not really - not unless it's printing silently, in which case it won't
need to communicate with the parent process at all (until bobowen's
stuff gets rolling).
Profit?
This seems to work. I've spun out a try build to get the reporter to try.
Okay, jimm has some suggestions. TIL about nsWindowsHelpers.h. Noice - I can create an Auto pointer thing for DevMode.