571 lines
11 KiB
C++
571 lines
11 KiB
C++
#ifndef LUNASVG_SVGPROPERTY_H
|
|
#define LUNASVG_SVGPROPERTY_H
|
|
|
|
#include "graphics.h"
|
|
|
|
#include <string>
|
|
|
|
namespace lunasvg {
|
|
|
|
enum class PropertyID : uint8_t {
|
|
Unknown = 0,
|
|
Alignment_Baseline,
|
|
Baseline_Shift,
|
|
Class,
|
|
Clip_Path,
|
|
Clip_Rule,
|
|
ClipPathUnits,
|
|
Color,
|
|
Cx,
|
|
Cy,
|
|
D,
|
|
Direction,
|
|
Display,
|
|
Dominant_Baseline,
|
|
Dx,
|
|
Dy,
|
|
Fill,
|
|
Fill_Opacity,
|
|
Fill_Rule,
|
|
Font_Family,
|
|
Font_Size,
|
|
Font_Style,
|
|
Font_Weight,
|
|
Fx,
|
|
Fy,
|
|
GradientTransform,
|
|
GradientUnits,
|
|
Height,
|
|
Href,
|
|
Id,
|
|
LengthAdjust,
|
|
Letter_Spacing,
|
|
Marker_End,
|
|
Marker_Mid,
|
|
Marker_Start,
|
|
MarkerHeight,
|
|
MarkerUnits,
|
|
MarkerWidth,
|
|
Mask,
|
|
Mask_Type,
|
|
MaskContentUnits,
|
|
MaskUnits,
|
|
Offset,
|
|
Opacity,
|
|
Orient,
|
|
Overflow,
|
|
PatternContentUnits,
|
|
PatternTransform,
|
|
PatternUnits,
|
|
Pointer_Events,
|
|
Points,
|
|
PreserveAspectRatio,
|
|
R,
|
|
RefX,
|
|
RefY,
|
|
Rotate,
|
|
Rx,
|
|
Ry,
|
|
SpreadMethod,
|
|
Stop_Color,
|
|
Stop_Opacity,
|
|
Stroke,
|
|
Stroke_Dasharray,
|
|
Stroke_Dashoffset,
|
|
Stroke_Linecap,
|
|
Stroke_Linejoin,
|
|
Stroke_Miterlimit,
|
|
Stroke_Opacity,
|
|
Stroke_Width,
|
|
Style,
|
|
Text_Anchor,
|
|
Text_Orientation,
|
|
TextLength,
|
|
Transform,
|
|
ViewBox,
|
|
Visibility,
|
|
White_Space,
|
|
Width,
|
|
Word_Spacing,
|
|
Writing_Mode,
|
|
X,
|
|
X1,
|
|
X2,
|
|
Y,
|
|
Y1,
|
|
Y2
|
|
};
|
|
|
|
PropertyID propertyid(std::string_view name);
|
|
PropertyID csspropertyid(std::string_view name);
|
|
|
|
class SVGElement;
|
|
|
|
class SVGProperty {
|
|
public:
|
|
SVGProperty(PropertyID id);
|
|
virtual ~SVGProperty() = default;
|
|
PropertyID id() const { return m_id; }
|
|
|
|
virtual bool parse(std::string_view input) = 0;
|
|
|
|
private:
|
|
SVGProperty(const SVGProperty&) = delete;
|
|
SVGProperty& operator=(const SVGProperty&) = delete;
|
|
PropertyID m_id;
|
|
};
|
|
|
|
class SVGString final : public SVGProperty {
|
|
public:
|
|
explicit SVGString(PropertyID id)
|
|
: SVGProperty(id)
|
|
{}
|
|
|
|
const std::string& value() const { return m_value; }
|
|
bool parse(std::string_view input) final;
|
|
|
|
private:
|
|
std::string m_value;
|
|
};
|
|
|
|
class Paint {
|
|
public:
|
|
Paint() = default;
|
|
explicit Paint(const Color& color) : m_color(color) {}
|
|
Paint(const std::string& id, const Color& color)
|
|
: m_id(id), m_color(color)
|
|
{}
|
|
|
|
const Color& color() const { return m_color; }
|
|
const std::string& id() const { return m_id; }
|
|
bool isNone() const { return m_id.empty() && !m_color.isVisible(); }
|
|
|
|
private:
|
|
std::string m_id;
|
|
Color m_color = Color::Transparent;
|
|
};
|
|
|
|
enum class Display : uint8_t {
|
|
Inline,
|
|
None
|
|
};
|
|
|
|
enum class Visibility : uint8_t {
|
|
Visible,
|
|
Hidden,
|
|
Collapse
|
|
};
|
|
|
|
enum class Overflow : uint8_t {
|
|
Visible,
|
|
Hidden
|
|
};
|
|
|
|
enum class PointerEvents : uint8_t {
|
|
None,
|
|
Auto,
|
|
Stroke,
|
|
Fill,
|
|
Painted,
|
|
Visible,
|
|
VisibleStroke,
|
|
VisibleFill,
|
|
VisiblePainted,
|
|
BoundingBox,
|
|
All
|
|
};
|
|
|
|
enum class FontStyle : uint8_t {
|
|
Normal,
|
|
Italic
|
|
};
|
|
|
|
enum class FontWeight : uint8_t {
|
|
Normal,
|
|
Bold
|
|
};
|
|
|
|
enum class AlignmentBaseline : uint8_t {
|
|
Auto,
|
|
Baseline,
|
|
BeforeEdge,
|
|
TextBeforeEdge,
|
|
Middle,
|
|
Central,
|
|
AfterEdge,
|
|
TextAfterEdge,
|
|
Ideographic,
|
|
Alphabetic,
|
|
Hanging,
|
|
Mathematical
|
|
};
|
|
|
|
enum class DominantBaseline : uint8_t {
|
|
Auto,
|
|
UseScript,
|
|
NoChange,
|
|
ResetSize,
|
|
Ideographic,
|
|
Alphabetic,
|
|
Hanging,
|
|
Mathematical,
|
|
Central,
|
|
Middle,
|
|
TextAfterEdge,
|
|
TextBeforeEdge
|
|
};
|
|
|
|
enum class TextAnchor : uint8_t {
|
|
Start,
|
|
Middle,
|
|
End
|
|
};
|
|
|
|
enum class WhiteSpace : uint8_t {
|
|
Default,
|
|
Preserve
|
|
};
|
|
|
|
enum class WritingMode : uint8_t {
|
|
Horizontal,
|
|
Vertical
|
|
};
|
|
|
|
enum class TextOrientation : uint8_t {
|
|
Mixed,
|
|
Upright
|
|
};
|
|
|
|
enum class Direction : uint8_t {
|
|
Ltr,
|
|
Rtl
|
|
};
|
|
|
|
enum class MaskType : uint8_t {
|
|
Luminance,
|
|
Alpha
|
|
};
|
|
|
|
enum class Units : uint8_t {
|
|
UserSpaceOnUse,
|
|
ObjectBoundingBox
|
|
};
|
|
|
|
enum class MarkerUnits : uint8_t {
|
|
StrokeWidth,
|
|
UserSpaceOnUse
|
|
};
|
|
|
|
enum class LengthAdjust : uint8_t {
|
|
Spacing,
|
|
SpacingAndGlyphs
|
|
};
|
|
|
|
template<typename Enum>
|
|
using SVGEnumerationEntry = std::pair<Enum, std::string_view>;
|
|
|
|
template<typename Enum>
|
|
class SVGEnumeration final : public SVGProperty {
|
|
public:
|
|
explicit SVGEnumeration(PropertyID id, Enum value)
|
|
: SVGProperty(id)
|
|
, m_value(value)
|
|
{}
|
|
|
|
Enum value() const { return m_value; }
|
|
bool parse(std::string_view input) final;
|
|
|
|
private:
|
|
template<unsigned int N>
|
|
bool parseEnum(std::string_view input, const SVGEnumerationEntry<Enum>(&entries)[N]);
|
|
Enum m_value;
|
|
};
|
|
|
|
class SVGAngle final : public SVGProperty {
|
|
public:
|
|
enum class OrientType {
|
|
Auto,
|
|
AutoStartReverse,
|
|
Angle
|
|
};
|
|
|
|
explicit SVGAngle(PropertyID id)
|
|
: SVGProperty(id)
|
|
{}
|
|
|
|
float value() const { return m_value; }
|
|
OrientType orientType() const { return m_orientType; }
|
|
bool parse(std::string_view input) final;
|
|
|
|
private:
|
|
float m_value = 0;
|
|
OrientType m_orientType = OrientType::Angle;
|
|
};
|
|
|
|
enum class LengthUnits : uint8_t {
|
|
None,
|
|
Percent,
|
|
Px,
|
|
Em,
|
|
Ex
|
|
};
|
|
|
|
enum class LengthDirection : uint8_t {
|
|
Horizontal,
|
|
Vertical,
|
|
Diagonal
|
|
};
|
|
|
|
enum class LengthNegativeMode : uint8_t {
|
|
Allow,
|
|
Forbid
|
|
};
|
|
|
|
class Length {
|
|
public:
|
|
Length() = default;
|
|
Length(float value, LengthUnits units)
|
|
: m_value(value), m_units(units)
|
|
{}
|
|
|
|
float value() const { return m_value; }
|
|
LengthUnits units() const { return m_units; }
|
|
|
|
bool parse(std::string_view input, LengthNegativeMode mode);
|
|
|
|
private:
|
|
float m_value = 0.f;
|
|
LengthUnits m_units = LengthUnits::None;
|
|
};
|
|
|
|
class SVGLength final : public SVGProperty {
|
|
public:
|
|
SVGLength(PropertyID id, LengthDirection direction, LengthNegativeMode negativeMode, float value = 0, LengthUnits units = LengthUnits::None)
|
|
: SVGProperty(id)
|
|
, m_direction(direction)
|
|
, m_negativeMode(negativeMode)
|
|
, m_value(value, units)
|
|
{}
|
|
|
|
bool isPercent() const { return m_value.units() == LengthUnits::Percent; }
|
|
|
|
LengthDirection direction() const { return m_direction; }
|
|
LengthNegativeMode negativeMode() const { return m_negativeMode; }
|
|
const Length& value() const { return m_value; }
|
|
bool parse(std::string_view input) final;
|
|
|
|
private:
|
|
const LengthDirection m_direction;
|
|
const LengthNegativeMode m_negativeMode;
|
|
Length m_value;
|
|
};
|
|
|
|
class LengthContext {
|
|
public:
|
|
LengthContext(const SVGElement* element, Units units = Units::UserSpaceOnUse)
|
|
: m_element(element), m_units(units)
|
|
{}
|
|
|
|
float valueForLength(const Length& length, LengthDirection direction) const;
|
|
float valueForLength(const SVGLength& length) const { return valueForLength(length.value(), length.direction()); }
|
|
|
|
private:
|
|
float viewportDimension(LengthDirection direction) const;
|
|
const SVGElement* m_element;
|
|
const Units m_units;
|
|
};
|
|
|
|
using LengthList = std::vector<Length>;
|
|
|
|
class SVGLengthList final : public SVGProperty {
|
|
public:
|
|
SVGLengthList(PropertyID id, LengthDirection direction, LengthNegativeMode negativeMode)
|
|
: SVGProperty(id)
|
|
, m_direction(direction)
|
|
, m_negativeMode(negativeMode)
|
|
{}
|
|
|
|
LengthDirection direction() const { return m_direction; }
|
|
LengthNegativeMode negativeMode() const { return m_negativeMode; }
|
|
const LengthList& values() const { return m_values; }
|
|
bool parse(std::string_view input) final;
|
|
|
|
private:
|
|
const LengthDirection m_direction;
|
|
const LengthNegativeMode m_negativeMode;
|
|
LengthList m_values;
|
|
};
|
|
|
|
class BaselineShift {
|
|
public:
|
|
enum class Type {
|
|
Baseline,
|
|
Sub,
|
|
Super,
|
|
Length
|
|
};
|
|
|
|
BaselineShift() = default;
|
|
BaselineShift(Type type) : m_type(type) {}
|
|
BaselineShift(const Length& length) : m_type(Type::Length), m_length(length) {}
|
|
|
|
Type type() const { return m_type; }
|
|
const Length& length() const { return m_length; }
|
|
|
|
private:
|
|
Type m_type{Type::Baseline};
|
|
Length m_length;
|
|
};
|
|
|
|
class SVGNumber : public SVGProperty {
|
|
public:
|
|
SVGNumber(PropertyID id, float value)
|
|
: SVGProperty(id)
|
|
, m_value(value)
|
|
{}
|
|
|
|
float value() const { return m_value; }
|
|
bool parse(std::string_view input) override;
|
|
|
|
private:
|
|
float m_value;
|
|
};
|
|
|
|
class SVGNumberPercentage final : public SVGProperty {
|
|
public:
|
|
SVGNumberPercentage(PropertyID id, float value)
|
|
: SVGProperty(id)
|
|
, m_value(value)
|
|
{}
|
|
|
|
float value() const { return m_value; }
|
|
bool parse(std::string_view input) final;
|
|
|
|
private:
|
|
float m_value;
|
|
};
|
|
|
|
using NumberList = std::vector<float>;
|
|
|
|
class SVGNumberList final : public SVGProperty {
|
|
public:
|
|
explicit SVGNumberList(PropertyID id)
|
|
: SVGProperty(id)
|
|
{}
|
|
|
|
const NumberList& values() const { return m_values; }
|
|
bool parse(std::string_view input) final;
|
|
|
|
private:
|
|
NumberList m_values;
|
|
};
|
|
|
|
class SVGPath final : public SVGProperty {
|
|
public:
|
|
explicit SVGPath(PropertyID id)
|
|
: SVGProperty(id)
|
|
{}
|
|
|
|
const Path& value() const { return m_value; }
|
|
bool parse(std::string_view input) final;
|
|
|
|
private:
|
|
Path m_value;
|
|
};
|
|
|
|
class SVGPoint final : public SVGProperty {
|
|
public:
|
|
explicit SVGPoint(PropertyID id)
|
|
: SVGProperty(id)
|
|
{}
|
|
|
|
const Point& value() const { return m_value; }
|
|
bool parse(std::string_view input) final;
|
|
|
|
private:
|
|
Point m_value;
|
|
};
|
|
|
|
using PointList = std::vector<Point>;
|
|
|
|
class SVGPointList final : public SVGProperty {
|
|
public:
|
|
explicit SVGPointList(PropertyID id)
|
|
: SVGProperty(id)
|
|
{}
|
|
|
|
const PointList& values() const { return m_values; }
|
|
bool parse(std::string_view input) final;
|
|
|
|
private:
|
|
PointList m_values;
|
|
};
|
|
|
|
class SVGRect final : public SVGProperty {
|
|
public:
|
|
explicit SVGRect(PropertyID id)
|
|
: SVGProperty(id)
|
|
, m_value(Rect::Invalid)
|
|
{}
|
|
|
|
const Rect& value() const { return m_value; }
|
|
bool parse(std::string_view input) final;
|
|
|
|
private:
|
|
Rect m_value;
|
|
};
|
|
|
|
class SVGTransform final : public SVGProperty {
|
|
public:
|
|
explicit SVGTransform(PropertyID id)
|
|
: SVGProperty(id)
|
|
{}
|
|
|
|
const Transform& value() const { return m_value; }
|
|
bool parse(std::string_view input) final;
|
|
|
|
private:
|
|
Transform m_value;
|
|
};
|
|
|
|
class SVGPreserveAspectRatio final : public SVGProperty {
|
|
public:
|
|
enum class AlignType {
|
|
None,
|
|
xMinYMin,
|
|
xMidYMin,
|
|
xMaxYMin,
|
|
xMinYMid,
|
|
xMidYMid,
|
|
xMaxYMid,
|
|
xMinYMax,
|
|
xMidYMax,
|
|
xMaxYMax
|
|
};
|
|
|
|
enum class MeetOrSlice {
|
|
Meet,
|
|
Slice
|
|
};
|
|
|
|
explicit SVGPreserveAspectRatio(PropertyID id)
|
|
: SVGProperty(id)
|
|
{}
|
|
|
|
AlignType alignType() const { return m_alignType; }
|
|
MeetOrSlice meetOrSlice() const { return m_meetOrSlice; }
|
|
bool parse(std::string_view input) final;
|
|
|
|
Rect getClipRect(const Rect& viewBoxRect, const Size& viewportSize) const;
|
|
Transform getTransform(const Rect& viewBoxRect, const Size& viewportSize) const;
|
|
void transformRect(Rect& dstRect, Rect& srcRect) const;
|
|
|
|
private:
|
|
AlignType m_alignType = AlignType::xMidYMid;
|
|
MeetOrSlice m_meetOrSlice = MeetOrSlice::Meet;
|
|
};
|
|
|
|
} // namespace lunasvg
|
|
|
|
#endif // LUNASVG_SVGPROPERTY_H
|