diff --git a/components/gfx/display_list/mod.rs b/components/gfx/display_list/mod.rs index b3ebd81d2b8..1aef67246a8 100644 --- a/components/gfx/display_list/mod.rs +++ b/components/gfx/display_list/mod.rs @@ -27,7 +27,7 @@ use azure::azure::AzFloat; use azure::azure_hl::{Color}; use collections::linked_list::{self, LinkedList}; -use geom::{Point2D, Rect, SideOffsets2D, Size2D, Matrix2D}; +use geom::{Matrix2D, Point2D, Rect, SideOffsets2D, Size2D, Matrix4}; use geom::approxeq::ApproxEq; use geom::num::Zero; use libc::uintptr_t; @@ -254,9 +254,7 @@ pub struct StackingContext { pub blend_mode: mix_blend_mode::T, /// A transform to be applied to this stacking context. - /// - /// TODO(pcwalton): 3D transforms. - pub transform: Matrix2D, + pub transform: Matrix4, } impl StackingContext { @@ -266,7 +264,7 @@ impl StackingContext { bounds: &Rect, overflow: &Rect, z_index: i32, - transform: &Matrix2D, + transform: &Matrix4, filters: filter::T, blend_mode: mix_blend_mode::T, layer: Option>) @@ -287,7 +285,7 @@ impl StackingContext { pub fn optimize_and_draw_into_context(&self, paint_context: &mut PaintContext, tile_bounds: &Rect, - transform: &Matrix2D, + transform: &Matrix4, clip_rect: Option<&Rect>) { let transform = transform.mul(&self.transform); let temporary_draw_target = @@ -320,7 +318,10 @@ impl StackingContext { // Set up our clip rect and transform. let old_transform = paint_subcontext.draw_target.get_transform(); - paint_subcontext.draw_target.set_transform(&transform); + let xform_2d = Matrix2D::new(transform.m11, transform.m12, + transform.m21, transform.m22, + transform.m41, transform.m42); + paint_subcontext.draw_target.set_transform(&xform_2d); paint_subcontext.push_clip_if_applicable(); // Steps 1 and 2: Borders and background for the root. @@ -342,7 +343,8 @@ impl StackingContext { positioned_kid.bounds .origin .y - .to_nearest_px() as AzFloat); + .to_nearest_px() as AzFloat, + 0.0); let new_tile_rect = self.compute_tile_rect_for_child_stacking_context(tile_bounds, &**positioned_kid); @@ -390,7 +392,8 @@ impl StackingContext { positioned_kid.bounds .origin .y - .to_nearest_px() as AzFloat); + .to_nearest_px() as AzFloat, + 0.0); let new_tile_rect = self.compute_tile_rect_for_child_stacking_context(tile_bounds, &**positioned_kid); diff --git a/components/gfx/paint_task.rs b/components/gfx/paint_task.rs index 29869f33c14..81385eca7ee 100644 --- a/components/gfx/paint_task.rs +++ b/components/gfx/paint_task.rs @@ -12,7 +12,8 @@ use paint_context::PaintContext; use azure::azure_hl::{SurfaceFormat, Color, DrawTarget, BackendType}; use azure::AzFloat; -use geom::matrix2d::Matrix2D; +use geom::Matrix4; +use geom::matrix::identity; use geom::point::Point2D; use geom::rect::Rect; use geom::size::Size2D; @@ -579,10 +580,11 @@ impl WorkerThread { stacking_context.overflow.origin.y.to_f32_px())); // Apply the translation to paint the tile we want. - let matrix: Matrix2D = Matrix2D::identity(); - let matrix = matrix.scale(scale as AzFloat, scale as AzFloat); + let matrix: Matrix4 = identity(); + let matrix = matrix.scale(scale as AzFloat, scale as AzFloat, 1.0); let matrix = matrix.translate(-tile_bounds.origin.x as AzFloat, - -tile_bounds.origin.y as AzFloat); + -tile_bounds.origin.y as AzFloat, + 0.0); // Clear the buffer. paint_context.clear(); diff --git a/components/layout/display_list_builder.rs b/components/layout/display_list_builder.rs index 1be5d3121a4..f2cf382a23a 100644 --- a/components/layout/display_list_builder.rs +++ b/components/layout/display_list_builder.rs @@ -18,10 +18,12 @@ use fragment::{CoordinateSystem, Fragment, IframeFragmentInfo, ImageFragmentInfo use fragment::{ScannedTextFragmentInfo, SpecificFragmentInfo}; use inline::InlineFlow; use list_item::ListItemFlow; -use model::{self, MaybeAuto, ToGfxMatrix}; +use model::{self, MaybeAuto, ToGfxMatrix, ToAu}; use table_cell::CollapsedBordersForCell; -use geom::{Matrix2D, Point2D, Rect, Size2D, SideOffsets2D}; +use geom::{Point2D, Rect, Size2D, SideOffsets2D}; +use geom::matrix::identity; +use geom::Matrix4; use gfx_traits::color; use gfx::display_list::{BLUR_INFLATION_FACTOR, BaseDisplayItem, BorderDisplayItem}; use gfx::display_list::{BorderRadii, BoxShadowClipMode, BoxShadowDisplayItem, ClippingRegion}; @@ -40,11 +42,12 @@ use std::cmp; use std::default::Default; use std::iter::repeat; use std::sync::Arc; +use std::f32; use style::computed_values::filter::Filter; -use style::computed_values::transform::ComputedMatrix; use style::computed_values::{background_attachment, background_clip, background_origin, background_repeat, background_size}; -use style::computed_values::{border_style, image_rendering, overflow_x, position, visibility}; +use style::computed_values::{border_style, image_rendering, overflow_x, position, + visibility, transform}; use style::properties::ComputedValues; use style::properties::style_structs::Border; use style::values::RGBA; @@ -1139,17 +1142,57 @@ impl FragmentDisplayListBuilding for Fragment { .relative_containing_block_mode, CoordinateSystem::Parent); - let transform_origin = self.style().get_effects().transform_origin; - let transform_origin = - Point2D(model::specified(transform_origin.horizontal, - border_box.size.width).to_f32_px(), - model::specified(transform_origin.vertical, - border_box.size.height).to_f32_px()); - let transform = self.style().get_effects().transform - .unwrap_or(ComputedMatrix::identity()).to_gfx_matrix(&border_box.size); + let mut transform = identity(); - let transform = Matrix2D::identity().translate(transform_origin.x, transform_origin.y) - .mul(&transform).translate(-transform_origin.x, -transform_origin.y); + if let Some(ref operations) = self.style().get_effects().transform { + let transform_origin = self.style().get_effects().transform_origin; + let transform_origin = + Point2D(model::specified(transform_origin.horizontal, + border_box.size.width).to_f32_px(), + model::specified(transform_origin.vertical, + border_box.size.height).to_f32_px()); + + let pre_transform = Matrix4::create_translation(transform_origin.x, + transform_origin.y, + 0.0); + let post_transform = Matrix4::create_translation(-transform_origin.x, + -transform_origin.y, + 0.0); + + for operation in operations { + let matrix = match operation { + &transform::ComputedOperation::Rotate(ax, ay, az, theta) => { + let theta = f32::consts::PI_2 - theta.radians(); + let transform = Matrix4::create_rotation(ax, ay, az, theta); + pre_transform.mul(&transform).mul(&post_transform) + } + &transform::ComputedOperation::Perspective(d) => { + let transform = Matrix4::create_perspective(d.to_f32_px()); + pre_transform.mul(&transform).mul(&post_transform) + } + &transform::ComputedOperation::Scale(sx, sy, sz) => { + let transform = Matrix4::create_scale(sx, sy, sz); + pre_transform.mul(&transform).mul(&post_transform) + } + &transform::ComputedOperation::Translate(tx, ty, tz) => { + let tx = tx.to_au(border_box.size.width).to_f32_px(); + let ty = ty.to_au(border_box.size.height).to_f32_px(); + let tz = tz.to_f32_px(); + Matrix4::create_translation(tx, ty, tz) + } + &transform::ComputedOperation::Matrix(m) => { + let transform = m.to_gfx_matrix(&border_box.size); + pre_transform.mul(&transform).mul(&post_transform) + } + &transform::ComputedOperation::Skew(sx, sy) => { + let transform = Matrix4::create_skew(sx, sy); + pre_transform.mul(&transform).mul(&post_transform) + } + }; + + transform = transform.mul(&matrix); + } + } // FIXME(pcwalton): Is this vertical-writing-direction-safe? let margin = self.margin.to_physical(base_flow.writing_mode); diff --git a/components/layout/layout_task.rs b/components/layout/layout_task.rs index b0ed2bc3c64..c12940904c3 100644 --- a/components/layout/layout_task.rs +++ b/components/layout/layout_task.rs @@ -27,7 +27,7 @@ use azure::azure::AzColor; use canvas_traits::CanvasMsg; use encoding::EncodingRef; use encoding::all::UTF_8; -use geom::matrix2d::Matrix2D; +use geom::matrix; use geom::point::Point2D; use geom::rect::Rect; use geom::scale_factor::ScaleFactor; @@ -854,7 +854,7 @@ impl LayoutTask { &origin, &origin, 0, - &Matrix2D::identity(), + &matrix::identity(), filter::T::new(Vec::new()), mix_blend_mode::T::normal, Some(paint_layer))); diff --git a/components/layout/model.rs b/components/layout/model.rs index 10c02e9964e..87e4d3cf3db 100644 --- a/components/layout/model.rs +++ b/components/layout/model.rs @@ -8,7 +8,7 @@ use fragment::Fragment; -use geom::{Matrix2D, SideOffsets2D, Size2D}; +use geom::{Matrix4, SideOffsets2D, Size2D}; use std::cmp::{max, min}; use std::fmt; use style::computed_values::transform::ComputedMatrix; @@ -426,21 +426,24 @@ pub fn padding_from_style(style: &ComputedValues, containing_block_inline_size: } pub trait ToGfxMatrix { - fn to_gfx_matrix(&self, containing_size: &Size2D) -> Matrix2D; + fn to_gfx_matrix(&self, containing_size: &Size2D) -> Matrix4; } impl ToGfxMatrix for ComputedMatrix { - fn to_gfx_matrix(&self, containing_size: &Size2D) -> Matrix2D { - Matrix2D::new(self.m11 as f32, - self.m12 as f32, - self.m21 as f32, - self.m22 as f32, - self.m31.to_au(containing_size.width).to_f32_px(), - self.m32.to_au(containing_size.height).to_f32_px()) + fn to_gfx_matrix(&self, containing_size: &Size2D) -> Matrix4 { + Matrix4 { + m11: self.m11 as f32, m12: self.m12 as f32, m13: self.m13 as f32, m14: self.m14 as f32, + m21: self.m21 as f32, m22: self.m22 as f32, m23: self.m23 as f32, m24: self.m24 as f32, + m31: self.m31 as f32, m32: self.m32 as f32, m33: self.m33 as f32, m34: self.m34 as f32, + m41: self.m41.to_au(containing_size.width).to_f32_px(), + m42: self.m42.to_au(containing_size.height).to_f32_px(), + m43: self.m43 as f32, + m44: self.m44 as f32 + } } } -trait ToAu { +pub trait ToAu { fn to_au(&self, containing_size: Au) -> Au; } diff --git a/components/servo/Cargo.lock b/components/servo/Cargo.lock index be5dd60b233..c311a09ccc7 100644 --- a/components/servo/Cargo.lock +++ b/components/servo/Cargo.lock @@ -357,7 +357,7 @@ dependencies = [ [[package]] name = "geom" version = "0.1.0" -source = "git+https://github.com/servo/rust-geom#c4bdb1ef8f4915ae636eb752b103f69246b50304" +source = "git+https://github.com/servo/rust-geom#270d0246b79fbf86fc2938c4952cae74e4025fcf" dependencies = [ "log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/components/style/properties.mako.rs b/components/style/properties.mako.rs index 69d14fad990..ed554dff4a5 100644 --- a/components/style/properties.mako.rs +++ b/components/style/properties.mako.rs @@ -3100,104 +3100,49 @@ pub mod longhands { use values::computed::{ToComputedValue, Context}; use cssparser::ToCss; - use std::f32; - use std::ops::Mul; use std::fmt; use util::geometry::Au; pub mod computed_value { use values::CSSFloat; use values::computed; - - use std::ops::Mul; + use values::specified; #[derive(Clone, Copy, Debug, PartialEq)] pub struct ComputedMatrix { - pub m11: CSSFloat, pub m12: CSSFloat, - pub m21: CSSFloat, pub m22: CSSFloat, - pub m31: computed::LengthAndPercentage, pub m32: computed::LengthAndPercentage, + pub m11: CSSFloat, pub m12: CSSFloat, pub m13: CSSFloat, pub m14: CSSFloat, + pub m21: CSSFloat, pub m22: CSSFloat, pub m23: CSSFloat, pub m24: CSSFloat, + pub m31: CSSFloat, pub m32: CSSFloat, pub m33: CSSFloat, pub m34: CSSFloat, + pub m41: computed::LengthAndPercentage, + pub m42: computed::LengthAndPercentage, + pub m43: CSSFloat, + pub m44: CSSFloat, } - impl Mul for ComputedMatrix { - type Output = ComputedMatrix; - - fn mul(self, other: ComputedMatrix) -> ComputedMatrix { - ComputedMatrix { - m11: self.m11*other.m11 + self.m12*other.m21, - m12: self.m11*other.m12 + self.m12*other.m22, - m21: self.m21*other.m11 + self.m22*other.m21, - m22: self.m21*other.m12 + self.m22*other.m22, - m31: self.m31.clone()*other.m11 + self.m32.clone()*other.m21 + other.m31, - m32: self.m31*other.m12 + self.m32*other.m22 + other.m32, - } - } + #[derive(Clone, Debug, PartialEq)] + pub enum ComputedOperation { + Matrix(ComputedMatrix), + Skew(CSSFloat, CSSFloat), + Translate(computed::LengthAndPercentage, + computed::LengthAndPercentage, + computed::Length), + Scale(CSSFloat, CSSFloat, CSSFloat), + Rotate(CSSFloat, CSSFloat, CSSFloat, specified::Angle), + Perspective(computed::Length), } - impl ComputedMatrix { - #[inline] - fn new(m11: CSSFloat, - m12: CSSFloat, - m21: CSSFloat, - m22: CSSFloat, - m31: computed::LengthAndPercentage, - m32: computed::LengthAndPercentage) - -> ComputedMatrix { - ComputedMatrix { - m11: m11, m12: m12, - m21: m21, m22: m22, - m31: m31, m32: m32, - } - } - - #[inline] - pub fn identity() -> ComputedMatrix { - ComputedMatrix { - m11: 1.0, m12: 0.0, - m21: 0.0, m22: 1.0, - m31: computed::LengthAndPercentage::zero(), - m32: computed::LengthAndPercentage::zero(), - } - } - - pub fn scale(&mut self, sx: CSSFloat, sy: CSSFloat) { - *self = ComputedMatrix::new(sx, 0.0, - 0.0, sy, - computed::LengthAndPercentage::zero(), - computed::LengthAndPercentage::zero()) * - (*self).clone() - } - - pub fn skew(&mut self, sx: CSSFloat, sy: CSSFloat) { - *self = ComputedMatrix::new(1.0, sx, - sy, 1.0, - computed::LengthAndPercentage::zero(), - computed::LengthAndPercentage::zero()) * - (*self).clone() - } - - pub fn translate(&mut self, - tx: computed::LengthAndPercentage, - ty: computed::LengthAndPercentage) { - *self = ComputedMatrix::new(1.0, 0.0, 0.0, 1.0, tx, ty) * (*self).clone() - } - - pub fn rotate(&mut self, theta: CSSFloat) { - *self = ComputedMatrix::new(theta.cos(), -theta.sin(), - theta.sin(), theta.cos(), - computed::LengthAndPercentage::zero(), - computed::LengthAndPercentage::zero()) * - (*self).clone() - } - } - - pub type T = Option; + pub type T = Option>; } #[derive(Clone, Debug, PartialEq)] pub struct SpecifiedMatrix { - m11: CSSFloat, m12: CSSFloat, - m21: CSSFloat, m22: CSSFloat, - m31: specified::LengthAndPercentage, m32: specified::LengthAndPercentage, + m11: CSSFloat, m12: CSSFloat, m13: CSSFloat, m14: CSSFloat, + m21: CSSFloat, m22: CSSFloat, m23: CSSFloat, m24: CSSFloat, + m31: CSSFloat, m32: CSSFloat, m33: CSSFloat, m34: CSSFloat, + m41: specified::LengthAndPercentage, + m42: specified::LengthAndPercentage, + m43: specified::Length, + m44: CSSFloat, } impl ToCss for SpecifiedMatrix { @@ -3207,38 +3152,6 @@ pub mod longhands { } } - impl Mul for SpecifiedMatrix { - type Output = SpecifiedMatrix; - - fn mul(self, other: SpecifiedMatrix) -> SpecifiedMatrix { - SpecifiedMatrix { - m11: self.m11*other.m11 + self.m12*other.m21, - m12: self.m11*other.m12 + self.m12*other.m22, - m21: self.m21*other.m11 + self.m22*other.m21, - m22: self.m21*other.m12 + self.m22*other.m22, - m31: self.m31.clone()*other.m11 + self.m32.clone()*other.m21 + other.m31, - m32: self.m31*other.m12 + self.m32*other.m22 + other.m32, - } - } - } - - impl SpecifiedMatrix { - #[inline] - fn new(m11: CSSFloat, - m12: CSSFloat, - m21: CSSFloat, - m22: CSSFloat, - m31: specified::LengthAndPercentage, - m32: specified::LengthAndPercentage) - -> SpecifiedMatrix { - SpecifiedMatrix { - m11: m11, m12: m12, - m21: m21, m22: m22, - m31: m31, m32: m32, - } - } - } - fn parse_two_lengths_or_percentages(input: &mut Parser) -> Result<(specified::LengthAndPercentage, specified::LengthAndPercentage),()> { @@ -3262,10 +3175,13 @@ pub mod longhands { #[derive(Clone, Debug, PartialEq)] enum SpecifiedOperation { Matrix(SpecifiedMatrix), - Translate(specified::LengthAndPercentage, specified::LengthAndPercentage), - Scale(CSSFloat, CSSFloat), - Rotate(specified::Angle), Skew(CSSFloat, CSSFloat), + Translate(specified::LengthAndPercentage, + specified::LengthAndPercentage, + specified::Length), + Scale(CSSFloat, CSSFloat, CSSFloat), + Rotate(CSSFloat, CSSFloat, CSSFloat, specified::Angle), + Perspective(specified::Length), } impl ToCss for SpecifiedOperation { @@ -3318,23 +3234,54 @@ pub mod longhands { if values.len() != 6 { return Err(()) } - let (tx, ty) = + let (tx, ty, tz) = (specified::Length::Absolute(Au::from_f32_px(values[4])), - specified::Length::Absolute(Au::from_f32_px(values[5]))); + specified::Length::Absolute(Au::from_f32_px(values[5])), + specified::Length::Absolute(Au(0))); let (tx, ty) = (specified::LengthAndPercentage::from_length(tx), specified::LengthAndPercentage::from_length(ty)); result.push(SpecifiedOperation::Matrix( - SpecifiedMatrix::new(values[0], values[1], - values[2], values[3], - tx, ty))); + SpecifiedMatrix { + m11: values[0], m12: values[1], m13: 0.0, m14: 0.0, + m21: values[2], m22: values[3], m23: 0.0, m24: 0.0, + m31: 0.0, m32: 0.0, m33: 1.0, m34: 0.0, + m41: tx, m42: ty, m43: tz, m44: 1.0 + })); + Ok(()) + })) + }, + "matrix3d" => { + try!(input.parse_nested_block(|input| { + let values = try!(input.parse_comma_separated(|input| { + input.expect_number() + })); + if values.len() != 16 { + return Err(()) + } + let (tx, ty, tz) = + (specified::Length::Absolute(Au::from_f32_px(values[12])), + specified::Length::Absolute(Au::from_f32_px(values[13])), + specified::Length::Absolute(Au::from_f32_px(values[14]))); + let (tx, ty) = + (specified::LengthAndPercentage::from_length(tx), + specified::LengthAndPercentage::from_length(ty)); + result.push(SpecifiedOperation::Matrix( + SpecifiedMatrix { + m11: values[ 0], m12: values[ 1], m13: values[ 2], m14: values[ 3], + m21: values[ 4], m22: values[ 5], m23: values[ 6], m24: values[ 7], + m31: values[ 8], m32: values[ 9], m33: values[10], m34: values[11], + m41: tx, m42: ty, m43: tz, m44: values[15] + })); Ok(()) })) }, "translate" => { try!(input.parse_nested_block(|input| { let (tx, ty) = try!(parse_two_lengths_or_percentages(input)); - result.push(SpecifiedOperation::Translate(tx, ty)); + result.push(SpecifiedOperation::Translate(tx, + ty, + specified::Length::Absolute(Au(0)))); Ok(()) })) }, @@ -3344,7 +3291,8 @@ pub mod longhands { result.push(SpecifiedOperation::Translate( specified::LengthAndPercentage::from_length_or_percentage( &tx), - specified::LengthAndPercentage::zero())); + specified::LengthAndPercentage::zero(), + specified::Length::Absolute(Au(0)))); Ok(()) })) }, @@ -3354,35 +3302,114 @@ pub mod longhands { result.push(SpecifiedOperation::Translate( specified::LengthAndPercentage::zero(), specified::LengthAndPercentage::from_length_or_percentage( - &ty))); + &ty), + specified::Length::Absolute(Au(0)))); Ok(()) })) }, + "translatez" => { + try!(input.parse_nested_block(|input| { + let tz = try!(specified::Length::parse(input)); + result.push(SpecifiedOperation::Translate( + specified::LengthAndPercentage::zero(), + specified::LengthAndPercentage::zero(), + tz)); + Ok(()) + })) + }, + "translate3d" => { + try!(input.parse_nested_block(|input| { + let tx = try!(specified::LengthOrPercentage::parse(input)); + try!(input.expect_comma()); + let ty = try!(specified::LengthOrPercentage::parse(input)); + try!(input.expect_comma()); + let tz = try!(specified::Length::parse(input)); + result.push(SpecifiedOperation::Translate( + specified::LengthAndPercentage::from_length_or_percentage(&tx), + specified::LengthAndPercentage::from_length_or_percentage(&ty), + tz)); + Ok(()) + })) + + }, "scale" => { try!(input.parse_nested_block(|input| { let (sx, sy) = try!(parse_two_floats(input)); - result.push(SpecifiedOperation::Scale(sx, sy)); + result.push(SpecifiedOperation::Scale(sx, sy, 1.0)); Ok(()) })) }, "scalex" => { try!(input.parse_nested_block(|input| { let sx = try!(input.expect_number()); - result.push(SpecifiedOperation::Scale(sx, 1.0)); + result.push(SpecifiedOperation::Scale(sx, 1.0, 1.0)); Ok(()) })) }, "scaley" => { try!(input.parse_nested_block(|input| { let sy = try!(input.expect_number()); - result.push(SpecifiedOperation::Scale(1.0, sy)); + result.push(SpecifiedOperation::Scale(1.0, sy, 1.0)); + Ok(()) + })) + }, + "scalez" => { + try!(input.parse_nested_block(|input| { + let sz = try!(input.expect_number()); + result.push(SpecifiedOperation::Scale(1.0, 1.0, sz)); + Ok(()) + })) + }, + "scale3d" => { + try!(input.parse_nested_block(|input| { + let sx = try!(input.expect_number()); + try!(input.expect_comma()); + let sy = try!(input.expect_number()); + try!(input.expect_comma()); + let sz = try!(input.expect_number()); + result.push(SpecifiedOperation::Scale(sx, sy, sz)); Ok(()) })) }, "rotate" => { try!(input.parse_nested_block(|input| { let theta = try!(specified::Angle::parse(input)); - result.push(SpecifiedOperation::Rotate(theta)); + result.push(SpecifiedOperation::Rotate(0.0, 0.0, 1.0, theta)); + Ok(()) + })) + }, + "rotatex" => { + try!(input.parse_nested_block(|input| { + let theta = try!(specified::Angle::parse(input)); + result.push(SpecifiedOperation::Rotate(1.0, 0.0, 0.0, theta)); + Ok(()) + })) + }, + "rotatey" => { + try!(input.parse_nested_block(|input| { + let theta = try!(specified::Angle::parse(input)); + result.push(SpecifiedOperation::Rotate(0.0, 1.0, 0.0, theta)); + Ok(()) + })) + }, + "rotatez" => { + try!(input.parse_nested_block(|input| { + let theta = try!(specified::Angle::parse(input)); + result.push(SpecifiedOperation::Rotate(0.0, 0.0, 1.0, theta)); + Ok(()) + })) + }, + "rotate3d" => { + try!(input.parse_nested_block(|input| { + let ax = try!(input.expect_number()); + try!(input.expect_comma()); + let ay = try!(input.expect_number()); + try!(input.expect_comma()); + let az = try!(input.expect_number()); + try!(input.expect_comma()); + let theta = try!(specified::Angle::parse(input)); + // TODO(gw): Check the axis can be normalized!! + result.push(SpecifiedOperation::Rotate(ax, ay, az, theta)); Ok(()) })) }, @@ -3406,6 +3433,13 @@ pub mod longhands { result.push(SpecifiedOperation::Skew(1.0, sy)); Ok(()) })) + }, + "perspective" => { + try!(input.parse_nested_block(|input| { + let d = try!(specified::Length::parse(input)); + result.push(SpecifiedOperation::Perspective(d)); + Ok(()) + })) } _ => return Err(()) } @@ -3427,32 +3461,41 @@ pub mod longhands { return None } - let mut result = computed_value::ComputedMatrix::identity(); + let mut result = vec!(); for operation in self.0.iter() { match *operation { SpecifiedOperation::Matrix(ref matrix) => { - result = computed_value::ComputedMatrix { - m11: matrix.m11, m12: matrix.m12, - m21: matrix.m21, m22: matrix.m22, - m31: matrix.m31.to_computed_value(context), - m32: matrix.m32.to_computed_value(context), - } * result + let m = computed_value::ComputedMatrix { + m11: matrix.m11, m12: matrix.m12, m13: matrix.m13, m14: matrix.m14, + m21: matrix.m21, m22: matrix.m22, m23: matrix.m23, m24: matrix.m24, + m31: matrix.m31, m32: matrix.m32, m33: matrix.m33, m34: matrix.m34, + m41: matrix.m41.to_computed_value(context), + m42: matrix.m42.to_computed_value(context), + m43: matrix.m43.to_computed_value(context).to_f32_px(), + m44: matrix.m44 + }; + result.push(computed_value::ComputedOperation::Matrix(m)); } - SpecifiedOperation::Translate(ref tx, ref ty) => { - result.translate(tx.to_computed_value(context), - ty.to_computed_value(context)) + SpecifiedOperation::Translate(ref tx, ref ty, ref tz) => { + result.push(computed_value::ComputedOperation::Translate(tx.to_computed_value(context), + ty.to_computed_value(context), + tz.to_computed_value(context))); } - SpecifiedOperation::Scale(sx, sy) => { - result.scale(sx, sy) + SpecifiedOperation::Scale(sx, sy, sz) => { + result.push(computed_value::ComputedOperation::Scale(sx, sy, sz)); } - SpecifiedOperation::Rotate(ref theta) => { - result.rotate(f32::consts::PI_2 - theta.radians()); + SpecifiedOperation::Rotate(ax, ay, az, theta) => { + result.push(computed_value::ComputedOperation::Rotate(ax, ay, az, theta)); } SpecifiedOperation::Skew(sx, sy) => { - result.skew(sx, sy) + result.push(computed_value::ComputedOperation::Skew(sx, sy)); } - } + SpecifiedOperation::Perspective(d) => { + result.push(computed_value::ComputedOperation::Perspective(d.to_computed_value(context))); + } + }; } + Some(result) } } diff --git a/ports/cef/Cargo.lock b/ports/cef/Cargo.lock index 922b2382558..a97641bafdb 100644 --- a/ports/cef/Cargo.lock +++ b/ports/cef/Cargo.lock @@ -366,7 +366,7 @@ dependencies = [ [[package]] name = "geom" version = "0.1.0" -source = "git+https://github.com/servo/rust-geom#c4bdb1ef8f4915ae636eb752b103f69246b50304" +source = "git+https://github.com/servo/rust-geom#270d0246b79fbf86fc2938c4952cae74e4025fcf" dependencies = [ "log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/ports/gonk/Cargo.lock b/ports/gonk/Cargo.lock index ea13428a8e0..3a6f3226c13 100644 --- a/ports/gonk/Cargo.lock +++ b/ports/gonk/Cargo.lock @@ -345,7 +345,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "geom" version = "0.1.0" -source = "git+https://github.com/servo/rust-geom#c4bdb1ef8f4915ae636eb752b103f69246b50304" +source = "git+https://github.com/servo/rust-geom#270d0246b79fbf86fc2938c4952cae74e4025fcf" dependencies = [ "log 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "num 0.1.24 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/tests/ref/basic.list b/tests/ref/basic.list index 4c3679508da..dab2eb15dcc 100644 --- a/tests/ref/basic.list +++ b/tests/ref/basic.list @@ -312,6 +312,7 @@ flaky_cpu == linebreak_simple_a.html linebreak_simple_b.html == text_transform_lowercase_a.html text_transform_lowercase_ref.html == text_transform_none_a.html text_transform_none_ref.html == text_transform_uppercase_a.html text_transform_uppercase_ref.html +== transform_3d.html transform_3d_ref.html == transform_simple_a.html transform_simple_ref.html == transform_stacking_context_a.html transform_stacking_context_ref.html == upper_id_attr.html upper_id_attr_ref.html diff --git a/tests/ref/transform_3d.html b/tests/ref/transform_3d.html new file mode 100644 index 00000000000..2d2880c7d4d --- /dev/null +++ b/tests/ref/transform_3d.html @@ -0,0 +1,127 @@ + + + + + + +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ + diff --git a/tests/ref/transform_3d_ref.html b/tests/ref/transform_3d_ref.html new file mode 100644 index 00000000000..2b3b8a2e1a1 --- /dev/null +++ b/tests/ref/transform_3d_ref.html @@ -0,0 +1,122 @@ + + + + + + +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +
+
+
+
+ +