78ca7e2e83f1b072ad74b7604bac78906f6cf607
[WebKit-https.git] / Source / WebCore / svg / SVGFontData.cpp
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
20 #include "config.h"
21
22 #if ENABLE(SVG_FONTS)
23 #include "SVGFontData.h"
24
25 #include "RenderObject.h"
26 #include "SVGAltGlyphElement.h"
27 #include "SVGFontElement.h"
28 #include "SVGFontFaceElement.h"
29 #include "SVGGlyph.h"
30 #include "SVGGlyphElement.h"
31 #include "SVGNames.h"
32 #include "SVGTextRunRenderingContext.h"
33 #include "TextRun.h"
34 #include "WidthIterator.h"
35 #include "XMLNames.h"
36 #include <wtf/text/StringBuilder.h>
37 #include <wtf/unicode/CharacterNames.h>
38 #include <wtf/unicode/Unicode.h>
39
40 using namespace WTF;
41 using namespace Unicode;
42
43 namespace WebCore {
44
45 SVGFontData::SVGFontData(SVGFontFaceElement* fontFaceElement)
46     : m_svgFontFaceElement(fontFaceElement)
47     , m_horizontalOriginX(fontFaceElement->horizontalOriginX())
48     , m_horizontalOriginY(fontFaceElement->horizontalOriginY())
49     , m_horizontalAdvanceX(fontFaceElement->horizontalAdvanceX())
50     , m_verticalOriginX(fontFaceElement->verticalOriginX())
51     , m_verticalOriginY(fontFaceElement->verticalOriginY())
52     , m_verticalAdvanceY(fontFaceElement->verticalAdvanceY())
53 {
54     ASSERT_ARG(fontFaceElement, fontFaceElement);
55 }
56
57 void SVGFontData::initializeFontData(SimpleFontData* fontData, float fontSize)
58 {
59     ASSERT(fontData);
60
61     SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement();
62     ASSERT(svgFontFaceElement);
63
64     SVGFontElement* svgFontElement = svgFontFaceElement->associatedFontElement();
65     ASSERT(svgFontElement);
66     GlyphData missingGlyphData;
67     missingGlyphData.fontData = fontData;
68     missingGlyphData.glyph = svgFontElement->missingGlyph();
69     fontData->setMissingGlyphData(missingGlyphData);
70
71     fontData->setZeroWidthSpaceGlyph(0);
72     fontData->determinePitch();
73
74     unsigned unitsPerEm = svgFontFaceElement->unitsPerEm();
75     float scale = scaleEmToUnits(fontSize, unitsPerEm);
76     float xHeight = svgFontFaceElement->xHeight() * scale;
77     float ascent = svgFontFaceElement->ascent() * scale;
78     float descent = svgFontFaceElement->descent() * scale;
79     float lineGap = 0.1f * fontSize;
80
81     GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(fontData, 0)->page();
82
83     if (!xHeight && glyphPageZero) {
84         // Fallback if x_heightAttr is not specified for the font element.
85         Glyph letterXGlyph = glyphPageZero->glyphDataForCharacter('x').glyph;
86         xHeight = letterXGlyph ? fontData->widthForGlyph(letterXGlyph) : 2 * ascent / 3;
87     }
88
89     FontMetrics& fontMetrics = fontData->fontMetrics();
90     fontMetrics.setUnitsPerEm(unitsPerEm);
91     fontMetrics.setAscent(ascent);
92     fontMetrics.setDescent(descent);
93     fontMetrics.setLineGap(lineGap);
94     fontMetrics.setLineSpacing(roundf(ascent) + roundf(descent) + roundf(lineGap));
95     fontMetrics.setXHeight(xHeight);
96
97     if (!glyphPageZero) {
98         fontData->setSpaceGlyph(0);
99         fontData->setSpaceWidth(0);
100         fontData->setAvgCharWidth(0);
101         fontData->setMaxCharWidth(ascent);
102         return;
103     }
104
105     // Calculate space width.
106     Glyph spaceGlyph = glyphPageZero->glyphDataForCharacter(' ').glyph;
107     fontData->setSpaceGlyph(spaceGlyph);
108     fontData->setSpaceWidth(fontData->widthForGlyph(spaceGlyph));
109
110     // Estimate average character width.
111     Glyph numeralZeroGlyph = glyphPageZero->glyphDataForCharacter('0').glyph;
112     fontData->setAvgCharWidth(numeralZeroGlyph ? fontData->widthForGlyph(numeralZeroGlyph) : fontData->spaceWidth());
113
114     // Estimate maximum character width.
115     Glyph letterWGlyph = glyphPageZero->glyphDataForCharacter('W').glyph;
116     fontData->setMaxCharWidth(letterWGlyph ? fontData->widthForGlyph(letterWGlyph) : ascent);
117 }
118
119 float SVGFontData::widthForSVGGlyph(Glyph glyph, float fontSize) const
120 {
121     SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement();
122     ASSERT(svgFontFaceElement);
123
124     SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement();
125     ASSERT(associatedFontElement);
126
127     SVGGlyph svgGlyph = associatedFontElement->svgGlyphForGlyph(glyph);
128     SVGGlyphElement::inheritUnspecifiedAttributes(svgGlyph, this);
129     return svgGlyph.horizontalAdvanceX * scaleEmToUnits(fontSize, svgFontFaceElement->unitsPerEm());
130 }
131
132 bool SVGFontData::applySVGGlyphSelection(WidthIterator& iterator, GlyphData& glyphData, bool mirror, int currentCharacter, unsigned& advanceLength) const
133 {
134     const TextRun& run = iterator.run();
135     Vector<SVGGlyph::ArabicForm>& arabicForms = iterator.arabicForms();
136     ASSERT(int(run.charactersLength()) >= currentCharacter);
137
138     // Associate text with arabic forms, if needed.
139     String remainingTextInRun;
140
141     if (run.is8Bit()) {
142         remainingTextInRun = String(run.data8(currentCharacter), run.charactersLength() - currentCharacter);
143         remainingTextInRun = Font::normalizeSpaces(remainingTextInRun.characters8(), remainingTextInRun.length());
144     } else {
145         remainingTextInRun = String(run.data16(currentCharacter), run.charactersLength() - currentCharacter);
146         remainingTextInRun = Font::normalizeSpaces(remainingTextInRun.characters16(), remainingTextInRun.length());
147     }
148
149     if (mirror)
150         remainingTextInRun = createStringWithMirroredCharacters(remainingTextInRun.characters(), remainingTextInRun.length());
151     if (!currentCharacter && arabicForms.isEmpty())
152         arabicForms = charactersWithArabicForm(remainingTextInRun, mirror);
153
154     SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement();
155     ASSERT(svgFontFaceElement);
156
157     SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement();
158     ASSERT(associatedFontElement);
159
160     RenderObject* renderObject = 0;
161     if (TextRun::RenderingContext* renderingContext = run.renderingContext())
162         renderObject = static_cast<SVGTextRunRenderingContext*>(renderingContext)->renderer();
163
164     String language;
165     bool isVerticalText = false;
166     Vector<String> altGlyphNames;
167
168     if (renderObject) {
169         RenderObject* parentRenderObject = renderObject->isText() ? renderObject->parent() : renderObject;
170         ASSERT(parentRenderObject);
171
172         isVerticalText = parentRenderObject->style()->svgStyle()->isVerticalWritingMode();
173         if (Element* parentRenderObjectElement = toElement(parentRenderObject->node())) {
174             language = parentRenderObjectElement->getAttribute(XMLNames::langAttr);
175
176             if (parentRenderObjectElement->hasTagName(SVGNames::altGlyphTag)) {
177                 SVGAltGlyphElement* altGlyph = static_cast<SVGAltGlyphElement*>(parentRenderObjectElement);
178                 if (!altGlyph->hasValidGlyphElements(altGlyphNames))
179                     altGlyphNames.clear();
180             }
181         }
182     }
183
184     Vector<SVGGlyph> glyphs;
185     size_t altGlyphNamesSize = altGlyphNames.size();
186     if (altGlyphNamesSize) {
187         for (size_t index = 0; index < altGlyphNamesSize; ++index)
188             associatedFontElement->collectGlyphsForGlyphName(altGlyphNames[index], glyphs);
189
190         // Assign the unicodeStringLength now that its known.
191         size_t glyphsSize = glyphs.size();
192         for (size_t i = 0; i < glyphsSize; ++i)
193             glyphs[i].unicodeStringLength = run.length();
194
195         // Do not check alt glyphs for compatibility. Just return the first one.
196         // Later code will fail if we do not do this and the glyph is incompatible.
197         if (glyphsSize) {
198             SVGGlyph& svgGlyph = glyphs[0];
199             iterator.setLastGlyphName(svgGlyph.glyphName);
200             glyphData.glyph = svgGlyph.tableEntry;
201             advanceLength = svgGlyph.unicodeStringLength;
202             return true;
203         }
204     } else
205         associatedFontElement->collectGlyphsForString(remainingTextInRun, glyphs);
206
207     size_t glyphsSize = glyphs.size();
208     for (size_t i = 0; i < glyphsSize; ++i) {
209         SVGGlyph& svgGlyph = glyphs[i];
210         if (svgGlyph.isPartOfLigature)
211             continue;
212         if (!isCompatibleGlyph(svgGlyph, isVerticalText, language, arabicForms, currentCharacter, currentCharacter + svgGlyph.unicodeStringLength))
213             continue;
214         iterator.setLastGlyphName(svgGlyph.glyphName);
215         glyphData.glyph = svgGlyph.tableEntry;
216         advanceLength = svgGlyph.unicodeStringLength;
217         return true;
218     }
219
220     iterator.setLastGlyphName(String());
221     return false;
222 }
223
224 bool SVGFontData::fillSVGGlyphPage(GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) const
225 {
226     ASSERT(fontData->isCustomFont());
227     ASSERT(fontData->isSVGFont());
228
229     SVGFontFaceElement* fontFaceElement = this->svgFontFaceElement();
230     ASSERT(fontFaceElement);
231
232     SVGFontElement* fontElement = fontFaceElement->associatedFontElement();
233     ASSERT(fontElement);
234
235     if (bufferLength == length)
236         return fillBMPGlyphs(fontElement, pageToFill, offset, length, buffer, fontData);
237
238     ASSERT(bufferLength == 2 * length);
239     return fillNonBMPGlyphs(fontElement, pageToFill, offset, length, buffer, fontData);
240 }
241
242 bool SVGFontData::fillBMPGlyphs(SVGFontElement* fontElement, GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, const SimpleFontData* fontData) const
243 {
244     bool haveGlyphs = false;
245     Vector<SVGGlyph> glyphs;
246     for (unsigned i = 0; i < length; ++i) {
247         String lookupString(buffer + i, 1);
248         fontElement->collectGlyphsForString(lookupString, glyphs);
249         if (glyphs.isEmpty()) {
250             pageToFill->setGlyphDataForIndex(offset + i, 0, 0);
251             continue;
252         }
253
254         // Associate entry in glyph page with first valid SVGGlyph.
255         // If there are multiple valid ones, just take the first one. WidthIterator will take
256         // care of matching to the correct glyph, if multiple ones are available, as that's
257         // only possible within the context of a string (eg. arabic form matching).
258         haveGlyphs = true;
259         pageToFill->setGlyphDataForIndex(offset + i, glyphs.first().tableEntry, fontData);
260         glyphs.clear();
261     }
262
263     return haveGlyphs;
264 }
265
266 bool SVGFontData::fillNonBMPGlyphs(SVGFontElement* fontElement, GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, const SimpleFontData* fontData) const
267 {
268     bool haveGlyphs = false;
269     Vector<SVGGlyph> glyphs;
270     for (unsigned i = 0; i < length; ++i) {
271         // Each character here consists of a surrogate pair
272         String lookupString(buffer + i * 2, 2);
273         fontElement->collectGlyphsForString(lookupString, glyphs);
274         if (glyphs.isEmpty()) {
275             pageToFill->setGlyphDataForIndex(offset + i, 0, 0);
276             continue;
277         }
278
279         // Associate entry in glyph page with first valid SVGGlyph.
280         // If there are multiple valid ones, just take the first one. WidthIterator will take
281         // care of matching to the correct glyph, if multiple ones are available, as that's
282         // only possible within the context of a string (eg. arabic form matching).
283         haveGlyphs = true;
284         pageToFill->setGlyphDataForIndex(offset + i, glyphs.first().tableEntry, fontData);
285         glyphs.clear();
286     }
287
288     return haveGlyphs;
289 }
290
291 String SVGFontData::createStringWithMirroredCharacters(const UChar* characters, unsigned length) const
292 {
293     StringBuilder mirroredCharacters;
294     mirroredCharacters.reserveCapacity(length);
295
296     unsigned i = 0;
297     while (i < length) {
298         UChar32 character;
299         U16_NEXT(characters, i, length, character);
300         mirroredCharacters.append(mirroredChar(character));
301     }
302
303     return mirroredCharacters.toString();
304 }
305
306 } // namespace WebCore
307
308 #endif