Gecko:CSSBorderRenderingWithShaders
Problem Statement
Our border-rendering problem can be reduced to the following parameters:
- For each side, a border style: one of SOLID, DASHED, DOTTED.
- For each side, a list of (color, width) pairs (say listing the colors from outside in). The list is empty if the side has no border.
- An outer rectangle.
- Horizontal and vertical radii for each corner.
Approach
- Divide the border into its 8 parts (some of which may be empty): 4 corners and 4 sides. We can do
simpler/faster things for sides.
- For each pixel:
- Compute the value of the pixel as if all border styles are SOLID
- Multiply its alpha value by a mask based on DASHED/DOTTED styles
Computing Color Values For Side Pixels
Just sample a 1D texture based on the distance of the pixel from the outer rectangle edge.
Computing Color Values For Corner Pixels
Precalculate the line segment where the two sides meet. bug 652650 has experiments and code for the best way to do this.
Assuming the pixel is on one side of that line, compute its distance to the outside border edge (hopefully bug 652650 has a method for that too) and use that to sample the 1D texture for that side.
Then do the same thing assuming the pixel is on the other side of the line.
Then combine the two values based on which side of the line (and how far from the line) the pixel actually is.
Computing Masks
Precalculate where the dots and/or dashes for each side are supposed to go. bug 652650 has experiments and code for this. I think we should ensure that there's a dot or dash centered on each corner (using a half-dot or half-dash if the style changes there); where a border side doesn't have enough room for at least a half-dash/half-dot, a gap, and then another half-dash/half-dot, we should just draw solid.
Then for a given pixel, if it's in a corner and doesn't clearly belong to one side or another, it must be part of a solid border or inside a dot or dash, so the mask value is 1.
Otherwise we know which side the pixel is on. We can compute where the nearest dash or dot must be, and test whether the pixel is inside the dash or dot (and draw antialiased if it's near the edge).