summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--demos/demos.pro4
-rw-r--r--demos/glhypnotizer/glhypnotizer.pro21
-rw-r--r--demos/glhypnotizer/hypnotizer.qrc6
-rw-r--r--demos/glhypnotizer/main.cpp356
-rw-r--r--demos/glhypnotizer/qt-logo.pngbin0 -> 2493 bytes
-rw-r--r--demos/glhypnotizer/spiral.svg100
-rw-r--r--doc/src/demos/glhypnotizer.qdoc38
-rw-r--r--doc/src/images/glhypnotizer-demo.pngbin0 -> 46888 bytes
-rw-r--r--src/3rdparty/wayland/qwaylandwindowmanager-client-protocol.h110
-rw-r--r--src/3rdparty/wayland/wayland-windowmanager-protocol.c37
-rw-r--r--src/declarative/qml/qdeclarativeengine.cpp3
-rw-r--r--src/gui/kernel/qapplication_mac.mm1
-rw-r--r--src/gui/kernel/qcocoaview_mac.mm2
-rw-r--r--src/gui/kernel/qplatformclipboard_qpa.cpp2
-rw-r--r--src/gui/kernel/qplatformclipboard_qpa.h2
-rw-r--r--src/gui/kernel/qwidget_qpa.cpp11
-rw-r--r--src/gui/painting/painting.pri4
-rw-r--r--src/gui/painting/qcosmeticstroker.cpp1010
-rw-r--r--src/gui/painting/qcosmeticstroker_p.h152
-rw-r--r--src/gui/painting/qoutlinemapper.cpp9
-rw-r--r--src/gui/painting/qoutlinemapper_p.h8
-rw-r--r--src/gui/painting/qpaintengine_mac_p.h2
-rw-r--r--src/gui/painting/qpaintengine_raster.cpp1474
-rw-r--r--src/gui/painting/qpaintengine_raster_p.h6
-rw-r--r--src/gui/painting/qpaintengineex.cpp47
-rw-r--r--src/gui/painting/qpaintengineex_p.h3
-rw-r--r--src/gui/painting/qpainter.cpp39
-rw-r--r--src/gui/painting/qrasterizer.cpp4
-rw-r--r--src/gui/painting/qtextureglyphcache.cpp4
-rw-r--r--src/gui/painting/qunifiedtoolbarsurface_mac.cpp6
-rw-r--r--src/gui/text/qfontdatabase_x11.cpp5
-rw-r--r--src/gui/text/qfontengine_coretext.mm20
-rw-r--r--src/gui/text/qfontengine_x11.cpp2
-rw-r--r--src/gui/text/qtextengine.cpp69
-rw-r--r--src/gui/text/qtextengine_p.h2
-rw-r--r--src/gui/text/qtextlayout.cpp22
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp33
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h1
-rw-r--r--src/opengl/qgl_qpa.cpp2
-rw-r--r--src/opengl/qpaintengine_opengl_p.h1
-rw-r--r--src/opengl/qwindowsurface_gl.cpp18
-rw-r--r--src/openvg/qpaintengine_vg_p.h1
-rw-r--r--src/plugins/platforms/glxconvenience/glxconvenience.pri8
-rw-r--r--src/plugins/platforms/glxconvenience/qglxconvenience.cpp30
-rw-r--r--src/plugins/platforms/minimal/qminimalintegration.cpp4
-rw-r--r--src/plugins/platforms/minimal/qminimalintegration.h2
-rw-r--r--src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandglcontext.cpp9
-rw-r--r--src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxcontext.cpp4
-rw-r--r--src/plugins/platforms/wayland/qwaylandclipboard.cpp115
-rw-r--r--src/plugins/platforms/wayland/qwaylandclipboard.h17
-rw-r--r--src/plugins/platforms/wayland/qwaylanddisplay.cpp50
-rw-r--r--src/plugins/platforms/wayland/qwaylanddisplay.h17
-rw-r--r--src/plugins/platforms/wayland/qwaylandwindow.cpp11
-rw-r--r--src/plugins/platforms/wayland/wayland.pro2
-rw-r--r--src/plugins/platforms/wayland/wayland_sha1.txt3
-rw-r--r--src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanagerintegration.cpp92
-rw-r--r--src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanagerintegration.h70
-rw-r--r--src/plugins/platforms/wayland/windowmanager_integration/windowmanager_integration.pri16
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.cpp11
-rw-r--r--src/plugins/platforms/xcb/qxcbwindow.h6
-rw-r--r--src/plugins/platforms/xcb/qxcbwindowsurface.cpp22
-rw-r--r--src/plugins/platforms/xlib/qxlibclipboard.cpp8
-rw-r--r--src/plugins/platforms/xlib/qxlibclipboard.h2
-rw-r--r--src/plugins/platforms/xlib/qxlibintegration.cpp2
-rw-r--r--src/plugins/platforms/xlib/qxlibscreen.cpp2
-rw-r--r--src/plugins/platforms/xlib/qxlibstatic.h1
-rw-r--r--src/plugins/platforms/xlib/qxlibwindow.cpp38
-rw-r--r--src/plugins/platforms/xlib/qxlibwindow.h8
-rw-r--r--src/plugins/platforms/xlib/qxlibwindowsurface.cpp27
-rw-r--r--tests/arthur/common/paintcommands.cpp20
-rw-r--r--tests/arthur/common/paintcommands.h1
-rw-r--r--tests/auto/declarative/qdeclarativeqt/tst_qdeclarativeqt.cpp2
-rw-r--r--tests/auto/lancelot/scripts/statictext.qps122
-rw-r--r--tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp2
-rw-r--r--tests/auto/qpainter/tst_qpainter.cpp6
-rw-r--r--tests/auto/qstatictext/tst_qstatictext.cpp4
-rw-r--r--tests/auto/qtextlayout/tst_qtextlayout.cpp42
77 files changed, 2913 insertions, 1500 deletions
diff --git a/demos/demos.pro b/demos/demos.pro
index f1d5b00..ed18446 100644
--- a/demos/demos.pro
+++ b/demos/demos.pro
@@ -44,6 +44,9 @@ wince*: SUBDIRS = \
contains(QT_CONFIG, opengl):!contains(QT_CONFIG, opengles1):!contains(QT_CONFIG, opengles2):{
SUBDIRS += demos_boxes
}
+contains(QT_CONFIG, opengl):contains(QT_CONFIG, svg){
+SUBDIRS += demos_glhypnotizer
+}
mac* && !qpa: SUBDIRS += demos_macmainwindow
wince*|symbian|embedded|x11: SUBDIRS += demos_embedded
@@ -103,6 +106,7 @@ demos_browser.subdir = browser
demos_boxes.subdir = boxes
demos_sub-attaq.subdir = sub-attaq
demos_spectrum.subdir = spectrum
+demos_glhypnotizer.subdir = glhypnotizer
#CONFIG += ordered
!ordered {
diff --git a/demos/glhypnotizer/glhypnotizer.pro b/demos/glhypnotizer/glhypnotizer.pro
new file mode 100644
index 0000000..a7fdf5e
--- /dev/null
+++ b/demos/glhypnotizer/glhypnotizer.pro
@@ -0,0 +1,21 @@
+TEMPLATE = app
+CONFIG -= moc
+INCLUDEPATH += .
+
+# Input
+SOURCES += main.cpp
+QT += opengl svg
+RESOURCES = hypnotizer.qrc
+
+build_all:!build_pass {
+ CONFIG -= build_all
+ CONFIG += release
+}
+
+# install
+target.path = $$[QT_INSTALL_DEMOS]/glhypnotizer
+sources.files = $$SOURCES $$HEADERS $$RESOURCES *.png *.pro *.svg
+sources.path = $$[QT_INSTALL_DEMOS]/glhypnotizer
+INSTALLS += target sources
+
+symbian: include($$QT_SOURCE_TREE/demos/symbianpkgrules.pri)
diff --git a/demos/glhypnotizer/hypnotizer.qrc b/demos/glhypnotizer/hypnotizer.qrc
new file mode 100644
index 0000000..97ba159
--- /dev/null
+++ b/demos/glhypnotizer/hypnotizer.qrc
@@ -0,0 +1,6 @@
+<!DOCTYPE RCC><RCC version="1.0">
+<qresource>
+ <file>qt-logo.png</file>
+ <file>spiral.svg</file>
+</qresource>
+</RCC> \ No newline at end of file
diff --git a/demos/glhypnotizer/main.cpp b/demos/glhypnotizer/main.cpp
new file mode 100644
index 0000000..cc1482d
--- /dev/null
+++ b/demos/glhypnotizer/main.cpp
@@ -0,0 +1,356 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the demonstration applications of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include <QtGui>
+#include <QtOpenGL>
+#include <QtSvg>
+
+#define NUM_SWIRLY_ITEMS 10
+
+class GLPainter : public QObject
+{
+ Q_OBJECT
+public:
+ GLPainter(QGLWidget *widget);
+ void stop();
+ void resizeViewport(const QSize &size);
+
+public slots:
+ void start();
+
+protected:
+ void timerEvent(QTimerEvent *event);
+ void paint();
+ void initSwirlyItems();
+ void updateSwirlyItems();
+ void drawSuggestiveMessages(QPainter *p);
+
+private:
+ QMutex mutex;
+ QGLWidget *glWidget;
+ int viewportWidth;
+ int viewportHeight;
+ bool doRendering;
+ qreal rotationAngle;
+ bool swirlClockwise;
+ QSvgRenderer svgRenderer;
+ QPixmap logo;
+ QPainter::PixmapFragment swirlyItems[NUM_SWIRLY_ITEMS];
+ int swirlyCounter;
+ int textCounter;
+ int messageYPos;
+ qreal scaleFactor;
+};
+
+
+GLPainter::GLPainter(QGLWidget *widget)
+ : glWidget(widget)
+ , doRendering(true)
+ , rotationAngle(rand() % 360)
+ , swirlClockwise((rand() % 2) == 1)
+ , svgRenderer(QLatin1String(":/spiral.svg"), this)
+ , logo(QLatin1String(":/qt-logo.png"))
+{
+}
+
+void GLPainter::start()
+{
+ glWidget->makeCurrent();
+ startTimer(20);
+}
+
+void GLPainter::stop()
+{
+ QMutexLocker locker(&mutex);
+ doRendering = false;
+}
+
+void GLPainter::resizeViewport(const QSize &size)
+{
+ QMutexLocker locker(&mutex);
+ viewportWidth = size.width();
+ viewportHeight = size.height();
+ initSwirlyItems();
+ textCounter = 0;
+ messageYPos = -1;
+}
+
+void GLPainter::timerEvent(QTimerEvent *event)
+{
+ QMutexLocker locker(&mutex);
+ if (!doRendering) {
+ killTimer(event->timerId());
+ QThread::currentThread()->quit();
+ return;
+ }
+ updateSwirlyItems();
+ paint();
+}
+
+void GLPainter::paint()
+{
+ QPainter p(glWidget);
+ p.fillRect(QRect(0, 0, viewportWidth, viewportHeight), Qt::white);
+ p.setRenderHints(QPainter::Antialiasing | QPainter::SmoothPixmapTransform);
+ p.translate(viewportWidth / 2, viewportHeight / 2);
+ p.rotate(rotationAngle * (swirlClockwise ? 1 : -1));
+ p.scale(svgRenderer.viewBox().width() / 200.0 * 0.65,
+ svgRenderer.viewBox().height() / 200.0 * 0.65);
+ p.translate(-viewportWidth / 2, -viewportHeight / 2);
+ svgRenderer.render(&p);
+ p.resetTransform();
+ p.drawPixmapFragments(swirlyItems, NUM_SWIRLY_ITEMS, logo);
+ drawSuggestiveMessages(&p);
+ p.end();
+ rotationAngle += 1.2;
+}
+
+void GLPainter::drawSuggestiveMessages(QPainter *p)
+{
+ const int numSuggestiveMessages = 7;
+ const char *texts[numSuggestiveMessages] = {" You feel relaxed.. ",
+ " Let your mind wander.. ",
+ " Look deep into the swirls.. ",
+ " Even deeper.. ",
+ " Qt is good! ",
+ " Qt is good for you! ",
+ " You MUST use Qt! "};
+ QFont font(p->font());
+ font.setPointSizeF(font.pointSizeF() * viewportWidth/200.0);
+ p->setFont(font);
+ QFontMetrics fm(font);
+ int messageNo = textCounter/314;
+ if (messageNo > 6 || messageNo < 0) {
+ qFatal("This should not happen: %d - %d", messageNo, textCounter);
+ }
+ QLatin1String text(texts[textCounter / 314]);
+ qreal textWidth = fm.width(text);
+ int alpha = 255 * qAbs(qSin(textCounter * 0.01));
+ if (messageYPos < 0 || (textCounter % 314 == 0)) {
+ messageYPos = qBound(fm.height(), rand() % viewportHeight,
+ viewportHeight - fm.height());
+ }
+ p->setPen(QColor(255, 255, 255, alpha));
+ p->setBackground(QColor(50, 50, 50, qBound(0, alpha, 50)));
+ p->setBackgroundMode(Qt::OpaqueMode);
+ p->drawText((viewportWidth / 2) - (textWidth/ 2), messageYPos, text);
+ ++textCounter;
+ if (textCounter >= (314 * numSuggestiveMessages))
+ textCounter = 0;
+}
+
+void GLPainter::initSwirlyItems()
+{
+ swirlyCounter = swirlClockwise ? 0 : 360;
+ scaleFactor = viewportWidth / 200.0;
+ QRectF logoRect(0, 0, logo.width(), logo.height());
+
+ for (int i=0; i<NUM_SWIRLY_ITEMS; ++i) {
+ if (swirlClockwise) {
+ swirlyItems[i] = QPainter::PixmapFragment::create(QPointF(0, 0), logoRect,
+ scaleFactor,
+ scaleFactor);
+ } else {
+ swirlyItems[i] = QPainter::PixmapFragment::create(QPointF(0, 0), logoRect,
+ scaleFactor * 1 / 360.0,
+ scaleFactor * 1 / 360.0);
+ }
+ }
+}
+
+void GLPainter::updateSwirlyItems()
+{
+ swirlyCounter += swirlClockwise ? 1 : -1;
+
+ for (int i=0; i<NUM_SWIRLY_ITEMS; ++i) {
+ int factor;
+ factor = swirlClockwise ? (swirlyCounter - i * 20) : (swirlyCounter + i * 20);
+ if (factor > 0 && factor <= 360) {
+ swirlyItems[i].x = viewportWidth / 2.0 + qSin(factor * 0.05) * (viewportWidth / 2.0) * (100.0 / factor);
+ swirlyItems[i].y = viewportHeight / 2.0 + qCos(factor * 0.05) * (viewportHeight / 2.0) * (100.0 / factor);
+ swirlyItems[i].rotation += -swirlyCounter * 0.01;
+ swirlyItems[i].scaleX += swirlClockwise ? -scaleFactor * 1 / 360.0 : scaleFactor * 1 / 360.0;
+ if (swirlClockwise) {
+ if (swirlyItems[i].scaleX < 0)
+ swirlyItems[i].scaleX = scaleFactor;
+ } else {
+ if (swirlyItems[i].scaleX > scaleFactor)
+ swirlyItems[i].scaleX = scaleFactor * 1 / 360.0;
+ }
+ swirlyItems[i].scaleY = swirlyItems[i].scaleX;
+ } else {
+ swirlyItems[i].scaleX = swirlyItems[i].scaleY = 0;
+ }
+ }
+ if (swirlClockwise) {
+ if (swirlyCounter > (360 + NUM_SWIRLY_ITEMS * 20))
+ swirlyCounter = 0;
+ } else {
+ if (swirlyCounter < -NUM_SWIRLY_ITEMS * 20)
+ swirlyCounter = 360;
+ }
+}
+
+class GLWidget : public QGLWidget
+{
+public:
+ GLWidget(QWidget *parent, QGLWidget *shareWidget = 0);
+ ~GLWidget();
+ void startRendering();
+ void stopRendering();
+
+protected:
+ void resizeEvent(QResizeEvent *event);
+ void paintEvent(QPaintEvent *event);
+ QSize sizeHint() const { return QSize(200, 200); }
+
+private:
+ GLPainter glPainter;
+ QThread glThread;
+};
+
+GLWidget::GLWidget(QWidget *parent, QGLWidget *share)
+ : QGLWidget(QGLFormat(QGL::SampleBuffers), parent, share)
+ , glPainter(this)
+ , glThread(this)
+{
+ setAttribute(Qt::WA_PaintOutsidePaintEvent);
+ setAttribute(Qt::WA_DeleteOnClose);
+}
+
+GLWidget::~GLWidget()
+{
+ stopRendering();
+}
+
+void GLWidget::startRendering()
+{
+ glPainter.moveToThread(&glThread);
+ connect(&glThread, SIGNAL(started()), &glPainter, SLOT(start()));
+ glThread.start();
+}
+
+void GLWidget::stopRendering()
+{
+ glPainter.stop();
+ glThread.wait();
+}
+
+void GLWidget::resizeEvent(QResizeEvent *event)
+{
+ glPainter.resizeViewport(event->size());
+}
+
+void GLWidget::paintEvent(QPaintEvent *)
+{
+ // Handled by GLPainter.
+}
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+public:
+ MainWindow();
+
+private slots:
+ void newThread();
+ void killThread();
+
+private:
+ QMdiArea mdiArea;
+ QGLWidget shareWidget;
+};
+
+MainWindow::MainWindow()
+ : QMainWindow(0)
+ , mdiArea(this)
+ , shareWidget(this)
+{
+ setWindowTitle("Qt GL Hypnotizer");
+ QMenu *menu = menuBar()->addMenu("&Hypnotizers");
+ menu->addAction("&New hypnotizer thread", this, SLOT(newThread()), QKeySequence("Ctrl+N"));
+ menu->addAction("&End current hypnotizer thread", this, SLOT(killThread()), QKeySequence("Ctrl+K"));
+ menu->addSeparator();
+ menu->addAction("E&xit", qApp, SLOT(quit()), QKeySequence("Ctrl+Q"));
+
+ setCentralWidget(&mdiArea);
+ shareWidget.resize(1, 1);
+ newThread();
+}
+
+void MainWindow::newThread()
+{
+ static int windowCount = 1;
+ if (mdiArea.subWindowList().count() > 9)
+ return;
+ GLWidget *widget = new GLWidget(&mdiArea, &shareWidget);
+ mdiArea.addSubWindow(widget);
+ widget->setWindowTitle("Thread #" + QString::number(windowCount++));
+ widget->show();
+ widget->startRendering();
+}
+
+void MainWindow::killThread()
+{
+ delete mdiArea.activeSubWindow();
+}
+
+int main(int argc, char *argv[])
+{
+ // Make Xlib and GLX thread safe under X11
+ QApplication::setAttribute(Qt::AA_X11InitThreads);
+ QApplication application(argc, argv);
+
+ // Using QPainter to draw into QGLWidgets is only supported with GL 2.0
+ if (!((QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_Version_2_0) ||
+ (QGLFormat::openGLVersionFlags() & QGLFormat::OpenGL_ES_Version_2_0))) {
+ QMessageBox::information(0, "Qt GL Hypnotizer",
+ "This system does not support OpenGL 2.0 or OpenGL ES 2.0, "
+ "which is required for this example to work.");
+ return 0;
+ }
+
+ MainWindow mainWindow;
+ mainWindow.show();
+ return application.exec();
+}
+
+#include "main.moc"
diff --git a/demos/glhypnotizer/qt-logo.png b/demos/glhypnotizer/qt-logo.png
new file mode 100644
index 0000000..eaea344
--- /dev/null
+++ b/demos/glhypnotizer/qt-logo.png
Binary files differ
diff --git a/demos/glhypnotizer/spiral.svg b/demos/glhypnotizer/spiral.svg
new file mode 100644
index 0000000..ff1f047
--- /dev/null
+++ b/demos/glhypnotizer/spiral.svg
@@ -0,0 +1,100 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:xlink="http://www.w3.org/1999/xlink"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="512"
+ height="512"
+ id="svg2"
+ version="1.1"
+ inkscape:version="0.47pre4 r22446"
+ sodipodi:docname="spiral.svg">
+ <defs
+ id="defs4">
+ <linearGradient
+ id="linearGradient5046">
+ <stop
+ style="stop-color:#000000;stop-opacity:0;"
+ offset="0"
+ id="stop5048" />
+ <stop
+ style="stop-color:#6c90da;stop-opacity:1;"
+ offset="1"
+ id="stop5050" />
+ </linearGradient>
+ <inkscape:perspective
+ sodipodi:type="inkscape:persp3d"
+ inkscape:vp_x="0 : 526.18109 : 1"
+ inkscape:vp_y="0 : 1000 : 0"
+ inkscape:vp_z="744.09448 : 526.18109 : 1"
+ inkscape:persp3d-origin="372.04724 : 350.78739 : 1"
+ id="perspective10" />
+ <radialGradient
+ inkscape:collect="always"
+ xlink:href="#linearGradient5046"
+ id="radialGradient5052"
+ cx="359.38702"
+ cy="438.07581"
+ fx="359.38702"
+ fy="438.07581"
+ r="304.44159"
+ gradientTransform="matrix(1,0,0,0.91551877,0,37.009184)"
+ gradientUnits="userSpaceOnUse" />
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.99232897"
+ inkscape:cx="267.31099"
+ inkscape:cy="295.6491"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ showgrid="false"
+ inkscape:window-width="963"
+ inkscape:window-height="1024"
+ inkscape:window-x="286"
+ inkscape:window-y="74"
+ inkscape:window-maximized="0" />
+ <metadata
+ id="metadata7">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <dc:title></dc:title>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1"
+ transform="translate(0,-540.36218)">
+ <path
+ sodipodi:type="spiral"
+ style="fill:url(#radialGradient5052);fill-opacity:1;stroke:#000000;stroke-width:20.29999924;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-opacity:1;stroke-dasharray:none"
+ id="path2816"
+ sodipodi:cx="331.42856"
+ sodipodi:cy="463.79074"
+ sodipodi:expansion="1"
+ sodipodi:revolution="3"
+ sodipodi:radius="337.44537"
+ sodipodi:argument="-18.046196"
+ sodipodi:t0="0"
+ d="m 331.42856,463.79074 c 11.74672,12.17647 -10.61822,21.84178 -20.23809,19.52382 -26.06925,-6.28154 -29.6746,-39.8823 -18.80954,-59.99999 19.43502,-35.98584 68.28562,-39.36493 99.76189,-18.09528 46.19269,31.21408 49.35062,97.07722 17.381,139.5238 -42.61047,56.57461 -126.00702,59.46265 -179.2857,16.66673 -67.04578,-53.85429 -69.64012,-155.00279 -15.95246,-219.0476 65.02296,-77.56686 184.03573,-79.85552 258.80951,-15.23819 88.11831,76.14929 90.09472,213.09185 14.52392,298.57141 C 400.3696,724.38498 245.45564,726.04525 149.28577,639.50509 40.011453,541.17265 38.669765,368.25918 136.1904,261.40987 245.59381,141.54108 436.52669,140.5196 554.04752,249.02876 684.51792,369.4945 685.21808,578.4614 565.71435,706.64779"
+ transform="matrix(0.9291373,0,0,0.91940263,-79.040559,394.33975)" />
+ </g>
+</svg>
diff --git a/doc/src/demos/glhypnotizer.qdoc b/doc/src/demos/glhypnotizer.qdoc
new file mode 100644
index 0000000..97b3c3b
--- /dev/null
+++ b/doc/src/demos/glhypnotizer.qdoc
@@ -0,0 +1,38 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Free Documentation License
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of this
+** file.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \example demos/glhypnotizer
+ \title GL Hypnotizer
+
+ This demo shows how to use OpenGL from a seperate thread.
+
+ \image glhypnotizer-demo.png
+
+ New MDI windows can be added by pressing Ctrl-N and each new child
+ window renders in it's own thread.
+*/
diff --git a/doc/src/images/glhypnotizer-demo.png b/doc/src/images/glhypnotizer-demo.png
new file mode 100644
index 0000000..5b7a1ae
--- /dev/null
+++ b/doc/src/images/glhypnotizer-demo.png
Binary files differ
diff --git a/src/3rdparty/wayland/qwaylandwindowmanager-client-protocol.h b/src/3rdparty/wayland/qwaylandwindowmanager-client-protocol.h
new file mode 100644
index 0000000..73673ae
--- /dev/null
+++ b/src/3rdparty/wayland/qwaylandwindowmanager-client-protocol.h
@@ -0,0 +1,110 @@
+/*
+ * Copyright © 2010 Kristian Høgsberg
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+
+#ifndef WAYLAND_WINDOWMANAGER_CLIENT_PROTOCOL_H
+#define WAYLAND_WINDOWMANAGER_CLIENT_PROTOCOL_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-util.h"
+
+struct wl_client;
+
+struct wl_windowmanager;
+
+struct wl_proxy;
+
+extern void
+wl_proxy_marshal(struct wl_proxy *p, uint32_t opcode, ...);
+extern struct wl_proxy *
+wl_proxy_create(struct wl_proxy *factory,
+ const struct wl_interface *interface);
+extern struct wl_proxy *
+wl_proxy_create_for_id(struct wl_display *display,
+ const struct wl_interface *interface, uint32_t id);
+extern void
+wl_proxy_destroy(struct wl_proxy *proxy);
+
+extern int
+wl_proxy_add_listener(struct wl_proxy *proxy,
+ void (**implementation)(void), void *data);
+
+extern void
+wl_proxy_set_user_data(struct wl_proxy *proxy, void *user_data);
+
+extern void *
+wl_proxy_get_user_data(struct wl_proxy *proxy);
+
+extern const struct wl_interface wl_windowmanager_interface;
+
+#define wl_WINDOWMANAGER_MAP_CLIENT_TO_PROCESS 0
+#define wl_WINDOWMANAGER_AUTHENTICATE_WITH_TOKEN 1
+
+static inline struct wl_windowmanager *
+wl_windowmanager_create(struct wl_display *display, uint32_t id)
+{
+ return (struct wl_windowmanager *)
+ wl_proxy_create_for_id(display, &wl_windowmanager_interface, id);
+}
+
+static inline void
+wl_windowmanager_set_user_data(struct wl_windowmanager *wl_windowmanager, void *user_data)
+{
+ wl_proxy_set_user_data((struct wl_proxy *) wl_windowmanager, user_data);
+}
+
+static inline void *
+wl_windowmanager_get_user_data(struct wl_windowmanager *wl_windowmanager)
+{
+ return wl_proxy_get_user_data((struct wl_proxy *) wl_windowmanager);
+}
+
+static inline void
+wl_windowmanager_destroy(struct wl_windowmanager *wl_windowmanager)
+{
+ wl_proxy_destroy((struct wl_proxy *) wl_windowmanager);
+}
+
+static inline void
+wl_windowmanager_map_client_to_process(struct wl_windowmanager *wl_windowmanager, uint32_t processid)
+{
+ wl_proxy_marshal((struct wl_proxy *) wl_windowmanager,
+ wl_WINDOWMANAGER_MAP_CLIENT_TO_PROCESS, processid);
+}
+
+static inline void
+wl_windowmanager_authenticate_with_token(struct wl_windowmanager *wl_windowmanager, const char *wl_authentication_token)
+{
+ wl_proxy_marshal((struct wl_proxy *) wl_windowmanager,
+ wl_WINDOWMANAGER_AUTHENTICATE_WITH_TOKEN, wl_authentication_token);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/3rdparty/wayland/wayland-windowmanager-protocol.c b/src/3rdparty/wayland/wayland-windowmanager-protocol.c
new file mode 100644
index 0000000..0250801
--- /dev/null
+++ b/src/3rdparty/wayland/wayland-windowmanager-protocol.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright © 2010 Kristian Høgsberg
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and its
+ * documentation for any purpose is hereby granted without fee, provided that
+ * the above copyright notice appear in all copies and that both that copyright
+ * notice and this permission notice appear in supporting documentation, and
+ * that the name of the copyright holders not be used in advertising or
+ * publicity pertaining to distribution of the software without specific,
+ * written prior permission. The copyright holders make no representations
+ * about the suitability of this software for any purpose. It is provided "as
+ * is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
+ * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
+ * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
+ * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
+ * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+ * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+ * OF THIS SOFTWARE.
+ */
+
+
+#include <stdlib.h>
+#include <stdint.h>
+#include "wayland-util.h"
+
+static const struct wl_message wl_windowmanager_requests[] = {
+ { "map_client_to_process", "u" },
+ { "authenticate_with_token", "s" },
+};
+
+WL_EXPORT const struct wl_interface wl_windowmanager_interface = {
+ "wl_windowmanager", 1,
+ ARRAY_LENGTH(wl_windowmanager_requests), wl_windowmanager_requests,
+ 0, NULL,
+};
diff --git a/src/declarative/qml/qdeclarativeengine.cpp b/src/declarative/qml/qdeclarativeengine.cpp
index b81f631..e5e89d4 100644
--- a/src/declarative/qml/qdeclarativeengine.cpp
+++ b/src/declarative/qml/qdeclarativeengine.cpp
@@ -1716,9 +1716,6 @@ QScriptValue QDeclarativeEnginePrivate::rect(QScriptContext *ctxt, QScriptEngine
qsreal w = ctxt->argument(2).toNumber();
qsreal h = ctxt->argument(3).toNumber();
- if (w < 0 || h < 0)
- return engine->nullValue();
-
return QDeclarativeEnginePrivate::get(engine)->scriptValueFromVariant(QVariant::fromValue(QRectF(x, y, w, h)));
}
diff --git a/src/gui/kernel/qapplication_mac.mm b/src/gui/kernel/qapplication_mac.mm
index eb0fd8d..0b9cad8 100644
--- a/src/gui/kernel/qapplication_mac.mm
+++ b/src/gui/kernel/qapplication_mac.mm
@@ -715,6 +715,7 @@ void qt_event_request_showsheet(QWidget *w)
{
Q_ASSERT(qt_mac_is_macsheet(w));
#ifdef QT_MAC_USE_COCOA
+ w->repaint();
[NSApp beginSheet:qt_mac_window_for(w) modalForWindow:qt_mac_window_for(w->parentWidget())
modalDelegate:nil didEndSelector:nil contextInfo:0];
#else
diff --git a/src/gui/kernel/qcocoaview_mac.mm b/src/gui/kernel/qcocoaview_mac.mm
index 13ff85b..e32fdeb 100644
--- a/src/gui/kernel/qcocoaview_mac.mm
+++ b/src/gui/kernel/qcocoaview_mac.mm
@@ -320,7 +320,7 @@ static int qCocoaViewCount = 0;
}
- CGContextFlush(context);
+ CGContextSynchronize(context);
qt_mac_release_graphics_context(context);
return;
}
diff --git a/src/gui/kernel/qplatformclipboard_qpa.cpp b/src/gui/kernel/qplatformclipboard_qpa.cpp
index 7905185..f8e4b62 100644
--- a/src/gui/kernel/qplatformclipboard_qpa.cpp
+++ b/src/gui/kernel/qplatformclipboard_qpa.cpp
@@ -83,7 +83,7 @@ QPlatformClipboard::~QPlatformClipboard()
}
-const QMimeData *QPlatformClipboard::mimeData(QClipboard::Mode mode) const
+QMimeData *QPlatformClipboard::mimeData(QClipboard::Mode mode)
{
//we know its clipboard
Q_UNUSED(mode);
diff --git a/src/gui/kernel/qplatformclipboard_qpa.h b/src/gui/kernel/qplatformclipboard_qpa.h
index 41aa951..6a40fbc 100644
--- a/src/gui/kernel/qplatformclipboard_qpa.h
+++ b/src/gui/kernel/qplatformclipboard_qpa.h
@@ -59,7 +59,7 @@ class Q_GUI_EXPORT QPlatformClipboard
public:
virtual ~QPlatformClipboard();
- virtual const QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard ) const;
+ virtual QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard);
virtual void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard);
virtual bool supportsMode(QClipboard::Mode mode) const;
void emitChanged(QClipboard::Mode mode);
diff --git a/src/gui/kernel/qwidget_qpa.cpp b/src/gui/kernel/qwidget_qpa.cpp
index a9bfba6..c7ce99a 100644
--- a/src/gui/kernel/qwidget_qpa.cpp
+++ b/src/gui/kernel/qwidget_qpa.cpp
@@ -731,12 +731,19 @@ QPlatformWindowFormat QWidget::platformWindowFormat() const
{
Q_D(const QWidget);
+ QPlatformWindowFormat format;
+
QTLWExtra *extra = d->maybeTopData();
if (extra){
- return extra->platformWindowFormat;
+ format = extra->platformWindowFormat;
} else {
- return QPlatformWindowFormat::defaultFormat();
+ format = QPlatformWindowFormat::defaultFormat();
}
+
+ if (testAttribute(Qt::WA_TranslucentBackground))
+ format.setAlpha(true);
+
+ return format;
}
void QWidgetPrivate::createSysExtra()
diff --git a/src/gui/painting/painting.pri b/src/gui/painting/painting.pri
index f1496b1..d5ae364 100644
--- a/src/gui/painting/painting.pri
+++ b/src/gui/painting/painting.pri
@@ -6,6 +6,7 @@ HEADERS += \
painting/qcolor.h \
painting/qcolor_p.h \
painting/qcolormap.h \
+ painting/qcosmeticstroker_p.h \
painting/qdrawutil.h \
painting/qemulationpaintengine_p.h \
painting/qgraphicssystem_p.h \
@@ -15,7 +16,7 @@ HEADERS += \
painting/qoutlinemapper_p.h \
painting/qpaintdevice.h \
painting/qpaintengine.h \
- painting/qpaintengine_p.h \
+ painting/qpaintengine_p.h \
painting/qpaintengine_alpha_p.h \
painting/qpaintengine_preview_p.h \
painting/qpaintengineex_p.h \
@@ -54,6 +55,7 @@ SOURCES += \
painting/qbrush.cpp \
painting/qcolor.cpp \
painting/qcolor_p.cpp \
+ painting/qcosmeticstroker.cpp \
painting/qcssutil.cpp \
painting/qdrawutil.cpp \
painting/qemulationpaintengine.cpp \
diff --git a/src/gui/painting/qcosmeticstroker.cpp b/src/gui/painting/qcosmeticstroker.cpp
new file mode 100644
index 0000000..cdc0978
--- /dev/null
+++ b/src/gui/painting/qcosmeticstroker.cpp
@@ -0,0 +1,1010 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qcosmeticstroker_p.h"
+#include "private/qpainterpath_p.h"
+#include <qdebug.h>
+#include <math.h>
+
+QT_BEGIN_NAMESPACE
+
+#if 0
+inline QString capString(int caps)
+{
+ QString str;
+ if (caps & QCosmeticStroker::CapBegin) {
+ str += "CapBegin ";
+ }
+ if (caps & QCosmeticStroker::CapEnd) {
+ str += "CapEnd ";
+ }
+ return str;
+}
+#endif
+
+#define toF26Dot6(x) ((int)((x)*64.))
+
+static inline uint sourceOver(uint d, uint color)
+{
+ return color + BYTE_MUL(d, qAlpha(~color));
+}
+
+inline static int F16Dot16FixedDiv(int x, int y)
+{
+ if (qAbs(x) > 0x7fff)
+ return (((qlonglong)x) << 16) / y;
+ return (x << 16) / y;
+}
+
+typedef void (*DrawPixel)(QCosmeticStroker *stroker, int x, int y, int coverage);
+
+namespace {
+
+struct Dasher {
+ QCosmeticStroker *stroker;
+ int *pattern;
+ int offset;
+ int dashIndex;
+ int dashOn;
+
+ Dasher(QCosmeticStroker *s, bool reverse, int start, int stop)
+ : stroker(s)
+ {
+ int delta = stop - start;
+ if (reverse) {
+ pattern = stroker->reversePattern;
+ offset = stroker->patternLength - stroker->patternOffset - delta - ((start & 63) - 32);
+ dashOn = 0;
+ } else {
+ pattern = stroker->pattern;
+ offset = stroker->patternOffset - ((start & 63) - 32);
+ dashOn = 1;
+ }
+ offset %= stroker->patternLength;
+ if (offset < 0)
+ offset += stroker->patternLength;
+
+ dashIndex = 0;
+ while (offset>= pattern[dashIndex])
+ ++dashIndex;
+
+// qDebug() << " dasher" << offset/64. << reverse << dashIndex;
+ stroker->patternOffset += delta;
+ stroker->patternOffset %= stroker->patternLength;
+ }
+
+ bool on() const {
+ return (dashIndex + dashOn) & 1;
+ }
+ void adjust() {
+ offset += 64;
+ if (offset >= pattern[dashIndex]) {
+ ++dashIndex;
+ dashIndex %= stroker->patternSize;
+ }
+ offset %= stroker->patternLength;
+// qDebug() << "dasher.adjust" << offset/64. << dashIndex;
+ }
+};
+
+struct NoDasher {
+ NoDasher(QCosmeticStroker *, bool, int, int) {}
+ bool on() const { return true; }
+ void adjust(int = 0) {}
+};
+
+};
+
+template<DrawPixel drawPixel, class Dasher>
+static void drawLine(QCosmeticStroker *stroker, qreal x1, qreal y1, qreal x2, qreal y2, int caps);
+template<DrawPixel drawPixel, class Dasher>
+static void drawLineAA(QCosmeticStroker *stroker, qreal x1, qreal y1, qreal x2, qreal y2, int caps);
+
+inline void drawPixel(QCosmeticStroker *stroker, int x, int y, int coverage)
+{
+ const QRect &cl = stroker->clip;
+ if (x < cl.x() || x > cl.right() || y < cl.y() || y > cl.bottom())
+ return;
+
+ int lastx = stroker->spans[stroker->current_span-1].x + stroker->spans[stroker->current_span-1].len ;
+ int lasty = stroker->spans[stroker->current_span-1].y;
+
+ if (stroker->current_span == QCosmeticStroker::NSPANS || y < lasty || (y == lasty && x < lastx)) {
+ stroker->blend(stroker->current_span, stroker->spans, &stroker->state->penData);
+ stroker->current_span = 0;
+ }
+
+ stroker->spans[stroker->current_span].x = ushort(x);
+ stroker->spans[stroker->current_span].len = 1;
+ stroker->spans[stroker->current_span].y = y;
+ stroker->spans[stroker->current_span].coverage = coverage*stroker->opacity >> 8;
+ ++stroker->current_span;
+}
+
+inline void drawPixelARGB32(QCosmeticStroker *stroker, int x, int y, int coverage)
+{
+ const QRect &cl = stroker->clip;
+ if (x < cl.x() || x > cl.right() || y < cl.y() || y > cl.bottom())
+ return;
+
+ int offset = x + stroker->ppl*y;
+ uint c = BYTE_MUL(stroker->color, coverage);
+ stroker->pixels[offset] = sourceOver(stroker->pixels[offset], c);
+}
+
+inline void drawPixelARGB32Opaque(QCosmeticStroker *stroker, int x, int y, int)
+{
+ const QRect &cl = stroker->clip;
+ if (x < cl.x() || x > cl.right() || y < cl.y() || y > cl.bottom())
+ return;
+
+ int offset = x + stroker->ppl*y;
+ stroker->pixels[offset] = sourceOver(stroker->pixels[offset], stroker->color);
+}
+
+enum StrokeSelection {
+ Aliased = 0,
+ AntiAliased = 1,
+ Solid = 0,
+ Dashed = 2,
+ RegularDraw = 0,
+ FastDraw = 4
+};
+
+static StrokeLine strokeLine(int strokeSelection)
+{
+ StrokeLine stroke;
+
+ switch (strokeSelection) {
+ case Aliased|Solid|RegularDraw:
+ stroke = &QT_PREPEND_NAMESPACE(drawLine)<drawPixel, NoDasher>;
+ break;
+ case Aliased|Solid|FastDraw:
+ stroke = &QT_PREPEND_NAMESPACE(drawLine)<drawPixelARGB32Opaque, NoDasher>;
+ break;
+ case Aliased|Dashed|RegularDraw:
+ stroke = &QT_PREPEND_NAMESPACE(drawLine)<drawPixel, Dasher>;
+ break;
+ case Aliased|Dashed|FastDraw:
+ stroke = &QT_PREPEND_NAMESPACE(drawLine)<drawPixelARGB32Opaque, Dasher>;
+ break;
+ case AntiAliased|Solid|RegularDraw:
+ stroke = &QT_PREPEND_NAMESPACE(drawLineAA)<drawPixel, NoDasher>;
+ break;
+ case AntiAliased|Solid|FastDraw:
+ stroke = &QT_PREPEND_NAMESPACE(drawLineAA)<drawPixelARGB32, NoDasher>;
+ break;
+ case AntiAliased|Dashed|RegularDraw:
+ stroke = &QT_PREPEND_NAMESPACE(drawLineAA)<drawPixel, Dasher>;
+ break;
+ case AntiAliased|Dashed|FastDraw:
+ stroke = &QT_PREPEND_NAMESPACE(drawLineAA)<drawPixelARGB32, Dasher>;
+ break;
+ default:
+ Q_ASSERT(false);
+ stroke = 0;
+ }
+ return stroke;
+}
+
+void QCosmeticStroker::setup()
+{
+ blend = state->penData.blend;
+ if (state->clip && state->clip->enabled && state->clip->hasRectClip && !state->clip->clipRect.isEmpty()) {
+ clip &= state->clip->clipRect;
+ blend = state->penData.unclipped_blend;
+ }
+
+ int strokeSelection = 0;
+ if (blend == state->penData.unclipped_blend
+ && state->penData.type == QSpanData::Solid
+ && (state->penData.rasterBuffer->format == QImage::Format_ARGB32_Premultiplied
+ || state->penData.rasterBuffer->format == QImage::Format_RGB32)
+ && state->compositionMode() == QPainter::CompositionMode_SourceOver)
+ strokeSelection |= FastDraw;
+
+ if (state->renderHints & QPainter::Antialiasing)
+ strokeSelection |= AntiAliased;
+
+ const QVector<qreal> &penPattern = state->lastPen.dashPattern();
+ if (penPattern.isEmpty()) {
+ Q_ASSERT(!pattern && !reversePattern);
+ pattern = 0;
+ reversePattern = 0;
+ patternLength = 0;
+ patternSize = 0;
+ } else {
+ pattern = (int *)malloc(penPattern.size()*sizeof(int));
+ reversePattern = (int *)malloc(penPattern.size()*sizeof(int));
+ patternSize = penPattern.size();
+
+ patternLength = 0;
+ for (int i = 0; i < patternSize; ++i) {
+ patternLength += (int) qMax(1. , penPattern.at(i)*64.);
+ pattern[i] = patternLength;
+ }
+ patternLength = 0;
+ for (int i = 0; i < patternSize; ++i) {
+ patternLength += (int) qMax(1., penPattern.at(patternSize - 1 - i)*64.);
+ reversePattern[i] = patternLength;
+ }
+ strokeSelection |= Dashed;
+// qDebug() << "setup: size=" << patternSize << "length=" << patternLength/64.;
+ }
+
+ stroke = strokeLine(strokeSelection);
+
+ qreal width = state->lastPen.widthF();
+ if (width == 0)
+ opacity = 256;
+ else if (state->lastPen.isCosmetic())
+ opacity = (int) 256*width;
+ else
+ opacity = (int) 256*width*state->txscale;
+ opacity = qBound(0, opacity, 256);
+
+ drawCaps = state->lastPen.capStyle() != Qt::FlatCap;
+
+ if (strokeSelection & FastDraw) {
+ color = INTERPOLATE_PIXEL_256(state->penData.solid.color, opacity, 0, 0);
+ QRasterBuffer *buffer = state->penData.rasterBuffer;
+ pixels = (uint *)buffer->buffer();
+ ppl = buffer->bytesPerLine()>>2;
+ }
+
+ // setup FP clip bounds
+ xmin = clip.left() - 1;
+ xmax = clip.right() + 2;
+ ymin = clip.top() - 1;
+ ymax = clip.bottom() + 2;
+
+ lastPixel.x = -1;
+}
+
+// returns true if the whole line gets clipped away
+bool QCosmeticStroker::clipLine(qreal &x1, qreal &y1, qreal &x2, qreal &y2)
+{
+ // basic/rough clipping is done in floating point coordinates to avoid
+ // integer overflow problems.
+ if (x1 < xmin) {
+ if (x2 <= xmin)
+ goto clipped;
+ y1 += (y2 - y1)/(x2 - x1) * (xmin - x1);
+ x1 = xmin;
+ } else if (x1 > xmax) {
+ if (x2 >= xmax)
+ goto clipped;
+ y1 += (y2 - y1)/(x2 - x1) * (xmax - x1);
+ x1 = xmax;
+ }
+ if (x2 < xmin) {
+ lastPixel.x = -1;
+ y2 += (y2 - y1)/(x2 - x1) * (xmin - x2);
+ x2 = xmin;
+ } else if (x2 > xmax) {
+ lastPixel.x = -1;
+ y2 += (y2 - y1)/(x2 - x1) * (xmax - x2);
+ x2 = xmax;
+ }
+
+ if (y1 < ymin) {
+ if (y2 <= ymin)
+ goto clipped;
+ x1 += (x2 - x1)/(y2 - y1) * (ymin - y1);
+ y1 = ymin;
+ } else if (y1 > ymax) {
+ if (y2 >= ymax)
+ goto clipped;
+ x1 += (x2 - x1)/(y2 - y1) * (ymax - y1);
+ y1 = ymax;
+ }
+ if (y2 < ymin) {
+ lastPixel.x = -1;
+ x2 += (x2 - x1)/(y2 - y1) * (ymin - y2);
+ y2 = ymin;
+ } else if (y2 > ymax) {
+ lastPixel.x = -1;
+ x2 += (x2 - x1)/(y2 - y1) * (ymax - y2);
+ y2 = ymax;
+ }
+
+ return false;
+
+ clipped:
+ lastPixel.x = -1;
+ return true;
+}
+
+
+void QCosmeticStroker::drawLine(const QPointF &p1, const QPointF &p2)
+{
+ QPointF start = p1 * state->matrix;
+ QPointF end = p2 * state->matrix;
+
+ patternOffset = state->lastPen.dashOffset()*64;
+ lastPixel.x = -1;
+
+ stroke(this, start.x(), start.y(), end.x(), end.y(), drawCaps ? CapBegin|CapEnd : 0);
+
+ blend(current_span, spans, &state->penData);
+ current_span = 0;
+}
+
+void QCosmeticStroker::drawPoints(const QPoint *points, int num)
+{
+ const QPoint *end = points + num;
+ while (points < end) {
+ QPointF p = QPointF(*points) * state->matrix;
+ drawPixel(this, qRound(p.x()), qRound(p.y()), 255);
+ ++points;
+ }
+
+ blend(current_span, spans, &state->penData);
+ current_span = 0;
+}
+
+void QCosmeticStroker::drawPoints(const QPointF *points, int num)
+{
+ const QPointF *end = points + num;
+ while (points < end) {
+ QPointF p = (*points) * state->matrix;
+ drawPixel(this, qRound(p.x()), qRound(p.y()), 255);
+ ++points;
+ }
+
+ blend(current_span, spans, &state->penData);
+ current_span = 0;
+}
+
+void QCosmeticStroker::calculateLastPoint(qreal rx1, qreal ry1, qreal rx2, qreal ry2)
+{
+ // this is basically the same code as used in the aliased stroke method,
+ // but it only determines the direction and last point of a line
+ //
+ // This is being used to have proper dropout control for closed contours
+ // by calculating the direction and last pixel of the last segment in the contour.
+ // the info is then used to perform dropout control when drawing the first line segment
+ // of the contour
+ lastPixel.x = -1;
+ lastPixel.y = -1;
+
+ if (clipLine(rx1, ry1, rx2, ry2))
+ return;
+
+ const int half = 32;
+ int x1 = toF26Dot6(rx1) + half;
+ int y1 = toF26Dot6(ry1) + half;
+ int x2 = toF26Dot6(rx2) + half;
+ int y2 = toF26Dot6(ry2) + half;
+
+ int dx = qAbs(x2 - x1);
+ int dy = qAbs(y2 - y1);
+
+ if (dx < dy) {
+ // vertical
+ bool swapped = false;
+ if (y1 > y2) {
+ swapped = true;
+ qSwap(y1, y2);
+ qSwap(x1, x2);
+ --x1; --x2; --y1; --y2;
+ }
+ int xinc = F16Dot16FixedDiv(x2 - x1, y2 - y1);
+ int x = x1 << 10;
+
+ int y = (y1+32) >> 6;
+ int ys = (y2+32) >> 6;
+
+ if (y != ys) {
+ x += ( ((((y << 6) + 32 - y1))) * xinc ) >> 6;
+
+ if (swapped) {
+ lastPixel.x = x >> 16;
+ lastPixel.y = y;
+ lastDir = QCosmeticStroker::BottomToTop;
+ } else {
+ lastPixel.x = (x + (ys - y - 1)*xinc) >> 16;
+ lastPixel.y = ys - 1;
+ lastDir = QCosmeticStroker::TopToBottom;
+ }
+ lastAxisAligned = qAbs(xinc) < (1 << 14);
+ }
+ } else {
+ // horizontal
+ if (!dx)
+ return;
+
+ bool swapped = false;
+ if (x1 > x2) {
+ swapped = true;
+ qSwap(x1, x2);
+ qSwap(y1, y2);
+ --x1; --x2; --y1; --y2;
+ }
+ int yinc = F16Dot16FixedDiv(y2 - y1, x2 - x1);
+ int y = y1 << 10;
+
+ int x = (x1+32) >> 6;
+ int xs = (x2+32) >> 6;
+
+ if (x != xs) {
+ y += ( ((((x << 6) + 32 - x1))) * yinc ) >> 6;
+
+ if (swapped) {
+ lastPixel.x = x;
+ lastPixel.y = y >> 16;
+ lastDir = QCosmeticStroker::RightToLeft;
+ } else {
+ lastPixel.x = xs - 1;
+ lastPixel.y = (y + (xs - x - 1)*yinc) >> 16;
+ lastDir = QCosmeticStroker::LeftToRight;
+ }
+ lastAxisAligned = qAbs(yinc) < (1 << 14);
+ }
+ }
+// qDebug() << " moveTo: setting last pixel to x/y dir" << lastPixel.x << lastPixel.y << lastDir;
+}
+
+static inline const QPainterPath::ElementType *subPath(const QPainterPath::ElementType *t, const QPainterPath::ElementType *end,
+ const qreal *points, bool *closed)
+{
+ const QPainterPath::ElementType *start = t;
+ ++t;
+
+ // find out if the subpath is closed
+ while (t < end) {
+ if (*t == QPainterPath::MoveToElement)
+ break;
+ ++t;
+ }
+
+ int offset = t - start - 1;
+// qDebug() << "subpath" << offset << points[0] << points[1] << points[2*offset] << points[2*offset+1];
+ *closed = (points[0] == points[2*offset] && points[1] == points[2*offset + 1]);
+
+ return t;
+}
+
+void QCosmeticStroker::drawPath(const QVectorPath &path)
+{
+// qDebug() << ">>>> drawpath" << path.convertToPainterPath()
+// << "antialiasing:" << (bool)(state->renderHints & QPainter::Antialiasing) << " implicit close:" << path.hasImplicitClose();
+ if (path.isEmpty())
+ return;
+
+ const qreal *points = path.points();
+ const QPainterPath::ElementType *type = path.elements();
+
+ if (type) {
+ const QPainterPath::ElementType *end = type + path.elementCount();
+
+ while (type < end) {
+ Q_ASSERT(type == path.elements() || *type == QPainterPath::MoveToElement);
+
+ QPointF p = QPointF(points[0], points[1]) * state->matrix;
+ QPointF movedTo = p;
+ patternOffset = state->lastPen.dashOffset()*64;
+ lastPixel.x = -1;
+
+ bool closed;
+ const QPainterPath::ElementType *e = subPath(type, end, points, &closed);
+ if (closed) {
+ const qreal *p = points + 2*(e-type);
+ QPointF p1 = QPointF(p[-4], p[-3]) * state->matrix;
+ QPointF p2 = QPointF(p[-2], p[-1]) * state->matrix;
+ calculateLastPoint(p1.x(), p1.y(), p2.x(), p2.y());
+ }
+ int caps = (!closed & drawCaps) ? CapBegin : NoCaps;
+// qDebug() << "closed =" << closed << capString(caps);
+
+ points += 2;
+ ++type;
+
+ while (type < e) {
+ QPointF p2 = QPointF(points[0], points[1]) * state->matrix;
+ switch (*type) {
+ case QPainterPath::MoveToElement:
+ Q_ASSERT(!"Logic error");
+ break;
+
+ case QPainterPath::LineToElement:
+ if (!closed && drawCaps && type == e - 1)
+ caps |= CapEnd;
+ stroke(this, p.x(), p.y(), p2.x(), p2.y(), caps);
+ p = p2;
+ points += 2;
+ ++type;
+ break;
+
+ case QPainterPath::CurveToElement: {
+ if (!closed && drawCaps && type == e - 3)
+ caps |= CapEnd;
+ QPointF p3 = QPointF(points[2], points[3]) * state->matrix;
+ QPointF p4 = QPointF(points[4], points[5]) * state->matrix;
+ renderCubic(p, p2, p3, p4, caps);
+ p = p4;
+ type += 3;
+ points += 6;
+ break;
+ }
+ case QPainterPath::CurveToDataElement:
+ Q_ASSERT(!"QPainterPath::toSubpathPolygons(), bad element type");
+ break;
+ }
+ caps = NoCaps;
+ }
+ }
+ } else { // !type, simple polygon
+ QPointF p = QPointF(points[0], points[1]) * state->matrix;
+ QPointF movedTo = p;
+ patternOffset = state->lastPen.dashOffset()*64;
+ lastPixel.x = -1;
+
+ const qreal *end = points + 2*path.elementCount();
+ // handle closed path case
+ bool closed = path.hasImplicitClose() || (points[0] == end[-2] && points[1] == end[-1]);
+ int caps = (!closed & drawCaps) ? CapBegin : NoCaps;
+ if (closed) {
+ QPointF p2 = QPointF(end[-2], end[-1]) * state->matrix;
+ calculateLastPoint(p2.x(), p2.y(), p.x(), p.y());
+ }
+
+ points += 2;
+ while (points < end) {
+ QPointF p2 = QPointF(points[0], points[1]) * state->matrix;
+
+ if (!closed && drawCaps && points == end - 2)
+ caps |= CapEnd;
+
+ stroke(this, p.x(), p.y(), p2.x(), p2.y(), caps);
+
+ p = p2;
+ points += 2;
+ caps = NoCaps;
+ }
+ if (path.hasImplicitClose())
+ stroke(this, p.x(), p.y(), movedTo.x(), movedTo.y(), NoCaps);
+ }
+
+
+ blend(current_span, spans, &state->penData);
+ current_span = 0;
+}
+
+void QCosmeticStroker::renderCubic(const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &p4, int caps)
+{
+// qDebug() << ">>>> renderCubic" << p1 << p2 << p3 << p4 << capString(caps);
+ const int maxSubDivisions = 6;
+ PointF points[3*maxSubDivisions + 4];
+
+ points[3].x = p1.x();
+ points[3].y = p1.y();
+ points[2].x = p2.x();
+ points[2].y = p2.y();
+ points[1].x = p3.x();
+ points[1].y = p3.y();
+ points[0].x = p4.x();
+ points[0].y = p4.y();
+
+ PointF *p = points;
+ int level = maxSubDivisions;
+
+ renderCubicSubdivision(p, level, caps);
+}
+
+static void splitCubic(QCosmeticStroker::PointF *points)
+{
+ const qreal half = .5;
+ qreal a, b, c, d;
+
+ points[6].x = points[3].x;
+ c = points[1].x;
+ d = points[2].x;
+ points[1].x = a = ( points[0].x + c ) * half;
+ points[5].x = b = ( points[3].x + d ) * half;
+ c = ( c + d ) * half;
+ points[2].x = a = ( a + c ) * half;
+ points[4].x = b = ( b + c ) * half;
+ points[3].x = ( a + b ) * half;
+
+ points[6].y = points[3].y;
+ c = points[1].y;
+ d = points[2].y;
+ points[1].y = a = ( points[0].y + c ) * half;
+ points[5].y = b = ( points[3].y + d ) * half;
+ c = ( c + d ) * half;
+ points[2].y = a = ( a + c ) * half;
+ points[4].y = b = ( b + c ) * half;
+ points[3].y = ( a + b ) * half;
+}
+
+void QCosmeticStroker::renderCubicSubdivision(QCosmeticStroker::PointF *points, int level, int caps)
+{
+ if (level) {
+ qreal dx = points[3].x - points[0].x;
+ qreal dy = points[3].y - points[0].y;
+ qreal len = ((qreal).25) * (qAbs(dx) + qAbs(dy));
+
+ if (qAbs(dx * (points[0].y - points[2].y) - dy * (points[0].x - points[2].x)) >= len ||
+ qAbs(dx * (points[0].y - points[1].y) - dy * (points[0].x - points[1].x)) >= len) {
+ splitCubic(points);
+
+ --level;
+ renderCubicSubdivision(points + 3, level, caps & CapBegin);
+ renderCubicSubdivision(points, level, caps & CapEnd);
+ return;
+ }
+ }
+
+ stroke(this, points[3].x, points[3].y, points[0].x, points[0].y, caps);
+}
+
+static inline int swapCaps(int caps)
+{
+ return ((caps & QCosmeticStroker::CapBegin) << 1) |
+ ((caps & QCosmeticStroker::CapEnd) >> 1);
+}
+
+// adjust line by half a pixel
+static inline void capAdjust(int caps, int &x1, int &x2, int &y, int yinc)
+{
+ if (caps & QCosmeticStroker::CapBegin) {
+ x1 -= 32;
+ y -= yinc >> 1;
+ }
+ if (caps & QCosmeticStroker::CapEnd) {
+ x2 += 32;
+ }
+}
+
+/*
+ The hard part about this is dropout control and avoiding douple drawing of points when
+ the drawing shifts from horizontal to vertical or back.
+ */
+template<DrawPixel drawPixel, class Dasher>
+static void drawLine(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx2, qreal ry2, int caps)
+{
+ if (stroker->clipLine(rx1, ry1, rx2, ry2))
+ return;
+
+ static const int half = 32;
+ int x1 = toF26Dot6(rx1) + half;
+ int y1 = toF26Dot6(ry1) + half;
+ int x2 = toF26Dot6(rx2) + half;
+ int y2 = toF26Dot6(ry2) + half;
+
+ int dx = qAbs(x2 - x1);
+ int dy = qAbs(y2 - y1);
+
+ QCosmeticStroker::Point last = stroker->lastPixel;
+
+// qDebug() << "stroke" << x1/64. << y1/64. << x2/64. << y2/64. << capString(caps);
+
+ if (dx < dy) {
+ // vertical
+
+ bool swapped = false;
+ if (y1 > y2) {
+ swapped = true;
+ qSwap(y1, y2);
+ qSwap(x1, x2);
+ caps = swapCaps(caps);
+ --x1; --x2; --y1; --y2;
+ }
+ int xinc = F16Dot16FixedDiv(x2 - x1, y2 - y1);
+ int x = x1 << 10;
+
+ capAdjust(caps, y1, y2, x, xinc);
+
+ int y = (y1+32) >> 6;
+ int ys = (y2+32) >> 6;
+
+ if (y != ys) {
+ x += ( ((((y << 6) + 32 - y1))) * xinc ) >> 6;
+
+ // calculate first and last pixel and perform dropout control
+ QCosmeticStroker::Direction dir = QCosmeticStroker::TopToBottom;
+ QCosmeticStroker::Point first;
+ first.x = x >> 16;
+ first.y = y;
+ last.x = (x + (ys - y - 1)*xinc) >> 16;
+ last.y = ys - 1;
+ if (swapped) {
+ qSwap(first, last);
+ dir = QCosmeticStroker::BottomToTop;
+ }
+ bool axisAligned = qAbs(xinc) < (1 << 14);
+ if (stroker->lastPixel.x >= 0) {
+ if (first.x == stroker->lastPixel.x &&
+ first.y == stroker->lastPixel.y) {
+ // remove duplicated pixel
+ if (swapped) {
+ --ys;
+ } else {
+ ++y;
+ x += xinc;
+ }
+ } else if (stroker->lastDir != dir &&
+ (((axisAligned && stroker->lastAxisAligned) &&
+ stroker->lastPixel.x != first.x && stroker->lastPixel.y != first.y) ||
+ (qAbs(stroker->lastPixel.x - first.x) > 1 &&
+ qAbs(stroker->lastPixel.y - first.y) > 1))) {
+ // have a missing pixel, insert it
+ if (swapped) {
+ ++ys;
+ } else {
+ --y;
+ x -= xinc;
+ }
+ }
+ }
+ stroker->lastDir = dir;
+ stroker->lastAxisAligned = axisAligned;
+
+ Dasher dasher(stroker, swapped, y << 6, ys << 6);
+
+ do {
+ if (dasher.on())
+ drawPixel(stroker, x >> 16, y, 255);
+ dasher.adjust();
+ x += xinc;
+ } while (++y < ys);
+ }
+ } else {
+ // horizontal
+ if (!dx)
+ return;
+
+ bool swapped = false;
+ if (x1 > x2) {
+ swapped = true;
+ qSwap(x1, x2);
+ qSwap(y1, y2);
+ caps = swapCaps(caps);
+ --x1; --x2; --y1; --y2;
+ }
+ int yinc = F16Dot16FixedDiv(y2 - y1, x2 - x1);
+ int y = y1 << 10;
+
+ capAdjust(caps, x1, x2, y, yinc);
+
+ int x = (x1+32) >> 6;
+ int xs = (x2+32) >> 6;
+
+
+ if (x != xs) {
+ y += ( ((((x << 6) + 32 - x1))) * yinc ) >> 6;
+
+ // calculate first and last pixel to perform dropout control
+ QCosmeticStroker::Direction dir = QCosmeticStroker::LeftToRight;
+ QCosmeticStroker::Point first;
+ first.x = x;
+ first.y = y >> 16;
+ last.x = xs - 1;
+ last.y = (y + (xs - x - 1)*yinc) >> 16;
+ if (swapped) {
+ qSwap(first, last);
+ dir = QCosmeticStroker::RightToLeft;
+ }
+ bool axisAligned = qAbs(yinc) < (1 << 14);
+ if (stroker->lastPixel.x >= 0) {
+ if (first.x == stroker->lastPixel.x && first.y == stroker->lastPixel.y) {
+ // remove duplicated pixel
+ if (swapped) {
+ --xs;
+ } else {
+ ++x;
+ y += yinc;
+ }
+ } else if (stroker->lastDir != dir &&
+ (((axisAligned && stroker->lastAxisAligned) &&
+ stroker->lastPixel.x != first.x && stroker->lastPixel.y != first.y) ||
+ (qAbs(stroker->lastPixel.x - first.x) > 1 &&
+ qAbs(stroker->lastPixel.y - first.y) > 1))) {
+ // have a missing pixel, insert it
+ if (swapped) {
+ ++xs;
+ } else {
+ --x;
+ y -= yinc;
+ }
+ }
+ }
+ stroker->lastDir = dir;
+ stroker->lastAxisAligned = axisAligned;
+
+ Dasher dasher(stroker, swapped, x << 6, xs << 6);
+
+ do {
+ if (dasher.on())
+ drawPixel(stroker, x, y >> 16, 255);
+ dasher.adjust();
+ y += yinc;
+ } while (++x < xs);
+ }
+ }
+ stroker->lastPixel = last;
+}
+
+
+template<DrawPixel drawPixel, class Dasher>
+static void drawLineAA(QCosmeticStroker *stroker, qreal rx1, qreal ry1, qreal rx2, qreal ry2, int caps)
+{
+ if (stroker->clipLine(rx1, ry1, rx2, ry2))
+ return;
+
+ int x1 = toF26Dot6(rx1);
+ int y1 = toF26Dot6(ry1);
+ int x2 = toF26Dot6(rx2);
+ int y2 = toF26Dot6(ry2);
+
+ int dx = x2 - x1;
+ int dy = y2 - y1;
+
+ if (qAbs(dx) < qAbs(dy)) {
+ // vertical
+
+ int xinc = F16Dot16FixedDiv(dx, dy);
+
+ bool swapped = false;
+ if (y1 > y2) {
+ qSwap(y1, y2);
+ qSwap(x1, x2);
+ swapped = true;
+ caps = swapCaps(caps);
+ }
+
+ int x = (x1 - 32) << 10;
+ x -= ( ((y1 & 63) - 32) * xinc ) >> 6;
+
+ capAdjust(caps, y1, y2, x, xinc);
+
+ Dasher dasher(stroker, swapped, y1, y2);
+
+ int y = y1 >> 6;
+ int ys = y2 >> 6;
+
+ int alphaStart, alphaEnd;
+ if (y == ys) {
+ alphaStart = y2 - y1;
+ Q_ASSERT(alphaStart >= 0 && alphaStart < 64);
+ alphaEnd = 0;
+ } else {
+ alphaStart = 64 - (y1 & 63);
+ alphaEnd = (y2 & 63);
+ }
+// qDebug() << "vertical" << x1/64. << y1/64. << x2/64. << y2/64.;
+// qDebug() << " x=" << x << "dx=" << dx << "xi=" << (x>>16) << "xsi=" << ((x+(ys-y)*dx)>>16) << "y=" << y << "ys=" << ys;
+
+ // draw first pixel
+ if (dasher.on()) {
+ uint alpha = (quint8)(x >> 8);
+ drawPixel(stroker, x>>16, y, (255-alpha) * alphaStart >> 6);
+ drawPixel(stroker, (x>>16) + 1, y, alpha * alphaStart >> 6);
+ }
+ dasher.adjust();
+ x += xinc;
+ ++y;
+ if (y < ys) {
+ do {
+ if (dasher.on()) {
+ uint alpha = (quint8)(x >> 8);
+ drawPixel(stroker, x>>16, y, (255-alpha));
+ drawPixel(stroker, (x>>16) + 1, y, alpha);
+ }
+ dasher.adjust();
+ x += xinc;
+ } while (++y < ys);
+ }
+ // draw last pixel
+ if (alphaEnd && dasher.on()) {
+ uint alpha = (quint8)(x >> 8);
+ drawPixel(stroker, x>>16, y, (255-alpha) * alphaEnd >> 6);
+ drawPixel(stroker, (x>>16) + 1, y, alpha * alphaEnd >> 6);
+ }
+ } else {
+ // horizontal
+ if (!dx)
+ return;
+
+ int yinc = F16Dot16FixedDiv(dy, dx);
+
+ bool swapped = false;
+ if (x1 > x2) {
+ qSwap(x1, x2);
+ qSwap(y1, y2);
+ swapped = true;
+ caps = swapCaps(caps);
+ }
+
+ int y = (y1 - 32) << 10;
+ y -= ( ((x1 & 63) - 32) * yinc ) >> 6;
+
+ capAdjust(caps, x1, x2, y, yinc);
+
+ Dasher dasher(stroker, swapped, x1, x2);
+
+ int x = x1 >> 6;
+ int xs = x2 >> 6;
+
+// qDebug() << "horizontal" << x1/64. << y1/64. << x2/64. << y2/64.;
+// qDebug() << " y=" << y << "dy=" << dy << "x=" << x << "xs=" << xs << "yi=" << (y>>16) << "ysi=" << ((y+(xs-x)*dy)>>16);
+ int alphaStart, alphaEnd;
+ if (x == xs) {
+ alphaStart = x2 - x1;
+ Q_ASSERT(alphaStart >= 0 && alphaStart < 64);
+ alphaEnd = 0;
+ } else {
+ alphaStart = 64 - (x1 & 63);
+ alphaEnd = (x2 & 63);
+ }
+
+ // draw first pixel
+ if (dasher.on()) {
+ uint alpha = (quint8)(y >> 8);
+ drawPixel(stroker, x, y>>16, (255-alpha) * alphaStart >> 6);
+ drawPixel(stroker, x, (y>>16) + 1, alpha * alphaStart >> 6);
+ }
+ dasher.adjust();
+ y += yinc;
+ ++x;
+ // draw line
+ if (x < xs) {
+ do {
+ if (dasher.on()) {
+ uint alpha = (quint8)(y >> 8);
+ drawPixel(stroker, x, y>>16, (255-alpha));
+ drawPixel(stroker, x, (y>>16) + 1, alpha);
+ }
+ dasher.adjust();
+ y += yinc;
+ } while (++x < xs);
+ }
+ // draw last pixel
+ if (alphaEnd && dasher.on()) {
+ uint alpha = (quint8)(y >> 8);
+ drawPixel(stroker, x, y>>16, (255-alpha) * alphaEnd >> 6);
+ drawPixel(stroker, x, (y>>16) + 1, alpha * alphaEnd >> 6);
+ }
+ }
+}
+
+QT_END_NAMESPACE
diff --git a/src/gui/painting/qcosmeticstroker_p.h b/src/gui/painting/qcosmeticstroker_p.h
new file mode 100644
index 0000000..0aa71fc
--- /dev/null
+++ b/src/gui/painting/qcosmeticstroker_p.h
@@ -0,0 +1,152 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtGui module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QCOSMETICSTROKER_P_H
+#define QCOSMETICSTROKER_P_H
+
+#include <private/qdrawhelper_p.h>
+#include <private/qvectorpath_p.h>
+#include <private/qpaintengine_raster_p.h>
+#include <qpen.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QCosmeticStroker;
+
+
+typedef void (*StrokeLine)(QCosmeticStroker *stroker, qreal x1, qreal y1, qreal x2, qreal y2, int caps);
+
+class QCosmeticStroker
+{
+public:
+ struct Point {
+ int x;
+ int y;
+ };
+ struct PointF {
+ qreal x;
+ qreal y;
+ };
+
+ enum Caps {
+ NoCaps = 0,
+ CapBegin = 0x1,
+ CapEnd = 0x2,
+ };
+
+ // used to avoid drop outs or duplicated points
+ enum Direction {
+ TopToBottom,
+ BottomToTop,
+ LeftToRight,
+ RightToLeft
+ };
+
+ QCosmeticStroker(QRasterPaintEngineState *s, const QRect &dr)
+ : state(s),
+ clip(dr),
+ pattern(0),
+ reversePattern(0),
+ patternSize(0),
+ patternLength(0),
+ patternOffset(0),
+ current_span(0),
+ lastDir(LeftToRight),
+ lastAxisAligned(false)
+ { setup(); }
+ ~QCosmeticStroker() { free(pattern); free(reversePattern); }
+ void drawLine(const QPointF &p1, const QPointF &p2);
+ void drawPath(const QVectorPath &path);
+ void drawPoints(const QPoint *points, int num);
+ void drawPoints(const QPointF *points, int num);
+
+
+ QRasterPaintEngineState *state;
+ QRect clip;
+ // clip bounds in real
+ qreal xmin, xmax;
+ qreal ymin, ymax;
+
+ StrokeLine stroke;
+ bool drawCaps;
+
+ int *pattern;
+ int *reversePattern;
+ int patternSize;
+ int patternLength;
+ int patternOffset;
+
+ enum { NSPANS = 255 };
+ QT_FT_Span spans[NSPANS];
+ int current_span;
+ ProcessSpans blend;
+
+ int opacity;
+
+ uint color;
+ uint *pixels;
+ int ppl;
+
+ Direction lastDir;
+ Point lastPixel;
+ bool lastAxisAligned;
+
+private:
+ void setup();
+
+ void renderCubic(const QPointF &p1, const QPointF &p2, const QPointF &p3, const QPointF &p4, int caps);
+ void renderCubicSubdivision(PointF *points, int level, int caps);
+ // used for closed subpaths
+ void calculateLastPoint(qreal rx1, qreal ry1, qreal rx2, qreal ry2);
+
+public:
+ bool clipLine(qreal &x1, qreal &y1, qreal &x2, qreal &y2);
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QCOSMETICLINE_H
diff --git a/src/gui/painting/qoutlinemapper.cpp b/src/gui/painting/qoutlinemapper.cpp
index 7c17c1b..8b607b2 100644
--- a/src/gui/painting/qoutlinemapper.cpp
+++ b/src/gui/painting/qoutlinemapper.cpp
@@ -47,6 +47,8 @@
QT_BEGIN_NAMESPACE
+static const qreal aliasedCoordinateDelta = 0.5 - 0.015625;
+
#define qreal_to_fixed_26_6(f) (int(f * 64))
@@ -214,6 +216,13 @@ void QOutlineMapper::endOutline()
elements = m_elements_dev.data();
}
+ if (m_round_coords) {
+ // round coordinates to match outlines drawn with drawLine_midpoint_i
+ for (int i = 0; i < m_elements.size(); ++i)
+ elements[i] = QPointF(qFloor(elements[i].x() + aliasedCoordinateDelta),
+ qFloor(elements[i].y() + aliasedCoordinateDelta));
+ }
+
controlPointRect = boundingRect(elements, element_count);
#ifdef QT_DEBUG_CONVERT
diff --git a/src/gui/painting/qoutlinemapper_p.h b/src/gui/painting/qoutlinemapper_p.h
index 1432d6f..388858c 100644
--- a/src/gui/painting/qoutlinemapper_p.h
+++ b/src/gui/painting/qoutlinemapper_p.h
@@ -95,7 +95,8 @@ public:
m_tags(0),
m_contours(0),
m_polygon_dev(0),
- m_in_clip_elements(false)
+ m_in_clip_elements(false),
+ m_round_coords(false)
{
}
@@ -201,6 +202,8 @@ public:
QT_FT_Outline *convertPath(const QPainterPath &path);
QT_FT_Outline *convertPath(const QVectorPath &path);
+ void setCoordinateRounding(bool coordinateRounding) { m_round_coords = coordinateRounding; }
+
inline QPainterPath::ElementType *elementTypes() const { return m_element_types.size() == 0 ? 0 : m_element_types.data(); }
public:
@@ -234,6 +237,9 @@ public:
bool m_valid;
bool m_in_clip_elements;
+
+private:
+ bool m_round_coords;
};
QT_END_NAMESPACE
diff --git a/src/gui/painting/qpaintengine_mac_p.h b/src/gui/painting/qpaintengine_mac_p.h
index c87501e..2434011 100644
--- a/src/gui/painting/qpaintengine_mac_p.h
+++ b/src/gui/painting/qpaintengine_mac_p.h
@@ -121,6 +121,8 @@ public:
void drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
{ QPaintEngine::drawPolygon(points, pointCount, mode); }
+ bool supportsTransformations(qreal, const QTransform &) const { return true; };
+
protected:
friend class QMacPrintEngine;
friend class QMacPrintEnginePrivate;
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index 5ce94f8..57c94a8 100644
--- a/src/gui/painting/qpaintengine_raster.cpp
+++ b/src/gui/painting/qpaintengine_raster.cpp
@@ -69,6 +69,7 @@
// #include <private/qrasterizer_p.h>
#include <private/qimage_p.h>
#include <private/qstatictext_p.h>
+#include <private/qcosmeticstroker_p.h>
#include "qmemrotate_p.h"
#include "qpaintengine_raster_p.h"
@@ -126,6 +127,9 @@ void dumpClip(int width, int height, const QClipData *clip);
// 4 pixels.
#define int_dim(pos, dim) (int(pos+dim) - int(pos))
+// use the same rounding as in qrasterizer.cpp (6 bit fixed point)
+static const qreal aliasedCoordinateDelta = 0.5 - 0.015625;
+
#ifdef Q_WS_WIN
extern bool qt_cleartype_enabled;
#endif
@@ -156,16 +160,6 @@ enum LineDrawMode {
LineDrawIncludeLastPixel
};
-static void drawLine_midpoint_i(int x1, int y1, int x2, int y2, ProcessSpans span_func, QSpanData *data,
- LineDrawMode style, const QIntRect &rect);
-static void drawLine_midpoint_dashed_i(int x1, int y1, int x2, int y2,
- QPen *pen, ProcessSpans span_func, QSpanData *data,
- LineDrawMode style, const QIntRect &devRect,
- int *patternOffset);
-// static void drawLine_midpoint_f(qreal x1, qreal y1, qreal x2, qreal y2,
-// ProcessSpans span_func, QSpanData *data,
-// LineDrawMode style, const QRect &devRect);
-
static void drawEllipse_midpoint_i(const QRect &rect, const QRect &clip,
ProcessSpans pen_func, ProcessSpans brush_func,
QSpanData *pen_data, QSpanData *brush_data);
@@ -789,14 +783,12 @@ void QRasterPaintEngine::updatePen(const QPen &pen)
s->stroker = 0;
}
+ ensureState(); // needed because of tx_noshear...
s->flags.fast_pen = pen_style > Qt::NoPen
- && s->penData.blend
- && !s->flags.antialiased
- && (penWidth == 0 || (penWidth <= 1
- && (s->matrix.type() <= QTransform::TxTranslate
- || pen.isCosmetic())));
+ && s->penData.blend
+ && ((pen.isCosmetic() && penWidth <= 1)
+ || (s->flags.tx_noshear && penWidth * s->txscale <= 1));
- ensureState(); // needed because of tx_noshear...
s->flags.non_complex_pen = qpen_capStyle(s->lastPen) <= Qt::SquareCap && s->flags.tx_noshear;
s->strokeFlags = 0;
@@ -1513,6 +1505,7 @@ void QRasterPaintEngine::drawRects(const QRect *rects, int rectCount)
qDebug(" - QRasterPaintEngine::drawRect(), rectCount=%d", rectCount);
#endif
Q_D(QRasterPaintEngine);
+ ensureState();
QRasterPaintEngineState *s = state();
// Fill
@@ -1541,32 +1534,14 @@ void QRasterPaintEngine::drawRects(const QRect *rects, int rectCount)
ensurePen();
if (s->penData.blend) {
- if (s->flags.fast_pen && s->lastPen.brush().isOpaque()) {
- const QRect *r = rects;
- const QRect *lastRect = rects + rectCount;
- while (r < lastRect) {
- int left = r->x();
- int right = r->x() + r->width();
- int top = r->y();
- int bottom = r->y() + r->height();
-
-#ifdef Q_WS_MAC
- int pts[] = { top, left,
- top, right,
- bottom, right,
- bottom, left };
-#else
- int pts[] = { left, top,
- right, top,
- right, bottom,
- left, bottom };
-#endif
-
- strokePolygonCosmetic((QPoint *) pts, 4, WindingMode);
- ++r;
+ QRectVectorPath path;
+ if (s->flags.fast_pen) {
+ QCosmeticStroker stroker(s, d->deviceRect);
+ for (int i = 0; i < rectCount; ++i) {
+ path.set(rects[i]);
+ stroker.drawPath(path);
}
} else {
- QRectVectorPath path;
for (int i = 0; i < rectCount; ++i) {
path.set(rects[i]);
stroke(path, s->pen);
@@ -1581,13 +1556,13 @@ void QRasterPaintEngine::drawRects(const QRect *rects, int rectCount)
void QRasterPaintEngine::drawRects(const QRectF *rects, int rectCount)
{
#ifdef QT_DEBUG_DRAW
- qDebug(" - QRasterPaintEngine::drawRect(), rectCount=%d", rectCount);
+ qDebug(" - QRasterPaintEngine::drawRect(QRectF*), rectCount=%d", rectCount);
#endif
#ifdef QT_FAST_SPANS
Q_D(QRasterPaintEngine);
+ ensureState();
QRasterPaintEngineState *s = state();
- ensureState();
if (s->flags.tx_noshear) {
ensureBrush();
@@ -1605,59 +1580,17 @@ void QRasterPaintEngine::drawRects(const QRectF *rects, int rectCount)
ensurePen();
if (s->penData.blend) {
- qreal width = s->pen.isCosmetic()
- ? (s->lastPen.widthF() == 0 ? 1 : s->lastPen.widthF())
- : s->lastPen.widthF() * s->txscale;
-
- if (s->flags.fast_pen && s->lastPen.brush().isOpaque()) {
- for (int i = 0; i < rectCount; ++i) {
- const QRectF &r = rects[i];
- qreal left = r.x();
- qreal right = r.x() + r.width();
- qreal top = r.y();
- qreal bottom = r.y() + r.height();
- qreal pts[] = { left, top,
- right, top,
- right, bottom,
- left, bottom };
- strokePolygonCosmetic((QPointF *) pts, 4, WindingMode);
- }
- } else if (width <= 1 && qpen_style(s->lastPen) == Qt::SolidLine) {
- d->initializeRasterizer(&s->penData);
-
+ QRectVectorPath path;
+ if (s->flags.fast_pen) {
+ QCosmeticStroker stroker(s, d->deviceRect);
for (int i = 0; i < rectCount; ++i) {
- const QRectF &rect = rects[i].normalized();
- if (rect.isEmpty()) {
- qreal pts[] = { rect.left(), rect.top(), rect.right(), rect.bottom() };
- QVectorPath vp(pts, 2, 0, QVectorPath::LinesHint);
- QPaintEngineEx::stroke(vp, s->lastPen);
- } else {
- const QPointF tl = s->matrix.map(rect.topLeft());
- const QPointF tr = s->matrix.map(rect.topRight());
- const QPointF bl = s->matrix.map(rect.bottomLeft());
- const QPointF br = s->matrix.map(rect.bottomRight());
- const qreal w = width / (rect.width() * s->txscale);
- const qreal h = width / (rect.height() * s->txscale);
- d->rasterizer->rasterizeLine(tl, tr, w); // top
- d->rasterizer->rasterizeLine(bl, br, w); // bottom
- d->rasterizer->rasterizeLine(bl, tl, h); // left
- d->rasterizer->rasterizeLine(br, tr, h); // right
- }
+ path.set(rects[i]);
+ stroker.drawPath(path);
}
} else {
for (int i = 0; i < rectCount; ++i) {
- const QRectF &r = rects[i];
- qreal left = r.x();
- qreal right = r.x() + r.width();
- qreal top = r.y();
- qreal bottom = r.y() + r.height();
- qreal pts[] = { left, top,
- right, top,
- right, bottom,
- left, bottom,
- left, top };
- QVectorPath vp(pts, 5, 0, QVectorPath::RectangleHint);
- QPaintEngineEx::stroke(vp, s->lastPen);
+ path.set(rects[i]);
+ QPaintEngineEx::stroke(path, s->lastPen);
}
}
}
@@ -1674,36 +1607,16 @@ void QRasterPaintEngine::drawRects(const QRectF *rects, int rectCount)
*/
void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
{
+ Q_D(QRasterPaintEngine);
QRasterPaintEngineState *s = state();
+
ensurePen(pen);
if (!s->penData.blend)
return;
- if (s->flags.fast_pen && !path.isCurved()
- && s->lastPen.brush().isOpaque()) {
- int count = path.elementCount();
- QPointF *points = (QPointF *) path.points();
- const QPainterPath::ElementType *types = path.elements();
- if (types) {
- int first = 0;
- int last;
- while (first < count) {
- while (first < count && types[first] != QPainterPath::MoveToElement) ++first;
- last = first + 1;
- while (last < count && types[last] == QPainterPath::LineToElement) ++last;
- strokePolygonCosmetic(points + first, last - first,
- path.hasImplicitClose() && last == count // only close last one..
- ? WindingMode
- : PolylineMode);
- first = last;
- }
- } else {
- strokePolygonCosmetic(points, count,
- path.hasImplicitClose()
- ? WindingMode
- : PolylineMode);
- }
-
+ if (s->flags.fast_pen) {
+ QCosmeticStroker stroker(s, d->deviceRect);
+ stroker.drawPath(path);
} else if (s->flags.non_complex_pen && path.shape() == QVectorPath::LinesHint) {
qreal width = s->lastPen.isCosmetic()
? (qpen_widthf(s->lastPen) == 0 ? 1 : qpen_widthf(s->lastPen))
@@ -1760,10 +1673,10 @@ void QRasterPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
static inline QRect toNormalizedFillRect(const QRectF &rect)
{
- int x1 = qRound(rect.x());
- int y1 = qRound(rect.y());
- int x2 = qRound(rect.right());
- int y2 = qRound(rect.bottom());
+ int x1 = qRound(rect.x() + aliasedCoordinateDelta);
+ int y1 = qRound(rect.y() + aliasedCoordinateDelta);
+ int x2 = qRound(rect.right() + aliasedCoordinateDelta);
+ int y2 = qRound(rect.bottom() + aliasedCoordinateDelta);
if (x2 < x1)
qSwap(x1, x2);
@@ -1818,26 +1731,6 @@ void QRasterPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
}
}
- if (path.shape() == QVectorPath::EllipseHint) {
- if (!s->flags.antialiased && s->matrix.type() <= QTransform::TxScale) {
- const qreal *p = path.points();
- QPointF tl = QPointF(p[0], p[1]) * s->matrix;
- QPointF br = QPointF(p[4], p[5]) * s->matrix;
- QRectF r = s->matrix.mapRect(QRectF(tl, br));
-
- ProcessSpans penBlend = d->getPenFunc(r, &s->penData);
- ProcessSpans brushBlend = d->getBrushFunc(r, &s->brushData);
- const QRect brect = QRect(int(r.x()), int(r.y()),
- int_dim(r.x(), r.width()),
- int_dim(r.y(), r.height()));
- if (brect == r) {
- drawEllipse_midpoint_i(brect, d->deviceRect, penBlend, brushBlend,
- &s->penData, &s->brushData);
- return;
- }
- }
- }
-
// ### Optimize for non transformed ellipses and rectangles...
QRectF cpRect = path.controlPointRect();
const QRect deviceRect = s->matrix.mapRect(cpRect).toRect();
@@ -2032,6 +1925,7 @@ void QRasterPaintEngine::fillPolygon(const QPointF *points, int pointCount, Poly
*/
void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
{
+ Q_D(QRasterPaintEngine);
QRasterPaintEngineState *s = state();
#ifdef QT_DEBUG_DRAW
@@ -2048,20 +1942,23 @@ void QRasterPaintEngine::drawPolygon(const QPointF *points, int pointCount, Poly
}
ensurePen();
- ensureBrush();
if (mode != PolylineMode) {
// Do the fill...
+ ensureBrush();
if (s->brushData.blend) {
+ d->outlineMapper->setCoordinateRounding(s->penData.blend && s->flags.fast_pen && s->lastPen.brush().isOpaque());
fillPolygon(points, pointCount, mode);
+ d->outlineMapper->setCoordinateRounding(false);
}
}
// Do the outline...
if (s->penData.blend) {
- if (s->flags.fast_pen && s->lastPen.brush().isOpaque())
- strokePolygonCosmetic(points, pointCount, mode);
- else {
- QVectorPath vp((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode));
+ QVectorPath vp((qreal *) points, pointCount, 0, QVectorPath::polygonFlags(mode));
+ if (s->flags.fast_pen) {
+ QCosmeticStroker stroker(s, d->deviceRect);
+ stroker.drawPath(vp);
+ } else {
QPaintEngineEx::stroke(vp, s->lastPen);
}
}
@@ -2090,13 +1987,7 @@ void QRasterPaintEngine::drawPolygon(const QPoint *points, int pointCount, Polyg
return;
}
- ensureState();
ensurePen();
- if (!(s->flags.int_xform && s->flags.fast_pen && (!s->penData.blend || s->pen.brush().isOpaque()))) {
- // this calls the float version
- QPaintEngineEx::drawPolygon(points, pointCount, mode);
- return;
- }
// Do the fill
if (mode != PolylineMode) {
@@ -2104,6 +1995,7 @@ void QRasterPaintEngine::drawPolygon(const QPoint *points, int pointCount, Polyg
if (s->brushData.blend) {
// Compose polygon fill..,
ensureOutlineMapper();
+ d->outlineMapper->setCoordinateRounding(s->penData.blend != 0);
d->outlineMapper->beginOutline(mode == WindingMode ? Qt::WindingFill : Qt::OddEvenFill);
d->outlineMapper->moveTo(*points);
const QPoint *p = points;
@@ -2117,235 +2009,30 @@ void QRasterPaintEngine::drawPolygon(const QPoint *points, int pointCount, Polyg
ProcessSpans brushBlend = d->getBrushFunc(d->outlineMapper->controlPointRect,
&s->brushData);
d->rasterize(d->outlineMapper->outline(), brushBlend, &s->brushData, d->rasterBuffer.data());
+ d->outlineMapper->setCoordinateRounding(false);
}
}
// Do the outline...
if (s->penData.blend) {
- if (s->flags.fast_pen && s->lastPen.brush().isOpaque())
- strokePolygonCosmetic(points, pointCount, mode);
- else {
- int count = pointCount * 2;
- QVarLengthArray<qreal> fpoints(count);
-#ifdef Q_WS_MAC
- for (int i=0; i<count; i+=2) {
- fpoints[i] = ((int *) points)[i+1];
- fpoints[i+1] = ((int *) points)[i];
- }
-#else
- for (int i=0; i<count; ++i)
- fpoints[i] = ((int *) points)[i];
-#endif
- QVectorPath vp((qreal *) fpoints.data(), pointCount, 0, QVectorPath::polygonFlags(mode));
- QPaintEngineEx::stroke(vp, s->lastPen);
+ int count = pointCount * 2;
+ QVarLengthArray<qreal> fpoints(count);
+ #ifdef Q_WS_MAC
+ for (int i=0; i<count; i+=2) {
+ fpoints[i] = ((int *) points)[i+1];
+ fpoints[i+1] = ((int *) points)[i];
}
- }
-}
-
-/*!
- \internal
-*/
-void QRasterPaintEngine::strokePolygonCosmetic(const QPointF *points, int pointCount, PolygonDrawMode mode)
-{
- Q_D(QRasterPaintEngine);
- QRasterPaintEngineState *s = state();
-
- Q_ASSERT(s->penData.blend);
- Q_ASSERT(s->flags.fast_pen);
-
- bool needs_closing = mode != PolylineMode && points[0] != points[pointCount-1];
-
- // Use fast path for 0 width / trivial pens.
- QIntRect devRect;
- devRect.set(d->deviceRect);
-
- LineDrawMode mode_for_last = (s->lastPen.capStyle() != Qt::FlatCap
- ? LineDrawIncludeLastPixel
- : LineDrawNormal);
- int dashOffset = int(s->lastPen.dashOffset());
-
- // Draw all the line segments.
- for (int i=1; i<pointCount; ++i) {
-
- QPointF lp1 = points[i-1] * s->matrix;
- QPointF lp2 = points[i] * s->matrix;
-
- const QRectF brect(lp1, lp2);
- ProcessSpans penBlend = d->getPenFunc(brect, &s->penData);
- if (qpen_style(s->lastPen) == Qt::SolidLine) {
- drawLine_midpoint_i(qFloor(lp1.x()), qFloor(lp1.y()),
- qFloor(lp2.x()), qFloor(lp2.y()),
- penBlend, &s->penData,
- i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel,
- devRect);
+ #else
+ for (int i=0; i<count; ++i)
+ fpoints[i] = ((int *) points)[i];
+ #endif
+ QVectorPath vp((qreal *) fpoints.data(), pointCount, 0, QVectorPath::polygonFlags(mode));
+
+ if (s->flags.fast_pen) {
+ QCosmeticStroker stroker(s, d->deviceRect);
+ stroker.drawPath(vp);
} else {
- drawLine_midpoint_dashed_i(qFloor(lp1.x()), qFloor(lp1.y()),
- qFloor(lp2.x()), qFloor(lp2.y()),
- &s->lastPen,
- penBlend, &s->penData,
- i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel,
- devRect, &dashOffset);
- }
- }
-
- // Polygons are implicitly closed.
- if (needs_closing) {
- QPointF lp1 = points[pointCount-1] * s->matrix;
- QPointF lp2 = points[0] * s->matrix;
-
- const QRectF brect(lp1, lp2);
- ProcessSpans penBlend = d->getPenFunc(brect, &s->penData);
- if (qpen_style(s->lastPen) == Qt::SolidLine) {
- drawLine_midpoint_i(qFloor(lp1.x()), qFloor(lp1.y()),
- qFloor(lp2.x()), qFloor(lp2.y()),
- penBlend, &s->penData,
- LineDrawIncludeLastPixel,
- devRect);
- } else {
- drawLine_midpoint_dashed_i(qFloor(lp1.x()), qFloor(lp1.y()),
- qFloor(lp2.x()), qFloor(lp2.y()),
- &s->lastPen,
- penBlend, &s->penData,
- LineDrawIncludeLastPixel,
- devRect, &dashOffset);
- }
- }
-
-}
-
-/*!
- \internal
-*/
-void QRasterPaintEngine::strokePolygonCosmetic(const QPoint *points, int pointCount, PolygonDrawMode mode)
-{
- Q_D(QRasterPaintEngine);
- QRasterPaintEngineState *s = state();
-
- // We assert here because this function is called from drawRects
- // and drawPolygon and they already do ensurePen(), so we skip that
- // here to avoid duplicate checks..
- Q_ASSERT(s->penData.blend);
-
- bool needs_closing = mode != PolylineMode && points[0] != points[pointCount-1];
-
- QIntRect devRect;
- devRect.set(d->deviceRect);
-
- LineDrawMode mode_for_last = (s->lastPen.capStyle() != Qt::FlatCap
- ? LineDrawIncludeLastPixel
- : LineDrawNormal);
-
- int m11 = int(s->matrix.m11());
- int m22 = int(s->matrix.m22());
- int dx = int(s->matrix.dx());
- int dy = int(s->matrix.dy());
- int m13 = int(s->matrix.m13());
- int m23 = int(s->matrix.m23());
- bool affine = !m13 && !m23;
-
- int dashOffset = int(s->lastPen.dashOffset());
-
- if (affine) {
- // Draw all the line segments.
- for (int i=1; i<pointCount; ++i) {
- const QPoint lp1 = points[i-1] * s->matrix;
- const QPoint lp2 = points[i] * s->matrix;
- const QRect brect(lp1, lp2);
- ProcessSpans penBlend = d->getPenFunc(brect, &s->penData);
-
- if (qpen_style(s->lastPen) == Qt::SolidLine)
- drawLine_midpoint_i(lp1.x(), lp1.y(),
- lp2.x(), lp2.y(),
- penBlend, &s->penData,
- i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel,
- devRect);
- else
- drawLine_midpoint_dashed_i(lp1.x(), lp1.y(),
- lp2.x(), lp2.y(),
- &s->lastPen,
- penBlend, &s->penData,
- i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel,
- devRect, &dashOffset);
-
- }
-
- // Polygons are implicitly closed.
- if (needs_closing) {
- const QPoint lp1 = points[pointCount - 1] * s->matrix;
- const QPoint lp2 = points[0] * s->matrix;
- const QRect brect(lp1, lp2);
- ProcessSpans penBlend = d->getPenFunc(brect, &s->penData);
-
- if (qpen_style(s->lastPen) == Qt::SolidLine)
- drawLine_midpoint_i(lp1.x(), lp1.y(),
- lp2.x(), lp2.y(),
- penBlend, &s->penData, LineDrawIncludeLastPixel,
- devRect);
- else
- drawLine_midpoint_dashed_i(lp1.x(), lp1.y(),
- lp2.x(), lp2.y(),
- &s->lastPen,
- penBlend, &s->penData, LineDrawIncludeLastPixel,
- devRect, &dashOffset);
- }
- } else {
- // Draw all the line segments.
- for (int i=1; i<pointCount; ++i) {
- int x1 = points[i-1].x() * m11 + dx;
- int y1 = points[i-1].y() * m22 + dy;
- qreal w = m13*points[i-1].x() + m23*points[i-1].y() + 1.;
- w = 1/w;
- x1 = int(x1*w);
- y1 = int(y1*w);
- int x2 = points[i].x() * m11 + dx;
- int y2 = points[i].y() * m22 + dy;
- w = m13*points[i].x() + m23*points[i].y() + 1.;
- w = 1/w;
- x2 = int(x2*w);
- y2 = int(y2*w);
-
- const QRect brect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
- ProcessSpans penBlend = d->getPenFunc(brect, &s->penData);
- if (qpen_style(s->lastPen) == Qt::SolidLine)
- drawLine_midpoint_i(x1, y1, x2, y2,
- penBlend, &s->penData,
- i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel,
- devRect);
- else
- drawLine_midpoint_dashed_i(x1, y1, x2, y2,
- &s->lastPen,
- penBlend, &s->penData,
- i == pointCount - 1 ? mode_for_last : LineDrawIncludeLastPixel,
- devRect, &dashOffset);
-
- }
-
- int x1 = points[pointCount-1].x() * m11 + dx;
- int y1 = points[pointCount-1].y() * m22 + dy;
- qreal w = m13*points[pointCount-1].x() + m23*points[pointCount-1].y() + 1.;
- w = 1/w;
- x1 = int(x1*w);
- y1 = int(y1*w);
- int x2 = points[0].x() * m11 + dx;
- int y2 = points[0].y() * m22 + dy;
- w = m13*points[0].x() + m23*points[0].y() + 1.;
- w = 1/w;
- x2 = int(x2 * w);
- y2 = int(y2 * w);
- // Polygons are implicitly closed.
-
- if (needs_closing) {
- const QRect brect(x1, y1, x2 - x1 + 1, y2 - y1 + 1);
- ProcessSpans penBlend = d->getPenFunc(brect, &s->penData);
- if (qpen_style(s->lastPen) == Qt::SolidLine)
- drawLine_midpoint_i(x1, y1, x2, y2,
- penBlend, &s->penData, LineDrawIncludeLastPixel,
- devRect);
- else
- drawLine_midpoint_dashed_i(x1, y1, x2, y2,
- &s->lastPen,
- penBlend, &s->penData, LineDrawIncludeLastPixel,
- devRect, &dashOffset);
+ QPaintEngineEx::stroke(vp, s->lastPen);
}
}
}
@@ -2579,7 +2266,10 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
int sr_b = qCeil(sr.bottom()) - 1;
if (s->matrix.type() <= QTransform::TxScale && !s->flags.antialiased && sr_l == sr_r && sr_t == sr_b) {
+ // as fillRect will apply the aliased coordinate delta we need to
+ // subtract it here as we don't use it for image drawing
QTransform old = s->matrix;
+ s->matrix = s->matrix * QTransform::fromTranslate(-aliasedCoordinateDelta, -aliasedCoordinateDelta);
// Do whatever fillRect() does, but without premultiplying the color if it's already premultiplied.
QRgb color = img.pixel(sr_l, sr_t);
@@ -2723,9 +2413,11 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
d->initializeRasterizer(&d->image_filler_xform);
d->rasterizer->setAntialiased(s->flags.antialiased);
+ const QPointF offs = s->flags.antialiased ? QPointF() : QPointF(aliasedCoordinateDelta, aliasedCoordinateDelta);
+
const QRectF &rect = r.normalized();
- const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f);
- const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f);
+ const QPointF a = s->matrix.map((rect.topLeft() + rect.bottomLeft()) * 0.5f) - offs;
+ const QPointF b = s->matrix.map((rect.topRight() + rect.bottomRight()) * 0.5f) - offs;
if (s->flags.tx_noshear)
d->rasterizer->rasterizeLine(a, b, rect.height() / rect.width());
@@ -2734,12 +2426,13 @@ void QRasterPaintEngine::drawImage(const QRectF &r, const QImage &img, const QRe
return;
}
#endif
+ const qreal offs = s->flags.antialiased ? qreal(0) : aliasedCoordinateDelta;
QPainterPath path;
path.addRect(r);
QTransform m = s->matrix;
s->matrix = QTransform(m.m11(), m.m12(), m.m13(),
m.m21(), m.m22(), m.m23(),
- m.m31(), m.m32(), m.m33());
+ m.m31() - offs, m.m32() - offs, m.m33());
fillPath(path, &d->image_filler_xform);
s->matrix = m;
} else {
@@ -3191,6 +2884,7 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
rightShift = 3; // divide by 8
int margin = cache->glyphMargin();
+ const QFixed offs = QFixed::fromReal(aliasedCoordinateDelta);
const uchar *bits = image.bits();
for (int i=0; i<numGlyphs; ++i) {
@@ -3201,7 +2895,7 @@ bool QRasterPaintEngine::drawCachedGlyphs(int numGlyphs, const glyph_t *glyphs,
continue;
int x = qFloor(positions[i].x) + c.baseLineX - margin;
- int y = qFloor(positions[i].y) - c.baseLineY - margin;
+ int y = qFloor(positions[i].y + offs) - c.baseLineY - margin;
// printf("drawing [%d %d %d %d] baseline [%d %d], glyph: %d, to: %d %d, pos: %d %d\n",
// c.x, c.y,
@@ -3239,13 +2933,15 @@ void QRasterPaintEngine::drawGlyphsS60(const QPointF &p, const QTextItemInt &ti)
fe->setFontScale(matrix.m11());
ti.fontEngine->getGlyphPositions(ti.glyphs, matrix, ti.flags, glyphs, positions);
+ const QFixed aliasDelta = QFixed::fromReal(aliasedCoordinateDelta);
+
for (int i=0; i<glyphs.size(); ++i) {
TOpenFontCharMetrics tmetrics;
const TUint8 *glyphBitmapBytes;
TSize glyphBitmapSize;
fe->getCharacterData(glyphs[i], tmetrics, glyphBitmapBytes, glyphBitmapSize);
- const int x = qFloor(positions[i].x + tmetrics.HorizBearingX());
- const int y = qFloor(positions[i].y - tmetrics.HorizBearingY());
+ const int x = qFloor(positions[i].x + tmetrics.HorizBearingX() + aliasDelta);
+ const int y = qFloor(positions[i].y - tmetrics.HorizBearingY() + aliasDelta);
alphaPenBlt(glyphBitmapBytes, glyphBitmapSize.iWidth, 8, x, y, glyphBitmapSize.iWidth, glyphBitmapSize.iHeight);
}
@@ -3346,19 +3042,6 @@ QRasterPaintEnginePrivate::getBrushFunc(const QRectF &rect,
}
inline ProcessSpans
-QRasterPaintEnginePrivate::getPenFunc(const QRect &rect,
- const QSpanData *data) const
-{
- Q_Q(const QRasterPaintEngine);
- const QRasterPaintEngineState *s = q->state();
-
- if (!s->flags.fast_pen && s->matrix.type() > QTransform::TxTranslate)
- return data->blend;
- const int penWidth = s->flags.fast_pen ? 1 : qCeil(s->pen.widthF());
- return isUnclipped(rect, penWidth) ? data->unclipped_blend : data->blend;
-}
-
-inline ProcessSpans
QRasterPaintEnginePrivate::getPenFunc(const QRectF &rect,
const QSpanData *data) const
{
@@ -3379,8 +3062,13 @@ void QRasterPaintEngine::drawStaticTextItem(QStaticTextItem *textItem)
ensurePen();
ensureState();
- drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions,
- textItem->fontEngine());
+ QFontEngine *fontEngine = textItem->fontEngine();
+ if (!supportsTransformations(fontEngine)) {
+ drawCachedGlyphs(textItem->numGlyphs, textItem->glyphs, textItem->glyphPositions,
+ fontEngine);
+ } else {
+ QPaintEngineEx::drawStaticTextItem(textItem);
+ }
}
/*!
@@ -3403,36 +3091,7 @@ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte
#if defined (Q_WS_WIN) || defined(Q_WS_MAC)
- bool drawCached = true;
-
- if (s->matrix.type() >= QTransform::TxProject)
- drawCached = false;
-
- // don't try to cache huge fonts
- const qreal pixelSize = ti.fontEngine->fontDef.pixelSize;
- if (pixelSize * pixelSize * qAbs(s->matrix.determinant()) >= 64 * 64)
- drawCached = false;
-
- // ### Remove the TestFontEngine and Box engine crap, in these
- // ### cases we should delegate painting to the font engine
- // ### directly...
-
-#if defined(Q_WS_WIN) && !defined(Q_WS_WINCE)
- QFontEngine::Type fontEngineType = ti.fontEngine->type();
- // qDebug() << "type" << fontEngineType << s->matrix.type();
- if ((fontEngineType == QFontEngine::Win && !((QFontEngineWin *) ti.fontEngine)->ttf && s->matrix.type() > QTransform::TxTranslate)
- || (s->matrix.type() <= QTransform::TxTranslate
- && (fontEngineType == QFontEngine::TestFontEngine
- || fontEngineType == QFontEngine::Box))) {
- drawCached = false;
- }
-#else
- if (s->matrix.type() > QTransform::TxTranslate)
- drawCached = false;
-#endif
- if (drawCached) {
- QRasterPaintEngineState *s = state();
-
+ if (!supportsTransformations(ti.fontEngine)) {
QVarLengthArray<QFixedPoint> positions;
QVarLengthArray<glyph_t> glyphs;
@@ -3467,7 +3126,7 @@ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte
|| (fontEngine->type() == QFontEngine::Proxy
&& !(static_cast<QProxyFontEngine *>(fontEngine)->drawAsOutline()))
)) {
- fontEngine->draw(this, qFloor(p.x()), qFloor(p.y()), ti);
+ fontEngine->draw(this, qFloor(p.x() + aliasedCoordinateDelta), qFloor(p.y() + aliasedCoordinateDelta), ti);
return;
}
#endif // Q_WS_QWS
@@ -3490,6 +3149,7 @@ void QRasterPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textIte
for(int i = 0; i < glyphs.size(); i++) {
QImage img = fontEngine->alphaMapForGlyph(glyphs[i]);
glyph_metrics_t metrics = fontEngine->boundingBox(glyphs[i]);
+ // ### hm, perhaps an QFixed offs = QFixed::fromReal(aliasedCoordinateDelta) is needed here?
alphaPenBlt(img.bits(), img.bytesPerLine(), img.depth(),
qRound(positions[i].x + metrics.x),
qRound(positions[i].y + metrics.y),
@@ -3544,48 +3204,16 @@ void QRasterPaintEngine::drawPoints(const QPointF *points, int pointCount)
QRasterPaintEngineState *s = state();
ensurePen();
- qreal pw = s->lastPen.widthF();
- if (!s->flags.fast_pen && (s->matrix.type() > QTransform::TxTranslate || pw > 1)) {
- QPaintEngineEx::drawPoints(points, pointCount);
-
- } else {
- if (!s->penData.blend)
- return;
-
- QVarLengthArray<QT_FT_Span, 4096> array(pointCount);
- QT_FT_Span span = { 0, 1, 0, 255 };
- const QPointF *end = points + pointCount;
- qreal trans_x, trans_y;
- int x, y;
- int left = d->deviceRect.x();
- int right = left + d->deviceRect.width();
- int top = d->deviceRect.y();
- int bottom = top + d->deviceRect.height();
- int count = 0;
- while (points < end) {
- s->matrix.map(points->x(), points->y(), &trans_x, &trans_y);
- x = qFloor(trans_x);
- y = qFloor(trans_y);
- if (x >= left && x < right && y >= top && y < bottom) {
- if (count > 0) {
- const QT_FT_Span &last = array[count - 1];
- // spans must be sorted on y (primary) and x (secondary)
- if (y < last.y || (y == last.y && x < last.x)) {
- s->penData.blend(count, array.constData(), &s->penData);
- count = 0;
- }
- }
-
- span.x = x;
- span.y = y;
- array[count++] = span;
- }
- ++points;
- }
+ if (!s->penData.blend)
+ return;
- if (count > 0)
- s->penData.blend(count, array.constData(), &s->penData);
+ if (!s->flags.fast_pen) {
+ QPaintEngineEx::drawPoints(points, pointCount);
+ return;
}
+
+ QCosmeticStroker stroker(s, d->deviceRect);
+ stroker.drawPoints(points, pointCount);
}
@@ -3595,48 +3223,16 @@ void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
QRasterPaintEngineState *s = state();
ensurePen();
- double pw = s->lastPen.widthF();
- if (!s->flags.fast_pen && (s->matrix.type() > QTransform::TxTranslate || pw > 1)) {
- QPaintEngineEx::drawPoints(points, pointCount);
-
- } else {
- if (!s->penData.blend)
- return;
-
- QVarLengthArray<QT_FT_Span, 4096> array(pointCount);
- QT_FT_Span span = { 0, 1, 0, 255 };
- const QPoint *end = points + pointCount;
- qreal trans_x, trans_y;
- int x, y;
- int left = d->deviceRect.x();
- int right = left + d->deviceRect.width();
- int top = d->deviceRect.y();
- int bottom = top + d->deviceRect.height();
- int count = 0;
- while (points < end) {
- s->matrix.map(points->x(), points->y(), &trans_x, &trans_y);
- x = qFloor(trans_x);
- y = qFloor(trans_y);
- if (x >= left && x < right && y >= top && y < bottom) {
- if (count > 0) {
- const QT_FT_Span &last = array[count - 1];
- // spans must be sorted on y (primary) and x (secondary)
- if (y < last.y || (y == last.y && x < last.x)) {
- s->penData.blend(count, array.constData(), &s->penData);
- count = 0;
- }
- }
-
- span.x = x;
- span.y = y;
- array[count++] = span;
- }
- ++points;
- }
+ if (!s->penData.blend)
+ return;
- if (count > 0)
- s->penData.blend(count, array.constData(), &s->penData);
+ if (!s->flags.fast_pen) {
+ QPaintEngineEx::drawPoints(points, pointCount);
+ return;
}
+
+ QCosmeticStroker stroker(s, d->deviceRect);
+ stroker.drawPoints(points, pointCount);
}
/*!
@@ -3645,59 +3241,22 @@ void QRasterPaintEngine::drawPoints(const QPoint *points, int pointCount)
void QRasterPaintEngine::drawLines(const QLine *lines, int lineCount)
{
#ifdef QT_DEBUG_DRAW
- qDebug() << " - QRasterPaintEngine::drawLine()";
+ qDebug() << " - QRasterPaintEngine::drawLines(QLine*)" << lineCount;
#endif
Q_D(QRasterPaintEngine);
QRasterPaintEngineState *s = state();
ensurePen();
+ if (!s->penData.blend)
+ return;
+
if (s->flags.fast_pen) {
- QIntRect bounds; bounds.set(d->deviceRect);
- LineDrawMode mode = s->lastPen.capStyle() == Qt::FlatCap
- ? LineDrawNormal
- : LineDrawIncludeLastPixel;
-
- int m11 = int(s->matrix.m11());
- int m22 = int(s->matrix.m22());
- int dx = qFloor(s->matrix.dx());
- int dy = qFloor(s->matrix.dy());
+ QCosmeticStroker stroker(s, d->deviceRect);
for (int i=0; i<lineCount; ++i) {
- int dashOffset = int(s->lastPen.dashOffset());
- if (s->flags.int_xform) {
- const QLine &l = lines[i];
- int x1 = l.x1() * m11 + dx;
- int y1 = l.y1() * m22 + dy;
- int x2 = l.x2() * m11 + dx;
- int y2 = l.y2() * m22 + dy;
-
- const QRect brect(QPoint(x1, y1), QPoint(x2, y2));
- ProcessSpans penBlend = d->getPenFunc(brect, &s->penData);
- if (qpen_style(s->lastPen) == Qt::SolidLine)
- drawLine_midpoint_i(x1, y1, x2, y2,
- penBlend, &s->penData, mode, bounds);
- else
- drawLine_midpoint_dashed_i(x1, y1, x2, y2,
- &s->lastPen, penBlend,
- &s->penData, mode, bounds,
- &dashOffset);
- } else {
- QLineF line = lines[i] * s->matrix;
- const QRectF brect(QPointF(line.x1(), line.y1()),
- QPointF(line.x2(), line.y2()));
- ProcessSpans penBlend = d->getPenFunc(brect, &s->penData);
- if (qpen_style(s->lastPen) == Qt::SolidLine)
- drawLine_midpoint_i(int(line.x1()), int(line.y1()),
- int(line.x2()), int(line.y2()),
- penBlend, &s->penData, mode, bounds);
- else
- drawLine_midpoint_dashed_i(int(line.x1()), int(line.y1()),
- int(line.x2()), int(line.y2()),
- &s->lastPen, penBlend,
- &s->penData, mode, bounds,
- &dashOffset);
- }
+ const QLine &l = lines[i];
+ stroker.drawLine(l.p1(), l.p2());
}
- } else if (s->penData.blend) {
+ } else {
QPaintEngineEx::drawLines(lines, lineCount);
}
}
@@ -3754,7 +3313,7 @@ void QRasterPaintEnginePrivate::rasterizeLine_dashed(QLineF line,
void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount)
{
#ifdef QT_DEBUG_DRAW
- qDebug() << " - QRasterPaintEngine::drawLine()";
+ qDebug() << " - QRasterPaintEngine::drawLines(QLineF *)" << lineCount;
#endif
Q_D(QRasterPaintEngine);
QRasterPaintEngineState *s = state();
@@ -3763,28 +3322,10 @@ void QRasterPaintEngine::drawLines(const QLineF *lines, int lineCount)
if (!s->penData.blend)
return;
if (s->flags.fast_pen) {
- QIntRect bounds;
- bounds.set(d->deviceRect);
- LineDrawMode mode = s->lastPen.capStyle() == Qt::FlatCap
- ? LineDrawNormal
- : LineDrawIncludeLastPixel;
-
+ QCosmeticStroker stroker(s, d->deviceRect);
for (int i=0; i<lineCount; ++i) {
- int dashOffset = int(s->lastPen.dashOffset());
- QLineF line = lines[i] * s->matrix;
- const QRectF brect(QPointF(line.x1(), line.y1()),
- QPointF(line.x2(), line.y2()));
- ProcessSpans penBlend = d->getPenFunc(brect, &s->penData);
- if (qpen_style(s->lastPen) == Qt::SolidLine)
- drawLine_midpoint_i(int(line.x1()), int(line.y1()),
- int(line.x2()), int(line.y2()),
- penBlend, &s->penData, mode, bounds);
- else
- drawLine_midpoint_dashed_i(int(line.x1()), int(line.y1()),
- int(line.x2()), int(line.y2()),
- &s->lastPen,
- penBlend, &s->penData, mode,
- bounds, &dashOffset);
+ QLineF line = lines[i];
+ stroker.drawLine(line.p1(), line.p2());
}
} else {
QPaintEngineEx::drawLines(lines, lineCount);
@@ -3802,7 +3343,8 @@ void QRasterPaintEngine::drawEllipse(const QRectF &rect)
ensurePen();
if (((qpen_style(s->lastPen) == Qt::SolidLine && s->flags.fast_pen)
- || (qpen_style(s->lastPen) == Qt::NoPen && !s->flags.antialiased))
+ || (qpen_style(s->lastPen) == Qt::NoPen))
+ && !s->flags.antialiased
&& qMax(rect.width(), rect.height()) < QT_RASTER_COORD_LIMIT
&& !rect.isEmpty()
&& s->matrix.type() <= QTransform::TxScale) // no shear
@@ -3870,6 +3412,37 @@ void QRasterPaintEngine::releaseDC(HDC) const
#endif
+bool QRasterPaintEngine::supportsTransformations(const QFontEngine *fontEngine) const
+{
+ const QTransform &m = state()->matrix;
+#if defined(Q_WS_WIN) && !defined(Q_WS_WINCE)
+ QFontEngine::Type fontEngineType = fontEngine->type();
+ if ((fontEngineType == QFontEngine::Win && !((QFontEngineWin *) fontEngine)->ttf && m.type() > QTransform::TxTranslate)
+ || (m.type() <= QTransform::TxTranslate
+ && (fontEngineType == QFontEngine::TestFontEngine
+ || fontEngineType == QFontEngine::Box))) {
+ return true;
+ }
+#endif
+ return supportsTransformations(fontEngine->fontDef.pixelSize, m);
+}
+
+bool QRasterPaintEngine::supportsTransformations(qreal pixelSize, const QTransform &m) const
+{
+#if defined(Q_WS_MAC)
+ // Mac font engines don't support scaling and rotation
+ if (m.type() > QTransform::TxTranslate)
+#else
+ if (m.type() >= QTransform::TxProject)
+#endif
+ return true;
+
+ if (pixelSize * pixelSize * qAbs(m.determinant()) >= 64 * 64)
+ return true;
+
+ return false;
+}
+
/*!
\internal
*/
@@ -4821,7 +4394,7 @@ static void qt_span_fill_clipped(int spanCount, const QSpan *spans, void *userDa
while (spans < end) {
QSpan *clipped = cspans;
spans = qt_intersect_spans(fillData->clip, &currentClip, spans, end, &clipped, NSPANS);
-// qDebug() << "processed " << processed << "clipped" << clipped-cspans
+// qDebug() << "processed " << spanCount - (end - spans) << "clipped" << clipped-cspans
// << "span:" << cspans->x << cspans->y << cspans->len << spans->coverage;
if (clipped - cspans)
@@ -5473,759 +5046,6 @@ void QSpanData::initTexture(const QImage *image, int alpha, QTextureData::Type _
adjustSpanMethods();
}
-#ifdef Q_WS_WIN
-
-
-#endif
-
-
-/*!
- \internal
-
- Draws a line using the floating point midpoint algorithm. The line
- \a line is already in device coords at this point.
-*/
-
-static void drawLine_midpoint_i(int x1, int y1, int x2, int y2, ProcessSpans span_func, QSpanData *data,
- LineDrawMode style, const QIntRect &devRect)
-{
-#ifdef QT_DEBUG_DRAW
- qDebug() << " - drawLine_midpoint_i" << QLine(QPoint(x1, y1), QPoint(x2, y2));
-#endif
-
- int x, y;
- int dx, dy, d, incrE, incrNE;
-
- dx = x2 - x1;
- dy = y2 - y1;
-
- const int NSPANS = 256;
- QT_FT_Span spans[NSPANS];
- int current = 0;
- bool ordered = true;
-
- if (dy == 0) {
- // specialcase horizontal lines
- if (y1 >= devRect.y1 && y1 < devRect.y2) {
- int start = qMax(devRect.x1, qMin(x1, x2));
- int stop = qMax(x1, x2) + 1;
- int stop_clipped = qMin(devRect.x2, stop);
- int len = stop_clipped - start;
- if (style == LineDrawNormal && stop == stop_clipped)
- len--;
- if (len > 0) {
- spans[0].x = ushort(start);
- spans[0].len = ushort(len);
- spans[0].y = y1;
- spans[0].coverage = 255;
- span_func(1, spans, data);
- }
- }
- return;
- } else if (dx == 0) {
- // specialcase vertical lines
- if (x1 >= devRect.x1 && x1 < devRect.x2) {
- int start = qMax(devRect.y1, qMin(y1, y2));
- int stop = qMax(y1, y2) + 1;
- int stop_clipped = qMin(devRect.y2, stop);
- int len = stop_clipped - start;
- if (style == LineDrawNormal && stop == stop_clipped)
- len--;
- // hw: create spans directly instead to possibly avoid clipping
- if (len > 0)
- fillRect_normalized(QRect(x1, start, 1, len).normalized(), data, 0);
- }
- return;
- }
-
-
- if (qAbs(dx) >= qAbs(dy)) { /* if x is the major axis: */
-
- if (x2 < x1) { /* if coordinates are out of order */
- qt_swap_int(x1, x2);
- dx = -dx;
-
- qt_swap_int(y1, y2);
- dy = -dy;
- }
-
- int x_lower_limit = - 128;
- if (x1 < x_lower_limit) {
- int cy = dy * (x_lower_limit - x1) / dx + y1;
- drawLine_midpoint_i(x_lower_limit, cy, x2, y2, span_func, data, style, devRect);
- return;
- }
-
- if (style == LineDrawNormal)
- --x2;
-
- // In the loops below we increment before call the span function so
- // we need to stop one pixel before
- x2 = qMin(x2, devRect.x2 - 1);
-
- // completely clipped, so abort
- if (x2 <= x1) {
- return;
- }
-
- int x = x1;
- int y = y1;
-
- if (y2 <= y1)
- ordered = false;
-
- {
- const int index = (ordered ? current : NSPANS - 1 - current);
- spans[index].coverage = 255;
- spans[index].x = x;
- spans[index].y = y;
-
- if (x >= devRect.x1 && y >= devRect.y1 && y < devRect.y2)
- spans[index].len = 1;
- else
- spans[index].len = 0;
- }
-
- if (y2 > y1) { // 315 -> 360 and 135 -> 180 (unit circle degrees)
- y2 = qMin(y2, devRect.y2 - 1);
-
- incrE = dy * 2;
- d = incrE - dx;
- incrNE = (dy - dx) * 2;
-
- if (y > y2)
- goto flush_and_return;
-
- while (x < x2) {
- ++x;
- if (d > 0) {
- if (spans[current].len > 0)
- ++current;
- if (current == NSPANS) {
- span_func(NSPANS, spans, data);
- current = 0;
- }
-
- ++y;
- d += incrNE;
- if (y > y2)
- goto flush_and_return;
-
- spans[current].len = 0;
- spans[current].coverage = 255;
- spans[current].x = x;
- spans[current].y = y;
- } else {
- d += incrE;
- if (x == devRect.x1)
- spans[current].x = devRect.x1;
- }
-
- if (x < devRect.x1 || y < devRect.y1)
- continue;
-
- Q_ASSERT(x<devRect.x2);
- Q_ASSERT(y<devRect.y2);
- Q_ASSERT(spans[current].y == y);
- spans[current].len++;
- }
- if (spans[current].len > 0) {
- ++current;
- }
- } else { // 0-45 and 180->225 (unit circle degrees)
-
- y1 = qMin(y1, devRect.y2 - 1);
-
- incrE = dy * 2;
- d = incrE + dx;
- incrNE = (dy + dx) * 2;
-
- if (y < devRect.y1)
- goto flush_and_return;
-
- while (x < x2) {
- ++x;
- if (d < 0) {
- if (spans[NSPANS - 1 - current].len > 0)
- ++current;
- if (current == NSPANS) {
- span_func(NSPANS, spans, data);
- current = 0;
- }
-
- --y;
- d += incrNE;
- if (y < devRect.y1)
- goto flush_and_return;
-
- const int index = NSPANS - 1 - current;
- spans[index].len = 0;
- spans[index].coverage = 255;
- spans[index].x = x;
- spans[index].y = y;
- } else {
- d += incrE;
- if (x == devRect.x1)
- spans[NSPANS - 1 - current].x = devRect.x1;
- }
-
- if (x < devRect.x1 || y > y1)
- continue;
-
- Q_ASSERT(x<devRect.x2 && y<devRect.y2);
- Q_ASSERT(spans[NSPANS - 1 - current].y == y);
- spans[NSPANS - 1 - current].len++;
- }
- if (spans[NSPANS - 1 - current].len > 0) {
- ++current;
- }
- }
-
- } else {
-
- // if y is the major axis:
-
- if (y2 < y1) { /* if coordinates are out of order */
- qt_swap_int(y1, y2);
- dy = -dy;
-
- qt_swap_int(x1, x2);
- dx = -dx;
- }
-
- int y_lower_limit = - 128;
- if (y1 < y_lower_limit) {
- int cx = dx * (y_lower_limit - y1) / dy + x1;
- drawLine_midpoint_i(cx, y_lower_limit, x2, y2, span_func, data, style, devRect);
- return;
- }
-
- if (style == LineDrawNormal)
- --y2;
-
- // In the loops below we increment before call the span function so
- // we need to stop one pixel before
- y2 = qMin(y2, devRect.y2 - 1);
-
- // completely clipped, so abort
- if (y2 <= y1) {
- return;
- }
-
- x = x1;
- y = y1;
-
- if (x>=devRect.x1 && y>=devRect.y1 && x < devRect.x2) {
- Q_ASSERT(x >= devRect.x1 && y >= devRect.y1 && x < devRect.x2 && y < devRect.y2);
- if (current == NSPANS) {
- span_func(NSPANS, spans, data);
- current = 0;
- }
- spans[current].len = 1;
- spans[current].coverage = 255;
- spans[current].x = x;
- spans[current].y = y;
- ++current;
- }
-
- if (x2 > x1) { // 90 -> 135 and 270 -> 315 (unit circle degrees)
- x2 = qMin(x2, devRect.x2 - 1);
- incrE = dx * 2;
- d = incrE - dy;
- incrNE = (dx - dy) * 2;
-
- if (x > x2)
- goto flush_and_return;
-
- while (y < y2) {
- if (d > 0) {
- ++x;
- d += incrNE;
- if (x > x2)
- goto flush_and_return;
- } else {
- d += incrE;
- }
- ++y;
- if (x < devRect.x1 || y < devRect.y1)
- continue;
- Q_ASSERT(x<devRect.x2 && y<devRect.y2);
- if (current == NSPANS) {
- span_func(NSPANS, spans, data);
- current = 0;
- }
- spans[current].len = 1;
- spans[current].coverage = 255;
- spans[current].x = x;
- spans[current].y = y;
- ++current;
- }
- } else { // 45 -> 90 and 225 -> 270 (unit circle degrees)
- x1 = qMin(x1, devRect.x2 - 1);
- incrE = dx * 2;
- d = incrE + dy;
- incrNE = (dx + dy) * 2;
-
- if (x < devRect.x1)
- goto flush_and_return;
-
- while (y < y2) {
- if (d < 0) {
- --x;
- d += incrNE;
- if (x < devRect.x1)
- goto flush_and_return;
- } else {
- d += incrE;
- }
- ++y;
- if (y < devRect.y1 || x > x1)
- continue;
- Q_ASSERT(x>=devRect.x1 && x<devRect.x2 && y>=devRect.y1 && y<devRect.y2);
- if (current == NSPANS) {
- span_func(NSPANS, spans, data);
- current = 0;
- }
- spans[current].len = 1;
- spans[current].coverage = 255;
- spans[current].x = x;
- spans[current].y = y;
- ++current;
- }
- }
- }
-flush_and_return:
- if (current > 0)
- span_func(current, ordered ? spans : spans + (NSPANS - current), data);
-}
-
-static void offset_pattern(int offset, bool *inDash, int *dashIndex, int *currentOffset, const QVarLengthArray<qreal> &pattern)
-{
- while (offset--) {
- if (--*currentOffset == 0) {
- *inDash = !*inDash;
- *dashIndex = ((*dashIndex + 1) % pattern.size());
- *currentOffset = int(pattern[*dashIndex]);
- }
- }
-}
-
-static void drawLine_midpoint_dashed_i(int x1, int y1, int x2, int y2,
- QPen *pen,
- ProcessSpans span_func, QSpanData *data,
- LineDrawMode style, const QIntRect &devRect,
- int *patternOffset)
-{
-#ifdef QT_DEBUG_DRAW
- qDebug() << " - drawLine_midpoint_dashed_i" << x1 << y1 << x2 << y2 << *patternOffset;
-#endif
-
- int x, y;
- int dx, dy, d, incrE, incrNE;
-
- dx = x2 - x1;
- dy = y2 - y1;
-
- Q_ASSERT(*patternOffset >= 0);
-
- const QVector<qreal> penPattern = pen->dashPattern();
- QVarLengthArray<qreal> pattern(penPattern.size());
-
- int patternLength = 0;
- for (int i = 0; i < penPattern.size(); ++i)
- patternLength += qMax<qreal>(1.0, (penPattern.at(i)));
-
- // pattern must be reversed if coordinates are out of order
- int reverseLength = -1;
- if (dy == 0 && x1 > x2)
- reverseLength = x1 - x2;
- else if (dx == 0 && y1 > y2)
- reverseLength = y1 - y2;
- else if (qAbs(dx) >= qAbs(dy) && x2 < x1) // x major axis
- reverseLength = qAbs(dx);
- else if (qAbs(dy) >= qAbs(dx) && y2 < y1) // y major axis
- reverseLength = qAbs(dy);
-
- const bool reversed = (reverseLength > -1);
- if (reversed) { // reverse pattern
- for (int i = 0; i < penPattern.size(); ++i)
- pattern[penPattern.size() - 1 - i] = qMax<qreal>(1.0, penPattern.at(i));
-
- *patternOffset = (patternLength - 1 - *patternOffset);
- *patternOffset += patternLength - (reverseLength % patternLength);
- *patternOffset = *patternOffset % patternLength;
- } else {
- for (int i = 0; i < penPattern.size(); ++i)
- pattern[i] = qMax<qreal>(1.0, penPattern.at(i));
- }
-
- int dashIndex = 0;
- bool inDash = !reversed;
- int currPattern = int(pattern[dashIndex]);
-
- // adjust pattern for offset
- offset_pattern(*patternOffset, &inDash, &dashIndex, &currPattern, pattern);
-
- const int NSPANS = 256;
- QT_FT_Span spans[NSPANS];
- int current = 0;
- bool ordered = true;
-
- if (dy == 0) {
- // specialcase horizontal lines
- if (y1 >= devRect.y1 && y1 < devRect.y2) {
- int start_unclipped = qMin(x1, x2);
- int start = qMax(devRect.x1, start_unclipped);
- int stop = qMax(x1, x2) + 1;
- int stop_clipped = qMin(devRect.x2, stop);
- int len = stop_clipped - start;
- if (style == LineDrawNormal && stop == stop_clipped)
- len--;
-
- // adjust pattern for starting offset
- offset_pattern(start - start_unclipped, &inDash, &dashIndex, &currPattern, pattern);
-
- if (len > 0) {
- int x = start;
- while (x < stop_clipped) {
- if (current == NSPANS) {
- span_func(NSPANS, spans, data);
- current = 0;
- }
- const int dash = qMin(currPattern, stop_clipped - x);
- if (inDash) {
- spans[current].x = ushort(x);
- spans[current].len = ushort(dash);
- spans[current].y = y1;
- spans[current].coverage = 255;
- ++current;
- }
- if (dash < currPattern) {
- currPattern -= dash;
- } else {
- dashIndex = (dashIndex + 1) % pattern.size();
- currPattern = int(pattern[dashIndex]);
- inDash = !inDash;
- }
- x += dash;
- }
- }
- }
- goto flush_and_return;
- } else if (dx == 0) {
- if (x1 >= devRect.x1 && x1 < devRect.x2) {
- int start_unclipped = qMin(y1, y2);
- int start = qMax(devRect.y1, start_unclipped);
- int stop = qMax(y1, y2) + 1;
- int stop_clipped = qMin(devRect.y2, stop);
- if (style == LineDrawNormal && stop == stop_clipped)
- --stop;
- else
- stop = stop_clipped;
-
- // adjust pattern for starting offset
- offset_pattern(start - start_unclipped, &inDash, &dashIndex, &currPattern, pattern);
-
- // loop over dashes
- int y = start;
- while (y < stop) {
- const int dash = qMin(currPattern, stop - y);
- if (inDash) {
- for (int i = 0; i < dash; ++i) {
- if (current == NSPANS) {
- span_func(NSPANS, spans, data);
- current = 0;
- }
- spans[current].x = x1;
- spans[current].len = 1;
- spans[current].coverage = 255;
- spans[current].y = ushort(y + i);
- ++current;
- }
- }
- if (dash < currPattern) {
- currPattern -= dash;
- } else {
- dashIndex = (dashIndex + 1) % pattern.size();
- currPattern = int(pattern[dashIndex]);
- inDash = !inDash;
- }
- y += dash;
- }
- }
- goto flush_and_return;
- }
-
- if (qAbs(dx) >= qAbs(dy)) { /* if x is the major axis: */
-
- if (x2 < x1) { /* if coordinates are out of order */
- qt_swap_int(x1, x2);
- dx = -dx;
-
- qt_swap_int(y1, y2);
- dy = -dy;
- }
-
- if (style == LineDrawNormal)
- --x2;
-
- // In the loops below we increment before call the span function so
- // we need to stop one pixel before
- x2 = qMin(x2, devRect.x2 - 1);
-
- // completely clipped, so abort
- if (x2 <= x1)
- goto flush_and_return;
-
- int x = x1;
- int y = y1;
-
- if (x >= devRect.x1 && y >= devRect.y1 && y < devRect.y2) {
- Q_ASSERT(x < devRect.x2);
- if (inDash) {
- if (current == NSPANS) {
- span_func(NSPANS, spans, data);
- current = 0;
- }
- spans[current].len = 1;
- spans[current].coverage = 255;
- spans[current].x = x;
- spans[current].y = y;
- ++current;
- }
- if (--currPattern <= 0) {
- inDash = !inDash;
- dashIndex = (dashIndex + 1) % pattern.size();
- currPattern = int(pattern[dashIndex]);
- }
- }
-
- if (y2 > y1) { // 315 -> 360 and 135 -> 180 (unit circle degrees)
- y2 = qMin(y2, devRect.y2 - 1);
-
- incrE = dy * 2;
- d = incrE - dx;
- incrNE = (dy - dx) * 2;
-
- if (y > y2)
- goto flush_and_return;
-
- while (x < x2) {
- if (d > 0) {
- ++y;
- d += incrNE;
- if (y > y2)
- goto flush_and_return;
- } else {
- d += incrE;
- }
- ++x;
-
- const bool skip = x < devRect.x1 || y < devRect.y1;
- Q_ASSERT(skip || (x < devRect.x2 && y < devRect.y2));
- if (inDash && !skip) {
- if (current == NSPANS) {
- span_func(NSPANS, spans, data);
- current = 0;
- }
- spans[current].len = 1;
- spans[current].coverage = 255;
- spans[current].x = x;
- spans[current].y = y;
- ++current;
- }
- if (--currPattern <= 0) {
- inDash = !inDash;
- dashIndex = (dashIndex + 1) % pattern.size();
- currPattern = int(pattern[dashIndex]);
- }
- }
- } else { // 0-45 and 180->225 (unit circle degrees)
- y1 = qMin(y1, devRect.y2 - 1);
-
- incrE = dy * 2;
- d = incrE + dx;
- incrNE = (dy + dx) * 2;
-
- if (y < devRect.y1)
- goto flush_and_return;
-
- while (x < x2) {
- if (d < 0) {
- if (current > 0) {
- span_func(current, spans, data);
- current = 0;
- }
-
- --y;
- d += incrNE;
- if (y < devRect.y1)
- goto flush_and_return;
- } else {
- d += incrE;
- }
- ++x;
-
- const bool skip = x < devRect.x1 || y > y1;
- Q_ASSERT(skip || (x < devRect.x2 && y < devRect.y2));
- if (inDash && !skip) {
- if (current == NSPANS) {
- span_func(NSPANS, spans, data);
- current = 0;
- }
- spans[current].len = 1;
- spans[current].coverage = 255;
- spans[current].x = x;
- spans[current].y = y;
- ++current;
- }
- if (--currPattern <= 0) {
- inDash = !inDash;
- dashIndex = (dashIndex + 1) % pattern.size();
- currPattern = int(pattern[dashIndex]);
- }
- }
- }
- } else {
-
- // if y is the major axis:
-
- if (y2 < y1) { /* if coordinates are out of order */
- qt_swap_int(y1, y2);
- dy = -dy;
-
- qt_swap_int(x1, x2);
- dx = -dx;
- }
-
- if (style == LineDrawNormal)
- --y2;
-
- // In the loops below we increment before call the span function so
- // we need to stop one pixel before
- y2 = qMin(y2, devRect.y2 - 1);
-
- // completely clipped, so abort
- if (y2 <= y1)
- goto flush_and_return;
-
- x = x1;
- y = y1;
-
- if (x>=devRect.x1 && y>=devRect.y1 && x < devRect.x2) {
- Q_ASSERT(x < devRect.x2);
- if (inDash) {
- if (current == NSPANS) {
- span_func(NSPANS, spans, data);
- current = 0;
- }
- spans[current].len = 1;
- spans[current].coverage = 255;
- spans[current].x = x;
- spans[current].y = y;
- ++current;
- }
- if (--currPattern <= 0) {
- inDash = !inDash;
- dashIndex = (dashIndex + 1) % pattern.size();
- currPattern = int(pattern[dashIndex]);
- }
- }
-
- if (x2 > x1) { // 90 -> 135 and 270 -> 315 (unit circle degrees)
- x2 = qMin(x2, devRect.x2 - 1);
- incrE = dx * 2;
- d = incrE - dy;
- incrNE = (dx - dy) * 2;
-
- if (x > x2)
- goto flush_and_return;
-
- while (y < y2) {
- if (d > 0) {
- ++x;
- d += incrNE;
- if (x > x2)
- goto flush_and_return;
- } else {
- d += incrE;
- }
- ++y;
- const bool skip = x < devRect.x1 || y < devRect.y1;
- Q_ASSERT(skip || (x < devRect.x2 && y < devRect.y2));
- if (inDash && !skip) {
- if (current == NSPANS) {
- span_func(NSPANS, spans, data);
- current = 0;
- }
- spans[current].len = 1;
- spans[current].coverage = 255;
- spans[current].x = x;
- spans[current].y = y;
- ++current;
- }
- if (--currPattern <= 0) {
- inDash = !inDash;
- dashIndex = (dashIndex + 1) % pattern.size();
- currPattern = int(pattern[dashIndex]);
- }
- }
- } else { // 45 -> 90 and 225 -> 270 (unit circle degrees)
- x1 = qMin(x1, devRect.x2 - 1);
- incrE = dx * 2;
- d = incrE + dy;
- incrNE = (dx + dy) * 2;
-
- if (x < devRect.x1)
- goto flush_and_return;
-
- while (y < y2) {
- if (d < 0) {
- --x;
- d += incrNE;
- if (x < devRect.x1)
- goto flush_and_return;
- } else {
- d += incrE;
- }
- ++y;
- const bool skip = y < devRect.y1 || x > x1;
- Q_ASSERT(skip || (x >= devRect.x1 && x < devRect.x2 && y < devRect.y2));
- if (inDash && !skip) {
- if (current == NSPANS) {
- span_func(NSPANS, spans, data);
- current = 0;
- }
- spans[current].len = 1;
- spans[current].coverage = 255;
- spans[current].x = x;
- spans[current].y = y;
- ++current;
- }
- if (--currPattern <= 0) {
- inDash = !inDash;
- dashIndex = (dashIndex + 1) % pattern.size();
- currPattern = int(pattern[dashIndex]);
- }
- }
- }
- }
-flush_and_return:
- if (current > 0)
- span_func(current, ordered ? spans : spans + (NSPANS - current), data);
-
- // adjust offset
- if (reversed) {
- *patternOffset = (patternLength - 1 - *patternOffset);
- } else {
- *patternOffset = 0;
- for (int i = 0; i <= dashIndex; ++i)
- *patternOffset += int(pattern[i]);
- *patternOffset += patternLength - currPattern - 1;
- *patternOffset = (*patternOffset % patternLength);
- }
-}
-
/*!
\internal
\a x and \a y is relative to the midpoint of \a rect.
diff --git a/src/gui/painting/qpaintengine_raster_p.h b/src/gui/painting/qpaintengine_raster_p.h
index 8859df0..8774fda 100644
--- a/src/gui/painting/qpaintengine_raster_p.h
+++ b/src/gui/painting/qpaintengine_raster_p.h
@@ -196,9 +196,6 @@ public:
void stroke(const QVectorPath &path, const QPen &pen);
void fill(const QVectorPath &path, const QBrush &brush);
- void strokePolygonCosmetic(const QPoint *pts, int pointCount, PolygonDrawMode mode);
- void strokePolygonCosmetic(const QPointF *pt, int pointCount, PolygonDrawMode mode);
-
void clip(const QVectorPath &path, Qt::ClipOperation op);
void clip(const QRect &rect, Qt::ClipOperation op);
void clip(const QRegion &region, Qt::ClipOperation op);
@@ -249,6 +246,8 @@ public:
virtual void drawBufferSpan(const uint *buffer, int bufsize,
int x, int y, int length, uint const_alpha);
#endif
+ bool supportsTransformations(const QFontEngine *fontEngine) const;
+ bool supportsTransformations(qreal pixelSize, const QTransform &m) const;
protected:
QRasterPaintEngine(QRasterPaintEnginePrivate &d, QPaintDevice *);
@@ -328,7 +327,6 @@ public:
bool isUnclipped_normalized(const QRect &rect) const;
bool isUnclipped(const QRect &rect, int penWidth) const;
bool isUnclipped(const QRectF &rect, int penWidth) const;
- ProcessSpans getPenFunc(const QRect &rect, const QSpanData *data) const;
ProcessSpans getPenFunc(const QRectF &rect, const QSpanData *data) const;
ProcessSpans getBrushFunc(const QRect &rect, const QSpanData *data) const;
ProcessSpans getBrushFunc(const QRectF &rect, const QSpanData *data) const;
diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp
index 30cf206..8510416 100644
--- a/src/gui/painting/qpaintengineex.cpp
+++ b/src/gui/painting/qpaintengineex.cpp
@@ -44,6 +44,8 @@
#include "qstroker_p.h"
#include "qbezier_p.h"
#include <private/qpainterpath_p.h>
+#include <private/qfontengine_p.h>
+#include <private/qstatictext_p.h>
#include <qvarlengtharray.h>
#include <qdebug.h>
@@ -831,7 +833,7 @@ void QPaintEngineEx::drawEllipse(const QRectF &r)
int point_count = 0;
x.points[0] = qt_curves_for_arc(r, 0, -360, x.points + 1, &point_count);
- QVectorPath vp((qreal *) pts, point_count, qpaintengineex_ellipse_types, QVectorPath::EllipseHint);
+ QVectorPath vp((qreal *) pts, point_count + 1, qpaintengineex_ellipse_types, QVectorPath::EllipseHint);
draw(vp);
}
@@ -1057,5 +1059,48 @@ Q_GUI_EXPORT QPainterPath qt_painterPathFromVectorPath(const QVectorPath &path)
return p;
}
+void QPaintEngineEx::drawStaticTextItem(QStaticTextItem *staticTextItem)
+{
+ QPainterPath path;
+#ifndef Q_WS_MAC
+ path.setFillRule(Qt::WindingFill);
+#endif
+
+ if (staticTextItem->numGlyphs == 0)
+ return;
+
+ QFontEngine *fontEngine = staticTextItem->fontEngine();
+ fontEngine->addGlyphsToPath(staticTextItem->glyphs, staticTextItem->glyphPositions,
+ staticTextItem->numGlyphs, &path, 0);
+ if (!path.isEmpty()) {
+ QPainterState *s = state();
+ QPainter::RenderHints oldHints = s->renderHints;
+ bool changedHints = false;
+ if (bool(oldHints & QPainter::TextAntialiasing)
+ && !bool(fontEngine->fontDef.styleStrategy & QFont::NoAntialias)
+ && !bool(oldHints & QPainter::Antialiasing)) {
+ s->renderHints |= QPainter::Antialiasing;
+ renderHintsChanged();
+ changedHints = true;
+ }
+
+ fill(qtVectorPathForPath(path), staticTextItem->color);
+
+ if (changedHints) {
+ s->renderHints = oldHints;
+ renderHintsChanged();
+ }
+ }
+}
+
+bool QPaintEngineEx::supportsTransformations(qreal pixelSize, const QTransform &m) const
+{
+ Q_UNUSED(pixelSize);
+
+ if (!m.isAffine())
+ return true;
+
+ return false;
+}
QT_END_NAMESPACE
diff --git a/src/gui/painting/qpaintengineex_p.h b/src/gui/painting/qpaintengineex_p.h
index 9730033..c605685 100644
--- a/src/gui/painting/qpaintengineex_p.h
+++ b/src/gui/painting/qpaintengineex_p.h
@@ -202,7 +202,7 @@ public:
virtual void updateState(const QPaintEngineState &state);
- virtual void drawStaticTextItem(QStaticTextItem *) = 0;
+ virtual void drawStaticTextItem(QStaticTextItem *);
virtual void setState(QPainterState *s);
inline QPainterState *state() { return static_cast<QPainterState *>(QPaintEngine::state); }
@@ -227,6 +227,7 @@ public:
IsEmulationEngine = 0x02 // If set, this object is a QEmulationEngine.
};
virtual uint flags() const {return 0;}
+ virtual bool supportsTransformations(qreal pixelSize, const QTransform &m) const;
protected:
QPaintEngineEx(QPaintEngineExPrivate &data);
diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp
index 17b7451..d2b35c8 100644
--- a/src/gui/painting/qpainter.cpp
+++ b/src/gui/painting/qpainter.cpp
@@ -152,14 +152,6 @@ static inline uint line_emulation(uint emulation)
| QPaintEngine_OpaqueBackground);
}
-static bool qt_paintengine_supports_transformations(QPaintEngine::Type type)
-{
- return type == QPaintEngine::OpenGL2
- || type == QPaintEngine::OpenVG
- || type == QPaintEngine::OpenGL
- || type == QPaintEngine::CoreGraphics;
-}
-
#ifndef QT_NO_DEBUG
static bool qt_painter_thread_test(int devType, const char *what, bool extraCondition = false)
{
@@ -5815,20 +5807,19 @@ void QPainter::drawGlyphRun(const QPointF &position, const QGlyphRun &glyphRun)
int count = qMin(glyphIndexes.size(), glyphPositions.size());
QVarLengthArray<QFixedPoint, 128> fixedPointPositions(count);
- bool paintEngineSupportsTransformations =
- d->extended != 0
- ? qt_paintengine_supports_transformations(d->extended->type())
- : qt_paintengine_supports_transformations(d->engine->type());
-
- // If the matrix is not affine, the paint engine will fall back to
- // drawing the glyphs as paths, which in turn means we should not
- // preprocess the glyph positions
- if (!d->state->matrix.isAffine())
- paintEngineSupportsTransformations = true;
+ QRawFontPrivate *fontD = QRawFontPrivate::get(font);
+ bool supportsTransformations;
+ if (d->extended != 0) {
+ supportsTransformations = d->extended->supportsTransformations(fontD->fontEngine->fontDef.pixelSize,
+ d->state->matrix);
+ } else {
+ supportsTransformations = d->engine->type() == QPaintEngine::CoreGraphics
+ || d->state->matrix.isAffine();
+ }
for (int i=0; i<count; ++i) {
QPointF processedPosition = position + glyphPositions.at(i);
- if (!paintEngineSupportsTransformations)
+ if (!supportsTransformations)
processedPosition = d->state->transform().map(processedPosition);
fixedPointPositions[i] = QFixedPoint::fromPointF(processedPosition);
}
@@ -6004,11 +5995,12 @@ void QPainter::drawStaticText(const QPointF &topLeftPosition, const QStaticText
return;
}
- bool paintEngineSupportsTransformations = qt_paintengine_supports_transformations(d->extended->type());
- if (paintEngineSupportsTransformations && !staticText_d->untransformedCoordinates) {
+ bool supportsTransformations = d->extended->supportsTransformations(staticText_d->font.pixelSize(),
+ d->state->matrix);
+ if (supportsTransformations && !staticText_d->untransformedCoordinates) {
staticText_d->untransformedCoordinates = true;
staticText_d->needsRelayout = true;
- } else if (!paintEngineSupportsTransformations && staticText_d->untransformedCoordinates) {
+ } else if (!supportsTransformations && staticText_d->untransformedCoordinates) {
staticText_d->untransformedCoordinates = false;
staticText_d->needsRelayout = true;
}
@@ -6468,8 +6460,7 @@ static void drawTextItemDecoration(QPainter *painter, const QPointF &pos, const
const qreal underlineOffset = fe->underlinePosition().toReal();
// deliberately ceil the offset to avoid the underline coming too close to
// the text above it.
- const qreal aliasedCoordinateDelta = 0.5 - 0.015625;
- const qreal underlinePos = pos.y() + qCeil(underlineOffset) - aliasedCoordinateDelta;
+ const qreal underlinePos = pos.y() + qCeil(underlineOffset);
if (underlineStyle == QTextCharFormat::SpellCheckUnderline) {
underlineStyle = QTextCharFormat::UnderlineStyle(QApplication::style()->styleHint(QStyle::SH_SpellCheckUnderlineStyle));
diff --git a/src/gui/painting/qrasterizer.cpp b/src/gui/painting/qrasterizer.cpp
index 6c5edbc..1d3f581 100644
--- a/src/gui/painting/qrasterizer.cpp
+++ b/src/gui/painting/qrasterizer.cpp
@@ -62,8 +62,8 @@ typedef int Q16Dot16;
#define SPAN_BUFFER_SIZE 256
-#define COORD_ROUNDING 0 // 0: round up, 1: round down
-#define COORD_OFFSET 0 // 26.6, 32 is half a pixel
+#define COORD_ROUNDING 1 // 0: round up, 1: round down
+#define COORD_OFFSET 32 // 26.6, 32 is half a pixel
static inline QT_FT_Vector PointToVector(const QPointF &p)
{
diff --git a/src/gui/painting/qtextureglyphcache.cpp b/src/gui/painting/qtextureglyphcache.cpp
index 53fefa4..613c473 100644
--- a/src/gui/painting/qtextureglyphcache.cpp
+++ b/src/gui/painting/qtextureglyphcache.cpp
@@ -367,7 +367,9 @@ void QImageTextureGlyphCache::createTextureData(int width, int height)
int QImageTextureGlyphCache::glyphMargin() const
{
-#if (defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA)) || defined(Q_WS_X11)
+#if (defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA))
+ return 1;
+#elif defined(Q_WS_X11)
return 0;
#else
return m_type == QFontEngineGlyphCache::Raster_RGBMask ? 2 : 0;
diff --git a/src/gui/painting/qunifiedtoolbarsurface_mac.cpp b/src/gui/painting/qunifiedtoolbarsurface_mac.cpp
index aecbf2b..1eb5e61 100644
--- a/src/gui/painting/qunifiedtoolbarsurface_mac.cpp
+++ b/src/gui/painting/qunifiedtoolbarsurface_mac.cpp
@@ -171,10 +171,8 @@ void QUnifiedToolbarSurface::flush(QWidget *widget)
if (!d->image)
return;
- if (widget->d_func()->flushRequested) {
- // We call display: directly to avoid flickering in the toolbar.
- qt_mac_display(widget);
- }
+ if (widget->d_func()->flushRequested)
+ qt_mac_setNeedsDisplay(widget);
}
void QUnifiedToolbarSurface::prepareBuffer(QImage::Format format, QWidget *widget)
diff --git a/src/gui/text/qfontdatabase_x11.cpp b/src/gui/text/qfontdatabase_x11.cpp
index 8a13d91..a5fdcb5 100644
--- a/src/gui/text/qfontdatabase_x11.cpp
+++ b/src/gui/text/qfontdatabase_x11.cpp
@@ -1996,6 +1996,11 @@ void QFontDatabase::load(const QFontPrivate *d, int script)
QFontCache::instance()->insertEngine(key, fe);
}
+// Needed for fontconfig version < 2.2.97
+#ifndef FC_FAMILYLANG
+#define FC_FAMILYLANG "familylang"
+#endif
+
static void registerFont(QFontDatabasePrivate::ApplicationFont *fnt)
{
#if defined(QT_NO_FONTCONFIG)
diff --git a/src/gui/text/qfontengine_coretext.mm b/src/gui/text/qfontengine_coretext.mm
index 24bd750..9a83599 100644
--- a/src/gui/text/qfontengine_coretext.mm
+++ b/src/gui/text/qfontengine_coretext.mm
@@ -100,7 +100,12 @@ QCoreTextFontEngineMulti::QCoreTextFontEngineMulti(const QCFString &name, const
QCFType<CTFontDescriptorRef> descriptor = CTFontDescriptorCreateWithNameAndSize(name, fontDef.pixelSize);
QCFType<CTFontRef> baseFont = CTFontCreateWithFontDescriptor(descriptor, fontDef.pixelSize, &transform);
- ctfont = CTFontCreateCopyWithSymbolicTraits(baseFont, fontDef.pixelSize, &transform, symbolicTraits, symbolicTraits);
+ ctfont = NULL;
+ // There is a side effect in Core Text: if we apply 0 as symbolic traits to a font in normal weight,
+ // we will get the light version of that font (while the way supposed to work doesn't:
+ // setting kCTFontWeightTrait to some value between -1.0 to 0.0 has no effect on font selection)
+ if (fontDef.weight != QFont::Normal || symbolicTraits)
+ ctfont = CTFontCreateCopyWithSymbolicTraits(baseFont, fontDef.pixelSize, &transform, symbolicTraits, symbolicTraits);
// CTFontCreateCopyWithSymbolicTraits returns NULL if we ask for a trait that does
// not exist for the given font. (for example italic)
@@ -725,10 +730,10 @@ void QCoreTextFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *position
}
}
-QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition, int /*margin*/, bool aa)
+QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition, int margin, bool aa)
{
const glyph_metrics_t br = boundingBox(glyph);
- QImage im(qRound(br.width)+2, qRound(br.height)+2, QImage::Format_RGB32);
+ QImage im(qRound(br.width) + margin * 2, qRound(br.height) + margin * 2, QImage::Format_RGB32);
im.fill(0);
CGColorSpaceRef colorspace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
@@ -740,9 +745,8 @@ QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition
8, im.bytesPerLine(), colorspace,
cgflags);
CGContextSetFontSize(ctx, fontDef.pixelSize);
- CGContextSetShouldAntialias(ctx, aa ||
- (fontDef.pointSize > qt_antialiasing_threshold
- && !(fontDef.styleStrategy & QFont::NoAntialias)));
+ CGContextSetShouldAntialias(ctx, (aa || fontDef.pointSize > qt_antialiasing_threshold)
+ && !(fontDef.styleStrategy & QFont::NoAntialias));
CGContextSetShouldSmoothFonts(ctx, aa);
CGAffineTransform oldTextMatrix = CGContextGetTextMatrix(ctx);
CGAffineTransform cgMatrix = CGAffineTransformMake(1, 0, 0, 1, 0, 0);
@@ -760,8 +764,8 @@ QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition
CGContextSetFont(ctx, cgFont);
- qreal pos_x = -br.x.toReal() + subPixelPosition.toReal();
- qreal pos_y = im.height() + br.y.toReal() - 1;
+ qreal pos_x = -br.x.toReal() + subPixelPosition.toReal() + margin;
+ qreal pos_y = im.height() + br.y.toReal() - margin;
CGContextSetTextPosition(ctx, pos_x, pos_y);
CGSize advance;
diff --git a/src/gui/text/qfontengine_x11.cpp b/src/gui/text/qfontengine_x11.cpp
index 0997048..e3bfa5d 100644
--- a/src/gui/text/qfontengine_x11.cpp
+++ b/src/gui/text/qfontengine_x11.cpp
@@ -1205,7 +1205,9 @@ QFontEngine *QFontEngineX11FT::cloneWithSize(qreal pixelSize) const
delete fe;
return 0;
} else {
+#ifndef QT_NO_XRENDER
fe->xglyph_format = xglyph_format;
+#endif
return fe;
}
}
diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp
index b43c8f4..ad4f6d3 100644
--- a/src/gui/text/qtextengine.cpp
+++ b/src/gui/text/qtextengine.cpp
@@ -2825,6 +2825,75 @@ QFixed QTextEngine::offsetInLigature(const QScriptItem *si, int pos, int max, in
return 0;
}
+// Scan in logClusters[from..to-1] for glyph_pos
+int QTextEngine::getClusterLength(unsigned short *logClusters,
+ const HB_CharAttributes *attributes,
+ int from, int to, int glyph_pos, int *start)
+{
+ int clusterLength = 0;
+ for (int i = from; i < to; i++) {
+ if (logClusters[i] == glyph_pos && attributes[i].charStop) {
+ if (*start < 0)
+ *start = i;
+ clusterLength++;
+ }
+ else if (clusterLength)
+ break;
+ }
+ return clusterLength;
+}
+
+int QTextEngine::positionInLigature(const QScriptItem *si, int end,
+ QFixed x, QFixed edge, int glyph_pos,
+ bool cursorOnCharacter)
+{
+ unsigned short *logClusters = this->logClusters(si);
+ int clusterStart = -1;
+ int clusterLength = 0;
+
+ if (si->analysis.script != QUnicodeTables::Common &&
+ si->analysis.script != QUnicodeTables::Greek) {
+ if (glyph_pos == -1)
+ return si->position + end;
+ else {
+ int i;
+ for (i = 0; i < end; i++)
+ if (logClusters[i] == glyph_pos)
+ break;
+ return si->position + i;
+ }
+ }
+
+ if (glyph_pos == -1 && end > 0)
+ glyph_pos = logClusters[end - 1];
+ else {
+ if (x <= edge)
+ glyph_pos--;
+ }
+
+ const HB_CharAttributes *attrs = attributes();
+ clusterLength = getClusterLength(logClusters, attrs, 0, end, glyph_pos, &clusterStart);
+
+ if (clusterLength) {
+ const QGlyphLayout &glyphs = shapedGlyphs(si);
+ QFixed glyphWidth = glyphs.effectiveAdvance(glyph_pos);
+ // the approximate width of each individual element of the ligature
+ QFixed perItemWidth = glyphWidth / clusterLength;
+ QFixed left = x > edge ? edge : edge - glyphWidth;
+ int n = ((x - left) / perItemWidth).floor().toInt();
+ QFixed dist = x - left - n * perItemWidth;
+ int closestItem = dist > (perItemWidth / 2) ? n + 1 : n;
+ if (cursorOnCharacter && closestItem > 0)
+ closestItem--;
+ int pos = si->position + clusterStart + closestItem;
+ // Jump to the next charStop
+ while (!attrs[pos].charStop && pos < end)
+ pos++;
+ return pos;
+ }
+ return si->position + end;
+}
+
int QTextEngine::previousLogicalPosition(int oldPos) const
{
const HB_CharAttributes *attrs = attributes();
diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h
index ed24d59..055974a 100644
--- a/src/gui/text/qtextengine_p.h
+++ b/src/gui/text/qtextengine_p.h
@@ -620,6 +620,7 @@ public:
QFixed leadingSpaceWidth(const QScriptLine &line);
QFixed offsetInLigature(const QScriptItem *si, int pos, int max, int glyph_pos);
+ int positionInLigature(const QScriptItem *si, int end, QFixed x, QFixed edge, int glyph_pos, bool cursorOnCharacter);
int previousLogicalPosition(int oldPos) const;
int nextLogicalPosition(int oldPos) const;
int lineNumberForTextPosition(int pos);
@@ -642,6 +643,7 @@ private:
void resolveAdditionalFormats() const;
int endOfLine(int lineNum);
int beginningOfLine(int lineNum);
+ int getClusterLength(unsigned short *logClusters, const HB_CharAttributes *attributes, int from, int to, int glyph_pos, int *start);
};
class QStackTextEngine : public QTextEngine {
diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp
index 988ae93..7bc87ee 100644
--- a/src/gui/text/qtextlayout.cpp
+++ b/src/gui/text/qtextlayout.cpp
@@ -2559,8 +2559,8 @@ qreal QTextLine::cursorToX(int *cursorPos, Edge edge) const
} else {
bool rtl = eng->isRightToLeft();
bool visual = eng->visualCursorMovement();
+ int end = qMin(lineEnd, si->position + l) - si->position;
if (reverse) {
- int end = qMin(lineEnd, si->position + l) - si->position;
int glyph_end = end == l ? si->num_glyphs : logClusters[end];
int glyph_start = glyph_pos;
if (visual && !rtl && !(lastLine && itm == (visualOrder[nItems - 1] + firstItem)))
@@ -2576,7 +2576,7 @@ qreal QTextLine::cursorToX(int *cursorPos, Edge edge) const
for (int i = glyph_start; i <= glyph_end; i++)
x += glyphs.effectiveAdvance(i);
}
- x += eng->offsetInLigature(si, pos, line.length, glyph_pos);
+ x += eng->offsetInLigature(si, pos, end, glyph_pos);
}
*cursorPos = pos + si->position;
@@ -2691,6 +2691,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
}
int glyph_pos = -1;
+ QFixed edge;
// has to be inside run
if (cpos == QTextLine::CursorOnCharacter) {
if (si.analysis.bidiLevel % 2) {
@@ -2701,6 +2702,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
if (pos < x)
break;
glyph_pos = gs;
+ edge = pos;
break;
}
pos -= glyphs.effectiveAdvance(gs);
@@ -2713,6 +2715,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
if (pos > x)
break;
glyph_pos = gs;
+ edge = pos;
}
pos += glyphs.effectiveAdvance(gs);
++gs;
@@ -2726,6 +2729,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
while (gs <= ge) {
if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) {
glyph_pos = gs;
+ edge = pos;
dist = qAbs(x-pos);
}
pos -= glyphs.effectiveAdvance(gs);
@@ -2735,6 +2739,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
while (ge >= gs) {
if (glyphs.attributes[ge].clusterStart && qAbs(x-pos) < dist) {
glyph_pos = ge;
+ edge = pos;
dist = qAbs(x-pos);
}
pos += glyphs.effectiveAdvance(ge);
@@ -2746,6 +2751,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
while (gs <= ge) {
if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) {
glyph_pos = gs;
+ edge = pos;
dist = qAbs(x-pos);
}
pos += glyphs.effectiveAdvance(gs);
@@ -2757,6 +2763,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
pos += glyphs.effectiveAdvance(gs);
if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) {
glyph_pos = gs;
+ edge = pos;
dist = qAbs(x-pos);
}
++gs;
@@ -2773,16 +2780,13 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
if (rtl && nchars > 0)
return insertionPoints[lastLine ? nchars : nchars - 1];
}
- return si.position + end;
+ return eng->positionInLigature(&si, end, x, pos, -1,
+ cpos == QTextLine::CursorOnCharacter);
}
}
Q_ASSERT(glyph_pos != -1);
- int j;
- for (j = 0; j < eng->length(item); ++j)
- if (logClusters[j] == glyph_pos)
- break;
-// qDebug("at pos %d (in run: %d)", si.position + j, j);
- return si.position + j;
+ return eng->positionInLigature(&si, end, x, edge, glyph_pos,
+ cpos == QTextLine::CursorOnCharacter);
}
}
// right of last item
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
index e62af62..3ac759c 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
@@ -1436,19 +1436,30 @@ void QGL2PaintEngineEx::drawStaticTextItem(QStaticTextItem *textItem)
ensureActive();
- QFontEngineGlyphCache::Type glyphType = textItem->fontEngine()->glyphFormat >= 0
- ? QFontEngineGlyphCache::Type(textItem->fontEngine()->glyphFormat)
- : d->glyphCacheType;
- if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) {
- if (d->device->alphaRequested() || state()->matrix.type() > QTransform::TxTranslate
- || (state()->composition_mode != QPainter::CompositionMode_Source
- && state()->composition_mode != QPainter::CompositionMode_SourceOver))
- {
- glyphType = QFontEngineGlyphCache::Raster_A8;
+ QPainterState *s = state();
+ float det = s->matrix.determinant();
+
+ // don't try to cache huge fonts or vastly transformed fonts
+ QFontEngine *fontEngine = textItem->fontEngine();
+ const qreal pixelSize = fontEngine->fontDef.pixelSize;
+ if (pixelSize * pixelSize * qAbs(det) < QT_MAX_CACHED_GLYPH_SIZE * QT_MAX_CACHED_GLYPH_SIZE ||
+ det < 0.25f || det > 4.f) {
+ QFontEngineGlyphCache::Type glyphType = fontEngine->glyphFormat >= 0
+ ? QFontEngineGlyphCache::Type(textItem->fontEngine()->glyphFormat)
+ : d->glyphCacheType;
+ if (glyphType == QFontEngineGlyphCache::Raster_RGBMask) {
+ if (d->device->alphaRequested() || s->matrix.type() > QTransform::TxTranslate
+ || (s->composition_mode != QPainter::CompositionMode_Source
+ && s->composition_mode != QPainter::CompositionMode_SourceOver))
+ {
+ glyphType = QFontEngineGlyphCache::Raster_A8;
+ }
}
- }
- d->drawCachedGlyphs(glyphType, textItem);
+ d->drawCachedGlyphs(glyphType, textItem);
+ } else {
+ QPaintEngineEx::drawStaticTextItem(textItem);
+ }
}
bool QGL2PaintEngineEx::drawTexture(const QRectF &dest, GLuint textureId, const QSize &size, const QRectF &src)
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
index 7ba92e4..2895d5a 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2_p.h
@@ -158,6 +158,7 @@ public:
void setRenderTextActive(bool);
bool isNativePaintingActive() const;
+ bool supportsTransformations(qreal, const QTransform &) const { return true; }
private:
Q_DISABLE_COPY(QGL2PaintEngineEx)
};
diff --git a/src/opengl/qgl_qpa.cpp b/src/opengl/qgl_qpa.cpp
index e7fc560..f8f3974 100644
--- a/src/opengl/qgl_qpa.cpp
+++ b/src/opengl/qgl_qpa.cpp
@@ -150,6 +150,8 @@ bool QGLContext::chooseContext(const QGLContext* shareContext)
if (shareContext) {
winFormat.setSharedContext(shareContext->d_func()->platformContext);
}
+ if (widget->testAttribute(Qt::WA_TranslucentBackground))
+ winFormat.setAlpha(true);
winFormat.setWindowApi(QPlatformWindowFormat::OpenGL);
winFormat.setWindowSurface(false);
widget->setPlatformWindowFormat(winFormat);
diff --git a/src/opengl/qpaintengine_opengl_p.h b/src/opengl/qpaintengine_opengl_p.h
index 5d5f5ce..8d0ea83 100644
--- a/src/opengl/qpaintengine_opengl_p.h
+++ b/src/opengl/qpaintengine_opengl_p.h
@@ -143,6 +143,7 @@ public:
Qt::HANDLE handle() const;
#endif
inline Type type() const { return QPaintEngine::OpenGL; }
+ bool supportsTransformations(qreal, const QTransform &) const { return true; }
private:
void drawPolyInternal(const QPolygonF &pa, bool close = true);
diff --git a/src/opengl/qwindowsurface_gl.cpp b/src/opengl/qwindowsurface_gl.cpp
index 7f63aea..ff55142 100644
--- a/src/opengl/qwindowsurface_gl.cpp
+++ b/src/opengl/qwindowsurface_gl.cpp
@@ -542,19 +542,27 @@ void QGLWindowSurface::beginPaint(const QRegion &)
d_ptr->did_paint = true;
updateGeometry();
- if (!context())
- return;
-
int clearFlags = 0;
- if (context()->d_func()->workaround_needsFullClearOnEveryFrame)
+ QGLContext *ctx = reinterpret_cast<QGLContext *>(window()->d_func()->extraData()->glContext);
+
+ if (!ctx)
+ return;
+
+ if (ctx->d_func()->workaround_needsFullClearOnEveryFrame)
clearFlags = GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT;
- else if (context()->format().alpha())
+ else if (ctx->format().alpha())
clearFlags = GL_COLOR_BUFFER_BIT;
if (clearFlags) {
+ if (d_ptr->fbo)
+ d_ptr->fbo->bind();
+
glClearColor(0.0, 0.0, 0.0, 0.0);
glClear(clearFlags);
+
+ if (d_ptr->fbo)
+ d_ptr->fbo->release();
}
}
diff --git a/src/openvg/qpaintengine_vg_p.h b/src/openvg/qpaintengine_vg_p.h
index f1ef0fb..267ecd4 100644
--- a/src/openvg/qpaintengine_vg_p.h
+++ b/src/openvg/qpaintengine_vg_p.h
@@ -159,6 +159,7 @@ public:
QVGPaintEnginePrivate *vgPrivate() { Q_D(QVGPaintEngine); return d; }
void fillRegion(const QRegion& region, const QColor& color, const QSize& surfaceSize);
+ bool supportsTransformations(qreal, const QTransform &) const { return true; }
protected:
QVGPaintEngine(QVGPaintEnginePrivate &data);
diff --git a/src/plugins/platforms/glxconvenience/glxconvenience.pri b/src/plugins/platforms/glxconvenience/glxconvenience.pri
index d6c9922..b4d43a3 100644
--- a/src/plugins/platforms/glxconvenience/glxconvenience.pri
+++ b/src/plugins/platforms/glxconvenience/glxconvenience.pri
@@ -5,3 +5,11 @@ HEADERS += \
SOURCES += \
$$PWD/qglxconvenience.cpp
+
+CONFIG += xrender
+
+xrender {
+ LIBS += -lXrender
+} else {
+ DEFINES += QT_NO_XRENDER
+}
diff --git a/src/plugins/platforms/glxconvenience/qglxconvenience.cpp b/src/plugins/platforms/glxconvenience/qglxconvenience.cpp
index c776f5b..34633d9 100644
--- a/src/plugins/platforms/glxconvenience/qglxconvenience.cpp
+++ b/src/plugins/platforms/glxconvenience/qglxconvenience.cpp
@@ -43,6 +43,10 @@
#include <QtCore/QVector>
+#ifndef QT_NO_XRENDER
+#include <X11/extensions/Xrender.h>
+#endif
+
enum {
XFocusOut = FocusOut,
XFocusIn = FocusIn,
@@ -84,14 +88,15 @@ QVector<int> qglx_buildSpec(const QPlatformWindowFormat &format, int drawableBit
spec[i++] = GLX_ALPHA_SIZE; spec[i++] = (format.alphaBufferSize() == -1) ? 1 : format.alphaBufferSize();
}
- spec[i++] = GLX_ACCUM_RED_SIZE; spec[i++] = (format.accumBufferSize() == -1) ? 1 : format.accumBufferSize();
- spec[i++] = GLX_ACCUM_GREEN_SIZE; spec[i++] = (format.accumBufferSize() == -1) ? 1 : format.accumBufferSize();
- spec[i++] = GLX_ACCUM_BLUE_SIZE; spec[i++] = (format.accumBufferSize() == -1) ? 1 : format.accumBufferSize();
+ if (format.accum()) {
+ spec[i++] = GLX_ACCUM_RED_SIZE; spec[i++] = (format.accumBufferSize() == -1) ? 1 : format.accumBufferSize();
+ spec[i++] = GLX_ACCUM_GREEN_SIZE; spec[i++] = (format.accumBufferSize() == -1) ? 1 : format.accumBufferSize();
+ spec[i++] = GLX_ACCUM_BLUE_SIZE; spec[i++] = (format.accumBufferSize() == -1) ? 1 : format.accumBufferSize();
- if (format.alpha()) {
- spec[i++] = GLX_ACCUM_ALPHA_SIZE; spec[i++] = (format.accumBufferSize() == -1) ? 1 : format.accumBufferSize();
+ if (format.alpha()) {
+ spec[i++] = GLX_ACCUM_ALPHA_SIZE; spec[i++] = (format.accumBufferSize() == -1) ? 1 : format.accumBufferSize();
+ }
}
-
} else {
spec[i++] = GLX_RENDER_TYPE; spec[i++] = GLX_COLOR_INDEX_BIT; //I'm really not sure if this works....
spec[i++] = GLX_BUFFER_SIZE; spec[i++] = 8;
@@ -136,8 +141,17 @@ GLXFBConfig qglx_findConfig(Display *display, int screen , const QPlatformWindow
if (reducedFormat.alpha()) {
int alphaSize;
glXGetFBConfigAttrib(display,configs[i],GLX_ALPHA_SIZE,&alphaSize);
- if (alphaSize > 0)
- break;
+ if (alphaSize > 0) {
+ XVisualInfo *visual = glXGetVisualFromFBConfig(display, chosenConfig);
+#if !defined(QT_NO_XRENDER)
+ XRenderPictFormat *pictFormat = XRenderFindVisualFormat(display, visual->visual);
+ if (pictFormat->direct.alphaMask > 0)
+ break;
+#else
+ if (visual->depth == 32)
+ break;
+#endif
+ }
} else {
break; // Just choose the first in the list if there's no alpha requested
}
diff --git a/src/plugins/platforms/minimal/qminimalintegration.cpp b/src/plugins/platforms/minimal/qminimalintegration.cpp
index 50c3626..b9ab528 100644
--- a/src/plugins/platforms/minimal/qminimalintegration.cpp
+++ b/src/plugins/platforms/minimal/qminimalintegration.cpp
@@ -50,8 +50,8 @@ QMinimalIntegration::QMinimalIntegration()
QMinimalScreen *mPrimaryScreen = new QMinimalScreen();
mPrimaryScreen->mGeometry = QRect(0, 0, 240, 320);
- mPrimaryScreen->mDepth = 16;
- mPrimaryScreen->mFormat = QImage::Format_RGB16;
+ mPrimaryScreen->mDepth = 32;
+ mPrimaryScreen->mFormat = QImage::Format_ARGB32_Premultiplied;
mScreens.append(mPrimaryScreen);
}
diff --git a/src/plugins/platforms/minimal/qminimalintegration.h b/src/plugins/platforms/minimal/qminimalintegration.h
index df4a9da..d1fcc42 100644
--- a/src/plugins/platforms/minimal/qminimalintegration.h
+++ b/src/plugins/platforms/minimal/qminimalintegration.h
@@ -51,7 +51,7 @@ class QMinimalScreen : public QPlatformScreen
{
public:
QMinimalScreen()
- : mDepth(16), mFormat(QImage::Format_RGB16) {}
+ : mDepth(32), mFormat(QImage::Format_ARGB32_Premultiplied) {}
QRect geometry() const { return mGeometry; }
int depth() const { return mDepth; }
diff --git a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandglcontext.cpp b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandglcontext.cpp
index 72ad5a8..0f27501 100644
--- a/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandglcontext.cpp
+++ b/src/plugins/platforms/wayland/gl_integration/wayland_egl/qwaylandglcontext.cpp
@@ -115,8 +115,15 @@ void *QWaylandGLContext::getProcAddress(const QString &string)
void QWaylandGLContext::setEglSurface(EGLSurface surface)
{
- doneCurrent();
+ bool wasCurrent = false;
+ if (QPlatformGLContext::currentContext() == this) {
+ wasCurrent = true;
+ doneCurrent();
+ }
mSurface = surface;
+ if (wasCurrent) {
+ makeCurrent();
+ }
}
EGLConfig QWaylandGLContext::eglConfig() const
diff --git a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxcontext.cpp b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxcontext.cpp
index e53381e..dff6ffa 100644
--- a/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxcontext.cpp
+++ b/src/plugins/platforms/wayland/gl_integration/xcomposite_glx/qwaylandxcompositeglxcontext.cpp
@@ -132,10 +132,12 @@ void QWaylandXCompositeGLXContext::geometryChanged()
Colormap cmap = XCreateColormap(mGlxIntegration->xDisplay(),mGlxIntegration->rootWindow(),visualInfo->visual,AllocNone);
XSetWindowAttributes a;
+ a.background_pixel = WhitePixel(mGlxIntegration->xDisplay(), mGlxIntegration->screen());
+ a.border_pixel = BlackPixel(mGlxIntegration->xDisplay(), mGlxIntegration->screen());
a.colormap = cmap;
mXWindow = XCreateWindow(mGlxIntegration->xDisplay(), mGlxIntegration->rootWindow(),0, 0, size.width(), size.height(),
0, visualInfo->depth, InputOutput, visualInfo->visual,
- CWColormap, &a);
+ CWBackPixel|CWBorderPixel|CWColormap, &a);
XCompositeRedirectWindow(mGlxIntegration->xDisplay(), mXWindow, CompositeRedirectManual);
XMapWindow(mGlxIntegration->xDisplay(), mXWindow);
diff --git a/src/plugins/platforms/wayland/qwaylandclipboard.cpp b/src/plugins/platforms/wayland/qwaylandclipboard.cpp
index f2e6ccf..b7f6ae5 100644
--- a/src/plugins/platforms/wayland/qwaylandclipboard.cpp
+++ b/src/plugins/platforms/wayland/qwaylandclipboard.cpp
@@ -48,16 +48,54 @@
#include <QtCore/QStringList>
#include <QtCore/QFile>
#include <QtCore/QtDebug>
+#include <QtGui/private/qdnd_p.h>
static QWaylandClipboard *clipboard;
+class QWaylandMimeData : public QInternalMimeData
+{
+public:
+ void clearAll();
+ void setFormats(const QStringList &formatList);
+ bool hasFormat_sys(const QString &mimeType) const;
+ QStringList formats_sys() const;
+ QVariant retrieveData_sys(const QString &mimeType, QVariant::Type type) const;
+private:
+ QStringList mFormatList;
+};
+
+void QWaylandMimeData::clearAll()
+{
+ clear();
+ mFormatList.clear();
+}
+
+void QWaylandMimeData::setFormats(const QStringList &formatList)
+{
+ mFormatList = formatList;
+}
+
+bool QWaylandMimeData::hasFormat_sys(const QString &mimeType) const
+{
+ return formats().contains(mimeType);
+}
+
+QStringList QWaylandMimeData::formats_sys() const
+{
+ return mFormatList;
+}
+
+QVariant QWaylandMimeData::retrieveData_sys(const QString &mimeType, QVariant::Type type) const
+{
+ return clipboard->retrieveData(mimeType, type);
+}
+
class QWaylandSelection
{
public:
QWaylandSelection(QWaylandDisplay *display, QMimeData *data);
~QWaylandSelection();
-private:
static uint32_t getTime();
static void send(void *data, struct wl_selection *selection, const char *mime_type, int fd);
static void cancelled(void *data, struct wl_selection *selection);
@@ -125,7 +163,7 @@ void QWaylandSelection::cancelled(void *data, struct wl_selection *selection)
}
QWaylandClipboard::QWaylandClipboard(QWaylandDisplay *display)
- : mDisplay(display), mSelection(0), mMimeDataIn(0), mOffer(0)
+ : mDisplay(display), mMimeDataIn(0), mOffer(0)
{
clipboard = this;
}
@@ -157,32 +195,39 @@ void QWaylandClipboard::forceRoundtrip(struct wl_display *display)
wl_display_iterate(display, WL_DISPLAY_READABLE);
}
-const QMimeData *QWaylandClipboard::mimeData(QClipboard::Mode mode) const
+QVariant QWaylandClipboard::retrieveData(const QString &mimeType, QVariant::Type type) const
+{
+ Q_UNUSED(type);
+ if (mOfferedMimeTypes.isEmpty() || !mOffer)
+ return QVariant();
+ int pipefd[2];
+ if (pipe(pipefd) == -1) {
+ qWarning("QWaylandClipboard: pipe() failed");
+ return QVariant();
+ }
+ QByteArray mimeTypeBa = mimeType.toLatin1();
+ wl_selection_offer_receive(mOffer, mimeTypeBa.constData(), pipefd[1]);
+ QByteArray content;
+ forceRoundtrip(mDisplay->wl_display());
+ char buf[256];
+ int n;
+ close(pipefd[1]);
+ while ((n = read(pipefd[0], &buf, sizeof buf)) > 0)
+ content.append(buf, n);
+ close(pipefd[0]);
+ return content;
+}
+
+QMimeData *QWaylandClipboard::mimeData(QClipboard::Mode mode)
{
Q_ASSERT(mode == QClipboard::Clipboard);
+ if (!mSelections.isEmpty())
+ return mSelections.last()->mMimeData;
if (!mMimeDataIn)
- mMimeDataIn = new QMimeData;
- mMimeDataIn->clear();
- if (!mOfferedMimeTypes.isEmpty() && mOffer) {
- foreach (const QString &mimeType, mOfferedMimeTypes) {
- int pipefd[2];
- if (pipe(pipefd) == -1) {
- qWarning("QWaylandClipboard::mimedata: pipe() failed");
- break;
- }
- QByteArray mimeTypeBa = mimeType.toLatin1();
- wl_selection_offer_receive(mOffer, mimeTypeBa.constData(), pipefd[1]);
- QByteArray content;
- forceRoundtrip(mDisplay->wl_display());
- char buf[256];
- int n;
- close(pipefd[1]);
- while ((n = read(pipefd[0], &buf, sizeof buf)) > 0)
- content.append(buf, n);
- close(pipefd[0]);
- mMimeDataIn->setData(mimeType, content);
- }
- }
+ mMimeDataIn = new QWaylandMimeData;
+ mMimeDataIn->clearAll();
+ if (!mOfferedMimeTypes.isEmpty() && mOffer)
+ mMimeDataIn->setFormats(mOfferedMimeTypes);
return mMimeDataIn;
}
@@ -192,7 +237,7 @@ void QWaylandClipboard::setMimeData(QMimeData *data, QClipboard::Mode mode)
if (!mDisplay->inputDevices().isEmpty()) {
if (!data)
data = new QMimeData;
- mSelection = new QWaylandSelection(mDisplay, data);
+ mSelections.append(new QWaylandSelection(mDisplay, data));
} else {
qWarning("QWaylandClipboard::setMimeData: No input devices");
}
@@ -222,21 +267,27 @@ void QWaylandClipboard::offer(void *data,
struct wl_selection_offer *selection_offer,
const char *type)
{
+ Q_UNUSED(data);
Q_UNUSED(selection_offer);
- QWaylandClipboard *self = static_cast<QWaylandClipboard *>(data);
- self->mOfferedMimeTypes.append(QString::fromLatin1(type));
+ clipboard->mOfferedMimeTypes.append(QString::fromLatin1(type));
}
void QWaylandClipboard::keyboardFocus(void *data,
struct wl_selection_offer *selection_offer,
wl_input_device *input_device)
{
- QWaylandClipboard *self = static_cast<QWaylandClipboard *>(data);
+ Q_UNUSED(data);
if (!input_device) {
wl_selection_offer_destroy(selection_offer);
- self->mOffer = 0;
+ clipboard->mOffer = 0;
return;
}
- self->mOffer = selection_offer;
- self->emitChanged(QClipboard::Clipboard);
+ clipboard->mOffer = selection_offer;
+ if (clipboard->mSelections.isEmpty())
+ QMetaObject::invokeMethod(&clipboard->mEmitter, "emitChanged", Qt::QueuedConnection);
+}
+
+void QWaylandClipboardSignalEmitter::emitChanged()
+{
+ clipboard->emitChanged(QClipboard::Clipboard);
}
diff --git a/src/plugins/platforms/wayland/qwaylandclipboard.h b/src/plugins/platforms/wayland/qwaylandclipboard.h
index dc51854..f45fb8d 100644
--- a/src/plugins/platforms/wayland/qwaylandclipboard.h
+++ b/src/plugins/platforms/wayland/qwaylandclipboard.h
@@ -44,18 +44,27 @@
#include <QtGui/QPlatformClipboard>
#include <QtCore/QStringList>
+#include <QtCore/QVariant>
class QWaylandDisplay;
class QWaylandSelection;
+class QWaylandMimeData;
struct wl_selection_offer;
+class QWaylandClipboardSignalEmitter : public QObject
+{
+ Q_OBJECT
+public slots:
+ void emitChanged();
+};
+
class QWaylandClipboard : public QPlatformClipboard
{
public:
QWaylandClipboard(QWaylandDisplay *display);
~QWaylandClipboard();
- const QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard) const;
+ QMimeData *mimeData(QClipboard::Mode mode = QClipboard::Clipboard);
void setMimeData(QMimeData *data, QClipboard::Mode mode = QClipboard::Clipboard);
bool supportsMode(QClipboard::Mode mode) const;
@@ -63,6 +72,8 @@ public:
void createSelectionOffer(uint32_t id);
+ QVariant retrieveData(const QString &mimeType, QVariant::Type type) const;
+
private:
static void offer(void *data,
struct wl_selection_offer *selection_offer,
@@ -76,11 +87,11 @@ private:
static void forceRoundtrip(struct wl_display *display);
QWaylandDisplay *mDisplay;
- QWaylandSelection *mSelection;
- mutable QMimeData *mMimeDataIn;
+ QWaylandMimeData *mMimeDataIn;
QList<QWaylandSelection *> mSelections;
QStringList mOfferedMimeTypes;
struct wl_selection_offer *mOffer;
+ QWaylandClipboardSignalEmitter mEmitter;
};
#endif // QWAYLANDCLIPBOARD_H
diff --git a/src/plugins/platforms/wayland/qwaylanddisplay.cpp b/src/plugins/platforms/wayland/qwaylanddisplay.cpp
index 14a8dcf..83516e9 100644
--- a/src/plugins/platforms/wayland/qwaylanddisplay.cpp
+++ b/src/plugins/platforms/wayland/qwaylanddisplay.cpp
@@ -51,6 +51,10 @@
#include "gl_integration/qwaylandglintegration.h"
#endif
+#ifdef QT_WAYLAND_WINDOWMANAGER_SUPPORT
+#include "windowmanager_integration/qwaylandwindowmanagerintegration.h"
+#endif
+
#include <QtCore/QAbstractEventDispatcher>
#include <QtGui/QApplication>
#include <QtGui/private/qapplication_p.h>
@@ -77,17 +81,17 @@ struct wl_buffer *QWaylandDisplay::createShmBuffer(int fd,
struct wl_visual *QWaylandDisplay::rgbVisual()
{
- return wl_display_get_rgb_visual(mDisplay);
+ return rgb_visual;
}
struct wl_visual *QWaylandDisplay::argbVisual()
{
- return wl_display_get_argb_visual(mDisplay);
+ return argb_visual;
}
struct wl_visual *QWaylandDisplay::argbPremultipliedVisual()
{
- return wl_display_get_premultiplied_argb_visual(mDisplay);
+ return premultiplied_argb_visual;
}
#ifdef QT_WAYLAND_GL_SUPPORT
@@ -97,6 +101,13 @@ QWaylandGLIntegration * QWaylandDisplay::eglIntegration()
}
#endif
+#ifdef QT_WAYLAND_WINDOWMANAGER_SUPPORT
+QWaylandWindowManagerIntegration *QWaylandDisplay::windowManagerIntegration()
+{
+ return mWindowManagerIntegration;
+}
+#endif
+
void QWaylandDisplay::shellHandleConfigure(void *data, struct wl_shell *shell,
uint32_t time, uint32_t edges,
struct wl_surface *surface,
@@ -116,6 +127,7 @@ const struct wl_shell_listener QWaylandDisplay::shellListener = {
};
QWaylandDisplay::QWaylandDisplay(void)
+ : argb_visual(0), premultiplied_argb_visual(0), rgb_visual(0)
{
mDisplay = wl_display_connect(NULL);
if (mDisplay == NULL) {
@@ -128,6 +140,11 @@ QWaylandDisplay::QWaylandDisplay(void)
#ifdef QT_WAYLAND_GL_SUPPORT
mEglIntegration = QWaylandGLIntegration::createGLIntegration(this);
#endif
+
+#ifdef QT_WAYLAND_WINDOWMANAGER_SUPPORT
+ mWindowManagerIntegration = QWaylandWindowManagerIntegration::createIntegration(this);
+#endif
+
blockingReadEvents();
qRegisterMetaType<uint32_t>("uint32_t");
@@ -228,6 +245,11 @@ const struct wl_output_listener QWaylandDisplay::outputListener = {
QWaylandDisplay::outputHandleGeometry
};
+const struct wl_compositor_listener QWaylandDisplay::compositorListener = {
+ QWaylandDisplay::handleVisual,
+};
+
+
void QWaylandDisplay::waitForScreens()
{
flushRequests();
@@ -256,6 +278,8 @@ void QWaylandDisplay::displayHandleGlobal(uint32_t id,
wl_output_add_listener(output, &outputListener, this);
} else if (interface == "wl_compositor") {
mCompositor = wl_compositor_create(mDisplay, id, 1);
+ wl_compositor_add_listener(mCompositor,
+ &compositorListener, this);
} else if (interface == "wl_shm") {
mShm = wl_shm_create(mDisplay, id, 1);
} else if (interface == "wl_shell"){
@@ -271,3 +295,23 @@ void QWaylandDisplay::displayHandleGlobal(uint32_t id,
clipboard->createSelectionOffer(id);
}
}
+
+void QWaylandDisplay::handleVisual(void *data,
+ struct wl_compositor *compositor,
+ uint32_t id, uint32_t token)
+{
+ QWaylandDisplay *self = static_cast<QWaylandDisplay *>(data);
+
+ switch (token) {
+ case WL_COMPOSITOR_VISUAL_ARGB32:
+ self->argb_visual = wl_visual_create(self->mDisplay, id, 1);
+ break;
+ case WL_COMPOSITOR_VISUAL_PREMULTIPLIED_ARGB32:
+ self->premultiplied_argb_visual =
+ wl_visual_create(self->mDisplay, id, 1);
+ break;
+ case WL_COMPOSITOR_VISUAL_XRGB32:
+ self->rgb_visual = wl_visual_create(self->mDisplay, id, 1);
+ break;
+ }
+}
diff --git a/src/plugins/platforms/wayland/qwaylanddisplay.h b/src/plugins/platforms/wayland/qwaylanddisplay.h
index 7cb2df1..765be62 100644
--- a/src/plugins/platforms/wayland/qwaylanddisplay.h
+++ b/src/plugins/platforms/wayland/qwaylanddisplay.h
@@ -55,6 +55,8 @@ class QWaylandBuffer;
class QPlatformScreen;
class QWaylandScreen;
class QWaylandGLIntegration;
+class QWaylandWindowManagerIntegration;
+
class QWaylandDisplay : public QObject {
Q_OBJECT
@@ -74,6 +76,11 @@ public:
#ifdef QT_WAYLAND_GL_SUPPORT
QWaylandGLIntegration *eglIntegration();
#endif
+
+#ifdef QT_WAYLAND_WINDOWMANAGER_SUPPORT
+ QWaylandWindowManagerIntegration *windowManagerIntegration();
+#endif
+
void setCursor(QWaylandBuffer *buffer, int32_t x, int32_t y);
void syncCallback(wl_display_sync_func_t func, void *data);
@@ -109,7 +116,10 @@ private:
uint32_t mSocketMask;
+ struct wl_visual *argb_visual, *premultiplied_argb_visual, *rgb_visual;
+
static const struct wl_output_listener outputListener;
+ static const struct wl_compositor_listener compositorListener;
static int sourceUpdate(uint32_t mask, void *data);
static void displayHandleGlobal(struct wl_display *display,
uint32_t id,
@@ -120,10 +130,17 @@ private:
int32_t x, int32_t y,
int32_t width, int32_t height);
+ static void handleVisual(void *data,
+ struct wl_compositor *compositor,
+ uint32_t id, uint32_t token);
#ifdef QT_WAYLAND_GL_SUPPORT
QWaylandGLIntegration *mEglIntegration;
#endif
+#ifdef QT_WAYLAND_WINDOWMANAGER_SUPPORT
+ QWaylandWindowManagerIntegration *mWindowManagerIntegration;
+#endif
+
static void shellHandleConfigure(void *data, struct wl_shell *shell,
uint32_t time, uint32_t edges,
struct wl_surface *surface,
diff --git a/src/plugins/platforms/wayland/qwaylandwindow.cpp b/src/plugins/platforms/wayland/qwaylandwindow.cpp
index 734591f..333a953 100644
--- a/src/plugins/platforms/wayland/qwaylandwindow.cpp
+++ b/src/plugins/platforms/wayland/qwaylandwindow.cpp
@@ -46,6 +46,11 @@
#include "qwaylandinputdevice.h"
#include "qwaylandscreen.h"
+#ifdef QT_WAYLAND_WINDOWMANAGER_SUPPORT
+#include "windowmanager_integration/qwaylandwindowmanagerintegration.h"
+#endif
+
+#include <QCoreApplication>
#include <QtGui/QWidget>
#include <QtGui/QWindowSystemInterface>
@@ -60,6 +65,11 @@ QWaylandWindow::QWaylandWindow(QWidget *window)
static WId id = 1;
mWindowId = id++;
+#ifdef QT_WAYLAND_WINDOWMANAGER_SUPPORT
+ mDisplay->windowManagerIntegration()->mapClientToProcess(qApp->applicationPid());
+ mDisplay->windowManagerIntegration()->authenticateWithToken();
+#endif
+
mSurface = mDisplay->createSurface(this);
}
@@ -120,7 +130,6 @@ void QWaylandWindow::attach(QWaylandBuffer *buffer)
}
}
-
void QWaylandWindow::damage(const QRegion &region)
{
//We have to do sync stuff before calling damage, or we might
diff --git a/src/plugins/platforms/wayland/wayland.pro b/src/plugins/platforms/wayland/wayland.pro
index 76f8be5..dca72fd 100644
--- a/src/plugins/platforms/wayland/wayland.pro
+++ b/src/plugins/platforms/wayland/wayland.pro
@@ -40,8 +40,10 @@ QMAKE_CXXFLAGS += $$QMAKE_CFLAGS_WAYLAND
INCLUDEPATH += $$PWD
include ($$PWD/gl_integration/gl_integration.pri)
+include ($$PWD/windowmanager_integration/windowmanager_integration.pri)
include (../fontdatabases/genericunix/genericunix.pri)
target.path += $$[QT_INSTALL_PLUGINS]/platforms
INSTALLS += target
+
diff --git a/src/plugins/platforms/wayland/wayland_sha1.txt b/src/plugins/platforms/wayland/wayland_sha1.txt
new file mode 100644
index 0000000..d262437
--- /dev/null
+++ b/src/plugins/platforms/wayland/wayland_sha1.txt
@@ -0,0 +1,3 @@
+This version of the Qt Wayland plugin is checked against the following sha1
+from the Wayland repository:
+eff7fc0d99be2e51eaa351785030c8d374ac71de
diff --git a/src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanagerintegration.cpp b/src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanagerintegration.cpp
new file mode 100644
index 0000000..e4a6218
--- /dev/null
+++ b/src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanagerintegration.cpp
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qwaylandwindowmanagerintegration.h"
+#include "qwaylandwindowmanager-client-protocol.h"
+
+#include <stdint.h>
+
+QWaylandWindowManagerIntegration *QWaylandWindowManagerIntegration::createIntegration(QWaylandDisplay *waylandDisplay)
+{
+ return new QWaylandWindowManagerIntegration(waylandDisplay);
+}
+
+QWaylandWindowManagerIntegration::QWaylandWindowManagerIntegration(QWaylandDisplay *waylandDisplay)
+ : mWaylandDisplay(waylandDisplay)
+ , mWaylandWindowManager(0)
+{
+ wl_display_add_global_listener(mWaylandDisplay->wl_display(),
+ QWaylandWindowManagerIntegration::wlHandleListenerGlobal,
+ this);
+}
+
+QWaylandWindowManagerIntegration::~QWaylandWindowManagerIntegration()
+{
+
+}
+
+struct wl_windowmanager *QWaylandWindowManagerIntegration::windowManager() const
+{
+ return mWaylandWindowManager;
+}
+
+void QWaylandWindowManagerIntegration::wlHandleListenerGlobal(wl_display *display, uint32_t id, const char *interface, uint32_t version, void *data)
+{
+ if (strcmp(interface, "wl_windowmanager") == 0) {
+ QWaylandWindowManagerIntegration *integration = static_cast<QWaylandWindowManagerIntegration *>(data);
+ integration->mWaylandWindowManager = wl_windowmanager_create(display, id);
+ }
+}
+
+void QWaylandWindowManagerIntegration::mapClientToProcess(long long processId)
+{
+ if (mWaylandWindowManager)
+ wl_windowmanager_map_client_to_process(mWaylandWindowManager, (uint32_t) processId);
+}
+
+void QWaylandWindowManagerIntegration::authenticateWithToken(const QByteArray &token)
+{
+ QByteArray authToken = token;
+ if (authToken.isEmpty())
+ authToken = qgetenv("WL_AUTHENTICATION_TOKEN");
+ if (mWaylandWindowManager)
+ wl_windowmanager_authenticate_with_token(mWaylandWindowManager, authToken.constData());
+}
diff --git a/src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanagerintegration.h b/src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanagerintegration.h
new file mode 100644
index 0000000..a79f205
--- /dev/null
+++ b/src/plugins/platforms/wayland/windowmanager_integration/qwaylandwindowmanagerintegration.h
@@ -0,0 +1,70 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the plugins of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QWAYLANDWINDOWMANAGERINTEGRATION_H
+#define QWAYLANDWINDOWMANAGERINTEGRATION_H
+
+#include <QObject>
+#include "wayland-client.h"
+#include "qwaylanddisplay.h"
+
+class QWaylandWindowManagerIntegration
+{
+public:
+ explicit QWaylandWindowManagerIntegration(QWaylandDisplay *waylandDisplay);
+ virtual ~QWaylandWindowManagerIntegration();
+ static QWaylandWindowManagerIntegration *createIntegration(QWaylandDisplay *waylandDisplay);
+ struct wl_windowmanager *windowManager() const;
+
+ void mapSurfaceToProcess(struct wl_surface *surface, long long processId);
+ void mapClientToProcess(long long processId);
+ void authenticateWithToken(const QByteArray &token = QByteArray());
+
+private:
+ static void wlHandleListenerGlobal(wl_display *display, uint32_t id,
+ const char *interface, uint32_t version, void *data);
+
+private:
+ QWaylandDisplay *mWaylandDisplay;
+ struct wl_windowmanager *mWaylandWindowManager;
+};
+
+#endif // QWAYLANDWINDOWMANAGERINTEGRATION_H
diff --git a/src/plugins/platforms/wayland/windowmanager_integration/windowmanager_integration.pri b/src/plugins/platforms/wayland/windowmanager_integration/windowmanager_integration.pri
new file mode 100644
index 0000000..664389a
--- /dev/null
+++ b/src/plugins/platforms/wayland/windowmanager_integration/windowmanager_integration.pri
@@ -0,0 +1,16 @@
+DEFINES += QT_WAYLAND_WINDOWMANAGER_SUPPORT
+
+contains(DEFINES, QT_WAYLAND_WINDOWMANAGER_SUPPORT) {
+
+ HEADERS += \
+ $$PWD/qwaylandwindowmanagerintegration.h
+
+ SOURCES += \
+ $$PWD/qwaylandwindowmanagerintegration.cpp
+
+ INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/wayland
+ HEADERS += \
+ $$QT_SOURCE_TREE/src/3rdparty/wayland/qwaylandwindowmanager-client-protocol.h
+ SOURCES += \
+ $$QT_SOURCE_TREE/src/3rdparty/wayland/wayland-windowmanager-protocol.c
+}
diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp
index c687e4c..0a02c7e 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindow.cpp
@@ -113,7 +113,8 @@ QXcbWindow::QXcbWindow(QWidget *tlw)
#if defined(XCB_USE_GLX) || defined(XCB_USE_EGL)
if (tlw->platformWindowFormat().windowApi() == QPlatformWindowFormat::OpenGL
- && QApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL))
+ && QApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)
+ || tlw->platformWindowFormat().alpha())
{
#if defined(XCB_USE_GLX)
XVisualInfo *visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(m_screen),m_screen->screenNumber(), tlw->platformWindowFormat());
@@ -131,13 +132,17 @@ QXcbWindow::QXcbWindow(QWidget *tlw)
visualInfo = XGetVisualInfo(DISPLAY_FROM_XCB(this), VisualIDMask, &visualInfoTemplate, &matchingCount);
#endif //XCB_USE_GLX
if (visualInfo) {
+ m_depth = visualInfo->depth;
+ m_format = (m_depth == 32) ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32;
Colormap cmap = XCreateColormap(DISPLAY_FROM_XCB(this), m_screen->root(), visualInfo->visual, AllocNone);
XSetWindowAttributes a;
+ a.background_pixel = WhitePixel(DISPLAY_FROM_XCB(this), m_screen->screenNumber());
+ a.border_pixel = BlackPixel(DISPLAY_FROM_XCB(this), m_screen->screenNumber());
a.colormap = cmap;
m_window = XCreateWindow(DISPLAY_FROM_XCB(this), m_screen->root(), tlw->x(), tlw->y(), tlw->width(), tlw->height(),
0, visualInfo->depth, InputOutput, visualInfo->visual,
- CWColormap, &a);
+ CWBackPixel|CWBorderPixel|CWColormap, &a);
printf("created GL window: %d\n", m_window);
} else {
@@ -147,6 +152,8 @@ QXcbWindow::QXcbWindow(QWidget *tlw)
#endif //defined(XCB_USE_GLX) || defined(XCB_USE_EGL)
{
m_window = xcb_generate_id(xcb_connection());
+ m_depth = m_screen->screen()->root_depth;
+ m_format = (m_depth == 32) ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32;
Q_XCB_CALL(xcb_create_window(xcb_connection(),
XCB_COPY_FROM_PARENT, // depth -- same as root
diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h
index 3f4d2d2..69d0bc2 100644
--- a/src/plugins/platforms/xcb/qxcbwindow.h
+++ b/src/plugins/platforms/xcb/qxcbwindow.h
@@ -44,6 +44,7 @@
#include <QtGui/QPlatformWindow>
#include <QtGui/QPlatformWindowFormat>
+#include <QtGui/QImage>
#include <xcb/xcb.h>
#include <xcb/sync.h>
@@ -74,6 +75,8 @@ public:
QPlatformGLContext *glContext() const;
xcb_window_t window() const { return m_window; }
+ uint depth() const { return m_depth; }
+ QImage::Format format() const { return m_format; }
void handleExposeEvent(const xcb_expose_event_t *event);
void handleClientMessageEvent(const xcb_client_message_event_t *event);
@@ -99,6 +102,9 @@ private:
xcb_window_t m_window;
QPlatformGLContext *m_context;
+ uint m_depth;
+ QImage::Format m_format;
+
xcb_sync_int64_t m_syncValue;
xcb_sync_counter_t m_syncCounter;
diff --git a/src/plugins/platforms/xcb/qxcbwindowsurface.cpp b/src/plugins/platforms/xcb/qxcbwindowsurface.cpp
index 827a899..4fcd207 100644
--- a/src/plugins/platforms/xcb/qxcbwindowsurface.cpp
+++ b/src/plugins/platforms/xcb/qxcbwindowsurface.cpp
@@ -54,11 +54,12 @@
#include <stdio.h>
#include <qdebug.h>
+#include <qpainter.h>
class QXcbShmImage : public QXcbObject
{
public:
- QXcbShmImage(QXcbScreen *connection, const QSize &size);
+ QXcbShmImage(QXcbScreen *connection, const QSize &size, uint depth, QImage::Format format);
~QXcbShmImage() { destroy(); }
QImage *image() { return &m_qimage; }
@@ -81,7 +82,7 @@ private:
QRegion m_dirty;
};
-QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size)
+QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size, uint depth, QImage::Format format)
: QXcbObject(screen->connection())
, m_gc(0)
, m_gc_window(0)
@@ -91,7 +92,7 @@ QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size)
size.width(),
size.height(),
XCB_IMAGE_FORMAT_Z_PIXMAP,
- screen->depth(),
+ depth,
0,
~0,
0);
@@ -111,7 +112,7 @@ QXcbShmImage::QXcbShmImage(QXcbScreen *screen, const QSize &size)
if (shmctl(m_shm_info.shmid, IPC_RMID, 0) == -1)
qWarning() << "QXcbWindowSurface: Error while marking the shared memory segment to be destroyed";
- m_qimage = QImage( (uchar*) m_xcb_image->data, m_xcb_image->width, m_xcb_image->height, m_xcb_image->stride, screen->format());
+ m_qimage = QImage( (uchar*) m_xcb_image->data, m_xcb_image->width, m_xcb_image->height, m_xcb_image->stride, format);
}
void QXcbShmImage::destroy()
@@ -189,6 +190,16 @@ QPaintDevice *QXcbWindowSurface::paintDevice()
void QXcbWindowSurface::beginPaint(const QRegion &region)
{
m_image->preparePaint(region);
+
+ if (m_image->image()->hasAlphaChannel()) {
+ QPainter p(m_image->image());
+ p.setCompositionMode(QPainter::CompositionMode_Source);
+ const QVector<QRect> rects = region.rects();
+ const QColor blank = Qt::transparent;
+ for (QVector<QRect>::const_iterator it = rects.begin(); it != rects.end(); ++it) {
+ p.fillRect(*it, blank);
+ }
+ }
}
void QXcbWindowSurface::endPaint(const QRegion &)
@@ -232,9 +243,10 @@ void QXcbWindowSurface::resize(const QSize &size)
QWindowSurface::resize(size);
QXcbScreen *screen = static_cast<QXcbScreen *>(QPlatformScreen::platformScreenForWidget(window()));
+ QXcbWindow* win = static_cast<QXcbWindow *>(window()->platformWindow());
delete m_image;
- m_image = new QXcbShmImage(screen, size);
+ m_image = new QXcbShmImage(screen, size, win->depth(), win->format());
Q_XCB_NOOP(connection());
m_syncingResize = true;
diff --git a/src/plugins/platforms/xlib/qxlibclipboard.cpp b/src/plugins/platforms/xlib/qxlibclipboard.cpp
index dbe81e0..2c1d91b 100644
--- a/src/plugins/platforms/xlib/qxlibclipboard.cpp
+++ b/src/plugins/platforms/xlib/qxlibclipboard.cpp
@@ -161,12 +161,11 @@ QXlibClipboard::QXlibClipboard(QXlibScreen *screen)
{
}
-const QMimeData * QXlibClipboard::mimeData(QClipboard::Mode mode) const
+QMimeData * QXlibClipboard::mimeData(QClipboard::Mode mode)
{
if (mode == QClipboard::Clipboard) {
if (!m_xClipboard) {
- QXlibClipboard *that = const_cast<QXlibClipboard *>(this);
- that->m_xClipboard = new QXlibClipboardMime(mode,that);
+ m_xClipboard = new QXlibClipboardMime(mode, this);
}
Window clipboardOwner = XGetSelectionOwner(screen()->display()->nativeDisplay(),QXlibStatic::atom(QXlibStatic::CLIPBOARD));
if (clipboardOwner == owner()) {
@@ -176,8 +175,7 @@ const QMimeData * QXlibClipboard::mimeData(QClipboard::Mode mode) const
}
} else if (mode == QClipboard::Selection) {
if (!m_xSelection) {
- QXlibClipboard *that = const_cast<QXlibClipboard *>(this);
- that->m_xSelection = new QXlibClipboardMime(mode,that);
+ m_xSelection = new QXlibClipboardMime(mode, this);
}
Window clipboardOwner = XGetSelectionOwner(screen()->display()->nativeDisplay(),XA_PRIMARY);
if (clipboardOwner == owner()) {
diff --git a/src/plugins/platforms/xlib/qxlibclipboard.h b/src/plugins/platforms/xlib/qxlibclipboard.h
index 5d78a7f..8fdc18b 100644
--- a/src/plugins/platforms/xlib/qxlibclipboard.h
+++ b/src/plugins/platforms/xlib/qxlibclipboard.h
@@ -51,7 +51,7 @@ class QXlibClipboard : public QPlatformClipboard
public:
QXlibClipboard(QXlibScreen *screen);
- const QMimeData *mimeData(QClipboard::Mode mode) const;
+ QMimeData *mimeData(QClipboard::Mode mode);
void setMimeData(QMimeData *data, QClipboard::Mode mode);
bool supportsMode(QClipboard::Mode mode) const;
diff --git a/src/plugins/platforms/xlib/qxlibintegration.cpp b/src/plugins/platforms/xlib/qxlibintegration.cpp
index 90ef066..02104d9 100644
--- a/src/plugins/platforms/xlib/qxlibintegration.cpp
+++ b/src/plugins/platforms/xlib/qxlibintegration.cpp
@@ -150,7 +150,7 @@ bool QXlibIntegration::hasOpenGL() const
{
#if !defined(QT_NO_OPENGL)
#if !defined(QT_OPENGL_ES_2)
- QXlibScreen *screen = static_cast<const QXlibScreen *>(mScreens.at(0));
+ QXlibScreen *screen = static_cast<QXlibScreen *>(mScreens.at(0));
return glXQueryExtension(screen->display()->nativeDisplay(), 0, 0) != 0;
#else
static bool eglHasbeenInitialized = false;
diff --git a/src/plugins/platforms/xlib/qxlibscreen.cpp b/src/plugins/platforms/xlib/qxlibscreen.cpp
index 8f21ec3..b069985 100644
--- a/src/plugins/platforms/xlib/qxlibscreen.cpp
+++ b/src/plugins/platforms/xlib/qxlibscreen.cpp
@@ -41,6 +41,8 @@
#include "qxlibscreen.h"
+#include <X11/extensions/Xfixes.h>
+
#include "qxlibcursor.h"
#include "qxlibwindow.h"
#include "qxlibkeyboard.h"
diff --git a/src/plugins/platforms/xlib/qxlibstatic.h b/src/plugins/platforms/xlib/qxlibstatic.h
index b46b28d..9caa2fa 100644
--- a/src/plugins/platforms/xlib/qxlibstatic.h
+++ b/src/plugins/platforms/xlib/qxlibstatic.h
@@ -136,6 +136,7 @@ typedef char *XPointer;
#endif
#ifndef QT_NO_XFIXES
+#include <X11/extensions/Xfixes.h>
typedef Bool (*PtrXFixesQueryExtension)(Display *, int *, int *);
typedef Status (*PtrXFixesQueryVersion)(Display *, int *, int *);
typedef void (*PtrXFixesSetCursorName)(Display *dpy, Cursor cursor, const char *name);
diff --git a/src/plugins/platforms/xlib/qxlibwindow.cpp b/src/plugins/platforms/xlib/qxlibwindow.cpp
index 1666b1c..823fae9 100644
--- a/src/plugins/platforms/xlib/qxlibwindow.cpp
+++ b/src/plugins/platforms/xlib/qxlibwindow.cpp
@@ -47,14 +47,6 @@
#include "qxlibstatic.h"
#include "qxlibdisplay.h"
-#include <QtGui/QWindowSystemInterface>
-#include <QSocketNotifier>
-#include <QApplication>
-#include <QDebug>
-
-#include <QtGui/private/qwindowsurface_p.h>
-#include <QtGui/private/qapplication_p.h>
-
#if !defined(QT_NO_OPENGL)
#if !defined(QT_OPENGL_ES_2)
#include "qglxintegration.h"
@@ -66,6 +58,15 @@
#endif //QT_OPENGL_ES_2
#endif //QT_NO_OPENGL
+
+#include <QtGui/QWindowSystemInterface>
+#include <QSocketNotifier>
+#include <QApplication>
+#include <QDebug>
+
+#include <QtGui/private/qwindowsurface_p.h>
+#include <QtGui/private/qapplication_p.h>
+
//#define MYX11_DEBUG
QT_BEGIN_NAMESPACE
@@ -80,9 +81,10 @@ QXlibWindow::QXlibWindow(QWidget *window)
int w = window->width();
int h = window->height();
- if(window->platformWindowFormat().windowApi() == QPlatformWindowFormat::OpenGL
- && QApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL) ) {
#if !defined(QT_NO_OPENGL)
+ if(window->platformWindowFormat().windowApi() == QPlatformWindowFormat::OpenGL
+ && QApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)
+ || window->platformWindowFormat().alpha()) {
#if !defined(QT_OPENGL_ES_2)
XVisualInfo *visualInfo = qglx_findVisualInfo(mScreen->display()->nativeDisplay(),mScreen->xScreenNumber(),window->platformWindowFormat());
#else
@@ -101,18 +103,28 @@ QXlibWindow::QXlibWindow(QWidget *window)
visualInfo = XGetVisualInfo(mScreen->display()->nativeDisplay(), VisualIDMask, &visualInfoTemplate, &matchingCount);
#endif //!defined(QT_OPENGL_ES_2)
if (visualInfo) {
- Colormap cmap = XCreateColormap(mScreen->display()->nativeDisplay(),mScreen->rootWindow(),visualInfo->visual,AllocNone);
+ mDepth = visualInfo->depth;
+ mFormat = (mDepth == 32) ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32;
+ mVisual = visualInfo->visual;
+ Colormap cmap = XCreateColormap(mScreen->display()->nativeDisplay(), mScreen->rootWindow(), visualInfo->visual, AllocNone);
XSetWindowAttributes a;
+ a.background_pixel = WhitePixel(mScreen->display()->nativeDisplay(), mScreen->xScreenNumber());
+ a.border_pixel = BlackPixel(mScreen->display()->nativeDisplay(), mScreen->xScreenNumber());
a.colormap = cmap;
x_window = XCreateWindow(mScreen->display()->nativeDisplay(), mScreen->rootWindow(),x, y, w, h,
0, visualInfo->depth, InputOutput, visualInfo->visual,
- CWColormap, &a);
+ CWBackPixel|CWBorderPixel|CWColormap, &a);
} else {
qFatal("no window!");
}
+ } else
#endif //!defined(QT_NO_OPENGL)
- } else {
+ {
+ mDepth = mScreen->depth();
+ mFormat = (mDepth == 32) ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32;
+ mVisual = mScreen->defaultVisual();
+
x_window = XCreateSimpleWindow(mScreen->display()->nativeDisplay(), mScreen->rootWindow(),
x, y, w, h, 0 /*border_width*/,
mScreen->blackPixel(), mScreen->whitePixel());
diff --git a/src/plugins/platforms/xlib/qxlibwindow.h b/src/plugins/platforms/xlib/qxlibwindow.h
index adc2f85..da29efb 100644
--- a/src/plugins/platforms/xlib/qxlibwindow.h
+++ b/src/plugins/platforms/xlib/qxlibwindow.h
@@ -122,6 +122,10 @@ public:
Window xWindow() const;
GC graphicsContext() const;
+ inline uint depth() const { return mDepth; }
+ QImage::Format format() const { return mFormat; }
+ Visual* visual() const { return mVisual; }
+
protected:
QVector<Atom> getNetWmState() const;
void setMWMHints(const QXlibMWMHints &mwmhints);
@@ -135,6 +139,10 @@ private:
Window x_window;
GC gc;
+ uint mDepth;
+ QImage::Format mFormat;
+ Visual* mVisual;
+
GC createGC();
QPlatformGLContext *mGLContext;
diff --git a/src/plugins/platforms/xlib/qxlibwindowsurface.cpp b/src/plugins/platforms/xlib/qxlibwindowsurface.cpp
index add21ac..e0c272d 100644
--- a/src/plugins/platforms/xlib/qxlibwindowsurface.cpp
+++ b/src/plugins/platforms/xlib/qxlibwindowsurface.cpp
@@ -49,6 +49,8 @@
#include "qxlibscreen.h"
#include "qxlibdisplay.h"
+#include "qpainter.h"
+
# include <sys/ipc.h>
# include <sys/shm.h>
# include <X11/extensions/XShm.h>
@@ -80,20 +82,19 @@ void QXlibShmImageInfo::destroy()
void QXlibWindowSurface::resizeShmImage(int width, int height)
{
+ QXlibScreen *screen = QXlibScreen::testLiteScreenForWidget(window());
+ QXlibWindow *win = static_cast<QXlibWindow*>(window()->platformWindow());
#ifdef DONT_USE_MIT_SHM
- shm_img = QImage(width, height, QImage::Format_RGB32);
+ shm_img = QImage(width, height, win->format());
#else
- QXlibScreen *screen = QXlibScreen::testLiteScreenForWidget(window());
if (image_info)
image_info->destroy();
else
image_info = new QXlibShmImageInfo(screen->display()->nativeDisplay());
- Visual *visual = screen->defaultVisual();
-
- XImage *image = XShmCreateImage (screen->display()->nativeDisplay(), visual, 24, ZPixmap, 0,
+ XImage *image = XShmCreateImage (screen->display()->nativeDisplay(), win->visual(), win->depth(), ZPixmap, 0,
&image_info->shminfo, width, height);
@@ -109,7 +110,7 @@ void QXlibWindowSurface::resizeShmImage(int width, int height)
Q_ASSERT(shm_attach_status == True);
- shm_img = QImage( (uchar*) image->data, image->width, image->height, image->bytes_per_line, QImage::Format_RGB32 );
+ shm_img = QImage( (uchar*) image->data, image->width, image->height, image->bytes_per_line, win->format() );
#endif
painted = false;
}
@@ -160,11 +161,11 @@ void QXlibWindowSurface::flush(QWidget *widget, const QRegion &region, const QPo
#ifdef DONT_USE_MIT_SHM
// just convert the image every time...
if (!shm_img.isNull()) {
- Visual *visual = DefaultVisual(screen->display(), screen->xScreenNumber());
+ QXlibWindow *win = static_cast<QXlibWindow*>(window()->platformWindow());
QImage image = shm_img;
//img.convertToFormat(
- XImage *xi = XCreateImage(screen->display(), visual, 24, ZPixmap,
+ XImage *xi = XCreateImage(screen->display(), win->visual(), win->depth(), ZPixmap,
0, (char *) image.scanLine(0), image.width(), image.height(),
32, image.bytesPerLine());
@@ -214,6 +215,16 @@ void QXlibWindowSurface::beginPaint(const QRegion &region)
{
Q_UNUSED(region);
resizeBuffer(size());
+
+ if (shm_img.hasAlphaChannel()) {
+ QPainter p(&shm_img);
+ p.setCompositionMode(QPainter::CompositionMode_Source);
+ const QVector<QRect> rects = region.rects();
+ const QColor blank = Qt::transparent;
+ for (QVector<QRect>::const_iterator it = rects.begin(); it != rects.end(); ++it) {
+ p.fillRect(*it, blank);
+ }
+ }
}
void QXlibWindowSurface::endPaint(const QRegion &region)
diff --git a/tests/arthur/common/paintcommands.cpp b/tests/arthur/common/paintcommands.cpp
index 184fbb9..298c699 100644
--- a/tests/arthur/common/paintcommands.cpp
+++ b/tests/arthur/common/paintcommands.cpp
@@ -48,6 +48,7 @@
#include <qtextstream.h>
#include <qtextlayout.h>
#include <qdebug.h>
+#include <QStaticText>
#ifdef QT3_SUPPORT
#include <q3painter.h>
@@ -464,6 +465,10 @@ void PaintCommands::staticInit()
"^drawText\\s+(-?\\w*)\\s+(-?\\w*)\\s+\"(.*)\"$",
"drawText <x> <y> <text>",
"drawText 10 10 \"my text\"");
+ DECL_PAINTCOMMAND("drawStaticText", command_drawStaticText,
+ "^drawStaticText\\s+(-?\\w*)\\s+(-?\\w*)\\s+\"(.*)\"$",
+ "drawStaticText <x> <y> <text>",
+ "drawStaticText 10 10 \"my text\"");
DECL_PAINTCOMMAND("drawTiledPixmap", command_drawTiledPixmap,
"^drawTiledPixmap\\s+([\\w.:\\/]*)"
"\\s+(-?\\w*)\\s+(-?\\w*)\\s*(-?\\w*)\\s*(-?\\w*)"
@@ -1404,6 +1409,21 @@ void PaintCommands::command_drawText(QRegExp re)
m_painter->drawText(x, y, txt);
}
+void PaintCommands::command_drawStaticText(QRegExp re)
+{
+ if (!m_shouldDrawText)
+ return;
+ QStringList caps = re.capturedTexts();
+ int x = convertToInt(caps.at(1));
+ int y = convertToInt(caps.at(2));
+ QString txt = caps.at(3);
+
+ if (m_verboseMode)
+ printf(" -(lance) drawStaticText(%d, %d, %s)\n", x, y, qPrintable(txt));
+
+ m_painter->drawStaticText(x, y, QStaticText(txt));
+}
+
/***************************************************************************************************/
void PaintCommands::command_noop(QRegExp)
{
diff --git a/tests/arthur/common/paintcommands.h b/tests/arthur/common/paintcommands.h
index 6cc0889..04492ea 100644
--- a/tests/arthur/common/paintcommands.h
+++ b/tests/arthur/common/paintcommands.h
@@ -209,6 +209,7 @@ private:
void command_drawRoundedRect(QRegExp re);
void command_drawRoundRect(QRegExp re);
void command_drawText(QRegExp re);
+ void command_drawStaticText(QRegExp re);
void command_drawTiledPixmap(QRegExp re);
void command_path_addEllipse(QRegExp re);
void command_path_addPolygon(QRegExp re);
diff --git a/tests/auto/declarative/qdeclarativeqt/tst_qdeclarativeqt.cpp b/tests/auto/declarative/qdeclarativeqt/tst_qdeclarativeqt.cpp
index d75960c..0d581d4 100644
--- a/tests/auto/declarative/qdeclarativeqt/tst_qdeclarativeqt.cpp
+++ b/tests/auto/declarative/qdeclarativeqt/tst_qdeclarativeqt.cpp
@@ -174,7 +174,7 @@ void tst_qdeclarativeqt::rect()
QCOMPARE(qvariant_cast<QRectF>(object->property("test2")), QRectF(-10, 13, 100, 109.6));
QCOMPARE(qvariant_cast<QRectF>(object->property("test3")), QRectF());
QCOMPARE(qvariant_cast<QRectF>(object->property("test4")), QRectF());
- QCOMPARE(qvariant_cast<QRectF>(object->property("test5")), QRectF());
+ QCOMPARE(qvariant_cast<QRectF>(object->property("test5")), QRectF(10, 13, 100, -109));
delete object;
}
diff --git a/tests/auto/lancelot/scripts/statictext.qps b/tests/auto/lancelot/scripts/statictext.qps
new file mode 100644
index 0000000..b62b623
--- /dev/null
+++ b/tests/auto/lancelot/scripts/statictext.qps
@@ -0,0 +1,122 @@
+drawStaticText -5 5 "Text that is drawn outside the bounds..."
+
+translate 20 20
+begin_block text_drawing
+save
+ setFont "sansserif" 10 normal
+ drawStaticText 0 20 "sansserif 10pt, normal"
+
+ setFont "sansserif" 12 normal
+ drawStaticText 0 40 "sansserif 12pt, normal"
+
+ setFont "sansserif" 10 bold
+ drawStaticText 0 60 "sansserif 12pt, bold"
+
+ setFont "sansserif" 10 bold italic
+ drawStaticText 0 80 "sansserif 10pt, bold italic"
+
+
+ translate 0 100
+ setPen #7fff0000
+
+ setFont "sansserif" 10 normal
+ drawStaticText 0 20 "alpha sansserif 10pt, normal"
+
+ setFont "sansserif" 12 normal
+ drawStaticText 0 40 "alpha sansserif 12pt, normal"
+
+ setFont "sansserif" 10 bold
+ drawStaticText 0 60 "alpha sansserif 12pt, bold"
+
+ setFont "sansserif" 10 bold italic
+ drawStaticText 0 80 "alpha sansserif 10pt, bold italic"
+
+
+ translate 0 100
+ setPen black
+ save
+ scale 0.9 0.9
+
+ setFont "sansserif" 10 normal
+ drawStaticText 0 20 "scaled sansserif 10pt, normal"
+
+ setFont "sansserif" 12 normal
+ drawStaticText 0 40 "scaled sansserif 12pt, normal"
+
+ setFont "sansserif" 10 bold
+ drawStaticText 0 60 "scaled sansserif 12pt, bold"
+
+ setFont "sansserif" 10 bold italic
+ drawStaticText 0 80 "scaled sansserif 10pt, bold italic"
+ restore
+
+ translate 0 100
+ setPen black
+ save
+ translate 200 90
+ rotate 185
+
+ setFont "sansserif" 10 normal
+ drawStaticText 0 20 "scaled sansserif 10pt, normal"
+
+ setFont "sansserif" 12 normal
+ drawStaticText 0 40 "scaled sansserif 12pt, normal"
+
+ setFont "sansserif" 10 bold
+ drawStaticText 0 60 "scaled sansserif 12pt, bold"
+
+ setFont "sansserif" 10 bold italic
+ drawStaticText 0 80 "scaled sansserif 10pt, bold italic"
+ restore
+
+ translate 0 100
+ gradient_appendStop 0 red
+ gradient_appendStop 0.5 #00ff00
+ gradient_appendStop 1 blue
+ gradient_setLinear 0 0 200 0
+ setPen brush
+
+ setFont "sansserif" 10 normal
+ drawStaticText 0 0 "gradient sansserif 10pt, normal"
+
+ setFont "sansserif" 12 normal
+ drawStaticText 0 20 "gradient sansserif 12pt, normal"
+
+ setFont "sansserif" 10 bold
+ drawStaticText 0 40 "gradient sansserif 12pt, bold"
+
+ setFont "sansserif" 10 bold italic
+ drawStaticText 0 60 "gradient sansserif 10pt, bold italic"
+restore
+end_block
+
+translate 250 0
+drawStaticText 25 520 "clipped to rectangle"
+save
+ setPen #3f000000
+ setBrush nobrush
+ drawRect 20 0 100 500
+ setClipRect 20 0 100 500
+ setPen black
+ repeat_block text_drawing
+restore
+
+translate 150 0
+drawStaticText 25 520 "clipped to path"
+save
+ path_moveTo clip 20 0
+ path_cubicTo clip 0 200 40 400 20 400
+ path_lineTo clip 30 500
+ path_lineTo clip 30 0
+ path_lineTo clip 40 0
+ path_lineTo clip 40 500
+ path_lineTo clip 120 500
+ path_lineTo clip 120 0
+ path_lineTo clip 20 0
+ setPen #3f000000
+ setBrush nobrush
+ drawPath clip
+ setClipPath clip
+ setPen black
+ repeat_block text_drawing
+restore
diff --git a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp
index 9b7b228..4f3b56f 100644
--- a/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp
+++ b/tests/auto/qgraphicsitem/tst_qgraphicsitem.cpp
@@ -6413,6 +6413,7 @@ void tst_QGraphicsItem::boundingRegion_data()
QTest::newRow("(0, 0, 10, 10) | 0.0 | identity | {(0, 0, 10, 10)}") << QLineF(0, 0, 10, 10) << qreal(0.0) << QTransform()
<< QRegion(QRect(0, 0, 10, 10));
+#if 0
{
QRegion r;
r += QRect(0, 0, 6, 2);
@@ -6430,6 +6431,7 @@ void tst_QGraphicsItem::boundingRegion_data()
r += QRect(6, 9, 4, 1);
QTest::newRow("(0, 0, 10, 10) | 1.0 | identity | {(0, 0, 10, 10)}") << QLineF(0, 0, 10, 10) << qreal(1.0) << QTransform() << r;
}
+#endif
QTest::newRow("(0, 0, 10, 0) | 0.0 | identity | {(0, 0, 10, 10)}") << QLineF(0, 0, 10, 0) << qreal(0.0) << QTransform()
<< QRegion(QRect(0, 0, 10, 1));
QTest::newRow("(0, 0, 10, 0) | 0.5 | identity | {(0, 0, 10, 1)}") << QLineF(0, 0, 10, 0) << qreal(0.5) << QTransform()
diff --git a/tests/auto/qpainter/tst_qpainter.cpp b/tests/auto/qpainter/tst_qpainter.cpp
index 501074f..948d14a 100644
--- a/tests/auto/qpainter/tst_qpainter.cpp
+++ b/tests/auto/qpainter/tst_qpainter.cpp
@@ -1315,7 +1315,7 @@ void tst_QPainter::drawRect2()
p.end();
QRect stroke = getPaintedSize(image, Qt::white);
- QCOMPARE(stroke, fill.adjusted(0, 0, 1, 1));
+ QCOMPARE(stroke.adjusted(1, 1, 0, 0), fill.adjusted(0, 0, 1, 1));
}
}
@@ -1412,13 +1412,13 @@ void tst_QPainter::drawPath_data()
{
QPainterPath p;
p.addRect(2.25, 2.25, 10, 10);
- QTest::newRow("non-aligned rect") << p << QRect(2, 2, 10, 10) << 10 * 10;
+ QTest::newRow("non-aligned rect") << p << QRect(3, 3, 10, 10) << 10 * 10;
}
{
QPainterPath p;
p.addRect(2.25, 2.25, 10.5, 10.5);
- QTest::newRow("non-aligned rect 2") << p << QRect(2, 2, 11, 11) << 11 * 11;
+ QTest::newRow("non-aligned rect 2") << p << QRect(3, 3, 10, 10) << 10 * 10;
}
{
diff --git a/tests/auto/qstatictext/tst_qstatictext.cpp b/tests/auto/qstatictext/tst_qstatictext.cpp
index 29845d9..e14c9db 100644
--- a/tests/auto/qstatictext/tst_qstatictext.cpp
+++ b/tests/auto/qstatictext/tst_qstatictext.cpp
@@ -361,7 +361,7 @@ bool tst_QStaticText::supportsTransformations() const
QPaintEngine::Type type = engine->type();
if (type == QPaintEngine::OpenGL
-#if !defined(Q_WS_WIN) && !defined(Q_WS_X11)
+#if !defined(Q_WS_WIN) && !defined(Q_WS_X11) && !defined(Q_WS_MAC)
|| type == QPaintEngine::Raster
#endif
)
@@ -601,7 +601,7 @@ void tst_QStaticText::setPenPlainText()
QStaticText staticText("XXXXX");
staticText.setTextFormat(Qt::PlainText);
- p.drawStaticText(0, fm.ascent(), staticText);
+ p.drawStaticText(0, 0, staticText);
}
QImage img = image.toImage();
diff --git a/tests/auto/qtextlayout/tst_qtextlayout.cpp b/tests/auto/qtextlayout/tst_qtextlayout.cpp
index b6adc2b..2414ab3 100644
--- a/tests/auto/qtextlayout/tst_qtextlayout.cpp
+++ b/tests/auto/qtextlayout/tst_qtextlayout.cpp
@@ -127,6 +127,8 @@ private slots:
void textWithSurrogates_qtbug15679();
void textWidthWithStackedTextEngine();
void textWidthWithLineSeparator();
+ void cursorInLigatureWithMultipleLines();
+ void xToCursorForLigatures();
private:
QFont testFont;
@@ -1460,5 +1462,45 @@ void tst_QTextLayout::textWidthWithLineSeparator()
QCOMPARE(line1.naturalTextWidth(), line2.naturalTextWidth());
}
+void tst_QTextLayout::cursorInLigatureWithMultipleLines()
+{
+#if !defined(Q_WS_MAC)
+ QSKIP("This test can not be run on Mac", SkipAll);
+#endif
+ QTextLayout layout("first line finish", QFont("Times", 20));
+ layout.beginLayout();
+ QTextLine line = layout.createLine();
+ line.setLineWidth(70);
+ line = layout.createLine();
+ layout.endLayout();
+
+ // The second line will be "finish", with "fi" as a ligature
+ QVERIFY(line.cursorToX(0) != line.cursorToX(1));
+}
+
+void tst_QTextLayout::xToCursorForLigatures()
+{
+#if !defined(Q_WS_MAC)
+ QSKIP("This test can not be run on Mac", SkipAll);
+#endif
+ QTextLayout layout("fi", QFont("Times", 20));
+ layout.beginLayout();
+ QTextLine line = layout.createLine();
+ layout.endLayout();
+
+ QVERIFY(line.xToCursor(0) != line.xToCursor(line.naturalTextWidth() / 2));
+
+ // U+0061 U+0308
+ QTextLayout layout2(QString::fromUtf8("\x61\xCC\x88"), QFont("Times", 20));
+
+ layout2.beginLayout();
+ line = layout2.createLine();
+ layout2.endLayout();
+
+ qreal width = line.naturalTextWidth();
+ QVERIFY(line.xToCursor(0) == line.xToCursor(width / 2) ||
+ line.xToCursor(width) == line.xToCursor(width / 2));
+}
+
QTEST_MAIN(tst_QTextLayout)
#include "tst_qtextlayout.moc"