source: trunk/src/kernel/qregion_pm.cpp@ 8

Last change on this file since 8 was 8, checked in by dmik, 20 years ago

Transferred Qt for OS/2 version 3.3.1-rc5 sources from the CVS

  • Property svn:keywords set to Id
File size: 10.8 KB
Line 
1/****************************************************************************
2** $Id: qregion_pm.cpp 8 2005-11-16 19:36:46Z dmik $
3**
4** Implementation of QRegion class for OS/2
5**
6** Copyright (C) 1992-2000 Trolltech AS. All rights reserved.
7** Copyright (C) 2004 Norman ASA. Initial OS/2 Port.
8** Copyright (C) 2005 netlabs.org. Further OS/2 Development.
9**
10** This file is part of the kernel module of the Qt GUI Toolkit.
11**
12** This file may be distributed under the terms of the Q Public License
13** as defined by Trolltech AS of Norway and appearing in the file
14** LICENSE.QPL included in the packaging of this file.
15**
16** This file may be distributed and/or modified under the terms of the
17** GNU General Public License version 2 as published by the Free Software
18** Foundation and appearing in the file LICENSE.GPL included in the
19** packaging of this file.
20**
21** Licensees holding valid Qt Enterprise Edition or Qt Professional Edition
22** licenses may use this file in accordance with the Qt Commercial License
23** Agreement provided with the Software.
24**
25** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
26** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
27**
28** See http://www.trolltech.com/pricing.html or email sales@trolltech.com for
29** information about Qt Commercial License Agreements.
30** See http://www.trolltech.com/qpl/ for QPL licensing information.
31** See http://www.trolltech.com/gpl/ for GPL licensing information.
32**
33** Contact info@trolltech.com if any conditions of this licensing are
34** not clear to you.
35**
36**********************************************************************/
37
38#include "qregion.h"
39#include "qpointarray.h"
40#include "qbuffer.h"
41#include "qbitmap.h"
42#include "qimage.h"
43#include "qt_os2.h"
44
45// We always create a GPI resuorce for a region with top and bottom corner
46// points made negative and swapped. This gives us no-cost top to bottom
47// flipping but requires to call GpiOffsetRegion() to offset the region up by
48// the height of the presentation space viewport before it is actually used on
49// that presentation space (usually for clipping) and, on the contrary, offset
50// the region got from GPI down before it is stored in QRegion.
51
52QRegion::QRegion()
53{
54 data = new QRegionData;
55 Q_CHECK_PTR( data );
56 data->rgn = 0;
57 data->is_null = TRUE;
58}
59
60QRegion::QRegion( bool is_null )
61{
62 data = new QRegionData;
63 Q_CHECK_PTR( data );
64 data->rgn = 0;
65 data->is_null = is_null;
66}
67
68QRegion::QRegion( const QRect &r, RegionType t )
69{
70 data = new QRegionData;
71 Q_CHECK_PTR( data );
72 data->is_null = FALSE;
73 if ( r.isEmpty() ) {
74 data->rgn = 0;
75 } else {
76 HPS hps = qt_display_ps();
77 if ( t == Rectangle ) { // rectangular region
78 RECTL rcl = { r.left(), -(r.bottom()+1), r.right()+1, -r.top() };
79 data->rgn = GpiCreateRegion( hps, 1, &rcl );
80 } else if ( t == Ellipse ) { // elliptic region
81//@@TODO (dmik): create elliptic regions using GpiCreateEllipticRegion() later.
82// now simply create it as rectangular.
83 RECTL rcl = { r.left(), -(r.bottom()+1), r.right()+1, -r.top() };
84 data->rgn = GpiCreateRegion( hps, 1, &rcl );
85 }
86 }
87}
88
89QRegion::QRegion( const QPointArray &a, bool winding )
90{
91 data = new QRegionData;
92 Q_CHECK_PTR( data );
93 data->is_null = FALSE;
94 QRect r = a.boundingRect();
95 if ( a.isEmpty() || r.isEmpty() ) {
96 data->rgn = 0;
97 } else {
98//@@TODO (dmik): create poligonal regions using GpiCreatePolygonRegion() later.
99// now simply create as bounding rectangle.
100 RECTL rcl = { r.left(), -(r.bottom()+1), r.right()+1, -r.top() };
101 data->rgn = GpiCreateRegion( qt_display_ps(), 1, &rcl );
102 }
103}
104
105QRegion::QRegion( const QRegion &r )
106{
107 data = r.data;
108 data->ref();
109}
110
111HRGN qt_pm_bitmapToRegion( const QBitmap& bitmap )
112{
113 HRGN region = 0;
114 QImage image = bitmap.convertToImage();
115 const int maxrect = 256;
116 RECTL rects[maxrect];
117 HPS hps = qt_display_ps();
118
119#define FlushSpans \
120 { \
121 HRGN r = GpiCreateRegion( hps, n, rects ); \
122 if ( region ) { \
123 GpiCombineRegion( hps, region, region, r, CRGN_OR ); \
124 GpiDestroyRegion( hps, r ); \
125 } else { \
126 region = r; \
127 } \
128 }
129
130#define AddSpan \
131 { \
132 rects[n].xLeft = prev1; \
133 rects[n].yBottom = -(y+1); \
134 rects[n].xRight = x-1+1; \
135 rects[n].yTop = -y; \
136 n++; \
137 if ( n == maxrect ) { \
138 FlushSpans \
139 n = 0; \
140 } \
141 }
142
143 int n = 0;
144 int zero = 0x00;
145
146 int x, y;
147 for ( y = 0; y < image.height(); y++ ) {
148 uchar *line = image.scanLine(y);
149 int w = image.width();
150 uchar all = zero;
151 int prev1 = -1;
152 for ( x = 0; x < w; ) {
153 uchar byte = line[x/8];
154 if ( x > w-8 || byte != all ) {
155 for ( int b = 8; b > 0 && x < w; b-- ) {
156 if ( !(byte & 0x80) == !all ) {
157 // More of the same
158 } else {
159 // A change.
160 if ( all != zero ) {
161 AddSpan;
162 all = zero;
163 } else {
164 prev1 = x;
165 all = ~zero;
166 }
167 }
168 byte <<= 1;
169 x++;
170 }
171 } else {
172 x += 8;
173 }
174 }
175 if ( all != zero ) {
176 AddSpan;
177 }
178 }
179 if ( n ) {
180 FlushSpans;
181 }
182
183 if ( !region )
184 region = GpiCreateRegion( hps, 0, NULL );
185
186 return region;
187}
188
189
190QRegion::QRegion( const QBitmap & bm )
191{
192 data = new QRegionData;
193 Q_CHECK_PTR( data );
194 data->is_null = FALSE;
195 if ( bm.isNull() )
196 data->rgn = 0;
197 else
198 data->rgn = qt_pm_bitmapToRegion( bm );
199}
200
201
202QRegion::~QRegion()
203{
204 if ( data->deref() ) {
205 if ( data->rgn )
206 GpiDestroyRegion( qt_display_ps(), data->rgn );
207 delete data;
208 }
209}
210
211QRegion &QRegion::operator=( const QRegion &r )
212{
213 r.data->ref(); // beware of r = r
214 if ( data->deref() ) {
215 if ( data->rgn )
216 GpiDestroyRegion( qt_display_ps(), data->rgn );
217 delete data;
218 }
219 data = r.data;
220 return *this;
221}
222
223
224QRegion QRegion::copy() const
225{
226 QRegion r ( data->is_null );
227 if ( !data->is_null && data->rgn ) {
228 HPS hps = qt_display_ps();
229 r.data->rgn = GpiCreateRegion( hps, 0, NULL );
230 GpiCombineRegion( hps, r.data->rgn, data->rgn, NULL, CRGN_COPY );
231 }
232 return r;
233}
234
235
236bool QRegion::isNull() const
237{
238 return data->is_null;
239}
240
241bool QRegion::isEmpty() const
242{
243 if ( data->is_null || data->rgn == 0 )
244 return TRUE;
245 RECTL rcl;
246 return GpiQueryRegionBox( qt_display_ps(), data->rgn, &rcl ) == RGN_NULL;
247}
248
249
250bool QRegion::contains( const QPoint &p ) const
251{
252 LONG rc = PRGN_OUTSIDE;
253 if ( data->rgn ) {
254 POINTL ptl = { p.x(), -(p.y()+1) };
255 rc = GpiPtInRegion( qt_display_ps(), data->rgn, &ptl );
256 }
257 return rc == PRGN_INSIDE;
258}
259
260bool QRegion::contains( const QRect &r ) const
261{
262 LONG rc = PRGN_OUTSIDE;
263 if ( data->rgn ) {
264 RECTL rcl = { r.left(), -(r.bottom()+1), r.right()+1, -r.top() };
265 rc = GpiRectInRegion( qt_display_ps(), data->rgn, &rcl );
266 }
267 return rc == RRGN_INSIDE || rc == RRGN_PARTIAL;
268}
269
270
271void QRegion::translate( int dx, int dy )
272{
273 if ( !data->rgn )
274 return;
275 detach();
276 POINTL ptl = { dx, -dy };
277 GpiOffsetRegion( qt_display_ps(), data->rgn, &ptl);
278}
279
280
281#define CRGN_NOP -1
282
283/*
284 Performs the actual OR, AND, SUB and XOR operation between regions.
285 Sets the resulting region handle to 0 to indicate an empty region.
286*/
287
288QRegion QRegion::pmCombine( const QRegion &r, int op ) const
289{
290 LONG both = CRGN_NOP, left = CRGN_NOP, right = CRGN_NOP;
291 switch ( op ) {
292 case QRGN_OR:
293 both = CRGN_OR;
294 left = right = CRGN_COPY;
295 break;
296 case QRGN_AND:
297 both = CRGN_AND;
298 break;
299 case QRGN_SUB:
300 both = CRGN_DIFF;
301 left = CRGN_COPY;
302 break;
303 case QRGN_XOR:
304 both = CRGN_XOR;
305 left = right = CRGN_COPY;
306 break;
307 default:
308#if defined(QT_CHECK_RANGE)
309 qWarning( "QRegion: Internal error in pmCombine" );
310#else
311 ;
312#endif
313 }
314
315 QRegion result( FALSE );
316 if ( !data->rgn && !r.data->rgn )
317 return result;
318 HPS hps = qt_display_ps();
319 result.data->rgn = GpiCreateRegion( hps, 0, NULL );
320 if ( data->rgn && r.data->rgn )
321 GpiCombineRegion( hps, result.data->rgn, data->rgn, r.data->rgn, both );
322 else if ( data->rgn && left != CRGN_NOP )
323 GpiCombineRegion( hps, result.data->rgn, data->rgn, NULL, left );
324 else if ( r.data->rgn && right != CRGN_NOP )
325 GpiCombineRegion( hps, result.data->rgn, r.data->rgn, NULL, right );
326 return result;
327}
328
329QRegion QRegion::unite( const QRegion &r ) const
330{
331 return pmCombine( r, QRGN_OR );
332}
333
334QRegion QRegion::intersect( const QRegion &r ) const
335{
336 return pmCombine( r, QRGN_AND );
337}
338
339QRegion QRegion::subtract( const QRegion &r ) const
340{
341 return pmCombine( r, QRGN_SUB );
342}
343
344QRegion QRegion::eor( const QRegion &r ) const
345{
346 return pmCombine( r, QRGN_XOR );
347}
348
349
350QRect QRegion::boundingRect() const
351{
352 RECTL rcl;
353 LONG rc = RGN_NULL;
354 if ( data->rgn )
355 rc = GpiQueryRegionBox( qt_display_ps(), data->rgn, &rcl );
356 if ( rc == RGN_NULL )
357 return QRect(0,0,0,0);
358 else
359 return QRect(rcl.xLeft, -rcl.yTop, rcl.xRight-rcl.xLeft, rcl.yTop-rcl.yBottom );
360}
361
362
363QMemArray<QRect> QRegion::rects() const
364{
365 QMemArray<QRect> a;
366 if ( !data->rgn )
367 return a;
368
369 HPS hps = qt_display_ps();
370 RGNRECT ctl = {1, 0, 0, RECTDIR_LFRT_TOPBOT};
371 if ( !GpiQueryRegionRects( hps, data->rgn, NULL, &ctl, NULL ) )
372 return a;
373
374 ctl.crc = ctl.crcReturned;
375 PRECTL rcls = new RECTL[ctl.crcReturned];
376 if ( !GpiQueryRegionRects( hps, data->rgn, NULL, &ctl, rcls ) ) {
377 delete [] rcls;
378 return a;
379 }
380
381 a = QMemArray<QRect>( ctl.crcReturned );
382 PRECTL r = rcls;
383 for ( int i=0; i<(int)a.size(); i++ ) {
384 a[i].setRect( r->xLeft, -r->yTop, r->xRight-r->xLeft, r->yTop-r->yBottom );
385 r++;
386 }
387
388 delete [] rcls;
389
390 return a;
391}
392
393void QRegion::setRects( const QRect *rects, int num )
394{
395 // Could be optimized
396 *this = QRegion();
397 for (int i=0; i<num; i++)
398 *this |= rects[i];
399}
400
401bool QRegion::operator==( const QRegion &r ) const
402{
403 if ( data == r.data ) // share the same data
404 return TRUE;
405 bool is_empty = data->is_null || data->rgn == 0;
406 bool r_is_empty = r.data->is_null || r.data->rgn == 0;
407 if ( (is_empty ^ r_is_empty ) ) // one is empty, not both
408 return FALSE;
409 return is_empty ?
410 TRUE : // both empty
411 GpiEqualRegion( qt_display_ps(), data->rgn, r.data->rgn ) == EQRGN_EQUAL;
412}
413
414void QRegion::update() const
415{
416 // lazy initialization. this method should be called only from handle()
417 data->rgn = GpiCreateRegion( qt_display_ps(), 0, NULL );
418}
Note: See TracBrowser for help on using the repository browser.