📄 q3paintengine_svg.cpp
字号:
index += reg.matchedLength(); }}/*! \internal Push the current drawing attributes on a stack. \sa restoreAttributes()*/void Q3SVGPaintEnginePrivate::saveAttributes(QPainter *pt){ pt->save(); // copy old state Q3SVGPaintEngineState st(*curr); stack.append(st); curr = &stack.last();}/*! \internal Pop the current drawing attributes off the stack. \sa saveAttributes()*/void Q3SVGPaintEnginePrivate::restoreAttributes(QPainter *pt){ pt->restore(); Q_ASSERT(stack.count() > 1); stack.removeLast(); curr = &stack.last();}void Q3SVGPaintEnginePrivate::setStyle(const QString &s, QPainter *pt){ QStringList rules = s.split(QLatin1Char(';'), QString::SkipEmptyParts); QPen pen = pt->pen(); QFont font = pt->font(); QStringList::ConstIterator it = rules.constBegin(); for (; it != rules.constEnd(); it++) { int col = (*it).indexOf(QLatin1Char(':')); if (col > 0) { QString prop = (*it).left(col).simplified(); QString val = (*it).right((*it).length() - col - 1); val = val.toLower().trimmed(); setStyleProperty(prop, val, &pen, &font, &curr->textalign, pt); } } pt->setPen(pen); pt->setFont(font);}void Q3SVGPaintEnginePrivate::setStyleProperty(const QString &prop, const QString &val, QPen *pen, QFont *font, int *talign, QPainter *pt){ if (prop == QLatin1String("stroke")) { if (val == QLatin1String("none")) { pen->setStyle(Qt::NoPen); } else { pen->setColor(parseColor(val)); if (pen->style() == Qt::NoPen) pen->setStyle(Qt::SolidLine); if (pen->width() == 0) pen->setWidth(1); } } else if (prop == QLatin1String("stroke-opacity")) { double opacity = parseLen(val); QColor c = pen->color(); c.setAlpha((int)(opacity*255)); pen->setColor(c); } else if (prop == QLatin1String("fill-opacity")) { double opacity = parseLen(val); QColor c = pt->brush().color(); c.setAlpha((int)(opacity*255)); pt->setBrush(c); } else if (prop == QLatin1String("stroke-width")) { double w = parseLen(val); if (w > 0.0001) pen->setWidth(int(w)); else pen->setStyle(Qt::NoPen); } else if (prop == QLatin1String("stroke-linecap")) { if (val == QLatin1String("butt")) pen->setCapStyle(Qt::FlatCap); else if (val == QLatin1String("round")) pen->setCapStyle(Qt::RoundCap); else if (val == QLatin1String("square")) pen->setCapStyle(Qt::SquareCap); } else if (prop == QLatin1String("stroke-linejoin")) { if (val == QLatin1String("miter")) pen->setJoinStyle(Qt::MiterJoin); else if (val == QLatin1String("round")) pen->setJoinStyle(Qt::RoundJoin); else if (val == QLatin1String("bevel")) pen->setJoinStyle(Qt::BevelJoin); } else if (prop == QLatin1String("stroke-dasharray")) { if (val == QLatin1String("18,6")) pen->setStyle(Qt::DashLine); else if (val == QLatin1String("3")) pen->setStyle(Qt::DotLine); else if (val == QLatin1String("9,6,3,6")) pen->setStyle(Qt::DashDotLine); else if (val == QLatin1String("9,3,3")) pen->setStyle(Qt::DashDotDotLine); } else if (prop == QLatin1String("fill")) { if (val == QLatin1String("none")) pt->setBrush(Qt::NoBrush); else pt->setBrush(parseColor(val)); } else if (prop == QLatin1String("font-size")) { font->setPixelSize(qRound(parseLen(val))); } else if (prop == QLatin1String("font-family")) { font->setFamily(val); } else if (prop == QLatin1String("font-style")) { if (val == QLatin1String("normal")) font->setItalic(false); else if (val == QLatin1String("italic")) font->setItalic(true); else qWarning("QSvgDevice::setStyleProperty: unhandled font-style: %s", val.latin1()); } else if (prop == QLatin1String("font-weight")) { int w = font->weight(); // no exact equivalents so we have to QLatin1String("round") a little bit if (val == QLatin1String("100") || val == QLatin1String("200")) w = QFont::Light; if (val == QLatin1String("300") || val == QLatin1String("400") || val == QLatin1String("normal")) w = QFont::Normal; else if (val == QLatin1String("500") || val == QLatin1String("600")) w = QFont::DemiBold; else if (val == QLatin1String("700") || val == QLatin1String("bold") || val == QLatin1String("800")) w = QFont::Bold; else if (val == QLatin1String("900")) w = QFont::Black; font->setWeight(w); } else if (prop == QLatin1String("text-anchor")) { if (val == QLatin1String("middle")) *talign = Qt::AlignHCenter; else if (val == QLatin1String("end")) *talign = Qt::AlignRight; else *talign = Qt::AlignLeft; }}void Q3SVGPaintEnginePrivate::drawPath(const QString &data, QPainter *pt){ double x0 = 0, y0 = 0; // starting point double x = 0, y = 0; // current point QPointF ctrlPt; QPainterPath path; // resulting path int idx = 0; // current data position int mode = 0, lastMode = 0; // parser state bool relative = false; // e.g. 'h' vs. 'H' QString commands(QLatin1String("MZLHVCSQTA")); // recognized commands int cmdArgs[] = { 2, 0, 2, 1, 1, 6, 4, 4, 2, 7 }; // no of arguments QRegExp reg(QString::fromLatin1("\\s*,?\\s*([+-]?\\d*\\.?\\d*)")); // floating point // detect next command while (idx < data.length()) { QChar ch = data[(int)idx++]; if (ch.isSpace()) continue; QChar chUp = ch.toUpper(); int cmd = commands.indexOf(chUp); if (cmd >= 0) { // switch to new command mode mode = cmd; relative = (ch != chUp); // e.g. 'm' instead of 'M' } else { if (mode && !ch.isLetter()) { cmd = mode; // continue in previous mode idx--; } else { qWarning("Q3SVGPaintEngine::drawPath: Unknown command"); return; } } // read in the required number of arguments const int maxArgs = 7; double arg[maxArgs]; int numArgs = cmdArgs[cmd]; for (int i = 0; i < numArgs; i++) { int pos = reg.indexIn(data, idx); if (pos == -1) { qWarning("Q3SVGPaintEngine::drawPath: Error parsing arguments"); return; } arg[i] = reg.cap(1).toDouble(); idx = pos + reg.matchedLength(); }; // process command double offsetX = relative ? x : 0; // correction offsets double offsetY = relative ? y : 0; // for relative commands switch (mode) { case 0: // 'M' move to x = x0 = arg[0] + offsetX; y = y0 = arg[1] + offsetY; path.moveTo(x0, y0); mode = 2; // -> 'L' break; case 1: // 'Z' close path x = x0; y = y0; path.closeSubpath(); mode = 0; break; case 2: // 'L' line to x = arg[0] + offsetX; y = arg[1] + offsetY; path.lineTo(x, y); break; case 3: // 'H' horizontal line x = arg[0] + offsetX; path.lineTo(x, y); break; case 4: // 'V' vertical line y = arg[0] + offsetY; path.lineTo(x, y); break; case 5: { // 'C' cubic bezier curveto QPointF c1(arg[0]+offsetX, arg[1]+offsetY); QPointF c2(arg[2]+offsetX, arg[3]+offsetY); QPointF e(arg[4]+offsetX, arg[5]+offsetY); path.cubicTo(c1, c2, e); ctrlPt = c2; x = e.x(); y = e.y(); break; } case 6: { // 'S' smooth shorthand QPointF c1; if (lastMode == 5 || lastMode == 6) c1 = QPointF(2*x-ctrlPt.x(), 2*y-ctrlPt.y()); else c1 = QPointF(x, y); QPointF c2(arg[0]+offsetX, arg[1]+offsetY); QPointF e(arg[2]+offsetX, arg[3]+offsetY); path.cubicTo(c1, c2, e); ctrlPt = c2; x = e.x(); y = e.y(); break; } case 7: { // 'Q' quadratic bezier curves QPointF c(arg[0]+offsetX, arg[1]+offsetY); QPointF e(arg[2]+offsetX, arg[3]+offsetY); path.quadTo(c, e); ctrlPt = c; x = e.x(); y = e.y(); break; } case 8: { // 'T' smooth shorthand QPointF e(arg[0]+offsetX, arg[1]+offsetY); QPointF c; if (lastMode == 7 || lastMode == 8) c = QPointF(2*x-ctrlPt.x(), 2*y-ctrlPt.y()); else c = QPointF(x, y); path.quadTo(c, e); ctrlPt = c; x = e.x(); y = e.y(); break; } case 9: // 'A' elliptical arc curve // ### just a straight line x = arg[5] + offsetX; y = arg[6] + offsetY; path.lineTo(x, y); break; }; lastMode = mode; } pt->drawPath(path);}/*! \internal Parses a CSS2-compatible color specification. Either a keyword or a numerical RGB specification like #ff00ff or rgb(255,0,50%).*/QColor Q3SVGPaintEnginePrivate::parseColor(const QString &col){ static const struct ColorTable { const char *name; const char *rgb; } coltab[] = { { "black", "#000000" }, { "silver", "#c0c0c0" }, { "gray", "#808080" }, { "white", "#ffffff" }, { "maroon", "#800000" }, { "red", "#ff0000" }, { "purple", "#800080" }, { "fuchsia", "#ff00ff" }, { "green", "#008000" }, { "lime", "#00ff00" }, { "olive", "#808000" }, { "yellow", "#ffff00" }, { "navy", "#000080" }, { "blue", "#0000ff" }, { "teal", "#008080" }, { "aqua", "#00ffff" }, // ### the latest spec has more { 0, 0 } }; // initialize color map on first use if (!qSvgColMap) { qSvgColMap = new QMap<QString,QString>; const struct ColorTable *t = coltab; while (t->name) { qSvgColMap->insert(QLatin1String(t->name), QLatin1String(t->rgb)); ++t; } } // a keyword? if (qSvgColMap->contains(col)) return QColor((*qSvgColMap)[col]); // in rgb(r,g,b) form ? QString c = col; c.replace(QRegExp(QString::fromLatin1("\\s*")), QLatin1String("")); QRegExp reg(QString::fromLatin1("^rgb\\((\\d+)(%?),(\\d+)(%?),(\\d+)(%?)\\)$")); if (reg.indexIn(c) >= 0) { int comp[3]; for (int i = 0; i < 3; i++) { comp[i] = reg.cap(2*i+1).toInt(); if (!reg.cap(2*i+2).isEmpty()) // percentage ? comp[i] = int((double(255*comp[i])/100.0)); } return QColor(comp[0], comp[1], comp[2]); } // check for predefined Qt color objects, #RRGGBB and #RGB return QColor(col);}static QString qt_svg_compose_path(const QPainterPath &path){ QString str, tmp; for (int i = 0; i < path.elementCount(); ++i) { const QPainterPath::Element &elm = path.elementAt(i); switch (elm.type) { case QPainterPath::LineToElement: tmp.sprintf("L %f %f ", elm.x, elm.y); str += tmp; break; case QPainterPath::MoveToElement: tmp.sprintf("M %f %f ", elm.x, elm.y); str += tmp; break; case QPainterPath::CurveToElement: { Q_ASSERT(path.elementCount() > i+2); const QPainterPath::Element cd1 = path.elementAt(i+1); const QPainterPath::Element cd2 = path.elementAt(i+2); Q_ASSERT(cd1.type == QPainterPath::CurveToDataElement && cd2.type == QPainterPath::CurveToDataElement); tmp.sprintf("C %f %f %f %f %f %f ", elm.x, elm.y, cd1.x, cd1.y, cd2.x, cd2.y); str += tmp; i += 2; break; } default: break; } } return str;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -