Back to Skiasharp

Manual additions for 4.148.0

documentation/docfx/releases/_sources/4.148.0.notes.md

4.151.06.9 KB
Original Source

Manual additions for 4.148.0

Maintainer-authored. Freeform Markdown — the Polish AI reads this and weaves it into the page (mainly the ## Breaking Changes section), summarizing/migrating rather than pasting it verbatim. It is never machine-overwritten and survives regeneration and re-polish.

Scope: 4.148.0 is the first stable v4 line (rolls up the 4.147.x previews), so it lands the bulk of the v4 breaking changes from the Skia m132/m147 upgrade. The items below are the ones the API signature diff cannot show — behavioral changes and interop-struct changes — and so must be documented here by hand. Signature breaks that are in the diff (the GRVkImageInfo/GrVkYcbcrConversionInfo retype + loss of value-equality, and the SKNativeObject setter) are summarized from SkiaSharp/SkiaSharp.breaking.md.

Behavioral breaking changes (same signature, different runtime behavior)

These compile unchanged but behave differently at runtime, so they never appear in a signature diff. Test text layout and stream seeking after upgrading from 3.x.

new SKFont() now has an empty typeface (#3735)

Upstream m132 removed the lazy "resolve default at draw time" pattern; the SkFont constructor now eagerly stores an empty typeface when given none.

  • Before (3.x): new SKFont().Typeface was null and resolved to the platform default at draw time — new SKFont().MeasureText("Hello") returned a real width.

  • After (4.x): the typeface is SKTypeface.Empty (0 glyphs), so MeasureText("Hello") returns 0 and nothing is drawn. Setting font.Typeface = null likewise yields SKTypeface.Empty.

  • Migration: construct with an explicit typeface, and detect "unset" with IsEmpty:

    csharp
    // Before (3.x) — worked via lazy default
    var font = new SKFont();
    var width = font.MeasureText("Hello"); // > 0
    
    // After (4.x) — pass the typeface you want
    var font = new SKFont(SKTypeface.Default);
    var width = font.MeasureText("Hello"); // > 0
    
    // Detecting "no typeface set"
    bool unset = font.Typeface.IsEmpty; // was: font.Typeface == null
    

new SKPaint().Typeface returns Default instead of null (#3736)

The underlying SkCompatPaint moved from SkFont() (null → lazy default) to SkFont(MakeEmpty()). SkiaSharp mitigates this so text still works out of the box, but the null semantics changed.

  • Before (3.x): new SKPaint().Typeface was null (lazy default).
  • After (4.x): it is SKTypeface.Default (non-null). Text measurement and drawing still work — SkiaSharp seeds a default font — and SKPaint.Reset() also restores that default.
  • Only observable break: code that used paint.Typeface == null to detect "no typeface set" no longer fires. Use paint.Typeface.IsEmpty, or drop the check (a usable default is always present).

SKTypeface.FromFamilyName("missing") returns Default, not null, on Android (#3737)

The old per-platform legacyMakeTypeface() path (which returned null on Android for an unknown family) was replaced by SKFontManager.Default.MatchFamily(name, style) ?? Default, making every platform consistent.

  • Before (3.x): Android returned null for a missing family; other platforms returned a fallback face.

  • After (4.x): all platforms return SKTypeface.DefaultFromFamilyName is now never null.

  • Migration: for a strict "was the font actually found?" check, use the font manager, which still returns null on no match:

    csharp
    // Strict null semantics (all platforms)
    var tf = SKFontManager.Default.MatchFamily("MissingFont");
    if (tf is null) { /* font not found — apply your own fallback */ }
    

SKTypeface.Default now resolves through the font manager (#3738)

SkTypeface::RefDefault()/MakeDefault() were removed upstream in m132. Default resolution moved to matchFamilyStyle(null, Normal) with an empty-typeface fallback.

  • Before (3.x): implemented via sk_typeface_ref_default().
  • After (4.x): implemented via the font manager; SKTypeface.Default is now guaranteed non-null on every platform, and Android API 36+ (where the manager could return null — the original #3693) falls back to SKTypeface.Empty instead of crashing.
  • Migration: none needed. Behavior is unchanged on macOS/Windows/Linux; Android API 36+ now works instead of failing.

SKStream.Move(long) now throws and is obsolete (#3740)

The native sk_stream_move offset is a 32-bit int. The Move(long) overload always did an unchecked (int) cast, silently truncating large offsets — a latent data-corruption bug.

  • Before (3.x): stream.Move((long)int.MaxValue + 1) silently truncated (wrapping negative); no warning.
  • After (4.x): the cast is checked((int)offset), so out-of-range offsets throw OverflowException, and the overload is [Obsolete] (compiler warning CS0618).
  • Migration: call Move(int) with an in-range offset (validate/clamp large values yourself first). Most callers already pass int-range values and only need to change the call to silence the obsolete warning.

Interop / native-struct breaking changes (not in any API diff)

GRVkBackendContextNative is an interop struct outside the public-API surface the diff tool compares, so its field removals appear in no *.breaking.md — they must be documented here.

Vulkan GRVkBackendContextNative — five fields removed (#3741)

Upstream simplified GrVkBackendContext; the redundant legacy fields were dropped.

  • Removed: fMinAPIVersion, fInstanceVersion, fExtensions, fFeatures, fOwnsInstanceAndDevice.

  • Migration: delete those assignments. Use the typed fVkExtensions in place of fExtensions, and fDeviceFeatures / fDeviceFeatures2 in place of fFeatures. Skia no longer manages instance/device ownership through the backend context, so fOwnsInstanceAndDevice has no replacement.

    csharp
    var ctx = new GRVkBackendContextNative
    {
        fInstance = instance,
        fPhysicalDevice = physicalDevice,
        fDevice = device,
        fQueue = queue,
        fGraphicsQueueIndex = queueIndex,
        fMaxAPIVersion = maxVersion,
        fVkExtensions = extensions,      // instead of fExtensions
        fDeviceFeatures = features,      // instead of fFeatures
        fGetProc = getProc,
        // fMinAPIVersion / fInstanceVersion / fExtensions /
        // fFeatures / fOwnsInstanceAndDevice — removed, delete these
    };
    

Vulkan GrVkYcbcrConversionInfo layout change (#3741)

A new Components field (and a new GRVkYcbcrComponents struct) was added to the Ycbcr conversion info, changing its layout. Code that manually constructs the struct or relies on its layout must account for the new field. (The related GRVkImageInfo.YcbcrConversionInfo retype from GrVkYcbcrConversionInfo to GRVkYcbcrConversionInfo, and the loss of value-equality on that type, are captured by the signature diff — the polish step summarizes those from SkiaSharp.breaking.md.)