]>
Commit | Line | Data |
---|---|---|
a90939db JF |
1 | /* |
2 | * This file is part of the WebKit project. | |
3 | * | |
4 | * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> | |
5 | * | |
6 | * This library is free software; you can redistribute it and/or | |
7 | * modify it under the terms of the GNU Library General Public | |
8 | * License as published by the Free Software Foundation; either | |
9 | * version 2 of the License, or (at your option) any later version. | |
10 | * | |
11 | * This library is distributed in the hope that it will be useful, | |
12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
14 | * Library General Public License for more details. | |
15 | * | |
16 | * You should have received a copy of the GNU Library General Public License | |
17 | * along with this library; see the file COPYING.LIB. If not, write to | |
18 | * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | |
19 | * Boston, MA 02110-1301, USA. | |
20 | * | |
21 | */ | |
22 | ||
23 | #ifndef SVGCharacterLayoutInfo_h | |
24 | #define SVGCharacterLayoutInfo_h | |
25 | ||
26 | #if ENABLE(SVG) | |
27 | #include <wtf/Assertions.h> | |
28 | #include <wtf/HashMap.h> | |
29 | #include <wtf/HashSet.h> | |
30 | #include <wtf/Vector.h> | |
31 | ||
32 | #include "TransformationMatrix.h" | |
33 | #include <wtf/RefCounted.h> | |
34 | #include "SVGRenderStyle.h" | |
35 | #include "SVGTextContentElement.h" | |
36 | ||
37 | namespace WebCore { | |
38 | ||
39 | class InlineBox; | |
40 | class InlineFlowBox; | |
41 | class SVGInlineTextBox; | |
42 | class SVGLengthList; | |
43 | class SVGNumberList; | |
44 | class SVGTextPositioningElement; | |
45 | ||
46 | template<class Type> | |
47 | class PositionedVector : public Vector<Type> | |
48 | { | |
49 | public: | |
50 | PositionedVector<Type>() | |
51 | : m_position(0) | |
52 | { | |
53 | } | |
54 | ||
55 | unsigned position() const | |
56 | { | |
57 | return m_position; | |
58 | } | |
59 | ||
60 | void advance(unsigned position) | |
61 | { | |
62 | m_position += position; | |
63 | ASSERT(m_position < Vector<Type>::size()); | |
64 | } | |
65 | ||
66 | Type valueAtCurrentPosition() const | |
67 | { | |
68 | ASSERT(m_position < Vector<Type>::size()); | |
69 | return Vector<Type>::at(m_position); | |
70 | } | |
71 | ||
72 | private: | |
73 | unsigned m_position; | |
74 | }; | |
75 | ||
76 | class PositionedFloatVector : public PositionedVector<float> { }; | |
77 | struct SVGChar; | |
78 | ||
79 | struct SVGCharacterLayoutInfo { | |
80 | SVGCharacterLayoutInfo(Vector<SVGChar>&); | |
81 | ||
82 | enum StackType { XStack, YStack, DxStack, DyStack, AngleStack, BaselineShiftStack }; | |
83 | ||
84 | bool xValueAvailable() const; | |
85 | bool yValueAvailable() const; | |
86 | bool dxValueAvailable() const; | |
87 | bool dyValueAvailable() const; | |
88 | bool angleValueAvailable() const; | |
89 | bool baselineShiftValueAvailable() const; | |
90 | ||
91 | float xValueNext() const; | |
92 | float yValueNext() const; | |
93 | float dxValueNext() const; | |
94 | float dyValueNext() const; | |
95 | float angleValueNext() const; | |
96 | float baselineShiftValueNext() const; | |
97 | ||
98 | void processedChunk(float savedShiftX, float savedShiftY); | |
99 | void processedSingleCharacter(); | |
100 | ||
101 | bool nextPathLayoutPointAndAngle(float glyphAdvance, float extraAdvance, float newOffset); | |
102 | ||
103 | // Used for text-on-path. | |
104 | void addLayoutInformation(InlineFlowBox*, float textAnchorOffset = 0.0f); | |
105 | ||
106 | bool inPathLayout() const; | |
107 | void setInPathLayout(bool value); | |
108 | ||
109 | // Used for anything else. | |
110 | void addLayoutInformation(SVGTextPositioningElement*); | |
111 | ||
112 | // Global position | |
113 | float curx; | |
114 | float cury; | |
115 | ||
116 | // Global rotation | |
117 | float angle; | |
118 | ||
119 | // Accumulated dx/dy values | |
120 | float dx; | |
121 | float dy; | |
122 | ||
123 | // Accumulated baseline-shift values | |
124 | float shiftx; | |
125 | float shifty; | |
126 | ||
127 | // Path specific advance values to handle lengthAdjust | |
128 | float pathExtraAdvance; | |
129 | float pathTextLength; | |
130 | float pathChunkLength; | |
131 | ||
132 | // Result vector | |
133 | Vector<SVGChar>& svgChars; | |
134 | bool nextDrawnSeperated : 1; | |
135 | ||
136 | private: | |
137 | // Used for baseline-shift. | |
138 | void addStackContent(StackType, float); | |
139 | ||
140 | // Used for angle. | |
141 | void addStackContent(StackType, SVGNumberList*); | |
142 | ||
143 | // Used for x/y/dx/dy. | |
144 | void addStackContent(StackType, SVGLengthList*, const SVGElement*); | |
145 | ||
146 | void addStackContent(StackType, const PositionedFloatVector&); | |
147 | ||
148 | void xStackWalk(); | |
149 | void yStackWalk(); | |
150 | void dxStackWalk(); | |
151 | void dyStackWalk(); | |
152 | void angleStackWalk(); | |
153 | void baselineShiftStackWalk(); | |
154 | ||
155 | private: | |
156 | bool xStackChanged : 1; | |
157 | bool yStackChanged : 1; | |
158 | bool dxStackChanged : 1; | |
159 | bool dyStackChanged : 1; | |
160 | bool angleStackChanged : 1; | |
161 | bool baselineShiftStackChanged : 1; | |
162 | ||
163 | // text on path layout | |
164 | bool pathLayout : 1; | |
165 | float currentOffset; | |
166 | float startOffset; | |
167 | float layoutPathLength; | |
168 | Path layoutPath; | |
169 | ||
170 | Vector<PositionedFloatVector> xStack; | |
171 | Vector<PositionedFloatVector> yStack; | |
172 | Vector<PositionedFloatVector> dxStack; | |
173 | Vector<PositionedFloatVector> dyStack; | |
174 | Vector<PositionedFloatVector> angleStack; | |
175 | Vector<float> baselineShiftStack; | |
176 | }; | |
177 | ||
178 | // Holds extra data, when the character is laid out on a path | |
179 | struct SVGCharOnPath : RefCounted<SVGCharOnPath> { | |
180 | static PassRefPtr<SVGCharOnPath> create() { return adoptRef(new SVGCharOnPath); } | |
181 | ||
182 | float xScale; | |
183 | float yScale; | |
184 | ||
185 | float xShift; | |
186 | float yShift; | |
187 | ||
188 | float orientationAngle; | |
189 | ||
190 | bool hidden : 1; | |
191 | ||
192 | private: | |
193 | SVGCharOnPath() | |
194 | : xScale(1.0f) | |
195 | , yScale(1.0f) | |
196 | , xShift(0.0f) | |
197 | , yShift(0.0f) | |
198 | , orientationAngle(0.0f) | |
199 | , hidden(false) | |
200 | { | |
201 | } | |
202 | }; | |
203 | ||
204 | struct SVGChar { | |
205 | SVGChar() | |
206 | : x(0.0f) | |
207 | , y(0.0f) | |
208 | , angle(0.0f) | |
209 | , orientationShiftX(0.0f) | |
210 | , orientationShiftY(0.0f) | |
211 | , pathData() | |
212 | , drawnSeperated(false) | |
213 | , newTextChunk(false) | |
214 | { | |
215 | } | |
216 | ||
217 | ~SVGChar() | |
218 | { | |
219 | } | |
220 | ||
221 | float x; | |
222 | float y; | |
223 | float angle; | |
224 | ||
225 | float orientationShiftX; | |
226 | float orientationShiftY; | |
227 | ||
228 | RefPtr<SVGCharOnPath> pathData; | |
229 | ||
230 | // Determines wheter this char needs to be drawn seperated | |
231 | bool drawnSeperated : 1; | |
232 | ||
233 | // Determines wheter this char starts a new chunk | |
234 | bool newTextChunk : 1; | |
235 | ||
236 | // Helper methods | |
237 | bool isHidden() const; | |
238 | TransformationMatrix characterTransform() const; | |
239 | }; | |
240 | ||
241 | struct SVGInlineBoxCharacterRange { | |
242 | SVGInlineBoxCharacterRange() | |
243 | : startOffset(INT_MIN) | |
244 | , endOffset(INT_MIN) | |
245 | , box(0) | |
246 | { | |
247 | } | |
248 | ||
249 | bool isOpen() const { return (startOffset == endOffset) && (endOffset == INT_MIN); } | |
250 | bool isClosed() const { return startOffset != INT_MIN && endOffset != INT_MIN; } | |
251 | ||
252 | int startOffset; | |
253 | int endOffset; | |
254 | ||
255 | InlineBox* box; | |
256 | }; | |
257 | ||
258 | // Convenience typedef | |
259 | typedef SVGTextContentElement::SVGLengthAdjustType ELengthAdjust; | |
260 | ||
261 | struct SVGTextChunk { | |
262 | SVGTextChunk() | |
263 | : anchor(TA_START) | |
264 | , textLength(0.0f) | |
265 | , lengthAdjust(SVGTextContentElement::LENGTHADJUST_SPACING) | |
266 | , ctm() | |
267 | , isVerticalText(false) | |
268 | , isTextPath(false) | |
269 | , start(0) | |
270 | , end(0) | |
271 | { } | |
272 | ||
273 | // text-anchor support | |
274 | ETextAnchor anchor; | |
275 | ||
276 | // textLength & lengthAdjust support | |
277 | float textLength; | |
278 | ELengthAdjust lengthAdjust; | |
279 | TransformationMatrix ctm; | |
280 | ||
281 | // status flags | |
282 | bool isVerticalText : 1; | |
283 | bool isTextPath : 1; | |
284 | ||
285 | // main chunk data | |
286 | Vector<SVGChar>::iterator start; | |
287 | Vector<SVGChar>::iterator end; | |
288 | ||
289 | Vector<SVGInlineBoxCharacterRange> boxes; | |
290 | }; | |
291 | ||
292 | struct SVGTextChunkWalkerBase { | |
293 | virtual ~SVGTextChunkWalkerBase() { } | |
294 | ||
295 | virtual void operator()(SVGInlineTextBox* textBox, int startOffset, const TransformationMatrix& chunkCtm, | |
296 | const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end) = 0; | |
297 | ||
298 | // Followings methods are only used for painting text chunks | |
299 | virtual void start(InlineBox*) = 0; | |
300 | virtual void end(InlineBox*) = 0; | |
301 | ||
302 | virtual bool setupFill(InlineBox*) = 0; | |
303 | virtual bool setupStroke(InlineBox*) = 0; | |
304 | }; | |
305 | ||
306 | template<typename CallbackClass> | |
307 | struct SVGTextChunkWalker : public SVGTextChunkWalkerBase { | |
308 | public: | |
309 | typedef void (CallbackClass::*SVGTextChunkWalkerCallback)(SVGInlineTextBox* textBox, | |
310 | int startOffset, | |
311 | const TransformationMatrix& chunkCtm, | |
312 | const Vector<SVGChar>::iterator& start, | |
313 | const Vector<SVGChar>::iterator& end); | |
314 | ||
315 | // These callbacks are only used for painting! | |
316 | typedef void (CallbackClass::*SVGTextChunkStartCallback)(InlineBox* box); | |
317 | typedef void (CallbackClass::*SVGTextChunkEndCallback)(InlineBox* box); | |
318 | ||
319 | typedef bool (CallbackClass::*SVGTextChunkSetupFillCallback)(InlineBox* box); | |
320 | typedef bool (CallbackClass::*SVGTextChunkSetupStrokeCallback)(InlineBox* box); | |
321 | ||
322 | SVGTextChunkWalker(CallbackClass* object, | |
323 | SVGTextChunkWalkerCallback walker, | |
324 | SVGTextChunkStartCallback start = 0, | |
325 | SVGTextChunkEndCallback end = 0, | |
326 | SVGTextChunkSetupFillCallback fill = 0, | |
327 | SVGTextChunkSetupStrokeCallback stroke = 0) | |
328 | : m_object(object) | |
329 | , m_walkerCallback(walker) | |
330 | , m_startCallback(start) | |
331 | , m_endCallback(end) | |
332 | , m_setupFillCallback(fill) | |
333 | , m_setupStrokeCallback(stroke) | |
334 | { | |
335 | ASSERT(object); | |
336 | ASSERT(walker); | |
337 | } | |
338 | ||
339 | virtual void operator()(SVGInlineTextBox* textBox, int startOffset, const TransformationMatrix& chunkCtm, | |
340 | const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end) | |
341 | { | |
342 | (*m_object.*m_walkerCallback)(textBox, startOffset, chunkCtm, start, end); | |
343 | } | |
344 | ||
345 | // Followings methods are only used for painting text chunks | |
346 | virtual void start(InlineBox* box) | |
347 | { | |
348 | if (m_startCallback) | |
349 | (*m_object.*m_startCallback)(box); | |
350 | else | |
351 | ASSERT_NOT_REACHED(); | |
352 | } | |
353 | ||
354 | virtual void end(InlineBox* box) | |
355 | { | |
356 | if (m_endCallback) | |
357 | (*m_object.*m_endCallback)(box); | |
358 | else | |
359 | ASSERT_NOT_REACHED(); | |
360 | } | |
361 | ||
362 | virtual bool setupFill(InlineBox* box) | |
363 | { | |
364 | if (m_setupFillCallback) | |
365 | return (*m_object.*m_setupFillCallback)(box); | |
366 | ||
367 | ASSERT_NOT_REACHED(); | |
368 | return false; | |
369 | } | |
370 | ||
371 | virtual bool setupStroke(InlineBox* box) | |
372 | { | |
373 | if (m_setupStrokeCallback) | |
374 | return (*m_object.*m_setupStrokeCallback)(box); | |
375 | ||
376 | ASSERT_NOT_REACHED(); | |
377 | return false; | |
378 | } | |
379 | ||
380 | private: | |
381 | CallbackClass* m_object; | |
382 | SVGTextChunkWalkerCallback m_walkerCallback; | |
383 | SVGTextChunkStartCallback m_startCallback; | |
384 | SVGTextChunkEndCallback m_endCallback; | |
385 | SVGTextChunkSetupFillCallback m_setupFillCallback; | |
386 | SVGTextChunkSetupStrokeCallback m_setupStrokeCallback; | |
387 | }; | |
388 | ||
389 | struct SVGTextChunkLayoutInfo { | |
390 | SVGTextChunkLayoutInfo(Vector<SVGTextChunk>& textChunks) | |
391 | : assignChunkProperties(true) | |
392 | , handlingTextPath(false) | |
393 | , svgTextChunks(textChunks) | |
394 | , it(0) | |
395 | { | |
396 | } | |
397 | ||
398 | bool assignChunkProperties : 1; | |
399 | bool handlingTextPath : 1; | |
400 | ||
401 | Vector<SVGTextChunk>& svgTextChunks; | |
402 | Vector<SVGChar>::iterator it; | |
403 | ||
404 | SVGTextChunk chunk; | |
405 | }; | |
406 | ||
407 | struct SVGTextDecorationInfo { | |
408 | // ETextDecoration is meant to be used here | |
409 | HashMap<int, RenderObject*> fillServerMap; | |
410 | HashMap<int, RenderObject*> strokeServerMap; | |
411 | }; | |
412 | ||
413 | } // namespace WebCore | |
414 | ||
415 | #endif // ENABLE(SVG) | |
416 | #endif // SVGCharacterLayoutInfo_h |