[SCM] WebKit Debian packaging branch, webkit-1.2, updated. upstream/1.1.90-6072-g9a69373

pfeldman at chromium.org pfeldman at chromium.org
Thu Apr 8 00:57:43 UTC 2010


The following commit has been merged in the webkit-1.2 branch:
commit 8061c7084c7270f03d9b5f11c83f1c71b8a4b676
Author: pfeldman at chromium.org <pfeldman at chromium.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Date:   Thu Jan 7 21:36:58 2010 +0000

    2009-01-07  Pavel Feldman  <pfeldman at chromium.org>
    
            Reviewed by Timothy Hatcher.
    
            Web Inspector: Migrate to canvas-based text viewer / editor that scales.
    
            https://bugs.webkit.org/show_bug.cgi?id=33001
    
            * WebCore.gypi:
            * WebCore.vcproj/WebCore.vcproj:
            * inspector/front-end/JavaScriptHighlighterScheme.js: Added.
            (WebInspector.JavaScriptHighlighterScheme):
            * inspector/front-end/KeyboardShortcut.js:
            * inspector/front-end/TextEditor.js: Added.
            (WebInspector.TextEditor):
            (WebInspector.TextSelectionModel):
            (WebInspector.TextCursor):
            * inspector/front-end/TextEditorHighlighter.js: Added.
            (WebInspector.TextEditorHighlighter):
            (WebInspector.TextEditorHighlighter.prototype.highlight):
            (WebInspector.TextEditorHighlighter.prototype._lex):
            * inspector/front-end/TextEditorModel.js: Added.
            (WebInspector.TextRange):
            (WebInspector.TextRange.prototype.clone):
            (WebInspector.TextEditorModel):
            * inspector/front-end/WebKit.qrc:
            * inspector/front-end/inspector.css:
            * inspector/front-end/inspector.html:
    
    
    git-svn-id: http://svn.webkit.org/repository/webkit/trunk@52945 268f45cc-cd09-0410-ab3c-d52691b4dbfc

diff --git a/WebCore/ChangeLog b/WebCore/ChangeLog
index bd891bd..263f570 100644
--- a/WebCore/ChangeLog
+++ b/WebCore/ChangeLog
@@ -1,3 +1,32 @@
+2009-01-07  Pavel Feldman  <pfeldman at chromium.org>
+
+        Reviewed by Timothy Hatcher.
+
+        Web Inspector: Migrate to canvas-based text viewer / editor that scales.
+
+        https://bugs.webkit.org/show_bug.cgi?id=33001
+
+        * WebCore.gypi:
+        * WebCore.vcproj/WebCore.vcproj:
+        * inspector/front-end/JavaScriptHighlighterScheme.js: Added.
+        (WebInspector.JavaScriptHighlighterScheme):
+        * inspector/front-end/KeyboardShortcut.js:
+        * inspector/front-end/TextEditor.js: Added.
+        (WebInspector.TextEditor):
+        (WebInspector.TextSelectionModel):
+        (WebInspector.TextCursor):
+        * inspector/front-end/TextEditorHighlighter.js: Added.
+        (WebInspector.TextEditorHighlighter):
+        (WebInspector.TextEditorHighlighter.prototype.highlight):
+        (WebInspector.TextEditorHighlighter.prototype._lex):
+        * inspector/front-end/TextEditorModel.js: Added.
+        (WebInspector.TextRange):
+        (WebInspector.TextRange.prototype.clone):
+        (WebInspector.TextEditorModel):
+        * inspector/front-end/WebKit.qrc:
+        * inspector/front-end/inspector.css:
+        * inspector/front-end/inspector.html:
+
 2010-01-07  Christian Sejersen  <christian.webkit at gmail.com>
 
         Reviewed by Darin Adler.
diff --git a/WebCore/WebCore.gypi b/WebCore/WebCore.gypi
index ec1092e..34323fa 100644
--- a/WebCore/WebCore.gypi
+++ b/WebCore/WebCore.gypi
@@ -3693,6 +3693,7 @@
             'inspector/front-end/InjectedScript.js',
             'inspector/front-end/InjectedScriptAccess.js',
             'inspector/front-end/inspector.js',
+            'inspector/front-end/JavaScriptHighlighterScheme.js',
             'inspector/front-end/JavaScriptSourceSyntaxHighlighter.js',
             'inspector/front-end/KeyboardShortcut.js',
             'inspector/front-end/MetricsSidebarPane.js',
@@ -3728,6 +3729,9 @@
             '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/TimelineAgent.js',
             'inspector/front-end/TimelineOverviewPane.js',
diff --git a/WebCore/WebCore.vcproj/WebCore.vcproj b/WebCore/WebCore.vcproj/WebCore.vcproj
index 9e30a53..da42a80 100644
--- a/WebCore/WebCore.vcproj/WebCore.vcproj
+++ b/WebCore/WebCore.vcproj/WebCore.vcproj
@@ -42856,6 +42856,10 @@
 					>
 				</File>
 				<File
+					RelativePath="..\inspector\front-end\JavaScriptHighlighterScheme.js"
+					>
+				</File>
+				<File
 					RelativePath="..\inspector\front-end\JavaScriptSourceSyntaxHighlighter.js"
 					>
 				</File>
@@ -42992,6 +42996,18 @@
 					>
 				</File>
 				<File
+					RelativePath="..\inspector\front-end\TextEditor.js"
+					>
+				</File>
+				<File
+					RelativePath="..\inspector\front-end\TextEditorHighlighter.js"
+					>
+				</File>
+				<File
+					RelativePath="..\inspector\front-end\TextEditorModel.js"
+					>
+				</File>
+				<File
 					RelativePath="..\inspector\front-end\TextPrompt.js"
 					>
 				</File>
