source: trunk/src/kernel/qpainter_pm.cpp@ 62

Last change on this file since 62 was 62, checked in by dmik, 19 years ago

Fixed QPainter::drawRoundRect(): the background of rectangles with rounded corners was 1 pixel taller than the frame.

  • Property svn:keywords set to Id
File size: 64.6 KB
Line 
1/****************************************************************************
2** $Id: qpainter_pm.cpp 62 2006-02-22 09:17:33Z dmik $
3**
4** Implementation of QPainter 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 "qpainter.h"
39#include "qpaintdevicemetrics.h"
40#include "qwidget.h"
41#include "qbitmap.h"
42#include "qpixmapcache.h"
43#include "qptrlist.h"
44/// @todo (dmik) later
45//#include "qprinter.h"
46#include <stdlib.h>
47#include <math.h>
48#include "qapplication_p.h"
49#include "qfontdata_p.h"
50#include "qt_os2.h"
51#include "qtextlayout_p.h"
52#include "qtextengine_p.h"
53#include "qfontengine_p.h"
54
55// QRgb has the same RGB format (0xaarrggbb) as OS/2 uses (ignoring the
56// highest alpha byte) so we just mask alpha to get the valid OS/2 color.
57#define COLOR_VALUE(c) ((flags & RGBColor) ? (c.rgb() & RGB_MASK) : c.pixel())
58
59// Innotek GCC lacks some API functions in its version of OS/2 Toolkit headers
60#if defined(Q_CC_GNU) && !defined(USE_OS2_TOOLKIT_HEADERS)
61extern "C" LONG APIENTRY GpiQueryNearestPaletteIndex(HPAL hpal, ULONG color);
62#endif
63
64// this function fixes a bug in OS/2 GPI: GpiSetBackColor() doesn't
65// change the background color attribute of line primitives.
66BOOL qt_GpiSetBackColor( HPS hps, LONG color )
67{
68 BOOL rc = FALSE;
69 rc = GpiSetBackColor( hps, color );
70 LINEBUNDLE lb;
71 lb.lBackColor = color;
72 rc &= GpiSetAttrs( hps, PRIM_LINE, LBB_BACK_COLOR, 0, (PBUNDLE) &lb );
73 return rc;
74}
75
76// this function fixes a bug in OS/2 GPI: GpiSetBackMix() doesn't
77// change the mix color attribute of line primitives. it also takes into
78// account the current pen style.
79BOOL qt_GpiSetBackMix( HPS hps, LONG mix, BOOL noPen )
80{
81 BOOL rc = FALSE;
82 rc = GpiSetBackMix( hps, mix );
83 LINEBUNDLE lb;
84 lb.usBackMixMode = noPen ? BM_LEAVEALONE : mix;
85 rc &= GpiSetAttrs( hps, PRIM_LINE, LBB_BACK_MIX_MODE, 0, (PBUNDLE) &lb );
86 return rc;
87}
88
89// helpers to draw geometric width lines
90
91struct qt_geom_line_handle
92{
93 enum { AreaAttrs = ABB_COLOR | ABB_SET | ABB_SYMBOL | ABB_BACK_MIX_MODE };
94 LONG aa;
95 AREABUNDLE ab;
96};
97
98void qt_begin_geom_line( HPS hps, LONG color, BOOL noPen, qt_geom_line_handle *h )
99{
100 Q_ASSERT( h );
101 h->aa = 0;
102 GpiQueryAttrs( hps, PRIM_AREA, h->AreaAttrs, &h->ab );
103 AREABUNDLE ab;
104 if ( h->ab.lColor != color ) {
105 ab.lColor = color;
106 h->aa |= ABB_COLOR;
107 }
108 if ( h->ab.usSet != LCID_DEFAULT ) {
109 ab.usSet = LCID_DEFAULT;
110 h->aa |= ABB_SET;
111 }
112 ab.usSymbol = noPen ? PATSYM_BLANK : PATSYM_SOLID;
113 if ( h->ab.usSymbol != ab.usSymbol ) {
114 h->aa |= ABB_SYMBOL;
115 }
116 if ( noPen && h->ab.usBackMixMode != BM_LEAVEALONE ) {
117 ab.usBackMixMode = BM_LEAVEALONE;
118 h->aa |= ABB_BACK_MIX_MODE;
119 }
120 GpiSetAttrs( hps, PRIM_AREA, h->aa, 0, &ab );
121 GpiBeginPath( hps, 1 );
122}
123
124void qt_end_geom_line( HPS hps, qt_geom_line_handle *h )
125{
126 GpiEndPath( hps );
127 GpiStrokePath( hps, 1, 0 );
128 GpiSetAttrs( hps, PRIM_AREA, h->aa, 0, &h->ab );
129}
130
131/* These functions are implemented in qapplication_pm.cpp */
132extern void qt_fill_tile( QPixmap *, const QPixmap & );
133extern void qt_draw_tiled_pixmap( HPS, int, int, int, int,
134 const QPixmap *, int, int, int );
135
136void qt_erase_background(
137 HPS hps, int x, int y, int w, int h,
138 const QColor &bg_color,
139 const QPixmap *bg_pixmap, int off_x, int off_y, int devh
140)
141{
142 if ( bg_pixmap && bg_pixmap->isNull() ) // empty background
143 return;
144 HPAL oldPal = 0;
145 if ( QColor::hPal() ) {
146 oldPal = GpiSelectPalette( hps, QColor::hPal() );
147 } else {
148 // direct RGB mode
149 GpiCreateLogColorTable( hps, 0, LCOLF_RGB, 0, 0, NULL );
150 }
151 if ( bg_pixmap ) {
152 // normalize pixmap offsets according to x and y
153 // to ensure that the offsets are always relative to
154 // the background origin point, regardless of what x and y are.
155 off_x = (off_x + x) % bg_pixmap->width();
156 off_y = (off_y + y) % bg_pixmap->height();
157 qt_draw_tiled_pixmap( hps, x, y, w, h, bg_pixmap, off_x, off_y, devh );
158 } else {
159 // flip y coordinate
160 if ( devh )
161 y = devh - (y + h);
162 // this function should be called only with window presentation space
163 // so simply use WinFillRect instead of GpiBox.
164 RECTL rcl = { x, y, x + w, y + h };
165 WinFillRect( hps, &rcl, bg_color.pixel() );
166 }
167 if ( QColor::hPal() ) {
168 GpiSelectPalette( hps, oldPal );
169 }
170}
171
172/*****************************************************************************
173 QPainter member functions
174 *****************************************************************************/
175
176void QPainter::initialize()
177{
178}
179
180void QPainter::cleanup()
181{
182}
183
184void QPainter::destroy()
185{
186
187}
188
189void QPainter::init()
190{
191 d = 0;
192 flags = IsStartingUp;
193 pdev = 0;
194 bg_col = white; // default background color
195 bg_mode = TransparentMode; // default background mode
196 rop = CopyROP; // default ROP
197 tabstops = 0; // default tabbing
198 tabarray = 0;
199 tabarraylen = 0;
200 block_ext = FALSE;
201 txop = txinv = 0;
202 ps_stack = 0;
203 wm_stack = 0;
204 hps = 0;
205 holdpal = 0;
206 holdrgn = HRGN_ERROR;
207 hbrushbm = 0;
208 pixmapBrush = nocolBrush = FALSE;
209 devh = 0;
210 pfont = 0;
211}
212
213
214void QPainter::setFont( const QFont &font )
215{
216#if defined(QT_CHECK_STATE)
217 if ( !isActive() )
218 qWarning( "QPainter::setFont: Will be reset by begin()" );
219#endif
220 if ( cfont.d != font.d || testf(VolatileDC) ) {
221 cfont = font;
222 setf(DirtyFont);
223 }
224}
225
226
227void QPainter::updateFont()
228{
229 QFont *temp = 0;
230 clearf(DirtyFont);
231 if ( testf(ExtDev) ) {
232 QPDevCmdParam param[1];
233 param[0].font = &cfont;
234 if ( !pdev->cmd( QPaintDevice::PdcSetFont, this, param ) || !hps )
235 return;
236 }
237 if ( pdev->devType() == QInternal::Printer ) {
238 //int dw = pdev->metric( QPaintDeviceMetrics::PdmWidth );
239 //int dh = pdev->metric( QPaintDeviceMetrics::PdmHeight );
240 // ### fix compat mode
241 //bool vxfScale = testf(Qt2Compat) && testf(VxF)
242 // && ( dw != ww || dw != vw || dh != wh || dh != vh );
243
244 if ( pfont ) temp = pfont;
245 pfont = new QFont( cfont.d, pdev );
246 pfont->selectTo( hps );
247 } else {
248 if ( pfont ) {
249 temp = pfont;
250 pfont = 0;
251 }
252 cfont.selectTo( hps );
253 }
254 delete temp;
255}
256
257
258void QPainter::updatePen()
259{
260 if ( testf(ExtDev) ) {
261 QPDevCmdParam param[1];
262 param[0].pen = &cpen;
263 if ( !pdev->cmd(QPaintDevice::PdcSetPen,this,param) || !hps )
264 return;
265 }
266
267 ULONG LineAttrs = LBB_COLOR | LBB_TYPE | LBB_BACK_MIX_MODE;
268 LINEBUNDLE lb;
269 lb.lColor = COLOR_VALUE( cpen.color() );
270 lb.usBackMixMode = GpiQueryBackMix( hps );
271
272 switch ( cpen.style() ) {
273 case NoPen:
274 lb.usType = LINETYPE_INVISIBLE;
275 lb.usBackMixMode = BM_LEAVEALONE;
276 break;
277 case SolidLine:
278 lb.usType = LINETYPE_SOLID;
279 break;
280 case DashLine:
281 lb.usType = LINETYPE_LONGDASH;
282 break;
283 case DotLine:
284 lb.usType = LINETYPE_DOT;
285 break;
286 case DashDotLine:
287 lb.usType = LINETYPE_DASHDOT;
288 break;
289 case DashDotDotLine:
290 lb.usType = LINETYPE_DASHDOUBLEDOT;
291 break;
292 case MPenStyle:
293#if defined(QT_CHECK_STATE)
294 qWarning("QPainter::updatePen: MPenStyle used as a value. It is a mask!");
295#endif
296 break;
297 }
298
299 if ( cpen.width() > 1 ) {
300 LineAttrs |= LBB_END;
301 switch ( cpen.capStyle() ) {
302 case SquareCap:
303 lb.usEnd = LINEEND_SQUARE;
304 break;
305 case RoundCap:
306 lb.usEnd = LINEEND_ROUND;
307 break;
308 case FlatCap:
309 lb.usEnd = LINEEND_FLAT;
310 break;
311 case MPenCapStyle:
312 LineAttrs &= ~LBB_END;
313#if defined(QT_CHECK_STATE)
314 qWarning("QPainter::updatePen: MPenCapStyle used as a value. It is a mask!");
315#endif
316 break;
317 }
318 LineAttrs |= LBB_JOIN;
319 switch ( cpen.joinStyle() ) {
320 case BevelJoin:
321 lb.usJoin = LINEJOIN_BEVEL;
322 break;
323 case RoundJoin:
324 lb.usJoin = LINEJOIN_ROUND;
325 break;
326 case MiterJoin:
327 lb.usJoin = LINEJOIN_MITRE;
328 break;
329 case MPenJoinStyle:
330 LineAttrs &= ~LBB_JOIN;
331#if defined(QT_CHECK_STATE)
332 qWarning("QPainter::updatePen: MPenJoinStyle used as a value. It is a mask!");
333#endif
334 break;
335 }
336 LineAttrs |= LBB_GEOM_WIDTH;
337 lb.lGeomWidth = cpen.width();
338 }
339 GpiSetAttrs( hps, PRIM_LINE, LineAttrs, 0, (PBUNDLE) &lb );
340 // also set the image color attribute used to draw bitmaps
341 // and char color attribute for drawing text
342 GpiSetAttrs( hps, PRIM_IMAGE, IBB_COLOR, 0, (PBUNDLE) &lb );
343 GpiSetAttrs( hps, PRIM_CHAR, CBB_COLOR, 0, (PBUNDLE) &lb );
344}
345
346void QPainter::updateBrush()
347{
348 if ( testf(ExtDev) ) {
349 QPDevCmdParam param[1];
350 param[0].brush = &cbrush;
351 if ( !pdev->cmd(QPaintDevice::PdcSetBrush,this,param) || !hps )
352 return;
353 }
354
355 AREABUNDLE ab;
356 ab.lColor = COLOR_VALUE( cbrush.data->color );
357 GpiSetAttrs( hps, PRIM_AREA, ABB_COLOR, 0, &ab );
358
359 // pattern attrs make sence for area attrs only, so we use global
360 // GpiSetPattern*() calls below (it's necessary to set them separately).
361
362 // delete the brush LCID if any
363 if ( hbrushbm ) {
364 GpiSetPatternSet( hps, LCID_DEFAULT );
365 GpiDeleteSetId( hps, LCID_QTPixmapBrush );
366 }
367
368 /// @todo (dmik) possibly pixmapBrush is not needed, hbrushbm and
369 // CustomPattern can substitute it.
370 pixmapBrush = nocolBrush = FALSE;
371 hbrushbm = 0;
372
373 int bs = cbrush.style();
374 if ( bs == CustomPattern ) {
375 HPS hbrushps = cbrush.pixmap()->hps;
376 hbrushbm = cbrush.pixmap()->hbm();
377 pixmapBrush = TRUE;
378 nocolBrush = cbrush.pixmap()->depth() == 1;
379 GpiSetBitmap( hbrushps, 0 );
380 GpiSetBitmapId( hps, hbrushbm, LCID_QTPixmapBrush );
381 GpiSetPatternSet( hps, LCID_QTPixmapBrush );
382 GpiSetBitmap( hbrushps, hbrushbm );
383 } else {
384 LONG pat;
385 if ( bs >= Dense1Pattern && bs <= Dense7Pattern ) {
386 pat = PATSYM_DENSE2 + (bs - Dense1Pattern);
387 } else {
388 switch ( bs ) {
389 case NoBrush:
390 pat = PATSYM_BLANK;
391 break;
392 case SolidPattern:
393 pat = PATSYM_SOLID;
394 break;
395 case HorPattern:
396 pat = PATSYM_HORIZ;
397 break;
398 case VerPattern:
399 pat = PATSYM_VERT;
400 break;
401 case CrossPattern:
402 pat = PATSYM_HATCH;
403 break;
404 case BDiagPattern:
405 pat = PATSYM_DIAG1;
406 break;
407 case FDiagPattern:
408 pat = PATSYM_DIAG3;
409 break;
410 case DiagCrossPattern:
411 pat = PATSYM_DIAGHATCH;
412 break;
413 default:
414 pat = PATSYM_HORIZ;
415 }
416 }
417 nocolBrush = TRUE;
418 GpiSetPatternSet( hps, LCID_DEFAULT );
419 GpiSetPattern( hps, pat );
420 }
421}
422
423
424bool QPainter::begin( const QPaintDevice *pd, bool unclipped )
425{
426 if ( isActive() ) { // already active painting
427#if defined(QT_CHECK_STATE)
428 qWarning( "QPainter::begin: Painter is already active."
429 "\n\tYou must end() the painter before a second begin()" );
430#endif
431 return FALSE;
432 }
433 if ( pd == 0 ) {
434#if defined(QT_CHECK_NULL)
435 qWarning( "QPainter::begin: Paint device cannot be null" );
436#endif
437 return FALSE;
438 }
439
440 const QWidget *copyFrom = 0;
441 pdev = redirect( (QPaintDevice*)pd );
442 if ( pdev ) { // redirected paint device?
443 if ( pd->devType() == QInternal::Widget )
444 copyFrom = (const QWidget *)pd; // copy widget settings
445 } else {
446 pdev = (QPaintDevice*)pd;
447 }
448
449 if ( pdev->isExtDev() && pdev->paintingActive() ) { // somebody else is already painting
450#if defined(QT_CHECK_STATE)
451 qWarning( "QPainter::begin: Another QPainter is already painting "
452 "this device;\n\tAn extended paint device can only be "
453 "painted by one QPainter at a time" );
454#endif
455 return FALSE;
456 }
457
458 bool reinit = flags != IsStartingUp; // 2nd, 3rd,.... time called
459 flags = 0x0; // init flags
460 int dt = pdev->devType(); // get the device type
461
462 if ( (pdev->devFlags & QInternal::ExternalDevice) != 0 )
463 setf(ExtDev); // this is an extended device
464 if ( (pdev->devFlags & QInternal::CompatibilityMode) != 0 )
465 setf(Qt2Compat);
466 else if ( dt == QInternal::Pixmap ) { // device is a pixmap
467 QPixmap *pm = (QPixmap*) pdev; // will modify it
468 pm->detach();
469 // Ensure the auxiliary masked bitmap created for masking is destroyed
470 // (to cause it to be recreated when the pixmap is blitted next time).
471 // Also ensure the alpha channel of the pixmap is unfolded -- any GPI
472 // call will clear the high byte that may be storing the alpha bits,
473 // so the pixmap will appear as fully transparent.
474 if ( pm->data->mask )
475 pm->prepareForMasking( FALSE, TRUE );
476 if ( pm->data->hasRealAlpha )
477 pm->unfoldAlphaChannel();
478 }
479
480 hps = 0;
481 holdpal = 0;
482 holdrgn = HRGN_ERROR;
483 devh = 0;
484
485 QRegion *repaintRgn = 0;
486
487 if ( testf(ExtDev) ) { // external device
488 if ( !pdev->cmd(QPaintDevice::PdcBegin,this,0) ) {
489 pdev = 0; // could not begin
490 clearf( IsActive | DirtyFont | ExtDev );
491 return FALSE;
492 }
493 if ( tabstops ) // update tabstops for device
494 setTabStops( tabstops );
495 if ( tabarray ) // update tabarray for device
496 setTabArray( tabarray );
497 }
498
499 setf( IsActive );
500 pdev->painters++; // also tell paint device
501 bro = QPoint( 0, 0 );
502 if ( reinit ) {
503 bg_mode = TransparentMode; // default background mode
504 rop = CopyROP; // default ROP
505 wxmat.reset(); // reset world xform matrix
506 xmat.reset();
507 ixmat.reset();
508 txop = txinv = 0;
509 if ( dt != QInternal::Widget ) {
510 QFont defaultFont; // default drawing tools
511 QPen defaultPen;
512 QBrush defaultBrush;
513 cfont = defaultFont; // set these drawing tools
514 cpen = defaultPen;
515 cbrush = defaultBrush;
516 bg_col = white; // default background color
517 }
518 }
519 wx = wy = vx = vy = 0; // default view origins
520 ww = 0;
521
522 if ( dt == QInternal::Widget ) { // device is a widget
523 QWidget *w = (QWidget*)pdev;
524 cfont = w->font(); // use widget font
525 cpen = QPen( w->foregroundColor() ); // use widget fg color
526 if ( reinit ) {
527 QBrush defaultBrush;
528 cbrush = defaultBrush;
529 }
530 bg_col = w->backgroundColor(); // use widget bg color
531 ww = vw = w->width(); // default view size
532 wh = vh = w->height();
533 devh = wh; // for final y coord. flipping
534 if ( !w->isDesktop() )
535 repaintRgn = // clip rgn passed from repaint()
536 (QRegion *) WinQueryWindowULong( w->winId(), QWL_QTCLIPRGN );
537 if ( w->testWState(Qt::WState_InPaintEvent) ) {
538 hps = w->hps; // during paint event
539 } else {
540 hps = w->getTargetPS ( unclipped ? QWidget::Unclipped :
541 QWidget::ClipAll );
542 w->hps = hps;
543 }
544 } else if ( dt == QInternal::Pixmap ) { // device is a pixmap
545 QPixmap *pm = (QPixmap*)pdev;
546 if ( pm->isNull() ) {
547#if defined(QT_CHECK_NULL)
548 qWarning( "QPainter::begin: Cannot paint null pixmap" );
549#endif
550 end();
551 return FALSE;
552 }
553 hps = pm->hps;
554 ww = vw = pm->width(); // default view size
555 wh = vh = pm->height();
556 devh = wh; // for final y coord. flipping
557 if ( pm->depth() == 1 ) { // monochrome pixmap
558 setf( MonoDev );
559 bg_col = color0;
560 cpen.setColor( color1 );
561 }
562/// @todo (dmik) later
563// } else if ( dt == QInternal::Printer ) { // device is a printer
564// if ( pdev->handle() )
565// hdc = pdev->handle();
566// flags |= (NoCache | RGBColor);
567// if ( qt_winver & WV_DOS_based )
568// flags |= VolatileDC;
569 } else if ( dt == QInternal::System ) { // system-dependent device
570 hps = pdev->handle();
571 if ( hps ) {
572 SIZEL sz;
573 GpiQueryPS( hps, &sz );
574 ww = vw = sz.cx;
575 wh = vh = sz.cy;
576 }
577 }
578 if ( testf(ExtDev) ) {
579 ww = vw = pdev->metric( QPaintDeviceMetrics::PdmWidth );
580 wh = vh = pdev->metric( QPaintDeviceMetrics::PdmHeight );
581 }
582 if ( ww == 0 )
583 ww = wh = vw = vh = 1024;
584 if ( copyFrom ) { // copy redirected widget
585 cfont = copyFrom->font();
586 cpen = QPen( copyFrom->foregroundColor() );
587 bg_col = copyFrom->backgroundColor();
588 repaintRgn =
589 (QRegion *) WinQueryWindowULong( copyFrom->winId(), QWL_QTCLIPRGN );
590 }
591 if ( testf(ExtDev) && hps == 0 ) { // external device
592 setBackgroundColor( bg_col ); // default background color
593 setBackgroundMode( TransparentMode ); // default background mode
594 setRasterOp( CopyROP ); // default raster operation
595 }
596 if ( hps ) { // initialize hps
597 if ( QColor::hPal() && dt != QInternal::Printer ) {
598 holdpal = GpiSelectPalette( hps, QColor::hPal() );
599 } else {
600 // direct RGB mode
601 GpiCreateLogColorTable( hps, 0, LCOLF_RGB, 0, 0, NULL );
602 }
603 qt_GpiSetBackColor( hps, COLOR_VALUE( bg_col ) );
604 GpiSetMix( hps, FM_OVERPAINT );
605 qt_GpiSetBackMix( hps, BM_LEAVEALONE, cpen.style() == NoPen );
606 GpiSetTextAlignment( hps, TA_NORMAL_HORIZ, TA_BASE );
607 }
608 updatePen();
609 updateBrush();
610 setBrushOrigin( 0, 0 );
611 if ( hps ) {
612 holdrgn = GpiQueryClipRegion( hps );
613 if ( repaintRgn ) {
614 // ensure that def_crgn is not null after assignment in any case
615 def_crgn = repaintRgn->isNull() ? QRegion( FALSE ) : *repaintRgn;
616 }
617 // clip region in GPI cannot be used for anything else, so detach it
618 def_crgn.detach();
619 if ( holdrgn ) {
620 // intersect the original clip region and the region from repaint()
621 if ( def_crgn.isNull() )
622 def_crgn = QRegion( 0, 0, ww, wh );
623 GpiSetClipRegion( hps, 0, NULL ); // deselect holdrgn
624 HRGN hrgn = def_crgn.handle( devh );
625 GpiCombineRegion( hps, hrgn, hrgn, holdrgn, CRGN_AND );
626 }
627 cur_crgn = def_crgn;
628 if ( !cur_crgn.isNull() )
629 GpiSetClipRegion( hps, cur_crgn.handle( devh ), NULL );
630 } else {
631 holdrgn = HRGN_ERROR;
632 }
633 setf(DirtyFont);
634
635 return TRUE;
636}
637
638bool QPainter::end()
639{
640 if ( !isActive() ) {
641#if defined(QT_CHECK_STATE)
642 qWarning( "QPainter::end: Missing begin() or begin() failed" );
643#endif
644 return FALSE;
645 }
646
647 killPStack();
648
649 // delete the brush LCID if any
650 if ( hbrushbm ) {
651 GpiSetPatternSet( hps, LCID_DEFAULT );
652 GpiDeleteSetId( hps, LCID_QTPixmapBrush );
653 hbrushbm = 0;
654 }
655 if ( holdrgn != HRGN_ERROR ) {
656 GpiSetClipRegion( hps, holdrgn, NULL );
657 holdrgn = HRGN_ERROR;
658 }
659 if ( holdpal ) {
660 GpiSelectPalette( hps, holdpal );
661 holdpal = 0;
662 }
663 if ( !pdev )
664 return FALSE;
665
666 if ( testf(ExtDev) )
667 pdev->cmd( QPaintDevice::PdcEnd, this, 0 );
668
669 if ( pdev->devType() == QInternal::Widget ) {
670 if ( !((QWidget*)pdev)->testWState(Qt::WState_InPaintEvent) ) {
671 QWidget *w = (QWidget*)pdev;
672 WinReleasePS( w->hps );
673 w->hps = 0;
674 }
675 }
676
677 if ( !def_crgn.isNull() )
678 def_crgn = QRegion();
679 cur_crgn = def_crgn;
680
681 if ( pfont ) {
682 delete pfont;
683 pfont = 0;
684 }
685 // cleanup printer font engines that could have been created by updateFont()
686 if( testf(ExtDev) )
687 QFontCache::instance->cleanupPrinterFonts();
688
689 flags = 0;
690 pdev->painters--;
691 pdev = 0;
692 hps = 0;
693 return TRUE;
694}
695
696void QPainter::flush(const QRegion &, CoordinateMode)
697{
698 flush();
699}
700
701void QPainter::flush()
702{
703}
704
705
706void QPainter::setBackgroundColor( const QColor &c )
707{
708 if ( !isActive() ) {
709#if defined(QT_CHECK_STATE)
710 qWarning( "QPainter::setBackgroundColor: Call begin() first" );
711#endif
712 return;
713 }
714 bg_col = c;
715 if ( testf(ExtDev) ) {
716 QPDevCmdParam param[1];
717 param[0].color = &bg_col;
718 if ( !pdev->cmd(QPaintDevice::PdcSetBkColor,this,param) || !hps )
719 return;
720 }
721 // set the back color for all primitives
722 qt_GpiSetBackColor( hps, COLOR_VALUE(c) );
723}
724
725// background rop codes are the same as foreground according to os2tk45
726static const LONG qt_ropCodes[] = {
727 FM_OVERPAINT, // CopyROP
728 FM_OR, // OrROP
729 FM_XOR, // XorROP
730 FM_SUBTRACT, // NotAndROP
731 FM_NOTCOPYSRC, // NotCopyROP
732 FM_MERGENOTSRC, // NotOrROP
733 FM_NOTXORSRC, // NotXorROP ??
734 FM_AND, // AndROP
735 FM_INVERT, // NotROP
736 FM_ZERO, // ClearROP
737 FM_ONE, // SetROP
738 FM_LEAVEALONE, // NopROP
739 FM_MASKSRCNOT, // AndNotROP
740 FM_MERGESRCNOT, // OrNotROP
741 FM_NOTMASKSRC, // NandROP
742 FM_NOTMERGESRC // NorROP
743};
744
745void QPainter::setBackgroundMode( BGMode m )
746{
747 if ( !isActive() ) {
748#if defined(QT_CHECK_STATE)
749 qWarning( "QPainter::setBackgroundMode: Call begin() first" );
750#endif
751 return;
752 }
753 if ( m != TransparentMode && m != OpaqueMode ) {
754#if defined(QT_CHECK_RANGE)
755 qWarning( "QPainter::setBackgroundMode: Invalid mode" );
756#endif
757 return;
758 }
759 bg_mode = m;
760 if ( testf(ExtDev) ) {
761 QPDevCmdParam param[1];
762 param[0].ival = m;
763 if ( !pdev->cmd(QPaintDevice::PdcSetBkMode,this,param) || !hps )
764 return;
765 }
766 // set the back mix for all primitives
767 qt_GpiSetBackMix(
768 hps, m == TransparentMode ? BM_LEAVEALONE : qt_ropCodes[rop],
769 cpen.style() == NoPen
770 );
771}
772
773void QPainter::setRasterOp( RasterOp r )
774{
775 if ( !isActive() ) {
776#if defined(QT_CHECK_STATE)
777 qWarning( "QPainter::setRasterOp: Call begin() first" );
778#endif
779 return;
780 }
781 if ( (uint)r > LastROP ) {
782#if defined(QT_CHECK_RANGE)
783 qWarning( "QPainter::setRasterOp: Invalid ROP code" );
784#endif
785 return;
786 }
787 rop = r;
788 if ( testf(ExtDev) ) {
789 QPDevCmdParam param[1];
790 param[0].ival = r;
791 if ( !pdev->cmd(QPaintDevice::PdcSetROP,this,param) || !hps )
792 return;
793 }
794 // set the mixes for all primitives
795 GpiSetMix( hps, qt_ropCodes[r] );
796 if ( bg_mode != TransparentMode )
797 qt_GpiSetBackMix( hps, qt_ropCodes[r], cpen.style() == NoPen );
798}
799
800void QPainter::setBrushOrigin( int x, int y )
801{
802 if ( !isActive() ) {
803#if defined(QT_CHECK_STATE)
804 qWarning( "QPainter::setBrushOrigin: Call begin() first" );
805#endif
806 return;
807 }
808 bro = QPoint(x,y);
809 if ( testf(ExtDev) ) {
810 QPDevCmdParam param[1];
811 param[0].point = &bro;
812 if ( !pdev->cmd(QPaintDevice::PdcSetBrushOrigin,this,param) || !hps )
813 return;
814 }
815 POINTL ptl = { x, y };
816 // make y coordinate bottom-relative
817 if ( devh ) ptl.y = devh - ptl.y;
818 GpiSetPatternRefPoint( hps, &ptl );
819}
820
821/**
822 * Sets up a native transformation matrix on this painter.
823 * If the paint device has a defined height (i.e. it's QPixmap or
824 * QWidget), the matrix is adjusted to automatically flip the y axis
825 * (to make it increase downwards).
826 *
827 * @param assumeYNegation
828 * If true, it is assumed that all y coordinates are negated before
829 * passing them to GPI calls. This mode is useful for drawing text
830 * because font letters are already flipped by GPI when the text is drawn,
831 * so using full y axis flip would flip letters again (that is definitely
832 * unwanted).
833 */
834bool QPainter::setNativeXForm( bool assumeYNegation )
835{
836 QWMatrix mtx;
837
838 if ( testf(VxF) ) {
839 mtx.translate( vx, vy );
840 mtx.scale( 1.0*vw/ww, 1.0*vh/wh );
841 mtx.translate( -wx, -wy );
842 mtx = wxmat * mtx;
843 } else {
844 mtx = wxmat;
845 }
846
847 // Qt rotates clockwise (despite stated in QWMatrix::rotate() docs),
848 // while GPI rotates counterclockwise. Correct this by changing
849 // m12 and m21 signs and also apply optional y translation.
850
851 MATRIXLF m;
852 m.fxM11 = (FIXED) (mtx.m11() * 65536.0);
853 m.fxM12 = (FIXED) (-mtx.m12() * 65536.0);
854 m.fxM21 = (FIXED) (-mtx.m21() * 65536.0);
855 m.fxM22 = (FIXED) (mtx.m22() * 65536.0);
856 m.lM31 = (LONG) mtx.dx();
857 m.lM32 = devh && assumeYNegation ? ((LONG) -mtx.dy()) : (LONG) mtx.dy();
858 m.lM13 = m.lM23 = 0;
859
860 BOOL ok = GpiSetDefaultViewMatrix( hps, 8, &m, TRANSFORM_REPLACE );
861 if (ok && devh) {
862 // add a matrix to do automatic y flip or just to move negative
863 // y coordinates back to the viewable area
864 m.fxM11 = MAKEFIXED( 1, 0 );
865 m.fxM12 = 0;
866 m.fxM21 = 0;
867 m.fxM22 = assumeYNegation ? MAKEFIXED( 1, 0 ) : MAKEFIXED( -1, 0 );
868 m.lM31 = 0;
869 m.lM32 = devh - 1;
870 m.lM13 = m.lM23 = 0;
871 ok = GpiSetDefaultViewMatrix( hps, 8, &m, TRANSFORM_ADD );
872 }
873
874 return ok;
875}
876
877void QPainter::clearNativeXForm()
878{
879 // restore identity matrix
880 GpiSetDefaultViewMatrix( hps, 0, NULL, TRANSFORM_REPLACE );
881}
882
883void QPainter::setClipping( bool enable )
884{
885 if ( !isActive() ) {
886#if defined(QT_CHECK_STATE)
887 qWarning( "QPainter::setClipping: Will be reset by begin()" );
888#endif
889 return;
890 }
891
892 if ( !isActive() || enable == testf(ClipOn) )
893 return;
894
895 setf( ClipOn, enable );
896 if ( testf(ExtDev) ) {
897 if ( block_ext )
898 return;
899 QPDevCmdParam param[1];
900 param[0].ival = enable;
901 if ( !pdev->cmd(QPaintDevice::PdcSetClip,this,param) || !hps )
902 return;
903 }
904
905 // the current clip region is stored in cur_crgn, so deselect the handle
906 // to let us operate on it. Note that the assignment op below will destroy
907 // the handle if it is no more referred, so there is no need to do it
908 // explicitly.
909 GpiSetClipRegion( hps, 0, NULL );
910
911 if ( enable ) {
912 if ( !def_crgn.isNull() )
913 cur_crgn = crgn.intersect( def_crgn );
914 else
915 cur_crgn = crgn.isNull() ? QRegion( FALSE ) : crgn;
916#ifndef QT_NO_PRINTER
917/// @todo (dmik) later
918// if ( pdev->devType() == QInternal::Printer ) {
919// double xscale = ((float)pdev->metric( QPaintDeviceMetrics::PdmPhysicalDpiX )) /
920// ((float)pdev->metric( QPaintDeviceMetrics::PdmDpiX ));
921// double yscale = ((float)pdev->metric( QPaintDeviceMetrics::PdmPhysicalDpiY )) /
922// ((float)pdev->metric( QPaintDeviceMetrics::PdmDpiY ));
923// double xoff = 0;
924// double yoff = 0;
925// QPrinter* printer = (QPrinter*)pdev;
926// if ( printer->fullPage() ) { // must adjust for margins
927// xoff = - GetDeviceCaps( printer->handle(), PHYSICALOFFSETX );
928// yoff = - GetDeviceCaps( printer->handle(), PHYSICALOFFSETY );
929// }
930// rgn = QWMatrix( xscale, 0, 0, yscale, xoff, yoff ) * rgn;
931// }
932#endif
933 } else {
934 cur_crgn = def_crgn;
935 }
936
937 // clip region in GPI cannot be used for anything else, so detach it
938 cur_crgn.detach();
939
940 if ( !cur_crgn.isNull() )
941 GpiSetClipRegion( hps, cur_crgn.handle( devh ), NULL );
942}
943
944
945void QPainter::setClipRect( const QRect &r, CoordinateMode m )
946{
947 QRegion rgn( r );
948 setClipRegion( rgn, m );
949}
950
951void QPainter::setClipRegion( const QRegion &rgn, CoordinateMode m )
952{
953#if defined(QT_CHECK_STATE)
954 if ( !isActive() )
955 qWarning( "QPainter::setClipRegion: Will be reset by begin()" );
956#endif
957 if ( m == CoordDevice )
958 crgn = rgn;
959 else
960 crgn = xmat * rgn;
961
962 if ( testf(ExtDev) ) {
963 if ( block_ext )
964 return;
965 QPDevCmdParam param[2];
966 param[0].rgn = &rgn;
967 param[1].ival = m;
968 if ( !pdev->cmd(QPaintDevice::PdcSetClipRegion,this,param) || !hps )
969 return;
970 }
971 clearf( ClipOn ); // be sure to update clip rgn
972 setClipping( TRUE );
973}
974
975// Note: this function does not check the array range!
976void QPainter::drawPolyInternal(
977 const QPointArray &a, bool close, bool winding, int index, int npoints,
978 bool disjoint
979)
980{
981 // QCOORD is a double word that is the same as POINTL members, and since
982 // the order of xp and yp fields in the QPoint is also the same, we simply
983 // cast QPointArray::data() to PPOINTL below.
984
985 if ( npoints < 0 )
986 npoints = a.size() - index;
987
988 QPointArray pa = a;
989 // flip y coordinates
990 if ( devh ) {
991 pa = QPointArray( npoints );
992 for ( int i = 0; i < npoints; i++ ) {
993 pa[i].setX( a[index+i].x() );
994 pa[i].setY( devh - (a[index+i].y() + 1) );
995 }
996 index = 0;
997 }
998
999 ULONG opts = winding ? BA_WINDING : BA_ALTERNATE;
1000 const PPOINTL ptls = ((PPOINTL) pa.data()) + index;
1001 if ( cpen.width() > 1 ) {
1002 if ( close ) {
1003 GpiBeginArea( hps, BA_NOBOUNDARY | opts );
1004 if ( disjoint ) {
1005 GpiPolyLineDisjoint( hps, npoints, ptls );
1006 } else {
1007 GpiMove( hps, ptls );
1008 GpiPolyLine( hps, npoints - 1, ptls + 1 );
1009 }
1010 GpiEndArea( hps );
1011 }
1012 qt_geom_line_handle gh;
1013 qt_begin_geom_line( hps, COLOR_VALUE(cpen.color()), cpen.style() == NoPen, &gh );
1014 if ( disjoint ) {
1015 GpiPolyLineDisjoint( hps, npoints, ptls );
1016 } else {
1017 GpiMove( hps, ptls );
1018 GpiPolyLine( hps, npoints - 1, ptls + 1 );
1019 }
1020 if ( close )
1021 GpiCloseFigure( hps );
1022 qt_end_geom_line( hps, &gh );
1023 } else {
1024 if ( close )
1025 GpiBeginArea( hps, BA_BOUNDARY | opts );
1026 else
1027 GpiBeginPath( hps, 1 );
1028 if ( disjoint ) {
1029 GpiPolyLineDisjoint( hps, npoints, ptls );
1030 } else {
1031 GpiMove( hps, ptls );
1032 GpiPolyLine( hps, npoints - 1, ptls + 1 );
1033 }
1034 if ( close )
1035 GpiEndArea( hps );
1036 else {
1037 GpiEndPath( hps );
1038 GpiOutlinePath( hps, 1, 0 );
1039 }
1040 }
1041}
1042
1043// angles in Qt are 1/16th of a degree, so the integer part of FIXED is
1044// angle/16 and the fixed part is (65536/16) * angle%16.
1045#define MAKEDEGREE(a16) MAKEFIXED((a16>>4), (a16<<12))
1046
1047static void doDrawArc( HPS hps, PPOINTL cptl, int first, int a, int alen )
1048{
1049 if ( first >= 0 ) {
1050 int sa, ea;
1051 for ( int i = first; i < 4; i++, cptl++ ) {
1052 sa = i * 90*16;
1053 ea = sa + 90*16;
1054 if (sa < a) sa = a;
1055 if (ea > a + alen) ea = a + alen;
1056 if (ea <= sa) break;
1057 ea -= sa;
1058 GpiPartialArc( hps, cptl, MAKEFIXED(1,0), MAKEDEGREE(sa), MAKEDEGREE(ea) );
1059 }
1060 } else {
1061 GpiPartialArc( hps, cptl, MAKEFIXED(1,0), MAKEDEGREE(a), MAKEDEGREE(alen) );
1062 }
1063}
1064
1065void QPainter::drawArcInternal(
1066 int x, int y, int w, int h, int a, int alen, ArcClose close
1067)
1068{
1069 if ( w <= 0 || h <= 0 ) {
1070 if ( w == 0 || h == 0 )
1071 return;
1072 fix_neg_rect( &x, &y, &w, &h );
1073 }
1074
1075 const int FullArc = 360*16;
1076 // correct angles
1077 if ( alen < 0 ) {
1078 a += alen;
1079 alen = -alen;
1080 }
1081 alen = QMIN( alen, FullArc );
1082 if ( a < 0 )
1083 a = FullArc - ((-a) % (FullArc));
1084 else
1085 a = a % FullArc;
1086
1087 int axr = (w - 1) / 2;
1088 int ayr = (h - 1) / 2;
1089 ARCPARAMS arcparams = { axr, ayr, 0, 0 };
1090 GpiSetArcParams( hps, &arcparams );
1091 int xc, yc;
1092 xc = x + axr;
1093 yc = y + ayr;
1094 // flip y coordinate
1095 if ( devh ) yc = devh - (yc + 1);
1096
1097 POINTL sptl = { xc, yc }, cptls [4];
1098 PPOINTL cptl = cptls;
1099 int first = -1;
1100
1101 // in order to draw arcs whose bounding reactangle has even width
1102 // and/or height we draw each quarter of the arc separately,
1103 // correspondingly moving its center point by one pixel.
1104 int extX = (w - 1) % 2;
1105 int extY = (h - 1) % 2;
1106 if ( extX != 0 || extY != 0 ) {
1107 for ( int i = 0, sa = 90*16; i < 4; i++, sa += 90*16, cptl++ ) {
1108 if ( first < 0 && sa > a )
1109 first = i;
1110 if ( first >= 0 ) {
1111 switch ( i ) {
1112 case 0: cptl->x = xc + extX; cptl->y = yc; break;
1113 case 1: cptl->x = xc; cptl->y = yc; break;
1114 case 2: cptl->x = xc; cptl->y = yc - extY; break;
1115 case 3: cptl->x = xc + extX; cptl->y = yc - extY; break;
1116 }
1117 }
1118 }
1119 cptl = cptls + first;
1120 } else {
1121 *cptl = sptl;
1122 }
1123
1124 if ( close != ClosePie ) {
1125 // set the current position to the start of the arc
1126 LONG oldMix = GpiQueryMix( hps );
1127 LONG oldType = GpiQueryLineType( hps );
1128 GpiSetMix( hps, FM_LEAVEALONE );
1129 GpiSetLineType( hps, LINETYPE_SOLID );
1130 GpiPartialArc( hps, cptl, MAKEFIXED(1,0), MAKEDEGREE(a), 0 );
1131 GpiSetLineType( hps, oldType );
1132 GpiSetMix( hps, oldMix );
1133 // cause the start point to be drawn (seems like a bug in OS/2 GPI)
1134 GpiQueryCurrentPosition( hps, &sptl );
1135 }
1136
1137 if ( cpen.width() > 1 ) {
1138 if ( close != CloseNone ) {
1139 GpiBeginArea( hps, BA_NOBOUNDARY | BA_ALTERNATE );
1140 GpiMove( hps, &sptl );
1141 doDrawArc( hps, cptl, first, a, alen );
1142 GpiEndArea( hps );
1143 }
1144 qt_geom_line_handle gh;
1145 qt_begin_geom_line( hps, COLOR_VALUE(cpen.color()),
1146 cpen.style() == NoPen, &gh );
1147
1148 GpiMove( hps, &sptl );
1149 doDrawArc( hps, cptl, first, a, alen );
1150
1151 if ( close != CloseNone )
1152 GpiCloseFigure( hps );
1153 qt_end_geom_line( hps, &gh );
1154 } else {
1155 if ( close != CloseNone )
1156 GpiBeginArea( hps, BA_BOUNDARY | BA_ALTERNATE );
1157 else
1158 GpiBeginPath( hps, 1 );
1159
1160 GpiMove( hps, &sptl );
1161 doDrawArc( hps, cptl, first, a, alen );
1162
1163 if ( close != CloseNone )
1164 GpiEndArea( hps );
1165 else {
1166 GpiEndPath( hps );
1167 GpiOutlinePath( hps, 1, 0 );
1168 }
1169 }
1170}
1171
1172void QPainter::drawPoint( int x, int y )
1173{
1174 if ( !isActive() )
1175 return;
1176 if ( testf(ExtDev|VxF|WxF) ) {
1177 if ( testf(ExtDev) ) {
1178 QPDevCmdParam param[1];
1179 QPoint p( x, y );
1180 param[0].point = &p;
1181 if ( !pdev->cmd(QPaintDevice::PdcDrawPoint,this,param) || !hps )
1182 return;
1183 }
1184 map( x, y, &x, &y );
1185 }
1186 POINTL ptl = { x, y };
1187 if ( devh ) ptl.y = devh - ( ptl.y + 1 );
1188 GpiSetPel( hps, &ptl );
1189}
1190
1191
1192void QPainter::drawPoints( const QPointArray& a, int index, int npoints )
1193{
1194 if ( npoints < 0 )
1195 npoints = a.size() - index;
1196 if ( index + npoints > (int)a.size() )
1197 npoints = a.size() - index;
1198 if ( !isActive() || npoints < 1 || index < 0 )
1199 return;
1200 QPointArray pa = a;
1201 if ( testf(ExtDev|VxF|WxF) ) {
1202 if ( testf(ExtDev) ) {
1203 QPDevCmdParam param[1];
1204 for (int i=0; i<npoints; i++) {
1205 QPoint p( pa[index+i].x(), pa[index+i].y() );
1206 param[0].point = &p;
1207 if ( !pdev->cmd(QPaintDevice::PdcDrawPoint,this,param))
1208 return;
1209 }
1210 if ( !hps ) return;
1211 }
1212 if ( txop != TxNone ) {
1213 pa = xForm( a, index, npoints );
1214 if ( pa.size() != a.size() ) {
1215 index = 0;
1216 npoints = pa.size();
1217 }
1218 }
1219 }
1220 for (int i=0; i<npoints; i++) {
1221 POINTL ptl = { pa[index+i].x(), pa[index+i].y() };
1222 if ( devh ) ptl.y = devh - ( ptl.y + 1 );
1223 GpiSetPel( hps, &ptl );
1224 }
1225}
1226
1227void QPainter::moveTo( int x, int y )
1228{
1229 if ( !isActive() )
1230 return;
1231 if ( testf(ExtDev|VxF|WxF) ) {
1232 if ( testf(ExtDev) ) {
1233 QPDevCmdParam param[1];
1234 QPoint p( x, y );
1235 param[0].point = &p;
1236 if ( !pdev->cmd(QPaintDevice::PdcMoveTo,this,param) || !hps )
1237 return;
1238 }
1239 map( x, y, &x, &y );
1240 }
1241 POINTL ptl = { x, y };
1242 if ( devh ) ptl.y = devh - ( ptl.y + 1 );
1243 GpiMove( hps, &ptl );
1244}
1245
1246
1247void QPainter::lineTo( int x, int y )
1248{
1249 if ( !isActive() )
1250 return;
1251 if ( testf(ExtDev|VxF|WxF) ) {
1252 if ( testf(ExtDev) ) {
1253 QPDevCmdParam param[1];
1254 QPoint p( x, y );
1255 param[0].point = &p;
1256 if ( !pdev->cmd(QPaintDevice::PdcLineTo,this,param) || !hps )
1257 return;
1258 }
1259 map( x, y, &x, &y );
1260 }
1261
1262 qt_geom_line_handle gh;
1263 if ( cpen.width() > 1 ) {
1264 qt_begin_geom_line( hps, COLOR_VALUE(cpen.color()), cpen.style() == NoPen, &gh );
1265 }
1266
1267 POINTL ptl = { x, y };
1268 if ( devh ) ptl.y = devh - ( ptl.y + 1 );
1269 GpiLine( hps, &ptl );
1270
1271 if ( cpen.width() > 1 ) {
1272 qt_end_geom_line( hps, &gh );
1273 }
1274}
1275
1276
1277void QPainter::drawLine( int x1, int y1, int x2, int y2 )
1278{
1279 if ( !isActive() )
1280 return;
1281 if ( testf(ExtDev|VxF|WxF) ) {
1282 if ( testf(ExtDev) ) {
1283 QPDevCmdParam param[2];
1284 QPoint p1(x1, y1), p2(x2, y2);
1285 param[0].point = &p1;
1286 param[1].point = &p2;
1287 if ( !pdev->cmd(QPaintDevice::PdcDrawLine,this,param) || !hps )
1288 return;
1289 }
1290 map( x1, y1, &x1, &y1 );
1291 map( x2, y2, &x2, &y2 );
1292 }
1293
1294 qt_geom_line_handle gh;
1295 if ( cpen.width() > 1 ) {
1296 qt_begin_geom_line( hps, COLOR_VALUE(cpen.color()), cpen.style() == NoPen, &gh );
1297 }
1298
1299 POINTL ptl = { x1, y1 };
1300 if ( devh ) ptl.y = devh - (ptl.y + 1);
1301 GpiMove( hps, &ptl );
1302 ptl.x = x2;
1303 ptl.y = y2;
1304 if ( devh ) ptl.y = devh - (ptl.y + 1);
1305 GpiLine( hps, &ptl );
1306
1307 if ( cpen.width() > 1 ) {
1308 qt_end_geom_line( hps, &gh );
1309 }
1310}
1311
1312static void doDrawRect( HPS hps, int x, int y, int w, int h, int axr, int ayr )
1313{
1314 const FIXED RightAngle = MAKEFIXED(90,0);
1315 const FIXED One = MAKEFIXED(1,0);
1316
1317 // top/right coordinates are inclusive
1318 -- w;
1319 -- h;
1320
1321 // beginning of the bottom side
1322 POINTL ptl = { x + axr, y };
1323 GpiMove( hps, &ptl );
1324 // center of the bottom-right arc
1325 ptl.x = x + w - axr; ptl.y = y + ayr;
1326 GpiPartialArc( hps, &ptl, One, MAKEFIXED(270,0), RightAngle );
1327 // center of the top-right arc
1328 /* ptl.x = x + w - axr; */ ptl.y = y + h - ayr;
1329 GpiPartialArc( hps, &ptl, One, MAKEFIXED(0,0), RightAngle );
1330 // center of the top-left arc
1331 ptl.x = x + axr; /* ptl.y = y + h - ayr; */
1332 GpiPartialArc( hps, &ptl, One, RightAngle, RightAngle );
1333 // center of the bottom-left arc
1334 /* ptl.x = x + axr; */ ptl.y = y + ayr;
1335 GpiPartialArc( hps, &ptl, One, MAKEFIXED(180,0), RightAngle );
1336}
1337
1338void QPainter::drawRectInternal(
1339 int x, int y, int w, int h, int wRnd, int hRnd
1340) {
1341 if ( w <= 0 || h <= 0 ) {
1342 if ( w == 0 || h == 0 )
1343 return;
1344 fix_neg_rect( &x, &y, &w, &h );
1345 }
1346
1347 // GpiBox API is buggy when it comes to rounded corners
1348 // combined with filling the interior (see ticket:16).
1349 // The fix is to draw rounded corners ourselves.
1350
1351 if ( wRnd == 0 || hRnd == 0 ) {
1352 POINTL ptl1 = { x, y };
1353 if ( devh ) ptl1.y = devh - ( ptl1.y + h );
1354 POINTL ptl2 = { x + w - 1, ptl1.y + h - 1 };
1355 if ( cpen.width() > 1 ) {
1356 GpiMove( hps, &ptl1 );
1357 GpiBox( hps, DRO_FILL, &ptl2, wRnd, hRnd );
1358 qt_geom_line_handle gh;
1359 qt_begin_geom_line( hps, COLOR_VALUE(cpen.color()),
1360 cpen.style() == NoPen, &gh );
1361 GpiMove( hps, &ptl1 );
1362 GpiBox( hps, DRO_OUTLINE, &ptl2, 0, 0 );
1363 qt_end_geom_line( hps, &gh );
1364 } else {
1365 GpiMove( hps, &ptl1 );
1366 GpiBox( hps, DRO_FILL | DRO_OUTLINE, &ptl2, 0, 0 );
1367 }
1368 return;
1369 }
1370
1371 // flip y coordinate
1372 if ( devh ) y = devh - ( y + h );
1373
1374 int axr = (wRnd - 1) / 2;
1375 int ayr = (hRnd - 1) / 2;
1376 ARCPARAMS arcparams = { axr, ayr, 0, 0 };
1377 GpiSetArcParams( hps, &arcparams );
1378
1379 if ( cpen.width() > 1 ) {
1380 GpiBeginArea( hps, BA_NOBOUNDARY | BA_ALTERNATE );
1381 doDrawRect( hps, x, y, w, h, axr, ayr );
1382 GpiEndArea( hps );
1383 qt_geom_line_handle gh;
1384 qt_begin_geom_line( hps, COLOR_VALUE(cpen.color()),
1385 cpen.style() == NoPen, &gh );
1386 doDrawRect( hps, x, y, w, h, axr, ayr );
1387 GpiCloseFigure( hps );
1388 qt_end_geom_line( hps, &gh );
1389 } else {
1390 GpiBeginArea( hps, BA_BOUNDARY | BA_ALTERNATE );
1391 doDrawRect( hps, x, y, w, h, axr, ayr );
1392 GpiEndArea( hps );
1393 }
1394}
1395
1396void QPainter::drawRect( int x, int y, int w, int h )
1397{
1398 if ( !isActive() )
1399 return;
1400 if ( testf(ExtDev|VxF|WxF) ) {
1401 if ( testf(ExtDev) ) {
1402 QPDevCmdParam param[1];
1403 QRect r( x, y, w, h );
1404 param[0].rect = &r;
1405 if ( !pdev->cmd(QPaintDevice::PdcDrawRect,this,param) || !hps )
1406 return;
1407 }
1408 if ( txop == TxRotShear ) { // rotate/shear polygon
1409 QPointArray a( QRect(x,y,w,h) );
1410 drawPolyInternal( xForm(a) );
1411 return;
1412 }
1413 map( x, y, w, h, &x, &y, &w, &h );
1414 }
1415
1416 drawRectInternal( x, y, w, h, 0, 0 );
1417}
1418
1419void QPainter::drawWinFocusRectInternal(
1420 int x, int y, int w, int h, const QColor &bgCol, bool xormode
1421)
1422{
1423 if ( !isActive() || txop == TxRotShear )
1424 return;
1425
1426 if ( testf(ExtDev|VxF|WxF) ) {
1427 if ( testf(ExtDev) ) {
1428 QPDevCmdParam param[1];
1429 QRect r( x, y, w, h );
1430 param[0].rect = &r;
1431 if ( !pdev->cmd(QPaintDevice::PdcDrawRect,this,param) || !hps )
1432 return;
1433 }
1434 map( x, y, w, h, &x, &y, &w, &h );
1435 }
1436 if ( w <= 0 || h <= 0 ) {
1437 if ( w == 0 || h == 0 )
1438 return;
1439 fix_neg_rect( &x, &y, &w, &h );
1440 }
1441
1442 // flip y coordinate
1443 if ( devh ) y = devh - (y + h);
1444
1445 ULONG la =
1446 LBB_COLOR | LBB_MIX_MODE | LBB_BACK_MIX_MODE | LBB_TYPE;
1447 LINEBUNDLE oldLb, lb;
1448 GpiQueryAttrs( hps, PRIM_LINE, la, &oldLb );
1449 if ( !xormode ) { // black/white mode
1450 if( qGray( bgCol.rgb() ) <= 128 )
1451 lb.lColor = CLR_WHITE;
1452 else
1453 lb.lColor = CLR_BLACK;
1454 lb.usMixMode = FM_OVERPAINT;
1455 } else { // xor mode
1456 lb.lColor = CLR_TRUE;
1457 lb.usMixMode = FM_XOR;
1458 }
1459 lb.usBackMixMode = BM_LEAVEALONE;
1460 lb.usType = LINETYPE_ALTERNATE;
1461 GpiSetAttrs( hps, PRIM_LINE, la, 0, &lb );
1462
1463 POINTL ptl = { x, y };
1464 GpiMove( hps, &ptl );
1465 ptl.x += w - 1;
1466 ptl.y += h - 1;
1467 GpiBox( hps, DRO_OUTLINE, &ptl, 0, 0 );
1468
1469 GpiSetAttrs( hps, PRIM_LINE, la, 0, &oldLb );
1470}
1471
1472void QPainter::drawWinFocusRect( int x, int y, int w, int h, const QColor &bgCol )
1473{
1474 drawWinFocusRectInternal( x, y, w, h, bgCol, FALSE );
1475}
1476
1477void QPainter::drawWinFocusRect( int x, int y, int w, int h )
1478{
1479 if (
1480 pdev->devType() == QInternal::Widget &&
1481 GpiQueryClipRegion( hps )
1482 ) {
1483 // GPI bug: LINETYPE_ALTERNATE lines are drawn wrongly in XOR mode
1484 // when the clip region is set on the hps. we use doublebuffering
1485 // to avoid this.
1486 QSize ws = ((QWidget*) pdev)->size();
1487 POINTL ptls[] = { { 0, 0 }, { ws.width(), ws.height() }, { 0, 0 } };
1488 QPixmap pm( ws );
1489 GpiBitBlt( pm.hps, hps, 3, ptls, ROP_SRCCOPY, BBO_IGNORE );
1490 HPS thisHps = hps;
1491 hps = pm.hps;
1492 drawWinFocusRectInternal( x, y, w, h, bg_col, TRUE );
1493 hps = thisHps;
1494 GpiBitBlt( hps, pm.hps, 3, ptls, ROP_SRCCOPY, BBO_IGNORE );
1495 } else {
1496 drawWinFocusRectInternal( x, y, w, h, bg_col, TRUE );
1497 }
1498}
1499
1500
1501void QPainter::drawRoundRect( int x, int y, int w, int h, int xRnd, int yRnd )
1502{
1503 if ( !isActive() )
1504 return;
1505 if ( xRnd <= 0 || yRnd <= 0 ) {
1506 drawRect( x, y, w, h ); // draw normal rectangle
1507 return;
1508 }
1509 if ( xRnd >= 100 ) // fix ranges
1510 xRnd = 99;
1511 if ( yRnd >= 100 )
1512 yRnd = 99;
1513 if ( testf(ExtDev|VxF|WxF) ) {
1514 if ( testf(ExtDev) ) {
1515 QPDevCmdParam param[3];
1516 QRect r( x, y, w, h );
1517 param[0].rect = &r;
1518 param[1].ival = xRnd;
1519 param[2].ival = yRnd;
1520 if ( !pdev->cmd(QPaintDevice::PdcDrawRoundRect,this,param) || !hps)
1521 return;
1522 }
1523 if ( txop == TxRotShear ) { // rotate/shear polygon
1524 if ( w <= 0 || h <= 0 )
1525 fix_neg_rect( &x, &y, &w, &h );
1526 int rxx = w*xRnd/200;
1527 int ryy = h*yRnd/200;
1528 // were there overflows?
1529 if ( rxx < 0 )
1530 rxx = w/200*xRnd;
1531 if ( ryy < 0 )
1532 ryy = h/200*yRnd;
1533 int rxx2 = 2*rxx;
1534 int ryy2 = 2*ryy;
1535 QPointArray a[4];
1536 a[0].makeArc( x, y, rxx2, ryy2, 1*16*90, 16*90, xmat );
1537 a[1].makeArc( x, y+h-ryy2, rxx2, ryy2, 2*16*90, 16*90, xmat );
1538 a[2].makeArc( x+w-rxx2, y+h-ryy2, rxx2, ryy2, 3*16*90, 16*90, xmat );
1539 a[3].makeArc( x+w-rxx2, y, rxx2, ryy2, 0*16*90, 16*90, xmat );
1540 // ### is there a better way to join QPointArrays?
1541 QPointArray aa;
1542 aa.resize( a[0].size() + a[1].size() + a[2].size() + a[3].size() );
1543 uint j = 0;
1544 for ( int k=0; k<4; k++ ) {
1545 for ( uint i=0; i<a[k].size(); i++ ) {
1546 aa.setPoint( j, a[k].point(i) );
1547 j++;
1548 }
1549 }
1550 drawPolyInternal( aa );
1551 return;
1552 }
1553 map( x, y, w, h, &x, &y, &w, &h );
1554 }
1555
1556 drawRectInternal( x, y, w, h, w*xRnd/99, h*yRnd/99 );
1557}
1558
1559
1560void QPainter::drawEllipse( int x, int y, int w, int h )
1561{
1562 if ( !isActive() )
1563 return;
1564 if ( testf(ExtDev|VxF|WxF) ) {
1565 if ( testf(ExtDev) ) {
1566 QPDevCmdParam param[1];
1567 QRect r( x, y, w, h );
1568 param[0].rect = &r;
1569 if ( !pdev->cmd(QPaintDevice::PdcDrawEllipse,this,param) || !hps )
1570 return;
1571 }
1572 if ( txop == TxRotShear ) { // rotate/shear polygon
1573 QPointArray a;
1574 int increment = cpen.style() == NoPen ? 1 : 0;
1575 a.makeArc( x, y, w+increment, h+increment, 0, 360*16, xmat );
1576 drawPolyInternal( a );
1577 return;
1578 }
1579 map( x, y, w, h, &x, &y, &w, &h );
1580 }
1581
1582 drawArcInternal( x, y, w, h );
1583}
1584
1585
1586void QPainter::drawArc( int x, int y, int w, int h, int a, int alen )
1587{
1588 if ( !isActive() )
1589 return;
1590 if ( testf(ExtDev|VxF|WxF) ) {
1591 if ( testf(ExtDev) ) {
1592 QPDevCmdParam param[3];
1593 QRect r( x, y, w, h );
1594 param[0].rect = &r;
1595 param[1].ival = a;
1596 param[2].ival = alen;
1597 if ( !pdev->cmd(QPaintDevice::PdcDrawArc,this,param) || !hps )
1598 return;
1599 }
1600 if ( txop == TxRotShear ) { // rotate/shear
1601 QPointArray pa;
1602 pa.makeArc( x, y, w, h, a, alen, xmat ); // arc polyline
1603 drawPolyInternal( pa, FALSE );
1604 return;
1605 }
1606 map( x, y, w, h, &x, &y, &w, &h );
1607 }
1608
1609 drawArcInternal( x, y, w, h, a, alen, CloseNone );
1610}
1611
1612
1613void QPainter::drawPie( int x, int y, int w, int h, int a, int alen )
1614{
1615 if ( !isActive() )
1616 return;
1617 if ( testf(ExtDev|VxF|WxF) ) {
1618 if ( testf(ExtDev) ) {
1619 QPDevCmdParam param[3];
1620 QRect r( x, y, w, h );
1621 param[0].rect = &r;
1622 param[1].ival = a;
1623 param[2].ival = alen;
1624 if ( !pdev->cmd(QPaintDevice::PdcDrawPie,this,param) || !hps )
1625 return;
1626 }
1627 if ( txop == TxRotShear ) { // rotate/shear
1628 QPointArray pa;
1629 int increment = cpen.style() == NoPen ? 1 : 0;
1630 pa.makeArc( x, y, w+increment, h+increment, a, alen, xmat ); // arc polyline
1631 int n = pa.size();
1632 int cx, cy;
1633 xmat.map(x+w/2, y+h/2, &cx, &cy);
1634 pa.resize( n+1 );
1635 pa.setPoint( n, cx, cy ); // add legs
1636 drawPolyInternal( pa );
1637 return;
1638 }
1639 map( x, y, w, h, &x, &y, &w, &h );
1640 }
1641
1642 drawArcInternal( x, y, w, h, a, alen, ClosePie );
1643}
1644
1645
1646void QPainter::drawChord( int x, int y, int w, int h, int a, int alen )
1647{
1648 if ( !isActive() )
1649 return;
1650 if ( testf(ExtDev|VxF|WxF) ) {
1651 if ( testf(ExtDev) ) {
1652 QPDevCmdParam param[3];
1653 QRect r( x, y, w, h );
1654 param[0].rect = &r;
1655 param[1].ival = a;
1656 param[2].ival = alen;
1657 if ( !pdev->cmd(QPaintDevice::PdcDrawChord,this,param) || !hps )
1658 return;
1659 }
1660 if ( txop == TxRotShear ) { // rotate/shear
1661 QPointArray pa;
1662 int increment = cpen.style() == NoPen ? 1 : 0;
1663 pa.makeArc( x, y, w+increment, h+increment, a, alen, xmat ); // arc polygon
1664 int n = pa.size();
1665 pa.resize( n+1 );
1666 pa.setPoint( n, pa.at(0) ); // connect endpoints
1667 drawPolyInternal( pa );
1668 return;
1669 }
1670 map( x, y, w, h, &x, &y, &w, &h );
1671 }
1672
1673 drawArcInternal( x, y, w, h, a, alen, CloseChord );
1674}
1675
1676
1677void QPainter::drawLineSegments( const QPointArray &a, int index, int nlines )
1678{
1679 if ( nlines < 0 )
1680 nlines = a.size()/2 - index/2;
1681 if ( index + nlines*2 > (int)a.size() )
1682 nlines = (a.size() - index)/2;
1683 if ( !isActive() || nlines < 1 || index < 0 )
1684 return;
1685 QPointArray pa = a;
1686 if ( testf(ExtDev|VxF|WxF) ) {
1687 if ( testf(ExtDev) ) {
1688 if ( 2*nlines != (int)pa.size() ) {
1689 pa = QPointArray( nlines*2 );
1690 for ( int i=0; i<nlines*2; i++ )
1691 pa.setPoint( i, a.point(index+i) );
1692 index = 0;
1693 }
1694 QPDevCmdParam param[1];
1695 param[0].ptarr = (QPointArray*)&pa;
1696 if ( !pdev->cmd(QPaintDevice::PdcDrawLineSegments,this,param)
1697 || !hps )
1698 return;
1699 }
1700 if ( txop != TxNone ) {
1701 pa = xForm( a, index, nlines*2 );
1702 if ( pa.size() != a.size() ) {
1703 index = 0;
1704 nlines = pa.size()/2;
1705 }
1706 }
1707 }
1708 drawPolyInternal( pa, FALSE, FALSE, index, nlines*2, TRUE );
1709}
1710
1711
1712void QPainter::drawPolyline( const QPointArray &a, int index, int npoints )
1713{
1714 if ( npoints < 0 )
1715 npoints = a.size() - index;
1716 if ( index + npoints > (int)a.size() )
1717 npoints = a.size() - index;
1718 if ( !isActive() || npoints < 2 || index < 0 )
1719 return;
1720 QPointArray pa = a;
1721 if ( testf(ExtDev|VxF|WxF) ) {
1722 if ( testf(ExtDev) ) {
1723 if ( npoints != (int)pa.size() ) {
1724 pa = QPointArray( npoints );
1725 for ( int i=0; i<npoints; i++ )
1726 pa.setPoint( i, a.point(index+i) );
1727 index = 0;
1728 }
1729 QPDevCmdParam param[1];
1730 param[0].ptarr = (QPointArray*)&pa;
1731 if ( !pdev->cmd(QPaintDevice::PdcDrawPolyline,this,param) || !hps )
1732 return;
1733 }
1734 if ( txop != TxNone ) {
1735 pa = xForm( pa, index, npoints );
1736 if ( pa.size() != a.size() ) {
1737 index = 0;
1738 npoints = pa.size();
1739 }
1740 }
1741 }
1742 drawPolyInternal( pa, FALSE, FALSE, index, npoints );
1743}
1744
1745
1746void QPainter::drawConvexPolygon( const QPointArray &pa,
1747 int index, int npoints )
1748{
1749 // Any efficient way?
1750 drawPolygon(pa,FALSE,index,npoints);
1751}
1752
1753void QPainter::drawPolygon( const QPointArray &a, bool winding, int index,
1754 int npoints )
1755{
1756 if ( npoints < 0 )
1757 npoints = a.size() - index;
1758 if ( index + npoints > (int)a.size() )
1759 npoints = a.size() - index;
1760 if ( !isActive() || npoints < 2 || index < 0 )
1761 return;
1762 QPointArray pa = a;
1763 if ( testf(ExtDev|VxF|WxF) ) {
1764 if ( testf(ExtDev) ) {
1765 if ( npoints != (int)a.size() ) {
1766 pa = QPointArray( npoints );
1767 for ( int i=0; i<npoints; i++ )
1768 pa.setPoint( i, a.point(index+i) );
1769 }
1770 QPDevCmdParam param[2];
1771 param[0].ptarr = (QPointArray*)&pa;
1772 param[1].ival = winding;
1773 if ( !pdev->cmd(QPaintDevice::PdcDrawPolygon,this,param) || !hps )
1774 return;
1775 }
1776 if ( txop != TxNone ) {
1777 pa = xForm( a, index, npoints );
1778 if ( pa.size() != a.size() ) {
1779 index = 0;
1780 npoints = pa.size();
1781 }
1782 }
1783 }
1784 drawPolyInternal( pa, TRUE, winding, index, npoints );
1785}
1786
1787#ifndef QT_NO_BEZIER
1788void QPainter::drawCubicBezier( const QPointArray &a, int index )
1789{
1790 if ( !isActive() )
1791 return;
1792 if ( (int)a.size() - index < 4 ) {
1793#if defined(QT_CHECK_RANGE)
1794 qWarning( "QPainter::drawCubicBezier: Cubic Bezier needs 4 control "
1795 "points" );
1796#endif
1797 return;
1798 }
1799 QPointArray pa( a );
1800 if ( testf(ExtDev|VxF|WxF) ) {
1801 if ( index != 0 || a.size() > 4 ) {
1802 pa = QPointArray( 4 );
1803 for ( int i=0; i<4; i++ )
1804 pa.setPoint( i, a.point(index+i) );
1805 index = 0;
1806 }
1807 if ( testf(ExtDev) ) {
1808 QPDevCmdParam param[1];
1809 param[0].ptarr = (QPointArray*)&pa;
1810 if ( !pdev->cmd(QPaintDevice::PdcDrawCubicBezier,this,param)
1811 || !hps )
1812 return;
1813 }
1814 if ( txop != TxNone )
1815 pa = xForm( pa );
1816 }
1817
1818 // flip y coordinates
1819 if ( devh ) {
1820 for ( int i = index; i < 4; i++ )
1821 pa[i].setY( devh - (pa[i].y() + 1) );
1822 }
1823
1824 qt_geom_line_handle gh;
1825 if ( cpen.width() > 1 )
1826 qt_begin_geom_line( hps, COLOR_VALUE(cpen.color()), cpen.style() == NoPen, &gh );
1827 GpiMove( hps, (PPOINTL)(pa.data()+index) );
1828 GpiPolySpline( hps, 3, (PPOINTL)(pa.data()+index+1) );
1829 if ( cpen.width() > 1 )
1830 qt_end_geom_line( hps, &gh );
1831}
1832#endif // QT_NO_BEZIER
1833
1834void QPainter::drawPixmap( int x, int y, const QPixmap &pixmap,
1835 int sx, int sy, int sw, int sh )
1836{
1837 if ( !isActive() || pixmap.isNull() )
1838 return;
1839 if ( sw < 0 )
1840 sw = pixmap.width() - sx;
1841 if ( sh < 0 )
1842 sh = pixmap.height() - sy;
1843
1844 // Sanity-check clipping
1845 if ( sx < 0 ) {
1846 x -= sx;
1847 sw += sx;
1848 sx = 0;
1849 }
1850 if ( sw + sx > pixmap.width() )
1851 sw = pixmap.width() - sx;
1852 if ( sy < 0 ) {
1853 y -= sy;
1854 sh += sy;
1855 sy = 0;
1856 }
1857 if ( sh + sy > pixmap.height() )
1858 sh = pixmap.height() - sy;
1859
1860 if ( sw <= 0 || sh <= 0 )
1861 return;
1862
1863 if ( testf(ExtDev|VxF|WxF) ) {
1864 if ( testf(ExtDev) || (txop == TxScale && pixmap.mask()) ||
1865 txop == TxRotShear ) {
1866 if ( sx != 0 || sy != 0 ||
1867 sw != pixmap.width() || sh != pixmap.height() ) {
1868 QPixmap tmp( sw, sh, pixmap.depth(), QPixmap::NormalOptim );
1869 bitBlt( &tmp, 0, 0, &pixmap, sx, sy, sw, sh, CopyROP, TRUE );
1870 if ( pixmap.mask() ) {
1871 QBitmap mask( sw, sh );
1872 bitBlt( &mask, 0, 0, pixmap.mask(), sx, sy, sw, sh,
1873 CopyROP, TRUE );
1874 tmp.setMask( mask );
1875 }
1876 drawPixmap( x, y, tmp );
1877 return;
1878 }
1879 if ( testf(ExtDev) ) {
1880 QPDevCmdParam param[2];
1881 QRect r( x, y, pixmap.width(), pixmap.height() );
1882 param[0].rect = &r;
1883 param[1].pixmap = &pixmap;
1884 if ( !pdev->cmd(QPaintDevice::PdcDrawPixmap,this,param)
1885 || !hps )
1886 return;
1887 }
1888 }
1889 if ( txop == TxTranslate )
1890 map( x, y, &x, &y );
1891 }
1892
1893 if ( txop <= TxTranslate ) { // use optimized bitBlt
1894 bitBlt( pdev, x, y, &pixmap, sx, sy, sw, sh, (RasterOp)rop );
1895 return;
1896 }
1897
1898 QPixmap *pm = (QPixmap*)&pixmap;
1899
1900/// @todo (dmik):
1901//
1902// For some unknown reason, the code below doesn't work for some selected
1903// target paint device width and scale factor combinations on my machine
1904// with ATI Radeon 9600 Pro and SNAP Version 2.9.2, build 446 -- GpiBitBlt
1905// simply does nothing (leaving the target hps untouched) but returns
1906// GPI_OK. This looks like a (video driver?) bug...
1907//
1908// An easy way to reproduce is to run the xform example, select the
1909// Image mode and set the scale factor to 360% (making sure the window
1910// size was not changed after starting the application).
1911//
1912#if 0
1913 if ( txop == TxScale && !pm->mask() ) {
1914 // Plain scaling and no mask, then GpiBitBlt is faster
1915 int w, h;
1916 map( x, y, sw, sh, &x, &y, &w, &h );
1917 // flip y coordinate
1918 if ( devh )
1919 y = devh - (y + h);
1920 POINTL ptls[] = {
1921 { x, y }, { x + w, y + h },
1922 { sx, sy }, { sw, sh }
1923 };
1924 GpiBitBlt( hps, pm->handle(), 4, ptls, ROP_SRCCOPY, BBO_IGNORE );
1925 } else
1926#endif
1927 {
1928#ifndef QT_NO_PIXMAP_TRANSFORMATION
1929 // We have a complex xform or scaling with mask, then xform the
1930 // pixmap (and possible mask) and bitBlt again.
1931 QWMatrix mat( m11(), m12(),
1932 m21(), m22(),
1933 dx(), dy() );
1934 mat = QPixmap::trueMatrix( mat, sw, sh );
1935 QPixmap pmx;
1936 if ( sx == 0 && sy == 0 &&
1937 sw == pixmap.width() && sh == pixmap.height() ) {
1938 pmx = pixmap; // xform the whole pixmap
1939 } else {
1940 pmx = QPixmap( sw, sh ); // xform subpixmap
1941 bitBlt( &pmx, 0, 0, pm, sx, sy, sw, sh );
1942 }
1943 pmx = pmx.xForm( mat );
1944 if ( pmx.isNull() ) // xformed into nothing
1945 return;
1946 if ( !pmx.mask() && txop == TxRotShear ) {
1947 QBitmap bm_clip( sw, sh, 1 ); // make full mask, xform it
1948 bm_clip.fill( color1 );
1949 pmx.setMask( bm_clip.xForm(mat) );
1950 }
1951 map( x, y, &x, &y ); //### already done above? // compute position of pixmap
1952 int dx, dy;
1953 mat.map( 0, 0, &dx, &dy );
1954 bitBlt( pdev, x - dx, y - dy, &pmx );
1955#endif
1956 }
1957}
1958
1959/* Internal, used by drawTiledPixmap */
1960
1961static void drawTile( QPainter *p, int x, int y, int w, int h,
1962 const QPixmap &pixmap, int xOffset, int yOffset )
1963{
1964 int yPos, xPos, drawH, drawW, yOff, xOff;
1965 yPos = y;
1966 yOff = yOffset;
1967 while( yPos < y + h ) {
1968 drawH = pixmap.height() - yOff; // Cropping first row
1969 if ( yPos + drawH > y + h ) // Cropping last row
1970 drawH = y + h - yPos;
1971 xPos = x;
1972 xOff = xOffset;
1973 while( xPos < x + w ) {
1974 drawW = pixmap.width() - xOff; // Cropping first column
1975 if ( xPos + drawW > x + w ) // Cropping last column
1976 drawW = x + w - xPos;
1977 p->drawPixmap( xPos, yPos, pixmap, xOff, yOff, drawW, drawH );
1978 xPos += drawW;
1979 xOff = 0;
1980 }
1981 yPos += drawH;
1982 yOff = 0;
1983 }
1984}
1985
1986void QPainter::drawTiledPixmap( int x, int y, int w, int h,
1987 const QPixmap &pixmap, int sx, int sy )
1988{
1989 int sw = pixmap.width();
1990 int sh = pixmap.height();
1991 if (!sw || !sh )
1992 return;
1993 if ( sx < 0 )
1994 sx = sw - -sx % sw;
1995 else
1996 sx = sx % sw;
1997 if ( sy < 0 )
1998 sy = sh - -sy % sh;
1999 else
2000 sy = sy % sh;
2001 /*
2002 Requirements for optimizing tiled pixmaps:
2003 - not an external device
2004 - not scale or rotshear
2005 - no mask
2006 */
2007 QBitmap *mask = (QBitmap *)pixmap.mask();
2008 if ( !testf(ExtDev) && txop <= TxTranslate && mask == 0 ) {
2009 if ( txop == TxTranslate )
2010 map( x, y, &x, &y );
2011 qt_draw_tiled_pixmap( hps, x, y, w, h, &pixmap, sx, sy, devh );
2012 return;
2013 }
2014 if ( sw*sh < 8192 && sw*sh < 16*w*h ) {
2015 int tw = sw, th = sh;
2016 while ( tw*th < 32678 && tw < w/2 )
2017 tw *= 2;
2018 while ( tw*th < 32678 && th < h/2 )
2019 th *= 2;
2020 QPixmap tile( tw, th, pixmap.depth(), QPixmap::BestOptim );
2021 qt_fill_tile( &tile, pixmap );
2022 if ( mask ) {
2023 QBitmap tilemask( tw, th, FALSE, QPixmap::NormalOptim );
2024 qt_fill_tile( &tilemask, *mask );
2025 tile.setMask( tilemask );
2026 }
2027 drawTile( this, x, y, w, h, tile, sx, sy );
2028 } else {
2029 drawTile( this, x, y, w, h, pixmap, sx, sy );
2030 }
2031}
2032
2033#if 0
2034//
2035// Generate a string that describes a transformed bitmap. This string is used
2036// to insert and find bitmaps in the global pixmap cache.
2037//
2038
2039static QString gen_text_bitmap_key( const QWMatrix &m, const QFont &font,
2040 const QString &str, int pos, int len )
2041{
2042 QString fk = font.key();
2043 int sz = 4*2 + len*2 + fk.length()*2 + sizeof(double)*6;
2044 QByteArray buf(sz);
2045 uchar *p = (uchar *)buf.data();
2046 *((double*)p)=m.m11(); p+=sizeof(double);
2047 *((double*)p)=m.m12(); p+=sizeof(double);
2048 *((double*)p)=m.m21(); p+=sizeof(double);
2049 *((double*)p)=m.m22(); p+=sizeof(double);
2050 *((double*)p)=m.dx(); p+=sizeof(double);
2051 *((double*)p)=m.dy(); p+=sizeof(double);
2052 QChar h1( '$' );
2053 QChar h2( 'q' );
2054 QChar h3( 't' );
2055 QChar h4( '$' );
2056 *((QChar*)p)=h1; p+=2;
2057 *((QChar*)p)=h2; p+=2;
2058 *((QChar*)p)=h3; p+=2;
2059 *((QChar*)p)=h4; p+=2;
2060 memcpy( (char*)p, (char*)(str.unicode()+pos), len*2 ); p += len*2;
2061 memcpy( (char*)p, (char*)fk.unicode(), fk.length()*2 ); p += fk.length()*2;
2062 return QString( (QChar*)buf.data(), buf.size()/2 );
2063}
2064
2065static QBitmap *get_text_bitmap( const QString &key )
2066{
2067 return (QBitmap*)QPixmapCache::find( key );
2068}
2069
2070static void ins_text_bitmap( const QString &key, QBitmap *bm )
2071{
2072 if ( !QPixmapCache::insert(key,bm) ) // cannot insert pixmap
2073 delete bm;
2074}
2075#endif
2076
2077void QPainter::drawText( int x, int y, const QString &str, int len, QPainter::TextDirection dir )
2078{
2079 drawText( x, y, str, 0, len, dir );
2080}
2081
2082void QPainter::drawText( int x, int y, const QString &str, int pos, int len, QPainter::TextDirection dir)
2083{
2084 if ( !isActive() )
2085 return;
2086
2087 const int slen = str.length();
2088 if (len < 0)
2089 len = slen - pos;
2090 if ( len == 0 || pos >= slen ) // empty string
2091 return;
2092 if ( pos + len > slen )
2093 len = slen - pos;
2094
2095 if ( testf(DirtyFont) )
2096 updateFont();
2097
2098 if ( testf(ExtDev) ) {
2099 QPDevCmdParam param[3];
2100 QString string = str.mid( pos, len );
2101 QPoint p( x, y );
2102 param[0].point = &p;
2103 param[1].str = &string;
2104 param[2].ival = QFont::NoScript;
2105 if ( !pdev->cmd(QPaintDevice::PdcDrawText2,this,param) || !hps )
2106 return;
2107 }
2108
2109 // we can't take the complete string here as we would otherwise
2110 // get quadratic behaviour when drawing long strings in parts.
2111 // we do however need some chars around the part we paint to get arabic shaping correct.
2112 // ### maybe possible to remove after cursor restrictions work in QRT
2113 int start = QMAX( 0, pos - 8 );
2114 int end = QMIN( (int)str.length(), pos + len + 8 );
2115 QConstString cstr( str.unicode() + start, end - start );
2116 pos -= start;
2117
2118 QTextLayout layout( cstr.string(), this );
2119 layout.beginLayout( QTextLayout::SingleLine );
2120
2121 layout.setBoundary( pos );
2122 layout.setBoundary( pos + len );
2123
2124 QTextEngine *engine = layout.d;
2125 if ( dir != Auto ) {
2126 int level = (dir == RTL) ? 1 : 0;
2127 for ( int i = engine->items.size(); i >= 0; i-- )
2128 engine->items[i].analysis.bidiLevel = level;
2129 }
2130
2131 // small hack to force skipping of unneeded items
2132 start = 0;
2133 while ( engine->items[start].position < pos )
2134 ++start;
2135 engine->currentItem = start;
2136 layout.beginLine( 0xfffffff );
2137 end = start;
2138 while ( !layout.atEnd() && layout.currentItem().from() < pos + len ) {
2139 layout.addCurrentItem();
2140 end++;
2141 }
2142 int ascent = fontMetrics().ascent();
2143 layout.endLine( 0, 0, Qt::SingleLine|Qt::AlignLeft, &ascent, 0 );
2144
2145 // do _not_ call endLayout() here, as it would clean up the shaped items and we would do shaping another time
2146 // for painting.
2147
2148 for ( int i = start; i < end; i++ ) {
2149 QScriptItem *si = &engine->items[i];
2150
2151 QFontEngine *fe = si->fontEngine;
2152 Q_ASSERT( fe );
2153
2154 int xpos = x + si->x;
2155 int ypos = y + si->y - ascent;
2156
2157/// @todo (dmik) do we really need this? we already have painter->handle()
2158// inside QFontEngine::draw(), and the font should have been selected into
2159// hps by updateFont()
2160// HPS oldPs = fe->hps;
2161// fe->hps = hps;
2162// fe->selectTo( hps );
2163
2164 int textFlags = 0;
2165 if ( cfont.d->underline ) textFlags |= Qt::Underline;
2166 if ( cfont.d->overline ) textFlags |= Qt::Overline;
2167 if ( cfont.d->strikeOut ) textFlags |= Qt::StrikeOut;
2168
2169 fe->draw( this, xpos, ypos, engine, si, textFlags );
2170/// @todo (dmik) need?
2171// fe->hps = oldPs;
2172 }
2173}
2174
2175
2176
2177void QPainter::drawTextItem( int x, int y, const QTextItem &ti, int textFlags )
2178{
2179 if ( testf(ExtDev) ) {
2180 QPDevCmdParam param[2];
2181 QPoint p(x, y);
2182 param[0].point = &p;
2183 param[1].textItem = &ti;
2184 bool retval = pdev->cmd(QPaintDevice::PdcDrawTextItem, this, param);
2185 if ( !retval || !hps )
2186 return;
2187 }
2188
2189 QTextEngine *engine = ti.engine;
2190 QScriptItem *si = &engine->items[ti.item];
2191
2192 engine->shape( ti.item );
2193 QFontEngine *fe = si->fontEngine;
2194 Q_ASSERT( fe );
2195
2196 x += si->x;
2197 y += si->y;
2198
2199/// @todo (dmik) do we really need this? we already have painter->handle()
2200// inside QFontEngine::draw(), and the font should have been selected into
2201// hps by updateFont()
2202// HPS oldPs = fe->hps;
2203// fe->hps = hps;
2204// fe->selectTo( hps );
2205
2206 fe->draw( this, x, y, engine, si, textFlags );
2207/// @todo (dmik) need?
2208// fe->hps = oldPs;
2209}
2210
2211
2212QPoint QPainter::pos() const
2213{
2214 QPoint p;
2215 if ( !isActive() || !hps )
2216 return p;
2217 POINTL ptl;
2218 GpiQueryCurrentPosition( hps, &ptl );
2219 if ( devh ) ptl.y = devh - ( ptl.y + 1 );
2220 p.rx() = ptl.x;
2221 p.ry() = ptl.y;
2222 return xFormDev( p );
2223}
2224
Note: See TracBrowser for help on using the repository browser.