Skip to content

Css improvements - #173

Open
alin-github wants to merge 26 commits into
weisJ:masterfrom
alin-github:css-improvements
Open

Css improvements#173
alin-github wants to merge 26 commits into
weisJ:masterfrom
alin-github:css-improvements

Conversation

@alin-github

Copy link
Copy Markdown

It's based top of custom-font-support branch right now (the other PR).

Rushed a bit at the end (some bug fix commits that allowed me to enable more ReSvg test folders were mostly done with AI but I did review/change some things).

I'm on vacation until 25.08 but in general I'm very ready to do major changes/refactoring including coding style if you think they are needed.

@alin-github alin-github mentioned this pull request Aug 6, 2026
@weisJ

weisJ commented Aug 7, 2026

Copy link
Copy Markdown
Owner

Thank you so much for the initiative. I will try to do a thorough review this weekend.

@alin-github

Copy link
Copy Markdown
Author

Hmm, textRefTest failed likely because of the sans-serif font used on my system was different from the sans-serif fonts in the 3 CI systems... (JSVG now has Kerning, while the reference Batik rendering doesn't)

@weisJ

weisJ commented Aug 7, 2026

Copy link
Copy Markdown
Owner

Maybe we can make kerning a rendering hint and disable it for those tests. This way at least we test that letter placement doesn't break completely.

@alin-github

Copy link
Copy Markdown
Author

Maybe we can make kerning a rendering hint and disable it for those tests. This way at least we test that letter placement doesn't break completely.

The problem with making kerning a rendering hint is that kerning is used in places where the Output context is not available: GlyphRenderer.layoutGlyphRun and TextMetrics.computeTextMetrics. So SVGDocument.prepareRenderContext would need to put it into the RenderContext as a separate field or so. What do you think?

@weisJ

weisJ commented Aug 7, 2026

Copy link
Copy Markdown
Owner

We could store a boolean indicating that kerning is enabled in the GlyphCursor. The Output is available when constructing that cursor, so we don't have to duplicate the rendering hints in the context.

Comment on lines +57 to +60
this.sequences = Collections.unmodifiableList(new ArrayList<>(sequences));
this.combinators = Collections.unmodifiableList(new ArrayList<>(combinators));
this.specificity = computeSpecificity();
}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of using Collections.unmodifiableList I usually just use List<? extends Type as the return type functions. Even though this still allows someone to modify the collection, it is only possible through unsafe casting. If we document that the constructor takes ownership of the list, we can avoid the copy of the list in here.

This also applies to the other instances of the Collections.unmodifiableList(new ArraList<>(list)) pattern.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done


/** Preceding element sibling, or null if first child */
public @Nullable ParsedElement previousSibling() {
ParsedElement parent = parent();

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This hides the member variable with the same name. Please also check for other instances of this.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed; found only one more case

Comment on lines +204 to +207
ParsedElement copyAsUseInstance(@NotNull NodeSupplier nodeSupplier) {
return deepCopy(nodeSupplier, null, 1, 1);
}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The most common case of elements referenced by <use> are ones which have a <defs> element as their parent. I suppose in this case one could simply "detach" the node, as it is never rendered directly (Please correct me if this is an incorrect assumption). If so, we should optimise this codepath.

Comment on lines +95 to +99
@Override
public @NotNull CssHints cssHints() {
return cssHints;
}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mark these as experimental (these = css hints related functions and the class itself). In the long run the CssHints need to be moved into the PlatformSupport (or similar).

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done. But kept CssParser.parseStyleSheet/parseStyleAttribute as-is, not sure what's best there.

Comment on lines +63 to +64
private final static class ParsedElementAnnotated {
public final @NotNull ParsedElement element;

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Modifier order should be static final. Also applies in other locations.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed including the other instances

Comment on lines +71 to +73
// Only a declared viewBox may introduce a scaling transform. Synthesizing one from the
// element's own size would wrongly scale content when the use-site size differs.
if (info != null) node.renderWithSize(size, node.declaredViewBox(), info.context(), info.output());

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a test case for this? (Maybe you did, but I overlooked it)

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added in UseTest.nestedSvgWithoutViewBoxIsNotScaled

Comment on lines +55 to +58
void toleratesReferenceCycle() {
// Cyclic references are severed and render nothing instead of failing the document.
Assertions.assertDoesNotThrow(() -> tryLoad("parser/useCycle.svg"));
Assertions.assertDoesNotThrow(() -> tryLoad("parser/useCycleSelfReference.svg"));

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we check that these elements are not painted e.g. by comparing to an empty svg?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment on lines -89 to -90
Optional<Float> contextFontSize();

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's deprecate this method instead of removing it.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done; documented that the method is not used

Comment on lines +128 to +130
if (previousCodepoint != null && cursor.isCurrentGlyphAutoLayout()) {
cursor.applyKerning(font.kerningAdjustment(previousCodepoint, codepoint));
}

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As mentioned in another comment. Let's create a rendering hint for kerning and store it in the glyph cursor (as the Output is available when the cursor is created). Then check here for cursor.isKerningEnabled().

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment on lines +56 to +58
// Batik doesn't apply kerning; the tolerance covers the resulting shift (measured 0.45% and 1.22%).
assertEquals(SUCCESS, compareImages("text/text1.svg", 0.7));
assertEquals(SUCCESS, compareImages("text/text2.svg", 1.8));

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Render these without kerning enabled.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

…on Apple systems.

Background: font-family:.some-font-name is ignored in browsers since it's invalid. Previously JSVG supported that, now it doesn't any more due to compliant CSS parsing.
@alin-github

Copy link
Copy Markdown
Author

We could store a boolean indicating that kerning is enabled in the GlyphCursor. The Output is available when constructing that cursor, so we don't have to duplicate the rendering hints in the context.

done

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.

2 participants