Split SDL_BlitScaled into SDL_UpperBlitScaled and SDL_LowerBlitScaled.
authorKen Rogoway <ken@rogoway.com>
Sun, 13 Mar 2011 22:38:41 -0500
changeset 5499 2b8e6d1e3817
parent 5498 ef1db08c40ac
child 5501 f48c1e0ca9ae
Split SDL_BlitScaled into SDL_UpperBlitScaled and SDL_LowerBlitScaled. Fixed issue when calling SDL_BlitScaled() directly with src or dst rectangles that were out of bounds.
include/SDL_surface.h
src/video/SDL_surface.c
--- a/include/SDL_surface.h	Tue Mar 15 23:26:22 2011 -0700
+++ b/include/SDL_surface.h	Sun Mar 13 22:38:41 2011 -0500
@@ -466,15 +466,23 @@
                                             SDL_Surface * dst,
                                             const SDL_Rect * dstrect);
 
+#define SDL_BlitScaled SDL_UpperBlitScaled
+
 /**
- *  \brief Perform a fast, low quality, stretch blit between two surfaces of the
- *         different pixel formats.
- *  
- *  \note This function calls SDL_SoftStretch or SDL_LowerBlit.
+ *  This is the public scaled blit function, SDL_BlitScaled(), and it performs
+ *  rectangle validation and clipping before passing it to SDL_LowerBlitScaled()
  */
-extern DECLSPEC int SDLCALL SDL_BlitScaled
+extern DECLSPEC int SDLCALL SDL_UpperBlitScaled
     (SDL_Surface * src, const SDL_Rect * srcrect,
-    SDL_Surface * dst, const SDL_Rect * dstrect);
+    SDL_Surface * dst, SDL_Rect * dstrect);
+
+/**
+ *  This is a semi-private blit function and it performs low-level surface
+ *  scaled blitting only.
+ */
+extern DECLSPEC int SDLCALL SDL_LowerBlitScaled
+    (SDL_Surface * src, SDL_Rect * srcrect,
+    SDL_Surface * dst, SDL_Rect * dstrect);
 
 
 /* Ends C function definitions when using C++ */
--- a/src/video/SDL_surface.c	Tue Mar 15 23:26:22 2011 -0700
+++ b/src/video/SDL_surface.c	Sun Mar 13 22:38:41 2011 -0500
@@ -602,12 +602,101 @@
     return 0;
 }
 
-/*
- * Scale and blit a surface 
-*/
 int
-SDL_BlitScaled(SDL_Surface * src, const SDL_Rect * srcrect,
-               SDL_Surface * dst, const SDL_Rect * dstrect)
+SDL_UpperBlitScaled(SDL_Surface * src, const SDL_Rect * srcrect,
+              SDL_Surface * dst, SDL_Rect * dstrect)
+{
+    SDL_Rect final_src, final_dst, fulldst;
+
+    /* Make sure the surfaces aren't locked */
+    if (!src || !dst) {
+        SDL_SetError("SDL_UpperBlitScaled: passed a NULL surface");
+        return (-1);
+    }
+    if (src->locked || dst->locked) {
+        SDL_SetError("Surfaces must not be locked during blit");
+        return (-1);
+    }
+
+    /* If the destination rectangle is NULL, use the entire dest surface */
+    if (dstrect == NULL) {
+        fulldst.x = fulldst.y = 0;
+        dstrect = &fulldst;
+    }
+
+    /* clip the source rectangle to the source surface */
+    if (srcrect) {
+        int maxw, maxh;
+
+        final_src.x = srcrect->x;
+        final_src.w = srcrect->w;
+        if (final_src.x < 0) {
+            final_src.w += final_src.x;
+            final_src.x = 0;
+        }
+        maxw = src->w - final_src.x;
+        if (maxw < final_src.w)
+            final_src.w = maxw;
+
+        final_src.y = srcrect->y;
+        final_src.h = srcrect->h;
+        if (final_src.y < 0) {
+            final_src.h += final_src.y;
+            final_src.y = 0;
+        }
+        maxh = src->h - final_src.y;
+        if (maxh < final_src.h)
+            final_src.h = maxh;
+
+    } else {
+        final_src.x = final_src.y = 0;
+        final_src.w = src->w;
+        final_src.h = src->h;
+    }
+
+    /* clip the destination rectangle against the clip rectangle */
+    if (dstrect) {
+        int maxw, maxh;
+
+        final_dst.x = dstrect->x;
+        final_dst.w = dstrect->w;
+        if (final_dst.x < 0) {
+            final_dst.w += final_dst.x;
+            final_dst.x = 0;
+        }
+        maxw = dst->w - final_dst.x;
+        if (maxw < final_dst.w)
+            final_dst.w = maxw;
+
+        final_dst.y = dstrect->y;
+        final_dst.h = dstrect->h;
+        if (final_dst.y < 0) {
+            final_dst.h += final_dst.y;
+            final_dst.y = 0;
+        }
+        maxh = dst->h - final_dst.y;
+        if (maxh < final_dst.h)
+            final_dst.h = maxh;
+    } else {
+        final_dst.x = final_dst.y = 0;
+        final_dst.w = dst->w;
+        final_dst.h = dst->h;
+    }
+
+    if (final_dst.w > 0 && final_dst.h > 0) {
+        return SDL_LowerBlitScaled(src, &final_src, dst, &final_dst);
+    }
+
+    return 0;
+}
+
+/**
+ *  This is a semi-private blit function and it performs low-level surface
+ *  scaled blitting only.
+ */
+int
+SDL_LowerBlitScaled(SDL_Surface * src, SDL_Rect * srcrect,
+                SDL_Surface * dst, SDL_Rect * dstrect)
 {
     /* Save off the original dst width, height */
     int dstW = dstrect->w;
@@ -618,11 +707,6 @@
     /* Clip the dst surface to the dstrect */
     SDL_SetClipRect( dst, &final_dst );
 
-    /* If the dest was clipped to a zero sized rect then exit */
-    if ( dst->clip_rect.w <= 0 || dst->clip_rect.h <= 0 ) {
-        return -1;
-    }
-
     /* Did the dst width change? */
     if ( dstW != dst->clip_rect.w ) {
         /* scale the src width appropriately */