/* * This file is part of the WebKit project. * * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public License * along with this library; see the file COPYING.LIB. If not, write to * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. * */ #ifndef SVGCharacterLayoutInfo_h #define SVGCharacterLayoutInfo_h #if ENABLE(SVG) #include <wtf/Assertions.h> #include <wtf/HashMap.h> #include <wtf/HashSet.h> #include <wtf/Vector.h> #include "TransformationMatrix.h" #include <wtf/RefCounted.h> #include "SVGRenderStyle.h" #include "SVGTextContentElement.h" namespace WebCore { class InlineBox; class InlineFlowBox; class SVGInlineTextBox; class SVGLengthList; class SVGNumberList; class SVGTextPositioningElement; template<class Type> class PositionedVector : public Vector<Type> { public: PositionedVector<Type>() : m_position(0) { } unsigned position() const { return m_position; } void advance(unsigned position) { m_position += position; ASSERT(m_position < Vector<Type>::size()); } Type valueAtCurrentPosition() const { ASSERT(m_position < Vector<Type>::size()); return Vector<Type>::at(m_position); } private: unsigned m_position; }; class PositionedFloatVector : public PositionedVector<float> { }; struct SVGChar; struct SVGCharacterLayoutInfo { SVGCharacterLayoutInfo(Vector<SVGChar>&); enum StackType { XStack, YStack, DxStack, DyStack, AngleStack, BaselineShiftStack }; bool xValueAvailable() const; bool yValueAvailable() const; bool dxValueAvailable() const; bool dyValueAvailable() const; bool angleValueAvailable() const; bool baselineShiftValueAvailable() const; float xValueNext() const; float yValueNext() const; float dxValueNext() const; float dyValueNext() const; float angleValueNext() const; float baselineShiftValueNext() const; void processedChunk(float savedShiftX, float savedShiftY); void processedSingleCharacter(); bool nextPathLayoutPointAndAngle(float glyphAdvance, float extraAdvance, float newOffset); // Used for text-on-path. void addLayoutInformation(InlineFlowBox*, float textAnchorOffset = 0.0f); bool inPathLayout() const; void setInPathLayout(bool value); // Used for anything else. void addLayoutInformation(SVGTextPositioningElement*); // Global position float curx; float cury; // Global rotation float angle; // Accumulated dx/dy values float dx; float dy; // Accumulated baseline-shift values float shiftx; float shifty; // Path specific advance values to handle lengthAdjust float pathExtraAdvance; float pathTextLength; float pathChunkLength; // Result vector Vector<SVGChar>& svgChars; bool nextDrawnSeperated : 1; private: // Used for baseline-shift. void addStackContent(StackType, float); // Used for angle. void addStackContent(StackType, SVGNumberList*); // Used for x/y/dx/dy. void addStackContent(StackType, SVGLengthList*, const SVGElement*); void addStackContent(StackType, const PositionedFloatVector&); void xStackWalk(); void yStackWalk(); void dxStackWalk(); void dyStackWalk(); void angleStackWalk(); void baselineShiftStackWalk(); private: bool xStackChanged : 1; bool yStackChanged : 1; bool dxStackChanged : 1; bool dyStackChanged : 1; bool angleStackChanged : 1; bool baselineShiftStackChanged : 1; // text on path layout bool pathLayout : 1; float currentOffset; float startOffset; float layoutPathLength; Path layoutPath; Vector<PositionedFloatVector> xStack; Vector<PositionedFloatVector> yStack; Vector<PositionedFloatVector> dxStack; Vector<PositionedFloatVector> dyStack; Vector<PositionedFloatVector> angleStack; Vector<float> baselineShiftStack; }; // Holds extra data, when the character is laid out on a path struct SVGCharOnPath : RefCounted<SVGCharOnPath> { static PassRefPtr<SVGCharOnPath> create() { return adoptRef(new SVGCharOnPath); } float xScale; float yScale; float xShift; float yShift; float orientationAngle; bool hidden : 1; private: SVGCharOnPath() : xScale(1.0f) , yScale(1.0f) , xShift(0.0f) , yShift(0.0f) , orientationAngle(0.0f) , hidden(false) { } }; struct SVGChar { SVGChar() : x(0.0f) , y(0.0f) , angle(0.0f) , orientationShiftX(0.0f) , orientationShiftY(0.0f) , pathData() , drawnSeperated(false) , newTextChunk(false) { } ~SVGChar() { } float x; float y; float angle; float orientationShiftX; float orientationShiftY; RefPtr<SVGCharOnPath> pathData; // Determines wheter this char needs to be drawn seperated bool drawnSeperated : 1; // Determines wheter this char starts a new chunk bool newTextChunk : 1; // Helper methods bool isHidden() const; TransformationMatrix characterTransform() const; }; struct SVGInlineBoxCharacterRange { SVGInlineBoxCharacterRange() : startOffset(INT_MIN) , endOffset(INT_MIN) , box(0) { } bool isOpen() const { return (startOffset == endOffset) && (endOffset == INT_MIN); } bool isClosed() const { return startOffset != INT_MIN && endOffset != INT_MIN; } int startOffset; int endOffset; InlineBox* box; }; // Convenience typedef typedef SVGTextContentElement::SVGLengthAdjustType ELengthAdjust; struct SVGTextChunk { SVGTextChunk() : anchor(TA_START) , textLength(0.0f) , lengthAdjust(SVGTextContentElement::LENGTHADJUST_SPACING) , ctm() , isVerticalText(false) , isTextPath(false) , start(0) , end(0) { } // text-anchor support ETextAnchor anchor; // textLength & lengthAdjust support float textLength; ELengthAdjust lengthAdjust; TransformationMatrix ctm; // status flags bool isVerticalText : 1; bool isTextPath : 1; // main chunk data Vector<SVGChar>::iterator start; Vector<SVGChar>::iterator end; Vector<SVGInlineBoxCharacterRange> boxes; }; struct SVGTextChunkWalkerBase { virtual ~SVGTextChunkWalkerBase() { } virtual void operator()(SVGInlineTextBox* textBox, int startOffset, const TransformationMatrix& chunkCtm, const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end) = 0; // Followings methods are only used for painting text chunks virtual void start(InlineBox*) = 0; virtual void end(InlineBox*) = 0; virtual bool setupFill(InlineBox*) = 0; virtual bool setupStroke(InlineBox*) = 0; }; template<typename CallbackClass> struct SVGTextChunkWalker : public SVGTextChunkWalkerBase { public: typedef void (CallbackClass::*SVGTextChunkWalkerCallback)(SVGInlineTextBox* textBox, int startOffset, const TransformationMatrix& chunkCtm, const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end); // These callbacks are only used for painting! typedef void (CallbackClass::*SVGTextChunkStartCallback)(InlineBox* box); typedef void (CallbackClass::*SVGTextChunkEndCallback)(InlineBox* box); typedef bool (CallbackClass::*SVGTextChunkSetupFillCallback)(InlineBox* box); typedef bool (CallbackClass::*SVGTextChunkSetupStrokeCallback)(InlineBox* box); SVGTextChunkWalker(CallbackClass* object, SVGTextChunkWalkerCallback walker, SVGTextChunkStartCallback start = 0, SVGTextChunkEndCallback end = 0, SVGTextChunkSetupFillCallback fill = 0, SVGTextChunkSetupStrokeCallback stroke = 0) : m_object(object) , m_walkerCallback(walker) , m_startCallback(start) , m_endCallback(end) , m_setupFillCallback(fill) , m_setupStrokeCallback(stroke) { ASSERT(object); ASSERT(walker); } virtual void operator()(SVGInlineTextBox* textBox, int startOffset, const TransformationMatrix& chunkCtm, const Vector<SVGChar>::iterator& start, const Vector<SVGChar>::iterator& end) { (*m_object.*m_walkerCallback)(textBox, startOffset, chunkCtm, start, end); } // Followings methods are only used for painting text chunks virtual void start(InlineBox* box) { if (m_startCallback) (*m_object.*m_startCallback)(box); else ASSERT_NOT_REACHED(); } virtual void end(InlineBox* box) { if (m_endCallback) (*m_object.*m_endCallback)(box); else ASSERT_NOT_REACHED(); } virtual bool setupFill(InlineBox* box) { if (m_setupFillCallback) return (*m_object.*m_setupFillCallback)(box); ASSERT_NOT_REACHED(); return false; } virtual bool setupStroke(InlineBox* box) { if (m_setupStrokeCallback) return (*m_object.*m_setupStrokeCallback)(box); ASSERT_NOT_REACHED(); return false; } private: CallbackClass* m_object; SVGTextChunkWalkerCallback m_walkerCallback; SVGTextChunkStartCallback m_startCallback; SVGTextChunkEndCallback m_endCallback; SVGTextChunkSetupFillCallback m_setupFillCallback; SVGTextChunkSetupStrokeCallback m_setupStrokeCallback; }; struct SVGTextChunkLayoutInfo { SVGTextChunkLayoutInfo(Vector<SVGTextChunk>& textChunks) : assignChunkProperties(true) , handlingTextPath(false) , svgTextChunks(textChunks) , it(0) { } bool assignChunkProperties : 1; bool handlingTextPath : 1; Vector<SVGTextChunk>& svgTextChunks; Vector<SVGChar>::iterator it; SVGTextChunk chunk; }; struct SVGTextDecorationInfo { // ETextDecoration is meant to be used here HashMap<int, RenderObject*> fillServerMap; HashMap<int, RenderObject*> strokeServerMap; }; } // namespace WebCore #endif // ENABLE(SVG) #endif // SVGCharacterLayoutInfo_h