• 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 <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 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     TransformationMatrix 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     TransformationMatrix 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 TransformationMatrix& 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 setupFill(InlineBox*) = 0;
302     virtual bool setupStroke(InlineBox*) = 0;
303 };
304 
305 template<typename CallbackClass>
306 struct SVGTextChunkWalker : public SVGTextChunkWalkerBase {
307 public:
308     typedef void (CallbackClass::*SVGTextChunkWalkerCallback)(SVGInlineTextBox* textBox,
309                                                               int startOffset,
310                                                               const TransformationMatrix& chunkCtm,
311                                                               const Vector<SVGChar>::iterator& start,
312                                                               const Vector<SVGChar>::iterator& end);
313 
314     // These callbacks are only used for painting!
315     typedef void (CallbackClass::*SVGTextChunkStartCallback)(InlineBox* box);
316     typedef void (CallbackClass::*SVGTextChunkEndCallback)(InlineBox* box);
317 
318     typedef bool (CallbackClass::*SVGTextChunkSetupFillCallback)(InlineBox* box);
319     typedef bool (CallbackClass::*SVGTextChunkSetupStrokeCallback)(InlineBox* box);
320 
321     SVGTextChunkWalker(CallbackClass* object,
322                        SVGTextChunkWalkerCallback walker,
323                        SVGTextChunkStartCallback start = 0,
324                        SVGTextChunkEndCallback end = 0,
325                        SVGTextChunkSetupFillCallback fill = 0,
326                        SVGTextChunkSetupStrokeCallback stroke = 0)
m_objectSVGTextChunkWalker327         : m_object(object)
328         , m_walkerCallback(walker)
329         , m_startCallback(start)
330         , m_endCallback(end)
331         , m_setupFillCallback(fill)
332         , m_setupStrokeCallback(stroke)
333     {
334         ASSERT(object);
335         ASSERT(walker);
336     }
337 
operatorSVGTextChunkWalker338     virtual void operator()(SVGInlineTextBox* textBox, int startOffset, const TransformationMatrix& chunkCtm,
339                             const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end)
340     {
341         (*m_object.*m_walkerCallback)(textBox, startOffset, chunkCtm, start, end);
342     }
343 
344     // Followings methods are only used for painting text chunks
startSVGTextChunkWalker345     virtual void start(InlineBox* box)
346     {
347         if (m_startCallback)
348             (*m_object.*m_startCallback)(box);
349         else
350             ASSERT_NOT_REACHED();
351     }
352 
endSVGTextChunkWalker353     virtual void end(InlineBox* box)
354     {
355         if (m_endCallback)
356             (*m_object.*m_endCallback)(box);
357         else
358             ASSERT_NOT_REACHED();
359     }
360 
setupFillSVGTextChunkWalker361     virtual bool setupFill(InlineBox* box)
362     {
363         if (m_setupFillCallback)
364             return (*m_object.*m_setupFillCallback)(box);
365 
366         ASSERT_NOT_REACHED();
367         return false;
368     }
369 
setupStrokeSVGTextChunkWalker370     virtual bool setupStroke(InlineBox* box)
371     {
372         if (m_setupStrokeCallback)
373             return (*m_object.*m_setupStrokeCallback)(box);
374 
375         ASSERT_NOT_REACHED();
376         return false;
377     }
378 
379 private:
380     CallbackClass* m_object;
381     SVGTextChunkWalkerCallback m_walkerCallback;
382     SVGTextChunkStartCallback m_startCallback;
383     SVGTextChunkEndCallback m_endCallback;
384     SVGTextChunkSetupFillCallback m_setupFillCallback;
385     SVGTextChunkSetupStrokeCallback m_setupStrokeCallback;
386 };
387 
388 struct SVGTextChunkLayoutInfo {
SVGTextChunkLayoutInfoSVGTextChunkLayoutInfo389     SVGTextChunkLayoutInfo(Vector<SVGTextChunk>& textChunks)
390         : assignChunkProperties(true)
391         , handlingTextPath(false)
392         , svgTextChunks(textChunks)
393         , it(0)
394     {
395     }
396 
397     bool assignChunkProperties : 1;
398     bool handlingTextPath : 1;
399 
400     Vector<SVGTextChunk>& svgTextChunks;
401     Vector<SVGChar>::iterator it;
402 
403     SVGTextChunk chunk;
404 };
405 
406 struct SVGTextDecorationInfo {
407     // ETextDecoration is meant to be used here
408     HashMap<int, RenderObject*> fillServerMap;
409     HashMap<int, RenderObject*> strokeServerMap;
410 };
411 
412 } // namespace WebCore
413 
414 #endif // ENABLE(SVG)
415 #endif // SVGCharacterLayoutInfo_h
416