diff --git a/gfx/src/nsDeviceContext.cpp b/gfx/src/nsDeviceContext.cpp index 58d2d9aa96cd..89f9ecf48bbf 100644 --- a/gfx/src/nsDeviceContext.cpp +++ b/gfx/src/nsDeviceContext.cpp @@ -251,7 +251,7 @@ nsDeviceContext::IsPrinterSurface() } void -nsDeviceContext::SetDPI() +nsDeviceContext::SetDPI(double* aScale) { float dpi = -1.0f; @@ -280,9 +280,21 @@ nsDeviceContext::SetDPI() dpi = 96.0f; } - CSSToLayoutDeviceScale scale = mWidget ? mWidget->GetDefaultScale() - : CSSToLayoutDeviceScale(1.0); - double devPixelsPerCSSPixel = scale.scale; + double devPixelsPerCSSPixel; + if (aScale && *aScale > 0.0) { + // if caller provided a scale, we just use it + devPixelsPerCSSPixel = *aScale; + } else { + // otherwise get from the widget, and return it in aScale for + // the caller to pass to child contexts if needed + CSSToLayoutDeviceScale scale = + mWidget ? mWidget->GetDefaultScale() + : CSSToLayoutDeviceScale(1.0); + devPixelsPerCSSPixel = scale.scale; + if (aScale) { + *aScale = devPixelsPerCSSPixel; + } + } mAppUnitsPerDevPixelAtUnitFullZoom = std::max(1, NS_lround(AppUnitsPerCSSPixel() / devPixelsPerCSSPixel)); @@ -632,11 +644,12 @@ nsDeviceContext::CalcPrintingSize() return (mWidth > 0 && mHeight > 0); } -bool nsDeviceContext::CheckDPIChange() { +bool nsDeviceContext::CheckDPIChange(double* aScale) +{ int32_t oldDevPixels = mAppUnitsPerDevPixelAtUnitFullZoom; int32_t oldInches = mAppUnitsPerPhysicalInch; - SetDPI(); + SetDPI(aScale); return oldDevPixels != mAppUnitsPerDevPixelAtUnitFullZoom || oldInches != mAppUnitsPerPhysicalInch; diff --git a/gfx/src/nsDeviceContext.h b/gfx/src/nsDeviceContext.h index 887125734634..b50e8af14de9 100644 --- a/gfx/src/nsDeviceContext.h +++ b/gfx/src/nsDeviceContext.h @@ -219,12 +219,18 @@ public: nsresult EndPage(); /** - * Check to see if the DPI has changed + * Check to see if the DPI has changed, or impose a new DPI scale value. + * @param aScale - If non-null, the default (unzoomed) CSS to device pixel + * scale factor will be returned here; and if it is > 0.0 + * on input, the given value will be used instead of + * getting it from the widget (if any). This is used to + * allow subdocument contexts to inherit the resolution + * setting of their parent. * @return whether there was actually a change in the DPI (whether * AppUnitsPerDevPixel() or AppUnitsPerPhysicalInch() * changed) */ - bool CheckDPIChange(); + bool CheckDPIChange(double* aScale = nullptr); /** * Set the full zoom factor: all lengths are multiplied by this factor @@ -249,7 +255,7 @@ private: // Private destructor, to discourage deletion outside of Release(): ~nsDeviceContext(); - void SetDPI(); + void SetDPI(double* aScale = nullptr); void ComputeClientRectUsingScreen(nsRect *outRect); void ComputeFullAreaUsingScreen(nsRect *outRect); void FindScreen(nsIScreen **outScreen); diff --git a/layout/base/nsPresContext.cpp b/layout/base/nsPresContext.cpp index 690e34d54ffd..40198fd3b366 100644 --- a/layout/base/nsPresContext.cpp +++ b/layout/base/nsPresContext.cpp @@ -1693,7 +1693,7 @@ nsPresContext::UIResolutionChangedSync() { if (!mPendingUIResolutionChanged) { mPendingUIResolutionChanged = true; - UIResolutionChangedInternal(); + UIResolutionChangedInternalScale(0.0); } } @@ -1705,7 +1705,12 @@ nsPresContext::UIResolutionChangedSubdocumentCallback(nsIDocument* aDocument, if (shell) { nsPresContext* pc = shell->GetPresContext(); if (pc) { - pc->UIResolutionChangedInternal(); + // For subdocuments, we want to apply the parent's scale, because there + // are cases where the subdoc's device context is connected to a widget + // that has an out-of-date resolution (it's on a different screen, but + // currently hidden, and will not be updated until shown): bug 1249279. + double scale = *static_cast(aData); + pc->UIResolutionChangedInternalScale(scale); } } return true; @@ -1730,10 +1735,16 @@ NotifyChildrenUIResolutionChanged(nsPIDOMWindowOuter* aWindow) void nsPresContext::UIResolutionChangedInternal() +{ + UIResolutionChangedInternalScale(0.0); +} + +void +nsPresContext::UIResolutionChangedInternalScale(double aScale) { mPendingUIResolutionChanged = false; - mDeviceContext->CheckDPIChange(); + mDeviceContext->CheckDPIChange(&aScale); if (mCurAppUnitsPerDevPixel != AppUnitsPerDevPixel()) { AppUnitsPerDevPixelChanged(); } @@ -1744,7 +1755,7 @@ nsPresContext::UIResolutionChangedInternal() } mDocument->EnumerateSubDocuments(UIResolutionChangedSubdocumentCallback, - nullptr); + &aScale); } void diff --git a/layout/base/nsPresContext.h b/layout/base/nsPresContext.h index 8144a7a3e4b9..32649974dee2 100644 --- a/layout/base/nsPresContext.h +++ b/layout/base/nsPresContext.h @@ -1102,8 +1102,17 @@ protected: friend class nsRunnableMethod; void ThemeChangedInternal(); void SysColorChangedInternal(); + + // update device context's resolution from the widget void UIResolutionChangedInternal(); + // if aScale > 0.0, use it as resolution scale factor to the device context + // (otherwise get it from the widget) + void UIResolutionChangedInternalScale(double aScale); + + // aData here is a pointer to a double that holds the CSS to device-pixel + // scale factor from the parent, which will be applied to the subdocument's + // device context instead of retrieving a scale from the widget. static bool UIResolutionChangedSubdocumentCallback(nsIDocument* aDocument, void* aData);