1 // FillStyle.cpp:  Graphical region filling styles, for Gnash.
2 //
3 //   Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012
4 //   Free Software Foundation, Inc.
5 //
6 // This program is free software; you can redistribute it and/or modify
7 // it under the terms of the GNU General Public License as published by
8 // the Free Software Foundation; either version 3 of the License, or
9 // (at your option) any later version.
10 //
11 // This program is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 //
16 // You should have received a copy of the GNU General Public License
17 // along with this program; if not, write to the Free Software
18 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
19 //
20 
21 #include "FillStyle.h"
22 
23 #include <ostream>
24 #include <boost/variant.hpp>
25 
26 #include "CachedBitmap.h"
27 #include "movie_definition.h"
28 #include "SWF.h"
29 #include "GnashNumeric.h"
30 #include "RunResources.h"
31 #include "GnashImage.h"
32 
33 namespace gnash {
34 
35 namespace {
36 
37 /// Create a lerped version of two other FillStyles.
38 //
39 /// The two fill styles must have exactly the same types. Callers are
40 /// responsible for ensuring this.
41 class SetLerp : public boost::static_visitor<>
42 {
43 public:
SetLerp(const FillStyle::Fill & a,const FillStyle::Fill & b,double ratio)44     SetLerp(const FillStyle::Fill& a, const FillStyle::Fill& b, double ratio)
45         :
46         _a(a),
47         _b(b),
48         _ratio(ratio)
49     {
50     }
51 
operator ()(T & f) const52     template<typename T> void operator()(T& f) const {
53         const T& a = boost::get<T>(_a);
54         const T& b = boost::get<T>(_b);
55         f.setLerp(a, b, _ratio);
56     }
57 
58 private:
59     const FillStyle::Fill& _a;
60     const FillStyle::Fill& _b;
61     const double _ratio;
62 
63 };
64 
65 }
66 
67 SWFMatrix
gradientMatrix(GradientFill::Type t,const SWFMatrix & m)68 gradientMatrix(GradientFill::Type t, const SWFMatrix& m)
69 {
70     SWFMatrix base;
71     switch (t) {
72         case GradientFill::LINEAR:
73             base.set_translation(128, 0);
74             base.set_scale(1.0 / 128, 1.0 / 128);
75             break;
76         case GradientFill::RADIAL:
77             base.set_scale(1.0 / 512, 1.0 / 512);
78             break;
79     }
80     base.concatenate(m);
81     return base;
82 }
83 
GradientFill(Type t,const SWFMatrix & m,const GradientRecords & recs)84 GradientFill::GradientFill(Type t, const SWFMatrix& m,
85         const GradientRecords& recs)
86     :
87     spreadMode(PAD),
88     interpolation(RGB),
89     _focalPoint(0.0),
90     _gradients(recs),
91     _type(t),
92     _matrix(gradientMatrix(t, m))
93 {
94     assert(recs.empty() || recs.size() > 1);
95 }
96 
97 void
setFocalPoint(double d)98 GradientFill::setFocalPoint(double d)
99 {
100     _focalPoint = clamp<float>(d, -1, 1);
101 }
102 
BitmapFill(Type t,const CachedBitmap * bi,SWFMatrix m,SmoothingPolicy pol)103 BitmapFill::BitmapFill(Type t, const CachedBitmap* bi, SWFMatrix m,
104         SmoothingPolicy pol)
105     :
106     _type(t),
107     _smoothingPolicy(pol),
108     _matrix(std::move(m)),
109     _bitmapInfo(bi),
110     _md(nullptr),
111     _id(0)
112 {
113 }
114 
BitmapFill(SWF::FillType t,movie_definition * md,std::uint16_t id,SWFMatrix m)115 BitmapFill::BitmapFill(SWF::FillType t, movie_definition* md,
116         std::uint16_t id, SWFMatrix m)
117     :
118     _type(),
119     _smoothingPolicy(),
120     _matrix(std::move(m)),
121     _bitmapInfo(nullptr),
122     _md(md),
123     _id(id)
124 {
125     assert(md);
126 
127     _smoothingPolicy = md->get_version() >= 8 ?
128         BitmapFill::SMOOTHING_ON : BitmapFill::SMOOTHING_UNSPECIFIED;
129 
130     switch (t) {
131         case SWF::FILL_TILED_BITMAP_HARD:
132             _type = BitmapFill::TILED;
133             _smoothingPolicy = BitmapFill::SMOOTHING_OFF;
134             break;
135 
136         case SWF::FILL_TILED_BITMAP:
137             _type = BitmapFill::TILED;
138             break;
139 
140         case SWF::FILL_CLIPPED_BITMAP_HARD:
141             _type = BitmapFill::CLIPPED;
142             _smoothingPolicy = BitmapFill::SMOOTHING_OFF;
143             break;
144 
145         case SWF::FILL_CLIPPED_BITMAP:
146             _type = BitmapFill::CLIPPED;
147             break;
148 
149         default:
150             std::abort();
151     }
152 }
153 
BitmapFill(const BitmapFill & other)154 BitmapFill::BitmapFill(const BitmapFill& other)
155     :
156     _type(other._type),
157     _smoothingPolicy(other._smoothingPolicy),
158     _matrix(other._matrix),
159     _bitmapInfo(other._bitmapInfo),
160     _md(other._md),
161     _id(other._id)
162 {
163 }
164 
~BitmapFill()165 BitmapFill::~BitmapFill()
166 {
167 }
168 
169 BitmapFill&
operator =(const BitmapFill & other)170 BitmapFill::operator=(const BitmapFill& other)
171 {
172     _type = other._type;
173     _smoothingPolicy = other._smoothingPolicy;
174     _matrix = other._matrix;
175     _bitmapInfo = other._bitmapInfo;
176     _md = other._md;
177     _id = other._id;
178     return *this;
179 }
180 
181 const CachedBitmap*
bitmap() const182 BitmapFill::bitmap() const
183 {
184     if (_bitmapInfo) {
185         return  _bitmapInfo.get();
186     }
187     if (!_md) {
188         return nullptr;
189     }
190     _bitmapInfo = _md->getBitmap(_id);
191 
192     // May still be 0!
193     return _bitmapInfo.get();
194 }
195 
196 void
setLerp(const GradientFill & a,const GradientFill & b,double ratio)197 GradientFill::setLerp(const GradientFill& a, const GradientFill& b,
198         double ratio)
199 {
200     assert(type() == a.type());
201     assert(_gradients.size() == a.recordCount());
202     assert(_gradients.size() == b.recordCount());
203 
204     for (size_t i = 0, e = _gradients.size(); i < e; ++i) {
205         const GradientRecord& ra = a.record(i);
206         const GradientRecord& rb = b.record(i);
207         _gradients[i].ratio = frnd(lerp<float>(ra.ratio, rb.ratio, ratio));
208         _gradients[i].color = lerp(ra.color, rb.color, ratio);
209     }
210     _matrix.set_lerp(a.matrix(), b.matrix(), ratio);
211 }
212 
213 void
setLerp(const BitmapFill & a,const BitmapFill & b,double ratio)214 BitmapFill::setLerp(const BitmapFill& a, const BitmapFill& b, double ratio)
215 {
216     _matrix.set_lerp(a.matrix(), b.matrix(), ratio);
217 }
218 
219 // Sets this style to a blend of a and b.  t = [0,1]
220 void
setLerp(FillStyle & f,const FillStyle & a,const FillStyle & b,double t)221 setLerp(FillStyle& f, const FillStyle& a, const FillStyle& b, double t)
222 {
223     assert(t >= 0 && t <= 1);
224     f.fill = a.fill;
225     boost::apply_visitor(SetLerp(a.fill, b.fill, t), f.fill);
226 }
227 
228 std::ostream&
operator <<(std::ostream & os,const BitmapFill::SmoothingPolicy & p)229 operator<<(std::ostream& os, const BitmapFill::SmoothingPolicy& p)
230 {
231     switch (p) {
232         case BitmapFill::SMOOTHING_UNSPECIFIED:
233             os << "unspecified";
234             break;
235         case BitmapFill::SMOOTHING_ON:
236             os << "on";
237             break;
238         case BitmapFill::SMOOTHING_OFF:
239             os << "off";
240             break;
241         default:
242             // cast to int required to avoid infinite recursion
243             os << "unknown " << +p;
244             break;
245     }
246     return os;
247 }
248 
249 std::ostream&
operator <<(std::ostream & o,GradientFill::Type t)250 operator<<(std::ostream& o, GradientFill::Type t)
251 {
252     switch (t) {
253         case GradientFill::LINEAR:
254             return o << "linear";
255         default:
256         case GradientFill::RADIAL:
257             return o << "radial";
258     }
259 }
260 
261 std::ostream&
operator <<(std::ostream & o,GradientFill::SpreadMode t)262 operator<<(std::ostream& o, GradientFill::SpreadMode t)
263 {
264     switch (t) {
265         case GradientFill::PAD:
266             return o << "pad";
267         case GradientFill::REPEAT:
268             return o << "repeat";
269         default:
270         case GradientFill::REFLECT:
271             return o << "reflect";
272     }
273 }
274 
275 std::ostream&
operator <<(std::ostream & o,GradientFill::InterpolationMode t)276 operator<<(std::ostream& o, GradientFill::InterpolationMode t)
277 {
278     switch (t) {
279         case GradientFill::RGB:
280             return o << "rgb";
281         default:
282         case GradientFill::LINEAR_RGB:
283             return o << "linear rgb";
284     }
285 }
286 
287 struct FillStyleOutput : boost::static_visitor<>
288 {
FillStyleOutputgnash::FillStyleOutput289     FillStyleOutput(std::ostream& o) : _os(o) {}
operator ()gnash::FillStyleOutput290     void operator()(const BitmapFill& bf) {
291         _os << boost::format("Bitmap fill: type %1%, smoothing %2%, "
292                 "matrix %3%") % bf.type() % bf.smoothingPolicy() % bf.matrix();
293     }
operator ()gnash::FillStyleOutput294     void operator()(const GradientFill& gf) {
295         _os << boost::format("Gradient fill: type %1%, spread mode %2%, "
296             "interpolation mode %3%, gradient count %4%, matrix %5%")
297             % gf.type() % gf.spreadMode % gf.interpolation %
298             gf.recordCount() % gf.matrix();
299     }
operator ()gnash::FillStyleOutput300     void operator()(const SolidFill& sf) {
301         _os << boost::format("Solid Fill: color %1%") % sf.color();
302     }
303 private:
304     std::ostream& _os;
305 };
306 
307 std::ostream&
operator <<(std::ostream & os,const FillStyle & fs)308 operator<<(std::ostream& os, const FillStyle& fs)
309 {
310     FillStyleOutput out(os);
311     boost::apply_visitor(out, fs.fill);
312     return os;
313 }
314 
315 } // namespace gnash
316 
317 
318 // Local Variables:
319 // mode: C++
320 // End:
321