MozReview-Commit-ID: 5tBsZXSVTf7
This commit is contained in:
Wes Kocher 2016-04-26 14:27:46 -07:00
Родитель 3b9a180178 f20e8d0047
Коммит 2c752b3679
48 изменённых файлов: 1172 добавлений и 569 удалений

Просмотреть файл

@ -105,6 +105,7 @@ devtools/client/sourceeditor/**
devtools/client/webaudioeditor/**
devtools/client/webconsole/**
!devtools/client/webconsole/panel.js
!devtools/client/webconsole/jsterm.js
devtools/client/webide/**
devtools/server/**
devtools/shared/*.js

Просмотреть файл

@ -138,7 +138,8 @@ function openTab(window, url, options) {
return window.BrowserApp.addTab(url, {
selected: options.inBackground ? false : true,
pinned: options.isPinned || false,
isPrivate: options.isPrivate || false
isPrivate: options.isPrivate || false,
parentId: window.BrowserApp.selectedTab.id
});
}

Просмотреть файл

@ -261,21 +261,9 @@ var AboutReaderListener = {
let url = content.document.location.href;
if (!this.isAboutReader) {
this._articlePromise = ReaderMode.parseDocument(content.document).catch(Cu.reportError);
content.document.location = "about:reader?url=" + encodeURIComponent(url);
ReaderMode.enterReaderMode(docShell, content);
} else {
let originalURL = ReaderMode.getOriginalUrl(url);
let webNav = docShell.QueryInterface(Ci.nsIWebNavigation);
let sh = webNav.sessionHistory;
if (webNav.canGoBack) {
let prevEntry = sh.getEntryAtIndex(sh.index - 1, false);
let prevURL = prevEntry.URI.spec;
if (prevURL && (prevURL == originalURL || !originalURL)) {
webNav.goBack();
break;
}
}
content.document.location = originalURL;
ReaderMode.leaveReaderMode(docShell, content);
}
break;

Просмотреть файл

@ -8,7 +8,6 @@
const {
createNode,
drawGraphElementBackground,
findOptimalTimeInterval,
TimeScale
} = require("devtools/client/animationinspector/utils");
@ -438,9 +437,6 @@ AnimationsTimeline.prototype = {
let intervalLength = findOptimalTimeInterval(minTimeInterval);
let intervalWidth = intervalLength * width / animationDuration;
drawGraphElementBackground(this.win.document, "time-graduations",
width, intervalWidth);
// And the time graduation header.
this.timeHeaderEl.innerHTML = "";

Просмотреть файл

@ -22,13 +22,6 @@ const OPTIMAL_TIME_INTERVAL_MAX_ITERS = 100;
// Time graduations should be multiple of one of these number.
const OPTIMAL_TIME_INTERVAL_MULTIPLES = [1, 2.5, 5];
// RGB color for the time interval background.
const TIME_INTERVAL_COLOR = [128, 136, 144];
// byte
const TIME_INTERVAL_OPACITY_MIN = 64;
// byte
const TIME_INTERVAL_OPACITY_MAX = 96;
const MILLIS_TIME_FORMAT_MAX_DURATION = 4000;
/**
@ -64,63 +57,6 @@ function createNode(options) {
exports.createNode = createNode;
/**
* Given a data-scale, draw the background for a graph (vertical lines) into a
* canvas and set that canvas as an image-element with an ID that can be used
* from CSS.
* @param {Document} document The document where the image-element should be
* set.
* @param {String} id The ID for the image-element.
* @param {Number} graphWidth The width of the graph.
* @param {Number} intervalWidth The width of one interval
*/
function drawGraphElementBackground(document, id, graphWidth, intervalWidth) {
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
// Don't do anything if the graph or the intervals have a width of 0
if (graphWidth === 0 || intervalWidth === 0) {
return;
}
// Set the canvas width (as requested) and height (1px, repeated along the Y
// axis).
canvas.width = graphWidth;
canvas.height = 1;
// Create the image data array which will receive the pixels.
let imageData = ctx.createImageData(canvas.width, canvas.height);
let pixelArray = imageData.data;
let buf = new ArrayBuffer(pixelArray.length);
let view8bit = new Uint8ClampedArray(buf);
let view32bit = new Uint32Array(buf);
// Build new millisecond tick lines...
let [r, g, b] = TIME_INTERVAL_COLOR;
let opacities = [TIME_INTERVAL_OPACITY_MAX, TIME_INTERVAL_OPACITY_MIN];
// Insert one tick line on each interval
for (let i = 0; i <= graphWidth / intervalWidth; i++) {
let x = i * intervalWidth;
// Ensure the last line is drawn on canvas
if (x >= graphWidth) {
x = graphWidth - 0.5;
}
let position = x | 0;
let alphaComponent = opacities[i % opacities.length];
view32bit[position] = (alphaComponent << 24) | (b << 16) | (g << 8) | r;
}
// Flush the image data and cache the waterfall background.
pixelArray.set(view8bit);
ctx.putImageData(imageData, 0, 0);
document.mozSetImageElement(id, canvas);
}
exports.drawGraphElementBackground = drawGraphElementBackground;
/**
* Find the optimal interval between time graduations in the animation timeline
* graph based on a minimum time interval

Просмотреть файл

@ -7,7 +7,9 @@ support-files =
doc_markup_dragdrop.html
doc_markup_dragdrop_autoscroll.html
doc_markup_edit.html
doc_markup_events.html
doc_markup_events1.html
doc_markup_events2.html
doc_markup_events3.html
doc_markup_events_form.html
doc_markup_events_jquery.html
doc_markup_events-overflow.html
@ -62,7 +64,9 @@ skip-if = e10s # scratchpad.xul is not loading in e10s window
[browser_markup_dragdrop_invalidNodes.js]
[browser_markup_dragdrop_reorder.js]
[browser_markup_dragdrop_tooltip.js]
[browser_markup_events.js]
[browser_markup_events1.js]
[browser_markup_events2.js]
[browser_markup_events3.js]
[browser_markup_events_form.js]
[browser_markup_events_jquery_1.0.js]
[browser_markup_events_jquery_1.1.js]

Просмотреть файл

@ -8,7 +8,7 @@
// Test that markup view event bubbles show the correct event info for DOM
// events.
const TEST_URL = URL_ROOT + "doc_markup_events.html";
const TEST_URL = URL_ROOT + "doc_markup_events1.html";
loadHelperScript("helper_events_test_runner.js");
@ -32,7 +32,7 @@ const TEST_DATA = [ // eslint-disable-line
expected: [
{
type: "mouseover",
filename: TEST_URL + ":62",
filename: TEST_URL + ":45",
attributes: [
"Capturing",
"DOM2"
@ -51,7 +51,7 @@ const TEST_DATA = [ // eslint-disable-line
expected: [
{
type: "click",
filename: TEST_URL + ":69",
filename: TEST_URL + ":52",
attributes: [
"Bubbling",
"DOM2"
@ -63,7 +63,7 @@ const TEST_DATA = [ // eslint-disable-line
},
{
type: "mouseup",
filename: TEST_URL + ":78",
filename: TEST_URL + ":57",
attributes: [
"Bubbling",
"DOM2"
@ -75,84 +75,6 @@ const TEST_DATA = [ // eslint-disable-line
}
]
},
{
selector: "#DOM0",
expected: [
{
type: "click",
filename: TEST_URL,
attributes: [
"Bubbling",
"DOM0"
],
handler: "alert('hi')"
}
]
},
{
selector: "#handleevent",
expected: [
{
type: "click",
filename: TEST_URL + ":89",
attributes: [
"Bubbling",
"DOM2"
],
handler: "handleEvent: function(blah) {\n" +
" alert(\"handleEvent clicked\");\n" +
"}"
}
]
},
{
selector: "#fatarrow",
expected: [
{
type: "click",
filename: TEST_URL + ":57",
attributes: [
"Bubbling",
"DOM2"
],
handler: "event => {\n" +
" alert(\"Yay for the fat arrow!\");\n" +
"}"
}
]
},
{
selector: "#boundhe",
expected: [
{
type: "click",
filename: TEST_URL + ":101",
attributes: [
"Bubbling",
"DOM2"
],
handler: "handleEvent: function() {\n" +
" alert(\"boundHandleEvent clicked\");\n" +
"}"
}
]
},
{
selector: "#bound",
expected: [
{
type: "click",
filename: TEST_URL + ":74",
attributes: [
"Bubbling",
"DOM2"
],
handler: "function boundClickHandler(event) {\n" +
" alert(\"Bound event clicked\");\n" +
"}"
}
]
},
// #noevents tests check that dynamically added events are properly displayed
// in the markupview
{
@ -169,7 +91,7 @@ const TEST_DATA = [ // eslint-disable-line
expected: [
{
type: "click",
filename: TEST_URL + ":106",
filename: TEST_URL + ":72",
attributes: [
"Bubbling",
"DOM2"
@ -190,6 +112,36 @@ const TEST_DATA = [ // eslint-disable-line
},
expected: []
},
{
selector: "#DOM0",
expected: [
{
type: "click",
filename: TEST_URL,
attributes: [
"Bubbling",
"DOM0"
],
handler: "alert('DOM0')"
}
]
},
{
selector: "#handleevent",
expected: [
{
type: "click",
filename: TEST_URL + ":67",
attributes: [
"Bubbling",
"DOM2"
],
handler: "handleEvent: function(blah) {\n" +
" alert(\"handleEvent\");\n" +
"}"
}
]
}
];
add_task(function* () {

Просмотреть файл

@ -0,0 +1,163 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* import-globals-from helper_events_test_runner.js */
"use strict";
// Test that markup view event bubbles show the correct event info for DOM
// events.
const TEST_URL = URL_ROOT + "doc_markup_events2.html";
loadHelperScript("helper_events_test_runner.js");
const TEST_DATA = [ // eslint-disable-line
{
selector: "#fatarrow",
expected: [
{
type: "click",
filename: TEST_URL + ":39",
attributes: [
"Bubbling",
"DOM2"
],
handler: "() => {\n" +
" alert(\"Fat arrow without params!\");\n" +
"}"
},
{
type: "click",
filename: TEST_URL + ":43",
attributes: [
"Bubbling",
"DOM2"
],
handler: "event => {\n" +
" alert(\"Fat arrow with 1 param!\");\n" +
"}"
},
{
type: "click",
filename: TEST_URL + ":47",
attributes: [
"Bubbling",
"DOM2"
],
handler: "(event, foo, bar) => {\n" +
" alert(\"Fat arrow with 3 params!\");\n" +
"}"
},
{
type: "click",
filename: TEST_URL + ":51",
attributes: [
"Bubbling",
"DOM2"
],
handler: "b => b"
}
]
},
{
selector: "#bound",
expected: [
{
type: "click",
filename: TEST_URL + ":62",
attributes: [
"Bubbling",
"DOM2"
],
handler: "function boundClickHandler(event) {\n" +
" alert(\"Bound event\");\n" +
"}"
}
]
},
{
selector: "#boundhe",
expected: [
{
type: "click",
filename: TEST_URL + ":85",
attributes: [
"Bubbling",
"DOM2"
],
handler: "handleEvent: function() {\n" +
" alert(\"boundHandleEvent\");\n" +
"}"
}
]
},
{
selector: "#comment-inline",
expected: [
{
type: "click",
filename: TEST_URL + ":91",
attributes: [
"Bubbling",
"DOM2"
],
handler: "function functionProceededByInlineComment() {\n" +
" alert(\"comment-inline\");\n" +
"}"
}
]
},
{
selector: "#comment-streaming",
expected: [
{
type: "click",
filename: TEST_URL + ":96",
attributes: [
"Bubbling",
"DOM2"
],
handler: "function functionProceededByStreamingComment() {\n" +
" alert(\"comment-streaming\");\n" +
"}"
}
]
},
{
selector: "#anon-object-method",
expected: [
{
type: "click",
filename: TEST_URL + ":71",
attributes: [
"Bubbling",
"DOM2"
],
handler: "anonObjectMethod: function() {\n" +
" alert(\"obj.anonObjectMethod\");\n" +
"}"
}
]
},
{
selector: "#object-method",
expected: [
{
type: "click",
filename: TEST_URL + ":75",
attributes: [
"Bubbling",
"DOM2"
],
handler: "objectMethod: function kay() {\n" +
" alert(\"obj.objectMethod\");\n" +
"}"
}
]
}
];
add_task(function* () {
yield runEventPopupTests(TEST_URL, TEST_DATA);
});

