[SCM] WebKit Debian packaging branch, webkit-1.1, updated. upstream/1.1.21-584-g1e41756

pfeldman at chromium.org pfeldman at chromium.org
Fri Feb 26 22:17:46 UTC 2010


The following commit has been merged in the webkit-1.1 branch:
commit 7bfdcfff540e4cfcd8491e6c5309e69f0b9dad28
Author: pfeldman at chromium.org <pfeldman at chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Thu Feb 11 17:16:57 2010 +0000

    2010-02-11  Pavel Feldman  <pfeldman at chromium.org>
    
            Reviewed by Timothy Hatcher.
    
            Web Inspector: split source code into chunks in order to improve text
            viewer performance on large files.
    
            https://bugs.webkit.org/show_bug.cgi?id=34816
    
            This change brings back SourceFrame's canvas+style magic, restores line
            wrapping and makes things a lot like they used to be.
            It removes TextEditor for now and renames NativeTextViewer into TextViewer.
            TextViewer is no longer derived from TextEditor.
            This TextViewer is still based on TextEditorModel, no iframes are involved.
    
            Instead of creating div per line, TextViewer splits source code into 50 line
            chunks. Upon scroll event, visible chunks are sharded into lines and individual
            lines are highlighted. Whenever highlighted region gets outside of the visible
            area, highlight spans are thrown away and region is replaced with the original
            plain text chunk.
    
            Complex stuff:
            - Whenever there is a need to manipulate individual lines (add message bubble /
            set breakpoint / reveal / etc.), individual chunks for such lines are created.
            - There is also an implicit machinery that is maintaining selection when it
            goes beyond the visible area.
            - Search occurrences are implemented as artificial spans interweaving
            highlighting markup.
    
            * WebCore.gypi:
            * WebCore.vcproj/WebCore.vcproj:
            * inspector/front-end/NativeTextViewer.js: Removed.
            * inspector/front-end/ScriptView.js:
            (WebInspector.ScriptView):
            * inspector/front-end/Settings.js:
            * inspector/front-end/SourceFrame.js:
            (WebInspector.SourceFrame):
            (WebInspector.SourceFrame.prototype.set visible):
            (WebInspector.SourceFrame.prototype.set executionLine):
            (WebInspector.SourceFrame.prototype.revealLine):
            (WebInspector.SourceFrame.prototype.addBreakpoint):
            (WebInspector.SourceFrame.prototype.removeBreakpoint):
            (WebInspector.SourceFrame.prototype.addMessage):
            (WebInspector.SourceFrame.prototype.clearMessages):
            (WebInspector.SourceFrame.prototype.sizeToFitContentHeight):
            (WebInspector.SourceFrame.prototype.setContent):
            (WebInspector.SourceFrame.prototype.highlightLine):
            (WebInspector.SourceFrame.prototype._createViewerIfNeeded):
            (WebInspector.SourceFrame.prototype.markAndRevealRange):
            (WebInspector.SourceFrame.prototype.clearMarkedRange):
            (WebInspector.SourceFrame.prototype._breakpointChanged):
            (WebInspector.SourceFrame.prototype._updateExecutionLine):
            (WebInspector.SourceFrame.prototype._addMessageToSource):
            (WebInspector.SourceFrame.prototype._addExistingBreakpointsToSource):
            (WebInspector.SourceFrame.prototype._addBreakpointToSource):
            (WebInspector.SourceFrame.prototype._removeBreakpointFromSource):
            (WebInspector.SourceFrame.prototype._mouseDown):
            (WebInspector.SourceFrame.prototype._editBreakpointCondition.committed):
            (WebInspector.SourceFrame.prototype._editBreakpointCondition.dismissed):
            (WebInspector.SourceFrame.prototype._editBreakpointCondition):
            (WebInspector.SourceFrame.prototype._showBreakpointConditionPopup):
            (WebInspector.SourceFrame.prototype._createConditionElement):
            (WebInspector.SourceFrame.prototype._keyDown):
            (WebInspector.SourceFrame.prototype.resize):
            (WebInspector.SourceFrame.prototype._drawProgramCounterInContext):
            (WebInspector.SourceFrame.prototype._drawProgramCounterImageIfNeeded):
            (WebInspector.SourceFrame.prototype._drawBreakpointImagesIfNeeded.drawBreakpoint):
            (WebInspector.SourceFrame.prototype._drawBreakpointImagesIfNeeded):
            * inspector/front-end/SourceView.js:
            (WebInspector.SourceView):
            (WebInspector.SourceView.prototype._removeBreakpoint):
            (WebInspector.SourceView.prototype.searchCanceled):
            (WebInspector.SourceView.prototype._jumpToSearchResult):
            * inspector/front-end/TextEditor.js: Removed.
            * inspector/front-end/TextViewer.js: Added.
            (WebInspector.TextViewer):
            (WebInspector.TextViewer.prototype.set mimeType):
            (WebInspector.TextViewer.prototype.get textModel):
            (WebInspector.TextViewer.prototype.revealLine):
            (WebInspector.TextViewer.prototype.addDecoration):
            (WebInspector.TextViewer.prototype.removeDecoration):
            (WebInspector.TextViewer.prototype.markAndRevealRange):
            (WebInspector.TextViewer.prototype.highlightLine):
            (WebInspector.TextViewer.prototype._textChanged):
            (WebInspector.TextViewer.prototype._createChunkRow):
            (WebInspector.TextViewer.prototype._makeLineAChunk):
            (WebInspector.TextViewer.prototype._indexChunks):
            (WebInspector.TextViewer.prototype._highlightChanged):
            (WebInspector.TextViewer.prototype._scroll):
            (WebInspector.TextViewer.prototype.setCoalescingUpdate):
            (WebInspector.TextViewer.prototype._repaintAll):
            (WebInspector.TextViewer.prototype._chunkForOffset):
            (WebInspector.TextViewer.prototype._chunkNumberForLine):
            (WebInspector.TextViewer.prototype._chunkStartLine):
            (WebInspector.TextViewer.prototype._restoreChunks):
            (WebInspector.TextViewer.prototype._repaint):
            (WebInspector.TextViewer.prototype._getSelection):
            (WebInspector.TextViewer.prototype._restoreSelection):
            (WebInspector.TextViewer.prototype._selectionToPosition):
            (WebInspector.TextViewer.prototype._createLineRow):
            (WebInspector.TextViewer.prototype._paintLine):
            (WebInspector.TextViewer.prototype._createSpan):
            (WebInspector.TextViewer.prototype._createLink):
            (WebInspector.TextViewer.prototype._rewriteHref):
            (WebInspector.TextViewer.prototype._markRange):
            (WebInspector.TextViewer.prototype._decimalDigits):
            (WebInspector.TextViewer.prototype.resize):
            * inspector/front-end/WebKit.qrc:
            * inspector/front-end/inspector.css:
            * inspector/front-end/inspector.html:
            * inspector/front-end/textEditor.css: Removed.
            * inspector/front-end/textViewer.css: Added.
            * inspector/front-end/utilities.js:
            (Node.prototype.traverseNextTextNode):
            (Node.prototype.rangeBoundaryForOffset):
    
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@54657 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index a977b76..f3e41d3 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,119 @@
+2010-02-11  Pavel Feldman  <pfeldman at chromium.org>
+
+        Reviewed by Timothy Hatcher.
+
+        Web Inspector: split source code into chunks in order to improve text
+        viewer performance on large files.
+
+        https://bugs.webkit.org/show_bug.cgi?id=34816
+
+        This change brings back SourceFrame's canvas+style magic, restores line
+        wrapping and makes things a lot like they used to be.
+        It removes TextEditor for now and renames NativeTextViewer into TextViewer.
+        TextViewer is no longer derived from TextEditor.
+        This TextViewer is still based on TextEditorModel, no iframes are involved.
+
+        Instead of creating div per line, TextViewer splits source code into 50 line
+        chunks. Upon scroll event, visible chunks are sharded into lines and individual
+        lines are highlighted. Whenever highlighted region gets outside of the visible
+        area, highlight spans are thrown away and region is replaced with the original
+        plain text chunk.
+
+        Complex stuff:
+        - Whenever there is a need to manipulate individual lines (add message bubble /
+        set breakpoint / reveal / etc.), individual chunks for such lines are created.
+        - There is also an implicit machinery that is maintaining selection when it
+        goes beyond the visible area.
+        - Search occurrences are implemented as artificial spans interweaving
+        highlighting markup.
+
+        * WebCore.gypi:
+        * WebCore.vcproj/WebCore.vcproj:
+        * inspector/front-end/NativeTextViewer.js: Removed.
+        * inspector/front-end/ScriptView.js:
+        (WebInspector.ScriptView):
+        * inspector/front-end/Settings.js:
+        * inspector/front-end/SourceFrame.js:
+        (WebInspector.SourceFrame):
+        (WebInspector.SourceFrame.prototype.set visible):
+        (WebInspector.SourceFrame.prototype.set executionLine):
+        (WebInspector.SourceFrame.prototype.revealLine):
+        (WebInspector.SourceFrame.prototype.addBreakpoint):
+        (WebInspector.SourceFrame.prototype.removeBreakpoint):
+        (WebInspector.SourceFrame.prototype.addMessage):
+        (WebInspector.SourceFrame.prototype.clearMessages):
+        (WebInspector.SourceFrame.prototype.sizeToFitContentHeight):
+        (WebInspector.SourceFrame.prototype.setContent):
+        (WebInspector.SourceFrame.prototype.highlightLine):
+        (WebInspector.SourceFrame.prototype._createViewerIfNeeded):
+        (WebInspector.SourceFrame.prototype.markAndRevealRange):
+        (WebInspector.SourceFrame.prototype.clearMarkedRange):
+        (WebInspector.SourceFrame.prototype._breakpointChanged):
+        (WebInspector.SourceFrame.prototype._updateExecutionLine):
+        (WebInspector.SourceFrame.prototype._addMessageToSource):
+        (WebInspector.SourceFrame.prototype._addExistingBreakpointsToSource):
+        (WebInspector.SourceFrame.prototype._addBreakpointToSource):
+        (WebInspector.SourceFrame.prototype._removeBreakpointFromSource):
+        (WebInspector.SourceFrame.prototype._mouseDown):
+        (WebInspector.SourceFrame.prototype._editBreakpointCondition.committed):
+        (WebInspector.SourceFrame.prototype._editBreakpointCondition.dismissed):
+        (WebInspector.SourceFrame.prototype._editBreakpointCondition):
+        (WebInspector.SourceFrame.prototype._showBreakpointConditionPopup):
+        (WebInspector.SourceFrame.prototype._createConditionElement):
+        (WebInspector.SourceFrame.prototype._keyDown):
+        (WebInspector.SourceFrame.prototype.resize):
+        (WebInspector.SourceFrame.prototype._drawProgramCounterInContext):
+        (WebInspector.SourceFrame.prototype._drawProgramCounterImageIfNeeded):
+        (WebInspector.SourceFrame.prototype._drawBreakpointImagesIfNeeded.drawBreakpoint):
+        (WebInspector.SourceFrame.prototype._drawBreakpointImagesIfNeeded):
+        * inspector/front-end/SourceView.js:
+        (WebInspector.SourceView):
+        (WebInspector.SourceView.prototype._removeBreakpoint):
+        (WebInspector.SourceView.prototype.searchCanceled):
+        (WebInspector.SourceView.prototype._jumpToSearchResult):
+        * inspector/front-end/TextEditor.js: Removed.
+        * inspector/front-end/TextViewer.js: Added.
+        (WebInspector.TextViewer):
+        (WebInspector.TextViewer.prototype.set mimeType):
+        (WebInspector.TextViewer.prototype.get textModel):
+        (WebInspector.TextViewer.prototype.revealLine):
+        (WebInspector.TextViewer.prototype.addDecoration):
+        (WebInspector.TextViewer.prototype.removeDecoration):
+        (WebInspector.TextViewer.prototype.markAndRevealRange):
+        (WebInspector.TextViewer.prototype.highlightLine):
+        (WebInspector.TextViewer.prototype._textChanged):
+        (WebInspector.TextViewer.prototype._createChunkRow):
+        (WebInspector.TextViewer.prototype._makeLineAChunk):
+        (WebInspector.TextViewer.prototype._indexChunks):
+        (WebInspector.TextViewer.prototype._highlightChanged):
+        (WebInspector.TextViewer.prototype._scroll):
+        (WebInspector.TextViewer.prototype.setCoalescingUpdate):
+        (WebInspector.TextViewer.prototype._repaintAll):
+        (WebInspector.TextViewer.prototype._chunkForOffset):
+        (WebInspector.TextViewer.prototype._chunkNumberForLine):
+        (WebInspector.TextViewer.prototype._chunkStartLine):
+        (WebInspector.TextViewer.prototype._restoreChunks):
+        (WebInspector.TextViewer.prototype._repaint):
+        (WebInspector.TextViewer.prototype._getSelection):
+        (WebInspector.TextViewer.prototype._restoreSelection):
+        (WebInspector.TextViewer.prototype._selectionToPosition):
+        (WebInspector.TextViewer.prototype._createLineRow):
+        (WebInspector.TextViewer.prototype._paintLine):
+        (WebInspector.TextViewer.prototype._createSpan):
+        (WebInspector.TextViewer.prototype._createLink):
+        (WebInspector.TextViewer.prototype._rewriteHref):
+        (WebInspector.TextViewer.prototype._markRange):
+        (WebInspector.TextViewer.prototype._decimalDigits):
+        (WebInspector.TextViewer.prototype.resize):
+        * inspector/front-end/WebKit.qrc:
+        * inspector/front-end/inspector.css:
+        * inspector/front-end/inspector.html:
+        * inspector/front-end/textEditor.css: Removed.
+        * inspector/front-end/textViewer.css: Added.
+        * inspector/front-end/utilities.js:
+        (Node.prototype.traverseNextTextNode):
+        (Node.prototype.rangeBoundaryForOffset):
+
 2010-02-11  Csaba Osztrogonác  <ossy at webkit.org>
 
         Reviewed by Tor Arne Vestbø.
diff --git a/WebCore/WebCore.gypi b/WebCore/WebCore.gypi
index 39423a7..ca9fd10 100644
--- a/WebCore/WebCore.gypi
+++ b/WebCore/WebCore.gypi
@@ -3739,7 +3739,6 @@
             'inspector/front-end/inspector.js',
             'inspector/front-end/KeyboardShortcut.js',
             'inspector/front-end/MetricsSidebarPane.js',
-            'inspector/front-end/NativeTextViewer.js',
             'inspector/front-end/Object.js',
             'inspector/front-end/ObjectProxy.js',
             'inspector/front-end/ObjectPropertiesSection.js',
@@ -3775,10 +3774,10 @@
             'inspector/front-end/StylesSidebarPane.js',
             'inspector/front-end/SummaryBar.js',
             'inspector/front-end/TestController.js',
-            'inspector/front-end/TextEditor.js',
             'inspector/front-end/TextEditorHighlighter.js',
             'inspector/front-end/TextEditorModel.js',
             'inspector/front-end/TextPrompt.js',
+            'inspector/front-end/TextViewer.js',
             'inspector/front-end/TimelineAgent.js',
             'inspector/front-end/TimelineOverviewPane.js',
             'inspector/front-end/TimelineGrid.js',
@@ -3792,7 +3791,7 @@
             'inspector/front-end/audits.css',
             'inspector/front-end/inspector.css',
             'inspector/front-end/inspectorSyntaxHighlight.css',
