~registry/dolphin-emu/triforce

« back to all changes in this revision

Viewing changes to Externals/wxWidgets3/src/gtk/bitmap.cpp

  • Committer: Sérgio Benjamim
  • Date: 2015-02-13 05:54:40 UTC
  • Revision ID: sergio_br2@yahoo.com.br-20150213055440-ey2rt3sjpy27km78
Dolphin Triforce branch from code.google, commit b957980 (4.0-315).

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/////////////////////////////////////////////////////////////////////////////
 
2
// Name:        src/gtk/bitmap.cpp
 
3
// Purpose:
 
4
// Author:      Robert Roebling
 
5
// Copyright:   (c) 1998 Robert Roebling
 
6
// Licence:     wxWindows licence
 
7
/////////////////////////////////////////////////////////////////////////////
 
8
 
 
9
// For compilers that support precompilation, includes "wx.h".
 
10
#include "wx/wxprec.h"
 
11
 
 
12
#include "wx/bitmap.h"
 
13
 
 
14
#ifndef WX_PRECOMP
 
15
    #include "wx/icon.h"
 
16
    #include "wx/image.h"
 
17
    #include "wx/colour.h"
 
18
#endif
 
19
 
 
20
#include "wx/rawbmp.h"
 
21
 
 
22
#include "wx/gtk/private/object.h"
 
23
#include "wx/gtk/private.h"
 
24
 
 
25
#include <gtk/gtk.h>
 
26
 
 
27
extern GtkWidget *wxGetRootWindow();
 
28
 
 
29
#ifndef __WXGTK3__
 
30
static void PixmapToPixbuf(GdkPixmap* pixmap, GdkPixbuf* pixbuf, int w, int h)
 
31
{
 
32
    gdk_pixbuf_get_from_drawable(pixbuf, pixmap, NULL, 0, 0, 0, 0, w, h);
 
33
    if (gdk_drawable_get_depth(pixmap) == 1)
 
34
    {
 
35
        // invert to match XBM convention
 
36
        guchar* p = gdk_pixbuf_get_pixels(pixbuf);
 
37
        const int inc = 3 + int(gdk_pixbuf_get_has_alpha(pixbuf) != 0);
 
38
        const int rowpad = gdk_pixbuf_get_rowstride(pixbuf) - w * inc;
 
39
        for (int y = h; y; y--, p += rowpad)
 
40
            for (int x = w; x; x--, p += inc)
 
41
            {
 
42
                // pixels are either (0,0,0) or (0xff,0xff,0xff)
 
43
                p[0] = ~p[0];
 
44
                p[1] = ~p[1];
 
45
                p[2] = ~p[2];
 
46
            }
 
47
    }
 
48
}
 
49
 
 
50
static void MaskToAlpha(GdkPixmap* mask, GdkPixbuf* pixbuf, int w, int h)
 
51
{
 
52
    GdkPixbuf* mask_pixbuf = gdk_pixbuf_get_from_drawable(
 
53
        NULL, mask, NULL, 0, 0, 0, 0, w, h);
 
54
    guchar* p = gdk_pixbuf_get_pixels(pixbuf) + 3;
 
55
    const guchar* mask_data = gdk_pixbuf_get_pixels(mask_pixbuf);
 
56
    const int rowpad = gdk_pixbuf_get_rowstride(pixbuf) - w * 4;
 
57
    const int mask_rowpad = gdk_pixbuf_get_rowstride(mask_pixbuf) - w * 3;
 
58
    for (int y = h; y; y--, p += rowpad, mask_data += mask_rowpad)
 
59
    {
 
60
        for (int x = w; x; x--, p += 4, mask_data += 3)
 
61
        {
 
62
            *p = 255;
 
63
            // no need to test all 3 components,
 
64
            //   pixels are either (0,0,0) or (0xff,0xff,0xff)
 
65
            if (mask_data[0] == 0)
 
66
                *p = 0;
 
67
        }
 
68
    }
 
69
    g_object_unref(mask_pixbuf);
 
70
}
 
71
#endif
 
72
 
 
73
//-----------------------------------------------------------------------------
 
74
// wxMask
 
75
//-----------------------------------------------------------------------------
 
76
 
 
77
IMPLEMENT_DYNAMIC_CLASS(wxMask, wxMaskBase)
 
78
 
 
79
wxMask::wxMask()
 
80
{
 
81
    m_bitmap = NULL;
 
82
}
 
83
 
 
84
wxMask::wxMask(const wxMask& mask)
 
85
{
 
86
#ifdef __WXGTK3__
 
87
    m_bitmap = NULL;
 
88
    if (mask.m_bitmap)
 
89
    {
 
90
        const int w = cairo_image_surface_get_width(mask.m_bitmap);
 
91
        const int h = cairo_image_surface_get_height(mask.m_bitmap);
 
92
        m_bitmap = cairo_image_surface_create(CAIRO_FORMAT_A8, w, h);
 
93
        const guchar* src = cairo_image_surface_get_data(mask.m_bitmap);
 
94
        guchar* dst = cairo_image_surface_get_data(m_bitmap);
 
95
        const int stride = cairo_image_surface_get_stride(m_bitmap);
 
96
        wxASSERT(stride == cairo_image_surface_get_stride(mask.m_bitmap));
 
97
        memcpy(dst, src, stride * h);
 
98
        cairo_surface_mark_dirty(m_bitmap);
 
99
    }
 
100
#else
 
101
    if ( !mask.m_bitmap )
 
102
    {
 
103
        m_bitmap = NULL;
 
104
        return;
 
105
    }
 
106
 
 
107
    // create a copy of an existing mask
 
108
    gint w, h;
 
109
    gdk_drawable_get_size(mask.m_bitmap, &w, &h);
 
110
    m_bitmap = gdk_pixmap_new(mask.m_bitmap, w, h, 1);
 
111
 
 
112
    wxGtkObject<GdkGC> gc(gdk_gc_new(m_bitmap));
 
113
    gdk_draw_drawable(m_bitmap, gc, mask.m_bitmap, 0, 0, 0, 0, -1, -1);
 
114
#endif
 
115
}
 
116
 
 
117
wxMask::wxMask( const wxBitmap& bitmap, const wxColour& colour )
 
118
{
 
119
    m_bitmap = NULL;
 
120
    InitFromColour(bitmap, colour);
 
121
}
 
122
 
 
123
#if wxUSE_PALETTE
 
124
wxMask::wxMask( const wxBitmap& bitmap, int paletteIndex )
 
125
{
 
126
    m_bitmap = NULL;
 
127
    Create( bitmap, paletteIndex );
 
128
}
 
129
#endif // wxUSE_PALETTE
 
130
 
 
131
wxMask::wxMask( const wxBitmap& bitmap )
 
132
{
 
133
    m_bitmap = NULL;
 
134
    InitFromMonoBitmap(bitmap);
 
135
}
 
136
 
 
137
#ifdef __WXGTK3__
 
138
wxMask::wxMask(cairo_surface_t* bitmap)
 
139
#else
 
140
wxMask::wxMask(GdkPixmap* bitmap)
 
141
#endif
 
142
{
 
143
    m_bitmap = bitmap;
 
144
}
 
145
 
 
146
wxMask::~wxMask()
 
147
{
 
148
    if (m_bitmap)
 
149
    {
 
150
#ifdef __WXGTK3__
 
151
        cairo_surface_destroy(m_bitmap);
 
152
#else
 
153
        g_object_unref (m_bitmap);
 
154
#endif
 
155
    }
 
156
}
 
157
 
 
158
void wxMask::FreeData()
 
159
{
 
160
    if (m_bitmap)
 
161
    {
 
162
#ifdef __WXGTK3__
 
163
        cairo_surface_destroy(m_bitmap);
 
164
#else
 
165
        g_object_unref (m_bitmap);
 
166
#endif
 
167
        m_bitmap = NULL;
 
168
    }
 
169
}
 
170
 
 
171
bool wxMask::InitFromColour(const wxBitmap& bitmap, const wxColour& colour)
 
