Closed Bug 328241 Opened 18 years ago Closed 17 years ago

Anti-aliasing problem with joining borders

Categories

(Core :: Graphics, defect)

x86
All
defect
Not set
normal

Tracking

()

RESOLVED FIXED

People

(Reporter: maikelkrause, Assigned: vlad)

References

Details

(Keywords: regression, testcase)

Attachments

(5 files, 1 obsolete file)

User-Agent:       Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a1) Gecko/20060222 Firefox/1.6a1
Build Identifier: Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.9a1) Gecko/20060222 Firefox/1.6a1

There seems to be an anti-aliasing problem between borders. This can be easily seen on the Acid2 test for instance, which uses such techniques to form squares.

Reproducible: Always

Steps to Reproduce:
1. Open attached testcase
Actual Results:  
Lines are visible where borders join.

Expected Results:  
Should see a perfect black square.
Attached file Testcase
Should see a perfect square.
Attached image Screenshot (winXP)
nope, i see it.
Status: UNCONFIRMED → NEW
Ever confirmed: true
Attached file Another testcase (obsolete) —
Here the bug is more visible than in the first testcase.
Attached file Another testcase
Testcase with doctype (to compare with Opera's rendering)
Attachment #213309 - Attachment is obsolete: true
According to bug 289480 (comment 289480#93) this bug created a regression in acid2 test rendering.
...which is what comment #0 already says...
Ryan, I'm not the QA contact for this bug. Therefore I do not need to read it all.  I just wanted to be helpful. 

Thanks for spamming the bug (with your comment and my compulsory reply).
Keywords: regression, testcase
Might be a good information that the bug is caused by a check-in that happened between 2006-01-24 and 2006-02-10. Anybody having builds from that timeframe should run either Acid2 or one of these testcases to identify the real time of the buggy check-in.
Correction: This bug has appeared in the Cairo branch with build 2005-11-09-13, much before its appearance in the trunk. It's invisible in build 2005-11-09-08. Maybe we should check what changes were made to the Cairo branch in that timeframe to find the check-in causing this bug.
What's the branch tag for the brach referenced in comment 10?
Blocks: acid2
Flags: blocking1.9a1?
This isn't a css rendering issue, sorry that I didn't see the bug sooner -- it has to do with how borders are rendered through gfx.  Lines and polygon edges were not antialiased before, now they are; this is causing this boundary issue.  There are a few potential fixes, but I'd need to talk to dbaron/bz/someone to figure out what the right way to do it is.

Ideally, the border rendering code would combine same-color border pieces into a single polygon to render instead of rendering them as 4 separate polygons always.  Also, that code can probably be simplified quite a bit; it goes through great pains (if I remember right) to do things like rendering width-2 borders as 2 lines instead of doing a polygon render.
Well, it's not that simple, since the borders can be different colors, but we don't want an approximation of the background in the middle even if they are.  Given anti-aliasing, cairo really needs an api for filling multiple polygons at once, in different colors, that avoids this issue.  I can't think off the top of my head how one would implement such an API, actually, but I'm not a graphics expert.  (And given dashed and dotted borders, it may be a lot of polygons.)
> Ideally, the border rendering code would combine same-color border pieces into
> a single polygon to render 

I'm not sure the simple case of 4 borders all of the same color (as here) can be expressed as a single polygon without running into this bug somewhere.  I'd love to be proved wrong, of course.  ;)
(In reply to comment #14)
> > Ideally, the border rendering code would combine same-color border pieces into
> > a single polygon to render 
> 
> I'm not sure the simple case of 4 borders all of the same color (as here) can
> be expressed as a single polygon without running into this bug somewhere.  I'd
> love to be proved wrong, of course.  ;)

Hmm, I'm not sure why not (I guess I should have said path, not necessarily polygon.. as I'm thinking of a polygon with holes :).. as dbaron points out though, we'd have a similar problem at different-color border joins, it would just be less visible (but no less wrong).
Attached file one more testcase
There's not much here that attachment 213310 [details] doesn't cover (just the dashed border, really), but attaching another one anyway.
Actually, I /think/ this may also be caused by us offsetting the coordinates of one side of each border side by 1, to get no overlap, whereas in this case we do want overlap.  That will give us overdraw in the case of translucent colors, though, but there's another way we can draw borders with translucency.  (Assuming they all have the same opacity -- if you have 4 borders with different opacities... that's just pain, I think.)

I think this is just an example of the generic seams problem that occurs when rendering using coverage-based antialiasing. It's popping up elsewhere, like when you render a rotated HTML page that contains a mosaic of images or elements (e.g. Google Maps).

The only solution IMHO is to turn off coverage-based antialiasing wherever it causes such problems, and use supersampling instead when resources are available.
I'd agree with that; this type of antialiasing would be really annoying for Web designers.
I would also vote at removing this type of antialiasing, as it only causes problems.
Stefanik, most of those testcases have nothing to do with this bug. The blurryness is caused by bug 324698.
The green border of http://www.hixie.ch/tests/evil/css/css21/tests/t1008-c44-ln-box-02-d-ag.xht really shows this bug, though. (Look at the corners of the frame!)
Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9a1) Gecko/20060407 Firefox/3.0a1

Using the testcases in this bug, I can confirm this on Linux.
OS: Windows XP → All
So here's an easy patch to fix this for the interim, until we can come up with a better solution.  This will disable AA for square borders (not for -moz-border-radius).

Some of the future solutions dbaron and I talked about:

1) For the common case where all sides of the border either have the same color (or are not present), render the entire border as one path.

2) If the borders have different colors but are at 100% opacity, then we need to adjust the generated polygons such that they truly overlap at the corners -- right now the border rendering code explicitly makes sure that they don't overlap, and tightly controls which side gets the extra pixel.  For the antialiasing to look right, the diagonal line from each border side should be drawn in the same location, not adjacant to eachother.

