Fixed bug #7614: Segmentation Fault in SDL_BlitSurface (#7808)

Update SDL_BlitSurface to use Intersect functions

(cherry picked from commit 3639743d8909406557663af0854dc7bd97956b24)
This commit is contained in:
Sylvain Becker 2024-01-19 17:39:57 +01:00 committed by Sam Lantinga
parent 87b5bb5840
commit bb969ac747

View file

@ -701,86 +701,65 @@ int SDL_LowerBlit(SDL_Surface *src, SDL_Rect *srcrect,
int SDL_UpperBlit(SDL_Surface *src, const SDL_Rect *srcrect, int SDL_UpperBlit(SDL_Surface *src, const SDL_Rect *srcrect,
SDL_Surface *dst, SDL_Rect *dstrect) SDL_Surface *dst, SDL_Rect *dstrect)
{ {
SDL_Rect fulldst; SDL_Rect r_src, r_dst;
int srcx, srcy;
Sint64 w, h;
/* Make sure the surfaces aren't locked */ /* Make sure the surfaces aren't locked */
if (!src || !dst) { if (!src) {
return SDL_InvalidParamError("SDL_UpperBlit(): src/dst"); return SDL_InvalidParamError("src");
} } else if (!dst) {
if (src->locked || dst->locked) { return SDL_InvalidParamError("dst");
} else if (src->locked || dst->locked) {
return SDL_SetError("Surfaces must not be locked during blit"); return SDL_SetError("Surfaces must not be locked during blit");
} }
/* If the destination rectangle is NULL, use the entire dest surface */ /* Full src surface */
if (!dstrect) { r_src.x = 0;
fulldst.x = fulldst.y = 0; r_src.y = 0;
fulldst.w = dst->w; r_src.w = src->w;
fulldst.h = dst->h; r_src.h = src->h;
dstrect = &fulldst;
if (dstrect) {
r_dst.x = dstrect->x;
r_dst.y = dstrect->y;
} else {
r_dst.x = 0;
r_dst.y = 0;
} }
/* clip the source rectangle to the source surface */ /* clip the source rectangle to the source surface */
if (srcrect) { if (srcrect) {
int maxw, maxh; SDL_Rect tmp;
if (SDL_IntersectRect(srcrect, &r_src, &tmp) == SDL_FALSE) {
srcx = srcrect->x; goto end;
w = srcrect->w;
if (srcx < 0) {
w += srcx;
dstrect->x -= srcx;
srcx = 0;
}
maxw = src->w - srcx;
if (maxw < w) {
w = maxw;
} }
srcy = srcrect->y; /* Shift dstrect, if srcrect origin has changed */
h = srcrect->h; r_dst.x += tmp.x - srcrect->x;
if (srcy < 0) { r_dst.y += tmp.y - srcrect->y;
h += srcy;
dstrect->y -= srcy;
srcy = 0;
}
maxh = src->h - srcy;
if (maxh < h) {
h = maxh;
}
} else { /* Update srcrect */
srcx = srcy = 0; r_src = tmp;
w = src->w;
h = src->h;
} }
/* There're no dstrect.w/h parameters. It's the same as srcrect */
r_dst.w = r_src.w;
r_dst.h = r_src.h;
/* clip the destination rectangle against the clip rectangle */ /* clip the destination rectangle against the clip rectangle */
{ {
SDL_Rect *clip = &dst->clip_rect; SDL_Rect tmp;
int dx, dy; if (SDL_IntersectRect(&r_dst, &dst->clip_rect, &tmp) == SDL_FALSE) {
goto end;
dx = clip->x - dstrect->x;
if (dx > 0) {
w -= dx;
dstrect->x += dx;
srcx += dx;
}
dx = dstrect->x + w - clip->x - clip->w;
if (dx > 0) {
w -= dx;
} }
dy = clip->y - dstrect->y; /* Shift srcrect, if dstrect has changed */
if (dy > 0) { r_src.x += tmp.x - r_dst.x;
h -= dy; r_src.y += tmp.y - r_dst.y;
dstrect->y += dy; r_src.w = tmp.w;
srcy += dy; r_src.h = tmp.h;
}
dy = dstrect->y + h - clip->y - clip->h; /* Update dstrect */
if (dy > 0) { r_dst = tmp;
h -= dy;
}
} }
/* Switch back to a fast blit if we were previously stretching */ /* Switch back to a fast blit if we were previously stretching */
@ -789,15 +768,17 @@ int SDL_UpperBlit(SDL_Surface *src, const SDL_Rect *srcrect,
SDL_InvalidateMap(src->map); SDL_InvalidateMap(src->map);
} }
if (w > 0 && h > 0) { if (r_dst.w > 0 && r_dst.h > 0) {
SDL_Rect sr; if (dstrect) { /* update output parameter */
sr.x = srcx; *dstrect = r_dst;
sr.y = srcy; }
sr.w = dstrect->w = w; return SDL_LowerBlit(src, &r_src, dst, dstrect);
sr.h = dstrect->h = h; }
return SDL_LowerBlit(src, &sr, dst, dstrect);
end:
if (dstrect) { /* update output parameter */
dstrect->w = dstrect->h = 0;
} }
dstrect->w = dstrect->h = 0;
return 0; return 0;
} }