Fix text-decoration positioning in quirks mode and set overflow areas to match. (Bug 403524) r=dbaron

Change the quirks mode text-decoration code (soon to be used for all
modes) to follow CSS 2.1's rules for positioning of decoration lines.
Decorations are now drawn at a constant vertical position established by
the element creating the decoration, and more than one of the same type
(underline, overline, line-through) of decoration are supported on the
same piece of text.

This means that text-decorations can now significantly overflow a text
frame, since the vertical-alignment of the element with text-decoration
may be substantially different from the vertical alignment of the text.
Set overflow areas for text frames with text decorations in
nsLineLayout::RelativePositionFrames since it must happen *after*
vertical alignment is done, and when relative positioning data are
consistent (nsIFrame::GetRelativeOffset matches the offset that has been
applied).
This commit is contained in:
Vitor Menezes 2011-08-03 11:30:58 -07:00
parent 506fb4223e
commit e915e08a19
11 changed files with 367 additions and 132 deletions

View File

@ -896,6 +896,8 @@ public:
NS_DECLARE_FRAME_PROPERTY(ScrollLayerCount, nsnull)
NS_DECLARE_FRAME_PROPERTY(LineBaselineOffset, nsnull)
/**
* Return the distance between the border edge of the frame and the
* margin edge of the frame. Like GetRect(), returns the dimensions

View File

@ -1480,6 +1480,26 @@ nsLineLayout::VerticalAlignLine()
}
PlaceTopBottomFrames(psd, -mTopEdge, lineHeight);
// 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 vertically-aligned
// somewhere other than the baseline. This property is then used by
// nsTextFrame::GetTextDecorations when the same conditions are met.
if (rootPFD.mFrame->GetStyleContext()->HasTextDecorationLines()) {
for (const PerFrameData* pfd = psd->mFirstFrame; pfd; pfd = pfd->mNext) {
const nsIFrame *const f = pfd->mFrame;
const nsStyleCoord& vAlign =
f->GetStyleContext()->GetStyleTextReset()->mVerticalAlign;
if (vAlign.GetUnit() != eStyleUnit_Enumerated ||
vAlign.GetIntValue() != NS_STYLE_VERTICAL_ALIGN_BASELINE) {
const nscoord offset = baselineY - (pfd->mBounds.y);
f->Properties().Set(nsIFrame::LineBaselineOffset(),
NS_INT32_TO_PTR(offset));
}
}
}
// Fill in returned line-box and max-element-width data
mLineBox->mBounds.x = psd->mLeftEdge;
mLineBox->mBounds.y = mTopEdge;
@ -2599,7 +2619,12 @@ nsLineLayout::RelativePositionFrames(PerSpanData* psd, nsOverflowAreas& aOverflo
} else {
r = pfd->mOverflowAreas;
if (pfd->GetFlag(PFD_ISTEXTFRAME)) {
if (pfd->GetFlag(PFD_RECOMPUTEOVERFLOW)) {
// We need to recompute overflow areas in two cases:
// (1) When PFD_RECOMPUTEOVERFLOW is set due to trimming
// (2) When there are text decorations, since we can't recompute the
// overflow area until Reflow and VerticalAlignLine have finished
if (pfd->GetFlag(PFD_RECOMPUTEOVERFLOW) ||
frame->GetStyleContext()->HasTextDecorationLines()) {
nsTextFrame* f = static_cast<nsTextFrame*>(frame);
r = f->RecomputeOverflow();
}

View File

@ -439,10 +439,11 @@ protected:
// return value, if that return value is not null. Calling
// DestroySelectionDetails() on a null value is still OK, just not necessary.
SelectionDetails* GetSelectionDetails();
void UnionTextDecorationOverflow(nsPresContext* aPresContext,
PropertyProvider& aProvider,
nsRect* aVisualOverflowRect);
void UnionAdditionalOverflow(nsPresContext* aPresContext,
PropertyProvider& aProvider,
nsRect* aVisualOverflowRect,
bool aIncludeTextDecorations);
void DrawText(gfxContext* aCtx,
const gfxPoint& aTextBaselinePt,
@ -465,40 +466,60 @@ protected:
const nsCharClipDisplayItem::ClipEdges& aClipEdges,
nscoord aLeftSideOffset);
struct TextDecorations {
PRUint8 mDecorations;
PRUint8 mOverStyle;
PRUint8 mUnderStyle;
PRUint8 mStrikeStyle;
nscolor mOverColor;
nscolor mUnderColor;
nscolor mStrikeColor;
struct LineDecoration {
nsIFrame* mFrame;
TextDecorations() :
mDecorations(0), mOverStyle(NS_STYLE_TEXT_DECORATION_STYLE_SOLID),
mUnderStyle(NS_STYLE_TEXT_DECORATION_STYLE_SOLID),
mStrikeStyle(NS_STYLE_TEXT_DECORATION_STYLE_SOLID),
mOverColor(NS_RGB(0, 0, 0)), mUnderColor(NS_RGB(0, 0, 0)),
mStrikeColor(NS_RGB(0, 0, 0))
{ }
// This is represents the offset from our baseline to mFrame's baseline;
// positive offsets are *above* the baseline and negative offsets below
nscoord mBaselineOffset;
PRBool HasDecorationlines() {
return HasUnderline() || HasOverline() || HasStrikeout();
}
PRBool HasUnderline() {
return (mDecorations & NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE) &&
mUnderStyle != NS_STYLE_TEXT_DECORATION_STYLE_NONE;
}
PRBool HasOverline() {
return (mDecorations & NS_STYLE_TEXT_DECORATION_LINE_OVERLINE) &&
mOverStyle != NS_STYLE_TEXT_DECORATION_STYLE_NONE;
}
PRBool HasStrikeout() {
return (mDecorations & NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH) &&
mStrikeStyle != NS_STYLE_TEXT_DECORATION_STYLE_NONE;
nscolor mColor;
PRUint8 mStyle;
LineDecoration(nsIFrame *const aFrame,
const nscoord aOff,
const nscolor aColor,
const PRUint8 aStyle)
: mFrame(aFrame),
mBaselineOffset(aOff),
mColor(aColor),
mStyle(aStyle)
{}
LineDecoration(const LineDecoration& aOther)
: mFrame(aOther.mFrame),
mBaselineOffset(aOther.mBaselineOffset),
mColor(aOther.mColor),
mStyle(aOther.mStyle)
{}
bool operator==(const LineDecoration& aOther) const {
return mFrame == aOther.mFrame &&
mStyle == aOther.mStyle &&
mColor == aOther.mColor &&
mBaselineOffset == aOther.mBaselineOffset;
}
};
TextDecorations GetTextDecorations(nsPresContext* aPresContext);
struct TextDecorations {
nsAutoTArray<LineDecoration, 1> mOverlines, mUnderlines, mStrikes;
TextDecorations() { }
PRBool HasDecorationLines() const {
return HasUnderline() || HasOverline() || HasStrikeout();
}
PRBool HasUnderline() const {
return !mUnderlines.IsEmpty();
}
PRBool HasOverline() const {
return !mOverlines.IsEmpty();
}
PRBool HasStrikeout() const {
return !mStrikes.IsEmpty();
}
};
void GetTextDecorations(nsPresContext* aPresContext,
TextDecorations& aDecorations);
// Set non empty rect to aRect, it should be overflow rect or frame rect.
// If the result rect is larger than the given rect, this returns PR_TRUE.

View File

@ -4260,11 +4260,10 @@ FillClippedRect(gfxContext* aCtx, nsPresContext* aPresContext,
aCtx->Fill();
}
nsTextFrame::TextDecorations
nsTextFrame::GetTextDecorations(nsPresContext* aPresContext)
void
nsTextFrame::GetTextDecorations(nsPresContext* aPresContext,
nsTextFrame::TextDecorations& aDecorations)
{
TextDecorations decorations;
// Quirks mode text decoration are rendered by children; see bug 1777
// In non-quirks mode, nsHTMLContainer::Paint and nsBlockFrame::Paint
// does the painting of text decorations.
@ -4273,28 +4272,33 @@ nsTextFrame::GetTextDecorations(nsPresContext* aPresContext)
// codepath. But for now this code is only used for quirks mode.
const nsCompatibility compatMode = aPresContext->CompatibilityMode();
if (compatMode != eCompatibility_NavQuirks)
return decorations;
return;
PRBool useOverride = PR_FALSE;
nscolor overrideColor;
// A mask of all possible decorations.
// FIXME: Per spec, we still need to draw all relevant decorations
// from ancestors, not just the nearest one from each.
PRUint8 decorMask = NS_STYLE_TEXT_DECORATION_LINE_LINES_MASK;
// frameTopOffset represents the offset to f's top from our baseline in our
// coordinate space
// baselineOffset represents the offset from our baseline to f's baseline or
// the nearest block's baseline, in our coordinate space, whichever is closest
// during the particular iteration
nscoord frameTopOffset = mAscent,
baselineOffset = 0;
PRBool isChild; // ignored
for (nsIFrame* f = this; decorMask && f;
NS_SUCCEEDED(f->GetParentStyleContextFrame(aPresContext, &f, &isChild))
|| (f = nsnull)) {
nsStyleContext* context = f->GetStyleContext();
bool nearestBlockFound = false;
for (nsIFrame* f = this, *fParent; f; f = fParent) {
nsStyleContext *const context = f->GetStyleContext();
if (!context->HasTextDecorationLines()) {
break;
}
const nsStyleTextReset* styleText = context->GetStyleTextReset();
if (!useOverride &&
(NS_STYLE_TEXT_DECORATION_LINE_OVERRIDE_ALL &
styleText->mTextDecorationLine)) {
const nsStyleTextReset *const styleText = context->GetStyleTextReset();
const PRUint8 textDecorations = styleText->mTextDecorationLine;
if (!useOverride &&
(NS_STYLE_TEXT_DECORATION_LINE_OVERRIDE_ALL & textDecorations))
{
// This handles the <a href="blah.html"><font color="green">La
// la la</font></a> case. The link underline should be green.
useOverride = PR_TRUE;
@ -4302,38 +4306,51 @@ nsTextFrame::GetTextDecorations(nsPresContext* aPresContext)
eCSSProperty_text_decoration_color);
}
// FIXME: see above (remove this check)
PRUint8 useDecorations = decorMask & styleText->mTextDecorationLine;
if (useDecorations) {// a decoration defined here
nscolor color = context->GetVisitedDependentColor(
eCSSProperty_text_decoration_color);
fParent = nsLayoutUtils::GetParentOrPlaceholderFor(
aPresContext->FrameManager(), f);
const bool firstBlock = !nearestBlockFound &&
nsLayoutUtils::GetAsBlock(fParent);
// FIXME: We also need to record the thickness and position
// metrics appropriate to this element (at least in standards
// mode). This will require adjusting the visual overflow region
// of this frame and maybe its ancestors. The positions should
// probably be relative to the line's baseline (when text
// decorations are specified on inlines we should look for their
// containing line; otherwise use the element's font); when
// drawing it should always be relative to the line baseline.
// This way we move the decorations for relative positioning.
if (NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE & useDecorations) {
decorations.mUnderColor = useOverride ? overrideColor : color;
decorations.mUnderStyle = styleText->GetDecorationStyle();
decorMask &= ~NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE;
decorations.mDecorations |= NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE;
// 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
// children (albeit the style should be preserved)
// However, if we're vertically aligned within a block, then we need to
// recover the right baseline from the line by querying the FrameProperty
// that should be set (see nsLineLayout::VerticalAlignLine).
if (firstBlock &&
(styleText->mVerticalAlign.GetUnit() != eStyleUnit_Enumerated ||
styleText->mVerticalAlign.GetIntValue() !=
NS_STYLE_VERTICAL_ALIGN_BASELINE)) {
baselineOffset = frameTopOffset -
NS_PTR_TO_INT32(f->Properties().Get(nsIFrame::LineBaselineOffset()));
}
else if (!nearestBlockFound) {
baselineOffset = frameTopOffset - f->GetBaseline();
}
nearestBlockFound = nearestBlockFound || firstBlock;
frameTopOffset += f->GetRect().Y() - f->GetRelativeOffset().y;
const PRUint8 style = styleText->GetDecorationStyle();
// Accumulate only elements that have decorations with a genuine style
if (textDecorations && style != NS_STYLE_TEXT_DECORATION_STYLE_NONE) {
const nscolor color = useOverride ? overrideColor
: context->GetVisitedDependentColor(eCSSProperty_text_decoration_color);
if (textDecorations & NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE) {
aDecorations.mUnderlines.AppendElement(
nsTextFrame::LineDecoration(f, baselineOffset, color,
style));
}
if (NS_STYLE_TEXT_DECORATION_LINE_OVERLINE & useDecorations) {
decorations.mOverColor = useOverride ? overrideColor : color;
decorations.mOverStyle = styleText->GetDecorationStyle();
decorMask &= ~NS_STYLE_TEXT_DECORATION_LINE_OVERLINE;
decorations.mDecorations |= NS_STYLE_TEXT_DECORATION_LINE_OVERLINE;
if (textDecorations & NS_STYLE_TEXT_DECORATION_LINE_OVERLINE) {
aDecorations.mOverlines.AppendElement(
nsTextFrame::LineDecoration(f, baselineOffset, color,
style));
}
if (NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH & useDecorations) {
decorations.mStrikeColor = useOverride ? overrideColor : color;
decorations.mStrikeStyle = styleText->GetDecorationStyle();
decorMask &= ~NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH;
decorations.mDecorations |= NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH;
if (textDecorations & NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH) {
aDecorations.mStrikes.AppendElement(
nsTextFrame::LineDecoration(f, baselineOffset, color,
style));
}
}
@ -4358,14 +4375,13 @@ nsTextFrame::GetTextDecorations(nsPresContext* aPresContext)
}
}
}
return decorations;
}
void
nsTextFrame::UnionTextDecorationOverflow(nsPresContext* aPresContext,
PropertyProvider& aProvider,
nsRect* aVisualOverflowRect)
nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext,
PropertyProvider& aProvider,
nsRect* aVisualOverflowRect,
bool aIncludeTextDecorations)
{
// Text-shadow overflows
nsRect shadowRect =
@ -4381,10 +4397,75 @@ nsTextFrame::UnionTextDecorationOverflow(nsPresContext* aPresContext,
nsRect fontRect(0, mAscent - fontAscent, GetSize().width, fontHeight);
aVisualOverflowRect->UnionRect(*aVisualOverflowRect, fontRect);
}
if (aIncludeTextDecorations) {
// Since CSS 2.1 requires that text-decoration defined on ancestors maintain
// style and position, they can be drawn at virtually any y-offset, so
// maxima and minima are required to reliably generate the rectangle for
// them
TextDecorations textDecs;
GetTextDecorations(aPresContext, textDecs);
if (textDecs.HasDecorationLines()) {
const nscoord width = GetSize().width;
const gfxFloat appUnitsPerDevUnit = aPresContext->AppUnitsPerDevPixel(),
gfxWidth = width / appUnitsPerDevUnit,
ascent = gfxFloat(mAscent) / appUnitsPerDevUnit;
nscoord top(nscoord_MAX), bottom(nscoord_MIN);
// Below we loop through all text decorations and compute the rectangle
// containing all of them, in this frame's coordinate space
for (PRUint32 i = 0; i < textDecs.mUnderlines.Length(); ++i) {
const LineDecoration& dec = textDecs.mUnderlines[i];
const gfxFont::Metrics metrics =
GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame));
const nsRect decorationRect =
nsCSSRendering::GetTextDecorationRect(aPresContext,
gfxSize(gfxWidth, metrics.underlineSize),
ascent, metrics.underlineOffset,
NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE, dec.mStyle) +
nsPoint(0, -dec.mBaselineOffset);
top = NS_MIN(decorationRect.y, top);
bottom = NS_MAX(decorationRect.YMost(), bottom);
}
for (PRUint32 i = 0; i < textDecs.mOverlines.Length(); ++i) {
const LineDecoration& dec = textDecs.mOverlines[i];
const gfxFont::Metrics metrics =
GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame));
const nsRect decorationRect =
nsCSSRendering::GetTextDecorationRect(aPresContext,
gfxSize(gfxWidth, metrics.underlineSize),
ascent, metrics.maxAscent,
NS_STYLE_TEXT_DECORATION_LINE_OVERLINE, dec.mStyle) +
nsPoint(0, -dec.mBaselineOffset);
top = NS_MIN(decorationRect.y, top);
bottom = NS_MAX(decorationRect.YMost(), bottom);
}
for (PRUint32 i = 0; i < textDecs.mStrikes.Length(); ++i) {
const LineDecoration& dec = textDecs.mStrikes[i];
const gfxFont::Metrics metrics =
GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame));
const nsRect decorationRect =
nsCSSRendering::GetTextDecorationRect(aPresContext,
gfxSize(gfxWidth, metrics.strikeoutSize),
ascent, metrics.strikeoutOffset,
NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH, dec.mStyle) +
nsPoint(0, -dec.mBaselineOffset);
top = NS_MIN(decorationRect.y, top);
bottom = NS_MAX(decorationRect.YMost(), bottom);
}
aVisualOverflowRect->UnionRect(*aVisualOverflowRect,
nsRect(0, top, width, bottom - top));
}
}
// When this frame is not selected, the text-decoration area must be in
// frame bounds.
nsRect decorationRect;
if (!(GetStateBits() & NS_FRAME_SELECTED_CONTENT) ||
!CombineSelectionUnderlineRect(aPresContext, *aVisualOverflowRect))
return;
@ -4401,52 +4482,67 @@ nsTextFrame::PaintTextDecorations(
const nsCharClipDisplayItem::ClipEdges& aClipEdges,
const nscolor* aOverrideColor)
{
TextDecorations decorations =
GetTextDecorations(aTextPaintStyle.PresContext());
if (!decorations.HasDecorationlines())
TextDecorations decorations;
GetTextDecorations(aTextPaintStyle.PresContext(), decorations);
if (!decorations.HasDecorationLines())
return;
// Hide text decorations if we're currently hiding @font-face fallback text
if (aProvider.GetFontGroup()->ShouldSkipDrawing())
return;
gfxFont* firstFont = aProvider.GetFontGroup()->GetFontAt(0);
if (!firstFont)
return; // OOM
const gfxFont::Metrics& fontMetrics = firstFont->GetMetrics();
gfxFloat app = aTextPaintStyle.PresContext()->AppUnitsPerDevPixel();
const gfxFloat app = aTextPaintStyle.PresContext()->AppUnitsPerDevPixel();
// XXX aFramePt is in AppUnits, shouldn't it be nsFloatPoint?
nscoord x = NSToCoordRound(aFramePt.x);
nscoord width = GetRect().width;
aClipEdges.Intersect(&x, &width);
gfxPoint pt(x / app, (aTextBaselinePt.y - mAscent) / app);
gfxPoint pt(x / app, 0);
gfxSize size(width / app, 0);
gfxFloat ascent = gfxFloat(mAscent) / app;
const gfxFloat ascent = gfxFloat(mAscent) / app;
const nscoord baseline = aTextBaselinePt.y - mAscent;
nscolor lineColor;
if (decorations.HasOverline()) {
lineColor = aOverrideColor ? *aOverrideColor : decorations.mOverColor;
size.height = fontMetrics.underlineSize;
nsCSSRendering::PaintDecorationLine(
aCtx, lineColor, pt, size, ascent, fontMetrics.maxAscent,
NS_STYLE_TEXT_DECORATION_LINE_OVERLINE, decorations.mOverStyle);
for (PRUint32 i = decorations.mUnderlines.Length(); i-- > 0; ) {
const LineDecoration& dec = decorations.mUnderlines[i];
gfxFontGroup* fontGroup = GetFontGroupForFrame(dec.mFrame);
const gfxFont::Metrics metrics = GetFirstFontMetrics(fontGroup);
size.height = metrics.underlineSize;
pt.y = (baseline - dec.mBaselineOffset) / app;
lineColor = aOverrideColor ? *aOverrideColor : dec.mColor;
nsCSSRendering::PaintDecorationLine(aCtx, lineColor, pt, size, ascent,
fontGroup->GetUnderlineOffset(), NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE,
dec.mStyle);
}
if (decorations.HasUnderline()) {
lineColor = aOverrideColor ? *aOverrideColor : decorations.mUnderColor;
size.height = fontMetrics.underlineSize;
gfxFloat offset = aProvider.GetFontGroup()->GetUnderlineOffset();
nsCSSRendering::PaintDecorationLine(
aCtx, lineColor, pt, size, ascent, offset,
NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE, decorations.mUnderStyle);
for (PRUint32 i = decorations.mOverlines.Length(); i-- > 0; ) {
const LineDecoration& dec = decorations.mOverlines[i];
const gfxFont::Metrics metrics =
GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame));
size.height = metrics.underlineSize;
pt.y = (baseline - dec.mBaselineOffset) / app;
lineColor = aOverrideColor ? *aOverrideColor : dec.mColor;
nsCSSRendering::PaintDecorationLine(aCtx, lineColor, pt, size, ascent,
metrics.maxAscent, NS_STYLE_TEXT_DECORATION_LINE_OVERLINE, dec.mStyle);
}
if (decorations.HasStrikeout()) {
lineColor = aOverrideColor ? *aOverrideColor : decorations.mStrikeColor;
size.height = fontMetrics.strikeoutSize;
gfxFloat offset = fontMetrics.strikeoutOffset;
nsCSSRendering::PaintDecorationLine(
aCtx, lineColor, pt, size, ascent, offset,
NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH, decorations.mStrikeStyle);
for (PRUint32 i = decorations.mStrikes.Length(); i-- > 0; ) {
const LineDecoration& dec = decorations.mStrikes[i];
const gfxFont::Metrics metrics =
GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame));
size.height = metrics.strikeoutSize;
pt.y = (baseline - dec.mBaselineOffset) / app;
lineColor = aOverrideColor ? *aOverrideColor : dec.mColor;
nsCSSRendering::PaintDecorationLine(aCtx, lineColor, pt, size, ascent,
metrics.strikeoutOffset, NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH,
dec.mStyle);
}
}
@ -7094,7 +7190,11 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
aMetrics.SetOverflowAreasToDesiredBounds();
aMetrics.VisualOverflow().UnionRect(aMetrics.VisualOverflow(), boundingBox);
UnionTextDecorationOverflow(presContext, provider, &aMetrics.VisualOverflow());
// When we have text decorations, we don't need to compute their overflow now
// because we're guaranteed to do it later
// (see nsLineLayout::RelativePositionFrames)
UnionAdditionalOverflow(presContext, provider, &aMetrics.VisualOverflow(),
false);
/////////////////////////////////////////////////////////////////////
// Clean up, update state
@ -7348,15 +7448,11 @@ nsTextFrame::RecomputeOverflow()
ComputeTransformedLength(provider),
gfxFont::LOOSE_INK_EXTENTS, nsnull,
&provider);
nsRect &vis = result.VisualOverflow();
vis.UnionRect(vis, RoundOut(textMetrics.mBoundingBox) + nsPoint(0, mAscent));
UnionTextDecorationOverflow(PresContext(), provider, &vis);
UnionAdditionalOverflow(PresContext(), provider, &vis, true);
return result;
}
static PRUnichar TransformChar(const nsStyleText* aStyle, gfxTextRun* aTextRun,
PRUint32 aSkippedOffset, PRUnichar aChar)
{

View File

@ -0,0 +1,16 @@
<html>
<head>
<style>
.high {vertical-align: 5em;}
.invisible {color: transparent;}
</style>
</head>
<body>
<div>
<span style="text-decoration: underline;">
underline<span class="invisible">continued<span class="invisible">continued</span></span></span>
<span class="invisible high">offset<span class="invisible high">offset</span></span>
</div>
<span style="text-decoration: underline;">also underlined</span>
</body>
</html>

View File

@ -0,0 +1,14 @@
<html>
<head>
<style>
.high {vertical-align: 5em;}
.invisible {color: transparent;}
</style>
</head>
<body>
<div style="text-decoration: underline;">
underline<span class="invisible high">continued<span class="invisible high">continued</span></span><br>
also underlined
</div>
</body>
</html>

View File

@ -0,0 +1,29 @@
<html>
<head>
<style>
.sup {vertical-align: super;}
.transparent {color: transparent;}
.alllines {text-decoration:line-through overline underline; color: purple;}
.highRel {position: relative; top: -4em;}
.lowRel {position: relative; top: 4em;}
.lowVert {vertical-align: -4em;}
.highVert {vertical-align: 4em;}
</style>
</head>
<body>
<p>
<span style="text-decoration: underline">Underlined <span class="transparent">still underlined</span></span>
<span style="text-decoration: underline">Underlined <span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span>
<span class="sup transparent">Offset</span>
</p>
<p>
<span class="alllines">
Before<span class="transparent">highlow</span>After</span>
</span>
<span class="highVert transparent">Offset</span><span class="lowVert transparent">text</span>
</p>
<p>
<span class="alllines">Before</span><span class="highRel alllines">high</span><span class="lowRel alllines">low</span><span class="alllines">After</span>
</p>
</body>
</html>

View File

@ -0,0 +1,29 @@
<html>
<head>
<style>
.sup {vertical-align: super;}
.transparent {color: transparent;}
.alllines {text-decoration:line-through overline underline; color: purple;}
.highRel {position: relative; top: -4em;}
.lowRel {position: relative; top: 4em;}
.lowVert {vertical-align: -4em;}
.highVert {vertical-align: 4em;}
</style>
</head>
<body>
<p>
<span style="text-decoration: underline">Underlined <span class="sup transparent">still underlined</span></span>
<span style="text-decoration: underline">Underlined <span class="sup">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></span>
</p>
<p>
<span class="alllines">
Before<span class="highVert transparent">high</span><span class="lowVert transparent">low</span>After
</span>
</p>
<p>
<span class="alllines">
Before<span class="highRel">high</span><span class="lowRel">low</span>After</span>
</span>
</p>
</body>
</html>

View File

@ -20,11 +20,13 @@
<span style="text-decoration: underline line-through overline;
-moz-text-decoration-style: dotted;">
Here has dotted decoration lines,
</span><span style="font-size: 2em;
text-decoration: underline line-through overline;
-moz-text-decoration-style: wavy;">
</span><span style="text-decoration: underline line-through overline;
-moz-text-decoration-style: dotted">
<span style="font-size: 2em;
text-decoration: underline line-through overline;
-moz-text-decoration-style: wavy;">
here has wavy decoration
lines</span><span style="text-decoration: underline line-through overline;
lines</span></span><span style="text-decoration: underline line-through overline;
-moz-text-decoration-style: dotted;">,
and here has dotted decoration lines.</span>
</p>
@ -32,13 +34,11 @@
<span style="text-decoration: underline line-through overline;
-moz-text-decoration-style: double;">
Here has double decoration lines,
</span><span style="font-size: 2em;
text-decoration: underline line-through overline;
-moz-text-decoration-style: double;">
<span style="font-size: 2em;">
here is specified as dashed decoration lines but should be
ignored</span><span style="text-decoration: underline line-through overline;
-moz-text-decoration-style: double;">,
and here has double decoration lines.</span>
and here has double decoration lines.</span></span>
</p>
<p>
Here is specified the decoration style as -moz-none.

View File

@ -89,3 +89,5 @@ fails == text-decoration-zorder-1-quirks.html text-decoration-zorder-1-ref.html
== text-decoration-propagation-1-quirks.html text-decoration-propagation-1-quirks-ref.html
fails == text-decoration-propagation-1-standards.html text-decoration-propagation-1-standards-ref.html
== 641444-1.html 641444-1-ref.html
== decoration-css21.html decoration-css21-ref.html # bug 403524
== decoration-css21-block.html decoration-css21-block-ref.html # bug 403524

View File

@ -134,6 +134,7 @@
filter: inherit;
mask: inherit;
opacity: inherit;
text-decoration: inherit;
-moz-box-ordinal-group: inherit !important;
}