How parsed values are passed to context

To find out how value of the SVG attribute will be passed to context, following algorithm should be applied:

  1. If attribute tag is included in passthrough_attributes sequence, then its value will be passed by Value Events Policy as a string.
  2. If for this element and attribute traits::attribute_type<ElementTag, AttributeTag>::type is tag::type::string, then value will also be passed by Value Events Policy as a string.
  3. Otherwise type of the attribute should be found in its description in SVG Specification.
  4. Attribute values of type <path data> (e.g. d attribute of path element) are described in Path section.
  5. Attribute values of type <transform list> (e.g. transform attribute) are described in Transform section.
  6. All others are passed through Value Events Policy.

Value Events Policy

Value Events Policy Concept

Value Events Policy is a class, containing static set methods, that receives reference to context object as a first argument, attribute tag as a second and a source tag as a third. Source tag is one of two types: tag::source::css and tag::source::attribute (they have common base tag::source::any). Source tag shows where value comes from – CSS value in style attribute or from separate SVG/XML attribute. Number and types of other parameters depends on an attribute type.

structvalue_events_policy
{
staticvoidset(Context&context,AttributeTagtag,SourceTagsource,ValueType1const&value1);
staticvoidset(Context&context,AttributeTagtag,SourceTagsource,ValueType1const&value1,ValueType2const&value2);
/*...*/
};

policy::value_events::forward_to_method used by default forward calls to set methods of context object:

template<classContext>
structforward_to_method
{
template<classAttributeTag,class...Args>
staticvoidset(Context&context,AttributeTagtag,tag::source::anyconst&,Args...args)
{
context.set(tag,args...);
}
};

Note

Source tag is dropped by default Value Events Policy, because default Attribute Traversal Policy processes only one value of the same property, even if both are provided (css_hides_presentation_attribute = true).

Note

Default Value Events Policy doesn’t pass tag::value::inherit values of properties and presentation attributes, that are inherited (see policy::value_events::skip_inherit). inherit value for such attributes is equivalent to its absence.

Example of default Value Events Policy usage:

#include<svgpp/svgpp.hpp>
usingnamespacesvgpp;
structContext
{
voidset(tag::attribute::amplitude,doublevalue)
{
std::cout<<value<<"\n";
}
};
voidfunc()
{
Contextcontext;
value_parser<tag::type::number>::parse(tag::attribute::amplitude(),context,std::string("3.14"),tag::source::attribute());
}

Example of own Value Events Policy implementation. Created policy::value_events::default_policy template class specialization for our context type (let it be boost::optional<double> in our example):

namespacesvgpp{namespacepolicy{namespacevalue_events
{
template<>
structdefault_policy<boost::optional<double>>
{
template<classAttributeTag>
staticvoidset(boost::optional<double>&context,AttributeTagtag,tag::source::any,doublevalue)
{
context=value;
}
};
}}}
voidfunc()
{
boost::optional<double>context;
value_parser<tag::type::number>::parse(tag::attribute::amplitude(),context,std::string("3.14"),tag::source::attribute());
if(context)
std::cout<<*context<<"\n";
}
Literal Values

If literal is one of attribute possible values, then this value will cause call with tag from tag::value namespace. Example of attributes that may have literal values:

gradientUnits="userSpaceOnUse | objectBoundingBox"
clip-path="<funciri> | none | inherit"

gradientUnits is limited to two literal values. clip-path, besides none and inherit literal values may get values of <FuncIRI> type.

Example of context implementation, that receives values of gradientUnits attributes:

classGradientContext
{
public:
GradientContext()
:m_gradientUnitsUserSpace(false)
{}
voidset(tag::attribute::gradientUnits,tag::value::userSpaceOnUse)
{
m_gradientUnitsUserSpace=true;
}
voidset(tag::attribute::gradientUnits,tag::value::objectBoundingBox)
{
m_gradientUnitsUserSpace=false;
}
private:
boolm_gradientUnitsUserSpace;
};
<length> or <coordinate>
Is passed as single argument, whose type is set by Length Factory (by default double).
<IRI> or <FuncIRI>
See IRI.
<integer>
Single argument of int type is used.
<number> or <opacity-value>
Is passed as single argument of number_type_ (by default double).

<percentage>

<color>
Is passed as single argument, whose type is set by Color Factory (by default 8 bit per channel RGB packed in int).
<color> [<icccolor>]

If <icccolor> isn’t set, then it is passed as single argument, whose type is set by Color Factory. Otherwise, second argument is added, whose type is set by ICC Color Factory. Example:

structContext
{
voidset(tag::attribute::flood_color,intrgb);
voidset(tag::attribute::flood_color,intrgb,tag::skip_icc_color);
voidset(tag::attribute::flood_color,tag::value::currentColor);
voidset(tag::attribute::flood_color,tag::value::inherit);
};
<angle>
Is passed as single argument, whose type and value are set by Angle Factory (by default double value in degrees).
<number-optional-number>
Is passed as one or two arguments of number_type_ type (by default double).
<list-of-numbers>, <list-of-lengths> or <list-of-points>

Is passed as single argument of unspecified type, which is model of Boost Single Pass Range.

range items have type:
  • number_type_ (by default double) in case of <list-of-numbers>;
  • that is set by Length Factory in case of <list-of-lengths>;
  • std::pair<number_type, number_type> (by default std::pair<double, double>) in case of <list-of-points>.

Example:

structContext
{
template<classRange>
voidset(tag::attribute::kernelMatrix,Rangeconst&range)
{
for(typenameboost::range_iterator<Range>::typeit=boost::begin(range),end=boost::end(range);
it!=end;++it)
std::cout<<*it;
}
};

Note

