diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 09:22:09 +0000 |
commit | 43a97878ce14b72f0981164f87f2e35e14151312 (patch) | |
tree | 620249daf56c0258faa40cbdcf9cfba06de2a846 /gfx/wr/examples/animation.rs | |
parent | Initial commit. (diff) | |
download | firefox-43a97878ce14b72f0981164f87f2e35e14151312.tar.xz firefox-43a97878ce14b72f0981164f87f2e35e14151312.zip |
Adding upstream version 110.0.1.upstream/110.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'gfx/wr/examples/animation.rs')
-rw-r--r-- | gfx/wr/examples/animation.rs | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/gfx/wr/examples/animation.rs b/gfx/wr/examples/animation.rs new file mode 100644 index 0000000000..7d24b6542e --- /dev/null +++ b/gfx/wr/examples/animation.rs @@ -0,0 +1,258 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +//! This example creates a 200x200 white rect and allows the user to move it +//! around by using the arrow keys and rotate with '<'/'>'. +//! It does this by using the animation API. + +//! The example also features seamless opaque/transparent split of a +//! rounded cornered rectangle, which is done automatically during the +//! scene building for render optimization. + +extern crate euclid; +extern crate gleam; +extern crate glutin; +extern crate webrender; +extern crate winit; + +#[path = "common/boilerplate.rs"] +mod boilerplate; + +use crate::boilerplate::{Example, HandyDandyRectBuilder}; +use euclid::Angle; +use webrender::api::*; +use webrender::render_api::*; +use webrender::api::units::*; + + +struct App { + property_key0: PropertyBindingKey<LayoutTransform>, + property_key1: PropertyBindingKey<LayoutTransform>, + property_key2: PropertyBindingKey<LayoutTransform>, + opacity_key: PropertyBindingKey<f32>, + opacity: f32, + angle0: f32, + angle1: f32, + angle2: f32, +} + +impl App { + fn add_rounded_rect( + &mut self, + bounds: LayoutRect, + color: ColorF, + builder: &mut DisplayListBuilder, + pipeline_id: PipelineId, + property_key: PropertyBindingKey<LayoutTransform>, + opacity_key: Option<PropertyBindingKey<f32>>, + spatial_tree_item_key: SpatialTreeItemKey, + ) { + let filters = match opacity_key { + Some(opacity_key) => { + vec![ + FilterOp::Opacity(PropertyBinding::Binding(opacity_key, self.opacity), self.opacity), + ] + } + None => { + vec![] + } + }; + + let spatial_id = builder.push_reference_frame( + bounds.min, + SpatialId::root_scroll_node(pipeline_id), + TransformStyle::Flat, + PropertyBinding::Binding(property_key, LayoutTransform::identity()), + ReferenceFrameKind::Transform { + is_2d_scale_translation: false, + should_snap: false, + paired_with_perspective: false, + }, + spatial_tree_item_key, + ); + + builder.push_simple_stacking_context_with_filters( + LayoutPoint::zero(), + spatial_id, + PrimitiveFlags::IS_BACKFACE_VISIBLE, + &filters, + &[], + &[] + ); + + let space_and_clip = SpaceAndClipInfo { + spatial_id, + clip_chain_id: ClipChainId::INVALID, + }; + let clip_bounds = LayoutRect::from_size(bounds.size()); + let complex_clip = ComplexClipRegion { + rect: clip_bounds, + radii: BorderRadius::uniform(30.0), + mode: ClipMode::Clip, + }; + let clip_id = builder.define_clip_rounded_rect( + space_and_clip.spatial_id, + complex_clip, + ); + let clip_chain_id = builder.define_clip_chain(None, [clip_id]); + + // Fill it with a white rect + builder.push_rect( + &CommonItemProperties::new( + LayoutRect::from_size(bounds.size()), + SpaceAndClipInfo { + spatial_id, + clip_chain_id, + } + ), + LayoutRect::from_size(bounds.size()), + color, + ); + + builder.pop_stacking_context(); + builder.pop_reference_frame(); + } +} + +impl Example for App { + const WIDTH: u32 = 2048; + const HEIGHT: u32 = 1536; + + fn render( + &mut self, + _api: &mut RenderApi, + builder: &mut DisplayListBuilder, + _txn: &mut Transaction, + _device_size: DeviceIntSize, + pipeline_id: PipelineId, + _document_id: DocumentId, + ) { + let opacity_key = self.opacity_key; + + let bounds = (150, 150).to(250, 250); + let key0 = self.property_key0; + self.add_rounded_rect( + bounds, + ColorF::new(1.0, 0.0, 0.0, 0.5), + builder, + pipeline_id, + key0, + Some(opacity_key), + SpatialTreeItemKey::new(0, 0) + ); + + let bounds = (400, 400).to(600, 600); + let key1 = self.property_key1; + self.add_rounded_rect( + bounds, + ColorF::new(0.0, 1.0, 0.0, 0.5), + builder, + pipeline_id, + key1, + None, + SpatialTreeItemKey::new(0, 1) + ); + + let bounds = (200, 500).to(350, 580); + let key2 = self.property_key2; + self.add_rounded_rect( + bounds, + ColorF::new(0.0, 0.0, 1.0, 0.5), + builder, + pipeline_id, + key2, + None, + SpatialTreeItemKey::new(0, 2) + ); + } + + fn on_event( + &mut self, + win_event: winit::event::WindowEvent, + _window: &winit::window::Window, + api: &mut RenderApi, + document_id: DocumentId + ) -> bool { + let mut rebuild_display_list = false; + + match win_event { + winit::event::WindowEvent::KeyboardInput { + input: winit::event::KeyboardInput { + state: winit::event::ElementState::Pressed, + virtual_keycode: Some(key), + .. + }, + .. + } => { + let (delta_angle, delta_opacity) = match key { + winit::event::VirtualKeyCode::Down => (0.0, -0.1), + winit::event::VirtualKeyCode::Up => (0.0, 0.1), + winit::event::VirtualKeyCode::Right => (1.0, 0.0), + winit::event::VirtualKeyCode::Left => (-1.0, 0.0), + winit::event::VirtualKeyCode::R => { + rebuild_display_list = true; + (0.0, 0.0) + } + _ => return false, + }; + // Update the transform based on the keyboard input and push it to + // webrender using the generate_frame API. This will recomposite with + // the updated transform. + self.opacity += delta_opacity; + self.angle0 += delta_angle * 0.1; + self.angle1 += delta_angle * 0.2; + self.angle2 -= delta_angle * 0.15; + let xf0 = LayoutTransform::rotation(0.0, 0.0, 1.0, Angle::radians(self.angle0)); + let xf1 = LayoutTransform::rotation(0.0, 0.0, 1.0, Angle::radians(self.angle1)); + let xf2 = LayoutTransform::rotation(0.0, 0.0, 1.0, Angle::radians(self.angle2)); + let mut txn = Transaction::new(); + txn.reset_dynamic_properties(); + txn.append_dynamic_properties( + DynamicProperties { + transforms: vec![ + PropertyValue { + key: self.property_key0, + value: xf0, + }, + PropertyValue { + key: self.property_key1, + value: xf1, + }, + PropertyValue { + key: self.property_key2, + value: xf2, + }, + ], + floats: vec![ + PropertyValue { + key: self.opacity_key, + value: self.opacity, + } + ], + colors: vec![], + }, + ); + txn.generate_frame(0, RenderReasons::empty()); + api.send_transaction(document_id, txn); + } + _ => (), + } + + rebuild_display_list + } +} + +fn main() { + let mut app = App { + property_key0: PropertyBindingKey::new(42), // arbitrary magic number + property_key1: PropertyBindingKey::new(44), // arbitrary magic number + property_key2: PropertyBindingKey::new(45), // arbitrary magic number + opacity_key: PropertyBindingKey::new(43), + opacity: 0.5, + angle0: 0.0, + angle1: 0.0, + angle2: 0.0, + }; + boilerplate::main_wrapper(&mut app, None); +} |