本文整理汇总了C++中SVGTextLayoutAttributes类的典型用法代码示例。如果您正苦于以下问题:C++ SVGTextLayoutAttributes类的具体用法?C++ SVGTextLayoutAttributes怎么用?C++ SVGTextLayoutAttributes使用的例子?那么, 这里精选的类代码示例或许可以为您提供帮助。
在下文中一共展示了SVGTextLayoutAttributes类的14个代码示例,这些例子默认根据受欢迎程度排序。您可以为喜欢或者感觉有用的代码点赞,您的评价将有助于系统推荐出更棒的C++代码示例。
示例1: currentLogicalCharacterMetrics
bool SVGTextLayoutEngine::currentLogicalCharacterMetrics(SVGTextLayoutAttributes& logicalAttributes, SVGTextMetrics& logicalMetrics)
{
logicalMetrics = SVGTextMetrics::emptyMetrics();
Vector<SVGTextMetrics>& textMetricsValues = logicalAttributes.textMetricsValues();
unsigned textMetricsSize = textMetricsValues.size();
while (true) {
if (m_logicalMetricsListOffset == textMetricsSize) {
if (!currentLogicalCharacterAttributes(logicalAttributes))
return false;
textMetricsValues = logicalAttributes.textMetricsValues();
textMetricsSize = textMetricsValues.size();
continue;
}
ASSERT(textMetricsSize);
ASSERT(m_logicalMetricsListOffset < textMetricsSize);
logicalMetrics = textMetricsValues.at(m_logicalMetricsListOffset);
if (logicalMetrics == SVGTextMetrics::emptyMetrics() || (!logicalMetrics.width() && !logicalMetrics.height())) {
advanceToNextLogicalCharacter(logicalMetrics);
continue;
}
// Stop if we found the next valid logical text metrics object.
return true;
}
ASSERT_NOT_REACHED();
return true;
}
示例2: modifyStartEndPositionsRespectingLigatures
void SVGTextQuery::modifyStartEndPositionsRespectingLigatures(Data* queryData, const SVGTextFragment& fragment, int& startPosition, int& endPosition) const
{
SVGTextLayoutAttributes* layoutAttributes = queryData->textRenderer->layoutAttributes();
Vector<SVGTextMetrics>& textMetricsValues = layoutAttributes->textMetricsValues();
unsigned textMetricsOffset = fragment.metricsListOffset;
// Compute the offset of the fragment within the box, since that's the
// space <startPosition, endPosition> is in (and that's what we need).
int fragmentOffsetInBox = fragment.characterOffset - queryData->textBox->start();
int fragmentEndInBox = fragmentOffsetInBox + fragment.length;
// Find the text metrics cell that start at or contain the character startPosition.
while (fragmentOffsetInBox < fragmentEndInBox) {
SVGTextMetrics& metrics = textMetricsValues[textMetricsOffset];
int glyphEnd = fragmentOffsetInBox + metrics.length();
if (startPosition < glyphEnd)
break;
fragmentOffsetInBox = glyphEnd;
textMetricsOffset++;
}
startPosition = fragmentOffsetInBox;
// Find the text metrics cell that contain or ends at the character endPosition.
while (fragmentOffsetInBox < fragmentEndInBox) {
SVGTextMetrics& metrics = textMetricsValues[textMetricsOffset];
fragmentOffsetInBox += metrics.length();
if (fragmentOffsetInBox >= endPosition)
break;
textMetricsOffset++;
}
endPosition = fragmentOffsetInBox;
}
示例3: assignEmptyLayoutAttributesForCharacter
void SVGTextLayoutAttributesBuilder::assignEmptyLayoutAttributesForCharacter(SVGTextLayoutAttributes& attributes) const
{
attributes.xValues().append(SVGTextLayoutAttributes::emptyValue());
attributes.yValues().append(SVGTextLayoutAttributes::emptyValue());
attributes.dxValues().append(SVGTextLayoutAttributes::emptyValue());
attributes.dyValues().append(SVGTextLayoutAttributes::emptyValue());
attributes.rotateValues().append(SVGTextLayoutAttributes::emptyValue());
// This doesn't add an empty value to textMetricsValues() on purpose!
}
示例4: measureTextRenderer
static void measureTextRenderer(RenderSVGInlineText* text, MeasureTextData* data, bool processRenderer)
{
ASSERT(text);
SVGTextLayoutAttributes* attributes = text->layoutAttributes();
Vector<SVGTextMetrics>* textMetricsValues = &attributes->textMetricsValues();
if (processRenderer) {
if (data->allCharactersMap)
attributes->clear();
else
textMetricsValues->clear();
}
SVGTextMetricsCalculator calculator(text);
bool preserveWhiteSpace = text->style()->whiteSpace() == PRE;
unsigned surrogatePairCharacters = 0;
unsigned skippedCharacters = 0;
unsigned textPosition = 0;
unsigned textLength = calculator.textLength();
SVGTextMetrics currentMetrics;
for (; textPosition < textLength; textPosition += currentMetrics.length()) {
currentMetrics = calculator.computeMetricsForCharacter(textPosition);
if (!currentMetrics.length())
break;
bool characterIsWhiteSpace = calculator.characterIsWhiteSpace(textPosition);
if (characterIsWhiteSpace && !preserveWhiteSpace && data->lastCharacterWasWhiteSpace) {
if (processRenderer)
textMetricsValues->append(SVGTextMetrics(SVGTextMetrics::SkippedSpaceMetrics));
if (data->allCharactersMap)
skippedCharacters += currentMetrics.length();
continue;
}
if (processRenderer) {
if (data->allCharactersMap) {
const SVGCharacterDataMap::const_iterator it = data->allCharactersMap->find(data->valueListPosition + textPosition - skippedCharacters - surrogatePairCharacters + 1);
if (it != data->allCharactersMap->end())
attributes->characterDataMap().set(textPosition + 1, it->value);
}
textMetricsValues->append(currentMetrics);
}
if (data->allCharactersMap && calculator.characterStartsSurrogatePair(textPosition))
surrogatePairCharacters++;
data->lastCharacterWasWhiteSpace = characterIsWhiteSpace;
}
if (!data->allCharactersMap)
return;
data->valueListPosition += textPosition - skippedCharacters;
}
示例5: toRenderSVGInlineText
void SVGTextLayoutAttributesBuilder::propagateLayoutAttributes(RenderObject* start, unsigned& atCharacter, UChar& lastCharacter) const
{
for (RenderObject* child = start->firstChild(); child; child = child->nextSibling()) {
if (child->isSVGInlineText()) {
RenderSVGInlineText* text = toRenderSVGInlineText(child);
const UChar* characters = text->characters();
unsigned textLength = text->textLength();
bool preserveWhiteSpace = shouldPreserveAllWhiteSpace(text->style());
SVGTextLayoutAttributes attributes;
attributes.reserveCapacity(textLength);
unsigned valueListPosition = atCharacter;
unsigned metricsLength = 1;
for (unsigned textPosition = 0; textPosition < textLength; textPosition += metricsLength) {
const UChar& currentCharacter = characters[textPosition];
SVGTextMetrics metrics = SVGTextMetrics::measureCharacterRange(text, textPosition, 1);
metricsLength = metrics.length();
if (!preserveWhiteSpace && characterIsSpace(currentCharacter) && characterIsSpaceOrNull(lastCharacter)) {
assignEmptyLayoutAttributesForCharacter(attributes);
attributes.textMetricsValues().append(SVGTextMetrics::emptyMetrics());
continue;
}
assignLayoutAttributesForCharacter(attributes, metrics, valueListPosition);
if (metricsLength > 1) {
for (unsigned i = 0; i < metricsLength - 1; ++i)
assignEmptyLayoutAttributesForCharacter(attributes);
}
lastCharacter = currentCharacter;
valueListPosition += metricsLength;
}
#if DUMP_TEXT_LAYOUT_ATTRIBUTES > 0
fprintf(stderr, "\nDumping layout attributes for RenderSVGInlineText, renderer=%p, node=%p (atCharacter: %i)\n", text, text->node(), atCharacter);
attributes.dump();
#endif
text->storeLayoutAttributes(attributes);
atCharacter = valueListPosition;
continue;
}
if (!child->isSVGInline())
continue;
propagateLayoutAttributes(child, atCharacter, lastCharacter);
}
}
示例6: ASSERT
void SVGTextMetricsBuilder::measureTextRenderer(RenderSVGInlineText* text, MeasureTextData* data)
{
ASSERT(text);
SVGTextLayoutAttributes* attributes = text->layoutAttributes();
Vector<SVGTextMetrics>* textMetricsValues = &attributes->textMetricsValues();
if (data->processRenderer) {
if (data->allCharactersMap)
attributes->clear();
else
textMetricsValues->clear();
}
initializeMeasurementWithTextRenderer(text);
bool preserveWhiteSpace = text->style()->whiteSpace() == PRE;
int surrogatePairCharacters = 0;
while (advance()) {
const UChar* currentCharacter = m_run.data16(m_textPosition);
if (*currentCharacter == ' ' && !preserveWhiteSpace && (!data->lastCharacter || *data->lastCharacter == ' ')) {
if (data->processRenderer)
textMetricsValues->append(SVGTextMetrics(SVGTextMetrics::SkippedSpaceMetrics));
if (data->allCharactersMap)
data->skippedCharacters += m_currentMetrics.length();
continue;
}
if (data->processRenderer) {
if (data->allCharactersMap) {
const SVGCharacterDataMap::const_iterator it = data->allCharactersMap->find(data->valueListPosition + m_textPosition - data->skippedCharacters - surrogatePairCharacters + 1);
if (it != data->allCharactersMap->end())
attributes->characterDataMap().set(m_textPosition + 1, it->value);
}
textMetricsValues->append(m_currentMetrics);
}
if (data->allCharactersMap && currentCharacterStartsSurrogatePair())
surrogatePairCharacters++;
data->lastCharacter = currentCharacter;
}
if (!data->allCharactersMap)
return;
data->valueListPosition += m_textPosition - data->skippedCharacters;
data->skippedCharacters = 0;
}
示例7: ASSERT
void RenderSVGText::subtreeChildWasAdded(RenderObject* child)
{
ASSERT(child);
if (!shouldHandleSubtreeMutations() || documentBeingDestroyed())
return;
// Always protect the cache before clearing text positioning elements when the cache will subsequently be rebuilt.
FontCachePurgePreventer fontCachePurgePreventer;
// The positioning elements cache doesn't include the new 'child' yet. Clear the
// cache, as the next buildLayoutAttributesForTextRenderer() call rebuilds it.
m_layoutAttributesBuilder.clearTextPositioningElements();
if (!child->isSVGInlineText() && !child->isSVGInline())
return;
// Detect changes in layout attributes and only measure those text parts that have changed!
Vector<SVGTextLayoutAttributes*> newLayoutAttributes;
collectLayoutAttributes(this, newLayoutAttributes);
if (newLayoutAttributes.isEmpty()) {
ASSERT(m_layoutAttributes.isEmpty());
return;
}
// Compare m_layoutAttributes with newLayoutAttributes to figure out which attribute got added.
size_t size = newLayoutAttributes.size();
SVGTextLayoutAttributes* attributes = 0;
for (size_t i = 0; i < size; ++i) {
attributes = newLayoutAttributes[i];
if (m_layoutAttributes.find(attributes) == notFound) {
// Every time this is invoked, there's only a single new entry in the newLayoutAttributes list, compared to the old in m_layoutAttributes.
bool stopAfterNext = false;
SVGTextLayoutAttributes* previous = 0;
SVGTextLayoutAttributes* next = 0;
ASSERT_UNUSED(child, &attributes->context() == child);
findPreviousAndNextAttributes(this, &attributes->context(), stopAfterNext, previous, next);
if (previous)
m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(previous->context());
m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(attributes->context());
if (next)
m_layoutAttributesBuilder.buildLayoutAttributesForTextRenderer(next->context());
break;
}
}
#ifndef NDEBUG
// Verify that m_layoutAttributes only differs by a maximum of one entry.
for (size_t i = 0; i < size; ++i)
ASSERT(m_layoutAttributes.find(newLayoutAttributes[i]) != notFound || newLayoutAttributes[i] == attributes);
#endif
m_layoutAttributes = newLayoutAttributes;
}
示例8: findFirstAndLastAttributesInVector
static inline void findFirstAndLastAttributesInVector(Vector<SVGTextLayoutAttributes*>& attributes, RenderSVGInlineText* firstContext, RenderSVGInlineText* lastContext,
SVGTextLayoutAttributes*& first, SVGTextLayoutAttributes*& last)
{
first = 0;
last = 0;
unsigned attributesSize = attributes.size();
for (unsigned i = 0; i < attributesSize; ++i) {
SVGTextLayoutAttributes* current = attributes[i];
if (!first && firstContext == ¤t->context())
first = current;
if (!last && lastContext == ¤t->context())
last = current;
if (first && last)
break;
}
ASSERT(first);
ASSERT(last);
}
示例9: assignLayoutAttributesForCharacter
void SVGTextLayoutAttributesBuilder::assignLayoutAttributesForCharacter(SVGTextLayoutAttributes& attributes, SVGTextMetrics& metrics, unsigned valueListPosition) const
{
attributes.xValues().append(nextLayoutValue(XValueAttribute, valueListPosition));
attributes.yValues().append(nextLayoutValue(YValueAttribute, valueListPosition));
attributes.dxValues().append(nextLayoutValue(DxValueAttribute, valueListPosition));
attributes.dyValues().append(nextLayoutValue(DyValueAttribute, valueListPosition));
attributes.rotateValues().append(nextLayoutValue(RotateValueAttribute, valueListPosition));
attributes.textMetricsValues().append(metrics);
}
示例10: recursiveCollectLayoutAttributes
void RenderSVGText::rebuildLayoutAttributes(Vector<SVGTextLayoutAttributes*>& affectedAttributes)
{
// Detect changes in layout attributes and only measure those text parts that have changed!
Vector<SVGTextLayoutAttributes*> newLayoutAttributes;
recursiveCollectLayoutAttributes(this, newLayoutAttributes);
if (newLayoutAttributes.isEmpty()) {
m_layoutAttributes.clear();
return;
}
// Compare m_layoutAttributes with newLayoutAttributes to figure out which attributes got added/removed.
size_t size = newLayoutAttributes.size();
for (size_t i = 0; i < size; ++i) {
SVGTextLayoutAttributes* attributes = newLayoutAttributes[i];
if (m_layoutAttributes.find(attributes) == notFound)
m_layoutAttributesBuilder.rebuildMetricsForTextRenderer(attributes->context());
}
size = affectedAttributes.size();
for (size_t i = 0; i < size; ++i)
m_layoutAttributesBuilder.rebuildMetricsForTextRenderer(affectedAttributes[i]->context());
m_layoutAttributes = newLayoutAttributes;
}
示例11: currentLogicalCharacterAttributes
bool SVGTextLayoutEngine::currentLogicalCharacterAttributes(SVGTextLayoutAttributes& logicalAttributes)
{
if (m_layoutAttributes.isEmpty())
return false;
logicalAttributes = m_layoutAttributes.first();
if (m_logicalCharacterOffset != logicalAttributes.xValues().size())
return true;
m_layoutAttributes.remove(0);
if (m_layoutAttributes.isEmpty())
return false;
logicalAttributes = m_layoutAttributes.first();
m_logicalMetricsListOffset = 0;
m_logicalCharacterOffset = 0;
return true;
}
示例12: spacingLayout
void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, LineLayoutSVGInlineText textLineLayout, const ComputedStyle& style)
{
if (m_inPathLayout && !m_textPathCalculator)
return;
// Find the start of the current text box in the metrics list.
m_visualMetricsIterator.advanceToTextStart(&textLineLayout, textBox->start());
const Font& font = style.font();
SVGTextLayoutEngineSpacing spacingLayout(font, style.effectiveZoom());
SVGTextLayoutEngineBaseline baselineLayout(font, style.effectiveZoom());
bool didStartTextFragment = false;
bool applySpacingToNextCharacter = false;
float lastAngle = 0;
float baselineShift = baselineLayout.calculateBaselineShift(style);
baselineShift -= baselineLayout.calculateAlignmentBaselineShift(m_isVerticalText, textLineLayout);
// Main layout algorithm.
const unsigned boxEndOffset = textBox->start() + textBox->len();
while (!m_visualMetricsIterator.isAtEnd() && m_visualMetricsIterator.characterOffset() < boxEndOffset) {
const SVGTextMetrics& visualMetrics = m_visualMetricsIterator.metrics();
if (visualMetrics.isEmpty()) {
m_visualMetricsIterator.next();
continue;
}
SVGTextLayoutAttributes* logicalAttributes = nullptr;
if (!currentLogicalCharacterAttributes(logicalAttributes))
break;
ASSERT(logicalAttributes);
SVGTextMetrics logicalMetrics(SVGTextMetrics::SkippedSpaceMetrics);
if (!currentLogicalCharacterMetrics(logicalAttributes, logicalMetrics))
break;
SVGCharacterDataMap& characterDataMap = logicalAttributes->characterDataMap();
SVGCharacterData data;
SVGCharacterDataMap::iterator it = characterDataMap.find(m_logicalCharacterOffset + 1);
if (it != characterDataMap.end())
data = it->value;
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_visualMetricsIterator.characterOffset() == textBox->start())
textBox->setStartsNewTextChunk(logicalAttributes->context()->characterStartsNewTextChunk(m_logicalCharacterOffset));
float angle = SVGTextLayoutAttributes::isEmptyValue(data.rotate) ? 0 : data.rotate;
// Calculate glyph orientation angle.
// Font::width() calculates the resolved FontOrientation for each character,
// but is not exposed today to avoid the API complexity.
UChar32 currentCharacter = textLineLayout.codepointAt(m_visualMetricsIterator.characterOffset());
FontOrientation fontOrientation = font.fontDescription().orientation();
fontOrientation = adjustOrientationForCharacterInMixedVertical(fontOrientation, currentCharacter);
// Calculate glyph advance.
// Shaping engine takes care of x/y orientation shifts for different fontOrientation values.
float glyphAdvance = visualMetrics.advance(fontOrientation);
// Assign current text position to x/y values, if needed.
updateCharacterPositionIfNeeded(x, y);
// Apply dx/dy value adjustments to current text position, if needed.
updateRelativePositionAdjustmentsIfNeeded(data.dx, data.dy);
// Calculate CSS 'letter-spacing' and 'word-spacing' for next character, if needed.
float spacing = spacingLayout.calculateCSSSpacing(currentCharacter);
float textPathOffset = 0;
float textPathShiftX = 0;
float textPathShiftY = 0;
if (m_inPathLayout) {
float scaledGlyphAdvance = glyphAdvance * m_textPathScaling;
if (m_isVerticalText) {
// If there's an absolute y position available, it marks the beginning of a new position along the path.
if (!SVGTextLayoutAttributes::isEmptyValue(y))
m_textPathCurrentOffset = y + m_textPathStartOffset;
m_textPathCurrentOffset += m_dy;
m_dy = 0;
// Apply dx/dy correction and setup translations that move to the glyph midpoint.
textPathShiftX += m_dx + baselineShift;
textPathShiftY -= scaledGlyphAdvance / 2;
} else {
// If there's an absolute x position available, it marks the beginning of a new position along the path.
if (!SVGTextLayoutAttributes::isEmptyValue(x))
m_textPathCurrentOffset = x + m_textPathStartOffset;
m_textPathCurrentOffset += m_dx;
m_dx = 0;
// Apply dx/dy correction and setup translations that move to the glyph midpoint.
textPathShiftX -= scaledGlyphAdvance / 2;
//.........这里部分代码省略.........
示例13: parentDefinesTextLength
void SVGTextLayoutEngine::layoutTextOnLineOrPath(SVGInlineTextBox* textBox, RenderSVGInlineText* text, const RenderStyle* style)
{
SVGElement* lengthContext = static_cast<SVGElement*>(text->parent()->node());
RenderObject* textParent = text->parent();
bool definesTextLength = textParent ? parentDefinesTextLength(textParent) : false;
const SVGRenderStyle* svgStyle = style->svgStyle();
ASSERT(svgStyle);
m_visualMetricsListOffset = 0;
m_visualCharacterOffset = 0;
Vector<SVGTextMetrics>& textMetricsValues = text->layoutAttributes().textMetricsValues();
const UChar* characters = text->characters();
const Font& font = style->font();
SVGTextLayoutEngineSpacing spacingLayout(font);
SVGTextLayoutEngineBaseline baselineLayout(font);
bool didStartTextFragment = false;
bool applySpacingToNextCharacter = false;
float lastAngle = 0;
float baselineShift = baselineLayout.calculateBaselineShift(svgStyle, lengthContext);
baselineShift -= baselineLayout.calculateAlignmentBaselineShift(m_isVerticalText, text);
// Main layout algorithm.
while (true) {
// Find the start of the current text box in this list, respecting ligatures.
SVGTextMetrics visualMetrics = SVGTextMetrics::emptyMetrics();
if (!currentVisualCharacterMetrics(textBox, text, visualMetrics))
break;
if (visualMetrics == SVGTextMetrics::emptyMetrics()) {
advanceToNextVisualCharacter(visualMetrics);
continue;
}
SVGTextLayoutAttributes logicalAttributes;
if (!currentLogicalCharacterAttributes(logicalAttributes))
break;
SVGTextMetrics logicalMetrics = SVGTextMetrics::emptyMetrics();
if (!currentLogicalCharacterMetrics(logicalAttributes, logicalMetrics))
break;
Vector<float>& xValues = logicalAttributes.xValues();
Vector<float>& yValues = logicalAttributes.yValues();
Vector<float>& dxValues = logicalAttributes.dxValues();
Vector<float>& dyValues = logicalAttributes.dyValues();
Vector<float>& rotateValues = logicalAttributes.rotateValues();
float x = xValues.at(m_logicalCharacterOffset);
float y = yValues.at(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 = 0;
if (!rotateValues.isEmpty()) {
float newAngle = rotateValues.at(m_logicalCharacterOffset);
if (newAngle != SVGTextLayoutAttributes::emptyValue())
angle = newAngle;
}
// Calculate glyph orientation angle.
const UChar* currentCharacter = characters + m_visualCharacterOffset;
float orientationAngle = baselineLayout.calculateGlyphOrientationAngle(m_isVerticalText, svgStyle, *currentCharacter);
// Calculate glyph advance & x/y orientation shifts.
float xOrientationShift = 0;
float yOrientationShift = 0;
float glyphAdvance = baselineLayout.calculateGlyphAdvanceAndOrientation(m_isVerticalText, visualMetrics, orientationAngle, xOrientationShift, yOrientationShift);
// Assign current text position to x/y values, if needed.
updateCharacerPositionIfNeeded(x, y);
// Apply dx/dy value adjustments to current text position, if needed.
updateRelativePositionAdjustmentsIfNeeded(dxValues, dyValues);
// 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);
float textPathOffset = 0;
if (m_inPathLayout) {
float scaledGlyphAdvance = glyphAdvance * m_textPathScaling;
if (m_isVerticalText) {
// If there's an absolute y position available, it marks the beginning of a new position along the path.
if (y != SVGTextLayoutAttributes::emptyValue())
m_textPathCurrentOffset = y + m_textPathStartOffset;
m_textPathCurrentOffset += m_dy - kerning;
m_dy = 0;
//.........这里部分代码省略.........
示例14: modifyStartEndPositionsRespectingLigatures
void SVGTextQuery::modifyStartEndPositionsRespectingLigatures(Data* queryData, int& startPosition, int& 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()->textLength();
bool alterStartPosition = true;
bool alterEndPosition = true;
int lastPositionOffset = -1;
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 == static_cast<int>(positionOffset))
alterStartPosition = false;
// If the start position maps to a character in the metrics list, we don't need to modify it.
if (endPosition == static_cast<int>(positionOffset))
alterEndPosition = false;
// Detect ligatures.
if (lastPositionOffset != -1 && lastPositionOffset - positionOffset > 1) {
if (alterStartPosition && startPosition > lastPositionOffset && startPosition < static_cast<int>(positionOffset)) {
startPosition = lastPositionOffset;
alterStartPosition = false;
}
if (alterEndPosition && endPosition > lastPositionOffset && endPosition < static_cast<int>(positionOffset)) {
endPosition = positionOffset;
alterEndPosition = false;
}
}
if (!alterStartPosition && !alterEndPosition)
break;
lastPositionOffset = positionOffset;
positionOffset += metrics.length();
}
if (!alterStartPosition && !alterEndPosition)
return;
if (lastPositionOffset != -1 && lastPositionOffset - positionOffset > 1) {
if (alterStartPosition && startPosition > lastPositionOffset && startPosition < static_cast<int>(positionOffset)) {
startPosition = lastPositionOffset;
alterStartPosition = false;
}
if (alterEndPosition && endPosition > lastPositionOffset && endPosition < static_cast<int>(positionOffset)) {
endPosition = positionOffset;
alterEndPosition = false;
}
}
}