Merge m-c to b2g-inbound. a=merge

This commit is contained in:
Ryan VanderMeulen 2014-08-30 12:45:54 -04:00
Родитель c4f283b284 52fab7eaca
Коммит 0eab81eaf0
1317 изменённых файлов: 66036 добавлений и 14353 удалений

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

@ -978,8 +978,7 @@ pref("apz.subframe.enabled", true);
pref("apz.overscroll.enabled", true);
pref("apz.overscroll.fling_friction", "0.02");
pref("apz.overscroll.fling_stopped_threshold", "0.4");
pref("apz.overscroll.clamping", "0.5");
pref("apz.overscroll.z_effect", "0.5");
pref("apz.overscroll.stretch_factor", "0.5");
pref("apz.overscroll.snap_back.spring_stiffness", "0.6");
pref("apz.overscroll.snap_back.spring_friction", "0.1");
pref("apz.overscroll.snap_back.mass", "1200");

Разница между файлами не показана из-за своего большого размера Загрузить разницу

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

@ -1395,6 +1395,9 @@ pref("devtools.scratchpad.showTrailingSpace", false);
pref("devtools.scratchpad.enableCodeFolding", true);
pref("devtools.scratchpad.enableAutocompletion", true);
// Enable the Storage Inspector
pref("devtools.storage.enabled", false);
// Enable the Style Editor.
pref("devtools.styleeditor.enabled", true);
pref("devtools.styleeditor.source-maps-enabled", false);

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

