Skip to content

Commit

Permalink
Fix #105436 Fix #105471: svg regressions
Browse files Browse the repository at this point in the history
  • Loading branch information
sidewayss authored and lasconic committed Apr 16, 2016
1 parent 2a071e4 commit e1b5c25
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 76 deletions.
145 changes: 75 additions & 70 deletions mscore/file.cpp
Expand Up @@ -2514,7 +2514,7 @@ bool MuseScore::saveSvg(Score* score, const QString& saveName)
QString title(score->title());
printer.setTitle(title);
printer.setFileName(saveName);
const PageFormat* pf = cs->pageFormat();
const PageFormat* pf = score->pageFormat();

QRectF r;
if (trimMargin >= 0 && score->npages() == 1) {
Expand All @@ -2539,80 +2539,85 @@ bool MuseScore::saveSvg(Score* score, const QString& saveName)
if (trimMargin >= 0 && score->npages() == 1)
p.translate(-r.topLeft());

foreach (Page* page, score->pages()) {
// 1st pass: StaffLines
foreach (System* s, *(page->systems())) {
for (int i = 0, n = s->staves()->size(); i < n; i++) {
if (score->staff(i)->invisible())
continue; // ignore invisible staves

// The goal here is to draw SVG staff lines more efficiently.
// MuseScore draws staff lines by measure, but for SVG they can
// generally be drawn once for each system. This makes a big
// difference for scores that scroll horizontally on a single
// page. But there is an exception to this rule:
//
// ~ One (or more) invisible measure(s) in a system/staff ~
// In this case the SVG staff lines for the system/staff
// are drawn by measure.
//
bool byMeasure = false;
for (MeasureBase* mb = s->firstMeasure(); mb != 0; mb = s->nextMeasure(mb)) {
if (!static_cast<Measure*>(mb)->visible(i)) {
byMeasure = true;
break;
}
}
if (byMeasure) { // Draw visible staff lines by measure
for (MeasureBase* mb = s->firstMeasure(); mb != 0; mb = s->nextMeasure(mb)) {
Measure* m = static_cast<Measure*>(mb);
if (m->visible(i)) {
StaffLines* sl = m->staffLines(i);
printer.setElement(sl);
paintElement(p, sl);
for (Page* page : score->pages()) {
// 1st pass: StaffLines
for (System* s : page->systems()) {
for (int i = 0, n = s->staves()->size(); i < n; i++) {
if (score->staff(i)->invisible())
continue; // ignore invisible staves

// The goal here is to draw SVG staff lines more efficiently.
// MuseScore draws staff lines by measure, but for SVG they can
// generally be drawn once for each system. This makes a big
// difference for scores that scroll horizontally on a single
// page. But there are exceptions to this rule:
//
// ~ One (or more) invisible measure(s) in a system/staff ~
// ~ One (or more) elements of type HBOX or VBOX ~
//
// In these cases the SVG staff lines for the system/staff
// are drawn by measure.
//
bool byMeasure = false;
for (MeasureBase* mb = s->firstMeasure(); mb != 0; mb = s->nextMeasure(mb)) {
if (mb->type() == Element::Type::HBOX
|| mb->type() == Element::Type::VBOX
|| !static_cast<Measure*>(mb)->visible(i)) {
byMeasure = true;
break;
}
}
}
}
else { // Draw staff lines once per system
StaffLines* firstSL = s->firstMeasure()->staffLines(i)->clone();
StaffLines* lastSL = s->lastMeasure()->staffLines(i);
firstSL->bbox().setRight(lastSL->bbox().right()
+ lastSL->pagePos().x()
- firstSL->pagePos().x());
printer.setElement(firstSL);
paintElement(p, firstSL);
}
}
}
// 2nd pass: the rest of the elements
QList<const Element*> pel = page->elements();
qStableSort(pel.begin(), pel.end(), elementLessThan);

Element::Type eType;
foreach (const Element* e, pel) {
// Always exclude invisible elements
if (!e->visible())
continue;

eType = e->type();
switch (eType) { // In future sub-type code, this switch() grows, and eType gets used
case Element::Type::STAFF_LINES : // Handled in the 1st pass above
continue; // Exclude from 2nd pass
break;
default:
break;
} // switch(eType)
if (byMeasure) { // Draw visible staff lines by measure
for (MeasureBase* mb = s->firstMeasure(); mb != 0; mb = s->nextMeasure(mb)) {
if (mb->type() != Element::Type::HBOX
&& mb->type() != Element::Type::VBOX
&& static_cast<Measure*>(mb)->visible(i)) {
StaffLines* sl = static_cast<Measure*>(mb)->staffLines(i);
printer.setElement(sl);
paintElement(p, sl);
}
}
}
else { // Draw staff lines once per system
StaffLines* firstSL = s->firstMeasure()->staffLines(i)->clone();
StaffLines* lastSL = s->lastMeasure()->staffLines(i);
firstSL->bbox().setRight(lastSL->bbox().right()
+ lastSL->pagePos().x()
- firstSL->pagePos().x());
printer.setElement(firstSL);
paintElement(p, firstSL);
}
}
}
// 2nd pass: the rest of the elements
QList<Element*> pel = page->elements();
qStableSort(pel.begin(), pel.end(), elementLessThan);

Element::Type eType;
for (const Element* e : pel) {
// Always exclude invisible elements
if (!e->visible())
continue;

// Set the Element pointer inside SvgGenerator/SvgPaintEngine
printer.setElement(e);
eType = e->type();
switch (eType) { // In future sub-type code, this switch() grows, and eType gets used
case Element::Type::STAFF_LINES : // Handled in the 1st pass above
continue; // Exclude from 2nd pass
break;
default:
break;
} // switch(eType)

// Paint it
paintElement(p, e);
}
p.translate(QPointF(pf->width() * DPI, 0.0));
// Set the Element pointer inside SvgGenerator/SvgPaintEngine
printer.setElement(e);

// Paint it
paintElement(p, e);
}
p.translate(QPointF(pf->width() * DPI, 0.0));
}

// Clean up and return
// Clean up and return
score->setPrinting(false);
MScore::pdfPrinting = false;
p.end(); // Writes MuseScore SVG file to disk, finally
Expand Down
33 changes: 27 additions & 6 deletions mscore/svggenerator.cpp
Expand Up @@ -232,7 +232,7 @@ class SvgPaintEngine : public QPaintEngine
QString stateString;
QTextStream stateStream;

// To eliminate transform attribute on polylines
// Qt translates everything. These help avoid SVG transform="translate()".
qreal _dx;
qreal _dy;

Expand Down Expand Up @@ -274,7 +274,8 @@ class SvgPaintEngine : public QPaintEngine

#define SVG_CLASS " class=\""

#define SVG_ELEMENT_END "/>"
#define SVG_ELEMENT_END "/>"
#define SVG_RPAREN_QUOTE ")\""

#define SVG_TITLE_BEGIN "<title>"
#define SVG_TITLE_END "</title>"
Expand Down Expand Up @@ -306,6 +307,8 @@ class SvgPaintEngine : public QPaintEngine
#define SVG_FILL_RULE " fill-rule=\"evenodd\""
#define SVG_VECTOR_EFFECT " vector-effect=\"non-scaling-stroke\""

#define SVG_MATRIX " transform=\"matrix("

public:
SvgPaintEngine()
: QPaintEngine(*new SvgPaintEnginePrivate,
Expand Down Expand Up @@ -1126,10 +1129,28 @@ void SvgPaintEngine::updateState(const QPaintEngineState &state)
if (!qFuzzyIsNull(state.opacity() - 1))
stateStream << SVG_OPACITY << state.opacity() << SVG_QUOTE;

// Set these class variables for later use in the drawXXX() functions
QMatrix mx = state.matrix();
_dx = mx.dx();
_dy = mx.dy();
// Translations, SVG transform="translate()", are handled separately from
// other transformations such as rotation. Qt translates everything, but
// other transformations do occur, and must be handled here.
QTransform t = state.transform();
if (t.m11() == t.m22() // No scaling
&& t.m12() == t.m21()) { // No rotation, etc.
// No transformation except translation
_dx = t.m31();
_dy = t.m32();
}
else {
// Other transformations are more straightforward with a full matrix
_dx = 0;
_dy = 0;
stateStream << SVG_MATRIX << t.m11() << SVG_COMMA
<< t.m12() << SVG_COMMA
<< t.m21() << SVG_COMMA
<< t.m22() << SVG_COMMA
<< t.m31() << SVG_COMMA
<< t.m32() << SVG_RPAREN_QUOTE;
}

}

void SvgPaintEngine::drawPath(const QPainterPath &p)
Expand Down

0 comments on commit e1b5c25

Please sign in to comment.