Bug 1617879 - Rewrite the check for transformed clip intersection with the primitive in WR r=gw

Instead of trying to extract an inner rectangle from a transformed inner rectange,
which by itself doesn't have an obviously "best" solution, we are going to test if the
visibility rect is within the polygon of the projected inner rect.

The test is more precise, could be slightly more heavy, but most importantly - it's correct.

Differential Revision: https://phabricator.services.mozilla.com/D65836

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Dzmitry Malyshau 2020-03-09 19:46:35 +00:00
Родитель 04f376ebc4
Коммит 0c4b15a728
5 изменённых файлов: 88 добавлений и 21 удалений

Просмотреть файл

@ -107,7 +107,7 @@ use crate::prim_store::{ClipData, ImageMaskData, SpaceMapper, VisibleMaskImageTi
use crate::prim_store::{PointKey, SizeKey, RectangleKey};
use crate::render_task_cache::to_cache_size;
use crate::resource_cache::{ImageRequest, ResourceCache};
use std::{cmp, ops, u32};
use std::{iter, ops, u32};
use crate::util::{extract_inner_rect_safe, project_rect, ScaleOffset};
// Type definitions for interning clip nodes.
@ -1371,10 +1371,8 @@ impl ClipItemKind {
}
};
if let Some(inner_clip_rect) = inner_rect.and_then(|ref inner_rect| {
project_inner_rect(transform, inner_rect)
}) {
if inner_clip_rect.contains_rect(&visible_rect) {
if let Some(ref inner_clip_rect) = inner_rect {
if let Some(()) = projected_rect_contains(inner_clip_rect, transform, &visible_rect) {
return match mode {
ClipMode::Clip => ClipResult::Accept,
ClipMode::ClipOut => ClipResult::Reject,
@ -1558,25 +1556,39 @@ pub fn rounded_rectangle_contains_point(
true
}
pub fn project_inner_rect(
pub fn projected_rect_contains(
source_rect: &LayoutRect,
transform: &LayoutToWorldTransform,
rect: &LayoutRect,
) -> Option<WorldRect> {
target_rect: &WorldRect,
) -> Option<()> {
let points = [
transform.transform_point2d(rect.origin)?,
transform.transform_point2d(rect.top_right())?,
transform.transform_point2d(rect.bottom_left())?,
transform.transform_point2d(rect.bottom_right())?,
transform.transform_point2d(source_rect.origin)?,
transform.transform_point2d(source_rect.top_right())?,
transform.transform_point2d(source_rect.bottom_right())?,
transform.transform_point2d(source_rect.bottom_left())?,
];
let target_points = [
target_rect.origin,
target_rect.top_right(),
target_rect.bottom_right(),
target_rect.bottom_left(),
];
let mut xs = [points[0].x, points[1].x, points[2].x, points[3].x];
let mut ys = [points[0].y, points[1].y, points[2].y, points[3].y];
xs.sort_by(|a, b| a.partial_cmp(b).unwrap_or(cmp::Ordering::Equal));
ys.sort_by(|a, b| a.partial_cmp(b).unwrap_or(cmp::Ordering::Equal));
Some(WorldRect::new(
WorldPoint::new(xs[1], ys[1]),
WorldSize::new(xs[2] - xs[1], ys[2] - ys[1]),
))
// iterate the edges of the transformed polygon
for (a, b) in points
.iter()
.cloned()
.zip(points[1..].iter().cloned().chain(iter::once(points[0])))
{
// check if every destination point is on the right of the edge
for &c in target_points.iter() {
if (b - a).cross(c - a) < 0.0 {
return None
}
}
}
Some(())
}
// Add a clip node into the list of clips to be processed

Просмотреть файл

@ -118,7 +118,7 @@ pub enum ImageSource {
#[cfg_attr(feature = "capture", derive(Serialize))]
#[cfg_attr(feature = "replay", derive(Deserialize))]
#[derive(MallocSizeOf)]
#[derive(Debug, MallocSizeOf)]
pub struct ImageData {
pub key: ApiImageKey,
pub stretch_size: LayoutSize,

Просмотреть файл

@ -0,0 +1,13 @@
# Test checks if a rotated clip with a long and thin rectangle would still
# correctly affect the primitive with regards to the inner bounds.
---
root:
items:
-
bounds: [0, 0, 0, 0]
type: "stacking-context"
items:
-
bounds: [100, 100, 14, 14]
type: rect
color: blue

Просмотреть файл

@ -0,0 +1,41 @@
# Test checks if a rotated clip with a long and thin rectangle would still
# correctly affect the primitive with regards to the inner bounds.
---
root:
items:
-
bounds: [0, 0, 0, 0]
type: "reference-frame"
id: 2
-
bounds: [0, 0, 0, 0]
type: "stacking-context"
transform: rotate(45) translate(200, 0)
items:
-
bounds: [0, 0, 20, 1000]
type: clip
id: 5
# uncomment this to see the clip area
#-
# bounds: [0, 0, 20, 1000]
# type: rect
# color: green
- # we aren't supposed to see this one
bounds: [0, 0, 0, 0]
type: "stacking-context"
clip-and-scroll: [2, 5]
items:
-
bounds: [120, 120, 10, 10]
type: rect
color: red
-
bounds: [0, 0, 0, 0]
type: "stacking-context"
clip-and-scroll: [2, 5]
items:
-
bounds: [100, 100, 14, 14]
type: rect
color: blue

Просмотреть файл

@ -14,3 +14,4 @@ skip_on(android,device) == color_targets(3) alpha_targets(1) stacking-context-cl
fuzzy(70,2400) == clip-and-filter-with-rotation.yaml clip-and-filter-with-rotation-ref.yaml
color_targets(1) alpha_targets(0) == clip-out-rotation.yaml blank.yaml # Unexpected color targets, see bug 1580795
== clipped-occlusion.yaml clipped-occlusion-ref.yaml
== clip-thin-rotated.yaml clip-thin-rotated-ref.yaml