From 0b1d94265f62a3372b8ac5b9fd8baf4f1d1144ba Mon Sep 17 00:00:00 2001 From: "roc+@cs.cmu.edu" Date: Tue, 22 May 2007 16:40:07 -0700 Subject: [PATCH] Bug 381127. Add whitespace trimming capability to BreakAndMeasureText. r=pavlov --- gfx/thebes/public/gfxFont.h | 7 +++++++ gfx/thebes/src/gfxFont.cpp | 36 +++++++++++++++++++++++++++--------- 2 files changed, 34 insertions(+), 9 deletions(-) diff --git a/gfx/thebes/public/gfxFont.h b/gfx/thebes/public/gfxFont.h index 7d12ab6b003..bb1b5a30c89 100644 --- a/gfx/thebes/public/gfxFont.h +++ b/gfx/thebes/public/gfxFont.h @@ -729,6 +729,12 @@ public: * linebreak before aStart. If false, then we will check the internal * line break opportunity state before deciding whether to return 0 as the * character to break before. + * @param aTrimWhitespace if non-null, then we allow a trailing run of + * spaces to be trimmed; the width of the space(s) will not be included in + * the measured string width for comparison with the limit aWidth, and + * trimmed spaces will not be included in returned metrics. The width + * of the trimmed spaces will be returned in aTrimWhitespace. + * Trimmed spaces are still counted in the "characters fit" result. * @param aMetrics if non-null, we fill this in for the returned substring. * If a hyphenation break was used, the hyphen is NOT included in the returned metrics. * @param aTightBoundingBox if true, we make the bounding box in aMetrics tight @@ -748,6 +754,7 @@ public: PRBool aLineBreakBefore, gfxFloat aWidth, PropertyProvider *aProvider, PRBool aSuppressInitialBreak, + gfxFloat *aTrimWhitespace, Metrics *aMetrics, PRBool aTightBoundingBox, PRBool *aUsedHyphenation, PRUint32 *aLastBreak); diff --git a/gfx/thebes/src/gfxFont.cpp b/gfx/thebes/src/gfxFont.cpp index 66dcd6c582b..d9591a67eb5 100644 --- a/gfx/thebes/src/gfxFont.cpp +++ b/gfx/thebes/src/gfxFont.cpp @@ -1228,6 +1228,7 @@ gfxTextRun::BreakAndMeasureText(PRUint32 aStart, PRUint32 aMaxLength, PRBool aLineBreakBefore, gfxFloat aWidth, PropertyProvider *aProvider, PRBool aSuppressInitialBreak, + gfxFloat *aTrimWhitespace, Metrics *aMetrics, PRBool aTightBoundingBox, PRBool *aUsedHyphenation, PRUint32 *aLastBreak) @@ -1260,6 +1261,8 @@ gfxTextRun::BreakAndMeasureText(PRUint32 aStart, PRUint32 aMaxLength, gfxFloat width = 0; gfxFloat advance = 0; + gfxFloat trimmableAdvance = 0; + PRUint32 trimmableChars = 0; PRInt32 lastBreak = -1; PRBool aborted = PR_FALSE; PRUint32 end = aStart + aMaxLength; @@ -1293,8 +1296,8 @@ gfxTextRun::BreakAndMeasureText(PRUint32 aStart, PRUint32 aMaxLength, if (hyphenation) { hyphenatedAdvance += aProvider->GetHyphenWidth(); } - - if (lastBreak < 0 || width + hyphenatedAdvance <= aWidth) { + + if (lastBreak < 0 || width + hyphenatedAdvance - trimmableAdvance <= aWidth) { // We can break here. lastBreak = i; lastBreakUsedHyphenation = hyphenation; @@ -1302,22 +1305,23 @@ gfxTextRun::BreakAndMeasureText(PRUint32 aStart, PRUint32 aMaxLength, width += advance; advance = 0; - if (width > aWidth) { + if (width - trimmableAdvance > aWidth) { // No more text fits. Abort aborted = PR_TRUE; break; } } + gfxFloat charAdvance = 0; if (i >= ligatureRunStart && i < ligatureRunEnd) { CompressedGlyph *glyphData = &charGlyphs[i]; if (glyphData->IsSimpleGlyph()) { - advance += glyphData->GetSimpleAdvance(); + charAdvance = glyphData->GetSimpleAdvance(); } else if (glyphData->IsComplexOrMissing()) { const DetailedGlyph *details = GetDetailedGlyphs(i); if (details) { while (1) { - advance += details->mAdvance; + charAdvance += details->mAdvance; if (details->mIsLastGlyph) break; ++details; @@ -1326,10 +1330,21 @@ gfxTextRun::BreakAndMeasureText(PRUint32 aStart, PRUint32 aMaxLength, } if (haveSpacing) { PropertyProvider::Spacing *space = &spacingBuffer[i - bufferStart]; - advance += space->mBefore + space->mAfter; + charAdvance += space->mBefore + space->mAfter; } } else { - advance += GetPartialLigatureWidth(i, i + 1, aProvider); + charAdvance += GetPartialLigatureWidth(i, i + 1, aProvider); + } + + advance += charAdvance; + if (aTrimWhitespace) { + if (GetChar(i) == ' ') { + ++trimmableChars; + trimmableAdvance += charAdvance; + } else { + trimmableAdvance = 0; + trimmableChars = 0; + } } } @@ -1342,7 +1357,7 @@ gfxTextRun::BreakAndMeasureText(PRUint32 aStart, PRUint32 aMaxLength, // 2) some of the text fit up to a break opportunity (width > aWidth && lastBreak >= 0) // 3) none of the text fits before a break opportunity (width > aWidth && lastBreak < 0) PRUint32 charsFit; - if (width <= aWidth) { + if (width - trimmableAdvance <= aWidth) { charsFit = aMaxLength; } else if (lastBreak >= 0) { charsFit = lastBreak - aStart; @@ -1351,7 +1366,10 @@ gfxTextRun::BreakAndMeasureText(PRUint32 aStart, PRUint32 aMaxLength, } if (aMetrics) { - *aMetrics = MeasureText(aStart, charsFit, aTightBoundingBox, aProvider); + *aMetrics = MeasureText(aStart, charsFit - trimmableChars, aTightBoundingBox, aProvider); + } + if (aTrimWhitespace) { + *aTrimWhitespace = trimmableAdvance; } if (aUsedHyphenation) { *aUsedHyphenation = lastBreakUsedHyphenation;