SimpleFontData::SimpleFontData(PassOwnPtr<SVGFontData> svgFontData, int size, bool syntheticBold, bool syntheticItalic) : m_platformData(FontPlatformData(size, syntheticBold, syntheticItalic)) , m_treatAsFixedPitch(false) , m_svgFontData(svgFontData) , m_isCustomFont(true) , m_isLoading(false) , m_isTextOrientationFallback(false) , m_isBrokenIdeographFallback(false) , m_hasVerticalGlyphs(false) { SVGFontFaceElement* svgFontFaceElement = m_svgFontData->svgFontFaceElement(); unsigned unitsPerEm = svgFontFaceElement->unitsPerEm(); float scale = size; if (unitsPerEm) scale /= unitsPerEm; float xHeight = svgFontFaceElement->xHeight() * scale; float ascent = svgFontFaceElement->ascent() * scale; float descent = svgFontFaceElement->descent() * scale; float lineGap = 0.1f * size; SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement(); if (!xHeight) { // Fallback if x_heightAttr is not specified for the font element. Vector<SVGGlyphIdentifier> letterXGlyphs; associatedFontElement->getGlyphIdentifiersForString(String("x", 1), letterXGlyphs); xHeight = letterXGlyphs.isEmpty() ? 2 * ascent / 3 : letterXGlyphs.first().horizontalAdvanceX * scale; } m_fontMetrics.setUnitsPerEm(unitsPerEm); m_fontMetrics.setAscent(ascent); m_fontMetrics.setDescent(descent); m_fontMetrics.setLineGap(lineGap); m_fontMetrics.setLineSpacing(roundf(ascent) + roundf(descent) + roundf(lineGap)); m_fontMetrics.setXHeight(xHeight); Vector<SVGGlyphIdentifier> spaceGlyphs; associatedFontElement->getGlyphIdentifiersForString(String(" ", 1), spaceGlyphs); m_spaceWidth = spaceGlyphs.isEmpty() ? xHeight : spaceGlyphs.first().horizontalAdvanceX * scale; Vector<SVGGlyphIdentifier> numeralZeroGlyphs; associatedFontElement->getGlyphIdentifiersForString(String("0", 1), numeralZeroGlyphs); m_avgCharWidth = numeralZeroGlyphs.isEmpty() ? m_spaceWidth : numeralZeroGlyphs.first().horizontalAdvanceX * scale; Vector<SVGGlyphIdentifier> letterWGlyphs; associatedFontElement->getGlyphIdentifiersForString(String("W", 1), letterWGlyphs); m_maxCharWidth = letterWGlyphs.isEmpty() ? ascent : letterWGlyphs.first().horizontalAdvanceX * scale; // FIXME: is there a way we can get the space glyph from the SVGGlyphIdentifier above? m_spaceGlyph = 0; m_zeroWidthSpaceGlyph = 0; determinePitch(); m_missingGlyphData.fontData = this; m_missingGlyphData.glyph = 0; }
float SVGFontData::widthForSVGGlyph(Glyph glyph, float fontSize) const { SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement(); ASSERT(svgFontFaceElement); SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement(); ASSERT(associatedFontElement); SVGGlyph svgGlyph = associatedFontElement->svgGlyphForGlyph(glyph); SVGGlyphElement::inheritUnspecifiedAttributes(svgGlyph, this); return svgGlyph.horizontalAdvanceX * scaleEmToUnits(fontSize, svgFontFaceElement->unitsPerEm()); }
bool SVGFontData::fillSVGGlyphPage(GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) const { ASSERT(fontData->isCustomFont()); ASSERT(fontData->isSVGFont()); SVGFontFaceElement* fontFaceElement = this->svgFontFaceElement(); ASSERT(fontFaceElement); SVGFontElement* fontElement = fontFaceElement->associatedFontElement(); ASSERT(fontElement); if (bufferLength == length) return fillBMPGlyphs(fontElement, pageToFill, offset, length, buffer, fontData); ASSERT(bufferLength == 2 * length); return fillNonBMPGlyphs(fontElement, pageToFill, offset, length, buffer, fontData); }
SimpleFontData::SimpleFontData(PassOwnPtr<SVGFontData> svgFontData, int size, bool syntheticBold, bool syntheticItalic) : m_orientation(Horizontal) , m_platformData(FontPlatformData(size, syntheticBold, syntheticItalic)) , m_treatAsFixedPitch(false) , m_svgFontData(svgFontData) , m_isCustomFont(true) , m_isLoading(false) , m_isBrokenIdeographFont(false) { SVGFontFaceElement* svgFontFaceElement = m_svgFontData->svgFontFaceElement(); m_unitsPerEm = svgFontFaceElement->unitsPerEm(); double scale = size; if (m_unitsPerEm) scale /= m_unitsPerEm; m_ascent = static_cast<int>(svgFontFaceElement->ascent() * scale); m_descent = static_cast<int>(svgFontFaceElement->descent() * scale); m_xHeight = static_cast<int>(svgFontFaceElement->xHeight() * scale); m_lineGap = 0.1f * size; m_lineSpacing = m_ascent + m_descent + m_lineGap; SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement(); Vector<SVGGlyphIdentifier> spaceGlyphs; associatedFontElement->getGlyphIdentifiersForString(String(" ", 1), spaceGlyphs); m_spaceWidth = spaceGlyphs.isEmpty() ? m_xHeight : static_cast<float>(spaceGlyphs.first().horizontalAdvanceX * scale); Vector<SVGGlyphIdentifier> numeralZeroGlyphs; associatedFontElement->getGlyphIdentifiersForString(String("0", 1), numeralZeroGlyphs); m_avgCharWidth = numeralZeroGlyphs.isEmpty() ? m_spaceWidth : static_cast<float>(numeralZeroGlyphs.first().horizontalAdvanceX * scale); Vector<SVGGlyphIdentifier> letterWGlyphs; associatedFontElement->getGlyphIdentifiersForString(String("W", 1), letterWGlyphs); m_maxCharWidth = letterWGlyphs.isEmpty() ? m_ascent : static_cast<float>(letterWGlyphs.first().horizontalAdvanceX * scale); // FIXME: is there a way we can get the space glyph from the SVGGlyphIdentifier above? m_spaceGlyph = 0; m_zeroWidthSpaceGlyph = 0; determinePitch(); m_adjustedSpaceWidth = roundf(m_spaceWidth); m_missingGlyphData.fontData = this; m_missingGlyphData.glyph = 0; }
float SVGTextLayoutEngineSpacing::calculateSVGKerning(bool isVerticalText, const SVGTextMetrics::Glyph& currentGlyph) { #if ENABLE(SVG_FONTS) const SimpleFontData* fontData = m_font.primaryFont(); if (!fontData->isSVGFont()) { m_lastGlyph.isValid = false; return 0; } ASSERT(fontData->isCustomFont()); ASSERT(fontData->isSVGFont()); const SVGFontData* svgFontData = static_cast<const SVGFontData*>(fontData->fontData()); SVGFontFaceElement* svgFontFace = svgFontData->svgFontFaceElement(); ASSERT(svgFontFace); SVGFontElement* svgFont = svgFontFace->associatedFontElement(); if (!svgFont) { m_lastGlyph.isValid = false; return 0; } float kerning = 0; if (m_lastGlyph.isValid) { if (isVerticalText) kerning = svgFont->verticalKerningForPairOfStringsAndGlyphs(m_lastGlyph.unicodeString, m_lastGlyph.name, currentGlyph.unicodeString, currentGlyph.name); else kerning = svgFont->horizontalKerningForPairOfStringsAndGlyphs(m_lastGlyph.unicodeString, m_lastGlyph.name, currentGlyph.unicodeString, currentGlyph.name); } m_lastGlyph = currentGlyph; m_lastGlyph.isValid = true; kerning *= m_font.size() / m_font.fontMetrics().unitsPerEm(); return kerning; #else UNUSED_PARAM(isVerticalText); UNUSED_PARAM(currentGlyph); return false; #endif }
void SVGFontData::initializeFontData(SimpleFontData* fontData, float fontSize) { ASSERT(fontData); SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement(); ASSERT(svgFontFaceElement); SVGFontElement* svgFontElement = svgFontFaceElement->associatedFontElement(); ASSERT(svgFontElement); GlyphData missingGlyphData; missingGlyphData.fontData = fontData; missingGlyphData.glyph = svgFontElement->missingGlyph(); fontData->setMissingGlyphData(missingGlyphData); fontData->setZeroWidthSpaceGlyph(0); fontData->determinePitch(); unsigned unitsPerEm = svgFontFaceElement->unitsPerEm(); float scale = scaleEmToUnits(fontSize, unitsPerEm); float xHeight = svgFontFaceElement->xHeight() * scale; float ascent = svgFontFaceElement->ascent() * scale; float descent = svgFontFaceElement->descent() * scale; float lineGap = 0.1f * fontSize; GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(fontData, 0)->page(); if (!xHeight && glyphPageZero) { // Fallback if x_heightAttr is not specified for the font element. Glyph letterXGlyph = glyphPageZero->glyphDataForCharacter('x').glyph; xHeight = letterXGlyph ? fontData->widthForGlyph(letterXGlyph) : 2 * ascent / 3; } FontMetrics& fontMetrics = fontData->fontMetrics(); fontMetrics.setUnitsPerEm(unitsPerEm); fontMetrics.setAscent(ascent); fontMetrics.setDescent(descent); fontMetrics.setLineGap(lineGap); fontMetrics.setLineSpacing(roundf(ascent) + roundf(descent) + roundf(lineGap)); fontMetrics.setXHeight(xHeight); if (!glyphPageZero) { fontData->setSpaceGlyph(0); fontData->setSpaceWidths(0); fontData->setAvgCharWidth(0); fontData->setMaxCharWidth(ascent); return; } // Calculate space width. Glyph spaceGlyph = glyphPageZero->glyphDataForCharacter(' ').glyph; fontData->setSpaceGlyph(spaceGlyph); fontData->setSpaceWidths(fontData->widthForGlyph(spaceGlyph)); // Estimate average character width. Glyph numeralZeroGlyph = glyphPageZero->glyphDataForCharacter('0').glyph; fontData->setAvgCharWidth(numeralZeroGlyph ? fontData->widthForGlyph(numeralZeroGlyph) : fontData->spaceWidth()); // Estimate maximum character width. Glyph letterWGlyph = glyphPageZero->glyphDataForCharacter('W').glyph; fontData->setMaxCharWidth(letterWGlyph ? fontData->widthForGlyph(letterWGlyph) : ascent); }
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; }