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