• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* Copyright (C) 2007-2008 The Android Open Source Project
2 **
3 ** This software is licensed under the terms of the GNU General Public
4 ** License version 2, as published by the Free Software Foundation, and
5 ** may be copied, distributed, and modified under those terms.
6 **
7 ** This program is distributed in the hope that it will be useful,
8 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
9 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10 ** GNU General Public License for more details.
11 */
12 #include "android/skin/surface.h"
13 #include "android/skin/argb.h"
14 #include <SDL.h>
15 
16 #define  DEBUG  1
17 
18 #if DEBUG
19 #include "android/utils/debug.h"
20 #define  D(...)   VERBOSE_PRINT(surface,__VA_ARGS__)
21 #else
22 #define  D(...)   ((void)0)
23 #endif
24 
25 struct SkinSurface {
26     int                  refcount;
27     uint32_t*            pixels;
28     SDL_Surface*         surface;
29     SkinSurfaceDoneFunc  done_func;
30     void*                done_user;
31 };
32 
33 static void
skin_surface_free(SkinSurface * s)34 skin_surface_free( SkinSurface*  s )
35 {
36     if (s->done_func) {
37         s->done_func( s->done_user );
38         s->done_func = NULL;
39     }
40     if (s->surface) {
41         SDL_FreeSurface(s->surface);
42         s->surface = NULL;
43     }
44     free(s);
45 }
46 
47 extern SkinSurface*
skin_surface_ref(SkinSurface * surface)48 skin_surface_ref( SkinSurface*  surface )
49 {
50     if (surface)
51         surface->refcount += 1;
52     return surface;
53 }
54 
55 extern void
skin_surface_unrefp(SkinSurface ** psurface)56 skin_surface_unrefp( SkinSurface*  *psurface )
57 {
58     SkinSurface*  surf = *psurface;
59     if (surf) {
60         if (--surf->refcount <= 0)
61             skin_surface_free(surf);
62         *psurface = NULL;
63     }
64 }
65 
66 
67 void
skin_surface_set_done(SkinSurface * s,SkinSurfaceDoneFunc done_func,void * done_user)68 skin_surface_set_done( SkinSurface*  s, SkinSurfaceDoneFunc  done_func, void*  done_user )
69 {
70     s->done_func = done_func;
71     s->done_user = done_user;
72 }
73 
74 #if SDL_BYTEORDER == SDL_BIG_ENDIAN
75 #  define  ARGB32_R_MASK  0xff000000
76 #  define  ARGB32_G_MASK  0x00ff0000
77 #  define  ARGB32_B_MASK  0x0000ff00
78 #  define  ARGB32_A_MASK  0x000000ff
79 #else
80 #  define  ARGB32_R_MASK  0x000000ff
81 #  define  ARGB32_G_MASK  0x0000ff00
82 #  define  ARGB32_B_MASK  0x00ff0000
83 #  define  ARGB32_A_MASK  0xff000000
84 #endif
85 
86 static SDL_Surface*
_sdl_surface_create_rgb(int width,int height,int depth,int flags)87 _sdl_surface_create_rgb( int  width,
88                          int  height,
89                          int  depth,
90                          int  flags )
91 {
92    Uint32   rmask, gmask, bmask, amask;
93 
94     if (depth == 8) {
95         rmask = gmask = bmask = 0;
96         amask = 0xff;
97     } else if (depth == 32) {
98         rmask = ARGB32_R_MASK;
99         gmask = ARGB32_G_MASK;
100         bmask = ARGB32_B_MASK;
101         amask = ARGB32_A_MASK;
102     } else
103         return NULL;
104 
105     return SDL_CreateRGBSurface( flags, width, height, depth,
106                                  rmask, gmask, bmask, amask );
107 }
108 
109 
110 static SDL_Surface*
_sdl_surface_create_rgb_from(int width,int height,int pitch,void * pixels,int depth)111 _sdl_surface_create_rgb_from( int   width,
112                               int   height,
113                               int   pitch,
114                               void* pixels,
115                               int   depth )
116 {
117    Uint32   rmask, gmask, bmask, amask;
118 
119     if (depth == 8) {
120         rmask = gmask = bmask = 0;
121         amask = 0xff;
122     } else if (depth == 32) {
123         rmask = ARGB32_R_MASK;
124         gmask = ARGB32_G_MASK;
125         bmask = ARGB32_B_MASK;
126         amask = ARGB32_A_MASK;
127     } else
128         return NULL;
129 
130     return SDL_CreateRGBSurfaceFrom( pixels, width, height, pitch, depth,
131                                      rmask, gmask, bmask, amask );
132 }
133 
134 
135 static SkinSurface*
_skin_surface_create(SDL_Surface * surface,void * pixels)136 _skin_surface_create( SDL_Surface*  surface,
137                       void*         pixels )
138 {
139     SkinSurface*  s = malloc(sizeof(*s));
140     if (s != NULL) {
141         s->refcount = 1;
142         s->pixels   = pixels;
143         s->surface  = surface;
144         s->done_func = NULL;
145         s->done_user = NULL;
146     }
147     else {
148         SDL_FreeSurface(surface);
149         free(pixels);
150         D( "not enough memory to allocate new skin surface !" );
151     }
152     return  s;
153 }
154 
155 
156 SkinSurface*
skin_surface_create_fast(int w,int h)157 skin_surface_create_fast( int  w, int  h )
158 {
159     SDL_Surface*  surface;
160 
161     surface = _sdl_surface_create_rgb( w, h, 32, SDL_HWSURFACE );
162     if (surface == NULL) {
163         surface = _sdl_surface_create_rgb( w, h, 32, SDL_SWSURFACE );
164         if (surface == NULL) {
165             D( "could not create fast %dx%d ARGB32 surface: %s",
166                w, h, SDL_GetError() );
167             return NULL;
168         }
169     }
170     return _skin_surface_create( surface, NULL );
171 }
172 
173 
174 SkinSurface*
skin_surface_create_slow(int w,int h)175 skin_surface_create_slow( int  w, int  h )
176 {
177     SDL_Surface*  surface;
178 
179     surface = _sdl_surface_create_rgb( w, h, 32, SDL_SWSURFACE );
180     if (surface == NULL) {
181         D( "could not create slow %dx%d ARGB32 surface: %s",
182             w, h, SDL_GetError() );
183         return NULL;
184     }
185     return _skin_surface_create( surface, NULL );
186 }
187 
188 
189 SkinSurface*
skin_surface_create_argb32_from(int w,int h,int pitch,uint32_t * pixels,int do_copy)190 skin_surface_create_argb32_from(
191                         int                  w,
192                         int                  h,
193                         int                  pitch,
194                         uint32_t*            pixels,
195                         int                  do_copy )
196 {
197     SDL_Surface*  surface;
198     uint32_t*     pixcopy = NULL;
199 
200     if (do_copy) {
201         size_t  size = h*pitch;
202         pixcopy = malloc( size );
203         if (pixcopy == NULL && size > 0) {
204             D( "not enough memory to create %dx%d ARGB32 surface",
205                w, h );
206             return NULL;
207         }
208         memcpy( pixcopy, pixels, size );
209     }
210 
211     surface = _sdl_surface_create_rgb_from( w, h, pitch,
212                                             pixcopy ? pixcopy : pixels,
213                                             32 );
214     if (surface == NULL) {
215         D( "could not create %dx%d slow ARGB32 surface: %s",
216             w, h, SDL_GetError() );
217         return NULL;
218     }
219     return _skin_surface_create( surface, pixcopy );
220 }
221 
222 
223 
224 
225 extern int
skin_surface_lock(SkinSurface * s,SkinSurfacePixels * pix)226 skin_surface_lock( SkinSurface*  s, SkinSurfacePixels  *pix )
227 {
228     if (!s || !s->surface) {
229         D( "error: trying to lock stale surface %p", s );
230         return -1;
231     }
232     if ( SDL_LockSurface( s->surface ) != 0 ) {
233         D( "could not lock surface %p: %s", s, SDL_GetError() );
234         return -1;
235     }
236     pix->w      = s->surface->w;
237     pix->h      = s->surface->h;
238     pix->pitch  = s->surface->pitch;
239     pix->pixels = s->surface->pixels;
240     return 0;
241 }
242 
243 /* unlock a slow surface that was previously locked */
244 extern void
skin_surface_unlock(SkinSurface * s)245 skin_surface_unlock( SkinSurface*  s )
246 {
247     if (s && s->surface)
248         SDL_UnlockSurface( s->surface );
249 }
250 
251 
252 #if 0
253 static uint32_t
254 skin_surface_map_argb( SkinSurface*  s, uint32_t  c )
255 {
256     if (s && s->surface) {
257         return SDL_MapRGBA( s->surface->format,
258                             ((c) >> 16) & 255,
259                             ((c) >> 8) & 255,
260                             ((c) & 255),
261                             ((c) >> 24) & 255 );
262     }
263     return 0x00000000;
264 }
265 #endif
266 
267 typedef struct {
268     int   x;
269     int   y;
270     int   w;
271     int   h;
272     int   sx;
273     int   sy;
274 
275     uint8_t*      dst_line;
276     int           dst_pitch;
277     SDL_Surface*  dst_lock;
278 
279     uint8_t*      src_line;
280     int           src_pitch;
281     SDL_Surface*  src_lock;
282     uint32_t      src_color;
283 
284 } SkinBlit;
285 
286 
287 static int
skin_blit_init_fill(SkinBlit * blit,SkinSurface * dst,SkinRect * dst_rect,uint32_t color)288 skin_blit_init_fill( SkinBlit*     blit,
289                      SkinSurface*  dst,
290                      SkinRect*     dst_rect,
291                      uint32_t      color )
292 {
293     int  x = dst_rect->pos.x;
294     int  y = dst_rect->pos.y;
295     int  w = dst_rect->size.w;
296     int  h = dst_rect->size.h;
297     int  delta;
298 
299     if (x < 0) {
300         w += x;
301         x  = 0;
302     }
303     delta = (x + w) - dst->surface->w;
304     if (delta > 0)
305         w -= delta;
306 
307     if (y < 0) {
308         h += y;
309         y  = 0;
310     }
311     delta = (y + h) - dst->surface->h;
312     if (delta > 0)
313         h -= delta;
314 
315     if (w <= 0 || h <= 0)
316         return 0;
317 
318     blit->x = x;
319     blit->y = y;
320     blit->w = w;
321     blit->h = h;
322 
323     if ( !SDL_LockSurface(dst->surface) )
324         return 0;
325 
326     blit->dst_lock  = dst->surface;
327     blit->dst_pitch = dst->surface->pitch;
328     blit->dst_line  = dst->surface->pixels + y*blit->dst_pitch;
329 
330     blit->src_lock  = NULL;
331     blit->src_color = color;
332 
333     return 1;
334 }
335 
336 static int
skin_blit_init_blit(SkinBlit * blit,SkinSurface * dst,SkinPos * dst_pos,SkinSurface * src,SkinRect * src_rect)337 skin_blit_init_blit( SkinBlit*     blit,
338                      SkinSurface*  dst,
339                      SkinPos*      dst_pos,
340                      SkinSurface*  src,
341                      SkinRect*     src_rect )
342 {
343     int  x  = dst_pos->x;
344     int  y  = dst_pos->y;
345     int  sx = src_rect->pos.x;
346     int  sy = src_rect->pos.y;
347     int  w  = src_rect->size.w;
348     int  h  = src_rect->size.h;
349     int  delta;
350 
351     if (x < 0) {
352         w  += x;
353         sx -= x;
354         x   = 0;
355     }
356     if (sx < 0) {
357         w  += sx;
358         x  -= sx;
359         sx  = 0;
360     }
361 
362     delta = (x + w) - dst->surface->w;
363     if (delta > 0)
364         w -= delta;
365 
366     delta = (sx + w) - src->surface->w;
367     if (delta > 0)
368         w -= delta;
369 
370     if (y < 0) {
371         h  += y;
372         sy += y;
373         y   = 0;
374     }
375     if (sy < 0) {
376         h  += sy;
377         y  -= sy;
378         sy  = 0;
379     }
380     delta = (y + h) - dst->surface->h;
381     if (delta > 0)
382         h -= delta;
383 
384     delta = (sy + h) - src->surface->h;
385 
386     if (w <= 0 || h <= 0)
387         return 0;
388 
389     blit->x = x;
390     blit->y = y;
391     blit->w = w;
392     blit->h = h;
393 
394     blit->sx = sx;
395     blit->sy = sy;
396 
397     if ( !SDL_LockSurface(dst->surface) )
398         return 0;
399 
400     blit->dst_lock  = dst->surface;
401     blit->dst_pitch = dst->surface->pitch;
402     blit->dst_line  = (uint8_t*) dst->surface->pixels + y*blit->dst_pitch;
403 
404     if ( !SDL_LockSurface(src->surface) ) {
405         SDL_UnlockSurface(dst->surface);
406         return 0;
407     }
408 
409     blit->src_lock  = src->surface;
410     blit->src_pitch = src->surface->pitch;
411     blit->src_line  = (uint8_t*) src->surface->pixels + sy*blit->src_pitch;
412 
413     return 1;
414 }
415 
416 static void
skin_blit_done(SkinBlit * blit)417 skin_blit_done( SkinBlit*  blit )
418 {
419     if (blit->src_lock)
420         SDL_UnlockSurface( blit->src_lock );
421     if (blit->dst_lock)
422         SDL_UnlockSurface( blit->dst_lock );
423     ARGB_DONE;
424 }
425 
426 typedef void (*SkinLineFillFunc)( uint32_t*  dst, uint32_t  color, int  len );
427 typedef void (*SkinLineBlitFunc)( uint32_t*  dst, const uint32_t*  src,  int  len );
428 
429 static void
skin_line_fill_copy(uint32_t * dst,uint32_t color,int len)430 skin_line_fill_copy( uint32_t*  dst, uint32_t  color, int  len )
431 {
432     uint32_t*  end = dst + len;
433 
434     while (dst + 4 <= end) {
435         dst[0] = dst[1] = dst[2] = dst[3] = color;
436         dst   += 4;
437     }
438     while (dst < end) {
439         dst[0] = color;
440         dst   += 1;
441     }
442 }
443 
444 static void
skin_line_fill_srcover(uint32_t * dst,uint32_t color,int len)445 skin_line_fill_srcover( uint32_t*  dst, uint32_t  color, int  len )
446 {
447     uint32_t*  end = dst + len;
448     uint32_t   alpha = (color >> 24);
449 
450     if (alpha == 255)
451     {
452         skin_line_fill_copy(dst, color, len);
453     }
454     else
455     {
456         ARGB_DECL(src_c);
457         ARGB_DECL_ZERO();
458 
459         alpha  = 255 - alpha;
460         alpha += (alpha >> 7);
461 
462         ARGB_UNPACK(src_c,color);
463 
464         for ( ; dst < end; dst++ )
465         {
466             ARGB_DECL(dst_c);
467 
468             ARGB_READ(dst_c,dst);
469             ARGB_MULSHIFT(dst_c,dst_c,alpha,8);
470             ARGB_ADD(dst_c,src_c);
471             ARGB_WRITE(dst_c,dst);
472         }
473     }
474 }
475 
476 static void
skin_line_fill_dstover(uint32_t * dst,uint32_t color,int len)477 skin_line_fill_dstover( uint32_t*  dst, uint32_t  color, int  len )
478 {
479     uint32_t*  end = dst + len;
480     ARGB_DECL(src_c);
481     ARGB_DECL_ZERO();
482 
483     ARGB_UNPACK(src_c,color);
484 
485     for ( ; dst < end; dst++ )
486     {
487         ARGB_DECL(dst_c);
488         ARGB_DECL(val);
489 
490         uint32_t   alpha;
491 
492         ARGB_READ(dst_c,dst);
493         alpha = 256 - (dst[0] >> 24);
494         ARGB_MULSHIFT(val,src_c,alpha,8);
495         ARGB_ADD(val,dst_c);
496         ARGB_WRITE(val,dst);
497     }
498 }
499 
500 extern void
skin_surface_fill(SkinSurface * dst,SkinRect * rect,uint32_t argb_premul,SkinBlitOp blitop)501 skin_surface_fill( SkinSurface*  dst,
502                    SkinRect*     rect,
503                    uint32_t      argb_premul,
504                    SkinBlitOp    blitop )
505 {
506     SkinLineFillFunc  fill;
507     SkinBlit          blit[1];
508 
509     switch (blitop) {
510         case SKIN_BLIT_COPY:    fill = skin_line_fill_copy; break;
511         case SKIN_BLIT_SRCOVER: fill = skin_line_fill_srcover; break;
512         case SKIN_BLIT_DSTOVER: fill = skin_line_fill_dstover; break;
513         default: return;
514     }
515 
516     if ( skin_blit_init_fill( blit, dst, rect, argb_premul ) ) {
517         uint8_t*   line  = blit->dst_line;
518         int        pitch = blit->dst_pitch;
519         uint8_t*   end   = line + pitch*blit->h;
520 
521         for ( ; line != end; line += pitch )
522             fill( (uint32_t*)line + blit->x, argb_premul, blit->w );
523     }
524 }
525 
526 
527 static void
skin_line_blit_copy(uint32_t * dst,const uint32_t * src,int len)528 skin_line_blit_copy( uint32_t*  dst, const uint32_t*  src, int  len )
529 {
530     memcpy( (char*)dst, (const char*)src, len*4 );
531 }
532 
533 
534 
535 static void
skin_line_blit_srcover(uint32_t * dst,const uint32_t * src,int len)536 skin_line_blit_srcover( uint32_t*  dst, const uint32_t*  src, int  len )
537 {
538     uint32_t*  end = dst + len;
539     ARGB_DECL_ZERO();
540 
541     for ( ; dst < end; dst++ ) {
542         ARGB_DECL(s);
543         ARGB_DECL(d);
544         ARGB_DECL(v);
545         uint32_t  alpha;
546 
547         ARGB_READ(s,src);
548         alpha = (src[0] >> 24);
549         if (alpha > 0) {
550             ARGB_READ(d,dst);
551             alpha = 256 - alpha;
552             ARGB_MULSHIFT(v,d,alpha,8);
553             ARGB_ADD(v,d);
554             ARGB_WRITE(v,dst);
555         }
556     }
557 }
558 
559 static void
skin_line_blit_dstover(uint32_t * dst,const uint32_t * src,int len)560 skin_line_blit_dstover( uint32_t*  dst, const uint32_t*  src, int  len )
561 {
562     uint32_t*  end = dst + len;
563     ARGB_DECL_ZERO();
564 
565     for ( ; dst < end; dst++ ) {
566         ARGB_DECL(s);
567         ARGB_DECL(d);
568         ARGB_DECL(v);
569         uint32_t  alpha;
570 
571         ARGB_READ(d,dst);
572         alpha = (dst[0] >> 24);
573         if (alpha < 255) {
574             ARGB_READ(s,src);
575             alpha = 256 - alpha;
576             ARGB_MULSHIFT(v,s,alpha,8);
577             ARGB_ADD(v,s);
578             ARGB_WRITE(v,dst);
579         }
580     }
581 }
582 
583 
584 extern void
skin_surface_blit(SkinSurface * dst,SkinPos * dst_pos,SkinSurface * src,SkinRect * src_rect,SkinBlitOp blitop)585 skin_surface_blit( SkinSurface*  dst,
586                    SkinPos*      dst_pos,
587                    SkinSurface*  src,
588                    SkinRect*     src_rect,
589                    SkinBlitOp    blitop )
590 {
591     SkinLineBlitFunc  func;
592     SkinBlit          blit[1];
593 
594     switch (blitop) {
595         case SKIN_BLIT_COPY:    func = skin_line_blit_copy; break;
596         case SKIN_BLIT_SRCOVER: func = skin_line_blit_srcover; break;
597         case SKIN_BLIT_DSTOVER: func = skin_line_blit_dstover; break;
598         default: return;
599     }
600 
601     if ( skin_blit_init_blit( blit, dst, dst_pos, src, src_rect ) ) {
602         uint8_t*   line   = blit->dst_line;
603         uint8_t*   sline  = blit->src_line;
604         int        pitch  = blit->dst_pitch;
605         int        spitch = blit->src_pitch;
606         uint8_t*   end    = line + pitch*blit->h;
607 
608         for ( ; line != end; line += pitch, sline += spitch )
609             func( (uint32_t*)line + blit->x, (uint32_t*)sline + blit->sx, blit->w );
610 
611         skin_blit_done(blit);
612     }
613 }
614