2 * Copyright (C) 2008 Nikolas Zimmermann <zimmermann@kde.org>
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.
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.
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.
23 #include "core/svg/SVGFontData.h"
27 #include "core/rendering/RenderObject.h"
28 #include "core/rendering/svg/SVGTextRunRenderingContext.h"
29 #include "core/svg/SVGAltGlyphElement.h"
30 #include "core/svg/SVGFontElement.h"
31 #include "core/svg/SVGFontFaceElement.h"
32 #include "core/svg/SVGGlyphElement.h"
33 #include "platform/fonts/Character.h"
34 #include "platform/fonts/SVGGlyph.h"
35 #include "platform/fonts/SimpleFontData.h"
36 #include "platform/fonts/WidthIterator.h"
37 #include "platform/text/TextRun.h"
38 #include "wtf/text/StringBuilder.h"
39 #include "wtf/unicode/CharacterNames.h"
40 #include "wtf/unicode/Unicode.h"
43 using namespace Unicode;
47 SVGFontData::SVGFontData(SVGFontFaceElement* fontFaceElement)
48 : CustomFontData(false)
49 , m_svgFontFaceElement(fontFaceElement)
50 , m_horizontalOriginX(fontFaceElement->horizontalOriginX())
51 , m_horizontalOriginY(fontFaceElement->horizontalOriginY())
52 , m_horizontalAdvanceX(fontFaceElement->horizontalAdvanceX())
53 , m_verticalOriginX(fontFaceElement->verticalOriginX())
54 , m_verticalOriginY(fontFaceElement->verticalOriginY())
55 , m_verticalAdvanceY(fontFaceElement->verticalAdvanceY())
57 ASSERT_ARG(fontFaceElement, fontFaceElement);
60 void SVGFontData::initializeFontData(SimpleFontData* fontData, float fontSize)
64 SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement();
65 ASSERT(svgFontFaceElement);
67 SVGFontElement* svgFontElement = svgFontFaceElement->associatedFontElement();
68 ASSERT(svgFontElement);
69 GlyphData missingGlyphData;
70 missingGlyphData.fontData = fontData;
71 missingGlyphData.glyph = svgFontElement->missingGlyph();
72 fontData->setMissingGlyphData(missingGlyphData);
74 fontData->setZeroWidthSpaceGlyph(0);
75 fontData->determinePitch();
77 unsigned unitsPerEm = svgFontFaceElement->unitsPerEm();
78 float scale = scaleEmToUnits(fontSize, unitsPerEm);
79 float xHeight = svgFontFaceElement->xHeight() * scale;
80 float ascent = svgFontFaceElement->ascent() * scale;
81 float descent = svgFontFaceElement->descent() * scale;
82 float lineGap = 0.1f * fontSize;
84 GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(fontData, 0)->page();
86 if (!xHeight && glyphPageZero) {
87 // Fallback if x_heightAttr is not specified for the font element.
88 Glyph letterXGlyph = glyphPageZero->glyphForCharacter('x');
89 xHeight = letterXGlyph ? fontData->widthForGlyph(letterXGlyph) : 2 * ascent / 3;
92 FontMetrics& fontMetrics = fontData->fontMetrics();
93 fontMetrics.setUnitsPerEm(unitsPerEm);
94 fontMetrics.setAscent(ascent);
95 fontMetrics.setDescent(descent);
96 fontMetrics.setLineGap(lineGap);
97 fontMetrics.setLineSpacing(roundf(ascent) + roundf(descent) + roundf(lineGap));
98 fontMetrics.setXHeight(xHeight);
100 if (!glyphPageZero) {
101 fontData->setSpaceGlyph(0);
102 fontData->setSpaceWidth(0);
103 fontData->setAvgCharWidth(0);
104 fontData->setMaxCharWidth(ascent);
108 // Calculate space width.
109 Glyph spaceGlyph = glyphPageZero->glyphForCharacter(' ');
110 fontData->setSpaceGlyph(spaceGlyph);
111 fontData->setSpaceWidth(fontData->widthForGlyph(spaceGlyph));
113 // Estimate average character width.
114 Glyph numeralZeroGlyph = glyphPageZero->glyphForCharacter('0');
115 fontData->setAvgCharWidth(numeralZeroGlyph ? fontData->widthForGlyph(numeralZeroGlyph) : fontData->spaceWidth());
117 // Estimate maximum character width.
118 Glyph letterWGlyph = glyphPageZero->glyphForCharacter('W');
119 fontData->setMaxCharWidth(letterWGlyph ? fontData->widthForGlyph(letterWGlyph) : ascent);
122 float SVGFontData::widthForSVGGlyph(Glyph glyph, float fontSize) const
124 SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement();
125 ASSERT(svgFontFaceElement);
127 SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement();
128 ASSERT(associatedFontElement);
130 SVGGlyph svgGlyph = associatedFontElement->svgGlyphForGlyph(glyph);
131 SVGGlyphElement::inheritUnspecifiedAttributes(svgGlyph, this);
132 return svgGlyph.horizontalAdvanceX * scaleEmToUnits(fontSize, svgFontFaceElement->unitsPerEm());
135 bool SVGFontData::applySVGGlyphSelection(WidthIterator& iterator, GlyphData& glyphData, bool mirror, int currentCharacter, unsigned& advanceLength) const
137 const TextRun& run = iterator.run();
138 Vector<SVGGlyph::ArabicForm>& arabicForms = iterator.arabicForms();
139 ASSERT(int(run.charactersLength()) >= currentCharacter);
141 // Associate text with arabic forms, if needed.
142 String remainingTextInRun;
145 remainingTextInRun = String(run.data8(currentCharacter), run.charactersLength() - currentCharacter);
146 remainingTextInRun = Character::normalizeSpaces(remainingTextInRun.characters8(), remainingTextInRun.length());
148 remainingTextInRun = String(run.data16(currentCharacter), run.charactersLength() - currentCharacter);
149 remainingTextInRun = Character::normalizeSpaces(remainingTextInRun.characters16(), remainingTextInRun.length());
153 remainingTextInRun = createStringWithMirroredCharacters(remainingTextInRun);
154 if (!currentCharacter && arabicForms.isEmpty())
155 arabicForms = charactersWithArabicForm(remainingTextInRun, mirror);
157 SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement();
158 ASSERT(svgFontFaceElement);
160 SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement();
161 ASSERT(associatedFontElement);
163 RenderObject* renderObject = 0;
164 if (TextRun::RenderingContext* renderingContext = run.renderingContext())
165 renderObject = static_cast<SVGTextRunRenderingContext*>(renderingContext)->renderer();
168 bool isVerticalText = false;
169 Vector<AtomicString> altGlyphNames;
172 RenderObject* parentRenderObject = renderObject->isText() ? renderObject->parent() : renderObject;
173 ASSERT(parentRenderObject);
175 isVerticalText = parentRenderObject->style()->svgStyle()->isVerticalWritingMode();
176 if (Element* parentRenderObjectElement = toElement(parentRenderObject->node())) {
177 language = parentRenderObjectElement->getAttribute(XMLNames::langAttr);
179 if (parentRenderObjectElement->hasTagName(SVGNames::altGlyphTag)) {
180 if (!toSVGAltGlyphElement(parentRenderObjectElement)->hasValidGlyphElements(altGlyphNames))
181 altGlyphNames.clear();
186 Vector<SVGGlyph> glyphs;
187 size_t altGlyphNamesSize = altGlyphNames.size();
188 if (altGlyphNamesSize) {
189 for (size_t index = 0; index < altGlyphNamesSize; ++index)
190 associatedFontElement->collectGlyphsForGlyphName(altGlyphNames[index], glyphs);
192 // Assign the unicodeStringLength now that its known.
193 size_t glyphsSize = glyphs.size();
194 for (size_t i = 0; i < glyphsSize; ++i)
195 glyphs[i].unicodeStringLength = run.length();
197 // Do not check alt glyphs for compatibility. Just return the first one.
198 // Later code will fail if we do not do this and the glyph is incompatible.
200 SVGGlyph& svgGlyph = glyphs[0];
201 iterator.setLastGlyphName(svgGlyph.glyphName);
202 glyphData.glyph = svgGlyph.tableEntry;
203 advanceLength = svgGlyph.unicodeStringLength;
207 associatedFontElement->collectGlyphsForString(remainingTextInRun, glyphs);
209 size_t glyphsSize = glyphs.size();
210 for (size_t i = 0; i < glyphsSize; ++i) {
211 SVGGlyph& svgGlyph = glyphs[i];
212 if (svgGlyph.isPartOfLigature)
214 if (!isCompatibleGlyph(svgGlyph, isVerticalText, language, arabicForms, currentCharacter, currentCharacter + svgGlyph.unicodeStringLength))
216 iterator.setLastGlyphName(svgGlyph.glyphName);
217 glyphData.glyph = svgGlyph.tableEntry;
218 advanceLength = svgGlyph.unicodeStringLength;
222 iterator.setLastGlyphName(String());
226 bool SVGFontData::fillSVGGlyphPage(GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) const
228 ASSERT(fontData->isCustomFont());
229 ASSERT(fontData->isSVGFont());
231 SVGFontFaceElement* fontFaceElement = this->svgFontFaceElement();
232 ASSERT(fontFaceElement);
234 SVGFontElement* fontElement = fontFaceElement->associatedFontElement();
237 if (bufferLength == length)
238 return fillBMPGlyphs(fontElement, pageToFill, offset, length, buffer, fontData);
240 ASSERT(bufferLength == 2 * length);
241 return fillNonBMPGlyphs(fontElement, pageToFill, offset, length, buffer, fontData);
244 bool SVGFontData::fillBMPGlyphs(SVGFontElement* fontElement, GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, const SimpleFontData* fontData) const
246 bool haveGlyphs = false;
247 Vector<SVGGlyph> glyphs;
248 for (unsigned i = 0; i < length; ++i) {
249 String lookupString(buffer + i, 1);
250 fontElement->collectGlyphsForString(lookupString, glyphs);
251 if (glyphs.isEmpty()) {
252 pageToFill->setGlyphDataForIndex(offset + i, 0, 0);
256 // Associate entry in glyph page with first valid SVGGlyph.
257 // If there are multiple valid ones, just take the first one. WidthIterator will take
258 // care of matching to the correct glyph, if multiple ones are available, as that's
259 // only possible within the context of a string (eg. arabic form matching).
261 pageToFill->setGlyphDataForIndex(offset + i, glyphs.first().tableEntry, fontData);
268 bool SVGFontData::fillNonBMPGlyphs(SVGFontElement* fontElement, GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, const SimpleFontData* fontData) const
270 bool haveGlyphs = false;
271 Vector<SVGGlyph> glyphs;
272 for (unsigned i = 0; i < length; ++i) {
273 // Each character here consists of a surrogate pair
274 String lookupString(buffer + i * 2, 2);
275 fontElement->collectGlyphsForString(lookupString, glyphs);
276 if (glyphs.isEmpty()) {
277 pageToFill->setGlyphDataForIndex(offset + i, 0, 0);
281 // Associate entry in glyph page with first valid SVGGlyph.
282 // If there are multiple valid ones, just take the first one. WidthIterator will take
283 // care of matching to the correct glyph, if multiple ones are available, as that's
284 // only possible within the context of a string (eg. arabic form matching).
286 pageToFill->setGlyphDataForIndex(offset + i, glyphs.first().tableEntry, fontData);
293 String SVGFontData::createStringWithMirroredCharacters(const String& string) const
295 if (string.isEmpty())
296 return emptyString();
298 unsigned length = string.length();
300 StringBuilder mirroredCharacters;
301 mirroredCharacters.reserveCapacity(length);
303 if (string.is8Bit()) {
304 const LChar* characters = string.characters8();
305 for (unsigned i = 0; i < length; ++i)
306 mirroredCharacters.append(mirroredChar(characters[i]));
308 const UChar* characters = string.characters16();
312 U16_NEXT(characters, i, length, character);
313 mirroredCharacters.append(mirroredChar(character));
317 return mirroredCharacters.toString();
320 } // namespace WebCore