service/NativeMailDocument.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | #include "NativeMailDocument.h" | ||
| 2 | #include "util/CanonicalContentId.h" | ||
| 3 | #include <QSet> | ||
| 4 | #include <QMap> | ||
| 5 | #include <QStringList> | ||
| 6 | #include <QUrl> | ||
| 7 | #include <QVector> | ||
| 8 | #include <array> | ||
| 9 | #include <functional> | ||
| 10 | #include <QColor> | ||
| 11 | #include <QHash> | ||
| 12 | #include <QRegularExpression> | ||
| 13 | #include <libxml/HTMLparser.h> | ||
| 14 | |||
| 15 | namespace { | ||
| 16 | struct Node { | ||
| 17 | QString tag, text, href, direction, contentId, style; | ||
| 18 | QUrl remoteUrl; | ||
| 19 | QByteArray imageData; // Compose: a decoded data: image | ||
| 20 | QString imageType; | ||
| 21 | int imageWidth = 0, imageHeight = 0; | ||
| 22 | int region = 0; // Compose: 1 signature, 2 quote (MailJD's markers) | ||
| 23 | int columns = 1, rows = 1; | ||
| 24 | QVector<int> children; | ||
| 25 | }; | ||
| 26 | struct Frame { | ||
| 27 | int node = 0; | ||
| 28 | bool suppressed = false; | ||
| 29 | }; | ||
| 30 | struct State { | ||
| 31 | htmlParserCtxtPtr parser = nullptr; | ||
| 32 | QVector<Node> nodes{Node{}}; | ||
| 33 | QVector<Frame> stack{Frame{}}; | ||
| 34 | bool limited = false, simplified = false, wasCancelled = false; | ||
| 35 | bool compose = false, wordHtml = false; | ||
| 36 | const std::atomic_bool *cancelled = nullptr; | ||
| 37 | 115894 | bool interrupted() { | |
| 38 |
6/6✓ Branch 2 → 3 taken 59457 times.
✓ Branch 2 → 6 taken 56437 times.
✓ Branch 4 → 5 taken 2 times.
✓ Branch 4 → 6 taken 59455 times.
✓ Branch 7 → 8 taken 2 times.
✓ Branch 7 → 10 taken 115892 times.
|
115894 | if (cancelled && cancelled->load(std::memory_order_relaxed)) { |
| 39 | 2 | wasCancelled = true; | |
| 40 |
1/2✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 2 times.
|
2 | if (parser) |
| 41 | ✗ | xmlStopParser(parser); | |
| 42 | } | ||
| 43 |
4/4✓ Branch 10 → 11 taken 115890 times.
✓ Branch 10 → 12 taken 4 times.
✓ Branch 11 → 12 taken 2 times.
✓ Branch 11 → 13 taken 115888 times.
|
115894 | return limited || wasCancelled; |
| 44 | } | ||
| 45 | int deniedEntities = 0; | ||
| 46 | qsizetype textCharacters = 0; | ||
| 47 | 3 | void stop() { | |
| 48 | 3 | limited = true; | |
| 49 |
1/2✓ Branch 2 → 3 taken 3 times.
✗ Branch 2 → 4 not taken.
|
3 | if (parser) |
| 50 | 3 | xmlStopParser(parser); | |
| 51 | 3 | } | |
| 52 | 32596 | void appendText(const QString &text) { | |
| 53 |
8/10✓ Branch 2 → 3 taken 32596 times.
✓ Branch 3 → 4 taken 32596 times.
✗ Branch 3 → 8 not taken.
✓ Branch 4 → 5 taken 32596 times.
✓ Branch 5 → 6 taken 32545 times.
✓ Branch 5 → 8 taken 51 times.
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 32545 times.
✓ Branch 10 → 11 taken 51 times.
✓ Branch 10 → 12 taken 32545 times.
|
32596 | if (interrupted() || stack.last().suppressed || text.isEmpty()) |
| 54 | 457 | return; | |
| 55 | 32545 | textCharacters += text.size(); | |
| 56 |
1/2✗ Branch 13 → 14 not taken.
✓ Branch 13 → 16 taken 32545 times.
|
32545 | if (textCharacters > 1024 * 1024) { |
| 57 | ✗ | stop(); | |
| 58 | ✗ | return; | |
| 59 | } | ||
| 60 |
1/1✓ Branch 16 → 17 taken 32545 times.
|
32545 | const int parent = stack.last().node; |
| 61 |
3/3✓ Branch 17 → 18 taken 32545 times.
✓ Branch 19 → 20 taken 10483 times.
✓ Branch 19 → 28 taken 22062 times.
|
32545 | if (!nodes[parent].children.isEmpty()) { |
| 62 |
2/2✓ Branch 20 → 21 taken 10483 times.
✓ Branch 21 → 22 taken 10483 times.
|
10483 | const int last = nodes[parent].children.last(); |
| 63 |
3/3✓ Branch 22 → 23 taken 10483 times.
✓ Branch 24 → 25 taken 405 times.
✓ Branch 24 → 28 taken 10078 times.
|
10483 | if (nodes[last].tag.isEmpty()) { |
| 64 |
2/2✓ Branch 25 → 26 taken 405 times.
✓ Branch 26 → 27 taken 405 times.
|
405 | nodes[last].text += text; |
| 65 | 405 | return; | |
| 66 | } | ||
| 67 | } | ||
| 68 |
2/2✓ Branch 29 → 30 taken 1 time.
✓ Branch 29 → 32 taken 32139 times.
|
32140 | if (nodes.size() >= NativeMailDocument::MaxNodes) { |
| 69 |
1/1✓ Branch 30 → 31 taken 1 time.
|
1 | stop(); |
| 70 | 1 | return; | |
| 71 | } | ||
| 72 | 32139 | const int next = nodes.size(); | |
| 73 |
2/2✓ Branch 33 → 34 taken 32139 times.
✓ Branch 34 → 35 taken 32139 times.
|
32139 | nodes[parent].children.append(next); |
| 74 |
1/1✓ Branch 35 → 36 taken 32139 times.
|
32139 | Node node; |
| 75 | 32139 | node.text = text; | |
| 76 |
1/1✓ Branch 37 → 38 taken 32139 times.
|
32139 | nodes.append(node); |
| 77 | 32139 | } | |
| 78 | }; | ||
| 79 | 84276 | QString attribute(const xmlChar **attributes, const char *name) { | |
| 80 |
2/2✓ Branch 2 → 3 taken 60431 times.
✓ Branch 2 → 4 taken 23845 times.
|
84276 | if (!attributes) |
| 81 | 60431 | return {}; | |
| 82 |
3/4✓ Branch 12 → 13 taken 24503 times.
✓ Branch 12 → 14 taken 17258 times.
✓ Branch 13 → 5 taken 24503 times.
✗ Branch 13 → 14 not taken.
|
41761 | for (int i = 0; attributes[i] && attributes[i + 1]; i += 2) |
| 83 |
2/2✓ Branch 6 → 7 taken 6587 times.
✓ Branch 6 → 11 taken 17916 times.
|
24503 | if (qstrcmp(reinterpret_cast<const char *>(attributes[i]), name) == 0) |
| 84 |
1/1✓ Branch 8 → 9 taken 6587 times.
|
6587 | return QString::fromUtf8(reinterpret_cast<const char *>(attributes[i + 1])); |
| 85 | 17258 | return {}; | |
| 86 | } | ||
| 87 | // Sprint 108 (D-9) composer styles: canonical values only — no functions | ||
| 88 | // other than rgb()/rgba(), no URLs, no escapes. | ||
| 89 | 56 | QString composeColor(const QString &value) { | |
| 90 |
4/7✓ Branch 2 → 3 taken 3 times.
✓ Branch 2 → 15 taken 53 times.
✓ Branch 4 → 5 taken 3 times.
✗ Branch 4 → 15 not taken.
✓ Branch 9 → 10 taken 3 times.
✗ Branch 121 → 122 not taken.
✗ Branch 121 → 123 not taken.
|
59 | static const QRegularExpression hex(QStringLiteral("^#([0-9a-f]{3}|[0-9a-f]{6})$")); |
| 91 | 6 | static const QRegularExpression rgb(QStringLiteral( | |
| 92 |
4/7✓ Branch 15 → 16 taken 3 times.
✓ Branch 15 → 28 taken 53 times.
✓ Branch 17 → 18 taken 3 times.
✗ Branch 17 → 28 not taken.
✓ Branch 22 → 23 taken 3 times.
✗ Branch 131 → 132 not taken.
✗ Branch 131 → 133 not taken.
|
62 | "^rgba?\\(\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*,\\s*(\\d{1,3})\\s*(?:,\\s*([0-9.]{1,6})\\s*)?\\)$")); |
| 93 |
4/7✓ Branch 28 → 29 taken 3 times.
✓ Branch 28 → 41 taken 53 times.
✓ Branch 30 → 31 taken 3 times.
✗ Branch 30 → 41 not taken.
✓ Branch 35 → 36 taken 3 times.
✗ Branch 141 → 142 not taken.
✗ Branch 141 → 143 not taken.
|
59 | static const QRegularExpression name(QStringLiteral("^[a-z]{3,20}$")); |
| 94 |
5/5✓ Branch 42 → 43 taken 56 times.
✓ Branch 43 → 44 taken 56 times.
✓ Branch 45 → 46 taken 43 times.
✓ Branch 45 → 50 taken 13 times.
✓ Branch 47 → 48 taken 43 times.
|
56 | if (hex.match(value).hasMatch()) return QColor(value).name(); |
| 95 |
1/1✓ Branch 51 → 52 taken 13 times.
|
13 | const auto match = rgb.match(value); |
| 96 |
3/3✓ Branch 52 → 53 taken 13 times.
✓ Branch 53 → 54 taken 3 times.
✓ Branch 53 → 84 taken 10 times.
|
13 | if (match.hasMatch()) { |
| 97 |
5/17✓ Branch 54 → 55 taken 3 times.
✗ Branch 56 → 57 not taken.
✓ Branch 56 → 61 taken 3 times.
✗ Branch 57 → 58 not taken.
✗ Branch 58 → 59 not taken.
✗ Branch 59 → 60 not taken.
✗ Branch 59 → 61 not taken.
✗ Branch 62 → 63 not taken.
✓ Branch 62 → 64 taken 3 times.
✓ Branch 64 → 65 taken 3 times.
✗ Branch 64 → 66 not taken.
✗ Branch 66 → 67 not taken.
✓ Branch 66 → 68 taken 3 times.
✗ Branch 150 → 151 not taken.
✗ Branch 150 → 152 not taken.
✗ Branch 154 → 155 not taken.
✗ Branch 154 → 156 not taken.
|
3 | if (!match.captured(4).isEmpty() && match.captured(4).toDouble() < 0.1) return {}; |
| 98 |
2/2✓ Branch 72 → 73 taken 3 times.
✓ Branch 75 → 76 taken 3 times.
|
9 | return QColor(qMin(255, match.captured(1).toInt()), qMin(255, match.captured(2).toInt()), |
| 99 |
5/5✓ Branch 68 → 69 taken 3 times.
✓ Branch 69 → 70 taken 3 times.
✓ Branch 71 → 72 taken 3 times.
✓ Branch 74 → 75 taken 3 times.
✓ Branch 78 → 79 taken 3 times.
|
12 | qMin(255, match.captured(3).toInt())).name(); |
| 100 | } | ||
| 101 |
4/7✓ Branch 85 → 86 taken 10 times.
✓ Branch 90 → 91 taken 8 times.
✗ Branch 90 → 101 not taken.
✓ Branch 104 → 105 taken 7 times.
✓ Branch 104 → 110 taken 3 times.
✗ Branch 178 → 179 not taken.
✗ Branch 178 → 180 not taken.
|
28 | if (name.match(value).hasMatch() && value != QLatin1String("transparent") && |
| 102 |
8/11✓ Branch 86 → 87 taken 10 times.
✓ Branch 87 → 88 taken 8 times.
✓ Branch 87 → 101 taken 2 times.
✓ Branch 93 → 94 taken 8 times.
✗ Branch 93 → 101 not taken.
✓ Branch 96 → 97 taken 8 times.
✗ Branch 96 → 101 not taken.
✓ Branch 99 → 100 taken 7 times.
✓ Branch 99 → 101 taken 1 time.
✓ Branch 102 → 103 taken 10 times.
✗ Branch 102 → 104 not taken.
|
28 | value != QLatin1String("inherit") && value != QLatin1String("initial") && QColor::isValidColorName(value)) |
| 103 |
1/1✓ Branch 107 → 108 taken 7 times.
|
7 | return QColor::fromString(value).name(); |
| 104 | 3 | return {}; | |
| 105 | 13 | } | |
| 106 | // A CSS length as whole pixels (px, pt, em at 16 px); -1 for anything else. | ||
| 107 | 370 | int composeLengthPixels(const QString &value) { | |
| 108 |
4/7✓ Branch 2 → 3 taken 8 times.
✓ Branch 2 → 15 taken 362 times.
✓ Branch 4 → 5 taken 8 times.
✗ Branch 4 → 15 not taken.
✓ Branch 9 → 10 taken 8 times.
✗ Branch 51 → 52 not taken.
✗ Branch 51 → 53 not taken.
|
378 | static const QRegularExpression length(QStringLiteral("^(-?[0-9]{1,4}(?:\\.[0-9]{1,3})?)(px|pt|em|rem)?$")); |
| 109 |
1/1✓ Branch 16 → 17 taken 370 times.
|
370 | const auto match = length.match(value); |
| 110 |
3/3✓ Branch 17 → 18 taken 370 times.
✓ Branch 18 → 19 taken 21 times.
✓ Branch 18 → 20 taken 349 times.
|
370 | if (!match.hasMatch()) return -1; |
| 111 |
2/2✓ Branch 20 → 21 taken 349 times.
✓ Branch 21 → 22 taken 349 times.
|
349 | const double number = match.captured(1).toDouble(); |
| 112 |
1/1✓ Branch 23 → 24 taken 349 times.
|
349 | const QString unit = match.captured(2); |
| 113 |
2/2✓ Branch 26 → 27 taken 4 times.
✓ Branch 26 → 28 taken 345 times.
|
694 | const double pixels = unit == QLatin1String("pt") ? number * 4.0 / 3.0 |
| 114 |
3/4✓ Branch 30 → 31 taken 337 times.
✓ Branch 30 → 34 taken 8 times.
✗ Branch 33 → 34 not taken.
✓ Branch 33 → 35 taken 337 times.
|
345 | : (unit == QLatin1String("em") || unit == QLatin1String("rem")) ? number * 16.0 |
| 115 | 349 | : number; | |
| 116 | 349 | return qBound(0, qRound(pixels), 400); | |
| 117 | 370 | } | |
| 118 | 34 | QString composeFontSize(const QString &value) { | |
| 119 | ✗ | static const QHash<QString, int> keywords{{"xx-small", 8}, {"x-small", 8}, {"small", 10}, {"medium", 12}, | |
| 120 |
5/10✓ Branch 2 → 3 taken 2 times.
✓ Branch 2 → 19 taken 32 times.
✓ Branch 4 → 5 taken 2 times.
✗ Branch 4 → 19 not taken.
✓ Branch 16 → 17 taken 14 times.
✓ Branch 16 → 18 taken 2 times.
✗ Branch 80 → 81 not taken.
✗ Branch 80 → 82 not taken.
✗ Branch 96 → 97 not taken.
✗ Branch 96 → 98 not taken.
|
50 | {"large", 14}, {"x-large", 18}, {"xx-large", 24}}; |
| 121 |
4/4✓ Branch 20 → 21 taken 2 times.
✓ Branch 20 → 32 taken 32 times.
✓ Branch 25 → 26 taken 2 times.
✓ Branch 26 → 27 taken 2 times.
|
36 | if (keywords.contains(value)) return QString::number(keywords.value(value)) + QStringLiteral("pt"); |
| 122 |
4/7✓ Branch 32 → 33 taken 2 times.
✓ Branch 32 → 45 taken 30 times.
✓ Branch 34 → 35 taken 2 times.
✗ Branch 34 → 45 not taken.
✓ Branch 39 → 40 taken 2 times.
✗ Branch 115 → 116 not taken.
✗ Branch 115 → 117 not taken.
|
34 | static const QRegularExpression size(QStringLiteral("^([0-9]{1,3}(?:\\.[0-9]{1,2})?)(px|pt|em|rem)$")); |
| 123 |
1/1✓ Branch 46 → 47 taken 32 times.
|
32 | const auto match = size.match(value); |
| 124 |
2/3✓ Branch 47 → 48 taken 32 times.
✗ Branch 48 → 49 not taken.
✓ Branch 48 → 50 taken 32 times.
|
32 | if (!match.hasMatch()) return {}; |
| 125 |
2/2✓ Branch 50 → 51 taken 32 times.
✓ Branch 51 → 52 taken 32 times.
|
32 | const double number = match.captured(1).toDouble(); |
| 126 |
1/1✓ Branch 53 → 54 taken 32 times.
|
32 | const QString unit = match.captured(2); |
| 127 |
2/2✓ Branch 56 → 57 taken 4 times.
✓ Branch 56 → 58 taken 28 times.
|
60 | const double points = unit == QLatin1String("px") ? number * 0.75 |
| 128 |
1/2✓ Branch 60 → 61 taken 28 times.
✗ Branch 60 → 62 not taken.
|
60 | : unit == QLatin1String("pt") ? number : number * 12.0; |
| 129 |
2/2✓ Branch 69 → 70 taken 32 times.
✓ Branch 70 → 71 taken 32 times.
|
32 | return QString::number(qBound(8, qRound(points), 36)) + QStringLiteral("pt"); |
| 130 | 34 | } | |
| 131 | 132 | QString composeFontFamily(const QString &value) { | |
| 132 | // Names only: letters, digits, spaces, commas, quotes and hyphens. The | ||
| 133 | // import maps the list onto the fixed D-6 set. | ||
| 134 |
1/2✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 132 times.
|
132 | if (value.size() > 160) return {}; |
| 135 |
4/7✓ Branch 5 → 6 taken 7 times.
✓ Branch 5 → 18 taken 125 times.
✓ Branch 7 → 8 taken 7 times.
✗ Branch 7 → 18 not taken.
✓ Branch 12 → 13 taken 7 times.
✗ Branch 41 → 42 not taken.
✗ Branch 41 → 43 not taken.
|
139 | static const QRegularExpression families(QStringLiteral("^[a-z0-9 ,'\"-]+$")); |
| 136 |
4/4✓ Branch 19 → 20 taken 132 times.
✓ Branch 20 → 21 taken 132 times.
✓ Branch 22 → 23 taken 1 time.
✓ Branch 22 → 24 taken 131 times.
|
132 | if (!families.match(value).hasMatch()) return {}; |
| 137 | 131 | QString out = value; | |
| 138 |
1/1✓ Branch 29 → 30 taken 131 times.
|
131 | out.replace(QLatin1Char('"'), QLatin1Char('\'')); |
| 139 | 131 | return out; | |
| 140 | 131 | } | |
| 141 | |||
| 142 | 28502 | QString safeInlineStyle(const QString &source, bool &simplified, QString &direction, bool compose = false) { | |
| 143 |
2/2✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 28501 times.
|
28502 | if (source.size() > 2048) { simplified = true; return {}; } |
| 144 | 28501 | QMap<QString, QString> output; | |
| 145 | 28501 | int declarations = 0; | |
| 146 |
5/5✓ Branch 7 → 8 taken 28501 times.
✓ Branch 8 → 9 taken 28501 times.
✓ Branch 9 → 10 taken 28501 times.
✓ Branch 335 → 11 taken 28824 times.
✓ Branch 335 → 336 taken 28500 times.
|
57324 | for (const QString &declaration : source.split(';')) { |
| 147 |
2/2✓ Branch 12 → 13 taken 1 time.
✓ Branch 12 → 14 taken 28823 times.
|
28824 | if (++declarations > 32) { simplified = true; break; } |
| 148 |
3/3✓ Branch 14 → 15 taken 28823 times.
✓ Branch 17 → 18 taken 27800 times.
✓ Branch 17 → 19 taken 1023 times.
|
29100 | if (declaration.trimmed().isEmpty()) continue; |
| 149 | 1023 | const qsizetype colon = declaration.indexOf(':'); | |
| 150 |
2/2✓ Branch 21 → 22 taken 1 time.
✓ Branch 21 → 23 taken 1022 times.
|
1023 | if (colon < 0) { simplified = true; continue; } |
| 151 |
3/3✓ Branch 23 → 24 taken 1022 times.
✓ Branch 24 → 25 taken 1022 times.
✓ Branch 25 → 26 taken 1022 times.
|
1022 | const QString property = declaration.left(colon).trimmed().toLower(); |
| 152 |
3/3✓ Branch 28 → 29 taken 1022 times.
✓ Branch 29 → 30 taken 1022 times.
✓ Branch 30 → 31 taken 1022 times.
|
1022 | QString value = declaration.mid(colon + 1).trimmed().toLower(); |
| 153 | 1022 | bool allowed = false; | |
| 154 |
2/2✓ Branch 34 → 35 taken 28 times.
✓ Branch 34 → 68 taken 994 times.
|
1022 | if (property == "font-weight") { |
| 155 |
7/7✓ Branch 36 → 37 taken 17 times.
✓ Branch 36 → 39 taken 11 times.
✓ Branch 38 → 39 taken 1 time.
✓ Branch 38 → 40 taken 16 times.
✓ Branch 41 → 42 taken 12 times.
✓ Branch 41 → 43 taken 16 times.
✓ Branch 42 → 61 taken 12 times.
|
28 | if (value == "bold" || value == "bolder") value = "bold"; |
| 156 |
7/7✓ Branch 44 → 45 taken 12 times.
✓ Branch 44 → 47 taken 4 times.
✓ Branch 46 → 47 taken 1 time.
✓ Branch 46 → 48 taken 11 times.
✓ Branch 49 → 50 taken 5 times.
✓ Branch 49 → 51 taken 11 times.
✓ Branch 50 → 61 taken 5 times.
|
16 | else if (value == "normal" || value == "lighter") value = "normal"; |
| 157 | else { | ||
| 158 | 11 | bool numeric = false; | |
| 159 |
1/1✓ Branch 51 → 52 taken 11 times.
|
11 | const int weight = value.toInt(&numeric); |
| 160 |
8/8✓ Branch 52 → 53 taken 10 times.
✓ Branch 52 → 60 taken 1 time.
✓ Branch 53 → 54 taken 9 times.
✓ Branch 53 → 60 taken 1 time.
✓ Branch 54 → 55 taken 8 times.
✓ Branch 54 → 60 taken 1 time.
✓ Branch 55 → 56 taken 7 times.
✓ Branch 55 → 60 taken 1 time.
|
11 | if (numeric && weight >= 100 && weight <= 900 && weight % 100 == 0) |
| 161 |
3/3✓ Branch 56 → 57 taken 4 times.
✓ Branch 56 → 58 taken 3 times.
✓ Branch 59 → 60 taken 7 times.
|
7 | value = weight >= 600 ? "bold" : "normal"; |
| 162 | } | ||
| 163 |
4/4✓ Branch 62 → 63 taken 12 times.
✓ Branch 62 → 65 taken 16 times.
✓ Branch 64 → 65 taken 8 times.
✓ Branch 64 → 66 taken 4 times.
|
28 | allowed = value == "bold" || value == "normal"; |
| 164 |
2/2✓ Branch 69 → 70 taken 4 times.
✓ Branch 69 → 79 taken 990 times.
|
994 | } else if (property == "font-style") { |
| 165 |
6/6✓ Branch 71 → 72 taken 3 times.
✓ Branch 71 → 76 taken 1 time.
✓ Branch 73 → 74 taken 2 times.
✓ Branch 73 → 76 taken 1 time.
✓ Branch 75 → 76 taken 1 time.
✓ Branch 75 → 77 taken 1 time.
|
4 | allowed = value == "normal" || value == "italic" || value == "oblique"; |
| 166 |
2/2✓ Branch 80 → 81 taken 8 times.
✓ Branch 80 → 115 taken 982 times.
|
990 | } else if (property == "text-decoration") { |
| 167 |
2/2✓ Branch 81 → 82 taken 8 times.
✓ Branch 84 → 85 taken 8 times.
|
16 | const auto tokens = value.simplified().split(' '); |
| 168 |
3/4✓ Branch 87 → 88 taken 8 times.
✗ Branch 87 → 91 not taken.
✓ Branch 89 → 90 taken 7 times.
✓ Branch 89 → 91 taken 1 time.
|
8 | allowed = !tokens.isEmpty() && tokens.size() <= 3; |
| 169 |
2/2✓ Branch 108 → 94 taken 13 times.
✓ Branch 108 → 109 taken 8 times.
|
21 | for (const auto &token : tokens) |
| 170 |
10/10✓ Branch 95 → 96 taken 9 times.
✓ Branch 95 → 105 taken 4 times.
✓ Branch 97 → 98 taken 7 times.
✓ Branch 97 → 104 taken 2 times.
✓ Branch 99 → 100 taken 6 times.
✓ Branch 99 → 104 taken 1 time.
✓ Branch 101 → 102 taken 5 times.
✓ Branch 101 → 104 taken 1 time.
✓ Branch 103 → 104 taken 3 times.
✓ Branch 103 → 105 taken 2 times.
|
13 | allowed = allowed && (token == "underline" || token == "line-through" || token == "overline" || token == "none"); |
| 171 |
1/1✓ Branch 110 → 111 taken 8 times.
|
8 | value = tokens.join(' '); |
| 172 |
2/2✓ Branch 116 → 117 taken 18 times.
✓ Branch 116 → 128 taken 964 times.
|
990 | } else if (property == "text-align") { |
| 173 |
8/8✓ Branch 118 → 119 taken 17 times.
✓ Branch 118 → 125 taken 1 time.
✓ Branch 120 → 121 taken 11 times.
✓ Branch 120 → 125 taken 6 times.
✓ Branch 122 → 123 taken 4 times.
✓ Branch 122 → 125 taken 7 times.
✓ Branch 124 → 125 taken 3 times.
✓ Branch 124 → 126 taken 1 time.
|
18 | allowed = value == "left" || value == "right" || value == "center" || value == "justify"; |
| 174 |
2/2✓ Branch 129 → 130 taken 2 times.
✓ Branch 129 → 138 taken 962 times.
|
964 | } else if (property == "direction") { |
| 175 |
3/4✓ Branch 131 → 132 taken 1 time.
✓ Branch 131 → 134 taken 1 time.
✗ Branch 133 → 134 not taken.
✓ Branch 133 → 135 taken 1 time.
|
2 | allowed = value == "rtl" || value == "ltr"; |
| 176 |
2/2✓ Branch 136 → 137 taken 1 time.
✓ Branch 136 → 312 taken 1 time.
|
2 | if (allowed) direction = value; |
| 177 |
2/2✓ Branch 139 → 140 taken 4 times.
✓ Branch 139 → 149 taken 958 times.
|
962 | } else if (property == "white-space") { |
| 178 |
6/6✓ Branch 141 → 142 taken 3 times.
✓ Branch 141 → 146 taken 1 time.
✓ Branch 143 → 144 taken 2 times.
✓ Branch 143 → 146 taken 1 time.
✓ Branch 145 → 146 taken 1 time.
✓ Branch 145 → 147 taken 1 time.
|
4 | allowed = value == "normal" || value == "pre" || value == "pre-wrap"; |
| 179 |
10/10✓ Branch 149 → 150 taken 702 times.
✓ Branch 149 → 157 taken 256 times.
✓ Branch 151 → 152 taken 662 times.
✓ Branch 151 → 156 taken 40 times.
✓ Branch 153 → 154 taken 653 times.
✓ Branch 153 → 156 taken 9 times.
✓ Branch 155 → 156 taken 7 times.
✓ Branch 155 → 157 taken 646 times.
✓ Branch 158 → 159 taken 56 times.
✓ Branch 158 → 176 taken 902 times.
|
958 | } else if (compose && (property == "color" || property == "background-color" || property == "background")) { |
| 180 |
1/1✓ Branch 159 → 160 taken 56 times.
|
56 | value = composeColor(value); |
| 181 | 56 | allowed = !value.isEmpty(); | |
| 182 |
6/6✓ Branch 163 → 164 taken 53 times.
✓ Branch 163 → 167 taken 3 times.
✓ Branch 165 → 166 taken 6 times.
✓ Branch 165 → 167 taken 47 times.
✓ Branch 168 → 169 taken 6 times.
✓ Branch 168 → 312 taken 50 times.
|
56 | if (allowed && property == "background") { |
| 183 |
1/1✓ Branch 172 → 173 taken 6 times.
|
6 | output.insert(QStringLiteral("background-color"), value); |
| 184 | 6 | continue; | |
| 185 | } | ||
| 186 |
6/6✓ Branch 176 → 177 taken 646 times.
✓ Branch 176 → 180 taken 256 times.
✓ Branch 178 → 179 taken 34 times.
✓ Branch 178 → 180 taken 612 times.
✓ Branch 181 → 182 taken 34 times.
✓ Branch 181 → 187 taken 868 times.
|
902 | } else if (compose && property == "font-size") { |
| 187 |
1/1✓ Branch 182 → 183 taken 34 times.
|
34 | value = composeFontSize(value); |
| 188 | 34 | allowed = !value.isEmpty(); | |
| 189 |
6/6✓ Branch 187 → 188 taken 612 times.
✓ Branch 187 → 191 taken 256 times.
✓ Branch 189 → 190 taken 132 times.
✓ Branch 189 → 191 taken 480 times.
✓ Branch 192 → 193 taken 132 times.
✓ Branch 192 → 198 taken 736 times.
|
868 | } else if (compose && property == "font-family") { |
| 190 |
1/1✓ Branch 193 → 194 taken 132 times.
|
132 | value = composeFontFamily(value); |
| 191 | 132 | allowed = !value.isEmpty(); | |
| 192 |
7/8✓ Branch 198 → 199 taken 480 times.
✓ Branch 198 → 208 taken 256 times.
✓ Branch 200 → 201 taken 478 times.
✓ Branch 200 → 207 taken 2 times.
✓ Branch 202 → 203 taken 478 times.
✗ Branch 202 → 207 not taken.
✓ Branch 204 → 205 taken 461 times.
✓ Branch 204 → 207 taken 17 times.
|
1675 | } else if (compose && (property == "margin-left" || property == "margin-right" || |
| 193 |
4/4✓ Branch 206 → 207 taken 19 times.
✓ Branch 206 → 208 taken 442 times.
✓ Branch 209 → 210 taken 38 times.
✓ Branch 209 → 222 taken 698 times.
|
1675 | property == "margin-top" || property == "margin-bottom")) { |
| 194 |
1/1✓ Branch 210 → 211 taken 38 times.
|
38 | const int pixels = composeLengthPixels(value); |
| 195 | 38 | allowed = pixels >= 0; | |
| 196 |
2/2✓ Branch 214 → 215 taken 38 times.
✓ Branch 215 → 216 taken 38 times.
|
38 | value = QString::number(pixels) + QStringLiteral("px"); |
| 197 |
6/6✓ Branch 222 → 223 taken 442 times.
✓ Branch 222 → 226 taken 256 times.
✓ Branch 224 → 225 taken 269 times.
✓ Branch 224 → 226 taken 173 times.
✓ Branch 227 → 228 taken 269 times.
✓ Branch 227 → 312 taken 429 times.
|
698 | } else if (compose && property == "margin") { |
| 198 |
2/2✓ Branch 228 → 229 taken 269 times.
✓ Branch 232 → 233 taken 269 times.
|
538 | const QStringList parts = value.simplified().split(QLatin1Char(' ')); |
| 199 |
5/10✓ Branch 234 → 235 taken 8 times.
✓ Branch 234 → 248 taken 261 times.
✓ Branch 236 → 237 taken 8 times.
✗ Branch 236 → 248 not taken.
✓ Branch 245 → 246 taken 32 times.
✓ Branch 245 → 247 taken 8 times.
✗ Branch 409 → 410 not taken.
✗ Branch 409 → 411 not taken.
✗ Branch 418 → 419 not taken.
✗ Branch 418 → 420 not taken.
|
309 | static const QStringList sides{"margin-top", "margin-right", "margin-bottom", "margin-left"}; |
| 200 |
5/10✓ Branch 248 → 249 taken 8 times.
✓ Branch 248 → 262 taken 261 times.
✓ Branch 250 → 251 taken 8 times.
✗ Branch 250 → 262 not taken.
✓ Branch 259 → 260 taken 32 times.
✓ Branch 259 → 261 taken 8 times.
✗ Branch 422 → 423 not taken.
✗ Branch 422 → 424 not taken.
✗ Branch 432 → 433 not taken.
✗ Branch 432 → 434 not taken.
|
309 | static const QList<QList<int>> pick{{0, 0, 0, 0}, {0, 1, 0, 1}, {0, 1, 2, 1}, {0, 1, 2, 3}}; |
| 201 |
3/6✓ Branch 263 → 264 taken 269 times.
✗ Branch 263 → 267 not taken.
✓ Branch 265 → 266 taken 269 times.
✗ Branch 265 → 267 not taken.
✓ Branch 268 → 269 taken 269 times.
✗ Branch 268 → 309 not taken.
|
269 | if (parts.size() >= 1 && parts.size() <= 4) { |
| 202 | 269 | QList<int> pixels; | |
| 203 |
5/7✗ Branch 273 → 274 not taken.
✓ Branch 273 → 275 taken 332 times.
✗ Branch 274 → 276 not taken.
✓ Branch 276 → 277 taken 332 times.
✓ Branch 277 → 278 taken 332 times.
✓ Branch 281 → 271 taken 332 times.
✓ Branch 281 → 282 taken 269 times.
|
601 | for (const QString &part : parts) pixels.append(composeLengthPixels(part == "auto" ? "0" : part)); |
| 204 |
2/2✓ Branch 283 → 284 taken 256 times.
✓ Branch 283 → 303 taken 13 times.
|
269 | if (!pixels.contains(-1)) { |
| 205 |
2/2✓ Branch 301 → 285 taken 1024 times.
✓ Branch 301 → 302 taken 256 times.
|
1280 | for (int side = 0; side < 4; ++side) |
| 206 |
4/4✓ Branch 291 → 292 taken 1024 times.
✓ Branch 292 → 293 taken 1024 times.
✓ Branch 293 → 294 taken 1024 times.
✓ Branch 295 → 296 taken 1024 times.
|
1024 | output.insert(sides[side], QString::number(pixels[pick[parts.size() - 1][side]]) + QStringLiteral("px")); |
| 207 | 256 | continue; | |
| 208 | 256 | } | |
| 209 | 269 | } | |
| 210 | 13 | simplified = true; | |
| 211 | 13 | continue; | |
| 212 | 269 | } | |
| 213 | // Authored colors/fonts/sizes/backgrounds remain theme-native and bounded. | ||
| 214 | // Only canonical keywords are serialized; CSS URLs/functions/escapes and | ||
| 215 | // arbitrary strings never become renderer capabilities. | ||
| 216 |
7/7✓ Branch 312 → 313 taken 295 times.
✓ Branch 312 → 316 taken 452 times.
✓ Branch 314 → 315 taken 294 times.
✓ Branch 314 → 316 taken 1 time.
✓ Branch 317 → 318 taken 294 times.
✓ Branch 317 → 319 taken 453 times.
✓ Branch 318 → 322 taken 294 times.
|
747 | if (allowed && property != "direction") output.insert(property, value); |
| 217 |
2/2✓ Branch 319 → 320 taken 1 time.
✓ Branch 319 → 321 taken 452 times.
|
453 | else if (allowed) continue; |
| 218 | 452 | else simplified = true; | |
| 219 | 29799 | } | |
| 220 | 28501 | QStringList declarationsOutput; | |
| 221 |
7/7✓ Branch 337 → 338 taken 28501 times.
✓ Branch 342 → 343 taken 1323 times.
✓ Branch 343 → 344 taken 1323 times.
✓ Branch 344 → 345 taken 1323 times.
✓ Branch 348 → 349 taken 29824 times.
✓ Branch 350 → 339 taken 1323 times.
✓ Branch 350 → 351 taken 28501 times.
|
29824 | for (auto it = output.cbegin(); it != output.cend(); ++it) declarationsOutput.append(it.key() + ':' + it.value()); |
| 222 |
1/1✓ Branch 352 → 353 taken 28501 times.
|
28501 | return declarationsOutput.join(';'); |
| 223 | 28525 | } | |
| 224 | |||
| 225 | 28969 | void start(void *context, const xmlChar *name, const xmlChar **attributes) { | |
| 226 | 28969 | auto &state = *static_cast<State *>(context); | |
| 227 |
2/3✓ Branch 2 → 3 taken 28969 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 28969 times.
|
28969 | if (state.interrupted()) |
| 228 | 467 | return; | |
| 229 |
5/6✓ Branch 6 → 7 taken 28967 times.
✓ Branch 6 → 9 taken 2 times.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 28967 times.
✓ Branch 11 → 12 taken 2 times.
✓ Branch 11 → 14 taken 28967 times.
|
57936 | if (state.stack.size() >= NativeMailDocument::MaxDepth || |
| 230 | 28967 | state.nodes.size() >= NativeMailDocument::MaxNodes) { | |
| 231 |
1/1✓ Branch 12 → 13 taken 2 times.
|
2 | state.stop(); |
| 232 | 2 | return; | |
| 233 | } | ||
| 234 |
1/1✓ Branch 15 → 16 taken 28967 times.
|
28967 | const QString tag = QString::fromUtf8(reinterpret_cast<const char *>(name)); |
| 235 | static const QSet<QString> suppressed{"head", "script", "style", "iframe", | ||
| 236 |
5/10✓ Branch 16 → 17 taken 13 times.
✓ Branch 16 → 33 taken 28954 times.
✓ Branch 18 → 19 taken 13 times.
✗ Branch 18 → 33 not taken.
✓ Branch 30 → 31 taken 91 times.
✓ Branch 30 → 32 taken 13 times.
✗ Branch 420 → 421 not taken.
✗ Branch 420 → 422 not taken.
✗ Branch 429 → 430 not taken.
✗ Branch 429 → 431 not taken.
|
29071 | "object", "embed", "template"}; |
| 237 |
5/5✓ Branch 33 → 34 taken 28967 times.
✓ Branch 34 → 35 taken 28683 times.
✓ Branch 34 → 37 taken 284 times.
✓ Branch 36 → 37 taken 181 times.
✓ Branch 36 → 38 taken 28502 times.
|
28967 | const bool hidden = state.stack.last().suppressed || suppressed.contains(tag); |
| 238 |
2/2✓ Branch 39 → 40 taken 465 times.
✓ Branch 39 → 43 taken 28502 times.
|
28967 | if (hidden) { |
| 239 |
2/2✓ Branch 40 → 41 taken 465 times.
✓ Branch 41 → 42 taken 465 times.
|
465 | state.stack.append({state.stack.last().node, true}); |
| 240 | 465 | return; | |
| 241 | } | ||
| 242 | static const QSet<QString> allowed{ | ||
| 243 | "html", "body", "div", "span", "p", "br", "hr", "h1", "h2", | ||
| 244 | "h3", "h4", "h5", "h6", "b", "strong", "i", "em", "u", | ||
| 245 | "s", "del", "blockquote", "ol", "ul", "li", "pre", "code", "table", | ||
| 246 |
5/10✓ Branch 43 → 44 taken 13 times.
✓ Branch 43 → 88 taken 28489 times.
✓ Branch 45 → 46 taken 13 times.
✗ Branch 45 → 88 not taken.
✓ Branch 85 → 86 taken 455 times.
✓ Branch 85 → 87 taken 13 times.
✗ Branch 434 → 435 not taken.
✗ Branch 434 → 436 not taken.
✗ Branch 443 → 444 not taken.
✗ Branch 443 → 445 not taken.
|
28970 | "thead", "tbody", "tfoot", "tr", "td", "th", "a", "img"}; |
| 247 |
1/1✓ Branch 88 → 89 taken 28502 times.
|
28502 | Node node; |
| 248 | static const QSet<QString> blocks{"section", "article", "header", "footer", | ||
| 249 | "main", "nav", "aside", "figure", | ||
| 250 |
5/10✓ Branch 89 → 90 taken 13 times.
✓ Branch 89 → 111 taken 28489 times.
✓ Branch 91 → 92 taken 13 times.
✗ Branch 91 → 111 not taken.
✓ Branch 108 → 109 taken 156 times.
✓ Branch 108 → 110 taken 13 times.
✗ Branch 447 → 448 not taken.
✗ Branch 447 → 449 not taken.
✗ Branch 456 → 457 not taken.
✗ Branch 456 → 458 not taken.
|
28671 | "figcaption", "details", "summary", "caption"}; |
| 251 |
2/2✓ Branch 112 → 113 taken 28440 times.
✓ Branch 112 → 114 taken 62 times.
|
57066 | node.tag = allowed.contains(tag) ? tag |
| 252 |
2/2✓ Branch 115 → 116 taken 12 times.
✓ Branch 115 → 119 taken 50 times.
|
74 | : blocks.contains(tag) ? QStringLiteral("div") |
| 253 |
4/4✓ Branch 124 → 125 taken 50 times.
✓ Branch 124 → 126 taken 28452 times.
✓ Branch 126 → 127 taken 12 times.
✓ Branch 126 → 128 taken 28490 times.
|
57004 | : QStringLiteral("span"); |
| 254 |
2/2✓ Branch 129 → 130 taken 62 times.
✓ Branch 129 → 131 taken 28440 times.
|
28502 | if (!allowed.contains(tag)) |
| 255 | 62 | state.simplified = true; | |
| 256 |
2/2✓ Branch 131 → 132 taken 28502 times.
✓ Branch 132 → 133 taken 28502 times.
|
28502 | node.style = safeInlineStyle(attribute(attributes, "style"), state.simplified, node.direction, state.compose); |
| 257 |
2/2✓ Branch 136 → 137 taken 13373 times.
✓ Branch 136 → 161 taken 15129 times.
|
28502 | if (state.compose) { |
| 258 |
2/2✓ Branch 137 → 138 taken 13373 times.
✓ Branch 141 → 142 taken 13373 times.
|
13373 | const QStringList classes = attribute(attributes, "class").split(QLatin1Char(' '), Qt::SkipEmptyParts); |
| 259 |
2/2✓ Branch 149 → 150 taken 6 times.
✓ Branch 149 → 151 taken 13367 times.
|
13373 | if (classes.contains(QStringLiteral("mailjd-signature"))) node.region = 1; |
| 260 |
2/2✓ Branch 157 → 158 taken 4 times.
✓ Branch 157 → 159 taken 13363 times.
|
13367 | else if (classes.contains(QStringLiteral("mailjd-quote"))) node.region = 2; |
| 261 | 13373 | } | |
| 262 |
2/2✓ Branch 161 → 162 taken 28502 times.
✓ Branch 162 → 163 taken 28502 times.
|
28502 | const auto direction = attribute(attributes, "dir").toLower(); |
| 263 |
6/6✓ Branch 165 → 166 taken 28478 times.
✓ Branch 165 → 168 taken 24 times.
✓ Branch 167 → 168 taken 26 times.
✓ Branch 167 → 169 taken 28452 times.
✓ Branch 170 → 171 taken 50 times.
✓ Branch 170 → 172 taken 28452 times.
|
28502 | if (direction == "rtl" || direction == "ltr") |
| 264 | 50 | node.direction = direction; | |
| 265 |
2/2✓ Branch 173 → 174 taken 4133 times.
✓ Branch 173 → 219 taken 24369 times.
|
28502 | if (tag == "a") { |
| 266 |
2/2✓ Branch 174 → 175 taken 4133 times.
✓ Branch 175 → 176 taken 4133 times.
|
4133 | const auto href = attribute(attributes, "href").trimmed(); |
| 267 |
1/1✓ Branch 177 → 178 taken 4133 times.
|
4133 | const QUrl url(href, QUrl::StrictMode); |
| 268 |
2/2✓ Branch 178 → 179 taken 4133 times.
✓ Branch 179 → 180 taken 4133 times.
|
4133 | const auto scheme = url.scheme().toLower(); |
| 269 |
7/7✓ Branch 182 → 183 taken 4132 times.
✓ Branch 182 → 200 taken 1 time.
✓ Branch 183 → 184 taken 4132 times.
✓ Branch 184 → 185 taken 4130 times.
✓ Branch 184 → 200 taken 2 times.
✓ Branch 186 → 187 taken 6 times.
✓ Branch 186 → 191 taken 4124 times.
|
12393 | if (href.size() <= 2048 && url.isValid() && |
| 270 |
7/9✓ Branch 188 → 189 taken 6 times.
✓ Branch 190 → 191 taken 1 time.
✓ Branch 190 → 199 taken 5 times.
✓ Branch 192 → 193 taken 4123 times.
✓ Branch 192 → 195 taken 2 times.
✓ Branch 205 → 206 taken 4104 times.
✓ Branch 205 → 211 taken 29 times.
✗ Branch 486 → 487 not taken.
✗ Branch 486 → 488 not taken.
|
12394 | ((scheme == "mailto" && !url.path().isEmpty()) || |
| 271 |
9/11✓ Branch 194 → 195 taken 4098 times.
✓ Branch 194 → 200 taken 25 times.
✓ Branch 196 → 197 taken 4100 times.
✓ Branch 198 → 199 taken 4099 times.
✓ Branch 198 → 200 taken 1 time.
✓ Branch 201 → 202 taken 4100 times.
✓ Branch 201 → 203 taken 33 times.
✓ Branch 203 → 204 taken 6 times.
✓ Branch 203 → 205 taken 4127 times.
✗ Branch 479 → 480 not taken.
✗ Branch 479 → 481 not taken.
|
16481 | ((scheme == "http" || scheme == "https") && !url.host().isEmpty()))) |
| 272 |
1/1✓ Branch 207 → 208 taken 4104 times.
|
4104 | node.href = url.toString(QUrl::FullyEncoded); |
| 273 | else { | ||
| 274 |
1/1✓ Branch 211 → 212 taken 29 times.
|
29 | node.tag = "span"; |
| 275 |
2/2✓ Branch 213 → 214 taken 28 times.
✓ Branch 213 → 215 taken 1 time.
|
29 | if (!href.isEmpty()) |
| 276 | 28 | state.simplified = true; | |
| 277 | } | ||
| 278 | 4133 | } | |
| 279 |
2/2✓ Branch 220 → 221 taken 475 times.
✓ Branch 220 → 386 taken 28027 times.
|
28502 | if (tag == "img") { |
| 280 |
1/1✓ Branch 221 → 222 taken 475 times.
|
475 | node.tag = "span"; |
| 281 |
2/2✓ Branch 222 → 223 taken 475 times.
✓ Branch 223 → 224 taken 475 times.
|
475 | const QString source = attribute(attributes, "src").trimmed(); |
| 282 |
9/12✓ Branch 225 → 226 taken 475 times.
✓ Branch 226 → 227 taken 475 times.
✓ Branch 227 → 228 taken 226 times.
✓ Branch 227 → 231 taken 249 times.
✓ Branch 229 → 230 taken 225 times.
✓ Branch 229 → 231 taken 1 time.
✓ Branch 232 → 233 taken 475 times.
✗ Branch 232 → 234 not taken.
✓ Branch 234 → 235 taken 225 times.
✓ Branch 234 → 255 taken 250 times.
✗ Branch 504 → 505 not taken.
✗ Branch 504 → 506 not taken.
|
475 | if (source.startsWith("cid:", Qt::CaseInsensitive) && source.size() <= 2048) { |
| 283 |
2/2✓ Branch 235 → 236 taken 225 times.
✓ Branch 236 → 237 taken 225 times.
|
225 | const QString id = canonicalContentId(source.mid(4)); |
| 284 | 225 | bool valid = !id.isEmpty(); | |
| 285 |
8/8✓ Branch 242 → 243 taken 812 times.
✓ Branch 242 → 245 taken 1 time.
✓ Branch 244 → 245 taken 1 time.
✓ Branch 244 → 246 taken 811 times.
✓ Branch 247 → 248 taken 2 times.
✓ Branch 247 → 249 taken 811 times.
✓ Branch 250 → 241 taken 813 times.
✓ Branch 250 → 251 taken 225 times.
|
1038 | for (QChar c : id) if (c.isSpace() || c.category() == QChar::Other_Control) valid = false; |
| 286 |
2/2✓ Branch 251 → 252 taken 222 times.
✓ Branch 251 → 253 taken 3 times.
|
225 | if (valid) node.contentId = id; |
| 287 | 225 | } | |
| 288 |
1/1✓ Branch 255 → 256 taken 475 times.
|
475 | const QUrl remote(source, QUrl::StrictMode); |
| 289 | // S106-038: the bound is on the encoded URL, as NativeDocumentCache::get() | ||
| 290 | // checks it — a non-ASCII URL under 4096 characters but above 4096 | ||
| 291 | // encoded bytes was cached and then never read back. | ||
| 292 |
10/12✓ Branch 259 → 260 taken 475 times.
✓ Branch 261 → 262 taken 474 times.
✓ Branch 261 → 279 taken 1 time.
✓ Branch 262 → 263 taken 474 times.
✓ Branch 263 → 264 taken 472 times.
✓ Branch 263 → 279 taken 2 times.
✓ Branch 267 → 268 taken 471 times.
✓ Branch 267 → 279 taken 1 time.
✓ Branch 290 → 291 taken 223 times.
✓ Branch 290 → 292 taken 252 times.
✗ Branch 532 → 533 not taken.
✗ Branch 532 → 534 not taken.
|
1422 | if (source.size() <= 4096 && remote.toEncoded().size() <= 4096 && remote.isValid() && |
| 293 |
2/5✓ Branch 265 → 266 taken 472 times.
✓ Branch 288 → 289 taken 475 times.
✗ Branch 288 → 290 not taken.
✗ Branch 527 → 528 not taken.
✗ Branch 527 → 529 not taken.
|
947 | remote.userInfo().isEmpty() && |
| 294 |
17/25✓ Branch 257 → 258 taken 475 times.
✗ Branch 257 → 279 not taken.
✓ Branch 269 → 270 taken 471 times.
✓ Branch 271 → 272 taken 223 times.
✓ Branch 271 → 279 taken 248 times.
✓ Branch 272 → 273 taken 223 times.
✓ Branch 274 → 275 taken 222 times.
✓ Branch 274 → 278 taken 1 time.
✓ Branch 275 → 276 taken 222 times.
✓ Branch 277 → 278 taken 222 times.
✗ Branch 277 → 279 not taken.
✓ Branch 280 → 281 taken 222 times.
✓ Branch 280 → 282 taken 253 times.
✓ Branch 282 → 283 taken 223 times.
✓ Branch 282 → 284 taken 252 times.
✓ Branch 284 → 285 taken 471 times.
✓ Branch 284 → 286 taken 4 times.
✓ Branch 286 → 287 taken 472 times.
✓ Branch 286 → 288 taken 3 times.
✗ Branch 512 → 513 not taken.
✗ Branch 512 → 514 not taken.
✗ Branch 517 → 518 not taken.
✗ Branch 517 → 519 not taken.
✗ Branch 522 → 523 not taken.
✗ Branch 522 → 524 not taken.
|
950 | !remote.host().isEmpty() && (remote.scheme() == "http" || remote.scheme() == "https")) |
| 295 | 223 | node.remoteUrl = remote; | |
| 296 |
11/15✓ Branch 292 → 293 taken 220 times.
✓ Branch 292 → 299 taken 255 times.
✓ Branch 296 → 297 taken 220 times.
✓ Branch 297 → 298 taken 4 times.
✓ Branch 297 → 299 taken 216 times.
✓ Branch 300 → 301 taken 220 times.
✓ Branch 300 → 302 taken 255 times.
✓ Branch 302 → 303 taken 220 times.
✓ Branch 302 → 304 taken 255 times.
✓ Branch 304 → 305 taken 4 times.
✓ Branch 304 → 346 taken 471 times.
✗ Branch 537 → 538 not taken.
✗ Branch 537 → 539 not taken.
✗ Branch 541 → 542 not taken.
✗ Branch 541 → 543 not taken.
|
695 | if (state.compose && source.startsWith(QStringLiteral("data:image/"), Qt::CaseInsensitive)) { |
| 297 | 6 | static const QRegularExpression dataUrl(QStringLiteral( | |
| 298 | "^data:(image/(?:png|jpeg|gif|webp));base64,([A-Za-z0-9+/=\\s]+)$"), | ||
| 299 |
4/7✓ Branch 305 → 306 taken 3 times.
✓ Branch 305 → 318 taken 1 time.
✓ Branch 307 → 308 taken 3 times.
✗ Branch 307 → 318 not taken.
✓ Branch 312 → 313 taken 3 times.
✗ Branch 552 → 553 not taken.
✗ Branch 552 → 554 not taken.
|
10 | QRegularExpression::CaseInsensitiveOption); |
| 300 |
1/1✓ Branch 319 → 320 taken 4 times.
|
4 | const auto match = dataUrl.match(source); |
| 301 |
2/3✓ Branch 320 → 321 taken 4 times.
✓ Branch 321 → 322 taken 4 times.
✗ Branch 321 → 344 not taken.
|
4 | if (match.hasMatch()) { |
| 302 |
3/3✓ Branch 323 → 324 taken 4 times.
✓ Branch 324 → 325 taken 4 times.
✓ Branch 325 → 326 taken 4 times.
|
4 | const QByteArray decoded = QByteArray::fromBase64(match.captured(2).toLatin1()); |
| 303 |
3/6✓ Branch 329 → 330 taken 4 times.
✗ Branch 329 → 333 not taken.
✓ Branch 331 → 332 taken 4 times.
✗ Branch 331 → 333 not taken.
✓ Branch 334 → 335 taken 4 times.
✗ Branch 334 → 342 not taken.
|
4 | if (!decoded.isEmpty() && decoded.size() <= NativeMailDocument::MaxDataImageBytes) { |
| 304 | 4 | node.imageData = decoded; | |
| 305 |
2/2✓ Branch 336 → 337 taken 4 times.
✓ Branch 337 → 338 taken 4 times.
|
4 | node.imageType = match.captured(1).toLower(); |
| 306 | } | ||
| 307 | 4 | } | |
| 308 | 4 | } | |
| 309 |
2/2✓ Branch 346 → 347 taken 220 times.
✓ Branch 346 → 356 taken 255 times.
|
475 | if (state.compose) { |
| 310 |
2/2✓ Branch 347 → 348 taken 220 times.
✓ Branch 348 → 349 taken 220 times.
|
220 | node.imageWidth = qBound(0, attribute(attributes, "width").toInt(), 4096); |
| 311 |
2/2✓ Branch 351 → 352 taken 220 times.
✓ Branch 352 → 353 taken 220 times.
|
220 | node.imageHeight = qBound(0, attribute(attributes, "height").toInt(), 4096); |
| 312 | } | ||
| 313 |
1/1✓ Branch 356 → 357 taken 475 times.
|
475 | node.text = attribute(attributes, "alt"); |
| 314 |
6/6✓ Branch 360 → 361 taken 411 times.
✓ Branch 360 → 363 taken 64 times.
✓ Branch 361 → 362 taken 208 times.
✓ Branch 361 → 363 taken 203 times.
✓ Branch 364 → 365 taken 208 times.
✓ Branch 364 → 372 taken 267 times.
|
475 | if (node.text.isEmpty() && !state.compose) |
| 315 | 208 | node.text = QStringLiteral("[Image]"); | |
| 316 | 475 | state.textCharacters += node.text.size(); | |
| 317 |
1/2✗ Branch 373 → 374 not taken.
✓ Branch 373 → 376 taken 475 times.
|
475 | if (state.textCharacters > 1024 * 1024) { |
| 318 | ✗ | state.stop(); | |
| 319 | ✗ | return; | |
| 320 | } | ||
| 321 | 475 | state.simplified = true; | |
| 322 | 475 | } | |
| 323 |
6/6✓ Branch 387 → 388 taken 24435 times.
✓ Branch 387 → 390 taken 4067 times.
✓ Branch 389 → 390 taken 121 times.
✓ Branch 389 → 391 taken 24314 times.
✓ Branch 392 → 393 taken 4188 times.
✓ Branch 392 → 396 taken 24314 times.
|
28502 | if (tag == "td" || tag == "th") { |
| 324 | 8376 | auto span = [&](const char *name) { | |
| 325 |
1/1✓ Branch 2 → 3 taken 8376 times.
|
8376 | const QString raw = attribute(attributes, name); |
| 326 |
2/2✓ Branch 4 → 5 taken 7329 times.
✓ Branch 4 → 6 taken 1047 times.
|
8376 | if (raw.isEmpty()) |
| 327 | 7329 | return 1; | |
| 328 | 1047 | bool valid = false; | |
| 329 |
1/1✓ Branch 6 → 7 taken 1047 times.
|
1047 | const int value = raw.toInt(&valid); |
| 330 |
4/4✓ Branch 7 → 8 taken 1045 times.
✓ Branch 7 → 10 taken 2 times.
✓ Branch 8 → 9 taken 1041 times.
✓ Branch 8 → 10 taken 4 times.
|
1047 | if (valid && value > 0) |
| 331 | 1041 | return value; | |
| 332 | 6 | state.simplified = true; | |
| 333 | 6 | return 1; | |
| 334 | 8376 | }; | |
| 335 |
1/1✓ Branch 393 → 394 taken 4188 times.
|
4188 | node.columns = span("colspan"); |
| 336 |
1/1✓ Branch 394 → 395 taken 4188 times.
|
4188 | node.rows = span("rowspan"); |
| 337 | } | ||
| 338 |
1/1✓ Branch 396 → 397 taken 28502 times.
|
28502 | const int parent = state.stack.last().node; |
| 339 | 28502 | const int next = state.nodes.size(); | |
| 340 |
2/2✓ Branch 398 → 399 taken 28502 times.
✓ Branch 399 → 400 taken 28502 times.
|
28502 | state.nodes[parent].children.append(next); |
| 341 |
1/1✓ Branch 400 → 401 taken 28502 times.
|
28502 | state.nodes.append(node); |
| 342 |
1/1✓ Branch 401 → 402 taken 28502 times.
|
28502 | state.stack.append({next, false}); |
| 343 | 29006 | } | |
| 344 | 28838 | void end(void *context, const xmlChar *) { | |
| 345 | 28838 | auto &state = *static_cast<State *>(context); | |
| 346 |
1/2✓ Branch 3 → 4 taken 28838 times.
✗ Branch 3 → 5 not taken.
|
28838 | if (state.stack.size() > 1) |
| 347 | 28838 | state.stack.removeLast(); | |
| 348 | 28838 | } | |
| 349 | 32596 | void characters(void *context, const xmlChar *text, int length) { | |
| 350 |
1/1✓ Branch 3 → 4 taken 32596 times.
|
32596 | static_cast<State *>(context)->appendText( |
| 351 |
1/1✓ Branch 2 → 3 taken 32596 times.
|
65192 | QString::fromUtf8(reinterpret_cast<const char *>(text), length)); |
| 352 | 32596 | } | |
| 353 | ✗ | xmlParserInputPtr denyEntity(void *context, const xmlChar *, const xmlChar *) { | |
| 354 | ✗ | ++static_cast<State *>(context)->deniedEntities; | |
| 355 | ✗ | return nullptr; | |
| 356 | } | ||
| 357 | 12 | void ignoreReport(void *, const char *, ...) {} | |
| 358 | |||
| 359 | 121 | bool tableFits(const QVector<Node> &nodes, int table, int &remainingCells) { | |
| 360 | 121 | QVector<int> rows; | |
| 361 | ✗ | std::function<void(int)> collect = [&](int id) { | |
| 362 | 1711 | const auto &node = nodes[id]; | |
| 363 |
2/2✓ Branch 4 → 5 taken 1576 times.
✓ Branch 4 → 7 taken 135 times.
|
1711 | if (node.tag == "tr") { |
| 364 | 1576 | rows.append(id); | |
| 365 | 1576 | return; | |
| 366 | } | ||
| 367 |
4/6✓ Branch 8 → 9 taken 121 times.
✓ Branch 8 → 11 taken 14 times.
✗ Branch 9 → 10 not taken.
✓ Branch 9 → 11 taken 121 times.
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 135 times.
|
135 | if (node.tag == "table" && id != table) |
| 368 | ✗ | return; | |
| 369 |
2/2✓ Branch 20 → 16 taken 1590 times.
✓ Branch 20 → 21 taken 135 times.
|
1725 | for (int child : node.children) |
| 370 |
1/1✓ Branch 17 → 18 taken 1590 times.
|
1590 | collect(child); |
| 371 |
1/1✓ Branch 2 → 3 taken 121 times.
|
121 | }; |
| 372 |
1/1✓ Branch 3 → 4 taken 121 times.
|
121 | collect(table); |
| 373 |
2/2✓ Branch 5 → 6 taken 2 times.
✓ Branch 5 → 7 taken 119 times.
|
121 | if (rows.size() > 128) |
| 374 | 2 | return false; | |
| 375 | 119 | std::array<std::array<bool, 32>, 128> occupied{}; | |
| 376 | 119 | int cells = 0; | |
| 377 |
2/2✓ Branch 58 → 8 taken 386 times.
✓ Branch 58 → 59 taken 111 times.
|
497 | for (int row = 0; row < rows.size(); ++row) { |
| 378 | 386 | int column = 0; | |
| 379 |
3/3✓ Branch 8 → 9 taken 386 times.
✓ Branch 54 → 12 taken 678 times.
✓ Branch 54 → 55 taken 378 times.
|
1056 | for (int id : nodes[rows[row]].children) { |
| 380 | 678 | const auto &cell = nodes[id]; | |
| 381 |
4/6✓ Branch 15 → 16 taken 119 times.
✓ Branch 15 → 19 taken 559 times.
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 19 taken 119 times.
✗ Branch 20 → 21 not taken.
✓ Branch 20 → 22 taken 678 times.
|
678 | if (cell.tag != "td" && cell.tag != "th") |
| 382 | ✗ | continue; | |
| 383 |
6/6✓ Branch 24 → 25 taken 687 times.
✓ Branch 24 → 29 taken 3 times.
✓ Branch 27 → 28 taken 12 times.
✓ Branch 27 → 29 taken 675 times.
✓ Branch 30 → 23 taken 12 times.
✓ Branch 30 → 31 taken 678 times.
|
690 | while (column < 32 && occupied[row][column]) |
| 384 | 12 | ++column; | |
| 385 |
5/6✓ Branch 31 → 32 taken 677 times.
✓ Branch 31 → 35 taken 1 time.
✓ Branch 32 → 33 taken 677 times.
✗ Branch 32 → 35 not taken.
✓ Branch 33 → 34 taken 674 times.
✓ Branch 33 → 35 taken 3 times.
|
678 | if (cell.columns > 32 || cell.rows > 128 || column + cell.columns > 32 || |
| 386 |
2/2✓ Branch 34 → 35 taken 1 time.
✓ Branch 34 → 36 taken 673 times.
|
674 | row + cell.rows > 128) |
| 387 | 8 | return false; | |
| 388 | 673 | cells += cell.columns * cell.rows; | |
| 389 |
4/4✓ Branch 36 → 37 taken 672 times.
✓ Branch 36 → 38 taken 1 time.
✓ Branch 37 → 38 taken 1 time.
✓ Branch 37 → 39 taken 671 times.
|
673 | if (cells > 2048 || cells > remainingCells) |
| 390 | 2 | return false; | |
| 391 |
2/2✓ Branch 50 → 40 taken 936 times.
✓ Branch 50 → 51 taken 670 times.
|
1606 | for (int r = row; r < row + cell.rows; ++r) |
| 392 |
2/2✓ Branch 48 → 41 taken 8885 times.
✓ Branch 48 → 49 taken 935 times.
|
9820 | for (int c = column; c < column + cell.columns; ++c) { |
| 393 |
2/2✓ Branch 43 → 44 taken 1 time.
✓ Branch 43 → 45 taken 8884 times.
|
8885 | if (occupied[r][c]) |
| 394 | 1 | return false; | |
| 395 | 8884 | occupied[r][c] = true; | |
| 396 | } | ||
| 397 | 670 | column += cell.columns; | |
| 398 | } | ||
| 399 | } | ||
| 400 | 111 | remainingCells -= cells; | |
| 401 | 111 | return true; | |
| 402 | 121 | } | |
| 403 | } // namespace | ||
| 404 | 590 | NativeMailDocument NativeMailDocument::prepare(const QByteArray &input, | |
| 405 | const std::atomic_bool *cancelled, Mode mode) { | ||
| 406 | 590 | NativeMailDocument result; | |
| 407 |
6/6✓ Branch 2 → 3 taken 71 times.
✓ Branch 2 → 6 taken 519 times.
✓ Branch 4 → 5 taken 1 time.
✓ Branch 4 → 6 taken 70 times.
✓ Branch 7 → 8 taken 1 time.
✓ Branch 7 → 9 taken 589 times.
|
590 | if (cancelled && cancelled->load(std::memory_order_relaxed)) { |
| 408 | 1 | result.outcome = Outcome::Cancelled; | |
| 409 | 1 | return result; | |
| 410 | } | ||
| 411 |
2/2✓ Branch 10 → 11 taken 2 times.
✓ Branch 10 → 12 taken 587 times.
|
589 | if (input.size() > MaxInputBytes) { |
| 412 | 2 | result.outcome = Outcome::Limited; | |
| 413 | 2 | return result; | |
| 414 | } | ||
| 415 |
1/1✓ Branch 12 → 13 taken 587 times.
|
587 | State state; |
| 416 | 587 | state.cancelled = cancelled; | |
| 417 | 587 | state.compose = mode == Mode::Compose; | |
| 418 |
5/6✓ Branch 13 → 14 taken 206 times.
✓ Branch 13 → 21 taken 381 times.
✓ Branch 16 → 17 taken 195 times.
✓ Branch 16 → 20 taken 11 times.
✗ Branch 19 → 20 not taken.
✓ Branch 19 → 21 taken 195 times.
|
782 | state.wordHtml = state.compose && (input.contains("MsoNormal") || |
| 419 | 195 | input.contains("urn:schemas-microsoft-com:office:office")); | |
| 420 | 587 | htmlSAXHandler sax{}; | |
| 421 | 587 | sax.startElement = start; | |
| 422 | 587 | sax.endElement = end; | |
| 423 | 587 | sax.characters = characters; | |
| 424 | 587 | sax.cdataBlock = characters; | |
| 425 | 587 | sax.resolveEntity = denyEntity; | |
| 426 | 587 | sax.warning = ignoreReport; | |
| 427 | 587 | sax.error = ignoreReport; | |
| 428 | 587 | sax.fatalError = ignoreReport; | |
| 429 | 587 | state.parser = | |
| 430 |
1/1✓ Branch 22 → 23 taken 587 times.
|
587 | htmlCreatePushParserCtxt(&sax, &state, nullptr, 0, nullptr, XML_CHAR_ENCODING_UTF8); |
| 431 |
1/2✗ Branch 23 → 24 not taken.
✓ Branch 23 → 25 taken 587 times.
|
587 | if (!state.parser) { |
| 432 | ✗ | result.outcome = Outcome::Failed; | |
| 433 | ✗ | return result; | |
| 434 | } | ||
| 435 |
1/1✓ Branch 25 → 26 taken 587 times.
|
587 | htmlCtxtUseOptions(state.parser, HTML_PARSE_RECOVER | HTML_PARSE_NONET | HTML_PARSE_NODEFDTD); |
| 436 |
7/7✓ Branch 33 → 34 taken 836 times.
✓ Branch 33 → 37 taken 586 times.
✓ Branch 34 → 35 taken 836 times.
✓ Branch 35 → 36 taken 835 times.
✓ Branch 35 → 37 taken 1 time.
✓ Branch 38 → 27 taken 835 times.
✓ Branch 38 → 39 taken 587 times.
|
1422 | for (qsizetype offset = 0; offset < input.size() && !state.interrupted(); offset += 8192) |
| 437 |
1/1✓ Branch 30 → 31 taken 835 times.
|
835 | htmlParseChunk(state.parser, input.constData() + offset, |
| 438 | 1670 | int(qMin<qsizetype>(8192, input.size() - offset)), 0); | |
| 439 |
3/3✓ Branch 39 → 40 taken 587 times.
✓ Branch 40 → 41 taken 584 times.
✓ Branch 40 → 42 taken 3 times.
|
587 | if (!state.interrupted()) |
| 440 |
1/1✓ Branch 41 → 42 taken 584 times.
|
584 | htmlParseChunk(state.parser, nullptr, 0, 1); |
| 441 | 587 | const int parseError = state.parser->errNo; | |
| 442 |
2/4✓ Branch 42 → 43 taken 587 times.
✗ Branch 42 → 44 not taken.
✗ Branch 43 → 44 not taken.
✓ Branch 43 → 45 taken 587 times.
|
587 | if (parseError == XML_ERR_RESOURCE_LIMIT || parseError == XML_ERR_NAME_TOO_LONG) |
| 443 | ✗ | state.limited = true; | |
| 444 |
2/4✓ Branch 45 → 46 taken 587 times.
✗ Branch 45 → 47 not taken.
✗ Branch 46 → 47 not taken.
✓ Branch 46 → 48 taken 587 times.
|
587 | const bool failed = parseError == XML_ERR_INTERNAL_ERROR || parseError == XML_ERR_NO_MEMORY; |
| 445 |
1/1✓ Branch 49 → 50 taken 587 times.
|
587 | htmlFreeParserCtxt(state.parser); |
| 446 | 587 | state.parser = nullptr; | |
| 447 | 587 | result.nodes = state.nodes.size(); | |
| 448 | 587 | result.deniedEntities = state.deniedEntities; | |
| 449 |
1/2✗ Branch 51 → 52 not taken.
✓ Branch 51 → 53 taken 587 times.
|
1174 | result.outcome = state.wasCancelled ? Outcome::Cancelled |
| 450 |
2/2✓ Branch 53 → 54 taken 3 times.
✓ Branch 53 → 55 taken 584 times.
|
1171 | : state.limited ? Outcome::Limited |
| 451 |
1/2✗ Branch 55 → 56 not taken.
✓ Branch 55 → 57 taken 584 times.
|
584 | : failed ? Outcome::Failed |
| 452 | : Outcome::Ready; | ||
| 453 |
2/2✓ Branch 60 → 61 taken 3 times.
✓ Branch 60 → 62 taken 584 times.
|
587 | if (result.outcome != Outcome::Ready) |
| 454 | 3 | return result; | |
| 455 | 584 | QString output; | |
| 456 | 584 | int remainingCells = 8192; | |
| 457 | static const QSet<QString> blockTags{"p", "div", "li", "h1", "h2", "h3", "h4", "h5", | ||
| 458 |
5/10✓ Branch 62 → 63 taken 13 times.
✓ Branch 62 → 85 taken 571 times.
✓ Branch 64 → 65 taken 13 times.
✗ Branch 64 → 85 not taken.
✓ Branch 82 → 83 taken 169 times.
✓ Branch 82 → 84 taken 13 times.
✗ Branch 112 → 113 not taken.
✗ Branch 112 → 114 not taken.
✗ Branch 121 → 122 not taken.
✗ Branch 121 → 123 not taken.
|
766 | "h6", "pre", "td", "th", "blockquote"}; |
| 459 | ✗ | std::function<void(int, bool, int, int)> emitNode = [&](int id, bool flatTable, int tableDepth, int region) { | |
| 460 |
3/3✓ Branch 2 → 3 taken 52322 times.
✓ Branch 3 → 4 taken 1 time.
✓ Branch 3 → 5 taken 52321 times.
|
52322 | if (state.interrupted()) |
| 461 | 28045 | return; | |
| 462 |
1/1✓ Branch 5 → 6 taken 52321 times.
|
52321 | const auto &node = state.nodes[id]; |
| 463 |
2/2✓ Branch 7 → 8 taken 28044 times.
✓ Branch 7 → 12 taken 24277 times.
|
52321 | if (node.tag.isEmpty()) { |
| 464 |
2/2✓ Branch 8 → 9 taken 28044 times.
✓ Branch 9 → 10 taken 28044 times.
|
28044 | output += node.text.toHtmlEscaped(); |
| 465 | 28044 | return; | |
| 466 | } | ||
| 467 | 24277 | QString tag = node.tag; | |
| 468 |
2/2✓ Branch 14 → 15 taken 121 times.
✓ Branch 14 → 23 taken 24156 times.
|
24277 | if (tag == "table") { |
| 469 | 121 | ++tableDepth; | |
| 470 |
5/7✓ Branch 15 → 16 taken 121 times.
✗ Branch 15 → 19 not taken.
✓ Branch 16 → 17 taken 121 times.
✗ Branch 16 → 19 not taken.
✓ Branch 17 → 18 taken 121 times.
✓ Branch 18 → 19 taken 10 times.
✓ Branch 18 → 20 taken 111 times.
|
121 | flatTable = flatTable || tableDepth > 3 || !tableFits(state.nodes, id, remainingCells); |
| 471 |
2/2✓ Branch 21 → 22 taken 10 times.
✓ Branch 21 → 23 taken 111 times.
|
121 | if (flatTable) |
| 472 | 10 | state.simplified = true; | |
| 473 | } | ||
| 474 |
12/12✓ Branch 23 → 24 taken 18341 times.
✓ Branch 23 → 37 taken 5936 times.
✓ Branch 25 → 26 taken 18339 times.
✓ Branch 25 → 36 taken 2 times.
✓ Branch 27 → 28 taken 18338 times.
✓ Branch 27 → 36 taken 1 time.
✓ Branch 29 → 30 taken 18336 times.
✓ Branch 29 → 36 taken 2 times.
✓ Branch 31 → 32 taken 18333 times.
✓ Branch 31 → 36 taken 3 times.
✓ Branch 33 → 34 taken 18330 times.
✓ Branch 33 → 36 taken 3 times.
|
60940 | if (tableDepth == 0 && (tag == "thead" || tag == "tbody" || tag == "tfoot" || tag == "tr" || |
| 475 |
4/4✓ Branch 35 → 36 taken 2 times.
✓ Branch 35 → 37 taken 18328 times.
✓ Branch 38 → 39 taken 13 times.
✓ Branch 38 → 40 taken 24264 times.
|
60940 | tag == "td" || tag == "th")) { |
| 476 | 13 | flatTable = true; | |
| 477 | 13 | state.simplified = true; | |
| 478 | } | ||
| 479 |
4/4✓ Branch 40 → 41 taken 5090 times.
✓ Branch 40 → 52 taken 19187 times.
✓ Branch 42 → 43 taken 5080 times.
✓ Branch 42 → 51 taken 10 times.
|
34447 | if (flatTable && |
| 480 |
10/10✓ Branch 44 → 45 taken 5077 times.
✓ Branch 44 → 51 taken 3 times.
✓ Branch 46 → 47 taken 5075 times.
✓ Branch 46 → 51 taken 2 times.
✓ Branch 48 → 49 taken 5072 times.
✓ Branch 48 → 51 taken 3 times.
✓ Branch 50 → 51 taken 1329 times.
✓ Branch 50 → 52 taken 3743 times.
✓ Branch 53 → 54 taken 1347 times.
✓ Branch 53 → 55 taken 22930 times.
|
34447 | (tag == "table" || tag == "thead" || tag == "tbody" || tag == "tfoot" || tag == "tr")) |
| 481 |
1/1✓ Branch 54 → 55 taken 1347 times.
|
1347 | tag = "div"; |
| 482 |
8/8✓ Branch 55 → 56 taken 5090 times.
✓ Branch 55 → 61 taken 19187 times.
✓ Branch 57 → 58 taken 1350 times.
✓ Branch 57 → 60 taken 3740 times.
✓ Branch 59 → 60 taken 3 times.
✓ Branch 59 → 61 taken 1347 times.
✓ Branch 62 → 63 taken 3743 times.
✓ Branch 62 → 64 taken 20534 times.
|
24277 | if (flatTable && (tag == "td" || tag == "th")) |
| 483 |
1/1✓ Branch 63 → 64 taken 3743 times.
|
3743 | tag = "span"; |
| 484 |
2/2✓ Branch 65 → 66 taken 24277 times.
✓ Branch 66 → 67 taken 24277 times.
|
24277 | output += '<' + tag; |
| 485 |
2/2✓ Branch 69 → 70 taken 51 times.
✓ Branch 69 → 77 taken 24226 times.
|
24277 | if (!node.direction.isEmpty()) |
| 486 |
3/3✓ Branch 71 → 72 taken 51 times.
✓ Branch 72 → 73 taken 51 times.
✓ Branch 73 → 74 taken 51 times.
|
51 | output += " dir=\"" + node.direction + '"'; |
| 487 | 24277 | QString style = node.style; | |
| 488 |
2/2✓ Branch 78 → 79 taken 13310 times.
✓ Branch 78 → 156 taken 10967 times.
|
24277 | if (state.compose) { |
| 489 |
2/2✓ Branch 80 → 81 taken 9 times.
✓ Branch 80 → 88 taken 13301 times.
|
13319 | if (tag == "code") style = QStringLiteral("font-family:mailjd-code"); |
| 490 | // A quote's gap comes from its paragraphs, not from the container. | ||
| 491 |
2/2✓ Branch 89 → 90 taken 17 times.
✓ Branch 89 → 105 taken 13293 times.
|
13310 | if (tag == "blockquote") |
| 492 |
4/5✓ Branch 94 → 95 taken 17 times.
✗ Branch 94 → 96 not taken.
✓ Branch 97 → 98 taken 17 times.
✓ Branch 98 → 99 taken 17 times.
✓ Branch 99 → 100 taken 17 times.
|
17 | style += QString(style.isEmpty() ? "" : ";") + QStringLiteral("margin-top:0px;margin-bottom:0px"); |
| 493 |
2/2✓ Branch 105 → 106 taken 10 times.
✓ Branch 105 → 107 taken 13300 times.
|
13310 | if (node.region > 0) region = node.region; |
| 494 | // Word HTML styles its paragraphs from the (dropped) head: margin 0. | ||
| 495 |
8/9✓ Branch 107 → 108 taken 120 times.
✓ Branch 107 → 114 taken 13190 times.
✓ Branch 109 → 110 taken 31 times.
✓ Branch 109 → 114 taken 89 times.
✓ Branch 111 → 112 taken 31 times.
✓ Branch 112 → 113 taken 31 times.
✗ Branch 112 → 114 not taken.
✓ Branch 115 → 116 taken 31 times.
✓ Branch 115 → 131 taken 13279 times.
|
13310 | if (state.wordHtml && tag == "p" && !style.contains(QLatin1String("margin"))) |
| 496 |
4/5✓ Branch 120 → 121 taken 31 times.
✗ Branch 120 → 122 not taken.
✓ Branch 123 → 124 taken 31 times.
✓ Branch 124 → 125 taken 31 times.
✓ Branch 125 → 126 taken 31 times.
|
31 | style += QString(style.isEmpty() ? "" : ";") + QStringLiteral("margin-top:0px;margin-bottom:0px"); |
| 497 | // Qt's importer turns -qt-user-state into the block's user state; | ||
| 498 | // the composer import reads the region back from it. | ||
| 499 |
6/6✓ Branch 131 → 132 taken 48 times.
✓ Branch 131 → 135 taken 13262 times.
✓ Branch 133 → 134 taken 38 times.
✓ Branch 133 → 135 taken 10 times.
✓ Branch 136 → 137 taken 38 times.
✓ Branch 136 → 156 taken 13272 times.
|
13310 | if (region > 0 && blockTags.contains(tag)) |
| 500 |
7/7✓ Branch 137 → 138 taken 38 times.
✓ Branch 142 → 143 taken 10 times.
✓ Branch 142 → 144 taken 28 times.
✓ Branch 145 → 146 taken 38 times.
✓ Branch 146 → 147 taken 38 times.
✓ Branch 147 → 148 taken 38 times.
✓ Branch 148 → 149 taken 38 times.
|
76 | style += QString(style.isEmpty() ? "" : ";") + QStringLiteral("-qt-user-state:") + QString::number(region); |
| 501 | } | ||
| 502 |
5/5✓ Branch 157 → 158 taken 555 times.
✓ Branch 157 → 165 taken 23722 times.
✓ Branch 159 → 160 taken 555 times.
✓ Branch 160 → 161 taken 555 times.
✓ Branch 161 → 162 taken 555 times.
|
24277 | if (!style.isEmpty()) output += " style=\"" + style + '"'; |
| 503 |
5/6✓ Branch 166 → 167 taken 4104 times.
✓ Branch 166 → 170 taken 20173 times.
✓ Branch 168 → 169 taken 4104 times.
✗ Branch 168 → 170 not taken.
✓ Branch 171 → 172 taken 4104 times.
✓ Branch 171 → 181 taken 20173 times.
|
24277 | if (tag == "a" && !node.href.isEmpty()) |
| 504 |
4/4✓ Branch 173 → 174 taken 4104 times.
✓ Branch 174 → 175 taken 4104 times.
✓ Branch 175 → 176 taken 4104 times.
✓ Branch 176 → 177 taken 4104 times.
|
4104 | output += " href=\"" + node.href.toHtmlEscaped() + '"'; |
| 505 |
8/8✓ Branch 182 → 183 taken 23950 times.
✓ Branch 182 → 185 taken 327 times.
✓ Branch 184 → 185 taken 118 times.
✓ Branch 184 → 187 taken 23832 times.
✓ Branch 185 → 186 taken 16 times.
✓ Branch 185 → 187 taken 429 times.
✓ Branch 188 → 189 taken 16 times.
✓ Branch 188 → 198 taken 24261 times.
|
24277 | if ((tag == "td" || tag == "th") && node.columns > 1) |
| 506 |
4/4✓ Branch 190 → 191 taken 16 times.
✓ Branch 191 → 192 taken 16 times.
✓ Branch 192 → 193 taken 16 times.
✓ Branch 193 → 194 taken 16 times.
|
16 | output += " colspan=\"" + QString::number(node.columns) + '"'; |
| 507 |
8/8✓ Branch 199 → 200 taken 23950 times.
✓ Branch 199 → 202 taken 327 times.
✓ Branch 201 → 202 taken 118 times.
✓ Branch 201 → 204 taken 23832 times.
✓ Branch 202 → 203 taken 16 times.
✓ Branch 202 → 204 taken 429 times.
✓ Branch 205 → 206 taken 16 times.
✓ Branch 205 → 215 taken 24261 times.
|
24277 | if ((tag == "td" || tag == "th") && node.rows > 1) |
| 508 |
4/4✓ Branch 207 → 208 taken 16 times.
✓ Branch 208 → 209 taken 16 times.
✓ Branch 209 → 210 taken 16 times.
✓ Branch 210 → 211 taken 16 times.
|
16 | output += " rowspan=\"" + QString::number(node.rows) + '"'; |
| 509 |
1/1✓ Branch 216 → 217 taken 24277 times.
|
24277 | output += '>'; |
| 510 |
11/11✓ Branch 218 → 219 taken 24055 times.
✓ Branch 218 → 223 taken 222 times.
✓ Branch 219 → 220 taken 24055 times.
✓ Branch 220 → 221 taken 23832 times.
✓ Branch 220 → 223 taken 223 times.
✓ Branch 222 → 223 taken 4 times.
✓ Branch 222 → 226 taken 23828 times.
✓ Branch 224 → 225 taken 305 times.
✓ Branch 224 → 226 taken 144 times.
✓ Branch 227 → 228 taken 305 times.
✓ Branch 227 → 249 taken 23972 times.
|
24726 | if ((!node.contentId.isEmpty() || !node.remoteUrl.isEmpty() || !node.imageData.isEmpty()) && |
| 511 | 449 | result.imageReferences.size() < NativeMailDocument::MaxImageReferences) { | |
| 512 |
1/1✓ Branch 233 → 234 taken 305 times.
|
610 | const QString marker = QStringLiteral("<!--mailjd-native-image-%1-->").arg(result.imageReferences.size()); |
| 513 | 305 | result.imageReferences.append({marker, node.contentId, node.remoteUrl, node.imageData, node.imageType, | |
| 514 | 758 | state.compose ? node.text : QString(), node.imageWidth, node.imageHeight}); | |
| 515 |
1/1✓ Branch 246 → 247 taken 305 times.
|
305 | output += marker; |
| 516 | 305 | } | |
| 517 |
11/11✓ Branch 249 → 250 taken 13310 times.
✓ Branch 249 → 256 taken 10967 times.
✓ Branch 251 → 252 taken 13298 times.
✓ Branch 251 → 257 taken 12 times.
✓ Branch 252 → 253 taken 13298 times.
✓ Branch 253 → 254 taken 13094 times.
✓ Branch 253 → 257 taken 204 times.
✓ Branch 255 → 256 taken 13090 times.
✓ Branch 255 → 257 taken 4 times.
✓ Branch 258 → 259 taken 24057 times.
✓ Branch 258 → 263 taken 220 times.
|
24277 | if (!(state.compose && (!node.contentId.isEmpty() || !node.remoteUrl.isEmpty() || !node.imageData.isEmpty()))) |
| 518 |
2/2✓ Branch 259 → 260 taken 24057 times.
✓ Branch 260 → 261 taken 24057 times.
|
24057 | output += node.text.toHtmlEscaped(); |
| 519 |
2/2✓ Branch 269 → 265 taken 51616 times.
✓ Branch 269 → 270 taken 24277 times.
|
75893 | for (int child : node.children) |
| 520 |
1/1✓ Branch 266 → 267 taken 51616 times.
|
51616 | emitNode(child, flatTable, tableDepth, region); |
| 521 |
6/6✓ Branch 271 → 272 taken 23897 times.
✓ Branch 271 → 275 taken 380 times.
✓ Branch 273 → 274 taken 23896 times.
✓ Branch 273 → 275 taken 1 time.
✓ Branch 276 → 277 taken 23896 times.
✓ Branch 276 → 284 taken 381 times.
|
24277 | if (tag != "br" && tag != "hr") |
| 522 |
3/3✓ Branch 278 → 279 taken 23896 times.
✓ Branch 279 → 280 taken 23896 times.
✓ Branch 280 → 281 taken 23896 times.
|
23896 | output += "</" + tag + '>'; |
| 523 |
8/8✓ Branch 284 → 285 taken 5090 times.
✓ Branch 284 → 290 taken 19187 times.
✓ Branch 286 → 287 taken 1350 times.
✓ Branch 286 → 289 taken 3740 times.
✓ Branch 288 → 289 taken 3 times.
✓ Branch 288 → 290 taken 1347 times.
✓ Branch 291 → 292 taken 3743 times.
✓ Branch 291 → 293 taken 20534 times.
|
24277 | if (flatTable && (node.tag == "td" || node.tag == "th")) |
| 524 |
1/1✓ Branch 292 → 293 taken 3743 times.
|
3743 | output += " | "; |
| 525 |
4/16✓ Branch 85 → 86 taken 584 times.
✓ Branch 241 → 242 taken 148 times.
✓ Branch 241 → 243 taken 157 times.
✓ Branch 244 → 245 taken 305 times.
✗ Branch 403 → 404 not taken.
✗ Branch 403 → 405 not taken.
✗ Branch 406 → 407 not taken.
✗ Branch 406 → 408 not taken.
✗ Branch 409 → 410 not taken.
✗ Branch 409 → 411 not taken.
✗ Branch 412 → 413 not taken.
✗ Branch 412 → 414 not taken.
✗ Branch 415 → 416 not taken.
✗ Branch 415 → 417 not taken.
✗ Branch 418 → 419 not taken.
✗ Branch 418 → 420 not taken.
|
25166 | }; |
| 526 |
5/5✓ Branch 86 → 87 taken 584 times.
✓ Branch 87 → 88 taken 584 times.
✓ Branch 88 → 89 taken 584 times.
✓ Branch 94 → 90 taken 706 times.
✓ Branch 94 → 95 taken 584 times.
|
1290 | for (int child : state.nodes[0].children) |
| 527 |
1/1✓ Branch 91 → 92 taken 706 times.
|
706 | emitNode(child, false, 0, 0); |
| 528 |
3/3✓ Branch 95 → 96 taken 584 times.
✓ Branch 96 → 97 taken 1 time.
✓ Branch 96 → 102 taken 583 times.
|
584 | if (state.interrupted()) { |
| 529 |
1/2✓ Branch 97 → 98 taken 1 time.
✗ Branch 97 → 99 not taken.
|
1 | result.outcome = state.wasCancelled ? Outcome::Cancelled : Outcome::Limited; |
| 530 |
1/1✓ Branch 100 → 101 taken 1 time.
|
1 | result.imageReferences.clear(); |
| 531 | 1 | return result; | |
| 532 | } | ||
| 533 | 583 | result.html = output; | |
| 534 | 583 | result.simplified = state.simplified; | |
| 535 | 583 | return result; | |
| 536 | 600 | } | |
| 537 |