From 8aa92738d04f773eb33b7a5f2cc65cd6e8c5cfc1 Mon Sep 17 00:00:00 2001 From: Ken Rogoway Date: Sun, 13 Mar 2011 22:38:41 -0500 Subject: [PATCH] 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 | 20 +++++--- src/video/SDL_surface.c | 104 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 108 insertions(+), 16 deletions(-) diff --git a/include/SDL_surface.h b/include/SDL_surface.h index 25f64d270..4bf003f26 100644 --- a/include/SDL_surface.h +++ b/include/SDL_surface.h @@ -466,15 +466,23 @@ extern DECLSPEC int SDLCALL SDL_SoftStretch(SDL_Surface * src, 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++ */ diff --git a/src/video/SDL_surface.c b/src/video/SDL_surface.c index 10fb5cf52..9e1684622 100644 --- a/src/video/SDL_surface.c +++ b/src/video/SDL_surface.c @@ -602,12 +602,101 @@ SDL_UpperBlit(SDL_Surface * src, const SDL_Rect * srcrect, 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 @@ SDL_BlitScaled(SDL_Surface * src, const SDL_Rect * srcrect, /* 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 */