Blob Blame History Raw
commit c51d6447fd0d124903d16bf5952efccbf9e1ca92
Author: Tom Anderson <thomasanderson@chromium.org>
Date:   Wed May 24 22:53:20 2023 +0000

    [Qt] Handle scale factor changes
    
    This is a speculative fix for https://crbug.com/1439149.  I suspect
    the scale factor is not set immediately on QT initialization, but
    is set asynchronously shortly after.  This CL adds a listener for
    QT scale changes.
    
    R=thestig
    
    Low-Coverage-Reason: No QT tests currently
    Change-Id: I7dea23e16a6bb26237564af2dc4e43480f6aea9f
    Bug: 1439149
    Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/4559732
    Reviewed-by: Lei Zhang <thestig@chromium.org>
    Commit-Queue: Thomas Anderson <thomasanderson@chromium.org>
    Auto-Submit: Thomas Anderson <thomasanderson@chromium.org>
    Cr-Commit-Position: refs/heads/main@{#1148805}

diff --git a/ui/qt/qt5_shim_moc.cc b/ui/qt/qt5_shim_moc.cc
index 8f8b6b57784a8..6e504f23c603a 100644
--- a/ui/qt/qt5_shim_moc.cc
+++ b/ui/qt/qt5_shim_moc.cc
@@ -23,8 +23,8 @@
 
 QT_BEGIN_MOC_NAMESPACE
 struct qt_meta_stringdata_qt__QtShim_t {
-  QByteArrayData data[6];
-  char stringdata[52];
+  QByteArrayData data[13];
+  char stringdata[151];
 };
 #define QT_MOC_LITERAL(idx, ofs, len)                                       \
   Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(                  \
@@ -33,9 +33,16 @@ struct qt_meta_stringdata_qt__QtShim_t {
 static const qt_meta_stringdata_qt__QtShim_t qt_meta_stringdata_qt__QtShim = {
     {QT_MOC_LITERAL(0, 0, 10), QT_MOC_LITERAL(1, 11, 11),
      QT_MOC_LITERAL(2, 23, 0), QT_MOC_LITERAL(3, 24, 4),
-     QT_MOC_LITERAL(4, 29, 14), QT_MOC_LITERAL(5, 44, 7)},
+     QT_MOC_LITERAL(4, 29, 14), QT_MOC_LITERAL(5, 44, 7),
+     QT_MOC_LITERAL(6, 52, 11), QT_MOC_LITERAL(7, 64, 8),
+     QT_MOC_LITERAL(8, 73, 6), QT_MOC_LITERAL(9, 80, 13),
+     QT_MOC_LITERAL(10, 94, 25), QT_MOC_LITERAL(11, 120, 3),
+     QT_MOC_LITERAL(12, 124, 26)},
     "qt::QtShim\0FontChanged\0\0font\0"
-    "PaletteChanged\0palette"};
+    "PaletteChanged\0palette\0ScreenAdded\0"
+    "QScreen*\0screen\0ScreenRemoved\0"
+    "LogicalDotsPerInchChanged\0dpi\0"
+    "PhysicalDotsPerInchChanged"};
 #undef QT_MOC_LITERAL
 
 static const uint qt_meta_data_qt__QtShim[] = {
@@ -44,7 +51,7 @@ static const uint qt_meta_data_qt__QtShim[] = {
     7,      // revision
     0,      // classname
     0, 0,   // classinfo
-    2, 14,  // methods
+    6, 14,  // methods
     0, 0,   // properties
     0, 0,   // enums/sets
     0, 0,   // constructors
@@ -52,11 +59,15 @@ static const uint qt_meta_data_qt__QtShim[] = {
     0,      // signalCount
 
     // slots: name, argc, parameters, tag, flags
-    1, 1, 24, 2, 0x08 /* Private */, 4, 1, 27, 2, 0x08 /* Private */,
+    1, 1, 44, 2, 0x08 /* Private */, 4, 1, 47, 2, 0x08 /* Private */, 6, 1, 50,
+    2, 0x08 /* Private */, 9, 1, 53, 2, 0x08 /* Private */, 10, 1, 56, 2,
+    0x08 /* Private */, 12, 1, 59, 2, 0x08 /* Private */,
 
     // slots: parameters
     QMetaType::Void, QMetaType::QFont, 3, QMetaType::Void, QMetaType::QPalette,
-    5,
+    5, QMetaType::Void, 0x80000000 | 7, 8, QMetaType::Void, 0x80000000 | 7, 8,
+    QMetaType::Void, QMetaType::QReal, 11, QMetaType::Void, QMetaType::QReal,
+    11,
 
     0  // eod
 };
@@ -74,6 +85,18 @@ void qt::QtShim::qt_static_metacall(QObject* _o,
       case 1:
         _t->PaletteChanged((*reinterpret_cast<const QPalette(*)>(_a[1])));
         break;
+      case 2:
+        _t->ScreenAdded((*reinterpret_cast<QScreen*(*)>(_a[1])));
+        break;
+      case 3:
+        _t->ScreenRemoved((*reinterpret_cast<QScreen*(*)>(_a[1])));
+        break;
+      case 4:
+        _t->LogicalDotsPerInchChanged((*reinterpret_cast<qreal(*)>(_a[1])));
+        break;
+      case 5:
+        _t->PhysicalDotsPerInchChanged((*reinterpret_cast<qreal(*)>(_a[1])));
+        break;
       default:;
     }
   }
@@ -107,15 +130,15 @@ int qt::QtShim::qt_metacall(QMetaObject::Call _c, int _id, void** _a) {
     return _id;
   }
   if (_c == QMetaObject::InvokeMetaMethod) {
-    if (_id < 2) {
+    if (_id < 6) {
       qt_static_metacall(this, _c, _id, _a);
     }
-    _id -= 2;
+    _id -= 6;
   } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
-    if (_id < 2) {
+    if (_id < 6) {
       *reinterpret_cast<int*>(_a[0]) = -1;
     }
-    _id -= 2;
+    _id -= 6;
   }
   return _id;
 }
diff --git a/ui/qt/qt6_shim_moc.cc b/ui/qt/qt6_shim_moc.cc
index 6d02ca317b65d..a16515008d892 100644
--- a/ui/qt/qt6_shim_moc.cc
+++ b/ui/qt/qt6_shim_moc.cc
@@ -26,8 +26,8 @@ QT_BEGIN_MOC_NAMESPACE
 QT_WARNING_PUSH
 QT_WARNING_DISABLE_DEPRECATED
 struct qt_meta_stringdata_qt__QtShim_t {
-  const uint offsetsAndSize[12];
-  char stringdata0[52];
+  const uint offsetsAndSize[26];
+  char stringdata0[151];
 };
 #define QT_MOC_LITERAL(ofs, len) \
   uint(offsetof(qt_meta_stringdata_qt__QtShim_t, stringdata0) + ofs), len
@@ -38,11 +38,21 @@ static const qt_meta_stringdata_qt__QtShim_t qt_meta_stringdata_qt__QtShim = {
         QT_MOC_LITERAL(23, 0),   // ""
         QT_MOC_LITERAL(24, 4),   // "font"
         QT_MOC_LITERAL(29, 14),  // "PaletteChanged"
-        QT_MOC_LITERAL(44, 7)    // "palette"
+        QT_MOC_LITERAL(44, 7),   // "palette"
+        QT_MOC_LITERAL(52, 11),  // "ScreenAdded"
+        QT_MOC_LITERAL(64, 8),   // "QScreen*"
+        QT_MOC_LITERAL(73, 6),   // "screen"
+        QT_MOC_LITERAL(80, 13),  // "ScreenRemoved"
+        QT_MOC_LITERAL(94, 25),  // "LogicalDotsPerInchChanged"
+        QT_MOC_LITERAL(120, 3),  // "dpi"
+        QT_MOC_LITERAL(124, 26)  // "PhysicalDotsPerInchChanged"
 
     },
     "qt::QtShim\0FontChanged\0\0font\0"
-    "PaletteChanged\0palette"};
+    "PaletteChanged\0palette\0ScreenAdded\0"
+    "QScreen*\0screen\0ScreenRemoved\0"
+    "LogicalDotsPerInchChanged\0dpi\0"
+    "PhysicalDotsPerInchChanged"};
 #undef QT_MOC_LITERAL
 
 static const uint qt_meta_data_qt__QtShim[] = {
@@ -51,7 +61,7 @@ static const uint qt_meta_data_qt__QtShim[] = {
     10,     // revision
     0,      // classname
     0, 0,   // classinfo
-    2, 14,  // methods
+    6, 14,  // methods
     0, 0,   // properties
     0, 0,   // enums/sets
     0, 0,   // constructors
@@ -59,11 +69,15 @@ static const uint qt_meta_data_qt__QtShim[] = {
     0,      // signalCount
 
     // slots: name, argc, parameters, tag, flags, initial metatype offsets
-    1, 1, 26, 2, 0x08, 1 /* Private */, 4, 1, 29, 2, 0x08, 3 /* Private */,
+    1, 1, 50, 2, 0x08, 1 /* Private */, 4, 1, 53, 2, 0x08, 3 /* Private */, 6,
+    1, 56, 2, 0x08, 5 /* Private */, 9, 1, 59, 2, 0x08, 7 /* Private */, 10, 1,
+    62, 2, 0x08, 9 /* Private */, 12, 1, 65, 2, 0x08, 11 /* Private */,
 
     // slots: parameters
     QMetaType::Void, QMetaType::QFont, 3, QMetaType::Void, QMetaType::QPalette,
-    5,
+    5, QMetaType::Void, 0x80000000 | 7, 8, QMetaType::Void, 0x80000000 | 7, 8,
+    QMetaType::Void, QMetaType::QReal, 11, QMetaType::Void, QMetaType::QReal,
+    11,
 
     0  // eod
 };
@@ -83,6 +97,22 @@ void qt::QtShim::qt_static_metacall(QObject* _o,
         _t->PaletteChanged(
             (*reinterpret_cast<std::add_pointer_t<QPalette>>(_a[1])));
         break;
+      case 2:
+        _t->ScreenAdded(
+            (*reinterpret_cast<std::add_pointer_t<QScreen*>>(_a[1])));
+        break;
+      case 3:
+        _t->ScreenRemoved(
+            (*reinterpret_cast<std::add_pointer_t<QScreen*>>(_a[1])));
+        break;
+      case 4:
+        _t->LogicalDotsPerInchChanged(
+            (*reinterpret_cast<std::add_pointer_t<qreal>>(_a[1])));
+        break;
+      case 5:
+        _t->PhysicalDotsPerInchChanged(
+            (*reinterpret_cast<std::add_pointer_t<qreal>>(_a[1])));
+        break;
       default:;
     }
   }
@@ -98,7 +128,15 @@ const QMetaObject qt::QtShim::staticMetaObject = {
          QtPrivate::TypeAndForceComplete<void, std::false_type>,
          QtPrivate::TypeAndForceComplete<const QFont&, std::false_type>,
          QtPrivate::TypeAndForceComplete<void, std::false_type>,
-         QtPrivate::TypeAndForceComplete<const QPalette&, std::false_type>
+         QtPrivate::TypeAndForceComplete<const QPalette&, std::false_type>,
+         QtPrivate::TypeAndForceComplete<void, std::false_type>,
+         QtPrivate::TypeAndForceComplete<QScreen*, std::false_type>,
+         QtPrivate::TypeAndForceComplete<void, std::false_type>,
+         QtPrivate::TypeAndForceComplete<QScreen*, std::false_type>,
+         QtPrivate::TypeAndForceComplete<void, std::false_type>,
+         QtPrivate::TypeAndForceComplete<qreal, std::false_type>,
+         QtPrivate::TypeAndForceComplete<void, std::false_type>,
+         QtPrivate::TypeAndForceComplete<qreal, std::false_type>
 
          >,
      nullptr}};
