source: trunk/src/gui/painting/qwindowsurface.cpp

Last change on this file was 846, checked in by Dmitry A. Kuminov, 14 years ago

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

File size: 10.2 KB
Line 
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 <private/qwindowsurface_p.h>
43#include <qwidget.h>
44#include <private/qwidget_p.h>
45#include <private/qbackingstore_p.h>
46#include <private/qapplication_p.h>
47
48QT_BEGIN_NAMESPACE
49
50class QWindowSurfacePrivate
51{
52public:
53 QWindowSurfacePrivate(QWidget *w)
54 : window(w)
55 , staticContentsSupport(0)
56 , partialUpdateSupport(1)
57 {
58 }
59
60 QWidget *window;
61 QRect geometry;
62 QRegion staticContents;
63 QList<QImage*> bufferImages;
64 uint staticContentsSupport : 1;
65 uint partialUpdateSupport : 1;
66};
67
68/*!
69 \class QWindowSurface
70 \since 4.3
71 \internal
72 \preliminary
73 \ingroup qws
74
75 \brief The QWindowSurface class provides the drawing area for top-level
76 windows.
77*/
78
79
80/*!
81 \fn void QWindowSurface::beginPaint(const QRegion &region)
82
83 This function is called before painting onto the surface begins,
84 with the \a region in which the painting will occur.
85
86 \sa endPaint(), paintDevice()
87*/
88
89/*!
90 \fn void QWindowSurface::endPaint(const QRegion &region)
91
92 This function is called after painting onto the surface has ended,
93 with the \a region in which the painting was performed.
94
95 \sa beginPaint(), paintDevice()
96*/
97
98/*!
99 \fn void QWindowSurface::flush(QWidget *widget, const QRegion &region,
100 const QPoint &offset)
101
102 Flushes the given \a region from the specified \a widget onto the
103 screen.
104
105 Note that the \a offset parameter is currently unused.
106*/
107
108/*!
109 \fn QPaintDevice* QWindowSurface::paintDevice()
110
111 Implement this function to return the appropriate paint device.
112*/
113
114/*!
115 Constructs an empty surface for the given top-level \a window.
116*/
117QWindowSurface::QWindowSurface(QWidget *window)
118 : d_ptr(new QWindowSurfacePrivate(window))
119{
120 if (!QApplicationPrivate::runtime_graphics_system) {
121 if(window)
122 window->setWindowSurface(this);
123 }
124}
125
126/*!
127 Destroys this surface.
128*/
129QWindowSurface::~QWindowSurface()
130{
131 if (d_ptr->window)
132 d_ptr->window->d_func()->extra->topextra->windowSurface = 0;
133 delete d_ptr;
134}
135
136/*!
137 Returns a pointer to the top-level window associated with this
138 surface.
139*/
140QWidget* QWindowSurface::window() const
141{
142 return d_ptr->window;
143}
144
145void QWindowSurface::beginPaint(const QRegion &)
146{
147}
148
149void QWindowSurface::endPaint(const QRegion &)
150{
151// QApplication::syncX();
152 qDeleteAll(d_ptr->bufferImages);
153 d_ptr->bufferImages.clear();
154}
155
156/*!
157 Sets the currently allocated area to be the given \a rect.
158
159 This function is called whenever area covered by the top-level
160 window changes.
161
162 \sa geometry()
163*/
164void QWindowSurface::setGeometry(const QRect &rect)
165{
166 d_ptr->geometry = rect;
167}
168
169/*!
170 Returns the currently allocated area on the screen.
171*/
172QRect QWindowSurface::geometry() const
173{
174 return d_ptr->geometry;
175}
176
177/*!
178 Scrolls the given \a area \a dx pixels to the right and \a dy
179 downward; both \a dx and \a dy may be negative.
180
181 Returns true if the area was scrolled successfully; false otherwise.
182*/
183bool QWindowSurface::scroll(const QRegion &area, int dx, int dy)
184{
185 Q_UNUSED(area);
186 Q_UNUSED(dx);
187 Q_UNUSED(dy);
188
189 return false;
190}
191
192/*!
193 Returns a QImage pointer which represents the actual buffer the \a widget
194 is drawn into or 0 if this is unavailable.
195
196 You must call beginPaint() before you call this function and the returned
197 pointer is only valid until endPaint() is called.
198*/
199QImage* QWindowSurface::buffer(const QWidget *widget)
200{
201 if (widget->window() != window())
202 return 0;
203
204 QPaintDevice *pdev = paintDevice();
205 if (!pdev || pdev->devType() != QInternal::Image)
206 return 0;
207
208 const QPoint off = offset(widget);
209 QImage *img = static_cast<QImage*>(pdev);
210
211 QRect rect(off, widget->size());
212 rect &= QRect(QPoint(), img->size());
213
214 if (rect.isEmpty())
215 return 0;
216
217 img = new QImage(img->scanLine(rect.y()) + rect.x() * img->depth() / 8,
218 rect.width(), rect.height(),
219 img->bytesPerLine(), img->format());
220 d_ptr->bufferImages.append(img);
221
222 return img;
223}
224
225/*!
226 Returns a QPixmap generated from the part of the backing store
227 corresponding to \a widget. Returns a null QPixmap if an error
228 occurs. The contents of the pixmap are only defined for the regions
229 of \a widget that have received paint events since the last resize
230 of the backing store.
231
232 If \a rectangle is a null rectangle (the default), the entire widget
233 is grabbed. Otherwise, the grabbed area is limited to \a rectangle.
234
235 The default implementation uses QWindowSurface::buffer().
236
237 \sa QPixmap::grabWidget()
238*/
239QPixmap QWindowSurface::grabWidget(const QWidget *widget, const QRect &rectangle) const
240{
241 QPixmap result;
242
243 if (widget->window() != window())
244 return result;
245
246 const QImage *img = const_cast<QWindowSurface *>(this)->buffer(widget->window());
247
248 if (!img || img->isNull())
249 return result;
250
251 QRect rect = rectangle.isEmpty() ? widget->rect() : (widget->rect() & rectangle);
252
253 rect.translate(offset(widget) - offset(widget->window()));
254 rect &= QRect(QPoint(), img->size());
255
256 if (rect.isEmpty())
257 return result;
258
259 QImage subimg(img->scanLine(rect.y()) + rect.x() * img->depth() / 8,
260 rect.width(), rect.height(),
261 img->bytesPerLine(), img->format());
262 subimg.detach(); //### expensive -- maybe we should have a real SubImage that shares reference count
263
264 result = QPixmap::fromImage(subimg);
265 return result;
266}
267
268/*!
269 Returns the offset of \a widget in the coordinates of this
270 window surface.
271 */
272QPoint QWindowSurface::offset(const QWidget *widget) const
273{
274 QWidget *window = d_ptr->window;
275 QPoint offset = widget->mapTo(window, QPoint());
276#ifdef Q_WS_QWS
277 offset += window->geometry().topLeft() - window->frameGeometry().topLeft();
278#endif
279 return offset;
280}
281
282/*!
283 \fn QRect QWindowSurface::rect(const QWidget *widget) const
284
285 Returns the rectangle for \a widget in the coordinates of this
286 window surface.
287*/
288
289bool QWindowSurface::hasStaticContentsSupport() const
290{
291 return d_ptr->staticContentsSupport;
292}
293
294void QWindowSurface::setStaticContentsSupport(bool enable)
295{
296 if (enable && !d_ptr->partialUpdateSupport) {
297 qWarning("QWindowSurface::setStaticContentsSupport: static contents support requires partial update support");
298 return;
299 }
300 d_ptr->staticContentsSupport = enable;
301}
302
303void QWindowSurface::setStaticContents(const QRegion &region)
304{
305 d_ptr->staticContents = region;
306}
307
308QRegion QWindowSurface::staticContents() const
309{
310 return d_ptr->staticContents;
311}
312
313bool QWindowSurface::hasStaticContents() const
314{
315 return d_ptr->staticContentsSupport && !d_ptr->staticContents.isEmpty();
316}
317
318bool QWindowSurface::hasPartialUpdateSupport() const
319{
320 return d_ptr->partialUpdateSupport;
321}
322
323void QWindowSurface::setPartialUpdateSupport(bool enable)
324{
325 if (!enable && d_ptr->staticContentsSupport) {
326 qWarning("QWindowSurface::setPartialUpdateSupport: static contents support requires partial update support");
327 return;
328 }
329 d_ptr->partialUpdateSupport = enable;
330}
331
332void qt_scrollRectInImage(QImage &img, const QRect &rect, const QPoint &offset)
333{
334 // make sure we don't detach
335 uchar *mem = const_cast<uchar*>(const_cast<const QImage &>(img).bits());
336
337 int lineskip = img.bytesPerLine();
338 int depth = img.depth() >> 3;
339
340 const QRect imageRect(0, 0, img.width(), img.height());
341 const QRect r = rect & imageRect & imageRect.translated(-offset);
342 const QPoint p = rect.topLeft() + offset;
343
344 if (r.isEmpty())
345 return;
346
347 const uchar *src;
348 uchar *dest;
349
350 if (r.top() < p.y()) {
351 src = mem + r.bottom() * lineskip + r.left() * depth;
352 dest = mem + (p.y() + r.height() - 1) * lineskip + p.x() * depth;
353 lineskip = -lineskip;
354 } else {
355 src = mem + r.top() * lineskip + r.left() * depth;
356 dest = mem + p.y() * lineskip + p.x() * depth;
357 }
358
359 const int w = r.width();
360 int h = r.height();
361 const int bytes = w * depth;
362
363 // overlapping segments?
364 if (offset.y() == 0 && qAbs(offset.x()) < w) {
365 do {
366 ::memmove(dest, src, bytes);
367 dest += lineskip;
368 src += lineskip;
369 } while (--h);
370 } else {
371 do {
372 ::memcpy(dest, src, bytes);
373 dest += lineskip;
374 src += lineskip;
375 } while (--h);
376 }
377}
378
379QT_END_NAMESPACE
Note: See TracBrowser for help on using the repository browser.