protect against invalid memory access if agg gradient lookup fails to build

This commit is contained in:
Dane Springmeyer 2013-09-27 15:24:33 -07:00
parent 423a8007ba
commit f4c3620d67
4 changed files with 139 additions and 132 deletions

View file

@ -137,7 +137,7 @@ namespace agg
//--------------------------------------------------------------------
void remove_all();
void add_color(double offset, const color_type& color);
void build_lut();
bool build_lut();
// Size-index Interface. This class can be used directly as the
// ColorF in span_gradient. All it needs is two access methods
@ -202,7 +202,7 @@ namespace agg
//------------------------------------------------------------------------
template<class T, unsigned S>
void gradient_lut<T,S>::build_lut()
bool gradient_lut<T,S>::build_lut()
{
quick_sort(m_color_profile, offset_less);
m_color_profile.cut_at(remove_duplicates(m_color_profile, offset_equal));
@ -234,7 +234,9 @@ namespace agg
{
m_color_lut[end] = c;
}
return true;
}
return false;
}
}

View file

@ -481,75 +481,79 @@ template <typename Src>
void apply_filter(Src & src, colorize_alpha const& op)
{
using namespace boost::gil;
agg::gradient_lut<agg::color_interpolator<agg::rgba8> > grad_lut;
grad_lut.remove_all();
std::size_t size = op.size();
if (size < 2) return;
double step = 1.0/(size-1);
double offset = 0.0;
BOOST_FOREACH( mapnik::filter::color_stop const& stop, op)
if (size > 1)
{
mapnik::color const& c = stop.color;
double stop_offset = stop.offset;
if (stop_offset == 0)
// interpolate multiple stops
agg::gradient_lut<agg::color_interpolator<agg::rgba8> > grad_lut;
double step = 1.0/(size-1);
double offset = 0.0;
BOOST_FOREACH( mapnik::filter::color_stop const& stop, op)
{
stop_offset = offset;
}
grad_lut.add_color(stop_offset, agg::rgba(c.red()/256.0,
c.green()/256.0,
c.blue()/256.0,
c.alpha()/256.0));
offset += step;
}
grad_lut.build_lut();
rgba8_view_t src_view = rgba8_view(src);
for (int y=0; y<src_view.height(); ++y)
{
rgba8_view_t::x_iterator src_it = src_view.row_begin(y);
for (int x=0; x<src_view.width(); ++x)
{
uint8_t & r = get_color(src_it[x], red_t());
uint8_t & g = get_color(src_it[x], green_t());
uint8_t & b = get_color(src_it[x], blue_t());
uint8_t & a = get_color(src_it[x], alpha_t());
if ( a > 0)
mapnik::color const& c = stop.color;
double stop_offset = stop.offset;
if (stop_offset == 0)
{
agg::rgba8 c = grad_lut[a];
r = (c.r * a + 255) >> 8;
g = (c.g * a + 255) >> 8;
b = (c.b * a + 255) >> 8;
#if 0
// rainbow
r = 0;
g = 0;
b = 0;
if (a < 64)
stop_offset = offset;
}
grad_lut.add_color(stop_offset, agg::rgba(c.red()/256.0,
c.green()/256.0,
c.blue()/256.0,
c.alpha()/256.0));
offset += step;
}
if (grad_lut.build_lut())
{
rgba8_view_t src_view = rgba8_view(src);
for (int y=0; y<src_view.height(); ++y)
{
rgba8_view_t::x_iterator src_it = src_view.row_begin(y);
for (int x=0; x<src_view.width(); ++x)
{
g = a * 4;
b = 255;
uint8_t & r = get_color(src_it[x], red_t());
uint8_t & g = get_color(src_it[x], green_t());
uint8_t & b = get_color(src_it[x], blue_t());
uint8_t & a = get_color(src_it[x], alpha_t());
if ( a > 0)
{
agg::rgba8 c = grad_lut[a];
r = (c.r * a + 255) >> 8;
g = (c.g * a + 255) >> 8;
b = (c.b * a + 255) >> 8;
if (r>a) r=a;
if (g>a) g=a;
if (b>a) b=a;
#if 0
// rainbow
r = 0;
g = 0;
b = 0;
if (a < 64)
{
g = a * 4;
b = 255;
}
else if (a >= 64 && a < 128)
{
g = 255;
b = 255 - ((a - 64) * 4);
}
else if (a >= 128 && a < 192)
{
r = (a - 128) * 4;
g = 255;
}
else // >= 192
{
r = 255;
g = 255 - ((a - 192) * 4);
}
r = (r * a + 255) >> 8;
g = (g * a + 255) >> 8;
b = (b * a + 255) >> 8;
#endif
}
}
else if (a >= 64 && a < 128)
{
g = 255;
b = 255 - ((a - 64) * 4);
}
else if (a >= 128 && a < 192)
{
r = (a - 128) * 4;
g = 255;
}
else // >= 192
{
r = 255;
g = 255 - ((a - 192) * 4);
}
r = (r * a + 255) >> 8;
g = (g * a + 255) >> 8;
b = (b * a + 255) >> 8;
#endif
}
}
}

View file

@ -151,87 +151,88 @@ public:
unsigned a = stop_color.alpha();
m_gradient_lut.add_color(st.first, agg::rgba8_pre(r, g, b, int(a * opacity)));
}
m_gradient_lut.build_lut();
agg::trans_affine transform = mtx;
transform.invert();
agg::trans_affine tr;
tr = grad.get_transform();
tr.invert();
transform *= tr;
if (grad.get_units() != USER_SPACE_ON_USE)
if (m_gradient_lut.build_lut())
{
double bx1=symbol_bbox.minx();
double by1=symbol_bbox.miny();
double bx2=symbol_bbox.maxx();
double by2=symbol_bbox.maxy();
agg::trans_affine transform = mtx;
transform.invert();
agg::trans_affine tr;
tr = grad.get_transform();
tr.invert();
transform *= tr;
if (grad.get_units() == OBJECT_BOUNDING_BOX)
if (grad.get_units() != USER_SPACE_ON_USE)
{
bounding_rect_single(curved_trans, path_id, &bx1, &by1, &bx2, &by2);
double bx1=symbol_bbox.minx();
double by1=symbol_bbox.miny();
double bx2=symbol_bbox.maxx();
double by2=symbol_bbox.maxy();
if (grad.get_units() == OBJECT_BOUNDING_BOX)
{
bounding_rect_single(curved_trans, path_id, &bx1, &by1, &bx2, &by2);
}
transform.translate(-bx1,-by1);
transform.scale(1.0/(bx2-bx1),1.0/(by2-by1));
}
transform.translate(-bx1,-by1);
transform.scale(1.0/(bx2-bx1),1.0/(by2-by1));
}
if (grad.get_gradient_type() == RADIAL)
{
typedef agg::gradient_radial_focus gradient_adaptor_type;
typedef agg::span_gradient<agg::rgba8,
interpolator_type,
gradient_adaptor_type,
color_func_type> span_gradient_type;
if (grad.get_gradient_type() == RADIAL)
{
typedef agg::gradient_radial_focus gradient_adaptor_type;
typedef agg::span_gradient<agg::rgba8,
interpolator_type,
gradient_adaptor_type,
color_func_type> span_gradient_type;
// the agg radial gradient assumes it is centred on 0
transform.translate(-x2,-y2);
// the agg radial gradient assumes it is centred on 0
transform.translate(-x2,-y2);
// scale everything up since agg turns things into integers a bit too soon
int scaleup=255;
radius*=scaleup;
x1*=scaleup;
y1*=scaleup;
x2*=scaleup;
y2*=scaleup;
// scale everything up since agg turns things into integers a bit too soon
int scaleup=255;
radius*=scaleup;
x1*=scaleup;
y1*=scaleup;
x2*=scaleup;
y2*=scaleup;
transform.scale(scaleup,scaleup);
interpolator_type span_interpolator(transform);
gradient_adaptor_type gradient_adaptor(radius,(x1-x2),(y1-y2));
transform.scale(scaleup,scaleup);
interpolator_type span_interpolator(transform);
gradient_adaptor_type gradient_adaptor(radius,(x1-x2),(y1-y2));
span_gradient_type span_gradient(span_interpolator,
gradient_adaptor,
m_gradient_lut,
0, radius);
span_gradient_type span_gradient(span_interpolator,
gradient_adaptor,
m_gradient_lut,
0, radius);
render_scanlines_aa(ras, sl, ren, m_alloc, span_gradient);
}
else
{
typedef linear_gradient_from_segment gradient_adaptor_type;
typedef agg::span_gradient<agg::rgba8,
interpolator_type,
gradient_adaptor_type,
color_func_type> span_gradient_type;
render_scanlines_aa(ras, sl, ren, m_alloc, span_gradient);
}
else
{
typedef linear_gradient_from_segment gradient_adaptor_type;
typedef agg::span_gradient<agg::rgba8,
interpolator_type,
gradient_adaptor_type,
color_func_type> span_gradient_type;
// scale everything up since agg turns things into integers a bit too soon
int scaleup=255;
x1*=scaleup;
y1*=scaleup;
x2*=scaleup;
y2*=scaleup;
// scale everything up since agg turns things into integers a bit too soon
int scaleup=255;
x1*=scaleup;
y1*=scaleup;
x2*=scaleup;
y2*=scaleup;
transform.scale(scaleup,scaleup);
transform.scale(scaleup,scaleup);
interpolator_type span_interpolator(transform);
gradient_adaptor_type gradient_adaptor(x1,y1,x2,y2);
interpolator_type span_interpolator(transform);
gradient_adaptor_type gradient_adaptor(x1,y1,x2,y2);
span_gradient_type span_gradient(span_interpolator,
gradient_adaptor,
m_gradient_lut,
0, scaleup);
span_gradient_type span_gradient(span_interpolator,
gradient_adaptor,
m_gradient_lut,
0, scaleup);
render_scanlines_aa(ras, sl, ren, m_alloc, span_gradient);
render_scanlines_aa(ras, sl, ren, m_alloc, span_gradient);
}
}
}

View file

@ -8,7 +8,7 @@
</Rule>
</Style>
<Style name="style" image-filters="colorize-alpha(blue 99%,blue)">
<Style name="style" image-filters="colorize-alpha(blue 100%,blue)">
<Rule>
<PointSymbolizer file="../../data/images/marker.png" allow-overlap="true" />
</Rule>