172
{
 
173
    const int w = bitmap.GetWidth();
 
174
    const int h = bitmap.GetHeight();
 
175
 
 
176
#ifdef __WXGTK3__
 
177
    m_bitmap = cairo_image_surface_create(CAIRO_FORMAT_A8, w, h);
 
178
    GdkPixbuf* pixbuf = bitmap.GetPixbufNoMask();
 
179
    const guchar* src = gdk_pixbuf_get_pixels(pixbuf);
 
180
    guchar* dst = cairo_image_surface_get_data(m_bitmap);
 
181
    const int stride_src = gdk_pixbuf_get_rowstride(pixbuf);
 
182
    const int stride_dst = cairo_image_surface_get_stride(m_bitmap);
 
183
    const int src_inc = gdk_pixbuf_get_n_channels(pixbuf);
 
184
    const guchar r = colour.Red();
 
185
    const guchar g = colour.Green();
 
186
    const guchar b = colour.Blue();
 
187
    for (int j = 0; j < h; j++, src += stride_src, dst += stride_dst)
 
188
    {
 
189
        const guchar* s = src;
 
190
        for (int i = 0; i < w; i++, s += src_inc)
 
191
        {
 
192
            dst[i] = 0xff;
 
193
            if (s[0] == r && s[1] == g && s[2] == b)
 
194
                dst[i] = 0;
 
195
        }
 
196
    }
 
197
    cairo_surface_mark_dirty(m_bitmap);
 
198
#else
 
199
    // create mask as XBM format bitmap
 
200
 
 
201
    // one bit per pixel, each row starts on a byte boundary
 
202
    const size_t out_size = size_t((w + 7) / 8) * unsigned(h);
 
203
    wxByte* out = new wxByte[out_size];
 
204
    // set bits are unmasked
 
205
    memset(out, 0xff, out_size);
 
206
    unsigned bit_index = 0;
 
207
    if (bitmap.HasPixbuf())
 
208
    {
 
209
        const wxByte r_mask = colour.Red();
 
210
        const wxByte g_mask = colour.Green();
 
211
        const wxByte b_mask = colour.Blue();
 
212
        GdkPixbuf* pixbuf = bitmap.GetPixbuf();
 
213
        const wxByte* in = gdk_pixbuf_get_pixels(pixbuf);
 
214
        const int inc = 3 + int(gdk_pixbuf_get_has_alpha(pixbuf) != 0);
 
215
        const int rowpadding = gdk_pixbuf_get_rowstride(pixbuf) - inc * w;
 
216
        for (int y = 0; y < h; y++, in += rowpadding)
 
217
        {
 
218
            for (int x = 0; x < w; x++, in += inc, bit_index++)
 
219
                if (in[0] == r_mask && in[1] == g_mask && in[2] == b_mask)
 
220
                    out[bit_index >> 3] ^= 1 << (bit_index & 7);
 
221
            // move index to next byte boundary
 
222
            bit_index = (bit_index + 7) & ~7u;
 
223
        }
 
224
    }
 
225
    else
 
226
    {
 
227
        GdkImage* image = gdk_drawable_get_image(bitmap.GetPixmap(), 0, 0, w, h);
 
228
        GdkColormap* colormap = gdk_image_get_colormap(image);
 
229
        guint32 mask_pixel;
 
230
        if (colormap == NULL)
 
231
            // mono bitmap, white is pixel value 0
 
232
            mask_pixel = guint32(colour.Red() != 255 || colour.Green() != 255 || colour.Blue() != 255);
 
233
        else
 
234
        {
 
235
            wxColor c(colour);
 
236
            c.CalcPixel(colormap);
 
237
            mask_pixel = c.GetPixel();
 
238
        }
 
239
        for (int y = 0; y < h; y++)
 
240
        {
 
241
            for (int x = 0; x < w; x++, bit_index++)
 
242
                if (gdk_image_get_pixel(image, x, y) == mask_pixel)
 
243
                    out[bit_index >> 3] ^= 1 << (bit_index & 7);
 
244
            bit_index = (bit_index + 7) & ~7u;
 
245
        }
 
246
        g_object_unref(image);
 
247
    }
 
248
    m_bitmap = gdk_bitmap_create_from_data(wxGetRootWindow()->window, (char*)out, w, h);
 
249
    delete[] out;
 
250
#endif
 
251
    return true;
 
252
}
 
253
 
 
254
bool wxMask::InitFromMonoBitmap(const wxBitmap& bitmap)
 
255
{
 
256
    if (!bitmap.IsOk()) return false;
 
257
 
 
258
    wxCHECK_MSG( bitmap.GetDepth() == 1, false, wxT("Cannot create mask from colour bitmap") );
 
259
 
 
260
#ifdef __WXGTK3__
 
261
    InitFromColour(bitmap, *wxBLACK);
 
262
#else
 
263
    m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, bitmap.GetWidth(), bitmap.GetHeight(), 1 );
 
264
 
 
265
    if (!m_bitmap) return false;
 
266
 
 
267
    wxGtkObject<GdkGC> gc(gdk_gc_new( m_bitmap ));
 
268
    gdk_gc_set_function(gc, GDK_COPY_INVERT);
 
269
    gdk_draw_drawable(m_bitmap, gc, bitmap.GetPixmap(), 0, 0, 0, 0, bitmap.GetWidth(), bitmap.GetHeight());
 
270
#endif
 
271
 
 
272
    return true;
 
273
}
 
274
 
 
275
wxBitmap wxMask::GetBitmap() const
 
276
{
 
277
    wxBitmap bitmap;
 
278
    if (m_bitmap)
 
279
    {
 
280
#ifdef __WXGTK3__
 
281
        cairo_surface_t* mask = m_bitmap;
 
282
        const int w = cairo_image_surface_get_width(mask);
 
283
        const int h = cairo_image_surface_get_height(mask);
 
284
        GdkPixbuf* pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, false, 8, w, h);
 
285
        const guchar* src = cairo_image_surface_get_data(mask);
 
286
        guchar* dst = gdk_pixbuf_get_pixels(pixbuf);
 
287
        const int stride_src = cairo_image_surface_get_stride(mask);
 
288
        const int stride_dst = gdk_pixbuf_get_rowstride(pixbuf);
 
289
        for (int j = 0; j < h; j++, src += stride_src, dst += stride_dst)
 
290
        {
 
291
            guchar* d = dst;
 
292
            for (int i = 0; i < w; i++, d += 3)
 
293
            {
 
294
                d[0] = src[i];
 
295
                d[1] = src[i];
 
296
                d[2] = src[i];
 
297
            }
 
298
        }
 
299
        bitmap = wxBitmap(pixbuf, 1);
 
300
#else
 
301
        GdkPixmap* mask = m_bitmap;
 
302
        int w, h;
 
303
        gdk_drawable_get_size(mask, &w, &h);
 
304
        GdkPixmap* pixmap = gdk_pixmap_new(mask, w, h, -1);
 
305
        GdkGC* gc = gdk_gc_new(pixmap);
 
306
        gdk_gc_set_function(gc, GDK_COPY_INVERT);
 
307
        gdk_draw_drawable(pixmap, gc, mask, 0, 0, 0, 0, w, h);
 
308
        g_object_unref(gc);
 
309
        bitmap = wxBitmap(pixmap);
 
310
#endif
 
311
    }
 
312
    return bitmap;
 
313
}
 
314
 
 
315
#ifdef __WXGTK3__
 
316
wxMask::operator cairo_surface_t*() const
 
317
#else
 
318
wxMask::operator GdkPixmap*() const
 
319
#endif
 
320
{
 
321
    return m_bitmap;
 
322
}
 
323
 
 
324
//-----------------------------------------------------------------------------
 
325
// wxBitmapRefData
 
326
//-----------------------------------------------------------------------------
 
327
 
 
328
class wxBitmapRefData: public wxGDIRefData
 
329
{
 
330
public:
 
331
    wxBitmapRefData(int width, int height, int depth);
 
332
    virtual ~wxBitmapRefData();
 
333
 
 
334
    virtual bool IsOk() const;
 
335
 
 
336
#ifdef __WXGTK3__
 
337
    GdkPixbuf* m_pixbufMask;
 
338
    GdkPixbuf* m_pixbufNoMask;
 
339
    cairo_surface_t* m_surface;
 
340
#else
 
341
    GdkPixmap      *m_pixmap;
 
342
    GdkPixbuf      *m_pixbuf;
 
343
#endif
 
344
    wxMask         *m_mask;
 
345
    int             m_width;
 
346
    int             m_height;
 
347
    int             m_bpp;
 
348
#ifndef __WXGTK3__
 
349
    bool m_alphaRequested;
 
350
#endif
 
351
 
 
352
    // We don't provide a copy ctor as copying m_pixmap and m_pixbuf properly
 
353
    // is expensive and we don't want to do it implicitly (and possibly
 
354
    // accidentally). wxBitmap::CloneGDIRefData() which does need to do it does
 
355
    // it explicitly itself.
 
356
    wxDECLARE_NO_COPY_CLASS(wxBitmapRefData);
 
357
};
 
358
 
 
359
wxBitmapRefData::wxBitmapRefData(int width, int height, int depth)
 
360
{
 
361
#ifdef __WXGTK3__
 
362
    m_pixbufMask = NULL;
 
363
    m_pixbufNoMask = NULL;
 
364
    m_surface = NULL;
 
365
#else
 
366
    m_pixmap = NULL;
 
367
    m_pixbuf = NULL;
 
368
#endif
 
369
    m_mask = NULL;
 
370
    m_width = width;
 
371
    m_height = height;
 
372
    m_bpp = depth;
 
373
#ifdef __WXGTK3__
 
374
    if (m_bpp != 1 && m_bpp != 32)
 
375
        m_bpp = 24;
 
376
#else
 
377
    if (m_bpp < 0)
 
378
        m_bpp = gdk_drawable_get_depth(wxGetRootWindow()->window);
 
379
    m_alphaRequested = depth == 32;
 
380
#endif
 
381
}
 
382
 
 
383
wxBitmapRefData::~wxBitmapRefData()
 
