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

Last change on this file since 1166 was 1166, checked in by Silvan Scherrer, 8 years ago

Qt4: fix a build issue with gcc version 4.7.3 and up

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 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 int widgetHeight;
354 bool vrnDirty : 1;
355 bool vrnDisabled : 1;
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->vrnDisabled = false;
393 wd->widgetHeight = 0;
394 wd->rclCount = 0;
395
396 // receive visible region change messages and other PM messages
397 widget->addPmEventFilter(this);
398 WinSetVisibleRegionNotify(widget->internalWinId(), TRUE);
399
400 if (widget != that->window()) {
401 // receive reparent messages from children to cleanup the map
402 widget->installEventFilter(this);
403 }
404}
405
406void QPMDiveWindowSurfacePrivate::removeWidget(QWidget *widget)
407{
408 if (widget != that->window()) {
409 widget->removeEventFilter(this);
410 subWidgets->remove(widget);
411 }
412
413 WinSetVisibleRegionNotify(widget->internalWinId(), FALSE);
414 widget->removePmEventFilter(this);
415}
416
417bool QPMDiveWindowSurfacePrivate::eventFilter(QObject *obj, QEvent *event)
418{
419 QWidget *widget = qobject_cast<QWidget *>(obj);
420 if (event->type() == QEvent::ParentAboutToChange ||
421 event->type() == QEvent::Destroy) {
422 removeWidget(widget);
423 }
424
425 return false;
426}
427
428bool QPMDiveWindowSurfacePrivate::pmEventFilter(QMSG *msg, MRESULT *result)
429{
430 switch (msg->msg) {
431 case WM_VRNDISABLED: {
432 DEBUG(() << "WM_VRNDISABLED:" << qDebugHWND(msg->hwnd));
433 if (msg->hwnd == that->window()->internalWinId()) {
434 if (!useFB)
435 DiveSetupBlitter(hDive, NULL);
436 data.vrnDisabled = true;
437 } else {
438 WidgetData *wd = widgetData(QWidget::find(msg->hwnd));
439 Q_ASSERT(wd);
440 if (wd)
441 wd->vrnDisabled = true;
442 }
443 *result = 0;
444 return true;
445 }
446 case DM_DRAGOVER: {
447 inDrag = true;
448 break;
449 }
450 case DM_DRAGLEAVE:
451 case DM_DROP: {
452 inDrag = false;
453 break;
454 }
455 case WM_VRNENABLED: {
456 DEBUG(() << "WM_VRNENABLED:" << qDebugHWND(msg->hwnd));
457 QWidget *widget = msg->hwnd == that->window()->internalWinId() ?
458 that->window() : QWidget::find(msg->hwnd);
459 WidgetData *wd = widgetData(widget);
460 Q_ASSERT(wd);
461 wd->vrnDisabled = false;
462 // Note that when an overlapping window of *other* process is moved
463 // over this window, PM still sends WM_VRNENABLED to it but with
464 // ffVisRgnChanged set to FALSE although the visible region *does*
465 // actually change (it doesn't seem to be the case for windows of
466 // the same process). The solution is to ignore this flag and always
467 // assume that the visible region was changed when we get this msg
468#if 0
469 if (LONGFROMMP(msg->mp1)) // window's visible region changed
470#endif
471 wd->vrnDirty = true;
472
473 if (widget == that->window())
474 posDirty = true;
475
476 // process pending flush events for this widget
477 for (QList<QPMDiveWindowSurfacePrivate::FlushArgs>::iterator
478 it = pending.begin(); it != pending.end();) {
479 if (it->widget == widget) {
480 that->doFlush(it->widget, it->from, it->to);
481 it = pending.erase(it);
482 } else {
483 ++it;
484 }
485 }
486
487 *result = 0;
488 return true;
489 }
490 default:
491 break;
492 }
493
494 return false;
495}
496
497QPMDiveWindowSurface::QPMDiveWindowSurface(QWidget* widget)
498 : QWindowSurface(widget), d(new QPMDiveWindowSurfacePrivate)
499{
500 d->that = this;
501 d->image = 0;
502 d->hDive = NULLHANDLE;
503 d->useFB = false;
504 d->bufNum = 0;
505 d->posDirty = true;
506 d->inDrag = false;
507 d->subWidgets = 0;
508
509 memset(&d->setup, 0, sizeof(SETUP_BLITTER));
510
511 // note that fccSrcColorFormat overrides the value specified during the
512 // source buffer creation, so they must match
513 Q_ASSERT(diveBestBufFormat != 0);
514 d->setup.fccSrcColorFormat = diveBestBufFormat;
515 d->setup.fccDstColorFormat = FOURCC_SCRN;
516
517 // add self to the map of participating widgets
518 d->addWidget(window());
519
520 setStaticContentsSupport(true);
521
522 DEBUG(() << "QPMDiveWindowSurface:" << widget);
523}
524
525QPMDiveWindowSurface::~QPMDiveWindowSurface()
526{
527 if (d->subWidgets) {
528 QList<QWidget *> keys = d->subWidgets->keys();
529 foreach(QWidget *w, keys)
530 d->removeWidget(w);
531 Q_ASSERT(d->subWidgets->count() == 0);
532 delete d->subWidgets;
533 }
534
535 d->removeWidget(window());
536
537 if (d->bufNum)
538 DiveFreeImageBuffer(d->hDive, d->bufNum);
539 if (d->hDive != NULLHANDLE)
540 DiveClose(d->hDive);
541 if (d->image)
542 delete d->image;
543}
544
545QPaintDevice *QPMDiveWindowSurface::paintDevice()
546{
547 return d->image;
548}
549
550void QPMDiveWindowSurface::flush(QWidget *widget, const QRegion &rgn,
551 const QPoint &offset)
552{
553 // Not ready for painting yet, bail out. This can happen in
554 // QWidget::create_sys()
555 if (!d->image || rgn.rectCount() == 0)
556 return;
557
558 // make sure the widget is known to us
559 if (!d->widgetData(widget))
560 d->addWidget(widget);
561
562 QRect br = rgn.boundingRect();
563
564 br.translate(offset);
565
566 if (d->inDrag || QDragManager::self()->isInOwnDrag()) {
567 // In drag, DIVE seems to not synchronize well with the mouse buffer
568 // that preserves the contents under the mouse pointer and the drag
569 // image while dragging (even when we use DiveBlitImage()). As a result,
570 // we will get some areas unpainted under if painting is done during
571 // drag. Use the WinGetPS()/GpiDrawBits() way to fix it. The below code
572 // is merely a copy of QT_BITMAP_MIRROR == 3 from qwindowsurface_raster.cpp
573
574 HPS wps = widget->getPS();
575
576 MATRIXLF m;
577 m.fxM11 = MAKEFIXED(1, 0);
578 m.fxM12 = 0;
579 m.lM13 = 0;
580 m.fxM21 = 0;
581 m.fxM22 = MAKEFIXED(-1, 0);
582 m.lM23 = 0;
583 m.lM31 = 0;
584 m.lM32 = widget->height() - 1;
585 GpiSetDefaultViewMatrix(wps, 8, &m, TRANSFORM_REPLACE);
586
587 // make sure br doesn't exceed the backing storage size (it may happen
588 // during resize & move due to the different event order)
589 br = br.intersected(QRect(0, 0, d->image->width(), d->image->height()));
590
591 QPoint wOffset = qt_qwidget_data(widget)->wrect.topLeft();
592 // note that we remove offset from wbr because the widget's HPS has a proper
593 // origin already that includes this offset (which is in fact a position of
594 // the widget relative to its top-level parent)
595 QRect wbr = br.translated(-offset - wOffset);
596
597 BITMAPINFOHEADER2 bmh;
598 memset(&bmh, 0, sizeof(BITMAPINFOHEADER2));
599 bmh.cbFix = sizeof(BITMAPINFOHEADER2);
600 bmh.cPlanes = 1;
601 bmh.cBitCount = d->image->depth();
602 bmh.cx = d->image->width();
603 bmh.cy = d->image->height();
604
605#ifdef QT_PM_NATIVEWIDGETMASK
606 int wh = widget->height();
607
608 // produce a clip region that excludes all descending obstacles
609 // (like child widgets with real HWNDs which are not excluded by Qt)
610 HWND wwnd = widget->internalWinId();
611 RECTL wrcl = { wbr.left(), wh - wbr.bottom() - 1,
612 wbr.right() + 1, wh - wbr.top() };
613 HRGN wrgn = GpiCreateRegion(wps, 1L, &wrcl);
614 ULONG rc = qt_WinProcessWindowObstacles(wwnd, NULL, wrgn, CRGN_DIFF,
615 PWO_Children);
616 if (rc == RGN_RECT || rc == RGN_COMPLEX) {
617 // set the clip region
618 HRGN oldRgn;
619 GpiSetClipRegion(wps, wrgn, &oldRgn);
620 wrgn = oldRgn;
621#endif
622 // Note: target is inclusive-inclusive, source is inclusive-exclusive
623 POINTL ptls[] = { { wbr.left(), wbr.top() },
624 { wbr.right(), wbr.bottom() },
625 { br.left(), br.top() },
626 { br.right() + 1, br.bottom() + 1 } };
627 GpiDrawBits(wps, (PVOID) const_cast<const QImage *>(d->image)->bits(),
628 (PBITMAPINFO2) &bmh, 4, ptls, ROP_SRCCOPY, BBO_IGNORE);
629
630#ifdef QT_PM_NATIVEWIDGETMASK
631 }
632
633 if (wrgn != NULLHANDLE)
634 GpiDestroyRegion(wps, wrgn);
635#endif
636
637 widget->releasePS(wps);
638
639 return;
640 }
641
642 QPoint wOffset = qt_qwidget_data(widget)->wrect.topLeft();
643 // note that we leave offset in wbr since in DIVE mode the origin of the
644 // blit target is always the top level window so we need to properly offset
645 // the target position if we are flushing its child widget
646 QRect wbr = br.translated(-wOffset);
647
648 QPMDiveWindowSurfacePrivate::WidgetData *wd = d->widgetData(widget);
649 Q_ASSERT(wd);
650
651 DEBUG(() << "QPMDiveWindowSurface::flush:" << window() << widget
652 << "vrnDisabled" << wd->vrnDisabled);
653
654 if (wd->vrnDisabled) {
655 // defer the flush
656 QPMDiveWindowSurfacePrivate::FlushArgs args = { widget,
657 br, wbr.topLeft() };
658 d->pending.append(args);
659 return;
660 }
661
662 doFlush(widget, br, wbr.topLeft());
663}
664
665bool QPMDiveWindowSurface::adjustSetup(QWidget *widget)
666{
667 DEBUG(() << "QPMDiveWindowSurface::adjustSetup:" << window() << widget);
668
669 HWND hwnd = window()->internalWinId();
670
671 // don't include lScreenPosX and the rest by default
672 d->setup.ulStructLen = offsetof(SETUP_BLITTER, lScreenPosX);
673 bool setupDirty = false;
674
675 QPMDiveWindowSurfacePrivate::WidgetData *wd = d->widgetData(widget);
676 Q_ASSERT(wd);
677
678 if (d->posDirty || wd->vrnDirty) {
679 setupDirty = true;
680 d->posDirty = false;
681 // the main widget moved, adjust the target poition
682 POINTL ptl = { 0, 0 };
683 WinMapWindowPoints(hwnd, HWND_DESKTOP, &ptl, 1);
684 d->setup.lScreenPosX = ptl.x;
685 d->setup.lScreenPosY = ptl.y;
686 d->setup.ulStructLen = offsetof(SETUP_BLITTER, ulNumDstRects);
687
688 DEBUG(() << "QPMDiveWindowSurface::adjustSetup:" << "posDirty"
689 << ptl.x << ptl.y);
690 }
691
692 bool wasVrnDirty = wd->vrnDirty;
693
694 if (wd->vrnDirty) {
695 setupDirty = true;
696 wd->vrnDirty = false;
697
698 HPS hps = widget->getPS();
699 HRGN hrgn = GpiCreateRegion(hps, 0L, NULL);
700
701 HWND hwndWidget = widget->internalWinId();
702 ULONG rc = WinQueryVisibleRegion(hwndWidget, hrgn);
703#ifdef QT_PM_NATIVEWIDGETMASK
704 if (rc != RGN_ERROR) {
705 // substract children from the visible region, if any
706 rc = qt_WinProcessWindowObstacles(hwndWidget, NULL, hrgn,
707 CRGN_DIFF, PWO_Children);
708#endif
709 if (rc != RGN_ERROR && hwnd != hwndWidget) {
710 // translate coords to the main widget's coordinate space
711 POINTL ptlOffset = { 0, 0 };
712 WinMapWindowPoints(hwnd, hwndWidget, &ptlOffset, 1);
713 ptlOffset.x = -ptlOffset.x;
714 ptlOffset.y = -ptlOffset.y;
715 GpiOffsetRegion(hps, hrgn, &ptlOffset);
716 }
717#ifdef QT_PM_NATIVEWIDGETMASK
718 }
719#endif
720
721 if (rc == RGN_RECT || rc == RGN_COMPLEX) {
722 RGNRECT rgnCtl;
723 rgnCtl.ircStart = 1;
724 rgnCtl.crc = rgnCtl.crcReturned = 0;
725 rgnCtl.ulDirection = RECTDIR_LFRT_TOPBOT;
726 if (GpiQueryRegionRects(hps, hrgn, NULL, &rgnCtl, NULL) &&
727 rgnCtl.crcReturned) {
728 rgnCtl.ircStart = 1;
729 rgnCtl.crc = rgnCtl.crcReturned;
730 rgnCtl.ulDirection = RECTDIR_LFRT_TOPBOT;
731 if (wd->rcls.size() < (int)rgnCtl.crc)
732 wd->rcls.resize((int)rgnCtl.crc);
733 wd->rclCount = rgnCtl.crc;
734 GpiQueryRegionRects(hps, hrgn, NULL, &rgnCtl, wd->rcls.data());
735 }
736 } else if (rc == RGN_NULL) {
737 wd->rclCount = 0;
738 }
739
740 GpiDestroyRegion(hps, hrgn);
741 widget->releasePS(hps);
742
743 // memorize the window height used for the additional visible region
744 // validation in doFlush()
745 wd->widgetHeight = widget->height();
746
747#if defined(QDIVE_DEBUG)
748 DEBUG(() << "QPMDiveWindowSurface::adjustSetup:" << "vrnDirty");
749 for (size_t i = 0; i < wd->rclCount; ++i)
750 DEBUG(() << " " << i << ":" << wd->rcls[i]);
751#endif
752 }
753
754 // make sure setup points to the correct visible rectangle array (note that
755 // we switch it even vrnDirty is false since the widget may change)
756 if (wasVrnDirty || d->setup.ulNumDstRects != wd->rclCount ||
757 (wd->rclCount && d->setup.pVisDstRects != wd->rcls.data()) ||
758 (!wd->rclCount && d->setup.pVisDstRects != NULL)) {
759 setupDirty = true;
760 d->setup.ulNumDstRects = wd->rclCount;
761 d->setup.pVisDstRects = wd->rclCount ? wd->rcls.data() : NULL;
762 d->setup.ulStructLen = sizeof(SETUP_BLITTER);
763 }
764
765 return setupDirty;
766}
767
768void QPMDiveWindowSurface::doFlush(QWidget *widget, const QRect &from, const QPoint &to)
769{
770 DEBUG(() << "QPMDiveWindowSurface::doFlush:" << window() << widget
771 << "from" << from << "to" << to);
772
773 // make sure from doesn't exceed the backing storage size (it may happen
774 // during resize & move due to the different event order)
775 QRect src = from.intersected(QRect(0, 0, d->image->width(), d->image->height()));
776 QPoint dst = to + (src.topLeft() - from.topLeft());
777
778 bool setupDirty = adjustSetup(widget);
779
780 // note that the source image is expected to be top-left oriented
781 // by DiveSetupBlitter() so we don't perform y coordinate flip
782
783 // flip destination y coordinate
784 dst.setY(window()->height() - dst.y() - src.height());
785
786 SETUP_BLITTER setupTmp = d->setup;
787 setupTmp.ulSrcWidth = src.width();
788 setupTmp.ulSrcHeight = src.height();
789 setupTmp.ulSrcPosX = src.left();
790 setupTmp.ulSrcPosY = src.top();
791 setupTmp.ulDstWidth = setupTmp.ulSrcWidth;
792 setupTmp.ulDstHeight = setupTmp.ulSrcHeight;
793 setupTmp.lDstPosX = dst.x();
794 setupTmp.lDstPosY = dst.y();
795
796 if (memcmp(&d->setup, &setupTmp, d->setup.ulStructLen)) {
797 setupDirty = true;
798 memcpy(&d->setup, &setupTmp, d->setup.ulStructLen);
799 }
800
801 if (setupDirty) {
802 DiveSetupBlitter(d->hDive, &d->setup);
803 }
804
805 DiveBlitImage(d->hDive, d->bufNum, DIVE_BUFFER_SCREEN);
806}
807
808void QPMDiveWindowSurface::setGeometry(const QRect &rect)
809{
810 // this method is mostly like QRasterWindowSurface::prepareBuffer()
811
812 QWindowSurface::setGeometry(rect);
813
814 if (d->image == 0 || d->image->width() < rect.width() || d->image->height() < rect.height()) {
815 int width = window()->width();
816 int height = window()->height();
817 if (d->image) {
818 width = qMax(d->image->width(), width);
819 height = qMax(d->image->height(), height);
820 }
821
822 if (width == 0 || height == 0) {
823 delete d->image;
824 d->image = 0;
825 return;
826 }
827
828 QImage *oldImage = d->image;
829
830 QImage::Format format = fourccToFormat(d->setup.fccSrcColorFormat);
831 Q_ASSERT(format != QImage::Format_Invalid);
832 d->image = new QImage(width, height, format);
833
834 if (!d->useFB) {
835 // associate the image data pointer with the buffer number
836 if (d->bufNum)
837 DiveFreeImageBuffer(d->hDive, d->bufNum);
838 d->bufNum = 0;
839 ULONG rc = DiveAllocImageBuffer(d->hDive, &d->bufNum,
840 d->setup.fccSrcColorFormat,
841 width, height,
842 d->image->bytesPerLine(),
843 (PBYTE)const_cast<const QImage *>(d->image)->bits());
844 if (rc != DIVE_SUCCESS) {
845 qWarning("QPMDiveWindowSurface::setGeometry: DiveAllocImageBuffer "
846 "returned 0x%08lX", rc);
847 delete d->image;
848 delete oldImage;
849 return;
850 }
851 }
852
853 if (oldImage && hasStaticContents()) {
854 // Make sure we use the const version of bits() (no detach).
855 const uchar *src = const_cast<const QImage *>(oldImage)->bits();
856 uchar *dst = d->image->bits();
857
858 const int srcBytesPerLine = oldImage->bytesPerLine();
859 const int dstBytesPerLine = d->image->bytesPerLine();
860 const int bytesPerPixel = oldImage->depth() >> 3;
861
862 QRegion staticRegion(staticContents());
863 // Make sure we're inside the boundaries of the old image.
864 staticRegion &= QRect(0, 0, oldImage->width(), oldImage->height());
865 const QVector<QRect> &rects = staticRegion.rects();
866 const QRect *srcRect = rects.constData();
867
868 // Copy the static content of the old image into the new one.
869 int numRectsLeft = rects.size();
870 do {
871 const int bytesOffset = srcRect->x() * bytesPerPixel;
872 const int dy = srcRect->y();
873
874 // Adjust src and dst to point to the right offset.
875 const uchar *s = src + dy * srcBytesPerLine + bytesOffset;
876 uchar *d = dst + dy * dstBytesPerLine + bytesOffset;
877 const int numBytes = srcRect->width() * bytesPerPixel;
878
879 int numScanLinesLeft = srcRect->height();
880 do {
881 ::memcpy(d, s, numBytes);
882 d += dstBytesPerLine;
883 s += srcBytesPerLine;
884 } while (--numScanLinesLeft);
885
886 ++srcRect;
887 } while (--numRectsLeft);
888 }
889
890 delete oldImage;
891 }
892}
893
894// from qwindowsurface.cpp
895extern void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset);
896
897bool QPMDiveWindowSurface::scroll(const QRegion &area, int dx, int dy)
898{
899 if (!d->image || d->image->isNull())
900 return false;
901
902 const QVector<QRect> rects = area.rects();
903 for (int i = 0; i < rects.size(); ++i)
904 qt_scrollRectInImage(*d->image, rects.at(i), QPoint(dx, dy));
905
906 return true;
907}
908
909// static
910QPMDiveWindowSurface *QPMDiveWindowSurface::create(QWidget *widget)
911{
912 if (!diveDllResolved) {
913 diveDllResolved = true;
914 diveDllOK = qgetenv("QT_PM_NO_DIVE").isEmpty();
915 if (diveDllOK) {
916 QByteArray diveEnv = qgetenv("QT_PM_DIVE").trimmed().toUpper();
917 if (diveEnv == "BLIT") {
918 // use DiveBlitImage()
919 diveUseFB = false;
920 } else if (diveEnv == "FB") {
921 // use direct framebuffer access
922 diveUseFB = true;
923 } else if (diveEnv == "FBSWM") {
924 // use direct framebuffer access, hide the mouse pointer
925 diveUseFB = true;
926 diveHideMouse = true;
927 } else {
928 // dedect the Panorama video driver presence
929 HMODULE hmod;
930 bool isPanorama =
931 DosQueryModuleHandle("VBE2GRAD", &hmod) == NO_ERROR &&
932 DosQueryModuleHandle("PANOGREX", &hmod) == NO_ERROR;
933 if (isPanorama) {
934 // if Panorama is detected, disable DIVE by default due to
935 // bugs in the DIVE implementation
936 diveDllOK = false;
937 } else {
938 // FBSWM is a safe default for SNAP and probably other drivers
939 diveUseFB = true;
940 diveHideMouse = true;
941 }
942 }
943 }
944
945 if (diveDllOK) {
946 // resolve Dive functions
947 for (size_t i = 0; i < sizeof(diveDllFuncs) / sizeof(diveDllFuncs[0]); ++i) {
948 *diveDllFuncs[i].entry = diveDll.resolve(diveDllFuncs[i].name);
949 if (!*diveDllFuncs[i].entry) {
950 diveDllOK = false;
951 break;
952 }
953 }
954
955 if (diveDllOK) {
956 diveCaps.ulStructLen = sizeof(diveCaps);
957 DiveQueryCaps(&diveCaps, DIVE_BUFFER_SCREEN);
958
959 DEBUG_VAR(diveCaps.fScreenDirect);
960 DEBUG_VAR(diveCaps.fBankSwitched);
961 DEBUG_VAR(diveCaps.ulDepth);
962 DEBUG_VAR(diveCaps.ulHorizontalResolution);
963 DEBUG_VAR(diveCaps.ulVerticalResolution);
964 DEBUG_VAR(diveCaps.ulScanLineBytes);
965 DEBUG(() << "diveCaps.fccColorEncoding"
966 << ((char*)&diveCaps.fccColorEncoding)[0]
967 << ((char*)&diveCaps.fccColorEncoding)[1]
968 << ((char*)&diveCaps.fccColorEncoding)[2]
969 << ((char*)&diveCaps.fccColorEncoding)[3]);
970
971 diveBestBufFormat = fourccScreenToBuffer(diveCaps.fccColorEncoding,
972 diveUseFB);
973 DEBUG(() << "diveBestBufFormat"
974 << ((char*)&diveBestBufFormat)[0]
975 << ((char*)&diveBestBufFormat)[1]
976 << ((char*)&diveBestBufFormat)[2]
977 << ((char*)&diveBestBufFormat)[3]);
978
979 if (diveUseFB) {
980 if (!diveCaps.fScreenDirect || diveCaps.fBankSwitched) {
981 // direct framebuffer is not supported by the driver
982 // (and switching banks is not supported by our code)
983 diveUseFB = false;
984 } else {
985 if (diveBestBufFormat == diveCaps.fccColorEncoding) {
986 // no color conversion is required
987 } else if (diveBestBufFormat == FOURCC_BGR4) {
988 // build the color conversion table
989 switch (diveCaps.fccColorEncoding) {
990#if 0
991 // FOURCC_R565/FOURCC_R555 should be handled directly
992 case FOURCC_R565: {
993 for (ULONG u = 0; u < 256; ++u) {
994 diveColorMap[0][u] = (u >> 3) << 0;
995 diveColorMap[1][u] = (u >> 2) << 5;
996 diveColorMap[2][u] = (u >> 3) << 11;
997 }
998 break;
999 }
1000 case FOURCC_R555: {
1001 for (ULONG u = 0; u < 256; ++u) {
1002 diveColorMap[0][u] = (u >> 3) << 0;
1003 diveColorMap[1][u] = (u >> 3) << 5;
1004 diveColorMap[2][u] = (u >> 3) << 10;
1005 }
1006 break;
1007 }
1008#endif
1009 case FOURCC_R664: {
1010 for (ULONG u = 0; u < 256; ++u) {
1011 diveColorMap[0][u] = (u >> 2) << 0;
1012 diveColorMap[1][u] = (u >> 2) << 6;
1013 diveColorMap[2][u] = (u >> 4) << 12;
1014 }
1015 break;
1016 }
1017#if 0
1018 // FOURCC_BGR4 should be handled directly
1019 case FOURCC_BGR4:
1020#endif
1021 case FOURCC_RGB4:
1022 case FOURCC_BGR3:
1023 case FOURCC_RGB3:
1024 break;
1025 default:
1026 // screen pixel format is not supported
1027 diveUseFB = false;
1028 break;
1029 }
1030 } else {
1031 Q_ASSERT(false);
1032 diveUseFB = false;
1033 }
1034 }
1035
1036 if (!diveUseFB) {
1037 // we disabled FB, recalculate the best format
1038 diveBestBufFormat = fourccScreenToBuffer(diveCaps.fccColorEncoding,
1039 diveUseFB);
1040 DEBUG(() << "diveBestBufFormat (final)"
1041 << ((char*)&diveBestBufFormat)[0]
1042 << ((char*)&diveBestBufFormat)[1]
1043 << ((char*)&diveBestBufFormat)[2]
1044 << ((char*)&diveBestBufFormat)[3]);
1045 }
1046 }
1047
1048 if (!diveUseFB) {
1049 if (diveBestBufFormat == 0) {
1050 // there is no working pixel format for the buffer for
1051 // DiveBlitImage() to work correctly with the current screen
1052 // format, give up
1053 diveDllOK = false;
1054 }
1055 }
1056
1057 mousePtrSize = WinQuerySysValue(HWND_DESKTOP, SV_CXPOINTER);
1058 }
1059 }
1060
1061 DEBUG_VAR(diveDllOK);
1062 DEBUG_VAR(diveUseFB);
1063 DEBUG_VAR(diveHideMouse);
1064 }
1065
1066 // Note: returning 0 from this method will cause using QRasterWindowSurface
1067 // as a fallback
1068
1069 if (!diveDllOK)
1070 return 0;
1071
1072 HDIVE hDive = NULLHANDLE;
1073 ULONG rc = DIVE_SUCCESS;
1074
1075 if (diveUseFB) {
1076 // we use a shared DIVE instance for all widgets
1077 if (diveHandle == NULLHANDLE)
1078 rc = DiveOpen(&diveHandle, FALSE, &diveFrameBuf);
1079 hDive = diveHandle;
1080 } else {
1081 // we need a new DIVE instance to reduce the number of calls to
1082 // DiveSetupBlitter() (as recommended by MMAPG)
1083 rc = DiveOpen(&hDive, FALSE, 0);
1084 }
1085
1086 if (rc != DIVE_SUCCESS) {
1087 qWarning("QPMDiveWindowSurface::create: DiveOpen returned 0x%08lX", rc);
1088 return 0;
1089 }
1090
1091 QPMDiveWindowSurface *surface = diveUseFB ?
1092 new QPMDiveWindowSurfaceFB(widget) : new QPMDiveWindowSurface(widget);
1093
1094 if (surface)
1095 surface->d->hDive = hDive;
1096 else if (!diveUseFB)
1097 DiveClose(hDive);
1098
1099 return surface;
1100}
1101
1102////////////////////////////////////////////////////////////////////////////////
1103
1104QPMDiveWindowSurfaceFB::QPMDiveWindowSurfaceFB(QWidget* widget)
1105 : QPMDiveWindowSurface(widget)
1106{
1107 d->useFB = true;
1108}
1109
1110QPMDiveWindowSurfaceFB::~QPMDiveWindowSurfaceFB()
1111{
1112 // prevent the shared DIVE handle from closing
1113 d->hDive = NULLHANDLE;
1114}
1115
1116void QPMDiveWindowSurfaceFB::doFlush(QWidget *widget, const QRect &from, const QPoint &to)
1117{
1118 DEBUG(() << "QPMDiveWindowSurfaceFB::doFlush:" << window() << widget
1119 << "from" << from << "to" << to);
1120
1121 // make sure from doesn't exceed the backing storage size (it may happen
1122 // during resize & move due to the different event order)
1123 QRect src = from.intersected(QRect(0, 0, d->image->width(), d->image->height()));
1124
1125 // convert the "to" coordinate to the delta
1126 QPoint dstDelta = from.topLeft() - to;
1127
1128 QPMDiveWindowSurfacePrivate::WidgetData *wd = d->widgetData(widget);
1129 Q_ASSERT(wd);
1130
1131 int widgetHeight = widget->height();
1132
1133 // sometimes PM does not send WM_VRNENABLED although the window size has
1134 // been changed (this is known to happen in FB mode with the Qt Assistant
1135 // application) which leads to screen corruption due to outdated visible
1136 // regions. A fix is to memorize the window height and check it here
1137 if (widgetHeight != wd->widgetHeight)
1138 wd->vrnDirty = true;
1139
1140 bool wasPosDirty = d->posDirty;
1141 bool wasVrnDirty = wd->vrnDirty;
1142
1143 adjustSetup(widget);
1144
1145 int windowHeight = window()->height();
1146
1147 if (wasVrnDirty) {
1148 // flip the y coordinate of all rectangles (both the image and the frame
1149 // buffer are top-left oriented) and also make all points inclusive
1150 for (ULONG i = 0; i < d->setup.ulNumDstRects; ++i) {
1151 RECTL &rcl = d->setup.pVisDstRects[i];
1152 --rcl.xRight;
1153 --rcl.yTop;
1154 rcl.yBottom = windowHeight - rcl.yBottom - 1;
1155 rcl.yTop = windowHeight - rcl.yTop - 1;
1156 }
1157 }
1158 if (wasPosDirty || wasVrnDirty) {
1159 // the same flip for the window position
1160 d->setup.lScreenPosY = diveCaps.ulVerticalResolution -
1161 d->setup.lScreenPosY - windowHeight;
1162 }
1163
1164 // just assume that the rectangle in DiveAcquireFrameBuffer() is in PM
1165 // coordinates (bottom-left based, top-right exclusive), MMREF doesn't
1166 // mention anything particular...
1167 RECTL rclDst = { src.left(),
1168 diveCaps.ulVerticalResolution -
1169 (d->setup.lScreenPosY + src.bottom() + dstDelta.y()) - 1,
1170 src.right() + 1,
1171 diveCaps.ulVerticalResolution -
1172 (d->setup.lScreenPosY + src.top() + dstDelta.y()) };
1173
1174 const int srcBpp = d->image->depth() >> 3;
1175 const int dstBpp = diveCaps.ulDepth >> 3;
1176 Q_ASSERT(srcBpp > 0); // we don't expect color depths < 1 byte here
1177
1178 const int srcBytesPerLine = d->image->bytesPerLine();
1179
1180 bool ptrHidden = false;
1181 if (diveHideMouse) {
1182 // DIVE is not able to preserve the software mouse pointer when
1183 // painting over it using the direct framebuffer access. We have to
1184 // hide it to avoid screen corruption underneath
1185 POINTL ptrPos;
1186 if (WinQueryPointerPos(HWND_DESKTOP, &ptrPos)) {
1187 ptrPos.x -= d->setup.lScreenPosX;
1188 ptrPos.y = diveCaps.ulVerticalResolution - ptrPos.y - 1 -
1189 d->setup.lScreenPosY;
1190 // keep a safety zone around the rectangle to each direction
1191 // as we don't know the exact mouse pointer configuration
1192 if (ptrPos.x >= (src.left() - mousePtrSize) &&
1193 ptrPos.x <= (src.right() + mousePtrSize) &&
1194 ptrPos.y >= (src.top() - mousePtrSize) &&
1195 ptrPos.y <= (src.bottom() + mousePtrSize))
1196 ptrHidden = WinShowPointer(HWND_DESKTOP, FALSE);
1197 }
1198 }
1199
1200 if (DiveAcquireFrameBuffer(d->hDive, &rclDst) == DIVE_SUCCESS) {
1201 // take each visible rectangle and blit it
1202 for (ULONG j = 0; j < d->setup.ulNumDstRects; ++j) {
1203 RECTL rcl = d->setup.pVisDstRects[j];
1204
1205 if (rcl.xLeft < src.left())
1206 rcl.xLeft = src.left();
1207 if (rcl.xRight > src.right())
1208 rcl.xRight = src.right();
1209 if (rcl.yTop < src.top())
1210 rcl.yTop = src.top();
1211 if (rcl.yBottom > src.bottom())
1212 rcl.yBottom = src.bottom();
1213
1214 int rows = rcl.yBottom - rcl.yTop + 1;
1215 int cols = rcl.xRight - rcl.xLeft + 1;
1216 int i;
1217
1218 if (cols > 0 && rows > 0) {
1219 const uchar *srcBits =
1220 d->image->scanLine(rcl.yTop) + rcl.xLeft * srcBpp;
1221 char *dstBits = diveFrameBuf +
1222 (d->setup.lScreenPosY + rcl.yTop + dstDelta.y()) * diveCaps.ulScanLineBytes +
1223 (d->setup.lScreenPosX + rcl.xLeft + dstDelta.x()) * dstBpp;
1224
1225 if (d->setup.fccSrcColorFormat == diveCaps.fccColorEncoding) {
1226 // no color conversion is required
1227 do {
1228 memcpy(dstBits, srcBits, srcBpp * cols);
1229 srcBits += srcBytesPerLine;
1230 dstBits += diveCaps.ulScanLineBytes;
1231 } while (--rows);
1232 } else {
1233 Q_ASSERT(d->setup.fccSrcColorFormat == FOURCC_BGR4);
1234 Q_ASSERT(d->image->format() == QImage::Format_RGB32);
1235 Q_ASSERT(srcBpp == 4);
1236 switch (diveCaps.fccColorEncoding) {
1237
1238#if 0
1239 // FOURCC_BGR4 is covered by memcpy()
1240 case FOURCC_BGR4:
1241 do {
1242 for (i = 0; i < cols; i++ ) {
1243 *(PULONG)dstBits = *(PULONG)srcBits;
1244 srcBits += 4;
1245 dstBits += 4;
1246 }
1247 srcBits += srcBytesPerLine - (cols * 4);
1248 dstBits += diveCaps.ulScanLineBytes - (cols * 4);
1249 } while (--rows);
1250 break;
1251#endif
1252
1253 case FOURCC_RGB4:
1254 do {
1255 for (i = 0; i < cols; i++ ) {
1256 *(PULONG)dstBits = bswap32_p(*(PULONG)srcBits) >> 8;
1257 srcBits += 4;
1258 dstBits += 4;
1259 }
1260 srcBits += srcBytesPerLine - (cols * 4);
1261 dstBits += diveCaps.ulScanLineBytes - (cols * 4);
1262 } while (--rows);
1263 break;
1264
1265 case FOURCC_BGR3:
1266 do {
1267 // copy in batches by 4 pixels
1268 for (i = cols; i >= 4; i -= 4) {
1269 *(PULONG)&dstBits[0] =
1270 (*(PULONG)&srcBits[0] & 0x00ffffff) |
1271 (*(PUCHAR)&srcBits[4] << 24);
1272 *(PULONG)&dstBits[4] =
1273 (*(PUSHORT)&srcBits[5]) |
1274 (*(PUSHORT)&srcBits[8] << 16);
1275 *(PULONG)&dstBits[8] =
1276 (*(PUCHAR)&srcBits[10]) |
1277 (*(PULONG)&srcBits[12] << 8);
1278 srcBits += 16;
1279 dstBits += 12;
1280 }
1281 // copy the rest
1282 while (i--) {
1283 dstBits[0] = srcBits[0];
1284 dstBits[1] = srcBits[1];
1285 dstBits[2] = srcBits[2];
1286 srcBits += 4;
1287 dstBits += 3;
1288 }
1289 srcBits += srcBytesPerLine - (cols * 4);
1290 dstBits += diveCaps.ulScanLineBytes - (cols * 3);
1291 } while (--rows);
1292 break;
1293
1294 case FOURCC_RGB3:
1295 do {
1296 // copy in batches by 4 pixels
1297 for (i = cols; i >= 4; i -= 4) {
1298 *(PULONG)&dstBits[0] =
1299 (*(PUCHAR)&srcBits[6] << 24) |
1300 (bswap32_p(*(PULONG)srcBits) >> 8);
1301 *(PULONG)&dstBits[4] =
1302 bswap32_p(*(PUSHORT)&srcBits[9]) |
1303 (bswap32_p(*(PUSHORT)&srcBits[4]) >> 16);
1304 *(PULONG)&dstBits[8] =
1305 (*(PUCHAR)&srcBits[8]) |
1306 (bswap32_p(*(PULONG)&srcBits[12]) & 0xffffff00);
1307 srcBits += 16;
1308 dstBits += 12;
1309 }
1310 // copy the rest
1311 while (i--) {
1312 dstBits[2] = srcBits[0];
1313 dstBits[1] = srcBits[1];
1314 dstBits[0] = srcBits[2];
1315 srcBits += 4;
1316 dstBits += 3;
1317 }
1318 srcBits += srcBytesPerLine - (cols * 4);
1319 dstBits += diveCaps.ulScanLineBytes - (cols * 3);
1320 } while (--rows);
1321 break;
1322
1323 default:
1324 // assumes that we initialized the diveColorMap table
1325 Q_ASSERT(dstBpp == 2);
1326 do {
1327 PUSHORT temp = (PUSHORT)dstBits;
1328 for (i = 0; i < cols; ++i) {
1329 *temp++ = (USHORT)
1330 (diveColorMap[0][srcBits[0]] |
1331 diveColorMap[1][srcBits[1]] |
1332 diveColorMap[2][srcBits[2]]);
1333 srcBits += 4;
1334 }
1335 srcBits += srcBytesPerLine - (cols * 4);
1336 dstBits += diveCaps.ulScanLineBytes;
1337 } while(--rows);
1338 break;
1339 }
1340 }
1341 }
1342 }
1343
1344 DiveDeacquireFrameBuffer(d->hDive);
1345 }
1346
1347 if (ptrHidden)
1348 WinShowPointer(HWND_DESKTOP, TRUE);
1349}
1350
1351QT_END_NAMESPACE
1352
Note: See TracBrowser for help on using the repository browser.