3333#include < QDebug>
3434#include < QDir>
3535#include < QFileInfo>
36+ #include < QGlyphRun>
37+ #include < QGraphicsBlurEffect>
3638#include < QGraphicsScene>
3739#include < QGraphicsSvgItem>
3840#include < QGraphicsTextItem>
3941#include < QImage>
4042#include < QMutex>
4143#include < QPainter>
44+ #include < QRawFont>
4245#include < QString>
4346#include < QStyleOptionGraphicsItem>
4447#include < QSvgRenderer>
4548#include < QTextBlockFormat>
4649#include < QTextCharFormat>
4750#include < QTextCursor>
4851#include < QTextDocument>
52+ #include < QTextLayout>
4953#include < QTextOption>
5054
5155#include < framework/mlt_log.h>
@@ -145,6 +149,60 @@ void blur(QImage &image, int radius)
145149 }
146150}
147151
152+ void appendShapedText (QPainterPath &path, const QPointF &pos, const QFont &font, const QString &text)
153+ {
154+ if (text.isEmpty ()) {
155+ return ;
156+ }
157+ QFont shapedFont (font);
158+ shapedFont.setHintingPreference (QFont::PreferFullHinting);
159+
160+ QTextLayout layout (text, shapedFont);
161+ QTextOption opt = layout.textOption ();
162+ opt.setTextDirection (Qt::LayoutDirectionAuto);
163+ layout.setTextOption (opt);
164+ layout.beginLayout ();
165+ while (true ) {
166+ QTextLine textLine = layout.createLine ();
167+ if (!textLine.isValid ()) {
168+ break ;
169+ }
170+ }
171+ layout.endLayout ();
172+
173+ for (int i = 0 ; i < layout.lineCount (); ++i) {
174+ QTextLine textLine = layout.lineAt (i);
175+ const auto glyphRuns = textLine.glyphRuns ();
176+ for (const QGlyphRun &run : glyphRuns) {
177+ const auto glyphIndexes = run.glyphIndexes ();
178+ const auto positions = run.positions ();
179+ const QRawFont rawFont = run.rawFont ();
180+ for (int g = 0 ; g < glyphIndexes.size (); ++g) {
181+ QPainterPath glyphPath = rawFont.pathForGlyph (glyphIndexes[g]);
182+ QPointF glyphPos = pos + positions[g] - QPointF (0 , textLine.ascent ());
183+ glyphPath.translate (glyphPos);
184+ path.addPath (glyphPath);
185+ }
186+ }
187+ }
188+
189+ // Same decoration geometry as QPainterPath::addText().
190+ if (font.underline () || font.overline () || font.strikeOut ()) {
191+ const QFontMetricsF metrics (font);
192+ const qreal lineWidth = metrics.lineWidth ();
193+ const qreal textWidth = layout.maximumWidth ();
194+ if (font.underline ()) {
195+ path.addRect (QRectF (pos.x (), pos.y () + metrics.underlinePos (), textWidth, lineWidth));
196+ }
197+ if (font.overline ()) {
198+ path.addRect (QRectF (pos.x (), pos.y () - metrics.overlinePos (), textWidth, lineWidth));
199+ }
200+ if (font.strikeOut ()) {
201+ path.addRect (QRectF (pos.x (), pos.y () - metrics.strikeOutPos (), textWidth, lineWidth));
202+ }
203+ }
204+ }
205+
148206class PlainTextItem : public QGraphicsItem
149207{
150208public:
@@ -167,6 +225,7 @@ class PlainTextItem : public QGraphicsItem
167225 m_pen.setWidthF (outline);
168226 m_pen.setJoinStyle (Qt::RoundJoin);
169227 m_font = font;
228+ m_font.setHintingPreference (QFont::PreferFullHinting);
170229 m_lineSpacing = lineSpacing + m_metrics.lineSpacing ();
171230 m_align = align;
172231 m_width = width;
@@ -176,11 +235,12 @@ class PlainTextItem : public QGraphicsItem
176235
177236 void updateText (const QString text)
178237 {
179- m_path.clear ();
180- // Calculate line width
181- const QStringList lines = text.split (' \n ' );
238+ const QStringList lines = text.split (QLatin1Char (' \n ' ));
182239 double linePos = m_metrics.ascent ();
183- foreach (const QString &line, lines) {
240+ m_path.clear ();
241+ m_path.setFillRule (Qt::WindingFill);
242+
243+ for (const QString &line : lines) {
184244 QPainterPath linePath;
185245 const QStringList tabLines = line.split (QLatin1Char (' \t ' ));
186246 if (m_tabWidth > 0 && tabLines.count () > 1 ) {
@@ -189,18 +249,17 @@ class PlainTextItem : public QGraphicsItem
189249 for (const QString &tline : tabLines) {
190250 QPainterPath tabPath;
191251 if (!tline.isEmpty ()) {
192- tabPath. addText (pos, linePos, m_font, tline);
252+ appendShapedText ( tabPath, QPointF (pos, linePos) , m_font, tline);
193253 linePath.addPath (tabPath);
194254 currentPos = pos + tabPath.boundingRect ().width ();
195255 } else {
196- // Several chained tabs
197256 currentPos = pos + m_tabWidth / 2 ;
198257 }
199258 int tabsCount = ceil (currentPos / m_tabWidth);
200259 pos = tabsCount * m_tabWidth;
201260 }
202261 } else {
203- linePath. addText (0 , linePos, m_font, line);
262+ appendShapedText ( linePath, QPointF (0 , linePos) , m_font, line);
204263 }
205264 linePos += m_lineSpacing;
206265 if (m_align == Qt::AlignHCenter) {
@@ -212,7 +271,7 @@ class PlainTextItem : public QGraphicsItem
212271 }
213272 m_path.addPath (linePath);
214273 }
215- m_path. setFillRule (Qt::WindingFill);
274+
216275 if (!m_path.isEmpty ()) {
217276 int minWidth = m_path.boundingRect ().width ();
218277 int minHeight = m_lineSpacing * lines.size ();
@@ -223,6 +282,7 @@ class PlainTextItem : public QGraphicsItem
223282 m_boundingRect.setHeight (minHeight);
224283 }
225284 }
285+ updateShadows ();
226286 }
227287
228288 virtual QRectF boundingRect () const { return m_boundingRect; }
@@ -247,10 +307,8 @@ class PlainTextItem : public QGraphicsItem
247307 void updateShadows ()
248308 {
249309 if (m_params.count () < 5 || m_params.at (0 ).toInt () == false ) {
250- // Invalid or no shadow wanted
251310 return ;
252311 }
253- // Build shadow image
254312 QColor shadowColor = QColor (m_params.at (1 ));
255313 int blurRadius = m_params.at (2 ).toInt ();
256314 int offsetX = m_params.at (3 ).toInt ();
@@ -396,6 +454,7 @@ void loadFromXml(producer_ktitle self,
396454 if (nodeAttributes.namedItem (" type" ).nodeValue () == " QGraphicsTextItem" ) {
397455 QDomNamedNodeMap txtProperties = node.namedItem (" content" ).attributes ();
398456 QFont font (txtProperties.namedItem (" font" ).nodeValue ());
457+ font.setHintingPreference (QFont::PreferFullHinting);
399458 QDomNode propsNode = txtProperties.namedItem (" font-bold" );
400459 if (!propsNode.isNull ()) {
401460 // Old: Bold/Not bold.
@@ -687,6 +746,10 @@ void loadFromXml(producer_ktitle self,
687746 gitem = txt;
688747 } else {
689748 QGraphicsTextItem *txt = scene->addText (text, font);
749+ txt->document ()->setDefaultFont (font);
750+ QTextOption opt = txt->document ()->defaultTextOption ();
751+ opt.setTextDirection (Qt::LayoutDirectionAuto);
752+ txt->document ()->setDefaultTextOption (opt);
690753 gitem = txt;
691754 if (txtProperties.namedItem (" font-outline" ).nodeValue ().toDouble () > 0.0 ) {
692755 QTextDocument *doc = txt->document ();
0 commit comments