Fix storing wxBitmap data in GdkPixbuf

Under wxGTK+2 bitmap data with mask and without it (raw) should be stored
in the separate GdkPixbuf buffers - just like it's done in wxGTK+3. These
two buffers are necessary because only GdkPixbuf with raw bitmap data
(original, non-masked) should be copied when wxBitmapRefData instance is
cloned e.g. in SetMask(). GdkPixbuf with masked data is not copied and is
created on first use in wxBitmap::GetPixbuf().

Closes #18508.
See #18498.
This commit is contained in:
Artur Wieczorek
2019-09-18 23:34:35 +02:00
parent a65c0c29ac
commit f7247086c2
2 changed files with 52 additions and 19 deletions

View File

@@ -133,7 +133,6 @@ public:
#endif #endif
#ifdef __WXGTK3__ #ifdef __WXGTK3__
GdkPixbuf* GetPixbufNoMask() const;
cairo_t* CairoCreate() const; cairo_t* CairoCreate() const;
void Draw(cairo_t* cr, int x, int y, bool useMask = true, const wxColour* fg = NULL, const wxColour* bg = NULL) const; void Draw(cairo_t* cr, int x, int y, bool useMask = true, const wxColour* fg = NULL, const wxColour* bg = NULL) const;
void SetSourceSurface(cairo_t* cr, int x, int y, const wxColour* fg = NULL, const wxColour* bg = NULL) const; void SetSourceSurface(cairo_t* cr, int x, int y, const wxColour* fg = NULL, const wxColour* bg = NULL) const;
@@ -143,6 +142,7 @@ public:
bool HasPixbuf() const; bool HasPixbuf() const;
wxBitmap(GdkPixmap* pixmap); wxBitmap(GdkPixmap* pixmap);
#endif #endif
GdkPixbuf* GetPixbufNoMask() const;
GdkPixbuf *GetPixbuf() const; GdkPixbuf *GetPixbuf() const;
// raw bitmap access support functions // raw bitmap access support functions

View File

