Skip to content
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

Monospace and fallback fonts tweaks #486

Merged
merged 7 commits into from
Jul 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 2 additions & 2 deletions cr3gui/data/epub.css
Original file line number Diff line number Diff line change
Expand Up @@ -137,15 +137,15 @@ table caption {
* approximation than no pre */
pre, xmp {
white-space: pre; /* has to be set in fb2def.h to work */
font-family: "Droid Sans Mono", "Liberation Mono", "DeJaVu Sans Mono", monospace;
font-family: monospace;
text-align: left;
margin-top: 0.5em;
margin-bottom: 0.5em;
/* background-color: #BFBFBF; */
}

/* Inline elements (all unknown elements default now to display: inline) */
code, kbd, samp, tt { font-family: "Droid Sans Mono", "Liberation Mono", "DeJaVu Sans Mono", monospace; }
code, kbd, samp, tt { font-family: monospace; }
sup { font-size: 70%; vertical-align: super; }
sub { font-size: 70%; vertical-align: sub; }
small { font-size: 80%; }
Expand Down
4 changes: 2 additions & 2 deletions cr3gui/data/fb2.css
Original file line number Diff line number Diff line change
Expand Up @@ -83,11 +83,11 @@ th { font-weight: bold; text-align: center; background-color: #DDD }
table caption { text-indent: 0px; padding: 4px; background-color: #EEE }
table, th, td { border-width: 1px; border-style: solid; border-color: black; border-collapse: collapse; }

tt, samp, kbd { font-family: "Droid Sans Mono", "Liberation Mono", "DeJaVu Sans Mono", "Courier New", "Courier", monospace; }
tt, samp, kbd { font-family: monospace; }
code, pre {
white-space: pre;
text-align: left;
font-family: "Droid Sans Mono", "Liberation Mono", "DeJaVu Sans Mono", "Courier New", "Courier", monospace;
font-family: monospace;
}
code {
display: inline;
Expand Down
2 changes: 2 additions & 0 deletions crengine/include/lvdocviewprops.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#define PROP_FONT_COLOR "font.color.default"
#define PROP_FONT_FACE "font.face.default"
#define PROP_FONT_BASE_WEIGHT "font.face.base.weight" // replaces PROP_FONT_WEIGHT_EMBOLDEN ("font.face.weight.embolden")
#define PROP_FONT_MONOSPACE_SCALE "font.monospace.size.scale.percent"
#define PROP_BACKGROUND_COLOR "background.color.default"
#define PROP_BACKGROUND_IMAGE "background.image.filename"
#define PROP_TXT_OPTION_PREFORMATTED "crengine.file.txt.preformatted"
Expand All @@ -18,6 +19,7 @@
#define PROP_LOG_AUTOFLUSH "crengine.log.autoflush"
#define PROP_FONT_SIZE "crengine.font.size"
#define PROP_FALLBACK_FONT_FACES "crengine.font.fallback.faces"
#define PROP_FALLBACK_FONT_SIZES_ADJUSTED "crengine.font.fallback.sizes.adjusted"
// multiple fallback font faces are to be separated by '|'
#define PROP_STATUS_FONT_COLOR "crengine.page.header.font.color"
#define PROP_STATUS_FONT_FACE "crengine.page.header.font.face"
Expand Down
17 changes: 15 additions & 2 deletions crengine/include/lvfntman.h
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,8 @@ class LVFontManager
int _antialiasMode;
kerning_mode_t _kerningMode;
hinting_mode_t _hintingMode;
int _monospaceSizeScale;
bool _fallbackFontSizesAdjusted;
public:
/// garbage collector frees unused fonts
virtual void gc() = 0;
Expand Down Expand Up @@ -643,16 +645,27 @@ class LVFontManager
/// get kerning mode: true==ON, false=OFF
virtual void SetKerningMode( kerning_mode_t mode ) { _kerningMode = mode; gc(); clearGlyphCache(); }

/// get monospace size scale percent
virtual int GetMonospaceSizeScale() { return _monospaceSizeScale; }
/// set monospace size scale percent
virtual void SetMonospaceSizeScale( int scale ) { _monospaceSizeScale = scale; gc(); clearGlyphCache(); }

/// get adjusted fallback font sizes state
virtual int GetFallbackFontSizesAdjusted() { return _fallbackFontSizesAdjusted; }
/// set adjusted fallback font sizes state
virtual void SetFallbackFontSizesAdjusted( bool adjusted ) { _fallbackFontSizesAdjusted = adjusted; gc(); }

/// constructor
LVFontManager() : _antialiasMode(font_aa_all), _kerningMode(KERNING_MODE_DISABLED), _hintingMode(HINTING_MODE_AUTOHINT) { }
LVFontManager() : _antialiasMode(font_aa_all), _kerningMode(KERNING_MODE_DISABLED), _hintingMode(HINTING_MODE_AUTOHINT)
, _monospaceSizeScale(100), _fallbackFontSizesAdjusted(false) { }
/// destructor
virtual ~LVFontManager() { }
/// returns available typefaces
virtual void getFaceList( lString32Collection & ) { }
/// returns available font files
virtual void getFontFileNameList( lString32Collection & ) { }
/// returns font filename and face index for font name
virtual bool getFontFileNameAndFaceIndex( lString32 name, bool bold, bool italic, lString8 & filename, int & index ) { return false; }
virtual bool getFontFileNameAndFaceIndex( lString32 name, bool bold, bool italic, lString8 & filename, int & index, int & family_type ) { return false; }
/// returns registered or instantiated document embedded font list
virtual void getRegisteredDocumentFontList( int document_id, lString32Collection & list ) { }
virtual void getInstantiatedDocumentFontList( int document_id, lString32Collection & list ) { }
Expand Down
12 changes: 12 additions & 0 deletions crengine/src/lvdocview.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6765,6 +6765,12 @@ CRPropRef LVDocView::propsApply(CRPropRef props) {
if ( UnicodeToUtf8(value) != oldFaces ) {
REQUEST_RENDER("propsApply fallback font faces")
}
} else if (name == PROP_FALLBACK_FONT_SIZES_ADJUSTED) {
bool adjusted = props->getIntDef(PROP_FALLBACK_FONT_SIZES_ADJUSTED, false);
if (fontMan->GetFallbackFontSizesAdjusted() != adjusted) {
fontMan->SetFallbackFontSizesAdjusted(adjusted);
REQUEST_RENDER("propsApply - adjusted fallback font sizes")
}
} else if (name == PROP_STATUS_FONT_FACE) {
setStatusFontFace(UnicodeToUtf8(value));
} else if (name == PROP_STATUS_LINE || name == PROP_SHOW_TIME
Expand Down Expand Up @@ -6800,6 +6806,12 @@ CRPropRef LVDocView::propsApply(CRPropRef props) {
fontSize = MAX_STATUS_FONT_SIZE;
setStatusFontSize(fontSize);//cr_font_sizes
value = lString32::itoa(fontSize);
} else if (name == PROP_FONT_MONOSPACE_SCALE) {
int scale = props->getIntDef(PROP_FONT_MONOSPACE_SCALE, 100);
if (fontMan->GetMonospaceSizeScale() != scale) {
fontMan->SetMonospaceSizeScale(scale);
REQUEST_RENDER("propsApply - font monospace size scale")
}
} else if (name == PROP_HYPHENATION_DICT) {
// hyphenation dictionary
lString32 id = props->getStringDef(PROP_HYPHENATION_DICT,
Expand Down
114 changes: 100 additions & 14 deletions crengine/src/lvfntman.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,15 @@ class LVFontDef
}

lUInt32 getHash() {
return (((((_size * 31) + _weight)*31 + _italic)*31 + _features)*31+ _family)*31 + _name.getHash();
lUInt32 h = (((((_size * 31) + _weight)*31 + _italic)*31 + _features)*31+ _family)*31 + _name.getHash();
// _bias is not a static property, and can be set/unset on these definitions.
// If a same _bias value is moved from one font to another, *adding* _bias
// to this hash may result in a final identical GetFontListHash() value
// (as GetFontListHash() does add all these hashes).
// We need to use it a multiplicator to be sure it changes GetFontListHash().
if ( _bias > 0 )
h *= _bias + 1;
return h;
}

/// returns font file name
Expand Down Expand Up @@ -594,7 +602,7 @@ class LVFontCache
if (doc == -1 || doc == documentId) // skip document fonts
hash = hash + _registered_list[i]->getDef()->getHash();
}
return 0;
return hash;
}
virtual void getFaceList( lString32Collection & list )
{
Expand All @@ -620,7 +628,7 @@ class LVFontCache
}
list.sort();
}
virtual bool getFontFileNameAndFaceIndex( lString32 name, bool bold, bool italic, lString8 & filename, int & index )
virtual bool getFontFileNameAndFaceIndex( lString32 name, bool bold, bool italic, lString8 & filename, int & index, int & family_type )
{
int base_weight = bold ? 700 : 400;
LVFontDef * best_def = NULL;
Expand All @@ -646,6 +654,7 @@ class LVFontCache
if ( best_def ) {
filename = best_def->getName();
index = best_def->getIndex();
family_type = best_def->getFamily();
return true;
}
return false;
Expand Down Expand Up @@ -1292,7 +1301,8 @@ class LVFreeTypeFace : public LVFont
FT_Face _face;
FT_GlyphSlot _slot;
FT_Matrix _matrix; // helper matrix for fake italic metrics
int _size; // caracter height in pixels
int _face_size; // font size in pixels (requested from face, internal)
int _size; // font size (~ visual char height) in pixels (public)
int _height; // full line height in pixels
int _hyphen_width;
int _baseline;
Expand Down Expand Up @@ -1344,6 +1354,9 @@ class LVFreeTypeFace : public LVFont
if ( _fallbackFontIsSet )
return _fallbackFont.get();
_fallbackFont = fontMan->GetFallbackFont(_size, getWeight(), _italic!=0);
if ( fontMan->GetFallbackFontSizesAdjusted() ) {
_fallbackFont = getVisuallyAdjustedOtherFont( _fallbackFont );
}
_fallbackFontIsSet = true;
return _fallbackFont.get();
}
Expand All @@ -1360,10 +1373,49 @@ class LVFreeTypeFace : public LVFont
if ( _nextFallbackFontIsSet )
return _nextFallbackFont.get();
_nextFallbackFont = fontMan->GetFallbackFont(_size, getWeight(), _italic!=0, _faceName);
if ( fontMan->GetFallbackFontSizesAdjusted() ) {
_nextFallbackFont = getVisuallyAdjustedOtherFont( _nextFallbackFont );
}
_nextFallbackFontIsSet = true;
return _nextFallbackFont.get();
}

LVFontRef getVisuallyAdjustedOtherFont( LVFontRef other_font ) {
if ( other_font.isNull() )
return other_font;
// We use the x-height (the height of the lowercase 'x')
// as the visual cue we want to make similar.
int h = getXHeight();
int other_h = ((LVFreeTypeFace*)(other_font.get()))->getXHeight();
int other_adjusted_size = (_size * h + _size/2) / other_h; // round it
if ( other_font->getSize() == other_adjusted_size )
return other_font;
return fontMan->GetFont(other_adjusted_size, other_font->getWeight(), other_font->getItalic()!=0,
other_font->getFontFamily(), other_font->getTypeFace(), other_font->getFeatures(), -1);
}

int getXHeight() {
int x_height = 0;
int glyph_index = getCharIndex( 'x', 0 );
if ( glyph_index ) {
int error = FT_Load_Glyph( _face, glyph_index, FT_LOAD_DEFAULT );
if ( !error ) {
x_height = _slot->metrics.horiBearingY;
}
}
if ( x_height <= 0 ) {
TT_OS2 * os2 = (TT_OS2 *)FT_Get_Sfnt_Table(_face, FT_SFNT_OS2);
if ( os2 && os2->sxHeight > 0 ) {
// The os2 table values are each a constant, that we need to scale
x_height = FT_MulFix(os2->sxHeight, _face->size->metrics.y_scale);
}
}
if ( x_height <= 0 ) {
x_height = _size*64 / 2; // 0.5em
}
return x_height;
}

virtual LVFont * getDecimalListItemFont() {
if ( _DecimalListItemFontIsSet )
return _DecimalListItemFont.get();
Expand Down Expand Up @@ -1436,7 +1488,7 @@ class LVFreeTypeFace : public LVFont
FT_Library getLibrary() { return _library; }

LVFreeTypeFace( LVMutex &mutex, FT_Library library, LVFontGlobalGlyphCache * globalCache )
: _mutex(mutex), _fontFamily(css_ff_sans_serif), _library(library), _face(NULL)
: _mutex(mutex), _fontFamily(css_ff_sans_serif), _library(library), _face(NULL), _face_size(0)
, _size(0), _hyphen_width(0), _baseline(0), _underline_offset(0), _underline_thickness(0)
, _weight(400), _italic(0), _features(0), _extra_metric(NULL)
, _glyph_cache(globalCache), _drawMonochrome(false)
Expand Down Expand Up @@ -1779,7 +1831,7 @@ class LVFreeTypeFace : public LVFont

// Used when an embedded font (registered by RegisterDocumentFont()) is intantiated
bool loadFromBuffer(LVByteArrayRef buf, int index, int size, css_font_family_t fontFamily,
bool monochrome, bool italicize, int weight=-1 ) {
bool monochrome, bool italicize, int weight=-1, int face_size=-1 ) {
FONT_GUARD
_hintingMode = fontMan->GetHintingMode();
_drawMonochrome = monochrome;
Expand All @@ -1806,6 +1858,7 @@ class LVFreeTypeFace : public LVFont
//FT_Face_SetUnpatentedHinting( _face, 1 );
_slot = _face->glyph;
_faceName = familyName(_face);
_face_size = face_size > 0 ? face_size : size;
CRLog::debug("Loaded font %s [%d]: faceName=%s, ", _fileName.c_str(), index, _faceName.c_str() );
//if ( !FT_IS_SCALABLE( _face ) ) {
// Clear();
Expand All @@ -1814,7 +1867,7 @@ class LVFreeTypeFace : public LVFont
error = FT_Set_Pixel_Sizes(
_face, /* handle to face object */
0, /* pixel_width */
size ); /* pixel_height */
_face_size ); /* pixel_height */

#if USE_HARFBUZZ==1
if (FT_Err_Ok == error) {
Expand Down Expand Up @@ -1892,7 +1945,7 @@ class LVFreeTypeFace : public LVFont

// Load font from file path
bool loadFromFile( const char * fname, int index, int size, css_font_family_t fontFamily,
bool monochrome, bool italicize, int weight=-1 ) {
bool monochrome, bool italicize, int weight=-1, int face_size=-1 ) {
FONT_GUARD
_hintingMode = fontMan->GetHintingMode();
_drawMonochrome = monochrome;
Expand Down Expand Up @@ -1923,6 +1976,7 @@ class LVFreeTypeFace : public LVFont
//FT_Face_SetUnpatentedHinting( _face, 1 );
_slot = _face->glyph;
_faceName = familyName(_face);
_face_size = face_size > 0 ? face_size : size;
CRLog::debug("Loaded font %s [%d]: faceName=%s, ", _fileName.c_str(), index, _faceName.c_str() );
//if ( !FT_IS_SCALABLE( _face ) ) {
// Clear();
Expand All @@ -1931,7 +1985,7 @@ class LVFreeTypeFace : public LVFont
error = FT_Set_Pixel_Sizes(
_face, /* handle to face object */
0, /* pixel_width */
size ); /* pixel_height */
_face_size ); /* pixel_height */

#if USE_HARFBUZZ==1
if (FT_Err_Ok == error) {
Expand Down Expand Up @@ -4427,7 +4481,7 @@ class LVFreeTypeFace : public LVFont
error = FT_Set_Pixel_Sizes(
_face, /* handle to face object */
0, /* pixel_width */
_size ); /* pixel_height */
_face_size ); /* pixel_height */
return;
}

Expand Down Expand Up @@ -5009,13 +5063,15 @@ class LVFreeTypeFontManager : public LVFontManager
FONT_MAN_GUARD
if ( _fallbackFontFaces.length() == 0 )
return LVFontRef();
/* No real need to limit the number of instances (we prefer accuracy)
// reduce number of possible distinct sizes for fallback font
if ( size>40 )
size &= 0xFFF8;
else if ( size>28 )
size &= 0xFFFC;
else if ( size>16 )
size &= 0xFFFE;
*/
// If forFaceName not provided, returns first font among _fallbackFontFaces.
// If forFaceName provided, returns the one just after it, if forFaceName is
// among _fallbackFontFaces. If it is not, return the first one.
Expand Down Expand Up @@ -5101,6 +5157,32 @@ class LVFreeTypeFontManager : public LVFontManager
}
}

/// set monospace size scale percent
virtual void SetMonospaceSizeScale( int scale )
{
FONT_MAN_GUARD
_monospaceSizeScale = scale;
gc();
clearGlyphCache();
// We would need to loop thru each instance and somehow invalidate
// the monospace instances, as we need to load another face size
// from the font file. This seems quite tedious to implement, as
// nodes at this moment keep each instance's refCount alive.
// But, when having only a single document loaded, _monospaceSizeScale
// being part of the document hash, changing it will cause a rerendering,
// which will cause all font instances to have no references and
// being destroyed before the re-rendering, which will instantiate
// them again with the adjusted size.
}

virtual void SetFallbackFontSizesAdjusted( bool adjusted )
{
FONT_MAN_GUARD
_fallbackFontSizesAdjusted = adjusted;
_cache.clearFallbackFonts();
gc();
}

/// clear glyph cache
virtual void clearGlyphCache()
{
Expand Down Expand Up @@ -5416,10 +5498,10 @@ class LVFreeTypeFontManager : public LVFontManager
_cache.regularizeRegisteredFontsWeights(print_updates);
}

virtual bool getFontFileNameAndFaceIndex( lString32 name, bool bold, bool italic, lString8 & filename, int & index )
virtual bool getFontFileNameAndFaceIndex( lString32 name, bool bold, bool italic, lString8 & filename, int & index, int & family_type )
{
FONT_MAN_GUARD
return _cache.getFontFileNameAndFaceIndex(name, bold, italic, filename, index);
return _cache.getFontFileNameAndFaceIndex(name, bold, italic, filename, index, family_type);
}

virtual void getRegisteredDocumentFontList( int document_id, lString32Collection & list )
Expand Down Expand Up @@ -5652,10 +5734,14 @@ class LVFreeTypeFontManager : public LVFontManager

//printf("going to load font file %s\n", fname.c_str());
bool loaded = false;
int face_size = size;
if ( family == css_ff_monospace && GetMonospaceSizeScale() != 100 ) {
face_size = size * GetMonospaceSizeScale() / 100;
}
if (item->getDef()->getBuf().isNull())
loaded = font->loadFromFile( pathname.c_str(), item->getDef()->getIndex(), size, family, isBitmapModeForSize(size), italicize, item->getDef()->getWeight() );
loaded = font->loadFromFile( pathname.c_str(), item->getDef()->getIndex(), size, family, isBitmapModeForSize(size), italicize, item->getDef()->getWeight(), face_size );
else
loaded = font->loadFromBuffer(item->getDef()->getBuf(), item->getDef()->getIndex(), size, family, isBitmapModeForSize(size), italicize, item->getDef()->getWeight() );
loaded = font->loadFromBuffer(item->getDef()->getBuf(), item->getDef()->getIndex(), size, family, isBitmapModeForSize(size), italicize, item->getDef()->getWeight(), face_size );
if (loaded) {
//fprintf(_log, " : loading from file %s : %s %d\n", item->getDef()->getName().c_str(),
// item->getDef()->getTypeFace().c_str(), item->getDef()->getSize() );
Expand Down
2 changes: 1 addition & 1 deletion crengine/src/lvtextfm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4845,7 +4845,7 @@ class LVFormatter {
if ( !grabbedExceedingSpace &&
m_pbuffer->min_space_condensing_percent != 100 &&
i < m_length-1 &&
( m_flags[i] & LCHAR_IS_SPACE ) &&
( m_flags[i] & LCHAR_IS_SPACE ) && !( m_flags[i] & LCHAR_LOCKED_SPACING ) &&
!(m_flags[i+1] & LCHAR_IS_SPACE) ) {
// Each space not followed by a space is candidate for space condensing
int dw = getMaxCondensedSpaceTruncation(i);
Expand Down
2 changes: 2 additions & 0 deletions crengine/src/lvtinydom.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,8 @@ lUInt32 calcGlobalSettingsHash(int documentId, bool already_rendered)
// if ( fontMan->getKerning() )
// hash += 127365;
hash = hash * 31 + (int)fontMan->GetKerningMode();
hash = hash * 31 + fontMan->GetMonospaceSizeScale();
hash = hash * 31 + (int)fontMan->GetFallbackFontSizesAdjusted();
hash = hash * 31 + fontMan->GetFontListHash(documentId);
// Hinting mode change does not need to trigger a re-render, as since
// we use FT_LOAD_TARGET_LIGHT, hinting has no effect on the x-axis
Expand Down