diff --git a/CHANGELOG.md b/CHANGELOG.md index 33f38777..34e318e0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,6 +64,20 @@ follow semantic versioning; release dates are ISO 8601. ### Fixed +- **The donut-centre KPI renders the weight it declares.** A style names a font + *family* and a *decoration*, and the decoration is what picks the face within the + family — the standard-14 face constants (`HELVETICA_BOLD`, `TIMES_ITALIC`, …) are + aliases of their family and carry no weight of their own. The chart default named + the bold face and set no decoration, so it rendered regular, measured with regular + metrics, in every donut chart that did not override the centre style. Nothing + announced it: the text laid out and drew. `FontLibrary` now logs one warning per + face constant it rewrites, the sixteen places in the library that named a face + redundantly name their family instead, and the resolved glyph program is pinned by + test — both the rule and the donut default itself, since the rule alone would not + catch the site going back. Three rendered documents change — the engine + deck, the feature catalogue and the chart showcase. ([#451](https://github.com/DemchaAV/GraphCompose/issues/451)) + + - **A heading no longer strands above a block that was asked to stay whole.** `keepWithNext()` decides by asking whether the heading plus the *first line* of the next block fits, but a `keepTogether()` block has no first line to break diff --git a/assets/readme/examples/chart-showcase.pdf b/assets/readme/examples/chart-showcase.pdf index c91ab4cf..0fde69f3 100644 Binary files a/assets/readme/examples/chart-showcase.pdf and b/assets/readme/examples/chart-showcase.pdf differ diff --git a/assets/readme/examples/engine-deck.pdf b/assets/readme/examples/engine-deck.pdf index 6477ea93..ff6dca0f 100644 Binary files a/assets/readme/examples/engine-deck.pdf and b/assets/readme/examples/engine-deck.pdf differ diff --git a/assets/readme/examples/feature-catalog.pdf b/assets/readme/examples/feature-catalog.pdf index 304cbdce..ea60f333 100644 Binary files a/assets/readme/examples/feature-catalog.pdf and b/assets/readme/examples/feature-catalog.pdf differ diff --git a/core/src/main/java/com/demcha/compose/document/chart/ChartDefaults.java b/core/src/main/java/com/demcha/compose/document/chart/ChartDefaults.java index c1348bf8..c0ce56f8 100644 --- a/core/src/main/java/com/demcha/compose/document/chart/ChartDefaults.java +++ b/core/src/main/java/com/demcha/compose/document/chart/ChartDefaults.java @@ -3,6 +3,7 @@ import com.demcha.compose.document.style.DocumentColor; import com.demcha.compose.document.style.DocumentPaint; import com.demcha.compose.document.style.DocumentStroke; +import com.demcha.compose.document.style.DocumentTextDecoration; import com.demcha.compose.document.style.DocumentTextStyle; import com.demcha.compose.font.FontName; @@ -98,7 +99,8 @@ public final class ChartDefaults { * Default donut-centre KPI text style. */ public static final DocumentTextStyle DONUT_CENTER_TEXT_STYLE = DocumentTextStyle.builder() - .fontName(FontName.HELVETICA_BOLD) + .fontName(FontName.HELVETICA) + .decoration(DocumentTextDecoration.BOLD) .size(13) .color(DocumentColor.rgb(45, 45, 45)) .build(); diff --git a/core/src/main/java/com/demcha/compose/document/dsl/HeadingBarStyle.java b/core/src/main/java/com/demcha/compose/document/dsl/HeadingBarStyle.java index 5586ed87..230b1154 100644 --- a/core/src/main/java/com/demcha/compose/document/dsl/HeadingBarStyle.java +++ b/core/src/main/java/com/demcha/compose/document/dsl/HeadingBarStyle.java @@ -18,7 +18,7 @@ public final class HeadingBarStyle { private static final DocumentTextStyle DEFAULT_TEXT = DocumentTextStyle.builder() - .fontName(FontName.HELVETICA_BOLD) + .fontName(FontName.HELVETICA) .decoration(DocumentTextDecoration.BOLD) .size(11) .build(); diff --git a/core/src/main/java/com/demcha/compose/document/dsl/TimelineBuilder.java b/core/src/main/java/com/demcha/compose/document/dsl/TimelineBuilder.java index 39d9d2a0..0c27a7a3 100644 --- a/core/src/main/java/com/demcha/compose/document/dsl/TimelineBuilder.java +++ b/core/src/main/java/com/demcha/compose/document/dsl/TimelineBuilder.java @@ -66,7 +66,7 @@ private static boolean notBlank(String value) { private static DocumentTextStyle defaultTitleStyle() { return DocumentTextStyle.builder() - .fontName(FontName.HELVETICA_BOLD) + .fontName(FontName.HELVETICA) .decoration(DocumentTextDecoration.BOLD) .size(11) .color(DEFAULT_INK) diff --git a/core/src/main/java/com/demcha/compose/document/dsl/TimelineMarker.java b/core/src/main/java/com/demcha/compose/document/dsl/TimelineMarker.java index 3ea83dda..17bcb9be 100644 --- a/core/src/main/java/com/demcha/compose/document/dsl/TimelineMarker.java +++ b/core/src/main/java/com/demcha/compose/document/dsl/TimelineMarker.java @@ -71,7 +71,7 @@ public static TimelineMarker circle(double size, DocumentColor fill, DocumentStr public static TimelineMarker numbered(int number, double size, DocumentColor fill, DocumentColor textColor) { DocumentTextStyle label = DocumentTextStyle.builder() - .fontName(FontName.HELVETICA_BOLD) + .fontName(FontName.HELVETICA) .decoration(DocumentTextDecoration.BOLD) .size(Math.max(6.0, size * 0.5)) .color(textColor == null ? DocumentColor.WHITE : textColor) diff --git a/core/src/main/java/com/demcha/compose/document/style/DocumentTextStyle.java b/core/src/main/java/com/demcha/compose/document/style/DocumentTextStyle.java index f3c891d6..30ba09bc 100644 --- a/core/src/main/java/com/demcha/compose/document/style/DocumentTextStyle.java +++ b/core/src/main/java/com/demcha/compose/document/style/DocumentTextStyle.java @@ -10,7 +10,11 @@ *

The DSL adapts this value into the internal engine text style during * composition. Instances are immutable and thread-safe.

* - * @param fontName font family name + * @param fontName font family name. The standard-14 face constants + * ({@code HELVETICA_BOLD}, {@code TIMES_ITALIC}, …) are aliases of + * their family and carry no weight or slant of their own — the face + * comes from {@code decoration}. Naming a face and leaving the + * decoration unset renders the regular face. * @param size font size in points * @param decoration text decoration * @param color text color diff --git a/core/src/main/java/com/demcha/compose/font/FontLibrary.java b/core/src/main/java/com/demcha/compose/font/FontLibrary.java index 2db8b777..5c1a99aa 100644 --- a/core/src/main/java/com/demcha/compose/font/FontLibrary.java +++ b/core/src/main/java/com/demcha/compose/font/FontLibrary.java @@ -1,5 +1,8 @@ package com.demcha.compose.font; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.util.Collections; import java.util.LinkedHashSet; import java.util.Map; @@ -22,6 +25,15 @@ */ public class FontLibrary { + private static final Logger LOG = LoggerFactory.getLogger(FontLibrary.class); + + /** + * Face aliases already reported, so the warning costs one line per name, not per + * lookup. Package-private so the guard covering the warning can start from a known + * state — a static cache is otherwise order-dependent across a test class. + */ + static final Set WARNED_FACE_ALIASES = ConcurrentHashMap.newKeySet(); + private static final Map FONT_ALIASES = Map.ofEntries( Map.entry(FontName.HELVETICA_BOLD, FontName.HELVETICA), Map.entry(FontName.HELVETICA_OBLIQUE, FontName.HELVETICA), @@ -147,6 +159,30 @@ private FontName resolveBaseFont(FontName fontName) { if (fontName == null || FontName.DEFAULT.equals(fontName)) { return FontName.HELVETICA; } - return FONT_ALIASES.getOrDefault(fontName, fontName); + FontName base = FONT_ALIASES.get(fontName); + if (base == null) { + return fontName; + } + warnOnceAboutFaceAlias(fontName, base); + return base; + } + + /** + * Warns the first time a style selects a standard-14 face by name. + * + *

A name like {@code HELVETICA_BOLD} is an alias of its family: it is rewritten + * to {@code HELVETICA} here, and the face is chosen later from the style's + * decoration. Naming the face therefore contributes nothing, and a style that names + * it and sets no decoration renders regular — silently, since the text still lays + * out and still draws. One line per distinct alias, so a document that uses the form + * a thousand times says so once.

+ */ + private static void warnOnceAboutFaceAlias(FontName requested, FontName base) { + if (WARNED_FACE_ALIASES.add(requested)) { + LOG.warn("fontName({}) selects the {} family, not a face — the face comes from the " + + "style's decoration. Name the family and set decoration(...) instead; " + + "as written this renders {} unless a decoration says otherwise.", + requested.name(), base.name(), base.name()); + } } } diff --git a/core/src/test/java/com/demcha/compose/font/FontFaceAliasWarningTest.java b/core/src/test/java/com/demcha/compose/font/FontFaceAliasWarningTest.java new file mode 100644 index 00000000..6526acf6 --- /dev/null +++ b/core/src/test/java/com/demcha/compose/font/FontFaceAliasWarningTest.java @@ -0,0 +1,114 @@ +package com.demcha.compose.font; + +import ch.qos.logback.classic.Level; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.core.read.ListAppender; + +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.slf4j.LoggerFactory; + +import java.util.List; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Covers the signal that makes the face-alias trap visible. + * + *

A standard-14 face constant is an alias of its family, so a style naming one and + * setting no decoration renders regular without failing, logging or measuring + * differently. The warning is the whole of what makes that observable, which makes it + * worth a test rather than a hope.

+ * + *

Known limit, asserted here rather than left implicit: the warning + * is keyed on the alias alone, not on the pairing of alias and decoration. The library + * cannot see the decoration at the point it rewrites the name. So the first use of + * {@code HELVETICA_BOLD} consumes the warning even when that use is correct, and a later + * broken one is silent. The signal catches a codebase that uses the form, not the + * individual style that gets it wrong; {@code DocsBoldFaceGuardTest} and + * {@code FontFaceResolutionTest} cover the specific sites.

+ */ +class FontFaceAliasWarningTest { + + private ListAppender appender; + private ch.qos.logback.classic.Logger logger; + + @BeforeEach + void captureWarnings() { + FontLibrary.WARNED_FACE_ALIASES.clear(); + logger = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(FontLibrary.class); + appender = new ListAppender<>(); + appender.start(); + logger.addAppender(appender); + logger.setLevel(Level.WARN); + } + + @AfterEach + void releaseAppender() { + logger.detachAppender(appender); + FontLibrary.WARNED_FACE_ALIASES.clear(); + } + + private List warnings() { + return appender.list.stream() + .filter(event -> event.getLevel() == Level.WARN) + .map(ILoggingEvent::getFormattedMessage) + .toList(); + } + + @Test + void namingAFaceWarnsOnceAndNamesBothTheConstantAndItsFamily() { + FontLibrary library = new FontLibrary(); + + library.getFont(FontName.HELVETICA_BOLD, Object.class); + + assertThat(warnings()) + .describedAs("naming a face must say so — it is the only signal that the " + + "constant carries no weight of its own") + .hasSize(1); + assertThat(warnings().get(0)) + .contains(FontName.HELVETICA_BOLD.name()) + .contains(FontName.HELVETICA.name()) + .contains("decoration"); + } + + @Test + void repeatingTheSameFaceDoesNotRepeatTheWarning() { + FontLibrary library = new FontLibrary(); + + for (int i = 0; i < 50; i++) { + library.getFont(FontName.HELVETICA_BOLD, Object.class); + } + + assertThat(warnings()) + .describedAs("the warning is per name, not per lookup: a document that uses the " + + "form on every span would otherwise bury its own output") + .hasSize(1); + } + + @Test + void eachFaceGetsItsOwnWarning() { + FontLibrary library = new FontLibrary(); + + library.getFont(FontName.HELVETICA_BOLD, Object.class); + library.getFont(FontName.TIMES_BOLD, Object.class); + library.getFont(FontName.COURIER_OBLIQUE, Object.class); + + assertThat(warnings()).hasSize(3); + assertThat(warnings()).anyMatch(message -> message.contains(FontName.TIMES_ROMAN.name())); + } + + @Test + void namingAFamilyIsSilent() { + FontLibrary library = new FontLibrary(); + + library.getFont(FontName.HELVETICA, Object.class); + library.getFont(FontName.TIMES_ROMAN, Object.class); + library.getFont(FontName.COURIER, Object.class); + + assertThat(warnings()) + .describedAs("the correct form must not be noisy, or the signal is worthless") + .isEmpty(); + } +} diff --git a/docs/font-coverage.md b/docs/font-coverage.md index a9f01847..40eb3c89 100644 --- a/docs/font-coverage.md +++ b/docs/font-coverage.md @@ -4,6 +4,28 @@ Not every character can be drawn by every font. This page explains what the built-in PDF fonts can encode, why an unexpected `?` sometimes appears, and the three ways to render the symbol you actually wanted. +## The name picks the family, the decoration picks the face + +A style names a family and a decoration, and those are two different choices: + +```java +DocumentTextStyle.builder() + .fontName(FontName.HELVETICA) // family + .decoration(DocumentTextDecoration.BOLD) // face within it + .size(28) + .build(); +``` + +The standard-14 face constants — `HELVETICA_BOLD`, `TIMES_ITALIC`, +`COURIER_BOLD_OBLIQUE` and the rest — are **aliases of their family**, not faces. +`FontLibrary` rewrites each one to its base family before any lookup, so naming a +face contributes nothing and the decoration alone decides the glyph program. A +style that names `HELVETICA_BOLD` and sets no decoration renders regular +Helvetica, measured with regular metrics; the text lays out and draws, so nothing +announces it. The library logs one warning per such name to make it visible. + +Name the family, set the decoration. + ## WinAnsi and the base-14 fonts The built-in fonts — `HELVETICA`, `TIMES`, `COURIER` and their bold / italic diff --git a/render-pdf/src/test/java/com/demcha/compose/document/backend/fixed/pdf/FontFaceResolutionTest.java b/render-pdf/src/test/java/com/demcha/compose/document/backend/fixed/pdf/FontFaceResolutionTest.java new file mode 100644 index 00000000..6932d0c1 --- /dev/null +++ b/render-pdf/src/test/java/com/demcha/compose/document/backend/fixed/pdf/FontFaceResolutionTest.java @@ -0,0 +1,89 @@ +package com.demcha.compose.document.backend.fixed.pdf; + +import com.demcha.compose.document.chart.ChartDefaults; +import com.demcha.compose.engine.render.pdf.PdfFont; +import com.demcha.compose.engine.components.content.text.TextDecoration; +import com.demcha.compose.font.FontLibrary; +import com.demcha.compose.font.FontName; + +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Pins the rule that decides which glyph program a style actually gets: the font + * name selects the family, the decoration selects the face within it. + * + *

The rule is easy to state and was invisible in the suite. {@code FontLibrary} + * rewrites every standard-14 face constant to its base family before any lookup, so + * {@code fontName(HELVETICA_BOLD)} contributes nothing and a style that sets no + * decoration renders regular — silently, because the text still measures and still + * draws. That is what the donut-centre KPI did.

+ * + *

Asserted on the resolved {@code PDFont}, which is the glyph program the page + * actually references, rather than on a rendered image: a weight difference is a font + * resource difference, and reading it directly says which face without a pixel + * threshold to argue about.

+ * + *

These assertions are the ones that must change if the alias is ever made a real + * fallback — which makes the behaviour change deliberate instead of incidental.

+ */ +class FontFaceResolutionTest { + + private static final FontLibrary LIBRARY = PdfFontLibraryFactory.standardLibrary(); + + private static String face(FontName name, TextDecoration decoration) { + PdfFont font = LIBRARY.getFont(name, PdfFont.class).orElseThrow(); + return font.fontType(decoration).getName(); + } + + @Test + void theDecorationSelectsTheFaceWithinTheFamily() { + assertThat(face(FontName.HELVETICA, TextDecoration.DEFAULT)).isEqualTo("Helvetica"); + assertThat(face(FontName.HELVETICA, TextDecoration.BOLD)).isEqualTo("Helvetica-Bold"); + assertThat(face(FontName.TIMES_ROMAN, TextDecoration.BOLD)).isEqualTo("Times-Bold"); + assertThat(face(FontName.COURIER, TextDecoration.BOLD)).isEqualTo("Courier-Bold"); + } + + @Test + void aFaceConstantIsAnAliasOfItsFamilyAndCarriesNoWeightOfItsOwn() { + assertThat(face(FontName.HELVETICA_BOLD, TextDecoration.DEFAULT)) + .describedAs("naming the bold face without a decoration renders regular — " + + "the constant is rewritten to its family before the lookup") + .isEqualTo("Helvetica"); + assertThat(face(FontName.TIMES_BOLD, TextDecoration.DEFAULT)).isEqualTo("Times-Roman"); + assertThat(face(FontName.COURIER_BOLD, TextDecoration.DEFAULT)).isEqualTo("Courier"); + + assertThat(face(FontName.HELVETICA_BOLD, TextDecoration.BOLD)) + .describedAs("the alias and the family resolve identically once a decoration " + + "is set, which is why naming the family is the clearer form") + .isEqualTo(face(FontName.HELVETICA, TextDecoration.BOLD)); + } + + /** + * The defect this rule was traced from, pinned at its own site. + * + *

Asserting the rule alone would not catch the regression: a style that goes back + * to naming the bold face and dropping the decoration still satisfies every general + * assertion above. The chart layout tests do not catch it either — they measure + * through fake metrics whose width depends on the character count and ignores the + * face — so without this the donut KPI could quietly return to regular.

+ */ + @Test + void theDonutCentreDefaultResolvesToABoldFace() { + assertThat(face(ChartDefaults.DONUT_CENTER_TEXT_STYLE.fontName(), + TextDecoration.valueOf(ChartDefaults.DONUT_CENTER_TEXT_STYLE.decoration().name()))) + .describedAs("the donut-centre KPI must resolve to a bold glyph program. Naming " + + "the bold face and setting no decoration renders regular — that is the " + + "defect, and it is invisible to the chart layout tests") + .isEqualTo("Helvetica-Bold"); + } + + @Test + void anAliasedNameFollowsTheDecorationEvenWhenTheyDisagree() { + assertThat(face(FontName.HELVETICA_BOLD, TextDecoration.ITALIC)) + .describedAs("the name says bold and the decoration says italic; the decoration " + + "wins, so the constant is actively misleading rather than redundant") + .isEqualTo("Helvetica-Oblique"); + } +} diff --git a/templates/src/main/java/com/demcha/compose/document/templates/coverletter/presets/EditorialBlueLetter.java b/templates/src/main/java/com/demcha/compose/document/templates/coverletter/presets/EditorialBlueLetter.java index 0508de22..aed0f415 100644 --- a/templates/src/main/java/com/demcha/compose/document/templates/coverletter/presets/EditorialBlueLetter.java +++ b/templates/src/main/java/com/demcha/compose/document/templates/coverletter/presets/EditorialBlueLetter.java @@ -110,7 +110,7 @@ public void compose(DocumentSession document, CoverLetterDocument doc) { } private Masthead.Style mastheadStyle() { - DocumentTextStyle nameStyle = TextStyles.of(FontName.HELVETICA_BOLD, + DocumentTextStyle nameStyle = TextStyles.of(FontName.HELVETICA, theme.typography().sizeHeadline(), DocumentTextDecoration.BOLD, NAME_COLOR); DocumentTextStyle titleStyle = TextStyles.of(FontName.HELVETICA, diff --git a/templates/src/main/java/com/demcha/compose/document/templates/coverletter/presets/ModernProfessionalLetter.java b/templates/src/main/java/com/demcha/compose/document/templates/coverletter/presets/ModernProfessionalLetter.java index aacedf52..08fb0d5c 100644 --- a/templates/src/main/java/com/demcha/compose/document/templates/coverletter/presets/ModernProfessionalLetter.java +++ b/templates/src/main/java/com/demcha/compose/document/templates/coverletter/presets/ModernProfessionalLetter.java @@ -102,7 +102,7 @@ public void compose(DocumentSession document, CoverLetterDocument doc) { Objects.requireNonNull(document, "document"); Objects.requireNonNull(doc, "doc"); - DocumentTextStyle nameStyle = TextStyles.of(FontName.HELVETICA_BOLD, + DocumentTextStyle nameStyle = TextStyles.of(FontName.HELVETICA, theme.typography().sizeHeadline(), DocumentTextDecoration.BOLD, NAME_COLOR); DocumentTextStyle contactBodyStyle = TextStyles.of(FontName.HELVETICA, diff --git a/templates/src/main/java/com/demcha/compose/document/templates/cv/presets/EditorialBlue.java b/templates/src/main/java/com/demcha/compose/document/templates/cv/presets/EditorialBlue.java index de65bf28..42637967 100644 --- a/templates/src/main/java/com/demcha/compose/document/templates/cv/presets/EditorialBlue.java +++ b/templates/src/main/java/com/demcha/compose/document/templates/cv/presets/EditorialBlue.java @@ -166,9 +166,9 @@ private void renderEntries(SectionBuilder section, EntriesSection entries) { } private void renderExperienceEntry(SectionBuilder section, CvEntry entry) { - DocumentTextStyle titleStyle = TextStyles.of(FontName.HELVETICA_BOLD, + DocumentTextStyle titleStyle = TextStyles.of(FontName.HELVETICA, 11.0, DocumentTextDecoration.BOLD, NAME_COLOR); - DocumentTextStyle dateStyle = TextStyles.of(FontName.HELVETICA_BOLD, + DocumentTextStyle dateStyle = TextStyles.of(FontName.HELVETICA, 11.0, DocumentTextDecoration.BOLD, theme.palette().rule()); DocumentTextStyle subtitleStyle = TextStyles.of(FontName.HELVETICA, 9.4, DocumentTextDecoration.ITALIC, theme.palette().ink()); @@ -180,9 +180,9 @@ private void renderExperienceEntry(SectionBuilder section, CvEntry entry) { } private void renderEducationEntry(SectionBuilder section, CvEntry entry) { - DocumentTextStyle titleStyle = TextStyles.of(FontName.HELVETICA_BOLD, + DocumentTextStyle titleStyle = TextStyles.of(FontName.HELVETICA, 10.6, DocumentTextDecoration.BOLD, NAME_COLOR); - DocumentTextStyle dateStyle = TextStyles.of(FontName.HELVETICA_BOLD, + DocumentTextStyle dateStyle = TextStyles.of(FontName.HELVETICA, 10.0, DocumentTextDecoration.BOLD, theme.palette().rule()); DocumentTextStyle subtitleStyle = TextStyles.of(FontName.HELVETICA, 9.2, DocumentTextDecoration.ITALIC, theme.palette().ink()); @@ -210,7 +210,7 @@ private void renderRows(SectionBuilder section, RowsSection rows) { } private void renderProject(SectionBuilder section, CvRow row) { - DocumentTextStyle titleStyle = TextStyles.of(FontName.HELVETICA_BOLD, + DocumentTextStyle titleStyle = TextStyles.of(FontName.HELVETICA, 10.6, DocumentTextDecoration.BOLD, NAME_COLOR); DocumentTextStyle stackStyle = TextStyles.of(FontName.HELVETICA, 9.3, DocumentTextDecoration.ITALIC, theme.palette().rule()); @@ -220,7 +220,7 @@ private void renderProject(SectionBuilder section, CvRow row) { } private void renderKeyValue(SectionBuilder section, CvRow row) { - DocumentTextStyle keyStyle = TextStyles.of(FontName.HELVETICA_BOLD, + DocumentTextStyle keyStyle = TextStyles.of(FontName.HELVETICA, theme.typography().sizeBody(), DocumentTextDecoration.BOLD, NAME_COLOR); LabelValueRenderer.render(section, row.label(), row.body(), @@ -300,14 +300,14 @@ private String displayTitle(String title) { } private DocumentTextStyle sectionTitleStyle() { - return TextStyles.of(FontName.HELVETICA_BOLD, + return TextStyles.of(FontName.HELVETICA, theme.typography().sizeBanner(), DocumentTextDecoration.BOLD, theme.palette().rule()); } private Masthead.Style mastheadStyle() { - DocumentTextStyle nameStyle = TextStyles.of(FontName.HELVETICA_BOLD, + DocumentTextStyle nameStyle = TextStyles.of(FontName.HELVETICA, theme.typography().sizeHeadline(), DocumentTextDecoration.BOLD, NAME_COLOR); DocumentTextStyle titleStyle = TextStyles.of(FontName.HELVETICA, diff --git a/templates/src/main/java/com/demcha/compose/document/templates/cv/presets/ModernProfessional.java b/templates/src/main/java/com/demcha/compose/document/templates/cv/presets/ModernProfessional.java index 67a59336..b1ab62a9 100644 --- a/templates/src/main/java/com/demcha/compose/document/templates/cv/presets/ModernProfessional.java +++ b/templates/src/main/java/com/demcha/compose/document/templates/cv/presets/ModernProfessional.java @@ -131,7 +131,7 @@ public void compose(DocumentSession document, CvDocument doc) { // unique to this preset (no other preset uses slate-blue // for the name or royal-blue for links). DocumentTextStyle nameStyle = DocumentTextStyle.builder() - .fontName(FontName.HELVETICA_BOLD) + .fontName(FontName.HELVETICA) .size(theme.typography().sizeHeadline()) .decoration(DocumentTextDecoration.BOLD) .color(NAME_COLOR) diff --git a/web/showcase/pdf/features/charts/chart-showcase.pdf b/web/showcase/pdf/features/charts/chart-showcase.pdf index 46ff2e91..0fde69f3 100644 Binary files a/web/showcase/pdf/features/charts/chart-showcase.pdf and b/web/showcase/pdf/features/charts/chart-showcase.pdf differ diff --git a/web/showcase/pdf/flagships/default/engine-deck.pdf b/web/showcase/pdf/flagships/default/engine-deck.pdf index 6477ea93..ff6dca0f 100644 Binary files a/web/showcase/pdf/flagships/default/engine-deck.pdf and b/web/showcase/pdf/flagships/default/engine-deck.pdf differ diff --git a/web/showcase/pdf/flagships/default/feature-catalog.pdf b/web/showcase/pdf/flagships/default/feature-catalog.pdf index 4ce2c16e..ea60f333 100644 Binary files a/web/showcase/pdf/flagships/default/feature-catalog.pdf and b/web/showcase/pdf/flagships/default/feature-catalog.pdf differ diff --git a/web/showcase/pptx/flagships/default/engine-deck.pptx b/web/showcase/pptx/flagships/default/engine-deck.pptx index 171e074f..05baefb2 100644 Binary files a/web/showcase/pptx/flagships/default/engine-deck.pptx and b/web/showcase/pptx/flagships/default/engine-deck.pptx differ