Commit 838bbf1f7a3c5a18a523fa6967222cac732767e9

Sylvain Becker 2020-03-17T09:35:42

Fixed bug 5037 - Regression 2.0.12 Alpha value of 0 on palette may become opaque (see also bug 3827)

diff --git a/src/render/SDL_render.c b/src/render/SDL_render.c
index 59c2f49..dfa70bc 100644
--- a/src/render/SDL_render.c
+++ b/src/render/SDL_render.c
@@ -1165,12 +1165,10 @@ SDL_CreateTextureFromSurface(SDL_Renderer * renderer, SDL_Surface * surface)
 
     /* If Palette contains alpha values, promotes to alpha format */
     if (fmt->palette) {
-        for (i = 0; i < fmt->palette->ncolors; i++) {
-            Uint8 alpha_value = fmt->palette->colors[i].a;
-            if (alpha_value != 0 && alpha_value != SDL_ALPHA_OPAQUE) {
-                needAlpha = SDL_TRUE;
-                break;
-            }
+        SDL_bool is_opaque, has_alpha_channel;
+        SDL_DetectPalette(fmt->palette, &is_opaque, &has_alpha_channel);
+        if (!is_opaque) {
+            needAlpha = SDL_TRUE;
         }
     }
 
diff --git a/src/video/SDL_pixels.c b/src/video/SDL_pixels.c
index f02a2bd..77de36c 100644
--- a/src/video/SDL_pixels.c
+++ b/src/video/SDL_pixels.c
@@ -801,6 +801,54 @@ SDL_FindColor(SDL_Palette * pal, Uint8 r, Uint8 g, Uint8 b, Uint8 a)
     return (pixel);
 }
 
+/* Tell whether palette is opaque, and if it has an alpha_channel */
+void
+SDL_DetectPalette(SDL_Palette *pal, SDL_bool *is_opaque, SDL_bool *has_alpha_channel)
+{
+    int i;
+
+    {
+        SDL_bool all_opaque = SDL_TRUE;
+        for (i = 0; i < pal->ncolors; i++) {
+            Uint8 alpha_value = pal->colors[i].a;
+            if (alpha_value != SDL_ALPHA_OPAQUE) {
+                all_opaque = SDL_FALSE;
+                break;
+            }
+        }
+
+        if (all_opaque) {
+            /* Palette is opaque, with an alpha channel */
+            *is_opaque = SDL_TRUE;
+            *has_alpha_channel = SDL_TRUE;
+            return;
+        }
+    }
+
+    {
+        SDL_bool all_transparent = SDL_TRUE;
+        for (i = 0; i < pal->ncolors; i++) {
+            Uint8 alpha_value = pal->colors[i].a;
+            if (alpha_value != SDL_ALPHA_TRANSPARENT) {
+                all_transparent = SDL_FALSE;
+                break;
+            }
+        }
+
+        if (all_transparent) {
+            /* Palette is opaque, without an alpha channel */
+            *is_opaque = SDL_TRUE;
+            *has_alpha_channel = SDL_FALSE;
+            return;
+        }
+    }
+
+    /* Palette has alpha values */
+    *is_opaque = SDL_FALSE;
+    *has_alpha_channel = SDL_TRUE;
+}
+
+
 /* Find the opaque pixel value corresponding to an RGB triple */
 Uint32
 SDL_MapRGB(const SDL_PixelFormat * format, Uint8 r, Uint8 g, Uint8 b)
diff --git a/src/video/SDL_pixels_c.h b/src/video/SDL_pixels_c.h
index c4baf41..8f511c0 100644
--- a/src/video/SDL_pixels_c.h
+++ b/src/video/SDL_pixels_c.h
@@ -40,6 +40,7 @@ extern void SDL_FreeBlitMap(SDL_BlitMap * map);
 /* Miscellaneous functions */
 extern void SDL_DitherColors(SDL_Color * colors, int bpp);
 extern Uint8 SDL_FindColor(SDL_Palette * pal, Uint8 r, Uint8 g, Uint8 b, Uint8 a);
+extern void SDL_DetectPalette(SDL_Palette *pal, SDL_bool *is_opaque, SDL_bool *has_alpha_channel);
 
 #endif /* SDL_pixels_c_h_ */
 
diff --git a/src/video/SDL_surface.c b/src/video/SDL_surface.c
index 3795b94..77a6bc8 100644
--- a/src/video/SDL_surface.c
+++ b/src/video/SDL_surface.c
@@ -1032,22 +1032,16 @@ SDL_ConvertSurface(SDL_Surface * surface, const SDL_PixelFormat * format,
      * -> set alpha channel to be opaque */
     if (surface->format->palette && format->Amask) {
         SDL_bool set_opaque = SDL_FALSE;
-        {
-            int i;
-            for (i = 0; i < surface->format->palette->ncolors; i++) {
-                Uint8 alpha_value = surface->format->palette->colors[i].a;
 
-                if (alpha_value != 0 && alpha_value != SDL_ALPHA_OPAQUE) {
-                    /* Palette has at least one alpha value. Don't do anything */
-                    set_opaque = SDL_FALSE;
-                    palette_has_alpha = SDL_TRUE;
-                    break;
-                }
+        SDL_bool is_opaque, has_alpha_channel;
+        SDL_DetectPalette(surface->format->palette, &is_opaque, &has_alpha_channel);
 
-                if (alpha_value == 0) {
-                    set_opaque = SDL_TRUE;
-                }
+        if (is_opaque) {
+            if (!has_alpha_channel) {
+                set_opaque = SDL_TRUE;
             }
+        } else {
+            palette_has_alpha = SDL_TRUE;
         }
 
         /* Set opaque and backup palette alpha values */