1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/gfx/src/nsDeviceContext.cpp Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,738 @@ 1.4 +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.8 + 1.9 +#include "nsDeviceContext.h" 1.10 +#include <algorithm> // for max 1.11 +#include "gfxASurface.h" // for gfxASurface, etc 1.12 +#include "gfxFont.h" // for gfxFontGroup 1.13 +#include "gfxImageSurface.h" // for gfxImageSurface 1.14 +#include "gfxPoint.h" // for gfxSize 1.15 +#include "mozilla/Attributes.h" // for MOZ_FINAL 1.16 +#include "mozilla/Preferences.h" // for Preferences 1.17 +#include "mozilla/Services.h" // for GetObserverService 1.18 +#include "mozilla/mozalloc.h" // for operator new 1.19 +#include "nsCRT.h" // for nsCRT 1.20 +#include "nsDebug.h" // for NS_NOTREACHED, NS_ASSERTION, etc 1.21 +#include "nsFont.h" // for nsFont 1.22 +#include "nsFontMetrics.h" // for nsFontMetrics 1.23 +#include "nsIAtom.h" // for nsIAtom, do_GetAtom 1.24 +#include "nsID.h" 1.25 +#include "nsIDeviceContextSpec.h" // for nsIDeviceContextSpec 1.26 +#include "nsILanguageAtomService.h" // for nsILanguageAtomService, etc 1.27 +#include "nsIObserver.h" // for nsIObserver, etc 1.28 +#include "nsIObserverService.h" // for nsIObserverService 1.29 +#include "nsIScreen.h" // for nsIScreen 1.30 +#include "nsIScreenManager.h" // for nsIScreenManager 1.31 +#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc 1.32 +#include "nsISupportsUtils.h" // for NS_ADDREF, NS_RELEASE 1.33 +#include "nsIWidget.h" // for nsIWidget, NS_NATIVE_WINDOW 1.34 +#include "nsRect.h" // for nsRect 1.35 +#include "nsRenderingContext.h" // for nsRenderingContext 1.36 +#include "nsServiceManagerUtils.h" // for do_GetService 1.37 +#include "nsString.h" // for nsDependentString 1.38 +#include "nsTArray.h" // for nsTArray, nsTArray_Impl 1.39 +#include "nsThreadUtils.h" // for NS_IsMainThread 1.40 + 1.41 +#if !XP_MACOSX 1.42 +#include "gfxPDFSurface.h" 1.43 +#endif 1.44 + 1.45 +#ifdef MOZ_WIDGET_GTK 1.46 +#include "gfxPSSurface.h" 1.47 +#elif XP_WIN 1.48 +#include "gfxWindowsSurface.h" 1.49 +#elif XP_MACOSX 1.50 +#include "gfxQuartzSurface.h" 1.51 +#endif 1.52 + 1.53 +using namespace mozilla; 1.54 +using mozilla::services::GetObserverService; 1.55 + 1.56 +class nsFontCache MOZ_FINAL : public nsIObserver 1.57 +{ 1.58 +public: 1.59 + nsFontCache() { MOZ_COUNT_CTOR(nsFontCache); } 1.60 + ~nsFontCache() { MOZ_COUNT_DTOR(nsFontCache); } 1.61 + 1.62 + NS_DECL_ISUPPORTS 1.63 + NS_DECL_NSIOBSERVER 1.64 + 1.65 + void Init(nsDeviceContext* aContext); 1.66 + void Destroy(); 1.67 + 1.68 + nsresult GetMetricsFor(const nsFont& aFont, nsIAtom* aLanguage, 1.69 + gfxUserFontSet* aUserFontSet, 1.70 + gfxTextPerfMetrics* aTextPerf, 1.71 + nsFontMetrics*& aMetrics); 1.72 + 1.73 + void FontMetricsDeleted(const nsFontMetrics* aFontMetrics); 1.74 + void Compact(); 1.75 + void Flush(); 1.76 + 1.77 +protected: 1.78 + nsDeviceContext* mContext; // owner 1.79 + nsCOMPtr<nsIAtom> mLocaleLanguage; 1.80 + nsTArray<nsFontMetrics*> mFontMetrics; 1.81 +}; 1.82 + 1.83 +NS_IMPL_ISUPPORTS(nsFontCache, nsIObserver) 1.84 + 1.85 +// The Init and Destroy methods are necessary because it's not 1.86 +// safe to call AddObserver from a constructor or RemoveObserver 1.87 +// from a destructor. That should be fixed. 1.88 +void 1.89 +nsFontCache::Init(nsDeviceContext* aContext) 1.90 +{ 1.91 + mContext = aContext; 1.92 + // register as a memory-pressure observer to free font resources 1.93 + // in low-memory situations. 1.94 + nsCOMPtr<nsIObserverService> obs = GetObserverService(); 1.95 + if (obs) 1.96 + obs->AddObserver(this, "memory-pressure", false); 1.97 + 1.98 + nsCOMPtr<nsILanguageAtomService> langService; 1.99 + langService = do_GetService(NS_LANGUAGEATOMSERVICE_CONTRACTID); 1.100 + if (langService) { 1.101 + mLocaleLanguage = langService->GetLocaleLanguage(); 1.102 + } 1.103 + if (!mLocaleLanguage) { 1.104 + mLocaleLanguage = do_GetAtom("x-western"); 1.105 + } 1.106 +} 1.107 + 1.108 +void 1.109 +nsFontCache::Destroy() 1.110 +{ 1.111 + nsCOMPtr<nsIObserverService> obs = GetObserverService(); 1.112 + if (obs) 1.113 + obs->RemoveObserver(this, "memory-pressure"); 1.114 + Flush(); 1.115 +} 1.116 + 1.117 +NS_IMETHODIMP 1.118 +nsFontCache::Observe(nsISupports*, const char* aTopic, const char16_t*) 1.119 +{ 1.120 + if (!nsCRT::strcmp(aTopic, "memory-pressure")) 1.121 + Compact(); 1.122 + return NS_OK; 1.123 +} 1.124 + 1.125 +nsresult 1.126 +nsFontCache::GetMetricsFor(const nsFont& aFont, nsIAtom* aLanguage, 1.127 + gfxUserFontSet* aUserFontSet, 1.128 + gfxTextPerfMetrics* aTextPerf, 1.129 + nsFontMetrics*& aMetrics) 1.130 +{ 1.131 + if (!aLanguage) 1.132 + aLanguage = mLocaleLanguage; 1.133 + 1.134 + // First check our cache 1.135 + // start from the end, which is where we put the most-recent-used element 1.136 + 1.137 + nsFontMetrics* fm; 1.138 + int32_t n = mFontMetrics.Length() - 1; 1.139 + for (int32_t i = n; i >= 0; --i) { 1.140 + fm = mFontMetrics[i]; 1.141 + if (fm->Font().Equals(aFont) && fm->GetUserFontSet() == aUserFontSet && 1.142 + fm->Language() == aLanguage) { 1.143 + if (i != n) { 1.144 + // promote it to the end of the cache 1.145 + mFontMetrics.RemoveElementAt(i); 1.146 + mFontMetrics.AppendElement(fm); 1.147 + } 1.148 + fm->GetThebesFontGroup()->UpdateFontList(); 1.149 + NS_ADDREF(aMetrics = fm); 1.150 + return NS_OK; 1.151 + } 1.152 + } 1.153 + 1.154 + // It's not in the cache. Get font metrics and then cache them. 1.155 + 1.156 + fm = new nsFontMetrics(); 1.157 + NS_ADDREF(fm); 1.158 + nsresult rv = fm->Init(aFont, aLanguage, mContext, aUserFontSet, aTextPerf); 1.159 + if (NS_SUCCEEDED(rv)) { 1.160 + // the mFontMetrics list has the "head" at the end, because append 1.161 + // is cheaper than insert 1.162 + mFontMetrics.AppendElement(fm); 1.163 + aMetrics = fm; 1.164 + NS_ADDREF(aMetrics); 1.165 + return NS_OK; 1.166 + } 1.167 + fm->Destroy(); 1.168 + NS_RELEASE(fm); 1.169 + 1.170 + // One reason why Init() fails is because the system is running out of 1.171 + // resources. e.g., on Win95/98 only a very limited number of GDI 1.172 + // objects are available. Compact the cache and try again. 1.173 + 1.174 + Compact(); 1.175 + fm = new nsFontMetrics(); 1.176 + NS_ADDREF(fm); 1.177 + rv = fm->Init(aFont, aLanguage, mContext, aUserFontSet, aTextPerf); 1.178 + if (NS_SUCCEEDED(rv)) { 1.179 + mFontMetrics.AppendElement(fm); 1.180 + aMetrics = fm; 1.181 + return NS_OK; 1.182 + } 1.183 + fm->Destroy(); 1.184 + NS_RELEASE(fm); 1.185 + 1.186 + // could not setup a new one, send an old one (XXX search a "best 1.187 + // match"?) 1.188 + 1.189 + n = mFontMetrics.Length() - 1; // could have changed in Compact() 1.190 + if (n >= 0) { 1.191 + aMetrics = mFontMetrics[n]; 1.192 + NS_ADDREF(aMetrics); 1.193 + return NS_OK; 1.194 + } 1.195 + 1.196 + NS_POSTCONDITION(NS_SUCCEEDED(rv), 1.197 + "font metrics should not be null - bug 136248"); 1.198 + return rv; 1.199 +} 1.200 + 1.201 +void 1.202 +nsFontCache::FontMetricsDeleted(const nsFontMetrics* aFontMetrics) 1.203 +{ 1.204 + mFontMetrics.RemoveElement(aFontMetrics); 1.205 +} 1.206 + 1.207 +void 1.208 +nsFontCache::Compact() 1.209 +{ 1.210 + // Need to loop backward because the running element can be removed on 1.211 + // the way 1.212 + for (int32_t i = mFontMetrics.Length()-1; i >= 0; --i) { 1.213 + nsFontMetrics* fm = mFontMetrics[i]; 1.214 + nsFontMetrics* oldfm = fm; 1.215 + // Destroy() isn't here because we want our device context to be 1.216 + // notified 1.217 + NS_RELEASE(fm); // this will reset fm to nullptr 1.218 + // if the font is really gone, it would have called back in 1.219 + // FontMetricsDeleted() and would have removed itself 1.220 + if (mFontMetrics.IndexOf(oldfm) != mFontMetrics.NoIndex) { 1.221 + // nope, the font is still there, so let's hold onto it too 1.222 + NS_ADDREF(oldfm); 1.223 + } 1.224 + } 1.225 +} 1.226 + 1.227 +void 1.228 +nsFontCache::Flush() 1.229 +{ 1.230 + for (int32_t i = mFontMetrics.Length()-1; i >= 0; --i) { 1.231 + nsFontMetrics* fm = mFontMetrics[i]; 1.232 + // Destroy() will unhook our device context from the fm so that we 1.233 + // won't waste time in triggering the notification of 1.234 + // FontMetricsDeleted() in the subsequent release 1.235 + fm->Destroy(); 1.236 + NS_RELEASE(fm); 1.237 + } 1.238 + mFontMetrics.Clear(); 1.239 +} 1.240 + 1.241 +nsDeviceContext::nsDeviceContext() 1.242 + : mWidth(0), mHeight(0), mDepth(0), 1.243 + mAppUnitsPerDevPixel(-1), mAppUnitsPerDevNotScaledPixel(-1), 1.244 + mAppUnitsPerPhysicalInch(-1), 1.245 + mPixelScale(1.0f), mPrintingScale(1.0f), 1.246 + mFontCache(nullptr) 1.247 +{ 1.248 + MOZ_ASSERT(NS_IsMainThread(), "nsDeviceContext created off main thread"); 1.249 +} 1.250 + 1.251 +// Note: we use a bare pointer for mFontCache so that nsFontCache 1.252 +// can be an incomplete type in nsDeviceContext.h. 1.253 +// Therefore we have to do all the refcounting by hand. 1.254 +nsDeviceContext::~nsDeviceContext() 1.255 +{ 1.256 + if (mFontCache) { 1.257 + mFontCache->Destroy(); 1.258 + NS_RELEASE(mFontCache); 1.259 + } 1.260 +} 1.261 + 1.262 +nsresult 1.263 +nsDeviceContext::GetMetricsFor(const nsFont& aFont, 1.264 + nsIAtom* aLanguage, 1.265 + gfxUserFontSet* aUserFontSet, 1.266 + gfxTextPerfMetrics* aTextPerf, 1.267 + nsFontMetrics*& aMetrics) 1.268 +{ 1.269 + if (!mFontCache) { 1.270 + mFontCache = new nsFontCache(); 1.271 + NS_ADDREF(mFontCache); 1.272 + mFontCache->Init(this); 1.273 + } 1.274 + 1.275 + return mFontCache->GetMetricsFor(aFont, aLanguage, aUserFontSet, 1.276 + aTextPerf, aMetrics); 1.277 +} 1.278 + 1.279 +nsresult 1.280 +nsDeviceContext::FlushFontCache(void) 1.281 +{ 1.282 + if (mFontCache) 1.283 + mFontCache->Flush(); 1.284 + return NS_OK; 1.285 +} 1.286 + 1.287 +nsresult 1.288 +nsDeviceContext::FontMetricsDeleted(const nsFontMetrics* aFontMetrics) 1.289 +{ 1.290 + if (mFontCache) { 1.291 + mFontCache->FontMetricsDeleted(aFontMetrics); 1.292 + } 1.293 + return NS_OK; 1.294 +} 1.295 + 1.296 +bool 1.297 +nsDeviceContext::IsPrinterSurface() 1.298 +{ 1.299 + return mPrintingSurface != nullptr; 1.300 +} 1.301 + 1.302 +void 1.303 +nsDeviceContext::SetDPI() 1.304 +{ 1.305 + float dpi = -1.0f; 1.306 + 1.307 + // PostScript, PDF and Mac (when printing) all use 72 dpi 1.308 + // Use a printing DC to determine the other dpi values 1.309 + if (mPrintingSurface) { 1.310 + switch (mPrintingSurface->GetType()) { 1.311 + case gfxSurfaceType::PDF: 1.312 + case gfxSurfaceType::PS: 1.313 + case gfxSurfaceType::Quartz: 1.314 + dpi = 72.0f; 1.315 + break; 1.316 +#ifdef XP_WIN 1.317 + case gfxSurfaceType::Win32: 1.318 + case gfxSurfaceType::Win32Printing: { 1.319 + HDC dc = reinterpret_cast<gfxWindowsSurface*>(mPrintingSurface.get())->GetDC(); 1.320 + int32_t OSVal = GetDeviceCaps(dc, LOGPIXELSY); 1.321 + dpi = 144.0f; 1.322 + mPrintingScale = float(OSVal) / dpi; 1.323 + break; 1.324 + } 1.325 +#endif 1.326 + default: 1.327 + NS_NOTREACHED("Unexpected printing surface type"); 1.328 + break; 1.329 + } 1.330 + 1.331 + mAppUnitsPerDevNotScaledPixel = 1.332 + NS_lround((AppUnitsPerCSSPixel() * 96) / dpi); 1.333 + } else { 1.334 + // A value of -1 means use the maximum of 96 and the system DPI. 1.335 + // A value of 0 means use the system DPI. A positive value is used as the DPI. 1.336 + // This sets the physical size of a device pixel and thus controls the 1.337 + // interpretation of physical units. 1.338 + int32_t prefDPI = Preferences::GetInt("layout.css.dpi", -1); 1.339 + 1.340 + if (prefDPI > 0) { 1.341 + dpi = prefDPI; 1.342 + } else if (mWidget) { 1.343 + dpi = mWidget->GetDPI(); 1.344 + 1.345 + if (prefDPI < 0) { 1.346 + dpi = std::max(96.0f, dpi); 1.347 + } 1.348 + } else { 1.349 + dpi = 96.0f; 1.350 + } 1.351 + 1.352 + CSSToLayoutDeviceScale scale = mWidget ? mWidget->GetDefaultScale() 1.353 + : CSSToLayoutDeviceScale(1.0); 1.354 + double devPixelsPerCSSPixel = scale.scale; 1.355 + 1.356 + mAppUnitsPerDevNotScaledPixel = 1.357 + std::max(1, NS_lround(AppUnitsPerCSSPixel() / devPixelsPerCSSPixel)); 1.358 + } 1.359 + 1.360 + NS_ASSERTION(dpi != -1.0, "no dpi set"); 1.361 + 1.362 + mAppUnitsPerPhysicalInch = NS_lround(dpi * mAppUnitsPerDevNotScaledPixel); 1.363 + UpdateScaledAppUnits(); 1.364 +} 1.365 + 1.366 +nsresult 1.367 +nsDeviceContext::Init(nsIWidget *aWidget) 1.368 +{ 1.369 + if (mScreenManager && mWidget == aWidget) 1.370 + return NS_OK; 1.371 + 1.372 + mWidget = aWidget; 1.373 + SetDPI(); 1.374 + 1.375 + if (mScreenManager) 1.376 + return NS_OK; 1.377 + 1.378 + mScreenManager = do_GetService("@mozilla.org/gfx/screenmanager;1"); 1.379 + 1.380 + return NS_OK; 1.381 +} 1.382 + 1.383 +already_AddRefed<nsRenderingContext> 1.384 +nsDeviceContext::CreateRenderingContext() 1.385 +{ 1.386 + nsRefPtr<gfxASurface> printingSurface = mPrintingSurface; 1.387 +#ifdef XP_MACOSX 1.388 + // CreateRenderingContext() can be called (on reflow) after EndPage() 1.389 + // but before BeginPage(). On OS X (and only there) mPrintingSurface 1.390 + // will in this case be null, because OS X printing surfaces are 1.391 + // per-page, and therefore only truly valid between calls to BeginPage() 1.392 + // and EndPage(). But we can get away with fudging things here, if need 1.393 + // be, by using a cached copy. 1.394 + if (!printingSurface) { 1.395 + printingSurface = mCachedPrintingSurface; 1.396 + } 1.397 +#endif 1.398 + nsRefPtr<nsRenderingContext> pContext = new nsRenderingContext(); 1.399 + 1.400 + RefPtr<gfx::DrawTarget> dt = 1.401 + gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(printingSurface, 1.402 + gfx::IntSize(mWidth, mHeight)); 1.403 + 1.404 + pContext->Init(this, dt); 1.405 + pContext->ThebesContext()->SetFlag(gfxContext::FLAG_DISABLE_SNAPPING); 1.406 + pContext->Scale(mPrintingScale, mPrintingScale); 1.407 + 1.408 + return pContext.forget(); 1.409 +} 1.410 + 1.411 +nsresult 1.412 +nsDeviceContext::GetDepth(uint32_t& aDepth) 1.413 +{ 1.414 + if (mDepth == 0) { 1.415 + nsCOMPtr<nsIScreen> primaryScreen; 1.416 + mScreenManager->GetPrimaryScreen(getter_AddRefs(primaryScreen)); 1.417 + primaryScreen->GetColorDepth(reinterpret_cast<int32_t *>(&mDepth)); 1.418 + } 1.419 + 1.420 + aDepth = mDepth; 1.421 + return NS_OK; 1.422 +} 1.423 + 1.424 +nsresult 1.425 +nsDeviceContext::GetDeviceSurfaceDimensions(nscoord &aWidth, nscoord &aHeight) 1.426 +{ 1.427 + if (mPrintingSurface) { 1.428 + // we have a printer device 1.429 + aWidth = mWidth; 1.430 + aHeight = mHeight; 1.431 + } else { 1.432 + nsRect area; 1.433 + ComputeFullAreaUsingScreen(&area); 1.434 + aWidth = area.width; 1.435 + aHeight = area.height; 1.436 + } 1.437 + 1.438 + return NS_OK; 1.439 +} 1.440 + 1.441 +nsresult 1.442 +nsDeviceContext::GetRect(nsRect &aRect) 1.443 +{ 1.444 + if (mPrintingSurface) { 1.445 + // we have a printer device 1.446 + aRect.x = 0; 1.447 + aRect.y = 0; 1.448 + aRect.width = mWidth; 1.449 + aRect.height = mHeight; 1.450 + } else 1.451 + ComputeFullAreaUsingScreen ( &aRect ); 1.452 + 1.453 + return NS_OK; 1.454 +} 1.455 + 1.456 +nsresult 1.457 +nsDeviceContext::GetClientRect(nsRect &aRect) 1.458 +{ 1.459 + if (mPrintingSurface) { 1.460 + // we have a printer device 1.461 + aRect.x = 0; 1.462 + aRect.y = 0; 1.463 + aRect.width = mWidth; 1.464 + aRect.height = mHeight; 1.465 + } 1.466 + else 1.467 + ComputeClientRectUsingScreen(&aRect); 1.468 + 1.469 + return NS_OK; 1.470 +} 1.471 + 1.472 +nsresult 1.473 +nsDeviceContext::InitForPrinting(nsIDeviceContextSpec *aDevice) 1.474 +{ 1.475 + NS_ENSURE_ARG_POINTER(aDevice); 1.476 + 1.477 + mDeviceContextSpec = aDevice; 1.478 + 1.479 + nsresult rv = aDevice->GetSurfaceForPrinter(getter_AddRefs(mPrintingSurface)); 1.480 + if (NS_FAILED(rv)) 1.481 + return NS_ERROR_FAILURE; 1.482 + 1.483 + Init(nullptr); 1.484 + 1.485 + CalcPrintingSize(); 1.486 + 1.487 + return NS_OK; 1.488 +} 1.489 + 1.490 +nsresult 1.491 +nsDeviceContext::BeginDocument(const nsAString& aTitle, 1.492 + char16_t* aPrintToFileName, 1.493 + int32_t aStartPage, 1.494 + int32_t aEndPage) 1.495 +{ 1.496 + static const char16_t kEmpty[] = { '\0' }; 1.497 + nsresult rv; 1.498 + 1.499 + rv = mPrintingSurface->BeginPrinting(aTitle, 1.500 + nsDependentString(aPrintToFileName ? aPrintToFileName : kEmpty)); 1.501 + 1.502 + if (NS_SUCCEEDED(rv) && mDeviceContextSpec) 1.503 + rv = mDeviceContextSpec->BeginDocument(aTitle, aPrintToFileName, aStartPage, aEndPage); 1.504 + 1.505 + return rv; 1.506 +} 1.507 + 1.508 + 1.509 +nsresult 1.510 +nsDeviceContext::EndDocument(void) 1.511 +{ 1.512 + nsresult rv = NS_OK; 1.513 + 1.514 + if (mPrintingSurface) { 1.515 + rv = mPrintingSurface->EndPrinting(); 1.516 + if (NS_SUCCEEDED(rv)) 1.517 + mPrintingSurface->Finish(); 1.518 + } 1.519 + 1.520 + if (mDeviceContextSpec) 1.521 + mDeviceContextSpec->EndDocument(); 1.522 + 1.523 + return rv; 1.524 +} 1.525 + 1.526 + 1.527 +nsresult 1.528 +nsDeviceContext::AbortDocument(void) 1.529 +{ 1.530 + nsresult rv = mPrintingSurface->AbortPrinting(); 1.531 + 1.532 + if (mDeviceContextSpec) 1.533 + mDeviceContextSpec->EndDocument(); 1.534 + 1.535 + return rv; 1.536 +} 1.537 + 1.538 + 1.539 +nsresult 1.540 +nsDeviceContext::BeginPage(void) 1.541 +{ 1.542 + nsresult rv = NS_OK; 1.543 + 1.544 + if (mDeviceContextSpec) 1.545 + rv = mDeviceContextSpec->BeginPage(); 1.546 + 1.547 + if (NS_FAILED(rv)) return rv; 1.548 + 1.549 +#ifdef XP_MACOSX 1.550 + // We need to get a new surface for each page on the Mac, as the 1.551 + // CGContextRefs are only good for one page. 1.552 + mDeviceContextSpec->GetSurfaceForPrinter(getter_AddRefs(mPrintingSurface)); 1.553 +#endif 1.554 + 1.555 + rv = mPrintingSurface->BeginPage(); 1.556 + 1.557 + return rv; 1.558 +} 1.559 + 1.560 +nsresult 1.561 +nsDeviceContext::EndPage(void) 1.562 +{ 1.563 + nsresult rv = mPrintingSurface->EndPage(); 1.564 + 1.565 +#ifdef XP_MACOSX 1.566 + // We need to release the CGContextRef in the surface here, plus it's 1.567 + // not something you would want anyway, as these CGContextRefs are only 1.568 + // good for one page. But we need to keep a cached reference to it, since 1.569 + // CreateRenderingContext() may try to access it when mPrintingSurface 1.570 + // would normally be null. See bug 665218. If we just stop nulling out 1.571 + // mPrintingSurface here (and thereby make that our cached copy), we'll 1.572 + // break all our null checks on mPrintingSurface. See bug 684622. 1.573 + mCachedPrintingSurface = mPrintingSurface; 1.574 + mPrintingSurface = nullptr; 1.575 +#endif 1.576 + 1.577 + if (mDeviceContextSpec) 1.578 + mDeviceContextSpec->EndPage(); 1.579 + 1.580 + return rv; 1.581 +} 1.582 + 1.583 +void 1.584 +nsDeviceContext::ComputeClientRectUsingScreen(nsRect* outRect) 1.585 +{ 1.586 + // we always need to recompute the clientRect 1.587 + // because the window may have moved onto a different screen. In the single 1.588 + // monitor case, we only need to do the computation if we haven't done it 1.589 + // once already, and remember that we have because we're assured it won't change. 1.590 + nsCOMPtr<nsIScreen> screen; 1.591 + FindScreen (getter_AddRefs(screen)); 1.592 + if (screen) { 1.593 + int32_t x, y, width, height; 1.594 + screen->GetAvailRect(&x, &y, &width, &height); 1.595 + 1.596 + // convert to device units 1.597 + outRect->y = NSIntPixelsToAppUnits(y, AppUnitsPerDevPixel()); 1.598 + outRect->x = NSIntPixelsToAppUnits(x, AppUnitsPerDevPixel()); 1.599 + outRect->width = NSIntPixelsToAppUnits(width, AppUnitsPerDevPixel()); 1.600 + outRect->height = NSIntPixelsToAppUnits(height, AppUnitsPerDevPixel()); 1.601 + } 1.602 +} 1.603 + 1.604 +void 1.605 +nsDeviceContext::ComputeFullAreaUsingScreen(nsRect* outRect) 1.606 +{ 1.607 + // if we have more than one screen, we always need to recompute the clientRect 1.608 + // because the window may have moved onto a different screen. In the single 1.609 + // monitor case, we only need to do the computation if we haven't done it 1.610 + // once already, and remember that we have because we're assured it won't change. 1.611 + nsCOMPtr<nsIScreen> screen; 1.612 + FindScreen ( getter_AddRefs(screen) ); 1.613 + if ( screen ) { 1.614 + int32_t x, y, width, height; 1.615 + screen->GetRect ( &x, &y, &width, &height ); 1.616 + 1.617 + // convert to device units 1.618 + outRect->y = NSIntPixelsToAppUnits(y, AppUnitsPerDevPixel()); 1.619 + outRect->x = NSIntPixelsToAppUnits(x, AppUnitsPerDevPixel()); 1.620 + outRect->width = NSIntPixelsToAppUnits(width, AppUnitsPerDevPixel()); 1.621 + outRect->height = NSIntPixelsToAppUnits(height, AppUnitsPerDevPixel()); 1.622 + 1.623 + mWidth = outRect->width; 1.624 + mHeight = outRect->height; 1.625 + } 1.626 +} 1.627 + 1.628 +// 1.629 +// FindScreen 1.630 +// 1.631 +// Determines which screen intersects the largest area of the given surface. 1.632 +// 1.633 +void 1.634 +nsDeviceContext::FindScreen(nsIScreen** outScreen) 1.635 +{ 1.636 + if (mWidget && mWidget->GetNativeData(NS_NATIVE_WINDOW)) 1.637 + mScreenManager->ScreenForNativeWidget(mWidget->GetNativeData(NS_NATIVE_WINDOW), 1.638 + outScreen); 1.639 + else 1.640 + mScreenManager->GetPrimaryScreen(outScreen); 1.641 +} 1.642 + 1.643 +void 1.644 +nsDeviceContext::CalcPrintingSize() 1.645 +{ 1.646 + if (!mPrintingSurface) 1.647 + return; 1.648 + 1.649 + bool inPoints = true; 1.650 + 1.651 + gfxSize size(0, 0); 1.652 + switch (mPrintingSurface->GetType()) { 1.653 + case gfxSurfaceType::Image: 1.654 + inPoints = false; 1.655 + size = reinterpret_cast<gfxImageSurface*>(mPrintingSurface.get())->GetSize(); 1.656 + break; 1.657 + 1.658 +#if defined(MOZ_PDF_PRINTING) 1.659 + case gfxSurfaceType::PDF: 1.660 + inPoints = true; 1.661 + size = reinterpret_cast<gfxPDFSurface*>(mPrintingSurface.get())->GetSize(); 1.662 + break; 1.663 +#endif 1.664 + 1.665 +#ifdef MOZ_WIDGET_GTK 1.666 + case gfxSurfaceType::PS: 1.667 + inPoints = true; 1.668 + size = reinterpret_cast<gfxPSSurface*>(mPrintingSurface.get())->GetSize(); 1.669 + break; 1.670 +#endif 1.671 + 1.672 +#ifdef XP_MACOSX 1.673 + case gfxSurfaceType::Quartz: 1.674 + inPoints = true; // this is really only true when we're printing 1.675 + size = reinterpret_cast<gfxQuartzSurface*>(mPrintingSurface.get())->GetSize(); 1.676 + break; 1.677 +#endif 1.678 + 1.679 +#ifdef XP_WIN 1.680 + case gfxSurfaceType::Win32: 1.681 + case gfxSurfaceType::Win32Printing: 1.682 + { 1.683 + inPoints = false; 1.684 + HDC dc = reinterpret_cast<gfxWindowsSurface*>(mPrintingSurface.get())->GetDC(); 1.685 + if (!dc) 1.686 + dc = GetDC((HWND)mWidget->GetNativeData(NS_NATIVE_WIDGET)); 1.687 + size.width = NSFloatPixelsToAppUnits(::GetDeviceCaps(dc, HORZRES)/mPrintingScale, AppUnitsPerDevPixel()); 1.688 + size.height = NSFloatPixelsToAppUnits(::GetDeviceCaps(dc, VERTRES)/mPrintingScale, AppUnitsPerDevPixel()); 1.689 + mDepth = (uint32_t)::GetDeviceCaps(dc, BITSPIXEL); 1.690 + if (dc != reinterpret_cast<gfxWindowsSurface*>(mPrintingSurface.get())->GetDC()) 1.691 + ReleaseDC((HWND)mWidget->GetNativeData(NS_NATIVE_WIDGET), dc); 1.692 + break; 1.693 + } 1.694 +#endif 1.695 + 1.696 + default: 1.697 + NS_ERROR("trying to print to unknown surface type"); 1.698 + } 1.699 + 1.700 + if (inPoints) { 1.701 + // For printing, CSS inches and physical inches are identical 1.702 + // so it doesn't matter which we use here 1.703 + mWidth = NSToCoordRound(float(size.width) * AppUnitsPerPhysicalInch() / 72); 1.704 + mHeight = NSToCoordRound(float(size.height) * AppUnitsPerPhysicalInch() / 72); 1.705 + } else { 1.706 + mWidth = NSToIntRound(size.width); 1.707 + mHeight = NSToIntRound(size.height); 1.708 + } 1.709 +} 1.710 + 1.711 +bool nsDeviceContext::CheckDPIChange() { 1.712 + int32_t oldDevPixels = mAppUnitsPerDevNotScaledPixel; 1.713 + int32_t oldInches = mAppUnitsPerPhysicalInch; 1.714 + 1.715 + SetDPI(); 1.716 + 1.717 + return oldDevPixels != mAppUnitsPerDevNotScaledPixel || 1.718 + oldInches != mAppUnitsPerPhysicalInch; 1.719 +} 1.720 + 1.721 +bool 1.722 +nsDeviceContext::SetPixelScale(float aScale) 1.723 +{ 1.724 + if (aScale <= 0) { 1.725 + NS_NOTREACHED("Invalid pixel scale value"); 1.726 + return false; 1.727 + } 1.728 + int32_t oldAppUnitsPerDevPixel = mAppUnitsPerDevPixel; 1.729 + mPixelScale = aScale; 1.730 + UpdateScaledAppUnits(); 1.731 + return oldAppUnitsPerDevPixel != mAppUnitsPerDevPixel; 1.732 +} 1.733 + 1.734 +void 1.735 +nsDeviceContext::UpdateScaledAppUnits() 1.736 +{ 1.737 + mAppUnitsPerDevPixel = 1.738 + std::max(1, NSToIntRound(float(mAppUnitsPerDevNotScaledPixel) / mPixelScale)); 1.739 + // adjust mPixelScale to reflect appunit rounding 1.740 + mPixelScale = float(mAppUnitsPerDevNotScaledPixel) / mAppUnitsPerDevPixel; 1.741 +}