Merge commit '0d52738239a3496122cb332378fc58cf9943c0d5' into new-svg-renderer

This commit is contained in:
Leon Styhre 2022-10-03 23:55:09 +02:00
commit 753fc92944
35 changed files with 761 additions and 4447 deletions

View file

@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.3)
project(lunasvg VERSION 2.3.2 LANGUAGES CXX C)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD 14)
set(CMAKE_C_STANDARD 11)
option(BUILD_SHARED_LIBS "Builds as shared library" OFF)

View file

@ -20,8 +20,6 @@ PRIVATE
"${CMAKE_CURRENT_LIST_DIR}/svgelement.cpp"
"${CMAKE_CURRENT_LIST_DIR}/symbolelement.cpp"
"${CMAKE_CURRENT_LIST_DIR}/useelement.cpp"
"${CMAKE_CURRENT_LIST_DIR}/cssparser.cpp"
"${CMAKE_CURRENT_LIST_DIR}/cssstylesheet.cpp"
)
target_include_directories(lunasvg

View file

@ -9,7 +9,7 @@ static plutovg_fill_rule_t to_plutovg_fill_rule(WindRule winding);
static plutovg_operator_t to_plutovg_operator(BlendMode mode);
static plutovg_line_cap_t to_plutovg_line_cap(LineCap cap);
static plutovg_line_join_t to_plutovg_line_join(LineJoin join);
static plutovg_spread_method_t to_plutovg_spread_method(SpreadMethod spread);
static plutovg_spread_method_t to_plutovg_spread_methood(SpreadMethod spread);
static void to_plutovg_stops(plutovg_gradient_t* gradient, const GradientStops& stops);
static void to_plutovg_path(plutovg_t* pluto, const Path& path);
@ -67,7 +67,7 @@ void Canvas::setLinearGradient(double x1, double y1, double x2, double y2, const
auto gradient = plutovg_gradient_create_linear(x1, y1, x2, y2);
auto matrix = to_plutovg_matrix(transform);
to_plutovg_stops(gradient, stops);
plutovg_gradient_set_spread(gradient, to_plutovg_spread_method(spread));
plutovg_gradient_set_spread(gradient, to_plutovg_spread_methood(spread));
plutovg_gradient_set_matrix(gradient, &matrix);
plutovg_set_source_gradient(pluto, gradient);
plutovg_gradient_destroy(gradient);
@ -78,7 +78,7 @@ void Canvas::setRadialGradient(double cx, double cy, double r, double fx, double
auto gradient = plutovg_gradient_create_radial(cx, cy, r, fx, fy, 0);
auto matrix = to_plutovg_matrix(transform);
to_plutovg_stops(gradient, stops);
plutovg_gradient_set_spread(gradient, to_plutovg_spread_method(spread));
plutovg_gradient_set_spread(gradient, to_plutovg_spread_methood(spread));
plutovg_gradient_set_matrix(gradient, &matrix);
plutovg_set_source_gradient(pluto, gradient);
plutovg_gradient_destroy(gradient);
@ -227,7 +227,7 @@ plutovg_line_join_t to_plutovg_line_join(LineJoin join)
return join == LineJoin::Miter ? plutovg_line_join_miter : join == LineJoin::Round ? plutovg_line_join_round : plutovg_line_join_bevel;
}
static plutovg_spread_method_t to_plutovg_spread_method(SpreadMethod spread)
static plutovg_spread_method_t to_plutovg_spread_methood(SpreadMethod spread)
{
return spread == SpreadMethod::Pad ? plutovg_spread_method_pad : spread == SpreadMethod::Reflect ? plutovg_spread_method_reflect : plutovg_spread_method_repeat;
}

View file

@ -5,13 +5,13 @@
namespace lunasvg {
ClipPathElement::ClipPathElement()
: GraphicsElement(ElementID::ClipPath)
: GraphicsElement(ElementId::ClipPath)
{
}
Units ClipPathElement::clipPathUnits() const
{
auto& value = get(PropertyID::ClipPathUnits);
auto& value = get(PropertyId::ClipPathUnits);
return Parser::parseUnits(value, Units::UserSpaceOnUse);
}

File diff suppressed because it is too large Load diff

View file

@ -1,305 +0,0 @@
#ifndef CSSPARSER_H
#define CSSPARSER_H
#include "parserutils.h"
#include "cssstylesheet.h"
#include <vector>
namespace lunasvg {
class CSSToken {
public:
enum class Type : uint8_t {
Unknown,
Ident,
Function,
AtKeyword,
Hash,
String,
BadString,
Url,
BadUrl,
Delim,
Number,
Percentage,
Dimension,
Whitespace,
Comment,
CDO,
CDC,
Colon,
Semicolon,
Comma,
LeftParenthesis,
RightParenthesis,
LeftSquareBracket,
RightSquareBracket,
LeftCurlyBracket,
RightCurlyBracket,
EndOfFile
};
enum class HashType : uint8_t {
Identifier,
Unrestricted
};
enum class NumberType : uint8_t {
Integer,
Number
};
enum class NumberSign : uint8_t {
None,
Plus,
Minus
};
CSSToken() = default;
explicit CSSToken(Type type) : m_type(type) {}
CSSToken(Type type, uint32_t delim) : m_type(type), m_delim(delim) {}
CSSToken(Type type, std::string_view data) : m_type(type), m_data(data) {}
CSSToken(Type type, HashType hashType, std::string_view data) : m_type(type), m_hashType(hashType), m_data(data) {}
CSSToken(Type type, NumberType numberType, NumberSign numberSign, double number)
: m_type(type), m_numberType(numberType), m_numberSign(numberSign), m_number(number)
{}
CSSToken(Type type, NumberType numberType, NumberSign numberSign, double number, std::string_view unit)
: m_type(type), m_numberType(numberType), m_numberSign(numberSign), m_number(number), m_data(unit)
{}
Type type() const { return m_type; }
HashType hashType() const { return m_hashType; }
NumberType numberType() const { return m_numberType; }
NumberSign numberSign() const { return m_numberSign; }
uint32_t delim() const { return m_delim; }
double number() const { return m_number; }
int integer() const { return static_cast<int>(m_number); }
const std::string_view& data() const { return m_data; }
static Type closeType(Type type) {
switch(type) {
case Type::Function:
case Type::LeftParenthesis:
return Type::RightParenthesis;
case Type::LeftSquareBracket:
return Type::RightSquareBracket;
case Type::LeftCurlyBracket:
return Type::RightCurlyBracket;
default:
assert(false);
}
}
private:
Type m_type{Type::Unknown};
HashType m_hashType{HashType::Identifier};
NumberType m_numberType{NumberType::Integer};
NumberSign m_numberSign{NumberSign::None};
uint32_t m_delim{0};
double m_number{0};
std::string_view m_data;
};
using CSSTokenList = std::vector<CSSToken>;
class CSSTokenStream {
public:
CSSTokenStream(const CSSToken* begin, const CSSToken* end)
: m_begin(begin), m_end(end)
{}
const CSSToken& peek() const {
static const CSSToken EndOfFileToken(CSSToken::Type::EndOfFile);
if(m_begin == m_end)
return EndOfFileToken;
return *m_begin;
}
void consume() {
assert(m_begin < m_end);
m_begin += 1;
}
void consumeWhitespace() {
while(m_begin < m_end && m_begin->type() == CSSToken::Type::Whitespace) {
m_begin += 1;
}
}
void consumeIncludingWhitespace() {
assert(m_begin < m_end);
do {
m_begin += 1;
} while(m_begin < m_end && m_begin->type() == CSSToken::Type::Whitespace);
}
void consumeComponent() {
assert(m_begin < m_end);
switch(m_begin->type()) {
case CSSToken::Type::Function:
case CSSToken::Type::LeftParenthesis:
case CSSToken::Type::LeftSquareBracket:
case CSSToken::Type::LeftCurlyBracket: {
auto closeType = CSSToken::closeType(m_begin->type());
m_begin += 1;
while(m_begin < m_end && m_begin->type() != closeType)
consumeComponent();
if(m_begin < m_end)
m_begin += 1;
break;
}
default:
m_begin += 1;
break;
}
}
CSSTokenStream consumeBlock() {
assert(m_begin < m_end);
auto closeType = CSSToken::closeType(m_begin->type());
m_begin += 1;
auto blockBegin = m_begin;
while(m_begin < m_end && m_begin->type() != closeType)
consumeComponent();
auto blockEnd = m_begin;
if(m_begin < m_end)
m_begin += 1;
return CSSTokenStream(blockBegin, blockEnd);
}
bool empty() const { return m_begin == m_end; }
const CSSToken& operator*() const { return peek(); }
const CSSToken* operator->() const { return &peek(); }
const CSSToken* begin() const { return m_begin; }
const CSSToken* end() const { return m_end; }
private:
const CSSToken* m_begin;
const CSSToken* m_end;
};
class CSSTokenStreamGuard {
public:
CSSTokenStreamGuard(CSSTokenStream& input)
: m_input(input), m_state(input)
{}
void release() { m_state = m_input; }
~CSSTokenStreamGuard() { m_input = m_state; }
private:
CSSTokenStream& m_input;
CSSTokenStream m_state;
};
class CSSTokenizer {
public:
CSSTokenizer(const std::string_view& input)
: m_input(input)
{}
CSSTokenStream tokenize();
private:
static bool isEscapeSequence(char first, char second);
static bool isIdentSequence(char first, char second, char third);
static bool isNumberSequence(char first, char second, char third);
bool isEscapeSequence() const;
bool isIdentSequence() const;
bool isNumberSequence() const;
bool isExponentSequence() const;
std::string_view substring(size_t offset, size_t count);
std::string_view addstring(std::string&& value);
std::string_view consumeName();
uint32_t consumeEscape();
CSSToken consumeStringToken();
CSSToken consumeNumericToken();
CSSToken consumeIdentLikeToken();
CSSToken consumeUrlToken();
CSSToken consumeBadUrlRemnants();
CSSToken consumeWhitespaceToken();
CSSToken consumeCommentToken();
CSSToken consumeSolidusToken();
CSSToken consumeHashToken();
CSSToken consumePlusSignToken();
CSSToken consumeHyphenMinusToken();
CSSToken consumeFullStopToken();
CSSToken consumeLessThanSignToken();
CSSToken consumeCommercialAtToken();
CSSToken consumeReverseSolidusToken();
CSSToken nextToken();
private:
using StringList = std::vector<std::string>;
ParserString m_input;
CSSTokenList m_tokenList;
StringList m_stringList;
};
class CSSParser {
public:
static void parseSheet(CSSRuleList& rules, const std::string_view& content);
static void parseStyle(CSSPropertyList& properties, const std::string_view& content);
private:
static bool consumeRule(CSSTokenStream& input, CSSRuleList& rules);
static bool consumeStyleRule(CSSTokenStream& input, CSSRuleList& rules);
static bool consumeAtRule(CSSTokenStream& input, CSSRuleList& rules);
static bool consumeImportRule(CSSTokenStream& input, CSSRuleList& rules);
static bool consumeSelectorList(CSSTokenStream& input, CSSSelectorList& selectors);
static bool consumeSelector(CSSTokenStream& input, CSSSelector& selector);
static bool consumeSimpleSelector(CSSTokenStream& input, CSSSimpleSelector& selector);
static bool consumeTagSelector(CSSTokenStream& input, CSSSimpleSelector& selector);
static bool consumeIdSelector(CSSTokenStream& input, CSSSimpleSelector& selector);
static bool consumeClassSelector(CSSTokenStream& input, CSSSimpleSelector& selector);
static bool consumeAttributeSelector(CSSTokenStream& input, CSSSimpleSelector& selector);
static bool consumePseudoSelector(CSSTokenStream& input, CSSSimpleSelector& selector);
static bool consumeCombinator(CSSTokenStream& input, CSSSimpleSelector::Combinator& combinator);
static bool consumeMatchPattern(CSSTokenStream& input, CSSSimpleSelector::Pseudo::MatchPattern& pattern);
static void consumeDeclaractionList(CSSTokenStream& input, CSSPropertyList& properties);
static bool consumeDeclaraction(CSSTokenStream& input, CSSPropertyList& properties);
static bool consumeDeclaractionValue(CSSTokenStream& input, CSSPropertyList& properties, CSSPropertyID id, bool important);
static RefPtr<CSSValue> consumeNone(CSSTokenStream& input);
static RefPtr<CSSValue> consumeNormal(CSSTokenStream& input);
static RefPtr<CSSValue> consumePercent(CSSTokenStream& input, bool negative);
static RefPtr<CSSValue> consumeNumber(CSSTokenStream& input, bool negative);
static RefPtr<CSSValue> consumeLength(CSSTokenStream& input, bool negative, bool unitless);
static RefPtr<CSSValue> consumeLengthOrNormal(CSSTokenStream& input, bool negative, bool unitless);
static RefPtr<CSSValue> consumeLengthOrPercent(CSSTokenStream& input, bool negative, bool unitless);
static RefPtr<CSSValue> consumeNumberOrPercent(CSSTokenStream& input, bool negative);
static RefPtr<CSSValue> consumeUrl(CSSTokenStream& input);
static RefPtr<CSSValue> consumeUrlOrNone(CSSTokenStream& input);
static RefPtr<CSSValue> consumeColor(CSSTokenStream& input);
static RefPtr<CSSValue> consumeRgb(CSSTokenStream& input);
static RefPtr<CSSValue> consumeFillOrStroke(CSSTokenStream& input);
static RefPtr<CSSValue> consumeDashList(CSSTokenStream& input);
static RefPtr<CSSValue> consumeFontWeight(CSSTokenStream& input);
static RefPtr<CSSValue> consumeFontSize(CSSTokenStream& input, bool unitless);
static RefPtr<CSSValue> consumeFontFamilyValue(CSSTokenStream& input);
static RefPtr<CSSValue> consumeFontFamily(CSSTokenStream& input);
static RefPtr<CSSValue> consumeValue(CSSTokenStream& input, CSSPropertyID id);
};
} // namespace lunasvg
#endif // CSSPARSER_H

View file

@ -1,378 +0,0 @@
#include "cssstylesheet.h"
#include "cssparser.h"
#include <cassert>
namespace lunasvg {
RefPtr<CSSInitialValue> CSSInitialValue::create()
{
static auto value = adoptPtr(new CSSInitialValue);
return value;
}
RefPtr<CSSInheritValue> CSSInheritValue::create()
{
static auto value = adoptPtr(new CSSInheritValue);
return value;
}
RefPtr<CSSIdentValue> CSSIdentValue::create(CSSValueID value)
{
static std::map<CSSValueID, RefPtr<CSSIdentValue>> table;
auto it = table.find(value);
if(it == table.end()) {
auto item = adoptPtr(new CSSIdentValue(value));
table.emplace(value, item);
return item;
}
return it->second;
}
RefPtr<CSSIntegerValue> CSSIntegerValue::create(int value)
{
return adoptPtr(new CSSIntegerValue(value));
}
RefPtr<CSSNumberValue> CSSNumberValue::create(double value)
{
return adoptPtr(new CSSNumberValue(value));
}
RefPtr<CSSPercentValue> CSSPercentValue::create(double value)
{
return adoptPtr(new CSSPercentValue(value));
}
RefPtr<CSSLengthValue> CSSLengthValue::create(double value, Unit unit)
{
return adoptPtr(new CSSLengthValue(value, unit));
}
RefPtr<CSSStringValue> CSSStringValue::create(std::string value)
{
return adoptPtr(new CSSStringValue(std::move(value)));
}
RefPtr<CSSUrlValue> CSSUrlValue::create(std::string value)
{
return adoptPtr(new CSSUrlValue(std::move(value)));
}
RefPtr<CSSColorValue> CSSColorValue::create(uint32_t value)
{
return adoptPtr(new CSSColorValue(value));
}
RefPtr<CSSColorValue> CSSColorValue::create(uint8_t r, uint8_t g, uint8_t b, uint8_t a)
{
return adoptPtr(new CSSColorValue(a << 24 | r << 16 | g << 8 | b));
}
RefPtr<CSSPairValue> CSSPairValue::create(RefPtr<CSSValue> first, RefPtr<CSSValue> second)
{
return adoptPtr(new CSSPairValue(std::move(first), std::move(second)));
}
RefPtr<CSSListValue> CSSListValue::create(CSSValueList values)
{
return adoptPtr(new CSSListValue(std::move(values)));
}
CSSPropertyID csspropertyid(const std::string_view& name)
{
static const struct {
std::string_view name;
CSSPropertyID value;
} table[] = {
{"clip-path", CSSPropertyID::Clip_Path},
{"clip-rule", CSSPropertyID::Clip_Rule},
{"color", CSSPropertyID::Color},
{"display", CSSPropertyID::Display},
{"fill", CSSPropertyID::Fill},
{"fill-opacity", CSSPropertyID::Fill_Opacity},
{"fill-rule", CSSPropertyID::Fill_Rule},
{"font-family", CSSPropertyID::Font_Family},
{"font-size", CSSPropertyID::Font_Size},
{"font-style", CSSPropertyID::Font_Style},
{"font-variant", CSSPropertyID::Font_Variant},
{"font-weight", CSSPropertyID::Font_Weight},
{"letter-spacing", CSSPropertyID::Letter_Spacing},
{"marker-end", CSSPropertyID::Marker_End},
{"marker-mid", CSSPropertyID::Marker_Mid},
{"marker-start", CSSPropertyID::Marker_Start},
{"mask", CSSPropertyID::Mask},
{"opacity", CSSPropertyID::Opacity},
{"overflow", CSSPropertyID::Overflow},
{"solid-color", CSSPropertyID::Solid_Color},
{"solid-opacity", CSSPropertyID::Solid_Opacity},
{"stop-color", CSSPropertyID::Stop_Color},
{"stop-opacity", CSSPropertyID::Stop_Opacity},
{"stroke", CSSPropertyID::Stroke},
{"stroke-dasharray", CSSPropertyID::Stroke_Dasharray},
{"stroke-dashoffset", CSSPropertyID::Stroke_Dashoffset},
{"stroke-linecap", CSSPropertyID::Stroke_Linecap},
{"stroke-linejoin", CSSPropertyID::Stroke_Linejoin},
{"stroke-miterlimit", CSSPropertyID::Stroke_Miterlimit},
{"stroke-opacity", CSSPropertyID::Stroke_Opacity},
{"stroke-width", CSSPropertyID::Stroke_Width},
{"text-anchor", CSSPropertyID::Text_Anchor},
{"text-decoration", CSSPropertyID::Text_Decoration},
{"visibility", CSSPropertyID::Visibility},
{"word-spacing", CSSPropertyID::Word_Spacing},
};
auto it = std::lower_bound(table, std::end(table), name, [](auto& item, auto& name) { return item.name < name; });
if(it != std::end(table) && it->name == name)
return it->value;
return CSSPropertyID::Unknown;
}
bool CSSSimpleSelector::Pseudo::matchnth(size_t count) const
{
auto [a, b] = pattern;
if(a == 0)
return count == b;
if(a > 0) {
if(count < b)
return false;
return (count - b) % a == 0;
}
if(count > b)
return false;
return (b - count) % -a == 0;
}
std::unique_ptr<CSSRule> CSSRule::create(CSSSelectorList selectors, CSSPropertyList properties)
{
return std::unique_ptr<CSSRule>(new CSSRule(std::move(selectors), std::move(properties)));
}
bool CSSRuleData::match(const Element* element) const
{
if(m_selector.empty())
return false;
if(m_selector.size() == 1)
return matchSimpleSelector(m_selector.front(), element);
auto it = m_selector.rbegin();
auto end = m_selector.rend();
if(!matchSimpleSelector(*it, element))
return false;
++it;
while(it != end) {
switch(it->combinator) {
case CSSSimpleSelector::Combinator::Child:
case CSSSimpleSelector::Combinator::Descendant:
element = element->parent;
break;
case CSSSimpleSelector::Combinator::DirectAdjacent:
case CSSSimpleSelector::Combinator::InDirectAdjacent:
element = element->previousElement();
break;
default:
assert(false);
}
if(element == nullptr)
return false;
auto match = matchSimpleSelector(*it, element);
if(!match && (it->combinator != CSSSimpleSelector::Combinator::Descendant && it->combinator != CSSSimpleSelector::Combinator::InDirectAdjacent))
return false;
if(match || (it->combinator != CSSSimpleSelector::Combinator::Descendant && it->combinator != CSSSimpleSelector::Combinator::InDirectAdjacent))
++it;
}
return true;
}
bool CSSRuleData::matchSimpleSelector(const CSSSimpleSelector& selector, const Element* element)
{
if(selector.id != ElementID::Star && selector.id != element->id)
return false;
for(auto& attribute : selector.attributes)
if(!matchAttributeSelector(attribute, element))
return false;
for(auto& pseudo : selector.pseudos)
if(!matchPseudoClassSelector(pseudo, element))
return false;
return true;
}
bool CSSRuleData::matchAttributeSelector(const CSSSimpleSelector::Attribute& attribute, const Element* element)
{
auto& value = element->get(attribute.id);
switch(attribute.type) {
case CSSSimpleSelector::Attribute::Type::None:
return !value.empty();
case CSSSimpleSelector::Attribute::Type::Equals:
return equals(value, attribute.value, false);
case CSSSimpleSelector::Attribute::Type::Contains:
return contains(value, attribute.value, false);
case CSSSimpleSelector::Attribute::Type::Includes:
return includes(value, attribute.value, false);
case CSSSimpleSelector::Attribute::Type::StartsWith:
return startswith(value, attribute.value, false);
case CSSSimpleSelector::Attribute::Type::EndsWith:
return endswith(value, attribute.value, false);
case CSSSimpleSelector::Attribute::Type::DashEquals:
return dashequals(value, attribute.value, false);
default:
return false;
}
}
bool CSSRuleData::matchPseudoClassSelector(const CSSSimpleSelector::Pseudo& pseudo, const Element* element)
{
if(pseudo.type == CSSSimpleSelector::Pseudo::Type::Empty)
return element->children.empty();
if(pseudo.type == CSSSimpleSelector::Pseudo::Type::Root)
return element->parent == nullptr;
if(pseudo.type == CSSSimpleSelector::Pseudo::Type::Is) {
for(auto& selector : pseudo.selectors) {
for(auto& sel : selector) {
if(!matchSimpleSelector(sel, element)) {
return false;
}
}
}
return true;
}
if(pseudo.type == CSSSimpleSelector::Pseudo::Type::Not) {
for(auto& selector : pseudo.selectors) {
for(auto& sel : selector) {
if(matchSimpleSelector(sel, element)) {
return false;
}
}
}
return true;
}
if(pseudo.type == CSSSimpleSelector::Pseudo::Type::FirstChild)
return !element->previousElement();
if(pseudo.type == CSSSimpleSelector::Pseudo::Type::LastChild)
return !element->nextElement();
if(pseudo.type == CSSSimpleSelector::Pseudo::Type::OnlyChild)
return !(element->previousElement() || element->nextElement());
if(pseudo.type == CSSSimpleSelector::Pseudo::Type::FirstOfType) {
auto child = element->nextElement();
while(child) {
if(child->id == element->id)
return false;
child = element->nextElement();
}
return true;
}
if(pseudo.type == CSSSimpleSelector::Pseudo::Type::LastOfType) {
auto child = element->nextElement();
while(child) {
if(child->id == element->id)
return false;
child = element->nextElement();
}
return true;
}
if(pseudo.type == CSSSimpleSelector::Pseudo::Type::OnlyOfType) {
auto child = element->nextElement();
while(child) {
if(child->id == element->id)
return false;
child = element->nextElement();
}
child = element->nextElement();
while(child) {
if(child->id == element->id)
return false;
child = element->nextElement();
}
return true;
}
if(pseudo.type == CSSSimpleSelector::Pseudo::Type::NthChild) {
int count = 1;
auto child = element->previousElement();
while(child) {
count += 1;
child = element->previousElement();
}
return pseudo.matchnth(count);
}
if(pseudo.type == CSSSimpleSelector::Pseudo::Type::NthLastChild) {
int count = 1;
auto child = element->nextElement();
while(child) {
count += 1;
child = element->nextElement();
}
return pseudo.matchnth(count);
}
if(pseudo.type == CSSSimpleSelector::Pseudo::Type::NthOfType) {
int count = 1;
auto child = element->previousElement();
while(child && child->id == element->id) {
count += 1;
child = element->previousElement();
}
return pseudo.matchnth(count);
}
if(pseudo.type == CSSSimpleSelector::Pseudo::Type::NthLastOfType) {
int count = 1;
auto child = element->nextElement();
while(child && child->id == element->id) {
count += 1;
child = element->nextElement();
}
return pseudo.matchnth(count);
}
return false;
}
void CSSStyleSheet::parse(const std::string_view& content)
{
auto position = m_ruleList.size();
CSSParser::parseSheet(m_ruleList, content);
for(; position < m_ruleList.size(); ++position) {
auto& rule = m_ruleList[position];
auto& properties = rule->properties();
for(auto& selector : rule->selectors()) {
uint32_t specificity = 0;
for(auto& sel : selector) {
specificity += (sel.id == ElementID::Star) ? 0x0 : 0x1;
for(auto& attribute : sel.attributes) {
specificity += (attribute.id == PropertyID::Id) ? 0x10000 : 0x100;
}
}
m_ruleSet.emplace(selector, properties, specificity, position);
}
}
}
} // namespace lunasvg

View file

@ -1,495 +0,0 @@
#ifndef CSSSTYLESHEET_H
#define CSSSTYLESHEET_H
#include "element.h"
#include "pointer.h"
#include <map>
#include <set>
namespace lunasvg {
class CSSValue : public RefCounted<CSSValue> {
public:
virtual ~CSSValue() = default;
virtual bool isInitialValue() const { return false; }
virtual bool isInheritValue() const { return false; }
virtual bool isIdentValue() const { return false; }
virtual bool isIntegerValue() const { return false; }
virtual bool isNumberValue() const { return false; }
virtual bool isPercentValue() const { return false; }
virtual bool isLengthValue() const { return false; }
virtual bool isStringValue() const { return false; }
virtual bool isUrlValue() const { return false; }
virtual bool isColorValue() const { return false; }
virtual bool isPairValue() const { return false; }
virtual bool isListValue() const { return false; }
protected:
CSSValue() = default;
};
using CSSValueList = std::vector<RefPtr<CSSValue>>;
class CSSInitialValue final : public CSSValue {
public:
static RefPtr<CSSInitialValue> create();
bool isInitialValue() const final { return true; }
private:
CSSInitialValue() = default;
};
template<>
struct is<CSSInitialValue> {
static bool check(const CSSValue& value) { return value.isInitialValue(); }
};
class CSSInheritValue final : public CSSValue {
public:
static RefPtr<CSSInheritValue> create();
bool isInheritValue() const final { return true; }
private:
CSSInheritValue() = default;
};
template<>
struct is<CSSInheritValue> {
static bool check(const CSSValue& value) { return value.isInheritValue(); }
};
enum class CSSValueID {
Unknown,
Auto,
Bevel,
Bold,
Bolder,
Butt,
Clip,
Collapse,
Color,
CurrentColor,
End,
Evenodd,
Hidden,
Inherit,
Initial,
Inline,
Italic,
Large,
Larger,
Lighter,
Medium,
Middle,
Miter,
None,
Nonzero,
Normal,
Oblique,
Round,
Small,
SmallCaps,
Smaller,
Square,
Start,
Stroke,
Visible,
XLarge,
XSmall,
XxLarge,
XxSmall,
XxxLarge
};
class CSSIdentValue final : public CSSValue {
public:
static RefPtr<CSSIdentValue> create(CSSValueID value);
CSSValueID value() const { return m_value; }
bool isIdentValue() const final { return true; }
private:
CSSIdentValue(CSSValueID value) : m_value(value) {}
CSSValueID m_value;
};
template<>
struct is<CSSIdentValue> {
static bool check(const CSSValue& value) { return value.isIdentValue(); }
};
class CSSIntegerValue final : public CSSValue {
public:
static RefPtr<CSSIntegerValue> create(int value);
int value() const { return m_value; }
bool isIntegerValue() const final { return true; }
private:
CSSIntegerValue(int value) : m_value(value) {}
int m_value;
};
template<>
struct is<CSSIntegerValue> {
static bool check(const CSSValue& value) { return value.isIntegerValue(); }
};
class CSSNumberValue final : public CSSValue {
public:
static RefPtr<CSSNumberValue> create(double value);
double value() const { return m_value; }
bool isNumberValue() const final { return true; }
private:
CSSNumberValue(double value) : m_value(value) {}
double m_value;
};
template<>
struct is<CSSNumberValue> {
static bool check(const CSSValue& value) { return value.isNumberValue(); }
};
class CSSPercentValue final : public CSSValue {
public:
static RefPtr<CSSPercentValue> create(double value);
double value() const { return m_value; }
bool isPercentValue() const final { return true; }
private:
CSSPercentValue(double value) : m_value(value) {}
double m_value;
};
template<>
struct is<CSSPercentValue> {
static bool check(const CSSValue& value) { return value.isPercentValue(); }
};
class CSSLengthValue final : public CSSValue {
public:
enum class Unit {
None,
Ems,
Exs,
Pixels,
Centimeters,
Millimeters,
Inches,
Points,
Picas,
ViewportWidth,
ViewportHeight,
ViewportMin,
ViewportMax,
Rems,
Chs
};
static RefPtr<CSSLengthValue> create(double value, Unit unit);
double value() const { return m_value; }
Unit unit() const { return m_unit; }
bool isLengthValue() const final { return true; }
private:
CSSLengthValue(double value, Unit unit)
: m_value(value), m_unit(unit)
{}
double m_value;
Unit m_unit;
};
template<>
struct is<CSSLengthValue> {
static bool check(const CSSValue& value) { return value.isLengthValue(); }
};
class CSSStringValue final : public CSSValue {
public:
static RefPtr<CSSStringValue> create(std::string value);
const std::string& value() const { return m_value; }
bool isStringValue() const final { return true; }
private:
CSSStringValue(std::string value) : m_value(std::move(value)) {}
std::string m_value;
};
template<>
struct is<CSSStringValue> {
static bool check(const CSSValue& value) { return value.isStringValue(); }
};
class CSSUrlValue final : public CSSValue {
public:
static RefPtr<CSSUrlValue> create(std::string value);
const std::string& value() const { return m_value; }
bool isUrlValue() const final { return true; }
private:
CSSUrlValue(std::string value) : m_value(std::move(value)) {}
std::string m_value;
};
template<>
struct is<CSSUrlValue> {
static bool check(const CSSValue& value) { return value.isUrlValue(); }
};
class CSSColorValue final : public CSSValue {
public:
static RefPtr<CSSColorValue> create(uint32_t value);
static RefPtr<CSSColorValue> create(uint8_t r, uint8_t g, uint8_t b, uint8_t a);
uint32_t value() const { return m_value; }
bool isColorValue() const final { return true; }
private:
CSSColorValue(uint32_t value) : m_value(value) {}
uint32_t m_value;
};
template<>
struct is<CSSColorValue> {
static bool check(const CSSValue& value) { return value.isColorValue(); }
};
class CSSPairValue final : public CSSValue {
public:
static RefPtr<CSSPairValue> create(RefPtr<CSSValue> first, RefPtr<CSSValue> second);
const RefPtr<CSSValue>& first() const { return m_first; }
const RefPtr<CSSValue>& second() const { return m_second; }
bool isPairValue() const final { return true; }
private:
CSSPairValue(RefPtr<CSSValue> first, RefPtr<CSSValue> second)
: m_first(first), m_second(second)
{}
RefPtr<CSSValue> m_first;
RefPtr<CSSValue> m_second;
};
template<>
struct is<CSSPairValue> {
static bool check(const CSSValue& value) { return value.isPairValue(); }
};
class CSSListValue : public CSSValue {
public:
static RefPtr<CSSListValue> create(CSSValueList values);
size_t length() const { return m_values.size(); }
const RefPtr<CSSValue>& front() const { return m_values.front(); }
const RefPtr<CSSValue>& back() const { return m_values.back(); }
const RefPtr<CSSValue>& at(size_t index) const { return m_values.at(index); }
const CSSValueList& values() const { return m_values; }
bool isListValue() const final { return true; }
protected:
CSSListValue(CSSValueList values) : m_values(std::move(values)) {}
CSSValueList m_values;
};
enum class CSSPropertyID {
Unknown = 0,
Clip_Path,
Clip_Rule,
Color,
Display,
Fill,
Fill_Opacity,
Fill_Rule,
Font_Family,
Font_Size,
Font_Style,
Font_Variant,
Font_Weight,
Letter_Spacing,
Marker_End,
Marker_Mid,
Marker_Start,
Mask,
Opacity,
Overflow,
Solid_Color,
Solid_Opacity,
Stop_Color,
Stop_Opacity,
Stroke,
Stroke_Dasharray,
Stroke_Dashoffset,
Stroke_Linecap,
Stroke_Linejoin,
Stroke_Miterlimit,
Stroke_Opacity,
Stroke_Width,
Text_Anchor,
Text_Decoration,
Visibility,
Word_Spacing
};
CSSPropertyID csspropertyid(const std::string_view& name);
class CSSProperty {
public:
CSSProperty(CSSPropertyID id, bool important, RefPtr<CSSValue> value)
: m_id(id), m_important(important), m_value(value)
{}
CSSPropertyID id() const { return m_id; }
bool important() const { return m_important; }
const RefPtr<CSSValue>& value() const { return m_value; }
private:
CSSPropertyID m_id;
bool m_important;
RefPtr<CSSValue> m_value;
};
using CSSPropertyList = std::vector<CSSProperty>;
using CSSPropertyMap = std::map<CSSPropertyID, CSSProperty>;
struct CSSSimpleSelector;
using CSSSelector = std::vector<CSSSimpleSelector>;
using CSSSelectorList = std::vector<CSSSelector>;
struct CSSSimpleSelector {
struct Attribute {
enum class Type {
None,
Equals,
Contains,
Includes,
StartsWith,
EndsWith,
DashEquals
};
Type type{Type::None};
PropertyID id{PropertyID::Unknown};
std::string value;
};
struct Pseudo {
enum class Type {
Unknown,
Empty,
Root,
Is,
Not,
FirstChild,
LastChild,
OnlyChild,
FirstOfType,
LastOfType,
OnlyOfType,
NthChild,
NthLastChild,
NthOfType,
NthLastOfType
};
using MatchPattern = std::pair<int16_t, int16_t>;
bool matchnth(size_t count) const;
Type type{Type::Unknown};
MatchPattern pattern;
CSSSelectorList selectors;
};
enum class Combinator {
None,
Descendant,
Child,
DirectAdjacent,
InDirectAdjacent
};
Combinator combinator{Combinator::Descendant};
ElementID id{ElementID::Star};
std::vector<Attribute> attributes;
std::vector<Pseudo> pseudos;
};
class CSSRule {
public:
static std::unique_ptr<CSSRule> create(CSSSelectorList selectors, CSSPropertyList properties);
const CSSSelectorList& selectors() const { return m_selectors; }
const CSSPropertyList& properties() const { return m_properties; }
private:
CSSRule(CSSSelectorList selectors, CSSPropertyList properties)
: m_selectors(std::move(selectors)), m_properties(std::move(properties))
{}
CSSSelectorList m_selectors;
CSSPropertyList m_properties;
};
using CSSRuleList = std::vector<std::unique_ptr<CSSRule>>;
class CSSRuleData {
public:
CSSRuleData(const CSSSelector& selector, const CSSPropertyList& properties, uint32_t specificity, uint32_t position)
: m_selector(selector), m_properties(properties), m_specificity(specificity), m_position(position)
{}
const CSSSelector& selector() const { return m_selector; }
const CSSPropertyList& properties() const { return m_properties; }
const uint32_t& specificity() const { return m_specificity; }
const uint32_t& position() const { return m_position; }
bool match(const Element* element) const;
private:
static bool matchSimpleSelector(const CSSSimpleSelector& selector, const Element* element);
static bool matchAttributeSelector(const CSSSimpleSelector::Attribute& attribute, const Element* element);
static bool matchPseudoClassSelector(const CSSSimpleSelector::Pseudo& pseudo, const Element* element);
private:
const CSSSelector& m_selector;
const CSSPropertyList& m_properties;
uint32_t m_specificity;
uint32_t m_position;
};
inline bool operator<(const CSSRuleData& a, const CSSRuleData& b) { return std::tie(a.specificity(), a.position()) < std::tie(b.specificity(), b.position()); }
inline bool operator>(const CSSRuleData& a, const CSSRuleData& b) { return std::tie(a.specificity(), a.position()) > std::tie(b.specificity(), b.position()); }
using CSSRuleSet = std::multiset<CSSRuleData>;
class ComputedStyle;
class CSSStyleSheet {
public:
CSSStyleSheet() = default;
void parse(const std::string_view& content);
bool empty() const { return m_ruleList.empty(); }
RefPtr<ComputedStyle> styleForElement(const Element* element, const RefPtr<ComputedStyle>& parentStyle) const;
private:
CSSRuleList m_ruleList;
CSSRuleSet m_ruleSet;
};
} // namespace lunasvg
#endif // CSSSTYLESHEET_H

View file

@ -3,7 +3,7 @@
namespace lunasvg {
DefsElement::DefsElement()
: GraphicsElement(ElementID::Defs)
: GraphicsElement(ElementId::Defs)
{
}

View file

@ -2,146 +2,9 @@
#include "parser.h"
#include "svgelement.h"
#include <algorithm>
namespace lunasvg {
ElementID elementid(const std::string_view& name)
{
static const struct {
std::string_view name;
ElementID value;
} table[] = {
{"a", ElementID::A},
{"circle", ElementID::Circle},
{"clipPath", ElementID::ClipPath},
{"defs", ElementID::Defs},
{"ellipse", ElementID::Ellipse},
{"g", ElementID::G},
{"image", ElementID::Image},
{"line", ElementID::Line},
{"linearGradient", ElementID::LinearGradient},
{"marker", ElementID::Marker},
{"mask", ElementID::Mask},
{"path", ElementID::Path},
{"pattern", ElementID::Pattern},
{"polygon", ElementID::Polygon},
{"polyline", ElementID::Polyline},
{"radialGradient", ElementID::RadialGradient},
{"rect", ElementID::Rect},
{"solidColor", ElementID::SolidColor},
{"stop", ElementID::Stop},
{"style", ElementID::Style},
{"svg", ElementID::Svg},
{"switch", ElementID::Switch},
{"symbol", ElementID::Symbol},
{"text", ElementID::Text},
{"textPath", ElementID::TextPath},
{"tref", ElementID::Tref},
{"tspan", ElementID::Tspan},
{"use", ElementID::Use}
};
auto it = std::lower_bound(table, std::end(table), name, [](auto& item, auto& name) { return item.name < name; });
if(it != std::end(table) && it->name == name)
return it->value;
return ElementID::Unknown;
}
PropertyID propertyid(const std::string_view& name)
{
static const struct {
std::string_view name;
PropertyID value;
} table[] = {
{"class", PropertyID::Class},
{"clip-path", PropertyID::Clip_Path},
{"clip-rule", PropertyID::Clip_Rule},
{"clipPathUnits", PropertyID::ClipPathUnits},
{"color", PropertyID::Color},
{"cx", PropertyID::Cx},
{"cy", PropertyID::Cy},
{"d", PropertyID::D},
{"dx", PropertyID::Dx},
{"dy", PropertyID::Dy},
{"display", PropertyID::Display},
{"fill", PropertyID::Fill},
{"fill-opacity", PropertyID::Fill_Opacity},
{"fill-rule", PropertyID::Fill_Rule},
{"font-family", PropertyID::Font_Family},
{"font-size", PropertyID::Font_Size},
{"font-style", PropertyID::Font_Style},
{"font-variant", PropertyID::Font_Variant},
{"font-weight", PropertyID::Font_Weight},
{"fx", PropertyID::Fx},
{"fy", PropertyID::Fy},
{"gradientTransform", PropertyID::GradientTransform},
{"gradientUnits", PropertyID::GradientUnits},
{"height", PropertyID::Height},
{"href", PropertyID::Href},
{"id", PropertyID::Id},
{"letter-spacing", PropertyID::Letter_Spacing},
{"marker-end", PropertyID::Marker_End},
{"marker-mid", PropertyID::Marker_Mid},
{"marker-start", PropertyID::Marker_Start},
{"markerHeight", PropertyID::MarkerHeight},
{"markerUnits", PropertyID::MarkerUnits},
{"markerWidth", PropertyID::MarkerWidth},
{"mask", PropertyID::Mask},
{"maskContentUnits", PropertyID::MaskContentUnits},
{"maskUnits", PropertyID::MaskUnits},
{"offset", PropertyID::Offset},
{"opacity", PropertyID::Opacity},
{"orient", PropertyID::Orient},
{"overflow", PropertyID::Overflow},
{"patternContentUnits", PropertyID::PatternContentUnits},
{"patternTransform", PropertyID::PatternTransform},
{"patternUnits", PropertyID::PatternUnits},
{"points", PropertyID::Points},
{"preserveAspectRatio", PropertyID::PreserveAspectRatio},
{"r", PropertyID::R},
{"refX", PropertyID::RefX},
{"refY", PropertyID::RefY},
{"rotate", PropertyID::Rotate},
{"rx", PropertyID::Rx},
{"ry", PropertyID::Ry},
{"solid-color", PropertyID::Solid_Color},
{"solid-opacity", PropertyID::Solid_Opacity},
{"spreadMethod", PropertyID::SpreadMethod},
{"startOffset", PropertyID::StartOffset},
{"stop-color", PropertyID::Stop_Color},
{"stop-opacity", PropertyID::Stop_Opacity},
{"stroke", PropertyID::Stroke},
{"stroke-dasharray", PropertyID::Stroke_Dasharray},
{"stroke-dashoffset", PropertyID::Stroke_Dashoffset},
{"stroke-linecap", PropertyID::Stroke_Linecap},
{"stroke-linejoin", PropertyID::Stroke_Linejoin},
{"stroke-miterlimit", PropertyID::Stroke_Miterlimit},
{"stroke-opacity", PropertyID::Stroke_Opacity},
{"stroke-width", PropertyID::Stroke_Width},
{"style", PropertyID::Style},
{"text-anchor", PropertyID::Text_Anchor},
{"text-decoration", PropertyID::Text_Decoration},
{"transform", PropertyID::Transform},
{"viewBox", PropertyID::ViewBox},
{"visibility", PropertyID::Visibility},
{"width", PropertyID::Width},
{"word-spacing", PropertyID::Word_Spacing},
{"x", PropertyID::X},
{"x1", PropertyID::X1},
{"x2", PropertyID::X2},
{"y", PropertyID::Y},
{"y1", PropertyID::Y1},
{"y2", PropertyID::Y2}
};
auto it = std::lower_bound(table, std::end(table), name, [](auto& item, auto& name) { return item.name < name; });
if(it != std::end(table) && it->name == name)
return it->value;
return PropertyID::Unknown;
}
void PropertyList::set(PropertyID id, const std::string& value, int specificity)
void PropertyList::set(PropertyId id, const std::string& value, int specificity)
{
auto property = get(id);
if(property == nullptr)
@ -158,7 +21,7 @@ void PropertyList::set(PropertyID id, const std::string& value, int specificity)
property->value = value;
}
Property* PropertyList::get(PropertyID id) const
Property* PropertyList::get(PropertyId id) const
{
auto data = m_properties.data();
auto end = data + m_properties.size();
@ -196,19 +59,19 @@ std::unique_ptr<Node> TextNode::clone() const
return std::move(node);
}
Element::Element(ElementID id)
Element::Element(ElementId id)
: id(id)
{
}
void Element::set(PropertyID id, const std::string& value, int specificity)
void Element::set(PropertyId id, const std::string& value, int specificity)
{
properties.set(id, value, specificity);
}
static const std::string EmptyString;
const std::string& Element::get(PropertyID id) const
const std::string& Element::get(PropertyId id) const
{
auto property = properties.get(id);
if(property == nullptr)
@ -219,7 +82,7 @@ const std::string& Element::get(PropertyID id) const
static const std::string InheritString{"inherit"};
const std::string& Element::find(PropertyID id) const
const std::string& Element::find(PropertyId id) const
{
auto element = this;
do {
@ -232,12 +95,12 @@ const std::string& Element::find(PropertyID id) const
return EmptyString;
}
bool Element::has(PropertyID id) const
bool Element::has(PropertyId id) const
{
return properties.get(id);
}
Element* Element::previousElement() const
Element* Element::previousSibling() const
{
if(parent == nullptr)
return nullptr;
@ -259,7 +122,7 @@ Element* Element::previousElement() const
return nullptr;
}
Element* Element::nextElement() const
Element* Element::nextSibling() const
{
if(parent == nullptr)
return nullptr;
@ -299,15 +162,15 @@ Rect Element::currentViewport() const
if(parent == nullptr)
{
auto element = static_cast<const SVGElement*>(this);
if(element->has(PropertyID::ViewBox))
if(element->has(PropertyId::ViewBox))
return element->viewBox();
return Rect{0, 0, 300, 150};
}
if(parent->id == ElementID::Svg)
if(parent->id == ElementId::Svg)
{
auto element = static_cast<SVGElement*>(parent);
if(element->has(PropertyID::ViewBox))
if(element->has(PropertyId::ViewBox))
return element->viewBox();
LengthContext lengthContext(element);

View file

@ -8,16 +8,15 @@
namespace lunasvg {
enum class ElementID {
enum class ElementId
{
Unknown = 0,
Star,
A,
Circle,
ClipPath,
Defs,
Ellipse,
G,
Image,
Line,
LinearGradient,
Marker,
@ -32,16 +31,12 @@ enum class ElementID {
Stop,
Style,
Svg,
Switch,
Symbol,
Text,
TextPath,
Tref,
Tspan,
Use
};
enum class PropertyID {
enum class PropertyId
{
Unknown = 0,
Class,
Clip_Path,
@ -51,17 +46,10 @@ enum class PropertyID {
Cx,
Cy,
D,
Dx,
Dy,
Display,
Fill,
Fill_Opacity,
Fill_Rule,
Font_Family,
Font_Size,
Font_Style,
Font_Variant,
Font_Weight,
Fx,
Fy,
GradientTransform,
@ -69,7 +57,6 @@ enum class PropertyID {
Height,
Href,
Id,
Letter_Spacing,
Marker_End,
Marker_Mid,
Marker_Start,
@ -91,13 +78,11 @@ enum class PropertyID {
R,
RefX,
RefY,
Rotate,
Rx,
Ry,
Solid_Color,
Solid_Opacity,
SpreadMethod,
StartOffset,
Stop_Color,
Stop_Opacity,
Stroke,
@ -109,13 +94,10 @@ enum class PropertyID {
Stroke_Opacity,
Stroke_Width,
Style,
Text_Anchor,
Text_Decoration,
Transform,
ViewBox,
Visibility,
Width,
Word_Spacing,
X,
X1,
X2,
@ -124,12 +106,9 @@ enum class PropertyID {
Y2
};
ElementID elementid(const std::string_view& name);
PropertyID propertyid(const std::string_view& name);
struct Property
{
PropertyID id;
PropertyId id;
std::string value;
int specificity;
};
@ -139,11 +118,10 @@ class PropertyList
public:
PropertyList() = default;
void set(PropertyID id, const std::string& value, int specificity);
Property* get(PropertyID id) const;
void set(PropertyId id, const std::string& value, int specificity);
Property* get(PropertyId id) const;
void add(const Property& property);
void add(const PropertyList& properties);
void clear() { m_properties.clear(); }
private:
std::vector<Property> m_properties;
@ -181,22 +159,20 @@ public:
std::string text;
};
using Attribute = std::pair<PropertyID, std::string>;
using AttributeList = std::vector<Attribute>;
using NodeList = std::list<std::unique_ptr<Node>>;
class Element : public Node
{
public:
Element(ElementID id);
Element(ElementId id);
void set(PropertyID id, const std::string& value, int specificity);
const std::string& get(PropertyID id) const;
const std::string& find(PropertyID id) const;
bool has(PropertyID id) const;
void set(PropertyId id, const std::string& value, int specificity);
const std::string& get(PropertyId id) const;
const std::string& find(PropertyId id) const;
bool has(PropertyId id) const;
Element* previousElement() const;
Element* nextElement() const;
Element* previousSibling() const;
Element* nextSibling() const;
Node* addChild(std::unique_ptr<Node> child);
void layoutChildren(LayoutContext* context, LayoutContainer* current) const;
Rect currentViewport() const;
@ -232,7 +208,7 @@ public:
}
public:
ElementID id;
ElementId id;
NodeList children;
PropertyList properties;
};

View file

@ -4,7 +4,7 @@
namespace lunasvg {
GElement::GElement()
: GraphicsElement(ElementID::G)
: GraphicsElement(ElementId::G)
{
}

View file

@ -6,7 +6,7 @@
namespace lunasvg {
GeometryElement::GeometryElement(ElementID id)
GeometryElement::GeometryElement(ElementId id)
: GraphicsElement(id)
{
}
@ -35,13 +35,13 @@ void GeometryElement::layout(LayoutContext* context, LayoutContainer* current) c
}
PathElement::PathElement()
: GeometryElement(ElementID::Path)
: GeometryElement(ElementId::Path)
{
}
Path PathElement::d() const
{
auto& value = get(PropertyID::D);
auto& value = get(PropertyId::D);
return Parser::parsePath(value);
}
@ -55,19 +55,19 @@ std::unique_ptr<Node> PathElement::clone() const
return cloneElement<PathElement>();
}
PolyElement::PolyElement(ElementID id)
PolyElement::PolyElement(ElementId id)
: GeometryElement(id)
{
}
PointList PolyElement::points() const
{
auto& value = get(PropertyID::Points);
auto& value = get(PropertyId::Points);
return Parser::parsePointList(value);
}
PolygonElement::PolygonElement()
: PolyElement(ElementID::Polygon)
: PolyElement(ElementId::Polygon)
{
}
@ -92,7 +92,7 @@ std::unique_ptr<Node> PolygonElement::clone() const
}
PolylineElement::PolylineElement()
: PolyElement(ElementID::Polyline)
: PolyElement(ElementId::Polyline)
{
}
@ -116,25 +116,25 @@ std::unique_ptr<Node> PolylineElement::clone() const
}
CircleElement::CircleElement()
: GeometryElement(ElementID::Circle)
: GeometryElement(ElementId::Circle)
{
}
Length CircleElement::cx() const
{
auto& value = get(PropertyID::Cx);
auto& value = get(PropertyId::Cx);
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
}
Length CircleElement::cy() const
{
auto& value = get(PropertyID::Cy);
auto& value = get(PropertyId::Cy);
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
}
Length CircleElement::r() const
{
auto& value = get(PropertyID::R);
auto& value = get(PropertyId::R);
return Parser::parseLength(value, ForbidNegativeLengths, Length::Zero);
}
@ -160,31 +160,31 @@ std::unique_ptr<Node> CircleElement::clone() const
}
EllipseElement::EllipseElement()
: GeometryElement(ElementID::Ellipse)
: GeometryElement(ElementId::Ellipse)
{
}
Length EllipseElement::cx() const
{
auto& value = get(PropertyID::Cx);
auto& value = get(PropertyId::Cx);
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
}
Length EllipseElement::cy() const
{
auto& value = get(PropertyID::Cy);
auto& value = get(PropertyId::Cy);
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
}
Length EllipseElement::rx() const
{
auto& value = get(PropertyID::Rx);
auto& value = get(PropertyId::Rx);
return Parser::parseLength(value, ForbidNegativeLengths, Length::Zero);
}
Length EllipseElement::ry() const
{
auto& value = get(PropertyID::Ry);
auto& value = get(PropertyId::Ry);
return Parser::parseLength(value, ForbidNegativeLengths, Length::Zero);
}
@ -212,31 +212,31 @@ std::unique_ptr<Node> EllipseElement::clone() const
}
LineElement::LineElement()
: GeometryElement(ElementID::Line)
: GeometryElement(ElementId::Line)
{
}
Length LineElement::x1() const
{
auto& value = get(PropertyID::X1);
auto& value = get(PropertyId::X1);
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
}
Length LineElement::y1() const
{
auto& value = get(PropertyID::Y1);
auto& value = get(PropertyId::Y1);
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
}
Length LineElement::x2() const
{
auto& value = get(PropertyID::X2);
auto& value = get(PropertyId::X2);
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
}
Length LineElement::y2() const
{
auto& value = get(PropertyID::Y2);
auto& value = get(PropertyId::Y2);
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
}
@ -260,43 +260,43 @@ std::unique_ptr<Node> LineElement::clone() const
}
RectElement::RectElement()
: GeometryElement(ElementID::Rect)
: GeometryElement(ElementId::Rect)
{
}
Length RectElement::x() const
{
auto& value = get(PropertyID::X);
auto& value = get(PropertyId::X);
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
}
Length RectElement::y() const
{
auto& value = get(PropertyID::Y);
auto& value = get(PropertyId::Y);
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
}
Length RectElement::rx() const
{
auto& value = get(PropertyID::Rx);
auto& value = get(PropertyId::Rx);
return Parser::parseLength(value, ForbidNegativeLengths, Length::Unknown);
}
Length RectElement::ry() const
{
auto& value = get(PropertyID::Ry);
auto& value = get(PropertyId::Ry);
return Parser::parseLength(value, ForbidNegativeLengths, Length::Unknown);
}
Length RectElement::width() const
{
auto& value = get(PropertyID::Width);
auto& value = get(PropertyId::Width);
return Parser::parseLength(value, ForbidNegativeLengths, Length::Zero);
}
Length RectElement::height() const
{
auto& value = get(PropertyID::Height);
auto& value = get(PropertyId::Height);
return Parser::parseLength(value, ForbidNegativeLengths, Length::Zero);
}

View file

@ -10,7 +10,7 @@ class LayoutShape;
class GeometryElement : public GraphicsElement
{
public:
GeometryElement(ElementID id);
GeometryElement(ElementId id);
bool isGeometry() const { return true; }
virtual void layout(LayoutContext* context, LayoutContainer* current) const;
@ -31,7 +31,7 @@ public:
class PolyElement : public GeometryElement
{
public:
PolyElement(ElementID id);
PolyElement(ElementId id);
PointList points() const;
};

View file

@ -3,14 +3,14 @@
namespace lunasvg {
GraphicsElement::GraphicsElement(ElementID id)
GraphicsElement::GraphicsElement(ElementId id)
: StyledElement(id)
{
}
Transform GraphicsElement::transform() const
{
auto& value = get(PropertyID::Transform);
auto& value = get(PropertyId::Transform);
return Parser::parseTransform(value);
}

View file

@ -8,7 +8,7 @@ namespace lunasvg {
class GraphicsElement : public StyledElement
{
public:
GraphicsElement(ElementID id);
GraphicsElement(ElementId id);
Transform transform() const;
};

View file

@ -479,14 +479,14 @@ void RenderState::endGroup(RenderState& state, const BlendInfo& info)
state.canvas->blend(canvas.get(), BlendMode::Src_Over, m_mode == RenderMode::Display ? info.opacity : 1.0);
}
LayoutContext::LayoutContext(const TreeBuilder* builder, LayoutSymbol* root)
: m_builder(builder), m_root(root)
LayoutContext::LayoutContext(const ParseDocument* document, LayoutSymbol* root)
: m_document(document), m_root(root)
{
}
Element* LayoutContext::getElementById(const std::string& id) const
{
return m_builder->getElementById(id);
return m_document->getElementById(id);
}
LayoutObject* LayoutContext::getResourcesById(const std::string& id) const
@ -517,7 +517,7 @@ LayoutMask* LayoutContext::getMasker(const std::string& id)
return static_cast<LayoutMask*>(ref);
auto element = getElementById(id);
if(element == nullptr || element->id != ElementID::Mask)
if(element == nullptr || element->id != ElementId::Mask)
return nullptr;
auto masker = static_cast<MaskElement*>(element)->getMasker(this);
@ -534,7 +534,7 @@ LayoutClipPath* LayoutContext::getClipper(const std::string& id)
return static_cast<LayoutClipPath*>(ref);
auto element = getElementById(id);
if(element == nullptr || element->id != ElementID::ClipPath)
if(element == nullptr || element->id != ElementId::ClipPath)
return nullptr;
auto clipper = static_cast<ClipPathElement*>(element)->getClipper(this);
@ -551,7 +551,7 @@ LayoutMarker* LayoutContext::getMarker(const std::string& id)
return static_cast<LayoutMarker*>(ref);
auto element = getElementById(id);
if(element == nullptr || element->id != ElementID::Marker)
if(element == nullptr || element->id != ElementId::Marker)
return nullptr;
auto marker = static_cast<MarkerElement*>(element)->getMarker(this);

View file

@ -346,13 +346,14 @@ private:
RenderMode m_mode;
};
class TreeBuilder;
class ParseDocument;
class StyledElement;
class GeometryElement;
class LayoutContext {
class LayoutContext
{
public:
LayoutContext(const TreeBuilder* builder, LayoutSymbol* root);
LayoutContext(const ParseDocument* document, LayoutSymbol* root);
Element* getElementById(const std::string& id) const;
LayoutObject* getResourcesById(const std::string& id) const;
@ -372,7 +373,7 @@ public:
bool hasReference(const Element* element) const;
private:
const TreeBuilder* m_builder;
const ParseDocument* m_document;
LayoutSymbol* m_root;
std::map<std::string, LayoutObject*> m_resourcesCache;
std::set<const Element*> m_references;

View file

@ -292,11 +292,11 @@ std::unique_ptr<Document> Document::loadFromData(const std::string& string)
std::unique_ptr<Document> Document::loadFromData(const char* data, std::size_t size)
{
TreeBuilder builder;
if(!builder.parse(data, size))
ParseDocument parser;
if(!parser.parse(data, size))
return nullptr;
auto root = builder.build();
auto root = parser.layout();
if(!root || root->children.empty())
return nullptr;

View file

@ -5,55 +5,55 @@
namespace lunasvg {
MarkerElement::MarkerElement()
: StyledElement(ElementID::Marker)
: StyledElement(ElementId::Marker)
{
}
Length MarkerElement::refX() const
{
auto& value = get(PropertyID::RefX);
auto& value = get(PropertyId::RefX);
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
}
Length MarkerElement::refY() const
{
auto& value = get(PropertyID::RefY);
auto& value = get(PropertyId::RefY);
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
}
Length MarkerElement::markerWidth() const
{
auto& value = get(PropertyID::MarkerWidth);
auto& value = get(PropertyId::MarkerWidth);
return Parser::parseLength(value, ForbidNegativeLengths, Length::ThreePercent);
}
Length MarkerElement::markerHeight() const
{
auto& value = get(PropertyID::MarkerHeight);
auto& value = get(PropertyId::MarkerHeight);
return Parser::parseLength(value, ForbidNegativeLengths, Length::ThreePercent);
}
Angle MarkerElement::orient() const
{
auto& value = get(PropertyID::Orient);
auto& value = get(PropertyId::Orient);
return Parser::parseAngle(value);
}
MarkerUnits MarkerElement::markerUnits() const
{
auto& value = get(PropertyID::MarkerUnits);
auto& value = get(PropertyId::MarkerUnits);
return Parser::parseMarkerUnits(value);
}
Rect MarkerElement::viewBox() const
{
auto& value = get(PropertyID::ViewBox);
auto& value = get(PropertyId::ViewBox);
return Parser::parseViewBox(value);
}
PreserveAspectRatio MarkerElement::preserveAspectRatio() const
{
auto& value = get(PropertyID::PreserveAspectRatio);
auto& value = get(PropertyId::PreserveAspectRatio);
return Parser::parsePreserveAspectRatio(value);
}

View file

@ -5,43 +5,43 @@
namespace lunasvg {
MaskElement::MaskElement()
: StyledElement(ElementID::Mask)
: StyledElement(ElementId::Mask)
{
}
Length MaskElement::x() const
{
auto& value = get(PropertyID::X);
auto& value = get(PropertyId::X);
return Parser::parseLength(value, AllowNegativeLengths, Length::MinusTenPercent);
}
Length MaskElement::y() const
{
auto& value = get(PropertyID::Y);
auto& value = get(PropertyId::Y);
return Parser::parseLength(value, AllowNegativeLengths, Length::MinusTenPercent);
}
Length MaskElement::width() const
{
auto& value = get(PropertyID::Width);
auto& value = get(PropertyId::Width);
return Parser::parseLength(value, ForbidNegativeLengths, Length::OneTwentyPercent);
}
Length MaskElement::height() const
{
auto& value = get(PropertyID::Height);
auto& value = get(PropertyId::Height);
return Parser::parseLength(value, ForbidNegativeLengths, Length::OneTwentyPercent);
}
Units MaskElement::maskUnits() const
{
auto& value = get(PropertyID::MaskUnits);
auto& value = get(PropertyId::MaskUnits);
return Parser::parseUnits(value, Units::ObjectBoundingBox);
}
Units MaskElement::maskContentUnits() const
{
auto& value = get(PropertyID::MaskContentUnits);
auto& value = get(PropertyId::MaskContentUnits);
return Parser::parseUnits(value, Units::UserSpaceOnUse);
}

View file

@ -7,37 +7,37 @@
namespace lunasvg {
PaintElement::PaintElement(ElementID id)
PaintElement::PaintElement(ElementId id)
: StyledElement(id)
{
}
GradientElement::GradientElement(ElementID id)
GradientElement::GradientElement(ElementId id)
: PaintElement(id)
{
}
Transform GradientElement::gradientTransform() const
{
auto& value = get(PropertyID::GradientTransform);
auto& value = get(PropertyId::GradientTransform);
return Parser::parseTransform(value);
}
SpreadMethod GradientElement::spreadMethod() const
{
auto& value = get(PropertyID::SpreadMethod);
auto& value = get(PropertyId::SpreadMethod);
return Parser::parseSpreadMethod(value);
}
Units GradientElement::gradientUnits() const
{
auto& value = get(PropertyID::GradientUnits);
auto& value = get(PropertyId::GradientUnits);
return Parser::parseUnits(value, Units::ObjectBoundingBox);
}
std::string GradientElement::href() const
{
auto& value = get(PropertyID::Href);
auto& value = get(PropertyId::Href);
return Parser::parseHref(value);
}
@ -50,7 +50,7 @@ GradientStops GradientElement::buildGradientStops() const
if(child->isText())
continue;
auto element = static_cast<Element*>(child.get());
if(element->id != ElementID::Stop)
if(element->id != ElementId::Stop)
continue;
auto stop = static_cast<StopElement*>(element);
auto offset = std::max(prevOffset, stop->offset());
@ -62,31 +62,31 @@ GradientStops GradientElement::buildGradientStops() const
}
LinearGradientElement::LinearGradientElement()
: GradientElement(ElementID::LinearGradient)
: GradientElement(ElementId::LinearGradient)
{
}
Length LinearGradientElement::x1() const
{
auto& value = get(PropertyID::X1);
auto& value = get(PropertyId::X1);
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
}
Length LinearGradientElement::y1() const
{
auto& value = get(PropertyID::Y1);
auto& value = get(PropertyId::Y1);
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
}
Length LinearGradientElement::x2() const
{
auto& value = get(PropertyID::X2);
auto& value = get(PropertyId::X2);
return Parser::parseLength(value, AllowNegativeLengths, Length::HundredPercent);
}
Length LinearGradientElement::y2() const
{
auto& value = get(PropertyID::Y2);
auto& value = get(PropertyId::Y2);
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
}
@ -98,30 +98,30 @@ std::unique_ptr<LayoutObject> LinearGradientElement::getPainter(LayoutContext* c
while(true)
{
if(!attributes.hasGradientTransform() && current->has(PropertyID::GradientTransform))
if(!attributes.hasGradientTransform() && current->has(PropertyId::GradientTransform))
attributes.setGradientTransform(current->gradientTransform());
if(!attributes.hasSpreadMethod() && current->has(PropertyID::SpreadMethod))
if(!attributes.hasSpreadMethod() && current->has(PropertyId::SpreadMethod))
attributes.setSpreadMethod(current->spreadMethod());
if(!attributes.hasGradientUnits() && current->has(PropertyID::GradientUnits))
if(!attributes.hasGradientUnits() && current->has(PropertyId::GradientUnits))
attributes.setGradientUnits(current->gradientUnits());
if(!attributes.hasGradientStops())
attributes.setGradientStops(current->buildGradientStops());
if(current->id == ElementID::LinearGradient)
if(current->id == ElementId::LinearGradient)
{
auto element = static_cast<const LinearGradientElement*>(current);
if(!attributes.hasX1() && element->has(PropertyID::X1))
if(!attributes.hasX1() && element->has(PropertyId::X1))
attributes.setX1(element->x1());
if(!attributes.hasY1() && element->has(PropertyID::Y1))
if(!attributes.hasY1() && element->has(PropertyId::Y1))
attributes.setY1(element->y1());
if(!attributes.hasX2() && element->has(PropertyID::X2))
if(!attributes.hasX2() && element->has(PropertyId::X2))
attributes.setX2(element->x2());
if(!attributes.hasY2() && element->has(PropertyID::Y2))
if(!attributes.hasY2() && element->has(PropertyId::Y2))
attributes.setY2(element->y2());
}
auto ref = context->getElementById(current->href());
if(!ref || !(ref->id == ElementID::LinearGradient || ref->id == ElementID::RadialGradient))
if(!ref || !(ref->id == ElementId::LinearGradient || ref->id == ElementId::RadialGradient))
break;
processedGradients.insert(current);
@ -164,37 +164,37 @@ std::unique_ptr<Node> LinearGradientElement::clone() const
}
RadialGradientElement::RadialGradientElement()
: GradientElement(ElementID::RadialGradient)
: GradientElement(ElementId::RadialGradient)
{
}
Length RadialGradientElement::cx() const
{
auto& value = get(PropertyID::Cx);
auto& value = get(PropertyId::Cx);
return Parser::parseLength(value, AllowNegativeLengths, Length::FiftyPercent);
}
Length RadialGradientElement::cy() const
{
auto& value = get(PropertyID::Cy);
auto& value = get(PropertyId::Cy);
return Parser::parseLength(value, AllowNegativeLengths, Length::FiftyPercent);
}
Length RadialGradientElement::r() const
{
auto& value = get(PropertyID::R);
auto& value = get(PropertyId::R);
return Parser::parseLength(value, ForbidNegativeLengths, Length::FiftyPercent);
}
Length RadialGradientElement::fx() const
{
auto& value = get(PropertyID::Fx);
auto& value = get(PropertyId::Fx);
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
}
Length RadialGradientElement::fy() const
{
auto& value = get(PropertyID::Fy);
auto& value = get(PropertyId::Fy);
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
}
@ -206,32 +206,32 @@ std::unique_ptr<LayoutObject> RadialGradientElement::getPainter(LayoutContext* c
while(true)
{
if(!attributes.hasGradientTransform() && current->has(PropertyID::GradientTransform))
if(!attributes.hasGradientTransform() && current->has(PropertyId::GradientTransform))
attributes.setGradientTransform(current->gradientTransform());
if(!attributes.hasSpreadMethod() && current->has(PropertyID::SpreadMethod))
if(!attributes.hasSpreadMethod() && current->has(PropertyId::SpreadMethod))
attributes.setSpreadMethod(current->spreadMethod());
if(!attributes.hasGradientUnits() && current->has(PropertyID::GradientUnits))
if(!attributes.hasGradientUnits() && current->has(PropertyId::GradientUnits))
attributes.setGradientUnits(current->gradientUnits());
if(!attributes.hasGradientStops())
attributes.setGradientStops(current->buildGradientStops());
if(current->id == ElementID::RadialGradient)
if(current->id == ElementId::RadialGradient)
{
auto element = static_cast<const RadialGradientElement*>(current);
if(!attributes.hasCx() && element->has(PropertyID::Cx))
if(!attributes.hasCx() && element->has(PropertyId::Cx))
attributes.setCx(element->cx());
if(!attributes.hasCy() && element->has(PropertyID::Cy))
if(!attributes.hasCy() && element->has(PropertyId::Cy))
attributes.setCy(element->cy());
if(!attributes.hasR() && element->has(PropertyID::R))
if(!attributes.hasR() && element->has(PropertyId::R))
attributes.setR(element->r());
if(!attributes.hasFx() && element->has(PropertyID::Fx))
if(!attributes.hasFx() && element->has(PropertyId::Fx))
attributes.setFx(element->fx());
if(!attributes.hasFy() && element->has(PropertyID::Fy))
if(!attributes.hasFy() && element->has(PropertyId::Fy))
attributes.setFy(element->fy());
}
auto ref = context->getElementById(current->href());
if(!ref || !(ref->id == ElementID::LinearGradient || ref->id == ElementID::RadialGradient))
if(!ref || !(ref->id == ElementId::LinearGradient || ref->id == ElementId::RadialGradient))
break;
processedGradients.insert(current);
@ -278,67 +278,67 @@ std::unique_ptr<Node> RadialGradientElement::clone() const
}
PatternElement::PatternElement()
: PaintElement(ElementID::Pattern)
: PaintElement(ElementId::Pattern)
{
}
Length PatternElement::x() const
{
auto& value = get(PropertyID::X);
auto& value = get(PropertyId::X);
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
}
Length PatternElement::y() const
{
auto& value = get(PropertyID::Y);
auto& value = get(PropertyId::Y);
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
}
Length PatternElement::width() const
{
auto& value = get(PropertyID::Width);
auto& value = get(PropertyId::Width);
return Parser::parseLength(value, ForbidNegativeLengths, Length::Zero);
}
Length PatternElement::height() const
{
auto& value = get(PropertyID::Height);
auto& value = get(PropertyId::Height);
return Parser::parseLength(value, ForbidNegativeLengths, Length::Zero);
}
Transform PatternElement::patternTransform() const
{
auto& value = get(PropertyID::PatternTransform);
auto& value = get(PropertyId::PatternTransform);
return Parser::parseTransform(value);
}
Units PatternElement::patternUnits() const
{
auto& value = get(PropertyID::PatternUnits);
auto& value = get(PropertyId::PatternUnits);
return Parser::parseUnits(value, Units::ObjectBoundingBox);
}
Units PatternElement::patternContentUnits() const
{
auto& value = get(PropertyID::PatternContentUnits);
auto& value = get(PropertyId::PatternContentUnits);
return Parser::parseUnits(value, Units::UserSpaceOnUse);
}
Rect PatternElement::viewBox() const
{
auto& value = get(PropertyID::ViewBox);
auto& value = get(PropertyId::ViewBox);
return Parser::parseViewBox(value);
}
PreserveAspectRatio PatternElement::preserveAspectRatio() const
{
auto& value = get(PropertyID::PreserveAspectRatio);
auto& value = get(PropertyId::PreserveAspectRatio);
return Parser::parsePreserveAspectRatio(value);
}
std::string PatternElement::href() const
{
auto& value = get(PropertyID::Href);
auto& value = get(PropertyId::Href);
return Parser::parseHref(value);
}
@ -353,29 +353,29 @@ std::unique_ptr<LayoutObject> PatternElement::getPainter(LayoutContext* context)
while(true)
{
if(!attributes.hasX() && current->has(PropertyID::X))
if(!attributes.hasX() && current->has(PropertyId::X))
attributes.setX(current->x());
if(!attributes.hasY() && current->has(PropertyID::Y))
if(!attributes.hasY() && current->has(PropertyId::Y))
attributes.setY(current->y());
if(!attributes.hasWidth() && current->has(PropertyID::Width))
if(!attributes.hasWidth() && current->has(PropertyId::Width))
attributes.setWidth(current->width());
if(!attributes.hasHeight() && current->has(PropertyID::Height))
if(!attributes.hasHeight() && current->has(PropertyId::Height))
attributes.setHeight(current->height());
if(!attributes.hasPatternTransform() && current->has(PropertyID::PatternTransform))
if(!attributes.hasPatternTransform() && current->has(PropertyId::PatternTransform))
attributes.setPatternTransform(current->patternTransform());
if(!attributes.hasPatternUnits() && current->has(PropertyID::PatternUnits))
if(!attributes.hasPatternUnits() && current->has(PropertyId::PatternUnits))
attributes.setPatternUnits(current->patternUnits());
if(!attributes.hasPatternContentUnits() && current->has(PropertyID::PatternContentUnits))
if(!attributes.hasPatternContentUnits() && current->has(PropertyId::PatternContentUnits))
attributes.setPatternContentUnits(current->patternContentUnits());
if(!attributes.hasViewBox() && current->has(PropertyID::ViewBox))
if(!attributes.hasViewBox() && current->has(PropertyId::ViewBox))
attributes.setViewBox(current->viewBox());
if(!attributes.hasPreserveAspectRatio() && current->has(PropertyID::PreserveAspectRatio))
if(!attributes.hasPreserveAspectRatio() && current->has(PropertyId::PreserveAspectRatio))
attributes.setPreserveAspectRatio(current->preserveAspectRatio());
if(!attributes.hasPatternContentElement() && current->children.size())
attributes.setPatternContentElement(current);
auto ref = context->getElementById(current->href());
if(!ref || ref->id != ElementID::Pattern)
if(!ref || ref->id != ElementId::Pattern)
break;
processedPatterns.insert(current);
@ -413,7 +413,7 @@ std::unique_ptr<Node> PatternElement::clone() const
}
SolidColorElement::SolidColorElement()
: PaintElement(ElementID::SolidColor)
: PaintElement(ElementId::SolidColor)
{
}

View file

@ -11,7 +11,7 @@ class LayoutObject;
class PaintElement : public StyledElement
{
public:
PaintElement(ElementID id);
PaintElement(ElementId id);
bool isPaint() const { return true; }
virtual std::unique_ptr<LayoutObject> getPainter(LayoutContext* context) const = 0;
@ -20,7 +20,7 @@ public:
class GradientElement : public PaintElement
{
public:
GradientElement(ElementID id);
GradientElement(ElementId id);
Transform gradientTransform() const;
SpreadMethod spreadMethod() const;

File diff suppressed because it is too large Load diff

View file

@ -2,7 +2,6 @@
#define PARSER_H
#include <map>
#include <set>
#include "property.h"
#include "element.h"
@ -64,10 +63,7 @@ private:
static bool parseTransform(const char*& ptr, const char* end, TransformType& type, double* values, int& count);
};
struct SimpleSelector;
using Selector = std::vector<SimpleSelector>;
using SelectorList = std::vector<Selector>;
struct Selector;
struct AttributeSelector
{
@ -82,19 +78,20 @@ struct AttributeSelector
Contains
};
MatchType matchType{MatchType::None};
PropertyID id{PropertyID::Unknown};
PropertyId id{PropertyId::Unknown};
std::string value;
MatchType matchType{MatchType::None};
};
struct PseudoClassSelector
using SelectorList = std::vector<Selector>;
struct PseudoClass
{
enum class Type
{
Unknown,
Empty,
Root,
Is,
Not,
FirstChild,
LastChild,
@ -105,9 +102,7 @@ struct PseudoClassSelector
};
Type type{Type::Unknown};
int16_t a{0};
int16_t b{0};
SelectorList subSelectors;
SelectorList notSelectors;
};
struct SimpleSelector
@ -120,10 +115,16 @@ struct SimpleSelector
InDirectAdjacent
};
Combinator combinator{Combinator::Descendant};
ElementID id{ElementID::Star};
ElementId id{ElementId::Star};
std::vector<AttributeSelector> attributeSelectors;
std::vector<PseudoClassSelector> pseudoClassSelectors;
std::vector<PseudoClass> pseudoClasses;
Combinator combinator{Combinator::Descendant};
};
struct Selector
{
std::vector<SimpleSelector> simpleSelectors;
int specificity{0};
};
struct Rule
@ -132,47 +133,21 @@ struct Rule
PropertyList declarations;
};
class RuleData {
class RuleMatchContext
{
public:
RuleData(const Selector& selector, const PropertyList& properties, uint32_t specificity, uint32_t position)
: m_selector(selector), m_properties(properties), m_specificity(specificity), m_position(position)
{}
const Selector& selector() const { return m_selector; }
const PropertyList& properties() const { return m_properties; }
const uint32_t& specificity() const { return m_specificity; }
const uint32_t& position() const { return m_position; }
bool match(const Element* element) const;
private:
bool matchSimpleSelector(const SimpleSelector& selector, const Element* element) const;
bool matchAttributeSelector(const AttributeSelector& selector, const Element* element) const;
bool matchPseudoClassSelector(const PseudoClassSelector& selector, const Element* element) const;
private:
Selector m_selector;
PropertyList m_properties;
uint32_t m_specificity;
uint32_t m_position;
};
inline bool operator<(const RuleData& a, const RuleData& b) { return std::tie(a.specificity(), a.position()) < std::tie(b.specificity(), b.position()); }
inline bool operator>(const RuleData& a, const RuleData& b) { return std::tie(a.specificity(), a.position()) > std::tie(b.specificity(), b.position()); }
class StyleSheet {
public:
StyleSheet() = default;
void parse(const std::string& content);
void add(const Rule& rule);
bool empty() const { return m_position == 0; }
RuleMatchContext(const std::vector<Rule>& rules);
std::vector<const PropertyList*> match(const Element* element) const;
private:
std::multiset<RuleData> m_rules;
uint32_t m_position{0};
bool selectorMatch(const Selector* selector, const Element* element) const;
bool simpleSelectorMatch(const SimpleSelector& selector, const Element* element) const;
bool attributeSelectorMatch(const AttributeSelector& selector, const Element* element) const;
bool pseudoClassMatch(const PseudoClass& pseudo, const Element* element) const;
private:
std::multimap<int, std::pair<const Selector*, const PropertyList*>, std::less<int>> m_selectors;
};
class CSSParser
@ -180,29 +155,35 @@ class CSSParser
public:
CSSParser() = default;
static bool parseSheet(StyleSheet* sheet, const std::string& value);
bool parseMore(const std::string& value);
const std::vector<Rule>& rules() const { return m_rules; }
private:
static bool parseAtRule(const char*& ptr, const char* end);
static bool parseRule(const char*& ptr, const char* end, Rule& rule);
static bool parseSelectors(const char*& ptr, const char* end, SelectorList& selectors);
static bool parseDeclarations(const char*& ptr, const char* end, PropertyList& declarations);
static bool parseSelector(const char*& ptr, const char* end, Selector& selector);
static bool parseSimpleSelector(const char*& ptr, const char* end, SimpleSelector& simpleSelector);
bool parseAtRule(const char*& ptr, const char* end) const;
bool parseRule(const char*& ptr, const char* end, Rule& rule) const;
bool parseSelectors(const char*& ptr, const char* end, SelectorList& selectors) const;
bool parseDeclarations(const char*& ptr, const char* end, PropertyList& declarations) const;
bool parseSelector(const char*& ptr, const char* end, Selector& selector) const;
bool parseSimpleSelector(const char*& ptr, const char* end, SimpleSelector& simpleSelector) const;
private:
std::vector<Rule> m_rules;
};
class LayoutSymbol;
class TreeBuilder {
class ParseDocument
{
public:
TreeBuilder();
~TreeBuilder();
ParseDocument();
~ParseDocument();
bool parse(const char* data, std::size_t size);
SVGElement* rootElement() const { return m_rootElement.get(); }
Element* getElementById(const std::string& id) const;
std::unique_ptr<LayoutSymbol> build() const;
std::unique_ptr<LayoutSymbol> layout() const;
private:
std::unique_ptr<SVGElement> m_rootElement;

View file

@ -6,8 +6,6 @@
#include <limits>
#include <string>
#include <algorithm>
#include <string_view>
#include <cassert>
namespace lunasvg {
@ -264,241 +262,6 @@ inline bool parseNumber(const char*& ptr, const char* end, T& number)
} // namespace Utils
class ParserString {
public:
explicit ParserString(const std::string_view& value)
: ParserString(value.data(), value.length())
{}
ParserString(const char* begin, size_t length)
: ParserString(begin, begin + length)
{}
ParserString(const char* begin, const char* end)
: ParserString(begin, begin, end)
{}
ParserString(const char* current, const char* begin, const char* end)
: m_current(current), m_begin(begin), m_end(end)
{}
ParserString operator+(size_t count) const {
auto current = m_current + count;
assert(m_end >= current);
return ParserString(current, m_begin, m_end);
}
ParserString operator-(size_t count) const {
auto current = m_current - count;
assert(current >= m_begin);
return ParserString(current, m_begin, m_end);
}
ParserString& operator+=(size_t count) {
*this = *this + count;
return *this;
}
ParserString& operator-=(size_t count) {
*this = *this - count;
return *this;
}
const char& operator*() const {
assert(m_current < m_end);
return *m_current;
}
char peek(size_t count = 0) const {
auto current = m_current + count;
assert(m_end >= current);
if(current == m_end)
return 0;
return *current;
}
char advance(size_t count = 1) {
m_current += count;
assert(m_end >= m_current);
if(m_current == m_end)
return 0;
return *m_current;
}
char get() const {
assert(m_end >= m_current);
if(m_current == m_end)
return 0;
return *m_current;
}
std::string_view string(size_t offset, size_t count) const { return string().substr(offset, count); }
std::string_view substring(size_t offset, size_t count) const { return substring().substr(offset, count); }
std::string_view string() const { return std::string_view(m_begin, length()); }
std::string_view substring() const { return std::string_view(m_current, sublength()); }
size_t offset() const { return m_current - m_begin; }
size_t length() const { return m_end - m_begin; }
size_t sublength() const { return m_end - m_current; }
const char* current() const { return m_current; }
const char* begin() const { return m_begin; }
const char* end() const { return m_end; }
bool empty() const { return m_current == m_end; }
private:
const char* m_current;
const char* m_begin;
const char* m_end;
};
constexpr bool isspace(int cc) { return (cc == ' ' || cc == '\n' || cc == '\t' || cc == '\r' || cc == '\f'); }
constexpr bool isdigit(int cc) { return (cc >= '0' && cc <= '9'); }
constexpr bool isupper(int cc) { return (cc >= 'A' && cc <= 'Z'); }
constexpr bool islower(int cc) { return (cc >= 'a' && cc <= 'z'); }
constexpr bool isalpha(int cc) { return isupper(cc) || islower(cc); }
constexpr bool isxupper(int cc) { return (cc >= 'A' && cc <= 'F'); }
constexpr bool isxlower(int cc) { return (cc >= 'a' && cc <= 'f'); }
constexpr bool isxdigit(int cc) { return isdigit(cc) || isxupper(cc) || isxlower(cc); }
constexpr int xdigit(int cc) {
if(isdigit(cc))
return cc - '0';
if(isxupper(cc))
return 10 + cc - 'A';
if(isxlower(cc))
return 10 + cc - 'a';
return 0;
}
constexpr char tolower(int cc) {
if(isupper(cc))
return cc + 0x20;
return cc;
}
constexpr bool equals(int a, int b, bool caseSensitive) {
if(caseSensitive)
return a == b;
return tolower(a) == tolower(b);
}
constexpr bool equals(const char* aData, size_t aLength, const char* bData, size_t bLength, bool caseSensitive) {
if(aLength != bLength)
return false;
auto aEnd = aData + aLength;
while(aData != aEnd) {
if(!equals(*aData, *bData, caseSensitive))
return false;
++aData;
++bData;
}
return true;
}
constexpr bool equals(const std::string_view& a, const std::string_view& b, bool caseSensitive) {
return equals(a.data(), a.length(), b.data(), b.length(), caseSensitive);
}
constexpr bool contains(const std::string_view& value, const std::string_view& subvalue, bool caseSensitive) {
if(subvalue.empty() || subvalue.length() > value.length())
return false;
auto it = value.data();
auto end = it + value.length();
while(it < end) {
size_t count = 0;
do {
if(!equals(*it, subvalue[count], caseSensitive))
break;
++count;
++it;
} while(it < end && count < subvalue.length());
if(count == subvalue.length())
return true;
++it;
}
return false;
}
constexpr bool includes(const std::string_view& value, const std::string_view& subvalue, bool caseSensitive) {
if(subvalue.empty() || subvalue.length() > value.length())
return false;
auto it = value.data();
auto end = it + value.length();
while(true) {
while(it < end && isspace(*it))
++it;
if(it >= end)
return false;
size_t count = 0;
auto begin = it;
do {
++count;
++it;
} while(it < end && !isspace(*it));
if(equals(begin, count, subvalue.data(), subvalue.length(), caseSensitive))
return true;
++it;
}
return false;
}
constexpr bool startswith(const std::string_view& value, const std::string_view& subvalue, bool caseSensitive) {
if(subvalue.empty() || subvalue.length() > value.length())
return false;
return equals(value.substr(0, subvalue.size()), subvalue, caseSensitive);
}
constexpr bool endswith(const std::string_view& value, const std::string_view& subvalue, bool caseSensitive) {
if(subvalue.empty() || subvalue.length() > value.length())
return false;
return equals(value.substr(value.size() - subvalue.size(), subvalue.size()), subvalue, caseSensitive);
}
constexpr bool dashequals(const std::string_view& value, const std::string_view& subvalue, bool caseSensitive) {
if(!startswith(value, subvalue, caseSensitive))
return false;
return (value.length() == subvalue.length() || value.at(subvalue.length()) == '-');
}
inline void appendCodepoint(std::string& output, uint32_t cp) {
char c[5] = {0, 0, 0, 0, 0};
if(cp < 0x80) {
c[1] = 0;
c[0] = cp;
} else if(cp < 0x800) {
c[2] = 0;
c[1] = (cp & 0x3F) | 0x80;
cp >>= 6;
c[0] = cp | 0xC0;
} else if(cp < 0x10000) {
c[3] = 0;
c[2] = (cp & 0x3F) | 0x80;
cp >>= 6;
c[1] = (cp & 0x3F) | 0x80;
cp >>= 6;
c[0] = cp | 0xE0;
} else if(cp < 0x110000) {
c[4] = 0;
c[3] = (cp & 0x3F) | 0x80;
cp >>= 6;
c[2] = (cp & 0x3F) | 0x80;
cp >>= 6;
c[1] = (cp & 0x3F) | 0x80;
cp >>= 6;
c[0] = cp | 0xF0;
}
output.append(c);
}
} // namespace lunasvg
#endif // PARSERUTILS_H

View file

@ -1,254 +0,0 @@
#ifndef POINTER_H
#define POINTER_H
#include <algorithm>
#include <cstdint>
namespace lunasvg {
template<typename T>
class RefCounted {
public:
RefCounted() = default;
void ref() { ++m_refCount; }
void deref() {
if(--m_refCount == 0) {
delete static_cast<T*>(this);
}
}
uint32_t refCount() const { return m_refCount; }
bool hasOneRefCount() const { return m_refCount == 1; }
private:
uint32_t m_refCount{1};
};
template<typename T>
inline void refIfNotNull(T* ptr)
{
if(ptr)
ptr->ref();
}
template<typename T>
inline void derefIfNotNull(T* ptr)
{
if(ptr)
ptr->deref();
}
template<typename T> class RefPtr;
template<typename T> RefPtr<T> adoptPtr(T*);
template<typename T>
class RefPtr {
public:
RefPtr() = default;
RefPtr(std::nullptr_t) : m_ptr(nullptr) {}
RefPtr(T* ptr) : m_ptr(ptr) { refIfNotNull(m_ptr); }
RefPtr(T& ref) : m_ptr(&ref) { m_ptr->ref(); }
RefPtr(const RefPtr<T>& p) : m_ptr(p.get()) { refIfNotNull(m_ptr); }
RefPtr(RefPtr<T>&& p) : m_ptr(p.release()) {}
template<typename U>
RefPtr(const RefPtr<U>& p) : m_ptr(p.get()) { refIfNotNull(m_ptr); }
template<typename U>
RefPtr(RefPtr<U>&& p) : m_ptr(p.release()) {}
~RefPtr() { derefIfNotNull(m_ptr); }
T* get() const { return m_ptr; }
T& operator*() const { return *m_ptr; }
T* operator->() const { return m_ptr; }
bool empty() const { return !m_ptr; }
bool operator!() const { return !m_ptr; }
operator bool() const { return !!m_ptr; }
RefPtr<T>& operator=(std::nullptr_t)
{
clear();
return *this;
}
RefPtr<T>& operator=(T* o)
{
RefPtr<T> p = o;
swap(p);
return *this;
}
RefPtr<T>& operator=(T& o)
{
RefPtr<T> p = o;
swap(p);
return *this;
}
RefPtr<T>& operator=(const RefPtr<T>& o)
{
RefPtr<T> p = o;
swap(p);
return *this;
}
RefPtr<T>& operator=(RefPtr<T>&& o)
{
RefPtr<T> p = std::move(o);
swap(p);
return *this;
}
template<typename U>
RefPtr<T>& operator=(const RefPtr<U>& o)
{
RefPtr<T> p = o;
swap(p);
return *this;
}
template<typename U>
RefPtr<T>& operator=(RefPtr<U>&& o)
{
RefPtr<T> p = std::move(o);
swap(p);
return *this;
}
void swap(RefPtr<T>& o)
{
std::swap(m_ptr, o.m_ptr);
}
T* release()
{
T* ptr = m_ptr;
m_ptr = nullptr;
return ptr;
}
void clear()
{
derefIfNotNull(m_ptr);
m_ptr = nullptr;
}
friend RefPtr<T> adoptPtr<T>(T*);
private:
RefPtr(T* ptr, std::nullptr_t) : m_ptr(ptr) {}
T* m_ptr{nullptr};
};
template<typename T>
inline RefPtr<T> adoptPtr(T* ptr)
{
return RefPtr<T>(ptr, nullptr);
}
template<class T>
inline void swap(RefPtr<T>& a, RefPtr<T>& b)
{
a.swap(b);
}
template<typename T, typename U>
inline bool operator==(const RefPtr<T>& a, const RefPtr<U>& b)
{
return a.get() == b.get();
}
template<typename T, typename U>
inline bool operator==(const RefPtr<T>& a, const U* b)
{
return a.get() == b;
}
template<typename T, typename U>
inline bool operator==(const T* a, const RefPtr<U>& b)
{
return a == b.get();
}
template<typename T>
inline bool operator==(const RefPtr<T>& a, std::nullptr_t)
{
return a.get() == nullptr;
}
template<typename T, typename U>
inline bool operator!=(const RefPtr<T>& a, const RefPtr<U>& b)
{
return a.get() != b.get();
}
template<typename T, typename U>
inline bool operator!=(const RefPtr<T>& a, const U* b)
{
return a.get() != b;
}
template<typename T, typename U>
inline bool operator!=(const T* a, const RefPtr<U>& b)
{
return a != b.get();
}
template<typename T>
inline bool operator!=(const RefPtr<T>& a, std::nullptr_t)
{
return a.get() != nullptr;
}
template<typename T>
struct is {
template<typename U>
static bool check(const U& value);
};
template<typename T, typename U>
constexpr bool is_a(U& value) {
return is<T>::check(value);
}
template<typename T, typename U>
constexpr bool is_a(const U& value) {
return is<T>::check(value);
}
template<typename T, typename U>
constexpr bool is_a(U* value) {
return value && is<T>::check(*value);
}
template<typename T, typename U>
constexpr bool is_a(const U* value) {
return value && is<T>::check(*value);
}
template<typename T, typename U>
constexpr T* to(U& value) {
return is_a<T>(value) ? static_cast<T*>(&value) : nullptr;
}
template<typename T, typename U>
constexpr const T* to(const U& value) {
return is_a<T>(value) ? static_cast<const T*>(&value) : nullptr;
}
template<typename T, typename U>
constexpr T* to(U* value) {
return is_a<T>(value) ? static_cast<T*>(value) : nullptr;
}
template<typename T, typename U>
constexpr const T* to(const U* value) {
return is_a<T>(value) ? static_cast<const T*>(value) : nullptr;
}
} // namespace lunasvg
#endif // POINTER_H

View file

@ -4,13 +4,13 @@
namespace lunasvg {
StopElement::StopElement()
: StyledElement(ElementID::Stop)
: StyledElement(ElementId::Stop)
{
}
double StopElement::offset() const
{
auto& value = get(PropertyID::Offset);
auto& value = get(PropertyId::Offset);
return Parser::parseNumberPercentage(value, 0.0);
}

View file

@ -3,164 +3,164 @@
namespace lunasvg {
StyledElement::StyledElement(ElementID id)
StyledElement::StyledElement(ElementId id)
: Element(id)
{
}
Paint StyledElement::fill() const
{
auto& value = find(PropertyID::Fill);
auto& value = find(PropertyId::Fill);
return Parser::parsePaint(value, this, Color::Black);
}
Paint StyledElement::stroke() const
{
auto& value = find(PropertyID::Stroke);
auto& value = find(PropertyId::Stroke);
return Parser::parsePaint(value, this, Color::Transparent);
}
Color StyledElement::color() const
{
auto& value = find(PropertyID::Color);
auto& value = find(PropertyId::Color);
return Parser::parseColor(value, this, Color::Black);
}
Color StyledElement::stop_color() const
{
auto& value = find(PropertyID::Stop_Color);
auto& value = find(PropertyId::Stop_Color);
return Parser::parseColor(value, this, Color::Black);
}
Color StyledElement::solid_color() const
{
auto& value = find(PropertyID::Solid_Color);
auto& value = find(PropertyId::Solid_Color);
return Parser::parseColor(value, this, Color::Black);
}
double StyledElement::opacity() const
{
auto& value = get(PropertyID::Opacity);
auto& value = get(PropertyId::Opacity);
return Parser::parseNumberPercentage(value, 1.0);
}
double StyledElement::fill_opacity() const
{
auto& value = find(PropertyID::Fill_Opacity);
auto& value = find(PropertyId::Fill_Opacity);
return Parser::parseNumberPercentage(value, 1.0);
}
double StyledElement::stroke_opacity() const
{
auto& value = find(PropertyID::Stroke_Opacity);
auto& value = find(PropertyId::Stroke_Opacity);
return Parser::parseNumberPercentage(value, 1.0);
}
double StyledElement::stop_opacity() const
{
auto& value = find(PropertyID::Stop_Opacity);
auto& value = find(PropertyId::Stop_Opacity);
return Parser::parseNumberPercentage(value, 1.0);
}
double StyledElement::solid_opacity() const
{
auto& value = find(PropertyID::Solid_Opacity);
auto& value = find(PropertyId::Solid_Opacity);
return Parser::parseNumberPercentage(value, 1.0);
}
double StyledElement::stroke_miterlimit() const
{
auto& value = find(PropertyID::Stroke_Miterlimit);
auto& value = find(PropertyId::Stroke_Miterlimit);
return Parser::parseNumber(value, 4.0);
}
Length StyledElement::stroke_width() const
{
auto& value = find(PropertyID::Stroke_Width);
auto& value = find(PropertyId::Stroke_Width);
return Parser::parseLength(value, ForbidNegativeLengths, Length::One);
}
Length StyledElement::stroke_dashoffset() const
{
auto& value = find(PropertyID::Stroke_Dashoffset);
auto& value = find(PropertyId::Stroke_Dashoffset);
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
}
LengthList StyledElement::stroke_dasharray() const
{
auto& value = find(PropertyID::Stroke_Dasharray);
auto& value = find(PropertyId::Stroke_Dasharray);
return Parser::parseLengthList(value, ForbidNegativeLengths);
}
WindRule StyledElement::fill_rule() const
{
auto& value = find(PropertyID::Fill_Rule);
auto& value = find(PropertyId::Fill_Rule);
return Parser::parseWindRule(value);
}
WindRule StyledElement::clip_rule() const
{
auto& value = find(PropertyID::Clip_Rule);
auto& value = find(PropertyId::Clip_Rule);
return Parser::parseWindRule(value);
}
LineCap StyledElement::stroke_linecap() const
{
auto& value = find(PropertyID::Stroke_Linecap);
auto& value = find(PropertyId::Stroke_Linecap);
return Parser::parseLineCap(value);
}
LineJoin StyledElement::stroke_linejoin() const
{
auto& value = find(PropertyID::Stroke_Linejoin);
auto& value = find(PropertyId::Stroke_Linejoin);
return Parser::parseLineJoin(value);
}
Display StyledElement::display() const
{
auto& value = get(PropertyID::Display);
auto& value = get(PropertyId::Display);
return Parser::parseDisplay(value);
}
Visibility StyledElement::visibility() const
{
auto& value = find(PropertyID::Visibility);
auto& value = find(PropertyId::Visibility);
return Parser::parseVisibility(value);
}
Overflow StyledElement::overflow() const
{
auto& value = get(PropertyID::Overflow);
auto& value = get(PropertyId::Overflow);
return Parser::parseOverflow(value, parent == nullptr ? Overflow::Visible : Overflow::Hidden);
}
std::string StyledElement::clip_path() const
{
auto& value = get(PropertyID::Clip_Path);
auto& value = get(PropertyId::Clip_Path);
return Parser::parseUrl(value);
}
std::string StyledElement::mask() const
{
auto& value = get(PropertyID::Mask);
auto& value = get(PropertyId::Mask);
return Parser::parseUrl(value);
}
std::string StyledElement::marker_start() const
{
auto& value = find(PropertyID::Marker_Start);
auto& value = find(PropertyId::Marker_Start);
return Parser::parseUrl(value);
}
std::string StyledElement::marker_mid() const
{
auto& value = find(PropertyID::Marker_Mid);
auto& value = find(PropertyId::Marker_Mid);
return Parser::parseUrl(value);
}
std::string StyledElement::marker_end() const
{
auto& value = find(PropertyID::Marker_End);
auto& value = find(PropertyId::Marker_End);
return Parser::parseUrl(value);
}

View file

@ -8,7 +8,7 @@ namespace lunasvg {
class StyledElement : public Element
{
public:
StyledElement(ElementID id);
StyledElement(ElementId id);
Paint fill() const;
Paint stroke() const;

View file

@ -3,7 +3,7 @@
namespace lunasvg {
StyleElement::StyleElement()
: Element(ElementID::Style)
: Element(ElementId::Style)
{
}

View file

@ -5,47 +5,47 @@
namespace lunasvg {
SVGElement::SVGElement()
: GraphicsElement(ElementID::Svg)
: GraphicsElement(ElementId::Svg)
{
}
Length SVGElement::x() const
{
auto& value = get(PropertyID::X);
auto& value = get(PropertyId::X);
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
}
Length SVGElement::y() const
{
auto& value = get(PropertyID::Y);
auto& value = get(PropertyId::Y);
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
}
Length SVGElement::width() const
{
auto& value = get(PropertyID::Width);
auto& value = get(PropertyId::Width);
return Parser::parseLength(value, ForbidNegativeLengths, Length::HundredPercent);
}
Length SVGElement::height() const
{
auto& value = get(PropertyID::Height);
auto& value = get(PropertyId::Height);
return Parser::parseLength(value, ForbidNegativeLengths, Length::HundredPercent);
}
Rect SVGElement::viewBox() const
{
auto& value = get(PropertyID::ViewBox);
auto& value = get(PropertyId::ViewBox);
return Parser::parseViewBox(value);
}
PreserveAspectRatio SVGElement::preserveAspectRatio() const
{
auto& value = get(PropertyID::PreserveAspectRatio);
auto& value = get(PropertyId::PreserveAspectRatio);
return Parser::parsePreserveAspectRatio(value);
}
std::unique_ptr<LayoutSymbol> SVGElement::build(const TreeBuilder* builder) const
std::unique_ptr<LayoutSymbol> SVGElement::layoutDocument(const ParseDocument* document) const
{
if(isDisplayNone())
return nullptr;
@ -73,7 +73,7 @@ std::unique_ptr<LayoutSymbol> SVGElement::build(const TreeBuilder* builder) cons
root->clip = isOverflowHidden() ? preserveAspectRatio.getClip(_w, _h, viewBox) : Rect::Invalid;
root->opacity = opacity();
LayoutContext context(builder, root.get());
LayoutContext context(document, root.get());
root->masker = context.getMasker(mask());
root->clipper = context.getClipper(clip_path());
layoutChildren(&context, root.get());

View file

@ -5,7 +5,7 @@
namespace lunasvg {
class TreeBuilder;
class ParseDocument;
class LayoutSymbol;
class SVGElement : public GraphicsElement
@ -20,7 +20,7 @@ public:
Rect viewBox() const;
PreserveAspectRatio preserveAspectRatio() const;
std::unique_ptr<LayoutSymbol> build(const TreeBuilder* builder) const;
std::unique_ptr<LayoutSymbol> layoutDocument(const ParseDocument* document) const;
void layout(LayoutContext* context, LayoutContainer* current) const;
std::unique_ptr<Node> clone() const;

View file

@ -4,43 +4,43 @@
namespace lunasvg {
SymbolElement::SymbolElement()
: StyledElement(ElementID::Symbol)
: StyledElement(ElementId::Symbol)
{
}
Length SymbolElement::x() const
{
auto& value = get(PropertyID::X);
auto& value = get(PropertyId::X);
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
}
Length SymbolElement::y() const
{
auto& value = get(PropertyID::Y);
auto& value = get(PropertyId::Y);
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
}
Length SymbolElement::width() const
{
auto& value = get(PropertyID::Width);
auto& value = get(PropertyId::Width);
return Parser::parseLength(value, ForbidNegativeLengths, Length::HundredPercent);
}
Length SymbolElement::height() const
{
auto& value = get(PropertyID::Height);
auto& value = get(PropertyId::Height);
return Parser::parseLength(value, ForbidNegativeLengths, Length::HundredPercent);
}
Rect SymbolElement::viewBox() const
{
auto& value = get(PropertyID::ViewBox);
auto& value = get(PropertyId::ViewBox);
return Parser::parseViewBox(value);
}
PreserveAspectRatio SymbolElement::preserveAspectRatio() const
{
auto& value = get(PropertyID::PreserveAspectRatio);
auto& value = get(PropertyId::PreserveAspectRatio);
return Parser::parsePreserveAspectRatio(value);
}

View file

@ -8,47 +8,47 @@
namespace lunasvg {
UseElement::UseElement()
: GraphicsElement(ElementID::Use)
: GraphicsElement(ElementId::Use)
{
}
Length UseElement::x() const
{
auto& value = get(PropertyID::X);
auto& value = get(PropertyId::X);
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
}
Length UseElement::y() const
{
auto& value = get(PropertyID::Y);
auto& value = get(PropertyId::Y);
return Parser::parseLength(value, AllowNegativeLengths, Length::Zero);
}
Length UseElement::width() const
{
auto& value = get(PropertyID::Width);
auto& value = get(PropertyId::Width);
return Parser::parseLength(value, ForbidNegativeLengths, Length::HundredPercent);
}
Length UseElement::height() const
{
auto& value = get(PropertyID::Height);
auto& value = get(PropertyId::Height);
return Parser::parseLength(value, ForbidNegativeLengths, Length::HundredPercent);
}
std::string UseElement::href() const
{
auto& value = get(PropertyID::Href);
auto& value = get(PropertyId::Href);
return Parser::parseHref(value);
}
void UseElement::transferWidthAndHeight(Element* element) const
{
auto& width = get(PropertyID::Width);
auto& height = get(PropertyID::Height);
auto& width = get(PropertyId::Width);
auto& height = get(PropertyId::Height);
element->set(PropertyID::Width, width, 0x0);
element->set(PropertyID::Height, height, 0x0);
element->set(PropertyId::Width, width, 0x0);
element->set(PropertyId::Height, height, 0x0);
}
void UseElement::layout(LayoutContext* context, LayoutContainer* current) const
@ -69,15 +69,15 @@ void UseElement::layout(LayoutContext* context, LayoutContainer* current) const
auto _x = lengthContext.valueForLength(x(), LengthMode::Width);
auto _y = lengthContext.valueForLength(y(), LengthMode::Height);
auto transform = get(PropertyID::Transform);
auto transform = get(PropertyId::Transform);
transform += "translate(";
transform += std::to_string(_x);
transform += ' ';
transform += std::to_string(_y);
transform += ')';
group->set(PropertyID::Transform, transform, 0x10);
group->set(PropertyId::Transform, transform, 0x10);
if(ref->id == ElementID::Svg || ref->id == ElementID::Symbol)
if(ref->id == ElementId::Svg || ref->id == ElementId::Symbol)
{
auto element = ref->cloneElement<SVGElement>();
transferWidthAndHeight(element.get());