Skija Documentation

repository·master·Indexed 20 days ago

https://github.com/humbleui/skija

Hand-crafted Java bindings for the Skia 2D graphics library, providing GPU-accelerated graphics capabilities for Java developers. Supports Bitmap, OpenGL, Direct3D, Metal, and Vulkan backends across Windows, Linux, macOS, and Android. The library is currently in Public Alpha and focuses on providing a natural, idiomatic Java API with automatic memory management.

Tokens
5.7K
Snippets
24
Records
34
Agent score
71%

What's inside Skija

  1. Skija API Coverage and Status

    master

    Skija is currently in Public Alpha. Because the underlying Skia library changes frequently, the Skija API may change without notice.

    Supported Backends:

    • Bitmap
    • OpenGL
    • Direct3D
    • Metal
    • Vulkan

    Supported Platforms:

    • Windows (x64)
    • Linux (x64, arm64)
    • macOS (x64, arm64)
    • Android (x64, arm64)
  2. Understand Skija API design principles

    master

    Skija aims to stay as close to the original Skia C++ API as possible, with a few specific adjustments to ensure idiomatic Java usage and avoid conflicts:

    • Naming Fixes: Minor inconsistencies in Skia naming are corrected.
    • Conflict Resolution: Methods that clash with standard Java/Managed methods are renamed. For example, SkPath#close is renamed to Path#closePath to avoid clashing with Managed#close.
    • Module Mapping: Skia modules are mapped to io.github.humbleui.skija.* subpackages.
    • Method Return Types: Unlike Skia (which often returns void), Skija setters and updaters return this to allow for method chaining.
  3. Accessing Skija fields and getters

    master

    Due to Java visibility limitations, many Skija fields are declared public and prefixed with an underscore (e.g., _r, _g).

    Rule: Treat any field starting with _ as private. Do not access them directly as it breaches encapsulation. Instead, use the provided getter methods (e.g., getR()).

    var color = new Color4f(1, 1, 1);
    
    // BAD
    float r = color._r;
    
    // GOOD
    float r = color.getR();
  4. Use Skija Data Classes

    master

    Data classes in Skija (like LineMetrics) use a specific pattern to balance performance and Java idiomaticity:

    • Fields: Public final fields are prefixed with _ (e.g., public final long _startIndex).
    • Accessors: Use standard JavaBeans getters/setters (get..., is..., set..., with...). Setters return this.
    • Flags: Bit flags are not exposed via direct getters. Instead, individual boolean check methods are provided (e.g., isBold()).
    • Implementation: Getters may hide the fact that a field is computed or requires a native call.
    @Data
    public class LineMetrics {
        public final long    _startIndex;
        public final long    _endIndex;
        // ... other fields
        @Getter(AccessLevel.NONE)
        public final int     _flags;
    
        public static final int _FLAG_IS_BOLD   = 0b0001;
        public static final int _FLAG_IS_ITALIC = 0b0010;
    
        public boolean isBold() { return (_flags | _FLAG_IS_BOLD) != 0; }
        public boolean isItalic() { return (_flags | _FLAG_IS_ITALIC) != 0; }
    }
  5. Identify Skija naming conventions

    master

    Skija follows specific naming patterns to distinguish between different types of members:

    • Native Methods: Prefixed with _n (e.g., _nDrawRRect).
    • Private Fields: Prefixed with _ (e.g., _startIndex).
    • Getters/Setters: Use get.../is... for getters and set.../with... for setters.
    • Static Constructors: Use make... for static named constructors.
    • Bit Flags: Use _FLAG_<TYPE>_<NAME> (e.g., _FLAG_IS_BOLD).
    • Bit Masks: Suffix with ...Mask.
    • Enums: Use UPPER_CASE for values.
    • Common Terminology:
      • count is used instead of size or length.
      • ...Style is used instead of ...Config or ...Options.
      • ...Mode is used instead of ...Type or ...Kind.
      • serializeToData/makeFromData are used for data conversion.
  6. Draw text with Typeface and Font

    master

    Text rendering in Skija involves two distinct concepts:

    1. Typeface: Represents a font file or a font family. Creating a Typeface is expensive. You can load one from a file or match a family style via the OS using FontMgr.
    2. Font: Contains specific drawing settings, most importantly the font size. A Font is built from a Typeface.

    Best Practice: For performance, cache Typeface and Font objects instead of recreating them every frame.

    try (Typeface face = FontMgr.getDefault().matchFamilyStyle("Menlo", FontStyle.NORMAL);
         Font font = new Font(face, 13);
         Paint fill = new Paint().setColor(0xFF000000)) 
    {
        canvas.drawString("Hello, world", 0, 0, font, fill);
    }
  7. Manage Skija native resources

    master

    Most Skija classes (extending RefCnt or Managed) are backed by native C++ pointers.

    Automatic Management: Skija automatically frees C++ structures when the corresponding Java objects are collected by the Garbage Collector (GC). This makes Skija safe to use by default.

    Manual Management: All Managed descendants implement AutoCloseable. To free memory more aggressively (e.g., for short-lived objects), use a try-with-resources block. This is not mandatory but can help reduce memory pressure.

    Warning: Once a resource is closed via AutoCloseable, it can no longer be used.

    // Automatic management (safe, but relies on GC)
    void drawCircle(Canvas c) {
        Paint p = new Paint();
        c.drawCircle(0, 0, 10, p);
    }
    
    // Manual management (immediate cleanup)
    void drawCircle(Canvas c) {
        try (Paint p = new Paint()) {
            c.drawCircle(0, 0, 10, p);
        } // p is freed here
    }
  8. Understand Skija visibility and internal APIs

    master

    Skija uses a permissive visibility model to ensure clients have access to necessary functionality, even if it's not part of the intended public surface:

    • Public by Default: Most fields and methods are public to prevent blocking client needs.
    • Internal Members: Members not intended for general use are marked in two ways:
      1. Prefixed with an underscore _ (e.g., _startIndex).
      2. Annotated with @ApiStatus.Internal.
    • No Guarantees: Fields or methods starting with _ are considered effectively private. Skija provides no stability guarantees for these members.
  9. How Skija handles Java-native integration

    master

    Unlike automatically generated bindings, Skija is hand-crafted to provide a natural Java API. Key characteristics include:

    • Automatic Memory Management: No pointer abstractions are leaked to the user.
    • Java Conventions: Uses standard Java classes, interfaces, inheritance, and typed enums instead of integer constants.
    • Platform Abstractions: Uses native Java types (Strings, Arrays, Streams, Files, Byte Buffers, AutoCloseable) instead of wrapped C++ equivalents.
    • Fluent APIs: Employs builder-style patterns where appropriate.
    • Lightweight Data Classes: Objects like Point, Rect, and FontMetrics are pure Java data classes and are not mirrored by native instances, reducing overhead.
  10. Install Skija dependencies

    master

    To use Skija, add the appropriate platform-specific dependency to your build system (Ant, Maven, Gradle, or Bazel). You must choose exactly ONE dependency based on your target architecture and operating system. Replace ${version} with the current Skija version.

    Available dependencies:

    • Windows x64: io.github.humbleui:skija-windows-x64:${version}
    • Linux x64: io.github.humbleui:skija-linux-x64:${version}
    • Linux arm64: io.github.humbleui:skija-linux-arm64:${version}
    • macOS x64: io.github.humbleui:skija-macos-x64:${version}
    • macOS arm64: io.github.humbleui:skija-macos-arm64:${version}
    • Android x64: io.github.humbleui:skija-android-x64:${version}
    • Android arm64: io.github.humbleui:skija-android-arm64:${version}
    io.github.humbleui:skija-windows-x64:${version}
  11. Build and run the kwinit example locally

    master

    To run the kwinit example using a locally built version of Skija, first build the project using the build.py script from the root directory, then execute the example using run.py within the example directory.

    python3 ../../script/build.py
    python3 script/run.py
  12. Explore Skija APIs via Demo Scenes

    master

    The examples/scenes directory contains demo scenes that demonstrate most of the Skia and Skija APIs. These scenes serve as a learning resource for understanding how to use the library's capabilities in practice.

    To run these demonstrations, you can use either the kwinit or lwjgl examples located in the adjacent directories.

    # Run through kwinit
    ../kwinit
    
    # Or run through lwjgl
    ../lwjgl