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

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

trunk: Merged in qt 4.6.3 sources from branches/vendor/nokia/qt.

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