layout: Use an accurately-sized clipping rectangle for box-shadow display list item properties instead of MaxRect (#44457)

Mobile phone runs OpenGL Embedded System. The precision is limited
comparing to Desktop which runs full OpenGL. This caused a bug where
box-shadow is not displayed on Android/OHOS. Instead of using an
infinite clip rect, we compute a bounded one. This should save some GPU
work as well.

Reference: [How to gracefully handle highp/mediump switch for mobile
Android
browsers?](https://discourse.threejs.org/t/how-to-gracefully-handle-highp-mediump-switch-for-mobile-android-browsers/77335)


Testing: Desktop WPT
[unchanged](https://github.com/servo/servo/actions/runs/24825758325).
Manually tested on Android/Ohos. Now look same as Firefox/Chrome.

| Before | After |
| -------- | -------- |
|
![Screenshot_20260423_154114.jpg](https://github.com/user-attachments/assets/b1c970c8-a30c-4fb8-acbc-c97fa9cc03f9)
|
![screenshot_20260423_154059_1776930134.jpg](https://github.com/user-attachments/assets/432a29c4-0c5c-4ff2-83eb-81db55e76f64)
|


Fixes: #44431
Closes: https://github.com/servo/webrender/pull/4879

---------

Signed-off-by: Euclid Ye <yezhizhenjiakang@gmail.com>
This commit is contained in:
Euclid Ye
2026-04-24 02:03:51 +08:00
committed by GitHub
parent 9189fe06a5
commit 464ae8204f

View File

@@ -17,7 +17,6 @@ use servo_arc::Arc as ServoArc;
use servo_base::id::{PipelineId, ScrollTreeNodeId};
use servo_config::opts::DiagnosticsLogging;
use servo_config::{pref, prefs};
use servo_geometry::MaxRect;
use servo_url::ServoUrl;
use style::Zero;
use style::color::{AbsoluteColor, ColorSpace};
@@ -1889,8 +1888,7 @@ impl<'a> BuilderForBoxFragment<'a> {
return;
}
// NB: According to CSS-BACKGROUNDS, box shadows render in *reverse* order (front to back).
let common = builder.common_properties(MaxRect::max_rect(), &style);
// Note: According to CSS-BACKGROUNDS, box shadows render in *reverse* order (front to back).
for box_shadow in box_shadows.iter().rev() {
let (rect, clip_mode) = if box_shadow.inset {
(*self.padding_rect(), BoxShadowClipMode::Inset)
@@ -1898,6 +1896,17 @@ impl<'a> BuilderForBoxFragment<'a> {
(self.border_rect, BoxShadowClipMode::Outset)
};
let offset = LayoutVector2D::new(
box_shadow.base.horizontal.px(),
box_shadow.base.vertical.px(),
);
let spread = box_shadow.spread.px();
let blur = box_shadow.base.blur.px();
let shifted = rect.translate(offset);
let spread_rect = shifted.inflate(spread, spread);
let shadow_rect = spread_rect.inflate(blur, blur);
let common = builder.common_properties(rect.union(&shadow_rect), &style);
builder.wr().push_box_shadow(
&common,
rect,