diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 15e1f6d..a1896de 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -8,7 +8,7 @@ env: # If the compilation fails, then the version specified here needs to be bumped up to reality. # Be sure to also update the rust-version property in the workspace Cargo.toml file, # plus all the README.md files of the affected packages. - RUST_MIN_VER: "1.70" + RUST_MIN_VER: "1.82" # List of packages that will be checked with the minimum supported Rust version. # This should be limited to packages that are intended for publishing. RUST_MIN_VER_PKGS: "-p peniko" diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b01c92..a89367c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,7 +13,7 @@ You can find its changes [documented below](#020-2024-09-19). ## [Unreleased] -This release has an [MSRV] of 1.70. +This release has an [MSRV] of 1.82. ## [0.2.0][] (2024-09-19) diff --git a/Cargo.lock b/Cargo.lock index c02a93b..c149a15 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,6 +8,15 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" +[[package]] +name = "color" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce566db61cc9ebcb00cf6f338ec87d1d030727152fd3661caad38d0113f76c11" +dependencies = [ + "libm", +] + [[package]] name = "kurbo" version = "0.11.1" @@ -23,9 +32,9 @@ dependencies = [ [[package]] name = "libm" -version = "0.2.8" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +checksum = "8355be11b20d696c8f18f6cc018c4e372165b1fa8126cef092399c9951984ffa" [[package]] name = "mint" @@ -37,6 +46,7 @@ checksum = "e53debba6bda7a793e5f99b8dacf19e626084f525f7829104ba9898f367d85ff" name = "peniko" version = "0.2.0" dependencies = [ + "color", "kurbo", "serde", "serde_bytes", diff --git a/Cargo.toml b/Cargo.toml index f5a93e9..ed191e2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,10 +8,9 @@ keywords = ["graphics", "vector", "style"] categories = ["graphics"] repository = "https://github.com/linebender/peniko" readme = "README.md" -# We support from Rust 1.70 so that CI uses the sparse protocol. # Keep in sync with RUST_MIN_VER in .github/workflows/ci.yml and with the relevant README.md files. # and with the MSRV in the `Unreleased` section of CHANGELOG.md. -rust-version = "1.70" +rust-version = "1.82" [package.metadata.docs.rs] all-features = true @@ -20,13 +19,15 @@ default-target = "x86_64-unknown-linux-gnu" targets = [] [features] -default = ["std"] -std = ["kurbo/std"] -libm = ["kurbo/libm"] +default = ["std", "legacy_color"] +std = ["color/std", "kurbo/std"] +libm = ["color/libm", "kurbo/libm"] mint = ["kurbo/mint"] serde = ["smallvec/serde", "kurbo/serde", "dep:serde_bytes", "dep:serde"] +legacy_color = [] [dependencies] +color = { version = "0.1.0", default-features = false } # NOTE: Make sure to keep this in sync with the version badge in README.md kurbo = { version = "0.11.1", default-features = false } smallvec = "1.13.2" @@ -69,8 +70,10 @@ rust.unused_macro_rules = "warn" rust.unused_qualifications = "warn" rust.variant_size_differences = "warn" -clippy.allow_attributes = "warn" -clippy.allow_attributes_without_reason = "warn" +# FIXME(color): I'm lazy about fixing this yet. +clippy.allow_attributes = "allow" +clippy.allow_attributes_without_reason = "allow" + clippy.cast_possible_truncation = "warn" clippy.collection_is_never_read = "warn" clippy.dbg_macro = "warn" diff --git a/README.md b/README.md index cc6231b..911d35d 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ contains. ## Minimum supported Rust Version (MSRV) -This version of Peniko has been verified to compile with **Rust 1.70** and later. +This version of Peniko has been verified to compile with **Rust 1.82** and later. Future versions of Peniko might increase the Rust version requirement. It will not be treated as a breaking change and as such can even happen with small patch releases. diff --git a/src/brush.rs b/src/brush.rs index 7cbb730..264db3d 100644 --- a/src/brush.rs +++ b/src/brush.rs @@ -1,24 +1,35 @@ // Copyright 2022 the Peniko Authors // SPDX-License-Identifier: Apache-2.0 OR MIT -use super::{Color, Gradient, Image}; +use super::{Gradient, Image}; +#[cfg(feature = "legacy_color")] +use crate::Color; +use color::{AlphaColor, Srgb}; /// Describes the color content of a filled or stroked shape. /// /// See also [`BrushRef`] which can be used to avoid allocations. -#[derive(Clone, PartialEq, Debug)] +// FIXME(color): `PartialEq` was removed from here for now. +#[derive(Clone, Debug)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum Brush { /// Solid color brush. - Solid(Color), + Solid(AlphaColor), /// Gradient brush. Gradient(Gradient), /// Image brush. Image(Image), } +#[cfg(feature = "legacy_color")] impl From for Brush { fn from(c: Color) -> Self { + Self::Solid(c.into()) + } +} + +impl From> for Brush { + fn from(c: AlphaColor) -> Self { Self::Solid(c) } } @@ -37,7 +48,8 @@ impl From for Brush { impl Default for Brush { fn default() -> Self { - Self::Solid(Color::default()) + // FIXME(color): Decide what to do about color and defaults + Self::Solid(color::palette::css::TRANSPARENT) } } @@ -58,7 +70,7 @@ impl Brush { self } else { match self { - Self::Solid(color) => color.multiply_alpha(alpha).into(), + Self::Solid(color) => color.mul_alpha(alpha).into(), Self::Gradient(mut gradient) => { gradient .stops @@ -77,10 +89,11 @@ impl Brush { /// This is useful for methods that would like to accept brushes by reference. Defining /// the type as `impl>` allows accepting types like `&LinearGradient` /// directly without cloning or allocating. -#[derive(Copy, Clone, PartialEq, Debug)] +// FIXME(color): `PartialEq` was removed from here for now. +#[derive(Copy, Clone, Debug)] pub enum BrushRef<'a> { /// Solid color brush. - Solid(Color), + Solid(AlphaColor), /// Gradient brush. Gradient(&'a Gradient), /// Image brush. @@ -99,14 +112,28 @@ impl BrushRef<'_> { } } +#[cfg(feature = "legacy_color")] impl From for BrushRef<'_> { fn from(color: Color) -> Self { - Self::Solid(color) + Self::Solid(color.into()) } } +#[cfg(feature = "legacy_color")] impl<'a> From<&'a Color> for BrushRef<'_> { fn from(color: &'a Color) -> Self { + Self::Solid((*color).into()) + } +} + +impl From> for BrushRef<'_> { + fn from(color: AlphaColor) -> Self { + Self::Solid(color) + } +} + +impl<'a> From<&'a AlphaColor> for BrushRef<'_> { + fn from(color: &'a AlphaColor) -> Self { Self::Solid(*color) } } diff --git a/src/color.rs b/src/color.rs index c1a1ed8..aa1a322 100644 --- a/src/color.rs +++ b/src/color.rs @@ -3,6 +3,7 @@ // Borrows code heavily from the piet (https://github.com/linebender/piet/) Color // type. +use color::{AlphaColor, Srgb}; #[cfg(all(not(feature = "std"), feature = "libm"))] #[allow(unused_imports)] use kurbo::common::FloatFuncs as _; @@ -467,6 +468,12 @@ impl Color { pub const YELLOW_GREEN: Color = Color::rgba8(154, 205, 50, 255); } +impl From for AlphaColor { + fn from(c: Color) -> Self { + Self::from_rgba8(c.r, c.g, c.b, c.a) + } +} + impl From<[u8; 3]> for Color { fn from(rgb: [u8; 3]) -> Self { Self::rgb8(rgb[0], rgb[1], rgb[2]) diff --git a/src/gradient.rs b/src/gradient.rs index c3b2e08..d68c92a 100644 --- a/src/gradient.rs +++ b/src/gradient.rs @@ -1,34 +1,41 @@ // Copyright 2022 the Peniko Authors // SPDX-License-Identifier: Apache-2.0 OR MIT -use super::{Color, Extend}; +use super::Extend; +#[cfg(feature = "legacy_color")] +use crate::Color; + +use color::{AlphaColor, Srgb}; use kurbo::Point; use smallvec::SmallVec; use core::hash::{Hash, Hasher}; /// Offset and color of a transition point in a [gradient](Gradient). -#[derive(Copy, Clone, PartialOrd, Default, Debug)] +// FIXME(color): Removed Default and PartialOrd for now. +#[derive(Copy, Clone, Debug)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct ColorStop { /// Normalized offset of the stop. pub offset: f32, /// Color at the specified offset. - pub color: Color, + pub color: AlphaColor, } impl Hash for ColorStop { fn hash(&self, state: &mut H) { self.offset.to_bits().hash(state); - self.color.hash(state); + // FIXME(color): Do the right thing here. + // self.color.hash(state); } } // Override PartialEq to use to_bits for the offset to match with the Hash impl impl PartialEq for ColorStop { fn eq(&self, other: &Self) -> bool { - self.offset.to_bits() == other.offset.to_bits() && self.color == other.color + // FIXME(color): Do the right thing here. + self.offset.to_bits() == other.offset.to_bits() // && self.color == other.color } } @@ -55,13 +62,23 @@ impl ColorStop { pub fn multiply_alpha(self, alpha: f32) -> Self { Self { offset: self.offset, - color: self.color.multiply_alpha(alpha), + color: self.color.mul_alpha(alpha), } } } +#[cfg(feature = "legacy_color")] impl From<(f32, Color)> for ColorStop { fn from(pair: (f32, Color)) -> Self { + Self { + offset: pair.0, + color: pair.1.into(), + } + } +} + +impl From<(f32, AlphaColor)> for ColorStop { + fn from(pair: (f32, AlphaColor)) -> Self { Self { offset: pair.0, color: pair.1, @@ -236,7 +253,20 @@ where } } +#[cfg(feature = "legacy_color")] impl ColorStopsSource for &'_ [Color] { + fn collect_stops(&self, vec: &mut SmallVec<[ColorStop; 4]>) { + if !self.is_empty() { + let denom = (self.len() - 1).max(1) as f32; + vec.extend(self.iter().enumerate().map(|(i, c)| ColorStop { + offset: (i as f32) / denom, + color: (*c).into(), + })); + } + } +} + +impl ColorStopsSource for &'_ [AlphaColor] { fn collect_stops(&self, vec: &mut SmallVec<[ColorStop; 4]>) { if !self.is_empty() { let denom = (self.len() - 1).max(1) as f32; @@ -248,8 +278,15 @@ impl ColorStopsSource for &'_ [Color] { } } +#[cfg(feature = "legacy_color")] impl ColorStopsSource for [Color; N] { fn collect_stops(&self, vec: &mut SmallVec<[ColorStop; 4]>) { (&self[..]).collect_stops(vec); } } + +impl ColorStopsSource for [AlphaColor; N] { + fn collect_stops(&self, vec: &mut SmallVec<[ColorStop; 4]>) { + (&self[..]).collect_stops(vec); + } +} diff --git a/src/lib.rs b/src/lib.rs index 3ef8dd5..6e058d0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,13 +3,14 @@ //! A Rust 2D graphics type library //! -//! The `peniko` library builds on top of [`kurbo`] and provides a set of generic types that define -//! styles for rendering and composition. +//! The `peniko` library builds on top of [`kurbo`] and [`color`] and provides a set of +//! generic types that define styles for rendering and composition. //! //! The name "peniko" is Esperanto for "brush" which is one family of types that the library //! contains. //! //! [`kurbo`]: https://crates.io/crates/kurbo +//! [`color`]: https://crates.io/crates/color #![cfg_attr(all(not(feature = "std"), not(test)), no_std)] #![cfg_attr(docsrs, feature(doc_auto_cfg))] @@ -25,6 +26,7 @@ mod blend; mod blob; mod brush; +#[cfg(feature = "legacy_color")] mod color; mod font; mod gradient; @@ -37,6 +39,7 @@ pub use kurbo; pub use blend::{BlendMode, Compose, Mix}; pub use blob::{Blob, WeakBlob}; pub use brush::{Brush, BrushRef, Extend}; +#[cfg(feature = "legacy_color")] pub use color::Color; pub use font::Font; pub use gradient::{ColorStop, ColorStops, ColorStopsSource, Gradient, GradientKind};