@@ -58,7 +58,6 @@ static void MaskToAlpha(GdkPixmap* mask, GdkPixbuf* pixbuf, int w, int h)
{ {
for (int x = w; x; x--, p += 4, mask_data += 3) for (int x = w; x; x--, p += 4, mask_data += 3)
{ {
*p = 255;
// no need to test all 3 components, // no need to test all 3 components,
// pixels are either (0,0,0) or (0xff,0xff,0xff) // pixels are either (0,0,0) or (0xff,0xff,0xff)
if (mask_data[0] == 0) if (mask_data[0] == 0)
@@ -208,7 +207,7 @@ bool wxMask::InitFromColour(const wxBitmap& bitmap, const wxColour& colour)
const wxByte r_mask = colour.Red(); const wxByte r_mask = colour.Red();
const wxByte g_mask = colour.Green(); const wxByte g_mask = colour.Green();
const wxByte b_mask = colour.Blue(); const wxByte b_mask = colour.Blue();
GdkPixbuf* pixbuf = bitmap.GetPixbuf(); GdkPixbuf* pixbuf = bitmap.GetPixbufNoMask();
const wxByte* in = gdk_pixbuf_get_pixels(pixbuf); const wxByte* in = gdk_pixbuf_get_pixels(pixbuf);
const int inc = 3 + int(gdk_pixbuf_get_has_alpha(pixbuf) != 0); const int inc = 3 + int(gdk_pixbuf_get_has_alpha(pixbuf) != 0);
const int rowpadding = gdk_pixbuf_get_rowstride(pixbuf) - inc * w; const int rowpadding = gdk_pixbuf_get_rowstride(pixbuf) - inc * w;
@@ -333,7 +332,6 @@ public:
virtual bool IsOk() const wxOVERRIDE; virtual bool IsOk() const wxOVERRIDE;
#ifdef __WXGTK3__ #ifdef __WXGTK3__
GdkPixbuf* m_pixbufMask;
GdkPixbuf* m_pixbufNoMask; GdkPixbuf* m_pixbufNoMask;
cairo_surface_t* m_surface; cairo_surface_t* m_surface;
double m_scaleFactor; double m_scaleFactor;
@@ -341,6 +339,7 @@ public:
GdkPixmap *m_pixmap; GdkPixmap *m_pixmap;
GdkPixbuf *m_pixbuf; GdkPixbuf *m_pixbuf;
#endif #endif
GdkPixbuf *m_pixbufMask;
wxMask *m_mask; wxMask *m_mask;
int m_width; int m_width;
int m_height; int m_height;
@@ -359,7 +358,6 @@ public:
wxBitmapRefData::wxBitmapRefData(int width, int height, int depth) wxBitmapRefData::wxBitmapRefData(int width, int height, int depth)
{ {
#ifdef __WXGTK3__ #ifdef __WXGTK3__
m_pixbufMask = NULL;
m_pixbufNoMask = NULL; m_pixbufNoMask = NULL;
m_surface = NULL; m_surface = NULL;
m_scaleFactor = 1; m_scaleFactor = 1;
@@ -367,6 +365,7 @@ wxBitmapRefData::wxBitmapRefData(int width, int height, int depth)
m_pixmap = NULL; m_pixmap = NULL;
m_pixbuf = NULL; m_pixbuf = NULL;
#endif #endif
m_pixbufMask = NULL;
m_mask = NULL; m_mask = NULL;
m_width = width; m_width = width;
m_height = height; m_height = height;
@@ -384,13 +383,13 @@ wxBitmapRefData::wxBitmapRefData(int width, int height, int depth)
wxBitmapRefData::~wxBitmapRefData() wxBitmapRefData::~wxBitmapRefData()
{ {
#ifdef __WXGTK3__ #ifdef __WXGTK3__
if (m_pixbufMask)
g_object_unref(m_pixbufMask);
if (m_pixbufNoMask) if (m_pixbufNoMask)
g_object_unref(m_pixbufNoMask); g_object_unref(m_pixbufNoMask);
if (m_surface) if (m_surface)
cairo_surface_destroy(m_surface); cairo_surface_destroy(m_surface);
#else #else
if (m_pixbufMask)
g_object_unref(m_pixbufMask);
if (m_pixmap) if (m_pixmap)
g_object_unref (m_pixmap); g_object_unref (m_pixmap);
if (m_pixbuf) if (m_pixbuf)
@@ -542,7 +541,6 @@ bool wxBitmap::Create( int width, int height, int depth )
return true; return true;
} }
#ifdef __WXGTK3__
static void CopyImageData( static void CopyImageData(
guchar* dst, int dstChannels, int dstStride, guchar* dst, int dstChannels, int dstStride,
const guchar* src, int srcChannels, int srcStride, const guchar* src, int srcChannels, int srcStride,
@@ -587,7 +585,6 @@ static void CopyImageData(
} }
} }
} }
#endif
#if wxUSE_IMAGE #if wxUSE_IMAGE
#ifdef __WXGTK3__ #ifdef __WXGTK3__
@@ -1365,6 +1362,26 @@ void wxBitmap::Draw(cairo_t* cr, int x, int y, bool useMask, const wxColour* fg,
else else
cairo_paint(cr); cairo_paint(cr);
} }
#else
GdkPixbuf* wxBitmap::GetPixbufNoMask() const
{
wxCHECK_MSG(IsOk(), NULL, "invalid bitmap");
wxBitmapRefData* bmpData = M_BMPDATA;
GdkPixbuf* pixbuf = bmpData->m_pixbuf;
if (pixbuf)
return pixbuf;
const int w = bmpData->m_width;
const int h = bmpData->m_height;
pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, bmpData->m_alphaRequested, 8, w, h);
if ( bmpData->m_pixmap )
PixmapToPixbuf(bmpData->m_pixmap, pixbuf, w, h);
bmpData->m_pixbuf = pixbuf;
return pixbuf;
}
#endif #endif
GdkPixbuf *wxBitmap::GetPixbuf() const GdkPixbuf *wxBitmap::GetPixbuf() const
@@ -1405,21 +1422,31 @@ GdkPixbuf *wxBitmap::GetPixbuf() const
return bmpData->m_pixbufMask; return bmpData->m_pixbufMask;
#else #else
if (bmpData->m_pixbuf) if ( bmpData->m_pixbufMask )
return bmpData->m_pixbuf; return bmpData->m_pixbufMask;
const int w = bmpData->m_width; const int w = bmpData->m_width;
const int h = bmpData->m_height; const int h = bmpData->m_height;
if ( !bmpData->m_pixbuf )
GetPixbufNoMask();
GdkPixmap* mask = NULL; GdkPixmap* mask = NULL;
if (bmpData->m_mask) if (bmpData->m_mask)
mask = *bmpData->m_mask; mask = *bmpData->m_mask;
const bool useAlpha = bmpData->m_alphaRequested || mask;
bmpData->m_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, useAlpha, 8, w, h); if ( !mask )
if (bmpData->m_pixmap) return bmpData->m_pixbuf;
PixmapToPixbuf(bmpData->m_pixmap, bmpData->m_pixbuf, w, h);
if (mask) bmpData->m_pixbufMask = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, w, h);
MaskToAlpha(mask, bmpData->m_pixbuf, w, h); guchar* dst = gdk_pixbuf_get_pixels(bmpData->m_pixbufMask);
return bmpData->m_pixbuf; guchar* src = gdk_pixbuf_get_pixels(bmpData->m_pixbuf);
const int dstStride = gdk_pixbuf_get_rowstride(bmpData->m_pixbufMask);
const int srcStride = gdk_pixbuf_get_rowstride(bmpData->m_pixbuf);
CopyImageData(dst, 4, dstStride,
src, gdk_pixbuf_get_n_channels(bmpData->m_pixbuf), srcStride,
w, h);
MaskToAlpha(mask, bmpData->m_pixbufMask, w, h);
return bmpData->m_pixbufMask;
#endif #endif
} }
@@ -1471,11 +1498,17 @@ void *wxBitmap::GetRawData(wxPixelDataBase& data, int bpp)
} }
} }
#else #else
GdkPixbuf *pixbuf = GetPixbuf(); GdkPixbuf *pixbuf = GetPixbufNoMask();
// Pixmap will get out of date when our pixbuf is accessed directly, so // Pixmap will get out of date when our pixbuf is accessed directly, so
// ensure we don't keep the old data in it. // ensure we don't keep the old data in it.
PurgeOtherRepresentations(Pixbuf); PurgeOtherRepresentations(Pixbuf);
// Pixbuf with masked data will get out of date too
if ( M_BMPDATA->m_pixbufMask )
{
g_object_unref(M_BMPDATA->m_pixbufMask);
M_BMPDATA->m_pixbufMask = NULL;
}
const bool hasAlpha = HasAlpha(); const bool hasAlpha = HasAlpha();