384
{
 
385
#ifdef __WXGTK3__
 
386
    if (m_pixbufMask)
 
387
        g_object_unref(m_pixbufMask);
 
388
    if (m_pixbufNoMask)
 
389
        g_object_unref(m_pixbufNoMask);
 
390
    if (m_surface)
 
391
        cairo_surface_destroy(m_surface);
 
392
#else
 
393
    if (m_pixmap)
 
394
        g_object_unref (m_pixmap);
 
395
    if (m_pixbuf)
 
396
        g_object_unref (m_pixbuf);
 
397
#endif
 
398
    delete m_mask;
 
399
}
 
400
 
 
401
bool wxBitmapRefData::IsOk() const
 
402
{
 
403
    return m_bpp != 0;
 
404
}
 
405
 
 
406
//-----------------------------------------------------------------------------
 
407
// wxBitmap
 
408
//-----------------------------------------------------------------------------
 
409
 
 
410
#define M_BMPDATA static_cast<wxBitmapRefData*>(m_refData)
 
411
 
 
412
IMPLEMENT_DYNAMIC_CLASS(wxBitmap,wxGDIObject)
 
413
 
 
414
wxBitmap::wxBitmap(const wxString &filename, wxBitmapType type)
 
415
{
 
416
    LoadFile(filename, type);
 
417
}
 
418
 
 
419
wxBitmap::wxBitmap(const char bits[], int width, int height, int depth)
 
420
{
 
421
    wxASSERT(depth == 1);
 
422
    if (width > 0 && height > 0 && depth == 1)
 
423
    {
 
424
        m_refData = new wxBitmapRefData(width, height, 1);
 
425
#ifdef __WXGTK3__
 
426
        GdkPixbuf* pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, false, 8, width, height);
 
427
        M_BMPDATA->m_pixbufNoMask = pixbuf;
 
428
        const char* src = bits;
 
429
        guchar* dst = gdk_pixbuf_get_pixels(pixbuf);
 
430
        const int stride_src = (width + 7) / 8;
 
431
        const int rowinc_dst = gdk_pixbuf_get_rowstride(pixbuf) - 3 * width;
 
432
        for (int j = 0; j < width; j++, src += stride_src, dst += rowinc_dst)
 
433
        {
 
434
            for (int i = 0; i < height; i++)
 
435
            {
 
436
                guchar c = 0xff;
 
437
                if (src[i >> 3] & (1 << (i & 7)))
 
438
                    c = 0;
 
439
                *dst++ = c;
 
440
                *dst++ = c;
 
441
                *dst++ = c;
 
442
            }
 
443
        }
 
444
#else
 
445
        M_BMPDATA->m_pixmap = gdk_bitmap_create_from_data(
 
446
            wxGetRootWindow()->window, bits, width, height);
 
447
#endif
 
448
    }
 
449
}
 
450
 
 
451
wxBitmap::wxBitmap(const char* const* bits)
 
452
{
 
453
    wxCHECK2_MSG(bits != NULL, return, wxT("invalid bitmap data"));
 
454
 
 
455
#if wxUSE_IMAGE
 
456
    *this = wxBitmap(wxImage(bits));
 
457
#elif defined __WXGTK3__
 
458
    GdkPixbuf* pixbuf = gdk_pixbuf_new_from_xpm_data(const_cast<const char**>(bits));
 
459
    if (pixbuf)
 
460
    {
 
461
        m_refData = new wxBitmapRefData(
 
462
            gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf),
 
463
            gdk_pixbuf_get_n_channels(pixbuf) * 8);
 
464
        M_BMPDATA->m_pixbufNoMask = pixbuf;
 
465
        wxASSERT(M_BMPDATA->m_bpp == 32 || !gdk_pixbuf_get_has_alpha(M_BMPDATA->m_pixbufNoMask));
 
466
    }
 
467
#else
 
468
    GdkBitmap* mask = NULL;
 
469
    GdkPixmap* pixmap = gdk_pixmap_create_from_xpm_d(wxGetRootWindow()->window, &mask, NULL, const_cast<char**>(bits));
 
470
    if (pixmap)
 
471
    {
 
472
        int width, height;
 
473
        gdk_drawable_get_size(pixmap, &width, &height);
 
474
        m_refData = new wxBitmapRefData(width, height, -1);
 
475
        M_BMPDATA->m_pixmap = pixmap;
 
476
        if (mask)
 
477
        {
 
478
            M_BMPDATA->m_mask = new wxMask(mask);
 
479
        }
 
480
    }
 
481
#endif
 
482
}
 
483
 
 
484
wxBitmap::wxBitmap(GdkPixbuf* pixbuf, int depth)
 
485
{
 
486
    if (pixbuf)
 
487
    {
 
488
        if (depth != 1)
 
489
            depth = gdk_pixbuf_get_n_channels(pixbuf) * 8;
 
490
        wxBitmapRefData* bmpData = new wxBitmapRefData(
 
491
            gdk_pixbuf_get_width(pixbuf), gdk_pixbuf_get_height(pixbuf),
 
492
            depth);
 
493
        m_refData = bmpData;
 
494
#ifdef __WXGTK3__
 
495
        bmpData->m_pixbufNoMask = pixbuf;
 
496
#else
 
497
        bmpData->m_pixbuf = pixbuf;
 
498
#endif
 
499
    }
 
500
}
 
501
 
 
502
#ifndef __WXGTK3__
 
503
wxBitmap::wxBitmap(GdkPixmap* pixmap)
 
504
{
 
505
    if (pixmap)
 
506
    {
 
507
        int w, h;
 
508
        gdk_drawable_get_size(pixmap, &w, &h);
 
509
        wxBitmapRefData* bmpData =
 
510
            new wxBitmapRefData(w, h, gdk_drawable_get_depth(pixmap));
 
511
        m_refData = bmpData;
 
512
        bmpData->m_pixmap = pixmap;
 
513
    }
 
514
}
 
515
#endif
 
516
 
 
517
wxBitmap::~wxBitmap()
 
518
{
 
519
}
 
520
 
 
521
bool wxBitmap::Create( int width, int height, int depth )
 
522
{
 
523
    UnRef();
 
524
    wxCHECK_MSG(width >= 0 && height >= 0, false, "invalid bitmap size");
 
525
    m_refData = new wxBitmapRefData(width, height, depth);
 
526
    return true;
 
527
}
 
528
 
 
529
#ifdef __WXGTK3__
 
530
static void CopyImageData(
 
531
    guchar* dst, int dstChannels, int dstStride,
 
532
    const guchar* src, int srcChannels, int srcStride,
 
533
    int w, int h)
 
534
{
 
535
    if (dstChannels == srcChannels)
 
536
    {
 
537
        if (dstStride == srcStride)
 
538
            memcpy(dst, src, size_t(dstStride) * h);
 
539
        else
 
540
        {
 
541
            const int stride = dstStride < srcStride ? dstStride : srcStride;
 
542
            for (int j = 0; j < h; j++, src += srcStride, dst += dstStride)
 
543
                memcpy(dst, src, stride);
 
544
        }
 
545
    }
 
546
    else
 
547
    {
 
548
        for (int j = 0; j < h; j++, src += srcStride, dst += dstStride)
 
549
        {
 
550
            guchar* d = dst;
 
551
            const guchar* s = src;
 
552
            if (dstChannels == 4)
 
553
            {
 
554
                for (int i = 0; i < w; i++, d += 4, s += 3)
 
555
                {
 
556
                    d[0] = s[0];
 
557
                    d[1] = s[1];
 
558
                    d[2] = s[2];
 
559
                    d[3] = 0xff;
 
560
                }
 
561
            }
 
562
            else
 
563
            {
 
564
                for (int i = 0; i < w; i++, d += 3, s += 4)
 
565
                {
 
566
                    d[0] = s[0];
 
567
                    d[1] = s[1];
 
568
                    d[2] = s[2];
 
569
                }
 
570
            }
 
571
        }
 
572
    }
 
573
}
 
574
#endif
 
575
 
 
576
#if wxUSE_IMAGE
 
577
#ifdef __WXGTK3__
 
578
wxBitmap::wxBitmap(const wxImage& image, int depth)
 
