JDK-8224636 : CSS "pointer-events" property "stroke" is not respected for SVG renderings
  • Type: Bug
  • Component: javafx
  • Sub-Component: web
  • Affected Version: openjfx13
  • Priority: P4
  • Status: Resolved
  • Resolution: Fixed
  • OS: linux_ubuntu
  • CPU: x86_64
  • Submitted: 2019-05-22
  • Updated: 2020-01-31
  • Resolved: 2019-07-16
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8 Other
8u241Fixed openjfx11.0.6Fixed
Description
ADDITIONAL SYSTEM INFORMATION :
Problem was reproduced on OpenJFX master.

A DESCRIPTION OF THE PROBLEM :
For SVG renderings the developer can specify, which graphics elements should receive
mouse events. For example:

.clickable {
    pointer-events: stroke;
}

configures all elements with the class "clickable" to receive pointer events. This was found
while evaluating if using bpmn.js (https://github.com/bpmn-io/bpmn-js) via JavaFX
WebView would be viable option for BPMN integration.

It was noticed, that hovering over normal elements works, but hovering/selecting connectors
did not. The problem was not reproducible in other webkit based browsers.

Analysis lead to the call sequence:

RenderSVGShape::nodeAtFloatPoint
calls into RenderSVGShape::strokeContains
calls into RenderSVGShape::shapeDependentStrokeContains
calls into Path::strokeContains

at that point the call sequence fails. The current implementation in JavaFX reads (TemporaryLinkStubsJava.cpp):

bool Path::strokeContains(StrokeStyleApplier*, const FloatPoint&) const
{
    notImplemented();
    return false;
}

As this method always reports false, strokes are never considered as targets for mouse events.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
1. Open index.html in a normal web browser, click on the strokes of the shapes, they will turn green
2. Run the attached TestBrwoser3.java, it will open a JavaFX Stage with a WebView, that loads the index.html
3. Click on the strokes of the shapes in the WebView

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
All shapes should react to the clicks by turning green.
ACTUAL -
Only the basic shapes (lower row): rect, circle and ellipse work, the complex shapes (upper row) path, polyline and polygon don't react.

---------- BEGIN SOURCE ----------
======================== TestBrowser3.java ==============
package eu.doppel_helix.dev.jdk.reproducecrash;

import com.sun.javafx.webkit.WebConsoleListener;
import java.util.logging.Handler;
import java.util.logging.Level;
import java.util.logging.Logger;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.layout.BorderPane;
import javafx.scene.web.WebView;
import javafx.stage.Stage;

public class TestBrowser3 implements Runnable {

    public static void main(String[] args) {
        Platform.startup(new TestBrowser3());
    }

    public void run() {
        final Stage primaryStage = new Stage();

        primaryStage.setTitle("Hello World!");
        final WebView view = new WebView();
        BorderPane bp = new BorderPane();
        bp.setCenter(view);
        primaryStage.setScene(new Scene(bp, 800, 600));
        primaryStage.show();

        WebConsoleListener.setDefaultListener((webView, message, lineNumber, sourceId) -> {
            System.out.println(message + "[at " + lineNumber + "]");
        });

        view.getEngine().load(TestBrowser3.class.getResource("index.html").toExternalForm());
    }

}


======================== index.html ==================
<!DOCTYPE html>
<html>
    <head>
        <title>Test pointer events on stroke</title>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <style type="text/css">
            rect, path, polyline, line, circle, ellipse, polygon {
                pointer-events: stroke;
                stroke: gray;
                stroke-opacity: 1;
                stroke-width: 10px;
                fill: transparent;
            }
            rect.clicked, path.clicked, polyline.clicked, line.clicked, circle.clicked, ellipse.clicked, polygon.clicked {
                stroke: green;
            }
        </style>
        <script>
            var testElements = [ "polyline", "path", "rect", "circle", "ellipse", "polygon" ];
            window.addEventListener( 'DOMContentLoaded', ( event ) => {
                for ( var el of testElements ) {
                    document.getElementById( el ).addEventListener( "mousedown", function ( evt ) {
                        this.classList.add( "clicked" );
                        console.log( "mousedown(" + evt.pageX + ", " + evt.pageY + ")" );
                    } );
                }
            } );

            function clearState() {
                for ( var el of testElements ) {
                    document.getElementById( el ).addEventListener( "mousedown", function ( evt ) {
                        this.classList.remove( "clicked" );
                    } );
                }
            }

            function isActivated( id ) {
                return document.getElementById( id ).classList.contains( "clicked" );
            }
        </script>
    </head>
    <body>
        <svg
            xmlns="http://www.w3.org/2000/svg"
            id="svg8"
            version="1.1"
            viewBox="0 0 300 200"
            height="400px"
            width="600px">

        <polyline points="10,10 60,10 60,60 10,60 " id="polyline" />
        <path d="M110 10 H 160 V 60 H 110" id="path"/>
        <polygon points="210,10 260,10 260,60 210,60 " id="polygon" />
        <rect x="10" y="110" width="50" height="50" id="rect"/>
        <circle cx="135" cy="135" r="25" id="circle"/>
        <ellipse cx="235" cy="135" rx="25" ry="25" id="ellipse"/>
        </svg>
        <p>
            It is expected, that a click on each of the shapes is recorded.
            In an interactive test a successful record is reflected by the
            shape turning green.
        </p>
    </body>
</html>
---------- END SOURCE ----------

FREQUENCY : always



Comments
Testing looks good, and this is a safe fix for basic functionality that isn't working, so pushing this to 13-dev for openjfx13.
18-07-2019

Changeset: 0553463dccee Author: kcr Date: 2019-07-16 05:41 -0700 URL: https://hg.openjdk.java.net/openjfx/13-dev/rt/rev/0553463dccee 8224636: CSS "pointer-events" property "stroke" is not respected for SVG renderings Reviewed-by: arajkumar, kcr Contributed-by: mblaesing@doppel-helix.eu
18-07-2019

Changeset: 68b681c097fd Author: kcr Date: 2019-07-16 05:41 -0700 URL: https://hg.openjdk.java.net/openjfx/jfx-dev/rt/rev/68b681c097fd 8224636: CSS "pointer-events" property "stroke" is not respected for SVG renderings Reviewed-by: arajkumar, kcr Contributed-by: mblaesing@doppel-helix.eu
16-07-2019