PageRenderTime 57ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/Source/WebCore/svg/SVGFontData.cpp

https://gitlab.com/paretje/qtwebkit
C++ | 298 lines | 213 code | 50 blank | 35 comment | 30 complexity | 76659bbea8fe6ec17ca77888a228c3ef MD5 | raw file
  1. /*
  2. * Copyright (C) 2008 Nikolas Zimmermann <zimmermann@kde.org>
  3. *
  4. * This library is free software; you can redistribute it and/or
  5. * modify it under the terms of the GNU Library General Public
  6. * License as published by the Free Software Foundation; either
  7. * version 2 of the License, or (at your option) any later version.
  8. *
  9. * This library is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12. * Library General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU Library General Public License
  15. * along with this library; see the file COPYING.LIB. If not, write to
  16. * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  17. * Boston, MA 02110-1301, USA.
  18. */
  19. #include "config.h"
  20. #if ENABLE(SVG_FONTS)
  21. #include "SVGFontData.h"
  22. #include "GlyphPage.h"
  23. #include "RenderElement.h"
  24. #include "SVGAltGlyphElement.h"
  25. #include "SVGFontElement.h"
  26. #include "SVGFontFaceElement.h"
  27. #include "SVGGlyph.h"
  28. #include "SVGGlyphElement.h"
  29. #include "SVGNames.h"
  30. #include "SVGTextRunRenderingContext.h"
  31. #include "TextRun.h"
  32. #include "WidthIterator.h"
  33. #include "XMLNames.h"
  34. #include <wtf/text/StringBuilder.h>
  35. #include <wtf/unicode/CharacterNames.h>
  36. using namespace WTF;
  37. using namespace Unicode;
  38. namespace WebCore {
  39. static String createStringWithMirroredCharacters(StringView);
  40. static void computeNormalizedSpaces(const TextRun&, bool mirror, String& normalizedSpacesStringCache);
  41. SVGFontData::SVGFontData(SVGFontFaceElement* fontFaceElement)
  42. : m_svgFontFaceElement(fontFaceElement)
  43. , m_horizontalOriginX(fontFaceElement->horizontalOriginX())
  44. , m_horizontalOriginY(fontFaceElement->horizontalOriginY())
  45. , m_horizontalAdvanceX(fontFaceElement->horizontalAdvanceX())
  46. , m_verticalOriginX(fontFaceElement->verticalOriginX())
  47. , m_verticalOriginY(fontFaceElement->verticalOriginY())
  48. , m_verticalAdvanceY(fontFaceElement->verticalAdvanceY())
  49. {
  50. ASSERT_ARG(fontFaceElement, fontFaceElement);
  51. }
  52. void SVGFontData::initializeFont(Font* font, float fontSize)
  53. {
  54. ASSERT(font);
  55. SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement();
  56. ASSERT(svgFontFaceElement);
  57. font->setZeroWidthSpaceGlyph(0);
  58. font->determinePitch();
  59. unsigned unitsPerEm = svgFontFaceElement->unitsPerEm();
  60. float scale = scaleEmToUnits(fontSize, unitsPerEm);
  61. float xHeight = svgFontFaceElement->xHeight() * scale;
  62. float ascent = svgFontFaceElement->ascent() * scale;
  63. float descent = svgFontFaceElement->descent() * scale;
  64. float lineGap = 0.1f * fontSize;
  65. const GlyphPage* glyphPageZero = font->glyphPage(0);
  66. if (!xHeight && glyphPageZero) {
  67. // Fallback if x_heightAttr is not specified for the font element.
  68. Glyph letterXGlyph = glyphPageZero->glyphDataForCharacter('x').glyph;
  69. xHeight = letterXGlyph ? font->widthForGlyph(letterXGlyph) : 2 * ascent / 3;
  70. }
  71. FontMetrics& fontMetrics = font->fontMetrics();
  72. fontMetrics.setUnitsPerEm(unitsPerEm);
  73. fontMetrics.setAscent(ascent);
  74. fontMetrics.setDescent(descent);
  75. fontMetrics.setLineGap(lineGap);
  76. fontMetrics.setLineSpacing(roundf(ascent) + roundf(descent) + roundf(lineGap));
  77. fontMetrics.setXHeight(xHeight);
  78. if (!glyphPageZero) {
  79. font->setSpaceGlyph(0);
  80. font->setSpaceWidths(0);
  81. font->setAvgCharWidth(0);
  82. font->setMaxCharWidth(ascent);
  83. return;
  84. }
  85. // Calculate space width.
  86. Glyph spaceGlyph = glyphPageZero->glyphDataForCharacter(' ').glyph;
  87. font->setSpaceGlyph(spaceGlyph);
  88. font->setSpaceWidths(font->widthForGlyph(spaceGlyph));
  89. // Estimate average character width.
  90. Glyph numeralZeroGlyph = glyphPageZero->glyphDataForCharacter('0').glyph;
  91. font->setAvgCharWidth(numeralZeroGlyph ? font->widthForGlyph(numeralZeroGlyph) : font->spaceWidth());
  92. // Estimate maximum character width.
  93. Glyph letterWGlyph = glyphPageZero->glyphDataForCharacter('W').glyph;
  94. font->setMaxCharWidth(letterWGlyph ? font->widthForGlyph(letterWGlyph) : ascent);
  95. }
  96. float SVGFontData::widthForSVGGlyph(Glyph glyph, float fontSize) const
  97. {
  98. SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement();
  99. ASSERT(svgFontFaceElement);
  100. SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement();
  101. ASSERT(associatedFontElement);
  102. SVGGlyph svgGlyph = associatedFontElement->svgGlyphForGlyph(glyph);
  103. SVGGlyphElement::inheritUnspecifiedAttributes(svgGlyph, this);
  104. return svgGlyph.horizontalAdvanceX * scaleEmToUnits(fontSize, svgFontFaceElement->unitsPerEm());
  105. }
  106. bool SVGFontData::applySVGGlyphSelection(WidthIterator& iterator, GlyphData& glyphData, bool mirror, int currentCharacter, unsigned& advanceLength, String& normalizedSpacesStringCache) const
  107. {
  108. const TextRun& run = iterator.run();
  109. Vector<SVGGlyph::ArabicForm>& arabicForms = iterator.arabicForms();
  110. ASSERT(run.charactersLength() >= static_cast<unsigned>(currentCharacter));
  111. SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement();
  112. ASSERT(svgFontFaceElement);
  113. SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement();
  114. ASSERT(associatedFontElement);
  115. RenderObject* renderObject = nullptr;
  116. if (TextRun::RenderingContext* renderingContext = run.renderingContext())
  117. renderObject = &static_cast<SVGTextRunRenderingContext*>(renderingContext)->renderer();
  118. String language;
  119. bool isVerticalText = false;
  120. Vector<String> altGlyphNames;
  121. if (renderObject) {
  122. RenderElement& parentRenderer = is<RenderElement>(*renderObject) ? downcast<RenderElement>(*renderObject) : *renderObject->parent();
  123. isVerticalText = parentRenderer.style().svgStyle().isVerticalWritingMode();
  124. if (Element* parentRendererElement = parentRenderer.element()) {
  125. language = parentRendererElement->getAttribute(XMLNames::langAttr);
  126. if (is<SVGAltGlyphElement>(*parentRendererElement)) {
  127. SVGAltGlyphElement& altGlyph = downcast<SVGAltGlyphElement>(*parentRendererElement);
  128. if (!altGlyph.hasValidGlyphElements(altGlyphNames))
  129. altGlyphNames.clear();
  130. }
  131. }
  132. }
  133. Vector<SVGGlyph> glyphs;
  134. if (!altGlyphNames.isEmpty()) {
  135. for (auto& name : altGlyphNames)
  136. associatedFontElement->collectGlyphsForGlyphName(name, glyphs);
  137. // Assign the unicodeStringLength now that its known.
  138. for (auto& glyph : glyphs)
  139. glyph.unicodeStringLength = run.length();
  140. // Do not check alt glyphs for compatibility. Just return the first one.
  141. // Later code will fail if we do not do this and the glyph is incompatible.
  142. if (!glyphs.isEmpty()) {
  143. SVGGlyph& svgGlyph = glyphs[0];
  144. iterator.setLastGlyphName(svgGlyph.glyphName);
  145. glyphData.glyph = svgGlyph.tableEntry;
  146. advanceLength = svgGlyph.unicodeStringLength;
  147. return true;
  148. }
  149. } else {
  150. // Associate text with arabic forms, if needed.
  151. computeNormalizedSpaces(run, mirror, normalizedSpacesStringCache);
  152. auto remainingTextInRun = normalizedSpacesStringCache.substring(currentCharacter);
  153. if (!currentCharacter && arabicForms.isEmpty())
  154. arabicForms = charactersWithArabicForm(remainingTextInRun, mirror);
  155. associatedFontElement->collectGlyphsForString(remainingTextInRun, glyphs);
  156. }
  157. for (auto& glyph : glyphs) {
  158. if (glyph.isPartOfLigature)
  159. continue;
  160. if (!isCompatibleGlyph(glyph, isVerticalText, language, arabicForms, currentCharacter, currentCharacter + glyph.unicodeStringLength))
  161. continue;
  162. iterator.setLastGlyphName(glyph.glyphName);
  163. glyphData.glyph = glyph.tableEntry;
  164. advanceLength = glyph.unicodeStringLength;
  165. return true;
  166. }
  167. iterator.setLastGlyphName(String());
  168. return false;
  169. }
  170. bool SVGFontData::fillSVGGlyphPage(GlyphPage* pageToFill, UChar* buffer, unsigned bufferLength) const
  171. {
  172. SVGFontFaceElement* fontFaceElement = this->svgFontFaceElement();
  173. ASSERT(fontFaceElement);
  174. SVGFontElement* fontElement = fontFaceElement->associatedFontElement();
  175. ASSERT(fontElement);
  176. if (bufferLength == GlyphPage::size)
  177. return fillBMPGlyphs(fontElement, pageToFill, buffer);
  178. ASSERT(bufferLength == 2 * GlyphPage::size);
  179. return fillNonBMPGlyphs(fontElement, pageToFill, buffer);
  180. }
  181. bool SVGFontData::fillBMPGlyphs(SVGFontElement* fontElement, GlyphPage* pageToFill, UChar* buffer) const
  182. {
  183. bool haveGlyphs = false;
  184. Vector<SVGGlyph> glyphs;
  185. for (unsigned i = 0; i < GlyphPage::size; ++i) {
  186. String lookupString(buffer + i, 1);
  187. fontElement->collectGlyphsForString(lookupString, glyphs);
  188. if (glyphs.isEmpty()) {
  189. pageToFill->setGlyphForIndex(i, 0);
  190. continue;
  191. }
  192. // Associate entry in glyph page with first valid SVGGlyph.
  193. // If there are multiple valid ones, just take the first one. WidthIterator will take
  194. // care of matching to the correct glyph, if multiple ones are available, as that's
  195. // only possible within the context of a string (eg. arabic form matching).
  196. haveGlyphs = true;
  197. pageToFill->setGlyphForIndex(i, glyphs.first().tableEntry);
  198. glyphs.clear();
  199. }
  200. return haveGlyphs;
  201. }
  202. bool SVGFontData::fillNonBMPGlyphs(SVGFontElement* fontElement, GlyphPage* pageToFill, UChar* buffer) const
  203. {
  204. bool haveGlyphs = false;
  205. Vector<SVGGlyph> glyphs;
  206. for (unsigned i = 0; i < GlyphPage::size; ++i) {
  207. // Each character here consists of a surrogate pair
  208. String lookupString(buffer + i * 2, 2);
  209. fontElement->collectGlyphsForString(lookupString, glyphs);
  210. if (glyphs.isEmpty()) {
  211. pageToFill->setGlyphForIndex(i, 0);
  212. continue;
  213. }
  214. // Associate entry in glyph page with first valid SVGGlyph.
  215. // If there are multiple valid ones, just take the first one. WidthIterator will take
  216. // care of matching to the correct glyph, if multiple ones are available, as that's
  217. // only possible within the context of a string (eg. arabic form matching).
  218. haveGlyphs = true;
  219. pageToFill->setGlyphForIndex(i, glyphs.first().tableEntry);
  220. glyphs.clear();
  221. }
  222. return haveGlyphs;
  223. }
  224. void computeNormalizedSpaces(const TextRun& run, bool mirror, String& normalizedSpacesStringCache)
  225. {
  226. if (normalizedSpacesStringCache.length() == static_cast<unsigned>(run.charactersLength()))
  227. return;
  228. if (run.is8Bit())
  229. normalizedSpacesStringCache = FontCascade::normalizeSpaces(run.characters8(), run.charactersLength());
  230. else
  231. normalizedSpacesStringCache = FontCascade::normalizeSpaces(run.characters16(), run.charactersLength());
  232. if (mirror)
  233. normalizedSpacesStringCache = createStringWithMirroredCharacters(normalizedSpacesStringCache);
  234. }
  235. String createStringWithMirroredCharacters(StringView string)
  236. {
  237. unsigned length = string.length();
  238. StringBuilder mirroredCharacters;
  239. mirroredCharacters.reserveCapacity(length);
  240. for (unsigned i = 0; i < length; ) {
  241. UChar32 character;
  242. U16_NEXT(string, i, length, character);
  243. mirroredCharacters.append(u_charMirror(character));
  244. }
  245. return mirroredCharacters.toString();
  246. }
  247. } // namespace WebCore
  248. #endif