Auto merge of #18234 - BorisChiou:stylo/transform/distance_mismatch, r=birtles,nox

stylo: Bug 1390039 - Implement compute_distance for mismatched transform lists.

Implement ComputeSquaredDistance for mismatched transform lists.
In order to do this, we have to convert a transform list into a 3d matrix,
so I move the code from layout module into style module for reusing it.

---
- [X] `./mach build -d` does not report any errors
- [X] `./mach test-tidy` does not report any errors
- [X] These changes fix [Bug 1390039](https://bugzilla.mozilla.org/show_bug.cgi?id=1390039).
- [X] These changes do not require tests because this is a Gecko feature and I add many tests in Gecko already.

<!-- Reviewable:start -->
---
This change is [<img src="https://reviewable.io/review_button.svg" height="34" align="absmiddle" alt="Reviewable"/>](https://reviewable.io/reviews/servo/servo/18234)
<!-- Reviewable:end -->
This commit is contained in:
bors-servo 2017-08-30 06:03:32 -05:00 committed by GitHub
commit 3fa5d83ab7
5 changed files with 191 additions and 151 deletions

View file

@ -10,7 +10,7 @@ use ServoArc;
use app_units::Au;
use canvas_traits::canvas::CanvasMsg;
use context::{LayoutContext, with_thread_local_font_context};
use euclid::{Transform3D, Point2D, Vector2D, Radians, Rect, Size2D};
use euclid::{Transform3D, Point2D, Vector2D, Rect, Size2D};
use floats::ClearType;
use flow::{self, ImmutableFlowUtils};
use flow_ref::FlowRef;
@ -25,7 +25,7 @@ use ipc_channel::ipc::IpcSender;
#[cfg(debug_assertions)]
use layout_debug;
use model::{self, IntrinsicISizes, IntrinsicISizesContribution, MaybeAuto, SizeConstraint};
use model::{style_length, ToGfxMatrix};
use model::style_length;
use msg::constellation_msg::{BrowsingContextId, PipelineId};
use net_traits::image::base::{Image, ImageMetadata};
use net_traits::image_cache::{ImageOrMetadataAvailable, UsePlaceholder};
@ -41,11 +41,12 @@ use std::cmp::{Ordering, max, min};
use std::collections::LinkedList;
use std::sync::{Arc, Mutex};
use style::computed_values::{border_collapse, box_sizing, clear, color, display, mix_blend_mode};
use style::computed_values::{overflow_wrap, overflow_x, position, text_decoration_line, transform};
use style::computed_values::{overflow_wrap, overflow_x, position, text_decoration_line};
use style::computed_values::{transform_style, vertical_align, white_space, word_break};
use style::computed_values::content::ContentItem;
use style::logical_geometry::{Direction, LogicalMargin, LogicalRect, LogicalSize, WritingMode};
use style::properties::ComputedValues;
use style::properties::longhands::transform::computed_value::T as TransformList;
use style::selector_parser::RestyleDamage;
use style::servo::restyle_damage::RECONSTRUCT_FLOW;
use style::str::char_is_whitespace;
@ -2863,12 +2864,12 @@ impl Fragment {
/// Returns the 4D matrix representing this fragment's transform.
pub fn transform_matrix(&self, stacking_relative_border_box: &Rect<Au>) -> Option<Transform3D<f32>> {
let operations = match self.style.get_box().transform.0 {
let list = &self.style.get_box().transform;
let transform = match list.to_transform_3d_matrix(Some(stacking_relative_border_box)) {
Some(transform) => transform,
None => return None,
Some(ref operations) => operations,
};
let mut transform = Transform3D::identity();
let transform_origin = &self.style.get_box().transform_origin;
let transform_origin_x =
transform_origin.horizontal
@ -2887,55 +2888,6 @@ impl Fragment {
-transform_origin_y,
-transform_origin_z);
for operation in operations {
let matrix = match *operation {
transform::ComputedOperation::Rotate(ax, ay, az, theta) => {
// https://www.w3.org/TR/css-transforms-1/#funcdef-rotate3d
// A direction vector that cannot be normalized, such as [0, 0, 0], will cause
// the rotation to not be applied, so we use identity matrix in this case.
let len = (ax * ax + ay * ay + az * az).sqrt();
if len > 0. {
let theta = 2.0f32 * f32::consts::PI - theta.radians();
Transform3D::create_rotation(ax / len, ay / len, az / len,
Radians::new(theta))
} else {
Transform3D::identity()
}
}
transform::ComputedOperation::Perspective(d) => {
create_perspective_matrix(d)
}
transform::ComputedOperation::Scale(sx, sy, sz) => {
Transform3D::create_scale(sx, sy, sz)
}
transform::ComputedOperation::Translate(tx, ty, tz) => {
let tx = tx.to_used_value(stacking_relative_border_box.size.width).to_f32_px();
let ty = ty.to_used_value(stacking_relative_border_box.size.height).to_f32_px();
let tz = tz.to_f32_px();
Transform3D::create_translation(tx, ty, tz)
}
transform::ComputedOperation::Matrix(m) => {
m.to_gfx_matrix()
}
transform::ComputedOperation::MatrixWithPercents(_) => {
// `-moz-transform` is not implemented in Servo yet.
unreachable!()
}
transform::ComputedOperation::Skew(theta_x, theta_y) => {
Transform3D::create_skew(Radians::new(theta_x.radians()),
Radians::new(theta_y.radians()))
}
transform::ComputedOperation::InterpolateMatrix { .. } |
transform::ComputedOperation::AccumulateMatrix { .. } => {
// TODO: Convert InterpolateMatrix/AccmulateMatrix into a valid Transform3D by
// the reference box.
Transform3D::identity()
}
};
transform = transform.pre_mul(&matrix);
}
Some(pre_transform.pre_mul(&transform).pre_mul(&post_transform))
}
@ -2960,7 +2912,7 @@ impl Fragment {
-perspective_origin.y,
0.0);
let perspective_matrix = create_perspective_matrix(length);
let perspective_matrix = TransformList::create_perspective_matrix(length);
Some(pre_transform.pre_mul(&perspective_matrix).pre_mul(&post_transform))
}
@ -3204,20 +3156,3 @@ impl Serialize for DebugId {
serializer.serialize_u16(self.0)
}
}
// TODO(gw): The transforms spec says that perspective length must
// be positive. However, there is some confusion between the spec
// and browser implementations as to handling the case of 0 for the
// perspective value. Until the spec bug is resolved, at least ensure
// that a provided perspective value of <= 0.0 doesn't cause panics
// and behaves as it does in other browsers.
// See https://lists.w3.org/Archives/Public/www-style/2016Jan/0020.html for more details.
#[inline]
fn create_perspective_matrix(d: Au) -> Transform3D<f32> {
let d = d.to_f32_px();
if d <= 0.0 {
Transform3D::identity()
} else {
Transform3D::create_perspective(d)
}
}

View file

@ -7,11 +7,10 @@
#![deny(unsafe_code)]
use app_units::Au;
use euclid::{Transform3D, SideOffsets2D, Size2D};
use euclid::{SideOffsets2D, Size2D};
use fragment::Fragment;
use std::cmp::{max, min};
use std::fmt;
use style::computed_values::transform::ComputedMatrix;
use style::logical_geometry::{LogicalMargin, WritingMode};
use style::properties::ComputedValues;
use style::values::computed::{BorderCornerRadius, LengthOrPercentageOrAuto};
@ -508,20 +507,6 @@ pub fn specified_margin_from_style(style: &ComputedValues,
MaybeAuto::from_style(margin_style.margin_left, Au(0)).specified_or_zero()))
}
pub trait ToGfxMatrix {
fn to_gfx_matrix(&self) -> Transform3D<f32>;
}
impl ToGfxMatrix for ComputedMatrix {
fn to_gfx_matrix(&self) -> Transform3D<f32> {
Transform3D::row_major(
self.m11 as f32, self.m12 as f32, self.m13 as f32, self.m14 as f32,
self.m21 as f32, self.m22 as f32, self.m23 as f32, self.m24 as f32,
self.m31 as f32, self.m32 as f32, self.m33 as f32, self.m34 as f32,
self.m41 as f32, self.m42 as f32, self.m43 as f32, self.m44 as f32)
}
}
/// A min-size and max-size constraint. The constructor has a optional `border`
/// parameter, and when it is present the constraint will be subtracted. This is
/// used to adjust the constraint for `box-sizing: border-box`, and when you do so