mirror of
https://bitbucket.org/smil3y/kdelibs.git
synced 2025-02-24 02:42:48 +00:00
420 lines
11 KiB
C++
420 lines
11 KiB
C++
/*
|
|
* 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 "AffineTransform.h"
|
|
#include <wtf/RefCounted.h>
|
|
#include "SVGRenderStyle.h"
|
|
#include "SVGTextContentElement.h"
|
|
|
|
// khtml
|
|
#include "rendering/render_line.h"
|
|
|
|
namespace WebCore {
|
|
|
|
using namespace khtml;
|
|
//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*);
|
|
|
|
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 whether this char needs to be drawn separated
|
|
bool drawnSeperated : 1;
|
|
|
|
// Determines whether this char starts a new chunk
|
|
bool newTextChunk : 1;
|
|
|
|
// Helper methods
|
|
bool isHidden() const;
|
|
AffineTransform 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;
|
|
AffineTransform 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 AffineTransform& 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 AffineTransform& 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 AffineTransform& 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
|