Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Maintenance 2024 #172

Draft
wants to merge 161 commits into
base: main
Choose a base branch
from
Draft

Maintenance 2024 #172

wants to merge 161 commits into from

Conversation

samizdatco
Copy link
Owner

@samizdatco samizdatco commented Oct 24, 2024

New Features

Website

  • Documentation is now hosted at skia-canvas.org. Go there for a more readable version of all the details that used to be wedged into the README file.

Imagery

  • Added initial SVG rendering support. Images can now load SVG files and can be drawn in a resolution-independent manner via drawImage() (thanks to @mpaperno Support SVG image rendering #180). Note that Images loaded from SVG files that don't have a width and height set on their root <svg> element have some quirks as of this release:
    • The Image object's width and height will both (misleadingly) report to be 150.
    • When passed to drawImage() without size arguments, the SVG will be scaled to a size that fits within the Canvas's current bounds (using an approach akin to CSS's object-fit: contain).
    • When using the 9-argument version of drawImage(), the ‘crop’ arguments (sx, sy, sWidth, & sHeight) will correspond to this scaled-to-fit size, not the Image's reported width & height.
  • WEBP support
  • Raw pixel data support
    • The toBuffer() and saveAs() methods now support "raw" as a format name and/or file extension, causing them to return non-encoded pixel data (by default in an "rgba" layout like a standard ImageData buffer)
    • Both functions now take an optional colorType argument to specify alternative pixel data layouts (e.g., "rgb" or "bgra")
  • ImageData enhancements
    • The drawImage() and createPattern() methods have been extended to accept ImageData objects as arguments. Previously only putImageData() could be used for rendering, but this method ignores the context's current transform, filters, opacity, etc.
    • When creating an ImageData via the getImageData() & createImageData() methods or new ImageData() constructor, the optional settings arg now allows you to select the colorType for the buffer's pixels.

Typography

  • FontLibrary.use() now supports dynamically loaded WOFF & WOFF2 fonts
  • The outlineText() method now takes an optional width argument and supports all the context's typographic settings (e.g., .font, .fontVariant, .textWrap, .textTracking, etc.)
  • Fonts with condensed/expanded widths can now be selected with the .fontStretch property. Note that stretch values included in the .font string will overwrite the current .fontStretch setting (or will reset it to normal if omitted).
  • Generic font family names are now mapped to fonts installed on the system. The serif, sans-serif, monospace, and system-ui families are currently supported.
  • Underlines, overlines, and strike-throughs can now be set via the Context's .textDecoration property.
  • Text spacing can now be fine-tuned using the .letterSpacing and .wordSpacing properties.

GUI

