# 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.

    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<class Context>
    struct forward_to_method
    {
      template<class AttributeTag, class ...Args>
      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 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>

    using namespace svgpp;

    struct Context
    {
      void set(tag::attribute::amplitude, double value)
      {
        std::cout << value << "\n";
      }
    };

    void func()
    {
      Context context;
      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):

    namespace svgpp { namespace policy { namespace value_events
    {
      template<>
      struct default_policy<boost::optional<double> >
      {
        template<class AttributeTag>
        static void set(boost::optional<double> & context, AttributeTag tag, tag::source::any, double value)
        {
          context = value;
        }
      };
    }}}

    void func()
    {
      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:

      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;
      };

<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:

      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);
      };

<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:

      struct Context
      {
        template<class Range>
        void set(tag::attribute::kernelMatrix, Range const & range)
        {
          for(typename boost::range_iterator<Range>::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<double, boost::single_pass_traversal_tag, double const &, 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:

      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 <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:

      typedef boost::variant<tag::value::none, tag::value::currentColor, int/* rgba */> SolidPaint;

      struct IRIPaint
      {
        IRIPaint(
          std::string const & fragment,
          boost::optional<SolidPaint> const & fallback = boost::optional<SolidPaint>());
      };

      typedef boost::variant<SolidPaint, IRIPaint> Paint;

      template<class AttributeTag>
      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<class IRI>
        void set(AttributeTag tag, IRI const & iri)
        {
          throw std::runtime_error("Non-local references aren't supported");
        }

        template<class IRI>
        void set(AttributeTag tag, tag::iri_fragment, IRI const & fragment)
        {
          m_paint = IRIPaint(std::string(boost::begin(fragment), boost::end(fragment)));
        }

        template<class IRI>
        void set(AttributeTag tag, IRI const &, tag::value::none val)
        {
          // Ignore non-local IRI, fallback to second option
          set(tag, val);
        }

        template<class IRI>
        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<SolidPaint>(val));
        }

        template<class IRI>
        void set(AttributeTag tag, IRI const &, tag::value::currentColor val)
        {
          // Ignore non-local IRI, fallback to second option
          set(tag, val);
        }

        template<class IRI>
        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<SolidPaint>(val));
        }

        template<class IRI>
        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<class IRI>
        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<SolidPaint>(val));
        }

      private:
        Paint m_paint;
      };