@ -6,9 +6,9 @@
var gSafeBrowsing = {
setReportPhishingMenu: function() {
// A phishing page will have a specific about:blocked content documentURI
var isPhishingPage = content.document.documentURI.startsWith("about:blocked?e=phishingBlocked");
var uri = getBrowser().currentURI;
var isPhishingPage = uri && uri.spec.startsWith("about:blocked?e=phishingBlocked");
// Show/hide the appropriate menu item.
document.getElementById("menu_HelpPopup_reportPhishingtoolmenu")
@ -24,7 +24,6 @@ var gSafeBrowsing = {
if (!broadcaster)
return;
var uri = getBrowser().currentURI;
if (uri && (uri.schemeIs("http") || uri.schemeIs("https")))
broadcaster.removeAttribute("disabled");
else

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

@ -0,0 +1,463 @@
/* 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/. */
"use strict";
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Promise.jsm");
Cu.import("resource://gre/modules/Task.jsm");
Cu.import("resource://gre/modules/Log.jsm");
this.EXPORTED_SYMBOLS = ["CardDavImporter"];
let log = Log.repository.getLogger("Loop.Importer.CardDAV");
log.level = Log.Level.Debug;
log.addAppender(new Log.ConsoleAppender(new Log.BasicFormatter()));
const DEPTH_RESOURCE_ONLY = "0";
const DEPTH_RESOURCE_AND_CHILDREN = "1";
const DEPTH_RESOURCE_AND_ALL_DESCENDENTS = "infinity";
this.CardDavImporter = function() {
};
/**
* CardDAV Address Book importer for Loop.
*
* The model for address book importers is to have a single public method,
* "startImport." When the import is done (or upon a fatal error), the
* caller's callback method is called.
*
* The current model for this importer is based on the subset of CardDAV
* implemented by Google. In theory, it should work with other CardDAV
* sources, but it has only been tested against Google at the moment.
*
* At the moment, this importer assumes that no local changes will be made
* to data retreived from a remote source: when performing a re-import,
* any records that have been previously imported will be completely
* removed and replaced with the data received from the CardDAV server.
* Witout this behavior, it would be impossible for users to take any
* actions to remove fields that are no longer valid.
*/
this.CardDavImporter.prototype = {
/**
* Begin import of an address book from a CardDAV server.
*
* @param {Object} options Information needed to perform the address
* book import. The following fields are currently
* defined:
* - "host": CardDAV server base address
* (e.g., "google.com")
* - "auth": Authentication mechanism to use.
* Currently, only "basic" is implemented.
* - "user": Username to use for basic auth
* - "password": Password to use for basic auth
* @param {Function} callback Callback function that will be invoked once the
* import operation is complete. The first argument
* passed to the callback will be an 'Error' object
* or 'null'. If the import operation was
* successful, then the second parameter will be a
* count of the number of contacts that were
* successfully imported.
* @param {Object} db Database to add imported contacts into.
* Nominally, this is the LoopContacts API. In
* practice, anything with the same interface
* should work here.
*/
startImport: function(options, callback, db) {
let auth;
if (!("auth" in options)) {
callback(new Error("No authentication specified"));
return;
}
if (options.auth === "basic") {
if (!("user" in options) || !("password" in options)) {
callback(new Error("Missing user or password for basic authentication"));
return;
}
auth = { method: "basic",
user: options.user,
password: options.password };
} else {
callback(new Error("Unknown authentication method"));
return;
}
if (!("host" in options)){
callback(new Error("Missing host for CardDav import"));
return;
}
let host = options.host;
Task.spawn(function* () {
log.info("Starting CardDAV import from " + host);
let baseURL = "https://" + host;
let startURL = baseURL + "/.well-known/carddav";
let abookURL;
// Get list of contact URLs
let body = "<d:propfind xmlns:d='DAV:'><d:prop><d:getetag />" +
"</d:prop></d:propfind>";
let abook = yield this._davPromise("PROPFIND", startURL, auth,
DEPTH_RESOURCE_AND_CHILDREN, body);
// Build multiget REPORT body from URLs in PROPFIND result
let contactElements = abook.responseXML.
getElementsByTagNameNS("DAV:", "href");
body = "<c:addressbook-multiget xmlns:d='DAV:' " +
"xmlns:c='urn:ietf:params:xml:ns:carddav'>" +
"<d:prop><d:getetag /> <c:address-data /></d:prop>\n";
for (let element of contactElements) {
let href = element.textContent;
if (href.substr(-1) == "/") {
abookURL = baseURL + href;
} else {
body += "<d:href>" + href + "</d:href>\n";
}
}
body += "</c:addressbook-multiget>";
// Retreive contact URL contents
let allEntries = yield this._davPromise("REPORT", abookURL, auth,
DEPTH_RESOURCE_AND_CHILDREN,
body);
// Parse multiget entites and add to DB
let addressData = allEntries.responseXML.getElementsByTagNameNS(
"urn:ietf:params:xml:ns:carddav", "address-data");
log.info("Retreived " + addressData.length + " contacts from " +
host + "; importing into database");
let importCount = 0;
for (let i = 0; i < addressData.length; i++) {
let vcard = addressData.item(i).textContent;
let contact = this._convertVcard(vcard);
contact.id += "@" + host;
contact.category = ["carddav@" + host];
let existing = yield this._dbPromise(db, "getByServiceId", contact.id);
if (existing) {
yield this._dbPromise(db, "remove", existing._guid);
}
// If the contact contains neither email nor phone number, then it
// is not useful in the Loop address book: do not add.
if (!("tel" in contact) && !("email" in contact)) {
continue;
}
yield this._dbPromise(db, "add", contact);
importCount++;
}
return importCount;
}.bind(this)).then(
(result) => {
log.info("Import complete: " + result + " contacts imported.");
callback(null, result);
},
(error) => {
log.error("Aborting import: " + error.fileName + ":" +
error.lineNumber + ": " + error.message);
callback(error);
}).then(null,
(error) => {
log.error("Error in callback: " + error.fileName +
":" + error.lineNumber + ": " + error.message);
callback(error);
}).then(null,
(error) => {
log.error("Error calling failure callback, giving up: " +
error.fileName + ":" + error.lineNumber + ": " +
error.message);
});
},
/**
* Wrap a LoopContacts-style operation in a promise. The operation is run
* immediately, and a corresponding Promise is returned. Error callbacks
* cause the promise to be rejected, and success cause it to be resolved.
*
* @param {Object} db Object the operation is to be performed on
* @param {String} method Name of operation being wrapped
* @param {Object} param Parameter to be passed to the operation
*
* @return {Object} Promise corresponding to the result of the operation.
*/
_dbPromise: function(db, method, param) {
return new Promise((resolve, reject) => {
db[method](param, (error, result) => {
if (error) {
reject(error);
} else {
resolve(result);
}
});
});
},
/**
* Converts a contact in VCard format (see RFC 6350) to the format used
* by the LoopContacts class.
*
* @param {String} vcard The contact to convert, in vcard format
* @return {Object} a LoopContacts-style contact object containing
* the relevant fields from the vcard.
*/
_convertVcard: function(vcard) {
let contact = {};
let nickname;
vcard.split(/[\r\n]+(?! )/).forEach(
function (contentline) {
contentline = contentline.replace(/[\r\n]+ /g, "");
let match = /^(.*?[^\\]):(.*)$/.exec(contentline);
if (match) {
let nameparam = match[1];
let value = match[2];
// Poor-man's unescaping
value = value.replace(/\\:/g, ":");
value = value.replace(/\\,/g, ",");
value = value.replace(/\\n/gi, "\n");
value = value.replace(/\\\\/g, "\\");
let param = nameparam.split(/;/);
let name = param[0];
let pref = false;
let type = [];
for (let i = 1; i < param.length; i++) {
if (/^PREF/.exec(param[i]) || /^TYPE=PREF/.exec(param[i])) {
pref = true;
}
let typeMatch = /^TYPE=(.*)/.exec(param[i]);
if (typeMatch) {
type.push(typeMatch[1].toLowerCase());
}
}
if (!type.length) {
type.push("other");
}
if (name === "FN") {
value = value.replace(/\\;/g, ";");
contact.name = [value];
}
if (name === "N") {
// Because we don't have lookbehinds, matching unescaped
// semicolons is a pain. Luckily, we know that \r and \n
// cannot appear in the strings, so we use them to swap
// unescaped semicolons for \n.
value = value.replace(/\\;/g, "\r");
value = value.replace(/;/g, "\n");
value = value.replace(/\r/g, ";");
let family, given, additional, prefix, suffix;
let values = value.split(/\n/);
if (values.length >= 5) {
[family, given, additional, prefix, suffix] = values;
if (prefix.length) {
contact.honorificPrefix = [prefix];
}
if (given.length) {
contact.givenName = [given];
}
if (additional.length) {
contact.additionalName = [additional];
}
if (family.length) {
contact.familyName = [family];
}
if (suffix.length) {
contact.honorificSuffix = [suffix];
}
}
}
if (name === "EMAIL") {
value = value.replace(/\\;/g, ";");
if (!("email" in contact)) {
contact.email = [];
}
contact.email.push({
pref: pref,
type: type,
value: value
});
}
if (name === "NICKNAME") {
value = value.replace(/\\;/g, ";");
// We don't store nickname in contact because it's not
// a supported field. We're saving it off here in case we
// need to use it if the fullname is blank.
nickname = value;
};
if (name === "ADR") {
value = value.replace(/\\;/g, "\r");
value = value.replace(/;/g, "\n");
value = value.replace(/\r/g, ";");
let pobox, extra, street, locality, region, code, country;
let values = value.split(/\n/);
if (values.length >= 7) {
[pobox, extra, street, locality, region, code, country] = values;
if (!("adr" in contact)) {
contact.adr = [];
}
contact.adr.push({
pref: pref,
type: type,
streetAddress: (street || pobox) + (extra ? (" " + extra) : ""),
locality: locality,
region: region,
postalCode: code,
countryName: country
});
}
}
if (name === "TEL") {
value = value.replace(/\\;/g, ";");
if (!("tel" in contact)) {
contact.tel = [];
}
contact.tel.push({
pref: pref,
type: type,
value: value
});
}
if (name === "ORG") {
value = value.replace(/\\;/g, "\r");
value = value.replace(/;/g, "\n");
value = value.replace(/\r/g, ";");
if (!("org" in contact)) {
contact.org = [];
}
contact.org.push(value.replace(/\n.*/, ""));
}
if (name === "TITLE") {
value = value.replace(/\\;/g, ";");
if (!("jobTitle" in contact)) {
contact.jobTitle = [];
}
contact.jobTitle.push(value);
}
if (name === "BDAY") {
value = value.replace(/\\;/g, ";");
contact.bday = Date.parse(value);
}
if (name === "UID") {
contact.id = value;
}
if (name === "NOTE") {
value = value.replace(/\\;/g, ";");
if (!("note" in contact)) {
contact.note = [];
}
contact.note.push(value);
}
}
}
);
// Basic sanity checking: make sure the name field isn't empty
if (!("name" in contact) || contact.name[0].length == 0) {
if (("familyName" in contact) && ("givenName" in contact)) {
// First, try to synthesize a full name from the name fields.
// Ordering is culturally sensitive, but we don't have
// cultural origin information available here. The best we
// can really do is "family, given additional"
contact.name = [contact.familyName[0] + ", " + contact.givenName[0]];
if (("additionalName" in contact)) {
contact.name[0] += " " + contact.additionalName[0];
}
} else {
if (nickname) {
contact.name = [nickname];
} else if ("familyName" in contact) {
contact.name = [contact.familyName[0]];
} else if ("givenName" in contact) {
contact.name = [contact.givenName[0]];
} else if ("org" in contact) {
contact.name = [contact.org[0]];
} else if ("email" in contact) {
contact.name = [contact.email[0].value];
} else if ("tel" in contact) {
contact.name = [contact.tel[0].value];
}
}
}
return contact;
},
/**
* Issues a CardDAV request (see RFC 6352) and returns a Promise to represent
* the success or failure state of the request.
*
* @param {String} method WebDAV method to use (e.g., "PROPFIND")
* @param {String} url HTTP URL to use for the request
* @param {Object} auth Object with authentication-related configuration.
* See documentation for startImport for details.
* @param {Number} depth Value to use for the WebDAV (HTTP) "Depth" header
* @param {String} body Body to include in the WebDAV (HTTP) request
*
* @return {Object} Promise representing the request operation outcome.
* If resolved, the resolution value is the XMLHttpRequest
* that was used to perform the request.
*/
_davPromise: function(method, url, auth, depth, body) {
return new Promise((resolve, reject) => {
let req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"].
createInstance(Ci.nsIXMLHttpRequest);
let user = "";
let password = "";
if (auth.method == "basic") {
user = auth.user;
password = auth.password;
}
req.open(method, url, true, user, password);
req.setRequestHeader("Depth", depth);
req.setRequestHeader("Content-Type", "application/xml; charset=utf-8");
req.onload = function() {
if (req.status < 400) {
resolve(req);
} else {
reject(new Error(req.status + " " + req.statusText));
}
};
req.onerror = function(error) {
reject(error);
}
req.send(body);
});
}
};

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

@ -10,6 +10,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "console",
"resource://gre/modules/devtools/Console.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "LoopStorage",
"resource:///modules/loop/LoopStorage.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "CardDavImporter",
"resource:///modules/loop/CardDavImporter.jsm");
XPCOMUtils.defineLazyGetter(this, "eventEmitter", function() {
const {EventEmitter} = Cu.import("resource://gre/modules/devtools/event-emitter.js", {});
return new EventEmitter();
@ -318,6 +320,13 @@ LoopStorage.on("upgrade", function(e, db) {
* violated. You'll notice this as well in the documentation for each method.
*/
let LoopContactsInternal = Object.freeze({
/**
* Map of contact importer names to instances
*/
_importServices: {
"carddav": new CardDavImporter()
},
/**
* Add a contact to the data store.
*
@ -757,8 +766,15 @@ let LoopContactsInternal = Object.freeze({
* be the result of the operation, if successfull.
*/
startImport: function(options, callback) {
//TODO in bug 972000.
callback(new Error("Not implemented yet!"));
if (!("service" in options)) {
callback(new Error("No import service specified in options"));
return;
}
if (!(options.service in this._importServices)) {
callback(new Error("Unknown import service specified: " + options.service));
return;
}
this._importServices[options.service].startImport(options, callback, this);
},
/**

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

@ -543,7 +543,7 @@ loop.shared.views = (function(_, OT, l10n) {
return (
FeedbackLayout({title: l10n.get("feedback_thank_you_heading")},
React.DOM.p({className: "info thank-you"},
l10n.get("feedback_window_will_close_in", {
l10n.get("feedback_window_will_close_in2", {
countdown: this.state.countdown,
num: this.state.countdown
}))

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

@ -543,7 +543,7 @@ loop.shared.views = (function(_, OT, l10n) {
return (
<FeedbackLayout title={l10n.get("feedback_thank_you_heading")}>
<p className="info thank-you">{
l10n.get("feedback_window_will_close_in", {
l10n.get("feedback_window_will_close_in2", {
countdown: this.state.countdown,
num: this.state.countdown
})}</p>

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

@ -13,6 +13,7 @@ BROWSER_CHROME_MANIFESTS += [
]
EXTRA_JS_MODULES.loop += [
'CardDavImporter.jsm',
'LoopContacts.jsm',
'LoopStorage.jsm',
'MozLoopAPI.jsm',

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

@ -4,6 +4,7 @@ support-files =
loop_fxa.sjs
../../../../base/content/test/general/browser_fxa_oauth.html
[browser_CardDavImporter.js]
[browser_fxa_login.js]
skip-if = !debug
[browser_loop_fxa_server.js]

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

@ -0,0 +1,364 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const {CardDavImporter} = Cu.import("resource:///modules/loop/CardDavImporter.jsm", {});
const mockDb = {
_store: { },
_next_guid: 1,
add: function(details, callback) {
if (!("id" in details)) {
callback(new Error("No 'id' field present"));
return;
}
details._guid = this._next_guid++;
this._store[details._guid] = details;
callback(null, details);
},
remove: function(guid, callback) {
if (!guid in this._store) {
callback(new Error("Could not find _guid '" + guid + "' in database"));
return;
}
delete this._store[guid];
callback(null);
},
get: function(guid, callback) {
callback(null, this._store[guid]);
},
getByServiceId: function(serviceId, callback) {
for (let guid in this._store) {
if (serviceId === this._store[guid].id) {
callback(null, this._store[guid]);
return;
}
}
callback(null, null);
},
removeAll: function(callback) {
this._store = {};
this._next_guid = 1;
callback(null);
}
};
const kAuth = {
"method": "basic",
"user": "username",
"password": "p455w0rd"
}
// "pid" for "provider ID"
let vcards = [
"VERSION:3.0\n" +
"N:Smith;John;;;\n" +
"FN:John Smith\n" +
"EMAIL;TYPE=work:john.smith@example.com\n" +
"REV:2011-07-12T14:43:20Z\n" +
"UID:pid1\n" +
"END:VCARD\n",
"VERSION:3.0\n" +
"N:Smith;Jane;;;\n" +
"FN:Jane Smith\n" +
"EMAIL:jane.smith@example.com\n" +
"REV:2011-07-12T14:43:20Z\n" +
"UID:pid2\n" +
"END:VCARD\n",
"VERSION:3.0\n" +
"N:García Fernández;Miguel Angel;José Antonio;Mr.;Jr.\n" +
"FN:Mr. Miguel Angel José Antonio\n García Fernández, Jr.\n" +
"EMAIL:mike@example.org\n" +
"EMAIL;PREF=1;TYPE=work:miguel.angel@example.net\n" +
"EMAIL;TYPE=home;UNKNOWNPARAMETER=frotz:majacf@example.com\n" +
"TEL:+3455555555\n" +
"TEL;PREF=1;TYPE=work:+3455556666\n" +
"TEL;TYPE=home;UNKNOWNPARAMETER=frotz:+3455557777\n" +
"ADR:;Suite 123;Calle Aduana\\, 29;MADRID;;28070;SPAIN\n" +
"ADR;TYPE=work:P.O. BOX 555;;;Washington;DC;20024-00555;USA\n" +
"ORG:Acme España SL\n" +
"TITLE:President\n" +
"BDAY:1965-05-05\n" +
"NOTE:Likes tulips\n" +
"REV:2011-07-12T14:43:20Z\n" +
"UID:pid3\n" +
"END:VCARD\n",
"VERSION:3.0\n" +
"N:Jones;Bob;;;\n" +
"EMAIL:bob.jones@example.com\n" +
"REV:2011-07-12T14:43:20Z\n" +
"UID:pid4\n" +
"END:VCARD\n",
"VERSION:3.0\n" +
"N:Jones;Davy;Randall;;\n" +
"EMAIL:davy.jones@example.com\n" +
"REV:2011-07-12T14:43:20Z\n" +
"UID:pid5\n" +
"END:VCARD\n",
"VERSION:3.0\n" +
"EMAIL:trip@example.com\n" +
"NICKNAME:Trip\n" +
"REV:2011-07-12T14:43:20Z\n" +
"UID:pid6\n" +
"END:VCARD\n",
"VERSION:3.0\n" +
"EMAIL:acme@example.com\n" +
"ORG:Acme, Inc.\n" +
"REV:2011-07-12T14:43:20Z\n" +
"UID:pid7\n" +
"END:VCARD\n",
"VERSION:3.0\n" +
"EMAIL:anyone@example.com\n" +
"REV:2011-07-12T14:43:20Z\n" +
"UID:pid8\n" +
"END:VCARD\n",
];
const monkeyPatchImporter = function(importer) {
// Set up the response bodies
let listPropfind =
'<?xml version="1.0" encoding="UTF-8"?>\n' +
'<d:multistatus xmlns:card="urn:ietf:params:xml:ns:carddav"\n' +
' xmlns:d="DAV:">\n' +
' <d:response>\n' +
' <d:href>/carddav/abook/</d:href>\n' +
' <d:propstat>\n' +
' <d:status>HTTP/1.1 200 OK</d:status>\n' +
' </d:propstat>\n' +
' <d:propstat>\n' +
' <d:status>HTTP/1.1 404 Not Found</d:status>\n' +
' <d:prop>\n' +
' <d:getetag/>\n' +
' </d:prop>\n' +
' </d:propstat>\n' +
' </d:response>\n';
let listReportMultiget =
'<?xml version="1.0" encoding="UTF-8"?>\n' +
'<d:multistatus xmlns:card="urn:ietf:params:xml:ns:carddav"\n' +
' xmlns:d="DAV:">\n';
vcards.forEach(vcard => {
let uid = /\nUID:(.*?)\n/.exec(vcard);
listPropfind +=
' <d:response>\n' +
' <d:href>/carddav/abook/' + uid + '</d:href>\n' +
' <d:propstat>\n' +
' <d:status>HTTP/1.1 200 OK</d:status>\n' +
' <d:prop>\n' +
' <d:getetag>"2011-07-12T07:43:20.855-07:00"</d:getetag>\n' +
' </d:prop>\n' +
' </d:propstat>\n' +
' </d:response>\n';
listReportMultiget +=
' <d:response>\n' +
' <d:href>/carddav/abook/' + uid + '</d:href>\n' +
' <d:propstat>\n' +
' <d:status>HTTP/1.1 200 OK</d:status>\n' +
' <d:prop>\n' +
' <d:getetag>"2011-07-12T07:43:20.855-07:00"</d:getetag>\n' +
' <card:address-data>' + vcard + '</card:address-data>\n' +
' </d:prop>\n' +
' </d:propstat>\n' +
' </d:response>\n';
});
listPropfind += "</d:multistatus>\n";
listReportMultiget += "</d:multistatus>\n";
importer._davPromise = function(method, url, auth, depth, body) {
return new Promise((resolve, reject) => {
if (auth.method != "basic" ||
auth.user != kAuth.user ||
auth.password != kAuth.password) {
reject(new Error("401 Auth Failure"));
return;
}
let request = method + " " + url + " " + depth;
let xmlParser = new DOMParser();
let responseXML;
switch (request) {
case "PROPFIND https://example.com/.well-known/carddav 1":
responseXML = xmlParser.parseFromString(listPropfind, "text/xml");
break;
case "REPORT https://example.com/carddav/abook/ 1":
responseXML = xmlParser.parseFromString(listReportMultiget, "text/xml");
break;
default:
reject(new Error("404 Not Found"));
return;
}
resolve({"responseXML": responseXML});
});
}.bind(importer);
return importer;
}
add_task(function* test_CardDavImport() {
let importer = monkeyPatchImporter(new CardDavImporter());
yield new Promise ((resolve, reject) => {
info("Initiating import");
importer.startImport({
"host": "example.com",
"auth": kAuth.method,
"user": kAuth.user,
"password": kAuth.password
}, (err, result) => { err ? reject(err) : resolve(result); }, mockDb);
});
info("Import succeeded");
Assert.equal(vcards.length, Object.keys(mockDb._store).length,
"Should import all VCards into database");
// Basic checks
let c = mockDb._store[1];
Assert.equal(c.name[0], "John Smith", "Full name should match");
Assert.equal(c.givenName[0], "John", "Given name should match");
Assert.equal(c.familyName[0], "Smith", "Family name should match");
Assert.equal(c.email[0].type, "work", "Email type should match");
Assert.equal(c.email[0].value, "john.smith@example.com", "Email should match");
Assert.equal(c.email[0].pref, false, "Pref should match");
Assert.equal(c.id, "pid1@example.com", "UID should match and be scoped to provider");
c = mockDb._store[2];
Assert.equal(c.name[0], "Jane Smith", "Full name should match");
Assert.equal(c.givenName[0], "Jane", "Given name should match");
Assert.equal(c.familyName[0], "Smith", "Family name should match");
Assert.equal(c.email[0].type, "other", "Email type should match");
Assert.equal(c.email[0].value, "jane.smith@example.com", "Email should match");
Assert.equal(c.email[0].pref, false, "Pref should match");
Assert.equal(c.id, "pid2@example.com", "UID should match and be scoped to provider");
// Check every field
c = mockDb._store[3];
Assert.equal(c.name[0], "Mr. Miguel Angel José Antonio García Fernández, Jr.", "Full name should match");
Assert.equal(c.givenName[0], "Miguel Angel", "Given name should match");
Assert.equal(c.additionalName[0], "José Antonio", "Other name should match");
Assert.equal(c.familyName[0], "García Fernández", "Family name should match");
Assert.equal(c.email.length, 3, "Email count should match");
Assert.equal(c.email[0].type, "other", "Email type should match");
Assert.equal(c.email[0].value, "mike@example.org", "Email should match");
Assert.equal(c.email[0].pref, false, "Pref should match");
Assert.equal(c.email[1].type, "work", "Email type should match");
Assert.equal(c.email[1].value, "miguel.angel@example.net", "Email should match");
Assert.equal(c.email[1].pref, true, "Pref should match");
Assert.equal(c.email[2].type, "home", "Email type should match");
Assert.equal(c.email[2].value, "majacf@example.com", "Email should match");
Assert.equal(c.email[2].pref, false, "Pref should match");
Assert.equal(c.tel.length, 3, "Phone number count should match");
Assert.equal(c.tel[0].type, "other", "Phone type should match");
Assert.equal(c.tel[0].value, "+3455555555", "Phone number should match");
Assert.equal(c.tel[0].pref, false, "Pref should match");
Assert.equal(c.tel[1].type, "work", "Phone type should match");
Assert.equal(c.tel[1].value, "+3455556666", "Phone number should match");
Assert.equal(c.tel[1].pref, true, "Pref should match");
Assert.equal(c.tel[2].type, "home", "Phone type should match");
Assert.equal(c.tel[2].value, "+3455557777", "Phone number should match");
Assert.equal(c.tel[2].pref, false, "Pref should match");
Assert.equal(c.adr.length, 2, "Address count should match");
Assert.equal(c.adr[0].pref, false, "Pref should match");
Assert.equal(c.adr[0].type, "other", "Type should match");
Assert.equal(c.adr[0].streetAddress, "Calle Aduana, 29 Suite 123", "Street address should match");
Assert.equal(c.adr[0].locality, "MADRID", "Locality should match");
Assert.equal(c.adr[0].postalCode, "28070", "Post code should match");
Assert.equal(c.adr[0].countryName, "SPAIN", "Country should match");
Assert.equal(c.adr[1].pref, false, "Pref should match");
Assert.equal(c.adr[1].type, "work", "Type should match");
Assert.equal(c.adr[1].streetAddress, "P.O. BOX 555", "Street address should match");
Assert.equal(c.adr[1].locality, "Washington", "Locality should match");
Assert.equal(c.adr[1].region, "DC", "Region should match");
Assert.equal(c.adr[1].postalCode, "20024-00555", "Post code should match");
Assert.equal(c.adr[1].countryName, "USA", "Country should match");
Assert.equal(c.org[0], "Acme España SL", "Org should match");
Assert.equal(c.jobTitle[0], "President", "Title should match");
Assert.equal(c.note[0], "Likes tulips", "Note should match");
let bday = new Date(c.bday);
Assert.equal(bday.getUTCFullYear(), 1965, "Birthday year should match");
Assert.equal(bday.getUTCMonth(), 4, "Birthday month should match");
Assert.equal(bday.getUTCDate(), 5, "Birthday day should match");
Assert.equal(c.id, "pid3@example.com", "UID should match and be scoped to provider");
// Check name synthesis
c = mockDb._store[4];
Assert.equal(c.name[0], "Jones, Bob", "Full name should be synthesized correctly");
c = mockDb._store[5];
Assert.equal(c.name[0], "Jones, Davy Randall", "Full name should be synthesized correctly");
c = mockDb._store[6];
Assert.equal(c.name[0], "Trip", "Full name should be synthesized correctly");
c = mockDb._store[7];
Assert.equal(c.name[0], "Acme, Inc.", "Full name should be synthesized correctly");
c = mockDb._store[8];
Assert.equal(c.name[0], "anyone@example.com", "Full name should be synthesized correctly");
// Check that a re-import doesn't cause contact duplication.
yield new Promise ((resolve, reject) => {
info("Initiating import");
importer.startImport({
"host": "example.com",
"auth": kAuth.method,
"user": kAuth.user,
"password": kAuth.password
}, (err, result) => { err ? reject(err) : resolve(result); }, mockDb);
});
Assert.equal(vcards.length, Object.keys(mockDb._store).length,
"Second import shouldn't increase DB size");
// Check that errors are propagated back to caller
let error = yield new Promise ((resolve, reject) => {
info("Initiating import");
importer.startImport({
"host": "example.com",
"auth": kAuth.method,
"user": kAuth.user,
"password": "invalidpassword"
}, (err, result) => { err ? resolve(err) : reject(new Error("Should have failed")); }, mockDb);
});
Assert.equal(error.message, "401 Auth Failure", "Auth error should propagate");
let error = yield new Promise ((resolve, reject) => {
info("Initiating import");
importer.startImport({
"host": "example.invalid",
"auth": kAuth.method,
"user": kAuth.user,
"password": kAuth.password
}, (err, result) => { err ? resolve(err) : reject(new Error("Should have failed")); }, mockDb);
});
Assert.equal(error.message, "404 Not Found", "Not found error should propagate");
let tmp = mockDb.getByServiceId;
mockDb.getByServiceId = function(serviceId, callback) {
callback(new Error("getByServiceId failed"));
};
let error = yield new Promise ((resolve, reject) => {
info("Initiating import");
importer.startImport({
"host": "example.com",
"auth": kAuth.method,
"user": kAuth.user,
"password": kAuth.password
}, (err, result) => { err ? resolve(err) : reject(new Error("Should have failed")); }, mockDb);
});
Assert.equal(error.message, "getByServiceId failed", "Database error should propagate");
mockDb.getByServiceId = tmp;
let error = yield new Promise ((resolve, reject) => {
info("Initiating import");
importer.startImport({
"host": "example.com",
}, (err, result) => { err ? resolve(err) : reject(new Error("Should have failed")); }, mockDb);
});
Assert.equal(error.message, "No authentication specified", "Missing parameters should generate error");
})

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

@ -11,7 +11,7 @@ add_task(loadLoopPanel);
add_task(function* test_mozLoop_pluralStrings() {
Assert.ok(gMozLoopAPI, "mozLoop should exist");
var strings = JSON.parse(gMozLoopAPI.getStrings("feedback_window_will_close_in"));
var strings = JSON.parse(gMozLoopAPI.getStrings("feedback_window_will_close_in2"));
Assert.equal(gMozLoopAPI.getPluralForm(0, strings.textContent),
"This window will close in {{countdown}} seconds");
Assert.equal(gMozLoopAPI.getPluralForm(1, strings.textContent),

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

@ -29,7 +29,6 @@ const MAX_ORDINAL = 99;
this.DevTools = function DevTools() {
this._tools = new Map(); // Map<toolId, tool>
this._themes = new Map(); // Map<themeId, theme>
this._eventParsers = new Map(); // Map<parserID, [handlers]>
this._toolboxes = new Map(); // Map<target, toolbox>
// destroy() is an observer's handler so we need to preserve context.
@ -42,7 +41,7 @@ this.DevTools = function DevTools() {
Services.obs.addObserver(this._teardown, "devtools-unloaded", false);
Services.obs.addObserver(this.destroy, "quit-application", false);
}
};
DevTools.prototype = {
/**
@ -66,10 +65,6 @@ DevTools.prototype = {
}
},
get eventParsers() {
return this._eventParsers;
},
/**
* Register a new developer tool.
*
@ -145,85 +140,6 @@ DevTools.prototype = {
}
},
/**
* Register a new event parser to be used in the processing of event info.
*
* @param {Object} parserObj
* Each parser must contain the following properties:
* - parser, which must take the following form:
* {
* id {String}: "jQuery events", // Unique id.
* getListeners: function(node) { }, // Function that takes a node and
* // returns an array of eventInfo
* // objects (see below).
*
* hasListeners: function(node) { }, // Optional function that takes a
* // node and returns a boolean
* // indicating whether a node has
* // listeners attached.
*
* normalizeHandler: function(fnDO) { }, // Optional function that takes a
* // Debugger.Object instance and
* // climbs the scope chain to get
* // the function that should be
* // displayed in the event bubble
* // see the following url for
* // details:
* // https://developer.mozilla.org/
* // docs/Tools/Debugger-API/
* // Debugger.Object
* }
*
* An eventInfo object should take the following form:
* {
* type {String}: "click",
* handler {Function}: event handler,
* tags {String}: "jQuery,Live", // These tags will be displayed as
* // attributes in the events popup.
* hide: { // Hide or show fields:
* debugger: false, // Debugger icon
* type: false, // Event type e.g. click
* filename: false, // Filename
* capturing: false, // Capturing
* dom0: false // DOM 0
* },
*
* override: { // The following can be overridden:
* type: "click",
* origin: "http://www.mozilla.com",
* searchString: 'onclick="doSomething()"',
* DOM0: true,
* capturing: true
* }
* }
*/
registerEventParser: function(parserObj) {
let parserId = parserObj.id;
if (!parserId) {
throw new Error("Cannot register new event parser with id " + parserId);
}
if (this._eventParsers.has(parserId)) {
throw new Error("Duplicate event parser id " + parserId);
}
this._eventParsers.set(parserId, {
getListeners: parserObj.getListeners,
hasListeners: parserObj.hasListeners,
normalizeHandler: parserObj.normalizeHandler
});
},
/**
* Removes parser that matches a given parserId.
*
* @param {String} parserId
* id of the event parser to unregister.
*/
unregisterEventParser: function(parserId) {
this._eventParsers.delete(parserId);
},
/**
* Sorting function used for sorting tools based on their ordinals.
*/
@ -555,10 +471,6 @@ DevTools.prototype = {
this.unregisterTool(key, true);
}
for (let [id] of this._eventParsers) {
this.unregisterEventParser(id, true);
}
// Cleaning down the toolboxes: i.e.
// for (let [target, toolbox] of this._toolboxes) toolbox.destroy();
// Is taken care of by the gDevToolsBrowser.forgetBrowserWindow

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

@ -26,6 +26,7 @@ browser.jar:
content/browser/devtools/frame-script-utils.js (shared/frame-script-utils.js)
content/browser/devtools/styleeditor.xul (styleeditor/styleeditor.xul)
content/browser/devtools/styleeditor.css (styleeditor/styleeditor.css)
content/browser/devtools/storage.xul (storage/storage.xul)
content/browser/devtools/computedview.xhtml (styleinspector/computedview.xhtml)
content/browser/devtools/cssruleview.xhtml (styleinspector/cssruleview.xhtml)
content/browser/devtools/ruleview.css (styleinspector/ruleview.css)

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

@ -21,8 +21,6 @@ loader.lazyGetter(this, "osString", () => Cc["@mozilla.org/xre/app-info;1"].getS
let events = require("sdk/system/events");
require("devtools/toolkit/event-parsers");
// Panels
loader.lazyGetter(this, "OptionsPanel", () => require("devtools/framework/toolbox-options").OptionsPanel);
loader.lazyGetter(this, "InspectorPanel", () => require("devtools/inspector/inspector-panel").InspectorPanel);
@ -35,6 +33,7 @@ loader.lazyGetter(this, "WebAudioEditorPanel", () => require("devtools/webaudioe
loader.lazyGetter(this, "ProfilerPanel", () => require("devtools/profiler/panel").ProfilerPanel);
loader.lazyGetter(this, "NetMonitorPanel", () => require("devtools/netmonitor/panel").NetMonitorPanel);
loader.lazyGetter(this, "ScratchpadPanel", () => require("devtools/scratchpad/scratchpad-panel").ScratchpadPanel);
loader.lazyGetter(this, "StoragePanel", () => require("devtools/storage/panel").StoragePanel);
// Strings
const toolboxProps = "chrome://browser/locale/devtools/toolbox.properties";
@ -44,11 +43,12 @@ const styleEditorProps = "chrome://browser/locale/devtools/styleeditor.propertie
const shaderEditorProps = "chrome://browser/locale/devtools/shadereditor.properties";
const canvasDebuggerProps = "chrome://browser/locale/devtools/canvasdebugger.properties";
const webAudioEditorProps = "chrome://browser/locale/devtools/webaudioeditor.properties";
const webConsoleProps = "chrome://browser/locale/devtools/webconsole.properties";
const profilerProps = "chrome://browser/locale/devtools/profiler.properties";
const netMonitorProps = "chrome://browser/locale/devtools/netmonitor.properties";
const scratchpadProps = "chrome://browser/locale/devtools/scratchpad.properties";
const storageProps = "chrome://browser/locale/devtools/storage.properties";
loader.lazyGetter(this, "toolboxStrings", () => Services.strings.createBundle(toolboxProps));
loader.lazyGetter(this, "webConsoleStrings", () => Services.strings.createBundle(webConsoleProps));
loader.lazyGetter(this, "debuggerStrings", () => Services.strings.createBundle(debuggerProps));
@ -60,6 +60,7 @@ loader.lazyGetter(this, "inspectorStrings", () => Services.strings.createBundle(
loader.lazyGetter(this, "profilerStrings",() => Services.strings.createBundle(profilerProps));
loader.lazyGetter(this, "netMonitorStrings", () => Services.strings.createBundle(netMonitorProps));
loader.lazyGetter(this, "scratchpadStrings", () => Services.strings.createBundle(scratchpadProps));
loader.lazyGetter(this, "storageStrings", () => Services.strings.createBundle(storageProps));
let Tools = {};
exports.Tools = Tools;
@ -318,9 +319,34 @@ Tools.netMonitor = {
}
};
Tools.storage = {
id: "storage",
key: l10n("open.commandkey", storageStrings),
ordinal: 9,
accesskey: l10n("open.accesskey", storageStrings),
modifiers: "shift",
visibilityswitch: "devtools.storage.enabled",
icon: "chrome://browser/skin/devtools/tool-storage.svg",
invertIconForLightTheme: true,
url: "chrome://browser/content/devtools/storage.xul",
label: l10n("storage.label", storageStrings),
tooltip: l10n("storage.tooltip", storageStrings),
inMenu: true,
isTargetSupported: function(target) {
return target.isLocalTab ||
(target.client.traits.storageInspector && !target.isAddon);
},
build: function(iframeWindow, toolbox) {
let panel = new StoragePanel(iframeWindow, toolbox);
return panel.open();
}
};
Tools.scratchpad = {
id: "scratchpad",
ordinal: 9,
ordinal: 10,
visibilityswitch: "devtools.scratchpad.enabled",
icon: "chrome://browser/skin/devtools/tool-scratchpad.svg",
invertIconForLightTheme: true,
@ -352,6 +378,7 @@ let defaultTools = [
Tools.webAudioEditor,
Tools.jsprofiler,
Tools.netMonitor,
Tools.storage,
Tools.scratchpad
];

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

@ -23,6 +23,7 @@ DIRS += [
'shadereditor',
'shared',
'sourceeditor',
'storage',
'styleeditor',
'styleinspector',
'tilt',

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

@ -16,7 +16,7 @@ function test() {
"-H 'User-Agent: " + aDebuggee.navigator.userAgent + "'",
"-H 'Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8'",
"-H 'Accept-Language: " + aDebuggee.navigator.language + "'",
"-H 'Accept-Encoding: gzip, deflate'",
"--compressed",
"-H 'X-Custom-Header-1: Custom value'",
"-H 'X-Custom-Header-2: 8.8.8.8'",
"-H 'X-Custom-Header-3: Mon, 3 Mar 2014 11:11:11 GMT'",
@ -31,7 +31,7 @@ function test() {
'-H "User-Agent: ' + aDebuggee.navigator.userAgent + '"',
'-H "Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"',
'-H "Accept-Language: ' + aDebuggee.navigator.language + '"',
'-H "Accept-Encoding: gzip, deflate"',
"--compressed",
'-H "X-Custom-Header-1: Custom value"',
'-H "X-Custom-Header-2: 8.8.8.8"',
'-H "X-Custom-Header-3: Mon, 3 Mar 2014 11:11:11 GMT"',

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

@ -57,6 +57,13 @@ var Resource = Class({
*/
get hasChildren() { return this.children && this.children.size > 0; },
/**
* Is this Resource the root (top level for the store)?
*/
get isRoot() {
return !this.parent
},
/**
* Sorted array of children for display
*/

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

@ -84,6 +84,9 @@ var ResourceContainer = Class({
evt.stopPropagation();
}, true);
if (!this.resource.isRoot) {
this.expanded = false;
}
this.update();
},

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

@ -35,8 +35,14 @@ let test = asyncTest(function*() {
function selectFileFirstLoad(projecteditor, resource) {
ok (resource && resource.path, "A valid resource has been passed in for selection " + (resource && resource.path));
projecteditor.projectTree.selectResource(resource);
let container = projecteditor.projectTree.getViewContainer(resource);
if (resource.isRoot) {
ok (container.expanded, "The root directory is expanded by default.");
return;
}
if (resource.isDir) {
ok (!container.expanded, "A directory is not expanded by default.");
return;
}

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

@ -120,6 +120,10 @@ this.Curl = {
}
for (let i = 0; i < headers.length; i++) {
let header = headers[i];
if (header.name === "Accept-Encoding"){
command.push("--compressed");
continue;
}
if (ignoredHeaders.has(header.name)) {
continue;
}

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

@ -38,7 +38,7 @@ const MAX_VISIBLE_STRING_SIZE = 100;
* entry in the table. Default: name.
* - emptyText: text to display when no entries in the table to display.
* - highlightUpdated: true to highlight the changed/added row.
* - removableColumns: Whether columns are removeable. If set to true,
* - removableColumns: Whether columns are removeable. If set to false,
* the context menu in the headers will not appear.
* - firstColumn: key of the first column that should appear.
*/
@ -55,7 +55,7 @@ function TableWidget(node, options={}) {
this.uniqueId = uniqueId || "name";
this.firstColumn = firstColumn || "";
this.highlightUpdated = highlightUpdated || false;
this.removableColumns = removableColumns || false;
this.removableColumns = removableColumns !== false;
this.tbody = this.document.createElementNS(XUL_NS, "hbox");
this.tbody.className = "table-widget-body theme-body";
@ -276,7 +276,7 @@ TableWidget.prototype = {
item = item[this.uniqueId];
}
return item == this.selectedRow[this.uniqueId];
return this.selectedRow && item == this.selectedRow[this.uniqueId];
},
/**
@ -687,6 +687,8 @@ Column.prototype = {
/**
* Event handler for the command event coming from the header context menu.
* Toggles the column if it was requested by the user.
* When called explicitly without parameters, it toggles the corresponding
* column.
*
* @param {string} event
* The name of the event. i.e. EVENTS.HEADER_CONTEXT_MENU
@ -696,6 +698,11 @@ Column.prototype = {
* true if the column is visible
*/
toggleColumn: function(event, id, checked) {
if (arguments.length == 0) {
// Act like a toggling method when called with no params
id = this.id;
checked = this.wrapper.hasAttribute("hidden");
}
if (id != this.id) {
return;
}
@ -960,6 +967,8 @@ Cell.prototype = {
*/
flash: function() {
this.label.classList.remove("flash-out");
// Cause a reflow so that the animation retriggers on adding back the class
let a = this.label.parentNode.offsetWidth;
this.label.classList.add("flash-out");
},

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

@ -65,7 +65,7 @@ TreeWidget.prototype = {
this._selectedLabel = this._selectedItem = null;
return;
}
if (!typeof id == "array") {
if (!Array.isArray(id)) {
return;
}
this._selectedLabel = this.root.setSelectedItem(id);

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

@ -0,0 +1,12 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
BROWSER_CHROME_MANIFESTS += ['test/browser.ini']
EXTRA_JS_MODULES.devtools.storage += [
'panel.js',
'ui.js'
]

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

@ -0,0 +1,83 @@
/* -*- Mode: Javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* 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/. */
const {Cc, Ci, Cu, Cr} = require("chrome");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/Promise.jsm");
let EventEmitter = require("devtools/toolkit/event-emitter");
loader.lazyGetter(this, "StorageFront",
() => require("devtools/server/actors/storage").StorageFront);
loader.lazyGetter(this, "StorageUI",
() => require("devtools/storage/ui").StorageUI);
this.StoragePanel = function StoragePanel(panelWin, toolbox) {
EventEmitter.decorate(this);
this._toolbox = toolbox;
this._target = toolbox.target;
this._panelWin = panelWin;
this.destroy = this.destroy.bind(this);
}
exports.StoragePanel = StoragePanel;
StoragePanel.prototype = {
get target() this._toolbox.target,
get panelWindow() this._panelWin,
/**
* open is effectively an asynchronous constructor
*/
open: function() {
let targetPromise;
// We always interact with the target as if it were remote
if (!this.target.isRemote) {
targetPromise = this.target.makeRemote();
} else {
targetPromise = Promise.resolve(this.target);
}
return targetPromise.then(() => {
this.target.on("close", this.destroy);
this._front = new StorageFront(this.target.client, this.target.form);
this.UI = new StorageUI(this._front, this._target, this._panelWin);
this.isReady = true;
this.emit("ready");
return this;
}, console.error);
},
/**
* Destroy the style editor.
*/
destroy: function() {
if (!this._destroyed) {
this.UI.destroy();
this._destroyed = true;
this._target.off("close", this.destroy);
this._target = null;
this._toolbox = null;
this._panelDoc = null;
}
return Promise.resolve(null);
},
}
XPCOMUtils.defineLazyGetter(StoragePanel.prototype, "strings",
function () {
return Services.strings.createBundle(
"chrome://browser/locale/devtools/storage.properties");
});

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

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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/. -->
<?xml-stylesheet href="chrome://browser/skin/" type="text/css"?>
<?xml-stylesheet href="chrome://browser/content/devtools/widgets.css" type="text/css"?>
<?xml-stylesheet href="chrome://browser/skin/devtools/common.css" type="text/css"?>
<?xml-stylesheet href="chrome://browser/skin/devtools/widgets.css" type="text/css"?>
<?xml-stylesheet href="chrome://browser/skin/devtools/storage.css" type="text/css"?>
<?xul-overlay href="chrome://global/content/editMenuOverlay.xul"?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript;version=1.8"
src="chrome://browser/content/devtools/theme-switching.js"/>
<script type="text/javascript" src="chrome://global/content/globalOverlay.js"/>
<commandset id="editMenuCommands"/>
<box flex="1" class="devtools-responsive-container theme-body">
<vbox id="storage-tree"/>
<splitter class="devtools-side-splitter"/>
<vbox id="storage-table" class="theme-sidebar" flex="1"/>
<splitter class="devtools-side-splitter"/>
<vbox id="storage-sidebar" class="devtools-sidebar-tabs" hidden="true">
<vbox flex="1"/>
</vbox>
</box>
</window>

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

@ -0,0 +1,15 @@
[DEFAULT]
skip-if = e10s # Bug 1049888 - storage actors do not work in e10s for now
subsuite = devtools
support-files =
storage-complex-values.html
storage-listings.html
storage-secured-iframe.html
storage-unsecured-iframe.html
storage-updates.html
head.js
[browser_storage_basic.js]
[browser_storage_dynamic_updates.js]
[browser_storage_sidebar.js]
[browser_storage_values.js]

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

@ -0,0 +1,114 @@
/* 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/. */
// Basic test to assert that the storage tree and table corresponding to each
// item in the storage tree is correctly displayed
// Entries that should be present in the tree for this test
// Format for each entry in the array :
// [
// ["path", "to", "tree", "item"], - The path to the tree item to click formed
// by id of each item
// ["key_value1", "key_value2", ...] - The value of the first (unique) column
// for each row in the table corresponding
// to the tree item selected.
// ]
// These entries are formed by the cookies, local storage, session storage and
// indexedDB entries created in storage-listings.html,
// storage-secured-iframe.html and storage-unsecured-iframe.html
const storeItems = [
[["cookies", "test1.example.org"],
["c1", "cs2", "c3", "uc1"]],
[["cookies", "sectest1.example.org"],
["uc1", "cs2", "sc1"]],
[["localStorage", "http://test1.example.org"],
["ls1", "ls2"]],
[["localStorage", "http://sectest1.example.org"],
["iframe-u-ls1"]],
[["localStorage", "https://sectest1.example.org"],
["iframe-s-ls1"]],
[["sessionStorage", "http://test1.example.org"],
["ss1"]],
[["sessionStorage", "http://sectest1.example.org"],
["iframe-u-ss1", "iframe-u-ss2"]],
[["sessionStorage", "https://sectest1.example.org"],
["iframe-s-ss1"]],
[["indexedDB", "http://test1.example.org"],
["idb1", "idb2"]],
[["indexedDB", "http://test1.example.org", "idb1"],
["obj1", "obj2"]],
[["indexedDB", "http://test1.example.org", "idb2"],
["obj3"]],
[["indexedDB", "http://test1.example.org", "idb1", "obj1"],
[1, 2, 3]],
[["indexedDB", "http://test1.example.org", "idb1", "obj2"],
[1]],
[["indexedDB", "http://test1.example.org", "idb2", "obj3"],
[]],
[["indexedDB", "http://sectest1.example.org"],
[]],
[["indexedDB", "https://sectest1.example.org"],
["idb-s1", "idb-s2"]],
[["indexedDB", "https://sectest1.example.org", "idb-s1"],
["obj-s1"]],
[["indexedDB", "https://sectest1.example.org", "idb-s2"],
["obj-s2"]],
[["indexedDB", "https://sectest1.example.org", "idb-s1", "obj-s1"],
[6, 7]],
[["indexedDB", "https://sectest1.example.org", "idb-s2", "obj-s2"],
[16]],
];
/**
* Test that the desired number of tree items are present
*/
function testTree() {
let doc = gPanelWindow.document;
for (let item of storeItems) {
ok(doc.querySelector("[data-id='" + JSON.stringify(item[0]) + "']"),
"Tree item " + item[0] + " should be present in the storage tree");
}
}
/**
* Test that correct table entries are shown for each of the tree item
*/
let testTables = Task.async(function*() {
let doc = gPanelWindow.document;
// Expand all nodes so that the synthesized click event actually works
gUI.tree.expandAll();
// First tree item is already selected so no clicking and waiting for update
for (let id of storeItems[0][1]) {
ok(doc.querySelector(".table-widget-cell[data-id='" + id + "']"),
"Table item " + id + " should be present");
}
// Click rest of the tree items and wait for the table to be updated
for (let item of storeItems.slice(1)) {
selectTreeItem(item[0]);
yield gUI.once("store-objects-updated");
// Check whether correct number of items are present in the table
is(doc.querySelectorAll(
".table-widget-wrapper:first-of-type .table-widget-cell"
).length, item[1].length, "Number of items in table is correct");
// Check if all the desired items are present in the table
for (let id of item[1]) {
ok(doc.querySelector(".table-widget-cell[data-id='" + id + "']"),
"Table item " + id + " should be present");
}
}
});
let startTest = Task.async(function*() {
testTree();
yield testTables();
finishTests();
});
function test() {
openTabAndSetupStorage(MAIN_DOMAIN + "storage-listings.html").then(startTest);
}

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

@ -0,0 +1,211 @@
/* 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/. */
let testUpdates = Task.async(function*() {
let $ = id => gPanelWindow.document.querySelector(id);
let $$ = sel => gPanelWindow.document.querySelectorAll(sel);
gUI.tree.expandAll();
ok(gUI.sidebar.hidden, "Sidebar is initially hidden");
selectTableItem("c1");
yield gUI.once("sidebar-updated");
// test that value is something initially
let initialValue = [[
{name: "c1", value: "1.2.3.4.5.6.7"},
{name: "c1.path", value: "/browser"}
],[
{name: "c1", value: "Array"},
{name: "c1.0", value: "1"},
{name: "c1.6", value: "7"}
]];
// test that value is something initially
let finalValue = [[
{name: "c1", value: '{"foo": 4,"bar":6}'},
{name: "c1.path", value: "/browser"}
],[
{name: "c1", value: "Object"},
{name: "c1.foo", value: "4"},
{name: "c1.bar", value: "6"}
]];
// Check that sidebar shows correct initial value
yield findVariableViewProperties(initialValue[0], false);
yield findVariableViewProperties(initialValue[1], true);
// Check if table shows correct initial value
ok($("#value [data-id='c1'].table-widget-cell"), "cell is present");
is($("#value [data-id='c1'].table-widget-cell").value, "1.2.3.4.5.6.7",
"correct initial value in table");
gWindow.addCookie("c1", '{"foo": 4,"bar":6}', "/browser");
yield gUI.once("sidebar-updated");
yield findVariableViewProperties(finalValue[0], false);
yield findVariableViewProperties(finalValue[1], true);
ok($("#value [data-id='c1'].table-widget-cell"), "cell is present after update");
is($("#value [data-id='c1'].table-widget-cell").value, '{"foo": 4,"bar":6}',
"correct final value in table");
// Add a new entry
is($$("#value .table-widget-cell").length, 2,
"Correct number of rows before update 0");
gWindow.addCookie("c3", "booyeah");
// Wait once for update and another time for value fetching
yield gUI.once("store-objects-updated");
yield gUI.once("store-objects-updated");
is($$("#value .table-widget-cell").length, 3,
"Correct number of rows after update 1");
// Add another
gWindow.addCookie("c4", "booyeah");
// Wait once for update and another time for value fetching
yield gUI.once("store-objects-updated");
yield gUI.once("store-objects-updated");
is($$("#value .table-widget-cell").length, 4,
"Correct number of rows after update 2");
// Removing cookies
gWindow.removeCookie("c1", "/browser");
yield gUI.once("sidebar-updated");
is($$("#value .table-widget-cell").length, 3,
"Correct number of rows after delete update 3");
ok(!$("#c1"), "Correct row got deleted");
ok(!gUI.sidebar.hidden, "Sidebar still visible for next row");
// Check if next element's value is visible in sidebar
yield findVariableViewProperties([{name: "c2", value: "foobar"}]);
// Keep deleting till no rows
gWindow.removeCookie("c3");
yield gUI.once("store-objects-updated");
is($$("#value .table-widget-cell").length, 2,
"Correct number of rows after delete update 4");
// Check if next element's value is visible in sidebar
yield findVariableViewProperties([{name: "c2", value: "foobar"}]);
gWindow.removeCookie("c2", "/browser");
yield gUI.once("sidebar-updated");
yield findVariableViewProperties([{name: "c4", value: "booyeah"}]);
is($$("#value .table-widget-cell").length, 1,
"Correct number of rows after delete update 5");
gWindow.removeCookie("c4");
yield gUI.once("store-objects-updated");
is($$("#value .table-widget-cell").length, 0,
"Correct number of rows after delete update 6");
ok(gUI.sidebar.hidden, "Sidebar is hidden when no rows");
// Testing in local storage
selectTreeItem(["localStorage", "http://test1.example.org"]);
yield gUI.once("store-objects-updated");
is($$("#value .table-widget-cell").length, 7,
"Correct number of rows after delete update 7");
ok($(".table-widget-cell[data-id='ls4']"), "ls4 exists before deleting");
gWindow.localStorage.removeItem("ls4");
yield gUI.once("store-objects-updated");
is($$("#value .table-widget-cell").length, 6,
"Correct number of rows after delete update 8");
ok(!$(".table-widget-cell[data-id='ls4']"),
"ls4 does not exists after deleting");
gWindow.localStorage.setItem("ls4", "again");
yield gUI.once("store-objects-updated");
yield gUI.once("store-objects-updated");
is($$("#value .table-widget-cell").length, 7,
"Correct number of rows after delete update 9");
ok($(".table-widget-cell[data-id='ls4']"),
"ls4 came back after adding it again");
// Updating a row
gWindow.localStorage.setItem("ls2", "ls2-changed");
yield gUI.once("store-objects-updated");
yield gUI.once("store-objects-updated");
is($("#value [data-id='ls2']").value, "ls2-changed",
"Value got updated for local storage");
// Testing in session storage
selectTreeItem(["sessionStorage", "http://test1.example.org"]);
yield gUI.once("store-objects-updated");
is($$("#value .table-widget-cell").length, 3,
"Correct number of rows for session storage");
gWindow.sessionStorage.setItem("ss4", "new-item");
yield gUI.once("store-objects-updated");
yield gUI.once("store-objects-updated");
is($$("#value .table-widget-cell").length, 4,
"Correct number of rows after session storage update");
// deleting item
gWindow.sessionStorage.removeItem("ss3");
yield gUI.once("store-objects-updated");
gWindow.sessionStorage.removeItem("ss1");
yield gUI.once("store-objects-updated");
is($$("#value .table-widget-cell").length, 2,
"Correct number of rows after removing items from session storage");
selectTableItem("ss2");
yield gUI.once("sidebar-updated");
ok(!gUI.sidebar.hidden, "sidebar is visible");
// Checking for correct value in sidebar before update
yield findVariableViewProperties([{name: "ss2", value: "foobar"}]);
gWindow.sessionStorage.setItem("ss2", "changed=ss2");
yield gUI.once("sidebar-updated");
is($("#value [data-id='ss2']").value, "changed=ss2",
"Value got updated for session storage in the table");
yield findVariableViewProperties([{name: "ss2", value: "changed=ss2"}]);
});
let startTest = Task.async(function*() {
yield testUpdates();
finishTests();
});
function test() {
openTabAndSetupStorage(MAIN_DOMAIN + "storage-updates.html").then(startTest);
}

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

@ -0,0 +1,67 @@
/* 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/. */
// Test to verify that the sidebar opens, closes and updates
// This test is not testing the values in the sidebar, being tested in _values
// Format: [
// <id of the table item to click> or <id array for tree item to select> or
// null to press Escape,
// <do we wait for the async "sidebar-updated" event>,
// <is the sidebar open>
// ]
const testCases = [
[["cookies", "sectest1.example.org"], 0, 0],
["cs2", 1, 1],
[null, 0, 0],
["cs2", 1, 1],
["uc1", 1, 1],
["uc1", 0, 1],
[["localStorage", "http://sectest1.example.org"], 0, 0],
["iframe-u-ls1", 1, 1],
["iframe-u-ls1", 0, 1],
[null, 0, 0],
[["sessionStorage", "http://test1.example.org"], 0, 0],
["ss1", 1, 1],
[null, 0, 0],
[["indexedDB", "http://test1.example.org"], 0, 0],
["idb2", 1, 1],
[["indexedDB", "http://test1.example.org", "idb2", "obj3"], 0, 0],
[["indexedDB", "https://sectest1.example.org", "idb-s2"], 0, 0],
["obj-s2", 1, 1],
[null, 0, 0],
[null, 0, 0],
["obj-s2", 1, 1],
[null, 0, 0],
];
let testSidebar = Task.async(function*() {
let doc = gPanelWindow.document;
for (let item of testCases) {
info("clicking for item " + item);
if (Array.isArray(item[0])) {
selectTreeItem(item[0]);
yield gUI.once("store-objects-updated");
}
else if (item[0]) {
selectTableItem(item[0]);
}
else {
EventUtils.sendKey("ESCAPE", gPanelWindow);
}
if (item[1]) {
yield gUI.once("sidebar-updated");
}
is(!item[2], gUI.sidebar.hidden, "Correct visibility state of sidebar");
}
});
let startTest = Task.async(function*() {
yield testSidebar();
finishTests();
});
function test() {
openTabAndSetupStorage(MAIN_DOMAIN + "storage-listings.html").then(startTest);
}

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

@ -0,0 +1,143 @@
/* 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/. */
// Test to verify that the values shown in sidebar are correct
// Format: [
// <id of the table item to click> or <id array for tree item to select> or
// null do click nothing,
// null to skip checking value in variables view or a key value pair object
// which will be asserted to exist in the storage sidebar,
// true if the check is to be made in the parsed value section
// ]
const testCases = [
["cs2", [
{name: "cs2", value: "sessionCookie"},
{name: "cs2.path", value: "/"},
{name: "cs2.isDomain", value: "true"},
{name: "cs2.isHttpOnly", value: "false"},
{name: "cs2.host", value: ".example.org"},
{name: "cs2.expires", value: "Session"},
{name: "cs2.isSecure", value: "false"},
]],
["c1", [
{name: "c1", value: JSON.stringify(["foo", "Bar", {foo: "Bar"}])},
{name: "c1.path", value: "/browser"},
{name: "c1.isDomain", value: "false"},
{name: "c1.isHttpOnly", value: "false"},
{name: "c1.host", value: "test1.example.org"},
{name: "c1.expires", value: new Date(2000000000000).toLocaleString()},
{name: "c1.isSecure", value: "false"},
]],
[/*"c1"*/, [
{name: "c1", value: "Array"},
{name: "c1.0", value: "foo"},
{name: "c1.1", value: "Bar"},
{name: "c1.2", value: "Object"},
{name: "c1.2.foo", value: "Bar"},
], true],
[["localStorage", "http://test1.example.org"]],
["ls2", [
{name: "ls2", value: "foobar-2"}
]],
["ls1", [
{name: "ls1", value: JSON.stringify({
es6: "for", the: "win", baz: [0, 2, 3, {
deep: "down",
nobody: "cares"
}]})}
]],
[/*ls1*/, [
{name: "ls1", value: "Object"},
{name: "ls1.es6", value: "for"},
{name: "ls1.the", value: "win"},
{name: "ls1.baz", value: "Array"},
{name: "ls1.baz.0", value: "0"},
{name: "ls1.baz.1", value: "2"},
{name: "ls1.baz.2", value: "3"},
{name: "ls1.baz.3", value: "Object"},
{name: "ls1.baz.3.deep", value: "down"},
{name: "ls1.baz.3.nobody", value: "cares"},
], true],
["ls3", [
{name: "ls3", "value": "http://foobar.com/baz.php"}
]],
[/*ls3*/, [
{name: "ls3", "value": "http://foobar.com/baz.php", dontMatch: true}
], true],
[["sessionStorage", "http://test1.example.org"]],
["ss1", [
{name: "ss1", value: "This#is#an#array"}
]],
[/*ss1*/, [
{name: "ss1", value: "Array"},
{name: "ss1.0", value: "This"},
{name: "ss1.1", value: "is"},
{name: "ss1.2", value: "an"},
{name: "ss1.3", value: "array"},
], true],
["ss2", [
{name: "ss2", value: "Array"},
{name: "ss2.0", value: "This"},
{name: "ss2.1", value: "is"},
{name: "ss2.2", value: "another"},
{name: "ss2.3", value: "array"},
], true],
["ss3", [
{name: "ss3", value: "Object"},
{name: "ss3.this", value: "is"},
{name: "ss3.an", value: "object"},
{name: "ss3.foo", value: "bar"},
], true],
[["indexedDB", "http://test1.example.org", "idb1", "obj1"]],
[1, [
{name: 1, value: JSON.stringify({id: 1, name: "foo", email: "foo@bar.com"})}
]],
[/*1*/, [
{name: "1.id", value: "1"},
{name: "1.name", value: "foo"},
{name: "1.email", value: "foo@bar.com"},
], true],
[["indexedDB", "http://test1.example.org", "idb1", "obj2"]],
[1, [
{name: 1, value: JSON.stringify({
id2: 1, name: "foo", email: "foo@bar.com", extra: "baz"
})}
]],
[/*1*/, [
{name: "1.id2", value: "1"},
{name: "1.name", value: "foo"},
{name: "1.email", value: "foo@bar.com"},
{name: "1.extra", value: "baz"},
], true]
];
let testValues = Task.async(function*() {
gUI.tree.expandAll();
let doc = gPanelWindow.document;
for (let item of testCases) {
info("clicking for item " + item);
if (Array.isArray(item[0])) {
selectTreeItem(item[0]);
yield gUI.once("store-objects-updated");
continue;
}
else if (item[0]) {
selectTableItem(item[0]);
}
if (item[0] && item[1]) {
yield gUI.once("sidebar-updated");
}
yield findVariableViewProperties(item[1], item[2]);
}
});
let startTest = Task.async(function*() {
yield testValues();
finishTests();
});
function test() {
openTabAndSetupStorage(MAIN_DOMAIN + "storage-complex-values.html").then(startTest);
}

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

@ -0,0 +1,499 @@
/* 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/. */
"use strict";
let tempScope = {};
Cu.import("resource://gre/modules/devtools/Loader.jsm", tempScope);
Cu.import("resource://gre/modules/devtools/Console.jsm", tempScope);
const console = tempScope.console;
const devtools = tempScope.devtools;
tempScope = null;
const require = devtools.require;
const TargetFactory = devtools.TargetFactory;
const SPLIT_CONSOLE_PREF = "devtools.toolbox.splitconsoleEnabled";
const STORAGE_PREF = "devtools.storage.enabled";
const PATH = "browser/browser/devtools/storage/test/";
const MAIN_DOMAIN = "http://test1.example.org/" + PATH;
const ALT_DOMAIN = "http://sectest1.example.org/" + PATH;
const ALT_DOMAIN_SECURED = "https://sectest1.example.org:443/" + PATH;
let {Promise: promise} = Cu.import("resource://gre/modules/Promise.jsm", {});
waitForExplicitFinish();
let gToolbox, gPanelWindow, gWindow, gUI;
Services.prefs.setBoolPref(STORAGE_PREF, true);
gDevTools.testing = true;
registerCleanupFunction(() => {
gToolbox = gPanelWindow = gWindow = gUI = null;
Services.prefs.clearUserPref(STORAGE_PREF);
Services.prefs.clearUserPref(SPLIT_CONSOLE_PREF);
gDevTools.testing = false;
while (gBrowser.tabs.length > 1) {
gBrowser.removeCurrentTab();
}
});
/**
* Add a new test tab in the browser and load the given url.
*
* @param {String} url The url to be loaded in the new tab
*
* @return a promise that resolves to the content window when the url is loaded
*/
function addTab(url) {
info("Adding a new tab with URL: '" + url + "'");
let def = promise.defer();
// Bug 921935 should bring waitForFocus() support to e10s, which would
// probably cover the case of the test losing focus when the page is loading.
// For now, we just make sure the window is focused.
window.focus();
let tab = window.gBrowser.selectedTab = window.gBrowser.addTab(url);
let linkedBrowser = tab.linkedBrowser;
linkedBrowser.addEventListener("load", function onload(event) {
if (event.originalTarget.location.href != url) {
return;
}
linkedBrowser.removeEventListener("load", onload, true);
info("URL '" + url + "' loading complete");
def.resolve(tab.linkedBrowser.contentWindow);
}, true);
return def.promise;
}
/**
* Opens the given url in a new tab, then sets up the page by waiting for
* all cookies, indexedDB items etc. to be created; Then opens the storage
* inspector and waits for the storage tree and table to be populated
*
* @param url {String} The url to be opened in the new tab
*
* @return {Promise} A promise that resolves after storage inspector is ready
*/
let openTabAndSetupStorage = Task.async(function*(url) {
/**
* This method iterates over iframes in a window and setups the indexed db
* required for this test.
*/
let setupIDBInFrames = (w, i, c) => {
if (w[i] && w[i].idbGenerator) {
w[i].setupIDB = w[i].idbGenerator(() => setupIDBInFrames(w, i + 1, c));
w[i].setupIDB.next();
}
else if (w[i] && w[i + 1]) {
setupIDBInFrames(w, i + 1, c);
}
else {
c();
}
};
let content = yield addTab(url);
let def = promise.defer();
// Setup the indexed db in main window.
gWindow = content.wrappedJSObject;
if (gWindow.idbGenerator) {
gWindow.setupIDB = gWindow.idbGenerator(() => {
setupIDBInFrames(gWindow, 0, () => {
def.resolve();
});
});
gWindow.setupIDB.next();
yield def.promise;
}
// open storage inspector
return yield openStoragePanel();
});
/**
* Open the toolbox, with the storage tool visible.
*
* @param cb {Function} Optional callback, if you don't want to use the returned
* promise
*
* @return {Promise} a promise that resolves when the storage inspector is ready
*/
let openStoragePanel = Task.async(function*(cb) {
info("Opening the storage inspector");
let target = TargetFactory.forTab(gBrowser.selectedTab);
let storage, toolbox;
// Checking if the toolbox and the storage are already loaded
// The storage-updated event should only be waited for if the storage
// isn't loaded yet
toolbox = gDevTools.getToolbox(target);
if (toolbox) {
storage = toolbox.getPanel("storage");
if (storage) {
gPanelWindow = storage.panelWindow;
gUI = storage.UI;
gToolbox = toolbox;
info("Toolbox and storage already open");
if (cb) {
return cb(storage, toolbox);
} else {
return {
toolbox: toolbox,
storage: storage
};
}
}
}
info("Opening the toolbox");
toolbox = yield gDevTools.showToolbox(target, "storage");
storage = toolbox.getPanel("storage");
gPanelWindow = storage.panelWindow;
gUI = storage.UI;
gToolbox = toolbox;
info("Waiting for the stores to update");
yield gUI.once("store-objects-updated");
yield waitForToolboxFrameFocus(toolbox);
if (cb) {
return cb(storage, toolbox);
} else {
return {
toolbox: toolbox,
storage: storage
};
}
});
/**
* Wait for the toolbox frame to receive focus after it loads
*
* @param toolbox {Toolbox}
*
* @return a promise that resolves when focus has been received
*/
function waitForToolboxFrameFocus(toolbox) {
info("Making sure that the toolbox's frame is focused");
let def = promise.defer();
let win = toolbox.frame.contentWindow;
waitForFocus(def.resolve, win);
return def.promise;
}
/**
* Forces GC, CC and Shrinking GC to get rid of disconnected docshells and
* windows.
*/
function forceCollections() {
Cu.forceGC();
Cu.forceCC();
Cu.forceShrinkingGC();
}
/**
* Cleans up and finishes the test
*/
function finishTests() {
// Cleanup so that indexed db created from this test do not interfere next ones
/**
* This method iterates over iframes in a window and clears the indexed db
* created by this test.
*/
let clearIDB = (w, i, c) => {
if (w[i] && w[i].clear) {
w[i].clearIterator = w[i].clear(() => clearIDB(w, i + 1, c));
w[i].clearIterator.next();
}
else if (w[i] && w[i + 1]) {
clearIDB(w, i + 1, c);
}
else {
c();
}
};
gWindow.clearIterator = gWindow.clear(() => {
clearIDB(gWindow, 0, () => {
// Forcing GC/CC to get rid of docshells and windows created by this test.
forceCollections();
finish();
});
});
gWindow.clearIterator.next();
}
// Sends a click event on the passed DOM node in an async manner
function click(node) {
node.scrollIntoView()
executeSoon(() => EventUtils.synthesizeMouseAtCenter(node, {}, gPanelWindow));
}
/**
* Recursively expand the variables view up to a given property.
*
* @param aOptions
* Options for view expansion:
* - rootVariable: start from the given scope/variable/property.
* - expandTo: string made up of property names you want to expand.
* For example: "body.firstChild.nextSibling" given |rootVariable:
* document|.
* @return object
* A promise that is resolved only when the last property in |expandTo|
* is found, and rejected otherwise. Resolution reason is always the
* last property - |nextSibling| in the example above. Rejection is
* always the last property that was found.
*/
function variablesViewExpandTo(aOptions) {
let root = aOptions.rootVariable;
let expandTo = aOptions.expandTo.split(".");
let lastDeferred = promise.defer();
function getNext(aProp) {
let name = expandTo.shift();
let newProp = aProp.get(name);
if (expandTo.length > 0) {
ok(newProp, "found property " + name);
if (newProp && newProp.expand) {
newProp.expand();
getNext(newProp);
}
else {
lastDeferred.reject(aProp);
}
}
else {
if (newProp) {
lastDeferred.resolve(newProp);
}
else {
lastDeferred.reject(aProp);
}
}
}
function fetchError(aProp) {
lastDeferred.reject(aProp);
}
if (root && root.expand) {
root.expand();
getNext(root);
}
else {
lastDeferred.resolve(root)
}
return lastDeferred.promise;
}
/**
* Find variables or properties in a VariablesView instance.
*
* @param array aRules
* The array of rules you want to match. Each rule is an object with:
* - name (string|regexp): property name to match.
* - value (string|regexp): property value to match.
* - dontMatch (boolean): make sure the rule doesn't match any property.
* @param boolean aParsed
* true if we want to test the rules in the parse value section of the
* storage sidebar
* @return object
* A promise object that is resolved when all the rules complete
* matching. The resolved callback is given an array of all the rules
* you wanted to check. Each rule has a new property: |matchedProp|
* which holds a reference to the Property object instance from the
* VariablesView. If the rule did not match, then |matchedProp| is
* undefined.
*/
function findVariableViewProperties(aRules, aParsed) {
// Initialize the search.
function init() {
// If aParsed is true, we are checking rules in the parsed value section of
// the storage sidebar. That scope uses a blank variable as a placeholder
// Thus, adding a blank parent to each name
if (aParsed) {
aRules = aRules.map(({name, value, dontMatch}) => {
return {name: "." + name, value, dontMatch}
});
}
// Separate out the rules that require expanding properties throughout the
// view.
let expandRules = [];
let rules = aRules.filter((aRule) => {
if (typeof aRule.name == "string" && aRule.name.indexOf(".") > -1) {
expandRules.push(aRule);
return false;
}
return true;
});
// Search through the view those rules that do not require any properties to
// be expanded. Build the array of matchers, outstanding promises to be
// resolved.
let outstanding = [];
finder(rules, gUI.view, outstanding);
// Process the rules that need to expand properties.
let lastStep = processExpandRules.bind(null, expandRules);
// Return the results - a promise resolved to hold the updated aRules array.
let returnResults = onAllRulesMatched.bind(null, aRules);
return promise.all(outstanding).then(lastStep).then(returnResults);
}
function onMatch(aProp, aRule, aMatched) {
if (aMatched && !aRule.matchedProp) {
aRule.matchedProp = aProp;
}
}
function finder(aRules, aView, aPromises) {
for (let scope of aView) {
for (let [id, prop] of scope) {
for (let rule of aRules) {
let matcher = matchVariablesViewProperty(prop, rule);
aPromises.push(matcher.then(onMatch.bind(null, prop, rule)));
}
}
}
}
function processExpandRules(aRules) {
let rule = aRules.shift();
if (!rule) {
return promise.resolve(null);
}
let deferred = promise.defer();
let expandOptions = {
rootVariable: gUI.view.getScopeAtIndex(aParsed ? 1: 0),
expandTo: rule.name
};
variablesViewExpandTo(expandOptions).then(function onSuccess(aProp) {
let name = rule.name;
let lastName = name.split(".").pop();
rule.name = lastName;
let matched = matchVariablesViewProperty(aProp, rule);
return matched.then(onMatch.bind(null, aProp, rule)).then(function() {
rule.name = name;
});
}, function onFailure() {
return promise.resolve(null);
}).then(processExpandRules.bind(null, aRules)).then(function() {
deferred.resolve(null);
});
return deferred.promise;
}
function onAllRulesMatched(aRules) {
for (let rule of aRules) {
let matched = rule.matchedProp;
if (matched && !rule.dontMatch) {
ok(true, "rule " + rule.name + " matched for property " + matched.name);
}
else if (matched && rule.dontMatch) {
ok(false, "rule " + rule.name + " should not match property " +
matched.name);
}
else {
ok(rule.dontMatch, "rule " + rule.name + " did not match any property");
}
}
return aRules;
}
return init();
}
/**
* Check if a given Property object from the variables view matches the given
* rule.
*
* @param object aProp
* The variable's view Property instance.
* @param object aRule
* Rules for matching the property. See findVariableViewProperties() for
* details.
* @return object
* A promise that is resolved when all the checks complete. Resolution
* result is a boolean that tells your promise callback the match
* result: true or false.
*/
function matchVariablesViewProperty(aProp, aRule) {
function resolve(aResult) {
return promise.resolve(aResult);
}
if (!aProp) {
return resolve(false);
}
if (aRule.name) {
let match = aRule.name instanceof RegExp ?
aRule.name.test(aProp.name) :
aProp.name == aRule.name;
if (!match) {
return resolve(false);
}
}
if ("value" in aRule) {
let displayValue = aProp.displayValue;
if (aProp.displayValueClassName == "token-string") {
displayValue = displayValue.substring(1, displayValue.length - 1);
}
let match = aRule.value instanceof RegExp ?
aRule.value.test(displayValue) :
displayValue == aRule.value;
if (!match) {
info("rule " + aRule.name + " did not match value, expected '" +
aRule.value + "', found '" + displayValue + "'");
return resolve(false);
}
}
return resolve(true);
}
/**
* Click selects a row in the table.
*
* @param {[String]} ids
* The array id of the item in the tree
*/
function selectTreeItem(ids) {
// Expand tree as some/all items could be collapsed leading to click on an
// incorrect tree item
gUI.tree.expandAll();
click(gPanelWindow.document.querySelector("[data-id='" + JSON.stringify(ids) +
"'] > .tree-widget-item"));
}
/**
* Click selects a row in the table.
*
* @param {String} id
* The id of the row in the table widget
*/
function selectTableItem(id) {
click(gPanelWindow.document.querySelector(".table-widget-cell[data-id='" +
id + "']"));
}

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

@ -0,0 +1,8 @@
# -*- Mode: python; c-basic-offset: 4; indent-tabs-mode: nil; tab-width: 40 -*-
# vim: set filetype=python:
# 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/.
BROWSER_CHROME_MANIFESTS += ['browser.ini']

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

@ -0,0 +1,99 @@
<!DOCTYPE HTML>
<html>
<!--
Bug 970517 - Storage inspector front end - tests
-->
<head>
<meta charset="utf-8">
<title>Storage inspector test for correct values in the sidebar</title>
</head>
<body>
<script type="application/javascript;version=1.7">
let partialHostname = location.hostname.match(/^[^.]+(\..*)$/)[1];
let cookieExpiresTime = 2000000000000;
// Setting up some cookies to eat.
document.cookie = "c1=" + JSON.stringify([
"foo", "Bar", {
foo: "Bar"
}]) + "; expires=" + new Date(cookieExpiresTime).toGMTString() +
"; path=/browser";
document.cookie = "cs2=sessionCookie; path=/; domain=" + partialHostname;
// ... and some local storage items ..
var es6 = "for";
localStorage.setItem("ls1", JSON.stringify({
es6, the: "win", baz: [0, 2, 3, {
deep: "down",
nobody: "cares"
}]}));
localStorage.setItem("ls2", "foobar-2");
localStorage.setItem("ls3", "http://foobar.com/baz.php");
// ... and finally some session storage items too
sessionStorage.setItem("ss1", "This#is#an#array");
sessionStorage.setItem("ss2", "This~is~another~array");
sessionStorage.setItem("ss3", "this#is~an#object~foo#bar");
console.log("added cookies and stuff from main page");
function success(event) {
setupIDB.next(event);
}
window.idbGenerator = function*(callback) {
let request = indexedDB.open("idb1", 1);
request.onupgradeneeded = success;
request.onerror = function(e) {
throw new Error("error opening db connection");
};
let event = yield undefined;
let db = event.target.result;
let store1 = db.createObjectStore("obj1", { keyPath: "id" });
store1.createIndex("name", "name", { unique: false });
store1.createIndex("email", "email", { unique: true });
let store2 = db.createObjectStore("obj2", { keyPath: "id2" });
store1.add({id: 1, name: "foo", email: "foo@bar.com"}).onsuccess = success;
yield undefined;
store1.add({id: 2, name: "foo2", email: "foo2@bar.com"}).onsuccess = success;
yield undefined;
store1.add({id: 3, name: "foo2", email: "foo3@bar.com"}).onsuccess = success;
yield undefined;
store2.add({id2: 1, name: "foo", email: "foo@bar.com", extra: "baz"}).onsuccess = success;
yield undefined;
store1.transaction.oncomplete = success;
yield undefined;
db.close();
request = indexedDB.open("idb2", 1);
request.onupgradeneeded = success;
event = yield undefined;
let db2 = event.target.result;
let store3 = db2.createObjectStore("obj3", { keyPath: "id3" });
store3.createIndex("name2", "name2", { unique: true });
store3.transaction.oncomplete = success;
yield undefined;
db2.close();
console.log("added cookies and stuff from main page");
callback();
}
function successClear(event) {
clearIterator.next(event);
}
window.clear = function*(callback) {
document.cookie = "c1=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/browser";
document.cookie = "cs2=; expires=Thu, 01 Jan 1970 00:00:00 GMT";
localStorage.clear();
sessionStorage.clear();
indexedDB.deleteDatabase("idb1").onsuccess = successClear;
yield undefined;
indexedDB.deleteDatabase("idb2").onsuccess = successClear;
yield undefined;
console.log("removed cookies and stuff from main page");
callback();
}
</script>
</body>
</html>

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

@ -0,0 +1,94 @@
<!DOCTYPE HTML>
<html>
<!--
Bug 970517 - Storage inspector front end - tests
-->
<head>
<meta charset="utf-8">
<title>Storage inspector test for listing hosts and storages</title>
</head>
<body>
<iframe src="http://sectest1.example.org/browser/browser/devtools/storage/test/storage-unsecured-iframe.html"></iframe>
<iframe src="https://sectest1.example.org:443/browser/browser/devtools/storage/test/storage-secured-iframe.html"></iframe>
<script type="application/javascript;version=1.7">
let partialHostname = location.hostname.match(/^[^.]+(\..*)$/)[1];
let cookieExpiresTime1 = 2000000000000;
let cookieExpiresTime2 = 2000000001000;
// Setting up some cookies to eat.
document.cookie = "c1=foobar; expires=" +
new Date(cookieExpiresTime1).toGMTString() + "; path=/browser";
document.cookie = "cs2=sessionCookie; path=/; domain=" + partialHostname;
document.cookie = "c3=foobar-2; secure=true; expires=" +
new Date(cookieExpiresTime2).toGMTString() + "; path=/";
// ... and some local storage items ..
localStorage.setItem("ls1", "foobar");
localStorage.setItem("ls2", "foobar-2");
// ... and finally some session storage items too
sessionStorage.setItem("ss1", "foobar-3");
console.log("added cookies and stuff from main page");
function success(event) {
setupIDB.next(event);
}
window.idbGenerator = function*(callback) {
let request = indexedDB.open("idb1", 1);
request.onupgradeneeded = success;
request.onerror = function(e) {
throw new Error("error opening db connection");
};
let event = yield undefined;
let db = event.target.result;
let store1 = db.createObjectStore("obj1", { keyPath: "id" });
store1.createIndex("name", "name", { unique: false });
store1.createIndex("email", "email", { unique: true });
let store2 = db.createObjectStore("obj2", { keyPath: "id2" });
store1.add({id: 1, name: "foo", email: "foo@bar.com"}).onsuccess = success;
yield undefined;
store1.add({id: 2, name: "foo2", email: "foo2@bar.com"}).onsuccess = success;
yield undefined;
store1.add({id: 3, name: "foo2", email: "foo3@bar.com"}).onsuccess = success;
yield undefined;
store2.add({id2: 1, name: "foo", email: "foo@bar.com", extra: "baz"}).onsuccess = success;
yield undefined;
store1.transaction.oncomplete = success;
yield undefined;
db.close();
request = indexedDB.open("idb2", 1);
request.onupgradeneeded = success;
event = yield undefined;
let db2 = event.target.result;
let store3 = db2.createObjectStore("obj3", { keyPath: "id3" });
store3.createIndex("name2", "name2", { unique: true });
store3.transaction.oncomplete = success;
yield undefined;
db2.close();
console.log("added cookies and stuff from main page");
callback();
}
function successClear(event) {
clearIterator.next(event);
}
window.clear = function*(callback) {
document.cookie = "c1=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/browser";
document.cookie = "c3=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; secure=true";
document.cookie = "cs2=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=" + partialHostname;
localStorage.clear();
sessionStorage.clear();
indexedDB.deleteDatabase("idb1").onsuccess = successClear;
yield undefined;
indexedDB.deleteDatabase("idb2").onsuccess = successClear;
yield undefined;
console.log("removed cookies and stuff from main page");
callback();
}
</script>
</body>
</html>

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

@ -0,0 +1,71 @@
<!DOCTYPE HTML>
<html>
<!--
Iframe for testing multiple host detetion in storage actor
-->
<head>
<meta charset="utf-8">
</head>
<body>
<script type="application/javascript;version=1.7">
document.cookie = "sc1=foobar;";
localStorage.setItem("iframe-s-ls1", "foobar");
sessionStorage.setItem("iframe-s-ss1", "foobar-2");
function success(event) {
setupIDB.next(event);
}
window.idbGenerator = function*(callback) {
let request = indexedDB.open("idb-s1", 1);
request.onupgradeneeded = success;
request.onerror = function(e) {
throw new Error("error opening db connection");
};
let event = yield undefined;
let db = event.target.result;
let store1 = db.createObjectStore("obj-s1", { keyPath: "id" });
store1.add({id: 6, name: "foo", email: "foo@bar.com"}).onsuccess = success;
yield undefined;
store1.add({id: 7, name: "foo2", email: "foo2@bar.com"}).onsuccess = success;
yield undefined;
store1.transaction.oncomplete = success;
yield undefined;
db.close();
request = indexedDB.open("idb-s2", 1);
request.onupgradeneeded = success;
event = yield undefined;
let db2 = event.target.result;
let store3 = db2.createObjectStore("obj-s2", { keyPath: "id3", autoIncrement: true });
store3.createIndex("name2", "name2", { unique: true });
store3.add({id3: 16, name2: "foo", email: "foo@bar.com"}).onsuccess = success;
yield undefined;
store3.transaction.oncomplete = success;
yield undefined;
db2.close();
console.log("added cookies and stuff from secured iframe");
callback();
}
function successClear(event) {
clearIterator.next(event);
}
window.clear = function*(callback) {
document.cookie = "sc1=; expires=Thu, 01 Jan 1970 00:00:00 GMT";
localStorage.clear();
sessionStorage.clear();
indexedDB.deleteDatabase("idb-s1").onsuccess = successClear;
yield undefined;
indexedDB.deleteDatabase("idb-s2").onsuccess = successClear;
yield undefined;
console.log("removed cookies and stuff from secured iframe");
callback();
}
</script>
</body>
</html>

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

@ -0,0 +1,27 @@
<!DOCTYPE HTML>
<html>
<!--
Iframe for testing multiple host detetion in storage actor
-->
<head>
<meta charset="utf-8">
</head>
<body>
<script>
document.cookie = "uc1=foobar; domain=.example.org; path=/; secure=true";
localStorage.setItem("iframe-u-ls1", "foobar");
sessionStorage.setItem("iframe-u-ss1", "foobar1");
sessionStorage.setItem("iframe-u-ss2", "foobar2");
console.log("added cookies and stuff from unsecured iframe");
window.clear = function*(callback) {
document.cookie = "uc1=; expires=Thu, 01 Jan 1970 00:00:00 GMT; path=/; domain=.example.org; secure=true";
localStorage.clear();
sessionStorage.clear();
console.log("removed cookies and stuff from unsecured iframe");
callback();
}
</script>
</body>
</html>

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

@ -0,0 +1,63 @@
<!DOCTYPE HTML>
<html>
<!--
Bug 965872 - Storage inspector actor with cookies, local storage and session storage.
-->
<head>
<meta charset="utf-8">
<title>Storage inspector blank html for tests</title>
</head>
<body>
<script>
window.addCookie = function(name, value, path, domain, expires, secure) {
var cookieString = name + "=" + value + ";";
if (path) {
cookieString += "path=" + path + ";";
}
if (domain) {
cookieString += "domain=" + domain + ";";
}
if (expires) {
cookieString += "expires=" + expires + ";";
}
if (secure) {
cookieString += "secure=true;";
}
document.cookie = cookieString;
};
window.removeCookie = function(name, path) {
document.cookie = name + "=;expires=Thu, 01 Jan 1970 00:00:00 GMT;path=" + path;
}
window.clear = function*(callback) {
var cookies = document.cookie;
for (var cookie of cookies.split(";")) {
removeCookie(cookie.split("=")[0]);
removeCookie(cookie.split("=")[0], "/browser");
}
localStorage.clear();
sessionStorage.clear();
callback();
}
window.onload = function() {
addCookie("c1", "1.2.3.4.5.6.7", "/browser");
addCookie("c2", "foobar", "/browser");
localStorage.setItem("ls1", "testing");
localStorage.setItem("ls2", "testing");
localStorage.setItem("ls3", "testing");
localStorage.setItem("ls4", "testing");
localStorage.setItem("ls5", "testing");
localStorage.setItem("ls6", "testing");
localStorage.setItem("ls7", "testing");
sessionStorage.setItem("ss1", "foobar");
sessionStorage.setItem("ss2", "foobar");
sessionStorage.setItem("ss3", "foobar");
}
</script>
</body>
</html>

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

@ -0,0 +1,565 @@
/* vim:set ts=2 sw=2 sts=2 et: */
/* 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/. */
"use strict";
const {Cu} = require("chrome");
const STORAGE_STRINGS = "chrome://browser/locale/devtools/storage.properties";
Cu.import("resource://gre/modules/Services.jsm");
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
XPCOMUtils.defineLazyGetter(this, "TreeWidget",
() => require("devtools/shared/widgets/TreeWidget").TreeWidget);
XPCOMUtils.defineLazyGetter(this, "TableWidget",
() => require("devtools/shared/widgets/TableWidget").TableWidget);
XPCOMUtils.defineLazyModuleGetter(this, "EventEmitter",
"resource://gre/modules/devtools/event-emitter.js");
XPCOMUtils.defineLazyModuleGetter(this, "ViewHelpers",
"resource:///modules/devtools/ViewHelpers.jsm");
XPCOMUtils.defineLazyModuleGetter(this, "VariablesView",
"resource:///modules/devtools/VariablesView.jsm");
/**
* Localization convenience methods.
*/
let L10N = new ViewHelpers.L10N(STORAGE_STRINGS);
const GENERIC_VARIABLES_VIEW_SETTINGS = {
lazyEmpty: true,
lazyEmptyDelay: 10, // ms
searchEnabled: true,
searchPlaceholder: L10N.getStr("storage.search.placeholder"),
preventDescriptorModifiers: true
};
// Columns which are hidden by default in the storage table
const HIDDEN_COLUMNS = [
"creationTime",
"isDomain",
"isSecure"
];
/**
* StorageUI is controls and builds the UI of the Storage Inspector.
*
* @param {Front} front
* Front for the storage actor
* @param {Target} target
* Interface for the page we're debugging
* @param {Window} panelWin
* Window of the toolbox panel to populate UI in.
*/
this.StorageUI = function StorageUI(front, target, panelWin) {
EventEmitter.decorate(this);
this._target = target;
this._window = panelWin;
this._panelDoc = panelWin.document;
this.front = front;
let treeNode = this._panelDoc.getElementById("storage-tree");
this.tree = new TreeWidget(treeNode, {defaultType: "dir"});
this.onHostSelect = this.onHostSelect.bind(this);
this.tree.on("select", this.onHostSelect);
let tableNode = this._panelDoc.getElementById("storage-table");
this.table = new TableWidget(tableNode, {
emptyText: L10N.getStr("table.emptyText"),
highlightUpdated: true,
});
this.displayObjectSidebar = this.displayObjectSidebar.bind(this);
this.table.on(TableWidget.EVENTS.ROW_SELECTED, this.displayObjectSidebar)
this.sidebar = this._panelDoc.getElementById("storage-sidebar");
this.sidebar.setAttribute("width", "300");
this.view = new VariablesView(this.sidebar.firstChild,
GENERIC_VARIABLES_VIEW_SETTINGS);
this.front.listStores().then(storageTypes => {
this.populateStorageTree(storageTypes);
});
this.onUpdate = this.onUpdate.bind(this);
this.front.on("stores-update", this.onUpdate);
this.handleKeypress = this.handleKeypress.bind(this);
this._panelDoc.addEventListener("keypress", this.handleKeypress);
}
exports.StorageUI = StorageUI;
StorageUI.prototype = {
storageTypes: null,
shouldResetColumns: true,
destroy: function() {
this.front.off("stores-update", this.onUpdate);
this._panelDoc.removeEventListener("keypress", this.handleKeypress)
},
/**
* Empties and hides the object viewer sidebar
*/
hideSidebar: function() {
this.view.empty();
this.sidebar.hidden = true;
this.table.clearSelection();
},
/**
* Removes the given item from the storage table. Reselects the next item in
* the table and repopulates the sidebar with that item's data if the item
* being removed was selected.
*/
removeItemFromTable: function(name) {
if (this.table.isSelected(name)) {
if (this.table.selectedIndex == 0) {
this.table.selectNextRow()
}
else {
this.table.selectPreviousRow();
}
this.table.remove(name);
this.displayObjectSidebar();
}
else {
this.table.remove(name);
}
},
/**
* Event handler for "stores-update" event coming from the storage actor.
*
* @param {object} argument0
* An object containing the details of the added, changed and deleted
* storage objects.
* Each of these 3 objects are of the following format:
* {
* <store_type1>: {
* <host1>: [<store_names1>, <store_name2>...],
* <host2>: [<store_names34>...], ...
* },
* <store_type2>: {
* <host1>: [<store_names1>, <store_name2>...],
* <host2>: [<store_names34>...], ...
* }, ...
* }
* Where store_type1 and store_type2 is one of cookies, indexedDB,
* sessionStorage and localStorage; host1, host2 are the host in which
* this change happened; and [<store_namesX] is an array of the names
* of the changed store objects. This array is empty for deleted object
* if the host was completely removed.
*/
onUpdate: function({ changed, added, deleted }) {
if (deleted) {
for (let type in deleted) {
for (let host in deleted[type]) {
if (!deleted[type][host].length) {
// This means that the whole host is deleted, thus the item should
// be removed from the storage tree
if (this.tree.isSelected([type, host])) {
this.table.clear();
this.hideSidebar();
this.tree.selectPreviousItem();
}
this.tree.remove([type, host]);
}
else if (this.tree.isSelected([type, host])) {
for (let name of deleted[type][host]) {
try {
// trying to parse names in case its for indexedDB
let names = JSON.parse(name);
if (!names[2]) {
if (this.tree.isSelected([type, host, names[0], names[1]])) {
this.tree.selectPreviousItem();
this.tree.remove([type, host, names[0], names[1]]);
this.table.clear();
this.hideSidebar();
}
}
else if (this.tree.isSelected([type, host, names[0], names[1]])) {
this.removeItemFromTable(names[2]);
}
}
catch (ex) {
this.removeItemFromTable(name);
}
}
}
}
}
}
if (added) {
for (let type in added) {
for (let host in added[type]) {
this.tree.add([type, {id: host, type: "url"}]);
for (let name of added[type][host]) {
try {
name = JSON.parse(name);
if (name.length == 3) {
name.splice(2, 1);
}
this.tree.add([type, host, ...name]);
if (!this.tree.selectedItem) {
this.tree.selectedItem = [type, host, name[0], name[1]];
this.fetchStorageObjects(type, host, [JSON.stringify(name)], 1);
}
} catch(ex) {}
}
if (this.tree.isSelected([type, host])) {
this.fetchStorageObjects(type, host, added[type][host], 1);
}
}
}
}
if (changed) {
let [type, host, db, objectStore] = this.tree.selectedItem;
if (changed[type] && changed[type][host]) {
if (changed[type][host].length) {
try {
let toUpdate = [];
for (let name of changed[type][host]) {
let names = JSON.parse(name);
if (names[0] == db && names[1] == objectStore && names[2]) {
toUpdate.push(name);
}
}
this.fetchStorageObjects(type, host, toUpdate, 2);
}
catch (ex) {
this.fetchStorageObjects(type, host, changed[type][host], 2);
}
}
}
}
if (added || deleted || changed) {
this.emit("store-objects-updated");
}
},
/**
* Fetches the storage objects from the storage actor and populates the
* storage table with the returned data.
*
* @param {string} type
* The type of storage. Ex. "cookies"
* @param {string} host
* Hostname
* @param {array} names
* Names of particular store objects. Empty if all are requested
* @param {number} reason
* 2 for update, 1 for new row in an existing table and 0 when
* populating a table for the first time for the given host/type
*/
fetchStorageObjects: function(type, host, names, reason) {
this.storageTypes[type].getStoreObjects(host, names).then(({data}) => {
if (!data.length) {
this.emit("store-objects-updated");
return;
}
if (this.shouldResetColumns) {
this.resetColumns(data[0], type);
}
this.populateTable(data, reason);
this.emit("store-objects-updated");
});
},
/**
* Populates the storage tree which displays the list of storages present for
* the page.
*
* @param {object} storageTypes
* List of storages and their corresponding hosts returned by the
* StorageFront.listStores call.
*/
populateStorageTree: function(storageTypes) {
this.storageTypes = {};
for (let type in storageTypes) {
let typeLabel = L10N.getStr("tree.labels." + type);
this.tree.add([{id: type, label: typeLabel, type: "store"}]);
if (storageTypes[type].hosts) {
this.storageTypes[type] = storageTypes[type];
for (let host in storageTypes[type].hosts) {
this.tree.add([type, {id: host, type: "url"}]);
for (let name of storageTypes[type].hosts[host]) {
try {
let names = JSON.parse(name);
this.tree.add([type, host, ...names]);
if (!this.tree.selectedItem) {
this.tree.selectedItem = [type, host, names[0], names[1]];
this.fetchStorageObjects(type, host, [name], 0);
}
} catch(ex) {}
}
if (!this.tree.selectedItem) {
this.tree.selectedItem = [type, host];
this.fetchStorageObjects(type, host, null, 0);
}
}
}
}
},
/**
* Populates the selected entry from teh table in the sidebar for a more
* detailed view.
*/
displayObjectSidebar: function() {
let item = this.table.selectedRow;
if (!item) {
// Make sure that sidebar is hidden and return
this.sidebar.hidden = true;
return;
}
this.sidebar.hidden = false;
this.view.empty();
let mainScope = this.view.addScope(L10N.getStr("storage.data.label"));
mainScope.expanded = true;
if (item.name && item.valueActor) {
let itemVar = mainScope.addItem(item.name + "", {}, true);
item.valueActor.string().then(value => {
// The main area where the value will be displayed
itemVar.setGrip(value);
// May be the item value is a json or a key value pair itself
this.parseItemValue(item.name, value);
// By default the item name and value are shown. If this is the only
// information available, then nothing else is to be displayed.
let itemProps = Object.keys(item);
if (itemProps.length == 3) {
this.emit("sidebar-updated");
return;
}
// Display any other information other than the item name and value
// which may be available.
let rawObject = Object.create(null);
let otherProps =
itemProps.filter(e => e != "name" && e != "value" && e != "valueActor");
for (let prop of otherProps) {
rawObject[prop] = item[prop];
}
itemVar.populate(rawObject, {sorted: true});
itemVar.twisty = true;
itemVar.expanded = true;
this.emit("sidebar-updated");
});
return;
}
// Case when displaying IndexedDB db/object store properties.
for (let key in item) {
mainScope.addItem(key, {}, true).setGrip(item[key]);
this.parseItemValue(key, item[key]);
}
this.emit("sidebar-updated");
},
/**
* Tries to parse a string value into either a json or a key-value separated
* object and populates the sidebar with the parsed value. The value can also
* be a key separated array.
*
* @param {string} name
* The key corresponding to the `value` string in the object
* @param {string} value
* The string to be parsed into an object
*/
parseItemValue: function(name, value) {
let json = null
try {
json = JSON.parse(value);
}
catch (ex) {
json = null;
}
if (!json && value) {
json = this._extractKeyValPairs(value);
}
// return if json is null, or same as value, or just a string.
if (!json || json == value || typeof json == "string") {
return;
}
// One special case is a url which gets separated as key value pair on :
if ((json.length == 2 || Object.keys(json).length == 1) &&
((json[0] || Object.keys(json)[0]) + "").match(/^(http|file|ftp)/)) {
return;
}
let jsonObject = Object.create(null);
jsonObject[name] = json;
let valueScope = this.view.getScopeAtIndex(1) ||
this.view.addScope(L10N.getStr("storage.parsedValue.label"));
valueScope.expanded = true;
let jsonVar = valueScope.addItem("", Object.create(null), true);
jsonVar.expanded = true;
jsonVar.twisty = true;
jsonVar.populate(jsonObject, {expanded: true});
},
/**
* Tries to parse a string into an object on the basis of key-value pairs,
* separated by various separators. If failed, tries to parse for single
* separator separated values to form an array.
*
* @param {string} value
* The string to be parsed into an object or array
*/
_extractKeyValPairs: function(value) {
let makeObject = (keySep, pairSep) => {
let object = {};
for (let pair of value.split(pairSep)) {
let [key, val] = pair.split(keySep);
object[key] = val;
}
return object;
};
// Possible separators.
const separators = ["=", ":", "~", "#", "&", "\\*", ",", "\\."];
// Testing for object
for (let i = 0; i < separators.length; i++) {
let kv = separators[i];
for (let j = 0; j < separators.length; j++) {
if (i == j) {
continue;
}
let p = separators[j];
let regex = new RegExp("^([^" + kv + p + "]*" + kv + "+[^" + kv + p +
"]*" + p + "*)+$", "g");
if (value.match(regex) && value.contains(kv) &&
(value.contains(p) || value.split(kv).length == 2)) {
return makeObject(kv, p);
}
}
}
// Testing for array
for (let i = 0; i < separators.length; i++) {
let p = separators[i];
let regex = new RegExp("^[^" + p + "]+(" + p + "+[^" + p + "]*)+$", "g");
if (value.match(regex)) {
return value.split(p.replace(/\\*/g, ""));
}
}
return null;
},
/**
* Select handler for the storage tree. Fetches details of the selected item
* from the storage details and populates the storage tree.
*
* @param {string} event
* The name of the event fired
* @param {array} item
* An array of ids which represent the location of the selected item in
* the storage tree
*/
onHostSelect: function(event, item) {
this.table.clear();
this.hideSidebar();
let [type, host] = item;
let names = null;
if (!host) {
return;
}
if (item.length > 2) {
names = [JSON.stringify(item.slice(2))];
}
this.shouldResetColumns = true;
this.fetchStorageObjects(type, host, names, 0);
},
/**
* Resets the column headers in the storage table with the pased object `data`
*
* @param {object} data
* The object from which key and values will be used for naming the
* headers of the columns
* @param {string} type
* The type of storage corresponding to the after-reset columns in the
* table.
*/
resetColumns: function(data, type) {
let columns = {};
let uniqueKey = null;
for (let key in data) {
if (!uniqueKey) {
this.table.uniqueId = uniqueKey = key;
}
columns[key] = L10N.getStr("table.headers." + type + "." + key);
}
this.table.setColumns(columns, null, HIDDEN_COLUMNS);
this.shouldResetColumns = false;
this.hideSidebar();
},
/**
* Populates or updates the rows in the storage table.
*
* @param {array[object]} data
* Array of objects to be populated in the storage table
* @param {number} reason
* The reason of this populateTable call. 2 for update, 1 for new row
* in an existing table and 0 when populating a table for the first
* time for the given host/type
*/
populateTable: function(data, reason) {
for (let item of data) {
if (item.value) {
item.valueActor = item.value;
item.value = item.value.initial || "";
}
if (item.expires != null) {
item.expires = item.expires
? new Date(item.expires).toLocaleString()
: L10N.getStr("label.expires.session");
}
if (item.creationTime != null) {
item.creationTime = new Date(item.creationTime).toLocaleString();
}
if (item.lastAccessed != null) {
item.lastAccessed = new Date(item.lastAccessed).toLocaleString();
}
if (reason < 2) {
this.table.push(item, reason == 0);
}
else {
this.table.update(item);
if (item == this.table.selectedRow && !this.sidebar.hidden) {
this.displayObjectSidebar();
}
}
}
},
/**
* Handles keypress event on the body table to close the sidebar when open
*
* @param {DOMEvent} event
* The event passed by the keypress event.
*/
handleKeypress: function(event) {
if (event.keyCode == event.DOM_VK_ESCAPE && !this.sidebar.hidden) {
// Stop Propagation to prevent opening up of split console
this.hideSidebar();
event.stopPropagation();
event.preventDefault();
}
}
}

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

@ -0,0 +1,100 @@
# 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/.
# LOCALIZATION NOTE These strings are used inside the Storage Editor tool.
# LOCALIZATION NOTE The correct localization of this file might be to keep it
# in English, or another language commonly spoken among web developers.
# You want to make that choice consistent across the developer tools.
# A good criteria is the language in which you'd find the best documentation
# on web development on the web.
# LOCALIZATION NOTE (chromeWindowTitle): This is the title of the Storage
# 'chrome' window. That is, the main window with all the cookies, etc.
# The argument is either the content document's title or its href if no title
# is available.
chromeWindowTitle=Storage [%S]
# LOCALIZATION NOTE (open.commandkey): This the key to use in
# conjunction with shift to open the storage editor
open.commandkey=VK_F9
# LOCALIZATION NOTE (open.accesskey): The access key used to open the storage
# editor.
open.accesskey=d
# LOCALIZATION NOTE (storage.label):
# This string is displayed in the title of the tab when the storage editor is
# displayed inside the developer tools window and in the Developer Tools Menu.
storage.label=Storage
# LOCALIZATION NOTE (storage.tooltip):
# This string is displayed in the tooltip of the tab when the storage editor is
# displayed inside the developer tools window.
storage.tooltip=Storage Inspector (Cookies, Local Storage ...)
# LOCALIZATION NOTE (tree.emptyText):
# This string is displayed when the Storage Tree is empty. This can happen when
# there are no websites on the current page (about:blank)
tree.emptyText=No hosts on the page
# LOCALIZATION NOTE (table.emptyText):
# This string is displayed when there are no rows in the Storage Table for the
# selected host.
table.emptyText=No data present for selected host
# LOCALIZATION NOTE (tree.labels.*):
# These strings are the labels for Storage type groups present in the Storage
# Tree, like cookies, local storage etc.
tree.labels.cookies=Cookies
tree.labels.localStorage=Local Storage
tree.labels.sessionStorage=Session Storage
tree.labels.indexedDB=Indexed DB
# LOCALIZATION NOTE (table.headers.*.*):
# These strings are the header names of the columns in the Storage Table for
# each type of storage available through the Storage Tree to the side.
table.headers.cookies.name=Name
table.headers.cookies.path=Path
table.headers.cookies.host=Domain
table.headers.cookies.expires=Expires on
table.headers.cookies.value=Value
table.headers.cookies.lastAccessed:Last accessed on
table.headers.cookies.creationTime:Created on
table.headers.cookies.isHttpOnly:isHttpOnly
table.headers.cookies.isSecure:isSecure
table.headers.cookies.isDomain:isDomain
table.headers.localStorage.name=Key
table.headers.localStorage.value=Value
table.headers.sessionStorage.name=Key
table.headers.sessionStorage.value=Value
table.headers.indexedDB.name=Key
table.headers.indexedDB.db=Database Name
table.headers.indexedDB.objectStore=Object Store Name
table.headers.indexedDB.value=Value
table.headers.indexedDB.origin=Origin
table.headers.indexedDB.version=Version
table.headers.indexedDB.objectStores=Object Stores
table.headers.indexedDB.keyPath=Key
table.headers.indexedDB.autoIncrement=Auto Increment
table.headers.indexedDB.indexes=Indexes
# LOCALIZATION NOTE (label.expires.session):
# This string is displayed in the expires column when the cookie is Session
# Cookie
label.expires.session=Session
# LOCALIZATION NOTE (storage.search.placeholder):
# This is the placeholder text in the sidebar search box
storage.search.placeholder=Filter values
# LOCALIZATION NOTE (storage.data.label):
# This is the heading displayed over the item value in the sidebar
storage.data.label=Data
# LOCALIZATION NOTE (storage.parsedValue.label):
# This is the heading displayed over the item parsed value in the sidebar
storage.parsedValue.label=Parsed Value

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

@ -55,11 +55,11 @@ feedback_category_other=Other:
feedback_custom_category_text_placeholder=What went wrong?
feedback_submit_button=Submit
feedback_back_button=Back
## LOCALIZATION NOTE (feedback_window_will_close_in):
## LOCALIZATION NOTE (feedback_window_will_close_in2):
## Semicolon-separated list of plural forms. See:
## http://developer.mozilla.org/en/docs/Localization_and_Plurals
## In this item, don't translate the part between {{..}}
feedback_window_will_close_in=This window will close in {{countdown}} second;This window will close in {{countdown}} seconds
feedback_window_will_close_in2=This window will close in {{countdown}} second;This window will close in {{countdown}} seconds
share_email_subject2=Invitation to chat
## LOCALIZATION NOTE (share_email_body2): In this item, don't translate the

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

@ -43,6 +43,7 @@
locale/browser/devtools/tilt.properties (%chrome/browser/devtools/tilt.properties)
locale/browser/devtools/scratchpad.properties (%chrome/browser/devtools/scratchpad.properties)
locale/browser/devtools/scratchpad.dtd (%chrome/browser/devtools/scratchpad.dtd)
locale/browser/devtools/storage.properties (%chrome/browser/devtools/storage.properties)
locale/browser/devtools/styleeditor.properties (%chrome/browser/devtools/styleeditor.properties)
locale/browser/devtools/styleeditor.dtd (%chrome/browser/devtools/styleeditor.dtd)
locale/browser/devtools/styleinspector.dtd (%chrome/browser/devtools/styleinspector.dtd)

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

@ -203,6 +203,7 @@ browser.jar:
skin/classic/browser/devtools/filetype-dir-close.svg (../shared/devtools/images/filetypes/dir-close.svg)
skin/classic/browser/devtools/filetype-dir-open.svg (../shared/devtools/images/filetypes/dir-open.svg)
skin/classic/browser/devtools/filetype-globe.svg (../shared/devtools/images/filetypes/globe.svg)
skin/classic/browser/devtools/filetype-store.svg (../shared/devtools/images/filetypes/store.svg)
skin/classic/browser/devtools/commandline-icon.png (../shared/devtools/images/commandline-icon.png)
skin/classic/browser/devtools/commandline-icon@2x.png (../shared/devtools/images/commandline-icon@2x.png)
skin/classic/browser/devtools/command-paintflashing.png (../shared/devtools/images/command-paintflashing.png)
@ -248,6 +249,7 @@ browser.jar:
* skin/classic/browser/devtools/shadereditor.css (devtools/shadereditor.css)
* skin/classic/browser/devtools/splitview.css (../shared/devtools/splitview.css)
skin/classic/browser/devtools/styleeditor.css (../shared/devtools/styleeditor.css)
skin/classic/browser/devtools/storage.css (../shared/devtools/storage.css)
* skin/classic/browser/devtools/webaudioeditor.css (devtools/webaudioeditor.css)
skin/classic/browser/devtools/magnifying-glass.png (../shared/devtools/images/magnifying-glass.png)
skin/classic/browser/devtools/magnifying-glass@2x.png (../shared/devtools/images/magnifying-glass@2x.png)
@ -310,6 +312,7 @@ browser.jar:
skin/classic/browser/devtools/tool-inspector.svg (../shared/devtools/images/tool-inspector.svg)
skin/classic/browser/devtools/tool-inspector.svg (../shared/devtools/images/tool-inspector.svg)
skin/classic/browser/devtools/tool-styleeditor.svg (../shared/devtools/images/tool-styleeditor.svg)
skin/classic/browser/devtools/tool-storage.svg (../shared/devtools/images/tool-storage.svg)
skin/classic/browser/devtools/tool-profiler.svg (../shared/devtools/images/tool-profiler.svg)
skin/classic/browser/devtools/tool-network.svg (../shared/devtools/images/tool-network.svg)
skin/classic/browser/devtools/tool-scratchpad.svg (../shared/devtools/images/tool-scratchpad.svg)

Двоичные данные
browser/themes/osx/Toolbar-yosemite.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 15 KiB

Двоичные данные
browser/themes/osx/Toolbar-yosemite@2x.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 34 KiB

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

@ -145,6 +145,10 @@ browser.jar:
skin/classic/browser/loop/toolbar@2x.png (loop/toolbar@2x.png)
skin/classic/browser/loop/toolbar-inverted.png (loop/toolbar-inverted.png)
skin/classic/browser/loop/toolbar-inverted@2x.png (loop/toolbar-inverted@2x.png)
skin/classic/browser/yosemite/loop/menuPanel.png (loop/menuPanel-yosemite.png)
skin/classic/browser/yosemite/loop/menuPanel@2x.png (loop/menuPanel-yosemite@2x.png)
skin/classic/browser/yosemite/loop/toolbar.png (loop/toolbar-yosemite.png)
skin/classic/browser/yosemite/loop/toolbar@2x.png (loop/toolbar-yosemite@2x.png)
skin/classic/browser/customizableui/background-noise-toolbar.png (customizableui/background-noise-toolbar.png)
skin/classic/browser/customizableui/customize-titleBar-toggle.png (customizableui/customize-titleBar-toggle.png)
skin/classic/browser/customizableui/customize-titleBar-toggle@2x.png (customizableui/customize-titleBar-toggle@2x.png)
@ -326,6 +330,7 @@ browser.jar:
skin/classic/browser/devtools/filetype-dir-close.svg (../shared/devtools/images/filetypes/dir-close.svg)
skin/classic/browser/devtools/filetype-dir-open.svg (../shared/devtools/images/filetypes/dir-open.svg)
skin/classic/browser/devtools/filetype-globe.svg (../shared/devtools/images/filetypes/globe.svg)
skin/classic/browser/devtools/filetype-store.svg (../shared/devtools/images/filetypes/store.svg)
skin/classic/browser/devtools/commandline-icon.png (../shared/devtools/images/commandline-icon.png)
skin/classic/browser/devtools/commandline-icon@2x.png (../shared/devtools/images/commandline-icon@2x.png)
skin/classic/browser/devtools/command-paintflashing.png (../shared/devtools/images/command-paintflashing.png)
@ -372,6 +377,7 @@ browser.jar:
* skin/classic/browser/devtools/shadereditor.css (devtools/shadereditor.css)
* skin/classic/browser/devtools/splitview.css (../shared/devtools/splitview.css)
skin/classic/browser/devtools/styleeditor.css (../shared/devtools/styleeditor.css)
skin/classic/browser/devtools/storage.css (../shared/devtools/storage.css)
* skin/classic/browser/devtools/webaudioeditor.css (devtools/webaudioeditor.css)
skin/classic/browser/devtools/magnifying-glass.png (../shared/devtools/images/magnifying-glass.png)
skin/classic/browser/devtools/magnifying-glass@2x.png (../shared/devtools/images/magnifying-glass@2x.png)
@ -434,6 +440,7 @@ browser.jar:
skin/classic/browser/devtools/tool-inspector.svg (../shared/devtools/images/tool-inspector.svg)
skin/classic/browser/devtools/tool-inspector.svg (../shared/devtools/images/tool-inspector.svg)
skin/classic/browser/devtools/tool-styleeditor.svg (../shared/devtools/images/tool-styleeditor.svg)
skin/classic/browser/devtools/tool-storage.svg (../shared/devtools/images/tool-storage.svg)
skin/classic/browser/devtools/tool-profiler.svg (../shared/devtools/images/tool-profiler.svg)
skin/classic/browser/devtools/tool-network.svg (../shared/devtools/images/tool-network.svg)
skin/classic/browser/devtools/tool-scratchpad.svg (../shared/devtools/images/tool-scratchpad.svg)
@ -503,6 +510,22 @@ browser.jar:
skin/classic/browser/tabbrowser/alltabs-box-bkgnd-icon@2x.png (tabbrowser/alltabs-box-bkgnd-icon-lion@2x.png)
skin/classic/browser/lion/tabview/tabview.png (tabview/tabview-lion.png)
skin/classic/browser/lion/places/toolbar.png (places/toolbar-lion.png)
skin/classic/browser/yosemite/Toolbar.png (Toolbar-yosemite.png)
skin/classic/browser/yosemite/Toolbar@2x.png (Toolbar-yosemite@2x.png)
skin/classic/browser/yosemite/menuPanel.png (menuPanel-yosemite.png)
skin/classic/browser/yosemite/menuPanel@2x.png (menuPanel-yosemite@2x.png)
skin/classic/browser/yosemite/menuPanel-customize.png (menuPanel-customize-yosemite.png)
skin/classic/browser/yosemite/menuPanel-customize@2x.png (menuPanel-customize-yosemite@2x.png)
skin/classic/browser/yosemite/menuPanel-exit.png (menuPanel-exit-yosemite.png)
skin/classic/browser/yosemite/menuPanel-exit@2x.png (menuPanel-exit-yosemite@2x.png)
skin/classic/browser/yosemite/menuPanel-help.png (menuPanel-help-yosemite.png)
skin/classic/browser/yosemite/menuPanel-help@2x.png (menuPanel-help-yosemite@2x.png)
skin/classic/browser/yosemite/menuPanel-small.png (menuPanel-small-yosemite.png)
skin/classic/browser/yosemite/menuPanel-small@2x.png (menuPanel-small-yosemite@2x.png)
skin/classic/browser/yosemite/reload-stop-go.png (reload-stop-go-yosemite.png)
skin/classic/browser/yosemite/reload-stop-go@2x.png (reload-stop-go-yosemite@2x.png)
skin/classic/browser/yosemite/sync-horizontalbar.png (sync-horizontalbar-yosemite.png)
skin/classic/browser/yosemite/sync-horizontalbar@2x.png (sync-horizontalbar-yosemite@2x.png)
skin/classic/browser/notification-pluginNormal.png (../shared/plugins/notification-pluginNormal.png)
skin/classic/browser/notification-pluginAlert.png (../shared/plugins/notification-pluginAlert.png)
skin/classic/browser/notification-pluginBlocked.png (../shared/plugins/notification-pluginBlocked.png)
@ -522,3 +545,23 @@ browser.jar:
% override chrome://browser/skin/tabbrowser/alltabs-box-bkgnd-icon.png chrome://browser/skin/lion/tabbrowser/alltabs-box-bkgnd-icon.png os=Darwin osversion>=10.7
% override chrome://browser/skin/tabview/tabview.png chrome://browser/skin/lion/tabview/tabview.png os=Darwin osversion>=10.7
% override chrome://browser/skin/places/toolbar.png chrome://browser/skin/lion/places/toolbar.png os=Darwin osversion>=10.7
% override chrome://browser/skin/Toolbar.png chrome://browser/skin/yosemite/Toolbar.png os=Darwin osversion>=10.10
% override chrome://browser/skin/Toolbar@2x.png chrome://browser/skin/yosemite/Toolbar@2x.png os=Darwin osversion>=10.10
% override chrome://browser/skin/menuPanel.png chrome://browser/skin/yosemite/menuPanel.png os=Darwin osversion>=10.10
% override chrome://browser/skin/menuPanel@2x.png chrome://browser/skin/yosemite/menuPanel@2x.png os=Darwin osversion>=10.10
% override chrome://browser/skin/loop/menuPanel.png chrome://browser/skin/yosemite/loop/menuPanel.png os=Darwin osversion>=10.10
% override chrome://browser/skin/loop/menuPanel@2x.png chrome://browser/skin/yosemite/loop/menuPanel@2x.png os=Darwin osversion>=10.10
% override chrome://browser/skin/loop/toolbar.png chrome://browser/skin/yosemite/loop/toolbar.png os=Darwin osversion>=10.10
% override chrome://browser/skin/loop/toolbar@2x.png chrome://browser/skin/yosemite/loop/toolbar@2x.png os=Darwin osversion>=10.10
% override chrome://browser/skin/menuPanel-customize.png chrome://browser/skin/yosemite/menuPanel-customize.png os=Darwin osversion>=10.10
% override chrome://browser/skin/menuPanel-customize@2x.png chrome://browser/skin/yosemite/menuPanel-customize@2x.png os=Darwin osversion>=10.10
% override chrome://browser/skin/menuPanel-exit.png chrome://browser/skin/yosemite/menuPanel-exit.png os=Darwin osversion>=10.10
% override chrome://browser/skin/menuPanel-exit@2x.png chrome://browser/skin/yosemite/menuPanel-exit@2x.png os=Darwin osversion>=10.10
% override chrome://browser/skin/menuPanel-help.png chrome://browser/skin/yosemite/menuPanel-help.png os=Darwin osversion>=10.10
% override chrome://browser/skin/menuPanel-help@2x.png chrome://browser/skin/yosemite/menuPanel-help@2x.png os=Darwin osversion>=10.10
% override chrome://browser/skin/menuPanel-small.png chrome://browser/skin/yosemite/menuPanel-small.png os=Darwin osversion>=10.10
% override chrome://browser/skin/menuPanel-small@2x.png chrome://browser/skin/yosemite/menuPanel-small@2x.png os=Darwin osversion>=10.10
% override chrome://browser/skin/reload-stop-go.png chrome://browser/skin/yosemite/reload-stop-go.png os=Darwin osversion>=10.10
% override chrome://browser/skin/reload-stop-go@2x.png chrome://browser/skin/yosemite/reload-stop-go@2x.png os=Darwin osversion>=10.10
% override chrome://browser/skin/sync-horizontalbar.png chrome://browser/skin/yosemite/sync-horizontalbar.png os=Darwin osversion>=10.10
% override chrome://browser/skin/sync-horizontalbar@2x.png chrome://browser/skin/yosemite/sync-horizontalbar@2x.png os=Darwin osversion>=10.10

Двоичные данные
browser/themes/osx/loop/menuPanel-yosemite.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 9.5 KiB

Двоичные данные
browser/themes/osx/loop/menuPanel-yosemite@2x.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 20 KiB

Двоичные данные
browser/themes/osx/loop/toolbar-yosemite.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 2.3 KiB

Двоичные данные
browser/themes/osx/loop/toolbar-yosemite@2x.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 4.7 KiB

Двоичные данные
browser/themes/osx/menuPanel-customize-yosemite.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 219 B

Двоичные данные
browser/themes/osx/menuPanel-customize-yosemite@2x.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 364 B

Двоичные данные
browser/themes/osx/menuPanel-exit-yosemite.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 515 B

Двоичные данные
browser/themes/osx/menuPanel-exit-yosemite@2x.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 939 B

Двоичные данные
browser/themes/osx/menuPanel-help-yosemite.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.5 KiB

Двоичные данные
browser/themes/osx/menuPanel-help-yosemite@2x.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 3.4 KiB

Двоичные данные
browser/themes/osx/menuPanel-small-yosemite.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.6 KiB

Двоичные данные
browser/themes/osx/menuPanel-small-yosemite@2x.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 4.1 KiB

Двоичные данные
browser/themes/osx/menuPanel-yosemite.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 19 KiB

Двоичные данные
browser/themes/osx/menuPanel-yosemite@2x.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 43 KiB

Двоичные данные
browser/themes/osx/reload-stop-go-yosemite.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 923 B

Двоичные данные
browser/themes/osx/reload-stop-go-yosemite@2x.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 1.6 KiB

Двоичные данные
browser/themes/osx/sync-horizontalbar-yosemite.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 311 B

Двоичные данные
browser/themes/osx/sync-horizontalbar-yosemite@2x.png Normal file

Двоичный файл не отображается.

После

Ширина:  |  Высота:  |  Размер: 609 B

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

@ -0,0 +1,7 @@
<svg width="16" xmlns="http://www.w3.org/2000/svg" height="16" viewBox="0 0 16 16" xmlns:xlink="http://www.w3.org/1999/xlink" enable-background="new 0 0 16 16">
<g>
<path d="m1.3,12.5v-2.4c0,0 0,2.5 6.7,2.5 6.7,0 6.7-2.5 6.7-2.5v2.4c0,0 0,2.7-6.8,2.7-6.6,0-6.6-2.7-6.6-2.7z"/>
<path d="m14.7,3.4c0-1.4-3-2.5-6.7-2.5s-6.7,1.1-6.7,2.5c0,.2 0,.3 .1,.5-.1-.3-.1-.4-.1-.4v1.5c0,0 0,2.7 6.7,2.7 6.7,0 6.8-2.7 6.8-2.7v-1.6c0,.1 0,.2-.1,.5-0-.2-0-.3-0-.5z"/>
<path d="m1.3,8.7v-2.4c0,0 0,2.5 6.7,2.5 6.7,0 6.7-2.5 6.7-2.5v2.4c0,0 0,2.7-6.8,2.7-6.6-0-6.6-2.7-6.6-2.7z"/>
</g>
</svg>

После

Ширина:  |  Высота:  |  Размер: 574 B

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

@ -0,0 +1,7 @@
<svg width="16" xmlns="http://www.w3.org/2000/svg" height="16" viewBox="0 0 16 16" xmlns:xlink="http://www.w3.org/1999/xlink" enable-background="new 0 0 16 16">
<g fill="#edf0f1">
<path d="m1.3,12.5v-2.4c0,0 0,2.5 6.7,2.5 6.7,0 6.7-2.5 6.7-2.5v2.4c0,0 0,2.7-6.8,2.7-6.6,0-6.6-2.7-6.6-2.7z"/>
<path d="m14.7,3.4c0-1.4-3-2.5-6.7-2.5s-6.7,1.1-6.7,2.5c0,.2 0,.3 .1,.5-.1-.3-.1-.4-.1-.4v1.5c0,0 0,2.7 6.7,2.7 6.7,0 6.8-2.7 6.8-2.7v-1.6c0,.1 0,.2-.1,.5-0-.2-0-.3-0-.5z"/>
<path d="m1.3,8.7v-2.4c0,0 0,2.5 6.7,2.5 6.7,0 6.7-2.5 6.7-2.5v2.4c0,0 0,2.7-6.8,2.7-6.6-0-6.6-2.7-6.6-2.7z"/>
</g>
</svg>

После

Ширина:  |  Высота:  |  Размер: 589 B

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

@ -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/. */
/* Storage Host Tree */
#storage-tree {
min-width: 220px;
max-width: 500px;
overflow: auto;
}
.theme-dark #storage-tree {
background: #343c45; /* Toolbars */
}
#storage-tree .tree-widget-item[type="store"]:after {
background-image: url(chrome://browser/skin/devtools/filetype-store.svg);
background-size: 18px 18px;
background-position: -1px 0;
}
/* Columns with date should have a min width so that date is visible */
#expires, #lastAccessed, #creationTime {
min-width: 150px;
}
/* Variables View Sidebar */
#storage-sidebar {
max-width: 500px;
min-width: 250px;
}
/* Responsive sidebar */
@media (max-width: 700px) {
#storage-tree {
max-width: 100%;
}
#storage-table #path {
display: none;
}
#storage-table .table-widget-cell {
min-width: 100px;
}
}

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

@ -1430,6 +1430,7 @@
padding: 10px 20px;
font-size: medium;
background: transparent;
pointer-events: none;
}
/* Tree Item */

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

@ -239,6 +239,7 @@ browser.jar:
skin/classic/browser/devtools/filetype-dir-close.svg (../shared/devtools/images/filetypes/dir-close.svg)
skin/classic/browser/devtools/filetype-dir-open.svg (../shared/devtools/images/filetypes/dir-open.svg)
skin/classic/browser/devtools/filetype-globe.svg (../shared/devtools/images/filetypes/globe.svg)
skin/classic/browser/devtools/filetype-store.svg (../shared/devtools/images/filetypes/store.svg)
skin/classic/browser/devtools/commandline-icon.png (../shared/devtools/images/commandline-icon.png)
skin/classic/browser/devtools/commandline-icon@2x.png (../shared/devtools/images/commandline-icon@2x.png)
skin/classic/browser/devtools/alerticon-warning.png (../shared/devtools/images/alerticon-warning.png)
@ -283,6 +284,7 @@ browser.jar:
* skin/classic/browser/devtools/profiler.css (devtools/profiler.css)
* skin/classic/browser/devtools/scratchpad.css (devtools/scratchpad.css)
* skin/classic/browser/devtools/shadereditor.css (devtools/shadereditor.css)
skin/classic/browser/devtools/storage.css (../shared/devtools/storage.css)
* skin/classic/browser/devtools/splitview.css (../shared/devtools/splitview.css)
skin/classic/browser/devtools/styleeditor.css (../shared/devtools/styleeditor.css)
* skin/classic/browser/devtools/webaudioeditor.css (devtools/webaudioeditor.css)
@ -346,6 +348,7 @@ browser.jar:
skin/classic/browser/devtools/tool-debugger-paused.svg (../shared/devtools/images/tool-debugger-paused.svg)
skin/classic/browser/devtools/tool-inspector.svg (../shared/devtools/images/tool-inspector.svg)
skin/classic/browser/devtools/tool-styleeditor.svg (../shared/devtools/images/tool-styleeditor.svg)
skin/classic/browser/devtools/tool-storage.svg (../shared/devtools/images/tool-storage.svg)
skin/classic/browser/devtools/tool-profiler.svg (../shared/devtools/images/tool-profiler.svg)
skin/classic/browser/devtools/tool-network.svg (../shared/devtools/images/tool-network.svg)
skin/classic/browser/devtools/tool-scratchpad.svg (../shared/devtools/images/tool-scratchpad.svg)
@ -654,6 +657,7 @@ browser.jar:
skin/classic/aero/browser/devtools/filetype-dir-close.svg (../shared/devtools/images/filetypes/dir-close.svg)
skin/classic/aero/browser/devtools/filetype-dir-open.svg (../shared/devtools/images/filetypes/dir-open.svg)
skin/classic/aero/browser/devtools/filetype-globe.svg (../shared/devtools/images/filetypes/globe.svg)
skin/classic/aero/browser/devtools/filetype-store.svg (../shared/devtools/images/filetypes/store.svg)
skin/classic/aero/browser/devtools/commandline-icon.png (../shared/devtools/images/commandline-icon.png)
skin/classic/aero/browser/devtools/commandline-icon@2x.png (../shared/devtools/images/commandline-icon@2x.png)
skin/classic/aero/browser/devtools/command-paintflashing.png (../shared/devtools/images/command-paintflashing.png)
@ -700,6 +704,7 @@ browser.jar:
* skin/classic/aero/browser/devtools/shadereditor.css (devtools/shadereditor.css)
* skin/classic/aero/browser/devtools/splitview.css (../shared/devtools/splitview.css)
skin/classic/aero/browser/devtools/styleeditor.css (../shared/devtools/styleeditor.css)
skin/classic/aero/browser/devtools/storage.css (../shared/devtools/storage.css)
* skin/classic/aero/browser/devtools/webaudioeditor.css (devtools/webaudioeditor.css)
skin/classic/aero/browser/devtools/magnifying-glass.png (../shared/devtools/images/magnifying-glass.png)
skin/classic/aero/browser/devtools/magnifying-glass@2x.png (../shared/devtools/images/magnifying-glass@2x.png)
@ -761,6 +766,7 @@ browser.jar:
skin/classic/aero/browser/devtools/tool-debugger-paused.svg (../shared/devtools/images/tool-debugger-paused.svg)
skin/classic/aero/browser/devtools/tool-inspector.svg (../shared/devtools/images/tool-inspector.svg)
skin/classic/aero/browser/devtools/tool-styleeditor.svg (../shared/devtools/images/tool-styleeditor.svg)
skin/classic/aero/browser/devtools/tool-storage.svg (../shared/devtools/images/tool-storage.svg)
skin/classic/aero/browser/devtools/tool-profiler.svg (../shared/devtools/images/tool-profiler.svg)
skin/classic/aero/browser/devtools/tool-network.svg (../shared/devtools/images/tool-network.svg)
skin/classic/aero/browser/devtools/tool-scratchpad.svg (../shared/devtools/images/tool-scratchpad.svg)

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

@ -1177,7 +1177,7 @@ nsContentSink::StartLayout(bool aIgnorePendingSheets)
// If the document we are loading has a reference or it is a
// frameset document, disable the scroll bars on the views.
mDocument->SetScrollToRef(mDocumentURI);
mDocument->SetScrollToRef(mDocument->GetDocumentURI());
}
void

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

@ -207,6 +207,8 @@ nsMixedContentBlocker::ShouldLoad(uint32_t aContentType,
// Assume active (high risk) content and blocked by default
MixedContentTypes classification = eMixedScript;
// Make decision to block/reject by default
*aDecision = REJECT_REQUEST;
// Notes on non-obvious decisions:
@ -339,10 +341,12 @@ nsMixedContentBlocker::ShouldLoad(uint32_t aContentType,
NS_FAILED(NS_URIChainHasFlags(aContentLocation, nsIProtocolHandler::URI_DOES_NOT_RETURN_DATA, &schemeNoReturnData)) ||
NS_FAILED(NS_URIChainHasFlags(aContentLocation, nsIProtocolHandler::URI_INHERITS_SECURITY_CONTEXT, &schemeInherits)) ||
NS_FAILED(NS_URIChainHasFlags(aContentLocation, nsIProtocolHandler::URI_SAFE_TO_LOAD_IN_SECURE_CONTEXT, &schemeSecure))) {
*aDecision = REJECT_REQUEST;
return NS_ERROR_FAILURE;
}
if (schemeLocal || schemeNoReturnData || schemeInherits || schemeSecure) {
*aDecision = ACCEPT;
return NS_OK;
}
@ -441,6 +445,7 @@ nsMixedContentBlocker::ShouldLoad(uint32_t aContentType,
bool isRootDocShell = false;
rv = docShell->GetAllowMixedContentAndConnectionData(&rootHasSecureConnection, &allowMixedContent, &isRootDocShell);
if (NS_FAILED(rv)) {
*aDecision = REJECT_REQUEST;
return rv;
}
@ -590,6 +595,7 @@ nsMixedContentBlocker::ShouldLoad(uint32_t aContentType,
// from within ShouldLoad
nsContentUtils::AddScriptRunner(
new nsMixedContentEvent(aRequestingContext, classification));
*aDecision = ACCEPT;
return NS_OK;
}
@ -610,8 +616,10 @@ nsMixedContentBlocker::ShouldProcess(uint32_t aContentType,
if (!aContentLocation) {
// aContentLocation may be null when a plugin is loading without an associated URI resource
if (aContentType == TYPE_OBJECT) {
*aDecision = ACCEPT;
return NS_OK;
} else {
*aDecision = REJECT_REQUEST;
return NS_ERROR_FAILURE;
}
}

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

@ -9,6 +9,12 @@
#include "base/string_util.h"
#include "base/process_util.h"
#ifdef XP_WIN
#include <codecvt>
#endif
#include <string>
using std::vector;
using std::string;
@ -43,6 +49,13 @@ GMPProcessParent::Launch(int32_t aTimeoutMs)
{
vector<string> args;
args.push_back(mGMPPath);
#ifdef XP_WIN
std::wstring_convert<std::codecvt_utf8<wchar_t>> converter;
std::wstring wGMPPath = converter.from_bytes(mGMPPath.c_str());
mAllowedFilesRead.push_back(wGMPPath + L"\\*");
#endif
return SyncLaunch(args, aTimeoutMs, base::GetCurrentProcessArchitecture());
}

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

@ -828,6 +828,7 @@ nsXULElement::BindToTree(nsIDocument* aDocument,
{
if (!aBindingParent &&
aDocument &&
!aDocument->IsLoadedAsInteractiveData() &&
!aDocument->AllowXULXBL() &&
!aDocument->HasWarnedAbout(nsIDocument::eImportXULIntoContent)) {
nsContentUtils::AddScriptRunner(new XULInContentErrorReporter(aDocument));

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

@ -4,6 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "AnimationPlayer.h"
#include "AnimationUtils.h"
#include "mozilla/dom/AnimationPlayerBinding.h"
namespace mozilla {
@ -20,34 +21,16 @@ AnimationPlayer::WrapObject(JSContext* aCx)
return dom::AnimationPlayerBinding::Wrap(aCx, this);
}
double
AnimationPlayer::StartTime() const
Nullable<double>
AnimationPlayer::GetStartTime() const
{
Nullable<double> startTime = mTimeline->ToTimelineTime(mStartTime);
return startTime.IsNull() ? 0.0 : startTime.Value();
return AnimationUtils::TimeDurationToDouble(mStartTime);
}
double
AnimationPlayer::CurrentTime() const
Nullable<double>
AnimationPlayer::GetCurrentTime() const
{
Nullable<TimeDuration> currentTime = GetCurrentTimeDuration();
// The current time is currently only going to be null when don't have a
// refresh driver (e.g. because we are in a display:none iframe).
//
// Web Animations says that in this case we should use a timeline time of
// 0 (the "effective timeline time") and calculate the current time from that.
// Doing that, however, requires storing the start time as an offset rather
// than a timestamp so for now we just return 0.
//
// FIXME: Store player start time and pause start as offsets rather than
// timestamps and return the appropriate current time when the timeline time
// is null.
if (currentTime.IsNull()) {
return 0.0;
}
return currentTime.Value().ToMilliseconds();
return AnimationUtils::TimeDurationToDouble(GetCurrentTimeDuration());
}
void
@ -87,5 +70,20 @@ AnimationPlayer::IsCurrent() const
return GetSource() && GetSource()->IsCurrent();
}
Nullable<TimeDuration>
AnimationPlayer::GetCurrentTimeDuration() const
{
Nullable<TimeDuration> result;
if (!mHoldTime.IsNull()) {
result = mHoldTime;
} else {
Nullable<TimeDuration> timelineTime = mTimeline->GetCurrentTimeDuration();
if (!timelineTime.IsNull() && !mStartTime.IsNull()) {
result.SetValue(timelineTime.Value() - mStartTime.Value());
}
}
return result;
}
} // namespace dom
} // namespace mozilla

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

@ -48,8 +48,8 @@ public:
// AnimationPlayer methods
Animation* GetSource() const { return mSource; }
AnimationTimeline* Timeline() const { return mTimeline; }
double StartTime() const;
double CurrentTime() const;
Nullable<double> GetStartTime() const;
Nullable<double> GetCurrentTime() const;
bool IsRunningOnCompositor() const { return mIsRunningOnCompositor; }
void SetSource(Animation* aSource);
@ -67,29 +67,12 @@ public:
bool IsCurrent() const;
// Return the duration since the start time of the player, taking into
// account the pause state. May be negative.
// Returns a null value if the timeline associated with this object has a
// current timestamp that is null or if the start time of this object is
// null.
Nullable<TimeDuration> GetCurrentTimeDuration() const {
const TimeStamp& timelineTime = mTimeline->GetCurrentTimeStamp();
// FIXME: In order to support arbitrary timelines we will need to fix
// the pause logic to handle the timeline time going backwards.
MOZ_ASSERT(timelineTime.IsNull() || !IsPaused() ||
timelineTime >= mPauseStart,
"if paused, any non-null value of aTime must be at least"
" mPauseStart");
Nullable<TimeDuration> result; // Initializes to null
if (!timelineTime.IsNull() && !mStartTime.IsNull()) {
result.SetValue((IsPaused() ? mPauseStart : timelineTime) - mStartTime);
}
return result;
}
// account the pause state. May be negative or null.
Nullable<TimeDuration> GetCurrentTimeDuration() const;
// The beginning of the delay period.
TimeStamp mStartTime;
TimeStamp mPauseStart;
Nullable<TimeDuration> mStartTime;
Nullable<TimeDuration> mHoldTime;
uint8_t mPlayState;
bool mIsRunningOnCompositor;

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

@ -5,6 +5,7 @@
#include "AnimationTimeline.h"
#include "mozilla/dom/AnimationTimelineBinding.h"
#include "AnimationUtils.h"
#include "nsContentUtils.h"
#include "nsIPresShell.h"
#include "nsPresContext.h"
@ -28,7 +29,7 @@ AnimationTimeline::WrapObject(JSContext* aCx)
Nullable<double>
AnimationTimeline::GetCurrentTime() const
{
return ToTimelineTime(GetCurrentTimeStamp());
return AnimationUtils::TimeDurationToDouble(GetCurrentTimeDuration());
}
TimeStamp
@ -67,10 +68,16 @@ AnimationTimeline::GetCurrentTimeStamp() const
return result;
}
Nullable<double>
AnimationTimeline::ToTimelineTime(const mozilla::TimeStamp& aTimeStamp) const
Nullable<TimeDuration>
AnimationTimeline::GetCurrentTimeDuration() const
{
Nullable<double> result; // Initializes to null
return ToTimelineTime(GetCurrentTimeStamp());
}
Nullable<TimeDuration>
AnimationTimeline::ToTimelineTime(const TimeStamp& aTimeStamp) const
{
Nullable<TimeDuration> result; // Initializes to null
if (aTimeStamp.IsNull()) {
return result;
}
@ -80,7 +87,20 @@ AnimationTimeline::ToTimelineTime(const mozilla::TimeStamp& aTimeStamp) const
return result;
}
result.SetValue(timing->TimeStampToDOMHighRes(aTimeStamp));
result.SetValue(aTimeStamp - timing->GetNavigationStartTimeStamp());
return result;
}
TimeStamp
AnimationTimeline::ToTimeStamp(const TimeDuration& aTimeDuration) const
{
TimeStamp result;
nsRefPtr<nsDOMNavigationTiming> timing = mDocument->GetNavigationTiming();
if (MOZ_UNLIKELY(!timing)) {
return result;
}
result = timing->GetNavigationStartTimeStamp() + aTimeDuration;
return result;
}

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

@ -33,12 +33,17 @@ public:
nsISupports* GetParentObject() const { return mDocument; }
virtual JSObject* WrapObject(JSContext* aCx) MOZ_OVERRIDE;
// WebIDL API
Nullable<double> GetCurrentTime() const;
mozilla::TimeStamp GetCurrentTimeStamp() const;
Nullable<double> ToTimelineTime(const mozilla::TimeStamp& aTimeStamp) const;
Nullable<TimeDuration> GetCurrentTimeDuration() const;
Nullable<TimeDuration> ToTimelineTime(const TimeStamp& aTimeStamp) const;
TimeStamp ToTimeStamp(const TimeDuration& aTimelineTime) const;
protected:
TimeStamp GetCurrentTimeStamp() const;
virtual ~AnimationTimeline() { }
nsCOMPtr<nsIDocument> mDocument;
@ -46,7 +51,7 @@ protected:
// Store the most recently returned value of current time. This is used
// in cases where we don't have a refresh driver (e.g. because we are in
// a display:none iframe).
mutable mozilla::TimeStamp mLastCurrentTime;
mutable TimeStamp mLastCurrentTime;
};
} // namespace dom

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

@ -0,0 +1,29 @@
/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
/* 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/. */
#include "mozilla/TimeStamp.h"
#include "mozilla/dom/Nullable.h"
namespace mozilla {
namespace dom {
class AnimationUtils
{
public:
static Nullable<double>
TimeDurationToDouble(const Nullable<TimeDuration>& aTime)
{
Nullable<double> result;
if (!aTime.IsNull()) {
result.SetValue(aTime.Value().ToMilliseconds());
}
return result;
}
};
} // namespace dom
} // namespace mozilla

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

@ -959,10 +959,15 @@ DOMInterfaces = {
'wrapperCache': False
},
'Performance': {
'Performance': [{
'nativeType': 'nsPerformance',
'resultNotAddRefed': [ 'timing', 'navigation' ]
},
{
'nativeType': 'mozilla::dom::workers::Performance',
'headerFile': 'mozilla/dom/workers/bindings/Performance.h',
'workers': True,
}],
'PerformanceTiming': {
'nativeType': 'nsPerformanceTiming',
@ -1619,7 +1624,12 @@ DOMInterfaces = {
'implicitJSContext': [
'close', 'importScripts',
],
'binaryNames': { 'console': 'getConsole', },
# Rename a few things so we don't have both classes and methods
# with the same name
'binaryNames': {
'console': 'getConsole',
'performance': 'getPerformance',
},
},
'WorkerLocation': {

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

@ -2155,7 +2155,8 @@ class MethodDefiner(PropertyDefiner):
if not static:
stringifier = descriptor.operations['Stringifier']
if (stringifier and
unforgeable == MemberIsUnforgeable(stringifier, descriptor)):
unforgeable == MemberIsUnforgeable(stringifier, descriptor) and
isMaybeExposedIn(stringifier, descriptor)):
toStringDesc = {
"name": "toString",
"nativeName": stringifier.identifier.name,
@ -2168,7 +2169,9 @@ class MethodDefiner(PropertyDefiner):
else:
self.regular.append(toStringDesc)
jsonifier = descriptor.operations['Jsonifier']
if jsonifier:
if (jsonifier and
unforgeable == MemberIsUnforgeable(jsonifier, descriptor) and
isMaybeExposedIn(jsonifier, descriptor)):
toJSONDesc = {
"name": "toJSON",
"nativeName": jsonifier.identifier.name,

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

@ -551,12 +551,7 @@ class Descriptor(DescriptorProvider):
self.interface.isExposedOnlyInSomeWorkers()))
def isExposedConditionally(self):
return (self.interface.getExtendedAttribute("Pref") or
self.interface.getExtendedAttribute("ChromeOnly") or
self.interface.getExtendedAttribute("Func") or
self.interface.getExtendedAttribute("AvailableIn") or
self.interface.getExtendedAttribute("CheckPermissions") or
self.hasThreadChecks())
return self.interface.isExposedConditionally() or self.hasThreadChecks()
def needsXrayResolveHooks(self):
"""

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

@ -1018,6 +1018,14 @@ class IDLInterface(IDLObjectWithScope):
self.parentScope.primaryGlobalName,
[self.location])
# Conditional exposure makes no sense for interfaces with no
# interface object, unless they're navigator properties.
if (self.isExposedConditionally() and
not self.hasInterfaceObject() and
not self.getNavigatorProperty()):
raise WebIDLError("Interface with no interface object is "
"exposed conditionally",
[self.location])
def isInterface(self):
return True
@ -1356,6 +1364,13 @@ class IDLInterface(IDLObjectWithScope):
def hasMembersInSlots(self):
return self._ownMembersInSlots != 0
def isExposedConditionally(self):
return (self.getExtendedAttribute("Pref") or
self.getExtendedAttribute("ChromeOnly") or
self.getExtendedAttribute("Func") or
self.getExtendedAttribute("AvailableIn") or
self.getExtendedAttribute("CheckPermissions"))
class IDLDictionary(IDLObjectWithScope):
def __init__(self, location, parentScope, name, parent, members):
assert isinstance(parentScope, IDLScope)

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

@ -1,6 +1,8 @@
// files that end in .txt list other tests
// other lines are assumed to be .html files
always-fail.html
conformance/00_test_list.txt
conformance/more/00_test_list.txt

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

@ -0,0 +1,834 @@
[DEFAULT]
skip-if = e10s || os == 'b2g' || ((os == 'linux') && (buildapp == 'b2g'))
support-files = mochi-single.html
mochi-wrapper.css
always-fail.html
conformance/00_readme.txt
conformance/00_test_list.txt
conformance/LICENSE_CHROMIUM
conformance/attribs/00_test_list.txt
conformance/attribs/gl-enable-vertex-attrib.html
conformance/attribs/gl-vertex-attrib-zero-issues.html
conformance/attribs/gl-vertex-attrib.html
conformance/attribs/gl-vertexattribpointer-offsets.html
conformance/attribs/gl-vertexattribpointer.html
conformance/buffers/00_test_list.txt
conformance/buffers/buffer-bind-test.html
conformance/buffers/buffer-data-array-buffer.html
conformance/buffers/index-validation-copies-indices.html
conformance/buffers/index-validation-crash-with-buffer-sub-data.html
conformance/buffers/index-validation-verifies-too-many-indices.html
conformance/buffers/index-validation-with-resized-buffer.html
conformance/buffers/index-validation.html
conformance/canvas/00_test_list.txt
conformance/canvas/buffer-offscreen-test.html
conformance/canvas/buffer-preserve-test.html
conformance/canvas/canvas-test.html
conformance/canvas/canvas-zero-size.html
conformance/canvas/drawingbuffer-static-canvas-test.html
conformance/canvas/drawingbuffer-test.html
conformance/canvas/viewport-unchanged-upon-resize.html
conformance/context/00_test_list.txt
conformance/context/constants.html
conformance/context/context-attribute-preserve-drawing-buffer.html
conformance/context/context-attributes-alpha-depth-stencil-antialias.html
conformance/context/context-lost-restored.html
conformance/context/context-lost.html
conformance/context/context-type-test.html
conformance/context/incorrect-context-object-behaviour.html
conformance/context/methods.html
conformance/context/premultiplyalpha-test.html
conformance/context/resource-sharing-test.html
conformance/extensions/00_test_list.txt
conformance/extensions/ext-sRGB.html
conformance/extensions/ext-shader-texture-lod.html
conformance/extensions/ext-texture-filter-anisotropic.html
conformance/extensions/oes-standard-derivatives.html
conformance/extensions/oes-texture-float.html
conformance/extensions/oes-vertex-array-object.html
conformance/extensions/webgl-compressed-texture-etc1.html
conformance/extensions/webgl-compressed-texture-s3tc.html
conformance/extensions/webgl-debug-renderer-info.html
conformance/extensions/webgl-debug-shaders.html
conformance/extensions/webgl-depth-texture.html
conformance/glsl/00_test_list.txt
conformance/glsl/functions/00_test_list.txt
conformance/glsl/functions/glsl-function-abs.html
conformance/glsl/functions/glsl-function-acos.html
conformance/glsl/functions/glsl-function-asin.html
conformance/glsl/functions/glsl-function-atan-xy.html
conformance/glsl/functions/glsl-function-atan.html
conformance/glsl/functions/glsl-function-ceil.html
conformance/glsl/functions/glsl-function-clamp-float.html
conformance/glsl/functions/glsl-function-clamp-gentype.html
conformance/glsl/functions/glsl-function-cos.html
conformance/glsl/functions/glsl-function-cross.html
conformance/glsl/functions/glsl-function-distance.html
conformance/glsl/functions/glsl-function-dot.html
conformance/glsl/functions/glsl-function-faceforward.html
conformance/glsl/functions/glsl-function-floor.html
conformance/glsl/functions/glsl-function-fract.html
conformance/glsl/functions/glsl-function-length.html
conformance/glsl/functions/glsl-function-lessThan.html
conformance/glsl/functions/glsl-function-max-float.html
conformance/glsl/functions/glsl-function-max-gentype.html
conformance/glsl/functions/glsl-function-min-float.html
conformance/glsl/functions/glsl-function-min-gentype.html
conformance/glsl/functions/glsl-function-mix-float.html
conformance/glsl/functions/glsl-function-mix-gentype.html
conformance/glsl/functions/glsl-function-mod-float.html
conformance/glsl/functions/glsl-function-mod-gentype.html
conformance/glsl/functions/glsl-function-normalize.html
conformance/glsl/functions/glsl-function-reflect.html
conformance/glsl/functions/glsl-function-refract.html
conformance/glsl/functions/glsl-function-sign.html
conformance/glsl/functions/glsl-function-sin.html
conformance/glsl/functions/glsl-function-smoothstep-float.html
conformance/glsl/functions/glsl-function-smoothstep-gentype.html
conformance/glsl/functions/glsl-function-step-float.html
conformance/glsl/functions/glsl-function-step-gentype.html
conformance/glsl/functions/glsl-function.html
conformance/glsl/implicit/00_test_list.txt
conformance/glsl/implicit/add_int_float.vert.html
conformance/glsl/implicit/add_int_mat2.vert.html
conformance/glsl/implicit/add_int_mat3.vert.html
conformance/glsl/implicit/add_int_mat4.vert.html
conformance/glsl/implicit/add_int_vec2.vert.html
conformance/glsl/implicit/add_int_vec3.vert.html
conformance/glsl/implicit/add_int_vec4.vert.html
conformance/glsl/implicit/add_ivec2_vec2.vert.html
conformance/glsl/implicit/add_ivec3_vec3.vert.html
conformance/glsl/implicit/add_ivec4_vec4.vert.html
conformance/glsl/implicit/assign_int_to_float.vert.html
conformance/glsl/implicit/assign_ivec2_to_vec2.vert.html
conformance/glsl/implicit/assign_ivec3_to_vec3.vert.html
conformance/glsl/implicit/assign_ivec4_to_vec4.vert.html
conformance/glsl/implicit/construct_struct.vert.html
conformance/glsl/implicit/divide_int_float.vert.html
conformance/glsl/implicit/divide_int_mat2.vert.html
conformance/glsl/implicit/divide_int_mat3.vert.html
conformance/glsl/implicit/divide_int_mat4.vert.html
conformance/glsl/implicit/divide_int_vec2.vert.html
conformance/glsl/implicit/divide_int_vec3.vert.html
conformance/glsl/implicit/divide_int_vec4.vert.html
conformance/glsl/implicit/divide_ivec2_vec2.vert.html
conformance/glsl/implicit/divide_ivec3_vec3.vert.html
conformance/glsl/implicit/divide_ivec4_vec4.vert.html
conformance/glsl/implicit/equal_int_float.vert.html
conformance/glsl/implicit/equal_ivec2_vec2.vert.html
conformance/glsl/implicit/equal_ivec3_vec3.vert.html
conformance/glsl/implicit/equal_ivec4_vec4.vert.html
conformance/glsl/implicit/function_int_float.vert.html
conformance/glsl/implicit/function_ivec2_vec2.vert.html
conformance/glsl/implicit/function_ivec3_vec3.vert.html
conformance/glsl/implicit/function_ivec4_vec4.vert.html
conformance/glsl/implicit/greater_than.vert.html
conformance/glsl/implicit/greater_than_equal.vert.html
conformance/glsl/implicit/less_than.vert.html
conformance/glsl/implicit/less_than_equal.vert.html
conformance/glsl/implicit/multiply_int_float.vert.html
conformance/glsl/implicit/multiply_int_mat2.vert.html
conformance/glsl/implicit/multiply_int_mat3.vert.html
conformance/glsl/implicit/multiply_int_mat4.vert.html
conformance/glsl/implicit/multiply_int_vec2.vert.html
conformance/glsl/implicit/multiply_int_vec3.vert.html
conformance/glsl/implicit/multiply_int_vec4.vert.html
conformance/glsl/implicit/multiply_ivec2_vec2.vert.html
conformance/glsl/implicit/multiply_ivec3_vec3.vert.html
conformance/glsl/implicit/multiply_ivec4_vec4.vert.html
conformance/glsl/implicit/not_equal_int_float.vert.html
conformance/glsl/implicit/not_equal_ivec2_vec2.vert.html
conformance/glsl/implicit/not_equal_ivec3_vec3.vert.html
conformance/glsl/implicit/not_equal_ivec4_vec4.vert.html
conformance/glsl/implicit/subtract_int_float.vert.html
conformance/glsl/implicit/subtract_int_mat2.vert.html
conformance/glsl/implicit/subtract_int_mat3.vert.html
conformance/glsl/implicit/subtract_int_mat4.vert.html
conformance/glsl/implicit/subtract_int_vec2.vert.html
conformance/glsl/implicit/subtract_int_vec3.vert.html
conformance/glsl/implicit/subtract_int_vec4.vert.html
conformance/glsl/implicit/subtract_ivec2_vec2.vert.html
conformance/glsl/implicit/subtract_ivec3_vec3.vert.html
conformance/glsl/implicit/subtract_ivec4_vec4.vert.html
conformance/glsl/implicit/ternary_int_float.vert.html
conformance/glsl/implicit/ternary_ivec2_vec2.vert.html
conformance/glsl/implicit/ternary_ivec3_vec3.vert.html
conformance/glsl/implicit/ternary_ivec4_vec4.vert.html
conformance/glsl/matrices/00_test_list.txt
conformance/glsl/matrices/glsl-mat4-to-mat3.html
conformance/glsl/misc/00_test_list.txt
conformance/glsl/misc/attrib-location-length-limits.html
conformance/glsl/misc/embedded-struct-definitions-forbidden.html
conformance/glsl/misc/glsl-2types-of-textures-on-same-unit.html
conformance/glsl/misc/glsl-function-nodes.html
conformance/glsl/misc/glsl-long-variable-names.html
conformance/glsl/misc/glsl-vertex-branch.html
conformance/glsl/misc/include.vs
conformance/glsl/misc/non-ascii-comments.vert.html
conformance/glsl/misc/non-ascii.vert.html
conformance/glsl/misc/re-compile-re-link.html
conformance/glsl/misc/shader-with-256-character-identifier.frag.html
conformance/glsl/misc/shader-with-257-character-identifier.frag.html
conformance/glsl/misc/shader-with-_webgl-identifier.vert.html
conformance/glsl/misc/shader-with-arbitrary-indexing.frag.html
conformance/glsl/misc/shader-with-arbitrary-indexing.vert.html
conformance/glsl/misc/shader-with-attrib-array.vert.html
conformance/glsl/misc/shader-with-attrib-struct.vert.html
conformance/glsl/misc/shader-with-clipvertex.vert.html
conformance/glsl/misc/shader-with-comma-assignment.html
conformance/glsl/misc/shader-with-comma-conditional-assignment.html
conformance/glsl/misc/shader-with-conditional-scoping.html
conformance/glsl/misc/shader-with-default-precision.frag.html
conformance/glsl/misc/shader-with-default-precision.vert.html
conformance/glsl/misc/shader-with-define-line-continuation.frag.html
conformance/glsl/misc/shader-with-dfdx-no-ext.frag.html
conformance/glsl/misc/shader-with-dfdx.frag.html
conformance/glsl/misc/shader-with-do-scoping.html
conformance/glsl/misc/shader-with-error-directive.html
conformance/glsl/misc/shader-with-explicit-int-cast.vert.html
conformance/glsl/misc/shader-with-float-return-value.frag.html
conformance/glsl/misc/shader-with-for-loop.html
conformance/glsl/misc/shader-with-for-scoping.html
conformance/glsl/misc/shader-with-frag-depth.frag.html
conformance/glsl/misc/shader-with-function-recursion.frag.html
conformance/glsl/misc/shader-with-function-scoped-struct.html
conformance/glsl/misc/shader-with-functional-scoping.html
conformance/glsl/misc/shader-with-glcolor.vert.html
conformance/glsl/misc/shader-with-gles-1.frag.html
conformance/glsl/misc/shader-with-gles-symbol.frag.html
conformance/glsl/misc/shader-with-glprojectionmatrix.vert.html
conformance/glsl/misc/shader-with-hex-int-constant-macro.html
conformance/glsl/misc/shader-with-implicit-vec3-to-vec4-cast.vert.html
conformance/glsl/misc/shader-with-include.vert.html
conformance/glsl/misc/shader-with-int-return-value.frag.html
conformance/glsl/misc/shader-with-invalid-identifier.frag.html
conformance/glsl/misc/shader-with-ivec2-return-value.frag.html
conformance/glsl/misc/shader-with-ivec3-return-value.frag.html
conformance/glsl/misc/shader-with-ivec4-return-value.frag.html
conformance/glsl/misc/shader-with-limited-indexing.frag.html
conformance/glsl/misc/shader-with-line-directive.html
conformance/glsl/misc/shader-with-long-line.html
conformance/glsl/misc/shader-with-non-ascii-error.frag.html
conformance/glsl/misc/shader-with-precision.frag.html
conformance/glsl/misc/shader-with-quoted-error.frag.html
conformance/glsl/misc/shader-with-undefined-preprocessor-symbol.frag.html
conformance/glsl/misc/shader-with-uniform-in-loop-condition.vert.html
conformance/glsl/misc/shader-with-vec2-return-value.frag.html
conformance/glsl/misc/shader-with-vec3-return-value.frag.html
conformance/glsl/misc/shader-with-vec4-return-value.frag.html
conformance/glsl/misc/shader-with-vec4-vec3-vec4-conditional.html
conformance/glsl/misc/shader-with-version-100.frag.html
conformance/glsl/misc/shader-with-version-100.vert.html
conformance/glsl/misc/shader-with-version-120.vert.html
conformance/glsl/misc/shader-with-version-130.vert.html
conformance/glsl/misc/shader-with-webgl-identifier.vert.html
conformance/glsl/misc/shader-without-precision.frag.html
conformance/glsl/misc/shared.html
conformance/glsl/misc/struct-nesting-exceeds-maximum.html
conformance/glsl/misc/struct-nesting-under-maximum.html
conformance/glsl/misc/uniform-location-length-limits.html
conformance/glsl/reserved/00_test_list.txt
conformance/glsl/reserved/_webgl_field.vert.html
conformance/glsl/reserved/_webgl_function.vert.html
conformance/glsl/reserved/_webgl_struct.vert.html
conformance/glsl/reserved/_webgl_variable.vert.html
conformance/glsl/reserved/webgl_field.vert.html
conformance/glsl/reserved/webgl_function.vert.html
conformance/glsl/reserved/webgl_struct.vert.html
conformance/glsl/reserved/webgl_variable.vert.html
conformance/glsl/samplers/00_test_list.txt
conformance/glsl/samplers/glsl-function-texture2d-bias.html
conformance/glsl/samplers/glsl-function-texture2dlod.html
conformance/glsl/samplers/glsl-function-texture2dproj.html
conformance/glsl/variables/00_test_list.txt
conformance/glsl/variables/gl-fragcoord.html
conformance/glsl/variables/gl-frontfacing.html
conformance/glsl/variables/gl-pointcoord.html
conformance/limits/00_test_list.txt
conformance/limits/gl-max-texture-dimensions.html
conformance/limits/gl-min-attribs.html
conformance/limits/gl-min-textures.html
conformance/limits/gl-min-uniforms.html
conformance/misc/00_test_list.txt
conformance/misc/bad-arguments-test.html
conformance/misc/delayed-drawing.html
conformance/misc/error-reporting.html
conformance/misc/functions-returning-strings.html
conformance/misc/instanceof-test.html
conformance/misc/invalid-passed-params.html
conformance/misc/is-object.html
conformance/misc/null-object-behaviour.html
conformance/misc/object-deletion-behaviour.html
conformance/misc/shader-precision-format.html
conformance/misc/type-conversion-test.html
conformance/misc/uninitialized-test.html
conformance/misc/webgl-specific.html
conformance/more/00_test_list.txt
conformance/more/README.md
conformance/more/all_tests.html
conformance/more/all_tests_linkonly.html
conformance/more/all_tests_sequential.html
conformance/more/conformance/argGenerators-A.js
conformance/more/conformance/argGenerators-B1.js
conformance/more/conformance/argGenerators-B2.js
conformance/more/conformance/argGenerators-B3.js
conformance/more/conformance/argGenerators-B4.js
conformance/more/conformance/argGenerators-C.js
conformance/more/conformance/argGenerators-D_G.js
conformance/more/conformance/argGenerators-G_I.js
conformance/more/conformance/argGenerators-L_S.js
conformance/more/conformance/argGenerators-S_V.js
conformance/more/conformance/badArgsArityLessThanArgc.html
conformance/more/conformance/constants.html
conformance/more/conformance/fuzzTheAPI.html
conformance/more/conformance/getContext.html
conformance/more/conformance/methods.html
conformance/more/conformance/quickCheckAPI-A.html
conformance/more/conformance/quickCheckAPI-B1.html
conformance/more/conformance/quickCheckAPI-B2.html
conformance/more/conformance/quickCheckAPI-B3.html
conformance/more/conformance/quickCheckAPI-B4.html
conformance/more/conformance/quickCheckAPI-C.html
conformance/more/conformance/quickCheckAPI-D_G.html
conformance/more/conformance/quickCheckAPI-G_I.html
conformance/more/conformance/quickCheckAPI-L_S.html
conformance/more/conformance/quickCheckAPI-S_V.html
conformance/more/conformance/quickCheckAPI.js
conformance/more/conformance/quickCheckAPIBadArgs.html
conformance/more/conformance/webGLArrays.html
conformance/more/demos/opengl_web.html
conformance/more/demos/video.html
conformance/more/functions/bindBuffer.html
conformance/more/functions/bindBufferBadArgs.html
conformance/more/functions/bindFramebufferLeaveNonZero.html
conformance/more/functions/bufferData.html
conformance/more/functions/bufferDataBadArgs.html
conformance/more/functions/bufferSubData.html
conformance/more/functions/bufferSubDataBadArgs.html
conformance/more/functions/copyTexImage2D.html
conformance/more/functions/copyTexImage2DBadArgs.html
conformance/more/functions/copyTexSubImage2D.html
conformance/more/functions/copyTexSubImage2DBadArgs.html
conformance/more/functions/deleteBufferBadArgs.html
conformance/more/functions/drawArrays.html
conformance/more/functions/drawArraysOutOfBounds.html
conformance/more/functions/drawElements.html
conformance/more/functions/drawElementsBadArgs.html
conformance/more/functions/isTests.html
conformance/more/functions/readPixels.html
conformance/more/functions/readPixelsBadArgs.html
conformance/more/functions/texImage2D.html
conformance/more/functions/texImage2DBadArgs.html
conformance/more/functions/texImage2DHTML.html
conformance/more/functions/texImage2DHTMLBadArgs.html
conformance/more/functions/texSubImage2D.html
conformance/more/functions/texSubImage2DBadArgs.html
conformance/more/functions/texSubImage2DHTML.html
conformance/more/functions/texSubImage2DHTMLBadArgs.html
conformance/more/functions/uniformMatrix.html
conformance/more/functions/uniformMatrixBadArgs.html
conformance/more/functions/uniformf.html
conformance/more/functions/uniformfArrayLen1.html
conformance/more/functions/uniformfBadArgs.html
conformance/more/functions/uniformi.html
conformance/more/functions/uniformiBadArgs.html
conformance/more/functions/vertexAttrib.html
conformance/more/functions/vertexAttribBadArgs.html
conformance/more/functions/vertexAttribPointer.html
conformance/more/functions/vertexAttribPointerBadArgs.html
conformance/more/glsl/arrayOutOfBounds.html
conformance/more/glsl/longLoops.html
conformance/more/glsl/uniformOutOfBounds.html
conformance/more/glsl/unusedAttribsUniforms.html
conformance/more/index.html
conformance/more/performance/CPUvsGPU.html
conformance/more/performance/bandwidth.html
conformance/more/performance/jsGCPause.html
conformance/more/performance/jsMatrixMult.html
conformance/more/performance/jsToGLOverhead.html
conformance/more/unit.css
conformance/more/unit.js
conformance/more/util.js
conformance/programs/00_test_list.txt
conformance/programs/get-active-test.html
conformance/programs/gl-bind-attrib-location-test.html
conformance/programs/gl-get-active-attribute.html
conformance/programs/gl-get-active-uniform.html
conformance/programs/gl-getshadersource.html
conformance/programs/gl-shader-test.html
conformance/programs/invalid-UTF-16.html
conformance/programs/program-test.html
conformance/reading/00_test_list.txt
conformance/reading/read-pixels-pack-alignment.html
conformance/reading/read-pixels-test.html
conformance/renderbuffers/00_test_list.txt
conformance/renderbuffers/framebuffer-object-attachment.html
conformance/renderbuffers/framebuffer-test.html
conformance/renderbuffers/renderbuffer-initialization.html
conformance/rendering/00_test_list.txt
conformance/rendering/draw-arrays-out-of-bounds.html
conformance/rendering/draw-elements-out-of-bounds.html
conformance/rendering/gl-clear.html
conformance/rendering/gl-drawelements.html
conformance/rendering/gl-scissor-test.html
conformance/rendering/line-loop-tri-fan.html
conformance/rendering/more-than-65536-indices.html
conformance/rendering/point-size.html
conformance/rendering/triangle.html
conformance/resources/3x3.png
conformance/resources/blue-1x1.jpg
conformance/resources/boolUniformShader.vert
conformance/resources/bug-32888-texture.png
conformance/resources/floatUniformShader.vert
conformance/resources/fragmentShader.frag
conformance/resources/glsl-conformance-test.js
conformance/resources/glsl-feature-tests.css
conformance/resources/glsl-generator.js
conformance/resources/gray-ramp-256-with-128-alpha.png
conformance/resources/gray-ramp-256.png
conformance/resources/gray-ramp-default-gamma.png
conformance/resources/gray-ramp-gamma0.1.png
conformance/resources/gray-ramp-gamma1.0.png
conformance/resources/gray-ramp-gamma2.0.png
conformance/resources/gray-ramp-gamma4.0.png
conformance/resources/gray-ramp-gamma9.0.png
conformance/resources/gray-ramp.png
conformance/resources/green-2x2-16bit.png
conformance/resources/intArrayUniformShader.vert
conformance/resources/intUniformShader.vert
conformance/resources/matUniformShader.vert
conformance/resources/noopUniformShader.frag
conformance/resources/noopUniformShader.vert
conformance/resources/npot-video.mp4
conformance/resources/npot-video.theora.ogv
conformance/resources/npot-video.webmvp8.webm
conformance/resources/pnglib.js
conformance/resources/red-green.mp4
conformance/resources/red-green.png
conformance/resources/red-green.theora.ogv
conformance/resources/red-green.webmvp8.webm
conformance/resources/red-indexed.png
conformance/resources/samplerUniformShader.frag
conformance/resources/small-square-with-cie-rgb-profile.png
conformance/resources/small-square-with-colormatch-profile.png
conformance/resources/small-square-with-colorspin-profile.jpg
conformance/resources/small-square-with-colorspin-profile.png
conformance/resources/small-square-with-e-srgb-profile.png
conformance/resources/small-square-with-smpte-c-profile.png
conformance/resources/small-square-with-srgb-iec61966-2.1-profile.png
conformance/resources/structUniformShader.vert
conformance/resources/vertexShader.vert
conformance/resources/webgl-test-utils.js
conformance/resources/webgl-test.js
conformance/resources/zero-alpha.png
conformance/state/00_test_list.txt
conformance/state/gl-enable-enum-test.html
conformance/state/gl-enum-tests.html
conformance/state/gl-get-calls.html
conformance/state/gl-geterror.html
conformance/state/gl-getstring.html
conformance/state/gl-object-get-calls.html
conformance/textures/00_test_list.txt
conformance/textures/compressed-tex-image.html
conformance/textures/copy-tex-image-and-sub-image-2d.html
conformance/textures/gl-pixelstorei.html
conformance/textures/gl-teximage.html
conformance/textures/origin-clean-conformance.html
conformance/textures/tex-image-and-sub-image-2d-with-array-buffer-view.html
conformance/textures/tex-image-and-sub-image-2d-with-canvas.html
conformance/textures/tex-image-and-sub-image-2d-with-image-data.html
conformance/textures/tex-image-and-sub-image-2d-with-image.html
conformance/textures/tex-image-and-sub-image-2d-with-video.html
conformance/textures/tex-image-and-uniform-binding-bugs.html
conformance/textures/tex-image-with-format-and-type.html
conformance/textures/tex-image-with-invalid-data.html
conformance/textures/tex-input-validation.html
conformance/textures/tex-sub-image-2d-bad-args.html
conformance/textures/tex-sub-image-2d.html
conformance/textures/texparameter-test.html
conformance/textures/texture-active-bind-2.html
conformance/textures/texture-active-bind.html
conformance/textures/texture-clear.html
conformance/textures/texture-complete.html
conformance/textures/texture-formats-test.html
conformance/textures/texture-mips.html
conformance/textures/texture-npot-video.html
conformance/textures/texture-npot.html
conformance/textures/texture-size-cube-maps.html
conformance/textures/texture-size.html
conformance/textures/texture-transparent-pixels-initialized.html
conformance/typedarrays/00_test_list.txt
conformance/typedarrays/array-buffer-crash.html
conformance/typedarrays/array-buffer-view-crash.html
conformance/typedarrays/array-unit-tests.html
conformance/uniforms/00_test_list.txt
conformance/uniforms/gl-uniform-arrays.html
conformance/uniforms/gl-uniform-bool.html
conformance/uniforms/gl-uniformmatrix4fv.html
conformance/uniforms/gl-unknown-uniform.html
conformance/uniforms/null-uniform-location.html
conformance/uniforms/uniform-location.html
conformance/uniforms/uniform-samplers-test.html
resources/cors-util.js
resources/desktop-gl-constants.js
resources/js-test-pre.js
resources/js-test-style.css
resources/opengl_logo.jpg
resources/thunderbird-logo-64x64.png
resources/webgl-logo.png
resources/webgl-test-harness.js
[_wrappers/test_always-fail.html]
[_wrappers/test_conformance__attribs__gl-enable-vertex-attrib.html]
[_wrappers/test_conformance__attribs__gl-vertex-attrib-zero-issues.html]
[_wrappers/test_conformance__attribs__gl-vertex-attrib.html]
[_wrappers/test_conformance__attribs__gl-vertexattribpointer-offsets.html]
[_wrappers/test_conformance__attribs__gl-vertexattribpointer.html]
[_wrappers/test_conformance__buffers__buffer-bind-test.html]
[_wrappers/test_conformance__buffers__buffer-data-array-buffer.html]
[_wrappers/test_conformance__buffers__index-validation-copies-indices.html]
[_wrappers/test_conformance__buffers__index-validation-crash-with-buffer-sub-data.html]
[_wrappers/test_conformance__buffers__index-validation-verifies-too-many-indices.html]
[_wrappers/test_conformance__buffers__index-validation-with-resized-buffer.html]
[_wrappers/test_conformance__buffers__index-validation.html]
[_wrappers/test_conformance__canvas__buffer-offscreen-test.html]
[_wrappers/test_conformance__canvas__buffer-preserve-test.html]
[_wrappers/test_conformance__canvas__canvas-test.html]
[_wrappers/test_conformance__canvas__canvas-zero-size.html]
[_wrappers/test_conformance__canvas__drawingbuffer-static-canvas-test.html]
skip-if = os == 'mac'
[_wrappers/test_conformance__canvas__drawingbuffer-test.html]
[_wrappers/test_conformance__canvas__viewport-unchanged-upon-resize.html]
[_wrappers/test_conformance__context__constants.html]
[_wrappers/test_conformance__context__context-attributes-alpha-depth-stencil-antialias.html]
skip-if = (os == 'b2g')
[_wrappers/test_conformance__context__context-lost-restored.html]
[_wrappers/test_conformance__context__context-lost.html]
[_wrappers/test_conformance__context__context-type-test.html]
[_wrappers/test_conformance__context__incorrect-context-object-behaviour.html]
[_wrappers/test_conformance__context__methods.html]
[_wrappers/test_conformance__context__premultiplyalpha-test.html]
[_wrappers/test_conformance__context__resource-sharing-test.html]
[_wrappers/test_conformance__extensions__oes-standard-derivatives.html]
[_wrappers/test_conformance__extensions__ext-texture-filter-anisotropic.html]
[_wrappers/test_conformance__extensions__oes-texture-float.html]
[_wrappers/test_conformance__extensions__oes-vertex-array-object.html]
[_wrappers/test_conformance__extensions__webgl-debug-renderer-info.html]
[_wrappers/test_conformance__extensions__webgl-debug-shaders.html]
[_wrappers/test_conformance__extensions__webgl-compressed-texture-etc1.html]
[_wrappers/test_conformance__extensions__webgl-compressed-texture-s3tc.html]
[_wrappers/test_conformance__extensions__ext-sRGB.html]
[_wrappers/test_conformance__extensions__ext-shader-texture-lod.html]
[_wrappers/test_conformance__glsl__functions__glsl-function.html]
[_wrappers/test_conformance__glsl__functions__glsl-function-abs.html]
[_wrappers/test_conformance__glsl__functions__glsl-function-acos.html]
[_wrappers/test_conformance__glsl__functions__glsl-function-asin.html]
[_wrappers/test_conformance__glsl__functions__glsl-function-atan.html]
[_wrappers/test_conformance__glsl__functions__glsl-function-atan-xy.html]
[_wrappers/test_conformance__glsl__functions__glsl-function-ceil.html]
[_wrappers/test_conformance__glsl__functions__glsl-function-clamp-float.html]
[_wrappers/test_conformance__glsl__functions__glsl-function-clamp-gentype.html]
[_wrappers/test_conformance__glsl__functions__glsl-function-cos.html]
[_wrappers/test_conformance__glsl__functions__glsl-function-cross.html]
[_wrappers/test_conformance__glsl__functions__glsl-function-distance.html]
[_wrappers/test_conformance__glsl__functions__glsl-function-dot.html]
[_wrappers/test_conformance__glsl__functions__glsl-function-faceforward.html]
[_wrappers/test_conformance__glsl__functions__glsl-function-floor.html]
[_wrappers/test_conformance__glsl__functions__glsl-function-fract.html]
[_wrappers/test_conformance__glsl__functions__glsl-function-length.html]
[_wrappers/test_conformance__glsl__functions__glsl-function-max-float.html]
[_wrappers/test_conformance__glsl__functions__glsl-function-max-gentype.html]
[_wrappers/test_conformance__glsl__functions__glsl-function-min-float.html]
[_wrappers/test_conformance__glsl__functions__glsl-function-min-gentype.html]
[_wrappers/test_conformance__glsl__functions__glsl-function-mix-float.html]
[_wrappers/test_conformance__glsl__functions__glsl-function-mix-gentype.html]
[_wrappers/test_conformance__glsl__functions__glsl-function-mod-float.html]
[_wrappers/test_conformance__glsl__functions__glsl-function-mod-gentype.html]
[_wrappers/test_conformance__glsl__functions__glsl-function-normalize.html]
[_wrappers/test_conformance__glsl__functions__glsl-function-reflect.html]
[_wrappers/test_conformance__glsl__functions__glsl-function-sign.html]
[_wrappers/test_conformance__glsl__functions__glsl-function-sin.html]
[_wrappers/test_conformance__glsl__functions__glsl-function-step-float.html]
[_wrappers/test_conformance__glsl__functions__glsl-function-step-gentype.html]
[_wrappers/test_conformance__glsl__functions__glsl-function-smoothstep-float.html]
[_wrappers/test_conformance__glsl__functions__glsl-function-smoothstep-gentype.html]
[_wrappers/test_conformance__glsl__implicit__add_int_float.vert.html]
[_wrappers/test_conformance__glsl__implicit__add_int_mat2.vert.html]
[_wrappers/test_conformance__glsl__implicit__add_int_mat3.vert.html]
[_wrappers/test_conformance__glsl__implicit__add_int_mat4.vert.html]
[_wrappers/test_conformance__glsl__implicit__add_int_vec2.vert.html]
[_wrappers/test_conformance__glsl__implicit__add_int_vec3.vert.html]
[_wrappers/test_conformance__glsl__implicit__add_int_vec4.vert.html]
[_wrappers/test_conformance__glsl__implicit__add_ivec2_vec2.vert.html]
[_wrappers/test_conformance__glsl__implicit__add_ivec3_vec3.vert.html]
[_wrappers/test_conformance__glsl__implicit__add_ivec4_vec4.vert.html]
[_wrappers/test_conformance__glsl__implicit__assign_int_to_float.vert.html]
[_wrappers/test_conformance__glsl__implicit__assign_ivec2_to_vec2.vert.html]
[_wrappers/test_conformance__glsl__implicit__assign_ivec3_to_vec3.vert.html]
[_wrappers/test_conformance__glsl__implicit__assign_ivec4_to_vec4.vert.html]
[_wrappers/test_conformance__glsl__implicit__construct_struct.vert.html]
[_wrappers/test_conformance__glsl__implicit__divide_int_float.vert.html]
[_wrappers/test_conformance__glsl__implicit__divide_int_mat2.vert.html]
[_wrappers/test_conformance__glsl__implicit__divide_int_mat3.vert.html]
[_wrappers/test_conformance__glsl__implicit__divide_int_mat4.vert.html]
[_wrappers/test_conformance__glsl__implicit__divide_int_vec2.vert.html]
[_wrappers/test_conformance__glsl__implicit__divide_int_vec3.vert.html]
[_wrappers/test_conformance__glsl__implicit__divide_int_vec4.vert.html]
[_wrappers/test_conformance__glsl__implicit__divide_ivec2_vec2.vert.html]
[_wrappers/test_conformance__glsl__implicit__divide_ivec3_vec3.vert.html]
[_wrappers/test_conformance__glsl__implicit__divide_ivec4_vec4.vert.html]
[_wrappers/test_conformance__glsl__implicit__equal_int_float.vert.html]
[_wrappers/test_conformance__glsl__implicit__equal_ivec2_vec2.vert.html]
[_wrappers/test_conformance__glsl__implicit__equal_ivec3_vec3.vert.html]
[_wrappers/test_conformance__glsl__implicit__equal_ivec4_vec4.vert.html]
[_wrappers/test_conformance__glsl__implicit__function_int_float.vert.html]
[_wrappers/test_conformance__glsl__implicit__function_ivec2_vec2.vert.html]
[_wrappers/test_conformance__glsl__implicit__function_ivec3_vec3.vert.html]
[_wrappers/test_conformance__glsl__implicit__function_ivec4_vec4.vert.html]
[_wrappers/test_conformance__glsl__implicit__greater_than.vert.html]
[_wrappers/test_conformance__glsl__implicit__greater_than_equal.vert.html]
[_wrappers/test_conformance__glsl__implicit__less_than.vert.html]
[_wrappers/test_conformance__glsl__implicit__less_than_equal.vert.html]
[_wrappers/test_conformance__glsl__implicit__multiply_int_float.vert.html]
[_wrappers/test_conformance__glsl__implicit__multiply_int_mat2.vert.html]
[_wrappers/test_conformance__glsl__implicit__multiply_int_mat3.vert.html]
[_wrappers/test_conformance__glsl__implicit__multiply_int_mat4.vert.html]
[_wrappers/test_conformance__glsl__implicit__multiply_int_vec2.vert.html]
[_wrappers/test_conformance__glsl__implicit__multiply_int_vec3.vert.html]
[_wrappers/test_conformance__glsl__implicit__multiply_int_vec4.vert.html]
[_wrappers/test_conformance__glsl__implicit__multiply_ivec2_vec2.vert.html]
[_wrappers/test_conformance__glsl__implicit__multiply_ivec3_vec3.vert.html]
[_wrappers/test_conformance__glsl__implicit__multiply_ivec4_vec4.vert.html]
[_wrappers/test_conformance__glsl__implicit__not_equal_int_float.vert.html]
[_wrappers/test_conformance__glsl__implicit__not_equal_ivec2_vec2.vert.html]
[_wrappers/test_conformance__glsl__implicit__not_equal_ivec3_vec3.vert.html]
[_wrappers/test_conformance__glsl__implicit__not_equal_ivec4_vec4.vert.html]
[_wrappers/test_conformance__glsl__implicit__subtract_int_float.vert.html]
[_wrappers/test_conformance__glsl__implicit__subtract_int_mat2.vert.html]
[_wrappers/test_conformance__glsl__implicit__subtract_int_mat3.vert.html]
[_wrappers/test_conformance__glsl__implicit__subtract_int_mat4.vert.html]
[_wrappers/test_conformance__glsl__implicit__subtract_int_vec2.vert.html]
[_wrappers/test_conformance__glsl__implicit__subtract_int_vec3.vert.html]
[_wrappers/test_conformance__glsl__implicit__subtract_int_vec4.vert.html]
[_wrappers/test_conformance__glsl__implicit__subtract_ivec2_vec2.vert.html]
[_wrappers/test_conformance__glsl__implicit__subtract_ivec3_vec3.vert.html]
[_wrappers/test_conformance__glsl__implicit__subtract_ivec4_vec4.vert.html]
[_wrappers/test_conformance__glsl__implicit__ternary_int_float.vert.html]
[_wrappers/test_conformance__glsl__implicit__ternary_ivec2_vec2.vert.html]
[_wrappers/test_conformance__glsl__implicit__ternary_ivec3_vec3.vert.html]
[_wrappers/test_conformance__glsl__implicit__ternary_ivec4_vec4.vert.html]
[_wrappers/test_conformance__glsl__misc__attrib-location-length-limits.html]
[_wrappers/test_conformance__glsl__misc__embedded-struct-definitions-forbidden.html]
[_wrappers/test_conformance__glsl__misc__glsl-function-nodes.html]
[_wrappers/test_conformance__glsl__misc__glsl-long-variable-names.html]
[_wrappers/test_conformance__glsl__misc__non-ascii-comments.vert.html]
[_wrappers/test_conformance__glsl__misc__non-ascii.vert.html]
[_wrappers/test_conformance__glsl__misc__shader-with-256-character-identifier.frag.html]
[_wrappers/test_conformance__glsl__misc__shader-with-257-character-identifier.frag.html]
[_wrappers/test_conformance__glsl__misc__shader-with-_webgl-identifier.vert.html]
[_wrappers/test_conformance__glsl__misc__shader-with-arbitrary-indexing.frag.html]
[_wrappers/test_conformance__glsl__misc__shader-with-arbitrary-indexing.vert.html]
[_wrappers/test_conformance__glsl__misc__shader-with-attrib-array.vert.html]
[_wrappers/test_conformance__glsl__misc__shader-with-attrib-struct.vert.html]
[_wrappers/test_conformance__glsl__misc__shader-with-clipvertex.vert.html]
[_wrappers/test_conformance__glsl__misc__shader-with-default-precision.frag.html]
[_wrappers/test_conformance__glsl__misc__shader-with-default-precision.vert.html]
[_wrappers/test_conformance__glsl__misc__shader-with-define-line-continuation.frag.html]
[_wrappers/test_conformance__glsl__misc__shader-with-dfdx-no-ext.frag.html]
[_wrappers/test_conformance__glsl__misc__shader-with-dfdx.frag.html]
[_wrappers/test_conformance__glsl__misc__shader-with-error-directive.html]
[_wrappers/test_conformance__glsl__misc__shader-with-explicit-int-cast.vert.html]
[_wrappers/test_conformance__glsl__misc__shader-with-float-return-value.frag.html]
[_wrappers/test_conformance__glsl__misc__shader-with-frag-depth.frag.html]
[_wrappers/test_conformance__glsl__misc__shader-with-function-recursion.frag.html]
[_wrappers/test_conformance__glsl__misc__shader-with-glcolor.vert.html]
[_wrappers/test_conformance__glsl__misc__shader-with-gles-1.frag.html]
[_wrappers/test_conformance__glsl__misc__shader-with-gles-symbol.frag.html]
[_wrappers/test_conformance__glsl__misc__shader-with-glprojectionmatrix.vert.html]
[_wrappers/test_conformance__glsl__misc__shader-with-implicit-vec3-to-vec4-cast.vert.html]
[_wrappers/test_conformance__glsl__misc__shader-with-include.vert.html]
[_wrappers/test_conformance__glsl__misc__shader-with-int-return-value.frag.html]
[_wrappers/test_conformance__glsl__misc__shader-with-invalid-identifier.frag.html]
[_wrappers/test_conformance__glsl__misc__shader-with-ivec2-return-value.frag.html]
[_wrappers/test_conformance__glsl__misc__shader-with-ivec3-return-value.frag.html]
[_wrappers/test_conformance__glsl__misc__shader-with-ivec4-return-value.frag.html]
[_wrappers/test_conformance__glsl__misc__shader-with-limited-indexing.frag.html]
[_wrappers/test_conformance__glsl__misc__shader-with-long-line.html]
[_wrappers/test_conformance__glsl__misc__shader-with-non-ascii-error.frag.html]
[_wrappers/test_conformance__glsl__misc__shader-with-precision.frag.html]
[_wrappers/test_conformance__glsl__misc__shader-with-quoted-error.frag.html]
[_wrappers/test_conformance__glsl__misc__shader-with-undefined-preprocessor-symbol.frag.html]
[_wrappers/test_conformance__glsl__misc__shader-with-uniform-in-loop-condition.vert.html]
[_wrappers/test_conformance__glsl__misc__shader-with-vec2-return-value.frag.html]
[_wrappers/test_conformance__glsl__misc__shader-with-vec3-return-value.frag.html]
[_wrappers/test_conformance__glsl__misc__shader-with-vec4-return-value.frag.html]
[_wrappers/test_conformance__glsl__misc__shader-with-version-100.frag.html]
[_wrappers/test_conformance__glsl__misc__shader-with-version-100.vert.html]
[_wrappers/test_conformance__glsl__misc__shader-with-version-120.vert.html]
[_wrappers/test_conformance__glsl__misc__shader-with-version-130.vert.html]
[_wrappers/test_conformance__glsl__misc__shader-with-webgl-identifier.vert.html]
[_wrappers/test_conformance__glsl__misc__shader-without-precision.frag.html]
[_wrappers/test_conformance__glsl__misc__shared.html]
[_wrappers/test_conformance__glsl__misc__struct-nesting-exceeds-maximum.html]
[_wrappers/test_conformance__glsl__misc__struct-nesting-under-maximum.html]
[_wrappers/test_conformance__glsl__misc__uniform-location-length-limits.html]
[_wrappers/test_conformance__glsl__reserved___webgl_field.vert.html]
[_wrappers/test_conformance__glsl__reserved___webgl_function.vert.html]
[_wrappers/test_conformance__glsl__reserved___webgl_struct.vert.html]
[_wrappers/test_conformance__glsl__reserved___webgl_variable.vert.html]
[_wrappers/test_conformance__glsl__reserved__webgl_field.vert.html]
[_wrappers/test_conformance__glsl__reserved__webgl_function.vert.html]
[_wrappers/test_conformance__glsl__reserved__webgl_struct.vert.html]
[_wrappers/test_conformance__glsl__reserved__webgl_variable.vert.html]
[_wrappers/test_conformance__glsl__variables__gl-fragcoord.html]
[_wrappers/test_conformance__glsl__variables__gl-frontfacing.html]
[_wrappers/test_conformance__glsl__variables__gl-pointcoord.html]
[_wrappers/test_conformance__limits__gl-min-attribs.html]
[_wrappers/test_conformance__limits__gl-max-texture-dimensions.html]
[_wrappers/test_conformance__limits__gl-min-textures.html]
[_wrappers/test_conformance__limits__gl-min-uniforms.html]
[_wrappers/test_conformance__misc__bad-arguments-test.html]
[_wrappers/test_conformance__misc__error-reporting.html]
[_wrappers/test_conformance__misc__instanceof-test.html]
[_wrappers/test_conformance__misc__invalid-passed-params.html]
skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux')
[_wrappers/test_conformance__misc__is-object.html]
[_wrappers/test_conformance__misc__null-object-behaviour.html]
[_wrappers/test_conformance__misc__functions-returning-strings.html]
[_wrappers/test_conformance__misc__object-deletion-behaviour.html]
[_wrappers/test_conformance__misc__shader-precision-format.html]
[_wrappers/test_conformance__misc__type-conversion-test.html]
skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux')
[_wrappers/test_conformance__misc__uninitialized-test.html]
skip-if = os == 'android'
[_wrappers/test_conformance__misc__webgl-specific.html]
[_wrappers/test_conformance__programs__get-active-test.html]
[_wrappers/test_conformance__programs__gl-bind-attrib-location-test.html]
[_wrappers/test_conformance__programs__gl-get-active-attribute.html]
[_wrappers/test_conformance__programs__gl-get-active-uniform.html]
[_wrappers/test_conformance__programs__gl-getshadersource.html]
[_wrappers/test_conformance__programs__gl-shader-test.html]
[_wrappers/test_conformance__programs__invalid-UTF-16.html]
[_wrappers/test_conformance__programs__program-test.html]
[_wrappers/test_conformance__reading__read-pixels-pack-alignment.html]
[_wrappers/test_conformance__reading__read-pixels-test.html]
skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux')
[_wrappers/test_conformance__renderbuffers__framebuffer-object-attachment.html]
skip-if = os == 'android'
[_wrappers/test_conformance__renderbuffers__framebuffer-test.html]
[_wrappers/test_conformance__renderbuffers__renderbuffer-initialization.html]
[_wrappers/test_conformance__rendering__draw-arrays-out-of-bounds.html]
[_wrappers/test_conformance__rendering__draw-elements-out-of-bounds.html]
[_wrappers/test_conformance__rendering__gl-clear.html]
[_wrappers/test_conformance__rendering__gl-drawelements.html]
[_wrappers/test_conformance__rendering__gl-scissor-test.html]
[_wrappers/test_conformance__rendering__more-than-65536-indices.html]
[_wrappers/test_conformance__rendering__point-size.html]
[_wrappers/test_conformance__rendering__triangle.html]
[_wrappers/test_conformance__rendering__line-loop-tri-fan.html]
[_wrappers/test_conformance__state__gl-enable-enum-test.html]
[_wrappers/test_conformance__state__gl-enum-tests.html]
[_wrappers/test_conformance__state__gl-get-calls.html]
[_wrappers/test_conformance__state__gl-geterror.html]
[_wrappers/test_conformance__state__gl-getstring.html]
[_wrappers/test_conformance__state__gl-object-get-calls.html]
[_wrappers/test_conformance__textures__compressed-tex-image.html]
[_wrappers/test_conformance__textures__copy-tex-image-and-sub-image-2d.html]
[_wrappers/test_conformance__textures__gl-pixelstorei.html]
[_wrappers/test_conformance__textures__gl-teximage.html]
skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux')
[_wrappers/test_conformance__textures__origin-clean-conformance.html]
[_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-array-buffer-view.html]
[_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-canvas.html]
[_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-image-data.html]
[_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-image.html]
[_wrappers/test_conformance__textures__tex-image-and-sub-image-2d-with-video.html]
skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux') || (os == 'win')
[_wrappers/test_conformance__textures__tex-image-and-uniform-binding-bugs.html]
skip-if = (os == 'b2g')
[_wrappers/test_conformance__textures__tex-image-with-format-and-type.html]
skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux')
[_wrappers/test_conformance__textures__tex-image-with-invalid-data.html]
[_wrappers/test_conformance__textures__tex-input-validation.html]
skip-if = (os == 'android') || (os == 'b2g') || (os == 'linux')
[_wrappers/test_conformance__textures__tex-sub-image-2d-bad-args.html]
[_wrappers/test_conformance__textures__tex-sub-image-2d.html]
[_wrappers/test_conformance__textures__texparameter-test.html]
[_wrappers/test_conformance__textures__texture-active-bind-2.html]
[_wrappers/test_conformance__textures__texture-active-bind.html]
[_wrappers/test_conformance__textures__texture-complete.html]
[_wrappers/test_conformance__textures__texture-formats-test.html]
[_wrappers/test_conformance__textures__texture-mips.html]
[_wrappers/test_conformance__textures__texture-npot-video.html]
skip-if = os == 'win'
[_wrappers/test_conformance__textures__texture-npot.html]
[_wrappers/test_conformance__textures__texture-size.html]
skip-if = os == 'android'
[_wrappers/test_conformance__textures__texture-size-cube-maps.html]
skip-if = os == 'android'
[_wrappers/test_conformance__textures__texture-transparent-pixels-initialized.html]
[_wrappers/test_conformance__typedarrays__array-buffer-crash.html]
[_wrappers/test_conformance__typedarrays__array-buffer-view-crash.html]
[_wrappers/test_conformance__typedarrays__array-unit-tests.html]
[_wrappers/test_conformance__uniforms__gl-uniform-arrays.html]
[_wrappers/test_conformance__uniforms__gl-uniform-bool.html]
[_wrappers/test_conformance__uniforms__gl-uniformmatrix4fv.html]
[_wrappers/test_conformance__uniforms__gl-unknown-uniform.html]
[_wrappers/test_conformance__uniforms__null-uniform-location.html]
[_wrappers/test_conformance__uniforms__uniform-location.html]
[_wrappers/test_conformance__uniforms__uniform-samplers-test.html]
[_wrappers/test_conformance__more__conformance__constants.html]
[_wrappers/test_conformance__more__conformance__getContext.html]
[_wrappers/test_conformance__more__conformance__methods.html]
[_wrappers/test_conformance__more__conformance__quickCheckAPI-A.html]
[_wrappers/test_conformance__more__conformance__quickCheckAPI-B1.html]
[_wrappers/test_conformance__more__conformance__quickCheckAPI-B2.html]
[_wrappers/test_conformance__more__conformance__quickCheckAPI-B3.html]
[_wrappers/test_conformance__more__conformance__quickCheckAPI-B4.html]
[_wrappers/test_conformance__more__conformance__quickCheckAPI-C.html]
[_wrappers/test_conformance__more__conformance__quickCheckAPI-D_G.html]
[_wrappers/test_conformance__more__conformance__quickCheckAPI-G_I.html]
[_wrappers/test_conformance__more__conformance__quickCheckAPI-L_S.html]
[_wrappers/test_conformance__more__conformance__quickCheckAPI-S_V.html]
[_wrappers/test_conformance__more__conformance__webGLArrays.html]
[_wrappers/test_conformance__more__functions__bindBuffer.html]
[_wrappers/test_conformance__more__functions__bindBufferBadArgs.html]
[_wrappers/test_conformance__more__functions__bindFramebufferLeaveNonZero.html]
[_wrappers/test_conformance__more__functions__bufferData.html]
[_wrappers/test_conformance__more__functions__bufferDataBadArgs.html]
[_wrappers/test_conformance__more__functions__bufferSubData.html]
[_wrappers/test_conformance__more__functions__bufferSubDataBadArgs.html]
[_wrappers/test_conformance__more__functions__copyTexImage2D.html]
[_wrappers/test_conformance__more__functions__copyTexImage2DBadArgs.html]
[_wrappers/test_conformance__more__functions__copyTexSubImage2D.html]
[_wrappers/test_conformance__more__functions__copyTexSubImage2DBadArgs.html]
[_wrappers/test_conformance__more__functions__deleteBufferBadArgs.html]
[_wrappers/test_conformance__more__functions__drawArrays.html]
[_wrappers/test_conformance__more__functions__drawArraysOutOfBounds.html]
[_wrappers/test_conformance__more__functions__drawElements.html]
[_wrappers/test_conformance__more__functions__drawElementsBadArgs.html]
[_wrappers/test_conformance__more__functions__isTests.html]
[_wrappers/test_conformance__more__functions__readPixels.html]
[_wrappers/test_conformance__more__functions__readPixelsBadArgs.html]
[_wrappers/test_conformance__more__functions__texImage2D.html]
[_wrappers/test_conformance__more__functions__texImage2DBadArgs.html]
[_wrappers/test_conformance__more__functions__texImage2DHTML.html]
[_wrappers/test_conformance__more__functions__texImage2DHTMLBadArgs.html]
[_wrappers/test_conformance__more__functions__texSubImage2D.html]
[_wrappers/test_conformance__more__functions__texSubImage2DBadArgs.html]
[_wrappers/test_conformance__more__functions__texSubImage2DHTML.html]
[_wrappers/test_conformance__more__functions__texSubImage2DHTMLBadArgs.html]
[_wrappers/test_conformance__more__functions__uniformf.html]
[_wrappers/test_conformance__more__functions__uniformfBadArgs.html]
[_wrappers/test_conformance__more__functions__uniformfArrayLen1.html]
[_wrappers/test_conformance__more__functions__uniformi.html]
[_wrappers/test_conformance__more__functions__uniformiBadArgs.html]
[_wrappers/test_conformance__more__functions__uniformMatrix.html]
[_wrappers/test_conformance__more__functions__uniformMatrixBadArgs.html]
[_wrappers/test_conformance__more__functions__vertexAttrib.html]
[_wrappers/test_conformance__more__functions__vertexAttribBadArgs.html]
[_wrappers/test_conformance__more__functions__vertexAttribPointer.html]
[_wrappers/test_conformance__more__functions__vertexAttribPointerBadArgs.html]
[_wrappers/test_conformance__more__glsl__arrayOutOfBounds.html]
[_wrappers/test_conformance__more__glsl__uniformOutOfBounds.html]

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

@ -0,0 +1,16 @@
<!DOCTYPE HTML>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<html>
<head>
<title>
Mochitest wrapper for WebGL Conformance Test Suite tests
</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<link rel="stylesheet" type="text/css" href="../mochi-wrapper.css"/>
</head>
<body>
<iframe src='../mochi-single.html?always-fail.html'>
</iframe>
</body>
</html>

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

@ -0,0 +1,16 @@
<!DOCTYPE HTML>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<html>
<head>
<title>
Mochitest wrapper for WebGL Conformance Test Suite tests
</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<link rel="stylesheet" type="text/css" href="../mochi-wrapper.css"/>
</head>
<body>
<iframe src='../mochi-single.html?conformance/attribs/gl-enable-vertex-attrib.html'>
</iframe>
</body>
</html>

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

@ -0,0 +1,16 @@
<!DOCTYPE HTML>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<html>
<head>
<title>
Mochitest wrapper for WebGL Conformance Test Suite tests
</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<link rel="stylesheet" type="text/css" href="../mochi-wrapper.css"/>
</head>
<body>
<iframe src='../mochi-single.html?conformance/attribs/gl-vertex-attrib-zero-issues.html'>
</iframe>
</body>
</html>

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

@ -0,0 +1,16 @@
<!DOCTYPE HTML>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<html>
<head>
<title>
Mochitest wrapper for WebGL Conformance Test Suite tests
</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<link rel="stylesheet" type="text/css" href="../mochi-wrapper.css"/>
</head>
<body>
<iframe src='../mochi-single.html?conformance/attribs/gl-vertex-attrib.html'>
</iframe>
</body>
</html>

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

@ -0,0 +1,16 @@
<!DOCTYPE HTML>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<html>
<head>
<title>
Mochitest wrapper for WebGL Conformance Test Suite tests
</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<link rel="stylesheet" type="text/css" href="../mochi-wrapper.css"/>
</head>
<body>
<iframe src='../mochi-single.html?conformance/attribs/gl-vertexattribpointer-offsets.html'>
</iframe>
</body>
</html>

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

@ -0,0 +1,16 @@
<!DOCTYPE HTML>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<html>
<head>
<title>
Mochitest wrapper for WebGL Conformance Test Suite tests
</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<link rel="stylesheet" type="text/css" href="../mochi-wrapper.css"/>
</head>
<body>
<iframe src='../mochi-single.html?conformance/attribs/gl-vertexattribpointer.html'>
</iframe>
</body>
</html>

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

@ -0,0 +1,16 @@
<!DOCTYPE HTML>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<html>
<head>
<title>
Mochitest wrapper for WebGL Conformance Test Suite tests
</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<link rel="stylesheet" type="text/css" href="../mochi-wrapper.css"/>
</head>
<body>
<iframe src='../mochi-single.html?conformance/buffers/buffer-bind-test.html'>
</iframe>
</body>
</html>

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

@ -0,0 +1,16 @@
<!DOCTYPE HTML>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<html>
<head>
<title>
Mochitest wrapper for WebGL Conformance Test Suite tests
</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<link rel="stylesheet" type="text/css" href="../mochi-wrapper.css"/>
</head>
<body>
<iframe src='../mochi-single.html?conformance/buffers/buffer-data-array-buffer.html'>
</iframe>
</body>
</html>

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

@ -0,0 +1,16 @@
<!DOCTYPE HTML>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<html>
<head>
<title>
Mochitest wrapper for WebGL Conformance Test Suite tests
</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<link rel="stylesheet" type="text/css" href="../mochi-wrapper.css"/>
</head>
<body>
<iframe src='../mochi-single.html?conformance/buffers/index-validation-copies-indices.html'>
</iframe>
</body>
</html>

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

@ -0,0 +1,16 @@
<!DOCTYPE HTML>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<html>
<head>
<title>
Mochitest wrapper for WebGL Conformance Test Suite tests
</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<link rel="stylesheet" type="text/css" href="../mochi-wrapper.css"/>
</head>
<body>
<iframe src='../mochi-single.html?conformance/buffers/index-validation-crash-with-buffer-sub-data.html'>
</iframe>
</body>
</html>

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

@ -0,0 +1,16 @@
<!DOCTYPE HTML>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<html>
<head>
<title>
Mochitest wrapper for WebGL Conformance Test Suite tests
</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<link rel="stylesheet" type="text/css" href="../mochi-wrapper.css"/>
</head>
<body>
<iframe src='../mochi-single.html?conformance/buffers/index-validation-verifies-too-many-indices.html'>
</iframe>
</body>
</html>

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

@ -0,0 +1,16 @@
<!DOCTYPE HTML>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<html>
<head>
<title>
Mochitest wrapper for WebGL Conformance Test Suite tests
</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<link rel="stylesheet" type="text/css" href="../mochi-wrapper.css"/>
</head>
<body>
<iframe src='../mochi-single.html?conformance/buffers/index-validation-with-resized-buffer.html'>
</iframe>
</body>
</html>

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

@ -0,0 +1,16 @@
<!DOCTYPE HTML>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<html>
<head>
<title>
Mochitest wrapper for WebGL Conformance Test Suite tests
</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<link rel="stylesheet" type="text/css" href="../mochi-wrapper.css"/>
</head>
<body>
<iframe src='../mochi-single.html?conformance/buffers/index-validation.html'>
</iframe>
</body>
</html>

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

@ -0,0 +1,16 @@
<!DOCTYPE HTML>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<html>
<head>
<title>
Mochitest wrapper for WebGL Conformance Test Suite tests
</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<link rel="stylesheet" type="text/css" href="../mochi-wrapper.css"/>
</head>
<body>
<iframe src='../mochi-single.html?conformance/canvas/buffer-offscreen-test.html'>
</iframe>
</body>
</html>

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

@ -0,0 +1,16 @@
<!DOCTYPE HTML>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<html>
<head>
<title>
Mochitest wrapper for WebGL Conformance Test Suite tests
</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<link rel="stylesheet" type="text/css" href="../mochi-wrapper.css"/>
</head>
<body>
<iframe src='../mochi-single.html?conformance/canvas/buffer-preserve-test.html'>
</iframe>
</body>
</html>

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

@ -0,0 +1,16 @@
<!DOCTYPE HTML>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<html>
<head>
<title>
Mochitest wrapper for WebGL Conformance Test Suite tests
</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<link rel="stylesheet" type="text/css" href="../mochi-wrapper.css"/>
</head>
<body>
<iframe src='../mochi-single.html?conformance/canvas/canvas-test.html'>
</iframe>
</body>
</html>

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше