Text selection and mouse events in Chrome

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Text selection and mouse events in Chrome

mitya
Hi,

We've recently hit a very nasty bug in our qooxdoo desktop app and
recent Chrome/Chromium versions. Symptoms are: if there is a selectable
text inside a qx.ui.window.Window, and you move the window (or just
single-click window header), you won't be able to select text by mouse
dragging anymore (double- or triple-clicking will work however). See a
link [1] to Playground snippet that demonstrates the issue. In case the
link expires, here is the code to run in Playground:

var win = new qx.ui.window.Window("First Window");
win.setWidth(300);
win.setHeight(200);
win.setShowMinimize(false);

this.getRoot().add(win, {left:20, top:20});
win.open();

var label = new qx.ui.basic.Label("Lorem ipsum dolor sit amet").set({
   selectable: true
});

win.add(label);

Now the gory details. As I've already mentioned, the issue is observed
*only* in recent Chrome/Chromium releases, for all desktop platforms;
Firefox and older WebKit-based browsers, like Safari or GNOME Epiphany,
are not affected. Furthermore, we've been able to track this bug down to
particular changeset in Chrome's Blink engine [2]. We didn't bisect
further to determine particular commit, but it seems quite plausible
that the culprit is [3]:

> Make the mousemove event cancellable
> The mouse move event used to be non cancellable in the 90s and
> when the specications changes in 2002-2003, not not everyone noticed.

The change was introduced about two years ago, in Chrome 31.0.1622.0.

Now guys, could you please help me understand what this issue is all
about? If my hypothesis is correct and it has something to do with
mousemove event cancellation, then what's going on? I could probably
suggest that mousemove events for the window, once canceled, are being
kept canceled forever? It's interesting that if you open DOM inspector
and just drag that label's DIV out of the window, somewhere to beginning
of BODY, you'll be able to select text again; that means, only the
window becomes "broken", not the entire application/document.

With all the above - is it a qooxdoo or a Chrome bug? If latter, we
should be able to concoct a plain non-qooxdoo MWE that Chrome guys would
probably expect from us. So here I'm kindly asking your assistance in
isolating (and, hopefully, fixing) this pesky bug.

Cheers,
Dimitri

[1] http://tinyurl.com/osswyny
[2]
http://build.chromium.org/f/chromium/perf/dashboard/ui/changelog_blink.html?url=/trunk&range=157209%3A157206
[3] http://src.chromium.org/viewvc/blink?view=rev&revision=157207

------------------------------------------------------------------------------
_______________________________________________
qooxdoo-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/qooxdoo-devel
Reply | Threaded
Open this post in threaded view
|

Re: Text selection and mouse events in Chrome

John Spackman-3
Hi Dimitri

I’ve been able to find the two stack traces that call preventDefault during a mousemove event, they are:

anonymous(),
qx.event.type.Native.preventDefault,
qx.event.type.Roll.stop,
qx.ui.window.Window._onMoveRoll,
qx.ui.core.EventHandler._dispatchEvent,
qx.event.dispatch.AbstractBubbling.dispatchEvent,
qx.event.Manager.dispatchEvent,
qx.event.Registration.fireEvent,
qx.event.handler.Gesture._fireEvent,
qx.event.handler.GestureCore.prototype._fireRoll(),
qx.event.handler.GestureCore.prototype.gestureMove(),
qx.event.handler.GestureCore.prototype.checkAndFireGesture(),
qx.event.handler.Gesture.prototype.__ho(),
qx.event.handler.Gesture.prototype.checkAndFireGesture(),
anonymous(),
qx.event.dispatch.Direct.prototype.dispatchEvent(),
bP()

