Curly braces do not scale with staff when Bravura or MuseJazz font is used

• Sep 11, 2019 - 13:28
Reported version
3.2
Type
Functional
Frequency
Few
Severity
S3 - Major
Reproducibility
Always
Status
closed
Regression
No
Workaround
No
Project

Create a 2p8h score (4 keyboard parts) using Bravura or MuseJazz as the default font.

Reduce the size of Piano II Primo and Secondo to 80% either with the scale function or with the "small staff" checkbox in staff properties.

Curly brackets (braces) remain at 100% size, fixed to the lower staff and extending beyond the upper staff, instead of adjusting to the smaller staff.

Toccata_and_Fugue_in_D_MinorM3.png


Comments

Title Curly brackets (braces) are too large in a score that uses Bravura or MuseJazz where some of the keyboard parts use small staves Curly braces do not scale with staff when Bravura or MuseJazz font is used
Frequency Many Once
Type Graphical (UI) Functional

I can reproduce
Basic example:
Create a score with two piano parts
In staff/part properties for both staves of one piano part, select small staff or reduce scale to 80%
In Format/Style/Score, change musical symbols font to Bravura or MuseJazz
Result: curly brace remains at 100% size. Can also reproduce when scale is increased to 120%

Bumping this one to the top since there is currently work with fonts and engraving going on. And, of course, because I've just encountered this bug myself :)

In reply to by Jojo-Schmitz

It seems to me that once upon a time MuseScore used to draw the brace as a shape from hard-coded Qt paint instructions. Then after Bravura was introduced, PR #2883 implemented drawing the brace from the font symbol instead. But the hard coded method for Emmentaler and Goinville's remained untouched, so the code checks what font is being used and it forks to either method.
(You can see lines like
if (score()->styleSt(StyleIdx::MusicalSymbolFont) == "Emmentaler" || score()->styleSt(StyleIdx::MusicalSymbolFont) == "Gonville")
at several places in bracket.cpp)
For this particular issue, the hard-coded method for the older fonts was already scaling OK, but the "symbol" method had a calculation that involved a divison by spatium, making the bracket stretch in inverse proportion to the staff scale.
This calculation ended up being unnecessary since it is implied when the bracket takes its top and bottom coordinates from the top and bottom staves. With the fix, the symbol is just drawn at 100% of its size, and the scaling of the QPainter does the job of scaling the brace, which seems to be the original intention of the code.

OK, thanks, that certainly explains it, "Hysterical Raisins" ;-)
But shouldn't we then get rid of that hard-coded method for Emmentaler and Gonville too now?
Or are these fonts simply lacking this symbol? In which case they should fallback to Bravura, as for all other missung symbols I guess? Or get that glyph added?
Maybe not for 3.5 though, as it would change the appearance of scores, might be something for the planned engraving/layout improvements in 3.6/4.0

here's the code:

            case BracketType::BRACE: {
                  if (score()->styleSt(Sid::MusicalSymbolFont) == "Emmentaler" || score()->styleSt(Sid::MusicalSymbolFont) == "Gonville") {
                        _braceSymbol = SymId::noSym;
                        qreal w = score()->styleP(Sid::akkoladeWidth);
 
#define XM(a) (a+700)*w/700
#define YM(a) (a+7100)*h2/7100
 
                        path.moveTo( XM(   -8), YM(-2048));
                        path.cubicTo(XM(   -8), YM(-3192), XM(-360), YM(-4304), XM( -360), YM(-5400)); // c 0
                        path.cubicTo(XM( -360), YM(-5952), XM(-264), YM(-6488), XM(   32), YM(-6968)); // c 1
                        path.cubicTo(XM(   36), YM(-6974), XM(  38), YM(-6984), XM(   38), YM(-6990)); // c 0
                        path.cubicTo(XM(   38), YM(-7008), XM(  16), YM(-7024), XM(    0), YM(-7024)); // c 0
                        path.cubicTo(XM(   -8), YM(-7024), XM( -22), YM(-7022), XM(  -32), YM(-7008)); // c 1
                        path.cubicTo(XM( -416), YM(-6392), XM(-544), YM(-5680), XM( -544), YM(-4960)); // c 0
                        path.cubicTo(XM( -544), YM(-3800), XM(-168), YM(-2680), XM( -168), YM(-1568)); // c 0
                        path.cubicTo(XM( -168), YM(-1016), XM(-264), YM( -496), XM( -560), YM(  -16)); // c 1
                        path.lineTo( XM( -560), YM(    0));  //  l 1
                        path.lineTo( XM( -560), YM(   16));  //  l 1
                        path.cubicTo(XM( -264), YM(  496), XM(-168), YM( 1016), XM( -168), YM( 1568)); // c 0
                        path.cubicTo(XM( -168), YM( 2680), XM(-544), YM( 3800), XM( -544), YM( 4960)); // c 0
                        path.cubicTo(XM( -544), YM( 5680), XM(-416), YM( 6392), XM(  -32), YM( 7008)); // c 1
                        path.cubicTo(XM(  -22), YM( 7022), XM(  -8), YM( 7024), XM(    0), YM( 7024)); // c 0
                        path.cubicTo(XM(   16), YM( 7024), XM(  38), YM( 7008), XM(   38), YM( 6990)); // c 0
                        path.cubicTo(XM(   38), YM( 6984), XM(  36), YM( 6974), XM(   32), YM( 6968)); // c 1
                        path.cubicTo(XM( -264), YM( 6488), XM(-360), YM( 5952), XM( -360), YM( 5400)); // c 0
                        path.cubicTo(XM( -360), YM( 4304), XM(  -8), YM( 3192), XM(   -8), YM( 2048)); // c 0
                        path.cubicTo(XM( -  8), YM( 1320), XM(-136), YM(  624), XM( -512), YM(    0)); // c 1
                        path.cubicTo(XM( -136), YM( -624), XM(  -8), YM(-1320), XM(   -8), YM(-2048)); // c 0*/
                        setbbox(path.boundingRect());
                        _shape.add(bbox());
                        }
                  else {
                        if (_braceSymbol == SymId::noSym)
                              _braceSymbol = SymId::brace;
                        qreal h = h2 * 2;
                        qreal w = symWidth(_braceSymbol) * _magx;
                        bbox().setRect(0, 0, w, h);
                        _shape.add(bbox());
                        }
                  }
                  break;

