Bug 1308113 - Account for letter- and word-spacing when resolving tab-size <number>. r=emilio

Differential Revision: https://phabricator.services.mozilla.com/D117331
This commit is contained in:
Jonathan Kew
2021-06-10 09:19:23 +00:00
parent 92b71b2c6b
commit fd9023b910
5 changed files with 40 additions and 29 deletions

View File

@@ -3419,15 +3419,17 @@ void nsTextFrame::PropertyProvider::GetSpacing(Range aRange,
static bool CanAddSpacingAfter(const gfxTextRun* aTextRun, uint32_t aOffset, static bool CanAddSpacingAfter(const gfxTextRun* aTextRun, uint32_t aOffset,
bool aNewlineIsSignificant) { bool aNewlineIsSignificant) {
if (aOffset + 1 >= aTextRun->GetLength()) return true; if (aOffset + 1 >= aTextRun->GetLength()) {
return aTextRun->IsClusterStart(aOffset + 1) && return true;
aTextRun->IsLigatureGroupStart(aOffset + 1) && }
!aTextRun->CharIsFormattingControl(aOffset) && const auto* g = aTextRun->GetCharacterGlyphs();
!(aNewlineIsSignificant && aTextRun->CharIsNewline(aOffset)); return g[aOffset + 1].IsClusterStart() &&
g[aOffset + 1].IsLigatureGroupStart() &&
!g[aOffset].CharIsFormattingControl() && !g[aOffset].CharIsTab() &&
!(aNewlineIsSignificant && g[aOffset].CharIsNewline());
} }
static gfxFloat ComputeTabWidthAppUnits(const nsIFrame* aFrame, static gfxFloat ComputeTabWidthAppUnits(const nsIFrame* aFrame) {
gfxTextRun* aTextRun) {
const auto& tabSize = aFrame->StyleText()->mMozTabSize; const auto& tabSize = aFrame->StyleText()->mMozTabSize;
if (tabSize.IsLength()) { if (tabSize.IsLength()) {
nscoord w = tabSize.length._0.ToAppUnits(); nscoord w = tabSize.length._0.ToAppUnits();
@@ -3439,13 +3441,17 @@ static gfxFloat ComputeTabWidthAppUnits(const nsIFrame* aFrame,
gfxFloat spaces = tabSize.number._0; gfxFloat spaces = tabSize.number._0;
MOZ_ASSERT(spaces >= 0); MOZ_ASSERT(spaces >= 0);
// Round the space width when converting to appunits the same way const nsIFrame* cb = aFrame->GetContainingBlock(0, aFrame->StyleDisplay());
// textruns do. const auto* styleText = cb->StyleText();
gfxFloat spaceWidthAppUnits = NS_round(
GetFirstFontMetrics(aTextRun->GetFontGroup(), aTextRun->IsVertical()) // Round the space width when converting to appunits the same way textruns do.
.spaceWidth * RefPtr<nsFontMetrics> fm = nsLayoutUtils::GetFontMetricsForFrame(cb, 1.0f);
aTextRun->GetAppUnitsPerDevUnit()); bool vertical = cb->GetWritingMode().IsCentralBaseline();
return spaces * spaceWidthAppUnits; nscoord spaceWidth = nscoord(NS_round(
GetFirstFontMetrics(fm->GetThebesFontGroup(), vertical).spaceWidth *
cb->PresContext()->AppUnitsPerDevPixel()));
return spaces * (spaceWidth + styleText->mLetterSpacing.ToAppUnits() +
styleText->mWordSpacing.Resolve(spaceWidth));
} }
void nsTextFrame::PropertyProvider::GetSpacingInternal(Range aRange, void nsTextFrame::PropertyProvider::GetSpacingInternal(Range aRange,
@@ -3498,7 +3504,7 @@ void nsTextFrame::PropertyProvider::GetSpacingInternal(Range aRange,
// Now add tab spacing, if there is any // Now add tab spacing, if there is any
if (!aIgnoreTabs) { if (!aIgnoreTabs) {
gfxFloat tabWidth = ComputeTabWidthAppUnits(mFrame, mTextRun); gfxFloat tabWidth = ComputeTabWidthAppUnits(mFrame);
if (tabWidth > 0) { if (tabWidth > 0) {
CalcTabWidths(aRange, tabWidth); CalcTabWidths(aRange, tabWidth);
if (mTabWidths) { if (mTabWidths) {
@@ -8476,7 +8482,7 @@ void nsTextFrame::AddInlineMinISizeForFlow(gfxContext* aRenderingContext,
provider.GetSpacing(Range(i, i + 1), &spacing); provider.GetSpacing(Range(i, i + 1), &spacing);
aData->mCurrentLine += nscoord(spacing.mBefore); aData->mCurrentLine += nscoord(spacing.mBefore);
if (tabWidth < 0) { if (tabWidth < 0) {
tabWidth = ComputeTabWidthAppUnits(this, textRun); tabWidth = ComputeTabWidthAppUnits(this);
} }
gfxFloat afterTab = AdvanceToNextTab(aData->mCurrentLine, tabWidth, gfxFloat afterTab = AdvanceToNextTab(aData->mCurrentLine, tabWidth,
provider.MinTabAdvance()); provider.MinTabAdvance());
@@ -8646,7 +8652,7 @@ void nsTextFrame::AddInlinePrefISizeForFlow(
provider.GetSpacing(Range(i, i + 1), &spacing); provider.GetSpacing(Range(i, i + 1), &spacing);
aData->mCurrentLine += nscoord(spacing.mBefore); aData->mCurrentLine += nscoord(spacing.mBefore);
if (tabWidth < 0) { if (tabWidth < 0) {
tabWidth = ComputeTabWidthAppUnits(this, textRun); tabWidth = ComputeTabWidthAppUnits(this);
} }
gfxFloat afterTab = AdvanceToNextTab(aData->mCurrentLine, tabWidth, gfxFloat afterTab = AdvanceToNextTab(aData->mCurrentLine, tabWidth,
provider.MinTabAdvance()); provider.MinTabAdvance());

View File

@@ -3,7 +3,8 @@
<head> <head>
<style> <style>
p { float:left; white-space:pre; border:1px solid black; clear:both; } p { float:left; white-space:pre; border:1px solid black; clear:both; }
.space { padding:0 2px; } .letterspace { letter-spacing:4px; }
.space { padding:0 4px 0 0; }
table { clear:both; } table { clear:both; }
</style> </style>
</head> </head>
@@ -20,12 +21,12 @@ table { clear:both; }
</div> </div>
<p> <p>
<span class="space">a</span> <span class="letterspace"> </span><span class="space">a</span>
</p> </p>
<div style="width:0"> <div style="width:0">
<p class="letterspace"> <p>
<span class="space">a</span> <span class="letterspace"> </span><span class="space">a</span>
</p> </p>
</div> </div>

View File

@@ -3,7 +3,7 @@
<head> <head>
<style> <style>
p { float:left; white-space:pre; border:1px solid black; clear:both; } p { float:left; white-space:pre; border:1px solid black; clear:both; }
.letterspace { letter-spacing:2px; } .letterspace { letter-spacing:4px; }
table { clear:both; } table { clear:both; }
</style> </style>
</head> </head>
@@ -19,8 +19,9 @@ table { clear:both; }
</p> </p>
</div> </div>
<!-- there should be 1px of letter-spacing after the tab, 1px before the 'a' and 2px after <!-- there should be no letter-spacing after the tab, because letter-spacing is
the a --> already incorporated into the calculation of the tab position, but there
will be 4px after the a -->
<p class="letterspace"> <p class="letterspace">
a a
</p> </p>

View File

@@ -2,10 +2,13 @@
<html> <html>
<head> <head>
<style> <style>
span { display:inline-block; width:10em; } span { display:inline-block; width:10ch; }
/* first tab-position will be at 2 * (space-width + word-spacing), i.e. 22ch,
so to advance there after the 3-ch word "tab" we need 19ch of added space */
span.tab { width: 19ch; }
</style> </style>
</head> </head>
<body style="width: 433px; height: 590px;"> <body style="font-family: monospace; width: 433px; height: 590px;">
<table border="1"> <table border="1">
<tr><td>space <span></span>.</td> <tr><td>space <span></span>.</td>
@@ -23,7 +26,7 @@ span { display:inline-block; width:10em; }
<tr><td>ideographic-space&#x3000;.</td> <tr><td>ideographic-space&#x3000;.</td>
<tr><td>newline <tr><td>newline
.</td> .</td>
<tr><td>tab&#9;.</td> <tr><td>tab<span class=tab></span>.</td>
<tr><td>form-feed&#12;.</td> <tr><td>form-feed&#12;.</td>
</table> </table>
@@ -42,7 +45,7 @@ span { display:inline-block; width:10em; }
<tr><td>ideographic-space&#x3000;.</td> <tr><td>ideographic-space&#x3000;.</td>
<tr><td>newline <tr><td>newline
.</td> .</td>
<tr><td>tab&#9;.</td> <tr><td>tab<span class=tab></span>.</td>
<tr><td>form-feed&#12;.</td> <tr><td>form-feed&#12;.</td>
</table> </table>

View File

@@ -1,6 +1,6 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html> <html>
<body style="word-spacing:10em; width: 433px; height: 590px;"> <body style="font-family: monospace; word-spacing:10ch; -moz-tab-size: 2; width: 433px; height: 590px;">
<table border="1"> <table border="1">
<tr><td>space .</td> <tr><td>space .</td>