anonymous(),
qx.event.type.Native.preventDefault,
qx.ui.core.EventHandler._dispatchEvent,
qx.event.dispatch.AbstractBubbling.dispatchEvent,
qx.event.Manager.dispatchEvent,
qx.event.Registration.fireEvent,
qx.event.handler.Gesture._fireEvent,
qx.event.handler.GestureCore._fireRoll,
qx.event.handler.GestureCore.gestureMove,
qx.event.handler.GestureCore.prototype.checkAndFireGesture(),
qx.event.handler.Gesture.prototype.__ho(),
qx.event.handler.Gesture.prototype.checkAndFireGesture(),
anonymous(),
qx.event.dispatch.Direct.prototype.dispatchEvent(),
bP()

But it’s only the first stack trace that seems to trigger the problem; the gesture code is trying to stop a “gesturemove” event but because the underlying native event is a “mousemove”, it’s the mousemove which is actually getting preventDefault’ed.  To test whether this is a Qooxdoo bug or a Chrome bug, I temporarily patched qx.event.type.Native.preventDefault to read:

    /**

     * Prevent browser default behavior, e.g. opening the context menu, ...

     */

    preventDefault : function()

    {

      this.base(arguments);

      if (this._native._original.type !== "mousemove")

        qx.bom.Event.preventDefault(this._native);

    },


Obviously far too crude a fix for real use but I think it shows that it’s not some other part of Qooxdoo which is subsequently suppressing events because only the browser is being excluded from preventDefault and the problem goes away.

The solution may lie in qx.event.handler.GestureCore.gestureMove, lines 240 onward currently say:

        if(!this.__isMultiPointerGesture) {

          this.__fireTrack("track", domEvent, gesture.target);

          this._fireRoll(domEvent, "touch", gesture.target);

        }


I think that in order to provide a unified touch/pointer event system, the call to this._fireRoll is trying to simulate a touch event (which would be reasonable to want to preventDefault) but it’s associated with the mousemove (domEvent  is a “pointermove” event and domEvent._original is then “mousemove” event), so I’ve tried patching it to this:

        if(!this.__isMultiPointerGesture) {

          if (domEvent._original && domEvent._original.type == "mousemove")

            domEvent.preventDefault = function(){};

          this.__fireTrack("track", domEvent, gesture.target);

          this._fireRoll(domEvent, "touch", gesture.target);

        }


That works, and as a workaround would be targeted at just this problem.  I have not tested it on any platforms which support gestures.

John

On 14/10/2015, 23:47, "Dimitri" <[hidden email]> wrote:

Hi,

We've recently hit a very nasty bug in our qooxdoo desktop app and
recent Chrome/Chromium versions. Symptoms are: if there is a selectable
text inside a qx.ui.window.Window, and you move the window (or just
single-click window header), you won't be able to select text by mouse
dragging anymore (double- or triple-clicking will work however). See a
link [1] to Playground snippet that demonstrates the issue. In case the
link expires, here is the code to run in Playground:

var win = new qx.ui.window.Window("First Window");
win.setWidth(300);
win.setHeight(200);
win.setShowMinimize(false);

this.getRoot().add(win, {left:20, top:20});
win.open();

var label = new qx.ui.basic.Label("Lorem ipsum dolor sit amet").set({
   selectable: true
});

win.add(label);

Now the gory details. As I've already mentioned, the issue is observed
*only* in recent Chrome/Chromium releases, for all desktop platforms;
Firefox and older WebKit-based browsers, like Safari or GNOME Epiphany,
are not affected. Furthermore, we've been able to track this bug down to
particular changeset in Chrome's Blink engine [2]. We didn't bisect
further to determine particular commit, but it seems quite plausible
that the culprit is [3]:

Make the mousemove event cancellable
The mouse move event used to be non cancellable in the 90s and
when the specications changes in 2002-2003, not not everyone noticed.

The change was introduced about two years ago, in Chrome 31.0.1622.0.

Now guys, could you please help me understand what this issue is all
about? If my hypothesis is correct and it has something to do with
mousemove event cancellation, then what's going on? I could probably
suggest that mousemove events for the window, once canceled, are being
kept canceled forever? It's interesting that if you open DOM inspector
and just drag that label's DIV out of the window, somewhere to beginning
of BODY, you'll be able to select text again; that means, only the
window becomes "broken", not the entire application/document.

