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]);