Просмотреть файл

@ -0,0 +1,161 @@
/* vim: set ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/* import-globals-from helper_events_test_runner.js */
"use strict";
// Test that markup view event bubbles show the correct event info for DOM
// events.
const TEST_URL = URL_ROOT + "doc_markup_events3.html";
loadHelperScript("helper_events_test_runner.js");
const TEST_DATA = [ // eslint-disable-line
{
selector: "#es6-method",
expected: [
{
type: "click",
filename: TEST_URL + ":91",
attributes: [
"Bubbling",
"DOM2"
],
handler: "es6Method() {\n" +
" alert(\"obj.es6Method\");\n" +
"}"
}
]
},
{
selector: "#generator",
expected: [
{
type: "click",
filename: TEST_URL + ":96",
attributes: [
"Bubbling",
"DOM2"
],
handler: "function* generator() {\n" +
" alert(\"generator\");\n" +
"}"
}
]
},
{
selector: "#anon-generator",
expected: [
{
type: "click",
filename: TEST_URL + ":55",
attributes: [
"Bubbling",
"DOM2"
],
handler: "function*() {\n" +
" alert(\"anonGenerator\");\n" +
"}"
}
]
},
{
selector: "#named-function-expression",
expected: [
{
type: "click",
filename: TEST_URL + ":23",
attributes: [
"Bubbling",
"DOM2"
],
handler: "let namedFunctionExpression =\n" +
" function foo() {\n" +
" alert(\"namedFunctionExpression\");\n" +
" }"
}
]
},
{
selector: "#anon-function-expression",
expected: [
{
type: "click",
filename: TEST_URL + ":27",
attributes: [
"Bubbling",
"DOM2"
],
handler: "let anonFunctionExpression = function() {\n" +
" alert(\"anonFunctionExpression\");\n" +
"}"
}
]
},
{
selector: "#returned-function",
expected: [
{
type: "click",
filename: TEST_URL + ":32",
attributes: [
"Bubbling",
"DOM2"
],
handler: "function bar() {\n" +
" alert(\"returnedFunction\");\n" +
"}"
}
]
},
{
selector: "#constructed-function",
expected: [
{
type: "click",
filename: TEST_URL + ":1",
attributes: [
"Bubbling",
"DOM2"
],
handler: ""
}
]
},
{
selector: "#constructed-function-with-body-string",
expected: [
{
type: "click",
filename: TEST_URL + ":1",
attributes: [
"Bubbling",
"DOM2"
],
handler: "alert(\"constructedFuncWithBodyString\");"
}
]
},
{
selector: "#multiple-assignment",
expected: [
{
type: "click",
filename: TEST_URL + ":42",
attributes: [
"Bubbling",
"DOM2"
],
handler: "let multipleAssignment = foo = bar = function multi() {\n" +
" alert(\"multipleAssignment\");\n" +
"}"
}
]
},
];
add_task(function* () {
yield runEventPopupTests(TEST_URL, TEST_DATA);
});

Просмотреть файл

