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

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

gui: Fixed a crash that could happen at program termination in Dive mode if a top-level window had a native HWND window embedded in it. This was partly a r775 regression and also supersedes this change at all. Closes #184.

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