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