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

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

gui: Implemented new blit mirroring method using undocumented GpiEnableYInversion() (QImage.mirrored() is still the default as it seems to show better performance, see #101 for more information).

File size: 19.5 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
4** Contact: Qt Software Information ([email protected])
5**
6** This file is part of the QtGui module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial Usage
10** Licensees holding valid Qt Commercial licenses may use this file in
11** accordance with the Qt Commercial License Agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and Nokia.
14**
15** GNU Lesser General Public License Usage
16** Alternatively, this file may be used under the terms of the GNU Lesser
17** General Public License version 2.1 as published by the Free Software
18** Foundation and appearing in the file LICENSE.LGPL included in the
19** packaging of this file. Please review the following information to
20** ensure the GNU Lesser General Public License version 2.1 requirements
21** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
22**
23** In addition, as a special exception, Nokia gives you certain
24** additional rights. These rights are described in the Nokia Qt LGPL
25** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
26** 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 are unsure which license is appropriate for your use, please
37** contact the sales department 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 <qt_windows.h>
47#endif
48
49#include <QtGui/qpaintdevice.h>
50#include <QtGui/qwidget.h>
51
52#include "private/qwindowsurface_raster_p.h"
53#include "private/qnativeimage_p.h"
54#include "private/qwidget_p.h"
55
56#ifdef Q_WS_X11
57#include "private/qpixmap_x11_p.h"
58#include "private/qt_x11_p.h"
59#include "private/qwidget_p.h"
60#include "qx11info_x11.h"
61#endif
62#include "private/qdrawhelper_p.h"
63
64#ifdef Q_WS_MAC
65#include <private/qt_cocoa_helpers_mac_p.h>
66#endif
67
68#if defined(Q_WS_PM) && defined(QT_LOG_BLITSPEED)
69#include <InnotekLIBC/FastInfoBlocks.h>
70#endif
71
72#if defined(Q_WS_PM)
73LONG APIENTRY GpiQueryYInversion(HPS hps);
74BOOL APIENTRY GpiEnableYInversion(HPS hps, LONG lHeight);
75#define QT_BITMAP_MIRROR 1 // 1 = QImage.mirrored()
76 // 2 = GpiEnableYInversion()
77 // 3 = GPI Matrix
78#endif
79
80QT_BEGIN_NAMESPACE
81
82#ifdef Q_WS_WIN
83PtrUpdateLayeredWindowIndirect ptrUpdateLayeredWindowIndirect;
84#endif
85
86#if defined(Q_WS_PM) && defined(QT_LOG_BLITSPEED)
87unsigned long long qt_total_blit_ms = 0;
88unsigned long long qt_total_blit_pixels = 0;
89#endif
90
91class QRasterWindowSurfacePrivate
92{
93public:
94 QNativeImage *image;
95
96#ifdef Q_WS_X11
97 GC gc;
98#ifndef QT_NO_XRENDER
99 uint translucentBackground : 1;
100#endif
101#endif
102#if defined(Q_WS_WIN) && !defined(Q_OS_WINCE)
103 uint canUseLayeredWindow : 1;
104#endif
105 uint inSetGeometry : 1;
106};
107
108QRasterWindowSurface::QRasterWindowSurface(QWidget *window)
109 : QWindowSurface(window), d_ptr(new QRasterWindowSurfacePrivate)
110{
111#ifdef Q_WS_X11
112 d_ptr->gc = XCreateGC(X11->display, window->handle(), 0, 0);
113#ifndef QT_NO_XRENDER
114 d_ptr->translucentBackground = X11->use_xrender
115 && window->x11Info().depth() == 32;
116#endif
117#endif
118#if defined(Q_WS_WIN) && !defined(Q_OS_WINCE)
119 d_ptr->canUseLayeredWindow = ptrUpdateLayeredWindowIndirect
120 && (qt_widget_private(window)->data.window_flags & Qt::FramelessWindowHint);
121#endif
122 d_ptr->image = 0;
123 d_ptr->inSetGeometry = false;
124 setStaticContentsSupport(true);
125}
126
127
128QRasterWindowSurface::~QRasterWindowSurface()
129{
130#ifdef Q_WS_X11
131 XFreeGC(X11->display, d_ptr->gc);
132#endif
133 if (d_ptr->image)
134 delete d_ptr->image;
135
136 delete d_ptr;
137}
138
139
140QPaintDevice *QRasterWindowSurface::paintDevice()
141{
142 return &d_ptr->image->image;
143}
144
145void QRasterWindowSurface::beginPaint(const QRegion &rgn)
146{
147#if (defined(Q_WS_X11) && !defined(QT_NO_XRENDER)) || (defined(Q_WS_WIN) && !defined(Q_OS_WINCE))
148 if (!qt_widget_private(window())->isOpaque) {
149#if defined(Q_WS_WIN) && !defined(Q_OS_WINCE)
150 if (d_ptr->image->image.format() != QImage::Format_ARGB32_Premultiplied
151 && d_ptr->canUseLayeredWindow)
152 prepareBuffer(QImage::Format_ARGB32_Premultiplied, window());
153#endif
154 QPainter p(&d_ptr->image->image);
155 p.setCompositionMode(QPainter::CompositionMode_Source);
156 const QVector<QRect> rects = rgn.rects();
157 const QColor blank = Qt::transparent;
158 for (QVector<QRect>::const_iterator it = rects.begin(); it != rects.end(); ++it) {
159 p.fillRect(*it, blank);
160 }
161 }
162#endif
163#if defined(Q_OS_WINCE)
164 Q_UNUSED(rgn);
165#endif
166}
167
168void QRasterWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoint &offset)
169{
170 Q_D(QRasterWindowSurface);
171
172 // Not ready for painting yet, bail out. This can happen in
173 // QWidget::create_sys()
174 if (!d->image)
175 return;
176
177#ifdef Q_WS_WIN
178 QRect br = rgn.boundingRect();
179
180#ifndef Q_OS_WINCE
181 if (!qt_widget_private(window())->isOpaque && d->canUseLayeredWindow) {
182 QRect r = window()->frameGeometry();
183 QPoint frameOffset = qt_widget_private(window())->frameStrut().topLeft();
184 QRect dirtyRect = br.translated(offset + frameOffset);
185
186 SIZE size = {r.width(), r.height()};
187 POINT ptDst = {r.x(), r.y()};
188 POINT ptSrc = {0, 0};
189 Q_BLENDFUNCTION blend = {AC_SRC_OVER, 0, (int)(255.0 * window()->windowOpacity()), Q_AC_SRC_ALPHA};
190 RECT dirty = {dirtyRect.x(), dirtyRect.y(),
191 dirtyRect.x() + dirtyRect.width(), dirtyRect.y() + dirtyRect.height()};
192 Q_UPDATELAYEREDWINDOWINFO info = {sizeof(info), NULL, &ptDst, &size, d->image->hdc, &ptSrc, 0, &blend, Q_ULW_ALPHA, &dirty};
193
194 (*ptrUpdateLayeredWindowIndirect)(window()->internalWinId(), &info);
195 } else
196#endif
197 {
198 QPoint wOffset = qt_qwidget_data(widget)->wrect.topLeft();
199
200 HDC widget_dc = widget->getDC();
201
202 QRect wbr = br.translated(-wOffset);
203 BitBlt(widget_dc, wbr.x(), wbr.y(), wbr.width(), wbr.height(),
204 d->image->hdc, br.x() + offset.x(), br.y() + offset.y(), SRCCOPY);
205 widget->releaseDC(widget_dc);
206 }
207
208#ifndef QT_NO_DEBUG
209 static bool flush = !qgetenv("QT_FLUSH_WINDOWSURFACE").isEmpty();
210 if (flush) {
211 SelectObject(qt_win_display_dc(), GetStockObject(BLACK_BRUSH));
212 Rectangle(qt_win_display_dc(), 0, 0, d->image->width() + 2, d->image->height() + 2);
213 BitBlt(qt_win_display_dc(), 1, 1, d->image->width(), d->image->height(),
214 d->image->hdc, 0, 0, SRCCOPY);
215 }
216#endif
217
218#endif
219
220#ifdef Q_WS_PM
221 QRect br = rgn.boundingRect();
222
223 HPS wps = widget->getPS();
224
225#if 0
226 qDebug("QRasterWindowSurface::flush: [%s] wps %x br %d,%d/%d,%d",
227 qWidgetName(widget).toUtf8().constData(), (unsigned int)wps,
228 br.x(), br.y(), br.width(), br.height());
229#endif
230
231#ifdef QT_LOG_BLITSPEED
232 unsigned long ticks = fibGetMsCount();
233#endif
234
235#if QT_BITMAP_MIRROR == 1
236
237 // flip the image vertically for PM
238 QImage img = d->image->image.mirrored();
239
240 QPoint wOffset = qt_qwidget_data(widget)->wrect.topLeft();
241 QRect wbr = br.translated(-wOffset);
242
243 br.translate(offset);
244
245 BITMAPINFOHEADER2 bmh;
246 memset(&bmh, 0, sizeof(BITMAPINFOHEADER2));
247 bmh.cbFix = sizeof(BITMAPINFOHEADER2);
248 bmh.cPlanes = 1;
249 bmh.cBitCount = 32; // @todo support 8-bit indexed colors?
250 bmh.cx = img.width();
251 bmh.cy = img.height();
252
253 int wh = widget->height();
254 int ih = img.height();
255
256 // Note: target is inclusive-inclusive, source is inclusive-exclusive
257 POINTL ptls[] = { { wbr.left(), wh - wbr.bottom() - 1 },
258 { wbr.right(), wh - wbr.top() - 1 },
259 { br.left(), ih - br.bottom() - 1 },
260 { br.right() + 1, ih - br.top() } };
261#if 0
262 qDebug("QRasterWindowSurface::flush: [%s] ptls %ld,%ld-%ld,%ld %ld,%ld-%ld,%ld",
263 qWidgetName(widget).toUtf8().constData(),
264 ptls[0].x, ptls[0].y, ptls[1].x, ptls[1].y,
265 ptls[2].x, ptls[2].y, ptls[3].x, ptls[3].y);
266#endif
267 GpiDrawBits(wps, (PVOID) img.bits(), (PBITMAPINFO2) &bmh, 4, ptls,
268 ROP_SRCCOPY, BBO_IGNORE);
269
270#elif QT_BITMAP_MIRROR == 2
271
272 QPoint wOffset = qt_qwidget_data(widget)->wrect.topLeft();
273 QRect wbr = br.translated(-wOffset);
274
275 br.translate(offset);
276
277 BITMAPINFOHEADER2 bmh;
278 memset(&bmh, 0, sizeof(BITMAPINFOHEADER2));
279 bmh.cbFix = sizeof(BITMAPINFOHEADER2);
280 bmh.cPlanes = 1;
281 bmh.cBitCount = 32; // @todo support 8-bit indexed colors?
282 bmh.cx = d->image->width();
283 bmh.cy = d->image->height();
284
285 // Note: target is inclusive-inclusive, source is inclusive-exclusive
286 POINTL ptls[] = { { wbr.left(), wbr.top() },
287 { wbr.right(), wbr.bottom() },
288 { br.left(), br.top() },
289 { br.right() + 1, br.bottom() + 1 } };
290#if 0
291 qDebug("QRasterWindowSurface::flush: [%s] ptls %ld,%ld-%ld,%ld %ld,%ld-%ld,%ld",
292 qWidgetName(widget).toUtf8().constData(),
293 ptls[0].x, ptls[0].y, ptls[1].x, ptls[1].y,
294 ptls[2].x, ptls[2].y, ptls[3].x, ptls[3].y);
295#endif
296
297 // setup the Y coordinate inversion (this seems to use the same GPI matrix
298 // transformation internally as we do in method 3 below)
299 LONG oldInversion = GpiQueryYInversion(wps);
300 GpiEnableYInversion(wps, widget->height() - 1);
301
302 GpiDrawBits(wps, (PVOID) d->image->image.bits(), (PBITMAPINFO2) &bmh,
303 4, ptls, ROP_SRCCOPY, BBO_IGNORE);
304
305 GpiEnableYInversion(wps, oldInversion);
306
307#elif QT_BITMAP_MIRROR == 3
308
309 // use the reflection + transformation matrix to flip the y axis.
310 // This should be slower than flipping the image ourselves (unless this
311 // particular matrix is recognized by the driver which then enters some
312 // special mode that doesn't require any flipping at all but uses the
313 // image as is) hence disabled for now.
314 // @todo check if it's really slower than flipping the image bits instead
315 // @todo I guess we can use DIVE here; check it too
316 MATRIXLF m;
317 m.fxM11 = MAKEFIXED(1, 0);
318 m.fxM12 = 0;
319 m.lM13 = 0;
320 m.fxM21 = 0;
321 m.fxM22 = MAKEFIXED(-1, 0);
322 m.lM23 = 0;
323 m.lM31 = 0;
324 m.lM32 = widget->height() - 1;
325 GpiSetDefaultViewMatrix(wps, 8, &m, TRANSFORM_REPLACE);
326
327 QPoint wOffset = qt_qwidget_data(widget)->wrect.topLeft();
328 QRect wbr = br.translated(-wOffset);
329
330 br.translate(offset);
331
332 BITMAPINFOHEADER2 bmh;
333 memset(&bmh, 0, sizeof(BITMAPINFOHEADER2));
334 bmh.cbFix = sizeof(BITMAPINFOHEADER2);
335 bmh.cPlanes = 1;
336 bmh.cBitCount = 32; // @todo support 8-bit indexed colors?
337 bmh.cx = d->image->width();
338 bmh.cy = d->image->height();
339
340 // Note: target is inclusive-inclusive, source is inclusive-exclusive
341 POINTL ptls[] = { { wbr.left(), wbr.top() },
342 { wbr.right(), wbr.bottom() },
343 { br.left(), br.top() },
344 { br.right() + 1, br.bottom() + 1 } };
345 GpiDrawBits(wps, (PVOID) d->image->image.bits(), (PBITMAPINFO2) &bmh, 4, ptls,
346 ROP_SRCCOPY, BBO_IGNORE);
347
348#ifndef QT_NO_DEBUG
349 // for debug flushing
350 const QImage img = d->image->image;
351#endif
352
353#else // if QT_BITMAP_MIRROR == 3
354# error "QT_BITMAP_MIRROR must be 1, 2 or 3"
355#endif
356
357 widget->releasePS(wps);
358
359#ifdef QT_LOG_BLITSPEED
360 ticks = fibGetMsCount() - ticks;
361 qt_total_blit_ms += ticks;
362 qt_total_blit_pixels += br.width() * br.height();
363#endif
364
365#ifndef QT_NO_DEBUG
366 static bool flush = !qgetenv("QT_FLUSH_WINDOWSURFACE").isEmpty();
367 if (flush) {
368 HPS dps = qt_display_ps();
369 RECTL rcl = { 10, 50, 10 + img.width() + 2, 50 + img.height() + 2 };
370 WinDrawBorder(dps, &rcl, 1, 1, CLR_BLACK, CLR_BLACK, 0);
371 POINTL ptls[] = { { 11, 51, },
372 { 11 + img.width() - 1, 51 + img.height() - 1 },
373 { 0, 0 },
374 { img.width(), img.height() } };
375 GpiDrawBits(dps, (PVOID) img.bits(), (PBITMAPINFO2) &bmh, 4, ptls,
376 ROP_SRCCOPY, BBO_IGNORE);
377 }
378#endif
379
380#endif // Q_WS_PM
381
382#ifdef Q_WS_X11
383 extern void *qt_getClipRects(const QRegion &r, int &num); // in qpaintengine_x11.cpp
384 extern QWidgetData* qt_widget_data(QWidget *);
385 QPoint wOffset = qt_qwidget_data(widget)->wrect.topLeft();
386
387 if (widget->window() != window()) {
388 XFreeGC(X11->display, d_ptr->gc);
389 d_ptr->gc = XCreateGC(X11->display, widget->handle(), 0, 0);
390 }
391
392 QRegion wrgn(rgn);
393 if (!wOffset.isNull())
394 wrgn.translate(-wOffset);
395 QRect wbr = wrgn.boundingRect();
396
397 int num;
398 XRectangle *rects = (XRectangle *)qt_getClipRects(wrgn, num);
399 XSetClipRectangles(X11->display, d_ptr->gc, 0, 0, rects, num, YXBanded);
400
401 QRect br = rgn.boundingRect().translated(offset);
402#ifndef QT_NO_MITSHM
403 if (d_ptr->image->xshmpm) {
404 XCopyArea(X11->display, d_ptr->image->xshmpm, widget->handle(), d_ptr->gc,
405 br.x(), br.y(), br.width(), br.height(), wbr.x(), wbr.y());
406 XSync(X11->display, False);
407 } else
408#endif
409 {
410 const QImage &src = d->image->image;
411 br = br.intersected(src.rect());
412 if (src.format() != QImage::Format_RGB32) {
413 QX11PixmapData *data = new QX11PixmapData(QPixmapData::PixmapType);
414 data->xinfo = widget->x11Info();
415 data->fromImage(src, Qt::AutoColor);
416 QPixmap pm = QPixmap(data);
417 XCopyArea(X11->display, pm.handle(), widget->handle(), d_ptr->gc, br.x() , br.y() , br.width(), br.height(), wbr.x(), wbr.y());
418 } else {
419 // qpaintengine_x11.cpp
420 extern void qt_x11_drawImage(const QRect &rect, const QPoint &pos, const QImage &image, Drawable hd, GC gc, Display *dpy, Visual *visual, int depth);
421 qt_x11_drawImage(br, wbr.topLeft(), src, widget->handle(), d_ptr->gc, X11->display, (Visual *)widget->x11Info().visual(), widget->x11Info().depth());
422 }
423 }
424#endif // FALCON
425
426#ifdef Q_WS_MAC
427
428// qDebug() << "Flushing" << widget << rgn << offset;
429
430// d->image->image.save("flush.png");
431
432 // Get a context for the widget.
433#ifndef QT_MAC_USE_COCOA
434 CGContextRef context;
435 CGrafPtr port = GetWindowPort(qt_mac_window_for(widget));
436 QDBeginCGContext(port, &context);
437#else
438 extern CGContextRef qt_mac_graphicsContextFor(QWidget *);
439 CGContextRef context = qt_mac_graphicsContextFor(widget);
440#endif
441 CGContextSaveGState(context);
442
443 // Flip context.
444 CGContextTranslateCTM(context, 0, widget->height());
445 CGContextScaleCTM(context, 1, -1);
446
447 // Clip to region.
448 const QVector<QRect> &rects = rgn.rects();
449 for (int i = 0; i < rects.size(); ++i) {
450 const QRect &rect = rects.at(i);
451 CGContextAddRect(context, CGRectMake(rect.x(), rect.y(), rect.width(), rect.height()));
452 }
453 CGContextClip(context);
454
455 QRect r = rgn.boundingRect();
456 const CGRect area = CGRectMake(r.x(), r.y(), r.width(), r.height());
457 CGImageRef image = CGBitmapContextCreateImage(d->image->cg);
458 CGImageRef subImage = CGImageCreateWithImageInRect(image, area);
459
460 qt_mac_drawCGImage(context, &area, subImage);
461 CGImageRelease(subImage);
462 CGImageRelease(image);
463
464// CGSize size = { d->image->image.width(), d->image->image.height() };
465// CGLayerRef layer = CGLayerCreateWithContext(d->image->cg, size, 0);
466// CGPoint pt = { 0, 0 };
467// CGContextDrawLayerAtPoint(context, pt, layer);
468// CGLayerRelease(layer);
469
470 // Restore context.
471 CGContextRestoreGState(context);
472#ifndef QT_MAC_USE_COCOA
473 QDEndCGContext(port, &context);
474#else
475 CGContextFlush(context);
476#endif
477#endif
478}
479
480void QRasterWindowSurface::setGeometry(const QRect &rect)
481{
482 QWindowSurface::setGeometry(rect);
483 Q_D(QRasterWindowSurface);
484 d->inSetGeometry = true;
485 if (d->image == 0 || d->image->width() < rect.width() || d->image->height() < rect.height()) {
486#if (defined(Q_WS_X11) && !defined(QT_NO_XRENDER)) || (defined(Q_WS_WIN) && !defined(Q_OS_WINCE))
487#ifndef Q_WS_WIN
488 if (d_ptr->translucentBackground)
489#else
490 if (!qt_widget_private(window())->isOpaque && d->canUseLayeredWindow)
491#endif
492 prepareBuffer(QImage::Format_ARGB32_Premultiplied, window());
493 else
494#endif
495 prepareBuffer(QNativeImage::systemFormat(), window());
496 }
497 d->inSetGeometry = false;
498}
499
500// from qwindowsurface.cpp
501extern void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset);
502
503bool QRasterWindowSurface::scroll(const QRegion &area, int dx, int dy)
504{
505#ifdef Q_WS_WIN
506 Q_D(QRasterWindowSurface);
507
508 if (!d->image || !d->image->hdc)
509 return false;
510
511 QRect rect = area.boundingRect();
512 BitBlt(d->image->hdc, rect.x()+dx, rect.y()+dy, rect.width(), rect.height(),
513 d->image->hdc, rect.x(), rect.y(), SRCCOPY);
514
515 return true;
516#else
517 Q_D(QRasterWindowSurface);
518
519 if (!d->image || d->image->image.isNull())
520 return false;
521
522 const QVector<QRect> rects = area.rects();
523 for (int i = 0; i < rects.size(); ++i)
524 qt_scrollRectInImage(d->image->image, rects.at(i), QPoint(dx, dy));
525
526 return true;
527#endif
528}
529
530
531void QRasterWindowSurface::prepareBuffer(QImage::Format format, QWidget *widget)
532{
533 Q_D(QRasterWindowSurface);
534
535 int width = window()->width();
536 int height = window()->height();
537 if (d->image) {
538 width = qMax(d->image->width(), width);
539 height = qMax(d->image->height(), height);
540 }
541
542 if (width == 0 || height == 0) {
543 delete d->image;
544 d->image = 0;
545 return;
546 }
547
548 QNativeImage *oldImage = d->image;
549
550 d->image = new QNativeImage(width, height, format, false, widget);
551
552 if (oldImage && d->inSetGeometry && hasStaticContents()) {
553 // Make sure we use the const version of bits() (no detach).
554 const uchar *src = const_cast<const QImage &>(oldImage->image).bits();
555 uchar *dst = d->image->image.bits();
556
557 const int srcBytesPerLine = oldImage->image.bytesPerLine();
558 const int dstBytesPerLine = d->image->image.bytesPerLine();
559 const int bytesPerPixel = oldImage->image.depth() >> 3;
560
561 QRegion staticRegion(staticContents());
562 // Make sure we're inside the boundaries of the old image.
563 staticRegion &= QRect(0, 0, oldImage->image.width(), oldImage->image.height());
564 const QVector<QRect> &rects = staticRegion.rects();
565 const QRect *srcRect = rects.constData();
566
567 // Copy the static content of the old image into the new one.
568 int numRectsLeft = rects.size();
569 do {
570 const int bytesOffset = srcRect->x() * bytesPerPixel;
571 const int dy = srcRect->y();
572
573 // Adjust src and dst to point to the right offset.
574 const uchar *s = src + dy * srcBytesPerLine + bytesOffset;
575 uchar *d = dst + dy * dstBytesPerLine + bytesOffset;
576 const int numBytes = srcRect->width() * bytesPerPixel;
577
578 int numScanLinesLeft = srcRect->height();
579 do {
580 ::memcpy(d, s, numBytes);
581 d += dstBytesPerLine;
582 s += srcBytesPerLine;
583 } while (--numScanLinesLeft);
584
585 ++srcRect;
586 } while (--numRectsLeft);
587 }
588
589 delete oldImage;
590}
591
592QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.