summaryrefslogtreecommitdiffstats
path: root/src/gui
diff options
context:
space:
mode:
authorJoão Abecasis <joao.abecasis@nokia.com>2012-02-21 14:58:57 +0100
committerJoão Abecasis <joao.abecasis@nokia.com>2012-02-21 14:58:57 +0100
commit31a0358afb4fde998d1eeeaa80fc32e4420266c7 (patch)
tree938455353474196c1f49b0529b5b644e19c21f3e /src/gui
parent4c8a4058c359c8d163c643120426079fc80c8214 (diff)
parent69da8588d41bbf5ab785f5ad7c1fce76deefc7d0 (diff)
Merge remote-tracking branch 'gerrit/master' into containers
Conflicts: src/corelib/tools/qbytearray.h Change-Id: I03b1f3e05c9b7a45130887c522fcd9b7aa387129
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/accessible/qaccessible.cpp161
-rw-r--r--src/gui/accessible/qaccessible.h16
-rw-r--r--src/gui/accessible/qaccessibleobject.cpp25
-rw-r--r--src/gui/accessible/qaccessibleobject.h2
-rw-r--r--src/gui/image/image.pri1
-rw-r--r--src/gui/image/qbitmap.cpp1
-rw-r--r--src/gui/image/qimage.cpp511
-rw-r--r--src/gui/image/qjpeghandler.cpp9
-rw-r--r--src/gui/image/qnativeimage.cpp1
-rw-r--r--src/gui/image/qpixmap.cpp21
-rw-r--r--src/gui/image/qpixmap.h1
-rw-r--r--src/gui/image/qpixmap_blitter.cpp26
-rw-r--r--src/gui/image/qpixmap_raster.cpp42
-rw-r--r--src/gui/image/qpixmap_win.cpp179
-rw-r--r--src/gui/image/qplatformpixmap.cpp1
-rw-r--r--src/gui/kernel/kernel.pri6
-rw-r--r--src/gui/kernel/qclipboard_qpa.cpp1
-rw-r--r--src/gui/kernel/qdnd.cpp1
-rw-r--r--src/gui/kernel/qevent.cpp12
-rw-r--r--src/gui/kernel/qguiapplication.cpp116
-rw-r--r--src/gui/kernel/qguiapplication.h4
-rw-r--r--src/gui/kernel/qguiapplication_p.h17
-rw-r--r--src/gui/kernel/qinputmethod_p.h1
-rw-r--r--src/gui/kernel/qopenglcontext.cpp3
-rw-r--r--src/gui/kernel/qopenglcontext_p.h3
-rw-r--r--src/gui/kernel/qpalette.cpp62
-rw-r--r--src/gui/kernel/qplatformintegration_qpa.cpp7
-rw-r--r--src/gui/kernel/qplatformintegration_qpa.h5
-rw-r--r--src/gui/kernel/qplatformintegrationplugin_qpa.h2
-rw-r--r--src/gui/kernel/qplatformopenglcontext_qpa.h3
-rw-r--r--src/gui/kernel/qplatformscreen_qpa.cpp2
-rw-r--r--src/gui/kernel/qplatformservices_qpa.cpp (renamed from src/gui/image/qpixmap_qpa.cpp)31
-rw-r--r--src/gui/kernel/qplatformservices_qpa.h (renamed from src/gui/util/qdesktopservices_qpa.cpp)30
-rw-r--r--src/gui/kernel/qplatformtheme_qpa.cpp36
-rw-r--r--src/gui/kernel/qplatformtheme_qpa.h19
-rw-r--r--src/gui/kernel/qplatformthemeplugin_qpa.h2
-rw-r--r--src/gui/kernel/qplatformwindow_qpa.cpp19
-rw-r--r--src/gui/kernel/qplatformwindow_qpa.h2
-rw-r--r--src/gui/kernel/qscreen.cpp48
-rw-r--r--src/gui/kernel/qscreen.h3
-rw-r--r--src/gui/kernel/qwindow.cpp94
-rw-r--r--src/gui/kernel/qwindow.h8
-rw-r--r--src/gui/kernel/qwindowdefs.h3
-rw-r--r--src/gui/kernel/qwindowsysteminterface_qpa.cpp22
-rw-r--r--src/gui/kernel/qwindowsysteminterface_qpa.h4
-rw-r--r--src/gui/kernel/qwindowsysteminterface_qpa_p.h8
-rw-r--r--src/gui/opengl/qopenglbuffer.cpp12
-rw-r--r--src/gui/opengl/qopenglframebufferobject.cpp107
-rw-r--r--src/gui/opengl/qopenglframebufferobject.h2
-rw-r--r--src/gui/opengl/qopenglframebufferobject_p.h4
-rw-r--r--src/gui/opengl/qopenglgradientcache_p.h2
-rw-r--r--src/gui/opengl/qopengltexturecache_p.h2
-rw-r--r--src/gui/painting/painting.pri6
-rw-r--r--src/gui/painting/qbackingstore.cpp1
-rw-r--r--src/gui/painting/qblendfunctions.cpp208
-rw-r--r--src/gui/painting/qdrawhelper.cpp3818
-rw-r--r--src/gui/painting/qdrawhelper_neon.cpp2
-rw-r--r--src/gui/painting/qdrawhelper_p.h1361
-rw-r--r--src/gui/painting/qdrawhelper_sse2.cpp7
-rw-r--r--src/gui/painting/qdrawhelper_sse_p.h2
-rw-r--r--src/gui/painting/qmemrotate.cpp380
-rw-r--r--src/gui/painting/qmemrotate_p.h38
-rw-r--r--src/gui/painting/qpathsimplifier.cpp1673
-rw-r--r--src/gui/painting/qpathsimplifier_p.h68
-rw-r--r--src/gui/painting/qstroker.cpp4
-rw-r--r--src/gui/text/qabstracttextdocumentlayout.cpp2
-rw-r--r--src/gui/text/qdistancefield.cpp762
-rw-r--r--src/gui/text/qdistancefield_p.h85
-rw-r--r--src/gui/text/qfont.cpp14
-rw-r--r--src/gui/text/qfont_p.h1
-rw-r--r--src/gui/text/qfont_qpa.cpp1
-rw-r--r--src/gui/text/qfontdatabase.cpp51
-rw-r--r--src/gui/text/qfontdatabase_qpa.cpp74
-rw-r--r--src/gui/text/qfontengine.cpp37
-rw-r--r--src/gui/text/qfontengine_ft.cpp14
-rw-r--r--src/gui/text/qfontengine_ft_p.h1
-rw-r--r--src/gui/text/qfontengine_p.h3
-rw-r--r--src/gui/text/qfontengine_qpa_p.h5
-rw-r--r--src/gui/text/qfontenginedirectwrite.cpp4
-rw-r--r--src/gui/text/qfontmetrics.cpp8
-rw-r--r--src/gui/text/qplatformfontdatabase_qpa.cpp12
-rw-r--r--src/gui/text/qplatformfontdatabase_qpa.h2
-rw-r--r--src/gui/text/qrawfont_qpa.cpp1
-rw-r--r--src/gui/text/qtextcursor.cpp26
-rw-r--r--src/gui/text/qtextdocumentlayout.cpp6
-rw-r--r--src/gui/text/qtextengine.cpp42
-rw-r--r--src/gui/text/qtextengine_p.h6
-rw-r--r--src/gui/text/qtextlayout.cpp8
-rw-r--r--src/gui/text/text.pri6
-rw-r--r--src/gui/util/qdesktopservices.cpp22
-rw-r--r--src/gui/util/qdesktopservices_mac.cpp127
-rw-r--r--src/gui/util/qdesktopservices_win.cpp177
-rw-r--r--src/gui/util/qdesktopservices_x11.cpp131
93 files changed, 5484 insertions, 5412 deletions
diff --git a/src/gui/accessible/qaccessible.cpp b/src/gui/accessible/qaccessible.cpp
index 8610ef726d..0d00df2a17 100644
--- a/src/gui/accessible/qaccessible.cpp
+++ b/src/gui/accessible/qaccessible.cpp
@@ -49,6 +49,7 @@
#include <QtGui/QGuiApplication>
#include <private/qguiapplication_p.h>
#include "qplatformaccessibility_qpa.h"
+#include "qplatformintegration_qpa.h"
#include <QtCore/qdebug.h>
#include <QtCore/qmetaobject.h>
@@ -359,29 +360,13 @@ QT_BEGIN_NAMESPACE
This enum type defines bit flags that can be combined to indicate
the relationship between two accessible objects.
- \value Unrelated The objects are unrelated.
- \value Self The objects are the same.
-
- \value Up The first object is above the second object.
- \value Down The first object is below the second object.
- \value Left The first object is left of the second object.
- \value Right The first object is right of the second object.
- \value Covers The first object covers the second object.
- \value Covered The first object is covered by the second object.
-
- \value FocusChild The first object is the second object's focus child.
\value Label The first object is the label of the second object.
\value Labelled The first object is labelled by the second object.
\value Controller The first object controls the second object.
\value Controlled The first object is controlled by the second object.
- \omitvalue GeometryMask
- \omitvalue LogicalMask
-
- Implementations of relationTo() return a combination of these flags.
+ Implementations of relations() return a combination of these flags.
Some values are mutually exclusive.
-
- Implementations of navigate() can accept only one distinct value.
*/
/*!
@@ -781,10 +766,9 @@ QAccessibleInterface *QAccessibleEvent::accessibleInterface() const
top-most child. childAt() is used for hit testing (finding the object
under the mouse).
- The relationTo() function provides information about how two
- different objects relate to each other, and navigate() allows
- traversing from one object to another object with a given
- relationship.
+ The relations() function provides information about the relations an
+ object has to other objects, and parent() and child() allows
+ traversing from one object to another object.
\section1 Properties
@@ -874,39 +858,27 @@ QAccessibleInterface *QAccessibleEvent::accessibleInterface() const
*/
/*!
- \fn QAccessible::Relation QAccessibleInterface::relationTo(const QAccessibleInterface *other) const
-
- Returns the relationship between this object and the \a
- other object.
-
- The returned value indicates the relation of the called object to
- the \a other object, e.g. if this object is a label for \a other
- the return value will be \c Label.
-
- Usually parent-child relations are not returned.
-
- The return value is a combination of the bit flags in the
- QAccessible::Relation enumeration.
-
- All objects provide this information.
+ Returns the meaningful relations to other widgets. Usually this will not return parent/child
+ relations, unless they are handled in a specific way such as in tree views.
+ It will typically return the labelled-by and label relations.
+ It should never return itself.
- \sa relations(), indexOfChild(), navigate()
+ \sa parent(), child()
*/
-QAccessible::Relation QAccessibleInterface::relationTo(const QAccessibleInterface *) const
+QVector<QPair<QAccessibleInterface*, QAccessible::Relation> >
+QAccessibleInterface::relations(QAccessible::Relation /*match = QAccessible::AllRelations*/) const
{
- return QAccessible::Unrelated;
+ return QVector<QPair<QAccessibleInterface*, QAccessible::Relation> >();
}
/*!
- Returns the meaningful relations to other widgets. Usually this will not return parent/child
- relations, unless they are handled in a specific way such as in tree views.
- It will typically return the labelled-by and label relations.
+ Returns the object that has the keyboard focus.
- \sa relationTo(), navigate()
+ The object returned can be any descendant, including itself.
*/
-QVector<QPair<QAccessibleInterface*, QAccessible::Relation> > QAccessibleInterface::relations() const
+QAccessibleInterface *QAccessibleInterface::focusChild() const
{
- return QVector<QPair<QAccessibleInterface*, QAccessible::Relation> >();
+ return 0;
}
/*!
@@ -950,49 +922,6 @@ QVector<QPair<QAccessibleInterface*, QAccessible::Relation> > QAccessibleInterfa
*/
/*!
- \fn int QAccessibleInterface::navigate(QAccessible::RelationFlag relation, int entry, QAccessibleInterface **target) const
-
- Navigates from this object to an object that has a relationship
- \a relation to this object, and returns the respective object in
- \a target. It is the caller's responsibility to delete *\a target
- after use.
-
- If an object is found, \a target is set to point to the object, and
- the index of the child of \a target is returned. The return value
- is 0 if \a target itself is the requested object. \a target is set
- to null if this object is the target object (i.e. the requested
- object is a handled by this object).
-
- If no object is found \a target is set to null, and the return
- value is -1.
-
- The \a entry parameter has two different meanings:
- \list
- \i \e{Hierarchical and Logical relationships} -- if multiple objects with
- the requested relationship exist \a entry specifies which one to
- return. \a entry is 1-based, e.g. use 1 to get the first (and
- possibly only) object with the requested relationship.
-
- The following code demonstrates how to use this function to
- navigate to the first child of an object:
-
- \snippet doc/src/snippets/code/src_gui_accessible_qaccessible.cpp 0
-
- \i \e{Geometric relationships} -- the index of the child from
- which to start navigating in the specified direction. \a entry
- can be 0 to navigate to a sibling of this object, or non-null to
- navigate within contained children that don't provide their own
- accessible information.
- \endlist
-
- Note that the \c Descendent value for \a relation is not supported.
-
- All objects support navigation.
-
- \sa relationTo(), childCount(), parent(), child()
-*/
-
-/*!
\fn QString QAccessibleInterface::text(QAccessible::Text t) const
Returns the value of the text property \a t of the object.
@@ -1140,60 +1069,24 @@ QColor QAccessibleInterface::backgroundColor() const
/*!
\class QAccessibleEvent
- \internal
-
- \brief The QAccessibleEvent class is used to query addition
- accessibility information about complex widgets.
-
- The event can be of type QEvent::AccessibilityDescription or
- QEvent::AccessibilityHelp.
+ \brief The QAccessibleEvent class is used to give detailed updates to the
+ accessibility framework. It is used together with \l QAccessible::updateAccessibility.
- Some QAccessibleInterface implementations send QAccessibleEvents
- to the widget they wrap to obtain the description or help text of
- a widget or of its children. The widget can answer by calling
- setValue() with the requested information.
-
- The default QWidget::event() implementation simply sets the text
- to be the widget's \l{QWidget::toolTip}{tooltip} (for \l
- AccessibilityDescription event) or its
- \l{QWidget::whatsThis}{"What's This?" text} (for \l
- AccessibilityHelp event).
+ The event is one of the \l QAccessible::Event which depending on the type of event needs to use
+ one of the subclasses of QAccessibleEvent.
\ingroup accessibility
- \ingroup events
- \inmodule QtWidgets
-*/
-
-/*!
- \fn QAccessibleEvent::QAccessibleEvent(Type type)
-
- Constructs an accessibility event of the given \a type, which
- must be QEvent::AccessibilityDescription or
- QEvent::AccessibilityHelp.
-*/
-
-/*!
- \fn int QAccessibleEvent::child() const
-
- Returns the (1-based) index of the child to which the request
- applies. If the child is 0, the request is for the widget itself.
-*/
-
-/*!
- \fn QString QAccessibleEvent::value() const
-
- Returns the text set using setValue().
-
- \sa setValue()
+ \inmodule QtGui
*/
/*!
- \fn void QAccessibleEvent::setValue(const QString &text)
+ \fn QAccessibleEvent::QAccessibleEvent(QAccessible::Event type, QObject *object, int child = -1)
- Set the description or help text for the given child() to \a
- text, thereby answering the request.
+ Constructs an accessibility event of the given \a type.
+ It also requires an \a object as source of the event and optionally a \a child index,
+ if the event comes from a child of the object.
- \sa value()
+ Using a \a child index maybe more efficient than creating the accessible interface for the child.
*/
/*!
diff --git a/src/gui/accessible/qaccessible.h b/src/gui/accessible/qaccessible.h
index dc74ac1814..e57033d9bf 100644
--- a/src/gui/accessible/qaccessible.h
+++ b/src/gui/accessible/qaccessible.h
@@ -291,6 +291,7 @@ public:
Splitter = 0x0000003E,
// Additional Qt roles where enum value does not map directly to MSAA:
LayeredPane = 0x0000003F,
+ Terminal = 0x00000040,
UserRole = 0x0000ffff
};
@@ -305,13 +306,11 @@ public:
};
enum RelationFlag {
- Unrelated = 0x00000000,
- FocusChild = 0x00010000,
Label = 0x00020000,
Labelled = 0x00040000,
Controller = 0x00080000,
Controlled = 0x00100000,
- LogicalMask = 0x00ff0000
+ AllRelations = 0xffffffff
};
Q_DECLARE_FLAGS(Relation, RelationFlag)
@@ -379,8 +378,8 @@ public:
virtual QWindow *window() const;
// relations
- virtual QAccessible::Relation relationTo(const QAccessibleInterface *other) const;
- virtual QVector<QPair<QAccessibleInterface*, QAccessible::Relation> > relations() const;
+ virtual QVector<QPair<QAccessibleInterface*, QAccessible::Relation> > relations(QAccessible::Relation match = QAccessible::AllRelations) const;
+ virtual QAccessibleInterface *focusChild() const;
virtual QAccessibleInterface *childAt(int x, int y) const = 0;
@@ -389,7 +388,6 @@ public:
virtual QAccessibleInterface *child(int index) const = 0;
virtual int childCount() const = 0;
virtual int indexOfChild(const QAccessibleInterface *) const = 0;
- virtual int navigate(QAccessible::RelationFlag relation, int index, QAccessibleInterface **iface) const = 0;
// properties and state
virtual QString text(QAccessible::Text t) const = 0;
@@ -432,10 +430,10 @@ private:
class Q_GUI_EXPORT QAccessibleEvent
{
public:
- inline QAccessibleEvent(QAccessible::Event type, QObject *object, int child = -1)
- : m_type(type), m_object(object), m_child(child)
+ inline QAccessibleEvent(QAccessible::Event typ, QObject *obj, int chld = -1)
+ : m_type(typ), m_object(obj), m_child(chld)
{
- Q_ASSERT(object);
+ Q_ASSERT(obj);
}
QAccessible::Event type() const { return m_type; }
diff --git a/src/gui/accessible/qaccessibleobject.cpp b/src/gui/accessible/qaccessibleobject.cpp
index b9e0ac388b..d277f39c43 100644
--- a/src/gui/accessible/qaccessibleobject.cpp
+++ b/src/gui/accessible/qaccessibleobject.cpp
@@ -237,28 +237,13 @@ QAccessibleInterface *QAccessibleApplication::child(int index) const
return 0;
}
+
/*! \reimp */
-int QAccessibleApplication::navigate(QAccessible::RelationFlag relation, int,
- QAccessibleInterface **target) const
+QAccessibleInterface *QAccessibleApplication::focusChild() const
{
- if (!target)
- return -1;
-
- *target = 0;
- QObject *targetObject = 0;
-
- switch (relation) {
- case QAccessible::FocusChild:
- if (QWindow *window = QGuiApplication::activeWindow()) {
- *target = window->accessibleRoot();
- return 0;
- }
- break;
- default:
- break;
- }
- *target = QAccessible::queryAccessibleInterface(targetObject);
- return *target ? 0 : -1;
+ if (QWindow *window = QGuiApplication::activeWindow())
+ return window->accessibleRoot();
+ return 0;
}
/*! \reimp */
diff --git a/src/gui/accessible/qaccessibleobject.h b/src/gui/accessible/qaccessibleobject.h
index 2372e82f89..d035f17b1d 100644
--- a/src/gui/accessible/qaccessibleobject.h
+++ b/src/gui/accessible/qaccessibleobject.h
@@ -85,11 +85,11 @@ public:
// relations
int childCount() const;
int indexOfChild(const QAccessibleInterface*) const;
+ QAccessibleInterface *focusChild() const;
// navigation
QAccessibleInterface *parent() const;
QAccessibleInterface *child(int index) const;
- int navigate(QAccessible::RelationFlag, int, QAccessibleInterface **) const;
// properties and state
QString text(QAccessible::Text t) const;
diff --git a/src/gui/image/image.pri b/src/gui/image/image.pri
index dd7b665ecc..f83e7e60c9 100644
--- a/src/gui/image/image.pri
+++ b/src/gui/image/image.pri
@@ -45,7 +45,6 @@ SOURCES += \
image/qimagepixmapcleanuphooks.cpp \
image/qvolatileimage.cpp
-SOURCES += image/qpixmap_qpa.cpp
win32: SOURCES += image/qpixmap_win.cpp
SOURCES += image/qvolatileimagedata.cpp
diff --git a/src/gui/image/qbitmap.cpp b/src/gui/image/qbitmap.cpp
index 8184200813..f3c26dd5b2 100644
--- a/src/gui/image/qbitmap.cpp
+++ b/src/gui/image/qbitmap.cpp
@@ -41,6 +41,7 @@
#include "qbitmap.h"
#include "qplatformpixmap_qpa.h"
+#include "qplatformintegration_qpa.h"
#include "qimage.h"
#include "qscreen.h"
#include "qvariant.h"
diff --git a/src/gui/image/qimage.cpp b/src/gui/image/qimage.cpp
index 07af19d06a..5b23dbf4dc 100644
--- a/src/gui/image/qimage.cpp
+++ b/src/gui/image/qimage.cpp
@@ -74,30 +74,6 @@ static inline bool isLocked(QImageData *data)
return data != 0 && data->is_locked;
}
-static inline bool checkPixelSize(const QImage::Format format)
-{
- switch (format) {
- case QImage::Format_ARGB8565_Premultiplied:
- return (sizeof(qargb8565) == 3);
- case QImage::Format_RGB666:
- return (sizeof(qrgb666) == 3);
- case QImage::Format_ARGB6666_Premultiplied:
- return (sizeof(qargb6666) == 3);
- case QImage::Format_RGB555:
- return (sizeof(qrgb555) == 2);
- case QImage::Format_ARGB8555_Premultiplied:
- return (sizeof(qargb8555) == 3);
- case QImage::Format_RGB888:
- return (sizeof(qrgb888) == 3);
- case QImage::Format_RGB444:
- return (sizeof(qrgb444) == 2);
- case QImage::Format_ARGB4444_Premultiplied:
- return (sizeof(qargb4444) == 2);
- default:
- return true;
- }
-}
-
#if defined(Q_CC_DEC) && defined(__alpha) && (__DECCXX_VER-0 >= 50190001)
#pragma message disable narrowptr
#endif
@@ -141,12 +117,6 @@ QImageData * QImageData::create(const QSize &size, QImage::Format format, int nu
if (!size.isValid() || numColors < 0 || format == QImage::Format_Invalid)
return 0; // invalid parameter(s)
- if (!checkPixelSize(format)) {
- qWarning("QImageData::create(): Invalid pixel size for format %i",
- format);
- return 0;
- }
-
uint width = size.width();
uint height = size.height();
uint depth = qt_depthForFormat(format);
@@ -793,12 +763,6 @@ QImageData *QImageData::create(uchar *data, int width, int height, int bpl, QIm
if (format == QImage::Format_Invalid)
return d;
- if (!checkPixelSize(format)) {
- qWarning("QImageData::create(): Invalid pixel size for format %i",
- format);
- return 0;
- }
-
const int depth = qt_depthForFormat(format);
const int calc_bytes_per_line = ((width * depth + 31)/32) * 4;
const int min_bytes_per_line = (width * depth + 7)/8;
@@ -1708,9 +1672,8 @@ void QImage::fill(const QColor &color)
pixel = PREMUL(pixel);
fill((uint) pixel);
- } else if (d->depth == 16 && d->format == QImage::Format_RGB16) {
- qrgb565 p(color.rgba());
- fill((uint) p.rawValue());
+ } else if (d->format == QImage::Format_RGB16) {
+ fill((uint) qConvertRgb32To16(color.rgba()));
} else if (d->depth == 1) {
if (color == Qt::color1)
@@ -2025,12 +1988,12 @@ static bool convert_indexed8_to_RGB16_inplace(QImageData *data, Qt::ImageConvers
quint16 colorTableRGB16[256];
if (data->colortable.isEmpty()) {
for (int i = 0; i < 256; ++i)
- colorTableRGB16[i] = qt_colorConvert<quint16, quint32>(qRgb(i, i, i), 0);
+ colorTableRGB16[i] = qConvertRgb32To16(qRgb(i, i, i));
} else {
// 1) convert the existing colors to RGB16
const int tableSize = data->colortable.size();
for (int i = 0; i < tableSize; ++i)
- colorTableRGB16[i] = qt_colorConvert<quint16, quint32>(data->colortable.at(i), 0);
+ colorTableRGB16[i] = qConvertRgb32To16(data->colortable.at(i));
data->colortable = QVector<QRgb>();
// 2) fill the rest of the table in case src_data > colortable.size()
@@ -2068,7 +2031,8 @@ static bool convert_RGB_to_RGB16_inplace(QImageData *data, Qt::ImageConversionFl
quint16 *dst_data = (quint16 *) data->data;
for (int i = 0; i < data->height; ++i) {
- qt_memconvert(dst_data, src_data, data->width);
+ for (int j = 0; j < data->width; ++j)
+ dst_data[j] = qConvertRgb32To16(src_data[j]);
src_data = (quint32 *) (((char*)src_data) + src_bytes_per_line);
dst_data = (quint16 *) (((char*)dst_data) + dst_bytes_per_line);
}
@@ -2878,60 +2842,33 @@ static void convert_Mono_to_Indexed8(QImageData *dest, const QImageData *src, Qt
}
}
-#define CONVERT_DECL(DST, SRC) \
- static void convert_##SRC##_to_##DST(QImageData *dest, \
- const QImageData *src, \
- Qt::ImageConversionFlags) \
- { \
- qt_rectconvert<DST, SRC>(reinterpret_cast<DST*>(dest->data), \
- reinterpret_cast<const SRC*>(src->data), \
- 0, 0, src->width, src->height, \
- dest->bytes_per_line, src->bytes_per_line); \
+// Cannot be used with indexed formats.
+static void convert_generic(QImageData *dest, const QImageData *src, Qt::ImageConversionFlags)
+{
+ const int buffer_size = 2048;
+ uint buffer[buffer_size];
+ const QPixelLayout *srcLayout = &qPixelLayouts[src->format];
+ const QPixelLayout *destLayout = &qPixelLayouts[dest->format];
+ const uchar *srcData = src->data;
+ uchar *destData = dest->data;
+
+ FetchPixelsFunc fetch = qFetchPixels[srcLayout->bpp];
+ StorePixelsFunc store = qStorePixels[destLayout->bpp];
+
+ for (int y = 0; y < src->height; ++y) {
+ int x = 0;
+ while (x < src->width) {
+ int l = qMin(src->width - x, buffer_size);
+ const uint *ptr = fetch(buffer, srcData, x, l);
+ ptr = srcLayout->convertToARGB32PM(buffer, ptr, l, srcLayout, 0);
+ ptr = destLayout->convertFromARGB32PM(buffer, ptr, l, destLayout, 0);
+ store(destData, ptr, x, l);
+ x += l;
+ }
+ srcData += src->bytes_per_line;
+ destData += dest->bytes_per_line;
}
-
-CONVERT_DECL(quint32, quint16)
-CONVERT_DECL(quint16, quint32)
-CONVERT_DECL(quint32, qargb8565)
-CONVERT_DECL(qargb8565, quint32)
-CONVERT_DECL(quint32, qrgb555)
-CONVERT_DECL(qrgb666, quint32)
-CONVERT_DECL(quint32, qrgb666)
-CONVERT_DECL(qargb6666, quint32)
-CONVERT_DECL(quint32, qargb6666)
-CONVERT_DECL(qrgb555, quint32)
-#if (defined(QT_QWS_DEPTH_15) && defined(QT_QWS_DEPTH_16))
-CONVERT_DECL(quint16, qrgb555)
-CONVERT_DECL(qrgb555, quint16)
-#endif
-CONVERT_DECL(quint32, qrgb888)
-CONVERT_DECL(qrgb888, quint32)
-CONVERT_DECL(quint32, qargb8555)
-CONVERT_DECL(qargb8555, quint32)
-CONVERT_DECL(quint32, qrgb444)
-CONVERT_DECL(qrgb444, quint32)
-CONVERT_DECL(quint32, qargb4444)
-CONVERT_DECL(qargb4444, quint32)
-#undef CONVERT_DECL
-#define CONVERT_PTR(DST, SRC) convert_##SRC##_to_##DST
-
-/*
- Format_Invalid,
- Format_Mono,
- Format_MonoLSB,
- Format_Indexed8,
- Format_RGB32,
- Format_ARGB32,
- Format_ARGB32_Premultiplied,
- Format_RGB16,
- Format_ARGB8565_Premultiplied,
- Format_RGB666,
- Format_ARGB6666_Premultiplied,
- Format_RGB555,
- Format_ARGB8555_Premultiplied,
- Format_RGB888
- Format_RGB444
- Format_ARGB4444_Premultiplied
-*/
+}
// first index source, second dest
@@ -3005,15 +2942,15 @@ static Image_Converter converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
mask_alpha_converter,
mask_alpha_converter,
- CONVERT_PTR(quint16, quint32),
- CONVERT_PTR(qargb8565, quint32),
- CONVERT_PTR(qrgb666, quint32),
- CONVERT_PTR(qargb6666, quint32),
- CONVERT_PTR(qrgb555, quint32),
- CONVERT_PTR(qargb8555, quint32),
- CONVERT_PTR(qrgb888, quint32),
- CONVERT_PTR(qrgb444, quint32),
- CONVERT_PTR(qargb4444, quint32)
+ convert_generic,
+ convert_generic,
+ convert_generic,
+ convert_generic,
+ convert_generic,
+ convert_generic,
+ convert_generic,
+ convert_generic,
+ convert_generic
}, // Format_RGB32
{
@@ -3024,15 +2961,15 @@ static Image_Converter converter_map[QImage::NImageFormats][QImage::NImageFormat
mask_alpha_converter,
0,
convert_ARGB_to_ARGB_PM,
- CONVERT_PTR(quint16, quint32),
- CONVERT_PTR(qargb8565, quint32),
- CONVERT_PTR(qrgb666, quint32),
- CONVERT_PTR(qargb6666, quint32),
- CONVERT_PTR(qrgb555, quint32),
- CONVERT_PTR(qargb8555, quint32),
- CONVERT_PTR(qrgb888, quint32),
- CONVERT_PTR(qrgb444, quint32),
- CONVERT_PTR(qargb4444, quint32)
+ convert_generic,
+ convert_generic,
+ convert_generic,
+ convert_generic,
+ convert_generic,
+ convert_generic,
+ convert_generic,
+ convert_generic,
+ convert_generic
}, // Format_ARGB32
{
@@ -3059,15 +2996,15 @@ static Image_Converter converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- CONVERT_PTR(quint32, quint16),
- CONVERT_PTR(quint32, quint16),
- CONVERT_PTR(quint32, quint16),
+ convert_generic,
+ convert_generic,
+ convert_generic,
0,
0,
0,
0,
#if defined(QT_QWS_DEPTH_15) && defined(QT_QWS_DEPTH_16)
- CONVERT_PTR(qrgb555, quint16),
+ convert_generic,
#else
0,
#endif
@@ -3082,9 +3019,9 @@ static Image_Converter converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- CONVERT_PTR(quint32, qargb8565),
- CONVERT_PTR(quint32, qargb8565),
- CONVERT_PTR(quint32, qargb8565),
+ convert_generic,
+ convert_generic,
+ convert_generic,
0,
0,
0,
@@ -3101,9 +3038,9 @@ static Image_Converter converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- CONVERT_PTR(quint32, qrgb666),
- CONVERT_PTR(quint32, qrgb666),
- CONVERT_PTR(quint32, qrgb666),
+ convert_generic,
+ convert_generic,
+ convert_generic,
0,
0,
0,
@@ -3120,9 +3057,9 @@ static Image_Converter converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- CONVERT_PTR(quint32, qargb6666),
- CONVERT_PTR(quint32, qargb6666),
- CONVERT_PTR(quint32, qargb6666),
+ convert_generic,
+ convert_generic,
+ convert_generic,
0,
0,
0,
@@ -3139,11 +3076,11 @@ static Image_Converter converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- CONVERT_PTR(quint32, qrgb555),
- CONVERT_PTR(quint32, qrgb555),
- CONVERT_PTR(quint32, qrgb555),
+ convert_generic,
+ convert_generic,
+ convert_generic,
#if defined(QT_QWS_DEPTH_15) && defined(QT_QWS_DEPTH_16)
- CONVERT_PTR(quint16, qrgb555),
+ convert_generic,
#else
0,
#endif
@@ -3162,9 +3099,9 @@ static Image_Converter converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- CONVERT_PTR(quint32, qargb8555),
- CONVERT_PTR(quint32, qargb8555),
- CONVERT_PTR(quint32, qargb8555),
+ convert_generic,
+ convert_generic,
+ convert_generic,
0,
0,
0,
@@ -3181,9 +3118,9 @@ static Image_Converter converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- CONVERT_PTR(quint32, qrgb888),
- CONVERT_PTR(quint32, qrgb888),
- CONVERT_PTR(quint32, qrgb888),
+ convert_generic,
+ convert_generic,
+ convert_generic,
0,
0,
0,
@@ -3200,9 +3137,9 @@ static Image_Converter converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- CONVERT_PTR(quint32, qrgb444),
- CONVERT_PTR(quint32, qrgb444),
- CONVERT_PTR(quint32, qrgb444),
+ convert_generic,
+ convert_generic,
+ convert_generic,
0,
0,
0,
@@ -3219,9 +3156,9 @@ static Image_Converter converter_map[QImage::NImageFormats][QImage::NImageFormat
0,
0,
0,
- CONVERT_PTR(quint32, qargb4444),
- CONVERT_PTR(quint32, qargb4444),
- CONVERT_PTR(quint32, qargb4444),
+ convert_generic,
+ convert_generic,
+ convert_generic,
0,
0,
0,
@@ -3626,35 +3563,28 @@ QRgb QImage::pixel(int x, int y) const
qWarning("QImage::pixel: coordinate (%d,%d) out of range", x, y);
return 12345;
}
- const uchar * s = scanLine(y);
+
+ const uchar * s = constScanLine(y);
switch(d->format) {
case Format_Mono:
- return d->colortable.at((*(s + (x >> 3)) >> (7- (x & 7))) & 1);
+ return d->colortable.at((*(s + (x >> 3)) >> (~x & 7)) & 1);
case Format_MonoLSB:
return d->colortable.at((*(s + (x >> 3)) >> (x & 7)) & 1);
case Format_Indexed8:
return d->colortable.at((int)s[x]);
- case Format_ARGB8565_Premultiplied:
- return qt_colorConvert<quint32, qargb8565>(reinterpret_cast<const qargb8565*>(s)[x], 0);
- case Format_RGB666:
- return qt_colorConvert<quint32, qrgb666>(reinterpret_cast<const qrgb666*>(s)[x], 0);
- case Format_ARGB6666_Premultiplied:
- return qt_colorConvert<quint32, qargb6666>(reinterpret_cast<const qargb6666*>(s)[x], 0);
- case Format_RGB555:
- return qt_colorConvert<quint32, qrgb555>(reinterpret_cast<const qrgb555*>(s)[x], 0);
- case Format_ARGB8555_Premultiplied:
- return qt_colorConvert<quint32, qargb8555>(reinterpret_cast<const qargb8555*>(s)[x], 0);
- case Format_RGB888:
- return qt_colorConvert<quint32, qrgb888>(reinterpret_cast<const qrgb888*>(s)[x], 0);
- case Format_RGB444:
- return qt_colorConvert<quint32, qrgb444>(reinterpret_cast<const qrgb444*>(s)[x], 0);
- case Format_ARGB4444_Premultiplied:
- return qt_colorConvert<quint32, qargb4444>(reinterpret_cast<const qargb4444*>(s)[x], 0);
+ case Format_RGB32:
+ case Format_ARGB32: // Keep old behaviour.
+ case Format_ARGB32_Premultiplied:
+ return reinterpret_cast<const QRgb *>(s)[x];
case Format_RGB16:
- return qt_colorConvert<quint32, quint16>(reinterpret_cast<const quint16*>(s)[x], 0);
+ return qConvertRgb16To32(reinterpret_cast<const quint16 *>(s)[x]);
default:
- return ((QRgb*)s)[x];
+ break;
}
+ const QPixelLayout *layout = &qPixelLayouts[d->format];
+ uint result;
+ const uint *ptr = qFetchPixels[layout->bpp](&result, s, x, 1);
+ return *layout->convertToARGB32PM(&result, ptr, 1, layout, 0);
}
@@ -3693,7 +3623,6 @@ void QImage::setPixel(int x, int y, uint index_or_rgb)
}
// detach is called from within scanLine
uchar * s = scanLine(y);
- const quint32p p = quint32p::fromRawData(index_or_rgb);
switch(d->format) {
case Format_Mono:
case Format_MonoLSB:
@@ -3710,54 +3639,38 @@ void QImage::setPixel(int x, int y, uint index_or_rgb)
else
*(s + (x >> 3)) |= (1 << (7-(x & 7)));
}
- break;
+ return;
case Format_Indexed8:
if (index_or_rgb >= (uint)d->colortable.size()) {
qWarning("QImage::setPixel: Index %d out of range", index_or_rgb);
return;
}
s[x] = index_or_rgb;
- break;
+ return;
case Format_RGB32:
//make sure alpha is 255, we depend on it in qdrawhelper for cases
// when image is set as a texture pattern on a qbrush
((uint *)s)[x] = uint(255 << 24) | index_or_rgb;
- break;
+ return;
case Format_ARGB32:
case Format_ARGB32_Premultiplied:
((uint *)s)[x] = index_or_rgb;
- break;
+ return;
case Format_RGB16:
- ((quint16 *)s)[x] = qt_colorConvert<quint16, quint32p>(p, 0);
- break;
- case Format_ARGB8565_Premultiplied:
- ((qargb8565*)s)[x] = qt_colorConvert<qargb8565, quint32p>(p, 0);
- break;
- case Format_RGB666:
- ((qrgb666*)s)[x] = qt_colorConvert<qrgb666, quint32p>(p, 0);
- break;
- case Format_ARGB6666_Premultiplied:
- ((qargb6666*)s)[x] = qt_colorConvert<qargb6666, quint32p>(p, 0);
- break;
- case Format_RGB555:
- ((qrgb555*)s)[x] = qt_colorConvert<qrgb555, quint32p>(p, 0);
- break;
- case Format_ARGB8555_Premultiplied:
- ((qargb8555*)s)[x] = qt_colorConvert<qargb8555, quint32p>(p, 0);
- break;
- case Format_RGB888:
- ((qrgb888*)s)[x] = qt_colorConvert<qrgb888, quint32p>(p, 0);
- break;
- case Format_RGB444:
- ((qrgb444*)s)[x] = qt_colorConvert<qrgb444, quint32p>(p, 0);
- break;
- case Format_ARGB4444_Premultiplied:
- ((qargb4444*)s)[x] = qt_colorConvert<qargb4444, quint32p>(p, 0);
- break;
+ ((quint16 *)s)[x] = qConvertRgb32To16(INV_PREMUL(index_or_rgb));
+ return;
case Format_Invalid:
case NImageFormats:
Q_ASSERT(false);
+ return;
+ default:
+ break;
}
+
+ const QPixelLayout *layout = &qPixelLayouts[d->format];
+ uint result;
+ const uint *ptr = layout->convertFromARGB32PM(&result, &index_or_rgb, 1, layout, 0);
+ qStorePixels[layout->bpp](s, ptr, x, 1);
}
/*!
@@ -3774,30 +3687,56 @@ bool QImage::allGray() const
if (!d)
return true;
- if (d->depth == 32) {
- int p = width()*height();
- const QRgb* b = (const QRgb*)bits();
- while (p--)
- if (!qIsGray(*b++))
- return false;
- } else if (d->depth == 16) {
- int p = width()*height();
- const ushort* b = (const ushort *)bits();
- while (p--)
- if (!qIsGray(qt_colorConvert<quint32, quint16>(*b++, 0)))
- return false;
- } else if (d->format == QImage::Format_RGB888) {
- int p = width()*height();
- const qrgb888* b = (const qrgb888 *)bits();
- while (p--)
- if (!qIsGray(qt_colorConvert<quint32, qrgb888>(*b++, 0)))
- return false;
- } else {
- if (d->colortable.isEmpty())
- return true;
- for (int i = 0; i < colorCount(); i++)
+ switch (d->format) {
+ case Format_Mono:
+ case Format_MonoLSB:
+ case Format_Indexed8:
+ for (int i = 0; i < d->colortable.size(); ++i) {
if (!qIsGray(d->colortable.at(i)))
return false;
+ }
+ return true;
+ case Format_RGB32:
+ case Format_ARGB32:
+ case Format_ARGB32_Premultiplied:
+ for (int j = 0; j < d->height; ++j) {
+ const QRgb *b = (const QRgb *)constScanLine(j);
+ for (int i = 0; i < d->width; ++i) {
+ if (!qIsGray(b[i]))
+ return false;
+ }
+ }
+ return true;
+ case Format_RGB16:
+ for (int j = 0; j < d->height; ++j) {
+ const quint16 *b = (const quint16 *)constScanLine(j);
+ for (int i = 0; i < d->width; ++i) {
+ if (!qIsGray(qConvertRgb16To32(b[i])))
+ return false;
+ }
+ }
+ return true;
+ default:
+ break;
+ }
+
+ const int buffer_size = 2048;
+ uint buffer[buffer_size];
+ const QPixelLayout *layout = &qPixelLayouts[d->format];
+ FetchPixelsFunc fetch = qFetchPixels[layout->bpp];
+ for (int j = 0; j < d->height; ++j) {
+ const uchar *b = constScanLine(j);
+ int x = 0;
+ while (x < d->width) {
+ int l = qMin(d->width - x, buffer_size);
+ const uint *ptr = fetch(buffer, b, x, l);
+ ptr = layout->convertToARGB32PM(buffer, ptr, l, layout, 0);
+ for (int i = 0; i < l; ++i) {
+ if (!qIsGray(ptr[i]))
+ return false;
+ }
+ x += l;
+ }
}
return true;
}
@@ -4320,7 +4259,7 @@ QImage QImage::rgbSwapped() const
case Format_Invalid:
case NImageFormats:
Q_ASSERT(false);
- break;
+ return res;
case Format_Mono:
case Format_MonoLSB:
case Format_Indexed8:
@@ -4329,7 +4268,7 @@ QImage QImage::rgbSwapped() const
QRgb c = res.d->colortable.at(i);
res.d->colortable[i] = QRgb(((c << 16) & 0xff0000) | ((c >> 16) & 0xff) | (c & 0xff00ff00));
}
- break;
+ return res;
case Format_RGB32:
case Format_ARGB32:
case Format_ARGB32_Premultiplied:
@@ -4345,7 +4284,7 @@ QImage QImage::rgbSwapped() const
q++;
}
}
- break;
+ return res;
case Format_RGB16:
res = QImage(d->width, d->height, d->format);
QIMAGE_SANITYCHECK_MEMORY(res);
@@ -4359,113 +4298,41 @@ QImage QImage::rgbSwapped() const
q++;
}
}
+ return res;
+ default:
break;
- case Format_ARGB8565_Premultiplied:
- res = QImage(d->width, d->height, d->format);
- QIMAGE_SANITYCHECK_MEMORY(res);
- for (int i = 0; i < d->height; i++) {
- const quint8 *p = constScanLine(i);
- quint8 *q = res.scanLine(i);
- const quint8 *end = p + d->width * sizeof(qargb8565);
- while (p < end) {
- q[0] = p[0];
- q[1] = (p[1] & 0xe0) | (p[2] >> 3);
- q[2] = (p[2] & 0x07) | (p[1] << 3);
- p += sizeof(qargb8565);
- q += sizeof(qargb8565);
- }
- }
- break;
- case Format_RGB666:
- res = QImage(d->width, d->height, d->format);
- QIMAGE_SANITYCHECK_MEMORY(res);
- for (int i = 0; i < d->height; i++) {
- qrgb666 *q = reinterpret_cast<qrgb666*>(res.scanLine(i));
- const qrgb666 *p = reinterpret_cast<const qrgb666*>(constScanLine(i));
- const qrgb666 *end = p + d->width;
- while (p < end) {
- const QRgb rgb = quint32(*p++);
- *q++ = qRgb(qBlue(rgb), qGreen(rgb), qRed(rgb));
- }
- }
- break;
- case Format_ARGB6666_Premultiplied:
- res = QImage(d->width, d->height, d->format);
- QIMAGE_SANITYCHECK_MEMORY(res);
- for (int i = 0; i < d->height; i++) {
- const quint8 *p = constScanLine(i);
- const quint8 *end = p + d->width * sizeof(qargb6666);
- quint8 *q = res.scanLine(i);
- while (p < end) {
- q[0] = (p[1] >> 4) | ((p[2] & 0x3) << 4) | (p[0] & 0xc0);
- q[1] = (p[1] & 0xf) | (p[0] << 4);
- q[2] = (p[2] & 0xfc) | ((p[0] >> 4) & 0x3);
- p += sizeof(qargb6666);
- q += sizeof(qargb6666);
- }
- }
- break;
- case Format_RGB555:
- res = QImage(d->width, d->height, d->format);
- QIMAGE_SANITYCHECK_MEMORY(res);
- for (int i = 0; i < d->height; i++) {
- quint16 *q = (quint16*)res.scanLine(i);
- const quint16 *p = (const quint16*)constScanLine(i);
- const quint16 *end = p + d->width;
- while (p < end) {
- *q = ((*p << 10) & 0x7c00) | ((*p >> 10) & 0x1f) | (*p & 0x3e0);
- p++;
- q++;
- }
- }
- break;
- case Format_ARGB8555_Premultiplied:
- res = QImage(d->width, d->height, d->format);
- QIMAGE_SANITYCHECK_MEMORY(res);
- for (int i = 0; i < d->height; i++) {
- const quint8 *p = constScanLine(i);
- quint8 *q = res.scanLine(i);
- const quint8 *end = p + d->width * sizeof(qargb8555);
- while (p < end) {
- q[0] = p[0];
- q[1] = (p[1] & 0xe0) | (p[2] >> 2);
- q[2] = (p[2] & 0x03) | ((p[1] << 2) & 0x7f);
- p += sizeof(qargb8555);
- q += sizeof(qargb8555);
- }
- }
- break;
- case Format_RGB888:
- res = QImage(d->width, d->height, d->format);
- QIMAGE_SANITYCHECK_MEMORY(res);
- for (int i = 0; i < d->height; i++) {
- quint8 *q = res.scanLine(i);
- const quint8 *p = constScanLine(i);
- const quint8 *end = p + d->width * sizeof(qrgb888);
- while (p < end) {
- q[0] = p[2];
- q[1] = p[1];
- q[2] = p[0];
- q += sizeof(qrgb888);
- p += sizeof(qrgb888);
- }
- }
- break;
- case Format_RGB444:
- case Format_ARGB4444_Premultiplied:
- res = QImage(d->width, d->height, d->format);
- QIMAGE_SANITYCHECK_MEMORY(res);
- for (int i = 0; i < d->height; i++) {
- quint16 *q = reinterpret_cast<quint16*>(res.scanLine(i));
- const quint16 *p = reinterpret_cast<const quint16*>(constScanLine(i));
- const quint16 *end = p + d->width;
- while (p < end) {
- *q = (*p & 0xf0f0) | ((*p & 0x0f) << 8) | ((*p & 0xf00) >> 8);
- p++;
- q++;
+ }
+
+ res = QImage(d->width, d->height, d->format);
+ QIMAGE_SANITYCHECK_MEMORY(res);
+ const QPixelLayout *layout = &qPixelLayouts[d->format];
+ Q_ASSERT(layout->redWidth == layout->blueWidth);
+ FetchPixelsFunc fetch = qFetchPixels[layout->bpp];
+ StorePixelsFunc store = qStorePixels[layout->bpp];
+
+ const uint redBlueMask = (1 << layout->redWidth) - 1;
+ const uint alphaGreenMask = (((1 << layout->alphaWidth) - 1) << layout->alphaShift)
+ | (((1 << layout->greenWidth) - 1) << layout->greenShift);
+
+ const int buffer_size = 2048;
+ uint buffer[buffer_size];
+ for (int i = 0; i < d->height; ++i) {
+ uchar *q = res.scanLine(i);
+ const uchar *p = constScanLine(i);
+ int x = 0;
+ while (x < d->width) {
+ int l = qMin(d->width - x, buffer_size);
+ const uint *ptr = fetch(buffer, p, x, l);
+ for (int j = 0; j < l; ++j) {
+ uint red = (ptr[j] >> layout->redShift) & redBlueMask;
+ uint blue = (ptr[j] >> layout->blueShift) & redBlueMask;
+ buffer[j] = (ptr[j] & alphaGreenMask)
+ | (red << layout->blueShift)
+ | (blue << layout->redShift);
}
+ store(q, buffer, x, l);
+ x += l;
}
- break;
}
return res;
}
diff --git a/src/gui/image/qjpeghandler.cpp b/src/gui/image/qjpeghandler.cpp
index 0260d18217..013a1a83b0 100644
--- a/src/gui/image/qjpeghandler.cpp
+++ b/src/gui/image/qjpeghandler.cpp
@@ -106,6 +106,13 @@ static void my_error_exit (j_common_ptr cinfo)
longjmp(myerr->setjmp_buffer, 1);
}
+static void my_output_message(j_common_ptr cinfo)
+{
+ char buffer[JMSG_LENGTH_MAX];
+ (*cinfo->err->format_message)(cinfo, buffer);
+ qWarning("%s", buffer);
+}
+
#if defined(Q_C_CALLBACKS)
}
#endif
@@ -530,6 +537,7 @@ static bool write_jpeg_image(const QImage &image, QIODevice *device, int sourceQ
cinfo.err = jpeg_std_error(&jerr);
jerr.error_exit = my_error_exit;
+ jerr.output_message = my_output_message;
if (!setjmp(jerr.setjmp_buffer)) {
// WARNING:
@@ -744,6 +752,7 @@ bool QJpegHandlerPrivate::readJpegHeader(QIODevice *device)
info.src = iod_src;
info.err = jpeg_std_error(&err);
err.error_exit = my_error_exit;
+ err.output_message = my_output_message;
if (!setjmp(err.setjmp_buffer)) {
#if defined(Q_OS_UNIXWARE)
diff --git a/src/gui/image/qnativeimage.cpp b/src/gui/image/qnativeimage.cpp
index 45a8e29100..96d7a0487b 100644
--- a/src/gui/image/qnativeimage.cpp
+++ b/src/gui/image/qnativeimage.cpp
@@ -41,6 +41,7 @@
#include <qdebug.h>
#include "qnativeimage_p.h"
+#include "qplatformscreen_qpa.h"
#include "private/qguiapplication_p.h"
#include "qscreen.h"
diff --git a/src/gui/image/qpixmap.cpp b/src/gui/image/qpixmap.cpp
index f1a06fa33c..e8c1304b74 100644
--- a/src/gui/image/qpixmap.cpp
+++ b/src/gui/image/qpixmap.cpp
@@ -1003,14 +1003,6 @@ bool QPixmap::isDetached() const
return data && data->ref.load() == 1;
}
-/*! \internal
- ### Qt5 - remove me.
-*/
-void QPixmap::deref()
-{
- Q_ASSERT_X(false, "QPixmap::deref()", "Do not call this function anymore!");
-}
-
/*!
Replaces this pixmap's data with the given \a image using the
specified \a flags to control the conversion. The \a flags
@@ -1613,9 +1605,22 @@ QPixmap QPixmap::fromImageReader(QImageReader *imageReader, Qt::ImageConversionF
\warning In general, grabbing an area outside the screen is not
safe. This depends on the underlying window system.
+ \warning The function is deprecated in Qt 5.0 since there might be
+ platform plugins in which window system identifiers (\c WId)
+ are local to a screen. Use QScreen::grabWindow() instead.
+
\sa grabWidget(), {Screenshot Example}
+ \sa QScreen
+ \deprecated
*/
+QPixmap QPixmap::grabWindow(WId window, int x, int y, int w, int h)
+{
+ qWarning("%s is deprecated, use QScreen::grabWindow() instead."
+ " Defaulting to primary screen.", Q_FUNC_INFO);
+ return QGuiApplication::primaryScreen()->grabWindow(window, x, y, w, h);
+}
+
/*!
\internal
*/
diff --git a/src/gui/image/qpixmap.h b/src/gui/image/qpixmap.h
index de76321f0a..27bfe15688 100644
--- a/src/gui/image/qpixmap.h
+++ b/src/gui/image/qpixmap.h
@@ -174,7 +174,6 @@ private:
QPixmap(const QSize &s, int type);
void doInit(int, int, int);
- void deref();
Q_DUMMY_COMPARISON_OPERATOR(QPixmap)
friend class QPlatformPixmap;
friend class QBitmap;
diff --git a/src/gui/image/qpixmap_blitter.cpp b/src/gui/image/qpixmap_blitter.cpp
index e5222fa216..382c0b8d1a 100644
--- a/src/gui/image/qpixmap_blitter.cpp
+++ b/src/gui/image/qpixmap_blitter.cpp
@@ -144,27 +144,11 @@ void QBlittablePlatformPixmap::fill(const QColor &color)
m_alpha = true;
}
- uint pixel;
- switch (blittable()->lock()->format()) {
- case QImage::Format_ARGB32_Premultiplied:
- pixel = PREMUL(color.rgba());
- break;
- case QImage::Format_ARGB8565_Premultiplied:
- pixel = qargb8565(color.rgba()).rawValue();
- break;
- case QImage::Format_ARGB8555_Premultiplied:
- pixel = qargb8555(color.rgba()).rawValue();
- break;
- case QImage::Format_ARGB6666_Premultiplied:
- pixel = qargb6666(color.rgba()).rawValue();
- break;
- case QImage::Format_ARGB4444_Premultiplied:
- pixel = qargb4444(color.rgba()).rawValue();
- break;
- default:
- pixel = color.rgba();
- break;
- }
+ uint pixel = PREMUL(color.rgba());
+ const QPixelLayout *layout = &qPixelLayouts[blittable()->lock()->format()];
+ Q_ASSERT(layout->convertFromARGB32PM);
+ layout->convertFromARGB32PM(&pixel, &pixel, 1, layout, 0);
+
//so premultiplied formats are supported and ARGB32 and RGB32
blittable()->lock()->fill(pixel);
}
diff --git a/src/gui/image/qpixmap_raster.cpp b/src/gui/image/qpixmap_raster.cpp
index 3fe5216313..8125b1360d 100644
--- a/src/gui/image/qpixmap_raster.cpp
+++ b/src/gui/image/qpixmap_raster.cpp
@@ -202,46 +202,10 @@ void QRasterPlatformPixmap::fill(const QColor &color)
image = QImage(image.width(), image.height(), toFormat);
}
}
-
- switch (image.format()) {
- case QImage::Format_ARGB8565_Premultiplied:
- pixel = qargb8565(color.rgba()).rawValue();
- break;
- case QImage::Format_ARGB8555_Premultiplied:
- pixel = qargb8555(color.rgba()).rawValue();
- break;
- case QImage::Format_ARGB6666_Premultiplied:
- pixel = qargb6666(color.rgba()).rawValue();
- break;
- case QImage::Format_ARGB4444_Premultiplied:
- pixel = qargb4444(color.rgba()).rawValue();
- break;
- default:
- pixel = PREMUL(color.rgba());
- break;
- }
- } else {
- switch (image.format()) {
- case QImage::Format_RGB16:
- pixel = qt_colorConvert<quint16, quint32>(color.rgba(), 0);
- break;
- case QImage::Format_RGB444:
- pixel = qrgb444(color.rgba()).rawValue();
- break;
- case QImage::Format_RGB555:
- pixel = qrgb555(color.rgba()).rawValue();
- break;
- case QImage::Format_RGB666:
- pixel = qrgb666(color.rgba()).rawValue();
- break;
- case QImage::Format_RGB888:
- pixel = qrgb888(color.rgba()).rawValue();
- break;
- default:
- pixel = color.rgba();
- break;
- }
}
+ pixel = PREMUL(color.rgba());
+ const QPixelLayout *layout = &qPixelLayouts[image.format()];
+ layout->convertFromARGB32PM(&pixel, &pixel, 1, layout, 0);
} else {
pixel = 0;
// ### what about 8 bits
diff --git a/src/gui/image/qpixmap_win.cpp b/src/gui/image/qpixmap_win.cpp
index 6b0ec38f53..227e70e1a6 100644
--- a/src/gui/image/qpixmap_win.cpp
+++ b/src/gui/image/qpixmap_win.cpp
@@ -47,8 +47,91 @@
#include <QScopedArrayPointer>
#include <qt_windows.h>
+#ifdef Q_OS_WINCE
+#define UNDER_NT
+#include <wingdi.h>
+#endif
+
QT_BEGIN_NAMESPACE
+#ifdef Q_OS_WINCE
+#define GetDIBits(a,b,c,d,e,f,g) qt_wince_GetDIBits(a,b,c,d,e,f,g)
+int qt_wince_GetDIBits(HDC /*hdc*/ , HBITMAP hSourceBitmap, uint, uint, LPVOID lpvBits, LPBITMAPINFO, uint)
+{
+ if (!lpvBits) {
+ qWarning("::GetDIBits(), lpvBits NULL");
+ return 0;
+ }
+ BITMAP bm;
+ GetObject(hSourceBitmap, sizeof(BITMAP), &bm);
+ bm.bmHeight = qAbs(bm.bmHeight);
+
+ HBITMAP hTargetBitmap;
+ void *pixels;
+
+ BITMAPINFO dibInfo;
+ memset(&dibInfo, 0, sizeof(dibInfo));
+ dibInfo.bmiHeader.biBitCount = 32;
+ dibInfo.bmiHeader.biClrImportant = 0;
+ dibInfo.bmiHeader.biClrUsed = 0;
+ dibInfo.bmiHeader.biCompression = BI_RGB;;
+ dibInfo.bmiHeader.biHeight = -bm.bmHeight;
+ dibInfo.bmiHeader.biWidth = bm.bmWidth;
+ dibInfo.bmiHeader.biPlanes = 1;
+ dibInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
+ dibInfo.bmiHeader.biSizeImage = bm.bmWidth * bm.bmHeight * 4;
+
+ HDC displayDC = GetDC(NULL);
+ if (!displayDC) {
+ qWarning("::GetDIBits(), failed to GetDC");
+ return 0;
+ }
+
+ int ret = bm.bmHeight;
+
+ hTargetBitmap = CreateDIBSection(displayDC, (const BITMAPINFO*) &dibInfo, DIB_RGB_COLORS,
+ (void**)&pixels, NULL, 0);
+ if (!hTargetBitmap) {
+ qWarning("::GetDIBits(), failed to CreateDIBSection");
+ return 0;
+ }
+
+ HDC hdcSrc = CreateCompatibleDC(displayDC);
+ HDC hdcDst = CreateCompatibleDC(displayDC);
+
+ if (!(hdcDst && hdcSrc)) {
+ qWarning("::GetDIBits(), failed to CreateCompatibleDC");
+ ret = 0;
+ }
+
+ HBITMAP hOldBitmap1 = (HBITMAP) SelectObject(hdcSrc, hSourceBitmap);
+ HBITMAP hOldBitmap2 = (HBITMAP) SelectObject(hdcDst, hTargetBitmap);
+
+ if (!(hOldBitmap1 && hOldBitmap2)) {
+ qWarning("::GetDIBits(), failed to SelectObject for bitmaps");
+ ret = 0;
+ }
+
+ if (!BitBlt(hdcDst, 0, 0, bm.bmWidth, bm.bmHeight, hdcSrc, 0, 0, SRCCOPY)) {
+ qWarning("::GetDIBits(), BitBlt failed");
+ ret = 0;
+ }
+
+ SelectObject(hdcSrc, hOldBitmap1);
+ SelectObject(hdcDst, hOldBitmap2);
+
+ DeleteDC(hdcSrc);
+ DeleteDC(hdcDst);
+
+ ReleaseDC(NULL, displayDC);
+
+ memcpy(lpvBits, pixels, dibInfo.bmiHeader.biSizeImage);
+
+ DeleteObject(hTargetBitmap);
+ return ret;
+}
+#endif
+
enum HBitmapFormat
{
HBitmapNoAlpha,
@@ -128,6 +211,8 @@ Q_GUI_EXPORT HBITMAP qt_pixmapToWinHBITMAP(const QPixmap &p, int hbitmapFormat =
return bitmap;
}
+#ifndef Q_OS_WINCE
+
Q_GUI_EXPORT QPixmap qt_pixmapFromWinHBITMAP(HBITMAP bitmap, int hbitmapFormat = 0)
{
// Verify size
@@ -191,6 +276,8 @@ Q_GUI_EXPORT QPixmap qt_pixmapFromWinHBITMAP(HBITMAP bitmap, int hbitmapFormat =
return QPixmap::fromImage(image);
}
+#endif //ifndef Q_OS_WINCE
+
Q_GUI_EXPORT HICON qt_pixmapToWinHICON(const QPixmap &p)
{
QBitmap maskBitmap = p.mask();
@@ -214,6 +301,8 @@ Q_GUI_EXPORT HICON qt_pixmapToWinHICON(const QPixmap &p)
return hIcon;
}
+#ifndef Q_OS_WINCE
+
Q_GUI_EXPORT QImage qt_imageFromWinHBITMAP(HDC hdc, HBITMAP bitmap, int w, int h)
{
BITMAPINFO bmi;
@@ -315,5 +404,95 @@ Q_GUI_EXPORT QPixmap qt_pixmapFromWinHICON(HICON icon)
DeleteDC(hdc);
return QPixmap::fromImage(image);
}
+#else //ifndef Q_OS_WINCE
+Q_GUI_EXPORT QPixmap qt_pixmapFromWinHICON(HICON icon)
+{
+ HDC screenDevice = GetDC(0);
+ HDC hdc = CreateCompatibleDC(screenDevice);
+ ReleaseDC(0, screenDevice);
+
+ ICONINFO iconinfo;
+ bool result = GetIconInfo(icon, &iconinfo);
+ if (!result)
+ qWarning("QPixmap::fromWinHICON(), failed to GetIconInfo()");
+
+ int w = 0;
+ int h = 0;
+ if (!iconinfo.xHotspot || !iconinfo.yHotspot) {
+ // We could not retrieve the icon size via GetIconInfo,
+ // so we try again using the icon bitmap.
+ BITMAP bm;
+ int result = GetObject(iconinfo.hbmColor, sizeof(BITMAP), &bm);
+ if (!result) result = GetObject(iconinfo.hbmMask, sizeof(BITMAP), &bm);
+ if (!result) {
+ qWarning("QPixmap::fromWinHICON(), failed to retrieve icon size");
+ return QPixmap();
+ }
+ w = bm.bmWidth;
+ h = bm.bmHeight;
+ } else {
+ // x and y Hotspot describes the icon center
+ w = iconinfo.xHotspot * 2;
+ h = iconinfo.yHotspot * 2;
+ }
+ const DWORD dwImageSize = w * h * 4;
+
+ BITMAPINFO bmi;
+ memset(&bmi, 0, sizeof(bmi));
+ bmi.bmiHeader.biSize = sizeof(BITMAPINFO);
+ bmi.bmiHeader.biWidth = w;
+ bmi.bmiHeader.biHeight = -h;
+ bmi.bmiHeader.biPlanes = 1;
+ bmi.bmiHeader.biBitCount = 32;
+ bmi.bmiHeader.biCompression = BI_RGB;
+ bmi.bmiHeader.biSizeImage = dwImageSize;
+
+ uchar* bits;
+
+ HBITMAP winBitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, (void**) &bits, 0, 0);
+ if (winBitmap )
+ memset(bits, 0xff, dwImageSize);
+ if (!winBitmap) {
+ qWarning("QPixmap::fromWinHICON(), failed to CreateDIBSection()");
+ return QPixmap();
+ }
+
+ HGDIOBJ oldhdc = (HBITMAP)SelectObject(hdc, winBitmap);
+ if (!DrawIconEx( hdc, 0, 0, icon, w, h, 0, 0, DI_NORMAL))
+ qWarning("QPixmap::fromWinHICON(), failed to DrawIcon()");
+
+ uint mask = 0xff000000;
+ // Create image and copy data into image.
+ QImage image(w, h, QImage::Format_ARGB32);
+
+ if (!image.isNull()) { // failed to alloc?
+ int bytes_per_line = w * sizeof(QRgb);
+ for (int y=0; y < h; ++y) {
+ QRgb *dest = (QRgb *) image.scanLine(y);
+ const QRgb *src = (const QRgb *) (bits + y * bytes_per_line);
+ for (int x=0; x < w; ++x) {
+ dest[x] = src[x];
+ }
+ }
+ }
+ if (!DrawIconEx( hdc, 0, 0, icon, w, h, 0, 0, DI_MASK))
+ qWarning("QPixmap::fromWinHICON(), failed to DrawIcon()");
+ if (!image.isNull()) { // failed to alloc?
+ int bytes_per_line = w * sizeof(QRgb);
+ for (int y=0; y < h; ++y) {
+ QRgb *dest = (QRgb *) image.scanLine(y);
+ const QRgb *src = (const QRgb *) (bits + y * bytes_per_line);
+ for (int x=0; x < w; ++x) {
+ if (!src[x])
+ dest[x] = dest[x] | mask;
+ }
+ }
+ }
+ SelectObject(hdc, oldhdc); //restore state
+ DeleteObject(winBitmap);
+ DeleteDC(hdc);
+ return QPixmap::fromImage(image);
+}
+#endif //ifndef Q_OS_WINCE
QT_END_NAMESPACE
diff --git a/src/gui/image/qplatformpixmap.cpp b/src/gui/image/qplatformpixmap.cpp
index 5162ea80d9..30ac6ce30e 100644
--- a/src/gui/image/qplatformpixmap.cpp
+++ b/src/gui/image/qplatformpixmap.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include "qplatformpixmap_qpa.h"
+#include "qplatformintegration_qpa.h"
#include <QtCore/qbuffer.h>
#include <QtGui/qbitmap.h>
#include <QtGui/qimagereader.h>
diff --git a/src/gui/kernel/kernel.pri b/src/gui/kernel/kernel.pri
index 7b01ba14cd..9c5f3b10da 100644
--- a/src/gui/kernel/kernel.pri
+++ b/src/gui/kernel/kernel.pri
@@ -55,7 +55,8 @@ HEADERS += \
kernel/qtouchdevice.h \
kernel/qtouchdevice_p.h \
kernel/qplatformsharedgraphicscache_qpa.h \
- kernel/qplatformdialoghelper_qpa.h
+ kernel/qplatformdialoghelper_qpa.h \
+ kernel/qplatformservices_qpa.h
SOURCES += \
kernel/qclipboard_qpa.cpp \
@@ -97,7 +98,8 @@ SOURCES += \
kernel/qstylehints.cpp \
kernel/qtouchdevice.cpp \
kernel/qplatformsharedgraphicscache_qpa.cpp \
- kernel/qplatformdialoghelper_qpa.cpp
+ kernel/qplatformdialoghelper_qpa.cpp \
+ kernel/qplatformservices_qpa.cpp
contains(QT_CONFIG, opengl)|contains(QT_CONFIG, opengles2)|contains(QT_CONFIG, egl) {
HEADERS += \
diff --git a/src/gui/kernel/qclipboard_qpa.cpp b/src/gui/kernel/qclipboard_qpa.cpp
index ec940385b8..b33ccd42a2 100644
--- a/src/gui/kernel/qclipboard_qpa.cpp
+++ b/src/gui/kernel/qclipboard_qpa.cpp
@@ -46,6 +46,7 @@
#include "qmimedata.h"
#include "private/qguiapplication_p.h"
#include "qplatformclipboard_qpa.h"
+#include "qplatformintegration_qpa.h"
QT_BEGIN_NAMESPACE
diff --git a/src/gui/kernel/qdnd.cpp b/src/gui/kernel/qdnd.cpp
index b9f0fe4f5b..2fb250cf18 100644
--- a/src/gui/kernel/qdnd.cpp
+++ b/src/gui/kernel/qdnd.cpp
@@ -59,6 +59,7 @@
#include "qimagewriter.h"
#include "qdebug.h"
#include <ctype.h>
+#include <qplatformintegration_qpa.h>
#include <qplatformdrag_qpa.h>
#include <private/qguiapplication_p.h>
diff --git a/src/gui/kernel/qevent.cpp b/src/gui/kernel/qevent.cpp
index 543f5453ff..c3a6be692b 100644
--- a/src/gui/kernel/qevent.cpp
+++ b/src/gui/kernel/qevent.cpp
@@ -3305,15 +3305,21 @@ QWindowStateChangeEvent::~QWindowStateChangeEvent()
\section1 Event Handling
- All touch events are of type QEvent::TouchBegin, QEvent::TouchUpdate, or QEvent::TouchEnd.
- Reimplement QWidget::event() or QAbstractScrollArea::viewportEvent() for widgets and
- QGraphicsItem::sceneEvent() for items in a graphics view to receive touch events.
+ All touch events are of type QEvent::TouchBegin, QEvent::TouchUpdate, QEvent::TouchEnd or
+ QEvent::TouchCancel. Reimplement QWidget::event() or QAbstractScrollArea::viewportEvent() for
+ widgets and QGraphicsItem::sceneEvent() for items in a graphics view to receive touch events.
The QEvent::TouchUpdate and QEvent::TouchEnd events are sent to the widget or item that
accepted the QEvent::TouchBegin event. If the QEvent::TouchBegin event is not accepted and not
filtered by an event filter, then no further touch events are sent until the next
QEvent::TouchBegin.
+ Some systems may send an event of type QEvent::TouchCancel. Upon receiving this event
+ applications are requested to ignore the entire active touch sequence. For example in a
+ composited system the compositor may decide to treat certain gestures as system-wide
+ gestures. Whenever such a decision is made (the gesture is recognized), the clients will be
+ notified with a QEvent::TouchCancel event so they can update their state accordingly.
+
The touchPoints() function returns a list of all touch points contained in the event.
Information about each touch point can be retrieved using the QTouchEvent::TouchPoint class.
The Qt::TouchPointState enum describes the different states that a touch point may have.
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp
index b1cbb5fcae..7cb3d4b488 100644
--- a/src/gui/kernel/qguiapplication.cpp
+++ b/src/gui/kernel/qguiapplication.cpp
@@ -48,6 +48,8 @@
#include "qplatformfontdatabase_qpa.h"
#include "qplatformwindow_qpa.h"
#include "qplatformnativeinterface_qpa.h"
+#include "qplatformtheme_qpa.h"
+#include "qplatformintegration_qpa.h"
#include <QtCore/QAbstractEventDispatcher>
#include <QtCore/private/qcoreapplication_p.h>
@@ -126,6 +128,7 @@ QWindow *QGuiApplicationPrivate::focus_window = 0;
static QBasicMutex applicationFontMutex;
QFont *QGuiApplicationPrivate::app_font = 0;
+bool QGuiApplicationPrivate::obey_desktop_settings = true;
extern void qRegisterGuiVariant();
extern void qUnregisterGuiVariant();
@@ -184,7 +187,8 @@ QGuiApplication::~QGuiApplication()
QGuiApplicationPrivate::QGuiApplicationPrivate(int &argc, char **argv, int flags)
: QCoreApplicationPrivate(argc, argv, flags),
styleHints(0),
- inputMethod(0)
+ inputMethod(0),
+ lastTouchType(QEvent::TouchEnd)
{
self = this;
application_type = QCoreApplication::GuiClient;
@@ -502,6 +506,8 @@ void QGuiApplicationPrivate::init()
QWindowSystemInterface::sendWindowSystemEvents(QCoreApplicationPrivate::eventDispatcher, QEventLoop::AllEvents);
}
+extern void qt_cleanupFontDatabase();
+
QGuiApplicationPrivate::~QGuiApplicationPrivate()
{
is_app_closing = true;
@@ -526,6 +532,8 @@ QGuiApplicationPrivate::~QGuiApplicationPrivate()
delete styleHints;
delete inputMethod;
+ qt_cleanupFontDatabase();
+
delete platform_integration;
platform_integration = 0;
}
@@ -655,6 +663,10 @@ void QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePriv
QGuiApplicationPrivate::reportLogicalDotsPerInchChange(
static_cast<QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent *>(e));
break;
+ case QWindowSystemInterfacePrivate::ThemeChange:
+ QGuiApplicationPrivate::processThemeChanged(
+ static_cast<QWindowSystemInterfacePrivate::ThemeChangeEvent *>(e));
+ break;
case QWindowSystemInterfacePrivate::Map:
QGuiApplicationPrivate::processMapEvent(static_cast<QWindowSystemInterfacePrivate::MapEvent *>(e));
break;
@@ -882,6 +894,14 @@ void QGuiApplicationPrivate::processWindowStateChangedEvent(QWindowSystemInterfa
}
}
+void QGuiApplicationPrivate::processThemeChanged(QWindowSystemInterfacePrivate::ThemeChangeEvent *tce)
+{
+ if (QWindow *window = tce->window.data()) {
+ QEvent e(QEvent::ThemeChange);
+ QGuiApplication::sendSpontaneousEvent(window, &e);
+ }
+}
+
void QGuiApplicationPrivate::processGeometryChangeEvent(QWindowSystemInterfacePrivate::GeometryChangeEvent *e)
{
if (e->tlw.isNull())
@@ -946,8 +966,55 @@ Q_GUI_EXPORT bool operator==(const QGuiApplicationPrivate::ActiveTouchPointsKey
void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::TouchEvent *e)
{
- QWindow *window = e->window.data();
QGuiApplicationPrivate *d = self;
+
+ if (e->touchType == QEvent::TouchCancel) {
+ // The touch sequence has been canceled (e.g. by the compositor).
+ // Send the TouchCancel to all windows with active touches and clean up.
+ QTouchEvent touchEvent(QEvent::TouchCancel, e->device, e->modifiers);
+ touchEvent.setTimestamp(e->timestamp);
+ QHash<ActiveTouchPointsKey, ActiveTouchPointsValue>::const_iterator it
+ = self->activeTouchPoints.constBegin(), ite = self->activeTouchPoints.constEnd();
+ QSet<QWindow *> windowsNeedingCancel;
+ while (it != ite) {
+ QWindow *w = it->window.data();
+ if (w)
+ windowsNeedingCancel.insert(w);
+ ++it;
+ }
+ for (QSet<QWindow *>::const_iterator winIt = windowsNeedingCancel.constBegin(),
+ winItEnd = windowsNeedingCancel.constEnd(); winIt != winItEnd; ++winIt) {
+ touchEvent.setWindow(*winIt);
+ QGuiApplication::sendSpontaneousEvent(*winIt, &touchEvent);
+ }
+ if (!self->synthesizedMousePoints.isEmpty() && !e->synthetic) {
+ for (QHash<QWindow *, SynthesizedMouseData>::const_iterator synthIt = self->synthesizedMousePoints.constBegin(),
+ synthItEnd = self->synthesizedMousePoints.constEnd(); synthIt != synthItEnd; ++synthIt) {
+ if (!synthIt->window)
+ continue;
+ QWindowSystemInterfacePrivate::MouseEvent fake(synthIt->window.data(),
+ e->timestamp,
+ synthIt->pos,
+ synthIt->screenPos,
+ Qt::NoButton,
+ e->modifiers);
+ fake.synthetic = true;
+ processMouseEvent(&fake);
+ }
+ self->synthesizedMousePoints.clear();
+ }
+ self->activeTouchPoints.clear();
+ self->lastTouchType = e->touchType;
+ return;
+ }
+
+ // Prevent sending ill-formed event sequences: Cancel can only be followed by a Begin.
+ if (self->lastTouchType == QEvent::TouchCancel && e->touchType != QEvent::TouchBegin)
+ return;
+
+ self->lastTouchType = e->touchType;
+
+ QWindow *window = e->window.data();
typedef QPair<Qt::TouchPointStates, QList<QTouchEvent::TouchPoint> > StatesAndTouchPoints;
QHash<QWindow *, StatesAndTouchPoints> windowsNeedingEvents;
@@ -1097,6 +1164,8 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
// exclude touchpads as those generate their own mouse events
if (touchEvent.device()->type() != QTouchDevice::TouchPad) {
Qt::MouseButtons b = eventType == QEvent::TouchEnd ? Qt::NoButton : Qt::LeftButton;
+ if (b == Qt::NoButton)
+ self->synthesizedMousePoints.clear();
QList<QTouchEvent::TouchPoint> touchPoints = touchEvent.touchPoints();
if (eventType == QEvent::TouchBegin)
@@ -1105,6 +1174,9 @@ void QGuiApplicationPrivate::processTouchEvent(QWindowSystemInterfacePrivate::To
for (int i = 0; i < touchPoints.count(); ++i) {
const QTouchEvent::TouchPoint &touchPoint = touchPoints.at(i);
if (touchPoint.id() == m_fakeMouseSourcePointId) {
+ if (b != Qt::NoButton)
+ self->synthesizedMousePoints.insert(w, SynthesizedMouseData(
+ touchPoint.pos(), touchPoint.screenPos(), w));
QWindowSystemInterfacePrivate::MouseEvent fake(w, e->timestamp,
touchPoint.pos(),
touchPoint.screenPos(),
@@ -1313,6 +1385,9 @@ QClipboard * QGuiApplication::clipboard()
QPalette QGuiApplication::palette()
{
if (!QGuiApplicationPrivate::app_pal)
+ if (const QPalette *themePalette = QGuiApplicationPrivate::platformTheme()->palette())
+ QGuiApplicationPrivate::app_pal = new QPalette(*themePalette);
+ if (!QGuiApplicationPrivate::app_pal)
QGuiApplicationPrivate::app_pal = new QPalette(Qt::black);
return *QGuiApplicationPrivate::app_pal;
}
@@ -1407,6 +1482,17 @@ void QGuiApplicationPrivate::emitLastWindowClosed()
}
}
+bool QGuiApplicationPrivate::shouldQuit()
+{
+ /* if there is no visible top-level window left, we allow the quit */
+ QWindowList list = QGuiApplication::topLevelWindows();
+ for (int i = 0; i < list.size(); ++i) {
+ QWindow *w = list.at(i);
+ if (w->isVisible())
+ return false;
+ }
+ return true;
+}
/*!
\property QGuiApplication::layoutDirection
@@ -1562,6 +1648,32 @@ QStyleHints *QGuiApplication::styleHints() const
return d->styleHints;
}
+/*!
+ Sets whether Qt should use the system's standard colors, fonts, etc., to
+ \a on. By default, this is true.
+
+ This function must be called before creating the QGuiApplication object, like
+ this:
+
+ \snippet doc/src/snippets/code/src_gui_kernel_qapplication.cpp 6
+
+ \sa desktopSettingsAware()
+*/
+void QGuiApplication::setDesktopSettingsAware(bool on)
+{
+ QGuiApplicationPrivate::obey_desktop_settings = on;
+}
+
+/*!
+ Returns true if Qt is set to use the system's standard colors, fonts, etc.;
+ otherwise returns false. The default is true.
+
+ \sa setDesktopSettingsAware()
+*/
+bool QGuiApplication::desktopSettingsAware()
+{
+ return QGuiApplicationPrivate::obey_desktop_settings;
+}
/*!
\since 5.0
diff --git a/src/gui/kernel/qguiapplication.h b/src/gui/kernel/qguiapplication.h
index 75046d8767..c374a05986 100644
--- a/src/gui/kernel/qguiapplication.h
+++ b/src/gui/kernel/qguiapplication.h
@@ -56,6 +56,7 @@ QT_BEGIN_NAMESPACE
class QGuiApplicationPrivate;
class QPlatformNativeInterface;
+class QPlatformIntegration;
class QPalette;
class QScreen;
class QStyleHints;
@@ -121,6 +122,9 @@ public:
static inline bool isLeftToRight() { return layoutDirection() == Qt::LeftToRight; }
QStyleHints *styleHints() const;
+ static void setDesktopSettingsAware(bool on);
+ static bool desktopSettingsAware();
+
QT_DEPRECATED QInputPanel *inputPanel() const;
QInputMethod *inputMethod() const;
diff --git a/src/gui/kernel/qguiapplication_p.h b/src/gui/kernel/qguiapplication_p.h
index d9444ebe95..7e6e0aa8c7 100644
--- a/src/gui/kernel/qguiapplication_p.h
+++ b/src/gui/kernel/qguiapplication_p.h
@@ -51,14 +51,14 @@
#include <QWindowSystemInterface>
#include "private/qwindowsysteminterface_qpa_p.h"
-#include <QtGui/qplatformintegration_qpa.h>
-#include <QtGui/qplatformtheme_qpa.h>
#include "private/qshortcutmap_p.h"
QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
+class QPlatformIntegration;
+class QPlatformTheme;
class Q_GUI_EXPORT QGuiApplicationPrivate : public QCoreApplicationPrivate
{
@@ -74,6 +74,8 @@ public:
virtual void notifyLayoutDirectionChange();
virtual void notifyActiveWindowChange(QWindow *previous);
+ virtual bool shouldQuit();
+
static Qt::KeyboardModifiers modifier_buttons;
static Qt::MouseButtons mouse_buttons;
@@ -125,6 +127,7 @@ public:
static void reportGeometryChange(QWindowSystemInterfacePrivate::ScreenGeometryEvent *e);
static void reportAvailableGeometryChange(QWindowSystemInterfacePrivate::ScreenAvailableGeometryEvent *e);
static void reportLogicalDotsPerInchChange(QWindowSystemInterfacePrivate::ScreenLogicalDotsPerInchEvent *e);
+ static void processThemeChanged(QWindowSystemInterfacePrivate::ThemeChangeEvent *tce);
static void processMapEvent(QWindowSystemInterfacePrivate::MapEvent *e);
static void processUnmapEvent(QWindowSystemInterfacePrivate::UnmapEvent *e);
@@ -181,6 +184,7 @@ public:
static QFont *app_font;
QStyleHints *styleHints;
+ static bool obey_desktop_settings;
QInputMethod *inputMethod;
static QList<QObject *> generic_plugin_list;
@@ -199,6 +203,15 @@ public:
QTouchEvent::TouchPoint touchPoint;
};
QHash<ActiveTouchPointsKey, ActiveTouchPointsValue> activeTouchPoints;
+ QEvent::Type lastTouchType;
+ struct SynthesizedMouseData {
+ SynthesizedMouseData(const QPointF &p, const QPointF &sp, QWindow *w)
+ : pos(p), screenPos(sp), window(w) { }
+ QPointF pos;
+ QPointF screenPos;
+ QWeakPointer<QWindow> window;
+ };
+ QHash<QWindow *, SynthesizedMouseData> synthesizedMousePoints;
private:
void init();
diff --git a/src/gui/kernel/qinputmethod_p.h b/src/gui/kernel/qinputmethod_p.h
index 862764d1bc..8a17c85990 100644
--- a/src/gui/kernel/qinputmethod_p.h
+++ b/src/gui/kernel/qinputmethod_p.h
@@ -47,6 +47,7 @@
#include <QtCore/QWeakPointer>
#include <QTransform>
#include <qplatforminputcontext_qpa.h>
+#include <qplatformintegration_qpa.h>
#include <private/qguiapplication_p.h>
QT_BEGIN_HEADER
diff --git a/src/gui/kernel/qopenglcontext.cpp b/src/gui/kernel/qopenglcontext.cpp
index 1b6d1d34c4..ba51653fcf 100644
--- a/src/gui/kernel/qopenglcontext.cpp
+++ b/src/gui/kernel/qopenglcontext.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include "qplatformopenglcontext_qpa.h"
+#include "qplatformintegration_qpa.h"
#include "qopenglcontext.h"
#include "qopenglcontext_p.h"
#include "qwindow.h"
@@ -289,7 +290,7 @@ bool QOpenGLContext::makeCurrent(QSurface *surface)
return false;
if (surface->surfaceType() != QSurface::OpenGLSurface) {
- qWarning() << "QOpenGLContext::makeBuffers() called with non-opengl surface";
+ qWarning() << "QOpenGLContext::makeCurrent() called with non-opengl surface";
return false;
}
diff --git a/src/gui/kernel/qopenglcontext_p.h b/src/gui/kernel/qopenglcontext_p.h
index 7b4e880ade..3e2c35f088 100644
--- a/src/gui/kernel/qopenglcontext_p.h
+++ b/src/gui/kernel/qopenglcontext_p.h
@@ -42,6 +42,8 @@
#ifndef QGUIGLCONTEXT_P_H
#define QGUIGLCONTEXT_P_H
+#ifndef QT_NO_OPENGL
+
#include "qopengl.h"
#include "qopenglcontext.h"
#include <private/qobject_p.h>
@@ -245,4 +247,5 @@ QT_END_NAMESPACE
QT_END_HEADER
+#endif // QT_NO_OPENGL
#endif // QGUIGLCONTEXT_P_H
diff --git a/src/gui/kernel/qpalette.cpp b/src/gui/kernel/qpalette.cpp
index 627731ff20..d5b17fa665 100644
--- a/src/gui/kernel/qpalette.cpp
+++ b/src/gui/kernel/qpalette.cpp
@@ -41,6 +41,7 @@
#include "qpalette.h"
#include "qguiapplication.h"
+#include "qguiapplication_p.h"
#include "qdatastream.h"
#include "qvariant.h"
#include "qdebug.h"
@@ -64,6 +65,29 @@ static QColor qt_mix_colors(QColor a, QColor b)
(a.blue() + b.blue()) / 2, (a.alpha() + b.alpha()) / 2);
}
+static void qt_palette_from_color(QPalette &pal, const QColor &button)
+{
+ int h, s, v;
+ button.getHsv(&h, &s, &v);
+ // inactive and active are the same..
+ const QBrush baseBrush = QBrush(v > 128 ? Qt::white : Qt::black);
+ const QBrush foregroundBrush = QBrush(v > 128 ? Qt::black : Qt::white);
+ const QBrush buttonBrush = QBrush(button);
+ const QBrush buttonBrushDark = QBrush(button.darker());
+ const QBrush buttonBrushDark150 = QBrush(button.darker(150));
+ const QBrush buttonBrushLight150 = QBrush(button.lighter(150));
+ const QBrush whiteBrush = QBrush(Qt::white);
+ pal.setColorGroup(QPalette::Active, foregroundBrush, buttonBrush, buttonBrushLight150,
+ buttonBrushDark, buttonBrushDark150, foregroundBrush, whiteBrush,
+ baseBrush, buttonBrush);
+ pal.setColorGroup(QPalette::Inactive, foregroundBrush, buttonBrush, buttonBrushLight150,
+ buttonBrushDark, buttonBrushDark150, foregroundBrush, whiteBrush,
+ baseBrush, buttonBrush);
+ pal.setColorGroup(QPalette::Disabled, buttonBrushDark, buttonBrush, buttonBrushLight150,
+ buttonBrushDark, buttonBrushDark150, buttonBrushDark,
+ whiteBrush, buttonBrush, buttonBrush);
+}
+
/*!
\fn const QColor &QPalette::color(ColorRole role) const
@@ -488,40 +512,20 @@ static QColor qt_mix_colors(QColor a, QColor b)
\sa QApplication::setPalette(), QApplication::palette()
*/
QPalette::QPalette()
- : d(QGuiApplication::palette().d),
- current_group(Active),
- resolve_mask(0)
-{
- d->ref.ref();
-}
-
-static void qt_palette_from_color(QPalette &pal, const QColor & button)
+ : d(0), current_group(Active), resolve_mask(0)
{
- QColor bg = button,
- btn = button,
- fg, base;
- int h, s, v;
- bg.getHsv(&h, &s, &v);
- if(v > 128) {
- fg = Qt::black;
- base = Qt::white;
+ // Initialize to application palette if present, else default to black.
+ // This makes it possible to instantiate QPalette outside QGuiApplication,
+ // for example in the platform plugins.
+ if (QGuiApplicationPrivate::app_pal) {
+ d = QGuiApplicationPrivate::app_pal->d;
+ d->ref.ref();
} else {
- fg = Qt::white;
- base = Qt::black;
+ init();
+ qt_palette_from_color(*this, Qt::black);
}
- //inactive and active are the same..
- pal.setColorGroup(QPalette::Active, QBrush(fg), QBrush(btn), QBrush(btn.lighter(150)),
- QBrush(btn.darker()), QBrush(btn.darker(150)), QBrush(fg), QBrush(Qt::white),
- QBrush(base), QBrush(bg));
- pal.setColorGroup(QPalette::Inactive, QBrush(fg), QBrush(btn), QBrush(btn.lighter(150)),
- QBrush(btn.darker()), QBrush(btn.darker(150)), QBrush(fg), QBrush(Qt::white),
- QBrush(base), QBrush(bg));
- pal.setColorGroup(QPalette::Disabled, QBrush(btn.darker()), QBrush(btn), QBrush(btn.lighter(150)),
- QBrush(btn.darker()), QBrush(btn.darker(150)), QBrush(btn.darker()),
- QBrush(Qt::white), QBrush(bg), QBrush(bg));
}
-
/*!
Constructs a palette from the \a button color. The other colors are
automatically calculated, based on this color. \c Window will be
diff --git a/src/gui/kernel/qplatformintegration_qpa.cpp b/src/gui/kernel/qplatformintegration_qpa.cpp
index e867e4e588..7a3fe05f7a 100644
--- a/src/gui/kernel/qplatformintegration_qpa.cpp
+++ b/src/gui/kernel/qplatformintegration_qpa.cpp
@@ -107,6 +107,11 @@ QPlatformNativeInterface * QPlatformIntegration::nativeInterface() const
return 0;
}
+QPlatformServices *QPlatformIntegration::services() const
+{
+ return 0;
+}
+
/*!
\class QPlatformIntegration
\since 4.8
@@ -215,12 +220,14 @@ QPlatformPixmap *QPlatformIntegration::createPlatformPixmap(QPlatformPixmap::Pix
return new QRasterPlatformPixmap(type);
}
+#ifndef QT_NO_OPENGL
QPlatformOpenGLContext *QPlatformIntegration::createPlatformOpenGLContext(QOpenGLContext *context) const
{
Q_UNUSED(context);
qWarning("This plugin does not support createPlatformOpenGLContext!");
return 0;
}
+#endif
/*!
Factory function for QPlatformSharedGraphicsCache. This function will return 0 if the platform
diff --git a/src/gui/kernel/qplatformintegration_qpa.h b/src/gui/kernel/qplatformintegration_qpa.h
index efaf495b81..483964b8f3 100644
--- a/src/gui/kernel/qplatformintegration_qpa.h
+++ b/src/gui/kernel/qplatformintegration_qpa.h
@@ -66,6 +66,7 @@ class QPlatformAccessibility;
class QPlatformTheme;
class QPlatformDialogHelper;
class QPlatformSharedGraphicsCache;
+class QPlatformServices;
class Q_GUI_EXPORT QPlatformIntegration
{
@@ -86,7 +87,9 @@ public:
virtual QPlatformPixmap *createPlatformPixmap(QPlatformPixmap::PixelType type) const;
virtual QPlatformWindow *createPlatformWindow(QWindow *window) const = 0;
virtual QPlatformBackingStore *createPlatformBackingStore(QWindow *window) const = 0;
+#ifndef QT_NO_OPENGL
virtual QPlatformOpenGLContext *createPlatformOpenGLContext(QOpenGLContext *context) const;
+#endif
virtual QPlatformSharedGraphicsCache *createPlatformSharedGraphicsCache(const char *cacheId) const;
// Event dispatcher:
@@ -106,6 +109,8 @@ public:
// Access native handles. The window handle is already available from Wid;
virtual QPlatformNativeInterface *nativeInterface() const;
+ virtual QPlatformServices *services() const;
+
enum StyleHint {
CursorFlashTime,
KeyboardInputInterval,
diff --git a/src/gui/kernel/qplatformintegrationplugin_qpa.h b/src/gui/kernel/qplatformintegrationplugin_qpa.h
index 84c2567bbd..d70569cbba 100644
--- a/src/gui/kernel/qplatformintegrationplugin_qpa.h
+++ b/src/gui/kernel/qplatformintegrationplugin_qpa.h
@@ -68,7 +68,7 @@ struct QPlatformIntegrationFactoryInterface : public QFactoryInterface
virtual QPlatformIntegration *create(const QString &key, const QStringList &paramList) = 0;
};
-#define QPlatformIntegrationFactoryInterface_iid "com.nokia.Qt.QPlatformIntegrationFactoryInterface"
+#define QPlatformIntegrationFactoryInterface_iid "org.qt-project.Qt.QPlatformIntegrationFactoryInterface"
Q_DECLARE_INTERFACE(QPlatformIntegrationFactoryInterface, QPlatformIntegrationFactoryInterface_iid)
diff --git a/src/gui/kernel/qplatformopenglcontext_qpa.h b/src/gui/kernel/qplatformopenglcontext_qpa.h
index 17d4e96f8e..af70368f5e 100644
--- a/src/gui/kernel/qplatformopenglcontext_qpa.h
+++ b/src/gui/kernel/qplatformopenglcontext_qpa.h
@@ -42,6 +42,8 @@
#ifndef QPLATFORMGLCONTEXT_H
#define QPLATFORMGLCONTEXT_H
+#ifndef QT_NO_OPENGL
+
#include <QtCore/qnamespace.h>
#include <QtGui/qsurfaceformat.h>
#include <QtGui/qwindow.h>
@@ -91,5 +93,6 @@ QT_END_NAMESPACE
QT_END_HEADER
+#endif // QT_NO_OPENGL
#endif // QPLATFORMGLCONTEXT_H
diff --git a/src/gui/kernel/qplatformscreen_qpa.cpp b/src/gui/kernel/qplatformscreen_qpa.cpp
index b8f1430d1b..c832d853f4 100644
--- a/src/gui/kernel/qplatformscreen_qpa.cpp
+++ b/src/gui/kernel/qplatformscreen_qpa.cpp
@@ -93,7 +93,7 @@ QWindow *QPlatformScreen::topLevelAt(const QPoint & pos) const
QWindowList list = QGuiApplication::topLevelWindows();
for (int i = list.size()-1; i >= 0; --i) {
QWindow *w = list[i];
- if (w->visible() && w->geometry().contains(pos))
+ if (w->isVisible() && w->geometry().contains(pos))
return w;
}
diff --git a/src/gui/image/qpixmap_qpa.cpp b/src/gui/kernel/qplatformservices_qpa.cpp
index 162c5f5286..7993a82f4e 100644
--- a/src/gui/image/qpixmap_qpa.cpp
+++ b/src/gui/kernel/qplatformservices_qpa.cpp
@@ -39,15 +39,36 @@
**
****************************************************************************/
-#include <qpixmap.h>
-#include <qscreen.h>
-#include <private/qguiapplication_p.h>
+#include "qplatformservices_qpa.h"
+
+#include <QtCore/QUrl>
+#include <QtCore/QString>
+#include <QtCore/QDebug>
QT_BEGIN_NAMESPACE
-QPixmap QPixmap::grabWindow(WId window, int x, int y, int w, int h)
+/*!
+ \class QPlatformServices
+ \since 5.0
+ \internal
+ \preliminary
+ \ingroup qpa
+
+ \brief The QPlatformServices provides the backend for desktop-related functionality.
+*/
+
+bool QPlatformServices::openUrl(const QUrl &url)
+{
+ qWarning("This plugin does not support QPlatformServices::openUrl() for '%s'.",
+ qPrintable(url.toString()));
+ return false;
+}
+
+bool QPlatformServices::openDocument(const QUrl &url)
{
- return QGuiApplication::primaryScreen()->handle()->grabWindow(window, x, y, w, h);
+ qWarning("This plugin does not support QPlatformServices::openDocument() for '%s'.",
+ qPrintable(url.toString()));
+ return false;
}
QT_END_NAMESPACE
diff --git a/src/gui/util/qdesktopservices_qpa.cpp b/src/gui/kernel/qplatformservices_qpa.h
index b94267e72e..aff2e5d6fe 100644
--- a/src/gui/util/qdesktopservices_qpa.cpp
+++ b/src/gui/kernel/qplatformservices_qpa.h
@@ -39,23 +39,27 @@
**
****************************************************************************/
-#include <qdebug.h>
-#include <qurl.h>
+#ifndef QPLATFORMSERVICES_QPA_H
+#define QPLATFORMSERVICES_QPA_H
+
+#include <QtCore/QtGlobal>
+
+QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
-static bool launchWebBrowser(const QUrl &url)
-{
- Q_UNUSED(url);
- qWarning("QDesktopServices::launchWebBrowser not implemented");
- return false;
-}
+class QUrl;
-static bool openDocument(const QUrl &file)
+class Q_GUI_EXPORT QPlatformServices
{
- Q_UNUSED(file);
- qWarning("QDesktopServices::openDocument not implemented");
- return false;
-}
+public:
+ virtual ~QPlatformServices() { }
+
+ virtual bool openUrl(const QUrl &url);
+ virtual bool openDocument(const QUrl &url);
+};
QT_END_NAMESPACE
+QT_END_HEADER
+
+#endif // QPLATFORMSERVICES_QPA_H
diff --git a/src/gui/kernel/qplatformtheme_qpa.cpp b/src/gui/kernel/qplatformtheme_qpa.cpp
index d2ff804ddf..aec465f0ff 100644
--- a/src/gui/kernel/qplatformtheme_qpa.cpp
+++ b/src/gui/kernel/qplatformtheme_qpa.cpp
@@ -42,6 +42,8 @@
#include "qplatformtheme_qpa.h"
#include <QtCore/QVariant>
+#include <QtCore/QStringList>
+#include <qpalette.h>
QT_BEGIN_NAMESPACE
@@ -68,6 +70,21 @@ QT_BEGIN_NAMESPACE
\value MaximumScrollBarDragDistance (int) Determines the value returned by
QStyle::pixelMetric(PM_MaximumDragDistance)
+ \value ToolButtonStyle (int) A value representing a Qt::ToolButtonStyle.
+
+ \value ToolBarIconSize Icon size for tool bars.
+
+ \value SystemIconThemeName (QString) Name of the icon theme.
+
+ \value SystemIconFallbackThemeName (QString) Name of the fallback icon theme.
+
+ \value IconThemeSearchPaths (QStringList) Search paths for icons.
+
+ \value ItemViewActivateItemOnSingleClick (bool) Activate items by single click.
+
+ \value StyleNames (QStringList) A list of preferred style names.
+
+
\sa themeHint(), QStyle::pixelMetric()
*/
@@ -95,9 +112,28 @@ QPlatformDialogHelper *QPlatformTheme::createPlatformDialogHelper(DialogType typ
return 0;
}
+const QPalette *QPlatformTheme::palette(Palette type) const
+{
+ Q_UNUSED(type)
+ return 0;
+}
+
QVariant QPlatformTheme::themeHint(ThemeHint hint) const
{
switch (hint) {
+ case QPlatformTheme::ItemViewActivateItemOnSingleClick:
+ return QVariant(false);
+ case QPlatformTheme::ToolButtonStyle:
+ return QVariant(int(Qt::ToolButtonIconOnly));
+ case QPlatformTheme::ToolBarIconSize:
+ return QVariant(int(0));
+ case QPlatformTheme::SystemIconThemeName:
+ case QPlatformTheme::SystemIconFallbackThemeName:
+ return QVariant(QString());
+ case QPlatformTheme::IconThemeSearchPaths:
+ return QVariant(QStringList());
+ case QPlatformTheme::StyleNames:
+ return QVariant(QStringList());
case TextCursorWidth:
return QVariant(1);
case DropShadow:
diff --git a/src/gui/kernel/qplatformtheme_qpa.h b/src/gui/kernel/qplatformtheme_qpa.h
index 2b87e63287..036432054e 100644
--- a/src/gui/kernel/qplatformtheme_qpa.h
+++ b/src/gui/kernel/qplatformtheme_qpa.h
@@ -48,13 +48,13 @@ QT_BEGIN_HEADER
QT_BEGIN_NAMESPACE
-
class QMenu;
class QMenuBar;
class QPlatformMenu;
class QPlatformMenuBar;
class QPlatformDialogHelper;
class QVariant;
+class QPalette;
class Q_GUI_EXPORT QPlatformTheme
{
@@ -62,7 +62,14 @@ public:
enum ThemeHint {
TextCursorWidth,
DropShadow,
- MaximumScrollBarDragDistance
+ MaximumScrollBarDragDistance,
+ ToolButtonStyle,
+ ToolBarIconSize,
+ ItemViewActivateItemOnSingleClick,
+ SystemIconThemeName,
+ SystemIconFallbackThemeName,
+ IconThemeSearchPaths,
+ StyleNames
};
enum DialogType {
@@ -71,12 +78,20 @@ public:
FontDialog
};
+ enum Palette {
+ SystemPalette,
+ ToolTipPalette,
+ NPalettes
+ };
+
virtual QPlatformMenu *createPlatformMenu(QMenu *menu = 0) const;
virtual QPlatformMenuBar *createPlatformMenuBar(QMenuBar *menuBar = 0) const;
virtual bool usePlatformNativeDialog(DialogType type) const;
virtual QPlatformDialogHelper *createPlatformDialogHelper(DialogType type) const;
+ virtual const QPalette *palette(Palette type = SystemPalette) const;
+
virtual QVariant themeHint(ThemeHint hint) const;
};
diff --git a/src/gui/kernel/qplatformthemeplugin_qpa.h b/src/gui/kernel/qplatformthemeplugin_qpa.h
index fb4f9f9b7c..3ce7cc5b02 100644
--- a/src/gui/kernel/qplatformthemeplugin_qpa.h
+++ b/src/gui/kernel/qplatformthemeplugin_qpa.h
@@ -68,7 +68,7 @@ struct QPlatformThemeFactoryInterface : public QFactoryInterface
virtual QPlatformTheme *create(const QString &key, const QStringList &paramList) = 0;
};
-#define QPlatformThemeFactoryInterface_iid "com.nokia.Qt.QPlatformThemeFactoryInterface"
+#define QPlatformThemeFactoryInterface_iid "org.qt-project.Qt.QPlatformThemeFactoryInterface"
Q_DECLARE_INTERFACE(QPlatformThemeFactoryInterface, QPlatformThemeFactoryInterface_iid)
diff --git a/src/gui/kernel/qplatformwindow_qpa.cpp b/src/gui/kernel/qplatformwindow_qpa.cpp
index c52a1cf757..e12228d7bd 100644
--- a/src/gui/kernel/qplatformwindow_qpa.cpp
+++ b/src/gui/kernel/qplatformwindow_qpa.cpp
@@ -114,6 +114,10 @@ QSurfaceFormat QPlatformWindow::format() const
can happen programatically(from ie. user application) or by the window manager. This means that
there is no need to call this function specifically from the window manager callback, instead
call QWindowSystemInterface::handleGeometryChange(QWindow *w, const QRect &newRect);
+
+ The position(x, y) part of the rect might be inclusive or exclusive of the window frame
+ as returned by frameMargins(). You can detect this in the plugin by checking
+ qt_window_private(window())->positionPolicy.
*/
void QPlatformWindow::setGeometry(const QRect &rect)
{
@@ -142,6 +146,7 @@ QMargins QPlatformWindow::frameMargins() const
void QPlatformWindow::setVisible(bool visible)
{
Q_UNUSED(visible);
+ QWindowSystemInterface::handleSynchronousExposeEvent(window(), QRect(QPoint(), geometry().size()));
}
/*!
Requests setting the window flags of this surface
@@ -152,6 +157,20 @@ Qt::WindowFlags QPlatformWindow::setWindowFlags(Qt::WindowFlags flags)
return flags;
}
+
+
+/*!
+ Returns if this window is exposed in the windowing system.
+
+ An exposeEvent() is sent every time this value changes.
+ */
+
+bool QPlatformWindow::isExposed() const
+{
+ Q_D(const QPlatformWindow);
+ return d->window->visible();
+}
+
/*!
Requests setting the window state of this surface
to \a type. Returns the actual state set.
diff --git a/src/gui/kernel/qplatformwindow_qpa.h b/src/gui/kernel/qplatformwindow_qpa.h
index 88bf633425..170f62162f 100644
--- a/src/gui/kernel/qplatformwindow_qpa.h
+++ b/src/gui/kernel/qplatformwindow_qpa.h
@@ -89,6 +89,8 @@ public:
virtual void raise();
virtual void lower();
+ virtual bool isExposed() const;
+
virtual void propagateSizeHints();
virtual void setOpacity(qreal level);
diff --git a/src/gui/kernel/qscreen.cpp b/src/gui/kernel/qscreen.cpp
index 67eb991b19..da0716b7d5 100644
--- a/src/gui/kernel/qscreen.cpp
+++ b/src/gui/kernel/qscreen.cpp
@@ -41,6 +41,7 @@
#include "qscreen.h"
#include "qscreen_p.h"
+#include "qpixmap.h"
#include "qplatformscreen_qpa.h"
#include <QtCore/private/qobject_p.h>
@@ -542,4 +543,51 @@ void QScreenPrivate::updatePrimaryOrientation()
primaryOrientation = geometry.width() >= geometry.height() ? Qt::LandscapeOrientation : Qt::PortraitOrientation;
}
+/*!
+ Creates and returns a pixmap constructed by grabbing the contents
+ of the given \a window restricted by QRect(\a x, \a y, \a width,
+ \a height).
+
+ The arguments (\a{x}, \a{y}) specify the offset in the window,
+ whereas (\a{width}, \a{height}) specify the area to be copied. If
+ \a width is negative, the function copies everything to the right
+ border of the window. If \a height is negative, the function
+ copies everything to the bottom of the window.
+
+ The window system identifier (\c WId) can be retrieved using the
+ QWidget::winId() function. The rationale for using a window
+ identifier and not a QWidget, is to enable grabbing of windows
+ that are not part of the application, window system frames, and so
+ on.
+
+ The grabWindow() function grabs pixels from the screen, not from
+ the window, i.e. if there is another window partially or entirely
+ over the one you grab, you get pixels from the overlying window,
+ too. The mouse cursor is generally not grabbed.
+
+ Note on X11 that if the given \a window doesn't have the same depth
+ as the root window, and another window partially or entirely
+ obscures the one you grab, you will \e not get pixels from the
+ overlying window. The contents of the obscured areas in the
+ pixmap will be undefined and uninitialized.
+
+ On Windows Vista and above grabbing a layered window, which is
+ created by setting the Qt::WA_TranslucentBackground attribute, will
+ not work. Instead grabbing the desktop widget should work.
+
+ \warning In general, grabbing an area outside the screen is not
+ safe. This depends on the underlying window system.
+ \since 5.0
+*/
+
+QPixmap QScreen::grabWindow(WId window, int x, int y, int w, int h) const
+{
+ const QPlatformScreen *platformScreen = handle();
+ if (!platformScreen) {
+ qWarning("%s invoked with handle==0", Q_FUNC_INFO);
+ return QPixmap();
+ }
+ return platformScreen->grabWindow(window, x, y, w, h);
+}
+
QT_END_NAMESPACE
diff --git a/src/gui/kernel/qscreen.h b/src/gui/kernel/qscreen.h
index f73cd0836f..111e10d340 100644
--- a/src/gui/kernel/qscreen.h
+++ b/src/gui/kernel/qscreen.h
@@ -61,6 +61,7 @@ class QPlatformScreen;
class QScreenPrivate;
class QWindow;
class QRect;
+class QPixmap;
class Q_GUI_EXPORT QScreen : public QObject
{
@@ -124,6 +125,8 @@ public:
bool isPortrait(Qt::ScreenOrientation orientation);
bool isLandscape(Qt::ScreenOrientation orientation);
+ QPixmap grabWindow(WId window, int x, int y, int w, int h) const;
+
Q_SIGNALS:
void sizeChanged(const QSize &size);
void geometryChanged(const QRect &geometry);
diff --git a/src/gui/kernel/qwindow.cpp b/src/gui/kernel/qwindow.cpp
index 4436884359..9c6b6c4bf7 100644
--- a/src/gui/kernel/qwindow.cpp
+++ b/src/gui/kernel/qwindow.cpp
@@ -42,6 +42,7 @@
#include "qwindow.h"
#include "qplatformwindow_qpa.h"
+#include "qplatformintegration_qpa.h"
#include "qsurfaceformat.h"
#ifndef QT_NO_OPENGL
#include "qplatformopenglcontext_qpa.h"
@@ -165,19 +166,14 @@ void QWindow::setVisible(bool visible)
return;
d->visible = visible;
emit visibleChanged(visible);
- if (QCoreApplication::instance() && !transientParent()) {
- QCoreApplicationPrivate *applicationPrivate = static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(QCoreApplication::instance()));
- if (visible) {
- applicationPrivate->ref();
- } else {
- applicationPrivate->deref();
- }
- }
if (!d->platformWindow)
create();
if (visible) {
+ // remove posted quit events when showing a new window
+ QCoreApplication::removePostedEvents(qApp, QEvent::Quit);
+
QShowEvent showEvent;
QGuiApplication::sendEvent(this, &showEvent);
}
@@ -190,8 +186,14 @@ void QWindow::setVisible(bool visible)
}
}
+
bool QWindow::visible() const
{
+ return isVisible();
+}
+
+bool QWindow::isVisible() const
+{
Q_D(const QWindow);
return d->visible;
@@ -219,7 +221,11 @@ WId QWindow::winId() const
Q_D(const QWindow);
if(!d->platformWindow)
const_cast<QWindow *>(this)->create();
- return d->platformWindow->winId();
+
+ WId id = d->platformWindow->winId();
+ // See the QPlatformWindow::winId() documentation
+ Q_ASSERT(id != WId(0));
+ return id;
}
QWindow *QWindow::parent() const
@@ -373,6 +379,25 @@ void QWindow::requestActivateWindow()
d->platformWindow->requestActivateWindow();
}
+
+/*!
+ Returns if this window is exposed in the windowing system.
+
+ When the window is not exposed, it is shown by the application
+ but it is still not showing in the windowing system, so the application
+ should minimize rendering and other graphical activities.
+
+ An exposeEvent() is sent every time this value changes.
+ */
+
+bool QWindow::isExposed() const
+{
+ Q_D(const QWindow);
+ if (d->platformWindow)
+ return d->platformWindow->isExposed();
+ return false;
+}
+
/*!
Returns true if the window should appear active from a style perspective.
@@ -511,15 +536,6 @@ void QWindow::setTransientParent(QWindow *parent)
QWindow *previousParent = d->transientParent;
d->transientParent = parent;
-
- if (QCoreApplication::instance() && d->visible) {
- QCoreApplicationPrivate *applicationPrivate = static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(QCoreApplication::instance()));
- if (parent && !previousParent) {
- applicationPrivate->deref();
- } else if (!parent && previousParent) {
- applicationPrivate->ref();
- }
- }
}
QWindow *QWindow::transientParent() const
@@ -731,6 +747,15 @@ void QWindow::setWindowIcon(const QImage &icon) const
void QWindow::destroy()
{
Q_D(QWindow);
+ QObjectList childrenWindows = children();
+ for (int i = 0; i < childrenWindows.size(); i++) {
+ QObject *object = childrenWindows.at(i);
+ if (object->isWindowType()) {
+ QWindow *w = static_cast<QWindow*>(object);
+ QGuiApplicationPrivate::window_list.removeAll(w);
+ w->destroy();
+ }
+ }
setVisible(false);
delete d->platformWindow;
d->platformWindow = 0;
@@ -881,22 +906,25 @@ bool QWindow::close()
if (QGuiApplicationPrivate::focus_window == this)
QGuiApplicationPrivate::focus_window = 0;
- QObjectList childrenWindows = children();
- for (int i = 0; i < childrenWindows.size(); i++) {
- QObject *object = childrenWindows.at(i);
- if (object->isWindowType()) {
- QWindow *w = static_cast<QWindow*>(object);
- QGuiApplicationPrivate::window_list.removeAll(w);
- w->destroy();
- }
- }
-
QGuiApplicationPrivate::window_list.removeAll(this);
destroy();
d->maybeQuitOnLastWindowClosed();
return true;
}
+
+
+/*!
+ The expose event is sent by the window system whenever the window's
+ exposure on screen changes.
+
+ If the window is moved off screen, is made totally obscured by another
+ window, iconified or similar, this function might be called and the
+ value of isExposed() might change to false. When this happens,
+ an application should stop its rendering as it is no longer visible
+ to the user.
+ */
+
void QWindow::exposeEvent(QExposeEvent *ev)
{
ev->ignore();
@@ -944,6 +972,7 @@ bool QWindow::event(QEvent *ev)
case QEvent::TouchBegin:
case QEvent::TouchUpdate:
case QEvent::TouchEnd:
+ case QEvent::TouchCancel:
touchEvent(static_cast<QTouchEvent *>(ev));
break;
@@ -979,7 +1008,7 @@ bool QWindow::event(QEvent *ev)
case QEvent::Close: {
Q_D(QWindow);
- bool wasVisible = visible();
+ bool wasVisible = isVisible();
destroy();
if (wasVisible)
d->maybeQuitOnLastWindowClosed();
@@ -1113,13 +1142,16 @@ void QWindowPrivate::maybeQuitOnLastWindowClosed()
bool lastWindowClosed = true;
for (int i = 0; i < list.size(); ++i) {
QWindow *w = list.at(i);
- if (!w->visible() || w->parent())
+ if (!w->isVisible())
continue;
lastWindowClosed = false;
break;
}
- if (lastWindowClosed)
+ if (lastWindowClosed) {
QGuiApplicationPrivate::emitLastWindowClosed();
+ QCoreApplicationPrivate *applicationPrivate = static_cast<QCoreApplicationPrivate*>(QObjectPrivate::get(QCoreApplication::instance()));
+ applicationPrivate->maybeQuit();
+ }
}
}
diff --git a/src/gui/kernel/qwindow.h b/src/gui/kernel/qwindow.h
index 98b468b142..1461f12520 100644
--- a/src/gui/kernel/qwindow.h
+++ b/src/gui/kernel/qwindow.h
@@ -89,7 +89,7 @@ class Q_GUI_EXPORT QWindow : public QObject, public QSurface
Q_PROPERTY(int y READ y WRITE setY NOTIFY yChanged)
Q_PROPERTY(int width READ width WRITE setWidth NOTIFY widthChanged)
Q_PROPERTY(int height READ height WRITE setHeight NOTIFY heightChanged)
- Q_PROPERTY(bool visible READ visible WRITE setVisible NOTIFY visibleChanged)
+ Q_PROPERTY(bool visible READ isVisible WRITE setVisible NOTIFY visibleChanged)
Q_PROPERTY(Qt::ScreenOrientation contentOrientation READ contentOrientation WRITE reportContentOrientationChange NOTIFY contentOrientationChanged)
public:
@@ -101,7 +101,9 @@ public:
void setSurfaceType(SurfaceType surfaceType);
SurfaceType surfaceType() const;
- bool visible() const;
+ QT_DEPRECATED bool visible() const;
+
+ bool isVisible() const;
void create();
@@ -150,6 +152,8 @@ public:
bool isAncestorOf(const QWindow *child, AncestorMode mode = IncludeTransients) const;
+ bool isExposed() const;
+
QSize minimumSize() const;
QSize maximumSize() const;
QSize baseSize() const;
diff --git a/src/gui/kernel/qwindowdefs.h b/src/gui/kernel/qwindowdefs.h
index 82cce0394b..c2d7a2fe2f 100644
--- a/src/gui/kernel/qwindowdefs.h
+++ b/src/gui/kernel/qwindowdefs.h
@@ -42,6 +42,7 @@
#ifndef QWINDOWDEFS_H
#define QWINDOWDEFS_H
+#include <QtCore/qglobal.h>
#include <QtCore/qobjectdefs.h>
#include <QtCore/qnamespace.h>
@@ -99,7 +100,7 @@ QT_END_HEADER
-typedef unsigned long WId;
+typedef QT_PREPEND_NAMESPACE(quintptr) WId;
diff --git a/src/gui/kernel/qwindowsysteminterface_qpa.cpp b/src/gui/kernel/qwindowsysteminterface_qpa.cpp
index ae94b75076..e6c4454104 100644
--- a/src/gui/kernel/qwindowsysteminterface_qpa.cpp
+++ b/src/gui/kernel/qwindowsysteminterface_qpa.cpp
@@ -296,6 +296,22 @@ void QWindowSystemInterface::handleTouchEvent(QWindow *tlw, ulong timestamp, QTo
QWindowSystemInterfacePrivate::queueWindowSystemEvent(e);
}
+void QWindowSystemInterface::handleTouchCancelEvent(QWindow *w, QTouchDevice *device,
+ Qt::KeyboardModifiers mods)
+{
+ unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed();
+ handleTouchCancelEvent(w, time, device, mods);
+}
+
+void QWindowSystemInterface::handleTouchCancelEvent(QWindow *w, ulong timestamp, QTouchDevice *device,
+ Qt::KeyboardModifiers mods)
+{
+ QWindowSystemInterfacePrivate::TouchEvent *e =
+ new QWindowSystemInterfacePrivate::TouchEvent(w, timestamp, QEvent::TouchCancel, device,
+ QList<QTouchEvent::TouchPoint>(), mods);
+ QWindowSystemInterfacePrivate::queueWindowSystemEvent(e);
+}
+
void QWindowSystemInterface::handleScreenOrientationChange(QScreen *screen, Qt::ScreenOrientation orientation)
{
QWindowSystemInterfacePrivate::ScreenOrientationEvent *e =
@@ -324,6 +340,12 @@ void QWindowSystemInterface::handleScreenLogicalDotsPerInchChange(QScreen *scree
QWindowSystemInterfacePrivate::queueWindowSystemEvent(e);
}
+void QWindowSystemInterface::handleThemeChange(QWindow *tlw)
+{
+ QWindowSystemInterfacePrivate::ThemeChangeEvent *e = new QWindowSystemInterfacePrivate::ThemeChangeEvent(tlw);
+ QWindowSystemInterfacePrivate::queueWindowSystemEvent(e);
+}
+
void QWindowSystemInterface::handleMapEvent(QWindow *tlw)
{
QWindowSystemInterfacePrivate::MapEvent *e = new QWindowSystemInterfacePrivate::MapEvent(tlw);
diff --git a/src/gui/kernel/qwindowsysteminterface_qpa.h b/src/gui/kernel/qwindowsysteminterface_qpa.h
index b99363eda7..78152a1178 100644
--- a/src/gui/kernel/qwindowsysteminterface_qpa.h
+++ b/src/gui/kernel/qwindowsysteminterface_qpa.h
@@ -101,6 +101,8 @@ public:
const QList<struct TouchPoint> &points, Qt::KeyboardModifiers mods = Qt::NoModifier);
static void handleTouchEvent(QWindow *w, ulong timestamp, QTouchDevice *device,
const QList<struct TouchPoint> &points, Qt::KeyboardModifiers mods = Qt::NoModifier);
+ static void handleTouchCancelEvent(QWindow *w, QTouchDevice *device, Qt::KeyboardModifiers mods = Qt::NoModifier);
+ static void handleTouchCancelEvent(QWindow *w, ulong timestamp, QTouchDevice *device, Qt::KeyboardModifiers mods = Qt::NoModifier);
static void handleGeometryChange(QWindow *w, const QRect &newRect);
static void handleSynchronousGeometryChange(QWindow *w, const QRect &newRect);
@@ -128,6 +130,8 @@ public:
static void handleScreenAvailableGeometryChange(QScreen *screen, const QRect &newAvailableGeometry);
static void handleScreenLogicalDotsPerInchChange(QScreen *screen, qreal newDpiX, qreal newDpiY);
+ static void handleThemeChange(QWindow *tlw);
+
// For event dispatcher implementations
static bool sendWindowSystemEvents(QAbstractEventDispatcher *eventDispatcher, QEventLoop::ProcessEventsFlags flags);
static int windowSystemEventsQueued();
diff --git a/src/gui/kernel/qwindowsysteminterface_qpa_p.h b/src/gui/kernel/qwindowsysteminterface_qpa_p.h
index 0bd9ba017a..661b39da88 100644
--- a/src/gui/kernel/qwindowsysteminterface_qpa_p.h
+++ b/src/gui/kernel/qwindowsysteminterface_qpa_p.h
@@ -64,6 +64,7 @@ public:
ScreenGeometry,
ScreenAvailableGeometry,
ScreenLogicalDotsPerInch,
+ ThemeChange,
Map,
Unmap,
Expose
@@ -230,6 +231,13 @@ public:
qreal dpiY;
};
+ class ThemeChangeEvent : public WindowSystemEvent {
+ public:
+ explicit ThemeChangeEvent(QWindow * w)
+ : WindowSystemEvent(ThemeChange), window(w) { }
+ QWeakPointer<QWindow> window;
+ };
+
class MapEvent : public WindowSystemEvent {
public:
MapEvent(QWindow *mapped)
diff --git a/src/gui/opengl/qopenglbuffer.cpp b/src/gui/opengl/qopenglbuffer.cpp
index e0ab98df21..e6879a9e60 100644
--- a/src/gui/opengl/qopenglbuffer.cpp
+++ b/src/gui/opengl/qopenglbuffer.cpp
@@ -529,7 +529,11 @@ void *QOpenGLBuffer::map(QOpenGLBuffer::Access access)
return glMapBufferARB(d->type, access);
#endif
Q_UNUSED(access);
- qWarning("QOpenGLBuffer::map(): pending implementation");
+ static bool warned = false;
+ if (!warned) {
+ qWarning("QOpenGLBuffer::map(): pending implementation");
+ warned = true;
+ }
return 0;
}
@@ -560,7 +564,11 @@ bool QOpenGLBuffer::unmap()
return false;
return glUnmapBufferARB(d->type) == GL_TRUE;
#endif
- qWarning("QOpenGLBuffer::map(): pending implementation");
+ static bool warned = false;
+ if (!warned) {
+ qWarning("QOpenGLBuffer::map(): pending implementation");
+ warned = true;
+ }
return 0;
}
diff --git a/src/gui/opengl/qopenglframebufferobject.cpp b/src/gui/opengl/qopenglframebufferobject.cpp
index 5e22554303..0eb264b2d9 100644
--- a/src/gui/opengl/qopenglframebufferobject.cpp
+++ b/src/gui/opengl/qopenglframebufferobject.cpp
@@ -313,9 +313,8 @@ bool QOpenGLFramebufferObjectFormat::operator!=(const QOpenGLFramebufferObjectFo
return !(*this == other);
}
-bool QOpenGLFramebufferObjectPrivate::checkFramebufferStatus() const
+bool QOpenGLFramebufferObjectPrivate::checkFramebufferStatus(QOpenGLContext *ctx) const
{
- QOpenGLContext *ctx = QOpenGLContext::currentContext();
if (!ctx)
return false; // Context no longer exists.
GLenum status = ctx->functions()->glCheckFramebufferStatus(GL_FRAMEBUFFER);
@@ -402,8 +401,6 @@ void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *, const QSi
GLuint texture = 0;
GLuint color_buffer = 0;
- GLuint depth_buffer = 0;
- GLuint stencil_buffer = 0;
QT_CHECK_GLERROR();
// init texture
@@ -417,8 +414,8 @@ void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *, const QSi
int height = size.height();
int level = 0;
while (width > 1 || height > 1) {
- width = (width + 1) >> 1;
- height = (height + 1) >> 1;
+ width = qMax(1, width >> 1);
+ height = qMax(1, height >> 1);
++level;
glTexImage2D(target, level, internal_format, width, height, 0,
GL_RGBA, GL_UNSIGNED_BYTE, NULL);
@@ -432,7 +429,7 @@ void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *, const QSi
target, texture, 0);
QT_CHECK_GLERROR();
- valid = checkFramebufferStatus();
+ valid = checkFramebufferStatus(ctx);
glBindTexture(target, 0);
color_buffer = 0;
@@ -458,12 +455,57 @@ void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *, const QSi
GL_RENDERBUFFER, color_buffer);
QT_CHECK_GLERROR();
- valid = checkFramebufferStatus();
+ valid = checkFramebufferStatus(ctx);
if (valid)
funcs.glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples);
}
+ format.setTextureTarget(target);
+ format.setSamples(int(samples));
+ format.setInternalTextureFormat(internal_format);
+ format.setMipmap(mipmap);
+
+ initAttachments(ctx, attachment);
+
+ funcs.glBindFramebuffer(GL_FRAMEBUFFER, ctx->d_func()->current_fbo);
+ if (valid) {
+ fbo_guard = new QOpenGLSharedResourceGuard(ctx, fbo, freeFramebufferFunc);
+ if (color_buffer)
+ color_buffer_guard = new QOpenGLSharedResourceGuard(ctx, color_buffer, freeRenderbufferFunc);
+ else
+ texture_guard = new QOpenGLSharedResourceGuard(ctx, texture, freeTextureFunc);
+ } else {
+ if (color_buffer)
+ funcs.glDeleteRenderbuffers(1, &color_buffer);
+ else
+ glDeleteTextures(1, &texture);
+ funcs.glDeleteFramebuffers(1, &fbo);
+ }
+ QT_CHECK_GLERROR();
+}
+
+void QOpenGLFramebufferObjectPrivate::initAttachments(QOpenGLContext *ctx, QOpenGLFramebufferObject::Attachment attachment)
+{
+ int samples = format.samples();
+
+ // free existing attachments
+ if (depth_buffer_guard) {
+ funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, 0);
+ depth_buffer_guard->free();
+ }
+ if (stencil_buffer_guard) {
+ funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
+ if (stencil_buffer_guard != depth_buffer_guard)
+ stencil_buffer_guard->free();
+ }
+
+ depth_buffer_guard = 0;
+ stencil_buffer_guard = 0;
+
+ GLuint depth_buffer = 0;
+ GLuint stencil_buffer = 0;
+
// In practice, a combined depth-stencil buffer is supported by all desktop platforms, while a
// separate stencil buffer is not. On embedded devices however, a combined depth-stencil buffer
// might not be supported while separate buffers are, according to QTBUG-12861.
@@ -488,7 +530,7 @@ void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *, const QSi
funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
GL_RENDERBUFFER, stencil_buffer);
- valid = checkFramebufferStatus();
+ valid = checkFramebufferStatus(ctx);
if (!valid) {
funcs.glDeleteRenderbuffers(1, &depth_buffer);
stencil_buffer = depth_buffer = 0;
@@ -529,7 +571,7 @@ void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *, const QSi
}
funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
GL_RENDERBUFFER, depth_buffer);
- valid = checkFramebufferStatus();
+ valid = checkFramebufferStatus(ctx);
if (!valid) {
funcs.glDeleteRenderbuffers(1, &depth_buffer);
depth_buffer = 0;
@@ -559,7 +601,7 @@ void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *, const QSi
}
funcs.glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
GL_RENDERBUFFER, stencil_buffer);
- valid = checkFramebufferStatus();
+ valid = checkFramebufferStatus(ctx);
if (!valid) {
funcs.glDeleteRenderbuffers(1, &stencil_buffer);
stencil_buffer = 0;
@@ -567,7 +609,7 @@ void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *, const QSi
}
// The FBO might have become valid after removing the depth or stencil buffer.
- valid = checkFramebufferStatus();
+ valid = checkFramebufferStatus(ctx);
if (depth_buffer && stencil_buffer) {
fbo_attachment = QOpenGLFramebufferObject::CombinedDepthStencil;
@@ -577,13 +619,7 @@ void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *, const QSi
fbo_attachment = QOpenGLFramebufferObject::NoAttachment;
}
- funcs.glBindFramebuffer(GL_FRAMEBUFFER, ctx->d_func()->current_fbo);
if (valid) {
- fbo_guard = new QOpenGLSharedResourceGuard(ctx, fbo, freeFramebufferFunc);
- if (color_buffer)
- color_buffer_guard = new QOpenGLSharedResourceGuard(ctx, color_buffer, freeRenderbufferFunc);
- else
- texture_guard = new QOpenGLSharedResourceGuard(ctx, texture, freeTextureFunc);
if (depth_buffer)
depth_buffer_guard = new QOpenGLSharedResourceGuard(ctx, depth_buffer, freeRenderbufferFunc);
if (stencil_buffer) {
@@ -593,23 +629,14 @@ void QOpenGLFramebufferObjectPrivate::init(QOpenGLFramebufferObject *, const QSi
stencil_buffer_guard = new QOpenGLSharedResourceGuard(ctx, stencil_buffer, freeRenderbufferFunc);
}
} else {
- if (color_buffer)
- funcs.glDeleteRenderbuffers(1, &color_buffer);
- else
- glDeleteTextures(1, &texture);
if (depth_buffer)
funcs.glDeleteRenderbuffers(1, &depth_buffer);
if (stencil_buffer && depth_buffer != stencil_buffer)
funcs.glDeleteRenderbuffers(1, &stencil_buffer);
- funcs.glDeleteFramebuffers(1, &fbo);
}
QT_CHECK_GLERROR();
- format.setTextureTarget(target);
- format.setSamples(int(samples));
format.setAttachment(fbo_attachment);
- format.setInternalTextureFormat(internal_format);
- format.setMipmap(mipmap);
}
/*!
@@ -861,7 +888,7 @@ bool QOpenGLFramebufferObject::bind()
qWarning("QOpenGLFramebufferObject::bind() called from incompatible context");
#endif
d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, d->fbo());
- d->valid = d->checkFramebufferStatus();
+ d->valid = d->checkFramebufferStatus(current);
if (d->valid && current)
current->d_func()->current_fbo = d->fbo();
return d->valid;
@@ -1108,6 +1135,30 @@ QOpenGLFramebufferObject::Attachment QOpenGLFramebufferObject::attachment() cons
}
/*!
+ Sets the attachments of the framebuffer object.
+
+ This can be used to free or reattach the depth and stencil buffer
+ attachments as needed.
+ */
+void QOpenGLFramebufferObject::setAttachment(QOpenGLFramebufferObject::Attachment attachment)
+{
+ Q_D(QOpenGLFramebufferObject);
+ if (attachment == d->fbo_attachment || !isValid())
+ return;
+ QOpenGLContext *current = QOpenGLContext::currentContext();
+ if (!current)
+ return;
+#ifdef QT_DEBUG
+ if (current->shareGroup() != d->fbo_guard->group())
+ qWarning("QOpenGLFramebufferObject::setAttachment() called from incompatible context");
+#endif
+ d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, d->fbo());
+ d->initAttachments(current, attachment);
+ if (current->d_func()->current_fbo != d->fbo())
+ d->funcs.glBindFramebuffer(GL_FRAMEBUFFER, current->d_func()->current_fbo);
+}
+
+/*!
Returns true if the framebuffer object is currently bound to a context,
otherwise false is returned.
*/
diff --git a/src/gui/opengl/qopenglframebufferobject.h b/src/gui/opengl/qopenglframebufferobject.h
index 0b2ead1cbb..63260f1940 100644
--- a/src/gui/opengl/qopenglframebufferobject.h
+++ b/src/gui/opengl/qopenglframebufferobject.h
@@ -101,6 +101,8 @@ public:
QImage toImage() const;
Attachment attachment() const;
+ void setAttachment(Attachment attachment);
+
GLuint handle() const;
static bool bindDefault();
diff --git a/src/gui/opengl/qopenglframebufferobject_p.h b/src/gui/opengl/qopenglframebufferobject_p.h
index 78d9d93ffe..23cab8f0af 100644
--- a/src/gui/opengl/qopenglframebufferobject_p.h
+++ b/src/gui/opengl/qopenglframebufferobject_p.h
@@ -120,7 +120,9 @@ public:
QOpenGLFramebufferObject::Attachment attachment,
GLenum internal_format, GLenum texture_target,
GLint samples = 0, bool mipmap = false);
- bool checkFramebufferStatus() const;
+ void initAttachments(QOpenGLContext *ctx, QOpenGLFramebufferObject::Attachment attachment);
+
+ bool checkFramebufferStatus(QOpenGLContext *ctx) const;
QOpenGLSharedResourceGuard *fbo_guard;
QOpenGLSharedResourceGuard *texture_guard;
QOpenGLSharedResourceGuard *depth_buffer_guard;
diff --git a/src/gui/opengl/qopenglgradientcache_p.h b/src/gui/opengl/qopenglgradientcache_p.h
index 4035689abd..7acc8c1d9d 100644
--- a/src/gui/opengl/qopenglgradientcache_p.h
+++ b/src/gui/opengl/qopenglgradientcache_p.h
@@ -52,9 +52,9 @@
#include <QMultiHash>
#include <QObject>
-#include <QtGui/QtGui>
#include <private/qopenglcontext_p.h>
#include <QtCore/qmutex.h>
+#include <QGradient>
QT_BEGIN_NAMESPACE
diff --git a/src/gui/opengl/qopengltexturecache_p.h b/src/gui/opengl/qopengltexturecache_p.h
index 549a2f4eab..8ff20e9464 100644
--- a/src/gui/opengl/qopengltexturecache_p.h
+++ b/src/gui/opengl/qopengltexturecache_p.h
@@ -55,7 +55,7 @@
#include <QHash>
#include <QObject>
-#include <QtGui/QtGui>
+#include <QCache>
#include <private/qopenglcontext_p.h>
#include <QtCore/qmutex.h>
diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri
index 61a25e9ac8..4cd2351b23 100644
--- a/src/gui/painting/painting.pri
+++ b/src/gui/painting/painting.pri
@@ -34,7 +34,8 @@ HEADERS += \
painting/qtextureglyphcache_p.h \
painting/qtransform.h \
painting/qplatformbackingstore_qpa.h \
- painting/qpaintbuffer_p.h
+ painting/qpaintbuffer_p.h \
+ painting/qpathsimplifier_p.h
SOURCES += \
@@ -68,7 +69,8 @@ SOURCES += \
painting/qtextureglyphcache.cpp \
painting/qtransform.cpp \
painting/qplatformbackingstore_qpa.cpp \
- painting/qpaintbuffer.cpp
+ painting/qpaintbuffer.cpp \
+ painting/qpathsimplifier.cpp
SOURCES += \
painting/qpaintengine_raster.cpp \
diff --git a/src/gui/painting/qbackingstore.cpp b/src/gui/painting/qbackingstore.cpp
index 37446f4f80..03c2fc8d6a 100644
--- a/src/gui/painting/qbackingstore.cpp
+++ b/src/gui/painting/qbackingstore.cpp
@@ -43,6 +43,7 @@
#include <qwindow.h>
#include <qpixmap.h>
#include <qplatformbackingstore_qpa.h>
+#include <qplatformintegration_qpa.h>
#include <qscreen.h>
#include <private/qguiapplication_p.h>
diff --git a/src/gui/painting/qblendfunctions.cpp b/src/gui/painting/qblendfunctions.cpp
index a83cadb161..f17a630c8d 100644
--- a/src/gui/painting/qblendfunctions.cpp
+++ b/src/gui/painting/qblendfunctions.cpp
@@ -71,21 +71,6 @@ struct SourceAndConstAlpha
RGB16 (565) format target format
************************************************************************/
-static inline quint16 convert_argb32_to_rgb16(quint32 spix)
-{
- quint32 b = spix;
- quint32 g = spix;
- b >>= 8;
- g >>= 5;
- b &= 0x0000f800;
- g &= 0x000007e0;
- spix >>= 3;
- b |= g;
- spix &= 0x0000001f;
- b |= spix;
- return b;
-}
-
struct Blend_RGB16_on_RGB16_NoAlpha {
inline void write(quint16 *dst, quint16 src) { *dst = src; }
@@ -108,46 +93,11 @@ struct Blend_RGB16_on_RGB16_ConstAlpha {
quint32 m_ialpha;
};
-struct Blend_ARGB24_on_RGB16_SourceAlpha {
- inline void write(quint16 *dst, const qargb8565 &src) {
- const uint alpha = src.alpha();
- if (alpha) {
- quint16 s = src.rawValue16();
- if (alpha < 255)
- s += BYTE_MUL_RGB16(*dst, 255 - alpha);
- *dst = s;
- }
- }
-
- inline void flush(void *) {}
-};
-
-struct Blend_ARGB24_on_RGB16_SourceAndConstAlpha {
- inline Blend_ARGB24_on_RGB16_SourceAndConstAlpha(quint32 alpha) {
- m_alpha = (alpha * 255) >> 8;
- }
-
- inline void write(quint16 *dst, qargb8565 src) {
- src = src.byte_mul(src.alpha(m_alpha));
- const uint alpha = src.alpha();
- if (alpha) {
- quint16 s = src.rawValue16();
- if (alpha < 255)
- s += BYTE_MUL_RGB16(*dst, 255 - alpha);
- *dst = s;
- }
- }
-
- inline void flush(void *) {}
-
- quint32 m_alpha;
-};
-
struct Blend_ARGB32_on_RGB16_SourceAlpha {
inline void write(quint16 *dst, quint32 src) {
const quint8 alpha = qAlpha(src);
- if(alpha) {
- quint16 s = convert_argb32_to_rgb16(src);
+ if (alpha) {
+ quint16 s = qConvertRgb32To16(src);
if(alpha < 255)
s += BYTE_MUL_RGB16(*dst, 255 - alpha);
*dst = s;
@@ -166,7 +116,7 @@ struct Blend_ARGB32_on_RGB16_SourceAndConstAlpha {
src = BYTE_MUL(src, m_alpha);
const quint8 alpha = qAlpha(src);
if(alpha) {
- quint16 s = convert_argb32_to_rgb16(src);
+ quint16 s = qConvertRgb32To16(src);
if(alpha < 255)
s += BYTE_MUL_RGB16(*dst, 255 - alpha);
*dst = s;
@@ -203,32 +153,6 @@ void qt_scale_image_rgb16_on_rgb16(uchar *destPixels, int dbpl,
}
}
-void qt_scale_image_argb24_on_rgb16(uchar *destPixels, int dbpl,
- const uchar *srcPixels, int sbpl,
- const QRectF &targetRect,
- const QRectF &sourceRect,
- const QRect &clip,
- int const_alpha)
-{
-#ifdef QT_DEBUG_DRAW
- printf("qt_scale_argb24_on_rgb16: dst=(%p, %d), src=(%p, %d), target=(%d, %d), [%d x %d], src=(%d, %d) [%d x %d] alpha=%d\n",
- destPixels, dbpl, srcPixels, sbpl,
- targetRect.x(), targetRect.y(), targetRect.width(), targetRect.height(),
- sourceRect.x(), sourceRect.y(), sourceRect.width(), sourceRect.height(),
- const_alpha);
-#endif
- if (const_alpha == 256) {
- Blend_ARGB24_on_RGB16_SourceAlpha noAlpha;
- qt_scale_image_16bit<qargb8565>(destPixels, dbpl, srcPixels, sbpl,
- targetRect, sourceRect, clip, noAlpha);
- } else {
- Blend_ARGB24_on_RGB16_SourceAndConstAlpha constAlpha(const_alpha);
- qt_scale_image_16bit<qargb8565>(destPixels, dbpl, srcPixels, sbpl,
- targetRect, sourceRect, clip, constAlpha);
- }
-}
-
-
void qt_scale_image_argb32_on_rgb16(uchar *destPixels, int dbpl,
const uchar *srcPixels, int sbpl,
const QRectF &targetRect,
@@ -280,7 +204,6 @@ void qt_blend_rgb16_on_rgb16(uchar *dst, int dbpl,
}
}
} else if (const_alpha != 0) {
- SourceAndConstAlpha alpha(const_alpha); // expects the 0-256 range
quint16 *d = (quint16 *) dst;
const quint16 *s = (const quint16 *) src;
quint8 a = (255 * const_alpha) >> 8;
@@ -296,79 +219,6 @@ void qt_blend_rgb16_on_rgb16(uchar *dst, int dbpl,
}
-template <typename T> void qt_blend_argb24_on_rgb16(uchar *destPixels, int dbpl,
- const uchar *srcPixels, int sbpl,
- int w, int h, const T &alphaFunc)
-{
- int srcOffset = w*3;
- int dstJPL = dbpl / 2;
- quint16 *dst = (quint16 *) destPixels;
- int dstExtraStride = dstJPL - w;
-
- for (int y=0; y<h; ++y) {
- const uchar *src = srcPixels + y * sbpl;
- const uchar *srcEnd = src + srcOffset;
- while (src < srcEnd) {
-#if defined(QT_ARCH_ARMV5) || defined(QT_ARCH_POWERPC) || defined(QT_ARCH_SH) || defined(QT_ARCH_AVR32) || (defined(QT_ARCH_WINDOWSCE) && !defined(_X86_)) || (defined(QT_ARCH_SPARC) && defined(Q_CC_GNU)) || (defined(QT_ARCH_INTEGRITY) && !defined(_X86_))
- // non-16-bit aligned memory access is not possible on PowerPC,
- // ARM <v6 (QT_ARCH_ARMV5) & SH & AVR32 & SPARC w/GCC
- quint16 spix = (quint16(src[2])<<8) + src[1];
-#else
- quint16 spix = *(quint16 *) (src + 1);
-#endif
- uchar alpha = alphaFunc.alpha(*src);
-
- if (alpha == 255) {
- *dst = spix;
- } else if (alpha != 0) {
- quint16 dpix = *dst;
- quint32 sia = 255 - alpha;
-
- quint16 dr = (dpix & 0x0000f800);
- quint16 dg = (dpix & 0x000007e0);
- quint16 db = (dpix & 0x0000001f);
-
- quint32 siar = dr * sia;
- quint32 siag = dg * sia;
- quint32 siab = db * sia;
-
- quint32 rr = ((siar + (siar>>8) + (0x80 << 8)) >> 8) & 0xf800;
- quint32 rg = ((siag + (siag>>8) + (0x80 << 3)) >> 8) & 0x07e0;
- quint32 rb = ((siab + (siab>>8) + (0x80 >> 3)) >> 8) & 0x001f;
-
- *dst = alphaFunc.bytemul(spix) + rr + rg + rb;
- }
-
- ++dst;
- src += 3;
- }
- dst += dstExtraStride;
- }
-
-}
-
-static void qt_blend_argb24_on_rgb16(uchar *destPixels, int dbpl,
- const uchar *srcPixels, int sbpl,
- int w, int h,
- int const_alpha)
-{
-#ifdef QT_DEBUG_DRAW
- printf("qt_blend_argb24_on_rgb16: dst=(%p, %d), src=(%p, %d), dim=(%d, %d) alpha=%d\n",
- destPixels, dbpl, srcPixels, sbpl, w, h, const_alpha);
-#endif
-
- if (const_alpha != 256) {
- SourceAndConstAlpha alphaFunc(const_alpha);
- qt_blend_argb24_on_rgb16(destPixels, dbpl, srcPixels, sbpl, w, h, alphaFunc);
- } else {
- SourceOnlyAlpha alphaFunc;
- qt_blend_argb24_on_rgb16(destPixels, dbpl, srcPixels, sbpl, w, h, alphaFunc);
- }
-}
-
-
-
-
void qt_blend_argb32_on_rgb16_const_alpha(uchar *destPixels, int dbpl,
const uchar *srcPixels, int sbpl,
int w, int h,
@@ -383,7 +233,7 @@ void qt_blend_argb32_on_rgb16_const_alpha(uchar *destPixels, int dbpl,
uint s = src[i];
s = BYTE_MUL(s, const_alpha);
int alpha = qAlpha(s);
- s = convert_argb32_to_rgb16(s);
+ s = qConvertRgb32To16(s);
s += BYTE_MUL_RGB16(dst[i], 255 - alpha);
dst[i] = s;
}
@@ -412,7 +262,7 @@ static void qt_blend_argb32_on_rgb16(uchar *destPixels, int dbpl,
quint32 alpha = spix >> 24;
if (alpha == 255) {
- dst[x] = convert_argb32_to_rgb16(spix);
+ dst[x] = qConvertRgb32To16(spix);
} else if (alpha != 0) {
quint32 dpix = dst[x];
@@ -473,7 +323,7 @@ static void qt_blend_rgb32_on_rgb16(uchar *destPixels, int dbpl,
while (dst < dstEnd) {
const quint32 *srcEnd = src + w;
while (src < srcEnd) {
- *dst = convert_argb32_to_rgb16(*src);
+ *dst = qConvertRgb32To16(*src);
++dst;
++src;
}
@@ -545,19 +395,11 @@ void qt_blend_rgb32_on_rgb32(uchar *destPixels, int dbpl,
const uint *src = (const uint *) srcPixels;
uint *dst = (uint *) destPixels;
- if (w <= 64) {
- for (int y=0; y<h; ++y) {
- qt_memconvert(dst, src, w);
- dst = (quint32 *)(((uchar *) dst) + dbpl);
- src = (const quint32 *)(((const uchar *) src) + sbpl);
- }
- } else {
- int len = w * 4;
- for (int y=0; y<h; ++y) {
- memcpy(dst, src, len);
- dst = (quint32 *)(((uchar *) dst) + dbpl);
- src = (const quint32 *)(((const uchar *) src) + sbpl);
- }
+ int len = w * 4;
+ for (int y=0; y<h; ++y) {
+ memcpy(dst, src, len);
+ dst = (quint32 *)(((uchar *) dst) + dbpl);
+ src = (const quint32 *)(((const uchar *) src) + sbpl);
}
}
@@ -681,28 +523,6 @@ void qt_transform_image_rgb16_on_rgb16(uchar *destPixels, int dbpl,
}
}
-void qt_transform_image_argb24_on_rgb16(uchar *destPixels, int dbpl,
- const uchar *srcPixels, int sbpl,
- const QRectF &targetRect,
- const QRectF &sourceRect,
- const QRect &clip,
- const QTransform &targetRectTransform,
- int const_alpha)
-{
- if (const_alpha == 256) {
- Blend_ARGB24_on_RGB16_SourceAlpha noAlpha;
- qt_transform_image(reinterpret_cast<quint16 *>(destPixels), dbpl,
- reinterpret_cast<const qargb8565 *>(srcPixels), sbpl,
- targetRect, sourceRect, clip, targetRectTransform, noAlpha);
- } else {
- Blend_ARGB24_on_RGB16_SourceAndConstAlpha constAlpha(const_alpha);
- qt_transform_image(reinterpret_cast<quint16 *>(destPixels), dbpl,
- reinterpret_cast<const qargb8565 *>(srcPixels), sbpl,
- targetRect, sourceRect, clip, targetRectTransform, constAlpha);
- }
-}
-
-
void qt_transform_image_argb32_on_rgb16(uchar *destPixels, int dbpl,
const uchar *srcPixels, int sbpl,
const QRectF &targetRect,
@@ -903,7 +723,7 @@ SrcOverScaleFunc qScaleFunctions[QImage::NImageFormats][QImage::NImageFormats] =
0, // Format_ARGB32,
qt_scale_image_argb32_on_rgb16, // Format_ARGB32_Premultiplied,
qt_scale_image_rgb16_on_rgb16, // Format_RGB16,
- qt_scale_image_argb24_on_rgb16, // Format_ARGB8565_Premultiplied,
+ 0, // Format_ARGB8565_Premultiplied,
0, // Format_RGB666,
0, // Format_ARGB6666_Premultiplied,
0, // Format_RGB555,
@@ -1195,7 +1015,7 @@ SrcOverBlendFunc qBlendFunctions[QImage::NImageFormats][QImage::NImageFormats] =
0, // Format_ARGB32,
qt_blend_argb32_on_rgb16, // Format_ARGB32_Premultiplied,
qt_blend_rgb16_on_rgb16, // Format_RGB16,
- qt_blend_argb24_on_rgb16, // Format_ARGB8565_Premultiplied,
+ 0, // Format_ARGB8565_Premultiplied,
0, // Format_RGB666,
0, // Format_ARGB6666_Premultiplied,
0, // Format_RGB555,
@@ -1486,7 +1306,7 @@ SrcOverTransformFunc qTransformFunctions[QImage::NImageFormats][QImage::NImageFo
0, // Format_ARGB32,
qt_transform_image_argb32_on_rgb16, // Format_ARGB32_Premultiplied,
qt_transform_image_rgb16_on_rgb16, // Format_RGB16,
- qt_transform_image_argb24_on_rgb16, // Format_ARGB8565_Premultiplied,
+ 0, // Format_ARGB8565_Premultiplied,
0, // Format_RGB666,
0, // Format_ARGB6666_Premultiplied,
0, // Format_RGB555,
diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp
index 13b8c8cae5..0491a3deaf 100644
--- a/src/gui/painting/qdrawhelper.cpp
+++ b/src/gui/painting/qdrawhelper.cpp
@@ -79,6 +79,232 @@ enum {
// must be multiple of 4 for easier SIMD implementations
static const int buffer_size = 2048;
+
+
+
+// To convert in place, let 'dest' and 'src' be the same.
+static const uint *QT_FASTCALL convertIndexedToARGB32PM(uint *buffer, const uint *src, int count,
+ const QPixelLayout *, const QRgb *clut)
+{
+ for (int i = 0; i < count; ++i)
+ buffer[i] = PREMUL(clut[src[i]]);
+ return buffer;
+}
+
+static const uint *QT_FASTCALL convertPassThrough(uint *, const uint *src, int,
+ const QPixelLayout *, const QRgb *)
+{
+ return src;
+}
+
+static const uint *QT_FASTCALL convertRGB16ToARGB32PM(uint *buffer, const uint *src, int count,
+ const QPixelLayout *, const QRgb *)
+{
+ for (int i = 0; i < count; ++i)
+ buffer[i] = qConvertRgb16To32(src[i]);
+ return buffer;
+}
+
+static const uint *QT_FASTCALL convertARGB32ToARGB32PM(uint *buffer, const uint *src, int count,
+ const QPixelLayout *, const QRgb *)
+{
+ for (int i = 0; i < count; ++i)
+ buffer[i] = PREMUL(src[i]);
+ return buffer;
+}
+
+static const uint *QT_FASTCALL convertToRGB32(uint *buffer, const uint *src, int count,
+ const QPixelLayout *layout, const QRgb *)
+{
+ Q_ASSERT(layout->redWidth >= 4);
+ Q_ASSERT(layout->greenWidth >= 4);
+ Q_ASSERT(layout->blueWidth >= 4);
+ Q_ASSERT(layout->alphaWidth == 0);
+
+ const uint redMask = ((1 << layout->redWidth) - 1);
+ const uint greenMask = ((1 << layout->greenWidth) - 1);
+ const uint blueMask = ((1 << layout->blueWidth) - 1);
+
+ const uchar redLeftShift = 8 - layout->redWidth;
+ const uchar greenLeftShift = 8 - layout->greenWidth;
+ const uchar blueLeftShift = 8 - layout->blueWidth;
+
+ const uchar redRightShift = 2 * layout->redWidth - 8;
+ const uchar greenRightShift = 2 * layout->greenWidth - 8;
+ const uchar blueRightShift = 2 * layout->blueWidth - 8;
+
+ for (int i = 0; i < count; ++i) {
+ uint red = (src[i] >> layout->redShift) & redMask;
+ uint green = (src[i] >> layout->greenShift) & greenMask;
+ uint blue = (src[i] >> layout->blueShift) & blueMask;
+
+ red = ((red << redLeftShift) | (red >> redRightShift)) << 16;
+ green = ((green << greenLeftShift) | (green >> greenRightShift)) << 8;
+ blue = (blue << blueLeftShift) | (blue >> blueRightShift);
+ buffer[i] = 0xff000000 | red | green | blue;
+ }
+
+ return buffer;
+}
+
+static const uint *QT_FASTCALL convertToARGB32PM(uint *buffer, const uint *src, int count,
+ const QPixelLayout *layout, const QRgb *)
+{
+ Q_ASSERT(layout->redWidth >= 4);
+ Q_ASSERT(layout->greenWidth >= 4);
+ Q_ASSERT(layout->blueWidth >= 4);
+ Q_ASSERT(layout->alphaWidth >= 4);
+
+ const uint redMask = ((1 << layout->redWidth) - 1);
+ const uint greenMask = ((1 << layout->greenWidth) - 1);
+ const uint blueMask = ((1 << layout->blueWidth) - 1);
+
+ const uchar redLeftShift = 8 - layout->redWidth;
+ const uchar greenLeftShift = 8 - layout->greenWidth;
+ const uchar blueLeftShift = 8 - layout->blueWidth;
+
+ const uchar redRightShift = 2 * layout->redWidth - 8;
+ const uchar greenRightShift = 2 * layout->greenWidth - 8;
+ const uchar blueRightShift = 2 * layout->blueWidth - 8;
+
+ const uint alphaMask = ((1 << layout->alphaWidth) - 1);
+ const uchar alphaLeftShift = 8 - layout->alphaWidth;
+ const uchar alphaRightShift = 2 * layout->alphaWidth - 8;
+
+ if (layout->premultiplied) {
+ for (int i = 0; i < count; ++i) {
+ uint alpha = (src[i] >> layout->alphaShift) & alphaMask;
+ uint red = (src[i] >> layout->redShift) & redMask;
+ uint green = (src[i] >> layout->greenShift) & greenMask;
+ uint blue = (src[i] >> layout->blueShift) & blueMask;
+
+ alpha = (alpha << alphaLeftShift) | (alpha >> alphaRightShift);
+ red = qMin(alpha, (red << redLeftShift) | (red >> redRightShift));
+ green = qMin(alpha, (green << greenLeftShift) | (green >> greenRightShift));
+ blue = qMin(alpha, (blue << blueLeftShift) | (blue >> blueRightShift));
+ buffer[i] = (alpha << 24) | (red << 16) | (green << 8) | blue;
+ }
+ } else {
+ for (int i = 0; i < count; ++i) {
+ uint alpha = (src[i] >> layout->alphaShift) & alphaMask;
+ uint red = (src[i] >> layout->redShift) & redMask;
+ uint green = (src[i] >> layout->greenShift) & greenMask;
+ uint blue = (src[i] >> layout->blueShift) & blueMask;
+
+ alpha = (alpha << alphaLeftShift) | (alpha >> alphaRightShift);
+ red = (red << redLeftShift) | (red >> redRightShift);
+ green = (green << greenLeftShift) | (green >> greenRightShift);
+ blue = (blue << blueLeftShift) | (blue >> blueRightShift);
+ buffer[i] = PREMUL((alpha << 24) | (red << 16) | (green << 8) | blue);
+ }
+ }
+ return buffer;
+}
+
+static const uint *QT_FASTCALL convertRGB16FromARGB32PM(uint *buffer, const uint *src, int count,
+ const QPixelLayout *, const QRgb *)
+{
+ for (int i = 0; i < count; ++i)
+ buffer[i] = qConvertRgb32To16(INV_PREMUL(src[i]));
+ return buffer;
+}
+
+static const uint *QT_FASTCALL convertARGB32FromARGB32PM(uint *buffer, const uint *src, int count,
+ const QPixelLayout *, const QRgb *)
+{
+ for (int i = 0; i < count; ++i)
+ buffer[i] = INV_PREMUL(src[i]);
+ return buffer;
+}
+
+static const uint *QT_FASTCALL convertFromARGB32PM(uint *buffer, const uint *src, int count,
+ const QPixelLayout *layout, const QRgb *)
+{
+ Q_ASSERT(layout->redWidth <= 8);
+ Q_ASSERT(layout->greenWidth <= 8);
+ Q_ASSERT(layout->blueWidth <= 8);
+ Q_ASSERT(layout->alphaWidth <= 8);
+
+ const uint redMask = (1 << layout->redWidth) - 1;
+ const uint greenMask = (1 << layout->greenWidth) - 1;
+ const uint blueMask = (1 << layout->blueWidth) - 1;
+ const uint alphaMask = (1 << layout->alphaWidth) - 1;
+
+ const uchar redRightShift = 24 - layout->redWidth;
+ const uchar greenRightShift = 16 - layout->greenWidth;
+ const uchar blueRightShift = 8 - layout->blueWidth;
+ const uchar alphaRightShift = 32 - layout->alphaWidth;
+
+ if (!layout->premultiplied) {
+ for (int i = 0; i < count; ++i)
+ buffer[i] = qAlpha(src[i]) == 255 ? src[i] : INV_PREMUL(src[i]);
+ src = buffer;
+ }
+ for (int i = 0; i < count; ++i) {
+ uint red = ((src[i] >> redRightShift) & redMask) << layout->redShift;
+ uint green = ((src[i] >> greenRightShift) & greenMask) << layout->greenShift;
+ uint blue = ((src[i] >> blueRightShift) & blueMask) << layout->blueShift;
+ uint alpha = ((src[i] >> alphaRightShift) & alphaMask) << layout->alphaShift;
+ buffer[i] = red | green | blue | alpha;
+ }
+ return buffer;
+}
+
+// Note:
+// convertToArgb32() assumes that no color channel is less than 4 bits.
+// convertFromArgb32() assumes that no color channel is more than 8 bits.
+// QImage::rgbSwapped() assumes that the red and blue color channels have the same number of bits.
+QPixelLayout qPixelLayouts[QImage::NImageFormats] = {
+ { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPPNone, 0, 0 }, // Format_Invalid
+ { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP1MSB, convertIndexedToARGB32PM, 0 }, // Format_Mono
+ { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP1LSB, convertIndexedToARGB32PM, 0 }, // Format_MonoLSB
+ { 0, 0, 0, 0, 0, 0, 0, 0, false, QPixelLayout::BPP8, convertIndexedToARGB32PM, 0 }, // Format_Indexed8
+ { 8, 16, 8, 8, 8, 0, 0, 0, false, QPixelLayout::BPP32, convertPassThrough, convertPassThrough }, // Format_RGB32
+ { 8, 16, 8, 8, 8, 0, 8, 24, false, QPixelLayout::BPP32, convertARGB32ToARGB32PM, convertARGB32FromARGB32PM }, // Format_ARGB32
+ { 8, 16, 8, 8, 8, 0, 8, 24, true, QPixelLayout::BPP32, convertPassThrough, convertPassThrough }, // Format_ARGB32_Premultiplied
+ { 5, 11, 6, 5, 5, 0, 0, 0, false, QPixelLayout::BPP16, convertRGB16ToARGB32PM, convertRGB16FromARGB32PM }, // Format_RGB16
+ { 5, 19, 6, 13, 5, 8, 8, 0, true, QPixelLayout::BPP24, convertToARGB32PM, convertFromARGB32PM }, // Format_ARGB8565_Premultiplied
+ { 6, 12, 6, 6, 6, 0, 0, 0, false, QPixelLayout::BPP24, convertToRGB32, convertFromARGB32PM }, // Format_RGB666
+ { 6, 12, 6, 6, 6, 0, 6, 18, true, QPixelLayout::BPP24, convertToARGB32PM, convertFromARGB32PM }, // Format_ARGB6666_Premultiplied
+ { 5, 10, 5, 5, 5, 0, 0, 0, false, QPixelLayout::BPP16, convertToRGB32, convertFromARGB32PM }, // Format_RGB555
+ { 5, 18, 5, 13, 5, 8, 8, 0, true, QPixelLayout::BPP24, convertToARGB32PM, convertFromARGB32PM }, // Format_ARGB8555_Premultiplied
+ { 8, 0, 8, 8, 8, 16, 0, 0, false, QPixelLayout::BPP24, convertToRGB32, convertFromARGB32PM }, // Format_RGB888
+ { 4, 8, 4, 4, 4, 0, 0, 0, false, QPixelLayout::BPP16, convertToRGB32, convertFromARGB32PM }, // Format_RGB444
+ { 4, 8, 4, 4, 4, 0, 4, 12, true, QPixelLayout::BPP16, convertToARGB32PM, convertFromARGB32PM } // Format_ARGB4444_Premultiplied
+};
+
+FetchPixelsFunc qFetchPixels[QPixelLayout::BPPCount] = {
+ 0, // BPPNone
+ fetchPixels<QPixelLayout::BPP1MSB>, // BPP1MSB
+ fetchPixels<QPixelLayout::BPP1LSB>, // BPP1LSB
+ fetchPixels<QPixelLayout::BPP8>, // BPP8
+ fetchPixels<QPixelLayout::BPP16>, // BPP16
+ fetchPixels<QPixelLayout::BPP24>, // BPP24
+ fetchPixels<QPixelLayout::BPP32> // BPP32
+};
+
+StorePixelsFunc qStorePixels[QPixelLayout::BPPCount] = {
+ 0, // BPPNone
+ storePixels<QPixelLayout::BPP1MSB>, // BPP1MSB
+ storePixels<QPixelLayout::BPP1LSB>, // BPP1LSB
+ storePixels<QPixelLayout::BPP8>, // BPP8
+ storePixels<QPixelLayout::BPP16>, // BPP16
+ storePixels<QPixelLayout::BPP24>, // BPP24
+ storePixels<QPixelLayout::BPP32> // BPP32
+};
+
+typedef uint (QT_FASTCALL *FetchPixelFunc)(const uchar *src, int index);
+
+FetchPixelFunc qFetchPixel[QPixelLayout::BPPCount] = {
+ 0, // BPPNone
+ fetchPixel<QPixelLayout::BPP1MSB>, // BPP1MSB
+ fetchPixel<QPixelLayout::BPP1LSB>, // BPP1LSB
+ fetchPixel<QPixelLayout::BPP8>, // BPP8
+ fetchPixel<QPixelLayout::BPP16>, // BPP16
+ fetchPixel<QPixelLayout::BPP24>, // BPP24
+ fetchPixel<QPixelLayout::BPP32> // BPP32
+};
+
/*
Destination fetch. This is simple as we don't have to do bounds checks or
transformations
@@ -110,14 +336,6 @@ static uint * QT_FASTCALL destFetchMonoLsb(uint *buffer, QRasterBuffer *rasterBu
return start;
}
-static uint * QT_FASTCALL destFetchARGB32(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
-{
- const uint *data = (const uint *)rasterBuffer->scanLine(y) + x;
- for (int i = 0; i < length; ++i)
- buffer[i] = PREMUL(data[i]);
- return buffer;
-}
-
static uint * QT_FASTCALL destFetchARGB32P(uint *, QRasterBuffer *rasterBuffer, int x, int y, int)
{
return (uint *)rasterBuffer->scanLine(y) + x;
@@ -131,37 +349,32 @@ static uint * QT_FASTCALL destFetchRGB16(uint *buffer, QRasterBuffer *rasterBuff
return buffer;
}
-template <class DST>
-Q_STATIC_TEMPLATE_FUNCTION uint * QT_FASTCALL destFetch(uint *buffer, QRasterBuffer *rasterBuffer,
- int x, int y, int length)
+static uint *QT_FASTCALL destFetch(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length)
{
- const DST *src = reinterpret_cast<DST*>(rasterBuffer->scanLine(y)) + x;
- quint32 *dest = reinterpret_cast<quint32*>(buffer);
- while (length--)
- *dest++ = *src++;
- return buffer;
+ const QPixelLayout *layout = &qPixelLayouts[rasterBuffer->format];
+ const uint *ptr = qFetchPixels[layout->bpp](buffer, rasterBuffer->scanLine(y), x, length);
+ return const_cast<uint *>(layout->convertToARGB32PM(buffer, ptr, length, layout, 0));
}
-# define SPANFUNC_POINTER_DESTFETCH(Arg) destFetch<Arg>
static DestFetchProc destFetchProc[QImage::NImageFormats] =
{
- 0, // Format_Invalid
- destFetchMono, // Format_Mono,
- destFetchMonoLsb, // Format_MonoLSB
- 0, // Format_Indexed8
- destFetchARGB32P, // Format_RGB32
- destFetchARGB32, // Format_ARGB32,
- destFetchARGB32P, // Format_ARGB32_Premultiplied
- destFetchRGB16, // Format_RGB16
- SPANFUNC_POINTER_DESTFETCH(qargb8565), // Format_ARGB8565_Premultiplied
- SPANFUNC_POINTER_DESTFETCH(qrgb666), // Format_RGB666
- SPANFUNC_POINTER_DESTFETCH(qargb6666), // Format_ARGB6666_Premultiplied
- SPANFUNC_POINTER_DESTFETCH(qrgb555), // Format_RGB555
- SPANFUNC_POINTER_DESTFETCH(qargb8555), // Format_ARGB8555_Premultiplied
- SPANFUNC_POINTER_DESTFETCH(qrgb888), // Format_RGB888
- SPANFUNC_POINTER_DESTFETCH(qrgb444), // Format_RGB444
- SPANFUNC_POINTER_DESTFETCH(qargb4444) // Format_ARGB4444_Premultiplied
+ 0, // Format_Invalid
+ destFetchMono, // Format_Mono,
+ destFetchMonoLsb, // Format_MonoLSB
+ 0, // Format_Indexed8
+ destFetchARGB32P, // Format_RGB32
+ destFetch, // Format_ARGB32,
+ destFetchARGB32P, // Format_ARGB32_Premultiplied
+ destFetchRGB16, // Format_RGB16
+ destFetch, // Format_ARGB8565_Premultiplied
+ destFetch, // Format_RGB666
+ destFetch, // Format_ARGB6666_Premultiplied
+ destFetch, // Format_RGB555
+ destFetch, // Format_ARGB8555_Premultiplied
+ destFetch, // Format_RGB888
+ destFetch, // Format_RGB444
+ destFetch // Format_ARGB4444_Premultiplied
};
/*
@@ -253,63 +466,47 @@ static void QT_FASTCALL destStoreMonoLsb(QRasterBuffer *rasterBuffer, int x, int
}
}
-static void QT_FASTCALL destStoreARGB32(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
-{
- uint *data = (uint *)rasterBuffer->scanLine(y) + x;
- for (int i = 0; i < length; ++i) {
- int p = buffer[i];
- int alpha = qAlpha(p);
- if (alpha == 255)
- data[i] = p;
- else if (alpha == 0)
- data[i] = 0;
- else {
- int inv_alpha = 0xff0000/qAlpha(buffer[i]);
- data[i] = (p & 0xff000000)
- | ((qRed(p)*inv_alpha) & 0xff0000)
- | (((qGreen(p)*inv_alpha) >> 8) & 0xff00)
- | ((qBlue(p)*inv_alpha) >> 16);
- }
- }
-}
-
static void QT_FASTCALL destStoreRGB16(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
{
quint16 *data = (quint16*)rasterBuffer->scanLine(y) + x;
- qt_memconvert<quint16, quint32>(data, buffer, length);
+ for (int i = 0; i < length; ++i)
+ data[i] = qConvertRgb32To16(buffer[i]);
}
-template <class DST>
-Q_STATIC_TEMPLATE_FUNCTION void QT_FASTCALL destStore(QRasterBuffer *rasterBuffer,
- int x, int y,
- const uint *buffer, int length)
+static void QT_FASTCALL destStore(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length)
{
- DST *dest = reinterpret_cast<DST*>(rasterBuffer->scanLine(y)) + x;
- const quint32p *src = reinterpret_cast<const quint32p*>(buffer);
- while (length--)
- *dest++ = DST(*src++);
+ uint buf[buffer_size];
+ const QPixelLayout *layout = &qPixelLayouts[rasterBuffer->format];
+ StorePixelsFunc store = qStorePixels[layout->bpp];
+ uchar *dest = rasterBuffer->scanLine(y);
+ while (length) {
+ int l = qMin(length, buffer_size);
+ const uint *ptr = layout->convertFromARGB32PM(buf, buffer, l, layout, 0);
+ store(dest, ptr, x, l);
+ length -= l;
+ buffer += l;
+ x += l;
+ }
}
-# define SPANFUNC_POINTER_DESTSTORE(DEST) destStore<DEST>
-
static DestStoreProc destStoreProc[QImage::NImageFormats] =
{
- 0, // Format_Invalid
- destStoreMono, // Format_Mono,
- destStoreMonoLsb, // Format_MonoLSB
- 0, // Format_Indexed8
- 0, // Format_RGB32
- destStoreARGB32, // Format_ARGB32,
- 0, // Format_ARGB32_Premultiplied
- destStoreRGB16, // Format_RGB16
- SPANFUNC_POINTER_DESTSTORE(qargb8565), // Format_ARGB8565_Premultiplied
- SPANFUNC_POINTER_DESTSTORE(qrgb666), // Format_RGB666
- SPANFUNC_POINTER_DESTSTORE(qargb6666), // Format_ARGB6666_Premultiplied
- SPANFUNC_POINTER_DESTSTORE(qrgb555), // Format_RGB555
- SPANFUNC_POINTER_DESTSTORE(qargb8555), // Format_ARGB8555_Premultiplied
- SPANFUNC_POINTER_DESTSTORE(qrgb888), // Format_RGB888
- SPANFUNC_POINTER_DESTSTORE(qrgb444), // Format_RGB444
- SPANFUNC_POINTER_DESTSTORE(qargb4444) // Format_ARGB4444_Premultiplied
+ 0, // Format_Invalid
+ destStoreMono, // Format_Mono,
+ destStoreMonoLsb, // Format_MonoLSB
+ 0, // Format_Indexed8
+ 0, // Format_RGB32
+ destStore, // Format_ARGB32,
+ 0, // Format_ARGB32_Premultiplied
+ destStoreRGB16, // Format_RGB16
+ destStore, // Format_ARGB8565_Premultiplied
+ destStore, // Format_RGB666
+ destStore, // Format_ARGB6666_Premultiplied
+ destStore, // Format_RGB555
+ destStore, // Format_ARGB8555_Premultiplied
+ destStore, // Format_RGB888
+ destStore, // Format_RGB444
+ destStore // Format_ARGB4444_Premultiplied
};
/*
@@ -327,218 +524,139 @@ static DestStoreProc destStoreProc[QImage::NImageFormats] =
The generic implementation does pixel by pixel fetches
*/
-template <QImage::Format format>
-Q_STATIC_TEMPLATE_FUNCTION uint QT_FASTCALL qt_fetchPixel(const uchar *scanLine, int x, const QVector<QRgb> *rgb);
-
-template<>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-uint QT_FASTCALL qt_fetchPixel<QImage::Format_Mono>(const uchar *scanLine,
- int x, const QVector<QRgb> *rgb)
-{
- bool pixel = scanLine[x>>3] & (0x80 >> (x & 7));
- if (rgb) return PREMUL(rgb->at(pixel ? 1 : 0));
- return pixel ? 0xff000000 : 0xffffffff;
-}
-
-template<>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-uint QT_FASTCALL qt_fetchPixel<QImage::Format_MonoLSB>(const uchar *scanLine,
- int x, const QVector<QRgb> *rgb)
-{
- bool pixel = scanLine[x>>3] & (0x1 << (x & 7));
- if (rgb) return PREMUL(rgb->at(pixel ? 1 : 0));
- return pixel ? 0xff000000 : 0xffffffff;
-}
-
-template<>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-uint QT_FASTCALL qt_fetchPixel<QImage::Format_Indexed8>(const uchar *scanLine,
- int x, const QVector<QRgb> *rgb)
-{
- return PREMUL(rgb->at(scanLine[x]));
-}
-
-template<>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB32>(const uchar *scanLine,
- int x, const QVector<QRgb> *)
-{
- return PREMUL(((const uint *)scanLine)[x]);
-}
-
-template<>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB32_Premultiplied>(const uchar *scanLine,
- int x, const QVector<QRgb> *)
-{
- return ((const uint *)scanLine)[x];
-}
-
-template<>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-uint QT_FASTCALL qt_fetchPixel<QImage::Format_RGB16>(const uchar *scanLine,
- int x, const QVector<QRgb> *)
-{
- return qConvertRgb16To32(((const ushort *)scanLine)[x]);
-}
-
-template<>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB8565_Premultiplied>(const uchar *scanLine,
- int x,
- const QVector<QRgb> *)
-{
- const qargb8565 color = reinterpret_cast<const qargb8565*>(scanLine)[x];
- return qt_colorConvert<quint32, qargb8565>(color, 0);
-}
+enum TextureBlendType {
+ BlendUntransformed,
+ BlendTiled,
+ BlendTransformed,
+ BlendTransformedTiled,
+ BlendTransformedBilinear,
+ BlendTransformedBilinearTiled,
+ NBlendTypes
+};
-template<>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-uint QT_FASTCALL qt_fetchPixel<QImage::Format_RGB666>(const uchar *scanLine,
- int x,
- const QVector<QRgb> *)
+static const uint *QT_FASTCALL fetchUntransformed(uint *buffer, const Operator *,
+ const QSpanData *data, int y, int x, int length)
{
- const qrgb666 color = reinterpret_cast<const qrgb666*>(scanLine)[x];
- return qt_colorConvert<quint32, qrgb666>(color, 0);
+ const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
+ const uint *ptr = qFetchPixels[layout->bpp](buffer, data->texture.scanLine(y), x, length);
+ const QRgb *clut = data->texture.colorTable ? data->texture.colorTable->constData() : 0;
+ return layout->convertToARGB32PM(buffer, ptr, length, layout, clut);
}
-template<>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB6666_Premultiplied>(const uchar *scanLine,
- int x,
- const QVector<QRgb> *)
+static const uint *QT_FASTCALL fetchUntransformedARGB32PM(uint *, const Operator *,
+ const QSpanData *data, int y, int x, int)
{
- const qargb6666 color = reinterpret_cast<const qargb6666*>(scanLine)[x];
- return qt_colorConvert<quint32, qargb6666>(color, 0);
+ const uchar *scanLine = data->texture.scanLine(y);
+ return ((const uint *)scanLine) + x;
}
-template<>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-uint QT_FASTCALL qt_fetchPixel<QImage::Format_RGB555>(const uchar *scanLine,
- int x,
- const QVector<QRgb> *)
+static const uint *QT_FASTCALL fetchUntransformedRGB16(uint *buffer, const Operator *,
+ const QSpanData *data, int y, int x,
+ int length)
{
- const qrgb555 color = reinterpret_cast<const qrgb555*>(scanLine)[x];
- return qt_colorConvert<quint32, qrgb555>(color, 0);
+ const quint16 *scanLine = (const quint16 *)data->texture.scanLine(y) + x;
+ for (int i = 0; i < length; ++i)
+ buffer[i] = qConvertRgb16To32(scanLine[i]);
+ return buffer;
}
-template<>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB8555_Premultiplied>(const uchar *scanLine,
- int x,
- const QVector<QRgb> *)
+// blendType is either BlendTransformed or BlendTransformedTiled
+template<TextureBlendType blendType>
+Q_STATIC_TEMPLATE_FUNCTION
+const uint *QT_FASTCALL fetchTransformedARGB32PM(uint *buffer, const Operator *, const QSpanData *data,
+ int y, int x, int length)
{
- const qargb8555 color = reinterpret_cast<const qargb8555*>(scanLine)[x];
- return qt_colorConvert<quint32, qargb8555>(color, 0);
-}
+ int image_width = data->texture.width;
+ int image_height = data->texture.height;
-template<>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-uint QT_FASTCALL qt_fetchPixel<QImage::Format_RGB888>(const uchar *scanLine,
- int x,
- const QVector<QRgb> *)
-{
- const qrgb888 color = reinterpret_cast<const qrgb888*>(scanLine)[x];
- return qt_colorConvert<quint32, qrgb888>(color, 0);
-}
+ const qreal cx = x + qreal(0.5);
+ const qreal cy = y + qreal(0.5);
-template<>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-uint QT_FASTCALL qt_fetchPixel<QImage::Format_RGB444>(const uchar *scanLine,
- int x,
- const QVector<QRgb> *)
-{
- const qrgb444 color = reinterpret_cast<const qrgb444*>(scanLine)[x];
- return qt_colorConvert<quint32, qrgb444>(color, 0);
-}
+ const uint *end = buffer + length;
+ uint *b = buffer;
+ if (data->fast_matrix) {
+ // The increment pr x in the scanline
+ int fdx = (int)(data->m11 * fixed_scale);
+ int fdy = (int)(data->m12 * fixed_scale);
-template<>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-uint QT_FASTCALL qt_fetchPixel<QImage::Format_ARGB4444_Premultiplied>(const uchar *scanLine,
- int x,
- const QVector<QRgb> *)
-{
- const qargb4444 color = reinterpret_cast<const qargb4444*>(scanLine)[x];
- return qt_colorConvert<quint32, qargb4444>(color, 0);
-}
+ int fx = int((data->m21 * cy
+ + data->m11 * cx + data->dx) * fixed_scale);
+ int fy = int((data->m22 * cy
+ + data->m12 * cx + data->dy) * fixed_scale);
-template<>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-uint QT_FASTCALL qt_fetchPixel<QImage::Format_Invalid>(const uchar *,
- int ,
- const QVector<QRgb> *)
-{
- return 0;
-}
+ while (b < end) {
+ int px = fx >> 16;
+ int py = fy >> 16;
-typedef uint (QT_FASTCALL *FetchPixelProc)(const uchar *scanLine, int x, const QVector<QRgb> *);
+ if (blendType == BlendTransformedTiled) {
+ px %= image_width;
+ py %= image_height;
+ if (px < 0) px += image_width;
+ if (py < 0) py += image_height;
+ } else {
+ px = qBound(0, px, image_width - 1);
+ py = qBound(0, py, image_height - 1);
+ }
+ *b = reinterpret_cast<const uint *>(data->texture.scanLine(py))[px];
-#define SPANFUNC_POINTER_FETCHPIXEL(Arg) qt_fetchPixel<QImage::Arg>
+ fx += fdx;
+ fy += fdy;
+ ++b;
+ }
+ } else {
+ const qreal fdx = data->m11;
+ const qreal fdy = data->m12;
+ const qreal fdw = data->m13;
+ qreal fx = data->m21 * cy + data->m11 * cx + data->dx;
+ qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
+ qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
-static const FetchPixelProc fetchPixelProc[QImage::NImageFormats] =
-{
- 0,
- SPANFUNC_POINTER_FETCHPIXEL(Format_Mono),
- SPANFUNC_POINTER_FETCHPIXEL(Format_MonoLSB),
- SPANFUNC_POINTER_FETCHPIXEL(Format_Indexed8),
- SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB32_Premultiplied),
- SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB32),
- SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB32_Premultiplied),
- SPANFUNC_POINTER_FETCHPIXEL(Format_RGB16),
- SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB8565_Premultiplied),
- SPANFUNC_POINTER_FETCHPIXEL(Format_RGB666),
- SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB6666_Premultiplied),
- SPANFUNC_POINTER_FETCHPIXEL(Format_RGB555),
- SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB8555_Premultiplied),
- SPANFUNC_POINTER_FETCHPIXEL(Format_RGB888),
- SPANFUNC_POINTER_FETCHPIXEL(Format_RGB444),
- SPANFUNC_POINTER_FETCHPIXEL(Format_ARGB4444_Premultiplied)
-};
+ while (b < end) {
+ const qreal iw = fw == 0 ? 1 : 1 / fw;
+ const qreal tx = fx * iw;
+ const qreal ty = fy * iw;
+ int px = int(tx) - (tx < 0);
+ int py = int(ty) - (ty < 0);
-enum TextureBlendType {
- BlendUntransformed,
- BlendTiled,
- BlendTransformed,
- BlendTransformedTiled,
- BlendTransformedBilinear,
- BlendTransformedBilinearTiled,
- NBlendTypes
-};
+ if (blendType == BlendTransformedTiled) {
+ px %= image_width;
+ py %= image_height;
+ if (px < 0) px += image_width;
+ if (py < 0) py += image_height;
+ } else {
+ px = qBound(0, px, image_width - 1);
+ py = qBound(0, py, image_height - 1);
+ }
+ *b = reinterpret_cast<const uint *>(data->texture.scanLine(py))[px];
-template <QImage::Format format>
-Q_STATIC_TEMPLATE_FUNCTION const uint * QT_FASTCALL qt_fetchUntransformed(uint *buffer, const Operator *, const QSpanData *data,
- int y, int x, int length)
-{
- const uchar *scanLine = data->texture.scanLine(y);
- for (int i = 0; i < length; ++i)
- buffer[i] = qt_fetchPixel<format>(scanLine, x + i, data->texture.colorTable);
+ fx += fdx;
+ fy += fdy;
+ fw += fdw;
+ //force increment to avoid /0
+ if (!fw) {
+ fw += fdw;
+ }
+ ++b;
+ }
+ }
return buffer;
}
-template <>
-Q_STATIC_TEMPLATE_SPECIALIZATION const uint * QT_FASTCALL
-qt_fetchUntransformed<QImage::Format_ARGB32_Premultiplied>(uint *, const Operator *,
- const QSpanData *data,
- int y, int x, int)
-{
- const uchar *scanLine = data->texture.scanLine(y);
- return ((const uint *)scanLine) + x;
-}
-
template<TextureBlendType blendType> /* either BlendTransformed or BlendTransformedTiled */
Q_STATIC_TEMPLATE_FUNCTION
-const uint * QT_FASTCALL fetchTransformed(uint *buffer, const Operator *, const QSpanData *data,
- int y, int x, int length)
+const uint *QT_FASTCALL fetchTransformed(uint *buffer, const Operator *, const QSpanData *data,
+ int y, int x, int length)
{
- FetchPixelProc fetch = fetchPixelProc[data->texture.format];
-
int image_width = data->texture.width;
int image_height = data->texture.height;
const qreal cx = x + qreal(0.5);
const qreal cy = y + qreal(0.5);
+ const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
+ FetchPixelFunc fetch = qFetchPixel[layout->bpp];
+
const uint *end = buffer + length;
uint *b = buffer;
if (data->fast_matrix) {
@@ -560,18 +678,12 @@ const uint * QT_FASTCALL fetchTransformed(uint *buffer, const Operator *, const
py %= image_height;
if (px < 0) px += image_width;
if (py < 0) py += image_height;
-
- const uchar *scanLine = data->texture.scanLine(py);
- *b = fetch(scanLine, px, data->texture.colorTable);
} else {
- if ((px < 0) || (px >= image_width)
- || (py < 0) || (py >= image_height)) {
- *b = uint(0);
- } else {
- const uchar *scanLine = data->texture.scanLine(py);
- *b = fetch(scanLine, px, data->texture.colorTable);
- }
+ px = qBound(0, px, image_width - 1);
+ py = qBound(0, py, image_height - 1);
}
+ *b = fetch(data->texture.scanLine(py), px);
+
fx += fdx;
fy += fdy;
++b;
@@ -597,18 +709,12 @@ const uint * QT_FASTCALL fetchTransformed(uint *buffer, const Operator *, const
py %= image_height;
if (px < 0) px += image_width;
if (py < 0) py += image_height;
-
- const uchar *scanLine = data->texture.scanLine(py);
- *b = fetch(scanLine, px, data->texture.colorTable);
} else {
- if ((px < 0) || (px >= image_width)
- || (py < 0) || (py >= image_height)) {
- *b = uint(0);
- } else {
- const uchar *scanLine = data->texture.scanLine(py);
- *b = fetch(scanLine, px, data->texture.colorTable);
- }
+ px = qBound(0, px, image_width - 1);
+ py = qBound(0, py, image_height - 1);
}
+ *b = fetch(data->texture.scanLine(py), px);
+
fx += fdx;
fy += fdy;
fw += fdw;
@@ -619,8 +725,8 @@ const uint * QT_FASTCALL fetchTransformed(uint *buffer, const Operator *, const
++b;
}
}
-
- return buffer;
+ const QRgb *clut = data->texture.colorTable ? data->texture.colorTable->constData() : 0;
+ return layout->convertToARGB32PM(buffer, buffer, length, layout, clut);
}
/** \internal
@@ -714,42 +820,42 @@ static inline uint interpolate_4_pixels_16(uint tl, uint tr, uint bl, uint br, i
#endif
template<TextureBlendType blendType>
-Q_STATIC_TEMPLATE_FUNCTION inline void fetchTransformedBilinear_pixelBounds(int max, int l1, int l2, int &v1, int &v2)
-{
- if (blendType == BlendTransformedBilinearTiled) {
- v1 %= max;
- if (v1 < 0) v1 += max;
- v2 = v1 + 1;
- v2 %= max;
- } else {
- if (v1 < l1) {
- v2 = v1 = l1;
- } else if (v1 >= l2) {
- v2 = v1 = l2;
- } else {
- v2 = v1 + 1;
- }
- }
+void fetchTransformedBilinear_pixelBounds(int max, int l1, int l2, int &v1, int &v2);
+template<>
+Q_STATIC_TEMPLATE_SPECIALIZATION
+inline void fetchTransformedBilinear_pixelBounds<BlendTransformedBilinearTiled>(int max, int, int, int &v1, int &v2)
+{
+ v1 %= max;
+ if (v1 < 0)
+ v1 += max;
+ v2 = v1 + 1;
+ if (v2 == max)
+ v2 = 0;
Q_ASSERT(v1 >= 0 && v1 < max);
Q_ASSERT(v2 >= 0 && v2 < max);
}
-template<TextureBlendType blendType, QImage::Format format> /* blendType = BlendTransformedBilinear or BlendTransformedBilinearTiled */
-Q_STATIC_TEMPLATE_FUNCTION
-const uint * QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Operator *, const QSpanData *data,
- int y, int x, int length)
+template<>
+Q_STATIC_TEMPLATE_SPECIALIZATION
+inline void fetchTransformedBilinear_pixelBounds<BlendTransformedBilinear>(int, int l1, int l2, int &v1, int &v2)
{
-#ifdef Q_CC_RVCT // needed to avoid compiler crash in RVCT 2.2
- FetchPixelProc fetch;
- if (format != QImage::Format_Invalid)
- fetch = qt_fetchPixel<format>;
+ if (v1 < l1)
+ v2 = v1 = l1;
+ else if (v1 >= l2)
+ v2 = v1 = l2;
else
- fetch = fetchPixelProc[data->texture.format];
-#else
- FetchPixelProc fetch = (format != QImage::Format_Invalid) ? FetchPixelProc(qt_fetchPixel<format>) : fetchPixelProc[data->texture.format];
-#endif
+ v2 = v1 + 1;
+ Q_ASSERT(v1 >= l1 && v1 <= l2);
+ Q_ASSERT(v2 >= l1 && v2 <= l2);
+}
+template<TextureBlendType blendType> /* blendType = BlendTransformedBilinear or BlendTransformedBilinearTiled */
+Q_STATIC_TEMPLATE_FUNCTION
+const uint * QT_FASTCALL fetchTransformedBilinearARGB32PM(uint *buffer, const Operator *,
+ const QSpanData *data, int y, int x,
+ int length)
+{
int image_width = data->texture.width;
int image_height = data->texture.height;
@@ -780,8 +886,8 @@ const uint * QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Operator *
int y1 = (fy >> 16);
int y2;
fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
- const uchar *s1 = data->texture.scanLine(y1);
- const uchar *s2 = data->texture.scanLine(y2);
+ const uint *s1 = (const uint *)data->texture.scanLine(y1);
+ const uint *s2 = (const uint *)data->texture.scanLine(y2);
if (fdx <= fixed_scale && fdx > 0) { // scale up on X
int disty = (fy & 0x0000ffff) >> 8;
@@ -806,8 +912,8 @@ const uint * QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Operator *
lim = qMin(count, image_x2-x+1);
if (x < image_x1) {
Q_ASSERT(x <= image_x2);
- uint t = fetch(s1, image_x1, data->texture.colorTable);
- uint b = fetch(s2, image_x1, data->texture.colorTable);
+ uint t = s1[image_x1];
+ uint b = s2[image_x1];
quint32 rb = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
quint32 ag = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
do {
@@ -819,8 +925,7 @@ const uint * QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Operator *
}
}
- if (blendType != BlendTransformedBilinearTiled &&
- (format == QImage::Format_ARGB32_Premultiplied || format == QImage::Format_RGB32)) {
+ if (blendType != BlendTransformedBilinearTiled) {
#if defined(QT_ALWAYS_HAVE_SSE2)
const __m128i disty_ = _mm_set1_epi16(disty);
const __m128i idisty_ = _mm_set1_epi16(idisty);
@@ -890,8 +995,8 @@ const uint * QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Operator *
x = qMin(x, image_x2);
}
- uint t = fetch(s1, x, data->texture.colorTable);
- uint b = fetch(s2, x, data->texture.colorTable);
+ uint t = s1[x];
+ uint b = s2[x];
intermediate_buffer[0][f] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
intermediate_buffer[1][f] = ((((t>>8) & 0xff00ff) * idisty + ((b>>8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
@@ -918,18 +1023,18 @@ const uint * QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Operator *
int y1 = (fy >> 16);
int y2;
fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
- const uchar *s1 = data->texture.scanLine(y1);
- const uchar *s2 = data->texture.scanLine(y2);
+ const uint *s1 = (const uint *)data->texture.scanLine(y1);
+ const uint *s2 = (const uint *)data->texture.scanLine(y2);
int disty = (fy & 0x0000ffff) >> 8;
int idisty = 256 - disty;
while (b < end) {
int x1 = (fx >> 16);
int x2;
fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
- uint tl = fetch(s1, x1, data->texture.colorTable);
- uint tr = fetch(s1, x2, data->texture.colorTable);
- uint bl = fetch(s2, x1, data->texture.colorTable);
- uint br = fetch(s2, x2, data->texture.colorTable);
+ uint tl = s1[x1];
+ uint tr = s1[x2];
+ uint bl = s2[x1];
+ uint br = s2[x2];
int distx = (fx & 0x0000ffff) >> 8;
int idistx = 256 - distx;
@@ -945,13 +1050,11 @@ const uint * QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Operator *
int y1 = (fy >> 16);
int y2;
fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
- const uchar *s1 = data->texture.scanLine(y1);
- const uchar *s2 = data->texture.scanLine(y2);
+ const uint *s1 = (const uint *)data->texture.scanLine(y1);
+ const uint *s2 = (const uint *)data->texture.scanLine(y2);
int disty = (fy & 0x0000ffff) >> 12;
- if (blendType != BlendTransformedBilinearTiled &&
- (format == QImage::Format_ARGB32_Premultiplied || format == QImage::Format_RGB32)) {
-
+ if (blendType != BlendTransformedBilinearTiled) {
#define BILINEAR_DOWNSCALE_BOUNDS_PROLOG \
while (b < end) { \
int x1 = (fx >> 16); \
@@ -959,10 +1062,10 @@ const uint * QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Operator *
fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2); \
if (x1 != x2) \
break; \
- uint tl = fetch(s1, x1, data->texture.colorTable); \
- uint tr = fetch(s1, x2, data->texture.colorTable); \
- uint bl = fetch(s2, x1, data->texture.colorTable); \
- uint br = fetch(s2, x2, data->texture.colorTable); \
+ uint tl = s1[x1]; \
+ uint tr = s1[x2]; \
+ uint bl = s2[x1]; \
+ uint br = s2[x2]; \
int distx = (fx & 0x0000ffff) >> 12; \
*b = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty); \
fx += fdx; \
@@ -1070,10 +1173,10 @@ const uint * QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Operator *
int x1 = (fx >> 16);
int x2;
fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
- uint tl = fetch(s1, x1, data->texture.colorTable);
- uint tr = fetch(s1, x2, data->texture.colorTable);
- uint bl = fetch(s2, x1, data->texture.colorTable);
- uint br = fetch(s2, x2, data->texture.colorTable);
+ uint tl = s1[x1];
+ uint tr = s1[x2];
+ uint bl = s2[x1];
+ uint br = s2[x2];
int distx = (fx & 0x0000ffff) >> 12;
*b = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty);
fx += fdx;
@@ -1092,13 +1195,13 @@ const uint * QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Operator *
fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
- const uchar *s1 = data->texture.scanLine(y1);
- const uchar *s2 = data->texture.scanLine(y2);
+ const uint *s1 = (const uint *)data->texture.scanLine(y1);
+ const uint *s2 = (const uint *)data->texture.scanLine(y2);
- uint tl = fetch(s1, x1, data->texture.colorTable);
- uint tr = fetch(s1, x2, data->texture.colorTable);
- uint bl = fetch(s2, x1, data->texture.colorTable);
- uint br = fetch(s2, x2, data->texture.colorTable);
+ uint tl = s1[x1];
+ uint tr = s1[x2];
+ uint bl = s2[x1];
+ uint br = s2[x2];
int distx = (fx & 0x0000ffff) >> 8;
int disty = (fy & 0x0000ffff) >> 8;
@@ -1124,13 +1227,13 @@ const uint * QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Operator *
fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
- const uchar *s1 = data->texture.scanLine(y1);
- const uchar *s2 = data->texture.scanLine(y2);
+ const uint *s1 = (const uint *)data->texture.scanLine(y1);
+ const uint *s2 = (const uint *)data->texture.scanLine(y2);
- uint tl = fetch(s1, x1, data->texture.colorTable);
- uint tr = fetch(s1, x2, data->texture.colorTable);
- uint bl = fetch(s2, x1, data->texture.colorTable);
- uint br = fetch(s2, x2, data->texture.colorTable);
+ uint tl = s1[x1];
+ uint tr = s1[x2];
+ uint bl = s2[x1];
+ uint br = s2[x2];
int distx = (fx & 0x0000ffff) >> 12;
int disty = (fy & 0x0000ffff) >> 12;
@@ -1170,13 +1273,13 @@ const uint * QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Operator *
fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
- const uchar *s1 = data->texture.scanLine(y1);
- const uchar *s2 = data->texture.scanLine(y2);
+ const uint *s1 = (const uint *)data->texture.scanLine(y1);
+ const uint *s2 = (const uint *)data->texture.scanLine(y2);
- uint tl = fetch(s1, x1, data->texture.colorTable);
- uint tr = fetch(s1, x2, data->texture.colorTable);
- uint bl = fetch(s2, x1, data->texture.colorTable);
- uint br = fetch(s2, x2, data->texture.colorTable);
+ uint tl = s1[x1];
+ uint tr = s1[x2];
+ uint bl = s2[x1];
+ uint br = s2[x2];
uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
@@ -1196,119 +1299,452 @@ const uint * QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Operator *
return buffer;
}
-#define SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Arg) qt_fetchUntransformed<QImage::Arg>
+// blendType = BlendTransformedBilinear or BlendTransformedBilinearTiled
+template<TextureBlendType blendType>
+Q_STATIC_TEMPLATE_FUNCTION
+const uint *QT_FASTCALL fetchTransformedBilinear(uint *buffer, const Operator *,
+ const QSpanData *data, int y, int x, int length)
+{
+ const QPixelLayout *layout = &qPixelLayouts[data->texture.format];
+ const QRgb *clut = data->texture.colorTable ? data->texture.colorTable->constData() : 0;
+
+ int image_width = data->texture.width;
+ int image_height = data->texture.height;
+
+ int image_x1 = data->texture.x1;
+ int image_y1 = data->texture.y1;
+ int image_x2 = data->texture.x2 - 1;
+ int image_y2 = data->texture.y2 - 1;
+
+ const qreal cx = x + qreal(0.5);
+ const qreal cy = y + qreal(0.5);
+
+ if (data->fast_matrix) {
+ // The increment pr x in the scanline
+ int fdx = (int)(data->m11 * fixed_scale);
+ int fdy = (int)(data->m12 * fixed_scale);
+
+ int fx = int((data->m21 * cy + data->m11 * cx + data->dx) * fixed_scale);
+ int fy = int((data->m22 * cy + data->m12 * cx + data->dy) * fixed_scale);
+
+ fx -= half_point;
+ fy -= half_point;
+
+ if (fdy == 0) { //simple scale, no rotation
+ int y1 = (fy >> 16);
+ int y2;
+ fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
+ const uchar *s1 = data->texture.scanLine(y1);
+ const uchar *s2 = data->texture.scanLine(y2);
+
+ if (fdx <= fixed_scale && fdx > 0) { // scale up on X
+ int disty = (fy & 0x0000ffff) >> 8;
+ int idisty = 256 - disty;
+ int x = fx >> 16;
+
+ // The idea is first to do the interpolation between the row s1 and the row s2
+ // into an intermediate buffer, then we interpolate between two pixel of this buffer.
+ FetchPixelsFunc fetch = qFetchPixels[layout->bpp];
+ uint buf1[buffer_size + 2];
+ uint buf2[buffer_size + 2];
+ const uint *ptr1;
+ const uint *ptr2;
+
+ int count = qCeil(length * data->m11) + 2; //+1 for the last pixel to interpolate with, and +1 for rounding errors.
+ Q_ASSERT(count <= buffer_size + 2); //length is supposed to be <= buffer_size and data->m11 < 1 in this case
+
+ if (blendType == BlendTransformedBilinearTiled) {
+ x %= image_width;
+ if (x < 0)
+ x += image_width;
+ int len1 = qMin(count, image_width - x);
+ int len2 = qMin(x, count - len1);
+
+ ptr1 = fetch(buf1, s1, x, len1);
+ ptr1 = layout->convertToARGB32PM(buf1, ptr1, len1, layout, clut);
+ ptr2 = fetch(buf2, s2, x, len1);
+ ptr2 = layout->convertToARGB32PM(buf2, ptr2, len1, layout, clut);
+ for (int i = 0; i < len1; ++i) {
+ uint t = ptr1[i];
+ uint b = ptr2[i];
+ buf1[i] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
+ buf2[i] = ((((t >> 8) & 0xff00ff) * idisty + ((b >> 8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
+ }
+
+ if (len2) {
+ ptr1 = fetch(buf1 + len1, s1, 0, len2);
+ ptr1 = layout->convertToARGB32PM(buf1 + len1, ptr1, len2, layout, clut);
+ ptr2 = fetch(buf2 + len1, s2, 0, len2);
+ ptr2 = layout->convertToARGB32PM(buf2 + len1, ptr2, len2, layout, clut);
+ for (int i = 0; i < len2; ++i) {
+ uint t = ptr1[i];
+ uint b = ptr2[i];
+ buf1[i + len1] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
+ buf2[i + len1] = ((((t >> 8) & 0xff00ff) * idisty + ((b >> 8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
+ }
+ }
+ for (int i = image_width; i < count; ++i) {
+ buf1[i] = buf1[i - image_width];
+ buf2[i] = buf2[i - image_width];
+ }
+ } else {
+ int start = qMax(x, image_x1);
+ int end = qMin(x + count, image_x2 + 1);
+ int len = qMax(1, end - start);
+ int leading = start - x;
+
+ ptr1 = fetch(buf1 + leading, s1, start, len);
+ ptr1 = layout->convertToARGB32PM(buf1 + leading, ptr1, len, layout, clut);
+ ptr2 = fetch(buf2 + leading, s2, start, len);
+ ptr2 = layout->convertToARGB32PM(buf2 + leading, ptr2, len, layout, clut);
+
+ for (int i = 0; i < len; ++i) {
+ uint t = ptr1[i];
+ uint b = ptr2[i];
+ buf1[i + leading] = (((t & 0xff00ff) * idisty + (b & 0xff00ff) * disty) >> 8) & 0xff00ff;
+ buf2[i + leading] = ((((t >> 8) & 0xff00ff) * idisty + ((b >> 8) & 0xff00ff) * disty) >> 8) & 0xff00ff;
+ }
+
+ for (int i = 0; i < leading; ++i) {
+ buf1[i] = buf1[leading];
+ buf2[i] = buf2[leading];
+ }
+ for (int i = leading + len; i < count; ++i) {
+ buf1[i] = buf1[i - 1];
+ buf2[i] = buf2[i - 1];
+ }
+ }
+
+ // Now interpolate the values from the intermediate_buffer to get the final result.
+ fx &= fixed_scale - 1;
+ Q_ASSERT((fx >> 16) == 0);
+ for (int i = 0; i < length; ++i) {
+ register int x1 = (fx >> 16);
+ register int x2 = x1 + 1;
+ Q_ASSERT(x1 >= 0);
+ Q_ASSERT(x2 < count);
+
+ register int distx = (fx & 0x0000ffff) >> 8;
+ register int idistx = 256 - distx;
+ int rb = ((buf1[x1] * idistx + buf1[x2] * distx) >> 8) & 0xff00ff;
+ int ag = (buf2[x1] * idistx + buf2[x2] * distx) & 0xff00ff00;
+ buffer[i] = rb | ag;
+ fx += fdx;
+ }
+ } else {
+ FetchPixelFunc fetch = qFetchPixel[layout->bpp];
+ uint buf1[buffer_size];
+ uint buf2[buffer_size];
+ uint *b = buffer;
+ while (length) {
+ int len = qMin(length, buffer_size / 2);
+ int fracX = fx;
+ for (int i = 0; i < len; ++i) {
+ int x1 = (fx >> 16);
+ int x2;
+ fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
+
+ buf1[i * 2 + 0] = fetch(s1, x1);
+ buf1[i * 2 + 1] = fetch(s1, x2);
+ buf2[i * 2 + 0] = fetch(s2, x1);
+ buf2[i * 2 + 1] = fetch(s2, x2);
+
+ fx += fdx;
+ }
+ layout->convertToARGB32PM(buf1, buf1, len * 2, layout, clut);
+ layout->convertToARGB32PM(buf2, buf2, len * 2, layout, clut);
+
+ if ((fdx < 0 && fdx > -(fixed_scale / 8)) || fabs(data->m22) < (1./8.)) { // scale up more than 8x
+ int disty = (fy & 0x0000ffff) >> 8;
+ int idisty = 256 - disty;
+ for (int i = 0; i < len; ++i) {
+ uint tl = buf1[i * 2 + 0];
+ uint tr = buf1[i * 2 + 1];
+ uint bl = buf2[i * 2 + 0];
+ uint br = buf2[i * 2 + 1];
+ int distx = (fracX & 0x0000ffff) >> 8;
+ int idistx = 256 - distx;
+ uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
+ uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
+ b[i] = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty);
+ fracX += fdx;
+ }
+ } else { //scale down
+ int disty = (fy & 0x0000ffff) >> 12;
+ for (int i = 0; i < len; ++i) {
+ uint tl = buf1[i * 2 + 0];
+ uint tr = buf1[i * 2 + 1];
+ uint bl = buf2[i * 2 + 0];
+ uint br = buf2[i * 2 + 1];
+ int distx = (fracX & 0x0000ffff) >> 12;
+ b[i] = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty);
+ fracX += fdx;
+ }
+ }
+ length -= len;
+ b += len;
+ }
+ }
+ } else { //rotation
+ FetchPixelFunc fetch = qFetchPixel[layout->bpp];
+ uint buf1[buffer_size];
+ uint buf2[buffer_size];
+ uint *b = buffer;
+
+ while (length) {
+ int len = qMin(length, buffer_size / 2);
+ int fracX = fx;
+ int fracY = fy;
+ for (int i = 0; i < len; ++i) {
+ int x1 = (fx >> 16);
+ int x2;
+ int y1 = (fy >> 16);
+ int y2;
+ fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
+ fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
+
+ const uchar *s1 = data->texture.scanLine(y1);
+ const uchar *s2 = data->texture.scanLine(y2);
+
+ buf1[i * 2 + 0] = fetch(s1, x1);
+ buf1[i * 2 + 1] = fetch(s1, x2);
+ buf2[i * 2 + 0] = fetch(s2, x1);
+ buf2[i * 2 + 1] = fetch(s2, x2);
+
+ fx += fdx;
+ fy += fdy;
+ }
+ layout->convertToARGB32PM(buf1, buf1, len * 2, layout, clut);
+ layout->convertToARGB32PM(buf2, buf2, len * 2, layout, clut);
+
+ if (fabs(data->m11) > 8 || fabs(data->m22) > 8) {
+ //if we are zooming more than 8 times, we use 8bit precision for the position.
+ for (int i = 0; i < len; ++i) {
+ uint tl = buf1[i * 2 + 0];
+ uint tr = buf1[i * 2 + 1];
+ uint bl = buf2[i * 2 + 0];
+ uint br = buf2[i * 2 + 1];
+
+ int distx = (fracX & 0x0000ffff) >> 8;
+ int disty = (fracY & 0x0000ffff) >> 8;
+ int idistx = 256 - distx;
+ int idisty = 256 - disty;
+
+ uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
+ uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
+ b[i] = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty);
+ fracX += fdx;
+ fracY += fdy;
+ }
+ } else {
+ //we are zooming less than 8x, use 4bit precision
+ for (int i = 0; i < len; ++i) {
+ uint tl = buf1[i * 2 + 0];
+ uint tr = buf1[i * 2 + 1];
+ uint bl = buf2[i * 2 + 0];
+ uint br = buf2[i * 2 + 1];
+
+ int distx = (fracX & 0x0000ffff) >> 12;
+ int disty = (fracY & 0x0000ffff) >> 12;
+
+ b[i] = interpolate_4_pixels_16(tl, tr, bl, br, distx, disty);
+ fracX += fdx;
+ fracY += fdy;
+ }
+ }
+
+ length -= len;
+ b += len;
+ }
+ }
+ } else {
+ const qreal fdx = data->m11;
+ const qreal fdy = data->m12;
+ const qreal fdw = data->m13;
+
+ qreal fx = data->m21 * cy + data->m11 * cx + data->dx;
+ qreal fy = data->m22 * cy + data->m12 * cx + data->dy;
+ qreal fw = data->m23 * cy + data->m13 * cx + data->m33;
+
+ FetchPixelFunc fetch = qFetchPixel[layout->bpp];
+ uint buf1[buffer_size];
+ uint buf2[buffer_size];
+ uint *b = buffer;
+
+ int distxs[buffer_size / 2];
+ int distys[buffer_size / 2];
+
+ while (length) {
+ int len = qMin(length, buffer_size / 2);
+ for (int i = 0; i < len; ++i) {
+ const qreal iw = fw == 0 ? 1 : 1 / fw;
+ const qreal px = fx * iw - qreal(0.5);
+ const qreal py = fy * iw - qreal(0.5);
+
+ int x1 = int(px) - (px < 0);
+ int x2;
+ int y1 = int(py) - (py < 0);
+ int y2;
+
+ distxs[i] = int((px - x1) * 256);
+ distys[i] = int((py - y1) * 256);
+
+ fetchTransformedBilinear_pixelBounds<blendType>(image_width, image_x1, image_x2, x1, x2);
+ fetchTransformedBilinear_pixelBounds<blendType>(image_height, image_y1, image_y2, y1, y2);
+
+ const uchar *s1 = data->texture.scanLine(y1);
+ const uchar *s2 = data->texture.scanLine(y2);
+
+ buf1[i * 2 + 0] = fetch(s1, x1);
+ buf1[i * 2 + 1] = fetch(s1, x2);
+ buf2[i * 2 + 0] = fetch(s2, x1);
+ buf2[i * 2 + 1] = fetch(s2, x2);
+
+ fx += fdx;
+ fy += fdy;
+ fw += fdw;
+ //force increment to avoid /0
+ if (!fw)
+ fw += fdw;
+ }
+
+ layout->convertToARGB32PM(buf1, buf1, len * 2, layout, clut);
+ layout->convertToARGB32PM(buf2, buf2, len * 2, layout, clut);
+
+ for (int i = 0; i < len; ++i) {
+ int distx = distxs[i];
+ int disty = distys[i];
+ int idistx = 256 - distx;
+ int idisty = 256 - disty;
+
+ uint tl = buf1[i * 2 + 0];
+ uint tr = buf1[i * 2 + 1];
+ uint bl = buf2[i * 2 + 0];
+ uint br = buf2[i * 2 + 1];
+
+ uint xtop = INTERPOLATE_PIXEL_256(tl, idistx, tr, distx);
+ uint xbot = INTERPOLATE_PIXEL_256(bl, idistx, br, distx);
+ b[i] = INTERPOLATE_PIXEL_256(xtop, idisty, xbot, disty);
+ }
+ length -= len;
+ b += len;
+ }
+ }
+
+ return buffer;
+}
static const SourceFetchProc sourceFetch[NBlendTypes][QImage::NImageFormats] = {
// Untransformed
{
0, // Invalid
- SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_Mono), // Mono
- SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_MonoLSB), // MonoLsb
- SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_Indexed8), // Indexed8
- SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32_Premultiplied), // RGB32
- SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32), // ARGB32
- SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32_Premultiplied), // ARGB32_Premultiplied
- SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB16), // RGB16
- SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB8565_Premultiplied),// ARGB8565_Premultiplied
- SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB666), // RGB666
- SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB6666_Premultiplied),// ARGB6666_Premultiplied
- SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB555), // RGB555
- SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB8555_Premultiplied),// ARGB8555_Premultiplied
- SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB888), // RGB888
- SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB444), // RGB444
- SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB4444_Premultiplied) // ARGB4444_Premultiplied
+ fetchUntransformed, // Mono
+ fetchUntransformed, // MonoLsb
+ fetchUntransformed, // Indexed8
+ fetchUntransformedARGB32PM, // RGB32
+ fetchUntransformed, // ARGB32
+ fetchUntransformedARGB32PM, // ARGB32_Premultiplied
+ fetchUntransformedRGB16, // RGB16
+ fetchUntransformed, // ARGB8565_Premultiplied
+ fetchUntransformed, // RGB666
+ fetchUntransformed, // ARGB6666_Premultiplied
+ fetchUntransformed, // RGB555
+ fetchUntransformed, // ARGB8555_Premultiplied
+ fetchUntransformed, // RGB888
+ fetchUntransformed, // RGB444
+ fetchUntransformed // ARGB4444_Premultiplied
},
// Tiled
{
0, // Invalid
- SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_Mono), // Mono
- SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_MonoLSB), // MonoLsb
- SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_Indexed8), // Indexed8
- SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32_Premultiplied), // RGB32
- SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32), // ARGB32
- SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB32_Premultiplied), // ARGB32_Premultiplied
- SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB16), // RGB16
- SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB8565_Premultiplied),// ARGB8565_Premultiplied
- SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB666), // RGB666
- SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB6666_Premultiplied),// ARGB6666_Premultiplied
- SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB555), // RGB555
- SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB8555_Premultiplied),// ARGB8555_Premultiplied
- SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB888), // RGB888
- SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_RGB444), // RGB444
- SPANFUNC_POINTER_FETCHHUNTRANSFORMED(Format_ARGB4444_Premultiplied) // ARGB4444_Premultiplied
+ fetchUntransformed, // Mono
+ fetchUntransformed, // MonoLsb
+ fetchUntransformed, // Indexed8
+ fetchUntransformedARGB32PM, // RGB32
+ fetchUntransformed, // ARGB32
+ fetchUntransformedARGB32PM, // ARGB32_Premultiplied
+ fetchUntransformedRGB16, // RGB16
+ fetchUntransformed, // ARGB8565_Premultiplied
+ fetchUntransformed, // RGB666
+ fetchUntransformed, // ARGB6666_Premultiplied
+ fetchUntransformed, // RGB555
+ fetchUntransformed, // ARGB8555_Premultiplied
+ fetchUntransformed, // RGB888
+ fetchUntransformed, // RGB444
+ fetchUntransformed // ARGB4444_Premultiplied
},
// Transformed
{
0, // Invalid
- fetchTransformed<BlendTransformed>, // Mono
- fetchTransformed<BlendTransformed>, // MonoLsb
- fetchTransformed<BlendTransformed>, // Indexed8
- fetchTransformed<BlendTransformed>, // RGB32
- fetchTransformed<BlendTransformed>, // ARGB32
- fetchTransformed<BlendTransformed>, // ARGB32_Premultiplied
- fetchTransformed<BlendTransformed>, // RGB16
- fetchTransformed<BlendTransformed>, // ARGB8565_Premultiplied
- fetchTransformed<BlendTransformed>, // RGB666
- fetchTransformed<BlendTransformed>, // ARGB6666_Premultiplied
- fetchTransformed<BlendTransformed>, // RGB555
- fetchTransformed<BlendTransformed>, // ARGB8555_Premultiplied
- fetchTransformed<BlendTransformed>, // RGB888
- fetchTransformed<BlendTransformed>, // RGB444
- fetchTransformed<BlendTransformed>, // ARGB4444_Premultiplied
+ fetchTransformed<BlendTransformed>, // Mono
+ fetchTransformed<BlendTransformed>, // MonoLsb
+ fetchTransformed<BlendTransformed>, // Indexed8
+ fetchTransformedARGB32PM<BlendTransformed>, // RGB32
+ fetchTransformed<BlendTransformed>, // ARGB32
+ fetchTransformedARGB32PM<BlendTransformed>, // ARGB32_Premultiplied
+ fetchTransformed<BlendTransformed>, // RGB16
+ fetchTransformed<BlendTransformed>, // ARGB8565_Premultiplied
+ fetchTransformed<BlendTransformed>, // RGB666
+ fetchTransformed<BlendTransformed>, // ARGB6666_Premultiplied
+ fetchTransformed<BlendTransformed>, // RGB555
+ fetchTransformed<BlendTransformed>, // ARGB8555_Premultiplied
+ fetchTransformed<BlendTransformed>, // RGB888
+ fetchTransformed<BlendTransformed>, // RGB444
+ fetchTransformed<BlendTransformed>, // ARGB4444_Premultiplied
},
{
0, // TransformedTiled
- fetchTransformed<BlendTransformedTiled>, // Mono
- fetchTransformed<BlendTransformedTiled>, // MonoLsb
- fetchTransformed<BlendTransformedTiled>, // Indexed8
- fetchTransformed<BlendTransformedTiled>, // RGB32
- fetchTransformed<BlendTransformedTiled>, // ARGB32
- fetchTransformed<BlendTransformedTiled>, // ARGB32_Premultiplied
- fetchTransformed<BlendTransformedTiled>, // RGB16
- fetchTransformed<BlendTransformedTiled>, // ARGB8565_Premultiplied
- fetchTransformed<BlendTransformedTiled>, // RGB666
- fetchTransformed<BlendTransformedTiled>, // ARGB6666_Premultiplied
- fetchTransformed<BlendTransformedTiled>, // RGB555
- fetchTransformed<BlendTransformedTiled>, // ARGB8555_Premultiplied
- fetchTransformed<BlendTransformedTiled>, // RGB888
- fetchTransformed<BlendTransformedTiled>, // RGB444
- fetchTransformed<BlendTransformedTiled>, // ARGB4444_Premultiplied
+ fetchTransformed<BlendTransformedTiled>, // Mono
+ fetchTransformed<BlendTransformedTiled>, // MonoLsb
+ fetchTransformed<BlendTransformedTiled>, // Indexed8
+ fetchTransformedARGB32PM<BlendTransformedTiled>, // RGB32
+ fetchTransformed<BlendTransformedTiled>, // ARGB32
+ fetchTransformedARGB32PM<BlendTransformedTiled>, // ARGB32_Premultiplied
+ fetchTransformed<BlendTransformedTiled>, // RGB16
+ fetchTransformed<BlendTransformedTiled>, // ARGB8565_Premultiplied
+ fetchTransformed<BlendTransformedTiled>, // RGB666
+ fetchTransformed<BlendTransformedTiled>, // ARGB6666_Premultiplied
+ fetchTransformed<BlendTransformedTiled>, // RGB555
+ fetchTransformed<BlendTransformedTiled>, // ARGB8555_Premultiplied
+ fetchTransformed<BlendTransformedTiled>, // RGB888
+ fetchTransformed<BlendTransformedTiled>, // RGB444
+ fetchTransformed<BlendTransformedTiled>, // ARGB4444_Premultiplied
},
{
0, // Bilinear
- fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // Mono
- fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // MonoLsb
- fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // Indexed8
- fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_ARGB32_Premultiplied>, // RGB32
- fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_ARGB32>, // ARGB32
- fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_ARGB32_Premultiplied>, // ARGB32_Premultiplied
- fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // RGB16
- fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // ARGB8565_Premultiplied
- fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // RGB666
- fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // ARGB6666_Premultiplied
- fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // RGB555
- fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // ARGB8555_Premultiplied
- fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // RGB888
- fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid>, // RGB444
- fetchTransformedBilinear<BlendTransformedBilinear, QImage::Format_Invalid> // ARGB4444_Premultiplied
+ fetchTransformedBilinear<BlendTransformedBilinear>, // Mono
+ fetchTransformedBilinear<BlendTransformedBilinear>, // MonoLsb
+ fetchTransformedBilinear<BlendTransformedBilinear>, // Indexed8
+ fetchTransformedBilinearARGB32PM<BlendTransformedBilinear>, // RGB32
+ fetchTransformedBilinear<BlendTransformedBilinear>, // ARGB32
+ fetchTransformedBilinearARGB32PM<BlendTransformedBilinear>, // ARGB32_Premultiplied
+ fetchTransformedBilinear<BlendTransformedBilinear>, // RGB16
+ fetchTransformedBilinear<BlendTransformedBilinear>, // ARGB8565_Premultiplied
+ fetchTransformedBilinear<BlendTransformedBilinear>, // RGB666
+ fetchTransformedBilinear<BlendTransformedBilinear>, // ARGB6666_Premultiplied
+ fetchTransformedBilinear<BlendTransformedBilinear>, // RGB555
+ fetchTransformedBilinear<BlendTransformedBilinear>, // ARGB8555_Premultiplied
+ fetchTransformedBilinear<BlendTransformedBilinear>, // RGB888
+ fetchTransformedBilinear<BlendTransformedBilinear>, // RGB444
+ fetchTransformedBilinear<BlendTransformedBilinear> // ARGB4444_Premultiplied
},
{
0, // BilinearTiled
- fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // Mono
- fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // MonoLsb
- fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // Indexed8
- fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_ARGB32_Premultiplied>, // RGB32
- fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_ARGB32>, // ARGB32
- fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_ARGB32_Premultiplied>, // ARGB32_Premultiplied
- fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // RGB16
- fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // ARGB8565_Premultiplied
- fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // RGB666
- fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // ARGB6666_Premultiplied
- fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // RGB555
- fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // ARGB8555_Premultiplied
- fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // RGB888
- fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid>, // RGB444
- fetchTransformedBilinear<BlendTransformedBilinearTiled, QImage::Format_Invalid> // ARGB4444_Premultiplied
+ fetchTransformedBilinear<BlendTransformedBilinearTiled>, // Mono
+ fetchTransformedBilinear<BlendTransformedBilinearTiled>, // MonoLsb
+ fetchTransformedBilinear<BlendTransformedBilinearTiled>, // Indexed8
+ fetchTransformedBilinearARGB32PM<BlendTransformedBilinearTiled>, // RGB32
+ fetchTransformedBilinear<BlendTransformedBilinearTiled>, // ARGB32
+ fetchTransformedBilinearARGB32PM<BlendTransformedBilinearTiled>, // ARGB32_Premultiplied
+ fetchTransformedBilinear<BlendTransformedBilinearTiled>, // RGB16
+ fetchTransformedBilinear<BlendTransformedBilinearTiled>, // ARGB8565_Premultiplied
+ fetchTransformedBilinear<BlendTransformedBilinearTiled>, // RGB666
+ fetchTransformedBilinear<BlendTransformedBilinearTiled>, // ARGB6666_Premultiplied
+ fetchTransformedBilinear<BlendTransformedBilinearTiled>, // RGB555
+ fetchTransformedBilinear<BlendTransformedBilinearTiled>, // ARGB8555_Premultiplied
+ fetchTransformedBilinear<BlendTransformedBilinearTiled>, // RGB888
+ fetchTransformedBilinear<BlendTransformedBilinearTiled>, // RGB444
+ fetchTransformedBilinear<BlendTransformedBilinearTiled> // ARGB4444_Premultiplied
},
};
@@ -3247,6 +3683,8 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in
// don't clear dest_fetch as it sets up the pointer correctly to save one copy
break;
default: {
+ if (data->type == QSpanData::Texture && data->texture.const_alpha != 256)
+ break;
const QSpan *lastSpan = spans + spanCount;
bool alphaSpans = false;
while (spans < lastSpan) {
@@ -3274,26 +3712,6 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in
// -------------------- blend methods ---------------------
-enum SpanMethod {
- RegularSpans,
- CallbackSpans
-};
-
-#if !defined(Q_CC_SUN)
-static
-#endif
-void drawBufferSpan(QSpanData *data, const uint *buffer, int bufsize,
- int x, int y, int length, uint const_alpha)
-{
- Q_UNUSED(data);
- Q_UNUSED(buffer);
- Q_UNUSED(bufsize);
- Q_UNUSED(x);
- Q_UNUSED(y);
- Q_UNUSED(length);
- Q_UNUSED(const_alpha);
-}
-
#if !defined(Q_CC_SUN)
static
#endif
@@ -3349,55 +3767,6 @@ static void blend_color_argb(int count, const QSpan *spans, void *userData)
}
}
-template <class T>
-Q_STATIC_TEMPLATE_FUNCTION void blendColor(int count, const QSpan *spans, void *userData)
-{
- QSpanData *data = reinterpret_cast<QSpanData *>(userData);
- Operator op = getOperator(data, spans, count);
-
- if (op.mode == QPainter::CompositionMode_Source) {
- const T c = qt_colorConvert<T, quint32p>(quint32p::fromRawData(data->solid.color), 0);
- while (count--) {
- T *target = ((T*)data->rasterBuffer->scanLine(spans->y))
- + spans->x;
- if (spans->coverage == 255) {
- qt_memfill(target, c, spans->len);
- } else {
- const quint8 alpha = T::alpha(spans->coverage);
- const T color = c.byte_mul(alpha);
- const int ialpha = T::ialpha(spans->coverage);
- const T *end = target + spans->len;
- while (target < end) {
- *target = color + target->byte_mul(ialpha);
- ++target;
- }
- }
- ++spans;
- }
- return;
- }
-
- if (op.mode == QPainter::CompositionMode_SourceOver) {
- while (count--) {
- const quint32 color = BYTE_MUL(data->solid.color, spans->coverage);
- const T c = qt_colorConvert<T, quint32p>(quint32p::fromRawData(color), 0);
- const quint8 ialpha = T::alpha(qAlpha(~color));
- T *target = ((T*)data->rasterBuffer->scanLine(spans->y)) + spans->x;
- const T *end = target + spans->len;
- while (target != end) {
- *target = c + target->byte_mul(ialpha);
- ++target;
- }
- ++spans;
- }
- return;
- }
-
- blend_color_generic(count, spans, userData);
-}
-
-#define SPANFUNC_POINTER_BLENDCOLOR(DST) blendColor<DST>
-
static void blend_color_rgb16(int count, const QSpan *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
@@ -3542,7 +3911,6 @@ struct QBlendBase
uint src_buffer[buffer_size];
};
-template <SpanMethod spanMethod>
class BlendSrcGeneric : public QBlendBase
{
public:
@@ -3553,38 +3921,30 @@ public:
const uint *fetch(int x, int y, int len)
{
- if (spanMethod == RegularSpans)
- dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, y, len) : buffer;
-
+ dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, y, len) : buffer;
return op.src_fetch(src_buffer, &op, data, y, x, len);
}
- void process(int x, int y, int len, int coverage, const uint *src, int offset)
+ void process(int, int, int len, int coverage, const uint *src, int offset)
{
- if (spanMethod == RegularSpans)
- op.func(dest + offset, src + offset, len, coverage);
- else
- drawBufferSpan(data, src + offset, len, x, y, len, coverage);
+ op.func(dest + offset, src + offset, len, coverage);
}
void store(int x, int y, int len)
{
- if (spanMethod == RegularSpans && op.dest_store) {
+ if (op.dest_store)
op.dest_store(data->rasterBuffer, x, y, dest, len);
- }
}
};
-template <SpanMethod spanMethod>
-Q_STATIC_TEMPLATE_FUNCTION void blend_src_generic(int count, const QSpan *spans, void *userData)
+static void blend_src_generic(int count, const QSpan *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
- BlendSrcGeneric<spanMethod> blend(data, getOperator(data, spans, count));
+ BlendSrcGeneric blend(data, getOperator(data, spans, count));
handleSpans(count, spans, data, blend);
}
-template <SpanMethod spanMethod>
-Q_STATIC_TEMPLATE_FUNCTION void blend_untransformed_generic(int count, const QSpan *spans, void *userData)
+static void blend_untransformed_generic(int count, const QSpan *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
@@ -3615,15 +3975,10 @@ Q_STATIC_TEMPLATE_FUNCTION void blend_untransformed_generic(int count, const QSp
while (length) {
int l = qMin(buffer_size, length);
const uint *src = op.src_fetch(src_buffer, &op, data, sy, sx, l);
- if (spanMethod == RegularSpans) {
- uint *dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer;
- op.func(dest, src, l, coverage);
- if (op.dest_store)
- op.dest_store(data->rasterBuffer, x, spans->y, dest, l);
- } else {
- drawBufferSpan(data, src, l, x, spans->y,
- l, coverage);
- }
+ uint *dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer;
+ op.func(dest, src, l, coverage);
+ if (op.dest_store)
+ op.dest_store(data->rasterBuffer, x, spans->y, dest, l);
x += l;
sx += l;
length -= l;
@@ -3634,13 +3989,12 @@ Q_STATIC_TEMPLATE_FUNCTION void blend_untransformed_generic(int count, const QSp
}
}
-template <SpanMethod spanMethod>
-Q_STATIC_TEMPLATE_FUNCTION void blend_untransformed_argb(int count, const QSpan *spans, void *userData)
+static void blend_untransformed_argb(int count, const QSpan *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
if (data->texture.format != QImage::Format_ARGB32_Premultiplied
&& data->texture.format != QImage::Format_RGB32) {
- blend_untransformed_generic<spanMethod>(count, spans, userData);
+ blend_untransformed_generic(count, spans, userData);
return;
}
@@ -3667,13 +4021,8 @@ Q_STATIC_TEMPLATE_FUNCTION void blend_untransformed_argb(int count, const QSpan
if (length > 0) {
const int coverage = (spans->coverage * data->texture.const_alpha) >> 8;
const uint *src = (uint *)data->texture.scanLine(sy) + sx;
- if (spanMethod == RegularSpans) {
- uint *dest = ((uint *)data->rasterBuffer->scanLine(spans->y)) + x;
- op.func(dest, src, length, coverage);
- } else {
- drawBufferSpan(data, src, length, x,
- spans->y, length, coverage);
- }
+ uint *dest = ((uint *)data->rasterBuffer->scanLine(spans->y)) + x;
+ op.func(dest, src, length, coverage);
}
}
++spans;
@@ -3731,1167 +4080,19 @@ static inline void blend_sourceOver_rgb16_rgb16(quint16 *dest,
}
}
-template <class DST, class SRC>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-inline void madd_2(DST *dest, const quint16 alpha, const SRC *src)
-{
- Q_ASSERT((quintptr(dest) & 0x3) == 0);
- Q_ASSERT((quintptr(src) & 0x3) == 0);
- dest[0] = dest[0].byte_mul(alpha >> 8) + DST(src[0]);
- dest[1] = dest[1].byte_mul(alpha & 0xff) + DST(src[1]);
-}
-
-template <class DST, class SRC>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-inline void madd_4(DST *dest, const quint32 alpha, const SRC *src)
-{
- Q_ASSERT((quintptr(dest) & 0x3) == 0);
- Q_ASSERT((quintptr(src) & 0x3) == 0);
- dest[0] = dest[0].byte_mul(alpha >> 24) + DST(src[0]);
- dest[1] = dest[1].byte_mul((alpha >> 16) & 0xff) + DST(src[1]);
- dest[2] = dest[2].byte_mul((alpha >> 8) & 0xff) + DST(src[2]);
- dest[3] = dest[3].byte_mul(alpha & 0xff) + DST(src[3]);
-}
-
-#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
-template <>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-inline void madd_4(qargb8565 *dest, const quint32 a, const qargb8565 *src)
-{
- Q_ASSERT((quintptr(dest) & 0x3) == 0);
- Q_ASSERT((quintptr(src) & 0x3) == 0);
-
- const quint32 *src32 = reinterpret_cast<const quint32*>(src);
- quint32 *dest32 = reinterpret_cast<quint32*>(dest);
- quint32 x, y, t;
- quint8 a8;
-
- {
- x = dest32[0];
- y = src32[0];
-
- a8 = a >> 24;
-
- // a0,g0
- t = ((((x & 0x0007e0ff) * a8) >> 5) & 0x0007e0ff) + (y & 0x0007c0f8);
-
- // r0,b0
- t |= ((((x & 0x00f81f00) * a8) >> 5) & 0x00f81f00) + (y & 0x00f81f00);
-
- a8 = (a >> 16) & 0xff;
-
- // a1
- t |= ((((x & 0xff000000) >> 5) * a8) & 0xff000000) + (y & 0xf8000000);
-
- dest32[0] = t;
- }
- {
- x = dest32[1];
- y = src32[1];
-
- // r1,b1
- t = ((((x & 0x0000f81f) * a8) >> 5) & 0x0000f81f) + (y & 0x0000f81f);
-
- // g1
- t |= ((((x & 0x000007e0) * a8) >> 5) & 0x000007e0) + (y & 0x000007c0);
-
- a8 = (a >> 8) & 0xff;
-
- // a2
- t |= ((((x & 0x00ff0000) * a8) >> 5) & 0x00ff0000) + (y & 0x00f80000);
-
- {
- // rgb2
- quint16 x16 = (x >> 24) | ((dest32[2] & 0x000000ff) << 8);
- quint16 y16 = (y >> 24) | ((src32[2] & 0x000000ff) << 8);
- quint16 t16;
-
- t16 = ((((x16 & 0xf81f) * a8) >> 5) & 0xf81f) + (y16 & 0xf81f);
- t16 |= ((((x16 & 0x07e0) * a8) >> 5) & 0x07e0) + (y16 & 0x07c0);
-
- // rg2
- t |= ((t16 & 0x00ff) << 24);
-
- dest32[1] = t;
-
- x = dest32[2];
- y = src32[2];
-
- // gb2
- t = (t16 >> 8);
- }
- }
- {
- a8 = a & 0xff;
-
- // g3,a3
- t |= ((((x & 0x07e0ff00) * a8) >> 5) & 0x07e0ff00) + (y & 0x07c0f800);
-
- // r3,b3
- t |= ((((x & 0xf81f0000) >> 5) * a8) & 0xf81f0000)+ (y & 0xf81f0000);
-
- dest32[2] = t;
- }
-}
-#endif
-
-#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
-template <>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-inline void madd_4(qargb8555 *dest, const quint32 a, const qargb8555 *src)
-{
- Q_ASSERT((quintptr(dest) & 0x3) == 0);
- Q_ASSERT((quintptr(src) & 0x3) == 0);
-
- const quint32 *src32 = reinterpret_cast<const quint32*>(src);
- quint32 *dest32 = reinterpret_cast<quint32*>(dest);
- quint32 x, y, t;
- quint8 a8;
-
- {
- x = dest32[0];
- y = src32[0];
-
- a8 = a >> 24;
-
- // a0,g0
- t = ((((x & 0x0003e0ff) * a8) >> 5) & 0x0003e0ff) + (y & 0x0003e0f8);
-
- // r0,b0
- t |= ((((x & 0x007c1f00) * a8) >> 5) & 0x007c1f00) + (y & 0x007c1f00);
-
- a8 = (a >> 16) & 0xff;
-
- // a1
- t |= ((((x & 0xff000000) >> 5) * a8) & 0xff000000) + (y & 0xf8000000);
-
- dest32[0] = t;
- }
- {
- x = dest32[1];
- y = src32[1];
-
- // r1,b1
- t = ((((x & 0x00007c1f) * a8) >> 5) & 0x00007c1f) + (y & 0x00007c1f);
-
- // g1
- t |= ((((x & 0x000003e0) * a8) >> 5) & 0x000003e0) + (y & 0x000003e0);
-
- a8 = (a >> 8) & 0xff;
-
- // a2
- t |= ((((x & 0x00ff0000) * a8) >> 5) & 0x00ff0000) + (y & 0x00f80000);
-
- {
- // rgb2
- quint16 x16 = (x >> 24) | ((dest32[2] & 0x000000ff) << 8);
- quint16 y16 = (y >> 24) | ((src32[2] & 0x000000ff) << 8);
- quint16 t16;
-
- t16 = ((((x16 & 0x7c1f) * a8) >> 5) & 0x7c1f) + (y16 & 0x7c1f);
- t16 |= ((((x16 & 0x03e0) * a8) >> 5) & 0x03e0) + (y16 & 0x03e0);
-
- // rg2
- t |= ((t16 & 0x00ff) << 24);
-
- dest32[1] = t;
-
- x = dest32[2];
- y = src32[2];
-
- // gb2
- t = (t16 >> 8);
- }
- }
- {
- a8 = a & 0xff;
-
- // g3,a3
- t |= ((((x & 0x03e0ff00) * a8) >> 5) & 0x03e0ff00) + (y & 0x03e0f800);
-
- // r3,b3
- t |= ((((x & 0x7c1f0000) >> 5) * a8) & 0x7c1f0000)+ (y & 0x7c1f0000);
-
- dest32[2] = t;
- }
-}
-#endif
-
-template <class T>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-inline quint16 alpha_2(const T *src)
-{
- Q_ASSERT((quintptr(src) & 0x3) == 0);
-
- if (T::hasAlpha())
- return (src[0].alpha() << 8) | src[1].alpha();
- else
- return 0xffff;
-}
-
-template <class T>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-inline quint32 alpha_4(const T *src)
-{
- Q_ASSERT((quintptr(src) & 0x3) == 0);
-
- if (T::hasAlpha()) {
- return (src[0].alpha() << 24) | (src[1].alpha() << 16)
- | (src[2].alpha() << 8) | src[3].alpha();
- } else {
- return 0xffffffff;
- }
-}
-
-template <>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-inline quint32 alpha_4(const qargb8565 *src)
-{
- const quint8 *src8 = reinterpret_cast<const quint8*>(src);
- return src8[0] << 24 | src8[3] << 16 | src8[6] << 8 | src8[9];
-}
-
-template <>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-inline quint32 alpha_4(const qargb6666 *src)
-{
- const quint8 *src8 = reinterpret_cast<const quint8*>(src);
- return ((src8[2] & 0xfc) | (src8[2] >> 6)) << 24
- | ((src8[5] & 0xfc) | (src8[5] >> 6)) << 16
- | ((src8[8] & 0xfc) | (src8[8] >> 6)) << 8
- | ((src8[11] & 0xfc) | (src8[11] >> 6));
-}
-
-template <>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-inline quint32 alpha_4(const qargb8555 *src)
-{
- Q_ASSERT((quintptr(src) & 0x3) == 0);
- const quint8 *src8 = reinterpret_cast<const quint8*>(src);
- return src8[0] << 24 | src8[3] << 16 | src8[6] << 8 | src8[9];
-}
-
-template <>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-inline quint16 alpha_2(const qargb4444 *src)
-{
- const quint32 *src32 = reinterpret_cast<const quint32*>(src);
- const quint32 t = (*src32 & 0xf000f000) |
- ((*src32 & 0xf000f000) >> 4);
- return (t >> 24) | (t & 0xff00);
-}
-
-template <class T>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-inline quint16 eff_alpha_2(quint16 alpha, const T*)
-{
- return (T::alpha((alpha >> 8) & 0xff) << 8)
- | T::alpha(alpha & 0xff);
-}
-
-template <>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-inline quint16 eff_alpha_2(quint16 a, const qrgb565*)
-{
- return ((((a & 0xff00) + 0x0100) >> 3) & 0xff00)
- | ((((a & 0x00ff) + 0x0001) >> 3) & 0x00ff);
-}
-
-template <>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-inline quint16 eff_alpha_2(quint16 a, const qrgb444*)
-{
- return (((a & 0x00ff) + 0x0001) >> 4)
- | ((((a & 0xff00) + 0x0100) >> 4) & 0xff00);
-}
-
-template <>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-inline quint16 eff_alpha_2(quint16 a, const qargb4444*)
-{
- return (((a & 0x00ff) + 0x0001) >> 4)
- | ((((a & 0xff00) + 0x0100) >> 4) & 0xff00);
-}
-
-template <class T>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-inline quint16 eff_ialpha_2(quint16 alpha, const T*)
-{
- return (T::ialpha((alpha >> 8) & 0xff) << 8)
- | T::ialpha(alpha & 0xff);
-}
-
-template <>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-inline quint16 eff_ialpha_2(quint16 a, const qrgb565 *dummy)
-{
- return 0x2020 - eff_alpha_2(a, dummy);
-}
-
-template <>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-inline quint16 eff_ialpha_2(quint16 a, const qargb4444 *dummy)
-{
- return 0x1010 - eff_alpha_2(a, dummy);
-}
-
-template <>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-inline quint16 eff_ialpha_2(quint16 a, const qrgb444 *dummy)
-{
- return 0x1010 - eff_alpha_2(a, dummy);
-}
-
-template <class T>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-inline quint32 eff_alpha_4(quint32 alpha, const T*)
-{
- return (T::alpha(alpha >> 24) << 24)
- | (T::alpha((alpha >> 16) & 0xff) << 16)
- | (T::alpha((alpha >> 8) & 0xff) << 8)
- | T::alpha(alpha & 0xff);
-}
-
-template <>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-inline quint32 eff_alpha_4(quint32 a, const qrgb888*)
-{
- return a;
-}
-
-template <>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-inline quint32 eff_alpha_4(quint32 a, const qargb8565*)
-{
- return ((((a & 0xff00ff00) + 0x01000100) >> 3) & 0xff00ff00)
- | ((((a & 0x00ff00ff) + 0x00010001) >> 3) & 0x00ff00ff);
-}
-
-template <>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-inline quint32 eff_alpha_4(quint32 a, const qargb6666*)
-{
- return ((((a & 0xff00ff00) >> 2) + 0x00400040) & 0xff00ff00)
- | ((((a & 0x00ff00ff) + 0x00010001) >> 2) & 0x00ff00ff);
-}
-
-template <>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-inline quint32 eff_alpha_4(quint32 a, const qrgb666*)
-{
- return ((((a & 0xff00ff00) >> 2) + 0x00400040) & 0xff00ff00)
- | ((((a & 0x00ff00ff) + 0x00010001) >> 2) & 0x00ff00ff);
-}
-
-template <>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-inline quint32 eff_alpha_4(quint32 a, const qargb8555*)
-{
- return ((((a & 0xff00ff00) + 0x01000100) >> 3) & 0xff00ff00)
- | ((((a & 0x00ff00ff) + 0x00010001) >> 3) & 0x00ff00ff);
-}
-
-template <class T>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-inline quint32 eff_ialpha_4(quint32 alpha, const T*)
-{
- return (T::ialpha(alpha >> 24) << 24)
- | (T::ialpha((alpha >> 16) & 0xff) << 16)
- | (T::ialpha((alpha >> 8) & 0xff) << 8)
- | T::ialpha(alpha & 0xff);
-}
-
-template <>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-inline quint32 eff_ialpha_4(quint32 a, const qrgb888*)
-{
- return ~a;
-}
-
-template <>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-inline quint32 eff_ialpha_4(quint32 a, const qargb8565 *dummy)
-{
- return 0x20202020 - eff_alpha_4(a, dummy);
-}
-
-template <>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-inline quint32 eff_ialpha_4(quint32 a, const qargb6666 *dummy)
-{
- return 0x40404040 - eff_alpha_4(a, dummy);
-}
-
-template <>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-inline quint32 eff_ialpha_4(quint32 a, const qrgb666 *dummy)
-{
- return 0x40404040 - eff_alpha_4(a, dummy);
-}
-
-template <>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-inline quint32 eff_ialpha_4(quint32 a, const qargb8555 *dummy)
-{
- return 0x20202020 - eff_alpha_4(a, dummy);
-}
-
-template <class DST, class SRC>
-inline void interpolate_pixel_unaligned_2(DST *dest, const SRC *src,
- quint16 alpha)
-{
- const quint16 a = eff_alpha_2(alpha, dest);
- const quint16 ia = eff_ialpha_2(alpha, dest);
- dest[0] = DST(src[0]).byte_mul(a >> 8) + dest[0].byte_mul(ia >> 8);
- dest[1] = DST(src[1]).byte_mul(a & 0xff) + dest[1].byte_mul(ia & 0xff);
-}
-
-template <class DST, class SRC>
-inline void interpolate_pixel_2(DST *dest, const SRC *src, quint16 alpha)
-{
- Q_ASSERT((quintptr(dest) & 0x3) == 0);
- Q_ASSERT((quintptr(src) & 0x3) == 0);
-
- const quint16 a = eff_alpha_2(alpha, dest);
- const quint16 ia = eff_ialpha_2(alpha, dest);
-
- dest[0] = DST(src[0]).byte_mul(a >> 8) + dest[0].byte_mul(ia >> 8);
- dest[1] = DST(src[1]).byte_mul(a & 0xff) + dest[1].byte_mul(ia & 0xff);
-}
-
-template <class DST, class SRC>
-inline void interpolate_pixel(DST &dest, quint8 a, const SRC &src, quint8 b)
-{
- if (SRC::hasAlpha() && !DST::hasAlpha())
- interpolate_pixel(dest, a, DST(src), b);
- else
- dest = dest.byte_mul(a) + DST(src).byte_mul(b);
-}
-
-template <>
-inline void interpolate_pixel(qargb8565 &dest, quint8 a,
- const qargb8565 &src, quint8 b)
-{
- quint8 *d = reinterpret_cast<quint8*>(&dest);
- const quint8 *s = reinterpret_cast<const quint8*>(&src);
- d[0] = (d[0] * a + s[0] * b) >> 5;
-
- const quint16 x = (d[2] << 8) | d[1];
- const quint16 y = (s[2] << 8) | s[1];
- quint16 t = (((x & 0x07e0) * a + (y & 0x07e0) * b) >> 5) & 0x07e0;
- t |= (((x & 0xf81f) * a + (y & 0xf81f) * b) >> 5) & 0xf81f;
-
- d[1] = t & 0xff;
- d[2] = t >> 8;
-}
-
-template <>
-inline void interpolate_pixel(qrgb565 &dest, quint8 a,
- const qrgb565 &src, quint8 b)
-{
- const quint16 x = dest.rawValue();
- const quint16 y = src.rawValue();
- quint16 t = (((x & 0x07e0) * a + (y & 0x07e0) * b) >> 5) & 0x07e0;
- t |= (((x & 0xf81f) * a + (y & 0xf81f) * b) >> 5) & 0xf81f;
- dest = t;
-}
-
-template <>
-inline void interpolate_pixel(qrgb555 &dest, quint8 a,
- const qrgb555 &src, quint8 b)
-{
- const quint16 x = dest.rawValue();
- const quint16 y = src.rawValue();
- quint16 t = (((x & 0x03e0) * a + (y & 0x03e0) * b) >> 5) & 0x03e0;
- t |= ((((x & 0x7c1f) * a) + ((y & 0x7c1f) * b)) >> 5) & 0x7c1f;
- dest = t;
-}
-
-template <>
-inline void interpolate_pixel(qrgb444 &dest, quint8 a,
- const qrgb444 &src, quint8 b)
-{
- const quint16 x = dest.rawValue();
- const quint16 y = src.rawValue();
- quint16 t = ((x & 0x00f0) * a + (y & 0x00f0) * b) & 0x0f00;
- t |= ((x & 0x0f0f) * a + (y & 0x0f0f) * b) & 0xf0f0;
- quint16 *d = reinterpret_cast<quint16*>(&dest);
- *d = (t >> 4);
-}
-
-template <class DST, class SRC>
-inline void interpolate_pixel_2(DST *dest, quint8 a,
- const SRC *src, quint8 b)
-{
- Q_ASSERT((quintptr(dest) & 0x3) == 0);
- Q_ASSERT((quintptr(src) & 0x3) == 0);
-
- Q_ASSERT(!SRC::hasAlpha());
-
- dest[0] = dest[0].byte_mul(a) + DST(src[0]).byte_mul(b);
- dest[1] = dest[1].byte_mul(a) + DST(src[1]).byte_mul(b);
-}
-
-template <>
-inline void interpolate_pixel_2(qrgb565 *dest, quint8 a,
- const qrgb565 *src, quint8 b)
-{
- quint32 *x = reinterpret_cast<quint32*>(dest);
- const quint32 *y = reinterpret_cast<const quint32*>(src);
- quint32 t = (((*x & 0xf81f07e0) >> 5) * a +
- ((*y & 0xf81f07e0) >> 5) * b) & 0xf81f07e0;
- t |= (((*x & 0x07e0f81f) * a
- + (*y & 0x07e0f81f) * b) >> 5) & 0x07e0f81f;
- *x = t;
-}
-
-template <>
-inline void interpolate_pixel_2(qrgb555 *dest, quint8 a,
- const qrgb555 *src, quint8 b)
-{
- quint32 *x = reinterpret_cast<quint32*>(dest);
- const quint32 *y = reinterpret_cast<const quint32*>(src);
- quint32 t = (((*x & 0x7c1f03e0) >> 5) * a +
- ((*y & 0x7c1f03e0) >> 5) * b) & 0x7c1f03e0;
- t |= (((*x & 0x03e07c1f) * a
- + (*y & 0x03e07c1f) * b) >> 5) & 0x03e07c1f;
- *x = t;
-}
-
-template <>
-inline void interpolate_pixel_2(qrgb444 *dest, quint8 a,
- const qrgb444 *src, quint8 b)
-{
- quint32 *x = reinterpret_cast<quint32*>(dest);
- const quint32 *y = reinterpret_cast<const quint32*>(src);
- quint32 t = ((*x & 0x0f0f0f0f) * a + (*y & 0x0f0f0f0f) * b) & 0xf0f0f0f0;
- t |= ((*x & 0x00f000f0) * a + (*y & 0x00f000f0) * b) & 0x0f000f00;
- *x = t >> 4;
-}
-
-template <class DST, class SRC>
-inline void interpolate_pixel_4(DST *dest, const SRC *src, quint32 alpha)
-{
- Q_ASSERT((quintptr(dest) & 0x3) == 0);
- Q_ASSERT((quintptr(src) & 0x3) == 0);
-
- const quint32 a = eff_alpha_4(alpha, dest);
- const quint32 ia = eff_ialpha_4(alpha, dest);
- dest[0] = DST(src[0]).byte_mul(a >> 24)
- + dest[0].byte_mul(ia >> 24);
- dest[1] = DST(src[1]).byte_mul((a >> 16) & 0xff)
- + dest[1].byte_mul((ia >> 16) & 0xff);
- dest[2] = DST(src[2]).byte_mul((a >> 8) & 0xff)
- + dest[2].byte_mul((ia >> 8) & 0xff);
- dest[3] = DST(src[3]).byte_mul(a & 0xff)
- + dest[3].byte_mul(ia & 0xff);
-}
-
-#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
-template <>
-inline void interpolate_pixel_4(qargb8565 *dest, const qargb8565 *src,
- quint32 alpha)
-{
- Q_ASSERT((quintptr(dest) & 0x3) == 0);
- Q_ASSERT((quintptr(src) & 0x3) == 0);
-
- const quint32 a = eff_alpha_4(alpha, dest);
- const quint32 ia = eff_ialpha_4(alpha, dest);
- const quint32 *src32 = reinterpret_cast<const quint32*>(src);
- quint32 *dest32 = reinterpret_cast<quint32*>(dest);
-
- quint32 x, y, t;
- quint8 a8, ia8;
- {
- x = src32[0];
- y = dest32[0];
-
- a8 = a >> 24;
- ia8 = ia >> 24;
-
- // a0,g0
- t = (((x & 0x0007e0ff) * a8 + (y & 0x0007e0ff) * ia8) >> 5)
- & 0x0007e0ff;
-
- // r0,b0
- t |= (((x & 0x00f81f00) * a8 + (y & 0x00f81f00) * ia8) >> 5)
- & 0x00f81f00;
-
- a8 = (a >> 16) & 0xff;
- ia8 = (ia >> 16) & 0xff;
-
- // a1
- t |= (((x & 0xff000000) >> 5) * a8 + ((y & 0xff000000) >> 5) * ia8)
- & 0xff000000;
-
- dest32[0] = t;
- }
- {
- x = src32[1];
- y = dest32[1];
-
- // r1,b1
- t = (((x & 0x0000f81f) * a8 + (y & 0x0000f81f) * ia8) >> 5)
- & 0x0000f81f;
-
- // g1
- t |= (((x & 0x000007e0) * a8 + (y & 0x000007e0) * ia8) >> 5)
- & 0x000007e0;
-
- a8 = (a >> 8) & 0xff;
- ia8 = (ia >> 8) & 0xff;
-
- // a2
- t |= (((x & 0x00ff0000) * a8 + (y & 0x00ff0000) * ia8) >> 5)
- & 0x00ff0000;
-
- {
- // rgb2
- quint16 x16 = (x >> 24) | ((src32[2] & 0x000000ff) << 8);
- quint16 y16 = (y >> 24) | ((dest32[2] & 0x000000ff) << 8);
- quint16 t16;
-
- t16 = (((x16 & 0xf81f) * a8 + (y16 & 0xf81f) * ia8) >> 5) & 0xf81f;
- t16 |= (((x16 & 0x07e0) * a8 + (y16 & 0x07e0) * ia8) >> 5) & 0x07e0;
-
- // rg2
- t |= ((t16 & 0x00ff) << 24);
-
- dest32[1] = t;
-
- x = src32[2];
- y = dest32[2];
-
- // gb2
- t = (t16 >> 8);
- }
- }
- {
- a8 = a & 0xff;
- ia8 = ia & 0xff;
-
- // g3,a3
- t |= (((x & 0x07e0ff00) * a8 + (y & 0x07e0ff00) * ia8) >> 5)
- & 0x07e0ff00;
-
- // r3,b3
- t |= (((x & 0xf81f0000) >> 5) * a8 + ((y & 0xf81f0000) >> 5) * ia8)
- & 0xf81f0000;
-
- dest32[2] = t;
- }
-}
-#endif
-
-#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
-template <>
-inline void interpolate_pixel_4(qargb8555 *dest, const qargb8555 *src,
- quint32 alpha)
-{
- Q_ASSERT((quintptr(dest) & 0x3) == 0);
- Q_ASSERT((quintptr(src) & 0x3) == 0);
-
-
- const quint32 a = eff_alpha_4(alpha, dest);
- const quint32 ia = eff_ialpha_4(alpha, dest);
- const quint32 *src32 = reinterpret_cast<const quint32*>(src);
- quint32 *dest32 = reinterpret_cast<quint32*>(dest);
-
- quint32 x, y, t;
- quint8 a8, ia8;
- {
- x = src32[0];
- y = dest32[0];
-
- a8 = a >> 24;
- ia8 = ia >> 24;
-
- // a0,g0
- t = (((x & 0x0003e0ff) * a8 + (y & 0x0003e0ff) * ia8) >> 5)
- & 0x0003e0ff;
-
- // r0,b0
- t |= (((x & 0x007c1f00) * a8 + (y & 0x007c1f00) * ia8) >> 5)
- & 0x007c1f00;
-
- a8 = (a >> 16) & 0xff;
- ia8 = (ia >> 16) & 0xff;
-
- // a1
- t |= (((x & 0xff000000) >> 5) * a8 + ((y & 0xff000000) >> 5) * ia8)
- & 0xff000000;
-
- dest32[0] = t;
- }
- {
- x = src32[1];
- y = dest32[1];
-
- // r1,b1
- t = (((x & 0x00007c1f) * a8 + (y & 0x00007c1f) * ia8) >> 5)
- & 0x00007c1f;
-
- // g1
- t |= (((x & 0x000003e0) * a8 + (y & 0x000003e0) * ia8) >> 5)
- & 0x000003e0;
-
- a8 = (a >> 8) & 0xff;
- ia8 = (ia >> 8) & 0xff;
-
- // a2
- t |= (((x & 0x00ff0000) * a8 + (y & 0x00ff0000) * ia8) >> 5)
- & 0x00ff0000;
-
- {
- // rgb2
- quint16 x16 = (x >> 24) | ((src32[2] & 0x000000ff) << 8);
- quint16 y16 = (y >> 24) | ((dest32[2] & 0x000000ff) << 8);
- quint16 t16;
-
- t16 = (((x16 & 0x7c1f) * a8 + (y16 & 0x7c1f) * ia8) >> 5) & 0x7c1f;
- t16 |= (((x16 & 0x03e0) * a8 + (y16 & 0x03e0) * ia8) >> 5) & 0x03e0;
-
- // rg2
- t |= ((t16 & 0x00ff) << 24);
-
- dest32[1] = t;
-
- x = src32[2];
- y = dest32[2];
-
- // gb2
- t = (t16 >> 8);
- }
- }
- {
- a8 = a & 0xff;
- ia8 = ia & 0xff;
-
- // g3,a3
- t |= (((x & 0x03e0ff00) * a8 + (y & 0x03e0ff00) * ia8) >> 5)
- & 0x03e0ff00;
-
- // r3,b3
- t |= (((x & 0x7c1f0000) >> 5) * a8 + ((y & 0x7c1f0000) >> 5) * ia8)
- & 0x7c1f0000;
-
- dest32[2] = t;
- }
-}
-#endif
-
-template <>
-inline void interpolate_pixel_4(qrgb888 *dest, const qrgb888 *src,
- quint32 alpha)
-{
- Q_ASSERT((quintptr(dest) & 0x3) == 0);
- Q_ASSERT((quintptr(src) & 0x3) == 0);
-
- const quint32 a = eff_alpha_4(alpha, dest);
- const quint32 ia = eff_ialpha_4(alpha, dest);
- const quint32 *src32 = reinterpret_cast<const quint32*>(src);
- quint32 *dest32 = reinterpret_cast<quint32*>(dest);
-
- {
- quint32 x = src32[0];
- quint32 y = dest32[0];
-
- quint32 t;
- t = ((x >> 8) & 0xff00ff) * (a >> 24)
- + ((y >> 8) & 0xff00ff) * (ia >> 24);
- t = (t + ((t >> 8) & 0xff00ff) + 0x800080);
- t &= 0xff00ff00;
-
- x = (x & 0xff0000) * (a >> 24)
- + (x & 0x0000ff) * ((a >> 16) & 0xff)
- + (y & 0xff0000) * (ia >> 24)
- + (y & 0x0000ff) * ((ia >> 16) & 0xff);
- x = (x + ((x >> 8) & 0xff00ff) + 0x800080) >> 8;
- x &= 0x00ff00ff;
-
- dest32[0] = x | t;
- }
- {
- quint32 x = src32[1];
- quint32 y = dest32[1];
-
- quint32 t;
- t = ((x >> 8) & 0xff0000) * ((a >> 16) & 0xff)
- + ((x >> 8) & 0x0000ff) * ((a >> 8) & 0xff)
- + ((y >> 8) & 0xff0000) * ((ia >> 16) & 0xff)
- + ((y >> 8) & 0x0000ff) * ((ia >> 8) & 0xff);
- t = (t + ((t >> 8) & 0xff00ff) + 0x800080);
- t &= 0xff00ff00;
-
- x = (x & 0xff0000) * ((a >> 16) & 0xff)
- + (x & 0x0000ff) * ((a >> 8) & 0xff)
- + (y & 0xff0000) * ((ia >> 16) & 0xff)
- + (y & 0x0000ff) * ((ia >> 8) & 0xff);
- x = (x + ((x >> 8) & 0xff00ff) + 0x800080) >> 8;
- x &= 0x00ff00ff;
-
- dest32[1] = x | t;
- }
- {
- quint32 x = src32[2];
- quint32 y = dest32[2];
-
- quint32 t;
- t = ((x >> 8) & 0xff0000) * ((a >> 8) & 0xff)
- + ((x >> 8) & 0x0000ff) * (a & 0xff)
- + ((y >> 8) & 0xff0000) * ((ia >> 8) & 0xff)
- + ((y >> 8) & 0x0000ff) * (ia & 0xff);
- t = (t + ((t >> 8) & 0xff00ff) + 0x800080);
- t &= 0xff00ff00;
-
- x = (x & 0xff00ff) * (a & 0xff)
- + (y & 0xff00ff) * (ia & 0xff);
- x = (x + ((x >> 8) & 0xff00ff) + 0x800080) >> 8;
- x &= 0x00ff00ff;
-
- dest32[2] = x | t;
- }
-}
-
-template <class DST, class SRC>
-inline void interpolate_pixel_4(DST *dest, quint8 a,
- const SRC *src, quint8 b)
-{
- Q_ASSERT((quintptr(dest) & 0x3) == 0);
- Q_ASSERT((quintptr(src) & 0x3) == 0);
-
- dest[0] = dest[0].byte_mul(a) + DST(src[0]).byte_mul(b);
- dest[1] = dest[1].byte_mul(a) + DST(src[1]).byte_mul(b);
- dest[2] = dest[2].byte_mul(a) + DST(src[2]).byte_mul(b);
- dest[3] = dest[3].byte_mul(a) + DST(src[3]).byte_mul(b);
-}
-
-template <class DST, class SRC>
-inline void blend_sourceOver_4(DST *dest, const SRC *src)
-{
- Q_ASSERT((quintptr(dest) & 0x3) == 0);
- Q_ASSERT((quintptr(src) & 0x3) == 0);
-
- const quint32 a = alpha_4(src);
- if (a == 0xffffffff) {
- qt_memconvert(dest, src, 4);
- } else if (a > 0) {
- quint32 buf[3]; // array of quint32 to get correct alignment
- qt_memconvert((DST*)(void*)buf, src, 4);
- madd_4(dest, eff_ialpha_4(a, dest), (DST*)(void*)buf);
- }
-}
-
-template <>
-inline void blend_sourceOver_4(qargb8565 *dest, const qargb8565 *src)
-{
- Q_ASSERT((quintptr(dest) & 0x3) == 0);
- Q_ASSERT((quintptr(src) & 0x3) == 0);
-
- const quint32 a = alpha_4(src);
- if (a == 0xffffffff) {
- qt_memconvert(dest, src, 4);
- } else if (a > 0) {
- madd_4(dest, eff_ialpha_4(a, dest), src);
- }
-}
-
-template <>
-inline void blend_sourceOver_4(qargb8555 *dest, const qargb8555 *src)
-{
- Q_ASSERT((quintptr(dest) & 0x3) == 0);
- Q_ASSERT((quintptr(src) & 0x3) == 0);
-
- const quint32 a = alpha_4(src);
- if (a == 0xffffffff) {
- qt_memconvert(dest, src, 4);
- } else if (a > 0) {
- madd_4(dest, eff_ialpha_4(a, dest), src);
- }
-}
-
-template <>
-inline void blend_sourceOver_4(qargb6666 *dest, const qargb6666 *src)
-{
- Q_ASSERT((quintptr(dest) & 0x3) == 0);
- Q_ASSERT((quintptr(src) & 0x3) == 0);
-
- const quint32 a = alpha_4(src);
- if (a == 0xffffffff) {
- qt_memconvert(dest, src, 4);
- } else if (a > 0) {
- madd_4(dest, eff_ialpha_4(a, dest), src);
- }
-}
-
-template <class DST, class SRC>
-void QT_FASTCALL blendUntransformed_unaligned(DST *dest, const SRC *src,
- quint8 coverage, int length)
-{
- Q_ASSERT(coverage > 0);
-
- if (coverage < 255) {
- if (SRC::hasAlpha()) {
- for (int i = 0; i < length; ++i) {
- if (src[i].alpha()) {
- const quint8 alpha = qt_div_255(int(src[i].alpha()) * int(coverage));
- interpolate_pixel(dest[i], DST::ialpha(alpha),
- src[i], DST::alpha(alpha));
- }
- }
- } else {
- const quint8 alpha = DST::alpha(coverage);
- const quint8 ialpha = DST::ialpha(coverage);
- if (alpha) {
- for (int i = 0; i < length; ++i)
- interpolate_pixel(dest[i], ialpha, src[i], alpha);
- }
- }
- return;
- }
-
- Q_ASSERT(coverage == 0xff);
- Q_ASSERT(SRC::hasAlpha());
-
- if (SRC::hasAlpha()) {
- for (int i = 0; i < length; ++i) {
- const quint8 a = src->alpha();
- if (a == 0xff)
- *dest = DST(*src);
- else if (a > 0) {
- if (DST::hasAlpha())
- *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(a));
- else
- *dest = DST(SRC(*src).truncedAlpha()) + dest->byte_mul(DST::ialpha(a));
- }
- ++src;
- ++dest;
- }
- }
-}
-
-template <class DST, class SRC>
-void QT_FASTCALL blendUntransformed_dest16(DST *dest, const SRC *src,
- quint8 coverage, int length)
-{
- Q_ASSERT(sizeof(DST) == 2);
- Q_ASSERT(sizeof(SRC) == 2);
- Q_ASSERT((quintptr(dest) & 0x3) == (quintptr(src) & 0x3));
- Q_ASSERT(coverage > 0);
-
- const int align = quintptr(dest) & 0x3;
-
- if (coverage < 255) {
- // align
- if (align) {
- const quint8 alpha = SRC::hasAlpha()
- ? qt_div_255(int(src->alpha()) * int(coverage))
- : coverage;
- if (alpha) {
- interpolate_pixel(*dest, DST::ialpha(alpha),
- *src, DST::alpha(alpha));
- }
- ++dest;
- ++src;
- --length;
- }
-
- if (SRC::hasAlpha()) {
- while (length >= 2) {
- const quint16 alpha16 = BYTE_MUL(uint(alpha_2(src)), uint(coverage));
- interpolate_pixel_2(dest, src, alpha16);
- length -= 2;
- src += 2;
- dest += 2;
- }
- } else {
- const quint8 alpha = DST::alpha(coverage);
- const quint8 ialpha = DST::ialpha(coverage);
-
- while (length >= 2) {
- interpolate_pixel_2(dest, ialpha, src, alpha);
- length -= 2;
- src += 2;
- dest += 2;
- }
- }
-
- // tail
- if (length) {
- const quint8 alpha = SRC::hasAlpha()
- ? qt_div_255(int(src->alpha()) * int(coverage))
- : coverage;
- if (alpha) {
- interpolate_pixel(*dest, DST::ialpha(alpha),
- *src, DST::alpha(alpha));
- }
- }
-
- return;
- }
-
- Q_ASSERT(SRC::hasAlpha());
- if (SRC::hasAlpha()) {
- if (align) {
- const quint8 alpha = src->alpha();
- if (alpha == 0xff)
- *dest = DST(*src);
- else if (alpha > 0)
- *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(alpha));
- ++dest;
- ++src;
- --length;
- }
-
- while (length >= 2) {
- Q_ASSERT((quintptr(dest) & 3) == 0);
- Q_ASSERT((quintptr(src) & 3) == 0);
-
- const quint16 a = alpha_2(src);
- if (a == 0xffff) {
- qt_memconvert(dest, src, 2);
- } else if (a > 0) {
- quint32 buf;
- if (sizeof(DST) == 2)
- qt_memconvert((DST*)(void*)&buf, src, 2);
- madd_2(dest, eff_ialpha_2(a, dest), (DST*)(void*)&buf);
- }
-
- length -= 2;
- src += 2;
- dest += 2;
- }
-
- if (length) {
- const quint8 alpha = src->alpha();
- if (alpha == 0xff)
- *dest = DST(*src);
- else if (alpha > 0)
- *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(alpha));
- }
- }
-}
-
-template <class DST, class SRC>
-void QT_FASTCALL blendUntransformed_dest24(DST *dest, const SRC *src,
- quint8 coverage, int length)
-{
- Q_ASSERT((quintptr(dest) & 0x3) == (quintptr(src) & 0x3));
- Q_ASSERT(sizeof(DST) == 3);
- Q_ASSERT(coverage > 0);
-
- const int align = quintptr(dest) & 0x3;
-
- if (coverage < 255) {
- // align
- for (int i = 0; i < align; ++i) {
- if (SRC::hasAlpha()) {
- const quint8 alpha = qt_div_255(int(src->alpha()) * int(coverage));
- if (alpha)
- interpolate_pixel(*dest, DST::ialpha(alpha),
- *src, DST::alpha(alpha));
- } else {
- interpolate_pixel(*dest, DST::ialpha(coverage),
- *src, DST::alpha(coverage));
- }
- ++dest;
- ++src;
- --length;
- }
-
- if (SRC::hasAlpha()) {
- while (length >= 4) {
- const quint32 alpha = QT_PREPEND_NAMESPACE(BYTE_MUL)(uint(alpha_4(src)), uint(coverage));
- if (alpha)
- interpolate_pixel_4(dest, src, alpha);
- length -= 4;
- src += 4;
- dest += 4;
- }
- } else {
- const quint8 alpha = DST::alpha(coverage);
- const quint8 ialpha = DST::ialpha(coverage);
- while (length >= 4) {
- interpolate_pixel_4(dest, ialpha, src, alpha);
- length -= 4;
- src += 4;
- dest += 4;
- }
- }
-
- // tail
- while (length--) {
- if (SRC::hasAlpha()) {
- const quint8 alpha = qt_div_255(int(src->alpha()) * int(coverage));
- if (alpha)
- interpolate_pixel(*dest, DST::ialpha(alpha),
- *src, DST::alpha(alpha));
- } else {
- interpolate_pixel(*dest, DST::ialpha(coverage),
- *src, DST::alpha(coverage));
- }
- ++dest;
- ++src;
- }
-
- return;
- }
-
-
- Q_ASSERT(coverage == 255);
- Q_ASSERT(SRC::hasAlpha());
-
- if (SRC::hasAlpha()) {
- // align
- for (int i = 0; i < align; ++i) {
- const quint8 a = src->alpha();
- if (a == 0xff) {
- *dest = DST(*src);
- } else if (a > 0) {
- *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(a));
- }
- ++dest;
- ++src;
- --length;
- }
-
- while (length >= 4) {
- blend_sourceOver_4(dest, src);
- length -= 4;
- src += 4;
- dest += 4;
- }
-
- // tail
- while (length--) {
- const quint8 a = src->alpha();
- if (a == 0xff) {
- *dest = DST(*src);
- } else if (a > 0) {
- *dest = DST(*src).truncedAlpha() + dest->byte_mul(DST::ialpha(a));
- }
- ++dest;
- ++src;
- }
- }
-}
-
-template <class DST, class SRC>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-void QT_FASTCALL blendUntransformed(int count, const QSpan *spans, void *userData)
+static void blend_untransformed_rgb565(int count, const QSpan *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData*>(userData);
QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
- if (mode != QPainter::CompositionMode_SourceOver &&
- mode != QPainter::CompositionMode_Source)
+ if (data->texture.format != QImage::Format_RGB16
+ || (mode != QPainter::CompositionMode_SourceOver
+ && mode != QPainter::CompositionMode_Source))
{
- blend_src_generic<RegularSpans>(count, spans, userData);
+ blend_untransformed_generic(count, spans, userData);
return;
}
- const bool modeSource = !SRC::hasAlpha() ||
- mode == QPainter::CompositionMode_Source;
const int image_width = data->texture.width;
const int image_height = data->texture.height;
int xoff = -qRound(-data->dx);
@@ -4917,20 +4118,15 @@ void QT_FASTCALL blendUntransformed(int count, const QSpan *spans, void *userDat
if (sx + length > image_width)
length = image_width - sx;
if (length > 0) {
- DST *dest = ((DST*)data->rasterBuffer->scanLine(spans->y)) + x;
- const SRC *src = (SRC*)data->texture.scanLine(sy) + sx;
- if (modeSource && coverage == 255) {
- qt_memconvert<DST, SRC>(dest, src, length);
- } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && length >= 3 &&
- (quintptr(dest) & 3) == (quintptr(src) & 3))
- {
- blendUntransformed_dest24(dest, src, coverage, length);
- } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && length >= 3 &&
- (quintptr(dest) & 3) == (quintptr(src) & 3))
- {
- blendUntransformed_dest16(dest, src, coverage, length);
+ quint16 *dest = (quint16 *)data->rasterBuffer->scanLine(spans->y) + x;
+ const quint16 *src = (quint16 *)data->texture.scanLine(sy) + sx;
+ if (coverage == 255) {
+ memcpy(dest, src, length * sizeof(quint16));
} else {
- blendUntransformed_unaligned(dest, src, coverage, length);
+ const quint8 alpha = (coverage + 1) >> 3;
+ const quint8 ialpha = 0x20 - alpha;
+ if (alpha > 0)
+ blend_sourceOver_rgb16_rgb16(dest, src, length, alpha, ialpha);
}
}
}
@@ -4938,69 +4134,7 @@ void QT_FASTCALL blendUntransformed(int count, const QSpan *spans, void *userDat
}
}
-static void blend_untransformed_rgb888(int count, const QSpan *spans,
- void *userData)
-{
- blend_untransformed_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_untransformed_argb6666(int count, const QSpan *spans,
- void *userData)
-{
- blend_untransformed_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_untransformed_rgb666(int count, const QSpan *spans,
- void *userData)
-{
- blend_untransformed_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_untransformed_argb8565(int count, const QSpan *spans,
- void *userData)
-{
- blend_untransformed_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_untransformed_rgb565(int count, const QSpan *spans,
- void *userData)
-{
- QSpanData *data = reinterpret_cast<QSpanData *>(userData);
-
- if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
- blendUntransformed<qrgb565, qargb8565>(count, spans, userData);
- else if (data->texture.format == QImage::Format_RGB16)
- blendUntransformed<qrgb565, qrgb565>(count, spans, userData);
- else
- blend_untransformed_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_untransformed_argb8555(int count, const QSpan *spans,
- void *userData)
-{
- blend_untransformed_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_untransformed_rgb555(int count, const QSpan *spans,
- void *userData)
-{
- blend_untransformed_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_untransformed_argb4444(int count, const QSpan *spans,
- void *userData)
-{
- blend_untransformed_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_untransformed_rgb444(int count, const QSpan *spans,
- void *userData)
-{
- blend_untransformed_generic<RegularSpans>(count, spans, userData);
-}
-
-template <SpanMethod spanMethod>
-Q_STATIC_TEMPLATE_FUNCTION void blend_tiled_generic(int count, const QSpan *spans, void *userData)
+static void blend_tiled_generic(int count, const QSpan *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
@@ -5034,15 +4168,10 @@ Q_STATIC_TEMPLATE_FUNCTION void blend_tiled_generic(int count, const QSpan *span
if (buffer_size < l)
l = buffer_size;
const uint *src = op.src_fetch(src_buffer, &op, data, sy, sx, l);
- if (spanMethod == RegularSpans) {
- uint *dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer;
- op.func(dest, src, l, coverage);
- if (op.dest_store)
- op.dest_store(data->rasterBuffer, x, spans->y, dest, l);
- } else {
- drawBufferSpan(data, src, l, x, spans->y, l,
- coverage);
- }
+ uint *dest = op.dest_fetch ? op.dest_fetch(buffer, data->rasterBuffer, x, spans->y, l) : buffer;
+ op.func(dest, src, l, coverage);
+ if (op.dest_store)
+ op.dest_store(data->rasterBuffer, x, spans->y, dest, l);
x += l;
sx += l;
length -= l;
@@ -5053,13 +4182,12 @@ Q_STATIC_TEMPLATE_FUNCTION void blend_tiled_generic(int count, const QSpan *span
}
}
-template <SpanMethod spanMethod>
-Q_STATIC_TEMPLATE_FUNCTION void blend_tiled_argb(int count, const QSpan *spans, void *userData)
+static void blend_tiled_argb(int count, const QSpan *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
if (data->texture.format != QImage::Format_ARGB32_Premultiplied
&& data->texture.format != QImage::Format_RGB32) {
- blend_tiled_generic<spanMethod>(count, spans, userData);
+ blend_tiled_generic(count, spans, userData);
return;
}
@@ -5091,13 +4219,8 @@ Q_STATIC_TEMPLATE_FUNCTION void blend_tiled_argb(int count, const QSpan *spans,
if (buffer_size < l)
l = buffer_size;
const uint *src = (uint *)data->texture.scanLine(sy) + sx;
- if (spanMethod == RegularSpans) {
- uint *dest = ((uint *)data->rasterBuffer->scanLine(spans->y)) + x;
- op.func(dest, src, l, coverage);
- } else {
- drawBufferSpan(data, src, buffer_size,
- x, spans->y, l, coverage);
- }
+ uint *dest = ((uint *)data->rasterBuffer->scanLine(spans->y)) + x;
+ op.func(dest, src, l, coverage);
x += l;
length -= l;
sx = 0;
@@ -5106,21 +4229,19 @@ Q_STATIC_TEMPLATE_FUNCTION void blend_tiled_argb(int count, const QSpan *spans,
}
}
-template <class DST, class SRC>
-Q_STATIC_TEMPLATE_FUNCTION void blendTiled(int count, const QSpan *spans, void *userData)
+static void blend_tiled_rgb565(int count, const QSpan *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData*>(userData);
QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
- if (mode != QPainter::CompositionMode_SourceOver &&
- mode != QPainter::CompositionMode_Source)
+ if (data->texture.format != QImage::Format_RGB16
+ || (mode != QPainter::CompositionMode_SourceOver
+ && mode != QPainter::CompositionMode_Source))
{
- blend_src_generic<RegularSpans>(count, spans, userData);
+ blend_tiled_generic(count, spans, userData);
return;
}
- const bool modeSource = !SRC::hasAlpha() ||
- mode == QPainter::CompositionMode_Source;
const int image_width = data->texture.width;
const int image_height = data->texture.height;
int xoff = -qRound(-data->dx) % image_width;
@@ -5147,7 +4268,7 @@ Q_STATIC_TEMPLATE_FUNCTION void blendTiled(int count, const QSpan *spans, void *
if (sy < 0)
sy += image_height;
- if (modeSource && coverage == 255) {
+ if (coverage == 255) {
// Copy the first texture block
length = qMin(image_width,length);
int tx = x;
@@ -5155,10 +4276,9 @@ Q_STATIC_TEMPLATE_FUNCTION void blendTiled(int count, const QSpan *spans, void *
int l = qMin(image_width - sx, length);
if (buffer_size < l)
l = buffer_size;
- DST *dest = ((DST*)data->rasterBuffer->scanLine(spans->y)) + tx;
- const SRC *src = (SRC*)data->texture.scanLine(sy) + sx;
-
- qt_memconvert<DST, SRC>(dest, src, l);
+ quint16 *dest = ((quint16 *)data->rasterBuffer->scanLine(spans->y)) + tx;
+ const quint16 *src = (quint16 *)data->texture.scanLine(sy) + sx;
+ memcpy(dest, src, l * sizeof(quint16));
length -= l;
tx += l;
sx = 0;
@@ -5172,110 +4292,51 @@ Q_STATIC_TEMPLATE_FUNCTION void blendTiled(int count, const QSpan *spans, void *
// - can use memcpy
int copy_image_width = qMin(image_width, int(spans->len));
length = spans->len - copy_image_width;
- DST *src = ((DST*)data->rasterBuffer->scanLine(spans->y)) + x;
- DST *dest = src + copy_image_width;
+ quint16 *src = ((quint16 *)data->rasterBuffer->scanLine(spans->y)) + x;
+ quint16 *dest = src + copy_image_width;
while (copy_image_width < length) {
- qt_memconvert(dest, src, copy_image_width);
+ memcpy(dest, src, copy_image_width * sizeof(quint16));
dest += copy_image_width;
length -= copy_image_width;
copy_image_width *= 2;
}
if (length > 0)
- qt_memconvert(dest, src, length);
+ memcpy(dest, src, length * sizeof(quint16));
} else {
- while (length) {
- int l = qMin(image_width - sx, length);
- if (buffer_size < l)
- l = buffer_size;
- DST *dest = ((DST*)data->rasterBuffer->scanLine(spans->y)) + x;
- const SRC *src = (SRC*)data->texture.scanLine(sy) + sx;
- if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
- (quintptr(dest) & 3) == (quintptr(src) & 3))
- {
- blendUntransformed_dest24(dest, src, coverage, l);
- } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
- (quintptr(dest) & 3) == (quintptr(src) & 3))
- {
- blendUntransformed_dest16(dest, src, coverage, l);
- } else {
- blendUntransformed_unaligned(dest, src, coverage, l);
+ const quint8 alpha = (coverage + 1) >> 3;
+ const quint8 ialpha = 0x20 - alpha;
+ if (alpha > 0) {
+ while (length) {
+ int l = qMin(image_width - sx, length);
+ if (buffer_size < l)
+ l = buffer_size;
+ quint16 *dest = ((quint16 *)data->rasterBuffer->scanLine(spans->y)) + x;
+ const quint16 *src = (quint16 *)data->texture.scanLine(sy) + sx;
+ blend_sourceOver_rgb16_rgb16(dest, src, l, alpha, ialpha);
+ x += l;
+ length -= l;
+ sx = 0;
}
-
- x += l;
- length -= l;
- sx = 0;
}
}
++spans;
}
}
-static void blend_tiled_rgb888(int count, const QSpan *spans, void *userData)
-{
- blend_tiled_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_tiled_argb6666(int count, const QSpan *spans, void *userData)
-{
- blend_tiled_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_tiled_rgb666(int count, const QSpan *spans, void *userData)
-{
- blend_tiled_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_tiled_argb8565(int count, const QSpan *spans, void *userData)
-{
- blend_tiled_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_tiled_rgb565(int count, const QSpan *spans, void *userData)
-{
- QSpanData *data = reinterpret_cast<QSpanData *>(userData);
-
- if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
- blendTiled<qrgb565, qargb8565>(count, spans, userData);
- else if (data->texture.format == QImage::Format_RGB16)
- blendTiled<qrgb565, qrgb565>(count, spans, userData);
- else
- blend_tiled_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_tiled_argb8555(int count, const QSpan *spans, void *userData)
-{
- blend_tiled_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_tiled_rgb555(int count, const QSpan *spans, void *userData)
-{
- blend_tiled_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_tiled_argb4444(int count, const QSpan *spans, void *userData)
-{
- blend_tiled_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_tiled_rgb444(int count, const QSpan *spans, void *userData)
-{
- blend_tiled_generic<RegularSpans>(count, spans, userData);
-}
-
-template <class DST, class SRC>
-Q_STATIC_TEMPLATE_FUNCTION void blendTransformedBilinear(int count, const QSpan *spans,
- void *userData)
+static void blend_transformed_bilinear_rgb565(int count, const QSpan *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData*>(userData);
QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
-
- if (mode != QPainter::CompositionMode_SourceOver) {
- blend_src_generic<RegularSpans>(count, spans, userData);
+ if (data->texture.format != QImage::Format_RGB16
+ || (mode != QPainter::CompositionMode_SourceOver
+ && mode != QPainter::CompositionMode_Source))
+ {
+ blend_src_generic(count, spans, userData);
return;
}
- SRC buffer[buffer_size];
+ quint16 buffer[buffer_size];
const int src_minx = data->texture.x1;
const int src_miny = data->texture.y1;
@@ -5289,13 +4350,14 @@ Q_STATIC_TEMPLATE_FUNCTION void blendTransformedBilinear(int count, const QSpan
while (count--) {
const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
- if (coverage == 0) {
+ const quint8 alpha = (coverage + 1) >> 3;
+ const quint8 ialpha = 0x20 - alpha;
+ if (alpha == 0) {
++spans;
continue;
}
- DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
- + spans->x;
+ quint16 *dest = (quint16 *)data->rasterBuffer->scanLine(spans->y) + spans->x;
const qreal cx = spans->x + qreal(0.5);
const qreal cy = spans->y + qreal(0.5);
int x = int((data->m21 * cy
@@ -5305,84 +4367,58 @@ Q_STATIC_TEMPLATE_FUNCTION void blendTransformedBilinear(int count, const QSpan
int length = spans->len;
while (length) {
- const int l = qMin(length, buffer_size);
+ int l;
+ quint16 *b;
+ if (ialpha == 0) {
+ l = length;
+ b = dest;
+ } else {
+ l = qMin(length, buffer_size);
+ b = buffer;
+ }
+ const quint16 *end = b + l;
- const SRC *end = buffer + l;
- SRC *b = buffer;
while (b < end) {
int x1 = (x >> 16);
int x2;
int y1 = (y >> 16);
int y2;
- const int distx = (x & 0x0000ffff) >> 8;
- const int disty = (y & 0x0000ffff) >> 8;
+ fetchTransformedBilinear_pixelBounds<BlendTransformedBilinear>(0, src_minx, src_maxx, x1, x2);
+ fetchTransformedBilinear_pixelBounds<BlendTransformedBilinear>(0, src_miny, src_maxy, y1, y2);
+
+ const quint16 *src1 = (quint16*)data->texture.scanLine(y1);
+ const quint16 *src2 = (quint16*)data->texture.scanLine(y2);
+ quint16 tl = src1[x1];
+ const quint16 tr = src1[x2];
+ quint16 bl = src2[x1];
+ const quint16 br = src2[x2];
+
+ const uint distxsl8 = x & 0xff00;
+ const uint distysl8 = y & 0xff00;
+ const uint distx = distxsl8 >> 8;
+ const uint disty = distysl8 >> 8;
+ const uint distxy = distx * disty;
+
+ const uint tlw = 0x10000 - distxsl8 - distysl8 + distxy; // (256 - distx) * (256 - disty)
+ const uint trw = distxsl8 - distxy; // distx * (256 - disty)
+ const uint blw = distysl8 - distxy; // (256 - distx) * disty
+ const uint brw = distxy; // distx * disty
+ uint red = ((tl & 0xf800) * tlw + (tr & 0xf800) * trw
+ + (bl & 0xf800) * blw + (br & 0xf800) * brw) & 0xf8000000;
+ uint green = ((tl & 0x07e0) * tlw + (tr & 0x07e0) * trw
+ + (bl & 0x07e0) * blw + (br & 0x07e0) * brw) & 0x07e00000;
+ uint blue = ((tl & 0x001f) * tlw + (tr & 0x001f) * trw
+ + (bl & 0x001f) * blw + (br & 0x001f) * brw);
+ *b = quint16((red | green | blue) >> 16);
- if (x1 < src_minx) {
- x2 = x1 = src_minx;
- } else if (x1 >= src_maxx) {
- x2 = x1 = src_maxx;
- } else {
- x2 = x1 + 1;
- }
- if (y1 < src_miny) {
- y2 = y1 = src_miny;
- } else if (y1 >= src_maxy) {
- y2 = y1 = src_maxy;
- } else {
- y2 = y1 + 1;
- }
-#if 0
- if (x1 == x2) {
- if (y1 == y2) {
- *b = ((SRC*)data->texture.scanLine(y1))[x1];
- } else {
- *b = ((SRC*)data->texture.scanLine(y1))[x1];
- const SRC t = data->texture.scanLine(y2)[x1];
- interpolate_pixel(*b, SRC::ialpha(disty),
- t, SRC::alpha(disty));
- }
- } else if (y1 == y2) {
- *b = ((SRC*)data->texture.scanLine(y1))[x1];
- const SRC t = ((SRC*)data->texture.scanLine(y1))[x2];
- interpolate_pixel(*b, SRC::ialpha(distx),
- t, SRC::alpha(distx));
- } else
-#endif
- {
- const SRC *src1 = (SRC*)data->texture.scanLine(y1);
- const SRC *src2 = (SRC*)data->texture.scanLine(y2);
- SRC tl = src1[x1];
- const SRC tr = src1[x2];
- SRC bl = src2[x1];
- const SRC br = src2[x2];
- const quint8 ax = SRC::alpha(distx);
- const quint8 iax = SRC::ialpha(distx);
-
- interpolate_pixel(tl, iax, tr, ax);
- interpolate_pixel(bl, iax, br, ax);
- interpolate_pixel(tl, SRC::ialpha(disty),
- bl, SRC::alpha(disty));
- *b = tl;
- }
++b;
-
x += fdx;
y += fdy;
}
- if (!SRC::hasAlpha() && coverage == 255) {
- qt_memconvert(dest, buffer, l);
- } else if (sizeof(DST) == 3 && l >= 4 &&
- (quintptr(dest) & 3) == (quintptr(buffer) & 3))
- {
- blendUntransformed_dest24(dest, buffer, coverage, l);
- } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
- (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
- blendUntransformed_dest16(dest, buffer, coverage, l);
- } else {
- blendUntransformed_unaligned(dest, buffer, coverage, l);
- }
+ if (ialpha != 0)
+ blend_sourceOver_rgb16_rgb16(dest, buffer, l, alpha, ialpha);
dest += l;
length -= l;
@@ -5396,13 +4432,14 @@ Q_STATIC_TEMPLATE_FUNCTION void blendTransformedBilinear(int count, const QSpan
while (count--) {
const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
- if (coverage == 0) {
+ const quint8 alpha = (coverage + 1) >> 3;
+ const quint8 ialpha = 0x20 - alpha;
+ if (alpha == 0) {
++spans;
continue;
}
- DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
- + spans->x;
+ quint16 *dest = (quint16 *)data->rasterBuffer->scanLine(spans->y) + spans->x;
const qreal cx = spans->x + qreal(0.5);
const qreal cy = spans->y + qreal(0.5);
@@ -5413,9 +4450,17 @@ Q_STATIC_TEMPLATE_FUNCTION void blendTransformedBilinear(int count, const QSpan
int length = spans->len;
while (length) {
- const int l = qMin(length, buffer_size);
- const SRC *end = buffer + l;
- SRC *b = buffer;
+ int l;
+ quint16 *b;
+ if (ialpha == 0) {
+ l = length;
+ b = dest;
+ } else {
+ l = qMin(length, buffer_size);
+ b = buffer;
+ }
+ const quint16 *end = b + l;
+
while (b < end) {
const qreal iw = w == 0 ? 1 : 1 / w;
const qreal px = x * iw - qreal(0.5);
@@ -5426,56 +4471,42 @@ Q_STATIC_TEMPLATE_FUNCTION void blendTransformedBilinear(int count, const QSpan
int y1 = int(py) - (py < 0);
int y2;
- const int distx = int((px - x1) * 256);
- const int disty = int((py - y1) * 256);
+ fetchTransformedBilinear_pixelBounds<BlendTransformedBilinear>(0, src_minx, src_maxx, x1, x2);
+ fetchTransformedBilinear_pixelBounds<BlendTransformedBilinear>(0, src_miny, src_maxy, y1, y2);
+
+ const quint16 *src1 = (quint16 *)data->texture.scanLine(y1);
+ const quint16 *src2 = (quint16 *)data->texture.scanLine(y2);
+ quint16 tl = src1[x1];
+ const quint16 tr = src1[x2];
+ quint16 bl = src2[x1];
+ const quint16 br = src2[x2];
+
+ const uint distx = uint((px - x1) * 256);
+ const uint disty = uint((py - y1) * 256);
+ const uint distxsl8 = distx << 8;
+ const uint distysl8 = disty << 8;
+ const uint distxy = distx * disty;
+
+ const uint tlw = 0x10000 - distxsl8 - distysl8 + distxy; // (256 - distx) * (256 - disty)
+ const uint trw = distxsl8 - distxy; // distx * (256 - disty)
+ const uint blw = distysl8 - distxy; // (256 - distx) * disty
+ const uint brw = distxy; // distx * disty
+ uint red = ((tl & 0xf800) * tlw + (tr & 0xf800) * trw
+ + (bl & 0xf800) * blw + (br & 0xf800) * brw) & 0xf8000000;
+ uint green = ((tl & 0x07e0) * tlw + (tr & 0x07e0) * trw
+ + (bl & 0x07e0) * blw + (br & 0x07e0) * brw) & 0x07e00000;
+ uint blue = ((tl & 0x001f) * tlw + (tr & 0x001f) * trw
+ + (bl & 0x001f) * blw + (br & 0x001f) * brw);
+ *b = quint16((red | green | blue) >> 16);
- if (x1 < src_minx) {
- x2 = x1 = src_minx;
- } else if (x1 >= src_maxx) {
- x2 = x1 = src_maxx;
- } else {
- x2 = x1 + 1;
- }
- if (y1 < src_miny) {
- y2 = y1 = src_miny;
- } else if (y1 >= src_maxy) {
- y2 = y1 = src_maxy;
- } else {
- y2 = y1 + 1;
- }
-
- const SRC *src1 = (SRC*)data->texture.scanLine(y1);
- const SRC *src2 = (SRC*)data->texture.scanLine(y2);
- SRC tl = src1[x1];
- const SRC tr = src1[x2];
- SRC bl = src2[x1];
- const SRC br = src2[x2];
- const quint8 ax = SRC::alpha(distx);
- const quint8 iax = SRC::ialpha(distx);
-
- interpolate_pixel(tl, iax, tr, ax);
- interpolate_pixel(bl, iax, br, ax);
- interpolate_pixel(tl, SRC::ialpha(disty),
- bl, SRC::alpha(disty));
- *b = tl;
++b;
-
x += fdx;
y += fdy;
w += fdw;
}
- if (!SRC::hasAlpha() && coverage == 255) {
- qt_memconvert(dest, buffer, l);
- } else if (sizeof(DST) == 3 && l >= 4 &&
- (quintptr(dest) & 3) == (quintptr(buffer) & 3))
- {
- blendUntransformed_dest24(dest, buffer, coverage, l);
- } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
- (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
- blendUntransformed_dest16(dest, buffer, coverage, l);
- } else {
- blendUntransformed_unaligned(dest, buffer, coverage, l);
- }
+
+ if (ialpha != 0)
+ blend_sourceOver_rgb16_rgb16(dest, buffer, l, alpha, ialpha);
dest += l;
length -= l;
@@ -5485,66 +4516,12 @@ Q_STATIC_TEMPLATE_FUNCTION void blendTransformedBilinear(int count, const QSpan
}
}
-static void blend_transformed_bilinear_rgb888(int count, const QSpan *spans, void *userData)
-{
- blend_src_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_transformed_bilinear_argb6666(int count, const QSpan *spans, void *userData)
-{
- blend_src_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_transformed_bilinear_rgb666(int count, const QSpan *spans, void *userData)
-{
- blend_src_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_transformed_bilinear_argb8565(int count, const QSpan *spans, void *userData)
-{
- blend_src_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_transformed_bilinear_rgb565(int count, const QSpan *spans,
- void *userData)
-{
- QSpanData *data = reinterpret_cast<QSpanData *>(userData);
-
- if (data->texture.format == QImage::Format_RGB16)
- blendTransformedBilinear<qrgb565, qrgb565>(count, spans, userData);
- else if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
- blendTransformedBilinear<qrgb565, qargb8565>(count, spans, userData);
- else
- blend_src_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_transformed_bilinear_argb8555(int count, const QSpan *spans, void *userData)
-{
- blend_src_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_transformed_bilinear_rgb555(int count, const QSpan *spans, void *userData)
-{
- blend_src_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_transformed_bilinear_argb4444(int count, const QSpan *spans, void *userData)
-{
- blend_src_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_transformed_bilinear_rgb444(int count, const QSpan *spans, void *userData)
-{
- blend_src_generic<RegularSpans>(count, spans, userData);
-}
-
-template <SpanMethod spanMethod>
-Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_argb(int count, const QSpan *spans, void *userData)
+static void blend_transformed_argb(int count, const QSpan *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
if (data->texture.format != QImage::Format_ARGB32_Premultiplied
&& data->texture.format != QImage::Format_RGB32) {
- blend_src_generic<spanMethod>(count, spans, userData);
+ blend_src_generic(count, spans, userData);
return;
}
@@ -5553,7 +4530,6 @@ Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_argb(int count, const QSpan *s
int image_width = data->texture.width;
int image_height = data->texture.height;
- const int scanline_offset = data->texture.bytesPerLine / 4;
if (data->fast_matrix) {
// The increment pr x in the scanline
@@ -5564,7 +4540,6 @@ Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_argb(int count, const QSpan *s
void *t = data->rasterBuffer->scanLine(spans->y);
uint *target = ((uint *)t) + spans->x;
- uint *image_bits = (uint *)data->texture.imageData;
const qreal cx = spans->x + qreal(0.5);
const qreal cy = spans->y + qreal(0.5);
@@ -5581,24 +4556,15 @@ Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_argb(int count, const QSpan *s
const uint *end = buffer + l;
uint *b = buffer;
while (b < end) {
- int px = x >> 16;
- int py = y >> 16;
-
- bool out = (px < 0) || (px >= image_width)
- || (py < 0) || (py >= image_height);
+ int px = qBound(0, x >> 16, image_width - 1);
+ int py = qBound(0, y >> 16, image_height - 1);
+ *b = reinterpret_cast<const uint *>(data->texture.scanLine(py))[px];
- int y_offset = py * scanline_offset;
- *b = out ? uint(0) : image_bits[y_offset + px];
x += fdx;
y += fdy;
++b;
}
- if (spanMethod == RegularSpans)
- func(target, buffer, l, coverage);
- else
- drawBufferSpan(data, buffer, buffer_size,
- spans->x + spans->len - length,
- spans->y, l, coverage);
+ func(target, buffer, l, coverage);
target += l;
length -= l;
}
@@ -5612,7 +4578,6 @@ Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_argb(int count, const QSpan *s
void *t = data->rasterBuffer->scanLine(spans->y);
uint *target = ((uint *)t) + spans->x;
- uint *image_bits = (uint *)data->texture.imageData;
const qreal cx = spans->x + qreal(0.5);
const qreal cy = spans->y + qreal(0.5);
@@ -5631,26 +4596,17 @@ Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_argb(int count, const QSpan *s
const qreal iw = w == 0 ? 1 : 1 / w;
const qreal tx = x * iw;
const qreal ty = y * iw;
- const int px = int(tx) - (tx < 0);
- const int py = int(ty) - (ty < 0);
+ const int px = qBound(0, int(tx) - (tx < 0), image_width - 1);
+ const int py = qBound(0, int(ty) - (ty < 0), image_height - 1);
- bool out = (px < 0) || (px >= image_width)
- || (py < 0) || (py >= image_height);
-
- int y_offset = py * scanline_offset;
- *b = out ? uint(0) : image_bits[y_offset + px];
+ *b = reinterpret_cast<const uint *>(data->texture.scanLine(py))[px];
x += fdx;
y += fdy;
w += fdw;
++b;
}
- if (spanMethod == RegularSpans)
- func(target, buffer, l, coverage);
- else
- drawBufferSpan(data, buffer, buffer_size,
- spans->x + spans->len - length,
- spans->y, l, coverage);
+ func(target, buffer, l, coverage);
target += l;
length -= l;
}
@@ -5659,18 +4615,20 @@ Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_argb(int count, const QSpan *s
}
}
-template <class DST, class SRC>
-Q_STATIC_TEMPLATE_FUNCTION void blendTransformed(int count, const QSpan *spans, void *userData)
+static void blend_transformed_rgb565(int count, const QSpan *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData*>(userData);
QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
- if (mode != QPainter::CompositionMode_SourceOver) {
- blend_src_generic<RegularSpans>(count, spans, userData);
+ if (data->texture.format != QImage::Format_RGB16
+ || (mode != QPainter::CompositionMode_SourceOver
+ && mode != QPainter::CompositionMode_Source))
+ {
+ blend_src_generic(count, spans, userData);
return;
}
- SRC buffer[buffer_size];
+ quint16 buffer[buffer_size];
const int image_width = data->texture.width;
const int image_height = data->texture.height;
@@ -5681,13 +4639,14 @@ Q_STATIC_TEMPLATE_FUNCTION void blendTransformed(int count, const QSpan *spans,
while (count--) {
const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
- if (coverage == 0) {
+ const quint8 alpha = (coverage + 1) >> 3;
+ const quint8 ialpha = 0x20 - alpha;
+ if (alpha == 0) {
++spans;
continue;
}
- DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
- + spans->x;
+ quint16 *dest = (quint16 *)data->rasterBuffer->scanLine(spans->y) + spans->x;
const qreal cx = spans->x + qreal(0.5);
const qreal cy = spans->y + qreal(0.5);
int x = int((data->m21 * cy
@@ -5697,39 +4656,30 @@ Q_STATIC_TEMPLATE_FUNCTION void blendTransformed(int count, const QSpan *spans,
int length = spans->len;
while (length) {
- const int l = qMin(length, buffer_size);
+ int l;
+ quint16 *b;
+ if (ialpha == 0) {
+ l = length;
+ b = dest;
+ } else {
+ l = qMin(length, buffer_size);
+ b = buffer;
+ }
+ const quint16 *end = b + l;
- const SRC *end = buffer + l;
- SRC *b = buffer;
while (b < end) {
- const int px = (x >> 16);
- const int py = (y >> 16);
+ const int px = qBound(0, x >> 16, image_width - 1);
+ const int py = qBound(0, y >> 16, image_height - 1);
- if ((px < 0) || (px >= image_width) ||
- (py < 0) || (py >= image_height))
- {
- *b = 0;
- } else {
- *b = ((SRC*)data->texture.scanLine(py))[px];
- }
+ *b = ((quint16 *)data->texture.scanLine(py))[px];
++b;
x += fdx;
y += fdy;
}
- if (!SRC::hasAlpha() && coverage == 255) {
- qt_memconvert(dest, buffer, l);
- } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
- (quintptr(dest) & 3) == (quintptr(buffer) & 3))
- {
- blendUntransformed_dest24(dest, buffer, coverage, l);
- } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
- (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
- blendUntransformed_dest16(dest, buffer, coverage, l);
- } else {
- blendUntransformed_unaligned(dest, buffer, coverage, l);
- }
+ if (ialpha != 0)
+ blend_sourceOver_rgb16_rgb16(dest, buffer, l, alpha, ialpha);
dest += l;
length -= l;
@@ -5743,13 +4693,14 @@ Q_STATIC_TEMPLATE_FUNCTION void blendTransformed(int count, const QSpan *spans,
while (count--) {
const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
- if (coverage == 0) {
+ const quint8 alpha = (coverage + 1) >> 3;
+ const quint8 ialpha = 0x20 - alpha;
+ if (alpha == 0) {
++spans;
continue;
}
- DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
- + spans->x;
+ quint16 *dest = (quint16 *)data->rasterBuffer->scanLine(spans->y) + spans->x;
const qreal cx = spans->x + qreal(0.5);
const qreal cy = spans->y + qreal(0.5);
@@ -5760,42 +4711,35 @@ Q_STATIC_TEMPLATE_FUNCTION void blendTransformed(int count, const QSpan *spans,
int length = spans->len;
while (length) {
- const int l = qMin(length, buffer_size);
- const SRC *end = buffer + l;
- SRC *b = buffer;
+ int l;
+ quint16 *b;
+ if (ialpha == 0) {
+ l = length;
+ b = dest;
+ } else {
+ l = qMin(length, buffer_size);
+ b = buffer;
+ }
+ const quint16 *end = b + l;
+
while (b < end) {
const qreal iw = w == 0 ? 1 : 1 / w;
const qreal tx = x * iw;
const qreal ty = y * iw;
- const int px = int(tx) - (tx < 0);
- const int py = int(ty) - (ty < 0);
+ const int px = qBound(0, int(tx) - (tx < 0), image_width - 1);
+ const int py = qBound(0, int(ty) - (ty < 0), image_height - 1);
- if ((px < 0) || (px >= image_width) ||
- (py < 0) || (py >= image_height))
- {
- *b = 0;
- } else {
- *b = ((SRC*)data->texture.scanLine(py))[px];
- }
+ *b = ((quint16 *)data->texture.scanLine(py))[px];
++b;
x += fdx;
y += fdy;
w += fdw;
}
- if (!SRC::hasAlpha() && coverage == 255) {
- qt_memconvert(dest, buffer, l);
- } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
- (quintptr(dest) & 3) == (quintptr(buffer) & 3))
- {
- blendUntransformed_dest24(dest, buffer, coverage, l);
- } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
- (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
- blendUntransformed_dest16(dest, buffer, coverage, l);
- } else {
- blendUntransformed_unaligned(dest, buffer, coverage, l);
- }
+
+ if (ialpha != 0)
+ blend_sourceOver_rgb16_rgb16(dest, buffer, l, alpha, ialpha);
dest += l;
length -= l;
@@ -5805,74 +4749,12 @@ Q_STATIC_TEMPLATE_FUNCTION void blendTransformed(int count, const QSpan *spans,
}
}
-static void blend_transformed_rgb888(int count, const QSpan *spans,
- void *userData)
-{
- blend_src_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_transformed_argb6666(int count, const QSpan *spans,
- void *userData)
-{
- blend_src_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_transformed_rgb666(int count, const QSpan *spans,
- void *userData)
-{
- blend_src_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_transformed_argb8565(int count, const QSpan *spans,
- void *userData)
-{
- blend_src_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_transformed_rgb565(int count, const QSpan *spans,
- void *userData)
-{
- QSpanData *data = reinterpret_cast<QSpanData *>(userData);
-
- if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
- blendTransformed<qrgb565, qargb8565>(count, spans, userData);
- else if (data->texture.format == QImage::Format_RGB16)
- blendTransformed<qrgb565, qrgb565>(count, spans, userData);
- else
- blend_src_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_transformed_argb8555(int count, const QSpan *spans,
- void *userData)
-{
- blend_src_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_transformed_rgb555(int count, const QSpan *spans,
- void *userData)
-{
- blend_src_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_transformed_argb4444(int count, const QSpan *spans,
- void *userData)
-{
- blend_src_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_transformed_rgb444(int count, const QSpan *spans,
- void *userData)
-{
- blend_src_generic<RegularSpans>(count, spans, userData);
-}
-
-template <SpanMethod spanMethod>
-Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_tiled_argb(int count, const QSpan *spans, void *userData)
+static void blend_transformed_tiled_argb(int count, const QSpan *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData *>(userData);
if (data->texture.format != QImage::Format_ARGB32_Premultiplied
&& data->texture.format != QImage::Format_RGB32) {
- blend_src_generic<spanMethod>(count, spans, userData);
+ blend_src_generic(count, spans, userData);
return;
}
@@ -5925,12 +4807,7 @@ Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_tiled_argb(int count, const QS
y += fdy;
++b;
}
- if (spanMethod == RegularSpans)
- func(target, buffer, l, coverage);
- else
- drawBufferSpan(data, buffer, buffer_size,
- spans->x + spans->len - length,
- spans->y, l, coverage);
+ func(target, buffer, l, coverage);
target += l;
length -= l;
}
@@ -5985,12 +4862,7 @@ Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_tiled_argb(int count, const QS
}
++b;
}
- if (spanMethod == RegularSpans)
- func(target, buffer, l, coverage);
- else
- drawBufferSpan(data, buffer, buffer_size,
- spans->x + spans->len - length,
- spans->y, l, coverage);
+ func(target, buffer, l, coverage);
target += l;
length -= l;
}
@@ -5999,18 +4871,20 @@ Q_STATIC_TEMPLATE_FUNCTION void blend_transformed_tiled_argb(int count, const QS
}
}
-template <class DST, class SRC>
-Q_STATIC_TEMPLATE_FUNCTION void blendTransformedTiled(int count, const QSpan *spans, void *userData)
+static void blend_transformed_tiled_rgb565(int count, const QSpan *spans, void *userData)
{
QSpanData *data = reinterpret_cast<QSpanData*>(userData);
QPainter::CompositionMode mode = data->rasterBuffer->compositionMode;
- if (mode != QPainter::CompositionMode_SourceOver) {
- blend_src_generic<RegularSpans>(count, spans, userData);
+ if (data->texture.format != QImage::Format_RGB16
+ || (mode != QPainter::CompositionMode_SourceOver
+ && mode != QPainter::CompositionMode_Source))
+ {
+ blend_src_generic(count, spans, userData);
return;
}
- SRC buffer[buffer_size];
+ quint16 buffer[buffer_size];
const int image_width = data->texture.width;
const int image_height = data->texture.height;
@@ -6021,13 +4895,14 @@ Q_STATIC_TEMPLATE_FUNCTION void blendTransformedTiled(int count, const QSpan *sp
while (count--) {
const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
- if (coverage == 0) {
+ const quint8 alpha = (coverage + 1) >> 3;
+ const quint8 ialpha = 0x20 - alpha;
+ if (alpha == 0) {
++spans;
continue;
}
- DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
- + spans->x;
+ quint16 *dest = (quint16 *)data->rasterBuffer->scanLine(spans->y) + spans->x;
const qreal cx = spans->x + qreal(0.5);
const qreal cy = spans->y + qreal(0.5);
int x = int((data->m21 * cy
@@ -6037,10 +4912,17 @@ Q_STATIC_TEMPLATE_FUNCTION void blendTransformedTiled(int count, const QSpan *sp
int length = spans->len;
while (length) {
- const int l = qMin(length, buffer_size);
+ int l;
+ quint16 *b;
+ if (ialpha == 0) {
+ l = length;
+ b = dest;
+ } else {
+ l = qMin(length, buffer_size);
+ b = buffer;
+ }
+ const quint16 *end = b + l;
- const SRC *end = buffer + l;
- SRC *b = buffer;
while (b < end) {
int px = (x >> 16) % image_width;
int py = (y >> 16) % image_height;
@@ -6050,25 +4932,15 @@ Q_STATIC_TEMPLATE_FUNCTION void blendTransformedTiled(int count, const QSpan *sp
if (py < 0)
py += image_height;
- *b = ((SRC*)data->texture.scanLine(py))[px];
+ *b = ((quint16 *)data->texture.scanLine(py))[px];
++b;
x += fdx;
y += fdy;
}
- if (!SRC::hasAlpha() && coverage == 255) {
- qt_memconvert(dest, buffer, l);
- } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
- (quintptr(dest) & 3) == (quintptr(buffer) & 3))
- {
- blendUntransformed_dest24(dest, buffer, coverage, l);
- } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
- (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
- blendUntransformed_dest16(dest, buffer, coverage, l);
- } else {
- blendUntransformed_unaligned(dest, buffer, coverage, l);
- }
+ if (ialpha != 0)
+ blend_sourceOver_rgb16_rgb16(dest, buffer, l, alpha, ialpha);
dest += l;
length -= l;
@@ -6082,13 +4954,14 @@ Q_STATIC_TEMPLATE_FUNCTION void blendTransformedTiled(int count, const QSpan *sp
while (count--) {
const quint8 coverage = (data->texture.const_alpha * spans->coverage) >> 8;
- if (coverage == 0) {
+ const quint8 alpha = (coverage + 1) >> 3;
+ const quint8 ialpha = 0x20 - alpha;
+ if (alpha == 0) {
++spans;
continue;
}
- DST *dest = (DST*)data->rasterBuffer->scanLine(spans->y)
- + spans->x;
+ quint16 *dest = (quint16 *)data->rasterBuffer->scanLine(spans->y) + spans->x;
const qreal cx = spans->x + qreal(0.5);
const qreal cy = spans->y + qreal(0.5);
@@ -6099,9 +4972,17 @@ Q_STATIC_TEMPLATE_FUNCTION void blendTransformedTiled(int count, const QSpan *sp
int length = spans->len;
while (length) {
- const int l = qMin(length, buffer_size);
- const SRC *end = buffer + l;
- SRC *b = buffer;
+ int l;
+ quint16 *b;
+ if (ialpha == 0) {
+ l = length;
+ b = dest;
+ } else {
+ l = qMin(length, buffer_size);
+ b = buffer;
+ }
+ const quint16 *end = b + l;
+
while (b < end) {
const qreal iw = w == 0 ? 1 : 1 / w;
const qreal tx = x * iw;
@@ -6117,7 +4998,7 @@ Q_STATIC_TEMPLATE_FUNCTION void blendTransformedTiled(int count, const QSpan *sp
if (py < 0)
py += image_height;
- *b = ((SRC*)data->texture.scanLine(py))[px];
+ *b = ((quint16 *)data->texture.scanLine(py))[px];
++b;
x += fdx;
@@ -6127,18 +5008,9 @@ Q_STATIC_TEMPLATE_FUNCTION void blendTransformedTiled(int count, const QSpan *sp
if (!w)
w += fdw;
}
- if (!SRC::hasAlpha() && coverage == 255) {
- qt_memconvert(dest, buffer, l);
- } else if (sizeof(DST) == 3 && sizeof(SRC) == 3 && l >= 4 &&
- (quintptr(dest) & 3) == (quintptr(buffer) & 3))
- {
- blendUntransformed_dest24(dest, buffer, coverage, l);
- } else if (sizeof(DST) == 2 && sizeof(SRC) == 2 && l >= 2 &&
- (quintptr(dest) & 3) == (quintptr(buffer) & 3)) {
- blendUntransformed_dest16(dest, buffer, coverage, l);
- } else {
- blendUntransformed_unaligned(dest, buffer, coverage, l);
- }
+
+ if (ialpha != 0)
+ blend_sourceOver_rgb16_rgb16(dest, buffer, l, alpha, ialpha);
dest += l;
length -= l;
@@ -6148,185 +5020,122 @@ Q_STATIC_TEMPLATE_FUNCTION void blendTransformedTiled(int count, const QSpan *sp
}
}
-static void blend_transformed_tiled_rgb888(int count, const QSpan *spans,
- void *userData)
-{
- blend_src_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_transformed_tiled_argb6666(int count, const QSpan *spans,
- void *userData)
-{
- blend_src_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_transformed_tiled_rgb666(int count, const QSpan *spans,
- void *userData)
-{
- blend_src_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_transformed_tiled_argb8565(int count, const QSpan *spans,
- void *userData)
-{
- blend_src_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_transformed_tiled_rgb565(int count, const QSpan *spans,
- void *userData)
-{
- QSpanData *data = reinterpret_cast<QSpanData *>(userData);
-
- if (data->texture.format == QImage::Format_ARGB8565_Premultiplied)
- blendTransformedTiled<qrgb565, qargb8565>(count, spans, userData);
- else if (data->texture.format == QImage::Format_RGB16)
- blendTransformedTiled<qrgb565, qrgb565>(count, spans, userData);
- else
- blend_src_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_transformed_tiled_argb8555(int count, const QSpan *spans,
- void *userData)
-{
- blend_src_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_transformed_tiled_rgb555(int count, const QSpan *spans,
- void *userData)
-{
- blend_src_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_transformed_tiled_argb4444(int count, const QSpan *spans,
- void *userData)
-{
- blend_src_generic<RegularSpans>(count, spans, userData);
-}
-
-static void blend_transformed_tiled_rgb444(int count, const QSpan *spans,
- void *userData)
-{
- blend_src_generic<RegularSpans>(count, spans, userData);
-}
-
-# define SPANFUNC_POINTER(Name, Arg) Name<Arg>
-
/* Image formats here are target formats */
static const ProcessSpans processTextureSpans[NBlendTypes][QImage::NImageFormats] = {
// Untransformed
{
0, // Invalid
- SPANFUNC_POINTER(blend_untransformed_generic, RegularSpans), // Mono
- SPANFUNC_POINTER(blend_untransformed_generic, RegularSpans), // MonoLsb
- SPANFUNC_POINTER(blend_untransformed_generic, RegularSpans), // Indexed8
- SPANFUNC_POINTER(blend_untransformed_generic, RegularSpans), // RGB32
- SPANFUNC_POINTER(blend_untransformed_generic, RegularSpans), // ARGB32
- SPANFUNC_POINTER(blend_untransformed_argb, RegularSpans), // ARGB32_Premultiplied
+ blend_untransformed_generic, // Mono
+ blend_untransformed_generic, // MonoLsb
+ blend_untransformed_generic, // Indexed8
+ blend_untransformed_generic, // RGB32
+ blend_untransformed_generic, // ARGB32
+ blend_untransformed_argb, // ARGB32_Premultiplied
blend_untransformed_rgb565,
- blend_untransformed_argb8565,
- blend_untransformed_rgb666,
- blend_untransformed_argb6666,
- blend_untransformed_rgb555,
- blend_untransformed_argb8555,
- blend_untransformed_rgb888,
- blend_untransformed_rgb444,
- blend_untransformed_argb4444,
+ blend_untransformed_generic,
+ blend_untransformed_generic,
+ blend_untransformed_generic,
+ blend_untransformed_generic,
+ blend_untransformed_generic,
+ blend_untransformed_generic,
+ blend_untransformed_generic,
+ blend_untransformed_generic,
},
// Tiled
{
0, // Invalid
- SPANFUNC_POINTER(blend_tiled_generic, RegularSpans), // Mono
- SPANFUNC_POINTER(blend_tiled_generic, RegularSpans), // MonoLsb
- SPANFUNC_POINTER(blend_tiled_generic, RegularSpans), // Indexed8
- SPANFUNC_POINTER(blend_tiled_generic, RegularSpans), // RGB32
- SPANFUNC_POINTER(blend_tiled_generic, RegularSpans), // ARGB32
- SPANFUNC_POINTER(blend_tiled_argb, RegularSpans), // ARGB32_Premultiplied
+ blend_tiled_generic, // Mono
+ blend_tiled_generic, // MonoLsb
+ blend_tiled_generic, // Indexed8
+ blend_tiled_generic, // RGB32
+ blend_tiled_generic, // ARGB32
+ blend_tiled_argb, // ARGB32_Premultiplied
blend_tiled_rgb565,
- blend_tiled_argb8565,
- blend_tiled_rgb666,
- blend_tiled_argb6666,
- blend_tiled_rgb555,
- blend_tiled_argb8555,
- blend_tiled_rgb888,
- blend_tiled_rgb444,
- blend_tiled_argb4444,
+ blend_tiled_generic,
+ blend_tiled_generic,
+ blend_tiled_generic,
+ blend_tiled_generic,
+ blend_tiled_generic,
+ blend_tiled_generic,
+ blend_tiled_generic,
+ blend_tiled_generic,
},
// Transformed
{
0, // Invalid
- SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Mono
- SPANFUNC_POINTER(blend_src_generic, RegularSpans), // MonoLsb
- SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Indexed8
- SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB32
- SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32
- SPANFUNC_POINTER(blend_transformed_argb, RegularSpans), // ARGB32_Premultiplied
+ blend_src_generic, // Mono
+ blend_src_generic, // MonoLsb
+ blend_src_generic, // Indexed8
+ blend_src_generic, // RGB32
+ blend_src_generic, // ARGB32
+ blend_transformed_argb, // ARGB32_Premultiplied
blend_transformed_rgb565,
- blend_transformed_argb8565,
- blend_transformed_rgb666,
- blend_transformed_argb6666,
- blend_transformed_rgb555,
- blend_transformed_argb8555,
- blend_transformed_rgb888,
- blend_transformed_rgb444,
- blend_transformed_argb4444,
+ blend_src_generic,
+ blend_src_generic,
+ blend_src_generic,
+ blend_src_generic,
+ blend_src_generic,
+ blend_src_generic,
+ blend_src_generic,
+ blend_src_generic,
},
// TransformedTiled
{
0,
- SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Mono
- SPANFUNC_POINTER(blend_src_generic, RegularSpans), // MonoLsb
- SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Indexed8
- SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB32
- SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32
- SPANFUNC_POINTER(blend_transformed_tiled_argb, RegularSpans), // ARGB32_Premultiplied
+ blend_src_generic, // Mono
+ blend_src_generic, // MonoLsb
+ blend_src_generic, // Indexed8
+ blend_src_generic, // RGB32
+ blend_src_generic, // ARGB32
+ blend_transformed_tiled_argb, // ARGB32_Premultiplied
blend_transformed_tiled_rgb565,
- blend_transformed_tiled_argb8565,
- blend_transformed_tiled_rgb666,
- blend_transformed_tiled_argb6666,
- blend_transformed_tiled_rgb555,
- blend_transformed_tiled_argb8555,
- blend_transformed_tiled_rgb888,
- blend_transformed_tiled_rgb444,
- blend_transformed_tiled_argb4444
+ blend_src_generic,
+ blend_src_generic,
+ blend_src_generic,
+ blend_src_generic,
+ blend_src_generic,
+ blend_src_generic,
+ blend_src_generic,
+ blend_src_generic
},
// Bilinear
{
0,
- SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Mono
- SPANFUNC_POINTER(blend_src_generic, RegularSpans), // MonoLsb
- SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Indexed8
- SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB32
- SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32
- SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32_Premultiplied
+ blend_src_generic, // Mono
+ blend_src_generic, // MonoLsb
+ blend_src_generic, // Indexed8
+ blend_src_generic, // RGB32
+ blend_src_generic, // ARGB32
+ blend_src_generic, // ARGB32_Premultiplied
blend_transformed_bilinear_rgb565,
- blend_transformed_bilinear_argb8565,
- blend_transformed_bilinear_rgb666,
- blend_transformed_bilinear_argb6666,
- blend_transformed_bilinear_rgb555,
- blend_transformed_bilinear_argb8555,
- blend_transformed_bilinear_rgb888,
- blend_transformed_bilinear_rgb444,
- blend_transformed_bilinear_argb4444,
+ blend_src_generic,
+ blend_src_generic,
+ blend_src_generic,
+ blend_src_generic,
+ blend_src_generic,
+ blend_src_generic,
+ blend_src_generic,
+ blend_src_generic,
},
// BilinearTiled
{
0,
- SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Mono
- SPANFUNC_POINTER(blend_src_generic, RegularSpans), // MonoLsb
- SPANFUNC_POINTER(blend_src_generic, RegularSpans), // Indexed8
- SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB32
- SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32
- SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB32_Premultiplied
- SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB16
- SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB8565_Premultiplied
- SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB666
- SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB6666_Premultiplied
- SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB555
- SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB8555_Premultiplied
- SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB888
- SPANFUNC_POINTER(blend_src_generic, RegularSpans), // RGB444
- SPANFUNC_POINTER(blend_src_generic, RegularSpans), // ARGB4444_Premultiplied
+ blend_src_generic, // Mono
+ blend_src_generic, // MonoLsb
+ blend_src_generic, // Indexed8
+ blend_src_generic, // RGB32
+ blend_src_generic, // ARGB32
+ blend_src_generic, // ARGB32_Premultiplied
+ blend_src_generic, // RGB16
+ blend_src_generic, // ARGB8565_Premultiplied
+ blend_src_generic, // RGB666
+ blend_src_generic, // ARGB6666_Premultiplied
+ blend_src_generic, // RGB555
+ blend_src_generic, // ARGB8555_Premultiplied
+ blend_src_generic, // RGB888
+ blend_src_generic, // RGB444
+ blend_src_generic, // ARGB4444_Premultiplied
}
};
@@ -6339,14 +5148,11 @@ void qBlendTexture(int count, const QSpan *spans, void *userData)
template <class DST>
inline void qt_bitmapblit_template(QRasterBuffer *rasterBuffer,
- int x, int y, quint32 color,
+ int x, int y, DST color,
const uchar *map,
- int mapWidth, int mapHeight, int mapStride,
- DST dummy = 0)
+ int mapWidth, int mapHeight, int mapStride)
{
- Q_UNUSED(dummy);
- const DST c = qt_colorConvert<DST, quint32>(color, 0);
- DST *dest = reinterpret_cast<DST*>(rasterBuffer->scanLine(y)) + x;
+ DST *dest = reinterpret_cast<DST *>(rasterBuffer->scanLine(y)) + x;
const int destStride = rasterBuffer->bytesPerLine() / sizeof(DST);
if (mapWidth > 8) {
@@ -6360,7 +5166,7 @@ inline void qt_bitmapblit_template(QRasterBuffer *rasterBuffer,
++n;
} else {
if (n) {
- qt_memfill(dest + x0, c, n);
+ qt_memfill(dest + x0, color, n);
x0 += n + 1;
n = 0;
} else {
@@ -6375,7 +5181,7 @@ inline void qt_bitmapblit_template(QRasterBuffer *rasterBuffer,
}
}
if (n)
- qt_memfill(dest + x0, c, n);
+ qt_memfill(dest + x0, color, n);
dest += destStride;
map += mapStride;
}
@@ -6387,7 +5193,7 @@ inline void qt_bitmapblit_template(QRasterBuffer *rasterBuffer,
if (s & 0x80) {
++n;
} else if (n) {
- qt_memfill(dest + x0, c, n);
+ qt_memfill(dest + x0, color, n);
x0 += n + 1;
n = 0;
} else {
@@ -6395,7 +5201,7 @@ inline void qt_bitmapblit_template(QRasterBuffer *rasterBuffer,
}
}
if (n)
- qt_memfill(dest + x0, c, n);
+ qt_memfill(dest + x0, color, n);
dest += destStride;
map += mapStride;
}
@@ -6448,7 +5254,7 @@ static void qt_gradient_quint32(int count, const QSpan *spans, void *userData)
}
} else {
- blend_src_generic<RegularSpans>(count, spans, userData);
+ blend_src_generic(count, spans, userData);
}
}
@@ -6496,7 +5302,7 @@ static void qt_gradient_quint16(int count, const QSpan *spans, void *userData)
data->solid.color = oldColor;
} else {
- blend_src_generic<RegularSpans>(count, spans, userData);
+ blend_src_generic(count, spans, userData);
}
}
@@ -6514,7 +5320,7 @@ inline static void qt_bitmapblit_quint16(QRasterBuffer *rasterBuffer,
const uchar *map,
int mapWidth, int mapHeight, int mapStride)
{
- qt_bitmapblit_template<quint16>(rasterBuffer, x, y, color,
+ qt_bitmapblit_template<quint16>(rasterBuffer, x, y, qConvertRgb32To16(color),
map, mapWidth, mapHeight, mapStride);
}
@@ -6572,7 +5378,7 @@ static void qt_alphamapblit_quint16(QRasterBuffer *rasterBuffer,
int mapWidth, int mapHeight, int mapStride,
const QClipData *)
{
- const quint16 c = qt_colorConvert<quint16, quint32>(color, 0);
+ const quint16 c = qConvertRgb32To16(color);
quint16 *dest = reinterpret_cast<quint16*>(rasterBuffer->scanLine(y)) + x;
const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint16);
@@ -6838,41 +5644,25 @@ static void qt_alphargbblit_quint32(QRasterBuffer *rasterBuffer,
}
}
-template <class T>
-inline void qt_rectfill_template(QRasterBuffer *rasterBuffer,
- int x, int y, int width, int height,
- quint32 color, T dummy = 0)
+static void qt_rectfill_quint32(QRasterBuffer *rasterBuffer,
+ int x, int y, int width, int height,
+ quint32 color)
{
- Q_UNUSED(dummy);
-
- qt_rectfill<T>(reinterpret_cast<T*>(rasterBuffer->buffer()),
- qt_colorConvert<T, quint32p>(quint32p::fromRawData(color), 0),
- x, y, width, height, rasterBuffer->bytesPerLine());
+ qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()),
+ color, x, y, width, height, rasterBuffer->bytesPerLine());
}
-#define QT_RECTFILL(T) \
- inline static void qt_rectfill_##T(QRasterBuffer *rasterBuffer, \
- int x, int y, int width, int height, \
- quint32 color) \
- { \
- qt_rectfill_template<T>(rasterBuffer, x, y, width, height, color); \
- }
-
-QT_RECTFILL(quint32)
-QT_RECTFILL(quint16)
-QT_RECTFILL(qargb8565)
-QT_RECTFILL(qrgb666)
-QT_RECTFILL(qargb6666)
-QT_RECTFILL(qrgb555)
-QT_RECTFILL(qargb8555)
-QT_RECTFILL(qrgb888)
-QT_RECTFILL(qrgb444)
-QT_RECTFILL(qargb4444)
-#undef QT_RECTFILL
+static void qt_rectfill_quint16(QRasterBuffer *rasterBuffer,
+ int x, int y, int width, int height,
+ quint32 color)
+{
+ qt_rectfill<quint16>(reinterpret_cast<quint16 *>(rasterBuffer->buffer()),
+ qConvertRgb32To16(color), x, y, width, height, rasterBuffer->bytesPerLine());
+}
-inline static void qt_rectfill_nonpremul_quint32(QRasterBuffer *rasterBuffer,
- int x, int y, int width, int height,
- quint32 color)
+static void qt_rectfill_nonpremul_quint32(QRasterBuffer *rasterBuffer,
+ int x, int y, int width, int height,
+ quint32 color)
{
qt_rectfill<quint32>(reinterpret_cast<quint32 *>(rasterBuffer->buffer()),
INV_PREMUL(color), x, y, width, height, rasterBuffer->bytesPerLine());
@@ -6889,19 +5679,19 @@ DrawHelper qDrawHelper[QImage::NImageFormats] =
// Format_Mono,
{
blend_color_generic,
- SPANFUNC_POINTER(blend_src_generic, RegularSpans),
+ blend_src_generic,
0, 0, 0, 0
},
// Format_MonoLSB,
{
blend_color_generic,
- SPANFUNC_POINTER(blend_src_generic, RegularSpans),
+ blend_src_generic,
0, 0, 0, 0
},
// Format_Indexed8,
{
blend_color_generic,
- SPANFUNC_POINTER(blend_src_generic, RegularSpans),
+ blend_src_generic,
0, 0, 0, 0
},
// Format_RGB32,
@@ -6942,88 +5732,78 @@ DrawHelper qDrawHelper[QImage::NImageFormats] =
},
// Format_ARGB8565_Premultiplied
{
- SPANFUNC_POINTER_BLENDCOLOR(qargb8565),
- SPANFUNC_POINTER(blend_src_generic, RegularSpans),
- 0, 0, 0,
- qt_rectfill_qargb8565
+ blend_color_generic,
+ blend_src_generic,
+ 0, 0, 0, 0
},
// Format_RGB666
{
- SPANFUNC_POINTER_BLENDCOLOR(qrgb666),
- SPANFUNC_POINTER(blend_src_generic, RegularSpans),
- 0, 0, 0,
- qt_rectfill_qrgb666
+ blend_color_generic,
+ blend_src_generic,
+ 0, 0, 0, 0
},
// Format_ARGB6666_Premultiplied
{
- SPANFUNC_POINTER_BLENDCOLOR(qargb6666),
- SPANFUNC_POINTER(blend_src_generic, RegularSpans),
- 0, 0, 0,
- qt_rectfill_qargb6666
+ blend_color_generic,
+ blend_src_generic,
+ 0, 0, 0, 0
},
// Format_RGB555
{
- SPANFUNC_POINTER_BLENDCOLOR(qrgb555),
- SPANFUNC_POINTER(blend_src_generic, RegularSpans),
- 0, 0, 0,
- qt_rectfill_qrgb555
+ blend_color_generic,
+ blend_src_generic,
+ 0, 0, 0, 0
},
// Format_ARGB8555_Premultiplied
{
- SPANFUNC_POINTER_BLENDCOLOR(qargb8555),
- SPANFUNC_POINTER(blend_src_generic, RegularSpans),
- 0, 0, 0,
- qt_rectfill_qargb8555
+ blend_color_generic,
+ blend_src_generic,
+ 0, 0, 0, 0
},
// Format_RGB888
{
- SPANFUNC_POINTER_BLENDCOLOR(qrgb888),
- SPANFUNC_POINTER(blend_src_generic, RegularSpans),
- 0, 0, 0,
- qt_rectfill_qrgb888
+ blend_color_generic,
+ blend_src_generic,
+ 0, 0, 0, 0
},
// Format_RGB444
{
- SPANFUNC_POINTER_BLENDCOLOR(qrgb444),
- SPANFUNC_POINTER(blend_src_generic, RegularSpans),
- 0, 0, 0,
- qt_rectfill_qrgb444
+ blend_color_generic,
+ blend_src_generic,
+ 0, 0, 0, 0
},
// Format_ARGB4444_Premultiplied
{
- SPANFUNC_POINTER_BLENDCOLOR(qargb4444),
- SPANFUNC_POINTER(blend_src_generic, RegularSpans),
- 0, 0, 0,
- qt_rectfill_qargb4444
+ blend_color_generic,
+ blend_src_generic,
+ 0, 0, 0, 0
}
};
#if defined(Q_CC_MSVC) && !defined(_MIPS_)
-template <class DST, class SRC>
-inline void qt_memfill_template(DST *dest, SRC color, int count)
+template <class T>
+inline void qt_memfill_template(T *dest, T color, int count)
{
- const DST c = qt_colorConvert<DST, SRC>(color, 0);
while (count--)
- *dest++ = c;
+ *dest++ = color;
}
#else
-template <class DST, class SRC>
-inline void qt_memfill_template(DST *dest, SRC color, int count)
+template <class T>
+inline void qt_memfill_template(T *dest, T color, int count)
{
- const DST c = qt_colorConvert<DST, SRC>(color, 0);
int n = (count + 7) / 8;
switch (count & 0x07)
{
- case 0: do { *dest++ = c;
- case 7: *dest++ = c;
- case 6: *dest++ = c;
- case 5: *dest++ = c;
- case 4: *dest++ = c;
- case 3: *dest++ = c;
- case 2: *dest++ = c;
- case 1: *dest++ = c;
+ case 0: do { *dest++ = color;
+ case 7: *dest++ = color;
+ case 6: *dest++ = color;
+ case 5: *dest++ = color;
+ case 4: *dest++ = color;
+ case 3: *dest++ = color;
+ case 2: *dest++ = color;
+ case 1: *dest++ = color;
} while (--n > 0);
}
}
@@ -7053,7 +5833,7 @@ inline void qt_memfill_template(quint16 *dest, quint16 value, int count)
static void qt_memfill_quint16(quint16 *dest, quint16 color, int count)
{
- qt_memfill_template<quint16, quint16>(dest, color, count);
+ qt_memfill_template<quint16>(dest, color, count);
}
typedef void (*qt_memfill32_func)(quint32 *dest, quint32 value, int count);
@@ -7067,8 +5847,8 @@ qt_memfill16_func qt_memfill16 = qt_memfill16_setup;
void qInitDrawhelperAsm()
{
- qt_memfill32 = qt_memfill_template<quint32, quint32>;
- qt_memfill16 = qt_memfill_quint16; //qt_memfill_template<quint16, quint16>;
+ qt_memfill32 = qt_memfill_template<quint32>;
+ qt_memfill16 = qt_memfill_quint16; //qt_memfill_template<quint16>;
CompositionFunction *functionForModeAsm = 0;
CompositionFunctionSolid *functionForModeSolidAsm = 0;
diff --git a/src/gui/painting/qdrawhelper_neon.cpp b/src/gui/painting/qdrawhelper_neon.cpp
index c3dd4fb1ef..895b44dc17 100644
--- a/src/gui/painting/qdrawhelper_neon.cpp
+++ b/src/gui/painting/qdrawhelper_neon.cpp
@@ -198,7 +198,7 @@ void qt_blend_rgb16_on_argb32_neon(uchar *destPixels, int dbpl,
while (h--) {
for (int x=0; x<w; ++x)
- dst[x] = INTERPOLATE_PIXEL_255(qt_colorConvert(src[x], dst[x]), a, dst[x], ia);
+ dst[x] = INTERPOLATE_PIXEL_255(qConvertRgb16To32(src[x]), a, dst[x], ia);
dst += dbpl;
src += sbpl;
}
diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h
index bf8eadcc03..2e88fe718a 100644
--- a/src/gui/painting/qdrawhelper_p.h
+++ b/src/gui/painting/qdrawhelper_p.h
@@ -657,1059 +657,22 @@ Q_STATIC_INLINE_FUNCTION uint BYTE_MUL_RGB16_32(uint x, uint a) {
| (((255*qGreen(p)) / qAlpha(p)) << 8) \
| ((255*qBlue(p)) / qAlpha(p))))
-template <class DST, class SRC>
-inline DST qt_colorConvert(SRC color, DST dummy)
-{
- Q_UNUSED(dummy);
- return DST(color);
-}
-
-
-template <>
-inline quint32 qt_colorConvert(quint16 color, quint32 dummy)
-{
- Q_UNUSED(dummy);
- const int r = (color & 0xf800);
- const int g = (color & 0x07e0);
- const int b = (color & 0x001f);
- const int tr = (r >> 8) | (r >> 13);
- const int tg = (g >> 3) | (g >> 9);
- const int tb = (b << 3) | (b >> 2);
-
- return qRgb(tr, tg, tb);
-}
-
-template <>
-inline quint16 qt_colorConvert(quint32 color, quint16 dummy)
-{
- Q_UNUSED(dummy);
- const int r = qRed(color) << 8;
- const int g = qGreen(color) << 3;
- const int b = qBlue(color) >> 3;
-
- return (r & 0xf800) | (g & 0x07e0)| (b & 0x001f);
-}
-
-class quint32p
-{
-public:
- inline quint32p(quint32 v) : data(PREMUL(v)) {}
-
- inline operator quint32() const { return data; }
-
- inline operator quint16() const
- {
- return qt_colorConvert<quint16, quint32>(data, 0);
- }
-
- Q_STATIC_INLINE_FUNCTION quint32p fromRawData(quint32 v)
- {
- quint32p p;
- p.data = v;
- return p;
- }
-
-private:
- quint32p() {}
- quint32 data;
-} Q_PACKED;
-
-class qabgr8888
-{
-public:
- inline qabgr8888(quint32 v)
- {
- data = qRgba(qBlue(v), qGreen(v), qRed(v), qAlpha(v));
- }
-
- inline bool operator==(const qabgr8888 &v) const { return data == v.data; }
-
-private:
- quint32 data;
-} Q_PACKED;
-
-class qrgb565;
-
-class qargb8565
-{
-public:
- Q_STATIC_INLINE_FUNCTION bool hasAlpha() { return true; }
-
- inline qargb8565() {}
- inline qargb8565(quint32 v);
- inline explicit qargb8565(quint32p v);
- inline qargb8565(const qargb8565 &v);
- inline qargb8565(const qrgb565 &v);
-
- inline operator quint32() const;
- inline operator quint16() const;
-
- inline quint8 alpha() const { return data[0]; }
- inline qargb8565 truncedAlpha() {
- data[0] &= 0xf8;
- data[1] &= 0xdf;
- return *this;
- }
- Q_STATIC_INLINE_FUNCTION quint8 alpha(quint8 a) { return (a + 1) >> 3; }
- Q_STATIC_INLINE_FUNCTION quint8 ialpha(quint8 a) { return 0x20 - alpha(a); }
-
- inline qargb8565 byte_mul(quint8 a) const;
- inline qargb8565 operator+(qargb8565 v) const;
- inline bool operator==(const qargb8565 &v) const;
-
- inline quint32 rawValue() const;
- inline quint16 rawValue16() const;
-
-private:
- friend class qrgb565;
-
- quint8 data[3];
-} Q_PACKED;
-
-class qrgb565
-{
-public:
- Q_STATIC_INLINE_FUNCTION bool hasAlpha() { return false; }
-
- qrgb565(int v = 0) : data(v) {}
-
- inline explicit qrgb565(quint32p v);
- inline explicit qrgb565(quint32 v);
- inline explicit qrgb565(const qargb8565 &v);
-
- inline operator quint32() const;
- inline operator quint16() const;
-
- inline qrgb565 operator+(qrgb565 v) const;
-
- inline quint8 alpha() const { return 0xff; }
- inline qrgb565 truncedAlpha() { return *this; }
- Q_STATIC_INLINE_FUNCTION quint8 alpha(quint8 a) { return (a + 1) >> 3; }
- Q_STATIC_INLINE_FUNCTION quint8 ialpha(quint8 a) { return 0x20 - alpha(a); }
-
- inline qrgb565 byte_mul(quint8 a) const;
-
- inline bool operator==(const qrgb565 &v) const;
- inline quint16 rawValue() const { return data; }
-
-private:
- friend class qargb8565;
-
- quint16 data;
-} Q_PACKED;
-
-qargb8565::qargb8565(quint32 v)
-{
- *this = qargb8565(quint32p(v));
-}
-
-qargb8565::qargb8565(quint32p v)
-{
- data[0] = qAlpha(v);
- const int r = qRed(v);
- const int g = qGreen(v);
- const int b = qBlue(v);
- data[1] = ((g << 3) & 0xe0) | (b >> 3);
- data[2] = (r & 0xf8) | (g >> 5);
-}
-
-qargb8565::qargb8565(const qargb8565 &v)
-{
- data[0] = v.data[0];
- data[1] = v.data[1];
- data[2] = v.data[2];
-}
-
-qargb8565::qargb8565(const qrgb565 &v)
-{
- data[0] = 0xff;
- data[1] = v.data & 0xff;
- data[2] = v.data >> 8;
-}
-
-qargb8565::operator quint32() const
-{
- const quint16 rgb = (data[2] << 8) | data[1];
- const int a = data[0];
- const int r = (rgb & 0xf800);
- const int g = (rgb & 0x07e0);
- const int b = (rgb & 0x001f);
- const int tr = qMin(a, (r >> 8) | (r >> 13));
- const int tg = qMin(a, (g >> 3) | (g >> 9));
- const int tb = qMin(a, (b << 3) | (b >> 2));
- return qRgba(tr, tg, tb, data[0]);
-}
-
-qargb8565::operator quint16() const
-{
- return (data[2] << 8) | data[1];
-}
-
-qargb8565 qargb8565::operator+(qargb8565 v) const
-{
- qargb8565 t;
- t.data[0] = data[0] + v.data[0];
- const quint16 rgb = ((data[2] + v.data[2]) << 8)
- + (data[1] + v.data[1]);
- t.data[1] = rgb & 0xff;
- t.data[2] = rgb >> 8;
- return t;
-}
-
-qargb8565 qargb8565::byte_mul(quint8 a) const
-{
- qargb8565 result;
- result.data[0] = (data[0] * a) >> 5;
-
- const quint16 x = (data[2] << 8) | data[1];
- const quint16 t = ((((x & 0x07e0) >> 5) * a) & 0x07e0) |
- ((((x & 0xf81f) * a) >> 5) & 0xf81f);
- result.data[1] = t & 0xff;
- result.data[2] = t >> 8;
- return result;
-}
-
-bool qargb8565::operator==(const qargb8565 &v) const
-{
- return data[0] == v.data[0]
- && data[1] == v.data[1]
- && data[2] == v.data[2];
-}
-
-quint32 qargb8565::rawValue() const
-{
- return (data[2] << 16) | (data[1] << 8) | data[0];
-}
-
-quint16 qargb8565::rawValue16() const
-{
- return (data[2] << 8) | data[1];
-}
-
-qrgb565::qrgb565(quint32p v)
-{
- *this = qrgb565(quint32(v));
-}
-
-qrgb565::qrgb565(quint32 v)
-{
- const int r = qRed(v) << 8;
- const int g = qGreen(v) << 3;
- const int b = qBlue(v) >> 3;
-
- data = (r & 0xf800) | (g & 0x07e0)| (b & 0x001f);
-}
-
-qrgb565::qrgb565(const qargb8565 &v)
-{
- data = (v.data[2] << 8) | v.data[1];
-}
-
-qrgb565::operator quint32() const
-{
- const int r = (data & 0xf800);
- const int g = (data & 0x07e0);
- const int b = (data & 0x001f);
- const int tr = (r >> 8) | (r >> 13);
- const int tg = (g >> 3) | (g >> 9);
- const int tb = (b << 3) | (b >> 2);
- return qRgb(tr, tg, tb);
-}
-
-qrgb565::operator quint16() const
-{
- return data;
-}
-
-qrgb565 qrgb565::operator+(qrgb565 v) const
-{
- qrgb565 t;
- t.data = data + v.data;
- return t;
-}
-
-qrgb565 qrgb565::byte_mul(quint8 a) const
-{
- qrgb565 result;
- result.data = ((((data & 0x07e0) >> 5) * a) & 0x07e0) |
- ((((data & 0xf81f) * a) >> 5) & 0xf81f);
- return result;
-}
-
-bool qrgb565::operator==(const qrgb565 &v) const
-{
- return data == v.data;
-}
-
-class qbgr565
-{
-public:
- inline qbgr565(quint16 v)
- {
- data = ((v & 0x001f) << 11) |
- (v & 0x07e0) |
- ((v & 0xf800) >> 11);
- }
-
- inline bool operator==(const qbgr565 &v) const
- {
- return data == v.data;
- }
-
-private:
- quint16 data;
-} Q_PACKED;
-
-class qrgb555;
-
-class qargb8555
-{
-public:
- Q_STATIC_INLINE_FUNCTION bool hasAlpha() { return true; }
-
- qargb8555() {}
- inline qargb8555(quint32 v);
- inline explicit qargb8555(quint32p v);
- inline qargb8555(const qargb8555 &v);
- inline qargb8555(const qrgb555 &v);
-
- inline operator quint32() const;
-
- inline quint8 alpha() const { return data[0]; }
- inline qargb8555 truncedAlpha() { data[0] &= 0xf8; return *this; }
- Q_STATIC_INLINE_FUNCTION quint8 alpha(quint8 a) { return (a + 1) >> 3; }
- Q_STATIC_INLINE_FUNCTION quint8 ialpha(quint8 a) { return 0x20 - alpha(a); }
-
- inline qargb8555 operator+(qargb8555 v) const;
- inline qargb8555 byte_mul(quint8 a) const;
-
- inline bool operator==(const qargb8555 &v) const;
-
- inline quint32 rawValue() const;
-
-private:
- friend class qrgb555;
- quint8 data[3];
-} Q_PACKED;
-
-class qrgb555
-{
-public:
- Q_STATIC_INLINE_FUNCTION bool hasAlpha() { return false; }
-
- inline qrgb555(int v = 0) : data(v) {}
-
- inline explicit qrgb555(quint32p v) { *this = qrgb555(quint32(v)); }
-
- inline explicit qrgb555(quint32 v)
- {
- const int r = qRed(v) << 7;
- const int g = qGreen(v) << 2;
- const int b = qBlue(v) >> 3;
-
- data = (r & 0x7c00) | (g & 0x03e0) | (b & 0x001f);
- }
-
- inline explicit qrgb555(quint16 v)
- {
- data = ((v >> 1) & (0x7c00 | 0x03e0)) |
- (v & 0x001f);
- }
-
- inline explicit qrgb555(const qargb8555 &v);
-
- inline operator quint32() const
- {
- const int r = (data & 0x7c00);
- const int g = (data & 0x03e0);
- const int b = (data & 0x001f);
- const int tr = (r >> 7) | (r >> 12);
- const int tg = (g >> 2) | (g >> 7);
- const int tb = (b << 3) | (b >> 2);
-
- return qRgb(tr, tg, tb);
- }
-
- inline operator quint16() const
- {
- const int r = ((data & 0x7c00) << 1) & 0xf800;
- const int g = (((data & 0x03e0) << 1) | ((data >> 4) & 0x0020)) & 0x07e0;
- const int b = (data & 0x001f);
-
- return r | g | b;
- }
-
- inline qrgb555 operator+(qrgb555 v) const;
- inline qrgb555 byte_mul(quint8 a) const;
-
- inline quint8 alpha() const { return 0xff; }
- inline qrgb555 truncedAlpha() { return *this; }
- Q_STATIC_INLINE_FUNCTION quint8 alpha(quint8 a) { return (a + 1) >> 3; }
- Q_STATIC_INLINE_FUNCTION quint8 ialpha(quint8 a) { return 0x20 - alpha(a); }
-
- inline bool operator==(const qrgb555 &v) const { return v.data == data; }
- inline bool operator!=(const qrgb555 &v) const { return v.data != data; }
-
- inline quint16 rawValue() const { return data; }
-
-private:
- friend class qargb8555;
- friend class qbgr555;
- quint16 data;
-
-} Q_PACKED;
-
-qrgb555::qrgb555(const qargb8555 &v)
-{
- data = (v.data[2] << 8) | v.data[1];
-}
-
-qrgb555 qrgb555::operator+(qrgb555 v) const
-{
- qrgb555 t;
- t.data = data + v.data;
- return t;
-}
-
-qrgb555 qrgb555::byte_mul(quint8 a) const
-{
- quint16 t = (((data & 0x3e0) * a) >> 5) & 0x03e0;
- t |= (((data & 0x7c1f) * a) >> 5) & 0x7c1f;
-
- qrgb555 result;
- result.data = t;
- return result;
-}
-
-class qbgr555
-{
-public:
- inline qbgr555(quint32 v) { *this = qbgr555(qrgb555(v)); }
-
- inline qbgr555(qrgb555 v)
- {
- data = ((v.data & 0x001f) << 10) |
- (v.data & 0x03e0) |
- ((v.data & 0x7c00) >> 10);
- }
-
- inline bool operator==(const qbgr555 &v) const
- {
- return data == v.data;
- }
-
-private:
- quint16 data;
-} Q_PACKED;
-
-qargb8555::qargb8555(quint32 v)
-{
- v = quint32p(v);
- data[0] = qAlpha(v);
- const int r = qRed(v);
- const int g = qGreen(v);
- const int b = qBlue(v);
- data[1] = ((g << 2) & 0xe0) | (b >> 3);
- data[2] = ((r >> 1) & 0x7c) | (g >> 6);
-
-}
-
-qargb8555::qargb8555(quint32p v)
-{
- data[0] = qAlpha(v);
- const int r = qRed(v);
- const int g = qGreen(v);
- const int b = qBlue(v);
- data[1] = ((g << 2) & 0xe0) | (b >> 3);
- data[2] = ((r >> 1) & 0x7c) | (g >> 6);
-}
-
-qargb8555::qargb8555(const qargb8555 &v)
-{
- data[0] = v.data[0];
- data[1] = v.data[1];
- data[2] = v.data[2];
-}
-
-qargb8555::qargb8555(const qrgb555 &v)
-{
- data[0] = 0xff;
- data[1] = v.data & 0xff;
- data[2] = v.data >> 8;
-}
-
-qargb8555::operator quint32() const
-{
- const quint16 rgb = (data[2] << 8) | data[1];
- const int r = (rgb & 0x7c00);
- const int g = (rgb & 0x03e0);
- const int b = (rgb & 0x001f);
- const int tr = (r >> 7) | (r >> 12);
- const int tg = (g >> 2) | (g >> 7);
- const int tb = (b << 3) | (b >> 2);
-
- return qRgba(tr, tg, tb, data[0]);
-}
-
-bool qargb8555::operator==(const qargb8555 &v) const
-{
- return data[0] == v.data[0]
- && data[1] == v.data[1]
- && data[2] == v.data[2];
-}
-
-quint32 qargb8555::rawValue() const
-{
- return (data[2] << 16) | (data[1] << 8) | data[0];
-}
-
-qargb8555 qargb8555::operator+(qargb8555 v) const
-{
- qargb8555 t;
- t.data[0] = data[0] + v.data[0];
- const quint16 rgb = ((data[2] + v.data[2]) << 8)
- + (data[1] + v.data[1]);
- t.data[1] = rgb & 0xff;
- t.data[2] = rgb >> 8;
- return t;
-}
-
-qargb8555 qargb8555::byte_mul(quint8 a) const
-{
- qargb8555 result;
- result.data[0] = (data[0] * a) >> 5;
-
- const quint16 x = (data[2] << 8) | data[1];
- quint16 t = (((x & 0x3e0) * a) >> 5) & 0x03e0;
- t |= (((x & 0x7c1f) * a) >> 5) & 0x7c1f;
- result.data[1] = t & 0xff;
- result.data[2] = t >> 8;
- return result;
-
-}
-
-class qrgb666;
-
-class qargb6666
-{
-public:
- Q_STATIC_INLINE_FUNCTION bool hasAlpha() { return true; }
-
- inline qargb6666() {}
- inline qargb6666(quint32 v) { *this = qargb6666(quint32p(v)); }
- inline explicit qargb6666(quint32p v);
- inline qargb6666(const qargb6666 &v);
- inline qargb6666(const qrgb666 &v);
-
- inline operator quint32 () const;
-
- inline quint8 alpha() const;
- inline qargb6666 truncedAlpha() { return *this; }
- Q_STATIC_INLINE_FUNCTION quint8 alpha(quint8 a) { return (a + 1) >> 2; }
- Q_STATIC_INLINE_FUNCTION quint8 ialpha(quint8 a) { return (255 - a + 1) >> 2; }
-
- inline qargb6666 byte_mul(quint8 a) const;
- inline qargb6666 operator+(qargb6666 v) const;
- inline bool operator==(const qargb6666 &v) const;
-
- inline quint32 rawValue() const;
-
-private:
- friend class qrgb666;
- quint8 data[3];
-
-} Q_PACKED;
-
-class qrgb666
-{
-public:
- Q_STATIC_INLINE_FUNCTION bool hasAlpha() { return false; }
-
- inline qrgb666() {}
- inline qrgb666(quint32 v);
- inline qrgb666(const qargb6666 &v);
-
- inline operator quint32 () const;
-
- inline quint8 alpha() const { return 0xff; }
- inline qrgb666 truncedAlpha() { return *this; }
- Q_STATIC_INLINE_FUNCTION quint8 alpha(quint8 a) { return (a + 1) >> 2; }
- Q_STATIC_INLINE_FUNCTION quint8 ialpha(quint8 a) { return (255 - a + 1) >> 2; }
-
- inline qrgb666 operator+(qrgb666 v) const;
- inline qrgb666 byte_mul(quint8 a) const;
-
- inline bool operator==(const qrgb666 &v) const;
- inline bool operator!=(const qrgb666 &v) const { return !(*this == v); }
-
- inline quint32 rawValue() const
- {
- return (data[2] << 16) | (data[1] << 8) | data[0];
- }
-
-private:
- friend class qargb6666;
-
- quint8 data[3];
-} Q_PACKED;
-
-qrgb666::qrgb666(quint32 v)
-{
- const uchar b = qBlue(v);
- const uchar g = qGreen(v);
- const uchar r = qRed(v);
- const uint p = (b >> 2) | ((g >> 2) << 6) | ((r >> 2) << 12);
- data[0] = qBlue(p);
- data[1] = qGreen(p);
- data[2] = qRed(p);
-}
-
-qrgb666::qrgb666(const qargb6666 &v)
-{
- data[0] = v.data[0];
- data[1] = v.data[1];
- data[2] = v.data[2] & 0x03;
-}
-
-qrgb666::operator quint32 () const
-{
- const uchar r = (data[2] << 6) | ((data[1] & 0xf0) >> 2) | (data[2] & 0x3);
- const uchar g = (data[1] << 4) | ((data[0] & 0xc0) >> 4) | ((data[1] & 0x0f) >> 2);
- const uchar b = (data[0] << 2) | ((data[0] & 0x3f) >> 4);
- return qRgb(r, g, b);
-}
-
-qrgb666 qrgb666::operator+(qrgb666 v) const
-{
- const quint32 x1 = (data[2] << 16) | (data[1] << 8) | data[0];
- const quint32 x2 = (v.data[2] << 16) | (v.data[1] << 8) | v.data[0];
- const quint32 t = x1 + x2;
- qrgb666 r;
- r.data[0] = t & 0xff;
- r.data[1] = (t >> 8) & 0xff;
- r.data[2] = (t >> 16) & 0xff;
- return r;
-}
-
-qrgb666 qrgb666::byte_mul(quint8 a) const
-{
- const quint32 x = (data[2] << 16) | (data[1] << 8) | data[0];
- const quint32 t = ((((x & 0x03f03f) * a) >> 6) & 0x03f03f) |
- ((((x & 0x000fc0) * a) >> 6) & 0x000fc0);
-
- qrgb666 r;
- r.data[0] = t & 0xff;
- r.data[1] = (t >> 8) & 0xff;
- r.data[2] = (t >> 16) & 0xff;
- return r;
-}
-
-bool qrgb666::operator==(const qrgb666 &v) const
-{
- return (data[0] == v.data[0] &&
- data[1] == v.data[1] &&
- data[2] == v.data[2]);
-}
-
-qargb6666::qargb6666(quint32p v)
-{
- const quint8 b = qBlue(v) >> 2;
- const quint8 g = qGreen(v) >> 2;
- const quint8 r = qRed(v) >> 2;
- const quint8 a = qAlpha(v) >> 2;
- const uint p = (a << 18) | (r << 12) | (g << 6) | b;
- data[0] = qBlue(p);
- data[1] = qGreen(p);
- data[2] = qRed(p);
-}
-
-qargb6666::qargb6666(const qargb6666 &v)
-{
- data[0] = v.data[0];
- data[1] = v.data[1];
- data[2] = v.data[2];
-}
-
-qargb6666::qargb6666(const qrgb666 &v)
-{
- data[0] = v.data[0];
- data[1] = v.data[1];
- data[2] = (v.data[2] | 0xfc);
-}
-
-qargb6666::operator quint32 () const
-{
- const quint8 r = (data[2] << 6) | ((data[1] & 0xf0) >> 2) | (data[2] & 0x3);
- const quint8 g = (data[1] << 4) | ((data[0] & 0xc0) >> 4) | ((data[1] & 0x0f) >> 2);
- const quint8 b = (data[0] << 2) | ((data[0] & 0x3f) >> 4);
- const quint8 a = (data[2] & 0xfc) | (data[2] >> 6);
- return qRgba(r, g, b, a);
-}
-
-qargb6666 qargb6666::operator+(qargb6666 v) const
-{
- const quint32 x1 = (data[2] << 16) | (data[1] << 8) | data[0];
- const quint32 x2 = (v.data[2] << 16) | (v.data[1] << 8) | v.data[0];
- const quint32 t = x1 + x2;
- qargb6666 r;
- r.data[0] = t & 0xff;
- r.data[1] = (t >> 8) & 0xff;
- r.data[2] = (t >> 16) & 0xff;
- return r;
-}
-
-quint8 qargb6666::alpha() const
-{
- return (data[2] & 0xfc) | (data[2] >> 6);
-}
-
-inline qargb6666 qargb6666::byte_mul(quint8 a) const
-{
- const quint32 x = (data[2] << 16) | (data[1] << 8) | data[0];
- const quint32 t = ((((x & 0x03f03f) * a) >> 6) & 0x03f03f) |
- ((((x & 0xfc0fc0) * a) >> 6) & 0xfc0fc0);
-
- qargb6666 r;
- r.data[0] = t & 0xff;
- r.data[1] = (t >> 8) & 0xff;
- r.data[2] = (t >> 16) & 0xff;
- return r;
-}
-
-bool qargb6666::operator==(const qargb6666 &v) const
-{
- return data[0] == v.data[0]
- && data[1] == v.data[1]
- && data[2] == v.data[2];
-}
-
-quint32 qargb6666::rawValue() const
-{
- return (data[2] << 16) | (data[1] << 8) | data[0];
-}
-
-class qrgb888
-{
-public:
- Q_STATIC_INLINE_FUNCTION bool hasAlpha() { return false; }
-
- inline qrgb888() {}
- inline qrgb888(quint32 v);
-
- inline operator quint32() const;
-
- inline quint8 alpha() const { return 0xff; }
- inline qrgb888 truncedAlpha() { return *this; }
- Q_STATIC_INLINE_FUNCTION quint8 alpha(quint8 a) { return a; }
- Q_STATIC_INLINE_FUNCTION quint8 ialpha(quint8 a) { return 255 - a; }
-
- inline qrgb888 byte_mul(quint8 a) const;
- inline qrgb888 operator+(qrgb888 v) const;
- inline bool operator==(qrgb888 v) const;
-
- inline quint32 rawValue() const;
-
-private:
+struct quint24 {
+ quint24(uint value);
+ operator uint() const;
uchar data[3];
-
} Q_PACKED;
-qrgb888::qrgb888(quint32 v)
+inline quint24::quint24(uint value)
{
- data[0] = qRed(v);
- data[1] = qGreen(v);
- data[2] = qBlue(v);
+ data[0] = uchar(value);
+ data[1] = uchar(value >> 8);
+ data[2] = uchar(value >> 16);
}
-qrgb888::operator quint32() const
+inline quint24::operator uint() const
{
- return qRgb(data[0], data[1], data[2]);
-}
-
-qrgb888 qrgb888::operator+(qrgb888 v) const
-{
- qrgb888 t = *this;
- t.data[0] += v.data[0];
- t.data[1] += v.data[1];
- t.data[2] += v.data[2];
- return t;
-}
-
-qrgb888 qrgb888::byte_mul(quint8 a) const
-{
- quint32 x(*this);
-
- quint32 t = (x & 0xff00ff) * a;
- t = (t + ((t >> 8) & 0xff00ff) + 0x800080) >> 8;
- t &= 0xff00ff;
-
- x = ((x >> 8) & 0xff00ff) * a;
- x = (x + ((x >> 8) & 0xff00ff) + 0x800080);
- x &= 0xff00ff00;
- x |= t;
- return qrgb888(x);
-}
-
-bool qrgb888::operator==(qrgb888 v) const
-{
- return (data[0] == v.data[0] &&
- data[1] == v.data[1] &&
- data[2] == v.data[2]);
-}
-
-quint32 qrgb888::rawValue() const
-{
- return (data[2] << 16) | (data[1] << 8) | data[0];
-}
-
-template <>
-inline qrgb888 qt_colorConvert(quint32 color, qrgb888 dummy)
-{
- Q_UNUSED(dummy);
- return qrgb888(color);
-}
-
-template <>
-inline quint32 qt_colorConvert(qrgb888 color, quint32 dummy)
-{
- Q_UNUSED(dummy);
- return quint32(color);
-}
-
-// hw: endianess??
-class quint24
-{
-public:
- inline quint24(quint32 v)
- {
- data[0] = qBlue(v);
- data[1] = qGreen(v);
- data[2] = qRed(v);
- }
-
- inline operator quint32 ()
- {
- return qRgb(data[2], data[1], data[0]);
- }
-
- inline bool operator==(const quint24 &v) const
- {
- return data[0] == v.data[0]
- && data[1] == v.data[1]
- && data[2] == v.data[2];
- }
-
-private:
- uchar data[3];
-} Q_PACKED;
-
-template <>
-inline quint24 qt_colorConvert(quint32 color, quint24 dummy)
-{
- Q_UNUSED(dummy);
- return quint24(color);
-}
-
-// hw: endianess??
-class quint18
-{
-public:
- inline quint18(quint32 v)
- {
- uchar b = qBlue(v);
- uchar g = qGreen(v);
- uchar r = qRed(v);
- uint p = (b >> 2) | ((g >> 2) << 6) | ((r >> 2) << 12);
- data[0] = qBlue(p);
- data[1] = qGreen(p);
- data[2] = qRed(p);
- }
-
- inline operator quint32 ()
- {
- const uchar r = (data[2] << 6) | ((data[1] & 0xf0) >> 2) | (data[2] & 0x3);
- const uchar g = (data[1] << 4) | ((data[0] & 0xc0) >> 4) | ((data[1] & 0x0f) >> 2);
- const uchar b = (data[0] << 2) | ((data[0] & 0x3f) >> 4);
- return qRgb(r, g, b);
- }
-
-private:
- uchar data[3];
-} Q_PACKED;
-
-template <>
-inline quint18 qt_colorConvert(quint32 color, quint18 dummy)
-{
- Q_UNUSED(dummy);
- return quint18(color);
-}
-
-class qrgb444;
-
-class qargb4444
-{
-public:
- Q_STATIC_INLINE_FUNCTION bool hasAlpha() { return true; }
-
- inline qargb4444() {}
- inline qargb4444(quint32 v) { *this = qargb4444(quint32p(v)); }
- inline explicit qargb4444(quint32p v);
- inline qargb4444(const qrgb444 &v);
-
- inline operator quint32() const;
- inline operator quint8() const;
-
- inline qargb4444 operator+(qargb4444 v) const;
-
- inline quint8 alpha() const { return ((data & 0xf000) >> 8) | ((data & 0xf000) >> 12); }
- inline qargb4444 truncedAlpha() { return *this; }
- Q_STATIC_INLINE_FUNCTION quint8 alpha(quint8 a) { return (a + 1) >> 4; }
- Q_STATIC_INLINE_FUNCTION quint8 ialpha(quint8 a) { return 0x10 - alpha(a); }
- inline qargb4444 byte_mul(quint8 a) const;
-
- inline bool operator==(const qargb4444 &v) const { return data == v.data; }
-
- inline quint16 rawValue() const { return data; }
-
-private:
- friend class qrgb444;
- quint16 data;
-
-} Q_PACKED;
-
-class qrgb444
-{
-public:
- Q_STATIC_INLINE_FUNCTION bool hasAlpha() { return false; }
-
- inline qrgb444() {}
- inline qrgb444(quint32 v);
- inline explicit qrgb444(qargb4444 v);
-
- inline operator quint32() const;
- inline operator quint8() const;
-
- inline qrgb444 operator+(qrgb444 v) const;
- inline quint8 alpha() const { return 0xff; }
- inline qrgb444 truncedAlpha() { return *this; }
- Q_STATIC_INLINE_FUNCTION quint8 alpha(quint8 a) { return (a + 1) >> 4; }
- Q_STATIC_INLINE_FUNCTION quint8 ialpha(quint8 a) { return 0x10 - alpha(a); }
- inline qrgb444 byte_mul(quint8 a) const;
-
- inline bool operator==(const qrgb444 &v) const { return data == v.data; }
- inline bool operator!=(const qrgb444 &v) const { return data != v.data; }
-
- inline quint16 rawValue() const { return data; }
-
-private:
- friend class qargb4444;
- quint16 data;
-
-} Q_PACKED;
-
-
-qargb4444::qargb4444(quint32p color)
-{
- quint32 v = color;
- v &= 0xf0f0f0f0;
- const int a = qAlpha(v) << 8;
- const int r = qRed(v) << 4;
- const int g = qGreen(v);
- const int b = qBlue(v) >> 4;
-
- data = a | r | g | b;
-}
-
-qargb4444::qargb4444(const qrgb444 &v)
-{
- data = v.data | 0xf000;
-}
-
-qargb4444::operator quint32() const
-{
- const int a = (data & 0xf000);
- const int r = (data & 0x0f00);
- const int g = (data & 0x00f0);
- const int b = (data & 0x000f);
- const int ta = (a >> 8) | (a >> 12);
- const int tr = (r >> 4) | (r >> 8);
- const int tg = g | (g >> 4);
- const int tb = (b << 4) | b;
-
- return qRgba(tr, tg, tb, ta);
-}
-
-qargb4444::operator quint8() const
-{
- // hw: optimize!
- return qt_colorConvert<quint8, quint32>(operator quint32(), 0);
-}
-
-qargb4444 qargb4444::operator+(qargb4444 v) const
-{
- qargb4444 t;
- t.data = data + v.data;
- return t;
-}
-
-qargb4444 qargb4444::byte_mul(quint8 a) const
-{
- quint16 t = (((data & 0xf0f0) * a) >> 4) & 0xf0f0;
- t |= (((data & 0x0f0f) * a) >> 4) & 0x0f0f;
-
- qargb4444 result;
- result.data = t;
- return result;
-}
-
-qrgb444::qrgb444(quint32 v)
-{
- v &= 0xf0f0f0f0;
- const int r = qRed(v) << 4;
- const int g = qGreen(v);
- const int b = qBlue(v) >> 4;
-
- data = r | g | b;
-}
-
-qrgb444::qrgb444(qargb4444 v)
-{
- data = v.data & 0x0fff;
-}
-
-qrgb444::operator quint32() const
-{
- const int r = (data & 0x0f00);
- const int g = (data & 0x00f0);
- const int b = (data & 0x000f);
- const int tr = (r >> 4) | (r >> 8);
- const int tg = g | (g >> 4);
- const int tb = (b << 4) | b;
-
- return qRgb(tr, tg, tb);
-}
-
-qrgb444::operator quint8() const
-{
- // hw: optimize!
- return qt_colorConvert<quint8, quint32>(operator quint32(), 0);
-}
-
-qrgb444 qrgb444::operator+(qrgb444 v) const
-{
- qrgb444 t;
- t.data = data + v.data;
- return t;
-}
-
-qrgb444 qrgb444::byte_mul(quint8 a) const
-{
- quint16 t = (((data & 0xf0f0) * a) >> 4) & 0xf0f0;
- t |= (((data & 0x0f0f) * a) >> 4) & 0x0f0f;
-
- qrgb444 result;
- result.data = t;
- return result;
+ return data[0] | (data[1] << 8) | (data[2] << 16);
}
template <class T>
@@ -1769,156 +732,6 @@ inline void qt_rectfill(T *dest, T value,
}
}
-template <class DST, class SRC>
-inline void qt_memconvert(DST *dest, const SRC *src, int count)
-{
- if (sizeof(DST) == 1) {
- while (count) {
- int n = 1;
- const SRC color = *src++;
- const DST dstColor = qt_colorConvert<DST, SRC>(color, 0);
- while (--count && (*src == color || dstColor == qt_colorConvert<DST, SRC>(*src, 0))) {
- ++n;
- ++src;
- }
- qt_memfill(dest, dstColor, n);
- dest += n;
- }
- } else {
- /* Duff's device */
- int n = (count + 7) / 8;
- switch (count & 0x07)
- {
- case 0: do { *dest++ = qt_colorConvert<DST, SRC>(*src++, 0);
- case 7: *dest++ = qt_colorConvert<DST, SRC>(*src++, 0);
- case 6: *dest++ = qt_colorConvert<DST, SRC>(*src++, 0);
- case 5: *dest++ = qt_colorConvert<DST, SRC>(*src++, 0);
- case 4: *dest++ = qt_colorConvert<DST, SRC>(*src++, 0);
- case 3: *dest++ = qt_colorConvert<DST, SRC>(*src++, 0);
- case 2: *dest++ = qt_colorConvert<DST, SRC>(*src++, 0);
- case 1: *dest++ = qt_colorConvert<DST, SRC>(*src++, 0);
- } while (--n > 0);
- }
- }
-}
-
-#define QT_TRIVIAL_MEMCONVERT_IMPL(T) \
- template <> \
- inline void qt_memconvert(T *dest, const T *src, int count) \
- { \
- memcpy(dest, src, count * sizeof(T)); \
- }
-QT_TRIVIAL_MEMCONVERT_IMPL(quint32)
-QT_TRIVIAL_MEMCONVERT_IMPL(qrgb888)
-QT_TRIVIAL_MEMCONVERT_IMPL(qargb6666)
-QT_TRIVIAL_MEMCONVERT_IMPL(qrgb666)
-QT_TRIVIAL_MEMCONVERT_IMPL(quint16)
-QT_TRIVIAL_MEMCONVERT_IMPL(qrgb565)
-QT_TRIVIAL_MEMCONVERT_IMPL(qargb8565)
-QT_TRIVIAL_MEMCONVERT_IMPL(qargb8555)
-QT_TRIVIAL_MEMCONVERT_IMPL(qrgb555)
-QT_TRIVIAL_MEMCONVERT_IMPL(qargb4444)
-QT_TRIVIAL_MEMCONVERT_IMPL(qrgb444)
-#undef QT_TRIVIAL_MEMCONVERT_IMPL
-
-#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
-template <>
-inline void qt_memconvert(qrgb666 *dest, const quint32 *src, int count)
-{
- if (count < 3) {
- switch (count) {
- case 2: *dest++ = qrgb666(*src++);
- case 1: *dest = qrgb666(*src);
- }
- return;
- }
-
- const int align = (quintptr(dest) & 3);
- switch (align) {
- case 1: *dest++ = qrgb666(*src++); --count;
- case 2: *dest++ = qrgb666(*src++); --count;
- case 3: *dest++ = qrgb666(*src++); --count;
- }
-
- quint32 *dest32 = reinterpret_cast<quint32*>(dest);
- int sourceCount = count >> 2;
- while (sourceCount--) {
- dest32[0] = ((src[1] & 0x00000c00) << 20)
- | ((src[1] & 0x000000fc) << 22)
- | ((src[0] & 0x00fc0000) >> 6)
- | ((src[0] & 0x0000fc00) >> 4)
- | ((src[0] & 0x000000fc) >> 2);
- dest32[1] = ((src[2] & 0x003c0000) << 10)
- | ((src[2] & 0x0000fc00) << 12)
- | ((src[2] & 0x000000fc) << 14)
- | ((src[1] & 0x00fc0000) >> 14)
- | ((src[1] & 0x0000f000) >> 12);
- dest32[2] = ((src[3] & 0x00fc0000) << 2)
- | ((src[3] & 0x0000fc00) << 4)
- | ((src[3] & 0x000000fc) << 6)
- | ((src[2] & 0x00c00000) >> 22);
- dest32 += 3;
- src += 4;
- }
-
- dest = reinterpret_cast<qrgb666*>(dest32);
- switch (count & 3) {
- case 3: *dest++ = qrgb666(*src++);
- case 2: *dest++ = qrgb666(*src++);
- case 1: *dest = qrgb666(*src);
- }
-}
-#endif // Q_BYTE_ORDER
-
-template <class T>
-inline void qt_rectcopy(T *dest, const T *src,
- int x, int y, int width, int height,
- int dstStride, int srcStride)
-{
- char *d = (char*)(dest + x) + y * dstStride;
- const char *s = (char*)(src);
- for (int i = 0; i < height; ++i) {
- ::memcpy(d, s, width * sizeof(T));
- d += dstStride;
- s += srcStride;
- }
-}
-
-template <class DST, class SRC>
-inline void qt_rectconvert(DST *dest, const SRC *src,
- int x, int y, int width, int height,
- int dstStride, int srcStride)
-{
- char *d = (char*)(dest + x) + y * dstStride;
- const char *s = (char*)(src);
- for (int i = 0; i < height; ++i) {
- qt_memconvert<DST,SRC>((DST*)d, (const SRC*)s, width);
- d += dstStride;
- s += srcStride;
- }
-}
-
-#define QT_RECTCONVERT_TRIVIAL_IMPL(T) \
- template <> \
- inline void qt_rectconvert(T *dest, const T *src, \
- int x, int y, int width, int height, \
- int dstStride, int srcStride) \
- { \
- qt_rectcopy(dest, src, x, y, width, height, dstStride, srcStride); \
- }
-QT_RECTCONVERT_TRIVIAL_IMPL(quint32)
-QT_RECTCONVERT_TRIVIAL_IMPL(qrgb888)
-QT_RECTCONVERT_TRIVIAL_IMPL(qargb6666)
-QT_RECTCONVERT_TRIVIAL_IMPL(qrgb666)
-QT_RECTCONVERT_TRIVIAL_IMPL(qrgb565)
-QT_RECTCONVERT_TRIVIAL_IMPL(qargb8565)
-QT_RECTCONVERT_TRIVIAL_IMPL(quint16)
-QT_RECTCONVERT_TRIVIAL_IMPL(qargb8555)
-QT_RECTCONVERT_TRIVIAL_IMPL(qrgb555)
-QT_RECTCONVERT_TRIVIAL_IMPL(qargb4444)
-QT_RECTCONVERT_TRIVIAL_IMPL(qrgb444)
-#undef QT_RECTCONVERT_TRIVIAL_IMPL
-
#define QT_MEMFILL_UINT(dest, length, color) \
qt_memfill<quint32>(dest, color, length);
@@ -2137,6 +950,162 @@ void QT_FASTCALL rasterop_solid_NotSource(uint *dest, int length, uint color, ui
void QT_FASTCALL rasterop_solid_NotSourceAndDestination(uint *dest, int length, uint color, uint const_alpha);
void QT_FASTCALL rasterop_solid_SourceAndNotDestination(uint *dest, int length, uint color, uint const_alpha);
+
+struct QPixelLayout;
+typedef const uint *(QT_FASTCALL *ConvertFunc)(uint *buffer, const uint *src, int count,
+ const QPixelLayout *layout, const QRgb *clut);
+
+struct QPixelLayout
+{
+ // Bits per pixel
+ enum BPP {
+ BPPNone,
+ BPP1MSB,
+ BPP1LSB,
+ BPP8,
+ BPP16,
+ BPP24,
+ BPP32,
+ BPPCount
+ };
+
+ // All numbers in bits.
+ uchar redWidth;
+ uchar redShift;
+ uchar greenWidth;
+ uchar greenShift;
+ uchar blueWidth;
+ uchar blueShift;
+ uchar alphaWidth;
+ uchar alphaShift;
+ bool premultiplied;
+ BPP bpp;
+ ConvertFunc convertToARGB32PM;
+ ConvertFunc convertFromARGB32PM;
+};
+
+template <QPixelLayout::BPP bpp>
+uint fetchPixel(const uchar *src, int index);
+
+template <>
+inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP1LSB>(const uchar *src, int index)
+{
+ return (src[index >> 3] >> (index & 7)) & 1;
+}
+
+template <>
+inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP1MSB>(const uchar *src, int index)
+{
+ return (src[index >> 3] >> (~index & 7)) & 1;
+}
+
+template <>
+inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP8>(const uchar *src, int index)
+{
+ return src[index];
+}
+
+template <>
+inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP16>(const uchar *src, int index)
+{
+ return reinterpret_cast<const quint16 *>(src)[index];
+}
+
+template <>
+inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP24>(const uchar *src, int index)
+{
+ return reinterpret_cast<const quint24 *>(src)[index];
+}
+
+template <>
+inline uint QT_FASTCALL fetchPixel<QPixelLayout::BPP32>(const uchar *src, int index)
+{
+ return reinterpret_cast<const uint *>(src)[index];
+}
+
+template <QPixelLayout::BPP bpp>
+inline const uint *QT_FASTCALL fetchPixels(uint *buffer, const uchar *src, int index, int count)
+{
+ for (int i = 0; i < count; ++i)
+ buffer[i] = fetchPixel<bpp>(src, index + i);
+ return buffer;
+}
+
+template <>
+inline const uint *QT_FASTCALL fetchPixels<QPixelLayout::BPP32>(uint *, const uchar *src, int index, int)
+{
+ return reinterpret_cast<const uint *>(src) + index;
+}
+
+typedef const uint *(QT_FASTCALL *FetchPixelsFunc)(uint *buffer, const uchar *src, int index, int count);
+
+
+template <QPixelLayout::BPP width>
+void storePixel(uchar *dest, int index, uint pixel);
+
+template <>
+inline void QT_FASTCALL storePixel<QPixelLayout::BPP1LSB>(uchar *dest, int index, uint pixel)
+{
+ if (pixel)
+ dest[index >> 3] |= 1 << (index & 7);
+ else
+ dest[index >> 3] &= ~(1 << (index & 7));
+}
+
+template <>
+inline void QT_FASTCALL storePixel<QPixelLayout::BPP1MSB>(uchar *dest, int index, uint pixel)
+{
+ if (pixel)
+ dest[index >> 3] |= 1 << (~index & 7);
+ else
+ dest[index >> 3] &= ~(1 << (~index & 7));
+}
+
+template <>
+inline void QT_FASTCALL storePixel<QPixelLayout::BPP8>(uchar *dest, int index, uint pixel)
+{
+ dest[index] = uchar(pixel);
+}
+
+template <>
+inline void QT_FASTCALL storePixel<QPixelLayout::BPP16>(uchar *dest, int index, uint pixel)
+{
+ reinterpret_cast<quint16 *>(dest)[index] = quint16(pixel);
+}
+
+template <>
+inline void QT_FASTCALL storePixel<QPixelLayout::BPP24>(uchar *dest, int index, uint pixel)
+{
+ reinterpret_cast<quint24 *>(dest)[index] = quint24(pixel);
+}
+
+template <>
+inline void QT_FASTCALL storePixel<QPixelLayout::BPP32>(uchar *dest, int index, uint pixel)
+{
+ reinterpret_cast<uint *>(dest)[index] = pixel;
+}
+
+template <QPixelLayout::BPP width>
+inline void QT_FASTCALL storePixels(uchar *dest, const uint *src, int index, int count)
+{
+ for (int i = 0; i < count; ++i)
+ storePixel<width>(dest, index + i, src[i]);
+}
+
+template <>
+inline void QT_FASTCALL storePixels<QPixelLayout::BPP32>(uchar *dest, const uint *src, int index, int count)
+{
+ memcpy(reinterpret_cast<uint *>(dest) + index, src, count * sizeof(uint));
+}
+
+typedef void (QT_FASTCALL *StorePixelsFunc)(uchar *dest, const uint *src, int index, int count);
+
+extern QPixelLayout qPixelLayouts[QImage::NImageFormats];
+extern FetchPixelsFunc qFetchPixels[QPixelLayout::BPPCount];
+extern StorePixelsFunc qStorePixels[QPixelLayout::BPPCount];
+
+
+
QT_END_NAMESPACE
#endif // QDRAWHELPER_P_H
diff --git a/src/gui/painting/qdrawhelper_sse2.cpp b/src/gui/painting/qdrawhelper_sse2.cpp
index 17b249a235..7b57d5c5e2 100644
--- a/src/gui/painting/qdrawhelper_sse2.cpp
+++ b/src/gui/painting/qdrawhelper_sse2.cpp
@@ -459,7 +459,7 @@ void qt_bitmapblit16_sse2(QRasterBuffer *rasterBuffer, int x, int y,
quint32 color,
const uchar *src, int width, int height, int stride)
{
- const quint16 c = qt_colorConvert<quint16, quint32>(color, 0);
+ const quint16 c = qConvertRgb32To16(color);
quint16 *dest = reinterpret_cast<quint16*>(rasterBuffer->scanLine(y)) + x;
const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint16);
@@ -629,8 +629,9 @@ void qt_scale_image_argb32_on_argb32_sse2(uchar *destPixels, int dbpl,
int x = 0;
ALIGNMENT_PROLOGUE_16BYTES(dst, x, w) {
- uint s = src[(srcx + x*ix) >> 16];
+ uint s = src[srcx >> 16];
dst[x] = s + BYTE_MUL(dst[x], qAlpha(~s));
+ srcx += ix;
}
__m128i srcxVector = _mm_set_epi32(srcx, srcx + ix, srcx + ix + ix, srcx + ix + ix + ix);
@@ -646,7 +647,7 @@ void qt_scale_image_argb32_on_argb32_sse2(uchar *destPixels, int dbpl,
}
for (; x<w; x++) {
- uint s = src[(srcx + x*ix) >> 16];
+ uint s = src[(basex + x*ix) >> 16];
dst[x] = s + BYTE_MUL(dst[x], qAlpha(~s));
}
dst = (quint32 *)(((uchar *) dst) + dbpl);
diff --git a/src/gui/painting/qdrawhelper_sse_p.h b/src/gui/painting/qdrawhelper_sse_p.h
index 81a5001fb3..494ee70fcb 100644
--- a/src/gui/painting/qdrawhelper_sse_p.h
+++ b/src/gui/painting/qdrawhelper_sse_p.h
@@ -127,7 +127,7 @@ inline void qt_bitmapblit16_sse_template(QRasterBuffer *rasterBuffer,
const uchar *src,
int width, int height, int stride)
{
- const quint16 c = qt_colorConvert<quint16, quint32>(color, 0);
+ const quint16 c = qConvertRgb32To16(color);
quint16 *dest = reinterpret_cast<quint16*>(rasterBuffer->scanLine(y)) + x;
const int destStride = rasterBuffer->bytesPerLine() / sizeof(quint16);
diff --git a/src/gui/painting/qmemrotate.cpp b/src/gui/painting/qmemrotate.cpp
index 5d027b669b..e6fcc3e5dd 100644
--- a/src/gui/painting/qmemrotate.cpp
+++ b/src/gui/painting/qmemrotate.cpp
@@ -53,36 +53,36 @@ static const int tileSize = 32;
#endif
#endif
-template <class DST, class SRC>
-Q_STATIC_TEMPLATE_FUNCTION inline void qt_memrotate90_cachedRead(const SRC *src, int w, int h,
- int sstride,
- DST *dest, int dstride)
+template <class T>
+Q_STATIC_TEMPLATE_FUNCTION
+inline void qt_memrotate90_cachedRead(const T *src, int w, int h, int sstride, T *dest,
+ int dstride)
{
const char *s = reinterpret_cast<const char*>(src);
char *d = reinterpret_cast<char*>(dest);
for (int y = 0; y < h; ++y) {
for (int x = w - 1; x >= 0; --x) {
- DST *destline = reinterpret_cast<DST*>(d + (w - x - 1) * dstride);
- destline[y] = qt_colorConvert<DST,SRC>(src[x], 0);
+ T *destline = reinterpret_cast<T *>(d + (w - x - 1) * dstride);
+ destline[y] = src[x];
}
s += sstride;
- src = reinterpret_cast<const SRC*>(s);
+ src = reinterpret_cast<const T*>(s);
}
}
-template <class DST, class SRC>
-Q_STATIC_TEMPLATE_FUNCTION inline void qt_memrotate270_cachedRead(const SRC *src, int w, int h,
- int sstride,
- DST *dest, int dstride)
+template <class T>
+Q_STATIC_TEMPLATE_FUNCTION
+inline void qt_memrotate270_cachedRead(const T *src, int w, int h, int sstride, T *dest,
+ int dstride)
{
const char *s = reinterpret_cast<const char*>(src);
char *d = reinterpret_cast<char*>(dest);
s += (h - 1) * sstride;
for (int y = h - 1; y >= 0; --y) {
- src = reinterpret_cast<const SRC*>(s);
+ src = reinterpret_cast<const T*>(s);
for (int x = 0; x < w; ++x) {
- DST *destline = reinterpret_cast<DST*>(d + x * dstride);
- destline[h - y - 1] = qt_colorConvert<DST,SRC>(src[x], 0);
+ T *destline = reinterpret_cast<T *>(d + x * dstride);
+ destline[h - y - 1] = src[x];
}
s -= sstride;
}
@@ -90,29 +90,29 @@ Q_STATIC_TEMPLATE_FUNCTION inline void qt_memrotate270_cachedRead(const SRC *src
#if QT_ROTATION_ALGORITHM == QT_ROTATION_CACHEDWRITE
-template <class DST, class SRC>
-Q_STATIC_TEMPLATE_FUNCTION inline void qt_memrotate90_cachedWrite(const SRC *src, int w, int h,
- int sstride,
- DST *dest, int dstride)
+template <class T>
+Q_STATIC_TEMPLATE_FUNCTION
+inline void qt_memrotate90_cachedWrite(const T *src, int w, int h, int sstride, T *dest,
+ int dstride)
{
for (int x = w - 1; x >= 0; --x) {
- DST *d = dest + (w - x - 1) * dstride;
+ T *d = dest + (w - x - 1) * dstride;
for (int y = 0; y < h; ++y) {
- *d++ = qt_colorConvert<DST,SRC>(src[y * sstride + x], 0);
+ *d++ = src[y * sstride + x];
}
}
}
-template <class DST, class SRC>
-Q_STATIC_TEMPLATE_FUNCTION inline void qt_memrotate270_cachedWrite(const SRC *src, int w, int h,
- int sstride,
- DST *dest, int dstride)
+template <class T>
+Q_STATIC_TEMPLATE_FUNCTION
+inline void qt_memrotate270_cachedWrite(const T *src, int w, int h, int sstride, T *dest,
+ int dstride)
{
for (int x = 0; x < w; ++x) {
- DST *d = dest + x * dstride;
+ T *d = dest + x * dstride;
for (int y = h - 1; y >= 0; --y) {
- *d++ = qt_colorConvert<DST,SRC>(src[y * sstride + x], 0);
+ *d++ = src[y * sstride + x];
}
}
}
@@ -123,23 +123,21 @@ Q_STATIC_TEMPLATE_FUNCTION inline void qt_memrotate270_cachedWrite(const SRC *sr
// TODO: packing algorithms should probably be modified on 64-bit architectures
-template <class DST, class SRC>
-Q_STATIC_TEMPLATE_FUNCTION inline void qt_memrotate90_packing(const SRC *src, int w, int h,
- int sstride,
- DST *dest, int dstride)
+template <class T>
+Q_STATIC_TEMPLATE_FUNCTION
+inline void qt_memrotate90_packing(const T *src, int w, int h, int sstride, T *dest, int dstride)
{
- sstride /= sizeof(SRC);
- dstride /= sizeof(DST);
+ sstride /= sizeof(T);
+ dstride /= sizeof(T);
- const int pack = sizeof(quint32) / sizeof(DST);
- const int unaligned = int((long(dest) & (sizeof(quint32)-1))) / sizeof(DST);
+ const int pack = sizeof(quint32) / sizeof(T);
+ const int unaligned = int((long(dest) & (sizeof(quint32)-1))) / sizeof(T);
for (int x = w - 1; x >= 0; --x) {
int y = 0;
for (int i = 0; i < unaligned; ++i) {
- dest[(w - x - 1) * dstride + y]
- = qt_colorConvert<DST,SRC>(src[y * sstride + x], 0);
+ dest[(w - x - 1) * dstride + y] = src[y * sstride + x];
++y;
}
@@ -147,40 +145,36 @@ Q_STATIC_TEMPLATE_FUNCTION inline void qt_memrotate90_packing(const SRC *src, in
+ unaligned);
const int rest = (h - unaligned) % pack;
while (y < h - rest) {
- quint32 c = qt_colorConvert<DST,SRC>(src[y * sstride + x], 0);
+ quint32 c = src[y * sstride + x];
for (int i = 1; i < pack; ++i) {
- c |= qt_colorConvert<DST,SRC>(src[(y + i) * sstride + x], 0)
- << (sizeof(int) * 8 / pack * i);
+ c |= src[(y + i) * sstride + x] << (sizeof(int) * 8 / pack * i);
}
*d++ = c;
y += pack;
}
while (y < h) {
- dest[(w - x - 1) * dstride + y]
- = qt_colorConvert<DST,SRC>(src[y * sstride + x], 0);
+ dest[(w - x - 1) * dstride + y] = src[y * sstride + x];
++y;
}
}
}
-template <class DST, class SRC>
-Q_STATIC_TEMPLATE_FUNCTION inline void qt_memrotate270_packing(const SRC *src, int w, int h,
- int sstride,
- DST *dest, int dstride)
+template <class T>
+Q_STATIC_TEMPLATE_FUNCTION
+inline void qt_memrotate270_packing(const T *src, int w, int h, int sstride, T *dest, int dstride)
{
- sstride /= sizeof(SRC);
- dstride /= sizeof(DST);
+ sstride /= sizeof(T);
+ dstride /= sizeof(T);
- const int pack = sizeof(quint32) / sizeof(DST);
- const int unaligned = int((long(dest) & (sizeof(quint32)-1))) / sizeof(DST);
+ const int pack = sizeof(quint32) / sizeof(T);
+ const int unaligned = int((long(dest) & (sizeof(quint32)-1))) / sizeof(T);
for (int x = 0; x < w; ++x) {
int y = h - 1;
for (int i = 0; i < unaligned; ++i) {
- dest[x * dstride + h - y - 1]
- = qt_colorConvert<DST,SRC>(src[y * sstride + x], 0);
+ dest[x * dstride + h - y - 1] = src[y * sstride + x];
--y;
}
@@ -188,17 +182,15 @@ Q_STATIC_TEMPLATE_FUNCTION inline void qt_memrotate270_packing(const SRC *src, i
+ unaligned);
const int rest = (h - unaligned) % pack;
while (y > rest) {
- quint32 c = qt_colorConvert<DST,SRC>(src[y * sstride + x], 0);
+ quint32 c = src[y * sstride + x];
for (int i = 1; i < pack; ++i) {
- c |= qt_colorConvert<DST,SRC>(src[(y - i) * sstride + x], 0)
- << (sizeof(int) * 8 / pack * i);
+ c |= src[(y - i) * sstride + x] << (sizeof(int) * 8 / pack * i);
}
*d++ = c;
y -= pack;
}
while (y >= 0) {
- dest[x * dstride + h - y - 1]
- = qt_colorConvert<DST,SRC>(src[y * sstride + x], 0);
+ dest[x * dstride + h - y - 1] = src[y * sstride + x];
--y;
}
}
@@ -207,17 +199,16 @@ Q_STATIC_TEMPLATE_FUNCTION inline void qt_memrotate270_packing(const SRC *src, i
#endif // QT_ROTATION_PACKING
#if QT_ROTATION_ALGORITHM == QT_ROTATION_TILED
-template <class DST, class SRC>
-Q_STATIC_TEMPLATE_FUNCTION inline void qt_memrotate90_tiled(const SRC *src, int w, int h,
- int sstride,
- DST *dest, int dstride)
+template <class T>
+Q_STATIC_TEMPLATE_FUNCTION
+inline void qt_memrotate90_tiled(const T *src, int w, int h, int sstride, T *dest, int dstride)
{
- sstride /= sizeof(SRC);
- dstride /= sizeof(DST);
+ sstride /= sizeof(T);
+ dstride /= sizeof(T);
- const int pack = sizeof(quint32) / sizeof(DST);
+ const int pack = sizeof(quint32) / sizeof(T);
const int unaligned =
- qMin(uint((quintptr(dest) & (sizeof(quint32)-1)) / sizeof(DST)), uint(h));
+ qMin(uint((quintptr(dest) & (sizeof(quint32)-1)) / sizeof(T)), uint(h));
const int restX = w % tileSize;
const int restY = (h - unaligned) % tileSize;
const int unoptimizedY = restY % pack;
@@ -230,9 +221,9 @@ Q_STATIC_TEMPLATE_FUNCTION inline void qt_memrotate90_tiled(const SRC *src, int
if (unaligned) {
for (int x = startx; x >= stopx; --x) {
- DST *d = dest + (w - x - 1) * dstride;
+ T *d = dest + (w - x - 1) * dstride;
for (int y = 0; y < unaligned; ++y) {
- *d++ = qt_colorConvert<DST,SRC>(src[y * sstride + x], 0);
+ *d++ = src[y * sstride + x];
}
}
}
@@ -244,10 +235,10 @@ Q_STATIC_TEMPLATE_FUNCTION inline void qt_memrotate90_tiled(const SRC *src, int
for (int x = startx; x >= stopx; --x) {
quint32 *d = reinterpret_cast<quint32*>(dest + (w - x - 1) * dstride + starty);
for (int y = starty; y < stopy; y += pack) {
- quint32 c = qt_colorConvert<DST,SRC>(src[y * sstride + x], 0);
+ quint32 c = src[y * sstride + x];
for (int i = 1; i < pack; ++i) {
const int shift = (sizeof(int) * 8 / pack * i);
- const DST color = qt_colorConvert<DST,SRC>(src[(y + i) * sstride + x], 0);
+ const T color = src[(y + i) * sstride + x];
c |= color << shift;
}
*d++ = c;
@@ -258,19 +249,19 @@ Q_STATIC_TEMPLATE_FUNCTION inline void qt_memrotate90_tiled(const SRC *src, int
if (unoptimizedY) {
const int starty = h - unoptimizedY;
for (int x = startx; x >= stopx; --x) {
- DST *d = dest + (w - x - 1) * dstride + starty;
+ T *d = dest + (w - x - 1) * dstride + starty;
for (int y = starty; y < h; ++y) {
- *d++ = qt_colorConvert<DST,SRC>(src[y * sstride + x], 0);
+ *d++ = src[y * sstride + x];
}
}
}
}
}
-template <class DST, class SRC>
-Q_STATIC_TEMPLATE_FUNCTION inline void qt_memrotate90_tiled_unpacked(const SRC *src, int w, int h,
- int sstride,
- DST *dest, int dstride)
+template <class T>
+Q_STATIC_TEMPLATE_FUNCTION
+inline void qt_memrotate90_tiled_unpacked(const T *src, int w, int h, int sstride, T *dest,
+ int dstride)
{
const int numTilesX = (w + tileSize - 1) / tileSize;
const int numTilesY = (h + tileSize - 1) / tileSize;
@@ -284,10 +275,10 @@ Q_STATIC_TEMPLATE_FUNCTION inline void qt_memrotate90_tiled_unpacked(const SRC *
const int stopy = qMin(starty + tileSize, h);
for (int x = startx; x >= stopx; --x) {
- DST *d = (DST*)((char*)dest + (w - x - 1) * dstride) + starty;
+ T *d = (T *)((char*)dest + (w - x - 1) * dstride) + starty;
const char *s = (const char*)(src + x) + starty * sstride;
for (int y = starty; y < stopy; ++y) {
- *d++ = qt_colorConvert<DST,SRC>(*(const SRC*)(s), 0);
+ *d++ = *(const T *)(s);
s += sstride;
}
}
@@ -295,17 +286,16 @@ Q_STATIC_TEMPLATE_FUNCTION inline void qt_memrotate90_tiled_unpacked(const SRC *
}
}
-template <class DST, class SRC>
-Q_STATIC_TEMPLATE_FUNCTION inline void qt_memrotate270_tiled(const SRC *src, int w, int h,
- int sstride,
- DST *dest, int dstride)
+template <class T>
+Q_STATIC_TEMPLATE_FUNCTION
+inline void qt_memrotate270_tiled(const T *src, int w, int h, int sstride, T *dest, int dstride)
{
- sstride /= sizeof(SRC);
- dstride /= sizeof(DST);
+ sstride /= sizeof(T);
+ dstride /= sizeof(T);
- const int pack = sizeof(quint32) / sizeof(DST);
+ const int pack = sizeof(quint32) / sizeof(T);
const int unaligned =
- qMin(uint((long(dest) & (sizeof(quint32)-1)) / sizeof(DST)), uint(h));
+ qMin(uint((long(dest) & (sizeof(quint32)-1)) / sizeof(T)), uint(h));
const int restX = w % tileSize;
const int restY = (h - unaligned) % tileSize;
const int unoptimizedY = restY % pack;
@@ -318,9 +308,9 @@ Q_STATIC_TEMPLATE_FUNCTION inline void qt_memrotate270_tiled(const SRC *src, int
if (unaligned) {
for (int x = startx; x < stopx; ++x) {
- DST *d = dest + x * dstride;
+ T *d = dest + x * dstride;
for (int y = h - 1; y >= h - unaligned; --y) {
- *d++ = qt_colorConvert<DST,SRC>(src[y * sstride + x], 0);
+ *d++ = src[y * sstride + x];
}
}
}
@@ -333,10 +323,10 @@ Q_STATIC_TEMPLATE_FUNCTION inline void qt_memrotate270_tiled(const SRC *src, int
quint32 *d = reinterpret_cast<quint32*>(dest + x * dstride
+ h - 1 - starty);
for (int y = starty; y > stopy; y -= pack) {
- quint32 c = qt_colorConvert<DST,SRC>(src[y * sstride + x], 0);
+ quint32 c = src[y * sstride + x];
for (int i = 1; i < pack; ++i) {
const int shift = (sizeof(int) * 8 / pack * i);
- const DST color = qt_colorConvert<DST,SRC>(src[(y - i) * sstride + x], 0);
+ const T color = src[(y - i) * sstride + x];
c |= color << shift;
}
*d++ = c;
@@ -346,19 +336,19 @@ Q_STATIC_TEMPLATE_FUNCTION inline void qt_memrotate270_tiled(const SRC *src, int
if (unoptimizedY) {
const int starty = unoptimizedY - 1;
for (int x = startx; x < stopx; ++x) {
- DST *d = dest + x * dstride + h - 1 - starty;
+ T *d = dest + x * dstride + h - 1 - starty;
for (int y = starty; y >= 0; --y) {
- *d++ = qt_colorConvert<DST,SRC>(src[y * sstride + x], 0);
+ *d++ = src[y * sstride + x];
}
}
}
}
}
-template <class DST, class SRC>
-Q_STATIC_TEMPLATE_FUNCTION inline void qt_memrotate270_tiled_unpacked(const SRC *src, int w, int h,
- int sstride,
- DST *dest, int dstride)
+template <class T>
+Q_STATIC_TEMPLATE_FUNCTION
+inline void qt_memrotate270_tiled_unpacked(const T *src, int w, int h, int sstride, T *dest,
+ int dstride)
{
const int numTilesX = (w + tileSize - 1) / tileSize;
const int numTilesY = (h + tileSize - 1) / tileSize;
@@ -372,10 +362,10 @@ Q_STATIC_TEMPLATE_FUNCTION inline void qt_memrotate270_tiled_unpacked(const SRC
const int stopy = qMax(starty - tileSize, 0);
for (int x = startx; x < stopx; ++x) {
- DST *d = (DST*)((char*)dest + x * dstride) + h - 1 - starty;
+ T *d = (T*)((char*)dest + x * dstride) + h - 1 - starty;
const char *s = (const char*)(src + x) + starty * sstride;
for (int y = starty; y >= stopy; --y) {
- *d++ = qt_colorConvert<DST,SRC>(*(const SRC*)s, 0);
+ *d++ = *(const T*)s;
s -= sstride;
}
}
@@ -385,214 +375,112 @@ Q_STATIC_TEMPLATE_FUNCTION inline void qt_memrotate270_tiled_unpacked(const SRC
#endif // QT_ROTATION_ALGORITHM
-template <class DST, class SRC>
-Q_STATIC_TEMPLATE_FUNCTION inline void qt_memrotate90_template(const SRC *src,
- int srcWidth, int srcHeight, int srcStride,
- DST *dest, int dstStride)
+template <class T>
+Q_STATIC_TEMPLATE_FUNCTION
+inline void qt_memrotate90_template(const T *src, int srcWidth, int srcHeight, int srcStride,
+ T *dest, int dstStride)
{
#if QT_ROTATION_ALGORITHM == QT_ROTATION_CACHEDREAD
- qt_memrotate90_cachedRead<DST,SRC>(src, srcWidth, srcHeight, srcStride,
- dest, dstStride);
+ qt_memrotate90_cachedRead<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
#elif QT_ROTATION_ALGORITHM == QT_ROTATION_CACHEDWRITE
- qt_memrotate90_cachedWrite<DST,SRC>(src, srcWidth, srcHeight, srcStride,
- dest, dstStride);
+ qt_memrotate90_cachedWrite<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
#elif QT_ROTATION_ALGORITHM == QT_ROTATION_PACKING
- qt_memrotate90_packing<DST,SRC>(src, srcWidth, srcHeight, srcStride,
- dest, dstStride);
+ qt_memrotate90_packing<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
#elif QT_ROTATION_ALGORITHM == QT_ROTATION_TILED
- qt_memrotate90_tiled<DST,SRC>(src, srcWidth, srcHeight, srcStride,
- dest, dstStride);
+ qt_memrotate90_tiled<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
#endif
}
-template <class DST, class SRC>
-Q_STATIC_TEMPLATE_FUNCTION inline void qt_memrotate180_template(const SRC *src,
- int w, int h, int sstride,
- DST *dest, int dstride)
+template <class T>
+Q_STATIC_TEMPLATE_FUNCTION
+inline void qt_memrotate180_template(const T *src, int w, int h, int sstride, T *dest, int dstride)
{
const char *s = (const char*)(src) + (h - 1) * sstride;
for (int y = h - 1; y >= 0; --y) {
- DST *d = reinterpret_cast<DST*>((char *)(dest) + (h - y - 1) * dstride);
- src = reinterpret_cast<const SRC*>(s);
+ T *d = reinterpret_cast<T*>((char *)(dest) + (h - y - 1) * dstride);
+ src = reinterpret_cast<const T*>(s);
for (int x = w - 1; x >= 0; --x) {
- d[w - x - 1] = qt_colorConvert<DST,SRC>(src[x], 0);
+ d[w - x - 1] = src[x];
}
s -= sstride;
}
}
-template <class DST, class SRC>
-Q_STATIC_TEMPLATE_FUNCTION inline void qt_memrotate270_template(const SRC *src,
- int srcWidth, int srcHeight, int srcStride,
- DST *dest, int dstStride)
+template <class T>
+Q_STATIC_TEMPLATE_FUNCTION
+inline void qt_memrotate270_template(const T *src, int srcWidth, int srcHeight, int srcStride,
+ T *dest, int dstStride)
{
#if QT_ROTATION_ALGORITHM == QT_ROTATION_CACHEDREAD
- qt_memrotate270_cachedRead<DST,SRC>(src, srcWidth, srcHeight, srcStride,
- dest, dstStride);
+ qt_memrotate270_cachedRead<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
#elif QT_ROTATION_ALGORITHM == QT_ROTATION_CACHEDWRITE
- qt_memrotate270_cachedWrite<DST,SRC>(src, srcWidth, srcHeight, srcStride,
- dest, dstStride);
+ qt_memrotate270_cachedWrite<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
#elif QT_ROTATION_ALGORITHM == QT_ROTATION_PACKING
- qt_memrotate270_packing<DST,SRC>(src, srcWidth, srcHeight, srcStride,
- dest, dstStride);
+ qt_memrotate270_packing<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
#elif QT_ROTATION_ALGORITHM == QT_ROTATION_TILED
- qt_memrotate270_tiled_unpacked<DST,SRC>(src, srcWidth, srcHeight,
- srcStride,
- dest, dstStride);
+ qt_memrotate270_tiled_unpacked<T>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
#endif
}
template <>
Q_STATIC_TEMPLATE_SPECIALIZATION
-inline void qt_memrotate90_template<quint24, quint24>(const quint24 *src,
- int srcWidth, int srcHeight, int srcStride,
- quint24 *dest, int dstStride)
+inline void qt_memrotate90_template<quint24>(const quint24 *src, int srcWidth, int srcHeight,
+ int srcStride, quint24 *dest, int dstStride)
{
#if QT_ROTATION_ALGORITHM == QT_ROTATION_CACHEDREAD
- qt_memrotate90_cachedRead<quint24,quint24>(src, srcWidth, srcHeight,
- srcStride, dest, dstStride);
+ qt_memrotate90_cachedRead<quint24>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
#elif QT_ROTATION_ALGORITHM == QT_ROTATION_CACHEDWRITE
- qt_memrotate90_cachedWrite<quint24,quint24>(src, srcWidth, srcHeight,
- srcStride, dest, dstStride);
+ qt_memrotate90_cachedWrite<quint24>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
#elif QT_ROTATION_ALGORITHM == QT_ROTATION_PACKING
// packed algorithm not implemented
- qt_memrotate90_cachedRead<quint24,quint24>(src, srcWidth, srcHeight,
- srcStride, dest, dstStride);
+ qt_memrotate90_cachedRead<quint24>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
#elif QT_ROTATION_ALGORITHM == QT_ROTATION_TILED
// packed algorithm not implemented
- qt_memrotate90_tiled_unpacked<quint24,quint24>(src, srcWidth, srcHeight,
- srcStride, dest, dstStride);
+ qt_memrotate90_tiled_unpacked<quint24>(src, srcWidth, srcHeight, srcStride, dest, dstStride);
#endif
}
-template <>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-inline void qt_memrotate90_template<quint24, quint32>(const quint32 *src,
- int srcWidth, int srcHeight, int srcStride,
- quint24 *dest, int dstStride)
-{
-#if QT_ROTATION_ALGORITHM == QT_ROTATION_CACHEDREAD
- qt_memrotate90_cachedRead<quint24,quint32>(src, srcWidth, srcHeight,
- srcStride, dest, dstStride);
-#elif QT_ROTATION_ALGORITHM == QT_ROTATION_CACHEDWRITE
- qt_memrotate90_cachedWrite<quint24,quint32>(src, srcWidth, srcHeight,
- srcStride, dest, dstStride);
-#elif QT_ROTATION_ALGORITHM == QT_ROTATION_PACKING
- // packed algorithm not implemented
- qt_memrotate90_cachedRead<quint24,quint32>(src, srcWidth, srcHeight,
- srcStride, dest, dstStride);
-#elif QT_ROTATION_ALGORITHM == QT_ROTATION_TILED
- // packed algorithm not implemented
- qt_memrotate90_tiled_unpacked<quint24,quint32>(src, srcWidth, srcHeight,
- srcStride, dest, dstStride);
-#endif
-}
-
-template <>
-Q_STATIC_TEMPLATE_SPECIALIZATION
-inline void qt_memrotate90_template<quint18, quint32>(const quint32 *src,
- int srcWidth, int srcHeight, int srcStride,
- quint18 *dest, int dstStride)
-{
-#if QT_ROTATION_ALGORITHM == QT_ROTATION_CACHEDREAD
- qt_memrotate90_cachedRead<quint18,quint32>(src, srcWidth, srcHeight,
- srcStride, dest, dstStride);
-#elif QT_ROTATION_ALGORITHM == QT_ROTATION_CACHEDWRITE
- qt_memrotate90_cachedWrite<quint18,quint32>(src, srcWidth, srcHeight,
- srcStride, dest, dstStride);
-#elif QT_ROTATION_ALGORITHM == QT_ROTATION_PACKING
- // packed algorithm not implemented
- qt_memrotate90_cachedRead<quint18,quint32>(src, srcWidth, srcHeight,
- srcStride, dest, dstStride);
-#elif QT_ROTATION_ALGORITHM == QT_ROTATION_TILED
- // packed algorithm not implemented
- qt_memrotate90_tiled_unpacked<quint18,quint32>(src, srcWidth, srcHeight,
- srcStride, dest, dstStride);
-#endif
-}
-
-#define QT_IMPL_MEMROTATE(srctype, desttype) \
-Q_GUI_EXPORT void qt_memrotate90(const srctype *src, int w, int h, int sstride, \
- desttype *dest, int dstride) \
+#define QT_IMPL_MEMROTATE(type) \
+Q_GUI_EXPORT void qt_memrotate90(const type *src, int w, int h, int sstride, \
+ type *dest, int dstride) \
{ \
qt_memrotate90_template(src, w, h, sstride, dest, dstride); \
} \
-Q_GUI_EXPORT void qt_memrotate180(const srctype *src, int w, int h, int sstride, \
- desttype *dest, int dstride) \
+Q_GUI_EXPORT void qt_memrotate180(const type *src, int w, int h, int sstride, \
+ type *dest, int dstride) \
{ \
qt_memrotate180_template(src, w, h, sstride, dest, dstride); \
} \
-Q_GUI_EXPORT void qt_memrotate270(const srctype *src, int w, int h, int sstride, \
- desttype *dest, int dstride) \
+Q_GUI_EXPORT void qt_memrotate270(const type *src, int w, int h, int sstride, \
+ type *dest, int dstride) \
{ \
qt_memrotate270_template(src, w, h, sstride, dest, dstride); \
}
-#define QT_IMPL_SIMPLE_MEMROTATE(srctype, desttype) \
-Q_GUI_EXPORT void qt_memrotate90(const srctype *src, int w, int h, int sstride, \
- desttype *dest, int dstride) \
+#define QT_IMPL_SIMPLE_MEMROTATE(type) \
+Q_GUI_EXPORT void qt_memrotate90(const type *src, int w, int h, int sstride, \
+ type *dest, int dstride) \
{ \
- qt_memrotate90_tiled_unpacked<desttype,srctype>(src, w, h, sstride, dest, dstride); \
+ qt_memrotate90_tiled_unpacked<type>(src, w, h, sstride, dest, dstride); \
} \
-Q_GUI_EXPORT void qt_memrotate180(const srctype *src, int w, int h, int sstride, \
- desttype *dest, int dstride) \
+Q_GUI_EXPORT void qt_memrotate180(const type *src, int w, int h, int sstride, \
+ type *dest, int dstride) \
{ \
qt_memrotate180_template(src, w, h, sstride, dest, dstride); \
} \
-Q_GUI_EXPORT void qt_memrotate270(const srctype *src, int w, int h, int sstride, \
- desttype *dest, int dstride) \
+Q_GUI_EXPORT void qt_memrotate270(const type *src, int w, int h, int sstride, \
+ type *dest, int dstride) \
{ \
- qt_memrotate270_tiled_unpacked<desttype,srctype>(src, w, h, sstride, dest, dstride); \
+ qt_memrotate270_tiled_unpacked<type>(src, w, h, sstride, dest, dstride); \
}
-QT_IMPL_MEMROTATE(quint32, quint32)
-QT_IMPL_MEMROTATE(quint32, quint16)
-QT_IMPL_MEMROTATE(quint16, quint32)
-QT_IMPL_MEMROTATE(quint16, quint16)
-QT_IMPL_MEMROTATE(quint24, quint24)
-QT_IMPL_MEMROTATE(quint32, quint24)
-QT_IMPL_MEMROTATE(quint32, quint18)
-QT_IMPL_MEMROTATE(quint32, quint8)
-QT_IMPL_MEMROTATE(quint16, quint8)
-QT_IMPL_MEMROTATE(qrgb444, quint8)
-QT_IMPL_MEMROTATE(quint8, quint8)
-
-#if defined(QT_QWS_ROTATE_BGR)
-QT_IMPL_SIMPLE_MEMROTATE(quint16, qbgr565)
-QT_IMPL_SIMPLE_MEMROTATE(quint32, qbgr565)
-QT_IMPL_SIMPLE_MEMROTATE(qrgb555, qbgr555)
-QT_IMPL_SIMPLE_MEMROTATE(quint32, qbgr555)
-#endif
-
-#ifdef QT_QWS_DEPTH_GENERIC
-QT_IMPL_MEMROTATE(quint32, qrgb_generic16)
-QT_IMPL_MEMROTATE(quint16, qrgb_generic16)
-#endif
-
-struct qrgb_gl_rgba
-{
-public:
- inline qrgb_gl_rgba(quint32 v) {
- if (QSysInfo::ByteOrder == QSysInfo::LittleEndian)
- data = ((v << 16) & 0xff0000) | ((v >> 16) & 0xff) | (v & 0xff00ff00);
- else
- data = (v << 8) | ((v >> 24) & 0xff);
- }
-
- inline operator quint32() const { return data; }
-
-private:
- quint32 data;
-} Q_PACKED;
-
-void Q_GUI_EXPORT qt_memrotate90_gl(const quint32 *src, int srcWidth, int srcHeight, int srcStride,
- quint32 *dest, int dstStride)
-{
- qt_memrotate90_template(src, srcWidth, srcHeight, srcStride, reinterpret_cast<qrgb_gl_rgba *>(dest), dstStride);
-}
+QT_IMPL_MEMROTATE(quint32)
+QT_IMPL_MEMROTATE(quint16)
+QT_IMPL_MEMROTATE(quint24)
+QT_IMPL_MEMROTATE(quint8)
void qt_memrotate90_16(const uchar *srcPixels, int w, int h, int sbpl, uchar *destPixels, int dbpl)
{
diff --git a/src/gui/painting/qmemrotate_p.h b/src/gui/painting/qmemrotate_p.h
index 4c4bc94767..a72310e330 100644
--- a/src/gui/painting/qmemrotate_p.h
+++ b/src/gui/painting/qmemrotate_p.h
@@ -70,37 +70,15 @@ QT_BEGIN_NAMESPACE
#endif
#endif
-#define QT_DECL_MEMROTATE(srctype, desttype) \
- void Q_GUI_EXPORT qt_memrotate90(const srctype*, int, int, int, desttype*, int); \
- void Q_GUI_EXPORT qt_memrotate180(const srctype*, int, int, int, desttype*, int); \
- void Q_GUI_EXPORT qt_memrotate270(const srctype*, int, int, int, desttype*, int)
+#define QT_DECL_MEMROTATE(type) \
+ void Q_GUI_EXPORT qt_memrotate90(const type*, int, int, int, type*, int); \
+ void Q_GUI_EXPORT qt_memrotate180(const type*, int, int, int, type*, int); \
+ void Q_GUI_EXPORT qt_memrotate270(const type*, int, int, int, type*, int)
-void Q_GUI_EXPORT qt_memrotate90(const quint32*, int, int, int, quint32*, int);
-void Q_GUI_EXPORT qt_memrotate180(const quint32*, int, int, int, quint32*, int);
-void Q_GUI_EXPORT qt_memrotate270(const quint32*, int, int, int, quint32*, int);
-
-QT_DECL_MEMROTATE(quint32, quint16);
-QT_DECL_MEMROTATE(quint16, quint32);
-QT_DECL_MEMROTATE(quint16, quint16);
-QT_DECL_MEMROTATE(quint24, quint24);
-QT_DECL_MEMROTATE(quint32, quint24);
-QT_DECL_MEMROTATE(quint32, quint18);
-QT_DECL_MEMROTATE(quint32, quint8);
-QT_DECL_MEMROTATE(quint16, quint8);
-QT_DECL_MEMROTATE(qrgb444, quint8);
-QT_DECL_MEMROTATE(quint8, quint8);
-
-#ifdef QT_QWS_ROTATE_BGR
-QT_DECL_MEMROTATE(quint16, qbgr565);
-QT_DECL_MEMROTATE(quint32, qbgr565);
-QT_DECL_MEMROTATE(qrgb555, qbgr555);
-QT_DECL_MEMROTATE(quint32, qbgr555);
-#endif
-
-#ifdef QT_QWS_DEPTH_GENERIC
-QT_DECL_MEMROTATE(quint32, qrgb_generic16);
-QT_DECL_MEMROTATE(quint16, qrgb_generic16);
-#endif
+QT_DECL_MEMROTATE(quint32);
+QT_DECL_MEMROTATE(quint16);
+QT_DECL_MEMROTATE(quint24);
+QT_DECL_MEMROTATE(quint8);
#undef QT_DECL_MEMROTATE
diff --git a/src/gui/painting/qpathsimplifier.cpp b/src/gui/painting/qpathsimplifier.cpp
new file mode 100644
index 0000000000..fc3ce6361b
--- /dev/null
+++ b/src/gui/painting/qpathsimplifier.cpp
@@ -0,0 +1,1673 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qpathsimplifier_p.h"
+
+#include <QtCore/qvarlengtharray.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qpoint.h>
+#include <QtCore/qalgorithms.h>
+
+#include <math.h>
+
+#include <private/qopengl_p.h>
+#include <private/qrbtree_p.h>
+
+QT_BEGIN_NAMESPACE
+
+#define Q_FIXED_POINT_SCALE 256
+#define Q_TRIANGULATE_END_OF_POLYGON quint32(-1)
+
+
+namespace {
+
+//============================================================================//
+// QPoint //
+//============================================================================//
+
+inline bool operator < (const QPoint &a, const QPoint &b)
+{
+ return a.y() < b.y() || (a.y() == b.y() && a.x() < b.x());
+}
+
+inline bool operator > (const QPoint &a, const QPoint &b)
+{
+ return b < a;
+}
+
+inline bool operator <= (const QPoint &a, const QPoint &b)
+{
+ return !(a > b);
+}
+
+inline bool operator >= (const QPoint &a, const QPoint &b)
+{
+ return !(a < b);
+}
+
+inline int cross(const QPoint &u, const QPoint &v)
+{
+ return u.x() * v.y() - u.y() * v.x();
+}
+
+inline int dot(const QPoint &u, const QPoint &v)
+{
+ return u.x() * v.x() + u.y() * v.y();
+}
+
+//============================================================================//
+// Fraction //
+//============================================================================//
+
+// Fraction must be in the range [0, 1)
+struct Fraction
+{
+ bool isValid() const { return denominator != 0; }
+
+ // numerator and denominator must not have common denominators.
+ unsigned int numerator, denominator;
+};
+
+inline unsigned int gcd(unsigned int x, unsigned int y)
+{
+ while (y != 0) {
+ unsigned int z = y;
+ y = x % y;
+ x = z;
+ }
+ return x;
+}
+
+// Fraction must be in the range [0, 1)
+// Assume input is valid.
+Fraction fraction(unsigned int n, unsigned int d) {
+ Fraction result;
+ if (n == 0) {
+ result.numerator = 0;
+ result.denominator = 1;
+ } else {
+ unsigned int g = gcd(n, d);
+ result.numerator = n / g;
+ result.denominator = d / g;
+ }
+ return result;
+}
+
+//============================================================================//
+// Rational //
+//============================================================================//
+
+struct Rational
+{
+ bool isValid() const { return fraction.isValid(); }
+ int integer;
+ Fraction fraction;
+};
+
+//============================================================================//
+// IntersectionPoint //
+//============================================================================//
+
+struct IntersectionPoint
+{
+ bool isValid() const { return x.fraction.isValid() && y.fraction.isValid(); }
+ QPoint round() const;
+ bool isAccurate() const { return x.fraction.numerator == 0 && y.fraction.numerator == 0; }
+
+ Rational x; // 8:8 signed, 32/32
+ Rational y; // 8:8 signed, 32/32
+};
+
+QPoint IntersectionPoint::round() const
+{
+ QPoint result(x.integer, y.integer);
+ if (2 * x.fraction.numerator >= x.fraction.denominator)
+ ++result.rx();
+ if (2 * y.fraction.numerator >= y.fraction.denominator)
+ ++result.ry();
+ return result;
+}
+
+// Return positive value if 'p' is to the right of the line 'v1'->'v2', negative if left of the
+// line and zero if exactly on the line.
+// The returned value is the z-component of the qCross product between 'v2-v1' and 'p-v1',
+// which is twice the signed area of the triangle 'p'->'v1'->'v2' (positive for CW order).
+inline int pointDistanceFromLine(const QPoint &p, const QPoint &v1, const QPoint &v2)
+{
+ return cross(v2 - v1, p - v1);
+}
+
+IntersectionPoint intersectionPoint(const QPoint &u1, const QPoint &u2,
+ const QPoint &v1, const QPoint &v2)
+{
+ IntersectionPoint result = {{0, {0, 0}}, {0, {0, 0}}};
+
+ QPoint u = u2 - u1;
+ QPoint v = v2 - v1;
+ int d1 = cross(u, v1 - u1);
+ int d2 = cross(u, v2 - u1);
+ int det = d2 - d1;
+ int d3 = cross(v, u1 - v1);
+ int d4 = d3 - det; //qCross(v, u2 - v1);
+
+ // Check that the math is correct.
+ Q_ASSERT(d4 == cross(v, u2 - v1));
+
+ // The intersection point can be expressed as:
+ // v1 - v * d1/det
+ // v2 - v * d2/det
+ // u1 + u * d3/det
+ // u2 + u * d4/det
+
+ // I'm only interested in lines that are crossing, so ignore parallel lines even if they overlap.
+ if (det == 0)
+ return result;
+
+ if (det < 0) {
+ det = -det;
+ d1 = -d1;
+ d2 = -d2;
+ d3 = -d3;
+ d4 = -d4;
+ }
+
+ // I'm only interested in lines intersecting at their interior, not at their end points.
+ // The lines intersect at their interior if and only if 'd1 < 0', 'd2 > 0', 'd3 < 0' and 'd4 > 0'.
+ if (d1 >= 0 || d2 <= 0 || d3 <= 0 || d4 >= 0)
+ return result;
+
+ // Calculate the intersection point as follows:
+ // v1 - v * d1/det | v1 <= v2 (component-wise)
+ // v2 - v * d2/det | v2 < v1 (component-wise)
+
+ // Assuming 16 bits per vector component.
+ if (v.x() >= 0) {
+ result.x.integer = v1.x() + int(qint64(-v.x()) * d1 / det);
+ result.x.fraction = fraction((unsigned int)(qint64(-v.x()) * d1 % det), (unsigned int)det);
+ } else {
+ result.x.integer = v2.x() + int(qint64(-v.x()) * d2 / det);
+ result.x.fraction = fraction((unsigned int)(qint64(-v.x()) * d2 % det), (unsigned int)det);
+ }
+
+ if (v.y() >= 0) {
+ result.y.integer = v1.y() + int(qint64(-v.y()) * d1 / det);
+ result.y.fraction = fraction((unsigned int)(qint64(-v.y()) * d1 % det), (unsigned int)det);
+ } else {
+ result.y.integer = v2.y() + int(qint64(-v.y()) * d2 / det);
+ result.y.fraction = fraction((unsigned int)(qint64(-v.y()) * d2 % det), (unsigned int)det);
+ }
+
+ Q_ASSERT(result.x.fraction.isValid());
+ Q_ASSERT(result.y.fraction.isValid());
+ return result;
+}
+
+//============================================================================//
+// PathSimplifier //
+//============================================================================//
+
+class PathSimplifier
+{
+public:
+ PathSimplifier(const QVectorPath &path, QDataBuffer<QPoint> &vertices,
+ QDataBuffer<quint32> &indices, const QTransform &matrix);
+
+private:
+ struct Element;
+
+ class BoundingVolumeHierarchy
+ {
+ public:
+ struct Node
+ {
+ enum Type
+ {
+ Leaf,
+ Split
+ };
+ Type type;
+ QPoint minimum;
+ QPoint maximum;
+ union {
+ Element *element; // type == Leaf
+ Node *left; // type == Split
+ };
+ Node *right;
+ };
+
+ BoundingVolumeHierarchy();
+ ~BoundingVolumeHierarchy();
+ void allocate(int nodeCount);
+ void free();
+ Node *newNode();
+
+ Node *root;
+ private:
+ void freeNode(Node *n);
+
+ Node *nodeBlock;
+ int blockSize;
+ int firstFree;
+ };
+
+ struct Element
+ {
+ enum Degree
+ {
+ Line = 1,
+ Quadratic = 2,
+ Cubic = 3
+ };
+
+ quint32 &upperIndex() { return indices[pointingUp ? degree : 0]; }
+ quint32 &lowerIndex() { return indices[pointingUp ? 0 : degree]; }
+ quint32 upperIndex() const { return indices[pointingUp ? degree : 0]; }
+ quint32 lowerIndex() const { return indices[pointingUp ? 0 : degree]; }
+ void flip();
+
+ QPoint middle;
+ quint32 indices[4]; // index to points
+ Element *next, *previous; // used in connectElements()
+ int winding; // used in connectElements()
+ union {
+ QRBTree<Element *>::Node *edgeNode; // used in connectElements()
+ BoundingVolumeHierarchy::Node *bvhNode;
+ };
+ Degree degree : 8;
+ uint processed : 1; // initially false, true when the element has been checked for intersections.
+ uint pointingUp : 1; // used in connectElements()
+ uint originallyPointingUp : 1; // used in connectElements()
+ };
+
+ class ElementAllocator
+ {
+ public:
+ ElementAllocator();
+ ~ElementAllocator();
+ void allocate(int count);
+ Element *newElement();
+ private:
+ struct ElementBlock
+ {
+ ElementBlock *next;
+ int blockSize;
+ int firstFree;
+ Element elements[1];
+ } *blocks;
+ };
+
+ struct Event
+ {
+ enum Type { Upper, Lower };
+ bool operator < (const Event &other) const;
+
+ QPoint point;
+ Type type;
+ Element *element;
+ };
+
+ typedef QRBTree<Element *>::Node RBNode;
+ typedef BoundingVolumeHierarchy::Node BVHNode;
+
+ void initElements(const QVectorPath &path, const QTransform &matrix);
+ void removeIntersections();
+ void connectElements();
+ void fillIndices();
+ BVHNode *buildTree(Element **elements, int elementCount);
+ bool intersectNodes(QDataBuffer<Element *> &elements, BVHNode *elementNode, BVHNode *treeNode);
+ bool equalElements(const Element *e1, const Element *e2);
+ bool splitLineAt(QDataBuffer<Element *> &elements, BVHNode *node, quint32 pointIndex, bool processAgain);
+ void appendSeparatingAxes(QVarLengthArray<QPoint, 12> &axes, Element *element);
+ QPair<int, int> calculateSeparatingAxisRange(const QPoint &axis, Element *element);
+ void splitCurve(QDataBuffer<Element *> &elements, BVHNode *node);
+ bool setElementToQuadratic(Element *element, quint32 pointIndex1, const QPoint &ctrl, quint32 pointIndex2);
+ bool setElementToCubic(Element *element, quint32 pointIndex1, const QPoint &ctrl1, const QPoint &ctrl2, quint32 pointIndex2);
+ void setElementToCubicAndSimplify(Element *element, quint32 pointIndex1, const QPoint &ctrl1, const QPoint &ctrl2, quint32 pointIndex2);
+ RBNode *findElementLeftOf(const Element *element, const QPair<RBNode *, RBNode *> &bounds);
+ bool elementIsLeftOf(const Element *left, const Element *right);
+ QPair<RBNode *, RBNode *> outerBounds(const QPoint &point);
+ static bool flattenQuadratic(const QPoint &u, const QPoint &v, const QPoint &w);
+ static bool flattenCubic(const QPoint &u, const QPoint &v, const QPoint &w, const QPoint &q);
+ static bool splitQuadratic(const QPoint &u, const QPoint &v, const QPoint &w, QPoint *result);
+ static bool splitCubic(const QPoint &u, const QPoint &v, const QPoint &w, const QPoint &q, QPoint *result);
+ void subDivQuadratic(const QPoint &u, const QPoint &v, const QPoint &w);
+ void subDivCubic(const QPoint &u, const QPoint &v, const QPoint &w, const QPoint &q);
+ static void sortEvents(Event *events, int count);
+
+ ElementAllocator m_elementAllocator;
+ QDataBuffer<Element *> m_elements;
+ QDataBuffer<QPoint> *m_points;
+ BoundingVolumeHierarchy m_bvh;
+ QDataBuffer<quint32> *m_indices;
+ QRBTree<Element *> m_elementList;
+ uint m_hints;
+};
+
+inline PathSimplifier::BoundingVolumeHierarchy::BoundingVolumeHierarchy()
+ : root(0)
+ , nodeBlock(0)
+ , blockSize(0)
+ , firstFree(0)
+{
+}
+
+inline PathSimplifier::BoundingVolumeHierarchy::~BoundingVolumeHierarchy()
+{
+ free();
+}
+
+inline void PathSimplifier::BoundingVolumeHierarchy::allocate(int nodeCount)
+{
+ Q_ASSERT(nodeBlock == 0);
+ Q_ASSERT(firstFree == 0);
+ nodeBlock = new Node[blockSize = nodeCount];
+}
+
+inline void PathSimplifier::BoundingVolumeHierarchy::free()
+{
+ freeNode(root);
+ delete[] nodeBlock;
+ nodeBlock = 0;
+ firstFree = blockSize = 0;
+ root = 0;
+}
+
+inline PathSimplifier::BVHNode *PathSimplifier::BoundingVolumeHierarchy::newNode()
+{
+ if (firstFree < blockSize)
+ return &nodeBlock[firstFree++];
+ return new Node;
+}
+
+inline void PathSimplifier::BoundingVolumeHierarchy::freeNode(Node *n)
+{
+ if (!n)
+ return;
+ Q_ASSERT(n->type == Node::Split || n->type == Node::Leaf);
+ if (n->type == Node::Split) {
+ freeNode(n->left);
+ freeNode(n->right);
+ }
+ if (!(n >= nodeBlock && n < nodeBlock + blockSize))
+ delete n;
+}
+
+inline PathSimplifier::ElementAllocator::ElementAllocator()
+ : blocks(0)
+{
+}
+
+inline PathSimplifier::ElementAllocator::~ElementAllocator()
+{
+ while (blocks) {
+ ElementBlock *block = blocks;
+ blocks = blocks->next;
+ free(block);
+ }
+}
+
+inline void PathSimplifier::ElementAllocator::allocate(int count)
+{
+ Q_ASSERT(blocks == 0);
+ Q_ASSERT(count > 0);
+ blocks = (ElementBlock *)malloc(sizeof(ElementBlock) + (count - 1) * sizeof(Element));
+ blocks->blockSize = count;
+ blocks->next = 0;
+ blocks->firstFree = 0;
+}
+
+inline PathSimplifier::Element *PathSimplifier::ElementAllocator::newElement()
+{
+ Q_ASSERT(blocks);
+ if (blocks->firstFree < blocks->blockSize)
+ return &blocks->elements[blocks->firstFree++];
+ ElementBlock *oldBlock = blocks;
+ blocks = (ElementBlock *)malloc(sizeof(ElementBlock) + (oldBlock->blockSize - 1) * sizeof(Element));
+ blocks->blockSize = oldBlock->blockSize;
+ blocks->next = oldBlock;
+ blocks->firstFree = 0;
+ return &blocks->elements[blocks->firstFree++];
+}
+
+
+inline bool PathSimplifier::Event::operator < (const Event &other) const
+{
+ if (point == other.point)
+ return type < other.type;
+ return other.point < point;
+}
+
+inline void PathSimplifier::Element::flip()
+{
+ for (int i = 0; i < (degree + 1) >> 1; ++i) {
+ Q_ASSERT(degree >= Line && degree <= Cubic);
+ Q_ASSERT(i >= 0 && i < degree);
+ qSwap(indices[i], indices[degree - i]);
+ }
+ pointingUp = !pointingUp;
+ Q_ASSERT(next == 0 && previous == 0);
+}
+
+PathSimplifier::PathSimplifier(const QVectorPath &path, QDataBuffer<QPoint> &vertices,
+ QDataBuffer<quint32> &indices, const QTransform &matrix)
+ : m_elements(0)
+ , m_points(&vertices)
+ , m_indices(&indices)
+{
+ m_points->reset();
+ m_indices->reset();
+ initElements(path, matrix);
+ if (!m_elements.isEmpty()) {
+ removeIntersections();
+ connectElements();
+ fillIndices();
+ }
+}
+
+void PathSimplifier::initElements(const QVectorPath &path, const QTransform &matrix)
+{
+ m_hints = path.hints();
+ int pathElementCount = path.elementCount();
+ if (pathElementCount == 0)
+ return;
+ m_elements.reserve(2 * pathElementCount);
+ m_elementAllocator.allocate(2 * pathElementCount);
+ m_points->reserve(2 * pathElementCount);
+ const QPainterPath::ElementType *e = path.elements();
+ const qreal *p = path.points();
+ if (e) {
+ qreal x, y;
+ quint32 moveToIndex = 0;
+ quint32 previousIndex = 0;
+ for (int i = 0; i < pathElementCount; ++i, ++e, p += 2) {
+ switch (*e) {
+ case QPainterPath::MoveToElement:
+ {
+ if (!m_points->isEmpty()) {
+ const QPoint &from = m_points->at(previousIndex);
+ const QPoint &to = m_points->at(moveToIndex);
+ if (from != to) {
+ Element *element = m_elementAllocator.newElement();
+ element->degree = Element::Line;
+ element->indices[0] = previousIndex;
+ element->indices[1] = moveToIndex;
+ element->middle.rx() = (from.x() + to.x()) >> 1;
+ element->middle.ry() = (from.y() + to.y()) >> 1;
+ m_elements.add(element);
+ }
+ }
+ previousIndex = moveToIndex = m_points->size();
+ matrix.map(p[0], p[1], &x, &y);
+ QPoint to(qRound(x * Q_FIXED_POINT_SCALE), qRound(y * Q_FIXED_POINT_SCALE));
+ m_points->add(to);
+ }
+ break;
+ case QPainterPath::LineToElement:
+ Q_ASSERT(!m_points->isEmpty());
+ {
+ matrix.map(p[0], p[1], &x, &y);
+ QPoint to(qRound(x * Q_FIXED_POINT_SCALE), qRound(y * Q_FIXED_POINT_SCALE));
+ const QPoint &from = m_points->last();
+ if (to != from) {
+ Element *element = m_elementAllocator.newElement();
+ element->degree = Element::Line;
+ element->indices[0] = previousIndex;
+ element->indices[1] = quint32(m_points->size());
+ element->middle.rx() = (from.x() + to.x()) >> 1;
+ element->middle.ry() = (from.y() + to.y()) >> 1;
+ m_elements.add(element);
+ previousIndex = m_points->size();
+ m_points->add(to);
+ }
+ }
+ break;
+ case QPainterPath::CurveToElement:
+ Q_ASSERT(i + 2 < pathElementCount);
+ Q_ASSERT(!m_points->isEmpty());
+ Q_ASSERT(e[1] == QPainterPath::CurveToDataElement);
+ Q_ASSERT(e[2] == QPainterPath::CurveToDataElement);
+ {
+ quint32 startPointIndex = previousIndex;
+ matrix.map(p[4], p[5], &x, &y);
+ QPoint end(qRound(x * Q_FIXED_POINT_SCALE), qRound(y * Q_FIXED_POINT_SCALE));
+ previousIndex = m_points->size();
+ m_points->add(end);
+
+ // See if this cubic bezier is really quadratic.
+ qreal x1 = p[-2] + qreal(1.5) * (p[0] - p[-2]);
+ qreal y1 = p[-1] + qreal(1.5) * (p[1] - p[-1]);
+ qreal x2 = p[4] + qreal(1.5) * (p[2] - p[4]);
+ qreal y2 = p[5] + qreal(1.5) * (p[3] - p[5]);
+
+ Element *element = m_elementAllocator.newElement();
+ if (qAbs(x1 - x2) < qreal(1e-3) && qAbs(y1 - y2) < qreal(1e-3)) {
+ // The bezier curve is quadratic.
+ matrix.map(x1, y1, &x, &y);
+ QPoint ctrl(qRound(x * Q_FIXED_POINT_SCALE),
+ qRound(y * Q_FIXED_POINT_SCALE));
+ setElementToQuadratic(element, startPointIndex, ctrl, previousIndex);
+ } else {
+ // The bezier curve is cubic.
+ matrix.map(p[0], p[1], &x, &y);
+ QPoint ctrl1(qRound(x * Q_FIXED_POINT_SCALE),
+ qRound(y * Q_FIXED_POINT_SCALE));
+ matrix.map(p[2], p[3], &x, &y);
+ QPoint ctrl2(qRound(x * Q_FIXED_POINT_SCALE),
+ qRound(y * Q_FIXED_POINT_SCALE));
+ setElementToCubicAndSimplify(element, startPointIndex, ctrl1, ctrl2,
+ previousIndex);
+ }
+ m_elements.add(element);
+ }
+ i += 2;
+ e += 2;
+ p += 4;
+
+ break;
+ default:
+ Q_ASSERT_X(0, "QSGPathSimplifier::initialize", "Unexpected element type.");
+ break;
+ }
+ }
+ if (!m_points->isEmpty()) {
+ const QPoint &from = m_points->at(previousIndex);
+ const QPoint &to = m_points->at(moveToIndex);
+ if (from != to) {
+ Element *element = m_elementAllocator.newElement();
+ element->degree = Element::Line;
+ element->indices[0] = previousIndex;
+ element->indices[1] = moveToIndex;
+ element->middle.rx() = (from.x() + to.x()) >> 1;
+ element->middle.ry() = (from.y() + to.y()) >> 1;
+ m_elements.add(element);
+ }
+ }
+ } else {
+ qreal x, y;
+
+ for (int i = 0; i < pathElementCount; ++i, p += 2) {
+ matrix.map(p[0], p[1], &x, &y);
+ QPoint to(qRound(x * Q_FIXED_POINT_SCALE), qRound(y * Q_FIXED_POINT_SCALE));
+ if (to != m_points->last())
+ m_points->add(to);
+ }
+
+ while (!m_points->isEmpty() && m_points->last() == m_points->first())
+ m_points->pop_back();
+
+ if (m_points->isEmpty())
+ return;
+
+ quint32 prev = quint32(m_points->size() - 1);
+ for (int i = 0; i < m_points->size(); ++i) {
+ QPoint &to = m_points->at(i);
+ QPoint &from = m_points->at(prev);
+ Element *element = m_elementAllocator.newElement();
+ element->degree = Element::Line;
+ element->indices[0] = prev;
+ element->indices[1] = quint32(i);
+ element->middle.rx() = (from.x() + to.x()) >> 1;
+ element->middle.ry() = (from.y() + to.y()) >> 1;
+ m_elements.add(element);
+ prev = i;
+ }
+ }
+
+ for (int i = 0; i < m_elements.size(); ++i)
+ m_elements.at(i)->processed = false;
+}
+
+void PathSimplifier::removeIntersections()
+{
+ Q_ASSERT(!m_elements.isEmpty());
+ QDataBuffer<Element *> elements(m_elements.size());
+ for (int i = 0; i < m_elements.size(); ++i)
+ elements.add(m_elements.at(i));
+ m_bvh.allocate(2 * m_elements.size());
+ m_bvh.root = buildTree(elements.data(), elements.size());
+
+ elements.reset();
+ for (int i = 0; i < m_elements.size(); ++i)
+ elements.add(m_elements.at(i));
+
+ while (!elements.isEmpty()) {
+ Element *element = elements.last();
+ elements.pop_back();
+ BVHNode *node = element->bvhNode;
+ Q_ASSERT(node->type == BVHNode::Leaf);
+ Q_ASSERT(node->element == element);
+ if (!element->processed) {
+ if (!intersectNodes(elements, node, m_bvh.root))
+ element->processed = true;
+ }
+ }
+
+ m_bvh.free(); // The bounding volume hierarchy is not needed anymore.
+}
+
+void PathSimplifier::connectElements()
+{
+ Q_ASSERT(!m_elements.isEmpty());
+ QDataBuffer<Event> events(m_elements.size() * 2);
+ for (int i = 0; i < m_elements.size(); ++i) {
+ Element *element = m_elements.at(i);
+ element->next = element->previous = 0;
+ element->winding = 0;
+ element->edgeNode = 0;
+ const QPoint &u = m_points->at(element->indices[0]);
+ const QPoint &v = m_points->at(element->indices[element->degree]);
+ if (u != v) {
+ element->pointingUp = element->originallyPointingUp = v < u;
+
+ Event event;
+ event.element = element;
+ event.point = u;
+ event.type = element->pointingUp ? Event::Lower : Event::Upper;
+ events.add(event);
+ event.point = v;
+ event.type = element->pointingUp ? Event::Upper : Event::Lower;
+ events.add(event);
+ }
+ }
+ QVarLengthArray<Element *, 8> orderedElements;
+ if (!events.isEmpty())
+ sortEvents(events.data(), events.size());
+ while (!events.isEmpty()) {
+ const Event *event = &events.last();
+ QPoint eventPoint = event->point;
+
+ // Find all elements passing through the event point.
+ QPair<RBNode *, RBNode *> bounds = outerBounds(eventPoint);
+
+ // Special case: single element above and single element below event point.
+ int eventCount = events.size();
+ if (event->type == Event::Lower && eventCount > 2) {
+ QPair<RBNode *, RBNode *> range;
+ range.first = bounds.first ? m_elementList.next(bounds.first)
+ : m_elementList.front(m_elementList.root);
+ range.second = bounds.second ? m_elementList.previous(bounds.second)
+ : m_elementList.back(m_elementList.root);
+
+ const Event *event2 = &events.at(eventCount - 2);
+ const Event *event3 = &events.at(eventCount - 3);
+ Q_ASSERT(event2->point == eventPoint); // There are always at least two events at a point.
+ if (range.first == range.second && event2->type == Event::Upper && event3->point != eventPoint) {
+ Element *element = event->element;
+ Element *element2 = event2->element;
+ element->edgeNode->data = event2->element;
+ element2->edgeNode = element->edgeNode;
+ element->edgeNode = 0;
+
+ events.pop_back();
+ events.pop_back();
+
+ if (element2->pointingUp != element->pointingUp)
+ element2->flip();
+ element2->winding = element->winding;
+ int winding = element->winding;
+ if (element->originallyPointingUp)
+ ++winding;
+ if (winding == 0 || winding == 1) {
+ if (element->pointingUp) {
+ element->previous = event2->element;
+ element2->next = event->element;
+ } else {
+ element->next = event2->element;
+ element2->previous = event->element;
+ }
+ }
+ continue;
+ }
+ }
+ orderedElements.clear();
+
+ // First, find the ones above the event point.
+ if (m_elementList.root) {
+ RBNode *current = bounds.first ? m_elementList.next(bounds.first)
+ : m_elementList.front(m_elementList.root);
+ while (current != bounds.second) {
+ Element *element = current->data;
+ Q_ASSERT(element->edgeNode == current);
+ int winding = element->winding;
+ if (element->originallyPointingUp)
+ ++winding;
+ const QPoint &lower = m_points->at(element->lowerIndex());
+ if (lower == eventPoint) {
+ if (winding == 0 || winding == 1)
+ orderedElements.append(current->data);
+ } else {
+ // The element is passing through 'event.point'.
+ Q_ASSERT(m_points->at(element->upperIndex()) != eventPoint);
+ Q_ASSERT(element->degree == Element::Line);
+ // Split the line.
+ Element *eventElement = event->element;
+ int indexIndex = (event->type == Event::Upper) == eventElement->pointingUp
+ ? eventElement->degree : 0;
+ quint32 pointIndex = eventElement->indices[indexIndex];
+ Q_ASSERT(eventPoint == m_points->at(pointIndex));
+
+ Element *upperElement = m_elementAllocator.newElement();
+ *upperElement = *element;
+ upperElement->lowerIndex() = element->upperIndex() = pointIndex;
+ upperElement->edgeNode = 0;
+ element->next = element->previous = 0;
+ if (upperElement->next)
+ upperElement->next->previous = upperElement;
+ else if (upperElement->previous)
+ upperElement->previous->next = upperElement;
+ if (element->pointingUp != element->originallyPointingUp)
+ element->flip();
+ if (winding == 0 || winding == 1)
+ orderedElements.append(upperElement);
+ m_elements.add(upperElement);
+ }
+ current = m_elementList.next(current);
+ }
+ }
+ while (!events.isEmpty() && events.last().point == eventPoint) {
+ event = &events.last();
+ if (event->type == Event::Upper) {
+ Q_ASSERT(event->point == m_points->at(event->element->upperIndex()));
+ RBNode *left = findElementLeftOf(event->element, bounds);
+ RBNode *node = m_elementList.newNode();
+ node->data = event->element;
+ Q_ASSERT(event->element->edgeNode == 0);
+ event->element->edgeNode = node;
+ m_elementList.attachAfter(left, node);
+ } else {
+ Q_ASSERT(event->type == Event::Lower);
+ Q_ASSERT(event->point == m_points->at(event->element->lowerIndex()));
+ Element *element = event->element;
+ Q_ASSERT(element->edgeNode);
+ m_elementList.deleteNode(element->edgeNode);
+ Q_ASSERT(element->edgeNode == 0);
+ }
+ events.pop_back();
+ }
+
+ if (m_elementList.root) {
+ RBNode *current = bounds.first ? m_elementList.next(bounds.first)
+ : m_elementList.front(m_elementList.root);
+ int winding = bounds.first ? bounds.first->data->winding : 0;
+
+ // Calculate winding numbers and flip elements if necessary.
+ while (current != bounds.second) {
+ Element *element = current->data;
+ Q_ASSERT(element->edgeNode == current);
+ int ccw = winding & 1;
+ Q_ASSERT(element->pointingUp == element->originallyPointingUp);
+ if (element->originallyPointingUp) {
+ --winding;
+ } else {
+ ++winding;
+ ccw ^= 1;
+ }
+ element->winding = winding;
+ if (ccw == 0)
+ element->flip();
+ current = m_elementList.next(current);
+ }
+
+ // Pick elements with correct winding number.
+ current = bounds.second ? m_elementList.previous(bounds.second)
+ : m_elementList.back(m_elementList.root);
+ while (current != bounds.first) {
+ Element *element = current->data;
+ Q_ASSERT(element->edgeNode == current);
+ Q_ASSERT(m_points->at(element->upperIndex()) == eventPoint);
+ int winding = element->winding;
+ if (element->originallyPointingUp)
+ ++winding;
+ if (winding == 0 || winding == 1)
+ orderedElements.append(current->data);
+ current = m_elementList.previous(current);
+ }
+ }
+
+ if (!orderedElements.isEmpty()) {
+ Q_ASSERT((orderedElements.size() & 1) == 0);
+ int i = 0;
+ Element *firstElement = orderedElements.at(0);
+ if (m_points->at(firstElement->indices[0]) != eventPoint) {
+ orderedElements.append(firstElement);
+ i = 1;
+ }
+ for (; i < orderedElements.size(); i += 2) {
+ Q_ASSERT(i + 1 < orderedElements.size());
+ Element *next = orderedElements.at(i);
+ Element *previous = orderedElements.at(i + 1);
+ Q_ASSERT(next->previous == 0);
+ Q_ASSERT(previous->next == 0);
+ next->previous = previous;
+ previous->next = next;
+ }
+ }
+ }
+#ifndef QT_NO_DEBUG
+ for (int i = 0; i < m_elements.size(); ++i) {
+ const Element *element = m_elements.at(i);
+ Q_ASSERT(element->next == 0 || element->next->previous == element);
+ Q_ASSERT(element->previous == 0 || element->previous->next == element);
+ Q_ASSERT((element->next == 0) == (element->previous == 0));
+ }
+#endif
+}
+
+void PathSimplifier::fillIndices()
+{
+ for (int i = 0; i < m_elements.size(); ++i)
+ m_elements.at(i)->processed = false;
+ for (int i = 0; i < m_elements.size(); ++i) {
+ Element *element = m_elements.at(i);
+ if (element->processed || element->next == 0)
+ continue;
+ do {
+ m_indices->add(element->indices[0]);
+ switch (element->degree) {
+ case Element::Quadratic:
+ {
+ QPoint pts[] = {
+ m_points->at(element->indices[0]),
+ m_points->at(element->indices[1]),
+ m_points->at(element->indices[2])
+ };
+ subDivQuadratic(pts[0], pts[1], pts[2]);
+ }
+ break;
+ case Element::Cubic:
+ {
+ QPoint pts[] = {
+ m_points->at(element->indices[0]),
+ m_points->at(element->indices[1]),
+ m_points->at(element->indices[2]),
+ m_points->at(element->indices[3])
+ };
+ subDivCubic(pts[0], pts[1], pts[2], pts[3]);
+ }
+ break;
+ default:
+ break;
+ }
+ Q_ASSERT(element->next);
+ element->processed = true;
+ element = element->next;
+ } while (element != m_elements.at(i));
+ m_indices->add(Q_TRIANGULATE_END_OF_POLYGON);
+ }
+}
+
+PathSimplifier::BVHNode *PathSimplifier::buildTree(Element **elements, int elementCount)
+{
+ Q_ASSERT(elementCount > 0);
+ BVHNode *node = m_bvh.newNode();
+ if (elementCount == 1) {
+ Element *element = *elements;
+ element->bvhNode = node;
+ node->type = BVHNode::Leaf;
+ node->element = element;
+ node->minimum = node->maximum = m_points->at(element->indices[0]);
+ for (int i = 1; i <= element->degree; ++i) {
+ const QPoint &p = m_points->at(element->indices[i]);
+ node->minimum.rx() = qMin(node->minimum.x(), p.x());
+ node->minimum.ry() = qMin(node->minimum.y(), p.y());
+ node->maximum.rx() = qMax(node->maximum.x(), p.x());
+ node->maximum.ry() = qMax(node->maximum.y(), p.y());
+ }
+ return node;
+ }
+
+ node->type = BVHNode::Split;
+
+ QPoint minimum, maximum;
+ minimum = maximum = elements[0]->middle;
+
+ for (int i = 1; i < elementCount; ++i) {
+ const QPoint &p = elements[i]->middle;
+ minimum.rx() = qMin(minimum.x(), p.x());
+ minimum.ry() = qMin(minimum.y(), p.y());
+ maximum.rx() = qMax(maximum.x(), p.x());
+ maximum.ry() = qMax(maximum.y(), p.y());
+ }
+
+ int comp, pivot;
+ if (maximum.x() - minimum.x() > maximum.y() - minimum.y()) {
+ comp = 0;
+ pivot = (maximum.x() + minimum.x()) >> 1;
+ } else {
+ comp = 1;
+ pivot = (maximum.y() + minimum.y()) >> 1;
+ }
+
+ int lo = 0;
+ int hi = elementCount - 1;
+ while (lo < hi) {
+ while (lo < hi && (&elements[lo]->middle.rx())[comp] <= pivot)
+ ++lo;
+ while (lo < hi && (&elements[hi]->middle.rx())[comp] > pivot)
+ --hi;
+ if (lo < hi)
+ qSwap(elements[lo], elements[hi]);
+ }
+
+ if (lo == elementCount) {
+ // All points are the same.
+ Q_ASSERT(minimum.x() == maximum.x() && minimum.y() == maximum.y());
+ lo = elementCount >> 1;
+ }
+
+ node->left = buildTree(elements, lo);
+ node->right = buildTree(elements + lo, elementCount - lo);
+
+ const BVHNode *left = node->left;
+ const BVHNode *right = node->right;
+ node->minimum.rx() = qMin(left->minimum.x(), right->minimum.x());
+ node->minimum.ry() = qMin(left->minimum.y(), right->minimum.y());
+ node->maximum.rx() = qMax(left->maximum.x(), right->maximum.x());
+ node->maximum.ry() = qMax(left->maximum.y(), right->maximum.y());
+
+ return node;
+}
+
+bool PathSimplifier::intersectNodes(QDataBuffer<Element *> &elements, BVHNode *elementNode,
+ BVHNode *treeNode)
+{
+ if (elementNode->minimum.x() >= treeNode->maximum.x()
+ || elementNode->minimum.y() >= treeNode->maximum.y()
+ || elementNode->maximum.x() <= treeNode->minimum.x()
+ || elementNode->maximum.y() <= treeNode->minimum.y())
+ {
+ return false;
+ }
+
+ Q_ASSERT(elementNode->type == BVHNode::Leaf);
+ Element *element = elementNode->element;
+ Q_ASSERT(!element->processed);
+
+ if (treeNode->type == BVHNode::Leaf) {
+ Element *nodeElement = treeNode->element;
+ if (!nodeElement->processed)
+ return false;
+
+ if (treeNode->element == elementNode->element)
+ return false;
+
+ if (equalElements(treeNode->element, elementNode->element))
+ return false; // element doesn't split itself.
+
+ if (element->degree == Element::Line && nodeElement->degree == Element::Line) {
+ const QPoint &u1 = m_points->at(element->indices[0]);
+ const QPoint &u2 = m_points->at(element->indices[1]);
+ const QPoint &v1 = m_points->at(nodeElement->indices[0]);
+ const QPoint &v2 = m_points->at(nodeElement->indices[1]);
+ IntersectionPoint intersection = intersectionPoint(u1, u2, v1, v2);
+ if (!intersection.isValid())
+ return false;
+
+ Q_ASSERT(intersection.x.integer >= qMin(u1.x(), u2.x()));
+ Q_ASSERT(intersection.y.integer >= qMin(u1.y(), u2.y()));
+ Q_ASSERT(intersection.x.integer >= qMin(v1.x(), v2.x()));
+ Q_ASSERT(intersection.y.integer >= qMin(v1.y(), v2.y()));
+
+ Q_ASSERT(intersection.x.integer <= qMax(u1.x(), u2.x()));
+ Q_ASSERT(intersection.y.integer <= qMax(u1.y(), u2.y()));
+ Q_ASSERT(intersection.x.integer <= qMax(v1.x(), v2.x()));
+ Q_ASSERT(intersection.y.integer <= qMax(v1.y(), v2.y()));
+
+ m_points->add(intersection.round());
+ splitLineAt(elements, treeNode, m_points->size() - 1, !intersection.isAccurate());
+ return splitLineAt(elements, elementNode, m_points->size() - 1, false);
+ } else {
+ QVarLengthArray<QPoint, 12> axes;
+ appendSeparatingAxes(axes, elementNode->element);
+ appendSeparatingAxes(axes, treeNode->element);
+ for (int i = 0; i < axes.size(); ++i) {
+ QPair<int, int> range1 = calculateSeparatingAxisRange(axes.at(i), elementNode->element);
+ QPair<int, int> range2 = calculateSeparatingAxisRange(axes.at(i), treeNode->element);
+ if (range1.first >= range2.second || range1.second <= range2.first) {
+ return false; // Separating axis found.
+ }
+ }
+ // Bounding areas overlap.
+ if (nodeElement->degree > Element::Line)
+ splitCurve(elements, treeNode);
+ if (element->degree > Element::Line) {
+ splitCurve(elements, elementNode);
+ } else {
+ // The element was not split, so it can be processed further.
+ if (intersectNodes(elements, elementNode, treeNode->left))
+ return true;
+ if (intersectNodes(elements, elementNode, treeNode->right))
+ return true;
+ return false;
+ }
+ return true;
+ }
+ } else {
+ if (intersectNodes(elements, elementNode, treeNode->left))
+ return true;
+ if (intersectNodes(elements, elementNode, treeNode->right))
+ return true;
+ return false;
+ }
+}
+
+bool PathSimplifier::equalElements(const Element *e1, const Element *e2)
+{
+ Q_ASSERT(e1 != e2);
+ if (e1->degree != e2->degree)
+ return false;
+
+ // Possibly equal and in the same direction.
+ bool equalSame = true;
+ for (int i = 0; i <= e1->degree; ++i)
+ equalSame &= m_points->at(e1->indices[i]) == m_points->at(e2->indices[i]);
+
+ // Possibly equal and in opposite directions.
+ bool equalOpposite = true;
+ for (int i = 0; i <= e1->degree; ++i)
+ equalOpposite &= m_points->at(e1->indices[e1->degree - i]) == m_points->at(e2->indices[i]);
+
+ return equalSame || equalOpposite;
+}
+
+bool PathSimplifier::splitLineAt(QDataBuffer<Element *> &elements, BVHNode *node,
+ quint32 pointIndex, bool processAgain)
+{
+ Q_ASSERT(node->type == BVHNode::Leaf);
+ Element *element = node->element;
+ Q_ASSERT(element->degree == Element::Line);
+ const QPoint &u = m_points->at(element->indices[0]);
+ const QPoint &v = m_points->at(element->indices[1]);
+ const QPoint &p = m_points->at(pointIndex);
+ if (u == p || v == p)
+ return false; // No split needed.
+
+ if (processAgain)
+ element->processed = false; // Needs to be processed again.
+
+ Element *first = node->element;
+ Element *second = m_elementAllocator.newElement();
+ *second = *first;
+ first->indices[1] = second->indices[0] = pointIndex;
+ first->middle.rx() = (u.x() + p.x()) >> 1;
+ first->middle.ry() = (u.y() + p.y()) >> 1;
+ second->middle.rx() = (v.x() + p.x()) >> 1;
+ second->middle.ry() = (v.y() + p.y()) >> 1;
+ m_elements.add(second);
+
+ BVHNode *left = m_bvh.newNode();
+ BVHNode *right = m_bvh.newNode();
+ left->type = right->type = BVHNode::Leaf;
+ left->element = first;
+ right->element = second;
+ left->minimum = right->minimum = node->minimum;
+ left->maximum = right->maximum = node->maximum;
+ if (u.x() < v.x())
+ left->maximum.rx() = right->minimum.rx() = p.x();
+ else
+ left->minimum.rx() = right->maximum.rx() = p.x();
+ if (u.y() < v.y())
+ left->maximum.ry() = right->minimum.ry() = p.y();
+ else
+ left->minimum.ry() = right->maximum.ry() = p.y();
+ left->element->bvhNode = left;
+ right->element->bvhNode = right;
+
+ node->type = BVHNode::Split;
+ node->left = left;
+ node->right = right;
+
+ if (!first->processed) {
+ elements.add(left->element);
+ elements.add(right->element);
+ }
+ return true;
+}
+
+void PathSimplifier::appendSeparatingAxes(QVarLengthArray<QPoint, 12> &axes, Element *element)
+{
+ switch (element->degree) {
+ case Element::Cubic:
+ {
+ const QPoint &u = m_points->at(element->indices[0]);
+ const QPoint &v = m_points->at(element->indices[1]);
+ const QPoint &w = m_points->at(element->indices[2]);
+ const QPoint &q = m_points->at(element->indices[3]);
+ QPoint ns[] = {
+ QPoint(u.y() - v.y(), v.x() - u.x()),
+ QPoint(v.y() - w.y(), w.x() - v.x()),
+ QPoint(w.y() - q.y(), q.x() - w.x()),
+ QPoint(q.y() - u.y(), u.x() - q.x()),
+ QPoint(u.y() - w.y(), w.x() - u.x()),
+ QPoint(v.y() - q.y(), q.x() - v.x())
+ };
+ for (int i = 0; i < 6; ++i) {
+ if (ns[i].x() || ns[i].y())
+ axes.append(ns[i]);
+ }
+ }
+ break;
+ case Element::Quadratic:
+ {
+ const QPoint &u = m_points->at(element->indices[0]);
+ const QPoint &v = m_points->at(element->indices[1]);
+ const QPoint &w = m_points->at(element->indices[2]);
+ QPoint ns[] = {
+ QPoint(u.y() - v.y(), v.x() - u.x()),
+ QPoint(v.y() - w.y(), w.x() - v.x()),
+ QPoint(w.y() - u.y(), u.x() - w.x())
+ };
+ for (int i = 0; i < 3; ++i) {
+ if (ns[i].x() || ns[i].y())
+ axes.append(ns[i]);
+ }
+ }
+ break;
+ case Element::Line:
+ {
+ const QPoint &u = m_points->at(element->indices[0]);
+ const QPoint &v = m_points->at(element->indices[1]);
+ QPoint n(u.y() - v.y(), v.x() - u.x());
+ if (n.x() || n.y())
+ axes.append(n);
+ }
+ break;
+ default:
+ Q_ASSERT_X(0, "QSGPathSimplifier::appendSeparatingAxes", "Unexpected element type.");
+ break;
+ }
+}
+
+QPair<int, int> PathSimplifier::calculateSeparatingAxisRange(const QPoint &axis, Element *element)
+{
+ QPair<int, int> range(0x7fffffff, -0x7fffffff);
+ for (int i = 0; i <= element->degree; ++i) {
+ const QPoint &p = m_points->at(element->indices[i]);
+ int dist = dot(axis, p);
+ range.first = qMin(range.first, dist);
+ range.second = qMax(range.second, dist);
+ }
+ return range;
+}
+
+void PathSimplifier::splitCurve(QDataBuffer<Element *> &elements, BVHNode *node)
+{
+ Q_ASSERT(node->type == BVHNode::Leaf);
+
+ Element *first = node->element;
+ Element *second = m_elementAllocator.newElement();
+ *second = *first;
+ m_elements.add(second);
+ Q_ASSERT(first->degree > Element::Line);
+
+ bool accurate = true;
+ const QPoint &u = m_points->at(first->indices[0]);
+ const QPoint &v = m_points->at(first->indices[1]);
+ const QPoint &w = m_points->at(first->indices[2]);
+
+ if (first->degree == Element::Quadratic) {
+ QPoint pts[3];
+ accurate = splitQuadratic(u, v, w, pts);
+ int pointIndex = m_points->size();
+ m_points->add(pts[1]);
+ accurate &= setElementToQuadratic(first, first->indices[0], pts[0], pointIndex);
+ accurate &= setElementToQuadratic(second, pointIndex, pts[2], second->indices[2]);
+ } else {
+ Q_ASSERT(first->degree == Element::Cubic);
+ const QPoint &q = m_points->at(first->indices[3]);
+ QPoint pts[5];
+ accurate = splitCubic(u, v, w, q, pts);
+ int pointIndex = m_points->size();
+ m_points->add(pts[2]);
+ accurate &= setElementToCubic(first, first->indices[0], pts[0], pts[1], pointIndex);
+ accurate &= setElementToCubic(second, pointIndex, pts[3], pts[4], second->indices[3]);
+ }
+
+ if (!accurate)
+ first->processed = second->processed = false; // Needs to be processed again.
+
+ BVHNode *left = m_bvh.newNode();
+ BVHNode *right = m_bvh.newNode();
+ left->type = right->type = BVHNode::Leaf;
+ left->element = first;
+ right->element = second;
+
+ left->minimum.rx() = left->minimum.ry() = right->minimum.rx() = right->minimum.ry() = INT_MAX;
+ left->maximum.rx() = left->maximum.ry() = right->maximum.rx() = right->maximum.ry() = INT_MIN;
+
+ for (int i = 0; i <= first->degree; ++i) {
+ QPoint &p = m_points->at(first->indices[i]);
+ left->minimum.rx() = qMin(left->minimum.x(), p.x());
+ left->minimum.ry() = qMin(left->minimum.y(), p.y());
+ left->maximum.rx() = qMax(left->maximum.x(), p.x());
+ left->maximum.ry() = qMax(left->maximum.y(), p.y());
+ }
+ for (int i = 0; i <= second->degree; ++i) {
+ QPoint &p = m_points->at(second->indices[i]);
+ right->minimum.rx() = qMin(right->minimum.x(), p.x());
+ right->minimum.ry() = qMin(right->minimum.y(), p.y());
+ right->maximum.rx() = qMax(right->maximum.x(), p.x());
+ right->maximum.ry() = qMax(right->maximum.y(), p.y());
+ }
+ left->element->bvhNode = left;
+ right->element->bvhNode = right;
+
+ node->type = BVHNode::Split;
+ node->left = left;
+ node->right = right;
+
+ if (!first->processed) {
+ elements.add(left->element);
+ elements.add(right->element);
+ }
+}
+
+bool PathSimplifier::setElementToQuadratic(Element *element, quint32 pointIndex1,
+ const QPoint &ctrl, quint32 pointIndex2)
+{
+ const QPoint &p1 = m_points->at(pointIndex1);
+ const QPoint &p2 = m_points->at(pointIndex2);
+ if (flattenQuadratic(p1, ctrl, p2)) {
+ // Insert line.
+ element->degree = Element::Line;
+ element->indices[0] = pointIndex1;
+ element->indices[1] = pointIndex2;
+ element->middle.rx() = (p1.x() + p2.x()) >> 1;
+ element->middle.ry() = (p1.y() + p2.y()) >> 1;
+ return false;
+ } else {
+ // Insert bezier.
+ element->degree = Element::Quadratic;
+ element->indices[0] = pointIndex1;
+ element->indices[1] = m_points->size();
+ element->indices[2] = pointIndex2;
+ element->middle.rx() = (p1.x() + ctrl.x() + p2.x()) / 3;
+ element->middle.ry() = (p1.y() + ctrl.y() + p2.y()) / 3;
+ m_points->add(ctrl);
+ return true;
+ }
+}
+
+bool PathSimplifier::setElementToCubic(Element *element, quint32 pointIndex1, const QPoint &v,
+ const QPoint &w, quint32 pointIndex2)
+{
+ const QPoint &u = m_points->at(pointIndex1);
+ const QPoint &q = m_points->at(pointIndex2);
+ if (flattenCubic(u, v, w, q)) {
+ // Insert line.
+ element->degree = Element::Line;
+ element->indices[0] = pointIndex1;
+ element->indices[1] = pointIndex2;
+ element->middle.rx() = (u.x() + q.x()) >> 1;
+ element->middle.ry() = (u.y() + q.y()) >> 1;
+ return false;
+ } else {
+ // Insert bezier.
+ element->degree = Element::Cubic;
+ element->indices[0] = pointIndex1;
+ element->indices[1] = m_points->size();
+ element->indices[2] = m_points->size() + 1;
+ element->indices[3] = pointIndex2;
+ element->middle.rx() = (u.x() + v.x() + w.x() + q.x()) >> 2;
+ element->middle.ry() = (u.y() + v.y() + w.y() + q.y()) >> 2;
+ m_points->add(v);
+ m_points->add(w);
+ return true;
+ }
+}
+
+void PathSimplifier::setElementToCubicAndSimplify(Element *element, quint32 pointIndex1,
+ const QPoint &v, const QPoint &w,
+ quint32 pointIndex2)
+{
+ const QPoint &u = m_points->at(pointIndex1);
+ const QPoint &q = m_points->at(pointIndex2);
+ if (flattenCubic(u, v, w, q)) {
+ // Insert line.
+ element->degree = Element::Line;
+ element->indices[0] = pointIndex1;
+ element->indices[1] = pointIndex2;
+ element->middle.rx() = (u.x() + q.x()) >> 1;
+ element->middle.ry() = (u.y() + q.y()) >> 1;
+ return;
+ }
+
+ bool intersecting = (u == q) || intersectionPoint(u, v, w, q).isValid();
+ if (!intersecting) {
+ // Insert bezier.
+ element->degree = Element::Cubic;
+ element->indices[0] = pointIndex1;
+ element->indices[1] = m_points->size();
+ element->indices[2] = m_points->size() + 1;
+ element->indices[3] = pointIndex2;
+ element->middle.rx() = (u.x() + v.x() + w.x() + q.x()) >> 2;
+ element->middle.ry() = (u.y() + v.y() + w.y() + q.y()) >> 2;
+ m_points->add(v);
+ m_points->add(w);
+ return;
+ }
+
+ QPoint pts[5];
+ splitCubic(u, v, w, q, pts);
+ int pointIndex = m_points->size();
+ m_points->add(pts[2]);
+ Element *element2 = m_elementAllocator.newElement();
+ m_elements.add(element2);
+ setElementToCubicAndSimplify(element, pointIndex1, pts[0], pts[1], pointIndex);
+ setElementToCubicAndSimplify(element2, pointIndex, pts[3], pts[4], pointIndex2);
+}
+
+PathSimplifier::RBNode *PathSimplifier::findElementLeftOf(const Element *element,
+ const QPair<RBNode *, RBNode *> &bounds)
+{
+ if (!m_elementList.root)
+ return 0;
+ RBNode *current = bounds.first;
+ Q_ASSERT(!current || !elementIsLeftOf(element, current->data));
+ if (!current)
+ current = m_elementList.front(m_elementList.root);
+ Q_ASSERT(current);
+ RBNode *result = 0;
+ while (current != bounds.second && !elementIsLeftOf(element, current->data)) {
+ result = current;
+ current = m_elementList.next(current);
+ }
+ return result;
+}
+
+bool PathSimplifier::elementIsLeftOf(const Element *left, const Element *right)
+{
+ const QPoint &leftU = m_points->at(left->upperIndex());
+ const QPoint &leftL = m_points->at(left->lowerIndex());
+ const QPoint &rightU = m_points->at(right->upperIndex());
+ const QPoint &rightL = m_points->at(right->lowerIndex());
+ Q_ASSERT(leftL >= rightU && rightL >= leftU);
+ if (leftU.x() < qMin(rightL.x(), rightU.x()))
+ return true;
+ if (leftU.x() > qMax(rightL.x(), rightU.x()))
+ return false;
+ int d = pointDistanceFromLine(leftU, rightL, rightU);
+ // d < 0: left, d > 0: right, d == 0: on top
+ if (d == 0) {
+ d = pointDistanceFromLine(leftL, rightL, rightU);
+ if (d == 0) {
+ if (right->degree > Element::Line) {
+ d = pointDistanceFromLine(leftL, rightL, m_points->at(right->indices[1]));
+ if (d == 0)
+ d = pointDistanceFromLine(leftL, rightL, m_points->at(right->indices[2]));
+ } else if (left->degree > Element::Line) {
+ d = pointDistanceFromLine(m_points->at(left->indices[1]), rightL, rightU);
+ if (d == 0)
+ d = pointDistanceFromLine(m_points->at(left->indices[2]), rightL, rightU);
+ }
+ }
+ }
+ return d < 0;
+}
+
+QPair<PathSimplifier::RBNode *, PathSimplifier::RBNode *> PathSimplifier::outerBounds(const QPoint &point)
+{
+ RBNode *current = m_elementList.root;
+ QPair<RBNode *, RBNode *> result(0, 0);
+
+ while (current) {
+ const Element *element = current->data;
+ Q_ASSERT(element->edgeNode == current);
+ const QPoint &v1 = m_points->at(element->lowerIndex());
+ const QPoint &v2 = m_points->at(element->upperIndex());
+ Q_ASSERT(point >= v2 && point <= v1);
+ if (point == v1 || point == v2)
+ break;
+ int d = pointDistanceFromLine(point, v1, v2);
+ if (d == 0) {
+ if (element->degree == Element::Line)
+ break;
+ d = pointDistanceFromLine(point, v1, m_points->at(element->indices[1]));
+ if (d == 0)
+ d = pointDistanceFromLine(point, v1, m_points->at(element->indices[2]));
+ Q_ASSERT(d != 0);
+ }
+ if (d < 0) {
+ result.second = current;
+ current = current->left;
+ } else {
+ result.first = current;
+ current = current->right;
+ }
+ }
+
+ if (!current)
+ return result;
+
+ RBNode *mid = current;
+
+ current = mid->left;
+ while (current) {
+ const Element *element = current->data;
+ Q_ASSERT(element->edgeNode == current);
+ const QPoint &v1 = m_points->at(element->lowerIndex());
+ const QPoint &v2 = m_points->at(element->upperIndex());
+ Q_ASSERT(point >= v2 && point <= v1);
+ bool equal = (point == v1 || point == v2);
+ if (!equal) {
+ int d = pointDistanceFromLine(point, v1, v2);
+ Q_ASSERT(d >= 0);
+ equal = (d == 0 && element->degree == Element::Line);
+ }
+ if (equal) {
+ current = current->left;
+ } else {
+ result.first = current;
+ current = current->right;
+ }
+ }
+
+ current = mid->right;
+ while (current) {
+ const Element *element = current->data;
+ Q_ASSERT(element->edgeNode == current);
+ const QPoint &v1 = m_points->at(element->lowerIndex());
+ const QPoint &v2 = m_points->at(element->upperIndex());
+ Q_ASSERT(point >= v2 && point <= v1);
+ bool equal = (point == v1 || point == v2);
+ if (!equal) {
+ int d = pointDistanceFromLine(point, v1, v2);
+ Q_ASSERT(d <= 0);
+ equal = (d == 0 && element->degree == Element::Line);
+ }
+ if (equal) {
+ current = current->right;
+ } else {
+ result.second = current;
+ current = current->left;
+ }
+ }
+
+ return result;
+}
+
+inline bool PathSimplifier::flattenQuadratic(const QPoint &u, const QPoint &v, const QPoint &w)
+{
+ QPoint deltas[2] = { v - u, w - v };
+ int d = qAbs(cross(deltas[0], deltas[1]));
+ int l = qAbs(deltas[0].x()) + qAbs(deltas[0].y()) + qAbs(deltas[1].x()) + qAbs(deltas[1].y());
+ return d < (Q_FIXED_POINT_SCALE * Q_FIXED_POINT_SCALE * 3 / 2) || l <= Q_FIXED_POINT_SCALE * 2;
+}
+
+inline bool PathSimplifier::flattenCubic(const QPoint &u, const QPoint &v,
+ const QPoint &w, const QPoint &q)
+{
+ QPoint deltas[] = { v - u, w - v, q - w, q - u };
+ int d = qAbs(cross(deltas[0], deltas[1])) + qAbs(cross(deltas[1], deltas[2]))
+ + qAbs(cross(deltas[0], deltas[3])) + qAbs(cross(deltas[3], deltas[2]));
+ int l = qAbs(deltas[0].x()) + qAbs(deltas[0].y()) + qAbs(deltas[1].x()) + qAbs(deltas[1].y())
+ + qAbs(deltas[2].x()) + qAbs(deltas[2].y());
+ return d < (Q_FIXED_POINT_SCALE * Q_FIXED_POINT_SCALE * 3) || l <= Q_FIXED_POINT_SCALE * 2;
+}
+
+inline bool PathSimplifier::splitQuadratic(const QPoint &u, const QPoint &v,
+ const QPoint &w, QPoint *result)
+{
+ result[0] = u + v;
+ result[2] = v + w;
+ result[1] = result[0] + result[2];
+ bool accurate = ((result[0].x() | result[0].y() | result[2].x() | result[2].y()) & 1) == 0
+ && ((result[1].x() | result[1].y()) & 3) == 0;
+ result[0].rx() >>= 1;
+ result[0].ry() >>= 1;
+ result[1].rx() >>= 2;
+ result[1].ry() >>= 2;
+ result[2].rx() >>= 1;
+ result[2].ry() >>= 1;
+ return accurate;
+}
+
+inline bool PathSimplifier::splitCubic(const QPoint &u, const QPoint &v,
+ const QPoint &w, const QPoint &q, QPoint *result)
+{
+ result[0] = u + v;
+ result[2] = v + w;
+ result[4] = w + q;
+ result[1] = result[0] + result[2];
+ result[3] = result[2] + result[4];
+ result[2] = result[1] + result[3];
+ bool accurate = ((result[0].x() | result[0].y() | result[4].x() | result[4].y()) & 1) == 0
+ && ((result[1].x() | result[1].y() | result[3].x() | result[3].y()) & 3) == 0
+ && ((result[2].x() | result[2].y()) & 7) == 0;
+ result[0].rx() >>= 1;
+ result[0].ry() >>= 1;
+ result[1].rx() >>= 2;
+ result[1].ry() >>= 2;
+ result[2].rx() >>= 3;
+ result[2].ry() >>= 3;
+ result[3].rx() >>= 2;
+ result[3].ry() >>= 2;
+ result[4].rx() >>= 1;
+ result[4].ry() >>= 1;
+ return accurate;
+}
+
+inline void PathSimplifier::subDivQuadratic(const QPoint &u, const QPoint &v, const QPoint &w)
+{
+ if (flattenQuadratic(u, v, w))
+ return;
+ QPoint pts[3];
+ splitQuadratic(u, v, w, pts);
+ subDivQuadratic(u, pts[0], pts[1]);
+ m_indices->add(m_points->size());
+ m_points->add(pts[1]);
+ subDivQuadratic(pts[1], pts[2], w);
+}
+
+inline void PathSimplifier::subDivCubic(const QPoint &u, const QPoint &v,
+ const QPoint &w, const QPoint &q)
+{
+ if (flattenCubic(u, v, w, q))
+ return;
+ QPoint pts[5];
+ splitCubic(u, v, w, q, pts);
+ subDivCubic(u, pts[0], pts[1], pts[2]);
+ m_indices->add(m_points->size());
+ m_points->add(pts[2]);
+ subDivCubic(pts[2], pts[3], pts[4], q);
+}
+
+void PathSimplifier::sortEvents(Event *events, int count)
+{
+ // Bucket sort + insertion sort.
+ Q_ASSERT(count > 0);
+ QDataBuffer<Event> buffer(count);
+ buffer.resize(count);
+ QScopedArrayPointer<int> bins(new int[count]);
+ int counts[0x101];
+ memset(counts, 0, sizeof(counts));
+
+ int minimum, maximum;
+ minimum = maximum = events[0].point.y();
+ for (int i = 1; i < count; ++i) {
+ minimum = qMin(minimum, events[i].point.y());
+ maximum = qMax(maximum, events[i].point.y());
+ }
+
+ for (int i = 0; i < count; ++i) {
+ bins[i] = ((maximum - events[i].point.y()) << 8) / (maximum - minimum + 1);
+ Q_ASSERT(bins[i] >= 0 && bins[i] < 0x100);
+ ++counts[bins[i]];
+ }
+
+ for (int i = 1; i < 0x100; ++i)
+ counts[i] += counts[i - 1];
+ counts[0x100] = counts[0xff];
+ Q_ASSERT(counts[0x100] == count);
+
+ for (int i = 0; i < count; ++i)
+ buffer.at(--counts[bins[i]]) = events[i];
+
+ int j = 0;
+ for (int i = 0; i < 0x100; ++i) {
+ for (; j < counts[i + 1]; ++j) {
+ int k = j;
+ while (k > 0 && (buffer.at(j) < events[k - 1])) {
+ events[k] = events[k - 1];
+ --k;
+ }
+ events[k] = buffer.at(j);
+ }
+ }
+}
+
+} // end anonymous namespace
+
+
+void qSimplifyPath(const QVectorPath &path, QDataBuffer<QPoint> &vertices,
+ QDataBuffer<quint32> &indices, const QTransform &matrix)
+{
+ PathSimplifier(path, vertices, indices, matrix);
+}
+
+void qSimplifyPath(const QPainterPath &path, QDataBuffer<QPoint> &vertices,
+ QDataBuffer<quint32> &indices, const QTransform &matrix)
+{
+ qSimplifyPath(qtVectorPathForPath(path), vertices, indices, matrix);
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/gui/painting/qpathsimplifier_p.h b/src/gui/painting/qpathsimplifier_p.h
new file mode 100644
index 0000000000..9941bd21f2
--- /dev/null
+++ b/src/gui/painting/qpathsimplifier_p.h
@@ -0,0 +1,68 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QPATHSIMPLIFIER_P_H
+#define QPATHSIMPLIFIER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <QtGui/qpainterpath.h>
+#include <QtGui/private/qdatabuffer_p.h>
+#include <QtGui/private/qvectorpath_p.h>
+
+QT_BEGIN_NAMESPACE
+
+// The returned vertices are in 8:8 fixed point format. The path is assumed to be in the range (-128, 128)x(-128, 128).
+void qSimplifyPath(const QVectorPath &path, QDataBuffer<QPoint> &vertices, QDataBuffer<quint32> &indices, const QTransform &matrix = QTransform());
+void qSimplifyPath(const QPainterPath &path, QDataBuffer<QPoint> &vertices, QDataBuffer<quint32> &indices, const QTransform &matrix = QTransform());
+
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/gui/painting/qstroker.cpp b/src/gui/painting/qstroker.cpp
index ddf828982a..1201a481b6 100644
--- a/src/gui/painting/qstroker.cpp
+++ b/src/gui/painting/qstroker.cpp
@@ -756,7 +756,9 @@ template <class Iterator> bool qt_stroke_side(Iterator *it,
#ifdef QPP_STROKE_DEBUG
qDebug("\n ---> (side) closed subpath");
#endif
- stroker->joinPoints(prev.x, prev.y, *startTangent, stroker->joinStyleMode());
+ // don't join empty subpaths
+ if (!first)
+ stroker->joinPoints(prev.x, prev.y, *startTangent, stroker->joinStyleMode());
return true;
} else {
#ifdef QPP_STROKE_DEBUG
diff --git a/src/gui/text/qabstracttextdocumentlayout.cpp b/src/gui/text/qabstracttextdocumentlayout.cpp
index 2c22b72846..7bf2a631ea 100644
--- a/src/gui/text/qabstracttextdocumentlayout.cpp
+++ b/src/gui/text/qabstracttextdocumentlayout.cpp
@@ -469,7 +469,7 @@ void QAbstractTextDocumentLayout::resizeInlineObject(QTextInlineObject item, int
QSizeF s = handler.iface->intrinsicSize(document(), posInDocument, format);
item.setWidth(s.width());
- item.setAscent(s.height() - 1);
+ item.setAscent(s.height());
item.setDescent(0);
}
diff --git a/src/gui/text/qdistancefield.cpp b/src/gui/text/qdistancefield.cpp
new file mode 100644
index 0000000000..fb06a26c8f
--- /dev/null
+++ b/src/gui/text/qdistancefield.cpp
@@ -0,0 +1,762 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qdistancefield_p.h"
+#include <qmath.h>
+#include <private/qdatabuffer_p.h>
+#include <private/qpathsimplifier_p.h>
+
+QT_BEGIN_NAMESPACE
+
+namespace
+{
+ enum FillHDir
+ {
+ LeftToRight,
+ RightToLeft
+ };
+
+ enum FillVDir
+ {
+ TopDown,
+ BottomUp
+ };
+
+ enum FillClip
+ {
+ NoClip,
+ Clip
+ };
+}
+
+template <FillClip clip, FillHDir dir>
+inline void fillLine(qint32 *, int, int, int, qint32, qint32)
+{
+}
+
+template <>
+inline void fillLine<Clip, LeftToRight>(qint32 *line, int width, int lx, int rx, qint32 d, qint32 dd)
+{
+ int fromX = qMax(0, lx >> 8);
+ int toX = qMin(width, rx >> 8);
+ int x = toX - fromX;
+ if (x <= 0)
+ return;
+ qint32 val = d + (((fromX << 8) + 0xff - lx) * dd >> 8);
+ line += fromX;
+ do {
+ *line = abs(val) < abs(*line) ? val : *line;
+ val += dd;
+ ++line;
+ } while (--x);
+}
+
+template <>
+inline void fillLine<Clip, RightToLeft>(qint32 *line, int width, int lx, int rx, qint32 d, qint32 dd)
+{
+ int fromX = qMax(0, lx >> 8);
+ int toX = qMin(width, rx >> 8);
+ int x = toX - fromX;
+ if (x <= 0)
+ return;
+ qint32 val = d + (((toX << 8) + 0xff - rx) * dd >> 8);
+ line += toX;
+ do {
+ val -= dd;
+ --line;
+ *line = abs(val) < abs(*line) ? val : *line;
+ } while (--x);
+}
+
+template <>
+inline void fillLine<NoClip, LeftToRight>(qint32 *line, int, int lx, int rx, qint32 d, qint32 dd)
+{
+ int fromX = lx >> 8;
+ int toX = rx >> 8;
+ int x = toX - fromX;
+ if (x <= 0)
+ return;
+ qint32 val = d + ((~lx & 0xff) * dd >> 8);
+ line += fromX;
+ do {
+ *line = abs(val) < abs(*line) ? val : *line;
+ val += dd;
+ ++line;
+ } while (--x);
+}
+
+template <>
+inline void fillLine<NoClip, RightToLeft>(qint32 *line, int, int lx, int rx, qint32 d, qint32 dd)
+{
+ int fromX = lx >> 8;
+ int toX = rx >> 8;
+ int x = toX - fromX;
+ if (x <= 0)
+ return;
+ qint32 val = d + ((~rx & 0xff) * dd >> 8);
+ line += toX;
+ do {
+ val -= dd;
+ --line;
+ *line = abs(val) < abs(*line) ? val : *line;
+ } while (--x);
+}
+
+template <FillClip clip, FillVDir vDir, FillHDir hDir>
+inline void fillLines(qint32 *bits, int width, int height, int upperY, int lowerY,
+ int &lx, int ldx, int &rx, int rdx, qint32 &d, qint32 ddy, qint32 ddx)
+{
+ Q_UNUSED(height);
+ Q_ASSERT(upperY < lowerY);
+ int y = lowerY - upperY;
+ if (vDir == TopDown) {
+ qint32 *line = bits + upperY * width;
+ do {
+ fillLine<clip, hDir>(line, width, lx, rx, d, ddx);
+ lx += ldx;
+ d += ddy;
+ rx += rdx;
+ line += width;
+ } while (--y);
+ } else {
+ qint32 *line = bits + lowerY * width;
+ do {
+ lx -= ldx;
+ d -= ddy;
+ rx -= rdx;
+ line -= width;
+ fillLine<clip, hDir>(line, width, lx, rx, d, ddx);
+ } while (--y);
+ }
+}
+
+template <FillClip clip>
+void drawTriangle(qint32 *bits, int width, int height, const QPoint *center,
+ const QPoint *v1, const QPoint *v2, qint32 value)
+{
+ const int y1 = clip == Clip ? qBound(0, v1->y() >> 8, height) : v1->y() >> 8;
+ const int y2 = clip == Clip ? qBound(0, v2->y() >> 8, height) : v2->y() >> 8;
+ const int yC = clip == Clip ? qBound(0, center->y() >> 8, height) : center->y() >> 8;
+
+ const int v1Frac = clip == Clip ? (y1 << 8) + 0xff - v1->y() : ~v2->y() & 0xff;
+ const int v2Frac = clip == Clip ? (y2 << 8) + 0xff - v2->y() : ~v1->y() & 0xff;
+ const int centerFrac = clip == Clip ? (yC << 8) + 0xff - center->y() : ~center->y() & 0xff;
+
+ int dx1 = 0, x1 = 0, dx2 = 0, x2 = 0;
+ qint32 dd1, d1, dd2, d2;
+ if (v1->y() != center->y()) {
+ dx1 = ((v1->x() - center->x()) << 8) / (v1->y() - center->y());
+ x1 = center->x() + centerFrac * (v1->x() - center->x()) / (v1->y() - center->y());
+ }
+ if (v2->y() != center->y()) {
+ dx2 = ((v2->x() - center->x()) << 8) / (v2->y() - center->y());
+ x2 = center->x() + centerFrac * (v2->x() - center->x()) / (v2->y() - center->y());
+ }
+
+ const qint32 div = (v2->x() - center->x()) * (v1->y() - center->y())
+ - (v2->y() - center->y()) * (v1->x() - center->x());
+ const qint32 dd = div ? qint32((qint64(value * (v1->y() - v2->y())) << 8) / div) : 0;
+
+ if (y2 < yC) {
+ if (y1 < yC) {
+ // Center at the bottom.
+ if (y2 < y1) {
+ // y2 < y1 < yC
+ // Long right edge.
+ d1 = centerFrac * value / (v1->y() - center->y());
+ dd1 = ((value << 8) / (v1->y() - center->y()));
+ fillLines<clip, BottomUp, LeftToRight>(bits, width, height, y1, yC, x1, dx1,
+ x2, dx2, d1, dd1, dd);
+ dx1 = ((v1->x() - v2->x()) << 8) / (v1->y() - v2->y());
+ x1 = v1->x() + v1Frac * (v1->x() - v2->x()) / (v1->y() - v2->y());
+ fillLines<clip, BottomUp, LeftToRight>(bits, width, height, y2, y1, x1, dx1,
+ x2, dx2, value, 0, dd);
+ } else {
+ // y1 <= y2 < yC
+ // Long left edge.
+ d2 = centerFrac * value / (v2->y() - center->y());
+ dd2 = ((value << 8) / (v2->y() - center->y()));
+ fillLines<clip, BottomUp, RightToLeft>(bits, width, height, y2, yC, x1, dx1,
+ x2, dx2, d2, dd2, dd);
+ if (y1 != y2) {
+ dx2 = ((v1->x() - v2->x()) << 8) / (v1->y() - v2->y());
+ x2 = v2->x() + v2Frac * (v1->x() - v2->x()) / (v1->y() - v2->y());
+ fillLines<clip, BottomUp, RightToLeft>(bits, width, height, y1, y2, x1, dx1,
+ x2, dx2, value, 0, dd);
+ }
+ }
+ } else {
+ // y2 < yC <= y1
+ // Center to the right.
+ int dx = ((v1->x() - v2->x()) << 8) / (v1->y() - v2->y());
+ int xUp, xDn;
+ xUp = xDn = v2->x() + (clip == Clip ? (yC << 8) + 0xff - v2->y()
+ : (center->y() | 0xff) - v2->y())
+ * (v1->x() - v2->x()) / (v1->y() - v2->y());
+ fillLines<clip, BottomUp, LeftToRight>(bits, width, height, y2, yC, xUp, dx,
+ x2, dx2, value, 0, dd);
+ if (yC != y1)
+ fillLines<clip, TopDown, LeftToRight>(bits, width, height, yC, y1, xDn, dx,
+ x1, dx1, value, 0, dd);
+ }
+ } else {
+ if (y1 < yC) {
+ // y1 < yC <= y2
+ // Center to the left.
+ int dx = ((v1->x() - v2->x()) << 8) / (v1->y() - v2->y());
+ int xUp, xDn;
+ xUp = xDn = v1->x() + (clip == Clip ? (yC << 8) + 0xff - v1->y()
+ : (center->y() | 0xff) - v1->y())
+ * (v1->x() - v2->x()) / (v1->y() - v2->y());
+ fillLines<clip, BottomUp, RightToLeft>(bits, width, height, y1, yC, x1, dx1,
+ xUp, dx, value, 0, dd);
+ if (yC != y2)
+ fillLines<clip, TopDown, RightToLeft>(bits, width, height, yC, y2, x2, dx2,
+ xDn, dx, value, 0, dd);
+ } else {
+ // Center at the top.
+ if (y2 < y1) {
+ // yC <= y2 < y1
+ // Long right edge.
+ if (yC != y2) {
+ d2 = centerFrac * value / (v2->y() - center->y());
+ dd2 = ((value << 8) / (v2->y() - center->y()));
+ fillLines<clip, TopDown, LeftToRight>(bits, width, height, yC, y2, x2, dx2,
+ x1, dx1, d2, dd2, dd);
+ }
+ dx2 = ((v1->x() - v2->x()) << 8) / (v1->y() - v2->y());
+ x2 = v2->x() + v2Frac * (v1->x() - v2->x()) / (v1->y() - v2->y());
+ fillLines<clip, TopDown, LeftToRight>(bits, width, height, y2, y1, x2, dx2,
+ x1, dx1, value, 0, dd);
+ } else {
+ // Long left edge.
+ // yC <= y1 <= y2
+ if (yC != y1) {
+ d1 = centerFrac * value / (v1->y() - center->y());
+ dd1 = ((value << 8) / (v1->y() - center->y()));
+ fillLines<clip, TopDown, RightToLeft>(bits, width, height, yC, y1, x2, dx2,
+ x1, dx1, d1, dd1, dd);
+ }
+ if (y1 != y2) {
+ dx1 = ((v1->x() - v2->x()) << 8) / (v1->y() - v2->y());
+ x1 = v1->x() + v1Frac * (v1->x() - v2->x()) / (v1->y() - v2->y());
+ fillLines<clip, TopDown, RightToLeft>(bits, width, height, y1, y2, x2, dx2,
+ x1, dx1, value, 0, dd);
+ }
+ }
+ }
+ }
+}
+
+template <FillClip clip>
+void drawRectangle(qint32 *bits, int width, int height,
+ const QPoint *int1, const QPoint *center1, const QPoint *ext1,
+ const QPoint *int2, const QPoint *center2, const QPoint *ext2,
+ qint32 extValue)
+{
+ if (center1->y() > center2->y()) {
+ qSwap(center1, center2);
+ qSwap(int1, ext2);
+ qSwap(ext1, int2);
+ extValue = -extValue;
+ }
+
+ Q_ASSERT(ext1->x() - center1->x() == center1->x() - int1->x());
+ Q_ASSERT(ext1->y() - center1->y() == center1->y() - int1->y());
+ Q_ASSERT(ext2->x() - center2->x() == center2->x() - int2->x());
+ Q_ASSERT(ext2->y() - center2->y() == center2->y() - int2->y());
+
+ const int yc1 = clip == Clip ? qBound(0, center1->y() >> 8, height) : center1->y() >> 8;
+ const int yc2 = clip == Clip ? qBound(0, center2->y() >> 8, height) : center2->y() >> 8;
+ const int yi1 = clip == Clip ? qBound(0, int1->y() >> 8, height) : int1->y() >> 8;
+ const int yi2 = clip == Clip ? qBound(0, int2->y() >> 8, height) : int2->y() >> 8;
+ const int ye1 = clip == Clip ? qBound(0, ext1->y() >> 8, height) : ext1->y() >> 8;
+ const int ye2 = clip == Clip ? qBound(0, ext2->y() >> 8, height) : ext2->y() >> 8;
+
+ const int center1Frac = clip == Clip ? (yc1 << 8) + 0xff - center1->y() : ~center1->y() & 0xff;
+ const int center2Frac = clip == Clip ? (yc2 << 8) + 0xff - center2->y() : ~center2->y() & 0xff;
+ const int int1Frac = clip == Clip ? (yi1 << 8) + 0xff - int1->y() : ~int1->y() & 0xff;
+ const int ext1Frac = clip == Clip ? (ye1 << 8) + 0xff - ext1->y() : ~ext1->y() & 0xff;
+
+ int dxC = 0, dxE = 0; // cap slope, edge slope
+ qint32 ddC = 0;
+ if (ext1->y() != int1->y()) {
+ dxC = ((ext1->x() - int1->x()) << 8) / (ext1->y() - int1->y());
+ ddC = (extValue << 9) / (ext1->y() - int1->y());
+ }
+ if (ext1->y() != ext2->y())
+ dxE = ((ext1->x() - ext2->x()) << 8) / (ext1->y() - ext2->y());
+
+ const qint32 div = (ext1->x() - int1->x()) * (ext2->y() - int1->y())
+ - (ext1->y() - int1->y()) * (ext2->x() - int1->x());
+ const qint32 dd = div ? qint32((qint64(extValue * (ext2->y() - ext1->y())) << 9) / div) : 0;
+
+ int xe1, xe2, xc1, xc2;
+ qint32 d;
+
+ qint32 intValue = -extValue;
+
+ if (center2->x() < center1->x()) {
+ // Leaning to the right. '/'
+ if (int1->y() < ext2->y()) {
+ // Mostly vertical.
+ Q_ASSERT(ext1->y() != ext2->y());
+ xe1 = ext1->x() + ext1Frac * (ext1->x() - ext2->x()) / (ext1->y() - ext2->y());
+ xe2 = int1->x() + int1Frac * (ext1->x() - ext2->x()) / (ext1->y() - ext2->y());
+ if (ye1 != yi1) {
+ xc2 = center1->x() + center1Frac * (ext1->x() - int1->x()) / (ext1->y() - int1->y());
+ xc2 += (ye1 - yc1) * dxC;
+ fillLines<clip, TopDown, LeftToRight>(bits, width, height, ye1, yi1, xe1, dxE,
+ xc2, dxC, extValue, 0, dd);
+ }
+ if (yi1 != ye2)
+ fillLines<clip, TopDown, LeftToRight>(bits, width, height, yi1, ye2, xe1, dxE,
+ xe2, dxE, extValue, 0, dd);
+ if (ye2 != yi2) {
+ xc1 = center2->x() + center2Frac * (ext1->x() - int1->x()) / (ext1->y() - int1->y());
+ xc1 += (ye2 - yc2) * dxC;
+ fillLines<clip, TopDown, RightToLeft>(bits, width, height, ye2, yi2, xc1, dxC,
+ xe2, dxE, intValue, 0, dd);
+ }
+ } else {
+ // Mostly horizontal.
+ Q_ASSERT(ext1->y() != int1->y());
+ xc1 = center2->x() + center2Frac * (ext1->x() - int1->x()) / (ext1->y() - int1->y());
+ xc2 = center1->x() + center1Frac * (ext1->x() - int1->x()) / (ext1->y() - int1->y());
+ xc1 += (ye2 - yc2) * dxC;
+ xc2 += (ye1 - yc1) * dxC;
+ if (ye1 != ye2) {
+ xe1 = ext1->x() + ext1Frac * (ext1->x() - ext2->x()) / (ext1->y() - ext2->y());
+ fillLines<clip, TopDown, LeftToRight>(bits, width, height, ye1, ye2, xe1, dxE,
+ xc2, dxC, extValue, 0, dd);
+ }
+ if (ye2 != yi1) {
+ d = (clip == Clip ? (ye2 << 8) + 0xff - center2->y()
+ : (ext2->y() | 0xff) - center2->y())
+ * 2 * extValue / (ext1->y() - int1->y());
+ fillLines<clip, TopDown, LeftToRight>(bits, width, height, ye2, yi1, xc1, dxC,
+ xc2, dxC, d, ddC, dd);
+ }
+ if (yi1 != yi2) {
+ xe2 = int1->x() + int1Frac * (ext1->x() - ext2->x()) / (ext1->y() - ext2->y());
+ fillLines<clip, TopDown, RightToLeft>(bits, width, height, yi1, yi2, xc1, dxC,
+ xe2, dxE, intValue, 0, dd);
+ }
+ }
+ } else {
+ // Leaning to the left. '\'
+ if (ext1->y() < int2->y()) {
+ // Mostly vertical.
+ Q_ASSERT(ext1->y() != ext2->y());
+ xe1 = ext1->x() + ext1Frac * (ext1->x() - ext2->x()) / (ext1->y() - ext2->y());
+ xe2 = int1->x() + int1Frac * (ext1->x() - ext2->x()) / (ext1->y() - ext2->y());
+ if (yi1 != ye1) {
+ xc1 = center1->x() + center1Frac * (ext1->x() - int1->x()) / (ext1->y() - int1->y());
+ xc1 += (yi1 - yc1) * dxC;
+ fillLines<clip, TopDown, RightToLeft>(bits, width, height, yi1, ye1, xc1, dxC,
+ xe2, dxE, intValue, 0, dd);
+ }
+ if (ye1 != yi2)
+ fillLines<clip, TopDown, RightToLeft>(bits, width, height, ye1, yi2, xe1, dxE,
+ xe2, dxE, intValue, 0, dd);
+ if (yi2 != ye2) {
+ xc2 = center2->x() + center2Frac * (ext1->x() - int1->x()) / (ext1->y() - int1->y());
+ xc2 += (yi2 - yc2) * dxC;
+ fillLines<clip, TopDown, LeftToRight>(bits, width, height, yi2, ye2, xe1, dxE,
+ xc2, dxC, extValue, 0, dd);
+ }
+ } else {
+ // Mostly horizontal.
+ Q_ASSERT(ext1->y() != int1->y());
+ xc1 = center1->x() + center1Frac * (ext1->x() - int1->x()) / (ext1->y() - int1->y());
+ xc2 = center2->x() + center2Frac * (ext1->x() - int1->x()) / (ext1->y() - int1->y());
+ xc1 += (yi1 - yc1) * dxC;
+ xc2 += (yi2 - yc2) * dxC;
+ if (yi1 != yi2) {
+ xe2 = int1->x() + int1Frac * (ext1->x() - ext2->x()) / (ext1->y() - ext2->y());
+ fillLines<clip, TopDown, RightToLeft>(bits, width, height, yi1, yi2, xc1, dxC,
+ xe2, dxE, intValue, 0, dd);
+ }
+ if (yi2 != ye1) {
+ d = (clip == Clip ? (yi2 << 8) + 0xff - center2->y()
+ : (int2->y() | 0xff) - center2->y())
+ * 2 * extValue / (ext1->y() - int1->y());
+ fillLines<clip, TopDown, RightToLeft>(bits, width, height, yi2, ye1, xc1, dxC,
+ xc2, dxC, d, ddC, dd);
+ }
+ if (ye1 != ye2) {
+ xe1 = ext1->x() + ext1Frac * (ext1->x() - ext2->x()) / (ext1->y() - ext2->y());
+ fillLines<clip, TopDown, LeftToRight>(bits, width, height, ye1, ye2, xe1, dxE,
+ xc2, dxC, extValue, 0, dd);
+ }
+ }
+ }
+}
+
+static void drawPolygons(qint32 *bits, int width, int height, const QPoint *vertices,
+ const quint32 *indices, int indexCount, qint32 value)
+{
+ Q_ASSERT(indexCount != 0);
+ Q_ASSERT(height <= 128);
+ QVarLengthArray<quint8, 16> scans[128];
+ int first = 0;
+ for (int i = 1; i < indexCount; ++i) {
+ quint32 idx1 = indices[i - 1];
+ quint32 idx2 = indices[i];
+ Q_ASSERT(idx1 != quint32(-1));
+ if (idx2 == quint32(-1)) {
+ idx2 = indices[first];
+ Q_ASSERT(idx2 != quint32(-1));
+ first = ++i;
+ }
+ const QPoint *v1 = &vertices[idx1];
+ const QPoint *v2 = &vertices[idx2];
+ if (v2->y() < v1->y())
+ qSwap(v1, v2);
+ int fromY = qMax(0, v1->y() >> 8);
+ int toY = qMin(height, v2->y() >> 8);
+ if (fromY >= toY)
+ continue;
+ int dx = ((v2->x() - v1->x()) << 8) / (v2->y() - v1->y());
+ int x = v1->x() + ((fromY << 8) + 0xff - v1->y()) * (v2->x() - v1->x()) / (v2->y() - v1->y());
+ for (int y = fromY; y < toY; ++y) {
+ quint32 c = quint32(x >> 8);
+ if (c < quint32(width))
+ scans[y].append(quint8(c));
+ x += dx;
+ }
+ }
+ for (int i = 0; i < height; ++i) {
+ quint8 *scanline = scans[i].data();
+ int size = scans[i].size();
+ for (int j = 1; j < size; ++j) {
+ int k = j;
+ quint8 value = scanline[k];
+ for (; k != 0 && value < scanline[k - 1]; --k)
+ scanline[k] = scanline[k - 1];
+ scanline[k] = value;
+ }
+ qint32 *line = bits + i * width;
+ int j = 0;
+ for (; j + 1 < size; j += 2) {
+ for (quint8 x = scanline[j]; x < scanline[j + 1]; ++x)
+ line[x] = value;
+ }
+ if (j < size) {
+ for (int x = scanline[j]; x < width; ++x)
+ line[x] = value;
+ }
+ }
+}
+
+static QImage makeDistanceField(int imgSize, const QPainterPath &path, int dfScale, int offs)
+{
+ QImage image(imgSize, imgSize, QImage::Format_Indexed8);
+
+ if (path.isEmpty()) {
+ image.fill(0);
+ return image;
+ }
+
+ QTransform transform;
+ transform.translate(offs, offs);
+ transform.scale(qreal(1) / dfScale, qreal(1) / dfScale);
+
+ QDataBuffer<quint32> pathIndices(0);
+ QDataBuffer<QPoint> pathVertices(0);
+ qSimplifyPath(path, pathVertices, pathIndices, transform);
+
+ const qint32 interiorColor = -0x7f80; // 8:8 signed format, -127.5
+ const qint32 exteriorColor = 0x7f80; // 8:8 signed format, 127.5
+
+ QScopedArrayPointer<qint32> bits(new qint32[imgSize * imgSize]);
+ for (int i = 0; i < imgSize * imgSize; ++i)
+ bits[i] = exteriorColor;
+
+ const qreal angleStep = qreal(15 * 3.141592653589793238 / 180);
+ const QPoint rotation(qRound(cos(angleStep) * 0x4000),
+ qRound(sin(angleStep) * 0x4000)); // 2:14 signed
+
+ const quint32 *indices = pathIndices.data();
+ QVarLengthArray<QPoint> normals;
+ QVarLengthArray<QPoint> vertices;
+ QVarLengthArray<bool> isConvex;
+ QVarLengthArray<bool> needsClipping;
+
+ drawPolygons(bits.data(), imgSize, imgSize, pathVertices.data(), indices, pathIndices.size(),
+ interiorColor);
+
+ int index = 0;
+
+ while (index < pathIndices.size()) {
+ normals.clear();
+ vertices.clear();
+ needsClipping.clear();
+
+ // Find end of polygon.
+ int end = index;
+ while (indices[end] != quint32(-1))
+ ++end;
+
+ // Calculate vertex normals.
+ for (int next = index, prev = end - 1; next < end; prev = next++) {
+ quint32 fromVertexIndex = indices[prev];
+ quint32 toVertexIndex = indices[next];
+
+ const QPoint &from = pathVertices.at(fromVertexIndex);
+ const QPoint &to = pathVertices.at(toVertexIndex);
+
+ QPoint n(to.y() - from.y(), from.x() - to.x());
+ if (n.x() == 0 && n.y() == 0)
+ continue;
+ int scale = qRound((offs << 16) / sqrt(qreal(n.x() * n.x() + n.y() * n.y()))); // 8:16
+ n.rx() = n.x() * scale >> 8;
+ n.ry() = n.y() * scale >> 8;
+ normals.append(n);
+ QPoint v(to.x() + 0x7f, to.y() + 0x7f);
+ vertices.append(v);
+ needsClipping.append((to.x() < offs << 8) || (to.x() >= (imgSize - offs) << 8)
+ || (to.y() < offs << 8) || (to.y() >= (imgSize - offs) << 8));
+ }
+
+ isConvex.resize(normals.count());
+ for (int next = 0, prev = normals.count() - 1; next < normals.count(); prev = next++) {
+ isConvex[prev] = normals.at(prev).x() * normals.at(next).y()
+ - normals.at(prev).y() * normals.at(next).x() < 0;
+ }
+
+ // Draw quads.
+ for (int next = 0, prev = normals.count() - 1; next < normals.count(); prev = next++) {
+ QPoint n = normals.at(next);
+ QPoint intPrev = vertices.at(prev);
+ QPoint extPrev = vertices.at(prev);
+ QPoint intNext = vertices.at(next);
+ QPoint extNext = vertices.at(next);
+
+ extPrev.rx() -= n.x();
+ extPrev.ry() -= n.y();
+ intPrev.rx() += n.x();
+ intPrev.ry() += n.y();
+ extNext.rx() -= n.x();
+ extNext.ry() -= n.y();
+ intNext.rx() += n.x();
+ intNext.ry() += n.y();
+
+ if (needsClipping[prev] || needsClipping[next]) {
+ drawRectangle<Clip>(bits.data(), imgSize, imgSize,
+ &intPrev, &vertices.at(prev), &extPrev,
+ &intNext, &vertices.at(next), &extNext,
+ exteriorColor);
+ } else {
+ drawRectangle<NoClip>(bits.data(), imgSize, imgSize,
+ &intPrev, &vertices.at(prev), &extPrev,
+ &intNext, &vertices.at(next), &extNext,
+ exteriorColor);
+ }
+
+ if (isConvex.at(prev)) {
+ QPoint p = extPrev;
+ if (needsClipping[prev]) {
+ for (;;) {
+ QPoint rn((n.x() * rotation.x() - n.y() * rotation.y()) >> 14,
+ (n.y() * rotation.x() + n.x() * rotation.y()) >> 14);
+ n = rn;
+ if (n.x() * normals.at(prev).y() - n.y() * normals.at(prev).x() <= 0) {
+ p.rx() = vertices.at(prev).x() - normals.at(prev).x();
+ p.ry() = vertices.at(prev).y() - normals.at(prev).y();
+ drawTriangle<Clip>(bits.data(), imgSize, imgSize, &vertices.at(prev),
+ &extPrev, &p, exteriorColor);
+ break;
+ }
+
+ p.rx() = vertices.at(prev).x() - n.x();
+ p.ry() = vertices.at(prev).y() - n.y();
+ drawTriangle<Clip>(bits.data(), imgSize, imgSize, &vertices.at(prev),
+ &extPrev, &p, exteriorColor);
+ extPrev = p;
+ }
+ } else {
+ for (;;) {
+ QPoint rn((n.x() * rotation.x() - n.y() * rotation.y()) >> 14,
+ (n.y() * rotation.x() + n.x() * rotation.y()) >> 14);
+ n = rn;
+ if (n.x() * normals.at(prev).y() - n.y() * normals.at(prev).x() <= 0) {
+ p.rx() = vertices.at(prev).x() - normals.at(prev).x();
+ p.ry() = vertices.at(prev).y() - normals.at(prev).y();
+ drawTriangle<NoClip>(bits.data(), imgSize, imgSize, &vertices.at(prev),
+ &extPrev, &p, exteriorColor);
+ break;
+ }
+
+ p.rx() = vertices.at(prev).x() - n.x();
+ p.ry() = vertices.at(prev).y() - n.y();
+ drawTriangle<NoClip>(bits.data(), imgSize, imgSize, &vertices.at(prev),
+ &extPrev, &p, exteriorColor);
+ extPrev = p;
+ }
+ }
+ } else {
+ QPoint p = intPrev;
+ if (needsClipping[prev]) {
+ for (;;) {
+ QPoint rn((n.x() * rotation.x() + n.y() * rotation.y()) >> 14,
+ (n.y() * rotation.x() - n.x() * rotation.y()) >> 14);
+ n = rn;
+ if (n.x() * normals.at(prev).y() - n.y() * normals.at(prev).x() >= 0) {
+ p.rx() = vertices.at(prev).x() + normals.at(prev).x();
+ p.ry() = vertices.at(prev).y() + normals.at(prev).y();
+ drawTriangle<Clip>(bits.data(), imgSize, imgSize, &vertices.at(prev),
+ &p, &intPrev, interiorColor);
+ break;
+ }
+
+ p.rx() = vertices.at(prev).x() + n.x();
+ p.ry() = vertices.at(prev).y() + n.y();
+ drawTriangle<Clip>(bits.data(), imgSize, imgSize, &vertices.at(prev),
+ &p, &intPrev, interiorColor);
+ intPrev = p;
+ }
+ } else {
+ for (;;) {
+ QPoint rn((n.x() * rotation.x() + n.y() * rotation.y()) >> 14,
+ (n.y() * rotation.x() - n.x() * rotation.y()) >> 14);
+ n = rn;
+ if (n.x() * normals.at(prev).y() - n.y() * normals.at(prev).x() >= 0) {
+ p.rx() = vertices.at(prev).x() + normals.at(prev).x();
+ p.ry() = vertices.at(prev).y() + normals.at(prev).y();
+ drawTriangle<NoClip>(bits.data(), imgSize, imgSize, &vertices.at(prev),
+ &p, &intPrev, interiorColor);
+ break;
+ }
+
+ p.rx() = vertices.at(prev).x() + n.x();
+ p.ry() = vertices.at(prev).y() + n.y();
+ drawTriangle<NoClip>(bits.data(), imgSize, imgSize, &vertices.at(prev),
+ &p, &intPrev, interiorColor);
+ intPrev = p;
+ }
+ }
+ }
+ }
+
+ index = end + 1;
+ }
+
+ const qint32 *inLine = bits.data();
+ uchar *outLine = image.bits();
+ int padding = image.bytesPerLine() - image.width();
+ for (int y = 0; y < imgSize; ++y) {
+ for (int x = 0; x < imgSize; ++x, ++inLine, ++outLine)
+ *outLine = uchar((0x7f80 - *inLine) >> 8);
+ outLine += padding;
+ }
+
+ return image;
+}
+
+bool qt_fontHasNarrowOutlines(const QRawFont &f)
+{
+ QRawFont font = f;
+ font.setPixelSize(QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE);
+ Q_ASSERT(font.isValid());
+
+ QVector<quint32> glyphIndices = font.glyphIndexesForString(QLatin1String("O"));
+ if (glyphIndices.size() < 1)
+ return false;
+
+ QImage im = font.alphaMapForGlyph(glyphIndices.at(0), QRawFont::PixelAntialiasing);
+ if (im.isNull())
+ return false;
+
+ int minHThick = 999;
+ int minVThick = 999;
+
+ int thick = 0;
+ bool in = false;
+ int y = (im.height() + 1) / 2;
+ for (int x = 0; x < im.width(); ++x) {
+ int a = qAlpha(im.pixel(x, y));
+ if (a > 127) {
+ in = true;
+ ++thick;
+ } else if (in) {
+ in = false;
+ minHThick = qMin(minHThick, thick);
+ thick = 0;
+ }
+ }
+
+ thick = 0;
+ in = false;
+ int x = (im.width() + 1) / 2;
+ for (int y = 0; y < im.height(); ++y) {
+ int a = qAlpha(im.pixel(x, y));
+ if (a > 127) {
+ in = true;
+ ++thick;
+ } else if (in) {
+ in = false;
+ minVThick = qMin(minVThick, thick);
+ thick = 0;
+ }
+ }
+
+ return minHThick == 1 || minVThick == 1;
+}
+
+QImage qt_renderDistanceFieldGlyph(const QRawFont &font, glyph_t glyph, bool doubleResolution)
+{
+ QRawFont renderFont = font;
+ renderFont.setPixelSize(QT_DISTANCEFIELD_BASEFONTSIZE(doubleResolution) * QT_DISTANCEFIELD_SCALE(doubleResolution));
+
+ QPainterPath path = renderFont.pathForGlyph(glyph);
+ path.translate(-path.boundingRect().topLeft());
+ path.setFillRule(Qt::WindingFill);
+
+ QImage im = makeDistanceField(QT_DISTANCEFIELD_TILESIZE(doubleResolution),
+ path,
+ QT_DISTANCEFIELD_SCALE(doubleResolution),
+ QT_DISTANCEFIELD_RADIUS(doubleResolution) / QT_DISTANCEFIELD_SCALE(doubleResolution));
+ return im;
+}
+
+QT_END_NAMESPACE
+
diff --git a/src/gui/text/qdistancefield_p.h b/src/gui/text/qdistancefield_p.h
new file mode 100644
index 0000000000..486d291b78
--- /dev/null
+++ b/src/gui/text/qdistancefield_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
+**
+** This file is part of the QtDeclarative module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** GNU Lesser General Public License Usage
+** This file may be used under the terms of the GNU Lesser General Public
+** License version 2.1 as published by the Free Software Foundation and
+** appearing in the file LICENSE.LGPL included in the packaging of this
+** file. Please review the following information to ensure the GNU Lesser
+** General Public License version 2.1 requirements will be met:
+** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights. These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU General
+** Public License version 3.0 as published by the Free Software Foundation
+** and appearing in the file LICENSE.GPL included in the packaging of this
+** file. Please review the following information to ensure the GNU General
+** Public License version 3.0 requirements will be met:
+** http://www.gnu.org/copyleft/gpl.html.
+**
+** Other Usage
+** Alternatively, this file may be used in accordance with the terms and
+** conditions contained in a signed written agreement between you and Nokia.
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QDISTANCEFIELD_H
+#define QDISTANCEFIELD_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include <qrawfont.h>
+#include <private/qfontengine_p.h>
+
+QT_BEGIN_NAMESPACE
+
+#define QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE 54
+#define QT_DISTANCEFIELD_DEFAULT_TILESIZE 64
+#define QT_DISTANCEFIELD_DEFAULT_SCALE 16
+#define QT_DISTANCEFIELD_DEFAULT_RADIUS 80
+#define QT_DISTANCEFIELD_HIGHGLYPHCOUNT 2000
+
+#define QT_DISTANCEFIELD_BASEFONTSIZE(NarrowOutlineFont) \
+ (NarrowOutlineFont ? QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE * 2 : \
+ QT_DISTANCEFIELD_DEFAULT_BASEFONTSIZE)
+#define QT_DISTANCEFIELD_TILESIZE(NarrowOutlineFont) \
+ (NarrowOutlineFont ? QT_DISTANCEFIELD_DEFAULT_TILESIZE * 2 : \
+ QT_DISTANCEFIELD_DEFAULT_TILESIZE)
+#define QT_DISTANCEFIELD_SCALE(NarrowOutlineFont) \
+ (NarrowOutlineFont ? QT_DISTANCEFIELD_DEFAULT_SCALE / 2 : \
+ QT_DISTANCEFIELD_DEFAULT_SCALE)
+#define QT_DISTANCEFIELD_RADIUS(NarrowOutlineFont) \
+ (NarrowOutlineFont ? QT_DISTANCEFIELD_DEFAULT_RADIUS / 2 : \
+ QT_DISTANCEFIELD_DEFAULT_RADIUS)
+
+bool Q_GUI_EXPORT qt_fontHasNarrowOutlines(const QRawFont &f);
+QImage Q_GUI_EXPORT qt_renderDistanceFieldGlyph(const QRawFont &font, glyph_t glyph, bool doubleResolution);
+
+QT_END_NAMESPACE
+
+#endif // QDISTANCEFIELD_H
diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp
index a347c62629..ee833a06cf 100644
--- a/src/gui/text/qfont.cpp
+++ b/src/gui/text/qfont.cpp
@@ -2729,6 +2729,20 @@ QFontEngine *QFontCache::findEngine(const Key &key)
return it.value().data;
}
+void QFontCache::removeEngine(QFontEngine *engine)
+{
+ EngineCache::iterator it = engineCache.begin();
+ while (it != engineCache.end()) {
+ if (it.value().data == engine) {
+ it = engineCache.erase(it);
+ if (--engine->cache_count == 0)
+ decreaseCost(engine->cache_cost);
+ } else {
+ ++it;
+ }
+ }
+}
+
void QFontCache::insertEngine(const Key &key, QFontEngine *engine)
{
FC_DEBUG("QFontCache: inserting new engine %p", engine);
diff --git a/src/gui/text/qfont_p.h b/src/gui/text/qfont_p.h
index e26a98aaf2..d10249201a 100644
--- a/src/gui/text/qfont_p.h
+++ b/src/gui/text/qfont_p.h
@@ -243,6 +243,7 @@ public:
QFontEngine *findEngine(const Key &key);
void insertEngine(const Key &key, QFontEngine *engine);
+ void removeEngine(QFontEngine *engine);
private:
diff --git a/src/gui/text/qfont_qpa.cpp b/src/gui/text/qfont_qpa.cpp
index 7fcbe98b6f..29ba7767bc 100644
--- a/src/gui/text/qfont_qpa.cpp
+++ b/src/gui/text/qfont_qpa.cpp
@@ -40,6 +40,7 @@
****************************************************************************/
#include <QtGui/private/qguiapplication_p.h>
+#include <QtGui/QPlatformIntegration>
#include <QtGui/QPlatformFontDatabase>
QT_BEGIN_NAMESPACE
diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp
index 3ef28b8e50..7fa486e1ee 100644
--- a/src/gui/text/qfontdatabase.cpp
+++ b/src/gui/text/qfontdatabase.cpp
@@ -39,7 +39,6 @@
**
****************************************************************************/
-#include <qdir.h>
#include "qfontdatabase.h"
#include "qdebug.h"
#include "qalgorithms.h"
@@ -47,12 +46,14 @@
#include "qvarlengtharray.h" // here or earlier - workaround for VC++6
#include "qthread.h"
#include "qmutex.h"
+#include "qfile.h"
+#include "qfileinfo.h"
#include "private/qunicodetables_p.h"
#include "qfontengine_p.h"
+#include "qplatformintegration_qpa.h"
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/qplatformfontdatabase_qpa.h>
-#include "qabstractfileengine.h"
#include <stdlib.h>
#include <limits.h>
@@ -196,7 +197,7 @@ struct QtFontStyle
// bitfield count-- in while condition does not work correctly in mwccsym2
count--;
QPlatformIntegration *integration = QGuiApplicationPrivate::platformIntegration();
- if (integration) { //on shut down there will be some that we don't release.
+ if (integration) {
integration->fontDatabase()->releaseHandle(pixelSizes[count].handle);
}
}
@@ -349,6 +350,7 @@ struct QtFontFamily
#endif
QString name;
+ QStringList aliases;
int count;
QtFontFoundry **foundries;
@@ -724,7 +726,7 @@ static void match(int script, const QFontDef &request,
const QString &family_name, const QString &foundry_name, int force_encoding_id,
QtFontDesc *desc, const QList<int> &blacklistedFamilies = QList<int>(), bool forceXLFD=false);
-static void initFontDef(const QtFontDesc &desc, const QFontDef &request, QFontDef *fontDef)
+static void initFontDef(const QtFontDesc &desc, const QFontDef &request, QFontDef *fontDef, bool multi)
{
fontDef->family = desc.family->name;
if (! desc.foundry->name.isEmpty() && desc.family->count > 1) {
@@ -743,8 +745,10 @@ static void initFontDef(const QtFontDesc &desc, const QFontDef &request, QFontDe
fontDef->styleHint = request.styleHint;
fontDef->styleStrategy = request.styleStrategy;
- fontDef->weight = desc.style->key.weight;
- fontDef->style = desc.style->key.style;
+ if (!multi)
+ fontDef->weight = desc.style->key.weight;
+ if (!multi)
+ fontDef->style = desc.style->key.style;
fontDef->fixedPitch = desc.family->fixedPitch;
fontDef->stretch = desc.style->key.stretch;
fontDef->ignorePitch = false;
@@ -794,6 +798,14 @@ static QStringList familyList(const QFontDef &req)
Q_GLOBAL_STATIC(QFontDatabasePrivate, privateDb)
Q_GLOBAL_STATIC_WITH_ARGS(QMutex, fontDatabaseMutex, (QMutex::Recursive))
+// used in qguiapplication.cpp
+void qt_cleanupFontDatabase()
+{
+ QFontDatabasePrivate *db = privateDb();
+ if (db)
+ db->free();
+}
+
// used in qfontengine_x11.cpp
QMutex *qt_fontdatabase_mutex()
{
@@ -986,6 +998,25 @@ unsigned int bestFoundry(int script, unsigned int score, int styleStrategy,
return score;
}
+static bool matchFamilyName(const QString &familyName, QtFontFamily *f)
+{
+ if (familyName.isEmpty())
+ return true;
+
+ if (f->name.compare(familyName, Qt::CaseInsensitive) == 0)
+ return true;
+
+ QStringList::const_iterator it = f->aliases.constBegin();
+ while (it != f->aliases.constEnd()) {
+ if ((*it).compare(familyName, Qt::CaseInsensitive) == 0)
+ return true;
+
+ ++it;
+ }
+
+ return false;
+}
+
/*!
\internal
@@ -1035,9 +1066,7 @@ static void match(int script, const QFontDef &request,
test.family = db->families[x];
test.familyIndex = x;
- if (!family_name.isEmpty()
- && test.family->name.compare(family_name, Qt::CaseInsensitive) != 0
- )
+ if (!matchFamilyName(family_name, test.family))
continue;
if (family_name.isEmpty())
@@ -2193,8 +2222,8 @@ bool QFontDatabasePrivate::isApplicationFont(const QString &fileName)
int QFontDatabase::addApplicationFont(const QString &fileName)
{
QByteArray data;
- QFile f(fileName);
- if (!(f.fileEngine()->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::LocalDiskFlag)) {
+ if (!QFileInfo(fileName).isNativePath()) {
+ QFile f(fileName);
if (!f.open(QIODevice::ReadOnly))
return -1;
data = f.readAll();
diff --git a/src/gui/text/qfontdatabase_qpa.cpp b/src/gui/text/qfontdatabase_qpa.cpp
index 16777d593c..1a1f08f73d 100644
--- a/src/gui/text/qfontdatabase_qpa.cpp
+++ b/src/gui/text/qfontdatabase_qpa.cpp
@@ -58,28 +58,49 @@ Q_GUI_EXPORT void qt_registerFont(const QString &familyName, const QString &fou
const QSupportedWritingSystems &writingSystems, void *handle)
{
QFontDatabasePrivate *d = privateDb();
- // qDebug() << "Adding font" << familyName << weight << style << pixelSize << antialiased;
- QtFontStyle::Key styleKey;
- styleKey.style = style;
- styleKey.weight = weight;
- styleKey.stretch = stretch;
- QtFontFamily *f = d->family(familyName, true);
- f->fixedPitch = fixedPitch;
-
- for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) {
- if (writingSystems.supported(QFontDatabase::WritingSystem(i))) {
- f->writingSystems[i] = QtFontFamily::Supported;
- } else {
- f->writingSystems[i] = QtFontFamily::Unsupported;
- }
+// qDebug() << "Adding font" << familyName << weight << style << pixelSize << antialiased;
+ QtFontStyle::Key styleKey;
+ styleKey.style = style;
+ styleKey.weight = weight;
+ styleKey.stretch = stretch;
+ QtFontFamily *f = d->family(familyName, true);
+ f->fixedPitch = fixedPitch;
+
+ for (int i = 0; i < QFontDatabase::WritingSystemsCount; ++i) {
+ if (writingSystems.supported(QFontDatabase::WritingSystem(i))) {
+ f->writingSystems[i] = QtFontFamily::Supported;
+ } else {
+ f->writingSystems[i] = QtFontFamily::Unsupported;
}
+ }
+
+ QtFontFoundry *foundry = f->foundry(foundryname, true);
+ QtFontStyle *fontStyle = foundry->style(styleKey, QString(), true);
+ fontStyle->smoothScalable = scalable;
+ fontStyle->antialiased = antialiased;
+ QtFontSize *size = fontStyle->pixelSize(pixelSize ? pixelSize : SMOOTH_SCALABLE, true);
+ if (size->handle) {
+ QPlatformIntegration *integration = QGuiApplicationPrivate::platformIntegration();
+ if (integration)
+ integration->fontDatabase()->releaseHandle(size->handle);
+ }
+ size->handle = handle;
+}
+
+Q_GUI_EXPORT void qt_registerAliasToFontFamily(const QString &familyName, const QString &alias)
+{
+ if (alias.isEmpty())
+ return;
- QtFontFoundry *foundry = f->foundry(foundryname, true);
- QtFontStyle *fontStyle = foundry->style(styleKey, QString(), true);
- fontStyle->smoothScalable = scalable;
- fontStyle->antialiased = antialiased;
- QtFontSize *size = fontStyle->pixelSize(pixelSize?pixelSize:SMOOTH_SCALABLE, true);
- size->handle = handle;
+ QFontDatabasePrivate *d = privateDb();
+ QtFontFamily *f = d->family(familyName, false);
+ if (!f)
+ return;
+
+ if (f->aliases.contains(alias, Qt::CaseInsensitive))
+ return;
+
+ f->aliases.push_back(alias);
}
static QStringList fallbackFamilies(const QString &family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script)
@@ -185,7 +206,8 @@ QFontEngine *loadEngine(int script, const QFontDef &request,
if (family && !family->fallbackFamilies.isEmpty())
fallbacks = family->fallbackFamilies;
- engine = new QFontEngineMultiQPA(engine, script, fallbacks);
+ QPlatformFontDatabase *pfdb = QGuiApplicationPrivate::platformIntegration()->fontDatabase();
+ engine = pfdb->fontEngineMulti(engine, QUnicodeTables::Script(script), fallbacks);
// Cache Multi font engine as well in case we got the FT single
// font engine when we are actually looking for a Multi one
@@ -278,7 +300,7 @@ QFontDatabase::findFont(int script, const QFontPrivate *fp,
}
if (engine && engine->type() != QFontEngine::TestFontEngine) {
- initFontDef(desc, request, &engine->fontDef);
+ initFontDef(desc, request, &engine->fontDef, engine->type() == QFontEngine::Multi);
if (fp) {
QFontDef def = request;
@@ -305,7 +327,7 @@ QFontDatabase::findFont(int script, const QFontPrivate *fp,
}
engine = loadEngine(script, def, desc.family, desc.foundry, desc.style, desc.size);
if (engine) {
- initFontDef(desc, def, &engine->fontDef);
+ initFontDef(desc, def, &engine->fontDef, engine->type() == QFontEngine::Multi);
}
}
}
@@ -377,8 +399,12 @@ void QFontDatabase::load(const QFontPrivate *d, int script)
req.family = *it;
fe = QFontDatabase::findFont(script, d, req, multi);
- if (fe && (fe->type()==QFontEngine::Box) && !req.family.isEmpty())
+ if (fe && (fe->type()==QFontEngine::Box) && !req.family.isEmpty()) {
+ if (fe->ref.load() == 0)
+ delete fe;
+
fe = 0;
+ }
}
if (fe->symbol || (d->request.styleStrategy & QFont::NoFontMerging)) {
diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp
index 156a4a1e59..a084a3dd8c 100644
--- a/src/gui/text/qfontengine.cpp
+++ b/src/gui/text/qfontengine.cpp
@@ -1379,18 +1379,24 @@ bool QFontEngineMulti::stringToCMap(const QChar *str, int len,
int glyph_pos = 0;
for (int i = 0; i < len; ++i) {
bool surrogate = (str[i].isHighSurrogate() && i < len-1 && str[i+1].isLowSurrogate());
-
+ uint ucs4 = surrogate ? QChar::surrogateToUcs4(str[i], str[i+1]) : str[i].unicode();
if (glyphs->glyphs[glyph_pos] == 0 && str[i].category() != QChar::Separator_Line) {
QGlyphLayoutInstance tmp = glyphs->instance(glyph_pos);
- for (int x = 1; x < engines.size(); ++x) {
+ for (int x=1; x < engines.size(); ++x) {
+ if (!shouldLoadFontEngineForCharacter(x, ucs4))
+ continue;
+
QFontEngine *engine = engines.at(x);
+ bool deleteThisEngine = false;
if (!engine) {
const_cast<QFontEngineMulti *>(this)->loadEngine(x);
engine = engines.at(x);
+ deleteThisEngine = true;
}
Q_ASSERT(engine != 0);
if (engine->type() == Box)
continue;
+
glyphs->advances_x[glyph_pos] = glyphs->advances_y[glyph_pos] = 0;
glyphs->offsets[glyph_pos] = QFixedPoint();
int num = 2;
@@ -1401,13 +1407,17 @@ bool QFontEngineMulti::stringToCMap(const QChar *str, int len,
// set the high byte to indicate which engine the glyph came from
glyphs->glyphs[glyph_pos] |= (x << 24);
break;
+ } else if (deleteThisEngine) {
+ const_cast<QFontEngineMulti *>(this)->unloadEngine(x);
}
}
+
// ensure we use metrics from the 1st font when we use the fallback image.
if (!glyphs->glyphs[glyph_pos]) {
glyphs->setInstance(glyph_pos, tmp);
}
}
+
if (surrogate)
++i;
++glyph_pos;
@@ -1418,6 +1428,29 @@ bool QFontEngineMulti::stringToCMap(const QChar *str, int len,
return true;
}
+bool QFontEngineMulti::shouldLoadFontEngineForCharacter(int at, uint ucs4) const
+{
+ Q_UNUSED(at);
+ Q_UNUSED(ucs4);
+ return true;
+}
+
+void QFontEngineMulti::unloadEngine(int at)
+{
+ QFontEngine *fontEngine = engines.at(at);
+ if (fontEngine == 0)
+ return;
+
+ // If there are other references to the engine, keep it around and keep the reference
+ if (fontEngine->ref.load() == 1) {
+ QFontCache::instance()->removeEngine(fontEngine);
+ if (fontEngine->cache_count == 0) {
+ delete fontEngine;
+ engines[at] = 0;
+ }
+ }
+}
+
glyph_metrics_t QFontEngineMulti::boundingBox(const QGlyphLayout &glyphs)
{
if (glyphs.numGlyphs <= 0)
diff --git a/src/gui/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp
index cecf9d1feb..14e2dba364 100644
--- a/src/gui/text/qfontengine_ft.cpp
+++ b/src/gui/text/qfontengine_ft.cpp
@@ -49,7 +49,7 @@
#ifndef QT_NO_FREETYPE
#include "qfile.h"
-#include "qabstractfileengine.h"
+#include "qfileinfo.h"
#include "qthreadstorage.h"
#include <qmath.h>
@@ -231,7 +231,7 @@ QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id,
QScopedPointer<QFreetypeFace> newFreetype(new QFreetypeFace);
FT_Face face;
if (!face_id.filename.isEmpty()) {
- QFile file(QString::fromUtf8(face_id.filename));
+ QString fileName = QString::fromUtf8(face_id.filename);
if (face_id.filename.startsWith(":qmemoryfonts/")) {
// from qfontdatabase.cpp
QByteArray idx = face_id.filename;
@@ -240,7 +240,8 @@ QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id,
newFreetype->fontData = qt_fontdata_from_index(idx.toInt(&ok));
if (!ok)
newFreetype->fontData = QByteArray();
- } else if (!(file.fileEngine()->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::LocalDiskFlag)) {
+ } else if (!QFileInfo(fileName).isNativePath()) {
+ QFile file(fileName);
if (!file.open(QIODevice::ReadOnly)) {
return 0;
}
@@ -876,7 +877,7 @@ QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
if (err != FT_Err_Ok)
qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
- if ((!set || set->outline_drawing) && fetchMetricsOnly)
+ if (!set || set->outline_drawing || fetchMetricsOnly)
return 0;
FT_GlyphSlot slot = face->glyph;
@@ -1172,8 +1173,7 @@ QFixed QFontEngineFT::ascent() const
QFixed QFontEngineFT::descent() const
{
- // subtract a pixel to work around QFontMetrics's built-in + 1
- return QFixed::fromFixed(-metrics.descender - 64);
+ return QFixed::fromFixed(-metrics.descender);
}
QFixed QFontEngineFT::leading() const
@@ -1588,7 +1588,7 @@ glyph_metrics_t QFontEngineFT::boundingBox(const QGlyphLayout &glyphs)
glyph_metrics_t overall;
// initialize with line height, we get the same behaviour on all platforms
overall.y = -ascent();
- overall.height = ascent() + descent() + 1;
+ overall.height = ascent() + descent();
QFixed ymax = 0;
QFixed xmax = 0;
diff --git a/src/gui/text/qfontengine_ft_p.h b/src/gui/text/qfontengine_ft_p.h
index a9e67c10e8..83b51685c0 100644
--- a/src/gui/text/qfontengine_ft_p.h
+++ b/src/gui/text/qfontengine_ft_p.h
@@ -328,6 +328,7 @@ protected:
private:
friend class QFontEngineFTRawFont;
friend class QFontconfigDatabase;
+ friend class QFontEngineMultiFontConfig;
int loadFlags(QGlyphSet *set, GlyphFormat format, int flags, bool &hsubpixel, int &vfactor) const;
diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h
index c0bd1afb80..023882d560 100644
--- a/src/gui/text/qfontengine_p.h
+++ b/src/gui/text/qfontengine_p.h
@@ -392,11 +392,14 @@ public:
loadEngine(at);
}
+ virtual bool shouldLoadFontEngineForCharacter(int at, uint ucs4) const;
+
protected:
friend class QPSPrintEnginePrivate;
friend class QPSPrintEngineFontMulti;
friend class QRawFont;
virtual void loadEngine(int at) = 0;
+ virtual void unloadEngine(int at);
QVector<QFontEngine *> engines;
};
diff --git a/src/gui/text/qfontengine_qpa_p.h b/src/gui/text/qfontengine_qpa_p.h
index 6a73b9d309..ed2e071ac2 100644
--- a/src/gui/text/qfontengine_qpa_p.h
+++ b/src/gui/text/qfontengine_qpa_p.h
@@ -243,13 +243,16 @@ struct QPAGenerator
QFontEngine *fe;
};
-class QFontEngineMultiQPA : public QFontEngineMulti
+class Q_GUI_EXPORT QFontEngineMultiQPA : public QFontEngineMulti
{
public:
QFontEngineMultiQPA(QFontEngine *fe, int script, const QStringList &fallbacks);
void loadEngine(int at);
+ int fallbackFamilyCount() const { return fallbackFamilies.size(); }
+ QString fallbackFamilyAt(int at) const { return fallbackFamilies.at(at); }
+
private:
QStringList fallbackFamilies;
int script;
diff --git a/src/gui/text/qfontenginedirectwrite.cpp b/src/gui/text/qfontenginedirectwrite.cpp
index afbc41daeb..0f21ae8a1e 100644
--- a/src/gui/text/qfontenginedirectwrite.cpp
+++ b/src/gui/text/qfontenginedirectwrite.cpp
@@ -484,8 +484,8 @@ QFixed QFontEngineDirectWrite::ascent() const
QFixed QFontEngineDirectWrite::descent() const
{
return fontDef.styleStrategy & QFont::ForceIntegerMetrics
- ? (m_descent - 1).round()
- : (m_descent - 1);
+ ? (m_descent).round()
+ : (m_descent);
}
QFixed QFontEngineDirectWrite::leading() const
diff --git a/src/gui/text/qfontmetrics.cpp b/src/gui/text/qfontmetrics.cpp
index a2f0dd724a..283494e316 100644
--- a/src/gui/text/qfontmetrics.cpp
+++ b/src/gui/text/qfontmetrics.cpp
@@ -288,7 +288,7 @@ int QFontMetrics::height() const
{
QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
Q_ASSERT(engine != 0);
- return qRound(engine->ascent()) + qRound(engine->descent()) + 1;
+ return qRound(engine->ascent()) + qRound(engine->descent());
}
/*!
@@ -316,7 +316,7 @@ int QFontMetrics::lineSpacing() const
{
QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
Q_ASSERT(engine != 0);
- return qRound(engine->leading()) + qRound(engine->ascent()) + qRound(engine->descent()) + 1;
+ return qRound(engine->leading()) + qRound(engine->ascent()) + qRound(engine->descent());
}
/*!
@@ -1147,7 +1147,7 @@ qreal QFontMetricsF::height() const
QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
Q_ASSERT(engine != 0);
- return (engine->ascent() + engine->descent() + 1).toReal();
+ return (engine->ascent() + engine->descent()).toReal();
}
/*!
@@ -1175,7 +1175,7 @@ qreal QFontMetricsF::lineSpacing() const
{
QFontEngine *engine = d->engineForScript(QUnicodeTables::Common);
Q_ASSERT(engine != 0);
- return (engine->leading() + engine->ascent() + engine->descent() + 1).toReal();
+ return (engine->leading() + engine->ascent() + engine->descent()).toReal();
}
/*!
diff --git a/src/gui/text/qplatformfontdatabase_qpa.cpp b/src/gui/text/qplatformfontdatabase_qpa.cpp
index f9cc97cbc7..8fcf421330 100644
--- a/src/gui/text/qplatformfontdatabase_qpa.cpp
+++ b/src/gui/text/qplatformfontdatabase_qpa.cpp
@@ -271,6 +271,18 @@ void QPlatformFontDatabase::populateFontDatabase()
}
/*!
+ Returns a multi font engine in the specified \a script to encapsulate \a fontEngine with the
+ option to fall back to to the fonts given by \a fallbacks if \a fontEngine does not support
+ a certain character.
+*/
+QFontEngineMulti *QPlatformFontDatabase::fontEngineMulti(QFontEngine *fontEngine,
+ QUnicodeTables::Script script,
+ const QStringList &fallbacks)
+{
+ return new QFontEngineMultiQPA(fontEngine, script, fallbacks);
+}
+
+/*!
Returns the font engine that can be used to render the font described by
the font definition, \a fontDef, in the specified \a script.
*/
diff --git a/src/gui/text/qplatformfontdatabase_qpa.h b/src/gui/text/qplatformfontdatabase_qpa.h
index 151442c5e1..6a58a3106c 100644
--- a/src/gui/text/qplatformfontdatabase_qpa.h
+++ b/src/gui/text/qplatformfontdatabase_qpa.h
@@ -82,12 +82,14 @@ Q_GUI_EXPORT bool operator==(const QSupportedWritingSystems &, const QSupportedW
Q_GUI_EXPORT bool operator!=(const QSupportedWritingSystems &, const QSupportedWritingSystems &);
class QFontRequestPrivate;
+class QFontEngineMulti;
class Q_GUI_EXPORT QPlatformFontDatabase
{
public:
virtual ~QPlatformFontDatabase();
virtual void populateFontDatabase();
+ virtual QFontEngineMulti *fontEngineMulti(QFontEngine *fontEngine, QUnicodeTables::Script script, const QStringList &fallbacks);
virtual QFontEngine *fontEngine(const QFontDef &fontDef, QUnicodeTables::Script script, void *handle);
virtual QStringList fallbacksForFamily(const QString family, const QFont::Style &style, const QFont::StyleHint &styleHint, const QUnicodeTables::Script &script) const;
virtual QStringList addApplicationFont(const QByteArray &fontData, const QString &fileName);
diff --git a/src/gui/text/qrawfont_qpa.cpp b/src/gui/text/qrawfont_qpa.cpp
index e9515fdf97..d037d5902d 100644
--- a/src/gui/text/qrawfont_qpa.cpp
+++ b/src/gui/text/qrawfont_qpa.cpp
@@ -44,6 +44,7 @@
#if !defined(QT_NO_RAWFONT)
#include "qrawfont_p.h"
+#include "qplatformintegration_qpa.h"
#include <QtGui/qplatformfontdatabase_qpa.h>
#include <private/qguiapplication_p.h>
diff --git a/src/gui/text/qtextcursor.cpp b/src/gui/text/qtextcursor.cpp
index 25ec09d9db..ddf2fb080e 100644
--- a/src/gui/text/qtextcursor.cpp
+++ b/src/gui/text/qtextcursor.cpp
@@ -414,11 +414,18 @@ bool QTextCursorPrivate::movePosition(QTextCursor::MoveOperation op, QTextCursor
break;
}
case QTextCursor::PreviousCharacter:
- newPosition = priv->previousCursorPosition(position, QTextLayout::SkipCharacters);
+ if (mode == QTextCursor::MoveAnchor && position != adjusted_anchor)
+ newPosition = qMin(position, adjusted_anchor);
+ else
+ newPosition = priv->previousCursorPosition(position, QTextLayout::SkipCharacters);
break;
case QTextCursor::Left:
- newPosition = visualMovement ? priv->leftCursorPosition(position)
- : priv->previousCursorPosition(position, QTextLayout::SkipCharacters);
+ if (mode == QTextCursor::MoveAnchor && position != adjusted_anchor)
+ newPosition = visualMovement ? qMax(position, adjusted_anchor)
+ : qMin(position, adjusted_anchor);
+ else
+ newPosition = visualMovement ? priv->leftCursorPosition(position)
+ : priv->previousCursorPosition(position, QTextLayout::SkipCharacters);
break;
case QTextCursor::StartOfWord: {
if (relativePos == 0)
@@ -530,11 +537,18 @@ bool QTextCursorPrivate::movePosition(QTextCursor::MoveOperation op, QTextCursor
break;
}
case QTextCursor::NextCharacter:
- newPosition = priv->nextCursorPosition(position, QTextLayout::SkipCharacters);
+ if (mode == QTextCursor::MoveAnchor && position != adjusted_anchor)
+ newPosition = qMax(position, adjusted_anchor);
+ else
+ newPosition = priv->nextCursorPosition(position, QTextLayout::SkipCharacters);
break;
case QTextCursor::Right:
- newPosition = visualMovement ? priv->rightCursorPosition(position)
- : priv->nextCursorPosition(position, QTextLayout::SkipCharacters);
+ if (mode == QTextCursor::MoveAnchor && position != adjusted_anchor)
+ newPosition = visualMovement ? qMin(position, adjusted_anchor)
+ : qMax(position, adjusted_anchor);
+ else
+ newPosition = visualMovement ? priv->rightCursorPosition(position)
+ : priv->nextCursorPosition(position, QTextLayout::SkipCharacters);
break;
case QTextCursor::NextWord:
case QTextCursor::WordRight:
diff --git a/src/gui/text/qtextdocumentlayout.cpp b/src/gui/text/qtextdocumentlayout.cpp
index cc3372d6e8..2aedfe9133 100644
--- a/src/gui/text/qtextdocumentlayout.cpp
+++ b/src/gui/text/qtextdocumentlayout.cpp
@@ -3002,15 +3002,15 @@ void QTextDocumentLayout::resizeInlineObject(QTextInlineObject item, int posInDo
{
case QTextCharFormat::AlignMiddle:
item.setDescent(inlineSize.height() / 2);
- item.setAscent(inlineSize.height() / 2 - 1);
+ item.setAscent(inlineSize.height() / 2);
break;
case QTextCharFormat::AlignBaseline:
item.setDescent(m.descent());
- item.setAscent(inlineSize.height() - m.descent() - 1);
+ item.setAscent(inlineSize.height() - m.descent());
break;
default:
item.setDescent(0);
- item.setAscent(inlineSize.height() - 1);
+ item.setAscent(inlineSize.height());
}
}
diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp
index 5e5354a980..bc7f4f7ad6 100644
--- a/src/gui/text/qtextengine.cpp
+++ b/src/gui/text/qtextengine.cpp
@@ -2237,7 +2237,7 @@ static inline bool prevCharJoins(const QString &string, int pos)
return (joining == QChar::Dual || joining == QChar::Center);
}
-QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int flags) const
+QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int flags, int from, int count) const
{
// qDebug() << "elidedText; available width" << width.toReal() << "text width:" << this->width(0, layoutData->string.length()).toReal();
@@ -2271,10 +2271,14 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int
validate();
+ const int to = count >= 0 && count <= layoutData->string.length() - from
+ ? from + count
+ : layoutData->string.length();
+
if (mode == Qt::ElideNone
- || this->width(0, layoutData->string.length()) <= width
- || layoutData->string.length() <= 1)
- return layoutData->string;
+ || this->width(from, layoutData->string.length()) <= width
+ || to - from <= 1)
+ return layoutData->string.mid(from, from - to);
QFixed ellipsisWidth;
QString ellipsisText;
@@ -2328,7 +2332,7 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int
if (mode == Qt::ElideRight) {
QFixed currentWidth;
int pos;
- int nextBreak = 0;
+ int nextBreak = from;
do {
pos = nextBreak;
@@ -2338,17 +2342,17 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int
++nextBreak;
currentWidth += this->width(pos, nextBreak - pos);
- } while (nextBreak < layoutData->string.length()
+ } while (nextBreak < to
&& currentWidth < availableWidth);
if (nextCharJoins(layoutData->string, pos))
ellipsisText.prepend(QChar(0x200d) /* ZWJ */);
- return layoutData->string.left(pos) + ellipsisText;
+ return layoutData->string.mid(from, pos - from) + ellipsisText;
} else if (mode == Qt::ElideLeft) {
QFixed currentWidth;
int pos;
- int nextBreak = layoutData->string.length();
+ int nextBreak = to;
do {
pos = nextBreak;
@@ -2358,22 +2362,22 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int
--nextBreak;
currentWidth += this->width(nextBreak, pos - nextBreak);
- } while (nextBreak > 0
+ } while (nextBreak > from
&& currentWidth < availableWidth);
if (prevCharJoins(layoutData->string, pos))
ellipsisText.append(QChar(0x200d) /* ZWJ */);
- return ellipsisText + layoutData->string.mid(pos);
+ return ellipsisText + layoutData->string.mid(pos, to - pos);
} else if (mode == Qt::ElideMiddle) {
QFixed leftWidth;
QFixed rightWidth;
- int leftPos = 0;
- int nextLeftBreak = 0;
+ int leftPos = from;
+ int nextLeftBreak = from;
- int rightPos = layoutData->string.length();
- int nextRightBreak = layoutData->string.length();
+ int rightPos = to;
+ int nextRightBreak = to;
do {
leftPos = nextLeftBreak;
@@ -2384,13 +2388,13 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int
++nextLeftBreak;
--nextRightBreak;
- while (nextRightBreak > 0 && !attributes[nextRightBreak].charStop)
+ while (nextRightBreak > from && !attributes[nextRightBreak].charStop)
--nextRightBreak;
leftWidth += this->width(leftPos, nextLeftBreak - leftPos);
rightWidth += this->width(nextRightBreak, rightPos - nextRightBreak);
- } while (nextLeftBreak < layoutData->string.length()
- && nextRightBreak > 0
+ } while (nextLeftBreak < to
+ && nextRightBreak > from
&& leftWidth + rightWidth < availableWidth);
if (nextCharJoins(layoutData->string, leftPos))
@@ -2398,10 +2402,10 @@ QString QTextEngine::elidedText(Qt::TextElideMode mode, const QFixed &width, int
if (prevCharJoins(layoutData->string, rightPos))
ellipsisText.append(QChar(0x200d) /* ZWJ */);
- return layoutData->string.left(leftPos) + ellipsisText + layoutData->string.mid(rightPos);
+ return layoutData->string.mid(from, leftPos - from) + ellipsisText + layoutData->string.mid(rightPos, to - rightPos);
}
- return layoutData->string;
+ return layoutData->string.mid(from, to - from);
}
void QTextEngine::setBoundary(int strPos) const
diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h
index 641d946aa9..b29f626b68 100644
--- a/src/gui/text/qtextengine_p.h
+++ b/src/gui/text/qtextengine_p.h
@@ -366,7 +366,7 @@ struct Q_AUTOTEST_EXPORT QScriptItem
QFixed leading;
QFixed width;
int glyph_data_offset;
- QFixed height() const { return ascent + descent + 1; }
+ QFixed height() const { return ascent + descent; }
};
@@ -396,7 +396,7 @@ struct Q_AUTOTEST_EXPORT QScriptLine
mutable uint gridfitted : 1;
uint hasTrailingSpaces : 1;
uint leadingIncluded : 1;
- QFixed height() const { return (ascent + descent).ceil() + 1
+ QFixed height() const { return (ascent + descent).ceil()
+ (leadingIncluded? qMax(QFixed(),leading) : QFixed()); }
QFixed base() const { return ascent
+ (leadingIncluded ? qMax(QFixed(),leading) : QFixed()); }
@@ -619,7 +619,7 @@ public:
bool atSpace(int position) const;
void indexAdditionalFormats();
- QString elidedText(Qt::TextElideMode mode, const QFixed &width, int flags = 0) const;
+ QString elidedText(Qt::TextElideMode mode, const QFixed &width, int flags = 0, int from = 0, int count = -1) const;
void shapeLine(const QScriptLine &line);
QFixed leadingSpaceWidth(const QScriptLine &line);
diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp
index ac92c4dd51..943caea644 100644
--- a/src/gui/text/qtextlayout.cpp
+++ b/src/gui/text/qtextlayout.cpp
@@ -1429,9 +1429,9 @@ qreal QTextLine::descent() const
}
/*!
- Returns the line's height. This is equal to ascent() + descent() + 1
+ Returns the line's height. This is equal to ascent() + descent()
if leading is not included. If leading is included, this equals to
- ascent() + descent() + leading() + 1.
+ ascent() + descent() + leading().
\sa ascent(), descent(), leading(), setLeadingIncluded()
*/
@@ -2124,8 +2124,8 @@ static QGlyphRun glyphRunWithInfo(QFontEngine *fontEngine, const QGlyphLayout &g
Q_ASSERT(glyphsArray.size() == positionsArray.size());
qreal fontHeight = font.ascent() + font.descent();
- qreal minY;
- qreal maxY;
+ qreal minY = 0;
+ qreal maxY = 0;
QVector<quint32> glyphs;
QVector<QPointF> positions;
for (int i=0; i<glyphsArray.size(); ++i) {
diff --git a/src/gui/text/text.pri b/src/gui/text/text.pri
index 63a731f116..6587769712 100644
--- a/src/gui/text/text.pri
+++ b/src/gui/text/text.pri
@@ -42,7 +42,8 @@ HEADERS += \
text/qrawfont_p.h \
text/qglyphrun.h \
text/qglyphrun_p.h \
- text/qharfbuzz_copy_p.h
+ text/qharfbuzz_copy_p.h \
+ text/qdistancefield_p.h
SOURCES += \
text/qfont.cpp \
@@ -73,7 +74,8 @@ SOURCES += \
text/qtextodfwriter.cpp \
text/qstatictext.cpp \
text/qrawfont.cpp \
- text/qglyphrun.cpp
+ text/qglyphrun.cpp \
+ text/qdistancefield.cpp
contains(QT_CONFIG, directwrite) {
LIBS_PRIVATE += -ldwrite
diff --git a/src/gui/util/qdesktopservices.cpp b/src/gui/util/qdesktopservices.cpp
index 0f1312e02d..25fb08f532 100644
--- a/src/gui/util/qdesktopservices.cpp
+++ b/src/gui/util/qdesktopservices.cpp
@@ -45,14 +45,15 @@
#include <qdebug.h>
-#include "qdesktopservices_qpa.cpp"
-
#include <qstandardpaths.h>
#include <qhash.h>
#include <qobject.h>
#include <qcoreapplication.h>
+#include <private/qguiapplication_p.h>
#include <qurl.h>
#include <qmutex.h>
+#include <qplatformservices_qpa.h>
+#include <qplatformintegration_qpa.h>
QT_BEGIN_NAMESPACE
@@ -185,14 +186,15 @@ bool QDesktopServices::openUrl(const QUrl &url)
return result; // ### support bool slot return type
}
}
-
- bool result;
- if (url.scheme() == QLatin1String("file"))
- result = openDocument(url);
- else
- result = launchWebBrowser(url);
-
- return result;
+ if (!url.isValid())
+ return false;
+ QPlatformServices *platformServices = QGuiApplicationPrivate::platformIntegration()->services();
+ if (!platformServices) {
+ qWarning("%s: The platform plugin does not support services.", Q_FUNC_INFO);
+ return false;
+ }
+ return url.scheme() == QStringLiteral("file") ?
+ platformServices->openDocument(url) : platformServices->openUrl(url);
}
/*!
diff --git a/src/gui/util/qdesktopservices_mac.cpp b/src/gui/util/qdesktopservices_mac.cpp
deleted file mode 100644
index 84c7156ef3..0000000000
--- a/src/gui/util/qdesktopservices_mac.cpp
+++ /dev/null
@@ -1,127 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** GNU Lesser General Public License Usage
-** This file may be used under the terms of the GNU Lesser General Public
-** License version 2.1 as published by the Free Software Foundation and
-** appearing in the file LICENSE.LGPL included in the packaging of this
-** file. Please review the following information to ensure the GNU Lesser
-** General Public License version 2.1 requirements will be met:
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU General
-** Public License version 3.0 as published by the Free Software Foundation
-** and appearing in the file LICENSE.GPL included in the packaging of this
-** file. Please review the following information to ensure the GNU General
-** Public License version 3.0 requirements will be met:
-** http://www.gnu.org/copyleft/gpl.html.
-**
-** Other Usage
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef QT_NO_DESKTOPSERVICES
-
-#include <qprocess.h>
-#include <qstringlist.h>
-#include <qdir.h>
-#include <qurl.h>
-#include <private/qcore_mac_p.h>
-#include <qcoreapplication.h>
-
-#include <ApplicationServices/ApplicationServices.h>
-
-QT_BEGIN_NAMESPACE
-
-/*
- Translates a QDesktopServices::StandardLocation into the mac equivalent.
-*/
-OSType translateLocation(QDesktopServices::StandardLocation type)
-{
- switch (type) {
- case QDesktopServices::DesktopLocation:
- return kDesktopFolderType; break;
-
- case QDesktopServices::DocumentsLocation:
- return kDocumentsFolderType; break;
-
- case QDesktopServices::FontsLocation:
- // There are at least two different font directories on the mac: /Library/Fonts and ~/Library/Fonts.
- // To select a specific one we have to specify a different first parameter when calling FSFindFolder.
- return kFontsFolderType; break;
-
- case QDesktopServices::ApplicationsLocation:
- return kApplicationsFolderType; break;
-
- case QDesktopServices::MusicLocation:
- return kMusicDocumentsFolderType; break;
-
- case QDesktopServices::MoviesLocation:
- return kMovieDocumentsFolderType; break;
-
- case QDesktopServices::PicturesLocation:
- return kPictureDocumentsFolderType; break;
-
- case QDesktopServices::TempLocation:
- return kTemporaryFolderType; break;
-
- case QDesktopServices::DataLocation:
- return kApplicationSupportFolderType; break;
-
- case QDesktopServices::CacheLocation:
- return kCachedDataFolderType; break;
-
- default:
- return kDesktopFolderType; break;
- }
-}
-
-static bool lsOpen(const QUrl &url)
-{
- if (!url.isValid() || url.scheme().isEmpty())
- return false;
-
- QCFType<CFURLRef> cfUrl = CFURLCreateWithString(0, QCFString(QString::fromLatin1(url.toEncoded())), 0);
- if (cfUrl == 0)
- return false;
-
- const OSStatus err = LSOpenCFURLRef(cfUrl, 0);
- return (err == noErr);
-}
-
-static bool launchWebBrowser(const QUrl &url)
-{
- return lsOpen(url);
-}
-
-static bool openDocument(const QUrl &file)
-{
- if (!file.isValid())
- return false;
-
- // LSOpen does not work in this case, use QProcess open instead.
- return QProcess::startDetached(QLatin1String("open"), QStringList() << file.toLocalFile());
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_NO_DESKTOPSERVICES
diff --git a/src/gui/util/qdesktopservices_win.cpp b/src/gui/util/qdesktopservices_win.cpp
deleted file mode 100644
index 88f245d6f6..0000000000
--- a/src/gui/util/qdesktopservices_win.cpp
+++ /dev/null
@@ -1,177 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** GNU Lesser General Public License Usage
-** This file may be used under the terms of the GNU Lesser General Public
-** License version 2.1 as published by the Free Software Foundation and
-** appearing in the file LICENSE.LGPL included in the packaging of this
-** file. Please review the following information to ensure the GNU Lesser
-** General Public License version 2.1 requirements will be met:
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU General
-** Public License version 3.0 as published by the Free Software Foundation
-** and appearing in the file LICENSE.GPL included in the packaging of this
-** file. Please review the following information to ensure the GNU General
-** Public License version 3.0 requirements will be met:
-** http://www.gnu.org/copyleft/gpl.html.
-**
-** Other Usage
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include <qsettings.h>
-#include <qdir.h>
-#include <private/qsystemlibrary_p.h>
-#include <qurl.h>
-#include <qstringlist.h>
-#include <qprocess.h>
-#include <qtemporaryfile.h>
-#include <qcoreapplication.h>
-
-#include <qt_windows.h>
-#include <shlobj.h>
-#if !defined(Q_OS_WINCE)
-# include <intshcut.h>
-#else
-# include <qguifunctions_wince.h>
-# if !defined(STANDARDSHELL_UI_MODEL)
-# include <winx.h>
-# endif
-#endif
-
-#ifndef CSIDL_MYMUSIC
-#define CSIDL_MYMUSIC 13
-#define CSIDL_MYVIDEO 14
-#endif
-
-#ifndef QT_NO_DESKTOPSERVICES
-
-QT_BEGIN_NAMESPACE
-
-static bool openDocument(const QUrl &file)
-{
- if (!file.isValid())
- return false;
- QString filePath = file.toLocalFile();
- if (filePath.isEmpty())
- filePath = file.toString();
- quintptr returnValue = (quintptr)ShellExecute(0, 0, (wchar_t*)filePath.utf16(), 0, 0, SW_SHOWNORMAL);
- return (returnValue > 32); //ShellExecute returns a value greater than 32 if successful
-}
-
-static QString expandEnvStrings(const QString &command)
-{
-#if defined(Q_OS_WINCE)
- return command;
-#else
- wchar_t buffer[MAX_PATH];
- if (ExpandEnvironmentStrings((wchar_t*)command.utf16(), buffer, MAX_PATH))
- return QString::fromWCharArray(buffer);
- else
- return command;
-#endif
-}
-
-static bool launchWebBrowser(const QUrl &url)
-{
- if (url.scheme() == QLatin1String("mailto")) {
- //Retrieve the commandline for the default mail client
- //the default key used below is the command line for the mailto: shell command
- DWORD bufferSize = sizeof(wchar_t) * MAX_PATH;
- long returnValue = -1;
- QString command;
-
- HKEY handle;
- LONG res;
- wchar_t keyValue[MAX_PATH] = {0};
- QString keyName(QLatin1String("mailto"));
-
- //Check if user has set preference, otherwise use default.
- res = RegOpenKeyEx(HKEY_CURRENT_USER,
- L"Software\\Microsoft\\Windows\\Shell\\Associations\\UrlAssociations\\mailto\\UserChoice",
- 0, KEY_READ, &handle);
- if (res == ERROR_SUCCESS) {
- returnValue = RegQueryValueEx(handle, L"Progid", 0, 0, reinterpret_cast<unsigned char*>(keyValue), &bufferSize);
- if (!returnValue)
- keyName = QString::fromUtf16((const ushort*)keyValue);
- RegCloseKey(handle);
- }
- keyName += QLatin1String("\\Shell\\Open\\Command");
- res = RegOpenKeyExW(HKEY_CLASSES_ROOT, (const wchar_t*)keyName.utf16(), 0, KEY_READ, &handle);
- if (res != ERROR_SUCCESS)
- return false;
-
- bufferSize = sizeof(wchar_t) * MAX_PATH;
- returnValue = RegQueryValueEx(handle, L"", 0, 0, reinterpret_cast<unsigned char*>(keyValue), &bufferSize);
- if (!returnValue)
- command = QString::fromRawData((QChar*)keyValue, bufferSize);
- RegCloseKey(handle);
-
- if (returnValue)
- return false;
-
- command = expandEnvStrings(command);
- command = command.trimmed();
- //Make sure the path for the process is in quotes
- int index = -1 ;
- if (command[0]!= QLatin1Char('\"')) {
- index = command.indexOf(QLatin1String(".exe "), 0, Qt::CaseInsensitive);
- command.insert(index+4, QLatin1Char('\"'));
- command.insert(0, QLatin1Char('\"'));
- }
- //pass the url as the parameter
- index = command.lastIndexOf(QLatin1String("%1"));
- if (index != -1){
- command.replace(index, 2, url.toString());
- }
- //start the process
- PROCESS_INFORMATION pi;
- ZeroMemory(&pi, sizeof(pi));
- STARTUPINFO si;
- ZeroMemory(&si, sizeof(si));
- si.cb = sizeof(si);
-
- returnValue = CreateProcess(NULL, (wchar_t*)command.utf16(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);
-
- if (!returnValue)
- return false;
-
- CloseHandle(pi.hProcess);
- CloseHandle(pi.hThread);
- return true;
- }
-
- if (!url.isValid())
- return false;
-
- if (url.scheme().isEmpty())
- return openDocument(url);
-
- quintptr returnValue = (quintptr)ShellExecute(0, 0, (wchar_t *)QString::fromUtf8(url.toEncoded().constData()).utf16(),
- 0, 0, SW_SHOWNORMAL);
- return (returnValue > 32);
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_NO_DESKTOPSERVICES
diff --git a/src/gui/util/qdesktopservices_x11.cpp b/src/gui/util/qdesktopservices_x11.cpp
deleted file mode 100644
index 73cf47a1db..0000000000
--- a/src/gui/util/qdesktopservices_x11.cpp
+++ /dev/null
@@ -1,131 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/
-**
-** This file is part of the QtGui module of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:LGPL$
-** GNU Lesser General Public License Usage
-** This file may be used under the terms of the GNU Lesser General Public
-** License version 2.1 as published by the Free Software Foundation and
-** appearing in the file LICENSE.LGPL included in the packaging of this
-** file. Please review the following information to ensure the GNU Lesser
-** General Public License version 2.1 requirements will be met:
-** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
-**
-** In addition, as a special exception, Nokia gives you certain additional
-** rights. These rights are described in the Nokia Qt LGPL Exception
-** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU General
-** Public License version 3.0 as published by the Free Software Foundation
-** and appearing in the file LICENSE.GPL included in the packaging of this
-** file. Please review the following information to ensure the GNU General
-** Public License version 3.0 requirements will be met:
-** http://www.gnu.org/copyleft/gpl.html.
-**
-** Other Usage
-** Alternatively, this file may be used in accordance with the terms and
-** conditions contained in a signed written agreement between you and Nokia.
-**
-**
-**
-**
-**
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "qdesktopservices.h"
-
-#ifndef QT_NO_DESKTOPSERVICES
-
-#include <qprocess.h>
-#include <qurl.h>
-#include <qdir.h>
-#include <qfile.h>
-#include <qtextstream.h>
-#include <private/qt_x11_p.h>
-#include <qcoreapplication.h>
-#include <stdlib.h>
-
-QT_BEGIN_NAMESPACE
-
-inline static bool launch(const QUrl &url, const QString &client)
-{
-#if !defined(QT_NO_PROCESS)
- return (QProcess::startDetached(client + QLatin1Char(' ') + QString::fromLatin1(url.toEncoded().constData())));
-#else
- return (::system((client + QLatin1Char(' ') + QString::fromLatin1(url.toEncoded().constData())).toLocal8Bit().constData()) != -1);
-#endif
-}
-
-static bool openDocument(const QUrl &url)
-{
- if (!url.isValid())
- return false;
-
- if (launch(url, QLatin1String("xdg-open")))
- return true;
-
- // Use the X11->desktopEnvironment value if X11 is non-NULL,
- // otherwise just attempt to launch command regardless of the desktop environment
- if ((!X11 || (X11 && X11->desktopEnvironment == DE_GNOME)) && launch(url, QLatin1String("gnome-open"))) {
- return true;
- } else {
- if ((!X11 || (X11 && X11->desktopEnvironment == DE_KDE)) && launch(url, QLatin1String("kfmclient exec")))
- return true;
- }
-
- if (launch(url, QLatin1String("firefox")))
- return true;
- if (launch(url, QLatin1String("mozilla")))
- return true;
- if (launch(url, QLatin1String("netscape")))
- return true;
- if (launch(url, QLatin1String("opera")))
- return true;
-
- return false;
-}
-
-static bool launchWebBrowser(const QUrl &url)
-{
- if (!url.isValid())
- return false;
- if (url.scheme() == QLatin1String("mailto"))
- return openDocument(url);
-
- if (launch(url, QLatin1String("xdg-open")))
- return true;
- if (launch(url, QString::fromLocal8Bit(getenv("DEFAULT_BROWSER"))))
- return true;
- if (launch(url, QString::fromLocal8Bit(getenv("BROWSER"))))
- return true;
-
- // Use the X11->desktopEnvironment value if X11 is non-NULL,
- // otherwise just attempt to launch command regardless of the desktop environment
- if ((!X11 || (X11 && X11->desktopEnvironment == DE_GNOME)) && launch(url, QLatin1String("gnome-open"))) {
- return true;
- } else {
- if ((!X11 || (X11 && X11->desktopEnvironment == DE_KDE)) && launch(url, QLatin1String("kfmclient openURL")))
- return true;
- }
-
- if (launch(url, QLatin1String("firefox")))
- return true;
- if (launch(url, QLatin1String("mozilla")))
- return true;
- if (launch(url, QLatin1String("netscape")))
- return true;
- if (launch(url, QLatin1String("opera")))
- return true;
- return false;
-}
-
-QT_END_NAMESPACE
-
-#endif // QT_NO_DESKTOPSERVICES