579
{
 
580
    wxCHECK_RET(image.IsOk(), "invalid image");
 
581
 
 
582
    const int w = image.GetWidth();
 
583
    const int h = image.GetHeight();
 
584
    const guchar* alpha = image.GetAlpha();
 
585
    if (depth < 0)
 
586
        depth = alpha ? 32 : 24;
 
587
    else if (depth != 1 && depth != 32)
 
588
        depth = 24;
 
589
    wxBitmapRefData* bmpData = new wxBitmapRefData(w, h, depth);
 
590
    m_refData = bmpData;
 
591
    GdkPixbuf* pixbuf_dst = gdk_pixbuf_new(GDK_COLORSPACE_RGB, depth == 32, 8, w, h);
 
592
    bmpData->m_pixbufNoMask = pixbuf_dst;
 
593
    wxASSERT(bmpData->m_bpp == 32 || !gdk_pixbuf_get_has_alpha(bmpData->m_pixbufNoMask));
 
594
    const guchar* src = image.GetData();
 
595
 
 
596
    guchar* dst = gdk_pixbuf_get_pixels(pixbuf_dst);
 
597
    const int dstStride = gdk_pixbuf_get_rowstride(pixbuf_dst);
 
598
    CopyImageData(dst, gdk_pixbuf_get_n_channels(pixbuf_dst), dstStride, src, 3, 3 * w, w, h);
 
599
 
 
600
    if (depth == 32 && alpha)
 
601
    {
 
602
        for (int j = 0; j < h; j++, dst += dstStride)
 
603
            for (int i = 0; i < w; i++)
 
604
                dst[i * 4 + 3] = *alpha++;
 
605
    }
 
606
    if (image.HasMask())
 
607
    {
 
608
        const guchar r = image.GetMaskRed();
 
609
        const guchar g = image.GetMaskGreen();
 
610
        const guchar b = image.GetMaskBlue();
 
611
        cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_A8, w, h);
 
612
        const int stride = cairo_image_surface_get_stride(surface);
 
613
        dst = cairo_image_surface_get_data(surface);
 
614
        memset(dst, 0xff, stride * h);
 
615
        for (int j = 0; j < h; j++, dst += stride)
 
616
            for (int i = 0; i < w; i++, src += 3)
 
617
                if (src[0] == r && src[1] == g && src[2] == b)
 
618
                    dst[i] = 0;
 
619
        cairo_surface_mark_dirty(surface);
 
620
        bmpData->m_mask = new wxMask(surface);
 
621
    }
 
622
}
 
623
#else
 
624
wxBitmap::wxBitmap(const wxImage& image, int depth)
 
625
{
 
626
    wxCHECK_RET(image.IsOk(), "invalid image");
 
627
 
 
628
    if (depth == 32 || (depth == -1 && image.HasAlpha()))
 
629
        CreateFromImageAsPixbuf(image);
 
630
    else
 
631
        // otherwise create pixmap, if alpha is present it will be converted to mask
 
632
        CreateFromImageAsPixmap(image, depth);
 
633
}
 
634
 
 
635
bool wxBitmap::CreateFromImageAsPixmap(const wxImage& image, int depth)
 
636
{
 
637
    const int w = image.GetWidth();
 
638
    const int h = image.GetHeight();
 
639
    if (depth == 1)
 
640
    {
 
641
        // create XBM format bitmap
 
642
 
 
643
        // one bit per pixel, each row starts on a byte boundary
 
644
        const size_t out_size = size_t((w + 7) / 8) * unsigned(h);
 
645
        wxByte* out = new wxByte[out_size];
 
646
        // set bits are black
 
647
        memset(out, 0xff, out_size);
 
648
        const wxByte* in = image.GetData();
 
649
        unsigned bit_index = 0;
 
650
        for (int y = 0; y < h; y++)
 
651
        {
 
652
            for (int x = 0; x < w; x++, in += 3, bit_index++)
 
653
                if (in[0] == 255 && in[1] == 255 && in[2] == 255)
 
654
                    out[bit_index >> 3] ^= 1 << (bit_index & 7);
 
655
            // move index to next byte boundary
 
656
            bit_index = (bit_index + 7) & ~7u;
 
657
        }
 
658
        SetPixmap(gdk_bitmap_create_from_data(wxGetRootWindow()->window, (char*)out, w, h));
 
659
        delete[] out;
 
660
 
 
661
        if (!M_BMPDATA)     // SetPixmap may have failed
 
662
            return false;
 
663
    }
 
664
    else
 
665
    {
 
666
        SetPixmap(gdk_pixmap_new(wxGetRootWindow()->window, w, h, depth));
 
667
        if (!M_BMPDATA)
 
668
            return false;
 
669
 
 
670
        wxGtkObject<GdkGC> gc(gdk_gc_new(M_BMPDATA->m_pixmap));
 
671
        gdk_draw_rgb_image(
 
672
            M_BMPDATA->m_pixmap, gc,
 
673
            0, 0, w, h,
 
674
            GDK_RGB_DITHER_NONE, image.GetData(), w * 3);
 
675
    }
 
676
 
 
677
    const wxByte* alpha = image.GetAlpha();
 
678
    if (alpha != NULL || image.HasMask())
 
679
    {
 
680
        // create mask as XBM format bitmap
 
681
 
 
682
        const size_t out_size = size_t((w + 7) / 8) * unsigned(h);
 
683
        wxByte* out = new wxByte[out_size];
 
684
        memset(out, 0xff, out_size);
 
685
        unsigned bit_index = 0;
 
686
        if (alpha != NULL)
 
687
        {
 
688
            for (int y = 0; y < h; y++)
 
689
            {
 
690
                for (int x = 0; x < w; x++, bit_index++)
 
691
                    if (*alpha++ < wxIMAGE_ALPHA_THRESHOLD)
 
692
                        out[bit_index >> 3] ^= 1 << (bit_index & 7);
 
693
                bit_index = (bit_index + 7) & ~7u;
 
694
            }
 
695
        }
 
696
        else
 
697
        {
 
698
            const wxByte r_mask = image.GetMaskRed();
 
699
            const wxByte g_mask = image.GetMaskGreen();
 
700
            const wxByte b_mask = image.GetMaskBlue();
 
701
            const wxByte* in = image.GetData();
 
702
            for (int y = 0; y < h; y++)
 
703
            {
 
704
                for (int x = 0; x < w; x++, in += 3, bit_index++)
 
705
                    if (in[0] == r_mask && in[1] == g_mask && in[2] == b_mask)
 
706
                        out[bit_index >> 3] ^= 1 << (bit_index & 7);
 
707
                bit_index = (bit_index + 7) & ~7u;
 
708
            }
 
709
        }
 
710
        SetMask(new wxMask(gdk_bitmap_create_from_data(M_BMPDATA->m_pixmap, (char*)out, w, h)));
 
711
        delete[] out;
 
712
    }
 
713
    return IsOk();
 
714
}
 
715
 
 
716
bool wxBitmap::CreateFromImageAsPixbuf(const wxImage& image)
 
717
{
 
718
    int width = image.GetWidth();
 
719
    int height = image.GetHeight();
 
720
 
 
721
    Create(width, height, 32);
 
722
    GdkPixbuf* pixbuf = GetPixbuf();
 
723
    if (!pixbuf)
 
724
        return false;
 
725
 
 
726
    // Copy the data:
 
727
    const unsigned char* in = image.GetData();
 
728
    unsigned char *out = gdk_pixbuf_get_pixels(pixbuf);
 
729
    unsigned char *alpha = image.GetAlpha();
 
730
 
 
731
    int rowpad = gdk_pixbuf_get_rowstride(pixbuf) - 4 * width;
 
732
 
 
733
    for (int y = 0; y < height; y++, out += rowpad)
 
734
    {
 
735
        for (int x = 0; x < width; x++, out += 4, in += 3)
 
736
        {
 
737
            out[0] = in[0];
 
738
            out[1] = in[1];
 
739
            out[2] = in[2];
 
740
            if (alpha)
 
741
                out[3] = *alpha++;
 
742
        }
 
743
    }
 
744
 
 
745
    return true;
 
746
}
 
747
#endif
 
748
 
 
749
wxImage wxBitmap::ConvertToImage() const
 
