Browse Source

LibWeb: Properly round CSSPixels values in device_to_css_rect

Ceiling width or height of a chrome viewport (this function is only used
when a chrome notifies LibWeb about a new viewport size) is never
correct. If we do that, PageClient::page_did_layout will set content
size to be 1 larger than an actual physical width or height respectively
(it always ceils) and thus a spurious scrollbar will appear.

This prevents occasional scrollbar flickering in Ladybird/Qt on Wayland
with fractional scaling enabled on compositors supporting
wp-fractional-scale-v1.
Dan Klishch 1 year ago
parent
commit
56d355a15e
2 changed files with 13 additions and 4 deletions
  1. 4 4
      Userland/Libraries/LibWeb/Page/Page.cpp
  2. 9 0
      Userland/Libraries/LibWeb/PixelUnits.h

+ 4 - 4
Userland/Libraries/LibWeb/Page/Page.cpp

@@ -120,10 +120,10 @@ CSSPixelRect Page::device_to_css_rect(DevicePixelRect rect) const
 {
     auto scale = client().device_pixels_per_css_pixel();
     return {
-        rect.x().value() / scale,
-        rect.y().value() / scale,
-        rect.width().value() / scale,
-        rect.height().value() / scale
+        CSSPixels::nearest_value_for(rect.x().value() / scale),
+        CSSPixels::nearest_value_for(rect.y().value() / scale),
+        CSSPixels::floored_value_for(rect.width().value() / scale),
+        CSSPixels::floored_value_for(rect.height().value() / scale),
     };
 }
 

+ 9 - 0
Userland/Libraries/LibWeb/PixelUnits.h

@@ -98,6 +98,15 @@ public:
         return from_raw(raw_value);
     }
 
+    template<FloatingPoint F>
+    static CSSPixels floored_value_for(F value)
+    {
+        i32 raw_value = 0;
+        if (!isnan(value))
+            raw_value = AK::clamp_to<int>(floor(value * fixed_point_denominator));
+        return from_raw(raw_value);
+    }
+
     template<Unsigned U>
     constexpr CSSPixels(U value)
     {