зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1846853 - Clamp negative outline-offset per spec r=emilio
A negative outline-offset value should be clamped per spec as to stop it from becoming invisible with large negative values. Spec ref: https://www.w3.org/TR/css-ui-4/#outline-offset Also added a new WPT reftest for this case as no tests existed prior, updated related WPT expectations, and updated a few old layout reftests. Differential Revision: https://phabricator.services.mozilla.com/D185357
This commit is contained in:
Родитель
846812dc70
Коммит
e115104963
|
@ -9880,16 +9880,17 @@ static void ComputeAndIncludeOutlineArea(nsIFrame* aFrame,
|
||||||
innerRect);
|
innerRect);
|
||||||
}
|
}
|
||||||
|
|
||||||
const nscoord offset = outline->mOutlineOffset.ToAppUnits();
|
|
||||||
nsRect outerRect(innerRect);
|
nsRect outerRect(innerRect);
|
||||||
|
outerRect.Inflate(outline->EffectiveOffsetFor(outerRect));
|
||||||
|
|
||||||
if (outline->mOutlineStyle.IsAuto()) {
|
if (outline->mOutlineStyle.IsAuto()) {
|
||||||
nsPresContext* pc = aFrame->PresContext();
|
nsPresContext* pc = aFrame->PresContext();
|
||||||
outerRect.Inflate(offset);
|
|
||||||
pc->Theme()->GetWidgetOverflow(pc->DeviceContext(), aFrame,
|
pc->Theme()->GetWidgetOverflow(pc->DeviceContext(), aFrame,
|
||||||
StyleAppearance::FocusOutline, &outerRect);
|
StyleAppearance::FocusOutline, &outerRect);
|
||||||
} else {
|
} else {
|
||||||
nscoord width = outline->GetOutlineWidth();
|
const nscoord width = outline->GetOutlineWidth();
|
||||||
outerRect.Inflate(width + offset);
|
outerRect.Inflate(width);
|
||||||
}
|
}
|
||||||
|
|
||||||
nsRect& vo = aOverflowAreas.InkOverflow();
|
nsRect& vo = aOverflowAreas.InkOverflow();
|
||||||
|
|
|
@ -962,9 +962,10 @@ nsCSSRendering::CreateBorderRendererForNonThemedOutline(
|
||||||
return Nothing();
|
return Nothing();
|
||||||
}
|
}
|
||||||
|
|
||||||
const nscoord offset = ourOutline->mOutlineOffset.ToAppUnits();
|
|
||||||
nsRect innerRect = aInnerRect;
|
nsRect innerRect = aInnerRect;
|
||||||
innerRect.Inflate(offset);
|
|
||||||
|
const nsSize effectiveOffset = ourOutline->EffectiveOffsetFor(innerRect);
|
||||||
|
innerRect.Inflate(effectiveOffset);
|
||||||
|
|
||||||
// If the dirty rect is completely inside the border area (e.g., only the
|
// If the dirty rect is completely inside the border area (e.g., only the
|
||||||
// content is being painted), then we can skip out now
|
// content is being painted), then we can skip out now
|
||||||
|
@ -975,7 +976,7 @@ nsCSSRendering::CreateBorderRendererForNonThemedOutline(
|
||||||
return Nothing();
|
return Nothing();
|
||||||
}
|
}
|
||||||
|
|
||||||
nscoord width = ourOutline->GetOutlineWidth();
|
const nscoord width = ourOutline->GetOutlineWidth();
|
||||||
|
|
||||||
StyleBorderStyle outlineStyle;
|
StyleBorderStyle outlineStyle;
|
||||||
// Themed outlines are handled by our callers, if supported.
|
// Themed outlines are handled by our callers, if supported.
|
||||||
|
@ -1009,10 +1010,13 @@ nsCSSRendering::CreateBorderRendererForNonThemedOutline(
|
||||||
RectCornerRadii innerRadii;
|
RectCornerRadii innerRadii;
|
||||||
ComputePixelRadii(twipsRadii, oneDevPixel, &innerRadii);
|
ComputePixelRadii(twipsRadii, oneDevPixel, &innerRadii);
|
||||||
|
|
||||||
Float devPixelOffset = aPresContext->AppUnitsToFloatDevPixels(offset);
|
const auto devPxOffset = LayoutDeviceSize::FromAppUnits(
|
||||||
const Float widths[4] = {
|
effectiveOffset, aPresContext->AppUnitsPerDevPixel());
|
||||||
outlineWidths[0] + devPixelOffset, outlineWidths[1] + devPixelOffset,
|
|
||||||
outlineWidths[2] + devPixelOffset, outlineWidths[3] + devPixelOffset};
|
const Float widths[4] = {outlineWidths[0] + devPxOffset.Height(),
|
||||||
|
outlineWidths[1] + devPxOffset.Width(),
|
||||||
|
outlineWidths[2] + devPxOffset.Height(),
|
||||||
|
outlineWidths[3] + devPxOffset.Width()};
|
||||||
nsCSSBorderRenderer::ComputeOuterRadii(innerRadii, widths, &outlineRadii);
|
nsCSSBorderRenderer::ComputeOuterRadii(innerRadii, widths, &outlineRadii);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4015,7 +4015,7 @@ void nsDisplayOutline::Paint(nsDisplayListBuilder* aBuilder, gfxContext* aCtx) {
|
||||||
nsRect rect = GetInnerRect() + ToReferenceFrame();
|
nsRect rect = GetInnerRect() + ToReferenceFrame();
|
||||||
nsPresContext* pc = mFrame->PresContext();
|
nsPresContext* pc = mFrame->PresContext();
|
||||||
if (IsThemedOutline()) {
|
if (IsThemedOutline()) {
|
||||||
rect.Inflate(mFrame->StyleOutline()->mOutlineOffset.ToAppUnits());
|
rect.Inflate(mFrame->StyleOutline()->EffectiveOffsetFor(rect));
|
||||||
pc->Theme()->DrawWidgetBackground(aCtx, mFrame,
|
pc->Theme()->DrawWidgetBackground(aCtx, mFrame,
|
||||||
StyleAppearance::FocusOutline, rect,
|
StyleAppearance::FocusOutline, rect,
|
||||||
GetPaintRect(aBuilder, aCtx));
|
GetPaintRect(aBuilder, aCtx));
|
||||||
|
@ -4044,7 +4044,7 @@ bool nsDisplayOutline::CreateWebRenderCommands(
|
||||||
nsPresContext* pc = mFrame->PresContext();
|
nsPresContext* pc = mFrame->PresContext();
|
||||||
nsRect rect = GetInnerRect() + ToReferenceFrame();
|
nsRect rect = GetInnerRect() + ToReferenceFrame();
|
||||||
if (IsThemedOutline()) {
|
if (IsThemedOutline()) {
|
||||||
rect.Inflate(mFrame->StyleOutline()->mOutlineOffset.ToAppUnits());
|
rect.Inflate(mFrame->StyleOutline()->EffectiveOffsetFor(rect));
|
||||||
return pc->Theme()->CreateWebRenderCommandsForWidget(
|
return pc->Theme()->CreateWebRenderCommandsForWidget(
|
||||||
aBuilder, aResources, aSc, aManager, mFrame,
|
aBuilder, aResources, aSc, aManager, mFrame,
|
||||||
StyleAppearance::FocusOutline, rect);
|
StyleAppearance::FocusOutline, rect);
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
<style type="text/css">
|
<style type="text/css">
|
||||||
|
|
||||||
* { -moz-outline-offset: -2px; outline-offset: -2px; }
|
* { -moz-outline-offset: -2px; outline-offset: -2px; }
|
||||||
body > span { outline: 1px dotted black; }
|
|
||||||
/* can't compare to border combined with negative margin because of
|
/* can't compare to border combined with negative margin because of
|
||||||
margin collapsing */
|
margin collapsing */
|
||||||
body > div { display: block; outline: 1px dotted black; width: 15em; }
|
body > div { display: block; outline: 1px dotted black; width: 15em; }
|
||||||
|
@ -17,7 +16,7 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<span></span><div>text<br>text<br>text</div>
|
<div>text<br>text<br>text</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<span></span><div>text</div><span>Some words that must be wider than 10em</span><div>text</div>
|
<div>text</div><span>Some words that must be wider than 10em</span><div>text</div>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -585,6 +585,18 @@ nsChangeHint nsStyleOutline::CalcDifference(
|
||||||
return nsChangeHint(0);
|
return nsChangeHint(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsSize nsStyleOutline::EffectiveOffsetFor(const nsRect& aRect) const {
|
||||||
|
const nscoord offset = mOutlineOffset.ToAppUnits();
|
||||||
|
|
||||||
|
if (offset >= 0) {
|
||||||
|
// Fast path for non-negative offset values
|
||||||
|
return nsSize(offset, offset);
|
||||||
|
}
|
||||||
|
|
||||||
|
return nsSize(std::max(offset, -(aRect.Width() / 2)),
|
||||||
|
std::max(offset, -(aRect.Height() / 2)));
|
||||||
|
}
|
||||||
|
|
||||||
// --------------------
|
// --------------------
|
||||||
// nsStyleList
|
// nsStyleList
|
||||||
//
|
//
|
||||||
|
|
|
@ -617,6 +617,8 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleOutline {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nsSize EffectiveOffsetFor(const nsRect& aRect) const;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// The actual value of outline-width is the computed value (an absolute
|
// The actual value of outline-width is the computed value (an absolute
|
||||||
// length, forced to zero when outline-style is none) rounded to device
|
// length, forced to zero when outline-style is none) rounded to device
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
[outline-013.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[outline-014.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[outline-015.html]
|
|
||||||
expected: FAIL
|
|
|
@ -1,2 +0,0 @@
|
||||||
[outline-016.html]
|
|
||||||
expected: FAIL
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<style>
|
||||||
|
div {
|
||||||
|
border: 2px solid black;
|
||||||
|
padding: 5px 0; /* No horizontal padding as outline-offset is not affected by it and span simulates it */
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
display: block;
|
||||||
|
|
||||||
|
/* 3/6px offset for border */
|
||||||
|
height: 2px;
|
||||||
|
width: calc(100% - 20em + 6px);
|
||||||
|
margin: -1px calc(10em - 3px); /* -1px vertical to remove height of span from div height */
|
||||||
|
background: red;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<p>PASS if there is a thin red line in the middle of the box.</p>
|
||||||
|
<div>
|
||||||
|
<span></span>
|
||||||
|
</div>
|
|
@ -0,0 +1,16 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<link rel="help" href="https://www.w3.org/TR/css-ui-4/#outline-offset">
|
||||||
|
<link rel="match" href="negative-outline-offset-ref.html">
|
||||||
|
<style>
|
||||||
|
div {
|
||||||
|
outline: 1px solid red;
|
||||||
|
outline-offset: -10em;
|
||||||
|
|
||||||
|
border: 2px solid black;
|
||||||
|
padding: 5px;
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<p>PASS if there is a thin red line in the middle of the box.</p>
|
||||||
|
<div></div>
|
Загрузка…
Ссылка в новой задаче