Bug 1492908 [wpt PR 13122] - Update wpt metadata, a=testonly
[gecko.git] / gfx / src / nsDeviceContext.cpp
blob65ad7f0d1c497a1a0c29deeb05d6699a8d9b7d83
1 /* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim: set sw=4 ts=4 expandtab: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "nsDeviceContext.h"
8 #include <algorithm> // for max
9 #include "gfxASurface.h" // for gfxASurface, etc
10 #include "gfxContext.h"
11 #include "gfxFont.h" // for gfxFontGroup
12 #include "gfxImageSurface.h" // for gfxImageSurface
13 #include "gfxPoint.h" // for gfxSize
14 #include "mozilla/Attributes.h" // for final
15 #include "mozilla/gfx/PathHelpers.h"
16 #include "mozilla/gfx/PrintTarget.h"
17 #include "mozilla/Preferences.h" // for Preferences
18 #include "mozilla/Services.h" // for GetObserverService
19 #include "mozilla/mozalloc.h" // for operator new
20 #include "nsCRT.h" // for nsCRT
21 #include "nsDebug.h" // for NS_ASSERTION, etc
22 #include "nsFont.h" // for nsFont
23 #include "nsFontMetrics.h" // for nsFontMetrics
24 #include "nsAtom.h" // for nsAtom, NS_Atomize
25 #include "nsID.h"
26 #include "nsIDeviceContextSpec.h" // for nsIDeviceContextSpec
27 #include "nsLanguageAtomService.h" // for nsLanguageAtomService
28 #include "nsIObserver.h" // for nsIObserver, etc
29 #include "nsIObserverService.h" // for nsIObserverService
30 #include "nsIScreen.h" // for nsIScreen
31 #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
32 #include "nsISupportsUtils.h" // for NS_ADDREF, NS_RELEASE
33 #include "nsIWidget.h" // for nsIWidget, NS_NATIVE_WINDOW
34 #include "nsRect.h" // for nsRect
35 #include "nsServiceManagerUtils.h" // for do_GetService
36 #include "nsString.h" // for nsDependentString
37 #include "nsTArray.h" // for nsTArray, nsTArray_Impl
38 #include "nsThreadUtils.h" // for NS_IsMainThread
39 #include "mozilla/gfx/Logging.h"
40 #include "mozilla/widget/ScreenManager.h" // for ScreenManager
42 using namespace mozilla;
43 using namespace mozilla::gfx;
44 using mozilla::services::GetObserverService;
45 using mozilla::widget::ScreenManager;
47 class nsFontCache final : public nsIObserver
49 public:
50 nsFontCache(): mContext(nullptr) {}
52 NS_DECL_ISUPPORTS
53 NS_DECL_NSIOBSERVER
55 void Init(nsDeviceContext* aContext);
56 void Destroy();
58 already_AddRefed<nsFontMetrics> GetMetricsFor(
59 const nsFont& aFont, const nsFontMetrics::Params& aParams);
61 void FontMetricsDeleted(const nsFontMetrics* aFontMetrics);
62 void Compact();
63 void Flush();
65 void UpdateUserFonts(gfxUserFontSet* aUserFontSet);
67 protected:
68 ~nsFontCache() {}
70 nsDeviceContext* mContext; // owner
71 RefPtr<nsAtom> mLocaleLanguage;
72 nsTArray<nsFontMetrics*> mFontMetrics;
75 NS_IMPL_ISUPPORTS(nsFontCache, nsIObserver)
77 // The Init and Destroy methods are necessary because it's not
78 // safe to call AddObserver from a constructor or RemoveObserver
79 // from a destructor. That should be fixed.
80 void
81 nsFontCache::Init(nsDeviceContext* aContext)
83 mContext = aContext;
84 // register as a memory-pressure observer to free font resources
85 // in low-memory situations.
86 nsCOMPtr<nsIObserverService> obs = GetObserverService();
87 if (obs)
88 obs->AddObserver(this, "memory-pressure", false);
90 mLocaleLanguage = nsLanguageAtomService::GetService()->GetLocaleLanguage();
91 if (!mLocaleLanguage) {
92 mLocaleLanguage = NS_Atomize("x-western");
96 void
97 nsFontCache::Destroy()
99 nsCOMPtr<nsIObserverService> obs = GetObserverService();
100 if (obs)
101 obs->RemoveObserver(this, "memory-pressure");
102 Flush();
105 NS_IMETHODIMP
106 nsFontCache::Observe(nsISupports*, const char* aTopic, const char16_t*)
108 if (!nsCRT::strcmp(aTopic, "memory-pressure"))
109 Compact();
110 return NS_OK;
113 already_AddRefed<nsFontMetrics>
114 nsFontCache::GetMetricsFor(const nsFont& aFont,
115 const nsFontMetrics::Params& aParams)
117 nsAtom* language = aParams.language ? aParams.language
118 : mLocaleLanguage.get();
120 // First check our cache
121 // start from the end, which is where we put the most-recent-used element
123 int32_t n = mFontMetrics.Length() - 1;
124 for (int32_t i = n; i >= 0; --i) {
125 nsFontMetrics* fm = mFontMetrics[i];
126 if (fm->Font().Equals(aFont) &&
127 fm->GetUserFontSet() == aParams.userFontSet &&
128 fm->Language() == language &&
129 fm->Orientation() == aParams.orientation) {
130 if (i != n) {
131 // promote it to the end of the cache
132 mFontMetrics.RemoveElementAt(i);
133 mFontMetrics.AppendElement(fm);
135 fm->GetThebesFontGroup()->UpdateUserFonts();
136 return do_AddRef(fm);
140 // It's not in the cache. Get font metrics and then cache them.
142 nsFontMetrics::Params params = aParams;
143 params.language = language;
144 RefPtr<nsFontMetrics> fm = new nsFontMetrics(aFont, params, mContext);
145 // the mFontMetrics list has the "head" at the end, because append
146 // is cheaper than insert
147 mFontMetrics.AppendElement(do_AddRef(fm).take());
148 return fm.forget();
151 void
152 nsFontCache::UpdateUserFonts(gfxUserFontSet* aUserFontSet)
154 for (nsFontMetrics* fm : mFontMetrics) {
155 gfxFontGroup* fg = fm->GetThebesFontGroup();
156 if (fg->GetUserFontSet() == aUserFontSet) {
157 fg->UpdateUserFonts();
162 void
163 nsFontCache::FontMetricsDeleted(const nsFontMetrics* aFontMetrics)
165 mFontMetrics.RemoveElement(aFontMetrics);
168 void
169 nsFontCache::Compact()
171 // Need to loop backward because the running element can be removed on
172 // the way
173 for (int32_t i = mFontMetrics.Length()-1; i >= 0; --i) {
174 nsFontMetrics* fm = mFontMetrics[i];
175 nsFontMetrics* oldfm = fm;
176 // Destroy() isn't here because we want our device context to be
177 // notified
178 NS_RELEASE(fm); // this will reset fm to nullptr
179 // if the font is really gone, it would have called back in
180 // FontMetricsDeleted() and would have removed itself
181 if (mFontMetrics.IndexOf(oldfm) != mFontMetrics.NoIndex) {
182 // nope, the font is still there, so let's hold onto it too
183 NS_ADDREF(oldfm);
188 void
189 nsFontCache::Flush()
191 for (int32_t i = mFontMetrics.Length()-1; i >= 0; --i) {
192 nsFontMetrics* fm = mFontMetrics[i];
193 // Destroy() will unhook our device context from the fm so that we
194 // won't waste time in triggering the notification of
195 // FontMetricsDeleted() in the subsequent release
196 fm->Destroy();
197 NS_RELEASE(fm);
199 mFontMetrics.Clear();
202 nsDeviceContext::nsDeviceContext()
203 : mWidth(0), mHeight(0),
204 mAppUnitsPerDevPixel(-1), mAppUnitsPerDevPixelAtUnitFullZoom(-1),
205 mAppUnitsPerPhysicalInch(-1),
206 mFullZoom(1.0f), mPrintingScale(1.0f),
207 mPrintingTranslate(gfxPoint(0, 0)),
208 mIsCurrentlyPrintingDoc(false)
209 #ifdef DEBUG
210 , mIsInitialized(false)
211 #endif
213 MOZ_ASSERT(NS_IsMainThread(), "nsDeviceContext created off main thread");
216 nsDeviceContext::~nsDeviceContext()
218 if (mFontCache) {
219 mFontCache->Destroy();
223 void
224 nsDeviceContext::InitFontCache()
226 if (!mFontCache) {
227 mFontCache = new nsFontCache();
228 mFontCache->Init(this);
232 void
233 nsDeviceContext::UpdateFontCacheUserFonts(gfxUserFontSet* aUserFontSet)
235 if (mFontCache) {
236 mFontCache->UpdateUserFonts(aUserFontSet);
240 already_AddRefed<nsFontMetrics>
241 nsDeviceContext::GetMetricsFor(const nsFont& aFont,
242 const nsFontMetrics::Params& aParams)
244 InitFontCache();
245 return mFontCache->GetMetricsFor(aFont, aParams);
248 nsresult
249 nsDeviceContext::FlushFontCache(void)
251 if (mFontCache)
252 mFontCache->Flush();
253 return NS_OK;
256 nsresult
257 nsDeviceContext::FontMetricsDeleted(const nsFontMetrics* aFontMetrics)
259 if (mFontCache) {
260 mFontCache->FontMetricsDeleted(aFontMetrics);
262 return NS_OK;
265 bool
266 nsDeviceContext::IsPrinterContext()
268 return mPrintTarget != nullptr;
271 void
272 nsDeviceContext::SetDPI(double* aScale)
274 float dpi;
276 // Use the printing DC to determine DPI values, if we have one.
277 if (mDeviceContextSpec) {
278 dpi = mDeviceContextSpec->GetDPI();
279 mPrintingScale = mDeviceContextSpec->GetPrintingScale();
280 mPrintingTranslate = mDeviceContextSpec->GetPrintingTranslate();
281 mAppUnitsPerDevPixelAtUnitFullZoom =
282 NS_lround((AppUnitsPerCSSPixel() * 96) / dpi);
283 } else {
284 nsCOMPtr<nsIScreen> primaryScreen;
285 ScreenManager& screenManager = ScreenManager::GetSingleton();
286 screenManager.GetPrimaryScreen(getter_AddRefs(primaryScreen));
287 MOZ_ASSERT(primaryScreen);
289 // A value of -1 means use the maximum of 96 and the system DPI.
290 // A value of 0 means use the system DPI. A positive value is used as the DPI.
291 // This sets the physical size of a device pixel and thus controls the
292 // interpretation of physical units.
293 int32_t prefDPI = Preferences::GetInt("layout.css.dpi", -1);
295 if (prefDPI > 0) {
296 dpi = prefDPI;
297 } else if (mWidget) {
298 // PuppetWidget could return -1 if the value's not available yet.
299 dpi = mWidget->GetDPI();
300 // In case that the widget returns -1, use the primary screen's
301 // value as default.
302 if (dpi < 0) {
303 primaryScreen->GetDpi(&dpi);
305 if (prefDPI < 0) {
306 dpi = std::max(96.0f, dpi);
308 } else {
309 dpi = 96.0f;
312 double devPixelsPerCSSPixel;
313 if (aScale && *aScale > 0.0) {
314 // if caller provided a scale, we just use it
315 devPixelsPerCSSPixel = *aScale;
316 } else {
317 // otherwise get from the widget, and return it in aScale for
318 // the caller to pass to child contexts if needed
319 CSSToLayoutDeviceScale scale =
320 mWidget ? mWidget->GetDefaultScale()
321 : CSSToLayoutDeviceScale(1.0);
322 devPixelsPerCSSPixel = scale.scale;
323 // In case that the widget returns -1, use the primary screen's
324 // value as default.
325 if (devPixelsPerCSSPixel < 0) {
326 primaryScreen->GetDefaultCSSScaleFactor(&devPixelsPerCSSPixel);
328 if (aScale) {
329 *aScale = devPixelsPerCSSPixel;
333 mAppUnitsPerDevPixelAtUnitFullZoom =
334 std::max(1, NS_lround(AppUnitsPerCSSPixel() / devPixelsPerCSSPixel));
337 NS_ASSERTION(dpi != -1.0, "no dpi set");
339 mAppUnitsPerPhysicalInch = NS_lround(dpi * mAppUnitsPerDevPixelAtUnitFullZoom);
340 UpdateAppUnitsForFullZoom();
343 nsresult
344 nsDeviceContext::Init(nsIWidget *aWidget)
346 #ifdef DEBUG
347 // We can't assert |!mIsInitialized| here since EndSwapDocShellsForDocument
348 // re-initializes nsDeviceContext objects. We can only assert in
349 // InitForPrinting (below).
350 mIsInitialized = true;
351 #endif
353 nsresult rv = NS_OK;
354 if (mScreenManager && mWidget == aWidget)
355 return rv;
357 mWidget = aWidget;
358 SetDPI();
360 if (mScreenManager)
361 return rv;
363 mScreenManager = do_GetService("@mozilla.org/gfx/screenmanager;1", &rv);
365 return rv;
368 // XXX This is only for printing. We should make that obvious in the name.
369 already_AddRefed<gfxContext>
370 nsDeviceContext::CreateRenderingContext()
372 return CreateRenderingContextCommon(/* not a reference context */ false);
375 already_AddRefed<gfxContext>
376 nsDeviceContext::CreateReferenceRenderingContext()
378 return CreateRenderingContextCommon(/* a reference context */ true);
381 already_AddRefed<gfxContext>
382 nsDeviceContext::CreateRenderingContextCommon(bool aWantReferenceContext)
384 MOZ_ASSERT(IsPrinterContext());
385 MOZ_ASSERT(mWidth > 0 && mHeight > 0);
387 RefPtr<gfx::DrawTarget> dt;
388 if (aWantReferenceContext) {
389 dt = mPrintTarget->GetReferenceDrawTarget();
390 } else {
391 // This will be null if e10s is disabled or print.print_via_parent=false.
392 RefPtr<DrawEventRecorder> recorder;
393 mDeviceContextSpec->GetDrawEventRecorder(getter_AddRefs(recorder));
394 dt = mPrintTarget->MakeDrawTarget(gfx::IntSize(mWidth, mHeight), recorder);
397 if (!dt || !dt->IsValid()) {
398 gfxCriticalNote
399 << "Failed to create draw target in device context sized "
400 << mWidth << "x" << mHeight << " and pointer "
401 << hexa(mPrintTarget);
402 return nullptr;
405 #ifdef XP_MACOSX
406 // The CGContextRef provided by PMSessionGetCGGraphicsContext is
407 // write-only, so we need to prevent gfxContext::PushGroupAndCopyBackground
408 // trying to read from it or else we'll crash.
409 // XXXjwatt Consider adding a MakeDrawTarget override to PrintTargetCG and
410 // moving this AddUserData call there.
411 dt->AddUserData(&gfxContext::sDontUseAsSourceKey, dt, nullptr);
412 #endif
413 dt->AddUserData(&sDisablePixelSnapping, (void*)0x1, nullptr);
415 RefPtr<gfxContext> pContext = gfxContext::CreateOrNull(dt);
416 MOZ_ASSERT(pContext); // already checked draw target above
418 gfxMatrix transform;
419 transform.PreTranslate(mPrintingTranslate);
420 if (mPrintTarget->RotateNeededForLandscape()) {
421 // Rotate page 90 degrees to draw landscape page on portrait paper
422 IntSize size = mPrintTarget->GetSize();
423 transform.PreTranslate(gfxPoint(0, size.width));
424 gfxMatrix rotate(0, -1,
425 1, 0,
426 0, 0);
427 transform = rotate * transform;
429 transform.PreScale(mPrintingScale, mPrintingScale);
431 pContext->SetMatrixDouble(transform);
432 return pContext.forget();
435 nsresult
436 nsDeviceContext::GetDepth(uint32_t& aDepth)
438 nsCOMPtr<nsIScreen> screen;
439 FindScreen(getter_AddRefs(screen));
440 if (!screen) {
441 ScreenManager& screenManager = ScreenManager::GetSingleton();
442 screenManager.GetPrimaryScreen(getter_AddRefs(screen));
443 MOZ_ASSERT(screen);
445 screen->GetColorDepth(reinterpret_cast<int32_t *>(&aDepth));
447 return NS_OK;
450 nsresult
451 nsDeviceContext::GetDeviceSurfaceDimensions(nscoord &aWidth, nscoord &aHeight)
453 if (IsPrinterContext()) {
454 aWidth = mWidth;
455 aHeight = mHeight;
456 } else {
457 nsRect area;
458 ComputeFullAreaUsingScreen(&area);
459 aWidth = area.Width();
460 aHeight = area.Height();
463 return NS_OK;
466 nsresult
467 nsDeviceContext::GetRect(nsRect &aRect)
469 if (IsPrinterContext()) {
470 aRect.SetRect(0, 0, mWidth, mHeight);
471 } else
472 ComputeFullAreaUsingScreen ( &aRect );
474 return NS_OK;
477 nsresult
478 nsDeviceContext::GetClientRect(nsRect &aRect)
480 if (IsPrinterContext()) {
481 aRect.SetRect(0, 0, mWidth, mHeight);
483 else
484 ComputeClientRectUsingScreen(&aRect);
486 return NS_OK;
489 nsresult
490 nsDeviceContext::InitForPrinting(nsIDeviceContextSpec *aDevice)
492 NS_ENSURE_ARG_POINTER(aDevice);
494 MOZ_ASSERT(!mIsInitialized,
495 "Only initialize once, immediately after construction");
497 // We don't set mIsInitialized here. The Init() call below does that.
499 mPrintTarget = aDevice->MakePrintTarget();
500 if (!mPrintTarget) {
501 return NS_ERROR_FAILURE;
504 mDeviceContextSpec = aDevice;
506 Init(nullptr);
508 if (!CalcPrintingSize()) {
509 return NS_ERROR_FAILURE;
512 return NS_OK;
515 nsresult
516 nsDeviceContext::BeginDocument(const nsAString& aTitle,
517 const nsAString& aPrintToFileName,
518 int32_t aStartPage,
519 int32_t aEndPage)
521 MOZ_ASSERT(!mIsCurrentlyPrintingDoc,
522 "Mismatched BeginDocument/EndDocument calls");
524 nsresult rv = mPrintTarget->BeginPrinting(aTitle, aPrintToFileName,
525 aStartPage, aEndPage);
527 if (NS_SUCCEEDED(rv)) {
528 if (mDeviceContextSpec) {
529 rv = mDeviceContextSpec->BeginDocument(aTitle, aPrintToFileName,
530 aStartPage, aEndPage);
532 mIsCurrentlyPrintingDoc = true;
535 // Warn about any failure (except user cancelling):
536 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv) || rv == NS_ERROR_ABORT,
537 "nsDeviceContext::BeginDocument failed");
539 return rv;
543 nsresult
544 nsDeviceContext::EndDocument(void)
546 MOZ_ASSERT(mIsCurrentlyPrintingDoc,
547 "Mismatched BeginDocument/EndDocument calls");
549 mIsCurrentlyPrintingDoc = false;
551 nsresult rv = mPrintTarget->EndPrinting();
552 if (NS_SUCCEEDED(rv)) {
553 mPrintTarget->Finish();
556 if (mDeviceContextSpec)
557 mDeviceContextSpec->EndDocument();
559 mPrintTarget = nullptr;
561 return rv;
565 nsresult
566 nsDeviceContext::AbortDocument(void)
568 MOZ_ASSERT(mIsCurrentlyPrintingDoc,
569 "Mismatched BeginDocument/EndDocument calls");
571 nsresult rv = mPrintTarget->AbortPrinting();
573 mIsCurrentlyPrintingDoc = false;
575 if (mDeviceContextSpec)
576 mDeviceContextSpec->EndDocument();
578 mPrintTarget = nullptr;
580 return rv;
584 nsresult
585 nsDeviceContext::BeginPage(void)
587 nsresult rv = NS_OK;
589 if (mDeviceContextSpec)
590 rv = mDeviceContextSpec->BeginPage();
592 if (NS_FAILED(rv)) return rv;
594 return mPrintTarget->BeginPage();
597 nsresult
598 nsDeviceContext::EndPage(void)
600 nsresult rv = mPrintTarget->EndPage();
602 if (mDeviceContextSpec)
603 mDeviceContextSpec->EndPage();
605 return rv;
608 void
609 nsDeviceContext::ComputeClientRectUsingScreen(nsRect* outRect)
611 // we always need to recompute the clientRect
612 // because the window may have moved onto a different screen. In the single
613 // monitor case, we only need to do the computation if we haven't done it
614 // once already, and remember that we have because we're assured it won't change.
615 nsCOMPtr<nsIScreen> screen;
616 FindScreen (getter_AddRefs(screen));
617 if (screen) {
618 int32_t x, y, width, height;
619 screen->GetAvailRect(&x, &y, &width, &height);
621 // convert to device units
622 outRect->SetRect(NSIntPixelsToAppUnits(x, AppUnitsPerDevPixel()),
623 NSIntPixelsToAppUnits(y, AppUnitsPerDevPixel()),
624 NSIntPixelsToAppUnits(width, AppUnitsPerDevPixel()),
625 NSIntPixelsToAppUnits(height, AppUnitsPerDevPixel()));
629 void
630 nsDeviceContext::ComputeFullAreaUsingScreen(nsRect* outRect)
632 // if we have more than one screen, we always need to recompute the clientRect
633 // because the window may have moved onto a different screen. In the single
634 // monitor case, we only need to do the computation if we haven't done it
635 // once already, and remember that we have because we're assured it won't change.
636 nsCOMPtr<nsIScreen> screen;
637 FindScreen ( getter_AddRefs(screen) );
638 if ( screen ) {
639 int32_t x, y, width, height;
640 screen->GetRect ( &x, &y, &width, &height );
642 // convert to device units
643 outRect->SetRect(NSIntPixelsToAppUnits(x, AppUnitsPerDevPixel()),
644 NSIntPixelsToAppUnits(y, AppUnitsPerDevPixel()),
645 NSIntPixelsToAppUnits(width, AppUnitsPerDevPixel()),
646 NSIntPixelsToAppUnits(height, AppUnitsPerDevPixel()));
647 mWidth = outRect->Width();
648 mHeight = outRect->Height();
653 // FindScreen
655 // Determines which screen intersects the largest area of the given surface.
657 void
658 nsDeviceContext::FindScreen(nsIScreen** outScreen)
660 if (!mWidget || !mScreenManager) {
661 return;
664 CheckDPIChange();
666 nsCOMPtr<nsIScreen> screen = mWidget->GetWidgetScreen();
667 screen.forget(outScreen);
669 if (!(*outScreen)) {
670 mScreenManager->GetPrimaryScreen(outScreen);
674 bool
675 nsDeviceContext::CalcPrintingSize()
677 gfxSize size(mPrintTarget->GetSize());
678 // For printing, CSS inches and physical inches are identical
679 // so it doesn't matter which we use here
680 mWidth = NSToCoordRound(size.width * AppUnitsPerPhysicalInch()
681 / POINTS_PER_INCH_FLOAT);
682 mHeight = NSToCoordRound(size.height * AppUnitsPerPhysicalInch()
683 / POINTS_PER_INCH_FLOAT);
685 return (mWidth > 0 && mHeight > 0);
688 bool nsDeviceContext::CheckDPIChange(double* aScale)
690 int32_t oldDevPixels = mAppUnitsPerDevPixelAtUnitFullZoom;
691 int32_t oldInches = mAppUnitsPerPhysicalInch;
693 SetDPI(aScale);
695 return oldDevPixels != mAppUnitsPerDevPixelAtUnitFullZoom ||
696 oldInches != mAppUnitsPerPhysicalInch;
699 bool
700 nsDeviceContext::SetFullZoom(float aScale)
702 if (aScale <= 0) {
703 MOZ_ASSERT_UNREACHABLE("Invalid full zoom value");
704 return false;
706 int32_t oldAppUnitsPerDevPixel = mAppUnitsPerDevPixel;
707 mFullZoom = aScale;
708 UpdateAppUnitsForFullZoom();
709 return oldAppUnitsPerDevPixel != mAppUnitsPerDevPixel;
712 void
713 nsDeviceContext::UpdateAppUnitsForFullZoom()
715 mAppUnitsPerDevPixel =
716 std::max(1, NSToIntRound(float(mAppUnitsPerDevPixelAtUnitFullZoom) / mFullZoom));
717 // adjust mFullZoom to reflect appunit rounding
718 mFullZoom = float(mAppUnitsPerDevPixelAtUnitFullZoom) / mAppUnitsPerDevPixel;
721 DesktopToLayoutDeviceScale
722 nsDeviceContext::GetDesktopToDeviceScale()
724 nsCOMPtr<nsIScreen> screen;
725 FindScreen(getter_AddRefs(screen));
727 if (screen) {
728 double scale;
729 screen->GetContentsScaleFactor(&scale);
730 return DesktopToLayoutDeviceScale(scale);
733 return DesktopToLayoutDeviceScale(1.0);
736 bool
737 nsDeviceContext::IsSyncPagePrinting() const
739 MOZ_ASSERT(mPrintTarget);
740 return mPrintTarget->IsSyncPagePrinting();
743 void
744 nsDeviceContext::RegisterPageDoneCallback(PrintTarget::PageDoneCallback&& aCallback)
746 MOZ_ASSERT(mPrintTarget && aCallback && !IsSyncPagePrinting());
747 mPrintTarget->RegisterPageDoneCallback(std::move(aCallback));
749 void
750 nsDeviceContext::UnregisterPageDoneCallback()
752 if (mPrintTarget) {
753 mPrintTarget->UnregisterPageDoneCallback();