@@ -127,15 +165,15 @@ int qt::QtShim::qt_metacall(QMetaObject::Call _c, int _id, void** _a) {
     return _id;
   }
   if (_c == QMetaObject::InvokeMetaMethod) {
-    if (_id < 2) {
+    if (_id < 6) {
       qt_static_metacall(this, _c, _id, _a);
     }
-    _id -= 2;
+    _id -= 6;
   } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
-    if (_id < 2) {
+    if (_id < 6) {
       *reinterpret_cast<QMetaType*>(_a[0]) = QMetaType();
     }
-    _id -= 2;
+    _id -= 6;
   }
   return _id;
 }
diff --git a/ui/qt/qt_interface.h b/ui/qt/qt_interface.h
index 6a362bc66c0e3..28dfc6603544f 100644
--- a/ui/qt/qt_interface.h
+++ b/ui/qt/qt_interface.h
@@ -118,6 +118,7 @@ class QtInterface {
 
     virtual void FontChanged() = 0;
     virtual void ThemeChanged() = 0;
+    virtual void ScaleFactorMaybeChanged() = 0;
   };
 
   QtInterface() = default;
diff --git a/ui/qt/qt_shim.cc b/ui/qt/qt_shim.cc
index 74d34ad196f18..0aec9c3aed4ad 100644
--- a/ui/qt/qt_shim.cc
+++ b/ui/qt/qt_shim.cc
@@ -16,6 +16,7 @@
 #include <QMimeType>
 #include <QPainter>
 #include <QPalette>
