зеркало из https://github.com/mozilla/pjs.git
Bug 619959, part 2. Fix handling of various values of pointer-events when stroke-opacity="0". r=longsonr,heycam. a=roc.
--HG-- extra : rebase_source : d2adfa6fb8abfc08e2c1693521668587d1aaa00d
This commit is contained in:
Родитель
b4814e30fe
Коммит
8521ecfb73
|
@ -65,6 +65,7 @@ _TEST_FILES = \
|
|||
test_isSupported.xhtml \
|
||||
test_nonAnimStrings.xhtml \
|
||||
test_pathSeg.xhtml \
|
||||
test_pointer-events.xhtml \
|
||||
test_pointer-events-2.xhtml \
|
||||
test_scientific.html \
|
||||
scientific-helper.svg \
|
||||
|
|
|
@ -0,0 +1,273 @@
|
|||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=619959
|
||||
-->
|
||||
<head>
|
||||
<title>Test 'pointer-events' handling</title>
|
||||
<script type="text/javascript" src="/MochiKit/packed.js"></script>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body onload="run_tests()">
|
||||
<script class="testbody" type="text/javascript">
|
||||
<![CDATA[
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var pointer_events_values = [
|
||||
'visiblePainted',
|
||||
'visibleFill',
|
||||
'visibleStroke',
|
||||
'visible',
|
||||
'painted',
|
||||
'fill',
|
||||
'stroke',
|
||||
'all',
|
||||
'none'
|
||||
];
|
||||
|
||||
var paint_values = [
|
||||
'blue',
|
||||
'transparent',
|
||||
'none'
|
||||
];
|
||||
|
||||
var opacity_values = [
|
||||
'1',
|
||||
'0.5',
|
||||
'0'
|
||||
];
|
||||
|
||||
var visibility_values = [
|
||||
'visible',
|
||||
'hidden',
|
||||
'collapse'
|
||||
];
|
||||
|
||||
/**
|
||||
* List of attributes and various values for which we want to test permutations
|
||||
* when hit testing stroke and fill.
|
||||
*
|
||||
* We're using an array of objects so that we have control over the order in
|
||||
* which permutations are tested.
|
||||
*
|
||||
* TODO: test the effect of clipping, masking, filters, markers, etc.
|
||||
*/
|
||||
var hit_test_attr_values = {
|
||||
fill: [
|
||||
{ name: 'pointer-events', values: pointer_events_values },
|
||||
{ name: 'fill', values: paint_values },
|
||||
{ name: 'fill-opacity', values: opacity_values },
|
||||
{ name: 'opacity', values: opacity_values },
|
||||
{ name: 'visibility', values: visibility_values }
|
||||
],
|
||||
stroke: [
|
||||
{ name: 'pointer-events', values: pointer_events_values },
|
||||
{ name: 'stroke', values: paint_values },
|
||||
{ name: 'stroke-opacity', values: opacity_values },
|
||||
{ name: 'opacity', values: opacity_values },
|
||||
{ name: 'visibility', values: visibility_values }
|
||||
]
|
||||
}
|
||||
|
||||
/**
|
||||
* The following object contains a list of 'pointer-events' property values,
|
||||
* each with an object detailing the conditions under which the fill and stroke
|
||||
* of a graphical object will intercept pointer events for the given value. If
|
||||
* the object contains a 'fill-intercepts-iff' property then the fill is
|
||||
* expected to intercept pointer events for that value of 'pointer-events' if
|
||||
* and only if the conditions listed in the 'fill-intercepts-iff' object are
|
||||
* met. If there are no conditions in the 'fill-intercepts-iff' object then the
|
||||
* fill should always intercept pointer events. However, if the
|
||||
* 'fill-intercepts-iff' property is not set at all then it indicates that the
|
||||
* fill should never intercept pointer events. The same rules apply for
|
||||
* 'stroke-intercepts-iff'.
|
||||
*
|
||||
* If an attribute name in the conditions list is followed by the "!"
|
||||
* character then the requirement for a hit is that its value is NOT any
|
||||
* of the values listed in the given array.
|
||||
*/
|
||||
var hit_conditions = {
|
||||
visiblePainted: {
|
||||
'fill-intercepts-iff': {
|
||||
'visibility': ['visible'],
|
||||
'fill!': ['none']
|
||||
},
|
||||
'stroke-intercepts-iff': {
|
||||
'visibility': ['visible'],
|
||||
'stroke!': ['none']
|
||||
}
|
||||
},
|
||||
visibleFill: {
|
||||
'fill-intercepts-iff': {
|
||||
visibility: ['visible']
|
||||
}
|
||||
// stroke never intercepts pointer events
|
||||
},
|
||||
visibleStroke: {
|
||||
// fill never intercepts pointer events
|
||||
'stroke-intercepts-iff': {
|
||||
visibility: ['visible']
|
||||
}
|
||||
},
|
||||
visible: {
|
||||
'fill-intercepts-iff': {
|
||||
visibility: ['visible']
|
||||
},
|
||||
'stroke-intercepts-iff': {
|
||||
visibility: ['visible']
|
||||
}
|
||||
},
|
||||
painted: {
|
||||
'fill-intercepts-iff': {
|
||||
'fill!': ['none']
|
||||
},
|
||||
'stroke-intercepts-iff': {
|
||||
'stroke!': ['none']
|
||||
}
|
||||
},
|
||||
fill: {
|
||||
'fill-intercepts-iff': {
|
||||
// fill always intercepts pointer events
|
||||
}
|
||||
// stroke never intercepts pointer events
|
||||
},
|
||||
stroke: {
|
||||
// fill never intercepts pointer events
|
||||
'stroke-intercepts-iff': {
|
||||
// stroke always intercepts pointer events
|
||||
}
|
||||
},
|
||||
all: {
|
||||
'fill-intercepts-iff': {
|
||||
// fill always intercepts pointer events
|
||||
},
|
||||
'stroke-intercepts-iff': {
|
||||
// stroke always intercepts pointer events
|
||||
}
|
||||
},
|
||||
none: {
|
||||
// neither fill nor stroke intercept pointer events
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Examine the current attribute values and return true if the specified target
|
||||
* (fill or stroke) is expected to intercept events, or else return false.
|
||||
*/
|
||||
function hit_expected(target /* {stroke|fill} */, attributes)
|
||||
{
|
||||
var intercepts_iff =
|
||||
hit_conditions[attributes['pointer-events']][target + '-intercepts-iff'];
|
||||
|
||||
if (!intercepts_iff) {
|
||||
return false; // never intercepts events
|
||||
}
|
||||
|
||||
for (var attr in intercepts_iff) {
|
||||
var vals = intercepts_iff[attr]; // must get this before we adjust 'attr'
|
||||
var invert = false;
|
||||
if (attr.substr(-1) == '!') {
|
||||
invert = true;
|
||||
attr = attr.substr(0, attr.length-1);
|
||||
}
|
||||
var match = vals.indexOf(attributes[attr]) > -1;
|
||||
if (invert) {
|
||||
match = !match;
|
||||
}
|
||||
if (!match) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function for_all_permutations(inputs, callback)
|
||||
{
|
||||
var current_permutation = arguments[2] || {};
|
||||
var index = arguments[3] || 0;
|
||||
|
||||
if (index < inputs.length) {
|
||||
var name = inputs[index].name;
|
||||
var values = inputs[index].values;
|
||||
for (var i = 0; i < values.length; ++i) {
|
||||
current_permutation[name] = values[i];
|
||||
for_all_permutations(inputs, callback, current_permutation, index+1);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
callback(current_permutation);
|
||||
}
|
||||
|
||||
function log_msg(target, id, attributes)
|
||||
{
|
||||
var msg = 'Check if events are intercepted by '+target+' on '+id+' for';
|
||||
for (var attr in attributes) {
|
||||
msg += ' '+attr+'='+attributes[attr];
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
function run_tests()
|
||||
{
|
||||
var div = document.getElementById("div");
|
||||
var dx = div.offsetLeft;
|
||||
var dy = div.offsetTop;
|
||||
|
||||
var id, element, target; // target is 'fill' or 'stroke'
|
||||
var x, y; // coordinates to hit test
|
||||
|
||||
function test_permutation(attributes) {
|
||||
for (var attr in attributes) {
|
||||
element.setAttribute(attr, attributes[attr]);
|
||||
}
|
||||
var hit = document.elementFromPoint(dx + x, dy + y) == element;
|
||||
is(hit, hit_expected(target, attributes), log_msg(target, id, attributes));
|
||||
}
|
||||
|
||||
// To reduce the chance of bogus results
|
||||
function clear_attributes_for_next_test(inputs) {
|
||||
for (var i = 0; i < inputs.length; ++i) {
|
||||
element.removeAttribute(inputs[i].name);
|
||||
}
|
||||
element.setAttribute('fill', 'none');
|
||||
element.setAttribute('stroke', 'none');
|
||||
}
|
||||
|
||||
id = 'rect';
|
||||
element = document.getElementById(id);
|
||||
|
||||
var target = 'fill';
|
||||
x = 30;
|
||||
y = 30;
|
||||
for_all_permutations(hit_test_attr_values[target], test_permutation);
|
||||
clear_attributes_for_next_test(hit_test_attr_values[target]);
|
||||
|
||||
var target = 'stroke';
|
||||
x = 5;
|
||||
y = 5;
|
||||
for_all_permutations(hit_test_attr_values[target], test_permutation);
|
||||
clear_attributes_for_next_test(hit_test_attr_values[target]);
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
]]>
|
||||
</script>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=619959">Mozilla Bug 619959</a>
|
||||
<p id="display"></p>
|
||||
<div id="content">
|
||||
|
||||
<div width="100%" height="1" id="div"></div>
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" id="svg">
|
||||
<rect id="rect" x="10" y="10" width="40" height="40" stroke-width="20"/>
|
||||
</svg>
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -159,7 +159,7 @@ nsSVGPathGeometryFrame::GetFrameForPoint(const nsPoint &aPoint)
|
|||
fillRule = GetClipRule();
|
||||
} else {
|
||||
mask = GetHittestMask();
|
||||
if (!mask || (!(mask & HITTEST_MASK_FORCE_TEST) &&
|
||||
if (!mask || ((mask & HITTEST_MASK_CHECK_MRECT) &&
|
||||
!mRect.Contains(aPoint)))
|
||||
return nsnull;
|
||||
fillRule = GetStyleSVG()->mFillRule;
|
||||
|
@ -521,24 +521,25 @@ nsSVGPathGeometryFrame::GetHittestMask()
|
|||
mask |= HITTEST_MASK_FILL;
|
||||
if (GetStyleSVG()->mStroke.mType != eStyleSVGPaintType_None)
|
||||
mask |= HITTEST_MASK_STROKE;
|
||||
if (GetStyleSVG()->mStrokeOpacity > 0)
|
||||
mask |= HITTEST_MASK_CHECK_MRECT;
|
||||
}
|
||||
break;
|
||||
case NS_STYLE_POINTER_EVENTS_VISIBLEFILL:
|
||||
if (GetStyleVisibility()->IsVisible()) {
|
||||
mask |= HITTEST_MASK_FILL | HITTEST_MASK_FORCE_TEST;
|
||||
mask |= HITTEST_MASK_FILL;
|
||||
}
|
||||
break;
|
||||
case NS_STYLE_POINTER_EVENTS_VISIBLESTROKE:
|
||||
if (GetStyleVisibility()->IsVisible()) {
|
||||
mask |= HITTEST_MASK_STROKE | HITTEST_MASK_FORCE_TEST;
|
||||
mask |= HITTEST_MASK_STROKE;
|
||||
}
|
||||
break;
|
||||
case NS_STYLE_POINTER_EVENTS_VISIBLE:
|
||||
if (GetStyleVisibility()->IsVisible()) {
|
||||
mask |=
|
||||
HITTEST_MASK_FILL |
|
||||
HITTEST_MASK_STROKE |
|
||||
HITTEST_MASK_FORCE_TEST;
|
||||
HITTEST_MASK_STROKE;
|
||||
}
|
||||
break;
|
||||
case NS_STYLE_POINTER_EVENTS_PAINTED:
|
||||
|
@ -546,18 +547,19 @@ nsSVGPathGeometryFrame::GetHittestMask()
|
|||
mask |= HITTEST_MASK_FILL;
|
||||
if (GetStyleSVG()->mStroke.mType != eStyleSVGPaintType_None)
|
||||
mask |= HITTEST_MASK_STROKE;
|
||||
if (GetStyleSVG()->mStrokeOpacity)
|
||||
mask |= HITTEST_MASK_CHECK_MRECT;
|
||||
break;
|
||||
case NS_STYLE_POINTER_EVENTS_FILL:
|
||||
mask |= HITTEST_MASK_FILL | HITTEST_MASK_FORCE_TEST;
|
||||
mask |= HITTEST_MASK_FILL;
|
||||
break;
|
||||
case NS_STYLE_POINTER_EVENTS_STROKE:
|
||||
mask |= HITTEST_MASK_STROKE | HITTEST_MASK_FORCE_TEST;
|
||||
mask |= HITTEST_MASK_STROKE;
|
||||
break;
|
||||
case NS_STYLE_POINTER_EVENTS_ALL:
|
||||
mask |=
|
||||
HITTEST_MASK_FILL |
|
||||
HITTEST_MASK_STROKE |
|
||||
HITTEST_MASK_FORCE_TEST;
|
||||
HITTEST_MASK_STROKE;
|
||||
break;
|
||||
default:
|
||||
NS_ERROR("not reached");
|
||||
|
|
|
@ -54,7 +54,7 @@ typedef nsSVGGeometryFrame nsSVGPathGeometryFrameBase;
|
|||
|
||||
#define HITTEST_MASK_FILL 0x01
|
||||
#define HITTEST_MASK_STROKE 0x02
|
||||
#define HITTEST_MASK_FORCE_TEST 0x04
|
||||
#define HITTEST_MASK_CHECK_MRECT 0x04
|
||||
|
||||
class nsSVGPathGeometryFrame : public nsSVGPathGeometryFrameBase,
|
||||
public nsISVGChildFrame
|
||||
|
|
Загрузка…
Ссылка в новой задаче