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