2
// Copyright (C) 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
4
// This program is free software; you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation; either version 3 of the License, or
7
// (at your option) any later version.
9
// This program is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
// GNU General Public License for more details.
14
// You should have received a copy of the GNU General Public License
15
// along with this program; if not, write to the Free Software
16
// Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
#ifndef BACKEND_RENDER_HANDLER_AGG_STYLE_H
19
#define BACKEND_RENDER_HANDLER_AGG_STYLE_H
21
// This include file used only to make Renderer_agg more readable.
24
// TODO: Instead of re-creating AGG fill styles again and again, they should
25
// be cached somewhere.
28
// Enable this DEFINE to limit the alpha value of all colors to 50% at most.
29
// This works only with solid and gradient fills (not bitmaps) and is used
30
// for debugging hidden characters.
31
//#define DEBUG_LIMIT_COLOR_ALPHA
36
/// Internal style class that represents a fill style. Roughly speaking, AGG
37
/// computes the fill areas of a flash composite shape and calls generate_span
38
/// to generate small horizontal pixel rows. generate_span provides whatever
39
/// fill pattern for that coordinate.
44
agg_style_base(bool solid, const agg::rgba8& color = agg::rgba8(0,0,0,0))
51
// Everytime a class has a virtual method it should
52
// also have a virtual destructor. This will ensure
53
// that the destructor for the *derived* class is invoked
54
// when deleting a pointer to base class !!
55
virtual ~agg_style_base() {}
57
bool solid() const { return _solid; }
59
agg::rgba8 color() const { return _color; }
61
// for non-solid styles:
62
virtual void generate_span(agg::rgba8* span, int x, int y, unsigned len) = 0;
74
/// Solid AGG fill style. generate_span is not used in this case as AGG does
75
/// solid fill styles internally.
76
class agg_style_solid : public agg_style_base
80
agg_style_solid(const agg::rgba8& color)
82
agg_style_base(true, color)
84
#ifdef DEBUG_LIMIT_COLOR_ALPHA
85
m_color.a = m_color.a>127 ? 127 : m_color.a;
89
void generate_span(agg::rgba8* /*span*/, int /*x*/, int /*y*/,
92
abort(); // never call generate_span for solid fill styles
97
#define image_accessor_clip_transp agg::image_accessor_clone
100
/// AGG bitmap fill style. There are quite a few combinations possible and so
101
/// the class types are defined outside. The bitmap can be tiled or clipped.
102
/// It can have any transformation SWFMatrix and color transform. Any pixel format
103
/// can be used, too.
104
template <class PixelFormat, class span_allocator_type, class img_source_type,
105
class interpolator_type, class sg_type>
106
class agg_style_bitmap : public agg_style_base
110
agg_style_bitmap(int width, int height, int rowlen, boost::uint8_t* data,
111
const gnash::SWFMatrix& mat, const gnash::cxform& cx)
113
agg_style_base(false),
115
m_rbuf(data, width, height, rowlen),
118
m_tr(mat.sx / 65535.0, mat.shx / 65535.0, mat.shy / 65535.0,
119
mat.sy / 65535.0, mat.tx, mat.ty),
120
m_interpolator(m_tr),
121
m_sg(m_img_src, m_interpolator)
124
// Convert the transformation SWFMatrix to AGG's class. It's basically the
125
// same and we could even use gnash::SWFMatrix since AGG does not require
126
// a real AGG descendant (templates!). However, it's better to use AGG's
127
// class as this should be faster (avoid type conversion).
130
virtual ~agg_style_bitmap() {
133
void generate_span(agg::rgba8* span, int x, int y, unsigned len)
135
m_sg.generate(span, x, y, len);
136
// Apply color transform
137
// TODO: Check if this can be optimized
138
if (m_cx.is_identity()) return;
139
for (unsigned int i=0; i<len; i++) {
140
m_cx.transform(span->r, span->g, span->b, span->a);
152
agg::rendering_buffer m_rbuf;
156
span_allocator_type m_sa;
159
img_source_type m_img_src;
162
agg::trans_affine m_tr;
165
interpolator_type m_interpolator;
172
/// AGG gradient fill style. Don't use Gnash texture bitmaps as this is slower
173
/// and less accurate. Even worse, the bitmap fill would need to be tweaked
174
/// to have non-repeating gradients (first and last color stops continue
175
/// forever on each side). This class can be used for any kind of gradient, so
176
/// even focal gradients should be possible.
177
template <class color_type, class span_allocator_type, class interpolator_type,
178
class gradient_func_type, class gradient_adaptor_type, class color_func_type,
180
class agg_style_gradient : public agg_style_base
184
agg_style_gradient(const gnash::fill_style& fs,
185
const gnash::SWFMatrix& mat, const gnash::cxform& cx,
188
agg_style_base(false),
190
m_tr(mat.sx / 65536.0, mat.shx/65536.0, mat.shy / 65536.0,
191
mat.sy / 65536.0, mat.tx, mat.ty),
192
m_span_interpolator(m_tr),
194
m_gradient_adaptor(m_gradient_func),
195
m_sg(m_span_interpolator, m_gradient_adaptor, m_gradient_lut, 0, norm_size),
196
m_need_premultiply(false)
198
// Build gradient lookup table
199
m_gradient_lut.remove_all();
201
for (int i = 0, e = fs.get_color_stop_count(); i != e; ++i) {
203
const gradient_record& gr = fs.get_color_stop(i);
204
rgba trans_color = m_cx.transform(gr.m_color);
206
#ifdef DEBUG_LIMIT_COLOR_ALPHA
207
trans_color.m_a = trans_color.m_a>127 ? 127 : trans_color.m_a;
210
if (trans_color.m_a < 255) m_need_premultiply = true;
212
m_gradient_lut.add_color(gr.m_ratio/255.0, agg::rgba8(trans_color.m_r,
213
trans_color.m_g, trans_color.m_b, trans_color.m_a));
217
m_gradient_lut.build_lut();
219
} // agg_style_gradient constructor
222
virtual ~agg_style_gradient()
227
void generate_span(color_type* span, int x, int y, unsigned len)
229
m_sg.generate(span, x, y, len);
231
if (!m_need_premultiply) return;
239
// Provide access to our gradient adaptor to allow re-initialization of
240
// focal gradients. I wanted to do this using partial template specialization
241
// but it became too complex for something that can be solved in a very easy
242
// (slightly unelegant) way.
243
gradient_adaptor_type& get_gradient_adaptor() {
244
return m_gradient_adaptor;
253
span_allocator_type m_sa;
256
agg::trans_affine m_tr;
259
interpolator_type m_span_interpolator;
261
gradient_func_type m_gradient_func;
264
gradient_adaptor_type m_gradient_adaptor;
267
color_func_type m_gradient_lut;
272
// premultiplication necessary?
273
bool m_need_premultiply;
275
}; // agg_style_gradient
280
// --- AGG HELPER CLASSES ------------------------------------------------------
282
/// Style handler for AGG's compound rasterizer. This is the class which is
283
/// called by AGG itself. It provides an interface to the various fill style
284
/// classes defined above.
285
class agg_style_handler
289
agg_style_handler() :
290
m_transparent(0, 0, 0, 0)
293
~agg_style_handler() {
294
int styles_size = m_styles.size();
295
for (int i=0; i<styles_size; i++)
299
/// Called by AGG to ask if a certain style is a solid color
300
bool is_solid(unsigned style) const {
301
assert(style < m_styles.size());
302
return m_styles[style]->solid();
305
/// Adds a new solid fill color style
306
void add_color(const agg::rgba8& color) {
307
agg_style_solid *st = new agg_style_solid(color);
308
m_styles.push_back(st);
311
/// Adds a new bitmap fill style
312
void add_bitmap(const agg_bitmap_info* bi, const gnash::SWFMatrix& mat,
313
const gnash::cxform& cx, bool repeat, bool smooth)
317
// See server/styles.h comments about when NULL return is possible.
318
// Don't warn here, we already warn at parse-time
319
//log_debug("WARNING: add_bitmap called with bi=NULL");
320
add_color(agg::rgba8_pre(0,0,0,0));
324
// Whew! There are 8 bitmap combinations (bpp, smooth, repeat) possible
325
// and AGG uses templates, so...
326
// I'd need to pass "span_image_filter_rgba_nn" (because span_image_xxx
327
// dependends on the pixel format) without passing the template
328
// parameters, but AFAIK this can't be done. But hey, this is my first
329
// C++ code (the whole AGG backend) and I immediately had to start with
330
// templates. I'm giving up and write eight versions of add_bitmap_xxx.
331
// So, if anyone has a better solution, for heaven's sake, implement it!!
336
if (bi->get_bpp()==24)
337
add_bitmap_repeat_aa_rgb24 (bi, mat, cx);
339
if (bi->get_bpp()==32)
340
add_bitmap_repeat_aa_rgba32 (bi, mat, cx);
346
if (bi->get_bpp()==24)
347
add_bitmap_repeat_nn_rgb24 (bi, mat, cx);
349
if (bi->get_bpp()==32)
350
add_bitmap_repeat_nn_rgba32 (bi, mat, cx);
358
if (bi->get_bpp()==24)
359
add_bitmap_clip_aa_rgb24 (bi, mat, cx);
361
if (bi->get_bpp()==32)
362
add_bitmap_clip_aa_rgba32 (bi, mat, cx);
368
if (bi->get_bpp()==24)
369
add_bitmap_clip_nn_rgb24 (bi, mat, cx);
371
if (bi->get_bpp()==32)
372
add_bitmap_clip_nn_rgba32 (bi, mat, cx);
385
void add_bitmap_repeat_nn_rgb24(const agg_bitmap_info* bi,
386
const gnash::SWFMatrix& mat, const gnash::cxform& cx)
389
// tiled, nearest neighbor method (faster)
391
typedef agg::pixfmt_rgb24_pre PixelFormat;
392
typedef agg::span_allocator<PixelFormat> span_allocator_type;
393
typedef agg::wrap_mode_repeat wrap_type;
394
typedef agg::image_accessor_wrap<PixelFormat, wrap_type, wrap_type> img_source_type;
395
typedef agg::span_interpolator_linear_subdiv<agg::trans_affine> interpolator_type;
396
typedef agg::span_image_filter_rgb_nn<img_source_type, interpolator_type> sg_type;
398
typedef agg_style_bitmap<PixelFormat, span_allocator_type, img_source_type,
399
interpolator_type, sg_type> st_type;
401
st_type* st = new st_type(bi->get_width(), bi->get_height(),
402
bi->get_rowlen(), bi->get_data(), mat, cx);
404
m_styles.push_back(st);
410
void add_bitmap_clip_nn_rgb24(const agg_bitmap_info* bi,
411
const gnash::SWFMatrix& mat, const gnash::cxform& cx)
414
// clipped, nearest neighbor method (faster)
416
typedef agg::pixfmt_rgb24_pre PixelFormat;
417
typedef agg::span_allocator<PixelFormat> span_allocator_type;
418
typedef image_accessor_clip_transp<PixelFormat> img_source_type;
419
typedef agg::span_interpolator_linear_subdiv<agg::trans_affine> interpolator_type;
420
typedef agg::span_image_filter_rgb_nn<img_source_type, interpolator_type> sg_type;
422
typedef agg_style_bitmap<PixelFormat, span_allocator_type, img_source_type,
423
interpolator_type, sg_type> st_type;
425
st_type* st = new st_type(bi->get_width(), bi->get_height(),
426
bi->get_rowlen(), bi->get_data(), mat, cx);
428
m_styles.push_back(st);
433
void add_bitmap_repeat_aa_rgb24(const agg_bitmap_info* bi,
434
const gnash::SWFMatrix& mat, const gnash::cxform& cx)
437
// tiled, bilinear method (better quality)
439
typedef agg::pixfmt_rgb24_pre PixelFormat;
440
typedef agg::span_allocator<PixelFormat> span_allocator_type;
441
typedef agg::wrap_mode_repeat wrap_type;
442
typedef agg::image_accessor_wrap<PixelFormat, wrap_type, wrap_type> img_source_type;
443
typedef agg::span_interpolator_linear_subdiv<agg::trans_affine> interpolator_type;
444
typedef agg::span_image_filter_rgb_bilinear<img_source_type, interpolator_type> sg_type;
446
typedef agg_style_bitmap<PixelFormat, span_allocator_type, img_source_type,
447
interpolator_type, sg_type> st_type;
449
st_type* st = new st_type(bi->get_width(), bi->get_height(),
450
bi->get_rowlen(), bi->get_data(), mat, cx);
452
m_styles.push_back(st);
456
void add_bitmap_clip_aa_rgb24(const agg_bitmap_info* bi,
457
const gnash::SWFMatrix& mat, const gnash::cxform& cx)
460
// clipped, bilinear method (better quality)
462
typedef agg::pixfmt_rgb24_pre PixelFormat;
463
typedef agg::span_allocator<PixelFormat> span_allocator_type;
464
typedef image_accessor_clip_transp<PixelFormat> img_source_type;
465
typedef agg::span_interpolator_linear_subdiv<agg::trans_affine> interpolator_type;
466
typedef agg::span_image_filter_rgb_bilinear<img_source_type, interpolator_type> sg_type;
468
typedef agg_style_bitmap<PixelFormat, span_allocator_type, img_source_type,
469
interpolator_type, sg_type> st_type;
471
st_type* st = new st_type(bi->get_width(), bi->get_height(),
472
bi->get_rowlen(), bi->get_data(), mat, cx);
474
m_styles.push_back(st);
481
void add_bitmap_repeat_nn_rgba32(const agg_bitmap_info* bi,
482
const gnash::SWFMatrix& mat, const gnash::cxform& cx)
485
// tiled, nearest neighbor method (faster)
487
typedef agg::pixfmt_rgba32_pre PixelFormat;
488
typedef agg::span_allocator<PixelFormat> span_allocator_type;
489
typedef agg::wrap_mode_repeat wrap_type;
490
typedef agg::image_accessor_wrap<PixelFormat, wrap_type, wrap_type> img_source_type;
491
typedef agg::span_interpolator_linear_subdiv<agg::trans_affine> interpolator_type;
492
typedef agg::span_image_filter_rgba_nn<img_source_type, interpolator_type> sg_type;
494
typedef agg_style_bitmap<PixelFormat, span_allocator_type, img_source_type,
495
interpolator_type, sg_type> st_type;
497
st_type* st = new st_type(bi->get_width(), bi->get_height(),
498
bi->get_rowlen(), bi->get_data(), mat, cx);
500
m_styles.push_back(st);
506
void add_bitmap_clip_nn_rgba32(const agg_bitmap_info* bi,
507
const gnash::SWFMatrix& mat, const gnash::cxform& cx)
510
// clipped, nearest neighbor method (faster)
512
typedef agg::pixfmt_rgba32_pre PixelFormat;
513
typedef agg::span_allocator<PixelFormat> span_allocator_type;
514
typedef image_accessor_clip_transp<PixelFormat> img_source_type;
515
typedef agg::span_interpolator_linear_subdiv<agg::trans_affine> interpolator_type;
516
typedef agg::span_image_filter_rgba_nn<img_source_type, interpolator_type> sg_type;
518
typedef agg_style_bitmap<PixelFormat, span_allocator_type, img_source_type,
519
interpolator_type, sg_type> st_type;
521
st_type* st = new st_type(bi->get_width(), bi->get_height(),
522
bi->get_rowlen(), bi->get_data(), mat, cx);
524
m_styles.push_back(st);
529
void add_bitmap_repeat_aa_rgba32(const agg_bitmap_info* bi,
530
const gnash::SWFMatrix& mat, const gnash::cxform& cx)
533
// tiled, bilinear method (better quality)
535
typedef agg::pixfmt_rgba32_pre PixelFormat;
536
typedef agg::span_allocator<PixelFormat> span_allocator_type;
537
typedef agg::wrap_mode_repeat wrap_type;
538
typedef agg::image_accessor_wrap<PixelFormat, wrap_type, wrap_type> img_source_type;
539
typedef agg::span_interpolator_linear_subdiv<agg::trans_affine> interpolator_type;
540
typedef agg::span_image_filter_rgba_bilinear<img_source_type, interpolator_type> sg_type;
542
typedef agg_style_bitmap<PixelFormat, span_allocator_type, img_source_type,
543
interpolator_type, sg_type> st_type;
545
st_type* st = new st_type(bi->get_width(), bi->get_height(),
546
bi->get_rowlen(), bi->get_data(), mat, cx);
548
m_styles.push_back(st);
552
void add_bitmap_clip_aa_rgba32(const agg_bitmap_info* bi,
553
const gnash::SWFMatrix& mat, const gnash::cxform& cx)
556
// clipped, bilinear method (better quality)
558
typedef agg::pixfmt_rgba32_pre PixelFormat;
559
typedef agg::span_allocator<PixelFormat> span_allocator_type;
560
typedef image_accessor_clip_transp<PixelFormat> img_source_type;
561
typedef agg::span_interpolator_linear_subdiv<agg::trans_affine> interpolator_type;
562
typedef agg::span_image_filter_rgba_bilinear<img_source_type, interpolator_type> sg_type;
564
typedef agg_style_bitmap<PixelFormat, span_allocator_type, img_source_type,
565
interpolator_type, sg_type> st_type;
567
st_type* st = new st_type(bi->get_width(), bi->get_height(),
568
bi->get_rowlen(), bi->get_data(), mat, cx);
570
m_styles.push_back(st);
576
void add_gradient_linear(const gnash::fill_style& fs,
577
const gnash::SWFMatrix& mat, const gnash::cxform& cx)
580
typedef agg::rgba8 color_type;
581
typedef agg::span_allocator<color_type> span_allocator_type;
582
typedef agg::span_interpolator_linear<agg::trans_affine> interpolator_type;
583
typedef agg::gradient_x gradient_func_type;
584
//typedef agg::gradient_repeat_adaptor<gradient_func_type> gradient_adaptor_type;
585
typedef gradient_func_type gradient_adaptor_type;
586
typedef agg::gradient_lut<agg::color_interpolator<color_type>, 256> color_func_type;
587
typedef agg::span_gradient<color_type,
589
gradient_adaptor_type,
590
color_func_type> sg_type;
592
typedef agg_style_gradient<color_type, span_allocator_type,
593
interpolator_type, gradient_func_type, gradient_adaptor_type,
594
color_func_type, sg_type> st_type;
596
st_type* st = new st_type(fs, mat, cx, 256);
598
// NOTE: The value 256 is based on the bitmap texture used by other
599
// Gnash renderers which is normally 256x1 pixels for linear gradients.
601
m_styles.push_back(st);
605
void add_gradient_radial(const gnash::fill_style& fs,
606
const gnash::SWFMatrix& mat, const gnash::cxform& cx)
609
typedef agg::rgba8 color_type;
610
typedef agg::span_allocator<color_type> span_allocator_type;
611
typedef agg::span_interpolator_linear<agg::trans_affine>
613
typedef agg::gradient_radial gradient_func_type;
614
typedef gradient_func_type gradient_adaptor_type;
615
typedef agg::gradient_lut<agg::color_interpolator<color_type>, 256>
617
typedef agg::span_gradient<color_type,
619
gradient_adaptor_type,
620
color_func_type> sg_type;
622
typedef agg_style_gradient<color_type, span_allocator_type,
623
interpolator_type, gradient_func_type, gradient_adaptor_type,
624
color_func_type, sg_type> st_type;
626
// move the center of the radial fill to where it should be
627
gnash::SWFMatrix transl;
628
transl.set_translation(-32, -32);
629
transl.concatenate(mat);
631
// div 2 because we need radius, not diameter
632
st_type* st = new st_type(fs, transl, cx, 64/2);
634
// NOTE: The value 64 is based on the bitmap texture used by other
635
// Gnash renderers which is normally 64x64 pixels for radial gradients.
637
m_styles.push_back(st);
640
void add_gradient_focal(const gnash::fill_style& fs,
641
const gnash::SWFMatrix& mat, const gnash::cxform& cx)
643
typedef agg::rgba8 color_type;
644
typedef agg::span_allocator<color_type> span_allocator_type;
645
typedef agg::span_interpolator_linear<agg::trans_affine> interpolator_type;
646
typedef agg::gradient_radial_focus gradient_func_type;
647
typedef gradient_func_type gradient_adaptor_type;
648
typedef agg::gradient_lut<agg::color_interpolator<color_type>, 256> color_func_type;
649
typedef agg::span_gradient<color_type, interpolator_type,
650
gradient_adaptor_type, color_func_type> sg_type;
652
typedef agg_style_gradient<color_type, span_allocator_type,
653
interpolator_type, gradient_func_type, gradient_adaptor_type,
654
color_func_type, sg_type> st_type;
656
// move the center of the focal fill (not its focal point) to where it
658
gnash::SWFMatrix transl;
659
transl.set_translation(-32, -32);
660
transl.concatenate(mat);
662
st_type* st = new st_type(fs, transl, cx, 64/2);
664
// re-initialize focal gradient settings
665
gradient_adaptor_type& adaptor = st->get_gradient_adaptor();
666
adaptor.init(32.0, fs.get_focal_point()*32.0, 0.0);
668
m_styles.push_back(st);
671
/// Returns the color of a certain fill style (solid)
672
agg::rgba8 color(unsigned style) const
674
if (style < m_styles.size())
675
return m_styles[style]->color();
677
return m_transparent;
680
/// Called by AGG to generate a scanline span for non-solid fills
681
void generate_span(agg::rgba8* span, int x, int y,
682
unsigned len, unsigned style)
684
m_styles[style]->generate_span(span,x,y,len);
689
std::vector<agg_style_base*> m_styles;
690
agg::rgba8 m_transparent;
691
}; // class agg_style_handler
695
class agg_mask_style_handler
699
agg_mask_style_handler() :
704
bool is_solid(unsigned /*style*/) const
709
const agg::gray8& color(unsigned /*style*/) const
714
void generate_span(agg::gray8* /*span*/, int /*x*/, int /*y*/,
715
int /*len*/, unsigned /*style*/)
717
abort(); // never call generate_span for solid fill styles
723
}; // class agg_mask_style_handler
728
#endif // BACKEND_RENDER_HANDLER_AGG_STYLE_H