mirror of
https://github.com/penpot/penpot.git
synced 2025-05-31 11:46:11 +02:00
✨ Embed stop data into RawGradientData
This commit is contained in:
parent
e7b74939cb
commit
281c0068d9
3 changed files with 69 additions and 38 deletions
|
@ -223,7 +223,7 @@
|
||||||
(h/call wasm/internal-module "_add_shape_solid_fill" rgba))
|
(h/call wasm/internal-module "_add_shape_solid_fill" rgba))
|
||||||
|
|
||||||
(some? gradient)
|
(some? gradient)
|
||||||
(let [size (sr-fills/gradient-byte-size gradient)
|
(let [size sr-fills/GRADIENT-BYTE-SIZE
|
||||||
offset (mem/alloc-bytes size)
|
offset (mem/alloc-bytes size)
|
||||||
heap (mem/get-heap-u32)]
|
heap (mem/get-heap-u32)]
|
||||||
(sr-fills/write-gradient-fill! offset heap gradient opacity)
|
(sr-fills/write-gradient-fill! offset heap gradient opacity)
|
||||||
|
@ -269,7 +269,7 @@
|
||||||
|
|
||||||
(cond
|
(cond
|
||||||
(some? gradient)
|
(some? gradient)
|
||||||
(let [size (sr-fills/gradient-byte-size gradient)
|
(let [size sr-fills/GRADIENT-BYTE-SIZE
|
||||||
offset (mem/alloc-bytes size)
|
offset (mem/alloc-bytes size)
|
||||||
heap (mem/get-heap-u32)]
|
heap (mem/get-heap-u32)]
|
||||||
(sr-fills/write-gradient-fill! offset heap gradient opacity)
|
(sr-fills/write-gradient-fill! offset heap gradient opacity)
|
||||||
|
|
|
@ -2,13 +2,13 @@
|
||||||
(:require
|
(:require
|
||||||
[app.render-wasm.serializers.color :as clr]))
|
[app.render-wasm.serializers.color :as clr]))
|
||||||
|
|
||||||
(def GRADIENT-STOP-SIZE 8)
|
(def ^:private GRADIENT-STOP-SIZE 8)
|
||||||
(def GRADIENT-BASE-SIZE 24)
|
(def ^:private GRADIENT-BASE-SIZE 28)
|
||||||
|
;; TODO: Define in shape model
|
||||||
|
(def ^:private MAX-GRADIENT-STOPS 8)
|
||||||
|
|
||||||
(defn gradient-byte-size
|
(def GRADIENT-BYTE-SIZE
|
||||||
[gradient]
|
(+ GRADIENT-BASE-SIZE (* MAX-GRADIENT-STOPS GRADIENT-STOP-SIZE)))
|
||||||
(let [stops (:stops gradient)]
|
|
||||||
(+ GRADIENT-BASE-SIZE (* (count stops) GRADIENT-STOP-SIZE))))
|
|
||||||
|
|
||||||
(defn write-gradient-fill!
|
(defn write-gradient-fill!
|
||||||
[offset heap gradient opacity]
|
[offset heap gradient opacity]
|
||||||
|
@ -18,13 +18,14 @@
|
||||||
end-x (:end-x gradient)
|
end-x (:end-x gradient)
|
||||||
end-y (:end-y gradient)
|
end-y (:end-y gradient)
|
||||||
width (or (:width gradient) 0)
|
width (or (:width gradient) 0)
|
||||||
stops (:stops gradient)]
|
stops (take MAX-GRADIENT-STOPS (:stops gradient))]
|
||||||
(.setFloat32 dview offset start-x true)
|
(.setFloat32 dview offset start-x true)
|
||||||
(.setFloat32 dview (+ offset 4) start-y true)
|
(.setFloat32 dview (+ offset 4) start-y true)
|
||||||
(.setFloat32 dview (+ offset 8) end-x true)
|
(.setFloat32 dview (+ offset 8) end-x true)
|
||||||
(.setFloat32 dview (+ offset 12) end-y true)
|
(.setFloat32 dview (+ offset 12) end-y true)
|
||||||
(.setFloat32 dview (+ offset 16) opacity true)
|
(.setFloat32 dview (+ offset 16) opacity true)
|
||||||
(.setFloat32 dview (+ offset 20) width true)
|
(.setFloat32 dview (+ offset 20) width true)
|
||||||
|
(.setUint32 dview (+ offset 24) (count stops) true)
|
||||||
(loop [stops (seq stops) offset (+ offset GRADIENT-BASE-SIZE)]
|
(loop [stops (seq stops) offset (+ offset GRADIENT-BASE-SIZE)]
|
||||||
(if (empty? stops)
|
(if (empty? stops)
|
||||||
offset
|
offset
|
||||||
|
|
|
@ -3,7 +3,10 @@ use skia_safe::{self as skia, Rect};
|
||||||
use super::Color;
|
use super::Color;
|
||||||
use crate::uuid::Uuid;
|
use crate::uuid::Uuid;
|
||||||
|
|
||||||
pub const RAW_FILL_DATA_SIZE: usize = 24;
|
const MAX_GRADIENT_STOPS: usize = 8;
|
||||||
|
const BASE_GRADIENT_DATA_SIZE: usize = 28;
|
||||||
|
const RAW_GRADIENT_DATA_SIZE: usize =
|
||||||
|
BASE_GRADIENT_DATA_SIZE + RAW_STOP_DATA_SIZE * MAX_GRADIENT_STOPS;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
@ -14,10 +17,12 @@ pub struct RawGradientData {
|
||||||
end_y: f32,
|
end_y: f32,
|
||||||
opacity: f32,
|
opacity: f32,
|
||||||
width: f32,
|
width: f32,
|
||||||
|
stop_count: u32,
|
||||||
|
stops: [RawStopData; MAX_GRADIENT_STOPS],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<[u8; RAW_FILL_DATA_SIZE]> for RawGradientData {
|
impl From<[u8; RAW_GRADIENT_DATA_SIZE]> for RawGradientData {
|
||||||
fn from(bytes: [u8; RAW_FILL_DATA_SIZE]) -> Self {
|
fn from(bytes: [u8; RAW_GRADIENT_DATA_SIZE]) -> Self {
|
||||||
Self {
|
Self {
|
||||||
start_x: f32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]),
|
start_x: f32::from_le_bytes([bytes[0], bytes[1], bytes[2], bytes[3]]),
|
||||||
start_y: f32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]),
|
start_y: f32::from_le_bytes([bytes[4], bytes[5], bytes[6], bytes[7]]),
|
||||||
|
@ -25,6 +30,16 @@ impl From<[u8; RAW_FILL_DATA_SIZE]> for RawGradientData {
|
||||||
end_y: f32::from_le_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]),
|
end_y: f32::from_le_bytes([bytes[12], bytes[13], bytes[14], bytes[15]]),
|
||||||
opacity: f32::from_le_bytes([bytes[16], bytes[17], bytes[18], bytes[19]]),
|
opacity: f32::from_le_bytes([bytes[16], bytes[17], bytes[18], bytes[19]]),
|
||||||
width: f32::from_le_bytes([bytes[20], bytes[21], bytes[22], bytes[23]]),
|
width: f32::from_le_bytes([bytes[20], bytes[21], bytes[22], bytes[23]]),
|
||||||
|
stop_count: u32::from_le_bytes([bytes[24], bytes[25], bytes[26], bytes[27]]),
|
||||||
|
// FIXME: 2025-04-22: use `array_chunks` once the next release is out
|
||||||
|
// and we update our devenv.
|
||||||
|
// See https://github.com/rust-lang/rust/issues/74985
|
||||||
|
stops: bytes[28..]
|
||||||
|
.chunks_exact(RAW_STOP_DATA_SIZE)
|
||||||
|
.map(|chunk| RawStopData::try_from(chunk).unwrap())
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.try_into()
|
||||||
|
.unwrap(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -75,6 +90,18 @@ impl From<[u8; RAW_STOP_DATA_SIZE]> for RawStopData {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: We won't need this once we use `array_chunks`. See comment above.
|
||||||
|
impl TryFrom<&[u8]> for RawStopData {
|
||||||
|
type Error = String;
|
||||||
|
|
||||||
|
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
|
||||||
|
let data: [u8; RAW_STOP_DATA_SIZE] = bytes
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| "Invalid stop data".to_string())?;
|
||||||
|
Ok(RawStopData::from(data))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, PartialEq)]
|
#[derive(Debug, Clone, PartialEq)]
|
||||||
pub struct Gradient {
|
pub struct Gradient {
|
||||||
colors: Vec<Color>,
|
colors: Vec<Color>,
|
||||||
|
@ -86,9 +113,11 @@ pub struct Gradient {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Gradient {
|
impl Gradient {
|
||||||
pub fn add_stop(&mut self, color: Color, offset: f32) {
|
fn add_stops(&mut self, stops: &[(Color, f32)]) {
|
||||||
self.colors.push(color);
|
let colors = stops.iter().map(|(color, _)| *color);
|
||||||
self.offsets.push(offset);
|
let offsets = stops.iter().map(|(_, offset)| *offset);
|
||||||
|
self.colors.extend(colors);
|
||||||
|
self.offsets.extend(offsets);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn to_linear_shader(&self, rect: &Rect) -> Option<skia::Shader> {
|
fn to_linear_shader(&self, rect: &Rect) -> Option<skia::Shader> {
|
||||||
|
@ -144,24 +173,14 @@ impl Gradient {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<&[u8]> for Gradient {
|
impl From<RawGradientData> for Gradient {
|
||||||
type Error = String;
|
fn from(raw_gradient: RawGradientData) -> Self {
|
||||||
|
let stops = raw_gradient
|
||||||
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
|
.stops
|
||||||
let raw_gradient_bytes: [u8; RAW_FILL_DATA_SIZE] = bytes[0..RAW_FILL_DATA_SIZE]
|
.iter()
|
||||||
.try_into()
|
.take(raw_gradient.stop_count as usize)
|
||||||
.map_err(|_| "Invalid gradient data".to_string())?;
|
.map(|stop| (stop.color(), stop.offset()))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
let raw_gradient = RawGradientData::from(raw_gradient_bytes);
|
|
||||||
let stops: Vec<RawStopData> = bytes[RAW_FILL_DATA_SIZE..]
|
|
||||||
.chunks(RAW_STOP_DATA_SIZE)
|
|
||||||
.map(|chunk| {
|
|
||||||
let data: [u8; RAW_STOP_DATA_SIZE] = chunk
|
|
||||||
.try_into()
|
|
||||||
.map_err(|_| "Invalid stop data".to_string())?;
|
|
||||||
Ok(RawStopData::from(data))
|
|
||||||
})
|
|
||||||
.collect::<Result<Vec<_>, Self::Error>>()?;
|
|
||||||
|
|
||||||
let mut gradient = Gradient {
|
let mut gradient = Gradient {
|
||||||
start: raw_gradient.start(),
|
start: raw_gradient.start(),
|
||||||
|
@ -172,9 +191,20 @@ impl TryFrom<&[u8]> for Gradient {
|
||||||
width: raw_gradient.width(),
|
width: raw_gradient.width(),
|
||||||
};
|
};
|
||||||
|
|
||||||
for stop in stops {
|
gradient.add_stops(&stops);
|
||||||
gradient.add_stop(stop.color(), stop.offset());
|
|
||||||
}
|
gradient
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<&[u8]> for Gradient {
|
||||||
|
type Error = String;
|
||||||
|
|
||||||
|
fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
|
||||||
|
let raw_gradient_bytes: [u8; RAW_GRADIENT_DATA_SIZE] = bytes[0..RAW_GRADIENT_DATA_SIZE]
|
||||||
|
.try_into()
|
||||||
|
.map_err(|_| "Invalid gradient data".to_string())?;
|
||||||
|
let gradient = RawGradientData::from(raw_gradient_bytes).into();
|
||||||
|
|
||||||
Ok(gradient)
|
Ok(gradient)
|
||||||
}
|
}
|
||||||
|
@ -228,7 +258,7 @@ impl Fill {
|
||||||
}
|
}
|
||||||
Self::LinearGradient(gradient) => {
|
Self::LinearGradient(gradient) => {
|
||||||
let mut p = skia::Paint::default();
|
let mut p = skia::Paint::default();
|
||||||
p.set_shader(gradient.to_linear_shader(&rect));
|
p.set_shader(gradient.to_linear_shader(rect));
|
||||||
p.set_alpha((gradient.opacity * 255.) as u8);
|
p.set_alpha((gradient.opacity * 255.) as u8);
|
||||||
p.set_style(skia::PaintStyle::Fill);
|
p.set_style(skia::PaintStyle::Fill);
|
||||||
p.set_anti_alias(anti_alias);
|
p.set_anti_alias(anti_alias);
|
||||||
|
@ -237,7 +267,7 @@ impl Fill {
|
||||||
}
|
}
|
||||||
Self::RadialGradient(gradient) => {
|
Self::RadialGradient(gradient) => {
|
||||||
let mut p = skia::Paint::default();
|
let mut p = skia::Paint::default();
|
||||||
p.set_shader(gradient.to_radial_shader(&rect));
|
p.set_shader(gradient.to_radial_shader(rect));
|
||||||
p.set_alpha((gradient.opacity * 255.) as u8);
|
p.set_alpha((gradient.opacity * 255.) as u8);
|
||||||
p.set_style(skia::PaintStyle::Fill);
|
p.set_style(skia::PaintStyle::Fill);
|
||||||
p.set_anti_alias(anti_alias);
|
p.set_anti_alias(anti_alias);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue