зеркало из https://github.com/mozilla/gecko-dev.git
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:
Родитель
04f376ebc4
Коммит
0c4b15a728
|
@ -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
|
||||
|
|
Загрузка…
Ссылка в новой задаче