Changeset 53184 in webkit


Ignore:
Timestamp:
Jan 13, 2010 7:24:14 AM (14 years ago)
Author:
pfeldman@chromium.org
Message:

2010-01-13 Pavel Feldman <pfeldman@chromium.org>

Reviewed by Timothy Hatcher.

Web Inspector: Scrolling editor to the 20Kth line is not smooth.

https://bugs.webkit.org/show_bug.cgi?id=33587

  • inspector/front-end/TextEditor.js: (WebInspector.TextEditor): (WebInspector.TextEditor.prototype._textChanged): (WebInspector.TextEditor.prototype._highlightChanged): (WebInspector.TextEditor.prototype._paintLinesContinuation):
  • inspector/front-end/TextEditorHighlighter.js: (WebInspector.TextEditorHighlighter): (WebInspector.TextEditorHighlighter.prototype.highlight): (WebInspector.TextEditorHighlighter.prototype._highlightInChunks): (WebInspector.TextEditorHighlighter.prototype.updateHighlight): (WebInspector.TextEditorHighlighter.prototype._highlightLines): (WebInspector.TextEditorHighlighter.prototype._lex):
  • inspector/front-end/TextEditorModel.js: (WebInspector.TextEditorModel.prototype._setLine): (WebInspector.TextEditorModel.prototype.setAttribute): (WebInspector.TextEditorModel.prototype.getAttribute): (WebInspector.TextEditorModel.prototype.removeAttribute):
