1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: http://www.qt-project.org/
7 ** This file is part of the QtDeclarative module of the Qt Toolkit.
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
45 #include <QTextLayout>
48 #include "QtQuick1/private/qdeclarativestyledtext_p.h"
51 QDeclarative1StyledText supports few tags:
56 <font color="color_name" size="1-7"></font>
58 The opening and closing tags must be correctly nested.
65 class QDeclarative1StyledTextPrivate
68 QDeclarative1StyledTextPrivate(const QString &t, QTextLayout &l) : text(t), layout(l), baseFont(layout.font()) {}
71 bool parseTag(const QChar *&ch, const QString &textIn, QString &textOut, QTextCharFormat &format);
72 bool parseCloseTag(const QChar *&ch, const QString &textIn);
73 void parseEntity(const QChar *&ch, const QString &textIn, QString &textOut);
74 bool parseFontAttributes(const QChar *&ch, const QString &textIn, QTextCharFormat &format);
75 QPair<QStringRef,QStringRef> parseAttribute(const QChar *&ch, const QString &textIn);
76 QStringRef parseValue(const QChar *&ch, const QString &textIn);
78 inline void skipSpace(const QChar *&ch) {
79 while (ch->isSpace() && !ch->isNull())
87 static const QChar lessThan;
88 static const QChar greaterThan;
89 static const QChar equals;
90 static const QChar singleQuote;
91 static const QChar doubleQuote;
92 static const QChar slash;
93 static const QChar ampersand;
96 const QChar QDeclarative1StyledTextPrivate::lessThan(QLatin1Char('<'));
97 const QChar QDeclarative1StyledTextPrivate::greaterThan(QLatin1Char('>'));
98 const QChar QDeclarative1StyledTextPrivate::equals(QLatin1Char('='));
99 const QChar QDeclarative1StyledTextPrivate::singleQuote(QLatin1Char('\''));
100 const QChar QDeclarative1StyledTextPrivate::doubleQuote(QLatin1Char('\"'));
101 const QChar QDeclarative1StyledTextPrivate::slash(QLatin1Char('/'));
102 const QChar QDeclarative1StyledTextPrivate::ampersand(QLatin1Char('&'));
104 QDeclarative1StyledText::QDeclarative1StyledText(const QString &string, QTextLayout &layout)
105 : d(new QDeclarative1StyledTextPrivate(string, layout))
109 QDeclarative1StyledText::~QDeclarative1StyledText()
114 void QDeclarative1StyledText::parse(const QString &string, QTextLayout &layout)
116 if (string.isEmpty())
118 QDeclarative1StyledText styledText(string, layout);
119 styledText.d->parse();
122 void QDeclarative1StyledTextPrivate::parse()
124 QList<QTextLayout::FormatRange> ranges;
125 QStack<QTextCharFormat> formatStack;
128 drawText.reserve(text.count());
133 const QChar *ch = text.constData();
134 while (!ch->isNull()) {
135 if (*ch == lessThan) {
137 drawText.append(QStringRef(&text, textStart, textLength));
138 if (rangeStart != drawText.length() && formatStack.count()) {
139 QTextLayout::FormatRange formatRange;
140 formatRange.format = formatStack.top();
141 formatRange.start = rangeStart;
142 formatRange.length = drawText.length() - rangeStart;
143 ranges.append(formatRange);
145 rangeStart = drawText.length();
149 if (parseCloseTag(ch, text)) {
150 if (formatStack.count())
154 QTextCharFormat format;
155 if (formatStack.count())
156 format = formatStack.top();
157 if (parseTag(ch, text, drawText, format))
158 formatStack.push(format);
160 textStart = ch - text.constData() + 1;
162 } else if (*ch == ampersand) {
164 drawText.append(QStringRef(&text, textStart, textLength));
165 parseEntity(ch, text, drawText);
166 textStart = ch - text.constData() + 1;
175 drawText.append(QStringRef(&text, textStart, textLength));
176 if (rangeStart != drawText.length() && formatStack.count()) {
177 QTextLayout::FormatRange formatRange;
178 formatRange.format = formatStack.top();
179 formatRange.start = rangeStart;
180 formatRange.length = drawText.length() - rangeStart;
181 ranges.append(formatRange);
184 layout.setText(drawText);
185 layout.setAdditionalFormats(ranges);
188 bool QDeclarative1StyledTextPrivate::parseTag(const QChar *&ch, const QString &textIn, QString &textOut, QTextCharFormat &format)
192 int tagStart = ch - textIn.constData();
194 while (!ch->isNull()) {
195 if (*ch == greaterThan) {
196 QStringRef tag(&textIn, tagStart, tagLength);
197 const QChar char0 = tag.at(0);
198 if (char0 == QLatin1Char('b')) {
200 format.setFontWeight(QFont::Bold);
201 else if (tagLength == 2 && tag.at(1) == QLatin1Char('r')) {
202 textOut.append(QChar(QChar::LineSeparator));
205 } else if (char0 == QLatin1Char('i')) {
207 format.setFontItalic(true);
210 } else if (ch->isSpace()) {
212 QStringRef tag(&textIn, tagStart, tagLength);
213 if (tag == QLatin1String("font"))
214 return parseFontAttributes(ch, textIn, format);
215 if (*ch == greaterThan || ch->isNull())
217 } else if (*ch != slash){
226 bool QDeclarative1StyledTextPrivate::parseCloseTag(const QChar *&ch, const QString &textIn)
230 int tagStart = ch - textIn.constData();
232 while (!ch->isNull()) {
233 if (*ch == greaterThan) {
234 QStringRef tag(&textIn, tagStart, tagLength);
235 const QChar char0 = tag.at(0);
236 if (char0 == QLatin1Char('b')) {
239 else if (tag.at(1) == QLatin1Char('r') && tagLength == 2)
241 } else if (char0 == QLatin1Char('i')) {
244 } else if (tag == QLatin1String("font")) {
248 } else if (!ch->isSpace()){
257 void QDeclarative1StyledTextPrivate::parseEntity(const QChar *&ch, const QString &textIn, QString &textOut)
259 int entityStart = ch - textIn.constData();
260 int entityLength = 0;
261 while (!ch->isNull()) {
262 if (*ch == QLatin1Char(';')) {
263 QStringRef entity(&textIn, entityStart, entityLength);
264 if (entity == QLatin1String("gt"))
265 textOut += QChar(62);
266 else if (entity == QLatin1String("lt"))
267 textOut += QChar(60);
268 else if (entity == QLatin1String("amp"))
269 textOut += QChar(38);
277 bool QDeclarative1StyledTextPrivate::parseFontAttributes(const QChar *&ch, const QString &textIn, QTextCharFormat &format)
280 QPair<QStringRef,QStringRef> attr;
282 attr = parseAttribute(ch, textIn);
283 if (attr.first == QLatin1String("color")) {
285 format.setForeground(QColor(attr.second.toString()));
286 } else if (attr.first == QLatin1String("size")) {
288 int size = attr.second.toString().toInt();
289 if (attr.second.at(0) == QLatin1Char('-') || attr.second.at(0) == QLatin1Char('+'))
291 if (size >= 1 && size <= 7) {
292 static const qreal scaling[] = { 0.7, 0.8, 1.0, 1.2, 1.5, 2.0, 2.4 };
293 format.setFontPointSize(baseFont.pointSize() * scaling[size-1]);
296 } while (!ch->isNull() && !attr.first.isEmpty());
301 QPair<QStringRef,QStringRef> QDeclarative1StyledTextPrivate::parseAttribute(const QChar *&ch, const QString &textIn)
305 int attrStart = ch - textIn.constData();
307 while (!ch->isNull()) {
308 if (*ch == greaterThan) {
310 } else if (*ch == equals) {
312 if (*ch != singleQuote && *ch != doubleQuote) {
313 while (*ch != greaterThan && !ch->isNull())
320 QStringRef attr(&textIn, attrStart, attrLength);
321 QStringRef val = parseValue(ch, textIn);
323 return QPair<QStringRef,QStringRef>(attr,val);
331 return QPair<QStringRef,QStringRef>();
334 QStringRef QDeclarative1StyledTextPrivate::parseValue(const QChar *&ch, const QString &textIn)
336 int valStart = ch - textIn.constData();
338 while (*ch != singleQuote && *ch != doubleQuote && !ch->isNull()) {
346 return QStringRef(&textIn, valStart, valLength);