source: trunk/src/gui/embedded/qscreen_qws.cpp@ 1123

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

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

  • Property svn:eol-style set to native
File size: 94.3 KB
Line 
1/****************************************************************************
2**
3** Copyright (C) 2011 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 "qplatformdefs.h"
43#include "qscreen_qws.h"
44
45#include "qcolormap.h"
46#include "qscreendriverfactory_qws.h"
47#include "qwindowsystem_qws.h"
48#include "qwidget.h"
49#include "qcolor.h"
50#include "qpixmap.h"
51#include "qvarlengtharray.h"
52#include "qwsdisplay_qws.h"
53#include "qpainter.h"
54#include <private/qdrawhelper_p.h>
55#include <private/qpaintengine_raster_p.h>
56#include <private/qpixmap_raster_p.h>
57#include <private/qwindowsurface_qws_p.h>
58#include <private/qpainter_p.h>
59#include <private/qwidget_p.h>
60#include <private/qgraphicssystem_qws_p.h>
61
62QT_BEGIN_NAMESPACE
63
64// #define QT_USE_MEMCPY_DUFF
65
66#ifndef QT_NO_QWS_CURSOR
67bool qt_sw_cursor=false;
68Q_GUI_EXPORT QScreenCursor * qt_screencursor = 0;
69#endif
70Q_GUI_EXPORT QScreen * qt_screen = 0;
71
72ClearCacheFunc QScreen::clearCacheFunc = 0;
73
74#ifndef QT_NO_QWS_CURSOR
75/*!
76 \class QScreenCursor
77 \ingroup qws
78
79 \brief The QScreenCursor class is a base class for screen cursors
80 in Qt for Embedded Linux.
81
82 Note that this class is non-portable, and that it is only
83 available in \l{Qt for Embedded Linux}.
84
85 QScreenCursor implements a software cursor, but can be subclassed
86 to support hardware cursors as well. When deriving from the
87 QScreenCursor class it is important to maintain the cursor's
88 image, position, hot spot (the point within the cursor's image
89 that will be the position of the associated mouse events) and
90 visibility as well as informing whether it is hardware accelerated
91 or not.
92
93 Note that there may only be one screen cursor at a time. Use the
94 static instance() function to retrieve a pointer to the current
95 screen cursor. Typically, the cursor is constructed by the QScreen
96 class or one of its descendants when it is initializing the
97 device; the QScreenCursor class should never be instantiated
98 explicitly.
99
100 Use the move() function to change the position of the cursor, and
101 the set() function to alter its image or its hot spot. In
102 addition, you can find out whether the cursor is accelerated or
103 not, using the isAccelerated() function, and the boundingRect()
104 function returns the cursor's bounding rectangle.
105
106 The cursor's appearance can be controlled using the isVisible(),
107 hide() and show() functions; alternatively the QWSServer class
108 provides some means of controlling the cursor's appearance using
109 the QWSServer::isCursorVisible() and QWSServer::setCursorVisible()
110 functions.
111
112 \sa QScreen, QWSServer
113*/
114
115/*!
116 \fn static QScreenCursor* QScreenCursor::instance()
117 \since 4.2
118
119 Returns a pointer to the application's unique screen cursor.
120*/
121
122extern bool qws_sw_cursor;
123
124/*!
125 Constructs a screen cursor
126*/
127QScreenCursor::QScreenCursor()
128{
129 pos = QPoint(qt_screen->deviceWidth()/2, qt_screen->deviceHeight()/2);
130 size = QSize(0,0);
131 enable = true;
132 hwaccel = false;
133 supportsAlpha = true;
134}
135
136/*!
137 Destroys the screen cursor.
138*/
139QScreenCursor::~QScreenCursor()
140{
141}
142
143/*!
144 Hides the cursor from the screen.
145
146 \sa show()
147*/
148void QScreenCursor::hide()
149{
150 if (enable) {
151 enable = false;
152 if (!hwaccel)
153 qt_screen->exposeRegion(boundingRect(), 0);
154 }
155}
156
157/*!
158 Shows the mouse cursor.
159
160 \sa hide()
161*/
162void QScreenCursor::show()
163{
164 if (!enable) {
165 enable = true;
166 if (!hwaccel)
167 qt_screen->exposeRegion(boundingRect(), 0);
168 }
169}
170
171/*!
172 Sets the cursor's image to be the given \a image.
173
174 The \a hotx and \a hoty parameters define the cursor's hot spot,
175 i.e., the point within the cursor's image that will be the
176 position of the associated mouse events.
177
178 \sa move()
179*/
180void QScreenCursor::set(const QImage &image, int hotx, int hoty)
181{
182 const QRect r = boundingRect();
183
184 hotspot = QPoint(hotx, hoty);
185 // These are in almost all cases the fastest formats to blend
186 QImage::Format f;
187 switch (qt_screen->depth()) {
188 case 12:
189 f = QImage::Format_ARGB4444_Premultiplied;
190 break;
191 case 15:
192 f = QImage::Format_ARGB8555_Premultiplied;
193 break;
194 case 16:
195 f = QImage::Format_ARGB8565_Premultiplied;
196 break;
197 case 18:
198 f = QImage::Format_ARGB6666_Premultiplied;
199 break;
200 default:
201 f = QImage::Format_ARGB32_Premultiplied;
202 }
203
204 cursor = image.convertToFormat(f);
205
206 size = image.size();
207
208 if (enable && !hwaccel)
209 qt_screen->exposeRegion(r | boundingRect(), 0);
210}
211
212/*!
213 Moves the mouse cursor to the given position, i.e., (\a x, \a y).
214
215 Note that the given position defines the top-left corner of the
216 cursor's image, i.e., not the cursor's hot spot (the position of
217 the associated mouse events).
218
219 \sa set()
220*/
221void QScreenCursor::move(int x, int y)
222{
223 QRegion r = boundingRect();
224 pos = QPoint(x,y);
225 if (enable && !hwaccel) {
226 r |= boundingRect();
227 qt_screen->exposeRegion(r, 0);
228 }
229}
230
231
232/*!
233 \fn void QScreenCursor::initSoftwareCursor ()
234
235 Initializes the screen cursor.
236
237 This function is typically called from the screen driver when
238 initializing the device. Alternatively, the cursor can be set
239 directly using the pointer returned by the static instance()
240 function.
241
242 \sa QScreen::initDevice()
243*/
244void QScreenCursor::initSoftwareCursor()
245{
246 qt_screencursor = new QScreenCursor;
247}
248
249
250#endif // QT_NO_QWS_CURSOR
251
252
253/*!
254 \fn QRect QScreenCursor::boundingRect () const
255
256 Returns the cursor's bounding rectangle.
257*/
258
259/*!
260 \internal
261 \fn bool QScreenCursor::enabled ()
262*/
263
264/*!
265 \fn QImage QScreenCursor::image () const
266
267 Returns the cursor's image.
268*/
269
270
271/*!
272 \fn bool QScreenCursor::isAccelerated () const
273
274 Returns true if the cursor is accelerated; otherwise false.
275*/
276
277/*!
278 \fn bool QScreenCursor::isVisible () const
279
280 Returns true if the cursor is visible; otherwise false.
281*/
282
283/*!
284 \internal
285 \fn bool QScreenCursor::supportsAlphaCursor () const
286*/
287
288/*
289 \variable QScreenCursor::cursor
290
291 \brief the cursor's image.
292
293 \sa image()
294*/
295
296/*
297 \variable QScreenCursor::size
298
299 \brief the cursor's size
300*/
301
302/*
303 \variable QScreenCursor::pos
304
305 \brief the cursor's position, i.e., the position of the top-left
306 corner of the crsor's image
307
308 \sa set(), move()
309*/
310
311/*
312 \variable QScreenCursor::hotspot
313
314 \brief the cursor's hotspot, i.e., the point within the cursor's
315 image that will be the position of the associated mouse events.
316
317 \sa set(), move()
318*/
319
320/*
321 \variable QScreenCursor::enable
322
323 \brief whether the cursor is visible or not
324
325 \sa isVisible()
326*/
327
328/*
329 \variable QScreenCursor::hwaccel
330
331 \brief holds whether the cursor is accelerated or not
332
333 If the cursor is not accelerated, its image will be included by
334 the screen when it composites the window surfaces.
335
336 \sa isAccelerated()
337
338*/
339
340/*
341 \variable QScreenCursor::supportsAlpha
342*/
343
344/*!
345 \internal
346 \macro qt_screencursor
347 \relates QScreenCursor
348
349 A global pointer referring to the unique screen cursor. It is
350 equivalent to the pointer returned by the
351 QScreenCursor::instance() function.
352*/
353
354
355
356class QScreenPrivate
357{
358public:
359 QScreenPrivate(QScreen *parent, QScreen::ClassId id = QScreen::CustomClass);
360 ~QScreenPrivate();
361
362 inline QImage::Format preferredImageFormat() const;
363
364 typedef void (*SolidFillFunc)(QScreen*, const QColor&, const QRegion&);
365 typedef void (*BlitFunc)(QScreen*, const QImage&, const QPoint&, const QRegion&);
366
367 SolidFillFunc solidFill;
368 BlitFunc blit;
369
370 QPoint offset;
371 QList<QScreen*> subScreens;
372 QPixmapDataFactory* pixmapFactory;
373 QGraphicsSystem* graphicsSystem;
374 QWSGraphicsSystem defaultGraphicsSystem; //###
375 QImage::Format pixelFormat;
376#if Q_BYTE_ORDER == Q_BIG_ENDIAN
377 bool fb_is_littleEndian;
378#endif
379#ifdef QT_QWS_CLIENTBLIT
380 bool supportsBlitInClients;
381#endif
382 int classId;
383 QScreen *q_ptr;
384};
385
386template <typename T>
387static void solidFill_template(QScreen *screen, const QColor &color,
388 const QRegion &region)
389{
390 T *dest = reinterpret_cast<T*>(screen->base());
391 const T c = qt_colorConvert<T, quint32>(color.rgba(), 0);
392 const int stride = screen->linestep();
393 const QVector<QRect> rects = region.rects();
394
395 for (int i = 0; i < rects.size(); ++i) {
396 const QRect r = rects.at(i);
397 qt_rectfill(dest, c, r.x(), r.y(), r.width(), r.height(), stride);
398 }
399}
400
401#ifdef QT_QWS_DEPTH_GENERIC
402static void solidFill_rgb_32bpp(QScreen *screen, const QColor &color,
403 const QRegion &region)
404{
405 quint32 *dest = reinterpret_cast<quint32*>(screen->base());
406 const quint32 c = qt_convertToRgb<quint32>(color.rgba());
407
408 const int stride = screen->linestep();
409 const QVector<QRect> rects = region.rects();
410
411 for (int i = 0; i < rects.size(); ++i) {
412 const QRect r = rects.at(i);
413 qt_rectfill(dest, c, r.x(), r.y(), r.width(), r.height(), stride);
414 }
415}
416
417static void solidFill_rgb_16bpp(QScreen *screen, const QColor &color,
418 const QRegion &region)
419{
420 quint16 *dest = reinterpret_cast<quint16*>(screen->base());
421 const quint16 c = qt_convertToRgb<quint32>(color.rgba());
422
423 const int stride = screen->linestep();
424 const QVector<QRect> rects = region.rects();
425
426 for (int i = 0; i < rects.size(); ++i) {
427 const QRect r = rects.at(i);
428 qt_rectfill(dest, c, r.x(), r.y(), r.width(), r.height(), stride);
429 }
430}
431#endif // QT_QWS_DEPTH_GENERIC
432
433#ifdef QT_QWS_DEPTH_4
434static inline void qt_rectfill_gray4(quint8 *dest, quint8 value,
435 int x, int y, int width, int height,
436 int stride)
437{
438 const int pixelsPerByte = 2;
439 dest += y * stride + x / pixelsPerByte;
440 const int doAlign = x & 1;
441 const int doTail = (width - doAlign) & 1;
442 const int width8 = (width - doAlign) / pixelsPerByte;
443
444 for (int j = 0; j < height; ++j) {
445 if (doAlign)
446 *dest = (*dest & 0xf0) | (value & 0x0f);
447 if (width8)
448 qt_memfill<quint8>(dest + doAlign, value, width8);
449 if (doTail) {
450 quint8 *d = dest + doAlign + width8;
451 *d = (*d & 0x0f) | (value & 0xf0);
452 }
453 dest += stride;
454 }
455}
456
457static void solidFill_gray4(QScreen *screen, const QColor &color,
458 const QRegion &region)
459{
460 quint8 *dest = reinterpret_cast<quint8*>(screen->base());
461 const quint8 c = qGray(color.rgba()) >> 4;
462 const quint8 c8 = (c << 4) | c;
463
464 const int stride = screen->linestep();
465 const QVector<QRect> rects = region.rects();
466
467 for (int i = 0; i < rects.size(); ++i) {
468 const QRect r = rects.at(i);
469 qt_rectfill_gray4(dest, c8, r.x(), r.y(), r.width(), r.height(),
470 stride);
471 }
472}
473#endif // QT_QWS_DEPTH_4
474
475#ifdef QT_QWS_DEPTH_1
476static inline void qt_rectfill_mono(quint8 *dest, quint8 value,
477 int x, int y, int width, int height,
478 int stride)
479{
480 const int pixelsPerByte = 8;
481 const int alignWidth = qMin(width, (8 - (x & 7)) & 7);
482 const int doAlign = (alignWidth > 0 ? 1 : 0);
483 const int alignStart = pixelsPerByte - 1 - (x & 7);
484 const int alignStop = alignStart - (alignWidth - 1);
485 const quint8 alignMask = ((1 << alignWidth) - 1) << alignStop;
486 const int tailWidth = (width - alignWidth) & 7;
487 const int doTail = (tailWidth > 0 ? 1 : 0);
488 const quint8 tailMask = (1 << (pixelsPerByte - tailWidth)) - 1;
489 const int width8 = (width - alignWidth) / pixelsPerByte;
490
491 dest += y * stride + x / pixelsPerByte;
492 stride -= (doAlign + width8);
493
494 for (int j = 0; j < height; ++j) {
495 if (doAlign) {
496 *dest = (*dest & ~alignMask) | (value & alignMask);
497 ++dest;
498 }
499 if (width8) {
500 qt_memfill<quint8>(dest, value, width8);
501 dest += width8;
502 }
503 if (doTail)
504 *dest = (*dest & tailMask) | (value & ~tailMask);
505 dest += stride;
506 }
507}
508
509static void solidFill_mono(QScreen *screen, const QColor &color,
510 const QRegion &region)
511{
512 quint8 *dest = reinterpret_cast<quint8*>(screen->base());
513 const quint8 c8 = (qGray(color.rgba()) >> 7) * 0xff;
514
515 const int stride = screen->linestep();
516 const QVector<QRect> rects = region.rects();
517
518 for (int i = 0; i < rects.size(); ++i) {
519 const QRect r = rects.at(i);
520 qt_rectfill_mono(dest, c8, r.x(), r.y(), r.width(), r.height(),
521 stride);
522 }
523}
524#endif // QT_QWS_DEPTH_1
525
526void qt_solidFill_setup(QScreen *screen, const QColor &color,
527 const QRegion &region)
528{
529 switch (screen->depth()) {
530#ifdef QT_QWS_DEPTH_32
531 case 32:
532 if (screen->pixelType() == QScreen::NormalPixel)
533 screen->d_ptr->solidFill = solidFill_template<quint32>;
534 else
535 screen->d_ptr->solidFill = solidFill_template<qabgr8888>;
536 break;
537#endif
538#ifdef QT_QWS_DEPTH_24
539 case 24:
540 if (screen->pixelType() == QScreen::NormalPixel)
541 screen->d_ptr->solidFill = solidFill_template<qrgb888>;
542 else
543 screen->d_ptr->solidFill = solidFill_template<quint24>;
544 break;
545#endif
546#ifdef QT_QWS_DEPTH_18
547 case 18:
548 screen->d_ptr->solidFill = solidFill_template<quint18>;
549 break;
550#endif
551#ifdef QT_QWS_DEPTH_16
552 case 16:
553 if (screen->pixelType() == QScreen::NormalPixel)
554 screen->d_ptr->solidFill = solidFill_template<quint16>;
555 else
556 screen->d_ptr->solidFill = solidFill_template<qbgr565>;
557 break;
558#endif
559#ifdef QT_QWS_DEPTH_15
560 case 15:
561 if (screen->pixelType() == QScreen::NormalPixel)
562 screen->d_ptr->solidFill = solidFill_template<qrgb555>;
563 else
564 screen->d_ptr->solidFill = solidFill_template<qbgr555>;
565 break;
566#endif
567#ifdef QT_QWS_DEPTH_12
568 case 12:
569 screen->d_ptr->solidFill = solidFill_template<qrgb444>;
570 break;
571#endif
572#ifdef QT_QWS_DEPTH_8
573 case 8:
574 screen->d_ptr->solidFill = solidFill_template<quint8>;
575 break;
576#endif
577#ifdef QT_QWS_DEPTH_4
578 case 4:
579 screen->d_ptr->solidFill = solidFill_gray4;
580 break;
581#endif
582#ifdef QT_QWS_DEPTH_1
583 case 1:
584 screen->d_ptr->solidFill = solidFill_mono;
585 break;
586#endif
587 default:
588 qFatal("solidFill_setup(): Screen depth %d not supported!",
589 screen->depth());
590 screen->d_ptr->solidFill = 0;
591 break;
592 }
593 screen->d_ptr->solidFill(screen, color, region);
594}
595
596template <typename DST, typename SRC>
597static void blit_template(QScreen *screen, const QImage &image,
598 const QPoint &topLeft, const QRegion &region)
599{
600 DST *dest = reinterpret_cast<DST*>(screen->base());
601 const int screenStride = screen->linestep();
602 const int imageStride = image.bytesPerLine();
603
604 if (region.rectCount() == 1) {
605 const QRect r = region.boundingRect();
606 const SRC *src = reinterpret_cast<const SRC*>(image.scanLine(r.y()))
607 + r.x();
608 qt_rectconvert<DST, SRC>(dest, src,
609 r.x() + topLeft.x(), r.y() + topLeft.y(),
610 r.width(), r.height(),
611 screenStride, imageStride);
612 } else {
613 const QVector<QRect> rects = region.rects();
614
615 for (int i = 0; i < rects.size(); ++i) {
616 const QRect r = rects.at(i);
617 const SRC *src = reinterpret_cast<const SRC*>(image.scanLine(r.y()))
618 + r.x();
619 qt_rectconvert<DST, SRC>(dest, src,
620 r.x() + topLeft.x(), r.y() + topLeft.y(),
621 r.width(), r.height(),
622 screenStride, imageStride);
623 }
624 }
625}
626
627#ifdef QT_QWS_DEPTH_32
628static void blit_32(QScreen *screen, const QImage &image,
629 const QPoint &topLeft, const QRegion &region)
630{
631 switch (image.format()) {
632 case QImage::Format_RGB32:
633 case QImage::Format_ARGB32:
634 case QImage::Format_ARGB32_Premultiplied:
635 blit_template<quint32, quint32>(screen, image, topLeft, region);
636 return;
637#ifdef QT_QWS_DEPTH_16
638 case QImage::Format_RGB16:
639 blit_template<quint32, quint16>(screen, image, topLeft, region);
640 return;
641#endif
642 default:
643 qCritical("blit_32(): Image format %d not supported!", image.format());
644 }
645}
646#endif // QT_QWS_DEPTH_32
647
648#ifdef QT_QWS_DEPTH_24
649static void blit_24(QScreen *screen, const QImage &image,
650 const QPoint &topLeft, const QRegion &region)
651{
652 switch (image.format()) {
653 case QImage::Format_RGB32:
654 case QImage::Format_ARGB32:
655 case QImage::Format_ARGB32_Premultiplied:
656 blit_template<quint24, quint32>(screen, image, topLeft, region);
657 return;
658 case QImage::Format_RGB888:
659 blit_template<quint24, qrgb888>(screen, image, topLeft, region);
660 return;
661#ifdef QT_QWS_DEPTH_16
662 case QImage::Format_RGB16:
663 blit_template<quint24, quint16>(screen, image, topLeft, region);
664 return;
665#endif
666 default:
667 qCritical("blit_24(): Image format %d not supported!", image.format());
668 }
669}
670
671static void blit_qrgb888(QScreen *screen, const QImage &image,
672 const QPoint &topLeft, const QRegion &region)
673{
674 switch (image.format()) {
675 case QImage::Format_RGB32:
676 case QImage::Format_ARGB32:
677 case QImage::Format_ARGB32_Premultiplied:
678 blit_template<qrgb888, quint32>(screen, image, topLeft, region);
679 return;
680 case QImage::Format_RGB888:
681 blit_template<qrgb888, qrgb888>(screen, image, topLeft, region);
682 return;
683#ifdef QT_QWS_DEPTH_16
684 case QImage::Format_RGB16:
685 blit_template<qrgb888, quint16>(screen, image, topLeft, region);
686 return;
687#endif
688 default:
689 qCritical("blit_24(): Image format %d not supported!", image.format());
690 break;
691 }
692}
693#endif // QT_QWS_DEPTH_24
694
695#ifdef QT_QWS_DEPTH_18
696static void blit_18(QScreen *screen, const QImage &image,
697 const QPoint &topLeft, const QRegion &region)
698{
699 switch (image.format()) {
700 case QImage::Format_RGB32:
701 case QImage::Format_ARGB32:
702 case QImage::Format_ARGB32_Premultiplied:
703 blit_template<qrgb666, quint32>(screen, image, topLeft, region);
704 return;
705 case QImage::Format_RGB666:
706 blit_template<qrgb666, qrgb666>(screen, image, topLeft, region);
707 return;
708#ifdef QT_QWS_DEPTH_16
709 case QImage::Format_RGB16:
710 blit_template<qrgb666, quint16>(screen, image, topLeft, region);
711 return;
712#endif
713 default:
714 qCritical("blit_18(): Image format %d not supported!", image.format());
715 }
716}
717#endif // QT_QWS_DEPTH_18
718
719#if (Q_BYTE_ORDER == Q_BIG_ENDIAN) && (defined(QT_QWS_DEPTH_16) || defined(QT_QWS_DEPTH_15))
720class quint16LE
721{
722public:
723 inline quint16LE(quint32 v) {
724 data = ((v & 0xff00) >> 8) | ((v & 0x00ff) << 8);
725 }
726
727 inline quint16LE(int v) {
728 data = ((v & 0xff00) >> 8) | ((v & 0x00ff) << 8);
729 }
730
731 inline quint16LE(quint16 v) {
732 data = ((v & 0xff00) >> 8) | ((v & 0x00ff) << 8);
733 }
734
735 inline quint16LE(qrgb555 v) {
736 data = (( (quint16)v & 0xff00) >> 8) |
737 (( (quint16)v & 0x00ff) << 8);
738 }
739
740 inline bool operator==(const quint16LE &v) const
741 {
742 return data == v.data;
743 }
744
745private:
746 quint16 data;
747};
748#endif
749
750#ifdef QT_QWS_DEPTH_16
751static void blit_16(QScreen *screen, const QImage &image,
752 const QPoint &topLeft, const QRegion &region)
753{
754 switch (image.format()) {
755 case QImage::Format_RGB32:
756 case QImage::Format_ARGB32:
757 case QImage::Format_ARGB32_Premultiplied:
758 // ### This probably doesn't work but it's a case which should never happen
759 blit_template<quint16, quint32>(screen, image, topLeft, region);
760 return;
761 case QImage::Format_RGB16:
762 blit_template<quint16, quint16>(screen, image, topLeft, region);
763 return;
764 default:
765 qCritical("blit_16(): Image format %d not supported!", image.format());
766 }
767}
768
769#if Q_BYTE_ORDER == Q_BIG_ENDIAN
770static void blit_16_bigToLittleEndian(QScreen *screen, const QImage &image,
771 const QPoint &topLeft,
772 const QRegion &region)
773{
774 switch (image.format()) {
775 case QImage::Format_RGB32:
776 case QImage::Format_ARGB32:
777 case QImage::Format_ARGB32_Premultiplied:
778 blit_template<quint16LE, quint32>(screen, image, topLeft, region);
779 return;
780 case QImage::Format_RGB16:
781 blit_template<quint16LE, quint16>(screen, image, topLeft, region);
782 return;
783 default:
784 qCritical("blit_16_bigToLittleEndian(): Image format %d not supported!", image.format());
785 }
786}
787
788#endif // Q_BIG_ENDIAN
789#endif // QT_QWS_DEPTH_16
790
791#ifdef QT_QWS_DEPTH_15
792static void blit_15(QScreen *screen, const QImage &image,
793 const QPoint &topLeft, const QRegion &region)
794{
795 switch (image.format()) {
796 case QImage::Format_RGB32:
797 case QImage::Format_ARGB32:
798 case QImage::Format_ARGB32_Premultiplied:
799 blit_template<qrgb555, quint32>(screen, image, topLeft, region);
800 return;
801 case QImage::Format_RGB555:
802 blit_template<qrgb555, qrgb555>(screen, image, topLeft, region);
803 return;
804 case QImage::Format_RGB16:
805 blit_template<qrgb555, quint16>(screen, image, topLeft, region);
806 return;
807 default:
808 qCritical("blit_15(): Image format %d not supported!", image.format());
809 }
810}
811
812#if Q_BYTE_ORDER == Q_BIG_ENDIAN
813static void blit_15_bigToLittleEndian(QScreen *screen, const QImage &image,
814 const QPoint &topLeft,
815 const QRegion &region)
816{
817 switch (image.format()) {
818 case QImage::Format_RGB555:
819 blit_template<quint16LE, qrgb555>(screen, image, topLeft, region);
820 return;
821 default:
822 qCritical("blit_15_bigToLittleEndian(): Image format %d not supported!", image.format());
823 }
824}
825#endif // Q_BIG_ENDIAN
826#endif // QT_QWS_DEPTH_15
827
828
829#ifdef QT_QWS_DEPTH_12
830static void blit_12(QScreen *screen, const QImage &image,
831 const QPoint &topLeft, const QRegion &region)
832{
833 switch (image.format()) {
834 case QImage::Format_ARGB4444_Premultiplied:
835 blit_template<qrgb444, qargb4444>(screen, image, topLeft, region);
836 return;
837 case QImage::Format_RGB444:
838 blit_template<qrgb444, qrgb444>(screen, image, topLeft, region);
839 return;
840 default:
841 qCritical("blit_12(): Image format %d not supported!", image.format());
842 }
843}
844#endif // QT_QWS_DEPTH_12
845
846#ifdef QT_QWS_DEPTH_8
847static void blit_8(QScreen *screen, const QImage &image,
848 const QPoint &topLeft, const QRegion &region)
849{
850 switch (image.format()) {
851 case QImage::Format_RGB32:
852 case QImage::Format_ARGB32:
853 case QImage::Format_ARGB32_Premultiplied:
854 blit_template<quint8, quint32>(screen, image, topLeft, region);
855 return;
856 case QImage::Format_RGB16:
857 blit_template<quint8, quint16>(screen, image, topLeft, region);
858 return;
859 case QImage::Format_ARGB4444_Premultiplied:
860 blit_template<quint8, qargb4444>(screen, image, topLeft, region);
861 return;
862 case QImage::Format_RGB444:
863 blit_template<quint8, qrgb444>(screen, image, topLeft, region);
864 return;
865 default:
866 qCritical("blit_8(): Image format %d not supported!", image.format());
867 }
868}
869#endif // QT_QWS_DEPTH_8
870
871#ifdef QT_QWS_DEPTH_4
872
873struct qgray4 { quint8 dummy; } Q_PACKED;
874
875template <typename SRC>
876Q_STATIC_TEMPLATE_FUNCTION inline quint8 qt_convertToGray4(SRC color);
877
878template <>
879inline quint8 qt_convertToGray4(quint32 color)
880{
881 return qGray(color) >> 4;
882}
883
884template <>
885inline quint8 qt_convertToGray4(quint16 color)
886{
887 const int r = (color & 0xf800) >> 11;
888 const int g = (color & 0x07e0) >> 6; // only keep 5 bit
889 const int b = (color & 0x001f);
890 return (r * 11 + g * 16 + b * 5) >> 6;
891}
892
893template <>
894inline quint8 qt_convertToGray4(qrgb444 color)
895{
896 return qt_convertToGray4(quint32(color));
897}
898
899template <>
900inline quint8 qt_convertToGray4(qargb4444 color)
901{
902 return qt_convertToGray4(quint32(color));
903}
904
905template <typename SRC>
906Q_STATIC_TEMPLATE_FUNCTION inline void qt_rectconvert_gray4(qgray4 *dest4, const SRC *src,
907 int x, int y, int width, int height,
908 int dstStride, int srcStride)
909{
910 const int pixelsPerByte = 2;
911 quint8 *dest8 = reinterpret_cast<quint8*>(dest4)
912 + y * dstStride + x / pixelsPerByte;
913 const int doAlign = x & 1;
914 const int doTail = (width - doAlign) & 1;
915 const int width8 = (width - doAlign) / pixelsPerByte;
916 const int count8 = (width8 + 3) / 4;
917
918 srcStride = srcStride / sizeof(SRC) - width;
919 dstStride -= (width8 + doAlign);
920
921 for (int i = 0; i < height; ++i) {
922 if (doAlign) {
923 *dest8 = (*dest8 & 0xf0) | qt_convertToGray4<SRC>(*src++);
924 ++dest8;
925 }
926 if (count8) {
927 int n = count8;
928 switch (width8 & 0x03) // duff's device
929 {
930 case 0: do { *dest8++ = qt_convertToGray4<SRC>(src[0]) << 4
931 | qt_convertToGray4<SRC>(src[1]);
932 src += 2;
933 case 3: *dest8++ = qt_convertToGray4<SRC>(src[0]) << 4
934 | qt_convertToGray4<SRC>(src[1]);
935 src += 2;
936 case 2: *dest8++ = qt_convertToGray4<SRC>(src[0]) << 4
937 | qt_convertToGray4<SRC>(src[1]);
938 src += 2;
939 case 1: *dest8++ = qt_convertToGray4<SRC>(src[0]) << 4
940 | qt_convertToGray4<SRC>(src[1]);
941 src += 2;
942 } while (--n > 0);
943 }
944 }
945
946 if (doTail)
947 *dest8 = qt_convertToGray4<SRC>(*src++) << 4 | (*dest8 & 0x0f);
948
949 dest8 += dstStride;
950 src += srcStride;
951 }
952}
953
954template <>
955void qt_rectconvert(qgray4 *dest, const quint32 *src,
956 int x, int y, int width, int height,
957 int dstStride, int srcStride)
958{
959 qt_rectconvert_gray4<quint32>(dest, src, x, y, width, height,
960 dstStride, srcStride);
961}
962
963template <>
964void qt_rectconvert(qgray4 *dest, const quint16 *src,
965 int x, int y, int width, int height,
966 int dstStride, int srcStride)
967{
968 qt_rectconvert_gray4<quint16>(dest, src, x, y, width, height,
969 dstStride, srcStride);
970}
971
972template <>
973void qt_rectconvert(qgray4 *dest, const qrgb444 *src,
974 int x, int y, int width, int height,
975 int dstStride, int srcStride)
976{
977 qt_rectconvert_gray4<qrgb444>(dest, src, x, y, width, height,
978 dstStride, srcStride);
979}
980
981template <>
982void qt_rectconvert(qgray4 *dest, const qargb4444 *src,
983 int x, int y, int width, int height,
984 int dstStride, int srcStride)
985{
986 qt_rectconvert_gray4<qargb4444>(dest, src, x, y, width, height,
987 dstStride, srcStride);
988}
989
990static void blit_4(QScreen *screen, const QImage &image,
991 const QPoint &topLeft, const QRegion &region)
992{
993 switch (image.format()) {
994 case QImage::Format_ARGB32_Premultiplied:
995 blit_template<qgray4, quint32>(screen, image, topLeft, region);
996 return;
997 case QImage::Format_RGB16:
998 blit_template<qgray4, quint16>(screen, image, topLeft, region);
999 return;
1000 case QImage::Format_RGB444:
1001 blit_template<qgray4, qrgb444>(screen, image, topLeft, region);
1002 return;
1003 case QImage::Format_ARGB4444_Premultiplied:
1004 blit_template<qgray4, qargb4444>(screen, image, topLeft, region);
1005 return;
1006 default:
1007 qCritical("blit_4(): Image format %d not supported!", image.format());
1008 }
1009}
1010#endif // QT_QWS_DEPTH_4
1011
1012#ifdef QT_QWS_DEPTH_1
1013
1014struct qmono { quint8 dummy; } Q_PACKED;
1015
1016template <typename SRC>
1017Q_STATIC_TEMPLATE_FUNCTION inline quint8 qt_convertToMono(SRC color);
1018
1019template <>
1020inline quint8 qt_convertToMono(quint32 color)
1021{
1022 return qGray(color) >> 7;
1023}
1024
1025template <>
1026inline quint8 qt_convertToMono(quint16 color)
1027{
1028 return (qGray(qt_colorConvert<quint32, quint16>(color, 0)) >> 7);
1029}
1030
1031template <>
1032inline quint8 qt_convertToMono(qargb4444 color)
1033{
1034 return (qGray(quint32(color)) >> 7);
1035}
1036
1037template <>
1038inline quint8 qt_convertToMono(qrgb444 color)
1039{
1040 return (qGray(quint32(color)) >> 7);
1041}
1042
1043template <typename SRC>
1044inline void qt_rectconvert_mono(qmono *dest, const SRC *src,
1045 int x, int y, int width, int height,
1046 int dstStride, int srcStride)
1047{
1048 const int pixelsPerByte = 8;
1049 quint8 *dest8 = reinterpret_cast<quint8*>(dest)
1050 + y * dstStride + x / pixelsPerByte;
1051 const int alignWidth = qMin(width, (8 - (x & 7)) & 7);
1052 const int doAlign = (alignWidth > 0 ? 1 : 0);
1053 const int alignStart = pixelsPerByte - 1 - (x & 7);
1054 const int alignStop = alignStart - (alignWidth - 1);
1055 const quint8 alignMask = ((1 << alignWidth) - 1) << alignStop;
1056 const int tailWidth = (width - alignWidth) & 7;
1057 const int doTail = (tailWidth > 0 ? 1 : 0);
1058 const quint8 tailMask = (1 << (pixelsPerByte - tailWidth)) - 1;
1059 const int width8 = (width - alignWidth) / pixelsPerByte;
1060
1061 srcStride = srcStride / sizeof(SRC) - (width8 * 8 + alignWidth);
1062 dstStride -= (width8 + doAlign);
1063
1064 for (int j = 0; j < height; ++j) {
1065 if (doAlign) {
1066 quint8 d = *dest8 & ~alignMask;
1067 for (int i = alignStart; i >= alignStop; --i)
1068 d |= qt_convertToMono<SRC>(*src++) << i;
1069 *dest8++ = d;
1070 }
1071 for (int i = 0; i < width8; ++i) {
1072 *dest8 = (qt_convertToMono<SRC>(src[0]) << 7)
1073 | (qt_convertToMono<SRC>(src[1]) << 6)
1074 | (qt_convertToMono<SRC>(src[2]) << 5)
1075 | (qt_convertToMono<SRC>(src[3]) << 4)
1076 | (qt_convertToMono<SRC>(src[4]) << 3)
1077 | (qt_convertToMono<SRC>(src[5]) << 2)
1078 | (qt_convertToMono<SRC>(src[6]) << 1)
1079 | (qt_convertToMono<SRC>(src[7]));
1080 src += 8;
1081 ++dest8;
1082 }
1083 if (doTail) {
1084 quint8 d = *dest8 & tailMask;
1085 switch (tailWidth) {
1086 case 7: d |= qt_convertToMono<SRC>(src[6]) << 1;
1087 case 6: d |= qt_convertToMono<SRC>(src[5]) << 2;
1088 case 5: d |= qt_convertToMono<SRC>(src[4]) << 3;
1089 case 4: d |= qt_convertToMono<SRC>(src[3]) << 4;
1090 case 3: d |= qt_convertToMono<SRC>(src[2]) << 5;
1091 case 2: d |= qt_convertToMono<SRC>(src[1]) << 6;
1092 case 1: d |= qt_convertToMono<SRC>(src[0]) << 7;
1093 }
1094 *dest8 = d;
1095 }
1096
1097 dest8 += dstStride;
1098 src += srcStride;
1099 }
1100}
1101
1102template <>
1103void qt_rectconvert(qmono *dest, const quint32 *src,
1104 int x, int y, int width, int height,
1105 int dstStride, int srcStride)
1106{
1107 qt_rectconvert_mono<quint32>(dest, src, x, y, width, height,
1108 dstStride, srcStride);
1109}
1110
1111template <>
1112void qt_rectconvert(qmono *dest, const quint16 *src,
1113 int x, int y, int width, int height,
1114 int dstStride, int srcStride)
1115{
1116 qt_rectconvert_mono<quint16>(dest, src, x, y, width, height,
1117 dstStride, srcStride);
1118}
1119
1120template <>
1121void qt_rectconvert(qmono *dest, const qrgb444 *src,
1122 int x, int y, int width, int height,
1123 int dstStride, int srcStride)
1124{
1125 qt_rectconvert_mono<qrgb444>(dest, src, x, y, width, height,
1126 dstStride, srcStride);
1127}
1128
1129template <>
1130void qt_rectconvert(qmono *dest, const qargb4444 *src,
1131 int x, int y, int width, int height,
1132 int dstStride, int srcStride)
1133{
1134 qt_rectconvert_mono<qargb4444>(dest, src, x, y, width, height,
1135 dstStride, srcStride);
1136}
1137
1138static void blit_1(QScreen *screen, const QImage &image,
1139 const QPoint &topLeft, const QRegion &region)
1140{
1141 switch (image.format()) {
1142 case QImage::Format_ARGB32_Premultiplied:
1143 blit_template<qmono, quint32>(screen, image, topLeft, region);
1144 return;
1145 case QImage::Format_RGB16:
1146 blit_template<qmono, quint16>(screen, image, topLeft, region);
1147 return;
1148 case QImage::Format_RGB444:
1149 blit_template<qmono, qrgb444>(screen, image, topLeft, region);
1150 return;
1151 case QImage::Format_ARGB4444_Premultiplied:
1152 blit_template<qmono, qargb4444>(screen, image, topLeft, region);
1153 return;
1154 default:
1155 qCritical("blit_1(): Image format %d not supported!", image.format());
1156 }
1157}
1158#endif // QT_QWS_DEPTH_1
1159
1160#ifdef QT_QWS_DEPTH_GENERIC
1161
1162static void blit_rgb(QScreen *screen, const QImage &image,
1163 const QPoint &topLeft, const QRegion &region)
1164{
1165 switch (image.format()) {
1166 case QImage::Format_ARGB32_Premultiplied:
1167 blit_template<qrgb, quint32>(screen, image, topLeft, region);
1168 return;
1169 case QImage::Format_RGB16:
1170 blit_template<qrgb, quint16>(screen, image, topLeft, region);
1171 return;
1172 default:
1173 qCritical("blit_rgb(): Image format %d not supported!", image.format());
1174 }
1175}
1176
1177void qt_set_generic_blit(QScreen *screen, int bpp,
1178 int len_red, int len_green, int len_blue, int len_alpha,
1179 int off_red, int off_green, int off_blue, int off_alpha)
1180{
1181 qrgb::bpp = bpp / 8;
1182 qrgb::len_red = len_red;
1183 qrgb::len_green = len_green;
1184 qrgb::len_blue = len_blue;
1185 qrgb::len_alpha = len_alpha;
1186 qrgb::off_red = off_red;
1187 qrgb::off_green = off_green;
1188 qrgb::off_blue = off_blue;
1189 qrgb::off_alpha = off_alpha;
1190 screen->d_ptr->blit = blit_rgb;
1191 if (bpp == 16)
1192 screen->d_ptr->solidFill = solidFill_rgb_16bpp;
1193 else if (bpp == 32)
1194 screen->d_ptr->solidFill = solidFill_rgb_32bpp;
1195}
1196
1197#endif // QT_QWS_DEPTH_GENERIC
1198
1199void qt_blit_setup(QScreen *screen, const QImage &image,
1200 const QPoint &topLeft, const QRegion &region)
1201{
1202 switch (screen->depth()) {
1203#ifdef QT_QWS_DEPTH_32
1204 case 32:
1205 if (screen->pixelType() == QScreen::NormalPixel)
1206 screen->d_ptr->blit = blit_32;
1207 else
1208 screen->d_ptr->blit = blit_template<qabgr8888, quint32>;
1209 break;
1210#endif
1211#ifdef QT_QWS_DEPTH_24
1212 case 24:
1213 if (screen->pixelType() == QScreen::NormalPixel)
1214 screen->d_ptr->blit = blit_qrgb888;
1215 else
1216 screen->d_ptr->blit = blit_24;
1217 break;
1218#endif
1219#ifdef QT_QWS_DEPTH_18
1220 case 18:
1221 screen->d_ptr->blit = blit_18;