With all the above - is it a qooxdoo or a Chrome bug? If latter, we
should be able to concoct a plain non-qooxdoo MWE that Chrome guys would
probably expect from us. So here I'm kindly asking your assistance in
isolating (and, hopefully, fixing) this pesky bug.

Cheers,
Dimitri

[2]

------------------------------------------------------------------------------
_______________________________________________
qooxdoo-devel mailing list


------------------------------------------------------------------------------

_______________________________________________
qooxdoo-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/qooxdoo-devel
Reply | Threaded
Open this post in threaded view
|

Re: Text selection and mouse events in Chrome

John Spackman-3
Actually thinking about it, when I said that my quick hack in qx.event.type.Native.preventDefault showed it can’t be another part of Qooxdoo causing the problem, that’s not true because there could be multiple native event handlers for mousemove within Qooxdoo.  That would need to be eliminated, but hopefully straightforward to track down and prove or disprove.

Hope it helps anyway :)

John

From: John Spackman
Reply-To: qooxdoo Development
Date: Thursday, 15 October 2015 at 09:55
To: qooxdoo Development
Subject: Re: [qooxdoo-devel] Text selection and mouse events in Chrome

Hi Dimitri

I’ve been able to find the two stack traces that call preventDefault during a mousemove event, they are:

anonymous(),
qx.event.type.Native.preventDefault,
qx.event.type.Roll.stop,
qx.ui.window.Window._onMoveRoll,
qx.ui.core.EventHandler._dispatchEvent,
qx.event.dispatch.AbstractBubbling.dispatchEvent,
qx.event.Manager.dispatchEvent,
qx.event.Registration.fireEvent,
qx.event.handler.Gesture._fireEvent,
qx.event.handler.GestureCore.prototype._fireRoll(),
qx.event.handler.GestureCore.prototype.gestureMove(),
qx.event.handler.GestureCore.prototype.checkAndFireGesture(),
qx.event.handler.Gesture.prototype.__ho(),
qx.event.handler.Gesture.prototype.checkAndFireGesture(),
anonymous(),
qx.event.dispatch.Direct.prototype.dispatchEvent(),
bP()

anonymous(),
qx.event.type.Native.preventDefault,
qx.ui.core.EventHandler._dispatchEvent,
qx.event.dispatch.AbstractBubbling.dispatchEvent,
qx.event.Manager.dispatchEvent,
qx.event.Registration.fireEvent,
qx.event.handler.Gesture._fireEvent,
qx.event.handler.GestureCore._fireRoll,
qx.event.handler.GestureCore.gestureMove,
qx.event.handler.GestureCore.prototype.checkAndFireGesture(),
qx.event.handler.Gesture.prototype.__ho(),
qx.event.handler.Gesture.prototype.checkAndFireGesture(),
anonymous(),
qx.event.dispatch.Direct.prototype.dispatchEvent(),
bP()

But it’s only the first stack trace that seems to trigger the problem; the gesture code is trying to stop a “gesturemove” event but because the underlying native event is a “mousemove”, it’s the mousemove which is actually getting preventDefault’ed.  To test whether this is a Qooxdoo bug or a Chrome bug, I temporarily patched qx.event.type.Native.preventDefault to read:

    /**

     * Prevent browser default behavior, e.g. opening the context menu, ...

     */

    preventDefault : function()

    {

      this.base(arguments);

      if (this._native._original.type !== "mousemove")

        qx.bom.Event.preventDefault(this._native);

    },


Obviously far too crude a fix for real use but I think it shows that it’s not some other part of Qooxdoo which is subsequently suppressing events because only the browser is being excluded from preventDefault and the problem goes away.

