mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 11:25:00 +00:00
Bug 1093553 - Improve handling of line-height metrics, block ascent, etc., in vertical writing mode. r=smontagu
This commit is contained in:
parent
e27a2da74c
commit
34fea182cd
@ -1902,22 +1902,28 @@ gfxFont::Draw(gfxTextRun *aTextRun, uint32_t aStart, uint32_t aEnd,
|
||||
gfxPoint p(aPt->x * aRunParams.devPerApp,
|
||||
aPt->y * aRunParams.devPerApp);
|
||||
const Metrics& metrics = GetMetrics(eHorizontal);
|
||||
// Adjust the matrix to draw the (horizontally-shaped) textrun with
|
||||
// 90-degree CW rotation, and adjust position so that the rotated
|
||||
// horizontal text (which uses a standard alphabetic baseline) will
|
||||
// Get a matrix we can use to draw the (horizontally-shaped) textrun
|
||||
// with 90-degree CW rotation.
|
||||
gfxMatrix mat = aRunParams.context->CurrentMatrix().
|
||||
Translate(p). // translate origin for rotation
|
||||
Rotate(M_PI / 2.0). // turn 90deg clockwise
|
||||
Translate(-p); // undo the translation
|
||||
|
||||
// If we're drawing rotated horizontal text for an element styled
|
||||
// text-orientation:mixed, the dominant baseline will be vertical-
|
||||
// centered. So in this case, we need to adjust the position so that
|
||||
// the rotated horizontal text (which uses an alphabetic baseline) will
|
||||
// look OK when juxtaposed with upright glyphs (rendered on a centered
|
||||
// vertical baseline). The adjustment here is somewhat ad hoc; we
|
||||
// should eventually look for baseline tables[1] in the fonts and use
|
||||
// those if available.
|
||||
// [1] http://www.microsoft.com/typography/otspec/base.htm
|
||||
aRunParams.context->SetMatrix(aRunParams.context->CurrentMatrix().
|
||||
Translate(p). // translate origin for rotation
|
||||
Rotate(M_PI / 2.0). // turn 90deg clockwise
|
||||
Translate(-p). // undo the translation
|
||||
Translate(gfxPoint(0, (metrics.emAscent - metrics.emDescent) / 2)));
|
||||
// and offset the (alphabetic) baseline of the
|
||||
// horizontally-shaped text from the (centered)
|
||||
// default baseline used for vertical
|
||||
// [1] See http://www.microsoft.com/typography/otspec/base.htm
|
||||
if (aTextRun->UseCenterBaseline()) {
|
||||
gfxPoint baseAdj(0, (metrics.emAscent - metrics.emDescent) / 2);
|
||||
mat.Translate(baseAdj);
|
||||
}
|
||||
|
||||
aRunParams.context->SetMatrix(mat);
|
||||
}
|
||||
|
||||
nsAutoPtr<gfxTextContextPaint> contextPaint;
|
||||
@ -2138,15 +2144,33 @@ gfxFont::Measure(gfxTextRun *aTextRun,
|
||||
// Current position in appunits
|
||||
gfxFont::Orientation orientation =
|
||||
aOrientation == gfxTextRunFactory::TEXT_ORIENT_VERTICAL_UPRIGHT
|
||||
? gfxFont::eVertical : gfxFont::eHorizontal;
|
||||
? eVertical : eHorizontal;
|
||||
const gfxFont::Metrics& fontMetrics = GetMetrics(orientation);
|
||||
|
||||
gfxFloat baselineOffset = 0;
|
||||
if (aTextRun->UseCenterBaseline() && orientation == eHorizontal) {
|
||||
// For a horizontal font being used in vertical writing mode with
|
||||
// text-orientation:mixed, the overall metrics we're accumulating
|
||||
// will be aimed at a center baseline. But this font's metrics were
|
||||
// based on the alphabetic baseline. So we compute a baseline offset
|
||||
// that will be applied to ascent/descent values and glyph rects
|
||||
// to effectively shift them relative to the baseline.
|
||||
// XXX Eventually we should probably use the BASE table, if present.
|
||||
// But it usually isn't, so we need an ad hoc adjustment for now.
|
||||
baselineOffset = appUnitsPerDevUnit *
|
||||
(fontMetrics.emAscent - fontMetrics.emDescent) / 2;
|
||||
}
|
||||
|
||||
RunMetrics metrics;
|
||||
metrics.mAscent = fontMetrics.maxAscent*appUnitsPerDevUnit;
|
||||
metrics.mDescent = fontMetrics.maxDescent*appUnitsPerDevUnit;
|
||||
metrics.mAscent = fontMetrics.maxAscent * appUnitsPerDevUnit;
|
||||
metrics.mDescent = fontMetrics.maxDescent * appUnitsPerDevUnit;
|
||||
|
||||
if (aStart == aEnd) {
|
||||
// exit now before we look at aSpacing[0], which is undefined
|
||||
metrics.mBoundingBox = gfxRect(0, -metrics.mAscent, 0, metrics.mAscent + metrics.mDescent);
|
||||
metrics.mAscent -= baselineOffset;
|
||||
metrics.mDescent += baselineOffset;
|
||||
metrics.mBoundingBox = gfxRect(0, -metrics.mAscent,
|
||||
0, metrics.mAscent + metrics.mDescent);
|
||||
return metrics;
|
||||
}
|
||||
|
||||
@ -2247,6 +2271,12 @@ gfxFont::Measure(gfxTextRun *aTextRun,
|
||||
metrics.mBoundingBox -= gfxPoint(x, 0);
|
||||
}
|
||||
|
||||
if (baselineOffset != 0) {
|
||||
metrics.mAscent -= baselineOffset;
|
||||
metrics.mDescent += baselineOffset;
|
||||
metrics.mBoundingBox.y += baselineOffset;
|
||||
}
|
||||
|
||||
metrics.mAdvanceWidth = x*direction;
|
||||
return metrics;
|
||||
}
|
||||
|
@ -4162,8 +4162,12 @@ nsCSSRendering::PaintDecorationLine(nsIFrame* aFrame,
|
||||
return;
|
||||
}
|
||||
|
||||
// The y position should be set to the middle of the line.
|
||||
rect.y += lineThickness / 2;
|
||||
// The block-direction position should be set to the middle of the line.
|
||||
if (aVertical) {
|
||||
rect.x -= lineThickness / 2;
|
||||
} else {
|
||||
rect.y += lineThickness / 2;
|
||||
}
|
||||
|
||||
switch (aStyle) {
|
||||
case NS_STYLE_TEXT_DECORATION_STYLE_SOLID:
|
||||
@ -4360,12 +4364,18 @@ nsCSSRendering::DecorationLineToPath(nsIFrame* aFrame,
|
||||
|
||||
gfxFloat lineThickness = std::max(NS_round(aLineSize.height), 1.0);
|
||||
|
||||
// The y position should be set to the middle of the line.
|
||||
rect.y += lineThickness / 2;
|
||||
|
||||
aGfxContext->Rectangle
|
||||
(gfxRect(gfxPoint(rect.TopLeft() - gfxPoint(0.0, lineThickness / 2)),
|
||||
gfxSize(rect.Width(), lineThickness)));
|
||||
// The block-direction position should be set to the middle of the line.
|
||||
if (aVertical) {
|
||||
rect.x -= lineThickness / 2;
|
||||
aGfxContext->Rectangle
|
||||
(gfxRect(gfxPoint(rect.TopLeft() - gfxPoint(lineThickness / 2, 0.0)),
|
||||
gfxSize(lineThickness, rect.Height())));
|
||||
} else {
|
||||
rect.y += lineThickness / 2;
|
||||
aGfxContext->Rectangle
|
||||
(gfxRect(gfxPoint(rect.TopLeft() - gfxPoint(0.0, lineThickness / 2)),
|
||||
gfxSize(rect.Width(), lineThickness)));
|
||||
}
|
||||
}
|
||||
|
||||
nsRect
|
||||
|
@ -3496,7 +3496,8 @@ nsLayoutUtils::GetFontMetricsForStyleContext(nsStyleContext* aStyleContext,
|
||||
WritingMode wm(aStyleContext);
|
||||
return pc->DeviceContext()->GetMetricsFor(
|
||||
font, aStyleContext->StyleFont()->mLanguage,
|
||||
wm.IsVertical() ? gfxFont::eVertical : gfxFont::eHorizontal,
|
||||
wm.IsVertical() && !wm.IsSideways()
|
||||
? gfxFont::eVertical : gfxFont::eHorizontal,
|
||||
fs, tp, *aFontMetrics);
|
||||
}
|
||||
|
||||
@ -4893,9 +4894,11 @@ nsLayoutUtils::PaintTextShadow(const nsIFrame* aFrame,
|
||||
|
||||
/* static */ nscoord
|
||||
nsLayoutUtils::GetCenteredFontBaseline(nsFontMetrics* aFontMetrics,
|
||||
nscoord aLineHeight)
|
||||
nscoord aLineHeight,
|
||||
bool aIsInverted)
|
||||
{
|
||||
nscoord fontAscent = aFontMetrics->MaxAscent();
|
||||
nscoord fontAscent = aIsInverted ? aFontMetrics->MaxDescent()
|
||||
: aFontMetrics->MaxAscent();
|
||||
nscoord fontHeight = aFontMetrics->MaxHeight();
|
||||
|
||||
nscoord leading = aLineHeight - fontHeight;
|
||||
@ -7350,7 +7353,8 @@ nsLayoutUtils::SetBSizeFromFontMetrics(const nsIFrame* aFrame,
|
||||
// The height of our box is the sum of our font size plus the top
|
||||
// and bottom border and padding. The height of children do not
|
||||
// affect our height.
|
||||
aMetrics.SetBlockStartAscent(fm->MaxAscent());
|
||||
aMetrics.SetBlockStartAscent(aLineWM.IsLineInverted() ? fm->MaxDescent()
|
||||
: fm->MaxAscent());
|
||||
aMetrics.BSize(aLineWM) = fm->MaxHeight();
|
||||
} else {
|
||||
NS_WARNING("Cannot get font metrics - defaulting sizes to 0");
|
||||
|
@ -1397,11 +1397,15 @@ public:
|
||||
/**
|
||||
* Gets the baseline to vertically center text from a font within a
|
||||
* line of specified height.
|
||||
* aIsInverted: true if the text is inverted relative to the block
|
||||
* direction, so that the block-dir "ascent" corresponds to font
|
||||
* descent. (Applies to sideways text in vertical-lr mode.)
|
||||
*
|
||||
* Returns the baseline position relative to the top of the line.
|
||||
*/
|
||||
static nscoord GetCenteredFontBaseline(nsFontMetrics* aFontMetrics,
|
||||
nscoord aLineHeight);
|
||||
nscoord aLineHeight,
|
||||
bool aIsInverted);
|
||||
|
||||
/**
|
||||
* Derive a baseline of |aFrame| (measured from its top border edge)
|
||||
|
@ -519,7 +519,8 @@ nsTextControlFrame::Reflow(nsPresContext* aPresContext,
|
||||
inflation);
|
||||
// now adjust for our borders and padding
|
||||
aDesiredSize.SetBlockStartAscent(
|
||||
nsLayoutUtils::GetCenteredFontBaseline(fontMet, lineHeight) +
|
||||
nsLayoutUtils::GetCenteredFontBaseline(fontMet, lineHeight,
|
||||
wm.IsLineInverted()) +
|
||||
aReflowState.ComputedLogicalBorderPadding().BStart(wm));
|
||||
|
||||
// overflow handling
|
||||
|
@ -168,12 +168,17 @@ public:
|
||||
/**
|
||||
* Return true if LTR. (Convenience method)
|
||||
*/
|
||||
bool IsBidiLTR() const { return eBidiLTR == (mWritingMode & eBidiMask); }
|
||||
bool IsBidiLTR() const { return eBidiLTR == GetBidiDir(); }
|
||||
|
||||
/**
|
||||
* True if vertical-mode block direction is LR (convenience method).
|
||||
*/
|
||||
bool IsVerticalLR() const { return eBlockLR == (mWritingMode & eBlockMask); }
|
||||
bool IsVerticalLR() const { return eBlockLR == GetBlockDir(); }
|
||||
|
||||
/**
|
||||
* True if vertical-mode block direction is RL (convenience method).
|
||||
*/
|
||||
bool IsVerticalRL() const { return eBlockRL == GetBlockDir(); }
|
||||
|
||||
/**
|
||||
* True if vertical writing mode, i.e. when
|
||||
|
@ -122,7 +122,8 @@ BRFrame::Reflow(nsPresContext* aPresContext,
|
||||
if (fm) {
|
||||
nscoord logicalHeight = aReflowState.CalcLineHeight();
|
||||
finalSize.BSize(wm) = logicalHeight;
|
||||
aMetrics.SetBlockStartAscent(nsLayoutUtils::GetCenteredFontBaseline(fm, logicalHeight));
|
||||
aMetrics.SetBlockStartAscent(nsLayoutUtils::GetCenteredFontBaseline(
|
||||
fm, logicalHeight, wm.IsLineInverted()));
|
||||
}
|
||||
else {
|
||||
aMetrics.SetBlockStartAscent(aMetrics.BSize(wm) = 0);
|
||||
|
@ -515,7 +515,9 @@ nsBlockFrame::GetCaretBaseline() const
|
||||
nscoord lineHeight =
|
||||
nsHTMLReflowState::CalcLineHeight(GetContent(), StyleContext(),
|
||||
contentRect.height, inflation);
|
||||
return nsLayoutUtils::GetCenteredFontBaseline(fm, lineHeight) + bp.top;
|
||||
const WritingMode wm = GetWritingMode();
|
||||
return nsLayoutUtils::GetCenteredFontBaseline(fm, lineHeight,
|
||||
wm.IsLineInverted()) + bp.top;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
@ -2552,7 +2554,8 @@ nsBlockFrame::ReflowDirtyLines(nsBlockReflowState& aState)
|
||||
nsLayoutUtils::FontSizeInflationFor(this));
|
||||
|
||||
nscoord minAscent =
|
||||
nsLayoutUtils::GetCenteredFontBaseline(fm, aState.mMinLineHeight);
|
||||
nsLayoutUtils::GetCenteredFontBaseline(fm, aState.mMinLineHeight,
|
||||
wm.IsLineInverted());
|
||||
nscoord minDescent = aState.mMinLineHeight - minAscent;
|
||||
|
||||
aState.mBCoord += std::max(minAscent, metrics.BlockStartAscent()) +
|
||||
|
@ -1339,7 +1339,12 @@ nsFrame::GetLogicalBaseline(WritingMode aWritingMode) const
|
||||
{
|
||||
NS_ASSERTION(!NS_SUBTREE_DIRTY(this),
|
||||
"frame must not be dirty");
|
||||
// Default to the bottom margin edge, per CSS2.1's definition of the
|
||||
// Baseline for inverted line content is the top (block-start) margin edge,
|
||||
// as the frame is in effect "flipped" for alignment purposes.
|
||||
if (aWritingMode.IsLineInverted()) {
|
||||
return -GetLogicalUsedMargin(aWritingMode).BStart(aWritingMode);
|
||||
}
|
||||
// Otherwise, the bottom margin edge, per CSS2.1's definition of the
|
||||
// 'baseline' value of 'vertical-align'.
|
||||
return BSize(aWritingMode) +
|
||||
GetLogicalUsedMargin(aWritingMode).BEnd(aWritingMode);
|
||||
|
@ -2098,7 +2098,8 @@ nsLineLayout::VerticalAlignFrames(PerSpanData* psd)
|
||||
#endif
|
||||
nscoord minimumLineBSize = mMinLineBSize;
|
||||
nscoord blockStart =
|
||||
-nsLayoutUtils::GetCenteredFontBaseline(fm, minimumLineBSize);
|
||||
-nsLayoutUtils::GetCenteredFontBaseline(fm, minimumLineBSize,
|
||||
lineWM.IsLineInverted());
|
||||
nscoord blockEnd = blockStart + minimumLineBSize;
|
||||
|
||||
if (blockStart < minBCoord) minBCoord = blockStart;
|
||||
|
@ -1790,13 +1790,13 @@ GetHyphenTextRun(gfxTextRun* aTextRun, gfxContext* aContext, nsTextFrame* aTextF
|
||||
}
|
||||
|
||||
static gfxFont::Metrics
|
||||
GetFirstFontMetrics(gfxFontGroup* aFontGroup, bool aVertical)
|
||||
GetFirstFontMetrics(gfxFontGroup* aFontGroup, bool aVerticalMetrics)
|
||||
{
|
||||
if (!aFontGroup)
|
||||
return gfxFont::Metrics();
|
||||
gfxFont* font = aFontGroup->GetFirstValidFont();
|
||||
return font->GetMetrics(aVertical ? gfxFont::eVertical :
|
||||
gfxFont::eHorizontal);
|
||||
return font->GetMetrics(aVerticalMetrics ? gfxFont::eVertical
|
||||
: gfxFont::eHorizontal);
|
||||
}
|
||||
|
||||
PR_STATIC_ASSERT(NS_STYLE_WHITESPACE_NORMAL == 0);
|
||||
@ -3161,7 +3161,7 @@ ComputeTabWidthAppUnits(nsIFrame* aFrame, gfxTextRun* aTextRun)
|
||||
// textruns do
|
||||
gfxFloat spaceWidthAppUnits =
|
||||
NS_round(GetFirstFontMetrics(aTextRun->GetFontGroup(),
|
||||
aTextRun->IsVertical()).spaceWidth *
|
||||
aTextRun->UseCenterBaseline()).spaceWidth *
|
||||
aTextRun->GetAppUnitsPerDevUnit());
|
||||
return textStyle->mTabSize * spaceWidthAppUnits;
|
||||
}
|
||||
@ -4918,7 +4918,9 @@ nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext,
|
||||
nsRect shadowRect =
|
||||
nsLayoutUtils::GetTextShadowRectsUnion(*aVisualOverflowRect, this);
|
||||
aVisualOverflowRect->UnionRect(*aVisualOverflowRect, shadowRect);
|
||||
bool vertical = mTextRun->IsVertical();
|
||||
bool verticalRun = mTextRun->IsVertical();
|
||||
bool useVerticalMetrics = verticalRun && mTextRun->UseCenterBaseline();
|
||||
bool inverted = GetWritingMode().IsLineInverted();
|
||||
|
||||
if (IsFloatingFirstLetterChild()) {
|
||||
// The underline/overline drawable area must be contained in the overflow
|
||||
@ -4935,11 +4937,13 @@ nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext,
|
||||
nsFontMetrics* fontMetrics = aProvider.GetFontMetrics();
|
||||
nscoord underlineOffset, underlineSize;
|
||||
fontMetrics->GetUnderline(underlineOffset, underlineSize);
|
||||
nscoord maxAscent = fontMetrics->MaxAscent();
|
||||
nscoord maxAscent = inverted ? fontMetrics->MaxDescent()
|
||||
: fontMetrics->MaxAscent();
|
||||
|
||||
gfxFloat appUnitsPerDevUnit = aPresContext->AppUnitsPerDevPixel();
|
||||
gfxFloat gfxWidth =
|
||||
(vertical ? aVisualOverflowRect->height : aVisualOverflowRect->width) /
|
||||
(verticalRun ? aVisualOverflowRect->height
|
||||
: aVisualOverflowRect->width) /
|
||||
appUnitsPerDevUnit;
|
||||
gfxFloat gfxAscent = gfxFloat(mAscent) / appUnitsPerDevUnit;
|
||||
gfxFloat gfxMaxAscent = maxAscent / appUnitsPerDevUnit;
|
||||
@ -4948,11 +4952,11 @@ nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext,
|
||||
nsRect underlineRect =
|
||||
nsCSSRendering::GetTextDecorationRect(aPresContext,
|
||||
gfxSize(gfxWidth, gfxUnderlineSize), gfxAscent, gfxUnderlineOffset,
|
||||
NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE, decorationStyle, vertical);
|
||||
NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE, decorationStyle, verticalRun);
|
||||
nsRect overlineRect =
|
||||
nsCSSRendering::GetTextDecorationRect(aPresContext,
|
||||
gfxSize(gfxWidth, gfxUnderlineSize), gfxAscent, gfxMaxAscent,
|
||||
NS_STYLE_TEXT_DECORATION_LINE_OVERLINE, decorationStyle, vertical);
|
||||
NS_STYLE_TEXT_DECORATION_LINE_OVERLINE, decorationStyle, verticalRun);
|
||||
|
||||
aVisualOverflowRect->UnionRect(*aVisualOverflowRect, underlineRect);
|
||||
aVisualOverflowRect->UnionRect(*aVisualOverflowRect, overlineRect);
|
||||
@ -4972,11 +4976,16 @@ nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext,
|
||||
nscoord inflationMinFontSize =
|
||||
nsLayoutUtils::InflationMinFontSizeFor(aBlock);
|
||||
|
||||
const nscoord measure = vertical ? GetSize().height : GetSize().width;
|
||||
const nscoord measure = verticalRun ? GetSize().height : GetSize().width;
|
||||
const gfxFloat appUnitsPerDevUnit = aPresContext->AppUnitsPerDevPixel(),
|
||||
gfxWidth = measure / appUnitsPerDevUnit,
|
||||
ascent = gfxFloat(mAscent) / appUnitsPerDevUnit;
|
||||
nscoord top(nscoord_MAX), bottom(nscoord_MIN);
|
||||
gfxWidth = measure / appUnitsPerDevUnit;
|
||||
gfxFloat ascent = gfxFloat(mAscent) / appUnitsPerDevUnit;
|
||||
const WritingMode wm = GetWritingMode();
|
||||
if (wm.IsVerticalRL()) {
|
||||
ascent = -ascent;
|
||||
}
|
||||
|
||||
nscoord topOrLeft(nscoord_MAX), bottomOrRight(nscoord_MIN);
|
||||
// Below we loop through all text decorations and compute the rectangle
|
||||
// containing all of them, in this frame's coordinate space
|
||||
for (uint32_t i = 0; i < textDecs.mUnderlines.Length(); ++i) {
|
||||
@ -4993,18 +5002,23 @@ nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext,
|
||||
GetInflationForTextDecorations(dec.mFrame, inflationMinFontSize);
|
||||
const gfxFont::Metrics metrics =
|
||||
GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame, inflation),
|
||||
vertical);
|
||||
useVerticalMetrics);
|
||||
|
||||
const nsRect decorationRect =
|
||||
nsCSSRendering::GetTextDecorationRect(aPresContext,
|
||||
gfxSize(gfxWidth, metrics.underlineSize),
|
||||
ascent, metrics.underlineOffset,
|
||||
NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE, decorationStyle,
|
||||
vertical) +
|
||||
verticalRun) +
|
||||
nsPoint(0, -dec.mBaselineOffset);
|
||||
|
||||
top = std::min(decorationRect.y, top);
|
||||
bottom = std::max(decorationRect.YMost(), bottom);
|
||||
if (verticalRun) {
|
||||
topOrLeft = std::min(decorationRect.x, topOrLeft);
|
||||
bottomOrRight = std::max(decorationRect.XMost(), bottomOrRight);
|
||||
} else {
|
||||
topOrLeft = std::min(decorationRect.y, topOrLeft);
|
||||
bottomOrRight = std::max(decorationRect.YMost(), bottomOrRight);
|
||||
}
|
||||
}
|
||||
for (uint32_t i = 0; i < textDecs.mOverlines.Length(); ++i) {
|
||||
const LineDecoration& dec = textDecs.mOverlines[i];
|
||||
@ -5020,18 +5034,23 @@ nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext,
|
||||
GetInflationForTextDecorations(dec.mFrame, inflationMinFontSize);
|
||||
const gfxFont::Metrics metrics =
|
||||
GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame, inflation),
|
||||
vertical);
|
||||
useVerticalMetrics);
|
||||
|
||||
const nsRect decorationRect =
|
||||
nsCSSRendering::GetTextDecorationRect(aPresContext,
|
||||
gfxSize(gfxWidth, metrics.underlineSize),
|
||||
ascent, metrics.maxAscent,
|
||||
NS_STYLE_TEXT_DECORATION_LINE_OVERLINE, decorationStyle,
|
||||
vertical) +
|
||||
verticalRun) +
|
||||
nsPoint(0, -dec.mBaselineOffset);
|
||||
|
||||
top = std::min(decorationRect.y, top);
|
||||
bottom = std::max(decorationRect.YMost(), bottom);
|
||||
if (verticalRun) {
|
||||
topOrLeft = std::min(decorationRect.x, topOrLeft);
|
||||
bottomOrRight = std::max(decorationRect.XMost(), bottomOrRight);
|
||||
} else {
|
||||
topOrLeft = std::min(decorationRect.y, topOrLeft);
|
||||
bottomOrRight = std::max(decorationRect.YMost(), bottomOrRight);
|
||||
}
|
||||
}
|
||||
for (uint32_t i = 0; i < textDecs.mStrikes.Length(); ++i) {
|
||||
const LineDecoration& dec = textDecs.mStrikes[i];
|
||||
@ -5047,23 +5066,29 @@ nsTextFrame::UnionAdditionalOverflow(nsPresContext* aPresContext,
|
||||
GetInflationForTextDecorations(dec.mFrame, inflationMinFontSize);
|
||||
const gfxFont::Metrics metrics =
|
||||
GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame, inflation),
|
||||
vertical);
|
||||
useVerticalMetrics);
|
||||
|
||||
const nsRect decorationRect =
|
||||
nsCSSRendering::GetTextDecorationRect(aPresContext,
|
||||
gfxSize(gfxWidth, metrics.strikeoutSize),
|
||||
ascent, metrics.strikeoutOffset,
|
||||
NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH, decorationStyle,
|
||||
vertical) +
|
||||
verticalRun) +
|
||||
nsPoint(0, -dec.mBaselineOffset);
|
||||
top = std::min(decorationRect.y, top);
|
||||
bottom = std::max(decorationRect.YMost(), bottom);
|
||||
|
||||
if (verticalRun) {
|
||||
topOrLeft = std::min(decorationRect.x, topOrLeft);
|
||||
bottomOrRight = std::max(decorationRect.XMost(), bottomOrRight);
|
||||
} else {
|
||||
topOrLeft = std::min(decorationRect.y, topOrLeft);
|
||||
bottomOrRight = std::max(decorationRect.YMost(), bottomOrRight);
|
||||
}
|
||||
}
|
||||
|
||||
aVisualOverflowRect->UnionRect(*aVisualOverflowRect,
|
||||
vertical ?
|
||||
nsRect(top, 0, bottom - top, measure) :
|
||||
nsRect(0, top, measure, bottom - top));
|
||||
aVisualOverflowRect->UnionRect(
|
||||
*aVisualOverflowRect,
|
||||
verticalRun ? nsRect(topOrLeft, 0, bottomOrRight - topOrLeft, measure)
|
||||
: nsRect(0, topOrLeft, measure, bottomOrRight - topOrLeft));
|
||||
}
|
||||
}
|
||||
// When this frame is not selected, the text-decoration area must be in
|
||||
@ -5723,19 +5748,20 @@ nsTextFrame::PaintTextSelectionDecorations(gfxContext* aCtx,
|
||||
}
|
||||
|
||||
gfxFont* firstFont = aProvider.GetFontGroup()->GetFirstValidFont();
|
||||
bool vertical = mTextRun->IsVertical();
|
||||
bool verticalRun = mTextRun->IsVertical();
|
||||
bool useVerticalMetrics = verticalRun && mTextRun->UseCenterBaseline();
|
||||
gfxFont::Metrics
|
||||
decorationMetrics(firstFont->GetMetrics(vertical ?
|
||||
decorationMetrics(firstFont->GetMetrics(useVerticalMetrics ?
|
||||
gfxFont::eVertical : gfxFont::eHorizontal));
|
||||
if (!vertical) {
|
||||
if (!useVerticalMetrics) {
|
||||
// The potential adjustment from using gfxFontGroup::GetUnderlineOffset
|
||||
// is only valid for horizontal text.
|
||||
// is only valid for horizontal font metrics.
|
||||
decorationMetrics.underlineOffset =
|
||||
aProvider.GetFontGroup()->GetUnderlineOffset();
|
||||
}
|
||||
|
||||
gfxFloat startIOffset =
|
||||
vertical ? aTextBaselinePt.y - aFramePt.y : aTextBaselinePt.x - aFramePt.x;
|
||||
verticalRun ? aTextBaselinePt.y - aFramePt.y : aTextBaselinePt.x - aFramePt.x;
|
||||
SelectionIterator iterator(selectedChars, aContentOffset, aContentLength,
|
||||
aProvider, mTextRun, startIOffset);
|
||||
gfxFloat iOffset, hyphenWidth;
|
||||
@ -5743,7 +5769,7 @@ nsTextFrame::PaintTextSelectionDecorations(gfxContext* aCtx,
|
||||
int32_t app = aTextPaintStyle.PresContext()->AppUnitsPerDevPixel();
|
||||
// XXX aTextBaselinePt is in AppUnits, shouldn't it be nsFloatPoint?
|
||||
gfxPoint pt;
|
||||
if (vertical) {
|
||||
if (verticalRun) {
|
||||
pt.x = (aTextBaselinePt.x - mAscent) / app;
|
||||
} else {
|
||||
pt.y = (aTextBaselinePt.y - mAscent) / app;
|
||||
@ -5757,7 +5783,7 @@ nsTextFrame::PaintTextSelectionDecorations(gfxContext* aCtx,
|
||||
gfxFloat advance = hyphenWidth +
|
||||
mTextRun->GetAdvanceWidth(offset, length, &aProvider);
|
||||
if (type == aSelectionType) {
|
||||
if (vertical) {
|
||||
if (verticalRun) {
|
||||
pt.y = (aFramePt.y + iOffset -
|
||||
(mTextRun->IsRightToLeft() ? advance : 0)) / app;
|
||||
} else {
|
||||
@ -5769,7 +5795,7 @@ nsTextFrame::PaintTextSelectionDecorations(gfxContext* aCtx,
|
||||
DrawSelectionDecorations(aCtx, dirtyRect, aSelectionType, this,
|
||||
aTextPaintStyle, selectedStyle, pt, xInFrame,
|
||||
width, mAscent / app, decorationMetrics,
|
||||
aCallbacks, vertical);
|
||||
aCallbacks, verticalRun);
|
||||
}
|
||||
iterator.UpdateWithAdvance(advance);
|
||||
}
|
||||
@ -6013,15 +6039,14 @@ nsTextFrame::PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt,
|
||||
|
||||
gfxContext* ctx = aRenderingContext->ThebesContext();
|
||||
const bool rtl = mTextRun->IsRightToLeft();
|
||||
const bool vertical = mTextRun->IsVertical();
|
||||
const bool verticalRun = mTextRun->IsVertical();
|
||||
WritingMode wm = GetWritingMode();
|
||||
const nscoord frameWidth = GetSize().width;
|
||||
gfxPoint framePt(aPt.x, aPt.y);
|
||||
gfxPoint textBaselinePt;
|
||||
if (vertical) {
|
||||
WritingMode wm = GetWritingMode();
|
||||
textBaselinePt =
|
||||
gfxPoint(wm.IsVerticalLR() ? aPt.x + mAscent
|
||||
: aPt.x + frameWidth - mAscent,
|
||||
if (verticalRun) {
|
||||
textBaselinePt = // XXX sideways-left will need different handling here
|
||||
gfxPoint(aPt.x + (wm.IsVerticalLR() ? mAscent : frameWidth - mAscent),
|
||||
rtl ? aPt.y + GetSize().height : aPt.y);
|
||||
} else {
|
||||
textBaselinePt = gfxPoint(rtl ? gfxFloat(aPt.x + frameWidth) : framePt.x,
|
||||
@ -6034,7 +6059,7 @@ nsTextFrame::PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt,
|
||||
&startOffset, &maxLength, &snappedLeftEdge, &snappedRightEdge)) {
|
||||
return;
|
||||
}
|
||||
if (vertical) {
|
||||
if (verticalRun) {
|
||||
textBaselinePt.y += rtl ? -snappedRightEdge : snappedLeftEdge;
|
||||
} else {
|
||||
textBaselinePt.x += rtl ? -snappedRightEdge : snappedLeftEdge;
|
||||
@ -6159,32 +6184,43 @@ nsTextFrame::DrawTextRunAndDecorations(
|
||||
nsTextFrame::DrawPathCallbacks* aCallbacks)
|
||||
{
|
||||
const gfxFloat app = aTextStyle.PresContext()->AppUnitsPerDevPixel();
|
||||
bool vertical = mTextRun->IsVertical();
|
||||
bool verticalRun = mTextRun->IsVertical();
|
||||
bool useVerticalMetrics = verticalRun && mTextRun->UseCenterBaseline();
|
||||
|
||||
// XXX aFramePt is in AppUnits, shouldn't it be nsFloatPoint?
|
||||
nscoord x = NSToCoordRound(aFramePt.x);
|
||||
nscoord y = NSToCoordRound(aFramePt.y);
|
||||
|
||||
// 'width' here is textrun-relative, so for a vertical run it's
|
||||
// really the height of the decoration
|
||||
nscoord width = vertical ? GetRect().height : GetRect().width;
|
||||
// 'measure' here is textrun-relative, so for a horizontal run it's the
|
||||
// width, while for a vertical run it's the height of the decoration
|
||||
const nsSize frameSize = GetSize();
|
||||
nscoord measure = verticalRun ? frameSize.height : frameSize.width;
|
||||
|
||||
// XXX todo: probably should have a vertical version of this...
|
||||
if (!vertical) {
|
||||
aClipEdges.Intersect(&x, &width);
|
||||
if (!verticalRun) {
|
||||
aClipEdges.Intersect(&x, &measure);
|
||||
}
|
||||
|
||||
// decPt is the physical point where the decoration is to be drawn,
|
||||
// relative to the frame; one of its coordinates will be updated below.
|
||||
gfxPoint decPt(x / app, y / app);
|
||||
gfxFloat& bCoord = vertical ? decPt.x : decPt.y;
|
||||
gfxFloat& bCoord = verticalRun ? decPt.x : decPt.y;
|
||||
|
||||
// ...whereas decSize is a textrun-relative size
|
||||
gfxSize decSize(width / app, 0);
|
||||
const gfxFloat ascent = gfxFloat(mAscent) / app;
|
||||
// decSize is a textrun-relative size, so its 'width' field is actually
|
||||
// the run-relative measure, and 'height' will be the line thickness
|
||||
gfxSize decSize(measure / app, 0);
|
||||
gfxFloat ascent = gfxFloat(mAscent) / app;
|
||||
|
||||
// The starting edge of the frame in block direction
|
||||
const gfxFloat frameBStart = vertical ? aFramePt.x : aFramePt.y;
|
||||
gfxFloat frameBStart = verticalRun ? aFramePt.x : aFramePt.y;
|
||||
|
||||
// In vertical-rl mode, block coordinates are measured from the right,
|
||||
// so we need to adjust here.
|
||||
const WritingMode wm = GetWritingMode();
|
||||
if (wm.IsVerticalRL()) {
|
||||
frameBStart += frameSize.width;
|
||||
ascent = -ascent;
|
||||
}
|
||||
|
||||
gfxRect dirtyRect(aDirtyRect.x / app, aDirtyRect.y / app,
|
||||
aDirtyRect.Width() / app, aDirtyRect.Height() / app);
|
||||
@ -6203,7 +6239,7 @@ nsTextFrame::DrawTextRunAndDecorations(
|
||||
GetInflationForTextDecorations(dec.mFrame, inflationMinFontSize);
|
||||
const gfxFont::Metrics metrics =
|
||||
GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame, inflation),
|
||||
vertical);
|
||||
useVerticalMetrics);
|
||||
|
||||
decSize.height = metrics.underlineSize;
|
||||
bCoord = (frameBStart - dec.mBaselineOffset) / app;
|
||||
@ -6211,7 +6247,7 @@ nsTextFrame::DrawTextRunAndDecorations(
|
||||
PaintDecorationLine(this, aCtx, dirtyRect, dec.mColor,
|
||||
aDecorationOverrideColor, decPt, 0.0, decSize, ascent,
|
||||
metrics.underlineOffset, NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE,
|
||||
dec.mStyle, eNormalDecoration, aCallbacks, vertical);
|
||||
dec.mStyle, eNormalDecoration, aCallbacks, verticalRun);
|
||||
}
|
||||
// Overlines
|
||||
for (uint32_t i = aDecorations.mOverlines.Length(); i-- > 0; ) {
|
||||
@ -6224,7 +6260,7 @@ nsTextFrame::DrawTextRunAndDecorations(
|
||||
GetInflationForTextDecorations(dec.mFrame, inflationMinFontSize);
|
||||
const gfxFont::Metrics metrics =
|
||||
GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame, inflation),
|
||||
vertical);
|
||||
useVerticalMetrics);
|
||||
|
||||
decSize.height = metrics.underlineSize;
|
||||
bCoord = (frameBStart - dec.mBaselineOffset) / app;
|
||||
@ -6232,7 +6268,7 @@ nsTextFrame::DrawTextRunAndDecorations(
|
||||
PaintDecorationLine(this, aCtx, dirtyRect, dec.mColor,
|
||||
aDecorationOverrideColor, decPt, 0.0, decSize, ascent,
|
||||
metrics.maxAscent, NS_STYLE_TEXT_DECORATION_LINE_OVERLINE, dec.mStyle,
|
||||
eNormalDecoration, aCallbacks, vertical);
|
||||
eNormalDecoration, aCallbacks, verticalRun);
|
||||
}
|
||||
|
||||
// CSS 2.1 mandates that text be painted after over/underlines, and *then*
|
||||
@ -6251,7 +6287,7 @@ nsTextFrame::DrawTextRunAndDecorations(
|
||||
GetInflationForTextDecorations(dec.mFrame, inflationMinFontSize);
|
||||
const gfxFont::Metrics metrics =
|
||||
GetFirstFontMetrics(GetFontGroupForFrame(dec.mFrame, inflation),
|
||||
vertical);
|
||||
useVerticalMetrics);
|
||||
|
||||
decSize.height = metrics.strikeoutSize;
|
||||
bCoord = (frameBStart - dec.mBaselineOffset) / app;
|
||||
@ -6259,7 +6295,7 @@ nsTextFrame::DrawTextRunAndDecorations(
|
||||
PaintDecorationLine(this, aCtx, dirtyRect, dec.mColor,
|
||||
aDecorationOverrideColor, decPt, 0.0, decSize, ascent,
|
||||
metrics.strikeoutOffset, NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH,
|
||||
dec.mStyle, eNormalDecoration, aCallbacks, vertical);
|
||||
dec.mStyle, eNormalDecoration, aCallbacks, verticalRun);
|
||||
}
|
||||
}
|
||||
|
||||
@ -6458,9 +6494,12 @@ nsTextFrame::CombineSelectionUnderlineRect(nsPresContext* aPresContext,
|
||||
GetFontSizeInflation());
|
||||
gfxFontGroup* fontGroup = fm->GetThebesFontGroup();
|
||||
gfxFont* firstFont = fontGroup->GetFirstValidFont();
|
||||
bool vertical = GetWritingMode().IsVertical();
|
||||
WritingMode wm = GetWritingMode();
|
||||
bool verticalRun = wm.IsVertical();
|
||||
bool useVerticalMetrics = verticalRun && !wm.IsSideways();
|
||||
const gfxFont::Metrics& metrics =
|
||||
firstFont->GetMetrics(vertical ? gfxFont::eVertical : gfxFont::eHorizontal);
|
||||
firstFont->GetMetrics(useVerticalMetrics ? gfxFont::eVertical
|
||||
: gfxFont::eHorizontal);
|
||||
gfxFloat underlineOffset = fontGroup->GetUnderlineOffset();
|
||||
gfxFloat ascent = aPresContext->AppUnitsToGfxUnits(mAscent);
|
||||
gfxFloat descentLimit =
|
||||
@ -6505,7 +6544,7 @@ nsTextFrame::CombineSelectionUnderlineRect(nsPresContext* aPresContext,
|
||||
decorationArea =
|
||||
nsCSSRendering::GetTextDecorationRect(aPresContext, size,
|
||||
ascent, underlineOffset, NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE,
|
||||
style, vertical, descentLimit);
|
||||
style, verticalRun, descentLimit);
|
||||
aRect.UnionRect(aRect, decorationArea);
|
||||
}
|
||||
DestroySelectionDetails(details);
|
||||
@ -7617,7 +7656,11 @@ nsTextFrame::ComputeTightBounds(gfxContext* aContext) const
|
||||
aContext, &provider);
|
||||
// mAscent should be the same as metrics.mAscent, but it's what we use to
|
||||
// paint so that's the one we'll use.
|
||||
nsRect boundingBox = RoundOut(metrics.mBoundingBox) + nsPoint(0, mAscent);
|
||||
nsRect boundingBox = RoundOut(metrics.mBoundingBox);
|
||||
if (GetWritingMode().IsLineInverted()) {
|
||||
boundingBox.y = -boundingBox.YMost();
|
||||
}
|
||||
boundingBox += nsPoint(0, mAscent);
|
||||
if (mTextRun->IsVertical()) {
|
||||
// Swap line-relative textMetrics dimensions to physical coordinates.
|
||||
Swap(boundingBox.x, boundingBox.y);
|
||||
@ -8302,9 +8345,15 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
|
||||
finalSize.BSize(wm) = 0;
|
||||
} else if (boundingBoxType != gfxFont::LOOSE_INK_EXTENTS) {
|
||||
// Use actual text metrics for floating first letter frame.
|
||||
aMetrics.SetBlockStartAscent(NSToCoordCeil(textMetrics.mAscent));
|
||||
finalSize.BSize(wm) = aMetrics.BlockStartAscent() +
|
||||
NSToCoordCeil(textMetrics.mDescent);
|
||||
if (wm.IsLineInverted()) {
|
||||
aMetrics.SetBlockStartAscent(NSToCoordCeil(textMetrics.mDescent));
|
||||
finalSize.BSize(wm) = aMetrics.BlockStartAscent() +
|
||||
NSToCoordCeil(textMetrics.mAscent);
|
||||
} else {
|
||||
aMetrics.SetBlockStartAscent(NSToCoordCeil(textMetrics.mAscent));
|
||||
finalSize.BSize(wm) = aMetrics.BlockStartAscent() +
|
||||
NSToCoordCeil(textMetrics.mDescent);
|
||||
}
|
||||
} else {
|
||||
// Otherwise, ascent should contain the overline drawable area.
|
||||
// And also descent should contain the underline drawable area.
|
||||
@ -8312,9 +8361,15 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
|
||||
nsFontMetrics* fm = provider.GetFontMetrics();
|
||||
nscoord fontAscent = fm->MaxAscent();
|
||||
nscoord fontDescent = fm->MaxDescent();
|
||||
aMetrics.SetBlockStartAscent(std::max(NSToCoordCeil(textMetrics.mAscent), fontAscent));
|
||||
nscoord descent = std::max(NSToCoordCeil(textMetrics.mDescent), fontDescent);
|
||||
finalSize.BSize(wm) = aMetrics.BlockStartAscent() + descent;
|
||||
if (wm.IsLineInverted()) {
|
||||
aMetrics.SetBlockStartAscent(std::max(NSToCoordCeil(textMetrics.mDescent), fontDescent));
|
||||
nscoord descent = std::max(NSToCoordCeil(textMetrics.mAscent), fontAscent);
|
||||
finalSize.BSize(wm) = aMetrics.BlockStartAscent() + descent;
|
||||
} else {
|
||||
aMetrics.SetBlockStartAscent(std::max(NSToCoordCeil(textMetrics.mAscent), fontAscent));
|
||||
nscoord descent = std::max(NSToCoordCeil(textMetrics.mDescent), fontDescent);
|
||||
finalSize.BSize(wm) = aMetrics.BlockStartAscent() + descent;
|
||||
}
|
||||
}
|
||||
aMetrics.SetSize(wm, finalSize);
|
||||
|
||||
@ -8327,13 +8382,17 @@ nsTextFrame::ReflowText(nsLineLayout& aLineLayout, nscoord aAvailableWidth,
|
||||
mAscent = aMetrics.BlockStartAscent();
|
||||
|
||||
// Handle text that runs outside its normal bounds.
|
||||
nsRect boundingBox = RoundOut(textMetrics.mBoundingBox) + nsPoint(0, mAscent);
|
||||
aMetrics.SetOverflowAreasToDesiredBounds();
|
||||
nsRect boundingBox = RoundOut(textMetrics.mBoundingBox);
|
||||
if (wm.IsLineInverted()) {
|
||||
boundingBox.y = -boundingBox.YMost();
|
||||
}
|
||||
boundingBox += nsPoint(0, mAscent);
|
||||
if (mTextRun->IsVertical()) {
|
||||
// Swap line-relative textMetrics dimensions to physical coordinates.
|
||||
Swap(boundingBox.x, boundingBox.y);
|
||||
Swap(boundingBox.width, boundingBox.height);
|
||||
}
|
||||
aMetrics.SetOverflowAreasToDesiredBounds();
|
||||
aMetrics.VisualOverflow().UnionRect(aMetrics.VisualOverflow(), boundingBox);
|
||||
|
||||
// When we have text decorations, we don't need to compute their overflow now
|
||||
@ -8549,18 +8608,23 @@ nsTextFrame::RecomputeOverflow(const nsHTMLReflowState& aBlockReflowState)
|
||||
ComputeTransformedLength(provider),
|
||||
gfxFont::LOOSE_INK_EXTENTS, nullptr,
|
||||
&provider);
|
||||
nsRect &vis = result.VisualOverflow();
|
||||
nsRect boundingBox = RoundOut(textMetrics.mBoundingBox) + nsPoint(0, mAscent);
|
||||
nsRect boundingBox = RoundOut(textMetrics.mBoundingBox);
|
||||
if (GetWritingMode().IsLineInverted()) {
|
||||
boundingBox.y = -boundingBox.YMost();
|
||||
}
|
||||
boundingBox += nsPoint(0, mAscent);
|
||||
if (mTextRun->IsVertical()) {
|
||||
// Swap line-relative textMetrics dimensions to physical coordinates.
|
||||
Swap(boundingBox.x, boundingBox.y);
|
||||
Swap(boundingBox.width, boundingBox.height);
|
||||
}
|
||||
nsRect &vis = result.VisualOverflow();
|
||||
vis.UnionRect(vis, boundingBox);
|
||||
UnionAdditionalOverflow(PresContext(), aBlockReflowState.frame, provider,
|
||||
&vis, true);
|
||||
return result;
|
||||
}
|
||||
|
||||
static char16_t TransformChar(const nsStyleText* aStyle, gfxTextRun* aTextRun,
|
||||
uint32_t aSkippedOffset, char16_t aChar)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user