Skip to content

Commit

Permalink
Simplify SVGTextQuery::modifyStartEndPositionsRespectingLigatures
Browse files Browse the repository at this point in the history
https://bugs.webkit.org/show_bug.cgi?id=262458

Reviewed by Chris Dumez.

Merge: https://src.chromium.org/viewvc/blink?view=revision&revision=177231

Simplify this method by passing it the fragment in question, and then use
SVGTextFragment::metricsListOffset to get a reasonable starting point.
Rewrite the big loop into two simpler loops - one for each end-point.
This shaves another ~15% off the TC in the bug (on top of 268656@main).

* Source/WebCore/rendering/svg/SVGTextQuery.cpp:
(SVGTextQuery::mapStartEndPositionsIntoFragmentCoordinates):
(SVGTextQuery::modifyStartEndPositionsRespectingLigatures):
* Source/WebCore/rendering/svg/SVGTextQuery.h:

Canonical link: https://commits.webkit.org/268751@main
  • Loading branch information
Ahmad-S792 authored and cdumez committed Oct 2, 2023
1 parent 6a5dbe0 commit 006900d
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 61 deletions.
83 changes: 23 additions & 60 deletions Source/WebCore/rendering/svg/SVGTextQuery.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,82 +155,45 @@ bool SVGTextQuery::mapStartEndPositionsIntoFragmentCoordinates(Data* queryData,
if (startPosition >= endPosition)
return false;

modifyStartEndPositionsRespectingLigatures(queryData, startPosition, endPosition);
modifyStartEndPositionsRespectingLigatures(queryData, fragment, startPosition, endPosition);
if (!queryData->textBox->mapStartEndPositionsIntoFragmentCoordinates(fragment, startPosition, endPosition))
return false;

ASSERT_WITH_SECURITY_IMPLICATION(startPosition < endPosition);
return true;
}

void SVGTextQuery::modifyStartEndPositionsRespectingLigatures(Data* queryData, unsigned& startPosition, unsigned& endPosition) const
void SVGTextQuery::modifyStartEndPositionsRespectingLigatures(Data* queryData, const SVGTextFragment& fragment, unsigned& startPosition, unsigned& endPosition) const
{
SVGTextLayoutAttributes* layoutAttributes = queryData->textRenderer->layoutAttributes();
Vector<SVGTextMetrics>& textMetricsValues = layoutAttributes->textMetricsValues();
unsigned boxStart = queryData->textBox->start();
unsigned boxLength = queryData->textBox->len();

unsigned textMetricsOffset = 0;
unsigned textMetricsSize = textMetricsValues.size();

unsigned positionOffset = 0;
unsigned positionSize = layoutAttributes->context().text().length();

bool alterStartPosition = true;
bool alterEndPosition = true;

std::optional<unsigned> lastPositionOffset;
for (; textMetricsOffset < textMetricsSize && positionOffset < positionSize; ++textMetricsOffset) {
SVGTextMetrics& metrics = textMetricsValues[textMetricsOffset];

// Advance to text box start location.
if (positionOffset < boxStart) {
positionOffset += metrics.length();
continue;
}

// Stop if we've finished processing this text box.
if (positionOffset >= boxStart + boxLength)
break;

// If the start position maps to a character in the metrics list, we don't need to modify it.
if (startPosition == positionOffset)
alterStartPosition = false;

// If the start position maps to a character in the metrics list, we don't need to modify it.
if (endPosition == positionOffset)
alterEndPosition = false;

// Detect ligatures.
if (lastPositionOffset && lastPositionOffset.value() - positionOffset > 1) {
if (alterStartPosition && startPosition > lastPositionOffset.value() && startPosition < positionOffset) {
startPosition = lastPositionOffset.value();
alterStartPosition = false;
}

if (alterEndPosition && endPosition > lastPositionOffset.value() && endPosition < positionOffset) {
endPosition = positionOffset;
alterEndPosition = false;
}
}
unsigned textMetricsOffset = fragment.metricsListOffset;

if (!alterStartPosition && !alterEndPosition)
// Compute the offset of the fragment within the box, since that's the
// space <startPosition, endPosition> is in (and that's what we need).
unsigned fragmentOffsetInBox = fragment.characterOffset - queryData->textBox->start();
unsigned fragmentEndInBox = fragmentOffsetInBox + fragment.length;
// Find the text metrics cell that start at or contain the character startPosition.
while (fragmentOffsetInBox < fragmentEndInBox) {
auto& metrics = textMetricsValues[textMetricsOffset];
unsigned glyphEnd = fragmentOffsetInBox + metrics.length();
if (startPosition < glyphEnd)
break;

lastPositionOffset = positionOffset;
positionOffset += metrics.length();
fragmentOffsetInBox = glyphEnd;
++textMetricsOffset;
}
startPosition = fragmentOffsetInBox;

if (!alterStartPosition && !alterEndPosition)
return;

if (lastPositionOffset && lastPositionOffset.value() - positionOffset > 1) {
if (alterStartPosition && startPosition > lastPositionOffset.value() && startPosition < positionOffset)
startPosition = lastPositionOffset.value();

if (alterEndPosition && endPosition > lastPositionOffset.value() && endPosition < positionOffset)
endPosition = positionOffset;
// Find the text metrics cell that contain or ends at the character endPosition.
while (fragmentOffsetInBox < fragmentEndInBox) {
auto& metrics = textMetricsValues[textMetricsOffset];
fragmentOffsetInBox += metrics.length();
if (fragmentOffsetInBox >= endPosition)
break;
++textMetricsOffset;
}
endPosition = fragmentOffsetInBox;
}

// numberOfCharacters() implementation
Expand Down
3 changes: 2 additions & 1 deletion Source/WebCore/rendering/svg/SVGTextQuery.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
/*
* Copyright (C) Research In Motion Limited 2010. All rights reserved.
* Copyright (C) 2014 Google Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
Expand Down Expand Up @@ -51,7 +52,7 @@ class SVGTextQuery {

void collectTextBoxesInFlowBox(LegacyInlineFlowBox*);
bool mapStartEndPositionsIntoFragmentCoordinates(Data*, const SVGTextFragment&, unsigned& startPosition, unsigned& endPosition) const;
void modifyStartEndPositionsRespectingLigatures(Data*, unsigned& startPosition, unsigned& endPosition) const;
void modifyStartEndPositionsRespectingLigatures(Data*, const SVGTextFragment&, unsigned& startPosition, unsigned& endPosition) const;

private:
bool numberOfCharactersCallback(Data*, const SVGTextFragment&) const;
Expand Down

0 comments on commit 006900d

Please sign in to comment.