Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Robust TransformRect #1426

Merged
merged 2 commits into from Jun 23, 2017
Merged
Changes from 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file
Failed to load files.

Always

Just for now

Prev

Robust TransformRect

  • Loading branch information
kvark committed Jun 23, 2017
commit b67e4b8737c507f42b9087df3b6d08b6ab39c58a
@@ -5,7 +5,7 @@
use std::f32::consts::{FRAC_1_SQRT_2};
use euclid::{Point2D, Rect, Size2D};
use euclid::{TypedRect, TypedPoint2D, TypedSize2D, TypedTransform2D, TypedTransform3D};
use webrender_traits::{DeviceIntRect, DeviceIntPoint, DeviceIntSize};
use webrender_traits::{DeviceIntRect, DevicePoint, DeviceRect, DeviceSize};
use webrender_traits::{LayerRect, WorldPoint3D, LayerToWorldTransform};
use webrender_traits::{BorderRadius, ComplexClipRegion, LayoutRect};
use num_traits::Zero;
@@ -202,6 +202,13 @@ pub struct TransformedRect {
pub kind: TransformedRectKind,
}

// Having an unlimited bounding box is fine up until we try
// to cast it to `i32`, where we get `-2147483648` for any
// values larger than or equal to 2^31.
//Note: clamping to i32::MIN and i32::MAX is not a solution,
// with explanation left as an exercise for the reader.
const MAX_COORD: f32 = 1.0e9;

impl TransformedRect {
pub fn new(rect: &LayerRect,
transform: &LayerToWorldTransform,
@@ -213,80 +220,43 @@ impl TransformedRect {
TransformedRectKind::Complex
};

// FIXME(gw): This code is meant to be a fast path for simple transforms.
// However, it fails on transforms that translate Z but result in an
// axis aligned rect.

/*
match kind {
TransformedRectKind::AxisAligned => {
let v0 = transform.transform_point(&rect.origin);
let v1 = transform.transform_point(&rect.top_right());
let v2 = transform.transform_point(&rect.bottom_left());
let v3 = transform.transform_point(&rect.bottom_right());
let screen_min_dp = Point2D::new(DevicePixel((v0.x * device_pixel_ratio).floor() as i32),
DevicePixel((v0.y * device_pixel_ratio).floor() as i32));
let screen_max_dp = Point2D::new(DevicePixel((v3.x * device_pixel_ratio).ceil() as i32),
DevicePixel((v3.y * device_pixel_ratio).ceil() as i32));
let screen_rect_dp = Rect::new(screen_min_dp, Size2D::new(screen_max_dp.x - screen_min_dp.x,
screen_max_dp.y - screen_min_dp.y));
TransformedRect {
local_rect: *rect,
vertices: [
Point4D::new(v0.x, v0.y, 0.0, 1.0),
Point4D::new(v1.x, v1.y, 0.0, 1.0),
Point4D::new(v2.x, v2.y, 0.0, 1.0),
Point4D::new(v3.x, v3.y, 0.0, 1.0),
],
bounding_rect: screen_rect_dp,
kind,
}
}
TransformedRectKind::Complex => {
*/
let vertices = [
transform.transform_point3d(&rect.origin.to_3d()),
transform.transform_point3d(&rect.bottom_left().to_3d()),
transform.transform_point3d(&rect.bottom_right().to_3d()),
transform.transform_point3d(&rect.top_right().to_3d()),
];

let (mut xs, mut ys) = ([0.0; 4], [0.0; 4]);

for (vertex, (x, y)) in vertices.iter().zip(xs.iter_mut().zip(ys.iter_mut())) {
*x = get_normal(vertex.x).unwrap_or(0.0);
*y = get_normal(vertex.y).unwrap_or(0.0);
}

xs.sort_by(|a, b| a.partial_cmp(b).unwrap());
ys.sort_by(|a, b| a.partial_cmp(b).unwrap());

let outer_min_dp = DeviceIntPoint::new((xs[0] * device_pixel_ratio).floor() as i32,
(ys[0] * device_pixel_ratio).floor() as i32);
let outer_max_dp = DeviceIntPoint::new((xs[3] * device_pixel_ratio).ceil() as i32,
(ys[3] * device_pixel_ratio).ceil() as i32);
let inner_min_dp = DeviceIntPoint::new((xs[1] * device_pixel_ratio).ceil() as i32,
(ys[1] * device_pixel_ratio).ceil() as i32);
let inner_max_dp = DeviceIntPoint::new((xs[2] * device_pixel_ratio).floor() as i32,
(ys[2] * device_pixel_ratio).floor() as i32);

TransformedRect {
local_rect: *rect,
vertices,
bounding_rect: DeviceIntRect::new(outer_min_dp,
DeviceIntSize::new(outer_max_dp.x.saturating_sub(outer_min_dp.x),
outer_max_dp.y.saturating_sub(outer_min_dp.y))),
inner_rect: DeviceIntRect::new(inner_min_dp,
DeviceIntSize::new(inner_max_dp.x.saturating_sub(inner_min_dp.x),
inner_max_dp.y.saturating_sub(inner_min_dp.y))),
kind,
}
/*
}
}*/

let vertices = [
transform.transform_point3d(&rect.origin.to_3d()),
transform.transform_point3d(&rect.bottom_left().to_3d()),
transform.transform_point3d(&rect.bottom_right().to_3d()),
transform.transform_point3d(&rect.top_right().to_3d()),
];

let (mut xs, mut ys) = ([0.0; 4], [0.0; 4]);

for (vertex, (x, y)) in vertices.iter().zip(xs.iter_mut().zip(ys.iter_mut())) {
*x = get_normal(vertex.x).unwrap_or(0.0);
*y = get_normal(vertex.y).unwrap_or(0.0);
}

xs.sort_by(|a, b| a.partial_cmp(b).unwrap());
ys.sort_by(|a, b| a.partial_cmp(b).unwrap());

let outer_min_dp = (DevicePoint::new(xs[0], ys[0]) * device_pixel_ratio).floor();
let outer_max_dp = (DevicePoint::new(xs[3], ys[3]) * device_pixel_ratio).ceil();
let inner_min_dp = (DevicePoint::new(xs[1], ys[1]) * device_pixel_ratio).ceil();
let inner_max_dp = (DevicePoint::new(xs[2], ys[2]) * device_pixel_ratio).floor();

let max_rect = DeviceRect::new(DevicePoint::new(-MAX_COORD, -MAX_COORD),
DeviceSize::new(2.0*MAX_COORD, 2.0*MAX_COORD));
let bounding_rect = DeviceRect::new(outer_min_dp, (outer_max_dp - outer_min_dp).to_size())
.intersection(&max_rect).unwrap_or(max_rect).to_i32();
let inner_rect = DeviceRect::new(inner_min_dp, (inner_max_dp - inner_min_dp).to_size())
.intersection(&max_rect).unwrap_or(max_rect).to_i32();

TransformedRect {
local_rect: *rect,
vertices,
bounding_rect,
inner_rect,
kind,
}
}
}

ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.