| Index: third_party/WebKit/Source/core/layout/svg/LayoutSVGInlineText.cpp
|
| diff --git a/third_party/WebKit/Source/core/layout/svg/LayoutSVGInlineText.cpp b/third_party/WebKit/Source/core/layout/svg/LayoutSVGInlineText.cpp
|
| index 3154e73ea24311e011b1b2f6700a7d9c2506d582..27da5076d205ab21e89fdc6d3895b635d7ef8c99 100644
|
| --- a/third_party/WebKit/Source/core/layout/svg/LayoutSVGInlineText.cpp
|
| +++ b/third_party/WebKit/Source/core/layout/svg/LayoutSVGInlineText.cpp
|
| @@ -207,7 +207,7 @@ PositionWithAffinity LayoutSVGInlineText::positionForPoint(const LayoutPoint& po
|
|
|
| namespace {
|
|
|
| -inline bool characterStartsSurrogatePair(const TextRun& run, unsigned index)
|
| +inline bool isValidSurrogatePair(const TextRun& run, unsigned index)
|
| {
|
| if (!U16_IS_LEAD(run[index]))
|
| return false;
|
| @@ -216,57 +216,7 @@ inline bool characterStartsSurrogatePair(const TextRun& run, unsigned index)
|
| return U16_IS_TRAIL(run[index + 1]);
|
| }
|
|
|
| -class SVGTextMetricsCalculator {
|
| -public:
|
| - SVGTextMetricsCalculator(LayoutSVGInlineText&);
|
| - ~SVGTextMetricsCalculator();
|
| -
|
| - bool advancePosition();
|
| - unsigned currentPosition() const { return m_currentPosition; }
|
| -
|
| - SVGTextMetrics currentCharacterMetrics();
|
| -
|
| - // TODO(pdr): Character-based iteration is ambiguous and error-prone. It
|
| - // should be unified under a single concept. See: https://crbug.com/593570
|
| - bool currentCharacterStartsSurrogatePair() const
|
| - {
|
| - return characterStartsSurrogatePair(m_run, m_currentPosition);
|
| - }
|
| - bool currentCharacterIsWhiteSpace() const
|
| - {
|
| - return m_run[m_currentPosition] == ' ';
|
| - }
|
| - unsigned characterCount() const
|
| - {
|
| - return static_cast<unsigned>(m_run.charactersLength());
|
| - }
|
| -
|
| -private:
|
| - void setupBidiRuns();
|
| -
|
| - static TextRun constructTextRun(LayoutSVGInlineText&, unsigned position, unsigned length, TextDirection);
|
| -
|
| - // Ensure |m_subrunRanges| is updated for the current bidi run, or the
|
| - // complete m_run if no bidi runs are present. Returns the current position
|
| - // in the subrun which can be used to index into |m_subrunRanges|.
|
| - unsigned updateSubrunRangesForCurrentPosition();
|
| -
|
| - // Current character position in m_text.
|
| - unsigned m_currentPosition;
|
| -
|
| - LayoutSVGInlineText& m_text;
|
| - float m_fontScalingFactor;
|
| - float m_cachedFontHeight;
|
| - TextRun m_run;
|
| -
|
| - BidiCharacterRun* m_bidiRun;
|
| - BidiResolver<TextRunIterator, BidiCharacterRun> m_bidiResolver;
|
| -
|
| - // Ranges for the current bidi run if present, or the entire run otherwise.
|
| - Vector<CharacterRange> m_subrunRanges;
|
| -};
|
| -
|
| -TextRun SVGTextMetricsCalculator::constructTextRun(LayoutSVGInlineText& text, unsigned position, unsigned length, TextDirection textDirection)
|
| +TextRun constructTextRun(LayoutSVGInlineText& text, unsigned position, unsigned length, TextDirection textDirection)
|
| {
|
| const ComputedStyle& style = text.styleRef();
|
|
|
| @@ -294,56 +244,12 @@ TextRun SVGTextMetricsCalculator::constructTextRun(LayoutSVGInlineText& text, un
|
| return run;
|
| }
|
|
|
| -SVGTextMetricsCalculator::SVGTextMetricsCalculator(LayoutSVGInlineText& text)
|
| - : m_currentPosition(0)
|
| - , m_text(text)
|
| - , m_fontScalingFactor(m_text.scalingFactor())
|
| - , m_cachedFontHeight(m_text.scaledFont().getFontMetrics().floatHeight() / m_fontScalingFactor)
|
| - , m_run(constructTextRun(m_text, 0, m_text.textLength(), m_text.styleRef().direction()))
|
| - , m_bidiRun(nullptr)
|
| -{
|
| - setupBidiRuns();
|
| -}
|
| -
|
| -SVGTextMetricsCalculator::~SVGTextMetricsCalculator()
|
| -{
|
| - m_bidiResolver.runs().deleteRuns();
|
| -}
|
| -
|
| -void SVGTextMetricsCalculator::setupBidiRuns()
|
| -{
|
| - BidiRunList<BidiCharacterRun>& bidiRuns = m_bidiResolver.runs();
|
| - bool bidiOverride = isOverride(m_text.styleRef().unicodeBidi());
|
| - BidiStatus status(LTR, bidiOverride);
|
| - if (m_run.is8Bit() || bidiOverride) {
|
| - WTF::Unicode::CharDirection direction = WTF::Unicode::LeftToRight;
|
| - // If BiDi override is in effect, use the specified direction.
|
| - if (bidiOverride && !m_text.styleRef().isLeftToRightDirection())
|
| - direction = WTF::Unicode::RightToLeft;
|
| - bidiRuns.addRun(new BidiCharacterRun(0, m_run.charactersLength(), status.context.get(), direction));
|
| - } else {
|
| - status.last = status.lastStrong = WTF::Unicode::OtherNeutral;
|
| - m_bidiResolver.setStatus(status);
|
| - m_bidiResolver.setPositionIgnoringNestedIsolates(TextRunIterator(&m_run, 0));
|
| - const bool hardLineBreak = false;
|
| - const bool reorderRuns = false;
|
| - m_bidiResolver.createBidiRunsForLine(TextRunIterator(&m_run, m_run.length()), NoVisualOverride, hardLineBreak, reorderRuns);
|
| - }
|
| - m_bidiRun = bidiRuns.firstRun();
|
| -}
|
| -
|
| -bool SVGTextMetricsCalculator::advancePosition()
|
| -{
|
| - m_currentPosition += currentCharacterStartsSurrogatePair() ? 2 : 1;
|
| - return m_currentPosition < characterCount();
|
| -}
|
| -
|
| // TODO(pdr): We only have per-glyph data so we need to synthesize per-grapheme
|
| // data. E.g., if 'fi' is shaped into a single glyph, we do not know the 'i'
|
| // position. The code below synthesizes an average glyph width when characters
|
| // share a single position. This will incorrectly split combining diacritics.
|
| // See: https://crbug.com/473476.
|
| -static void synthesizeGraphemeWidths(const TextRun& run, Vector<CharacterRange>& ranges)
|
| +void synthesizeGraphemeWidths(const TextRun& run, Vector<CharacterRange>& ranges)
|
| {
|
| unsigned distributeCount = 0;
|
| for (int rangeIndex = static_cast<int>(ranges.size()) - 1; rangeIndex >= 0; --rangeIndex) {
|
| @@ -352,7 +258,7 @@ static void synthesizeGraphemeWidths(const TextRun& run, Vector<CharacterRange>&
|
| distributeCount++;
|
| } else if (distributeCount != 0) {
|
| // Only count surrogate pairs as a single character.
|
| - bool surrogatePair = characterStartsSurrogatePair(run, rangeIndex);
|
| + bool surrogatePair = isValidSurrogatePair(run, rangeIndex);
|
| if (!surrogatePair)
|
| distributeCount++;
|
|
|
| @@ -373,38 +279,38 @@ static void synthesizeGraphemeWidths(const TextRun& run, Vector<CharacterRange>&
|
| }
|
| }
|
|
|
| -unsigned SVGTextMetricsCalculator::updateSubrunRangesForCurrentPosition()
|
| +} // namespace
|
| +
|
| +void LayoutSVGInlineText::addMetricsFromRun(
|
| + const TextRun& run, bool& lastCharacterWasWhiteSpace)
|
| {
|
| - ASSERT(m_bidiRun);
|
| - if (m_currentPosition >= static_cast<unsigned>(m_bidiRun->stop())) {
|
| - m_bidiRun = m_bidiRun->next();
|
| - // Ensure new subrange ranges are computed below.
|
| - m_subrunRanges.clear();
|
| - }
|
| - ASSERT(m_bidiRun);
|
| - ASSERT(static_cast<int>(m_currentPosition) < m_bidiRun->stop());
|
| -
|
| - unsigned positionInRun = m_currentPosition - m_bidiRun->start();
|
| - if (positionInRun >= m_subrunRanges.size()) {
|
| - TextRun subRun = constructTextRun(m_text, m_bidiRun->start(),
|
| - m_bidiRun->stop() - m_bidiRun->start(), m_bidiRun->direction());
|
| - m_subrunRanges = m_text.scaledFont().individualCharacterRanges(subRun);
|
| - synthesizeGraphemeWidths(subRun, m_subrunRanges);
|
| - }
|
| + Vector<CharacterRange> charRanges = scaledFont().individualCharacterRanges(run);
|
| + synthesizeGraphemeWidths(run, charRanges);
|
|
|
| - ASSERT(m_subrunRanges.size() && positionInRun < m_subrunRanges.size());
|
| - return positionInRun;
|
| -}
|
| + const float cachedFontHeight = scaledFont().getFontMetrics().floatHeight() / m_scalingFactor;
|
| + const bool preserveWhiteSpace = styleRef().whiteSpace() == PRE;
|
| + const unsigned runLength = static_cast<unsigned>(run.length());
|
|
|
| -SVGTextMetrics SVGTextMetricsCalculator::currentCharacterMetrics()
|
| -{
|
| - unsigned currentSubrunPosition = updateSubrunRangesForCurrentPosition();
|
| - unsigned length = currentCharacterStartsSurrogatePair() ? 2 : 1;
|
| - float width = m_subrunRanges[currentSubrunPosition].width();
|
| - return SVGTextMetrics(length, width / m_fontScalingFactor, m_cachedFontHeight);
|
| -}
|
| + // TODO(pdr): Character-based iteration is ambiguous and error-prone. It
|
| + // should be unified under a single concept. See: https://crbug.com/593570
|
| + unsigned characterIndex = 0;
|
| + while (characterIndex < runLength) {
|
| + bool currentCharacterIsWhiteSpace = run[characterIndex] == ' ';
|
| + if (!preserveWhiteSpace && lastCharacterWasWhiteSpace && currentCharacterIsWhiteSpace) {
|
| + m_metrics.append(SVGTextMetrics(SVGTextMetrics::SkippedSpaceMetrics));
|
| + characterIndex++;
|
| + continue;
|
| + }
|
|
|
| -} // namespace
|
| + unsigned length = isValidSurrogatePair(run, characterIndex) ? 2 : 1;
|
| + float width = charRanges[characterIndex].width() / m_scalingFactor;
|
| +
|
| + m_metrics.append(SVGTextMetrics(length, width, cachedFontHeight));
|
| +
|
| + lastCharacterWasWhiteSpace = currentCharacterIsWhiteSpace;
|
| + characterIndex += length;
|
| + }
|
| +}
|
|
|
| void LayoutSVGInlineText::updateMetricsList(bool& lastCharacterWasWhiteSpace)
|
| {
|
| @@ -413,23 +319,33 @@ void LayoutSVGInlineText::updateMetricsList(bool& lastCharacterWasWhiteSpace)
|
| if (!textLength())
|
| return;
|
|
|
| - // TODO(pdr): This loop is too tightly coupled to SVGTextMetricsCalculator.
|
| - // We should refactor SVGTextMetricsCalculator to be a simple bidi run
|
| - // iterator and move all subrun logic to a single function.
|
| - SVGTextMetricsCalculator calculator(*this);
|
| - bool preserveWhiteSpace = styleRef().whiteSpace() == PRE;
|
| - do {
|
| - bool currentCharacterIsWhiteSpace = calculator.currentCharacterIsWhiteSpace();
|
| - if (!preserveWhiteSpace && lastCharacterWasWhiteSpace && currentCharacterIsWhiteSpace) {
|
| - m_metrics.append(SVGTextMetrics(SVGTextMetrics::SkippedSpaceMetrics));
|
| - ASSERT(calculator.currentCharacterMetrics().length() == 1);
|
| - continue;
|
| - }
|
| + TextRun run = constructTextRun(*this, 0, textLength(), styleRef().direction());
|
| + BidiResolver<TextRunIterator, BidiCharacterRun> bidiResolver;
|
| + BidiRunList<BidiCharacterRun>& bidiRuns = bidiResolver.runs();
|
| + bool bidiOverride = isOverride(styleRef().unicodeBidi());
|
| + BidiStatus status(LTR, bidiOverride);
|
| + if (run.is8Bit() || bidiOverride) {
|
| + WTF::Unicode::CharDirection direction = WTF::Unicode::LeftToRight;
|
| + // If BiDi override is in effect, use the specified direction.
|
| + if (bidiOverride && !styleRef().isLeftToRightDirection())
|
| + direction = WTF::Unicode::RightToLeft;
|
| + bidiRuns.addRun(new BidiCharacterRun(0, run.charactersLength(), status.context.get(), direction));
|
| + } else {
|
| + status.last = status.lastStrong = WTF::Unicode::OtherNeutral;
|
| + bidiResolver.setStatus(status);
|
| + bidiResolver.setPositionIgnoringNestedIsolates(TextRunIterator(&run, 0));
|
| + const bool hardLineBreak = false;
|
| + const bool reorderRuns = false;
|
| + bidiResolver.createBidiRunsForLine(TextRunIterator(&run, run.length()), NoVisualOverride, hardLineBreak, reorderRuns);
|
| + }
|
|
|
| - m_metrics.append(calculator.currentCharacterMetrics());
|
| + for (const BidiCharacterRun* bidiRun = bidiRuns.firstRun(); bidiRun; bidiRun = bidiRun->next()) {
|
| + TextRun subRun = constructTextRun(*this, bidiRun->start(), bidiRun->stop() - bidiRun->start(),
|
| + bidiRun->direction());
|
| + addMetricsFromRun(subRun, lastCharacterWasWhiteSpace);
|
| + }
|
|
|
| - lastCharacterWasWhiteSpace = currentCharacterIsWhiteSpace;
|
| - } while (calculator.advancePosition());
|
| + bidiResolver.runs().deleteRuns();
|
| }
|
|
|
| void LayoutSVGInlineText::updateScaledFont()
|
|
|