Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
michael@0 | 1 | /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- |
michael@0 | 2 | * This Source Code Form is subject to the terms of the Mozilla Public |
michael@0 | 3 | * License, v. 2.0. If a copy of the MPL was not distributed with this |
michael@0 | 4 | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
michael@0 | 5 | |
michael@0 | 6 | #include "gfxWindowsSurface.h" |
michael@0 | 7 | #include "gfxContext.h" |
michael@0 | 8 | #include "gfxPlatform.h" |
michael@0 | 9 | |
michael@0 | 10 | #include "cairo.h" |
michael@0 | 11 | #include "cairo-win32.h" |
michael@0 | 12 | |
michael@0 | 13 | #include "nsString.h" |
michael@0 | 14 | |
michael@0 | 15 | gfxWindowsSurface::gfxWindowsSurface(HWND wnd, uint32_t flags) : |
michael@0 | 16 | mOwnsDC(true), mForPrinting(false), mWnd(wnd) |
michael@0 | 17 | { |
michael@0 | 18 | mDC = ::GetDC(mWnd); |
michael@0 | 19 | InitWithDC(flags); |
michael@0 | 20 | } |
michael@0 | 21 | |
michael@0 | 22 | gfxWindowsSurface::gfxWindowsSurface(HDC dc, uint32_t flags) : |
michael@0 | 23 | mOwnsDC(false), mForPrinting(false), mDC(dc), mWnd(nullptr) |
michael@0 | 24 | { |
michael@0 | 25 | if (flags & FLAG_TAKE_DC) |
michael@0 | 26 | mOwnsDC = true; |
michael@0 | 27 | |
michael@0 | 28 | #ifdef NS_PRINTING |
michael@0 | 29 | if (flags & FLAG_FOR_PRINTING) { |
michael@0 | 30 | Init(cairo_win32_printing_surface_create(mDC)); |
michael@0 | 31 | mForPrinting = true; |
michael@0 | 32 | } else |
michael@0 | 33 | #endif |
michael@0 | 34 | InitWithDC(flags); |
michael@0 | 35 | } |
michael@0 | 36 | |
michael@0 | 37 | gfxWindowsSurface::gfxWindowsSurface(IDirect3DSurface9 *surface, uint32_t flags) : |
michael@0 | 38 | mOwnsDC(false), mForPrinting(false), mDC(0), mWnd(nullptr) |
michael@0 | 39 | { |
michael@0 | 40 | cairo_surface_t *surf = cairo_win32_surface_create_with_d3dsurface9(surface); |
michael@0 | 41 | Init(surf); |
michael@0 | 42 | } |
michael@0 | 43 | |
michael@0 | 44 | |
michael@0 | 45 | void |
michael@0 | 46 | gfxWindowsSurface::MakeInvalid(gfxIntSize& size) |
michael@0 | 47 | { |
michael@0 | 48 | size = gfxIntSize(-1, -1); |
michael@0 | 49 | } |
michael@0 | 50 | |
michael@0 | 51 | gfxWindowsSurface::gfxWindowsSurface(const gfxIntSize& realSize, gfxImageFormat imageFormat) : |
michael@0 | 52 | mOwnsDC(false), mForPrinting(false), mWnd(nullptr) |
michael@0 | 53 | { |
michael@0 | 54 | gfxIntSize size(realSize); |
michael@0 | 55 | if (!CheckSurfaceSize(size)) |
michael@0 | 56 | MakeInvalid(size); |
michael@0 | 57 | |
michael@0 | 58 | cairo_surface_t *surf = cairo_win32_surface_create_with_dib((cairo_format_t)(int)imageFormat, |
michael@0 | 59 | size.width, size.height); |
michael@0 | 60 | |
michael@0 | 61 | Init(surf); |
michael@0 | 62 | |
michael@0 | 63 | if (CairoStatus() == CAIRO_STATUS_SUCCESS) { |
michael@0 | 64 | mDC = cairo_win32_surface_get_dc(CairoSurface()); |
michael@0 | 65 | RecordMemoryUsed(size.width * size.height * 4 + sizeof(gfxWindowsSurface)); |
michael@0 | 66 | } else { |
michael@0 | 67 | mDC = nullptr; |
michael@0 | 68 | } |
michael@0 | 69 | } |
michael@0 | 70 | |
michael@0 | 71 | gfxWindowsSurface::gfxWindowsSurface(HDC dc, const gfxIntSize& realSize, gfxImageFormat imageFormat) : |
michael@0 | 72 | mOwnsDC(false), mForPrinting(false), mWnd(nullptr) |
michael@0 | 73 | { |
michael@0 | 74 | gfxIntSize size(realSize); |
michael@0 | 75 | if (!CheckSurfaceSize(size)) |
michael@0 | 76 | MakeInvalid(size); |
michael@0 | 77 | |
michael@0 | 78 | cairo_surface_t *surf = cairo_win32_surface_create_with_ddb(dc, (cairo_format_t)(int)imageFormat, |
michael@0 | 79 | size.width, size.height); |
michael@0 | 80 | |
michael@0 | 81 | Init(surf); |
michael@0 | 82 | |
michael@0 | 83 | if (mSurfaceValid) { |
michael@0 | 84 | // DDBs will generally only use 3 bytes per pixel when RGB24 |
michael@0 | 85 | int bytesPerPixel = ((imageFormat == gfxImageFormat::RGB24) ? 3 : 4); |
michael@0 | 86 | RecordMemoryUsed(size.width * size.height * bytesPerPixel + sizeof(gfxWindowsSurface)); |
michael@0 | 87 | } |
michael@0 | 88 | |
michael@0 | 89 | if (CairoStatus() == 0) |
michael@0 | 90 | mDC = cairo_win32_surface_get_dc(CairoSurface()); |
michael@0 | 91 | else |
michael@0 | 92 | mDC = nullptr; |
michael@0 | 93 | } |
michael@0 | 94 | |
michael@0 | 95 | gfxWindowsSurface::gfxWindowsSurface(cairo_surface_t *csurf) : |
michael@0 | 96 | mOwnsDC(false), mForPrinting(false), mWnd(nullptr) |
michael@0 | 97 | { |
michael@0 | 98 | if (cairo_surface_status(csurf) == 0) |
michael@0 | 99 | mDC = cairo_win32_surface_get_dc(csurf); |
michael@0 | 100 | else |
michael@0 | 101 | mDC = nullptr; |
michael@0 | 102 | |
michael@0 | 103 | if (cairo_surface_get_type(csurf) == CAIRO_SURFACE_TYPE_WIN32_PRINTING) |
michael@0 | 104 | mForPrinting = true; |
michael@0 | 105 | |
michael@0 | 106 | Init(csurf, true); |
michael@0 | 107 | } |
michael@0 | 108 | |
michael@0 | 109 | void |
michael@0 | 110 | gfxWindowsSurface::InitWithDC(uint32_t flags) |
michael@0 | 111 | { |
michael@0 | 112 | if (flags & FLAG_IS_TRANSPARENT) { |
michael@0 | 113 | Init(cairo_win32_surface_create_with_alpha(mDC)); |
michael@0 | 114 | } else { |
michael@0 | 115 | Init(cairo_win32_surface_create(mDC)); |
michael@0 | 116 | } |
michael@0 | 117 | } |
michael@0 | 118 | |
michael@0 | 119 | already_AddRefed<gfxASurface> |
michael@0 | 120 | gfxWindowsSurface::CreateSimilarSurface(gfxContentType aContent, |
michael@0 | 121 | const gfxIntSize& aSize) |
michael@0 | 122 | { |
michael@0 | 123 | if (!mSurface || !mSurfaceValid) { |
michael@0 | 124 | return nullptr; |
michael@0 | 125 | } |
michael@0 | 126 | |
michael@0 | 127 | cairo_surface_t *surface; |
michael@0 | 128 | if (!mForPrinting && GetContentType() == gfxContentType::COLOR_ALPHA) { |
michael@0 | 129 | // When creating a similar surface to a transparent surface, ensure |
michael@0 | 130 | // the new surface uses a DIB. cairo_surface_create_similar won't |
michael@0 | 131 | // use a DIB for a gfxContentType::COLOR surface if this surface doesn't |
michael@0 | 132 | // have a DIB (e.g. if we're a transparent window surface). But |
michael@0 | 133 | // we need a DIB to perform well if the new surface is composited into |
michael@0 | 134 | // a surface that's the result of create_similar(gfxContentType::COLOR_ALPHA) |
michael@0 | 135 | // (e.g. a backbuffer for the window) --- that new surface *would* |
michael@0 | 136 | // have a DIB. |
michael@0 | 137 | surface = |
michael@0 | 138 | cairo_win32_surface_create_with_dib((cairo_format_t)(int)gfxPlatform::GetPlatform()->OptimalFormatForContent(aContent), |
michael@0 | 139 | aSize.width, aSize.height); |
michael@0 | 140 | } else { |
michael@0 | 141 | surface = |
michael@0 | 142 | cairo_surface_create_similar(mSurface, (cairo_content_t)(int)aContent, |
michael@0 | 143 | aSize.width, aSize.height); |
michael@0 | 144 | } |
michael@0 | 145 | |
michael@0 | 146 | if (cairo_surface_status(surface)) { |
michael@0 | 147 | cairo_surface_destroy(surface); |
michael@0 | 148 | return nullptr; |
michael@0 | 149 | } |
michael@0 | 150 | |
michael@0 | 151 | nsRefPtr<gfxASurface> result = Wrap(surface, aSize); |
michael@0 | 152 | cairo_surface_destroy(surface); |
michael@0 | 153 | return result.forget(); |
michael@0 | 154 | } |
michael@0 | 155 | |
michael@0 | 156 | gfxWindowsSurface::~gfxWindowsSurface() |
michael@0 | 157 | { |
michael@0 | 158 | if (mOwnsDC) { |
michael@0 | 159 | if (mWnd) |
michael@0 | 160 | ::ReleaseDC(mWnd, mDC); |
michael@0 | 161 | else |
michael@0 | 162 | ::DeleteDC(mDC); |
michael@0 | 163 | } |
michael@0 | 164 | } |
michael@0 | 165 | |
michael@0 | 166 | HDC |
michael@0 | 167 | gfxWindowsSurface::GetDCWithClip(gfxContext *ctx) |
michael@0 | 168 | { |
michael@0 | 169 | return cairo_win32_get_dc_with_clip (ctx->GetCairo()); |
michael@0 | 170 | } |
michael@0 | 171 | |
michael@0 | 172 | HDC |
michael@0 | 173 | gfxWindowsSurface::GetDC() |
michael@0 | 174 | { |
michael@0 | 175 | return cairo_win32_surface_get_dc (CairoSurface()); |
michael@0 | 176 | } |
michael@0 | 177 | |
michael@0 | 178 | |
michael@0 | 179 | already_AddRefed<gfxImageSurface> |
michael@0 | 180 | gfxWindowsSurface::GetAsImageSurface() |
michael@0 | 181 | { |
michael@0 | 182 | if (!mSurfaceValid) { |
michael@0 | 183 | NS_WARNING ("GetImageSurface on an invalid (null) surface; who's calling this without checking for surface errors?"); |
michael@0 | 184 | return nullptr; |
michael@0 | 185 | } |
michael@0 | 186 | |
michael@0 | 187 | NS_ASSERTION(CairoSurface() != nullptr, "CairoSurface() shouldn't be nullptr when mSurfaceValid is TRUE!"); |
michael@0 | 188 | |
michael@0 | 189 | if (mForPrinting) |
michael@0 | 190 | return nullptr; |
michael@0 | 191 | |
michael@0 | 192 | cairo_surface_t *isurf = cairo_win32_surface_get_image(CairoSurface()); |
michael@0 | 193 | if (!isurf) |
michael@0 | 194 | return nullptr; |
michael@0 | 195 | |
michael@0 | 196 | nsRefPtr<gfxImageSurface> result = gfxASurface::Wrap(isurf).downcast<gfxImageSurface>(); |
michael@0 | 197 | result->SetOpaqueRect(GetOpaqueRect()); |
michael@0 | 198 | |
michael@0 | 199 | return result.forget(); |
michael@0 | 200 | } |
michael@0 | 201 | |
michael@0 | 202 | nsresult |
michael@0 | 203 | gfxWindowsSurface::BeginPrinting(const nsAString& aTitle, |
michael@0 | 204 | const nsAString& aPrintToFileName) |
michael@0 | 205 | { |
michael@0 | 206 | #ifdef NS_PRINTING |
michael@0 | 207 | #define DOC_TITLE_LENGTH (MAX_PATH-1) |
michael@0 | 208 | DOCINFOW docinfo; |
michael@0 | 209 | |
michael@0 | 210 | nsString titleStr(aTitle); |
michael@0 | 211 | if (titleStr.Length() > DOC_TITLE_LENGTH) { |
michael@0 | 212 | titleStr.SetLength(DOC_TITLE_LENGTH-3); |
michael@0 | 213 | titleStr.AppendLiteral("..."); |
michael@0 | 214 | } |
michael@0 | 215 | |
michael@0 | 216 | nsString docName(aPrintToFileName); |
michael@0 | 217 | docinfo.cbSize = sizeof(docinfo); |
michael@0 | 218 | docinfo.lpszDocName = titleStr.Length() > 0 ? titleStr.get() : L"Mozilla Document"; |
michael@0 | 219 | docinfo.lpszOutput = docName.Length() > 0 ? docName.get() : nullptr; |
michael@0 | 220 | docinfo.lpszDatatype = nullptr; |
michael@0 | 221 | docinfo.fwType = 0; |
michael@0 | 222 | |
michael@0 | 223 | ::StartDocW(mDC, &docinfo); |
michael@0 | 224 | |
michael@0 | 225 | return NS_OK; |
michael@0 | 226 | #else |
michael@0 | 227 | return NS_ERROR_FAILURE; |
michael@0 | 228 | #endif |
michael@0 | 229 | } |
michael@0 | 230 | |
michael@0 | 231 | nsresult |
michael@0 | 232 | gfxWindowsSurface::EndPrinting() |
michael@0 | 233 | { |
michael@0 | 234 | #ifdef NS_PRINTING |
michael@0 | 235 | int result = ::EndDoc(mDC); |
michael@0 | 236 | if (result <= 0) |
michael@0 | 237 | return NS_ERROR_FAILURE; |
michael@0 | 238 | |
michael@0 | 239 | return NS_OK; |
michael@0 | 240 | #else |
michael@0 | 241 | return NS_ERROR_FAILURE; |
michael@0 | 242 | #endif |
michael@0 | 243 | } |
michael@0 | 244 | |
michael@0 | 245 | nsresult |
michael@0 | 246 | gfxWindowsSurface::AbortPrinting() |
michael@0 | 247 | { |
michael@0 | 248 | #ifdef NS_PRINTING |
michael@0 | 249 | int result = ::AbortDoc(mDC); |
michael@0 | 250 | if (result <= 0) |
michael@0 | 251 | return NS_ERROR_FAILURE; |
michael@0 | 252 | return NS_OK; |
michael@0 | 253 | #else |
michael@0 | 254 | return NS_ERROR_FAILURE; |
michael@0 | 255 | #endif |
michael@0 | 256 | } |
michael@0 | 257 | |
michael@0 | 258 | nsresult |
michael@0 | 259 | gfxWindowsSurface::BeginPage() |
michael@0 | 260 | { |
michael@0 | 261 | #ifdef NS_PRINTING |
michael@0 | 262 | int result = ::StartPage(mDC); |
michael@0 | 263 | if (result <= 0) |
michael@0 | 264 | return NS_ERROR_FAILURE; |
michael@0 | 265 | return NS_OK; |
michael@0 | 266 | #else |
michael@0 | 267 | return NS_ERROR_FAILURE; |
michael@0 | 268 | #endif |
michael@0 | 269 | } |
michael@0 | 270 | |
michael@0 | 271 | nsresult |
michael@0 | 272 | gfxWindowsSurface::EndPage() |
michael@0 | 273 | { |
michael@0 | 274 | #ifdef NS_PRINTING |
michael@0 | 275 | if (mForPrinting) |
michael@0 | 276 | cairo_surface_show_page(CairoSurface()); |
michael@0 | 277 | int result = ::EndPage(mDC); |
michael@0 | 278 | if (result <= 0) |
michael@0 | 279 | return NS_ERROR_FAILURE; |
michael@0 | 280 | return NS_OK; |
michael@0 | 281 | #else |
michael@0 | 282 | return NS_ERROR_FAILURE; |
michael@0 | 283 | #endif |
michael@0 | 284 | } |
michael@0 | 285 | |
michael@0 | 286 | int32_t |
michael@0 | 287 | gfxWindowsSurface::GetDefaultContextFlags() const |
michael@0 | 288 | { |
michael@0 | 289 | if (mForPrinting) |
michael@0 | 290 | return gfxContext::FLAG_SIMPLIFY_OPERATORS | |
michael@0 | 291 | gfxContext::FLAG_DISABLE_SNAPPING | |
michael@0 | 292 | gfxContext::FLAG_DISABLE_COPY_BACKGROUND; |
michael@0 | 293 | |
michael@0 | 294 | return 0; |
michael@0 | 295 | } |
michael@0 | 296 | |
michael@0 | 297 | const gfxIntSize |
michael@0 | 298 | gfxWindowsSurface::GetSize() const |
michael@0 | 299 | { |
michael@0 | 300 | if (!mSurfaceValid) { |
michael@0 | 301 | NS_WARNING ("GetImageSurface on an invalid (null) surface; who's calling this without checking for surface errors?"); |
michael@0 | 302 | return gfxIntSize(-1, -1); |
michael@0 | 303 | } |
michael@0 | 304 | |
michael@0 | 305 | NS_ASSERTION(mSurface != nullptr, "CairoSurface() shouldn't be nullptr when mSurfaceValid is TRUE!"); |
michael@0 | 306 | |
michael@0 | 307 | return gfxIntSize(cairo_win32_surface_get_width(mSurface), |
michael@0 | 308 | cairo_win32_surface_get_height(mSurface)); |
michael@0 | 309 | } |
michael@0 | 310 | |
michael@0 | 311 | gfxMemoryLocation |
michael@0 | 312 | gfxWindowsSurface::GetMemoryLocation() const |
michael@0 | 313 | { |
michael@0 | 314 | return gfxMemoryLocation::IN_PROCESS_NONHEAP; |
michael@0 | 315 | } |