Qt
Internal/Contributor docs for the Qt SDK. <b>Note:</b> These are NOT official API docs; those are found <a href='https://doc.qt.io/'>here</a>.
Loading...
Searching...
No Matches
qsvgvisitorimpl.cpp
Go to the documentation of this file.
1// Copyright (C) 2024 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qsvgvisitorimpl_p.h"
5#include "qquickgenerator_p.h"
6#include "qquicknodeinfo_p.h"
7
8#include <private/qsvgvisitor_p.h>
9
10#include <QString>
11#include <QPainter>
12#include <QTextDocument>
13#include <QTextLayout>
14#include <QMatrix4x4>
15#include <QQuickItem>
16
17#include <private/qquickshape_p.h>
18#include <private/qquicktext_p.h>
19#include <private/qquicktranslate_p.h>
20#include <private/qquickitem_p.h>
21
22#include <private/qquickimagebase_p_p.h>
23#include <private/qquickimage_p.h>
24#include <private/qsgcurveprocessor_p.h>
25
26#include <private/qquadpath_p.h>
27
28#include "utils_p.h"
29#include <QtCore/qloggingcategory.h>
30
32
33using namespace Qt::StringLiterals;
34
35Q_DECLARE_LOGGING_CATEGORY(lcQuickVectorImage)
36
38{
39public:
41 {
42 m_dummyImage = QImage(1, 1, QImage::Format_RGB32);
43 m_dummyPainter.begin(&m_dummyImage);
45 defaultPen.setMiterLimit(4);
46 m_dummyPainter.setPen(defaultPen);
47 m_dummyPainter.setBrush(Qt::black);
48 }
49
51 {
52 m_dummyPainter.end();
53 }
54
55 QPainter& painter() { return m_dummyPainter; }
56 QSvgExtraStates& states() { return m_svgState; }
57
59 {
60 if (m_dummyPainter.brush().style() == Qt::NoBrush ||
61 m_dummyPainter.brush().color() == QColorConstants::Transparent) {
63 }
64
65 QColor fillColor;
66 fillColor = m_dummyPainter.brush().color();
67 fillColor.setAlphaF(m_svgState.fillOpacity);
68
69 return fillColor;
70 }
71
73 {
74 return m_svgState.fillOpacity;
75 }
76
78 {
79 if (m_dummyPainter.brush().style() == Qt::LinearGradientPattern || m_dummyPainter.brush().style() == Qt::RadialGradientPattern || m_dummyPainter.brush().style() == Qt::ConicalGradientPattern )
80 return m_dummyPainter.brush().gradient();
81 return nullptr;
82 }
83
85 {
86 if (m_dummyPainter.pen().brush().style() == Qt::NoBrush ||
87 m_dummyPainter.pen().brush().color() == QColorConstants::Transparent) {
89 }
90
91 QColor strokeColor;
92 strokeColor = m_dummyPainter.pen().brush().color();
93 strokeColor.setAlphaF(m_svgState.strokeOpacity);
94
95 return strokeColor;
96 }
97
98 static QGradient applyOpacityToGradient(const QGradient &gradient, float opacity)
99 {
100 QGradient grad = gradient;
101 QGradientStops stops;
102 for (auto &stop : grad.stops()) {
103 stop.second.setAlphaF(stop.second.alphaF() * opacity);
104 stops.append(stop);
105 }
106
107 grad.setStops(stops);
108
109 return grad;
110 }
111
112 float currentStrokeWidth() const
113 {
114 float penWidth = m_dummyPainter.pen().widthF();
115 return penWidth ? penWidth : 1;
116 }
117
119 {
120 return m_dummyPainter.pen();
121 }
122
123protected:
127};
128
130
131namespace {
132inline bool isPathContainer(const QSvgStructureNode *node)
133{
134 bool foundPath = false;
135 for (const auto *child : node->renderers()) {
136 switch (child->type()) {
137 // nodes that shouldn't go inside Shape{}
138 case QSvgNode::Switch:
139 case QSvgNode::Doc:
140 case QSvgNode::Group:
142 case QSvgNode::Use:
143 case QSvgNode::Video:
144 //qCDebug(lcQuickVectorGraphics) << "NOT path container because" << node->typeName() ;
145 return false;
146
147 // nodes that could go inside Shape{}
148 case QSvgNode::Defs:
149 case QSvgNode::Image:
151 case QSvgNode::Text:
152 case QSvgNode::Tspan:
153 break;
154
155 // nodes that are done as pure ShapePath{}
156 case QSvgNode::Rect:
157 case QSvgNode::Circle:
159 case QSvgNode::Line:
160 case QSvgNode::Path:
163 if (!child->style().transform.isDefault()) {
164 //qCDebug(lcQuickVectorGraphics) << "NOT path container because local transform";
165 return false;
166 }
167 foundPath = true;
168 break;
169 default:
170 qCDebug(lcQuickVectorImage) << "Unhandled type in switch" << child->type();
171 break;
172 }
173 }
174 //qCDebug(lcQuickVectorGraphics) << "Container" << node->nodeId() << node->typeName() << "is" << foundPath;
175 return foundPath;
176}
177
178void populateStrokeStyle(StrokeStyle &srokeStyle)
179{
180 QPen p = styleResolver->currentStroke();
181 srokeStyle.lineCapStyle = p.capStyle();
182 srokeStyle.lineJoinStyle = p.joinStyle() == Qt::SvgMiterJoin ? Qt::MiterJoin : p.joinStyle(); //TODO support SvgMiterJoin
183 srokeStyle.miterLimit = p.miterLimit();
184 srokeStyle.dashOffset = p.dashOffset();
185 srokeStyle.dashArray = p.dashPattern();
186 srokeStyle.color = styleResolver->currentStrokeColor();
187 srokeStyle.width = p.widthF();
188}
189
190};
191
193 : m_svgFileName(svgFileName)
194 , m_generator(generator)
195{
196}
197
199{
200 if (!m_generator) {
201 qCDebug(lcQuickVectorImage) << "No valid QQuickGenerator is set. Genration will stop";
202 return;
203 }
204
205 auto *doc = QSvgTinyDocument::load(m_svgFileName);
206 if (!doc) {
207 qCDebug(lcQuickVectorImage) << "Not a valid Svg File : " << m_svgFileName;
208 return;
209 }
210
212}
213
215{
216 handleBaseNodeSetup(node);
217
219 fillCommonNodeInfo(node, info);
220
221 m_generator->generateNode(info);
222
223 handleBaseNodeEnd(node);
224}
225
227{
228 // TODO: this requires proper asset management.
229 handleBaseNodeSetup(node);
230
232 fillCommonNodeInfo(node, info);
233 info.image = node->image();
234 info.rect = node->rect();
235 info.externalFileReference = node->filename();
236
237 m_generator->generateImageNode(info);
238
239 handleBaseNodeEnd(node);
240}
241
243{
244 QRectF rect = node->rect();
245 QPointF rads = node->radius();
246 // This is using Qt::RelativeSize semantics: percentage of half rect size
247 qreal x1 = rect.left();
248 qreal x2 = rect.right();
249 qreal y1 = rect.top();
250 qreal y2 = rect.bottom();
251
252 qreal rx = rads.x() * rect.width() / 200;
253 qreal ry = rads.y() * rect.height() / 200;
255
256 p.moveTo(x1 + rx, y1);
257 p.lineTo(x2 - rx, y1);
258 // qCDebug(lcQuickVectorGraphics) << "Line1" << x2 - rx << y1;
259 p.arcTo(x2 - rx * 2, y1, rx * 2, ry * 2, 90, -90); // ARC to x2, y1 + ry
260 // qCDebug(lcQuickVectorGraphics) << "p1" << p;
261
262 p.lineTo(x2, y2 - ry);
263 p.arcTo(x2 - rx * 2, y2 - ry * 2, rx * 2, ry * 2, 0, -90); // ARC to x2 - rx, y2
264
265 p.lineTo(x1 + rx, y2);
266 p.arcTo(x1, y2 - ry * 2, rx * 2, ry * 2, 270, -90); // ARC to x1, y2 - ry
267
268 p.lineTo(x1, y1 + ry);
269 p.arcTo(x1, y1, rx * 2, ry * 2, 180, -90); // ARC to x1 + rx, y1
270
271 handlePathNode(node, p);
272}
273
275{
276 QRectF rect = node->rect();
277
280
281 handlePathNode(node, p);
282}
283
285{
286 handlePathNode(node, node->path());
287}
288
290{
292 p.moveTo(node->line().p1());
293 p.lineTo(node->line().p2());
294 handlePathNode(node, p);
295}
296
298{
300 handlePathNode(node, p);
301}
302
304{
306 handlePathNode(node, p);
307}
308
309QString QSvgVisitorImpl::gradientCssDescription(const QGradient *gradient)
310{
311 QString cssDescription;
312 if (gradient->type() == QGradient::LinearGradient) {
313 const QLinearGradient *linearGradient = static_cast<const QLinearGradient *>(gradient);
314
315 cssDescription += " -qt-foreground: qlineargradient("_L1;
316 cssDescription += "x1:"_L1 + QString::number(linearGradient->start().x()) + u',';
317 cssDescription += "y1:"_L1 + QString::number(linearGradient->start().y()) + u',';
318 cssDescription += "x2:"_L1 + QString::number(linearGradient->finalStop().x()) + u',';
319 cssDescription += "y2:"_L1 + QString::number(linearGradient->finalStop().y()) + u',';
320 } else if (gradient->type() == QGradient::RadialGradient) {
321 const QRadialGradient *radialGradient = static_cast<const QRadialGradient *>(gradient);
322
323 cssDescription += " -qt-foreground: qradialgradient("_L1;
324 cssDescription += "cx:"_L1 + QString::number(radialGradient->center().x()) + u',';
325 cssDescription += "cy:"_L1 + QString::number(radialGradient->center().y()) + u',';
326 cssDescription += "fx:"_L1 + QString::number(radialGradient->focalPoint().x()) + u',';
327 cssDescription += "fy:"_L1 + QString::number(radialGradient->focalPoint().y()) + u',';
328 cssDescription += "radius:"_L1 + QString::number(radialGradient->radius()) + u',';
329 } else {
330 const QConicalGradient *conicalGradient = static_cast<const QConicalGradient *>(gradient);
331
332 cssDescription += " -qt-foreground: qconicalgradient("_L1;
333 cssDescription += "cx:"_L1 + QString::number(conicalGradient->center().x()) + u',';
334 cssDescription += "cy:"_L1 + QString::number(conicalGradient->center().y()) + u',';
335 cssDescription += "angle:"_L1 + QString::number(conicalGradient->angle()) + u',';
336 }
337
338 const QStringList coordinateModes = { "logical"_L1, "stretchtodevice"_L1, "objectbounding"_L1, "object"_L1 };
339 cssDescription += "coordinatemode:"_L1;
340 cssDescription += coordinateModes.at(int(gradient->coordinateMode()));
341 cssDescription += u',';
342
343 const QStringList spreads = { "pad"_L1, "reflect"_L1, "repeat"_L1 };
344 cssDescription += "spread:"_L1;
345 cssDescription += spreads.at(int(gradient->spread()));
346
347 for (const QGradientStop &stop : gradient->stops()) {
348 cssDescription += ",stop:"_L1;
349 cssDescription += QString::number(stop.first);
350 cssDescription += u' ';
351 cssDescription += stop.second.name(QColor::HexArgb);
352 }
353
354 cssDescription += ");"_L1;
355
356 return cssDescription;
357}
358
359QString QSvgVisitorImpl::colorCssDescription(QColor color)
360{
361 QString cssDescription;
362 cssDescription += QStringLiteral("rgba(");
363 cssDescription += QString::number(color.red()) + QStringLiteral(",");
364 cssDescription += QString::number(color.blue()) + QStringLiteral(",");
365 cssDescription += QString::number(color.green()) + QStringLiteral(",");
366 cssDescription += QString::number(color.alphaF()) + QStringLiteral(")");
367
368 return cssDescription;
369}
370
372{
373 handleBaseNodeSetup(node);
374 const bool isTextArea = node->type() == QSvgNode::Textarea;
375
377 bool needsRichText = false;
378 bool preserveWhiteSpace = node->whitespaceMode() == QSvgText::Preserve;
379 const QGradient *mainGradient = styleResolver->currentFillGradient();
380#if QT_CONFIG(texthtmlparser)
381 bool needsPathNode = mainGradient != nullptr;
382#endif
383 for (const auto *tspan : node->tspans()) {
384 if (!tspan) {
385 text += QStringLiteral("<br>");
386 continue;
387 }
388
389 // Note: We cannot get the font directly from the style, since this does
390 // not apply the weight, since this is relative and depends on current state.
391 handleBaseNodeSetup(tspan);
392 QFont font = styleResolver->painter().font();
393
394 QString styleTagContent;
395
398 styleTagContent += QStringLiteral("font-family: %1;").arg(font.family());
399 }
400
403 && font.weight() != QFont::Bold) {
404 styleTagContent += QStringLiteral("font-weight: %1;").arg(int(font.weight()));
405 }
406
408 // Pixel size stored as point size in SVG parser
409 styleTagContent += QStringLiteral("font-size: %1px;").arg(int(font.pointSizeF()));
410 }
411
414 styleTagContent += QStringLiteral("font-variant: small-caps;");
415 }
416
417 if (styleResolver->currentFillGradient() != nullptr
418 && styleResolver->currentFillGradient() != mainGradient) {
419 const QGradient grad = styleResolver->applyOpacityToGradient(*styleResolver->currentFillGradient(), styleResolver->currentFillOpacity());
420 styleTagContent += gradientCssDescription(&grad) + u';';
421#if QT_CONFIG(texthtmlparser)
422 needsPathNode = true;
423#endif
424 }
425
426 QString strokeColor = colorCssDescription(styleResolver->currentStrokeColor());
427 if (!strokeColor.isEmpty()) {
428 styleTagContent += QStringLiteral("-qt-stroke-color:%1;").arg(strokeColor);
429 styleTagContent += QStringLiteral("-qt-stroke-width:%1;").arg(styleResolver->currentStrokeWidth());
430#if QT_CONFIG(texthtmlparser)
431 needsPathNode = true;
432#endif
433 }
434
435 if (tspan->whitespaceMode() == QSvgText::Preserve && !preserveWhiteSpace)
436 styleTagContent += QStringLiteral("white-space: pre-wrap;");
437
438 QString content = tspan->text().toHtmlEscaped();
439 content.replace(QLatin1Char('\t'), QLatin1Char(' '));
440 content.replace(QLatin1Char('\n'), QLatin1Char(' '));
441
442 bool fontTag = false;
443 if (!tspan->style().fill.isDefault()) {
444 auto &b = tspan->style().fill->qbrush();
445 qCDebug(lcQuickVectorImage) << "tspan FILL:" << b;
446 if (b.style() != Qt::NoBrush)
447 {
448 if (qFuzzyCompare(b.color().alphaF() + 1.0, 2.0))
449 {
450 QString spanColor = b.color().name();
451 fontTag = !spanColor.isEmpty();
452 if (fontTag)
453 text += QStringLiteral("<font color=\"%1\">").arg(spanColor);
454 } else {
455 QString spanColor = colorCssDescription(b.color());
456 styleTagContent += QStringLiteral("color:%1").arg(spanColor);
457 }
458 }
459 }
460
461 needsRichText = needsRichText || !styleTagContent.isEmpty();
462 if (!styleTagContent.isEmpty())
463 text += QStringLiteral("<span style=\"%1\">").arg(styleTagContent);
464
466 text += QStringLiteral("<b>");
467
469 text += QStringLiteral("<i>");
470
471
473 switch (font.capitalization()) {
475 content = content.toLower();
476 break;
478 content = content.toUpper();
479 break;
481 // ### We need to iterate over the string and do the title case conversion,
482 // since this is not part of QString.
483 qCWarning(lcQuickVectorImage) << "Title case not implemented for tspan";
484 break;
485 default:
486 break;
487 }
488 }
489 text += content;
490 if (fontTag)
491 text += QStringLiteral("</font>");
492
494 text += QStringLiteral("</i>");
495
497 text += QStringLiteral("</b>");
498
499 if (!styleTagContent.isEmpty())
500 text += QStringLiteral("</span>");
501
502 handleBaseNodeEnd(tspan);
503 }
504
505 if (preserveWhiteSpace && (needsRichText || styleResolver->currentFillGradient() != nullptr))
506 text = QStringLiteral("<span style=\"white-space: pre-wrap\">") + text + QStringLiteral("</span>");
507
508 QFont font = styleResolver->painter().font();
509 if (font.pixelSize() <= 0 && font.pointSize() > 0)
510 font.setPixelSize(font.pointSize()); // Pixel size stored as point size by SVG parser
511
512#if QT_CONFIG(texthtmlparser)
513 if (needsPathNode) {
514 QTextDocument document;
515 document.setHtml(text);
516 if (isTextArea && node->size().width() > 0)
517 document.setTextWidth(node->size().width());
518 document.setDefaultFont(font);
519 document.pageCount(); // Force layout
520
521 QTextBlock block = document.firstBlock();
522 while (block.isValid()) {
523 QTextLayout *lout = block.layout();
524
525 if (lout != nullptr) {
526 auto addPathForFormat = [&](QPainterPath p, QTextCharFormat fmt) {
528 fillCommonNodeInfo(node, info);
529 auto fillStyle = node->style().fill;
530 if (fillStyle)
531 info.fillRule = fillStyle->fillRule();
532
533 if (fmt.hasProperty(QTextCharFormat::ForegroundBrush)) {
534 info.fillColor = fmt.foreground().color();
535 if (fmt.foreground().gradient() != nullptr && fmt.foreground().gradient()->type() != QGradient::NoGradient)
536 info.grad = *fmt.foreground().gradient();
537 } else {
538 info.fillColor = styleResolver->currentFillColor();
539 }
540
541 info.painterPath = p;
542
543 if (fmt.hasProperty(QTextCharFormat::TextOutline)) {
544 info.strokeStyle.width = fmt.textOutline().widthF();
545 info.strokeStyle.color = fmt.textOutline().color();
546 } else {
547 info.strokeStyle.color = styleResolver->currentStrokeColor();
548 info.strokeStyle.width = styleResolver->currentStrokeWidth();
549 }
550
551 if (info.grad.type() == QGradient::NoGradient && styleResolver->currentFillGradient() != nullptr)
552 info.grad = styleResolver->applyOpacityToGradient(*styleResolver->currentFillGradient(), styleResolver->currentFillOpacity());
553
554 m_generator->generatePath(info);
555 };
556
557 qreal baselineOffset = -QFontMetricsF(font).ascent();
558 if (lout->lineCount() > 0 && lout->lineAt(0).isValid())
559 baselineOffset = -lout->lineAt(0).ascent();
560
561 const QPointF baselineTranslation(0.0, baselineOffset);
562 auto glyphsToPath = [&](QList<QGlyphRun> glyphRuns) {
564 path.setFillRule(Qt::WindingFill);
565 for (const QGlyphRun &glyphRun : glyphRuns) {
566 QRawFont font = glyphRun.rawFont();
567 QList<quint32> glyphIndexes = glyphRun.glyphIndexes();
568 QList<QPointF> positions = glyphRun.positions();
569
570 for (qsizetype j = 0; j < glyphIndexes.size(); ++j) {
571 quint32 glyphIndex = glyphIndexes.at(j);
572 const QPointF &pos = positions.at(j);
573
574 QPainterPath p = font.pathForGlyph(glyphIndex);
575 p.translate(pos + node->position() + baselineTranslation);
576 path.addPath(p);
577 }
578 }
579
580 return path;
581 };
582
583 QList<QTextLayout::FormatRange> formats = block.textFormats();
584 for (int i = 0; i < formats.size(); ++i) {
586
587 // If we hit a "multi" anchor, it means we have additional formats to apply
588 // for both this and the subsequent range, so we merge them.
589 if (!range.format.anchorNames().isEmpty()
590 && range.format.anchorNames().first().startsWith(QStringLiteral("multi"))
591 && i < formats.size() - 1) {
592 QTextLayout::FormatRange nextRange = formats.at(++i);
593 range.length += nextRange.length;
594 range.format.merge(nextRange.format);
595 }
596 QList<QGlyphRun> glyphRuns = lout->glyphRuns(range.start, range.length);
597 QPainterPath path = glyphsToPath(glyphRuns);
598 addPathForFormat(path, range.format);
599 }
600 }
601
602 block = block.next();
603 }
604 } else
605#endif
606 {
608 fillCommonNodeInfo(node, info);
609
610 info.position = node->position();
611 info.size = node->size();
612 info.font = font;
613 info.text = text;
614 info.isTextArea = isTextArea;
615 info.needsRichText = needsRichText;
616 info.fillColor = styleResolver->currentFillColor();
617 info.alignment = styleResolver->states().textAnchor;
618 info.strokeColor = styleResolver->currentStrokeColor();
619
620 m_generator->generateTextNode(info);
621 }
622
623 handleBaseNodeEnd(node);
624}
625
627{
628 QSvgNode *link = node->link();
629 if (!link)
630 return;
631
632 handleBaseNodeSetup(node);
634 fillCommonNodeInfo(node, info);
635
637 info.startPos = node->start();
638
639 m_generator->generateUseNode(info);
640
642
644 m_generator->generateUseNode(info);
645 handleBaseNodeEnd(node);
646}
647
649{
650 Q_UNUSED(node)
651
652 return m_generator->generateDefsNode(NodeInfo{});
653}
654
656{
657 constexpr bool forceSeparatePaths = false;
658 handleBaseNodeSetup(node);
659
661
662 fillCommonNodeInfo(node, info);
663 info.forceSeparatePaths = forceSeparatePaths;
664 info.isPathContainer = isPathContainer(node);
666
667 return m_generator->generateStructureNode(info);;
668}
669
671{
672 handleBaseNodeEnd(node);
673 // qCDebug(lcQuickVectorGraphics) << "REVERT" << node->nodeId() << node->type() << (m_styleResolver->painter().pen().style() != Qt::NoPen) << m_styleResolver->painter().pen().color().name()
674 // << (m_styleResolver->painter().pen().brush().style() != Qt::NoBrush) << m_styleResolver->painter().pen().brush().color().name();
675
677 fillCommonNodeInfo(node, info);
679
680 m_generator->generateStructureNode(info);
681}
682
684{
685 handleBaseNodeSetup(node);
686
688 fillCommonNodeInfo(node, info);
689
690 const QSvgTinyDocument *doc = static_cast<const QSvgTinyDocument *>(node);
691 info.size = doc->size();
692 info.viewBox = doc->viewBox();
693 info.isPathContainer = isPathContainer(node);
695
696 return m_generator->generateRootNode(info);;
697}
698
700{
701 handleBaseNodeEnd(node);
702 qCDebug(lcQuickVectorImage) << "REVERT" << node->nodeId() << node->type() << (styleResolver->painter().pen().style() != Qt::NoPen)
703 << styleResolver->painter().pen().color().name() << (styleResolver->painter().pen().brush().style() != Qt::NoBrush)
704 << styleResolver->painter().pen().brush().color().name();
705
707 fillCommonNodeInfo(node, info);
709
710 m_generator->generateRootNode(info);
711}
712
713void QSvgVisitorImpl::fillCommonNodeInfo(const QSvgNode *node, NodeInfo &info)
714{
715 info.nodeId = node->nodeId();
716 info.typeName = node->typeName();
717 info.isDefaultTransform = node->style().transform.isDefault();
718 info.transform = !info.isDefaultTransform ? node->style().transform->qtransform() : QTransform();
719 info.isDefaultOpacity = node->style().opacity.isDefault();
720 info.opacity = !info.isDefaultOpacity ? node->style().opacity->opacity() : 1.0;
721 info.isVisible = node->isVisible();
722 info.isDisplayed = node->displayMode() != QSvgNode::DisplayMode::NoneMode;
723}
724
725void QSvgVisitorImpl::handleBaseNodeSetup(const QSvgNode *node)
726{
727 qCDebug(lcQuickVectorImage) << "Before SETUP" << node << "fill" << styleResolver->currentFillColor()
728 << "stroke" << styleResolver->currentStrokeColor() << styleResolver->currentStrokeWidth()
729 << node->nodeId() << " type: " << node->typeName() << " " << node->type();
730
731 node->applyStyle(&styleResolver->painter(), styleResolver->states());
732
733 qCDebug(lcQuickVectorImage) << "After SETUP" << node << "fill" << styleResolver->currentFillColor()
734 << "stroke" << styleResolver->currentStrokeColor()
735 << styleResolver->currentStrokeWidth() << node->nodeId();
736}
737
738void QSvgVisitorImpl::handleBaseNode(const QSvgNode *node)
739{
741 fillCommonNodeInfo(node, info);
742
743 m_generator->generateNodeBase(info);
744}
745
746void QSvgVisitorImpl::handleBaseNodeEnd(const QSvgNode *node)
747{
748 node->revertStyle(&styleResolver->painter(), styleResolver->states());
749
750 qCDebug(lcQuickVectorImage) << "After END" << node << "fill" << styleResolver->currentFillColor()
751 << "stroke" << styleResolver->currentStrokeColor() << styleResolver->currentStrokeWidth()
752 << node->nodeId();
753}
754
755void QSvgVisitorImpl::handlePathNode(const QSvgNode *node, const QPainterPath &path)
756{
757 handleBaseNodeSetup(node);
758
760 fillCommonNodeInfo(node, info);
761 auto fillStyle = node->style().fill;
762 if (fillStyle)
763 info.fillRule = fillStyle->fillRule();
764
765 info.painterPath = path;
766 info.fillColor = styleResolver->currentFillColor();
767 populateStrokeStyle(info.strokeStyle);
768 if (styleResolver->currentFillGradient() != nullptr)
769 info.grad = styleResolver->applyOpacityToGradient(*styleResolver->currentFillGradient(), styleResolver->currentFillOpacity());
770
771 m_generator->generatePath(info);
772
773 handleBaseNodeEnd(node);
774}
775
The QColor class provides colors based on RGB, HSV or CMYK values.
Definition qcolor.h:31
void setAlphaF(float alpha)
Sets the alpha of this color to alpha.
Definition qcolor.cpp:1511
@ HexArgb
Definition qcolor.h:36
\inmodule QtGui
Definition qbrush.h:446
\reentrant \inmodule QtGui
qreal ascent() const
Returns the ascent of the font.
\reentrant
Definition qfont.h:22
QString family() const
Returns the requested font family name.
Definition qfont.cpp:817
int pixelSize() const
Returns the pixel size of the font if it was set with setPixelSize().
Definition qfont.cpp:1074
bool italic() const
Returns true if the style() of the font is not QFont::StyleNormal.
Definition qfont.h:376
@ AllLowercase
Definition qfont.h:100
@ AllUppercase
Definition qfont.h:99
@ Capitalize
Definition qfont.h:102
@ SmallCaps
Definition qfont.h:101
Capitalization capitalization() const
Definition qfont.cpp:1743
Weight weight() const
Returns the weight of the font, using the same scale as the \l{QFont::Weight} enumeration.
Definition qfont.cpp:1133
@ SizeResolved
Definition qfont.h:115
@ FamilyResolved
Definition qfont.h:114
@ WeightResolved
Definition qfont.h:118
@ CapitalizationResolved
Definition qfont.h:126
@ StyleResolved
Definition qfont.h:119
@ FamiliesResolved
Definition qfont.h:131
int pointSize() const
Returns the point size of the font.
Definition qfont.cpp:884
void setPixelSize(int)
Sets the font size to pixelSize pixels, with a maxiumum size of an unsigned 16-bit integer.
Definition qfont.cpp:1049
uint resolveMask() const
Definition qfont.h:312
bool bold() const
Returns true if weight() is a value greater than \l{Weight}{QFont::Medium}; otherwise returns false.
Definition qfont.h:369
qreal pointSizeF() const
Returns the point size of the font.
Definition qfont.cpp:1034
@ Bold
Definition qfont.h:70
@ Normal
Definition qfont.h:67
The QGlyphRun class provides direct access to the internal glyphs in a font.
Definition qglyphrun.h:20
\inmodule QtGui
Definition qbrush.h:135
Spread spread() const
Returns the spread method use by this gradient.
Definition qbrush.h:347
CoordinateMode coordinateMode() const
Definition qbrush.cpp:1672
void setStops(const QGradientStops &stops)
Replaces the current set of stop points with the given stopPoints.
Definition qbrush.cpp:1608
Type type() const
Returns the type of gradient.
Definition qbrush.h:344
QGradientStops stops() const
Returns the stop points for this gradient.
Definition qbrush.cpp:1631
@ LinearGradient
Definition qbrush.h:139
@ NoGradient
Definition qbrush.h:142
@ RadialGradient
Definition qbrush.h:140
\inmodule QtGui
Definition qimage.h:37
@ Format_RGB32
Definition qimage.h:46
constexpr QPointF p1() const
Returns the line's start point.
Definition qline.h:317
constexpr QPointF p2() const
Returns the line's end point.
Definition qline.h:322
\inmodule QtGui
Definition qbrush.h:394
void append(parameter_type t)
Definition qlist.h:458
\inmodule QtGui
void moveTo(const QPointF &p)
Moves the current point to the given point, implicitly starting a new subpath and closing the previou...
void addEllipse(const QRectF &rect)
Creates an ellipse within the specified boundingRectangle and adds it to the painter path as a closed...
The QPainter class performs low-level painting on widgets and other paint devices.
Definition qpainter.h:46
\inmodule QtGui
Definition qpen.h:28
Qt::PenCapStyle capStyle() const
Returns the pen's cap style.
Definition qpen.cpp:636
void setMiterLimit(qreal limit)
Sets the miter limit of this pen to the given limit.
Definition qpen.cpp:545
\inmodule QtCore\reentrant
Definition qpoint.h:217
virtual void generatePath(const PathNodeInfo &info)=0
virtual bool generateRootNode(const StructureNodeInfo &info)=0
virtual void generateNodeBase(const NodeInfo &info)=0
virtual bool generateStructureNode(const StructureNodeInfo &info)=0
virtual void generateNode(const NodeInfo &info)=0
virtual bool generateDefsNode(const NodeInfo &info)=0
virtual void generateImageNode(const ImageNodeInfo &info)=0
virtual void generateTextNode(const TextNodeInfo &info)=0
virtual void generateUseNode(const UseNodeInfo &info)=0
\inmodule QtGui
Definition qbrush.h:412
The QRawFont class provides access to a single physical instance of a font.
Definition qrawfont.h:24
\inmodule QtCore\reentrant
Definition qrect.h:484
constexpr qreal width() const noexcept
Returns the width.
Definition qsize.h:332
\inmodule QtCore
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:129
QString & fill(QChar c, qsizetype size=-1)
Sets every character in the string to character ch.
Definition qstring.cpp:6358
QString & replace(qsizetype i, qsizetype len, QChar after)
Definition qstring.cpp:3824
bool isEmpty() const noexcept
Returns true if the string has no characters; otherwise returns false.
Definition qstring.h:192
QString toLower() const &
Definition qstring.h:435
static QString number(int, int base=10)
This is an overloaded member function, provided for convenience. It differs from the above function o...
Definition qstring.cpp:8084
QString toUpper() const &
Definition qstring.h:439
QString toHtmlEscaped() const
QRectF rect() const
const QImage & image() const
QRectF rect() const
QString filename() const
QLineF line() const
void revertStyle(QPainter *p, QSvgExtraStates &states) const
Definition qsvgnode.cpp:253
QString typeName() const
Definition qsvgnode.cpp:384
void applyStyle(QPainter *p, QSvgExtraStates &states) const
Definition qsvgnode.cpp:232
DisplayMode displayMode() const
Definition qsvgnode.cpp:599
QString nodeId() const
Definition qsvgnode_p.h:212
const QSvgStyle & style() const
Definition qsvgnode_p.h:169
bool isVisible() const
Definition qsvgnode_p.h:207
virtual Type type() const =0
qreal opacity() const
const QPainterPath & path() const
const QPolygonF & polygon() const
const QPolygonF & polygon() const
QPointF radius() const
QRectF rect() const
bool isDefault() const
Definition qsvgstyle_p.h:78
QList< QSvgNode * > renderers() const
const QGradient * currentFillGradient() const
QColor currentFillColor() const
QSvgExtraStates & states()
static QGradient applyOpacityToGradient(const QGradient &gradient, float opacity)
QPen currentStroke() const
qreal currentFillOpacity() const
float currentStrokeWidth() const
QSvgExtraStates m_svgState
QColor currentStrokeColor() const
QSvgRefCounter< QSvgOpacityStyle > opacity
QSvgRefCounter< QSvgTransformStyle > transform
QSvgRefCounter< QSvgFillStyle > fill
QPointF position() const
QSizeF size() const
const QList< QSvgTspan * > tspans() const
WhitespaceMode whitespaceMode() const
Type type() const override
Type type() const override
static QSvgTinyDocument * load(const QString &file, QtSvg::Options options={})
QRectF viewBox() const
const QTransform & qtransform() const
QSvgNode * link() const
QPointF start() const
void visitPolygonNode(const QSvgPolygon *node) override
void visitEllipseNode(const QSvgEllipse *node) override
void visitPathNode(const QSvgPath *node) override
bool visitDefsNodeStart(const QSvgDefs *node) override
QSvgVisitorImpl(const QString svgFileName, QQuickGenerator *generator)
void visitDocumentNodeEnd(const QSvgTinyDocument *node) override
void visitStructureNodeEnd(const QSvgStructureNode *node) override
void visitRectNode(const QSvgRect *node) override
void visitLineNode(const QSvgLine *node) override
void visitNode(const QSvgNode *node) override
void visitPolylineNode(const QSvgPolyline *node) override
void visitUseNode(const QSvgUse *node) override
bool visitDocumentNodeStart(const QSvgTinyDocument *node) override
void visitImageNode(const QSvgImage *node) override
void visitTextNode(const QSvgText *node) override
bool visitStructureNodeStart(const QSvgStructureNode *node) override
void traverse(const QSvgStructureNode *node)
\reentrant
bool isValid() const
Returns true if this text block is valid; otherwise returns false.
QList< QTextLayout::FormatRange > textFormats() const
QTextBlock next() const
Returns the text block in the document after this block, or an empty text block if this is the last o...
QTextLayout * layout() const
Returns the QTextLayout that is used to lay out and display the block's contents.
\reentrant \inmodule QtGui
\reentrant
Definition qtextlayout.h:70
QList< QGlyphRun > glyphRuns(int from=-1, int length=-1, GlyphRunRetrievalFlags flags=DefaultRetrievalFlags) const
This is an overloaded member function, provided for convenience. It differs from the above function o...
int lineCount() const
Returns the number of lines in this text layout.
QTextLine lineAt(int i) const
Returns the {i}-th line of text in this text layout.
bool isValid() const
Returns true if this text line is valid; otherwise returns false.
qreal ascent() const
Returns the line's ascent.
The QTransform class specifies 2D transformations of a coordinate system.
Definition qtransform.h:20
QString text
rect
[4]
EGLint EGLint * formats
constexpr QColor Transparent
Definition qcolor.h:310
QPainterPath polygonToPath(const QPolygonF &poly, bool closed)
Definition utils_p.h:66
Combined button and popup list for selecting options.
@ black
Definition qnamespace.h:30
@ SolidLine
@ NoPen
@ SvgMiterJoin
@ MiterJoin
@ RadialGradientPattern
@ LinearGradientPattern
@ NoBrush
@ ConicalGradientPattern
@ WindingFill
@ FlatCap
QPair< qreal, QColor > QGradientStop
Definition qbrush.h:131
static const QCssKnownValue positions[NumKnownPositionModes - 1]
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
Definition qfloat16.h:333
#define Q_GLOBAL_STATIC(TYPE, NAME,...)
#define qCWarning(category,...)
#define qCDebug(category,...)
#define Q_DECLARE_LOGGING_CATEGORY(name)
GLboolean GLboolean GLboolean b
GLuint GLfloat GLfloat GLfloat GLfloat y1
GLuint GLfloat GLfloat GLfloat x1
GLsizei range
GLuint color
[2]
GLfixed GLfixed GLfixed y2
GLfixed GLfixed x2
GLsizei const GLchar *const * path
GLfloat GLfloat p
[1]
#define QStringLiteral(str)
#define Q_UNUSED(x)
unsigned int quint32
Definition qtypes.h:50
ptrdiff_t qsizetype
Definition qtypes.h:165
double qreal
Definition qtypes.h:187
QVideoFrameFormat::PixelFormat fmt
QRandomGenerator generator(sseq)
p ry()++
p rx()++
QLayoutItem * child
[0]
QHostInfo info
[0]
\inmodule QtCore \reentrant
Definition qchar.h:18
QByteArray name
Definition moc.h:29