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:
@@ -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
|
||||||
|
@@ -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();
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user