Repository navigation
Conversation
…DI (#412) Second part of step 6 of #412. Text and FontCache no longer use GDI or GDI+: the glyph outlines, advance widths, kerning, metrics and the list of font families come from the static, settable FontProvider.Current, not from FrameImpl.MainFrame, so texts work without a frame and on every platform. - FontProvider and FontFace (public, new) describe what the kernel needs. A face returns its glyphs as Bezier path data in the layout of GraphicsPath.AddString, which the kernel turns into geometry with GlyphShapeBuilder as before, so no provider can flatten the outlines. - ManagedFontProvider (public, new) is the default on all platforms, as decided for #412. It indexes the TrueType fonts of the system font directories by reading only their header tables, and loads a font file when a face is used. Files and font data can be added. - FontCache no longer creates a GDI device context in its constructor or deletes it in a finalizer, which ended the process outside Windows. - Without any font, painting and the extent of a text leave it out; GetOutline and similar explicit requests throw an InvalidOperationException that says what to do. - ShowPropertyFont and DimensionStyle list the families of the provider. - CADability.Forms.GdiFontProvider (public, new) is the old GDI implementation for applications that want it. TrueTypeFont reads the underline and strikeout metrics, adds both as rectangles like GDI+ does, and can read only the header tables of a font file. Tests: both test projects register Liberation Sans in an assembly initializer, so texts have a font even on a machine without fonts. The text tests that were inconclusive on Linux ("text needs GDI") now run there; new FontProviderTests cover text without a frame, the default face for unknown fonts, the exception without fonts, underline and strikeout, style fallback, header-only reading and the finalizer. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YXvDW91oXpy7RquGHNxgR5
Resolves the conflict with #497 in FontCache: the managed font calls of this branch now run under the same lock (this) that #497 introduced, and Clear disposes the glyph display lists and empties all caches, including the faces. FontProvider.Current, which calls Clear, documents that the display lists of the views need to be rebuilt when it is set after texts were painted. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YXvDW91oXpy7RquGHNxgR5
|
Merged
The stacked PRs #470, #471, #472 and #479 contain the merge as well; none of them had further conflicts. Generated by Claude Code |
ClearingTheFontCacheDisposesTheGlyphLists reflected on the 'kerning' field of the GDI FontCache, which this branch replaces by the 'faces' of FontProvider.Current, so it failed with a NullReferenceException on Windows. It now checks that Clear empties the faces, and it runs on every platform, because the font cache no longer needs GDI. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YXvDW91oXpy7RquGHNxgR5
|
One more adaptation after the merge with #497.
The test now checks that
Generated by Claude Code |
…nto feature/font-service
|
The Linux job on This failure is not caused by this PR. The test comes from #498, which is now on I am re-running the failed job once. If it fails again, the race in the parallel STEP import of #498 needs a fix on Generated by Claude Code |
Step 6 of #412, part 2 of 3.
Stacked on #466. The base branch is
feature/managed-font-provider, so the diff shows only this part. Once #466 is merged, change the base tomaster. Both are also merged into the integration branchintegration/issue-412(#467).What changes
TextandFontCacheno longer use GDI or GDI+. Outlines, advance widths, kerning, metrics and the list of font families all come from the static, settableFontProvider.Current, and no longer fromFrameImpl.MainFrame. Texts therefore work without a frame and on every platform.New public API (minor version)
FontProviderCurrent(static, settable),GetFamilyNames(),GetFace(family, bold, italic),GetDefaultFace(bold, italic)FontFaceGetAdvanceWidth,GetKerning(em units),GetGlyphPathManagedFontProviderGdiFontProviderFontFace.GetGlyphPathreturns Bezier path data in the layout ofGraphicsPath.AddString. The kernel builds the geometry from it with the existingGlyphShapeBuilder, as before. A provider therefore cannot flatten the outlines, and every provider produces the same exact curves (problem 2 in #412).The new API uses
bool bold, bool italicand notSystem.Drawing.FontStyle, so step 8 does not have to break it again.ManagedFontProvider(default on all platforms, as decided for #412)head,hhea,maxp,OS/2,post,name), so hundreds of fonts are indexed quickly. A font file is loaded completely only when one of its faces is used.AddFontFileandAddFontDataadd more fonts, e.g. embedded resources.GetDefaultFace: Microsoft Sans Serif, Arial, Liberation Sans, DejaVu Sans, Helvetica, Noto Sans, FreeSans, otherwise the first family.Problem 1 of #412 is fixed
FontCache: it no longer creates a device context in its constructor or deletes one in its finalizer. Outside Windows the constructor threw and the finalizer then ended the process.GetOutline,GetShapesandGetCenterlinethrow anInvalidOperationExceptionthat says what to do.Other changes
ShowPropertyFontandDimensionStylelist the families of the provider instead ofSystem.Drawing.FontFamily.Families.TrueTypeFont:post,OS/2) and adds both as rectangles over the advance width, as GDI+ does;ReadHeaders).Behaviour changes for the release notes
On Windows, texts now use the managed reader by default. The glyphs come from the same font files and should match GDI within float precision. Part 3 adds the Windows test that compares them.
What the managed reader leaves out:
.otffiles) cannot be read. A text in such a font falls back to the default face. Read the CFF outlines of OpenType fonts in the managed font reader #470 removes this limitation.glyfwithoutgvar) and knows only the family of the default instance, e.g. "Bahnschrift". A text in such a named instance falls back to the default face. Variable OpenType fonts withCFF2outlines are left out completely. The Windows CI run of the integration branch showed this: the glyph tests for these instances were skipped there.Applications that need any of these can set
FontProvider.Current = new GdiFontProvider(). Support for variable fonts (named instances,gvarandCFF2) is a possible follow-up.CADability.Gdi(public) is no longer used by the kernel for fonts. It stays until 2.0.Tests
tests/CADability.Tests/Files/Fonts, OFL) in an[AssemblyInitialize], in addition to the system fonts. Texts therefore have a font even on a build server without any fonts installed.ProjectTestand 5 inImportTests. The guards are removed.FontProviderTests:FontCacheGlyphTests: no longer limited to Windows. They run for every installed font, plus a newDataRowfor Liberation Sans. The survey over all fonts (CADABILITY_FONT_SURVEY=1) found 0 fonts with glyphs without triangles among the 47 TrueType fonts in the Linux container.Local run on Linux:
CADability.Tests: 633 passed, 12 skipped (Windows fonts that are not installed), 0 failed.CADability.ImportTests: 88 passed, 0 skipped (5 before), 0 failed./usr/share/fontshidden, which simulates a runner without fonts.CADability.Formsbuild.On Windows (the Windows CI of #469, run on the integration branch): the reference-bitmap tests in
ProjectTest, which now render text from the managed reader, pass. So do the glyph tests for Arial, Calibri, Segoe UI and Bahnschrift.No change to the csproj version.
🤖 Generated with Claude Code
https://claude.ai/code/session_01YXvDW91oXpy7RquGHNxgR5