Closed Bug 405300 Opened 17 years ago Closed 13 years ago

<canvas> isPointInPath doesn't transform its coordinates


(Core :: Graphics: Canvas2D, defect)

Not set





(Reporter: ilmari.heikkinen, Assigned: Benjamin)




(Keywords: dev-doc-complete)


(3 files, 1 obsolete file)

User-Agent:       Mozilla/5.0 (X11; U; Linux i686 (x86_64); fi; rv:1.9b1) Gecko/2007110903 Firefox/3.0b1
Build Identifier: Mozilla/5.0 (X11; U; Linux i686 (x86_64); fi; rv:1.9b1) Gecko/2007110903 Firefox/3.0b1

When using ctx.isPointInPath(x,y), the x,y-coords should be multiplied by the current transformation matrix to have isPointInPath work for transformed paths. 

The WhatWG spec[1] wording is a bit confusing on this matter: 
"The isPointInPath(x, y) method must return true if the point given by the x and y coordinates passed to the method, when treated as coordinates in the canvas' coordinate space unaffected by the current transformation..."

The idea being that the x,y-coordinates are in canvas space and hence must be transformed to the current space to do the isPointInPath-test.


Reproducible: Always

Steps to Reproduce:
1. Change canvas transform (translate/rotate/scale.)
2. Use isPointInPath on a point that would have had its return value changed by the transform.

Actual Results:  
The return value didn't change.

Expected Results:  
The return value should've had changed.
Component: General → Layout: Canvas
Product: Firefox → Core
QA Contact: general → layout.canvas
Version: unspecified → Trunk
This bug is INVALID as far as I can tell.
Opera handles isPointInPath coordinates as untransformed coordinates. See test in URL with Firefox vs. Opera. With setTransform, Firefox's behaviour can be worked around.

Attachment #290828 - Flags: review?
Attachment #290828 - Flags: review? → review?(vladimir)
My original explanation of "how to fix" is wrong. The patch works, but the math is: multiply mouse coords by the inverse of the current transformation matrix.  Which the patch does implicitly (changing the matrix changes the path's matrix as well, so transforming the path to the point's matrix equals to transforming the point to the path's matrix.)

It can be worked around on a web page by using setTransform or by manually keeping track of the current transformation matrix and doing multiply(invert(matrix), [x,y,1]). Latter way + bbox / circle test can then be used to implement a crude version of isPointInPath for browsers that lack it.
Ever confirmed: true
Flags: blocking1.9?
WONTFIX'ing this as per bug 380338 -- paths don't get transformed, points do.  Changing the transformation matrix has no effect on the path that's currently built up.
Closed: 17 years ago
Flags: blocking1.9?
Resolution: --- → WONTFIX
Note that you need to keep track of the current transformation matrix on Firefox 2. Implementation is left to the reader. Cheers!
I don't understand why this still is a WONTFIX, but here is a simple testcase of isPointInPath with transformations, and a (very simple) workaround for Mozilla included.
(Sorry, the circles should highlight when you move your mouse over them in the testcase.)
Comment #5 is incorrect. Paths are transformed "IF" there transform is set before the path is drawn. The transform should not be applied retroactively as was being requested in the referenced bug.  As per the specification the isPointInPath method should test the query point "AS IS" again the "transformed" Path.

Please reopen this issue!
Please reopen this, all other modern browsers are implementing correctly and this functionality is critical to making canvas interactive (e.g. is my mouse inside this path after transforms have been applied). 


tested on IE9, Chrome, Opera, Safari (iphone and ipad)
For those struggling with this, a "simple" workaround is to detect the bug, then replace isPointInPath() with a correct one (please excuse the poor formatting, just a copy/paste of old code):

var c2dp = CanvasRenderingContext2D.prototype;

//  special isPointInPath method to workaround Mozilla bug 405300
//      []
function isPointInPath_mozilla( x, y )
    this.setTransform( 1, 0, 0, 1, 0, 0 );
    var ret = this.isPointInPath_old( x, y );
    return ret;

//  test for the presence of the bug, and set the workaround function only if needed
var ctx = document.createElement( "canvas" ).getContext( "2d" );
ctx.translate( 50, 0 );
ctx.moveTo( 125, 50 );
ctx.arc( 100, 50, 25, 0, 360, false );
if( !ctx.isPointInPath( 150, 50 ) )
    c2dp.isPointInPath_old = c2dp.isPointInPath;
    c2dp.isPointInPath = isPointInPath_mozilla;
We should get either the spec or our implementation changed.
Blocks: 622842
Resolution: WONTFIX → ---
Attached patch updated patchSplinter Review
This is an updated patch.
Attachment #290828 - Attachment is obsolete: true
Attachment #533682 - Flags: review?(joe)
Comment on attachment 533682 [details] [diff] [review]
updated patch

Review of attachment 533682 [details] [diff] [review]:

What should we do about the spec issue? The spec needs to be changed if everyone else does something different.
Attachment #533682 - Flags: superreview?(roc)
Attachment #533682 - Flags: review?(joe)
Attachment #533682 - Flags: review+
Everyone else is doing something different, but they're all doing the same thing: following the spec.
Comment on attachment 533682 [details] [diff] [review]
updated patch

Review of attachment 533682 [details] [diff] [review]:

Benjamin's right. This change makes us follow the spec.
Attachment #533682 - Flags: superreview?(roc) → superreview+
Assignee: nobody → benjamin
Closed: 17 years ago13 years ago
Keywords: checkin-needed
Resolution: --- → FIXED
Target Milestone: --- → mozilla7
Documentation updated:

And mentioned on Firefox 7 for developers.
Build identifier: Mozilla/5.0 (X11; Linux x86_64; rv:7.0) Gecko/20100101 Firefox/7.0

All tests mentioned in comment 7 , comment 10 and comment 14 passed. Marking bug as VERIFIED-FIXED.
You need to log in before you can comment on or make changes to this bug.