marijnh/CodeMirror2 — pull request #473 by njx (2012-03-30 21:50:12+00:00)
Title: Fix scrolling flicker in WebKit and IE9+

The current CodeMirror virtual scrolling approach relies on sliding the "mover" div around within a large scroll region as the user scrolls. In Firefox, this looks fine, but in Chrome, Safari, and IE, scrolling in large documents is flickery--portions of the code flash in and out during scrolling. This is because the browser actually moves the mover div offscreen during the scroll before CodeMirror gets a chance to reposition the div, causing some or all of the scroller to draw a blank square briefly before the mover div is repositioned.

This pull request introduces a new "flickerFix" option which is true by default in all browsers except Firefox and IE <9 (see below for explanation why). With flickerFix set to true, we suppress the standard vertical scrollbar within the scroller itself, and create a separate div that's exactly the width of its scrollbar. Within that div, we create a tall inner div that's set to the virtual height of the document--this inner div is invisible (and always blank), but lets us set the scroll thumb position and size of the scrollbar. In the main scroll region, the mover div only slides around a (relatively) small amount in order to match its top visible pixel with the virtual scroll position--it never slides all the way off the screen. This eliminates the flicker.

From the point of view of other code within CodeMirror, the only difference is that any code which needs to access the scrollTop or scrollHeight of the scroller div now needs to look at "vScrollElt" instead. With flickerFix off, this is just set to the scroller as in the original code, but with flickerFix on it's set to the vertical scrollbar. Horizontal scrolling is still handled by the scroller itself.

In addition to listening to onScroll events from the separate scrollbar, we also listen to mousewheel/touch scroll events on the scroller itself and handle them manually for vertical scrolls.

There is a little messiness in the CSS for dealing with OS X Lion. In that case, we need to make the scrollbar overlap the content (the OS takes care of auto-hiding it when it's not in use). We also have to prop open the scrollbar div to a minimum width in some browsers.

As noted above, we disable the new flicker-fix code on Firefox and IE <9 by default. In the case of Firefox, the original approach doesn't flicker anyway, and we found that touch scrolling felt less smooth with the flicker-fix code because of the limited resolution of the mousewheel events that Firefox generates during a touch-throw scroll. (Aside from that, though, the flicker-fix code does work fine in Firefox.)

In the case of IE <9, we ran into some browser bugs, and rather than trying to build nasty workarounds into the flicker-fix code, we felt that it was better to just explicitly not support those older versions of IE.

We've tested the new flicker-fix approach in the most recent versions of Chrome, Safari and IE9. We also tested Firefox and IE 7/8 to make sure that the old scrolling code is still working properly in those cases (i.e., we didn't break the old behavior). We tested all browsers on Windows XP, Windows 7, Mac OS X Snow Leopard (10.6), and Mac OS X Lion (10.7).

I'll add some line notes to the diffs to explain some of the less obvious bits of code.

=====

Legalese: The attached code is covered by the MIT license as follows.

Copyright ©2012 Adobe Systems Incorporated. All Rights Reserved.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.