diff options
author | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2019-12-04 01:00:07 +0100 |
---|---|---|
committer | Qt Forward Merge Bot <qt_forward_merge_bot@qt-project.org> | 2019-12-04 01:00:07 +0100 |
commit | d025c1a75f722f3adfd77f8d7f887e754c925d17 (patch) | |
tree | 22efcb332a975652cbde1db81e15b844c4007137 | |
parent | 2ed59f0d42d2817a5855be167f5e3ccf23563e39 (diff) | |
parent | dc7fa56948a2a7953f645c7f9d7237925b3f9abe (diff) |
Merge remote-tracking branch 'origin/5.14' into 5.15
Change-Id: Ia70e81943ef097941339f9ef9ace28592a2eb740
-rw-r--r-- | src/corelib/kernel/qvariant.cpp | 4 | ||||
-rw-r--r-- | src/corelib/time/qdatetimeparser.cpp | 12 | ||||
-rw-r--r-- | src/corelib/time/qtimezoneprivate_mac.mm | 36 | ||||
-rw-r--r-- | src/gui/rhi/qrhi_p.h | 20 | ||||
-rw-r--r-- | src/gui/text/qcssparser.cpp | 1 | ||||
-rw-r--r-- | src/gui/text/qcssparser_p.h | 4 | ||||
-rw-r--r-- | src/gui/text/qtexthtmlparser.cpp | 7 | ||||
-rw-r--r-- | src/opengl/qgl.cpp | 2 | ||||
-rw-r--r-- | src/plugins/platforms/wasm/qwasmopenglcontext.cpp | 7 | ||||
-rw-r--r-- | src/plugins/styles/mac/qmacstyle_mac.mm | 8 | ||||
-rw-r--r-- | tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp | 20 | ||||
-rw-r--r-- | tests/auto/gui/kernel/qguivariant/test/tst_qguivariant.cpp | 21 | ||||
-rw-r--r-- | tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp | 38 |
13 files changed, 125 insertions, 55 deletions
diff --git a/src/corelib/kernel/qvariant.cpp b/src/corelib/kernel/qvariant.cpp index 705cae6cf4..762a761026 100644 --- a/src/corelib/kernel/qvariant.cpp +++ b/src/corelib/kernel/qvariant.cpp @@ -2577,8 +2577,8 @@ void QVariant::save(QDataStream &s) const } else if (typeId >= QMetaType::QKeySequence && typeId <= QMetaType::QQuaternion) { // and as a result these types received lower ids too typeId +=1; - } else if (typeId == QMetaType::QPolygonF) { - // This existed in Qt 4 only as a custom type + } else if (typeId == QMetaType::QPolygonF || typeId == QMetaType::QUuid) { + // These existed in Qt 4 only as a custom type typeId = 127; fakeUserType = true; } diff --git a/src/corelib/time/qdatetimeparser.cpp b/src/corelib/time/qdatetimeparser.cpp index 70d6f280bf..2501bbaab7 100644 --- a/src/corelib/time/qdatetimeparser.cpp +++ b/src/corelib/time/qdatetimeparser.cpp @@ -369,13 +369,6 @@ static QString unquote(const QStringRef &str) } return ret; } -/*! - \internal - - Parses the format \a newFormat. If successful, returns \c true and - sets up the format. Else keeps the old format and returns \c false. - -*/ static inline int countRepeat(const QString &str, int index, int maxCount) { @@ -394,7 +387,12 @@ static inline void appendSeparator(QStringList *list, const QString &string, int list->append(lastQuote >= from ? unquote(separator) : separator.toString()); } +/*! + \internal + Parses the format \a newFormat. If successful, returns \c true and sets up + the format. Else keeps the old format and returns \c false. +*/ bool QDateTimeParser::parseFormat(const QString &newFormat) { const QLatin1Char quote('\''); diff --git a/src/corelib/time/qtimezoneprivate_mac.mm b/src/corelib/time/qtimezoneprivate_mac.mm index 4509e316f9..1fb48a31d3 100644 --- a/src/corelib/time/qtimezoneprivate_mac.mm +++ b/src/corelib/time/qtimezoneprivate_mac.mm @@ -60,22 +60,24 @@ QT_BEGIN_NAMESPACE // Create the system default time zone QMacTimeZonePrivate::QMacTimeZonePrivate() - : m_nstz(0) { - init(systemTimeZoneId()); + // Reset the cached system tz then instantiate it: + [NSTimeZone resetSystemTimeZone]; + m_nstz = [NSTimeZone.systemTimeZone retain]; + Q_ASSERT(m_nstz); + m_id = QString::fromNSString(m_nstz.name).toUtf8(); } // Create a named time zone QMacTimeZonePrivate::QMacTimeZonePrivate(const QByteArray &ianaId) - : m_nstz(0) + : m_nstz(nil) { init(ianaId); } QMacTimeZonePrivate::QMacTimeZonePrivate(const QMacTimeZonePrivate &other) - : QTimeZonePrivate(other), m_nstz(0) + : QTimeZonePrivate(other), m_nstz([other.m_nstz copy]) { - m_nstz = [other.m_nstz copy]; } QMacTimeZonePrivate::~QMacTimeZonePrivate() @@ -109,7 +111,7 @@ void QMacTimeZonePrivate::init(const QByteArray &ianaId) QString QMacTimeZonePrivate::comment() const { - return QString::fromNSString([m_nstz description]); + return QString::fromNSString(m_nstz.description); } QString QMacTimeZonePrivate::displayName(QTimeZone::TimeType timeType, @@ -212,7 +214,7 @@ bool QMacTimeZonePrivate::hasTransitions() const // TODO Not sure what is returned in event of no transitions, assume will be before requested date NSDate *epoch = [NSDate dateWithTimeIntervalSince1970:0]; const NSDate *date = [m_nstz nextDaylightSavingTimeTransitionAfterDate:epoch]; - const bool result = ([date timeIntervalSince1970] > [epoch timeIntervalSince1970]); + const bool result = (date.timeIntervalSince1970 > epoch.timeIntervalSince1970); return result; } @@ -222,7 +224,7 @@ QTimeZonePrivate::Data QMacTimeZonePrivate::nextTransition(qint64 afterMSecsSinc const NSTimeInterval seconds = afterMSecsSinceEpoch / 1000.0; NSDate *nextDate = [NSDate dateWithTimeIntervalSince1970:seconds]; nextDate = [m_nstz nextDaylightSavingTimeTransitionAfterDate:nextDate]; - const NSTimeInterval nextSecs = [nextDate timeIntervalSince1970]; + const NSTimeInterval nextSecs = nextDate.timeIntervalSince1970; if (nextDate == nil || nextSecs <= seconds) { [nextDate release]; return invalidData(); @@ -248,7 +250,7 @@ QTimeZonePrivate::Data QMacTimeZonePrivate::previousTransition(qint64 beforeMSec NSDate *nextDate = [NSDate dateWithTimeIntervalSince1970:nextSecs]; nextDate = [m_nstz nextDaylightSavingTimeTransitionAfterDate:nextDate]; if (nextDate != nil - && (tranSecs = [nextDate timeIntervalSince1970]) < endSecs) { + && (tranSecs = nextDate.timeIntervalSince1970) < endSecs) { // There's a transition within the last year before endSecs: nextSecs = tranSecs; } else { @@ -257,7 +259,7 @@ QTimeZonePrivate::Data QMacTimeZonePrivate::previousTransition(qint64 beforeMSec nextDate = [m_nstz nextDaylightSavingTimeTransitionAfterDate:nextDate]; if (nextDate != nil) { NSTimeInterval lateSecs = nextSecs; - nextSecs = [nextDate timeIntervalSince1970]; + nextSecs = nextDate.timeIntervalSince1970; Q_ASSERT(nextSecs <= endSecs - year || nextSecs == tranSecs); /* We're looking at the first ever transition for our zone, at @@ -283,8 +285,7 @@ QTimeZonePrivate::Data QMacTimeZonePrivate::previousTransition(qint64 beforeMSec NSTimeInterval middle = nextSecs / 2 + lateSecs / 2; NSDate *split = [NSDate dateWithTimeIntervalSince1970:middle]; split = [m_nstz nextDaylightSavingTimeTransitionAfterDate:split]; - if (split != nil - && (tranSecs = [split timeIntervalSince1970]) < endSecs) { + if (split != nil && (tranSecs = split.timeIntervalSince1970) < endSecs) { nextDate = split; nextSecs = tranSecs; } else { @@ -301,7 +302,7 @@ QTimeZonePrivate::Data QMacTimeZonePrivate::previousTransition(qint64 beforeMSec while (nextDate != nil && nextSecs < endSecs) { prevSecs = nextSecs; nextDate = [m_nstz nextDaylightSavingTimeTransitionAfterDate:nextDate]; - nextSecs = [nextDate timeIntervalSince1970]; + nextSecs = nextDate.timeIntervalSince1970; if (nextSecs <= prevSecs) // presumably no later data available break; } @@ -316,18 +317,19 @@ QByteArray QMacTimeZonePrivate::systemTimeZoneId() const { // Reset the cached system tz then return the name [NSTimeZone resetSystemTimeZone]; - return QString::fromNSString([[NSTimeZone systemTimeZone] name]).toUtf8(); + Q_ASSERT(NSTimeZone.systemTimeZone); + return QString::fromNSString(NSTimeZone.systemTimeZone.name).toUtf8(); } QList<QByteArray> QMacTimeZonePrivate::availableTimeZoneIds() const { - NSEnumerator *enumerator = [[NSTimeZone knownTimeZoneNames] objectEnumerator]; - QByteArray tzid = QString::fromNSString([enumerator nextObject]).toUtf8(); + NSEnumerator *enumerator = NSTimeZone.knownTimeZoneNames.objectEnumerator; + QByteArray tzid = QString::fromNSString(enumerator.nextObject).toUtf8(); QList<QByteArray> list; while (!tzid.isEmpty()) { list << tzid; - tzid = QString::fromNSString([enumerator nextObject]).toUtf8(); + tzid = QString::fromNSString(enumerator.nextObject).toUtf8(); } std::sort(list.begin(), list.end()); diff --git a/src/gui/rhi/qrhi_p.h b/src/gui/rhi/qrhi_p.h index 9df2c58962..6fb9c44ae6 100644 --- a/src/gui/rhi/qrhi_p.h +++ b/src/gui/rhi/qrhi_p.h @@ -246,10 +246,6 @@ public: m_bindings.clear(); std::copy(first, last, std::back_inserter(m_bindings)); } - void setBindings(const QVector<QRhiVertexInputBinding> &bindings) // compat., to be removed - { - setBindings(bindings.cbegin(), bindings.cend()); - } const QRhiVertexInputBinding *cbeginBindings() const { return m_bindings.cbegin(); } const QRhiVertexInputBinding *cendBindings() const { return m_bindings.cend(); } const QRhiVertexInputBinding *bindingAt(int index) const { return &m_bindings.at(index); } @@ -261,10 +257,6 @@ public: m_attributes.clear(); std::copy(first, last, std::back_inserter(m_attributes)); } - void setAttributes(const QVector<QRhiVertexInputAttribute> &attributes) // compat., to be removed - { - setAttributes(attributes.cbegin(), attributes.cend()); - } const QRhiVertexInputAttribute *cbeginAttributes() const { return m_attributes.cbegin(); } const QRhiVertexInputAttribute *cendAttributes() const { return m_attributes.cend(); } @@ -551,9 +543,6 @@ public: QRhiTextureUploadDescription() = default; QRhiTextureUploadDescription(const QRhiTextureUploadEntry &entry); QRhiTextureUploadDescription(std::initializer_list<QRhiTextureUploadEntry> list); - QRhiTextureUploadDescription(const QVector<QRhiTextureUploadEntry> &entries) // compat., to be removed - : m_entries(entries.cbegin(), entries.cend()) - { } void setEntries(std::initializer_list<QRhiTextureUploadEntry> list) { m_entries = list; } template<typename InputIterator> @@ -978,11 +967,6 @@ public: std::copy(first, last, std::back_inserter(m_bindings)); } - void setBindings(const QVector<QRhiShaderResourceBinding> &bindings) // compat., to be removed - { - setBindings(bindings.cbegin(), bindings.cend()); - } - const QRhiShaderResourceBinding *cbeginBindings() const { return m_bindings.cbegin(); } const QRhiShaderResourceBinding *cendBindings() const { return m_bindings.cend(); } @@ -1171,10 +1155,6 @@ public: m_shaderStages.clear(); std::copy(first, last, std::back_inserter(m_shaderStages)); } - void setShaderStages(const QVector<QRhiShaderStage> &stages) // compat., to be removed - { - setShaderStages(stages.cbegin(), stages.cend()); - } const QRhiShaderStage *cbeginShaderStages() const { return m_shaderStages.cbegin(); } const QRhiShaderStage *cendShaderStages() const { return m_shaderStages.cend(); } diff --git a/src/gui/text/qcssparser.cpp b/src/gui/text/qcssparser.cpp index cf3d8e5ea2..c0b0071e4d 100644 --- a/src/gui/text/qcssparser.cpp +++ b/src/gui/text/qcssparser.cpp @@ -444,6 +444,7 @@ void ValueExtractor::lengthValues(const Declaration &decl, int *m) { if (decl.d->parsed.isValid()) { QList<QVariant> v = decl.d->parsed.toList(); + Q_ASSERT(v.size() == 4); for (int i = 0; i < 4; i++) m[i] = lengthValueFromData(qvariant_cast<LengthData>(v.at(i)), f); return; diff --git a/src/gui/text/qcssparser_p.h b/src/gui/text/qcssparser_p.h index b8bf259dda..ef5ae8c80b 100644 --- a/src/gui/text/qcssparser_p.h +++ b/src/gui/text/qcssparser_p.h @@ -858,13 +858,13 @@ struct Q_GUI_EXPORT ValueExtractor bool extractImage(QIcon *icon, Qt::Alignment *a, QSize *size); bool extractIcon(QIcon *icon, QSize *size); - int lengthValue(const Declaration &decl); + void lengthValues(const Declaration &decl, int *m); private: void extractFont(); void borderValue(const Declaration &decl, int *width, QCss::BorderStyle *style, QBrush *color); LengthData lengthValue(const Value& v); - void lengthValues(const Declaration &decl, int *m); + int lengthValue(const Declaration &decl); QSize sizeValue(const Declaration &decl); void sizeValues(const Declaration &decl, QSize *radii); diff --git a/src/gui/text/qtexthtmlparser.cpp b/src/gui/text/qtexthtmlparser.cpp index 5d37982a8b..b867f42480 100644 --- a/src/gui/text/qtexthtmlparser.cpp +++ b/src/gui/text/qtexthtmlparser.cpp @@ -1209,8 +1209,11 @@ void QTextHtmlParserNode::applyCssDeclarations(const QVector<QCss::Declaration> if (decl.styleValue() != QCss::BorderStyle_Unknown && decl.styleValue() != QCss::BorderStyle_Native) borderStyle = static_cast<QTextFrameFormat::BorderStyle>(decl.styleValue() - 1); break; - case QCss::BorderWidth: - tableBorder = extractor.lengthValue(decl); + case QCss::BorderWidth: { + int borders[4]; + extractor.lengthValues(decl, borders); + tableBorder = borders[0]; + } break; case QCss::BorderCollapse: borderCollapse = decl.borderCollapseValue(); diff --git a/src/opengl/qgl.cpp b/src/opengl/qgl.cpp index 618f6801de..4108b70094 100644 --- a/src/opengl/qgl.cpp +++ b/src/opengl/qgl.cpp @@ -4963,7 +4963,7 @@ void QGLWidget::renderText(double x, double y, double z, const QString &str, con // The only option in Qt 5 is the shader-based OpenGL 2 paint engine. // Setting fixed pipeline transformations is futile. Instead, pass the // extra values directly and let the engine figure the matrices out. - static_cast<QGL2PaintEngineEx *>(p->paintEngine())->setTranslateZ(-win_z); + static_cast<QGL2PaintEngineEx *>(p->paintEngine())->setTranslateZ(-2 * win_z); qt_gl_draw_text(p, qRound(win_x), qRound(win_y), str, font); diff --git a/src/plugins/platforms/wasm/qwasmopenglcontext.cpp b/src/plugins/platforms/wasm/qwasmopenglcontext.cpp index 62087f54bd..0532b7e726 100644 --- a/src/plugins/platforms/wasm/qwasmopenglcontext.cpp +++ b/src/plugins/platforms/wasm/qwasmopenglcontext.cpp @@ -30,6 +30,7 @@ #include "qwasmopenglcontext.h" #include "qwasmintegration.h" #include <EGL/egl.h> +#include <emscripten/val.h> QT_BEGIN_NAMESPACE @@ -50,7 +51,13 @@ QWasmOpenGLContext::QWasmOpenGLContext(const QSurfaceFormat &format) QWasmOpenGLContext::~QWasmOpenGLContext() { if (m_context) { + // Destroy GL context. Work around bug in emscripten_webgl_destroy_context + // which removes all event handlers on the canvas by temporarily removing + // emscripten's JSEvents global object. + emscripten::val jsEvents = emscripten::val::global("window")["JSEvents"]; + emscripten::val::global("window").set("JSEvents", emscripten::val::undefined()); emscripten_webgl_destroy_context(m_context); + emscripten::val::global("window").set("JSEvents", jsEvents); m_context = 0; } } diff --git a/src/plugins/styles/mac/qmacstyle_mac.mm b/src/plugins/styles/mac/qmacstyle_mac.mm index 3c97db44ad..93d2681fd8 100644 --- a/src/plugins/styles/mac/qmacstyle_mac.mm +++ b/src/plugins/styles/mac/qmacstyle_mac.mm @@ -1748,16 +1748,16 @@ QRectF QMacStylePrivate::comboboxEditBounds(const QRectF &outerBounds, const Coc if (cw.type == ComboBox) { switch (cw.size) { case QStyleHelper::SizeLarge: - ret = ret.adjusted(0, 0, -28, 0).translated(3, 4.5); + ret = ret.adjusted(0, 0, -25, 0).translated(2, 4.5); ret.setHeight(16); break; case QStyleHelper::SizeSmall: - ret = ret.adjusted(0, 0, -24, 0).translated(3, 2); + ret = ret.adjusted(0, 0, -22, 0).translated(2, 3); ret.setHeight(14); break; case QStyleHelper::SizeMini: - ret = ret.adjusted(0, 0, -21, 0).translated(2, 3); - ret.setHeight(11); + ret = ret.adjusted(0, 0, -19, 0).translated(2, 2.5); + ret.setHeight(10.5); break; default: break; diff --git a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp index 074cb07092..9e0881f1a6 100644 --- a/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp +++ b/tests/auto/corelib/kernel/qvariant/tst_qvariant.cpp @@ -278,6 +278,7 @@ private slots: void accessSequentialContainerKey(); void fromStdVariant(); + void qt4UuidDataStream(); private: void dataStream_data(QDataStream::Version version); @@ -5025,5 +5026,24 @@ void tst_QVariant::fromStdVariant() #endif } +void tst_QVariant::qt4UuidDataStream() +{ + qRegisterMetaTypeStreamOperators<QUuid>(); + + QByteArray data; + QDataStream stream(&data, QIODevice::WriteOnly); + stream.setVersion(QDataStream::Qt_4_8); + QUuid source(0x12345678,0x1234,0x1234,0x12,0x23,0x34,0x45,0x56,0x67,0x78,0x89); + stream << QVariant::fromValue(source); + const QByteArray qt4Data = QByteArray::fromHex("0000007f000000000651557569640012345678123412341223344556677889"); + QCOMPARE(data, qt4Data); + + QDataStream input(&data, QIODevice::ReadOnly); + input.setVersion(QDataStream::Qt_4_8); + QVariant result; + input >> result; + QCOMPARE(result.value<QUuid>(), source); +} + QTEST_MAIN(tst_QVariant) #include "tst_qvariant.moc" diff --git a/tests/auto/gui/kernel/qguivariant/test/tst_qguivariant.cpp b/tests/auto/gui/kernel/qguivariant/test/tst_qguivariant.cpp index a057ec2207..0b9fc3c9ae 100644 --- a/tests/auto/gui/kernel/qguivariant/test/tst_qguivariant.cpp +++ b/tests/auto/gui/kernel/qguivariant/test/tst_qguivariant.cpp @@ -113,6 +113,7 @@ private slots: void guiVariantAtExit(); void iconEquality(); + void qt4QPolygonFDataStream(); }; void tst_QGuiVariant::constructor_invalid_data() @@ -783,5 +784,25 @@ void tst_QGuiVariant::iconEquality() QVERIFY(a != b); } +void tst_QGuiVariant::qt4QPolygonFDataStream() +{ + qRegisterMetaTypeStreamOperators<QPolygonF>(); + + QByteArray data; + QDataStream stream(&data, QIODevice::WriteOnly); + stream.setVersion(QDataStream::Qt_4_8); + QPolygonF polygon; + polygon.append(QPointF(2, 3)); + stream << QVariant::fromValue(polygon); + const QByteArray qt4Data = QByteArray::fromHex("0000007f000000000a51506f6c79676f6e46000000000140000000000000004008000000000000"); + QCOMPARE(data, qt4Data); + + QDataStream input(&data, QIODevice::ReadOnly); + input.setVersion(QDataStream::Qt_4_8); + QVariant result; + input >> result; + QCOMPARE(result.value<QPolygonF>(), polygon); +} + QTEST_MAIN(tst_QGuiVariant) #include "tst_qguivariant.moc" diff --git a/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp b/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp index b6917f1208..2f5936cf74 100644 --- a/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp +++ b/tests/auto/gui/text/qtextdocumentfragment/tst_qtextdocumentfragment.cpp @@ -182,6 +182,8 @@ private slots: void css_bodyBackground(); void css_tableCellBackground(); void css_tableCellBorder(); + void css_tableCellBorderWidthOneValue(); + void css_tableCellBorderWidthTwoValues(); void css_tableCellBorderShorthand(); void css_tableCellAllBordersShorthand(); void css_tableCellOverrideOneBorder(); @@ -1787,6 +1789,42 @@ void tst_QTextDocumentFragment::css_tableCellBorder() QCOMPARE(cellFormat.topBorderStyle(), QTextFrameFormat::BorderStyle_Groove); } +void tst_QTextDocumentFragment::css_tableCellBorderWidthOneValue() // QTBUG-80496 +{ + const char html[] = "<head><style type=\"text/css\"> body, td { border-width: 2px; }</style></head> <body> <table> <tr> <td></td> </tr> </table> </body> </html>"; + doc->setHtml(html); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + + QTextTableCell cell = table->cellAt(0, 0); + QTextTableCellFormat cellFormat = cell.format().toTableCellFormat(); + QCOMPARE(cellFormat.leftBorder(), qreal(2)); + QCOMPARE(cellFormat.rightBorder(), qreal(2)); + QCOMPARE(cellFormat.bottomBorder(), qreal(2)); + QCOMPARE(cellFormat.topBorder(), qreal(2)); +} + +void tst_QTextDocumentFragment::css_tableCellBorderWidthTwoValues() // QTBUG-80496 +{ + const char html[] = "<head><style type=\"text/css\"> body, td { border-width: 2px 3px; }</style></head> <body> <table> <tr> <td></td> </tr> </table> </body> </html>"; + doc->setHtml(html); + + cursor.movePosition(QTextCursor::Start); + cursor.movePosition(QTextCursor::NextBlock); + QTextTable *table = cursor.currentTable(); + QVERIFY(table); + + QTextTableCell cell = table->cellAt(0, 0); + QTextTableCellFormat cellFormat = cell.format().toTableCellFormat(); + QCOMPARE(cellFormat.leftBorder(), qreal(3)); + QCOMPARE(cellFormat.rightBorder(), qreal(3)); + QCOMPARE(cellFormat.bottomBorder(), qreal(2)); + QCOMPARE(cellFormat.topBorder(), qreal(2)); +} + void tst_QTextDocumentFragment::css_tableCellBorderShorthand() { const char html[] = "<body><table><tr><td style=\"border-left:1px solid green;border-right:2px dashed red;border-bottom:3px dotted yellow;border-top:4px dot-dash blue\">Foo</td></tr></table></body>"; |