.. _passing-values: 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: #. If attribute tag is included in :ref:`passthrough_attributes ` sequence, then its value will be passed by `Value Events Policy`_ as a :ref:`string `. #. If for this element and attribute ``traits::attribute_type::type`` is ``tag::type::string``, then value will also be passed by `Value Events Policy`_ as a :ref:`string `. #. Otherwise type of the attribute should be found in its description in `SVG Specification `_. #. Attribute values of type ` `_ (e.g. **d** attribute of **path** element) are described in :ref:`path_section` section. #. Attribute values of type ` `_ (e.g. **transform** attribute) are described in :ref:`transform-section` section. #. 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. :: struct value_events_policy { static void set(Context & context, AttributeTag tag, SourceTag source, ValueType1 const & value1); static void set(Context & context, AttributeTag tag, SourceTag source, ValueType1 const & value1, ValueType2 const & value2); /*...*/ }; ``policy::value_events::forward_to_method`` used by default forward calls to ``set`` methods of ``context`` object:: template struct forward_to_method { template static void set(Context & context, AttributeTag tag, tag::source::any const &, Args... args) { context.set(tag, args...); } }; .. note:: Source tag is dropped by default *Value Events Policy*, because default :ref:`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 using namespace svgpp; struct Context { void set(tag::attribute::amplitude, double value) { std::cout << value << "\n"; } }; void func() { Context context; value_parser::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`` in our example):: namespace svgpp { namespace policy { namespace value_events { template<> struct default_policy > { template static void set(boost::optional & context, AttributeTag tag, tag::source::any, double value) { context = value; } }; }}} void func() { boost::optional context; value_parser::parse(tag::attribute::amplitude(), context, std::string("3.14"), tag::source::attribute()); if (context) std::cout << *context << "\n"; } .. _Literal Values: *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 = " | none | inherit" **gradientUnits** is limited to two literal values. **clip-path**, besides **none** and **inherit** literal values may get values of ** type. Example of context implementation, that receives values of **gradientUnits** attributes:: class GradientContext { public: GradientContext() : m_gradientUnitsUserSpace(false) {} void set(tag::attribute::gradientUnits, tag::value::userSpaceOnUse) { m_gradientUnitsUserSpace = true; } void set(tag::attribute::gradientUnits, tag::value::objectBoundingBox) { m_gradientUnitsUserSpace = false; } private: bool m_gradientUnitsUserSpace; }; ** or ** Is passed as single argument, whose type is set by :ref:`Length Factory ` (by default ``double``). ** or ** See :ref:`iri-section`. ** Single argument of ``int`` type is used. ** or ** Is passed as single argument of number_type_ (by default ``double``). ** ** Is passed as single argument, whose type is set by :ref:`Color Factory ` (by default 8 bit per channel RGB packed in ``int``). * []* If ** isn't set, then it is passed as single argument, whose type is set by :ref:`Color Factory `. Otherwise, second argument is added, whose type is set by :ref:`ICC Color Factory `. Example:: struct Context { void set(tag::attribute::flood_color, int rgb); void set(tag::attribute::flood_color, int rgb, tag::skip_icc_color); void set(tag::attribute::flood_color, tag::value::currentColor); void set(tag::attribute::flood_color, tag::value::inherit); }; ** Is passed as single argument, whose type and value are set by *Angle Factory* (by default ``double`` value in degrees). ** Is passed as one or two arguments of number_type_ type (by default ``double``). **, ** or ** 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 **; * that is set by :ref:`Length Factory ` in case of **; * ``std::pair`` (by default ``std::pair``) in case of **. Example:: struct Context { template void set(tag::attribute::kernelMatrix, Range const & range) { for(typename boost::range_iterator::type it = 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:: typedef boost::any_range Range; ** 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:: struct Context { void set(tag::attribute::text_decoration, tag::value::none); void set(tag::attribute::text_decoration, tag::value::inherit); void set(tag::attribute::text_decoration, tag::value::underline, bool underline, tag::value::overline, bool overline, tag::value::line_through, bool line_through, tag::value::blink, bool blink); }; **enable-background** property **accumulate**, **new** and **inherit** values are passed as `Literal Values`_. Values as **new ** 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)``. ** Possible combinations of argument types: * (``tag::value::inherit``) * (``tag::value::none``) * (``tag::value::currentColor``) * (**) * (**, **) * (**, ``tag::value::none``) * (**, ``tag::value::currentColor``) * (**, **) * (**, **, **) Which types corresponds to ** and ** is described above. If :ref:`IRI Policy ` ``policy::iri::distinguish_local`` is used, then number of methods with ** is doubled: * (``tag::value::inherit``) * (``tag::value::none``) * (``tag::value::currentColor``) * (**) * (**, **) * (**, ``tag::value::none``) * (``tag::iri_fragment``, **, ``tag::value::none``) * (**, ``tag::value::currentColor``) * (``tag::iri_fragment``, **, ``tag::value::currentColor``) * (**, **) * (``tag::iri_fragment``, **, **) * (**, **, **) * (``tag::iri_fragment``, **, **, **) Example:: typedef boost::variant SolidPaint; struct IRIPaint { IRIPaint( std::string const & fragment, boost::optional const & fallback = boost::optional()); }; typedef boost::variant Paint; template class PaintContext { public: void set(AttributeTag, tag::value::none) { m_paint = tag::value::none(); } void set(AttributeTag, tag::value::currentColor) { m_paint = tag::value::currentColor(); } void set(AttributeTag, int color, tag::skip_icc_color = tag::skip_icc_color()) { m_paint = color; } template void set(AttributeTag tag, IRI const & iri) { throw std::runtime_error("Non-local references aren't supported"); } template void set(AttributeTag tag, tag::iri_fragment, IRI const & fragment) { m_paint = IRIPaint(std::string(boost::begin(fragment), boost::end(fragment))); } template void set(AttributeTag tag, IRI const &, tag::value::none val) { // Ignore non-local IRI, fallback to second option set(tag, val); } template void set(AttributeTag tag, tag::iri_fragment, IRI const & fragment, tag::value::none val) { m_paint = IRIPaint(std::string(boost::begin(fragment), boost::end(fragment)), boost::optional(val)); } template void set(AttributeTag tag, IRI const &, tag::value::currentColor val) { // Ignore non-local IRI, fallback to second option set(tag, val); } template void set(AttributeTag tag, tag::iri_fragment, IRI const & fragment, tag::value::currentColor val) { m_paint = IRIPaint(std::string(boost::begin(fragment), boost::end(fragment)), boost::optional(val)); } template void set(AttributeTag tag, IRI const &, agg::rgba8 val, tag::skip_icc_color = tag::skip_icc_color()) { // Ignore non-local IRI, fallback to second option set(tag, val); } template void set(AttributeTag tag, tag::iri_fragment, IRI const & fragment, int val, tag::skip_icc_color = tag::skip_icc_color()) { m_paint = IRIPaint(std::string(boost::begin(fragment), boost::end(fragment)), boost::optional(val)); } private: Paint m_paint; };