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

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

gui: Disabled debug output.

File size: 15.0 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
68QT_BEGIN_NAMESPACE
69
70#ifdef Q_WS_WIN
71PtrUpdateLayeredWindowIndirect ptrUpdateLayeredWindowIndirect;
72#endif
73
74class QRasterWindowSurfacePrivate
75{
76public:
77 QNativeImage *image;
78
79#ifdef Q_WS_X11
80 GC gc;
81#ifndef QT_NO_XRENDER
82 uint translucentBackground : 1;
83#endif
84#endif
85#if defined(Q_WS_WIN) && !defined(Q_OS_WINCE)
86 uint canUseLayeredWindow : 1;
87#endif
88 uint inSetGeometry : 1;
89};
90
91QRasterWindowSurface::QRasterWindowSurface(QWidget *window)
92 : QWindowSurface(window), d_ptr(new QRasterWindowSurfacePrivate)
93{
94#ifdef Q_WS_X11
95 d_ptr->gc = XCreateGC(X11->display, window->handle(), 0, 0);
96#ifndef QT_NO_XRENDER
97 d_ptr->translucentBackground = X11->use_xrender
98 && window->x11Info().depth() == 32;
99#endif
100#endif
101#if defined(Q_WS_WIN) && !defined(Q_OS_WINCE)
102 d_ptr->canUseLayeredWindow = ptrUpdateLayeredWindowIndirect
103 && (qt_widget_private(window)->data.window_flags & Qt::FramelessWindowHint);
104#endif
105 d_ptr->image = 0;
106 d_ptr->inSetGeometry = false;
107 setStaticContentsSupport(true);
108}
109
110
111QRasterWindowSurface::~QRasterWindowSurface()
112{
113#ifdef Q_WS_X11
114 XFreeGC(X11->display, d_ptr->gc);
115#endif
116 if (d_ptr->image)
117 delete d_ptr->image;
118
119 delete d_ptr;
120}
121
122
123QPaintDevice *QRasterWindowSurface::paintDevice()
124{
125 return &d_ptr->image->image;
126}
127
128void QRasterWindowSurface::beginPaint(const QRegion &rgn)
129{
130#if (defined(Q_WS_X11) && !defined(QT_NO_XRENDER)) || (defined(Q_WS_WIN) && !defined(Q_OS_WINCE))
131 if (!qt_widget_private(window())->isOpaque) {
132#if defined(Q_WS_WIN) && !defined(Q_OS_WINCE)
133 if (d_ptr->image->image.format() != QImage::Format_ARGB32_Premultiplied
134 && d_ptr->canUseLayeredWindow)
135 prepareBuffer(QImage::Format_ARGB32_Premultiplied, window());
136#endif
137 QPainter p(&d_ptr->image->image);
138 p.setCompositionMode(QPainter::CompositionMode_Source);
139 const QVector<QRect> rects = rgn.rects();
140 const QColor blank = Qt::transparent;
141 for (QVector<QRect>::const_iterator it = rects.begin(); it != rects.end(); ++it) {
142 p.fillRect(*it, blank);
143 }
144 }
145#endif
146#if defined(Q_OS_WINCE)
147 Q_UNUSED(rgn);
148#endif
149}
150
151void QRasterWindowSurface::flush(QWidget *widget, const QRegion &rgn, const QPoint &offset)
152{
153 Q_D(QRasterWindowSurface);
154
155 // Not ready for painting yet, bail out. This can happen in
156 // QWidget::create_sys()
157 if (!d->image)
158 return;
159
160#ifdef Q_WS_WIN
161 QRect br = rgn.boundingRect();
162
163#ifndef Q_OS_WINCE
164 if (!qt_widget_private(window())->isOpaque && d->canUseLayeredWindow) {
165 QRect r = window()->frameGeometry();
166 QPoint frameOffset = qt_widget_private(window())->frameStrut().topLeft();
167 QRect dirtyRect = br.translated(offset + frameOffset);
168
169 SIZE size = {r.width(), r.height()};
170 POINT ptDst = {r.x(), r.y()};
171 POINT ptSrc = {0, 0};
172 Q_BLENDFUNCTION blend = {AC_SRC_OVER, 0, (int)(255.0 * window()->windowOpacity()), Q_AC_SRC_ALPHA};
173 RECT dirty = {dirtyRect.x(), dirtyRect.y(),
174 dirtyRect.x() + dirtyRect.width(), dirtyRect.y() + dirtyRect.height()};
175 Q_UPDATELAYEREDWINDOWINFO info = {sizeof(info), NULL, &ptDst, &size, d->image->hdc, &ptSrc, 0, &blend, Q_ULW_ALPHA, &dirty};
176
177 (*ptrUpdateLayeredWindowIndirect)(window()->internalWinId(), &info);
178 } else
179#endif
180 {
181 QPoint wOffset = qt_qwidget_data(widget)->wrect.topLeft();
182
183 HDC widget_dc = widget->getDC();
184
185 QRect wbr = br.translated(-wOffset);
186 BitBlt(widget_dc, wbr.x(), wbr.y(), wbr.width(), wbr.height(),
187 d->image->hdc, br.x() + offset.x(), br.y() + offset.y(), SRCCOPY);
188 widget->releaseDC(widget_dc);
189 }
190
191#ifndef QT_NO_DEBUG
192 static bool flush = !qgetenv("QT_FLUSH_WINDOWSURFACE").isEmpty();
193 if (flush) {
194 SelectObject(qt_win_display_dc(), GetStockObject(BLACK_BRUSH));
195 Rectangle(qt_win_display_dc(), 0, 0, d->image->width() + 2, d->image->height() + 2);
196 BitBlt(qt_win_display_dc(), 1, 1, d->image->width(), d->image->height(),
197 d->image->hdc, 0, 0, SRCCOPY);
198 }
199#endif
200
201#endif
202
203#ifdef Q_WS_PM
204 QRect br = rgn.boundingRect();
205#if 0
206 qDebug("QRasterWindowSurface::flush: [%s] br=%d,%d/%d,%d",
207 qWidgetName(widget).toUtf8().constData(),
208 br.x(), br.y(), br.width(), br.height());
209#endif
210
211 HPS wps = widget->getPS();
212
213 // use the reflection + transformation matrix to flip the y axis
214 // @todo check if it's really slower than flipping the image bits instead
215 // @todo I guess we can use DIVE here; check it too
216 MATRIXLF m;
217 m.fxM11 = MAKEFIXED(1, 0);
218 m.fxM12 = 0;
219 m.lM13 = 0;
220 m.fxM21 = 0;
221 m.fxM22 = MAKEFIXED(-1, 0);
222 m.lM23 = 0;
223 m.lM31 = 0;
224 m.lM32 = widget->height() - 1;
225 GpiSetDefaultViewMatrix(wps, 8, &m, TRANSFORM_REPLACE);
226
227 QPoint wOffset = qt_qwidget_data(widget)->wrect.topLeft();
228 QRect wbr = br.translated(-wOffset);
229
230 br.translate(offset);
231
232 BITMAPINFOHEADER2 bmh;
233 memset(&bmh, 0, sizeof(BITMAPINFOHEADER2));
234 bmh.cbFix = sizeof(BITMAPINFOHEADER2);
235 bmh.cPlanes = 1;
236 bmh.cBitCount = 32; // @todo support 8-bit indexed colors?
237 bmh.cx = d->image->width();
238 bmh.cy = d->image->height();
239
240 // Note: target is inclusive-inclusive, source is inclusive-exclusive
241 POINTL ptls[] = { { wbr.left(), wbr.top() },
242 { wbr.right(), wbr.bottom() },
243 { br.left(), br.top() },
244 { br.right() + 1, br.bottom() + 1 } };
245 GpiDrawBits(wps, (PVOID) d->image->image.bits(), (PBITMAPINFO2) &bmh, 4, ptls,
246 ROP_SRCCOPY, BBO_IGNORE);
247
248 widget->releasePS(wps);
249#endif
250
251#ifdef Q_WS_X11
252 extern void *qt_getClipRects(const QRegion &r, int &num); // in qpaintengine_x11.cpp
253 extern QWidgetData* qt_widget_data(QWidget *);
254 QPoint wOffset = qt_qwidget_data(widget)->wrect.topLeft();
255
256 if (widget->window() != window()) {
257 XFreeGC(X11->display, d_ptr->gc);
258 d_ptr->gc = XCreateGC(X11->display, widget->handle(), 0, 0);
259 }
260
261 QRegion wrgn(rgn);
262 if (!wOffset.isNull())
263 wrgn.translate(-wOffset);
264 QRect wbr = wrgn.boundingRect();
265
266 int num;
267 XRectangle *rects = (XRectangle *)qt_getClipRects(wrgn, num);
268 XSetClipRectangles(X11->display, d_ptr->gc, 0, 0, rects, num, YXBanded);
269
270 QRect br = rgn.boundingRect().translated(offset);
271#ifndef QT_NO_MITSHM
272 if (d_ptr->image->xshmpm) {
273 XCopyArea(X11->display, d_ptr->image->xshmpm, widget->handle(), d_ptr->gc,
274 br.x(), br.y(), br.width(), br.height(), wbr.x(), wbr.y());
275 XSync(X11->display, False);
276 } else
277#endif
278 {
279 const QImage &src = d->image->image;
280 br = br.intersected(src.rect());
281 if (src.format() != QImage::Format_RGB32) {
282 QX11PixmapData *data = new QX11PixmapData(QPixmapData::PixmapType);
283 data->xinfo = widget->x11Info();
284 data->fromImage(src, Qt::AutoColor);
285 QPixmap pm = QPixmap(data);
286 XCopyArea(X11->display, pm.handle(), widget->handle(), d_ptr->gc, br.x() , br.y() , br.width(), br.height(), wbr.x(), wbr.y());
287 } else {
288 // qpaintengine_x11.cpp
289 extern void qt_x11_drawImage(const QRect &rect, const QPoint &pos, const QImage &image, Drawable hd, GC gc, Display *dpy, Visual *visual, int depth);
290 qt_x11_drawImage(br, wbr.topLeft(), src, widget->handle(), d_ptr->gc, X11->display, (Visual *)widget->x11Info().visual(), widget->x11Info().depth());
291 }
292 }
293#endif // FALCON
294
295#ifdef Q_WS_MAC
296
297// qDebug() << "Flushing" << widget << rgn << offset;
298
299// d->image->image.save("flush.png");
300
301 // Get a context for the widget.
302#ifndef QT_MAC_USE_COCOA
303 CGContextRef context;
304 CGrafPtr port = GetWindowPort(qt_mac_window_for(widget));
305 QDBeginCGContext(port, &context);
306#else
307 extern CGContextRef qt_mac_graphicsContextFor(QWidget *);
308 CGContextRef context = qt_mac_graphicsContextFor(widget);
309#endif
310 CGContextSaveGState(context);
311
312 // Flip context.
313 CGContextTranslateCTM(context, 0, widget->height());
314 CGContextScaleCTM(context, 1, -1);
315
316 // Clip to region.
317 const QVector<QRect> &rects = rgn.rects();
318 for (int i = 0; i < rects.size(); ++i) {
319 const QRect &rect = rects.at(i);
320 CGContextAddRect(context, CGRectMake(rect.x(), rect.y(), rect.width(), rect.height()));
321 }
322 CGContextClip(context);
323
324 QRect r = rgn.boundingRect();
325 const CGRect area = CGRectMake(r.x(), r.y(), r.width(), r.height());
326 CGImageRef image = CGBitmapContextCreateImage(d->image->cg);
327 CGImageRef subImage = CGImageCreateWithImageInRect(image, area);
328
329 qt_mac_drawCGImage(context, &area, subImage);
330 CGImageRelease(subImage);
331 CGImageRelease(image);
332
333// CGSize size = { d->image->image.width(), d->image->image.height() };
334// CGLayerRef layer = CGLayerCreateWithContext(d->image->cg, size, 0);
335// CGPoint pt = { 0, 0 };
336// CGContextDrawLayerAtPoint(context, pt, layer);
337// CGLayerRelease(layer);
338
339 // Restore context.
340 CGContextRestoreGState(context);
341#ifndef QT_MAC_USE_COCOA
342 QDEndCGContext(port, &context);
343#else
344 CGContextFlush(context);
345#endif
346#endif
347}
348
349void QRasterWindowSurface::setGeometry(const QRect &rect)
350{
351 QWindowSurface::setGeometry(rect);
352 Q_D(QRasterWindowSurface);
353 d->inSetGeometry = true;
354 if (d->image == 0 || d->image->width() < rect.width() || d->image->height() < rect.height()) {
355#if (defined(Q_WS_X11) && !defined(QT_NO_XRENDER)) || (defined(Q_WS_WIN) && !defined(Q_OS_WINCE))
356#ifndef Q_WS_WIN
357 if (d_ptr->translucentBackground)
358#else
359 if (!qt_widget_private(window())->isOpaque && d->canUseLayeredWindow)
360#endif
361 prepareBuffer(QImage::Format_ARGB32_Premultiplied, window());
362 else
363#endif
364 prepareBuffer(QNativeImage::systemFormat(), window());
365 }
366 d->inSetGeometry = false;
367}
368
369// from qwindowsurface.cpp
370extern void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset);
371
372bool QRasterWindowSurface::scroll(const QRegion &area, int dx, int dy)
373{
374#ifdef Q_WS_WIN
375 Q_D(QRasterWindowSurface);
376
377 if (!d->image || !d->image->hdc)
378 return false;
379
380 QRect rect = area.boundingRect();
381 BitBlt(d->image->hdc, rect.x()+dx, rect.y()+dy, rect.width(), rect.height(),
382 d->image->hdc, rect.x(), rect.y(), SRCCOPY);
383
384 return true;
385#else
386 Q_D(QRasterWindowSurface);
387
388 if (!d->image || d->image->image.isNull())
389 return false;
390
391 const QVector<QRect> rects = area.rects();
392 for (int i = 0; i < rects.size(); ++i)
393 qt_scrollRectInImage(d->image->image, rects.at(i), QPoint(dx, dy));
394
395 return true;
396#endif
397}
398
399
400void QRasterWindowSurface::prepareBuffer(QImage::Format format, QWidget *widget)
401{
402 Q_D(QRasterWindowSurface);
403
404 int width = window()->width();
405 int height = window()->height();
406 if (d->image) {
407 width = qMax(d->image->width(), width);
408 height = qMax(d->image->height(), height);
409 }
410
411 if (width == 0 || height == 0) {
412 delete d->image;
413 d->image = 0;
414 return;
415 }
416
417 QNativeImage *oldImage = d->image;
418
419 d->image = new QNativeImage(width, height, format, false, widget);
420
421 if (oldImage && d->inSetGeometry && hasStaticContents()) {
422 // Make sure we use the const version of bits() (no detach).
423 const uchar *src = const_cast<const QImage &>(oldImage->image).bits();
424 uchar *dst = d->image->image.bits();
425
426 const int srcBytesPerLine = oldImage->image.bytesPerLine();
427 const int dstBytesPerLine = d->image->image.bytesPerLine();
428 const int bytesPerPixel = oldImage->image.depth() >> 3;
429
430 QRegion staticRegion(staticContents());
431 // Make sure we're inside the boundaries of the old image.
432 staticRegion &= QRect(0, 0, oldImage->image.width(), oldImage->image.height());
433 const QVector<QRect> &rects = staticRegion.rects();
434 const QRect *srcRect = rects.constData();
435
436 // Copy the static content of the old image into the new one.
437 int numRectsLeft = rects.size();
438 do {
439 const int bytesOffset = srcRect->x() * bytesPerPixel;
440 const int dy = srcRect->y();
441
442 // Adjust src and dst to point to the right offset.
443 const uchar *s = src + dy * srcBytesPerLine + bytesOffset;
444 uchar *d = dst + dy * dstBytesPerLine + bytesOffset;
445 const int numBytes = srcRect->width() * bytesPerPixel;
446
447 int numScanLinesLeft = srcRect->height();
448 do {
449 ::memcpy(d, s, numBytes);
450 d += dstBytesPerLine;
451 s += srcBytesPerLine;
452 } while (--numScanLinesLeft);
453
454 ++srcRect;
455 } while (--numRectsLeft);
456 }
457
458 delete oldImage;
459}
460
461QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.