1 //
2 // Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2011, 2012
3 // Free Software Foundation, Inc
4 //
5 // This program is free software; you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation; either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18
19 #ifndef BACKEND_RENDER_HANDLER_AGG_STYLE_H
20 #define BACKEND_RENDER_HANDLER_AGG_STYLE_H
21
22 // TODO: Instead of re-creating AGG fill styles again and again, they should
23 // be cached somewhere. NOTE that bitmap styles referencing bitmaps would need
24 // to re-check the bitmap definitions as parsing goes on.
25
26 #include <vector>
27 #include <boost/ptr_container/ptr_vector.hpp>
28 #pragma GCC diagnostic push
29 #pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
30 #include <agg_gradient_lut.h>
31 #include <agg_color_rgba.h>
32 #include <agg_color_gray.h>
33 #include <agg_image_accessors.h>
34 #include <agg_span_allocator.h>
35 #include <agg_span_gradient.h>
36 #include <agg_span_interpolator_linear.h>
37 #include <agg_image_filters.h>
38 #include <agg_span_image_filter_rgb.h>
39 #include <agg_span_image_filter_rgba.h>
40 #include <agg_pixfmt_rgb.h>
41 #include <agg_pixfmt_rgba.h>
42 #pragma GCC diagnostic pop
43
44 #include "LinearRGB.h"
45 #include "Renderer_agg_bitmap.h"
46 #include "GnashAlgorithm.h"
47 #include "FillStyle.h"
48 #include "SWFCxForm.h"
49 #include "SWFMatrix.h"
50
51 namespace gnash {
52
53 class StyleHandler;
54
55 // Forward declarations.
56 namespace {
57
58 /// Creates 8 bitmap functions
59 template<typename FillMode, typename Pixel>
60 void storeBitmap(StyleHandler& st, const agg_bitmap_info* bi,
61 const SWFMatrix& mat, const SWFCxForm& cx,
62 bool smooth);
63 template<typename FillMode> void storeBitmap(StyleHandler& st,
64 const agg_bitmap_info* bi, const SWFMatrix& mat, const SWFCxForm& cx,
65 bool smooth);
66
67 /// Creates many (should be 18) gradient functions.
68 void storeGradient(StyleHandler& st, const GradientFill& fs,
69 const SWFMatrix& mat, const SWFCxForm& cx);
70 template<typename Spread> void storeGradient(StyleHandler& st,
71 const GradientFill& fs, const SWFMatrix& mat, const SWFCxForm& cx);
72 template<typename Spread, typename Interpolation>
73 void storeGradient(StyleHandler& st, const GradientFill& fs,
74 const SWFMatrix& mat, const SWFCxForm& cx);
75 }
76
77 /// Internal style class that represents a fill style. Roughly speaking, AGG
78 /// computes the fill areas of a flash composite shape and calls generate_span
79 /// to generate small horizontal pixel rows. generate_span provides whatever
80 /// fill pattern for that coordinate.
81 class AggStyle
82 {
83 public:
84 AggStyle(bool solid, agg::rgba8 color = agg::rgba8(0,0,0,0))
85 :
_solid(solid)86 _solid(solid),
87 _color(std::move(color))
88 {
89 }
90
91 // Everytime a class has a virtual method it should
92 // also have a virtual destructor. This will ensure
93 // that the destructor for the *derived* class is invoked
94 // when deleting a pointer to base class !!
~AggStyle()95 virtual ~AggStyle() {}
solid()96 bool solid() const { return _solid; }
color()97 agg::rgba8 color() const { return _color; }
98
99 // for non-solid styles:
100 virtual void generate_span(agg::rgba8* span, int x, int y,
101 unsigned len) = 0;
102
103 private:
104 // for solid styles:
105 const bool _solid;
106 const agg::rgba8 _color;
107 };
108
109 namespace {
110
111 /// Tile bitmap fills.
112 struct Tile
113 {
114 template<typename P> struct Type {
115 typedef agg::wrap_mode_repeat Wrap;
116 typedef agg::image_accessor_wrap<P, Wrap, Wrap> type;
117 };
118 };
119
120 /// Clip bitmap fills.
121 struct Clip
122 {
123 template<typename P> struct Type {
124 typedef agg::image_accessor_clone<P> type;
125 };
126 };
127
128 /// Base class for filter types.
129 template<typename P, typename W>
130 struct FilterType
131 {
132 typedef typename P::PixelFormat PixelFormat;
133 typedef typename W::template Type<PixelFormat>::type SourceType;
134 typedef agg::span_allocator<PixelFormat> Allocator;
135 typedef agg::span_interpolator_linear<agg::trans_affine>
136 Interpolator;
137 };
138
139 /// Class with typedefs for RGBA operations.
140 struct RGBA
141 {
142 typedef agg::pixfmt_rgba32_pre PixelFormat;
143
144 template<typename SourceType, typename Interpolator>
145 struct Simple {
146 typedef agg::span_image_filter_rgba_nn<SourceType, Interpolator> type;
147 };
148
149 template<typename SourceType, typename Interpolator>
150 struct AntiAlias {
151 typedef agg::span_image_filter_rgba_bilinear<SourceType, Interpolator>
152 type;
153 };
154 };
155
156 /// Class with typedefs for RGB operations.
157 struct RGB
158 {
159 typedef agg::pixfmt_rgb24_pre PixelFormat;
160
161 template<typename SourceType, typename Interpolator>
162 struct Simple {
163 typedef agg::span_image_filter_rgb_nn<SourceType, Interpolator> type;
164 };
165
166 template<typename SourceType, typename Interpolator>
167 struct AntiAlias {
168 typedef agg::span_image_filter_rgb_bilinear<SourceType, Interpolator>
169 type;
170 };
171 };
172
173 /// Nearest Neighbour filter type for quick, lower quality scaling.
174 template<typename P, typename W>
175 struct NN : public FilterType<P, W>
176 {
177 typedef FilterType<P, W> BaseType;
178 typedef typename P::template Simple<
179 typename BaseType::SourceType,
180 typename BaseType::Interpolator>::type Generator;
181 };
182
183 /// Bilinear filter type for higher quality scaling.
184 template<typename P, typename W>
185 struct AA : public FilterType<P, W>
186 {
187 typedef FilterType<P, W> BaseType;
188 typedef typename P::template AntiAlias<
189 typename BaseType::SourceType,
190 typename BaseType::Interpolator>::type Generator;
191 };
192
193 /// A reflecting adaptor for Gradients.
194 struct Reflect
195 {
196 template<typename T> struct Type {
197 typedef agg::gradient_reflect_adaptor<T> type;
198 };
199 };
200
201 /// A repeating adaptor for Gradients.
202 struct Repeat
203 {
204 template<typename T> struct Type {
205 typedef agg::gradient_repeat_adaptor<T> type;
206 };
207 };
208
209 /// A padding (default) adaptor for Gradients.
210 struct Pad
211 {
212 template<typename T> struct Type {
213 typedef T type;
214 };
215 };
216
217 /// The default RGB color interpolator
218 struct InterpolatorLinearRGB
219 {
220 template<typename Pixel> struct Type {
221 typedef agg::gradient_lut<linear_rgb_interpolator<Pixel>, 256> type;
222 };
223 };
224
225 /// The default RGB color interpolator
226 struct InterpolatorRGB
227 {
228 template<typename Pixel> struct Type {
229 typedef agg::gradient_lut<agg::color_interpolator<Pixel>, 256> type;
230 };
231 };
232
233 /// AGG gradient fill style. Don't use Gnash texture bitmaps as this is slower
234 /// and less accurate. Even worse, the bitmap fill would need to be tweaked
235 /// to have non-repeating gradients (first and last color stops continue
236 /// forever on each side). This class can be used for any kind of gradient, so
237 /// even focal gradients should be possible.
238 template <class Color, class Allocator, class Interpolator, class GradientType,
239 class Adaptor, class ColorInterpolator, class SpanGenerator>
240 class GradientStyle : public AggStyle
241 {
242 public:
243
244 GradientStyle(const GradientFill& fs, const SWFMatrix& mat,
245 SWFCxForm cx, int norm_size, GradientType gr = GradientType())
246 :
AggStyle(false)247 AggStyle(false),
248 m_cx(std::move(cx)),
249 m_tr(mat.a() / 65536.0, mat.b() / 65536.0, mat.c() / 65536.0,
250 mat.d() / 65536.0, mat.tx(), mat.ty()),
251 m_span_interpolator(m_tr),
252 m_gradient_adaptor(std::move(gr)),
253 m_sg(m_span_interpolator, m_gradient_adaptor, m_gradient_lut, 0,
254 norm_size),
255
256 m_need_premultiply(false)
257 {
258 // Build gradient lookup table
259 m_gradient_lut.remove_all();
260 const size_t size = fs.recordCount();
261
262 // It is essential that at least two colours are added; otherwise agg
263 // will use uninitialized values.
264 assert(size > 1);
265
266 for (size_t i = 0; i != size; ++i) {
267 const GradientRecord& gr = fs.record(i);
268 const rgba tr = m_cx.transform(gr.color);
269 if (tr.m_a < 0xff) m_need_premultiply = true;
270 m_gradient_lut.add_color(gr.ratio / 255.0,
271 agg::rgba8(tr.m_r, tr.m_g, tr.m_b, tr.m_a));
272 }
273 m_gradient_lut.build_lut();
274
275 } // GradientStyle constructor
276
~GradientStyle()277 virtual ~GradientStyle() { }
278
generate_span(Color * span,int x,int y,unsigned len)279 void generate_span(Color* span, int x, int y, unsigned len) {
280 m_sg.generate(span, x, y, len);
281 if (!m_need_premultiply) return;
282
283 while (len--) {
284 span->premultiply();
285 ++span;
286 }
287 }
288
289 protected:
290
291 // Color transform
292 SWFCxForm m_cx;
293
294 // Span allocator
295 Allocator m_sa;
296
297 // Transformer
298 agg::trans_affine m_tr;
299
300 // Span interpolator
301 Interpolator m_span_interpolator;
302
303 // Gradient adaptor
304 Adaptor m_gradient_adaptor;
305
306 // Gradient LUT
307 ColorInterpolator m_gradient_lut;
308
309 // Span generator
310 SpanGenerator m_sg;
311
312 // premultiplication necessary?
313 bool m_need_premultiply;
314 };
315
316 /// A set of typedefs for a Gradient
317 //
318 /// @tparam G An agg gradient type
319 /// @tparam A The type of Adaptor: see Reflect, Repeat, Pad
320 /// @tparam I The type of ColorInterpolator: see InterpolatorRGB
321 template<typename G, typename A, typename I>
322 struct Gradient
323 {
324 typedef agg::rgba8 Color;
325 typedef G GradientType;
326 typedef typename A::template Type<G>::type Adaptor;
327 typedef typename I::template Type<Color>::type ColorInterpolator;
328 typedef agg::span_allocator<Color> Allocator;
329 typedef agg::span_interpolator_linear<agg::trans_affine> Interpolator;
330 typedef agg::span_gradient<Color, Interpolator, Adaptor,
331 ColorInterpolator> Generator;
332 typedef GradientStyle<Color, Allocator, Interpolator, GradientType,
333 Adaptor, ColorInterpolator, Generator> Type;
334 };
335
336
337 /// Solid AGG fill style. generate_span is not used in this case as AGG does
338 /// solid fill styles internally.
339 class SolidStyle : public AggStyle
340 {
341 public:
342
SolidStyle(const agg::rgba8 & color)343 SolidStyle(const agg::rgba8& color)
344 :
345 AggStyle(true, color)
346 {
347 }
348
generate_span(agg::rgba8 *,int,int,unsigned)349 void generate_span(agg::rgba8* /*span*/, int /*x*/, int /*y*/,
350 unsigned /*len*/)
351 {
352 abort(); // never call generate_span for solid fill styles
353 }
354 };
355
356
357 /// AGG bitmap fill style. There are quite a few combinations possible and so
358 /// the class types are defined outside. The bitmap can be tiled or clipped.
359 /// It can have any transformation SWFMatrix and color transform. Any pixel format
360 /// can be used, too.
361 template <class PixelFormat, class Allocator, class SourceType,
362 class Interpolator, class Generator>
363 class BitmapStyle : public AggStyle
364 {
365 public:
366
BitmapStyle(int width,int height,int rowlen,std::uint8_t * data,const SWFMatrix & mat,SWFCxForm cx)367 BitmapStyle(int width, int height, int rowlen, std::uint8_t* data,
368 const SWFMatrix& mat, SWFCxForm cx)
369 :
370 AggStyle(false),
371 m_cx(std::move(cx)),
372 m_rbuf(data, width, height, rowlen),
373 m_pixf(m_rbuf),
374 m_img_src(m_pixf),
375 m_tr(mat.a() / 65535.0, mat.b() / 65535.0, mat.c() / 65535.0,
376 mat.d() / 65535.0, mat.tx(), mat.ty()),
377 m_interpolator(m_tr),
378 m_sg(m_img_src, m_interpolator)
379 {
380 }
381
~BitmapStyle()382 virtual ~BitmapStyle() {
383 }
384
generate_span(agg::rgba8 * span,int x,int y,unsigned len)385 void generate_span(agg::rgba8* span, int x, int y, unsigned len)
386 {
387 m_sg.generate(span, x, y, len);
388
389 const bool transform = (m_cx != SWFCxForm());
390
391 for (size_t i = 0; i < len; ++i) {
392 // We must always do this because dynamic bitmaps (BitmapData)
393 // can have any values. Loaded bitmaps are handled when loaded.
394 span->r = std::min(span->r, span->a);
395 span->g = std::min(span->g, span->a);
396 span->b = std::min(span->b, span->a);
397 if (transform) {
398 m_cx.transform(span->r, span->g, span->b, span->a);
399 span->premultiply();
400 }
401 ++span;
402 }
403 }
404
405 private:
406
407 // Color transform
408 SWFCxForm m_cx;
409
410 // Pixel access
411 agg::rendering_buffer m_rbuf;
412 PixelFormat m_pixf;
413
414 // Span allocator
415 Allocator m_sa;
416
417 // Image accessor
418 SourceType m_img_src;
419
420 // Transformer
421 agg::trans_affine m_tr;
422
423 // Interpolator
424 Interpolator m_interpolator;
425
426 // Span generator
427 Generator m_sg;
428 };
429
430 }
431
432
433 // --- AGG HELPER CLASSES ------------------------------------------------------
434
435 /// Style handler for AGG's compound rasterizer. This is the class which is
436 /// called by AGG itself. It provides an interface to the various fill style
437 /// classes defined above.
438 class StyleHandler
439 {
440 public:
441
StyleHandler()442 StyleHandler() :
443 m_transparent(0, 0, 0, 0)
444 {}
445
~StyleHandler()446 ~StyleHandler() {
447 }
448
449 /// Called by AGG to ask if a certain style is a solid color
is_solid(unsigned style)450 bool is_solid(unsigned style) const {
451 assert(style < _styles.size());
452 return _styles[style].solid();
453 }
454
455 /// Adds a new solid fill color style
add_color(const agg::rgba8 & color)456 void add_color(const agg::rgba8& color) {
457 SolidStyle *st = new SolidStyle(color);
458 _styles.push_back(st);
459 }
460
461 /// Adds a new bitmap fill style
add_bitmap(const agg_bitmap_info * bi,const SWFMatrix & mat,const SWFCxForm & cx,bool repeat,bool smooth)462 void add_bitmap(const agg_bitmap_info* bi, const SWFMatrix& mat,
463 const SWFCxForm& cx, bool repeat, bool smooth) {
464
465 assert(bi);
466
467 // Tiled
468 if (repeat) {
469 storeBitmap<Tile>(*this, bi, mat, cx, smooth);
470 return;
471 }
472
473 storeBitmap<Clip>(*this, bi, mat, cx, smooth);
474 }
475
476 template<typename T>
addLinearGradient(const GradientFill & fs,const SWFMatrix & mat,const SWFCxForm & cx)477 void addLinearGradient(const GradientFill& fs, const SWFMatrix& mat,
478 const SWFCxForm& cx)
479 {
480 // NOTE: The value 256 is based on the bitmap texture used by other
481 // Gnash renderers which is normally 256x1 pixels for linear gradients.
482 typename T::Type* st = new typename T::Type(fs, mat, cx, 256);
483 _styles.push_back(st);
484 }
485
486 template<typename T>
addFocalGradient(const GradientFill & fs,const SWFMatrix & mat,const SWFCxForm & cx)487 void addFocalGradient(const GradientFill& fs, const SWFMatrix& mat,
488 const SWFCxForm& cx)
489 {
490 typename T::GradientType gr;
491 gr.init(32.0, fs.focalPoint() * 32.0, 0.0);
492
493 // div 2 because we need radius, not diameter
494 typename T::Type* st = new typename T::Type(fs, mat, cx, 32.0, gr);
495
496 // NOTE: The value 64 is based on the bitmap texture used by other
497 // Gnash renderers which is normally 64x64 pixels for radial gradients.
498 _styles.push_back(st);
499 }
500
501 template<typename T>
addRadialGradient(const GradientFill & fs,const SWFMatrix & mat,const SWFCxForm & cx)502 void addRadialGradient(const GradientFill& fs, const SWFMatrix& mat,
503 const SWFCxForm& cx)
504 {
505
506 // div 2 because we need radius, not diameter
507 typename T::Type* st = new typename T::Type(fs, mat, cx, 64 / 2);
508
509 // NOTE: The value 64 is based on the bitmap texture used by other
510 // Gnash renderers which is normally 64x64 pixels for radial gradients.
511 _styles.push_back(st);
512 }
513
514 /// Returns the color of a certain fill style (solid)
color(unsigned style)515 agg::rgba8 color(unsigned style) const
516 {
517 if (style < _styles.size())
518 return _styles[style].color();
519
520 return m_transparent;
521 }
522
523 /// Called by AGG to generate a scanline span for non-solid fills
generate_span(agg::rgba8 * span,int x,int y,unsigned len,unsigned style)524 void generate_span(agg::rgba8* span, int x, int y,
525 unsigned len, unsigned style)
526 {
527 _styles[style].generate_span(span,x,y,len);
528 }
529
530
531 /// Add a bitmap with the specified filter
532 //
533 /// @tparam Filter The FilterType to use. This affects scaling
534 /// quality, pixel type etc.
535 template<typename Filter> void
addBitmap(const agg_bitmap_info * bi,const SWFMatrix & mat,const SWFCxForm & cx)536 addBitmap(const agg_bitmap_info* bi, const SWFMatrix& mat,
537 const SWFCxForm& cx)
538 {
539 typedef typename Filter::PixelFormat PixelFormat;
540 typedef typename Filter::Generator Generator;
541 typedef typename Filter::Allocator Allocator;
542 typedef typename Filter::SourceType SourceType;
543 typedef typename Filter::Interpolator Interpolator;
544
545 typedef BitmapStyle<PixelFormat, Allocator,
546 SourceType, Interpolator, Generator> Style;
547
548 Style* st = new Style(bi->get_width(), bi->get_height(),
549 bi->get_rowlen(), bi->get_data(), mat, cx);
550
551 _styles.push_back(st);
552 }
553
554 boost::ptr_vector<AggStyle> _styles;
555 agg::rgba8 m_transparent;
556
557 };
558
559 class agg_mask_style_handler
560 {
561 public:
562
agg_mask_style_handler()563 agg_mask_style_handler() :
564 m_color(255,255)
565 {
566 }
567
is_solid(unsigned)568 bool is_solid(unsigned /*style*/) const
569 {
570 return true;
571 }
572
color(unsigned)573 const agg::gray8& color(unsigned /*style*/) const
574 {
575 return m_color;
576 }
577
generate_span(agg::gray8 *,int,int,int,unsigned)578 void generate_span(agg::gray8* /*span*/, int /*x*/, int /*y*/,
579 int /*len*/, unsigned /*style*/)
580 {
581 abort(); // never call generate_span for solid fill styles
582 }
583
584 private:
585 agg::gray8 m_color;
586
587 }; // class agg_mask_style_handler
588
589 /// Style handler
590 //
591 /// Transfer FillStyles to agg styles.
592 struct AddStyles : boost::static_visitor<>
593 {
AddStylesAddStyles594 AddStyles(SWFMatrix stage, SWFMatrix fill, const SWFCxForm& c,
595 StyleHandler& sh, Quality q)
596 :
597 _stageMatrix(stage.invert()),
598 _fillMatrix(fill.invert()),
599 _cx(c),
600 _sh(sh),
601 _quality(q)
602 {
603 }
604
operatorAddStyles605 void operator()(const GradientFill& f) const {
606 SWFMatrix m = f.matrix();
607 m.concatenate(_fillMatrix);
608 m.concatenate(_stageMatrix);
609 storeGradient(_sh, f, m, _cx);
610 }
611
operatorAddStyles612 void operator()(const SolidFill& f) const {
613 const rgba color = _cx.transform(f.color());
614
615 // add the color to our self-made style handler (basically
616 // just a list)
617 _sh.add_color(agg::rgba8_pre(color.m_r, color.m_g, color.m_b,
618 color.m_a));
619 }
620
operatorAddStyles621 void operator()(const BitmapFill& f) const {
622 SWFMatrix m = f.matrix();
623 m.concatenate(_fillMatrix);
624 m.concatenate(_stageMatrix);
625
626 // Smoothing policy:
627 //
628 // - If unspecified, smooth when _quality >= BEST
629 // - If ON or forced, smooth when _quality > LOW
630 // - If OFF, don't smooth
631 //
632 // TODO: take a forceBitmapSmoothing parameter.
633 // which should be computed by the VM looking
634 // at MovieClip.forceSmoothing.
635 bool smooth = false;
636 if (_quality > QUALITY_LOW) {
637 // TODO: if forceSmoothing is true, smooth !
638 switch (f.smoothingPolicy()) {
639 case BitmapFill::SMOOTHING_UNSPECIFIED:
640 if (_quality >= QUALITY_BEST) smooth = true;
641 break;
642 case BitmapFill::SMOOTHING_ON:
643 smooth = true;
644 break;
645 default: break;
646 }
647 }
648
649 const bool tiled = (f.type() == BitmapFill::TILED);
650
651 const CachedBitmap* bm = f.bitmap();
652
653 if (!bm) {
654 // See misc-swfmill.all/missing_bitmap.swf
655 _sh.add_color(agg::rgba8_pre(255,0,0,255));
656 }
657 else if ( bm->disposed() ) {
658 // See misc-ming.all/BeginBitmapFill.swf
659 _sh.add_color(agg::rgba8_pre(0,0,0,0));
660 }
661 else {
662 _sh.add_bitmap(dynamic_cast<const agg_bitmap_info*>(bm),
663 m, _cx, tiled, smooth);
664 }
665 }
666
667 private:
668
669 /// The inverted stage matrix.
670 const SWFMatrix _stageMatrix;
671
672 /// The inverted fill matrix.
673 const SWFMatrix _fillMatrix;
674 const SWFCxForm& _cx;
675 StyleHandler& _sh;
676 const Quality _quality;
677 };
678
679 namespace {
680
681 template<typename FillMode, typename Pixel>
682 void
storeBitmap(StyleHandler & st,const agg_bitmap_info * bi,const SWFMatrix & mat,const SWFCxForm & cx,bool smooth)683 storeBitmap(StyleHandler& st, const agg_bitmap_info* bi,
684 const SWFMatrix& mat, const SWFCxForm& cx, bool smooth)
685 {
686 if (smooth) {
687 st.addBitmap<AA<Pixel, FillMode> >(bi, mat, cx);
688 return;
689 }
690 st.addBitmap<NN<Pixel, FillMode> >(bi, mat, cx);
691 }
692
693 template<typename FillMode>
694 void
storeBitmap(StyleHandler & st,const agg_bitmap_info * bi,const SWFMatrix & mat,const SWFCxForm & cx,bool smooth)695 storeBitmap(StyleHandler& st, const agg_bitmap_info* bi,
696 const SWFMatrix& mat, const SWFCxForm& cx, bool smooth)
697 {
698
699 if (bi->get_bpp() == 24) {
700 storeBitmap<FillMode, RGB>(st, bi, mat, cx, smooth);
701 return;
702 }
703 storeBitmap<FillMode, RGBA>(st, bi, mat, cx, smooth);
704 }
705
706 template<typename Spread, typename Interpolation>
707 void
storeGradient(StyleHandler & st,const GradientFill & fs,const SWFMatrix & mat,const SWFCxForm & cx)708 storeGradient(StyleHandler& st, const GradientFill& fs, const SWFMatrix& mat,
709 const SWFCxForm& cx)
710 {
711
712 typedef agg::gradient_x Linear;
713 typedef agg::gradient_radial Radial;
714 typedef agg::gradient_radial_focus Focal;
715
716 typedef Gradient<Linear, Spread, Interpolation> LinearGradient;
717 typedef Gradient<Focal, Spread, Interpolation> FocalGradient;
718 typedef Gradient<Radial, Spread, Interpolation> RadialGradient;
719
720 switch (fs.type()) {
721 case GradientFill::LINEAR:
722 st.addLinearGradient<LinearGradient>(fs, mat, cx);
723 return;
724
725 case GradientFill::RADIAL:
726 if (fs.focalPoint()) {
727 st.addFocalGradient<FocalGradient>(fs, mat, cx);
728 return;
729 }
730 st.addRadialGradient<RadialGradient>(fs, mat, cx);
731 }
732 }
733
734 template<typename Spread>
735 void
storeGradient(StyleHandler & st,const GradientFill & fs,const SWFMatrix & mat,const SWFCxForm & cx)736 storeGradient(StyleHandler& st, const GradientFill& fs, const SWFMatrix& mat,
737 const SWFCxForm& cx)
738 {
739 switch (fs.interpolation) {
740 case SWF::GRADIENT_INTERPOLATION_NORMAL:
741 storeGradient<Spread, InterpolatorRGB>(st, fs, mat, cx);
742 break;
743 case SWF::GRADIENT_INTERPOLATION_LINEAR:
744 storeGradient<Spread, InterpolatorLinearRGB>(st, fs, mat, cx);
745 break;
746 }
747
748 }
749
750 void
storeGradient(StyleHandler & st,const GradientFill & fs,const SWFMatrix & mat,const SWFCxForm & cx)751 storeGradient(StyleHandler& st, const GradientFill& fs, const SWFMatrix& mat,
752 const SWFCxForm& cx)
753 {
754
755 switch (fs.spreadMode) {
756 case GradientFill::PAD:
757 storeGradient<Pad>(st, fs, mat, cx);
758 break;
759 case GradientFill::REFLECT:
760 storeGradient<Reflect>(st, fs, mat, cx);
761 break;
762 case GradientFill::REPEAT:
763 storeGradient<Repeat>(st, fs, mat, cx);
764 break;
765 }
766 }
767
768 }
769
770 } // namespace gnash
771
772 #endif // BACKEND_RENDER_HANDLER_AGG_STYLE_H
773