750
{
 
751
#ifdef __WXGTK3__
 
752
    wxImage image;
 
753
    wxCHECK_MSG(IsOk(), image, "invalid bitmap");
 
754
    wxBitmapRefData* bmpData = M_BMPDATA;
 
755
    const int w = bmpData->m_width;
 
756
    const int h = bmpData->m_height;
 
757
    image.Create(w, h, false);
 
758
    guchar* dst = image.GetData();
 
759
    GdkPixbuf* pixbuf_src = NULL;
 
760
    if (bmpData->m_pixbufNoMask)
 
761
        pixbuf_src = bmpData->m_pixbufNoMask;
 
762
    else if (bmpData->m_surface)
 
763
    {
 
764
        pixbuf_src = gdk_pixbuf_get_from_surface(bmpData->m_surface, 0, 0, w, h);
 
765
        bmpData->m_pixbufNoMask = pixbuf_src;
 
766
        wxASSERT(bmpData->m_bpp == 32 || !gdk_pixbuf_get_has_alpha(bmpData->m_pixbufNoMask));
 
767
    }
 
768
    if (pixbuf_src)
 
769
    {
 
770
        const guchar* src = gdk_pixbuf_get_pixels(pixbuf_src);
 
771
        const int srcStride = gdk_pixbuf_get_rowstride(pixbuf_src);
 
772
        const int srcChannels = gdk_pixbuf_get_n_channels(pixbuf_src);
 
773
        CopyImageData(dst, 3, 3 * w, src, srcChannels, srcStride, w, h);
 
774
 
 
775
        if (srcChannels == 4)
 
776
        {
 
777
            image.SetAlpha();
 
778
            guchar* alpha = image.GetAlpha();
 
779
            for (int j = 0; j < h; j++, src += srcStride)
 
780
            {
 
781
                const guchar* s = src;
 
782
                for (int i = 0; i < w; i++, s += 4)
 
783
                    *alpha++ = s[3];
 
784
            }
 
785
        }
 
786
    }
 
787
    cairo_surface_t* maskSurf = NULL;
 
788
    if (bmpData->m_mask)
 
789
        maskSurf = *bmpData->m_mask;
 
790
    if (maskSurf)
 
791
    {
 
792
        const guchar r = 1;
 
793
        const guchar g = 2;
 
794
        const guchar b = 3;
 
795
        image.SetMaskColour(r, g, b);
 
796
        wxASSERT(cairo_image_surface_get_format(maskSurf) == CAIRO_FORMAT_A8);
 
797
        const int stride = cairo_image_surface_get_stride(maskSurf);
 
798
        const guchar* src = cairo_image_surface_get_data(maskSurf);
 
799
        for (int j = 0; j < h; j++, src += stride)
 
800
        {
 
801
            for (int i = 0; i < w; i++, dst += 3)
 
802
                if (src[i] == 0)
 
803
                {
 
804
                    dst[0] = r;
 
805
                    dst[1] = g;
 
806
                    dst[2] = b;
 
807
                }
 
808
                else if (dst[0] == r && dst[1] == g && dst[2] == b)
 
809
                    dst[2]--;
 
810
        }
 
811
    }
 
812
#else
 
813
    wxCHECK_MSG( IsOk(), wxNullImage, wxT("invalid bitmap") );
 
814
 
 
815
    const int w = GetWidth();
 
816
    const int h = GetHeight();
 
817
    wxImage image(w, h, false);
 
818
    unsigned char *data = image.GetData();
 
819
 
 
820
    wxCHECK_MSG(data != NULL, wxNullImage, wxT("couldn't create image") );
 
821
 
 
822
    // prefer pixbuf if available, it will preserve alpha and should be quicker
 
823
    if (HasPixbuf())
 
824
    {
 
825
        GdkPixbuf *pixbuf = GetPixbuf();
 
826
        unsigned char* alpha = NULL;
 
827
        if (gdk_pixbuf_get_has_alpha(pixbuf))
 
828
        {
 
829
            image.SetAlpha();
 
830
            alpha = image.GetAlpha();
 
831
        }
 
832
        const unsigned char* in = gdk_pixbuf_get_pixels(pixbuf);
 
833
        unsigned char *out = data;
 
834
        const int inc = 3 + int(alpha != NULL);
 
835
        const int rowpad = gdk_pixbuf_get_rowstride(pixbuf) - inc * w;
 
836
 
 
837
        for (int y = 0; y < h; y++, in += rowpad)
 
838
        {
 
839
            for (int x = 0; x < w; x++, in += inc, out += 3)
 
840
            {
 
841
                out[0] = in[0];
 
842
                out[1] = in[1];
 
843
                out[2] = in[2];
 
844
                if (alpha != NULL)
 
845
                    *alpha++ = in[3];
 
846
            }
 
847
        }
 
848
    }
 
849
    else
 
850
    {
 
851
        GdkPixmap* pixmap = GetPixmap();
 
852
        GdkPixmap* pixmap_invert = NULL;
 
853
        if (GetDepth() == 1)
 
854
        {
 
855
            // mono bitmaps are inverted, i.e. 0 is white
 
856
            pixmap_invert = gdk_pixmap_new(pixmap, w, h, 1);
 
857
            wxGtkObject<GdkGC> gc(gdk_gc_new(pixmap_invert));
 
858
            gdk_gc_set_function(gc, GDK_COPY_INVERT);
 
859
            gdk_draw_drawable(pixmap_invert, gc, pixmap, 0, 0, 0, 0, w, h);
 
860
            pixmap = pixmap_invert;
 
861
        }
 
862
        // create a pixbuf which shares data with the wxImage
 
863
        GdkPixbuf* pixbuf = gdk_pixbuf_new_from_data(
 
864
            data, GDK_COLORSPACE_RGB, false, 8, w, h, 3 * w, NULL, NULL);
 
865
 
 
866
        gdk_pixbuf_get_from_drawable(pixbuf, pixmap, NULL, 0, 0, 0, 0, w, h);
 
867
 
 
868
        g_object_unref(pixbuf);
 
869
        if (pixmap_invert != NULL)
 
870
            g_object_unref(pixmap_invert);
 
871
    }
 
872
    // convert mask, unless there is already alpha
 
873
    if (GetMask() && !image.HasAlpha())
 
874
    {
 
875
        // we hard code the mask colour for now but we could also make an
 
876
        // effort (and waste time) to choose a colour not present in the
 
877
        // image already to avoid having to fudge the pixels below --
 
878
        // whether it's worth to do it is unclear however
 
879
        const int MASK_RED = 1;
 
880
        const int MASK_GREEN = 2;
 
881
        const int MASK_BLUE = 3;
 
882
        const int MASK_BLUE_REPLACEMENT = 2;
 
883
 
 
884
        image.SetMaskColour(MASK_RED, MASK_GREEN, MASK_BLUE);
 
885
        GdkImage* image_mask = gdk_drawable_get_image(*GetMask(), 0, 0, w, h);
 
886
 
 
887
        for (int y = 0; y < h; y++)
 
888
        {
 
889
            for (int x = 0; x < w; x++, data += 3)
 
890
            {
 
891
                if (gdk_image_get_pixel(image_mask, x, y) == 0)
 
892
                {
 
893
                    data[0] = MASK_RED;
 
894
                    data[1] = MASK_GREEN;
 
895
                    data[2] = MASK_BLUE;
 
896
                }
 
897
                else if (data[0] == MASK_RED && data[1] == MASK_GREEN && data[2] == MASK_BLUE)
 
898
                {
 
899
                    // we have to fudge the colour a bit to prevent
 
900
                    // this pixel from appearing transparent
 
901
                    data[2] = MASK_BLUE_REPLACEMENT;
 
902
                }
 
903
            }
 
904
        }
 
905
        g_object_unref(image_mask);
 
906
    }
 
907
#endif
 
908
 
 
909
    return image;
 
910
}
 
911
 
 
912
#endif // wxUSE_IMAGE
 
913
 
 
914
int wxBitmap::GetHeight() const
 
915
{
 
916
    wxCHECK_MSG( IsOk(), -1, wxT("invalid bitmap") );
 
917
 
 
918
    return M_BMPDATA->m_height;
 
919
}
 
920
 
 
921
int wxBitmap::GetWidth() const
 
922
{
 
923
    wxCHECK_MSG( IsOk(), -1, wxT("invalid bitmap") );
 
924
 
 
925
    return M_BMPDATA->m_width;
 
926
}
 
927
 
 
928
int wxBitmap::GetDepth() const
 
929
{
 
930
    wxCHECK_MSG( IsOk(), -1, wxT("invalid bitmap") );
 
931
 
 
932
    return M_BMPDATA->m_bpp;
 
933
}
 
934
 
 
935
wxMask *wxBitmap::GetMask() const
 
936
{
 
937
    wxCHECK_MSG( IsOk(), NULL, wxT("invalid bitmap") );
 
938
 
 
939
    return M_BMPDATA->m_mask;
 
940
}
 
941
 
 
942
void wxBitmap::SetMask( wxMask *mask )
 
943
{
 
944
    wxCHECK_RET( IsOk(), wxT("invalid bitmap") );
 
945
 
 
946
    AllocExclusive();
 
947
    delete M_BMPDATA->m_mask;
 
948
    M_BMPDATA->m_mask = mask;
 
949
}
 
950
 
 
951
bool wxBitmap::CopyFromIcon(const wxIcon& icon)
 
952
{
 
953
    *this = icon;
 
954
    return IsOk();
 
955
}
 
956
 
 
957
#ifdef __WXGTK3__
 
958
static cairo_surface_t* GetSubSurface(cairo_surface_t* surface, const wxRect& rect)
 
959
{
 
960
    cairo_surface_flush(surface);
 
961
    const cairo_format_t format = cairo_image_surface_get_format(surface);
 
962
    int x = rect.x;
 
963
    if (format != CAIRO_FORMAT_A8)
 
964
        x *= 4;
 
965
    cairo_surface_t* subSurface = cairo_image_surface_create(format, rect.width, rect.height);
 
966
    const int srcStride = cairo_image_surface_get_stride(surface);
 
967
    const int dstStride = cairo_image_surface_get_stride(subSurface);
 
968
    const guchar* src = cairo_image_surface_get_data(surface) + rect.y * srcStride + x;
 
969
    guchar* dst = cairo_image_surface_get_data(subSurface);
 
970
    for (int j = 0; j < rect.height; j++, src += srcStride, dst += dstStride)
 
971
        memcpy(dst, src, dstStride);
 
972
    cairo_surface_mark_dirty(subSurface);
 
973
    return subSurface;
 
974
}
 
975
#endif
 
976
 
 
977
wxBitmap wxBitmap::GetSubBitmap( const wxRect& rect) const
 
