michael@0: /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #include "gfxWindowsSurface.h" michael@0: #include "gfxContext.h" michael@0: #include "gfxPlatform.h" michael@0: michael@0: #include "cairo.h" michael@0: #include "cairo-win32.h" michael@0: michael@0: #include "nsString.h" michael@0: michael@0: gfxWindowsSurface::gfxWindowsSurface(HWND wnd, uint32_t flags) : michael@0: mOwnsDC(true), mForPrinting(false), mWnd(wnd) michael@0: { michael@0: mDC = ::GetDC(mWnd); michael@0: InitWithDC(flags); michael@0: } michael@0: michael@0: gfxWindowsSurface::gfxWindowsSurface(HDC dc, uint32_t flags) : michael@0: mOwnsDC(false), mForPrinting(false), mDC(dc), mWnd(nullptr) michael@0: { michael@0: if (flags & FLAG_TAKE_DC) michael@0: mOwnsDC = true; michael@0: michael@0: #ifdef NS_PRINTING michael@0: if (flags & FLAG_FOR_PRINTING) { michael@0: Init(cairo_win32_printing_surface_create(mDC)); michael@0: mForPrinting = true; michael@0: } else michael@0: #endif michael@0: InitWithDC(flags); michael@0: } michael@0: michael@0: gfxWindowsSurface::gfxWindowsSurface(IDirect3DSurface9 *surface, uint32_t flags) : michael@0: mOwnsDC(false), mForPrinting(false), mDC(0), mWnd(nullptr) michael@0: { michael@0: cairo_surface_t *surf = cairo_win32_surface_create_with_d3dsurface9(surface); michael@0: Init(surf); michael@0: } michael@0: michael@0: michael@0: void michael@0: gfxWindowsSurface::MakeInvalid(gfxIntSize& size) michael@0: { michael@0: size = gfxIntSize(-1, -1); michael@0: } michael@0: michael@0: gfxWindowsSurface::gfxWindowsSurface(const gfxIntSize& realSize, gfxImageFormat imageFormat) : michael@0: mOwnsDC(false), mForPrinting(false), mWnd(nullptr) michael@0: { michael@0: gfxIntSize size(realSize); michael@0: if (!CheckSurfaceSize(size)) michael@0: MakeInvalid(size); michael@0: michael@0: cairo_surface_t *surf = cairo_win32_surface_create_with_dib((cairo_format_t)(int)imageFormat, michael@0: size.width, size.height); michael@0: michael@0: Init(surf); michael@0: michael@0: if (CairoStatus() == CAIRO_STATUS_SUCCESS) { michael@0: mDC = cairo_win32_surface_get_dc(CairoSurface()); michael@0: RecordMemoryUsed(size.width * size.height * 4 + sizeof(gfxWindowsSurface)); michael@0: } else { michael@0: mDC = nullptr; michael@0: } michael@0: } michael@0: michael@0: gfxWindowsSurface::gfxWindowsSurface(HDC dc, const gfxIntSize& realSize, gfxImageFormat imageFormat) : michael@0: mOwnsDC(false), mForPrinting(false), mWnd(nullptr) michael@0: { michael@0: gfxIntSize size(realSize); michael@0: if (!CheckSurfaceSize(size)) michael@0: MakeInvalid(size); michael@0: michael@0: cairo_surface_t *surf = cairo_win32_surface_create_with_ddb(dc, (cairo_format_t)(int)imageFormat, michael@0: size.width, size.height); michael@0: michael@0: Init(surf); michael@0: michael@0: if (mSurfaceValid) { michael@0: // DDBs will generally only use 3 bytes per pixel when RGB24 michael@0: int bytesPerPixel = ((imageFormat == gfxImageFormat::RGB24) ? 3 : 4); michael@0: RecordMemoryUsed(size.width * size.height * bytesPerPixel + sizeof(gfxWindowsSurface)); michael@0: } michael@0: michael@0: if (CairoStatus() == 0) michael@0: mDC = cairo_win32_surface_get_dc(CairoSurface()); michael@0: else michael@0: mDC = nullptr; michael@0: } michael@0: michael@0: gfxWindowsSurface::gfxWindowsSurface(cairo_surface_t *csurf) : michael@0: mOwnsDC(false), mForPrinting(false), mWnd(nullptr) michael@0: { michael@0: if (cairo_surface_status(csurf) == 0) michael@0: mDC = cairo_win32_surface_get_dc(csurf); michael@0: else michael@0: mDC = nullptr; michael@0: michael@0: if (cairo_surface_get_type(csurf) == CAIRO_SURFACE_TYPE_WIN32_PRINTING) michael@0: mForPrinting = true; michael@0: michael@0: Init(csurf, true); michael@0: } michael@0: michael@0: void michael@0: gfxWindowsSurface::InitWithDC(uint32_t flags) michael@0: { michael@0: if (flags & FLAG_IS_TRANSPARENT) { michael@0: Init(cairo_win32_surface_create_with_alpha(mDC)); michael@0: } else { michael@0: Init(cairo_win32_surface_create(mDC)); michael@0: } michael@0: } michael@0: michael@0: already_AddRefed michael@0: gfxWindowsSurface::CreateSimilarSurface(gfxContentType aContent, michael@0: const gfxIntSize& aSize) michael@0: { michael@0: if (!mSurface || !mSurfaceValid) { michael@0: return nullptr; michael@0: } michael@0: michael@0: cairo_surface_t *surface; michael@0: if (!mForPrinting && GetContentType() == gfxContentType::COLOR_ALPHA) { michael@0: // When creating a similar surface to a transparent surface, ensure michael@0: // the new surface uses a DIB. cairo_surface_create_similar won't michael@0: // use a DIB for a gfxContentType::COLOR surface if this surface doesn't michael@0: // have a DIB (e.g. if we're a transparent window surface). But michael@0: // we need a DIB to perform well if the new surface is composited into michael@0: // a surface that's the result of create_similar(gfxContentType::COLOR_ALPHA) michael@0: // (e.g. a backbuffer for the window) --- that new surface *would* michael@0: // have a DIB. michael@0: surface = michael@0: cairo_win32_surface_create_with_dib((cairo_format_t)(int)gfxPlatform::GetPlatform()->OptimalFormatForContent(aContent), michael@0: aSize.width, aSize.height); michael@0: } else { michael@0: surface = michael@0: cairo_surface_create_similar(mSurface, (cairo_content_t)(int)aContent, michael@0: aSize.width, aSize.height); michael@0: } michael@0: michael@0: if (cairo_surface_status(surface)) { michael@0: cairo_surface_destroy(surface); michael@0: return nullptr; michael@0: } michael@0: michael@0: nsRefPtr result = Wrap(surface, aSize); michael@0: cairo_surface_destroy(surface); michael@0: return result.forget(); michael@0: } michael@0: michael@0: gfxWindowsSurface::~gfxWindowsSurface() michael@0: { michael@0: if (mOwnsDC) { michael@0: if (mWnd) michael@0: ::ReleaseDC(mWnd, mDC); michael@0: else michael@0: ::DeleteDC(mDC); michael@0: } michael@0: } michael@0: michael@0: HDC michael@0: gfxWindowsSurface::GetDCWithClip(gfxContext *ctx) michael@0: { michael@0: return cairo_win32_get_dc_with_clip (ctx->GetCairo()); michael@0: } michael@0: michael@0: HDC michael@0: gfxWindowsSurface::GetDC() michael@0: { michael@0: return cairo_win32_surface_get_dc (CairoSurface()); michael@0: } michael@0: michael@0: michael@0: already_AddRefed michael@0: gfxWindowsSurface::GetAsImageSurface() michael@0: { michael@0: if (!mSurfaceValid) { michael@0: NS_WARNING ("GetImageSurface on an invalid (null) surface; who's calling this without checking for surface errors?"); michael@0: return nullptr; michael@0: } michael@0: michael@0: NS_ASSERTION(CairoSurface() != nullptr, "CairoSurface() shouldn't be nullptr when mSurfaceValid is TRUE!"); michael@0: michael@0: if (mForPrinting) michael@0: return nullptr; michael@0: michael@0: cairo_surface_t *isurf = cairo_win32_surface_get_image(CairoSurface()); michael@0: if (!isurf) michael@0: return nullptr; michael@0: michael@0: nsRefPtr result = gfxASurface::Wrap(isurf).downcast(); michael@0: result->SetOpaqueRect(GetOpaqueRect()); michael@0: michael@0: return result.forget(); michael@0: } michael@0: michael@0: nsresult michael@0: gfxWindowsSurface::BeginPrinting(const nsAString& aTitle, michael@0: const nsAString& aPrintToFileName) michael@0: { michael@0: #ifdef NS_PRINTING michael@0: #define DOC_TITLE_LENGTH (MAX_PATH-1) michael@0: DOCINFOW docinfo; michael@0: michael@0: nsString titleStr(aTitle); michael@0: if (titleStr.Length() > DOC_TITLE_LENGTH) { michael@0: titleStr.SetLength(DOC_TITLE_LENGTH-3); michael@0: titleStr.AppendLiteral("..."); michael@0: } michael@0: michael@0: nsString docName(aPrintToFileName); michael@0: docinfo.cbSize = sizeof(docinfo); michael@0: docinfo.lpszDocName = titleStr.Length() > 0 ? titleStr.get() : L"Mozilla Document"; michael@0: docinfo.lpszOutput = docName.Length() > 0 ? docName.get() : nullptr; michael@0: docinfo.lpszDatatype = nullptr; michael@0: docinfo.fwType = 0; michael@0: michael@0: ::StartDocW(mDC, &docinfo); michael@0: michael@0: return NS_OK; michael@0: #else michael@0: return NS_ERROR_FAILURE; michael@0: #endif michael@0: } michael@0: michael@0: nsresult michael@0: gfxWindowsSurface::EndPrinting() michael@0: { michael@0: #ifdef NS_PRINTING michael@0: int result = ::EndDoc(mDC); michael@0: if (result <= 0) michael@0: return NS_ERROR_FAILURE; michael@0: michael@0: return NS_OK; michael@0: #else michael@0: return NS_ERROR_FAILURE; michael@0: #endif michael@0: } michael@0: michael@0: nsresult michael@0: gfxWindowsSurface::AbortPrinting() michael@0: { michael@0: #ifdef NS_PRINTING michael@0: int result = ::AbortDoc(mDC); michael@0: if (result <= 0) michael@0: return NS_ERROR_FAILURE; michael@0: return NS_OK; michael@0: #else michael@0: return NS_ERROR_FAILURE; michael@0: #endif michael@0: } michael@0: michael@0: nsresult michael@0: gfxWindowsSurface::BeginPage() michael@0: { michael@0: #ifdef NS_PRINTING michael@0: int result = ::StartPage(mDC); michael@0: if (result <= 0) michael@0: return NS_ERROR_FAILURE; michael@0: return NS_OK; michael@0: #else michael@0: return NS_ERROR_FAILURE; michael@0: #endif michael@0: } michael@0: michael@0: nsresult michael@0: gfxWindowsSurface::EndPage() michael@0: { michael@0: #ifdef NS_PRINTING michael@0: if (mForPrinting) michael@0: cairo_surface_show_page(CairoSurface()); michael@0: int result = ::EndPage(mDC); michael@0: if (result <= 0) michael@0: return NS_ERROR_FAILURE; michael@0: return NS_OK; michael@0: #else michael@0: return NS_ERROR_FAILURE; michael@0: #endif michael@0: } michael@0: michael@0: int32_t michael@0: gfxWindowsSurface::GetDefaultContextFlags() const michael@0: { michael@0: if (mForPrinting) michael@0: return gfxContext::FLAG_SIMPLIFY_OPERATORS | michael@0: gfxContext::FLAG_DISABLE_SNAPPING | michael@0: gfxContext::FLAG_DISABLE_COPY_BACKGROUND; michael@0: michael@0: return 0; michael@0: } michael@0: michael@0: const gfxIntSize michael@0: gfxWindowsSurface::GetSize() const michael@0: { michael@0: if (!mSurfaceValid) { michael@0: NS_WARNING ("GetImageSurface on an invalid (null) surface; who's calling this without checking for surface errors?"); michael@0: return gfxIntSize(-1, -1); michael@0: } michael@0: michael@0: NS_ASSERTION(mSurface != nullptr, "CairoSurface() shouldn't be nullptr when mSurfaceValid is TRUE!"); michael@0: michael@0: return gfxIntSize(cairo_win32_surface_get_width(mSurface), michael@0: cairo_win32_surface_get_height(mSurface)); michael@0: } michael@0: michael@0: gfxMemoryLocation michael@0: gfxWindowsSurface::GetMemoryLocation() const michael@0: { michael@0: return gfxMemoryLocation::IN_PROCESS_NONHEAP; michael@0: }