Bug 930928 - Shader compilation errors should be displayed in the editor, r=rcampbell,anton

This commit is contained in:
Victor Porof 2013-11-05 14:07:37 +02:00
parent 24a44f10ae
commit fa839ec160
18 changed files with 543 additions and 58 deletions

View File

@ -159,7 +159,7 @@ var Scratchpad = {
{
this._dirty = aValue;
if (!aValue && this.editor)
this.editor.markClean();
this.editor.setClean();
this._updateTitle();
},

View File

@ -15,6 +15,7 @@ Cu.import("resource:///modules/devtools/ViewHelpers.jsm");
const require = Cu.import("resource://gre/modules/devtools/Loader.jsm", {}).devtools.require;
const promise = require("sdk/core/promise");
const EventEmitter = require("devtools/shared/event-emitter");
const {Tooltip} = require("devtools/shared/widgets/Tooltip");
const Editor = require("devtools/sourceeditor/editor");
// The panel's window global is an EventEmitter firing the following events:
@ -31,11 +32,14 @@ const EVENTS = {
};
const STRINGS_URI = "chrome://browser/locale/devtools/shadereditor.properties"
const HIGHLIGHT_COLOR = [1, 0, 0, 1];
const TYPING_MAX_DELAY = 500;
const HIGHLIGHT_COLOR = [1, 0, 0, 1]; // rgba
const TYPING_MAX_DELAY = 500; // ms
const SHADERS_AUTOGROW_ITEMS = 4;
const GUTTER_ERROR_PANEL_OFFSET_X = 7; // px
const GUTTER_ERROR_PANEL_DELAY = 100; // ms
const DEFAULT_EDITOR_CONFIG = {
mode: Editor.modes.text,
gutters: ["errors"],
lineNumbers: true,
showAnnotationRuler: true
};
@ -426,6 +430,9 @@ let ShadersEditorsView = {
*/
_onChanged: function(type) {
setNamedTimeout("gl-typed", TYPING_MAX_DELAY, () => this._doCompile(type));
// Remove all the gutter markers and line classes from the editor.
this._cleanEditor(type);
},
/**
@ -442,13 +449,117 @@ let ShadersEditorsView = {
try {
yield shaderActor.compile(editor.getText());
window.emit(EVENTS.SHADER_COMPILED, null);
// TODO: remove error gutter markers, after bug 919709 lands.
} catch (error) {
window.emit(EVENTS.SHADER_COMPILED, error);
// TODO: add error gutter markers, after bug 919709 lands.
this._onSuccessfulCompilation();
} catch (e) {
this._onFailedCompilation(type, editor, e);
}
}.bind(this));
},
/**
* Called uppon a successful shader compilation.
*/
_onSuccessfulCompilation: function() {
// Signal that the shader was compiled successfully.
window.emit(EVENTS.SHADER_COMPILED, null);
},
/**
* Called uppon an unsuccessful shader compilation.
*/
_onFailedCompilation: function(type, editor, errors) {
let lineCount = editor.lineCount();
let currentLine = editor.getCursor().line;
let listeners = { mouseenter: this._onMarkerMouseEnter };
function matchLinesAndMessages(string) {
return {
// First number that is not equal to 0.
lineMatch: string.match(/\d{2,}|[1-9]/),
// The string after all the numbers, semicolons and spaces.
textMatch: string.match(/[^\s\d:][^\r\n|]*/)
};
}
function discardInvalidMatches(e) {
// Discard empty line and text matches.
return e.lineMatch && e.textMatch;
}
function sanitizeValidMatches(e) {
return {
// Drivers might yield retarded line numbers under some obscure
// circumstances. Don't throw the errors away in those cases,
// just display them on the currently edited line.
line: e.lineMatch[0] > lineCount ? currentLine : e.lineMatch[0] - 1,
// Trim whitespace from the beginning and the end of the message,
// and replace all other occurences of double spaces to a single space.
text: e.textMatch[0].trim().replace(/\s{2,}/g, " ")
};
}
function sortByLine(first, second) {
// Sort all the errors ascending by their corresponding line number.
return first.line > second.line ? 1 : -1;
}
function groupSameLineMessages(accumulator, current) {
// Group errors corresponding to the same line number to a single object.
let previous = accumulator[accumulator.length - 1];
if (!previous || previous.line != current.line) {
return [...accumulator, {
line: current.line,
messages: [current.text]
}];
} else {
previous.messages.push(current.text);
return accumulator;
}
}
function displayErrors({ line, messages }) {
// Add gutter markers and line classes for every error in the source.
editor.addMarker(line, "errors", "error");
editor.setMarkerListeners(line, "errors", "error", listeners, messages);
editor.addLineClass(line, "error-line");
}
(this._errors[type] = errors.link
.split("ERROR")
.map(matchLinesAndMessages)
.filter(discardInvalidMatches)
.map(sanitizeValidMatches)
.sort(sortByLine)
.reduce(groupSameLineMessages, []))
.forEach(displayErrors);
// Signal that the shader wasn't compiled successfully.
window.emit(EVENTS.SHADER_COMPILED, errors);
},
/**
* Event listener for the 'mouseenter' event on a marker in the editor gutter.
*/
_onMarkerMouseEnter: function(line, node, messages) {
if (node._markerErrorsTooltip) {
return;
}
let tooltip = node._markerErrorsTooltip = new Tooltip(document);
tooltip.defaultOffsetX = GUTTER_ERROR_PANEL_OFFSET_X;
tooltip.setTextContent.apply(tooltip, messages);
tooltip.startTogglingOnHover(node, () => true, GUTTER_ERROR_PANEL_DELAY);
},
/**
* Removes all the gutter markers and line classes from the editor.
*/
_cleanEditor: function(type) {
this._getEditor(type).then(editor => {
editor.removeAllMarkers("errors");
this._errors[type].forEach(e => editor.removeLineClass(e.line));
this._errors[type].length = 0;
});
},
_errors: {
vs: [],
fs: []
}
};

View File

@ -9,6 +9,8 @@ support-files =
[browser_se_aaa_run_first_leaktest.js]
[browser_se_bfcache.js]
[browser_se_editors-contents.js]
[browser_se_editors-error-gutter.js]
[browser_se_editors-error-tooltip.js]
[browser_se_editors-lazy-init.js]
[browser_se_first-run.js]
[browser_se_navigation.js]

View File

@ -0,0 +1,156 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if error indicators are shown in the editor's gutter and text area
* when there's a shader compilation error.
*/
function ifWebGLSupported() {
let [target, debuggee, panel] = yield initShaderEditor(SIMPLE_CANVAS_URL);
let { gFront, EVENTS, ShadersEditorsView } = panel.panelWin;
reload(target);
yield once(gFront, "program-linked");
let vsEditor = yield ShadersEditorsView._getEditor("vs");
let fsEditor = yield ShadersEditorsView._getEditor("fs");
vsEditor.replaceText("vec3", { line: 7, ch: 22 }, { line: 7, ch: 26 });
let vertError = yield once(panel.panelWin, EVENTS.SHADER_COMPILED);
checkHasVertFirstError(true, vertError);
checkHasVertSecondError(false, vertError);
info("Error marks added in the vertex shader editor.");
vsEditor.insertText(" ", { line: 1, ch: 0 });
is(vsEditor.getText(1), " precision lowp float;", "Typed space.");
checkHasVertFirstError(false, vertError);
checkHasVertSecondError(false, vertError);
info("Error marks removed while typing in the vertex shader editor.");
let vertError = yield once(panel.panelWin, EVENTS.SHADER_COMPILED);
checkHasVertFirstError(true, vertError);
checkHasVertSecondError(false, vertError);
info("Error marks were re-added after recompiling the vertex shader.");
fsEditor.replaceText("vec4", { line: 2, ch: 14 }, { line: 2, ch: 18 });
let fragError = yield once(panel.panelWin, EVENTS.SHADER_COMPILED);
checkHasVertFirstError(true, vertError);
checkHasVertSecondError(false, vertError);
checkHasFragError(true, fragError);
info("Error marks added in the fragment shader editor.");
fsEditor.insertText(" ", { line: 1, ch: 0 });
is(fsEditor.getText(1), " precision lowp float;", "Typed space.");
checkHasVertFirstError(true, vertError);
checkHasVertSecondError(false, vertError);
checkHasFragError(false, fragError);
info("Error marks removed while typing in the fragment shader editor.");
let fragError = yield once(panel.panelWin, EVENTS.SHADER_COMPILED);
checkHasVertFirstError(true, vertError);
checkHasVertSecondError(false, vertError);
checkHasFragError(true, fragError);
info("Error marks were re-added after recompiling the fragment shader.");
vsEditor.replaceText("2", { line: 3, ch: 19 }, { line: 3, ch: 20 });
checkHasVertFirstError(false, vertError);
checkHasVertSecondError(false, vertError);
checkHasFragError(true, fragError);
info("Error marks removed while typing in the vertex shader editor again.");
let vertError = yield once(panel.panelWin, EVENTS.SHADER_COMPILED);
checkHasVertFirstError(true, vertError);
checkHasVertSecondError(true, vertError);
checkHasFragError(true, fragError);
info("Error marks were re-added after recompiling the fragment shader again.");
yield teardown(panel);
finish();
function checkHasVertFirstError(bool, error) {
ok(error, "Vertex shader compiled with errors.");
isnot(error.link, "", "The linkage status should not be empty.");
let line = 7;
info("Checking first vertex shader error on line " + line + "...");
is(vsEditor.hasMarker(line, "errors", "error"), bool,
"Error is " + (bool ? "" : "not ") + "shown in the editor's gutter.");
is(vsEditor.hasLineClass(line, "error-line"), bool,
"Error style is " + (bool ? "" : "not ") + "applied to the faulty line.");
let parsed = ShadersEditorsView._errors.vs;
is(parsed.length >= 1, bool,
"There's " + (bool ? ">= 1" : "< 1") + " parsed vertex shader error(s).");
if (bool) {
is(parsed[0].line, line,
"The correct line was parsed.");
is(parsed[0].messages.length, 2,
"There are 2 parsed messages.");
ok(parsed[0].messages[0].contains("'constructor' : too many arguments"),
"The correct first message was parsed.");
ok(parsed[0].messages[1].contains("'assign' : cannot convert from"),
"The correct second message was parsed.");
}
}
function checkHasVertSecondError(bool, error) {
ok(error, "Vertex shader compiled with errors.");
isnot(error.link, "", "The linkage status should not be empty.");
let line = 8;
info("Checking second vertex shader error on line " + line + "...");
is(vsEditor.hasMarker(line, "errors", "error"), bool,
"Error is " + (bool ? "" : "not ") + "shown in the editor's gutter.");
is(vsEditor.hasLineClass(line, "error-line"), bool,
"Error style is " + (bool ? "" : "not ") + "applied to the faulty line.");
let parsed = ShadersEditorsView._errors.vs;
is(parsed.length >= 2, bool,
"There's " + (bool ? ">= 2" : "< 2") + " parsed vertex shader error(s).");
if (bool) {
is(parsed[1].line, line,
"The correct line was parsed.");
is(parsed[1].messages.length, 1,
"There is 1 parsed message.");
ok(parsed[1].messages[0].contains("'assign' : cannot convert from"),
"The correct message was parsed.");
}
}
function checkHasFragError(bool, error) {
ok(error, "Fragment shader compiled with errors.");
isnot(error.link, "", "The linkage status should not be empty.");
let line = 5;
info("Checking first vertex shader error on line " + line + "...");
is(fsEditor.hasMarker(line, "errors", "error"), bool,
"Error is " + (bool ? "" : "not ") + "shown in the editor's gutter.");
is(fsEditor.hasLineClass(line, "error-line"), bool,
"Error style is " + (bool ? "" : "not ") + "applied to the faulty line.");
let parsed = ShadersEditorsView._errors.fs;
is(parsed.length >= 1, bool,
"There's " + (bool ? ">= 2" : "< 1") + " parsed fragment shader error(s).");
if (bool) {
is(parsed[0].line, line,
"The correct line was parsed.");
is(parsed[0].messages.length, 1,
"There is 1 parsed message.");
ok(parsed[0].messages[0].contains("'constructor' : too many arguments"),
"The correct message was parsed.");
}
}
}
function once(aTarget, aEvent) {
let deferred = promise.defer();
aTarget.once(aEvent, (aName, aData) => deferred.resolve(aData));
return deferred.promise;
}

View File

@ -0,0 +1,59 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if error tooltips can be opened from the editor's gutter when there's
* a shader compilation error.
*/
function ifWebGLSupported() {
let [target, debuggee, panel] = yield initShaderEditor(SIMPLE_CANVAS_URL);
let { gFront, EVENTS, ShadersEditorsView } = panel.panelWin;
reload(target);
yield once(gFront, "program-linked");
let vsEditor = yield ShadersEditorsView._getEditor("vs");
let fsEditor = yield ShadersEditorsView._getEditor("fs");
vsEditor.replaceText("vec3", { line: 7, ch: 22 }, { line: 7, ch: 26 });
yield once(panel.panelWin, EVENTS.SHADER_COMPILED);
// Synthesizing 'mouseenter' events doesn't work, hack around this by
// manually calling the event listener with the expected arguments.
let editorDocument = vsEditor.container.contentDocument;
let marker = editorDocument.querySelector(".error");
let parsed = ShadersEditorsView._errors.vs[0].messages;
ShadersEditorsView._onMarkerMouseEnter(7, marker, parsed);
let tooltip = marker._markerErrorsTooltip;
ok(tooltip, "A tooltip was created successfully.");
let content = tooltip.content;
ok(tooltip.content,
"Some tooltip's content was set.");
is(tooltip.content.className, "devtools-tooltip-simple-text-container",
"The tooltip's content container was created correctly.");
let messages = content.childNodes;
is(messages.length, 2,
"There are two messages displayed in the tooltip.");
is(messages[0].className, "devtools-tooltip-simple-text",
"The first message was created correctly.");
is(messages[1].className, "devtools-tooltip-simple-text",
"The second message was created correctly.");
ok(messages[0].textContent.contains("'constructor' : too many arguments"),
"The first message contains the correct text.");
ok(messages[1].textContent.contains("'assign' : cannot convert"),
"The second message contains the correct text.");
yield teardown(panel);
finish();
}
function once(aTarget, aEvent) {
let deferred = promise.defer();
aTarget.once(aEvent, (aName, aData) => deferred.resolve(aData));
return deferred.promise;
}

View File

@ -2,7 +2,8 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Tests if editing a vertex and a fragment shader works properly.
* Tests if editing a vertex and a fragment shader would permanently store
* their new source on the backend and reshow it in the frontend when required.
*/
function ifWebGLSupported() {

View File

@ -95,6 +95,10 @@ function Tooltip(doc) {
module.exports.Tooltip = Tooltip;
Tooltip.prototype = {
defaultPosition: "before_start",
defaultOffsetX: 0,
defaultOffsetY: 0,
/**
* Show the tooltip. It might be wise to append some content first if you
* don't want the tooltip to be empty. You may access the content of the
@ -105,9 +109,12 @@ Tooltip.prototype = {
* https://developer.mozilla.org/en-US/docs/XUL/PopupGuide/Positioning
* Defaults to before_start
*/
show: function(anchor, position="before_start") {
show: function(anchor,
position = this.defaultPosition,
x = this.defaultOffsetX,
y = this.defaultOffsetY) {
this.panel.hidden = false;
this.panel.openPopup(anchor, position);
this.panel.openPopup(anchor, position, x, y);
},
/**
@ -257,6 +264,28 @@ Tooltip.prototype = {
return this.panel.firstChild;
},
/**
* Sets some text as the content of this tooltip.
*
* @param string[] messages
* A list of text messages.
*/
setTextContent: function(...messages) {
let vbox = this.doc.createElement("vbox");
vbox.className = "devtools-tooltip-simple-text-container";
vbox.setAttribute("flex", "1");
for (let text of messages) {
let description = this.doc.createElement("description");
description.setAttribute("flex", "1");
description.className = "devtools-tooltip-simple-text";
description.textContent = text;
vbox.appendChild(description);
}
this.content = vbox;
},
/**
* Fill the tooltip with an image, displayed over a tiled background useful
* for transparent images.

View File

@ -1,15 +1,25 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
.errors,
.breakpoints {
width: 16px;
}
.breakpoint, .debugLocation, .breakpoint-debugLocation {
.error, .breakpoint, .debugLocation, .breakpoint-debugLocation {
display: inline-block;
margin-left: 5px;
width: 14px;
height: 14px;
width: 12px;
height: 12px;
background-repeat: no-repeat;
background-position: center center;
background-size: 12px;
background-position: center;
background-size: contain;
}
.error {
background-image: url("chrome://browser/skin/devtools/orion-error.png");
opacity: 0.75;
}
.breakpoint {
@ -23,4 +33,8 @@
.breakpoint.debugLocation {
background-image: url("chrome://browser/skin/devtools/orion-debug-location.png"),
url("chrome://browser/skin/devtools/orion-breakpoint.png");
}
}
.error-line {
background: rgba(255,0,0,0.2);
}

View File

@ -6,38 +6,6 @@
const dbginfo = new WeakMap();
// Private functions
/**
* Adds a marker to the breakpoints gutter.
* Type should be either a 'breakpoint' or a 'debugLocation'.
*/
function addMarker(cm, line, type) {
let info = cm.lineInfo(line);
if (info.gutterMarkers)
return void info.gutterMarkers.breakpoints.classList.add(type);
let mark = cm.getWrapperElement().ownerDocument.createElement("div");
mark.className = type;
mark.innerHTML = "";
cm.setGutterMarker(info.line, "breakpoints", mark);
}
/**
* Removes a marker from the breakpoints gutter.
* Type should be either a 'breakpoint' or a 'debugLocation'.
*/
function removeMarker(cm, line, type) {
let info = cm.lineInfo(line);
if (!info || !info.gutterMarkers)
return;
info.gutterMarkers.breakpoints.classList.remove(type);
}
// These functions implement search within the debugger. Since
// search in the debugger is different from other components,
// we can't use search.js CodeMirror addon. This is a slightly
@ -155,7 +123,7 @@ function addBreakpoint(ctx, line, cond) {
let meta = dbginfo.get(ed);
let info = cm.lineInfo(line);
addMarker(cm, line, "breakpoint");
ed.addMarker(line, "breakpoints", "breakpoint");
meta.breakpoints[line] = { condition: cond };
info.handle.on("delete", function onDelete() {
@ -179,7 +147,7 @@ function removeBreakpoint(ctx, line) {
let info = cm.lineInfo(line);
meta.breakpoints[info.line] = null;
removeMarker(cm, info.line, "breakpoint");
ed.removeMarker(info.line, "breakpoints", "breakpoint");
ed.emit("breakpointRemoved", line);
}
@ -203,11 +171,11 @@ function getBreakpoints(ctx) {
* display the line on which the Debugger is currently paused.
*/
function setDebugLocation(ctx, line) {
let { ed, cm } = ctx;
let { ed } = ctx;
let meta = dbginfo.get(ed);
meta.debugLocation = line;
addMarker(cm, line, "debugLocation");
ed.addMarker(line, "breakpoints", "debugLocation");
}
/**
@ -226,11 +194,11 @@ function getDebugLocation(ctx) {
* also removes a visual anchor from the breakpoints gutter.
*/
function clearDebugLocation(ctx) {
let { ed, cm } = ctx;
let { ed } = ctx;
let meta = dbginfo.get(ed);
if (meta.debugLocation != null) {
removeMarker(cm, meta.debugLocation, "debugLocation");
ed.removeMarker(meta.debugLocation, "breakpoints", "debugLocation");
meta.debugLocation = null;
}
}

View File

@ -340,7 +340,7 @@ Editor.prototype = {
* Replaces contents of a text area within the from/to {line, ch}
* range. If neither from nor to arguments are provided works
* exactly like setText. If only from object is provided, inserts
* text at that point.
* text at that point, *overwriting* as many characters as needed.
*/
replaceText: function (value, from, to) {
let cm = editors.get(this);
@ -356,6 +356,15 @@ Editor.prototype = {
cm.replaceRange(value, from, to);
},
/**
* Inserts text at the specified {line, ch} position, shifting existing
* contents as necessary.
*/
insertText: function (value, at) {
let cm = editors.get(this);
cm.replaceRange(value, at, at);
},
/**
* Deselects contents of the text area.
*/
@ -370,7 +379,7 @@ Editor.prototype = {
* Marks the contents as clean and returns the current
* version number.
*/
markClean: function () {
setClean: function () {
let cm = editors.get(this);
this.version = cm.changeGeneration();
return this.version;
@ -519,6 +528,120 @@ Editor.prototype = {
this.setFirstVisibleLine(topLine);
},
/**
* Returns whether a marker of a specified class exists in a line's gutter.
*/
hasMarker: function (line, gutterName, markerClass) {
let cm = editors.get(this);
let info = cm.lineInfo(line);
if (!info)
return false;
let gutterMarkers = info.gutterMarkers;
if (!gutterMarkers)
return false;
let marker = gutterMarkers[gutterName];
if (!marker)
return false;
return marker.classList.contains(markerClass);
},
/**
* Adds a marker with a specified class to a line's gutter. If another marker
* exists on that line, the new marker class is added to its class list.
*/
addMarker: function (line, gutterName, markerClass) {
let cm = editors.get(this);
let info = cm.lineInfo(line);
if (!info)
return;
let gutterMarkers = info.gutterMarkers;
if (gutterMarkers) {
let marker = gutterMarkers[gutterName];
if (marker) {
marker.classList.add(markerClass);
return;
}
}
let marker = cm.getWrapperElement().ownerDocument.createElement("div");
marker.className = markerClass;
cm.setGutterMarker(info.line, gutterName, marker);
},
/**
* The reverse of addMarker. Removes a marker of a specified class from a
* line's gutter.
*/
removeMarker: function (line, gutterName, markerClass) {
if (!this.hasMarker(line, gutterName, markerClass))
return;
let cm = editors.get(this);
cm.lineInfo(line).gutterMarkers[gutterName].classList.remove(markerClass);
},
/**
* Remove all gutter markers in the gutter with the given name.
*/
removeAllMarkers: function (gutterName) {
let cm = editors.get(this);
cm.clearGutter(gutterName);
},
/**
* Handles attaching a set of events listeners on a marker. They should
* be passed as an object literal with keys as event names and values as
* function listeners. The line number, marker node and optional data
* will be passed as arguments to the function listener.
*
* You don't need to worry about removing these event listeners.
* They're automatically orphaned when clearing markers.
*/
setMarkerListeners: function(line, gutterName, markerClass, events, data) {
if (!this.hasMarker(line, gutterName, markerClass))
return;
let cm = editors.get(this);
let marker = cm.lineInfo(line).gutterMarkers[gutterName];
for (let name in events) {
let listener = events[name].bind(this, line, marker, data);
marker.addEventListener(name, listener);
}
},
/**
* Returns whether a line is decorated using the specified class name.
*/
hasLineClass: function (line, className) {
let cm = editors.get(this);
let info = cm.lineInfo(line);
if (!info)
return false;
return info.wrapClass == className;
},
/**
* Set a CSS class name for the given line, including the text and gutter.
*/
addLineClass: function (line, className) {
let cm = editors.get(this);
cm.addLineClass(line, "wrap", className);
},
/**
* The reverse of addLineClass.
*/
removeLineClass: function (line, className) {
let cm = editors.get(this);
cm.removeLineClass(line, "wrap", className);
},
destroy: function () {
this.container = null;
this.config = null;

View File

@ -376,7 +376,7 @@ StyleSheetEditor.prototype = {
if (callback) {
callback(returnFile);
}
this.sourceEditor.markClean();
this.sourceEditor.setClean();
}.bind(this));
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -143,6 +143,7 @@ browser.jar:
skin/classic/browser/devtools/orion.css (devtools/orion.css)
skin/classic/browser/devtools/orion-container.css (devtools/orion-container.css)
skin/classic/browser/devtools/orion-task.png (devtools/orion-task.png)
skin/classic/browser/devtools/orion-error.png (devtools/orion-error.png)
skin/classic/browser/devtools/orion-breakpoint.png (devtools/orion-breakpoint.png)
skin/classic/browser/devtools/orion-debug-location.png (devtools/orion-debug-location.png)
skin/classic/browser/devtools/breadcrumbs-scrollbutton.png (devtools/breadcrumbs-scrollbutton.png)

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -232,6 +232,7 @@ browser.jar:
skin/classic/browser/devtools/orion.css (devtools/orion.css)
skin/classic/browser/devtools/orion-container.css (devtools/orion-container.css)
skin/classic/browser/devtools/orion-task.png (devtools/orion-task.png)
skin/classic/browser/devtools/orion-error.png (devtools/orion-error.png)
skin/classic/browser/devtools/orion-breakpoint.png (devtools/orion-breakpoint.png)
skin/classic/browser/devtools/orion-debug-location.png (devtools/orion-debug-location.png)
* skin/classic/browser/devtools/webconsole.css (devtools/webconsole.css)

View File

@ -121,11 +121,29 @@
background: #eee;
border-radius: 3px;
}
.devtools-tooltip.devtools-tooltip-panel .panel-arrowcontent {
/* If the tooltip uses a <panel> XUL element instead */
padding: 4px;
}
.devtools-tooltip-simple-text {
background: linear-gradient(1deg, transparent 0%, rgba(94,136,176,0.1) 100%);
max-width: 400px;
margin: 0 -4px; /* Compensate for the .panel-arrowcontent padding. */
padding: 8px 12px;
text-shadow: 0 1px 0 #fff;
white-space: pre-wrap;
}
.devtools-tooltip-simple-text:first-child {
margin-top: -4px;
}
.devtools-tooltip-simple-text:last-child {
margin-bottom: -4px;
}
.devtools-tooltip-tiles {
background-color: #eee;
background-image: linear-gradient(45deg, #ccc 25%, transparent 25%, transparent 75%, #ccc 75%, #ccc),

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

@ -167,6 +167,7 @@ browser.jar:
skin/classic/browser/devtools/orion.css (devtools/orion.css)
skin/classic/browser/devtools/orion-container.css (devtools/orion-container.css)
skin/classic/browser/devtools/orion-task.png (devtools/orion-task.png)
skin/classic/browser/devtools/orion-error.png (devtools/orion-error.png)
skin/classic/browser/devtools/orion-breakpoint.png (devtools/orion-breakpoint.png)
skin/classic/browser/devtools/orion-debug-location.png (devtools/orion-debug-location.png)
* skin/classic/browser/devtools/webconsole.css (devtools/webconsole.css)
@ -444,6 +445,7 @@ browser.jar:
skin/classic/aero/browser/devtools/orion.css (devtools/orion.css)
skin/classic/aero/browser/devtools/orion-container.css (devtools/orion-container.css)
skin/classic/aero/browser/devtools/orion-task.png (devtools/orion-task.png)
skin/classic/aero/browser/devtools/orion-error.png (devtools/orion-error.png)
skin/classic/aero/browser/devtools/orion-breakpoint.png (devtools/orion-breakpoint.png)
skin/classic/aero/browser/devtools/orion-debug-location.png (devtools/orion-debug-location.png)
* skin/classic/aero/browser/devtools/webconsole.css (devtools/webconsole.css)