Open Bug 1258112 Opened 9 years ago Updated 6 months ago

Firefox's border pixel-snapping behavior causes thin borders to disappear entirely when scaled down (e.g. via CSS Transform or print-preview)

Categories

(Core :: Graphics: WebRender, defect)

44 Branch
defect

Tracking

()

People

(Reporter: hildobijl, Unassigned)

References

(Blocks 1 open bug)

Details

(Keywords: reproducible)

Attachments

(2 files)

User Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.87 Safari/537.36 Steps to reproduce: Here's a JSFiddle as an example. https://jsfiddle.net/mxoa9s60/ In other words: make a div with a CSS scale property. Put inside of it a div with a (thin) border. Then watch how this border is affected by the scale. Actual results: The borders on the four sides are of different width. And this width is very unpredictable. Sometimes a border disappears altogether for low scales. But if you make the scale even lower, the border reappears and a border on some other side disappears. It's crazy. Expected results: The borders should all remain the same width. (And remain visible.) To be precise, when a border of "0.8px" is scaled by a factor "0.5", the resulting border should look exactly like it would've looked when given the width "0.4px" without scaling. Google Chrome does this well enough. Firefox doesn't.
Component: Untriaged → CSS Parsing and Computation
Product: Firefox → Core
Status: UNCONFIRMED → NEW
Has STR: --- → yes
Ever confirmed: true
Keywords: reproducible
See Also: → 1490361

Clarifying what sorts of outcomes are realistic here:

(In reply to Hildo Bijl from comment #0)

Expected results:

The borders should all ... remain visible

Let's focus on this^ request; I think this is the least-controversial expectation here.

To be
precise, when a border of "0.8px" is scaled by a factor "0.5", the resulting
border should look exactly like it would've looked when given the width
"0.4px" without scaling.

This is a reasonable intuition but it's a non-goal and is not actually how borders work in any browser.

In the absence of transforms, I think all browsers snap borders to whole-number display-pixel-values (at least, they do for borders less than 1px) -- so e.g. 0.4px will just round up to one display-pixel (and so will 0.01px), at computed-value-time (i.e. and it actually reserves & occupies that much layout space, rather than the specified tiny-fraction-of-a-pixel). This is interoperable and required for compatibility; you can try e.g. data:text/html,<div style="border: 0.01px solid black">Hi in various browsers and see that it occupies a full display-pixel (e.g. it's equivalent to border:1px solid black on a traditional non-HiDPI display resolution).

In contrast, transform:scale(0.5) is a paint-time effect and we don't get the opportunity to make the border specially-reserve-and-occupy a full display pixel of layout space when we apply a scaling transform. Chrome seems to use antialiasing to paint the scaled-down partial-pixel-width-border, whereas Firefox seems to still try to paint a whole number of pixels (possibly 0); we round down to 0px for sufficiently-small scales / sufficiently-thin borders. This outcome is not-great; ideally we should allow ourselves to paint fractional-width-borders as antialiased partial-pixels when we're scaling them, I think.

Also FWIW, I can see that the original testcase here renders without a top black border in old Firefox nightlies e.g. Firefox Nightly 48.0a1 (2016-03-19), but the whole black border paints in current Firefox Nightly (2022-06-21).

But if I reduce the scale to e.g. 0.2 or 0.5, I can still reproduce (the black border disappears).

I've got a clearer/more-comprehensive testcase on my dupe bug, which I'll repost here for clarity/convenience.

Attachment #8732527 - Attachment description: reporter's testcase → reporter's testcase (might not repro the bug anymore unless you use devtools to reduce the transform:scale(...) fraction)

screenshot of reduced testcase 1 in Firefox vs Chrome: https://bugzilla.mozilla.org/attachment.cgi?id=9282271

Summary: Firefox scales borders unequally, and sometimes the borders disappear altogether by scaling → Firefox's border pixel-snapping behavior causes thin borders to disappear entirely when scaled down (e.g. via CSS Transform or print-preview)
See Also: → 1784322
Severity: normal → S3

The severity field for this bug is relatively low, S3. However, the bug has 5 duplicates.
:emilio, could you consider increasing the bug severity?

For more information, please visit auto_nag documentation.

Flags: needinfo?(emilio)

Other browsers are going to match our behavior here and it's not clear there's a terribly-better behavior around. We could make WebRender force 1 dev px borders at paint-time too, but...

Flags: needinfo?(emilio)
See Also: → 1796718

(In reply to Emilio Cobos Álvarez (:emilio) from comment #12)

Other browsers are going to match our behavior here and it's not clear there's a terribly-better behavior around

Do we know if/when that's going to happen? I think some of it was happening in https://issues.chromium.org/issues/40178820 for a little while, but I'm still seeing Chrome and WebKit both render my attached reduced testcase 1 with fuzzy antialiased borders. I'm not sure if that's because they have special-cases for borders less than 1px wide, or if they never finished implementing this change, or something else.

Even if other browsers do end up matching us here, we might want to add some sort of mitigation for print-preview in particular (like the WebRender mitigation in comment 12), to avoid having borders mysteriously disappear in print-preview, per the last bit of bug 1775345 comment 0 (see screenshot https://bug1775345.bmoattachments.org/attachment.cgi?id=9282272 ).

(This came across my radar again today because I was print-previewing a page that had a <table> with 1px-thick borders, with some bordered empty cells on the final page. That final page just looked entirely blank in print-preview, which was confusing & looked like Firefox was mistakenly generating a final blank page.)

Looking at the Blink bug about border-snapping, it seems their feature-flag for this was called SnapBorderWidthsBeforeLayout which shipped to release in v109 per https://chromestatus.com/feature/4651561863610368 and seems to have stuck. I think that (and the associated WebKit changes) are the thing that Emilio was referring to in comment 12 as other-browsers-going-to-match-us (correct me if I'm wrong though).

I think the last paragraph of my comment 3 is still an accurate description of the compat situation here -- Firefox optimizes for keeping borders crisp, even in the face of transform with fractional scales, whereas other browsers do not (and hence scaled-down borders still show up [albeit in a fuzzy/antialiased form] for them, whereas they entirely disappear for us).

Duplicate of this bug: 1888270

I think we should move this to graphics given the comments above. If we were to fix this, it should be by antialiasing borders, not by changing layout / style computation.

Component: CSS Parsing and Computation → Graphics: WebRender
Blocks: wr-snap
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: