154 : d(
new QQuickStyledTextPrivate(string, layout, imgTags, baseUrl, context, preloadImages, fontSizeModified))
178 QList<QTextLayout::FormatRange> ranges;
179 QStack<QTextCharFormat> formatStack;
182 drawText.reserve(text.size());
184 updateImagePositions = !imgTags->isEmpty();
189 bool formatChanged =
false;
191 const QChar *ch = text.constData();
192 while (!ch->isNull()) {
193 if (*ch == lessThan) {
195 appendText(text, textStart, textLength, drawText);
197 drawText.append(space);
202 if (rangeStart != drawText.size() && formatStack.size()) {
204 QTextLayout::FormatRange formatRange;
205 formatRange.format = formatStack.top();
206 formatRange.start = rangeStart;
207 formatRange.length = drawText.size() - rangeStart;
208 ranges.append(formatRange);
209 formatChanged =
false;
210 }
else if (ranges.size()) {
211 ranges.last().length += drawText.size() - rangeStart;
214 rangeStart = drawText.size();
218 if (parseCloseTag(ch, text, drawText)) {
219 if (formatStack.size()) {
220 formatChanged =
true;
225 QTextCharFormat format;
226 if (formatStack.size())
227 format = formatStack.top();
228 if (parseTag(ch, text, drawText, format)) {
229 formatChanged =
true;
230 formatStack.push(format);
233 textStart = ch - text.constData() + 1;
235 }
else if (*ch == ampersand) {
237 appendText(text, textStart, textLength, drawText);
238 parseEntity(ch, text, drawText);
239 textStart = ch - text.constData() + 1;
241 }
else if (ch->isSpace()) {
243 appendText(text, textStart, textLength, drawText);
246 for (
const QChar *n = ch + 1; !n->isNull() && n->isSpace(); ++n)
249 }
else if (*ch == lineFeed) {
250 drawText.append(QChar(QChar::LineSeparator));
253 drawText.append(QChar(QChar::Nbsp));
256 textStart = ch - text.constData() + 1;
265 appendText(text, textStart, textLength, drawText);
266 if (rangeStart != drawText.size() && formatStack.size()) {
268 QTextLayout::FormatRange formatRange;
269 formatRange.format = formatStack.top();
270 formatRange.start = rangeStart;
271 formatRange.length = drawText.size() - rangeStart;
272 ranges.append(formatRange);
273 }
else if (ranges.size()) {
274 ranges.last().length += drawText.size() - rangeStart;
281 for (
int i = 0; i < imgTags->size(); ++i) {
282 const QQuickStyledTextImgTag *image = imgTags->at(i);
283 QTextLayout::FormatRange range;
284 QTextImageFormat imgFmt;
285 if (image->size.isValid()) {
286 imgFmt.setWidth(image->size.width() + QQuickStyledTextImgTag::HMargin * 2);
287 imgFmt.setHeight(image->size.height());
290 imgFmt.setVerticalAlignment(QTextCharFormat::AlignBaseline);
291 imgFmt.setObjectIndex(i);
292 if (!image->tooltip.isEmpty())
293 imgFmt.setToolTip(image->tooltip);
294 range.format = imgFmt;
295 range.start = image->position;
297 ranges.append(range);
301 layout.setText(drawText);
302 layout.setFormats(ranges);
333 int tagStart = ch - textIn.constData();
335 while (!ch->isNull()) {
336 if (*ch == greaterThan) {
339 auto tag = QStringView(textIn).mid(tagStart, tagLength);
340 switch (lookupHtmlTag(tag)) {
342 format.setFontWeight(QFont::Bold);
345 textOut.append(QChar(QChar::LineSeparator));
350 format.setFontItalic(
true);
354 textOut.append(QChar::LineSeparator);
361 textOut.append(QChar::LineSeparator);
362 format.setFontFamilies(QStringList {QString::fromLatin1(
"Courier New"), QString::fromLatin1(
"courier")});
363 format.setFontFixedPitch(
true);
366 format.setFontUnderline(
true);
373 listStack.push(listItem);
382 int level = tag.at(1).digitValue();
384 textOut.append(QChar::LineSeparator);
387 setFontSize(7 - level, format);
388 format.setFontWeight(QFont::Bold);
392 format.setFontStrikeOut(
true);
395 format.setFontWeight(QFont::Bold);
398 format.setFontStrikeOut(
true);
405 listStack.push(listItem);
410 textOut.append(QChar(QChar::LineSeparator));
411 if (!listStack.isEmpty()) {
412 int count = ++listStack.top().level;
413 for (
int i = 0; i < listStack.size(); ++i)
414 textOut += QString(tabsize, QChar::Nbsp);
415 switch (listStack.top().format) {
417 textOut += QString::number(count) % QLatin1Char(
'.');
420 textOut +=
toAlpha(count,
false) % QLatin1Char(
'.');
423 textOut +=
toAlpha(count,
true) % QLatin1Char(
'.');
426 textOut +=
toRoman(count,
false) % QLatin1Char(
'.');
429 textOut +=
toRoman(count,
true) % QLatin1Char(
'.');
441 textOut += QString(2, QChar::Nbsp);
448 }
else if (ch->isSpace()) {
450 auto tag = QStringView(textIn).mid(tagStart, tagLength);
451 switch (lookupHtmlTag(tag)) {
453 return parseFontAttributes(ch, textIn, format);
455 parseOrderedListAttributes(ch, textIn);
458 parseUnorderedListAttributes(ch, textIn);
461 return parseAnchorAttributes(ch, textIn, format);
463 parseImageAttributes(ch, textIn, textOut);
466 if (*ch == greaterThan || ch->isNull())
470 }
else if (*ch != slash) {
575 std::pair<QStringView,QStringView> attr;
577 attr = parseAttribute(ch, textIn);
578 if (is_equal_ignoring_case(attr.first, QLatin1String(
"color"))) {
580 format.setForeground(QColor::fromString(attr.second));
581 }
else if (is_equal_ignoring_case(attr.first, QLatin1String(
"size"))) {
583 int size = attr.second.toInt();
584 if (attr.second.at(0) == QLatin1Char(
'-') || attr.second.at(0) == QLatin1Char(
'+'))
586 if (size >= 1 && size <= 7)
587 setFontSize(size, format);
589 }
while (!ch->isNull() && !attr.first.isEmpty());
603 std::pair<QStringView,QStringView> attr;
605 attr = parseAttribute(ch, textIn);
606 if (is_equal_ignoring_case(attr.first, QLatin1String(
"type"))) {
608 if (attr.second == QLatin1String(
"a"))
610 else if (attr.second == QLatin1String(
"A"))
612 else if (attr.second == QLatin1String(
"i"))
614 else if (attr.second == QLatin1String(
"I"))
617 }
while (!ch->isNull() && !attr.first.isEmpty());
619 listStack.push(listItem);
652 std::pair<QStringView,QStringView> attr;
654 attr = parseAttribute(ch, textIn);
655 if (is_equal_ignoring_case(attr.first, QLatin1String(
"href"))) {
656 format.setAnchorHref(attr.second.toString());
657 format.setAnchor(
true);
658 format.setFontUnderline(
true);
660 }
else if (is_equal_ignoring_case(attr.first, QLatin1String(
"title"))) {
661 format.setToolTip(attr.second.toString());
664 }
while (!ch->isNull() && !attr.first.isEmpty());
672 QQuickStyledTextImgTag *image =
new QQuickStyledTextImgTag;
673 image->position = textOut.size();
675 std::pair<QStringView,QStringView> attr;
677 attr = parseAttribute(ch, textIn);
678 if (is_equal_ignoring_case(attr.first, QLatin1String(
"src"))) {
679 image->url = QUrl(attr.second.toString());
680 }
else if (is_equal_ignoring_case(attr.first, QLatin1String(
"title"))) {
681 image->tooltip = attr.second.toString();
682 }
else if (is_equal_ignoring_case(attr.first, QLatin1String(
"width"))) {
684 int v = attr.second.toInt(&ok);
686 image->size.setWidth(v);
688 qCWarning(lcStyledText) <<
"Invalid width provided for <img>";
689 }
else if (is_equal_ignoring_case(attr.first, QLatin1String(
"height"))) {
691 int v = attr.second.toInt(&ok);
693 image->size.setHeight(v);
695 qCWarning(lcStyledText) <<
"Invalid height provided for <img>";
696 }
else if (is_equal_ignoring_case(attr.first, QLatin1String(
"align"))) {
697 if (is_equal_ignoring_case(attr.second, QLatin1String(
"top"))) {
698 image->align = QQuickStyledTextImgTag::Top;
699 }
else if (is_equal_ignoring_case(attr.second, QLatin1String(
"middle"))) {
700 image->align = QQuickStyledTextImgTag::Middle;
703 }
while (!ch->isNull() && !attr.first.isEmpty());
709 QUrl url = baseUrl.resolved(image->url);
710 if (url.isLocalFile()) {
711 image->pix.reset(
new QQuickPixmap(context->engine(), url, QRect(), image->size));
712 if (image->pix && image->pix->isReady()) {
713 image->size = image->pix->implicitSize();
721 if (!image->url.isValid()) {
723 qCWarning(lcStyledText) <<
"StyledText - Invalid base url in img tag";
727 imgTags->append(image);
731 QQuickStyledTextImgTag *image = imgTags->value(nbImages);
732 image->position = textOut.size();
733 std::pair<QStringView,QStringView> attr;
735 attr = parseAttribute(ch, textIn);
736 }
while (!ch->isNull() && !attr.first.isEmpty());
740 textOut += QChar::ObjectReplacementCharacter;
748 int attrStart = ch - textIn.constData();
750 while (!ch->isNull()) {
751 if (*ch == greaterThan) {
753 }
else if (*ch == equals) {
755 if (*ch != singleQuote && *ch != doubleQuote) {
756 while (*ch != greaterThan && !ch->isNull())
763 auto attr = QStringView(textIn).mid(attrStart, attrLength);
764 QStringView val = parseValue(ch, textIn);
766 return std::pair<QStringView,QStringView>(attr,val);
774 return std::pair<QStringView,QStringView>();
808 QString result = QLatin1String(
"?");
811 QByteArray romanNumeral;
813 static const char romanSymbolsLower[] =
"iiivixxxlxcccdcmmmm";
814 static const char romanSymbolsUpper[] =
"IIIVIXXXLXCCCDCMMMM";
815 QByteArray romanSymbols;
817 romanSymbols = QByteArray::fromRawData(romanSymbolsLower,
sizeof(romanSymbolsLower));
819 romanSymbols = QByteArray::fromRawData(romanSymbolsUpper,
sizeof(romanSymbolsUpper));
821 int c[] = { 1, 4, 5, 9, 10, 40, 50, 90, 100, 400, 500, 900, 1000 };
823 for (
int i = 12; i >= 0; n %= c[i], i--) {
826 int startDigit = i + (i + 3) / 4;
836 romanNumeral.append(romanSymbols.mid(startDigit, numDigits));
839 result = QString::fromLatin1(romanNumeral);
QList< QQuickStyledTextImgTag * > * imgTags
bool parseCloseTag(const QChar *&ch, const QString &textIn, QString &textOut)
void parseImageAttributes(const QChar *&ch, const QString &textIn, QString &textOut)
void setFontSize(int size, QTextCharFormat &format)
bool parseTag(const QChar *&ch, const QString &textIn, QString &textOut, QTextCharFormat &format)
bool parseAnchorAttributes(const QChar *&ch, const QString &textIn, QTextCharFormat &format)
std::pair< QStringView, QStringView > parseAttribute(const QChar *&ch, const QString &textIn)
void parseEntity(const QChar *&ch, const QString &textIn, QString &textOut)
QStringView parseValue(const QChar *&ch, const QString &textIn)
static QString toRoman(int value, bool upper)
bool parseFontAttributes(const QChar *&ch, const QString &textIn, QTextCharFormat &format)
bool parseOrderedListAttributes(const QChar *&ch, const QString &textIn)
void appendText(const QString &textIn, int start, int length, QString &textOut)
void skipSpace(const QChar *&ch)
QQuickStyledTextPrivate(const QString &t, QTextLayout &l, QList< QQuickStyledTextImgTag * > &imgTags, const QUrl &baseUrl, QQmlContext *context, bool preloadImages, bool *fontSizeModified)
static QString toAlpha(int value, bool upper)
bool parseUnorderedListAttributes(const QChar *&ch, const QString &textIn)
#define QQUICKSTYLEDPARSER_COORD_LIMIT