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; }
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; }
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); }
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; }
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); } }
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; }
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; } } }