@ -23,8 +23,7 @@ const TEST_DATA = [
attributes: [
"jQuery"
],
handler: "// Handle when the DOM is ready\n" +
"ready: function() {\n" +
handler: "ready: function() {\n" +
" // Make sure that the DOM is not already loaded\n" +
" if (!jQuery.isReady) {\n" +
" // Remember that the DOM is ready\n" +

Просмотреть файл

@ -23,8 +23,7 @@ const TEST_DATA = [
attributes: [
"jQuery"
],
handler: "// Handle when the DOM is ready\n" +
"ready: function() {\n" +
handler: "ready: function() {\n" +
" // Make sure that the DOM is not already loaded\n" +
" if (!jQuery.isReady) {\n" +
" // Remember that the DOM is ready\n" +

Просмотреть файл

@ -19,15 +19,6 @@
#noevents,
#DOM0,
#handleevent,
#fatarrow,
#bound,
#boundhe {
border: 1px solid #000;
width: 200px;
min-height: 1em;
cursor: pointer;
}
#output,
#noevents {
cursor: auto;
@ -41,22 +32,14 @@
function init() {
let container = document.getElementById("container");
let multiple = document.getElementById("multiple");
let fatarrow = document.getElementById("fatarrow");
container.addEventListener("mouseover", mouseoverHandler, true);
multiple.addEventListener("click", clickHandler, false);
multiple.addEventListener("mouseup", mouseupHandler, false);
new handleEventClick();
new boundHandleEventClick();
let bound = document.getElementById("bound");
boundClickHandler = boundClickHandler.bind(this);
bound.addEventListener("click", boundClickHandler);
fatarrow.addEventListener("click", event => {
alert("Yay for the fat arrow!");
});
let he = new handleEventClick();
let handleevent = document.getElementById("handleevent");
handleevent.addEventListener("click", he);
}
function mouseoverHandler(event) {
@ -71,54 +54,38 @@
output.textContent = "click";
}
function boundClickHandler(event) {
alert("Bound event clicked");
}
function mouseupHandler(event) {
let output = document.getElementById("output");
output.textContent = "mouseup";
}
function handleEventClick(hehe) {
let handleevent = document.getElementById("handleevent");
handleevent.addEventListener("click", this);
}
handleEventClick.prototype = {
handleEvent: function(blah) {
alert("handleEvent clicked");
}
};
function boundHandleEventClick() {
let boundhe = document.getElementById("boundhe");
this.handleEvent = this.handleEvent.bind(this);
boundhe.addEventListener("click", this);
}
boundHandleEventClick.prototype = {
handleEvent: function() {
alert("boundHandleEvent clicked");
alert("handleEvent");
}
};
function noeventsClickHandler(event) {
alert("noevents has an event listener");
};
}
function addNoeventsClickHandler() {
let noevents = document.getElementById("noevents");
noevents.addEventListener("click", noeventsClickHandler);
};
}
function removeNoeventsClickHandler() {
let noevents = document.getElementById("noevents");
noevents.removeEventListener("click", noeventsClickHandler);
};
}
</script>
</head>
<body onload="init();">
<h1>Events test 1</h1>
<div id="container">
<div>1</div>
<div>2</div>
@ -139,11 +106,8 @@
<div id="multiple">multiple</div>
</div>
<div id="output"></div>
<div id="noevents">No events here</div>
<div id="DOM0" onclick="alert('hi')">DOM0 event here</div>
<div id="handleevent">handleEvent event here</div>
<div id="fatarrow">Fat arrow event</div>
<div id="boundhe">Bound handleEvent</div>
<div id="bound">Bound event</div>
<div id="noevents">noevents</div>
<div id="DOM0" onclick="alert('DOM0')">DOM0 event here</div>
<div id="handleevent">handleEvent</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,111 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
#fatarrow,
#bound,
#boundhe,
#comment-inline,
#comment-streaming,
#anon-object-method,
#object-method {
border: 1px solid #000;
width: 200px;
min-height: 1em;
cursor: pointer;
}
</style>
<script type="application/javascript;version=1.8">
function init() {
let fatarrow = document.getElementById("fatarrow");
let he = new handleEventClick();
let anonObjectMethod = document.getElementById("anon-object-method");
anonObjectMethod.addEventListener("click", he.anonObjectMethod);
let objectMethod = document.getElementById("object-method");
objectMethod.addEventListener("click", he.objectMethod);
let bhe = new boundHandleEventClick();
let boundheNode = document.getElementById("boundhe");
bhe.handleEvent = bhe.handleEvent.bind(bhe);
boundheNode.addEventListener("click", bhe);
let boundNode = document.getElementById("bound");
boundClickHandler = boundClickHandler.bind(this);
boundNode.addEventListener("click", boundClickHandler);
fatarrow.addEventListener("click", () => {
alert("Fat arrow without params!");
});
fatarrow.addEventListener("click", event => {
alert("Fat arrow with 1 param!");
});
fatarrow.addEventListener("click", (event, foo, bar) => {
alert("Fat arrow with 3 params!");
});
fatarrow.addEventListener("click", b => b);
let inlineCommentNode = document.getElementById("comment-inline");
inlineCommentNode
.addEventListener("click", functionProceededByInlineComment);
let streamingCommentNode = document.getElementById("comment-streaming");
streamingCommentNode
.addEventListener("click", functionProceededByStreamingComment);
}
function boundClickHandler(event) {
alert("Bound event");
}
function handleEventClick(hehe) {
}
handleEventClick.prototype = {
anonObjectMethod: function() {
alert("obj.anonObjectMethod");
},
objectMethod: function kay() {
alert("obj.objectMethod");
},
};
function boundHandleEventClick() {
}
boundHandleEventClick.prototype = {
handleEvent: function() {
alert("boundHandleEvent");
}
};
// A function proceeded with an inline comment
function functionProceededByInlineComment() {
alert("comment-inline");
}
/* A function proceeded with a streaming comment */
function functionProceededByStreamingComment() {
alert("comment-streaming");
}
</script>
</head>
<body onload="init();">
<h1>Events test 2</h1>
<div id="fatarrow">Fat arrows</div>
<div id="boundhe">Bound handleEvent</div>
<div id="bound">Bound event</div>
<div id="comment-inline">Event proceeded by an inline comment</div>
<div id="comment-streaming">Event proceeded by a streaming comment</div>
<div id="anon-object-method">Anonymous object method</div>
<div id="object-method">Object method</div>
</body>
</html>

Просмотреть файл

@ -0,0 +1,115 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<style>
#es6-method,
#generator,
#anon-generator,
#named-function-expression,
#anon-function-expression,
#returned-function,
#constructed-function,
#constructed-function-with-body-string,
#multiple-assignment {
border: 1px solid #000;
width: 200px;
min-height: 1em;
cursor: pointer;
}
</style>
<script type="application/javascript;version=1.8">
let namedFunctionExpression =
function foo() {
alert("namedFunctionExpression");
}
let anonFunctionExpression = function() {
alert("anonFunctionExpression");
};
let returnedFunction = (function() {
return function bar() {
alert("returnedFunction");
}
})();
let constructedFunc = new Function();
let constructedFuncWithBodyString =
new Function('a', 'b', 'c', 'alert("constructedFuncWithBodyString");');
let multipleAssignment = foo = bar = function multi() {
alert("multipleAssignment");
}
function init() {
let he = new handleEventClick();
let es6Method = document.getElementById("es6-method");
es6Method.addEventListener("click", he.es6Method);
let generatorNode = document.getElementById("generator");
generatorNode.addEventListener("click", generator);
let anonGenerator = document.getElementById("anon-generator");
anonGenerator.addEventListener("click", function* () {
alert("anonGenerator");
});
let namedFunctionExpressionNode =
document.getElementById("named-function-expression");
namedFunctionExpressionNode.addEventListener("click",
namedFunctionExpression);
let anonFunctionExpressionNode =
document.getElementById("anon-function-expression");
anonFunctionExpressionNode.addEventListener("click",
anonFunctionExpression);
let returnedFunctionNode = document.getElementById("returned-function");
returnedFunctionNode.addEventListener("click", returnedFunction);
let constructedFunctionNode =
document.getElementById("constructed-function");
constructedFunctionNode.addEventListener("click", constructedFunc);
let constructedFunctionWithBodyStringNode =
document.getElementById("constructed-function-with-body-string");
constructedFunctionWithBodyStringNode
.addEventListener("click", constructedFuncWithBodyString);
let multipleAssignmentNode =
document.getElementById("multiple-assignment");
multipleAssignmentNode.addEventListener("click", multipleAssignment);
}
function handleEventClick(hehe) {
}
handleEventClick.prototype = {
es6Method() {
alert("obj.es6Method");
}
};
function* generator() {
alert("generator");
}
</script>
</head>
<body onload="init();">
<h1>Events test 3</h1>
<div id="es6-method">ES6 method</div>
<div id="generator">Generator</div>
<div id="anon-generator">Anonymous Generator</div>
<div id="named-function-expression">Named Function Expression</div>
<div id="anon-function-expression">Anonymous Function Expression</div>
<div id="returned-function">Returned Function</div>
<div id="constructed-function">Constructed Function</div>
<div id="constructed-function-with-body-string">
Constructed Function with body string
</div>
<div id="multiple-assignment">Multiple Assignment</div>
</body>
</html>

Просмотреть файл

