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

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

gui: OS/2: In Dive mode, the screen would get corrupted if the application created a child window with a real HWND (as e.g. smplayer does). Fixes #163.

File size: 22.1 KB
RevLine 
[708]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** 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 [email protected].
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();
[745]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)
[708]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 // Note: target is inclusive-inclusive, source is inclusive-exclusive
251 POINTL ptls[] = { { wbr.left(), wh - wbr.bottom() - 1 },
252 { wbr.right(), wh - wbr.top() - 1 },
253 { br.left(), ih - br.bottom() - 1 },
254 { br.right() + 1, ih - br.top() } };
255#if 0
256 qDebug() << "QRasterWindowSurface::flush:" << widget << "ptls"
257 << ptls[0].x << ptls[0].y << ptls[1].x << ptls[1].y
258 << ptls[2].x << ptls[2].y << ptls[3].x << ptls[3].y
259 << "img.size" << img.size() << "img.bits" << img.bits();
260#endif
261 GpiDrawBits(wps, (PVOID) img.bits(), (PBITMAPINFO2) &bmh, 4, ptls,
262 ROP_SRCCOPY, BBO_IGNORE);
263
264#elif QT_BITMAP_MIRROR == 2
265
266 // Use GpiEnableYInversion to flip the y axis. This is almost as fast as
267 // QT_BITMAP_MIRROR == 3. "Almost" is probably due to some extra overhead
268 // on the method call compared to the direct matrix manipulation.
269
270 br.translate(offset);
271
272 // make sure br doesn't exceed the backing storage size (it may happen
273 // during resize & move due to the different event order)
274 br = br.intersected(QRect(0, 0, d->image->width(), d->image->height()));
275
276 QPoint wOffset = qt_qwidget_data(widget)->wrect.topLeft();
[745]277 // note that we remove offset from wbr because the widget's HPS has a proper
278 // origin already that includes this offset (which is in fact a position of
279 // the widget relative to its top-level parent)
[708]280 QRect wbr = br.translated(-offset - wOffset);
281
282 BITMAPINFOHEADER2 bmh;
283 memset(&bmh, 0, sizeof(BITMAPINFOHEADER2));
284 bmh.cbFix = sizeof(BITMAPINFOHEADER2);
285 bmh.cPlanes = 1;
286 bmh.cBitCount = 32; // @todo support 8-bit indexed colors?
287 bmh.cx = d->image->width();
288 bmh.cy = d->image->height();
289
290 // Note: target is inclusive-inclusive, source is inclusive-exclusive
291 POINTL ptls[] = { { wbr.left(), wbr.top() },
292 { wbr.right(), wbr.bottom() },
293 { br.left(), br.top() },
294 { br.right() + 1, br.bottom() + 1 } };
295#if 0
296 qDebug() << "QRasterWindowSurface::flush:" << widget << "ptls"
297 << ptls[0].x << ptls[0].y << ptls[1].x << ptls[1].y
298 << ptls[2].x << ptls[2].y << ptls[3].x << ptls[3].y
299 << "img.size" << d->image->size() << "img.bits" << d->image->bits();
300#endif
301
302 // setup the Y coordinate inversion (this seems to use the same GPI matrix
303 // transformation internally as we do in method 3 below)
304 LONG oldInversion = GpiQueryYInversion(wps);
305 GpiEnableYInversion(wps, widget->height() - 1);
306
[719]307 GpiDrawBits(wps, (PVOID) const_cast<const QImage &>(d->image->image).bits(),
308 (PBITMAPINFO2) &bmh, 4, ptls, ROP_SRCCOPY, BBO_IGNORE);
[708]309
310 GpiEnableYInversion(wps, oldInversion);
311
312#ifndef QT_NO_DEBUG
313 // for debug flushing
314 const QImage img = d->image->image;
315#endif
316
317#elif QT_BITMAP_MIRROR == 3
318
319 // Use the reflection + transformation matrix to flip the y axis.
320 // This is proven to be much faster than manual image flipping on the real
321 // video hardware as it probably involves some hardware acceleration in
322 // the video driver.
323
324 MATRIXLF m;
325 m.fxM11 = MAKEFIXED(1, 0);
326 m.fxM12 = 0;
327 m.lM13 = 0;
328 m.fxM21 = 0;
329 m.fxM22 = MAKEFIXED(-1, 0);
330 m.lM23 = 0;
331 m.lM31 = 0;
332 m.lM32 = widget->height() - 1;
333 GpiSetDefaultViewMatrix(wps, 8, &m, TRANSFORM_REPLACE);
334
335 br.translate(offset);
336
337 // make sure br doesn't exceed the backing storage size (it may happen
338 // during resize & move due to the different event order)
339 br = br.intersected(QRect(0, 0, d->image->width(), d->image->height()));
340
341 QPoint wOffset = qt_qwidget_data(widget)->wrect.topLeft();
[745]342 // note that we remove offset from wbr because the widget's HPS has a proper
343 // origin already that includes this offset (which is in fact a position of
344 // the widget relative to its top-level parent)
[708]345 QRect wbr = br.translated(-offset - wOffset);
346
347 BITMAPINFOHEADER2 bmh;
348 memset(&bmh, 0, sizeof(BITMAPINFOHEADER2));
349 bmh.cbFix = sizeof(BITMAPINFOHEADER2);
350 bmh.cPlanes = 1;
351 bmh.cBitCount = 32; // @todo support 8-bit indexed colors?
352 bmh.cx = d->image->width();
353 bmh.cy = d->image->height();
354
355 // Note: target is inclusive-inclusive, source is inclusive-exclusive
356 POINTL ptls[] = { { wbr.left(), wbr.top() },
357 { wbr.right(), wbr.bottom() },
358 { br.left(), br.top() },
359 { br.right() + 1, br.bottom() + 1 } };
[719]360 GpiDrawBits(wps, (PVOID) const_cast<const QImage &>(d->image->image).bits(),
361 (PBITMAPINFO2) &bmh, 4, ptls, ROP_SRCCOPY, BBO_IGNORE);
[708]362
363#ifndef QT_NO_DEBUG
364 // for debug flushing
365 const QImage img = d->image->image;
366#endif
367
368#else // if QT_BITMAP_MIRROR == 3
369# error "QT_BITMAP_MIRROR must be 1, 2 or 3"
370#endif
371
372 widget->releasePS(wps);
373
374#ifdef QT_LOG_BLITSPEED
375 ticks = fibGetMsCount() - ticks;
376 qt_total_blit_ms += ticks;
377 qt_total_blit_pixels += br.width() * br.height();
378#endif
379
380#ifndef QT_NO_DEBUG
381 static bool flush = !qgetenv("QT_FLUSH_WINDOWSURFACE").isEmpty();
382 if (flush) {
383 HPS dps = qt_display_ps();
384 RECTL rcl = { 10, 50, 10 + img.width() + 2, 50 + img.height() + 2 };
385 WinDrawBorder(dps, &rcl, 1, 1, CLR_BLACK, CLR_BLACK, 0);
386 POINTL ptls[] = { { 11, 51, },
387 { 11 + img.width() - 1, 51 + img.height() - 1 },
388 { 0, 0 },
389 { img.width(), img.height() } };
390 GpiDrawBits(dps, (PVOID) img.bits(), (PBITMAPINFO2) &bmh, 4, ptls,
391 ROP_SRCCOPY, BBO_IGNORE);
392 }
393#endif
394
395#endif // Q_WS_PM
396
397#ifdef Q_WS_X11
398 extern void *qt_getClipRects(const QRegion &r, int &num); // in qpaintengine_x11.cpp
399 extern QWidgetData* qt_widget_data(QWidget *);
400 QPoint wOffset = qt_qwidget_data(widget)->wrect.topLeft();
401
402 if (widget->window() != window()) {
403 XFreeGC(X11->display, d_ptr->gc);
404 d_ptr->gc = XCreateGC(X11->display, widget->handle(), 0, 0);
405 }
406
407 QRegion wrgn(rgn);
408 if (!wOffset.isNull())
409 wrgn.translate(-wOffset);
410 QRect wbr = wrgn.boundingRect();
411
412 if (wrgn.rectCount() != 1) {
413 int num;
414 XRectangle *rects = (XRectangle *)qt_getClipRects(wrgn, num);
415 XSetClipRectangles(X11->display, d_ptr->gc, 0, 0, rects, num, YXBanded);
416 }
417
418 QRect br = rgn.boundingRect().translated(offset);
419#ifndef QT_NO_MITSHM
420 if (d_ptr->image->xshmpm) {
421 XCopyArea(X11->display, d_ptr->image->xshmpm, widget->handle(), d_ptr->gc,
422 br.x(), br.y(), br.width(), br.height(), wbr.x(), wbr.y());
423 XSync(X11->display, False);
424 } else if (d_ptr->image->xshmimg) {
425 const QImage &src = d->image->image;
426 br = br.intersected(src.rect());
427 XShmPutImage(X11->display, widget->handle(), d_ptr->gc, d_ptr->image->xshmimg,
428 br.x(), br.y(), wbr.x(), wbr.y(), br.width(), br.height(), False);
429 XSync(X11->display, False);
430 } else
431#endif
432 {
433 const QImage &src = d->image->image;
434 br = br.intersected(src.rect());
435 if (src.format() != QImage::Format_RGB32 || widget->x11Info().depth() < 24) {
436 Q_ASSERT(src.depth() >= 16);
437 const QImage sub_src(src.scanLine(br.y()) + br.x() * (uint(src.depth()) / 8),
438 br.width(), br.height(), src.bytesPerLine(), src.format());
439 QX11PixmapData *data = new QX11PixmapData(QPixmapData::PixmapType);
440 data->xinfo = widget->x11Info();
441 data->fromImage(sub_src, Qt::NoOpaqueDetection);
442 QPixmap pm = QPixmap(data);
443 XCopyArea(X11->display, pm.handle(), widget->handle(), d_ptr->gc, 0 , 0 , br.width(), br.height(), wbr.x(), wbr.y());
444 } else {
445 // qpaintengine_x11.cpp
446 extern void qt_x11_drawImage(const QRect &rect, const QPoint &pos, const QImage &image, Drawable hd, GC gc, Display *dpy, Visual *visual, int depth);
447 qt_x11_drawImage(br, wbr.topLeft(), src, widget->handle(), d_ptr->gc, X11->display, (Visual *)widget->x11Info().visual(), widget->x11Info().depth());
448 }
449 }
450
451 if (wrgn.rectCount() != 1)
452 XSetClipMask(X11->display, d_ptr->gc, XNone);
453#endif // FALCON
454
455#ifdef Q_WS_MAC
456
457// qDebug() << "Flushing" << widget << rgn << offset;
458
459// d->image->image.save("flush.png");
460
461 Q_UNUSED(offset);
462 // Get a context for the widget.
463#ifndef QT_MAC_USE_COCOA
464 CGContextRef context;
465 CGrafPtr port = GetWindowPort(qt_mac_window_for(widget));
466 QDBeginCGContext(port, &context);
467#else
468 extern CGContextRef qt_mac_graphicsContextFor(QWidget *);
469 CGContextRef context = qt_mac_graphicsContextFor(widget);
470#endif
471 CGContextSaveGState(context);
472
473 // Flip context.
474 CGContextTranslateCTM(context, 0, widget->height());
475 CGContextScaleCTM(context, 1, -1);
476
477 // Clip to region.
478 const QVector<QRect> &rects = rgn.rects();
479 for (int i = 0; i < rects.size(); ++i) {
480 const QRect &rect = rects.at(i);
481 CGContextAddRect(context, CGRectMake(rect.x(), rect.y(), rect.width(), rect.height()));
482 }
483 CGContextClip(context);
484
485 QRect r = rgn.boundingRect();
486 const CGRect area = CGRectMake(r.x(), r.y(), r.width(), r.height());
487 CGImageRef image = CGBitmapContextCreateImage(d->image->cg);
488 CGImageRef subImage = CGImageCreateWithImageInRect(image, area);
489
490 qt_mac_drawCGImage(context, &area, subImage);
491 CGImageRelease(subImage);
492 CGImageRelease(image);
493
494// CGSize size = { d->image->image.width(), d->image->image.height() };
495// CGLayerRef layer = CGLayerCreateWithContext(d->image->cg, size, 0);
496// CGPoint pt = { 0, 0 };
497// CGContextDrawLayerAtPoint(context, pt, layer);
498// CGLayerRelease(layer);
499
500 // Restore context.
501 CGContextRestoreGState(context);
502#ifndef QT_MAC_USE_COCOA
503 QDEndCGContext(port, &context);
504#else
505 CGContextFlush(context);
506#endif
507#endif
508
509#ifdef Q_OS_SYMBIAN
510 Q_UNUSED(widget);
511 Q_UNUSED(rgn);
512 Q_UNUSED(offset);
513#endif
514}
515
516void QRasterWindowSurface::setGeometry(const QRect &rect)
517{
518 QWindowSurface::setGeometry(rect);
519 Q_D(QRasterWindowSurface);
520 d->inSetGeometry = true;
521 if (d->image == 0 || d->image->width() < rect.width() || d->image->height() < rect.height()) {
522#if (defined(Q_WS_X11) && !defined(QT_NO_XRENDER)) || (defined(Q_WS_WIN) && !defined(Q_WS_WINCE))
523#ifndef Q_WS_WIN
524 if (d_ptr->translucentBackground)
525#else
526 if (!qt_widget_private(window())->isOpaque)
527#endif
528 prepareBuffer(QImage::Format_ARGB32_Premultiplied, window());
529 else
530#endif
531 prepareBuffer(QNativeImage::systemFormat(), window());
532 }
533 d->inSetGeometry = false;
534}
535
536// from qwindowsurface.cpp
537extern void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset);
538
539bool QRasterWindowSurface::scroll(const QRegion &area, int dx, int dy)
540{
541#ifdef Q_WS_WIN
542 Q_D(QRasterWindowSurface);
543
544 if (!d->image || !d->image->hdc)
545 return false;
546
547 QRect rect = area.boundingRect();
548 BitBlt(d->image->hdc, rect.x()+dx, rect.y()+dy, rect.width(), rect.height(),
549 d->image->hdc, rect.x(), rect.y(), SRCCOPY);
550
551 return true;
552#else
553 Q_D(QRasterWindowSurface);
554
555 if (!d->image || d->image->image.isNull())
556 return false;
557
558 const QVector<QRect> rects = area.rects();
559 for (int i = 0; i < rects.size(); ++i)
560 qt_scrollRectInImage(d->image->image, rects.at(i), QPoint(dx, dy));
561
562 return true;
563#endif
564}
565
566
567void QRasterWindowSurface::prepareBuffer(QImage::Format format, QWidget *widget)
568{
569 Q_D(QRasterWindowSurface);
570
571 int width = window()->width();
572 int height = window()->height();
573 if (d->image) {
574 width = qMax(d->image->width(), width);
575 height = qMax(d->image->height(), height);
576 }
577
578 if (width == 0 || height == 0) {
579 delete d->image;
580 d->image = 0;
581 return;
582 }
583
584 QNativeImage *oldImage = d->image;
585
586 d->image = new QNativeImage(width, height, format, false, widget);
587
588 if (oldImage && d->inSetGeometry && hasStaticContents()) {
589 // Make sure we use the const version of bits() (no detach).
590 const uchar *src = const_cast<const QImage &>(oldImage->image).bits();
591 uchar *dst = d->image->image.bits();
592
593 const int srcBytesPerLine = oldImage->image.bytesPerLine();
594 const int dstBytesPerLine = d->image->image.bytesPerLine();
595 const int bytesPerPixel = oldImage->image.depth() >> 3;
596
597 QRegion staticRegion(staticContents());
598 // Make sure we're inside the boundaries of the old image.
599 staticRegion &= QRect(0, 0, oldImage->image.width(), oldImage->image.height());
600 const QVector<QRect> &rects = staticRegion.rects();
601 const QRect *srcRect = rects.constData();
602
603 // Copy the static content of the old image into the new one.
604 int numRectsLeft = rects.size();
605 do {
606 const int bytesOffset = srcRect->x() * bytesPerPixel;
607 const int dy = srcRect->y();
608
609 // Adjust src and dst to point to the right offset.
610 const uchar *s = src + dy * srcBytesPerLine + bytesOffset;
611 uchar *d = dst + dy * dstBytesPerLine + bytesOffset;
612 const int numBytes = srcRect->width() * bytesPerPixel;
613
614 int numScanLinesLeft = srcRect->height();
615 do {
616 ::memcpy(d, s, numBytes);
617 d += dstBytesPerLine;
618 s += srcBytesPerLine;
619 } while (--numScanLinesLeft);
620
621 ++srcRect;
622 } while (--numRectsLeft);
623 }
624
625 delete oldImage;
626}
627
628QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.