diff options
Diffstat (limited to 'Source/WebCore/svg/SVGFontElement.cpp')
-rw-r--r-- | Source/WebCore/svg/SVGFontElement.cpp | 271 |
1 files changed, 3 insertions, 268 deletions
diff --git a/Source/WebCore/svg/SVGFontElement.cpp b/Source/WebCore/svg/SVGFontElement.cpp index c0355239f..6427281be 100644 --- a/Source/WebCore/svg/SVGFontElement.cpp +++ b/Source/WebCore/svg/SVGFontElement.cpp @@ -26,8 +26,7 @@ #include "Document.h" #include "ElementIterator.h" -#include "Font.h" -#include "GlyphPageTreeNode.h" +#include "FontCascade.h" #include "SVGGlyphElement.h" #include "SVGHKernElement.h" #include "SVGMissingGlyphElement.h" @@ -47,278 +46,14 @@ END_REGISTER_ANIMATED_PROPERTIES inline SVGFontElement::SVGFontElement(const QualifiedName& tagName, Document& document) : SVGElement(tagName, document) - , m_missingGlyph(0) - , m_isGlyphCacheValid(false) { ASSERT(hasTagName(SVGNames::fontTag)); registerAnimatedPropertiesForSVGFontElement(); } -PassRefPtr<SVGFontElement> SVGFontElement::create(const QualifiedName& tagName, Document& document) +Ref<SVGFontElement> SVGFontElement::create(const QualifiedName& tagName, Document& document) { - return adoptRef(new SVGFontElement(tagName, document)); -} - -void SVGFontElement::invalidateGlyphCache() -{ - if (m_isGlyphCacheValid) { - m_glyphMap.clear(); - m_horizontalKerningMap.clear(); - m_verticalKerningMap.clear(); - } - m_isGlyphCacheValid = false; -} - -const SVGMissingGlyphElement* SVGFontElement::firstMissingGlyphElement() const -{ - return childrenOfType<SVGMissingGlyphElement>(*this).first(); -} - -void SVGFontElement::registerLigaturesInGlyphCache(Vector<String>& ligatures) -{ - ASSERT(!ligatures.isEmpty()); - - // Register each character of a ligature in the map, if not present. - // Eg. If only a "fi" ligature is present, but not "f" and "i", the - // GlyphPage will not contain any entries for "f" and "i", so the - // SVGFont is not used to render the text "fi1234". Register an - // empty SVGGlyph with the character, so the SVG Font will be used - // to render the text. If someone tries to render "f2" the SVG Font - // will not be able to find a glyph for "f", but handles the fallback - // character substitution properly through glyphDataForCharacter(). - Vector<SVGGlyph> glyphs; - size_t ligaturesSize = ligatures.size(); - for (size_t i = 0; i < ligaturesSize; ++i) { - const String& unicode = ligatures[i]; - - unsigned unicodeLength = unicode.length(); - ASSERT(unicodeLength > 1); - - const UChar* characters = unicode.deprecatedCharacters(); - for (unsigned i = 0; i < unicodeLength; ++i) { - String lookupString(characters + i, 1); - m_glyphMap.collectGlyphsForString(lookupString, glyphs); - if (!glyphs.isEmpty()) { - glyphs.clear(); - continue; - } - - // This glyph is never meant to be used for rendering, only as identifier as a part of a ligature. - SVGGlyph newGlyphPart; - newGlyphPart.isPartOfLigature = true; - m_glyphMap.addGlyph(String(), lookupString, newGlyphPart); - } - } -} - -void SVGFontElement::ensureGlyphCache() -{ - if (m_isGlyphCacheValid) - return; - - const SVGMissingGlyphElement* firstMissingGlyphElement = nullptr; - Vector<String> ligatures; - for (auto& child : childrenOfType<SVGElement>(*this)) { - if (isSVGGlyphElement(child)) { - SVGGlyphElement& glyph = toSVGGlyphElement(child); - AtomicString unicode = glyph.fastGetAttribute(SVGNames::unicodeAttr); - AtomicString glyphId = glyph.getIdAttribute(); - if (glyphId.isEmpty() && unicode.isEmpty()) - continue; - - m_glyphMap.addGlyph(glyphId, unicode, glyph.buildGlyphIdentifier()); - - // Register ligatures, if needed, don't mix up with surrogate pairs though! - if (unicode.length() > 1 && !U16_IS_SURROGATE(unicode[0])) - ligatures.append(unicode.string()); - } else if (isSVGHKernElement(child)) { - SVGHKernElement& hkern = toSVGHKernElement(child); - hkern.buildHorizontalKerningPair(m_horizontalKerningMap); - } else if (isSVGVKernElement(child)) { - SVGVKernElement& vkern = toSVGVKernElement(child); - vkern.buildVerticalKerningPair(m_verticalKerningMap); - } else if (isSVGMissingGlyphElement(child) && !firstMissingGlyphElement) - firstMissingGlyphElement = &toSVGMissingGlyphElement(child); - } - - // Register each character of each ligature, if needed. - if (!ligatures.isEmpty()) - registerLigaturesInGlyphCache(ligatures); - - // Register missing-glyph element, if present. - if (firstMissingGlyphElement) { - SVGGlyph svgGlyph = SVGGlyphElement::buildGenericGlyphIdentifier(firstMissingGlyphElement); - m_glyphMap.appendToGlyphTable(svgGlyph); - m_missingGlyph = svgGlyph.tableEntry; - ASSERT(m_missingGlyph > 0); - } - - m_isGlyphCacheValid = true; -} - -void SVGKerningMap::clear() -{ - unicodeMap.clear(); - glyphMap.clear(); - kerningUnicodeRangeMap.clear(); -} - -void SVGKerningMap::insert(const SVGKerningPair& kerningPair) -{ - SVGKerning svgKerning; - svgKerning.kerning = kerningPair.kerning; - svgKerning.unicodeRange2 = kerningPair.unicodeRange2; - svgKerning.unicodeName2 = kerningPair.unicodeName2; - svgKerning.glyphName2 = kerningPair.glyphName2; - - HashSet<String>::const_iterator uIt = kerningPair.unicodeName1.begin(); - const HashSet<String>::const_iterator uEnd = kerningPair.unicodeName1.end(); - for (; uIt != uEnd; ++uIt) { - if (unicodeMap.contains(*uIt)) - unicodeMap.get(*uIt)->append(svgKerning); - else { - auto newVector = std::make_unique<SVGKerningVector>(); - newVector->append(svgKerning); - unicodeMap.add(*uIt, std::move(newVector)); - } - } - - HashSet<String>::const_iterator gIt = kerningPair.glyphName1.begin(); - const HashSet<String>::const_iterator gEnd = kerningPair.glyphName1.end(); - for (; gIt != gEnd; ++gIt) { - if (glyphMap.contains(*gIt)) - glyphMap.get(*gIt)->append(svgKerning); - else { - auto newVector = std::make_unique<SVGKerningVector>(); - newVector->append(svgKerning); - glyphMap.add(*gIt, std::move(newVector)); - } - } - - if (!kerningPair.unicodeRange1.isEmpty()) - kerningUnicodeRangeMap.append(kerningPair); -} - -static inline bool stringMatchesUnicodeRange(const String& unicodeString, const UnicodeRanges& ranges) -{ - if (unicodeString.isEmpty()) - return false; - - if (!ranges.isEmpty()) { - UChar firstChar = unicodeString[0]; - const UnicodeRanges::const_iterator end = ranges.end(); - for (UnicodeRanges::const_iterator it = ranges.begin(); it != end; ++it) { - if (firstChar >= it->first && firstChar <= it->second) - return true; - } - } - - return false; -} - -static inline bool stringMatchesGlyphName(const String& glyphName, const HashSet<String>& glyphValues) -{ - if (glyphName.isEmpty()) - return false; - - return glyphValues.contains(glyphName); -} - -static inline bool stringMatchesUnicodeName(const String& unicodeName, const HashSet<String>& unicodeValues) -{ - if (unicodeName.isEmpty()) - return false; - - return unicodeValues.contains(unicodeName); -} - -static inline bool matches(const String& u2, const String& g2, const SVGKerning& svgKerning) -{ - return stringMatchesGlyphName(g2, svgKerning.glyphName2) - || stringMatchesUnicodeName(u2, svgKerning.unicodeName2) - || stringMatchesUnicodeRange(u2, svgKerning.unicodeRange2); -} - -static inline bool matches(const String& u1, const String& u2, const String& g2, const SVGKerningPair& svgKerningPair) -{ - return stringMatchesUnicodeRange(u1, svgKerningPair.unicodeRange1) && matches(u2, g2, svgKerningPair); -} - -static inline float kerningForPairOfStringsAndGlyphs(const SVGKerningMap& kerningMap, const String& u1, const String& g1, const String& u2, const String& g2) -{ - if (!g1.isEmpty() && kerningMap.glyphMap.contains(g1)) { - SVGKerningVector* kerningVector = kerningMap.glyphMap.get(g1); - SVGKerningVector::const_iterator it = kerningVector->end() - 1; - const SVGKerningVector::const_iterator begin = kerningVector->begin() - 1; - for (; it != begin; --it) { - if (matches(u2, g2, *it)) - return it->kerning; - } - } - - if (!u1.isEmpty()) { - if (kerningMap.unicodeMap.contains(u1)) { - SVGKerningVector* kerningVector = kerningMap.unicodeMap.get(u1); - SVGKerningVector::const_iterator it = kerningVector->end() - 1; - const SVGKerningVector::const_iterator begin = kerningVector->begin() - 1; - for (; it != begin; --it) { - if (matches(u2, g2, *it)) - return it->kerning; - } - } - - if (!kerningMap.kerningUnicodeRangeMap.isEmpty()) { - Vector<SVGKerningPair>::const_iterator it = kerningMap.kerningUnicodeRangeMap.end() - 1; - const Vector<SVGKerningPair>::const_iterator begin = kerningMap.kerningUnicodeRangeMap.begin() - 1; - for (; it != begin; --it) { - if (matches(u1, u2, g2, *it)) - return it->kerning; - } - } - } - - return 0; -} - -float SVGFontElement::horizontalKerningForPairOfStringsAndGlyphs(const String& u1, const String& g1, const String& u2, const String& g2) const -{ - if (m_horizontalKerningMap.isEmpty()) - return 0; - - return kerningForPairOfStringsAndGlyphs(m_horizontalKerningMap, u1, g1, u2, g2); -} - -float SVGFontElement::verticalKerningForPairOfStringsAndGlyphs(const String& u1, const String& g1, const String& u2, const String& g2) const -{ - if (m_verticalKerningMap.isEmpty()) - return 0; - - return kerningForPairOfStringsAndGlyphs(m_verticalKerningMap, u1, g1, u2, g2); -} - -void SVGFontElement::collectGlyphsForString(const String& string, Vector<SVGGlyph>& glyphs) -{ - ensureGlyphCache(); - m_glyphMap.collectGlyphsForString(string, glyphs); -} - -void SVGFontElement::collectGlyphsForGlyphName(const String& glyphName, Vector<SVGGlyph>& glyphs) -{ - ensureGlyphCache(); - // FIXME: We only support glyphName -> single glyph mapping so far. - glyphs.append(m_glyphMap.glyphIdentifierForGlyphName(glyphName)); -} - -SVGGlyph SVGFontElement::svgGlyphForGlyph(Glyph glyph) -{ - ensureGlyphCache(); - return m_glyphMap.svgGlyphForGlyph(glyph); -} - -Glyph SVGFontElement::missingGlyph() -{ - ensureGlyphCache(); - return m_missingGlyph; + return adoptRef(*new SVGFontElement(tagName, document)); } } |