Skip to content

Fontique: duplication and redundant re-scanning in load_fonts_from_paths #683

Description

@7sDream

Description

When using Collection::load_fonts_from_paths to register fonts from a directory, the resulting Collection contains duplicate entries for the same font file.

❯ cargo run --release -- a --no-system -I Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB -vv
    Finished `release` profile [optimized] target(s) in 0.22s
     Running `target\release\fontfor.exe a --no-system -I Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB -vv`
Font(s) support the character "a"(U+0061, 97, 0x61):
LXGW WenKai GB
        LXGW WenKai GB  Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiGB-Regular.ttf:0
        LXGW WenKai GB  Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiGB-Regular.ttf:0
        LXGW WenKai GB  Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiGB-Regular.ttf:0
        LXGW WenKai GB  Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiGB-Regular.ttf:0
        LXGW WenKai GB Light    Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiGB-Light.ttf:0
        LXGW WenKai GB Light    Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiGB-Light.ttf:0
        LXGW WenKai GB Light    Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiGB-Light.ttf:0
        LXGW WenKai GB Light    Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiGB-Light.ttf:0
        LXGW WenKai GB Light    Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiGB-Light.ttf:0
        LXGW WenKai GB Light    Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiGB-Light.ttf:0
        LXGW WenKai GB Medium   Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiGB-Medium.ttf:0
        LXGW WenKai GB Medium   Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiGB-Medium.ttf:0
        LXGW WenKai GB Medium   Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiGB-Medium.ttf:0
        LXGW WenKai GB Medium   Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiGB-Medium.ttf:0
        LXGW WenKai GB Medium   Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiGB-Medium.ttf:0
LXGW WenKai Mono GB
        LXGW WenKai Mono GB     Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiMonoGB-Regular.ttf:0
        LXGW WenKai Mono GB Light       Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiMonoGB-Light.ttf:0
        LXGW WenKai Mono GB Light       Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiMonoGB-Light.ttf:0
        LXGW WenKai Mono GB Light       Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiMonoGB-Light.ttf:0
        LXGW WenKai Mono GB Medium      Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiMonoGB-Medium.ttf:0
        LXGW WenKai Mono GB Medium      Y:\Cloud\Data\Fonts\Free\Lxgw\WenkaiGB\LXGWWenKaiMonoGB-Medium.ttf:0

Cause

Currently, the load_fonts_from_path function contains a families map inside it, and each time the scan_path callback is triggered, the register_font_impl it calls adds all fonts in this families map to self.families. Throughout the entire process, families is never cleared.

At the same time, it is quite strange that while the scan_path callback already returns ScannedFont, register_font_impl still uses scan_memory to re-process all fonts in the data. This not only causes performance issues but also leads to further font duplication when processing TTC files...

For example, when I was testing on Linux, I encountered this spectacle:
❯ cargo run --release -- a --no-system -I /usr/share/fonts
    Finished `release` profile [optimized] target(s) in 0.87s
     Running `target/release/fontfor a --no-system -I /usr/share/fonts`
Font(s) support the character "a"(U+0061, 97, 0x61):
Adwaita Mono                  with 690 styles
Adwaita Sans                  with 339 styles
C059                          with 138 styles
Cantarell                     with 1065 styles
D050000L                      with 32 styles
Droid Sans                    with 323 styles
Droid Sans Devanagari         with 159 styles
Droid Sans Thai               with 149 styles
Font Awesome 6 Brands         with 168 styles
Font Awesome 6 Free           with 333 styles
Jomolhari                     with 79 styles
Liberation Mono               with 306 styles
Liberation Sans               with 290 styles
Liberation Serif              with 274 styles
Madan2                        with 66 styles
Nimbus Mono PS                with 118 styles
Nimbus Roman                  with 102 styles
Nimbus Sans                   with 86 styles
Nimbus Sans Narrow            with 70 styles
Noto Sans                     with 224 styles
Noto Sans CJK HK              with 695 styles
Noto Sans CJK JP              with 695 styles
Noto Sans CJK KR              with 695 styles
Noto Sans CJK SC              with 695 styles
Noto Sans CJK TC              with 695 styles
Noto Sans Math                with 147 styles
Noto Sans Mono                with 109 styles
Noto Sans Mono CJK HK         with 670 styles
Noto Sans Mono CJK JP         with 670 styles
Noto Sans Mono CJK KR         with 670 styles
Noto Sans Mono CJK SC         with 670 styles
Noto Sans Mono CJK TC         with 670 styles
Noto Sans Sinhala             with 106 styles
Noto Sans Symbols             with 105 styles
Noto Serif                    with 178 styles
Noto Serif CJK HK             with 645 styles
Noto Serif CJK JP             with 645 styles
Noto Serif CJK KR             with 645 styles
Noto Serif CJK SC             with 645 styles
Noto Serif CJK TC             with 645 styles
Open Sans                     with 605 styles
P052                          with 54 styles
Padauk                        with 93 styles
PakType Naskh Basic           with 55 styles
PakType Naskh Basic Semi Wide with 54 styles
PakType Naskh Basic Wide      with 53 styles
RIT Meera New                 with 52 styles
RIT Rachana                   with 198 styles
STIX Two Math                 with 45 styles
STIX Two Text                 with 324 styles
Standard Symbols PS           with 11 styles
Symbola                       with 165 styles
URW Bookman                   with 34 styles
URW Gothic                    with 18 styles
Vazirmatn                     with 1 style
Z003                          with 2 styles

I had intended to submit a PR (implementing ScannedFont registration directly within the scan_path callback) to fix this issue. However, given that the current implementation is quite messy, I am not confident that I understand the rationale behind the current design, so I have opted to submit an issue instead.

Additionally, these two lines of code also seem very strange and redundant. This is just an extra found and is unrelated to the issue mentioned above.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions