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