From 4dae04e594f6662dcfb03fd304494841ca542091 Mon Sep 17 00:00:00 2001 From: athenian200 Date: Fri, 23 Oct 2020 14:34:55 -0500 Subject: Issue #1673 - Part 1: Allow tab-size to accept . Currently -moz-tab-size only accepts values, and both Chrome and Firefox currently support values and have for some time now. So with this you would be able to support sizes in px or em, for instance. This was implemented in Firefox 53 and was trivial to backport. --- layout/generic/nsTextFrame.cpp | 74 +++++++++++++++++++++++++----------------- 1 file changed, 45 insertions(+), 29 deletions(-) (limited to 'layout/generic') diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index c7b55961c..749b8b944 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -3178,7 +3178,7 @@ public: return mFontMetrics; } - void CalcTabWidths(Range aTransformedRange); + void CalcTabWidths(Range aTransformedRange, gfxFloat aTabWidth); const gfxSkipCharsIterator& GetEndHint() { return mTempIterator; } @@ -3364,6 +3364,28 @@ CanAddSpacingAfter(const gfxTextRun* aTextRun, uint32_t aOffset) aTextRun->IsLigatureGroupStart(aOffset + 1); } +static gfxFloat +ComputeTabWidthAppUnits(nsIFrame* aFrame, gfxTextRun* aTextRun) +{ + const nsStyleText* textStyle = aFrame->StyleText(); + if (textStyle->mTabSize.GetUnit() != eStyleUnit_Factor) { + nscoord w = textStyle->mTabSize.GetCoordValue(); + MOZ_ASSERT(w >= 0); + return w; + } + + gfxFloat spaces = textStyle->mTabSize.GetFactorValue(); + MOZ_ASSERT(spaces >= 0); + + // Round the space width when converting to appunits the same way + // textruns do. + gfxFloat spaceWidthAppUnits = + NS_round(GetFirstFontMetrics(aTextRun->GetFontGroup(), + aTextRun->IsVertical()).spaceWidth * + aTextRun->GetAppUnitsPerDevUnit()); + return spaces * spaceWidthAppUnits; +} + void PropertyProvider::GetSpacingInternal(Range aRange, Spacing* aSpacing, bool aIgnoreTabs) @@ -3411,17 +3433,16 @@ PropertyProvider::GetSpacingInternal(Range aRange, Spacing* aSpacing, } } - // Ignore tab spacing rather than computing it, if the tab size is 0 - if (!aIgnoreTabs) - aIgnoreTabs = mFrame->StyleText()->mTabSize == 0; - // Now add tab spacing, if there is any if (!aIgnoreTabs) { - CalcTabWidths(aRange); - if (mTabWidths) { - mTabWidths->ApplySpacing(aSpacing, - aRange.start - mStart.GetSkippedOffset(), - aRange.Length()); + gfxFloat tabWidth = ComputeTabWidthAppUnits(mFrame, mTextRun); + if (tabWidth > 0) { + CalcTabWidths(aRange); + if (mTabWidths) { + mTabWidths->ApplySpacing(aSpacing, + aRange.start - mStart.GetSkippedOffset(), + aRange.Length()); + } } } @@ -3444,33 +3465,23 @@ PropertyProvider::GetSpacingInternal(Range aRange, Spacing* aSpacing, } } -static gfxFloat -ComputeTabWidthAppUnits(nsIFrame* aFrame, const gfxTextRun* aTextRun) -{ - // Get the number of spaces from CSS -moz-tab-size - const nsStyleText* textStyle = aFrame->StyleText(); - - return textStyle->mTabSize * GetSpaceWidthAppUnits(aTextRun); -} - // aX and the result are in whole appunits. static gfxFloat AdvanceToNextTab(gfxFloat aX, nsIFrame* aFrame, - const gfxTextRun* aTextRun, gfxFloat* aCachedTabWidth) + gfxTextRun* aTextRun, gfxFloat* aTabWidth) { - if (*aCachedTabWidth < 0) { - *aCachedTabWidth = ComputeTabWidthAppUnits(aFrame, aTextRun); - } // Advance aX to the next multiple of *aCachedTabWidth. We must advance // by at least 1 appunit. // XXX should we make this 1 CSS pixel? - return ceil((aX + 1)/(*aCachedTabWidth))*(*aCachedTabWidth); + return ceil((aX + 1)/ aTabWidth) * aTabWidth; } void -PropertyProvider::CalcTabWidths(Range aRange) +PropertyProvider::CalcTabWidths(Range aRange, gfxFloat aTabWidth) { + MOZ_ASSERT(aTabWidth > 0); + if (!mTabWidths) { if (mReflowing && !mLineContainer) { // Intrinsic width computation does its own tab processing. We @@ -3505,7 +3516,6 @@ PropertyProvider::CalcTabWidths(Range aRange) NS_ASSERTION(mReflowing, "We need precomputed tab widths, but don't have enough."); - gfxFloat tabWidth = -1; for (uint32_t i = tabsEnd; i < aRange.end; ++i) { Spacing spacing; GetSpacingInternal(Range(i, i + 1), &spacing, true); @@ -3527,7 +3537,7 @@ PropertyProvider::CalcTabWidths(Range aRange) mFrame->SetProperty(TabWidthProperty(), mTabWidths); } double nextTab = AdvanceToNextTab(mOffsetFromBlockOriginForTabs, - mFrame, mTextRun, &tabWidth); + mFrame, mTextRun, aTabWidth); mTabWidths->mWidths.AppendElement(TabWidth(i - startOffset, NSToIntRound(nextTab - mOffsetFromBlockOriginForTabs))); mOffsetFromBlockOriginForTabs = nextTab; @@ -8321,9 +8331,12 @@ nsTextFrame::AddInlineMinISizeForFlow(nsRenderingContext *aRenderingContext, PropertyProvider::Spacing spacing; provider.GetSpacing(Range(i, i + 1), &spacing); aData->mCurrentLine += nscoord(spacing.mBefore); + if (tabWidth < 0) { + tabWidth = ComputeTabWidthAppUnits(this, textRun); + } gfxFloat afterTab = AdvanceToNextTab(aData->mCurrentLine, this, - textRun, &tabWidth); + textRun, tabWidth); aData->mCurrentLine = nscoord(afterTab + spacing.mAfter); wordStart = i + 1; } else if (i < flowEndInTextRun || @@ -8480,9 +8493,12 @@ nsTextFrame::AddInlinePrefISizeForFlow(nsRenderingContext *aRenderingContext, PropertyProvider::Spacing spacing; provider.GetSpacing(Range(i, i + 1), &spacing); aData->mCurrentLine += nscoord(spacing.mBefore); + if (tabWidth < 0) { + tabWidth = ComputeTabWidthAppUnits(this, textRun); + } gfxFloat afterTab = AdvanceToNextTab(aData->mCurrentLine, this, - textRun, &tabWidth); + textRun, tabWidth); aData->mCurrentLine = nscoord(afterTab + spacing.mAfter); lineStart = i + 1; } else if (preformattedNewline) { -- cgit v1.2.3 From 4de0e9c68d3f1a04d5d6c236d5f06fff7244c074 Mon Sep 17 00:00:00 2001 From: athenian200 Date: Fri, 23 Oct 2020 19:45:52 -0500 Subject: Issue #1673 - Part 2: Make tab-size animatable and fix typos. There were a few typos in the previous patch and this patch also makes tab-size animatable which didn't really require much of a change at all. --- layout/generic/nsTextFrame.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'layout/generic') diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index 749b8b944..83e50ca43 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -3437,7 +3437,7 @@ PropertyProvider::GetSpacingInternal(Range aRange, Spacing* aSpacing, if (!aIgnoreTabs) { gfxFloat tabWidth = ComputeTabWidthAppUnits(mFrame, mTextRun); if (tabWidth > 0) { - CalcTabWidths(aRange); + CalcTabWidths(aRange, tabWidth); if (mTabWidths) { mTabWidths->ApplySpacing(aSpacing, aRange.start - mStart.GetSkippedOffset(), @@ -3468,13 +3468,13 @@ PropertyProvider::GetSpacingInternal(Range aRange, Spacing* aSpacing, // aX and the result are in whole appunits. static gfxFloat AdvanceToNextTab(gfxFloat aX, nsIFrame* aFrame, - gfxTextRun* aTextRun, gfxFloat* aTabWidth) + gfxTextRun* aTextRun, gfxFloat aTabWidth) { // Advance aX to the next multiple of *aCachedTabWidth. We must advance // by at least 1 appunit. // XXX should we make this 1 CSS pixel? - return ceil((aX + 1)/ aTabWidth) * aTabWidth; + return NS_round((aX + 1) / aTabWidth) * aTabWidth; } void -- cgit v1.2.3 From 90309c01a811c7e05baf6d95a2fde2bdd4cdeaf5 Mon Sep 17 00:00:00 2001 From: athenian200 Date: Sun, 25 Oct 2020 14:27:17 -0500 Subject: Issue #1673 - Part 3: Bring minimum tab advance up to spec. This provides a clearer rule for the minimum tab advance that brings us to alignment with the spec and both major browsers. --- layout/generic/nsTextFrame.cpp | 41 ++++++++++++++++++++++++++++++----------- 1 file changed, 30 insertions(+), 11 deletions(-) (limited to 'layout/generic') diff --git a/layout/generic/nsTextFrame.cpp b/layout/generic/nsTextFrame.cpp index 83e50ca43..a93c71b28 100644 --- a/layout/generic/nsTextFrame.cpp +++ b/layout/generic/nsTextFrame.cpp @@ -1718,6 +1718,16 @@ GetSpaceWidthAppUnits(const gfxTextRun* aTextRun) return spaceWidthAppUnits; } +static gfxFloat +GetMinTabAdvanceAppUnits(const gfxTextRun* aTextRun) +{ + gfxFloat chWidthAppUnits = + NS_round(GetFirstFontMetrics(aTextRun->GetFontGroup(), + aTextRun->IsVertical()).zeroOrAveCharWidth * + aTextRun->GetAppUnitsPerDevUnit()); + return 0.5 * chWidthAppUnits; +} + static nscoord LetterSpacing(nsIFrame* aFrame, const nsStyleText* aStyleText = nullptr) { @@ -3092,6 +3102,7 @@ public: mLength(aLength), mWordSpacing(WordSpacing(aFrame, mTextRun, aTextStyle)), mLetterSpacing(LetterSpacing(aFrame, aTextStyle)), + mMinTabAdvance(-1.0), mHyphenWidth(-1), mOffsetFromBlockOriginForTabs(aOffsetFromBlockOriginForTabs), mReflowing(true), @@ -3116,6 +3127,7 @@ public: mLength(aFrame->GetContentLength()), mWordSpacing(WordSpacing(aFrame, mTextRun)), mLetterSpacing(LetterSpacing(aFrame)), + mMinTabAdvance(-1.0), mHyphenWidth(-1), mOffsetFromBlockOriginForTabs(0), mReflowing(false), @@ -3180,6 +3192,13 @@ public: void CalcTabWidths(Range aTransformedRange, gfxFloat aTabWidth); + gfxFloat MinTabAdvance() { + if (mMinTabAdvance < 0.0) { + mMinTabAdvance = GetMinTabAdvanceAppUnits(mTextRun); + } + return mMinTabAdvance; + } + const gfxSkipCharsIterator& GetEndHint() { return mTempIterator; } protected: @@ -3212,6 +3231,7 @@ protected: int32_t mLength; // DOM string length, may be INT32_MAX gfxFloat mWordSpacing; // space for each whitespace char gfxFloat mLetterSpacing; // space for each letter + gfxFloat mMinTabAdvance; // min advance for char gfxFloat mHyphenWidth; gfxFloat mOffsetFromBlockOriginForTabs; @@ -3467,14 +3487,13 @@ PropertyProvider::GetSpacingInternal(Range aRange, Spacing* aSpacing, // aX and the result are in whole appunits. static gfxFloat -AdvanceToNextTab(gfxFloat aX, nsIFrame* aFrame, - gfxTextRun* aTextRun, gfxFloat aTabWidth) +AdvanceToNextTab(gfxFloat aX, nsIFrame* aFrame, gfxTextRun* aTextRun, + gfxFloat aTabWidth, gfxFloat aMinAdvance) { - // Advance aX to the next multiple of *aCachedTabWidth. We must advance - // by at least 1 appunit. - // XXX should we make this 1 CSS pixel? - return NS_round((aX + 1) / aTabWidth) * aTabWidth; + // Advance aX to the next multiple of aTabWidth. We must advance + // by at least aMinAdvance. + return ceil((aX + aMinAdvance) / aTabWidth) * aTabWidth; } void @@ -3537,7 +3556,7 @@ PropertyProvider::CalcTabWidths(Range aRange, gfxFloat aTabWidth) mFrame->SetProperty(TabWidthProperty(), mTabWidths); } double nextTab = AdvanceToNextTab(mOffsetFromBlockOriginForTabs, - mFrame, mTextRun, aTabWidth); + mFrame, mTextRun, aTabWidth, MinTabAdvance()); mTabWidths->mWidths.AppendElement(TabWidth(i - startOffset, NSToIntRound(nextTab - mOffsetFromBlockOriginForTabs))); mOffsetFromBlockOriginForTabs = nextTab; @@ -8335,8 +8354,8 @@ nsTextFrame::AddInlineMinISizeForFlow(nsRenderingContext *aRenderingContext, tabWidth = ComputeTabWidthAppUnits(this, textRun); } gfxFloat afterTab = - AdvanceToNextTab(aData->mCurrentLine, this, - textRun, tabWidth); + AdvanceToNextTab(aData->mCurrentLine, this, textRun, tabWidth, + provider.MinTabAdvance()); aData->mCurrentLine = nscoord(afterTab + spacing.mAfter); wordStart = i + 1; } else if (i < flowEndInTextRun || @@ -8497,8 +8516,8 @@ nsTextFrame::AddInlinePrefISizeForFlow(nsRenderingContext *aRenderingContext, tabWidth = ComputeTabWidthAppUnits(this, textRun); } gfxFloat afterTab = - AdvanceToNextTab(aData->mCurrentLine, this, - textRun, tabWidth); + AdvanceToNextTab(aData->mCurrentLine, this, textRun, tabWidth, + provider.MinTabAdvance()); aData->mCurrentLine = nscoord(afterTab + spacing.mAfter); lineStart = i + 1; } else if (preformattedNewline) { -- cgit v1.2.3