If template function can’t be used (e.g. it is virtual function), then Boost any_range can be used as range type instead:

typedefboost::any_range<double,boost::single_pass_traversal_tag,doubleconst&,std::ptrdiff_t>Range;
<shape>
Is passed as 5 arguments - first is tag tag::value::rect, others are of number_type_ type (by default double): (tag::value::rect(), top, right, bottom, left).
viewBox attribute
Is passed as 4 arguments of number_type_ type (by default double): (x, y, width, height).
bbox attribute
Is passed as 4 arguments of number_type_ type (by default double): (lo_x, lo_y, hi_x, hi_y).
preserveAspectRatio attribute
Depending on value is passed as:
  • (bool defer, tag::value::none)

  • (bool defer, AlignT align, MeetOrSliceT meetOrSlice)

    Type AlignT is one of tag::value::xMinYMin, tag::value::xMidYMin, tag::value::xMaxYMin, tag::value::xMinYMid, tag::value::xMidYMid, tag::value::xMaxYMid, tag::value::xMinYMax, tag::value::xMidYMax, tag::value::xMaxYMax. Type MeetOrSliceT is tag::value::meet or tag::value::slice.

text-decoration property

none and inherit values are passed as Literal Values. Other values are passed as 8 arguments, 4 of which is of type bool, each of them preceded with tag, describing argument meaning. Boolean parameters takes true value if corresponding text decoration is set in property:

structContext
{
voidset(tag::attribute::text_decoration,tag::value::none);
voidset(tag::attribute::text_decoration,tag::value::inherit);
voidset(tag::attribute::text_decoration,
tag::value::underline,boolunderline,
tag::value::overline,booloverline,
tag::value::line_through,boolline_through,
tag::value::blink,boolblink);
};
enable-background property
accumulate, new and inherit values are passed as Literal Values. Values as new <x> <y> <width> <height> are passed as 5 arguments, first of them is tag, other have type number_type_ (by default double): (tag::value::new_(), x, y, width, height).
<paint>

Possible combinations of argument types:

  • (tag::value::inherit)
  • (tag::value::none)
  • (tag::value::currentColor)
  • (<color>)
  • (<color>, <icccolor>)
  • (<iri>, tag::value::none)
  • (<iri>, tag::value::currentColor)
  • (<iri>, <color>)
  • (<iri>, <color>, <icccolor>)

Which types corresponds to <color> and <icccolor> is described above.

If IRI Policy policy::iri::distinguish_local is used, then number of methods with <iri> is doubled:

  • (tag::value::inherit)
  • (tag::value::none)
  • (tag::value::currentColor)
  • (<color>)
  • (<color>, <icccolor>)
  • (<iri>, tag::value::none)
  • (tag::iri_fragment, <iri fragment>, tag::value::none)
  • (<iri>, tag::value::currentColor)
  • (tag::iri_fragment, <iri fragment>, tag::value::currentColor)
  • (<iri>, <color>)
  • (tag::iri_fragment, <iri fragment>, <color>)
  • (<iri>, <color>, <icccolor>)
  • (tag::iri_fragment, <iri fragment>, <color>, <icccolor>)

Example:

typedefboost::variant<tag::value::none,tag::value::currentColor,int/* rgba */>SolidPaint;
structIRIPaint
{
IRIPaint(
std::stringconst&fragment,
boost::optional<SolidPaint>const&fallback=boost::optional<SolidPaint>());
};
typedefboost::variant<SolidPaint,IRIPaint>Paint;
template<classAttributeTag>
classPaintContext
{
public:
voidset(AttributeTag,tag::value::none)
{
m_paint=tag::value::none();
}
voidset(AttributeTag,tag::value::currentColor)
{
m_paint=tag::value::currentColor();
}
voidset(AttributeTag,intcolor,tag::skip_icc_color=tag::skip_icc_color())
{
m_paint=color;
}
template<classIRI>
voidset(AttributeTagtag,IRIconst&iri)
{
throwstd::runtime_error("Non-local references aren't supported");
}
template<classIRI>
voidset(AttributeTagtag,tag::iri_fragment,IRIconst&fragment)
{
m_paint=IRIPaint(std::string(boost::begin(fragment),boost::end(fragment)));
}
template<classIRI>
voidset(AttributeTagtag,IRIconst&,tag::value::noneval)
{
// Ignore non-local IRI, fallback to second option
set(tag,val);
}
template<classIRI>
voidset(AttributeTagtag,tag::iri_fragment,IRIconst&fragment,tag::value::noneval)
{
m_paint=IRIPaint(std::string(boost::begin(fragment),boost::end(fragment)),boost::optional<SolidPaint>(val));
}
template<classIRI>
voidset(AttributeTagtag,IRIconst&,tag::value::currentColorval)
{
// Ignore non-local IRI, fallback to second option
set(tag,val);
}
template<classIRI>
voidset(AttributeTagtag,tag::iri_fragment,IRIconst&fragment,tag::value::currentColorval)
{
m_paint=IRIPaint(std::string(boost::begin(fragment),boost::end(fragment)),boost::optional<SolidPaint>(val));
}
template<classIRI>
voidset(AttributeTagtag,IRIconst&,agg::rgba8val,tag::skip_icc_color=tag::skip_icc_color())
{
// Ignore non-local IRI, fallback to second option
set(tag,val);
}
template<classIRI>
voidset(AttributeTagtag,tag::iri_fragment,IRIconst&fragment,intval,tag::skip_icc_color=tag::skip_icc_color())
{
m_paint=IRIPaint(std::string(boost::begin(fragment),boost::end(fragment)),boost::optional<SolidPaint>(val));
}
private:
Paintm_paint;
};