зеркало из https://github.com/mozilla/gecko-dev.git
Bug 727125 - Lazily compute LineBaselineOffset when needed so it is present after a dynamic change of 'text-decoration'. r=dbaron
This fixes the positioning of underlines set on a block or its ancestor when drawn on children of a block that have a vertical-align != baseline. The lazy computation is done all at once for all children of a block to avoid O(N^2) searches for the line containing a frame.
This commit is contained in:
Родитель
6020c3fe5e
Коммит
d1e6d153b7
|
@ -731,6 +731,16 @@ nsLineLayout::ReflowFrame(nsIFrame* aFrame,
|
|||
printf("\n");
|
||||
#endif
|
||||
|
||||
if (mCurrentSpan == mRootSpan) {
|
||||
pfd->mFrame->Properties().Remove(nsIFrame::LineBaselineOffset());
|
||||
} else {
|
||||
#ifdef DEBUG
|
||||
bool hasLineOffset;
|
||||
pfd->mFrame->Properties().Get(nsIFrame::LineBaselineOffset(), &hasLineOffset);
|
||||
NS_ASSERTION(!hasLineOffset, "LineBaselineOffset was set but was not expected");
|
||||
#endif
|
||||
}
|
||||
|
||||
mTextJustificationNumSpaces = 0;
|
||||
mTextJustificationNumLetters = 0;
|
||||
|
||||
|
@ -1452,22 +1462,6 @@ nsLineLayout::BlockDirAlignLine()
|
|||
}
|
||||
PlaceStartEndFrames(psd, -mBStartEdge, lineBSize);
|
||||
|
||||
// If the frame being reflowed has text decorations, we simulate the
|
||||
// propagation of those decorations to a line-level element by storing the
|
||||
// offset in a frame property on any child frames that are aligned in the
|
||||
// block direction somewhere other than the baseline. This property is then
|
||||
// used by nsTextFrame::GetTextDecorations when the same conditions are met.
|
||||
if (rootPFD.mFrame->StyleContext()->HasTextDecorationLines()) {
|
||||
for (const PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) {
|
||||
const nsIFrame *const f = pfd->mFrame;
|
||||
if (f->VerticalAlignEnum() != NS_STYLE_VERTICAL_ALIGN_BASELINE) {
|
||||
const nscoord offset = baselineBCoord - pfd->mBounds.BStart(lineWM);
|
||||
f->Properties().Set(nsIFrame::LineBaselineOffset(),
|
||||
NS_INT32_TO_PTR(offset));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Fill in returned line-box and max-element-width data
|
||||
mLineBox->SetBounds(lineWM,
|
||||
psd->mIStart, mBStartEdge,
|
||||
|
|
|
@ -4620,6 +4620,40 @@ PaintSelectionBackground(gfxContext* aCtx, nsPresContext* aPresContext,
|
|||
}
|
||||
}
|
||||
|
||||
// Attempt to get the LineBaselineOffset property of aChildFrame
|
||||
// If not set, calculate this value for all child frames of aBlockFrame
|
||||
static nscoord
|
||||
LazyGetLineBaselineOffset(nsIFrame* aChildFrame, nsBlockFrame* aBlockFrame)
|
||||
{
|
||||
bool offsetFound;
|
||||
nscoord offset = NS_PTR_TO_INT32(
|
||||
aChildFrame->Properties().Get(nsIFrame::LineBaselineOffset(), &offsetFound)
|
||||
);
|
||||
|
||||
if (!offsetFound) {
|
||||
for (nsBlockFrame::line_iterator line = aBlockFrame->begin_lines(),
|
||||
line_end = aBlockFrame->end_lines();
|
||||
line != line_end; line++) {
|
||||
if (line->IsInline()) {
|
||||
int32_t n = line->GetChildCount();
|
||||
nscoord lineBaseline = line->BStart() + line->GetAscent();
|
||||
for (nsIFrame* lineFrame = line->mFirstChild;
|
||||
n > 0; lineFrame = lineFrame->GetNextSibling(), --n) {
|
||||
offset = lineBaseline - lineFrame->GetNormalPosition().y;
|
||||
lineFrame->Properties().Set(nsIFrame::LineBaselineOffset(),
|
||||
NS_INT32_TO_PTR(offset));
|
||||
}
|
||||
}
|
||||
}
|
||||
return NS_PTR_TO_INT32(
|
||||
aChildFrame->Properties().Get(nsIFrame::LineBaselineOffset(), &offsetFound)
|
||||
);
|
||||
|
||||
} else {
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsTextFrame::GetTextDecorations(
|
||||
nsPresContext* aPresContext,
|
||||
|
@ -4663,7 +4697,8 @@ nsTextFrame::GetTextDecorations(
|
|||
nsLayoutUtils::GetColor(f, eCSSProperty_text_decoration_color);
|
||||
}
|
||||
|
||||
const bool firstBlock = !nearestBlockFound && nsLayoutUtils::GetAsBlock(f);
|
||||
nsBlockFrame* fBlock = nsLayoutUtils::GetAsBlock(f);
|
||||
const bool firstBlock = !nearestBlockFound && fBlock;
|
||||
|
||||
// Not updating positions once we hit a parent block is equivalent to
|
||||
// the CSS 2.1 spec that blocks should propagate decorations down to their
|
||||
|
@ -4674,13 +4709,15 @@ nsTextFrame::GetTextDecorations(
|
|||
if (firstBlock) {
|
||||
// At this point, fChild can't be null since TextFrames can't be blocks
|
||||
if (fChild->VerticalAlignEnum() != NS_STYLE_VERTICAL_ALIGN_BASELINE) {
|
||||
|
||||
// Since offset is the offset in the child's coordinate space, we have
|
||||
// to undo the accumulation to bring the transform out of the block's
|
||||
// coordinate space
|
||||
const nscoord lineBaselineOffset = LazyGetLineBaselineOffset(fChild,
|
||||
fBlock);
|
||||
|
||||
baselineOffset =
|
||||
frameTopOffset - fChild->GetNormalPosition().y
|
||||
- NS_PTR_TO_INT32(
|
||||
fChild->Properties().Get(nsIFrame::LineBaselineOffset()));
|
||||
frameTopOffset - fChild->GetNormalPosition().y - lineBaselineOffset;
|
||||
}
|
||||
}
|
||||
else if (!nearestBlockFound) {
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
<html>
|
||||
<head>
|
||||
<style>
|
||||
.underline {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.align-bottom {
|
||||
vertical-align: bottom;
|
||||
}
|
||||
.align-top {
|
||||
vertical-align: top;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p class="underline">
|
||||
<span class="align-bottom">This</span> line has a bottom vertical align span. <br />
|
||||
<span class="align-top">This</span> line has a top vertical align span.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,26 @@
|
|||
<html class="reftest-wait">
|
||||
<head>
|
||||
<script type="text/javascript">
|
||||
function addUnderline() {
|
||||
var element = document.getElementById("dynamicUnderline");
|
||||
element.style.textDecoration = "underline";
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
document.addEventListener('MozReftestInvalidate', addUnderline, false);
|
||||
</script>
|
||||
<style>
|
||||
.align-bottom {
|
||||
vertical-align: bottom;
|
||||
}
|
||||
.align-top {
|
||||
vertical-align: top;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p id="dynamicUnderline">
|
||||
<span class="align-bottom">This</span> line has a bottom vertical align span. <br />
|
||||
<span class="align-top">This</span> line has a top vertical align span.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,21 @@
|
|||
<html>
|
||||
<head>
|
||||
<style>
|
||||
.underline {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.align-bottom {
|
||||
vertical-align: bottom;
|
||||
}
|
||||
.align-top {
|
||||
vertical-align: top;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p class="underline">
|
||||
<span class="align-bottom">This line has only a bottom vertical align span.</span> <br />
|
||||
<span class="align-top">This line has a top vertical align span.</span>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,26 @@
|
|||
<html class="reftest-wait">
|
||||
<head>
|
||||
<script type="text/javascript">
|
||||
function addUnderline() {
|
||||
var element = document.getElementById("dynamicUnderline");
|
||||
element.style.textDecoration = "underline";
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
document.addEventListener('MozReftestInvalidate', addUnderline, false);
|
||||
</script>
|
||||
<style>
|
||||
.align-bottom {
|
||||
vertical-align: bottom;
|
||||
}
|
||||
.align-top {
|
||||
vertical-align: top;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p id="dynamicUnderline">
|
||||
<span class="align-bottom">This line has only a bottom vertical align span.</span> <br />
|
||||
<span class="align-top">This line has a top vertical align span.</span>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,22 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
.underline {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.align-bottom {
|
||||
vertical-align: bottom;
|
||||
}
|
||||
.align-top {
|
||||
vertical-align: top;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p class="underline">
|
||||
<span class="align-bottom">This</span> line has a bottom vertical align span. <br />
|
||||
<span class="align-top">This</span> line has a top vertical align span.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,27 @@
|
|||
<!DOCTYPE html>
|
||||
<html class="reftest-wait">
|
||||
<head>
|
||||
<script type="text/javascript">
|
||||
function addUnderline() {
|
||||
var element = document.getElementById("dynamicUnderline");
|
||||
element.style.textDecoration = "underline";
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
document.addEventListener('MozReftestInvalidate', addUnderline, false);
|
||||
</script>
|
||||
<style>
|
||||
.align-bottom {
|
||||
vertical-align: bottom;
|
||||
}
|
||||
.align-top {
|
||||
vertical-align: top;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p id="dynamicUnderline">
|
||||
<span class="align-bottom">This</span> line has a bottom vertical align span. <br />
|
||||
<span class="align-top">This</span> line has a top vertical align span.
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,22 @@
|
|||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
.underline {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.align-bottom {
|
||||
vertical-align: bottom;
|
||||
}
|
||||
.align-top {
|
||||
vertical-align: top;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p class="underline">
|
||||
<span class="align-bottom">This line has only a bottom vertical align span.</span> <br />
|
||||
<span class="align-top">This line has a top vertical align span.</span>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,27 @@
|
|||
<!DOCTYPE html>
|
||||
<html class="reftest-wait">
|
||||
<head>
|
||||
<script type="text/javascript">
|
||||
function addUnderline() {
|
||||
var element = document.getElementById("dynamicUnderline");
|
||||
element.style.textDecoration = "underline";
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
document.addEventListener('MozReftestInvalidate', addUnderline, false);
|
||||
</script>
|
||||
<style>
|
||||
.align-bottom {
|
||||
vertical-align: bottom;
|
||||
}
|
||||
.align-top {
|
||||
vertical-align: top;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p id="dynamicUnderline">
|
||||
<span class="align-bottom">This line has only a bottom vertical align span.</span> <br />
|
||||
<span class="align-top">This line has a top vertical align span.</span>
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
|
@ -4,6 +4,10 @@ skip-if(B2G) == complex-decoration-style-standards.html complex-decoration-style
|
|||
== decoration-color-standards.html decoration-color-standards-ref.html
|
||||
== decoration-style-quirks.html decoration-style-quirks-ref.html
|
||||
== decoration-style-standards.html decoration-style-standards-ref.html
|
||||
fuzzy-if(B2G,255,1) == dynamic-underline-vertical-align-quirks-1.html dynamic-underline-vertical-align-quirks-1-ref.html
|
||||
fuzzy-if(B2G,255,1) == dynamic-underline-vertical-align-standards-1.html dynamic-underline-vertical-align-standards-1-ref.html
|
||||
fails == dynamic-underline-vertical-align-quirks-2.html dynamic-underline-vertical-align-quirks-2-ref.html
|
||||
fuzzy-if(B2G,255,1) == dynamic-underline-vertical-align-standards-2.html dynamic-underline-vertical-align-standards-2-ref.html
|
||||
== line-through-style-block-solid-quirks.html line-through-style-block-quirks-ref.html
|
||||
!= line-through-style-block-dotted-quirks.html line-through-style-block-quirks-ref.html
|
||||
!= line-through-style-block-dashed-quirks.html line-through-style-block-quirks-ref.html
|
||||
|
|
Загрузка…
Ссылка в новой задаче