-
Couldn't load subscription status.
- Fork 3k
Cleanup several aspects of tech debt around graphics and font management #30665
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Cleanup several aspects of tech debt around graphics and font management #30665
Conversation
534179c to
11f8dd6
Compare
| } else { | ||
| double h = ldata->bracketHeight; | ||
| double mag = h / (100 * item->magS()); | ||
| double glyphHeight = item->symBbox(ldata->braceSymbol).height(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
double glyphHeight = item->symHeight(ldata->braceSymbol);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great work! A few minor comments.
| // Score symbols | ||
| RectF FontProvider::symBBox(const muse::draw::Font& f, char32_t ucs4) const | ||
| { | ||
| return fontsEngine()->symBBox(f, ucs4); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove the methods from FontsEngine as well?
| sym.bbox = fontProvider()->symBBox(m_font, sym.code); | ||
| sym.advance = fontProvider()->symAdvance(m_font, sym.code); | ||
| sym.bbox = fontProvider()->boundingRect(m_font, sym.code); | ||
| sym.advance = fontProvider()->horizontalAdvance(m_font, sym.code); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe (part of) the reason was that that sym.code doesn't fit in Char for all symbols but needs char32_t instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It looks to me like SMuFL symbols will fit in Char. Char is char16_t which has a highest value of 0xFFFF. The highest value needed for SMuFL fonts should be 0xF8FF
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That is an excellent point, hadn't thought of that. This actually tells me two things:
- I should make a char32_t version of boundingRect and horizontalAdvance to properly replace symBBox and symAdvanbce, just to be 100% that if we do need the metrics for 32bit characters we have them and they work correctly.
- The fact that it all just worked, despite cutting the 32bit codes into a Char, clearly means that no music symbol uses code points beyond the 16bit range, and that's confirmed by the Smufl specification. So I am also going to turn sym.code into a char16_t.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So, about the first point: I ended up generalizing all the metric functions to 32bit characters, cause there's really no reason not to. That way we can also get rid of the inFont vs inFontUcs4 distinction.
About the second point: yes the Smufl code points are all within the 16 bit range, however I discovered that the unicode standard also has a range dedicated to music symbols which is beyond the 16 bit range. Smufl suggests that if a symbol exists both in Smufl and in Unicode it should be included at both code points but some of our fonts only included it at the Unicode point, so we do need to keep the 32bit variable after all.
| #include <QPaintDevice> | ||
| #include <QFontDatabase> | ||
| #include <QFontMetricsF> | ||
| #include <qrawfont.h> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| #include <qrawfont.h> | |
| #include <QRawFont> |
| size_t smallGroupLimit() const { return m_smallGroupLimit; } | ||
|
|
||
| bool updateColumns() const { return m_updateColumns; } | ||
| void setUpdateColumns(bool v) { m_updateColumns = v; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unused?
| dividerLdata->moveY(ctx.conf().styleD(Sid::dividerLeftY) * SPATIUM20); | ||
| dividerLdata->setPosX(ctx.conf().styleD(Sid::dividerLeftX) * SPATIUM20); | ||
| dividerLdata->moveY(ctx.conf().styleD(Sid::dividerLeftY) * ctx.conf().defaultSpatium()); | ||
| dividerLdata->setPosX(ctx.conf().styleD(Sid::dividerLeftX) * ctx.conf().defaultSpatium()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder whether it makes sense at all to use the default spatium here and not the score spatium
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It definitely doesn't, but I won't bother fixing it now cause I have a whole secret rework of system dividers in the pipeline ;)
| { | ||
| Font f(font(t)); | ||
| f.setPointSizeF(f.pointSizeF() * MScore::pixelRatio); | ||
| #ifndef Q_OS_MACOS |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correction on the commit message: it was actually a non-Mac specific issue. See also #17997; the .org issues linked in a comment in the code might give some clarification
I think this should go hand in hand with removing As a solution, I would propose:
|
|
Another option might be to figure out what's the difference between QFont::pixelSize and QFont::pointSize, and whether that can somehow help us |
|
|
||
| void AccidentalsLayout::alignVerticalSets(AccidentalGroups& vertSets, AccidentalsLayoutContext& ctx) | ||
| { | ||
| std::map<int, std::vector<Accidental*> > columns; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This could be a sorted std::vector<...> if you're only iterating over it later on.
11f8dd6 to
6725ed0
Compare
1e1476a to
b63abe1
Compare
The reason why that code exist is that we handle text via Qt font metrics but music symbols via FreeType metrics. That is now managed by FontProviderDispatcher so there is no reason to keep this code hidden behind a compiler flag. In fact it doesn't even compile if the flag is removed.
I have never really understood what this quantity represents, other than it has a value of 5 and was multiplied by 72 to obtain the DPI. From what I can gather, it seems that the idea is to start from 72 points per inch (which comes from the definition of the typographical point, defined as 1/72 of an inch) and to set resolution of the program to 5 times that. In that sense DPI_F is probably intended as a "fractional" resolution with respect to the typographical point. That results in a DPI of 360. It now seems that this DPI_F variable is effectively unused (all the functions that take it as parameter end up ignoring it). And the DPI can be just set to 360, I don't see why it has to be constructed as an integer multiple of a typographical unit (in fact most printers have resolutions of 600 or 1200 DPI, which are not multiples of 72).
The necessity of using Qt for some font metrics and FreeType for others came from musescore#22189, which was caused by a Qt bug. Qt has now resolved that bug by introducing the flag PreferTypoLineMetrics. So there is no reason now for using two different source of metrics for text. In fact, I see also no reason to not use Qt for the music symbols fonts. I don't know the historical reason for that, but Qt should be able to handle them like any other font. To me this just feels like historical tech debt. Additionally, given that all of our drawing uses QPainter, using Qt for the metrics that define such drawing feels more logical to me and more likely to work consistently in all situations. Incidentally, this also happens to fix musescore#30456. I don't know why, but FreeType returns wrong values for the line spacing, while Qt seems to give the correct values.
After switching the symbol metrics to Qt, I found that Qt wasn't returning very precise bounding boxes. They seemed to all have some (small, but noticeable) rounding errors. By contrast, the bounding boxes that we were getting before were pixel-perfect. This may well be the historical reason why Qt metrics were not used for music symbol. It turns out though that Qt wasn't imprecise, it was just limited by the resolution of 360 DPI that we were setting ourselves. I assume that QFontMetricsF, despite returning double precision values, internally still rounds to whatever resolution is set. Increasing the resolution to 1200 DPI makes Qt's metrics on music symbols also pixel-perfect. As far as I understand, this resolution value only affects internal calculations, not the actual rendering resolution (plus music font metrics are cached anyway), so I don't think this should have any impact on performance. This also requires updating the value of default spatium (having finally understood what that 24.8 was). That number implicitely assumed a DPI of 360. We should obviously just write the spatium with the proper conversion factor from millimetres to pixels/points. Luckily this doesn't affect existing files, where it's already written in millimitres.
I have no idea what that magic number of 100 was about nor why it was even working before the change of resolution. It definitely wasn't working anymore with the new resolution.
Music symbols are just characters in a font, so there is no reason why their metrics should need special functions.
Error was always there but somehow was made visible by the change of resolution.
This is another variable that has never made any sense to me whatsoever. I can only infer from the way it was used that it was meant to represent the default value of spatium in pixel units. But if that's the case, the way in which it was defined made no sense at all. DPI / 72 used to just be equal to DPI_F, so SPATIUM20 was equal to 5 * DPI_F = 25. To me, the only reason why this seemed to work correctly as the default spatium value is that it just happened to be close to 24.8, which was the actual value. This commit removes SPATIUM20 and replaces it with appropriate calls to the style defaults. In a couple of places (namely StaffType and EngravingFont) the Score and the corresponding Style haven't been created yet, so they need to access the StyleDef class directly. In fact I don't see what StyleDef should make its members private. I think they can be public cause they are const so they can't be changed.
No idea about the exact history of this. It seems to have been introduced as a Mac-specific hack ages ago to solve some Qt-related problem. Pretty sure it's not necessary anymore (also produces no difference in vtests).
I think this was the only DOM class that still had its own draw method. I have moved it to the respective draw module where it belongs.
Cause that will work with both 16bit and 32bit (i.e. ucs4) character maps
b63abe1 to
ca2dc51
Compare
Please refer to the commit descriptions for explanations about the specific changes. Should be reviewed one commit at a time so that what I'm doing makes more sense.
All the vtests will fail. The vast majority are rounding errors, which is expected (especially considering the change in internal resolution, which means the rasterization when creating the PNGs is going to be different).
A few of them happen because the layout is right on the edge of a decision threshold (does the measure fit in this line or not, does the accidental fit in this spot without colliding with the others or not...) and the rounding errors due to all the changes I'm making (especially the better definition of SPATIUM in styledef.cpp) are enough to go over the threshold.
In some cases, it seems that my changes have removed some unnecessary fallbacks in the music symbol fonts (see e.g. line-1 and line-2 where the reference image falls back to the Bravura 8va symbols whereas the new image seems to pick up the correct symbol from Emmentaler).
@miiizen I think I need your help with some of the harmony-related vtests. Specifically, there seems to have been an increase in the vertical spacing of some stacked chord symbols, as well as in the horizontal spacing between the literal and the numeral (e.g. C7). That is surely due to switching to the Qt font metrics, but I don't know in what way or how to best correct it.
@cbjeukendrup there is one more cleanup I'd like to make, and that's removing MScore::pixelRatio. I really don't like that every single text-related draw method needs to know about it and use it to set the font size to the right scaling value. It feels like something that should be handled by the technical implementation of the Painter itself. It is, in the end, it's part of the same Transform that maps Musescore's inner coordinates to the actual screen or printer device. Do you have any suggestion on how to handle that?