Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(211)

Side by Side Diff: Source/core/svg/SVGFontData.cpp

Issue 656913006: Remove SVG fonts (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Update tests for landing Created 6 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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/shaping/SimpleShaper.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)->pag e();
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 * asc ent / 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(numeral ZeroGlyph) : fontData->spaceWidth());
119
120 // Estimate maximum character width.
121 Glyph letterWGlyph = glyphPageZero->glyphForCharacter('W');
122 fontData->setMaxCharWidth(letterWGlyph ? fontData->widthForGlyph(letterWGlyp h) : 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 => Rende rView::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 associatedFontEle ment's one.
139 if (!svgFontFaceElement->inDocument())
140 return m_horizontalAdvanceX * scaleEmToUnits(fontSize, svgFontFaceElemen t->unitsPerEm());
141
142 SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontEl ement();
143 ASSERT(associatedFontElement);
144
145 SVGGlyph svgGlyph = associatedFontElement->svgGlyphForGlyph(glyph);
146 SVGGlyphElement::inheritUnspecifiedAttributes(svgGlyph, this);
147 return svgGlyph.horizontalAdvanceX * scaleEmToUnits(fontSize, svgFontFaceEle ment->unitsPerEm());
148 }
149
150 bool SVGFontData::applySVGGlyphSelection(SimpleShaper& shaper, GlyphData& glyphD ata, bool mirror, int currentCharacter, unsigned& advanceLength) const
151 {
152 const TextRun& run = shaper.run();
153 Vector<SVGGlyph::ArabicForm>& arabicForms = shaper.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.charactersL ength() - currentCharacter);
161 remainingTextInRun = Character::normalizeSpaces(remainingTextInRun.chara cters8(), remainingTextInRun.length());
162 } else {
163 remainingTextInRun = String(run.data16(currentCharacter), run.characters Length() - currentCharacter);
164 remainingTextInRun = Character::normalizeSpaces(remainingTextInRun.chara cters16(), remainingTextInRun.length());
165 }
166
167 if (mirror)
168 remainingTextInRun = createStringWithMirroredCharacters(remainingTextInR un);
169 if (!currentCharacter && arabicForms.isEmpty())
170 arabicForms = charactersWithArabicForm(remainingTextInRun, mirror);
171
172 SVGFontFaceElement* svgFontFaceElement = this->svgFontFaceElement();
173 SVGFontElement* associatedFontElement = svgFontFaceElement->associatedFontEl ement();
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().isVerticalWriti ngMode();
189 if (Element* parentRenderObjectElement = toElement(parentRenderObject->n ode())) {
190 language = parentRenderObjectElement->getAttribute(XMLNames::langAtt r);
191
192 if (isSVGAltGlyphElement(*parentRenderObjectElement)) {
193 if (!toSVGAltGlyphElement(*parentRenderObjectElement).hasValidGl yphElements(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(altGlyphNam es[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 incompatib le.
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, unsig ned 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, fo ntData);
247
248 ASSERT(bufferLength == 2 * length);
249 return fillNonBMPGlyphs(fontElement, pageToFill, offset, length, buffer, fon tData);
250 }
251
252 bool SVGFontData::fillBMPGlyphs(SVGFontElement* fontElement, GlyphPage* pageToFi ll, unsigned offset, unsigned length, UChar* buffer, const SimpleFontData* fontD ata) 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. SimpleShap er 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 matchin g).
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* pageT oFill, unsigned offset, unsigned length, UChar* buffer, const SimpleFontData* fo ntData) 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. SimpleShap er 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 matchin g).
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) con st
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 SVGFont FaceElement.
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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698