Closed Bug 2004666 Opened 7 months ago Closed 28 days ago

Gitlab right sidebar text jitters while scrolling with pixel alignment disabled

Categories

(Core :: Graphics: WebRender, defect, P2)

Firefox 148
defect

Tracking

()

RESOLVED FIXED
153 Branch
Tracking Status
firefox148 --- wontfix
firefox153 --- fixed
firefox154 --- fixed

People

(Reporter: ke5trel, Assigned: gw)

References

(Blocks 1 open bug)

Details

Attachments

(4 files)

STR:

  1. Set layout.disable-pixel-alignment = true on latest Nightly 147.0a1 on Ubuntu 25.10.
  2. Visit https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4703.
  3. Rapidly scroll up and down the page.

Expected:
Right sidebar contents remain stable while scrolling.

Actual:
Right sidebar text jitters up and down slightly while scrolling.

Method of scrolling doesn't matter, occurs with mousehweel, scrollbar and autoscroll.

Not a regression, reproducible back to introduction of pixel alignment setting.

Severity: -- → S3
Priority: -- → P2
Assignee: nobody → mozilla

Under layout.disable-pixel-alignment, content rasterized into a tile cache
whose raster node is in the root coordinate system but is not root itself
(sticky / scrolled / fixed) was snapped against the cache's own node. That
is a no-op, so glyphs and line decorations inherited the cache's fractional
composite offset and jittered sub-pixel while scrolling.

  • SpaceSnapper: snap root-coordinate-system surfaces against root rather
    than the surface's own raster node. Snapping can also cross a coordinate-system
    boundary when the relative transform is a 90/180/270-degree rotation or reflection,
    which maps the device grid onto itself; such a frame is decomposed into a ScaleOffset
    plus an x/y swap. Genuinely scaled / perspective raster roots keep the own-node snap.
  • Text runs snap their reference-frame origin against root via the full prim-to-root
    transform rather than against the surface's raster space.
  • nsCSSRendering: when pixel alignment is disabled, only skip pre-snapping the
    text-decoration geometry when it is drawn through WebRender's text path (which
    device-snaps it at frame time); software / non-WebRender-text drawing
    (e.g. drawSnapshot) keeps pre-snapping.
Status: NEW → RESOLVED
Closed: 1 month ago
Resolution: --- → FIXED
Target Milestone: --- → 153 Branch
Blocks: 1971253
QA Whiteboard: [qa-triage-done-c154/b153]

Still reproducible on latest Nightly 154.0a1 (2026-06-17) on Ubuntu 26.04. Easier to reproduce at 100% display scaling than 125%.

Status: RESOLVED → REOPENED
Resolution: FIXED → ---

I can repro at 100% display scaling - it looks like this is a float accuracy issue - things land exactly on 0.5 pixels and then the float math sometimes ends up flipping those -0.5px or +0.5px.

(that is, the landed fix above is good and correct, but there is an additional issue which shows up when things land right on 0.5 device px boundaries).

The display-list builder reconstitutes a reference frame's origin as a
scrolled-space value plus a re-added external scroll offset. At large scroll
magnitudes that f32 round-trip loses a few low bits, leaving the origin a
fraction off its intended sub-pixel position. When that lands on the
device-pixel snap tie, snapped content inside the reference frame (e.g. a
position:sticky element) flips +/-1px frame-to-frame as the scene is rebuilt
while scrolling.

Quantize the origin to a 1/128 px grid in SceneSpatialNode::new_reference_frame.
This removes the float noise while preserving genuine sub-pixel placement, and
operates in WebRender coordinate space so it is device-pixel-scale independent.

Note that this is a kludge - we should eventually aim to do this math in exact
coordinates such that we don't have this float accuracy loss.

Status: REOPENED → RESOLVED
Closed: 1 month ago28 days ago
Resolution: --- → FIXED
Regressions: 2050692

I'm still not able to repro this locally - I think it will be related to the first patch in this bug though, rather than the second one. Investigating today.

Minimized wrench repro reftest:

root:
  items:
    - type: stacking-context
      bounds: [100.5, 80, 300, 100]
      transform: identity()
      is-2d: true
      items:
        - type: text
          text: "XXXXXXXX"
          origin: [0, 30]
          size: 32
          color: [0, 0, 0, 1]
          font: "Ahem.ttf"
root:
  items:
    - type: text
      text: "XXXXXXXX"
      origin: [100.5, 110]
      size: 32
      color: [0, 0, 0, 1]
      font: "Ahem.ttf"

You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: