File indexing completed on 2024-04-28 15:24:19

0001 /*
0002  * This file is part of the WebKit project.
0003  *
0004  * Copyright (C) 2007 Nikolas Zimmermann <zimmermann@kde.org>
0005  *
0006  * This library is free software; you can redistribute it and/or
0007  * modify it under the terms of the GNU Library General Public
0008  * License as published by the Free Software Foundation; either
0009  * version 2 of the License, or (at your option) any later version.
0010  *
0011  * This library is distributed in the hope that it will be useful,
0012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
0013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0014  * Library General Public License for more details.
0015  *
0016  * You should have received a copy of the GNU Library General Public License
0017  * along with this library; see the file COPYING.LIB.  If not, write to
0018  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0019  * Boston, MA 02110-1301, USA.
0020  *
0021  */
0022 
0023 #ifndef SVGCharacterLayoutInfo_h
0024 #define SVGCharacterLayoutInfo_h
0025 
0026 #if ENABLE(SVG)
0027 #include <wtf/Assertions.h>
0028 #include <wtf/HashMap.h>
0029 #include <wtf/HashSet.h>
0030 #include <wtf/Vector.h>
0031 
0032 #include "AffineTransform.h"
0033 #include <wtf/RefCounted.h>
0034 #include "SVGRenderStyle.h"
0035 #include "SVGTextContentElement.h"
0036 
0037 // khtml
0038 #include "rendering/render_line.h"
0039 
0040 namespace WebCore
0041 {
0042 
0043 using namespace khtml;
0044 //class InlineBox;
0045 //class InlineFlowBox;
0046 class SVGInlineTextBox;
0047 class SVGLengthList;
0048 class SVGNumberList;
0049 class SVGTextPositioningElement;
0050 
0051 template<class Type>
0052 class PositionedVector : public Vector<Type>
0053 {
0054 public:
0055     PositionedVector<Type>()
0056         : m_position(0)
0057     {
0058     }
0059 
0060     unsigned position() const
0061     {
0062         return m_position;
0063     }
0064 
0065     void advance(unsigned position)
0066     {
0067         m_position += position;
0068         ASSERT(m_position < Vector<Type>::size());
0069     }
0070 
0071     Type valueAtCurrentPosition() const
0072     {
0073         ASSERT(m_position < Vector<Type>::size());
0074         return Vector<Type>::at(m_position);
0075     }
0076 
0077 private:
0078     unsigned m_position;
0079 };
0080 
0081 class PositionedFloatVector : public PositionedVector<float> { };
0082 struct SVGChar;
0083 
0084 struct SVGCharacterLayoutInfo {
0085     SVGCharacterLayoutInfo(Vector<SVGChar> &);
0086 
0087     enum StackType { XStack, YStack, DxStack, DyStack, AngleStack, BaselineShiftStack };
0088 
0089     bool xValueAvailable() const;
0090     bool yValueAvailable() const;
0091     bool dxValueAvailable() const;
0092     bool dyValueAvailable() const;
0093     bool angleValueAvailable() const;
0094     bool baselineShiftValueAvailable() const;
0095 
0096     float xValueNext() const;
0097     float yValueNext() const;
0098     float dxValueNext() const;
0099     float dyValueNext() const;
0100     float angleValueNext() const;
0101     float baselineShiftValueNext() const;
0102 
0103     void processedChunk(float savedShiftX, float savedShiftY);
0104     void processedSingleCharacter();
0105 
0106     bool nextPathLayoutPointAndAngle(float glyphAdvance, float extraAdvance, float newOffset);
0107 
0108     // Used for text-on-path.
0109     void addLayoutInformation(InlineFlowBox *, float textAnchorOffset = 0.0f);
0110 
0111     bool inPathLayout() const;
0112     void setInPathLayout(bool value);
0113 
0114     // Used for anything else.
0115     void addLayoutInformation(SVGTextPositioningElement *);
0116 
0117     // Global position
0118     float curx;
0119     float cury;
0120 
0121     // Global rotation
0122     float angle;
0123 
0124     // Accumulated dx/dy values
0125     float dx;
0126     float dy;
0127 
0128     // Accumulated baseline-shift values
0129     float shiftx;
0130     float shifty;
0131 
0132     // Path specific advance values to handle lengthAdjust
0133     float pathExtraAdvance;
0134     float pathTextLength;
0135     float pathChunkLength;
0136 
0137     // Result vector
0138     Vector<SVGChar> &svgChars;
0139     bool nextDrawnSeperated : 1;
0140 
0141 private:
0142     // Used for baseline-shift.
0143     void addStackContent(StackType, float);
0144 
0145     // Used for angle.
0146     void addStackContent(StackType, SVGNumberList *);
0147 
0148     // Used for x/y/dx/dy.
0149     void addStackContent(StackType, SVGLengthList *);
0150 
0151     void addStackContent(StackType, const PositionedFloatVector &);
0152 
0153     void xStackWalk();
0154     void yStackWalk();
0155     void dxStackWalk();
0156     void dyStackWalk();
0157     void angleStackWalk();
0158     void baselineShiftStackWalk();
0159 
0160 private:
0161     bool xStackChanged : 1;
0162     bool yStackChanged : 1;
0163     bool dxStackChanged : 1;
0164     bool dyStackChanged : 1;
0165     bool angleStackChanged : 1;
0166     bool baselineShiftStackChanged : 1;
0167 
0168     // text on path layout
0169     bool pathLayout : 1;
0170     float currentOffset;
0171     float startOffset;
0172     float layoutPathLength;
0173     Path layoutPath;
0174 
0175     Vector<PositionedFloatVector> xStack;
0176     Vector<PositionedFloatVector> yStack;
0177     Vector<PositionedFloatVector> dxStack;
0178     Vector<PositionedFloatVector> dyStack;
0179     Vector<PositionedFloatVector> angleStack;
0180     Vector<float> baselineShiftStack;
0181 };
0182 
0183 // Holds extra data, when the character is laid out on a path
0184 struct SVGCharOnPath : RefCounted<SVGCharOnPath> {
0185     static PassRefPtr<SVGCharOnPath> create()
0186     {
0187         return adoptRef(new SVGCharOnPath);
0188     }
0189 
0190     float xScale;
0191     float yScale;
0192 
0193     float xShift;
0194     float yShift;
0195 
0196     float orientationAngle;
0197 
0198     bool hidden : 1;
0199 
0200 private:
0201     SVGCharOnPath()
0202         : xScale(1.0f)
0203         , yScale(1.0f)
0204         , xShift(0.0f)
0205         , yShift(0.0f)
0206         , orientationAngle(0.0f)
0207         , hidden(false)
0208     {
0209     }
0210 };
0211 
0212 struct SVGChar {
0213     SVGChar()
0214         : x(0.0f)
0215         , y(0.0f)
0216         , angle(0.0f)
0217         , orientationShiftX(0.0f)
0218         , orientationShiftY(0.0f)
0219         , pathData()
0220         , drawnSeperated(false)
0221         , newTextChunk(false)
0222     {
0223     }
0224 
0225     ~SVGChar()
0226     {
0227     }
0228 
0229     float x;
0230     float y;
0231     float angle;
0232 
0233     float orientationShiftX;
0234     float orientationShiftY;
0235 
0236     RefPtr<SVGCharOnPath> pathData;
0237 
0238     // Determines whether this char needs to be drawn separated
0239     bool drawnSeperated : 1;
0240 
0241     // Determines whether this char starts a new chunk
0242     bool newTextChunk : 1;
0243 
0244     // Helper methods
0245     bool isHidden() const;
0246     AffineTransform characterTransform() const;
0247 };
0248 
0249 struct SVGInlineBoxCharacterRange {
0250     SVGInlineBoxCharacterRange()
0251         : startOffset(INT_MIN)
0252         , endOffset(INT_MIN)
0253         , box(nullptr)
0254     {
0255     }
0256 
0257     bool isOpen() const
0258     {
0259         return (startOffset == endOffset) && (endOffset == INT_MIN);
0260     }
0261     bool isClosed() const
0262     {
0263         return startOffset != INT_MIN && endOffset != INT_MIN;
0264     }
0265 
0266     int startOffset;
0267     int endOffset;
0268 
0269     InlineBox *box;
0270 };
0271 
0272 // Convenience typedef
0273 typedef SVGTextContentElement::SVGLengthAdjustType ELengthAdjust;
0274 
0275 struct SVGTextChunk {
0276     SVGTextChunk()
0277         : anchor(TA_START)
0278         , textLength(0.0f)
0279         , lengthAdjust(SVGTextContentElement::LENGTHADJUST_SPACING)
0280         , ctm()
0281         , isVerticalText(false)
0282         , isTextPath(false)
0283         , start(nullptr)
0284         , end(nullptr)
0285     { }
0286 
0287     // text-anchor support
0288     ETextAnchor anchor;
0289 
0290     // textLength & lengthAdjust support
0291     float textLength;
0292     ELengthAdjust lengthAdjust;
0293     AffineTransform ctm;
0294 
0295     // status flags
0296     bool isVerticalText : 1;
0297     bool isTextPath : 1;
0298 
0299     // main chunk data
0300     Vector<SVGChar>::iterator start;
0301     Vector<SVGChar>::iterator end;
0302 
0303     Vector<SVGInlineBoxCharacterRange> boxes;
0304 };
0305 
0306 struct SVGTextChunkWalkerBase {
0307     virtual ~SVGTextChunkWalkerBase() { }
0308 
0309     virtual void operator()(SVGInlineTextBox *textBox, int startOffset, const AffineTransform &chunkCtm,
0310                             const Vector<SVGChar>::iterator &start, const Vector<SVGChar>::iterator &end) = 0;
0311 
0312     // Followings methods are only used for painting text chunks
0313     virtual void start(InlineBox *) = 0;
0314     virtual void end(InlineBox *) = 0;
0315 
0316     virtual bool setupFill(InlineBox *) = 0;
0317     virtual bool setupStroke(InlineBox *) = 0;
0318 };
0319 
0320 template<typename CallbackClass>
0321 struct SVGTextChunkWalker : public SVGTextChunkWalkerBase {
0322 public:
0323     typedef void (CallbackClass::*SVGTextChunkWalkerCallback)(SVGInlineTextBox *textBox,
0324             int startOffset,
0325             const AffineTransform &chunkCtm,
0326             const Vector<SVGChar>::iterator &start,
0327             const Vector<SVGChar>::iterator &end);
0328 
0329     // These callbacks are only used for painting!
0330     typedef void (CallbackClass::*SVGTextChunkStartCallback)(InlineBox *box);
0331     typedef void (CallbackClass::*SVGTextChunkEndCallback)(InlineBox *box);
0332 
0333     typedef bool (CallbackClass::*SVGTextChunkSetupFillCallback)(InlineBox *box);
0334     typedef bool (CallbackClass::*SVGTextChunkSetupStrokeCallback)(InlineBox *box);
0335 
0336     SVGTextChunkWalker(CallbackClass *object,
0337                        SVGTextChunkWalkerCallback walker,
0338                        SVGTextChunkStartCallback start = nullptr,
0339                        SVGTextChunkEndCallback end = nullptr,
0340                        SVGTextChunkSetupFillCallback fill = nullptr,
0341                        SVGTextChunkSetupStrokeCallback stroke = nullptr)
0342         : m_object(object)
0343         , m_walkerCallback(walker)
0344         , m_startCallback(start)
0345         , m_endCallback(end)
0346         , m_setupFillCallback(fill)
0347         , m_setupStrokeCallback(stroke)
0348     {
0349         ASSERT(object);
0350         ASSERT(walker);
0351     }
0352 
0353     virtual void operator()(SVGInlineTextBox *textBox, int startOffset, const AffineTransform &chunkCtm,
0354                             const Vector<SVGChar>::iterator &start, const Vector<SVGChar>::iterator &end) override
0355     {
0356         (*m_object.*m_walkerCallback)(textBox, startOffset, chunkCtm, start, end);
0357     }
0358 
0359     // Followings methods are only used for painting text chunks
0360     void start(InlineBox *box) override
0361     {
0362         if (m_startCallback) {
0363             (*m_object.*m_startCallback)(box);
0364         } else {
0365             ASSERT_NOT_REACHED();
0366         }
0367     }
0368 
0369     void end(InlineBox *box) override
0370     {
0371         if (m_endCallback) {
0372             (*m_object.*m_endCallback)(box);
0373         } else {
0374             ASSERT_NOT_REACHED();
0375         }
0376     }
0377 
0378     bool setupFill(InlineBox *box) override
0379     {
0380         if (m_setupFillCallback) {
0381             return (*m_object.*m_setupFillCallback)(box);
0382         }
0383 
0384         ASSERT_NOT_REACHED();
0385         return false;
0386     }
0387 
0388     bool setupStroke(InlineBox *box) override
0389     {
0390         if (m_setupStrokeCallback) {
0391             return (*m_object.*m_setupStrokeCallback)(box);
0392         }
0393 
0394         ASSERT_NOT_REACHED();
0395         return false;
0396     }
0397 
0398 private:
0399     CallbackClass *m_object;
0400     SVGTextChunkWalkerCallback m_walkerCallback;
0401     SVGTextChunkStartCallback m_startCallback;
0402     SVGTextChunkEndCallback m_endCallback;
0403     SVGTextChunkSetupFillCallback m_setupFillCallback;
0404     SVGTextChunkSetupStrokeCallback m_setupStrokeCallback;
0405 };
0406 
0407 struct SVGTextChunkLayoutInfo {
0408     SVGTextChunkLayoutInfo(Vector<SVGTextChunk> &textChunks)
0409         : assignChunkProperties(true)
0410         , handlingTextPath(false)
0411         , svgTextChunks(textChunks)
0412         , it(nullptr)
0413     {
0414     }
0415 
0416     bool assignChunkProperties : 1;
0417     bool handlingTextPath : 1;
0418 
0419     Vector<SVGTextChunk> &svgTextChunks;
0420     Vector<SVGChar>::iterator it;
0421 
0422     SVGTextChunk chunk;
0423 };
0424 
0425 struct SVGTextDecorationInfo {
0426     // ETextDecoration is meant to be used here
0427     HashMap<int, RenderObject *> fillServerMap;
0428     HashMap<int, RenderObject *> strokeServerMap;
0429 };
0430 
0431 } // namespace WebCore
0432 
0433 #endif // ENABLE(SVG)
0434 #endif // SVGCharacterLayoutInfo_h