void walk(const TextRun& run, bool isVerticalText, const String& language, int from, int to) { // Should hold true for SVG text, otherwhise sth. is wrong ASSERT(to - from == run.length()); Vector<SVGGlyphIdentifier::ArabicForm> chars(charactersWithArabicForm(String(run.data(from), run.length()), run.rtl())); SVGGlyphIdentifier identifier; bool foundGlyph = false; int characterLookupRange; int endOfScanRange = to + m_walkerData.extraCharsAvailable; bool haveAltGlyph = false; SVGGlyphIdentifier altGlyphIdentifier; if (RenderObject* renderObject = run.referencingRenderObject()) { if (renderObject->element() && renderObject->element()->hasTagName(SVGNames::altGlyphTag)) { SVGGlyphElement* glyphElement = static_cast<SVGAltGlyphElement*>(renderObject->element())->glyphElement(); if (glyphElement) { haveAltGlyph = true; altGlyphIdentifier = glyphElement->buildGlyphIdentifier(); altGlyphIdentifier.isValid = true; altGlyphIdentifier.nameLength = to - from; } } } for (int i = from; i < to; ++i) { // If characterLookupRange is > 0, then the font defined ligatures (length of unicode property value > 1). // We have to check wheter the current character & the next character define a ligature. This needs to be // extended to the n-th next character (where n is 'characterLookupRange'), to check for any possible ligature. characterLookupRange = endOfScanRange - i; String lookupString(run.data(i), characterLookupRange); Vector<SVGGlyphIdentifier> glyphs; if (haveAltGlyph) glyphs.append(altGlyphIdentifier); else m_fontElement->getGlyphIdentifiersForString(lookupString, glyphs); Vector<SVGGlyphIdentifier>::iterator it = glyphs.begin(); Vector<SVGGlyphIdentifier>::iterator end = glyphs.end(); for (; it != end; ++it) { identifier = *it; if (identifier.isValid && isCompatibleGlyph(identifier, isVerticalText, language, chars, i, i + identifier.nameLength)) { ASSERT(characterLookupRange > 0); i += identifier.nameLength - 1; m_walkerData.charsConsumed += identifier.nameLength; m_walkerData.glyphName = identifier.glyphName; foundGlyph = true; SVGGlyphElement::inheritUnspecifiedAttributes(identifier, m_fontData); break; } } if (!foundGlyph) { ++m_walkerData.charsConsumed; if (SVGMissingGlyphElement* element = m_fontElement->firstMissingGlyphElement()) { // <missing-glyph> element support identifier = SVGGlyphElement::buildGenericGlyphIdentifier(element); SVGGlyphElement::inheritUnspecifiedAttributes(identifier, m_fontData); identifier.isValid = true; } else { // Fallback to system font fallback TextRun subRun(run); subRun.setText(subRun.data(i), 1); (*m_walkerMissingGlyphCallback)(subRun, m_walkerData); continue; } } if (!(*m_walkerCallback)(identifier, m_walkerData)) break; foundGlyph = false; } }
bool SVGFontData::applySVGGlyphSelection(WidthIterator& iterator, GlyphData& glyphData, bool mirror, int currentCharacter, unsigned& advanceLength, String& normalizedSpacesStringCache) const { const TextRun& run = iterator.run(); Vector<SVGGlyph::ArabicForm>& arabicForms = iterator.arabicForms(); ASSERT(run.charactersLength() >= static_cast<unsigned>(currentCharacter)); SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement(); ASSERT(svgFontFaceElement); SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement(); ASSERT(associatedFontElement); RenderObject* renderObject = nullptr; if (TextRun::RenderingContext* renderingContext = run.renderingContext()) renderObject = &static_cast<SVGTextRunRenderingContext*>(renderingContext)->renderer(); String language; bool isVerticalText = false; Vector<String> altGlyphNames; if (renderObject) { RenderElement& parentRenderer = is<RenderElement>(*renderObject) ? downcast<RenderElement>(*renderObject) : *renderObject->parent(); isVerticalText = parentRenderer.style().svgStyle().isVerticalWritingMode(); if (Element* parentRendererElement = parentRenderer.element()) { language = parentRendererElement->getAttribute(XMLNames::langAttr); if (is<SVGAltGlyphElement>(*parentRendererElement)) { SVGAltGlyphElement& altGlyph = downcast<SVGAltGlyphElement>(*parentRendererElement); if (!altGlyph.hasValidGlyphElements(altGlyphNames)) altGlyphNames.clear(); } } } Vector<SVGGlyph> glyphs; size_t altGlyphNamesSize = altGlyphNames.size(); if (altGlyphNamesSize) { for (size_t index = 0; index < altGlyphNamesSize; ++index) associatedFontElement->collectGlyphsForGlyphName(altGlyphNames[index], glyphs); // Assign the unicodeStringLength now that its known. size_t glyphsSize = glyphs.size(); for (size_t i = 0; i < glyphsSize; ++i) glyphs[i].unicodeStringLength = run.length(); // Do not check alt glyphs for compatibility. Just return the first one. // Later code will fail if we do not do this and the glyph is incompatible. if (glyphsSize) { SVGGlyph& svgGlyph = glyphs[0]; iterator.setLastGlyphName(svgGlyph.glyphName); glyphData.glyph = svgGlyph.tableEntry; advanceLength = svgGlyph.unicodeStringLength; return true; } } else { // Associate text with arabic forms, if needed. computeNormalizedSpaces(run, mirror, normalizedSpacesStringCache); auto remainingTextInRun = normalizedSpacesStringCache.substring(currentCharacter); if (!currentCharacter && arabicForms.isEmpty()) arabicForms = charactersWithArabicForm(remainingTextInRun, mirror); associatedFontElement->collectGlyphsForString(remainingTextInRun, glyphs); } size_t glyphsSize = glyphs.size(); for (size_t i = 0; i < glyphsSize; ++i) { SVGGlyph& svgGlyph = glyphs[i]; if (svgGlyph.isPartOfLigature) continue; if (!isCompatibleGlyph(svgGlyph, isVerticalText, language, arabicForms, currentCharacter, currentCharacter + svgGlyph.unicodeStringLength)) continue; iterator.setLastGlyphName(svgGlyph.glyphName); glyphData.glyph = svgGlyph.tableEntry; advanceLength = svgGlyph.unicodeStringLength; return true; } iterator.setLastGlyphName(String()); return false; }
bool SVGFontData::applySVGGlyphSelection(WidthIterator& iterator, GlyphData& glyphData, bool mirror, int currentCharacter, unsigned& advanceLength) const { const TextRun& run = iterator.run(); Vector<SVGGlyph::ArabicForm>& arabicForms = iterator.arabicForms(); ASSERT(int(run.charactersLength()) >= currentCharacter); // Associate text with arabic forms, if needed. String remainingTextInRun(run.data16(currentCharacter), run.charactersLength() - currentCharacter); remainingTextInRun = Font::normalizeSpaces(remainingTextInRun.characters(), remainingTextInRun.length()); if (mirror) remainingTextInRun = createStringWithMirroredCharacters(remainingTextInRun.characters(), remainingTextInRun.length()); if (!currentCharacter && arabicForms.isEmpty()) arabicForms = charactersWithArabicForm(remainingTextInRun, mirror); SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement(); ASSERT(svgFontFaceElement); SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement(); ASSERT(associatedFontElement); RenderObject* renderObject = 0; if (TextRun::RenderingContext* renderingContext = run.renderingContext()) renderObject = static_cast<SVGTextRunRenderingContext*>(renderingContext)->renderer(); String language; bool isVerticalText = false; Vector<String> altGlyphNames; if (renderObject) { RenderObject* parentRenderObject = renderObject->isText() ? renderObject->parent() : renderObject; ASSERT(parentRenderObject); isVerticalText = parentRenderObject->style()->svgStyle()->isVerticalWritingMode(); if (Element* parentRenderObjectElement = toElement(parentRenderObject->node())) { language = parentRenderObjectElement->getAttribute(XMLNames::langAttr); if (parentRenderObjectElement->hasTagName(SVGNames::altGlyphTag)) { SVGAltGlyphElement* altGlyph = static_cast<SVGAltGlyphElement*>(parentRenderObjectElement); if (!altGlyph->hasValidGlyphElements(altGlyphNames)) altGlyphNames.clear(); } } } Vector<SVGGlyph> glyphs; size_t altGlyphNamesSize = altGlyphNames.size(); if (altGlyphNamesSize) { for (size_t index = 0; index < altGlyphNamesSize; ++index) associatedFontElement->collectGlyphsForGlyphName(altGlyphNames[index], glyphs); // Assign the unicodeStringLength now that its known. size_t glyphsSize = glyphs.size(); for (size_t i = 0; i < glyphsSize; ++i) glyphs[i].unicodeStringLength = run.length(); } else associatedFontElement->collectGlyphsForString(remainingTextInRun, glyphs); size_t glyphsSize = glyphs.size(); for (size_t i = 0; i < glyphsSize; ++i) { SVGGlyph& svgGlyph = glyphs[i]; if (svgGlyph.isPartOfLigature) continue; if (!isCompatibleGlyph(svgGlyph, isVerticalText, language, arabicForms, currentCharacter, currentCharacter + svgGlyph.unicodeStringLength)) continue; iterator.setLastGlyphName(svgGlyph.glyphName); glyphData.glyph = svgGlyph.tableEntry; advanceLength = svgGlyph.unicodeStringLength; return true; } iterator.setLastGlyphName(String()); return false; }