Fix CSS border rounding and currentcolor clipping

This commit is contained in:
Basilisk-Dev 2026-05-09 14:27:59 -04:00 committed by wuggy
commit 84b9b77335
10 changed files with 147 additions and 21 deletions

View file

@ -1743,7 +1743,9 @@ nsCSSRendering::PaintBackground(const PaintBGParams& aParams)
} }
static bool static bool
IsOpaqueBorderEdge(const nsStyleBorder& aBorder, mozilla::Side aSide) IsOpaqueBorderEdge(const nsStyleBorder& aBorder,
const nsStyleColor& aColor,
mozilla::Side aSide)
{ {
if (aBorder.GetComputedBorder().Side(aSide) == 0) if (aBorder.GetComputedBorder().Side(aSide) == 0)
return true; return true;
@ -1765,25 +1767,20 @@ IsOpaqueBorderEdge(const nsStyleBorder& aBorder, mozilla::Side aSide)
if (aBorder.mBorderImageSource.GetType() != eStyleImageType_Null) if (aBorder.mBorderImageSource.GetType() != eStyleImageType_Null)
return false; return false;
StyleComplexColor color = aBorder.mBorderColor[aSide]; nscolor color = aColor.CalcComplexColor(aBorder.mBorderColor[aSide]);
// We don't know the foreground color here, so if it's being used return NS_GET_A(color) == 255;
// we must assume it might be transparent.
if (!color.IsNumericColor()) {
return false;
}
return NS_GET_A(color.mColor) == 255;
} }
/** /**
* Returns true if all border edges are either missing or opaque. * Returns true if all border edges are either missing or opaque.
*/ */
static bool static bool
IsOpaqueBorder(const nsStyleBorder& aBorder) IsOpaqueBorder(const nsStyleBorder& aBorder, const nsStyleColor& aColor)
{ {
if (aBorder.mBorderColors) if (aBorder.mBorderColors)
return false; return false;
NS_FOR_CSS_SIDES(i) { NS_FOR_CSS_SIDES(i) {
if (!IsOpaqueBorderEdge(aBorder, i)) if (!IsOpaqueBorderEdge(aBorder, aColor, i))
return false; return false;
} }
return true; return true;
@ -1916,7 +1913,7 @@ nsCSSRendering::GetImageLayerClip(const nsStyleImageLayers::Layer& aLayer,
} }
bool isSolidBorder = bool isSolidBorder =
aWillPaintBorder && IsOpaqueBorder(aBorder); aWillPaintBorder && IsOpaqueBorder(aBorder, *aForFrame->StyleColor());
if (isSolidBorder && layerClip == StyleGeometryBox::Border) { if (isSolidBorder && layerClip == StyleGeometryBox::Border) {
// If we have rounded corners, we need to inflate the background // If we have rounded corners, we need to inflate the background
// drawing area a bit to avoid seams between the border and // drawing area a bit to avoid seams between the border and

View file

@ -0,0 +1,18 @@
<!doctype html>
<meta charset="utf-8">
<style>
:root {
--color: #fff;
background: var(--color);
color: var(--color);
}
div {
display: block;
width: 51px;
height: 51px;
border-radius: 50%;
background-color: #323232;
border: 10px solid var(--color);
}
</style>
<div></div>

View file

@ -0,0 +1,18 @@
<!doctype html>
<meta charset="utf-8">
<style>
:root {
--color: #fff;
background: var(--color);
color: var(--color);
}
div {
display: block;
width: 51px;
height: 51px;
border-radius: 50%;
background-color: #323232;
border: 10px solid currentcolor;
}
</style>
<div></div>

View file

@ -89,6 +89,8 @@ fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)||/^Windows\x20NT\x206\.2/.te
# Test for antialiasing gaps between background and border # Test for antialiasing gaps between background and border
fuzzy-if(gtkWidget,1,9) fuzzy-if(winWidget&&!d2d,1,9) fuzzy-if(d2d,5,40) fuzzy-if(skiaContent,1,9) == curved-border-background-nogap.html curved-border-background-nogap-ref.html fuzzy-if(gtkWidget,1,9) fuzzy-if(winWidget&&!d2d,1,9) fuzzy-if(d2d,5,40) fuzzy-if(skiaContent,1,9) == curved-border-background-nogap.html curved-border-background-nogap-ref.html
== currentcolor-border-radius.html currentcolor-border-radius-ref.html
== color-layer-1a.html color-layer-1-ref.html == color-layer-1a.html color-layer-1-ref.html
== corner-split.html corner-split-ref.svg # bug 1185636 == corner-split.html corner-split-ref.svg # bug 1185636

View file

@ -3312,6 +3312,66 @@ nsComputedDOMStyle::DoGetBorderRightWidth()
return GetBorderWidthFor(eSideRight); return GetBorderWidthFor(eSideRight);
} }
already_AddRefed<CSSValue>
nsComputedDOMStyle::DoGetBorderWidth()
{
nscoord widths[4];
if (mInnerFrame) {
AssertFlushedPendingReflows();
const nsMargin& usedBorder = mInnerFrame->GetUsedBorder();
NS_FOR_CSS_SIDES(side) {
widths[side] = usedBorder.Side(side);
}
} else {
const nsStyleBorder* border = StyleBorder();
NS_FOR_CSS_SIDES(side) {
widths[side] = border->GetComputedBorderWidth(side);
}
}
RefPtr<nsDOMCSSValueList> valueList = GetROCSSValueList(false);
RefPtr<nsROCSSPrimitiveValue> top = new nsROCSSPrimitiveValue;
top->SetAppUnits(widths[eSideTop]);
valueList->AppendCSSValue(top.forget());
if (widths[eSideRight] == widths[eSideLeft]) {
if (widths[eSideTop] == widths[eSideBottom]) {
if (widths[eSideTop] == widths[eSideRight]) {
return valueList.forget();
}
RefPtr<nsROCSSPrimitiveValue> right = new nsROCSSPrimitiveValue;
right->SetAppUnits(widths[eSideRight]);
valueList->AppendCSSValue(right.forget());
return valueList.forget();
}
RefPtr<nsROCSSPrimitiveValue> right = new nsROCSSPrimitiveValue;
right->SetAppUnits(widths[eSideRight]);
valueList->AppendCSSValue(right.forget());
RefPtr<nsROCSSPrimitiveValue> bottom = new nsROCSSPrimitiveValue;
bottom->SetAppUnits(widths[eSideBottom]);
valueList->AppendCSSValue(bottom.forget());
return valueList.forget();
}
RefPtr<nsROCSSPrimitiveValue> right = new nsROCSSPrimitiveValue;
right->SetAppUnits(widths[eSideRight]);
valueList->AppendCSSValue(right.forget());
RefPtr<nsROCSSPrimitiveValue> bottom = new nsROCSSPrimitiveValue;
bottom->SetAppUnits(widths[eSideBottom]);
valueList->AppendCSSValue(bottom.forget());
RefPtr<nsROCSSPrimitiveValue> left = new nsROCSSPrimitiveValue;
left->SetAppUnits(widths[eSideLeft]);
valueList->AppendCSSValue(left.forget());
return valueList.forget();
}
already_AddRefed<CSSValue> already_AddRefed<CSSValue>
nsComputedDOMStyle::DoGetBorderTopColor() nsComputedDOMStyle::DoGetBorderTopColor()
{ {
@ -6960,4 +7020,5 @@ already_AddRefed<CSSValue>
nsComputedDOMStyle::DoGetOverflowBlockEnd() nsComputedDOMStyle::DoGetOverflowBlockEnd()
{ {
return DoGetOverflowBlock(); return DoGetOverflowBlock();
} }

View file

@ -345,6 +345,7 @@ private:
already_AddRefed<CSSValue> DoGetBorderBottomWidth(); already_AddRefed<CSSValue> DoGetBorderBottomWidth();
already_AddRefed<CSSValue> DoGetBorderLeftWidth(); already_AddRefed<CSSValue> DoGetBorderLeftWidth();
already_AddRefed<CSSValue> DoGetBorderRightWidth(); already_AddRefed<CSSValue> DoGetBorderRightWidth();
already_AddRefed<CSSValue> DoGetBorderWidth();
already_AddRefed<CSSValue> DoGetBorderTopColor(); already_AddRefed<CSSValue> DoGetBorderTopColor();
already_AddRefed<CSSValue> DoGetBorderBottomColor(); already_AddRefed<CSSValue> DoGetBorderBottomColor();
already_AddRefed<CSSValue> DoGetBorderLeftColor(); already_AddRefed<CSSValue> DoGetBorderLeftColor();

View file

@ -96,7 +96,7 @@ COMPUTED_STYLE_PROP(border_top_left_radius, BorderTopLeftRadius)
COMPUTED_STYLE_PROP(border_top_right_radius, BorderTopRightRadius) COMPUTED_STYLE_PROP(border_top_right_radius, BorderTopRightRadius)
COMPUTED_STYLE_PROP(border_top_style, BorderTopStyle) COMPUTED_STYLE_PROP(border_top_style, BorderTopStyle)
COMPUTED_STYLE_PROP(border_top_width, BorderTopWidth) COMPUTED_STYLE_PROP(border_top_width, BorderTopWidth)
//// COMPUTED_STYLE_PROP(border_width, BorderWidth) COMPUTED_STYLE_PROP(border_width, BorderWidth)
COMPUTED_STYLE_PROP(bottom, Bottom) COMPUTED_STYLE_PROP(bottom, Bottom)
COMPUTED_STYLE_PROP(box_decoration_break, BoxDecorationBreak) COMPUTED_STYLE_PROP(box_decoration_break, BoxDecorationBreak)
COMPUTED_STYLE_PROP(box_shadow, BoxShadow) COMPUTED_STYLE_PROP(box_shadow, BoxShadow)

View file

@ -8352,7 +8352,9 @@ nsRuleNode::ComputeOutlineData(void* aStartStruct,
SETCOORD_LH | SETCOORD_INITIAL_ZERO | SETCOORD_CALC_LENGTH_ONLY | SETCOORD_LH | SETCOORD_INITIAL_ZERO | SETCOORD_CALC_LENGTH_ONLY |
SETCOORD_UNSET_INITIAL, SETCOORD_UNSET_INITIAL,
aContext, mPresContext, conditions)) { aContext, mPresContext, conditions)) {
outline->mOutlineOffset = tempCoord.GetCoordValue(); outline->mOutlineOffset =
NS_ROUND_OFFSET_TO_PIXELS(tempCoord.GetCoordValue(),
mPresContext->AppUnitsPerDevPixel());
} else { } else {
NS_ASSERTION(outlineOffsetValue->GetUnit() == eCSSUnit_Null, NS_ASSERTION(outlineOffsetValue->GetUnit() == eCSSUnit_Null,
"unexpected unit"); "unexpected unit");

View file

@ -1148,18 +1148,16 @@ private:
// Border widths are rounded to the nearest integer number of pixels, but values // Border widths are rounded to the nearest integer number of pixels, but values
// between zero and one device pixels are always rounded up to one device pixel. // between zero and one device pixels are always rounded up to one device pixel.
#define NS_ROUND_BORDER_TO_PIXELS(l,tpp) \ #define NS_ROUND_BORDER_TO_PIXELS(l,tpp) \
((l) == 0) ? 0 : std::max((tpp), ((l) + ((tpp) / 2)) / (tpp) * (tpp)) (((l) == 0) ? 0 : std::max((tpp), (l) / (tpp) * (tpp)))
// Caret widths are rounded to the nearest-below integer number of pixels, but values // Caret widths are rounded to the nearest-below integer number of pixels, but values
// between zero and one device pixels are always rounded up to one device pixel. // between zero and one device pixels are always rounded up to one device pixel.
#define NS_ROUND_CARET_TO_PIXELS(l,tpp) \ #define NS_ROUND_CARET_TO_PIXELS(l,tpp) \
((l) == 0) ? 0 : std::max((tpp), (l) / (tpp) * (tpp)) NS_ROUND_BORDER_TO_PIXELS(l,tpp)
// Outline offset is rounded to the nearest integer number of pixels, but values // Outline offset is snapped like border widths, preserving the sign.
// between zero and one device pixels are always rounded up to one device pixel.
// Note that the offset can be negative.
#define NS_ROUND_OFFSET_TO_PIXELS(l,tpp) \ #define NS_ROUND_OFFSET_TO_PIXELS(l,tpp) \
(((l) == 0) ? 0 : \ (((l) == 0) ? 0 : \
((l) > 0) ? std::max( (tpp), ((l) + ((tpp) / 2)) / (tpp) * (tpp)) : \ (((l) > 0) ? NS_ROUND_BORDER_TO_PIXELS((l), (tpp)) : \
std::min(-(tpp), ((l) - ((tpp) / 2)) / (tpp) * (tpp))) std::min(-(tpp), (l) / (tpp) * (tpp))))
// Returns if the given border style type is visible or not // Returns if the given border style type is visible or not
static bool IsVisibleBorderStyle(uint8_t aStyle) static bool IsVisibleBorderStyle(uint8_t aStyle)

View file

@ -42,8 +42,37 @@ function checkWidth(property, setupProperty, setupValue) {
}); });
} }
function checkOffset(property) {
tests.forEach(function(test) {
var specified = test[0];
var expected = test[1];
var div = document.createElement("div");
div.style[property] = specified;
display.appendChild(div);
is(document.defaultView.getComputedStyle(div, "")[property], expected,
property + " computes " + specified + " as " + expected);
display.removeChild(div);
});
tests.forEach(function(test) {
var specified = test[0];
var expected = test[0] == "0px" ? "0px" : "-" + test[1];
var div = document.createElement("div");
div.style[property] = "-" + specified;
display.appendChild(div);
is(document.defaultView.getComputedStyle(div, "")[property], expected,
property + " computes -" + specified + " as " + expected);
display.removeChild(div);
});
}
checkWidth("borderWidth", "borderStyle", "solid"); checkWidth("borderWidth", "borderStyle", "solid");
checkWidth("outlineWidth", "outlineStyle", "solid"); checkWidth("outlineWidth", "outlineStyle", "solid");
checkOffset("outlineOffset");
</script> </script>
</pre> </pre>