source: trunk/src/gui/painting/qwindowsurface_pm.cpp@ 775

Last change on this file since 775 was 775, checked in by Dmitry A. Kuminov, 15 years ago

gui: Fixed a possible crash and an endless PM event loop recursion when re-parenting widgets in DIVE mode. This could be seen when dragging a toolbar out of the dock widget, dragging it back then closing the application (crash) or attempting to drag the toolbar out again (endless recursion).

File size: 52.0 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation ([email protected])
6**
7** Copyright (C) 2010 netlabs.org. OS/2 parts.
8**
9** This file is part of the QtGui module of the Qt Toolkit.
10**
11** $QT_BEGIN_LICENSE:LGPL$
12** Commercial Usage
13** Licensees holding valid Qt Commercial licenses may use this file in
14** accordance with the Qt Commercial License Agreement provided with the
15** Software or, alternatively, in accordance with the terms contained in
16** a written agreement between you and Nokia.
17**
18** GNU Lesser General Public License Usage
19** Alternatively, this file may be used under the terms of the GNU Lesser
20** General Public License version 2.1 as published by the Free Software
21** Foundation and appearing in the file LICENSE.LGPL included in the
22** packaging of this file. Please review the following information to
23** ensure the GNU Lesser General Public License version 2.1 requirements
24** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
25**
26** In addition, as a special exception, Nokia gives you certain additional
27** rights. These rights are described in the Nokia Qt LGPL Exception
28** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
29**
30** GNU General Public License Usage
31** Alternatively, this file may be used under the terms of the GNU
32** General Public License version 3.0 as published by the Free Software
33** Foundation and appearing in the file LICENSE.GPL included in the
34** packaging of this file. Please review the following information to
35** ensure the GNU General Public License version 3.0 requirements will be
36** met: http://www.gnu.org/copyleft/gpl.html.
37**
38** If you have questions regarding the use of this file, please contact
39** Nokia at [email protected].
40** $QT_END_LICENSE$
41**
42****************************************************************************/
43
44#include <qdebug.h>
45
46//#define QDIVE_DEBUG
47
48#if defined QDIVE_DEBUG
49#define DEBUG(a) qDebug a
50#define DEBUG_VAR(v) DEBUG(() << #v << v)
51#define DEBUG_VAR_HEX(v) DEBUG(() << #v << qDebugFmtHex(v))
52#else
53#define DEBUG(a) do {} while(0)
54#define DEBUG_VAR(v) do {} while(0)
55#define DEBUG_VAR_HEX(v) do {} while(0)
56#endif
57
58#include <qt_os2.h>
59#include <qlibrary.h>
60#include <qobject.h>
61#include <qevent.h>
62
63#include "qwindowsurface_pm_p.h"
64#include "private/qnativeimage_p.h"
65
66////////////////////////////////////////////////////////////////////////////////
67
68// The below definitions are stolen from the OS/2 Toolkit 4.5 headers (dive.h)
69// to avoid the requirement of having the Toolkit installed when building Qt
70// and let it dynamically link to dive.dll.
71
72#define mmioFOURCC( ch0, ch1, ch2, ch3 ) \
73 ( (ULONG)(BYTE)(ch0) | ( (ULONG)(BYTE)(ch1) << 8 ) | \
74 ( (ULONG)(BYTE)(ch2) << 16 ) | ( (ULONG)(BYTE)(ch3) << 24 ) )
75
76#define FOURCC_SCRN 0
77#define FOURCC_BGR4 mmioFOURCC( 'B', 'G', 'R', '4' )
78#define FOURCC_RGB4 mmioFOURCC( 'R', 'G', 'B', '4' )
79#define FOURCC_BGR3 mmioFOURCC( 'B', 'G', 'R', '3' )
80#define FOURCC_RGB3 mmioFOURCC( 'R', 'G', 'B', '3' )
81#define FOURCC_R565 mmioFOURCC( 'R', '5', '6', '5' )
82#define FOURCC_R555 mmioFOURCC( 'R', '5', '5', '5' )
83#define FOURCC_R664 mmioFOURCC( 'R', '6', '6', '4' )
84
85#define FOURCC ULONG
86#define HDIVE ULONG
87
88#define DIVE_SUCCESS 0x00000000
89
90#define DIVE_BUFFER_SCREEN 0x00000000
91#define DIVE_BUFFER_GRAPHICS_PLANE 0x00000001
92#define DIVE_BUFFER_ALTERNATE_PLANE 0x00000002
93
94typedef struct _DIVE_CAPS {
95
96 ULONG ulStructLen; /* Set equal to sizeof(DIVE_CAPS) */
97 ULONG ulPlaneCount; /* Number of defined planes. */
98
99 /* Info returned in the following fields pertains to ulPlaneID. */
100 BOOL fScreenDirect; /* TRUE if can get addressability to vram. */
101 BOOL fBankSwitched; /* TRUE if vram is bank-switched. */
102 ULONG ulDepth; /* Number of bits per pixel. */
103 ULONG ulHorizontalResolution; /* Screen width in pixels. */
104 ULONG ulVerticalResolution; /* Screen height in pixels. */
105 ULONG ulScanLineBytes; /* Screen scan line size in bytes. */
106 FOURCC fccColorEncoding; /* Colorspace encoding of the screen. */
107 ULONG ulApertureSize; /* Size of vram aperture in bytes. */
108
109 ULONG ulInputFormats; /* Number of input color formats. */
110 ULONG ulOutputFormats; /* Number of output color formats. */
111 ULONG ulFormatLength; /* Length of format buffer. */
112 PVOID pFormatData; /* Pointer to color format buffer FOURCC's.*/
113
114 } DIVE_CAPS;
115typedef DIVE_CAPS *PDIVE_CAPS;
116
117typedef struct _SETUP_BLITTER {
118
119 /* Set the ulStructLen field equal to the amount of the structure used. */
120 /* allowable: blank lines below mark sizes of 8, 28, 32, 52, 60, or 68. */
121 ULONG ulStructLen;
122 /* Set the ulInvert flags based on the following: */
123 /* b0001 = d01 = h01 = flip the image in the horizontal direction. */
124 /* b0010 = d02 = h02 = flip the image in the vertical direction. */
125 /* All other bits ignored. */
126 ULONG fInvert;
127
128 /* This is the color format of the source data. See "FOURCC.H" */
129 FOURCC fccSrcColorFormat;
130 /* This is the width of the source image in pixels. */
131 ULONG ulSrcWidth;
132 /* This is the height of the source image in pixels. */
133 ULONG ulSrcHeight;
134 /* This is the horizontal offset from which to start displaying for */
135 /* use in displaying a sub-portion of the source image. */
136 ULONG ulSrcPosX;
137 /* This is the vertical offset from which to start displaying. */
138 ULONG ulSrcPosY;
139
140 /* This is the dither type to use. 0 defines no dither and 1 */
141 /* defines 2x2 dither (all others ignored). Note: dithering is only */
142 /* supported in direct color to LUT8 conversions. */
143 ULONG ulDitherType;
144
145 /* This is the color format of the destinaion data. See "FOURCC.H" */
146 FOURCC fccDstColorFormat;
147 /* This is the width of the destination image in pixels. */
148 ULONG ulDstWidth;
149 /* This is the height of the destination image in pixels. */
150 ULONG ulDstHeight;
151 /* This is the horizontal offset from which to start displaying for */
152 /* use in displaying to sub-portion of the destination image. */
153 LONG lDstPosX;
154 /* This is the vertical offset from which to start displaying. */
155 LONG lDstPosY;
156
157 /* This is the world screen horizontal position, where 0 is left. */
158 /* These are ignored if the destination is not the screen. */
159 LONG lScreenPosX;
160 /* This is the world screen vertical position, where 0 is bottom. */
161 LONG lScreenPosY;
162
163 /* This is the number of visible rectangular regions being passed in. */
164 /* These are ignored if the destination is not the screen. */
165 /* Also, if you application *KNOWS* that the region is fully visible */
166 /* (like not going to the screen), the you can use DIVE_FULLY_VISIBLE */
167 /* instead of making up a bogus visible region structure. */
168 ULONG ulNumDstRects;
169 /* This points to an array of visible regions which defines what */
170 /* portions of the source image are to be displayed. */
171 PRECTL pVisDstRects; /* Pointer to array of visible rectangles. */
172
173 } SETUP_BLITTER;
174typedef SETUP_BLITTER *PSETUP_BLITTER;
175
176// functions resolved by dive.dll
177
178static
179ULONG (APIENTRY *DiveQueryCaps) ( PDIVE_CAPS pDiveCaps,
180 ULONG ulPlaneBufNum ) = 0;
181
182static
183ULONG (APIENTRY *DiveOpen) ( HDIVE *phDiveInst,
184 BOOL fNonScreenInstance,
185 PVOID ppFrameBuffer ) = 0;
186
187static
188ULONG (APIENTRY *DiveSetupBlitter) ( HDIVE hDiveInst,
189 PSETUP_BLITTER pSetupBlitter ) = 0;
190
191static
192ULONG (APIENTRY *DiveBlitImage) ( HDIVE hDiveInst,
193 ULONG ulSrcBufNumber,
194 ULONG ulDstBufNumber ) = 0;
195
196static
197ULONG (APIENTRY *DiveClose) ( HDIVE hDiveInst ) = 0;
198
199static
200ULONG (APIENTRY *DiveAcquireFrameBuffer) ( HDIVE hDiveInst,
201 PRECTL prectlDst ) = 0;
202
203static
204ULONG (APIENTRY *DiveDeacquireFrameBuffer) ( HDIVE hDiveInst ) = 0;
205
206static
207ULONG (APIENTRY *DiveAllocImageBuffer) ( HDIVE hDiveInst,
208 PULONG pulBufferNumber,
209 FOURCC fccColorSpace,
210 ULONG ulWidth,
211 ULONG ulHeight,
212 ULONG ulLineSizeBytes,
213 PBYTE pbImageBuffer ) = 0;
214
215static
216ULONG (APIENTRY *DiveFreeImageBuffer) ( HDIVE hDiveInst,
217 ULONG ulBufferNumber ) = 0;
218
219static
220ULONG (APIENTRY *DiveBeginImageBufferAccess) ( HDIVE hDiveInst,
221 ULONG ulBufferNumber,
222 PBYTE *ppbImageBuffer,
223 PULONG pulBufferScanLineBytes,
224 PULONG pulBufferScanLines ) = 0;
225
226static
227ULONG (APIENTRY *DiveEndImageBufferAccess) ( HDIVE hDiveInst,
228 ULONG ulBufferNumber ) = 0;
229
230// function table
231
232#define FUNC_ENTRY(name) { #name, (void **)&name }
233
234static struct { const char *name; void **entry; } diveDllFuncs[] =
235{
236 FUNC_ENTRY(DiveQueryCaps),
237 FUNC_ENTRY(DiveOpen),
238 FUNC_ENTRY(DiveSetupBlitter),
239 FUNC_ENTRY(DiveBlitImage),
240 FUNC_ENTRY(DiveClose),
241 FUNC_ENTRY(DiveAcquireFrameBuffer),
242 FUNC_ENTRY(DiveDeacquireFrameBuffer),
243 FUNC_ENTRY(DiveAllocImageBuffer),
244 FUNC_ENTRY(DiveFreeImageBuffer),
245 FUNC_ENTRY(DiveBeginImageBufferAccess),
246 FUNC_ENTRY(DiveEndImageBufferAccess),
247};
248
249static QLibrary diveDll(QLatin1String("dive"));
250static bool diveDllResolved = false;
251static bool diveDllOK = false;
252
253static DIVE_CAPS diveCaps = { 0 };
254static bool diveUseFB = false;
255static ULONG diveColorMap[3][256] = { { 0 } };
256static HDIVE diveHandle = NULLHANDLE;
257static char *diveFrameBuf = NULL;
258static bool diveHideMouse = false;
259static FOURCC diveBestBufFormat = 0;
260
261static LONG mousePtrSize = 0;
262
263////////////////////////////////////////////////////////////////////////////////
264
265QT_BEGIN_NAMESPACE
266
267#ifdef Q_CC_GNU
268extern inline unsigned bswap32_p(unsigned u)
269{
270 __asm__ __volatile__ ("bswap %0\n"
271 : "=r" (u)
272 : "0" (u));
273 return u;
274}
275#else
276#define bswap32_p(a) \
277 ((((ULONG)(a)) >> 24) | (((ULONG)(a)) << 24) | \
278 (((ULONG)(a) << 8) & 0x00ff0000) | (((ULONG)(a) >> 8) & 0x0000ff00))
279#endif
280
281// Returns a directly matching QImage format for the given FOURCC (including
282// bit order and depth, scan line size etc.) or Format_Invalid.
283static QImage::Format fourccToFormat(FOURCC fourcc)
284{
285 switch (fourcc) {
286 case FOURCC_R555: return QImage::Format_RGB555;
287 case FOURCC_R565: return QImage::Format_RGB16;
288 case FOURCC_RGB3: return QImage::Format_RGB888;
289 case FOURCC_BGR4: return QImage::Format_RGB32;
290 default: return QImage::Format_Invalid;
291 }
292}
293
294// Returns a FOURCC that is best for the buffer used to blit to the given
295// screen FOURCC. Returns 0 (FOURC_SCRN) if there is no suitable conversion,
296// otherwise it is guaranteed that the returned value is accepted by
297// fourccToFormat(). If isFB is true, the selection is made for the direct
298// framebuffer access mode.
299static FOURCC fourccScreenToBuffer(FOURCC fourcc, bool isFB)
300{
301 // return it as is if supported by fourccToFormat()
302 if (fourccToFormat(fourcc) != QImage::Format_Invalid)
303 return fourcc;
304
305 if (!isFB) {
306 // otherwise, use FOURCC_RGB3 (which in theory should always work; if not,
307 // we will add exceptions here and return 0 in such cases). Note that
308 // although working with 32-bit pixels would be faster, we cannot return
309 // FOURCC_BGR4 here because DiveBlitImage() is known to crahsh when the
310 // source buffer is BGR4 and the screen is not (at least, it's the case
311 // with recent SNAP versions)
312 return FOURCC_RGB3;
313 }
314
315 // in direct framebuffer access mode, we use BGR4 which should be faster
316 // (note that our color conversion table built in QPMDiveWindowSurface::create()
317 // only works with BGR4 for now so we must return it here otherwise the FB
318 // mode will be disabled)
319 return FOURCC_BGR4;
320}
321
322class QPMDiveWindowSurfaceFB : public QPMDiveWindowSurface
323{
324public:
325 QPMDiveWindowSurfaceFB(QWidget *widget);
326 ~QPMDiveWindowSurfaceFB();
327 void doFlush(QWidget *widget, const QRect &from, const QPoint &to);
328};
329
330struct QPMDiveWindowSurfacePrivate : public QObject, private QWidget::PmEventFilter
331{
332 QPMDiveWindowSurface *that;
333
334 QImage *image;
335 HDIVE hDive;
336 bool useFB;
337 ULONG bufNum;
338 bool posDirty;
339 bool vrnDisabled;
340 bool inDrag;
341 SETUP_BLITTER setup;
342
343 struct FlushArgs
344 {
345 QWidget *widget;
346 QRect from;
347 QPoint to;
348 };
349 QList<FlushArgs> pending;
350
351 struct WidgetData
352 {
353 QWidget *widget;
354 int widgetHeight;
355 bool vrnDirty;
356 size_t rclCount;
357 QVector<RECTL> rcls;
358 };
359
360 WidgetData data;
361 QMap<HWND, WidgetData> *subWidgets;
362
363 void addWidget(QWidget *widget);
364 void removeWidget(QWidget *widget);
365
366 WidgetData *widgetData(QWidget *widget) {
367 // check for the most common case (no sub-widgets with own HWNDs)
368 if (widget == that->window())
369 return &data;
370 if (!subWidgets || !subWidgets->contains(widget->internalWinId()))
371 return 0;
372 return &(*subWidgets)[widget->internalWinId()];
373 }
374
375 bool eventFilter(QObject *obj, QEvent *event);
376 bool pmEventFilter(QMSG *msg, MRESULT *result);
377};
378
379void QPMDiveWindowSurfacePrivate::addWidget(QWidget *widget)
380{
381 Q_ASSERT(widget->internalWinId());
382
383 WidgetData *wd = &data;
384 if (widget != that->window()) {
385 // lazily create the sub-widget map (only when really necessary)
386 if (!subWidgets)
387 subWidgets = new QMap<HWND, WidgetData>();
388 wd = &(*subWidgets)[widget->internalWinId()];
389 }
390
391 wd->widget = widget;
392 wd->vrnDirty = true;
393 wd->widgetHeight = 0;
394 wd->rclCount = 0;
395
396 if (widget == that->window()) {
397 // receive visible region change messages (note that we don't do this
398 // for sub-widgets as it causes some strange PM freezes if these widgets
399 // are embedded windows manipulated by other processes). We also want
400 // to handle other PM messages
401 widget->addPmEventFilter(this);
402 WinSetVisibleRegionNotify(widget->internalWinId(), TRUE);
403 } else {
404 // receive various PM messages
405 widget->addPmEventFilter(this);
406 // receive reparent messages from children to cleanup the map
407 widget->installEventFilter(this);
408 }
409}
410
411void QPMDiveWindowSurfacePrivate::removeWidget(QWidget *widget)
412{
413 if (widget == that->window()) {
414 WinSetVisibleRegionNotify(widget->internalWinId(), FALSE);
415 widget->removePmEventFilter(this);
416 } else {
417 widget->removeEventFilter(this);
418 widget->removePmEventFilter(this);
419 subWidgets->remove(widget->internalWinId());
420 }
421}
422
423bool QPMDiveWindowSurfacePrivate::eventFilter(QObject *obj, QEvent *event)
424{
425 QWidget *widget = qobject_cast<QWidget *>(obj);
426 if (event->type() == QEvent::ParentAboutToChange) {
427 removeWidget(widget);
428 }
429
430 return false;
431}
432
433bool QPMDiveWindowSurfacePrivate::pmEventFilter(QMSG *msg, MRESULT *result)
434{
435 switch (msg->msg) {
436 case WM_VRNDISABLED: {
437 if (!useFB)
438 DiveSetupBlitter(hDive, NULL);
439 vrnDisabled = true;
440 *result = 0;
441 return true;
442 }
443 case DM_DRAGOVER: {
444 inDrag = true;
445 break;
446 }
447 case DM_DRAGLEAVE:
448 case DM_DROP: {
449 inDrag = false;
450 break;
451 }
452 case WM_VRNENABLED: {
453 vrnDisabled = false;
454 // Note that when an overlapping window of *other* process is moved
455 // over this window, PM still sends WM_VRNENABLED to it but with
456 // ffVisRgnChanged set to FALSE although the visible region *does*
457 // actually change (it doesn't seem to be the case for windows of
458 // the same process). The solution is to ignore this flag and always
459 // assume that the visible region was changed when we get this msg
460#if 0
461 if (LONGFROMMP(msg->mp1)) // window's visible region changed
462#endif
463 {
464 // mark all widgets' visible regions as dirty
465 data.vrnDirty = true;
466 if (subWidgets) {
467 foreach(HWND hwnd, subWidgets->keys())
468 (*subWidgets)[hwnd].vrnDirty = true;
469 }
470 }
471 posDirty = true;
472
473 // process pending flush events
474 foreach(const QPMDiveWindowSurfacePrivate::FlushArgs &args, pending)
475 that->doFlush(args.widget, args.from, args.to);
476 pending.clear();
477
478 *result = 0;
479 return true;
480 }
481 case WM_SIZE: {
482 if (msg->hwnd != that->window()->internalWinId()) {
483 // sometimes PM doesn't send WM_VRNENABLED to the main widget
484 // when the sub-widget (its descendant) gets resized within it;
485 // fix it here by invalidating all visible regions
486 data.vrnDirty = true;
487 if (subWidgets) {
488 foreach(HWND hwnd, subWidgets->keys())
489 (*subWidgets)[hwnd].vrnDirty = true;
490 }
491 }
492 break;
493 }
494 default:
495 break;
496 }
497
498 return false;
499}
500
501QPMDiveWindowSurface::QPMDiveWindowSurface(QWidget* widget)
502 : QWindowSurface(widget), d(new QPMDiveWindowSurfacePrivate)
503{
504 d->that = this;
505 d->image = 0;
506 d->hDive = NULLHANDLE;
507 d->useFB = false;
508 d->bufNum = 0;
509 d->posDirty = true;
510 d->vrnDisabled = false;
511 d->inDrag = false;
512 d->subWidgets = 0;
513
514 memset(&d->setup, 0, sizeof(SETUP_BLITTER));
515
516 // note that fccSrcColorFormat overrides the value specified during the
517 // source buffer creation, so they must match
518 Q_ASSERT(diveBestBufFormat != 0);
519 d->setup.fccSrcColorFormat = diveBestBufFormat;
520 d->setup.fccDstColorFormat = FOURCC_SCRN;
521
522 // add self to the map of participating widgets
523 d->addWidget(window());
524
525 setStaticContentsSupport(true);
526}
527
528QPMDiveWindowSurface::~QPMDiveWindowSurface()
529{
530 if (d->subWidgets) {
531 foreach(HWND hwnd, d->subWidgets->keys())
532 d->removeWidget((*d->subWidgets)[hwnd].widget);
533 Q_ASSERT(d->subWidgets->count() == 0);
534 delete d->subWidgets;
535 }
536
537 d->removeWidget(window());
538
539 if (d->bufNum)
540 DiveFreeImageBuffer(d->hDive, d->bufNum);
541 if (d->hDive != NULLHANDLE)
542 DiveClose(d->hDive);
543 if (d->image)
544 delete d->image;
545}
546
547QPaintDevice *QPMDiveWindowSurface::paintDevice()
548{
549 return d->image;
550}
551
552void QPMDiveWindowSurface::flush(QWidget *widget, const QRegion &rgn,
553 const QPoint &offset)
554{
555 // Not ready for painting yet, bail out. This can happen in
556 // QWidget::create_sys()
557 if (!d->image || rgn.rectCount() == 0)
558 return;
559
560 // make sure the widget is known to us
561 if (!d->widgetData(widget))
562 d->addWidget(widget);
563
564 QRect br = rgn.boundingRect();
565
566 br.translate(offset);
567
568 if (d->inDrag) {
569 // In drag, DIVE seems to not synchronize well with the mouse buffer
570 // that preserves the contents under the mouse pointer and the drag
571 // image while dragging (even when we use DiveBlitImage()). As a result,
572 // we will get some areas unpainted under if painting is done during
573 // drag. Use the WinGetPS()/GpiDrawBits() way to fix it. The below code
574 // is merely a copy of QT_BITMAP_MIRROR == 3 from qwindowsurface_raster.cpp
575
576 HPS wps = widget->getPS();
577
578 MATRIXLF m;
579 m.fxM11 = MAKEFIXED(1, 0);
580 m.fxM12 = 0;
581 m.lM13 = 0;
582 m.fxM21 = 0;
583 m.fxM22 = MAKEFIXED(-1, 0);
584 m.lM23 = 0;
585 m.lM31 = 0;
586 m.lM32 = widget->height() - 1;
587 GpiSetDefaultViewMatrix(wps, 8, &m, TRANSFORM_REPLACE);
588
589 // make sure br doesn't exceed the backing storage size (it may happen
590 // during resize & move due to the different event order)
591 br = br.intersected(QRect(0, 0, d->image->width(), d->image->height()));
592
593 QPoint wOffset = qt_qwidget_data(widget)->wrect.topLeft();
594 // note that we remove offset from wbr because the widget's HPS has a proper
595 // origin already that includes this offset (which is in fact a position of
596 // the widget relative to its top-level parent)
597 QRect wbr = br.translated(-offset - wOffset);
598
599 BITMAPINFOHEADER2 bmh;
600 memset(&bmh, 0, sizeof(BITMAPINFOHEADER2));
601 bmh.cbFix = sizeof(BITMAPINFOHEADER2);
602 bmh.cPlanes = 1;
603 bmh.cBitCount = d->image->depth();
604 bmh.cx = d->image->width();
605 bmh.cy = d->image->height();
606
607 int wh = widget->height();
608
609 // produce a clip region that excludes all descending obstacles
610 // (like child widgets with real HWNDs which are not excluded by Qt)
611 HWND wwnd = widget->internalWinId();
612 RECTL wrcl = { wbr.left(), wh - wbr.bottom() - 1,
613 wbr.right() + 1, wh - wbr.top() };
614 HRGN wrgn = GpiCreateRegion(wps, 1L, &wrcl);
615 ULONG rc = qt_WinProcessWindowObstacles(wwnd, NULL, wrgn, CRGN_DIFF,
616 PWO_Children);
617 if (rc == RGN_RECT || rc == RGN_COMPLEX) {
618 // set the clip region
619 HRGN oldRgn;
620 GpiSetClipRegion(wps, wrgn, &oldRgn);
621 wrgn = oldRgn;
622
623 // Note: target is inclusive-inclusive, source is inclusive-exclusive
624 POINTL ptls[] = { { wbr.left(), wbr.top() },
625 { wbr.right(), wbr.bottom() },
626 { br.left(), br.top() },
627 { br.right() + 1, br.bottom() + 1 } };
628 GpiDrawBits(wps, (PVOID) const_cast<const QImage *>(d->image)->bits(),
629 (PBITMAPINFO2) &bmh, 4, ptls, ROP_SRCCOPY, BBO_IGNORE);
630 }
631
632 if (wrgn != NULLHANDLE)
633 GpiDestroyRegion(wps, wrgn);
634
635 widget->releasePS(wps);
636
637 return;
638 }
639
640 QPoint wOffset = qt_qwidget_data(widget)->wrect.topLeft();
641 // note that we leave offset in wbr since in DIVE mode the origin of the
642 // blit target is always the top level window so we need to properly offset
643 // the target position if we are flushing its child widget
644 QRect wbr = br.translated(-wOffset);
645
646 if (d->vrnDisabled) {
647 // defer the flush
648 QPMDiveWindowSurfacePrivate::FlushArgs args = { widget,
649 br, wbr.topLeft() };
650 d->pending.append(args);
651 return;
652 }
653
654 doFlush(widget, br, wbr.topLeft());
655}
656
657bool QPMDiveWindowSurface::adjustSetup(QWidget *widget)
658{
659 HWND hwnd = window()->internalWinId();
660
661 // don't include lScreenPosX and the rest by default
662 d->setup.ulStructLen = offsetof(SETUP_BLITTER, lScreenPosX);
663 bool setupDirty = false;
664
665 QPMDiveWindowSurfacePrivate::WidgetData *wd = d->widgetData(widget);
666 Q_ASSERT(wd);
667
668 if (d->posDirty || wd->vrnDirty) {
669 setupDirty = true;
670 d->posDirty = false;
671 // the main widget moved, adjust the target poition
672 POINTL ptl = { 0, 0 };
673 WinMapWindowPoints(hwnd, HWND_DESKTOP, &ptl, 1);
674 d->setup.lScreenPosX = ptl.x;
675 d->setup.lScreenPosY = ptl.y;
676 d->setup.ulStructLen = offsetof(SETUP_BLITTER, ulNumDstRects);
677
678 DEBUG(() << "QPMDiveWindowSurface::adjustSetup:" << "posDirty"
679 << ptl.x << ptl.y);
680 }
681
682 bool wasVrnDirty = wd->vrnDirty;
683
684 if (wd->vrnDirty) {
685 setupDirty = true;
686 wd->vrnDirty = false;
687
688 HPS hps = window()->getPS();
689 HRGN hrgn = GpiCreateRegion(hps, 0L, NULL);
690
691 ULONG rc = WinQueryVisibleRegion(hwnd, hrgn);
692 if (rc != RGN_ERROR) {
693 HWND hwndWidget = widget->internalWinId();
694 POINTL ptlOffset = { 0, 0 };
695 if (hwnd != hwndWidget) {
696 // translate the main widget's visible region to this widget's
697 // coordinate space
698 WinMapWindowPoints(hwnd, hwndWidget, &ptlOffset, 1);
699 GpiOffsetRegion(hps, hrgn, &ptlOffset);
700 }
701 // substract children from the visible region, if any
702 rc = qt_WinProcessWindowObstacles(hwndWidget, NULL, hrgn,
703 CRGN_DIFF, PWO_Children);
704 if (rc != RGN_ERROR && hwnd != hwndWidget) {
705 // translate back to the main widget's coordinate space
706 ptlOffset.x = -ptlOffset.x;
707 ptlOffset.y = -ptlOffset.y;
708 GpiOffsetRegion(hps, hrgn, &ptlOffset);
709 }
710 }
711
712 if (rc == RGN_RECT || rc == RGN_COMPLEX) {
713 RGNRECT rgnCtl;
714 rgnCtl.ircStart = 1;
715 rgnCtl.crc = rgnCtl.crcReturned = 0;
716 rgnCtl.ulDirection = RECTDIR_LFRT_TOPBOT;
717 if (GpiQueryRegionRects(hps, hrgn, NULL, &rgnCtl, NULL) &&
718 rgnCtl.crcReturned) {
719 rgnCtl.ircStart = 1;
720 rgnCtl.crc = rgnCtl.crcReturned;
721 rgnCtl.ulDirection = RECTDIR_LFRT_TOPBOT;
722 if (wd->rcls.size() < (int)rgnCtl.crc)
723 wd->rcls.resize((int)rgnCtl.crc);
724 wd->rclCount = rgnCtl.crc;
725 GpiQueryRegionRects(hps, hrgn, NULL, &rgnCtl, wd->rcls.data());
726 }
727 } else if (rc == RGN_NULL) {
728 wd->rclCount = 0;
729 }
730
731 GpiDestroyRegion(hps, hrgn);
732 window()->releasePS(hps);
733
734 // memorize the window height used for the additional visible region
735 // validation in doFlush()
736 wd->widgetHeight = widget->height();
737
738#if defined(QDIVE_DEBUG)
739 DEBUG(() << "QPMDiveWindowSurface::adjustSetup:" << "vrnDirty");
740 for (size_t i = 0; i < wd->rclCount; ++i)
741 DEBUG(() << " " << i << ":" << wd->rcls[i]);
742#endif
743 }
744
745 // make sure setup points to the correct visible rectangle array (note that
746 // we switch it even vrnDirty is false since the widget may change)
747 if (wasVrnDirty || d->setup.ulNumDstRects != wd->rclCount ||
748 (wd->rclCount && d->setup.pVisDstRects != wd->rcls.data()) ||
749 (!wd->rclCount && d->setup.pVisDstRects != NULL)) {
750 setupDirty = true;
751 d->setup.ulNumDstRects = wd->rclCount;
752 d->setup.pVisDstRects = wd->rclCount ? wd->rcls.data() : NULL;
753 d->setup.ulStructLen = sizeof(SETUP_BLITTER);
754 }
755
756 return setupDirty;
757}
758
759void QPMDiveWindowSurface::doFlush(QWidget *widget, const QRect &from, const QPoint &to)
760{
761 DEBUG(() << "QPMDiveWindowSurface::doFlush:" << window() << widget
762 << "from" << from << "to" << to);
763
764 // make sure from doesn't exceed the backing storage size (it may happen
765 // during resize & move due to the different event order)
766 QRect src = from.intersected(QRect(0, 0, d->image->width(), d->image->height()));
767 QPoint dst = to + (src.topLeft() - from.topLeft());
768
769 bool setupDirty = adjustSetup(widget);
770
771 // note that the source image is expected to be top-left oriented
772 // by DiveSetupBlitter() so we don't perform y coordinate flip
773
774 // flip destination y coordinate
775 dst.setY(window()->height() - dst.y() - src.height());
776
777 SETUP_BLITTER setupTmp = d->setup;
778 setupTmp.ulSrcWidth = src.width();
779 setupTmp.ulSrcHeight = src.height();
780 setupTmp.ulSrcPosX = src.left();
781 setupTmp.ulSrcPosY = src.top();
782 setupTmp.ulDstWidth = setupTmp.ulSrcWidth;
783 setupTmp.ulDstHeight = setupTmp.ulSrcHeight;
784 setupTmp.lDstPosX = dst.x();
785 setupTmp.lDstPosY = dst.y();
786
787 if (memcmp(&d->setup, &setupTmp, d->setup.ulStructLen)) {
788 setupDirty = true;
789 memcpy(&d->setup, &setupTmp, d->setup.ulStructLen);
790 }
791
792 if (setupDirty) {
793 DiveSetupBlitter(d->hDive, &d->setup);
794 }
795
796 DiveBlitImage(d->hDive, d->bufNum, DIVE_BUFFER_SCREEN);
797}
798
799void QPMDiveWindowSurface::setGeometry(const QRect &rect)
800{
801 // this method is mostly like QRasterWindowSurface::prepareBuffer()
802
803 QWindowSurface::setGeometry(rect);
804
805 if (d->image == 0 || d->image->width() < rect.width() || d->image->height() < rect.height()) {
806 int width = window()->width();
807 int height = window()->height();
808 if (d->image) {
809 width = qMax(d->image->width(), width);
810 height = qMax(d->image->height(), height);
811 }
812
813 if (width == 0 || height == 0) {
814 delete d->image;
815 d->image = 0;
816 return;
817 }
818
819 QImage *oldImage = d->image;
820
821 QImage::Format format = fourccToFormat(d->setup.fccSrcColorFormat);
822 Q_ASSERT(format != QImage::Format_Invalid);
823 d->image = new QImage(width, height, format);
824
825 if (!d->useFB) {
826 // associate the image data pointer with the buffer number
827 if (d->bufNum)
828 DiveFreeImageBuffer(d->hDive, d->bufNum);
829 d->bufNum = 0;
830 ULONG rc = DiveAllocImageBuffer(d->hDive, &d->bufNum,
831 d->setup.fccSrcColorFormat,
832 width, height,
833 d->image->bytesPerLine(),
834 (PBYTE)const_cast<const QImage *>(d->image)->bits());
835 if (rc != DIVE_SUCCESS) {
836 qWarning("QPMDiveWindowSurface::setGeometry: DiveAllocImageBuffer "
837 "returned 0x%08lX", rc);
838 delete d->image;
839 delete oldImage;
840 return;
841 }
842 }
843
844 if (oldImage && hasStaticContents()) {
845 // Make sure we use the const version of bits() (no detach).
846 const uchar *src = const_cast<const QImage *>(oldImage)->bits();
847 uchar *dst = d->image->bits();
848
849 const int srcBytesPerLine = oldImage->bytesPerLine();
850 const int dstBytesPerLine = d->image->bytesPerLine();
851 const int bytesPerPixel = oldImage->depth() >> 3;
852
853 QRegion staticRegion(staticContents());
854 // Make sure we're inside the boundaries of the old image.
855 staticRegion &= QRect(0, 0, oldImage->width(), oldImage->height());
856 const QVector<QRect> &rects = staticRegion.rects();
857 const QRect *srcRect = rects.constData();
858
859 // Copy the static content of the old image into the new one.
860 int numRectsLeft = rects.size();
861 do {
862 const int bytesOffset = srcRect->x() * bytesPerPixel;
863 const int dy = srcRect->y();
864
865 // Adjust src and dst to point to the right offset.
866 const uchar *s = src + dy * srcBytesPerLine + bytesOffset;
867 uchar *d = dst + dy * dstBytesPerLine + bytesOffset;
868 const int numBytes = srcRect->width() * bytesPerPixel;
869
870 int numScanLinesLeft = srcRect->height();
871 do {
872 ::memcpy(d, s, numBytes);
873 d += dstBytesPerLine;
874 s += srcBytesPerLine;
875 } while (--numScanLinesLeft);
876
877 ++srcRect;
878 } while (--numRectsLeft);
879 }
880
881 delete oldImage;
882 }
883}
884
885// from qwindowsurface.cpp
886extern void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset);
887
888bool QPMDiveWindowSurface::scroll(const QRegion &area, int dx, int dy)
889{
890 if (!d->image || d->image->isNull())
891 return false;
892
893 const QVector<QRect> rects = area.rects();
894 for (int i = 0; i < rects.size(); ++i)
895 qt_scrollRectInImage(*d->image, rects.at(i), QPoint(dx, dy));
896
897 return true;
898}
899
900// static
901QPMDiveWindowSurface *QPMDiveWindowSurface::create(QWidget *widget)
902{
903 if (!diveDllResolved) {
904 diveDllResolved = true;
905 diveDllOK = qgetenv("QT_PM_NO_DIVE").isEmpty();
906 if (diveDllOK) {
907 QByteArray diveEnv = qgetenv("QT_PM_DIVE").trimmed().toUpper();
908 if (diveEnv == "BLIT") {
909 // use DiveBlitImage()
910 diveUseFB = false;
911 } else if (diveEnv == "FB") {
912 // use direct framebuffer access
913 diveUseFB = true;
914 } else if (diveEnv == "FBSWM") {
915 // use direct framebuffer access, hide the mouse pointer
916 diveUseFB = true;
917 diveHideMouse = true;
918 } else {
919 // dedect the Panorama video driver presense
920 bool isPanorama = qgetenv("C1") == "VBE2GRAD" &&
921 qgetenv("GREEXT") == "PANOGREX";
922 if (isPanorama) {
923 // if Panorama is detected, disable DIVE by default due to
924 // bugs in the DIVE implementation
925 diveDllOK = false;
926 } else {
927 // FBSWM is a safe default for SNAP and probably other drivers
928 diveUseFB = true;
929 diveHideMouse = true;
930 }
931 }
932 }
933
934 if (diveDllOK) {
935 // resolve Dive functions
936 for (size_t i = 0; i < sizeof(diveDllFuncs) / sizeof(diveDllFuncs[0]); ++i) {
937 *diveDllFuncs[i].entry = diveDll.resolve(diveDllFuncs[i].name);
938 if (!*diveDllFuncs[i].entry) {
939 diveDllOK = false;
940 break;
941 }
942 }
943
944 if (diveDllOK) {
945 diveCaps.ulStructLen = sizeof(diveCaps);
946 DiveQueryCaps(&diveCaps, DIVE_BUFFER_SCREEN);
947
948 DEBUG_VAR(diveCaps.fScreenDirect);
949 DEBUG_VAR(diveCaps.fBankSwitched);
950 DEBUG_VAR(diveCaps.ulDepth);
951 DEBUG_VAR(diveCaps.ulHorizontalResolution);
952 DEBUG_VAR(diveCaps.ulVerticalResolution);
953 DEBUG_VAR(diveCaps.ulScanLineBytes);
954 DEBUG(() << "diveCaps.fccColorEncoding"
955 << ((char*)&diveCaps.fccColorEncoding)[0]
956 << ((char*)&diveCaps.fccColorEncoding)[1]
957 << ((char*)&diveCaps.fccColorEncoding)[2]
958 << ((char*)&diveCaps.fccColorEncoding)[3]);
959
960 diveBestBufFormat = fourccScreenToBuffer(diveCaps.fccColorEncoding,
961 diveUseFB);
962 DEBUG(() << "diveBestBufFormat"
963 << ((char*)&diveBestBufFormat)[0]
964 << ((char*)&diveBestBufFormat)[1]
965 << ((char*)&diveBestBufFormat)[2]
966 << ((char*)&diveBestBufFormat)[3]);
967
968 if (diveUseFB) {
969 if (!diveCaps.fScreenDirect || diveCaps.fBankSwitched) {
970 // direct framebuffer is not supported by the driver
971 // (and switching banks is not supported by our code)
972 diveUseFB = false;
973 } else {
974 if (diveBestBufFormat == diveCaps.fccColorEncoding) {
975 // no color conversion is required
976 } else if (diveBestBufFormat == FOURCC_BGR4) {
977 // build the color conversion table
978 switch (diveCaps.fccColorEncoding) {
979#if 0
980 // FOURCC_R565/FOURCC_R555 should be handled directly
981 case FOURCC_R565: {
982 for (ULONG u = 0; u < 256; ++u) {
983 diveColorMap[0][u] = (u >> 3) << 0;
984 diveColorMap[1][u] = (u >> 2) << 5;
985 diveColorMap[2][u] = (u >> 3) << 11;
986 }
987 break;
988 }
989 case FOURCC_R555: {
990 for (ULONG u = 0; u < 256; ++u) {
991 diveColorMap[0][u] = (u >> 3) << 0;
992 diveColorMap[1][u] = (u >> 3) << 5;
993 diveColorMap[2][u] = (u >> 3) << 10;
994 }
995 break;
996 }
997#endif
998 case FOURCC_R664: {
999 for (ULONG u = 0; u < 256; ++u) {
1000 diveColorMap[0][u] = (u >> 2) << 0;
1001 diveColorMap[1][u] = (u >> 2) << 6;
1002 diveColorMap[2][u] = (u >> 4) << 12;
1003 }
1004 break;
1005 }
1006#if 0
1007 // FOURCC_BGR4 should be handled directly
1008 case FOURCC_BGR4:
1009#endif
1010 case FOURCC_RGB4:
1011 case FOURCC_BGR3:
1012 case FOURCC_RGB3:
1013 break;
1014 default:
1015 // screen pixel format is not supported
1016 diveUseFB = false;
1017 break;
1018 }
1019 } else {
1020 Q_ASSERT(false);
1021 diveUseFB = false;
1022 }
1023 }
1024
1025 if (!diveUseFB) {
1026 // we disabled FB, recalculate the best format
1027 diveBestBufFormat = fourccScreenToBuffer(diveCaps.fccColorEncoding,
1028 diveUseFB);
1029 DEBUG(() << "diveBestBufFormat (final)"
1030 << ((char*)&diveBestBufFormat)[0]
1031 << ((char*)&diveBestBufFormat)[1]
1032 << ((char*)&diveBestBufFormat)[2]
1033 << ((char*)&diveBestBufFormat)[3]);
1034 }
1035 }
1036
1037 if (!diveUseFB) {
1038 if (diveBestBufFormat == 0) {
1039 // there is no working pixel format for the buffer for
1040 // DiveBlitImage() to work correctly with the current screen
1041 // format, give up
1042 diveDllOK = false;
1043 }
1044 }
1045
1046 mousePtrSize = WinQuerySysValue(HWND_DESKTOP, SV_CXPOINTER);
1047 }
1048 }
1049
1050 DEBUG_VAR(diveDllOK);
1051 DEBUG_VAR(diveUseFB);
1052 DEBUG_VAR(diveHideMouse);
1053 }
1054
1055 // Note: returning 0 from this method will cause using QRasterWindowSurface
1056 // as a fallback
1057
1058 if (!diveDllOK)
1059 return 0;
1060
1061 HDIVE hDive = NULLHANDLE;
1062 ULONG rc = DIVE_SUCCESS;
1063
1064 if (diveUseFB) {
1065 // we use a shared DIVE instance for all widgets
1066 if (diveHandle == NULLHANDLE)
1067 rc = DiveOpen(&diveHandle, FALSE, &diveFrameBuf);
1068 hDive = diveHandle;
1069 } else {
1070 // we need a new DIVE instance to reduce the number of calls to
1071 // DiveSetupBlitter() (as recommended by MMAPG)
1072 rc = DiveOpen(&hDive, FALSE, 0);
1073 }
1074
1075 if (rc != DIVE_SUCCESS) {
1076 qWarning("QPMDiveWindowSurface::create: DiveOpen returned 0x%08lX", rc);
1077 return 0;
1078 }
1079
1080 QPMDiveWindowSurface *surface = diveUseFB ?
1081 new QPMDiveWindowSurfaceFB(widget) : new QPMDiveWindowSurface(widget);
1082
1083 if (surface)
1084 surface->d->hDive = hDive;
1085 else if (!diveUseFB)
1086 DiveClose(hDive);
1087
1088 return surface;
1089}
1090
1091////////////////////////////////////////////////////////////////////////////////
1092
1093QPMDiveWindowSurfaceFB::QPMDiveWindowSurfaceFB(QWidget* widget)
1094 : QPMDiveWindowSurface(widget)
1095{
1096 d->useFB = true;
1097}
1098
1099QPMDiveWindowSurfaceFB::~QPMDiveWindowSurfaceFB()
1100{
1101 // prevent the shared DIVE handle from closing
1102 d->hDive = NULLHANDLE;
1103}
1104
1105void QPMDiveWindowSurfaceFB::doFlush(QWidget *widget, const QRect &from, const QPoint &to)
1106{
1107 DEBUG(() << "QPMDiveWindowSurfaceFB::doFlush:" << window() << widget
1108 << "from" << from << "to" << to);
1109
1110 // make sure from doesn't exceed the backing storage size (it may happen
1111 // during resize & move due to the different event order)
1112 QRect src = from.intersected(QRect(0, 0, d->image->width(), d->image->height()));
1113
1114 // convert the "to" coordinate to the delta
1115 QPoint dstDelta = from.topLeft() - to;
1116
1117 QPMDiveWindowSurfacePrivate::WidgetData *wd = d->widgetData(widget);
1118 Q_ASSERT(wd);
1119
1120 int widgetHeight = widget->height();
1121
1122 // sometimes PM does not send WM_VRNENABLED although the window size has
1123 // been changed (this is known to happen in FB mode with the Qt Assistant
1124 // application) which leads to screen corruption due to outdated visible
1125 // regions. A fix is to memorize the window height and check it here
1126 if (widgetHeight != wd->widgetHeight)
1127 wd->vrnDirty = true;
1128
1129 bool wasPosDirty = d->posDirty;
1130 bool wasVrnDirty = wd->vrnDirty;
1131
1132 adjustSetup(widget);
1133
1134 int windowHeight = window()->height();
1135
1136 if (wasVrnDirty) {
1137 // flip the y coordinate of all rectangles (both the image and the frame
1138 // buffer are top-left oriented) and also make all points inclusive
1139 for (ULONG i = 0; i < d->setup.ulNumDstRects; ++i) {
1140 RECTL &rcl = d->setup.pVisDstRects[i];
1141 --rcl.xRight;
1142 --rcl.yTop;
1143 rcl.yBottom = windowHeight - rcl.yBottom - 1;
1144 rcl.yTop = windowHeight - rcl.yTop - 1;
1145 }
1146 }
1147 if (wasPosDirty || wasVrnDirty) {
1148 // the same flip for the window position
1149 d->setup.lScreenPosY = diveCaps.ulVerticalResolution -
1150 d->setup.lScreenPosY - windowHeight;
1151 }
1152
1153 // just assume that the rectangle in DiveAcquireFrameBuffer() is in PM
1154 // coordinates (bottom-left based, top-right exclusive), MMREF doesn't
1155 // mention anything particular...
1156 RECTL rclDst = { src.left(),
1157 diveCaps.ulVerticalResolution -
1158 (d->setup.lScreenPosY + src.bottom() + dstDelta.y()) - 1,
1159 src.right() + 1,
1160 diveCaps.ulVerticalResolution -
1161 (d->setup.lScreenPosY + src.top() + dstDelta.y()) };
1162
1163 const int srcBpp = d->image->depth() >> 3;
1164 const int dstBpp = diveCaps.ulDepth >> 3;
1165 Q_ASSERT(srcBpp > 0); // we don't expect color depths < 1 byte here
1166
1167 const int srcBytesPerLine = d->image->bytesPerLine();
1168
1169 bool ptrHidden = false;
1170 if (diveHideMouse) {
1171 // DIVE is not able to preserve the software mouse pointer when
1172 // painting over it using the direct framebuffer access. We have to
1173 // hide it to avoid screen corruption underneath
1174 POINTL ptrPos;
1175 if (WinQueryPointerPos(HWND_DESKTOP, &ptrPos)) {
1176 ptrPos.x -= d->setup.lScreenPosX;
1177 ptrPos.y = diveCaps.ulVerticalResolution - ptrPos.y - 1 -
1178 d->setup.lScreenPosY;
1179 // keep a safety zone around the rectangle to each direction
1180 // as we don't know the exact mouse pointer configuration
1181 if (ptrPos.x >= (src.left() - mousePtrSize) &&
1182 ptrPos.x <= (src.right() + mousePtrSize) &&
1183 ptrPos.y >= (src.top() - mousePtrSize) &&
1184 ptrPos.y <= (src.bottom() + mousePtrSize))
1185 ptrHidden = WinShowPointer(HWND_DESKTOP, FALSE);
1186 }
1187 }
1188
1189 if (DiveAcquireFrameBuffer(d->hDive, &rclDst) == DIVE_SUCCESS) {
1190 // take each visible rectangle and blit it
1191 for (ULONG i = 0; i < d->setup.ulNumDstRects; ++i) {
1192 RECTL rcl = d->setup.pVisDstRects[i];
1193
1194 if (rcl.xLeft < src.left())
1195 rcl.xLeft = src.left();
1196 if (rcl.xRight > src.right())
1197 rcl.xRight = src.right();
1198 if (rcl.yTop < src.top())
1199 rcl.yTop = src.top();
1200 if (rcl.yBottom > src.bottom())
1201 rcl.yBottom = src.bottom();
1202
1203 int rows = rcl.yBottom - rcl.yTop + 1;
1204 int cols = rcl.xRight - rcl.xLeft + 1;
1205 int i;
1206
1207 if (cols > 0 && rows > 0) {
1208 const uchar *srcBits =
1209 d->image->scanLine(rcl.yTop) + rcl.xLeft * srcBpp;
1210 char *dstBits = diveFrameBuf +
1211 (d->setup.lScreenPosY + rcl.yTop + dstDelta.y()) * diveCaps.ulScanLineBytes +
1212 (d->setup.lScreenPosX + rcl.xLeft + dstDelta.x()) * dstBpp;
1213
1214 if (d->setup.fccSrcColorFormat == diveCaps.fccColorEncoding) {
1215 // no color conversion is required
1216 do {
1217 memcpy(dstBits, srcBits, srcBpp * cols);
1218 srcBits += srcBytesPerLine;
1219 dstBits += diveCaps.ulScanLineBytes;
1220 } while (--rows);
1221 } else {
1222 Q_ASSERT(d->setup.fccSrcColorFormat == FOURCC_BGR4);
1223 Q_ASSERT(d->image->format() == QImage::Format_RGB32);
1224 Q_ASSERT(srcBpp == 4);
1225 switch (diveCaps.fccColorEncoding) {
1226
1227#if 0
1228 // FOURCC_BGR4 is covered by memcpy()
1229 case FOURCC_BGR4:
1230 do {
1231 for (i = 0; i < cols; i++ ) {
1232 *(PULONG)dstBits = *(PULONG)srcBits;
1233 srcBits += 4;
1234 dstBits += 4;
1235 }
1236 srcBits += srcBytesPerLine - (cols * 4);
1237 dstBits += diveCaps.ulScanLineBytes - (cols * 4);
1238 } while (--rows);
1239 break;
1240#endif
1241
1242 case FOURCC_RGB4:
1243 do {
1244 for (i = 0; i < cols; i++ ) {
1245 *(PULONG)dstBits = bswap32_p(*(PULONG)srcBits) >> 8;
1246 srcBits += 4;
1247 dstBits += 4;
1248 }
1249 srcBits += srcBytesPerLine - (cols * 4);
1250 dstBits += diveCaps.ulScanLineBytes - (cols * 4);
1251 } while (--rows);
1252 break;
1253
1254 case FOURCC_BGR3:
1255 do {
1256 // copy in batches by 4 pixels
1257 for (i = cols; i >= 4; i -= 4) {
1258 *(PULONG)&dstBits[0] =
1259 (*(PULONG)&srcBits[0] & 0x00ffffff) |
1260 (*(PUCHAR)&srcBits[4] << 24);
1261 *(PULONG)&dstBits[4] =
1262 (*(PUSHORT)&srcBits[5]) |
1263 (*(PUSHORT)&srcBits[8] << 16);
1264 *(PULONG)&dstBits[8] =
1265 (*(PUCHAR)&srcBits[10]) |
1266 (*(PULONG)&srcBits[12] << 8);
1267 srcBits += 16;
1268 dstBits += 12;
1269 }
1270 // copy the rest
1271 while (i--) {
1272 dstBits[0] = srcBits[0];
1273 dstBits[1] = srcBits[1];
1274 dstBits[2] = srcBits[2];
1275 srcBits += 4;
1276 dstBits += 3;
1277 }
1278 srcBits += srcBytesPerLine - (cols * 4);
1279 dstBits += diveCaps.ulScanLineBytes - (cols * 3);
1280 } while (--rows);
1281 break;
1282
1283 case FOURCC_RGB3:
1284 do {
1285 // copy in batches by 4 pixels
1286 for (i = cols; i >= 4; i -= 4) {
1287 *(PULONG)&dstBits[0] =
1288 (*(PUCHAR)&srcBits[6] << 24) |
1289 (bswap32_p(*(PULONG)srcBits) >> 8);
1290 *(PULONG)&dstBits[4] =
1291 bswap32_p(*(PUSHORT)&srcBits[9]) |
1292 (bswap32_p(*(PUSHORT)&srcBits[4]) >> 16);
1293 *(PULONG)&dstBits[8] =
1294 (*(PUCHAR)&srcBits[8]) |
1295 (bswap32_p(*(PULONG)&srcBits[12]) & 0xffffff00);
1296 srcBits += 16;
1297 dstBits += 12;
1298 }
1299 // copy the rest
1300 while (i--) {
1301 dstBits[2] = srcBits[0];
1302 dstBits[1] = srcBits[1];
1303 dstBits[0] = srcBits[2];
1304 srcBits += 4;
1305 dstBits += 3;
1306 }
1307 srcBits += srcBytesPerLine - (cols * 4);
1308 dstBits += diveCaps.ulScanLineBytes - (cols * 3);
1309 } while (--rows);
1310 break;
1311
1312 default:
1313 // assumes that we initialized the diveColorMap table
1314 Q_ASSERT(dstBpp == 2);
1315 do {
1316 PUSHORT temp = (PUSHORT)dstBits;
1317 for (i = 0; i < cols; ++i) {
1318 *temp++ = (USHORT)
1319 (diveColorMap[0][srcBits[0]] |
1320 diveColorMap[1][srcBits[1]] |
1321 diveColorMap[2][srcBits[2]]);
1322 srcBits += 4;
1323 }
1324 srcBits += srcBytesPerLine - (cols * 4);
1325 dstBits += diveCaps.ulScanLineBytes;
1326 } while(--rows);
1327 break;
1328 }
1329 }
1330 }
1331 }
1332
1333 DiveDeacquireFrameBuffer(d->hDive);
1334 }
1335
1336 if (ptrHidden)
1337 WinShowPointer(HWND_DESKTOP, TRUE);
1338}
1339
1340QT_END_NAMESPACE
1341
Note: See TracBrowser for help on using the repository browser.