mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-28 04:35:33 +00:00
eb34bd15b9
This also holds the resolution in the print settings, so that we can start to remove the access to the native Windows print devices in the child process.
332 lines
9.0 KiB
C++
332 lines
9.0 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 "gfxWindowsSurface.h"
|
|
#include "gfxContext.h"
|
|
#include "gfxPlatform.h"
|
|
#include "mozilla/gfx/HelpersCairo.h"
|
|
#include "mozilla/gfx/Logging.h"
|
|
|
|
#include "cairo.h"
|
|
#include "cairo-win32.h"
|
|
|
|
#include "nsString.h"
|
|
|
|
gfxWindowsSurface::gfxWindowsSurface(HWND wnd, uint32_t flags) :
|
|
mOwnsDC(true), mForPrinting(false), mWnd(wnd)
|
|
{
|
|
mDC = ::GetDC(mWnd);
|
|
InitWithDC(flags);
|
|
}
|
|
|
|
gfxWindowsSurface::gfxWindowsSurface(HDC dc, uint32_t flags) :
|
|
mOwnsDC(false), mForPrinting(false), mDC(dc), mWnd(nullptr)
|
|
{
|
|
if (flags & FLAG_TAKE_DC)
|
|
mOwnsDC = true;
|
|
|
|
#ifdef NS_PRINTING
|
|
if (flags & FLAG_FOR_PRINTING) {
|
|
Init(cairo_win32_printing_surface_create(mDC));
|
|
mForPrinting = true;
|
|
if (!mSurfaceValid) {
|
|
gfxCriticalNote << "Invalid printing surface";
|
|
}
|
|
} else
|
|
#endif
|
|
InitWithDC(flags);
|
|
}
|
|
|
|
gfxWindowsSurface::gfxWindowsSurface(IDirect3DSurface9 *surface, uint32_t flags) :
|
|
mOwnsDC(false), mForPrinting(false), mDC(0), mWnd(nullptr)
|
|
{
|
|
cairo_surface_t *surf = cairo_win32_surface_create_with_d3dsurface9(surface);
|
|
Init(surf);
|
|
}
|
|
|
|
|
|
void
|
|
gfxWindowsSurface::MakeInvalid(mozilla::gfx::IntSize& size)
|
|
{
|
|
size = mozilla::gfx::IntSize(-1, -1);
|
|
}
|
|
|
|
gfxWindowsSurface::gfxWindowsSurface(const mozilla::gfx::IntSize& realSize, gfxImageFormat imageFormat) :
|
|
mOwnsDC(false), mForPrinting(false), mWnd(nullptr)
|
|
{
|
|
mozilla::gfx::IntSize size(realSize);
|
|
if (!CheckSurfaceSize(size))
|
|
MakeInvalid(size);
|
|
|
|
cairo_format_t cformat = GfxFormatToCairoFormat(imageFormat);
|
|
cairo_surface_t *surf =
|
|
cairo_win32_surface_create_with_dib(cformat, size.width, size.height);
|
|
|
|
Init(surf);
|
|
|
|
if (CairoStatus() == CAIRO_STATUS_SUCCESS) {
|
|
mDC = cairo_win32_surface_get_dc(CairoSurface());
|
|
RecordMemoryUsed(size.width * size.height * 4 + sizeof(gfxWindowsSurface));
|
|
} else {
|
|
mDC = nullptr;
|
|
}
|
|
}
|
|
|
|
gfxWindowsSurface::gfxWindowsSurface(HDC dc, const mozilla::gfx::IntSize& realSize, gfxImageFormat imageFormat) :
|
|
mOwnsDC(false), mForPrinting(false), mWnd(nullptr)
|
|
{
|
|
mozilla::gfx::IntSize size(realSize);
|
|
if (!CheckSurfaceSize(size))
|
|
MakeInvalid(size);
|
|
|
|
cairo_format_t cformat = GfxFormatToCairoFormat(imageFormat);
|
|
cairo_surface_t *surf =
|
|
cairo_win32_surface_create_with_ddb(dc, cformat,
|
|
size.width, size.height);
|
|
|
|
Init(surf);
|
|
|
|
if (mSurfaceValid) {
|
|
// DDBs will generally only use 3 bytes per pixel when RGB24
|
|
int bytesPerPixel =
|
|
((imageFormat == mozilla::gfx::SurfaceFormat::X8R8G8B8_UINT32) ? 3 : 4);
|
|
RecordMemoryUsed(size.width * size.height * bytesPerPixel + sizeof(gfxWindowsSurface));
|
|
}
|
|
|
|
if (CairoStatus() == 0)
|
|
mDC = cairo_win32_surface_get_dc(CairoSurface());
|
|
else
|
|
mDC = nullptr;
|
|
}
|
|
|
|
gfxWindowsSurface::gfxWindowsSurface(cairo_surface_t *csurf) :
|
|
mOwnsDC(false), mForPrinting(false), mWnd(nullptr)
|
|
{
|
|
if (cairo_surface_status(csurf) == 0)
|
|
mDC = cairo_win32_surface_get_dc(csurf);
|
|
else
|
|
mDC = nullptr;
|
|
|
|
if (cairo_surface_get_type(csurf) == CAIRO_SURFACE_TYPE_WIN32_PRINTING)
|
|
mForPrinting = true;
|
|
|
|
Init(csurf, true);
|
|
}
|
|
|
|
void
|
|
gfxWindowsSurface::InitWithDC(uint32_t flags)
|
|
{
|
|
if (flags & FLAG_IS_TRANSPARENT) {
|
|
Init(cairo_win32_surface_create_with_alpha(mDC));
|
|
} else {
|
|
Init(cairo_win32_surface_create(mDC));
|
|
}
|
|
}
|
|
|
|
already_AddRefed<gfxASurface>
|
|
gfxWindowsSurface::CreateSimilarSurface(gfxContentType aContent,
|
|
const mozilla::gfx::IntSize& aSize)
|
|
{
|
|
if (!mSurface || !mSurfaceValid) {
|
|
return nullptr;
|
|
}
|
|
|
|
cairo_surface_t *surface;
|
|
if (!mForPrinting && GetContentType() == gfxContentType::COLOR_ALPHA) {
|
|
// When creating a similar surface to a transparent surface, ensure
|
|
// the new surface uses a DIB. cairo_surface_create_similar won't
|
|
// use a DIB for a gfxContentType::COLOR surface if this surface doesn't
|
|
// have a DIB (e.g. if we're a transparent window surface). But
|
|
// we need a DIB to perform well if the new surface is composited into
|
|
// a surface that's the result of create_similar(gfxContentType::COLOR_ALPHA)
|
|
// (e.g. a backbuffer for the window) --- that new surface *would*
|
|
// have a DIB.
|
|
gfxImageFormat gformat =
|
|
gfxPlatform::GetPlatform()->OptimalFormatForContent(aContent);
|
|
cairo_format_t cformat = GfxFormatToCairoFormat(gformat);
|
|
surface = cairo_win32_surface_create_with_dib(cformat, aSize.width,
|
|
aSize.height);
|
|
} else {
|
|
surface =
|
|
cairo_surface_create_similar(mSurface, (cairo_content_t)(int)aContent,
|
|
aSize.width, aSize.height);
|
|
}
|
|
|
|
if (cairo_surface_status(surface)) {
|
|
cairo_surface_destroy(surface);
|
|
return nullptr;
|
|
}
|
|
|
|
RefPtr<gfxASurface> result = Wrap(surface, aSize);
|
|
cairo_surface_destroy(surface);
|
|
return result.forget();
|
|
}
|
|
|
|
gfxWindowsSurface::~gfxWindowsSurface()
|
|
{
|
|
if (mOwnsDC) {
|
|
if (mWnd)
|
|
::ReleaseDC(mWnd, mDC);
|
|
else
|
|
::DeleteDC(mDC);
|
|
}
|
|
}
|
|
|
|
HDC
|
|
gfxWindowsSurface::GetDC()
|
|
{
|
|
return cairo_win32_surface_get_dc (CairoSurface());
|
|
}
|
|
|
|
|
|
already_AddRefed<gfxImageSurface>
|
|
gfxWindowsSurface::GetAsImageSurface()
|
|
{
|
|
if (!mSurfaceValid) {
|
|
NS_WARNING ("GetImageSurface on an invalid (null) surface; who's calling this without checking for surface errors?");
|
|
return nullptr;
|
|
}
|
|
|
|
NS_ASSERTION(CairoSurface() != nullptr, "CairoSurface() shouldn't be nullptr when mSurfaceValid is TRUE!");
|
|
|
|
if (mForPrinting)
|
|
return nullptr;
|
|
|
|
cairo_surface_t *isurf = cairo_win32_surface_get_image(CairoSurface());
|
|
if (!isurf)
|
|
return nullptr;
|
|
|
|
RefPtr<gfxImageSurface> result = gfxASurface::Wrap(isurf).downcast<gfxImageSurface>();
|
|
result->SetOpaqueRect(GetOpaqueRect());
|
|
|
|
return result.forget();
|
|
}
|
|
|
|
nsresult
|
|
gfxWindowsSurface::BeginPrinting(const nsAString& aTitle,
|
|
const nsAString& aPrintToFileName)
|
|
{
|
|
#ifdef NS_PRINTING
|
|
#define DOC_TITLE_LENGTH (MAX_PATH-1)
|
|
if (!mForPrinting) {
|
|
return NS_OK;
|
|
}
|
|
|
|
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(mDC, &docinfo);
|
|
|
|
return NS_OK;
|
|
#else
|
|
return NS_ERROR_FAILURE;
|
|
#endif
|
|
}
|
|
|
|
nsresult
|
|
gfxWindowsSurface::EndPrinting()
|
|
{
|
|
#ifdef NS_PRINTING
|
|
if (!mForPrinting) {
|
|
return NS_OK;
|
|
}
|
|
|
|
int result = ::EndDoc(mDC);
|
|
if (result <= 0)
|
|
return NS_ERROR_FAILURE;
|
|
|
|
return NS_OK;
|
|
#else
|
|
return NS_ERROR_FAILURE;
|
|
#endif
|
|
}
|
|
|
|
nsresult
|
|
gfxWindowsSurface::AbortPrinting()
|
|
{
|
|
#ifdef NS_PRINTING
|
|
if (!mForPrinting) {
|
|
return NS_OK;
|
|
}
|
|
|
|
int result = ::AbortDoc(mDC);
|
|
if (result <= 0)
|
|
return NS_ERROR_FAILURE;
|
|
return NS_OK;
|
|
#else
|
|
return NS_ERROR_FAILURE;
|
|
#endif
|
|
}
|
|
|
|
nsresult
|
|
gfxWindowsSurface::BeginPage()
|
|
{
|
|
#ifdef NS_PRINTING
|
|
if (!mForPrinting) {
|
|
return NS_OK;
|
|
}
|
|
|
|
int result = ::StartPage(mDC);
|
|
if (result <= 0)
|
|
return NS_ERROR_FAILURE;
|
|
return NS_OK;
|
|
#else
|
|
return NS_ERROR_FAILURE;
|
|
#endif
|
|
}
|
|
|
|
nsresult
|
|
gfxWindowsSurface::EndPage()
|
|
{
|
|
#ifdef NS_PRINTING
|
|
if (!mForPrinting) {
|
|
return NS_OK;
|
|
}
|
|
|
|
cairo_surface_show_page(CairoSurface());
|
|
int result = ::EndPage(mDC);
|
|
if (result <= 0)
|
|
return NS_ERROR_FAILURE;
|
|
return NS_OK;
|
|
#else
|
|
return NS_ERROR_FAILURE;
|
|
#endif
|
|
}
|
|
|
|
const mozilla::gfx::IntSize
|
|
gfxWindowsSurface::GetSize() const
|
|
{
|
|
if (mForPrinting) {
|
|
// On Windows we need to use the printable area of the page.
|
|
float width = (::GetDeviceCaps(mDC, HORZRES) * POINTS_PER_INCH_FLOAT)
|
|
/ ::GetDeviceCaps(mDC, LOGPIXELSX);
|
|
float height = (::GetDeviceCaps(mDC, VERTRES) * POINTS_PER_INCH_FLOAT)
|
|
/ ::GetDeviceCaps(mDC, LOGPIXELSY);
|
|
return mozilla::gfx::IntSize(width, height);
|
|
}
|
|
|
|
if (!mSurfaceValid) {
|
|
NS_WARNING ("GetImageSurface on an invalid (null) surface; who's calling this without checking for surface errors?");
|
|
return mozilla::gfx::IntSize(-1, -1);
|
|
}
|
|
|
|
NS_ASSERTION(mSurface != nullptr, "CairoSurface() shouldn't be nullptr when mSurfaceValid is TRUE!");
|
|
|
|
return mozilla::gfx::IntSize(cairo_win32_surface_get_width(mSurface),
|
|
cairo_win32_surface_get_height(mSurface));
|
|
}
|