File indexing completed on 2024-05-12 05:04:25

0001 /**
0002  * SPDX-FileCopyrightText: 2023 Janet Black
0003  *
0004  * SPDX-License-Identifier: LGPL-2.0-or-later
0005  */
0006 
0007 #include "textpreprocessing.h"
0008 
0009 #include <QQuickTextDocument>
0010 #include <QTextBlock>
0011 #include <QTextCursor>
0012 #include <QTextDocument>
0013 
0014 TextPreprocessing::TextPreprocessing(QObject *parent)
0015     : QObject(parent)
0016 {
0017 }
0018 
0019 TextPreprocessing::~TextPreprocessing()
0020 {
0021 }
0022 
0023 static const auto fsi = QStringLiteral("\u2068");
0024 static const auto pdi = QStringLiteral("\u2069");
0025 static const auto lineSeparator = QStringLiteral("\u2028");
0026 
0027 QString TextPreprocessing::preprocessHTML(const QString &html, const QColor &linkColor)
0028 {
0029     QTextDocument doc;
0030     doc.setHtml(html);
0031 
0032     // transform mentions into isolates
0033     // this causes mentions to effectively be treated as opaque and non-text for
0034     // the purposes of the bidirectionality algorithim, which is how users expect
0035     // them to behave
0036     // pt 1 of 475043 fix
0037     for (auto block = doc.begin(); block != doc.end(); block = block.next()) {
0038         for (auto fragment = block.begin(); fragment != block.end(); fragment++) {
0039             auto it = fragment.fragment();
0040 
0041             if (it.charFormat().isAnchor() && it.text().startsWith(QStringLiteral("@"))) {
0042                 QTextCursor curs(&doc);
0043                 curs.setPosition(it.position(), QTextCursor::MoveAnchor);
0044                 curs.setPosition(it.position() + it.length(), QTextCursor::KeepAnchor);
0045                 curs.insertText(fsi + it.text() + pdi);
0046             }
0047 
0048             // while we're iterating through fragments we might as well set the kirigami
0049             // link colour here
0050             if (it.charFormat().isAnchor()) {
0051                 auto format = it.charFormat();
0052                 format.setForeground(linkColor);
0053                 format.setFontUnderline(false);
0054                 format.setUnderlineStyle(QTextCharFormat::NoUnderline);
0055 
0056                 QTextCursor curs(&doc);
0057                 curs.setPosition(it.position(), QTextCursor::MoveAnchor);
0058                 curs.setPosition(it.position() + it.length(), QTextCursor::KeepAnchor);
0059                 curs.setCharFormat(format);
0060             }
0061         }
0062     }
0063 
0064     // split apart <br> into different text blocks
0065     // so that different spans can have different layout directions
0066     // better matching bidirectionality behaviour that users are expecting
0067     // pt 2 of 475043 fix
0068     for (auto cursor = doc.find(lineSeparator); !cursor.isNull(); cursor = doc.find(lineSeparator, cursor)) {
0069         cursor.insertBlock();
0070     }
0071 
0072     return doc.toHtml();
0073 }
0074 
0075 #include "moc_textpreprocessing.cpp"