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