Implement enough of 3d transforms spec to run the CSS FPS demo.

This commit is contained in:
Glenn Watson 2015-06-18 13:06:31 +10:00
parent d86c587925
commit 39ddbbb0e1
19 changed files with 894 additions and 145 deletions

View file

@ -56,10 +56,10 @@ use std::cmp::{max, min};
use std::fmt;
use std::sync::Arc;
use style::computed_values::{border_collapse, box_sizing, display, float, overflow_x, overflow_y};
use style::computed_values::{position, text_align};
use style::computed_values::{transform, transform_style, position, text_align};
use style::properties::ComputedValues;
use style::values::computed::{LengthOrPercentage, LengthOrPercentageOrAuto};
use style::values::computed::{LengthOrPercentageOrNone};
use style::values::computed::{LengthOrNone, LengthOrPercentageOrNone};
use util::geometry::{Au, MAX_AU, MAX_RECT};
use util::logical_geometry::{LogicalPoint, LogicalRect, LogicalSize, WritingMode};
use util::opts;
@ -617,6 +617,33 @@ impl BlockFlow {
}
}
pub fn transform_requires_layer(&self) -> bool {
// Check if the transform matrix is 2D or 3D
if let Some(ref transform_list) = self.fragment.style().get_effects().transform {
for transform in transform_list {
match transform {
&transform::ComputedOperation::Perspective(..) => {
return true;
}
&transform::ComputedOperation::Matrix(m) => {
// See http://dev.w3.org/csswg/css-transforms/#2d-matrix
if m.m31 != 0.0 || m.m32 != 0.0 ||
m.m13 != 0.0 || m.m23 != 0.0 ||
m.m43 != 0.0 || m.m14 != 0.0 ||
m.m24 != 0.0 || m.m34 != 0.0 ||
m.m33 != 1.0 || m.m44 != 1.0 {
return true;
}
}
_ => {}
}
}
}
// Neither perspective nor transform present
false
}
/// Compute the actual inline size and position for this block.
pub fn compute_used_inline_size(&mut self,
layout_context: &LayoutContext,
@ -1676,6 +1703,16 @@ impl Flow for BlockFlow {
self.base.stacking_relative_position_of_display_port = MAX_RECT;
}
// This flow needs a layer if it has a 3d transform, or provides perspective
// to child layers. See http://dev.w3.org/csswg/css-transforms/#3d-rendering-contexts.
let transform_style = self.fragment.style().get_used_transform_style();
let has_3d_transform = self.transform_requires_layer();
let has_perspective = self.fragment.style().get_effects().perspective != LengthOrNone::None;
if has_3d_transform || has_perspective {
self.base.flags.insert(NEEDS_LAYER);
}
if self.base.flags.contains(IS_ABSOLUTELY_POSITIONED) {
let position_start = self.base.position.start.to_physical(self.base.writing_mode,
container_size);
@ -1818,6 +1855,16 @@ impl Flow for BlockFlow {
// Process children.
for kid in self.base.child_iter() {
// If this layer preserves the 3d context of children,
// then children will need a render layer.
// TODO(gw): This isn't always correct. In some cases
// this may create extra layers than needed. I think
// there are also some edge cases where children don't
// get a layer when they should.
if transform_style == transform_style::T::preserve_3d {
flow::mut_base(kid).flags.insert(NEEDS_LAYER);
}
if flow::base(kid).flags.contains(INLINE_POSITION_IS_STATIC) ||
flow::base(kid).flags.contains(BLOCK_POSITION_IS_STATIC) {
let kid_base = flow::mut_base(kid);