From b9886e97f5f629a58ef3c36bc7a8bc9b6d7bf609 Mon Sep 17 00:00:00 2001 From: Mirko Brodesser Date: Mon, 16 Sep 2019 08:40:38 +0000 Subject: [PATCH] Bug 1581471: part 2) Factor out finding wrap index for line content to `CurrentLine`. r=hsivonen Depends on D45976 Differential Revision: https://phabricator.services.mozilla.com/D45977 --HG-- extra : moz-landing-system : lando --- dom/base/nsPlainTextSerializer.cpp | 140 ++++++++++++++++------------- dom/base/nsPlainTextSerializer.h | 6 ++ 2 files changed, 83 insertions(+), 63 deletions(-) diff --git a/dom/base/nsPlainTextSerializer.cpp b/dom/base/nsPlainTextSerializer.cpp index 00cc760792f9..cc24fc0b12ed 100644 --- a/dom/base/nsPlainTextSerializer.cpp +++ b/dom/base/nsPlainTextSerializer.cpp @@ -12,6 +12,8 @@ #include "nsPlainTextSerializer.h" +#include + #include "nsPrintfCString.h" #include "nsIServiceManager.h" #include "nsDebug.h" @@ -120,6 +122,78 @@ void nsPlainTextSerializer::CurrentLine::ResetContentAndIndentationHeader() { mIndentation.mHeader.Truncate(); } +int32_t nsPlainTextSerializer::CurrentLine::FindWrapIndexForContent( + const uint32_t aWrapColumn, const uint32_t aContentWidth, + mozilla::intl::LineBreaker* aLineBreaker) const { + MOZ_ASSERT(aContentWidth < std::numeric_limits::max()); + MOZ_ASSERT(static_cast(aContentWidth) == + GetUnicharStringWidth(mContent)); + + const uint32_t prefixwidth = DeterminePrefixWidth(); + int32_t goodSpace = mContent.Length(); + + if (aLineBreaker) { + // We go from the end removing one letter at a time until + // we have a reasonable width + uint32_t width = aContentWidth; + while (goodSpace > 0 && (width + prefixwidth > aWrapColumn)) { + goodSpace--; + width -= GetUnicharWidth(mContent[goodSpace]); + } + + goodSpace++; + + goodSpace = + aLineBreaker->Prev(mContent.get(), mContent.Length(), goodSpace); + if (goodSpace != NS_LINEBREAKER_NEED_MORE_TEXT && + nsCRT::IsAsciiSpace(mContent.CharAt(goodSpace - 1))) { + --goodSpace; // adjust the position since line breaker returns a + // position next to space + } + } else { + // In this case we don't want strings, especially CJK-ones, to be split. + // See + // https://bugzilla.mozilla.org/show_bug.cgi?id=333064 for more + // information. + + if (mContent.IsEmpty() || aWrapColumn < prefixwidth) { + goodSpace = NS_LINEBREAKER_NEED_MORE_TEXT; + } else { + goodSpace = std::min(aWrapColumn - prefixwidth, mContent.Length() - 1); + while (goodSpace >= 0 && + !nsCRT::IsAsciiSpace(mContent.CharAt(goodSpace))) { + goodSpace--; + } + } + } + + if (goodSpace == NS_LINEBREAKER_NEED_MORE_TEXT) { + // If we didn't find a good place to break, accept long line and + // try to find another place to break + goodSpace = + (prefixwidth > aWrapColumn + 1) ? 1 : aWrapColumn - prefixwidth + 1; + if (aLineBreaker) { + if ((uint32_t)goodSpace < mContent.Length()) + goodSpace = + aLineBreaker->Next(mContent.get(), mContent.Length(), goodSpace); + if (goodSpace == NS_LINEBREAKER_NEED_MORE_TEXT) + goodSpace = mContent.Length(); + } else { + // In this case we don't want strings, especially CJK-ones, to be + // split. See + // https://bugzilla.mozilla.org/show_bug.cgi?id=333064 for more + // information. + goodSpace = (prefixwidth > aWrapColumn) ? 1 : aWrapColumn - prefixwidth; + const int32_t linelength = mContent.Length(); + while (goodSpace < linelength && + !nsCRT::IsAsciiSpace(mContent.CharAt(goodSpace))) { + goodSpace++; + } + } + } + return goodSpace; +} + nsPlainTextSerializer::OutputManager::OutputManager(const int32_t aFlags, nsAString& aOutput) : mFlags{aFlags}, mOutput{aOutput}, mAtFirstColumn{true} { @@ -1224,75 +1298,15 @@ void nsPlainTextSerializer::MaybeWrapAndOutputCompleteLines() { uint32_t bonuswidth = (mWrapColumn > 20) ? 4 : 0; while (currentLineContentWidth + prefixwidth > mWrapColumn + bonuswidth) { - int32_t goodSpace = mCurrentLine.mContent.Length(); - - if (mLineBreaker) { - // We go from the end removing one letter at a time until - // we have a reasonable width - uint32_t width = currentLineContentWidth; - while (goodSpace > 0 && (width + prefixwidth > mWrapColumn)) { - goodSpace--; - width -= GetUnicharWidth(mCurrentLine.mContent[goodSpace]); - } - - goodSpace++; - - goodSpace = mLineBreaker->Prev(mCurrentLine.mContent.get(), - mCurrentLine.mContent.Length(), goodSpace); - if (goodSpace != NS_LINEBREAKER_NEED_MORE_TEXT && - nsCRT::IsAsciiSpace(mCurrentLine.mContent.CharAt(goodSpace - 1))) { - --goodSpace; // adjust the position since line breaker returns a - // position next to space - } - } else { - // In this case we don't want strings, especially CJK-ones, to be split. - // See - // https://bugzilla.mozilla.org/show_bug.cgi?id=333064 for more - // information. - - if (mCurrentLine.mContent.IsEmpty() || mWrapColumn < prefixwidth) { - goodSpace = NS_LINEBREAKER_NEED_MORE_TEXT; - } else { - goodSpace = std::min(mWrapColumn - prefixwidth, - mCurrentLine.mContent.Length() - 1); - while (goodSpace >= 0 && - !nsCRT::IsAsciiSpace(mCurrentLine.mContent.CharAt(goodSpace))) { - goodSpace--; - } - } - } - - nsAutoString restOfLine; - if (goodSpace == NS_LINEBREAKER_NEED_MORE_TEXT) { - // If we didn't find a good place to break, accept long line and - // try to find another place to break - goodSpace = - (prefixwidth > mWrapColumn + 1) ? 1 : mWrapColumn - prefixwidth + 1; - if (mLineBreaker) { - if ((uint32_t)goodSpace < mCurrentLine.mContent.Length()) - goodSpace = - mLineBreaker->Next(mCurrentLine.mContent.get(), - mCurrentLine.mContent.Length(), goodSpace); - if (goodSpace == NS_LINEBREAKER_NEED_MORE_TEXT) - goodSpace = mCurrentLine.mContent.Length(); - } else { - // In this case we don't want strings, especially CJK-ones, to be - // split. See - // https://bugzilla.mozilla.org/show_bug.cgi?id=333064 for more - // information. - goodSpace = (prefixwidth > mWrapColumn) ? 1 : mWrapColumn - prefixwidth; - while (goodSpace < linelength && - !nsCRT::IsAsciiSpace(mCurrentLine.mContent.CharAt(goodSpace))) { - goodSpace++; - } - } - } + const int32_t goodSpace = mCurrentLine.FindWrapIndexForContent( + mWrapColumn, currentLineContentWidth, mLineBreaker); if ((goodSpace < linelength) && (goodSpace > 0)) { // Found a place to break // -1 (trim a char at the break position) // only if the line break was a space. + nsAutoString restOfLine; if (nsCRT::IsAsciiSpace(mCurrentLine.mContent.CharAt(goodSpace))) { mCurrentLine.mContent.Right(restOfLine, linelength - goodSpace - 1); } else { diff --git a/dom/base/nsPlainTextSerializer.h b/dom/base/nsPlainTextSerializer.h index 4422b3175c35..7dde10a46696 100644 --- a/dom/base/nsPlainTextSerializer.h +++ b/dom/base/nsPlainTextSerializer.h @@ -229,6 +229,12 @@ class nsPlainTextSerializer final : public nsIContentSerializer { return !mContent.IsEmpty() || !mIndentation.mHeader.IsEmpty(); } + // @param aContentWidth Has to be the unichar string width of mContent. + // @param aLineBreaker May be nullptr. + int32_t FindWrapIndexForContent( + uint32_t aWrapColumn, uint32_t aContentWidth, + mozilla::intl::LineBreaker* aLineBreaker) const; + // @return Combined width of cite quote level and indentation. uint32_t DeterminePrefixWidth() const { // XXX: Should calculate prefixwidth with GetUnicharStringWidth