3 * (c) 2010 Alexander Warg <warg@os.inf.tu-dresden.de>
4 * economic rights: Technische Universität Dresden (Germany)
6 * This file is part of TUD:OS and distributed under the terms of the
7 * GNU General Public License 2.
8 * Please see the COPYING-GPL-2 file for details.
12 #include <l4/scout-gfx/icon>
13 #include <l4/mag-gfx/canvas>
17 namespace Scout_gfx { namespace Pt {
19 template <typename PT>
20 class Icon : public Scout_gfx::Icon
26 typedef typename PT::Pixel Pixel;
34 mutable Icon_data const *_n;
36 static Icon_data const *_f;
39 static Icon_data const *find(void const *src_id)
41 Icon_data const *x = _f;
44 if (x->_src_id == src_id)
53 int ref_cnt() const { return _ref_cnt; }
54 int put() const { return --_ref_cnt; }
55 void get() const { ++_ref_cnt; }
56 void const *src_id() const { return _src_id; }
59 Icon_data(void const *src_id, Area const &size)
60 : _src_id(src_id), _n(_f)
62 unsigned long s = size.pixels() * (sizeof(Pixel) + 1);
63 // printf("create icon data %p for %p (%lu bytes)\n", this, src_id, s);
64 unsigned char *b = (unsigned char*)malloc(s);
68 _p = reinterpret_cast<Pixel*>(b);
69 _a = b + size.pixels() * sizeof(Pixel);
77 // printf("release icon data: %p for %p\n", this, _src_id);
78 Icon_data const **x = &_f;
91 Pixel const *pixel() const { return _p; }
92 Pixel *pixel() { return _p; }
94 unsigned char const *alpha() const { return _a; }
95 unsigned char *alpha() { return _a; }
98 typedef typename PT::Pixel Pixel;
110 void set_geometry(Rect const &s)
113 _size = _s.max(s.area());
117 * Define new icon pixels from rgba buffer
119 * \param vshift vertical shift of pixels
120 * \param shadow shadow divisor, low value -> dark shadow
121 * special case zero -> no shadow
123 * The buffer must contains W*H pixels. Each pixels consists
124 * of four bytes, red, green, blue, and alpha.
126 void rgba(void const *src, Area const &size, int vshift = 0, int shadow = 4);
129 * Define icon to be a glow of an rgba image
131 * \param src source rgba image to extract the glow's shape from
132 * \param c glow color
134 void glow(unsigned char const *src, Area const &size, Mag_gfx::Rgba32::Color c);
140 void draw(Canvas *c, Point const &p);
141 Widget *find(Point const &);
149 template <typename PT>
150 Icon<PT>::Icon() : _d(0)
154 template <typename PT>
156 Icon<PT>::rgba(void const *_src, Area const &size, int vshift, int shadow)
158 using Mag_gfx::Rgba32;
159 using Mag_gfx::color_conv;
161 typedef typename PT::Pixel Pixel;
162 typedef typename PT::Color Color;
164 if (_d && _d->put() == 0)
165 delete const_cast<Icon_data*>(_d);
167 _size = size.max(_size);
169 char const *id = (char const *)_src + vshift * 10 + shadow;
170 // printf("icon from rgba[%dx%d]: %p %d %d -> %p\n", size.w(), size.h(), _src, vshift, shadow, id);
172 if (Icon_data const *d = Icon_data::find(id))
179 Icon_data *n = new Icon_data(id, size);
180 Pixel *_pixel = n->pixel();
181 unsigned char *_alpha = n->alpha();
186 Rgba32::Pixel const *src = reinterpret_cast<Rgba32::Pixel const *>(_src);
187 src += _s.w() * vshift;
188 /* convert rgba values to pixel type and alpha channel */
189 for (int j = (_s.h() - vshift) * _s.w();
191 --j, ++src, ++_alpha, ++_pixel)
193 Rgba32::Color s = *src;
194 *_pixel = color_conv<Color>(s);
201 /* handle special case of no shadow */
205 _pixel = n->pixel() + 3 * _s.w();
206 _alpha = n->alpha() + 3 * _s.w();
207 /* generate shadow shape from blurred alpha channel */
208 /* apply shadow to pixels */
209 Color shcol(0, 0, 0);
210 src = reinterpret_cast<Rgba32::Pixel const *>(_src);
211 for (int j = 0; j < _s.h() - 5; j++, src+=3, _pixel += 3, _alpha += 3)
212 for (int i = 0; i < _s.w() - 3; i++)
215 for (int k = 0; k < 3; k++)
216 for (int l = 0; l < 3; l++)
217 v += Rgba32::Color(src[(k * _s.w()) + l]).a();
221 *_pixel = PT::mix(shcol, *_pixel, *_alpha);
222 *_alpha = std::min(255, *_alpha + v);
232 blur(unsigned char *src, unsigned char *dst, int w, int h)
234 const int kernel = 3;
235 int scale = (kernel*2 + 1)*(kernel*2 + 1);
237 scale = (scale*210)>>8;
238 for (int j = kernel; j < h - kernel; j++)
239 for (int i = kernel; i < w - kernel; i++)
242 for (int k = -kernel; k <= kernel; k++)
243 for (int l = -kernel; l <= kernel; l++)
244 v += src[w*(j + k) + (i + l)];
246 dst[w*j + i] = std::min(v/scale, 255);
251 * Copy pixel with alpha
253 template <typename PT>
256 transfer_pixel(PT const *src, int src_a, int alpha, PT *dst)
260 int register a = (src_a * alpha)>>8;
261 if (a) *dst = PT::Traits::mix(*dst, *src, a);
267 * An Icon has the following layout:
269 * P1---+--------+----+
270 * | cs | hs | cs | top row
271 * +----P2-------+----+
273 * | vs | | vs | mid row
275 * +----+--------P3---+
276 * | cs | hs | cs | low row
277 * +------------------P4
279 * cs ... corner slice
280 * hs ... horizontal slice
281 * vs ... vertical slice
288 template <typename PT>
291 draw_cslice(PT const *src, unsigned char const *src_a,
292 int src_pitch, int alpha,
293 char *dst, int dst_pitch, int w, int h)
295 for (int j = 0; j < h; j++)
299 unsigned char const *sa = src_a;
300 PT *d = reinterpret_cast<PT*>(dst);
302 for (int i = 0; i < w; i++, s++, sa++, d++)
303 transfer_pixel(s, *sa, alpha, d);
313 * Draw horizontal slice
315 template <typename PT>
318 draw_hslice(PT const *src, unsigned char const *src_a,
319 int src_pitch, int alpha,
320 char *dst, int dst_pitch, int w, int h)
322 for (int j = 0; j < h; j++)
326 PT *d = reinterpret_cast<PT*>(dst);
328 for (int i = 0; i < w; i++, d++)
329 transfer_pixel(s, sa, alpha, d);
339 for (int j = 0; j < h; j++) {
345 for (int i = 0; i < w; i++, d++)
346 transfer_pixel(s, sa, alpha, d);
348 src += src_pitch, src_a += src_pitch, dst += dst_pitch;
350 * Draw vertical slice
352 template <typename PT>
355 draw_vslice(PT const *src, unsigned char const *src_a,
357 char *dst, int dst_pitch, int w, int h)
359 for (int i = 0; i < w; i++)
366 for (int j = 0; j < h; j++, d += dst_pitch)
367 transfer_pixel(s, sa, alpha, reinterpret_cast<PT*>(d));
379 template <typename PT>
382 draw_center(PT const *src, unsigned char const *src_a,
384 char *dst, int dst_pitch, int w, int h)
389 for (int j = 0; j < h; j++, dst += dst_pitch)
392 PT *d = reinterpret_cast<PT*>(dst);
394 for (int i = 0; i < w; i++, d++)
395 transfer_pixel(s, sa, alpha, d);
401 * Clip rectangle against clipping region
403 * The out parameters are the resulting x/y offsets and the
404 * visible width and height.
406 * \return 1 if rectangle intersects with clipping region,
411 clip(int px1, int py1, int px2, int py2,
413 int *out_x, int *out_y, int *out_w, int *out_h)
415 /* determine intersection of rectangle and clipping region */
416 int x1 = std::max(px1, c.x1());
417 int y1 = std::max(py1, c.y1());
418 int x2 = std::min(px2, c.x2());
419 int y2 = std::min(py2, c.y2());
421 *out_w = x2 - x1 + 1;
422 *out_h = y2 - y1 + 1;
426 return (*out_w > 0) && (*out_h > 0);
429 } // end of internal stuff
431 template <typename PT>
433 Icon<PT>::glow(unsigned char const *_src, Area const &size,
434 Mag_gfx::Rgba32::Color c)
436 using Mag_gfx::Rgba32;
437 using Mag_gfx::color_conv;
439 typedef typename PT::Color MColor;
441 if (_d && _d->put() == 0)
442 delete const_cast<Icon_data*>(_d);
444 char const *id = (char const *)_src -10;
446 if (Icon_data const *d = Icon_data::find(id))
453 Icon_data *n = new Icon_data(id, size);
454 Pixel *_pixel = n->pixel();
455 unsigned char *_alpha = n->alpha();
460 Rgba32::Pixel const *src = reinterpret_cast<Rgba32::Pixel const*>(_src);
461 /* extract shape from alpha channel of rgba source image */
462 for (int j = 0; j < _s.pixels(); j++, ++src)
463 *(_alpha++) = Rgba32::Color(*src).a();
465 unsigned char *_b = (unsigned char *)malloc(_s.pixels());
467 for (int i = 0; i < 2; i++)
469 blur(_alpha, _b, _s.w(), _s.h());
470 blur(_b, _alpha, _s.w(), _s.h());
475 /* assign pixels and alpha */
476 MColor s = color_conv<MColor>(c);
477 for (int j = 0; j < _s.pixels(); j++)
482 template <typename PT>
484 Icon<PT>::draw(Canvas *c, Point const &p)
486 typedef typename PT::Pixel Pixel;
487 typedef typename PT::Color Color;
492 Pixel const *const _pixel = _d->pixel();
493 unsigned char const *const _alpha = _d->alpha();
495 char *addr = (char *)c->buffer();
497 if (!addr || (_icon_alpha == 0))
500 Rect const cl = c->clip();
501 int const bpl = c->bytes_per_line();
503 /* determine point positions */
505 Point const p4 = p1 + Point(_size.w(), _size.h());
506 Point const p2 = p1 + Point(_s.w() / 2, _s.h() / 2);
507 Point const p3 = p2.max(p4 - Point(_s.w() / 2, _s.h() / 2));
511 const int tx4 = _s.w();
512 const int ty4 = _s.h();
513 const int tx2 = _s.w()/2;
514 const int ty2 = _s.h()/2;
515 const int tx3 = std::max(tx4 - _s.w()/2, tx2);
516 const int ty3 = std::max(ty4 - _s.h()/2, ty2);
518 Pixel const *src = _pixel + _s.w()*ty1;
519 unsigned char const *src_a = _alpha + _s.w()*ty1;
526 if (clip(p1.x(), p1.y(), p2.x() - 1, p2.y() - 1, cl, &dx, &dy, &w, &h))
527 draw_cslice(src + tx1 + dy*_s.w() + dx, src_a + tx1 + dy*_s.w() + dx, _s.w(), _icon_alpha,
528 addr + (p1.y() + dy)*bpl + (p1.x() + dx) * sizeof(Pixel), bpl, w, h);
530 if (clip(p2.x(), p1.y(), p3.x() - 1, p2.y() - 1, cl, &dx, &dy, &w, &h))
531 draw_hslice(src + tx2 + dy*_s.w(), src_a + tx2 + dy*_s.w(), _s.w(), _icon_alpha,
532 addr + (p1.y() + dy)*bpl + (p2.x() + dx) * sizeof(Pixel), bpl, w, h);
534 if (clip(p3.x(), p1.y(), p4.x() - 1, p2.y() - 1, cl, &dx, &dy, &w, &h))
535 draw_cslice(src + tx3 + dy*_s.w() + dx, src_a + tx3 + dy*_s.w() + dx, _s.w(), _icon_alpha,
536 addr + (p1.y() + dy)*bpl + (p3.x() + dx) * sizeof(Pixel), bpl, w, h);
542 src = _pixel + _s.w()*ty2;
543 src_a = _alpha + _s.w()*ty2;
545 if (clip(p1.x(), p2.y(), p2.x() - 1, p3.y() - 1, cl, &dx, &dy, &w, &h))
546 draw_vslice(src + tx1 + dx, src_a + tx1 + dx, _s.w(), _icon_alpha,
547 addr + (p2.y() + dy)*bpl + (p1.x() + dx) * sizeof(Pixel), bpl, w, h);
549 if (clip(p2.x(), p2.y(), p3.x() - 1, p3.y() - 1, cl, &dx, &dy, &w, &h))
550 draw_center(src + tx2, src_a + tx2, _s.w(), _icon_alpha,
551 addr + (p2.y() + dy)*bpl + (p2.x() + dx) * sizeof(Pixel), bpl, w, h);
553 if (clip(p3.x(), p2.y(), p4.x() - 1, p3.y() - 1, cl, &dx, &dy, &w, &h))
554 draw_vslice(src + tx3 + dx, src_a + tx3 + dx, _s.w(), _icon_alpha,
555 addr + (p2.y() + dy)*bpl + (p3.x() + dx) * sizeof(Pixel), bpl, w, h);
561 src = _pixel + _s.w()*ty3;
562 src_a = _alpha + _s.w()*ty3;
564 if (clip(p1.x(), p3.y(), p2.x() - 1, p4.y() - 1, cl, &dx, &dy, &w, &h))
565 draw_cslice(src + tx1 + dy*_s.w() + dx, src_a + tx1 + dy*_s.w() + dx, _s.w(), _icon_alpha,
566 addr + (p3.y() + dy)*bpl + (p1.x() + dx) * sizeof(Pixel), bpl, w, h);
568 if (clip(p2.x(), p3.y(), p3.x() - 1, p4.y() - 1, cl, &dx, &dy, &w, &h))
569 draw_hslice(src + tx2 + dy*_s.w(), src_a + tx2 + dy*_s.w(), _s.w(), _icon_alpha,
570 addr + (p3.y() + dy)*bpl + (p2.x() + dx) * sizeof(Pixel), bpl, w, h);
572 if (clip(p3.x(), p3.y(), p4.x() - 1, p4.y() - 1, cl, &dx, &dy, &w, &h))
573 draw_cslice(src + tx3 + dy*_s.w() + dx, src_a + tx3 + dy*_s.w() + dx, _s.w(), _icon_alpha,
574 addr + (p3.y() + dy)*bpl + (p3.x() + dx) * sizeof(Pixel), bpl, w, h);
578 template <typename PT>
580 Icon<PT>::find(Point const &p)
582 if (!Widget::find(p) || !_d)
585 unsigned char const *_alpha = _d->alpha();
588 // FIXME: also support horizontally scaled icons
589 /* check icon boundaries (the height is flexible) */
590 if (!Rect(_size).contains(n))
594 if (n.x() <= _s.w() / 2)
596 else if (n.x() > _size.w() - _s.w() / 2)
597 x = n.x() - _size.w() + _s.w();
602 if (n.y() <= _s.h() / 2)
604 else if (n.y() > _size.h() - _s.h() / 2)
605 y = n.y() - _size.h() + _s.h();
609 return _alpha[y * _s.w() + x] ? this : 0;
612 template <typename PT>
613 typename Icon<PT>::Icon_data const *Icon<PT>::Icon_data::_f;