First step towards 3d transforms.

* Add parser support for 3d transforms.
 * Change ComputedMatrix to a representation that suits interpolation.
 * Switch stacking contexts to use 4x4 matrices.

The transforms themselves are still converted to 2d and handled by azure for now, but this is a small standalone part that can be landed now to make it easier to review.
This commit is contained in:
Glenn Watson 2015-05-29 08:31:05 +10:00
parent 09f2977cc9
commit f47ba6fd33
12 changed files with 530 additions and 186 deletions

View file

@ -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);

View file

@ -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)));

View file

@ -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<Au>) -> Matrix2D<f32>;
fn to_gfx_matrix(&self, containing_size: &Size2D<Au>) -> Matrix4<f32>;
}
impl ToGfxMatrix for ComputedMatrix {
fn to_gfx_matrix(&self, containing_size: &Size2D<Au>) -> Matrix2D<f32> {
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<Au>) -> Matrix4<f32> {
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;
}