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