source: trunk/src/gui/painting/qwindowsurface_raster.cpp

Last change on this file was 1034, checked in by Dmitry A. Kuminov, 14 years ago

OS/2: Disable native window masking code as it is not complete.

This code is only necessary for child widgets that have native windows.
Applications using this approach are very rare (they include e.g. video
players that paint to Qt widgets on their own using native window IDs)
and they don't need masking in these widgets or their ancestors anyway.

The current implementation lacks some functionality -- in particular, it
cannot properly issue WM_VRNENABLED/WM_VRNDISABLED notifications
which breaks those video players, so that keeping it enabled makes little
to no sense.

The relevant code remains in place but guarded by the
QT_PM_NATIVEWIDGETMASK compiler macro so that it can be enabled
as needed for further experiments. See also #203 for more details.

File size: 23.9 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4** All rights reserved.
5** Contact: Nokia Corporation (qt-info@nokia.com)
6**
7** This file is part of the QtGui module of the Qt Toolkit.
8**
9** $QT_BEGIN_LICENSE:LGPL$
10** Commercial Usage
11** Licensees holding valid Qt Commercial licenses may use this file in
12** accordance with the Qt Commercial License Agreement provided with the
13** Software or, alternatively, in accordance with the terms contained in
14** a written agreement between you and Nokia.
15**
16** GNU Lesser General Public License Usage
17** Alternatively, this file may be used under the terms of the GNU Lesser
18** General Public License version 2.1 as published by the Free Software
19** Foundation and appearing in the file LICENSE.LGPL included in the
20** packaging of this file. Please review the following information to
21** ensure the GNU Lesser General Public License version 2.1 requirements
22** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23**
24** In addition, as a special exception, Nokia gives you certain additional
25** rights. These rights are described in the Nokia Qt LGPL Exception
26** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27**
28** GNU General Public License Usage
29** Alternatively, this file may be used under the terms of the GNU
30** General Public License version 3.0 as published by the Free Software
31** Foundation and appearing in the file LICENSE.GPL included in the
32** packaging of this file. Please review the following information to
33** ensure the GNU General Public License version 3.0 requirements will be
34** met: http://www.gnu.org/copyleft/gpl.html.
35**
36** If you have questions regarding the use of this file, please contact
37** Nokia at qt-info@nokia.com.
38** $QT_END_LICENSE$
39**
40****************************************************************************/
41
42#include <qdebug.h>
43
44#include <qglobal.h> // for Q_WS_WIN define (non-PCH)
45#ifdef Q_WS_WIN
46#include <qlibrary.h>
47#include <qt_windows.h>
48#endif
49
50#include <QtGui/qpaintdevice.h>
51#include <QtGui/qwidget.h>
52
53#include "private/qwindowsurface_raster_p.h"
54#include "private/qnativeimage_p.h"
55#include "private/qwidget_p.h"
56
57#ifdef Q_WS_X11
58#include "private/qpixmap_x11_p.h"
59#include "private/qt_x11_p.h"
60#include "private/qwidget_p.h"
61#include "qx11info_x11.h"
62#endif
63#include "private/qdrawhelper_p.h"
64
65#ifdef Q_WS_MAC
66#include <private/qt_cocoa_helpers_mac_p.h>
67#endif
68
69#if defined(Q_WS_PM) && defined(QT_LOG_BLITSPEED)
70#include <InnotekLIBC/FastInfoBlocks.h>
71#endif
72
73#if defined(Q_WS_PM)
74LONG APIENTRY GpiQueryYInversion(HPS hps);
75BOOL APIENTRY GpiEnableYInversion(HPS hps, LONG lHeight);
76#define QT_BITMAP_MIRROR 3 // 1 = QImage.mirrored()
77 // 2 = GpiEnableYInversion()
78 // 3 = GPI Matrix (seems to be the fastest)
79#endif
80
81QT_BEGIN_NAMESPACE
82
83#if defined(Q_WS_PM) && defined(QT_LOG_BLITSPEED)
84unsigned long long qt_total_blit_ms = 0;
85unsigned long long qt_total_blit_pixels = 0;
86#endif
87
88class QRasterWindowSurfacePrivate
89{
90public:
91 QNativeImage *image;
92
93#ifdef Q_WS_X11
94 GC gc;
95#ifndef QT_NO_XRENDER
96 uint translucentBackground : 1;
97#endif
98#endif
99 uint inSetGeometry : 1;
100};
101
102QRasterWindowSurface::QRasterWindowSurface(QWidget *window)
103 : QWindowSurface(window), d_ptr(new QRasterWindowSurfacePrivate)
104{
105#ifdef Q_WS_X11
106 d_ptr->gc = XCreateGC(X11->display, window->handle(), 0, 0);
107#ifndef QT_NO_XRENDER
108 d_ptr->translucentBackground = X11->use_xrender
109 && window->x11Info().depth() == 32;
110#endif
111#endif
112 d_ptr->image = 0;
113 d_ptr->inSetGeometry = false;
114 setStaticContentsSupport(true);
115}
116
117
118QRasterWindowSurface::~QRasterWindowSurface()
119{
120#ifdef Q_WS_X11
121 XFreeGC(X11->display, d_ptr->gc);
122#endif
123 if (d_ptr->image)
124 delete d_ptr->image;
125}
126
127
128QPaintDevice *QRasterWindowSurface::paintDevice()
129{
130 return &d_ptr->image->image;
131}
132
133void QRasterWindowSurface::beginPaint(const QRegion &rgn)
134{
135#if (defined(Q_WS_X11) && !defined(QT_NO_XRENDER)) || (defined(Q_WS_WIN) && !defined(Q_WS_WINCE))
136 if (!qt_widget_private(window())->isOpaque && window()->testAttribute(Qt::WA_TranslucentBackground)) {
137#if defined(Q_WS_WIN) && !defined(Q_WS_WINCE)
138 if (d_ptr->image->image.format() != QImage::Format_ARGB32_Premultiplied)
139 prepareBuffer(QImage::Format_ARGB32_Premultiplied, window());
140#endif
141 QPainter p(&d_ptr->image->image);
142 p.setCompositionMode(QPainter::CompositionMode_Source);
143 const QVector<QRect> rects = rgn.rects();
144 const QColor blank = Qt::transparent;
145 for (QVector<QRect>::const_iterator it = rects.begin(); it != rects.end(); ++it) {
146 p.fillRect(*it, blank);
147 }
148 }
149#else
150 Q_UNUSED(rgn);
151#endif
152}
153
154void QRasterWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoint &offset)
155{
156 Q_D(QRasterWindowSurface);
157
158 // Not ready for painting yet, bail out. This can happen in
159 // QWidget::create_sys()
160 if (!d->image || rgn.rectCount() == 0)
161 return;
162
163#ifdef Q_WS_WIN
164 QRect br = rgn.boundingRect();
165
166#ifndef Q_WS_WINCE
167 if (!qt_widget_private(window())->isOpaque
168 && window()->testAttribute(Qt::WA_TranslucentBackground)
169 && (qt_widget_private(window())->data.window_flags & Qt::FramelessWindowHint))
170 {
171 QRect r = window()->frameGeometry();
172 QPoint frameOffset = qt_widget_private(window())->frameStrut().topLeft();
173 QRect dirtyRect = br.translated(offset + frameOffset);
174
175 SIZE size = {r.width(), r.height()};
176 POINT ptDst = {r.x(), r.y()};
177 POINT ptSrc = {0, 0};
178 BLENDFUNCTION blend = {AC_SRC_OVER, 0, (int)(255.0 * window()->windowOpacity()), Q_AC_SRC_ALPHA};
179 RECT dirty = {dirtyRect.x(), dirtyRect.y(),
180 dirtyRect.x() + dirtyRect.width(), dirtyRect.y() + dirtyRect.height()};
181 Q_UPDATELAYEREDWINDOWINFO info = {sizeof(info), NULL, &ptDst, &size, d->image->hdc, &ptSrc, 0, &blend, Q_ULW_ALPHA, &dirty};
182 ptrUpdateLayeredWindowIndirect(window()->internalWinId(), &info);
183 } else
184#endif
185 {
186 QPoint wOffset = qt_qwidget_data(widget)->wrect.topLeft();
187
188 HDC widget_dc = widget->getDC();
189
190 QRect wbr = br.translated(-wOffset);
191 BitBlt(widget_dc, wbr.x(), wbr.y(), wbr.width(), wbr.height(),
192 d->image->hdc, br.x() + offset.x(), br.y() + offset.y(), SRCCOPY);
193 widget->releaseDC(widget_dc);
194 }
195
196#ifndef QT_NO_DEBUG
197 static bool flush = !qgetenv("QT_FLUSH_WINDOWSURFACE").isEmpty();
198 if (flush) {
199 SelectObject(qt_win_display_dc(), GetStockObject(BLACK_BRUSH));
200 Rectangle(qt_win_display_dc(), 0, 0, d->image->width() + 2, d->image->height() + 2);
201 BitBlt(qt_win_display_dc(), 1, 1, d->image->width(), d->image->height(),
202 d->image->hdc, 0, 0, SRCCOPY);
203 }
204#endif
205
206#endif
207
208#ifdef Q_WS_PM
209 QRect br = rgn.boundingRect();
210
211 HPS wps = widget->getPS();
212
213#if 0
214 qDebug() << "QRasterWindowSurface::flush:" << widget
215 << "wps" << qDebugFmtHex(wps) << "br" << br;
216#endif
217
218#ifdef QT_LOG_BLITSPEED
219 unsigned long ticks = fibGetMsCount();
220#endif
221
222#if QT_BITMAP_MIRROR == 1
223
224 // flip the image vertically for PM
225 QImage img = d->image->image.mirrored();
226
227 br.translate(offset);
228
229 // make sure br doesn't exceed the backing storage size (it may happen
230 // during resize & move due to the different event order)
231 br = br.intersected(QRect(0, 0, img.width(), img.height()));
232
233 QPoint wOffset = qt_qwidget_data(widget)->wrect.topLeft();
234 // note that we remove offset from wbr because the widget's HPS has a proper
235 // origin already that includes this offset (which is in fact a position of
236 // the widget relative to its top-level parent)
237 QRect wbr = br.translated(-offset - wOffset);
238
239 BITMAPINFOHEADER2 bmh;
240 memset(&bmh, 0, sizeof(BITMAPINFOHEADER2));
241 bmh.cbFix = sizeof(BITMAPINFOHEADER2);
242 bmh.cPlanes = 1;
243 bmh.cBitCount = 32; // @todo support 8-bit indexed colors?
244 bmh.cx = img.width();
245 bmh.cy = img.height();
246
247 int wh = widget->height();
248 int ih = img.height();
249
250#ifdef QT_PM_NATIVEWIDGETMASK
251 // produce a clip region that excludes all descending obstacles
252 // (like child widgets with real HWNDs which are not excluded by Qt)
253 HWND wwnd = widget->winId();
254 RECTL wrcl = { wbr.left(), wh - wbr.bottom() - 1,
255 wbr.right() + 1, wh - wbr.top() };
256 HRGN wrgn = GpiCreateRegion(wps, 1L, &wrcl);
257 ULONG rc = qt_WinProcessWindowObstacles(wwnd, NULL, wrgn, CRGN_DIFF,
258 PWO_Children);
259 if (rc == RGN_RECT || rc == RGN_COMPLEX) {
260 // set the clip region
261 HRGN oldRgn;
262 GpiSetClipRegion(wps, wrgn, &oldRgn);
263 wrgn = oldRgn;
264#endif
265 // Note: target is inclusive-inclusive, source is inclusive-exclusive
266 POINTL ptls[] = { { wbr.left(), wh - wbr.bottom() - 1 },
267 { wbr.right(), wh - wbr.top() - 1 },
268 { br.left(), ih - br.bottom() - 1 },
269 { br.right() + 1, ih - br.top() } };
270#if 0
271 qDebug() << "QRasterWindowSurface::flush:" << widget << "ptls"
272 << ptls[0].x << ptls[0].y << ptls[1].x << ptls[1].y
273 << ptls[2].x << ptls[2].y << ptls[3].x << ptls[3].y
274 << "img.size" << img.size() << "img.bits" << img.bits();
275#endif
276 GpiDrawBits(wps, (PVOID) img.bits(), (PBITMAPINFO2) &bmh, 4, ptls,
277 ROP_SRCCOPY, BBO_IGNORE);
278
279#ifdef QT_PM_NATIVEWIDGETMASK
280 }
281
282 if (wrgn != NULLHANDLE)
283 GpiDestroyRegion(wps, wrgn);
284#endif
285
286#elif QT_BITMAP_MIRROR == 2
287
288 // Use GpiEnableYInversion to flip the y axis. This is almost as fast as
289 // QT_BITMAP_MIRROR == 3. "Almost" is probably due to some extra overhead
290 // on the method call compared to the direct matrix manipulation.
291
292 br.translate(offset);
293
294 // make sure br doesn't exceed the backing storage size (it may happen
295 // during resize & move due to the different event order)
296 br = br.intersected(QRect(0, 0, d->image->width(), d->image->height()));
297
298 QPoint wOffset = qt_qwidget_data(widget)->wrect.topLeft();
299 // note that we remove offset from wbr because the widget's HPS has a proper
300 // origin already that includes this offset (which is in fact a position of
301 // the widget relative to its top-level parent)
302 QRect wbr = br.translated(-offset - wOffset);
303
304 BITMAPINFOHEADER2 bmh;
305 memset(&bmh, 0, sizeof(BITMAPINFOHEADER2));
306 bmh.cbFix = sizeof(BITMAPINFOHEADER2);
307 bmh.cPlanes = 1;
308 bmh.cBitCount = 32; // @todo support 8-bit indexed colors?
309 bmh.cx = d->image->width();
310 bmh.cy = d->image->height();
311
312#ifdef QT_PM_NATIVEWIDGETMASK
313 int wh = widget->height();
314
315 // produce a clip region that excludes all descending obstacles
316 // (like child widgets with real HWNDs which are not excluded by Qt)
317 HWND wwnd = widget->winId();
318 RECTL wrcl = { wbr.left(), wh - wbr.bottom() - 1,
319 wbr.right() + 1, wh - wbr.top() };
320 HRGN wrgn = GpiCreateRegion(wps, 1L, &wrcl);
321 ULONG rc = qt_WinProcessWindowObstacles(wwnd, NULL, wrgn, CRGN_DIFF,
322 PWO_Children);
323 if (rc == RGN_RECT || rc == RGN_COMPLEX) {
324 // set the clip region
325 HRGN oldRgn;
326 GpiSetClipRegion(wps, wrgn, &oldRgn);
327 wrgn = oldRgn;
328#endif
329 // Note: target is inclusive-inclusive, source is inclusive-exclusive
330 POINTL ptls[] = { { wbr.left(), wbr.top() },
331 { wbr.right(), wbr.bottom() },
332 { br.left(), br.top() },
333 { br.right() + 1, br.bottom() + 1 } };
334#if 0
335 qDebug() << "QRasterWindowSurface::flush:" << widget << "ptls"
336 << ptls[0].x << ptls[0].y << ptls[1].x << ptls[1].y
337 << ptls[2].x << ptls[2].y << ptls[3].x << ptls[3].y
338 << "img.size" << d->image->size() << "img.bits" << d->image->bits();
339#endif
340
341 // setup the Y coordinate inversion (this seems to use the same GPI matrix
342 // transformation internally as we do in method 3 below)
343 LONG oldInversion = GpiQueryYInversion(wps);
344 GpiEnableYInversion(wps, widget->height() - 1);
345
346 GpiDrawBits(wps, (PVOID) const_cast<const QImage &>(d->image->image).bits(),
347 (PBITMAPINFO2) &bmh, 4, ptls, ROP_SRCCOPY, BBO_IGNORE);
348
349 GpiEnableYInversion(wps, oldInversion);
350
351#ifdef QT_PM_NATIVEWIDGETMASK
352 }
353
354 if (wrgn != NULLHANDLE)
355 GpiDestroyRegion(wps, wrgn);
356#endif
357
358#ifndef QT_NO_DEBUG
359 // for debug flushing
360 const QImage img = d->image->image;
361#endif
362
363#elif QT_BITMAP_MIRROR == 3
364
365 // Use the reflection + transformation matrix to flip the y axis.
366 // This is proven to be much faster than manual image flipping on the real
367 // video hardware as it probably involves some hardware acceleration in
368 // the video driver.
369
370 MATRIXLF m;
371 m.fxM11 = MAKEFIXED(1, 0);
372 m.fxM12 = 0;
373 m.lM13 = 0;
374 m.fxM21 = 0;
375 m.fxM22 = MAKEFIXED(-1, 0);
376 m.lM23 = 0;
377 m.lM31 = 0;
378 m.lM32 = widget->height() - 1;
379 GpiSetDefaultViewMatrix(wps, 8, &m, TRANSFORM_REPLACE);
380
381 br.translate(offset);
382
383 // make sure br doesn't exceed the backing storage size (it may happen
384 // during resize & move due to the different event order)
385 br = br.intersected(QRect(0, 0, d->image->width(), d->image->height()));
386
387 QPoint wOffset = qt_qwidget_data(widget)->wrect.topLeft();
388 // note that we remove offset from wbr because the widget's HPS has a proper
389 // origin already that includes this offset (which is in fact a position of
390 // the widget relative to its top-level parent)
391 QRect wbr = br.translated(-offset - wOffset);
392
393 BITMAPINFOHEADER2 bmh;
394 memset(&bmh, 0, sizeof(BITMAPINFOHEADER2));
395 bmh.cbFix = sizeof(BITMAPINFOHEADER2);
396 bmh.cPlanes = 1;
397 bmh.cBitCount = 32; // @todo support 8-bit indexed colors?
398 bmh.cx = d->image->width();
399 bmh.cy = d->image->height();
400
401#ifdef QT_PM_NATIVEWIDGETMASK
402 int wh = widget->height();
403
404 // produce a clip region that excludes all descending obstacles
405 // (like child widgets with real HWNDs which are not excluded by Qt)
406 HWND wwnd = widget->winId();
407 RECTL wrcl = { wbr.left(), wh - wbr.bottom() - 1,
408 wbr.right() + 1, wh - wbr.top() };
409 HRGN wrgn = GpiCreateRegion(wps, 1L, &wrcl);
410 ULONG rc = qt_WinProcessWindowObstacles(wwnd, NULL, wrgn, CRGN_DIFF,
411 PWO_Children);
412 if (rc == RGN_RECT || rc == RGN_COMPLEX) {
413 // set the clip region
414 HRGN oldRgn;
415 GpiSetClipRegion(wps, wrgn, &oldRgn);
416 wrgn = oldRgn;
417#endif
418 // Note: target is inclusive-inclusive, source is inclusive-exclusive
419 POINTL ptls[] = { { wbr.left(), wbr.top() },
420 { wbr.right(), wbr.bottom() },
421 { br.left(), br.top() },
422 { br.right() + 1, br.bottom() + 1 } };
423 GpiDrawBits(wps, (PVOID) const_cast<const QImage &>(d->image->image).bits(),
424 (PBITMAPINFO2) &bmh, 4, ptls, ROP_SRCCOPY, BBO_IGNORE);
425
426#ifdef QT_PM_NATIVEWIDGETMASK
427 }
428
429 if (wrgn != NULLHANDLE)
430 GpiDestroyRegion(wps, wrgn);
431#endif
432
433#ifndef QT_NO_DEBUG
434 // for debug flushing
435 const QImage img = d->image->image;
436#endif
437
438#else // if QT_BITMAP_MIRROR == 3
439# error "QT_BITMAP_MIRROR must be 1, 2 or 3"
440#endif
441
442 widget->releasePS(wps);
443
444#ifdef QT_LOG_BLITSPEED
445 ticks = fibGetMsCount() - ticks;
446 qt_total_blit_ms += ticks;
447 qt_total_blit_pixels += br.width() * br.height();
448#endif
449
450#ifndef QT_NO_DEBUG
451 static bool flush = !qgetenv("QT_FLUSH_WINDOWSURFACE").isEmpty();
452 if (flush) {
453 HPS dps = qt_display_ps();
454 RECTL rcl = { 10, 50, 10 + img.width() + 2, 50 + img.height() + 2 };
455 WinDrawBorder(dps, &rcl, 1, 1, CLR_BLACK, CLR_BLACK, 0);
456 POINTL ptls[] = { { 11, 51, },
457 { 11 + img.width() - 1, 51 + img.height() - 1 },
458 { 0, 0 },
459 { img.width(), img.height() } };
460 GpiDrawBits(dps, (PVOID) img.bits(), (PBITMAPINFO2) &bmh, 4, ptls,
461 ROP_SRCCOPY, BBO_IGNORE);
462 }
463#endif
464
465#endif // Q_WS_PM
466
467#ifdef Q_WS_X11
468 extern void *qt_getClipRects(const QRegion &r, int &num); // in qpaintengine_x11.cpp
469 extern QWidgetData* qt_widget_data(QWidget *);
470 QPoint wOffset = qt_qwidget_data(widget)->wrect.topLeft();
471
472 if (widget->window() != window()) {
473 XFreeGC(X11->display, d_ptr->gc);
474 d_ptr->gc = XCreateGC(X11->display, widget->handle(), 0, 0);
475 }
476
477 QRegion wrgn(rgn);
478 if (!wOffset.isNull())
479 wrgn.translate(-wOffset);
480 QRect wbr = wrgn.boundingRect();
481
482 if (wrgn.rectCount() != 1) {
483 int num;
484 XRectangle *rects = (XRectangle *)qt_getClipRects(wrgn, num);
485 XSetClipRectangles(X11->display, d_ptr->gc, 0, 0, rects, num, YXBanded);
486 }
487
488 QRect br = rgn.boundingRect().translated(offset);
489#ifndef QT_NO_MITSHM
490 if (d_ptr->image->xshmpm) {
491 XCopyArea(X11->display, d_ptr->image->xshmpm, widget->handle(), d_ptr->gc,
492 br.x(), br.y(), br.width(), br.height(), wbr.x(), wbr.y());
493 XSync(X11->display, False);
494 } else if (d_ptr->image->xshmimg) {
495 const QImage &src = d->image->image;
496 br = br.intersected(src.rect());
497 XShmPutImage(X11->display, widget->handle(), d_ptr->gc, d_ptr->image->xshmimg,
498 br.x(), br.y(), wbr.x(), wbr.y(), br.width(), br.height(), False);
499 XSync(X11->display, False);
500 } else
501#endif
502 {
503 const QImage &src = d->image->image;
504 br = br.intersected(src.rect());
505 if (src.format() != QImage::Format_RGB32 || widget->x11Info().depth() < 24) {
506 Q_ASSERT(src.depth() >= 16);
507 const QImage sub_src(src.scanLine(br.y()) + br.x() * (uint(src.depth()) / 8),
508 br.width(), br.height(), src.bytesPerLine(), src.format());
509 QX11PixmapData *data = new QX11PixmapData(QPixmapData::PixmapType);
510 data->xinfo = widget->x11Info();
511 data->fromImage(sub_src, Qt::NoOpaqueDetection);
512 QPixmap pm = QPixmap(data);
513 XCopyArea(X11->display, pm.handle(), widget->handle(), d_ptr->gc, 0 , 0 , br.width(), br.height(), wbr.x(), wbr.y());
514 } else {
515 // qpaintengine_x11.cpp
516 extern void qt_x11_drawImage(const QRect &rect, const QPoint &pos, const QImage &image, Drawable hd, GC gc, Display *dpy, Visual *visual, int depth);
517 qt_x11_drawImage(br, wbr.topLeft(), src, widget->handle(), d_ptr->gc, X11->display, (Visual *)widget->x11Info().visual(), widget->x11Info().depth());
518 }
519 }
520
521 if (wrgn.rectCount() != 1)
522 XSetClipMask(X11->display, d_ptr->gc, XNone);
523#endif // FALCON
524
525#ifdef Q_WS_MAC
526
527// qDebug() << "Flushing" << widget << rgn << offset;
528
529// d->image->image.save("flush.png");
530
531 Q_UNUSED(offset);
532 // Get a context for the widget.
533#ifndef QT_MAC_USE_COCOA
534 CGContextRef context;
535 CGrafPtr port = GetWindowPort(qt_mac_window_for(widget));
536 QDBeginCGContext(port, &context);
537#else
538 extern CGContextRef qt_mac_graphicsContextFor(QWidget *);
539 CGContextRef context = qt_mac_graphicsContextFor(widget);
540#endif
541 CGContextSaveGState(context);
542
543 // Flip context.
544 CGContextTranslateCTM(context, 0, widget->height());
545 CGContextScaleCTM(context, 1, -1);
546
547 // Clip to region.
548 const QVector<QRect> &rects = rgn.rects();
549 for (int i = 0; i < rects.size(); ++i) {
550 const QRect &rect = rects.at(i);
551 CGContextAddRect(context, CGRectMake(rect.x(), rect.y(), rect.width(), rect.height()));
552 }
553 CGContextClip(context);
554
555 QRect r = rgn.boundingRect();
556 const CGRect area = CGRectMake(r.x(), r.y(), r.width(), r.height());
557 CGImageRef image = CGBitmapContextCreateImage(d->image->cg);
558 CGImageRef subImage = CGImageCreateWithImageInRect(image, area);
559
560 qt_mac_drawCGImage(context, &area, subImage);
561 CGImageRelease(subImage);
562 CGImageRelease(image);
563
564// CGSize size = { d->image->image.width(), d->image->image.height() };
565// CGLayerRef layer = CGLayerCreateWithContext(d->image->cg, size, 0);
566// CGPoint pt = { 0, 0 };
567// CGContextDrawLayerAtPoint(context, pt, layer);
568// CGLayerRelease(layer);
569
570 // Restore context.
571 CGContextRestoreGState(context);
572#ifndef QT_MAC_USE_COCOA
573 QDEndCGContext(port, &context);
574#endif
575#endif // Q_WS_MAC
576
577#ifdef Q_OS_SYMBIAN
578 Q_UNUSED(widget);
579 Q_UNUSED(rgn);
580 Q_UNUSED(offset);
581#endif
582}
583
584void QRasterWindowSurface::setGeometry(const QRect &rect)
585{
586 QWindowSurface::setGeometry(rect);
587 Q_D(QRasterWindowSurface);
588 d->inSetGeometry = true;
589 if (d->image == 0 || d->image->width() < rect.width() || d->image->height() < rect.height()) {
590#if (defined(Q_WS_X11) && !defined(QT_NO_XRENDER)) || (defined(Q_WS_WIN) && !defined(Q_WS_WINCE))
591#ifndef Q_WS_WIN
592 if (d_ptr->translucentBackground)
593#else
594 if (!qt_widget_private(window())->isOpaque)
595#endif
596 prepareBuffer(QImage::Format_ARGB32_Premultiplied, window());
597 else
598#endif
599 prepareBuffer(QNativeImage::systemFormat(), window());
600 }
601 d->inSetGeometry = false;
602}
603
604// from qwindowsurface.cpp
605extern void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset);
606
607bool QRasterWindowSurface::scroll(const QRegion &area, int dx, int dy)
608{
609#ifdef Q_WS_WIN
610 Q_D(QRasterWindowSurface);
611
612 if (!d->image || !d->image->hdc)
613 return false;
614
615 QRect rect = area.boundingRect();
616 BitBlt(d->image->hdc, rect.x()+dx, rect.y()+dy, rect.width(), rect.height(),
617 d->image->hdc, rect.x(), rect.y(), SRCCOPY);
618
619 return true;
620#else
621 Q_D(QRasterWindowSurface);
622
623 if (!d->image || d->image->image.isNull())
624 return false;
625
626 const QVector<QRect> rects = area.rects();
627 for (int i = 0; i < rects.size(); ++i)
628 qt_scrollRectInImage(d->image->image, rects.at(i), QPoint(dx, dy));
629
630 return true;
631#endif
632}
633
634
635void QRasterWindowSurface::prepareBuffer(QImage::Format format, QWidget *widget)
636{
637 Q_D(QRasterWindowSurface);
638
639 int width = window()->width();
640 int height = window()->height();
641 if (d->image) {
642 width = qMax(d->image->width(), width);
643 height = qMax(d->image->height(), height);
644 }
645
646 if (width == 0 || height == 0) {
647 delete d->image;
648 d->image = 0;
649 return;
650 }
651
652 QNativeImage *oldImage = d->image;
653
654 d->image = new QNativeImage(width, height, format, false, widget);
655
656 if (oldImage && d->inSetGeometry && hasStaticContents()) {
657 // Make sure we use the const version of bits() (no detach).
658 const uchar *src = const_cast<const QImage &>(oldImage->image).bits();
659 uchar *dst = d->image->image.bits();
660
661 const int srcBytesPerLine = oldImage->image.bytesPerLine();
662 const int dstBytesPerLine = d->image->image.bytesPerLine();
663 const int bytesPerPixel = oldImage->image.depth() >> 3;
664
665 QRegion staticRegion(staticContents());
666 // Make sure we're inside the boundaries of the old image.
667 staticRegion &= QRect(0, 0, oldImage->image.width(), oldImage->image.height());
668 const QVector<QRect> &rects = staticRegion.rects();
669 const QRect *srcRect = rects.constData();
670
671 // Copy the static content of the old image into the new one.
672 int numRectsLeft = rects.size();
673 do {
674 const int bytesOffset = srcRect->x() * bytesPerPixel;
675 const int dy = srcRect->y();
676
677 // Adjust src and dst to point to the right offset.
678 const uchar *s = src + dy * srcBytesPerLine + bytesOffset;
679 uchar *d = dst + dy * dstBytesPerLine + bytesOffset;
680 const int numBytes = srcRect->width() * bytesPerPixel;
681
682 int numScanLinesLeft = srcRect->height();
683 do {
684 ::memcpy(d, s, numBytes);
685 d += dstBytesPerLine;
686 s += srcBytesPerLine;
687 } while (--numScanLinesLeft);
688
689 ++srcRect;
690 } while (--numRectsLeft);
691 }
692
693 delete oldImage;
694}
695
696QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.