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