978
{
 
979
    wxBitmap ret;
 
980
 
 
981
    wxCHECK_MSG(IsOk(), ret, wxT("invalid bitmap"));
 
982
 
 
983
    const int w = rect.width;
 
984
    const int h = rect.height;
 
985
    const wxBitmapRefData* bmpData = M_BMPDATA;
 
986
 
 
987
    wxCHECK_MSG(rect.x >= 0 && rect.y >= 0 &&
 
988
                rect.x + w <= bmpData->m_width &&
 
989
                rect.y + h <= bmpData->m_height,
 
990
                ret, wxT("invalid bitmap region"));
 
991
 
 
992
    wxBitmapRefData * const newRef = new wxBitmapRefData(w, h, bmpData->m_bpp);
 
993
    ret.m_refData = newRef;
 
994
 
 
995
#ifdef __WXGTK3__
 
996
    if (bmpData->m_pixbufNoMask)
 
997
    {
 
998
        GdkPixbuf* pixbuf = gdk_pixbuf_new_subpixbuf(bmpData->m_pixbufNoMask, rect.x, rect.y, w, h);
 
999
        newRef->m_pixbufNoMask = gdk_pixbuf_copy(pixbuf);
 
1000
        wxASSERT(newRef->m_bpp == 32 || !gdk_pixbuf_get_has_alpha(newRef->m_pixbufNoMask));
 
1001
        g_object_unref(pixbuf);
 
1002
    }
 
1003
    else if (bmpData->m_surface)
 
1004
        newRef->m_surface = GetSubSurface(bmpData->m_surface, rect);
 
1005
 
 
1006
    cairo_surface_t* maskSurf = NULL;
 
1007
    if (bmpData->m_mask)
 
1008
        maskSurf = *bmpData->m_mask;
 
1009
    if (maskSurf)
 
1010
    {
 
1011
        newRef->m_mask = new wxMask(GetSubSurface(maskSurf, rect));
 
1012
    }
 
1013
#else
 
1014
    if (bmpData->m_pixbuf)
 
1015
    {
 
1016
        GdkPixbuf* pixbuf =
 
1017
            gdk_pixbuf_new_subpixbuf(bmpData->m_pixbuf, rect.x, rect.y, w, h);
 
1018
        newRef->m_pixbuf = gdk_pixbuf_copy(pixbuf);
 
1019
        g_object_unref(pixbuf);
 
1020
    }
 
1021
    if (bmpData->m_pixmap)
 
1022
    {
 
1023
        newRef->m_pixmap = gdk_pixmap_new(bmpData->m_pixmap, w, h, -1);
 
1024
        GdkGC* gc = gdk_gc_new(newRef->m_pixmap);
 
1025
        gdk_draw_drawable(
 
1026
            newRef->m_pixmap, gc, bmpData->m_pixmap, rect.x, rect.y, 0, 0, w, h);
 
1027
        g_object_unref(gc);
 
1028
    }
 
1029
    GdkPixmap* mask = NULL;
 
1030
    if (bmpData->m_mask)
 
1031
        mask = *bmpData->m_mask;
 
1032
    if (mask)
 
1033
    {
 
1034
        GdkPixmap* sub_mask = gdk_pixmap_new(mask, w, h, 1);
 
1035
        newRef->m_mask = new wxMask(sub_mask);
 
1036
        GdkGC* gc = gdk_gc_new(sub_mask);
 
1037
        gdk_draw_drawable(
 
1038
            sub_mask, gc, mask, rect.x, rect.y, 0, 0, w, h);
 
1039
        g_object_unref(gc);
 
1040
    }
 
1041
#endif
 
1042
 
 
1043
    return ret;
 
1044
}
 
1045
 
 
1046
bool wxBitmap::SaveFile( const wxString &name, wxBitmapType type, const wxPalette *WXUNUSED(palette) ) const
 
1047
{
 
1048
    wxCHECK_MSG( IsOk(), false, wxT("invalid bitmap") );
 
1049
 
 
1050
    const char* type_name = NULL;
 
1051
    switch (type)
 
1052
    {
 
1053
        case wxBITMAP_TYPE_ANI:  type_name = "ani";  break;
 
1054
        case wxBITMAP_TYPE_BMP:  type_name = "bmp";  break;
 
1055
        case wxBITMAP_TYPE_GIF:  type_name = "gif";  break;
 
1056
        case wxBITMAP_TYPE_ICO:  type_name = "ico";  break;
 
1057
        case wxBITMAP_TYPE_JPEG: type_name = "jpeg"; break;
 
1058
        case wxBITMAP_TYPE_PCX:  type_name = "pcx";  break;
 
1059
        case wxBITMAP_TYPE_PNG:  type_name = "png";  break;
 
1060
        case wxBITMAP_TYPE_PNM:  type_name = "pnm";  break;
 
1061
        case wxBITMAP_TYPE_TGA:  type_name = "tga";  break;
 
1062
        case wxBITMAP_TYPE_TIFF: type_name = "tiff"; break;
 
1063
        case wxBITMAP_TYPE_XBM:  type_name = "xbm";  break;
 
1064
        case wxBITMAP_TYPE_XPM:  type_name = "xpm";  break;
 
1065
        default: break;
 
1066
    }
 
1067
    if (type_name &&
 
1068
        gdk_pixbuf_save(GetPixbuf(), wxGTK_CONV_FN(name), type_name, NULL, NULL))
 
1069
    {
 
1070
        return true;
 
1071
    }
 
1072
#if wxUSE_IMAGE
 
1073
    return ConvertToImage().SaveFile(name, type);
 
1074
#else
 
1075
    return false;
 
1076
#endif
 
1077
}
 
1078
 
 
1079
bool wxBitmap::LoadFile( const wxString &name, wxBitmapType type )
 
1080
{
 
1081
    GdkPixbuf* pixbuf = gdk_pixbuf_new_from_file(wxGTK_CONV_FN(name), NULL);
 
1082
    if (pixbuf)
 
1083
    {
 
1084
        *this = wxBitmap(pixbuf);
 
1085
        return true;
 
1086
    }
 
1087
#if wxUSE_IMAGE
 
1088
    wxImage image;
 
1089
    if (image.LoadFile(name, type) && image.IsOk())
 
1090
    {
 
1091
        *this = wxBitmap(image);
 
1092
        return true;
 
1093
    }
 
1094
#else
 
1095
    wxUnusedVar(type);
 
1096
#endif
 
1097
    return false;
 
1098
}
 
1099
 
 
1100
#if wxUSE_PALETTE
 
1101
wxPalette *wxBitmap::GetPalette() const
 
1102
{
 
1103
    return NULL;
 
1104
}
 
1105
 
 
1106
void wxBitmap::SetPalette(const wxPalette& WXUNUSED(palette))
 
1107
{
 
1108
    // TODO
 
1109
}
 
1110
#endif // wxUSE_PALETTE
 
1111
 
 
1112
void wxBitmap::SetHeight( int height )
 
1113
{
 
1114
    AllocExclusive();
 
1115
    M_BMPDATA->m_height = height;
 
1116
}
 
1117
 
 
1118
void wxBitmap::SetWidth( int width )
 
1119
{
 
1120
    AllocExclusive();
 
1121
    M_BMPDATA->m_width = width;
 
1122
}
 
1123
 
 
1124
void wxBitmap::SetDepth( int depth )
 
1125
{
 
1126
    AllocExclusive();
 
1127
    M_BMPDATA->m_bpp = depth;
 
1128
}
 
1129
 
 
1130
#ifndef __WXGTK3__
 
1131
void wxBitmap::SetPixmap( GdkPixmap *pixmap )
 
1132
{
 
1133
    UnRef();
 
1134
 
 
1135
    if (!pixmap)
 
1136
        return;
 
1137
 
 
1138
    int w, h;
 
1139
    gdk_drawable_get_size(pixmap, &w, &h);
 
1140
    wxBitmapRefData* bmpData = new wxBitmapRefData(w, h, 0);
 
1141
    m_refData = bmpData;
 
1142
    bmpData->m_pixmap = pixmap;
 
1143
    bmpData->m_bpp = gdk_drawable_get_depth(pixmap);
 
1144
}
 
1145
 
 
1146
GdkPixmap *wxBitmap::GetPixmap() const
 
1147
{
 
1148
    wxCHECK_MSG( IsOk(), NULL, wxT("invalid bitmap") );
 
1149
 
 
1150
    wxBitmapRefData* bmpData = M_BMPDATA;
 
1151
    if (bmpData->m_pixmap)
 
1152
        return bmpData->m_pixmap;
 
1153
 
 
1154
    if (bmpData->m_pixbuf)
 
1155
    {
 
1156
        GdkPixmap* pixmap = NULL;
 
1157
        GdkPixmap** mask_pixmap = NULL;
 
1158
        if (gdk_pixbuf_get_has_alpha(bmpData->m_pixbuf))
 
1159
        {
 
1160
            // make new mask from alpha
 
1161
            mask_pixmap = &pixmap;
 
1162
        }
 
1163
        gdk_pixbuf_render_pixmap_and_mask(
 
1164
            bmpData->m_pixbuf, &bmpData->m_pixmap, mask_pixmap, 128);
 
1165
        if (pixmap)
 
1166
        {
 
1167
            delete bmpData->m_mask;
 
1168
            bmpData->m_mask = new wxMask(pixmap);
 
1169
        }
 
1170
    }
 
1171
    else
 
1172
    {
 
1173
        bmpData->m_pixmap = gdk_pixmap_new(wxGetRootWindow()->window,
 
1174
            bmpData->m_width, bmpData->m_height, bmpData->m_bpp == 1 ? 1 : -1);
 
1175
    }
 
1176
    return bmpData->m_pixmap;
 
1177
}
 
1178
 
 
1179
bool wxBitmap::HasPixmap() const
 
1180
{
 
1181
    wxCHECK_MSG( IsOk(), false, wxT("invalid bitmap") );
 
1182
 
 
1183
    return M_BMPDATA->m_pixmap != NULL;
 
1184
}
 
1185
#endif
 
1186
 
 
1187
#ifdef __WXGTK3__
 
1188
GdkPixbuf* wxBitmap::GetPixbufNoMask() const
 
1189
{
 
1190
    wxCHECK_MSG(IsOk(), NULL, "invalid bitmap");
 
1191
 
 
1192
    wxBitmapRefData* bmpData = M_BMPDATA;
 
1193
    GdkPixbuf* pixbuf = bmpData->m_pixbufNoMask;
 
1194
    if (pixbuf)
 
1195
        return pixbuf;
 
1196
 
 
1197
    const int w = bmpData->m_width;
 
1198
    const int h = bmpData->m_height;
 
1199
    if (bmpData->m_surface)
 
1200
        pixbuf = gdk_pixbuf_get_from_surface(bmpData->m_surface, 0, 0, w, h);
 
1201
    else
 
1202
        pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, bmpData->m_bpp == 32, 8, w, h);
 
1203
    bmpData->m_pixbufNoMask = pixbuf;
 
1204
    wxASSERT(bmpData->m_bpp == 32 || !gdk_pixbuf_get_has_alpha(bmpData->m_pixbufNoMask));
 
1205
 
 
1206
    return pixbuf;
 
1207
}
 
1208
 
 
1209
// helper to set up a simulated depth 1 surface
 
1210
static void SetSourceSurface1(const wxBitmapRefData* bmpData, cairo_t* cr, int x, int y, const wxColour* fg, const wxColour* bg)
 
1211
{
 
1212
    GdkPixbuf* pixbuf = gdk_pixbuf_copy(bmpData->m_pixbufNoMask);
 
1213
    const int w = bmpData->m_width;
 
1214
    const int h = bmpData->m_height;
 
1215
    const int stride = gdk_pixbuf_get_rowstride(pixbuf);
 
1216
    const int channels = gdk_pixbuf_get_n_channels(pixbuf);
 
1217
    guchar* dst = gdk_pixbuf_get_pixels(pixbuf);
 
1218
    guchar fg_r = 0, fg_g = 0, fg_b = 0;
 
1219
    if (fg && fg->IsOk())
 
1220
    {
 
1221
        fg_r = fg->Red();
 
1222
        fg_g = fg->Green();
 
1223
        fg_b = fg->Blue();
 
1224
    }
 
1225
    guchar bg_r = 255, bg_g = 255, bg_b = 255;
 
1226
    if (bg && bg->IsOk())
 
1227
    {
 
1228
        bg_r = bg->Red();
 
1229
        bg_g = bg->Green();
 
1230
        bg_b = bg->Blue();
 
1231
    }
 
1232
    for (int j = 0; j < h; j++, dst += stride)
 
1233
    {
 
1234
        guchar* d = dst;
 
1235
        for (int i = 0; i < w; i++, d += channels)
 
1236
            if (d[0])
 
1237
            {
 
1238
                d[0] = bg_r;
 
1239
                d[1] = bg_g;
 
1240
                d[2] = bg_b;
 
1241
            }
 
1242
            else
 
1243
            {
 
1244
                d[0] = fg_r;
 
1245
                d[1] = fg_g;
 
1246
                d[2] = fg_b;
 
1247
            }
 
1248
    }
 
1249
    gdk_cairo_set_source_pixbuf(cr, pixbuf, x, y);
 
1250
    g_object_unref(pixbuf);
 
1251
}
 
1252
 
 
1253
void wxBitmap::SetSourceSurface(cairo_t* cr, int x, int y, const wxColour* fg, const wxColour* bg) const
 
1254
{
 
1255
    wxBitmapRefData* bmpData = M_BMPDATA;
 
1256
    if (bmpData->m_surface)
 
1257
    {
 
1258
        cairo_set_source_surface(cr, bmpData->m_surface, x, y);
 
1259
        return;
 
1260
    }
 
1261
    wxCHECK_RET(bmpData->m_pixbufNoMask, "no bitmap data");
 
1262
    if (bmpData->m_bpp == 1)
 
1263
        SetSourceSurface1(bmpData, cr, x, y, fg, bg);
 
1264
    else
 
1265
    {
 
1266
        gdk_cairo_set_source_pixbuf(cr, bmpData->m_pixbufNoMask, x, y);
 
1267
        cairo_pattern_get_surface(cairo_get_source(cr), &bmpData->m_surface);
 
1268
        cairo_surface_reference(bmpData->m_surface);
 
1269
    }
 
1270
}
 
1271
 
 
1272
cairo_t* wxBitmap::CairoCreate() const
 
1273
{
 
1274
    wxCHECK_MSG(IsOk(), NULL, "invalid bitmap");
 
1275
 
 
1276
    wxBitmapRefData* bmpData = M_BMPDATA;
 
1277
    cairo_t* cr;
 
1278
    if (bmpData->m_surface)
 
1279
        cr = cairo_create(bmpData->m_surface);
 
1280
    else
 
1281
    {
 
1282
        GdkPixbuf* pixbuf = bmpData->m_pixbufNoMask;
 
1283
        const bool useAlpha = bmpData->m_bpp == 32 || (pixbuf && gdk_pixbuf_get_has_alpha(pixbuf));
 
1284
        bmpData->m_surface = cairo_image_surface_create(
 
1285
            useAlpha ? CAIRO_FORMAT_ARGB32 : CAIRO_FORMAT_RGB24,
 
1286
            bmpData->m_width, bmpData->m_height);
 
1287
        cr = cairo_create(bmpData->m_surface);
 
1288
        if (pixbuf)
 
1289
        {
 
1290
            gdk_cairo_set_source_pixbuf(cr, pixbuf, 0, 0);
 
1291
            cairo_paint(cr);
 
1292
            cairo_set_source_rgb(cr, 0, 0, 0);
 
1293
        }
 
1294
    }
 
1295
    if (bmpData->m_pixbufNoMask)
 
1296
    {
 
1297
        g_object_unref(bmpData->m_pixbufNoMask);
 
1298
        bmpData->m_pixbufNoMask = NULL;
 
1299
    }
 
1300
    if (bmpData->m_pixbufMask)
 
1301
    {
 
1302
        g_object_unref(bmpData->m_pixbufMask);
 
1303
        bmpData->m_pixbufMask = NULL;
 
1304
    }
 
1305
    wxASSERT(cr && cairo_status(cr) == 0);
 
1306
    return cr;
 
1307
}
 
1308
 
 
1309
void wxBitmap::Draw(cairo_t* cr, int x, int y, bool useMask, const wxColour* fg, const wxColour* bg) const
 
1310
{
 
1311
    wxCHECK_RET(IsOk(), "invalid bitmap");
 
1312
 
 
1313
    wxBitmapRefData* bmpData = M_BMPDATA;
 
1314
    SetSourceSurface(cr, x, y, fg, bg);
 
1315
    cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_NEAREST);
 
1316
    cairo_surface_t* mask = NULL;
 
1317
    if (useMask && bmpData->m_mask)
 
1318
        mask = *bmpData->m_mask;
 
1319
    if (mask)
 
1320
        cairo_mask_surface(cr, mask, x, y);
 
1321
    else
 
1322
        cairo_paint(cr);
 
1323
}
 
1324
#endif
 
1325
 
 
1326
GdkPixbuf *wxBitmap::GetPixbuf() const
 
1327
{
 
1328
    wxCHECK_MSG( IsOk(), NULL, wxT("invalid bitmap") );
 
1329
 
 
1330
    wxBitmapRefData* bmpData = M_BMPDATA;
 
1331
#ifdef __WXGTK3__
 
1332
    if (bmpData->m_pixbufMask)
 
1333
        return bmpData->m_pixbufMask;
 
1334
 
 
1335
    if (bmpData->m_pixbufNoMask == NULL)
 
1336
        GetPixbufNoMask();
 
1337
    cairo_surface_t* mask = NULL;
 
1338
    if (bmpData->m_mask)
 
1339
        mask = *bmpData->m_mask;
 
1340
    if (mask == NULL)
 
1341
        return bmpData->m_pixbufNoMask;
 
1342
 
 
1343
    const int w = bmpData->m_width;
 
1344
    const int h = bmpData->m_height;
 
1345
    bmpData->m_pixbufMask = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, w, h);
 
1346
 
 
1347
    guchar* dst = gdk_pixbuf_get_pixels(bmpData->m_pixbufMask);
 
1348
    const int dstStride = gdk_pixbuf_get_rowstride(bmpData->m_pixbufMask);
 
1349
    CopyImageData(dst, 4, dstStride,
 
1350
        gdk_pixbuf_get_pixels(bmpData->m_pixbufNoMask),
 
1351
        gdk_pixbuf_get_n_channels(bmpData->m_pixbufNoMask),
 
1352
        gdk_pixbuf_get_rowstride(bmpData->m_pixbufNoMask),
 
1353
        w, h);
 
1354
 
 
1355
    const guchar* src = cairo_image_surface_get_data(mask);
 
1356
    const int srcStride = cairo_image_surface_get_stride(mask);
 
1357
    for (int j = 0; j < h; j++, src += srcStride, dst += dstStride)
 
1358
        for (int i = 0; i < w; i++)
 
1359
            if (src[i] == 0)
 
1360
                dst[i * 4 + 3] = 0;
 
1361
 
 
1362
    return bmpData->m_pixbufMask;
 
1363
#else
 
1364
    if (bmpData->m_pixbuf)
 
1365
        return bmpData->m_pixbuf;
 
1366
 
 
1367
    const int w = bmpData->m_width;
 
1368
    const int h = bmpData->m_height;
 
1369
    GdkPixmap* mask = NULL;
 
1370
    if (bmpData->m_mask)
 
1371
        mask = *bmpData->m_mask;
 
1372
    const bool useAlpha = bmpData->m_alphaRequested || mask;
 
1373
    bmpData->m_pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, useAlpha, 8, w, h);
 
1374
    if (bmpData->m_pixmap)
 
1375
        PixmapToPixbuf(bmpData->m_pixmap, bmpData->m_pixbuf, w, h);
 
1376
    if (mask)
 
1377
        MaskToAlpha(mask, bmpData->m_pixbuf, w, h);
 
1378
    return bmpData->m_pixbuf;
 
1379
#endif
 
1380
}
 
1381
 
 
1382
#ifndef __WXGTK3__
 
1383
bool wxBitmap::HasPixbuf() const
 
1384
{
 
1385
    wxCHECK_MSG( IsOk(), false, wxT("invalid bitmap") );
 
1386
 
 
1387
    return M_BMPDATA->m_pixbuf != NULL;
 
1388
}
 
1389
 
 
1390
void wxBitmap::PurgeOtherRepresentations(wxBitmap::Representation keep)
 
1391
{
 
1392
    if (keep == Pixmap && HasPixbuf())
 
1393
    {
 
1394
        g_object_unref (M_BMPDATA->m_pixbuf);
 
1395
        M_BMPDATA->m_pixbuf = NULL;
 
1396
    }
 
1397
    if (keep == Pixbuf && HasPixmap())
 
1398
    {
 
1399
        g_object_unref (M_BMPDATA->m_pixmap);
 
1400
        M_BMPDATA->m_pixmap = NULL;
 
1401
    }
 
1402
}
 
1403
#endif
 
1404
 
 
1405
#ifdef wxHAS_RAW_BITMAP
 
1406
void *wxBitmap::GetRawData(wxPixelDataBase& data, int bpp)
 
1407
{
 
1408
    void* bits = NULL;
 
1409
#ifdef __WXGTK3__
 
1410
    GdkPixbuf* pixbuf = GetPixbufNoMask();
 
1411
    if ((bpp == 32) == (gdk_pixbuf_get_has_alpha(pixbuf) != 0))
 
1412
    {
 
1413
        bits = gdk_pixbuf_get_pixels(pixbuf);
 
1414
        wxBitmapRefData* bmpData = M_BMPDATA;
 
1415
        data.m_width = bmpData->m_width;
 
1416
        data.m_height = bmpData->m_height;
 
1417
        data.m_stride = gdk_pixbuf_get_rowstride(pixbuf);
 
1418
        if (bmpData->m_pixbufMask)
 
1419
        {
 
1420
            g_object_unref(bmpData->m_pixbufMask);
 
1421
            bmpData->m_pixbufMask = NULL;
 
1422
        }
 
1423
        if (bmpData->m_surface)
 
1424
        {
 
1425
            cairo_surface_destroy(bmpData->m_surface);
 
1426
            bmpData->m_surface = NULL;
 
1427
        }
 
1428
    }
 
1429
#else
 
1430
    GdkPixbuf *pixbuf = GetPixbuf();
 
1431
    const bool hasAlpha = HasAlpha();
 
1432
 
 
1433
    // allow access if bpp is valid and matches existence of alpha
 
1434
    if ( pixbuf && ((bpp == 24 && !hasAlpha) || (bpp == 32 && hasAlpha)) )
 
1435
    {
 
1436
        data.m_height = gdk_pixbuf_get_height( pixbuf );
 
1437
        data.m_width = gdk_pixbuf_get_width( pixbuf );
 
1438
        data.m_stride = gdk_pixbuf_get_rowstride( pixbuf );
 
1439
        bits = gdk_pixbuf_get_pixels(pixbuf);
 
1440
    }
 
1441
#endif
 
1442
    return bits;
 
1443
}
 
1444
 
 
1445
void wxBitmap::UngetRawData(wxPixelDataBase& WXUNUSED(data))
 
1446
{
 
1447
}
 
1448
#endif // wxHAS_RAW_BITMAP
 
1449
 
 
1450
bool wxBitmap::HasAlpha() const
 
1451
{
 
1452
    const wxBitmapRefData* bmpData = M_BMPDATA;
 
1453
#ifdef __WXGTK3__
 
1454
    return bmpData && bmpData->m_bpp == 32;
 
1455
#else
 
1456
    return bmpData && (bmpData->m_alphaRequested ||
 
1457
        (bmpData->m_pixbuf && gdk_pixbuf_get_has_alpha(bmpData->m_pixbuf)));
 
1458
#endif
 
1459
}
 
1460
 
 
1461
wxGDIRefData* wxBitmap::CreateGDIRefData() const
 
1462
{
 
1463
    return new wxBitmapRefData(0, 0, 0);
 
1464
}
 
1465
 
 
1466
wxGDIRefData* wxBitmap::CloneGDIRefData(const wxGDIRefData* data) const
 
1467
{
 
1468
    const wxBitmapRefData* oldRef = static_cast<const wxBitmapRefData*>(data);
 
1469
    wxBitmapRefData * const newRef = new wxBitmapRefData(oldRef->m_width,
 
1470
                                                         oldRef->m_height,
 
1471
                                                         oldRef->m_bpp);
 
1472
#ifdef __WXGTK3__
 
1473
    if (oldRef->m_pixbufNoMask)
 
1474
        newRef->m_pixbufNoMask = gdk_pixbuf_copy(oldRef->m_pixbufNoMask);
 
1475
    if (oldRef->m_surface)
 
1476
    {
 
1477
        const int w = oldRef->m_width;
 
1478
        const int h = oldRef->m_height;
 
1479
        cairo_surface_t* surface = cairo_image_surface_create(
 
1480
            cairo_image_surface_get_format(oldRef->m_surface), w, h);
 
1481
        newRef->m_surface = surface;
 
1482
        cairo_surface_flush(oldRef->m_surface);
 
1483
        const guchar* src = cairo_image_surface_get_data(oldRef->m_surface);
 
1484
        guchar* dst = cairo_image_surface_get_data(surface);
 
1485
        const int stride = cairo_image_surface_get_stride(surface);
 
1486
        wxASSERT(stride == cairo_image_surface_get_stride(oldRef->m_surface));
 
1487
        memcpy(dst, src, stride * h);
 
1488
        cairo_surface_mark_dirty(surface);
 
1489
    }
 
1490
#else
 
1491
    if (oldRef->m_pixmap != NULL)
 
1492
    {
 
1493
        newRef->m_pixmap = gdk_pixmap_new(
 
1494
            oldRef->m_pixmap, oldRef->m_width, oldRef->m_height,
 
1495
            // use pixmap depth, m_bpp may not match
 
1496
            gdk_drawable_get_depth(oldRef->m_pixmap));
 
1497
        wxGtkObject<GdkGC> gc(gdk_gc_new(newRef->m_pixmap));
 
1498
        gdk_draw_drawable(
 
1499
            newRef->m_pixmap, gc, oldRef->m_pixmap, 0, 0, 0, 0, -1, -1);
 
1500
    }
 
1501
    if (oldRef->m_pixbuf != NULL)
 
1502
    {
 
1503
        newRef->m_pixbuf = gdk_pixbuf_copy(oldRef->m_pixbuf);
 
1504
    }
 
1505
#endif
 
1506
    if (oldRef->m_mask != NULL)
 
1507
    {
 
1508
        newRef->m_mask = new wxMask(*oldRef->m_mask);
 
1509
    }
 
1510
 
 
1511
    return newRef;
 
1512
}
 
1513
 
 
1514
/* static */ void wxBitmap::InitStandardHandlers()
 
1515
{
 
1516
    // TODO: Insert handler based on GdkPixbufs handler later
 
1517
}