The solution may lie in qx.event.handler.GestureCore.gestureMove, lines 240 onward currently say:

        if(!this.__isMultiPointerGesture) {

          this.__fireTrack("track", domEvent, gesture.target);

          this._fireRoll(domEvent, "touch", gesture.target);

        }


I think that in order to provide a unified touch/pointer event system, the call to this._fireRoll is trying to simulate a touch event (which would be reasonable to want to preventDefault) but it’s associated with the mousemove (domEvent  is a “pointermove” event and domEvent._original is then “mousemove” event), so I’ve tried patching it to this:

        if(!this.__isMultiPointerGesture) {

          if (domEvent._original && domEvent._original.type == "mousemove")

            domEvent.preventDefault = function(){};

          this.__fireTrack("track", domEvent, gesture.target);

          this._fireRoll(domEvent, "touch", gesture.target);

        }


That works, and as a workaround would be targeted at just this problem.  I have not tested it on any platforms which support gestures.

John

On 14/10/2015, 23:47, "Dimitri" <[hidden email]> wrote:

Hi,

We've recently hit a very nasty bug in our qooxdoo desktop app and
recent Chrome/Chromium versions. Symptoms are: if there is a selectable
text inside a qx.ui.window.Window, and you move the window (or just
single-click window header), you won't be able to select text by mouse
dragging anymore (double- or triple-clicking will work however). See a
link [1] to Playground snippet that demonstrates the issue. In case the
link expires, here is the code to run in Playground:

var win = new qx.ui.window.Window("First Window");
win.setWidth(300);
win.setHeight(200);
win.setShowMinimize(false);

this.getRoot().add(win, {left:20, top:20});
win.open();

var label = new qx.ui.basic.Label("Lorem ipsum dolor sit amet").set({
   selectable: true
});

win.add(label);

Now the gory details. As I've already mentioned, the issue is observed
*only* in recent Chrome/Chromium releases, for all desktop platforms;
Firefox and older WebKit-based browsers, like Safari or GNOME Epiphany,
are not affected. Furthermore, we've been able to track this bug down to
particular changeset in Chrome's Blink engine [2]. We didn't bisect
further to determine particular commit, but it seems quite plausible
that the culprit is [3]:

Make the mousemove event cancellable
The mouse move event used to be non cancellable in the 90s and
when the specications changes in 2002-2003, not not everyone noticed.

The change was introduced about two years ago, in Chrome 31.0.1622.0.

Now guys, could you please help me understand what this issue is all
about? If my hypothesis is correct and it has something to do with
mousemove event cancellation, then what's going on? I could probably
suggest that mousemove events for the window, once canceled, are being
kept canceled forever? It's interesting that if you open DOM inspector
and just drag that label's DIV out of the window, somewhere to beginning
of BODY, you'll be able to select text again; that means, only the
window becomes "broken", not the entire application/document.

With all the above - is it a qooxdoo or a Chrome bug? If latter, we
should be able to concoct a plain non-qooxdoo MWE that Chrome guys would
probably expect from us. So here I'm kindly asking your assistance in
isolating (and, hopefully, fixing) this pesky bug.

Cheers,
Dimitri

[2]

------------------------------------------------------------------------------
_______________________________________________
qooxdoo-devel mailing list

------------------------------------------------------------------------------ _______________________________________________ qooxdoo-devel mailing list [hidden email] https://lists.sourceforge.net/lists/listinfo/qooxdoo-devel

------------------------------------------------------------------------------

_______________________________________________
qooxdoo-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/qooxdoo-devel
Reply | Threaded
Open this post in threaded view
|

Re: Text selection and mouse events in Chrome

Andreas Ecker-2
Dimitri, John,

thanks for the detailed report and analysis. Created a bugzilla entry, so that everyone can contribute to and follow-up on this issue:

@Dimitri: Added it on your behalf, but couldn’t add you to the CC List of the bug. Please add yourself to the qooxdoo bugzilla and to this particular bug.

Andreas


Von: John Spackman <[hidden email]>
Antworten an: qooxdoo Development <[hidden email]>
Datum: Donnerstag, 15. Oktober 2015 11:03
An: qooxdoo Development <[hidden email]>
Betreff: Re: [qooxdoo-devel] Text selection and mouse events in Chrome

Actually thinking about it, when I said that my quick hack in qx.event.type.Native.preventDefault showed it can’t be another part of Qooxdoo causing the problem, that’s not true because there could be multiple native event handlers for mousemove within Qooxdoo.  That would need to be eliminated, but hopefully straightforward to track down and prove or disprove.

Hope it helps anyway :)

John

From: John Spackman
Reply-To: qooxdoo Development
Date: Thursday, 15 October 2015 at 09:55
To: qooxdoo Development
Subject: Re: [qooxdoo-devel] Text selection and mouse events in Chrome

Hi Dimitri

I’ve been able to find the two stack traces that call preventDefault during a mousemove event, they are:

anonymous(),
qx.event.type.Native.preventDefault,
qx.event.type.Roll.stop,
qx.ui.window.Window._onMoveRoll,
qx.ui.core.EventHandler._dispatchEvent,
qx.event.dispatch.AbstractBubbling.dispatchEvent,
qx.event.Manager.dispatchEvent,
qx.event.Registration.fireEvent,
qx.event.handler.Gesture._fireEvent,
qx.event.handler.GestureCore.prototype._fireRoll(),
qx.event.handler.GestureCore.prototype.gestureMove(),
qx.event.handler.GestureCore.prototype.checkAndFireGesture(),
qx.event.handler.Gesture.prototype.__ho(),
qx.event.handler.Gesture.prototype.checkAndFireGesture(),
anonymous(),
qx.event.dispatch.Direct.prototype.dispatchEvent(),
bP()

anonymous(),
qx.event.type.Native.preventDefault,
qx.ui.core.EventHandler._dispatchEvent,
qx.event.dispatch.AbstractBubbling.dispatchEvent,
qx.event.Manager.dispatchEvent,
qx.event.Registration.fireEvent,
qx.event.handler.Gesture._fireEvent,
qx.event.handler.GestureCore._fireRoll,
qx.event.handler.GestureCore.gestureMove,
qx.event.handler.GestureCore.prototype.checkAndFireGesture(),
qx.event.handler.Gesture.prototype.__ho(),
qx.event.handler.Gesture.prototype.checkAndFireGesture(),
anonymous(),
qx.event.dispatch.Direct.prototype.dispatchEvent(),
bP()

But it’s only the first stack trace that seems to trigger the problem; the gesture code is trying to stop a “gesturemove” event but because the underlying native event is a “mousemove”, it’s the mousemove which is actually getting preventDefault’ed.  To test whether this is a Qooxdoo bug or a Chrome bug, I temporarily patched qx.event.type.Native.preventDefault to read:

    /**

     * Preventbrowser defaultbehavior,e.g. openingthe contextmenu, ...

     */

    preventDefault : function()

    {

      this.base(arguments);

      if (this._native._original.type !== "mousemove")

        qx.bom.Event.preventDefault(this._native);

    },


Obviously far too crude a fix for real use but I think it shows that it’s not some other part of Qooxdoo which is subsequently suppressing events because only the browser is being excluded from preventDefault and the problem goes away.

The solution may lie in qx.event.handler.GestureCore.gestureMove, lines 240 onward currently say:

        if(!this.__isMultiPointerGesture) {

          this.__fireTrack("track", domEvent, gesture.target);

          this._fireRoll(domEvent, "touch", gesture.target);

        }


I think that in order to provide a unified touch/pointer event system, the call to this._fireRoll is trying to simulate a touch event (which would be reasonable to want to preventDefault) but it’s associated with the mousemove (domEvent  is a “pointermove” event and domEvent._original is then “mousemove” event), so I’ve tried patching it to this:

        if(!this.__isMultiPointerGesture) {

          if (domEvent._original && domEvent._original.type == "mousemove")

            domEvent.preventDefault = function(){};

          this.__fireTrack("track", domEvent, gesture.target);

          this._fireRoll(domEvent, "touch", gesture.target);

        }


