Color transparency support in html import/export

Export of color transparency component is added for cases where color
is exported to html. New static function colorValue() is added to
prepare CSS string representation of QColor. When the color is opaque,
it falls down to QColor::name() method which was used previously,
otherwise it returns 'rgba()' CSS statement or 'transparent' keyword in
case transparency is 0.
6-digit precision is used for alpha value as it's maximum which can be
processed properly by Gecko and Webkit engines
(http://lists.w3.org/Archives/Public/www-style/2009Dec/0295.html).

Import part for rgba() statement was also added to QCssParser. It
supports rgba() color values as stated in CSS Color Module Level 3
(http://www.w3.org/TR/css3-color/#rgba-color).

Import of undocumented statement 'rgba(int,int,int,int);' was also
added to preserve regression test success and to provide compatibility
with previous code relying on this behaviour.

Test cases added to QCssParser autotest for rgba(int,int,int,float)
statement and to QTextDocument autotest for rgba(int,int,int,float)
and 'transparent' statements for certain 'color', 'background-color'
and 'bgcolor' properties.

Change-Id: Id341c4e800249820d52edef8003e50f9a74d062b
Reviewed-by: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@nokia.com>
This commit is contained in:
Alexey Chernov 2012-07-02 23:14:31 +04:00 committed by Qt by Nokia
parent 69fb70f6b3
commit 2d5d6c8fbc
4 changed files with 155 additions and 5 deletions

View File

@ -702,6 +702,7 @@ static ColorData parseColorValue(QCss::Value v)
}
bool rgb = lst.at(0).startsWith(QLatin1String("rgb"));
bool rgba = lst.at(0).startsWith(QLatin1String("rgba"));
Parser p(lst.at(1));
if (!p.testExpr())
@ -723,7 +724,14 @@ static ColorData parseColorValue(QCss::Value v)
int v1 = colorDigits.at(0).variant.toInt();
int v2 = colorDigits.at(2).variant.toInt();
int v3 = colorDigits.at(4).variant.toInt();
int alpha = colorDigits.count() >= 7 ? colorDigits.at(6).variant.toInt() : 255;
int alpha = 255;
if (colorDigits.count() >= 7) {
int alphaValue = colorDigits.at(6).variant.toInt();
if (rgba && alphaValue <= 1)
alpha = colorDigits.at(6).variant.toReal() * 255.;
else
alpha = alphaValue;
}
return rgb ? QColor::fromRgb(v1, v2, v3, alpha)
: QColor::fromHsv(v1, v2, v3, alpha);

View File

@ -1990,6 +1990,25 @@ static QTextFormat formatDifference(const QTextFormat &from, const QTextFormat &
return diff;
}
static QString colorValue(QColor color)
{
QString result;
if (color.alpha() == 255) {
result = color.name();
} else if (color.alpha()) {
QString alphaValue = QString::number(color.alphaF(), 'f', 6).remove(QRegExp(QLatin1String("\\.?0*$")));
result = QString::fromLatin1("rgba(%1,%2,%3,%4)").arg(color.red())
.arg(color.green())
.arg(color.blue())
.arg(alphaValue);
} else {
result = QLatin1String("transparent");
}
return result;
}
QTextHtmlExporter::QTextHtmlExporter(const QTextDocument *_doc)
: doc(_doc), fragmentMarkers(false)
{
@ -2186,7 +2205,7 @@ bool QTextHtmlExporter::emitCharFormatStyle(const QTextCharFormat &format)
if (format.foreground() != defaultCharFormat.foreground()
&& format.foreground().style() != Qt::NoBrush) {
html += QLatin1String(" color:");
html += format.foreground().color().name();
html += colorValue(format.foreground().color());
html += QLatin1Char(';');
attributesEmitted = true;
}
@ -2194,7 +2213,7 @@ bool QTextHtmlExporter::emitCharFormatStyle(const QTextCharFormat &format)
if (format.background() != defaultCharFormat.background()
&& format.background().style() == Qt::SolidPattern) {
html += QLatin1String(" background-color:");
html += format.background().color().name();
html += colorValue(format.background().color());
html += QLatin1Char(';');
attributesEmitted = true;
}
@ -2729,7 +2748,7 @@ void QTextHtmlExporter::emitBackgroundAttribute(const QTextFormat &format)
} else {
const QBrush &brush = format.background();
if (brush.style() == Qt::SolidPattern) {
emitAttribute("bgcolor", brush.color().name());
emitAttribute("bgcolor", colorValue(brush.color()));
} else if (brush.style() == Qt::TexturePattern) {
const bool isPixmap = qHasPixmapTexture(brush);
const qint64 cacheKey = isPixmap ? brush.texture().cacheKey() : brush.textureImage().cacheKey();
@ -2937,7 +2956,7 @@ void QTextHtmlExporter::emitFrameStyle(const QTextFrameFormat &format, FrameType
if (format.borderBrush() != defaultFormat.borderBrush()) {
html += QLatin1String(" border-color:");
html += format.borderBrush().color().name();
html += colorValue(format.borderBrush().color());
html += QLatin1Char(';');
}

View File

@ -855,6 +855,7 @@ void tst_QCssParser::colorValue_data()
QTest::newRow("functional1") << "color: rgb(21, 45, 73)" << QColor(21, 45, 73);
QTest::newRow("functional2") << "color: rgb(100%, 0%, 100%)" << QColor(0xff, 0, 0xff);
QTest::newRow("rgba") << "color: rgba(10, 20, 30, 40)" << QColor(10, 20, 30, 40);
QTest::newRow("rgbaf") << "color: rgba(10, 20, 30, 0.5)" << QColor(10, 20, 30, 127);
QTest::newRow("rgb") << "color: rgb(10, 20, 30, 40)" << QColor(10, 20, 30, 40);
QTest::newRow("hsl") << "color: hsv(10, 20, 30)" << QColor::fromHsv(10, 20, 30, 255);
QTest::newRow("hsla") << "color: hsva(10, 20, 30, 40)" << QColor::fromHsv(10, 20, 30, 40);

View File

@ -110,6 +110,8 @@ private slots:
void setFragmentMarkersInHtmlExport();
void toHtmlBodyBgColor();
void toHtmlBodyBgColorRgba();
void toHtmlBodyBgColorTransparent();
void toHtmlRootFrameProperties();
void capitalizationHtmlInExport();
void wordspacingHtmlExport();
@ -894,6 +896,32 @@ void tst_QTextDocument::toHtml_data()
QString("<p OPENDEFAULTBLOCKSTYLE background-color:#0000ff;\">Blah</p>");
}
{
CREATE_DOC_AND_CURSOR();
QTextBlockFormat fmt;
fmt.setBackground(QColor(255, 0, 0, 51));
cursor.insertBlock(fmt);
cursor.insertText("Blah");
QTest::newRow("bgcolor-rgba") << QTextDocumentFragment(&doc)
<< QString("EMPTYBLOCK") +
QString("<p OPENDEFAULTBLOCKSTYLE background-color:rgba(255,0,0,0.2);\">Blah</p>");
}
{
CREATE_DOC_AND_CURSOR();
QTextBlockFormat fmt;
fmt.setBackground(QColor(255, 0, 0, 0));
cursor.insertBlock(fmt);
cursor.insertText("Blah");
QTest::newRow("bgcolor-transparent") << QTextDocumentFragment(&doc)
<< QString("EMPTYBLOCK") +
QString("<p OPENDEFAULTBLOCKSTYLE background-color:transparent;\">Blah</p>");
}
{
CREATE_DOC_AND_CURSOR();
@ -939,6 +967,28 @@ void tst_QTextDocument::toHtml_data()
<< QString("<p DEFAULTBLOCKSTYLE><span style=\" color:#00ff00;\">Blah</span></p>");
}
{
CREATE_DOC_AND_CURSOR();
QTextCharFormat fmt;
fmt.setForeground(QColor(0, 255, 0, 51));
cursor.insertText("Blah", fmt);
QTest::newRow("color-rgba") << QTextDocumentFragment(&doc)
<< QString("<p DEFAULTBLOCKSTYLE><span style=\" color:rgba(0,255,0,0.2);\">Blah</span></p>");
}
{
CREATE_DOC_AND_CURSOR();
QTextCharFormat fmt;
fmt.setForeground(QColor(0, 255, 0, 0));
cursor.insertText("Blah", fmt);
QTest::newRow("color-transparent") << QTextDocumentFragment(&doc)
<< QString("<p DEFAULTBLOCKSTYLE><span style=\" color:transparent;\">Blah</span></p>");
}
{
CREATE_DOC_AND_CURSOR();
@ -950,6 +1000,28 @@ void tst_QTextDocument::toHtml_data()
<< QString("<p DEFAULTBLOCKSTYLE><span style=\" background-color:#00ff00;\">Blah</span></p>");
}
{
CREATE_DOC_AND_CURSOR();
QTextCharFormat fmt;
fmt.setBackground(QColor(0, 255, 0, 51));
cursor.insertText("Blah", fmt);
QTest::newRow("span-bgcolor-rgba") << QTextDocumentFragment(&doc)
<< QString("<p DEFAULTBLOCKSTYLE><span style=\" background-color:rgba(0,255,0,0.2);\">Blah</span></p>");
}
{
CREATE_DOC_AND_CURSOR();
QTextCharFormat fmt;
fmt.setBackground(QColor(0, 255, 0, 0));
cursor.insertText("Blah", fmt);
QTest::newRow("span-bgcolor-transparent") << QTextDocumentFragment(&doc)
<< QString("<p DEFAULTBLOCKSTYLE><span style=\" background-color:transparent;\">Blah</span></p>");
}
{
CREATE_DOC_AND_CURSOR();
@ -1706,6 +1778,56 @@ void tst_QTextDocument::toHtmlBodyBgColor()
QCOMPARE(doc.toHtml(), expectedHtml);
}
void tst_QTextDocument::toHtmlBodyBgColorRgba()
{
CREATE_DOC_AND_CURSOR();
cursor.insertText("Blah");
QTextFrameFormat fmt = doc.rootFrame()->frameFormat();
fmt.setBackground(QColor(255, 0, 0, 51));
doc.rootFrame()->setFrameFormat(fmt);
QString expectedHtml("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" "
"\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n"
"</style></head>"
"<body style=\" font-family:'%1'; font-size:%2pt; font-weight:%3; font-style:%4;\""
" bgcolor=\"rgba(255,0,0,0.2)\">\n"
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Blah</p>"
"</body></html>");
expectedHtml = expectedHtml.arg(defaultFont.family()).arg(defaultFont.pointSizeF()).arg(defaultFont.weight() * 8).arg((defaultFont.italic() ? "italic" : "normal"));
QCOMPARE(doc.toHtml(), expectedHtml);
}
void tst_QTextDocument::toHtmlBodyBgColorTransparent()
{
CREATE_DOC_AND_CURSOR();
cursor.insertText("Blah");
QTextFrameFormat fmt = doc.rootFrame()->frameFormat();
fmt.setBackground(QColor(255, 0, 0, 0));
doc.rootFrame()->setFrameFormat(fmt);
QString expectedHtml("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.0//EN\" "
"\"http://www.w3.org/TR/REC-html40/strict.dtd\">\n"
"<html><head><meta name=\"qrichtext\" content=\"1\" /><style type=\"text/css\">\n"
"p, li { white-space: pre-wrap; }\n"
"</style></head>"
"<body style=\" font-family:'%1'; font-size:%2pt; font-weight:%3; font-style:%4;\""
" bgcolor=\"transparent\">\n"
"<p style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">Blah</p>"
"</body></html>");
expectedHtml = expectedHtml.arg(defaultFont.family()).arg(defaultFont.pointSizeF()).arg(defaultFont.weight() * 8).arg((defaultFont.italic() ? "italic" : "normal"));
QCOMPARE(doc.toHtml(), expectedHtml);
}
void tst_QTextDocument::toHtmlRootFrameProperties()
{
CREATE_DOC_AND_CURSOR();