static inline float applyFontTransforms(GlyphBuffer* glyphBuffer, bool ltr, int& lastGlyphCount, const SimpleFontData* fontData, WidthIterator& iterator, TypesettingFeatures typesettingFeatures, CharactersTreatedAsSpace& charactersTreatedAsSpace) { ASSERT(typesettingFeatures & (Kerning | Ligatures)); if (!glyphBuffer) return 0; int glyphBufferSize = glyphBuffer->size(); if (glyphBuffer->size() <= lastGlyphCount + 1) return 0; GlyphBufferAdvance* advances = glyphBuffer->advances(0); float widthDifference = 0; for (int i = lastGlyphCount; i < glyphBufferSize; ++i) widthDifference -= advances[i].width(); if (!ltr) glyphBuffer->reverse(lastGlyphCount, glyphBufferSize - lastGlyphCount); #if !ENABLE(SVG_FONTS) UNUSED_PARAM(iterator); #else // We need to handle transforms on SVG fonts internally, since they are rendered internally. if (fontData->isSVGFont()) { // SVG font ligatures are handled during glyph selection, only kerning remaining. if (iterator.run().renderingContext() && (typesettingFeatures & Kerning)) { // FIXME: We could pass the necessary context down to this level so we can lazily create rendering contexts at this point. // However, a larger refactoring of SVG fonts might necessary to sidestep this problem completely. iterator.run().renderingContext()->applySVGKerning(fontData, iterator, glyphBuffer, lastGlyphCount); } } else #endif fontData->applyTransforms(glyphBuffer->glyphs(lastGlyphCount), advances + lastGlyphCount, glyphBufferSize - lastGlyphCount, typesettingFeatures); if (!ltr) glyphBuffer->reverse(lastGlyphCount, glyphBufferSize - lastGlyphCount); for (size_t i = 0; i < charactersTreatedAsSpace.size(); ++i) { int spaceOffset = charactersTreatedAsSpace[i].first; const OriginalAdvancesForCharacterTreatedAsSpace& originalAdvances = charactersTreatedAsSpace[i].second; if (spaceOffset && !originalAdvances.characterIsSpace) glyphBuffer->advances(spaceOffset - 1)->setWidth(originalAdvances.advanceBeforeCharacter); glyphBuffer->advances(spaceOffset)->setWidth(originalAdvances.advanceAtCharacter); } charactersTreatedAsSpace.clear(); for (int i = lastGlyphCount; i < glyphBufferSize; ++i) widthDifference += advances[i].width(); lastGlyphCount = glyphBufferSize; return widthDifference; }
static inline float applyFontTransforms(GlyphBuffer* glyphBuffer, bool ltr, int& lastGlyphCount, const SimpleFontData* fontData, WidthIterator& iterator, TypesettingFeatures typesettingFeatures, CharactersTreatedAsSpace& charactersTreatedAsSpace) { ASSERT(typesettingFeatures & (Kerning | Ligatures)); if (!glyphBuffer) return 0; int glyphBufferSize = glyphBuffer->size(); if (glyphBuffer->size() <= lastGlyphCount + 1) return 0; GlyphBufferAdvance* advances = glyphBuffer->advances(0); float widthDifference = 0; for (int i = lastGlyphCount; i < glyphBufferSize; ++i) widthDifference -= advances[i].width(); if (!ltr) glyphBuffer->reverse(lastGlyphCount, glyphBufferSize - lastGlyphCount); #if ENABLE(SVG_FONTS) // We need to handle transforms on SVG fonts internally, since they are rendered internally. if (fontData->isSVGFont()) { // SVG font fallbacks doesn't work properly and will not have a renderingContext. see: textRunNeedsRenderingContext() // SVG font ligatures are handled during glyph selection, only kerning remaining. if (iterator.run().renderingContext() && (typesettingFeatures & Kerning)) iterator.run().renderingContext()->applySVGKerning(fontData, iterator, glyphBuffer, lastGlyphCount); } else #endif fontData->applyTransforms(glyphBuffer->glyphs(lastGlyphCount), advances + lastGlyphCount, glyphBufferSize - lastGlyphCount, typesettingFeatures); if (!ltr) glyphBuffer->reverse(lastGlyphCount, glyphBufferSize - lastGlyphCount); for (size_t i = 0; i < charactersTreatedAsSpace.size(); ++i) { int spaceOffset = charactersTreatedAsSpace[i].first; const OriginalAdvancesForCharacterTreatedAsSpace& originalAdvances = charactersTreatedAsSpace[i].second; if (spaceOffset && !originalAdvances.characterIsSpace) glyphBuffer->advances(spaceOffset - 1)->setWidth(originalAdvances.advanceBeforeCharacter); glyphBuffer->advances(spaceOffset)->setWidth(originalAdvances.advanceAtCharacter); } charactersTreatedAsSpace.clear(); for (int i = lastGlyphCount; i < glyphBufferSize; ++i) widthDifference += advances[i].width(); lastGlyphCount = glyphBufferSize; return widthDifference; }
bool SVGTextRunRenderingContext::applySVGKerning(const SimpleFontData* fontData, WidthIterator& iterator, GlyphBuffer* glyphBuffer, int from) const { ASSERT(glyphBuffer); ASSERT(glyphBuffer->size() > 1); SVGFontElement* fontElement = 0; SVGFontFaceElement* fontFaceElement = 0; svgFontAndFontFaceElementForFontData(fontData, fontFaceElement, fontElement); if (!fontElement || !fontFaceElement) return false; if (fontElement->horizontalKerningMapIsEmpty()) return true; float scale = scaleEmToUnits(fontData->platformData().size(), fontFaceElement->unitsPerEm()); String lastGlyphName; String lastUnicodeString; int characterOffset = iterator.m_currentCharacter; String text = iterator.run().string(); const int glyphCount = glyphBuffer->size() - from; GlyphBufferAdvance* advances = glyphBuffer->advances(from); for (int i = 0; i < glyphCount; ++i) { Glyph glyph = glyphBuffer->glyphAt(from + i); if (!glyph) continue; float kerning = 0; SVGGlyph svgGlyph = fontElement->svgGlyphForGlyph(glyph); String unicodeString = text.substring(characterOffset, svgGlyph.unicodeStringLength); if (i >= 1) { // FIXME: Support vertical text. kerning = fontElement->horizontalKerningForPairOfStringsAndGlyphs(lastUnicodeString, lastGlyphName, unicodeString, svgGlyph.glyphName); advances[i - 1].setWidth(advances[i - 1].width() - kerning * scale); } lastGlyphName = svgGlyph.glyphName; lastUnicodeString = unicodeString; characterOffset += svgGlyph.unicodeStringLength; } return true; }
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; }