OLD | NEW |
| (Empty) |
1 /* | |
2 * Copyright (C) 2007, 2008 Nikolas Zimmermann <zimmermann@kde.org> | |
3 * Copyright (C) Research In Motion Limited 2010-2011. All rights reserved. | |
4 * | |
5 * This library is free software; you can redistribute it and/or | |
6 * modify it under the terms of the GNU Library General Public | |
7 * License as published by the Free Software Foundation; either | |
8 * version 2 of the License, or (at your option) any later version. | |
9 * | |
10 * This library is distributed in the hope that it will be useful, | |
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 * Library General Public License for more details. | |
14 * | |
15 * You should have received a copy of the GNU Library General Public License | |
16 * along with this library; see the file COPYING.LIB. If not, write to | |
17 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | |
18 * Boston, MA 02110-1301, USA. | |
19 */ | |
20 | |
21 #include "config.h" | |
22 | |
23 #if ENABLE(SVG_FONTS) | |
24 #include "core/rendering/svg/SVGTextRunRenderingContext.h" | |
25 | |
26 #include "core/rendering/RenderObject.h" | |
27 #include "core/svg/SVGFontData.h" | |
28 #include "core/svg/SVGFontElement.h" | |
29 #include "core/svg/SVGFontFaceElement.h" | |
30 #include "core/svg/SVGGlyphElement.h" | |
31 #include "platform/fonts/GlyphBuffer.h" | |
32 #include "platform/fonts/shaping/SimpleShaper.h" | |
33 #include "platform/graphics/GraphicsContext.h" | |
34 | |
35 namespace blink { | |
36 | |
37 static inline const SVGFontData* svgFontAndFontFaceElementForFontData(const Simp
leFontData* fontData, SVGFontFaceElement*& fontFace, SVGFontElement*& font) | |
38 { | |
39 ASSERT(fontData); | |
40 ASSERT(fontData->isCustomFont()); | |
41 ASSERT(fontData->isSVGFont()); | |
42 | |
43 RefPtr<CustomFontData> customFontData = fontData->customFontData(); | |
44 const SVGFontData* svgFontData = toSVGFontData(customFontData); | |
45 | |
46 // FIXME crbug.com/359380 : The current editing impl references the font aft
er the svg font nodes are removed. | |
47 if (svgFontData->shouldSkipDrawing()) | |
48 return 0; | |
49 | |
50 fontFace = svgFontData->svgFontFaceElement(); | |
51 ASSERT(fontFace); | |
52 | |
53 font = fontFace->associatedFontElement(); | |
54 return svgFontData; | |
55 } | |
56 | |
57 static inline RenderObject* firstParentRendererForNonTextNode(RenderObject* rend
erer) | |
58 { | |
59 ASSERT(renderer); | |
60 return renderer->isText() ? renderer->parent() : renderer; | |
61 } | |
62 | |
63 static inline RenderObject* renderObjectFromRun(const TextRun& run) | |
64 { | |
65 if (TextRun::RenderingContext* renderingContext = run.renderingContext()) | |
66 return static_cast<SVGTextRunRenderingContext*>(renderingContext)->rende
rer(); | |
67 return 0; | |
68 } | |
69 | |
70 float SVGTextRunRenderingContext::floatWidthUsingSVGFont(const Font& font, const
TextRun& run, int& charsConsumed, Glyph& glyphId) const | |
71 { | |
72 SimpleShaper it(&font, run); | |
73 GlyphBuffer glyphBuffer; | |
74 charsConsumed += it.advance(run.length(), &glyphBuffer); | |
75 glyphId = !glyphBuffer.isEmpty() ? glyphBuffer.glyphAt(0) : 0; | |
76 return it.runWidthSoFar(); | |
77 } | |
78 | |
79 void SVGTextRunRenderingContext::drawSVGGlyphs(GraphicsContext* context, const T
extRun& run, const SimpleFontData* fontData, const GlyphBuffer& glyphBuffer, int
from, int numGlyphs, const FloatPoint& point) const | |
80 { | |
81 SVGFontElement* fontElement = 0; | |
82 SVGFontFaceElement* fontFaceElement = 0; | |
83 | |
84 const SVGFontData* svgFontData = svgFontAndFontFaceElementForFontData(fontDa
ta, fontFaceElement, fontElement); | |
85 if (!fontElement || !fontFaceElement) | |
86 return; | |
87 | |
88 // We can only paint SVGFonts if a context is available. | |
89 RenderObject* renderObject = renderObjectFromRun(run); | |
90 ASSERT(renderObject); | |
91 | |
92 bool isVerticalText = false; | |
93 if (RenderObject* parentRenderObject = firstParentRendererForNonTextNode(ren
derObject)) { | |
94 RenderStyle* parentRenderObjectStyle = parentRenderObject->style(); | |
95 ASSERT(parentRenderObjectStyle); | |
96 isVerticalText = parentRenderObjectStyle->svgStyle().isVerticalWritingMo
de(); | |
97 } | |
98 | |
99 float scale = scaleEmToUnits(fontData->platformData().size(), fontFaceElemen
t->unitsPerEm()); | |
100 | |
101 FloatPoint glyphOrigin; | |
102 glyphOrigin.setX(svgFontData->horizontalOriginX() * scale); | |
103 glyphOrigin.setY(svgFontData->horizontalOriginY() * scale); | |
104 | |
105 FloatPoint currentPoint = point; | |
106 for (int i = 0; i < numGlyphs; ++i) { | |
107 Glyph glyph = glyphBuffer.glyphAt(from + i); | |
108 if (!glyph) | |
109 continue; | |
110 | |
111 float advance = glyphBuffer.advanceAt(from + i); | |
112 SVGGlyph svgGlyph = fontElement->svgGlyphForGlyph(glyph); | |
113 ASSERT(!svgGlyph.isPartOfLigature); | |
114 ASSERT(svgGlyph.tableEntry == glyph); | |
115 | |
116 SVGGlyphElement::inheritUnspecifiedAttributes(svgGlyph, svgFontData); | |
117 | |
118 // FIXME: Support arbitary SVG content as glyph (currently limited to <g
lyph d="..."> situations). | |
119 if (svgGlyph.pathData.isEmpty()) { | |
120 if (isVerticalText) | |
121 currentPoint.move(0, advance); | |
122 else | |
123 currentPoint.move(advance, 0); | |
124 continue; | |
125 } | |
126 | |
127 if (isVerticalText) { | |
128 glyphOrigin.setX(svgGlyph.verticalOriginX * scale); | |
129 glyphOrigin.setY(svgGlyph.verticalOriginY * scale); | |
130 } | |
131 | |
132 AffineTransform glyphPathTransform; | |
133 glyphPathTransform.translate(currentPoint.x() + glyphOrigin.x(), current
Point.y() + glyphOrigin.y()); | |
134 glyphPathTransform.scale(scale, -scale); | |
135 | |
136 Path glyphPath = svgGlyph.pathData; | |
137 glyphPath.transform(glyphPathTransform); | |
138 | |
139 if (context->textDrawingMode() == TextModeStroke) | |
140 context->strokePath(glyphPath); | |
141 else | |
142 context->fillPath(glyphPath); | |
143 | |
144 if (isVerticalText) | |
145 currentPoint.move(0, advance); | |
146 else | |
147 currentPoint.move(advance, 0); | |
148 } | |
149 } | |
150 | |
151 GlyphData SVGTextRunRenderingContext::glyphDataForCharacter(const Font& font, co
nst TextRun& run, SimpleShaper& iterator, UChar32 character, bool mirror, int cu
rrentCharacter, unsigned& advanceLength) | |
152 { | |
153 const SimpleFontData* primaryFont = font.primaryFont(); | |
154 ASSERT(primaryFont); | |
155 | |
156 pair<GlyphData, GlyphPage*> pair = font.glyphDataAndPageForCharacter(charact
er, mirror); | |
157 GlyphData glyphData = pair.first; | |
158 | |
159 // Check if we have the missing glyph data, in which case we can just return
. | |
160 GlyphData missingGlyphData = primaryFont->missingGlyphData(); | |
161 if (glyphData.glyph == missingGlyphData.glyph && glyphData.fontData == missi
ngGlyphData.fontData) { | |
162 ASSERT(glyphData.fontData); | |
163 return glyphData; | |
164 } | |
165 | |
166 // Save data fromt he font fallback list because we may modify it later. Do
this before the | |
167 // potential change to glyphData.fontData below. | |
168 FontFallbackList* fontList = font.fontList(); | |
169 ASSERT(fontList); | |
170 FontFallbackList::GlyphPagesStateSaver glyphPagesSaver(*fontList); | |
171 | |
172 // Characters enclosed by an <altGlyph> element, may not be registered in th
e GlyphPage. | |
173 const SimpleFontData* originalFontData = glyphData.fontData; | |
174 if (originalFontData && !originalFontData->isSVGFont()) { | |
175 if (TextRun::RenderingContext* renderingContext = run.renderingContext()
) { | |
176 RenderObject* renderObject = static_cast<SVGTextRunRenderingContext*
>(renderingContext)->renderer(); | |
177 RenderObject* parentRenderObject = renderObject->isText() ? renderOb
ject->parent() : renderObject; | |
178 ASSERT(parentRenderObject); | |
179 if (Element* parentRenderObjectElement = toElement(parentRenderObjec
t->node())) { | |
180 if (isSVGAltGlyphElement(*parentRenderObjectElement)) | |
181 glyphData.fontData = primaryFont; | |
182 } | |
183 } | |
184 } | |
185 | |
186 const SimpleFontData* fontData = glyphData.fontData; | |
187 if (fontData) { | |
188 if (!fontData->isSVGFont()) | |
189 return glyphData; | |
190 | |
191 SVGFontElement* fontElement = 0; | |
192 SVGFontFaceElement* fontFaceElement = 0; | |
193 | |
194 const SVGFontData* svgFontData = svgFontAndFontFaceElementForFontData(fo
ntData, fontFaceElement, fontElement); | |
195 if (!fontElement || !fontFaceElement) | |
196 return glyphData; | |
197 | |
198 // If we got here, we're dealing with a glyph defined in a SVG Font. | |
199 // The returned glyph by glyphDataAndPageForCharacter() is a glyph store
d in the SVG Font glyph table. | |
200 // This doesn't necessarily mean the glyph is suitable for rendering/mea
suring in this context, its | |
201 // arabic-form/orientation/... may not match, we have to apply SVG Glyph
selection to discover that. | |
202 if (svgFontData->applySVGGlyphSelection(iterator, glyphData, mirror, cur
rentCharacter, advanceLength)) | |
203 return glyphData; | |
204 } | |
205 | |
206 GlyphPage* page = pair.second; | |
207 ASSERT(page); | |
208 | |
209 // No suitable glyph found that is compatible with the requirments (same lan
guage, arabic-form, orientation etc.) | |
210 // Even though our GlyphPage contains an entry for eg. glyph "a", it's not c
ompatible. So we have to temporarily | |
211 // remove the glyph data information from the GlyphPage, and retry the looku
p, which handles font fallbacks correctly. | |
212 page->setGlyphDataForCharacter(character, 0, 0); | |
213 | |
214 // Assure that the font fallback glyph selection worked, aka. the fallbackGl
yphData font data is not the same as before. | |
215 GlyphData fallbackGlyphData = font.glyphDataForCharacter(character, mirror); | |
216 ASSERT(fallbackGlyphData.fontData != fontData); | |
217 | |
218 // Restore original state of the SVG Font glyph table and the current font f
allback list, | |
219 // to assure the next lookup of the same glyph won't immediately return the
fallback glyph. | |
220 page->setGlyphDataForCharacter(character, glyphData.glyph, originalFontData)
; | |
221 ASSERT(fallbackGlyphData.fontData); | |
222 return fallbackGlyphData; | |
223 } | |
224 | |
225 } | |
226 | |
227 #endif | |
OLD | NEW |