Rendering

  • The Canvas object has a new engine property which describes whether the CPU or GPU is being used, which graphics device was selected, and what (if any) error prevented it from being initialized.
  • The .transform and .setTransform methods on Context, Path2D, and CanvasPattern objects can now take their arguments in additional formats. They can now be passed a DOMMatrix object or a string with a list of transformation operations compatible with the CSS transform property. The DOMMatrix constructor also supports these strings as well as plain, matrix-like objects with numeric attributes named a, b, c, d, e, & f (contributed by @mpaperno Allow .transform() to take DOMMatrix or CSS transform strings as arguments #178).
  • The number of background threads used for asynchronous exports can now be controlled with the SKIA_CANVAS_THREADS environment variable

Breaking Changes

  • An upgrade to Neon with N-API v8 raised the minimum required Node version to 12.22+, 14.17+, or 16+.
  • Images now load asynchronously in cases where the src property has been set to a local path. As a result, it's now necessary to await img.decode() or set up an .on("load", …) handler before drawing it—even when the src is non-remote.
  • The KeyboardEvent object returned by the keyup/keydown and input event listeners now has fields and values consistent with browser behavior. In particular, code is now a name (e.g., ShiftLeft or KeyS) rather than a numeric scancode, key is a straightforward label for the key (e.g., Shift or s) and the new location field provides a numeric description of which variant of a key was pressed.
  • The deprecated .async property has been removed. See the v0.9.28 release notes for details.
  • The non-standard .textTracking property has been removed in favor of the new .letterSpacing property

Bugfixes

Misc. Improvements

  • Upgraded Skia to milestone 129
  • Added TypeScript definitions for the Window object’s event types (contributed by @saantonandre EventEmitter intellisense/type safety #163) and the roundRect method (contributed by @sandy85625 & @santilema)
  • Performance improvements to FontLibrary, speeding up operations like listing families and adding new typefaces.
  • Updated winit and replaced the end-of-life’d skulpin-based Vulkan renderer with a new implementation using Vulkano for window-drawing on Windows and Linux.

    It’s a fairly direct adaptation of Vulkano sample code for device setup with skia-specific rendering routines inspired by @pragmatrix’s renderer for emergent. All of which is to say, if you understand this better than I do I'd love some suggestions for improving the rendering setup.

  • The GPU is now initialized only when it is needed, not at startup. As a result, setting that Canvas's .gpu property to false immediately after creation will prevent any GPU-related resource acquisition from occurring (though rendering speed will be predictably slower).
  • The sample-count used by the GPU for multiscale antialiasing can now be configured through the optional msaa export argument. If omitted, defaults to 4x MSAA.
  • Added support for non-default imports (e.g., import {Image} from "skia-canvs") when used as an ES Module.
  • The getImageData() method now makes use of the GPU (if enabled) and caches data between calls, greatly improving performance for sequential queries

- use vendored version of skulpin
- upgrade ash to match version vulkano is using
- the error message/device info is accessible through the status() accessor
- ported to use the deprecated `run_on_demand` event loop
- should refactor to use `run_app_on_demand`
- in order to let the App make callback connections to the js runtime, the `roundtrip` function is passed in as a closure after capturing the `cx` from the initial launch() call
- removed a bunch of UserEvent wrapping; now just passing CanvasEvents to the windows as-is
- moved `App` & `Cadence` into their own module and separated `Window` and `WIndowManager`
- use the instance passed as args to lifecycle methods
- remove the unsafe Send impl from VulkanRenderer (which gets created on the main thread before being sent to the window thread)
samizdatco and others added 30 commits November 11, 2024 21:22
- a thread wakes up every 2 seconds and drops any contexts that haven't rendered in that time
- only performs the supported() check once and discards the test context when done
it became unnecessary for Metal setup at some point
- switch `get_surface` to `with_surface` closure to include cleanup
- also drop the old `get_surface`→`surface` RenderingEngine→Engine methods
- the supported sampling rates are reported in the `canvas.engine.samples` array
- both engines' `with_surface` handlers now take a custom msaa arg to override the default (4x)
- parsing and passing them individually was getting ungainly
- now runs once per second rather than after every surface
- omitting the option defaults to 4x MSAA if available
- setting it to a positive power of 2 (that's supported by the GPU) will choose 2x, 4x, 8x, etc. MSAA when rasterizing
- setting it to 0 or `false` will use shader-based antialiasing techniques (typically with higher quality results than when MSAA is enabled but can get *very* slow for more complex images)
- note that the gpu drivers tend to list "1x" as a valid option but it's unclear how/whether that differs from `0` in practice
- otherwise it will mean the (rayon) thread count reported in canvas.engine is off by one
- e.g., `brightness(2)` and `brightness(200%)` are now equivalent
* Added functionality to load images from decoded pixel buffers

* sync up with maintenance-2024 changes

* add settings arg to ImageData constructor

- colorType can be 'rgba' (the default), 'rgb', 'bgra', or 'argb'
- colorSpace can currently only be 'srgb' but 'display-p3' support is on the todo list

* add `loadImageData` helper

- uses a common implementation with the Image.src loader (thus the weird callback design of `fetchData` to fulfill Image's expectations of sync loads for local files)

* Added functionality to export canvas as raw pixel data, skipping encoding step. Adds support for "raw" format to existing export options and adds specific `Canvas#toRaw()` method.

* sync up with maintenance-2024

* support `colorType` arg in get/put/createImageData methods

- dropped the alias from 'argb' to the odd-seeming 16 bit color type (is it actually commonly used though?)

* support `colorType` arg in saveAs/toBuffer

* allow ImageData to be passed to drawImage

* test ImageData initialization

* consolidate ImageData typedefs

* test the `this` mapping in Image.onload

* only perform null-check once

* allow ImageData to be passed to `createPattern`

* add `.bytesPerPixel` property to ImageData

* note that BMP is not being used as an encoding

- it's just so we can use the common parts of the encoded-image path

* make Image into a proper EventEmitter

- the `.onload` and `.onerror` properties are still supported, but `on`, `once`, and `off` now work too
- moved the fetchData routine back into Image as a static method so it can still be used by loadImageData

* use async i/o for loading local image files

- previously img.src='./local/file/path' would synchronously load the data and the image would immediately be ready for use
- now, even local files should wait for img.decode() or img.on('load') to resolve first

* set `complete` even if load failed

- the real way to judge success is complete==true *and* non-zero width/height

* genericize return type for with_surface

- it now just uses the closure's Result type

* use cpu renderer for filter test

- since the output differs, use the version that will be stable across CI runs

* nudge the test point to avoid cpu/gpu antialiasing differences

* use gpu for `getImageData` and cache bitmap between calls

- significantly faster for single `get`s and absurdly fast for subsequent gets of the same canvas content (since it's using a cached bitmap that's invalidated on the next drawing command)
- required adding a reference to the ctx's Canvas to the call so it can access the current gpu::RenderingEngine mode (and initialize it if needed)

* drop unnecessary imports & muts

* update `with_surface` signatures for Vulkan and dummy engine

* fix ImageData constructor's arg parsing

* update changelog

* include `colorType` arg when passing export opts

* allow ImageData to be initialized from Image

* update Image & ImageData docs

* update changelog

* update class ToC

* add `colorType` layout test

---------

Co-authored-by: ggolda <[email protected]>
Co-authored-by: Christian Swinehart <[email protected]>
Co-authored-by: Max Paperno <[email protected]>
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.

3 participants