+#include <QScreen>
 #include <QStyle>
 #include <QStyleOptionTitleBar>
 
@@ -52,8 +53,9 @@ FontHinting QtHintingToFontHinting(QFont::HintingPreference hinting) {
 // Obtain the average color of a gradient.
 SkColor GradientColor(const QGradient& gradient) {
   QGradientStops stops = gradient.stops();
-  if (stops.empty())
+  if (stops.empty()) {
     return qRgba(0, 0, 0, 0);
+  }
 
   float a = 0;
   float r = 0;
@@ -86,11 +88,13 @@ SkColor GradientColor(const QGradient& gradient) {
 // Obtain the average color of a texture.
 SkColor TextureColor(QImage image) {
   size_t size = image.width() * image.height();
-  if (!size)
+  if (!size) {
     return qRgba(0, 0, 0, 0);
+  }
 
-  if (image.format() != QImage::Format_ARGB32_Premultiplied)
+  if (image.format() != QImage::Format_ARGB32_Premultiplied) {
     image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
+  }
 
   size_t a = 0;
   size_t r = 0;
@@ -203,6 +207,13 @@ QtShim::QtShim(QtInterface::Delegate* delegate, int* argc, char** argv)
           SLOT(FontChanged(const QFont&)));
   connect(&app_, SIGNAL(paletteChanged(const QPalette&)), this,
           SLOT(PaletteChanged(const QPalette&)));
+  connect(&app_, SIGNAL(screenAdded(QScreen*)), this,
+          SLOT(ScreenAdded(QScreen*)));
+  connect(&app_, SIGNAL(screenRemoved(QScreen*)), this,
+          SLOT(ScreenRemoved(QScreen*)));
+  for (QScreen* screen : app_.screens()) {
+    ScreenAdded(screen);
+  }
 }
 
 QtShim::~QtShim() = default;
@@ -241,8 +252,9 @@ Image QtShim::GetIconForContentType(const String& content_type,
       auto icon = QIcon::fromTheme(name);
       auto pixmap = icon.pixmap(size);
       auto image = pixmap.toImage();
-      if (image.format() != QImage::Format_ARGB32_Premultiplied)
+      if (image.format() != QImage::Format_ARGB32_Premultiplied) {
         image = image.convertToFormat(QImage::Format_ARGB32_Premultiplied);
+      }
       if (auto bytes = image.sizeInBytes()) {
         return {image.width(), image.height(),
                 static_cast<float>(image.devicePixelRatio()),
@@ -283,6 +295,30 @@ void QtShim::PaletteChanged(const QPalette& palette) {
   delegate_->ThemeChanged();
 }
 
+DISABLE_CFI_VCALL
+void QtShim::ScreenAdded(QScreen* screen) {
+  connect(screen, SIGNAL(logicalDotsPerInchChanged(qreal)), this,
+          SLOT(LogicalDotsPerInchChanged(qreal)));
+  connect(screen, SIGNAL(physicalDotsPerInchChanged(qreal)), this,
+          SLOT(PhysicalDotsPerInchChanged(qreal)));
+  delegate_->ScaleFactorMaybeChanged();
+}
+
+DISABLE_CFI_VCALL
+void QtShim::ScreenRemoved(QScreen* screen) {
+  delegate_->ScaleFactorMaybeChanged();
+}
+
+DISABLE_CFI_VCALL
+void QtShim::LogicalDotsPerInchChanged(qreal dpi) {
+  delegate_->ScaleFactorMaybeChanged();
+}
+
+DISABLE_CFI_VCALL
+void QtShim::PhysicalDotsPerInchChanged(qreal dpi) {
+  delegate_->ScaleFactorMaybeChanged();
+}
+
 Image QtShim::DrawHeader(int width,
                          int height,
                          SkColor default_color,
@@ -309,8 +345,9 @@ QImage QtShim::DrawHeaderImpl(int width,
     QStyleOptionTitleBar opt;
     opt.rect = QRect(-kBorderWidth, -kBorderWidth, width + 2 * kBorderWidth,
                      height + 2 * kBorderWidth);
-    if (state == ColorState::kNormal)
+    if (state == ColorState::kNormal) {
       opt.titleBarState = QStyle::State_Active;
+    }
     app_.style()->drawComplexControl(QStyle::CC_TitleBar, &opt, &painter,
                                      nullptr);
   } else {
diff --git a/ui/qt/qt_shim.h b/ui/qt/qt_shim.h
index 607e6fe22dfc0..d979c47d589d4 100644
--- a/ui/qt/qt_shim.h
+++ b/ui/qt/qt_shim.h
@@ -42,6 +42,10 @@ class QtShim : public QObject, public QtInterface {
  private slots:
   void FontChanged(const QFont& font);
   void PaletteChanged(const QPalette& palette);
+  void ScreenAdded(QScreen* screen);
+  void ScreenRemoved(QScreen* screen);
+  void LogicalDotsPerInchChanged(qreal dpi);
+  void PhysicalDotsPerInchChanged(qreal dpi);
 
  private:
   QImage DrawHeaderImpl(int width,
diff --git a/ui/qt/qt_ui.cc b/ui/qt/qt_ui.cc
index 6a3b58e9f930b..bac5245a069f9 100644
--- a/ui/qt/qt_ui.cc
+++ b/ui/qt/qt_ui.cc
@@ -19,6 +19,7 @@
 #include "base/nix/xdg_util.h"
 #include "base/notreached.h"
 #include "base/path_service.h"
+#include "base/task/single_thread_task_runner.h"
 #include "base/time/time.h"
 #include "cc/paint/paint_canvas.h"
 #include "chrome/browser/themes/theme_properties.h"  // nogncheck
@@ -36,6 +37,7 @@
 #include "ui/gfx/image/image.h"
 #include "ui/gfx/image/image_skia_rep.h"
 #include "ui/gfx/image/image_skia_source.h"
+#include "ui/linux/device_scale_factor_observer.h"
 #include "ui/linux/linux_ui.h"
 #include "ui/linux/nav_button_provider.h"
 #include "ui/native_theme/native_theme_aura.h"
@@ -194,16 +196,21 @@ void QtUi::GetDefaultFontDescription(std::string* family_out,
                                      int* style_out,
                                      int* weight_out,
                                      gfx::FontRenderParams* params_out) const {
-  if (family_out)
+  if (family_out) {
     *family_out = font_family_;
-  if (size_pixels_out)
+  }
+  if (size_pixels_out) {
     *size_pixels_out = font_size_pixels_;
-  if (style_out)
+  }
+  if (style_out) {
     *style_out = font_style_;
-  if (weight_out)
+  }
+  if (weight_out) {
     *weight_out = font_weight_;
-  if (params_out)
+  }
+  if (params_out) {
     *params_out = font_params_;
+  }
 }
 
 ui::SelectFileDialog* QtUi::CreateSelectFileDialog(
@@ -236,6 +245,7 @@ bool QtUi::Initialize() {
   ui::ColorProviderManager::Get().AppendColorProviderInitializer(
       base::BindRepeating(&QtUi::AddNativeColorMixer, base::Unretained(this)));
   FontChanged();
+  scale_factor_ = shim_->GetScaleFactor();
 
   return true;
 }
@@ -246,8 +256,9 @@ ui::NativeTheme* QtUi::GetNativeTheme() const {
 
 bool QtUi::GetColor(int id, SkColor* color, bool use_custom_frame) const {
   auto value = GetColor(id, use_custom_frame);
-  if (value)
+  if (value) {
     *color = *value;
+  }
   return value.has_value();
 }
 
@@ -297,8 +308,9 @@ gfx::Image QtUi::GetIconForContentType(const std::string& content_type,
                                        float scale) const {
   Image image =
       shim_->GetIconForContentType(String(content_type.c_str()), size * scale);
-  if (!image.data_argb.size())
+  if (!image.data_argb.size()) {
     return {};
+  }
 
   SkImageInfo image_info = SkImageInfo::Make(
       image.width, image.height, kBGRA_8888_SkColorType, kPremul_SkAlphaType);
@@ -345,14 +357,16 @@ bool QtUi::AnimationsEnabled() const {
 
 void QtUi::AddWindowButtonOrderObserver(
     ui::WindowButtonOrderObserver* observer) {
-  if (fallback_linux_ui_)
+  if (fallback_linux_ui_) {
     fallback_linux_ui_->AddWindowButtonOrderObserver(observer);
+  }
 }
 
 void QtUi::RemoveWindowButtonOrderObserver(
     ui::WindowButtonOrderObserver* observer) {
-  if (fallback_linux_ui_)
+  if (fallback_linux_ui_) {
     fallback_linux_ui_->RemoveWindowButtonOrderObserver(observer);
+  }
 }
 
 std::unique_ptr<ui::NavButtonProvider> QtUi::CreateNavButtonProvider() {
@@ -441,11 +455,24 @@ void QtUi::ThemeChanged() {
   native_theme_->ThemeChanged(PreferDarkTheme());
 }
 
+void QtUi::ScaleFactorMaybeChanged() {
+  // This gets called whenever the monitor configuration changes.  Handle the
+  // scale change asynchronously to allow the change to propagate to QT's scale
+  // factor. This also coalesces scale change events together.
+  if (!scale_factor_task_active_) {
+    scale_factor_task_active_ = true;
+    base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask(
+        FROM_HERE, base::BindOnce(&QtUi::ScaleFactorMaybeChangedImpl,
+                                  weak_factory_.GetWeakPtr()));
+  }
+}
+
 DISABLE_CFI_VCALL
 void QtUi::AddNativeColorMixer(ui::ColorProvider* provider,
                                const ui::ColorProviderManager::Key& key) {
-  if (key.system_theme != ui::SystemTheme::kQt)
+  if (key.system_theme != ui::SystemTheme::kQt) {
     return;
+  }
 
   ui::ColorMixer& mixer = provider->AddMixer();
   // These color constants are required by native_chrome_color_mixer_linux.cc
@@ -494,8 +521,9 @@ void QtUi::AddNativeColorMixer(ui::ColorProvider* provider,
        ColorState::kInactive},
       {ui::kColorNativeToolbarBackground, ColorType::kButtonBg},
   };
-  for (const auto& map : kMaps)
+  for (const auto& map : kMaps) {
     mixer[map.id] = {shim_->GetColor(map.role, map.state)};
+  }
 
   const bool use_custom_frame =
       key.frame_type == ui::ColorProviderManager::FrameType::kChromium;
@@ -578,6 +606,20 @@ absl::optional<SkColor> QtUi::GetColor(int id, bool use_custom_frame) const {
   }
 }
 
+DISABLE_CFI_VCALL
+void QtUi::ScaleFactorMaybeChangedImpl() {
+  scale_factor_task_active_ = false;
+  double scale = shim_->GetScaleFactor();
+  if (scale == scale_factor_) {
+    return;
+  }
+  scale_factor_ = scale;
+  for (ui::DeviceScaleFactorObserver& observer :
+       device_scale_factor_observer_list()) {
+    observer.OnDeviceScaleFactorChanged();
+  }
+}
+
 std::unique_ptr<ui::LinuxUiAndTheme> CreateQtUi(
     ui::LinuxUi* fallback_linux_ui) {
   return std::make_unique<QtUi>(fallback_linux_ui);
diff --git a/ui/qt/qt_ui.h b/ui/qt/qt_ui.h
index b53ed93240708..3319edf1ea9bc 100644
--- a/ui/qt/qt_ui.h
+++ b/ui/qt/qt_ui.h
@@ -8,6 +8,7 @@
 #include <memory>
 
 #include "base/component_export.h"
+#include "base/memory/weak_ptr.h"
 #include "printing/buildflags/buildflags.h"
 #include "third_party/abseil-cpp/absl/types/optional.h"
 #include "ui/color/color_provider.h"
@@ -88,11 +89,14 @@ class QtUi : public ui::LinuxUiAndTheme, QtInterface::Delegate {
   // QtInterface::Delegate:
   void FontChanged() override;
   void ThemeChanged() override;
+  void ScaleFactorMaybeChanged() override;
 
  private:
   void AddNativeColorMixer(ui::ColorProvider* provider,
                            const ui::ColorProviderManager::Key& key);
 
+  void ScaleFactorMaybeChangedImpl();
+
   absl::optional<SkColor> GetColor(int id, bool use_custom_frame) const;
 
   // TODO(https://crbug.com/1317782): This is a fallback for any unimplemented
@@ -114,6 +118,11 @@ class QtUi : public ui::LinuxUiAndTheme, QtInterface::Delegate {
   std::unique_ptr<QtInterface> shim_;
 
   std::unique_ptr<QtNativeTheme> native_theme_;
+
+  bool scale_factor_task_active_ = false;
+  double scale_factor_ = 1.0;
+
+  base::WeakPtrFactory<QtUi> weak_factory_{this};
 };
 
 // This should be the only symbol exported from this component.