Location:
trunk/WebCore
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/WebCore/ChangeLog

    r53183 r53184  
     12010-01-13  Pavel Feldman  <pfeldman@chromium.org>
     2
     3        Reviewed by Timothy Hatcher.
     4
     5        Web Inspector: Scrolling editor to the 20Kth line is not smooth.
     6
     7        https://bugs.webkit.org/show_bug.cgi?id=33587
     8
     9        * inspector/front-end/TextEditor.js:
     10        (WebInspector.TextEditor):
     11        (WebInspector.TextEditor.prototype._textChanged):
     12        (WebInspector.TextEditor.prototype._highlightChanged):
     13        (WebInspector.TextEditor.prototype._paintLinesContinuation):
     14        * inspector/front-end/TextEditorHighlighter.js:
     15        (WebInspector.TextEditorHighlighter):
     16        (WebInspector.TextEditorHighlighter.prototype.highlight):
     17        (WebInspector.TextEditorHighlighter.prototype._highlightInChunks):
     18        (WebInspector.TextEditorHighlighter.prototype.updateHighlight):
     19        (WebInspector.TextEditorHighlighter.prototype._highlightLines):
     20        (WebInspector.TextEditorHighlighter.prototype._lex):
     21        * inspector/front-end/TextEditorModel.js:
     22        (WebInspector.TextEditorModel.prototype._setLine):
     23        (WebInspector.TextEditorModel.prototype.setAttribute):
     24        (WebInspector.TextEditorModel.prototype.getAttribute):
     25        (WebInspector.TextEditorModel.prototype.removeAttribute):
     26
    1272010-01-13  Jocelyn Turcotte  <jocelyn.turcotte@nokia.com>
    228
  • trunk/WebCore/inspector/front-end/TextEditor.js

    r53052 r53184  
    3232{
    3333    this._textModel = new WebInspector.TextEditorModel(this._textChanged.bind(this));
    34     this._highlighter = new WebInspector.TextEditorHighlighter(this._textModel);
     34    this._highlighter = new WebInspector.TextEditorHighlighter(this._textModel, this._highlightChanged.bind(this));
    3535
    3636    this.element = document.createElement("div");
     
    184184            this._invalidateLines(newRange.startLine, this._textModel.linesCount + Math.max(0, oldRange.endLine - newRange.endLine));
    185185
    186         this._invalidateHighlight(newRange.startLine);
     186        if (this._highlightingEnabled) {
     187            var lastVisibleLine = Math.min(this._textModel.linesCount, this._offsetToLineNumber(this._scrollTop + this._canvas.height) + 1);
     188            this._highlighter.updateHighlight(newRange.startLine, lastVisibleLine);
     189        }
     190
    187191        this._updateSize(newRange.startLine, Math.max(newRange.endLine, oldRange.endLine));
    188192        if (oldRange.linesCount !== newRange.linesCount) {
     
    206210        this._invalidateLines(oldRange.startLine, oldRange.endLine + 1);
    207211        this._invalidateLines(newRange.startLine, newRange.endLine + 1);
     212        this._paint();
     213    },
     214
     215    _highlightChanged: function(fromLine, toLine)
     216    {
     217        this._invalidateLines(fromLine, toLine + 1);
    208218        this._paint();
    209219    },
     
    321331        lastLine = Math.min(lastLine, this._textModel.linesCount);
    322332
     333        if (this._highlightingEnabled)
     334            this._highlighter.highlight(lastLine);
     335
    323336        if (this._selection.startLine === this._selection.endLine && firstLine <= this._selection.startLine && this._selection.startLine < lastLine)
    324337            this._paintCurrentLine(this._selection.startLine);
    325 
    326         if (this._highlightingEnabled)
    327             this._highlighter.highlight(firstLine, lastLine);
    328338
    329339        this._paintSelection(firstLine, lastLine);
     
    339349            }
    340350
    341             var attributes = this._textModel.getAttributes(i, "highlight");
     351            var highlighterState = this._textModel.getAttribute(i, "highlighter-state");
    342352            var plainTextStart = -1;
    343353            for (var j = 0; j < line.length;) {
    344                 var attribute = attributes && attributes[j];
     354                var attribute = highlighterState && highlighterState.attributes[j];
    345355                if (!attribute || !attribute.style) {
    346356                    if (plainTextStart === -1)
     
    631641    },
    632642
    633     _invalidateHighlight: function(startLine)
    634     {
    635         if (!this._highlightingEnabled)
    636             return;
    637         var firstVisibleLine = Math.max(0, this._offsetToLineNumber(this._scrollTop) - 1);
    638         var lastVisibleLine = Math.min(this._textModel.linesCount, this._offsetToLineNumber(this._scrollTop + this._canvas.height) + 1);
    639 
    640         var damage = this._highlighter.highlight(startLine, lastVisibleLine);
    641         for (var line in damage)
    642             this._invalidateLines(line, parseInt(line) + 1);
    643     },
    644 
    645643    _paintSelection: function(firstLine, lastLine)
    646644    {
  • trunk/WebCore/inspector/front-end/TextEditorHighlighter.js

    r52985 r53184  
    3030 */
    3131
    32 WebInspector.TextEditorHighlighter = function(textModel)
     32WebInspector.TextEditorHighlighter = function(textModel, damageCallback)
    3333{
    3434    this._textModel = textModel;
     
    4141    this._styles["keyword"] = "rgb(170, 13, 145)";
    4242    this._styles["number"] = "rgb(28, 0, 207)";
     43
     44    this._damageCallback = damageCallback;   
    4345}
    4446
    4547WebInspector.TextEditorHighlighter.prototype = {
    46     highlight: function(startLine, endLine)
     48    highlight: function(endLine)
    4749    {
    48         // Rewind to the last highlighted line to gain proper highlighter context.
    49         while (startLine > 0 && !this._textModel.getAttribute(startLine - 1, 0, "highlighter-state"))
     50        // First check if we have work to do.
     51        var state = this._textModel.getAttribute(endLine - 1, "highlighter-state")
     52        if (state && !state.outOfDate) {
     53            // Last line is highlighted, just exit.
     54            return;
     55        }
     56
     57        this._requestedEndLine = endLine;
     58
     59        if (this._highlightTimer) {
     60            // There is a timer scheduled, it will catch the new job based on the new endLine set.
     61            return;
     62        }
     63
     64        // We will be highlighting. First rewind to the last highlighted line to gain proper highlighter context.
     65        var startLine = endLine;
     66        while (startLine > 0) {
     67            var state = this._textModel.getAttribute(startLine - 1, "highlighter-state");
     68            if (state && !state.outOfDate)
     69                break;
    5070            startLine--;
     71        }
    5172
     73        // Do small highlight synchronously. This will provide instant highlight on PageUp / PageDown, gentle scrolling.
     74        var toLine = Math.min(startLine + 200, endLine);
     75        this._highlightLines(startLine, toLine);
     76
     77        // Schedule tail highlight if necessary.
     78        if (endLine > toLine)
     79            this._highlightTimer = setTimeout(this._highlightInChunks.bind(this, toLine, endLine), 100);
     80    },
     81
     82    _highlightInChunks: function(startLine, endLine)
     83    {
     84        delete this._highlightTimer;
     85
     86        // First we always check if we have work to do. Could be that user scrolled back and we can quit.
     87        var state = this._textModel.getAttribute(this._requestedEndLine - 1, "highlighter-state");
     88        if (state && !state.outOfDate)
     89            return;
     90
     91        if (this._requestedEndLine !== endLine) {
     92            // User keeps updating the job in between of our timer ticks. Just reschedule self, don't eat CPU (they must be scrolling).
     93            this._highlightTimer = setTimeout(this._highlightInChunks.bind(this, startLine, this._requestedEndLine), 200);
     94            return;
     95        }
     96
     97        // Highlight 500 lines chunk.
     98        var toLine = Math.min(startLine + 500, this._requestedEndLine);
     99        this._highlightLines(startLine, toLine);
     100
     101        // Schedule tail highlight if necessary.
     102        if (toLine < this._requestedEndLine)
     103            this._highlightTimer = setTimeout(this._highlightInChunks.bind(this, toLine, this._requestedEndLine), 10);
     104    },
     105
     106    updateHighlight: function(startLine, endLine)
     107    {
     108        // Start line was edited, we should highlight everything until endLine synchronously.
     109        var state = this._textModel.getAttribute(startLine, "highlighter-state");
     110        if (!state || state.outOfDate) {
     111            // Highlighter did not reach this point yet, nothing to update. It will reach it on subsequent timer tick and do the job.
     112            return;
     113        }
     114
     115        var restored = this._highlightLines(startLine, endLine);
     116
     117        // Set invalidated flag to the subsequent lines.
     118        for (var i = endLine; i < this._textModel.linesCount; ++i) {
     119            var highlighterState = this._textModel.getAttribute(i, "highlighter-state");
     120            if (highlighterState)
     121                highlighterState.outOfDate = !restored;
     122            else
     123                return;
     124        }
     125    },
     126
     127    _highlightLines: function(startLine, endLine)
     128    {
    52129        // Restore highlighter context taken from previous line.
    53         var state = this._textModel.getAttribute(startLine - 1, 0, "highlighter-state");
    54          if (state)
    55              this._tokenizer.condition = state.postCondition;
    56          else
    57              this._tokenizer.condition = this._tokenizer.initialCondition;
    58         // Each line has associated state attribute with pre- and post-highlighter conditions.
    59         // Highlight lines from range until we find line precondition matching highlighter state.
    60         var damage = {};
     130        var state = this._textModel.getAttribute(startLine - 1, "highlighter-state");
     131        if (state)
     132            this._tokenizer.condition = state.postCondition;
     133        else
     134            this._tokenizer.condition = this._tokenizer.initialCondition;
     135
     136        var damagedFrom = startLine;
     137        var damagedTo = startLine;
    61138        for (var i = startLine; i < endLine; ++i) {
    62             state = this._textModel.getAttribute(i, 0, "highlighter-state");
    63             if (state && state.preCondition === this._tokenizer.condition) {
    64                 // Following lines are up to date, no need re-highlight.
    65                 this._tokenizer.condition = state.postCondition;
    66                 continue;
    67             }
    68 
    69             damage[i] = true;
     139            damagedTo = i;
    70140
    71141            state = {};
    72142            state.preCondition = this._tokenizer.condition;
     143            state.attributes = {};
    73144
    74             this._textModel.removeAttributes(i, "highlight");
    75             this._lex(this._textModel.line(i), i);
     145            this._lex(this._textModel.line(i), i, state.attributes);
    76146
    77147            state.postCondition = this._tokenizer.condition;
    78             this._textModel.addAttribute(i, 0, "highlighter-state", state);
     148            this._textModel.setAttribute(i, "highlighter-state", state);
     149
     150            var nextLineState = this._textModel.getAttribute(i + 1, "highlighter-state");
     151            if (nextLineState && nextLineState.preCondition === state.postCondition) {
     152                // Following lines are up to date, no need re-highlight.
     153                this._damageCallback(damagedFrom, damagedTo);
     154                return true;
     155            }
    79156        }
    80 
    81         state = this._textModel.getAttribute(endLine, 0, "highlighter-state");
    82 
    83         if (state && state.preCondition !== this._tokenizer.condition) {
    84             // Requested highlight range is over, but we did not recover. Invalidate tail highlighting.
    85             for (var i = endLine; i < this._textModel.linesCount; ++i)
    86                 this._textModel.removeAttributes(i, "highlighter-state");
    87         }
    88         return damage;
     157        this._damageCallback(damagedFrom, damagedTo);
     158        return false;
    89159    },
    90160
    91     _lex: function(line, lineNumber) {
     161    _lex: function(line, lineNumber, attributes) {
    92162         this._tokenizer.line = line;
    93163         var column = 0;
     
    96166             var tokenType = this._tokenizer.tokenType;
    97167             if (tokenType)
    98                  this._textModel.addAttribute(lineNumber, column, "highlight", { length: newColumn - column, style: this._styles[tokenType] });
     168                 attributes[column] = { length: newColumn - column, style: this._styles[tokenType] };
    99169             column = newColumn;
    100170         } while (column < line.length)
  • trunk/WebCore/inspector/front-end/TextEditorModel.js

    r52945 r53184  
    137137    {
    138138        this._lines[lineNumber] = text;
    139         delete this._attributes[lineNumber];
    140139    },
    141140
     
    187186    },
    188187
    189     addAttribute: function(line, column, name, value)
     188    setAttribute: function(line, name, value)
    190189    {
    191190        var attrs = this._attributes[line];
     
    194193            this._attributes[line] = attrs;
    195194        }
    196         var family = attrs[name];
    197         if (!family) {
    198             family = [];
    199             attrs[name] = family;
    200         }
    201         family[column] = value;
    202     },
    203 
    204     getAttribute: function(line, column, name)
    205     {
    206         var family = this.getAttributes(line, name);
    207         return family ? family[column] : null;
    208     },
    209 
    210     getAttributes: function(line, name)
     195        attrs[name] = value;
     196    },
     197
     198    getAttribute: function(line, name)
    211199    {
    212200        var attrs = this._attributes[line];
     
    214202    },
    215203
    216     removeAttributes: function(line, name)
     204    removeAttribute: function(line, name)
    217205    {
    218206        var attrs = this._attributes[line];
Note: See TracChangeset for help on using the changeset viewer.