3) If the borders have different colors and are all at the same opacity (but not 100%), we render the borders at 100% opacity in a subsurface and then paint that in at whatever the desired opacity is (giving us the same output as #2, with a constant opacity).

4) If the borders have different colors and different opacities, then we've got some trouble.  What should the joinining line look like between a 30% opacity red left border and 50% opacity blue top border?  My initial thought is a 40% opacity red-blue join, so that there is a smooth progression for the 30% to the 50%.  Alternatively, in this non-common case, we could fall back to just not doing antialiasing here.
Assignee: nobody → vladimir
Status: NEW → ASSIGNED
Attachment #219188 - Flags: review?
Attachment #219188 - Flags: review? → review?(dbaron)
Comment on attachment 219188 [details] [diff] [review]
disable antialiasing for borders, for now

This patch looks fine.  (It reminds me that I really need to fix dashed/dotted border drawing at some point to do the right thing, but that's bug 19963.)


5) I think there's also a fifth possibility.  I think it *should* be possible to do additional drawing on top that will fix up the edge.  In particular, I'd think you could implement a function that took a path and two colors (where the first color was painted first, and on the left side of the path, and the second color was painted afterwards, and on the right side of the path) and do additional drawing on all pixels that are crossed by the path to get them to the correct color, modulo a small amount of rounding error accumulation.  (Of course, such a function would have problems at pixels that were both crossed by the path and not completely covered by the two regions -- but that shouldn't be an issue in this case.)
Attachment #219188 - Flags: review?(dbaron) → review+
(In reply to comment #26)
> (From update of attachment 219188 [details] [diff] [review] [edit])
> This patch looks fine.  (It reminds me that I really need to fix dashed/dotted
> border drawing at some point to do the right thing, but that's bug 19963.)

Checked in.

> 5) I think there's also a fifth possibility.  I think it *should* be possible
> to do additional drawing on top that will fix up the edge.  In particular, I'd
> think you could implement a function that took a path and two colors (where the
> first color was painted first, and on the left side of the path, and the second
> color was painted afterwards, and on the right side of the path) and do
> additional drawing on all pixels that are crossed by the path to get them to
> the correct color, modulo a small amount of rounding error accumulation.  (Of
> course, such a function would have problems at pixels that were both crossed by
> the path and not completely covered by the two regions -- but that shouldn't be
> an issue in this case.)

Hmm, maybe; this should be doable in the case of opaque borders, but with any sort of translucent borders it becomes hard.. the final result depends on what's underneath, and we would have already drawn a "wrong" antialiased border there already.  I'm not sure if it would be possible in that case.
> the final result depends on
> what's underneath, and we would have already drawn a "wrong" antialiased border
> there already.  I'm not sure if it would be possible in that case.

Couldn't you clip the drawing in a way that the wrong stuff won't be drawn?
In the cases with alpha, however, the issue would be that too little was drawn, not too much, so drawing something else with alpha on top ought to be able to correct the problem unless the math is nonlinear.
I have not yet had the chance to look into the provided test cases in detail, nor what the geometry and constraints of "borders" even are.

The various proposed workarounds for the problem seem reasonable, but I think there are still some possible fixes for the problem that have not been discussed here. Specifically, between Vlad's #3 (draw opaque to intermediate surface, then blend result) but before #4 (disable antialiasing), there are generalizations of #3 that will support various alpha values of the connecting objects. The trick is to carefully use ADD or SATURATE operators.

Ee've had discussions about seams issues like this on the cairo list before. Here's an example of an SVG file that was provided to the cairo list as a very hard case to avoid the seams problem:

http://cairographics.org/~cworth/images/star_and_ring.svg

This is a particularly challenging figure since the two objects mutually overlap each other and both are translucent. SVG is 2.5-dimensional, so can't actually express mutually overlapping figures directly. So the objects in the SVG file here have been pre-sliced, which is what introduces the seams problem.

Here's a post from me showing an approach that achieves the desired result:

http://lists.freedesktop.org/archives/cairo/2005-March/003457.html

What I did not provide there was an algorithm for taking the original pre-sliced objects and also drawing the correct result. (Owen Taylor did later sketch out something that would be possible to implement, but might require some rather elaborate data structures (BSP say) in order to be efficient:

http://lists.freedesktop.org/archives/cairo/2005-March/003461.html

But, if the problematic edges are "known" to the programmer, then an approach like I show above might be helpful, without requiring anything like Owen described. (Here is where I don't know the constraints of the problem being attempted in this bug report.)

And while we're throwing things out, another general solution is to use the SATURATE operator and drawing objects front-to-back. This is similar to what OpenGL does to avoid seams, and has been demonstrated to be an effective approach with cairo by a gnuplot developer, (modulo some correctness bugs in the X server implementation of SATURATE).

Anyway, I hope some of that might be relevant or helpful.

-Carl
See also bug 342262, "Antialiasing causes seams in rotated HTML content".
Blocks: b-order
Flags: blocking1.9a1? → blocking1.9-
Whiteboard: [wanted-1.9]
Fixed by patch for bug 368247.
Status: ASSIGNED → RESOLVED
Closed: 17 years ago
Resolution: --- → FIXED
Shouldn't we back out the no-antialiasing patch now that we got antialiasing right?
Flags: wanted1.9+
Whiteboard: [wanted-1.9]
I would love to see this re-opened to add antialiasing back in with a real fix instead of just removing it. Joining borders look pretty bad in FireFox at the moment.
Scott, reopening is generally reserved for when patches get backed out.  If you want a followup fix, please file a separate bug.
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: