1
/////////////////////////////////////////////////////////////////////////////
2
// Name: src/gtk/region.cpp
4
// Author: Robert Roebling
5
// Modified: VZ at 05.10.00: use AllocExclusive(), comparison fixed
6
// Copyright: (c) 1998 Robert Roebling
7
// Licence: wxWindows licence
8
/////////////////////////////////////////////////////////////////////////////
10
// ============================================================================
12
// ============================================================================
14
// ----------------------------------------------------------------------------
16
// ----------------------------------------------------------------------------
18
// For compilers that support precompilation, includes "wx.h".
19
#include "wx/wxprec.h"
21
#include "wx/region.h"
25
// ----------------------------------------------------------------------------
26
// wxRegionRefData: private class containing the information about the region
27
// ----------------------------------------------------------------------------
29
class wxRegionRefData : public wxGDIRefData
37
wxRegionRefData(const wxRegionRefData& refData)
41
m_region = cairo_region_copy(refData.m_region);
43
m_region = gdk_region_copy(refData.m_region);
47
virtual ~wxRegionRefData()
52
cairo_region_destroy(m_region);
54
gdk_region_destroy( m_region );
60
cairo_region_t* m_region;
66
// ----------------------------------------------------------------------------
68
// ----------------------------------------------------------------------------
70
#define M_REGIONDATA static_cast<wxRegionRefData*>(m_refData)
71
#define M_REGIONDATA_OF(r) static_cast<wxRegionRefData*>(r.m_refData)
73
IMPLEMENT_DYNAMIC_CLASS(wxRegion, wxGDIObject)
74
IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator,wxObject)
76
// ----------------------------------------------------------------------------
77
// wxRegion construction
78
// ----------------------------------------------------------------------------
80
void wxRegion::InitRect(wxCoord x, wxCoord y, wxCoord w, wxCoord h)
88
m_refData = new wxRegionRefData();
91
M_REGIONDATA->m_region = cairo_region_create_rectangle(&rect);
93
M_REGIONDATA->m_region = gdk_region_rectangle( &rect );
98
wxRegion::wxRegion(const GdkRegion* region)
100
m_refData = new wxRegionRefData();
101
M_REGIONDATA->m_region = gdk_region_copy(const_cast<GdkRegion*>(region));
105
wxRegion::wxRegion( size_t n, const wxPoint *points,
106
wxPolygonFillMode fillStyle )
109
// Make a cairo path from the points, draw it onto an image surface, use
110
// gdk_cairo_region_create_from_surface() to get a cairo region
112
// need at least 3 points to make a useful polygon
116
int min_x = points[0].x;
118
int min_y = points[0].y;
121
for (i = 1; i < n; i++)
123
const int x = points[i].x;
128
const int y = points[i].y;
134
const int w = max_x - min_x + 1;
135
const int h = max_y - min_y + 1;
136
// make surface just big enough to contain polygon (A1 is native format
137
// for gdk_cairo_region_create_from_surface)
138
cairo_surface_t* surface = cairo_image_surface_create(CAIRO_FORMAT_A1, w, h);
139
memset(cairo_image_surface_get_data(surface), 0, cairo_image_surface_get_stride(surface) * h);
140
cairo_surface_mark_dirty(surface);
141
cairo_surface_set_device_offset(surface, -min_x, -min_y);
142
cairo_t* cr = cairo_create(surface);
143
cairo_set_antialias(cr, CAIRO_ANTIALIAS_NONE);
144
if (fillStyle == wxODDEVEN_RULE)
145
cairo_set_fill_rule(cr, CAIRO_FILL_RULE_EVEN_ODD);
147
cairo_move_to(cr, points[0].x, points[0].y);
148
for (i = 1; i < n; i++)
149
cairo_line_to(cr, points[i].x, points[i].y);
150
cairo_close_path(cr);
153
cairo_surface_flush(surface);
154
m_refData = new wxRegionRefData;
155
M_REGIONDATA->m_region = gdk_cairo_region_create_from_surface(surface);
156
cairo_surface_destroy(surface);
158
GdkPoint *gdkpoints = new GdkPoint[n];
159
for ( size_t i = 0 ; i < n ; i++ )
161
gdkpoints[i].x = points[i].x;
162
gdkpoints[i].y = points[i].y;
165
m_refData = new wxRegionRefData();
167
GdkRegion* reg = gdk_region_polygon
171
fillStyle == wxWINDING_RULE ? GDK_WINDING_RULE
175
M_REGIONDATA->m_region = reg;
181
wxRegion::~wxRegion()
183
// m_refData unrefed in ~wxObject
186
wxGDIRefData *wxRegion::CreateGDIRefData() const
188
// should never be called
193
wxGDIRefData *wxRegion::CloneGDIRefData(const wxGDIRefData *data) const
195
return new wxRegionRefData(*static_cast<const wxRegionRefData*>(data));
198
// ----------------------------------------------------------------------------
199
// wxRegion comparison
200
// ----------------------------------------------------------------------------
202
bool wxRegion::DoIsEqual(const wxRegion& region) const
205
return cairo_region_equal(
206
M_REGIONDATA->m_region, M_REGIONDATA_OF(region)->m_region);
208
return gdk_region_equal(M_REGIONDATA->m_region,
209
M_REGIONDATA_OF(region)->m_region) != 0;
213
// ----------------------------------------------------------------------------
214
// wxRegion operations
215
// ----------------------------------------------------------------------------
217
void wxRegion::Clear()
222
bool wxRegion::DoUnionWithRect(const wxRect& r)
224
// workaround for a strange GTK/X11 bug: taking union with an empty
225
// rectangle results in an empty region which is definitely not what we
232
InitRect(r.x, r.y, r.width, r.height);
241
rect.width = r.width;
242
rect.height = r.height;
245
cairo_region_union_rectangle(M_REGIONDATA->m_region, &rect);
247
gdk_region_union_with_rect( M_REGIONDATA->m_region, &rect );
254
bool wxRegion::DoUnionWithRegion( const wxRegion& region )
256
if (region.m_refData == NULL)
258
else if (m_refData == NULL)
260
m_refData = new wxRegionRefData(*M_REGIONDATA_OF(region));
266
cairo_region_union(M_REGIONDATA->m_region, M_REGIONDATA_OF(region)->m_region);
268
gdk_region_union( M_REGIONDATA->m_region, region.GetRegion() );
275
bool wxRegion::DoIntersect( const wxRegion& region )
277
if (region.m_refData == NULL || m_refData == NULL)
283
cairo_region_intersect(M_REGIONDATA->m_region, M_REGIONDATA_OF(region)->m_region);
285
gdk_region_intersect( M_REGIONDATA->m_region, region.GetRegion() );
291
bool wxRegion::DoSubtract( const wxRegion& region )
293
if (region.m_refData == NULL || m_refData == NULL)
299
cairo_region_subtract(M_REGIONDATA->m_region, M_REGIONDATA_OF(region)->m_region);
301
gdk_region_subtract( M_REGIONDATA->m_region, region.GetRegion() );
307
bool wxRegion::DoXor( const wxRegion& region )
309
if (region.m_refData == NULL)
311
else if (m_refData == NULL)
313
// XOR-ing with an invalid region is the same as XOR-ing with an empty
314
// one, i.e. it is simply a copy.
315
m_refData = new wxRegionRefData(*M_REGIONDATA_OF(region));
322
cairo_region_xor(M_REGIONDATA->m_region, M_REGIONDATA_OF(region)->m_region);
324
gdk_region_xor( M_REGIONDATA->m_region, region.GetRegion() );
331
bool wxRegion::DoOffset( wxCoord x, wxCoord y )
333
wxCHECK_MSG( m_refData, false, wxS("invalid region") );
338
cairo_region_translate(M_REGIONDATA->m_region, x, y);
340
gdk_region_offset( M_REGIONDATA->m_region, x, y );
346
// ----------------------------------------------------------------------------
348
// ----------------------------------------------------------------------------
350
bool wxRegion::DoGetBox( wxCoord &x, wxCoord &y, wxCoord &w, wxCoord &h ) const
356
cairo_region_get_extents(M_REGIONDATA->m_region, &rect);
358
gdk_region_get_clipbox( M_REGIONDATA->m_region, &rect );
378
bool wxRegion::IsEmpty() const
381
return m_refData == NULL || cairo_region_is_empty(M_REGIONDATA->m_region);
383
return m_refData == NULL || gdk_region_empty(M_REGIONDATA->m_region);
387
wxRegionContain wxRegion::DoContainsPoint( wxCoord x, wxCoord y ) const
390
if (m_refData == NULL || !cairo_region_contains_point(M_REGIONDATA->m_region, x, y))
392
if (m_refData == NULL || !gdk_region_point_in(M_REGIONDATA->m_region, x, y))
399
wxRegionContain wxRegion::DoContainsRect(const wxRect& r) const
407
rect.width = r.width;
408
rect.height = r.height;
410
switch (cairo_region_contains_rectangle(M_REGIONDATA->m_region, &rect))
412
case CAIRO_REGION_OVERLAP_IN: return wxInRegion;
413
case CAIRO_REGION_OVERLAP_PART: return wxPartRegion;
417
GdkOverlapType res = gdk_region_rect_in( M_REGIONDATA->m_region, &rect );
420
case GDK_OVERLAP_RECTANGLE_IN: return wxInRegion;
421
case GDK_OVERLAP_RECTANGLE_OUT: return wxOutRegion;
422
case GDK_OVERLAP_RECTANGLE_PART: return wxPartRegion;
429
cairo_region_t* wxRegion::GetRegion() const
431
GdkRegion *wxRegion::GetRegion() const
437
return M_REGIONDATA->m_region;
440
// ----------------------------------------------------------------------------
442
// ----------------------------------------------------------------------------
444
wxRegionIterator::wxRegionIterator()
450
wxRegionIterator::wxRegionIterator( const wxRegion& region )
456
void wxRegionIterator::Init()
462
wxRegionIterator::~wxRegionIterator()
467
void wxRegionIterator::CreateRects( const wxRegion& region )
473
cairo_region_t* cairoRegion = region.GetRegion();
474
if (cairoRegion == NULL)
476
m_numRects = cairo_region_num_rectangles(cairoRegion);
480
m_rects = new wxRect[m_numRects];
481
for (int i = 0; i < m_numRects; i++)
484
cairo_region_get_rectangle(cairoRegion, i, &gr);
485
wxRect &wr = m_rects[i];
489
wr.height = gr.height;
493
GdkRegion *gdkregion = region.GetRegion();
497
GdkRectangle* gdkrects;
498
gdk_region_get_rectangles(gdkregion, &gdkrects, &m_numRects);
502
m_rects = new wxRect[m_numRects];
503
for (int i = 0; i < m_numRects; ++i)
505
GdkRectangle &gr = gdkrects[i];
506
wxRect &wr = m_rects[i];
510
wr.height = gr.height;
517
void wxRegionIterator::Reset( const wxRegion& region )
524
bool wxRegionIterator::HaveRects() const
526
return m_current < m_numRects;
529
wxRegionIterator& wxRegionIterator::operator ++ ()
537
wxRegionIterator wxRegionIterator::operator ++ (int)
539
wxRegionIterator tmp = *this;
547
wxCoord wxRegionIterator::GetX() const
549
wxCHECK_MSG( HaveRects(), 0, wxT("invalid wxRegionIterator") );
551
return m_rects[m_current].x;
554
wxCoord wxRegionIterator::GetY() const
556
wxCHECK_MSG( HaveRects(), 0, wxT("invalid wxRegionIterator") );
558
return m_rects[m_current].y;
561
wxCoord wxRegionIterator::GetW() const
563
wxCHECK_MSG( HaveRects(), 0, wxT("invalid wxRegionIterator") );
565
return m_rects[m_current].width;
568
wxCoord wxRegionIterator::GetH() const
570
wxCHECK_MSG( HaveRects(), 0, wxT("invalid wxRegionIterator") );
572
return m_rects[m_current].height;
575
wxRect wxRegionIterator::GetRect() const
579
r = m_rects[m_current];
584
wxRegionIterator& wxRegionIterator::operator=(const wxRegionIterator& ri)
590
m_current = ri.m_current;
591
m_numRects = ri.m_numRects;
594
m_rects = new wxRect[m_numRects];
595
memcpy(m_rects, ri.m_rects, m_numRects * sizeof m_rects[0]);