Bug 1353493 - Cache the return value for nsIWidget::DefaultScaleOverride(). r=kanru
authorMasatoshi Kimura <VYV03354@nifty.ne.jp>
Thu, 06 Apr 2017 23:30:09 +0900
changeset 558278 f0792bb960b6e16be5d854366ba81ec2a604052c
parent 558277 b21110aa79591ea6556ca0c9781675ec039e6599
child 558279 05a48259d0732cd1880c6cb82452b740135a6688
push id52860
push userbmo:walkingice0204@gmail.com
push dateFri, 07 Apr 2017 13:29:26 +0000
reviewerskanru
bugs1353493
milestone55.0a1
Bug 1353493 - Cache the return value for nsIWidget::DefaultScaleOverride(). r=kanru MozReview-Commit-ID: ExP179bxbHe
layout/base/nsPresContext.cpp
widget/nsBaseWidget.cpp
widget/nsIWidget.h
--- a/layout/base/nsPresContext.cpp
+++ b/layout/base/nsPresContext.cpp
@@ -690,16 +690,22 @@ nsPresContext::AppUnitsPerDevPixelChange
 }
 
 void
 nsPresContext::PreferenceChanged(const char* aPrefName)
 {
   nsDependentCString prefName(aPrefName);
   if (prefName.EqualsLiteral("layout.css.dpi") ||
       prefName.EqualsLiteral("layout.css.devPixelsPerPx")) {
+
+    // We can't use a separate observer, callback, or var cache
+    // Because they don't guarantee the order of function calls.
+    // We have to update the scale override value first.
+    nsIWidget::ScaleOverrideChanged();
+
     int32_t oldAppUnitsPerDevPixel = AppUnitsPerDevPixel();
     if (mDeviceContext->CheckDPIChange() && mShell) {
       nsCOMPtr<nsIPresShell> shell = mShell;
       // Re-fetch the view manager's window dimensions in case there's a deferred
       // resize which hasn't affected our mVisibleArea yet
       nscoord oldWidthAppUnits, oldHeightAppUnits;
       RefPtr<nsViewManager> vm = shell->GetViewManager();
       if (!vm) {
--- a/widget/nsBaseWidget.cpp
+++ b/widget/nsBaseWidget.cpp
@@ -568,30 +568,86 @@ CSSToLayoutDeviceScale nsIWidget::GetDef
 
   if (devPixelsPerCSSPixel <= 0.0) {
     devPixelsPerCSSPixel = GetDefaultScaleInternal();
   }
 
   return CSSToLayoutDeviceScale(devPixelsPerCSSPixel);
 }
 
+// The number of device pixels per CSS pixel. A value <= 0 means choose
+// automatically based on the DPI. A positive value is used as-is. This effectively
+// controls the size of a CSS "px".
+static double sDevPixelsPerCSSPixel = -1.0;
+
+/* static */
+void nsIWidget::ScaleOverrideChanged()
+{
+  nsAdoptingCString prefString = Preferences::GetCString("layout.css.devPixelsPerPx");
+  if (!prefString.IsEmpty()) {
+    sDevPixelsPerCSSPixel = PR_strtod(prefString, nullptr);
+  } else {
+    sDevPixelsPerCSSPixel = -1.0;
+  }
+}
+
+class ProfileChangeObserver final : public nsIObserver
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIOBSERVER
+  static void Init();
+private:
+  ProfileChangeObserver();
+  ~ProfileChangeObserver();
+};
+
+ProfileChangeObserver::ProfileChangeObserver()
+{
+}
+
+ProfileChangeObserver::~ProfileChangeObserver()
+{
+}
+
+/* static */
+void ProfileChangeObserver::Init()
+{
+  nsCOMPtr<nsIObserver> profileChangeObserver = new ProfileChangeObserver();
+  nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
+  obs->AddObserver(profileChangeObserver, "profile-do-change", false);
+  // We don't have to observe XPCOM shutdown to remove the observer
+  // explicitly. Also, we don't have to hold a strong reference to the
+  // observer on our own. The observer service will do them for us.
+}
+
+NS_IMPL_ISUPPORTS(ProfileChangeObserver,
+                  nsIObserver)
+
+NS_IMETHODIMP
+ProfileChangeObserver::Observe(nsISupports* aSubject, const char* aTopic,
+                               const char16_t* aData)
+{
+  if (!strcmp(aTopic, "profile-do-change")) {
+    nsIWidget::ScaleOverrideChanged();
+  }
+  return NS_OK;
+}
+
 /* static */
 double nsIWidget::DefaultScaleOverride()
 {
-  // The number of device pixels per CSS pixel. A value <= 0 means choose
-  // automatically based on the DPI. A positive value is used as-is. This effectively
-  // controls the size of a CSS "px".
-  double devPixelsPerCSSPixel = -1.0;
-
-  nsAdoptingCString prefString = Preferences::GetCString("layout.css.devPixelsPerPx");
-  if (!prefString.IsEmpty()) {
-    devPixelsPerCSSPixel = PR_strtod(prefString, nullptr);
+  static bool valueCached = false;
+  if (!valueCached) {
+    ScaleOverrideChanged();
+    ProfileChangeObserver::Init();
+    valueCached = true;
   }
 
-  return devPixelsPerCSSPixel;
+  return sDevPixelsPerCSSPixel;
 }
 
 //-------------------------------------------------------------------------
 //
 // Add a child to the list of children
 //
 //-------------------------------------------------------------------------
 void nsBaseWidget::AddChild(nsIWidget* aChild)
--- a/widget/nsIWidget.h
+++ b/widget/nsIWidget.h
@@ -567,16 +567,22 @@ class nsIWidget : public nsISupports
      * default number of device pixels per CSS pixel to use. This should
      * depend on OS/platform settings such as the Mac's "UI scale factor"
      * or Windows' "font DPI". This will take into account Gecko preferences
      * overriding the system setting.
      */
     mozilla::CSSToLayoutDeviceScale GetDefaultScale();
 
     /**
+     * Cache the scale override value. Call whenever the scale override
+     * value is changed.
+     */
+    static void ScaleOverrideChanged();
+
+    /**
      * Return the Gecko override of the system default scale, if any;
      * returns <= 0.0 if the system scale should be used as-is.
      * nsIWidget::GetDefaultScale() [above] takes this into account.
      * It is exposed here so that code that wants to check for a
      * default-scale override without having a widget on hand can
      * easily access the same value.
      * Note that any scale override is a browser-wide value, whereas
      * the default GetDefaultScale value (when no override is present)