In reply to by Jojo-Schmitz

I agree that this hard-coded brace is outdated, plus it stretches the bracket in some ugly ways sometimes as when spanning to only 1 staff.

The Bravura/Musejazz symbol implementation doesn't stretch the brace, instead it chooses the most appropriate symbol for the number of span staves. Certainly looks better, however sometimes can lead to gigantic braces.


if (v == 1)
_braceSymbol = SymId::braceSmall;
else if (v <= 2)
_braceSymbol = SymId::brace;
else if (v <= 3)
_braceSymbol = SymId::braceLarge;
else
_braceSymbol = SymId::braceLarger;
}

(Stretching a font is usually a no-no in the "serious" typography world, but it was abused since the advent of graphic design apps. The principle is that a metal glyph in traditional typesetting would never be stretched, so we kind of honor that aesthetic philosophy when in digital graphic design, and that's why stretching things is considered 'ugly'. However, I am not sure if there should be an exception when spanning across too many staves that even the "braceLargest" symbol looks too bold)

Gonville seems have a brace of its own, but it does look pretty ugly, way too thin (IMHO):
GonvilleBrace.png
Looks the same for Emmentaler (when disabeling that special code, so that's not the way to go here)

About 4.0, I think the brackets need a bigger overhaul, implementing the brackets name (staff-group names in musicxml?) and allowing manual and automatic indent when needed (see https://musescore.org/en/node/281639), also control visibility on a page.
Plus, maybe being able to draw the bracket before the staff names (like in Violins { I / II ) which is often seen in literature. In sum, allowing all or most real world case uses.
The bracket 'inspector' illustrates very well how many things are missing. I was tempted to contribute on that but it seems this should be a bigger project included in the intern plans for 4.0

In reply to by Jojo-Schmitz

This one seems to be from Bravura, but badly stretched.
If you remove the "gonville" part on the "if" that leads to the hardcoded brace, I believe it will use the Bravura symbol - however you have to remember to remove the "gonville" condition from two more IFs in brackets.cpp (lines 84 and 116) so the correct font width is calculated for the bracket not being stretched like in the picture.

This all means that it would be trivial to just remove the hard coded brace and make everything use bravura. However it would change look of scores, as you said. (of course would lead to several vtest fails too)

Ah, makes sense, seems I had disabled only 2 of the 3

And indeed, disabling those 3 reveals that all 4 fonts now fall back to Bravura.
At least for Gonville we should do this in any case IMHO, not so sure for Emmentaler though

If you guys were to make Bravura's the default "curly" brace, then the width property in styles would be defunct since it only affects Emmentaler's curly-brace. Although for the most part Bravura's looks better overall, the ability to change Emmentaler's brace width via the style settings gives the user a little extra control, and because of that I'm kind of against removing this altogether, but then again, Bravura's doesn't really need width adjustment and it looks pretty decent, so whatever.

Personally I'd like to see some extra customization options like let the curly brace be a little "longer" than the staves altogether so that it hangs over them just a bit kinda like old-style scores from hundreds of years ago , or maybe a little under them if the user wants. But those would be icing on the cake options.

Leave it for now, this would be for a different issue anyhow.
We should also disable those bracket settings for those fonts that don't support it

Fix version
3.5.1