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
SDL_CalculatePitch(Uint32 format,int width)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 *
SDL_CreateRGBSurfaceWithFormat(Uint32 flags,int width,int height,int depth,Uint32 format)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 *
SDL_CreateRGBSurface(Uint32 flags,int width,int height,int depth,Uint32 Rmask,Uint32 Gmask,Uint32 Bmask,Uint32 Amask)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 *
SDL_CreateRGBSurfaceFrom(void * pixels,int width,int height,int depth,int pitch,Uint32 Rmask,Uint32 Gmask,Uint32 Bmask,Uint32 Amask)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 *
SDL_CreateRGBSurfaceWithFormatFrom(void * pixels,int width,int height,int depth,int pitch,Uint32 format)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
SDL_SetSurfacePalette(SDL_Surface * surface,SDL_Palette * palette)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
SDL_SetSurfaceRLE(SDL_Surface * surface,int flag)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 int
SDL_SetColorKey(SDL_Surface * surface,int flag,Uint32 key)253 SDL_SetColorKey(SDL_Surface * surface, int flag, Uint32 key)
254 {
255     int flags;
256 
257     if (!surface) {
258         return SDL_InvalidParamError("surface");
259     }
260 
261     if (surface->format->palette && key >= ((Uint32) surface->format->palette->ncolors)) {
262         return SDL_InvalidParamError("key");
263     }
264 
265     if (flag & SDL_RLEACCEL) {
266         SDL_SetSurfaceRLE(surface, 1);
267     }
268 
269     flags = surface->map->info.flags;
270     if (flag) {
271         surface->map->info.flags |= SDL_COPY_COLORKEY;
272         surface->map->info.colorkey = key;
273     } else {
274         surface->map->info.flags &= ~SDL_COPY_COLORKEY;
275     }
276     if (surface->map->info.flags != flags) {
277         SDL_InvalidateMap(surface->map);
278     }
279 
280     return 0;
281 }
282 
283 SDL_bool
SDL_HasColorKey(SDL_Surface * surface)284 SDL_HasColorKey(SDL_Surface * surface)
285 {
286     if (!surface) {
287         return SDL_FALSE;
288     }
289 
290     if (!(surface->map->info.flags & SDL_COPY_COLORKEY)) {
291         return SDL_FALSE;
292     }
293 
294     return SDL_TRUE;
295 }
296 
297 int
SDL_GetColorKey(SDL_Surface * surface,Uint32 * key)298 SDL_GetColorKey(SDL_Surface * surface, Uint32 * key)
299 {
300     if (!surface) {
301         return SDL_InvalidParamError("surface");
302     }
303 
304     if (!(surface->map->info.flags & SDL_COPY_COLORKEY)) {
305         return SDL_SetError("Surface doesn't have a colorkey");
306     }
307 
308     if (key) {
309         *key = surface->map->info.colorkey;
310     }
311     return 0;
312 }
313 
314 /* This is a fairly slow function to switch from colorkey to alpha */
315 static void
SDL_ConvertColorkeyToAlpha(SDL_Surface * surface,SDL_bool ignore_alpha)316 SDL_ConvertColorkeyToAlpha(SDL_Surface * surface, SDL_bool ignore_alpha)
317 {
318     int x, y;
319 
320     if (!surface) {
321         return;
322     }
323 
324     if (!(surface->map->info.flags & SDL_COPY_COLORKEY) ||
325         !surface->format->Amask) {
326         return;
327     }
328 
329     SDL_LockSurface(surface);
330 
331     switch (surface->format->BytesPerPixel) {
332     case 2:
333         {
334             Uint16 *row, *spot;
335             Uint16 ckey = (Uint16) surface->map->info.colorkey;
336             Uint16 mask = (Uint16) (~surface->format->Amask);
337 
338             /* Ignore, or not, alpha in colorkey comparison */
339             if (ignore_alpha) {
340                 ckey &= mask;
341                 row = (Uint16 *) surface->pixels;
342                 for (y = surface->h; y--;) {
343                     spot = row;
344                     for (x = surface->w; x--;) {
345                         if ((*spot & mask) == ckey) {
346                             *spot &= mask;
347                         }
348                         ++spot;
349                     }
350                     row += surface->pitch / 2;
351                 }
352             } else {
353                 row = (Uint16 *) surface->pixels;
354                 for (y = surface->h; y--;) {
355                     spot = row;
356                     for (x = surface->w; x--;) {
357                         if (*spot == ckey) {
358                             *spot &= mask;
359                         }
360                         ++spot;
361                     }
362                     row += surface->pitch / 2;
363                 }
364             }
365         }
366         break;
367     case 3:
368         /* FIXME */
369         break;
370     case 4:
371         {
372             Uint32 *row, *spot;
373             Uint32 ckey = surface->map->info.colorkey;
374             Uint32 mask = ~surface->format->Amask;
375 
376             /* Ignore, or not, alpha in colorkey comparison */
377             if (ignore_alpha) {
378                 ckey &= mask;
379                 row = (Uint32 *) surface->pixels;
380                 for (y = surface->h; y--;) {
381                     spot = row;
382                     for (x = surface->w; x--;) {
383                         if ((*spot & mask) == ckey) {
384                             *spot &= mask;
385                         }
386                         ++spot;
387                     }
388                     row += surface->pitch / 4;
389                 }
390             } else {
391                 row = (Uint32 *) surface->pixels;
392                 for (y = surface->h; y--;) {
393                     spot = row;
394                     for (x = surface->w; x--;) {
395                         if (*spot == ckey) {
396                             *spot &= mask;
397                         }
398                         ++spot;
399                     }
400                     row += surface->pitch / 4;
401                 }
402             }
403         }
404         break;
405     }
406 
407     SDL_UnlockSurface(surface);
408 
409     SDL_SetColorKey(surface, 0, 0);
410     SDL_SetSurfaceBlendMode(surface, SDL_BLENDMODE_BLEND);
411 }
412 
413 int
SDL_SetSurfaceColorMod(SDL_Surface * surface,Uint8 r,Uint8 g,Uint8 b)414 SDL_SetSurfaceColorMod(SDL_Surface * surface, Uint8 r, Uint8 g, Uint8 b)
415 {
416     int flags;
417 
418     if (!surface) {
419         return -1;
420     }
421 
422     surface->map->info.r = r;
423     surface->map->info.g = g;
424     surface->map->info.b = b;
425 
426     flags = surface->map->info.flags;
427     if (r != 0xFF || g != 0xFF || b != 0xFF) {
428         surface->map->info.flags |= SDL_COPY_MODULATE_COLOR;
429     } else {
430         surface->map->info.flags &= ~SDL_COPY_MODULATE_COLOR;
431     }
432     if (surface->map->info.flags != flags) {
433         SDL_InvalidateMap(surface->map);
434     }
435     return 0;
436 }
437 
438 
439 int
SDL_GetSurfaceColorMod(SDL_Surface * surface,Uint8 * r,Uint8 * g,Uint8 * b)440 SDL_GetSurfaceColorMod(SDL_Surface * surface, Uint8 * r, Uint8 * g, Uint8 * b)
441 {
442     if (!surface) {
443         return -1;
444     }
445 
446     if (r) {
447         *r = surface->map->info.r;
448     }
449     if (g) {
450         *g = surface->map->info.g;
451     }
452     if (b) {
453         *b = surface->map->info.b;
454     }
455     return 0;
456 }
457 
458 int
SDL_SetSurfaceAlphaMod(SDL_Surface * surface,Uint8 alpha)459 SDL_SetSurfaceAlphaMod(SDL_Surface * surface, Uint8 alpha)
460 {
461     int flags;
462 
463     if (!surface) {
464         return -1;
465     }
466 
467     surface->map->info.a = alpha;
468 
469     flags = surface->map->info.flags;
470     if (alpha != 0xFF) {
471         surface->map->info.flags |= SDL_COPY_MODULATE_ALPHA;
472     } else {
473         surface->map->info.flags &= ~SDL_COPY_MODULATE_ALPHA;
474     }
475     if (surface->map->info.flags != flags) {
476         SDL_InvalidateMap(surface->map);
477     }
478     return 0;
479 }
480 
481 int
SDL_GetSurfaceAlphaMod(SDL_Surface * surface,Uint8 * alpha)482 SDL_GetSurfaceAlphaMod(SDL_Surface * surface, Uint8 * alpha)
483 {
484     if (!surface) {
485         return -1;
486     }
487 
488     if (alpha) {
489         *alpha = surface->map->info.a;
490     }
491     return 0;
492 }
493 
494 int
SDL_SetSurfaceBlendMode(SDL_Surface * surface,SDL_BlendMode blendMode)495 SDL_SetSurfaceBlendMode(SDL_Surface * surface, SDL_BlendMode blendMode)
496 {
497     int flags, status;
498 
499     if (!surface) {
500         return -1;
501     }
502 
503     status = 0;
504     flags = surface->map->info.flags;
505     surface->map->info.flags &=
506         ~(SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | SDL_COPY_MUL);
507     switch (blendMode) {
508     case SDL_BLENDMODE_NONE:
509         break;
510     case SDL_BLENDMODE_BLEND:
511         surface->map->info.flags |= SDL_COPY_BLEND;
512         break;
513     case SDL_BLENDMODE_ADD:
514         surface->map->info.flags |= SDL_COPY_ADD;
515         break;
516     case SDL_BLENDMODE_MOD:
517         surface->map->info.flags |= SDL_COPY_MOD;
518         break;
519     case SDL_BLENDMODE_MUL:
520         surface->map->info.flags |= SDL_COPY_MUL;
521         break;
522     default:
523         status = SDL_Unsupported();
524         break;
525     }
526 
527     if (surface->map->info.flags != flags) {
528         SDL_InvalidateMap(surface->map);
529     }
530 
531     return status;
532 }
533 
534 int
SDL_GetSurfaceBlendMode(SDL_Surface * surface,SDL_BlendMode * blendMode)535 SDL_GetSurfaceBlendMode(SDL_Surface * surface, SDL_BlendMode *blendMode)
536 {
537     if (!surface) {
538         return -1;
539     }
540 
541     if (!blendMode) {
542         return 0;
543     }
544 
545     switch (surface->map->
546             info.flags & (SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | SDL_COPY_MUL)) {
547     case SDL_COPY_BLEND:
548         *blendMode = SDL_BLENDMODE_BLEND;
549         break;
550     case SDL_COPY_ADD:
551         *blendMode = SDL_BLENDMODE_ADD;
552         break;
553     case SDL_COPY_MOD:
554         *blendMode = SDL_BLENDMODE_MOD;
555         break;
556     case SDL_COPY_MUL:
557         *blendMode = SDL_BLENDMODE_MUL;
558         break;
559     default:
560         *blendMode = SDL_BLENDMODE_NONE;
561         break;
562     }
563     return 0;
564 }
565 
566 SDL_bool
SDL_SetClipRect(SDL_Surface * surface,const SDL_Rect * rect)567 SDL_SetClipRect(SDL_Surface * surface, const SDL_Rect * rect)
568 {
569     SDL_Rect full_rect;
570 
571     /* Don't do anything if there's no surface to act on */
572     if (!surface) {
573         return SDL_FALSE;
574     }
575 
576     /* Set up the full surface rectangle */
577     full_rect.x = 0;
578     full_rect.y = 0;
579     full_rect.w = surface->w;
580     full_rect.h = surface->h;
581 
582     /* Set the clipping rectangle */
583     if (!rect) {
584         surface->clip_rect = full_rect;
585         return SDL_TRUE;
586     }
587     return SDL_IntersectRect(rect, &full_rect, &surface->clip_rect);
588 }
589 
590 void
SDL_GetClipRect(SDL_Surface * surface,SDL_Rect * rect)591 SDL_GetClipRect(SDL_Surface * surface, SDL_Rect * rect)
592 {
593     if (surface && rect) {
594         *rect = surface->clip_rect;
595     }
596 }
597 
598 /*
599  * Set up a blit between two surfaces -- split into three parts:
600  * The upper part, SDL_UpperBlit(), performs clipping and rectangle
601  * verification.  The lower part is a pointer to a low level
602  * accelerated blitting function.
603  *
604  * These parts are separated out and each used internally by this
605  * library in the optimimum places.  They are exported so that if
606  * you know exactly what you are doing, you can optimize your code
607  * by calling the one(s) you need.
608  */
609 int
SDL_LowerBlit(SDL_Surface * src,SDL_Rect * srcrect,SDL_Surface * dst,SDL_Rect * dstrect)610 SDL_LowerBlit(SDL_Surface * src, SDL_Rect * srcrect,
611               SDL_Surface * dst, SDL_Rect * dstrect)
612 {
613     /* Check to make sure the blit mapping is valid */
614     if ((src->map->dst != dst) ||
615         (dst->format->palette &&
616          src->map->dst_palette_version != dst->format->palette->version) ||
617         (src->format->palette &&
618          src->map->src_palette_version != src->format->palette->version)) {
619         if (SDL_MapSurface(src, dst) < 0) {
620             return (-1);
621         }
622         /* just here for debugging */
623 /*         printf */
624 /*             ("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", */
625 /*              src, dst->flags, src->map->info.flags, dst, dst->flags, */
626 /*              dst->map->info.flags, src->map->blit); */
627     }
628     return (src->map->blit(src, srcrect, dst, dstrect));
629 }
630 
631 
632 int
SDL_UpperBlit(SDL_Surface * src,const SDL_Rect * srcrect,SDL_Surface * dst,SDL_Rect * dstrect)633 SDL_UpperBlit(SDL_Surface * src, const SDL_Rect * srcrect,
634               SDL_Surface * dst, SDL_Rect * dstrect)
635 {
636     SDL_Rect fulldst;
637     int srcx, srcy, w, h;
638 
639     /* Make sure the surfaces aren't locked */
640     if (!src || !dst) {
641         return SDL_SetError("SDL_UpperBlit: passed a NULL surface");
642     }
643     if (src->locked || dst->locked) {
644         return SDL_SetError("Surfaces must not be locked during blit");
645     }
646 
647     /* If the destination rectangle is NULL, use the entire dest surface */
648     if (dstrect == NULL) {
649         fulldst.x = fulldst.y = 0;
650         fulldst.w = dst->w;
651         fulldst.h = dst->h;
652         dstrect = &fulldst;
653     }
654 
655     /* clip the source rectangle to the source surface */
656     if (srcrect) {
657         int maxw, maxh;
658 
659         srcx = srcrect->x;
660         w = srcrect->w;
661         if (srcx < 0) {
662             w += srcx;
663             dstrect->x -= srcx;
664             srcx = 0;
665         }
666         maxw = src->w - srcx;
667         if (maxw < w)
668             w = maxw;
669 
670         srcy = srcrect->y;
671         h = srcrect->h;
672         if (srcy < 0) {
673             h += srcy;
674             dstrect->y -= srcy;
675             srcy = 0;
676         }
677         maxh = src->h - srcy;
678         if (maxh < h)
679             h = maxh;
680 
681     } else {
682         srcx = srcy = 0;
683         w = src->w;
684         h = src->h;
685     }
686 
687     /* clip the destination rectangle against the clip rectangle */
688     {
689         SDL_Rect *clip = &dst->clip_rect;
690         int dx, dy;
691 
692         dx = clip->x - dstrect->x;
693         if (dx > 0) {
694             w -= dx;
695             dstrect->x += dx;
696             srcx += dx;
697         }
698         dx = dstrect->x + w - clip->x - clip->w;
699         if (dx > 0)
700             w -= dx;
701 
702         dy = clip->y - dstrect->y;
703         if (dy > 0) {
704             h -= dy;
705             dstrect->y += dy;
706             srcy += dy;
707         }
708         dy = dstrect->y + h - clip->y - clip->h;
709         if (dy > 0)
710             h -= dy;
711     }
712 
713     /* Switch back to a fast blit if we were previously stretching */
714     if (src->map->info.flags & SDL_COPY_NEAREST) {
715         src->map->info.flags &= ~SDL_COPY_NEAREST;
716         SDL_InvalidateMap(src->map);
717     }
718 
719     if (w > 0 && h > 0) {
720         SDL_Rect sr;
721         sr.x = srcx;
722         sr.y = srcy;
723         sr.w = dstrect->w = w;
724         sr.h = dstrect->h = h;
725         return SDL_LowerBlit(src, &sr, dst, dstrect);
726     }
727     dstrect->w = dstrect->h = 0;
728     return 0;
729 }
730 
731 int
SDL_UpperBlitScaled(SDL_Surface * src,const SDL_Rect * srcrect,SDL_Surface * dst,SDL_Rect * dstrect)732 SDL_UpperBlitScaled(SDL_Surface * src, const SDL_Rect * srcrect,
733               SDL_Surface * dst, SDL_Rect * dstrect)
734 {
735     double src_x0, src_y0, src_x1, src_y1;
736     double dst_x0, dst_y0, dst_x1, dst_y1;
737     SDL_Rect final_src, final_dst;
738     double scaling_w, scaling_h;
739     int src_w, src_h;
740     int dst_w, dst_h;
741 
742     /* Make sure the surfaces aren't locked */
743     if (!src || !dst) {
744         return SDL_SetError("SDL_UpperBlitScaled: passed a NULL surface");
745     }
746     if (src->locked || dst->locked) {
747         return SDL_SetError("Surfaces must not be locked during blit");
748     }
749 
750     if (NULL == srcrect) {
751         src_w = src->w;
752         src_h = src->h;
753     } else {
754         src_w = srcrect->w;
755         src_h = srcrect->h;
756     }
757 
758     if (NULL == dstrect) {
759         dst_w = dst->w;
760         dst_h = dst->h;
761     } else {
762         dst_w = dstrect->w;
763         dst_h = dstrect->h;
764     }
765 
766     if (dst_w == src_w && dst_h == src_h) {
767         /* No scaling, defer to regular blit */
768         return SDL_BlitSurface(src, srcrect, dst, dstrect);
769     }
770 
771     scaling_w = (double)dst_w / src_w;
772     scaling_h = (double)dst_h / src_h;
773 
774     if (NULL == dstrect) {
775         dst_x0 = 0;
776         dst_y0 = 0;
777         dst_x1 = dst_w - 1;
778         dst_y1 = dst_h - 1;
779     } else {
780         dst_x0 = dstrect->x;
781         dst_y0 = dstrect->y;
782         dst_x1 = dst_x0 + dst_w - 1;
783         dst_y1 = dst_y0 + dst_h - 1;
784     }
785 
786     if (NULL == srcrect) {
787         src_x0 = 0;
788         src_y0 = 0;
789         src_x1 = src_w - 1;
790         src_y1 = src_h - 1;
791     } else {
792         src_x0 = srcrect->x;
793         src_y0 = srcrect->y;
794         src_x1 = src_x0 + src_w - 1;
795         src_y1 = src_y0 + src_h - 1;
796 
797         /* Clip source rectangle to the source surface */
798 
799         if (src_x0 < 0) {
800             dst_x0 -= src_x0 * scaling_w;
801             src_x0 = 0;
802         }
803 
804         if (src_x1 >= src->w) {
805             dst_x1 -= (src_x1 - src->w + 1) * scaling_w;
806             src_x1 = src->w - 1;
807         }
808 
809         if (src_y0 < 0) {
810             dst_y0 -= src_y0 * scaling_h;
811             src_y0 = 0;
812         }
813 
814         if (src_y1 >= src->h) {
815             dst_y1 -= (src_y1 - src->h + 1) * scaling_h;
816             src_y1 = src->h - 1;
817         }
818     }
819 
820     /* Clip destination rectangle to the clip rectangle */
821 
822     /* Translate to clip space for easier calculations */
823     dst_x0 -= dst->clip_rect.x;
824     dst_x1 -= dst->clip_rect.x;
825     dst_y0 -= dst->clip_rect.y;
826     dst_y1 -= dst->clip_rect.y;
827 
828     if (dst_x0 < 0) {
829         src_x0 -= dst_x0 / scaling_w;
830         dst_x0 = 0;
831     }
832 
833     if (dst_x1 >= dst->clip_rect.w) {
834         src_x1 -= (dst_x1 - dst->clip_rect.w + 1) / scaling_w;
835         dst_x1 = dst->clip_rect.w - 1;
836     }
837 
838     if (dst_y0 < 0) {
839         src_y0 -= dst_y0 / scaling_h;
840         dst_y0 = 0;
841     }
842 
843     if (dst_y1 >= dst->clip_rect.h) {
844         src_y1 -= (dst_y1 - dst->clip_rect.h + 1) / scaling_h;
845         dst_y1 = dst->clip_rect.h - 1;
846     }
847 
848     /* Translate back to surface coordinates */
849     dst_x0 += dst->clip_rect.x;
850     dst_x1 += dst->clip_rect.x;
851     dst_y0 += dst->clip_rect.y;
852     dst_y1 += dst->clip_rect.y;
853 
854     final_src.x = (int)SDL_floor(src_x0 + 0.5);
855     final_src.y = (int)SDL_floor(src_y0 + 0.5);
856     final_src.w = (int)SDL_floor(src_x1 + 1 + 0.5) - (int)SDL_floor(src_x0 + 0.5);
857     final_src.h = (int)SDL_floor(src_y1 + 1 + 0.5) - (int)SDL_floor(src_y0 + 0.5);
858 
859     final_dst.x = (int)SDL_floor(dst_x0 + 0.5);
860     final_dst.y = (int)SDL_floor(dst_y0 + 0.5);
861     final_dst.w = (int)SDL_floor(dst_x1 - dst_x0 + 1.5);
862     final_dst.h = (int)SDL_floor(dst_y1 - dst_y0 + 1.5);
863 
864     if (final_dst.w < 0)
865         final_dst.w = 0;
866     if (final_dst.h < 0)
867         final_dst.h = 0;
868 
869     if (dstrect)
870         *dstrect = final_dst;
871 
872     if (final_dst.w == 0 || final_dst.h == 0 ||
873         final_src.w <= 0 || final_src.h <= 0) {
874         /* No-op. */
875         return 0;
876     }
877 
878     return SDL_LowerBlitScaled(src, &final_src, dst, &final_dst);
879 }
880 
881 /**
882  *  This is a semi-private blit function and it performs low-level surface
883  *  scaled blitting only.
884  */
885 int
SDL_LowerBlitScaled(SDL_Surface * src,SDL_Rect * srcrect,SDL_Surface * dst,SDL_Rect * dstrect)886 SDL_LowerBlitScaled(SDL_Surface * src, SDL_Rect * srcrect,
887                 SDL_Surface * dst, SDL_Rect * dstrect)
888 {
889     static const Uint32 complex_copy_flags = (
890         SDL_COPY_MODULATE_COLOR | SDL_COPY_MODULATE_ALPHA |
891         SDL_COPY_BLEND | SDL_COPY_ADD | SDL_COPY_MOD | SDL_COPY_MUL |
892         SDL_COPY_COLORKEY
893     );
894 
895     if (!(src->map->info.flags & SDL_COPY_NEAREST)) {
896         src->map->info.flags |= SDL_COPY_NEAREST;
897         SDL_InvalidateMap(src->map);
898     }
899 
900     if ( !(src->map->info.flags & complex_copy_flags) &&
901          src->format->format == dst->format->format &&
902          !SDL_ISPIXELFORMAT_INDEXED(src->format->format) ) {
903         return SDL_SoftStretch( src, srcrect, dst, dstrect );
904     } else {
905         return SDL_LowerBlit( src, srcrect, dst, dstrect );
906     }
907 }
908 
909 /*
910  * Lock a surface to directly access the pixels
911  */
912 int
SDL_LockSurface(SDL_Surface * surface)913 SDL_LockSurface(SDL_Surface * surface)
914 {
915     if (!surface->locked) {
916 #if SDL_HAVE_RLE
917         /* Perform the lock */
918         if (surface->flags & SDL_RLEACCEL) {
919             SDL_UnRLESurface(surface, 1);
920             surface->flags |= SDL_RLEACCEL;     /* save accel'd state */
921         }
922 #endif
923     }
924 
925     /* Increment the surface lock count, for recursive locks */
926     ++surface->locked;
927 
928     /* Ready to go.. */
929     return (0);
930 }
931 
932 /*
933  * Unlock a previously locked surface
934  */
935 void
SDL_UnlockSurface(SDL_Surface * surface)936 SDL_UnlockSurface(SDL_Surface * surface)
937 {
938     /* Only perform an unlock if we are locked */
939     if (!surface->locked || (--surface->locked > 0)) {
940         return;
941     }
942 
943 #if SDL_HAVE_RLE
944     /* Update RLE encoded surface with new data */
945     if ((surface->flags & SDL_RLEACCEL) == SDL_RLEACCEL) {
946         surface->flags &= ~SDL_RLEACCEL;        /* stop lying */
947         SDL_RLESurface(surface);
948     }
949 #endif
950 }
951 
952 /*
953  * Creates a new surface identical to the existing surface
954  */
955 SDL_Surface *
SDL_DuplicateSurface(SDL_Surface * surface)956 SDL_DuplicateSurface(SDL_Surface * surface)
957 {
958     return SDL_ConvertSurface(surface, surface->format, surface->flags);
959 }
960 
961 /*
962  * Convert a surface into the specified pixel format.
963  */
964 SDL_Surface *
SDL_ConvertSurface(SDL_Surface * surface,const SDL_PixelFormat * format,Uint32 flags)965 SDL_ConvertSurface(SDL_Surface * surface, const SDL_PixelFormat * format,
966                    Uint32 flags)
967 {
968     SDL_Surface *convert;
969     Uint32 copy_flags;
970     SDL_Color copy_color;
971     SDL_Rect bounds;
972     int ret;
973     SDL_bool palette_ck_transform = SDL_FALSE;
974     int palette_ck_value = 0;
975     SDL_bool palette_has_alpha = SDL_FALSE;
976     Uint8 *palette_saved_alpha = NULL;
977 
978     if (!surface) {
979         SDL_InvalidParamError("surface");
980         return NULL;
981     }
982     if (!format) {
983         SDL_InvalidParamError("format");
984         return NULL;
985     }
986 
987     /* Check for empty destination palette! (results in empty image) */
988     if (format->palette != NULL) {
989         int i;
990         for (i = 0; i < format->palette->ncolors; ++i) {
991             if ((format->palette->colors[i].r != 0xFF) ||
992                 (format->palette->colors[i].g != 0xFF) ||
993                 (format->palette->colors[i].b != 0xFF))
994                 break;
995         }
996         if (i == format->palette->ncolors) {
997             SDL_SetError("Empty destination palette");
998             return (NULL);
999         }
1000     }
1001 
1002     /* Create a new surface with the desired format */
1003     convert = SDL_CreateRGBSurface(flags, surface->w, surface->h,
1004                                    format->BitsPerPixel, format->Rmask,
1005                                    format->Gmask, format->Bmask,
1006                                    format->Amask);
1007     if (convert == NULL) {
1008         return (NULL);
1009     }
1010 
1011     /* Copy the palette if any */
1012     if (format->palette && convert->format->palette) {
1013         SDL_memcpy(convert->format->palette->colors,
1014                    format->palette->colors,
1015                    format->palette->ncolors * sizeof(SDL_Color));
1016         convert->format->palette->ncolors = format->palette->ncolors;
1017     }
1018 
1019     /* Save the original copy flags */
1020     copy_flags = surface->map->info.flags;
1021     copy_color.r = surface->map->info.r;
1022     copy_color.g = surface->map->info.g;
1023     copy_color.b = surface->map->info.b;
1024     copy_color.a = surface->map->info.a;
1025     surface->map->info.r = 0xFF;
1026     surface->map->info.g = 0xFF;
1027     surface->map->info.b = 0xFF;
1028     surface->map->info.a = 0xFF;
1029     surface->map->info.flags = 0;
1030     SDL_InvalidateMap(surface->map);
1031 
1032     /* Copy over the image data */
1033     bounds.x = 0;
1034     bounds.y = 0;
1035     bounds.w = surface->w;
1036     bounds.h = surface->h;
1037 
1038     /* Source surface has a palette with no real alpha (0 or OPAQUE).
1039      * Destination format has alpha.
1040      * -> set alpha channel to be opaque */
1041     if (surface->format->palette && format->Amask) {
1042         SDL_bool set_opaque = SDL_FALSE;
1043 
1044         SDL_bool is_opaque, has_alpha_channel;
1045         SDL_DetectPalette(surface->format->palette, &is_opaque, &has_alpha_channel);
1046 
1047         if (is_opaque) {
1048             if (!has_alpha_channel) {
1049                 set_opaque = SDL_TRUE;
1050             }
1051         } else {
1052             palette_has_alpha = SDL_TRUE;
1053         }
1054 
1055         /* Set opaque and backup palette alpha values */
1056         if (set_opaque) {
1057             int i;
1058             palette_saved_alpha = SDL_stack_alloc(Uint8, surface->format->palette->ncolors);
1059             for (i = 0; i < surface->format->palette->ncolors; i++) {
1060                 palette_saved_alpha[i] = surface->format->palette->colors[i].a;
1061                 surface->format->palette->colors[i].a = SDL_ALPHA_OPAQUE;
1062             }
1063         }
1064     }
1065 
1066     /* Transform colorkey to alpha. for cases where source palette has duplicate values, and colorkey is one of them */
1067     if (copy_flags & SDL_COPY_COLORKEY) {
1068         if (surface->format->palette && !format->palette) {
1069             palette_ck_transform = SDL_TRUE;
1070             palette_has_alpha = SDL_TRUE;
1071             palette_ck_value = surface->format->palette->colors[surface->map->info.colorkey].a;
1072             surface->format->palette->colors[surface->map->info.colorkey].a = SDL_ALPHA_TRANSPARENT;
1073         }
1074     }
1075 
1076     ret = SDL_LowerBlit(surface, &bounds, convert, &bounds);
1077 
1078     /* Restore colorkey alpha value */
1079     if (palette_ck_transform) {
1080         surface->format->palette->colors[surface->map->info.colorkey].a = palette_ck_value;
1081     }
1082 
1083     /* Restore palette alpha values */
1084     if (palette_saved_alpha) {
1085         int i;
1086         for (i = 0; i < surface->format->palette->ncolors; i++) {
1087             surface->format->palette->colors[i].a = palette_saved_alpha[i];
1088         }
1089         SDL_stack_free(palette_saved_alpha);
1090     }
1091 
1092     /* Clean up the original surface, and update converted surface */
1093     convert->map->info.r = copy_color.r;
1094     convert->map->info.g = copy_color.g;
1095     convert->map->info.b = copy_color.b;
1096     convert->map->info.a = copy_color.a;
1097     convert->map->info.flags =
1098         (copy_flags &
1099          ~(SDL_COPY_COLORKEY | SDL_COPY_BLEND
1100            | SDL_COPY_RLE_DESIRED | SDL_COPY_RLE_COLORKEY |
1101            SDL_COPY_RLE_ALPHAKEY));
1102     surface->map->info.r = copy_color.r;
1103     surface->map->info.g = copy_color.g;
1104     surface->map->info.b = copy_color.b;
1105     surface->map->info.a = copy_color.a;
1106     surface->map->info.flags = copy_flags;
1107     SDL_InvalidateMap(surface->map);
1108 
1109     /* SDL_LowerBlit failed, and so the conversion */
1110     if (ret < 0) {
1111         SDL_FreeSurface(convert);
1112         return NULL;
1113     }
1114 
1115     if (copy_flags & SDL_COPY_COLORKEY) {
1116         SDL_bool set_colorkey_by_color = SDL_FALSE;
1117         SDL_bool convert_colorkey = SDL_TRUE;
1118 
1119         if (surface->format->palette) {
1120             if (format->palette &&
1121                 surface->format->palette->ncolors <= format->palette->ncolors &&
1122                 (SDL_memcmp(surface->format->palette->colors, format->palette->colors,
1123                   surface->format->palette->ncolors * sizeof(SDL_Color)) == 0)) {
1124                 /* The palette is identical, just set the same colorkey */
1125                 SDL_SetColorKey(convert, 1, surface->map->info.colorkey);
1126             } else if (!format->palette) {
1127                 if (format->Amask) {
1128                     /* No need to add the colorkey, transparency is in the alpha channel*/
1129                 } else {
1130                     /* Only set the colorkey information */
1131                     set_colorkey_by_color = SDL_TRUE;
1132                     convert_colorkey = SDL_FALSE;
1133                 }
1134             } else {
1135                 set_colorkey_by_color = SDL_TRUE;
1136             }
1137         } else {
1138             set_colorkey_by_color = SDL_TRUE;
1139         }
1140 
1141         if (set_colorkey_by_color) {
1142             SDL_Surface *tmp;
1143             SDL_Surface *tmp2;
1144             int converted_colorkey = 0;
1145 
1146             /* Create a dummy surface to get the colorkey converted */
1147             tmp = SDL_CreateRGBSurface(0, 1, 1,
1148                                    surface->format->BitsPerPixel, surface->format->Rmask,
1149                                    surface->format->Gmask, surface->format->Bmask,
1150                                    surface->format->Amask);
1151 
1152             /* Share the palette, if any */
1153             if (surface->format->palette) {
1154                 SDL_SetSurfacePalette(tmp, surface->format->palette);
1155             }
1156 
1157             SDL_FillRect(tmp, NULL, surface->map->info.colorkey);
1158 
1159             tmp->map->info.flags &= ~SDL_COPY_COLORKEY;
1160 
1161             /* Convertion of the colorkey */
1162             tmp2 = SDL_ConvertSurface(tmp, format, 0);
1163 
1164             /* Get the converted colorkey */
1165             SDL_memcpy(&converted_colorkey, tmp2->pixels, tmp2->format->BytesPerPixel);
1166 
1167             SDL_FreeSurface(tmp);
1168             SDL_FreeSurface(tmp2);
1169 
1170             /* Set the converted colorkey on the new surface */
1171             SDL_SetColorKey(convert, 1, converted_colorkey);
1172 
1173             /* This is needed when converting for 3D texture upload */
1174             if (convert_colorkey) {
1175                 SDL_ConvertColorkeyToAlpha(convert, SDL_TRUE);
1176             }
1177         }
1178     }
1179     SDL_SetClipRect(convert, &surface->clip_rect);
1180 
1181     /* Enable alpha blending by default if the new surface has an
1182      * alpha channel or alpha modulation */
1183     if ((surface->format->Amask && format->Amask) ||
1184         (palette_has_alpha && format->Amask) ||
1185         (copy_flags & SDL_COPY_MODULATE_ALPHA)) {
1186         SDL_SetSurfaceBlendMode(convert, SDL_BLENDMODE_BLEND);
1187     }
1188     if ((copy_flags & SDL_COPY_RLE_DESIRED) || (flags & SDL_RLEACCEL)) {
1189         SDL_SetSurfaceRLE(convert, SDL_RLEACCEL);
1190     }
1191 
1192     /* We're ready to go! */
1193     return (convert);
1194 }
1195 
1196 SDL_Surface *
SDL_ConvertSurfaceFormat(SDL_Surface * surface,Uint32 pixel_format,Uint32 flags)1197 SDL_ConvertSurfaceFormat(SDL_Surface * surface, Uint32 pixel_format,
1198                          Uint32 flags)
1199 {
1200     SDL_PixelFormat *fmt;
1201     SDL_Surface *convert = NULL;
1202 
1203     fmt = SDL_AllocFormat(pixel_format);
1204     if (fmt) {
1205         convert = SDL_ConvertSurface(surface, fmt, flags);
1206         SDL_FreeFormat(fmt);
1207     }
1208     return convert;
1209 }
1210 
1211 /*
1212  * Create a surface on the stack for quick blit operations
1213  */
1214 static SDL_INLINE SDL_bool
SDL_CreateSurfaceOnStack(int width,int height,Uint32 pixel_format,void * pixels,int pitch,SDL_Surface * surface,SDL_PixelFormat * format,SDL_BlitMap * blitmap)1215 SDL_CreateSurfaceOnStack(int width, int height, Uint32 pixel_format,
1216                          void * pixels, int pitch, SDL_Surface * surface,
1217                          SDL_PixelFormat * format, SDL_BlitMap * blitmap)
1218 {
1219     if (SDL_ISPIXELFORMAT_INDEXED(pixel_format)) {
1220         SDL_SetError("Indexed pixel formats not supported");
1221         return SDL_FALSE;
1222     }
1223     if (SDL_InitFormat(format, pixel_format) < 0) {
1224         return SDL_FALSE;
1225     }
1226 
1227     SDL_zerop(surface);
1228     surface->flags = SDL_PREALLOC;
1229     surface->format = format;
1230     surface->pixels = pixels;
1231     surface->w = width;
1232     surface->h = height;
1233     surface->pitch = pitch;
1234     /* We don't actually need to set up the clip rect for our purposes */
1235     /* SDL_SetClipRect(surface, NULL); */
1236 
1237     /* Allocate an empty mapping */
1238     SDL_zerop(blitmap);
1239     blitmap->info.r = 0xFF;
1240     blitmap->info.g = 0xFF;
1241     blitmap->info.b = 0xFF;
1242     blitmap->info.a = 0xFF;
1243     surface->map = blitmap;
1244 
1245     /* The surface is ready to go */
1246     surface->refcount = 1;
1247     return SDL_TRUE;
1248 }
1249 
1250 /*
1251  * Copy a block of pixels of one format to another format
1252  */
SDL_ConvertPixels(int width,int height,Uint32 src_format,const void * src,int src_pitch,Uint32 dst_format,void * dst,int dst_pitch)1253 int SDL_ConvertPixels(int width, int height,
1254                       Uint32 src_format, const void * src, int src_pitch,
1255                       Uint32 dst_format, void * dst, int dst_pitch)
1256 {
1257     SDL_Surface src_surface, dst_surface;
1258     SDL_PixelFormat src_fmt, dst_fmt;
1259     SDL_BlitMap src_blitmap, dst_blitmap;
1260     SDL_Rect rect;
1261     void *nonconst_src = (void *) src;
1262 
1263     /* Check to make sure we are blitting somewhere, so we don't crash */
1264     if (!dst) {
1265         return SDL_InvalidParamError("dst");
1266     }
1267     if (!dst_pitch) {
1268         return SDL_InvalidParamError("dst_pitch");
1269     }
1270 
1271 #if SDL_HAVE_YUV
1272     if (SDL_ISPIXELFORMAT_FOURCC(src_format) && SDL_ISPIXELFORMAT_FOURCC(dst_format)) {
1273         return SDL_ConvertPixels_YUV_to_YUV(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch);
1274     } else if (SDL_ISPIXELFORMAT_FOURCC(src_format)) {
1275         return SDL_ConvertPixels_YUV_to_RGB(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch);
1276     } else if (SDL_ISPIXELFORMAT_FOURCC(dst_format)) {
1277         return SDL_ConvertPixels_RGB_to_YUV(width, height, src_format, src, src_pitch, dst_format, dst, dst_pitch);
1278     }
1279 #else
1280     if (SDL_ISPIXELFORMAT_FOURCC(src_format) || SDL_ISPIXELFORMAT_FOURCC(dst_format)) {
1281         SDL_SetError("SDL not built with YUV support");
1282         return -1;
1283     }
1284 #endif
1285 
1286     /* Fast path for same format copy */
1287     if (src_format == dst_format) {
1288         int i;
1289         const int bpp = SDL_BYTESPERPIXEL(src_format);
1290         width *= bpp;
1291         for (i = height; i--;) {
1292             SDL_memcpy(dst, src, width);
1293             src = (const Uint8*)src + src_pitch;
1294             dst = (Uint8*)dst + dst_pitch;
1295         }
1296         return 0;
1297     }
1298 
1299     if (!SDL_CreateSurfaceOnStack(width, height, src_format, nonconst_src,
1300                                   src_pitch,
1301                                   &src_surface, &src_fmt, &src_blitmap)) {
1302         return -1;
1303     }
1304     if (!SDL_CreateSurfaceOnStack(width, height, dst_format, dst, dst_pitch,
1305                                   &dst_surface, &dst_fmt, &dst_blitmap)) {
1306         return -1;
1307     }
1308 
1309     /* Set up the rect and go! */
1310     rect.x = 0;
1311     rect.y = 0;
1312     rect.w = width;
1313     rect.h = height;
1314     return SDL_LowerBlit(&src_surface, &rect, &dst_surface, &rect);
1315 }
1316 
1317 /*
1318  * Free a surface created by the above function.
1319  */
1320 void
SDL_FreeSurface(SDL_Surface * surface)1321 SDL_FreeSurface(SDL_Surface * surface)
1322 {
1323     if (surface == NULL) {
1324         return;
1325     }
1326     if (surface->flags & SDL_DONTFREE) {
1327         return;
1328     }
1329     SDL_InvalidateMap(surface->map);
1330 
1331     if (--surface->refcount > 0) {
1332         return;
1333     }
1334     while (surface->locked > 0) {
1335         SDL_UnlockSurface(surface);
1336     }
1337 #if SDL_HAVE_RLE
1338     if (surface->flags & SDL_RLEACCEL) {
1339         SDL_UnRLESurface(surface, 0);
1340     }
1341 #endif
1342     if (surface->format) {
1343         SDL_SetSurfacePalette(surface, NULL);
1344         SDL_FreeFormat(surface->format);
1345         surface->format = NULL;
1346     }
1347     if (surface->flags & SDL_PREALLOC) {
1348         /* Don't free */
1349     } else if (surface->flags & SDL_SIMD_ALIGNED) {
1350         /* Free aligned */
1351         SDL_SIMDFree(surface->pixels);
1352     } else {
1353         /* Normal */
1354         SDL_free(surface->pixels);
1355     }
1356     if (surface->map) {
1357         SDL_FreeBlitMap(surface->map);
1358     }
1359     SDL_free(surface);
1360 }
1361 
1362 /* vi: set ts=4 sw=4 expandtab: */
1363