@ -32,21 +32,14 @@
#root,
html, body {
margin: 0;
height: 100%;
}
#root {
display: flex;
flex-direction: column;
justify-content: center;
}
#app {
/* Center the viewports container */
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
height: 100vh;
/* Snap to the top of the app when there isn't enough vertical space anymore
to center the viewports (so we don't lose the global toolbar) */
@ -85,7 +78,7 @@ html, body {
color: var(--theme-body-color-alt);
border-radius: 2px;
box-shadow: var(--rdm-box-shadow);
margin: 30px 0;
margin: 10% 0 30px 0;
padding: 4px 5px;
display: inline-flex;
-moz-user-select: none;

Просмотреть файл

@ -594,10 +594,15 @@ InplaceEditor.prototype = {
return "";
}
// A DOM element is used to test the validity of various units. This is to
// avoid having to do an async call to the server to get this information.
let el = this.doc.createElement("div");
let units = ["px", "deg", "s"];
for (let unit of units) {
let value = beforeValue + "1" + unit + afterValue;
if (domUtils.cssPropertyIsValid(this.property.name, value)) {
el.style.setProperty(this.property.name, "");
el.style.setProperty(this.property.name, value);
if (el.style.getPropertyValue(this.property.name) !== "") {
return unit;
}
}

Просмотреть файл

@ -3,15 +3,16 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that the tree widget api works fine
"use strict";
const TEST_URI = "data:text/html;charset=utf-8,<head>" +
"<link rel='stylesheet' type='text/css' href='chrome://devtools/skin/widg" +
"ets.css'></head><body><div></div><span></span></body>";
const {TreeWidget} = require("devtools/client/shared/widgets/TreeWidget");
add_task(function*() {
add_task(function* () {
yield addTab("about:blank");
let [host, win, doc] = yield createHost("bottom", TEST_URI);
let [host,, doc] = yield createHost("bottom", TEST_URI);
let tree = new TreeWidget(doc.querySelector("div"), {
defaultType: "store"
@ -40,8 +41,14 @@ function populateTree(tree, doc) {
label: "Level 3 - Child 1",
type: "dir"
}]);
tree.add(["level1", "level2-1", { id: "level3-2", label: "Level 3 - Child 2"}]);
tree.add(["level1", "level2-1", { id: "level3-3", label: "Level 3 - Child 3"}]);
tree.add(["level1", "level2-1", {
id: "level3-2",
label: "Level 3 - Child 2"
}]);
tree.add(["level1", "level2-1", {
id: "level3-3",
label: "Level 3 - Child 3"
}]);
tree.add(["level1", {
id: "level2-2",
label: "Level 2.1"
@ -67,7 +74,8 @@ function populateTree(tree, doc) {
* Test if the nodes are inserted correctly in the tree.
*/
function testTreeItemInsertedCorrectly(tree, doc) {
is(tree.root.children.children.length, 2, "Number of top level elements match");
is(tree.root.children.children.length, 2,
"Number of top level elements match");
is(tree.root.children.firstChild.lastChild.children.length, 3,
"Number of first second level elements match");
is(tree.root.children.lastChild.lastChild.children.length, 1,
@ -83,7 +91,8 @@ function testTreeItemInsertedCorrectly(tree, doc) {
is(tree.root.children.firstChild.nextSibling.dataset.id,
JSON.stringify(["level1.1"]),
"Data id of second top level element matches");
is(tree.root.children.firstChild.nextSibling.firstChild.textContent, "level1.1",
is(tree.root.children.firstChild.nextSibling.firstChild.textContent,
"level1.1",
"Text content of second top level element matches");
// Adding a new non text item in the tree.
@ -116,7 +125,7 @@ function testTreeItemInsertedCorrectly(tree, doc) {
function populateUnsortedTree(tree, doc) {
tree.sorted = false;
tree.add([{ id: "g-1", label: "g-1"}])
tree.add([{ id: "g-1", label: "g-1"}]);
tree.add(["g-1", { id: "d-2", label: "d-2.1"}]);
tree.add(["g-1", { id: "b-2", label: "b-2.2"}]);
tree.add(["g-1", { id: "a-2", label: "a-2.3"}]);
@ -189,7 +198,7 @@ function testAPI(tree, doc) {
// test if clear selection works
tree.clearSelection();
ok(!doc.querySelector(".theme-selected"),
"Nothing selected after clear selection call")
"Nothing selected after clear selection call");
// test if collapseAll/expandAll work
ok(doc.querySelectorAll("[expanded]").length > 0,
@ -232,6 +241,11 @@ function testAPI(tree, doc) {
ok(!doc.querySelector("[data-id='" +
JSON.stringify(["level1", "level2", "level3"]) + "']"),
"level1-level2-level3 item does not exist after removing");
let level2item = doc.querySelector("[data-id='" +
JSON.stringify(["level1", "level2"]) + "'] > .tree-widget-item");
ok(level2item.hasAttribute("empty"),
"level1-level2 item is marked as empty after removing");
tree.add([{
id: "level1",
label: "Level 1"

Просмотреть файл

@ -538,6 +538,9 @@ TreeItem.prototype = {
if (!items.length) {
this.items.delete(id);
}
if (this.items.size == 0) {
this.label.setAttribute("empty", "true");
}
deleted.remove(items);
} else if (!id) {
this.destroy();

Просмотреть файл

@ -26,6 +26,7 @@
<menupopup id="storage-tree-popup">
<menuitem id="storage-tree-popup-delete-all"
label="&storage.popupMenu.deleteAllLabel;"/>
<menuitem id="storage-tree-popup-delete-database"/>
</menupopup>
<menupopup id="storage-table-popup">
<menuitem id="storage-table-popup-delete"/>

Просмотреть файл

@ -29,6 +29,7 @@ support-files =
[browser_storage_delete_tree.js]
[browser_storage_dynamic_updates.js]
[browser_storage_empty_objectstores.js]
[browser_storage_indexeddb_delete.js]
[browser_storage_localstorage_edit.js]
[browser_storage_overflow.js]
[browser_storage_search.js]

Просмотреть файл

@ -0,0 +1,48 @@
/* 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/. */
/* import-globals-from ../../framework/test/shared-head.js */
"use strict";
// Test deleting indexedDB database from the tree using context menu
add_task(function* () {
yield openTabAndSetupStorage(MAIN_DOMAIN + "storage-empty-objectstores.html");
let contextMenu = gPanelWindow.document.getElementById("storage-tree-popup");
let menuDeleteDb = contextMenu.querySelector(
"#storage-tree-popup-delete-database");
info("test state before delete");
yield checkState([
[["indexedDB", "http://test1.example.org"], ["idb1", "idb2"]],
]);
info("do the delete");
const deletedDb = ["indexedDB", "http://test1.example.org", "idb1"];
yield selectTreeItem(deletedDb);
// Wait once for update and another time for value fetching
let eventWait = gUI.once("store-objects-updated").then(
() => gUI.once("store-objects-updated"));
let selector = `[data-id='${JSON.stringify(deletedDb)}'] > .tree-widget-item`;
let target = gPanelWindow.document.querySelector(selector);
ok(target, `tree item found in ${deletedDb.join(" > ")}`);
yield waitForContextMenu(contextMenu, target, () => {
info(`Opened tree context menu in ${deletedDb.join(" > ")}`);
menuDeleteDb.click();
});
yield eventWait;
info("test state after delete");
yield checkState([
[["indexedDB", "http://test1.example.org"], ["idb2"]],
]);
yield finishTests();
});

Просмотреть файл

@ -51,6 +51,14 @@ const REASON = {
// trimmed with ellipsis if it's longer.
const ITEM_NAME_MAX_LENGTH = 32;
function addEllipsis(name) {
if (name.length > ITEM_NAME_MAX_LENGTH) {
return name.substr(0, ITEM_NAME_MAX_LENGTH) + L10N.ellipsis;
}
return name;
}
/**
* StorageUI is controls and builds the UI of the Storage Inspector.
*
@ -125,6 +133,7 @@ var StorageUI = this.StorageUI = function StorageUI(front, target, panelWin) {
this.onRemoveItem = this.onRemoveItem.bind(this);
this.onRemoveAllFrom = this.onRemoveAllFrom.bind(this);
this.onRemoveAll = this.onRemoveAll.bind(this);
this.onRemoveDatabase = this.onRemoveDatabase.bind(this);
this._tablePopupDelete = this._panelDoc.getElementById(
"storage-table-popup-delete");
@ -142,6 +151,11 @@ var StorageUI = this.StorageUI = function StorageUI(front, target, panelWin) {
this._treePopupDeleteAll = this._panelDoc.getElementById(
"storage-tree-popup-delete-all");
this._treePopupDeleteAll.addEventListener("command", this.onRemoveAll);
this._treePopupDeleteDatabase = this._panelDoc.getElementById(
"storage-tree-popup-delete-database");
this._treePopupDeleteDatabase.addEventListener("command",
this.onRemoveDatabase);
};
exports.StorageUI = StorageUI;
@ -169,14 +183,19 @@ StorageUI.prototype = {
this._treePopup.removeEventListener("popupshowing",
this.onTreePopupShowing);
this._treePopupDeleteAll.removeEventListener("command", this.onRemoveAll);
this._treePopupDeleteAll.removeEventListener("command",
this.onRemoveAll);
this._treePopupDeleteDatabase.removeEventListener("command",
this.onRemoveDatabase);
this._tablePopup.removeEventListener("popupshowing",
this.onTablePopupShowing);
this._tablePopupDelete.removeEventListener("command", this.onRemoveItem);
this._tablePopupDelete.removeEventListener("command",
this.onRemoveItem);
this._tablePopupDeleteAllFrom.removeEventListener("command",
this.onRemoveAllFrom);
this._tablePopupDeleteAll.removeEventListener("command", this.onRemoveAll);
this._tablePopupDeleteAll.removeEventListener("command",
this.onRemoveAll);
},
/**
@ -338,24 +357,33 @@ StorageUI.prototype = {
}
this.tree.remove([type, host]);
} else if (this.tree.isSelected([type, host])) {
} else {
for (let name of deleted[type][host]) {
try {
// trying to parse names in case its for indexedDB
// trying to parse names in case of indexedDB or cache
let names = JSON.parse(name);
if (!this.tree.isSelected([type, host, names[0], names[1]])) {
return;
// Is a whole cache, database or objectstore deleted?
// Then remove it from the tree.
if (names.length < 3) {
if (this.tree.isSelected([type, host, ...names])) {
this.table.clear();
this.hideSidebar();
this.tree.selectPreviousItem();
}
this.tree.remove([type, host, ...names]);
}
if (!names[2]) {
this.tree.selectPreviousItem();
this.tree.remove([type, host, names[0], names[1]]);
this.table.clear();
this.hideSidebar();
} else {
this.removeItemFromTable(names[2]);
// Remove the item from table if currently displayed.
if (names.length > 0) {
let tableItemName = names.pop();
if (this.tree.isSelected([type, host, ...names])) {
this.removeItemFromTable(tableItemName);
}
}
} catch (ex) {
this.removeItemFromTable(name);
if (this.tree.isSelected([type, host])) {
this.removeItemFromTable(name);
}
}
}
}
@ -793,24 +821,16 @@ StorageUI.prototype = {
return;
}
const maxLen = ITEM_NAME_MAX_LENGTH;
let [type] = this.tree.selectedItem;
let rowId = this.table.contextMenuRowId;
let data = this.table.items.get(rowId);
let name = data[this.table.uniqueId];
if (name.length > maxLen) {
name = name.substr(0, maxLen) + L10N.ellipsis;
}
let name = addEllipsis(data[this.table.uniqueId]);
this._tablePopupDelete.setAttribute("label",
L10N.getFormatStr("storage.popupMenu.deleteLabel", name));
if (type === "cookies") {
let host = data.host;
if (host.length > maxLen) {
host = host.substr(0, maxLen) + L10N.ellipsis;
}
let host = addEllipsis(data.host);
this._tablePopupDeleteAllFrom.hidden = false;
this._tablePopupDeleteAllFrom.setAttribute("label",
@ -823,13 +843,23 @@ StorageUI.prototype = {
onTreePopupShowing: function(event) {
let showMenu = false;
let selectedItem = this.tree.selectedItem;
// Never show menu on the 1st level item
if (selectedItem && selectedItem.length > 1) {
if (selectedItem) {
// this.currentActor() would return wrong value here
let actor = this.storageTypes[selectedItem[0]];
if (actor.removeAll) {
showMenu = true;
let showDeleteAll = selectedItem.length == 2 && actor.removeAll;
this._treePopupDeleteAll.hidden = !showDeleteAll;
let showDeleteDb = selectedItem.length == 3 && actor.removeDatabase;
this._treePopupDeleteDatabase.hidden = !showDeleteDb;
if (showDeleteDb) {
let dbName = addEllipsis(selectedItem[2]);
this._treePopupDeleteDatabase.setAttribute("label",
L10N.getFormatStr("storage.popupMenu.deleteLabel", dbName));
}
showMenu = showDeleteAll || showDeleteDb;
}
if (!showMenu) {
@ -874,4 +904,11 @@ StorageUI.prototype = {
actor.removeAll(host, data.host);
},
onRemoveDatabase: function() {
let [type, host, name] = this.tree.selectedItem;
let actor = this.storageTypes[type];
actor.removeDatabase(host, name);
}
};

Просмотреть файл

@ -47,8 +47,7 @@
--timeline-animation-height: 20px;
/* The size of a keyframe marker in the keyframes diagram */
--keyframes-marker-size: 10px;
/* The color of the time graduation borders. This should match the the color
devtools/client/animationinspector/utils.js */
/* The color of the time graduation borders */
--time-graduation-border-color: rgba(128, 136, 144, .5);
}
@ -227,17 +226,6 @@ body {
height: 100%;
overflow: hidden;
position: relative;
/* The timeline gets its background-image from a canvas element created in
/devtools/client/animationinspector/utils.js drawGraphElementBackground
thanks to document.mozSetImageElement("time-graduations", canvas)
This is done so that the background can be built dynamically from script */
background-image: -moz-element(#time-graduations);
background-repeat: repeat-y;
/* Make the background be 100% of the timeline area so that it resizes with
it and subtract the width of the sidebar and the buffer at the right of the
timeline */
background-size: calc(100% - var(--timeline-sidebar-width) - var(--keyframes-marker-size)) 100%;
background-position: var(--timeline-sidebar-width) 0;
display: flex;
flex-direction: column;
}
@ -299,7 +287,10 @@ body {
.animation-timeline .time-header .time-tick {
position: absolute;
top: 3px;
top: 0;
height: 100vh;
padding-top: 3px;
border-left: 0.5px solid var(--time-graduation-border-color);
}
.animation-timeline .animations {

Просмотреть файл

@ -244,3 +244,8 @@
.theme-firebug .devtools-toolbarbutton {
min-width: 24px;
}
/* Move the Inspector button a bit down (looks better) */
.theme-firebug #command-button-pick > image {
margin-bottom: -4px;
}

Просмотреть файл

@ -259,6 +259,26 @@ ul.children + .tag-line::before {
z-index: 1;
}
/* Firebug Theme */
.theme-firebug .theme-fg-color3 {
color: var(--theme-graphs-full-blue);
}
.theme-firebug .open,
.theme-firebug .close,
.theme-firebug .attr-name.theme-fg-color2 {
color: var(--theme-highlight-purple);
}
.theme-firebug .attr-value.theme-fg-color6 {
color: var(--theme-highlight-red);
}
.theme-firebug .markupview-events {
font-size: var(--theme-toolbar-font-size);
}
/* Selected nodes in the tree should have light selected text.
theme-selected doesn't work in this case since the text is a
sibling of the class, not a child. */
@ -273,6 +293,12 @@ ul.children + .tag-line::before {
color: var(--theme-selection-color);
}
/* Make sure even text nodes are white when selected in the Inspector panel. */
.theme-firebug .theme-selected ~ .editor .open,
.theme-firebug .theme-selected ~ .editor .close {
color: var(--theme-selection-color);
}
/* In case a node isn't displayed in the page, we fade the syntax highlighting */
.not-displayed .open,
.not-displayed .close {
@ -294,23 +320,3 @@ ul.children + .tag-line::before {
background-color: var(--theme-body-color-alt);
color: var(--theme-body-background);
}
/* Firebug Theme */
.theme-firebug .theme-fg-color3 {
color: var(--theme-graphs-full-blue);
}
.theme-firebug .open,
.theme-firebug .close,
.theme-firebug .attr-name.theme-fg-color2 {
color: var(--theme-highlight-purple);
}
.theme-firebug .attr-value.theme-fg-color6 {
color: var(--theme-highlight-red);
}
.theme-firebug .markupview-events {
font-size: var(--theme-toolbar-font-size);
}

Просмотреть файл

@ -529,6 +529,12 @@ html, body, #app, #memory-tool {
padding: 0;
}
/* Override Firebug styles for toolbar buttons to fix entire row height. */
.theme-firebug .heap-tree-item-individuals > button {
margin: 0 auto;
min-height: inherit;
}
/**
* Tree map
*/

Просмотреть файл

@ -6,9 +6,9 @@
"use strict";
const {Cc, Ci, Cu} = require("chrome");
const {Ci, Cu} = require("chrome");
const {Utils: WebConsoleUtils, CONSOLE_WORKER_IDS} =
const {Utils: WebConsoleUtils} =
require("devtools/shared/webconsole/utils");
const promise = require("promise");
const Debugger = require("Debugger");
@ -315,7 +315,7 @@ JSTerm.prototype = {
errorMessage += " ";
errorDocLink = this.hud.document.createElementNS(XHTML_NS, "a");
errorDocLink.className = "learn-more-link webconsole-learn-more-link";
errorDocLink.textContent = "[" + l10n.getStr("webConsoleMoreInfoLabel") + "]";
errorDocLink.textContent = `[${l10n.getStr("webConsoleMoreInfoLabel")}]`;
errorDocLink.title = errorDocURL;
errorDocLink.href = "#";
errorDocLink.draggable = false;
@ -326,7 +326,7 @@ JSTerm.prototype = {
// Wrap thrown strings in Error objects, so `throw "foo"` outputs
// "Error: foo"
if (typeof(response.exception) === "string") {
if (typeof response.exception === "string") {
errorMessage = new Error(errorMessage).toString();
}
let result = response.result;
@ -372,7 +372,8 @@ JSTerm.prototype = {
return;
}
let msg = new Messages.JavaScriptEvalOutput(response, errorMessage, errorDocLink);
let msg = new Messages.JavaScriptEvalOutput(response,
errorMessage, errorDocLink);
this.hud.output.addMessage(msg);
if (callback) {
@ -424,7 +425,7 @@ JSTerm.prototype = {
// attempt to execute the content of the inputNode
executeString = executeString || this.getInputValue();
if (!executeString) {
return;
return null;
}
let selectedNodeActor = null;
@ -1022,6 +1023,7 @@ JSTerm.prototype = {
}
},
/* eslint-disable complexity */
/**
* The inputNode "keypress" event handler.
*
@ -1213,7 +1215,7 @@ JSTerm.prototype = {
}
break;
case Ci.nsIDOMKeyEvent.DOM_VK_RIGHT: {
case Ci.nsIDOMKeyEvent.DOM_VK_RIGHT:
let cursorAtTheEnd = this.inputNode.selectionStart ==
this.inputNode.selectionEnd &&
this.inputNode.selectionStart ==
@ -1231,7 +1233,7 @@ JSTerm.prototype = {
this.clearCompletion();
}
break;
}
case Ci.nsIDOMKeyEvent.DOM_VK_TAB:
// Generate a completion and accept the first proposed value.
if (this.complete(this.COMPLETE_HINT_ONLY) &&
@ -1247,6 +1249,7 @@ JSTerm.prototype = {
break;
}
},
/* eslint-enable complexity */
/**
* The inputNode "focus" event handler.

Просмотреть файл

@ -200,11 +200,7 @@ BrowserAddonActor.prototype = {
} catch (e) {}
if (global instanceof Ci.nsIDOMWindow) {
let id = {};
if (mapURIToAddonID(global.document.documentURIObject, id)) {
return id.value === this.id;
}
return false;
return mapURIToAddonID(global.document.documentURIObject) == this.id;
}
// Check the global for a __URI__ property and then try to map that to an
@ -223,9 +219,8 @@ BrowserAddonActor.prototype = {
return false;
}
let id = {};
if (mapURIToAddonID(uri, id)) {
return id.value === this.id;
if (mapURIToAddonID(uri) == this.id) {
return true;
}
}

Просмотреть файл

@ -87,8 +87,10 @@ const FONT_FAMILY_PREVIEW_TEXT_SIZE = 20;
const PSEUDO_CLASSES = [":hover", ":active", ":focus"];
const HIDDEN_CLASS = "__fx-devtools-hide-shortcut__";
const XHTML_NS = "http://www.w3.org/1999/xhtml";
const XUL_NS = 'http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul';
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
const IMAGE_FETCHING_TIMEOUT = 500;
const RX_FUNC_NAME = /((var|const|let)\s+)?([\w$.]+\s*[:=]\s*)*(function)?\s*\*?\s*([\w$]+)?\s*$/;
// The possible completions to a ':' with added score to give certain values
// some preference.
const PSEUDO_SELECTORS = [
@ -553,28 +555,22 @@ var NodeActor = exports.NodeActor = protocol.ActorClass({
/*
The script returned is the whole script and
scriptSource.substr(script.sourceStart, script.sourceLength) returns
something like:
something like this:
() { doSomething(); }
So we need to work back to the preceeding \n, ; or } so we can get the
appropriate function info e.g.:
() => { doSomething(); }
function doit() { doSomething(); }
doit: function() { doSomething(); }
So we need to use some regex magic to get the appropriate function info
e.g.:
() => { ... }
function doit() { ... }
doit: function() { ... }
es6func() { ... }
var|let|const foo = function () { ... }
function generator*() { ... }
*/
let scriptBeforeFunc = scriptSource.substr(0, script.sourceStart);
let lastEnding = Math.max(
scriptBeforeFunc.lastIndexOf(";"),
scriptBeforeFunc.lastIndexOf("}"),
scriptBeforeFunc.lastIndexOf("{"),
scriptBeforeFunc.lastIndexOf("("),
scriptBeforeFunc.lastIndexOf(","),
scriptBeforeFunc.lastIndexOf("!")
);
if (lastEnding !== -1) {
let functionPrefix = scriptBeforeFunc.substr(lastEnding + 1);
functionSource = functionPrefix + functionSource;
let matches = scriptBeforeFunc.match(RX_FUNC_NAME);
if (matches && matches.length > 0) {
functionSource = matches[0].trim() + functionSource;
}
let dom0 = false;

Просмотреть файл

@ -34,7 +34,6 @@ loader.lazyGetter(this, "Debugger", () => {
});
loader.lazyRequireGetter(this, "CssLogic", "devtools/shared/inspector/css-logic", true);
loader.lazyRequireGetter(this, "events", "sdk/event/core");
loader.lazyRequireGetter(this, "mapURIToAddonID", "devtools/server/actors/utils/map-uri-to-addon-id");
loader.lazyRequireGetter(this, "setTimeout", "sdk/timers", true);
/**

Просмотреть файл

@ -238,39 +238,43 @@ let SourceActor = ActorClass({
}
let localURI = resolveURIToLocalPath(nsuri);
if (!localURI) {
return;
}
let id = {};
if (localURI && mapURIToAddonID(localURI, id)) {
this._addonID = id.value;
let id = mapURIToAddonID(localURI);
if (!id) {
return;
}
this._addonID = id;
if (localURI instanceof Ci.nsIJARURI) {
// The path in the add-on is easy for jar: uris
this._addonPath = localURI.JAREntry;
if (localURI instanceof Ci.nsIJARURI) {
// The path in the add-on is easy for jar: uris
this._addonPath = localURI.JAREntry;
}
else if (localURI instanceof Ci.nsIFileURL) {
// For file: uris walk up to find the last directory that is part of the
// add-on
let target = localURI.file;
let path = target.leafName;
// We can assume that the directory containing the source file is part
// of the add-on
let root = target.parent;
let file = root.parent;
while (file && mapURIToAddonID(Services.io.newFileURI(file))) {
path = root.leafName + "/" + path;
root = file;
file = file.parent;
}
else if (localURI instanceof Ci.nsIFileURL) {
// For file: uris walk up to find the last directory that is part of the
// add-on
let target = localURI.file;
let path = target.leafName;
// We can assume that the directory containing the source file is part
// of the add-on
let root = target.parent;
let file = root.parent;
while (file && mapURIToAddonID(Services.io.newFileURI(file), {})) {
path = root.leafName + "/" + path;
root = file;
file = file.parent;
}
if (!file) {
const error = new Error("Could not find the root of the add-on for " + this.url);
DevToolsUtils.reportException("SourceActor.prototype._mapSourceToAddon", error)
return;
}
this._addonPath = path;
if (!file) {
const error = new Error("Could not find the root of the add-on for " + this.url);
DevToolsUtils.reportException("SourceActor.prototype._mapSourceToAddon", error)
return;
}
this._addonPath = path;
}
},

Просмотреть файл

@ -1519,6 +1519,31 @@ StorageActors.createActor({
events.off(this.storageActor, "window-destroyed", this.onWindowDestroyed);
},
/**
* Remove an indexedDB database from given host with a given name.
*/
removeDatabase: method(Task.async(function* (host, name) {
let win = this.storageActor.getWindowFromHost(host);
if (win) {
let principal = win.document.nodePrincipal;
let result = yield this.removeDB(host, principal, name);
if (!result.error) {
if (this.hostVsStores.has(host)) {
this.hostVsStores.get(host).delete(name);
}
this.storageActor.update("deleted", "indexedDB", {
[host]: [ JSON.stringify([name]) ]
});
}
}
}), {
request: {
host: Arg(0, "string"),
name: Arg(1, "string"),
},
response: {}
}),
getHostName: function(location) {
if (!location.host) {
return location.href;
@ -1691,8 +1716,7 @@ StorageActors.createActor({
this.getNameFromDatabaseFile = indexedDBHelpers.getNameFromDatabaseFile;
this.getValuesForHost = indexedDBHelpers.getValuesForHost;
this.getObjectStoreData = indexedDBHelpers.getObjectStoreData;
this.patchMetadataMapsAndProtos =
indexedDBHelpers.patchMetadataMapsAndProtos;
this.removeDB = indexedDBHelpers.removeDB;
return;
}
@ -1710,13 +1734,14 @@ StorageActors.createActor({
callParentProcessAsync.bind(null, "getDBNamesForHost");
this.getValuesForHost =
callParentProcessAsync.bind(null, "getValuesForHost");
this.removeDB =
callParentProcessAsync.bind(null, "removeDB");
addMessageListener("storage:storage-indexedDB-request-child", msg => {
switch (msg.json.method) {
case "backToChild":
let func = msg.json.args.shift();
let deferred = unresolvedPromises.get(func);
if (deferred) {
unresolvedPromises.delete(func);
deferred.resolve(msg.json.args[0]);
@ -1767,14 +1792,12 @@ var indexedDBHelpers = {
let dbData = new DatabaseMetadata(host, db);
db.close();
this.backToChild("getDBMetaData", dbData);
success.resolve(dbData);
success.resolve(this.backToChild("getDBMetaData", dbData));
};
request.onerror = () => {
console.error("Error opening indexeddb database " + name + " for host " +
host);
this.backToChild("getDBMetaData", null);
success.resolve(null);
console.error(
`Error opening indexeddb database ${name} for host ${host}`);
success.resolve(this.backToChild("getDBMetaData", null));
};
return success.promise;
}),
@ -1787,7 +1810,31 @@ var indexedDBHelpers = {
return require("indexedDB").openForPrincipal(principal, name);
},
/**
removeDB: Task.async(function* (host, principal, name) {
let request = require("indexedDB").deleteForPrincipal(principal, name);
let result = new promise(resolve => {
request.onsuccess = () => {
resolve({});
};
request.onblocked = () => {
console.error(
`Deleting indexedDB database ${name} for host ${host} is blocked`);
resolve({ error: "blocked" });
};
request.onerror = () => {
console.error(
`Error deleting indexedDB database ${name} for host ${host}`);
resolve({ error: request.error });
};
});
return this.backToChild("removeDB", yield result);
}),
/**
* Fetches all the databases and their metadata for the given `host`.
*/
getDBNamesForHost: Task.async(function* (host) {
@ -2042,29 +2089,26 @@ var indexedDBHelpers = {
},
handleChildRequest: function(msg) {
let host;
let name;
let args = msg.data.args;
switch (msg.json.method) {
case "getDBMetaData": {
host = args[0];
let principal = args[1];
name = args[2];
let [host, principal, name] = args;
return indexedDBHelpers.getDBMetaData(host, principal, name);
}
case "getDBNamesForHost":
host = args[0];
case "getDBNamesForHost": {
let [host] = args;
return indexedDBHelpers.getDBNamesForHost(host);
}
case "getValuesForHost": {
host = args[0];
name = args[1];
let options = args[2];
let hostVsStores = args[3];
let principal = args[4];
let [host, name, options, hostVsStores, principal] = args;
return indexedDBHelpers.getValuesForHost(host, name, options,
hostVsStores, principal);
}
case "removeDB": {
let [host, principal, name] = args;
return indexedDBHelpers.removeDB(host, principal, name);
}
default:
console.error("ERR_DIRECTOR_PARENT_UNKNOWN_METHOD", msg.json.method);
throw new Error("ERR_DIRECTOR_PARENT_UNKNOWN_METHOD");

Просмотреть файл

@ -8,52 +8,37 @@
const DevToolsUtils = require("devtools/shared/DevToolsUtils");
const Services = require("Services");
const { Cc, Ci } = require("chrome");
Object.defineProperty(this, "addonManager", {
get: (function () {
let cached;
return () => {
if (cached === undefined) {
// catch errors as the addonManager might not exist in this environment
// (eg, xpcshell)
try {
cached = Cc["@mozilla.org/addons/integration;1"]
.getService(Ci.amIAddonManager);
} catch (ex) {
cached = null;
}
}
return cached;
}
}())
});
loader.lazyServiceGetter(this, "AddonPathService",
"@mozilla.org/addon-path-service;1",
"amIAddonPathService");
const B2G_ID = "{3c2e2abc-06d4-11e1-ac3b-374f68613e61}";
const GRAPHENE_ID = "{d1bfe7d9-c01e-4237-998b-7b5f960a4314}";
/**
* This is a wrapper around amIAddonManager.mapURIToAddonID which always returns
* This is a wrapper around amIAddonPathService.mapURIToAddonID which always returns
* false on B2G and graphene to avoid loading the add-on manager there and
* reports any exceptions rather than throwing so that the caller doesn't have
* to worry about them.
*/
module.exports = function mapURIToAddonID(uri, id) {
if (!Services.appinfo
|| Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT
|| Services.appinfo.ID === undefined /* XPCShell */
|| Services.appinfo.ID == B2G_ID
|| Services.appinfo.ID == GRAPHENE_ID
|| !uri
|| !addonManager) {
if (!Services.appinfo
|| Services.appinfo.processType == Services.appinfo.PROCESS_TYPE_CONTENT
|| Services.appinfo.ID === undefined /* XPCShell */
|| Services.appinfo.ID == B2G_ID
|| Services.appinfo.ID == GRAPHENE_ID
|| !AddonPathService) {
module.exports = function mapURIToAddonId(uri) {
return false;
}
try {
return addonManager.mapURIToAddonID(uri, id);
}
catch (e) {
DevToolsUtils.reportException("mapURIToAddonID", e);
return false;
}
};
};
} else {
module.exports = function mapURIToAddonId(uri) {
try {
return AddonPathService.mapURIToAddonId(uri);
}
catch (e) {
DevToolsUtils.reportException("mapURIToAddonId", e);
return false;
}
};
}

Просмотреть файл

@ -153,6 +153,9 @@ class ActionBarTextSelection extends Layer implements TextSelection, GeckoEventL
public void run() {
try {
if (event.equals("TextSelection:ShowHandles")) {
Telemetry.sendUIEvent(TelemetryContract.Event.SHOW,
TelemetryContract.Method.CONTENT, "text_selection");
selectionID = message.getString("selectionID");
final JSONArray handles = message.getJSONArray("handles");
for (int i = 0; i < handles.length(); i++) {

Просмотреть файл

@ -16,6 +16,8 @@ import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.widget.ImageView;
/**
* Special version of ImageView for favicons.
@ -25,6 +27,9 @@ import android.widget.ImageView;
public class FaviconView extends ImageView {
private static String DEFAULT_FAVICON_KEY = FaviconView.class.getSimpleName() + "DefaultFavicon";
// Default x/y-radius of the oval used to round the corners of the background (dp)
private static final int DEFAULT_CORNER_RADIUS_DP = 4;
private Bitmap mIconBitmap;
// Reference to the unscaled bitmap, if any, to prevent repeated assignments of the same bitmap
@ -45,21 +50,15 @@ public class FaviconView extends ImageView {
// Dominant color of the favicon.
private int mDominantColor;
// Stroke width for the border.
private static float sStrokeWidth;
// Paint for drawing the stroke.
private static final Paint sStrokePaint;
// Paint for drawing the background.
private static final Paint sBackgroundPaint;
// Size of the stroke rectangle.
private final RectF mStrokeRect;
// Size of the background rectangle.
private final RectF mBackgroundRect;
// The x/y-radius of the oval used to round the corners of the background (pixels)
private final float mBackgroundCornerRadius;
// Type of the border whose value is defined in attrs.xml .
private final boolean isDominantBorderEnabled;
@ -68,9 +67,6 @@ public class FaviconView extends ImageView {
// Initializing the static paints.
static {
sStrokePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
sStrokePaint.setStyle(Paint.Style.STROKE);
sBackgroundPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
sBackgroundPaint.setStyle(Paint.Style.FILL);
}
@ -90,16 +86,10 @@ public class FaviconView extends ImageView {
setScaleType(ImageView.ScaleType.CENTER);
}
mStrokeRect = new RectF();
mBackgroundRect = new RectF();
final DisplayMetrics metrics = getResources().getDisplayMetrics();
if (sStrokeWidth == 0) {
sStrokeWidth = getResources().getDisplayMetrics().density;
sStrokePaint.setStrokeWidth(sStrokeWidth);
}
mStrokeRect.left = mStrokeRect.top = sStrokeWidth;
mBackgroundRect.left = mBackgroundRect.top = sStrokeWidth * 2.0f;
mBackgroundRect = new RectF(0, 0, 0, 0);
mBackgroundCornerRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, DEFAULT_CORNER_RADIUS_DP, metrics);
}
@Override
@ -114,26 +104,21 @@ public class FaviconView extends ImageView {
mActualWidth = w;
mActualHeight = h;
mStrokeRect.right = w - sStrokeWidth;
mStrokeRect.bottom = h - sStrokeWidth;
mBackgroundRect.right = mStrokeRect.right - sStrokeWidth;
mBackgroundRect.bottom = mStrokeRect.bottom - sStrokeWidth;
mBackgroundRect.right = w;
mBackgroundRect.bottom = h;
formatImage();
}
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (isDominantBorderEnabled) {
// 27.5% transparent dominant color.
sBackgroundPaint.setColor(mDominantColor & 0x46FFFFFF);
canvas.drawRect(mStrokeRect, sBackgroundPaint);
sBackgroundPaint.setColor(mDominantColor & 0x7FFFFFFF);
sStrokePaint.setColor(mDominantColor);
canvas.drawRoundRect(mStrokeRect, sStrokeWidth, sStrokeWidth, sStrokePaint);
canvas.drawRoundRect(mBackgroundRect, mBackgroundCornerRadius, mBackgroundCornerRadius, sBackgroundPaint);
}
super.onDraw(canvas);
}
/**

Просмотреть файл

@ -37,21 +37,9 @@ var AboutReaderListener = {
let url = content.document.location.href;
if (!this.isAboutReader) {
this._articlePromise = ReaderMode.parseDocument(content.document).catch(Cu.reportError);
content.document.location = "about:reader?url=" + encodeURIComponent(url);
ReaderMode.enterReaderMode(docShell, content);
} else {
let originalURL = ReaderMode.getOriginalUrl(url);
let webNav = docShell.QueryInterface(Ci.nsIWebNavigation);
let sh = webNav.sessionHistory;
if (webNav.canGoBack) {
let prevEntry = sh.getEntryAtIndex(sh.index - 1, false);
let prevURL = prevEntry.URI.spec;
if (prevURL && (prevURL == originalURL || !originalURL)) {
webNav.goBack();
break;
}
}
content.document.location = originalURL;
ReaderMode.leaveReaderMode(docShell, content);
}
break;

Просмотреть файл

@ -52,14 +52,21 @@ Notification.prototype = {
},
observe(subject, topic, data) {
if (topic === "alertclickcallback") {
notificationsMap.get(this.extension).emit("clicked", data);
}
if (topic === "alertfinished") {
notificationsMap.get(this.extension).emit("closed", data);
let notifications = notificationsMap.get(this.extension);
// Don't try to emit events if the extension has been unloaded
if (!notifications) {
return;
}
notificationsMap.get(this.extension).delete(this.id);
if (topic === "alertclickcallback") {
notifications.emit("clicked", data);
}
if (topic === "alertfinished") {
notifications.emit("closed", data);
}
notifications.delete(this.id);
},
};

Просмотреть файл

@ -259,7 +259,7 @@ AboutReader.prototype = {
},
_onReaderClose: function() {
this._win.location.href = this._getOriginalUrl();
ReaderMode.leaveReaderMode(this._mm.docShell, this._win);
},
_setFontSize: function(newFontSize) {

Просмотреть файл

@ -87,6 +87,48 @@ this.ReaderMode = {
}
},
/**
* Enter the reader mode by going forward one step in history if applicable,
* if not, append the about:reader page in the history instead.
*/
enterReaderMode: function(docShell, win) {
let url = win.document.location.href;
let readerURL = "about:reader?url=" + encodeURIComponent(url);
let webNav = docShell.QueryInterface(Ci.nsIWebNavigation);
let sh = webNav.sessionHistory;
if (webNav.canGoForward) {
let forwardEntry = sh.getEntryAtIndex(sh.index + 1, false);
let forwardURL = forwardEntry.URI.spec;
if (forwardURL && (forwardURL == readerURL || !readerURL)) {
webNav.goForward();
return;
}
}
win.document.location = readerURL;
},
/**
* Exit the reader mode by going back one step in history if applicable,
* if not, append the original page in the history instead.
*/
leaveReaderMode: function(docShell, win) {
let url = win.document.location.href;
let originalURL = this.getOriginalUrl(url);
let webNav = docShell.QueryInterface(Ci.nsIWebNavigation);
let sh = webNav.sessionHistory;
if (webNav.canGoBack) {
let prevEntry = sh.getEntryAtIndex(sh.index - 1, false);
let prevURL = prevEntry.URI.spec;
if (prevURL && (prevURL == originalURL || !originalURL)) {
webNav.goBack();
return;
}
}
win.document.location = originalURL;
},
/**
* Returns original URL from an about:reader URL.
*

Просмотреть файл

@ -54,7 +54,6 @@ support-files =
[test_autocomplete3.xul]
[test_autocomplete4.xul]
[test_autocomplete5.xul]
[test_autocomplete_change_after_focus.html]
[test_autocomplete_delayOnPaste.xul]
[test_autocomplete_emphasis.xul]
[test_autocomplete_with_composition_on_input.html]

Просмотреть файл

@ -1,69 +0,0 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=998893
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 998893 - Ensure that input.value changes affect autocomplete</title>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"></script>
<link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
<script type="application/javascript">
/** Test for Bug 998893 **/
SimpleTest.waitForExplicitFinish();
SimpleTest.waitForFocus(setup);
function setup() {
SpecialPowers.formHistory.update([
{ op : "bump", fieldname: "field1", value: "Default text option" },
{ op : "bump", fieldname: "field1", value: "New value option" },
], {
handleCompletion: function() {
runTest();
},
});
}
function handleEnter(evt) {
if (evt.keyCode != KeyEvent.DOM_VK_RETURN) {
return;
}
info("RETURN received for phase: " + evt.eventPhase);
is(evt.target.value, "New value option", "Check that the correct autocomplete entry was used");
SimpleTest.finish();
}
function popupShownListener(evt) {
info("popupshown");
sendKey("DOWN");
sendKey("RETURN"); // select the first entry in the popup
sendKey("RETURN"); // try to submit the form with the filled value
}
SpecialPowers.addAutoCompletePopupEventListener(window, "popupshown", popupShownListener);
function runTest() {
var field = document.getElementById("field1");
field.addEventListener("focus", function onFocus() {
info("field focused");
field.value = "New value";
sendKey("DOWN");
});
field.addEventListener("keypress", handleEnter, true);
field.focus();
}
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=998893">Mozilla Bug 998893</a>
<p id="display"><input id="field1" value="Default text"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
</body>
</html>

Просмотреть файл

@ -1,3 +1,5 @@
[test_autocomplete_change_after_focus.html]
skip-if = toolkit == "android"
[test_mousecapture.xhtml]
skip-if = toolkit == "android"

Просмотреть файл

@ -0,0 +1,105 @@
<!DOCTYPE html>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=998893
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 998893 - Ensure that input.value changes affect autocomplete</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
<script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<script type="text/javascript">
/** Test for Bug 998893 **/
add_task(function* waitForFocus() {
yield new Promise(resolve => SimpleTest.waitForFocus(resolve));
});
add_task(function* setup() {
yield new Promise(resolve => {
let chromeScript = SpecialPowers.loadChromeScript(function() {
const {FormHistory} = Components.utils.import("resource://gre/modules/FormHistory.jsm", null);
FormHistory.update([
{ op : "bump", fieldname: "field1", value: "Default text option" },
{ op : "bump", fieldname: "field1", value: "New value option" },
], {
handleCompletion: function() {
sendAsyncMessage("Test:Resume");
},
});
});
chromeScript.addMessageListener("Test:Resume", function resumeListener() {
chromeScript.removeMessageListener("Test:Resume", resumeListener);
chromeScript.destroy();
resolve();
});
});
});
add_task(function* runTest() {
let promisePopupShown = new Promise(resolve => {
let chromeScript = SpecialPowers.loadChromeScript(function() {
Components.utils.import("resource://gre/modules/Services.jsm");
let window = Services.wm.getMostRecentWindow("navigator:browser");
let popup = window.document.getElementById("PopupAutoComplete");
popup.addEventListener("popupshown", function popupShown() {
popup.removeEventListener("popupshown", popupShown);
sendAsyncMessage("Test:Resume");
});
});
chromeScript.addMessageListener("Test:Resume", function resumeListener() {
chromeScript.removeMessageListener("Test:Resume", resumeListener);
chromeScript.destroy();
resolve();
});
});
let field = document.getElementById("field1");
let promiseFieldFocus = new Promise(resolve => {
field.addEventListener("focus", function onFocus() {
info("field focused");
field.value = "New value";
sendKey("DOWN");
resolve();
});
});
let handleEnterPromise = new Promise(resolve => {
function handleEnter(evt) {
if (evt.keyCode != KeyEvent.DOM_VK_RETURN) {
return;
}
info("RETURN received for phase: " + evt.eventPhase);
is(evt.target.value, "New value option", "Check that the correct autocomplete entry was used");
resolve();
}
field.addEventListener("keypress", handleEnter, true);
});
field.focus();
yield promiseFieldFocus;
yield promisePopupShown;
sendKey("DOWN");
sendKey("RETURN");
sendKey("RETURN");
yield handleEnterPromise;
});
</script>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=998893">Mozilla Bug 998893</a>
<p id="display"><input id="field1" value="Default text"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
</body>
</html>

Просмотреть файл

@ -129,6 +129,16 @@ AddonPathService::InsertPath(const nsAString& path, const nsAString& addonIdStri
return NS_OK;
}
NS_IMETHODIMP
AddonPathService::MapURIToAddonId(nsIURI* aURI, nsAString& addonIdString)
{
if (JSAddonId* id = MapURIToAddonID(aURI)) {
JSFlatString* flat = JS_ASSERT_STRING_IS_FLAT(JS::StringOfAddonId(id));
AssignJSFlatString(addonIdString, flat);
}
return NS_OK;
}
static nsresult
ResolveURI(nsIURI* aURI, nsAString& out)
{

Просмотреть файл

@ -5,6 +5,8 @@
#include "nsISupports.idl"
interface nsIURI;
/**
* This service maps file system paths where add-ons reside to the ID
* of the add-on. Paths are added by the add-on manager. They can
@ -26,4 +28,10 @@ interface amIAddonPathService : nsISupports
* associated with the given add-on ID.
*/
void insertPath(in AString path, in AString addonId);
/**
* Given a URI to a file, return the ID of the add-on that the file belongs
* to. Returns an empty string if there is no add-on there.
*/
AString mapURIToAddonId(in nsIURI aURI);
};

Просмотреть файл

@ -71,6 +71,10 @@ XPCOMUtils.defineLazyServiceGetter(this,
"AddonPolicyService",
"@mozilla.org/addons/policy-service;1",
"nsIAddonPolicyService");
XPCOMUtils.defineLazyServiceGetter(this,
"AddonPathService",
"@mozilla.org/addon-path-service;1",
"amIAddonPathService");
XPCOMUtils.defineLazyGetter(this, "CertUtils", function() {
let certUtils = {};
@ -2435,8 +2439,7 @@ this.XPIProvider = {
logger.info("Mapping " + aID + " to " + aFile.path);
this._addonFileMap.set(aID, aFile.path);
let service = Cc["@mozilla.org/addon-path-service;1"].getService(Ci.amIAddonPathService);
service.insertPath(aFile.path, aID);
AddonPathService.insertPath(aFile.path, aID);
},
/**
@ -4106,20 +4109,8 @@ this.XPIProvider = {
* @see amIAddonManager.mapURIToAddonID
*/
mapURIToAddonID: function(aURI) {
if (aURI.scheme == "moz-extension") {
return AddonPolicyService.extensionURIToAddonId(aURI);
}
let resolved = this._resolveURIToFile(aURI);
if (!resolved || !(resolved instanceof Ci.nsIFileURL))
return null;
for (let [id, path] of this._addonFileMap) {
if (resolved.file.path.startsWith(path))
return id;
}
return null;
// Returns `null` instead of empty string if the URI can't be mapped.
return AddonPathService.mapURIToAddonId(aURI) || null;
},
/**

Просмотреть файл

@ -83,8 +83,10 @@ function run_test_early() {
"resource://gre/modules/addons/XPIProvider.jsm", {});
// Make the early API call.
do_check_null(s.XPIProvider.mapURIToAddonID(uri));
// AddonManager still misses its provider and so doesn't work yet.
do_check_null(AddonManager.mapURIToAddonID(uri));
// But calling XPIProvider directly works immediately
do_check_eq(s.XPIProvider.mapURIToAddonID(uri), id);
// Actually start up the manager.
startupManager(false);

Просмотреть файл

@ -413,12 +413,16 @@ GfxInfo::GetFeatureStatusImpl(int32_t aFeature,
// Don't evaluate special cases when evaluating the downloaded blocklist.
if (aDriverInfo.IsEmpty()) {
if (aFeature == nsIGfxInfo::FEATURE_CANVAS2D_ACCELERATION) {
// It's slower than software due to not having a compositing fast path
if (mSDKVersion >= 11) {
*aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
} else {
if (mSDKVersion < 11) {
// It's slower than software due to not having a compositing fast path
*aStatus = nsIGfxInfo::FEATURE_BLOCKED_OS_VERSION;
aFailureId = "FEATURE_FAILURE_CANVAS_2D_SDK";
} else if (mGLStrings->Renderer().Find("Vivante GC1000") != -1) {
// Blocklist Vivante GC1000. See bug 1248183.
*aStatus = nsIGfxInfo::FEATURE_BLOCKED_DEVICE;
aFailureId = "FEATURE_FAILED_CANVAS_2D_HW";
} else {
*aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
}
return NS_OK;
}