-            'inspector/front-end/textEditor.css',
+            'inspector/front-end/textViewer.css',
         ],
         'webinspector_image_files': [
 
diff --git a/WebCore/WebCore.vcproj/WebCore.vcproj b/WebCore/WebCore.vcproj/WebCore.vcproj
index 885304a..21df2bc 100644
--- a/WebCore/WebCore.vcproj/WebCore.vcproj
+++ b/WebCore/WebCore.vcproj/WebCore.vcproj
@@ -42848,10 +42848,6 @@
 					>
 				</File>
 				<File
-					RelativePath="..\inspector\front-end\NativeTextViewer.js"
-					>
-				</File>
-				<File
 					RelativePath="..\inspector\front-end\Object.js"
 					>
 				</File>
@@ -42992,23 +42988,23 @@
 					>
 				</File>
 				<File
-					RelativePath="..\inspector\front-end\TextEditor.js"
+					RelativePath="..\inspector\front-end\TextEditorHighlighter.js"
 					>
 				</File>
 				<File
-					RelativePath="..\inspector\front-end\TextEditorHighlighter.js"
+					RelativePath="..\inspector\front-end\TextEditorModel.js"
 					>
 				</File>
 				<File
-					RelativePath="..\inspector\front-end\TextEditorModel.js"
+					RelativePath="..\inspector\front-end\TextPrompt.js"
 					>
 				</File>
 				<File
-					RelativePath="..\inspector\front-end\textEditor.css"
+					RelativePath="..\inspector\front-end\TextViewer.js"
 					>
 				</File>
 				<File
-					RelativePath="..\inspector\front-end\TextPrompt.js"
+					RelativePath="..\inspector\front-end\textViewer.css"
 					>
 				</File>
 				<File
diff --git a/WebCore/inspector/front-end/NativeTextViewer.js b/WebCore/inspector/front-end/NativeTextViewer.js
deleted file mode 100644
index 5e7db27..0000000
--- a/WebCore/inspector/front-end/NativeTextViewer.js
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Copyright (C) 2009 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-WebInspector.NativeTextViewer = function(textModel, platform, url)
-{
-    WebInspector.TextEditor.call(this, textModel, platform);
-    this._sheet.tabIndex = 0;
-    this._canvas.style.zIndex = 0;
-    this._createLineDivs();
-    this._url = url;
-    this._selectionColor = "rgb(241, 234, 0)";
-}
-
-WebInspector.NativeTextViewer.prototype = {
-    // WebInspector.TextModel listener
-    _textChanged: function(oldRange, newRange, oldText, newText)
-    {
-        this._createLineDivs();
-        WebInspector.TextEditor.prototype._textChanged.call(this, oldRange, newRange, oldText, newText);
-    },
-
-    _createLineDivs: function()
-    {
-        this._container.removeChild(this._sheet);
-        this._sheet.removeChildren();
-        for (var i = 0; i < this._textModel.linesCount; ++i) {
-            var lineDiv = document.createElement("div");
-            lineDiv.className = "native-text-editor-line";
-            var text = this._textModel.line(i);
-            lineDiv.textContent = text;
-            if (!text)
-                lineDiv.style.minHeight = this._textLineHeight + "px";
-            this._sheet.appendChild(lineDiv);
-            this._textModel.setAttribute(i, "line-div", lineDiv);
-            this._textModel.removeAttribute(i, "div-highlighted");
-        }
-        this._container.appendChild(this._sheet);
-    },
-
-    _updatePreferredSize: function(startLine, endLine)
-    {
-        // Preferred size is automatically calculated based on the line divs.
-        // Only handle line numbers here.
-        
-        this.setCoalescingUpdate(true);
-        var newLineNumberDigits = this._decimalDigits(this._textModel.linesCount);
-        this._lineNumberWidth = (newLineNumberDigits + 2) * this._digitWidth;
-
-        this._container.style.left = this._lineNumberWidth + "px";
-
-        this._lineNumberDigits = newLineNumberDigits;
-        this.repaintAll();
-
-        // Changes to size can change the client area (scrollers can appear/disappear)
-        this.resize();
-        this.setCoalescingUpdate(false);
-    },
-
-    _scroll: function(e)
-    {
-        // Do instant repaint so that offset of canvas was in sync with the sheet.
-        this._repaintOnScroll();
-    },
-
-    _registerMouseListeners: function()
-    {
-        this.element.addEventListener("contextmenu", this._contextMenu.bind(this), false);
-        this.element.addEventListener("mousedown", this._mouseDown.bind(this), false);
-    },
-
-    _registerKeyboardListeners: function()
-    {
-        // Noop - let browser take care of this.
-    },
-
-    _registerClipboardListeners: function()
-    {
-        // Noop - let browser take care of this.
-    },
-
-    _positionDivDecoration: function()
-    {
-        // Div decorations have fixed positions in our case.
-    },
-
-    _registerShortcuts: function()
-    {
-        // Noop.
-    },
-
-    _mouseDown: function(e)
-    {
-        if (e.target !== this.element || e.button === 2 || (this._isMac && e.ctrlKey))
-            return;
-        this._lineNumberDecorator.mouseDown(this._lineForMouseEvent(e), e);
-    },
-
-    _contextMenu: function(e)
-    {
-        if (e.target !== this.element)
-            return;
-        this._lineNumberDecorator.contextMenu(this._lineForMouseEvent(e), e);
-    },
-
-    _lineForMouseEvent: function(e)
-    {
-        return Math.max(0, this._offsetToLine(e.offsetY + this._scrollTop) - 1);
-    },
-
-    _lineHeight: function(lineNumber)
-    {
-        // Use cached value first.
-        if (this._lineOffsetsCache[lineNumber + 1])
-            return this._lineOffsetsCache[lineNumber + 1] - this._lineOffsetsCache[lineNumber];
-
-        // Get metrics from the browser.
-        var element = this._textModel.getAttribute(lineNumber, "line-div");
-        if (lineNumber + 1 < this._textModel.linesCount) {
-            var nextElement = this._textModel.getAttribute(lineNumber + 1, "line-div");
-            return nextElement.offsetTop - element.offsetTop;
-        }
-        return element.parentElement.offsetHeight - element.offsetTop;
-    },
-
-    _paintLine: function(lineNumber, lineOffset)
-    {
-        var divHighlighted = this._textModel.getAttribute(lineNumber, "div-highlighted");
-        if (divHighlighted)
-            return;
-
-        var highlighterState = this._textModel.getAttribute(lineNumber, "highlighter-state");
-        if (!highlighterState)
-            return;
-
-        var line = this._textModel.line(lineNumber);
-        var element = this._textModel.getAttribute(lineNumber, "line-div");
-        element.removeChildren();
- 
-        var plainTextStart = -1;
-        for (var j = 0; j < line.length;) {
-            if (j > 1000) {
-                // This line is too long - do not waste cycles on minified js highlighting.
-                break;
-            }
-            var attribute = highlighterState && highlighterState.attributes[j];
-            if (!attribute || !attribute.style) {
-                if (plainTextStart === -1)
-                    plainTextStart = j;
-                j++;
-            } else {
-                if (plainTextStart !== -1) {
-                    element.appendChild(document.createTextNode(line.substring(plainTextStart, j)));
-                    plainTextStart = -1;
-                }
-                element.appendChild(this._createSpan(line.substring(j, j + attribute.length), attribute.tokenType));
-                j += attribute.length;
-            }
-        }
-        if (plainTextStart !== -1)
-            element.appendChild(document.createTextNode(line.substring(plainTextStart, line.length)));
-
-        this._textModel.setAttribute(lineNumber, "div-highlighted", true);
-    },
-
-    _createSpan: function(content, className)
-    {
-        if (className === "html-resource-link" || className === "html-external-link")
-            return this._createLink(content, className === "html-external-link");
-
-        var span = document.createElement("span");
-        span.className = "webkit-" + className;
-        span.appendChild(document.createTextNode(content));
-        return span;
-    },
-
-    _createLink: function(content, isExternal)
-    {
-        var quote = content.charAt(0);
-        if (content.length > 1 && (quote === "\"" ||   quote === "'"))
-            content = content.substring(1, content.length - 1);
-        else
-            quote = null;
-
-        var a = WebInspector.linkifyURLAsNode(this._rewriteHref(content), content, null, isExternal);
-        var span = document.createElement("span");
-        span.className = "webkit-html-attribute-value";
-        if (quote)
-            span.appendChild(document.createTextNode(quote));
-        span.appendChild(a);
-        if (quote)
-            span.appendChild(document.createTextNode(quote));
-        return span;
-    },
-
-    _rewriteHref: function(hrefValue, isExternal)
-    {
-        if (!this._url || !hrefValue || hrefValue.indexOf("://") > 0)
-            return hrefValue;
-        return WebInspector.completeURL(this._url, hrefValue);
-    },
-
-    setDivDecoration: function(lineNumber, element)
-    {
-        var existingElement = this._textModel.getAttribute(lineNumber, "div-decoration");
-        if (existingElement && existingElement.parentNode)
-            existingElement.parentNode.removeChild(existingElement);
-        this._textModel.removeAttribute(lineNumber, "div-decoration");
-
-        if (element) {
-            if (lineNumber < this._textModel.linesCount - 1) {
-                var lineDiv = this._textModel.getAttribute(lineNumber + 1, "line-div");
-                this._sheet.insertBefore(element, lineDiv);
-            } else
-                this._sheet.appendChild(element);
-            this._textModel.setAttribute(lineNumber, "div-decoration", element);
-        }
-        this.revalidateDecorationsAndPaint();
-    },
-
-    initFontMetrics: function()
-    {
-        WebInspector.TextEditor.prototype.initFontMetrics.call(this);
-        for (var i = 0; i < this._textModel.linesCount; ++i) {
-            var lineDiv = this._textModel.getAttribute(i, "line-div");
-            if (!this._textModel.line(i))
-                lineDiv.style.minHeight = this._textLineHeight + "px";
-        }
-    }
-}
-
-WebInspector.NativeTextViewer.prototype.__proto__ = WebInspector.TextEditor.prototype;
diff --git a/WebCore/inspector/front-end/ScriptView.js b/WebCore/inspector/front-end/ScriptView.js
index cf7f1b1..c5a8b81 100644
--- a/WebCore/inspector/front-end/ScriptView.js
+++ b/WebCore/inspector/front-end/ScriptView.js
@@ -33,7 +33,7 @@ WebInspector.ScriptView = function(script)
 
     this._frameNeedsSetup = true;
     this._sourceFrameSetup = false;
-    this.sourceFrame = new WebInspector.SourceFrame(this.element, this._addBreakpoint.bind(this));
+    this.sourceFrame = new WebInspector.SourceFrame(this.element, this._addBreakpoint.bind(this), this._removeBreakpoint.bind(this));
 }
 
 WebInspector.ScriptView.prototype = {
@@ -87,6 +87,7 @@ WebInspector.ScriptView.prototype = {
     showingLastSearchResult: WebInspector.SourceView.prototype.showingLastSearchResult,
     _jumpToSearchResult: WebInspector.SourceView.prototype._jumpToSearchResult,
     _sourceFrameSetupFinished: WebInspector.SourceView.prototype._sourceFrameSetupFinished,
+    _removeBreakpoint: WebInspector.SourceView.prototype._removeBreakpoint,
     resize: WebInspector.SourceView.prototype.resize
 }
 
diff --git a/WebCore/inspector/front-end/Settings.js b/WebCore/inspector/front-end/Settings.js
index bc0daa5..85aecd5 100644
--- a/WebCore/inspector/front-end/Settings.js
+++ b/WebCore/inspector/front-end/Settings.js
@@ -38,8 +38,7 @@ var Preferences = {
     styleRulesExpandedState: {},
     showMissingLocalizedStrings: false,
     samplingCPUProfiler: false,
-    showColorNicknames: true,
-    useCanvasBasedEditor: false
+    showColorNicknames: true
 }
 
 WebInspector.populateFrontendSettings = function(settingsString)
diff --git a/WebCore/inspector/front-end/SourceFrame.js b/WebCore/inspector/front-end/SourceFrame.js
index bc9122b..0f90700 100644
--- a/WebCore/inspector/front-end/SourceFrame.js
+++ b/WebCore/inspector/front-end/SourceFrame.js
@@ -28,7 +28,7 @@
  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
-WebInspector.SourceFrame = function(parentElement, addBreakpointDelegate)
+WebInspector.SourceFrame = function(parentElement, addBreakpointDelegate, removeBreakpointDelegate)
 {
     this._parentElement = parentElement;
 
@@ -44,6 +44,7 @@ WebInspector.SourceFrame = function(parentElement, addBreakpointDelegate)
     this._loaded = false;
 
     this._addBreakpointDelegate = addBreakpointDelegate;
+    this._removeBreakpointDelegate = removeBreakpointDelegate;
 }
 
 WebInspector.SourceFrame.prototype = {
@@ -51,7 +52,7 @@ WebInspector.SourceFrame.prototype = {
     set visible(visible)
     {
         this._visible = visible;
-        this._createEditorIfNeeded();
+        this._createViewerIfNeeded();
     },
 
     get executionLine()
@@ -63,15 +64,18 @@ WebInspector.SourceFrame.prototype = {
     {
         if (this._executionLine === x)
             return;
+
+        var previousLine = this._executionLine;
         this._executionLine = x;
-        if (this._editor)
-            this._editor.repaintAll();
+
+        if (this._textViewer)
+            this._updateExecutionLine(previousLine);
     },
 
     revealLine: function(lineNumber)
     {
-        if (this._editor)
-            this._editor.reveal(lineNumber - 1, 0);
+        if (this._textViewer)
+            this._textViewer.revealLine(lineNumber - 1, 0);
         else
             this._lineNumberToReveal = lineNumber;
     },
@@ -82,7 +86,8 @@ WebInspector.SourceFrame.prototype = {
         breakpoint.addEventListener("enabled", this._breakpointChanged, this);
         breakpoint.addEventListener("disabled", this._breakpointChanged, this);
         breakpoint.addEventListener("condition-changed", this._breakpointChanged, this);
-        this._addBreakpointToSource(breakpoint);
+        if (this._textViewer)
+            this._addBreakpointToSource(breakpoint);
     },
 
     removeBreakpoint: function(breakpoint)
@@ -91,7 +96,8 @@ WebInspector.SourceFrame.prototype = {
         breakpoint.removeEventListener("enabled", null, this);
         breakpoint.removeEventListener("disabled", null, this);
         breakpoint.removeEventListener("condition-changed", null, this);
-        this._removeBreakpointFromSource(breakpoint);
+        if (this._textViewer)
+            this._removeBreakpointFromSource(breakpoint);
     },
 
     addMessage: function(msg)
@@ -100,7 +106,7 @@ WebInspector.SourceFrame.prototype = {
         if (!msg.message || msg.line <= 0 || !msg.isErrorOrWarning())
             return;
         this._messages.push(msg)
-        if (this._editor)
+        if (this._textViewer)
             this._addMessageToSource(msg);
     },
 
@@ -114,14 +120,14 @@ WebInspector.SourceFrame.prototype = {
         this._messages = [];
         this._rowMessages = {};
         this._messageBubbles = {};
-        if (this._editor)
-            this._editor.revalidateDecorationsAndPaint();
+        if (this._textViewer)
+            this._textViewer.resize();
     },
 
     sizeToFitContentHeight: function()
     {
-        if (this._editor)
-            this._editor.revalidateDecorationsAndPaint();
+        if (this._textViewer)
+            this._textViewer.revalidateDecorationsAndPaint();
     },
 
     setContent: function(mimeType, content, url)
@@ -130,47 +136,56 @@ WebInspector.SourceFrame.prototype = {
         this._textModel.setText(null, content);
         this._mimeType = mimeType;
         this._url = url;
-        this._createEditorIfNeeded();
+        this._createViewerIfNeeded();
+    },
+
+    highlightLine: function(line)
+    {
+        if (this._textViewer)
+            this._textViewer.highlightLine(line - 1);
+        else
+            this._lineToHighlight = line;
     },
 
-    _createEditorIfNeeded: function()
+    _createViewerIfNeeded: function()
     {
-        if (!this._visible || !this._loaded || this._editor)
+        if (!this._visible || !this._loaded || this._textViewer)
             return;
 
-        var editorConstructor = Preferences.useCanvasBasedEditor ? WebInspector.TextEditor : WebInspector.NativeTextViewer;
-        this._editor = new editorConstructor(this._textModel, WebInspector.platform, this._url);
-        this._editor.lineNumberDecorator = new WebInspector.BreakpointLineNumberDecorator(this, this._editor.textModel);
-        this._editor.lineDecorator = new WebInspector.ExecutionLineDecorator(this);
-        this._editor.readOnly = true;
-        this._element = this._editor.element;
-        this._element.addEventListener("keydown", this._keyDown.bind(this), true);
-        this._parentElement.appendChild(this._element);
-        this._editor.initFontMetrics();
+        this._textViewer = new WebInspector.TextViewer(this._textModel, WebInspector.platform, this._url);
+        var element = this._textViewer.element;
+        element.addEventListener("keydown", this._keyDown.bind(this), true);
+        element.addEventListener("contextmenu", this._contextMenu.bind(this), true);
+        element.addEventListener("mousedown", this._mouseDown.bind(this), true);
+        this._parentElement.appendChild(element);
 
-        this._editor.mimeType = this._mimeType;
+        this._needsProgramCounterImage = true;
+        this._needsBreakpointImages = true;
 
+        this._textViewer.beginUpdates();
+
+        this._textViewer.mimeType = this._mimeType;
         this._addExistingMessagesToSource();
         this._addExistingBreakpointsToSource();
-
-        this._editor.setCoalescingUpdate(true);
-        this._editor.resize();
-        this._editor.revalidateDecorationsAndPaint();
-
-        if (this._executionLine)
-            this.revealLine(this._executionLine);
+        this._updateExecutionLine();
+        this._textViewer.resize();
 
         if (this._lineNumberToReveal) {
             this.revealLine(this._lineNumberToReveal);
             delete this._lineNumberToReveal;
         }
 
-        if (this._pendingSelectionRange) {
-            var range = this._pendingSelectionRange;
-            this._editor.setSelection(range.startLine, range.startColumn, range.endLine, range.endColumn);
-            delete this._pendingSelectionRange;
+        if (this._pendingMarkRange) {
+            var range = this._pendingMarkRange;
+            this.markAndRevealRange(range);
+            delete this._pendingMarkRange;
         }
-        this._editor.setCoalescingUpdate(false);
+
+        if (this._lineToHighlight) {
+            this.highlightLine(this._lineToHighlight);
+            delete this._lineToHighlight;
+        }
+        this._textViewer.endUpdates();
     },
 
     findSearchMatches: function(query)
@@ -215,21 +230,20 @@ WebInspector.SourceFrame.prototype = {
         return ranges;
     },
 
-    setSelection: function(range)
+    markAndRevealRange: function(range)
     {
-        if (this._editor)
-            this._editor.setSelection(range.startLine, range.startColumn, range.endLine, range.endColumn);
+        if (this._textViewer)
+            this._textViewer.markAndRevealRange(range);
         else
-            this._pendingSelectionRange = range;
+            this._pendingMarkRange = range;
     },
 
-    clearSelection: function()
+    clearMarkedRange: function()
     {
-        if (this._editor) {
-            var range = this._editor.selection;
-            this._editor.setSelection(range.endLine, range.endColumn, range.endLine, range.endColumn);
+        if (this._textViewer) {
+            this._textViewer.markAndRevealRange(null);
         } else
-            delete this._pendingSelectionRange;
+            delete this._pendingMarkRange;
     },
 
     _incrementMessageRepeatCount: function(msg, repeatDelta)
@@ -247,6 +261,40 @@ WebInspector.SourceFrame.prototype = {
         msg._resourceMessageRepeatCountElement.textContent = WebInspector.UIString(" (repeated %d times)", msg.repeatCount);
     },
 
+    _breakpointChanged: function(event)
+    {
+        var breakpoint = event.target;
+        var lineNumber = breakpoint.line - 1;
+        if (lineNumber >= this._textModel.linesCount)
+            return;
+
+        if (breakpoint.enabled)
+            this._textViewer.removeDecoration(lineNumber, "webkit-breakpoint-disabled");
+        else
+            this._textViewer.addDecoration(lineNumber, "webkit-breakpoint-disabled");
+
+        if (breakpoint.condition)
+            this._textViewer.addDecoration(lineNumber, "webkit-breakpoint-conditional");
+        else
+            this._textViewer.removeDecoration(lineNumber, "webkit-breakpoint-conditional");
+    },
+
+    _updateExecutionLine: function(previousLine)
+    {
+        if (previousLine) {
+            if (previousLine - 1 < this._textModel.linesCount)
+                this._textViewer.removeDecoration(previousLine - 1, "webkit-execution-line");
+        }
+
+        if (!this._executionLine)
+            return;
+
+        this._drawProgramCounterImageIfNeeded();
+
+        if (this._executionLine < this._textModel.linesCount)
+            this._textViewer.addDecoration(this._executionLine - 1, "webkit-execution-line");
+    },
+
     _addExistingMessagesToSource: function()
     {
         var length = this._messages.length;
@@ -264,7 +312,7 @@ WebInspector.SourceFrame.prototype = {
             messageBubbleElement = document.createElement("div");
             messageBubbleElement.className = "webkit-html-message-bubble";
             this._messageBubbles[msg.line] = messageBubbleElement;
-            this._editor.setDivDecoration(msg.line - 1, messageBubbleElement);
+            this._textViewer.addDecoration(msg.line - 1, messageBubbleElement);
         }
 
         var rowMessages = this._rowMessages[msg.line];
@@ -276,7 +324,6 @@ WebInspector.SourceFrame.prototype = {
         for (var i = 0; i < rowMessages.length; ++i) {
             if (rowMessages[i].isEqual(msg, true)) {
                 this._incrementMessageRepeatCount(rowMessages[i], msg.repeatDelta);
-                this._editor.revalidateDecorationsAndPaint();
                 return;
             }
         }
@@ -307,35 +354,51 @@ WebInspector.SourceFrame.prototype = {
         messageLineElement.appendChild(document.createTextNode(msg.message));
 
         msg._resourceMessageLineElement = messageLineElement;
-
-        this._editor.revalidateDecorationsAndPaint();
     },
 
     _addExistingBreakpointsToSource: function()
     {
-        var length = this.breakpoints.length;
-        for (var i = 0; i < length; ++i)
+        for (var i = 0; i < this.breakpoints.length; ++i)
             this._addBreakpointToSource(this.breakpoints[i]);
     },
 
     _addBreakpointToSource: function(breakpoint)
     {
-        this._textModel.setAttribute(breakpoint.line - 1, "breakpoint", breakpoint);
+        var lineNumber = breakpoint.line - 1;
+        if (lineNumber >= this._textModel.linesCount)
+            return;
+
+        this._textModel.setAttribute(lineNumber, "breakpoint", breakpoint);
         breakpoint.sourceText = this._textModel.line(breakpoint.line - 1);
-        this._editor.paintLineNumbers();
+        this._drawBreakpointImagesIfNeeded();
+
+        this._textViewer.beginUpdates();
+        this._textViewer.addDecoration(lineNumber, "webkit-breakpoint");
+        if (!breakpoint.enabled)
+            this._textViewer.addDecoration(lineNumber, "webkit-breakpoint-disabled");
+        if (breakpoint.condition)
+            this._textViewer.addDecoration(lineNumber, "webkit-breakpoint-conditional");
+        this._textViewer.endUpdates();
     },
 
     _removeBreakpointFromSource: function(breakpoint)
     {
-        this._textModel.removeAttribute(breakpoint.line - 1, "breakpoint");
-        this._editor.paintLineNumbers();
+        var lineNumber = breakpoint.line - 1;
+        this._textViewer.beginUpdates();
+        this._textModel.removeAttribute(lineNumber, "breakpoint");
+        this._textViewer.removeDecoration(lineNumber, "webkit-breakpoint");
+        this._textViewer.removeDecoration(lineNumber, "webkit-breakpoint-disabled");
+        this._textViewer.removeDecoration(lineNumber, "webkit-breakpoint-conditional");
+        this._textViewer.endUpdates();
     },
 
-    _contextMenu: function(lineNumber, event)
+    _contextMenu: function(event)
     {
-        if (!this._addBreakpointDelegate)
+        if (event.target.className !== "webkit-line-number")
             return;
+        var row = event.target.parentElement;
 
+        var lineNumber = row.lineNumber;
         var contextMenu = new WebInspector.ContextMenu();
 
         var breakpoint = this._textModel.getAttribute(lineNumber, "breakpoint");
@@ -364,13 +427,19 @@ WebInspector.SourceFrame.prototype = {
         contextMenu.show(event);
     },
 
-    _toggleBreakpoint: function(lineNumber, event)
+    _mouseDown: function(event)
     {
         if (event.button != 0 || event.altKey || event.ctrlKey || event.metaKey || event.shiftKey)
             return;
+        if (event.target.className !== "webkit-line-number")
+            return;
+        var row = event.target.parentElement;
+
+        var lineNumber = row.lineNumber;
+
         var breakpoint = this._textModel.getAttribute(lineNumber, "breakpoint");
         if (breakpoint)
-            WebInspector.panels.scripts.removeBreakpoint(breakpoint);
+            this._removeBreakpointDelegate(breakpoint);
         else if (this._addBreakpointDelegate)
             this._addBreakpointDelegate(lineNumber + 1);
         event.preventDefault();
@@ -383,14 +452,15 @@ WebInspector.SourceFrame.prototype = {
         function committed(element, newText)
         {
             breakpoint.condition = newText;
-            this._editor.paintLineNumbers();
             dismissed.call(this);
         }
 
         function dismissed()
         {
-            this._editor.setDivDecoration(breakpoint.line - 1, null);
+            if (this._conditionElement)
+                this._textViewer.removeDecoration(breakpoint.line - 1, this._conditionElement);
             delete this._conditionEditorElement;
+            delete this._conditionElement;
         }
 
         var dismissedHandler = dismissed.bind(this);
@@ -403,23 +473,23 @@ WebInspector.SourceFrame.prototype = {
 
     _showBreakpointConditionPopup: function(lineNumber)
     {
-        var conditionElement = this._createConditionElement(lineNumber);
-        this._editor.setDivDecoration(lineNumber - 1, conditionElement);
+        this._conditionElement = this._createConditionElement(lineNumber);
+        this._textViewer.addDecoration(lineNumber - 1, this._conditionElement);
     },
 
     _createConditionElement: function(lineNumber)
     {
         var conditionElement = document.createElement("div");
-        conditionElement.className = "source-breakpoint-condition";
+        conditionElement.className = "source-frame-breakpoint-condition";
 
         var labelElement = document.createElement("label");
-        labelElement.className = "source-breakpoint-message";
-        labelElement.htmlFor = "source-breakpoint-condition";
+        labelElement.className = "source-frame-breakpoint-message";
+        labelElement.htmlFor = "source-frame-breakpoint-condition";
         labelElement.appendChild(document.createTextNode(WebInspector.UIString("The breakpoint on line %d will stop only if this expression is true:", lineNumber)));
         conditionElement.appendChild(labelElement);
 
         var editorElement = document.createElement("input");
-        editorElement.id = "source-breakpoint-condition";
+        editorElement.id = "source-frame-breakpoint-condition";
         editorElement.className = "monospace";
         editorElement.type = "text"
         conditionElement.appendChild(editorElement);
@@ -435,9 +505,8 @@ WebInspector.SourceFrame.prototype = {
         if (handler) {
             handler(event);
             event.preventDefault();
-        } else {
+        } else
             WebInspector.documentKeyDown(event);
-        }
     },
 
     _evalSelectionInCallFrame: function(event)
@@ -458,146 +527,139 @@ WebInspector.SourceFrame.prototype = {
         });
     },
 
-    _breakpointChanged: function(event)
+    resize: function()
     {
-        this._editor.paintLineNumbers();
+        if (this._textViewer)
+            this._textViewer.resize();
     },
 
-    resize: function()
+    _drawProgramCounterInContext: function(ctx, glow)
     {
-        if (this._editor)
-            this._editor.resize();
-    }
-}
+        if (glow)
+            ctx.save();
 
-WebInspector.SourceFrame.prototype.__proto__ = WebInspector.Object.prototype;
+        ctx.beginPath();
+        ctx.moveTo(17, 2);
+        ctx.lineTo(19, 2);
+        ctx.lineTo(19, 0);
+        ctx.lineTo(21, 0);
+        ctx.lineTo(26, 5.5);
+        ctx.lineTo(21, 11);
+        ctx.lineTo(19, 11);
+        ctx.lineTo(19, 9);
+        ctx.lineTo(17, 9);
+        ctx.closePath();
+        ctx.fillStyle = "rgb(142, 5, 4)";
 
-WebInspector.BreakpointLineNumberDecorator = function(sourceFrame, textModel)
-{
-    this._sourceFrame = sourceFrame;
-    this._textModel = textModel;
-}
+        if (glow) {
+            ctx.shadowBlur = 4;
+            ctx.shadowColor = "rgb(255, 255, 255)";
+            ctx.shadowOffsetX = -1;
+            ctx.shadowOffsetY = 0;
+        }
 
-WebInspector.BreakpointLineNumberDecorator.prototype = {
-    decorate: function(lineNumber, ctx, x, y, width, height, lineHeight)
-    {
-        var breakpoint = this._textModel.getAttribute(lineNumber, "breakpoint");
-        var isExecutionLine = lineNumber + 1 === this._sourceFrame._executionLine;
-        if (breakpoint || isExecutionLine) {
-            ctx.save();
-            ctx.translate(x + 4, y + 2);
-            var breakpointWidth = width - 6;
-            var breakpointHeight = lineHeight - 4;
-    
-            if (breakpoint)
-                this._paintBreakpoint(ctx, breakpointWidth, breakpointHeight, breakpoint);
-    
-            if (isExecutionLine)
-                this._paintProgramCounter(ctx, breakpointWidth, breakpointHeight, false);
+        ctx.fill();
+        ctx.fill(); // Fill twice to get a good shadow and darker anti-aliased pixels.
 
+        if (glow)
             ctx.restore();
-        }
+    },
 
-        if (isExecutionLine) {
-            // Override default behavior.
-            return true;
-        }
+    _drawProgramCounterImageIfNeeded: function()
+    {
+        if (!this._needsProgramCounterImage)
+            return;
+
+        var ctx = document.getCSSCanvasContext("2d", "program-counter", 26, 11);
+        ctx.clearRect(0, 0, 26, 11);
+        this._drawProgramCounterInContext(ctx, true);
 
-        ctx.fillStyle = breakpoint ? "rgb(255,255,255)" : "rgb(155,155,155)";
-        return false;
+        delete this._needsProgramCounterImage;
     },
 
-    _paintBreakpoint: function(ctx, width, height, breakpoint)
+    _drawBreakpointImagesIfNeeded: function(conditional)
     {
-        ctx.beginPath();
-        ctx.moveTo(0, 2);
-        ctx.lineTo(2, 0);
-        ctx.lineTo(width - 5, 0);
-        ctx.lineTo(width, height / 2);
-        ctx.lineTo(width - 5, height);
-        ctx.lineTo(2, height);
-        ctx.lineTo(0, height - 2);
-        ctx.closePath();
-        ctx.fillStyle = breakpoint.condition ? "rgb(217, 142, 1)" : "rgb(1, 142, 217)";
-        ctx.strokeStyle = breakpoint.condition ? "rgb(205, 103, 0)" : "rgb(0, 103, 205)";
-        ctx.lineWidth = 3;
-        ctx.fill();
+        if (!this._needsBreakpointImages)
+            return;
+
+        function drawBreakpoint(ctx, disabled, conditional)
+        {
+            ctx.beginPath();
+            ctx.moveTo(0, 2);
+            ctx.lineTo(2, 0);
+            ctx.lineTo(21, 0);
+            ctx.lineTo(26, 5.5);
+            ctx.lineTo(21, 11);
+            ctx.lineTo(2, 11);
+            ctx.lineTo(0, 9);
+            ctx.closePath();
+            ctx.fillStyle = conditional ? "rgb(217, 142, 1)" : "rgb(1, 142, 217)";
+            ctx.strokeStyle = conditional ? "rgb(205, 103, 0)" : "rgb(0, 103, 205)";
+            ctx.lineWidth = 3;
+            ctx.fill();
+            ctx.save();
+            ctx.clip();
+            ctx.stroke();
+            ctx.restore();
 
-        ctx.save();
-        ctx.clip();
-        ctx.stroke();
-        ctx.restore();
+            if (!disabled)
+                return;
 
-        if (!breakpoint.enabled) {
             ctx.save();
             ctx.globalCompositeOperation = "destination-out";
             ctx.fillStyle = "rgba(0, 0, 0, 0.5)";
-            ctx.fillRect(0, 0, width, height);
+            ctx.fillRect(0, 0, 26, 11);
             ctx.restore();
         }
-    },
 
-    _paintProgramCounter: function(ctx, width, height)
-    {
-        ctx.save();
 
-        ctx.beginPath();
-        ctx.moveTo(width - 9, 2);
-        ctx.lineTo(width - 7, 2);
-        ctx.lineTo(width - 7, 0);
-        ctx.lineTo(width - 5, 0);
-        ctx.lineTo(width, height / 2);
-        ctx.lineTo(width - 5, height);
-        ctx.lineTo(width - 7, height);
-        ctx.lineTo(width - 7, height - 2);
-        ctx.lineTo(width - 9, height - 2);
-        ctx.closePath();
-        ctx.fillStyle = "rgb(142, 5, 4)";
+        // Unconditional breakpoints.
 
-        ctx.shadowBlur = 4;
-        ctx.shadowColor = "rgb(255, 255, 255)";
-        ctx.shadowOffsetX = -1;
-        ctx.shadowOffsetY = 0;
+        var ctx = document.getCSSCanvasContext("2d", "breakpoint", 26, 11);
+        ctx.clearRect(0, 0, 26, 11);
+        drawBreakpoint(ctx);
 
-        ctx.fill();
-        ctx.fill(); // Fill twice to get a good shadow and darker anti-aliased pixels.
+        var ctx = document.getCSSCanvasContext("2d", "breakpoint-program-counter", 26, 11);
+        ctx.clearRect(0, 0, 26, 11);
+        drawBreakpoint(ctx);
+        ctx.clearRect(20, 0, 6, 11);
+        this._drawProgramCounterInContext(ctx, true);
 
-        ctx.restore();
-    },
+        var ctx = document.getCSSCanvasContext("2d", "breakpoint-disabled", 26, 11);
+        ctx.clearRect(0, 0, 26, 11);
+        drawBreakpoint(ctx, true);
 
-    mouseDown: function(lineNumber, e)
-    {
-        this._sourceFrame._toggleBreakpoint(lineNumber, e);
-        return true;
-    },
+        var ctx = document.getCSSCanvasContext("2d", "breakpoint-disabled-program-counter", 26, 11);
+        ctx.clearRect(0, 0, 26, 11);
+        drawBreakpoint(ctx, true);
+        ctx.clearRect(20, 0, 6, 11);
+        this._drawProgramCounterInContext(ctx, true);
 
-    contextMenu: function(lineNumber, e)
-    {
-        this._sourceFrame._contextMenu(lineNumber, e);
-        return true;
-    }
-}
 
-WebInspector.ExecutionLineDecorator = function(sourceFrame)
-{
-    this._sourceFrame = sourceFrame;
-}
+        // Conditional breakpoints.
 
-WebInspector.ExecutionLineDecorator.prototype = {
-    decorate: function(lineNumber, ctx, x, y, width, height, lineHeight)
-    {
-        if (this._sourceFrame._executionLine !== lineNumber + 1)
-            return;
-        ctx.save();
-        ctx.fillStyle = "rgb(171, 191, 254)";
-        ctx.fillRect(x, y, width, height);
-        
-        ctx.beginPath();
-        ctx.rect(x - 1, y, width + 2, height);
-        ctx.clip();
-        ctx.strokeStyle = "rgb(64, 115, 244)";
-        ctx.stroke();
+        var ctx = document.getCSSCanvasContext("2d", "breakpoint-conditional", 26, 11);
+        ctx.clearRect(0, 0, 26, 11);
+        drawBreakpoint(ctx, false, true);
 
-        ctx.restore();
+        var ctx = document.getCSSCanvasContext("2d", "breakpoint-conditional-program-counter", 26, 11);
+        ctx.clearRect(0, 0, 26, 11);
+        drawBreakpoint(ctx, false, true);
+        ctx.clearRect(20, 0, 6, 11);
+        this._drawProgramCounterInContext(ctx, true);
+
+        var ctx = document.getCSSCanvasContext("2d", "breakpoint-disabled-conditional", 26, 11);
+        ctx.clearRect(0, 0, 26, 11);
+        drawBreakpoint(ctx, true, true);
+
+        var ctx = document.getCSSCanvasContext("2d", "breakpoint-disabled-conditional-program-counter", 26, 11);
+        ctx.clearRect(0, 0, 26, 11);
+        drawBreakpoint(ctx, true, true);
+        ctx.clearRect(20, 0, 6, 11);
+        this._drawProgramCounterInContext(ctx, true);
+
+        delete this._needsBreakpointImages;
     }
 }
+
+WebInspector.SourceFrame.prototype.__proto__ = WebInspector.Object.prototype;
diff --git a/WebCore/inspector/front-end/SourceView.js b/WebCore/inspector/front-end/SourceView.js
index 7fc8499..b401c12 100644
--- a/WebCore/inspector/front-end/SourceView.js
+++ b/WebCore/inspector/front-end/SourceView.js
@@ -32,7 +32,7 @@ WebInspector.SourceView = function(resource)
 
     this.element.addStyleClass("source");
 
-    this.sourceFrame = new WebInspector.SourceFrame(this.contentElement, this._addBreakpoint.bind(this));
+    this.sourceFrame = new WebInspector.SourceFrame(this.contentElement, this._addBreakpoint.bind(this), this._removeBreakpoint.bind(this));
     resource.addEventListener("finished", this._resourceLoadingFinished, this);
     this._frameNeedsSetup = true;
 }
@@ -58,16 +58,6 @@ WebInspector.SourceView.prototype = {
             this.sourceFrame.resize();
     },
 
-    detach: function()
-    {
-        WebInspector.ResourceView.prototype.detach.call(this);
-
-        // FIXME: We need to mark the frame for setup on detach because the frame DOM is cleared
-        // when it is removed from the document. Is this a bug?
-        this._frameNeedsSetup = true;
-        this._sourceFrameSetup = false;
-    },
-
     setupSourceFrameIfNeeded: function()
     {
         if (!this._frameNeedsSetup)
@@ -118,6 +108,12 @@ WebInspector.SourceView.prototype = {
         }
     },
 
+    _removeBreakpoint: function(breakpoint)
+    {
+        if (WebInspector.panels.scripts)
+            WebInspector.panels.scripts.removeBreakpoint(breakpoint);
+    },
+
     // The rest of the methods in this prototype need to be generic enough to work with a ScriptView.
     // The ScriptView prototype pulls these methods into it's prototype to avoid duplicate code.
 
@@ -125,7 +121,7 @@ WebInspector.SourceView.prototype = {
     {
         this._currentSearchResultIndex = -1;
         this._searchResults = [];
-        this.sourceFrame.clearSelection();
+        this.sourceFrame.clearMarkedRange();
         delete this._delayedFindSearchMatches;
     },
 
@@ -225,7 +221,7 @@ WebInspector.SourceView.prototype = {
         if (!foundRange)
             return;
 
-        this.sourceFrame.setSelection(foundRange);
+        this.sourceFrame.markAndRevealRange(foundRange);
     },
 
     _sourceFrameSetupFinished: function()
diff --git a/WebCore/inspector/front-end/TextEditor.js b/WebCore/inspector/front-end/TextEditor.js
deleted file mode 100644
index 9268280..0000000
--- a/WebCore/inspector/front-end/TextEditor.js
+++ /dev/null
@@ -1,1168 +0,0 @@
-/*
- * Copyright (C) 2009 Google Inc. All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- *     * Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- *     * Redistributions in binary form must reproduce the above
- * copyright notice, this list of conditions and the following disclaimer
- * in the documentation and/or other materials provided with the
- * distribution.
- *     * Neither the name of Google Inc. nor the names of its
- * contributors may be used to endorse or promote products derived from
- * this software without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-WebInspector.TextEditor = function(textModel, platform)
-{
-    this._textModel = textModel;
-    this._textModel.changeListener = this._textChanged.bind(this);
-    this._highlighter = new WebInspector.TextEditorHighlighter(this._textModel, this._highlightChanged.bind(this));
-
-    this.element = document.createElement("div");
-    this.element.className = "text-editor monospace";
-    this.element.tabIndex = 0;
-
-    this._canvas = document.createElement("canvas");
-    this._canvas.className = "text-editor-canvas";
-    this.element.appendChild(this._canvas);
-
-    this._container = document.createElement("div");
-    this._container.className = "text-editor-container";
-    this.element.appendChild(this._container);
-
-    this._sheet = document.createElement("div");
-    this._container.appendChild(this._sheet);
-
-    var cursorElement = document.createElement("div");
-    cursorElement.className = "text-editor-cursor";
-    this._container.appendChild(cursorElement);
-    this._cursor = new WebInspector.TextCursor(cursorElement);
-
-    this._container.addEventListener("scroll", this._scroll.bind(this), false);
-
-    this._registerMouseListeners();
-    this._registerKeyboardListeners();
-    this._registerClipboardListeners();
-
-    this._desiredCaretColumn = 0;
-    this._scrollLeft = 0;
-    this._scrollTop = 0;
-
-    this._ctx = this._canvas.getContext("2d");
-    this._selection = new WebInspector.TextSelectionModel(this._selectionChanged.bind(this));
-
-    this._isMac = platform && (platform.indexOf("mac") === 0);
-    this._paintCoalescingLevel = 0;
-
-    this._registerShortcuts();
-    // Debugging flags, allow disabling / enabling highlights and track repaints.
-    this._highlightingEnabled = true;
-    this._debugMode = false;
-
-    this._textWidth = 0;
-    this._longestLineNumber = 0;
-
-    this._lineOffsetsCache = [0];
-    this._readOnly = false;
-    this._selectionColor = "rgb(181, 213, 255)";
-}
-
-WebInspector.TextEditor.prototype = {
-    set text(text)
-    {
-        var lastLine = this._textModel.linesCount - 1;
-        this._textModel.setText(null, text);
-        this._textModel.resetUndoStack();
-        this._setCaretLocation(0, 0);
-    },
-
-    set mimeType(mimeType)
-    {
-        this._highlighter.mimeType = mimeType;
-    },
-
-    get textModel()
-    {
-        return this._textModel;
-    },
-
-    set readOnly(readOnly)
-    {
-        this._readOnly = readOnly;
-        if (readOnly)
-            this.element.addStyleClass("text-editor-readonly")
-        else
-            this.element.removeStyleClass("text-editor-readonly")
-    },
-
-    set lineNumberDecorator(lineNumberDecorator)
-    {
-        this._lineNumberDecorator = lineNumberDecorator;
-    },
-
-    set lineDecorator(lineDecorator)
-    {
-        this._lineDecorator = lineDecorator;
-    },
-
-    get selection()
-    {
-        return this._selection.range();
-    },
-
-    setSelection: function(startLine, startColumn, endLine, endColumn)
-    {
-        var start = this._fit(startLine, startColumn);
-        this._selection.setStart(start.line, start.column);
-        this._setSelectionEnd(endLine, endColumn);
-    },
-
-    setDivDecoration: function(lineNumber, element)
-    {
-        var existingElement = this._textModel.getAttribute(lineNumber, "div-decoration");
-        if (existingElement && existingElement.parentNode)
-            existingElement.parentNode.removeChild(existingElement);
-        this._textModel.removeAttribute(lineNumber, "div-decoration");
-
-        if (element) {
-            this.element.appendChild(element);
-            this._textModel.setAttribute(lineNumber, "div-decoration", element);
-        }
-        this.revalidateDecorationsAndPaint();
-    },
-
-    _registerMouseListeners: function()
-    {
-        this.element.addEventListener("contextmenu", this._contextMenu.bind(this), false);
-        this.element.addEventListener("mouseup", this._mouseUp.bind(this), false);
-        this.element.addEventListener("mousedown", this._mouseDown.bind(this), false);
-        this.element.addEventListener("mousemove", this._mouseMove.bind(this), false);
-        this.element.addEventListener("mouseout", this._mouseOut.bind(this), false);
-        this.element.addEventListener("dblclick", this._dblClick.bind(this), false);
-    },
-
-    _registerKeyboardListeners: function()
-    {
-        this._container.addEventListener("keydown", this._keyDown.bind(this), false);
-        this._container.addEventListener("textInput", this._textInput.bind(this), false);
-    },
-
-    _registerClipboardListeners: function()
-    {
-        this._container.addEventListener("beforecopy", this._beforeCopy.bind(this), false);
-        this._container.addEventListener("copy", this._copy.bind(this), false);
-        this._container.addEventListener("beforecut", this._beforeCut.bind(this), false);
-        this._container.addEventListener("cut", this._cut.bind(this), false);
-        this._container.addEventListener("beforepaste", this._beforePaste.bind(this), false);
-        this._container.addEventListener("paste", this._paste.bind(this), false);
-    },
-
-    _offsetToLine: function(offset)
-    {
-        if (offset > this._lineOffsetsCache[this._lineOffsetsCache.length - 1]) {
-            // Seeking outside cached area. Fill the cache.
-            var lineNumber = this._lineOffsetsCache.length;
-            while (lineNumber < this._textModel.linesCount && this._lineToOffset(lineNumber) < offset)
-                lineNumber++;
-            return lineNumber;
-        }
-
-        // Bisect.
-        var from = 0;
-        var to = this._lineOffsetsCache.length;
-        while (to > from + 1) {
-            var mid = Math.floor((from + to) / 2);
-            if (this._lineOffsetsCache[mid] > offset)
-                to = mid;
-            else
-                from = mid;
-        }
-        return to;
-    },
-
-    _lineToOffset: function(lineNumber)
-    {
-        var offset = this._lineOffsetsCache[lineNumber];
-        if (offset)
-            return offset;
-        for (var line = lineNumber; line > 0; --line) {
-            if (this._lineOffsetsCache[line])
-                break;
-        }
-        offset = this._lineOffsetsCache[line];
-        for (var i = line + 1; i <= lineNumber; ++i) {
-            offset += this._lineHeight(i - 1);
-            this._lineOffsetsCache[i] = offset;
-        }
-        return offset;
-    },
-
-    _lineHeight: function(lineNumber)
-    {
-        // Use cached value first.
-        if (this._lineOffsetsCache[lineNumber + 1])
-            return this._lineOffsetsCache[lineNumber + 1] - this._lineOffsetsCache[lineNumber];
-
-        var element = this._textModel.getAttribute(lineNumber, "div-decoration");
-        if (element)
-            return 2 * this._textLineHeight + element.clientHeight;
-        return this._textLineHeight;
-    },
-
-    reveal: function(line, column)
-    {
-        this._scrollTop = this._container.scrollTop;
-        this._scrollLeft = this._container.scrollLeft;
-
-        var maxScrollTop = this._lineToOffset(line);
-        var minScrollTop = maxScrollTop + this._lineHeight(line) - this._canvas.height;
-        if (this._scrollTop > maxScrollTop)
-            this._container.scrollTop = maxScrollTop - this._textLineHeight * 2;
-        else if (this._scrollTop < minScrollTop)
-            this._container.scrollTop = minScrollTop + this._textLineHeight * 2;
-
-        var firstColumn = this._columnForOffset(line, this._scrollLeft);
-        var maxScrollLeft = this._columnToOffset(line, column);
-        var minScrollLeft = maxScrollLeft - this._container.clientWidth + this._lineNumberWidth;
-        if (this._scrollLeft < minScrollLeft)
-            this._container.scrollLeft = minScrollLeft + 100;
-        else if (this._scrollLeft > maxScrollLeft)
-            this._container.scrollLeft = maxScrollLeft;
-        else if (minScrollLeft < 0 && maxScrollLeft > 0)
-            this._container.scrollLeft = 0;
-    },
-
-    // WebInspector.TextModel listener
-    _textChanged: function(oldRange, newRange, oldText, newText)
-    {
-        if (newRange.linesCount == oldRange.linesCount)
-            this._invalidateLines(newRange.startLine, newRange.endLine + 1);
-        else
-            // Lines shifted, invalidate all under start line. Also clear lines that now are outside model range.
-            this._invalidateLines(newRange.startLine, this._textModel.linesCount + Math.max(0, oldRange.endLine - newRange.endLine));
-
-        if (this._highlightingEnabled) {
-            var lastVisibleLine = Math.min(this._textModel.linesCount, this._offsetToLine(this._scrollTop + this._canvas.height) + 1);
-            this._highlighter.updateHighlight(newRange.startLine, lastVisibleLine);
-        }
-
-        this._updatePreferredSize(newRange.startLine, Math.max(newRange.endLine, oldRange.endLine));
-        if (oldRange.linesCount !== newRange.linesCount) {
-            // Invalidate offset cache.
-            this._lineOffsetsCache.length = oldRange.startLine + 1;
-            // Force linenumber cache to be continuous.
-            this._lineToOffset(oldRange.startLine);
-            this.paintLineNumbers();
-        }
-        this._paint();
-    },
-
-    // WebInspector.TextSelectionModel listener
-    _selectionChanged: function(oldRange, newRange)
-    {
-        if (oldRange.isEmpty() && newRange.isEmpty() && oldRange.startLine === newRange.startLine) {
-            // Nothing to repaint.
-            return;
-        }
-
-        this._invalidateLines(oldRange.startLine, oldRange.endLine + 1);
-        this._invalidateLines(newRange.startLine, newRange.endLine + 1);
-        this._paint();
-    },
-
-    _highlightChanged: function(fromLine, toLine)
-    {
-        if (this._muteHighlightListener)
-            return;
-
-        this._invalidateLines(fromLine, toLine);
-        this._paint();
-    },
-
-    revalidateDecorationsAndPaint: function()
-    {
-        this.setCoalescingUpdate(true);
-        this._lineOffsetsCache = [0];
-        this._updatePreferredSize(0, this._textModel.linesCount);
-        this.repaintAll();
-        this.setCoalescingUpdate(false);
-    },
-
-    _updatePreferredSize: function(startLine, endLine)
-    {
-        this._ctx.font = this._font;
-        this.setCoalescingUpdate(true);
-        var guardedEndLine = Math.min(this._textModel.linesCount, endLine + 1);
-        var newMaximum = false;
-        for (var i = startLine; i < guardedEndLine; ++i) {
-            var lineWidth = this._ctx.measureText(this._textModel.line(i)).width;
-            if (lineWidth > this._textWidth) {
-                this._textWidth = lineWidth;
-                this._longestLineNumber = i;
-                newMaximum = true;
-            }
-        }
-
-        if (!newMaximum && startLine <= this._longestLineNumber && this._longestLineNumber <= endLine) {
-            this._textWidth = 0;
-            this._longestLineNumber = 0;
-            for (var i = 0; i < this._textModel.linesCount; ++i) {
-                var lineWidth = this._ctx.measureText(this._textModel.line(i)).width;
-                if (lineWidth > this._textWidth) {
-                    this._textWidth = lineWidth;
-                    this._longestLineNumber = i;
-                }
-            }
-        }
-
-        var newLineNumberDigits = this._decimalDigits(this._textModel.linesCount);
-        this._lineNumberWidth = (newLineNumberDigits + 2) * this._digitWidth;
-        this._container.style.left = this._lineNumberWidth + "px";
-
-        var newWidth = this._textWidth + "px";
-        var newHeight = this._lineToOffset(this._textModel.linesCount) + "px";
-        this._sheet.style.width = newWidth;
-        this._sheet.style.height = newHeight;
-
-        if (newLineNumberDigits !== this._lineNumberDigits) {
-            this._lineNumberDigits = newLineNumberDigits;
-            this.repaintAll();
-        }
-
-        // Changes to size can change the client area (scrollers can appear/disappear)
-        this.resize();
-        this.setCoalescingUpdate(false);
-    },
-
-    resize: function()
-    {
-        if (this._canvas.width !== this._container.clientWidth || this._canvas.height !== this._container.clientHeight) {
-            this._canvas.width = this._container.clientWidth + this._lineNumberWidth;
-            this._canvas.height = this._container.clientHeight;
-            this.repaintAll();
-        }
-    },
-
-    repaintAll: function()
-    {
-        this._invalidateLines(0, this._textModel.linesCount);
-        this._paint();
-    },
-
-    _invalidateLines: function(startLine, endLine)
-    {
-        if (!this._damage)
-            this._damage = [ { startLine: startLine, endLine: endLine } ];
-        else {
-            for (var i = 0; i < this._damage.length; ++i) {
-                var chunk = this._damage[i];
-                if (chunk.startLine <= endLine && chunk.endLine >= startLine) {
-                    chunk.startLine = Math.min(chunk.startLine, startLine);
-                    chunk.endLine = Math.max(chunk.endLine, endLine);
-                    return;
-                }
-            }
-            this._damage.push({ startLine: startLine, endLine: endLine });
-        }
-    },
-
-    _paint: function()
-    {
-        this._scrollTop = this._container.scrollTop;
-        this._scrollLeft = this._container.scrollLeft;
-
-        if (this._paintCoalescingLevel)
-            return;
-
-        this._updateDivDecorations();
-
-        this.paintLineNumbers();
-
-        for (var i = 0; this._damage && i < this._damage.length; ++i)
-            this._paintLines(this._damage[i].startLine, this._damage[i].endLine);
-        delete this._damage;
-
-        this._updateCursor(this._selection.endLine, this._selection.endColumn);
-    },
-
-    _paintLines: function(firstLine, lastLine)
-    {
-        this._ctx.font = this._font;
-        this._ctx.textBaseline = "bottom";
-
-        firstLine = Math.max(firstLine, this._offsetToLine(this._scrollTop) - 1);
-        lastLine = Math.min(lastLine, this._offsetToLine(this._scrollTop + this._canvas.height) + 1);
-        if (firstLine > lastLine)
-            return;
-
-        if (this._debugMode) {
-            WebInspector.log("Repaint %d:%d", firstLine, lastLine);
-            this._ctx.fillStyle = "rgb(255,255,0)";
-            var fromOffset = this._lineToOffset(firstLine);
-            var toOffset = this._lineToOffset(lastLine);
-            this._ctx.fillRect(this._lineNumberWidth - 1, fromOffset - this._scrollTop, this._canvas.width - this._lineNumberWidth + 1, toOffset - fromOffset);
-            setTimeout(this._paintLinesContinuation.bind(this, firstLine, lastLine), 100);
-        } else
-            this._paintLinesContinuation(firstLine, lastLine);
-    },
-
-    _paintLinesContinuation: function(firstLine, lastLine) {
-        // Clip editor area.
-        this._ctx.save();
-        this._ctx.beginPath();
-        this._ctx.rect(this._lineNumberWidth - 1, 0, this._canvas.width - this._lineNumberWidth + 1, this._canvas.height);
-        this._ctx.clip();
-
-        // First clear the region, then update last line to fit model (this clears removed lines from the end of the document).
-        var fromOffset = this._lineToOffset(firstLine);
-        var toOffset = lastLine < this._textModel.linesCount ? this._lineToOffset(lastLine) : this._canvas.height + this._scrollTop;
-
-        // Do not clear region when paintCurrentLine is likely to do all the necessary work.
-        if (this._readOnly || firstLine + 1 != lastLine || this._selection.endLine != firstLine) {
-            this._ctx.fillStyle = "rgb(255,255,255)";
-            this._ctx.fillRect(0, fromOffset - this._scrollTop, this._canvas.width, toOffset - fromOffset);
-        }
-        lastLine = Math.min(lastLine, this._textModel.linesCount);
-
-        // Paint current line for editable mode only.
-        if (!this._readOnly && this._selection.startLine === this._selection.endLine && firstLine <= this._selection.startLine && this._selection.startLine < lastLine)
-            this._paintCurrentLine(this._selection.startLine);
-
-        this._paintSelection(firstLine, lastLine);
-
-        if (this._highlightingEnabled) {
-            this._muteHighlightListener = true;
-            this._highlighter.highlight(lastLine);
-            delete this._muteHighlightListener;
-        }
-        for (var i = firstLine; i < lastLine; ++i) {
-            var lineOffset = this._lineToOffset(i) - this._scrollTop;
-
-            if (this._lineDecorator)
-                this._lineDecorator.decorate(i, this._ctx, this._lineNumberWidth - 1, lineOffset, this._canvas.width - this._lineNumberWidth + 1, this._lineHeight(i), this._textLineHeight);
-
-            var element = this._textModel.getAttribute(i, "div-decoration");
-            if (element)
-                this._positionDivDecoration(i, element, true);
-
-            this._paintLine(i, lineOffset);
-        }
-        this._ctx.restore();
-    },
-
-    _paintLine: function(lineNumber, lineOffset)
-    {
-        var line = this._textModel.line(lineNumber);
-        if (!this._highlightingEnabled) {
-            this._ctx.fillStyle = "rgb(0,0,0)";
-            this._ctx.fillText(line, this._lineNumberWidth - this._scrollLeft, lineOffset + this._textLineHeight);
-            return;
-        }
-
-        if (line.length > 1000) {
-            // Optimization: no need to paint decorations outside visible area.
-            var firstColumn = this._columnForOffset(lineNumber, this._scrollLeft);
-            var lastColumn = this._columnForOffset(lineNumber, this._scrollLeft + this._canvas.width);
-        }
-        var highlighterState = this._textModel.getAttribute(lineNumber, "highlighter-state");
-        var plainTextStart = -1;
-        for (var j = 0; j < line.length;) {
-            var attribute = highlighterState && highlighterState.attributes[j];
-            if (attribute && firstColumn && j + attribute.length < firstColumn) {
-                j += attribute.length;
-                continue;
-            }
-            if (attribute && lastColumn && j > lastColumn)
-                break;
-            if (!attribute || !attribute.style) {
-                if (plainTextStart === -1)
-                    plainTextStart = j;
-                j++;
-            } else {
-                if (plainTextStart !== -1) {
-                    this._ctx.fillStyle = "rgb(0,0,0)";
-                    this._ctx.fillText(line.substring(plainTextStart, j), this._lineNumberWidth - this._scrollLeft + this._columnToOffset(lineNumber, plainTextStart), lineOffset + this._textLineHeight);
-                    plainTextStart = -1;
-                }
-                this._ctx.fillStyle = attribute.style;
-                this._ctx.fillText(line.substring(j, j + attribute.length), this._lineNumberWidth - this._scrollLeft + this._columnToOffset(lineNumber, j), lineOffset + this._textLineHeight);
-                j += attribute.length;
-            }
-        }
-        if (plainTextStart !== -1) {
-            this._ctx.fillStyle = "rgb(0,0,0)";
-            this._ctx.fillText(line.substring(plainTextStart, j), this._lineNumberWidth - this._scrollLeft + this._columnToOffset(lineNumber, plainTextStart), lineOffset + this._textLineHeight);
-        }
-    },
-
-    paintLineNumbers: function()
-    {
-        this._ctx.font = this._font;
-        this._ctx.textBaseline = "bottom";
-
-        this._ctx.fillStyle = "rgb(255,255,255)";
-        this._ctx.fillRect(0, 0, this._lineNumberWidth - 2, this._canvas.height);
-
-        this._ctx.fillStyle = "rgb(235,235,235)";
-        this._ctx.fillRect(this._lineNumberWidth - 2, 0, 1, this._canvas.height);
-
-        var firstLine = Math.max(0, this._offsetToLine(this._scrollTop) - 1);
-        var lastLine = Math.min(this._textModel.linesCount, this._offsetToLine(this._scrollTop + this._canvas.height) + 1);
-
-        for (var i = firstLine; i < lastLine; ++i) {
-            var lineOffset = this._lineToOffset(i) - this._scrollTop;
-            this._ctx.fillStyle = "rgb(155,155,155)";
-            if (this._lineNumberDecorator && this._lineNumberDecorator.decorate(i, this._ctx, 0, lineOffset, this._lineNumberWidth, this._lineHeight(i), this._textLineHeight))
-                continue;
-            this._ctx.fillText(i + 1, (this._lineNumberDigits - this._decimalDigits(i + 1) + 1) * this._digitWidth, lineOffset + this._textLineHeight);
-        }
-    },
-
-    _paintCurrentLine: function(line)
-    {
-        this._ctx.fillStyle = "rgb(232, 242, 254)";
-        this._ctx.fillRect(0, this._lineToOffset(line) - this._scrollTop, this._canvas.width, this._lineHeight(line));
-    },
-
-    _scroll: function(e)
-    {
-        // Hide div-based cursor first.
-        this._cursor._cursorElement.style.display = "none";
-        setTimeout(this._repaintOnScroll.bind(this), 10);
-    },
-
-    _repaintOnScroll: function()
-    {
-        if (this._scrollTop !== this._container.scrollTop || this._scrollLeft !== this._container.scrollLeft) {
-            this._scrollTop = this._container.scrollTop;
-            this._scrollLeft = this._container.scrollLeft;
-            this.repaintAll();
-        }
-    },
-
-    _mouseUp: function(e)
-    {
-        this._isDragging = false;
-    },
-
-    _mouseDown: function(e)
-    {
-        if (e.button === 2 || (this._isMac && e.ctrlKey))
-            return;
-
-        var location = this._caretForMouseEvent(e);
-
-        if (e.target === this.element && this._lineNumberDecorator) {
-            if (this._lineNumberDecorator.mouseDown(location.line, e))            
-                return;
-        }
-
-        if (e.shiftKey)
-            this._setSelectionEnd(location.line, location.column);
-        else
-            this._setCaretLocation(location.line, location.column);
-        this._isDragging = true;
-        this._textModel.markUndoableState();
-    },
-
-    _mouseMove: function(e)
-    {
-        if (!this._isDragging)
-            return;
-        var location = this._caretForMouseEvent(e);
-        this._setSelectionEnd(location.line, location.column)
-    },
-
-    _mouseOut: function(e)
-    {
-    },
-
-    _dblClick: function(e)
-    {
-        var location = this._caretForMouseEvent(e);
-        var range = this._textModel.wordRange(location.line, location.column);
-        this.setSelection(range.startLine, range.startColumn, range.endLine, range.endColumn);
-    },
-
-    _contextMenu: function(e)
-    {
-        if (e.target === this.element && this._lineNumberDecorator) {
-            var location = this._caretForMouseEvent(e);
-            if (this._lineNumberDecorator.contextMenu(location.line, e))
-                return;
-        } else {
-            var range = this._selection.range();
-            if (!range.isEmpty()) {
-                var text = this._textModel.copyRange(range);
-                var contextMenu = new WebInspector.ContextMenu();
-                contextMenu.appendItem(WebInspector.UIString("Copy"), this._copy.bind(this));
-                contextMenu.show(event);
-            }
-        }
-    },
-
-    _caretForMouseEvent: function(e)
-    {
-        var lineNumber = Math.max(0, this._offsetToLine(e.offsetY + (e.target === this.element ? this._scrollTop : 0)) - 1);
-        var offset = e.offsetX + this._scrollLeft;
-        return { line: lineNumber, column: this._columnForOffset(lineNumber, offset) };
-    },
-
-    _columnForOffset: function(lineNumber, offset)
-    {
-        var length = 0;
-        var line = this._textModel.line(lineNumber);
-
-        // First pretend it is monospace to get a quick guess.
-        var charWidth = this._ctx.measureText("a").width;
-        var index = Math.floor(offset / charWidth);
-        var indexOffset = this._ctx.measureText(line.substring(0, index)).width;
-        if (offset >= indexOffset && index < line.length && offset < indexOffset + this._ctx.measureText(line.charAt(index)).width)
-            return index;
-
-        // Fallback to non-monospace.
-        var delta = indexOffset < offset ? 1 : -1;
-        while (index >=0 && index < line.length) {
-            index += delta;
-            indexOffset += delta * this._ctx.measureText(line.charAt(index)).width;
-            if (offset >= indexOffset && offset < indexOffset + charWidth)
-                return index;
-        }
-        return line.length;
-    },
-
-    _columnToOffset: function(lineNumber, column)
-    {
-        var line = this._textModel.line(lineNumber);
-        return this._ctx.measureText(line.substring(0, column)).width;
-    },
-
-    _keyDown: function(e)
-    {
-        var shortcutKey = WebInspector.KeyboardShortcut.makeKeyFromEvent(e);
-        var handler = this._shortcuts[shortcutKey];
-        if (handler) {
-            handler.call(this);
-            e.preventDefault();
-            e.stopPropagation();
-            return;
-        }
-
-        if (this._handleNavigationKey(e)) {
-            e.preventDefault();
-            e.stopPropagation();
-            return;
-        }
-
-        if (this._readOnly)
-            return;
-
-        var keyCodes = WebInspector.KeyboardShortcut.KeyCodes;
-        switch (e.keyCode) {
-            case keyCodes.Backspace:
-                this._handleBackspaceKey();
-                break;
-            case keyCodes.Delete:
-                this._handleDeleteKey();
-                break;
-            case keyCodes.Tab:
-                this._replaceSelectionWith("\t");
-                break;
-            case keyCodes.Enter:
-                this._replaceSelectionWith("\n");
-                break;
-            default:
-                return;
-        }
-
-        e.preventDefault();
-        e.stopPropagation();
-    },
-
-    _handleNavigationKey: function(e)
-    {
-        var caretLine = this._selection.endLine;
-        var caretColumn = this._selection.endColumn;
-        var arrowAction = e.shiftKey ? this._setSelectionEnd : this._setCaretLocation;
-
-        var keyCodes = WebInspector.KeyboardShortcut.KeyCodes;
-        switch (e.keyCode) {
-            case keyCodes.Up:
-            case keyCodes.PageUp:
-                if (e.metaKey)
-                    arrowAction.call(this, 0, 0, true);
-                else if (e.ctrlKey)
-                    this._container.scrollTop -= this._lineHeight(caretLine);
-                else {
-                    if (e.keyCode === keyCodes.Up)
-                        arrowAction.call(this, caretLine - 1, this._desiredCaretColumn, true);
-                    else {
-                        var offset = Math.max(0, this._lineToOffset(caretLine) - this._canvas.height);
-                        arrowAction.call(this, this._offsetToLine(offset), this._desiredCaretColumn, true);
-                    }
-                }
-                break;
-            case keyCodes.Down:
-            case keyCodes.PageDown:
-                if (e.metaKey)
-                    arrowAction.call(this, this._textModel.linesCount - 1, this._textModel.lineLength(this._textModel.linesCount - 1), true);
-                else if (e.ctrlKey)
-                    this._container.scrollTop += this._lineHeight(caretLine);
-                else {
-                    if (e.keyCode === keyCodes.Down)
-                        arrowAction.call(this, caretLine + 1, this._desiredCaretColumn, true);
-                    else {
-                        var offset = this._lineToOffset(caretLine) + this._canvas.height;
-                        arrowAction.call(this, this._offsetToLine(offset), this._desiredCaretColumn, true);
-                    }
-                }
-                break;
-            case keyCodes.Home:
-                if (this._isMetaCtrl(e))
-                    arrowAction.call(this, 0, 0, true);
-                else
-                    arrowAction.call(this, this._selection.endLine, 0);
-                break;
-            case keyCodes.End:
-                if (this._isMetaCtrl(e))
-                    arrowAction.call(this, this._textModel.linesCount - 1, this._textModel.lineLength(this._textModel.linesCount - 1), true);
-                else
-                    arrowAction.call(this, this._selection.endLine, this._textModel.lineLength(this._selection.endLine));
-                break;
-            case keyCodes.Left:
-                if (!e.shiftKey && !e.metaKey && !this._isAltCtrl(e) && !this._selection.isEmpty()) {
-                    // Reset selection
-                    var range = this._selection.range();
-                    this._setCaretLocation(range.startLine, range.startColumn);
-                } else if (e.metaKey)
-                    arrowAction.call(this, this._selection.endLine, 0);
-                else if (caretColumn === 0 && caretLine > 0)
-                    arrowAction.call(this, caretLine - 1, this._textModel.lineLength(caretLine - 1));
-                else if (this._isAltCtrl(e)) {
-                    caretColumn = this._textModel.wordStart(this._selection.endLine, this._selection.endColumn);
-                    if (caretColumn === this._selection.endColumn)
-                        caretColumn = 0;
-                    arrowAction.call(this, caretLine, caretColumn);
-                } else
-                    arrowAction.call(this, caretLine, caretColumn - 1);
-                break;
-            case keyCodes.Right:
-                var line = this._textModel.line(caretLine);
-                if (!e.shiftKey && !e.metaKey && !this._isAltCtrl(e) && !this._selection.isEmpty()) {
-                    // Reset selection
-                    var range = this._selection.range();
-                    this._setCaretLocation(range.endLine, range.endColumn);
-                } else if (e.metaKey)
-                    arrowAction.call(this, this._selection.endLine, this._textModel.lineLength(this._selection.endLine));
-                else if (caretColumn === line.length && caretLine < this._textModel.linesCount - 1)
-                    arrowAction.call(this, caretLine + 1, 0);
-                else if (this._isAltCtrl(e)) {
-                    caretColumn = this._textModel.wordEnd(this._selection.endLine, this._selection.endColumn);
-                    if (caretColumn === this._selection.endColumn)
-                        caretColumn = line.length;
-                    arrowAction.call(this, caretLine, caretColumn);
-                } else
-                    arrowAction.call(this, caretLine, caretColumn + 1);
-                break;
-            default:
-                return false;
-        }
-        this._textModel.markUndoableState();
-        return true;
-    },
-
-    _textInput: function(e)
-    {
-        if (this._readOnly)
-            return;
-
-        if (e.data && !e.altKey && !e.ctrlKey && !e.metaKey) {
-            this._replaceSelectionWith(e.data);
-            e.preventDefault();
-            e.stopPropagation();
-        }
-    },
-
-    _setCaretLocation: function(line, column, updown)
-    {
-        this.setSelection(line, column, line, column, updown);
-    },
-
-    _setSelectionEnd: function(line, column, updown)
-    {
-        if (!updown)
-            this._desiredCaretColumn = column;
-
-        var end = this._fit(line, column);
-        this._selection.setEnd(end.line, end.column);
-        this.reveal(this._selection.endLine, this._selection.endColumn);
-        this._updateCursor(end.line, end.column);
-    },
-
-    _updateDivDecorations: function()
-    {
-        var firstLine = this._offsetToLine(this._scrollTop) - 1;
-        var lastLine = this._offsetToLine(this._scrollTop + this._canvas.height) + 1;
-
-        var linesCount = this._textModel.linesCount;
-        for (var i = 0; i < linesCount; ++i) {
-            var element = this._textModel.getAttribute(i, "div-decoration");
-            if (element) {
-                this._lineOffsetsCache.length = Math.min(this._lineOffsetsCache.length, i + 1);
-                this._positionDivDecoration(i, element, i > firstLine && i < lastLine);
-            }
-        }
-    },
-
-    _positionDivDecoration: function(lineNumber, element, visible)
-    {
-        element.style.position = "absolute";
-        element.style.top = this._lineToOffset(lineNumber) - this._scrollTop + this._textLineHeight + "px";
-        element.style.left = this._lineNumberWidth + "px";
-        element.style.setProperty("max-width", this._canvas.width + "px");
-    },
-
-    _updateCursor: function(line, column)
-    {
-        if (line >= this._textModel.linesCount)
-            return;
-        var offset = this._columnToOffset(line, column);
-        if (offset >= this._container.scrollLeft && !this._readOnly)
-            this._cursor.setLocation(this._lineNumberWidth + offset - 1, this._lineToOffset(line));
-        else
-            this._cursor.hide();
-    },
-
-    _fit: function(line, column)
-    {
-        line = Math.max(0, Math.min(line, this._textModel.linesCount - 1));
-        var lineLength = this._textModel.lineLength(line);
-        column = Math.max(0, Math.min(column, lineLength));
-        return { line: line, column: column };
-    },
-
-    _paintSelection: function(firstLine, lastLine)
-    {
-        if (this._selection.isEmpty())
-            return;
-        var range = this._selection.range();
-        this._ctx.fillStyle = this._selectionColor;
-
-        firstLine = Math.max(firstLine, range.startLine);
-        endLine = Math.min(lastLine, range.endLine + 1);
-
-        for (var i = firstLine; i < endLine; ++i) {
-            var line = this._textModel.line(i);
-            var from, to;
-
-            if (i === range.startLine) {
-                var offset = this._columnToOffset(range.startLine, range.startColumn);
-                from = offset - this._scrollLeft + this._lineNumberWidth - 1;
-            } else
-                from = 0;
-
-            if (i === range.endLine) {
-                var offset = this._columnToOffset(range.endLine, range.endColumn);
-                to = offset - this._scrollLeft + this._lineNumberWidth - 1;
-            } else
-                to = this._canvas.width;
-
-            this._ctx.fillRect(from, this._lineToOffset(i) - this._scrollTop, to - from, this._lineHeight(i));
-        }
-        this._ctx.fillStyle = "rgb(0, 0, 0)";
-    },
-
-    _beforeCopy: function(e)
-    {
-        if (!this._selection.isEmpty())
-            e.preventDefault();
-    },
-
-    _copy: function(e)
-    {
-        var range = this._selection.range();
-        var text = this._textModel.copyRange(range);
-
-        function delayCopy()
-        {
-            InspectorFrontendHost.copyText(text);
-        }
-
-        setTimeout(delayCopy);
-        if (e)
-            e.preventDefault();
-    },
-
-    _beforeCut: function(e)
-    {
-        if (!this._selection.isEmpty())
-            e.preventDefault();
-    },
-
-    _cut: function(e)
-    {
-        if (this._readOnly) {
-            e.preventDefault();
-            return;
-        }
-
-        this._textModel.markUndoableState();
-        this._copy(e);
-        this._replaceSelectionWith("");
-    },
-
-    _beforePaste: function(e)
-    {
-        e.preventDefault();
-    },
-
-    _paste: function(e)
-    {
-        if (this._readOnly) {
-            e.preventDefault();
-            return;
-        }
-
-        var text = e.clipboardData.getData("Text");
-        if (!text)
-            return;
-
-        this._textModel.markUndoableState();
-        this._replaceSelectionWith(text);
-        e.preventDefault();
-    },
-
-    _replaceSelectionWith: function(newText, overrideRange)
-    {
-        var range = overrideRange || this._selection.range();
-        this.setCoalescingUpdate(true);
-        var newRange = this._textModel.setText(range, newText);
-        this._setCaretLocation(newRange.endLine, newRange.endColumn);
-        this.setCoalescingUpdate(false);
-    },
-
-    setCoalescingUpdate: function(enabled)
-    {
-        if (enabled)
-            this._paintCoalescingLevel++;
-        else
-            this._paintCoalescingLevel--;
-        if (!this._paintCoalescingLevel)
-            this._paint();
-    },
-
-    _selectAll: function()
-    {
-        // No need to reveal last selection line in select all.
-        this._selection.setStart(0, 0);
-        var lastLineNum = this._textModel.linesCount - 1;
-        this._selection.setEnd(lastLineNum, this._textModel.lineLength(lastLineNum));
-        this._updateCursor(this._selection.endLine, this._selection.endColumn);
-    },
-
-    initFontMetrics: function()
-    {
-        var computedStyle = window.getComputedStyle(this.element);
-        this._font = computedStyle.fontSize + " " + computedStyle.fontFamily;
-        this._ctx.font = this._font;
-        this._digitWidth = this._ctx.measureText("0").width;
-        this._textLineHeight = Math.floor(parseInt(this._ctx.font) * 1.4);
-        this._cursor.setTextLineHeight(this._textLineHeight);
-    },
-
-    _registerShortcuts: function()
-    {
-        var modifiers = WebInspector.KeyboardShortcut.Modifiers;
-        this._shortcuts = {};
-        this._shortcuts[WebInspector.KeyboardShortcut.makeKey("z", this._isMac ? modifiers.Meta : modifiers.Ctrl)] = this._handleUndo.bind(this);
-        this._shortcuts[WebInspector.KeyboardShortcut.makeKey("z", modifiers.Shift | (this._isMac ? modifiers.Meta : modifiers.Ctrl))] = this._handleRedo.bind(this);
-        this._shortcuts[WebInspector.KeyboardShortcut.makeKey("a", this._isMac ? modifiers.Meta : modifiers.Ctrl)] = this._selectAll.bind(this);
-        if (this._isMac)
-            this._shortcuts[WebInspector.KeyboardShortcut.makeKey("d", modifiers.Ctrl)] = this._handleDeleteKey.bind(this);
-
-        this._shortcuts[WebInspector.KeyboardShortcut.makeKey("d", modifiers.Ctrl | modifiers.Alt)] = this._handleToggleDebugMode.bind(this);
-        this._shortcuts[WebInspector.KeyboardShortcut.makeKey("h", modifiers.Ctrl | modifiers.Alt)] = this._handleToggleHighlightMode.bind(this);
-    },
-
-    _handleUndo: function()
-    {
-        this.setCoalescingUpdate(true);
-        var range = this._textModel.undo();
-        if (range)
-            this._setCaretLocation(range.endLine, range.endColumn);
-        this.setCoalescingUpdate(false);
-    },
-
-    _handleRedo: function()
-    {
-        this.setCoalescingUpdate(true);
-        var range = this._textModel.redo();
-        if (range)
-            this._setCaretLocation(range.endLine, range.endColumn);
-        this.setCoalescingUpdate(false);
-    },
-
-    _handleDeleteKey: function()
-    {
-        var range = this._selection.range();
-        if (range.isEmpty()) {
-            if (range.endColumn < this._textModel.lineLength(range.startLine))
-                range.endColumn++;
-            else if (range.endLine < this._textModel.linesCount) {
-                range.endLine++;
-                range.endColumn = 0;
-            } else
-                return;
-        } else
-            this._textModel.markUndoableState();
-        this._replaceSelectionWith("", range);
-    },
-
-    _handleBackspaceKey: function()
-    {
-        var range = this._selection.range();
-        if (range.isEmpty()) {
-            if (range.startColumn > 0)
-                range.startColumn--;
-            else if (range.startLine > 0) {
-                range.startLine--;
-                range.startColumn = this._textModel.lineLength(range.startLine);
-            } else
-                return;
-        } else
-            this._textModel.markUndoableState();
-        this._replaceSelectionWith("", range);
-    },
-
-    _handleToggleDebugMode: function()
-    {
-        this._debugMode = !this._debugMode;
-    },
-
-    _handleToggleHighlightMode: function()
-    {
-        this._highlightingEnabled = !this._highlightingEnabled;
-    },
-
-    _isMetaCtrl: function(e)
-    {
-        return this._isMac ? e.metaKey : e.ctrlKey;
-    },
-
-    _isAltCtrl: function(e)
-    {
-        return this._isMac ? e.altKey : e.ctrlKey;
-    },
-
-    _decimalDigits: function(number)
-    {
-        return Math.ceil(Math.log(number + 1) / Math.log(10));
-    }
-}
-
-WebInspector.TextSelectionModel = function(changeListener)
-{
-    this.startLine = 0;
-    this.startColumn = 0;
-    this.endLine = 0;
-    this.endColumn = 0;
-    this._changeListener = changeListener;
-}
-
-WebInspector.TextSelectionModel.prototype = {
-    setStart: function(line, column)
-    {
-        var oldRange = this.range();
-
-        this.startLine = line;
-        this.startColumn = column;
-        this.endLine = line;
-        this.endColumn = column;
-
-        this._changeListener(oldRange, this.range());
-    },
-
-    setEnd: function(line, column)
-    {
-        var oldRange = this.range();
-
-        this.endLine = line;
-        this.endColumn = column;
-
-        this._changeListener(oldRange, this.range(), this.endLine, this.endColumn);
-    },
-
-    range: function()
-    {
-        if (this.startLine < this.endLine || (this.startLine === this.endLine && this.startColumn <= this.endColumn))
-            return new WebInspector.TextRange(this.startLine, this.startColumn, this.endLine, this.endColumn);
-        else
-            return new WebInspector.TextRange(this.endLine, this.endColumn, this.startLine, this.startColumn);
-    },
-
-    isEmpty: function()
-    {
-        return this.startLine === this.endLine && this.startColumn === this.endColumn;
-    }
-}
-
-WebInspector.TextCursor = function(cursorElement)
-{
-    this._visible = false;
-    this._cursorElement = cursorElement;
-}
-
-WebInspector.TextCursor.prototype = {
-    setLocation: function(x, y)
-    {
-        this._x = x;
-        this._y = y;
-        if (this._paintInterval) {
-            window.clearInterval(this._paintInterval);
-            delete this._paintInterval;
-        }
-        this._paintInterval = window.setInterval(this._paint.bind(this, false), 500);
-        this._paint(true);
-    },
-
-    hide: function()
-    {
-        if (this._paintInterval) {
-            window.clearInterval(this._paintInterval);
-            delete this._paintInterval;
-        }
-        this._cursorElement.style.display = "none";
-    },
-
-    setTextLineHeight: function(textLineHeight)
-    {
-        this._cursorElement.style.height = textLineHeight + "px";
-    },
-
-    _paint: function(force)
-    {
-        if (force)
-            this._visible = true;
-        else
-            this._visible = !this._visible;
-        this._cursorElement.style.left = this._x + "px";
-        this._cursorElement.style.top = this._y + "px";
-        this._cursorElement.style.display = this._visible ? "block" : "none";
-    }
-}
diff --git a/WebCore/inspector/front-end/TextViewer.js b/WebCore/inspector/front-end/TextViewer.js
new file mode 100644
index 0000000..ced7232
--- /dev/null
+++ b/WebCore/inspector/front-end/TextViewer.js
@@ -0,0 +1,666 @@
+/*
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ *     * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *     * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following disclaimer
+ * in the documentation and/or other materials provided with the
+ * distribution.
+ *     * Neither the name of Google Inc. nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+WebInspector.TextViewer = function(textModel, platform, url)
+{
+    this._textModel = textModel;
+    this._textModel.changeListener = this._buildChunks.bind(this);
+    this._highlighter = new WebInspector.TextEditorHighlighter(this._textModel, this._highlightDataReady.bind(this));
+
+    this.element = document.createElement("div");
+    this.element.className = "text-editor monospace";
+
+    this.element.addEventListener("scroll", this._scroll.bind(this), false);
+
+    this._url = url;
+
+    this._linesContainerElement = document.createElement("table");
+    this._linesContainerElement.className = "text-editor-lines";
+    this._linesContainerElement.setAttribute("cellspacing", 0);
+    this._linesContainerElement.setAttribute("cellpadding", 0);
+    this.element.appendChild(this._linesContainerElement);
+
+    this._defaultChunkSize = 50;
+    this._paintCoalescingLevel = 0;
+}
+
+WebInspector.TextViewer.prototype = {
+    set mimeType(mimeType)
+    {
+        this._highlighter.mimeType = mimeType;
+    },
+
+    get textModel()
+    {
+        return this._textModel;
+    },
+
+    revealLine: function(lineNumber)
+    {
+        if (lineNumber >= this._textModel.linesCount)
+            return;
+
+        var chunk = this._makeLineAChunk(lineNumber);
+        chunk.element.scrollIntoViewIfNeeded();
+    },
+
+    addDecoration: function(lineNumber, decoration)
+    {
+        var chunk = this._makeLineAChunk(lineNumber);
+        chunk.addDecoration(decoration);
+    },
+
+    removeDecoration: function(lineNumber, decoration)
+    {
+        var chunk = this._makeLineAChunk(lineNumber);
+        chunk.removeDecoration(decoration);
+    },
+
+    markAndRevealRange: function(range)
+    {
+        if (this._rangeToMark) {
+            var markedLine = this._rangeToMark.startLine;
+            this._rangeToMark = null;
+            this._paintLines(markedLine, markedLine + 1);
+        }
+
+        if (range) {
+            this._rangeToMark = range;
+            this.revealLine(range.startLine);
+            this._paintLines(range.startLine, range.startLine + 1);
+        }
+    },
+
+    highlightLine: function(lineNumber)
+    {
+        // FIXME: restore animation.
+        if (typeof this._highlightedLine === "number") {
+            var chunk = this._makeLineAChunk(this._highlightedLine);
+            chunk.removeDecoration("webkit-highlighted-line");
+        }
+        this._highlightedLine = lineNumber;
+        this.revealLine(lineNumber);
+        var chunk = this._makeLineAChunk(lineNumber);
+        chunk.addDecoration("webkit-highlighted-line");
+    },
+
+    _buildChunks: function()
+    {
+        this._linesContainerElement.removeChildren();
+
+        var paintLinesCallback = this._paintLines.bind(this);
+        this._textChunks = [];
+        for (var i = 0; i < this._textModel.linesCount; i += this._defaultChunkSize) {
+            var chunk = new WebInspector.TextChunk(this._textModel, i, i + this._defaultChunkSize, paintLinesCallback);
+            this._textChunks.push(chunk);
+            this._linesContainerElement.appendChild(chunk.element);
+        }
+        this._indexChunks();
+        this._repaintAll();
+    },
+
+    _makeLineAChunk: function(lineNumber)
+    {
+        if (!this._textChunks)
+            this._buildChunks();
+
+        var chunkNumber = this._chunkNumberForLine(lineNumber);
+        var oldChunk = this._textChunks[chunkNumber];
+        if (oldChunk.linesCount === 1)
+            return oldChunk;
+
+        var wasExpanded = oldChunk.expanded;
+        oldChunk.expanded = false;
+
+        var insertIndex = oldChunk.chunkNumber + 1;
+        var paintLinesCallback = this._paintLines.bind(this);
+
+        // Prefix chunk.
+        if (lineNumber > oldChunk.startLine) {
+            var prefixChunk = new WebInspector.TextChunk(this._textModel, oldChunk.startLine, lineNumber, paintLinesCallback);
+            this._textChunks.splice(insertIndex++, 0, prefixChunk);
+            this._linesContainerElement.insertBefore(prefixChunk.element, oldChunk.element);
+        }
+
+        // Line chunk.
+        var lineChunk = new WebInspector.TextChunk(this._textModel, lineNumber, lineNumber + 1, paintLinesCallback);
+        this._textChunks.splice(insertIndex++, 0, lineChunk);
+        this._linesContainerElement.insertBefore(lineChunk.element, oldChunk.element);
+
+        // Suffix chunk.
+        if (oldChunk.startLine + oldChunk.linesCount > lineNumber + 1) {
+            var suffixChunk = new WebInspector.TextChunk(this._textModel, lineNumber + 1, oldChunk.startLine + oldChunk.linesCount, paintLinesCallback);
+            this._textChunks.splice(insertIndex, 0, suffixChunk);
+            this._linesContainerElement.insertBefore(suffixChunk.element, oldChunk.element);
+        }
+
+        // Remove enclosing chunk.
+        this._textChunks.splice(oldChunk.chunkNumber, 1);
+        this._linesContainerElement.removeChild(oldChunk.element);
+        this._indexChunks();
+
+        if (wasExpanded) {
+            if (prefixChunk)
+                prefixChunk.expanded = true;
+            lineChunk.expanded = true;
+            if (suffixChunk)
+                suffixChunk.expanded = true;
+        }
+
+        return lineChunk;
+    },
+
+    _indexChunks: function()
+    {
+        for (var i = 0; i < this._textChunks.length; ++i)
+            this._textChunks[i].chunkNumber = i;
+    },
+
+    _scroll: function()
+    {
+        this._repaintAll();
+    },
+
+    beginUpdates: function(enabled)
+    {
+        this._paintCoalescingLevel++;
+    },
+
+    endUpdates: function(enabled)
+    {
+        this._paintCoalescingLevel--;
+        if (!this._paintCoalescingLevel)
+            this._repaintAll();
+    },
+
+    _chunkForOffset: function(offset)
+    {
+        var currentOffset = 0;
+        var row = this._linesContainerElement.firstChild;
+        while (row) {
+            var rowHeight = row.offsetHeight;
+            if (offset >= currentOffset && offset < currentOffset + rowHeight)
+                return row.chunkNumber;
+            row = row.nextSibling;
+            currentOffset += rowHeight;
+        }
+        return this._textChunks.length - 1;
+    },
+
+    _chunkNumberForLine: function(lineNumber)
+    {
+        for (var i = 0; i < this._textChunks.length; ++i) {
+            var line = this._textChunks[i].startLine;
+            if (lineNumber >= this._textChunks[i].startLine && lineNumber < this._textChunks[i].startLine + this._textChunks[i].linesCount)
+                return i;
+        }
+        return this._textChunks.length - 1;
+    },
+
+    _chunkForLine: function(lineNumber)
+    {
+        return this._textChunks[this._chunkNumberForLine(lineNumber)];
+    },
+
+    _chunkStartLine: function(chunkNumber)
+    {
+        var lineNumber = 0;
+        for (var i = 0; i < chunkNumber && i < this._textChunks.length; ++i)
+            lineNumber += this._textChunks[i].linesCount;
+        return lineNumber;
+    },
+
+    _repaintAll: function()
+    {
+        if (this._paintCoalescingLevel)
+            return;
+
+        if (!this._textChunks)
+            this._buildChunks();
+
+        var visibleFrom = this.element.scrollTop;
+        var visibleTo = this.element.scrollTop + this.element.clientHeight;
+
+        var offset = 0;
+        var firstVisibleLine = -1;
+        var lastVisibleLine = 0;
+        var toExpand = [];
+        var toCollapse = [];
+        for (var i = 0; i < this._textChunks.length; ++i) {
+            var chunk = this._textChunks[i];
+            var chunkHeight = chunk.height;
+            if (offset + chunkHeight > visibleFrom && offset < visibleTo) {
+                toExpand.push(chunk);
+                if (firstVisibleLine === -1)
+                    firstVisibleLine = chunk.startLine;
+                lastVisibleLine = chunk.startLine + chunk.linesCount;
+            } else {
+                toCollapse.push(chunk);
+                if (offset >= visibleTo)
+                    break;
+            }
+            offset += chunkHeight;
+        }
+
+        for (var j = i; j < this._textChunks.length; ++j)
+            toCollapse.push(this._textChunks[i]);
+
+        var selection = this._getSelection();
+
+        this._muteHighlightListener = true;
+        this._highlighter.highlight(lastVisibleLine);
+        delete this._muteHighlightListener;
+
+        for (var i = 0; i < toCollapse.length; ++i)
+            toCollapse[i].expanded = false;
+        for (var i = 0; i < toExpand.length; ++i)
+            toExpand[i].expanded = true;
+
+        this._restoreSelection(selection);
+    },
+
+    _highlightDataReady: function(fromLine, toLine)
+    {
+        if (this._muteHighlightListener)
+            return;
+
+        var selection;
+        for (var i = fromLine; i < toLine; ++i) {
+            var lineRow = this._textModel.getAttribute(i, "line-row");
+            if (!lineRow || lineRow.highlighted)
+                continue;
+            if (!selection)
+                selection = this._getSelection();
+            this._paintLine(lineRow, i);
+        }
+        this._restoreSelection(selection);
+    },
+
+    _paintLines: function(fromLine, toLine)
+    {
+        for (var i = fromLine; i < toLine; ++i) {
+            var lineRow = this._textModel.getAttribute(i, "line-row");
+            if (lineRow)
+                this._paintLine(lineRow, i);
+        }
+    },
+
+    _paintLine: function(lineRow, lineNumber)
+    {
+        var element = lineRow.lastChild;
+        var highlighterState = this._textModel.getAttribute(lineNumber, "highlighter-state");
+        var line = this._textModel.line(lineNumber);
+
+        if (!highlighterState) {
+            if (this._rangeToMark && this._rangeToMark.startLine === lineNumber)
+                this._markRange(element, line, this._rangeToMark.startColumn, this._rangeToMark.endColumn);
+            return;
+        }
+
+        element.removeChildren();
+
+        var plainTextStart = -1;
+        for (var j = 0; j < line.length;) {
+            if (j > 1000) {
+                // This line is too long - do not waste cycles on minified js highlighting.
+                break;
+            }
+            var attribute = highlighterState && highlighterState.attributes[j];
+            if (!attribute || !attribute.style) {
+                if (plainTextStart === -1)
+                    plainTextStart = j;
+                j++;
+            } else {
+                if (plainTextStart !== -1) {
+                    element.appendChild(document.createTextNode(line.substring(plainTextStart, j)));
+                    plainTextStart = -1;
+                }
+                element.appendChild(this._createSpan(line.substring(j, j + attribute.length), attribute.tokenType));
+                j += attribute.length;
+            }
+        }
+        if (plainTextStart !== -1)
+            element.appendChild(document.createTextNode(line.substring(plainTextStart, line.length)));
+        if (this._rangeToMark && this._rangeToMark.startLine === lineNumber)
+            this._markRange(element, line, this._rangeToMark.startColumn, this._rangeToMark.endColumn);
+        if (lineRow.decorationsElement)
+            element.appendChild(lineRow.decorationsElement);
+    },
+
+    _getSelection: function()
+    {
+        var selection = window.getSelection();
+        if (selection.isCollapsed)
+            return null;
+        var selectionRange = selection.getRangeAt(0);
+        var start = this._selectionToPosition(selectionRange.startContainer, selectionRange.startOffset);
+        var end = this._selectionToPosition(selectionRange.endContainer, selectionRange.endOffset);
+        return new WebInspector.TextRange(start.line, start.column, end.line, end.column);
+    },
+
+    _restoreSelection: function(range)
+    {
+        if (!range)
+            return;
+        var startRow = this._textModel.getAttribute(range.startLine, "line-row");
+        if (startRow)
+            var start = startRow.lastChild.rangeBoundaryForOffset(range.startColumn);
+        else {
+            var offset = range.startColumn;
+            var chunkNumber = this._chunkNumberForLine(range.startLine);
+            for (var i = this._chunkStartLine(chunkNumber); i < range.startLine; ++i)
+                offset += this._textModel.line(i).length + 1; // \n
+            var lineCell = this._textChunks[chunkNumber].element.lastChild;
+            if (lineCell.firstChild)
+                var start = { container: lineCell.firstChild, offset: offset };
+            else
+                var start = { container: lineCell, offset: 0 };
+        }
+
+        var endRow = this._textModel.getAttribute(range.endLine, "line-row");
+        if (endRow)
+            var end = endRow.lastChild.rangeBoundaryForOffset(range.endColumn);
+        else {
+            var offset = range.endColumn;
+            var chunkNumber = this._chunkNumberForLine(range.endLine);
+            for (var i = this._chunkStartLine(chunkNumber); i < range.endLine; ++i)
+                offset += this._textModel.line(i).length + 1; // \n
+            var lineCell = this._textChunks[chunkNumber].element.lastChild;
+            if (lineCell.firstChild)
+                var end = { container: lineCell.firstChild, offset: offset };
+            else
+                var end = { container: lineCell, offset: 0 };
+        }
+
+        var selectionRange = document.createRange();
+        selectionRange.setStart(start.container, start.offset);
+        selectionRange.setEnd(end.container, end.offset);
+
+        var selection = window.getSelection();
+        selection.removeAllRanges();
+        selection.addRange(selectionRange);
+    },
+
+    _selectionToPosition: function(container, offset)
+    {
+        if (container === this.element && offset === 0)
+            return { line: 0, column: 0 };
+        if (container === this.element && offset === 1)
+            return { line: this._textModel.linesCount - 1, column: this._textModel.lineLength(this._textModel.linesCount - 1) };
+
+        var lineRow = container.enclosingNodeOrSelfWithNodeName("tr");
+        var lineNumber = lineRow.lineNumber;
+        if (container.nodeName === "TD" && offset === 0)
+            return { line: lineNumber, column: 0 };
+        if (container.nodeName === "TD" && offset === 1)
+            return { line: lineNumber, column: this._textModel.lineLength(lineNumber) };
+
+        var column = 0;
+        if (lineRow.chunk) {
+            // This is chunk.
+            var text = lineRow.lastChild.textContent;
+            for (var i = 0; i < offset; ++i) {
+                if (text.charAt(i) === "\n") {
+                    lineNumber++;
+                    column = 0;
+                } else
+                    column++; 
+            }
+            return { line: lineNumber, column: column };
+        }
+
+        // This is individul line.
+        var column = 0;
+        var node = lineRow.lastChild.traverseNextTextNode(lineRow.lastChild);
+        while (node && node !== container) {
+            column += node.textContent.length;
+            node = node.traverseNextTextNode(lineRow.lastChild);
+        }
+        column += offset;
+        return { line: lineRow.lineNumber, column: column };
+    },
+
+    _createSpan: function(content, className)
+    {
+        if (className === "html-resource-link" || className === "html-external-link")
+            return this._createLink(content, className === "html-external-link");
+
+        var span = document.createElement("span");
+        span.className = "webkit-" + className;
+        span.appendChild(document.createTextNode(content));
+        return span;
+    },
+
+    _createLink: function(content, isExternal)
+    {
+        var quote = content.charAt(0);
+        if (content.length > 1 && (quote === "\"" ||   quote === "'"))
+            content = content.substring(1, content.length - 1);
+        else
+            quote = null;
+
+        var a = WebInspector.linkifyURLAsNode(this._rewriteHref(content), content, null, isExternal);
+        var span = document.createElement("span");
+        span.className = "webkit-html-attribute-value";
+        if (quote)
+            span.appendChild(document.createTextNode(quote));
+        span.appendChild(a);
+        if (quote)
+            span.appendChild(document.createTextNode(quote));
+        return span;
+    },
+
+    _rewriteHref: function(hrefValue, isExternal)
+    {
+        if (!this._url || !hrefValue || hrefValue.indexOf("://") > 0)
+            return hrefValue;
+        return WebInspector.completeURL(this._url, hrefValue);
+    },
+
+    _markRange: function(element, lineText, startOffset, endOffset)
+    {
+        var markNode = document.createElement("span");
+        markNode.className = "webkit-markup";
+        markNode.textContent = lineText.substring(startOffset, endOffset);
+
+        var markLength = endOffset - startOffset;
+        var boundary = element.rangeBoundaryForOffset(startOffset);
+        var textNode = boundary.container;
+        var text = textNode.textContent;
+
+        if (boundary.offset + markLength < text.length) {
+            // Selection belong to a single split mode.
+            textNode.textContent = text.substring(boundary.offset + markLength);
+            textNode.parentElement.insertBefore(markNode, textNode);
+            var prefixNode = document.createTextNode(text.substring(0, boundary.offset));
+            textNode.parentElement.insertBefore(prefixNode, markNode);
+            return;
+        }
+
+        var parentElement = textNode.parentElement;
+        var anchorElement = textNode.nextSibling;
+
+        markLength -= text.length - boundary.offset;
+        textNode.textContent = text.substring(0, boundary.offset);
+        textNode = textNode.traverseNextTextNode(element);
+
+        while (textNode) {
+            var text = textNode.textContent;
+            if (markLength < text.length) {
+                textNode.textContent = text.substring(markLength);
+                break;
+            }
+
+            markLength -= text.length;
+            textNode.textContent = "";
+            textNode = textNode.traverseNextTextNode(element);
+        }
+
+        parentElement.insertBefore(markNode, anchorElement);
+    },
+
+    resize: function()
+    {
+        this._repaintAll();
+    }
+}
+
+WebInspector.TextChunk = function(textModel, startLine, endLine, paintLinesCallback)
+{
+    this.element = document.createElement("tr");
+    this._textModel = textModel;
+    this.element.chunk = this;
+    this.element.lineNumber = startLine;
+
+    this.startLine = startLine;
+    endLine = Math.min(this._textModel.linesCount, endLine);
+    this.linesCount = endLine - startLine;
+
+    this._lineNumberElement = document.createElement("td");
+    this._lineNumberElement.className = "webkit-line-number";
+    this._lineNumberElement.textContent = this._lineNumberText(this.startLine);
+    this.element.appendChild(this._lineNumberElement);
+
+    this._lineContentElement = document.createElement("td");
+    this._lineContentElement.className = "webkit-line-content";
+    this.element.appendChild(this._lineContentElement);
+
+    this._expanded = false;
+
+    var lines = [];
+    for (var i = this.startLine; i < this.startLine + this.linesCount; ++i)
+        lines.push(this._textModel.line(i));
+    this._lineContentElement.textContent = lines.join("\n");
+    this._paintLines = paintLinesCallback;
+}
+
+WebInspector.TextChunk.prototype = {
+    addDecoration: function(decoration)
+    {
+        if (typeof decoration === "string") {
+            this.element.addStyleClass(decoration);
+            return;
+        }
+        if (!this.element.decorationsElement) {
+            this.element.decorationsElement = document.createElement("div");
+            this._lineContentElement.appendChild(this.element.decorationsElement);
+        }
+        this.element.decorationsElement.appendChild(decoration);
+    },
+
+    removeDecoration: function(decoration)
+    {
+        if (typeof decoration === "string") {
+            this.element.removeStyleClass(decoration);
+            return;
+        }
+        if (!this.element.decorationsElement)
+            return;
+        this.element.decorationsElement.removeChild(decoration);
+    },
+
+    get expanded()
+    {
+        return this._expanded;
+    },
+
+    set expanded(expanded)
+    {
+        if (this._expanded === expanded)
+            return;
+
+        this._expanded = expanded;
+
+        if (this.linesCount === 1) {
+            this._textModel.setAttribute(this.startLine, "line-row", this.element);
+            if (expanded)
+                this._paintLines(this.startLine, this.startLine + 1);
+            return;
+        }
+
+        if (expanded) {
+            var parentElement = this.element.parentElement;
+            for (var i = this.startLine; i < this.startLine + this.linesCount; ++i) {
+                var lineRow = document.createElement("tr");
+                lineRow.lineNumber = i;
+
+                var lineNumberElement = document.createElement("td");
+                lineNumberElement.className = "webkit-line-number";
+                lineNumberElement.textContent = this._lineNumberText(i);
+                lineRow.appendChild(lineNumberElement);
+
+                var lineContentElement = document.createElement("td");
+                lineContentElement.className = "webkit-line-content";
+                lineContentElement.textContent = this._textModel.line(i);
+                lineRow.appendChild(lineContentElement);
+
+                this._textModel.setAttribute(i, "line-row", lineRow);
+                parentElement.insertBefore(lineRow, this.element);
+            }
+            parentElement.removeChild(this.element);
+
+            this._paintLines(this.startLine, this.startLine + this.linesCount);
+        } else {
+            var firstLine = this._textModel.getAttribute(this.startLine, "line-row");
+            var parentElement = firstLine.parentElement;
+
+            parentElement.insertBefore(this.element, firstLine);
+            for (var i = this.startLine; i < this.startLine + this.linesCount; ++i) {
+                var lineRow = this._textModel.getAttribute(i, "line-row");
+                this._textModel.removeAttribute(i, "line-row");
+                parentElement.removeChild(lineRow);
+            }
+        }
+    },
+
+    get height()
+    {
+        if (!this._expanded)
+            return this.element.offsetHeight;
+        var result = 0;
+        for (var i = this.startLine; i < this.startLine + this.linesCount; ++i) {
+            var lineRow = this._textModel.getAttribute(i, "line-row");
+            result += lineRow.offsetHeight;
+        }
+        return result;
+    },
+
+    _lineNumberText: function(lineNumber)
+    {
+        var totalDigits = Math.ceil(Math.log(this._textModel.linesCount + 1) / Math.log(10));
+        var digits = Math.ceil(Math.log(lineNumber + 2) / Math.log(10));
+
+        var text = "";
+        for (var i = digits; i < totalDigits; ++i)
+            text += " ";
+        text += lineNumber + 1;
+        return text;
+    }
+}
diff --git a/WebCore/inspector/front-end/WebKit.qrc b/WebCore/inspector/front-end/WebKit.qrc
index 765f9b4..efa2bfc 100644
--- a/WebCore/inspector/front-end/WebKit.qrc
+++ b/WebCore/inspector/front-end/WebKit.qrc
@@ -39,7 +39,6 @@
     <file>InspectorFrontendHostStub.js</file>
     <file>KeyboardShortcut.js</file>
     <file>MetricsSidebarPane.js</file>
-    <file>NativeTextViewer.js</file>
     <file>Object.js</file>
     <file>ObjectPropertiesSection.js</file>
     <file>ObjectProxy.js</file>
@@ -75,10 +74,10 @@
     <file>StylesSidebarPane.js</file>
     <file>SummaryBar.js</file>
     <file>TestController.js</file>
-    <file>TextEditor.js</file>
     <file>TextEditorHighlighter.js</file>
     <file>TextEditorModel.js</file>
     <file>TextPrompt.js</file>
+    <file>TextViewer.js</file>
     <file>TimelineAgent.js</file>
     <file>TimelineGrid.js</file>
     <file>TimelineOverviewPane.js</file>
@@ -92,7 +91,7 @@
     <file>audits.css</file>
     <file>inspector.css</file>
     <file>inspectorSyntaxHighlight.css</file>
-    <file>textEditor.css</file>
+    <file>textViewer.css</file>
     <file>Images/back.png</file>
     <file>Images/checker.png</file>
     <file>Images/clearConsoleButtonGlyph.png</file>
diff --git a/WebCore/inspector/front-end/inspector.css b/WebCore/inspector/front-end/inspector.css
index 45b8ec3..53f1e4b 100644
--- a/WebCore/inspector/front-end/inspector.css
+++ b/WebCore/inspector/front-end/inspector.css
@@ -3772,7 +3772,7 @@ ol.breakpoint-list {
     white-space: pre;
 }
 
-.source-breakpoint-condition {
+.source-frame-breakpoint-condition {
     z-index: 30;
     padding: 4px;
     background-color: rgb(203, 226, 255);
@@ -3781,7 +3781,7 @@ ol.breakpoint-list {
     width: 90%; 
 }
 
-.source-breakpoint-message {
+.source-frame-breakpoint-message {
     background-color: transparent;
     font-family: Lucida Grande, sans-serif; 
     font-weight: normal;
@@ -3793,7 +3793,7 @@ ol.breakpoint-list {
     margin: 0 0 2px 0; 
 }
 
-#source-breakpoint-condition {
+#source-frame-breakpoint-condition {
     margin: 0;
     border: 1px inset rgb(190, 190, 190) !important;
     width: 100%;
diff --git a/WebCore/inspector/front-end/inspector.html b/WebCore/inspector/front-end/inspector.html
index 0dee8f2..4ddd10e 100644
--- a/WebCore/inspector/front-end/inspector.html
+++ b/WebCore/inspector/front-end/inspector.html
@@ -30,7 +30,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 <head>
     <meta http-equiv="content-type" content="text/html; charset=utf-8">
     <link rel="stylesheet" type="text/css" href="audits.css">
-    <link rel="stylesheet" type="text/css" href="textEditor.css">
+    <link rel="stylesheet" type="text/css" href="textViewer.css">
     <link rel="stylesheet" type="text/css" href="inspector.css">
     <link rel="stylesheet" type="text/css" href="inspectorSyntaxHighlight.css">
     <script type="text/javascript" src="utilities.js"></script>
@@ -97,9 +97,8 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     <script type="text/javascript" src="SourceFrame.js"></script>
     <script type="text/javascript" src="DOMSyntaxHighlighter.js"></script>
     <script type="text/javascript" src="TextEditorModel.js"></script>
-    <script type="text/javascript" src="TextEditor.js"></script>
     <script type="text/javascript" src="TextEditorHighlighter.js"></script>
-    <script type="text/javascript" src="NativeTextViewer.js"></script>
+    <script type="text/javascript" src="TextViewer.js"></script>
     <script type="text/javascript" src="SourceTokenizer.js"></script>
     <script type="text/javascript" src="SourceCSSTokenizer.js"></script>
     <script type="text/javascript" src="SourceHTMLTokenizer.js"></script>
diff --git a/WebCore/inspector/front-end/textEditor.css b/WebCore/inspector/front-end/textEditor.css
deleted file mode 100644
index 93495f2..0000000
--- a/WebCore/inspector/front-end/textEditor.css
+++ /dev/null
@@ -1,90 +0,0 @@
-.text-editor {
-    position: absolute;
-    top:0;
-    left:0;
-    right:0;
-    bottom:0;
-    -webkit-user-select: text;
-    -webkit-user-modify: read-write-plaintext-only;
-}
-
-.text-editor-readonly {
-    -webkit-user-modify: read-only;
-}
-
-.text-editor-canvas {
-    position: absolute;
-    top:0;
-    left:0;
-    right:0;
-    bottom:0;
-    z-index: 10;
-    pointer-events: none;
-}
-
-.text-editor-container {
-    position: absolute;
-    top:0;
-    left:0;
-    right:0;
-    bottom:0;
-    overflow: auto;
-}
-
-.text-editor-cursor {
-    -webkit-user-select: none;
-    -webkit-user-modify: none;
-    position: absolute;
-    top:0;
-    left:0;
-    width:1px;
-    height: 14px;
-    z-index: 20;
-    background-color: black;
-    pointer-events: none;
-}
-
-.native-text-editor-line {
-    white-space: pre;
-}
-
-.webkit-html-message-bubble {
-    -webkit-box-shadow: black 0px 2px 5px;
-    -webkit-border-radius: 9px;
-    -webkit-border-fit: lines;
-    font-size: 10px;
-    font-family: Lucida Grande, sans-serif;
-    font-weight: bold;
-    margin: 6px 25px;
-    padding: 0 7px 1px;
-    z-index:20;
-}
-
-.webkit-html-warning-message {
-    background-color: rgb(100%, 62%, 42%);
-    border: 2px solid rgb(100%, 52%, 21%);
-}
-
-.webkit-html-error-message {
-    background-color: rgb(100%, 42%, 42%);
-    border: 2px solid rgb(100%, 31%, 31%);
-}
-
-.webkit-html-message-line {
-    padding-left: 23px;
-    text-indent: -20px;
-}
-
-.webkit-html-message-line-hover {
-    padding-left: 23px;
-    text-indent: -20px;
-    white-space: auto;
-    text-overflow: auto;
-    overflow: auto;
-}
-
-.webkit-html-message-icon {
-    position: relative;
-    top: 2px;
-    margin: 0 4px;
-}
diff --git a/WebCore/inspector/front-end/textViewer.css b/WebCore/inspector/front-end/textViewer.css
new file mode 100644
index 0000000..563c61b
--- /dev/null
+++ b/WebCore/inspector/front-end/textViewer.css
@@ -0,0 +1,139 @@
+.text-editor {
+    position: absolute;
+    top:0;
+    left:0;
+    right:0;
+    bottom:0;
+    white-space: pre-wrap;
+    overflow: auto;
+}
+
+.text-editor-lines {
+    border: 0;
+    width: 100%;
+    vertical-align: baseline;
+    -webkit-border-horizontal-spacing: 0;
+    -webkit-border-vertical-spacing: 0;
+    -webkit-user-select: text;
+}
+
+.webkit-html-message-bubble {
+    -webkit-box-shadow: black 0px 2px 5px;
+    -webkit-border-radius: 9px;
+    -webkit-border-fit: lines;
+    font-size: 10px;
+    font-family: Lucida Grande, sans-serif;
+    font-weight: bold;
+    margin: 6px 25px;
+    padding: 0 7px 1px;
+    z-index:20;
+    max-width: 80%;
+    
+}
+
+.webkit-html-warning-message {
+    background-color: rgb(100%, 62%, 42%);
+    border: 2px solid rgb(100%, 52%, 21%);
+}
+
+.webkit-html-error-message {
+    background-color: rgb(100%, 42%, 42%);
+    border: 2px solid rgb(100%, 31%, 31%);
+}
+
+.webkit-html-message-line {
+    padding-left: 23px;
+    text-indent: -20px;
+}
+
+.webkit-html-message-line-hover {
+    padding-left: 23px;
+    text-indent: -20px;
+    white-space: auto;
+    text-overflow: auto;
+    overflow: auto;
+}
+
+.webkit-html-message-icon {
+    position: relative;
+    top: 2px;
+    margin: 0 4px;
+}
+
+.webkit-line-number {
+    color: rgb(128, 128, 128);
+    text-align: right;
+    white-space: pre;
+    word-break: normal;
+    -webkit-user-select: none;
+    background-color: rgb(240, 240, 240);
+    border-right: 1px solid rgb(187, 187, 187) !important;
+    padding-left: 2px;
+    padding-right: 2px;
+    vertical-align: top;
+    background-repeat: no-repeat;
+    background-position: right 1px;
+}
+
+.webkit-line-content {
+    white-space: pre-wrap;
+    padding-left: 2px;
+}
+
+.webkit-execution-line .webkit-line-number {
+    color: transparent;
+    background-image: -webkit-canvas(program-counter);
+}
+
+.webkit-breakpoint .webkit-line-number {
+    color: white;
+    background-image: -webkit-canvas(breakpoint);
+}
+
+.webkit-breakpoint-disabled .webkit-line-number {
+    color: white;
+    background-image: -webkit-canvas(breakpoint-disabled);
+}
+
+.webkit-breakpoint.webkit-execution-line .webkit-line-number {
+    color: transparent;
+    background-image: -webkit-canvas(breakpoint-program-counter);
+}
+
+.webkit-breakpoint-disabled.webkit-execution-line .webkit-line-number {
+    color: transparent;
+    background-image: -webkit-canvas(breakpoint-disabled-program-counter);
+}
+
+.webkit-breakpoint.webkit-breakpoint-conditional .webkit-line-number {
+    color: white;
+    background-image: -webkit-canvas(breakpoint-conditional);
+}
+
+.webkit-breakpoint-disabled.webkit-breakpoint-conditional .webkit-line-number {
+    color: white;
+    background-image: -webkit-canvas(breakpoint-disabled-conditional);
+}
+
+.webkit-breakpoint.webkit-breakpoint-conditional.webkit-execution-line .webkit-line-number {
+    color: transparent;
+    background-image: -webkit-canvas(breakpoint-conditional-program-counter);
+}
+
+.webkit-breakpoint-disabled.webkit-breakpoint-conditional.webkit-execution-line .webkit-line-number {
+    color: transparent;
+    background-image: -webkit-canvas(breakpoint-disabled-conditional-program-counter);
+}
+
+.webkit-execution-line .webkit-line-content {
+    background-color: rgb(171, 191, 254);
+    outline: 1px solid rgb(64, 115, 244);
+}
+
+.webkit-markup {
+    background-color: rgb(241, 234, 0);
+}
+
+.webkit-highlighted-line .webkit-line-content {
+    background-color: rgb(255, 255, 120);
+}
diff --git a/WebCore/inspector/front-end/utilities.js b/WebCore/inspector/front-end/utilities.js
index d54005a..60d3b45 100644
--- a/WebCore/inspector/front-end/utilities.js
+++ b/WebCore/inspector/front-end/utilities.js
@@ -145,6 +145,30 @@ Node.prototype.rangeOfWord = function(offset, stopCharacters, stayWithinNode, di
     return result;
 }
 
+Node.prototype.traverseNextTextNode = function(stayWithin)
+{
+    var node = this.traverseNextNode(stayWithin);
+    if (!node)
+        return;
+
+    while (node && node.nodeType !== Node.TEXT_NODE)
+        node = node.traverseNextNode(stayWithin);
+
+    return node;
+}
+
+Node.prototype.rangeBoundaryForOffset = function(offset)
+{
+    var node = this.traverseNextTextNode(this);
+    while (node && offset > node.nodeValue.length) {
+        offset -= node.nodeValue.length;
+        node = node.traverseNextTextNode(this);
+    }
+    if (!node)
+        return { container: this, offset: 0 };
+    return { container: node, offset: offset };
+}
+
 Element.prototype.removeStyleClass = function(className) 
 {
     // Test for the simple case first.

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list