Text vert. alignment: why QFontMetrics::tightBoundingRect?

• Oct 20, 2012 - 10:05

Context: commit 4ee8a2e44 (self-compiled, Qt SDK, Ubuntu 11.10)

Recently, vertical alignment of texts has changed, raising a few issues. This is one.

Since commit 2baa6615ef (Oct 4), QFontMetrics::tightBoundingRect() is used to get the bounding of a SimpleText and to position it (libmscore/simpletext.cpp, function layout(), line 130).

The result is that the vertical position of a text snippet depends upon the glyphs it contains. For instance, if the alignment is TOP, the text vert. pos. changes if it contains upper cases/ascenders or not; on BOTTOM, it changes if it contains descenders or not.

In the example below, both Composer and Lyricist have the same vertical alignment (BOTTOM), but they are not aligned vertically, because the Composer text contains descenders (the parentheses) and the Lyricist text does not.

sample

This also affected the position of lyric syllables and prompted a change in Lyrics default formatting as a fix attempt.

Questions:

1) Is this intended to work this way or not?

2) Is more work planned in this area or this was the intended as a definitive solution?

Thanks,

M.

Attachment Size
Composer_lyricist_misaligned.png 4.06 KB

Comments

The "tightBoundingRect()" method is selected by intention. It solves several problems but unfortunately seems to creates some new. The former boundingRect() does not work well with text frames which always look displaced. It does not work at all for the MuseScore20 font which is used for dynamics. The old version looks only right for simple cases and not if you mix fonts/font sizes on a line.

What you really want in the title is an alignment to the text baseline. So i think the text style for Lyricist and composer is wrong, the vertical alignment should be "text baseline".

Maybe more changes are necessary to get all cases right.

In reply to by [DELETED] 3

Thanks for the reply! In order to better grasp the issues involved, a summary of the problems solved by using tightBoundingRect() would be very useful. In the meantime, these are some considerations.

Baseline
Arguably, the commonest alignment for real texts (MuseScore20 is not really a text font) is base line for most usages.

However, due to interaction with this matter , it is currently not possible -- at least I could not find a general enough way -- to align a text with a frame bottom edge if any text alignment is used other than BOTTOM. Using Offset style values (either absolute or percent) requires values which depend upon the frame actual height.

Multi-font texts
I am not sure this is an issue here: tightBoundingRect() is used in SimpleText class, and SimpleText texts are by definition single-font. In general, for proper alignment of multi-font texts, I think we should rely on QDocument.

'All cases'
For TOP, BASE LINE and BOTTOM alignment, I am not sure the 'tight' bbox be correct: that "on" (with no ascenders) will have more blank above than "off" or that "up" (with a descender) will have less blank below than "down" is to be expected, being a characteristic of almost all writings (I cannot really think of a writing system in which this -- or similar considerations -- are not true).

MIDDLE alignment can be different, I agree. In most cases, when a single text is centred within some height, a visual centring is optimal (=>'tight' bbox; but even in this case, our eye is accustomed to compensate for lack of acenders/upper case or descenders). As soon as there are two such texts, they are expected to line up in some way and usually using the 'non-tight' bbox approximates the result enough.

So, for SimpleText in general, I am wondering if it is not the case to re-consider this choice.

Thanks again,

M.

In reply to by [DELETED] 3

Great! Base line alignment does work indeed!

I was looking at the SimpleText::layout() function, and there is something I do not understand in lines 161-180 (the 2 "if / else if" sets in "layout to parent frame"): it seems to me that two concepts of alignment+reloff roles are mixed:

1) for ALIGN_BOTTOM and ALIGN_VCENTER, the text is first moved to the bottom / centre of the frame (alignment = alignment relative to the frame) and then further displaced by a percentage of the frame height according to reloff(); this results in extra displacement. This is evident if a Y reloff of 100% is used: it should position the text around the frame bottom edge, but in fact the text ends up way below the frame.

2) for ALIGN_BASELINE, the text is first baseline aligned on its own ref. pt. (alignemnt = 'internal' alignment of text) and then the ref. pt. is displaced in the frame according to reloff() (and this alignment works as expected).

(for ALIGN_TOP, the two concepts seem to coincide).

For horizontal alignment, 1) seems to always be used. I suspect 2) to be the 'right' one, as the purpose of each element (alignment, offset, reloff) is clear and consistent.

If this is true, the whole block from line 161 (if(align() & ALIGN_BOTTOM)) to line 180 (bb.translate(layoutOffset);) could be removed. I tried and the result seems to work.

What do you think?

Thanks,

M.

In reply to by Marc Sabatella

I am not sure. The semantics of these alignments did change a few times; chances are a template / style some weeks old might be still valid.

Of course, this refers to templates / styles made for 2.0. I suspect the latest change in alignment is more similar to 1.2 situation; so, this might not be a (serious) problem for 1.2 files (other will be; backward compatibility with 1.2 is still largely unexplored).

Do you still have an unanswered question? Please log in first to post your question.