diff --git a/WebCore/inspector/front-end/JavaScriptHighlighterScheme.js b/WebCore/inspector/front-end/JavaScriptHighlighterScheme.js
new file mode 100644
index 0000000..03bf049
--- /dev/null
+++ b/WebCore/inspector/front-end/JavaScriptHighlighterScheme.js
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All Rights Reserved.
+ * 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:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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.JavaScriptHighlighterScheme = function() {
+    this.LexState = {
+        Initial: 1,
+        DivisionAllowed: 2
+    };
+    this.ContinueState = {
+        None: 0,
+        Comment: 1,
+        SingleQuoteString: 2,
+        DoubleQuoteString: 3,
+        RegExp: 4
+    };
+
+    var keywords = [
+        "null", "true", "false", "break", "case", "catch", "const", "default", "finally", "for",
+        "instanceof", "new", "var", "continue", "function", "return", "void", "delete", "if",
+        "this", "do", "while", "else", "in", "switch", "throw", "try", "typeof", "debugger",
+        "class", "enum", "export", "extends", "import", "super", "get", "set"
+    ].keySet();
+
+    var tokenTypes = WebInspector.TextEditorHighlighter.TokenType;
+
+    this.rules = [{
+        name: "singleLineCommentAction",
+        pattern: /^(?:\/\/.*)/,
+        type: tokenTypes.Comment
+    }, {
+        name: "multiLineSingleLineCommentAction",
+        pattern: /^(?:\/\*(?:[^\*]|\*[^\/])*\*+\/)/,
+        type: tokenTypes.Comment
+    }, {
+        name: "multiLineCommentStartAction",
+        pattern: /^(?:\/\*(?:[^\*]|\*[^\/])*)/,
+        type: tokenTypes.Comment,
+        postContinueState: this.ContinueState.Comment
+    }, {
+        name: "multiLineCommentEndAction",
+        pattern: /^(?:(?:[^\*]|\*[^\/])*\*+\/)/,
+        type: tokenTypes.Comment,
+        preContinueState: this.ContinueState.Comment,
+        postContinueState: this.ContinueState.None
+    }, {
+        name: "multiLineCommentMiddleAction",
+        pattern: /^.*/,
+        type: tokenTypes.Comment,
+        preContinueState: this.ContinueState.Comment
+    }, {
+        name: "numericLiteralAction",
+        pattern: /^(?:(?:0|[1-9]\d*)\.\d+?(?:[eE](?:\d+|\+\d+|-\d+))?|\.\d+(?:[eE](?:\d+|\+\d+|-\d+))?|(?:0|[1-9]\d*)(?:[eE](?:\d+|\+\d+|-\d+))?|0x[0-9a-fA-F]+|0X[0-9a-fA-F]+)\s*/,
+        type: tokenTypes.Number,
+        postLexState: this.LexState.DivisionAllowed
+    }, {
+        name: "stringLiteralAction",
+        pattern: /^(?:"(?:[^"\\]|\\(?:['"\bfnrtv]|[^'"\bfnrtv0-9xu]|0|x[0-9a-fA-F][0-9a-fA-F]|(?:u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])))*"|'(?:[^'\\]|\\(?:['"\bfnrtv]|[^'"\bfnrtv0-9xu]|0|x[0-9a-fA-F][0-9a-fA-F]|(?:u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])))*')/,
+        type: tokenTypes.String,
+        postLexState: this.LexState.Initial
+    }, {
+        name: "singleQuoteStringStartAction",
+        pattern: /^(?:'(?:[^'\\]|\\(?:['"\bfnrtv]|[^'"\bfnrtv0-9xu]|0|x[0-9a-fA-F][0-9a-fA-F]|(?:u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])))*)\\$/,
+        type: tokenTypes.String,
+        postContinueState:  this.ContinueState.SingleQuoteString
+    }, {
+        name: "singleQuoteStringEndAction",
+        pattern: /^(?:(?:[^'\\]|\\(?:['"\bfnrtv]|[^'"\bfnrtv0-9xu]|0|x[0-9a-fA-F][0-9a-fA-F]|(?:u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])))*')/,
+        type: tokenTypes.String,
+        preContinueState: this.ContinueState.SingleQuoteString,
+        postContinueState: this.ContinueState.None
+    }, {
+        name: "singleQuoteStringMiddleAction",
+        pattern: /^(?:(?:[^'\\]|\\(?:['"\bfnrtv]|[^'"\bfnrtv0-9xu]|0|x[0-9a-fA-F][0-9a-fA-F]|(?:u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])))*)\\$/,
+        type: tokenTypes.String,
+        preContinueState: this.ContinueState.SingleQuoteString
+    }, {
+        name: "doubleQuoteStringStartAction",
+        pattern: /^(?:"(?:[^"\\]|\\(?:['"\bfnrtv]|[^'"\bfnrtv0-9xu]|0|x[0-9a-fA-F][0-9a-fA-F]|(?:u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])))*)\\$/,
+        type: tokenTypes.String,
+        postContinueState: this.ContinueState.DoubleQuoteString
+    }, {
+        name: "doubleQuoteStringEndAction",
+        pattern: /^(?:(?:[^"\\]|\\(?:['"\bfnrtv]|[^'"\bfnrtv0-9xu]|0|x[0-9a-fA-F][0-9a-fA-F]|(?:u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])))*")/,
+        type: tokenTypes.String,
+        preContinueState: this.ContinueState.DoubleQuoteString,
+        postContinueState: this.ContinueState.None
+    }, {
+        name: "doubleQuoteStringMiddleAction",
+        pattern: /^(?:(?:[^"\\]|\\(?:['"\bfnrtv]|[^'"\bfnrtv0-9xu]|0|x[0-9a-fA-F][0-9a-fA-F]|(?:u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F])))*)\\$/,
+        type: tokenTypes.String,
+        preContinueState: this.ContinueState.DoubleQuoteString
+    }, {
+        name: "keywordAction",
+        pattern: /^(?:(?:[a-zA-Z]|[$_]|\\(?:u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]))(?:(?:[a-zA-Z]|[$_]|\\(?:u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]))|[0-9])*)/,
+        keywords: keywords,
+        type: tokenTypes.Keyword,
+        postLexState: this.LexState.Initial
+    }, {
+        name: "identAction",
+        pattern: /^(?:(?:[a-zA-Z]|[$_]|\\(?:u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]))(?:(?:[a-zA-Z]|[$_]|\\(?:u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]))|[0-9])*)\s*/,
+        postLexState: this.LexState.DivisionAllowed
+    }, {
+        name: "rightParenAction",
+        pattern: /^\)\s*/,
+        postLexState: this.LexState.DivisionAllowed
+    }, {
+        name: "punctuatorAction",
+        pattern: /^(?:<=|>=|===|==|!=|!==|\+\+|\-\-|<<|>>|>>>|&&|\|\||\+=|\-=|\*=|%=|<<=|>>=|>>>=|&=|\|=|^=|[\s{}\(\[\]\.;,<>\+\-\*%&\|\^!~\?:=])/,
+        postLexState: this.LexState.Initial
+    }, {
+        name: "divPunctuatorAction",
+        pattern: /^(?:\/=?)/,
+        preLexState: this.LexState.DivisionAllowed,
+        postLexState: this.LexState.Initial
+    }, {
+        name: "regExpLiteralAction",
+        pattern: /^(?:\/(?:(?:\\.)|[^\\*\/])(?:(?:\\.)|[^\\\/])*\/(?:(?:[a-zA-Z]|[$_]|\\(?:u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]))|[0-9])*)/,
+        type: tokenTypes.String,
+        postLexState: this.LexState.Initial
+    }, {
+        name: "regExpStartAction",
+        pattern: /^(?:\/(?:(?:\\.)|[^\\*\/])(?:(?:\\.)|[^\\\/])*)\\$/,
+        type: tokenTypes.String,
+        postContinueState: this.ContinueState.RegExp
+    }, {
+        name: "regExpEndAction",
+        pattern: /^(?:(?:(?:\\.)|[^\\\/])*\/(?:(?:[a-zA-Z]|[$_]|\\(?:u[0-9a-fA-F][0-9a-fA-F][0-9a-fA-F][0-9a-fA-F]))|[0-9])*)/,
+        type: tokenTypes.String,
+        preContinueState: this.ContinueState.RegExp,
+        postContinueState: this.ContinueState.None
+    }, {
+        name: "regExpMiddleAction",
+        pattern: /^(?:(?:(?:\\.)|[^\\\/])*)\\$/,
+        type: tokenTypes.String,
+        preContinueState: this.ContinueState.RegExp
+    }, {
+        name: "whitespace",
+        pattern: /^\s+$/
+    }];
+}
+
+WebInspector.JavaScriptHighlighterScheme.prototype = {
+    reset: function(highlighter)
+    {
+        highlighter.lexState = this.LexState.Initial;
+        highlighter.continueState = this.ContinueState.None;
+    }
+}
diff --git a/WebCore/inspector/front-end/KeyboardShortcut.js b/WebCore/inspector/front-end/KeyboardShortcut.js
index 0a068d5..b4dda8b 100644
--- a/WebCore/inspector/front-end/KeyboardShortcut.js
+++ b/WebCore/inspector/front-end/KeyboardShortcut.js
@@ -45,6 +45,7 @@ WebInspector.KeyboardShortcut.Modifiers = {
 
 WebInspector.KeyboardShortcut.KeyCodes = {
     Backspace: 8,
+    Tab: 9,
     Esc: 27,
     Space: 32,
     PageUp: 33,      // also NUM_NORTH_EAST
@@ -56,6 +57,7 @@ WebInspector.KeyboardShortcut.KeyCodes = {
     Right: 39,       // also NUM_EAST
     Down: 40,        // also NUM_SOUTH
     Delete: 46,
+    Zero: 48,
     F1: 112,
     F2: 113,
     F3: 114,
@@ -69,11 +71,13 @@ WebInspector.KeyboardShortcut.KeyCodes = {
     F11: 122,
     F12: 123,
     Semicolon: 186,    // ;
+    Plus: 187,         // +
     Comma: 188,        // ,
+    Minus: 189,        // -
     Period: 190,       // .
     Slash: 191,        // /
     Apostrophe: 192,   // `
-    SingleQuote: 222,  // '
+    SingleQuote: 222   // '
 };
 
 /**
diff --git a/WebCore/inspector/front-end/TextEditor.js b/WebCore/inspector/front-end/TextEditor.js
new file mode 100644
index 0000000..93b53d0
--- /dev/null
+++ b/WebCore/inspector/front-end/TextEditor.js
@@ -0,0 +1,910 @@
+/*
+ * 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(platform)
+{
+    this._textModel = new WebInspector.TextEditorModel(this._textChanged.bind(this));
+    this._highlighter = new WebInspector.TextEditorHighlighter(this._textModel);
+
+    this.element = document.createElement("div");
+    this.element.className = "text-editor";
+    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._sheet.className = "text-editor-sheet";
+    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));
+    this._sheet.addEventListener("mouseup", this._mouseUp.bind(this));
+    this._sheet.addEventListener("mousedown", this._mouseDown.bind(this));
+    this._sheet.addEventListener("mousemove", this._mouseMove.bind(this));
+    this._sheet.addEventListener("mouseout", this._mouseOut.bind(this));
+    this._sheet.addEventListener("dblclick", this._dblClick.bind(this));
+    this.element.addEventListener("keydown", this._keyDown.bind(this));
+    this.element.addEventListener("textInput", this._textInput.bind(this));
+    this.element.addEventListener("beforecopy", this._beforeCopy.bind(this));
+    this.element.addEventListener("copy", this._copy.bind(this));
+    this.element.addEventListener("beforecut", this._beforeCut.bind(this));
+    this.element.addEventListener("cut", this._cut.bind(this));
+    this.element.addEventListener("beforepaste", this._beforePaste.bind(this));
+    this.element.addEventListener("paste", this._paste.bind(this));
+
+    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._isMacTiger = platform === "mac-tiger";
+    this._isMacLeopard = platform === "mac-leopard";
+    this._isMac = this._isMacTiger || this._isMacLeopard;
+    this._isWin = platform === "windows";
+
+    this._initFont();
+
+    this._paintCoalescingLevel = 0;
+
+    this._registerShortcuts();
+    // Debugging flags, allow disabling / enabling highlights and track repaints.
+    this._highlightingEnabled = true;
+    this._debugMode = false;
+    this._lineAlignmentOffset = 0;
+
+    this._textWidth = 0;
+    this._longestLineNumber = 0;
+}
+
+WebInspector.TextEditor.prototype = {
+    set text(text)
+    {
+        var lastLine = this._textModel.linesCount - 1;
+        this._textModel.setText(null, text);
+        this._textModel.resetUndoStack();
+        this._setCaretLocation(0, 0);
+    },
+
+    setSelection: function(startLine, startColumn, endLine, endColumn)
+    {
+        var start = this._fit(startLine, startColumn);
+        this._selection.setStart(start.line, start.column);
+        this._setSelectionEnd(endLine, endColumn);
+    },
+
+    reveal: function(line, column) {
+        var firstLine = this._scrollTop / this._lineHeight;
+        var visibleLines = this._canvas.height / this._lineHeight;
+        var minTop = (line - visibleLines + 1) * this._lineHeight;
+        var maxTop = line * this._lineHeight;
+        if (this._scrollTop < minTop) {
+            this._lineAlignmentOffset = this._canvas.height % this._lineHeight;
+            this._container.scrollTop = minTop;
+        } else if (this._scrollTop > maxTop) {
+            this._lineAlignmentOffset = 0;
+            this._container.scrollTop = maxTop;
+        }
+
+        var firstColumn = this._columnForOffset(line, this._scrollLeft);
+        var maxLeft = this._columnToOffset(line, column);
+        var minLeft = maxLeft - this._container.clientWidth + this._lineNumberOffset;
+        if (this._scrollLeft < minLeft)
+            this._container.scrollLeft = minLeft + 100;
+        if (this._scrollLeft > maxLeft)
+            this._container.scrollLeft = maxLeft;
+    },
+
+    // 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));
+
+        this._invalidateHighlight(newRange.startLine);
+        this._updateSize(newRange.startLine, Math.max(newRange.endLine, oldRange.endLine));
+        this._paint();
+    },
+
+    // WebInspector.TextSelectionModel listener
+    _selectionChanged: function(oldRange, newRange)
+    {
+        this._invalidateLines(oldRange.startLine, oldRange.endLine + 1);
+        this._invalidateLines(newRange.startLine, newRange.endLine + 1);
+        this._paint();
+    },
+
+    _updateSize: function(startLine, endLine)
+    {
+        var newLineNumberDigits = this._decimalDigits(this._textModel.linesCount);
+        this._lineNumberOffset = (newLineNumberDigits + 2) * this._digitWidth;
+
+        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;
+                }
+            }
+        }
+
+        this._sheet.style.width = this._textWidth + this._lineNumberOffset + "px";
+        this._sheet.style.height = this._lineHeight * this._textModel.linesCount + "px";
+
+        if (this._canvas.width !== this._container.clientWidth || this._canvas.height !== this._container.clientHeight || newLineNumberDigits !== this._lineNumberDigits) {
+            this._canvas.width = this._container.clientWidth;
+            this._canvas.height = this._container.clientHeight;
+            this._lineNumberDigits = newLineNumberDigits;
+            this._repaintAll();
+        }
+    },
+
+    _repaintAll: function()
+    {
+        this._invalidateLines(0, this._textModel.linesCount);
+        this._paint();
+        this._updateCursor(this._selection.endLine, this._selection.endColumn);
+    },
+
+    _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()
+    {
+        if (this._paintCoalescingLevel)
+            return;
+
+        for (var i = 0; this._damage && i < this._damage.length; ++i)
+            this._paintLines(this._damage[i].startLine, this._damage[i].endLine);
+        delete this._damage;
+    },
+
+    _paintLines: function(firstLine, lastLine)
+    {
+        this._ctx.font = this._font;
+        this._ctx.textBaseline = "bottom";
+
+        firstLine = Math.max(firstLine, Math.floor(this._scrollTop / this._lineHeight) - 1);
+        lastLine = Math.min(lastLine, Math.ceil((this._scrollTop + this._canvas.height) / this._lineHeight) + 1);
+        if (firstLine > lastLine)
+            return;
+
+        if (this._debugMode) {
+            WebInspector.log("Repaint %d:%d", firstLine, lastLine);
+            this._ctx.fillStyle = "rgb(255,255,0)";
+            var height = (lastLine - firstLine) * this._lineHeight;
+            this._ctx.fillRect(0, this._lineHeight * firstLine - this._scrollTop, this._canvas.width, height);
+            setTimeout(this._paintLinesContinuation.bind(this, firstLine, lastLine), 100);
+        } else
+            this._paintLinesContinuation(firstLine, lastLine);
+    },
+
+    _paintLinesContinuation: function(firstLine, lastLine) {
+        // Clear all.
+        var height = (lastLine - firstLine) * this._lineHeight;
+        this._ctx.fillStyle = "rgb(255,255,255)";
+        this._ctx.fillRect(0, this._lineHeight * firstLine - this._scrollTop, this._canvas.width, height);
+
+        lastLine = Math.min(lastLine, this._textModel.linesCount);
+
+        // Paint line numbers and separator.
+        this._ctx.fillStyle = "rgb(235,235,235)";
+        this._ctx.fillRect(this._lineNumberOffset - 2, 0, 1, this._canvas.width);
+        this._ctx.fillStyle = "rgb(155,155,155)";
+        for (var i = firstLine; i < lastLine; ++i)
+           this._ctx.fillText(i + 1, (this._lineNumberDigits - this._decimalDigits(i + 1) + 1) * this._digitWidth, this._lineHeight * (i + 1) - this._scrollTop);
+
+        // Clip editor area.
+        this._ctx.save();
+        this._ctx.beginPath();
+        this._ctx.rect(this._lineNumberOffset - 1, 0, this._canvas.width - this._lineNumberOffset + 1, this._canvas.height);
+        this._ctx.clip();
+
+        if (this._selection.startLine === this._selection.endLine && firstLine <= this._selection.startLine && this._selection.startLine < lastLine)
+            this._paintCurrentLine(this._selection.startLine);
+
+        if (this._highlightingEnabled)
+            this._highlighter.highlight(firstLine, lastLine);
+
+        this._paintSelection(firstLine, lastLine);
+
+        for (var i = firstLine; i < lastLine; ++i) {
+            var line = this._textModel.line(i);
+            if (!this._highlightingEnabled) {
+                this._ctx.fillText(line, this._lineNumberOffset - this._scrollLeft, this._lineHeight * (i + 1) - this._scrollTop);
+                continue;
+            }
+
+            var attributes = this._textModel.getAttributes(i, "highlight");
+            var plainTextStart = -1;
+            for (var j = 0; j < line.length;) {
+                var attribute = attributes && attributes[j];
+                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._lineNumberOffset - this._scrollLeft + this._columnToOffset(i, plainTextStart), this._lineHeight * (i + 1) - this._scrollTop);
+                        plainTextStart = -1;
+                    }
+                    this._ctx.fillStyle = attribute.style;
+                    this._ctx.fillText(line.substring(j, j + attribute.length), this._lineNumberOffset - this._scrollLeft + this._columnToOffset(i, j), this._lineHeight * (i + 1) - this._scrollTop);
+                    j += attribute.length;
+                }
+            }
+            if (plainTextStart !== -1) {
+                this._ctx.fillStyle = "rgb(0,0,0)";
+                this._ctx.fillText(line.substring(plainTextStart, line.length), this._lineNumberOffset - this._scrollLeft + this._columnToOffset(i, plainTextStart), this._lineHeight * (i + 1) - this._scrollTop);
+            }
+        }
+        this._ctx.restore();
+    },
+
+    _paintCurrentLine: function(line)
+    {
+        this._ctx.fillStyle = "rgb(232, 242, 254)";
+        this._ctx.fillRect(0, this._lineHeight * line - this._scrollTop, this._canvas.width, this._lineHeight);
+        this._ctx.fillStyle = "rgb(0, 0, 0)";
+    },
+
+    _scroll: function(e)
+    {
+        if (this._muteScroll)
+            return;
+
+        if (this._container.scrollTop === 0)
+            this._lineAlignmentOffset = 0;
+        else if (this._container.scrollTop + this._container.clientHeight === this._textModel.linesCount * this._lineHeight)
+            this._lineAlignmentOffset = this._container.scrollTop % this._lineHeight;
+
+        // Enforce line alignment.
+        if (this._container.scrollTop % this._lineHeight !== this._lineAlignmentOffset) {
+            var linesOffset = Math.floor(this._container.scrollTop / this._lineHeight);
+            this._muteScroll = true;
+            this._container.scrollTop = linesOffset * this._lineHeight + this._lineAlignmentOffset;
+            delete this._muteScroll;
+        }
+
+        // Hide div-based cursor first.
+        this._cursor._cursorElement.style.display = "none";
+        setTimeout(this._repaintOnScroll.bind(this), 0);
+    },
+
+    _repaintOnScroll: function()
+    {
+        var linesOffset = Math.floor(this._container.scrollTop / this._lineHeight);
+        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)
+    {
+        var location = this._caretForMouseEvent(e);
+        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)
+    {
+        this._isDragging = false;
+    },
+
+    _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);
+    },
+
+    _caretForMouseEvent: function(e)
+    {
+        var lineNumber = Math.floor((e.y + this._scrollTop - 4) / this._lineHeight);
+        var line = this._textModel.line(lineNumber);
+        var offset = e.x + this._scrollLeft - this._lineNumberOffset - this._digitWidth;
+        return { line: lineNumber, column: this._columnForOffset(lineNumber, offset) };
+    },
+
+    _columnForOffset: function(lineNumber, offset)
+    {
+        var line = this._textModel.line(lineNumber);
+        for (var column = 0; column < line.length; ++column) {
+            if (this._ctx.measureText(line.substring(0, column)).width > offset)
+                break;
+        }
+        return column;
+    },
+
+    _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;
+        }
+
+        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;
+                else {
+                    var jump = e.keyCode === keyCodes.Up ? 1 : Math.floor(this._canvas.height / this._lineHeight);
+                    arrowAction.call(this, caretLine - jump, 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;
+                else {
+                    var jump = e.keyCode === keyCodes.Down ? 1 : Math.floor(this._canvas.height / this._lineHeight);
+                    arrowAction.call(this, caretLine + jump, this._desiredCaretColumn, true);
+                }
+                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 (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);
+    },
+
+    _updateCursor: function(line, column)
+    {
+        if (line > this._textModel.linesCount)
+            return;
+        var offset = this._columnToOffset(line, column);
+        if (offset >= this._container.scrollLeft)
+            this._cursor.setLocation(this._lineNumberOffset + offset - 1, line * this._lineHeight);
+        else
+            this._cursor.setLocation(0, 0);
+    },
+
+    _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 };
+    },
+
+    _invalidateHighlight: function(startLine)
+    {
+        if (!this._highlightingEnabled)
+            return;
+        var firstVisibleLine = Math.max(0, Math.floor(this._scrollTop / this._lineHeight) - 1);
+        var lastVisibleLine = Math.min(this._textModel.linesCount, Math.ceil(firstVisibleLine + this._canvas.height / this._lineHeight + 1));
+
+        var damage = this._highlighter.highlight(startLine, lastVisibleLine);
+        for (var line in damage)
+            this._invalidateLines(line, parseInt(line) + 1);
+    },
+
+    _paintSelection: function(firstLine, lastLine)
+    {
+        if (this._selection.isEmpty())
+            return;
+        var range = this._selection.range();
+        this._ctx.fillStyle = "rgb(181, 213, 255)";
+
+        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._lineNumberOffset - 1;
+            } else
+                from = 0;
+
+            if (i === range.endLine) {
+                var offset = this._columnToOffset(range.endLine, range.endColumn);
+                to = offset - this._scrollLeft + this._lineNumberOffset - 1;
+            } else
+                to = this._canvas.width;
+
+            this._ctx.fillRect(from, this._lineHeight * i - this._scrollTop, to - from, this._lineHeight);
+        }
+        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);
+
+        e.preventDefault();
+        e.clipboardData.clearData();
+        e.clipboardData.setData("text/plain", text);
+    },
+
+    _beforeCut: function(e)
+    {
+        if (!this._selection.isEmpty())
+            e.preventDefault();
+    },
+
+    _cut: function(e)
+    {
+        this._textModel.markUndoableState();
+        this._copy(e);
+        this._replaceSelectionWith("");
+    },
+
+    _beforePaste: function(e)
+    {
+        e.preventDefault();
+    },
+
+    _paste: function(e)
+    {
+        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);
+    },
+
+    _initFont: function(sansSerif, fontSize)
+    {
+        if (sansSerif) {
+            this._isMonospace = false;
+            this._fontSize = fontSize || 11;
+            this._font = this._fontSize + "px sans-serif";
+        } else {
+            this._isMonospace = true;
+            this._fontSize = fontSize || 10;
+            this._font = this._fontSize + "px monospace";
+            if (this._isMac)
+                this._font = this._fontSize + "px Monaco";
+            else if (this._isWin)
+                this._font = (this._fontSize + 1) + "px Courier New";
+        }
+        this._ctx.font = this._font;
+        this._digitWidth = this._ctx.measureText("0").width;
+
+        this._lineHeight = Math.floor(this._fontSize * 1.4);
+        this._cursor.setLineHeight(this._lineHeight);
+    },
+
+    _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);
+        this._shortcuts[WebInspector.KeyboardShortcut.makeKey(WebInspector.KeyboardShortcut.KeyCodes.Plus, this._isMac ? modifiers.Meta : modifiers.Ctrl)] = this._handleZoomIn.bind(this);
+        this._shortcuts[WebInspector.KeyboardShortcut.makeKey(WebInspector.KeyboardShortcut.KeyCodes.Minus, this._isMac ? modifiers.Meta : modifiers.Ctrl)] = this._handleZoomOut.bind(this);
+        this._shortcuts[WebInspector.KeyboardShortcut.makeKey(WebInspector.KeyboardShortcut.KeyCodes.Zero, this._isMac ? modifiers.Meta : modifiers.Ctrl)] = this._handleZoomReset.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);
+        this._shortcuts[WebInspector.KeyboardShortcut.makeKey("m", modifiers.Ctrl | modifiers.Alt)] = this._handleToggleMonospaceMode.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;
+    },
+
+    _handleZoomIn: function()
+    {
+        if (this._fontSize < 25)
+            this._changeFont(!this._isMonospace, this._fontSize + 1);
+    },
+
+    _handleZoomOut: function()
+    {
+        if (this._fontSize > 1)
+            this._changeFont(!this._isMonospace, this._fontSize - 1);
+    },
+
+    _handleZoomReset: function()
+    {
+        this._changeFont(!this._isMonospace);
+    },
+
+    _handleToggleMonospaceMode: function()
+    {
+        this._changeFont(this._isMonospace, this._fontSize);
+    },
+
+    _changeFont: function(sansSerif, fontSize) {
+        this._initFont(sansSerif, fontSize);
+        this._updateSize(0, this._textModel.linesCount);
+        this._repaintAll();
+    },
+
+    _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);
+    },
+
+    setLineHeight: function(lineHeight)
+    {
+        this._cursorElement.style.height = lineHeight + "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/TextEditorHighlighter.js b/WebCore/inspector/front-end/TextEditorHighlighter.js
new file mode 100644
index 0000000..e1d2bd6
--- /dev/null
+++ b/WebCore/inspector/front-end/TextEditorHighlighter.js
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ * Copyright (C) 2009 Apple 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.TextEditorHighlighter = function(textModel)
+{
+    this._textModel = textModel;
+    this._highlighterScheme = new WebInspector.JavaScriptHighlighterScheme();
+
+    this._styles = [];
+    this._styles[WebInspector.TextEditorHighlighter.TokenType.Comment] = "rgb(0, 116, 0)";
+    this._styles[WebInspector.TextEditorHighlighter.TokenType.String] = "rgb(196, 26, 22)";
+    this._styles[WebInspector.TextEditorHighlighter.TokenType.Keyword] = "rgb(170, 13, 145)";
+    this._styles[WebInspector.TextEditorHighlighter.TokenType.Number] = "rgb(28, 0, 207)";
+}
+
+WebInspector.TextEditorHighlighter.TokenType = {
+    Comment: 0,
+    String: 1,
+    Keyword: 2,
+    Number: 3
+}
+
+WebInspector.TextEditorHighlighter.prototype = {
+    highlight: function(startLine, endLine)
+    {
+        this._highlighterScheme.reset(this);
+        // Rewind to the last highlighted line to gain proper highlighter context.
+        while (startLine > 0 && !this._textModel.getAttribute(startLine - 1, 0, "highlighter-state"))
+            startLine--;
+
+        // Restore highlighter context taken from previous line.
+        var state = this._textModel.getAttribute(startLine - 1, 0, "highlighter-state");
+        if (state) {
+            this.continueState = state.postContinueState;
+            this.lexState = state.postLexState;
+        }
+
+        // Each line has associated state attribute with pre- and post-highlighter conditions.
+        // Highlight lines from range until we find line precondition matching highlighter state.
+        var damage = {};
+        for (var i = startLine; i < endLine; ++i) {
+            state = this._textModel.getAttribute(i, 0, "highlighter-state");
+            if (state && state.preContinueState === this.continueState && state.preLexState === this.lexState) {
+                // Following lines are up to date, no need re-highlight.
+                this.continueState = state.postContinueState;
+                this.lexState = state.postLexState;
+                continue;
+            }
+
+            damage[i] = true;
+
+            state = {};
+            state.preContinueState = this.continueState;
+            state.preLexState = this.lexState;
+
+            this._textModel.removeAttributes(i, "highlight");
+            var line = this._textModel.line(i);
+            for (var j = 0; j < line.length;)
+                j += this._lex(line.substring(j), i, j);
+
+            state.postContinueState = this.continueState;
+            state.postLexState = this.lexState;
+            this._textModel.addAttribute(i, 0, "highlighter-state", state);
+        }
+
+        state = this._textModel.getAttribute(endLine, 0, "highlighter-state");
+
+        if (state && (state.preContinueState !== this.continueState || state.preLexState !== this.lexState)) {
+            // Requested highlight range is over, but we did not recover. Invalidate tail highlighting.
+            for (var i = endLine; i < this._textModel.linesCount; ++i)
+                this._textModel.removeAttributes(i, "highlighter-state");
+        }
+
+        return damage;
+    },
+
+    _lex: function(codeFragment, line, column) {
+        var token = null;
+        for (var i = 0; i < this._highlighterScheme.rules.length; i++) {
+            var rule = this._highlighterScheme.rules[i];
+            var ruleContinueStateCondition = typeof rule.preContinueState !== "undefined" ? rule.preContinueState : this._highlighterScheme.ContinueState.None;
+            if (this.continueState !== ruleContinueStateCondition)
+                continue;
+            if (typeof rule.preLexState !== "undefined" && this.lexState !== rule.preLexState)
+                continue;
+
+            var match = rule.pattern.exec(codeFragment);
+            if (match) {
+                token = match[0];
+                if (token && (!rule.keywords || (token in rule.keywords))) {
+                    if (typeof rule.type === "number")
+                        this._textModel.addAttribute(line, column, "highlight", { length: token.length, style: this._styles[rule.type] });
+                    if (typeof rule.postLexState !== "undefined")
+                        this.lexState = rule.postLexState;
+                    if (typeof rule.postContinueState !== "undefined")
+                        this.continueState = rule.postContinueState;
+                    return token.length;
+                }
+            }
+        }
+        return 1;
+    }
+}
diff --git a/WebCore/inspector/front-end/TextEditorModel.js b/WebCore/inspector/front-end/TextEditorModel.js
new file mode 100644
index 0000000..5c5a74e
--- /dev/null
+++ b/WebCore/inspector/front-end/TextEditorModel.js
@@ -0,0 +1,294 @@
+/*
+ * 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.TextRange = function(startLine, startColumn, endLine, endColumn)
+{
+    this.startLine = startLine;
+    this.startColumn = startColumn;
+    this.endLine = endLine;
+    this.endColumn = endColumn;
+}
+
+WebInspector.TextRange.prototype = {
+    isEmpty: function()
+    {
+        return this.startLine === this.endLine && this.startColumn === this.endColumn;
+    },
+
+    get linesCount()
+    {
+        return this.endLine - this.startLine;
+    },
+
+    clone: function()
+    {
+        return new WebInspector.TextRange(this.startLine, this.startColumn, this.endLine, this.endColumn); 
+    }
+}
+
+WebInspector.TextEditorModel = function(changeListener)
+{
+    this._changeListener = changeListener;
+    this._lines = [""];
+    this._attributes = [];
+    this._undoStack = [];
+    this._noPunctuationRegex = /[^ !%&()*+,-.:;<=>?\[\]\^{|}~]+/;
+}
+
+WebInspector.TextEditorModel.prototype = {
+
+    get linesCount()
+    {
+        return this._lines.length;
+    },
+
+    line: function(lineNumber)
+    {
+        if (lineNumber >= this._lines.length)
+            throw "Out of bounds:" + lineNumber;
+        return this._lines[lineNumber];
+    },
+
+    lineLength: function(lineNumber)
+    {
+        return this._lines[lineNumber].length;
+    },
+
+    setText: function(range, text)
+    {
+        if (!range)
+            range = new WebInspector.TextRange(0, 0, this._lines.length - 1, this._lines[this._lines.length - 1].length);
+        var command = this._pushUndoableCommand(range, text);
+        var newRange = this._innerSetText(range, text);
+        command.range = newRange.clone();
+
+        this._changeListener(range, newRange, command.text, text);
+        return newRange;
+    },
+
+    _innerSetText: function(range, text)
+    {
+        this._eraseRange(range);
+        if (text === "")
+            return new WebInspector.TextRange(range.startLine, range.startColumn, range.startLine, range.startColumn);
+
+        var newLines = text.split("\n");
+        var prefix = this._lines[range.startLine].substring(0, range.startColumn);
+        var prefixArguments = this._arguments
+        var suffix = this._lines[range.startLine].substring(range.startColumn);
+
+        var postCaret = prefix.length;
+        // Insert text.
+        if (newLines.length === 1) {
+            this._setLine(range.startLine, prefix + newLines[0] + suffix);
+            postCaret += newLines[0].length;
+        } else {
+            this._setLine(range.startLine, prefix + newLines[0]);
+            for (var i = 1; i < newLines.length; ++i)
+                this._insertLine(range.startLine + i, newLines[i]);
+            this._setLine(range.startLine + newLines.length - 1, newLines[newLines.length - 1] + suffix);
+            postCaret = newLines[newLines.length - 1].length;
+        }
+        return new WebInspector.TextRange(range.startLine, range.startColumn,
+                                          range.startLine + newLines.length - 1, postCaret);
+    },
+
+    _eraseRange: function(range)
+    {
+        if (range.isEmpty())
+            return;
+
+        var prefix = this._lines[range.startLine].substring(0, range.startColumn);
+        var suffix = this._lines[range.endLine].substring(range.endColumn);
+
+        if (range.endLine > range.startLine)
+            this._removeLines(range.startLine + 1, range.endLine - range.startLine);
+        this._setLine(range.startLine, prefix + suffix);
+    },
+
+    _setLine: function(lineNumber, text)
+    {
+        this._lines[lineNumber] = text;
+        delete this._attributes[lineNumber];
+    },
+
+    _removeLines: function(fromLine, count)
+    {
+        this._lines.splice(fromLine, count);
+        this._attributes.splice(fromLine, count);
+    },
+
+    _insertLine: function(lineNumber, text)
+    {
+        this._lines.splice(lineNumber, 0, text);
+        this._attributes.splice(lineNumber, 0, []);
+    },
+
+    wordRange: function(lineNumber, column)
+    {
+        return new WebInspector.TextRange(lineNumber, this.wordStart(lineNumber, column, true), lineNumber, this.wordEnd(lineNumber, column, true));
+    },
+
+    wordStart: function(lineNumber, column, gapless)
+    {
+        var line = this._lines[lineNumber];
+        var prefix = line.substring(0, column).split("").reverse().join("");
+        var prefixMatch = this._noPunctuationRegex.exec(prefix);
+        return prefixMatch && (!gapless || prefixMatch.index === 0) ? column - prefixMatch.index - prefixMatch[0].length : column;
+    },
+
+    wordEnd: function(lineNumber, column, gapless)
+    {
+        var line = this._lines[lineNumber];
+        var suffix = line.substring(column);
+        var suffixMatch = this._noPunctuationRegex.exec(suffix);
+        return suffixMatch && (!gapless || suffixMatch.index === 0) ? column + suffixMatch.index + suffixMatch[0].length : column;
+    },
+
+    copyRange: function(range)
+    {
+        var clip = [];
+        if (range.startLine === range.endLine) {
+            clip.push(this._lines[range.startLine].substring(range.startColumn, range.endColumn));
+            return clip.join("\n");
+        }
+        clip.push(this._lines[range.startLine].substring(range.startColumn));
+        for (var i = range.startLine + 1; i < range.endLine; ++i)
+            clip.push(this._lines[i]);
+        clip.push(this._lines[range.endLine].substring(0, range.endColumn));
+        return clip.join("\n");
+    },
+
+    addAttribute: function(line, column, name, value)
+    {
+        var attrs = this._attributes[line];
+        if (!attrs) {
+            attrs = [];
+            this._attributes[line] = attrs;
+        }
+        var family = attrs[name];
+        if (!family) {
+            family = [];
+            attrs[name] = family;
+        }
+        family[column] = value;
+    },
+
+    getAttribute: function(line, column, name)
+    {
+        var family = this.getAttributes(line, name);
+        return family ? family[column] : null;
+    },
+
+    getAttributes: function(line, name)
+    {
+        var attrs = this._attributes[line];
+        return attrs ? attrs[name] : null;
+    },
+
+    removeAttributes: function(line, name)
+    {
+        var attrs = this._attributes[line];
+        if (attrs)
+            delete attrs[name];
+    },
+
+    _pushUndoableCommand: function(range, text)
+    {
+        var command = {
+            text: this.copyRange(range),
+            startLine: range.startLine,
+            startColumn: range.startColumn,
+            endLine: range.startLine,
+            endColumn: range.startColumn
+        };
+        if (this._inUndo)
+            this._redoStack.push(command);
+        else {
+            if (!this._inRedo)
+                this._redoStack = [];
+            this._undoStack.push(command);
+        }
+        return command;
+    },
+
+    undo: function()
+    {
+        this._markRedoableState();
+
+        this._inUndo = true;
+        var range = this._doUndo(this._undoStack);
+        delete this._inUndo;
+
+        return range;
+    },
+
+    redo: function()
+    {
+        this.markUndoableState();
+
+        this._inRedo = true;
+        var range = this._doUndo(this._redoStack);
+        delete this._inRedo;
+
+        return range;
+    },
+
+    _doUndo: function(stack)
+    {
+        var range = null;
+        for (var i = stack.length - 1; i >= 0; --i) {
+            var command = stack[i];
+            stack.length = i;
+
+            range = this.setText(command.range, command.text);
+            if (i > 0 && stack[i - 1].explicit)
+                return range;
+        }
+        return range;
+    },
+
+    markUndoableState: function()
+    {
+        if (this._undoStack.length)
+            this._undoStack[this._undoStack.length - 1].explicit = true;
+    },
+
+    _markRedoableState: function()
+    {
+        if (this._redoStack.length)
+            this._redoStack[this._redoStack.length - 1].explicit = true;
+    },
+
+    resetUndoStack: function()
+    {
+        this._undoStack = [];
+    }
+}
diff --git a/WebCore/inspector/front-end/WebKit.qrc b/WebCore/inspector/front-end/WebKit.qrc
index 4a21e2c..85dbc6b 100644
--- a/WebCore/inspector/front-end/WebKit.qrc
+++ b/WebCore/inspector/front-end/WebKit.qrc
@@ -35,6 +35,7 @@
     <file>inspector.js</file>
     <file>InspectorBackendStub.js</file>
     <file>InspectorFrontendHostStub.js</file>
+    <file>JavaScriptHighlighterScheme.js</file>
     <file>JavaScriptSourceSyntaxHighlighter.js</file>
     <file>KeyboardShortcut.js</file>
     <file>MetricsSidebarPane.js</file>
@@ -70,6 +71,9 @@
     <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>TimelineAgent.js</file>
     <file>TimelineGrid.js</file>
diff --git a/WebCore/inspector/front-end/inspector.css b/WebCore/inspector/front-end/inspector.css
index b676175..dff8c29 100644
--- a/WebCore/inspector/front-end/inspector.css
+++ b/WebCore/inspector/front-end/inspector.css
@@ -3758,3 +3758,49 @@ ol.breakpoint-list {
 .webkit-html-js-node, .webkit-html-css-node {
     white-space: pre;
 }
+
+.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-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-sheet {
+    opacity: 0;
+}
+
+.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;
+}
diff --git a/WebCore/inspector/front-end/inspector.html b/WebCore/inspector/front-end/inspector.html
index 9f78c0f..128f2e8 100644
--- a/WebCore/inspector/front-end/inspector.html
+++ b/WebCore/inspector/front-end/inspector.html
@@ -94,6 +94,10 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     <script type="text/javascript" src="SourceSyntaxHighlighter.js"></script>
     <script type="text/javascript" src="CSSSourceSyntaxHighlighter.js"></script>
     <script type="text/javascript" src="JavaScriptSourceSyntaxHighlighter.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="JavaScriptHighlighterScheme.js"></script>
     <script type="text/javascript" src="SourceView.js"></script>
     <script type="text/javascript" src="FontView.js"></script>
     <script type="text/javascript" src="ImageView.js"></script>

-- 
WebKit Debian packaging



More information about the Pkg-webkit-commits mailing list