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

Fixes #641 Support fallback fonts #669

Merged
merged 4 commits into from
Mar 19, 2021
Merged

Conversation

danfickle
Copy link
Owner

Fixes #641

Including major refactor of PDF font resolver and passing test.

Why it is required:
Currently fonts not matching the specified font-family in CSS are not used. This PR allows one to register fonts to be used in the event that there are no fonts which match the font-family and support the current character.

Fallback fonts can be registered to try before the built-in fonts (FALLBACK_PRE) or after (FALLBACK_FINAL).

We can now do:

           // DOCUMENT fonts will only match if the `font-family` includes 'SourceSans'.
           builder.useFont(
                    new File("target/test/visual-tests/SourceSansPro-Regular.ttf"),
                    "SourceSans", 400, FontStyle.NORMAL, true,
                    EnumSet.of(FSFontUseCase.DOCUMENT));
            // This font however will be tried after the `font-family` fonts but before the built-in fonts.
            builder.useFont(
                    new File("target/test/visual-tests/Karla-Bold.ttf"),
                    "Karla", 700, FontStyle.NORMAL, true,
                    EnumSet.of(FSFontUseCase.FALLBACK_PRE));
<div style="font-family: 'SourceSans'; font-weight: 400;">
Text should look normal!
</div>

<!-- Using fallback font -->
<div style="font-family: 'no-exist'; font-weight: 400;">
Text should look bold!
</div>

Fallback fonts are sorted from lowest priority to highest. The inputs are provided from CSS.

private int getFontPriority(FontDescription font, String[] families, IdentValue weight, IdentValue desiredStyle, IdentValue variant) {
            String fontFamily = font.getFamily();
            int fontWeight = font.getWeight();
            IdentValue fontStyle = font.getStyle();

            List<String> desiredFamilies = families != null ?
                    Arrays.asList(families) : Collections.emptyList();
            int desiredWeight = FontResolverHelper.convertWeightToInt(weight);

            if (fontWeight == desiredWeight &&
                fontStyle == desiredStyle) {
                // Exact match for weight and style.
                return getFamilyPriority(fontFamily, desiredFamilies);
            } else if (Math.abs(fontWeight - desiredWeight) < 200 &&
                       fontStyle == desiredStyle) {
                // Near enough weight match, exact style match.
                return 3 + getFamilyPriority(fontFamily, desiredFamilies);
            } else if (fontStyle == desiredStyle) {
                // No weight match, but style matches.
                return 6 + getFamilyPriority(fontFamily, desiredFamilies);
            } else {
                // Neither weight nor style matches.
                return 9 + getFamilyPriority(fontFamily, desiredFamilies);
            }
        }

        private int getFamilyPriority(String fontFamily, List<String> desiredFamilies) {
            if (!desiredFamilies.isEmpty() &&
                desiredFamilies.get(0).equals(fontFamily)) {
                return 1;
            } else if (desiredFamilies.contains(fontFamily)) {
                return 2;
            } else {
                return 3;
            }
        }

Including major refactor of PDF font resolver and working test.
to avoid mega class in PdfBoxFontResolver.
This optimization was assumable designed to avoid the O(n) lookup of a font family variants. However when n is mostly 4 or under it is unneeded and complicates the code without good reason.

Speaking of premature opts, also added a few performance tweaks to the matching process.
@danfickle danfickle merged commit bde3106 into open-dev-v1 Mar 19, 2021
@danfickle danfickle deleted the fix_641_fallback_font branch March 19, 2021 08:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

How to override font family for all the text in html in PdfRendererBuilder?
1 participant