summaryrefslogtreecommitdiffstats
path: root/gfx/wr/examples/animation.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 09:22:09 +0000
commit43a97878ce14b72f0981164f87f2e35e14151312 (patch)
tree620249daf56c0258faa40cbdcf9cfba06de2a846 /gfx/wr/examples/animation.rs
parentInitial commit. (diff)
downloadfirefox-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.rs258
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);
+}