1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/gtk/region.cpp
4 // Author: Robert Roebling
5 // Modified: VZ at 05.10.00: use AllocExclusive(), comparison fixed
7 // Copyright: (c) 1998 Robert Roebling
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // ============================================================================
13 // ============================================================================
15 // ----------------------------------------------------------------------------
17 // ----------------------------------------------------------------------------
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
22 #include "wx/region.h"
26 // ----------------------------------------------------------------------------
27 // wxRegionRefData: private class containing the information about the region
28 // ----------------------------------------------------------------------------
30 class wxRegionRefData
: public wxGDIRefData
38 wxRegionRefData(const wxRegionRefData
& refData
)
42 m_region
= cairo_region_copy(refData
.m_region
);
44 m_region
= gdk_region_copy(refData
.m_region
);
48 virtual ~wxRegionRefData()
53 cairo_region_destroy(m_region
);
55 gdk_region_destroy( m_region
);
61 cairo_region_t
* m_region
;
67 // ----------------------------------------------------------------------------
69 // ----------------------------------------------------------------------------
71 #define M_REGIONDATA static_cast<wxRegionRefData*>(m_refData)
72 #define M_REGIONDATA_OF(r) static_cast<wxRegionRefData*>(r.m_refData)
74 IMPLEMENT_DYNAMIC_CLASS(wxRegion
, wxGDIObject
)
75 IMPLEMENT_DYNAMIC_CLASS(wxRegionIterator
,wxObject
)
77 // ----------------------------------------------------------------------------
78 // wxRegion construction
79 // ----------------------------------------------------------------------------
81 void wxRegion::InitRect(wxCoord x
, wxCoord y
, wxCoord w
, wxCoord h
)
89 m_refData
= new wxRegionRefData();
92 M_REGIONDATA
->m_region
= cairo_region_create_rectangle(&rect
);
94 M_REGIONDATA
->m_region
= gdk_region_rectangle( &rect
);
99 wxRegion::wxRegion(const GdkRegion
* region
)
101 m_refData
= new wxRegionRefData();
102 M_REGIONDATA
->m_region
= gdk_region_copy(const_cast<GdkRegion
*>(region
));
106 wxRegion::wxRegion( size_t n
, const wxPoint
*points
,
107 wxPolygonFillMode fillStyle
)
110 // Make a cairo path from the points, draw it onto an image surface, use
111 // gdk_cairo_region_create_from_surface() to get a cairo region
113 // need at least 3 points to make a useful polygon
117 int min_x
= points
[0].x
;
119 int min_y
= points
[0].y
;
122 for (i
= 1; i
< n
; i
++)
124 const int x
= points
[i
].x
;
129 const int y
= points
[i
].y
;
135 const int w
= max_x
- min_x
+ 1;
136 const int h
= max_y
- min_y
+ 1;
137 // make surface just big enough to contain polygon (A1 is native format
138 // for gdk_cairo_region_create_from_surface)
139 cairo_surface_t
* surface
= cairo_image_surface_create(CAIRO_FORMAT_A1
, w
, h
);
140 memset(cairo_image_surface_get_data(surface
), 0, cairo_image_surface_get_stride(surface
) * h
);
141 cairo_surface_mark_dirty(surface
);
142 cairo_surface_set_device_offset(surface
, -min_x
, -min_y
);
143 cairo_t
* cr
= cairo_create(surface
);
144 cairo_set_antialias(cr
, CAIRO_ANTIALIAS_NONE
);
145 if (fillStyle
== wxODDEVEN_RULE
)
146 cairo_set_fill_rule(cr
, CAIRO_FILL_RULE_EVEN_ODD
);
148 cairo_move_to(cr
, points
[0].x
, points
[0].y
);
149 for (i
= 1; i
< n
; i
++)
150 cairo_line_to(cr
, points
[i
].x
, points
[i
].y
);
151 cairo_close_path(cr
);
154 cairo_surface_flush(surface
);
155 m_refData
= new wxRegionRefData
;
156 M_REGIONDATA
->m_region
= gdk_cairo_region_create_from_surface(surface
);
157 cairo_surface_destroy(surface
);
159 GdkPoint
*gdkpoints
= new GdkPoint
[n
];
160 for ( size_t i
= 0 ; i
< n
; i
++ )
162 gdkpoints
[i
].x
= points
[i
].x
;
163 gdkpoints
[i
].y
= points
[i
].y
;
166 m_refData
= new wxRegionRefData();
168 GdkRegion
* reg
= gdk_region_polygon
172 fillStyle
== wxWINDING_RULE
? GDK_WINDING_RULE
176 M_REGIONDATA
->m_region
= reg
;
182 wxRegion::~wxRegion()
184 // m_refData unrefed in ~wxObject
187 wxGDIRefData
*wxRegion::CreateGDIRefData() const
189 // should never be called
194 wxGDIRefData
*wxRegion::CloneGDIRefData(const wxGDIRefData
*data
) const
196 return new wxRegionRefData(*static_cast<const wxRegionRefData
*>(data
));
199 // ----------------------------------------------------------------------------
200 // wxRegion comparison
201 // ----------------------------------------------------------------------------
203 bool wxRegion::DoIsEqual(const wxRegion
& region
) const
206 return cairo_region_equal(
207 M_REGIONDATA
->m_region
, M_REGIONDATA_OF(region
)->m_region
);
209 return gdk_region_equal(M_REGIONDATA
->m_region
,
210 M_REGIONDATA_OF(region
)->m_region
) != 0;
214 // ----------------------------------------------------------------------------
215 // wxRegion operations
216 // ----------------------------------------------------------------------------
218 void wxRegion::Clear()
223 bool wxRegion::DoUnionWithRect(const wxRect
& r
)
225 // workaround for a strange GTK/X11 bug: taking union with an empty
226 // rectangle results in an empty region which is definitely not what we
233 InitRect(r
.x
, r
.y
, r
.width
, r
.height
);
242 rect
.width
= r
.width
;
243 rect
.height
= r
.height
;
246 cairo_region_union_rectangle(M_REGIONDATA
->m_region
, &rect
);
248 gdk_region_union_with_rect( M_REGIONDATA
->m_region
, &rect
);
255 bool wxRegion::DoUnionWithRegion( const wxRegion
& region
)
257 if (region
.m_refData
== NULL
)
259 else if (m_refData
== NULL
)
261 m_refData
= new wxRegionRefData(*M_REGIONDATA_OF(region
));
267 cairo_region_union(M_REGIONDATA
->m_region
, M_REGIONDATA_OF(region
)->m_region
);
269 gdk_region_union( M_REGIONDATA
->m_region
, region
.GetRegion() );
276 bool wxRegion::DoIntersect( const wxRegion
& region
)
278 if (region
.m_refData
== NULL
|| m_refData
== NULL
)
284 cairo_region_intersect(M_REGIONDATA
->m_region
, M_REGIONDATA_OF(region
)->m_region
);
286 gdk_region_intersect( M_REGIONDATA
->m_region
, region
.GetRegion() );
292 bool wxRegion::DoSubtract( const wxRegion
& region
)
294 if (region
.m_refData
== NULL
|| m_refData
== NULL
)
300 cairo_region_subtract(M_REGIONDATA
->m_region
, M_REGIONDATA_OF(region
)->m_region
);
302 gdk_region_subtract( M_REGIONDATA
->m_region
, region
.GetRegion() );
308 bool wxRegion::DoXor( const wxRegion
& region
)
310 if (region
.m_refData
== NULL
)
312 else if (m_refData
== NULL
)
314 // XOR-ing with an invalid region is the same as XOR-ing with an empty
315 // one, i.e. it is simply a copy.
316 m_refData
= new wxRegionRefData(*M_REGIONDATA_OF(region
));
323 cairo_region_xor(M_REGIONDATA
->m_region
, M_REGIONDATA_OF(region
)->m_region
);
325 gdk_region_xor( M_REGIONDATA
->m_region
, region
.GetRegion() );
332 bool wxRegion::DoOffset( wxCoord x
, wxCoord y
)
334 wxCHECK_MSG( m_refData
, false, wxS("invalid region") );
339 cairo_region_translate(M_REGIONDATA
->m_region
, x
, y
);
341 gdk_region_offset( M_REGIONDATA
->m_region
, x
, y
);
347 // ----------------------------------------------------------------------------
349 // ----------------------------------------------------------------------------
351 bool wxRegion::DoGetBox( wxCoord
&x
, wxCoord
&y
, wxCoord
&w
, wxCoord
&h
) const
357 cairo_region_get_extents(M_REGIONDATA
->m_region
, &rect
);
359 gdk_region_get_clipbox( M_REGIONDATA
->m_region
, &rect
);
379 bool wxRegion::IsEmpty() const
382 return m_refData
== NULL
|| cairo_region_is_empty(M_REGIONDATA
->m_region
);
384 return m_refData
== NULL
|| gdk_region_empty(M_REGIONDATA
->m_region
);
388 wxRegionContain
wxRegion::DoContainsPoint( wxCoord x
, wxCoord y
) const
391 if (m_refData
== NULL
|| !cairo_region_contains_point(M_REGIONDATA
->m_region
, x
, y
))
393 if (m_refData
== NULL
|| !gdk_region_point_in(M_REGIONDATA
->m_region
, x
, y
))
400 wxRegionContain
wxRegion::DoContainsRect(const wxRect
& r
) const
408 rect
.width
= r
.width
;
409 rect
.height
= r
.height
;
411 switch (cairo_region_contains_rectangle(M_REGIONDATA
->m_region
, &rect
))
413 case CAIRO_REGION_OVERLAP_IN
: return wxInRegion
;
414 case CAIRO_REGION_OVERLAP_PART
: return wxPartRegion
;
418 GdkOverlapType res
= gdk_region_rect_in( M_REGIONDATA
->m_region
, &rect
);
421 case GDK_OVERLAP_RECTANGLE_IN
: return wxInRegion
;
422 case GDK_OVERLAP_RECTANGLE_OUT
: return wxOutRegion
;
423 case GDK_OVERLAP_RECTANGLE_PART
: return wxPartRegion
;
430 cairo_region_t
* wxRegion::GetRegion() const
432 GdkRegion
*wxRegion::GetRegion() const
438 return M_REGIONDATA
->m_region
;
441 // ----------------------------------------------------------------------------
443 // ----------------------------------------------------------------------------
445 wxRegionIterator::wxRegionIterator()
451 wxRegionIterator::wxRegionIterator( const wxRegion
& region
)
457 void wxRegionIterator::Init()
463 wxRegionIterator::~wxRegionIterator()
468 void wxRegionIterator::CreateRects( const wxRegion
& region
)
474 cairo_region_t
* cairoRegion
= region
.GetRegion();
475 if (cairoRegion
== NULL
)
477 m_numRects
= cairo_region_num_rectangles(cairoRegion
);
481 m_rects
= new wxRect
[m_numRects
];
482 for (int i
= 0; i
< m_numRects
; i
++)
485 cairo_region_get_rectangle(cairoRegion
, i
, &gr
);
486 wxRect
&wr
= m_rects
[i
];
490 wr
.height
= gr
.height
;
494 GdkRegion
*gdkregion
= region
.GetRegion();
498 GdkRectangle
* gdkrects
;
499 gdk_region_get_rectangles(gdkregion
, &gdkrects
, &m_numRects
);
503 m_rects
= new wxRect
[m_numRects
];
504 for (int i
= 0; i
< m_numRects
; ++i
)
506 GdkRectangle
&gr
= gdkrects
[i
];
507 wxRect
&wr
= m_rects
[i
];
511 wr
.height
= gr
.height
;
518 void wxRegionIterator::Reset( const wxRegion
& region
)
525 bool wxRegionIterator::HaveRects() const
527 return m_current
< m_numRects
;
530 wxRegionIterator
& wxRegionIterator::operator ++ ()
538 wxRegionIterator
wxRegionIterator::operator ++ (int)
540 wxRegionIterator tmp
= *this;
548 wxCoord
wxRegionIterator::GetX() const
550 wxCHECK_MSG( HaveRects(), 0, wxT("invalid wxRegionIterator") );
552 return m_rects
[m_current
].x
;
555 wxCoord
wxRegionIterator::GetY() const
557 wxCHECK_MSG( HaveRects(), 0, wxT("invalid wxRegionIterator") );
559 return m_rects
[m_current
].y
;
562 wxCoord
wxRegionIterator::GetW() const
564 wxCHECK_MSG( HaveRects(), 0, wxT("invalid wxRegionIterator") );
566 return m_rects
[m_current
].width
;
569 wxCoord
wxRegionIterator::GetH() const
571 wxCHECK_MSG( HaveRects(), 0, wxT("invalid wxRegionIterator") );
573 return m_rects
[m_current
].height
;
576 wxRect
wxRegionIterator::GetRect() const
580 r
= m_rects
[m_current
];
585 wxRegionIterator
& wxRegionIterator::operator=(const wxRegionIterator
& ri
)
591 m_current
= ri
.m_current
;
592 m_numRects
= ri
.m_numRects
;
595 m_rects
= new wxRect
[m_numRects
];
596 memcpy(m_rects
, ri
.m_rects
, m_numRects
* sizeof m_rects
[0]);