agg::gradient_props

oncaphillis edited this page Mar 20, 2014 · 1 revision

gradient_subpixel_shift

The original implementation of AGGs gradient fill algorithms works with a constant named gradient_subpixel_shift which determines the precision of AGGs fixed-point arithmetic in the realm of the span_gradient<...> template class. The previous value was 4 which allows for 16 different values after the dot. In my attempt to use AGG as an poppler backend I found out that it is not uncommon for PDF documents to initially define their gradients in the range G:={0.0...1.0} ans later scale the gradient up to its target size with the help of the current transformation matrix, which results in jaggy gradients. It would therefore be desirable to somehow make the subpixel_shift a parameter of span_gradient<...> with as little as possible divergence from the original API.

||| :-------------------------------------------------------------:|:----------------------------------------------------------------------: |A jaggy gradient with subpixel_shift==4|A smooth gradient with subpixel_shift==8|

A simple solution would be to provide an additional template argument to span_gradient<...> and all GradientF classes which need to know about the shift factor. Even more simple would be if span_gradient "inherits" the subpixel_shift from GradientF like.

static const int subpixel_shift = GradientF::subpixel_shift;

This however would mean that every GradientF_ implementation has to come up with its own ''static const int' definition of subpixel_shift. We need a mechanism which provides us with s decent default value if there isn't such constant defined.

Enter SFINAE

A bit of SFINAE magic helps us.We make span_gradient<...> not pull the constant from the GradienF_ argument directly but let another template class handle the decision if there is a 'const int subpixel_shift' defined in the class and to come up with a default value if ther isn't.

template<class GradientF>
class gradient_props
{
private:
    typedef char Yes;
    typedef char No[2];

    template<typename X,const X *> struct has;
    template <typename Y> static Yes & Test(has<int,&Y::subpixel_shift>*);
    template <typename Y> static  No & Test(...);
    template<class X,bool B>
    struct V
    {
        static const int value = 4;
    };

    template<class X>
    struct V<X,true>
    {
        static const int value=X::subpixel_shift;
    };
public:
    static const int subpixel_shift = V<GradientF,sizeof(Test<GradientF>(0))==sizeof(Yes)>::value;
    static const int subpixel_scale = 1 << subpixel_shift;
    static const int subpixel_mask  = subpixel_scale - 1;
};

span_gradient<...> may now use gradient_props::subpixel_shift to access the shift value associated with a given gradient function. Old classes like gradient_circle or gradient_xy which do not use the constant at all still work as they used to and one might reuse them with different shift values by simple sub classing like.

class my_gradient_x : public agg::gradient_x
{
public:
    static const int subpixel_shift = 8;
    .... 
};     

Only those gradient function classes which need to have knowledge about the shift factor need special treatment like:

template<class T=void>
bascic_gradient_radial_focus; 

Base classes like these pull their shift factor from the template argument T via 'gradient_props::subpixel_shift': The default argument still guarantees that the old constants are used. and e.g gradient_radial_focus can simply be defined as

typedef basic_gradient_radial_focus<> gradient_radial_focus;

Deduction from this basic gradient might be done via CRPT like

class my_gradient_radial_focus : public agg::basic_radial_focus<my_gradient_radial_focus>
{
public:
     static const int subpixel_shift = 8;
}
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Press h to open a hovercard with more details.