sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_surface.c (39016B)


      1 /*
      2   Simple DirectMedia Layer
      3   Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
      4 
      5   This software is provided 'as-is', without any express or implied
      6   warranty.  In no event will the authors be held liable for any damages
      7   arising from the use of this software.
      8 
      9   Permission is granted to anyone to use this software for any purpose,
     10   including commercial applications, and to alter it and redistribute it
     11   freely, subject to the following restrictions:
     12 
     13   1. The origin of this software must not be misrepresented; you must not
     14      claim that you wrote the original software. If you use this software
     15      in a product, an acknowledgment in the product documentation would be
     16      appreciated but is not required.
     17   2. Altered source versions must be plainly marked as such, and must not be
     18      misrepresented as being the original software.
     19   3. This notice may not be removed or altered from any source distribution.
     20 */
     21 #include "../SDL_internal.h"
     22 
     23 #include "SDL_video.h"
     24 #include "SDL_sysvideo.h"
     25 #include "SDL_blit.h"
     26 #include "SDL_RLEaccel_c.h"
     27 #include "SDL_pixels_c.h"
     28 #include "SDL_yuv_c.h"
     29 
     30 
     31 /* Check to make sure we can safely check multiplication of surface w and pitch and it won't overflow size_t */
     32 SDL_COMPILE_TIME_ASSERT(surface_size_assumptions,
     33     sizeof(int) == sizeof(Sint32) && sizeof(size_t) >= sizeof(Sint32));
     34 
     35 /* Public routines */
     36 
     37 /*
     38  * Calculate the pad-aligned scanline width of a surface
     39  */
     40 static Sint64
     41 SDL_CalculatePitch(Uint32 format, int width)
     42 {
     43     Sint64 pitch;
     44 
     45     if (SDL_ISPIXELFORMAT_FOURCC(format) || SDL_BITSPERPIXEL(format) >= 8) {
     46         pitch = ((Sint64)width * SDL_BYTESPERPIXEL(format));
     47     } else {
     48         pitch = (((Sint64)width * SDL_BITSPERPIXEL(format)) + 7) / 8;
     49     }
     50     pitch = (pitch + 3) & ~3;   /* 4-byte aligning for speed */
     51     return pitch;
     52 }
     53 
     54 /*
     55  * Create an empty RGB surface of the appropriate depth using the given
     56  * enum SDL_PIXELFORMAT_* format
     57  */
     58 SDL_Surface *
     59 SDL_CreateRGBSurfaceWithFormat(Uint32 flags, int width, int height, int depth,
     60                                Uint32 format)
     61 {
     62     Sint64 pitch;
     63     SDL_Surface *surface;
     64 
     65     /* The flags are no longer used, make the compiler happy */
     66     (void)flags;
     67 
     68     pitch = SDL_CalculatePitch(format, width);
     69     if (pitch < 0 || pitch > SDL_MAX_SINT32) {
     70         /* Overflow... */
     71         SDL_OutOfMemory();
     72         return NULL;
     73     }
     74 
     75     /* Allocate the surface */
     76     surface = (SDL_Surface *) SDL_calloc(1, sizeof(*surface));
     77     if (surface == NULL) {
     78         SDL_OutOfMemory();
     79         return NULL;
     80     }
     81 
     82     surface->format = SDL_AllocFormat(format);
     83     if (!surface->format) {
     84         SDL_FreeSurface(surface);
     85         return NULL;
     86     }
     87     surface->w = width;
     88     surface->h = height;
     89     surface->pitch = (int)pitch;
     90     SDL_SetClipRect(surface, NULL);
     91 
     92     if (SDL_ISPIXELFORMAT_INDEXED(surface->format->format)) {
     93         SDL_Palette *palette =
     94             SDL_AllocPalette((1 << surface->format->BitsPerPixel));
     95         if (!palette) {
     96             SDL_FreeSurface(surface);
     97             return NULL;
     98         }
     99         if (palette->ncolors == 2) {
    100             /* Create a black and white bitmap palette */
    101             palette->colors[0].r = 0xFF;
    102             palette->colors[0].g = 0xFF;
    103             palette->colors[0].b = 0xFF;
    104             palette->colors[1].r = 0x00;
    105             palette->colors[1].g = 0x00;
    106             palette->colors[1].b = 0x00;
    107         }
    108         SDL_SetSurfacePalette(surface, palette);
    109         SDL_FreePalette(palette);
    110     }
    111 
    112     /* Get the pixels */
    113     if (surface->w && surface->h) {
    114         /* Assumptions checked in surface_size_assumptions assert above */
    115         Sint64 size = ((Sint64)surface->h * surface->pitch);
    116         if (size < 0 || size > SDL_MAX_SINT32) {
    117             /* Overflow... */
    118             SDL_FreeSurface(surface);
    119             SDL_OutOfMemory();
    120             return NULL;
    121         }
    122 
    123         surface->pixels = SDL_SIMDAlloc((size_t)size);
    124         if (!surface->pixels) {
    125             SDL_FreeSurface(surface);
    126             SDL_OutOfMemory();
    127             return NULL;
    128         }
    129         surface->flags |= SDL_SIMD_ALIGNED;
    130         /* This is important for bitmaps */
    131         SDL_memset(surface->pixels, 0, surface->h * surface->pitch);
    132     }
    133 
    134     /* Allocate an empty mapping */
    135     surface->map = SDL_AllocBlitMap();
    136     if (!surface->map) {
    137         SDL_FreeSurface(surface);
    138         return NULL;
    139     }
    140 
    141     /* By default surface with an alpha mask are set up for blending */
    142     if (surface->format->Amask) {
    143         SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
    144     }
    145 
    146     /* The surface is ready to go */
    147     surface->refcount = 1;
    148     return surface;
    149 }
    150 
    151 /*
    152  * Create an empty RGB surface of the appropriate depth
    153  */
    154 SDL_Surface *
    155 SDL_CreateRGBSurface(Uint32 flags,
    156                      int width, int height, int depth,
    157                      Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
    158 {
    159     Uint32 format;
    160 
    161     /* Get the pixel format */
    162     format = SDL_MasksToPixelFormatEnum(depth, Rmask, Gmask, Bmask, Amask);
    163     if (format == SDL_PIXELFORMAT_UNKNOWN) {
    164         SDL_SetError("Unknown pixel format");
    165         return NULL;
    166     }
    167 
    168     return SDL_CreateRGBSurfaceWithFormat(flags, width, height, depth, format);
    169 }
    170 
    171 /*
    172  * Create an RGB surface from an existing memory buffer
    173  */
    174 SDL_Surface *
    175 SDL_CreateRGBSurfaceFrom(void *pixels,
    176                          int width, int height, int depth, int pitch,
    177                          Uint32 Rmask, Uint32 Gmask, Uint32 Bmask,
    178                          Uint32 Amask)
    179 {
    180     SDL_Surface *surface;
    181 
    182     surface = SDL_CreateRGBSurface(0, 0, 0, depth, Rmask, Gmask, Bmask, Amask);
    183     if (surface != NULL) {
    184         surface->flags |= SDL_PREALLOC;
    185         surface->pixels = pixels;
    186         surface->w = width;
    187         surface->h = height;
    188         surface->pitch = pitch;
    189         SDL_SetClipRect(surface, NULL);
    190     }
    191     return surface;
    192 }
    193 
    194 /*
    195  * Create an RGB surface from an existing memory buffer using the given given
    196  * enum SDL_PIXELFORMAT_* format
    197  */
    198 SDL_Surface *
    199 SDL_CreateRGBSurfaceWithFormatFrom(void *pixels,
    200                          int width, int height, int depth, int pitch,
    201                          Uint32 format)
    202 {
    203     SDL_Surface *surface;
    204 
    205     surface = SDL_CreateRGBSurfaceWithFormat(0, 0, 0, depth, format);
    206     if (surface != NULL) {
    207         surface->flags |= SDL_PREALLOC;
    208         surface->pixels = pixels;
    209         surface->w = width;
    210         surface->h = height;
    211         surface->pitch = pitch;
    212         SDL_SetClipRect(surface, NULL);
    213     }
    214     return surface;
    215 }
    216 
    217 int
    218 SDL_SetSurfacePalette(SDL_Surface * surface, SDL_Palette * palette)
    219 {
    220     if (!surface) {
    221         return SDL_SetError("SDL_SetSurfacePalette() passed a NULL surface");
    222     }
    223     if (SDL_SetPixelFormatPalette(surface->format, palette) < 0) {
    224         return -1;
    225     }
    226     SDL_InvalidateMap(surface->map);
    227 
    228     return 0;
    229 }
    230 
    231 int
    232 SDL_SetSurfaceRLE(SDL_Surface * surface, int flag)
    233 {
    234     int flags;
    235 
    236     if (!surface) {
    237         return -1;
    238     }
    239 
    240     flags = surface->map->info.flags;
    241     if (flag) {
    242         surface->map->info.flags |= SDL_COPY_RLE_DESIRED;
    243     } else {
    244         surface->map->info.flags &= ~SDL_COPY_RLE_DESIRED;
    245     }
    246     if (surface->map->info.flags != flags) {
    247         SDL_InvalidateMap(surface->map);
    248     }
    249     return 0;
    250 }
    251 
    252 SDL_bool
    253 SDL_HasSurfaceRLE(SDL_Surface * surface)
    254 {
    255     if (!surface) {
    256         return SDL_FALSE;
    257     }
    258 
    259     if (!(surface->map->info.flags & SDL_COPY_RLE_DESIRED)) {
    260         return SDL_FALSE;
    261     }
    262 
    263     return SDL_TRUE;
    264 }
    265 
    266 int
    267 SDL_SetColorKey(SDL_Surface * surface, int flag, Uint32 key)
    268 {
    269     int flags;
    270 
    271     if (!surface) {
    272         return SDL_InvalidParamError("surface");
    273     }
    274 
    275     if (surface->format->palette && key >= ((Uint32) surface->format->palette->ncolors)) {
    276         return SDL_InvalidParamError("key");
    277     }
    278 
    279     if (flag & SDL_RLEACCEL) {
    280         SDL_SetSurfaceRLE(surface, 1);
    281     }
    282 
    283     flags = surface->map->info.flags;
    284     if (flag) {
    285         surface->map->info.flags |= SDL_COPY_COLORKEY;
    286         surface->map->info.colorkey = key;
    287     } else {
    288         surface->map->info.flags &= ~SDL_COPY_COLORKEY;
    289     }
    290     if (surface->map->info.flags != flags) {
    291         SDL_InvalidateMap(surface->map);
    292     }
    293 
    294     return 0;
    295 }
    296 
    297 SDL_bool
    298 SDL_HasColorKey(SDL_Surface * surface)
    299 {
    300     if (!surface) {
    301         return SDL_FALSE;
    302     }
    303 
    304     if (!(surface->map->info.flags & SDL_COPY_COLORKEY)) {
    305         return SDL_FALSE;
    306     }
    307 
    308     return SDL_TRUE;
    309 }
    310 
    311 int
    312 SDL_GetColorKey(SDL_Surface * surface, Uint32 * key)
    313 {
    314     if (!surface) {
    315         return SDL_InvalidParamError("surface");
    316     }
    317 
    318     if (!(surface->map->info.flags & SDL_COPY_COLORKEY)) {
    319         return SDL_SetError("Surface doesn't have a colorkey");
    320     }
    321 
    322     if (key) {
    323         *key = surface->map->info.colorkey;
    324     }
    325     return 0;
    326 }
    327 
    328 /* This is a fairly slow function to switch from colorkey to alpha */
    329 static void
    330 SDL_ConvertColorkeyToAlpha(SDL_Surface * surface, SDL_bool ignore_alpha)
    331 {
    332     int x, y;
    333 
    334     if (!surface) {
    335         return;
    336     }
    337 
    338     if (!(surface->map->info.flags & SDL_COPY_COLORKEY) ||
    339         !surface->format->Amask) {
    340         return;
    341     }
    342 
    343     SDL_LockSurface(surface);
    344 
    345     switch (surface->format->BytesPerPixel) {
    346     case 2:
    347         {
    348             Uint16 *row, *spot;
    349             Uint16 ckey = (Uint16) surface->map->info.colorkey;
    350             Uint16 mask = (Uint16) (~surface->format->Amask);
    351 
    352             /* Ignore, or not, alpha in colorkey comparison */
    353             if (ignore_alpha) {
    354                 ckey &= mask;
    355                 row = (Uint16 *) surface->pixels;
    356                 for (y = surface->h; y--;) {
    357                     spot = row;
    358                     for (x = surface->w; x--;) {
    359                         if ((*spot & mask) == ckey) {
    360                             *spot &= mask;
    361                         }
    362                         ++spot;
    363                     }
    364                     row += surface->pitch / 2;
    365                 }
    366             } else {
    367                 row = (Uint16 *) surface->pixels;
    368                 for (y = surface->h; y--;) {
    369                     spot = row;
    370                     for (x = surface->w; x--;) {
    371                         if (*spot == ckey) {
    372                             *spot &= mask;
    373                         }
    374                         ++spot;
    375                     }
    376                     row += surface->pitch / 2;
    377                 }
    378             }
    379         }
    380         break;
    381     case 3:
    382         /* FIXME */
    383         break;
    384     case 4:
    385         {
    386             Uint32 *row, *spot;
    387             Uint32 ckey = surface->map->info.colorkey;
    388             Uint32 mask = ~surface->format->Amask;
    389 
    390             /* Ignore, or not, alpha in colorkey comparison */
    391             if (ignore_alpha) {
    392                 ckey &= mask;
    393                 row = (Uint32 *) surface->pixels;
    394                 for (y = surface->h; y--;) {
    395                     spot = row;
    396                     for (x = surface->w; x--;) {
    397                         if ((*spot & mask) == ckey) {
    398                             *spot &= mask;
    399                         }
    400                         ++spot;
    401                     }
    402                     row += surface->pitch / 4;
    403                 }
    404             } else {
    405                 row = (Uint32 *) surface->pixels;
    406                 for (y = surface->h; y--;) {
    407                     spot = row;
    408                     for (x = surface->w; x--;) {
    409                         if (*spot == ckey) {
    410                             *spot &= mask;
    411                         }
    412                         ++spot;
    413                     }
    414                     row += surface->pitch / 4;
    415                 }
    416             }
    417         }
    418         break;
    419     }
    420 
    421     SDL_UnlockSurface(surface);
    422 
    423     SDL_SetColorKey(surface, 0, 0);
    424     SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
    425 }
    426 
    427 int
    428 SDL_SetSurfaceColorMod(SDL_Surface * surface, Uint8 r, Uint8 g, Uint8 b)
    429 {
    430     int flags;
    431 
    432     if (!surface) {
    433         return -1;
    434     }
    435 
    436     surface->map->info.r = r;
    437     surface->map->info.g = g;
    438     surface->map->info.b = b;
    439 
    440     flags = surface->map->info.flags;
    441     if (r != 0xFF || g != 0xFF || b != 0xFF) {
    442         surface->map->info.flags |= SDL_COPY_MODULATE_COLOR;
    443     } else {
    444         surface->map->info.flags &= ~SDL_COPY_MODULATE_COLOR;
    445     }
    446     if (surface->map->info.flags != flags) {
    447         SDL_InvalidateMap(surface->map);
    448     }
    449     return 0;
    450 }
    451 
    452 
    453 int
    454 SDL_GetSurfaceColorMod(SDL_Surface * surface, Uint8 * r, Uint8 * g, Uint8 * b)
    455 {
    456     if (!surface) {
    457         return -1;
    458     }
    459 
    460     if (r) {
    461         *r = surface->map->info.r;
    462     }
    463     if (g) {
    464         *g = surface->map->info.g;
    465     }
    466     if (b) {
    467         *b = surface->map->info.b;
    468     }
    469     return 0;
    470 }
    471 
    472 int
    473 SDL_SetSurfaceAlphaMod(SDL_Surface * surface, Uint8 alpha)
    474 {
    475     int flags;
    476 
    477     if (!surface) {
    478         return -1;
    479     }
    480 
    481     surface->map->info.a = alpha;
    482 
    483     flags = surface->map->info.flags;
    484     if (alpha != 0xFF) {
    485         surface->map->info.flags |= SDL_COPY_MODULATE_ALPHA;
    486     } else {
    487         surface->map->info.flags &= ~SDL_COPY_MODULATE_ALPHA;
    488     }
    489     if (surface->map->info.flags != flags) {
    490         SDL_InvalidateMap(surface->map);
    491     }
    492     return 0;
    493 }
    494 
    495 int
    496 SDL_GetSurfaceAlphaMod(SDL_Surface * surface, Uint8 * alpha)
    497 {
    498     if (!surface) {
    499         return -1;
    500     }
    501 
    502     if (alpha) {
    503         *alpha = surface->map->info.a;
    504     }
    505     return 0;
    506 }
    507 
    508 int
    509 SDL_SetSurfaceBlendMode(SDL_Surface * surface, SDL_BlendMode blendMode)
    510 {
    511     int flags, status;
    512 
    513     if (!surface) {
    514         return -1;
    515     }
    516 
    517     status = 0;
    518     flags = surface->map->info.flags;
    519     surface->map->info.flags &=
    520         ~(SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | SDL_COPY_MUL);
    521     switch (blendMode) {
    522     case SDL_BLENDMODE_NONE:
    523         break;
    524     case SDL_BLENDMODE_BLEND:
    525         surface->map->info.flags |= SDL_COPY_BLEND;
    526         break;
    527     case SDL_BLENDMODE_ADD:
    528         surface->map->info.flags |= SDL_COPY_ADD;
    529         break;
    530     case SDL_BLENDMODE_MOD:
    531         surface->map->info.flags |= SDL_COPY_MOD;
    532         break;
    533     case SDL_BLENDMODE_MUL:
    534         surface->map->info.flags |= SDL_COPY_MUL;
    535         break;
    536     default:
    537         status = SDL_Unsupported();
    538         break;
    539     }
    540 
    541     if (surface->map->info.flags != flags) {
    542         SDL_InvalidateMap(surface->map);
    543     }
    544 
    545     return status;
    546 }
    547 
    548 int
    549 SDL_GetSurfaceBlendMode(SDL_Surface * surface, SDL_BlendMode *blendMode)
    550 {
    551     if (!surface) {
    552         return -1;
    553     }
    554 
    555     if (!blendMode) {
    556         return 0;
    557     }
    558 
    559     switch (surface->map->
    560             info.flags & (SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | SDL_COPY_MUL)) {
    561     case SDL_COPY_BLEND:
    562         *blendMode = SDL_BLENDMODE_BLEND;
    563         break;
    564     case SDL_COPY_ADD:
    565         *blendMode = SDL_BLENDMODE_ADD;
    566         break;
    567     case SDL_COPY_MOD:
    568         *blendMode = SDL_BLENDMODE_MOD;
    569         break;
    570     case SDL_COPY_MUL:
    571         *blendMode = SDL_BLENDMODE_MUL;
    572         break;
    573     default:
    574         *blendMode = SDL_BLENDMODE_NONE;
    575         break;
    576     }
    577     return 0;
    578 }
    579 
    580 SDL_bool
    581 SDL_SetClipRect(SDL_Surface * surface, const SDL_Rect * rect)
    582 {
    583     SDL_Rect full_rect;
    584 
    585     /* Don't do anything if there's no surface to act on */
    586     if (!surface) {
    587         return SDL_FALSE;
    588     }
    589 
    590     /* Set up the full surface rectangle */
    591     full_rect.x = 0;
    592     full_rect.y = 0;
    593     full_rect.w = surface->w;
    594     full_rect.h = surface->h;
    595 
    596     /* Set the clipping rectangle */
    597     if (!rect) {
    598         surface->clip_rect = full_rect;
    599         return SDL_TRUE;
    600     }
    601     return SDL_IntersectRect(rect, &full_rect, &surface->clip_rect);
    602 }
    603 
    604 void
    605 SDL_GetClipRect(SDL_Surface * surface, SDL_Rect * rect)
    606 {
    607     if (surface && rect) {
    608         *rect = surface->clip_rect;
    609     }
    610 }
    611 
    612 /*
    613  * Set up a blit between two surfaces -- split into three parts:
    614  * The upper part, SDL_UpperBlit(), performs clipping and rectangle
    615  * verification.  The lower part is a pointer to a low level
    616  * accelerated blitting function.
    617  *
    618  * These parts are separated out and each used internally by this
    619  * library in the optimimum places.  They are exported so that if
    620  * you know exactly what you are doing, you can optimize your code
    621  * by calling the one(s) you need.
    622  */
    623 int
    624 SDL_LowerBlit(SDL_Surface * src, SDL_Rect * srcrect,
    625               SDL_Surface * dst, SDL_Rect * dstrect)
    626 {
    627     /* Check to make sure the blit mapping is valid */
    628     if ((src->map->dst != dst) ||
    629         (dst->format->palette &&
    630          src->map->dst_palette_version != dst->format->palette->version) ||
    631         (src->format->palette &&
    632          src->map->src_palette_version != src->format->palette->version)) {
    633         if (SDL_MapSurface(src, dst) < 0) {
    634             return (-1);
    635         }
    636         /* just here for debugging */
    637 /*         printf */
    638 /*             ("src = 0x%08X src->flags = %08X src->map->info.flags = %08x\ndst = 0x%08X dst->flags = %08X dst->map->info.flags = %08X\nsrc->map->blit = 0x%08x\n", */
    639 /*              src, dst->flags, src->map->info.flags, dst, dst->flags, */
    640 /*              dst->map->info.flags, src->map->blit); */
    641     }
    642     return (src->map->blit(src, srcrect, dst, dstrect));
    643 }
    644 
    645 
    646 int
    647 SDL_UpperBlit(SDL_Surface * src, const SDL_Rect * srcrect,
    648               SDL_Surface * dst, SDL_Rect * dstrect)
    649 {
    650     SDL_Rect fulldst;
    651     int srcx, srcy, w, h;
    652 
    653     /* Make sure the surfaces aren't locked */
    654     if (!src || !dst) {
    655         return SDL_SetError("SDL_UpperBlit: passed a NULL surface");
    656     }
    657     if (src->locked || dst->locked) {
    658         return SDL_SetError("Surfaces must not be locked during blit");
    659     }
    660 
    661     /* If the destination rectangle is NULL, use the entire dest surface */
    662     if (dstrect == NULL) {
    663         fulldst.x = fulldst.y = 0;
    664         fulldst.w = dst->w;
    665         fulldst.h = dst->h;
    666         dstrect = &fulldst;
    667     }
    668 
    669     /* clip the source rectangle to the source surface */
    670     if (srcrect) {
    671         int maxw, maxh;
    672 
    673         srcx = srcrect->x;
    674         w = srcrect->w;
    675         if (srcx < 0) {
    676             w += srcx;
    677             dstrect->x -= srcx;
    678             srcx = 0;
    679         }
    680         maxw = src->w - srcx;
    681         if (maxw < w)
    682             w = maxw;
    683 
    684         srcy = srcrect->y;
    685         h = srcrect->h;
    686         if (srcy < 0) {
    687             h += srcy;
    688             dstrect->y -= srcy;
    689             srcy = 0;
    690         }
    691         maxh = src->h - srcy;
    692         if (maxh < h)
    693             h = maxh;
    694 
    695     } else {
    696         srcx = srcy = 0;
    697         w = src->w;
    698         h = src->h;
    699     }
    700 
    701     /* clip the destination rectangle against the clip rectangle */
    702     {
    703         SDL_Rect *clip = &dst->clip_rect;
    704         int dx, dy;
    705 
    706         dx = clip->x - dstrect->x;
    707         if (dx > 0) {
    708             w -= dx;
    709             dstrect->x += dx;
    710             srcx += dx;
    711         }
    712         dx = dstrect->x + w - clip->x - clip->w;
    713         if (dx > 0)
    714             w -= dx;
    715 
    716         dy = clip->y - dstrect->y;
    717         if (dy > 0) {
    718             h -= dy;
    719             dstrect->y += dy;
    720             srcy += dy;
    721         }
    722         dy = dstrect->y + h - clip->y - clip->h;
    723         if (dy > 0)
    724             h -= dy;
    725     }
    726 
    727     /* Switch back to a fast blit if we were previously stretching */
    728     if (src->map->info.flags & SDL_COPY_NEAREST) {
    729         src->map->info.flags &= ~SDL_COPY_NEAREST;
    730         SDL_InvalidateMap(src->map);
    731     }
    732 
    733     if (w > 0 && h > 0) {
    734         SDL_Rect sr;
    735         sr.x = srcx;
    736         sr.y = srcy;
    737         sr.w = dstrect->w = w;
    738         sr.h = dstrect->h = h;
    739         return SDL_LowerBlit(src, &sr, dst, dstrect);
    740     }
    741     dstrect->w = dstrect->h = 0;
    742     return 0;
    743 }
    744 
    745 int
    746 SDL_UpperBlitScaled(SDL_Surface * src, const SDL_Rect * srcrect,
    747               SDL_Surface * dst, SDL_Rect * dstrect)
    748 {
    749     double src_x0, src_y0, src_x1, src_y1;
    750     double dst_x0, dst_y0, dst_x1, dst_y1;
    751     SDL_Rect final_src, final_dst;
    752     double scaling_w, scaling_h;
    753     int src_w, src_h;
    754     int dst_w, dst_h;
    755 
    756     /* Make sure the surfaces aren't locked */
    757     if (!src || !dst) {
    758         return SDL_SetError("SDL_UpperBlitScaled: passed a NULL surface");
    759     }
    760     if (src->locked || dst->locked) {
    761         return SDL_SetError("Surfaces must not be locked during blit");
    762     }
    763 
    764     if (NULL == srcrect) {
    765         src_w = src->w;
    766         src_h = src->h;
    767     } else {
    768         src_w = srcrect->w;
    769         src_h = srcrect->h;
    770     }
    771 
    772     if (NULL == dstrect) {
    773         dst_w = dst->w;
    774         dst_h = dst->h;
    775     } else {
    776         dst_w = dstrect->w;
    777         dst_h = dstrect->h;
    778     }
    779 
    780     if (dst_w == src_w && dst_h == src_h) {
    781         /* No scaling, defer to regular blit */
    782         return SDL_BlitSurface(src, srcrect, dst, dstrect);
    783     }
    784 
    785     scaling_w = (double)dst_w / src_w;
    786     scaling_h = (double)dst_h / src_h;
    787 
    788     if (NULL == dstrect) {
    789         dst_x0 = 0;
    790         dst_y0 = 0;
    791         dst_x1 = dst_w - 1;
    792         dst_y1 = dst_h - 1;
    793     } else {
    794         dst_x0 = dstrect->x;
    795         dst_y0 = dstrect->y;
    796         dst_x1 = dst_x0 + dst_w - 1;
    797         dst_y1 = dst_y0 + dst_h - 1;
    798     }
    799 
    800     if (NULL == srcrect) {
    801         src_x0 = 0;
    802         src_y0 = 0;
    803         src_x1 = src_w - 1;
    804         src_y1 = src_h - 1;
    805     } else {
    806         src_x0 = srcrect->x;
    807         src_y0 = srcrect->y;
    808         src_x1 = src_x0 + src_w - 1;
    809         src_y1 = src_y0 + src_h - 1;
    810 
    811         /* Clip source rectangle to the source surface */
    812 
    813         if (src_x0 < 0) {
    814             dst_x0 -= src_x0 * scaling_w;
    815             src_x0 = 0;
    816         }
    817 
    818         if (src_x1 >= src->w) {
    819             dst_x1 -= (src_x1 - src->w + 1) * scaling_w;
    820             src_x1 = src->w - 1;
    821         }
    822 
    823         if (src_y0 < 0) {
    824             dst_y0 -= src_y0 * scaling_h;
    825             src_y0 = 0;
    826         }
    827 
    828         if (src_y1 >= src->h) {
    829             dst_y1 -= (src_y1 - src->h + 1) * scaling_h;
    830             src_y1 = src->h - 1;
    831         }
    832     }
    833 
    834     /* Clip destination rectangle to the clip rectangle */
    835 
    836     /* Translate to clip space for easier calculations */
    837     dst_x0 -= dst->clip_rect.x;
    838     dst_x1 -= dst->clip_rect.x;
    839     dst_y0 -= dst->clip_rect.y;
    840     dst_y1 -= dst->clip_rect.y;
    841 
    842     if (dst_x0 < 0) {
    843         src_x0 -= dst_x0 / scaling_w;
    844         dst_x0 = 0;
    845     }
    846 
    847     if (dst_x1 >= dst->clip_rect.w) {
    848         src_x1 -= (dst_x1 - dst->clip_rect.w + 1) / scaling_w;
    849         dst_x1 = dst->clip_rect.w - 1;
    850     }
    851 
    852     if (dst_y0 < 0) {
    853         src_y0 -= dst_y0 / scaling_h;
    854         dst_y0 = 0;
    855     }
    856 
    857     if (dst_y1 >= dst->clip_rect.h) {
    858         src_y1 -= (dst_y1 - dst->clip_rect.h + 1) / scaling_h;
    859         dst_y1 = dst->clip_rect.h - 1;
    860     }
    861 
    862     /* Translate back to surface coordinates */
    863     dst_x0 += dst->clip_rect.x;
    864     dst_x1 += dst->clip_rect.x;
    865     dst_y0 += dst->clip_rect.y;
    866     dst_y1 += dst->clip_rect.y;
    867 
    868     final_src.x = (int)SDL_floor(src_x0 + 0.5);
    869     final_src.y = (int)SDL_floor(src_y0 + 0.5);
    870     final_src.w = (int)SDL_floor(src_x1 + 1 + 0.5) - (int)SDL_floor(src_x0 + 0.5);
    871     final_src.h = (int)SDL_floor(src_y1 + 1 + 0.5) - (int)SDL_floor(src_y0 + 0.5);
    872 
    873     final_dst.x = (int)SDL_floor(dst_x0 + 0.5);
    874     final_dst.y = (int)SDL_floor(dst_y0 + 0.5);
    875     final_dst.w = (int)SDL_floor(dst_x1 - dst_x0 + 1.5);
    876     final_dst.h = (int)SDL_floor(dst_y1 - dst_y0 + 1.5);
    877 
    878     if (final_dst.w < 0)
    879         final_dst.w = 0;
    880     if (final_dst.h < 0)
    881         final_dst.h = 0;
    882 
    883     if (dstrect)
    884         *dstrect = final_dst;
    885 
    886     if (final_dst.w == 0 || final_dst.h == 0 ||
    887         final_src.w <= 0 || final_src.h <= 0) {
    888         /* No-op. */
    889         return 0;
    890     }
    891 
    892     return SDL_LowerBlitScaled(src, &final_src, dst, &final_dst);
    893 }
    894 
    895 /**
    896  *  This is a semi-private blit function and it performs low-level surface
    897  *  scaled blitting only.
    898  */
    899 int
    900 SDL_LowerBlitScaled(SDL_Surface * src, SDL_Rect * srcrect,
    901                 SDL_Surface * dst, SDL_Rect * dstrect)
    902 {
    903     static const Uint32 complex_copy_flags = (
    904         SDL_COPY_MODULATE_COLOR | SDL_COPY_MODULATE_ALPHA |
    905         SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | SDL_COPY_MUL |
    906         SDL_COPY_COLORKEY
    907     );
    908 
    909     if (!(src->map->info.flags & SDL_COPY_NEAREST)) {
    910         src->map->info.flags |= SDL_COPY_NEAREST;
    911         SDL_InvalidateMap(src->map);
    912     }
    913 
    914     if ( !(src->map->info.flags & complex_copy_flags) &&
    915          src->format->format == dst->format->format &&
    916          !SDL_ISPIXELFORMAT_INDEXED(src->format->format) ) {
    917         return SDL_SoftStretch( src, srcrect, dst, dstrect );
    918     } else {
    919         return SDL_LowerBlit( src, srcrect, dst, dstrect );
    920     }
    921 }
    922 
    923 /*
    924  * Lock a surface to directly access the pixels
    925  */
    926 int
    927 SDL_LockSurface(SDL_Surface * surface)
    928 {
    929     if (!surface->locked) {
    930 #if SDL_HAVE_RLE
    931         /* Perform the lock */
    932         if (surface->flags & SDL_RLEACCEL) {
    933             SDL_UnRLESurface(surface, 1);
    934             surface->flags |= SDL_RLEACCEL;     /* save accel'd state */
    935         }
    936 #endif
    937     }
    938 
    939     /* Increment the surface lock count, for recursive locks */
    940     ++surface->locked;
    941 
    942     /* Ready to go.. */
    943     return (0);
    944 }
    945 
    946 /*
    947  * Unlock a previously locked surface
    948  */
    949 void
    950 SDL_UnlockSurface(SDL_Surface * surface)
    951 {
    952     /* Only perform an unlock if we are locked */
    953     if (!surface->locked || (--surface->locked > 0)) {
    954         return;
    955     }
    956 
    957 #if SDL_HAVE_RLE
    958     /* Update RLE encoded surface with new data */
    959     if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
    960         surface->flags &= ~SDL_RLEACCEL;        /* stop lying */
    961         SDL_RLESurface(surface);
    962     }
    963 #endif
    964 }
    965 
    966 /*
    967  * Creates a new surface identical to the existing surface
    968  */
    969 SDL_Surface *
    970 SDL_DuplicateSurface(SDL_Surface * surface)
    971 {
    972     return SDL_ConvertSurface(surface, surface->format, surface->flags);
    973 }
    974 
    975 /*
    976  * Convert a surface into the specified pixel format.
    977  */
    978 SDL_Surface *
    979 SDL_ConvertSurface(SDL_Surface * surface, const SDL_PixelFormat * format,
    980                    Uint32 flags)
    981 {
    982     SDL_Surface *convert;
    983     Uint32 copy_flags;
    984     SDL_Color copy_color;
    985     SDL_Rect bounds;
    986     int ret;
    987     SDL_bool palette_ck_transform = SDL_FALSE;
    988     int palette_ck_value = 0;
    989     SDL_bool palette_has_alpha = SDL_FALSE;
    990     Uint8 *palette_saved_alpha = NULL;
    991 
    992     if (!surface) {
    993         SDL_InvalidParamError("surface");
    994         return NULL;
    995     }
    996     if (!format) {
    997         SDL_InvalidParamError("format");
    998         return NULL;
    999     }
   1000 
   1001     /* Check for empty destination palette! (results in empty image) */
   1002     if (format->palette != NULL) {
   1003         int i;
   1004         for (i = 0; i < format->palette->ncolors; ++i) {
   1005             if ((format->palette->colors[i].r != 0xFF) ||
   1006                 (format->palette->colors[i].g != 0xFF) ||
   1007                 (format->palette->colors[i].b != 0xFF))
   1008                 break;
   1009         }
   1010         if (i == format->palette->ncolors) {
   1011             SDL_SetError("Empty destination palette");
   1012             return (NULL);
   1013         }
   1014     }
   1015 
   1016     /* Create a new surface with the desired format */
   1017     convert = SDL_CreateRGBSurface(flags, surface->w, surface->h,
   1018                                    format->BitsPerPixel, format->Rmask,
   1019                                    format->Gmask, format->Bmask,
   1020                                    format->Amask);
   1021     if (convert == NULL) {
   1022         return (NULL);
   1023     }
   1024 
   1025     /* Copy the palette if any */
   1026     if (format->palette && convert->format->palette) {
   1027         SDL_memcpy(convert->format->palette->colors,
   1028                    format->palette->colors,
   1029                    format->palette->ncolors * sizeof(SDL_Color));
   1030         convert->format->palette->ncolors = format->palette->ncolors;
   1031     }
   1032 
   1033     /* Save the original copy flags */
   1034     copy_flags = surface->map->info.flags;
   1035     copy_color.r = surface->map->info.r;
   1036     copy_color.g = surface->map->info.g;
   1037     copy_color.b = surface->map->info.b;
   1038     copy_color.a = surface->map->info.a;
   1039     surface->map->info.r = 0xFF;
   1040     surface->map->info.g = 0xFF;
   1041     surface->map->info.b = 0xFF;
   1042     surface->map->info.a = 0xFF;
   1043     surface->map->info.flags = (copy_flags & (SDL_COPY_RLE_COLORKEY | SDL_COPY_RLE_ALPHAKEY));
   1044     SDL_InvalidateMap(surface->map);
   1045 
   1046     /* Copy over the image data */
   1047     bounds.x = 0;
   1048     bounds.y = 0;
   1049     bounds.w = surface->w;
   1050     bounds.h = surface->h;
   1051 
   1052     /* Source surface has a palette with no real alpha (0 or OPAQUE).
   1053      * Destination format has alpha.
   1054      * -> set alpha channel to be opaque */
   1055     if (surface->format->palette && format->Amask) {
   1056         SDL_bool set_opaque = SDL_FALSE;
   1057 
   1058         SDL_bool is_opaque, has_alpha_channel;
   1059         SDL_DetectPalette(surface->format->palette, &is_opaque, &has_alpha_channel);
   1060 
   1061         if (is_opaque) {
   1062             if (!has_alpha_channel) {
   1063                 set_opaque = SDL_TRUE;
   1064             }
   1065         } else {
   1066             palette_has_alpha = SDL_TRUE;
   1067         }
   1068 
   1069         /* Set opaque and backup palette alpha values */
   1070         if (set_opaque) {
   1071             int i;
   1072             palette_saved_alpha = SDL_stack_alloc(Uint8, surface->format->palette->ncolors);
   1073             for (i = 0; i < surface->format->palette->ncolors; i++) {
   1074                 palette_saved_alpha[i] = surface->format->palette->colors[i].a;
   1075                 surface->format->palette->colors[i].a = SDL_ALPHA_OPAQUE;
   1076             }
   1077         }
   1078     }
   1079 
   1080     /* Transform colorkey to alpha. for cases where source palette has duplicate values, and colorkey is one of them */
   1081     if (copy_flags & SDL_COPY_COLORKEY) {
   1082         if (surface->format->palette && !format->palette) {
   1083             palette_ck_transform = SDL_TRUE;
   1084             palette_has_alpha = SDL_TRUE;
   1085             palette_ck_value = surface->format->palette->colors[surface->map->info.colorkey].a;
   1086             surface->format->palette->colors[surface->map->info.colorkey].a = SDL_ALPHA_TRANSPARENT;
   1087         }
   1088     }
   1089 
   1090     ret = SDL_LowerBlit(surface, &bounds, convert, &bounds);
   1091 
   1092     /* Restore colorkey alpha value */
   1093     if (palette_ck_transform) {
   1094         surface->format->palette->colors[surface->map->info.colorkey].a = palette_ck_value;
   1095     }
   1096 
   1097     /* Restore palette alpha values */
   1098     if (palette_saved_alpha) {
   1099         int i;
   1100         for (i = 0; i < surface->format->palette->ncolors; i++) {
   1101             surface->format->palette->colors[i].a = palette_saved_alpha[i];
   1102         }
   1103         SDL_stack_free(palette_saved_alpha);
   1104     }
   1105 
   1106     /* Clean up the original surface, and update converted surface */
   1107     convert->map->info.r = copy_color.r;
   1108     convert->map->info.g = copy_color.g;
   1109     convert->map->info.b = copy_color.b;
   1110     convert->map->info.a = copy_color.a;
   1111     convert->map->info.flags =
   1112         (copy_flags &
   1113          ~(SDL_COPY_COLORKEY | SDL_COPY_BLEND
   1114            | SDL_COPY_RLE_DESIRED | SDL_COPY_RLE_COLORKEY |
   1115            SDL_COPY_RLE_ALPHAKEY));
   1116     surface->map->info.r = copy_color.r;
   1117     surface->map->info.g = copy_color.g;
   1118     surface->map->info.b = copy_color.b;
   1119     surface->map->info.a = copy_color.a;
   1120     surface->map->info.flags = copy_flags;
   1121     SDL_InvalidateMap(surface->map);
   1122 
   1123     /* SDL_LowerBlit failed, and so the conversion */
   1124     if (ret < 0) {
   1125         SDL_FreeSurface(convert);
   1126         return NULL;
   1127     }
   1128 
   1129     if (copy_flags & SDL_COPY_COLORKEY) {
   1130         SDL_bool set_colorkey_by_color = SDL_FALSE;
   1131         SDL_bool convert_colorkey = SDL_TRUE;
   1132 
   1133         if (surface->format->palette) {
   1134             if (format->palette &&
   1135                 surface->format->palette->ncolors <= format->palette->ncolors &&
   1136                 (SDL_memcmp(surface->format->palette->colors, format->palette->colors,
   1137                   surface->format->palette->ncolors * sizeof(SDL_Color)) == 0)) {
   1138                 /* The palette is identical, just set the same colorkey */
   1139                 SDL_SetColorKey(convert, 1, surface->map->info.colorkey);
   1140             } else if (!format->palette) {
   1141                 if (format->Amask) {
   1142                     /* No need to add the colorkey, transparency is in the alpha channel*/
   1143                 } else {
   1144                     /* Only set the colorkey information */
   1145                     set_colorkey_by_color = SDL_TRUE;
   1146                     convert_colorkey = SDL_FALSE;
   1147                 }
   1148             } else {
   1149                 set_colorkey_by_color = SDL_TRUE;
   1150             }
   1151         } else {
   1152             set_colorkey_by_color = SDL_TRUE;
   1153         }
   1154 
   1155         if (set_colorkey_by_color) {
   1156             SDL_Surface *tmp;
   1157             SDL_Surface *tmp2;
   1158             int converted_colorkey = 0;
   1159 
   1160             /* Create a dummy surface to get the colorkey converted */
   1161             tmp = SDL_CreateRGBSurface(0, 1, 1,
   1162                                    surface->format->BitsPerPixel, surface->format->Rmask,
   1163                                    surface->format->Gmask, surface->format->Bmask,
   1164                                    surface->format->Amask);
   1165 
   1166             /* Share the palette, if any */
   1167             if (surface->format->palette) {
   1168                 SDL_SetSurfacePalette(tmp, surface->format->palette);
   1169             }
   1170 
   1171             SDL_FillRect(tmp, NULL, surface->map->info.colorkey);
   1172 
   1173             tmp->map->info.flags &= ~SDL_COPY_COLORKEY;
   1174 
   1175             /* Convertion of the colorkey */
   1176             tmp2 = SDL_ConvertSurface(tmp, format, 0);
   1177 
   1178             /* Get the converted colorkey */
   1179             SDL_memcpy(&converted_colorkey, tmp2->pixels, tmp2->format->BytesPerPixel);
   1180 
   1181             SDL_FreeSurface(tmp);
   1182             SDL_FreeSurface(tmp2);
   1183 
   1184             /* Set the converted colorkey on the new surface */
   1185             SDL_SetColorKey(convert, 1, converted_colorkey);
   1186 
   1187             /* This is needed when converting for 3D texture upload */
   1188             if (convert_colorkey) {
   1189                 SDL_ConvertColorkeyToAlpha(convert, SDL_TRUE);
   1190             }
   1191         }
   1192     }
   1193     SDL_SetClipRect(convert, &surface->clip_rect);
   1194 
   1195     /* Enable alpha blending by default if the new surface has an
   1196      * alpha channel or alpha modulation */
   1197     if ((surface->format->Amask && format->Amask) ||
   1198         (palette_has_alpha && format->Amask) ||
   1199         (copy_flags & SDL_COPY_MODULATE_ALPHA)) {
   1200         SDL_SetSurfaceBlendMode(convert, SDL_BLENDMODE_BLEND);
   1201     }
   1202     if ((copy_flags & SDL_COPY_RLE_DESIRED) || (flags & SDL_RLEACCEL)) {
   1203         SDL_SetSurfaceRLE(convert, SDL_RLEACCEL);
   1204     }
   1205 
   1206     /* We're ready to go! */
   1207     return (convert);
   1208 }
   1209 
   1210 SDL_Surface *
   1211 SDL_ConvertSurfaceFormat(SDL_Surface * surface, Uint32 pixel_format,
   1212                          Uint32 flags)
   1213 {
   1214     SDL_PixelFormat *fmt;
   1215     SDL_Surface *convert = NULL;
   1216 
   1217     fmt = SDL_AllocFormat(pixel_format);
   1218     if (fmt) {
   1219         convert = SDL_ConvertSurface(surface, fmt, flags);
   1220         SDL_FreeFormat(fmt);
   1221     }
   1222     return convert;
   1223 }
   1224 
   1225 /*
   1226  * Create a surface on the stack for quick blit operations
   1227  */
   1228 static SDL_INLINE SDL_bool
   1229 SDL_CreateSurfaceOnStack(int width, int height, Uint32 pixel_format,
   1230                          void * pixels, int pitch, SDL_Surface * surface,
   1231                          SDL_PixelFormat * format, SDL_BlitMap * blitmap)
   1232 {
   1233     if (SDL_ISPIXELFORMAT_INDEXED(pixel_format)) {
   1234         SDL_SetError("Indexed pixel formats not supported");
   1235         return SDL_FALSE;
   1236     }
   1237     if (SDL_InitFormat(format, pixel_format) < 0) {
   1238         return SDL_FALSE;
   1239     }
   1240 
   1241     SDL_zerop(surface);
   1242     surface->flags = SDL_PREALLOC;
   1243     surface->format = format;
   1244     surface->pixels = pixels;
   1245     surface->w = width;
   1246     surface->h = height;
   1247     surface->pitch = pitch;
   1248     /* We don't actually need to set up the clip rect for our purposes */
   1249     /* SDL_SetClipRect(surface, NULL); */
   1250 
   1251     /* Allocate an empty mapping */
   1252     SDL_zerop(blitmap);
   1253     blitmap->info.r = 0xFF;
   1254     blitmap->info.g = 0xFF;
   1255     blitmap->info.b = 0xFF;
   1256     blitmap->info.a = 0xFF;
   1257     surface->map = blitmap;
   1258 
   1259     /* The surface is ready to go */
   1260     surface->refcount = 1;
   1261     return SDL_TRUE;
   1262 }
   1263 
   1264 /*
   1265  * Copy a block of pixels of one format to another format
   1266  */
   1267 int SDL_ConvertPixels(int width, int height,
   1268                       Uint32 src_format, const void * src, int src_pitch,
   1269                       Uint32 dst_format, void * dst, int dst_pitch)
   1270 {
   1271     SDL_Surface src_surface, dst_surface;
   1272     SDL_PixelFormat src_fmt, dst_fmt;
   1273     SDL_BlitMap src_blitmap, dst_blitmap;
   1274     SDL_Rect rect;
   1275     void *nonconst_src = (void *) src;
   1276     int ret;
   1277 
   1278     /* Check to make sure we are blitting somewhere, so we don't crash */
   1279     if (!dst) {
   1280         return SDL_InvalidParamError("dst");
   1281     }
   1282     if (!dst_pitch) {
   1283         return SDL_InvalidParamError("dst_pitch");
   1284     }
   1285 
   1286 #if SDL_HAVE_YUV
   1287     if (SDL_ISPIXELFORMAT_FOURCC(src_format) && SDL_ISPIXELFORMAT_FOURCC(dst_format)) {
   1288         return SDL_ConvertPixels_YUV_to_YUV(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch);
   1289     } else if (SDL_ISPIXELFORMAT_FOURCC(src_format)) {
   1290         return SDL_ConvertPixels_YUV_to_RGB(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch);
   1291     } else if (SDL_ISPIXELFORMAT_FOURCC(dst_format)) {
   1292         return SDL_ConvertPixels_RGB_to_YUV(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch);
   1293     }
   1294 #else
   1295     if (SDL_ISPIXELFORMAT_FOURCC(src_format) || SDL_ISPIXELFORMAT_FOURCC(dst_format)) {
   1296         SDL_SetError("SDL not built with YUV support");
   1297         return -1;
   1298     }
   1299 #endif
   1300 
   1301     /* Fast path for same format copy */
   1302     if (src_format == dst_format) {
   1303         int i;
   1304         const int bpp = SDL_BYTESPERPIXEL(src_format);
   1305         width *= bpp;
   1306         for (i = height; i--;) {
   1307             SDL_memcpy(dst, src, width);
   1308             src = (const Uint8*)src + src_pitch;
   1309             dst = (Uint8*)dst + dst_pitch;
   1310         }
   1311         return 0;
   1312     }
   1313 
   1314     if (!SDL_CreateSurfaceOnStack(width, height, src_format, nonconst_src,
   1315                                   src_pitch,
   1316                                   &src_surface, &src_fmt, &src_blitmap)) {
   1317         return -1;
   1318     }
   1319     if (!SDL_CreateSurfaceOnStack(width, height, dst_format, dst, dst_pitch,
   1320                                   &dst_surface, &dst_fmt, &dst_blitmap)) {
   1321         return -1;
   1322     }
   1323 
   1324     /* Set up the rect and go! */
   1325     rect.x = 0;
   1326     rect.y = 0;
   1327     rect.w = width;
   1328     rect.h = height;
   1329     ret = SDL_LowerBlit(&src_surface, &rect, &dst_surface, &rect);
   1330 
   1331     /* Free blitmap reference, after blitting between stack'ed surfaces */
   1332     SDL_InvalidateMap(src_surface.map);
   1333 
   1334     return ret;
   1335 }
   1336 
   1337 /*
   1338  * Free a surface created by the above function.
   1339  */
   1340 void
   1341 SDL_FreeSurface(SDL_Surface * surface)
   1342 {
   1343     if (surface == NULL) {
   1344         return;
   1345     }
   1346     if (surface->flags & SDL_DONTFREE) {
   1347         return;
   1348     }
   1349     SDL_InvalidateMap(surface->map);
   1350 
   1351     SDL_InvalidateAllBlitMap(surface);
   1352 
   1353     if (--surface->refcount > 0) {
   1354         return;
   1355     }
   1356     while (surface->locked > 0) {
   1357         SDL_UnlockSurface(surface);
   1358     }
   1359 #if SDL_HAVE_RLE
   1360     if (surface->flags & SDL_RLEACCEL) {
   1361         SDL_UnRLESurface(surface, 0);
   1362     }
   1363 #endif
   1364     if (surface->format) {
   1365         SDL_SetSurfacePalette(surface, NULL);
   1366         SDL_FreeFormat(surface->format);
   1367         surface->format = NULL;
   1368     }
   1369     if (surface->flags & SDL_PREALLOC) {
   1370         /* Don't free */
   1371     } else if (surface->flags & SDL_SIMD_ALIGNED) {
   1372         /* Free aligned */
   1373         SDL_SIMDFree(surface->pixels);
   1374     } else {
   1375         /* Normal */
   1376         SDL_free(surface->pixels);
   1377     }
   1378     if (surface->map) {
   1379         SDL_FreeBlitMap(surface->map);
   1380     }
   1381     SDL_free(surface);
   1382 }
   1383 
   1384 /* vi: set ts=4 sw=4 expandtab: */