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

Last change on this file since 712 was 708, checked in by Dmitry A. Kuminov, 16 years ago

gui: Use the fastest GPI matrix transformation for mirroring the image when drawing windows using the old GpiDrawBits() approach.

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