• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "AffineTransform.h"
28 #include "SVGRenderStyle.h"
29 #include "SVGTextContentElement.h"
30 
31 #include <wtf/Assertions.h>
32 #include <wtf/HashMap.h>
33 #include <wtf/HashSet.h>
34 #include <wtf/RefCounted.h>
35 #include <wtf/Vector.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 public:
49     PositionedVector<Type>()
50         : m_position(0)
51     {
52     }
53 
position()54     unsigned position() const
55     {
56         return m_position;
57     }
58 
advance(unsigned position)59     void advance(unsigned position)
60     {
61         m_position += position;
62         ASSERT(m_position < Vector<Type>::size());
63     }
64 
valueAtCurrentPosition()65     Type valueAtCurrentPosition() const
66     {
67         ASSERT(m_position < Vector<Type>::size());
68         return Vector<Type>::at(m_position);
69     }
70 
71 private:
72     unsigned m_position;
73 };
74 
75 class PositionedFloatVector : public PositionedVector<float> { };
76 struct SVGChar;
77 
78 struct SVGCharacterLayoutInfo {
79     SVGCharacterLayoutInfo(Vector<SVGChar>&);
80 
81     enum StackType { XStack, YStack, DxStack, DyStack, AngleStack, BaselineShiftStack };
82 
83     bool xValueAvailable() const;
84     bool yValueAvailable() const;
85     bool dxValueAvailable() const;
86     bool dyValueAvailable() const;
87     bool angleValueAvailable() const;
88     bool baselineShiftValueAvailable() const;
89 
90     float xValueNext() const;
91     float yValueNext() const;
92     float dxValueNext() const;
93     float dyValueNext() const;
94     float angleValueNext() const;
95     float baselineShiftValueNext() const;
96 
97     void processedChunk(float savedShiftX, float savedShiftY);
98     void processedSingleCharacter();
99 
100     bool nextPathLayoutPointAndAngle(float glyphAdvance, float extraAdvance, float newOffset);
101 
102     // Used for text-on-path.
103     void addLayoutInformation(InlineFlowBox*, float textAnchorOffset = 0.0f);
104 
105     bool inPathLayout() const;
106     void setInPathLayout(bool value);
107 
108     // Used for anything else.
109     void addLayoutInformation(SVGTextPositioningElement*);
110 
111     // Global position
112     float curx;
113     float cury;
114 
115     // Global rotation
116     float angle;
117 
118     // Accumulated dx/dy values
119     float dx;
120     float dy;
121 
122     // Accumulated baseline-shift values
123     float shiftx;
124     float shifty;
125 
126     // Path specific advance values to handle lengthAdjust
127     float pathExtraAdvance;
128     float pathTextLength;
129     float pathChunkLength;
130 
131     // Result vector
132     Vector<SVGChar>& svgChars;
133     bool nextDrawnSeperated : 1;
134 
135 private:
136     // Used for baseline-shift.
137     void addStackContent(StackType, float);
138 
139     // Used for angle.
140     void addStackContent(StackType, SVGNumberList*);
141 
142     // Used for x/y/dx/dy.
143     void addStackContent(StackType, SVGLengthList*, const SVGElement*);
144 
145     void addStackContent(StackType, const PositionedFloatVector&);
146 
147     void xStackWalk();
148     void yStackWalk();
149     void dxStackWalk();
150     void dyStackWalk();
151     void angleStackWalk();
152     void baselineShiftStackWalk();
153 
154 private:
155     bool xStackChanged : 1;
156     bool yStackChanged : 1;
157     bool dxStackChanged : 1;
158     bool dyStackChanged : 1;
159     bool angleStackChanged : 1;
160     bool baselineShiftStackChanged : 1;
161 
162     // text on path layout
163     bool pathLayout : 1;
164     float currentOffset;
165     float startOffset;
166     float layoutPathLength;
167     Path layoutPath;
168 
169     Vector<PositionedFloatVector> xStack;
170     Vector<PositionedFloatVector> yStack;
171     Vector<PositionedFloatVector> dxStack;
172     Vector<PositionedFloatVector> dyStack;
173     Vector<PositionedFloatVector> angleStack;
174     Vector<float> baselineShiftStack;
175 };
176 
177 // Holds extra data, when the character is laid out on a path
178 struct SVGCharOnPath : RefCounted<SVGCharOnPath> {
createSVGCharOnPath179     static PassRefPtr<SVGCharOnPath> create() { return adoptRef(new SVGCharOnPath); }
180 
181     float xScale;
182     float yScale;
183 
184     float xShift;
185     float yShift;
186 
187     float orientationAngle;
188 
189     bool hidden : 1;
190 
191 private:
SVGCharOnPathSVGCharOnPath192     SVGCharOnPath()
193         : xScale(1.0f)
194         , yScale(1.0f)
195         , xShift(0.0f)
196         , yShift(0.0f)
197         , orientationAngle(0.0f)
198         , hidden(false)
199     {
200     }
201 };
202 
203 struct SVGChar {
SVGCharSVGChar204     SVGChar()
205         : x(0.0f)
206         , y(0.0f)
207         , angle(0.0f)
208         , orientationShiftX(0.0f)
209         , orientationShiftY(0.0f)
210         , pathData()
211         , drawnSeperated(false)
212         , newTextChunk(false)
213     {
214     }
215 
~SVGCharSVGChar216     ~SVGChar()
217     {
218     }
219 
220     float x;
221     float y;
222     float angle;
223 
224     float orientationShiftX;
225     float orientationShiftY;
226 
227     RefPtr<SVGCharOnPath> pathData;
228 
229     // Determines wheter this char needs to be drawn seperated
230     bool drawnSeperated : 1;
231 
232     // Determines wheter this char starts a new chunk
233     bool newTextChunk : 1;
234 
235     // Helper methods
236     bool isHidden() const;
237     AffineTransform characterTransform() const;
238 };
239 
240 struct SVGInlineBoxCharacterRange {
SVGInlineBoxCharacterRangeSVGInlineBoxCharacterRange241     SVGInlineBoxCharacterRange()
242         : startOffset(INT_MIN)
243         , endOffset(INT_MIN)
244         , box(0)
245     {
246     }
247 
isOpenSVGInlineBoxCharacterRange248     bool isOpen() const { return (startOffset == endOffset) && (endOffset == INT_MIN); }
isClosedSVGInlineBoxCharacterRange249     bool isClosed() const { return startOffset != INT_MIN && endOffset != INT_MIN; }
250 
251     int startOffset;
252     int endOffset;
253 
254     InlineBox* box;
255 };
256 
257 // Convenience typedef
258 typedef SVGTextContentElement::SVGLengthAdjustType ELengthAdjust;
259 
260 struct SVGTextChunk {
SVGTextChunkSVGTextChunk261     SVGTextChunk()
262         : anchor(TA_START)
263         , textLength(0.0f)
264         , lengthAdjust(SVGTextContentElement::LENGTHADJUST_SPACING)
265         , ctm()
266         , isVerticalText(false)
267         , isTextPath(false)
268         , start(0)
269         , end(0)
270     { }
271 
272     // text-anchor support
273     ETextAnchor anchor;
274 
275     // textLength & lengthAdjust support
276     float textLength;
277     ELengthAdjust lengthAdjust;
278     AffineTransform ctm;
279 
280     // status flags
281     bool isVerticalText : 1;
282     bool isTextPath : 1;
283 
284     // main chunk data
285     Vector<SVGChar>::iterator start;
286     Vector<SVGChar>::iterator end;
287 
288     Vector<SVGInlineBoxCharacterRange> boxes;
289 };
290 
291 struct SVGTextChunkWalkerBase {
~SVGTextChunkWalkerBaseSVGTextChunkWalkerBase292     virtual ~SVGTextChunkWalkerBase() { }
293 
294     virtual void operator()(SVGInlineTextBox* textBox, int startOffset, const AffineTransform& chunkCtm,
295                             const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end) = 0;
296 
297     // Followings methods are only used for painting text chunks
298     virtual void start(InlineBox*) = 0;
299     virtual void end(InlineBox*) = 0;
300 
301     virtual bool setupBackground(InlineBox*) = 0;
302     virtual bool setupFill(InlineBox*) = 0;
303     virtual bool setupFillSelection(InlineBox*) = 0;
304     virtual bool setupStroke(InlineBox*) = 0;
305     virtual bool setupStrokeSelection(InlineBox*) = 0;
306     virtual bool setupForeground(InlineBox*) = 0;
307 };
308 
309 template<typename CallbackClass>
310 struct SVGTextChunkWalker : public SVGTextChunkWalkerBase {
311 public:
312     typedef void (CallbackClass::*SVGTextChunkWalkerCallback)(SVGInlineTextBox* textBox,
313                                                               int startOffset,
314                                                               const AffineTransform& chunkCtm,
315                                                               const Vector<SVGChar>::iterator& start,
316                                                               const Vector<SVGChar>::iterator& end);
317 
318     // These callbacks are only used for painting!
319     typedef void (CallbackClass::*SVGTextChunkStartCallback)(InlineBox* box);
320     typedef void (CallbackClass::*SVGTextChunkEndCallback)(InlineBox* box);
321 
322     typedef bool (CallbackClass::*SVGTextChunkSetupBackgroundCallback)(InlineBox* box);
323     typedef bool (CallbackClass::*SVGTextChunkSetupFillCallback)(InlineBox* box);
324     typedef bool (CallbackClass::*SVGTextChunkSetupStrokeCallback)(InlineBox* box);
325     typedef bool (CallbackClass::*SVGTextChunkSetupForegroundCallback)(InlineBox* box);
326 
327     SVGTextChunkWalker(CallbackClass* object,
328                        SVGTextChunkWalkerCallback walker,
329                        SVGTextChunkStartCallback start = 0,
330                        SVGTextChunkEndCallback end = 0,
331                        SVGTextChunkSetupBackgroundCallback background = 0,
332                        SVGTextChunkSetupFillCallback fill = 0,
333                        SVGTextChunkSetupFillCallback fillSelection = 0,
334                        SVGTextChunkSetupStrokeCallback stroke = 0,
335                        SVGTextChunkSetupStrokeCallback strokeSelection = 0,
336                        SVGTextChunkSetupForegroundCallback foreground = 0)
m_objectSVGTextChunkWalker337         : m_object(object)
338         , m_walkerCallback(walker)
339         , m_startCallback(start)
340         , m_endCallback(end)
341         , m_setupBackgroundCallback(background)
342         , m_setupFillCallback(fill)
343         , m_setupFillSelectionCallback(fillSelection)
344         , m_setupStrokeCallback(stroke)
345         , m_setupStrokeSelectionCallback(strokeSelection)
346         , m_setupForegroundCallback(foreground)
347     {
348         ASSERT(object);
349         ASSERT(walker);
350     }
351 
operatorSVGTextChunkWalker352     virtual void operator()(SVGInlineTextBox* textBox, int startOffset, const AffineTransform& chunkCtm,
353                             const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end)
354     {
355         (*m_object.*m_walkerCallback)(textBox, startOffset, chunkCtm, start, end);
356     }
357 
358     // Followings methods are only used for painting text chunks
startSVGTextChunkWalker359     virtual void start(InlineBox* box)
360     {
361         if (m_startCallback)
362             (*m_object.*m_startCallback)(box);
363         else
364             ASSERT_NOT_REACHED();
365     }
366 
endSVGTextChunkWalker367     virtual void end(InlineBox* box)
368     {
369         if (m_endCallback)
370             (*m_object.*m_endCallback)(box);
371         else
372             ASSERT_NOT_REACHED();
373     }
374 
setupBackgroundSVGTextChunkWalker375     virtual bool setupBackground(InlineBox* box)
376     {
377         if (m_setupBackgroundCallback)
378             return (*m_object.*m_setupBackgroundCallback)(box);
379 
380         ASSERT_NOT_REACHED();
381         return false;
382     }
383 
setupFillSVGTextChunkWalker384     virtual bool setupFill(InlineBox* box)
385     {
386         if (m_setupFillCallback)
387             return (*m_object.*m_setupFillCallback)(box);
388 
389         ASSERT_NOT_REACHED();
390         return false;
391     }
392 
setupFillSelectionSVGTextChunkWalker393     virtual bool setupFillSelection(InlineBox* box)
394     {
395         if (m_setupFillSelectionCallback)
396             return (*m_object.*m_setupFillSelectionCallback)(box);
397 
398         ASSERT_NOT_REACHED();
399         return false;
400     }
401 
setupStrokeSVGTextChunkWalker402     virtual bool setupStroke(InlineBox* box)
403     {
404         if (m_setupStrokeCallback)
405             return (*m_object.*m_setupStrokeCallback)(box);
406 
407         ASSERT_NOT_REACHED();
408         return false;
409     }
410 
setupStrokeSelectionSVGTextChunkWalker411     virtual bool setupStrokeSelection(InlineBox* box)
412     {
413         if (m_setupStrokeSelectionCallback)
414             return (*m_object.*m_setupStrokeSelectionCallback)(box);
415 
416         ASSERT_NOT_REACHED();
417         return false;
418     }
419 
setupForegroundSVGTextChunkWalker420     virtual bool setupForeground(InlineBox* box)
421     {
422         if (m_setupForegroundCallback)
423             return (*m_object.*m_setupForegroundCallback)(box);
424 
425         ASSERT_NOT_REACHED();
426         return false;
427     }
428 
429 private:
430     CallbackClass* m_object;
431     SVGTextChunkWalkerCallback m_walkerCallback;
432     SVGTextChunkStartCallback m_startCallback;
433     SVGTextChunkEndCallback m_endCallback;
434     SVGTextChunkSetupBackgroundCallback m_setupBackgroundCallback;
435     SVGTextChunkSetupFillCallback m_setupFillCallback;
436     SVGTextChunkSetupFillCallback m_setupFillSelectionCallback;
437     SVGTextChunkSetupStrokeCallback m_setupStrokeCallback;
438     SVGTextChunkSetupStrokeCallback m_setupStrokeSelectionCallback;
439     SVGTextChunkSetupForegroundCallback m_setupForegroundCallback;
440 };
441 
442 struct SVGTextChunkLayoutInfo {
SVGTextChunkLayoutInfoSVGTextChunkLayoutInfo443     SVGTextChunkLayoutInfo(Vector<SVGTextChunk>& textChunks)
444         : assignChunkProperties(true)
445         , handlingTextPath(false)
446         , svgTextChunks(textChunks)
447         , it(0)
448     {
449     }
450 
451     bool assignChunkProperties : 1;
452     bool handlingTextPath : 1;
453 
454     Vector<SVGTextChunk>& svgTextChunks;
455     Vector<SVGChar>::iterator it;
456 
457     SVGTextChunk chunk;
458 };
459 
460 struct SVGTextDecorationInfo {
461     // ETextDecoration is meant to be used here
462     HashMap<int, RenderObject*> fillServerMap;
463     HashMap<int, RenderObject*> strokeServerMap;
464 };
465 
466 } // namespace WebCore
467 
468 #endif // ENABLE(SVG)
469 #endif // SVGCharacterLayoutInfo_h
470