Upstream version 11.39.266.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / 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 "core/svg/SVGFontData.h"
24
25 #include "core/SVGNames.h"
26 #include "core/XMLNames.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"
41
42 using namespace WTF;
43 using namespace Unicode;
44
45 namespace blink {
46
47 SVGFontData::SVGFontData(SVGFontFaceElement* fontFaceElement)
48     : CustomFontData()
49     , m_svgFontFaceElement(fontFaceElement->createWeakRef())
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())
56 {
57     ASSERT_ARG(fontFaceElement, fontFaceElement);
58 }
59
60 SVGFontData::~SVGFontData()
61 {
62 }
63
64 void SVGFontData::initializeFontData(SimpleFontData* fontData, float fontSize)
65 {
66     ASSERT(fontData);
67
68     SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement();
69
70     SVGFontElement* svgFontElement = svgFontFaceElement->associatedFontElement();
71     ASSERT(svgFontElement);
72     GlyphData missingGlyphData;
73     missingGlyphData.fontData = fontData;
74     missingGlyphData.glyph = svgFontElement->missingGlyph();
75     fontData->setMissingGlyphData(missingGlyphData);
76
77     fontData->setZeroWidthSpaceGlyph(0);
78     fontData->determinePitch();
79
80     unsigned unitsPerEm = svgFontFaceElement->unitsPerEm();
81     float scale = scaleEmToUnits(fontSize, unitsPerEm);
82     float xHeight = svgFontFaceElement->xHeight() * scale;
83     float ascent = svgFontFaceElement->ascent() * scale;
84     float descent = svgFontFaceElement->descent() * scale;
85     float lineGap = 0.1f * fontSize;
86
87     GlyphPage* glyphPageZero = GlyphPageTreeNode::getRootChild(fontData, 0)->page();
88
89     if (!xHeight && glyphPageZero) {
90         // Fallback if x_heightAttr is not specified for the font element.
91         Glyph letterXGlyph = glyphPageZero->glyphForCharacter('x');
92         xHeight = letterXGlyph ? fontData->widthForGlyph(letterXGlyph) : 2 * ascent / 3;
93     }
94
95     FontMetrics& fontMetrics = fontData->fontMetrics();
96     fontMetrics.setUnitsPerEm(unitsPerEm);
97     fontMetrics.setAscent(ascent);
98     fontMetrics.setDescent(descent);
99     fontMetrics.setLineGap(lineGap);
100     fontMetrics.setLineSpacing(roundf(ascent) + roundf(descent) + roundf(lineGap));
101     fontMetrics.setXHeight(xHeight);
102
103     if (!glyphPageZero) {
104         fontData->setSpaceGlyph(0);
105         fontData->setSpaceWidth(0);
106         fontData->setAvgCharWidth(0);
107         fontData->setMaxCharWidth(ascent);
108         return;
109     }
110
111     // Calculate space width.
112     Glyph spaceGlyph = glyphPageZero->glyphForCharacter(' ');
113     fontData->setSpaceGlyph(spaceGlyph);
114     fontData->setSpaceWidth(fontData->widthForGlyph(spaceGlyph));
115
116     // Estimate average character width.
117     Glyph numeralZeroGlyph = glyphPageZero->glyphForCharacter('0');
118     fontData->setAvgCharWidth(numeralZeroGlyph ? fontData->widthForGlyph(numeralZeroGlyph) : fontData->spaceWidth());
119
120     // Estimate maximum character width.
121     Glyph letterWGlyph = glyphPageZero->glyphForCharacter('W');
122     fontData->setMaxCharWidth(letterWGlyph ? fontData->widthForGlyph(letterWGlyph) : ascent);
123 }
124
125 float SVGFontData::widthForSVGGlyph(Glyph glyph, float fontSize) const
126 {
127     // FIXME: (http://crbug.com/359380) Width calculation may be triggered after removeNode from the current editing impl.
128     // The retrieved width is not being used, so here we return a dummy value.
129     if (shouldSkipDrawing())
130         return 0.0;
131
132     SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement();
133
134     // RenderView::clearSelection is invoked while removing some element, e.g.
135     // Document::nodeWillBeRemoved => FrameSelection::nodeWillBeRemoved => RenderView::clearSelection.
136     // Since recalc style has not been executed yet, RenderStyle might have some reference to
137     // SVGFontFaceElement which was also removed.
138     // In this case, use default horizontalAdvanceX instead of associatedFontElement's one.
139     if (!svgFontFaceElement->inDocument())
140         return m_horizontalAdvanceX * scaleEmToUnits(fontSize, svgFontFaceElement->unitsPerEm());
141
142     SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement();
143     ASSERT(associatedFontElement);
144
145     SVGGlyph svgGlyph = associatedFontElement->svgGlyphForGlyph(glyph);
146     SVGGlyphElement::inheritUnspecifiedAttributes(svgGlyph, this);
147     return svgGlyph.horizontalAdvanceX * scaleEmToUnits(fontSize, svgFontFaceElement->unitsPerEm());
148 }
149
150 bool SVGFontData::applySVGGlyphSelection(WidthIterator& iterator, GlyphData& glyphData, bool mirror, int currentCharacter, unsigned& advanceLength) const
151 {
152     const TextRun& run = iterator.run();
153     Vector<SVGGlyph::ArabicForm>& arabicForms = iterator.arabicForms();
154     ASSERT(int(run.charactersLength()) >= currentCharacter);
155
156     // Associate text with arabic forms, if needed.
157     String remainingTextInRun;
158
159     if (run.is8Bit()) {
160         remainingTextInRun = String(run.data8(currentCharacter), run.charactersLength() - currentCharacter);
161         remainingTextInRun = Character::normalizeSpaces(remainingTextInRun.characters8(), remainingTextInRun.length());
162     } else {
163         remainingTextInRun = String(run.data16(currentCharacter), run.charactersLength() - currentCharacter);
164         remainingTextInRun = Character::normalizeSpaces(remainingTextInRun.characters16(), remainingTextInRun.length());
165     }
166
167     if (mirror)
168         remainingTextInRun = createStringWithMirroredCharacters(remainingTextInRun);
169     if (!currentCharacter && arabicForms.isEmpty())
170         arabicForms = charactersWithArabicForm(remainingTextInRun, mirror);
171
172     SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement();
173     SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontElement();
174     ASSERT(associatedFontElement);
175
176     RenderObject* renderObject = 0;
177     if (TextRun::RenderingContext* renderingContext = run.renderingContext())
178         renderObject = static_cast<SVGTextRunRenderingContext*>(renderingContext)->renderer();
179
180     String language;
181     bool isVerticalText = false;
182     Vector<AtomicString> altGlyphNames;
183
184     if (renderObject) {
185         RenderObject* parentRenderObject = renderObject->isText() ? renderObject->parent() : renderObject;
186         ASSERT(parentRenderObject);
187
188         isVerticalText = parentRenderObject->style()->svgStyle().isVerticalWritingMode();
189         if (Element* parentRenderObjectElement = toElement(parentRenderObject->node())) {
190             language = parentRenderObjectElement->getAttribute(XMLNames::langAttr);
191
192             if (isSVGAltGlyphElement(*parentRenderObjectElement)) {
193                 if (!toSVGAltGlyphElement(*parentRenderObjectElement).hasValidGlyphElements(altGlyphNames))
194                     altGlyphNames.clear();
195             }
196         }
197     }
198
199     Vector<SVGGlyph> glyphs;
200     size_t altGlyphNamesSize = altGlyphNames.size();
201     if (altGlyphNamesSize) {
202         for (size_t index = 0; index < altGlyphNamesSize; ++index)
203             associatedFontElement->collectGlyphsForAltGlyphReference(altGlyphNames[index], glyphs);
204
205         // Assign the unicodeStringLength now that its known.
206         size_t glyphsSize = glyphs.size();
207         for (size_t i = 0; i < glyphsSize; ++i)
208             glyphs[i].unicodeStringLength = run.length();
209
210         // Do not check alt glyphs for compatibility. Just return the first one.
211         // Later code will fail if we do not do this and the glyph is incompatible.
212         if (glyphsSize) {
213             SVGGlyph& svgGlyph = glyphs[0];
214             glyphData.glyph = svgGlyph.tableEntry;
215             advanceLength = svgGlyph.unicodeStringLength;
216             return true;
217         }
218     } else
219         associatedFontElement->collectGlyphsForString(remainingTextInRun, glyphs);
220
221     size_t glyphsSize = glyphs.size();
222     for (size_t i = 0; i < glyphsSize; ++i) {
223         SVGGlyph& svgGlyph = glyphs[i];
224         if (svgGlyph.isPartOfLigature)
225             continue;
226         if (!isCompatibleGlyph(svgGlyph, isVerticalText, language, arabicForms, currentCharacter, currentCharacter + svgGlyph.unicodeStringLength))
227             continue;
228         glyphData.glyph = svgGlyph.tableEntry;
229         advanceLength = svgGlyph.unicodeStringLength;
230         return true;
231     }
232
233     return false;
234 }
235
236 bool SVGFontData::fillSVGGlyphPage(GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, unsigned bufferLength, const SimpleFontData* fontData) const
237 {
238     ASSERT(fontData->isCustomFont());
239     ASSERT(fontData->isSVGFont());
240
241     SVGFontFaceElement* fontFaceElement = this->svgFontFaceElement();
242     SVGFontElement* fontElement = fontFaceElement->associatedFontElement();
243     ASSERT(fontElement);
244
245     if (bufferLength == length)
246         return fillBMPGlyphs(fontElement, pageToFill, offset, length, buffer, fontData);
247
248     ASSERT(bufferLength == 2 * length);
249     return fillNonBMPGlyphs(fontElement, pageToFill, offset, length, buffer, fontData);
250 }
251
252 bool SVGFontData::fillBMPGlyphs(SVGFontElement* fontElement, GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, const SimpleFontData* fontData) const
253 {
254     bool haveGlyphs = false;
255     Vector<SVGGlyph> glyphs;
256     for (unsigned i = 0; i < length; ++i) {
257         String lookupString(buffer + i, 1);
258         fontElement->collectGlyphsForString(lookupString, glyphs);
259         if (glyphs.isEmpty())
260             continue;
261
262         // Associate entry in glyph page with first valid SVGGlyph.
263         // If there are multiple valid ones, just take the first one. WidthIterator will take
264         // care of matching to the correct glyph, if multiple ones are available, as that's
265         // only possible within the context of a string (eg. arabic form matching).
266         haveGlyphs = true;
267         pageToFill->setGlyphDataForIndex(offset + i, glyphs.first().tableEntry, fontData);
268         glyphs.clear();
269     }
270
271     return haveGlyphs;
272 }
273
274 bool SVGFontData::fillNonBMPGlyphs(SVGFontElement* fontElement, GlyphPage* pageToFill, unsigned offset, unsigned length, UChar* buffer, const SimpleFontData* fontData) const
275 {
276     bool haveGlyphs = false;
277     Vector<SVGGlyph> glyphs;
278     for (unsigned i = 0; i < length; ++i) {
279         // Each character here consists of a surrogate pair
280         String lookupString(buffer + i * 2, 2);
281         fontElement->collectGlyphsForString(lookupString, glyphs);
282         if (glyphs.isEmpty())
283             continue;
284
285         // Associate entry in glyph page with first valid SVGGlyph.
286         // If there are multiple valid ones, just take the first one. WidthIterator will take
287         // care of matching to the correct glyph, if multiple ones are available, as that's
288         // only possible within the context of a string (eg. arabic form matching).
289         haveGlyphs = true;
290         pageToFill->setGlyphDataForIndex(offset + i, glyphs.first().tableEntry, fontData);
291         glyphs.clear();
292     }
293
294     return haveGlyphs;
295 }
296
297 String SVGFontData::createStringWithMirroredCharacters(const String& string) const
298 {
299     if (string.isEmpty())
300         return emptyString();
301
302     unsigned length = string.length();
303
304     StringBuilder mirroredCharacters;
305     mirroredCharacters.reserveCapacity(length);
306
307     if (string.is8Bit()) {
308         const LChar* characters = string.characters8();
309         for (unsigned i = 0; i < length; ++i)
310             mirroredCharacters.append(mirroredChar(characters[i]));
311     } else {
312         const UChar* characters = string.characters16();
313         unsigned i = 0;
314         while (i < length) {
315             UChar32 character;
316             U16_NEXT(characters, i, length, character);
317             mirroredCharacters.append(mirroredChar(character));
318         }
319     }
320
321     return mirroredCharacters.toString();
322 }
323
324 SVGFontFaceElement* SVGFontData::svgFontFaceElement() const
325 {
326     // FIXME: SVGFontData should be only used from the document with the SVGFontFaceElement.
327     RELEASE_ASSERT(m_svgFontFaceElement && m_svgFontFaceElement->inDocument());
328     return m_svgFontFaceElement.get();
329 }
330
331 bool SVGFontData::shouldSkipDrawing() const
332 {
333     // FIXME: (http://crbug.com/359380) Glyph may be referenced after removeNode from the current editing impl.
334     return !m_svgFontFaceElement || !m_svgFontFaceElement->inDocument();
335 }
336
337 } // namespace blink
338
339 #endif