servo: Merge #4530 - layout: Implement `pointer-events: none` per SVG 1.1 § 16.6 (from pcwalton:pointer-events); r=mbrubeck

SVG-only values are not yet supported.

r? @mbrubeck

Source-Repo: https://github.com/servo/servo
Source-Revision: a88e668091842dc77169b235a03b5264e65ebdc6
This commit is contained in:
Patrick Walton 2015-01-08 10:48:55 -07:00
Родитель ff1c5b6981
Коммит 349c217b6b
4 изменённых файлов: 58 добавлений и 12 удалений

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

@ -39,10 +39,9 @@ use servo_util::range::Range;
use servo_util::smallvec::{SmallVec, SmallVec8}; use servo_util::smallvec::{SmallVec, SmallVec8};
use std::fmt; use std::fmt;
use std::slice::Items; use std::slice::Items;
use style::ComputedValues;
use style::computed_values::border_style;
use style::computed_values::cursor;
use std::sync::Arc; use std::sync::Arc;
use style::ComputedValues;
use style::computed_values::{border_style, cursor, pointer_events};
// It seems cleaner to have layout code not mention Azure directly, so let's just reexport this for // It seems cleaner to have layout code not mention Azure directly, so let's just reexport this for
// layout to use. // layout to use.
@ -340,9 +339,9 @@ impl StackingContext {
tile_subrect.translate(&-child_stacking_context.bounds.to_azure_rect().origin) tile_subrect.translate(&-child_stacking_context.bounds.to_azure_rect().origin)
} }
/// Places all nodes containing the point of interest into `result`, topmost first. If /// Places all nodes containing the point of interest into `result`, topmost first. Respects
/// `topmost_only` is true, stops after placing one node into the list. `result` must be empty /// the `pointer-events` CSS property If `topmost_only` is true, stops after placing one node
/// upon entry to this function. /// into the list. `result` must be empty upon entry to this function.
pub fn hit_test(&self, pub fn hit_test(&self,
point: Point2D<Au>, point: Point2D<Au>,
result: &mut Vec<DisplayItemMetadata>, result: &mut Vec<DisplayItemMetadata>,
@ -363,6 +362,10 @@ impl StackingContext {
// Can't possibly hit. // Can't possibly hit.
continue continue
} }
if item.base().metadata.pointing.is_none() {
// `pointer-events` is `none`. Ignore this item.
continue
}
match *item { match *item {
DisplayItem::BorderClass(ref border) => { DisplayItem::BorderClass(ref border) => {
// If the point is inside the border, it didn't hit the border! // If the point is inside the border, it didn't hit the border!
@ -632,8 +635,9 @@ impl ClippingRegion {
pub struct DisplayItemMetadata { pub struct DisplayItemMetadata {
/// The DOM node from which this display item originated. /// The DOM node from which this display item originated.
pub node: OpaqueNode, pub node: OpaqueNode,
/// The value of the `cursor` property when the mouse hovers over this display item. /// The value of the `cursor` property when the mouse hovers over this display item. If `None`,
pub cursor: Cursor, /// this display item is ineligible for pointer events (`pointer-events: none`).
pub pointing: Option<Cursor>,
} }
impl DisplayItemMetadata { impl DisplayItemMetadata {
@ -646,9 +650,10 @@ impl DisplayItemMetadata {
-> DisplayItemMetadata { -> DisplayItemMetadata {
DisplayItemMetadata { DisplayItemMetadata {
node: node, node: node,
cursor: match style.get_pointing().cursor { pointing: match (style.get_pointing().pointer_events, style.get_pointing().cursor) {
cursor::T::AutoCursor => default_cursor, (pointer_events::T::none, _) => None,
cursor::T::SpecifiedCursor(cursor) => cursor, (pointer_events::T::auto, cursor::T::AutoCursor) => Some(default_cursor),
(pointer_events::T::auto, cursor::T::SpecifiedCursor(cursor)) => Some(cursor),
}, },
} }
} }

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

@ -998,7 +998,7 @@ impl LayoutRPC for LayoutRPCImpl {
// Compute the new cursor. // Compute the new cursor.
let cursor = if !mouse_over_list.is_empty() { let cursor = if !mouse_over_list.is_empty() {
mouse_over_list[0].cursor mouse_over_list[0].pointing.unwrap()
} else { } else {
Cursor::DefaultCursor Cursor::DefaultCursor
}; };

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

@ -1546,6 +1546,11 @@ pub mod longhands {
} }
</%self:single_component_value> </%self:single_component_value>
// NB: `pointer-events: auto` (and use of `pointer-events` in anything that isn't SVG, in fact)
// is nonstandard, slated for CSS4-UI.
// TODO(pcwalton): SVG-only values.
${single_keyword("pointer-events", "auto none")}
// Box-shadow, etc. // Box-shadow, etc.
${new_style_struct("Effects", is_inherited=False)} ${new_style_struct("Effects", is_inherited=False)}

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

@ -0,0 +1,36 @@
<!DOCTYPE html>
<html>
<head>
<style>
#overlay {
width: 200px;
height: 150px;
background: green;
opacity: 0.5;
pointer-events: none;
}
button {
position: relative;
top: 10px;
width: 150px;
height: 50px;
border: solid black 2px;
box-sizing: border-box;
font: Helvetica bold;
font-size: 18px;
text-align: center;
background: black;
color: white;
}
</style>
</head>
<body>
<button id=button>Click me!</button>
<div id=overlay></div>
<script>
document.getElementById('button').addEventListener('click', function() { alert("Ouch!"); });
</script>
</body>
</html>