That works, and as a workaround would be targeted at just this problem.  I have not tested it on any platforms which support gestures.

John

On 14/10/2015, 23:47, "Dimitri" <[hidden email]> wrote:

Hi,

We've recently hit a very nasty bug in our qooxdoo desktop app and
recent Chrome/Chromium versions. Symptoms are: if there is a selectable
text inside a qx.ui.window.Window, and you move the window (or just
single-click window header), you won't be able to select text by mouse
dragging anymore (double- or triple-clicking will work however). See a
link [1] to Playground snippet that demonstrates the issue. In case the
link expires, here is the code to run in Playground:

var win = new qx.ui.window.Window("First Window");
win.setWidth(300);
win.setHeight(200);
win.setShowMinimize(false);

this.getRoot().add(win, {left:20, top:20});
win.open();

var label = new qx.ui.basic.Label("Lorem ipsum dolor sit amet").set({
   selectable: true
});

win.add(label);

Now the gory details. As I've already mentioned, the issue is observed
*only* in recent Chrome/Chromium releases, for all desktop platforms;
Firefox and older WebKit-based browsers, like Safari or GNOME Epiphany,
are not affected. Furthermore, we've been able to track this bug down to
particular changeset in Chrome's Blink engine [2]. We didn't bisect
further to determine particular commit, but it seems quite plausible
that the culprit is [3]:

Make the mousemove event cancellable
The mouse move event used to be non cancellable in the 90s and
when the specications changes in 2002-2003, not not everyone noticed.

The change was introduced about two years ago, in Chrome 31.0.1622.0.

Now guys, could you please help me understand what this issue is all
about? If my hypothesis is correct and it has something to do with
mousemove event cancellation, then what's going on? I could probably
suggest that mousemove events for the window, once canceled, are being
kept canceled forever? It's interesting that if you open DOM inspector
and just drag that label's DIV out of the window, somewhere to beginning
of BODY, you'll be able to select text again; that means, only the
window becomes "broken", not the entire application/document.

With all the above - is it a qooxdoo or a Chrome bug? If latter, we
should be able to concoct a plain non-qooxdoo MWE that Chrome guys would
probably expect from us. So here I'm kindly asking your assistance in
isolating (and, hopefully, fixing) this pesky bug.

Cheers,
Dimitri

[2]

------------------------------------------------------------------------------
_______________________________________________
qooxdoo-devel mailing list

------------------------------------------------------------------------------ _______________________________________________ qooxdoo-devel mailing list [hidden email]https://lists.sourceforge.net/lists/listinfo/qooxdoo-devel

------------------------------------------------------------------------------

_______________________________________________
qooxdoo-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/qooxdoo-devel
Reply | Threaded
Open this post in threaded view
|

Re: Text selection and mouse events in Chrome

mitya
Andreas, thanks for filing the bug, I was about to do the same.

John, thanks a lot for your detailed explanation. I think we should
continue in Bugzilla. There are some interesting observations I have
made and going to share. See you there!

Dimitri

Andreas Ecker wrote:

> Dimitri, John,
>
> thanks for the detailed report and analysis. Created a bugzilla entry,
> so that everyone can contribute to and follow-up on this issue:
> http://bugzilla.qooxdoo.org/show_bug.cgi?id=9218 [5]
>
> @Dimitri: Added it on your behalf, but couldn’t add you to the CC
> List of the bug. Please add yourself to the qooxdoo bugzilla and to
> this particular bug.
>
> Andreas


------------------------------------------------------------------------------
_______________________________________________
qooxdoo-devel mailing list
[hidden email]
https://lists.sourceforge.net/lists/listinfo/qooxdoo-devel