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 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* 48 skin_surface_ref( SkinSurface* surface ) 49 { 50 if (surface) 51 surface->refcount += 1; 52 return surface; 53 } 54 55 extern void 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 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* 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* 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* 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* 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* 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* 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 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 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 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 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 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 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 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 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 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 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 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 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 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