summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorQt Continuous Integration System <qt-info@nokia.com>2011-04-22 09:24:06 (GMT)
committerQt Continuous Integration System <qt-info@nokia.com>2011-04-22 09:24:06 (GMT)
commitd805cf6f5fe4961093a0698ae6df18400536d2e0 (patch)
tree470839793de2567fd8b085f198edd0d72126fc38
parentd044c182edda4379e07b7f693d3c14f815fd3842 (diff)
parent1a1683c2d57debbb3e7f3ae6001eb2c8685dca02 (diff)
downloadQt-d805cf6f5fe4961093a0698ae6df18400536d2e0.zip
Qt-d805cf6f5fe4961093a0698ae6df18400536d2e0.tar.gz
Qt-d805cf6f5fe4961093a0698ae6df18400536d2e0.tar.bz2
Merge branch 'master' of git://scm.dev.nokia.troll.no/qt/qt-fire-team
* 'master' of git://scm.dev.nokia.troll.no/qt/qt-fire-team: (25 commits) doc: Simplify language in QGlyphs docs doc: Minor cleanup in QGlyphs docs Remove extra comma at the end of enum list Fix compilation with Qt3Support Don't transform glyph positions for Core Graphics paint engine Skip linearGradientSymmetry test on QWS. Turn on HarfBuzz support for Mac/Cocoa Support visual cursor movement for BIDI text Disable tst_QPixmap::onlyNullPixmapsOutsideGuiThread on Mac Revert "Switch the default graphics system to raster on Mac." Fix an race condition in the auto test. Made linearGradientSymmetry test pass on qreal=float platforms. Make sure #ifdef'd tests still have main() function Long live QRawFont! Fix an race condition in the auto test. Another attempt at fixing the MSVC2005 build. Compile fix in qdrawhelper_sse2.cpp for MSVC 2005. Compile fix in qdrawhelper_sse2.cpp. Added support for six-parameter radial gradients. Improved gradient table generation performance for two-stop gradients. ...
-rwxr-xr-xconfigure16
-rw-r--r--src/corelib/global/qglobal.h6
-rw-r--r--src/gui/kernel/qwidget.cpp1
-rw-r--r--src/gui/painting/qbrush.cpp191
-rw-r--r--src/gui/painting/qbrush.h12
-rw-r--r--src/gui/painting/qdrawhelper.cpp238
-rw-r--r--src/gui/painting/qdrawhelper_neon.cpp40
-rw-r--r--src/gui/painting/qdrawhelper_p.h258
-rw-r--r--src/gui/painting/qdrawhelper_sse2.cpp52
-rw-r--r--src/gui/painting/qpaintbuffer.cpp23
-rw-r--r--src/gui/painting/qpaintengine_mac.cpp3
-rw-r--r--src/gui/painting/qpaintengine_raster.cpp81
-rw-r--r--src/gui/painting/qpaintengineex.cpp46
-rw-r--r--src/gui/painting/qpainter.cpp73
-rw-r--r--src/gui/painting/qpainter.h3
-rw-r--r--src/gui/painting/qpainter_p.h10
-rw-r--r--src/gui/painting/qunifiedtoolbarsurface_mac.cpp3
-rw-r--r--src/gui/text/qfont.cpp26
-rw-r--r--src/gui/text/qfont_win.cpp17
-rw-r--r--src/gui/text/qfontdatabase.cpp27
-rw-r--r--src/gui/text/qfontdatabase_mac.cpp7
-rw-r--r--src/gui/text/qfontdatabase_s60.cpp2
-rw-r--r--src/gui/text/qfontdatabase_win.cpp90
-rw-r--r--src/gui/text/qfontengine.cpp18
-rw-r--r--src/gui/text/qfontengine_coretext.mm316
-rw-r--r--src/gui/text/qfontengine_coretext_p.h27
-rw-r--r--src/gui/text/qfontengine_ft.cpp162
-rw-r--r--src/gui/text/qfontengine_ft_p.h15
-rw-r--r--src/gui/text/qfontengine_mac.mm21
-rw-r--r--src/gui/text/qfontengine_mac_p.h2
-rw-r--r--src/gui/text/qfontengine_p.h5
-rw-r--r--src/gui/text/qfontengine_x11_p.h1
-rw-r--r--src/gui/text/qfontenginedirectwrite.cpp54
-rw-r--r--src/gui/text/qfontenginedirectwrite_p.h11
-rw-r--r--src/gui/text/qglyphs.cpp99
-rw-r--r--src/gui/text/qglyphs.h19
-rw-r--r--src/gui/text/qglyphs_p.h25
-rw-r--r--src/gui/text/qrawfont.cpp612
-rw-r--r--src/gui/text/qrawfont.h140
-rw-r--r--src/gui/text/qrawfont_ft.cpp189
-rw-r--r--src/gui/text/qrawfont_mac.cpp105
-rw-r--r--src/gui/text/qrawfont_p.h132
-rw-r--r--src/gui/text/qrawfont_win.cpp750
-rw-r--r--src/gui/text/qtextcursor.cpp42
-rw-r--r--src/gui/text/qtextcursor.h4
-rw-r--r--src/gui/text/qtextdocument.cpp23
-rw-r--r--src/gui/text/qtextdocument.h5
-rw-r--r--src/gui/text/qtextdocument_p.cpp15
-rw-r--r--src/gui/text/qtextdocument_p.h4
-rw-r--r--src/gui/text/qtextengine.cpp331
-rw-r--r--src/gui/text/qtextengine_p.h60
-rw-r--r--src/gui/text/qtextlayout.cpp452
-rw-r--r--src/gui/text/qtextlayout.h11
-rw-r--r--src/gui/text/qtextobject.cpp2
-rw-r--r--src/gui/text/qtextobject.h2
-rw-r--r--src/gui/text/text.pri25
-rw-r--r--src/gui/widgets/qlinecontrol.cpp9
-rw-r--r--src/gui/widgets/qlinecontrol_p.h8
-rw-r--r--src/gui/widgets/qlineedit.cpp28
-rw-r--r--src/gui/widgets/qlineedit.h4
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager.cpp2
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadermanager_p.h2
-rw-r--r--src/opengl/gl2paintengineex/qglengineshadersource_p.h18
-rw-r--r--src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp8
-rw-r--r--src/opengl/qpaintengine_opengl.cpp60
-rw-r--r--src/openvg/qpaintengine_vg.cpp111
-rw-r--r--src/qt3support/text/q3richtext.cpp1
-rw-r--r--tests/arthur/common/paintcommands.cpp34
-rw-r--r--tests/arthur/common/paintcommands.h1
-rw-r--r--tests/arthur/data/qps/radial_gradients_extended.qps95
-rw-r--r--tests/arthur/data/qps/radial_gradients_extended_qps.pngbin0 -> 107978 bytes
-rw-r--r--tests/auto/gui.pro1
-rw-r--r--tests/auto/qcomplextext/tst_qcomplextext.cpp87
-rw-r--r--tests/auto/qglyphs/tst_qglyphs.cpp21
-rw-r--r--tests/auto/qlineedit/tst_qlineedit.cpp136
-rw-r--r--tests/auto/qpainter/tst_qpainter.cpp43
-rw-r--r--tests/auto/qpixmap/tst_qpixmap.cpp4
-rw-r--r--tests/auto/qrawfont/qrawfont.pro13
-rw-r--r--tests/auto/qrawfont/testfont.ttfbin0 -> 63212 bytes
-rw-r--r--tests/auto/qrawfont/testfont_bold_italic.ttfbin0 -> 49760 bytes
-rw-r--r--tests/auto/qrawfont/tst_qrawfont.cpp814
-rw-r--r--tests/auto/qtextedit/tst_qtextedit.cpp149
-rw-r--r--tests/auto/qwizard/tst_qwizard.cpp13
83 files changed, 5624 insertions, 942 deletions
diff --git a/configure b/configure
index 99b79fc..9b923ab 100755
--- a/configure
+++ b/configure
@@ -804,6 +804,7 @@ CFG_MAC_XARCH=auto
CFG_MAC_CARBON=no
CFG_MAC_COCOA=yes
COMMANDLINE_MAC_CARBON=no
+CFG_MAC_HARFBUZZ=no
CFG_SXE=no
CFG_PREFIX_INSTALL=yes
CFG_SDK=
@@ -1040,7 +1041,7 @@ while [ "$#" -gt 0 ]; do
VAL=no
;;
#Qt style yes options
- -incremental|-qvfb|-profile|-shared|-static|-sm|-xinerama|-xshape|-xsync|-xinput|-egl|-reduce-exports|-pch|-separate-debug-info|-stl|-freetype|-xcursor|-xfixes|-xrandr|-xrender|-mitshm|-fontconfig|-xkb|-nis|-qdbus|-dbus|-dbus-linked|-glib|-gstreamer|-gtkstyle|-cups|-iconv|-largefile|-h|-help|-v|-verbose|-debug|-release|-fast|-accessibility|-confirm-license|-gnumake|-framework|-qt3support|-debug-and-release|-exceptions|-cocoa|-carbon|-universal|-prefix-install|-silent|-armfpa|-optimized-qmake|-dwarf2|-reduce-relocations|-sse|-openssl|-openssl-linked|-ptmalloc|-xmlpatterns|-phonon|-phonon-backend|-multimedia|-audio-backend|-svg|-declarative|-declarative-debug|-javascript-jit|-script|-scripttools|-rpath|-force-pkg-config|-s60|-usedeffiles)
+ -incremental|-qvfb|-profile|-shared|-static|-sm|-xinerama|-xshape|-xsync|-xinput|-egl|-reduce-exports|-pch|-separate-debug-info|-stl|-freetype|-xcursor|-xfixes|-xrandr|-xrender|-mitshm|-fontconfig|-xkb|-nis|-qdbus|-dbus|-dbus-linked|-glib|-gstreamer|-gtkstyle|-cups|-iconv|-largefile|-h|-help|-v|-verbose|-debug|-release|-fast|-accessibility|-confirm-license|-gnumake|-framework|-qt3support|-debug-and-release|-exceptions|-cocoa|-carbon|-universal|-harfbuzz|-prefix-install|-silent|-armfpa|-optimized-qmake|-dwarf2|-reduce-relocations|-sse|-openssl|-openssl-linked|-ptmalloc|-xmlpatterns|-phonon|-phonon-backend|-multimedia|-audio-backend|-svg|-declarative|-declarative-debug|-javascript-jit|-script|-scripttools|-rpath|-force-pkg-config|-s60|-usedeffiles)
VAR=`echo $1 | sed "s,^-\(.*\),\1,"`
VAL=yes
;;
@@ -1498,6 +1499,13 @@ while [ "$#" -gt 0 ]; do
UNKNOWN_OPT=yes
fi
;;
+ harfbuzz)
+ if [ "$PLATFORM_MAC" = "yes" ] && [ "$CFG_MAC_CARBON" != "yes" ] && [ "$VAL" = "yes" ]; then
+ CFG_MAC_HARFBUZZ="$VAL"
+ else
+ UNKNOWN_OPT=yes
+ fi
+ ;;
framework)
if [ "$PLATFORM_MAC" = "yes" ] || [ "$PLATFORM_QPA" = "yes" ]; then
@@ -4245,6 +4253,11 @@ Qt/Mac only:
-sdk <sdk> ......... Build Qt using Apple provided SDK <sdk>. This option requires gcc 4.
To use a different SDK with gcc 3.3, set the SDKROOT environment variable.
+ -harfbuzz .......... Use HarfBuzz to do text layout instead of Core Text when possible.
+ It is only available to Cocoa builds.
+ * -no-harfbuzz ....... Disable HarfBuzz on Mac. It can still be enabled by setting
+ QT_ENABLE_HARFBUZZ environment variable.
+
EOF
fi
@@ -7209,6 +7222,7 @@ fi
[ "$CFG_NAS" = "system" ] && QT_CONFIG="$QT_CONFIG nas"
[ "$CFG_OPENSSL" = "yes" ] && QT_CONFIG="$QT_CONFIG openssl"
[ "$CFG_OPENSSL" = "linked" ] && QT_CONFIG="$QT_CONFIG openssl-linked"
+[ "$CFG_MAC_HARFBUZZ" = "yes" ] && QT_CONFIG="$QT_CONFIG harfbuzz"
if [ "$PLATFORM_X11" = "yes" ]; then
[ "$CFG_SM" = "yes" ] && QT_CONFIG="$QT_CONFIG x11sm"
diff --git a/src/corelib/global/qglobal.h b/src/corelib/global/qglobal.h
index 7c5c354..d8ffd6d 100644
--- a/src/corelib/global/qglobal.h
+++ b/src/corelib/global/qglobal.h
@@ -2743,6 +2743,12 @@ QT_LICENSED_MODULE(DBus)
# endif
#endif
+#if !(defined(Q_WS_WIN) && !defined(Q_WS_WINCE)) \
+ && !(defined(Q_WS_MAC) && defined(QT_MAC_USE_COCOA)) \
+ && !(defined(Q_WS_X11) && !defined(QT_NO_FREETYPE))
+# define QT_NO_RAWFONT
+#endif
+
QT_END_NAMESPACE
QT_END_HEADER
diff --git a/src/gui/kernel/qwidget.cpp b/src/gui/kernel/qwidget.cpp
index 5705214..758ccce 100644
--- a/src/gui/kernel/qwidget.cpp
+++ b/src/gui/kernel/qwidget.cpp
@@ -1588,6 +1588,7 @@ QWidget::~QWidget()
// delete layout while we still are a valid widget
delete d->layout;
+ d->layout = 0;
// Remove myself from focus list
Q_ASSERT(d->focus_next->d_func()->focus_prev == this);
diff --git a/src/gui/painting/qbrush.cpp b/src/gui/painting/qbrush.cpp
index bf5764a..3ff7eb8 100644
--- a/src/gui/painting/qbrush.cpp
+++ b/src/gui/painting/qbrush.cpp
@@ -840,6 +840,22 @@ const QGradient *QBrush::gradient() const
return 0;
}
+Q_GUI_EXPORT bool qt_isExtendedRadialGradient(const QBrush &brush)
+{
+ if (brush.style() == Qt::RadialGradientPattern) {
+ const QGradient *g = brush.gradient();
+ const QRadialGradient *rg = static_cast<const QRadialGradient *>(g);
+
+ if (!qFuzzyIsNull(rg->focalRadius()))
+ return true;
+
+ QPointF delta = rg->focalPoint() - rg->center();
+ if (delta.x() * delta.x() + delta.y() * delta.y() > rg->radius() * rg->radius())
+ return true;
+ }
+
+ return false;
+}
/*!
Returns true if the brush is fully opaque otherwise false. A brush
@@ -849,6 +865,7 @@ const QGradient *QBrush::gradient() const
\i The alpha component of the color() is 255.
\i Its texture() does not have an alpha channel and is not a QBitmap.
\i The colors in the gradient() all have an alpha component that is 255.
+ \i It is an extended radial gradient.
\endlist
*/
@@ -860,6 +877,9 @@ bool QBrush::isOpaque() const
if (d->style == Qt::SolidPattern)
return opaqueColor;
+ if (qt_isExtendedRadialGradient(*this))
+ return false;
+
if (d->style == Qt::LinearGradientPattern
|| d->style == Qt::RadialGradientPattern
|| d->style == Qt::ConicalGradientPattern) {
@@ -1209,8 +1229,10 @@ QDataStream &operator>>(QDataStream &s, QBrush &b)
\list
\o \e Linear gradients interpolate colors between start and end points.
- \o \e Radial gradients interpolate colors between a focal point and end
- points on a circle surrounding it.
+ \o \e Simple radial gradients interpolate colors between a focal point
+ and end points on a circle surrounding it.
+ \o \e Extended radial gradients interpolate colors between a center and
+ a focal circle.
\o \e Conical gradients interpolate colors around a center point.
\endlist
@@ -1506,8 +1528,6 @@ void QGradient::setInterpolationMode(InterpolationMode mode)
dummy = p;
}
-#undef Q_DUMMY_ACCESSOR
-
/*!
\fn bool QGradient::operator!=(const QGradient &gradient) const
\since 4.2
@@ -1541,7 +1561,7 @@ bool QGradient::operator==(const QGradient &gradient) const
|| m_data.radial.cy != gradient.m_data.radial.cy
|| m_data.radial.fx != gradient.m_data.radial.fx
|| m_data.radial.fy != gradient.m_data.radial.fy
- || m_data.radial.radius != gradient.m_data.radial.radius)
+ || m_data.radial.cradius != gradient.m_data.radial.cradius)
return false;
} else { // m_type == ConicalGradient
if (m_data.conical.cx != gradient.m_data.conical.cx
@@ -1747,10 +1767,17 @@ void QLinearGradient::setFinalStop(const QPointF &stop)
\brief The QRadialGradient class is used in combination with QBrush to
specify a radial gradient brush.
- Radial gradients interpolate colors between a focal point and end
- points on a circle surrounding it. Outside the end points the
- gradient is either padded, reflected or repeated depending on the
- currently set \l {QGradient::Spread}{spread} method:
+ Qt supports both simple and extended radial gradients.
+
+ Simple radial gradients interpolate colors between a focal point and end
+ points on a circle surrounding it. Extended radial gradients interpolate
+ colors between a focal circle and a center circle. Points outside the cone
+ defined by the two circles will be transparent. For simple radial gradients
+ the focal point is adjusted to lie inside the center circle, whereas the
+ focal point can have any position in an extended radial gradient.
+
+ Outside the end points the gradient is either padded, reflected or repeated
+ depending on the currently set \l {QGradient::Spread}{spread} method:
\table
\row
@@ -1795,9 +1822,14 @@ static QPointF qt_radial_gradient_adapt_focal_point(const QPointF &center,
}
/*!
- Constructs a radial gradient with the given \a center, \a
+ Constructs a simple radial gradient with the given \a center, \a
radius and \a focalPoint.
+ \note If the given focal point is outside the circle defined by the
+ center (\a cx, \a cy) and the \a radius it will be re-adjusted to
+ the intersection between the line from the center to the focal point
+ and the circle.
+
\sa QGradient::setColorAt(), QGradient::setStops()
*/
@@ -1807,7 +1839,7 @@ QRadialGradient::QRadialGradient(const QPointF &center, qreal radius, const QPoi
m_spread = PadSpread;
m_data.radial.cx = center.x();
m_data.radial.cy = center.y();
- m_data.radial.radius = radius;
+ m_data.radial.cradius = radius;
QPointF adapted_focal = qt_radial_gradient_adapt_focal_point(center, radius, focalPoint);
m_data.radial.fx = adapted_focal.x();
@@ -1815,7 +1847,7 @@ QRadialGradient::QRadialGradient(const QPointF &center, qreal radius, const QPoi
}
/*!
- Constructs a radial gradient with the given \a center, \a
+ Constructs a simple radial gradient with the given \a center, \a
radius and the focal point in the circle center.
\sa QGradient::setColorAt(), QGradient::setStops()
@@ -1826,16 +1858,21 @@ QRadialGradient::QRadialGradient(const QPointF &center, qreal radius)
m_spread = PadSpread;
m_data.radial.cx = center.x();
m_data.radial.cy = center.y();
- m_data.radial.radius = radius;
+ m_data.radial.cradius = radius;
m_data.radial.fx = center.x();
m_data.radial.fy = center.y();
}
/*!
- Constructs a radial gradient with the given center (\a cx, \a cy),
+ Constructs a simple radial gradient with the given center (\a cx, \a cy),
\a radius and focal point (\a fx, \a fy).
+ \note If the given focal point is outside the circle defined by the
+ center (\a cx, \a cy) and the \a radius it will be re-adjusted to
+ the intersection between the line from the center to the focal point
+ and the circle.
+
\sa QGradient::setColorAt(), QGradient::setStops()
*/
@@ -1845,7 +1882,7 @@ QRadialGradient::QRadialGradient(qreal cx, qreal cy, qreal radius, qreal fx, qre
m_spread = PadSpread;
m_data.radial.cx = cx;
m_data.radial.cy = cy;
- m_data.radial.radius = radius;
+ m_data.radial.cradius = radius;
QPointF adapted_focal = qt_radial_gradient_adapt_focal_point(QPointF(cx, cy),
radius,
@@ -1856,7 +1893,7 @@ QRadialGradient::QRadialGradient(qreal cx, qreal cy, qreal radius, qreal fx, qre
}
/*!
- Constructs a radial gradient with the center at (\a cx, \a cy) and the
+ Constructs a simple radial gradient with the center at (\a cx, \a cy) and the
specified \a radius. The focal point lies at the center of the circle.
\sa QGradient::setColorAt(), QGradient::setStops()
@@ -1867,14 +1904,14 @@ QRadialGradient::QRadialGradient(qreal cx, qreal cy, qreal radius)
m_spread = PadSpread;
m_data.radial.cx = cx;
m_data.radial.cy = cy;
- m_data.radial.radius = radius;
+ m_data.radial.cradius = radius;
m_data.radial.fx = cx;
m_data.radial.fy = cy;
}
/*!
- Constructs a radial gradient with the center and focal point at
+ Constructs a simple radial gradient with the center and focal point at
(0, 0) with a radius of 1.
*/
QRadialGradient::QRadialGradient()
@@ -1883,11 +1920,51 @@ QRadialGradient::QRadialGradient()
m_spread = PadSpread;
m_data.radial.cx = 0;
m_data.radial.cy = 0;
- m_data.radial.radius = 1;
+ m_data.radial.cradius = 1;
m_data.radial.fx = 0;
m_data.radial.fy = 0;
}
+/*!
+ \since 4.8
+
+ Constructs an extended radial gradient with the given \a center, \a
+ centerRadius, \a focalPoint, and \a focalRadius.
+*/
+QRadialGradient::QRadialGradient(const QPointF &center, qreal centerRadius, const QPointF &focalPoint, qreal focalRadius)
+{
+ m_type = RadialGradient;
+ m_spread = PadSpread;
+ m_data.radial.cx = center.x();
+ m_data.radial.cy = center.y();
+ m_data.radial.cradius = centerRadius;
+
+ m_data.radial.fx = focalPoint.x();
+ m_data.radial.fy = focalPoint.y();
+ setFocalRadius(focalRadius);
+}
+
+/*!
+ \since 4.8
+
+ Constructs an extended radial gradient with the given \a center, \a
+ centerRadius, \a focalPoint, and \a focalRadius.
+ Constructs a radial gradient with the given center (\a cx, \a cy),
+ center radius \a centerRadius, focal point (\a fx, \a fy), and
+ focal radius \a focalRadius.
+*/
+QRadialGradient::QRadialGradient(qreal cx, qreal cy, qreal centerRadius, qreal fx, qreal fy, qreal focalRadius)
+{
+ m_type = RadialGradient;
+ m_spread = PadSpread;
+ m_data.radial.cx = cx;
+ m_data.radial.cy = cy;
+ m_data.radial.cradius = centerRadius;
+
+ m_data.radial.fx = fx;
+ m_data.radial.fy = fy;
+ setFocalRadius(focalRadius);
+}
/*!
Returns the center of this radial gradient in logical coordinates.
@@ -1932,13 +2009,15 @@ void QRadialGradient::setCenter(const QPointF &center)
/*!
Returns the radius of this radial gradient in logical coordinates.
+ Equivalent to centerRadius()
+
\sa QGradient::stops()
*/
qreal QRadialGradient::radius() const
{
Q_ASSERT(m_type == RadialGradient);
- return m_data.radial.radius;
+ return m_data.radial.cradius;
}
@@ -1947,13 +2026,81 @@ qreal QRadialGradient::radius() const
Sets the radius of this radial gradient in logical coordinates
to \a radius
+
+ Equivalent to setCenterRadius()
*/
void QRadialGradient::setRadius(qreal radius)
{
Q_ASSERT(m_type == RadialGradient);
- m_data.radial.radius = radius;
+ m_data.radial.cradius = radius;
+}
+
+/*!
+ \since 4.8
+
+ Returns the center radius of this radial gradient in logical
+ coordinates.
+
+ \sa QGradient::stops()
+*/
+qreal QRadialGradient::centerRadius() const
+{
+ Q_ASSERT(m_type == RadialGradient);
+ return m_data.radial.cradius;
+}
+
+/*
+ \since 4.8
+
+ Sets the center radius of this radial gradient in logical coordinates
+ to \a radius
+*/
+void QRadialGradient::setCenterRadius(qreal radius)
+{
+ Q_ASSERT(m_type == RadialGradient);
+ m_data.radial.cradius = radius;
+}
+
+/*!
+ \since 4.8
+
+ Returns the focal radius of this radial gradient in logical
+ coordinates.
+
+ \sa QGradient::stops()
+*/
+qreal QRadialGradient::focalRadius() const
+{
+ Q_ASSERT(m_type == RadialGradient);
+ Q_DUMMY_ACCESSOR
+
+ // mask away low three bits
+ union { float f; quint32 i; } u;
+ u.i = i & ~0x07;
+ return u.f;
}
+/*
+ \since 4.8
+
+ Sets the focal radius of this radial gradient in logical coordinates
+ to \a radius
+*/
+void QRadialGradient::setFocalRadius(qreal radius)
+{
+ Q_ASSERT(m_type == RadialGradient);
+ Q_DUMMY_ACCESSOR
+
+ // Since there's no QGradientData, we only have the dummy void * to
+ // store additional data in. The three lowest bits are already
+ // taken, thus we cut the three lowest bits from the significand
+ // and store the radius as a float.
+ union { float f; quint32 i; } u;
+ u.f = float(radius);
+ // add 0x04 to round up when we drop the three lowest bits
+ i |= (u.i + 0x04) & ~0x07;
+ dummy = p;
+}
/*!
Returns the focal point of this radial gradient in logical
@@ -2193,4 +2340,6 @@ void QConicalGradient::setAngle(qreal angle)
\sa setTransform()
*/
+#undef Q_DUMMY_ACCESSOR
+
QT_END_NAMESPACE
diff --git a/src/gui/painting/qbrush.h b/src/gui/painting/qbrush.h
index 8b31319..d914c8c 100644
--- a/src/gui/painting/qbrush.h
+++ b/src/gui/painting/qbrush.h
@@ -255,6 +255,7 @@ private:
friend class QLinearGradient;
friend class QRadialGradient;
friend class QConicalGradient;
+ friend class QBrush;
Type m_type;
Spread m_spread;
@@ -264,7 +265,7 @@ private:
qreal x1, y1, x2, y2;
} linear;
struct {
- qreal cx, cy, fx, fy, radius;
+ qreal cx, cy, fx, fy, cradius;
} radial;
struct {
qreal cx, cy, angle;
@@ -303,6 +304,9 @@ public:
QRadialGradient(const QPointF &center, qreal radius);
QRadialGradient(qreal cx, qreal cy, qreal radius);
+ QRadialGradient(const QPointF &center, qreal centerRadius, const QPointF &focalPoint, qreal focalRadius);
+ QRadialGradient(qreal cx, qreal cy, qreal centerRadius, qreal fx, qreal fy, qreal focalRadius);
+
QPointF center() const;
void setCenter(const QPointF &center);
inline void setCenter(qreal x, qreal y) { setCenter(QPointF(x, y)); }
@@ -313,6 +317,12 @@ public:
qreal radius() const;
void setRadius(qreal radius);
+
+ qreal centerRadius() const;
+ void setCenterRadius(qreal radius);
+
+ qreal focalRadius() const;
+ void setFocalRadius(qreal radius);
};
diff --git a/src/gui/painting/qdrawhelper.cpp b/src/gui/painting/qdrawhelper.cpp
index 5e75e4a..ae9993e 100644
--- a/src/gui/painting/qdrawhelper.cpp
+++ b/src/gui/painting/qdrawhelper.cpp
@@ -75,43 +75,9 @@ enum {
fixed_scale = 1 << 16,
half_point = 1 << 15
};
-static const int buffer_size = 2048;
-
-struct LinearGradientValues
-{
- qreal dx;
- qreal dy;
- qreal l;
- qreal off;
-};
-
-struct RadialGradientValues
-{
- qreal dx;
- qreal dy;
- qreal a;
-};
-
-struct Operator;
-typedef uint* (QT_FASTCALL *DestFetchProc)(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length);
-typedef void (QT_FASTCALL *DestStoreProc)(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length);
-typedef const uint* (QT_FASTCALL *SourceFetchProc)(uint *buffer, const Operator *o, const QSpanData *data, int y, int x, int length);
-
-struct Operator
-{
- QPainter::CompositionMode mode;
- DestFetchProc dest_fetch;
- DestStoreProc dest_store;
- SourceFetchProc src_fetch;
- CompositionFunctionSolid funcSolid;
- CompositionFunction func;
- union {
- LinearGradientValues linear;
- RadialGradientValues radial;
-// TextureValues texture;
- };
-};
+// must be multiple of 4 for easier SIMD implementations
+static const int buffer_size = 2048;
/*
Destination fetch. This is simple as we don't have to do bounds checks or
@@ -1346,64 +1312,13 @@ static const SourceFetchProc sourceFetch[NBlendTypes][QImage::NImageFormats] = {
},
};
-
-static inline uint qt_gradient_pixel(const QGradientData *data, qreal pos)
-{
- int ipos = int(pos * (GRADIENT_STOPTABLE_SIZE - 1) + qreal(0.5));
-
- // calculate the actual offset.
- if (ipos < 0 || ipos >= GRADIENT_STOPTABLE_SIZE) {
- if (data->spread == QGradient::RepeatSpread) {
- ipos = ipos % GRADIENT_STOPTABLE_SIZE;
- ipos = ipos < 0 ? GRADIENT_STOPTABLE_SIZE + ipos : ipos;
-
- } else if (data->spread == QGradient::ReflectSpread) {
- const int limit = GRADIENT_STOPTABLE_SIZE * 2 - 1;
- ipos = ipos % limit;
- ipos = ipos < 0 ? limit + ipos : ipos;
- ipos = ipos >= GRADIENT_STOPTABLE_SIZE ? limit - ipos : ipos;
-
- } else {
- if (ipos < 0) ipos = 0;
- else if (ipos >= GRADIENT_STOPTABLE_SIZE) ipos = GRADIENT_STOPTABLE_SIZE-1;
- }
- }
-
- Q_ASSERT(ipos >= 0);
- Q_ASSERT(ipos < GRADIENT_STOPTABLE_SIZE);
-
- return data->colorTable[ipos];
-}
-
#define FIXPT_BITS 8
#define FIXPT_SIZE (1<<FIXPT_BITS)
static uint qt_gradient_pixel_fixed(const QGradientData *data, int fixed_pos)
{
int ipos = (fixed_pos + (FIXPT_SIZE / 2)) >> FIXPT_BITS;
-
- // calculate the actual offset.
- if (ipos < 0 || ipos >= GRADIENT_STOPTABLE_SIZE) {
- if (data->spread == QGradient::RepeatSpread) {
- ipos = ipos % GRADIENT_STOPTABLE_SIZE;
- ipos = ipos < 0 ? GRADIENT_STOPTABLE_SIZE + ipos : ipos;
-
- } else if (data->spread == QGradient::ReflectSpread) {
- const int limit = GRADIENT_STOPTABLE_SIZE * 2 - 1;
- ipos = ipos % limit;
- ipos = ipos < 0 ? limit + ipos : ipos;
- ipos = ipos >= GRADIENT_STOPTABLE_SIZE ? limit - ipos : ipos;
-
- } else {
- if (ipos < 0) ipos = 0;
- else if (ipos >= GRADIENT_STOPTABLE_SIZE) ipos = GRADIENT_STOPTABLE_SIZE-1;
- }
- }
-
- Q_ASSERT(ipos >= 0);
- Q_ASSERT(ipos < GRADIENT_STOPTABLE_SIZE);
-
- return data->colorTable[ipos];
+ return data->colorTable[qt_gradient_clamp(data, ipos)];
}
static void QT_FASTCALL getLinearGradientValues(LinearGradientValues *v, const QSpanData *data)
@@ -1419,8 +1334,8 @@ static void QT_FASTCALL getLinearGradientValues(LinearGradientValues *v, const Q
}
}
-static const uint * QT_FASTCALL fetchLinearGradient(uint *buffer, const Operator *op, const QSpanData *data,
- int y, int x, int length)
+static const uint * QT_FASTCALL qt_fetch_linear_gradient(uint *buffer, const Operator *op, const QSpanData *data,
+ int y, int x, int length)
{
const uint *b = buffer;
qreal t, inc;
@@ -1487,110 +1402,65 @@ static const uint * QT_FASTCALL fetchLinearGradient(uint *buffer, const Operator
return b;
}
-static inline qreal determinant(qreal a, qreal b, qreal c)
-{
- return (b * b) - (4 * a * c);
-}
-
-// function to evaluate real roots
-static inline qreal realRoots(qreal a, qreal b, qreal detSqrt)
-{
- return (-b + detSqrt)/(2 * a);
-}
-
-static inline qreal qSafeSqrt(qreal x)
-{
- return x > 0 ? qSqrt(x) : 0;
-}
-
static void QT_FASTCALL getRadialGradientValues(RadialGradientValues *v, const QSpanData *data)
{
v->dx = data->gradient.radial.center.x - data->gradient.radial.focal.x;
v->dy = data->gradient.radial.center.y - data->gradient.radial.focal.y;
- v->a = data->gradient.radial.radius*data->gradient.radial.radius - v->dx*v->dx - v->dy*v->dy;
-}
-
-static const uint * QT_FASTCALL fetchRadialGradient(uint *buffer, const Operator *op, const QSpanData *data,
- int y, int x, int length)
-{
- const uint *b = buffer;
- qreal rx = data->m21 * (y + qreal(0.5))
- + data->dx + data->m11 * (x + qreal(0.5));
- qreal ry = data->m22 * (y + qreal(0.5))
- + data->dy + data->m12 * (x + qreal(0.5));
- bool affine = !data->m13 && !data->m23;
- //qreal r = data->gradient.radial.radius;
-
- const uint *end = buffer + length;
- if (affine) {
- rx -= data->gradient.radial.focal.x;
- ry -= data->gradient.radial.focal.y;
-
- qreal inv_a = 1 / qreal(2 * op->radial.a);
-
- const qreal delta_rx = data->m11;
- const qreal delta_ry = data->m12;
- qreal b = 2*(rx * op->radial.dx + ry * op->radial.dy);
- qreal delta_b = 2*(delta_rx * op->radial.dx + delta_ry * op->radial.dy);
- const qreal b_delta_b = 2 * b * delta_b;
- const qreal delta_b_delta_b = 2 * delta_b * delta_b;
+ v->dr = data->gradient.radial.center.radius - data->gradient.radial.focal.radius;
+ v->sqrfr = data->gradient.radial.focal.radius * data->gradient.radial.focal.radius;
- const qreal bb = b * b;
- const qreal delta_bb = delta_b * delta_b;
+ v->a = v->dr * v->dr - v->dx*v->dx - v->dy*v->dy;
+ v->inv2a = 1 / (2 * v->a);
- b *= inv_a;
- delta_b *= inv_a;
-
- const qreal rxrxryry = rx * rx + ry * ry;
- const qreal delta_rxrxryry = delta_rx * delta_rx + delta_ry * delta_ry;
- const qreal rx_plus_ry = 2*(rx * delta_rx + ry * delta_ry);
- const qreal delta_rx_plus_ry = 2 * delta_rxrxryry;
-
- inv_a *= inv_a;
+ v->extended = !qFuzzyIsNull(data->gradient.radial.focal.radius) || v->a <= 0;
+}
- qreal det = (bb + 4 * op->radial.a * rxrxryry) * inv_a;
- qreal delta_det = (b_delta_b + delta_bb + 4 * op->radial.a * (rx_plus_ry + delta_rxrxryry)) * inv_a;
- const qreal delta_delta_det = (delta_b_delta_b + 4 * op->radial.a * delta_rx_plus_ry) * inv_a;
+class RadialFetchPlain
+{
+public:
+ static inline void fetch(uint *buffer, uint *end, const Operator *op, const QSpanData *data, qreal det,
+ qreal delta_det, qreal delta_delta_det, qreal b, qreal delta_b)
+ {
+ if (op->radial.extended) {
+ while (buffer < end) {
+ quint32 result = 0;
+ if (det >= 0) {
+ qreal w = qSqrt(det) - b;
+ if (data->gradient.radial.focal.radius + op->radial.dr * w >= 0)
+ result = qt_gradient_pixel(&data->gradient, w);
+ }
- while (buffer < end) {
- *buffer = qt_gradient_pixel(&data->gradient, qSafeSqrt(det) - b);
+ *buffer = result;
- det += delta_det;
- delta_det += delta_delta_det;
- b += delta_b;
+ det += delta_det;
+ delta_det += delta_delta_det;
+ b += delta_b;
- ++buffer;
- }
- } else {
- qreal rw = data->m23 * (y + qreal(0.5))
- + data->m33 + data->m13 * (x + qreal(0.5));
- if (!rw)
- rw = 1;
- while (buffer < end) {
- qreal gx = rx/rw - data->gradient.radial.focal.x;
- qreal gy = ry/rw - data->gradient.radial.focal.y;
- qreal b = 2*(gx*op->radial.dx + gy*op->radial.dy);
- qreal det = determinant(op->radial.a, b , -(gx*gx + gy*gy));
- qreal s = realRoots(op->radial.a, b, qSafeSqrt(det));
-
- *buffer = qt_gradient_pixel(&data->gradient, s);
+ ++buffer;
+ }
+ } else {
+ while (buffer < end) {
+ *buffer++ = qt_gradient_pixel(&data->gradient, qSqrt(det) - b);
- rx += data->m11;
- ry += data->m12;
- rw += data->m13;
- if (!rw) {
- rw += data->m13;
+ det += delta_det;
+ delta_det += delta_delta_det;
+ b += delta_b;
}
- ++buffer;
}
}
+};
- return b;
+const uint * QT_FASTCALL qt_fetch_radial_gradient_plain(uint *buffer, const Operator *op, const QSpanData *data,
+ int y, int x, int length)
+{
+ return qt_fetch_radial_gradient_template<RadialFetchPlain>(buffer, op, data, y, x, length);
}
-static const uint * QT_FASTCALL fetchConicalGradient(uint *buffer, const Operator *, const QSpanData *data,
- int y, int x, int length)
+static SourceFetchProc qt_fetch_radial_gradient = qt_fetch_radial_gradient_plain;
+
+static const uint * QT_FASTCALL qt_fetch_conical_gradient(uint *buffer, const Operator *, const QSpanData *data,
+ int y, int x, int length)
{
const uint *b = buffer;
qreal rx = data->m21 * (y + qreal(0.5))
@@ -3347,16 +3217,16 @@ static inline Operator getOperator(const QSpanData *data, const QSpan *spans, in
case QSpanData::LinearGradient:
solidSource = !data->gradient.alphaColor;
getLinearGradientValues(&op.linear, data);
- op.src_fetch = fetchLinearGradient;
+ op.src_fetch = qt_fetch_linear_gradient;
break;
case QSpanData::RadialGradient:
solidSource = !data->gradient.alphaColor;
getRadialGradientValues(&op.radial, data);
- op.src_fetch = fetchRadialGradient;
+ op.src_fetch = qt_fetch_radial_gradient;
break;
case QSpanData::ConicalGradient:
solidSource = !data->gradient.alphaColor;
- op.src_fetch = fetchConicalGradient;
+ op.src_fetch = qt_fetch_conical_gradient;
break;
case QSpanData::Texture:
op.src_fetch = sourceFetch[getBlendType(data)][data->texture.format];
@@ -7888,6 +7758,11 @@ void qInitDrawhelperAsm()
qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_RGB32] = qt_blend_rgb32_on_rgb32_sse2;
qBlendFunctions[QImage::Format_RGB32][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2;
qBlendFunctions[QImage::Format_ARGB32_Premultiplied][QImage::Format_ARGB32_Premultiplied] = qt_blend_argb32_on_argb32_sse2;
+
+ extern const uint * QT_FASTCALL qt_fetch_radial_gradient_sse2(uint *buffer, const Operator *op, const QSpanData *data,
+ int y, int x, int length);
+
+ qt_fetch_radial_gradient = qt_fetch_radial_gradient_sse2;
}
#ifdef QT_HAVE_SSSE3
@@ -7983,6 +7858,11 @@ void qInitDrawhelperAsm()
qMemRotateFunctions[QImage::Format_RGB16][0] = qt_memrotate90_16_neon;
qMemRotateFunctions[QImage::Format_RGB16][2] = qt_memrotate270_16_neon;
qt_memfill32 = qt_memfill32_neon;
+
+ extern const uint * QT_FASTCALL qt_fetch_radial_gradient_neon(uint *buffer, const Operator *op, const QSpanData *data,
+ int y, int x, int length);
+
+ qt_fetch_radial_gradient = qt_fetch_radial_gradient_neon;
}
#endif
diff --git a/src/gui/painting/qdrawhelper_neon.cpp b/src/gui/painting/qdrawhelper_neon.cpp
index debca37..e673dd9 100644
--- a/src/gui/painting/qdrawhelper_neon.cpp
+++ b/src/gui/painting/qdrawhelper_neon.cpp
@@ -955,6 +955,46 @@ void qt_memrotate270_16_neon(const uchar *srcPixels, int w, int h,
}
}
+class QSimdNeon
+{
+public:
+ typedef int32x4_t Int32x4;
+ typedef float32x4_t Float32x4;
+
+ union Vect_buffer_i { Int32x4 v; int i[4]; };
+ union Vect_buffer_f { Float32x4 v; float f[4]; };
+
+ static inline Float32x4 v_dup(float x) { return vdupq_n_f32(x); }
+ static inline Int32x4 v_dup(int x) { return vdupq_n_s32(x); }
+ static inline Int32x4 v_dup(uint x) { return vdupq_n_s32(x); }
+
+ static inline Float32x4 v_add(Float32x4 a, Float32x4 b) { return vaddq_f32(a, b); }
+ static inline Int32x4 v_add(Int32x4 a, Int32x4 b) { return vaddq_s32(a, b); }
+
+ static inline Float32x4 v_max(Float32x4 a, Float32x4 b) { return vmaxq_f32(a, b); }
+ static inline Float32x4 v_min(Float32x4 a, Float32x4 b) { return vminq_f32(a, b); }
+ static inline Int32x4 v_min_16(Int32x4 a, Int32x4 b) { return vminq_s32(a, b); }
+
+ static inline Int32x4 v_and(Int32x4 a, Int32x4 b) { return vandq_s32(a, b); }
+
+ static inline Float32x4 v_sub(Float32x4 a, Float32x4 b) { return vsubq_f32(a, b); }
+ static inline Int32x4 v_sub(Int32x4 a, Int32x4 b) { return vsubq_s32(a, b); }
+
+ static inline Float32x4 v_mul(Float32x4 a, Float32x4 b) { return vmulq_f32(a, b); }
+
+ static inline Float32x4 v_sqrt(Float32x4 x) { Float32x4 y = vrsqrteq_f32(x); y = vmulq_f32(y, vrsqrtsq_f32(x, vmulq_f32(y, y))); return vmulq_f32(x, y); }
+
+ static inline Int32x4 v_toInt(Float32x4 x) { return vcvtq_s32_f32(x); }
+
+ static inline Int32x4 v_greaterOrEqual(Float32x4 a, Float32x4 b) { return vcge_f32(a, b); }
+};
+
+const uint * QT_FASTCALL qt_fetch_radial_gradient_neon(uint *buffer, const Operator *op, const QSpanData *data,
+ int y, int x, int length)
+{
+ return qt_fetch_radial_gradient_template<QRadialFetchSimd<QSimdNeon> >(buffer, op, data, y, x, length);
+}
+
QT_END_NAMESPACE
#endif // QT_HAVE_NEON
diff --git a/src/gui/painting/qdrawhelper_p.h b/src/gui/painting/qdrawhelper_p.h
index d4e731b..e93d736 100644
--- a/src/gui/painting/qdrawhelper_p.h
+++ b/src/gui/painting/qdrawhelper_p.h
@@ -63,6 +63,7 @@
#endif
#include "private/qrasterdefs_p.h"
#include <private/qsimd_p.h>
+#include <private/qmath_p.h>
#ifdef Q_WS_QWS
#include "QtGui/qscreen_qws.h"
@@ -178,6 +179,44 @@ void qBlendTextureCallback(int count, const QSpan *spans, void *userData);
typedef void (QT_FASTCALL *CompositionFunction)(uint *dest, const uint *src, int length, uint const_alpha);
typedef void (QT_FASTCALL *CompositionFunctionSolid)(uint *dest, int length, uint color, uint const_alpha);
+struct LinearGradientValues
+{
+ qreal dx;
+ qreal dy;
+ qreal l;
+ qreal off;
+};
+
+struct RadialGradientValues
+{
+ qreal dx;
+ qreal dy;
+ qreal dr;
+ qreal sqrfr;
+ qreal a;
+ qreal inv2a;
+ bool extended;
+};
+
+struct Operator;
+typedef uint* (QT_FASTCALL *DestFetchProc)(uint *buffer, QRasterBuffer *rasterBuffer, int x, int y, int length);
+typedef void (QT_FASTCALL *DestStoreProc)(QRasterBuffer *rasterBuffer, int x, int y, const uint *buffer, int length);
+typedef const uint* (QT_FASTCALL *SourceFetchProc)(uint *buffer, const Operator *o, const QSpanData *data, int y, int x, int length);
+
+struct Operator
+{
+ QPainter::CompositionMode mode;
+ DestFetchProc dest_fetch;
+ DestStoreProc dest_store;
+ SourceFetchProc src_fetch;
+ CompositionFunctionSolid funcSolid;
+ CompositionFunction func;
+ union {
+ LinearGradientValues linear;
+ RadialGradientValues radial;
+ };
+};
+
void qInitDrawhelperAsm();
class QRasterPaintEngine;
@@ -204,12 +243,13 @@ struct QRadialGradientData
struct {
qreal x;
qreal y;
+ qreal radius;
} center;
struct {
qreal x;
qreal y;
+ qreal radius;
} focal;
- qreal radius;
};
struct QConicalGradientData
@@ -233,8 +273,10 @@ struct QGradientData
#ifdef Q_WS_QWS
#define GRADIENT_STOPTABLE_SIZE 256
+#define GRADIENT_STOPTABLE_SIZE_SHIFT 8
#else
#define GRADIENT_STOPTABLE_SIZE 1024
+#define GRADIENT_STOPTABLE_SIZE_SHIFT 10
#endif
uint* colorTable; //[GRADIENT_STOPTABLE_SIZE];
@@ -308,6 +350,220 @@ struct QSpanData
void adjustSpanMethods();
};
+static inline uint qt_gradient_clamp(const QGradientData *data, int ipos)
+{
+ if (ipos < 0 || ipos >= GRADIENT_STOPTABLE_SIZE) {
+ if (data->spread == QGradient::RepeatSpread) {
+ ipos = ipos % GRADIENT_STOPTABLE_SIZE;
+ ipos = ipos < 0 ? GRADIENT_STOPTABLE_SIZE + ipos : ipos;
+ } else if (data->spread == QGradient::ReflectSpread) {
+ const int limit = GRADIENT_STOPTABLE_SIZE * 2;
+ ipos = ipos % limit;
+ ipos = ipos < 0 ? limit + ipos : ipos;
+ ipos = ipos >= GRADIENT_STOPTABLE_SIZE ? limit - 1 - ipos : ipos;
+ } else {
+ if (ipos < 0)
+ ipos = 0;
+ else if (ipos >= GRADIENT_STOPTABLE_SIZE)
+ ipos = GRADIENT_STOPTABLE_SIZE-1;
+ }
+ }
+
+ Q_ASSERT(ipos >= 0);
+ Q_ASSERT(ipos < GRADIENT_STOPTABLE_SIZE);
+
+ return ipos;
+}
+
+static inline uint qt_gradient_pixel(const QGradientData *data, qreal pos)
+{
+ int ipos = int(pos * (GRADIENT_STOPTABLE_SIZE - 1) + qreal(0.5));
+ return data->colorTable[qt_gradient_clamp(data, ipos)];
+}
+
+static inline qreal qRadialDeterminant(qreal a, qreal b, qreal c)
+{
+ return (b * b) - (4 * a * c);
+}
+
+template <class RadialFetchFunc>
+const uint * QT_FASTCALL qt_fetch_radial_gradient_template(uint *buffer, const Operator *op, const QSpanData *data,
+ int y, int x, int length)
+{
+ // avoid division by zero
+ if (qFuzzyIsNull(op->radial.a)) {
+ extern void (*qt_memfill32)(quint32 *dest, quint32 value, int count);
+ qt_memfill32(buffer, 0, length);
+ return buffer;
+ }
+
+ const uint *b = buffer;
+ qreal rx = data->m21 * (y + qreal(0.5))
+ + data->dx + data->m11 * (x + qreal(0.5));
+ qreal ry = data->m22 * (y + qreal(0.5))
+ + data->dy + data->m12 * (x + qreal(0.5));
+ bool affine = !data->m13 && !data->m23;
+
+ uint *end = buffer + length;
+ if (affine) {
+ rx -= data->gradient.radial.focal.x;
+ ry -= data->gradient.radial.focal.y;
+
+ qreal inv_a = 1 / qreal(2 * op->radial.a);
+
+ const qreal delta_rx = data->m11;
+ const qreal delta_ry = data->m12;
+
+ qreal b = 2*(op->radial.dr*data->gradient.radial.focal.radius + rx * op->radial.dx + ry * op->radial.dy);
+ qreal delta_b = 2*(delta_rx * op->radial.dx + delta_ry * op->radial.dy);
+ const qreal b_delta_b = 2 * b * delta_b;
+ const qreal delta_b_delta_b = 2 * delta_b * delta_b;
+
+ const qreal bb = b * b;
+ const qreal delta_bb = delta_b * delta_b;
+
+ b *= inv_a;
+ delta_b *= inv_a;
+
+ const qreal rxrxryry = rx * rx + ry * ry;
+ const qreal delta_rxrxryry = delta_rx * delta_rx + delta_ry * delta_ry;
+ const qreal rx_plus_ry = 2*(rx * delta_rx + ry * delta_ry);
+ const qreal delta_rx_plus_ry = 2 * delta_rxrxryry;
+
+ inv_a *= inv_a;
+
+ qreal det = (bb - 4 * op->radial.a * (op->radial.sqrfr - rxrxryry)) * inv_a;
+ qreal delta_det = (b_delta_b + delta_bb + 4 * op->radial.a * (rx_plus_ry + delta_rxrxryry)) * inv_a;
+ const qreal delta_delta_det = (delta_b_delta_b + 4 * op->radial.a * delta_rx_plus_ry) * inv_a;
+
+ RadialFetchFunc::fetch(buffer, end, op, data, det, delta_det, delta_delta_det, b, delta_b);
+ } else {
+ qreal rw = data->m23 * (y + qreal(0.5))
+ + data->m33 + data->m13 * (x + qreal(0.5));
+
+ while (buffer < end) {
+ if (rw == 0) {
+ *buffer = 0;
+ } else {
+ qreal invRw = 1 / rw;
+ qreal gx = rx * invRw - data->gradient.radial.focal.x;
+ qreal gy = ry * invRw - data->gradient.radial.focal.y;
+ qreal b = 2*(op->radial.dr*data->gradient.radial.focal.radius + gx*op->radial.dx + gy*op->radial.dy);
+ qreal det = qRadialDeterminant(op->radial.a, b, op->radial.sqrfr - (gx*gx + gy*gy));
+
+ quint32 result = 0;
+ if (det >= 0) {
+ qreal detSqrt = qSqrt(det);
+
+ qreal s0 = (-b - detSqrt) * op->radial.inv2a;
+ qreal s1 = (-b + detSqrt) * op->radial.inv2a;
+
+ qreal s = qMax(s0, s1);
+
+ if (data->gradient.radial.focal.radius + op->radial.dr * s >= 0)
+ result = qt_gradient_pixel(&data->gradient, s);
+ }
+
+ *buffer = result;
+ }
+
+ rx += data->m11;
+ ry += data->m12;
+ rw += data->m13;
+
+ ++buffer;
+ }
+ }
+
+ return b;
+}
+
+template <class Simd>
+class QRadialFetchSimd
+{
+public:
+ static void fetch(uint *buffer, uint *end, const Operator *op, const QSpanData *data, qreal det,
+ qreal delta_det, qreal delta_delta_det, qreal b, qreal delta_b)
+ {
+ typename Simd::Vect_buffer_f det_vec;
+ typename Simd::Vect_buffer_f delta_det4_vec;
+ typename Simd::Vect_buffer_f b_vec;
+
+ for (int i = 0; i < 4; ++i) {
+ det_vec.f[i] = det;
+ delta_det4_vec.f[i] = 4 * delta_det;
+ b_vec.f[i] = b;
+
+ det += delta_det;
+ delta_det += delta_delta_det;
+ b += delta_b;
+ }
+
+ const typename Simd::Float32x4 v_delta_delta_det16 = Simd::v_dup(16 * delta_delta_det);
+ const typename Simd::Float32x4 v_delta_delta_det6 = Simd::v_dup(6 * delta_delta_det);
+ const typename Simd::Float32x4 v_delta_b4 = Simd::v_dup(4 * delta_b);
+
+ const typename Simd::Float32x4 v_r0 = Simd::v_dup(data->gradient.radial.focal.radius);
+ const typename Simd::Float32x4 v_dr = Simd::v_dup(op->radial.dr);
+
+ const typename Simd::Float32x4 v_min = Simd::v_dup(0.0f);
+ const typename Simd::Float32x4 v_max = Simd::v_dup(GRADIENT_STOPTABLE_SIZE-1.5f);
+ const typename Simd::Float32x4 v_half = Simd::v_dup(0.5f);
+
+ const typename Simd::Float32x4 v_table_size_minus_one = Simd::v_dup(float(GRADIENT_STOPTABLE_SIZE-1));
+
+ const typename Simd::Int32x4 v_repeat_mask = Simd::v_dup(~(uint(0xffffff) << GRADIENT_STOPTABLE_SIZE_SHIFT));
+ const typename Simd::Int32x4 v_reflect_mask = Simd::v_dup(~(uint(0xffffff) << (GRADIENT_STOPTABLE_SIZE_SHIFT+1)));
+
+ const typename Simd::Int32x4 v_reflect_limit = Simd::v_dup(2 * GRADIENT_STOPTABLE_SIZE - 1);
+
+ const int extended_mask = op->radial.extended ? 0x0 : ~0x0;
+
+#define FETCH_RADIAL_LOOP_PROLOGUE \
+ while (buffer < end) { \
+ typename Simd::Vect_buffer_i v_buffer_mask; \
+ v_buffer_mask.v = Simd::v_greaterOrEqual(det_vec.v, v_min); \
+ const typename Simd::Float32x4 v_index_local = Simd::v_sub(Simd::v_sqrt(Simd::v_max(v_min, det_vec.v)), b_vec.v); \
+ const typename Simd::Float32x4 v_index = Simd::v_add(Simd::v_mul(v_index_local, v_table_size_minus_one), v_half); \
+ v_buffer_mask.v = Simd::v_and(v_buffer_mask.v, Simd::v_greaterOrEqual(Simd::v_add(v_r0, Simd::v_mul(v_dr, v_index_local)), v_min)); \
+ typename Simd::Vect_buffer_i index_vec;
+#define FETCH_RADIAL_LOOP_CLAMP_REPEAT \
+ index_vec.v = Simd::v_and(v_repeat_mask, Simd::v_toInt(v_index));
+#define FETCH_RADIAL_LOOP_CLAMP_REFLECT \
+ const typename Simd::Int32x4 v_index_i = Simd::v_and(v_reflect_mask, Simd::v_toInt(v_index)); \
+ const typename Simd::Int32x4 v_index_i_inv = Simd::v_sub(v_reflect_limit, v_index_i); \
+ index_vec.v = Simd::v_min_16(v_index_i, v_index_i_inv);
+#define FETCH_RADIAL_LOOP_CLAMP_PAD \
+ index_vec.v = Simd::v_toInt(Simd::v_min(v_max, Simd::v_max(v_min, v_index)));
+#define FETCH_RADIAL_LOOP_EPILOGUE \
+ det_vec.v = Simd::v_add(Simd::v_add(det_vec.v, delta_det4_vec.v), v_delta_delta_det6); \
+ delta_det4_vec.v = Simd::v_add(delta_det4_vec.v, v_delta_delta_det16); \
+ b_vec.v = Simd::v_add(b_vec.v, v_delta_b4); \
+ for (int i = 0; i < 4; ++i) \
+ *buffer++ = (extended_mask | v_buffer_mask.i[i]) & data->gradient.colorTable[index_vec.i[i]]; \
+ }
+
+#define FETCH_RADIAL_LOOP(FETCH_RADIAL_LOOP_CLAMP) \
+ FETCH_RADIAL_LOOP_PROLOGUE \
+ FETCH_RADIAL_LOOP_CLAMP \
+ FETCH_RADIAL_LOOP_EPILOGUE
+
+ switch (data->gradient.spread) {
+ case QGradient::RepeatSpread:
+ FETCH_RADIAL_LOOP(FETCH_RADIAL_LOOP_CLAMP_REPEAT)
+ break;
+ case QGradient::ReflectSpread:
+ FETCH_RADIAL_LOOP(FETCH_RADIAL_LOOP_CLAMP_REFLECT)
+ break;
+ case QGradient::PadSpread:
+ FETCH_RADIAL_LOOP(FETCH_RADIAL_LOOP_CLAMP_PAD)
+ break;
+ default:
+ Q_ASSERT(false);
+ }
+ }
+};
+
#if defined(Q_CC_RVCT)
# pragma push
# pragma arm
diff --git a/src/gui/painting/qdrawhelper_sse2.cpp b/src/gui/painting/qdrawhelper_sse2.cpp
index aad6bc9..be6dc91 100644
--- a/src/gui/painting/qdrawhelper_sse2.cpp
+++ b/src/gui/painting/qdrawhelper_sse2.cpp
@@ -491,6 +491,58 @@ void qt_bitmapblit16_sse2(QRasterBuffer *rasterBuffer, int x, int y,
}
}
+class QSimdSse2
+{
+public:
+ typedef __m128i Int32x4;
+ typedef __m128 Float32x4;
+
+ union Vect_buffer_i { Int32x4 v; int i[4]; };
+ union Vect_buffer_f { Float32x4 v; float f[4]; };
+
+ static inline Float32x4 v_dup(float x) { return _mm_set1_ps(x); }
+ static inline Float32x4 v_dup(double x) { return _mm_set1_ps(x); }
+ static inline Int32x4 v_dup(int x) { return _mm_set1_epi32(x); }
+ static inline Int32x4 v_dup(uint x) { return _mm_set1_epi32(x); }
+
+ static inline Float32x4 v_add(Float32x4 a, Float32x4 b) { return _mm_add_ps(a, b); }
+ static inline Int32x4 v_add(Int32x4 a, Int32x4 b) { return _mm_add_epi32(a, b); }
+
+ static inline Float32x4 v_max(Float32x4 a, Float32x4 b) { return _mm_max_ps(a, b); }
+ static inline Float32x4 v_min(Float32x4 a, Float32x4 b) { return _mm_min_ps(a, b); }
+ static inline Int32x4 v_min_16(Int32x4 a, Int32x4 b) { return _mm_min_epi16(a, b); }
+
+ static inline Int32x4 v_and(Int32x4 a, Int32x4 b) { return _mm_and_si128(a, b); }
+
+ static inline Float32x4 v_sub(Float32x4 a, Float32x4 b) { return _mm_sub_ps(a, b); }
+ static inline Int32x4 v_sub(Int32x4 a, Int32x4 b) { return _mm_sub_epi32(a, b); }
+
+ static inline Float32x4 v_mul(Float32x4 a, Float32x4 b) { return _mm_mul_ps(a, b); }
+
+ static inline Float32x4 v_sqrt(Float32x4 x) { return _mm_sqrt_ps(x); }
+
+ static inline Int32x4 v_toInt(Float32x4 x) { return _mm_cvttps_epi32(x); }
+
+ // pre-VS 2008 doesn't have cast intrinsics, whereas 2008 and later requires it
+#if defined(Q_CC_MSVC) && _MSC_VER < 1500
+ static inline Int32x4 v_greaterOrEqual(Float32x4 a, Float32x4 b)
+ {
+ union Convert { Int32x4 vi; Float32x4 vf; } convert;
+ convert.vf = _mm_cmpgt_ps(a, b);
+ return convert.vi;
+ }
+#else
+ static inline Int32x4 v_greaterOrEqual(Float32x4 a, Float32x4 b) { return _mm_castps_si128(_mm_cmpgt_ps(a, b)); }
+#endif
+};
+
+const uint * QT_FASTCALL qt_fetch_radial_gradient_sse2(uint *buffer, const Operator *op, const QSpanData *data,
+ int y, int x, int length)
+{
+ return qt_fetch_radial_gradient_template<QRadialFetchSimd<QSimdSse2> >(buffer, op, data, y, x, length);
+}
+
+
QT_END_NAMESPACE
#endif // QT_HAVE_SSE2
diff --git a/src/gui/painting/qpaintbuffer.cpp b/src/gui/painting/qpaintbuffer.cpp
index dd4b3db..7870def 100644
--- a/src/gui/painting/qpaintbuffer.cpp
+++ b/src/gui/painting/qpaintbuffer.cpp
@@ -47,6 +47,7 @@
#include <private/qimage_p.h>
#include <qstatictext.h>
#include <private/qstatictext_p.h>
+#include <private/qrawfont_p.h>
#include <QDebug>
@@ -1754,26 +1755,38 @@ void QPainterReplayer::process(const QPaintBufferCommand &cmd)
painter->setClipRegion(region, Qt::ClipOperation(cmd.extra));
break; }
+#if !defined(QT_NO_RAWFONT)
case QPaintBufferPrivate::Cmd_DrawStaticText: {
QVariantList variants(d->variants.at(cmd.offset).value<QVariantList>());
QFont font = variants.at(0).value<QFont>();
- QVector<quint32> glyphs;
+ QVector<quint32> glyphIndexes;
QVector<QPointF> positions;
for (int i=0; i<(variants.size() - 1) / 2; ++i) {
- glyphs.append(variants.at(i*2 + 1).toUInt());
+ glyphIndexes.append(variants.at(i*2 + 1).toUInt());
positions.append(variants.at(i*2 + 2).toPointF());
}
painter->setFont(font);
- qt_draw_glyphs(painter, glyphs.constData(), positions.constData(), glyphs.size());
-
- break;
+ QRawFont rawFont;
+ QRawFontPrivate *rawFontD = QRawFontPrivate::get(rawFont);
+ QFontPrivate *fontD = QFontPrivate::get(font);
+ rawFontD->fontEngine = fontD->engineForScript(QUnicodeTables::Common);
+ rawFontD->fontEngine->ref.ref();
+
+ QGlyphs glyphs;
+ glyphs.setFont(rawFont);
+ glyphs.setGlyphIndexes(glyphIndexes);
+ glyphs.setPositions(positions);
+
+ painter->drawGlyphs(QPointF(), glyphs);
+ break;
}
+#endif
case QPaintBufferPrivate::Cmd_DrawText: {
QPointF pos(d->floats.at(cmd.extra), d->floats.at(cmd.extra+1));
diff --git a/src/gui/painting/qpaintengine_mac.cpp b/src/gui/painting/qpaintengine_mac.cpp
index 8aab7c7..cc75b86 100644
--- a/src/gui/painting/qpaintengine_mac.cpp
+++ b/src/gui/painting/qpaintengine_mac.cpp
@@ -1544,8 +1544,9 @@ void QCoreGraphicsPaintEnginePrivate::setFillBrush(const QPointF &offset)
QPointF center(radialGrad->center());
QPointF focal(radialGrad->focalPoint());
qreal radius = radialGrad->radius();
+ qreal focalRadius = radialGrad->focalRadius();
shading = CGShadingCreateRadial(colorspace, CGPointMake(focal.x(), focal.y()),
- 0.0, CGPointMake(center.x(), center.y()), radius, fill_func, false, true);
+ focalRadius, CGPointMake(center.x(), center.y()), radius, fill_func, false, true);
}
CGFunctionRelease(fill_func);
diff --git a/src/gui/painting/qpaintengine_raster.cpp b/src/gui/painting/qpaintengine_raster.cpp
index 6902543..2119e30 100644
--- a/src/gui/painting/qpaintengine_raster.cpp
+++ b/src/gui/painting/qpaintengine_raster.cpp
@@ -5033,6 +5033,84 @@ void QGradientCache::generateGradientColorTable(const QGradient& gradient, uint
bool colorInterpolation = (gradient.interpolationMode() == QGradient::ColorInterpolation);
+ if (stopCount == 2) {
+ uint first_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity);
+ uint second_color = ARGB_COMBINE_ALPHA(stops[1].second.rgba(), opacity);
+
+ qreal first_stop = stops[0].first;
+ qreal second_stop = stops[1].first;
+
+ if (second_stop < first_stop) {
+ qSwap(first_color, second_color);
+ qSwap(first_stop, second_stop);
+ }
+
+ if (colorInterpolation) {
+ first_color = PREMUL(first_color);
+ second_color = PREMUL(second_color);
+ }
+
+ int first_index = qRound(first_stop * (GRADIENT_STOPTABLE_SIZE-1));
+ int second_index = qRound(second_stop * (GRADIENT_STOPTABLE_SIZE-1));
+
+ uint red_first = qRed(first_color) << 16;
+ uint green_first = qGreen(first_color) << 16;
+ uint blue_first = qBlue(first_color) << 16;
+ uint alpha_first = qAlpha(first_color) << 16;
+
+ uint red_second = qRed(second_color) << 16;
+ uint green_second = qGreen(second_color) << 16;
+ uint blue_second = qBlue(second_color) << 16;
+ uint alpha_second = qAlpha(second_color) << 16;
+
+ int i = 0;
+ for (; i <= qMin(GRADIENT_STOPTABLE_SIZE, first_index); ++i) {
+ if (colorInterpolation)
+ colorTable[i] = first_color;
+ else
+ colorTable[i] = PREMUL(first_color);
+ }
+
+ if (i < second_index) {
+ qreal reciprocal = qreal(1) / (second_index - first_index);
+
+ int red_delta = qRound(int(red_second - red_first) * reciprocal);
+ int green_delta = qRound(int(green_second - green_first) * reciprocal);
+ int blue_delta = qRound(int(blue_second - blue_first) * reciprocal);
+ int alpha_delta = qRound(int(alpha_second - alpha_first) * reciprocal);
+
+ // rounding
+ red_first += 1 << 15;
+ green_first += 1 << 15;
+ blue_first += 1 << 15;
+ alpha_first += 1 << 15;
+
+ for (; i < qMin(GRADIENT_STOPTABLE_SIZE, second_index); ++i) {
+ red_first += red_delta;
+ green_first += green_delta;
+ blue_first += blue_delta;
+ alpha_first += alpha_delta;
+
+ const uint color = ((alpha_first << 8) & 0xff000000) | (red_first & 0xff0000)
+ | ((green_first >> 8) & 0xff00) | (blue_first >> 16);
+
+ if (colorInterpolation)
+ colorTable[i] = color;
+ else
+ colorTable[i] = PREMUL(color);
+ }
+ }
+
+ for (; i < GRADIENT_STOPTABLE_SIZE; ++i) {
+ if (colorInterpolation)
+ colorTable[i] = second_color;
+ else
+ colorTable[i] = PREMUL(second_color);
+ }
+
+ return;
+ }
+
uint current_color = ARGB_COMBINE_ALPHA(stops[0].second.rgba(), opacity);
if (stopCount == 1) {
current_color = PREMUL(current_color);
@@ -5204,10 +5282,11 @@ void QSpanData::setup(const QBrush &brush, int alpha, QPainter::CompositionMode
QPointF center = g->center();
radialData.center.x = center.x();
radialData.center.y = center.y();
+ radialData.center.radius = g->centerRadius();
QPointF focal = g->focalPoint();
radialData.focal.x = focal.x();
radialData.focal.y = focal.y();
- radialData.radius = g->radius();
+ radialData.focal.radius = g->focalRadius();
}
break;
diff --git a/src/gui/painting/qpaintengineex.cpp b/src/gui/painting/qpaintengineex.cpp
index 509fb77..7f601eb 100644
--- a/src/gui/painting/qpaintengineex.cpp
+++ b/src/gui/painting/qpaintengineex.cpp
@@ -1012,4 +1012,50 @@ void QPaintEngineEx::updateState(const QPaintEngineState &)
// do nothing...
}
+Q_GUI_EXPORT QPainterPath qt_painterPathFromVectorPath(const QVectorPath &path)
+{
+ const qreal *points = path.points();
+ const QPainterPath::ElementType *types = path.elements();
+
+ QPainterPath p;
+ if (types) {
+ int id = 0;
+ for (int i=0; i<path.elementCount(); ++i) {
+ switch(types[i]) {
+ case QPainterPath::MoveToElement:
+ p.moveTo(QPointF(points[id], points[id+1]));
+ id+=2;
+ break;
+ case QPainterPath::LineToElement:
+ p.lineTo(QPointF(points[id], points[id+1]));
+ id+=2;
+ break;
+ case QPainterPath::CurveToElement: {
+ QPointF p1(points[id], points[id+1]);
+ QPointF p2(points[id+2], points[id+3]);
+ QPointF p3(points[id+4], points[id+5]);
+ p.cubicTo(p1, p2, p3);
+ id+=6;
+ break;
+ }
+ case QPainterPath::CurveToDataElement:
+ ;
+ break;
+ }
+ }
+ } else {
+ p.moveTo(QPointF(points[0], points[1]));
+ int id = 2;
+ for (int i=1; i<path.elementCount(); ++i) {
+ p.lineTo(QPointF(points[id], points[id+1]));
+ id+=2;
+ }
+ }
+ if (path.hints() & QVectorPath::WindingFill)
+ p.setFillRule(Qt::WindingFill);
+
+ return p;
+}
+
+
QT_END_NAMESPACE
diff --git a/src/gui/painting/qpainter.cpp b/src/gui/painting/qpainter.cpp
index 50d65e6..25bf6be 100644
--- a/src/gui/painting/qpainter.cpp
+++ b/src/gui/painting/qpainter.cpp
@@ -75,6 +75,7 @@
#include <private/qstatictext_p.h>
#include <private/qglyphs_p.h>
#include <private/qstylehelper_p.h>
+#include <private/qrawfont_p.h>
QT_BEGIN_NAMESPACE
@@ -155,7 +156,8 @@ static bool qt_paintengine_supports_transformations(QPaintEngine::Type type)
{
return type == QPaintEngine::OpenGL2
|| type == QPaintEngine::OpenVG
- || type == QPaintEngine::OpenGL;
+ || type == QPaintEngine::OpenGL
+ || type == QPaintEngine::CoreGraphics;
}
#ifndef QT_NO_DEBUG
@@ -502,8 +504,12 @@ void QPainterPrivate::draw_helper(const QPainterPath &originalPath, DrawOperatio
q->save();
state->matrix = QTransform();
- state->dirtyFlags |= QPaintEngine::DirtyTransform;
- updateState(state);
+ if (extended) {
+ extended->transformChanged();
+ } else {
+ state->dirtyFlags |= QPaintEngine::DirtyTransform;
+ updateState(state);
+ }
engine->drawImage(absPathRect,
image,
QRectF(0, 0, absPathRect.width(), absPathRect.height()),
@@ -686,11 +692,14 @@ void QPainterPrivate::updateInvMatrix()
invMatrix = state->matrix.inverted();
}
+extern bool qt_isExtendedRadialGradient(const QBrush &brush);
+
void QPainterPrivate::updateEmulationSpecifier(QPainterState *s)
{
bool alpha = false;
bool linearGradient = false;
bool radialGradient = false;
+ bool extendedRadialGradient = false;
bool conicalGradient = false;
bool patternBrush = false;
bool xform = false;
@@ -722,6 +731,7 @@ void QPainterPrivate::updateEmulationSpecifier(QPainterState *s)
(brushStyle == Qt::LinearGradientPattern));
radialGradient = ((penBrushStyle == Qt::RadialGradientPattern) ||
(brushStyle == Qt::RadialGradientPattern));
+ extendedRadialGradient = radialGradient && (qt_isExtendedRadialGradient(penBrush) || qt_isExtendedRadialGradient(s->brush));
conicalGradient = ((penBrushStyle == Qt::ConicalGradientPattern) ||
(brushStyle == Qt::ConicalGradientPattern));
patternBrush = (((penBrushStyle > Qt::SolidPattern
@@ -805,7 +815,7 @@ void QPainterPrivate::updateEmulationSpecifier(QPainterState *s)
s->emulationSpecifier &= ~QPaintEngine::LinearGradientFill;
// Radial gradient emulation
- if (radialGradient && !engine->hasFeature(QPaintEngine::RadialGradientFill))
+ if (extendedRadialGradient || (radialGradient && !engine->hasFeature(QPaintEngine::RadialGradientFill)))
s->emulationSpecifier |= QPaintEngine::RadialGradientFill;
else
s->emulationSpecifier &= ~QPaintEngine::RadialGradientFill;
@@ -5790,12 +5800,14 @@ void QPainter::drawImage(const QRectF &targetRect, const QImage &image, const QR
\sa QGlyphs::setFont(), QGlyphs::setPositions(), QGlyphs::setGlyphIndexes()
*/
+#if !defined(QT_NO_RAWFONT)
void QPainter::drawGlyphs(const QPointF &position, const QGlyphs &glyphs)
{
Q_D(QPainter);
- QFont oldFont = d->state->font;
- d->state->font = glyphs.font();
+ QRawFont font = glyphs.font();
+ if (!font.isValid())
+ return;
QVector<quint32> glyphIndexes = glyphs.glyphIndexes();
QVector<QPointF> glyphPositions = glyphs.positions();
@@ -5806,7 +5818,7 @@ void QPainter::drawGlyphs(const QPointF &position, const QGlyphs &glyphs)
bool paintEngineSupportsTransformations =
d->extended != 0
? qt_paintengine_supports_transformations(d->extended->type())
- : false;
+ : qt_paintengine_supports_transformations(d->engine->type());
for (int i=0; i<count; ++i) {
QPointF processedPosition = position + glyphPositions.at(i);
if (!paintEngineSupportsTransformations)
@@ -5814,39 +5826,20 @@ void QPainter::drawGlyphs(const QPointF &position, const QGlyphs &glyphs)
fixedPointPositions[i] = QFixedPoint::fromPointF(processedPosition);
}
- d->drawGlyphs(glyphIndexes.data(), fixedPointPositions.data(), count);
-
- d->state->font = oldFont;
-}
-
-void qt_draw_glyphs(QPainter *painter, const quint32 *glyphArray, const QPointF *positionArray,
- int glyphCount)
-{
- QVarLengthArray<QFixedPoint, 128> positions(glyphCount);
- for (int i=0; i<glyphCount; ++i)
- positions[i] = QFixedPoint::fromPointF(positionArray[i]);
-
- QPainterPrivate *painter_d = QPainterPrivate::get(painter);
- painter_d->drawGlyphs(const_cast<quint32 *>(glyphArray), positions.data(), glyphCount);
+ d->drawGlyphs(glyphIndexes.data(), fixedPointPositions.data(), count, font, glyphs.overline(),
+ glyphs.underline(), glyphs.strikeOut());
}
-void QPainterPrivate::drawGlyphs(quint32 *glyphArray, QFixedPoint *positions, int glyphCount)
+void QPainterPrivate::drawGlyphs(quint32 *glyphArray, QFixedPoint *positions, int glyphCount,
+ const QRawFont &font, bool overline, bool underline,
+ bool strikeOut)
{
Q_Q(QPainter);
updateState(state);
- QFontEngine *fontEngine = state->font.d->engineForScript(QUnicodeTables::Common);
-
- while (fontEngine->type() == QFontEngine::Multi) {
- // Pick engine based on first glyph in array if we are using a multi engine.
- // (all glyphs must be for same font)
- int engineIdx = 0;
- if (glyphCount > 0)
- engineIdx = glyphArray[0] >> 24;
-
- fontEngine = static_cast<QFontEngineMulti *>(fontEngine)->engine(engineIdx);
- }
+ QRawFontPrivate *fontD = QRawFontPrivate::get(font);
+ QFontEngine *fontEngine = fontD->fontEngine;
QFixed leftMost;
QFixed rightMost;
@@ -5881,7 +5874,6 @@ void QPainterPrivate::drawGlyphs(quint32 *glyphArray, QFixedPoint *positions, in
extended->drawStaticTextItem(&staticTextItem);
} else {
QTextItemInt textItem;
- textItem.f = &state->font;
textItem.fontEngine = fontEngine;
QVarLengthArray<QFixed, 128> advances(glyphCount);
@@ -5903,20 +5895,21 @@ void QPainterPrivate::drawGlyphs(quint32 *glyphArray, QFixedPoint *positions, in
}
QTextItemInt::RenderFlags flags;
- if (state->font.underline())
+ if (underline)
flags |= QTextItemInt::Underline;
- if (state->font.overline())
+ if (overline)
flags |= QTextItemInt::Overline;
- if (state->font.strikeOut())
+ if (strikeOut)
flags |= QTextItemInt::StrikeOut;
drawTextItemDecoration(q, QPointF(leftMost.toReal(), baseLine.toReal()),
fontEngine,
- (state->font.underline()
- ? QTextCharFormat::SingleUnderline
- : QTextCharFormat::NoUnderline),
+ (underline
+ ? QTextCharFormat::SingleUnderline
+ : QTextCharFormat::NoUnderline),
flags, width.toReal(), QTextCharFormat());
}
+#endif // QT_NO_RAWFONT
/*!
diff --git a/src/gui/painting/qpainter.h b/src/gui/painting/qpainter.h
index ae2fdf2..1a432e6 100644
--- a/src/gui/painting/qpainter.h
+++ b/src/gui/painting/qpainter.h
@@ -399,7 +399,9 @@ public:
void setLayoutDirection(Qt::LayoutDirection direction);
Qt::LayoutDirection layoutDirection() const;
+#if !defined(QT_NO_RAWFONT)
void drawGlyphs(const QPointF &position, const QGlyphs &glyphs);
+#endif
void drawStaticText(const QPointF &topLeftPosition, const QStaticText &staticText);
inline void drawStaticText(const QPoint &topLeftPosition, const QStaticText &staticText);
@@ -551,6 +553,7 @@ private:
friend class QPaintEngine;
friend class QPaintEngineExPrivate;
friend class QOpenGLPaintEngine;
+ friend class QVGPaintEngine;
friend class QX11PaintEngine;
friend class QX11PaintEnginePrivate;
friend class QWin32PaintEngine;
diff --git a/src/gui/painting/qpainter_p.h b/src/gui/painting/qpainter_p.h
index 26d8fc3..205c10a 100644
--- a/src/gui/painting/qpainter_p.h
+++ b/src/gui/painting/qpainter_p.h
@@ -184,6 +184,7 @@ struct QPainterDummyState
QTransform transform;
};
+class QRawFont;
class QPainterPrivate
{
Q_DECLARE_PUBLIC(QPainter)
@@ -229,7 +230,12 @@ public:
void draw_helper(const QPainterPath &path, DrawOperation operation = StrokeAndFillDraw);
void drawStretchedGradient(const QPainterPath &path, DrawOperation operation);
void drawOpaqueBackground(const QPainterPath &path, DrawOperation operation);
- void drawGlyphs(quint32 *glyphArray, QFixedPoint *positionArray, int glyphCount);
+
+#if !defined(QT_NO_RAWFONT)
+ void drawGlyphs(quint32 *glyphArray, QFixedPoint *positionArray, int glyphCount,
+ const QRawFont &font, bool overline = false, bool underline = false,
+ bool strikeOut = false);
+#endif
void updateMatrix();
void updateInvMatrix();
@@ -259,8 +265,6 @@ public:
};
Q_GUI_EXPORT void qt_draw_helper(QPainterPrivate *p, const QPainterPath &path, QPainterPrivate::DrawOperation operation);
-Q_GUI_EXPORT void qt_draw_glyphs(QPainter *painter, const quint32 *glyphArray,
- const QPointF *positionArray, int glyphCount);
QString qt_generate_brush_key(const QBrush &brush);
diff --git a/src/gui/painting/qunifiedtoolbarsurface_mac.cpp b/src/gui/painting/qunifiedtoolbarsurface_mac.cpp
index 3876c3d..2fda6b9 100644
--- a/src/gui/painting/qunifiedtoolbarsurface_mac.cpp
+++ b/src/gui/painting/qunifiedtoolbarsurface_mac.cpp
@@ -152,7 +152,8 @@ void QUnifiedToolbarSurface::beginPaint(const QRegion &rgn)
void QUnifiedToolbarSurface::updateToolbarOffset(QWidget *widget)
{
QMainWindowLayout *mlayout = qobject_cast<QMainWindowLayout*> (widget->window()->layout());
- mlayout->updateUnifiedToolbarOffset();
+ if (mlayout)
+ mlayout->updateUnifiedToolbarOffset();
}
void QUnifiedToolbarSurface::flush(QWidget *widget, const QRegion &region, const QPoint &offset)
diff --git a/src/gui/text/qfont.cpp b/src/gui/text/qfont.cpp
index f77e237..b8cfb1f 100644
--- a/src/gui/text/qfont.cpp
+++ b/src/gui/text/qfont.cpp
@@ -282,27 +282,16 @@ QFontPrivate::~QFontPrivate()
scFont = 0;
}
-#if !defined(Q_WS_MAC)
extern QMutex *qt_fontdatabase_mutex();
-QFontEngine *QFontPrivate::engineForScript(int script) const
-{
- QMutexLocker locker(qt_fontdatabase_mutex());
- if (script >= QUnicodeTables::Inherited)
- script = QUnicodeTables::Common;
- if (engineData && engineData->fontCache != QFontCache::instance()) {
- // throw out engineData that came from a different thread
- engineData->ref.deref();
- engineData = 0;
- }
- if (!engineData || !engineData->engines[script])
- QFontDatabase::load(this, script);
- return engineData->engines[script];
-}
+#if !defined(Q_WS_MAC)
+#define QT_FONT_ENGINE_FROM_DATA(data, script) data->engines[script]
#else
+#define QT_FONT_ENGINE_FROM_DATA(data, script) data->engine
+#endif
+
QFontEngine *QFontPrivate::engineForScript(int script) const
{
- extern QMutex *qt_fontdatabase_mutex();
QMutexLocker locker(qt_fontdatabase_mutex());
if (script >= QUnicodeTables::Inherited)
script = QUnicodeTables::Common;
@@ -311,11 +300,10 @@ QFontEngine *QFontPrivate::engineForScript(int script) const
engineData->ref.deref();
engineData = 0;
}
- if (!engineData || !engineData->engine)
+ if (!engineData || !QT_FONT_ENGINE_FROM_DATA(engineData, script))
QFontDatabase::load(this, script);
- return engineData->engine;
+ return QT_FONT_ENGINE_FROM_DATA(engineData, script);
}
-#endif
void QFontPrivate::alterCharForCapitalization(QChar &c) const {
switch (capital) {
diff --git a/src/gui/text/qfont_win.cpp b/src/gui/text/qfont_win.cpp
index 7d710ea..3ef761b 100644
--- a/src/gui/text/qfont_win.cpp
+++ b/src/gui/text/qfont_win.cpp
@@ -58,6 +58,7 @@
QT_BEGIN_NAMESPACE
extern HDC shared_dc(); // common dc for all fonts
+extern QFont::Weight weightFromInteger(int weight); // qfontdatabase.cpp
// ### maybe move to qapplication_win
QFont qt_LOGFONTtoQFont(LOGFONT& lf, bool /*scale*/)
@@ -65,20 +66,8 @@ QFont qt_LOGFONTtoQFont(LOGFONT& lf, bool /*scale*/)
QString family = QString::fromWCharArray(lf.lfFaceName);
QFont qf(family);
qf.setItalic(lf.lfItalic);
- if (lf.lfWeight != FW_DONTCARE) {
- int weight;
- if (lf.lfWeight < 400)
- weight = QFont::Light;
- else if (lf.lfWeight < 600)
- weight = QFont::Normal;
- else if (lf.lfWeight < 700)
- weight = QFont::DemiBold;
- else if (lf.lfWeight < 800)
- weight = QFont::Bold;
- else
- weight = QFont::Black;
- qf.setWeight(weight);
- }
+ if (lf.lfWeight != FW_DONTCARE)
+ qf.setWeight(weightFromInteger(lf.lfWeight));
int lfh = qAbs(lf.lfHeight);
qf.setPointSizeF(lfh * 72.0 / GetDeviceCaps(shared_dc(),LOGPIXELSY));
qf.setUnderline(false);
diff --git a/src/gui/text/qfontdatabase.cpp b/src/gui/text/qfontdatabase.cpp
index 94f21b8..36b0ea9 100644
--- a/src/gui/text/qfontdatabase.cpp
+++ b/src/gui/text/qfontdatabase.cpp
@@ -136,6 +136,21 @@ static int getFontWeight(const QString &weightString)
return (int) QFont::Normal;
}
+// convert 0 ~ 1000 integer to QFont::Weight
+QFont::Weight weightFromInteger(int weight)
+{
+ if (weight < 400)
+ return QFont::Light;
+ else if (weight < 600)
+ return QFont::Normal;
+ else if (weight < 700)
+ return QFont::DemiBold;
+ else if (weight < 800)
+ return QFont::Bold;
+ else
+ return QFont::Black;
+}
+
struct QtFontEncoding
{
signed int encoding : 16;
@@ -497,8 +512,6 @@ QtFontFoundry *QtFontFamily::foundry(const QString &f, bool create)
// ### copied to tools/makeqpf/qpf2.cpp
-#if (defined(Q_WS_QWS) && !defined(QT_NO_FREETYPE)) || defined(Q_WS_WIN) || defined(Q_OS_SYMBIAN) || (defined(Q_WS_MAC) && !defined(QT_MAC_USE_COCOA))
-
// see the Unicode subset bitfields in the MSDN docs
static int requiredUnicodeBits[QFontDatabase::WritingSystemsCount][2] = {
// Any,
@@ -576,7 +589,7 @@ static int requiredUnicodeBits[QFontDatabase::WritingSystemsCount][2] = {
#define JapaneseCsbBit 17
#define KoreanCsbBit 21
-static QList<QFontDatabase::WritingSystem> determineWritingSystemsFromTrueTypeBits(quint32 unicodeRange[4], quint32 codePageRange[2])
+QList<QFontDatabase::WritingSystem> qt_determine_writing_systems_from_truetype_bits(quint32 unicodeRange[4], quint32 codePageRange[2])
{
QList<QFontDatabase::WritingSystem> writingSystems;
bool hasScript = false;
@@ -623,7 +636,6 @@ static QList<QFontDatabase::WritingSystem> determineWritingSystemsFromTrueTypeBi
return writingSystems;
}
-#endif
#if defined(Q_OS_SYMBIAN) && defined(QT_NO_FREETYPE)
// class with virtual destructor, derived in qfontdatabase_s60.cpp
@@ -873,7 +885,7 @@ QStringList QFontDatabasePrivate::addTTFile(const QByteArray &file, const QByteA
os2->ulCodePageRange1, os2->ulCodePageRange2
};
- writingSystems = determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
+ writingSystems = qt_determine_writing_systems_from_truetype_bits(unicodeRange, codePageRange);
//for (int i = 0; i < writingSystems.count(); ++i)
// qDebug() << QFontDatabase::writingSystemName(writingSystems.at(i));
}
@@ -936,6 +948,11 @@ static const int scriptForWritingSystem[] = {
QUnicodeTables::Nko // Nko
};
+int qt_script_for_writing_system(QFontDatabase::WritingSystem writingSystem)
+{
+ return scriptForWritingSystem[writingSystem];
+}
+
#if defined Q_WS_QWS || (defined(Q_WS_X11) && !defined(QT_NO_FONTCONFIG)) || defined(Q_WS_WIN)
static inline bool requiresOpenType(int writingSystem)
diff --git a/src/gui/text/qfontdatabase_mac.cpp b/src/gui/text/qfontdatabase_mac.cpp
index ad2c1b2..5ba236b 100644
--- a/src/gui/text/qfontdatabase_mac.cpp
+++ b/src/gui/text/qfontdatabase_mac.cpp
@@ -72,7 +72,7 @@ static void initWritingSystems(QtFontFamily *family, ATSFontRef atsFont)
qFromBigEndian<quint32>(os2Table.data() + 54)
};
quint32 codePageRange[2] = { qFromBigEndian<quint32>(os2Table.data() + 78), qFromBigEndian<quint32>(os2Table.data() + 82) };
- QList<QFontDatabase::WritingSystem> systems = determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
+ QList<QFontDatabase::WritingSystem> systems = qt_determine_writing_systems_from_truetype_bits(unicodeRange, codePageRange);
#if 0
QCFString name;
ATSFontGetName(atsFont, kATSOptionFlagsDefault, &name);
@@ -244,6 +244,11 @@ static const char *styleHint(const QFontDef &request)
return stylehint;
}
+static inline float weightToFloat(unsigned int weight)
+{
+ return (weight - 50) / 100.0;
+}
+
void QFontDatabase::load(const QFontPrivate *d, int script)
{
// sanity checks
diff --git a/src/gui/text/qfontdatabase_s60.cpp b/src/gui/text/qfontdatabase_s60.cpp
index 6d3970e..1db4a7d 100644
--- a/src/gui/text/qfontdatabase_s60.cpp
+++ b/src/gui/text/qfontdatabase_s60.cpp
@@ -521,7 +521,7 @@ static bool registerScreenDeviceFont(int screenDeviceFontIndex,
qFromBigEndian<quint32>(ulCodePageRange + 4)
};
const QList<QFontDatabase::WritingSystem> writingSystems =
- determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
+ qt_determine_writing_systems_from_truetype_bits(unicodeRange, codePageRange);
foreach (const QFontDatabase::WritingSystem system, writingSystems)
family->writingSystems[system] = QtFontFamily::Supported;
return true;
diff --git a/src/gui/text/qfontdatabase_win.cpp b/src/gui/text/qfontdatabase_win.cpp
index 8279195..05b7509 100644
--- a/src/gui/text/qfontdatabase_win.cpp
+++ b/src/gui/text/qfontdatabase_win.cpp
@@ -242,6 +242,8 @@ error:
return i18n_name;
}
+extern QFont::Weight weightFromInteger(int weight); // qfontdatabase.cpp
+
static
void addFontToDatabase(QString familyName, const QString &scriptName,
TEXTMETRIC *textmetric,
@@ -274,16 +276,7 @@ void addFontToDatabase(QString familyName, const QString &scriptName,
if (familyName[0] != QLatin1Char('@') && !familyName.startsWith(QLatin1String("WST_"))) {
QtFontStyle::Key styleKey;
styleKey.style = italic ? QFont::StyleItalic : QFont::StyleNormal;
- if (weight < 400)
- styleKey.weight = QFont::Light;
- else if (weight < 600)
- styleKey.weight = QFont::Normal;
- else if (weight < 700)
- styleKey.weight = QFont::DemiBold;
- else if (weight < 800)
- styleKey.weight = QFont::Bold;
- else
- styleKey.weight = QFont::Black;
+ styleKey.weight = weightFromInteger(weight);
QtFontFamily *family = privateDb()->family(familyName, true);
@@ -340,7 +333,7 @@ void addFontToDatabase(QString familyName, const QString &scriptName,
quint32 codePageRange[2] = {
signature->fsCsb[0], signature->fsCsb[1]
};
- QList<QFontDatabase::WritingSystem> systems = determineWritingSystemsFromTrueTypeBits(unicodeRange, codePageRange);
+ QList<QFontDatabase::WritingSystem> systems = qt_determine_writing_systems_from_truetype_bits(unicodeRange, codePageRange);
for (int i = 0; i < systems.count(); ++i) {
QFontDatabase::WritingSystem writingSystem = systems.at(i);
@@ -530,26 +523,26 @@ static inline void load(const QString &family = QString(), int = -1)
-static void initFontInfo(QFontEngineWin *fe, const QFontDef &request, const QFontPrivate *fp)
+static void initFontInfo(QFontEngineWin *fe, const QFontDef &request, HDC fontHdc, int dpi)
{
fe->fontDef = request; // most settings are equal
- HDC dc = ((request.styleStrategy & QFont::PreferDevice) && fp->hdc) ? fp->hdc : shared_dc();
+ HDC dc = ((request.styleStrategy & QFont::PreferDevice) && fontHdc) ? fontHdc : shared_dc();
SelectObject(dc, fe->hfont);
wchar_t n[64];
GetTextFace(dc, 64, n);
fe->fontDef.family = QString::fromWCharArray(n);
fe->fontDef.fixedPitch = !(fe->tm.tmPitchAndFamily & TMPF_FIXED_PITCH);
if (fe->fontDef.pointSize < 0) {
- fe->fontDef.pointSize = fe->fontDef.pixelSize * 72. / fp->dpi;
+ fe->fontDef.pointSize = fe->fontDef.pixelSize * 72. / dpi;
} else if (fe->fontDef.pixelSize == -1) {
- fe->fontDef.pixelSize = qRound(fe->fontDef.pointSize * fp->dpi / 72.);
+ fe->fontDef.pixelSize = qRound(fe->fontDef.pointSize * dpi / 72.);
}
}
#if !defined(QT_NO_DIRECTWRITE)
static void initFontInfo(QFontEngineDirectWrite *fe, const QFontDef &request,
- const QFontPrivate *fp, IDWriteFont *font)
+ int dpi, IDWriteFont *font)
{
fe->fontDef = request;
@@ -601,9 +594,9 @@ static void initFontInfo(QFontEngineDirectWrite *fe, const QFontDef &request,
qErrnoWarning(hr, "initFontInfo: Failed to get family name");
if (fe->fontDef.pointSize < 0)
- fe->fontDef.pointSize = fe->fontDef.pixelSize * 72. / fp->dpi;
+ fe->fontDef.pointSize = fe->fontDef.pixelSize * 72. / dpi;
else if (fe->fontDef.pixelSize == -1)
- fe->fontDef.pixelSize = qRound(fe->fontDef.pointSize * fp->dpi / 72.);
+ fe->fontDef.pixelSize = qRound(fe->fontDef.pointSize * dpi / 72.);
}
#endif
@@ -679,20 +672,21 @@ static inline HFONT systemFont()
#define DEFAULT_GUI_FONT 17
#endif
-static
-QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &request, const QtFontDesc *desc,
- const QStringList &family_list)
+static QFontEngine *loadEngine(int script, const QFontDef &request,
+ HDC fontHdc, int dpi, bool rawMode,
+ const QtFontDesc *desc,
+ const QStringList &family_list)
{
LOGFONT lf;
memset(&lf, 0, sizeof(LOGFONT));
- bool useDevice = (request.styleStrategy & QFont::PreferDevice) && fp->hdc;
+ bool useDevice = (request.styleStrategy & QFont::PreferDevice) && fontHdc;
HDC hdc = shared_dc();
- QString font_name = desc->family->name;
+ QString font_name = desc != 0 ? desc->family->name : request.family;
if (useDevice) {
- hdc = fp->hdc;
+ hdc = fontHdc;
font_name = request.family;
}
@@ -710,9 +704,9 @@ QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &requ
bool useDirectWrite = false;
#endif
- if (fp->rawMode) { // will choose a stock font
+ if (rawMode) { // will choose a stock font
int f, deffnt = SYSTEM_FONT;
- QString fam = desc->family->name.toLower();
+ QString fam = desc != 0 ? desc->family->name.toLower() : request.family.toLower();
if (fam == QLatin1String("default"))
f = deffnt;
else if (fam == QLatin1String("system"))
@@ -766,11 +760,11 @@ QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &requ
lf.lfWidth = 0;
lf.lfEscapement = 0;
lf.lfOrientation = 0;
- if (desc->style->key.weight == 50)
+ if (desc == 0 || desc->style->key.weight == 50)
lf.lfWeight = FW_DONTCARE;
else
lf.lfWeight = (desc->style->key.weight*900)/99;
- lf.lfItalic = (desc->style->key.style != QFont::StyleNormal);
+ lf.lfItalic = (desc != 0 && desc->style->key.style != QFont::StyleNormal);
lf.lfCharSet = DEFAULT_CHARSET;
int strat = OUT_DEFAULT_PRECIS;
@@ -901,9 +895,11 @@ QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &requ
&lf,
&directWriteFont);
if (FAILED(hr)) {
+#ifndef QT_NO_DEBUG
qErrnoWarning("QFontEngine::loadEngine: CreateFontFromLOGFONT failed "
"for %ls (0x%lx)",
lf.lfFaceName, hr);
+#endif
} else {
DeleteObject(hfont);
useDirectWrite = true;
@@ -933,22 +929,27 @@ QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &requ
}
}
- initFontInfo(few, request, fp);
+ initFontInfo(few, request, fontHdc, dpi);
fe = few;
}
#if !defined(QT_NO_DIRECTWRITE)
else {
QFontDatabasePrivate *db = privateDb();
- QFontEngineDirectWrite *fedw = new QFontEngineDirectWrite(font_name,
- db->directWriteFactory,
- db->directWriteGdiInterop,
- directWriteFont,
- request.pixelSize);
- initFontInfo(fedw, request, fp, directWriteFont);
+ IDWriteFontFace *directWriteFontFace = NULL;
+ HRESULT hr = directWriteFont->CreateFontFace(&directWriteFontFace);
+ if (SUCCEEDED(hr)) {
+ QFontEngineDirectWrite *fedw = new QFontEngineDirectWrite(db->directWriteFactory,
+ directWriteFontFace,
+ request.pixelSize);
+
+ initFontInfo(fedw, request, dpi, directWriteFont);
- fe = fedw;
+ fe = fedw;
+ } else {
+ qErrnoWarning(hr, "QFontEngine::loadEngine: CreateFontFace failed");
+ }
}
if (directWriteFont != 0)
@@ -957,6 +958,7 @@ QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &requ
if(script == QUnicodeTables::Common
&& !(request.styleStrategy & QFont::NoFontMerging)
+ && desc != 0
&& !(desc->family->writingSystems[QFontDatabase::Symbol] & QtFontFamily::Supported)) {
if(!tryFonts) {
LANGID lid = GetUserDefaultLangID();
@@ -993,6 +995,20 @@ QFontEngine *loadEngine(int script, const QFontPrivate *fp, const QFontDef &requ
return fe;
}
+QFontEngine *qt_load_font_engine_win(const QFontDef &request)
+{
+ // From qfont.cpp
+ extern int qt_defaultDpi();
+
+ QFontCache::Key key(request, QUnicodeTables::Common);
+ QFontEngine *fe = QFontCache::instance()->findEngine(key);
+ if (fe != 0)
+ return fe;
+ else
+ return loadEngine(QUnicodeTables::Common, request, 0, qt_defaultDpi(), false, 0,
+ QStringList());
+}
+
const char *styleHint(const QFontDef &request)
{
const char *stylehint = 0;
@@ -1053,7 +1069,7 @@ static QFontEngine *loadWin(const QFontPrivate *d, int script, const QFontDef &r
}
if (!desc.family)
break;
- fe = loadEngine(script, d, req, &desc, family_list);
+ fe = loadEngine(script, req, d->hdc, d->dpi, d->rawMode, &desc, family_list);
if (!fe)
blacklistedFamilies.append(desc.familyIndex);
}
diff --git a/src/gui/text/qfontengine.cpp b/src/gui/text/qfontengine.cpp
index 3adf4eb..2f76cc6 100644
--- a/src/gui/text/qfontengine.cpp
+++ b/src/gui/text/qfontengine.cpp
@@ -237,24 +237,6 @@ glyph_metrics_t QFontEngine::boundingBox(glyph_t glyph, const QTransform &matrix
return metrics;
}
-QFont QFontEngine::createExplicitFont() const
-{
- return createExplicitFontWithName(fontDef.family);
-}
-
-QFont QFontEngine::createExplicitFontWithName(const QString &familyName) const
-{
- QFont font(familyName);
- font.setStyleStrategy(QFont::NoFontMerging);
- font.setWeight(fontDef.weight);
- font.setItalic(fontDef.style == QFont::StyleItalic);
- if (fontDef.pointSize < 0)
- font.setPixelSize(fontDef.pixelSize);
- else
- font.setPointSizeF(fontDef.pointSize);
- return font;
-}
-
QFixed QFontEngine::xHeight() const
{
QGlyphLayoutArray<8> glyphs;
diff --git a/src/gui/text/qfontengine_coretext.mm b/src/gui/text/qfontengine_coretext.mm
index 4d9192e..20b3730 100644
--- a/src/gui/text/qfontengine_coretext.mm
+++ b/src/gui/text/qfontengine_coretext.mm
@@ -52,6 +52,31 @@ QT_BEGIN_NAMESPACE
static float SYNTHETIC_ITALIC_SKEW = tanf(14 * acosf(0) / 90);
+static void loadAdvancesForGlyphs(CTFontRef ctfont,
+ QVarLengthArray<CGGlyph> &cgGlyphs,
+ QGlyphLayout *glyphs, int len,
+ QTextEngine::ShaperFlags flags,
+ const QFontDef &fontDef)
+{
+ Q_UNUSED(flags);
+ QVarLengthArray<CGSize> advances(len);
+ CTFontGetAdvancesForGlyphs(ctfont, kCTFontHorizontalOrientation, cgGlyphs.data(), advances.data(), len);
+
+ for (int i = 0; i < len; ++i) {
+ if (glyphs->glyphs[i] & 0xff000000)
+ continue;
+ glyphs->advances_x[i] = QFixed::fromReal(advances[i].width);
+ glyphs->advances_y[i] = QFixed::fromReal(advances[i].height);
+ }
+
+ if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) {
+ for (int i = 0; i < len; ++i) {
+ glyphs->advances_x[i] = glyphs->advances_x[i].round();
+ glyphs->advances_y[i] = glyphs->advances_y[i].round();
+ }
+ }
+}
+
QCoreTextFontEngineMulti::QCoreTextFontEngineMulti(const QCFString &name, const QFontDef &fontDef, bool kerning)
: QFontEngineMulti(0)
{
@@ -83,7 +108,31 @@ QCoreTextFontEngineMulti::QCoreTextFontEngineMulti(const QCFString &name, const
ctfont = baseFont;
CFRetain(ctfont);
}
+ init(kerning);
+}
+
+QCoreTextFontEngineMulti::QCoreTextFontEngineMulti(CGFontRef cgFontRef, const QFontDef &fontDef, bool kerning)
+ : QFontEngineMulti(0)
+{
+ this->fontDef = fontDef;
+
+ transform = CGAffineTransformIdentity;
+ if (fontDef.stretch != 100) {
+ transform = CGAffineTransformMakeScale(float(fontDef.stretch) / float(100), 1);
+ }
+
+ ctfont = CTFontCreateWithGraphicsFont(cgFontRef, fontDef.pixelSize, &transform, NULL);
+ init(kerning);
+}
+
+QCoreTextFontEngineMulti::~QCoreTextFontEngineMulti()
+{
+ CFRelease(ctfont);
+}
+void QCoreTextFontEngineMulti::init(bool kerning)
+{
+ Q_ASSERT(ctfont != NULL);
attributeDict = CFDictionaryCreateMutable(0, 2,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
@@ -94,26 +143,20 @@ QCoreTextFontEngineMulti::QCoreTextFontEngineMulti(const QCFString &name, const
CFDictionaryAddValue(attributeDict, kCTKernAttributeName, noKern);
}
- QCoreTextFontEngine *fe = new QCoreTextFontEngine(ctfont, fontDef, this);
+ QCoreTextFontEngine *fe = new QCoreTextFontEngine(ctfont, fontDef);
fe->ref.ref();
engines.append(fe);
-
-}
-
-QCoreTextFontEngineMulti::~QCoreTextFontEngineMulti()
-{
- CFRelease(ctfont);
}
-uint QCoreTextFontEngineMulti::fontIndexForFont(CTFontRef id) const
+uint QCoreTextFontEngineMulti::fontIndexForFont(CTFontRef font) const
{
for (int i = 0; i < engines.count(); ++i) {
- if (CFEqual(engineAt(i)->ctfont, id))
+ if (CFEqual(engineAt(i)->ctfont, font))
return i;
}
QCoreTextFontEngineMulti *that = const_cast<QCoreTextFontEngineMulti *>(this);
- QCoreTextFontEngine *fe = new QCoreTextFontEngine(id, fontDef, that);
+ QCoreTextFontEngine *fe = new QCoreTextFontEngine(font, fontDef);
fe->ref.ref();
that->engines.append(fe);
return engines.count() - 1;
@@ -317,72 +360,45 @@ bool QCoreTextFontEngineMulti::stringToCMap(const QChar *str, int len, QGlyphLay
if (flags & QTextEngine::GlyphIndicesOnly)
return true;
- QVarLengthArray<CGSize> advances(len);
- CTFontGetAdvancesForGlyphs(ctfont, kCTFontHorizontalOrientation, cgGlyphs.data(), advances.data(), len);
-
- for (int i = 0; i < len; ++i) {
- if (glyphs->glyphs[i] & 0xff000000)
- continue;
- glyphs->advances_x[i] = QFixed::fromReal(advances[i].width);
- glyphs->advances_y[i] = QFixed::fromReal(advances[i].height);
- }
-
- if (fontDef.styleStrategy & QFont::ForceIntegerMetrics) {
- for (int i = 0; i < len; ++i) {
- glyphs->advances_x[i] = glyphs->advances_x[i].round();
- glyphs->advances_y[i] = glyphs->advances_y[i].round();
- }
- }
-
+ loadAdvancesForGlyphs(ctfont, cgGlyphs, glyphs, len, flags, fontDef);
return true;
}
-void QCoreTextFontEngineMulti::recalcAdvances(int , QGlyphLayout *, QTextEngine::ShaperFlags) const
-{
-}
-void QCoreTextFontEngineMulti::doKerning(int , QGlyphLayout *, QTextEngine::ShaperFlags) const
-{
-}
-
void QCoreTextFontEngineMulti::loadEngine(int)
{
// Do nothing
Q_ASSERT(false);
}
+extern int qt_antialiasing_threshold; // from qapplication.cpp
+static inline CGAffineTransform transformFromFontDef(const QFontDef &fontDef)
+{
+ CGAffineTransform transform = CGAffineTransformIdentity;
+ if (fontDef.stretch != 100)
+ transform = CGAffineTransformMakeScale(float(fontDef.stretch) / float(100), 1);
+ return transform;
+}
-QCoreTextFontEngine::QCoreTextFontEngine(CTFontRef font, const QFontDef &def,
- QCoreTextFontEngineMulti *multiEngine)
+QCoreTextFontEngine::QCoreTextFontEngine(CTFontRef font, const QFontDef &def)
{
fontDef = def;
- parentEngine = multiEngine;
- synthesisFlags = 0;
+ transform = transformFromFontDef(fontDef);
ctfont = font;
CFRetain(ctfont);
- cgFont = CTFontCopyGraphicsFont(ctfont, NULL);
- CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(ctfont);
- if (fontDef.weight >= QFont::Bold && !(traits & kCTFontBoldTrait)) {
- synthesisFlags |= SynthesizedBold;
- }
-
- if (fontDef.style != QFont::StyleNormal && !(traits & kCTFontItalicTrait)) {
- synthesisFlags |= SynthesizedItalic;
- }
- transform = CGAffineTransformIdentity;
- if (fontDef.stretch != 100) {
- transform = CGAffineTransformMakeScale(float(fontDef.stretch) / float(100), 1);
- }
- QByteArray os2Table = getSfntTable(MAKE_TAG('O', 'S', '/', '2'));
- if (os2Table.size() >= 10)
- fsType = qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(os2Table.constData() + 8));
+ cgFont = CTFontCopyGraphicsFont(font, NULL);
+ init();
+}
- QSettings appleSettings(QLatin1String("apple.com"));
- QVariant appleValue = appleSettings.value(QLatin1String("AppleAntiAliasingThreshold"));
- if (appleValue.isValid())
- antialiasing_threshold = appleValue.toInt();
- else
- antialiasing_threshold = -1;
+QCoreTextFontEngine::QCoreTextFontEngine(CGFontRef font, const QFontDef &def)
+{
+ fontDef = def;
+ transform = transformFromFontDef(fontDef);
+ cgFont = font;
+ // Keep reference count balanced
+ CFRetain(cgFont);
+ ctfont = CTFontCreateWithGraphicsFont(font, fontDef.pixelSize, &transform, NULL);
+ init();
}
QCoreTextFontEngine::~QCoreTextFontEngine()
@@ -391,9 +407,89 @@ QCoreTextFontEngine::~QCoreTextFontEngine()
CFRelease(ctfont);
}
-bool QCoreTextFontEngine::stringToCMap(const QChar *, int, QGlyphLayout *, int *, QTextEngine::ShaperFlags) const
+extern QFont::Weight weightFromInteger(int weight); // qfontdatabase.cpp
+
+int getTraitValue(CFDictionaryRef allTraits, CFStringRef trait)
{
- return false;
+ if (CFDictionaryContainsKey(allTraits, trait)) {
+ CFNumberRef traitNum = (CFNumberRef) CFDictionaryGetValue(allTraits, trait);
+ float v = 0;
+ CFNumberGetValue(traitNum, kCFNumberFloatType, &v);
+ // the value we get from CFNumberRef is from -1.0 to 1.0
+ int value = v * 500 + 500;
+ return value;
+ }
+
+ return 0;
+}
+
+void QCoreTextFontEngine::init()
+{
+ Q_ASSERT(ctfont != NULL);
+ Q_ASSERT(cgFont != NULL);
+
+ QCFString family = CTFontCopyFamilyName(ctfont);
+ fontDef.family = family;
+
+ synthesisFlags = 0;
+ CTFontSymbolicTraits traits = CTFontGetSymbolicTraits(ctfont);
+ if (traits & kCTFontItalicTrait)
+ fontDef.style = QFont::StyleItalic;
+
+ CFDictionaryRef allTraits = CTFontCopyTraits(ctfont);
+ fontDef.weight = weightFromInteger(getTraitValue(allTraits, kCTFontWeightTrait));
+ int slant = getTraitValue(allTraits, kCTFontSlantTrait);
+ if (slant > 500 && !(traits & kCTFontItalicTrait))
+ fontDef.style = QFont::StyleOblique;
+ CFRelease(allTraits);
+
+ if (fontDef.weight >= QFont::Bold && !(traits & kCTFontBoldTrait))
+ synthesisFlags |= SynthesizedBold;
+ // XXX: we probably don't need to synthesis italic for oblique font
+ if (fontDef.style != QFont::StyleNormal && !(traits & kCTFontItalicTrait))
+ synthesisFlags |= SynthesizedItalic;
+
+ avgCharWidth = 0;
+ QByteArray os2Table = getSfntTable(MAKE_TAG('O', 'S', '/', '2'));
+ unsigned emSize = CTFontGetUnitsPerEm(ctfont);
+ if (os2Table.size() >= 10) {
+ fsType = qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(os2Table.constData() + 8));
+ // qAbs is a workaround for weird fonts like Lucida Grande
+ qint16 width = qAbs(qFromBigEndian<qint16>(reinterpret_cast<const uchar *>(os2Table.constData() + 2)));
+ avgCharWidth = QFixed::fromReal(width * fontDef.pixelSize / emSize);
+ } else
+ avgCharWidth = QFontEngine::averageCharWidth();
+
+ ctMaxCharWidth = ctMinLeftBearing = ctMinRightBearing = 0;
+ QByteArray hheaTable = getSfntTable(MAKE_TAG('h', 'h', 'e', 'a'));
+ if (hheaTable.size() >= 16) {
+ quint16 width = qFromBigEndian<quint16>(reinterpret_cast<const uchar *>(hheaTable.constData() + 10));
+ ctMaxCharWidth = width * fontDef.pixelSize / emSize;
+ qint16 bearing = qFromBigEndian<qint16>(reinterpret_cast<const uchar *>(hheaTable.constData() + 12));
+ ctMinLeftBearing = bearing * fontDef.pixelSize / emSize;
+ bearing = qFromBigEndian<qint16>(reinterpret_cast<const uchar *>(hheaTable.constData() + 14));
+ ctMinRightBearing = bearing * fontDef.pixelSize / emSize;
+ }
+}
+
+bool QCoreTextFontEngine::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs,
+ int *nglyphs, QTextEngine::ShaperFlags flags) const
+{
+ *nglyphs = len;
+ QCFType<CFStringRef> cfstring;
+
+ QVarLengthArray<CGGlyph> cgGlyphs(len);
+ CTFontGetGlyphsForCharacters(ctfont, (const UniChar*)str, cgGlyphs.data(), len);
+
+ for (int i = 0; i < len; ++i)
+ if (cgGlyphs[i])
+ glyphs->glyphs[i] = cgGlyphs[i];
+
+ if (flags & QTextEngine::GlyphIndicesOnly)
+ return true;
+
+ loadAdvancesForGlyphs(ctfont, cgGlyphs, glyphs, len, flags, fontDef);
+ return true;
}
glyph_metrics_t QCoreTextFontEngine::boundingBox(const QGlyphLayout &glyphs)
@@ -407,6 +503,7 @@ glyph_metrics_t QCoreTextFontEngine::boundingBox(const QGlyphLayout &glyphs)
}
return glyph_metrics_t(0, -(ascent()), w - lastRightBearing(glyphs, round), ascent()+descent(), w, 0);
}
+
glyph_metrics_t QCoreTextFontEngine::boundingBox(glyph_t glyph)
{
glyph_metrics_t ret;
@@ -460,31 +557,29 @@ QFixed QCoreTextFontEngine::xHeight() const
? QFixed::fromReal(CTFontGetXHeight(ctfont)).round()
: QFixed::fromReal(CTFontGetXHeight(ctfont));
}
+
QFixed QCoreTextFontEngine::averageCharWidth() const
{
- // ### Need to implement properly and get the information from the OS/2 Table.
return (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
- ? QFontEngine::averageCharWidth().round()
- : QFontEngine::averageCharWidth();
+ ? avgCharWidth.round() : avgCharWidth;
}
qreal QCoreTextFontEngine::maxCharWidth() const
{
- // ### Max Help!
- return 0;
-
+ return (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
+ ? qRound(ctMaxCharWidth) : ctMaxCharWidth;
}
+
qreal QCoreTextFontEngine::minLeftBearing() const
{
- // ### Min Help!
- return 0;
-
+ return (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
+ ? qRound(ctMinLeftBearing) : ctMinLeftBearing;
}
+
qreal QCoreTextFontEngine::minRightBearing() const
{
- // ### Max Help! (even thought it's right)
- return 0;
-
+ return (fontDef.styleStrategy & QFont::ForceIntegerMetrics)
+ ? qRound(ctMinRightBearing) : ctMinLeftBearing;
}
void QCoreTextFontEngine::draw(CGContextRef ctx, qreal x, qreal y, const QTextItemInt &ti, int paintDeviceHeight)
@@ -602,12 +697,6 @@ void QCoreTextFontEngine::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *position
}
}
-QFont QCoreTextFontEngine::createExplicitFont() const
-{
- QString familyName = QCFString::toQString(CTFontCopyFamilyName(ctfont));
- return createExplicitFontWithName(familyName);
-}
-
QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition, int /*margin*/, bool aa)
{
const glyph_metrics_t br = boundingBox(glyph);
@@ -624,7 +713,7 @@ QImage QCoreTextFontEngine::imageForGlyph(glyph_t glyph, QFixed subPixelPosition
cgflags);
CGContextSetFontSize(ctx, fontDef.pixelSize);
CGContextSetShouldAntialias(ctx, aa ||
- (fontDef.pointSize > antialiasing_threshold
+ (fontDef.pointSize > qt_antialiasing_threshold
&& !(fontDef.styleStrategy & QFont::NoAntialias)));
CGContextSetShouldSmoothFonts(ctx, aa);
CGAffineTransform oldTextMatrix = CGContextGetTextMatrix(ctx);
@@ -696,12 +785,19 @@ QImage QCoreTextFontEngine::alphaRGBMapForGlyph(glyph_t glyph, QFixed subPixelPo
return im;
}
-void QCoreTextFontEngine::recalcAdvances(int numGlyphs, QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
+void QCoreTextFontEngine::recalcAdvances(QGlyphLayout *glyphs, QTextEngine::ShaperFlags flags) const
{
- Q_ASSERT(false);
- Q_UNUSED(numGlyphs);
- Q_UNUSED(glyphs);
- Q_UNUSED(flags);
+ int i, numGlyphs = glyphs->numGlyphs;
+ QVarLengthArray<CGGlyph> cgGlyphs(numGlyphs);
+
+ for (i = 0; i < numGlyphs; ++i) {
+ if (glyphs->glyphs[i] & 0xff000000)
+ cgGlyphs[i] = 0;
+ else
+ cgGlyphs[i] = glyphs->glyphs[i];
+ }
+
+ loadAdvancesForGlyphs(ctfont, cgGlyphs, glyphs, numGlyphs, flags, fontDef);
}
QFontEngine::FaceId QCoreTextFontEngine::faceId() const
@@ -711,36 +807,36 @@ QFontEngine::FaceId QCoreTextFontEngine::faceId() const
bool QCoreTextFontEngine::canRender(const QChar *string, int len)
{
- QCFType<CTFontRef> retFont = CTFontCreateForString(ctfont,
- QCFType<CFStringRef>(CFStringCreateWithCharactersNoCopy(0,
- reinterpret_cast<const UniChar *>(string),
- len, kCFAllocatorNull)),
- CFRangeMake(0, len));
- return retFont != 0;
- return false;
-}
-
- bool QCoreTextFontEngine::getSfntTableData(uint tag, uchar *buffer, uint *length) const
- {
- QCFType<CFDataRef> table = CTFontCopyTable(ctfont, tag, 0);
- if (!table || !length)
- return false;
- CFIndex tableLength = CFDataGetLength(table);
- int availableLength = *length;
- *length = tableLength;
- if (buffer) {
- if (tableLength > availableLength)
- return false;
- CFDataGetBytes(table, CFRangeMake(0, tableLength), buffer);
- }
- return true;
- }
+ QVarLengthArray<CGGlyph> cgGlyphs(len);
+ return CTFontGetGlyphsForCharacters(ctfont, (const UniChar *) string, cgGlyphs.data(), len);
+}
+
+bool QCoreTextFontEngine::getSfntTableData(uint tag, uchar *buffer, uint *length) const
+{
+ QCFType<CFDataRef> table = CTFontCopyTable(ctfont, tag, 0);
+ if (!table || !length)
+ return false;
+ CFIndex tableLength = CFDataGetLength(table);
+ int availableLength = *length;
+ *length = tableLength;
+ if (buffer) {
+ if (tableLength > availableLength)
+ return false;
+ CFDataGetBytes(table, CFRangeMake(0, tableLength), buffer);
+ }
+ return true;
+}
void QCoreTextFontEngine::getUnscaledGlyph(glyph_t, QPainterPath *, glyph_metrics_t *)
{
// ###
}
+QFixed QCoreTextFontEngine::emSquareSize() const
+{
+ return QFixed::QFixed(int(CTFontGetUnitsPerEm(ctfont)));
+}
+
QT_END_NAMESPACE
#endif// !defined(Q_WS_MAC) || (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
diff --git a/src/gui/text/qfontengine_coretext_p.h b/src/gui/text/qfontengine_coretext_p.h
index 7d17aef..1503c3f 100644
--- a/src/gui/text/qfontengine_coretext_p.h
+++ b/src/gui/text/qfontengine_coretext_p.h
@@ -46,15 +46,17 @@
#if !defined(Q_WS_MAC) || (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
+class QRawFontPrivate;
class QCoreTextFontEngineMulti;
class QCoreTextFontEngine : public QFontEngine
{
public:
- QCoreTextFontEngine(CTFontRef font, const QFontDef &def,
- QCoreTextFontEngineMulti *multiEngine = 0);
+ QCoreTextFontEngine(CTFontRef font, const QFontDef &def);
+ QCoreTextFontEngine(CGFontRef font, const QFontDef &def);
~QCoreTextFontEngine();
+
virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs, QTextEngine::ShaperFlags flags) const;
- virtual void recalcAdvances(int , QGlyphLayout *, QTextEngine::ShaperFlags) const;
+ virtual void recalcAdvances(QGlyphLayout *, QTextEngine::ShaperFlags) const;
virtual glyph_metrics_t boundingBox(const QGlyphLayout &glyphs);
virtual glyph_metrics_t boundingBox(glyph_t glyph);
@@ -87,23 +89,29 @@ public:
virtual QImage alphaRGBMapForGlyph(glyph_t, QFixed subPixelPosition, int margin, const QTransform &t);
virtual qreal minRightBearing() const;
virtual qreal minLeftBearing() const;
- virtual QFont createExplicitFont() const;
+ virtual QFixed emSquareSize() const;
private:
+ friend class QRawFontPrivate;
+
+ void init();
QImage imageForGlyph(glyph_t glyph, QFixed subPixelPosition, int margin, bool colorful);
CTFontRef ctfont;
CGFontRef cgFont;
- QCoreTextFontEngineMulti *parentEngine;
int synthesisFlags;
CGAffineTransform transform;
+ QFixed avgCharWidth;
+ qreal ctMaxCharWidth;
+ qreal ctMinLeftBearing;
+ qreal ctMinRightBearing;
friend class QCoreTextFontEngineMulti;
- int antialiasing_threshold;
};
class QCoreTextFontEngineMulti : public QFontEngineMulti
{
public:
QCoreTextFontEngineMulti(const QCFString &name, const QFontDef &fontDef, bool kerning);
+ QCoreTextFontEngineMulti(CGFontRef cgFontRef, const QFontDef &fontDef, bool kerning);
~QCoreTextFontEngineMulti();
virtual bool stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs, int *nglyphs,
@@ -112,19 +120,16 @@ public:
QTextEngine::ShaperFlags flags,
unsigned short *logClusters, const HB_CharAttributes *charAttributes) const;
-
- virtual void recalcAdvances(int , QGlyphLayout *, QTextEngine::ShaperFlags) const;
- virtual void doKerning(int , QGlyphLayout *, QTextEngine::ShaperFlags) const;
-
virtual const char *name() const { return "CoreText"; }
protected:
virtual void loadEngine(int at);
private:
+ void init(bool kerning);
inline const QCoreTextFontEngine *engineAt(int i) const
{ return static_cast<const QCoreTextFontEngine *>(engines.at(i)); }
- uint fontIndexForFont(CTFontRef id) const;
+ uint fontIndexForFont(CTFontRef font) const;
CTFontRef ctfont;
mutable QCFType<CFMutableDictionaryRef> attributeDict;
CGAffineTransform transform;
diff --git a/src/gui/text/qfontengine_ft.cpp b/src/gui/text/qfontengine_ft.cpp
index ffdaaa7..8f2da9b 100644
--- a/src/gui/text/qfontengine_ft.cpp
+++ b/src/gui/text/qfontengine_ft.cpp
@@ -200,9 +200,10 @@ HB_Error QFreetypeFace::getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 p
* Returns the freetype face or 0 in case of an empty file or any other problems
* (like not being able to open the file)
*/
-QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id)
+QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id,
+ const QByteArray &fontData)
{
- if (face_id.filename.isEmpty())
+ if (face_id.filename.isEmpty() && fontData.isEmpty())
return 0;
QtFreetypeData *freetypeData = qt_getFreetypeData();
@@ -215,21 +216,25 @@ QFreetypeFace *QFreetypeFace::getFace(const QFontEngine::FaceId &face_id)
} else {
QScopedPointer<QFreetypeFace> newFreetype(new QFreetypeFace);
FT_Face face;
- QFile file(QString::fromUtf8(face_id.filename));
- if (face_id.filename.startsWith(":qmemoryfonts/")) {
- // from qfontdatabase.cpp
- extern QByteArray qt_fontdata_from_index(int);
- QByteArray idx = face_id.filename;
- idx.remove(0, 14); // remove ':qmemoryfonts/'
- bool ok = false;
- newFreetype->fontData = qt_fontdata_from_index(idx.toInt(&ok));
- if (!ok)
- newFreetype->fontData = QByteArray();
- } else if (!(file.fileEngine()->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::LocalDiskFlag)) {
- if (!file.open(QIODevice::ReadOnly)) {
- return 0;
+ if (!face_id.filename.isEmpty()) {
+ QFile file(QString::fromUtf8(face_id.filename));
+ if (face_id.filename.startsWith(":qmemoryfonts/")) {
+ // from qfontdatabase.cpp
+ extern QByteArray qt_fontdata_from_index(int);
+ QByteArray idx = face_id.filename;
+ idx.remove(0, 14); // remove ':qmemoryfonts/'
+ bool ok = false;
+ newFreetype->fontData = qt_fontdata_from_index(idx.toInt(&ok));
+ if (!ok)
+ newFreetype->fontData = QByteArray();
+ } else if (!(file.fileEngine()->fileFlags(QAbstractFileEngine::FlagsMask) & QAbstractFileEngine::LocalDiskFlag)) {
+ if (!file.open(QIODevice::ReadOnly)) {
+ return 0;
+ }
+ newFreetype->fontData = file.readAll();
}
- newFreetype->fontData = file.readAll();
+ } else {
+ newFreetype->fontData = fontData;
}
if (!newFreetype->fontData.isEmpty()) {
if (FT_New_Memory_Face(freetypeData->library, (const FT_Byte *)newFreetype->fontData.constData(), newFreetype->fontData.size(), face_id.index, &face)) {
@@ -651,8 +656,21 @@ void QFontEngineFT::freeGlyphSets()
freeServerGlyphSet(transformedGlyphSets.at(i).id);
}
-bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format)
+bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
+ const QByteArray &fontData)
{
+ return init(faceId, antialias, format, QFreetypeFace::getFace(faceId, fontData));
+}
+
+bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format,
+ QFreetypeFace *freetypeFace)
+{
+ freetype = freetypeFace;
+ if (!freetype) {
+ xsize = 0;
+ ysize = 0;
+ return false;
+ }
defaultFormat = format;
this->antialias = antialias;
@@ -664,12 +682,6 @@ bool QFontEngineFT::init(FaceId faceId, bool antialias, GlyphFormat format)
glyphFormat = QFontEngineGlyphCache::Raster_RGBMask;
face_id = faceId;
- freetype = QFreetypeFace::getFace(face_id);
- if (!freetype) {
- xsize = 0;
- ysize = 0;
- return false;
- }
symbol = freetype->symbol_map != 0;
PS_FontInfoRec psrec;
@@ -791,6 +803,106 @@ int QFontEngineFT::loadFlags(QGlyphSet *set, GlyphFormat format, int flags,
return load_flags;
}
+QFontEngineFT::Glyph *QFontEngineFT::loadGlyphMetrics(QGlyphSet *set, uint glyph, GlyphFormat format) const
+{
+ Glyph *g = set->getGlyph(glyph);
+ if (g && g->format == format)
+ return g;
+
+ bool hsubpixel = false;
+ int vfactor = 1;
+ int load_flags = loadFlags(set, format, 0, hsubpixel, vfactor);
+
+ // apply our matrix to this, but note that the metrics will not be affected by this.
+ FT_Face face = lockFace();
+ FT_Matrix matrix = this->matrix;
+ FT_Matrix_Multiply(&set->transformationMatrix, &matrix);
+ FT_Set_Transform(face, &matrix, 0);
+ freetype->matrix = matrix;
+
+ bool transform = matrix.xx != 0x10000 || matrix.yy != 0x10000 || matrix.xy != 0 || matrix.yx != 0;
+ if (transform)
+ load_flags |= FT_LOAD_NO_BITMAP;
+
+ FT_Error err = FT_Load_Glyph(face, glyph, load_flags);
+ if (err && (load_flags & FT_LOAD_NO_BITMAP)) {
+ load_flags &= ~FT_LOAD_NO_BITMAP;
+ err = FT_Load_Glyph(face, glyph, load_flags);
+ }
+ if (err == FT_Err_Too_Few_Arguments) {
+ // this is an error in the bytecode interpreter, just try to run without it
+ load_flags |= FT_LOAD_FORCE_AUTOHINT;
+ err = FT_Load_Glyph(face, glyph, load_flags);
+ }
+ if (err != FT_Err_Ok)
+ qWarning("load glyph failed err=%x face=%p, glyph=%d", err, face, glyph);
+
+ unlockFace();
+ if (set->outline_drawing)
+ return 0;
+
+ if (!g) {
+ g = new Glyph;
+ g->uploadedToServer = false;
+ g->data = 0;
+ }
+
+ FT_GlyphSlot slot = face->glyph;
+ if (embolden) Q_FT_GLYPHSLOT_EMBOLDEN(slot);
+ int left = slot->metrics.horiBearingX;
+ int right = slot->metrics.horiBearingX + slot->metrics.width;
+ int top = slot->metrics.horiBearingY;
+ int bottom = slot->metrics.horiBearingY - slot->metrics.height;
+ if (transform && slot->format != FT_GLYPH_FORMAT_BITMAP) { // freetype doesn't apply the transformation on the metrics
+ int l, r, t, b;
+ FT_Vector vector;
+ vector.x = left;
+ vector.y = top;
+ FT_Vector_Transform(&vector, &matrix);
+ l = r = vector.x;
+ t = b = vector.y;
+ vector.x = right;
+ vector.y = top;
+ FT_Vector_Transform(&vector, &matrix);
+ if (l > vector.x) l = vector.x;
+ if (r < vector.x) r = vector.x;
+ if (t < vector.y) t = vector.y;
+ if (b > vector.y) b = vector.y;
+ vector.x = right;
+ vector.y = bottom;
+ FT_Vector_Transform(&vector, &matrix);
+ if (l > vector.x) l = vector.x;
+ if (r < vector.x) r = vector.x;
+ if (t < vector.y) t = vector.y;
+ if (b > vector.y) b = vector.y;
+ vector.x = left;
+ vector.y = bottom;
+ FT_Vector_Transform(&vector, &matrix);
+ if (l > vector.x) l = vector.x;
+ if (r < vector.x) r = vector.x;
+ if (t < vector.y) t = vector.y;
+ if (b > vector.y) b = vector.y;
+ left = l;
+ right = r;
+ top = t;
+ bottom = b;
+ }
+ left = FLOOR(left);
+ right = CEIL(right);
+ bottom = FLOOR(bottom);
+ top = CEIL(top);
+
+ g->linearAdvance = face->glyph->linearHoriAdvance >> 10;
+ g->width = TRUNC(right-left);
+ g->height = TRUNC(top-bottom);
+ g->x = TRUNC(left);
+ g->y = TRUNC(top);
+ g->advance = TRUNC(ROUND(face->glyph->advance.x));
+ g->format = Format_None;
+
+ return g;
+}
+
QFontEngineFT::Glyph *QFontEngineFT::loadGlyph(QGlyphSet *set, uint glyph,
QFixed subPixelPosition,
GlyphFormat format,
@@ -1511,7 +1623,7 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs
mtx->lock();
}
- if (FcCharSetHasChar(freetype->charset, uc)) {
+ if (freetype->charset != 0 && FcCharSetHasChar(freetype->charset, uc)) {
#else
if (false) {
#endif
@@ -1546,7 +1658,7 @@ bool QFontEngineFT::stringToCMap(const QChar *str, int len, QGlyphLayout *glyphs
mtx->lock();
}
- if (FcCharSetHasChar(freetype->charset, uc))
+ if (freetype->charset == 0 || FcCharSetHasChar(freetype->charset, uc))
#endif
{
redo:
diff --git a/src/gui/text/qfontengine_ft_p.h b/src/gui/text/qfontengine_ft_p.h
index 451d26e..887efed 100644
--- a/src/gui/text/qfontengine_ft_p.h
+++ b/src/gui/text/qfontengine_ft_p.h
@@ -74,6 +74,8 @@
QT_BEGIN_NAMESPACE
+class QFontEngineFTRawFont;
+
/*
* This struct represents one font file on disk (like Arial.ttf) and is shared between all the font engines
* that show this font file (at different pixel sizes).
@@ -84,7 +86,8 @@ struct QFreetypeFace
QFontEngine::Properties properties() const;
bool getSfntTable(uint tag, uchar *buffer, uint *length) const;
- static QFreetypeFace *getFace(const QFontEngine::FaceId &face_id);
+ static QFreetypeFace *getFace(const QFontEngine::FaceId &face_id,
+ const QByteArray &fontData = QByteArray());
void release(const QFontEngine::FaceId &face_id);
// locks the struct for usage. Any read/write operations require locking.
@@ -119,6 +122,7 @@ struct QFreetypeFace
static void addBitmapToPath(FT_GlyphSlot slot, const QFixedPoint &point, QPainterPath *path, bool = false);
private:
+ friend class QFontEngineFTRawFont;
friend class QScopedPointerDeleter<QFreetypeFace>;
QFreetypeFace() : _lock(QMutex::Recursive) {}
~QFreetypeFace() {}
@@ -300,7 +304,10 @@ private:
QFontEngineFT(const QFontDef &fd);
virtual ~QFontEngineFT();
- bool init(FaceId faceId, bool antiaalias, GlyphFormat defaultFormat = Format_None);
+ bool init(FaceId faceId, bool antiaalias, GlyphFormat defaultFormat = Format_None,
+ const QByteArray &fontData = QByteArray());
+ bool init(FaceId faceId, bool antialias, GlyphFormat format,
+ QFreetypeFace *freetypeFace);
virtual HB_Error getPointInOutline(HB_Glyph glyph, int flags, hb_uint32 point, HB_Fixed *xpos, HB_Fixed *ypos, hb_uint32 *nPoints);
@@ -312,6 +319,7 @@ private:
};
void setDefaultHintStyle(HintStyle style);
+ HintStyle defaultHintStyle() const { return default_hint_style; }
protected:
void freeGlyphSets();
@@ -335,6 +343,9 @@ protected:
bool embeddedbitmap;
private:
+ friend class QFontEngineFTRawFont;
+
+ QFontEngineFT::Glyph *loadGlyphMetrics(QGlyphSet *set, uint glyph, GlyphFormat format) const;
int loadFlags(QGlyphSet *set, GlyphFormat format, int flags, bool &hsubpixel, int &vfactor) const;
GlyphFormat defaultFormat;
diff --git a/src/gui/text/qfontengine_mac.mm b/src/gui/text/qfontengine_mac.mm
index 7751bbe..673a7c8 100644
--- a/src/gui/text/qfontengine_mac.mm
+++ b/src/gui/text/qfontengine_mac.mm
@@ -922,27 +922,6 @@ static void addGlyphsToPathHelper(ATSUStyle style, glyph_t *glyphs, QFixedPoint
DisposeATSCubicClosePathUPP(closePath);
}
-QFont QFontEngineMac::createExplicitFont() const
-{
- FMFont fmFont = FMGetFontFromATSFontRef(fontID);
-
- FMFontFamily fmFamily;
- FMFontStyle fmStyle;
- QString familyName;
- if (!FMGetFontFamilyInstanceFromFont(fmFont, &fmFamily, &fmStyle)) {
- ATSFontFamilyRef familyRef = FMGetATSFontFamilyRefFromFontFamily(fmFamily);
- QCFString cfFamilyName;;
- ATSFontFamilyGetName(familyRef, kATSOptionFlagsDefault, &cfFamilyName);
- familyName = cfFamilyName;
- } else {
- QCFString cfFontName;
- ATSFontGetName(fontID, kATSOptionFlagsDefault, &cfFontName);
- familyName = cfFontName;
- }
-
- return createExplicitFontWithName(familyName);
-}
-
void QFontEngineMac::addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs, QPainterPath *path,
QTextItem::RenderFlags)
{
diff --git a/src/gui/text/qfontengine_mac_p.h b/src/gui/text/qfontengine_mac_p.h
index 6967348..385fa83 100644
--- a/src/gui/text/qfontengine_mac_p.h
+++ b/src/gui/text/qfontengine_mac_p.h
@@ -66,8 +66,6 @@ public:
virtual qreal maxCharWidth() const;
virtual QFixed averageCharWidth() const;
- virtual QFont createExplicitFont() const;
-
virtual void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int numGlyphs,
QPainterPath *path, QTextItem::RenderFlags);
diff --git a/src/gui/text/qfontengine_p.h b/src/gui/text/qfontengine_p.h
index 7b29993..5b39fd3 100644
--- a/src/gui/text/qfontengine_p.h
+++ b/src/gui/text/qfontengine_p.h
@@ -185,9 +185,6 @@ public:
virtual void addGlyphsToPath(glyph_t *glyphs, QFixedPoint *positions, int nglyphs,
QPainterPath *path, QTextItem::RenderFlags flags);
- /* Creates a QFont object to represent this particular QFontEngine */
- virtual QFont createExplicitFont() const;
-
void getGlyphPositions(const QGlyphLayout &glyphs, const QTransform &matrix, QTextItem::RenderFlags flags,
QVarLengthArray<glyph_t> &glyphs_out, QVarLengthArray<QFixedPoint> &positions);
@@ -276,7 +273,6 @@ public:
int glyphFormat;
protected:
- QFont createExplicitFontWithName(const QString &familyName) const;
static const QVector<QRgb> &grayPalette();
QFixed lastRightBearing(const QGlyphLayout &glyphs, bool round = false);
@@ -431,6 +427,7 @@ public:
protected:
friend class QPSPrintEnginePrivate;
friend class QPSPrintEngineFontMulti;
+ friend class QRawFont;
virtual void loadEngine(int at) = 0;
QVector<QFontEngine *> engines;
};
diff --git a/src/gui/text/qfontengine_x11_p.h b/src/gui/text/qfontengine_x11_p.h
index 2a4a9cd..ad68fac 100644
--- a/src/gui/text/qfontengine_x11_p.h
+++ b/src/gui/text/qfontengine_x11_p.h
@@ -157,6 +157,7 @@ private:
class Q_GUI_EXPORT QFontEngineX11FT : public QFontEngineFT
{
public:
+ explicit QFontEngineX11FT(const QFontDef &fontDef) : QFontEngineFT(fontDef) {}
explicit QFontEngineX11FT(FcPattern *pattern, const QFontDef &fd, int screen);
~QFontEngineX11FT();
diff --git a/src/gui/text/qfontenginedirectwrite.cpp b/src/gui/text/qfontenginedirectwrite.cpp
index af5bab2..f0a3644 100644
--- a/src/gui/text/qfontenginedirectwrite.cpp
+++ b/src/gui/text/qfontenginedirectwrite.cpp
@@ -170,17 +170,12 @@ namespace {
}
-QFontEngineDirectWrite::QFontEngineDirectWrite(const QString &name,
- IDWriteFactory *directWriteFactory,
- IDWriteGdiInterop *directWriteGdiInterop,
- IDWriteFont *directWriteFont,
+QFontEngineDirectWrite::QFontEngineDirectWrite(IDWriteFactory *directWriteFactory,
+ IDWriteFontFace *directWriteFontFace,
qreal pixelSize)
- : m_name(name)
- , m_directWriteFont(directWriteFont)
- , m_directWriteFontFace(0)
+ : m_directWriteFontFace(directWriteFontFace)
, m_directWriteFactory(directWriteFactory)
, m_directWriteBitmapRenderTarget(0)
- , m_directWriteGdiInterop(directWriteGdiInterop)
, m_lineThickness(-1)
, m_unitsPerEm(-1)
, m_ascent(-1)
@@ -188,24 +183,17 @@ QFontEngineDirectWrite::QFontEngineDirectWrite(const QString &name,
, m_xHeight(-1)
, m_lineGap(-1)
{
- m_directWriteFont->AddRef();
m_directWriteFactory->AddRef();
- m_directWriteGdiInterop->AddRef();
+ m_directWriteFontFace->AddRef();
fontDef.pixelSize = pixelSize;
-
- HRESULT hr = m_directWriteFont->CreateFontFace(&m_directWriteFontFace);
- if (FAILED(hr))
- qErrnoWarning("QFontEngineDirectWrite: CreateFontFace failed");
-
collectMetrics();
}
QFontEngineDirectWrite::~QFontEngineDirectWrite()
{
- m_directWriteFont->Release();
m_directWriteFactory->Release();
- m_directWriteGdiInterop->Release();
+ m_directWriteFontFace->Release();
if (m_directWriteBitmapRenderTarget != 0)
m_directWriteBitmapRenderTarget->Release();
@@ -213,10 +201,10 @@ QFontEngineDirectWrite::~QFontEngineDirectWrite()
void QFontEngineDirectWrite::collectMetrics()
{
- if (m_directWriteFont != 0) {
+ if (m_directWriteFontFace != 0) {
DWRITE_FONT_METRICS metrics;
- m_directWriteFont->GetMetrics(&metrics);
+ m_directWriteFontFace->GetMetrics(&metrics);
m_unitsPerEm = metrics.designUnitsPerEm;
m_lineThickness = DESIGN_TO_LOGICAL(metrics.underlineThickness);
@@ -616,19 +604,25 @@ const char *QFontEngineDirectWrite::name() const
bool QFontEngineDirectWrite::canRender(const QChar *string, int len)
{
- for (int i=0; i<len; ++i) {
- BOOL exists;
- UINT32 codePoint = getChar(string, i, len);
- HRESULT hr = m_directWriteFont->HasCharacter(codePoint, &exists);
- if (FAILED(hr)) {
- qErrnoWarning("QFontEngineDirectWrite::canRender: HasCharacter failed");
- return false;
- } else if (!exists) {
- return false;
+ QVarLengthArray<UINT32> codePoints(len);
+ int actualLength = 0;
+ for (int i=0; i<len; ++i, actualLength++)
+ codePoints[actualLength] = getChar(string, i, len);
+
+ QVarLengthArray<UINT16> glyphIndices(actualLength);
+ HRESULT hr = m_directWriteFontFace->GetGlyphIndices(codePoints.data(), actualLength,
+ glyphIndices.data());
+ if (FAILED(hr)) {
+ qErrnoWarning(hr, "QFontEngineDirectWrite::canRender: GetGlyphIndices failed");
+ return false;
+ } else {
+ for (int i=0; i<glyphIndices.size(); ++i) {
+ if (glyphIndices.at(i) == 0)
+ return false;
}
- }
- return true;
+ return true;
+ }
}
QFontEngine::Type QFontEngineDirectWrite::type() const
diff --git a/src/gui/text/qfontenginedirectwrite_p.h b/src/gui/text/qfontenginedirectwrite_p.h
index 80f90b8..c440a6c 100644
--- a/src/gui/text/qfontenginedirectwrite_p.h
+++ b/src/gui/text/qfontenginedirectwrite_p.h
@@ -69,10 +69,8 @@ class QFontEngineDirectWrite : public QFontEngine
{
Q_OBJECT
public:
- explicit QFontEngineDirectWrite(const QString &name,
- IDWriteFactory *directWriteFactory,
- IDWriteGdiInterop *directWriteGdiInterop,
- IDWriteFont *directWriteFont,
+ explicit QFontEngineDirectWrite(IDWriteFactory *directWriteFactory,
+ IDWriteFontFace *directWriteFontFace,
qreal pixelSize);
~QFontEngineDirectWrite();
@@ -107,15 +105,14 @@ public:
Type type() const;
private:
+ friend class QRawFontPrivate;
+
QImage imageForGlyph(glyph_t t, QFixed subPixelPosition, int margin, const QTransform &xform);
void collectMetrics();
- QString m_name;
- IDWriteFont *m_directWriteFont;
IDWriteFontFace *m_directWriteFontFace;
IDWriteFactory *m_directWriteFactory;
IDWriteBitmapRenderTarget *m_directWriteBitmapRenderTarget;
- IDWriteGdiInterop *m_directWriteGdiInterop;
QFixed m_lineThickness;
int m_unitsPerEm;
diff --git a/src/gui/text/qglyphs.cpp b/src/gui/text/qglyphs.cpp
index affa08a..cfea6ec 100644
--- a/src/gui/text/qglyphs.cpp
+++ b/src/gui/text/qglyphs.cpp
@@ -39,6 +39,10 @@
**
****************************************************************************/
+#include "qglobal.h"
+
+#if !defined(QT_NO_RAWFONT)
+
#include "qglyphs.h"
#include "qglyphs_p.h"
@@ -46,7 +50,7 @@ QT_BEGIN_NAMESPACE
/*!
\class QGlyphs
- \brief the QGlyphs class provides direct access to the internal glyphs in a font
+ \brief The QGlyphs class provides direct access to the internal glyphs in a font.
\since 4.8
\ingroup text
@@ -69,8 +73,14 @@ QT_BEGIN_NAMESPACE
It is the user's responsibility to ensure that the selected font actually contains the
provided glyph indexes.
- QTextLayout::glyphs() can be used to convert unicode encoded text into a list of QGlyphs
- objects, and QPainter::drawGlyphs() can be used to draw the glyphs.
+ QTextLayout::glyphs() or QTextFragment::glyphs() can be used to convert unicode encoded text
+ into a list of QGlyphs objects, and QPainter::drawGlyphs() can be used to draw the glyphs.
+
+ \note Please note that QRawFont is considered local to the thread in which it is constructed.
+ This in turn means that a new QRawFont will have to be created and set on the QGlyphs if it is
+ moved to a different thread. If the QGlyphs contains a reference to a QRawFont from a different
+ thread than the current, it will not be possible to draw the glyphs using a QPainter, as the
+ QRawFont is considered invalid and inaccessible in this case.
*/
@@ -124,6 +134,9 @@ bool QGlyphs::operator==(const QGlyphs &other) const
return ((d == other.d)
|| (d->glyphIndexes == other.d->glyphIndexes
&& d->glyphPositions == other.d->glyphPositions
+ && d->overline == other.d->overline
+ && d->underline == other.d->underline
+ && d->strikeOut == other.d->strikeOut
&& d->font == other.d->font));
}
@@ -171,18 +184,17 @@ QGlyphs &QGlyphs::operator+=(const QGlyphs &other)
\sa setFont()
*/
-QFont QGlyphs::font() const
+QRawFont QGlyphs::font() const
{
return d->font;
}
/*!
- Sets the font in which to look up the glyph indexes to \a font. This must be an explicitly
- resolvable font which defines glyphs for the specified glyph indexes.
+ Sets the font in which to look up the glyph indexes to \a font.
\sa font(), setGlyphIndexes()
*/
-void QGlyphs::setFont(const QFont &font)
+void QGlyphs::setFont(const QRawFont &font)
{
detach();
d->font = font;
@@ -234,7 +246,78 @@ void QGlyphs::clear()
detach();
d->glyphPositions = QVector<QPointF>();
d->glyphIndexes = QVector<quint32>();
- d->font = QFont();
+ d->font = QRawFont();
+ d->strikeOut = false;
+ d->overline = false;
+ d->underline = false;
+}
+
+/*!
+ Returns true if this QGlyphs should be painted with an overline decoration.
+
+ \sa setOverline()
+*/
+bool QGlyphs::overline() const
+{
+ return d->overline;
+}
+
+/*!
+ Indicates that this QGlyphs should be painted with an overline decoration if \a overline is true.
+ Otherwise the QGlyphs should be painted with no overline decoration.
+
+ \sa overline()
+*/
+void QGlyphs::setOverline(bool overline)
+{
+ detach();
+ d->overline = overline;
+}
+
+/*!
+ Returns true if this QGlyphs should be painted with an underline decoration.
+
+ \sa setUnderline()
+*/
+bool QGlyphs::underline() const
+{
+ return d->underline;
+}
+
+/*!
+ Indicates that this QGlyphs should be painted with an underline decoration if \a underline is
+ true. Otherwise the QGlyphs should be painted with no underline decoration.
+
+ \sa underline()
+*/
+void QGlyphs::setUnderline(bool underline)
+{
+ detach();
+ d->underline = underline;
+}
+
+/*!
+ Returns true if this QGlyphs should be painted with a strike out decoration.
+
+ \sa setStrikeOut()
+*/
+bool QGlyphs::strikeOut() const
+{
+ return d->strikeOut;
+}
+
+/*!
+ Indicates that this QGlyphs should be painted with an strike out decoration if \a strikeOut is
+ true. Otherwise the QGlyphs should be painted with no strike out decoration.
+
+ \sa strikeOut()
+*/
+void QGlyphs::setStrikeOut(bool strikeOut)
+{
+ detach();
+ d->strikeOut = strikeOut;
}
QT_END_NAMESPACE
+
+#endif // QT_NO_RAWFONT
diff --git a/src/gui/text/qglyphs.h b/src/gui/text/qglyphs.h
index 5f37136..4d7dcaf 100644
--- a/src/gui/text/qglyphs.h
+++ b/src/gui/text/qglyphs.h
@@ -45,7 +45,9 @@
#include <QtCore/qsharedpointer.h>
#include <QtCore/qvector.h>
#include <QtCore/qpoint.h>
-#include <QtGui/qfont.h>
+#include <QtGui/qrawfont.h>
+
+#if !defined(QT_NO_RAWFONT)
QT_BEGIN_HEADER
@@ -61,8 +63,8 @@ public:
QGlyphs(const QGlyphs &other);
~QGlyphs();
- QFont font() const;
- void setFont(const QFont &font);
+ QRawFont font() const;
+ void setFont(const QRawFont &font);
QVector<quint32> glyphIndexes() const;
void setGlyphIndexes(const QVector<quint32> &glyphIndexes);
@@ -76,6 +78,15 @@ public:
bool operator==(const QGlyphs &other) const;
bool operator!=(const QGlyphs &other) const;
+ void setOverline(bool overline);
+ bool overline() const;
+
+ void setUnderline(bool underline);
+ bool underline() const;
+
+ void setStrikeOut(bool strikeOut);
+ bool strikeOut() const;
+
private:
friend class QGlyphsPrivate;
friend class QTextLine;
@@ -85,12 +96,12 @@ private:
void detach();
QExplicitlySharedDataPointer<QGlyphsPrivate> d;
-
};
QT_END_NAMESPACE
QT_END_HEADER
+#endif // QT_NO_RAWFONT
#endif // QGLYPHS_H
diff --git a/src/gui/text/qglyphs_p.h b/src/gui/text/qglyphs_p.h
index c632e2f..944f777 100644
--- a/src/gui/text/qglyphs_p.h
+++ b/src/gui/text/qglyphs_p.h
@@ -53,8 +53,12 @@
// We mean it.
//
-#include <qfont.h>
#include "qglyphs.h"
+#include "qrawfont.h"
+
+#include <qfont.h>
+
+#if !defined(QT_NO_RAWFONT)
QT_BEGIN_HEADER
@@ -64,17 +68,30 @@ class QGlyphsPrivate: public QSharedData
{
public:
QGlyphsPrivate()
+ : overline(false)
+ , underline(false)
+ , strikeOut(false)
{
}
QGlyphsPrivate(const QGlyphsPrivate &other)
- : QSharedData(other), glyphIndexes(other.glyphIndexes), glyphPositions(other.glyphPositions), font(other.font)
+ : QSharedData(other)
+ , glyphIndexes(other.glyphIndexes)
+ , glyphPositions(other.glyphPositions)
+ , font(other.font)
+ , overline(other.overline)
+ , underline(other.underline)
+ , strikeOut(other.strikeOut)
{
}
QVector<quint32> glyphIndexes;
QVector<QPointF> glyphPositions;
- QFont font;
+ QRawFont font;
+
+ uint overline : 1;
+ uint underline : 1;
+ uint strikeOut : 1;
};
QT_END_NAMESPACE
@@ -82,3 +99,5 @@ QT_END_NAMESPACE
QT_END_HEADER
#endif // QGLYPHS_P_H
+
+#endif // QT_NO_RAWFONT
diff --git a/src/gui/text/qrawfont.cpp b/src/gui/text/qrawfont.cpp
new file mode 100644
index 0000000..4a715c2
--- /dev/null
+++ b/src/gui/text/qrawfont.cpp
@@ -0,0 +1,612 @@
+/****************************************************************************
+**
+** 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 "qglobal.h"
+
+#if !defined(QT_NO_RAWFONT)
+
+#include "qrawfont.h"
+#include "qrawfont_p.h"
+
+#include <QtCore/qthread.h>
+#include <QtCore/qendian.h>
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QRawFont
+ \brief The QRawFont class provides access to a single physical instance of a font.
+ \since 4.8
+
+ \ingroup text
+ \mainclass
+
+ \note QRawFont is a low level class. For most purposes QFont is a more appropriate class.
+
+ Most commonly, when presenting text in a user interface, the exact fonts used
+ to render the characters is to some extent unknown. This can be the case for several
+ reasons: For instance, the actual, physical fonts present on the target system could be
+ unexpected to the developers, or the text could contain user selected styles, sizes or
+ writing systems that are not supported by font chosen in the code.
+
+ Therefore, Qt's QFont class really represents a query for fonts. When text is interpreted,
+ Qt will do its best to match the text to the query, but depending on the support, different
+ fonts can be used behind the scenes.
+
+ For most use cases, this is both expected and necessary, as it minimizes the possibility of
+ text in the user interface being undisplayable. In some cases, however, more direct control
+ over the process might be useful. It is for these use cases the QRawFont class exists.
+
+ A QRawFont object represents a single, physical instance of a given font in a given pixel size.
+ I.e. in the typical case it represents a set of TrueType or OpenType font tables and uses a
+ user specified pixel size to convert metrics into logical pixel units. In can be used in
+ combination with the QGlyphs class to draw specific glyph indexes at specific positions, and
+ also have accessors to some relevant data in the physical font.
+
+ QRawFont only provides support for the main font technologies: GDI and DirectWrite on Windows
+ platforms, FreeType on Symbian and Linux platforms and CoreText on Mac OS X. For other
+ font back-ends, the APIs will be disabled.
+
+ QRawFont can be constructed in a number of ways:
+ \list
+ \o \l It can be constructed by calling QTextLayout::glyphs() or QTextFragment::glyphs(). The
+ returned QGlyphs objects will contain QRawFont objects which represent the actual fonts
+ used to render each portion of the text.
+ \o \l It can be constructed by passing a QFont object to QRawFont::fromFont(). The function
+ will return a QRawFont object representing the font that will be selected as response to
+ the QFont query and the selected writing system.
+ \o \l It can be constructed by passing a file name or QByteArray directly to the QRawFont
+ constructor, or by calling loadFromFile() or loadFromData(). In this case, the
+ font will not be registered in QFontDatabase, and it will not be available as part of
+ regular font selection.
+ \endlist
+
+ QRawFont is considered local to the thread in which it is constructed (either using a
+ constructor, or by calling loadFromData() or loadFromFile()). The QRawFont cannot be moved to a
+ different thread, but will have to be recreated in the thread in question.
+
+ \note For the requirement of caching glyph indexes and font selections for static text to avoid
+ reshaping and relayouting in the inner loop of an application, a better choice is the QStaticText
+ class, since it optimizes the memory cost of the cache and also provides the possibility of paint
+ engine specific caches for an additional speed-up.
+*/
+
+/*!
+ \enum QRawFont::AntialiasingType
+
+ This enum represents the different ways a glyph can be rasterized in the function
+ alphaMapForGlyph().
+
+ \value PixelAntialiasing Will rasterize by measuring the coverage of the shape on whole pixels.
+ The returned image contains the alpha values of each pixel based on the coverage of
+ the glyph shape.
+ \value SubPixelAntialiasing Will rasterize by measuring the coverage of each subpixel,
+ returning a separate alpha value for each of the red, green and blue components of
+ each pixel.
+*/
+
+/*!
+ Constructs an invalid QRawFont.
+*/
+QRawFont::QRawFont()
+ : d(new QRawFontPrivate)
+{
+}
+
+/*!
+ Constructs a QRawFont representing the font contained in the file referenced by \a fileName,
+ with \a pixelSize size in pixels, and the selected \a hintingPreference.
+
+ \note The referenced file must contain a TrueType or OpenType font.
+*/
+QRawFont::QRawFont(const QString &fileName,
+ int pixelSize,
+ QFont::HintingPreference hintingPreference)
+ : d(new QRawFontPrivate)
+{
+ loadFromFile(fileName, pixelSize, hintingPreference);
+}
+
+/*!
+ Constructs a QRawFont representing the font contained in \a fontData.
+
+ \note The data must contain a TrueType or OpenType font.
+*/
+QRawFont::QRawFont(const QByteArray &fontData,
+ int pixelSize,
+ QFont::HintingPreference hintingPreference)
+ : d(new QRawFontPrivate)
+{
+ loadFromData(fontData, pixelSize, hintingPreference);
+}
+
+/*!
+ Creates a QRawFont which is a copy of \a other.
+*/
+QRawFont::QRawFont(const QRawFont &other)
+{
+ d = other.d;
+}
+
+/*!
+ Destroys the QRawFont
+*/
+QRawFont::~QRawFont()
+{
+}
+
+/*!
+ Assigns \a other to this QRawFont.
+*/
+QRawFont &QRawFont::operator=(const QRawFont &other)
+{
+ d = other.d;
+ return *this;
+}
+
+/*!
+ Returns true if the QRawFont is valid and false otherwise.
+*/
+bool QRawFont::isValid() const
+{
+ Q_ASSERT(d->thread == 0 || d->thread == QThread::currentThread());
+ return d->fontEngine != 0;
+}
+
+/*!
+ Replaces the current QRawFont with the contents of the file references by \a fileName.
+
+ The file must reference a TrueType or OpenType font.
+
+ \sa loadFromData()
+*/
+void QRawFont::loadFromFile(const QString &fileName,
+ int pixelSize,
+ QFont::HintingPreference hintingPreference)
+{
+ QFile file(fileName);
+ if (file.open(QIODevice::ReadOnly))
+ loadFromData(file.readAll(), pixelSize, hintingPreference);
+}
+
+/*!
+ Replaces the current QRawFont with the contents of \a fontData.
+
+ The \a fontData must contain a TrueType or OpenType font.
+
+ \sa loadFromFile()
+*/
+void QRawFont::loadFromData(const QByteArray &fontData,
+ int pixelSize,
+ QFont::HintingPreference hintingPreference)
+{
+ detach();
+ d->cleanUp();
+ d->hintingPreference = hintingPreference;
+ d->thread = QThread::currentThread();
+ d->platformLoadFromData(fontData, pixelSize, hintingPreference);
+}
+
+/*!
+ This function returns a rasterized image of the glyph at a given \a glyphIndex in the underlying
+ font, if the QRawFont is valid, otherwise it will return an invalid QImage.
+
+ If \a antialiasingType is set to QRawFont::SubPixelAntialiasing, then the resulting image will be
+ in QImage::Format_RGB32 and the RGB values of each pixel will represent the subpixel opacities of
+ the pixel in the rasterization of the glyph. Otherwise, the image will be in the format of
+ QImage::Format_A8 and each pixel will contain the opacity of the pixel in the rasterization.
+
+ \sa pathForGlyph(), QPainter::drawGlyphs()
+*/
+QImage QRawFont::alphaMapForGlyph(quint32 glyphIndex, AntialiasingType antialiasingType,
+ const QTransform &transform) const
+{
+ if (!isValid())
+ return QImage();
+
+ if (antialiasingType == SubPixelAntialiasing)
+ return d->fontEngine->alphaRGBMapForGlyph(glyphIndex, QFixed(), 0, transform);
+ else
+ return d->fontEngine->alphaMapForGlyph(glyphIndex, QFixed(), transform);
+}
+
+/*!
+ This function returns the shape of the glyph at a given \a glyphIndex in the underlying font
+ if the QRawFont is valid. Otherwise, it returns an empty QPainterPath.
+
+ The returned glyph will always be unhinted.
+
+ \sa alphaMapForGlyph(), QPainterPath::addText()
+*/
+QPainterPath QRawFont::pathForGlyph(quint32 glyphIndex) const
+{
+ if (!isValid())
+ return QPainterPath();
+
+ QFixedPoint position;
+ QPainterPath path;
+ d->fontEngine->addGlyphsToPath(&glyphIndex, &position, 1, &path, 0);
+ return path;
+}
+
+/*!
+ Returns true if this QRawFont is equal to \a other. Otherwise, returns false.
+*/
+bool QRawFont::operator==(const QRawFont &other) const
+{
+ return d->fontEngine == other.d->fontEngine;
+}
+
+/*!
+ Returns the ascent of this QRawFont in pixel units.
+
+ \sa QFontMetricsF::ascent()
+*/
+qreal QRawFont::ascent() const
+{
+ if (!isValid())
+ return 0.0;
+
+ return d->fontEngine->ascent().toReal();
+}
+
+/*!
+ Returns the descent of this QRawFont in pixel units.
+
+ \sa QFontMetricsF::descent()
+*/
+qreal QRawFont::descent() const
+{
+ if (!isValid())
+ return 0.0;
+
+ return d->fontEngine->descent().toReal();
+}
+
+/*!
+ Returns the pixel size set for this QRawFont. The pixel size affects how glyphs are
+ rasterized, the size of glyphs returned by pathForGlyph(), and is used to convert
+ internal metrics from design units to logical pixel units.
+
+ \sa setPixelSize()
+*/
+int QRawFont::pixelSize() const
+{
+ if (!isValid())
+ return -1;
+
+ return d->fontEngine->fontDef.pixelSize;
+}
+
+/*!
+ Returns the number of design units define the width and height of the em square
+ for this QRawFont. This value is used together with the pixel size when converting design metrics
+ to pixel units, as the internal metrics are specified in design units and the pixel size gives
+ the size of 1 em in pixels.
+
+ \sa pixelSize(), setPixelSize()
+*/
+qreal QRawFont::unitsPerEm() const
+{
+ if (!isValid())
+ return 0.0;
+
+ return d->fontEngine->emSquareSize().toReal();
+}
+
+/*!
+ Returns the family name of this QRawFont.
+*/
+QString QRawFont::familyName() const
+{
+ if (!isValid())
+ return QString();
+
+ return d->fontEngine->fontDef.family;
+}
+
+/*!
+ Returns the style of this QRawFont.
+
+ \sa QFont::style()
+*/
+QFont::Style QRawFont::style() const
+{
+ if (!isValid())
+ return QFont::StyleNormal;
+
+ return QFont::Style(d->fontEngine->fontDef.style);
+}
+
+/*!
+ Returns the weight of this QRawFont.
+
+ \sa QFont::weight()
+*/
+int QRawFont::weight() const
+{
+ if (!isValid())
+ return -1;
+
+ return int(d->fontEngine->fontDef.weight);
+}
+
+/*!
+ Converts a string of unicode points to glyph indexes using the CMAP table in the
+ underlying font. Note that in cases where there are other tables in the font that affect the
+ shaping of the text, the returned glyph indexes will not correctly represent the rendering
+ of the text. To get the correctly shaped text, you can use QTextLayout to lay out and shape the
+ text, and then call QTextLayout::glyphs() to get the set of glyph index list and QRawFont pairs.
+
+ \sa advancesForGlyphIndexes(), QGlyphs, QTextLayout::glyphs(), QTextFragment::glyphs()
+*/
+QVector<quint32> QRawFont::glyphIndexesForString(const QString &text) const
+{
+ if (!isValid())
+ return QVector<quint32>();
+
+ int nglyphs = text.size();
+ QVarLengthGlyphLayoutArray glyphs(nglyphs);
+ if (!d->fontEngine->stringToCMap(text.data(), text.size(), &glyphs, &nglyphs,
+ QTextEngine::GlyphIndicesOnly)) {
+ glyphs.resize(nglyphs);
+ if (!d->fontEngine->stringToCMap(text.data(), text.size(), &glyphs, &nglyphs,
+ QTextEngine::GlyphIndicesOnly)) {
+ Q_ASSERT_X(false, Q_FUNC_INFO, "stringToCMap shouldn't fail twice");
+ return QVector<quint32>();
+ }
+ }
+
+ QVector<quint32> glyphIndexes;
+ for (int i=0; i<nglyphs; ++i)
+ glyphIndexes.append(glyphs.glyphs[i]);
+
+ return glyphIndexes;
+}
+
+/*!
+ Returns the QRawFont's advances for each of the \a glyphIndexes in pixel units. The advances
+ give the distance from the position of a given glyph to where the next glyph should be drawn
+ to make it appear as if the two glyphs are unspaced.
+
+ \sa QTextLine::horizontalAdvance(), QFontMetricsF::width()
+*/
+QVector<QPointF> QRawFont::advancesForGlyphIndexes(const QVector<quint32> &glyphIndexes) const
+{
+ if (!isValid())
+ return QVector<QPointF>();
+
+ int numGlyphs = glyphIndexes.size();
+ QVarLengthGlyphLayoutArray glyphs(numGlyphs);
+ qMemCopy(glyphs.glyphs, glyphIndexes.data(), numGlyphs * sizeof(quint32));
+
+ d->fontEngine->recalcAdvances(&glyphs, 0);
+
+ QVector<QPointF> advances;
+ for (int i=0; i<numGlyphs; ++i)
+ advances.append(QPointF(glyphs.advances_x[i].toReal(), glyphs.advances_y[i].toReal()));
+
+ return advances;
+}
+
+/*!
+ Returns the hinting preference used to construct this QRawFont.
+
+ \sa QFont::hintingPreference()
+*/
+QFont::HintingPreference QRawFont::hintingPreference() const
+{
+ if (!isValid())
+ return QFont::PreferDefaultHinting;
+
+ return d->hintingPreference;
+}
+
+/*!
+ Retrieves the sfnt table named \a tagName from the underlying physical font, or an empty
+ byte array if no such table was found. The returned font table's byte order is Big Endian, like
+ the sfnt format specifies. The \a tagName must be four characters long and should be formatted
+ in the default endianness of the current platform.
+*/
+QByteArray QRawFont::fontTable(const char *tagName) const
+{
+ if (!isValid())
+ return QByteArray();
+
+ const quint32 *tagId = reinterpret_cast<const quint32 *>(tagName);
+ return d->fontEngine->getSfntTable(qToBigEndian(*tagId));
+}
+
+// From qfontdatabase.cpp
+extern QList<QFontDatabase::WritingSystem> qt_determine_writing_systems_from_truetype_bits(quint32 unicodeRange[4], quint32 codePageRange[2]);
+
+/*!
+ Returns a list of writing systems supported by the font according to designer supplied
+ information in the font file. Please note that this does not guarantee support for a
+ specific unicode point in the font. You can use the supportsCharacter() to check support
+ for a single, specific character.
+
+ \note The list is determined based on the unicode ranges and codepage ranges set in the font's
+ OS/2 table and requires such a table to be present in the underlying font file.
+
+ \sa supportsCharacter()
+*/
+QList<QFontDatabase::WritingSystem> QRawFont::supportedWritingSystems() const
+{
+ if (isValid()) {
+ QByteArray os2Table = fontTable("OS/2");
+ if (!os2Table.isEmpty() && os2Table.size() > 86) {
+ char *data = os2Table.data();
+ quint32 *bigEndianUnicodeRanges = reinterpret_cast<quint32 *>(data + 42);
+ quint32 *bigEndianCodepageRanges = reinterpret_cast<quint32 *>(data + 78);
+
+ quint32 unicodeRanges[4];
+ quint32 codepageRanges[2];
+
+ for (int i=0; i<4; ++i) {
+ if (i < 2)
+ codepageRanges[i] = qFromBigEndian(bigEndianCodepageRanges[i]);
+ unicodeRanges[i] = qFromBigEndian(bigEndianUnicodeRanges[i]);
+ }
+
+ return qt_determine_writing_systems_from_truetype_bits(unicodeRanges, codepageRanges);
+ }
+ }
+
+ return QList<QFontDatabase::WritingSystem>();
+}
+
+/*!
+ Returns true if the font has a glyph that corresponds to the given \a character.
+
+ \sa supportedWritingSystems()
+*/
+bool QRawFont::supportsCharacter(const QChar &character) const
+{
+ if (!isValid())
+ return false;
+
+ return d->fontEngine->canRender(&character, 1);
+}
+
+/*!
+ Returns true if the font has a glyph that corresponds to the UCS-4 encoded character \a ucs4.
+
+ \sa supportedWritingSystems()
+*/
+bool QRawFont::supportsCharacter(quint32 ucs4) const
+{
+ if (!isValid())
+ return false;
+
+ QString str = QString::fromUcs4(&ucs4, 1);
+ return d->fontEngine->canRender(str.constData(), str.size());
+}
+
+// qfontdatabase.cpp
+extern int qt_script_for_writing_system(QFontDatabase::WritingSystem writingSystem);
+
+/*!
+ Fetches the physical representation based on a \a font query. The physical font returned is
+ the font that will be preferred by Qt in order to display text in the selected \a writingSystem.
+*/
+QRawFont QRawFont::fromFont(const QFont &font, QFontDatabase::WritingSystem writingSystem)
+{
+#if defined(Q_WS_MAC)
+ QTextLayout layout(QFontDatabase::writingSystemSample(writingSystem), font);
+ layout.beginLayout();
+ QTextLine line = layout.createLine();
+ layout.endLayout();
+ QList<QGlyphs> list = layout.glyphs();
+ if (list.size()) {
+ // Pick the one matches the family name we originally requested,
+ // if none of them match, just pick the first one
+ for (int i = 0; i < list.size(); i++) {
+ QGlyphs glyphs = list.at(i);
+ QRawFont rawfont = glyphs.font();
+ if (rawfont.familyName() == font.family())
+ return rawfont;
+ }
+ return list.at(0).font();
+ }
+ return QRawFont();
+#else
+ QFontPrivate *font_d = QFontPrivate::get(font);
+ int script = qt_script_for_writing_system(writingSystem);
+ QFontEngine *fe = font_d->engineForScript(script);
+
+ if (fe != 0 && fe->type() == QFontEngine::Multi) {
+ QFontEngineMulti *multiEngine = static_cast<QFontEngineMulti *>(fe);
+ fe = multiEngine->engine(0);
+ if (fe == 0) {
+ multiEngine->loadEngine(0);
+ fe = multiEngine->engine(0);
+ }
+ }
+
+ if (fe != 0) {
+ QRawFont rawFont;
+ rawFont.d.data()->fontEngine = fe;
+ rawFont.d.data()->fontEngine->ref.ref();
+ rawFont.d.data()->hintingPreference = font.hintingPreference();
+ return rawFont;
+ } else {
+ return QRawFont();
+ }
+#endif
+}
+
+/*!
+ Sets the pixel size with which this font should be rendered to \a pixelSize.
+*/
+void QRawFont::setPixelSize(int pixelSize)
+{
+ detach();
+ d->platformSetPixelSize(pixelSize);
+}
+
+/*!
+ \internal
+*/
+void QRawFont::detach()
+{
+ if (d->ref != 1)
+ d.detach();
+}
+
+/*!
+ \internal
+*/
+void QRawFontPrivate::cleanUp()
+{
+ platformCleanUp();
+ if (fontEngine != 0) {
+ fontEngine->ref.deref();
+ if (fontEngine->cache_count == 0 && fontEngine->ref == 0)
+ delete fontEngine;
+ fontEngine = 0;
+ }
+ hintingPreference = QFont::PreferDefaultHinting;
+}
+
+#endif // QT_NO_RAWFONT
+
+QT_END_NAMESPACE
diff --git a/src/gui/text/qrawfont.h b/src/gui/text/qrawfont.h
new file mode 100644
index 0000000..96dc838
--- /dev/null
+++ b/src/gui/text/qrawfont.h
@@ -0,0 +1,140 @@
+/****************************************************************************
+**
+** 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 QRAWFONT_H
+#define QRAWFONT_H
+
+#include <QtCore/qstring.h>
+#include <QtCore/qiodevice.h>
+#include <QtCore/qglobal.h>
+#include <QtCore/qobject.h>
+#include <QtCore/qpoint.h>
+#include <QtGui/qfont.h>
+#include <QtGui/qtransform.h>
+#include <QtGui/qfontdatabase.h>
+
+#if !defined(QT_NO_RAWFONT)
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Gui)
+
+class QRawFontPrivate;
+class Q_GUI_EXPORT QRawFont
+{
+public:
+ enum AntialiasingType {
+ PixelAntialiasing,
+ SubPixelAntialiasing
+ };
+
+ QRawFont();
+ QRawFont(const QString &fileName,
+ int pixelSize,
+ QFont::HintingPreference hintingPreference = QFont::PreferDefaultHinting);
+ QRawFont(const QByteArray &fontData,
+ int pixelSize,
+ QFont::HintingPreference hintingPreference = QFont::PreferDefaultHinting);
+ QRawFont(const QRawFont &other);
+ ~QRawFont();
+
+ bool isValid() const;
+
+ QRawFont &operator=(const QRawFont &other);
+ bool operator==(const QRawFont &other) const;
+
+ QString familyName() const;
+
+ QFont::Style style() const;
+ int weight() const;
+
+ QVector<quint32> glyphIndexesForString(const QString &text) const;
+ QVector<QPointF> advancesForGlyphIndexes(const QVector<quint32> &glyphIndexes) const;
+
+ QImage alphaMapForGlyph(quint32 glyphIndex,
+ AntialiasingType antialiasingType = SubPixelAntialiasing,
+ const QTransform &transform = QTransform()) const;
+ QPainterPath pathForGlyph(quint32 glyphIndex) const;
+
+ void setPixelSize(int pixelSize);
+ int pixelSize() const;
+
+ QFont::HintingPreference hintingPreference() const;
+
+ qreal ascent() const;
+ qreal descent() const;
+
+ qreal unitsPerEm() const;
+
+ void loadFromFile(const QString &fileName,
+ int pixelSize,
+ QFont::HintingPreference hintingPreference);
+
+ void loadFromData(const QByteArray &fontData,
+ int pixelSize,
+ QFont::HintingPreference hintingPreference);
+
+ bool supportsCharacter(quint32 ucs4) const;
+ bool supportsCharacter(const QChar &character) const;
+ QList<QFontDatabase::WritingSystem> supportedWritingSystems() const;
+
+ QByteArray fontTable(const char *tagName) const;
+
+ static QRawFont fromFont(const QFont &font,
+ QFontDatabase::WritingSystem writingSystem = QFontDatabase::Any);
+
+private:
+ friend class QRawFontPrivate;
+
+ void detach();
+
+ QExplicitlySharedDataPointer<QRawFontPrivate> d;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QT_NO_RAWFONT
+
+#endif // QRAWFONT_H
diff --git a/src/gui/text/qrawfont_ft.cpp b/src/gui/text/qrawfont_ft.cpp
new file mode 100644
index 0000000..eefbd92
--- /dev/null
+++ b/src/gui/text/qrawfont_ft.cpp
@@ -0,0 +1,189 @@
+/****************************************************************************
+**
+** 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 <QtCore/qglobal.h>
+
+#if !defined(QT_NO_RAWFONT)
+
+#include "qrawfont_p.h"
+#include "qfontengine_ft_p.h"
+
+#if defined(Q_WS_X11)
+# include "qfontengine_x11_p.h"
+#endif
+
+QT_BEGIN_NAMESPACE
+
+class QFontEngineFTRawFont
+
+#if defined(Q_WS_X11)
+ : public QFontEngineX11FT
+#else
+ : public QFontEngineFT
+#endif
+
+{
+public:
+ QFontEngineFTRawFont(const QFontDef &fontDef)
+#if defined(Q_WS_X11)
+ : QFontEngineX11FT(fontDef)
+#else
+ : QFontEngineFT(fontDef)
+#endif
+ {
+ }
+
+ void updateFamilyNameAndStyle()
+ {
+ fontDef.family = QString::fromAscii(freetype->face->family_name);
+
+ if (freetype->face->style_flags & FT_STYLE_FLAG_ITALIC)
+ fontDef.style = QFont::StyleItalic;
+
+ if (freetype->face->style_flags & FT_STYLE_FLAG_BOLD)
+ fontDef.weight = QFont::Bold;
+ }
+
+ bool initFromData(const QByteArray &fontData)
+ {
+ FaceId faceId;
+ faceId.filename = "";
+ faceId.index = 0;
+
+ return init(faceId, true, Format_None, fontData);
+ }
+
+ bool initFromFontEngine(QFontEngine *oldFontEngine)
+ {
+ QFontEngineFT *fe = static_cast<QFontEngineFT *>(oldFontEngine);
+
+ // Increase the reference of this QFreetypeFace since one more QFontEngineFT
+ // will be using it
+ fe->freetype->ref.ref();
+ if (!init(fe->faceId(), fe->antialias, fe->defaultFormat, fe->freetype))
+ return false;
+
+ default_load_flags = fe->default_load_flags;
+ default_hint_style = fe->default_hint_style;
+ antialias = fe->antialias;
+ transform = fe->transform;
+ embolden = fe->embolden;
+ subpixelType = fe->subpixelType;
+ lcdFilterType = fe->lcdFilterType;
+ canUploadGlyphsToServer = fe->canUploadGlyphsToServer;
+ embeddedbitmap = fe->embeddedbitmap;
+
+#if defined(Q_WS_X11)
+ xglyph_format = static_cast<QFontEngineX11FT *>(fe)->xglyph_format;
+#endif
+ return true;
+ }
+};
+
+
+void QRawFontPrivate::platformCleanUp()
+{
+ // Font engine handles all resources
+}
+
+void QRawFontPrivate::platformLoadFromData(const QByteArray &fontData, int pixelSize,
+ QFont::HintingPreference hintingPreference)
+{
+ Q_ASSERT(fontEngine == 0);
+
+ QFontDef fontDef;
+ fontDef.pixelSize = pixelSize;
+
+ QFontEngineFTRawFont *fe = new QFontEngineFTRawFont(fontDef);
+ if (!fe->initFromData(fontData)) {
+ delete fe;
+ return;
+ }
+
+ fe->updateFamilyNameAndStyle();
+
+ switch (hintingPreference) {
+ case QFont::PreferNoHinting:
+ fe->setDefaultHintStyle(QFontEngineFT::HintNone);
+ break;
+ case QFont::PreferFullHinting:
+ fe->setDefaultHintStyle(QFontEngineFT::HintFull);
+ break;
+ case QFont::PreferVerticalHinting:
+ fe->setDefaultHintStyle(QFontEngineFT::HintLight);
+ break;
+ default:
+ // Leave it as it is
+ break;
+ }
+
+ fontEngine = fe;
+ fontEngine->ref.ref();
+}
+
+void QRawFontPrivate::platformSetPixelSize(int pixelSize)
+{
+ if (fontEngine == NULL)
+ return;
+
+ QFontEngine *oldFontEngine = fontEngine;
+
+ QFontDef fontDef;
+ fontDef.pixelSize = pixelSize;
+ QFontEngineFTRawFont *fe = new QFontEngineFTRawFont(fontDef);
+ if (!fe->initFromFontEngine(oldFontEngine)) {
+ delete fe;
+ return;
+ }
+
+ fontEngine = fe;
+ fontEngine->fontDef = oldFontEngine->fontDef;
+ fontEngine->fontDef.pixelSize = pixelSize;
+ fontEngine->ref.ref();
+ Q_ASSERT(fontEngine != oldFontEngine);
+ oldFontEngine->ref.deref();
+ if (oldFontEngine->cache_count == 0 && oldFontEngine->ref == 0)
+ delete oldFontEngine;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_RAWFONT
diff --git a/src/gui/text/qrawfont_mac.cpp b/src/gui/text/qrawfont_mac.cpp
new file mode 100644
index 0000000..56005c6
--- /dev/null
+++ b/src/gui/text/qrawfont_mac.cpp
@@ -0,0 +1,105 @@
+/****************************************************************************
+**
+** 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 test suite 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 <QtCore/qglobal.h>
+
+#if !defined(QT_NO_RAWFONT)
+
+#include "qrawfont_p.h"
+#include "qfontengine_coretext_p.h"
+
+QT_BEGIN_NAMESPACE
+
+void QRawFontPrivate::platformCleanUp()
+{
+}
+
+extern int qt_defaultDpi();
+
+void QRawFontPrivate::platformLoadFromData(const QByteArray &fontData,
+ int pixelSize,
+ QFont::HintingPreference hintingPreference)
+{
+ // Mac OS X ignores it
+ Q_UNUSED(hintingPreference);
+
+ QCFType<CGDataProviderRef> dataProvider = CGDataProviderCreateWithData(NULL,
+ fontData.constData(), fontData.size(), NULL);
+
+ CGFontRef cgFont = CGFontCreateWithDataProvider(dataProvider);
+
+ if (cgFont == NULL) {
+ qWarning("QRawFont::platformLoadFromData: CGFontCreateWithDataProvider failed");
+ } else {
+ QFontDef def;
+ def.pixelSize = pixelSize;
+ def.pointSize = pixelSize * 72.0 / qt_defaultDpi();
+ fontEngine = new QCoreTextFontEngine(cgFont, def);
+ CFRelease(cgFont);
+ fontEngine->ref.ref();
+ }
+}
+
+void QRawFontPrivate::platformSetPixelSize(int pixelSize)
+{
+ if (fontEngine == NULL)
+ return;
+
+ QFontEngine *oldFontEngine = fontEngine;
+
+ QFontDef fontDef = oldFontEngine->fontDef;
+ fontDef.pixelSize = pixelSize;
+ fontDef.pointSize = pixelSize * 72.0 / qt_defaultDpi();
+
+ QCoreTextFontEngine *ctFontEngine = static_cast<QCoreTextFontEngine *>(oldFontEngine);
+ Q_ASSERT(ctFontEngine->cgFont);
+
+ fontEngine = new QCoreTextFontEngine(ctFontEngine->cgFont, fontDef);
+ fontEngine->ref.ref();
+ Q_ASSERT(fontEngine != oldFontEngine);
+ oldFontEngine->ref.deref();
+ if (oldFontEngine->cache_count == 0 && oldFontEngine->ref == 0)
+ delete oldFontEngine;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_RAWFONT
diff --git a/src/gui/text/qrawfont_p.h b/src/gui/text/qrawfont_p.h
new file mode 100644
index 0000000..f9a9ab5
--- /dev/null
+++ b/src/gui/text/qrawfont_p.h
@@ -0,0 +1,132 @@
+/****************************************************************************
+**
+** 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 QRAWFONTPRIVATE_P_H
+#define QRAWFONTPRIVATE_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "qrawfont.h"
+#include "qfontengine_p.h"
+#include <QtCore/qthreadstorage.h>
+
+#if !defined(QT_NO_RAWFONT)
+
+QT_BEGIN_NAMESPACE
+
+namespace { class CustomFontFileLoader; }
+class Q_AUTOTEST_EXPORT QRawFontPrivate
+{
+public:
+ QRawFontPrivate()
+ : fontEngine(0)
+ , hintingPreference(QFont::PreferDefaultHinting)
+ , thread(0)
+#if defined(Q_WS_WIN)
+ , fontHandle(NULL)
+ , ptrAddFontMemResourceEx(NULL)
+ , ptrRemoveFontMemResourceEx(NULL)
+#endif
+ {}
+
+ QRawFontPrivate(const QRawFontPrivate &other)
+ : hintingPreference(other.hintingPreference)
+ , thread(other.thread)
+#if defined(Q_WS_WIN)
+ , fontHandle(NULL)
+ , ptrAddFontMemResourceEx(other.ptrAddFontMemResourceEx)
+ , ptrRemoveFontMemResourceEx(other.ptrRemoveFontMemResourceEx)
+ , uniqueFamilyName(other.uniqueFamilyName)
+#endif
+ {
+ fontEngine = other.fontEngine;
+ if (fontEngine != 0)
+ fontEngine->ref.ref();
+ }
+
+ ~QRawFontPrivate()
+ {
+ Q_ASSERT(ref == 0);
+ cleanUp();
+ }
+
+ void cleanUp();
+ void platformCleanUp();
+ void platformLoadFromData(const QByteArray &fontData,
+ int pixelSize,
+ QFont::HintingPreference hintingPreference);
+ void platformSetPixelSize(int pixelSize);
+
+ static QRawFontPrivate *get(const QRawFont &font) { return font.d.data(); }
+
+ QFontEngine *fontEngine;
+ QFont::HintingPreference hintingPreference;
+ QThread *thread;
+ QAtomicInt ref;
+
+#if defined(Q_WS_WIN)
+ HANDLE fontHandle;
+
+ typedef HANDLE (WINAPI *PtrAddFontMemResourceEx)(PVOID, DWORD, PVOID, DWORD *);
+ typedef BOOL (WINAPI *PtrRemoveFontMemResourceEx)(HANDLE);
+
+ PtrAddFontMemResourceEx ptrAddFontMemResourceEx;
+ PtrRemoveFontMemResourceEx ptrRemoveFontMemResourceEx;
+
+ QString uniqueFamilyName;
+
+#endif // Q_WS_WIN
+};
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_RAWFONT
+
+#endif // QRAWFONTPRIVATE_P_H
diff --git a/src/gui/text/qrawfont_win.cpp b/src/gui/text/qrawfont_win.cpp
new file mode 100644
index 0000000..fb5c6f4
--- /dev/null
+++ b/src/gui/text/qrawfont_win.cpp
@@ -0,0 +1,750 @@
+/****************************************************************************
+**
+** 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 test suite 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 "qrawfont_p.h"
+#include <private/qsystemlibrary_p.h>
+
+#if !defined(QT_NO_DIRECTWRITE)
+# include "qfontenginedirectwrite_p.h"
+# include <dwrite.h>
+#endif
+
+#if !defined(QT_NO_RAWFONT)
+
+QT_BEGIN_NAMESPACE
+
+namespace {
+
+ template<typename T>
+ struct BigEndian
+ {
+ quint8 data[sizeof(T)];
+
+ operator T() const
+ {
+ T littleEndian = 0;
+ for (int i=0; i<sizeof(T); ++i) {
+ littleEndian |= data[i] << ((sizeof(T) - i - 1) * 8);
+ }
+
+ return littleEndian;
+ }
+
+ BigEndian<T> &operator=(const T &t)
+ {
+ for (int i=0; i<sizeof(T); ++i) {
+ data[i] = ((t >> (sizeof(T) - i - 1) * 8) & 0xff);
+ }
+
+ return *this;
+ }
+ };
+
+# pragma pack(1)
+
+ // Common structure for all formats of the "name" table
+ struct NameTable
+ {
+ BigEndian<quint16> format;
+ BigEndian<quint16> count;
+ BigEndian<quint16> stringOffset;
+ };
+
+ struct NameRecord
+ {
+ BigEndian<quint16> platformID;
+ BigEndian<quint16> encodingID;
+ BigEndian<quint16> languageID;
+ BigEndian<quint16> nameID;
+ BigEndian<quint16> length;
+ BigEndian<quint16> offset;
+ };
+
+ struct OffsetSubTable
+ {
+ BigEndian<quint32> scalerType;
+ BigEndian<quint16> numTables;
+ BigEndian<quint16> searchRange;
+ BigEndian<quint16> entrySelector;
+ BigEndian<quint16> rangeShift;
+ };
+
+ struct TableDirectory
+ {
+ BigEndian<quint32> identifier;
+ BigEndian<quint32> checkSum;
+ BigEndian<quint32> offset;
+ BigEndian<quint32> length;
+ };
+
+ struct OS2Table
+ {
+ BigEndian<quint16> version;
+ BigEndian<qint16> avgCharWidth;
+ BigEndian<quint16> weightClass;
+ BigEndian<quint16> widthClass;
+ BigEndian<quint16> type;
+ BigEndian<qint16> subscriptXSize;
+ BigEndian<qint16> subscriptYSize;
+ BigEndian<qint16> subscriptXOffset;
+ BigEndian<qint16> subscriptYOffset;
+ BigEndian<qint16> superscriptXSize;
+ BigEndian<qint16> superscriptYSize;
+ BigEndian<qint16> superscriptXOffset;
+ BigEndian<qint16> superscriptYOffset;
+ BigEndian<qint16> strikeOutSize;
+ BigEndian<qint16> strikeOutPosition;
+ BigEndian<qint16> familyClass;
+ quint8 panose[10];
+ BigEndian<quint32> unicodeRanges[4];
+ quint8 vendorID[4];
+ BigEndian<quint16> selection;
+ BigEndian<quint16> firstCharIndex;
+ BigEndian<quint16> lastCharIndex;
+ BigEndian<qint16> typoAscender;
+ BigEndian<qint16> typoDescender;
+ BigEndian<qint16> typoLineGap;
+ BigEndian<quint16> winAscent;
+ BigEndian<quint16> winDescent;
+ BigEndian<quint32> codepageRanges[2];
+ BigEndian<qint16> height;
+ BigEndian<qint16> capHeight;
+ BigEndian<quint16> defaultChar;
+ BigEndian<quint16> breakChar;
+ BigEndian<quint16> maxContext;
+ };
+
+# pragma pack()
+
+ class EmbeddedFont
+ {
+ public:
+ EmbeddedFont(const QByteArray &fontData);
+
+ QString changeFamilyName(const QString &newFamilyName);
+ QByteArray data() const { return m_fontData; }
+ TableDirectory *tableDirectoryEntry(const QByteArray &tagName);
+ QString familyName(TableDirectory *nameTableDirectory = 0);
+
+ private:
+ QByteArray m_fontData;
+ };
+
+ EmbeddedFont::EmbeddedFont(const QByteArray &fontData) : m_fontData(fontData)
+ {
+ }
+
+ TableDirectory *EmbeddedFont::tableDirectoryEntry(const QByteArray &tagName)
+ {
+ Q_ASSERT(tagName.size() == 4);
+
+ const BigEndian<quint32> *tagIdPtr =
+ reinterpret_cast<const BigEndian<quint32> *>(tagName.constData());
+ quint32 tagId = *tagIdPtr;
+
+ OffsetSubTable *offsetSubTable = reinterpret_cast<OffsetSubTable *>(m_fontData.data());
+ TableDirectory *tableDirectory = reinterpret_cast<TableDirectory *>(offsetSubTable + 1);
+
+ TableDirectory *nameTableDirectoryEntry = 0;
+ for (int i=0; i<offsetSubTable->numTables; ++i, ++tableDirectory) {
+ if (tableDirectory->identifier == tagId) {
+ nameTableDirectoryEntry = tableDirectory;
+ break;
+ }
+ }
+
+ return nameTableDirectoryEntry;
+ }
+
+ QString EmbeddedFont::familyName(TableDirectory *nameTableDirectoryEntry)
+ {
+ QString name;
+
+ if (nameTableDirectoryEntry == 0)
+ nameTableDirectoryEntry = tableDirectoryEntry("name");
+
+ if (nameTableDirectoryEntry != 0) {
+ NameTable *nameTable = reinterpret_cast<NameTable *>(m_fontData.data()
+ + nameTableDirectoryEntry->offset);
+ NameRecord *nameRecord = reinterpret_cast<NameRecord *>(nameTable + 1);
+ for (int i=0; i<nameTable->count; ++i, ++nameRecord) {
+ if (nameRecord->nameID == 1
+ && nameRecord->platformID == 3 // Windows
+ && nameRecord->languageID == 0x0409) { // US English
+ const void *ptr = reinterpret_cast<const quint8 *>(nameTable)
+ + nameTable->stringOffset
+ + nameRecord->offset;
+
+ const BigEndian<quint16> *s = reinterpret_cast<const BigEndian<quint16> *>(ptr);
+ for (int j=0; j<nameRecord->length / sizeof(quint16); ++j)
+ name += QChar(s[j]);
+
+ break;
+ }
+ }
+ }
+
+ return name;
+ }
+
+ QString EmbeddedFont::changeFamilyName(const QString &newFamilyName)
+ {
+ TableDirectory *nameTableDirectoryEntry = tableDirectoryEntry("name");
+ if (nameTableDirectoryEntry == 0)
+ return QString();
+
+ QString oldFamilyName = familyName(nameTableDirectoryEntry);
+
+ // Reserve size for name table header, five required name records and string
+ const int requiredRecordCount = 5;
+ quint16 nameIds[requiredRecordCount] = { 1, 2, 3, 4, 6 };
+
+ int sizeOfHeader = sizeof(NameTable) + sizeof(NameRecord) * requiredRecordCount;
+ int newFamilyNameSize = newFamilyName.size() * sizeof(quint16);
+
+ const QString regularString = QString::fromLatin1("Regular");
+ int regularStringSize = regularString.size() * sizeof(quint16);
+
+ // Align table size of table to 32 bits (pad with 0)
+ int fullSize = ((sizeOfHeader + newFamilyNameSize + regularStringSize) & ~3) + 4;
+
+ QByteArray newNameTable(fullSize, char(0));
+
+ {
+ NameTable *nameTable = reinterpret_cast<NameTable *>(newNameTable.data());
+ nameTable->count = requiredRecordCount;
+ nameTable->stringOffset = sizeOfHeader;
+
+ NameRecord *nameRecord = reinterpret_cast<NameRecord *>(nameTable + 1);
+ for (int i=0; i<requiredRecordCount; ++i, nameRecord++) {
+ nameRecord->nameID = nameIds[i];
+ nameRecord->encodingID = 1;
+ nameRecord->languageID = 0x0409;
+ nameRecord->platformID = 3;
+ nameRecord->length = newFamilyNameSize;
+
+ // Special case for sub-family
+ if (nameIds[i] == 4) {
+ nameRecord->offset = newFamilyNameSize;
+ nameRecord->length = regularStringSize;
+ }
+ }
+
+ // nameRecord now points to string data
+ BigEndian<quint16> *stringStorage = reinterpret_cast<BigEndian<quint16> *>(nameRecord);
+ const quint16 *sourceString = newFamilyName.utf16();
+ for (int i=0; i<newFamilyName.size(); ++i)
+ stringStorage[i] = sourceString[i];
+ stringStorage += newFamilyName.size();
+
+ sourceString = regularString.utf16();
+ for (int i=0; i<regularString.size(); ++i)
+ stringStorage[i] = sourceString[i];
+ }
+
+ quint32 *p = reinterpret_cast<quint32 *>(newNameTable.data());
+ quint32 *tableEnd = reinterpret_cast<quint32 *>(newNameTable.data() + fullSize);
+
+ quint32 checkSum = 0;
+ while (p < tableEnd)
+ checkSum += *(p++);
+
+ nameTableDirectoryEntry->checkSum = checkSum;
+ nameTableDirectoryEntry->offset = m_fontData.size();
+ nameTableDirectoryEntry->length = fullSize;
+
+ m_fontData.append(newNameTable);
+
+ return oldFamilyName;
+ }
+
+#if !defined(QT_NO_DIRECTWRITE)
+
+ class DirectWriteFontFileStream: public IDWriteFontFileStream
+ {
+ public:
+ DirectWriteFontFileStream(const QByteArray &fontData)
+ : m_fontData(fontData)
+ , m_referenceCount(0)
+ {
+ }
+
+ ~DirectWriteFontFileStream()
+ {
+ }
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **object);
+ ULONG STDMETHODCALLTYPE AddRef();
+ ULONG STDMETHODCALLTYPE Release();
+
+ HRESULT STDMETHODCALLTYPE ReadFileFragment(const void **fragmentStart, UINT64 fileOffset,
+ UINT64 fragmentSize, OUT void **fragmentContext);
+ void STDMETHODCALLTYPE ReleaseFileFragment(void *fragmentContext);
+ HRESULT STDMETHODCALLTYPE GetFileSize(OUT UINT64 *fileSize);
+ HRESULT STDMETHODCALLTYPE GetLastWriteTime(OUT UINT64 *lastWriteTime);
+
+ private:
+ QByteArray m_fontData;
+ ULONG m_referenceCount;
+ };
+
+ HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::QueryInterface(REFIID iid, void **object)
+ {
+ if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileStream)) {
+ *object = this;
+ AddRef();
+ return S_OK;
+ } else {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+ }
+
+ ULONG STDMETHODCALLTYPE DirectWriteFontFileStream::AddRef()
+ {
+ return InterlockedIncrement(&m_referenceCount);
+ }
+
+ ULONG STDMETHODCALLTYPE DirectWriteFontFileStream::Release()
+ {
+ ULONG newCount = InterlockedDecrement(&m_referenceCount);
+ if (newCount == 0)
+ delete this;
+ return newCount;
+ }
+
+ HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::ReadFileFragment(
+ const void **fragmentStart,
+ UINT64 fileOffset,
+ UINT64 fragmentSize,
+ OUT void **fragmentContext)
+ {
+ *fragmentContext = NULL;
+ if (fragmentSize + fileOffset <= m_fontData.size()) {
+ *fragmentStart = m_fontData.data() + fileOffset;
+ return S_OK;
+ } else {
+ *fragmentStart = NULL;
+ return E_FAIL;
+ }
+ }
+
+ void STDMETHODCALLTYPE DirectWriteFontFileStream::ReleaseFileFragment(void *)
+ {
+ }
+
+ HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::GetFileSize(UINT64 *fileSize)
+ {
+ *fileSize = m_fontData.size();
+ return S_OK;
+ }
+
+ HRESULT STDMETHODCALLTYPE DirectWriteFontFileStream::GetLastWriteTime(UINT64 *lastWriteTime)
+ {
+ *lastWriteTime = 0;
+ return E_NOTIMPL;
+ }
+
+ class DirectWriteFontFileLoader: public IDWriteFontFileLoader
+ {
+ public:
+ DirectWriteFontFileLoader() : m_referenceCount(0) {}
+
+ ~DirectWriteFontFileLoader()
+ {
+ }
+
+ inline void addKey(const void *key, const QByteArray &fontData)
+ {
+ Q_ASSERT(!m_fontDatas.contains(key));
+ m_fontDatas.insert(key, fontData);
+ }
+
+ inline void removeKey(const void *key)
+ {
+ m_fontDatas.remove(key);
+ }
+
+ HRESULT STDMETHODCALLTYPE QueryInterface(REFIID iid, void **object);
+ ULONG STDMETHODCALLTYPE AddRef();
+ ULONG STDMETHODCALLTYPE Release();
+
+ HRESULT STDMETHODCALLTYPE CreateStreamFromKey(void const *fontFileReferenceKey,
+ UINT32 fontFileReferenceKeySize,
+ OUT IDWriteFontFileStream **fontFileStream);
+
+ private:
+ ULONG m_referenceCount;
+ QHash<const void *, QByteArray> m_fontDatas;
+ };
+
+ HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::QueryInterface(const IID &iid,
+ void **object)
+ {
+ if (iid == IID_IUnknown || iid == __uuidof(IDWriteFontFileLoader)) {
+ *object = this;
+ AddRef();
+ return S_OK;
+ } else {
+ *object = NULL;
+ return E_NOINTERFACE;
+ }
+ }
+
+ ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::AddRef()
+ {
+ return InterlockedIncrement(&m_referenceCount);
+ }
+
+ ULONG STDMETHODCALLTYPE DirectWriteFontFileLoader::Release()
+ {
+ ULONG newCount = InterlockedDecrement(&m_referenceCount);
+ if (newCount == 0)
+ delete this;
+ return newCount;
+ }
+
+ HRESULT STDMETHODCALLTYPE DirectWriteFontFileLoader::CreateStreamFromKey(
+ void const *fontFileReferenceKey,
+ UINT32 fontFileReferenceKeySize,
+ IDWriteFontFileStream **fontFileStream)
+ {
+ Q_UNUSED(fontFileReferenceKeySize);
+
+ if (fontFileReferenceKeySize != sizeof(const void *)) {
+ qWarning("DirectWriteFontFileLoader::CreateStreamFromKey: Wrong key size");
+ return E_FAIL;
+ }
+
+ const void *key = *reinterpret_cast<void * const *>(fontFileReferenceKey);
+ *fontFileStream = NULL;
+ if (!m_fontDatas.contains(key))
+ return E_FAIL;
+
+ QByteArray fontData = m_fontDatas.value(key);
+ DirectWriteFontFileStream *stream = new DirectWriteFontFileStream(fontData);
+ stream->AddRef();
+ *fontFileStream = stream;
+
+ return S_OK;
+ }
+
+ class CustomFontFileLoader
+ {
+ public:
+ CustomFontFileLoader() : m_directWriteFactory(0), m_directWriteFontFileLoader(0)
+ {
+ HRESULT hres = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED,
+ __uuidof(IDWriteFactory),
+ reinterpret_cast<IUnknown **>(&m_directWriteFactory));
+ if (FAILED(hres)) {
+ qErrnoWarning(hres, "CustomFontFileLoader::CustomFontFileLoader: "
+ "DWriteCreateFactory failed.");
+ } else {
+ m_directWriteFontFileLoader = new DirectWriteFontFileLoader();
+ m_directWriteFactory->RegisterFontFileLoader(m_directWriteFontFileLoader);
+ }
+ }
+
+ ~CustomFontFileLoader()
+ {
+ if (m_directWriteFactory != 0 && m_directWriteFontFileLoader != 0)
+ m_directWriteFactory->UnregisterFontFileLoader(m_directWriteFontFileLoader);
+
+ if (m_directWriteFactory != 0)
+ m_directWriteFactory->Release();
+ }
+
+ void addKey(const void *key, const QByteArray &fontData)
+ {
+ if (m_directWriteFontFileLoader != 0)
+ m_directWriteFontFileLoader->addKey(key, fontData);
+ }
+
+ void removeKey(const void *key)
+ {
+ if (m_directWriteFontFileLoader != 0)
+ m_directWriteFontFileLoader->removeKey(key);
+ }
+
+ IDWriteFontFileLoader *loader() const
+ {
+ return m_directWriteFontFileLoader;
+ }
+
+ private:
+ IDWriteFactory *m_directWriteFactory;
+ DirectWriteFontFileLoader *m_directWriteFontFileLoader;
+ };
+
+#endif
+
+} // Anonymous namespace
+
+
+// From qfontdatabase_win.cpp
+extern QFontEngine *qt_load_font_engine_win(const QFontDef &request);
+// From qfontdatabase.cpp
+extern QFont::Weight weightFromInteger(int weight);
+
+void QRawFontPrivate::platformCleanUp()
+{
+ if (fontHandle != NULL) {
+ if (ptrRemoveFontMemResourceEx == NULL) {
+ void *func = QSystemLibrary::resolve(QLatin1String("gdi32"), "RemoveFontMemResourceEx");
+ ptrRemoveFontMemResourceEx =
+ reinterpret_cast<QRawFontPrivate::PtrRemoveFontMemResourceEx>(func);
+ }
+
+ if (ptrRemoveFontMemResourceEx == NULL) {
+ qWarning("QRawFont::platformCleanUp: Can't find RemoveFontMemResourceEx in gdi32");
+ fontHandle = NULL;
+ } else {
+ ptrRemoveFontMemResourceEx(fontHandle);
+ fontHandle = NULL;
+ }
+ }
+}
+
+void QRawFontPrivate::platformLoadFromData(const QByteArray &_fontData,
+ int pixelSize,
+ QFont::HintingPreference hintingPreference)
+{
+ QByteArray fontData(_fontData);
+ EmbeddedFont font(fontData);
+
+#if !defined(QT_NO_DIRECTWRITE)
+ if (hintingPreference == QFont::PreferDefaultHinting
+ || hintingPreference == QFont::PreferFullHinting)
+#endif
+ {
+ GUID guid;
+ CoCreateGuid(&guid);
+
+ uniqueFamilyName = QString::fromLatin1("f")
+ + QString::number(guid.Data1, 36) + QLatin1Char('-')
+ + QString::number(guid.Data2, 36) + QLatin1Char('-')
+ + QString::number(guid.Data3, 36) + QLatin1Char('-')
+ + QString::number(*reinterpret_cast<quint64 *>(guid.Data4), 36);
+
+ QString actualFontName = font.changeFamilyName(uniqueFamilyName);
+ if (actualFontName.isEmpty()) {
+ qWarning("QRawFont::platformLoadFromData: Can't change family name of font");
+ return;
+ }
+
+ if (ptrAddFontMemResourceEx == NULL || ptrRemoveFontMemResourceEx == NULL) {
+ void *func = QSystemLibrary::resolve(QLatin1String("gdi32"), "RemoveFontMemResourceEx");
+ ptrRemoveFontMemResourceEx =
+ reinterpret_cast<QRawFontPrivate::PtrRemoveFontMemResourceEx>(func);
+
+ func = QSystemLibrary::resolve(QLatin1String("gdi32"), "AddFontMemResourceEx");
+ ptrAddFontMemResourceEx =
+ reinterpret_cast<QRawFontPrivate::PtrAddFontMemResourceEx>(func);
+ }
+
+ Q_ASSERT(fontHandle == NULL);
+ if (ptrAddFontMemResourceEx != NULL && ptrRemoveFontMemResourceEx != NULL) {
+ DWORD count = 0;
+ fontData = font.data();
+ fontHandle = ptrAddFontMemResourceEx(fontData.data(), fontData.size(), 0, &count);
+
+ if (count == 0 && fontHandle != NULL) {
+ ptrRemoveFontMemResourceEx(fontHandle);
+ fontHandle = NULL;
+ }
+ }
+
+ if (fontHandle == NULL) {
+ qWarning("QRawFont::platformLoadFromData: AddFontMemResourceEx failed");
+ } else {
+ QFontDef request;
+ request.family = uniqueFamilyName;
+ request.pixelSize = pixelSize;
+ request.styleStrategy = QFont::NoFontMerging | QFont::PreferMatch;
+ request.hintingPreference = hintingPreference;
+
+ fontEngine = qt_load_font_engine_win(request);
+ if (request.family != fontEngine->fontDef.family) {
+ qWarning("QRawFont::platformLoadFromData: Failed to load font. "
+ "Got fallback instead: %s", qPrintable(fontEngine->fontDef.family));
+ if (fontEngine->cache_count == 0 && fontEngine->ref == 0)
+ delete fontEngine;
+ fontEngine = 0;
+ } else {
+ Q_ASSERT(fontEngine->cache_count == 0 && fontEngine->ref == 0);
+
+ // Override the generated font name
+ fontEngine->fontDef.family = actualFontName;
+ fontEngine->ref.ref();
+ }
+ }
+ }
+#if !defined(QT_NO_DIRECTWRITE)
+ else {
+ CustomFontFileLoader fontFileLoader;
+ fontFileLoader.addKey(this, fontData);
+
+ IDWriteFactory *factory = NULL;
+ HRESULT hres = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED,
+ __uuidof(IDWriteFactory),
+ reinterpret_cast<IUnknown **>(&factory));
+ if (FAILED(hres)) {
+ qErrnoWarning(hres, "QRawFont::platformLoadFromData: DWriteCreateFactory failed");
+ return;
+ }
+
+ IDWriteFontFile *fontFile = NULL;
+ void *key = this;
+
+ hres = factory->CreateCustomFontFileReference(&key, sizeof(void *),
+ fontFileLoader.loader(), &fontFile);
+ if (FAILED(hres)) {
+ qErrnoWarning(hres, "QRawFont::platformLoadFromData: "
+ "CreateCustomFontFileReference failed");
+ factory->Release();
+ return;
+ }
+
+ BOOL isSupportedFontType;
+ DWRITE_FONT_FILE_TYPE fontFileType;
+ DWRITE_FONT_FACE_TYPE fontFaceType;
+ UINT32 numberOfFaces;
+ fontFile->Analyze(&isSupportedFontType, &fontFileType, &fontFaceType, &numberOfFaces);
+ if (!isSupportedFontType) {
+ fontFile->Release();
+ factory->Release();
+ return;
+ }
+
+ IDWriteFontFace *directWriteFontFace = NULL;
+ hres = factory->CreateFontFace(fontFaceType, 1, &fontFile, 0, DWRITE_FONT_SIMULATIONS_NONE,
+ &directWriteFontFace);
+ if (FAILED(hres)) {
+ qErrnoWarning(hres, "QRawFont::platformLoadFromData: CreateFontFace failed");
+ fontFile->Release();
+ factory->Release();
+ return;
+ }
+
+ fontFile->Release();
+
+ fontEngine = new QFontEngineDirectWrite(factory, directWriteFontFace, pixelSize);
+
+ // Get font family from font data
+ fontEngine->fontDef.family = font.familyName();
+ fontEngine->ref.ref();
+
+ directWriteFontFace->Release();
+ factory->Release();
+ }
+#endif
+
+ // Get style and weight info
+ if (fontEngine != 0) {
+ TableDirectory *os2TableEntry = font.tableDirectoryEntry("OS/2");
+ if (os2TableEntry != 0) {
+ const OS2Table *os2Table =
+ reinterpret_cast<const OS2Table *>(fontData.constData()
+ + os2TableEntry->offset);
+
+ bool italic = os2Table->selection & 1;
+ bool oblique = os2Table->selection & 128;
+
+ if (italic)
+ fontEngine->fontDef.style = QFont::StyleItalic;
+ else if (oblique)
+ fontEngine->fontDef.style = QFont::StyleOblique;
+ else
+ fontEngine->fontDef.style = QFont::StyleNormal;
+
+ fontEngine->fontDef.weight = weightFromInteger(os2Table->weightClass);
+ }
+ }
+}
+
+void QRawFontPrivate::platformSetPixelSize(int pixelSize)
+{
+ if (fontEngine == NULL)
+ return;
+
+ QFontEngine *oldFontEngine = fontEngine;
+
+#if !defined(QT_NO_DIRECTWRITE)
+ if (fontEngine->type() == QFontEngine::Win)
+#endif
+
+ {
+ QFontDef request = fontEngine->fontDef;
+ QString actualFontName = request.family;
+ if (!uniqueFamilyName.isEmpty())
+ request.family = uniqueFamilyName;
+ request.pixelSize = pixelSize;
+
+ fontEngine = qt_load_font_engine_win(request);
+ if (fontEngine != NULL) {
+ fontEngine->fontDef.family = actualFontName;
+ fontEngine->ref.ref();
+ }
+ }
+
+#if !defined(QT_NO_DIRECTWRITE)
+ else {
+ QFontEngineDirectWrite *dWriteFE = static_cast<QFontEngineDirectWrite *>(fontEngine);
+ fontEngine = new QFontEngineDirectWrite(dWriteFE->m_directWriteFactory,
+ dWriteFE->m_directWriteFontFace,
+ pixelSize);
+
+ fontEngine->fontDef = dWriteFE->fontDef;
+ fontEngine->fontDef.pixelSize = pixelSize;
+ fontEngine->ref.ref();
+ }
+#endif
+
+ Q_ASSERT(fontEngine != oldFontEngine);
+ oldFontEngine->ref.deref();
+ if (oldFontEngine->cache_count == 0 && oldFontEngine->ref == 0)
+ delete oldFontEngine;
+}
+
+QT_END_NAMESPACE
+
+#endif // QT_NO_RAWFONT
diff --git a/src/gui/text/qtextcursor.cpp b/src/gui/text/qtextcursor.cpp
index 6ddfdb0..4f6857a 100644
--- a/src/gui/text/qtextcursor.cpp
+++ b/src/gui/text/qtextcursor.cpp
@@ -362,20 +362,23 @@ bool QTextCursorPrivate::movePosition(QTextCursor::MoveOperation op, QTextCursor
currentCharFormat = -1;
bool adjustX = true;
QTextBlock blockIt = block();
+ bool visualMovement = priv->defaultCursorMoveStyle == QTextCursor::Visual;
if (!blockIt.isValid())
return false;
- if (op >= QTextCursor::Left && op <= QTextCursor::WordRight
- && blockIt.textDirection() == Qt::RightToLeft) {
- if (op == QTextCursor::Left)
- op = QTextCursor::NextCharacter;
- else if (op == QTextCursor::Right)
- op = QTextCursor::PreviousCharacter;
- else if (op == QTextCursor::WordLeft)
+ if (blockIt.textDirection() == Qt::RightToLeft) {
+ if (op == QTextCursor::WordLeft)
op = QTextCursor::NextWord;
else if (op == QTextCursor::WordRight)
op = QTextCursor::PreviousWord;
+
+ if (!visualMovement) {
+ if (op == QTextCursor::Left)
+ op = QTextCursor::NextCharacter;
+ else if (op == QTextCursor::Right)
+ op = QTextCursor::PreviousCharacter;
+ }
}
const QTextLayout *layout = blockLayout(blockIt);
@@ -418,9 +421,12 @@ bool QTextCursorPrivate::movePosition(QTextCursor::MoveOperation op, QTextCursor
break;
}
case QTextCursor::PreviousCharacter:
- case QTextCursor::Left:
newPosition = priv->previousCursorPosition(position, QTextLayout::SkipCharacters);
break;
+ case QTextCursor::Left:
+ newPosition = visualMovement ? priv->leftCursorPosition(position)
+ : priv->previousCursorPosition(position, QTextLayout::SkipCharacters);
+ break;
case QTextCursor::StartOfWord: {
if (relativePos == 0)
break;
@@ -529,9 +535,12 @@ bool QTextCursorPrivate::movePosition(QTextCursor::MoveOperation op, QTextCursor
break;
}
case QTextCursor::NextCharacter:
- case QTextCursor::Right:
newPosition = priv->nextCursorPosition(position, QTextLayout::SkipCharacters);
break;
+ case QTextCursor::Right:
+ newPosition = visualMovement ? priv->rightCursorPosition(position)
+ : priv->nextCursorPosition(position, QTextLayout::SkipCharacters);
+ break;
case QTextCursor::NextWord:
case QTextCursor::WordRight:
newPosition = priv->nextCursorPosition(position, QTextLayout::SkipWords);
@@ -2558,4 +2567,19 @@ QTextDocument *QTextCursor::document() const
return 0; // document went away
}
+/*!
+ \enum QTextCursor::MoveStyle
+
+ This enum describes the movement style available to QTextCursor. The options
+ are:
+
+ \value Logical Within a left-to-right text block, increase cursor position
+ when pressing left arrow key, decrease cursor position when pressing the
+ right arrow key. If the text block is right-to-left, the opposite behavior
+ applies.
+ \value Visual Pressing the left arrow key will always cause the cursor to move
+ left, regardless of the text's writing direction. The same behavior applies to
+ right arrow key.
+*/
+
QT_END_NAMESPACE
diff --git a/src/gui/text/qtextcursor.h b/src/gui/text/qtextcursor.h
index 4eaeb41..9e4c0b8 100644
--- a/src/gui/text/qtextcursor.h
+++ b/src/gui/text/qtextcursor.h
@@ -86,6 +86,10 @@ public:
MoveAnchor,
KeepAnchor
};
+ enum MoveStyle {
+ Logical,
+ Visual
+ };
void setPosition(int pos, MoveMode mode = MoveAnchor);
int position() const;
diff --git a/src/gui/text/qtextdocument.cpp b/src/gui/text/qtextdocument.cpp
index 6dbd755..36f3c6c 100644
--- a/src/gui/text/qtextdocument.cpp
+++ b/src/gui/text/qtextdocument.cpp
@@ -586,6 +586,29 @@ void QTextDocument::setDefaultTextOption(const QTextOption &option)
}
/*!
+ \since 4.8
+
+ The default cursor movement style is used by all QTextCursor objects
+ created from the document. The default is QTextCursor::Logical.
+*/
+QTextCursor::MoveStyle QTextDocument::defaultCursorMoveStyle() const
+{
+ Q_D(const QTextDocument);
+ return d->defaultCursorMoveStyle;
+}
+
+/*!
+ \since 4.8
+
+ Set the default cursor movement style.
+*/
+void QTextDocument::setDefaultCursorMoveStyle(QTextCursor::MoveStyle style)
+{
+ Q_D(QTextDocument);
+ d->defaultCursorMoveStyle = style;
+}
+
+/*!
\fn void QTextDocument::markContentsDirty(int position, int length)
Marks the contents specified by the given \a position and \a length
diff --git a/src/gui/text/qtextdocument.h b/src/gui/text/qtextdocument.h
index f87ccc9..e515b36 100644
--- a/src/gui/text/qtextdocument.h
+++ b/src/gui/text/qtextdocument.h
@@ -46,6 +46,7 @@
#include <QtCore/qsize.h>
#include <QtCore/qrect.h>
#include <QtGui/qfont.h>
+#include <QtGui/qtextcursor.h>
QT_BEGIN_HEADER
@@ -60,7 +61,6 @@ class QPainter;
class QPrinter;
class QAbstractTextDocumentLayout;
class QPoint;
-class QTextCursor;
class QTextObject;
class QTextFormat;
class QTextFrame;
@@ -269,6 +269,9 @@ public:
QTextOption defaultTextOption() const;
void setDefaultTextOption(const QTextOption &option);
+ QTextCursor::MoveStyle defaultCursorMoveStyle() const;
+ void setDefaultCursorMoveStyle(QTextCursor::MoveStyle style);
+
Q_SIGNALS:
void contentsChange(int from, int charsRemoves, int charsAdded);
void contentsChanged();
diff --git a/src/gui/text/qtextdocument_p.cpp b/src/gui/text/qtextdocument_p.cpp
index 2172f74..71af89f 100644
--- a/src/gui/text/qtextdocument_p.cpp
+++ b/src/gui/text/qtextdocument_p.cpp
@@ -209,6 +209,7 @@ QTextDocumentPrivate::QTextDocumentPrivate()
defaultTextOption.setTabStop(80); // same as in qtextengine.cpp
defaultTextOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
+ defaultCursorMoveStyle = QTextCursor::Logical;
indentWidth = 40;
documentMargin = 4;
@@ -1382,6 +1383,20 @@ int QTextDocumentPrivate::previousCursorPosition(int position, QTextLayout::Curs
return it.layout()->previousCursorPosition(position-start, mode) + start;
}
+int QTextDocumentPrivate::leftCursorPosition(int position) const
+{
+ QTextBlock it = blocksFind(position);
+ int start = it.position();
+ return it.layout()->leftCursorPosition(position-start) + start;
+}
+
+int QTextDocumentPrivate::rightCursorPosition(int position) const
+{
+ QTextBlock it = blocksFind(position);
+ int start = it.position();
+ return it.layout()->rightCursorPosition(position-start) + start;
+}
+
void QTextDocumentPrivate::changeObjectFormat(QTextObject *obj, int format)
{
beginEditBlock();
diff --git a/src/gui/text/qtextdocument_p.h b/src/gui/text/qtextdocument_p.h
index b464f2e..6563920 100644
--- a/src/gui/text/qtextdocument_p.h
+++ b/src/gui/text/qtextdocument_p.h
@@ -64,6 +64,7 @@
#include "private/qtextformat_p.h"
#include "QtGui/qtextdocument.h"
#include "QtGui/qtextobject.h"
+#include "QtGui/qtextcursor.h"
#include "QtCore/qmap.h"
#include "QtCore/qvariant.h"
#include "QtCore/qurl.h"
@@ -244,6 +245,8 @@ public:
int nextCursorPosition(int position, QTextLayout::CursorMode mode) const;
int previousCursorPosition(int position, QTextLayout::CursorMode mode) const;
+ int leftCursorPosition(int position) const;
+ int rightCursorPosition(int position) const;
void changeObjectFormat(QTextObject *group, int format);
@@ -339,6 +342,7 @@ private:
public:
QTextOption defaultTextOption;
+ QTextCursor::MoveStyle defaultCursorMoveStyle;
#ifndef QT_NO_CSSPARSER
QCss::StyleSheet parsedDefaultStyleSheet;
#endif
diff --git a/src/gui/text/qtextengine.cpp b/src/gui/text/qtextengine.cpp
index 08d0eca..dab4bb7 100644
--- a/src/gui/text/qtextengine.cpp
+++ b/src/gui/text/qtextengine.cpp
@@ -856,6 +856,21 @@ void QTextEngine::shapeLine(const QScriptLine &line)
}
}
+#if !defined(QT_ENABLE_HARFBUZZ_FOR_MAC)
+static bool enableHarfBuzz()
+{
+ static enum { Yes, No, Unknown } status = Unknown;
+
+ if (status == Unknown) {
+ QByteArray v = qgetenv("QT_ENABLE_HARFBUZZ");
+ bool value = !v.isEmpty() && v != "0" && v != "false";
+ if (value) status = Yes;
+ else status = No;
+ }
+ return status == Yes;
+}
+#endif
+
void QTextEngine::shapeText(int item) const
{
Q_ASSERT(item < layoutData->items.size());
@@ -865,7 +880,24 @@ void QTextEngine::shapeText(int item) const
return;
#if defined(Q_WS_MAC)
- shapeTextMac(item);
+#if !defined(QT_ENABLE_HARFBUZZ_FOR_MAC)
+ if (enableHarfBuzz()) {
+#endif
+ QFontEngine *actualFontEngine = fontEngine(si, &si.ascent, &si.descent, &si.leading);
+ if (actualFontEngine->type() == QFontEngine::Multi)
+ actualFontEngine = static_cast<QFontEngineMulti *>(actualFontEngine)->engine(0);
+
+ HB_Face face = actualFontEngine->harfbuzzFace();
+ HB_Script script = (HB_Script) si.analysis.script;
+ if (face->supported_scripts[script])
+ shapeTextWithHarfbuzz(item);
+ else
+ shapeTextMac(item);
+#if !defined(QT_ENABLE_HARFBUZZ_FOR_MAC)
+ } else {
+ shapeTextMac(item);
+ }
+#endif
#elif defined(Q_WS_WINCE)
shapeTextWithCE(item);
#else
@@ -1304,6 +1336,7 @@ static void init(QTextEngine *e)
e->ignoreBidi = false;
e->cacheGlyphs = false;
e->forceJustification = false;
+ e->visualMovement = false;
e->layoutData = 0;
@@ -2737,6 +2770,180 @@ QFixed QTextEngine::leadingSpaceWidth(const QScriptLine &line)
return width(line.from + pos, line.length - pos);
}
+QFixed QTextEngine::alignLine(const QScriptLine &line)
+{
+ QFixed x = 0;
+ justify(line);
+ // if width is QFIXED_MAX that means we used setNumColumns() and that implicitly makes this line left aligned.
+ if (!line.justified && line.width != QFIXED_MAX) {
+ int align = option.alignment();
+ if (align & Qt::AlignJustify && isRightToLeft())
+ align = Qt::AlignRight;
+ if (align & Qt::AlignRight)
+ x = line.width - (line.textAdvance + leadingSpaceWidth(line));
+ else if (align & Qt::AlignHCenter)
+ x = (line.width - line.textAdvance)/2;
+ }
+ return x;
+}
+
+QFixed QTextEngine::offsetInLigature(const QScriptItem *si, int pos, int max, int glyph_pos)
+{
+ unsigned short *logClusters = this->logClusters(si);
+ const QGlyphLayout &glyphs = shapedGlyphs(si);
+
+ int offsetInCluster = 0;
+ for (int i = pos - 1; i >= 0; i--) {
+ if (logClusters[i] == glyph_pos)
+ offsetInCluster++;
+ else
+ break;
+ }
+
+ // in the case that the offset is inside a (multi-character) glyph,
+ // interpolate the position.
+ if (offsetInCluster > 0) {
+ int clusterLength = 0;
+ for (int i = pos - offsetInCluster; i < max; i++) {
+ if (logClusters[i] == glyph_pos)
+ clusterLength++;
+ else
+ break;
+ }
+ if (clusterLength)
+ return glyphs.advances_x[glyph_pos] * offsetInCluster / clusterLength;
+ }
+
+ return 0;
+}
+
+int QTextEngine::previousLogicalPosition(int oldPos) const
+{
+ const HB_CharAttributes *attrs = attributes();
+ if (!attrs || oldPos < 0)
+ return oldPos;
+
+ if (oldPos <= 0)
+ return 0;
+ oldPos--;
+ while (oldPos && !attrs[oldPos].charStop)
+ oldPos--;
+ return oldPos;
+}
+
+int QTextEngine::nextLogicalPosition(int oldPos) const
+{
+ const HB_CharAttributes *attrs = attributes();
+ int len = block.isValid() ? block.length() - 1
+ : layoutData->string.length();
+ Q_ASSERT(len <= layoutData->string.length());
+ if (!attrs || oldPos < 0 || oldPos >= len)
+ return oldPos;
+
+ oldPos++;
+ while (oldPos < len && !attrs[oldPos].charStop)
+ oldPos++;
+ return oldPos;
+}
+
+int QTextEngine::lineNumberForTextPosition(int pos)
+{
+ if (!layoutData)
+ itemize();
+ if (pos == layoutData->string.length() && lines.size())
+ return lines.size() - 1;
+ for (int i = 0; i < lines.size(); ++i) {
+ const QScriptLine& line = lines[i];
+ if (line.from + line.length > pos)
+ return i;
+ }
+ return -1;
+}
+
+void QTextEngine::insertionPointsForLine(int lineNum, QVector<int> &insertionPoints)
+{
+ QTextLineItemIterator iterator(this, lineNum);
+ bool rtl = isRightToLeft();
+ bool lastLine = lineNum >= lines.size() - 1;
+
+ while (!iterator.atEnd()) {
+ iterator.next();
+ const QScriptItem *si = &layoutData->items[iterator.item];
+ if (si->analysis.bidiLevel % 2) {
+ int i = iterator.itemEnd - 1, min = iterator.itemStart;
+ if (lastLine && (rtl ? iterator.atBeginning() : iterator.atEnd()))
+ i++;
+ for (; i >= min; i--)
+ insertionPoints.push_back(i);
+ } else {
+ int i = iterator.itemStart, max = iterator.itemEnd;
+ if (lastLine && (rtl ? iterator.atBeginning() : iterator.atEnd()))
+ max++;
+ for (; i < max; i++)
+ insertionPoints.push_back(i);
+ }
+ }
+}
+
+int QTextEngine::endOfLine(int lineNum)
+{
+ QVector<int> insertionPoints;
+ insertionPointsForLine(lineNum, insertionPoints);
+
+ if (insertionPoints.size() > 0)
+ return insertionPoints.last();
+ return 0;
+}
+
+int QTextEngine::beginningOfLine(int lineNum)
+{
+ QVector<int> insertionPoints;
+ insertionPointsForLine(lineNum, insertionPoints);
+
+ if (insertionPoints.size() > 0)
+ return insertionPoints.first();
+ return 0;
+}
+
+int QTextEngine::positionAfterVisualMovement(int pos, QTextCursor::MoveOperation op)
+{
+ if (!layoutData)
+ itemize();
+
+ bool moveRight = (op == QTextCursor::Right);
+ bool alignRight = isRightToLeft();
+ if (!layoutData->hasBidi)
+ return moveRight ^ alignRight ? nextLogicalPosition(pos) : previousLogicalPosition(pos);
+
+ int lineNum = lineNumberForTextPosition(pos);
+ Q_ASSERT(lineNum >= 0);
+
+ QVector<int> insertionPoints;
+ insertionPointsForLine(lineNum, insertionPoints);
+ int i, max = insertionPoints.size();
+ for (i = 0; i < max; i++)
+ if (pos == insertionPoints[i]) {
+ if (moveRight) {
+ if (i + 1 < max)
+ return insertionPoints[i + 1];
+ } else {
+ if (i > 0)
+ return insertionPoints[i - 1];
+ }
+
+ if (moveRight ^ alignRight) {
+ if (lineNum + 1 < lines.size())
+ return alignRight ? endOfLine(lineNum + 1) : beginningOfLine(lineNum + 1);
+ }
+ else {
+ if (lineNum > 0)
+ return alignRight ? beginningOfLine(lineNum - 1) : endOfLine(lineNum - 1);
+ }
+ }
+
+ return pos;
+}
+
QStackTextEngine::QStackTextEngine(const QString &string, const QFont &f)
: QTextEngine(string, f),
_layoutData(string, _memory, MemSize)
@@ -2841,5 +3048,127 @@ glyph_metrics_t glyph_metrics_t::transformed(const QTransform &matrix) const
return m;
}
+QTextLineItemIterator::QTextLineItemIterator(QTextEngine *_eng, int _lineNum, const QPointF &pos,
+ const QTextLayout::FormatRange *_selection)
+ : eng(_eng),
+ line(eng->lines[_lineNum]),
+ si(0),
+ lineNum(_lineNum),
+ lineEnd(line.from + line.length),
+ firstItem(eng->findItem(line.from)),
+ lastItem(eng->findItem(lineEnd - 1)),
+ nItems((firstItem >= 0 && lastItem >= firstItem)? (lastItem-firstItem+1) : 0),
+ logicalItem(-1),
+ item(-1),
+ visualOrder(nItems),
+ levels(nItems),
+ selection(_selection)
+{
+ pos_x = x = QFixed::fromReal(pos.x());
+
+ x += line.x;
+
+ x += eng->alignLine(line);
+
+ for (int i = 0; i < nItems; ++i)
+ levels[i] = eng->layoutData->items[i+firstItem].analysis.bidiLevel;
+ QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
+
+ eng->shapeLine(line);
+}
+
+QScriptItem &QTextLineItemIterator::next()
+{
+ x += itemWidth;
+
+ ++logicalItem;
+ item = visualOrder[logicalItem] + firstItem;
+ itemLength = eng->length(item);
+ si = &eng->layoutData->items[item];
+ if (!si->num_glyphs)
+ eng->shape(item);
+
+ if (si->analysis.flags >= QScriptAnalysis::TabOrObject) {
+ itemWidth = si->width;
+ return *si;
+ }
+
+ unsigned short *logClusters = eng->logClusters(si);
+ QGlyphLayout glyphs = eng->shapedGlyphs(si);
+
+ itemStart = qMax(line.from, si->position);
+ glyphsStart = logClusters[itemStart - si->position];
+ if (lineEnd < si->position + itemLength) {
+ itemEnd = lineEnd;
+ glyphsEnd = logClusters[itemEnd-si->position];
+ } else {
+ itemEnd = si->position + itemLength;
+ glyphsEnd = si->num_glyphs;
+ }
+ // show soft-hyphen at line-break
+ if (si->position + itemLength >= lineEnd
+ && eng->layoutData->string.at(lineEnd - 1) == 0x00ad)
+ glyphs.attributes[glyphsEnd - 1].dontPrint = false;
+
+ itemWidth = 0;
+ for (int g = glyphsStart; g < glyphsEnd; ++g)
+ itemWidth += glyphs.effectiveAdvance(g);
+
+ return *si;
+}
+
+bool QTextLineItemIterator::getSelectionBounds(QFixed *selectionX, QFixed *selectionWidth) const
+{
+ *selectionX = *selectionWidth = 0;
+
+ if (!selection)
+ return false;
+
+ if (si->analysis.flags >= QScriptAnalysis::TabOrObject) {
+ if (si->position >= selection->start + selection->length
+ || si->position + itemLength <= selection->start)
+ return false;
+
+ *selectionX = x;
+ *selectionWidth = itemWidth;
+ } else {
+ unsigned short *logClusters = eng->logClusters(si);
+ QGlyphLayout glyphs = eng->shapedGlyphs(si);
+
+ int from = qMax(itemStart, selection->start) - si->position;
+ int to = qMin(itemEnd, selection->start + selection->length) - si->position;
+ if (from >= to)
+ return false;
+
+ int start_glyph = logClusters[from];
+ int end_glyph = (to == eng->length(item)) ? si->num_glyphs : logClusters[to];
+ QFixed soff;
+ QFixed swidth;
+ if (si->analysis.bidiLevel %2) {
+ for (int g = glyphsEnd - 1; g >= end_glyph; --g)
+ soff += glyphs.effectiveAdvance(g);
+ for (int g = end_glyph - 1; g >= start_glyph; --g)
+ swidth += glyphs.effectiveAdvance(g);
+ } else {
+ for (int g = glyphsStart; g < start_glyph; ++g)
+ soff += glyphs.effectiveAdvance(g);
+ for (int g = start_glyph; g < end_glyph; ++g)
+ swidth += glyphs.effectiveAdvance(g);
+ }
+
+ // If the starting character is in the middle of a ligature,
+ // selection should only contain the right part of that ligature
+ // glyph, so we need to get the width of the left part here and
+ // add it to *selectionX
+ QFixed leftOffsetInLigature = eng->offsetInLigature(si, from, to, start_glyph);
+ *selectionX = x + soff + leftOffsetInLigature;
+ *selectionWidth = swidth - leftOffsetInLigature;
+ // If the ending character is also part of a ligature, swidth does
+ // not contain that part yet, we also need to find out the width of
+ // that left part
+ *selectionWidth += eng->offsetInLigature(si, to, eng->length(item), end_glyph);
+ }
+ return true;
+}
QT_END_NAMESPACE
diff --git a/src/gui/text/qtextengine_p.h b/src/gui/text/qtextengine_p.h
index 366c5c3..c476485 100644
--- a/src/gui/text/qtextengine_p.h
+++ b/src/gui/text/qtextengine_p.h
@@ -64,6 +64,7 @@
#include "QtGui/qpaintengine.h"
#include "QtGui/qtextobject.h"
#include "QtGui/qtextoption.h"
+#include "QtGui/qtextcursor.h"
#include "QtCore/qset.h"
#include "QtCore/qdebug.h"
#ifndef QT_BUILD_COMPAT_LIB
@@ -471,6 +472,7 @@ public:
void shape(int item) const;
void justify(const QScriptLine &si);
+ QFixed alignLine(const QScriptLine &line);
QFixed width(int charFrom, int numChars) const;
glyph_metrics_t boundingBox(int from, int len) const;
@@ -586,12 +588,18 @@ public:
uint cacheGlyphs : 1;
uint stackEngine : 1;
uint forceJustification : 1;
+ uint visualMovement : 1;
int *underlinePositions;
mutable LayoutData *layoutData;
inline bool hasFormats() const { return (block.docHandle() || specialData); }
+ inline bool visualCursorMovement() const
+ {
+ return (visualMovement ||
+ (block.docHandle() ? block.docHandle()->defaultCursorMoveStyle == QTextCursor::Visual : false));
+ }
struct SpecialData {
int preeditPosition;
@@ -611,6 +619,13 @@ public:
void shapeLine(const QScriptLine &line);
QFixed leadingSpaceWidth(const QScriptLine &line);
+ QFixed offsetInLigature(const QScriptItem *si, int pos, int max, int glyph_pos);
+ int previousLogicalPosition(int oldPos) const;
+ int nextLogicalPosition(int oldPos) const;
+ int lineNumberForTextPosition(int pos);
+ int positionAfterVisualMovement(int oldPos, QTextCursor::MoveOperation op);
+ void insertionPointsForLine(int lineNum, QVector<int> &insertionPoints);
+
private:
void setBoundary(int strPos) const;
void addRequiredBoundaries() const;
@@ -625,6 +640,8 @@ private:
void splitItem(int item, int pos) const;
void resolveAdditionalFormats() const;
+ int endOfLine(int lineNum);
+ int beginningOfLine(int lineNum);
};
class QStackTextEngine : public QTextEngine {
@@ -635,6 +652,49 @@ public:
void *_memory[MemSize];
};
+struct QTextLineItemIterator
+{
+ QTextLineItemIterator(QTextEngine *eng, int lineNum, const QPointF &pos = QPointF(),
+ const QTextLayout::FormatRange *_selection = 0);
+
+ inline bool atEnd() const { return logicalItem >= nItems - 1; }
+ inline bool atBeginning() const { return logicalItem <= 0; }
+ QScriptItem &next();
+
+ bool getSelectionBounds(QFixed *selectionX, QFixed *selectionWidth) const;
+ inline bool isOutsideSelection() const {
+ QFixed tmp1, tmp2;
+ return !getSelectionBounds(&tmp1, &tmp2);
+ }
+
+ QTextEngine *eng;
+
+ QFixed x;
+ QFixed pos_x;
+ const QScriptLine &line;
+ QScriptItem *si;
+
+ int lineNum;
+ int lineEnd;
+ int firstItem;
+ int lastItem;
+ int nItems;
+ int logicalItem;
+ int item;
+ int itemLength;
+
+ int glyphsStart;
+ int glyphsEnd;
+ int itemStart;
+ int itemEnd;
+
+ QFixed itemWidth;
+
+ QVarLengthArray<int> visualOrder;
+ QVarLengthArray<uchar> levels;
+
+ const QTextLayout::FormatRange *selection;
+};
Q_DECLARE_OPERATORS_FOR_FLAGS(QTextEngine::ShaperFlags)
diff --git a/src/gui/text/qtextlayout.cpp b/src/gui/text/qtextlayout.cpp
index afe6949..bd224c6 100644
--- a/src/gui/text/qtextlayout.cpp
+++ b/src/gui/text/qtextlayout.cpp
@@ -54,35 +54,24 @@
#include "qpainterpath.h"
#include "qglyphs.h"
#include "qglyphs_p.h"
+#include "qrawfont.h"
+#include "qrawfont_p.h"
#include <limits.h>
#include <qdebug.h>
#include "qfontengine_p.h"
+#if !defined(QT_NO_FREETYPE)
+# include "qfontengine_ft_p.h"
+#endif
+
QT_BEGIN_NAMESPACE
#define ObjectSelectionBrush (QTextFormat::ForegroundBrush + 1)
#define SuppressText 0x5012
#define SuppressBackground 0x513
-static QFixed alignLine(QTextEngine *eng, const QScriptLine &line)
-{
- QFixed x = 0;
- eng->justify(line);
- // if width is QFIXED_MAX that means we used setNumColumns() and that implicitly makes this line left aligned.
- if (!line.justified && line.width != QFIXED_MAX) {
- int align = eng->option.alignment();
- if (align & Qt::AlignJustify && eng->isRightToLeft())
- align = Qt::AlignRight;
- if (align & Qt::AlignRight)
- x = line.width - (line.textAdvance + eng->leadingSpaceWidth(line));
- else if (align & Qt::AlignHCenter)
- x = (line.width - line.textAdvance)/2;
- }
- return x;
-}
-
/*!
\class QTextLayout::FormatRange
\reentrant
@@ -590,6 +579,30 @@ bool QTextLayout::cacheEnabled() const
}
/*!
+ Set the visual cursor movement style. If the QTextLayout is backed by
+ a document, you can ignore this and use the option in QTextDocument,
+ this option is for widgets like QLineEdit or custom widgets without
+ a QTextDocument. Default value is QTextCursor::Logical.
+
+ \sa setCursorMoveStyle()
+*/
+void QTextLayout::setCursorMoveStyle(QTextCursor::MoveStyle style)
+{
+ d->visualMovement = style == QTextCursor::Visual ? true : false;
+}
+
+/*!
+ The cursor movement style of this QTextLayout. The default is
+ QTextCursor::Logical.
+
+ \sa setCursorMoveStyle()
+*/
+QTextCursor::MoveStyle QTextLayout::cursorMoveStyle() const
+{
+ return d->visualMovement ? QTextCursor::Visual : QTextCursor::Logical;
+}
+
+/*!
Begins the layout process.
\sa endLayout()
@@ -712,6 +725,34 @@ int QTextLayout::previousCursorPosition(int oldPos, CursorMode mode) const
}
/*!
+ Returns the cursor position to the right of \a oldPos, next to it.
+ It's dependent on the visual position of characters, after bi-directional
+ reordering.
+
+ \sa leftCursorPosition(), nextCursorPosition()
+*/
+int QTextLayout::rightCursorPosition(int oldPos) const
+{
+ int newPos = d->positionAfterVisualMovement(oldPos, QTextCursor::Right);
+// qDebug("%d -> %d", oldPos, newPos);
+ return newPos;
+}
+
+/*!
+ Returns the cursor position to the left of \a oldPos, next to it.
+ It's dependent on the visual position of characters, after bi-directional
+ reordering.
+
+ \sa rightCursorPosition(), previousCursorPosition()
+*/
+int QTextLayout::leftCursorPosition(int oldPos) const
+{
+ int newPos = d->positionAfterVisualMovement(oldPos, QTextCursor::Left);
+// qDebug("%d -> %d", oldPos, newPos);
+ return newPos;
+}
+
+/*!/
Returns true if position \a pos is a valid cursor position.
In a Unicode context some positions in the text are not valid
@@ -809,16 +850,8 @@ QTextLine QTextLayout::lineAt(int i) const
*/
QTextLine QTextLayout::lineForTextPosition(int pos) const
{
- for (int i = 0; i < d->lines.size(); ++i) {
- const QScriptLine& line = d->lines[i];
- if (line.from + (int)line.length > pos)
- return QTextLine(i, d);
- }
- if (!d->layoutData)
- d->itemize();
- if (pos == d->layoutData->string.length() && d->lines.size())
- return QTextLine(d->lines.size()-1, d);
- return QTextLine();
+ int lineNum = d->lineNumberForTextPosition(pos);
+ return lineNum >= 0 ? lineAt(lineNum) : QTextLine();
}
/*!
@@ -913,201 +946,6 @@ void QTextLayout::setFlags(int flags)
}
}
-struct QTextLineItemIterator
-{
- QTextLineItemIterator(QTextEngine *eng, int lineNum, const QPointF &pos = QPointF(),
- const QTextLayout::FormatRange *_selection = 0);
-
- inline bool atEnd() const { return logicalItem >= nItems - 1; }
- QScriptItem &next();
-
- bool getSelectionBounds(QFixed *selectionX, QFixed *selectionWidth) const;
- inline bool isOutsideSelection() const {
- QFixed tmp1, tmp2;
- return !getSelectionBounds(&tmp1, &tmp2);
- }
-
- QTextEngine *eng;
-
- QFixed x;
- QFixed pos_x;
- const QScriptLine &line;
- QScriptItem *si;
-
- int lineEnd;
- int firstItem;
- int lastItem;
- int nItems;
- int logicalItem;
- int item;
- int itemLength;
-
- int glyphsStart;
- int glyphsEnd;
- int itemStart;
- int itemEnd;
-
- QFixed itemWidth;
-
- QVarLengthArray<int> visualOrder;
- QVarLengthArray<uchar> levels;
-
- const QTextLayout::FormatRange *selection;
-};
-
-QTextLineItemIterator::QTextLineItemIterator(QTextEngine *_eng, int lineNum, const QPointF &pos,
- const QTextLayout::FormatRange *_selection)
- : eng(_eng),
- line(eng->lines[lineNum]),
- si(0),
- lineEnd(line.from + line.length),
- firstItem(eng->findItem(line.from)),
- lastItem(eng->findItem(lineEnd - 1)),
- nItems((firstItem >= 0 && lastItem >= firstItem)? (lastItem-firstItem+1) : 0),
- logicalItem(-1),
- item(-1),
- visualOrder(nItems),
- levels(nItems),
- selection(_selection)
-{
- pos_x = x = QFixed::fromReal(pos.x());
-
- x += line.x;
-
- x += alignLine(eng, line);
-
- for (int i = 0; i < nItems; ++i)
- levels[i] = eng->layoutData->items[i+firstItem].analysis.bidiLevel;
- QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
-
- eng->shapeLine(line);
-}
-
-QScriptItem &QTextLineItemIterator::next()
-{
- x += itemWidth;
-
- ++logicalItem;
- item = visualOrder[logicalItem] + firstItem;
- itemLength = eng->length(item);
- si = &eng->layoutData->items[item];
- if (!si->num_glyphs)
- eng->shape(item);
-
- if (si->analysis.flags >= QScriptAnalysis::TabOrObject) {
- itemWidth = si->width;
- return *si;
- }
-
- unsigned short *logClusters = eng->logClusters(si);
- QGlyphLayout glyphs = eng->shapedGlyphs(si);
-
- itemStart = qMax(line.from, si->position);
- glyphsStart = logClusters[itemStart - si->position];
- if (lineEnd < si->position + itemLength) {
- itemEnd = lineEnd;
- glyphsEnd = logClusters[itemEnd-si->position];
- } else {
- itemEnd = si->position + itemLength;
- glyphsEnd = si->num_glyphs;
- }
- // show soft-hyphen at line-break
- if (si->position + itemLength >= lineEnd
- && eng->layoutData->string.at(lineEnd - 1) == 0x00ad)
- glyphs.attributes[glyphsEnd - 1].dontPrint = false;
-
- itemWidth = 0;
- for (int g = glyphsStart; g < glyphsEnd; ++g)
- itemWidth += glyphs.effectiveAdvance(g);
-
- return *si;
-}
-
-static QFixed offsetInLigature(const unsigned short *logClusters,
- const QGlyphLayout &glyphs,
- int pos, int max, int glyph_pos)
-{
- int offsetInCluster = 0;
- for (int i = pos - 1; i >= 0; i--) {
- if (logClusters[i] == glyph_pos)
- offsetInCluster++;
- else
- break;
- }
-
- // in the case that the offset is inside a (multi-character) glyph,
- // interpolate the position.
- if (offsetInCluster > 0) {
- int clusterLength = 0;
- for (int i = pos - offsetInCluster; i < max; i++) {
- if (logClusters[i] == glyph_pos)
- clusterLength++;
- else
- break;
- }
- if (clusterLength)
- return glyphs.advances_x[glyph_pos] * offsetInCluster / clusterLength;
- }
-
- return 0;
-}
-
-bool QTextLineItemIterator::getSelectionBounds(QFixed *selectionX, QFixed *selectionWidth) const
-{
- *selectionX = *selectionWidth = 0;
-
- if (!selection)
- return false;
-
- if (si->analysis.flags >= QScriptAnalysis::TabOrObject) {
- if (si->position >= selection->start + selection->length
- || si->position + itemLength <= selection->start)
- return false;
-
- *selectionX = x;
- *selectionWidth = itemWidth;
- } else {
- unsigned short *logClusters = eng->logClusters(si);
- QGlyphLayout glyphs = eng->shapedGlyphs(si);
-
- int from = qMax(itemStart, selection->start) - si->position;
- int to = qMin(itemEnd, selection->start + selection->length) - si->position;
- if (from >= to)
- return false;
-
- int start_glyph = logClusters[from];
- int end_glyph = (to == eng->length(item)) ? si->num_glyphs : logClusters[to];
- QFixed soff;
- QFixed swidth;
- if (si->analysis.bidiLevel %2) {
- for (int g = glyphsEnd - 1; g >= end_glyph; --g)
- soff += glyphs.effectiveAdvance(g);
- for (int g = end_glyph - 1; g >= start_glyph; --g)
- swidth += glyphs.effectiveAdvance(g);
- } else {
- for (int g = glyphsStart; g < start_glyph; ++g)
- soff += glyphs.effectiveAdvance(g);
- for (int g = start_glyph; g < end_glyph; ++g)
- swidth += glyphs.effectiveAdvance(g);
- }
-
- // If the starting character is in the middle of a ligature,
- // selection should only contain the right part of that ligature
- // glyph, so we need to get the width of the left part here and
- // add it to *selectionX
- QFixed leftOffsetInLigature = offsetInLigature(logClusters, glyphs, from,
- to, start_glyph);
- *selectionX = x + soff + leftOffsetInLigature;
- *selectionWidth = swidth - leftOffsetInLigature;
- // If the ending character is also part of a ligature, swidth does
- // not contain that part yet, we also need to find out the width of
- // that left part
- *selectionWidth += offsetInLigature(logClusters, glyphs, to,
- eng->length(item), end_glyph);
- }
- return true;
-}
-
static void addSelectedRegionsToPath(QTextEngine *eng, int lineNumber, const QPointF &pos, QTextLayout::FormatRange *selection,
QPainterPath *region, QRectF boundingRect)
{
@@ -1158,6 +996,7 @@ static inline QRectF clipIfValid(const QRectF &rect, const QRectF &clip)
\sa draw(), QPainter::drawGlyphs()
*/
+#if !defined(QT_NO_RAWFONT)
QList<QGlyphs> QTextLayout::glyphs() const
{
QList<QGlyphs> glyphs;
@@ -1166,6 +1005,7 @@ QList<QGlyphs> QTextLayout::glyphs() const
return glyphs;
}
+#endif // QT_NO_RAWFONT
/*!
Draws the whole layout on the painter \a p at the position specified by \a pos.
@@ -1374,18 +1214,9 @@ void QTextLayout::drawCursor(QPainter *p, const QPointF &pos, int cursorPosition
QFixed pos_y = QFixed::fromReal(position.y());
cursorPosition = qBound(0, cursorPosition, d->layoutData->string.length());
- int line = 0;
- if (cursorPosition == d->layoutData->string.length()) {
- line = d->lines.size() - 1;
- } else {
- // ### binary search
- for (line = 0; line < d->lines.size(); line++) {
- const QScriptLine &sl = d->lines[line];
- if (sl.from <= cursorPosition && sl.from + (int)sl.length > cursorPosition)
- break;
- }
- }
-
+ int line = d->lineNumberForTextPosition(cursorPosition);
+ if (line < 0)
+ line = 0;
if (line >= d->lines.size())
return;
@@ -1394,7 +1225,15 @@ void QTextLayout::drawCursor(QPainter *p, const QPointF &pos, int cursorPosition
qreal x = position.x() + l.cursorToX(cursorPosition);
- int itm = d->findItem(cursorPosition - 1);
+ int itm;
+
+ if (d->visualCursorMovement()) {
+ if (cursorPosition == sl.from + sl.length)
+ cursorPosition--;
+ itm = d->findItem(cursorPosition);
+ } else
+ itm = d->findItem(cursorPosition - 1);
+
QFixed base = sl.base();
QFixed descent = sl.descent;
bool rightToLeft = d->isRightToLeft();
@@ -1504,7 +1343,7 @@ QRectF QTextLine::rect() const
QRectF QTextLine::naturalTextRect() const
{
const QScriptLine& sl = eng->lines[i];
- QFixed x = sl.x + alignLine(eng, sl);
+ QFixed x = sl.x + eng->alignLine(sl);
QFixed width = sl.textWidth;
if (sl.justified)
@@ -2257,6 +2096,7 @@ namespace {
\sa QTextLayout::glyphs()
*/
+#if !defined(QT_NO_RAWFONT)
QList<QGlyphs> QTextLine::glyphs(int from, int length) const
{
const QScriptLine &line = eng->lines[i];
@@ -2331,7 +2171,35 @@ QList<QGlyphs> QTextLine::glyphs(int from, int length) const
QFontEngine *fontEngine = keys.at(i);
// Make a font for this particular engine
- QFont font = fontEngine->createExplicitFont();
+ QRawFont font;
+ QRawFontPrivate *fontD = QRawFontPrivate::get(font);
+ fontD->fontEngine = fontEngine;
+ fontD->fontEngine->ref.ref();
+
+#if defined(Q_WS_WIN)
+ if (fontEngine->supportsSubPixelPositions())
+ fontD->hintingPreference = QFont::PreferVerticalHinting;
+ else
+ fontD->hintingPreference = QFont::PreferFullHinting;
+#elif defined(Q_WS_MAC)
+ fontD->hintingPreference = QFont::PreferNoHinting;
+#elif !defined(QT_NO_FREETYPE)
+ if (fontEngine->type() == QFontEngine::Freetype) {
+ QFontEngineFT *freeTypeEngine = static_cast<QFontEngineFT *>(fontEngine);
+ switch (freeTypeEngine->defaultHintStyle()) {
+ case QFontEngineFT::HintNone:
+ fontD->hintingPreference = QFont::PreferNoHinting;
+ break;
+ case QFontEngineFT::HintLight:
+ fontD->hintingPreference = QFont::PreferVerticalHinting;
+ break;
+ case QFontEngineFT::HintMedium:
+ case QFontEngineFT::HintFull:
+ fontD->hintingPreference = QFont::PreferFullHinting;
+ break;
+ };
+ }
+#endif
QList<GlyphInfo> glyphLayouts = glyphLayoutHash.values(fontEngine);
for (int j=0; j<glyphLayouts.size(); ++j) {
@@ -2339,10 +2207,6 @@ QList<QGlyphs> QTextLine::glyphs(int from, int length) const
const QGlyphLayout &glyphLayout = glyphLayouts.at(j).glyphLayout;
const QTextItem::RenderFlags &flags = glyphLayouts.at(j).flags;
- font.setOverline(flags.testFlag(QTextItem::Overline));
- font.setUnderline(flags.testFlag(QTextItem::Underline));
- font.setStrikeOut(flags.testFlag(QTextItem::StrikeOut));
-
QVarLengthArray<glyph_t> glyphsArray;
QVarLengthArray<QFixedPoint> positionsArray;
@@ -2361,19 +2225,22 @@ QList<QGlyphs> QTextLine::glyphs(int from, int length) const
glyphIndexes.setGlyphIndexes(glyphs);
glyphIndexes.setPositions(positions);
- QPair<QFontEngine *, int> key(fontEngine, int(flags));
+ glyphIndexes.setOverline(flags.testFlag(QTextItem::Overline));
+ glyphIndexes.setUnderline(flags.testFlag(QTextItem::Underline));
+ glyphIndexes.setStrikeOut(flags.testFlag(QTextItem::StrikeOut));
+ glyphIndexes.setFont(font);
+ QPair<QFontEngine *, int> key(fontEngine, int(flags));
if (!glyphsHash.contains(key))
- glyphsHash.insert(key, QGlyphs());
-
- QGlyphs &target = glyphsHash[key];
- target += glyphIndexes;
- target.setFont(font);
+ glyphsHash.insert(key, glyphIndexes);
+ else
+ glyphsHash[key] += glyphIndexes;
}
}
return glyphsHash.values();
}
+#endif // QT_NO_RAWFONT
/*!
\fn void QTextLine::draw(QPainter *painter, const QPointF &position, const QTextLayout::FormatRange *selection) const
@@ -2596,9 +2463,10 @@ qreal QTextLine::cursorToX(int *cursorPos, Edge edge) const
eng->itemize();
const QScriptLine &line = eng->lines[i];
+ bool lastLine = i >= eng->lines.size() - 1;
QFixed x = line.x;
- x += alignLine(eng, line);
+ x += eng->alignLine(line);
if (!i && !eng->layoutData->items.size()) {
*cursorPos = 0;
@@ -2684,21 +2552,29 @@ qreal QTextLine::cursorToX(int *cursorPos, Edge edge) const
logClusters = eng->logClusters(si);
glyphs = eng->shapedGlyphs(si);
if (si->analysis.flags >= QScriptAnalysis::TabOrObject) {
- if(pos == l)
+ if (pos == (reverse ? 0 : l))
x += si->width;
} else {
+ bool rtl = eng->isRightToLeft();
+ bool visual = eng->visualCursorMovement();
if (reverse) {
int end = qMin(lineEnd, si->position + l) - si->position;
int glyph_end = end == l ? si->num_glyphs : logClusters[end];
- for (int i = glyph_end - 1; i >= glyph_pos; i--)
+ int glyph_start = glyph_pos;
+ if (visual && !rtl && !(lastLine && itm == (visualOrder[nItems - 1] + firstItem)))
+ glyph_start++;
+ for (int i = glyph_end - 1; i >= glyph_start; i--)
x += glyphs.effectiveAdvance(i);
} else {
int start = qMax(line.from - si->position, 0);
int glyph_start = logClusters[start];
- for (int i = glyph_start; i < glyph_pos; i++)
+ int glyph_end = glyph_pos;
+ if (!visual || !rtl || (lastLine && itm == visualOrder[0] + firstItem))
+ glyph_end--;
+ for (int i = glyph_start; i <= glyph_end; i++)
x += glyphs.effectiveAdvance(i);
}
- x += offsetInLigature(logClusters, glyphs, pos, line.length, glyph_pos);
+ x += eng->offsetInLigature(si, pos, line.length, glyph_pos);
}
*cursorPos = pos + si->position;
@@ -2717,6 +2593,8 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
{
QFixed x = QFixed::fromReal(_x);
const QScriptLine &line = eng->lines[i];
+ bool lastLine = i >= eng->lines.size() - 1;
+ int lineNum = i;
if (!eng->layoutData)
eng->itemize();
@@ -2734,7 +2612,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
return 0;
x -= line.x;
- x -= alignLine(eng, line);
+ x -= eng->alignLine(line);
// qDebug("xToCursor: x=%f, cpos=%d", x.toReal(), cpos);
QVarLengthArray<int> visualOrder(nItems);
@@ -2743,6 +2621,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
levels[i] = eng->layoutData->items[i+firstItem].analysis.bidiLevel;
QTextEngine::bidiReorder(nItems, levels.data(), visualOrder.data());
+ bool visual = eng->visualCursorMovement();
if (x <= 0) {
// left of first item
int item = visualOrder[0]+firstItem;
@@ -2759,8 +2638,13 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
|| (line.justified && x < line.width)) {
// has to be in one of the runs
QFixed pos;
+ bool rtl = eng->isRightToLeft();
eng->shapeLine(line);
+ QVector<int> insertionPoints;
+ if (visual && rtl)
+ eng->insertionPointsForLine(lineNum, insertionPoints);
+ int nchars = 0;
for (int i = 0; i < nItems; ++i) {
int item = visualOrder[i]+firstItem;
QScriptItem &si = eng->layoutData->items[item];
@@ -2790,6 +2674,7 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
if (pos + item_width < x) {
pos += item_width;
+ nchars += end;
continue;
}
// qDebug(" inside run");
@@ -2834,27 +2719,60 @@ int QTextLine::xToCursor(qreal _x, CursorPosition cpos) const
} else {
QFixed dist = INT_MAX/256;
if (si.analysis.bidiLevel % 2) {
- pos += item_width;
- while (gs <= ge) {
- if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) {
- glyph_pos = gs;
- dist = qAbs(x-pos);
+ if (!visual || rtl || (lastLine && i == nItems - 1)) {
+ pos += item_width;
+ while (gs <= ge) {
+ if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) {
+ glyph_pos = gs;
+ dist = qAbs(x-pos);
+ }
+ pos -= glyphs.effectiveAdvance(gs);
+ ++gs;
+ }
+ } else {
+ while (ge >= gs) {
+ if (glyphs.attributes[ge].clusterStart && qAbs(x-pos) < dist) {
+ glyph_pos = ge;
+ dist = qAbs(x-pos);
+ }
+ pos += glyphs.effectiveAdvance(ge);
+ --ge;
}
- pos -= glyphs.effectiveAdvance(gs);
- ++gs;
}
} else {
- while (gs <= ge) {
- if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) {
- glyph_pos = gs;
- dist = qAbs(x-pos);
+ if (!visual || !rtl || (lastLine && i == 0)) {
+ while (gs <= ge) {
+ if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) {
+ glyph_pos = gs;
+ dist = qAbs(x-pos);
+ }
+ pos += glyphs.effectiveAdvance(gs);
+ ++gs;
}
- pos += glyphs.effectiveAdvance(gs);
- ++gs;
+ } else {
+ QFixed oldPos = pos;
+ while (gs <= ge) {
+ pos += glyphs.effectiveAdvance(gs);
+ if (glyphs.attributes[gs].clusterStart && qAbs(x-pos) < dist) {
+ glyph_pos = gs;
+ dist = qAbs(x-pos);
+ }
+ ++gs;
+ }
+ pos = oldPos;
}
}
- if (qAbs(x-pos) < dist)
+ if (qAbs(x-pos) < dist) {
+ if (visual) {
+ if (!rtl && i < nItems - 1) {
+ nchars += end;
+ continue;
+ }
+ if (rtl && nchars > 0)
+ return insertionPoints[lastLine ? nchars : nchars - 1];
+ }
return si.position + end;
+ }
}
Q_ASSERT(glyph_pos != -1);
int j;
diff --git a/src/gui/text/qtextlayout.h b/src/gui/text/qtextlayout.h
index 0f64c33..6aa81f9 100644
--- a/src/gui/text/qtextlayout.h
+++ b/src/gui/text/qtextlayout.h
@@ -50,6 +50,7 @@
#include <QtGui/qevent.h>
#include <QtGui/qtextformat.h>
#include <QtGui/qglyphs.h>
+#include <QtGui/qtextcursor.h>
QT_BEGIN_HEADER
@@ -136,6 +137,9 @@ public:
void setCacheEnabled(bool enable);
bool cacheEnabled() const;
+ void setCursorMoveStyle(QTextCursor::MoveStyle style);
+ QTextCursor::MoveStyle cursorMoveStyle() const;
+
void beginLayout();
void endLayout();
void clearLayout();
@@ -153,6 +157,8 @@ public:
bool isValidCursorPosition(int pos) const;
int nextCursorPosition(int oldPos, CursorMode mode = SkipCharacters) const;
int previousCursorPosition(int oldPos, CursorMode mode = SkipCharacters) const;
+ int leftCursorPosition(int oldPos) const;
+ int rightCursorPosition(int oldPos) const;
void draw(QPainter *p, const QPointF &pos, const QVector<FormatRange> &selections = QVector<FormatRange>(),
const QRectF &clip = QRectF()) const;
@@ -167,7 +173,9 @@ public:
qreal minimumWidth() const;
qreal maximumWidth() const;
+#if !defined(QT_NO_RAWFONT)
QList<QGlyphs> glyphs() const;
+#endif
QTextEngine *engine() const { return d; }
void setFlags(int flags);
@@ -239,7 +247,10 @@ public:
private:
QTextLine(int line, QTextEngine *e) : i(line), eng(e) {}
void layout_helper(int numGlyphs);
+
+#if !defined(QT_NO_RAWFONT)
QList<QGlyphs> glyphs(int from, int length) const;
+#endif
friend class QTextLayout;
friend class QTextFragment;
diff --git a/src/gui/text/qtextobject.cpp b/src/gui/text/qtextobject.cpp
index 0081550..0a9dff8 100644
--- a/src/gui/text/qtextobject.cpp
+++ b/src/gui/text/qtextobject.cpp
@@ -1661,6 +1661,7 @@ QTextBlock::iterator &QTextBlock::iterator::operator--()
\sa QGlyphs, QTextBlock::layout(), QTextLayout::position(), QPainter::drawGlyphs()
*/
+#if !defined(QT_NO_RAWFONT)
QList<QGlyphs> QTextFragment::glyphs() const
{
if (!p || !n)
@@ -1684,6 +1685,7 @@ QList<QGlyphs> QTextFragment::glyphs() const
return ret;
}
+#endif // QT_NO_RAWFONT
/*!
Returns the position of this text fragment in the document.
diff --git a/src/gui/text/qtextobject.h b/src/gui/text/qtextobject.h
index fface3f..2e588c2 100644
--- a/src/gui/text/qtextobject.h
+++ b/src/gui/text/qtextobject.h
@@ -316,7 +316,9 @@ public:
int charFormatIndex() const;
QString text() const;
+#if !defined(QT_NO_RAWFONT)
QList<QGlyphs> glyphs() const;
+#endif
private:
const QTextDocumentPrivate *p;
diff --git a/src/gui/text/text.pri b/src/gui/text/text.pri
index 7fb2783..83be5b4 100644
--- a/src/gui/text/text.pri
+++ b/src/gui/text/text.pri
@@ -41,7 +41,9 @@ HEADERS += \
text/qstatictext_p.h \
text/qstatictext.h \
text/qglyphs.h \
- text/qglyphs_p.h
+ text/qglyphs_p.h \
+ text/qrawfont.h \
+ text/qrawfont_p.h
SOURCES += \
text/qfont.cpp \
@@ -72,12 +74,14 @@ SOURCES += \
text/qzip.cpp \
text/qtextodfwriter.cpp \
text/qstatictext.cpp \
- text/qglyphs.cpp
+ text/qglyphs.cpp \
+ text/qrawfont.cpp
win32 {
SOURCES += \
text/qfont_win.cpp \
- text/qfontengine_win.cpp
+ text/qfontengine_win.cpp \
+ text/qrawfont_win.cpp
HEADERS += text/qfontengine_win_p.h
}
@@ -95,7 +99,8 @@ unix:x11 {
SOURCES += \
text/qfont_x11.cpp \
text/qfontengine_x11.cpp \
- text/qfontengine_ft.cpp
+ text/qfontengine_ft.cpp \
+ text/qrawfont_ft.cpp
}
!embedded:!qpa:!x11:mac {
@@ -104,10 +109,14 @@ unix:x11 {
OBJECTIVE_HEADERS += \
text/qfontengine_coretext_p.h
SOURCES += \
- text/qfont_mac.cpp
+ text/qfont_mac.cpp \
+ text/qrawfont_mac.cpp
OBJECTIVE_SOURCES += \
text/qfontengine_coretext.mm \
text/qfontengine_mac.mm
+ contains(QT_CONFIG, harfbuzz) {
+ DEFINES += QT_ENABLE_HARFBUZZ_FOR_MAC
+ }
}
embedded {
@@ -116,7 +125,8 @@ embedded {
text/qfontengine_qws.cpp \
text/qfontengine_ft.cpp \
text/qfontengine_qpf.cpp \
- text/qabstractfontengine_qws.cpp
+ text/qabstractfontengine_qws.cpp \
+ text/qrawfont_ft.cpp
HEADERS += \
text/qfontengine_ft_p.h \
text/qfontengine_qpf_p.h \
@@ -143,7 +153,8 @@ symbian {
text/qfont_s60.cpp
contains(QT_CONFIG, freetype) {
SOURCES += \
- text/qfontengine_ft.cpp
+ text/qfontengine_ft.cpp \
+ text/qrawfont_ft.cpp
HEADERS += \
text/qfontengine_ft_p.h
DEFINES += \
diff --git a/src/gui/widgets/qlinecontrol.cpp b/src/gui/widgets/qlinecontrol.cpp
index 3eac64a..a1b3ff8 100644
--- a/src/gui/widgets/qlinecontrol.cpp
+++ b/src/gui/widgets/qlinecontrol.cpp
@@ -1577,6 +1577,7 @@ void QLineControl::processKeyEvent(QKeyEvent* event)
}
bool unknown = false;
+ bool visual = cursorMoveStyle() == QTextCursor::Visual;
if (false) {
}
@@ -1641,11 +1642,11 @@ void QLineControl::processKeyEvent(QKeyEvent* event)
#endif
moveCursor(selectionEnd(), false);
} else {
- cursorForward(0, layoutDirection() == Qt::LeftToRight ? 1 : -1);
+ cursorForward(0, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
}
}
else if (event == QKeySequence::SelectNextChar) {
- cursorForward(1, layoutDirection() == Qt::LeftToRight ? 1 : -1);
+ cursorForward(1, visual ? 1 : (layoutDirection() == Qt::LeftToRight ? 1 : -1));
}
else if (event == QKeySequence::MoveToPreviousChar) {
#if !defined(Q_WS_WIN) || defined(QT_NO_COMPLETER)
@@ -1656,11 +1657,11 @@ void QLineControl::processKeyEvent(QKeyEvent* event)
#endif
moveCursor(selectionStart(), false);
} else {
- cursorForward(0, layoutDirection() == Qt::LeftToRight ? -1 : 1);
+ cursorForward(0, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
}
}
else if (event == QKeySequence::SelectPreviousChar) {
- cursorForward(1, layoutDirection() == Qt::LeftToRight ? -1 : 1);
+ cursorForward(1, visual ? -1 : (layoutDirection() == Qt::LeftToRight ? -1 : 1));
}
else if (event == QKeySequence::MoveToNextWord) {
if (echoMode() == QLineEdit::Normal)
diff --git a/src/gui/widgets/qlinecontrol_p.h b/src/gui/widgets/qlinecontrol_p.h
index 3c505c8..0042f17 100644
--- a/src/gui/widgets/qlinecontrol_p.h
+++ b/src/gui/widgets/qlinecontrol_p.h
@@ -160,6 +160,8 @@ public:
int cursorWidth() const { return m_cursorWidth; }
void setCursorWidth(int value) { m_cursorWidth = value; }
+ QTextCursor::MoveStyle cursorMoveStyle() const { return m_textLayout.cursorMoveStyle(); }
+ void setCursorMoveStyle(QTextCursor::MoveStyle style) { m_textLayout.setCursorMoveStyle(style); }
void moveCursor(int pos, bool mark = false);
void cursorForward(bool mark, int steps)
@@ -167,10 +169,12 @@ public:
int c = m_cursor;
if (steps > 0) {
while (steps--)
- c = m_textLayout.nextCursorPosition(c);
+ c = cursorMoveStyle() == QTextCursor::Visual ? m_textLayout.rightCursorPosition(c)
+ : m_textLayout.nextCursorPosition(c);
} else if (steps < 0) {
while (steps++)
- c = m_textLayout.previousCursorPosition(c);
+ c = cursorMoveStyle() == QTextCursor::Visual ? m_textLayout.leftCursorPosition(c)
+ : m_textLayout.previousCursorPosition(c);
}
moveCursor(c, mark);
}
diff --git a/src/gui/widgets/qlineedit.cpp b/src/gui/widgets/qlineedit.cpp
index 07bd273..43c3f52 100644
--- a/src/gui/widgets/qlineedit.cpp
+++ b/src/gui/widgets/qlineedit.cpp
@@ -1112,6 +1112,34 @@ void QLineEdit::setDragEnabled(bool b)
/*!
+ \property QLineEdit::cursorMoveStyle
+ \brief the movement style of cursor in this line edit
+ \since 4.8
+
+ When this property is set to QTextCursor::Visual, the line edit will use visual
+ movement style. Pressing the left arrow key will always cause the cursor to move
+ left, regardless of the text's writing direction. The same behavior applies to
+ right arrow key.
+
+ When the property is QTextCursor::Logical (the default), within a LTR text block,
+ increase cursor position when pressing left arrow key, decrease cursor position
+ when pressing the right arrow key. If the text block is right to left, the opposite
+ behavior applies.
+*/
+
+QTextCursor::MoveStyle QLineEdit::cursorMoveStyle() const
+{
+ Q_D(const QLineEdit);
+ return d->control->cursorMoveStyle();
+}
+
+void QLineEdit::setCursorMoveStyle(QTextCursor::MoveStyle style)
+{
+ Q_D(QLineEdit);
+ d->control->setCursorMoveStyle(style);
+}
+
+/*!
\property QLineEdit::acceptableInput
\brief whether the input satisfies the inputMask and the
validator.
diff --git a/src/gui/widgets/qlineedit.h b/src/gui/widgets/qlineedit.h
index 636cee7..73a736c 100644
--- a/src/gui/widgets/qlineedit.h
+++ b/src/gui/widgets/qlineedit.h
@@ -43,6 +43,7 @@
#define QLINEEDIT_H
#include <QtGui/qframe.h>
+#include <QtGui/qtextcursor.h>
#include <QtCore/qstring.h>
#include <QtCore/qmargins.h>
@@ -158,6 +159,9 @@ public:
void setDragEnabled(bool b);
bool dragEnabled() const;
+ void setCursorMoveStyle(QTextCursor::MoveStyle style);
+ QTextCursor::MoveStyle cursorMoveStyle() const;
+
QString inputMask() const;
void setInputMask(const QString &inputMask);
bool hasAcceptableInput() const;
diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
index 8068aa8..207ab3d 100644
--- a/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
+++ b/src/opengl/gl2paintengineex/qglengineshadermanager.cpp
@@ -495,6 +495,8 @@ GLuint QGLEngineShaderManager::getUniformLocation(Uniform id)
"fmp",
"fmp2_m_radius2",
"inverse_2_fmp2_m_radius2",
+ "sqrfr",
+ "bradius",
"invertedTextureSize",
"brushTransform",
"brushTexture",
diff --git a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
index 7cc9dc3..bf2fe42 100644
--- a/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
+++ b/src/opengl/gl2paintengineex/qglengineshadermanager_p.h
@@ -442,6 +442,8 @@ public:
Fmp,
Fmp2MRadius2,
Inverse2Fmp2MRadius2,
+ SqrFr,
+ BRadius,
InvertedTextureSize,
BrushTransform,
BrushTexture,
diff --git a/src/opengl/gl2paintengineex/qglengineshadersource_p.h b/src/opengl/gl2paintengineex/qglengineshadersource_p.h
index fc8b9ef..9362c58 100644
--- a/src/opengl/gl2paintengineex/qglengineshadersource_p.h
+++ b/src/opengl/gl2paintengineex/qglengineshadersource_p.h
@@ -241,6 +241,7 @@ static const char* const qglslPositionWithRadialGradientBrushVertexShader = "\n\
uniform mediump vec2 halfViewportSize; \n\
uniform highp mat3 brushTransform; \n\
uniform highp vec2 fmp; \n\
+ uniform highp vec3 bradius; \n\
varying highp float b; \n\
varying highp vec2 A; \n\
void setPosition(void) \n\
@@ -253,7 +254,7 @@ static const char* const qglslPositionWithRadialGradientBrushVertexShader = "\n\
mediump float invertedHTexCoordsZ = 1.0 / hTexCoords.z; \n\
gl_Position = vec4(gl_Position.xy * invertedHTexCoordsZ, 0.0, invertedHTexCoordsZ); \n\
A = hTexCoords.xy * invertedHTexCoordsZ; \n\
- b = 2.0 * dot(A, fmp); \n\
+ b = bradius.x + 2.0 * dot(A, fmp); \n\
}\n";
static const char* const qglslAffinePositionWithRadialGradientBrushVertexShader
@@ -263,13 +264,22 @@ static const char* const qglslRadialGradientBrushSrcFragmentShader = "\n\
uniform sampler2D brushTexture; \n\
uniform highp float fmp2_m_radius2; \n\
uniform highp float inverse_2_fmp2_m_radius2; \n\
+ uniform highp float sqrfr; \n\
varying highp float b; \n\
varying highp vec2 A; \n\
+ uniform highp vec3 bradius; \n\
lowp vec4 srcPixel() \n\
{ \n\
- highp float c = -dot(A, A); \n\
- highp vec2 val = vec2((-b + sqrt(b*b - 4.0*fmp2_m_radius2*c)) * inverse_2_fmp2_m_radius2, 0.5); \n\
- return texture2D(brushTexture, val); \n\
+ highp float c = sqrfr-dot(A, A); \n\
+ highp float det = b*b - 4.0*fmp2_m_radius2*c; \n\
+ lowp vec4 result = vec4(0.0); \n\
+ if (det >= 0.0) { \n\
+ highp float detSqrt = sqrt(det); \n\
+ highp float w = max((-b - detSqrt) * inverse_2_fmp2_m_radius2, (-b + detSqrt) * inverse_2_fmp2_m_radius2); \n\
+ if (bradius.y + w * bradius.z >= 0.0) \n\
+ result = texture2D(brushTexture, vec2(w, 0.5)); \n\
+ } \n\
+ return result; \n\
}\n";
diff --git a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
index 18c684f..a2707e0 100644
--- a/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
+++ b/src/opengl/gl2paintengineex/qpaintengineex_opengl2.cpp
@@ -301,7 +301,7 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms()
const QRadialGradient *g = static_cast<const QRadialGradient *>(currentBrush.gradient());
QPointF realCenter = g->center();
QPointF realFocal = g->focalPoint();
- qreal realRadius = g->radius();
+ qreal realRadius = g->centerRadius() - g->focalRadius();
translationPoint = realFocal;
QPointF fmp = realCenter - realFocal;
@@ -311,6 +311,12 @@ void QGL2PaintEngineExPrivate::updateBrushUniforms()
shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Fmp2MRadius2), fmp2_m_radius2);
shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::Inverse2Fmp2MRadius2),
GLfloat(1.0 / (2.0*fmp2_m_radius2)));
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::SqrFr),
+ GLfloat(g->focalRadius() * g->focalRadius()));
+ shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::BRadius),
+ GLfloat(2 * (g->centerRadius() - g->focalRadius()) * g->focalRadius()),
+ g->focalRadius(),
+ g->centerRadius() - g->focalRadius());
QVector2D halfViewportSize(width*0.5, height*0.5);
shaderManager->currentProgram()->setUniformValue(location(QGLEngineShaderManager::HalfViewportSize), halfViewportSize);
diff --git a/src/opengl/qpaintengine_opengl.cpp b/src/opengl/qpaintengine_opengl.cpp
index 2c01ac4..efa050d 100644
--- a/src/opengl/qpaintengine_opengl.cpp
+++ b/src/opengl/qpaintengine_opengl.cpp
@@ -2119,6 +2119,7 @@ void QOpenGLPaintEnginePrivate::fillPath(const QPainterPath &path)
updateGLMatrix();
}
+extern bool qt_isExtendedRadialGradient(const QBrush &brush);
static inline bool needsEmulation(Qt::BrushStyle style)
{
@@ -2129,9 +2130,11 @@ static inline bool needsEmulation(Qt::BrushStyle style)
void QOpenGLPaintEnginePrivate::updateUseEmulation()
{
- use_emulation = !use_fragment_programs
- && ((has_pen && needsEmulation(pen_brush_style))
- || (has_brush && needsEmulation(brush_style)));
+ use_emulation = (!use_fragment_programs
+ && ((has_pen && needsEmulation(pen_brush_style))
+ || (has_brush && needsEmulation(brush_style))))
+ || (has_pen && qt_isExtendedRadialGradient(cpen.brush()))
+ || (has_brush && qt_isExtendedRadialGradient(cbrush));
}
void QOpenGLPaintEngine::updatePen(const QPen &pen)
@@ -5442,50 +5445,7 @@ void QOpenGLPaintEngine::transformChanged()
updateMatrix(state()->matrix);
}
-static QPainterPath painterPathFromVectorPath(const QVectorPath &path)
-{
- const qreal *points = path.points();
- const QPainterPath::ElementType *types = path.elements();
-
- QPainterPath p;
- if (types) {
- int id = 0;
- for (int i=0; i<path.elementCount(); ++i) {
- switch(types[i]) {
- case QPainterPath::MoveToElement:
- p.moveTo(QPointF(points[id], points[id+1]));
- id+=2;
- break;
- case QPainterPath::LineToElement:
- p.lineTo(QPointF(points[id], points[id+1]));
- id+=2;
- break;
- case QPainterPath::CurveToElement: {
- QPointF p1(points[id], points[id+1]);
- QPointF p2(points[id+2], points[id+3]);
- QPointF p3(points[id+4], points[id+5]);
- p.cubicTo(p1, p2, p3);
- id+=6;
- break;
- }
- case QPainterPath::CurveToDataElement:
- ;
- break;
- }
- }
- } else {
- p.moveTo(QPointF(points[0], points[1]));
- int id = 2;
- for (int i=1; i<path.elementCount(); ++i) {
- p.lineTo(QPointF(points[id], points[id+1]));
- id+=2;
- }
- }
- if (path.hints() & QVectorPath::WindingFill)
- p.setFillRule(Qt::WindingFill);
-
- return p;
-}
+extern QPainterPath qt_painterPathFromVectorPath(const QVectorPath &path);
void QOpenGLPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
{
@@ -5494,11 +5454,11 @@ void QOpenGLPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
if (brush.style() == Qt::NoBrush)
return;
- if (!d->use_fragment_programs && needsEmulation(brush.style())) {
+ if ((!d->use_fragment_programs && needsEmulation(brush.style())) || qt_isExtendedRadialGradient(brush)) {
QPainter *p = painter();
QBrush oldBrush = p->brush();
p->setBrush(brush);
- qt_draw_helper(p->d_ptr.data(), painterPathFromVectorPath(path), QPainterPrivate::FillDraw);
+ qt_draw_helper(p->d_ptr.data(), qt_painterPathFromVectorPath(path), QPainterPrivate::FillDraw);
p->setBrush(oldBrush);
return;
}
@@ -5515,7 +5475,7 @@ void QOpenGLPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
drawRects(&r, 1);
updatePen(old_pen);
} else {
- d->fillPath(painterPathFromVectorPath(path));
+ d->fillPath(qt_painterPathFromVectorPath(path));
}
updateBrush(old_brush, state()->brushOrigin);
diff --git a/src/openvg/qpaintengine_vg.cpp b/src/openvg/qpaintengine_vg.cpp
index 3c2b5fd..7c9d102 100644
--- a/src/openvg/qpaintengine_vg.cpp
+++ b/src/openvg/qpaintengine_vg.cpp
@@ -173,6 +173,9 @@ public:
bool forcePenChange; // Force a pen change, even if the same.
bool forceBrushChange; // Force a brush change, even if the same.
+ bool hasExtendedRadialGradientPen; // Current pen's brush is extended radial gradient.
+ bool hasExtendedRadialGradientBrush; // Current brush is extended radial gradient.
+
VGPaintType penType; // Type of the last pen that was set.
VGPaintType brushType; // Type of the last brush that was set.
@@ -275,6 +278,27 @@ public:
}
}
+ inline bool needsEmulation(const QBrush &brush) const
+ {
+ extern bool qt_isExtendedRadialGradient(const QBrush &brush);
+ return qt_isExtendedRadialGradient(brush);
+ }
+
+ inline bool needsEmulation() const
+ {
+ return hasExtendedRadialGradientPen || hasExtendedRadialGradientBrush;
+ }
+
+ inline bool needsPenEmulation() const
+ {
+ return hasExtendedRadialGradientPen;
+ }
+
+ inline bool needsBrushEmulation() const
+ {
+ return hasExtendedRadialGradientBrush;
+ }
+
// Set various modes, but only if different.
inline void setImageMode(VGImageMode mode);
inline void setRenderingQuality(VGRenderingQuality mode);
@@ -355,6 +379,10 @@ void QVGPaintEnginePrivate::init()
forcePenChange = true;
forceBrushChange = true;
+
+ hasExtendedRadialGradientPen = false;
+ hasExtendedRadialGradientBrush = false;
+
penType = (VGPaintType)0;
brushType = (VGPaintType)0;
@@ -1534,6 +1562,10 @@ bool QVGPaintEngine::end()
void QVGPaintEngine::draw(const QVectorPath &path)
{
Q_D(QVGPaintEngine);
+ if (d->needsEmulation()) {
+ QPaintEngineEx::draw(path);
+ return;
+ }
QVGPainterState *s = state();
VGPath vgpath = d->vectorPathToVGPath(path);
if (!path.hasWindingFill())
@@ -1543,9 +1575,19 @@ void QVGPaintEngine::draw(const QVectorPath &path)
vgDestroyPath(vgpath);
}
+extern QPainterPath qt_painterPathFromVectorPath(const QVectorPath &path);
+
void QVGPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
{
Q_D(QVGPaintEngine);
+ if (d->needsEmulation(brush)) {
+ QPainter *p = painter();
+ QBrush oldBrush = p->brush();
+ p->setBrush(brush);
+ qt_draw_helper(p->d_ptr.data(), qt_painterPathFromVectorPath(path), QPainterPrivate::FillDraw);
+ p->setBrush(oldBrush);
+ return;
+ }
VGPath vgpath = d->vectorPathToVGPath(path);
if (!path.hasWindingFill())
d->fill(vgpath, brush, VG_EVEN_ODD);
@@ -1557,6 +1599,10 @@ void QVGPaintEngine::fill(const QVectorPath &path, const QBrush &brush)
void QVGPaintEngine::stroke(const QVectorPath &path, const QPen &pen)
{
Q_D(QVGPaintEngine);
+ if (d->needsEmulation(pen.brush())) {
+ QPaintEngineEx::stroke(path, pen);
+ return;
+ }
VGPath vgpath = d->vectorPathToVGPath(path);
d->stroke(vgpath, pen);
vgDestroyPath(vgpath);
@@ -2360,12 +2406,17 @@ void QVGPaintEngine::penChanged()
{
Q_D(QVGPaintEngine);
d->dirty |= QPaintEngine::DirtyPen;
+
+ d->hasExtendedRadialGradientPen =
+ state()->pen.style() != Qt::NoPen && d->needsEmulation(state()->pen.brush());
}
void QVGPaintEngine::brushChanged()
{
Q_D(QVGPaintEngine);
d->dirty |= QPaintEngine::DirtyBrush;
+
+ d->hasExtendedRadialGradientPen = d->needsEmulation(state()->brush);
}
void QVGPaintEngine::brushOriginChanged()
@@ -2544,6 +2595,11 @@ void QVGPaintEngine::fillRect(const QRectF &rect, const QBrush &brush)
return;
}
+ if (d->needsEmulation(brush)) {
+ QPaintEngineEx::fillRect(rect, brush);
+ return;
+ }
+
#if !defined(QVG_NO_MODIFY_PATH)
VGfloat coords[8];
if (d->simpleTransform) {
@@ -2621,6 +2677,10 @@ void QVGPaintEngine::fillRect(const QRectF &rect, const QColor &color)
void QVGPaintEngine::drawRoundedRect(const QRectF &rect, qreal xrad, qreal yrad, Qt::SizeMode mode)
{
Q_D(QVGPaintEngine);
+ if (d->needsEmulation()) {
+ QPaintEngineEx::drawRoundedRect(rect, xrad, yrad, mode);
+ return;
+ }
if (d->simpleTransform) {
QVGPainterState *s = state();
VGPath vgpath = d->roundedRectPath(rect, xrad, yrad, mode);
@@ -2637,6 +2697,10 @@ void QVGPaintEngine::drawRects(const QRect *rects, int rectCount)
{
#if !defined(QVG_NO_MODIFY_PATH)
Q_D(QVGPaintEngine);
+ if (d->needsEmulation()) {
+ QPaintEngineEx::drawRects(rects, rectCount);
+ return;
+ }
QVGPainterState *s = state();
for (int i = 0; i < rectCount; ++i, ++rects) {
VGfloat coords[8];
@@ -2678,6 +2742,10 @@ void QVGPaintEngine::drawRects(const QRectF *rects, int rectCount)
{
#if !defined(QVG_NO_MODIFY_PATH)
Q_D(QVGPaintEngine);
+ if (d->needsEmulation()) {
+ QPaintEngineEx::drawRects(rects, rectCount);
+ return;
+ }
QVGPainterState *s = state();
for (int i = 0; i < rectCount; ++i, ++rects) {
VGfloat coords[8];
@@ -2716,6 +2784,10 @@ void QVGPaintEngine::drawLines(const QLine *lines, int lineCount)
{
#if !defined(QVG_NO_MODIFY_PATH)
Q_D(QVGPaintEngine);
+ if (d->needsEmulation()) {
+ QPaintEngineEx::drawLines(lines, lineCount);
+ return;
+ }
QVGPainterState *s = state();
for (int i = 0; i < lineCount; ++i, ++lines) {
VGfloat coords[4];
@@ -2744,6 +2816,10 @@ void QVGPaintEngine::drawLines(const QLineF *lines, int lineCount)
{
#if !defined(QVG_NO_MODIFY_PATH)
Q_D(QVGPaintEngine);
+ if (d->needsEmulation()) {
+ QPaintEngineEx::drawLines(lines, lineCount);
+ return;
+ }
QVGPainterState *s = state();
for (int i = 0; i < lineCount; ++i, ++lines) {
VGfloat coords[4];
@@ -2773,6 +2849,10 @@ void QVGPaintEngine::drawEllipse(const QRectF &r)
// Based on the description of vguEllipse() in the OpenVG specification.
// We don't use vguEllipse(), to avoid unnecessary library dependencies.
Q_D(QVGPaintEngine);
+ if (d->needsEmulation()) {
+ QPaintEngineEx::drawEllipse(r);
+ return;
+ }
if (d->simpleTransform) {
QVGPainterState *s = state();
VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD,
@@ -2823,6 +2903,10 @@ void QVGPaintEngine::drawPath(const QPainterPath &path)
// Shortcut past the QPainterPath -> QVectorPath conversion,
// converting the QPainterPath directly into a VGPath.
Q_D(QVGPaintEngine);
+ if (d->needsEmulation()) {
+ QPaintEngineEx::drawPath(path);
+ return;
+ }
QVGPainterState *s = state();
VGPath vgpath = d->painterPathToVGPath(path);
if (path.fillRule() == Qt::OddEvenFill)
@@ -2837,6 +2921,11 @@ void QVGPaintEngine::drawPoints(const QPointF *points, int pointCount)
#if !defined(QVG_NO_MODIFY_PATH)
Q_D(QVGPaintEngine);
+ if (d->needsPenEmulation()) {
+ QPaintEngineEx::drawPoints(points, pointCount);
+ return;
+ }
+
// Set up a new pen if necessary.
QPen pen = state()->pen;
if (pen.style() == Qt::NoPen)
@@ -2871,6 +2960,11 @@ void QVGPaintEngine::drawPoints(const QPoint *points, int pointCount)
#if !defined(QVG_NO_MODIFY_PATH)
Q_D(QVGPaintEngine);
+ if (d->needsEmulation()) {
+ QPaintEngineEx::drawPoints(points, pointCount);
+ return;
+ }
+
// Set up a new pen if necessary.
QPen pen = state()->pen;
if (pen.style() == Qt::NoPen)
@@ -2903,6 +2997,12 @@ void QVGPaintEngine::drawPoints(const QPoint *points, int pointCount)
void QVGPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonDrawMode mode)
{
Q_D(QVGPaintEngine);
+
+ if (d->needsEmulation()) {
+ QPaintEngineEx::drawPolygon(points, pointCount, mode);
+ return;
+ }
+
QVGPainterState *s = state();
VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD,
VG_PATH_DATATYPE_F,
@@ -2950,6 +3050,12 @@ void QVGPaintEngine::drawPolygon(const QPointF *points, int pointCount, PolygonD
void QVGPaintEngine::drawPolygon(const QPoint *points, int pointCount, PolygonDrawMode mode)
{
Q_D(QVGPaintEngine);
+
+ if (d->needsEmulation()) {
+ QPaintEngineEx::drawPolygon(points, pointCount, mode);
+ return;
+ }
+
QVGPainterState *s = state();
VGPath path = vgCreatePath(VG_PATH_FORMAT_STANDARD,
VG_PATH_DATATYPE_F,
@@ -3596,6 +3702,11 @@ void QVGPaintEngine::drawTextItem(const QPointF &p, const QTextItem &textItem)
return;
}
+ if (d->needsPenEmulation()) {
+ QPaintEngineEx::drawTextItem(p, textItem);
+ return;
+ }
+
// Get the glyphs and positions associated with the text item.
QVarLengthArray<QFixedPoint> positions;
QVarLengthArray<glyph_t> glyphs;
diff --git a/src/qt3support/text/q3richtext.cpp b/src/qt3support/text/q3richtext.cpp
index 668a322..6c77405 100644
--- a/src/qt3support/text/q3richtext.cpp
+++ b/src/qt3support/text/q3richtext.cpp
@@ -63,6 +63,7 @@
#include "qstyleoption.h"
#include "q3stylesheet.h"
#include "qtextstream.h"
+#include <private/qtextdocument_p.h>
#include <private/qtextengine_p.h>
#include <stdlib.h>
diff --git a/tests/arthur/common/paintcommands.cpp b/tests/arthur/common/paintcommands.cpp
index 7a018e3..9273142 100644
--- a/tests/arthur/common/paintcommands.cpp
+++ b/tests/arthur/common/paintcommands.cpp
@@ -346,8 +346,12 @@ void PaintCommands::staticInit()
"gradient_setLinear 1.0 1.0 2.0 2.0");
DECL_PAINTCOMMAND("gradient_setRadial", command_gradient_setRadial,
"^gradient_setRadial\\s+([\\w.]*)\\s+([\\w.]*)\\s+([\\w.]*)\\s?([\\w.]*)\\s?([\\w.]*)$",
- "gradient_setRadial <cx> <cy> <rad> <fx> <fy>\n - C is the center\n - rad is the angle in degrees\n - F is the focal point",
+ "gradient_setRadial <cx> <cy> <rad> <fx> <fy>\n - C is the center\n - rad is the radius\n - F is the focal point",
"gradient_setRadial 1.0 1.0 45.0 2.0 2.0");
+ DECL_PAINTCOMMAND("gradient_setRadialExtended", command_gradient_setRadialExtended,
+ "^gradient_setRadialExtended\\s+([\\w.]*)\\s+([\\w.]*)\\s+([\\w.]*)\\s?([\\w.]*)\\s?([\\w.]*)\\s?([\\w.]*)$",
+ "gradient_setRadialExtended <cx> <cy> <rad> <fx> <fy> <frad>\n - C is the center\n - rad is the center radius\n - F is the focal point\n - frad is the focal radius",
+ "gradient_setRadialExtended 1.0 1.0 45.0 2.0 2.0 45.0");
DECL_PAINTCOMMAND("gradient_setLinearPen", command_gradient_setLinearPen,
"^gradient_setLinearPen\\s+([\\w.]*)\\s+([\\w.]*)\\s+([\\w.]*)\\s+([\\w.]*)$",
"gradient_setLinearPen <x1> <y1> <x2> <y2>",
@@ -2400,7 +2404,7 @@ void PaintCommands::command_gradient_setRadial(QRegExp re)
double fy = convertToDouble(caps.at(5));
if (m_verboseMode)
- printf(" -(lance) gradient_setRadial center=(%.2f, %.2f), radius=%.2f focal=(%.2f, %.2f), "
+ printf(" -(lance) gradient_setRadial center=(%.2f, %.2f), radius=%.2f, focal=(%.2f, %.2f), "
"spread=%d\n",
cx, cy, rad, fx, fy, m_gradientSpread);
@@ -2415,6 +2419,32 @@ void PaintCommands::command_gradient_setRadial(QRegExp re)
}
/***************************************************************************************************/
+void PaintCommands::command_gradient_setRadialExtended(QRegExp re)
+{
+ QStringList caps = re.capturedTexts();
+ double cx = convertToDouble(caps.at(1));
+ double cy = convertToDouble(caps.at(2));
+ double rad = convertToDouble(caps.at(3));
+ double fx = convertToDouble(caps.at(4));
+ double fy = convertToDouble(caps.at(5));
+ double frad = convertToDouble(caps.at(6));
+
+ if (m_verboseMode)
+ printf(" -(lance) gradient_setRadialExtended center=(%.2f, %.2f), radius=%.2f, focal=(%.2f, %.2f), "
+ "focal radius=%.2f, spread=%d\n",
+ cx, cy, rad, fx, fy, frad, m_gradientSpread);
+
+ QRadialGradient rg(QPointF(cx, cy), rad, QPointF(fx, fy), frad);
+ rg.setStops(m_gradientStops);
+ rg.setSpread(m_gradientSpread);
+ rg.setCoordinateMode(m_gradientCoordinate);
+ QBrush brush(rg);
+ QTransform brush_matrix = m_painter->brush().transform();
+ brush.setTransform(brush_matrix);
+ m_painter->setBrush(brush);
+}
+
+/***************************************************************************************************/
void PaintCommands::command_gradient_setConical(QRegExp re)
{
QStringList caps = re.capturedTexts();
diff --git a/tests/arthur/common/paintcommands.h b/tests/arthur/common/paintcommands.h
index 2740412..08c0e25 100644
--- a/tests/arthur/common/paintcommands.h
+++ b/tests/arthur/common/paintcommands.h
@@ -179,6 +179,7 @@ private:
void command_gradient_setConical(QRegExp re);
void command_gradient_setLinear(QRegExp re);
void command_gradient_setRadial(QRegExp re);
+ void command_gradient_setRadialExtended(QRegExp re);
void command_gradient_setLinearPen(QRegExp re);
void command_gradient_setSpread(QRegExp re);
void command_gradient_setCoordinateMode(QRegExp re);
diff --git a/tests/arthur/data/qps/radial_gradients_extended.qps b/tests/arthur/data/qps/radial_gradients_extended.qps
new file mode 100644
index 0000000..d80a149
--- /dev/null
+++ b/tests/arthur/data/qps/radial_gradients_extended.qps
@@ -0,0 +1,95 @@
+path_addRect path 400 0 80 80
+path_addEllipse path 440 40 60 60
+
+setRenderHint Antialiasing
+
+setPen black
+
+begin_block gradients
+gradient_clearStops
+gradient_appendStop 0 red
+gradient_appendStop 0.25 orange
+gradient_appendStop 0.5 yellow
+gradient_appendStop 0.8 green
+gradient_appendStop 1 cyan
+
+gradient_setSpread PadSpread
+gradient_setRadialExtended 0 0 20 40 40 10
+drawRect 0 0 100 100
+
+gradient_setSpread ReflectSpread
+gradient_setRadialExtended 120 20 20 140 40 10
+drawEllipse 100 0 100 100
+
+gradient_setSpread RepeatSpread
+gradient_setRadialExtended 240 20 20 260 40 10
+drawRoundRect 200 0 100 100
+
+gradient_clearStops
+gradient_appendStop 0 3f7f7fff
+gradient_appendStop 0.5 dfdfffff
+gradient_appendStop 1 7f00007f
+
+gradient_setSpread PadSpread
+gradient_setRadialExtended 320 20 20 340 40 10
+drawPolygon [300 0 390 0 350 99]
+
+gradient_setSpread ReflectSpread
+gradient_setRadialExtended 420 20 20 440 40 10
+drawPath path
+
+gradient_setSpread RepeatSpread
+gradient_setRadialExtended 520 20 20 540 40 10
+drawPie 500 0 100 100 720 4320
+end_block
+
+translate 0 100
+scale 1 2
+repeat_block gradients
+
+resetMatrix
+translate 0 300
+brushTranslate 30 0
+brushScale 0.9 0.9
+repeat_block gradients
+
+# Some helpful info perhaps?
+resetMatrix
+setPen black
+
+drawText 610 50 "No XForm"
+drawText 610 200 "scale 1x2"
+drawText 610 300 "brush transform"
+drawText 10 450 "Pad"
+drawText 110 450 "Reflect"
+drawText 210 450 "Repeat"
+drawText 310 450 "Pad w/alpha"
+drawText 410 450 "Reflect w/alpha"
+drawText 510 450 "Repeat w/alpha"
+
+# Radius and focal indicators
+setPen 3f000000
+setBrush nobrush
+
+begin_block ellipse_draw
+setClipRect 0 0 100 100
+drawEllipse -30 -30 100 100
+drawEllipse 35 35 11 11
+translate 100 0
+end_block
+
+repeat_block ellipse_draw
+repeat_block ellipse_draw
+repeat_block ellipse_draw
+repeat_block ellipse_draw
+repeat_block ellipse_draw
+
+resetMatrix
+translate 0 100
+scale 1 2
+repeat_block ellipse_draw
+repeat_block ellipse_draw
+repeat_block ellipse_draw
+repeat_block ellipse_draw
+repeat_block ellipse_draw
+repeat_block ellipse_draw
diff --git a/tests/arthur/data/qps/radial_gradients_extended_qps.png b/tests/arthur/data/qps/radial_gradients_extended_qps.png
new file mode 100644
index 0000000..45a3e60
--- /dev/null
+++ b/tests/arthur/data/qps/radial_gradients_extended_qps.png
Binary files differ
diff --git a/tests/auto/gui.pro b/tests/auto/gui.pro
index 186f00c..6230220 100644
--- a/tests/auto/gui.pro
+++ b/tests/auto/gui.pro
@@ -139,6 +139,7 @@ SUBDIRS=\
qpushbutton \
qquaternion \
qradiobutton \
+ qrawfont \
qregexpvalidator \
qregion \
qscrollarea \
diff --git a/tests/auto/qcomplextext/tst_qcomplextext.cpp b/tests/auto/qcomplextext/tst_qcomplextext.cpp
index 3d8e290..04943c5 100644
--- a/tests/auto/qcomplextext/tst_qcomplextext.cpp
+++ b/tests/auto/qcomplextext/tst_qcomplextext.cpp
@@ -71,6 +71,10 @@ private slots:
void bidiReorderString();
void bidiCursor_qtbug2795();
void bidiCursor_PDF();
+ void bidiCursorMovement_data();
+ void bidiCursorMovement();
+ void bidiCursorLogicalMovement_data();
+ void bidiCursorLogicalMovement();
};
tst_QComplexText::tst_QComplexText()
@@ -185,6 +189,89 @@ void tst_QComplexText::bidiCursor_qtbug2795()
QVERIFY(x1 == x2);
}
+void tst_QComplexText::bidiCursorMovement_data()
+{
+ QTest::addColumn<QString>("logical");
+ QTest::addColumn<int>("basicDir");
+
+ const LV *data = logical_visual;
+ while ( data->name ) {
+ //next we fill it with data
+ QTest::newRow( data->name )
+ << QString::fromUtf8( data->logical )
+ << (int) data->basicDir;
+ data++;
+ }
+}
+
+void tst_QComplexText::bidiCursorMovement()
+{
+ QFETCH(QString, logical);
+ QFETCH(int, basicDir);
+
+ QTextLayout layout(logical);
+
+ QTextOption option = layout.textOption();
+ option.setTextDirection(basicDir == QChar::DirL ? Qt::LeftToRight : Qt::RightToLeft);
+ layout.setTextOption(option);
+ bool moved;
+ int oldPos, newPos = 0;
+ qreal x, newX;
+
+ layout.beginLayout();
+ QTextLine line = layout.createLine();
+ layout.endLayout();
+
+ newX = line.cursorToX(0);
+ do {
+ oldPos = newPos;
+ x = newX;
+ newX = line.cursorToX(oldPos);
+ if (basicDir == QChar::DirL) {
+ QVERIFY(newX >= x);
+ newPos = layout.rightCursorPosition(oldPos);
+ } else
+ {
+ QVERIFY(newX <= x);
+ newPos = layout.leftCursorPosition(oldPos);
+ }
+ moved = (oldPos != newPos);
+ } while (moved);
+}
+
+void tst_QComplexText::bidiCursorLogicalMovement_data()
+{
+ bidiCursorMovement_data();
+}
+
+void tst_QComplexText::bidiCursorLogicalMovement()
+{
+ QFETCH(QString, logical);
+ QFETCH(int, basicDir);
+
+ QTextLayout layout(logical);
+
+ QTextOption option = layout.textOption();
+ option.setTextDirection(basicDir == QChar::DirL ? Qt::LeftToRight : Qt::RightToLeft);
+ layout.setTextOption(option);
+ bool moved;
+ int oldPos, newPos = 0;
+
+ do {
+ oldPos = newPos;
+ newPos = layout.nextCursorPosition(oldPos);
+ QVERIFY(newPos >= oldPos);
+ moved = (oldPos != newPos);
+ } while (moved);
+
+ do {
+ oldPos = newPos;
+ newPos = layout.previousCursorPosition(oldPos);
+ QVERIFY(newPos <= oldPos);
+ moved = (oldPos != newPos);
+ } while (moved);
+}
+
void tst_QComplexText::bidiCursor_PDF()
{
QString str = QString::fromUtf8("\342\200\252hello\342\200\254");
diff --git a/tests/auto/qglyphs/tst_qglyphs.cpp b/tests/auto/qglyphs/tst_qglyphs.cpp
index 1c0aa9e..ffa0d00 100644
--- a/tests/auto/qglyphs/tst_qglyphs.cpp
+++ b/tests/auto/qglyphs/tst_qglyphs.cpp
@@ -52,6 +52,7 @@ class tst_QGlyphs: public QObject
{
Q_OBJECT
+#if !defined(QT_NO_RAWFONT)
private slots:
void initTestCase();
void cleanupTestCase();
@@ -75,8 +76,12 @@ private slots:
private:
int m_testFontId;
QFont m_testFont;
+#endif // QT_NO_RAWFONT
+
};
+#if !defined(QT_NO_RAWFONT)
+
Q_DECLARE_METATYPE(QGlyphs);
void tst_QGlyphs::initTestCase()
@@ -116,7 +121,7 @@ static QGlyphs make_dummy_indexes()
positions.append(QPointF(3, 4));
positions.append(QPointF(5, 6));
- glyphs.setFont(font);
+ glyphs.setFont(QRawFont::fromFont(font));
glyphs.setGlyphIndexes(glyphIndexes);
glyphs.setPositions(positions);
@@ -141,7 +146,7 @@ void tst_QGlyphs::copyConstructor()
positions.append(QPointF(3, 4));
positions.append(QPointF(5, 6));
- glyphs.setFont(font);
+ glyphs.setFont(QRawFont::fromFont(font));
glyphs.setGlyphIndexes(glyphIndexes);
glyphs.setPositions(positions);
}
@@ -180,14 +185,16 @@ void tst_QGlyphs::equalsOperator_data()
positions[2] += QPointF(1, 1);
busted.setPositions(positions);
+
QTest::newRow("Different positions") << one << busted << false;
}
{
QGlyphs busted(two);
- QFont font = busted.font();
- font.setPointSize(font.pointSize() * 2);
- busted.setFont(font);
+
+ QFont font;
+ font.setPixelSize(busted.font().pixelSize() * 2);
+ busted.setFont(QRawFont::fromFont(font));
QTest::newRow("Different fonts") << one << busted << false;
}
@@ -288,7 +295,7 @@ void tst_QGlyphs::drawNonExistentGlyphs()
QGlyphs glyphs;
glyphs.setGlyphIndexes(glyphIndexes);
glyphs.setPositions(glyphPositions);
- glyphs.setFont(m_testFont);
+ glyphs.setFont(QRawFont::fromFont(m_testFont));
QPixmap image(1000, 1000);
image.fill(Qt::white);
@@ -568,6 +575,8 @@ void tst_QGlyphs::drawRightToLeft()
}
+#endif // QT_NO_RAWFONT
+
QTEST_MAIN(tst_QGlyphs)
#include "tst_qglyphs.moc"
diff --git a/tests/auto/qlineedit/tst_qlineedit.cpp b/tests/auto/qlineedit/tst_qlineedit.cpp
index 9176174..f45481c 100644
--- a/tests/auto/qlineedit/tst_qlineedit.cpp
+++ b/tests/auto/qlineedit/tst_qlineedit.cpp
@@ -282,6 +282,12 @@ private slots:
void validateAndSet();
#endif
+ void bidiVisualMovement_data();
+ void bidiVisualMovement();
+
+ void bidiLogicalMovement_data();
+ void bidiLogicalMovement();
+
protected slots:
#ifdef QT3_SUPPORT
void lostFocus();
@@ -3760,5 +3766,135 @@ void tst_QLineEdit::QTBUG13520_textNotVisible()
}
+void tst_QLineEdit::bidiVisualMovement_data()
+{
+ QTest::addColumn<QString>("logical");
+ QTest::addColumn<int>("basicDir");
+ QTest::addColumn<IntList>("positionList");
+
+ QTest::newRow("Latin text")
+ << QString::fromUtf8("abc")
+ << (int) QChar::DirL
+ << (IntList() << 0 << 1 << 2 << 3);
+ QTest::newRow("Hebrew text, one item")
+ << QString::fromUtf8("\327\220\327\221\327\222")
+ << (int) QChar::DirR
+ << (QList<int>() << 0 << 1 << 2 << 3);
+ QTest::newRow("Hebrew text after Latin text")
+ << QString::fromUtf8("abc\327\220\327\221\327\222")
+ << (int) QChar::DirL
+ << (QList<int>() << 0 << 1 << 2 << 6 << 5 << 4 << 3);
+ QTest::newRow("Latin text after Hebrew text")
+ << QString::fromUtf8("\327\220\327\221\327\222abc")
+ << (int) QChar::DirR
+ << (QList<int>() << 0 << 1 << 2 << 6 << 5 << 4 << 3);
+ QTest::newRow("LTR, 3 items")
+ << QString::fromUtf8("abc\327\220\327\221\327\222abc")
+ << (int) QChar::DirL
+ << (QList<int>() << 0 << 1 << 2 << 5 << 4 << 3 << 6 << 7 << 8 << 9);
+ QTest::newRow("RTL, 3 items")
+ << QString::fromUtf8("\327\220\327\221\327\222abc\327\220\327\221\327\222")
+ << (int) QChar::DirR
+ << (QList<int>() << 0 << 1 << 2 << 5 << 4 << 3 << 6 << 7 << 8 << 9);
+ QTest::newRow("LTR, 4 items")
+ << QString::fromUtf8("abc\327\220\327\221\327\222abc\327\220\327\221\327\222")
+ << (int) QChar::DirL
+ << (QList<int>() << 0 << 1 << 2 << 5 << 4 << 3 << 6 << 7 << 8 << 12 << 11 << 10 << 9);
+ QTest::newRow("RTL, 4 items")
+ << QString::fromUtf8("\327\220\327\221\327\222abc\327\220\327\221\327\222abc")
+ << (int) QChar::DirR
+ << (QList<int>() << 0 << 1 << 2 << 5 << 4 << 3 << 6 << 7 << 8 << 12 << 11 << 10 << 9);
+}
+
+void tst_QLineEdit::bidiVisualMovement()
+{
+ QFETCH(QString, logical);
+ QFETCH(int, basicDir);
+ QFETCH(IntList, positionList);
+
+ QLineEdit le;
+ le.setText(logical);
+
+ le.setCursorMoveStyle(QTextCursor::Visual);
+ le.setCursorPosition(0);
+
+ bool moved;
+ int i = 0, oldPos, newPos = 0;
+
+ do {
+ oldPos = newPos;
+ QVERIFY(oldPos == positionList[i]);
+ if (basicDir == QChar::DirL) {
+ QTest::keyClick(&le, Qt::Key_Right);
+ } else
+ QTest::keyClick(&le, Qt::Key_Left);
+ newPos = le.cursorPosition();
+ moved = (oldPos != newPos);
+ i++;
+ } while (moved);
+
+ QVERIFY(i == positionList.size());
+
+ do {
+ i--;
+ oldPos = newPos;
+ QVERIFY(oldPos == positionList[i]);
+ if (basicDir == QChar::DirL) {
+ QTest::keyClick(&le, Qt::Key_Left);
+ } else
+ {
+ QTest::keyClick(&le, Qt::Key_Right);
+ }
+ newPos = le.cursorPosition();
+ moved = (oldPos != newPos);
+ } while (moved && i >= 0);
+}
+
+void tst_QLineEdit::bidiLogicalMovement_data()
+{
+ bidiVisualMovement_data();
+}
+
+void tst_QLineEdit::bidiLogicalMovement()
+{
+ QFETCH(QString, logical);
+ QFETCH(int, basicDir);
+
+ QLineEdit le;
+ le.setText(logical);
+
+ le.setCursorMoveStyle(QTextCursor::Logical);
+ le.setCursorPosition(0);
+
+ bool moved;
+ int i = 0, oldPos, newPos = 0;
+
+ do {
+ oldPos = newPos;
+ QVERIFY(oldPos == i);
+ if (basicDir == QChar::DirL) {
+ QTest::keyClick(&le, Qt::Key_Right);
+ } else
+ QTest::keyClick(&le, Qt::Key_Left);
+ newPos = le.cursorPosition();
+ moved = (oldPos != newPos);
+ i++;
+ } while (moved);
+
+ do {
+ i--;
+ oldPos = newPos;
+ QVERIFY(oldPos == i);
+ if (basicDir == QChar::DirL) {
+ QTest::keyClick(&le, Qt::Key_Left);
+ } else
+ {
+ QTest::keyClick(&le, Qt::Key_Right);
+ }
+ newPos = le.cursorPosition();
+ moved = (oldPos != newPos);
+ } while (moved && i >= 0);
+}
+
QTEST_MAIN(tst_QLineEdit)
#include "tst_qlineedit.moc"
diff --git a/tests/auto/qpainter/tst_qpainter.cpp b/tests/auto/qpainter/tst_qpainter.cpp
index c21514b..76bc5d63 100644
--- a/tests/auto/qpainter/tst_qpainter.cpp
+++ b/tests/auto/qpainter/tst_qpainter.cpp
@@ -77,6 +77,7 @@
# define SRCDIR "."
#endif
+Q_DECLARE_METATYPE(QGradientStops)
Q_DECLARE_METATYPE(QLine)
Q_DECLARE_METATYPE(QRect)
Q_DECLARE_METATYPE(QSize)
@@ -189,6 +190,7 @@ private slots:
void fillRect_stretchToDeviceMode();
void monoImages();
+ void linearGradientSymmetry_data();
void linearGradientSymmetry();
void gradientInterpolation();
@@ -3983,8 +3985,42 @@ static QLinearGradient inverseGradient(QLinearGradient g)
return g2;
}
+void tst_QPainter::linearGradientSymmetry_data()
+{
+ QTest::addColumn<QGradientStops>("stops");
+
+ if (sizeof(qreal) != sizeof(float)) {
+ QGradientStops stops;
+ stops << qMakePair(qreal(0.0), QColor(Qt::blue));
+ stops << qMakePair(qreal(0.2), QColor(220, 220, 220, 0));
+ stops << qMakePair(qreal(0.6), QColor(Qt::red));
+ stops << qMakePair(qreal(0.9), QColor(220, 220, 220, 255));
+ stops << qMakePair(qreal(1.0), QColor(Qt::black));
+ QTest::newRow("multiple stops") << stops;
+ }
+
+ {
+ QGradientStops stops;
+ stops << qMakePair(qreal(0.0), QColor(Qt::blue));
+ stops << qMakePair(qreal(1.0), QColor(Qt::black));
+ QTest::newRow("two stops") << stops;
+ }
+
+ if (sizeof(qreal) != sizeof(float)) {
+ QGradientStops stops;
+ stops << qMakePair(qreal(0.3), QColor(Qt::blue));
+ stops << qMakePair(qreal(0.6), QColor(Qt::black));
+ QTest::newRow("two stops 2") << stops;
+ }
+}
+
void tst_QPainter::linearGradientSymmetry()
{
+#ifdef Q_WS_QWS
+ QSKIP("QWS has limited resolution in the gradient color table", SkipAll);
+#else
+ QFETCH(QGradientStops, stops);
+
QImage a(64, 8, QImage::Format_ARGB32_Premultiplied);
QImage b(64, 8, QImage::Format_ARGB32_Premultiplied);
@@ -3992,11 +4028,7 @@ void tst_QPainter::linearGradientSymmetry()
b.fill(0);
QLinearGradient gradient(QRectF(b.rect()).topLeft(), QRectF(b.rect()).topRight());
- gradient.setColorAt(0.0, Qt::blue);
- gradient.setColorAt(0.2, QColor(220, 220, 220, 0));
- gradient.setColorAt(0.6, Qt::red);
- gradient.setColorAt(0.9, QColor(220, 220, 220, 255));
- gradient.setColorAt(1.0, Qt::black);
+ gradient.setStops(stops);
QPainter pa(&a);
pa.fillRect(a.rect(), gradient);
@@ -4008,6 +4040,7 @@ void tst_QPainter::linearGradientSymmetry()
b = b.mirrored(true);
QCOMPARE(a, b);
+#endif
}
void tst_QPainter::gradientInterpolation()
diff --git a/tests/auto/qpixmap/tst_qpixmap.cpp b/tests/auto/qpixmap/tst_qpixmap.cpp
index 4d032e8..4ba51de 100644
--- a/tests/auto/qpixmap/tst_qpixmap.cpp
+++ b/tests/auto/qpixmap/tst_qpixmap.cpp
@@ -1337,7 +1337,7 @@ void tst_QPixmap::toSymbianCFbsBitmap()
void tst_QPixmap::onlyNullPixmapsOutsideGuiThread()
{
-#if !defined(Q_WS_WIN)
+#if !defined(Q_WS_WIN) && !defined(Q_WS_MAC)
class Thread : public QThread
{
public:
@@ -1370,7 +1370,7 @@ void tst_QPixmap::onlyNullPixmapsOutsideGuiThread()
thread.wait();
#endif
-#endif // !defined(Q_WS_WIN)
+#endif // !defined(Q_WS_WIN) && !defined(Q_WS_MAC)
}
void tst_QPixmap::refUnref()
diff --git a/tests/auto/qrawfont/qrawfont.pro b/tests/auto/qrawfont/qrawfont.pro
new file mode 100644
index 0000000..ccdccfb
--- /dev/null
+++ b/tests/auto/qrawfont/qrawfont.pro
@@ -0,0 +1,13 @@
+load(qttest_p4)
+QT = core gui
+
+SOURCES += \
+ tst_qrawfont.cpp
+
+INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/harfbuzz/src
+
+wince*|symbian*: {
+ DEFINES += SRCDIR=\\\"\\\"
+} else {
+ DEFINES += SRCDIR=\\\"$$PWD/\\\"
+}
diff --git a/tests/auto/qrawfont/testfont.ttf b/tests/auto/qrawfont/testfont.ttf
new file mode 100644
index 0000000..d6042d2
--- /dev/null
+++ b/tests/auto/qrawfont/testfont.ttf
Binary files differ
diff --git a/tests/auto/qrawfont/testfont_bold_italic.ttf b/tests/auto/qrawfont/testfont_bold_italic.ttf
new file mode 100644
index 0000000..9f65ac8
--- /dev/null
+++ b/tests/auto/qrawfont/testfont_bold_italic.ttf
Binary files differ
diff --git a/tests/auto/qrawfont/tst_qrawfont.cpp b/tests/auto/qrawfont/tst_qrawfont.cpp
new file mode 100644
index 0000000..3aa4006
--- /dev/null
+++ b/tests/auto/qrawfont/tst_qrawfont.cpp
@@ -0,0 +1,814 @@
+/****************************************************************************
+**
+** 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 test suite 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 <QtTest/QtTest>
+
+#include <qrawfont.h>
+#include <private/qrawfont_p.h>
+
+class tst_QRawFont: public QObject
+{
+ Q_OBJECT
+
+#if !defined(QT_NO_RAWFONT)
+private slots:
+ void invalidRawFont();
+
+ void explicitRawFontNotLoadedInDatabase_data();
+ void explicitRawFontNotLoadedInDatabase();
+
+ void explicitRawFontNotAvailableInSystem_data();
+ void explicitRawFontNotAvailableInSystem();
+
+ void correctFontData_data();
+ void correctFontData();
+
+ void glyphIndices();
+
+ void advances_data();
+ void advances();
+
+ void textLayout();
+
+ void fontTable_data();
+ void fontTable();
+
+ void supportedWritingSystems_data();
+ void supportedWritingSystems();
+
+ void supportsCharacter_data();
+ void supportsCharacter();
+
+ void supportsUcs4Character_data();
+ void supportsUcs4Character();
+
+ void fromFont_data();
+ void fromFont();
+
+ void copyConstructor_data();
+ void copyConstructor();
+
+ void detach_data();
+ void detach();
+
+ void unsupportedWritingSystem_data();
+ void unsupportedWritingSystem();
+#endif // QT_NO_RAWFONT
+};
+
+#if !defined(QT_NO_RAWFONT)
+Q_DECLARE_METATYPE(QFont::HintingPreference)
+Q_DECLARE_METATYPE(QFont::Style)
+Q_DECLARE_METATYPE(QFont::Weight)
+Q_DECLARE_METATYPE(QFontDatabase::WritingSystem)
+
+void tst_QRawFont::invalidRawFont()
+{
+ QRawFont font;
+ QVERIFY(!font.isValid());
+ QCOMPARE(font.pixelSize(), -1);
+ QVERIFY(font.familyName().isEmpty());
+ QCOMPARE(font.style(), QFont::StyleNormal);
+ QCOMPARE(font.weight(), -1);
+ QCOMPARE(font.ascent(), 0.0);
+ QCOMPARE(font.descent(), 0.0);
+ QVERIFY(font.glyphIndexesForString(QLatin1String("Test")).isEmpty());
+}
+
+void tst_QRawFont::explicitRawFontNotLoadedInDatabase_data()
+{
+ QTest::addColumn<QFont::HintingPreference>("hintingPreference");
+
+ QTest::newRow("Default hinting preference") << QFont::PreferDefaultHinting;
+ QTest::newRow("No hinting") << QFont::PreferNoHinting;
+ QTest::newRow("Vertical hinting") << QFont::PreferVerticalHinting;
+ QTest::newRow("Full hinting") << QFont::PreferFullHinting;
+}
+
+void tst_QRawFont::explicitRawFontNotLoadedInDatabase()
+{
+ QFETCH(QFont::HintingPreference, hintingPreference);
+
+ QRawFont font(QLatin1String(SRCDIR "testfont.ttf"), 10, hintingPreference);
+ QVERIFY(font.isValid());
+
+ QVERIFY(!QFontDatabase().families().contains(font.familyName()));
+}
+
+void tst_QRawFont::explicitRawFontNotAvailableInSystem_data()
+{
+ QTest::addColumn<QFont::HintingPreference>("hintingPreference");
+
+ QTest::newRow("Default hinting preference") << QFont::PreferDefaultHinting;
+ QTest::newRow("No hinting") << QFont::PreferNoHinting;
+ QTest::newRow("Vertical hinting") << QFont::PreferVerticalHinting;
+ QTest::newRow("Full hinting") << QFont::PreferFullHinting;
+}
+
+void tst_QRawFont::explicitRawFontNotAvailableInSystem()
+{
+ QFETCH(QFont::HintingPreference, hintingPreference);
+
+ QRawFont rawfont(QLatin1String(SRCDIR "testfont.ttf"), 10, hintingPreference);
+
+ {
+ QFont font(rawfont.familyName(), 10);
+
+ QVERIFY(!font.exactMatch());
+ QVERIFY(font.family() != QFontInfo(font).family());
+ }
+}
+
+void tst_QRawFont::correctFontData_data()
+{
+ QTest::addColumn<QString>("fileName");
+ QTest::addColumn<QString>("expectedFamilyName");
+ QTest::addColumn<QFont::Style>("style");
+ QTest::addColumn<QFont::Weight>("weight");
+ QTest::addColumn<QFont::HintingPreference>("hintingPreference");
+ QTest::addColumn<qreal>("unitsPerEm");
+ QTest::addColumn<int>("pixelSize");
+
+ int hintingPreferences[] = {
+ int(QFont::PreferDefaultHinting),
+ int(QFont::PreferNoHinting),
+ int(QFont::PreferVerticalHinting),
+ int(QFont::PreferFullHinting),
+ -1
+ };
+ int *hintingPreference = hintingPreferences;
+
+ while (*hintingPreference >= 0) {
+ QString fileName = QLatin1String(SRCDIR "testfont.ttf");
+ QString title = fileName
+ + QLatin1String(": hintingPreference=")
+ + QString::number(*hintingPreference);
+
+ QTest::newRow(qPrintable(title))
+ << fileName
+ << QString::fromLatin1("QtBidiTestFont")
+ << QFont::StyleNormal
+ << QFont::Normal
+ << QFont::HintingPreference(*hintingPreference)
+ << 1000.0
+ << 10;
+
+ fileName = QLatin1String(SRCDIR "testfont_bold_italic.ttf");
+ title = fileName
+ + QLatin1String(": hintingPreference=")
+ + QString::number(*hintingPreference);
+
+ QTest::newRow(qPrintable(title))
+ << fileName
+ << QString::fromLatin1("QtBidiTestFont")
+ << QFont::StyleItalic
+ << QFont::Bold
+ << QFont::HintingPreference(*hintingPreference)
+ << 1000.0
+ << 10;
+
+ ++hintingPreference;
+ }
+}
+
+void tst_QRawFont::correctFontData()
+{
+ QFETCH(QString, fileName);
+ QFETCH(QString, expectedFamilyName);
+ QFETCH(QFont::Style, style);
+ QFETCH(QFont::Weight, weight);
+ QFETCH(QFont::HintingPreference, hintingPreference);
+ QFETCH(qreal, unitsPerEm);
+ QFETCH(int, pixelSize);
+
+ QRawFont font(fileName, 10, hintingPreference);
+ QVERIFY(font.isValid());
+
+ QCOMPARE(font.familyName(), expectedFamilyName);
+ QCOMPARE(font.style(), style);
+ QCOMPARE(font.weight(), int(weight));
+ QCOMPARE(font.hintingPreference(), hintingPreference);
+ QCOMPARE(font.unitsPerEm(), unitsPerEm);
+ QCOMPARE(font.pixelSize(), pixelSize);
+}
+
+void tst_QRawFont::glyphIndices()
+{
+ QRawFont font(QLatin1String(SRCDIR "testfont.ttf"), 10);
+ QVERIFY(font.isValid());
+
+ QVector<quint32> glyphIndices = font.glyphIndexesForString(QLatin1String("Foobar"));
+ QVector<quint32> expectedGlyphIndices;
+ expectedGlyphIndices << 44 << 83 << 83 << 70 << 69 << 86;
+
+ QCOMPARE(glyphIndices, expectedGlyphIndices);
+}
+
+void tst_QRawFont::advances_data()
+{
+ QTest::addColumn<QFont::HintingPreference>("hintingPreference");
+
+ QTest::newRow("Default hinting preference") << QFont::PreferDefaultHinting;
+ QTest::newRow("No hinting") << QFont::PreferNoHinting;
+ QTest::newRow("Vertical hinting") << QFont::PreferVerticalHinting;
+ QTest::newRow("Full hinting") << QFont::PreferFullHinting;
+}
+
+void tst_QRawFont::advances()
+{
+ QFETCH(QFont::HintingPreference, hintingPreference);
+
+ QRawFont font(QLatin1String(SRCDIR "testfont.ttf"), 10, hintingPreference);
+ QVERIFY(font.isValid());
+
+ QRawFontPrivate *font_d = QRawFontPrivate::get(font);
+ QVERIFY(font_d->fontEngine != 0);
+
+ QVector<quint32> glyphIndices;
+ glyphIndices << 44 << 83 << 83 << 70 << 69 << 86; // "Foobar"
+
+ bool supportsSubPixelPositions = font_d->fontEngine->supportsSubPixelPositions();
+ QVector<QPointF> advances = font.advancesForGlyphIndexes(glyphIndices);
+ for (int i=0; i<glyphIndices.size(); ++i) {
+ QVERIFY(qFuzzyCompare(qRound(advances.at(i).x()), 8.0));
+ if (supportsSubPixelPositions)
+ QVERIFY(advances.at(i).x() > 8.0);
+
+ QVERIFY(qFuzzyIsNull(advances.at(i).y()));
+ }
+}
+
+void tst_QRawFont::textLayout()
+{
+ QFontDatabase fontDatabase;
+ int id = fontDatabase.addApplicationFont(SRCDIR "testfont.ttf");
+ QVERIFY(id >= 0);
+
+ QString familyName = QString::fromLatin1("QtBidiTestFont");
+ QFont font(familyName);
+ font.setPixelSize(18);
+ QCOMPARE(QFontInfo(font).family(), familyName);
+
+ QTextLayout layout(QLatin1String("Foobar"));
+ layout.setFont(font);
+ layout.beginLayout();
+ layout.createLine();
+ layout.endLayout();
+
+ QList<QGlyphs> glyphss = layout.glyphs();
+ QCOMPARE(glyphss.size(), 1);
+
+ QGlyphs glyphs = glyphss.at(0);
+
+ QRawFont rawFont = glyphs.font();
+ QVERIFY(rawFont.isValid());
+ QCOMPARE(rawFont.familyName(), familyName);
+ QCOMPARE(rawFont.pixelSize(), 18);
+
+ QVector<quint32> expectedGlyphIndices;
+ expectedGlyphIndices << 44 << 83 << 83 << 70 << 69 << 86;
+
+ QCOMPARE(glyphs.glyphIndexes(), expectedGlyphIndices);
+
+ QVERIFY(fontDatabase.removeApplicationFont(id));
+}
+
+void tst_QRawFont::fontTable_data()
+{
+ QTest::addColumn<QByteArray>("tagName");
+ QTest::addColumn<QFont::HintingPreference>("hintingPreference");
+ QTest::addColumn<int>("offset");
+ QTest::addColumn<quint32>("expectedValue");
+
+ QTest::newRow("Head table, magic number, default hinting")
+ << QByteArray("head")
+ << QFont::PreferDefaultHinting
+ << 12
+ << (QSysInfo::ByteOrder == QSysInfo::BigEndian
+ ? 0x5F0F3CF5
+ : 0xF53C0F5F);
+
+ QTest::newRow("Head table, magic number, no hinting")
+ << QByteArray("head")
+ << QFont::PreferNoHinting
+ << 12
+ << (QSysInfo::ByteOrder == QSysInfo::BigEndian
+ ? 0x5F0F3CF5
+ : 0xF53C0F5F);
+
+ QTest::newRow("Head table, magic number, vertical hinting")
+ << QByteArray("head")
+ << QFont::PreferVerticalHinting
+ << 12
+ << (QSysInfo::ByteOrder == QSysInfo::BigEndian
+ ? 0x5F0F3CF5
+ : 0xF53C0F5F);
+
+ QTest::newRow("Head table, magic number, full hinting")
+ << QByteArray("head")
+ << QFont::PreferFullHinting
+ << 12
+ << (QSysInfo::ByteOrder == QSysInfo::BigEndian
+ ? 0x5F0F3CF5
+ : 0xF53C0F5F);
+}
+
+void tst_QRawFont::fontTable()
+{
+ QFETCH(QByteArray, tagName);
+ QFETCH(QFont::HintingPreference, hintingPreference);
+ QFETCH(int, offset);
+ QFETCH(quint32, expectedValue);
+
+ QRawFont font(QString::fromLatin1(SRCDIR "testfont.ttf"), 10, hintingPreference);
+ QVERIFY(font.isValid());
+
+ QByteArray table = font.fontTable(tagName);
+ QVERIFY(!table.isEmpty());
+
+ const quint32 *value = reinterpret_cast<const quint32 *>(table.constData() + offset);
+ QCOMPARE(*value, expectedValue);
+}
+
+typedef QList<QFontDatabase::WritingSystem> WritingSystemList;
+Q_DECLARE_METATYPE(WritingSystemList)
+
+void tst_QRawFont::supportedWritingSystems_data()
+{
+ QTest::addColumn<QString>("fileName");
+ QTest::addColumn<WritingSystemList>("writingSystems");
+ QTest::addColumn<QFont::HintingPreference>("hintingPreference");
+
+ for (int hintingPreference=QFont::PreferDefaultHinting;
+ hintingPreference<=QFont::PreferFullHinting;
+ ++hintingPreference) {
+
+ QTest::newRow(qPrintable(QString::fromLatin1("testfont.ttf, hintingPreference=%1")
+ .arg(hintingPreference)))
+ << QString::fromLatin1(SRCDIR "testfont.ttf")
+ << (QList<QFontDatabase::WritingSystem>()
+ << QFontDatabase::Latin
+ << QFontDatabase::Hebrew
+ << QFontDatabase::Vietnamese) // Vietnamese uses same unicode bits as Latin
+ << QFont::HintingPreference(hintingPreference);
+
+ QTest::newRow(qPrintable(QString::fromLatin1("testfont_bold_italic.ttf, hintingPreference=%1")
+ .arg(hintingPreference)))
+ << QString::fromLatin1(SRCDIR "testfont_bold_italic.ttf")
+ << (QList<QFontDatabase::WritingSystem>()
+ << QFontDatabase::Latin
+ << QFontDatabase::Hebrew
+ << QFontDatabase::Devanagari
+ << QFontDatabase::Vietnamese) // Vietnamese uses same unicode bits as Latin
+ << QFont::HintingPreference(hintingPreference);
+ }
+}
+
+void tst_QRawFont::supportedWritingSystems()
+{
+ QFETCH(QString, fileName);
+ QFETCH(WritingSystemList, writingSystems);
+ QFETCH(QFont::HintingPreference, hintingPreference);
+
+ QRawFont font(fileName, 10, hintingPreference);
+ QVERIFY(font.isValid());
+
+ WritingSystemList actualWritingSystems = font.supportedWritingSystems();
+ QCOMPARE(actualWritingSystems.size(), writingSystems.size());
+
+ foreach (QFontDatabase::WritingSystem writingSystem, writingSystems)
+ QVERIFY(actualWritingSystems.contains(writingSystem));
+}
+
+void tst_QRawFont::supportsCharacter_data()
+{
+ QTest::addColumn<QString>("fileName");
+ QTest::addColumn<QFont::HintingPreference>("hintingPreference");
+ QTest::addColumn<QChar>("character");
+ QTest::addColumn<bool>("shouldBeSupported");
+
+ const char *fileNames[2] = {
+ SRCDIR "testfont.ttf",
+ SRCDIR "testfont_bold_italic.ttf"
+ };
+
+ for (int hintingPreference=QFont::PreferDefaultHinting;
+ hintingPreference<=QFont::PreferFullHinting;
+ ++hintingPreference) {
+
+ for (int i=0; i<2; ++i) {
+ QString fileName = QLatin1String(fileNames[i]);
+
+ // Latin text
+ for (char ch='!'; ch<='~'; ++ch) {
+ QString title = QString::fromLatin1("%1, character=0x%2, hintingPreference=%3")
+ .arg(fileName).arg(QString::number(ch, 16)).arg(hintingPreference);
+
+ QTest::newRow(qPrintable(title))
+ << fileName
+ << QFont::HintingPreference(hintingPreference)
+ << QChar::fromLatin1(ch)
+ << true;
+ }
+
+ // Hebrew text
+ for (quint16 ch=0x05D0; ch<=0x05EA; ++ch) {
+ QString title = QString::fromLatin1("%1, character=0x%2, hintingPreference=%3")
+ .arg(fileName).arg(QString::number(ch, 16)).arg(hintingPreference);
+
+ QTest::newRow(qPrintable(title))
+ << fileName
+ << QFont::HintingPreference(hintingPreference)
+ << QChar(ch)
+ << true;
+ }
+
+ QTest::newRow(qPrintable(QString::fromLatin1("Missing character, %1, hintingPreference=%2")
+ .arg(fileName).arg(hintingPreference)))
+ << fileName
+ << QFont::HintingPreference(hintingPreference)
+ << QChar(0xD8)
+ << false;
+ }
+ }
+}
+
+void tst_QRawFont::supportsCharacter()
+{
+ QFETCH(QString, fileName);
+ QFETCH(QFont::HintingPreference, hintingPreference);
+ QFETCH(QChar, character);
+ QFETCH(bool, shouldBeSupported);
+
+ QRawFont font(fileName, 10, hintingPreference);
+ QVERIFY(font.isValid());
+
+ QCOMPARE(font.supportsCharacter(character), shouldBeSupported);
+}
+
+void tst_QRawFont::supportsUcs4Character_data()
+{
+ QTest::addColumn<QString>("fileName");
+ QTest::addColumn<QFont::HintingPreference>("hintingPreference");
+ QTest::addColumn<quint32>("ucs4");
+ QTest::addColumn<bool>("shouldBeSupported");
+
+ // Gothic text
+ for (int hintingPreference=QFont::PreferDefaultHinting;
+ hintingPreference<=QFont::PreferFullHinting;
+ ++hintingPreference) {
+ for (quint32 ch=0x10330; ch<=0x1034A; ++ch) {
+ {
+ QString fileName = QString::fromLatin1(SRCDIR "testfont.ttf");
+ QString title = QString::fromLatin1("%1, character=0x%2, hintingPreference=%3")
+ .arg(fileName).arg(QString::number(ch, 16)).arg(hintingPreference);
+
+ QTest::newRow(qPrintable(title))
+ << fileName
+ << QFont::HintingPreference(hintingPreference)
+ << ch
+ << true;
+ }
+
+ {
+ QString fileName = QString::fromLatin1(SRCDIR "testfont_bold_italic.ttf");
+ QString title = QString::fromLatin1("%1, character=0x%2, hintingPreference=%3")
+ .arg(fileName).arg(QString::number(ch, 16)).arg(hintingPreference);
+
+ QTest::newRow(qPrintable(title))
+ << fileName
+ << QFont::HintingPreference(hintingPreference)
+ << ch
+ << false;
+ }
+ }
+ }
+}
+
+void tst_QRawFont::supportsUcs4Character()
+{
+ QFETCH(QString, fileName);
+ QFETCH(QFont::HintingPreference, hintingPreference);
+ QFETCH(quint32, ucs4);
+ QFETCH(bool, shouldBeSupported);
+
+ QRawFont font(fileName, 10, hintingPreference);
+ QVERIFY(font.isValid());
+
+ QCOMPARE(font.supportsCharacter(ucs4), shouldBeSupported);
+}
+
+void tst_QRawFont::fromFont_data()
+{
+ QTest::addColumn<QString>("fileName");
+ QTest::addColumn<QFont::HintingPreference>("hintingPreference");
+ QTest::addColumn<QString>("familyName");
+ QTest::addColumn<QFontDatabase::WritingSystem>("writingSystem");
+
+ for (int i=QFont::PreferDefaultHinting; i<=QFont::PreferFullHinting; ++i) {
+ QString titleBase = QString::fromLatin1("%2, hintingPreference=%1, writingSystem=%3")
+ .arg(i);
+ {
+ QString fileName = QString::fromLatin1(SRCDIR "testfont.ttf");
+ QFontDatabase::WritingSystem writingSystem = QFontDatabase::Any;
+
+ QString title = titleBase.arg(fileName).arg(writingSystem);
+ QTest::newRow(qPrintable(title))
+ << fileName
+ << QFont::HintingPreference(i)
+ << "QtBidiTestFont"
+ << writingSystem;
+ }
+
+ {
+ QString fileName = QString::fromLatin1(SRCDIR "testfont.ttf");
+ QFontDatabase::WritingSystem writingSystem = QFontDatabase::Hebrew;
+
+ QString title = titleBase.arg(fileName).arg(writingSystem);
+ QTest::newRow(qPrintable(title))
+ << fileName
+ << QFont::HintingPreference(i)
+ << "QtBidiTestFont"
+ << writingSystem;
+ }
+
+ {
+ QString fileName = QString::fromLatin1(SRCDIR "testfont.ttf");
+ QFontDatabase::WritingSystem writingSystem = QFontDatabase::Latin;
+
+ QString title = titleBase.arg(fileName).arg(writingSystem);
+ QTest::newRow(qPrintable(title))
+ << fileName
+ << QFont::HintingPreference(i)
+ << "QtBidiTestFont"
+ << writingSystem;
+ }
+ }
+}
+
+void tst_QRawFont::fromFont()
+{
+ QFETCH(QString, fileName);
+ QFETCH(QFont::HintingPreference, hintingPreference);
+ QFETCH(QString, familyName);
+ QFETCH(QFontDatabase::WritingSystem, writingSystem);
+
+ QFontDatabase fontDatabase;
+ int id = fontDatabase.addApplicationFont(fileName);
+ QVERIFY(id >= 0);
+
+ QFont font(familyName);
+ font.setHintingPreference(hintingPreference);
+ font.setPixelSize(26);
+
+ QRawFont rawFont = QRawFont::fromFont(font, writingSystem);
+ QVERIFY(rawFont.isValid());
+ QCOMPARE(rawFont.familyName(), familyName);
+ QCOMPARE(rawFont.pixelSize(), 26);
+
+ QVERIFY(fontDatabase.removeApplicationFont(id));
+}
+
+void tst_QRawFont::copyConstructor_data()
+{
+ QTest::addColumn<QFont::HintingPreference>("hintingPreference");
+
+ QTest::newRow("Default hinting preference") << QFont::PreferDefaultHinting;
+ QTest::newRow("No hinting preference") << QFont::PreferNoHinting;
+ QTest::newRow("Vertical hinting preference") << QFont::PreferVerticalHinting;
+ QTest::newRow("Full hinting preference") << QFont::PreferFullHinting;
+}
+
+void tst_QRawFont::copyConstructor()
+{
+ QFETCH(QFont::HintingPreference, hintingPreference);
+
+ {
+ QString rawFontFamilyName;
+ int rawFontPixelSize;
+ qreal rawFontAscent;
+ qreal rawFontDescent;
+ int rawFontTableSize;
+
+ QRawFont outerRawFont;
+ {
+ QRawFont rawFont(QString::fromLatin1(SRCDIR "testfont.ttf"), 11, hintingPreference);
+ QVERIFY(rawFont.isValid());
+
+ rawFontFamilyName = rawFont.familyName();
+ rawFontPixelSize = rawFont.pixelSize();
+ rawFontAscent = rawFont.ascent();
+ rawFontDescent = rawFont.descent();
+ rawFontTableSize = rawFont.fontTable("glyf").size();
+ QVERIFY(rawFontTableSize > 0);
+
+ {
+ QRawFont otherRawFont(rawFont);
+ QVERIFY(otherRawFont.isValid());
+ QCOMPARE(otherRawFont.pixelSize(), rawFontPixelSize);
+ QCOMPARE(otherRawFont.familyName(), rawFontFamilyName);
+ QCOMPARE(otherRawFont.hintingPreference(), hintingPreference);
+ QCOMPARE(otherRawFont.ascent(), rawFontAscent);
+ QCOMPARE(otherRawFont.descent(), rawFontDescent);
+ QCOMPARE(otherRawFont.fontTable("glyf").size(), rawFontTableSize);
+ }
+
+ {
+ QRawFont otherRawFont = rawFont;
+ QVERIFY(otherRawFont.isValid());
+ QCOMPARE(otherRawFont.pixelSize(), rawFontPixelSize);
+ QCOMPARE(otherRawFont.familyName(), rawFontFamilyName);
+ QCOMPARE(otherRawFont.hintingPreference(), hintingPreference);
+ QCOMPARE(otherRawFont.ascent(), rawFontAscent);
+ QCOMPARE(otherRawFont.descent(), rawFontDescent);
+ QCOMPARE(otherRawFont.fontTable("glyf").size(), rawFontTableSize);
+ }
+
+ outerRawFont = rawFont;
+ }
+
+ QVERIFY(outerRawFont.isValid());
+ QCOMPARE(outerRawFont.pixelSize(), rawFontPixelSize);
+ QCOMPARE(outerRawFont.familyName(), rawFontFamilyName);
+ QCOMPARE(outerRawFont.hintingPreference(), hintingPreference);
+ QCOMPARE(outerRawFont.ascent(), rawFontAscent);
+ QCOMPARE(outerRawFont.descent(), rawFontDescent);
+ QCOMPARE(outerRawFont.fontTable("glyf").size(), rawFontTableSize);
+ }
+}
+
+void tst_QRawFont::detach_data()
+{
+ QTest::addColumn<QFont::HintingPreference>("hintingPreference");
+
+ QTest::newRow("Default hinting preference") << QFont::PreferDefaultHinting;
+ QTest::newRow("No hinting preference") << QFont::PreferNoHinting;
+ QTest::newRow("Vertical hinting preference") << QFont::PreferVerticalHinting;
+ QTest::newRow("Full hinting preference") << QFont::PreferFullHinting;
+}
+
+void tst_QRawFont::detach()
+{
+ QFETCH(QFont::HintingPreference, hintingPreference);
+
+ {
+ QString rawFontFamilyName;
+ int rawFontPixelSize;
+ qreal rawFontAscent;
+ qreal rawFontDescent;
+ int rawFontTableSize;
+
+ QRawFont outerRawFont;
+ {
+ QRawFont rawFont(QString::fromLatin1(SRCDIR "testfont.ttf"), 11, hintingPreference);
+ QVERIFY(rawFont.isValid());
+
+ rawFontFamilyName = rawFont.familyName();
+ rawFontPixelSize = rawFont.pixelSize();
+ rawFontAscent = rawFont.ascent();
+ rawFontDescent = rawFont.descent();
+ rawFontTableSize = rawFont.fontTable("glyf").size();
+ QVERIFY(rawFontTableSize > 0);
+
+ {
+ QRawFont otherRawFont(rawFont);
+
+ otherRawFont.loadFromFile(QLatin1String(SRCDIR "testfont.ttf"),
+ rawFontPixelSize, hintingPreference);
+
+ QVERIFY(otherRawFont.isValid());
+ QCOMPARE(otherRawFont.pixelSize(), rawFontPixelSize);
+ QCOMPARE(otherRawFont.familyName(), rawFontFamilyName);
+ QCOMPARE(otherRawFont.hintingPreference(), hintingPreference);
+ QCOMPARE(otherRawFont.ascent(), rawFontAscent);
+ QCOMPARE(otherRawFont.descent(), rawFontDescent);
+ QCOMPARE(otherRawFont.fontTable("glyf").size(), rawFontTableSize);
+ }
+
+ {
+ QRawFont otherRawFont = rawFont;
+
+ otherRawFont.loadFromFile(QLatin1String(SRCDIR "testfont.ttf"),
+ rawFontPixelSize, hintingPreference);
+
+ QVERIFY(otherRawFont.isValid());
+ QCOMPARE(otherRawFont.pixelSize(), rawFontPixelSize);
+ QCOMPARE(otherRawFont.familyName(), rawFontFamilyName);
+ QCOMPARE(otherRawFont.hintingPreference(), hintingPreference);
+ QCOMPARE(otherRawFont.ascent(), rawFontAscent);
+ QCOMPARE(otherRawFont.descent(), rawFontDescent);
+ QCOMPARE(otherRawFont.fontTable("glyf").size(), rawFontTableSize);
+ }
+
+ outerRawFont = rawFont;
+
+ rawFont.loadFromFile(QLatin1String(SRCDIR "testfont.ttf"), rawFontPixelSize,
+ hintingPreference);
+ }
+
+ QVERIFY(outerRawFont.isValid());
+ QCOMPARE(outerRawFont.pixelSize(), rawFontPixelSize);
+ QCOMPARE(outerRawFont.familyName(), rawFontFamilyName);
+ QCOMPARE(outerRawFont.hintingPreference(), hintingPreference);
+ QCOMPARE(outerRawFont.ascent(), rawFontAscent);
+ QCOMPARE(outerRawFont.descent(), rawFontDescent);
+ QCOMPARE(outerRawFont.fontTable("glyf").size(), rawFontTableSize);
+ }
+}
+
+void tst_QRawFont::unsupportedWritingSystem_data()
+{
+ QTest::addColumn<QFont::HintingPreference>("hintingPreference");
+
+ QTest::newRow("Default hinting preference") << QFont::PreferDefaultHinting;
+ QTest::newRow("No hinting preference") << QFont::PreferNoHinting;
+ QTest::newRow("Vertical hinting preference") << QFont::PreferVerticalHinting;
+ QTest::newRow("Full hinting preference") << QFont::PreferFullHinting;
+}
+
+void tst_QRawFont::unsupportedWritingSystem()
+{
+ QFETCH(QFont::HintingPreference, hintingPreference);
+
+ QFontDatabase fontDatabase;
+ int id = fontDatabase.addApplicationFont(QLatin1String(SRCDIR "testfont.ttf"));
+
+ QFont font("QtBidiTestFont");
+ font.setHintingPreference(hintingPreference);
+ font.setPixelSize(12);
+
+ QRawFont rawFont = QRawFont::fromFont(font, QFontDatabase::Any);
+ QCOMPARE(rawFont.familyName(), QString::fromLatin1("QtBidiTestFont"));
+ QCOMPARE(rawFont.pixelSize(), 12);
+
+ rawFont = QRawFont::fromFont(font, QFontDatabase::Hebrew);
+ QCOMPARE(rawFont.familyName(), QString::fromLatin1("QtBidiTestFont"));
+ QCOMPARE(rawFont.pixelSize(), 12);
+
+ QString arabicText = QFontDatabase::writingSystemSample(QFontDatabase::Arabic);
+
+ QTextLayout layout;
+ layout.setFont(font);
+ layout.setText(arabicText);
+ layout.beginLayout();
+ layout.createLine();
+ layout.endLayout();
+
+ QList<QGlyphs> glyphss = layout.glyphs();
+ QCOMPARE(glyphss.size(), 1);
+
+ QGlyphs glyphs = glyphss.at(0);
+ QRawFont layoutFont = glyphs.font();
+ QVERIFY(layoutFont.familyName() != QString::fromLatin1("QtBidiTestFont"));
+ QCOMPARE(layoutFont.pixelSize(), 12);
+
+ rawFont = QRawFont::fromFont(font, QFontDatabase::Arabic);
+ QCOMPARE(rawFont.familyName(), layoutFont.familyName());
+ QCOMPARE(rawFont.pixelSize(), 12);
+
+ fontDatabase.removeApplicationFont(id);
+}
+
+#endif // QT_NO_RAWFONT
+
+QTEST_MAIN(tst_QRawFont)
+#include "tst_qrawfont.moc"
+
diff --git a/tests/auto/qtextedit/tst_qtextedit.cpp b/tests/auto/qtextedit/tst_qtextedit.cpp
index 9ca17b9..5a64593 100644
--- a/tests/auto/qtextedit/tst_qtextedit.cpp
+++ b/tests/auto/qtextedit/tst_qtextedit.cpp
@@ -42,7 +42,6 @@
#include <QtTest/QtTest>
-
#include <qtextedit.h>
#include <qtextcursor.h>
#include <qtextlist.h>
@@ -69,6 +68,7 @@ typedef QList<keyPairType> pairListType;
Q_DECLARE_METATYPE(pairListType);
Q_DECLARE_METATYPE(keyPairType);
Q_DECLARE_METATYPE(QList<bool>);
+Q_DECLARE_METATYPE(QList<int>);
#ifdef Q_WS_MAC
#include <Carbon/Carbon.h>
@@ -205,6 +205,11 @@ private slots:
#ifndef QT_NO_CONTEXTMENU
void taskQTBUG_7902_contextMenuCrash();
#endif
+ void bidiVisualMovement_data();
+ void bidiVisualMovement();
+
+ void bidiLogicalMovement_data();
+ void bidiLogicalMovement();
private:
void createSelection();
@@ -2235,5 +2240,147 @@ void tst_QTextEdit::taskQTBUG_7902_contextMenuCrash()
}
#endif
+void tst_QTextEdit::bidiVisualMovement_data()
+{
+ QTest::addColumn<QString>("logical");
+ QTest::addColumn<int>("basicDir");
+ QTest::addColumn<QList<int> >("positionList");
+
+ QTest::newRow("Latin text")
+ << QString::fromUtf8("abc")
+ << (int) QChar::DirL
+ << (QList<int>() << 0 << 1 << 2 << 3);
+ QTest::newRow("Hebrew text, one item")
+ << QString::fromUtf8("\327\220\327\221\327\222")
+ << (int) QChar::DirR
+ << (QList<int>() << 0 << 1 << 2 << 3);
+ QTest::newRow("Hebrew text after Latin text")
+ << QString::fromUtf8("abc\327\220\327\221\327\222")
+ << (int) QChar::DirL
+ << (QList<int>() << 0 << 1 << 2 << 6 << 5 << 4 << 3);
+ QTest::newRow("Latin text after Hebrew text")
+ << QString::fromUtf8("\327\220\327\221\327\222abc")
+ << (int) QChar::DirR
+ << (QList<int>() << 0 << 1 << 2 << 6 << 5 << 4 << 3);
+ QTest::newRow("LTR, 3 items")
+ << QString::fromUtf8("abc\327\220\327\221\327\222abc")
+ << (int) QChar::DirL
+ << (QList<int>() << 0 << 1 << 2 << 5 << 4 << 3 << 6 << 7 << 8 << 9);
+ QTest::newRow("RTL, 3 items")
+ << QString::fromUtf8("\327\220\327\221\327\222abc\327\220\327\221\327\222")
+ << (int) QChar::DirR
+ << (QList<int>() << 0 << 1 << 2 << 5 << 4 << 3 << 6 << 7 << 8 << 9);
+ QTest::newRow("LTR, 4 items")
+ << QString::fromUtf8("abc\327\220\327\221\327\222abc\327\220\327\221\327\222")
+ << (int) QChar::DirL
+ << (QList<int>() << 0 << 1 << 2 << 5 << 4 << 3 << 6 << 7 << 8 << 12 << 11 << 10 << 9);
+ QTest::newRow("RTL, 4 items")
+ << QString::fromUtf8("\327\220\327\221\327\222abc\327\220\327\221\327\222abc")
+ << (int) QChar::DirR
+ << (QList<int>() << 0 << 1 << 2 << 5 << 4 << 3 << 6 << 7 << 8 << 12 << 11 << 10 << 9);
+}
+
+void tst_QTextEdit::bidiVisualMovement()
+{
+ QFETCH(QString, logical);
+ QFETCH(int, basicDir);
+ QFETCH(QList<int>, positionList);
+
+ ed->setText(logical);
+
+ QTextOption option = ed->document()->defaultTextOption();
+ option.setTextDirection(basicDir == QChar::DirL ? Qt::LeftToRight : Qt::RightToLeft);
+ ed->document()->setDefaultTextOption(option);
+
+ ed->document()->setDefaultCursorMoveStyle(QTextCursor::Visual);
+ ed->moveCursor(QTextCursor::Start);
+ ed->show();
+
+ bool moved;
+ int i = 0, oldPos, newPos = 0;
+
+ do {
+ oldPos = newPos;
+ QVERIFY(oldPos == positionList[i]);
+ if (basicDir == QChar::DirL) {
+ ed->moveCursor(QTextCursor::Right);
+ } else
+ {
+ ed->moveCursor(QTextCursor::Left);
+ }
+ newPos = ed->textCursor().position();
+ moved = (oldPos != newPos);
+ i++;
+ } while (moved);
+
+ QVERIFY(i == positionList.size());
+
+ do {
+ i--;
+ oldPos = newPos;
+ QVERIFY(oldPos == positionList[i]);
+ if (basicDir == QChar::DirL) {
+ ed->moveCursor(QTextCursor::Left);
+ } else
+ {
+ ed->moveCursor(QTextCursor::Right);
+ }
+ newPos = ed->textCursor().position();
+ moved = (oldPos != newPos);
+ } while (moved && i >= 0);
+}
+
+void tst_QTextEdit::bidiLogicalMovement_data()
+{
+ bidiVisualMovement_data();
+}
+
+void tst_QTextEdit::bidiLogicalMovement()
+{
+ QFETCH(QString, logical);
+ QFETCH(int, basicDir);
+
+ ed->setText(logical);
+
+ QTextOption option = ed->document()->defaultTextOption();
+ option.setTextDirection(basicDir == QChar::DirL ? Qt::LeftToRight : Qt::RightToLeft);
+ ed->document()->setDefaultTextOption(option);
+
+ ed->document()->setDefaultCursorMoveStyle(QTextCursor::Logical);
+ ed->moveCursor(QTextCursor::Start);
+ ed->show();
+
+ bool moved;
+ int i = 0, oldPos, newPos = 0;
+
+ do {
+ oldPos = newPos;
+ QVERIFY(oldPos == i);
+ if (basicDir == QChar::DirL) {
+ ed->moveCursor(QTextCursor::Right);
+ } else
+ {
+ ed->moveCursor(QTextCursor::Left);
+ }
+ newPos = ed->textCursor().position();
+ moved = (oldPos != newPos);
+ i++;
+ } while (moved);
+
+ do {
+ i--;
+ oldPos = newPos;
+ QVERIFY(oldPos == i);
+ if (basicDir == QChar::DirL) {
+ ed->moveCursor(QTextCursor::Left);
+ } else
+ {
+ ed->moveCursor(QTextCursor::Right);
+ }
+ newPos = ed->textCursor().position();
+ moved = (oldPos != newPos);
+ } while (moved && i >= 0);
+}
+
QTEST_MAIN(tst_QTextEdit)
#include "tst_qtextedit.moc"
diff --git a/tests/auto/qwizard/tst_qwizard.cpp b/tests/auto/qwizard/tst_qwizard.cpp
index a813727..5667d40 100644
--- a/tests/auto/qwizard/tst_qwizard.cpp
+++ b/tests/auto/qwizard/tst_qwizard.cpp
@@ -1770,8 +1770,11 @@ public:
~TestWizard()
{
- foreach (int id, pageIds)
- delete page(id);
+ foreach (int id, pageIds) {
+ QWizardPage *page_to_delete = page(id);
+ removePage(id);
+ delete page_to_delete;
+ }
}
void applyOperations(const QList<Operation *> &operations)
@@ -2548,8 +2551,8 @@ void tst_QWizard::task177022_setFixedSize()
QWizard wiz;
QWizardPage page1;
QWizardPage page2;
- wiz.addPage(&page1);
- wiz.addPage(&page2);
+ int page1_id = wiz.addPage(&page1);
+ int page2_id = wiz.addPage(&page2);
wiz.setFixedSize(width, height);
if (wiz.wizardStyle() == QWizard::AeroStyle)
QEXPECT_FAIL("", "this probably relates to non-client area hack for AeroStyle titlebar "
@@ -2576,6 +2579,8 @@ void tst_QWizard::task177022_setFixedSize()
QCOMPARE(wiz.maximumWidth(), width);
QCOMPARE(wiz.maximumHeight(), height);
+ wiz.removePage(page1_id);
+ wiz.removePage(page2_id);
}
void tst_QWizard::task248107_backButton()