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