Gnash  0.8.11dev
Renderer_agg_style.h
Go to the documentation of this file.
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 #include <agg_gradient_lut.h>
29 #include <agg_color_rgba.h>
30 #include <agg_color_gray.h>
31 #include <agg_image_accessors.h>
32 #include <agg_span_allocator.h>
33 #include <agg_span_gradient.h>
34 #include <agg_span_interpolator_linear.h>
35 #include <agg_image_filters.h>
36 #include <agg_span_image_filter_rgb.h>
37 #include <agg_span_image_filter_rgba.h>
38 #include <agg_pixfmt_rgb.h>
39 #include <agg_pixfmt_rgba.h>
40 #include <iostream>
41 
42 #include "LinearRGB.h"
43 #include "Renderer_agg_bitmap.h"
44 #include "GnashAlgorithm.h"
45 #include "FillStyle.h"
46 #include "SWFCxForm.h"
47 #include "SWFMatrix.h"
48 
49 namespace gnash {
50 
51 class StyleHandler;
52 
53 // Forward declarations.
54 namespace {
55 
57  template<typename FillMode, typename Pixel>
58  void storeBitmap(StyleHandler& st, const agg_bitmap_info* bi,
59  const SWFMatrix& mat, const SWFCxForm& cx,
60  bool smooth);
61  template<typename FillMode> void storeBitmap(StyleHandler& st,
62  const agg_bitmap_info* bi, const SWFMatrix& mat, const SWFCxForm& cx,
63  bool smooth);
64 
66  void storeGradient(StyleHandler& st, const GradientFill& fs,
67  const SWFMatrix& mat, const SWFCxForm& cx);
68  template<typename Spread> void storeGradient(StyleHandler& st,
69  const GradientFill& fs, const SWFMatrix& mat, const SWFCxForm& cx);
70  template<typename Spread, typename Interpolation>
71  void storeGradient(StyleHandler& st, const GradientFill& fs,
72  const SWFMatrix& mat, const SWFCxForm& cx);
73 }
74 
79 class AggStyle
80 {
81 public:
82  AggStyle(bool solid, const agg::rgba8& color = agg::rgba8(0,0,0,0))
83  :
84  _solid(solid),
85  _color(color)
86  {
87  }
88 
89  // Everytime a class has a virtual method it should
90  // also have a virtual destructor. This will ensure
91  // that the destructor for the *derived* class is invoked
92  // when deleting a pointer to base class !!
93  virtual ~AggStyle() {}
94  bool solid() const { return _solid; }
95  agg::rgba8 color() const { return _color; }
96 
97  // for non-solid styles:
98  virtual void generate_span(agg::rgba8* span, int x, int y,
99  unsigned len) = 0;
100 
101 private:
102  // for solid styles:
103  const bool _solid;
104  const agg::rgba8 _color;
105 };
106 
107 namespace {
108 
110 struct Tile
111 {
112  template<typename P> struct Type {
113  typedef agg::wrap_mode_repeat Wrap;
114  typedef agg::image_accessor_wrap<P, Wrap, Wrap> type;
115  };
116 };
117 
119 struct Clip
120 {
121  template<typename P> struct Type {
122  typedef agg::image_accessor_clone<P> type;
123  };
124 };
125 
127 template<typename P, typename W>
128 struct FilterType
129 {
130  typedef typename P::PixelFormat PixelFormat;
131  typedef typename W::template Type<PixelFormat>::type SourceType;
132  typedef agg::span_allocator<PixelFormat> Allocator;
133  typedef agg::span_interpolator_linear<agg::trans_affine>
134  Interpolator;
135 };
136 
138 struct RGBA
139 {
140  typedef agg::pixfmt_rgba32_pre PixelFormat;
141 
142  template<typename SourceType, typename Interpolator>
143  struct Simple {
144  typedef agg::span_image_filter_rgba_nn<SourceType, Interpolator> type;
145  };
146 
147  template<typename SourceType, typename Interpolator>
148  struct AntiAlias {
149  typedef agg::span_image_filter_rgba_bilinear<SourceType, Interpolator>
150  type;
151  };
152 };
153 
155 struct RGB
156 {
157  typedef agg::pixfmt_rgb24_pre PixelFormat;
158 
159  template<typename SourceType, typename Interpolator>
160  struct Simple {
161  typedef agg::span_image_filter_rgb_nn<SourceType, Interpolator> type;
162  };
163 
164  template<typename SourceType, typename Interpolator>
165  struct AntiAlias {
166  typedef agg::span_image_filter_rgb_bilinear<SourceType, Interpolator>
167  type;
168  };
169 };
170 
172 template<typename P, typename W>
173 struct NN : public FilterType<P, W>
174 {
175  typedef FilterType<P, W> BaseType;
176  typedef typename P::template Simple<
177  typename BaseType::SourceType,
178  typename BaseType::Interpolator>::type Generator;
179 };
180 
182 template<typename P, typename W>
183 struct AA : public FilterType<P, W>
184 {
185  typedef FilterType<P, W> BaseType;
186  typedef typename P::template AntiAlias<
187  typename BaseType::SourceType,
188  typename BaseType::Interpolator>::type Generator;
189 };
190 
192 struct Reflect
193 {
194  template<typename T> struct Type {
195  typedef agg::gradient_reflect_adaptor<T> type;
196  };
197 };
198 
200 struct Repeat
201 {
202  template<typename T> struct Type {
203  typedef agg::gradient_repeat_adaptor<T> type;
204  };
205 };
206 
208 struct Pad
209 {
210  template<typename T> struct Type {
211  typedef T type;
212  };
213 };
214 
216 struct InterpolatorLinearRGB
217 {
218  template<typename Pixel> struct Type {
219  typedef agg::gradient_lut<linear_rgb_interpolator<Pixel>, 256> type;
220  };
221 };
222 
224 struct InterpolatorRGB
225 {
226  template<typename Pixel> struct Type {
227  typedef agg::gradient_lut<agg::color_interpolator<Pixel>, 256> type;
228  };
229 };
230 
236 template <class Color, class Allocator, class Interpolator, class GradientType,
237  class Adaptor, class ColorInterpolator, class SpanGenerator>
238 class GradientStyle : public AggStyle
239 {
240 public:
241 
242  GradientStyle(const GradientFill& fs, const SWFMatrix& mat,
243  const SWFCxForm& cx, int norm_size, GradientType gr = GradientType())
244  :
245  AggStyle(false),
246  m_cx(cx),
247  m_tr(mat.a() / 65536.0, mat.b() / 65536.0, mat.c() / 65536.0,
248  mat.d() / 65536.0, mat.tx(), mat.ty()),
250  m_gradient_adaptor(gr),
252  norm_size),
253 
254  m_need_premultiply(false)
255  {
256  // Build gradient lookup table
257  m_gradient_lut.remove_all();
258  const size_t size = fs.recordCount();
259 
260  // It is essential that at least two colours are added; otherwise agg
261  // will use uninitialized values.
262  assert(size > 1);
263 
264  for (size_t i = 0; i != size; ++i) {
265  const GradientRecord& gr = fs.record(i);
266  const rgba tr = m_cx.transform(gr.color);
267  if (tr.m_a < 0xff) m_need_premultiply = true;
268  m_gradient_lut.add_color(gr.ratio / 255.0,
269  agg::rgba8(tr.m_r, tr.m_g, tr.m_b, tr.m_a));
270  }
271  m_gradient_lut.build_lut();
272 
273  } // GradientStyle constructor
274 
275  virtual ~GradientStyle() { }
276 
277  void generate_span(Color* span, int x, int y, unsigned len) {
278  m_sg.generate(span, x, y, len);
279  if (!m_need_premultiply) return;
280 
281  while (len--) {
282  span->premultiply();
283  ++span;
284  }
285  }
286 
287 protected:
288 
289  // Color transform
290  SWFCxForm m_cx;
291 
292  // Span allocator
293  Allocator m_sa;
294 
295  // Transformer
296  agg::trans_affine m_tr;
297 
298  // Span interpolator
299  Interpolator m_span_interpolator;
300 
301  // Gradient adaptor
303 
304  // Gradient LUT
305  ColorInterpolator m_gradient_lut;
306 
307  // Span generator
308  SpanGenerator m_sg;
309 
310  // premultiplication necessary?
312 };
313 
315 //
319 template<typename G, typename A, typename I>
320 struct Gradient
321 {
322  typedef agg::rgba8 Color;
323  typedef G GradientType;
324  typedef typename A::template Type<G>::type Adaptor;
325  typedef typename I::template Type<Color>::type ColorInterpolator;
326  typedef agg::span_allocator<Color> Allocator;
327  typedef agg::span_interpolator_linear<agg::trans_affine> Interpolator;
328  typedef agg::span_gradient<Color, Interpolator, Adaptor,
329  ColorInterpolator> Generator;
330  typedef GradientStyle<Color, Allocator, Interpolator, GradientType,
331  Adaptor, ColorInterpolator, Generator> Type;
332 };
333 
334 
337 class SolidStyle : public AggStyle
338 {
339 public:
340 
341  SolidStyle(const agg::rgba8& color)
342  :
343  AggStyle(true, color)
344  {
345  }
346 
347  void generate_span(agg::rgba8* /*span*/, int /*x*/, int /*y*/,
348  unsigned /*len*/)
349  {
350  abort(); // never call generate_span for solid fill styles
351  }
352 };
353 
354 
359 template <class PixelFormat, class Allocator, class SourceType,
360  class Interpolator, class Generator>
361 class BitmapStyle : public AggStyle
362 {
363 public:
364 
365  BitmapStyle(int width, int height, int rowlen, boost::uint8_t* data,
366  const SWFMatrix& mat, const SWFCxForm& cx)
367  :
368  AggStyle(false),
369  m_cx(cx),
370  m_rbuf(data, width, height, rowlen),
371  m_pixf(m_rbuf),
372  m_img_src(m_pixf),
373  m_tr(mat.a() / 65535.0, mat.b() / 65535.0, mat.c() / 65535.0,
374  mat.d() / 65535.0, mat.tx(), mat.ty()),
377  {
378  }
379 
380  virtual ~BitmapStyle() {
381  }
382 
383  void generate_span(agg::rgba8* span, int x, int y, unsigned len)
384  {
385  m_sg.generate(span, x, y, len);
386 
387  const bool transform = (m_cx != SWFCxForm());
388 
389  for (size_t i = 0; i < len; ++i) {
390  // We must always do this because dynamic bitmaps (BitmapData)
391  // can have any values. Loaded bitmaps are handled when loaded.
392  span->r = std::min(span->r, span->a);
393  span->g = std::min(span->g, span->a);
394  span->b = std::min(span->b, span->a);
395  if (transform) {
396  m_cx.transform(span->r, span->g, span->b, span->a);
397  span->premultiply();
398  }
399  ++span;
400  }
401  }
402 
403 private:
404 
405  // Color transform
406  SWFCxForm m_cx;
407 
408  // Pixel access
409  agg::rendering_buffer m_rbuf;
410  PixelFormat m_pixf;
411 
412  // Span allocator
413  Allocator m_sa;
414 
415  // Image accessor
416  SourceType m_img_src;
417 
418  // Transformer
419  agg::trans_affine m_tr;
420 
421  // Interpolator
422  Interpolator m_interpolator;
423 
424  // Span generator
425  Generator m_sg;
426 };
427 
428 }
429 
430 
431 // --- AGG HELPER CLASSES ------------------------------------------------------
432 
437 {
438 public:
439 
441  m_transparent(0, 0, 0, 0)
442  {}
443 
445  }
446 
448  bool is_solid(unsigned style) const {
449  assert(style < _styles.size());
450  return _styles[style].solid();
451  }
452 
454  void add_color(const agg::rgba8& color) {
455  SolidStyle *st = new SolidStyle(color);
456  _styles.push_back(st);
457  }
458 
460  void add_bitmap(const agg_bitmap_info* bi, const SWFMatrix& mat,
461  const SWFCxForm& cx, bool repeat, bool smooth) {
462 
463  assert(bi);
464 
465  // Tiled
466  if (repeat) {
467  storeBitmap<Tile>(*this, bi, mat, cx, smooth);
468  return;
469  }
470 
471  storeBitmap<Clip>(*this, bi, mat, cx, smooth);
472  }
473 
474  template<typename T>
475  void addLinearGradient(const GradientFill& fs, const SWFMatrix& mat,
476  const SWFCxForm& cx)
477  {
478  // NOTE: The value 256 is based on the bitmap texture used by other
479  // Gnash renderers which is normally 256x1 pixels for linear gradients.
480  typename T::Type* st = new typename T::Type(fs, mat, cx, 256);
481  _styles.push_back(st);
482  }
483 
484  template<typename T>
485  void addFocalGradient(const GradientFill& fs, const SWFMatrix& mat,
486  const SWFCxForm& cx)
487  {
488  typename T::GradientType gr;
489  gr.init(32.0, fs.focalPoint() * 32.0, 0.0);
490 
491  // div 2 because we need radius, not diameter
492  typename T::Type* st = new typename T::Type(fs, mat, cx, 32.0, gr);
493 
494  // NOTE: The value 64 is based on the bitmap texture used by other
495  // Gnash renderers which is normally 64x64 pixels for radial gradients.
496  _styles.push_back(st);
497  }
498 
499  template<typename T>
500  void addRadialGradient(const GradientFill& fs, const SWFMatrix& mat,
501  const SWFCxForm& cx)
502  {
503 
504  // div 2 because we need radius, not diameter
505  typename T::Type* st = new typename T::Type(fs, mat, cx, 64 / 2);
506 
507  // NOTE: The value 64 is based on the bitmap texture used by other
508  // Gnash renderers which is normally 64x64 pixels for radial gradients.
509  _styles.push_back(st);
510  }
511 
513  agg::rgba8 color(unsigned style) const
514  {
515  if (style < _styles.size())
516  return _styles[style].color();
517 
518  return m_transparent;
519  }
520 
522  void generate_span(agg::rgba8* span, int x, int y,
523  unsigned len, unsigned style)
524  {
525  _styles[style].generate_span(span,x,y,len);
526  }
527 
528 
530  //
533  template<typename Filter> void
534  addBitmap(const agg_bitmap_info* bi, const SWFMatrix& mat,
535  const SWFCxForm& cx)
536  {
537  typedef typename Filter::PixelFormat PixelFormat;
538  typedef typename Filter::Generator Generator;
539  typedef typename Filter::Allocator Allocator;
540  typedef typename Filter::SourceType SourceType;
541  typedef typename Filter::Interpolator Interpolator;
542 
543  typedef BitmapStyle<PixelFormat, Allocator,
544  SourceType, Interpolator, Generator> Style;
545 
546  Style* st = new Style(bi->get_width(), bi->get_height(),
547  bi->get_rowlen(), bi->get_data(), mat, cx);
548 
549  _styles.push_back(st);
550  }
551 
552  boost::ptr_vector<AggStyle> _styles;
553  agg::rgba8 m_transparent;
554 
555 };
556 
558 {
559 public:
560 
562  m_color(255,255)
563  {
564  }
565 
566  bool is_solid(unsigned /*style*/) const
567  {
568  return true;
569  }
570 
571  const agg::gray8& color(unsigned /*style*/) const
572  {
573  return m_color;
574  }
575 
576  void generate_span(agg::gray8* /*span*/, int /*x*/, int /*y*/,
577  int /*len*/, unsigned /*style*/)
578  {
579  abort(); // never call generate_span for solid fill styles
580  }
581 
582 private:
583  agg::gray8 m_color;
584 
585 }; // class agg_mask_style_handler
586 
588 //
590 struct AddStyles : boost::static_visitor<>
591 {
593  StyleHandler& sh, Quality q)
594  :
595  _stageMatrix(stage.invert()),
596  _fillMatrix(fill.invert()),
597  _cx(c),
598  _sh(sh),
599  _quality(q)
600  {
601  }
602 
603  void operator()(const GradientFill& f) const {
604  SWFMatrix m = f.matrix();
605  m.concatenate(_fillMatrix);
606  m.concatenate(_stageMatrix);
607  storeGradient(_sh, f, m, _cx);
608  }
609 
610  void operator()(const SolidFill& f) const {
611  const rgba color = _cx.transform(f.color());
612 
613  // add the color to our self-made style handler (basically
614  // just a list)
615  _sh.add_color(agg::rgba8_pre(color.m_r, color.m_g, color.m_b,
616  color.m_a));
617  }
618 
619  void operator()(const BitmapFill& f) const {
620  SWFMatrix m = f.matrix();
621  m.concatenate(_fillMatrix);
622  m.concatenate(_stageMatrix);
623 
624  // Smoothing policy:
625  //
626  // - If unspecified, smooth when _quality >= BEST
627  // - If ON or forced, smooth when _quality > LOW
628  // - If OFF, don't smooth
629  //
630  // TODO: take a forceBitmapSmoothing parameter.
631  // which should be computed by the VM looking
632  // at MovieClip.forceSmoothing.
633  bool smooth = false;
634  if (_quality > QUALITY_LOW) {
635  // TODO: if forceSmoothing is true, smooth !
636  switch (f.smoothingPolicy()) {
638  if (_quality >= QUALITY_BEST) smooth = true;
639  break;
641  smooth = true;
642  break;
643  default: break;
644  }
645  }
646 
647  const bool tiled = (f.type() == BitmapFill::TILED);
648 
649  const CachedBitmap* bm = f.bitmap();
650 
651  if (!bm) {
652  // See misc-swfmill.all/missing_bitmap.swf
653  _sh.add_color(agg::rgba8_pre(255,0,0,255));
654  }
655  else if ( bm->disposed() ) {
656  // See misc-ming.all/BeginBitmapFill.swf
657  _sh.add_color(agg::rgba8_pre(0,0,0,0));
658  }
659  else {
660  _sh.add_bitmap(dynamic_cast<const agg_bitmap_info*>(bm),
661  m, _cx, tiled, smooth);
662  }
663  }
664 
665 private:
666 
668  const SWFMatrix _stageMatrix;
669 
671  const SWFMatrix _fillMatrix;
672  const SWFCxForm& _cx;
673  StyleHandler& _sh;
674  const Quality _quality;
675 };
676 
677 namespace {
678 
679 template<typename FillMode, typename Pixel>
680 void
681 storeBitmap(StyleHandler& st, const agg_bitmap_info* bi,
682  const SWFMatrix& mat, const SWFCxForm& cx, bool smooth)
683 {
684  if (smooth) {
685  st.addBitmap<AA<Pixel, FillMode> >(bi, mat, cx);
686  return;
687  }
688  st.addBitmap<NN<Pixel, FillMode> >(bi, mat, cx);
689 }
690 
691 template<typename FillMode>
692 void
693 storeBitmap(StyleHandler& st, const agg_bitmap_info* bi,
694  const SWFMatrix& mat, const SWFCxForm& cx, bool smooth)
695 {
696 
697  if (bi->get_bpp() == 24) {
698  storeBitmap<FillMode, RGB>(st, bi, mat, cx, smooth);
699  return;
700  }
701  storeBitmap<FillMode, RGBA>(st, bi, mat, cx, smooth);
702 }
703 
704 template<typename Spread, typename Interpolation>
705 void
706 storeGradient(StyleHandler& st, const GradientFill& fs, const SWFMatrix& mat,
707  const SWFCxForm& cx)
708 {
709 
710  typedef agg::gradient_x Linear;
711  typedef agg::gradient_radial Radial;
712  typedef agg::gradient_radial_focus Focal;
713 
714  typedef Gradient<Linear, Spread, Interpolation> LinearGradient;
715  typedef Gradient<Focal, Spread, Interpolation> FocalGradient;
716  typedef Gradient<Radial, Spread, Interpolation> RadialGradient;
717 
718  switch (fs.type()) {
720  st.addLinearGradient<LinearGradient>(fs, mat, cx);
721  return;
722 
724  if (fs.focalPoint()) {
725  st.addFocalGradient<FocalGradient>(fs, mat, cx);
726  return;
727  }
728  st.addRadialGradient<RadialGradient>(fs, mat, cx);
729  }
730 }
731 
732 template<typename Spread>
733 void
734 storeGradient(StyleHandler& st, const GradientFill& fs, const SWFMatrix& mat,
735  const SWFCxForm& cx)
736 {
737  switch (fs.interpolation) {
739  storeGradient<Spread, InterpolatorRGB>(st, fs, mat, cx);
740  break;
742  storeGradient<Spread, InterpolatorLinearRGB>(st, fs, mat, cx);
743  break;
744  }
745 
746 }
747 
748 void
749 storeGradient(StyleHandler& st, const GradientFill& fs, const SWFMatrix& mat,
750  const SWFCxForm& cx)
751 {
752 
753  switch (fs.spreadMode) {
754  case GradientFill::PAD:
755  storeGradient<Pad>(st, fs, mat, cx);
756  break;
758  storeGradient<Reflect>(st, fs, mat, cx);
759  break;
761  storeGradient<Repeat>(st, fs, mat, cx);
762  break;
763  }
764 }
765 
766 }
767 
768 } // namespace gnash
769 
770 #endif // BACKEND_RENDER_HANDLER_AGG_STYLE_H