diff options
Diffstat (limited to 'Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp')
-rw-r--r-- | Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp | 139 |
1 files changed, 56 insertions, 83 deletions
diff --git a/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp b/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp index aec25e146..0a0c3cd0b 100644 --- a/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp +++ b/Source/WebCore/rendering/svg/SVGTextLayoutEngine.cpp @@ -18,10 +18,9 @@ */ #include "config.h" - -#if ENABLE(SVG) #include "SVGTextLayoutEngine.h" +#include "PathTraversalState.h" #include "RenderSVGTextPath.h" #include "SVGElement.h" #include "SVGInlineTextBox.h" @@ -111,7 +110,7 @@ void SVGTextLayoutEngine::updateRelativePositionAdjustmentsIfNeeded(float dx, fl m_dy = dy; } -void SVGTextLayoutEngine::recordTextFragment(SVGInlineTextBox* textBox, Vector<SVGTextMetrics>& textMetricsValues) +void SVGTextLayoutEngine::recordTextFragment(SVGInlineTextBox& textBox, Vector<SVGTextMetrics>& textMetricsValues) { ASSERT(!m_currentTextFragment.length); ASSERT(m_visualMetricsListOffset > 0); @@ -138,7 +137,7 @@ void SVGTextLayoutEngine::recordTextFragment(SVGInlineTextBox* textBox, Vector<S } } - textBox->textFragments().append(m_currentTextFragment); + textBox.textFragments().append(m_currentTextFragment); m_currentTextFragment = SVGTextFragment(); } @@ -162,58 +161,39 @@ bool SVGTextLayoutEngine::parentDefinesTextLength(RenderObject* parent) const return false; } -void SVGTextLayoutEngine::beginTextPathLayout(RenderObject* object, SVGTextLayoutEngine& lineLayout) +void SVGTextLayoutEngine::beginTextPathLayout(RenderSVGTextPath& textPath, SVGTextLayoutEngine& lineLayout) { - ASSERT(object); - m_inPathLayout = true; - RenderSVGTextPath* textPath = toRenderSVGTextPath(object); - m_textPath = textPath->layoutPath(); + m_textPath = textPath.layoutPath(); if (m_textPath.isEmpty()) return; - m_textPathStartOffset = textPath->startOffset(); + + m_textPathStartOffset = textPath.startOffset(); m_textPathLength = m_textPath.length(); if (m_textPathStartOffset > 0 && m_textPathStartOffset <= 1) m_textPathStartOffset *= m_textPathLength; - float totalLength = 0; - unsigned totalCharacters = 0; - lineLayout.m_chunkLayoutBuilder.buildTextChunks(lineLayout.m_lineLayoutBoxes); - const Vector<SVGTextChunk>& textChunks = lineLayout.m_chunkLayoutBuilder.textChunks(); - - unsigned size = textChunks.size(); - for (unsigned i = 0; i < size; ++i) { - const SVGTextChunk& chunk = textChunks.at(i); - - float length = 0; - unsigned characters = 0; - chunk.calculateLength(length, characters); - - // Handle text-anchor as additional start offset for text paths. - m_textPathStartOffset += chunk.calculateTextAnchorShift(length); - - totalLength += length; - totalCharacters += characters; - } + // Handle text-anchor as additional start offset for text paths. + m_textPathStartOffset += lineLayout.m_chunkLayoutBuilder.totalAnchorShift(); m_textPathCurrentOffset = m_textPathStartOffset; // Eventually handle textLength adjustments. - SVGLengthAdjustType lengthAdjust = SVGLengthAdjustUnknown; - float desiredTextLength = 0; - - if (SVGTextContentElement* textContentElement = SVGTextContentElement::elementFromRenderer(textPath)) { - SVGLengthContext lengthContext(textContentElement); - lengthAdjust = textContentElement->lengthAdjust(); - desiredTextLength = textContentElement->specifiedTextLength().value(lengthContext); - } + auto* textContentElement = SVGTextContentElement::elementFromRenderer(&textPath); + if (!textContentElement) + return; + SVGLengthContext lengthContext(textContentElement); + float desiredTextLength = textContentElement->specifiedTextLength().value(lengthContext); if (!desiredTextLength) return; - if (lengthAdjust == SVGLengthAdjustSpacing) + float totalLength = lineLayout.m_chunkLayoutBuilder.totalLength(); + unsigned totalCharacters = lineLayout.m_chunkLayoutBuilder.totalCharacters(); + + if (textContentElement->lengthAdjust() == SVGLengthAdjustSpacing) m_textPathSpacing = (desiredTextLength - totalLength) / totalCharacters; else m_textPathScaling = desiredTextLength / totalLength; @@ -230,27 +210,25 @@ void SVGTextLayoutEngine::endTextPathLayout() m_textPathScaling = 1; } -void SVGTextLayoutEngine::layoutInlineTextBox(SVGInlineTextBox* textBox) +void SVGTextLayoutEngine::layoutInlineTextBox(SVGInlineTextBox& textBox) { - ASSERT(textBox); - - RenderSVGInlineText& text = textBox->renderer(); + RenderSVGInlineText& text = textBox.renderer(); ASSERT(text.parent()); ASSERT(text.parent()->element()); ASSERT(text.parent()->element()->isSVGElement()); const RenderStyle& style = text.style(); - textBox->clearTextFragments(); - m_isVerticalText = style.svgStyle().isVerticalWritingMode(); - layoutTextOnLineOrPath(textBox, &text, &style); + textBox.clearTextFragments(); + m_isVerticalText = style.isVerticalWritingMode(); + layoutTextOnLineOrPath(textBox, text, style); if (m_inPathLayout) { - m_pathLayoutBoxes.append(textBox); + m_pathLayoutBoxes.append(&textBox); return; } - m_lineLayoutBoxes.append(textBox); + m_lineLayoutBoxes.append(&textBox); } #if DUMP_TEXT_FRAGMENTS > 0 @@ -292,7 +270,7 @@ void SVGTextLayoutEngine::finalizeTransformMatrices(Vector<SVGInlineTextBox*>& b unsigned fragmentCount = fragments.size(); for (unsigned i = 0; i < fragmentCount; ++i) { - m_chunkLayoutBuilder.transformationForTextBox(textBox, textBoxTransformation); + textBoxTransformation = m_chunkLayoutBuilder.transformationForTextBox(textBox); if (textBoxTransformation.isIdentity()) continue; ASSERT(fragments[i].lengthAdjustTransform.isIdentity()); @@ -380,12 +358,12 @@ bool SVGTextLayoutEngine::currentLogicalCharacterMetrics(SVGTextLayoutAttributes return true; } -bool SVGTextLayoutEngine::currentVisualCharacterMetrics(SVGInlineTextBox* textBox, Vector<SVGTextMetrics>& visualMetricsValues, SVGTextMetrics& visualMetrics) +bool SVGTextLayoutEngine::currentVisualCharacterMetrics(const SVGInlineTextBox& textBox, Vector<SVGTextMetrics>& visualMetricsValues, SVGTextMetrics& visualMetrics) { ASSERT(!visualMetricsValues.isEmpty()); unsigned textMetricsSize = visualMetricsValues.size(); - unsigned boxStart = textBox->start(); - unsigned boxLength = textBox->len(); + unsigned boxStart = textBox.start(); + unsigned boxLength = textBox.len(); if (m_visualMetricsListOffset == textMetricsSize) return false; @@ -420,26 +398,28 @@ void SVGTextLayoutEngine::advanceToNextVisualCharacter(const SVGTextMetrics& vis m_visualCharacterOffset += visualMetrics.length(); } -void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, RenderSVGInlineText* text, const RenderStyle* style) +void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox& textBox, RenderSVGInlineText& text, const RenderStyle& style) { if (m_inPathLayout && m_textPath.isEmpty()) return; - SVGElement* lengthContext = toSVGElement(text->parent()->element()); + RenderElement* textParent = text.parent(); + ASSERT(textParent); + SVGElement* lengthContext = downcast<SVGElement>(textParent->element()); - RenderObject* textParent = text->parent(); - bool definesTextLength = textParent ? parentDefinesTextLength(textParent) : false; + bool definesTextLength = parentDefinesTextLength(textParent); - const SVGRenderStyle& svgStyle = style->svgStyle(); + const SVGRenderStyle& svgStyle = style.svgStyle(); m_visualMetricsListOffset = 0; m_visualCharacterOffset = 0; - Vector<SVGTextMetrics>& visualMetricsValues = text->layoutAttributes()->textMetricsValues(); + Vector<SVGTextMetrics>& visualMetricsValues = text.layoutAttributes()->textMetricsValues(); ASSERT(!visualMetricsValues.isEmpty()); - const UChar* characters = text->deprecatedCharacters(); - const Font& font = style->font(); + auto upconvertedCharacters = StringView(text.text()).upconvertedCharacters(); + const UChar* characters = upconvertedCharacters; + const FontCascade& font = style.fontCascade(); SVGTextLayoutEngineSpacing spacingLayout(font); SVGTextLayoutEngineBaseline baselineLayout(font); @@ -448,7 +428,7 @@ void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, Rend bool applySpacingToNextCharacter = false; float lastAngle = 0; - float baselineShift = baselineLayout.calculateBaselineShift(&svgStyle, lengthContext); + float baselineShift = baselineLayout.calculateBaselineShift(svgStyle, lengthContext); baselineShift -= baselineLayout.calculateAlignmentBaselineShift(m_isVerticalText, text); // Main layout algorithm. @@ -481,16 +461,16 @@ void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, Rend float x = data.x; float y = data.y; - // When we've advanced to the box start offset, determine using the original x/y values, - // whether this character starts a new text chunk, before doing any further processing. - if (m_visualCharacterOffset == textBox->start()) - textBox->setStartsNewTextChunk(logicalAttributes->context().characterStartsNewTextChunk(m_logicalCharacterOffset)); + // When we've advanced to the box start offset, determine using the original x/y values + // whether this character starts a new text chunk before doing any further processing. + if (m_visualCharacterOffset == textBox.start()) + textBox.setStartsNewTextChunk(logicalAttributes->context().characterStartsNewTextChunk(m_logicalCharacterOffset)); float angle = data.rotate == SVGTextLayoutAttributes::emptyValue() ? 0 : data.rotate; // Calculate glyph orientation angle. const UChar* currentCharacter = characters + m_visualCharacterOffset; - float orientationAngle = baselineLayout.calculateGlyphOrientationAngle(m_isVerticalText, &svgStyle, *currentCharacter); + float orientationAngle = baselineLayout.calculateGlyphOrientationAngle(m_isVerticalText, svgStyle, *currentCharacter); // Calculate glyph advance & x/y orientation shifts. float xOrientationShift = 0; @@ -503,9 +483,6 @@ void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, Rend // Apply dx/dy value adjustments to current text position, if needed. updateRelativePositionAdjustmentsIfNeeded(data.dx, data.dy); - // Calculate SVG Fonts kerning, if needed. - float kerning = spacingLayout.calculateSVGKerning(m_isVerticalText, visualMetrics.glyph()); - // Calculate CSS 'kerning', 'letter-spacing' and 'word-spacing' for next character, if needed. float spacing = spacingLayout.calculateCSSKerningAndSpacing(&svgStyle, lengthContext, currentCharacter); @@ -517,7 +494,7 @@ void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, Rend if (y != SVGTextLayoutAttributes::emptyValue()) m_textPathCurrentOffset = y + m_textPathStartOffset; - m_textPathCurrentOffset += m_dy - kerning; + m_textPathCurrentOffset += m_dy; m_dy = 0; // Apply dx/dy correction and setup translations that move to the glyph midpoint. @@ -528,7 +505,7 @@ void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, Rend if (x != SVGTextLayoutAttributes::emptyValue()) m_textPathCurrentOffset = x + m_textPathStartOffset; - m_textPathCurrentOffset += m_dx - kerning; + m_textPathCurrentOffset += m_dx; m_dx = 0; // Apply dx/dy correction and setup translations that move to the glyph midpoint. @@ -553,27 +530,25 @@ void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, Rend if (textPathOffset > m_textPathLength) break; - bool ok = false; - FloatPoint point = m_textPath.pointAtLength(textPathOffset, ok); - ASSERT(ok); + bool success = false; + auto traversalState(m_textPath.traversalStateAtLength(textPathOffset, success)); + ASSERT(success); + FloatPoint point = traversalState.current(); x = point.x(); y = point.y(); - angle = m_textPath.normalAngleAtLength(textPathOffset, ok); - ASSERT(ok); + + angle = traversalState.normalAngle(); // For vertical text on path, the actual angle has to be rotated 90 degrees anti-clockwise, not the orientation angle! if (m_isVerticalText) angle -= 90; } else { // Apply all previously calculated shift values. - if (m_isVerticalText) { + if (m_isVerticalText) x += baselineShift; - y -= kerning; - } else { - x -= kerning; + else y -= baselineShift; - } x += m_dx; y += m_dy; @@ -581,7 +556,7 @@ void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, Rend // Determine whether we have to start a new fragment. bool shouldStartNewFragment = m_dx || m_dy || m_isVerticalText || m_inPathLayout || angle || angle != lastAngle - || orientationAngle || kerning || applySpacingToNextCharacter || definesTextLength; + || orientationAngle || applySpacingToNextCharacter || definesTextLength; // If we already started a fragment, close it now. if (didStartTextFragment && shouldStartNewFragment) { @@ -651,5 +626,3 @@ void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, Rend } } - -#endif // ENABLE(SVG) |