Index: third_party/WebKit/Source/core/layout/svg/SVGTextQuery.cpp |
diff --git a/third_party/WebKit/Source/core/layout/svg/SVGTextQuery.cpp b/third_party/WebKit/Source/core/layout/svg/SVGTextQuery.cpp |
index 8c3173e3171fb19055ac71e968374813c92f7cd8..d1670c7da4a082ffa86ecd56be4db95cc6898b2f 100644 |
--- a/third_party/WebKit/Source/core/layout/svg/SVGTextQuery.cpp |
+++ b/third_party/WebKit/Source/core/layout/svg/SVGTextQuery.cpp |
@@ -293,27 +293,27 @@ struct StartPositionOfCharacterData : QueryData { |
FloatPoint startPosition; |
}; |
-static FloatPoint calculateGlyphPositionWithoutTransform(const QueryData* queryData, const SVGTextFragment& fragment, unsigned offsetInFragment) |
+static FloatPoint logicalGlyphPositionToPhysical(const QueryData* queryData, const SVGTextFragment& fragment, float logicalGlyphOffset) |
{ |
- float glyphOffsetInDirection = calculateGlyphRange(queryData, fragment, 0, offsetInFragment); |
- |
+ float physicalGlyphOffset = logicalGlyphOffset; |
if (!queryData->textBox->isLeftToRightDirection()) { |
float fragmentExtent = queryData->isVerticalText ? fragment.height : fragment.width; |
- glyphOffsetInDirection = fragmentExtent - glyphOffsetInDirection; |
+ physicalGlyphOffset = fragmentExtent - logicalGlyphOffset; |
} |
FloatPoint glyphPosition(fragment.x, fragment.y); |
if (queryData->isVerticalText) |
- glyphPosition.move(0, glyphOffsetInDirection); |
+ glyphPosition.move(0, physicalGlyphOffset); |
else |
- glyphPosition.move(glyphOffsetInDirection, 0); |
+ glyphPosition.move(physicalGlyphOffset, 0); |
return glyphPosition; |
} |
static FloatPoint calculateGlyphPosition(const QueryData* queryData, const SVGTextFragment& fragment, unsigned offsetInFragment) |
{ |
- FloatPoint glyphPosition = calculateGlyphPositionWithoutTransform(queryData, fragment, offsetInFragment); |
+ float glyphOffsetInDirection = calculateGlyphRange(queryData, fragment, 0, offsetInFragment); |
+ FloatPoint glyphPosition = logicalGlyphPositionToPhysical(queryData, fragment, glyphOffsetInDirection); |
if (fragment.isTransformed()) { |
AffineTransform fragmentTransform = fragment.buildFragmentTransform(SVGTextFragment::TransformIgnoringTextLength); |
glyphPosition = fragmentTransform.mapPoint(glyphPosition); |
@@ -421,33 +421,39 @@ struct ExtentOfCharacterData : QueryData { |
FloatRect extent; |
}; |
-static inline FloatRect calculateGlyphBoundaries(const QueryData* queryData, const SVGTextFragment& fragment, int startPosition) |
+static FloatRect physicalGlyphExtents(const QueryData* queryData, const SVGTextMetrics& metrics, const FloatPoint& glyphPosition) |
{ |
- float scalingFactor = queryData->textLineLayout.scalingFactor(); |
- ASSERT(scalingFactor); |
- |
- FloatPoint glyphPosition = calculateGlyphPositionWithoutTransform(queryData, fragment, startPosition); |
- glyphPosition.move(0, -queryData->textLineLayout.scaledFont().getFontMetrics().floatAscent() / scalingFactor); |
- |
- // Use the SVGTextMetrics computed by SVGTextMetricsBuilder (which spends |
- // time attempting to compute more correct glyph bounds already, handling |
- // cursive scripts to some degree.) |
- const MetricsList& textMetricsValues = queryData->textLineLayout.layoutAttributes()->textMetricsValues(); |
- auto metrics = findMetricsForCharacter(textMetricsValues, fragment, startPosition); |
- |
// TODO(fs): Negative glyph extents seems kind of weird to have, but |
// presently it can occur in some cases (like Arabic.) |
- FloatSize glyphSize(std::max<float>(metrics->width(), 0), std::max<float>(metrics->height(), 0)); |
+ FloatRect glyphExtents( |
+ glyphPosition, |
+ FloatSize(std::max<float>(metrics.width(), 0), std::max<float>(metrics.height(), 0))); |
// If RTL, adjust the starting point to align with the LHS of the glyph bounding box. |
if (!queryData->textBox->isLeftToRightDirection()) { |
if (queryData->isVerticalText) |
- glyphPosition.move(0, -glyphSize.height()); |
+ glyphExtents.move(0, -glyphExtents.height()); |
else |
- glyphPosition.move(-glyphSize.width(), 0); |
+ glyphExtents.move(-glyphExtents.width(), 0); |
} |
+ return glyphExtents; |
+} |
+ |
+static inline FloatRect calculateGlyphBoundaries(const QueryData* queryData, const SVGTextFragment& fragment, int startPosition) |
+{ |
+ const float scalingFactor = queryData->textLineLayout.scalingFactor(); |
+ ASSERT(scalingFactor); |
+ const float baseline = queryData->textLineLayout.scaledFont().getFontMetrics().floatAscent() / scalingFactor; |
- FloatRect extent(glyphPosition, glyphSize); |
+ float glyphOffsetInDirection = calculateGlyphRange(queryData, fragment, 0, startPosition); |
+ FloatPoint glyphPosition = logicalGlyphPositionToPhysical(queryData, fragment, glyphOffsetInDirection); |
+ glyphPosition.move(0, -baseline); |
+ |
+ // Use the SVGTextMetrics computed by SVGTextMetricsBuilder. |
+ const MetricsList& metricsList = queryData->textLineLayout.layoutAttributes()->textMetricsValues(); |
+ auto metrics = findMetricsForCharacter(metricsList, fragment, startPosition); |
+ |
+ FloatRect extent = physicalGlyphExtents(queryData, *metrics, glyphPosition); |
if (fragment.isTransformed()) { |
AffineTransform fragmentTransform = fragment.buildFragmentTransform(SVGTextFragment::TransformIgnoringTextLength); |
extent = fragmentTransform.mapRect(extent); |
@@ -455,14 +461,6 @@ static inline FloatRect calculateGlyphBoundaries(const QueryData* queryData, con |
return extent; |
} |
-static inline FloatRect calculateFragmentBoundaries(LineLayoutSVGInlineText textLineLayout, const SVGTextFragment& fragment) |
-{ |
- float scalingFactor = textLineLayout.scalingFactor(); |
- ASSERT(scalingFactor); |
- float baseline = textLineLayout.scaledFont().getFontMetrics().floatAscent() / scalingFactor; |
- return fragment.boundingBox(baseline); |
-} |
- |
static bool extentOfCharacterCallback(QueryData* queryData, const SVGTextFragment& fragment) |
{ |
ExtentOfCharacterData* data = static_cast<ExtentOfCharacterData*>(queryData); |
@@ -540,18 +538,27 @@ static bool characterNumberAtPositionCallback(QueryData* queryData, const SVGTex |
{ |
CharacterNumberAtPositionData* data = static_cast<CharacterNumberAtPositionData*>(queryData); |
+ const float scalingFactor = data->textLineLayout.scalingFactor(); |
+ ASSERT(scalingFactor); |
+ const float baseline = data->textLineLayout.scaledFont().getFontMetrics().floatAscent() / scalingFactor; |
+ |
// Test the query point against the bounds of the entire fragment first. |
- FloatRect fragmentExtents = calculateFragmentBoundaries(queryData->textLineLayout, fragment); |
- if (!fragmentExtents.contains(data->position)) |
+ if (!fragment.boundingBox(baseline).contains(data->position)) |
return false; |
+ AffineTransform fragmentTransform = fragment.buildFragmentTransform(SVGTextFragment::TransformIgnoringTextLength); |
+ |
// Iterate through the glyphs in this fragment, and check if their extents |
// contain the query point. |
- const Vector<SVGTextMetrics>& textMetrics = queryData->textLineLayout.layoutAttributes()->textMetricsValues(); |
- unsigned textMetricsOffset = fragment.metricsListOffset; |
+ MetricsList::const_iterator metrics = |
+ data->textLineLayout.layoutAttributes()->textMetricsValues().begin() + fragment.metricsListOffset; |
unsigned fragmentOffset = 0; |
+ float glyphOffset = 0; |
while (fragmentOffset < fragment.length) { |
- FloatRect extent = calculateGlyphBoundaries(queryData, fragment, fragmentOffset); |
+ FloatPoint glyphPosition = logicalGlyphPositionToPhysical(data, fragment, glyphOffset); |
+ glyphPosition.move(0, -baseline); |
+ |
+ FloatRect extent = fragmentTransform.mapRect(physicalGlyphExtents(data, *metrics, glyphPosition)); |
if (extent.contains(data->position)) { |
// Compute the character offset of the glyph within the text node. |
unsigned offsetInBox = fragment.characterOffset - queryData->textBox->start() + fragmentOffset; |
@@ -559,8 +566,9 @@ static bool characterNumberAtPositionCallback(QueryData* queryData, const SVGTex |
data->hitLayoutItem = LineLayoutItem(data->textLineLayout); |
return true; |
} |
- fragmentOffset += textMetrics[textMetricsOffset].length(); |
- textMetricsOffset++; |
+ fragmentOffset += metrics->length(); |
+ glyphOffset += data->isVerticalText ? metrics->height() : metrics->width(); |
+ ++metrics; |
} |
return false; |
} |