Skip to content

Commit

Permalink
Fix ttf font bounding box calculations (#6109)
Browse files Browse the repository at this point in the history
letterSpacing scales the default spacing between glyphs, as such it needs to default to 1.f.

This means, letterSpacing of 1.0 means neutral letter spacing, glyph is placed in default position, respecting the glyph's advance value.

    If letterSpacing is 0.75, this means that spacing between letters is reduced by 0.25 * the whitespace width of the current font.

*If letterSpacing is 1.25, this means that an additional space of 0.25 * the whitespace width is added between letters.

    Since proportional fonts have per-glyph advance values, we use a constant width as whitespace width.

    additionally, per spec, we scale the default whitespace width by the font's property spaceSize

Also remove comments in docs specifying that we use p to calculate the size of the space character which is no longer true since some time ago

Fixes #6106
  • Loading branch information
tgfrerer authored and arturoc committed Aug 18, 2018
1 parent 4b03c10 commit 12c9912
Show file tree
Hide file tree
Showing 2 changed files with 26 additions and 20 deletions.
22 changes: 11 additions & 11 deletions libs/openFrameworks/graphics/ofTrueTypeFont.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -450,7 +450,7 @@ bool ofTrueTypeFont::initLibraries(){
ofTrueTypeFont::ofTrueTypeFont()
:settings("",0){
bLoadedOk = false;
letterSpacing = 0;
letterSpacing = 1;
spaceSize = 1;
fontUnitScale = 1;
stringQuads.setMode(OF_PRIMITIVE_TRIANGLES);
Expand Down Expand Up @@ -1054,25 +1054,24 @@ void ofTrueTypeFont::iterateString(const string & str, float x, float y, bool vF
} else if (c == '\t') {
if (settings.direction == OF_TTF_LEFT_TO_RIGHT){
f(c, pos);
pos.x += getGlyphProperties(' ').advance * TAB_WIDTH;
pos.x += letterSpacing * directionX;
pos.x += (getGlyphProperties(' ').advance * spaceSize * letterSpacing) * TAB_WIDTH * directionX;
} else{
pos.x += getGlyphProperties(' ').advance * TAB_WIDTH * letterSpacing * directionX;
pos.x += (getGlyphProperties(' ').advance * spaceSize * letterSpacing) * TAB_WIDTH * directionX;
f(c, pos);
}
prevC = c;
} else if(isValidGlyph(c)) {
const auto & props = getGlyphProperties(c);
if(prevC>0){
pos.x += getKerning(c,prevC);// * directionX;
pos.x += getKerning(c,prevC);
}
if(settings.direction == OF_TTF_LEFT_TO_RIGHT){
f(c,pos);
pos.x += props.advance * directionX;
pos.x += letterSpacing * directionX;
pos.x += getGlyphProperties(' ').advance * spaceSize * (letterSpacing - 1.f) * directionX;
}else{
pos.x += props.advance * directionX;
pos.x += letterSpacing * directionX;
pos.x += getGlyphProperties(' ').advance * spaceSize * (letterSpacing - 1.f) * directionX;
f(c,pos);
}
prevC = c;
Expand Down Expand Up @@ -1169,10 +1168,11 @@ ofRectangle ofTrueTypeFont::getStringBoundingBox(const std::string& c, float x,

iterateString( c, x, y, vflip, [&]( uint32_t c, glm::vec2 pos ){
auto props = getGlyphProperties( c );

if ( c == '\t' ){
props.advance = getGlyphProperties( ' ' ).advance * letterSpacing * TAB_WIDTH;
props.advance = (getGlyphProperties(' ').advance * spaceSize * letterSpacing) * TAB_WIDTH;
}
maxX = max( maxX, pos.x + props.advance * letterSpacing );
maxX = max( maxX, pos.x + props.xmin + props.width );
minX = min( minX, pos.x );
if ( vflip ){
minY = min( minY, pos.y - ( props.ymax - props.ymin ) );
Expand Down Expand Up @@ -1231,7 +1231,7 @@ glm::vec2 ofTrueTypeFont::getFirstGlyphPosForTexture(const std::string & str, bo
try{
if (c != '\n') {
auto g = loadGlyph(c);
lineWidth += g.props.advance * letterSpacing;
lineWidth += g.props.advance + getGlyphProperties(' ').advance * spaceSize * (letterSpacing - 1.f);
width = max(width, lineWidth);
}else{
lineWidth = 0;
Expand Down Expand Up @@ -1267,7 +1267,7 @@ ofTexture ofTrueTypeFont::getStringTexture(const std::string& str, bool vflip) c
int x = pos.x + g.props.xmin;
int y = g.props.ymax + pos.y;
glyphPositions.emplace_back(x, y);
lineWidth += g.props.advance * letterSpacing;
lineWidth += g.props.advance + getGlyphProperties(' ').advance * spaceSize * (letterSpacing - 1.f);
width = max(width, lineWidth);
height = max(height, y + long(getLineHeight()));
}else{
Expand Down
24 changes: 15 additions & 9 deletions libs/openFrameworks/graphics/ofTrueTypeFont.h
Original file line number Diff line number Diff line change
Expand Up @@ -276,31 +276,37 @@ class ofTrueTypeFont{

/// \brief Returns letter spacing of font object.
///
/// You can control this by the ofTrueTypeFont::setLetterSpacing() function. 1.0 = default spacing,
/// less then 1.0 would be tighter spacing, greater then 1.0 would be wider spacing.
/// You can control this by the ofTrueTypeFont::setLetterSpacing() function. 1.f = default spacing,
/// less than 1.0 means tighter spacing, greater than 1.0 means wider spacing.
///
/// \returns the letter spacing of font object.
float getLetterSpacing() const;

/// \brief Sets the letter spacing of the font object.
///
/// 1.0 = default spacing, less then 1.0 would be tighter spacing, greater then 1.0 would be wider spacing.
/// \param spacing Spacing of font object.
/// 1.f = default spacing, less than 1.f would be tighter spacing, greater than 1.f would be wider spacing.
///
/// \param spacing Scale for spacing between letters for this font.
void setLetterSpacing(float spacing);

/// \brief Returns a variable that represents how wide spaces are.
///
/// It's a scalar for the width of the letter 'p', so 1.0 means that a space will be the size of the lower
/// case 'p' of that font. 2.0 means that it's 2 times the size of the lower case 'p', etc.
/// The value returned is a scalar for the advance (=width) of the whitespace glyph, so 1.0 means
/// that a space will be the default width of a whitespace glyph of this font, 2.0 means that
/// it's 2 times the default width, etc.
///
/// \returns the width of the space.
float getSpaceSize() const;

/// \brief Sets the size of the space ' ' character.
/// \brief Sets the width for the whitespace character for this font
///
/// This number, which defaults to 1.0, scales the width of the letter 'p' for the space.
/// This number, which defaults to 1.0, scales the width of a whitespace, based on the
/// width of the whitespace glyph of this font.
///
/// Setting spaceSize to 2.f will make whitespaces twice as wide, 0.5f will make whitespaces
/// half as wide, etc.
///
/// \param size Scales the width of the letter 'p' for the space.
/// \param size Scales the width of the whitespace glyph for this font.
void setSpaceSize(float size);

/// \brief Returns the string width.
Expand Down

0 comments on commit 12c9912

Please sign in to comment.