Refactored ColorF to RgbaF.

This commit is contained in:
Samuel Guerra 2024-02-19 18:59:39 -03:00
parent 8f721718e3
commit 312d0e7083
17 changed files with 309 additions and 192 deletions

View File

@ -1,4 +1,6 @@
* Continue removing webrender from view API.
- Rename RgbaF to Rgba, move Rgba to unit crate, use it directly.
- Finish text API, GlyphInstance, GlyphOptions.
# Documentation

View File

@ -26,7 +26,7 @@ fn app_main() {
Window! {
title = "Calculator";
data = var(Calculator::default());
// zero_ui::properties::inspector::show_bounds = true;
zero_ui::window::inspector::show_center_points = true;
resizable = false;
auto_size = true;
padding = 5;

View File

@ -9,7 +9,7 @@ use crate::{
use zero_ui_color::{
filter::RenderFilter,
gradient::{RenderExtendMode, RenderGradientStop},
rgba, RenderColor, RenderMixBlendMode,
rgba, RenderMixBlendMode,
};
use zero_ui_layout::unit::{
euclid, AngleRadian, Factor, FactorUnits, Px, PxCornerRadius, PxLine, PxPoint, PxRect, PxSideOffsets, PxSize, PxTransform, PxVector,
@ -24,6 +24,7 @@ use zero_ui_view_api::{
unit::PxToWr,
webrender_api::{self, FontRenderMode, GlyphInstance, GlyphOptions, SpatialTreeItemKey},
window::FrameId,
RgbaF,
};
use crate::{
@ -245,12 +246,12 @@ pub struct FrameBuilder {
can_reuse: bool,
open_reuse: Option<ReuseStart>,
clear_color: Option<RenderColor>,
clear_color: Option<RgbaF>,
widget_count: usize,
widget_count_offsets: ParallelSegmentOffsets,
debug_dot_overlays: Vec<(PxPoint, RenderColor)>,
debug_dot_overlays: Vec<(PxPoint, RgbaF)>,
}
impl FrameBuilder {
/// New builder.
@ -372,7 +373,7 @@ impl FrameBuilder {
///
/// Note that the clear color is always *rendered* first before all other layers, if more then
/// one layer sets the clear color only the value set on the top-most layer is used.
pub fn set_clear_color(&mut self, color: RenderColor) {
pub fn set_clear_color(&mut self, color: RgbaF) {
self.clear_color = Some(color);
}
@ -1538,7 +1539,7 @@ impl FrameBuilder {
clip_rect: PxRect,
glyphs: &[GlyphInstance],
font: &impl Font,
color: FrameValue<RenderColor>,
color: FrameValue<RgbaF>,
synthesis: FontSynthesis,
aa: FontAntiAliasing,
) {
@ -1615,7 +1616,7 @@ impl FrameBuilder {
/// part of the screen is affected, as the entire region is redraw every full frame even if the color did not actually change.
///
/// [`RenderMode::Software`]: zero_ui_view_api::window::RenderMode::Software
pub fn push_color(&mut self, clip_rect: PxRect, color: FrameValue<RenderColor>) {
pub fn push_color(&mut self, clip_rect: PxRect, color: FrameValue<RgbaF>) {
expect_inner!(self.push_color);
warn_empty!(self.push_color(clip_rect));
@ -1782,7 +1783,7 @@ impl FrameBuilder {
}
/// Push a styled vertical or horizontal line.
pub fn push_line(&mut self, clip_rect: PxRect, orientation: border::LineOrientation, color: RenderColor, style: border::LineStyle) {
pub fn push_line(&mut self, clip_rect: PxRect, orientation: border::LineOrientation, color: RgbaF, style: border::LineStyle) {
expect_inner!(self.push_line);
warn_empty!(self.push_line(clip_rect));
@ -1801,16 +1802,16 @@ impl FrameBuilder {
self.display_list.push_border(
clip_rect,
widths,
webrender_api::BorderSide { color, style },
webrender_api::BorderSide {
color: RenderColor::TRANSPARENT,
zero_ui_view_api::BorderSide { color, style },
zero_ui_view_api::BorderSide {
color: RgbaF::new(0.0, 0.0, 0.0, 0.0),
style: webrender_api::BorderStyle::Hidden,
},
webrender_api::BorderSide {
color: RenderColor::TRANSPARENT,
zero_ui_view_api::BorderSide {
color: RgbaF::new(0.0, 0.0, 0.0, 0.0),
style: webrender_api::BorderStyle::Hidden,
},
webrender_api::BorderSide { color, style },
zero_ui_view_api::BorderSide { color, style },
PxCornerRadius::zero(),
);
}
@ -1825,7 +1826,7 @@ impl FrameBuilder {
/// Record the `offset` in the current context and [`push_debug_dot`] after render.
///
/// [`push_debug_dot`]: Self::push_debug_dot
pub fn push_debug_dot_overlay(&mut self, offset: PxPoint, color: impl Into<RenderColor>) {
pub fn push_debug_dot_overlay(&mut self, offset: PxPoint, color: impl Into<RgbaF>) {
if let Some(offset) = self.transform.transform_point(offset) {
self.debug_dot_overlays.push((offset, color.into()));
}
@ -1834,7 +1835,7 @@ impl FrameBuilder {
/// Push a `color` dot to mark the `offset`.
///
/// The *dot* is a circle of the `color` highlighted by an white outline and shadow.
pub fn push_debug_dot(&mut self, offset: PxPoint, color: impl Into<RenderColor>) {
pub fn push_debug_dot(&mut self, offset: PxPoint, color: impl Into<RgbaF>) {
if !self.visible {
return;
}
@ -1843,38 +1844,40 @@ impl FrameBuilder {
let radius = PxSize::splat(Px(6)) * scale;
let color = color.into();
let mut builder = webrender_api::GradientBuilder::new();
builder.push(RenderGradientStop { offset: 0.0, color });
builder.push(RenderGradientStop { offset: 0.5, color });
builder.push(RenderGradientStop {
offset: 0.6,
color: RenderColor::WHITE,
});
builder.push(RenderGradientStop {
offset: 0.7,
color: RenderColor::WHITE,
});
builder.push(RenderGradientStop {
offset: 0.8,
color: RenderColor::BLACK,
});
builder.push(RenderGradientStop {
offset: 1.0,
color: RenderColor::TRANSPARENT,
});
let center = radius.to_vector().to_point();
let gradient = builder.radial_gradient(center.to_wr(), radius.to_wr(), RenderExtendMode::Clamp);
let stops = builder.into_stops();
let bounds = radius * 2.0.fct();
let offset = offset - radius.to_vector();
self.display_list.push_radial_gradient(
PxRect::new(offset, bounds),
gradient,
&stops,
webrender_api::RadialGradient {
center: center.to_wr(),
radius: radius.to_wr(),
start_offset: 0.0,
end_offset: 1.0,
extend_mode: RenderExtendMode::Clamp,
},
&[
RenderGradientStop { offset: 0.0, color },
RenderGradientStop { offset: 0.5, color },
RenderGradientStop {
offset: 0.6,
color: RgbaF::new(1.0, 1.0, 1.0, 1.0),
},
RenderGradientStop {
offset: 0.7,
color: RgbaF::new(1.0, 1.0, 1.0, 1.0),
},
RenderGradientStop {
offset: 0.8,
color: RgbaF::new(0.0, 0.0, 0.0, 1.0),
},
RenderGradientStop {
offset: 1.0,
color: RgbaF::new(0.0, 0.0, 0.0, 0.0),
},
],
PxPoint::zero(),
bounds,
PxSize::zero(),
@ -2212,7 +2215,7 @@ pub struct BuiltFrame {
/// Built display list.
pub display_list: DisplayList,
/// Clear color selected for the frame.
pub clear_color: RenderColor,
pub clear_color: RgbaF,
}
enum RenderLineCommand {
@ -2247,12 +2250,12 @@ pub struct FrameUpdate {
transforms: Vec<FrameValueUpdate<PxTransform>>,
floats: Vec<FrameValueUpdate<f32>>,
colors: Vec<FrameValueUpdate<RenderColor>>,
colors: Vec<FrameValueUpdate<RgbaF>>,
extensions: Vec<(ApiExtensionId, ApiExtensionPayload)>,
current_clear_color: RenderColor,
clear_color: Option<RenderColor>,
current_clear_color: RgbaF,
clear_color: Option<RgbaF>,
frame_id: FrameId,
widget_id: WidgetId,
@ -2282,7 +2285,7 @@ impl FrameUpdate {
root_id: WidgetId,
root_bounds: WidgetBoundsInfo,
renderer: Option<&ViewRenderer>,
clear_color: RenderColor,
clear_color: RgbaF,
) -> Self {
let _ = renderer;
FrameUpdate {
@ -2331,7 +2334,7 @@ impl FrameUpdate {
}
/// Change the color used to clear the pixel buffer when redrawing the frame.
pub fn set_clear_color(&mut self, color: RenderColor) {
pub fn set_clear_color(&mut self, color: RgbaF) {
if self.visible {
self.clear_color = Some(color);
}
@ -2662,14 +2665,14 @@ impl FrameUpdate {
/// Update a color value.
///
/// See [`FrameBuilder::push_color`] for details.
pub fn update_color(&mut self, new_value: FrameValueUpdate<RenderColor>) {
pub fn update_color(&mut self, new_value: FrameValueUpdate<RgbaF>) {
if self.visible {
self.colors.push(new_value)
}
}
/// Update a color value, if there is one.
pub fn update_color_opt(&mut self, new_value: Option<FrameValueUpdate<RenderColor>>) {
pub fn update_color_opt(&mut self, new_value: Option<FrameValueUpdate<RgbaF>>) {
if let Some(value) = new_value {
self.update_color(value)
}
@ -2775,9 +2778,9 @@ pub struct BuiltFrameUpdate {
/// Bound floats update.
pub floats: Vec<FrameValueUpdate<f32>>,
/// Bound colors update.
pub colors: Vec<FrameValueUpdate<RenderColor>>,
pub colors: Vec<FrameValueUpdate<RgbaF>>,
/// New clear color.
pub clear_color: Option<RenderColor>,
pub clear_color: Option<RgbaF>,
/// Renderer extension updates.
pub extensions: Vec<(ApiExtensionId, ApiExtensionPayload)>,
}

View File

@ -260,9 +260,9 @@ impl BorderSide {
Self::new(colors::BLACK.transparent(), BorderStyle::Hidden)
}
}
impl From<BorderSide> for w_api::BorderSide {
impl From<BorderSide> for zero_ui_view_api::BorderSide {
fn from(s: BorderSide) -> Self {
w_api::BorderSide {
zero_ui_view_api::BorderSide {
color: s.color.into(),
style: s.style.into(),
}

View File

@ -226,7 +226,6 @@ impl WINDOW {
/// Test only methods.
#[cfg(any(test, doc, feature = "test_util"))]
mod _impl {
use zero_ui_color::RenderColor;
use zero_ui_layout::{
context::{InlineConstraints, InlineConstraintsLayout, InlineConstraintsMeasure, LayoutMetrics, LAYOUT},
unit::{FactorUnits, Length, Px, PxConstraints2d, PxSize, PxTransform},
@ -467,7 +466,7 @@ mod _impl {
wgt.id,
wgt.bounds.lock().clone(),
None,
RenderColor::BLACK,
zero_ui_view_api::RgbaF::new(0.0, 0.0, 0.0, 1.0),
);
f
};

View File

@ -10,13 +10,9 @@ use zero_ui_var::{
animation::{easing::EasingStep, Transitionable},
impl_from_and_into_var,
};
use zero_ui_view_api::{
display_list::{FilterOp, FrameValue},
unit::PxToWr,
webrender_api::Shadow,
};
use zero_ui_view_api::display_list::{FilterOp, FrameValue};
use crate::{RenderColor, Rgba};
use crate::{Rgba, RgbaF};
/// A color filter or combination of filters.
///
@ -199,11 +195,11 @@ impl Filter {
offset,
blur_radius,
color,
} => FilterOp::DropShadow(Shadow {
offset: offset.layout().to_wr().to_vector(),
color: RenderColor::from(*color),
} => FilterOp::DropShadow {
offset: offset.layout().to_vector().cast(),
color: RgbaF::from(*color),
blur_radius: blur_radius.layout_f32_x(),
}),
},
})
.collect()
}
@ -318,13 +314,17 @@ impl fmt::Debug for FilterData {
FilterOp::Opacity(o) => write!(f, "opacity({}.pct())", *o.value() * 100.0),
FilterOp::Saturate(s) => write!(f, "saturate({}.pct())", s * 100.0),
FilterOp::Sepia(s) => bool_or_pct("sepia", *s, f),
FilterOp::DropShadow(s) => write!(
FilterOp::DropShadow {
offset,
color,
blur_radius,
} => write!(
f,
"drop_shadow(({}, {}), {}, {})",
s.offset.x,
s.offset.y,
s.blur_radius,
Rgba::from(s.color)
offset.x,
offset.y,
blur_radius,
Rgba::from(*color)
),
FilterOp::ColorMatrix(m) => write!(f, "color_matrix({:?})", ColorMatrix(*m)),
FilterOp::Flood(c) => write!(f, "flood({})", Rgba::from(*c)),
@ -342,17 +342,10 @@ impl fmt::Debug for FilterData {
}
}
fn lerp_wr_color(s: RenderColor, to: &RenderColor, step: EasingStep) -> RenderColor {
fn lerp_rgbaf(s: RgbaF, to: &RgbaF, step: EasingStep) -> RgbaF {
Rgba::from(s).lerp(Rgba::from(*to), step).into()
}
fn lerp_wr_shadow(mut s: Shadow, to: &Shadow, step: EasingStep) -> Shadow {
s.offset = Transitionable::lerp(s.offset, &to.offset, step);
s.color = lerp_wr_color(s.color, &to.color, step);
s.blur_radius = s.blur_radius.lerp(&to.blur_radius, step);
s
}
fn lerp_frame_value<T: Transitionable>(s: FrameValue<T>, to: &FrameValue<T>, step: EasingStep) -> FrameValue<T> {
let mut bind_data = None;
let mut value = match s {
@ -413,8 +406,21 @@ fn lerp_filter_op(mut s: FilterOp, to: &FilterOp, step: EasingStep) -> FilterOp
(FilterOp::Sepia(a), FilterOp::Sepia(b)) => {
*a = a.lerp(b, step);
}
(FilterOp::DropShadow(a), FilterOp::DropShadow(b)) => {
*a = lerp_wr_shadow(*a, b, step);
(
FilterOp::DropShadow {
offset,
color,
blur_radius,
},
FilterOp::DropShadow {
offset: to_offset,
color: to_color,
blur_radius: to_blur,
},
) => {
*offset = Transitionable::lerp(*offset, to_offset, step);
*color = lerp_rgbaf(*color, to_color, step);
*blur_radius = blur_radius.lerp(to_blur, step);
}
(FilterOp::ColorMatrix(a), FilterOp::ColorMatrix(b)) => {
for (a, b) in a.iter_mut().zip(b) {
@ -422,7 +428,7 @@ fn lerp_filter_op(mut s: FilterOp, to: &FilterOp, step: EasingStep) -> FilterOp
}
}
(FilterOp::Flood(a), FilterOp::Flood(b)) => {
*a = lerp_wr_color(*a, b, step);
*a = lerp_rgbaf(*a, b, step);
}
(a, b) => {
if step >= 1.fct() {

View File

@ -519,7 +519,7 @@ impl Transitionable for ColorStop {
/// Computed [`GradientStop`].
///
/// The color offset is in the 0..=1 range.
pub type RenderGradientStop = zero_ui_view_api::webrender_api::GradientStop;
pub type RenderGradientStop = zero_ui_view_api::GradientStop;
/// A stop in a gradient.
#[derive(Clone, PartialEq, serde::Serialize, serde::Deserialize)]
@ -933,7 +933,7 @@ impl GradientStops {
render_stops.push(RenderGradientStop {
// offset and color will be calculated later.
offset: 0.0,
color: RenderColor::BLACK,
color: RgbaF::new(0.0, 0.0, 0.0, 1.0),
})
}
}
@ -1031,12 +1031,12 @@ impl GradientStops {
ExtendMode::Repeat | ExtendMode::Reflect => {
// fill with the average of all colors.
let len = render_stops.len() as f32;
let color = RenderColor {
r: render_stops.iter().map(|s| s.color.r).sum::<f32>() / len,
g: render_stops.iter().map(|s| s.color.g).sum::<f32>() / len,
b: render_stops.iter().map(|s| s.color.b).sum::<f32>() / len,
a: render_stops.iter().map(|s| s.color.a).sum::<f32>() / len,
};
let color = RgbaF::new(
render_stops.iter().map(|s| s.color[0]).sum::<f32>() / len,
render_stops.iter().map(|s| s.color[1]).sum::<f32>() / len,
render_stops.iter().map(|s| s.color[2]).sum::<f32>() / len,
render_stops.iter().map(|s| s.color[3]).sum::<f32>() / len,
);
render_stops.clear();
render_stops.push(RenderGradientStop { offset: 0.0, color });
render_stops.push(RenderGradientStop { offset: 1.0, color });
@ -1288,14 +1288,14 @@ mod tests {
assert_eq!(
stops[0],
RenderGradientStop {
color: RenderColor::BLACK,
color: RgbaF::new(0.0, 0.0, 0.0, 1.0),
offset: 0.0
}
);
assert_eq!(
stops[1],
RenderGradientStop {
color: RenderColor::WHITE,
color: RgbaF::new(1.0, 1.0, 1.0, 1.0),
offset: 1.0
}
);
@ -1355,26 +1355,21 @@ mod tests {
assert_eq!(
stops[0],
RenderGradientStop {
color: RenderColor::BLACK,
color: RgbaF::new(0.0, 0.0, 0.0, 1.0),
offset: 0.0
}
);
assert_eq!(
stops[1],
RenderGradientStop {
color: RenderColor {
r: 0.5,
g: 0.5,
b: 0.5,
a: 1.0
},
color: RgbaF::new(0.5, 0.5, 0.5, 1.0),
offset: 30.0 / 100.0
}
);
assert_eq!(
stops[2],
RenderGradientStop {
color: RenderColor::WHITE,
color: RgbaF::new(1.0, 1.0, 1.0, 1.0),
offset: 1.0
}
);

View File

@ -15,6 +15,8 @@ use zero_ui_var::{
};
use zero_ui_view_api::webrender_api;
pub use zero_ui_view_api::RgbaF;
pub use zero_ui_view_api::config::ColorScheme;
#[doc(hidden)]
@ -66,9 +68,6 @@ const EPSILON: f32 = 0.00001;
/// Minimal difference between values in around the 1.0..=100.0 scale.
const EPSILON_100: f32 = 0.001;
/// Webrender RGBA.
pub type RenderColor = webrender_api::ColorF;
/// RGB + alpha.
///
/// # Equality
@ -895,12 +894,12 @@ impl_from_and_into_var! {
}
}
fn from(color: RenderColor) -> Rgba {
fn from(color: RgbaF) -> Rgba {
Rgba {
red: color.r,
green: color.g,
blue: color.b,
alpha: color.a,
red: color[0],
green: color[1],
blue: color[2],
alpha: color[3],
}
}
}
@ -986,7 +985,7 @@ impl_from_and_into_var! {
}
/// Values are clamped to the `[0.0..=1.0]` range and `NaN` becomes `0.0`.
impl From<Rgba> for RenderColor {
impl From<Rgba> for RgbaF {
fn from(rgba: Rgba) -> Self {
fn c(f: f32) -> f32 {
if f.is_nan() || f <= 0.0 {
@ -997,12 +996,7 @@ impl From<Rgba> for RenderColor {
f
}
}
RenderColor {
r: c(rgba.red),
g: c(rgba.green),
b: c(rgba.blue),
a: c(rgba.alpha),
}
RgbaF::new(c(rgba.red), c(rgba.green), c(rgba.blue), c(rgba.alpha))
}
}
@ -1207,7 +1201,7 @@ impl From<Factor> for RgbaComponent {
}
/// Linear interpolate between `a` and `b` by the normalized `amount`.
pub fn lerp_render_color(a: RenderColor, b: RenderColor, amount: f32) -> RenderColor {
pub fn lerp_render_color(a: RgbaF, b: RgbaF, amount: f32) -> RgbaF {
let a = Rgba::from(a);
let b = Rgba::from(b);
a.lerp(b, amount.fct()).into()

View File

@ -1841,8 +1841,6 @@ enum InitState {
Inited,
}
type RenderColor = zero_ui_view_api::webrender_api::ColorF;
/// Implementer of window UI node tree initialization and management.
struct ContentCtrl {
vars: WindowVars,
@ -1854,7 +1852,7 @@ struct ContentCtrl {
init_state: InitState,
frame_id: FrameId,
clear_color: RenderColor,
clear_color: zero_ui_view_api::RgbaF,
}
impl ContentCtrl {
pub fn new(vars: WindowVars, commands: WindowCommands, window: WindowRoot) -> Self {
@ -1869,7 +1867,7 @@ impl ContentCtrl {
init_state: InitState::SkipOne,
frame_id: FrameId::INVALID,
clear_color: RenderColor::BLACK,
clear_color: zero_ui_view_api::RgbaF::new(0.0, 0.0, 0.0, 1.0),
}
}

View File

@ -16,6 +16,7 @@ use crate::{
image::ImageTextureId,
unit::PxToWr,
window::FrameId,
BorderSide, GradientStop, RgbaF,
};
use zero_ui_unit::*;
@ -250,10 +251,10 @@ impl DisplayListBuilder {
&mut self,
bounds: PxRect,
widths: PxSideOffsets,
top: wr::BorderSide,
right: wr::BorderSide,
bottom: wr::BorderSide,
left: wr::BorderSide,
top: BorderSide,
right: BorderSide,
bottom: BorderSide,
left: BorderSide,
radius: PxCornerRadius,
) {
self.list.push(DisplayItem::Border {
@ -291,7 +292,7 @@ impl DisplayListBuilder {
clip_rect: PxRect,
font_id: FontId,
glyphs: &[wr::GlyphInstance],
color: FrameValue<wr::ColorF>,
color: FrameValue<RgbaF>,
options: wr::GlyphOptions,
) {
self.list.push(DisplayItem::Text {
@ -327,7 +328,7 @@ impl DisplayListBuilder {
}
/// Push a color rectangle.
pub fn push_color(&mut self, clip_rect: PxRect, color: FrameValue<wr::ColorF>) {
pub fn push_color(&mut self, clip_rect: PxRect, color: FrameValue<RgbaF>) {
self.list.push(DisplayItem::Color { clip_rect, color })
}
@ -352,7 +353,7 @@ impl DisplayListBuilder {
&mut self,
clip_rect: PxRect,
gradient: wr::Gradient,
stops: &[wr::GradientStop],
stops: &[GradientStop],
tile_origin: PxPoint,
tile_size: PxSize,
tile_spacing: PxSize,
@ -372,7 +373,7 @@ impl DisplayListBuilder {
&mut self,
clip_rect: PxRect,
gradient: wr::RadialGradient,
stops: &[wr::GradientStop],
stops: &[GradientStop],
tile_origin: PxPoint,
tile_size: PxSize,
tile_spacing: PxSize,
@ -392,7 +393,7 @@ impl DisplayListBuilder {
&mut self,
clip_rect: PxRect,
gradient: wr::ConicGradient,
stops: &[wr::GradientStop],
stops: &[GradientStop],
tile_origin: PxPoint,
tile_size: PxSize,
tile_spacing: PxSize,
@ -411,7 +412,7 @@ impl DisplayListBuilder {
pub fn push_line(
&mut self,
clip_rect: PxRect,
color: wr::ColorF,
color: RgbaF,
style: wr::LineStyle,
wavy_line_thickness: f32,
orientation: wr::LineOrientation,
@ -782,7 +783,7 @@ impl PxToWr for f32 {
}
}
// to work with into_wr
impl PxToWr for wr::ColorF {
impl PxToWr for RgbaF {
type AsDevice = wr::ColorF;
type AsLayout = wr::ColorF;
@ -790,15 +791,15 @@ impl PxToWr for wr::ColorF {
type AsWorld = wr::ColorF;
fn to_wr_device(self) -> Self::AsDevice {
self
self.to_wr()
}
fn to_wr_world(self) -> Self::AsWorld {
self
self.to_wr()
}
fn to_wr(self) -> Self::AsLayout {
self
wr::ColorF::new(self[0], self[1], self[2], self[3])
}
}
@ -933,7 +934,7 @@ impl DisplayListCache {
ext: &mut dyn DisplayListExtension,
transforms: Vec<FrameValueUpdate<PxTransform>>,
floats: Vec<FrameValueUpdate<f32>>,
colors: Vec<FrameValueUpdate<wr::ColorF>>,
colors: Vec<FrameValueUpdate<RgbaF>>,
extensions: Vec<(ApiExtensionId, ApiExtensionPayload)>,
resized: bool,
) -> Result<Option<wr::DynamicProperties>, wr::BuiltDisplayList> {
@ -1013,13 +1014,20 @@ pub enum FilterOp {
/// Sepia, in [0..=1] range.
Sepia(f32),
/// Pixel perfect shadow.
DropShadow(wr::Shadow),
DropShadow {
/// Shadow offset.
offset: euclid::Vector2D<f32, Px>,
/// Shadow color.
color: RgbaF,
/// Shadow blur.
blur_radius: f32,
},
/// Custom filter.
///
/// The color matrix is in the format of SVG color matrix, [0..5] is the first matrix row.
ColorMatrix([f32; 20]),
/// Fill with color.
Flood(wr::ColorF),
Flood(RgbaF),
}
impl FilterOp {
/// To webrender filter-op.
@ -1034,12 +1042,20 @@ impl FilterOp {
FilterOp::Opacity(o) => wr::FilterOp::Opacity(o.into_wr(), *o.value()),
FilterOp::Saturate(s) => wr::FilterOp::Saturate(s),
FilterOp::Sepia(s) => wr::FilterOp::Sepia(s),
FilterOp::DropShadow(d) => wr::FilterOp::DropShadow(d),
FilterOp::DropShadow {
offset,
color,
blur_radius,
} => wr::FilterOp::DropShadow(wr::Shadow {
offset: offset.cast_unit(),
color: color.to_wr(),
blur_radius,
}),
FilterOp::ColorMatrix(m) => wr::FilterOp::ColorMatrix([
m[0], m[5], m[10], m[15], m[1], m[6], m[11], m[16], m[2], m[7], m[12], m[17], m[3], m[8], m[13], m[18], m[4], m[9], m[14],
m[19],
]),
FilterOp::Flood(c) => wr::FilterOp::Flood(c),
FilterOp::Flood(c) => wr::FilterOp::Flood(c.to_wr()),
}
}
}
@ -1088,7 +1104,7 @@ enum DisplayItem {
Border {
bounds: PxRect,
widths: PxSideOffsets,
sides: [wr::BorderSide; 4],
sides: [BorderSide; 4],
radius: PxCornerRadius,
},
NinePatchBorder {
@ -1104,7 +1120,7 @@ enum DisplayItem {
clip_rect: PxRect,
font_id: FontId,
glyphs: Box<[wr::GlyphInstance]>,
color: FrameValue<wr::ColorF>,
color: FrameValue<RgbaF>,
options: wr::GlyphOptions,
},
@ -1120,7 +1136,7 @@ enum DisplayItem {
Color {
clip_rect: PxRect,
color: FrameValue<wr::ColorF>,
color: FrameValue<RgbaF>,
},
BackdropFilter {
clip_rect: PxRect,
@ -1132,7 +1148,7 @@ enum DisplayItem {
LinearGradient {
clip_rect: PxRect,
gradient: wr::Gradient,
stops: Box<[wr::GradientStop]>,
stops: Box<[GradientStop]>,
tile_origin: PxPoint,
tile_size: PxSize,
tile_spacing: PxSize,
@ -1140,7 +1156,7 @@ enum DisplayItem {
RadialGradient {
clip_rect: PxRect,
gradient: wr::RadialGradient,
stops: Box<[wr::GradientStop]>,
stops: Box<[GradientStop]>,
tile_origin: PxPoint,
tile_size: PxSize,
tile_spacing: PxSize,
@ -1148,7 +1164,7 @@ enum DisplayItem {
ConicGradient {
clip_rect: PxRect,
gradient: wr::ConicGradient,
stops: Box<[wr::GradientStop]>,
stops: Box<[GradientStop]>,
tile_origin: PxPoint,
tile_size: PxSize,
tile_spacing: PxSize,
@ -1156,7 +1172,7 @@ enum DisplayItem {
Line {
clip_rect: PxRect,
color: wr::ColorF,
color: RgbaF,
style: wr::LineStyle,
wavy_line_thickness: f32,
orientation: wr::LineOrientation,
@ -1323,7 +1339,7 @@ impl DisplayItem {
bounds,
glyphs,
wr::FontInstanceKey(cache.id_namespace(), font_id.get()),
color.into_value(),
color.into_value().to_wr(),
Some(*options),
);
}
@ -1381,10 +1397,10 @@ impl DisplayItem {
bounds,
widths.to_wr(),
wr::BorderDetails::Normal(wr::NormalBorder {
left: *left,
right: *right,
top: *top,
bottom: *bottom,
left: left.to_wr(),
right: right.to_wr(),
top: top.to_wr(),
bottom: bottom.to_wr(),
radius: radius.to_wr(),
do_aa: true,
}),
@ -1406,15 +1422,36 @@ impl DisplayItem {
wr::NinePatchBorderSource::Image(wr::ImageKey(cache.id_namespace(), image_id.get()), *rendering)
}
NinePatchSource::LinearGradient { gradient, stops } => {
wr_list.push_stops(stops);
let stops: Vec<_> = stops
.iter()
.map(|s| wr::GradientStop {
offset: s.offset,
color: s.color.to_wr(),
})
.collect();
wr_list.push_stops(&stops);
wr::NinePatchBorderSource::Gradient(*gradient)
}
NinePatchSource::RadialGradient { gradient, stops } => {
wr_list.push_stops(stops);
let stops: Vec<_> = stops
.iter()
.map(|s| wr::GradientStop {
offset: s.offset,
color: s.color.to_wr(),
})
.collect();
wr_list.push_stops(&stops);
wr::NinePatchBorderSource::RadialGradient(*gradient)
}
NinePatchSource::ConicGradient { gradient, stops } => {
wr_list.push_stops(stops);
let stops: Vec<_> = stops
.iter()
.map(|s| wr::GradientStop {
offset: s.offset,
color: s.color.to_wr(),
})
.collect();
wr_list.push_stops(&stops);
wr::NinePatchBorderSource::ConicGradient(*gradient)
}
};
@ -1494,9 +1531,16 @@ impl DisplayItem {
let bounds = PxRect::new(-tile_origin, clip_rect.size + tile_origin.to_vector().to_size()).to_wr();
let clip = sc.clip_chain_id(wr_list);
// stops needs to immediately followed by the gradient, if the clip-chain item
// stops needs to be immediately followed by the gradient, if the clip-chain item
// is inserted in the between the stops are lost.
wr_list.push_stops(stops);
let stops: Vec<_> = stops
.iter()
.map(|s| wr::GradientStop {
offset: s.offset,
color: s.color.to_wr(),
})
.collect();
wr_list.push_stops(&stops);
wr_list.push_gradient(
&wr::CommonItemProperties {
clip_rect: clip_rect.to_wr(),
@ -1523,7 +1567,14 @@ impl DisplayItem {
let bounds = PxRect::new(-tile_origin, clip_rect.size + tile_origin.to_vector().to_size()).to_wr();
let clip = sc.clip_chain_id(wr_list);
wr_list.push_stops(stops);
let stops: Vec<_> = stops
.iter()
.map(|s| wr::GradientStop {
offset: s.offset,
color: s.color.to_wr(),
})
.collect();
wr_list.push_stops(&stops);
wr_list.push_radial_gradient(
&wr::CommonItemProperties {
clip_rect: clip_rect.to_wr(),
@ -1550,7 +1601,14 @@ impl DisplayItem {
let bounds = PxRect::new(-tile_origin, clip_rect.size + tile_origin.to_vector().to_size()).to_wr();
let clip = sc.clip_chain_id(wr_list);
wr_list.push_stops(stops);
let stops: Vec<_> = stops
.iter()
.map(|s| wr::GradientStop {
offset: s.offset,
color: s.color.to_wr(),
})
.collect();
wr_list.push_stops(&stops);
wr_list.push_conic_gradient(
&wr::CommonItemProperties {
clip_rect: clip_rect.to_wr(),
@ -1583,7 +1641,7 @@ impl DisplayItem {
&bounds,
*wavy_line_thickness,
*orientation,
color,
&color.to_wr(),
*style,
);
}
@ -1671,7 +1729,7 @@ impl DisplayItem {
_ => false,
}
}
fn update_color(&mut self, t: &FrameValueUpdate<wr::ColorF>) -> bool {
fn update_color(&mut self, t: &FrameValueUpdate<RgbaF>) -> bool {
match self {
DisplayItem::Color {
color:
@ -1705,15 +1763,15 @@ pub enum NinePatchSource {
},
LinearGradient {
gradient: wr::Gradient,
stops: Box<[wr::GradientStop]>,
stops: Box<[GradientStop]>,
},
RadialGradient {
gradient: wr::RadialGradient,
stops: Box<[wr::GradientStop]>,
stops: Box<[GradientStop]>,
},
ConicGradient {
gradient: wr::ConicGradient,
stops: Box<[wr::GradientStop]>,
stops: Box<[GradientStop]>,
},
}

View File

@ -10,10 +10,11 @@ use crate::{
keyboard::{Key, KeyCode, KeyState},
mouse::{ButtonId, ButtonState, MouseButton, MouseScrollDelta},
touch::{TouchPhase, TouchUpdate},
unit::PxToWr,
window::{EventFrameRendered, FrameId, HeadlessOpenData, MonitorId, MonitorInfo, WindowChanged, WindowId, WindowOpenData},
};
use serde::{Deserialize, Serialize};
use std::{fmt, path::PathBuf};
use std::{fmt, ops, path::PathBuf};
use zero_ui_txt::Txt;
use zero_ui_unit::{DipPoint, PxRect, PxSize};
@ -773,6 +774,68 @@ impl std::error::Error for ViewProcessOffline {}
/// View Process IPC result.
pub(crate) type VpResult<T> = std::result::Result<T, ViewProcessOffline>;
/// RGBA color with normalized components (`0.0..=1.0`).
#[derive(Default, Debug, PartialEq, Clone, Copy, Serialize, Deserialize)]
pub struct RgbaF(pub [f32; 4]);
impl RgbaF {
/// New RGBA.
pub const fn new(r: f32, g: f32, b: f32, a: f32) -> Self {
Self([r, g, b, a])
}
}
impl ops::Deref for RgbaF {
type Target = [f32; 4];
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl ops::DerefMut for RgbaF {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
/// Offset and color in a gradient.
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize)]
pub struct GradientStop {
/// Offset in pixels.
pub offset: f32,
/// Color at the offset.
pub color: RgbaF,
}
/// Border side line style and color.
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Serialize)]
pub struct BorderSide {
/// Line color.
pub color: RgbaF,
/// Line Style.
pub style: webrender_api::BorderStyle,
}
impl PxToWr for BorderSide {
type AsDevice = webrender_api::BorderSide;
type AsLayout = webrender_api::BorderSide;
type AsWorld = webrender_api::BorderSide;
fn to_wr_device(self) -> Self::AsDevice {
self.to_wr()
}
fn to_wr_world(self) -> Self::AsWorld {
self.to_wr()
}
fn to_wr(self) -> Self::AsLayout {
webrender_api::BorderSide {
color: self.color.to_wr(),
style: self.style,
}
}
}
#[cfg(test)]
mod tests {
use super::*;

View File

@ -3,7 +3,7 @@
use std::fmt;
use serde::{Deserialize, Serialize};
use webrender_api::{ColorF, Epoch, RenderReasons};
use webrender_api::{Epoch, RenderReasons};
use zero_ui_txt::Txt;
use crate::{
@ -12,6 +12,7 @@ use crate::{
config::ColorScheme,
display_list::{DisplayList, FrameValueUpdate},
image::{ImageId, ImageLoadedData, ImageMaskMode},
RgbaF,
};
use zero_ui_unit::{Dip, DipPoint, DipRect, DipSize, DipToPx as _, Factor, Px, PxPoint, PxSize, PxToDip, PxTransform};
@ -252,7 +253,7 @@ pub struct FrameRequest {
pub id: FrameId,
/// Frame clear color.
pub clear_color: ColorF,
pub clear_color: RgbaF,
/// Display list.
pub display_list: DisplayList,
@ -291,13 +292,13 @@ pub struct FrameUpdateRequest {
/// Bound floats.
pub floats: Vec<FrameValueUpdate<f32>>,
/// Bound colors.
pub colors: Vec<FrameValueUpdate<ColorF>>,
pub colors: Vec<FrameValueUpdate<RgbaF>>,
/// Render update extension key and payload.
pub extensions: Vec<(ApiExtensionId, ApiExtensionPayload)>,
/// New clear color.
pub clear_color: Option<ColorF>,
pub clear_color: Option<RgbaF>,
/// Create an image or mask from this rendered frame.
///

View File

@ -4,7 +4,7 @@ use winit::event_loop::EventLoopWindowTarget;
use tracing::span::EnteredSpan;
use webrender::{
api::{ColorF, DocumentId, DynamicProperties, FontInstanceKey, FontInstanceOptions, FontKey, FontVariation, PipelineId},
api::{DocumentId, DynamicProperties, FontInstanceKey, FontInstanceOptions, FontKey, FontVariation, PipelineId},
RenderApi, Renderer, Transaction,
};
use zero_ui_unit::{DipSize, DipToPx, Factor, Px, PxRect};
@ -15,7 +15,7 @@ use zero_ui_view_api::{
image::{ImageId, ImageLoadedData, ImageMaskMode, ImageTextureId},
unit::*,
window::{FrameCapture, FrameId, FrameRequest, FrameUpdateRequest, HeadlessRequest, RenderMode, WindowId},
ViewProcessGen,
RgbaF, ViewProcessGen,
};
use crate::{
@ -45,7 +45,7 @@ pub(crate) struct Surface {
image_use: ImageUseMap,
display_list_cache: DisplayListCache,
clear_color: Option<ColorF>,
clear_color: Option<RgbaF>,
pending_frames: VecDeque<(FrameId, FrameCapture, Option<EnteredSpan>)>,
rendered_frame_id: FrameId,
@ -85,7 +85,7 @@ impl Surface {
renderer_id: Some((gen.get() as u64) << 32 | id.get() as u64),
// this clear color paints over the one set using `Renderer::set_clear_color`.
clear_color: ColorF::new(0.0, 0.0, 0.0, 0.0),
clear_color: webrender::api::ColorF::new(0.0, 0.0, 0.0, 0.0),
allow_advanced_blend_equation: context.is_software(),
clear_caches_with_quads: !context.is_software(),
@ -277,7 +277,7 @@ impl Surface {
let render_reasons = frame.render_reasons();
self.renderer.as_mut().unwrap().set_clear_color(frame.clear_color);
self.renderer.as_mut().unwrap().set_clear_color(frame.clear_color.to_wr());
let mut txn = Transaction::new();
txn.reset_dynamic_properties();
@ -299,7 +299,7 @@ impl Surface {
&mut self.display_list_cache,
);
self.renderer.as_mut().unwrap().set_clear_color(frame.clear_color);
self.renderer.as_mut().unwrap().set_clear_color(frame.clear_color.to_wr());
self.clear_color = Some(frame.clear_color);
txn.set_display_list(frame.id.epoch(), (self.pipeline_id, display_list));
@ -324,7 +324,7 @@ impl Surface {
if let Some(color) = frame.clear_color {
self.clear_color = Some(color);
self.renderer.as_mut().unwrap().set_clear_color(color);
self.renderer.as_mut().unwrap().set_clear_color(color.to_wr());
}
let resized = self.resized;

View File

@ -12,9 +12,7 @@ use std::{
use tracing::span::EnteredSpan;
use webrender::{
api::{
ColorF, DocumentId, DynamicProperties, FontInstanceFlags, FontInstanceKey, FontInstanceOptions, FontKey, FontVariation, PipelineId,
},
api::{DocumentId, DynamicProperties, FontInstanceFlags, FontInstanceKey, FontInstanceOptions, FontKey, FontVariation, PipelineId},
RenderApi, Renderer, Transaction, UploadMethod, VertexUsageHint,
};
@ -36,7 +34,7 @@ use zero_ui_view_api::{
CursorIcon, FocusIndicator, FrameCapture, FrameId, FrameRequest, FrameUpdateRequest, RenderMode, VideoMode, WindowId,
WindowRequest, WindowState, WindowStateAll,
},
DeviceId, Event, ViewProcessGen,
DeviceId, Event, RgbaF, ViewProcessGen,
};
use zero_ui_view_api::dialog as dlg_api;
@ -65,7 +63,7 @@ pub(crate) struct Window {
image_use: ImageUseMap,
display_list_cache: DisplayListCache,
clear_color: Option<ColorF>,
clear_color: Option<RgbaF>,
context: GlContext, // context must be dropped before window.
window: GWindow,
@ -287,7 +285,7 @@ impl Window {
renderer_id: Some((gen.get() as u64) << 32 | id.get() as u64),
// this clear color paints over the one set using `Renderer::set_clear_color`.
clear_color: ColorF::new(0.0, 0.0, 0.0, 0.0),
clear_color: webrender::api::ColorF::new(0.0, 0.0, 0.0, 0.0),
allow_advanced_blend_equation: context.is_software(),
clear_caches_with_quads: !context.is_software(),
@ -1257,7 +1255,7 @@ impl Window {
pub fn render(&mut self, frame: FrameRequest) {
let _scope = tracing::trace_span!("render", ?frame.id).entered();
self.renderer.as_mut().unwrap().set_clear_color(frame.clear_color);
self.renderer.as_mut().unwrap().set_clear_color(frame.clear_color.to_wr());
let mut txn = Transaction::new();
txn.set_root_pipeline(self.pipeline_id);
@ -1283,7 +1281,7 @@ impl Window {
colors: vec![],
});
self.renderer.as_mut().unwrap().set_clear_color(frame.clear_color);
self.renderer.as_mut().unwrap().set_clear_color(frame.clear_color.to_wr());
self.clear_color = Some(frame.clear_color);
txn.set_display_list(frame.id.epoch(), (self.pipeline_id, display_list));
@ -1304,7 +1302,7 @@ impl Window {
if let Some(color) = frame.clear_color {
self.clear_color = Some(color);
self.renderer.as_mut().unwrap().set_clear_color(color);
self.renderer.as_mut().unwrap().set_clear_color(color.to_wr());
}
let resized = self.resized;

View File

@ -274,7 +274,7 @@ mod inspector_window {
inspector::{InspectorActualVars, InstanceItem, WidgetInfoInspectorExt as _},
OnVarArgs,
};
use zero_ui_color::RenderColor;
use zero_ui_color::RgbaF;
use zero_ui_ext_font::{FontStyle, FontWeight};
use zero_ui_ext_input::focus::FOCUS;
use zero_ui_ext_l10n::lang;
@ -501,7 +501,7 @@ mod inspector_window {
let b = Dip::new(16).to_px(factor);
let m = b / Px(2) - a / Px(2);
let color = FrameValue::Value(RenderColor::from(colors::WHITE));
let color = FrameValue::Value(RgbaF::from(colors::WHITE));
frame.push_color(PxRect::new(PxPoint::new(m, Px(0)), PxSize::new(a, b)), color);
frame.push_color(PxRect::new(PxPoint::new(Px(0), m), PxSize::new(b, a)), color);

View File

@ -2,7 +2,7 @@
//!
use zero_ui_app::access::ACCESS_SCROLL_EVENT;
use zero_ui_color::RenderColor;
use zero_ui_color::RgbaF;
use zero_ui_ext_input::focus::FOCUS;
use zero_ui_ext_input::focus::FOCUS_CHANGED_EVENT;
use zero_ui_ext_input::mouse::MouseScrollDelta;
@ -1216,7 +1216,7 @@ pub fn overscroll_node(child: impl UiNode) -> impl UiNode {
offset: 1.0,
color: {
let mut c = color;
c.a = 0.0;
c[3] = 0.0;
c
},
},
@ -1225,8 +1225,8 @@ pub fn overscroll_node(child: impl UiNode) -> impl UiNode {
frame.with_auto_hit_test(false, |frame| {
if !v_rect.size.is_empty() {
let mut color: RenderColor = OVERSCROLL_COLOR_VAR.get().into();
color.a *= (OVERSCROLL_VERTICAL_OFFSET_VAR.get().abs().0).min(1.0);
let mut color: RgbaF = OVERSCROLL_COLOR_VAR.get().into();
color[3] *= (OVERSCROLL_VERTICAL_OFFSET_VAR.get().abs().0).min(1.0);
let stops = stops(color);
let mut radius = v_rect.size;
@ -1243,8 +1243,8 @@ pub fn overscroll_node(child: impl UiNode) -> impl UiNode {
);
}
if !h_rect.size.is_empty() {
let mut color: RenderColor = OVERSCROLL_COLOR_VAR.get().into();
color.a *= (OVERSCROLL_HORIZONTAL_OFFSET_VAR.get().abs().0).min(1.0);
let mut color: RgbaF = OVERSCROLL_COLOR_VAR.get().into();
color[3] *= (OVERSCROLL_HORIZONTAL_OFFSET_VAR.get().abs().0).min(1.0);
let stops = stops(color);
let mut radius = h_rect.size;

View File

@ -107,7 +107,7 @@
pub use zero_ui_color::{
color_scheme_highlight, color_scheme_map, color_scheme_pair, colors, hex, hsl, hsla, hsla_linear_sampler, hsla_sampler, hsv, hsva,
lerp_space, rgb, rgba, rgba_sampler, web_colors, with_lerp_space, ColorPair, ColorScheme, Hsla, Hsva, LerpSpace, MixBlendMode,
PreMulRgba, RenderColor, RenderMixBlendMode, Rgba, COLOR_SCHEME_VAR,
PreMulRgba, RenderMixBlendMode, Rgba, RgbaF, COLOR_SCHEME_VAR,
};
pub use zero_ui_wgt::color_scheme;