Merge mozilla-central to b2g-inbound

This commit is contained in:
Carsten "Tomcat" Book 2014-08-28 16:15:55 +02:00
Родитель eb8fd38ecc 6ea8870876
Коммит 49bc66d73d
241 изменённых файлов: 4570 добавлений и 1516 удалений

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

@ -1440,8 +1440,15 @@ HyperTextAccessible::SelectionBoundsAt(int32_t aSelectionNum,
endOffset = tempOffset;
}
*aStartOffset = DOMPointToOffset(startNode, startOffset);
*aEndOffset = DOMPointToOffset(endNode, endOffset, true);
if (!nsContentUtils::ContentIsDescendantOf(startNode, mContent))
*aStartOffset = 0;
else
*aStartOffset = DOMPointToOffset(startNode, startOffset);
if (!nsContentUtils::ContentIsDescendantOf(endNode, mContent))
*aEndOffset = CharacterCount();
else
*aEndOffset = DOMPointToOffset(endNode, endOffset, true);
return true;
}

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

@ -120,7 +120,7 @@ this.ContentControl.prototype = {
// Attempt to forward move to a potential child cursor in our
// new position.
this.sendToChild(vc, aMessage, { action: childAction});
this.sendToChild(vc, aMessage, { action: childAction }, true);
}
} else if (!this._childMessageSenders.has(aMessage.target)) {
// We failed to move, and the message is not from a child, so forward
@ -136,6 +136,8 @@ this.ContentControl.prototype = {
}
if (!Utils.getMessageManager(aEvent.target)) {
aEvent.preventDefault();
} else {
aEvent.target.focus();
}
},
@ -153,6 +155,7 @@ this.ContentControl.prototype = {
if (!forwarded) {
this._contentScope.get().sendAsyncMessage('AccessFu:CursorCleared');
}
this.document.activeElement.blur();
},
handleAutoMove: function cc_handleAutoMove(aMessage) {
@ -248,7 +251,7 @@ this.ContentControl.prototype = {
};
let vc = this.vc;
if (!this.sendToChild(vc, aMessage)) {
if (!this.sendToChild(vc, aMessage, null, true)) {
let position = vc.position;
activateAccessible(getActivatableDescendant(position) || position);
}
@ -347,12 +350,18 @@ this.ContentControl.prototype = {
return null;
},
sendToChild: function cc_sendToChild(aVirtualCursor, aMessage, aReplacer) {
let mm = this.getChildCursor(aVirtualCursor.position);
sendToChild: function cc_sendToChild(aVirtualCursor, aMessage, aReplacer,
aFocus) {
let position = aVirtualCursor.position;
let mm = this.getChildCursor(position);
if (!mm) {
return false;
}
if (aFocus) {
position.takeFocus();
}
// XXX: This is a silly way to make a deep copy
let newJSON = JSON.parse(JSON.stringify(aMessage.json));
newJSON.origin = 'parent';
@ -432,7 +441,7 @@ this.ContentControl.prototype = {
noOpIfOnScreen: true,
forcePresent: true
}
});
}, null, true);
if (!moved && !sentToChild) {
forcePresentFunc();

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

@ -156,7 +156,8 @@ this.EventManager.prototype = {
let reason = event.reason;
let oldAccessible = event.oldAccessible;
if (this.editState.editing) {
if (this.editState.editing &&
!Utils.getState(position).contains(States.FOCUSED)) {
aEvent.accessibleDocument.takeFocus();
}
this.present(

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

@ -303,6 +303,12 @@ AccessFuContentTest.prototype = {
this.lazyCompare(android, expected.android));
}
if (expected.focused) {
var doc = currentTabDocument();
is(doc.activeElement, doc.querySelector(expected.focused),
'Correct element is focused');
}
this.pump();
}

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

@ -30,10 +30,12 @@
[
// Simple traversal forward
[ContentMessages.simpleMoveNext, {
speak: ['Phone status bar', 'Traversal Rule test document']
speak: ['Phone status bar', 'Traversal Rule test document'],
focused: 'body'
}],
[ContentMessages.simpleMoveNext, {
speak: ['wow', {'string': 'headingLevel', 'args': [1]} ,'such app']
speak: ['wow', {'string': 'headingLevel', 'args': [1]} ,'such app'],
focused: 'iframe'
}],
[ContentMessages.simpleMoveNext, {
speak: ['many option', {'string': 'stateNotChecked'},

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

@ -111,7 +111,7 @@
function changeDOMSelection(aID, aNodeID1, aNodeOffset1,
aNodeID2, aNodeOffset2,
aStartOffset, aEndOffset)
aTests)
{
this.hyperText = getAccessible(aID, [ nsIAccessibleText ]);
@ -130,15 +130,18 @@
this.finalCheck = function changeDOMSelection_finalCheck()
{
is(this.hyperText.selectionCount, 1,
"setSelectionBounds: Wrong selection count for " + aID);
var startOffset = {}, endOffset = {};
this.hyperText.getSelectionBounds(0, startOffset, endOffset);
for (var i = 0; i < aTests.length; i++) {
var text = getAccessible(aTests[i][0], nsIAccessibleText);
is(text.selectionCount, 1,
"setSelectionBounds: Wrong selection count for " + aID);
var startOffset = {}, endOffset = {};
text.getSelectionBounds(0, startOffset, endOffset);
is(startOffset.value, aStartOffset,
"setSelectionBounds: Wrong start offset for " + aID);
is(endOffset.value, aEndOffset,
"setSelectionBounds: Wrong end offset for " + aID);
is(startOffset.value, aTests[i][1],
"setSelectionBounds: Wrong start offset for " + aID);
is(endOffset.value, aTests[i][2],
"setSelectionBounds: Wrong end offset for " + aID);
}
}
this.getID = function changeDOMSelection_getID()
@ -179,7 +182,10 @@
gQueue.push(new synthFocus("textarea", onfocusEventSeq("textarea")));
gQueue.push(new changeSelection("textarea", 1, 3));
gQueue.push(new changeDOMSelection("c1", "c1_span1", 0, "c1_span2", 0, 2, 2));
gQueue.push(new changeDOMSelection("c1", "c1_span1", 0, "c1_span2", 0,
[["c1", 2, 2]]));
gQueue.push(new changeDOMSelection("c2", "c2", 0, "c2_div2", 1,
[["c2", 0, 3], ["c2_div2", 0, 2]]));
gQueue.invoke(); // Will call SimpleTest.finish();
}
@ -209,6 +215,7 @@
<input id="textbox" value="hello"/>
<textarea id="textarea">hello</textarea>
<div id="c1">hi<span id="c1_span1"></span><span id="c1_span2"></span>hi</div>
<div id="c2">hi<div id="c2_div2">hi</div></div>
</body>
</html>

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

@ -25,6 +25,7 @@
#ifdef XP_WIN
// we want a wmain entry point
#define XRE_DONT_SUPPORT_XPSP2 // See https://bugzil.la/1023941#c32
#include "nsWindowsWMain.cpp"
#define snprintf _snprintf
#define strcasecmp _stricmp

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

@ -30,6 +30,11 @@ LOCAL_INCLUDES += [
'/xpcom/build',
]
DELAYLOAD_DLLS += [
'mozglue.dll',
]
USE_STATIC_LIBS = True
if CONFIG['_MSC_VER']:
# Always enter a Windows program through wmain, whether or not we're
# a console application.
@ -50,9 +55,15 @@ if CONFIG['OS_ARCH'] == 'WINNT':
if CONFIG['OS_ARCH'] == 'WINNT' and not CONFIG['GNU_CC']:
LDFLAGS += ['/HEAP:0x40000']
USE_LIBS += [
'xpcomglue',
]
if CONFIG['OS_ARCH'] == 'WINNT':
USE_LIBS += [
'mozglue',
'xpcomglue_staticruntime',
]
else:
USE_LIBS += [
'xpcomglue',
]
DISABLE_STL_WRAPPING = True

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

@ -249,15 +249,37 @@ var tests = {
SocialService.registerProviderListener(function providerListener(topic, origin, providers) {
if (topic != "provider-update")
return;
is(origin, addonManifest.origin, "provider updated")
// The worker will have reloaded and the current provider instance
// disabled, removed from the provider list. We have a reference
// here, check it is is disabled.
is(provider.enabled, false, "old provider instance is disabled")
is(origin, addonManifest.origin, "provider manifest updated")
SocialService.unregisterProviderListener(providerListener);
Services.prefs.clearUserPref("social.whitelist");
let provider = Social._getProviderFromOrigin(origin);
is(provider.manifest.version, 2, "manifest version is 2");
Social.uninstallProvider(origin, function() {
gBrowser.removeTab(tab);
next();
});
// Get the new provider instance, fetch the manifest via workerapi
// and validate that data as well.
let p = Social._getProviderFromOrigin(origin);
is(p.manifest.version, 2, "manifest version is 2");
let port = p.getWorkerPort();
ok(port, "got a new port");
port.onmessage = function (e) {
let topic = e.data.topic;
switch (topic) {
case "social.manifest":
let manifest = e.data.data;
is(manifest.version, 2, "manifest version is 2");
port.close();
Social.uninstallProvider(origin, function() {
Services.prefs.clearUserPref("social.whitelist");
gBrowser.removeTab(tab);
next();
});
break;
}
}
port.postMessage({topic: "test-init"});
port.postMessage({topic: "manifest-get"});
});
let port = provider.getWorkerPort();

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

@ -2,7 +2,7 @@
* 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 testPort, sidebarPort, apiPort;
let testPort, sidebarPort, apiPort, updatingManifest=false;
onconnect = function(e) {
let port = e.ports[0];
@ -116,12 +116,21 @@ onconnect = function(e) {
if (testPort)
testPort.postMessage({topic:"got-share-data-message", result: event.data.result});
break;
case "manifest-get":
apiPort.postMessage({topic: 'social.manifest-get'});
break;
case "worker.update":
updatingManifest = true;
apiPort.postMessage({topic: 'social.manifest-get'});
break;
case "social.manifest":
event.data.data.version = 2;
apiPort.postMessage({topic: 'social.manifest-set', data: event.data.data});
if (updatingManifest) {
updatingManifest = false;
event.data.data.version = 2;
apiPort.postMessage({topic: 'social.manifest-set', data: event.data.data});
} else if (testPort) {
testPort.postMessage({topic:"social.manifest", data: event.data.data});
}
break;
}
}

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

@ -1668,6 +1668,12 @@
</xul:hbox>
</xul:vbox>
</xul:vbox>
<xul:vbox pack="start">
<xul:toolbarbutton anonid="closebutton"
class="messageCloseButton popup-notification-closebutton tabbable close-icon"
xbl:inherits="oncommand=closebuttoncommand"
tooltiptext="&closeNotification.tooltip;"/>
</xul:vbox>
</xul:hbox>
</content>
<resources>

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

@ -1171,6 +1171,7 @@ SourceScripts.prototype = {
// both in the editor and the breakpoints pane.
DebuggerController.Breakpoints.updatePaneBreakpoints();
DebuggerController.Breakpoints.updateEditorBreakpoints();
DebuggerController.HitCounts.updateEditorHitCounts();
// Make sure the events listeners are up to date.
if (DebuggerView.instrumentsPaneTab == "events-tab") {
@ -1223,6 +1224,7 @@ SourceScripts.prototype = {
// both in the editor and the breakpoints pane.
DebuggerController.Breakpoints.updatePaneBreakpoints();
DebuggerController.Breakpoints.updateEditorBreakpoints();
DebuggerController.HitCounts.updateEditorHitCounts();
// Signal that sources have been added.
window.emit(EVENTS.SOURCES_ADDED);
@ -1488,6 +1490,7 @@ Tracer.prototype = {
let fields = [
"name",
"location",
"hitCount",
"parameterNames",
"depth",
"arguments",
@ -1521,6 +1524,7 @@ Tracer.prototype = {
}
this._trace = null;
DebuggerController.HitCounts.clear();
aCallback(aResponse);
});
},
@ -1529,6 +1533,15 @@ Tracer.prototype = {
const tracesLength = traces.length;
let tracesToShow;
// Update hit counts.
for (let t of traces) {
if (t.type == "enteredFrame") {
DebuggerController.HitCounts.set(t.location, t.hitCount);
}
}
DebuggerController.HitCounts.updateEditorHitCounts();
// Limit number of traces to be shown in the log.
if (tracesLength > TracerView.MAX_TRACES) {
tracesToShow = traces.slice(tracesLength - TracerView.MAX_TRACES, tracesLength);
this._stack.splice(0, this._stack.length);
@ -1537,6 +1550,7 @@ Tracer.prototype = {
tracesToShow = traces;
}
// Show traces in the log.
for (let t of tracesToShow) {
if (t.type == "enteredFrame") {
this._onCall(t);
@ -1544,7 +1558,6 @@ Tracer.prototype = {
this._onReturn(t);
}
}
DebuggerView.Tracer.commit();
},
@ -2224,6 +2237,84 @@ Object.defineProperty(Breakpoints.prototype, "_addedOrDisabled", {
}
});
/**
* Handles Tracer's hit counts.
*/
function HitCounts() {
/**
* Storage of hit counts for every location
* hitCount = _locations[url][line][column]
*/
this._hitCounts = Object.create(null);
}
HitCounts.prototype = {
set: function({url, line, column}, aHitCount) {
if (!this._hitCounts[url]) {
this._hitCounts[url] = Object.create(null);
}
if (!this._hitCounts[url][line]) {
this._hitCounts[url][line] = Object.create(null);
}
this._hitCounts[url][line][column] = aHitCount;
},
/**
* Update all the hit counts in the editor view. This is invoked when the
* selected script is changed, or when new sources are received via the
* _onNewSource and _onSourcesAdded event listeners.
*/
updateEditorHitCounts: function() {
// First, remove all hit counters.
DebuggerView.editor.removeAllMarkers("hit-counts");
// Then, add new hit counts, just for the current source.
for (let url in this._hitCounts) {
for (let line in this._hitCounts[url]) {
for (let column in this._hitCounts[url][line]) {
this._updateEditorHitCount({url, line, column});
}
}
}
},
/**
* Update a hit counter on a certain line.
*/
_updateEditorHitCount: function({url, line, column}) {
// Editor must be initialized.
if (!DebuggerView.editor) {
return;
}
// No need to do anything if the counter's source is not being shown in the
// editor.
if (DebuggerView.Sources.selectedValue != url) {
return;
}
// There might be more counters on the same line. We need to combine them
// into one.
let content = Object.keys(this._hitCounts[url][line])
.sort() // Sort by key (column).
.map(a => this._hitCounts[url][line][a]) // Extract values.
.map(a => a + "\u00D7") // Format hit count (e.g. 146×).
.join("|");
// CodeMirror's lines are indexed from 0, while traces start from 1
DebuggerView.editor.addContentMarker(line - 1, "hit-counts", "hit-count",
content);
},
/**
* Remove all hit couters and clear the storage
*/
clear: function() {
DebuggerView.editor.removeAllMarkers("hit-counts");
this._hitCounts = Object.create(null);
}
}
/**
* Localization convenience methods.
*/
@ -2265,6 +2356,7 @@ DebuggerController.SourceScripts = new SourceScripts();
DebuggerController.Breakpoints = new Breakpoints();
DebuggerController.Breakpoints.DOM = new EventListeners();
DebuggerController.Tracer = new Tracer();
DebuggerController.HitCounts = new HitCounts();
/**
* Export some properties to the global scope for easier access.

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

@ -221,12 +221,17 @@ let DebuggerView = {
extraKeys[shortcut] = () => DebuggerView.Filtering[func]();
}
let gutters = ["breakpoints"];
if (Services.prefs.getBoolPref("devtools.debugger.tracer")) {
gutters.unshift("hit-counts");
}
this.editor = new Editor({
mode: Editor.modes.text,
readOnly: true,
lineNumbers: true,
showAnnotationRuler: true,
gutters: [ "breakpoints" ],
gutters: gutters,
extraKeys: extraKeys,
contextMenu: "sourceEditorContextMenu"
});
@ -410,6 +415,7 @@ let DebuggerView = {
// Synchronize any other components with the currently displayed source.
DebuggerView.Sources.selectedValue = aSource.url;
DebuggerController.Breakpoints.updateEditorBreakpoints();
DebuggerController.HitCounts.updateEditorHitCounts();
histogram.add(Date.now() - startTime);

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

@ -23,6 +23,7 @@ support-files =
code_math.map
code_math.min.js
code_math_bogus_map.js
code_same-line-functions.js
code_script-switching-01.js
code_script-switching-02.js
code_test-editor-mode
@ -74,6 +75,7 @@ support-files =
doc_pretty-print-on-paused.html
doc_random-javascript.html
doc_recursion-stack.html
doc_same-line-functions.html
doc_scope-variable.html
doc_scope-variable-2.html
doc_scope-variable-3.html
@ -161,6 +163,8 @@ skip-if = true # Bug 933950 (leaky test)
[browser_dbg_function-display-name.js]
[browser_dbg_global-method-override.js]
[browser_dbg_globalactor.js]
[browser_dbg_hit-counts-01.js]
[browser_dbg_hit-counts-02.js]
[browser_dbg_host-layout.js]
[browser_dbg_iframes.js]
[browser_dbg_instruments-pane-collapse.js]

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

@ -0,0 +1,65 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* Evaluating two functions on the same line and checking for correct hit count
* for both of them in CodeMirror's gutter.
*/
const TAB_URL = EXAMPLE_URL + "doc_same-line-functions.html";
const CODE_URL = "code_same-line-functions.js";
let gTab, gDebuggee, gPanel, gDebugger;
let gEditor;
function test() {
Task.async(function* () {
yield pushPrefs(["devtools.debugger.tracer", true]);
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gEditor = gDebugger.DebuggerView.editor;
Task.async(function* () {
yield waitForSourceShown(gPanel, CODE_URL);
yield startTracing(gPanel);
clickButton();
yield waitForClientEvents(aPanel, "traces");
testHitCounts();
yield stopTracing(gPanel);
yield popPrefs();
yield closeDebuggerAndFinish(gPanel);
})();
});
})().catch(e => {
ok(false, "Got an error: " + e.message + "\n" + e.stack);
});
}
function clickButton() {
EventUtils.sendMouseEvent({ type: "click" },
gDebuggee.document.querySelector("button"),
gDebuggee);
}
function testHitCounts() {
let marker = gEditor.getMarker(0, 'hit-counts');
is(marker.innerHTML, "1\u00D7|1\u00D7",
"Both functions should be hit only once.");
}
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gEditor = null;
});

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

@ -0,0 +1,70 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
/**
* When tracing is stopped all hit counters should be cleared.
*/
const TAB_URL = EXAMPLE_URL + "doc_same-line-functions.html";
const CODE_URL = "code_same-line-functions.js";
let gTab, gDebuggee, gPanel, gDebugger;
let gEditor;
function test() {
Task.async(function* () {
yield pushPrefs(["devtools.debugger.tracer", true]);
initDebugger(TAB_URL).then(([aTab, aDebuggee, aPanel]) => {
gTab = aTab;
gDebuggee = aDebuggee;
gPanel = aPanel;
gDebugger = gPanel.panelWin;
gEditor = gDebugger.DebuggerView.editor;
Task.async(function* () {
yield waitForSourceShown(gPanel, CODE_URL);
yield startTracing(gPanel);
clickButton();
yield waitForClientEvents(aPanel, "traces");
testHitCountsBeforeStopping();
yield stopTracing(gPanel);
testHitCountsAfterStopping();
yield popPrefs();
yield closeDebuggerAndFinish(gPanel);
})();
});
})().catch(e => {
ok(false, "Got an error: " + e.message + "\n" + e.stack);
});
}
function clickButton() {
EventUtils.sendMouseEvent({ type: "click" },
gDebuggee.document.querySelector("button"),
gDebuggee);
}
function testHitCountsBeforeStopping() {
let marker = gEditor.getMarker(0, 'hit-counts');
ok(marker, "A counter should exists.");
}
function testHitCountsAfterStopping() {
let marker = gEditor.getMarker(0, 'hit-counts');
is(marker, undefined, "A counter should be cleared.");
}
registerCleanupFunction(function() {
gTab = null;
gDebuggee = null;
gPanel = null;
gDebugger = null;
gEditor = null;
});

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

@ -0,0 +1 @@
function first() { var a = "first"; second(); function second() { var a = "second"; } }

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

@ -0,0 +1,15 @@
<!-- Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ -->
<!doctype html>
<html>
<head>
<meta charset="utf-8"/>
<title>Debugger Tracer test page</title>
</head>
<body>
<script src="code_same-line-functions.js"></script>
<button onclick="first()">Click me!</button>
</body>
</html>

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

@ -926,3 +926,14 @@ function doInterrupt(aPanel) {
return rdpInvoke(threadClient, threadClient.interrupt);
}
function pushPrefs(...aPrefs) {
let deferred = promise.defer();
SpecialPowers.pushPrefEnv({"set": aPrefs}, deferred.resolve);
return deferred.promise;
}
function popPrefs() {
let deferred = promise.defer();
SpecialPowers.popPrefEnv(deferred.resolve);
return deferred.promise;
}

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

@ -36,6 +36,7 @@ function test() {
emptyText: "This is dummy empty text",
highlightUpdated: true,
removableColumns: true,
firstColumn: "col4"
});
startTests();
});
@ -126,12 +127,42 @@ function populateTable() {
function testTreeItemInsertedCorrectly() {
is(table.tbody.children.length, 4*2 /* double because splitters */,
"4 columns exist");
for (let i = 0; i < 4; i++) {
is(table.tbody.children[i*2].firstChild.children.length, 9 + 1 /* header */,
// Test firstColumn option and check if the nodes are inserted correctly
is(table.tbody.children[0].firstChild.children.length, 9 + 1 /* header */,
"Correct rows in column 4");
is(table.tbody.children[0].firstChild.firstChild.value, "Column 4",
"Correct column header value");
for (let i = 1; i < 4; i++) {
is(table.tbody.children[i * 2].firstChild.children.length, 9 + 1 /* header */,
"Correct rows in column " + i);
is(table.tbody.children[i*2].firstChild.firstChild.value, "Column " + (i + 1),
is(table.tbody.children[i * 2].firstChild.firstChild.value, "Column " + i,
"Correct column header value");
}
for (let i = 1; i < 10; i++) {
is(table.tbody.children[2].firstChild.children[i].value, "id" + i,
"Correct value in row " + i);
}
// Remove firstColumn option and reset the table
table.clear();
table.firstColumn = "";
table.setColumns({
col1: "Column 1",
col2: "Column 2",
col3: "Column 3",
col4: "Column 4"
});
populateTable();
// Check if the nodes are inserted correctly without firstColumn option
for (let i = 0; i < 4; i++) {
is(table.tbody.children[i * 2].firstChild.children.length, 9 + 1 /* header */,
"Correct rows in column " + i);
is(table.tbody.children[i * 2].firstChild.firstChild.value, "Column " + (i + 1),
"Correct column header value");
}
for (let i = 1; i < 10; i++) {
is(table.tbody.firstChild.firstChild.children[i].value, "id" + i,
"Correct value in row " + i);

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

@ -40,6 +40,7 @@ const MAX_VISIBLE_STRING_SIZE = 100;
* - highlightUpdated: true to highlight the changed/added row.
* - removableColumns: Whether columns are removeable. If set to true,
* the context menu in the headers will not appear.
* - firstColumn: key of the first column that should appear.
*/
function TableWidget(node, options={}) {
EventEmitter.decorate(this);
@ -48,10 +49,11 @@ function TableWidget(node, options={}) {
this.window = this.document.defaultView;
this._parent = node;
let {initialColumns, emptyText, uniqueId, highlightUpdated, removableColumns} =
options;
let {initialColumns, emptyText, uniqueId, highlightUpdated, removableColumns,
firstColumn} = options;
this.emptyText = emptyText || "";
this.uniqueId = uniqueId || "name";
this.firstColumn = firstColumn || "";
this.highlightUpdated = highlightUpdated || false;
this.removableColumns = removableColumns || false;
@ -237,10 +239,24 @@ TableWidget.prototype = {
sortOn = null;
}
if (!(this.firstColumn in columns)) {
this.firstColumn = null;
}
if (this.firstColumn) {
this.columns.set(this.firstColumn,
new Column(this, this.firstColumn, columns[this.firstColumn]));
}
for (let id in columns) {
if (!sortOn) {
sortOn = id;
}
if (this.firstColumn && id == this.firstColumn) {
continue;
}
this.columns.set(id, new Column(this, id, columns[id]));
if (hiddenColumns.indexOf(id) > -1) {
this.columns.get(id).toggleColumn();

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

@ -7,6 +7,10 @@
width: 16px;
}
.hit-counts {
width: 6px;
}
.error, .breakpoint, .debugLocation, .breakpoint-debugLocation {
display: inline-block;
margin-left: 5px;
@ -17,6 +21,17 @@
background-size: contain;
}
.hit-count {
display: inline-block;
height: 12px;
border: solid rgba(0,0,0,0.2);
border-width: 1px 1px 1px 0;
border-radius: 0 3px 3px 0;
padding: 0 3px;
font-size: 10px;
pointer-events: none;
}
.error {
background-image: url("chrome://browser/skin/devtools/editor-error.png");
opacity: 0.75;

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

@ -115,6 +115,7 @@ function hasBreakpoint(ctx, line) {
let markers = cm.lineInfo(line).gutterMarkers;
return markers != null &&
markers.breakpoints &&
markers.breakpoints.classList.contains("breakpoint");
}

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

@ -618,6 +618,32 @@ Editor.prototype = {
cm.lineInfo(line).gutterMarkers[gutterName].classList.remove(markerClass);
},
/**
* Adds a marker with a specified class and an HTML content to a line's
* gutter. If another marker exists on that line, it is overwritten by a new
* marker.
*/
addContentMarker: function (line, gutterName, markerClass, content) {
let cm = editors.get(this);
let info = cm.lineInfo(line);
if (!info)
return;
let marker = cm.getWrapperElement().ownerDocument.createElement("div");
marker.className = markerClass;
marker.innerHTML = content;
cm.setGutterMarker(info.line, gutterName, marker);
},
/**
* The reverse of addContentMarker. Removes any line's markers in the
* specified gutter.
*/
removeContentMarker: function (line, gutterName) {
let cm = editors.get(this);
cm.setGutterMarker(info.line, gutterName, null);
},
getMarker: function(line, gutterName) {
let cm = editors.get(this);
let info = cm.lineInfo(line);

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

@ -10,8 +10,12 @@ const {Cc, Ci, Cu} = require("chrome");
loader.lazyImporter(this, "VariablesView", "resource:///modules/devtools/VariablesView.jsm");
loader.lazyImporter(this, "escapeHTML", "resource:///modules/devtools/VariablesView.jsm");
loader.lazyImporter(this, "gDevTools", "resource:///modules/devtools/gDevTools.jsm");
loader.lazyImporter(this, "Task","resource://gre/modules/Task.jsm");
loader.lazyImporter(this, "Task", "resource://gre/modules/Task.jsm");
loader.lazyImporter(this, "PluralForm", "resource://gre/modules/PluralForm.jsm");
loader.lazyImporter(this, "ObjectClient", "resource://gre/modules/devtools/dbg-client.jsm");
loader.lazyRequireGetter(this, "promise");
loader.lazyRequireGetter(this, "TableWidget", "devtools/shared/widgets/TableWidget", true);
const Heritage = require("sdk/core/heritage");
const URI = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
@ -81,6 +85,7 @@ const CONSOLE_API_LEVELS_TO_SEVERITIES = {
info: "info",
log: "log",
trace: "log",
table: "log",
debug: "log",
dir: "log",
group: "log",
@ -111,6 +116,12 @@ const RE_CLEANUP_STYLES = [
/['"(]*(?:chrome|resource|about|app|data|https?|ftp|file):+\/*/gi,
];
// Maximum number of rows to display in console.table().
const TABLE_ROW_MAX_ITEMS = 1000;
// Maximum number of columns to display in console.table().
const TABLE_COLUMN_MAX_ITEMS = 10;
/**
* The ConsoleOutput object is used to manage output of messages in the Web
* Console.
@ -1616,6 +1627,344 @@ Messages.ConsoleTrace.prototype = Heritage.extend(Messages.Simple.prototype,
_renderRepeatNode: function() { },
}); // Messages.ConsoleTrace.prototype
/**
* The ConsoleTable message is used for console.table() calls.
*
* @constructor
* @extends Messages.Extended
* @param object packet
* The Console API call packet received from the server.
*/
Messages.ConsoleTable = function(packet)
{
let options = {
className: "cm-s-mozilla",
timestamp: packet.timeStamp,
category: "webdev",
severity: CONSOLE_API_LEVELS_TO_SEVERITIES[packet.level],
private: packet.private,
filterDuplicates: false,
location: {
url: packet.filename,
line: packet.lineNumber,
},
};
this._populateTableData = this._populateTableData.bind(this);
this._renderTable = this._renderTable.bind(this);
Messages.Extended.call(this, [this._renderTable], options);
this._repeatID.consoleApiLevel = packet.level;
this._arguments = packet.arguments;
};
Messages.ConsoleTable.prototype = Heritage.extend(Messages.Extended.prototype,
{
/**
* Holds the arguments the content script passed to the console.table()
* method.
*
* @private
* @type array
*/
_arguments: null,
/**
* Array of objects that holds the data to log in the table.
*
* @private
* @type array
*/
_data: null,
/**
* Key value pair of the id and display name for the columns in the table.
* Refer to the TableWidget API.
*
* @private
* @type object
*/
_columns: null,
/**
* A promise that resolves when the table data is ready or null if invalid
* arguments are provided.
*
* @private
* @type promise|null
*/
_populatePromise: null,
init: function()
{
let result = Messages.Extended.prototype.init.apply(this, arguments);
this._data = [];
this._columns = {};
this._populatePromise = this._populateTableData();
return result;
},
/**
* Sets the key value pair of the id and display name for the columns in the
* table.
*
* @private
* @param array|string columns
* Either a string or array containing the names for the columns in
* the output table.
*/
_setColumns: function(columns)
{
if (columns.class == "Array") {
let items = columns.preview.items;
for (let item of items) {
if (typeof item == "string") {
this._columns[item] = item;
}
}
} else if (typeof columns == "string" && columns) {
this._columns[columns] = columns;
}
},
/**
* Retrieves the table data and columns from the arguments received from the
* server.
*
* @return Promise|null
* Returns a promise that resolves when the table data is ready or
* null if the arguments are invalid.
*/
_populateTableData: function()
{
let deferred = promise.defer();
if (this._arguments.length <= 0) {
return;
}
let data = this._arguments[0];
if (data.class != "Array" && data.class != "Object" &&
data.class != "Map" && data.class != "Set") {
return;
}
let hasColumnsArg = false;
if (this._arguments.length > 1) {
if (data.class == "Object" || data.class == "Array") {
this._columns["_index"] = l10n.getStr("table.index");
} else {
this._columns["_index"] = l10n.getStr("table.iterationIndex");
}
this._setColumns(this._arguments[1]);
hasColumnsArg = true;
}
if (data.class == "Object" || data.class == "Array") {
// Get the object properties, and parse the key and value properties into
// the table data and columns.
this.client = new ObjectClient(this.output.owner.jsterm.hud.proxy.client,
data);
this.client.getPrototypeAndProperties(aResponse => {
let {ownProperties} = aResponse;
let rowCount = 0;
let columnCount = 0;
for (let index of Object.keys(ownProperties || {})) {
// Avoid outputting the length property if the data argument provided
// is an array
if (data.class == "Array" && index == "length") {
continue;
}
if (!hasColumnsArg) {
this._columns["_index"] = l10n.getStr("table.index");
}
let property = ownProperties[index].value;
let item = { _index: index };
if (property.class == "Object" || property.class == "Array") {
let {preview} = property;
let entries = property.class == "Object" ?
preview.ownProperties : preview.items;
for (let key of Object.keys(entries)) {
let value = property.class == "Object" ?
preview.ownProperties[key].value : preview.items[key];
item[key] = this._renderValueGrip(value, { concise: true });
if (!hasColumnsArg && !(key in this._columns) &&
(++columnCount <= TABLE_COLUMN_MAX_ITEMS)) {
this._columns[key] = key;
}
}
} else {
// Display the value for any non-object data input.
item["_value"] = this._renderValueGrip(property, { concise: true });
if (!hasColumnsArg && !("_value" in this._columns)) {
this._columns["_value"] = l10n.getStr("table.value");
}
}
this._data.push(item);
if (++rowCount == TABLE_ROW_MAX_ITEMS) {
break;
}
}
deferred.resolve();
});
} else if (data.class == "Map") {
let entries = data.preview.entries;
if (!hasColumnsArg) {
this._columns["_index"] = l10n.getStr("table.iterationIndex");
this._columns["_key"] = l10n.getStr("table.key");
this._columns["_value"] = l10n.getStr("table.value");
}
let rowCount = 0;
for (let index of Object.keys(entries || {})) {
let [key, value] = entries[index];
let item = {
_index: index,
_key: this._renderValueGrip(key, { concise: true }),
_value: this._renderValueGrip(value, { concise: true })
};
this._data.push(item);
if (++rowCount == TABLE_ROW_MAX_ITEMS) {
break;
}
}
deferred.resolve();
} else if (data.class == "Set") {
let entries = data.preview.items;
if (!hasColumnsArg) {
this._columns["_index"] = l10n.getStr("table.iterationIndex");
this._columns["_value"] = l10n.getStr("table.value");
}
let rowCount = 0;
for (let index of Object.keys(entries || {})) {
let value = entries[index];
let item = {
_index : index,
_value: this._renderValueGrip(value, { concise: true })
};
this._data.push(item);
if (++rowCount == TABLE_ROW_MAX_ITEMS) {
break;
}
}
deferred.resolve();
}
return deferred.promise;
},
render: function()
{
Messages.Extended.prototype.render.apply(this, arguments);
this.element.setAttribute("open", true);
return this;
},
/**
* Render the table.
*
* @private
* @return DOMElement
*/
_renderTable: function()
{
let cmvar = this.document.createElementNS(XHTML_NS, "span");
cmvar.className = "cm-variable";
cmvar.textContent = "console";
let cmprop = this.document.createElementNS(XHTML_NS, "span");
cmprop.className = "cm-property";
cmprop.textContent = "table";
let title = this.document.createElementNS(XHTML_NS, "span");
title.className = "message-body devtools-monospace";
title.appendChild(cmvar);
title.appendChild(this.document.createTextNode("."));
title.appendChild(cmprop);
title.appendChild(this.document.createTextNode("():"));
let repeatNode = Messages.Simple.prototype._renderRepeatNode.call(this);
let location = Messages.Simple.prototype._renderLocation.call(this);
if (location) {
location.target = "jsdebugger";
}
let body = this.document.createElementNS(XHTML_NS, "span");
body.className = "message-flex-body";
body.appendChild(title);
if (repeatNode) {
body.appendChild(repeatNode);
}
if (location) {
body.appendChild(location);
}
body.appendChild(this.document.createTextNode("\n"));
let result = this.document.createElementNS(XHTML_NS, "div");
result.appendChild(body);
if (this._populatePromise) {
this._populatePromise.then(() => {
if (this._data.length > 0) {
let widget = new Widgets.Table(this, this._data, this._columns).render();
result.appendChild(widget.element);
}
result.scrollIntoView();
this.output.owner.emit("messages-table-rendered");
// Release object actors
if (Array.isArray(this._arguments)) {
for (let arg of this._arguments) {
if (WebConsoleUtils.isActorGrip(arg)) {
this.output._releaseObject(arg.actor);
}
}
}
this._arguments = null;
});
}
return result;
},
_renderBody: function()
{
let body = Messages.Simple.prototype._renderBody.apply(this, arguments);
body.classList.remove("devtools-monospace", "message-body");
return body;
},
// no-op for the message location and .repeats elements.
// |this._renderTable| handles customized message output.
_renderLocation: function() { },
_renderRepeatNode: function() { },
}); // Messages.ConsoleTable.prototype
let Widgets = {};
/**
@ -3012,6 +3361,63 @@ Widgets.Stacktrace.prototype = Heritage.extend(Widgets.BaseWidget.prototype,
}); // Widgets.Stacktrace.prototype
/**
* The table widget.
*
* @constructor
* @extends Widgets.BaseWidget
* @param object message
* The owning message.
* @param array data
* Array of objects that holds the data to log in the table.
* @param object columns
* Object containing the key value pair of the id and display name for
* the columns in the table.
*/
Widgets.Table = function(message, data, columns)
{
Widgets.BaseWidget.call(this, message);
this.data = data;
this.columns = columns;
};
Widgets.Table.prototype = Heritage.extend(Widgets.BaseWidget.prototype,
{
/**
* Array of objects that holds the data to output in the table.
* @type array
*/
data: null,
/**
* Object containing the key value pair of the id and display name for
* the columns in the table.
* @type object
*/
columns: null,
render: function() {
if (this.element) {
return this;
}
let result = this.element = this.document.createElementNS(XHTML_NS, "div");
result.className = "consoletable devtools-monospace";
this.table = new TableWidget(result, {
initialColumns: this.columns,
uniqueId: "_index",
firstColumn: "_index"
});
for (let row of this.data) {
this.table.push(row);
}
return this;
}
}); // Widgets.Table.prototype
function gSequenceId()
{
return gSequenceId.n++;

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

@ -67,6 +67,7 @@ support-files =
test-console-extras.html
test-console-replaced-api.html
test-console.html
test-console-table.html
test-console-output-02.html
test-console-output-03.html
test-console-output-04.html
@ -305,6 +306,7 @@ skip-if = buildapp == 'mulet'
[browser_webconsole_output_dom_elements_03.js]
[browser_webconsole_output_dom_elements_04.js]
[browser_webconsole_output_events.js]
[browser_webconsole_output_table.js]
[browser_console_variables_view_highlighter.js]
[browser_webconsole_start_netmon_first.js]
[browser_webconsole_console_trace_duplicates.js]

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

@ -0,0 +1,158 @@
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
// Tests that console.table() works as intended.
"use strict";
const TEST_URI = "http://example.com/browser/browser/devtools/webconsole/test/test-console-table.html";
const TEST_DATA = [
{
command: "console.table(languages1)",
data: [
{ _index: "0", name: "\"JavaScript\"", fileExtension: "Array[1]" },
{ _index: "1", name: "Object", fileExtension: "\".ts\"" },
{ _index: "2", name: "\"CoffeeScript\"", fileExtension: "\".coffee\"" }
],
columns: { _index: "(index)", name: "name", fileExtension: "fileExtension" }
},
{
command: "console.table(languages1, 'name')",
data: [
{ _index: "0", name: "\"JavaScript\"", fileExtension: "Array[1]" },
{ _index: "1", name: "Object", fileExtension: "\".ts\"" },
{ _index: "2", name: "\"CoffeeScript\"", fileExtension: "\".coffee\"" }
],
columns: { _index: "(index)", name: "name" }
},
{
command: "console.table(languages1, ['name'])",
data: [
{ _index: "0", name: "\"JavaScript\"", fileExtension: "Array[1]" },
{ _index: "1", name: "Object", fileExtension: "\".ts\"" },
{ _index: "2", name: "\"CoffeeScript\"", fileExtension: "\".coffee\"" }
],
columns: { _index: "(index)", name: "name" }
},
{
command: "console.table(languages2)",
data: [
{ _index: "csharp", name: "\"C#\"", paradigm: "\"object-oriented\"" },
{ _index: "fsharp", name: "\"F#\"", paradigm: "\"functional\"" }
],
columns: { _index: "(index)", name: "name", paradigm: "paradigm" }
},
{
command: "console.table([[1, 2], [3, 4]])",
data: [
{ _index: "0", 0: "1", 1: "2" },
{ _index: "1", 0: "3", 1: "4" }
],
columns: { _index: "(index)", 0: "0", 1: "1" }
},
{
command: "console.table({a: [1, 2], b: [3, 4]})",
data: [
{ _index: "a", 0: "1", 1: "2" },
{ _index: "b", 0: "3", 1: "4" }
],
columns: { _index: "(index)", 0: "0", 1: "1" }
},
{
command: "console.table(family)",
data: [
{ _index: "mother", firstName: "\"Susan\"", lastName: "\"Doyle\"", age: "32" },
{ _index: "father", firstName: "\"John\"", lastName: "\"Doyle\"", age: "33" },
{ _index: "daughter", firstName: "\"Lily\"", lastName: "\"Doyle\"", age: "5" },
{ _index: "son", firstName: "\"Mike\"", lastName: "\"Doyle\"", age: "8" },
],
columns: { _index: "(index)", firstName: "firstName", lastName: "lastName", age: "age" }
},
{
command: "console.table(family, [])",
data: [
{ _index: "mother", firstName: "\"Susan\"", lastName: "\"Doyle\"", age: "32" },
{ _index: "father", firstName: "\"John\"", lastName: "\"Doyle\"", age: "33" },
{ _index: "daughter", firstName: "\"Lily\"", lastName: "\"Doyle\"", age: "5" },
{ _index: "son", firstName: "\"Mike\"", lastName: "\"Doyle\"", age: "8" },
],
columns: { _index: "(index)" }
},
{
command: "console.table(family, ['firstName', 'lastName'])",
data: [
{ _index: "mother", firstName: "\"Susan\"", lastName: "\"Doyle\"", age: "32" },
{ _index: "father", firstName: "\"John\"", lastName: "\"Doyle\"", age: "33" },
{ _index: "daughter", firstName: "\"Lily\"", lastName: "\"Doyle\"", age: "5" },
{ _index: "son", firstName: "\"Mike\"", lastName: "\"Doyle\"", age: "8" },
],
columns: { _index: "(index)", firstName: "firstName", lastName: "lastName" }
},
{
command: "console.table(mySet)",
data: [
{ _index: "0", _value: "1" },
{ _index: "1", _value: "5" },
{ _index: "2", _value: "\"some text\"" },
{ _index: "3", _value: "null" },
{ _index: "4", _value: "undefined" }
],
columns: { _index: "(iteration index)", _value: "Values" }
},
{
command: "console.table(myMap)",
data: [
{ _index: "0", _key: "\"a string\"", _value: "\"value associated with 'a string'\"" },
{ _index: "1", _key: "5", _value: "\"value associated with 5\"" },
],
columns: { _index: "(iteration index)", _key: "Key", _value: "Values" }
}
];
let test = asyncTest(function*() {
const {tab} = yield loadTab(TEST_URI);
let hud = yield openConsole(tab);
for (let testdata of TEST_DATA) {
hud.jsterm.clearOutput();
info("Executing " + testdata.command);
let onTableRender = once(hud.ui, "messages-table-rendered");
hud.jsterm.execute(testdata.command);
yield onTableRender;
let [result] = yield waitForMessages({
webconsole: hud,
messages: [{
name: testdata.command + " output",
consoleTable: true
}],
});
let node = [...result.matched][0];
ok(node, "found trace log node");
let obj = node._messageObject;
ok(obj, "console.trace message object");
ok(obj._data, "found table data object");
let data = obj._data.map(entries => {
let result = {};
for (let key of Object.keys(entries)) {
result[key] = entries[key] instanceof HTMLElement ?
entries[key].textContent : entries[key];
}
return result;
});
is(data.toSource(), testdata.data.toSource(), "table data is correct");
ok(obj._columns, "found table column object");
is(obj._columns.toSource(), testdata.columns.toSource(), "table column is correct");
}
});

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

@ -912,6 +912,8 @@ function openDebugger(aOptions = {})
* message.
* - consoleGroup: boolean, set to |true| to match a console.group()
* message.
* - consoleTable: boolean, set to |true| to match a console.table()
* message.
* - longString: boolean, set to |true} to match long strings in the
* message.
* - collapsible: boolean, set to |true| to match messages that can
@ -970,6 +972,22 @@ function waitForMessages(aOptions)
return result;
}
function checkConsoleTable(aRule, aElement)
{
let elemText = aElement.textContent;
let table = aRule.consoleTable;
if (!checkText("console.table():", elemText)) {
return false;
}
aRule.category = CATEGORY_WEBDEV;
aRule.severity = SEVERITY_LOG;
aRule.type = Messages.ConsoleTable;
return true;
}
function checkConsoleTrace(aRule, aElement)
{
let elemText = aElement.textContent;
@ -1146,6 +1164,10 @@ function waitForMessages(aOptions)
return false;
}
if (aRule.consoleTable && !checkConsoleTable(aRule, aElement)) {
return false;
}
if (aRule.consoleTrace && !checkConsoleTrace(aRule, aElement)) {
return false;
}
@ -1593,3 +1615,34 @@ function checkOutputForInputs(hud, inputTests)
return Task.spawn(runner);
}
/**
* Wait for eventName on target.
* @param {Object} target An observable object that either supports on/off or
* addEventListener/removeEventListener
* @param {String} eventName
* @param {Boolean} useCapture Optional, for addEventListener/removeEventListener
* @return A promise that resolves when the event has been handled
*/
function once(target, eventName, useCapture=false) {
info("Waiting for event: '" + eventName + "' on " + target + ".");
let deferred = promise.defer();
for (let [add, remove] of [
["addEventListener", "removeEventListener"],
["addListener", "removeListener"],
["on", "off"]
]) {
if ((add in target) && (remove in target)) {
target[add](eventName, function onEvent(...aArgs) {
target[remove](eventName, onEvent, useCapture);
deferred.resolve.apply(deferred, aArgs);
}, useCapture);
break;
}
}
return deferred.promise;
}

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

@ -7,9 +7,6 @@
console.log("start");
console.clear()
console.dirxml()
console.profile()
console.profileEnd()
console.table()
console.log("end");
}
</script>

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

@ -0,0 +1,52 @@
<!DOCTYPE HTML>
<html dir="ltr" lang="en">
<head>
<meta charset="utf8">
<!--
- Any copyright is dedicated to the Public Domain.
- http://creativecommons.org/publicdomain/zero/1.0/
-->
<title>Test for Bug 899753 - console.table support</title>
<script>
var languages1 = [
{ name: "JavaScript", fileExtension: [".js"] },
{ name: { a: "TypeScript" }, fileExtension: ".ts" },
{ name: "CoffeeScript", fileExtension: ".coffee" }
];
var languages2 = {
csharp: { name: "C#", paradigm: "object-oriented" },
fsharp: { name: "F#", paradigm: "functional" }
};
function Person(firstName, lastName, age)
{
this.firstName = firstName;
this.lastName = lastName;
this.age = age;
}
var family = {};
family.mother = new Person("Susan", "Doyle", 32);
family.father = new Person("John", "Doyle", 33);
family.daughter = new Person("Lily", "Doyle", 5);
family.son = new Person("Mike", "Doyle", 8);
var myMap = new Map();
myMap.set("a string", "value associated with 'a string'");
myMap.set(5, "value associated with 5");
var mySet = new Set();
mySet.add(1);
mySet.add(5);
mySet.add("some text");
mySet.add(null);
mySet.add(undefined);
</script>
</head>
<body>
<p>Hello world!</p>
</body>
</html>

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

@ -123,6 +123,7 @@ const LEVELS = {
info: SEVERITY_INFO,
log: SEVERITY_LOG,
trace: SEVERITY_LOG,
table: SEVERITY_LOG,
debug: SEVERITY_LOG,
dir: SEVERITY_LOG,
group: SEVERITY_LOG,
@ -1212,6 +1213,11 @@ WebConsoleFrame.prototype = {
node = msg.init(this.output).render().element;
break;
}
case "table": {
let msg = new Messages.ConsoleTable(aMessage);
node = msg.init(this.output).render().element;
break;
}
case "trace": {
let msg = new Messages.ConsoleTrace(aMessage);
node = msg.init(this.output).render().element;

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

@ -250,3 +250,10 @@ messageToggleDetails=Show/hide message details.
# example: 1 empty slot
# example: 5 empty slots
emptySlotLabel=#1 empty slot;#1 empty slots
# LOCALIZATION NOTE (table.index, table.iterationIndex, table.key, table.value):
# the column header displayed in the console table widget.
table.index=(index)
table.iterationIndex=(iteration index)
table.key=Key
table.value=Values

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

@ -2664,6 +2664,7 @@ richlistitem[type~="action"][actiontype="switchtab"][selected="true"] > .ac-url-
#sidebar,
sidebarheader {
-moz-appearance: -moz-mac-vibrancy-light;
background-color: #e2e7ed;
}

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

@ -63,6 +63,10 @@ a {
margin: 3px;
}
.message-body-wrapper .table-widget-body {
overflow: visible;
}
/* The red bubble that shows the number of times a message is repeated */
.message-repeats {
-moz-user-select: none;
@ -223,6 +227,13 @@ a {
color: hsl(24,85%,39%);
}
.theme-selected .console-string,
.theme-selected .cm-number,
.theme-selected .cm-variable,
.theme-selected .kind-ArrayLike {
color: #f5f7fa !important; /* Selection Text Color */
}
.message[category=network] > .indent {
-moz-border-end: solid #000 6px;
}
@ -429,6 +440,10 @@ a {
border-radius: 3px;
}
.consoletable {
margin: 5px 0 0 0;
}
.theme-light .message[severity=error] .stacktrace {
background-color: rgba(255, 255, 255, 0.5);
}

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

@ -44,6 +44,20 @@ public:
{
}
ExplicitChildIterator(const ExplicitChildIterator& aOther)
: mParent(aOther.mParent), mChild(aOther.mChild),
mDefaultChild(aOther.mDefaultChild),
mShadowIterator(aOther.mShadowIterator ?
new ExplicitChildIterator(*aOther.mShadowIterator) :
nullptr),
mIndexInInserted(aOther.mIndexInInserted), mIsFirst(aOther.mIsFirst) {}
ExplicitChildIterator(ExplicitChildIterator&& aOther)
: mParent(aOther.mParent), mChild(aOther.mChild),
mDefaultChild(aOther.mDefaultChild),
mShadowIterator(Move(aOther.mShadowIterator)),
mIndexInInserted(aOther.mIndexInInserted), mIsFirst(aOther.mIsFirst) {}
nsIContent* GetNextChild();
// Looks for aChildToFind respecting insertion points until aChildToFind
@ -118,6 +132,12 @@ public:
Init(false);
}
FlattenedChildIterator(FlattenedChildIterator&& aOther)
: ExplicitChildIterator(Move(aOther)), mXBLInvolved(aOther.mXBLInvolved) {}
FlattenedChildIterator(const FlattenedChildIterator& aOther)
: ExplicitChildIterator(aOther), mXBLInvolved(aOther.mXBLInvolved) {}
bool XBLInvolved() { return mXBLInvolved; }
protected:
@ -126,7 +146,7 @@ protected:
* doesn't want to consider XBL.
*/
FlattenedChildIterator(nsIContent* aParent, bool aIgnoreXBL)
: ExplicitChildIterator(aParent), mXBLInvolved(false)
: ExplicitChildIterator(aParent), mXBLInvolved(false)
{
Init(aIgnoreXBL);
}
@ -152,6 +172,16 @@ public:
mOriginalContent(aNode), mFlags(aFlags),
mPhase(eNeedBeforeKid) {}
AllChildrenIterator(AllChildrenIterator&& aOther)
: FlattenedChildIterator(Move(aOther)),
mOriginalContent(aOther.mOriginalContent),
mAnonKids(Move(aOther.mAnonKids)), mFlags(aOther.mFlags),
mPhase(aOther.mPhase)
#ifdef DEBUG
, mMutationGuard(aOther.mMutationGuard)
#endif
{}
#ifdef DEBUG
~AllChildrenIterator() { MOZ_ASSERT(!mMutationGuard.Mutated(0)); }
#endif

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

@ -1,4 +1,5 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=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/. */
@ -50,13 +51,17 @@ RemoveMapRef(nsAttrHashKey::KeyType aKey, nsRefPtr<Attr>& aData,
nsDOMAttributeMap::~nsDOMAttributeMap()
{
mAttributeCache.Enumerate(RemoveMapRef, nullptr);
if (mAttributeCache) {
mAttributeCache->Enumerate(RemoveMapRef, nullptr);
}
}
void
nsDOMAttributeMap::DropReference()
{
mAttributeCache.Enumerate(RemoveMapRef, nullptr);
if (mAttributeCache) {
mAttributeCache->Enumerate(RemoveMapRef, nullptr);
}
mContent = nullptr;
}
@ -82,7 +87,9 @@ TraverseMapEntry(nsAttrHashKey::KeyType aKey, nsRefPtr<Attr>& aData,
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsDOMAttributeMap)
tmp->mAttributeCache.Enumerate(TraverseMapEntry, &cb);
if (tmp->mAttributeCache) {
tmp->mAttributeCache->Enumerate(TraverseMapEntry, &cb);
}
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mContent)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
@ -136,9 +143,10 @@ SetOwnerDocumentFunc(nsAttrHashKey::KeyType aKey,
nsresult
nsDOMAttributeMap::SetOwnerDocument(nsIDocument* aDocument)
{
uint32_t n = mAttributeCache.Enumerate(SetOwnerDocumentFunc, aDocument);
NS_ENSURE_TRUE(n == mAttributeCache.Count(), NS_ERROR_FAILURE);
if (mAttributeCache) {
uint32_t n = mAttributeCache->Enumerate(SetOwnerDocumentFunc, aDocument);
NS_ENSURE_TRUE(n == mAttributeCache->Count(), NS_ERROR_FAILURE);
}
return NS_OK;
}
@ -146,13 +154,15 @@ void
nsDOMAttributeMap::DropAttribute(int32_t aNamespaceID, nsIAtom* aLocalName)
{
nsAttrKey attr(aNamespaceID, aLocalName);
Attr *node = mAttributeCache.GetWeak(attr);
if (node) {
// Break link to map
node->SetMap(nullptr);
if (mAttributeCache) {
Attr *node = mAttributeCache->GetWeak(attr);
if (node) {
// Break link to map
node->SetMap(nullptr);
// Remove from cache
mAttributeCache.Remove(attr);
// Remove from cache
mAttributeCache->Remove(attr);
}
}
}
@ -164,7 +174,13 @@ nsDOMAttributeMap::RemoveAttribute(mozilla::dom::NodeInfo* aNodeInfo)
nsAttrKey attr(aNodeInfo->NamespaceID(), aNodeInfo->NameAtom());
nsRefPtr<Attr> node;
if (!mAttributeCache.Get(attr, getter_AddRefs(node))) {
if (mAttributeCache && mAttributeCache->Get(attr, getter_AddRefs(node))) {
// Break link to map
node->SetMap(nullptr);
// Remove from cache
mAttributeCache->Remove(attr);
} else {
nsAutoString value;
// As we are removing the attribute we need to set the current value in
// the attribute node.
@ -172,13 +188,6 @@ nsDOMAttributeMap::RemoveAttribute(mozilla::dom::NodeInfo* aNodeInfo)
nsRefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
node = new Attr(nullptr, ni.forget(), value, true);
}
else {
// Break link to map
node->SetMap(nullptr);
// Remove from cache
mAttributeCache.Remove(attr);
}
return node.forget();
}
@ -190,12 +199,13 @@ nsDOMAttributeMap::GetAttribute(mozilla::dom::NodeInfo* aNodeInfo, bool aNsAware
nsAttrKey attr(aNodeInfo->NamespaceID(), aNodeInfo->NameAtom());
Attr* node = mAttributeCache.GetWeak(attr);
EnsureAttributeCache();
Attr* node = mAttributeCache->GetWeak(attr);
if (!node) {
nsRefPtr<mozilla::dom::NodeInfo> ni = aNodeInfo;
nsRefPtr<Attr> newAttr =
new Attr(this, ni.forget(), EmptyString(), aNsAware);
mAttributeCache.Put(attr, newAttr);
mAttributeCache->Put(attr, newAttr);
node = newAttr;
}
@ -241,6 +251,14 @@ nsDOMAttributeMap::GetNamedItem(const nsAString& aAttrName,
return NS_OK;
}
void
nsDOMAttributeMap::EnsureAttributeCache()
{
if (!mAttributeCache) {
mAttributeCache = MakeUnique<AttrCache>();
}
}
NS_IMETHODIMP
nsDOMAttributeMap::SetNamedItem(nsIDOMAttr* aAttr, nsIDOMAttr** aReturn)
{
@ -342,7 +360,8 @@ nsDOMAttributeMap::SetNamedItemInternal(Attr& aAttr,
// Add the new attribute to the attribute map before updating
// its value in the element. @see bug 364413.
nsAttrKey attrkey(ni->NamespaceID(), ni->NameAtom());
mAttributeCache.Put(attrkey, &aAttr);
EnsureAttributeCache();
mAttributeCache->Put(attrkey, &aAttr);
aAttr.SetMap(this);
rv = mContent->SetAttr(ni->NamespaceID(), ni->NameAtom(),
@ -528,14 +547,14 @@ nsDOMAttributeMap::RemoveNamedItemNS(const nsAString& aNamespaceURI,
uint32_t
nsDOMAttributeMap::Count() const
{
return mAttributeCache.Count();
return mAttributeCache ? mAttributeCache->Count() : 0;
}
uint32_t
nsDOMAttributeMap::Enumerate(AttrCache::EnumReadFunction aFunc,
void *aUserArg) const
{
return mAttributeCache.EnumerateRead(aFunc, aUserArg);
return mAttributeCache ? mAttributeCache->EnumerateRead(aFunc, aUserArg) : 0;
}
size_t
@ -551,8 +570,10 @@ size_t
nsDOMAttributeMap::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const
{
size_t n = aMallocSizeOf(this);
n += mAttributeCache.SizeOfExcludingThis(AttrCacheSizeEnumerator,
aMallocSizeOf);
n += mAttributeCache
? mAttributeCache->SizeOfExcludingThis(AttrCacheSizeEnumerator,
aMallocSizeOf)
: 0;
// NB: mContent is non-owning and thus not counted.
return n;

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

@ -11,6 +11,7 @@
#define nsDOMAttributeMap_h
#include "mozilla/MemoryReporting.h"
#include "mozilla/UniquePtr.h"
#include "mozilla/dom/Attr.h"
#include "mozilla/ErrorResult.h"
#include "nsCycleCollectionParticipant.h"
@ -183,9 +184,11 @@ private:
nsCOMPtr<Element> mContent;
/**
* Cache of Attrs.
* Cache of Attrs. It's usually empty, and thus initialized lazily.
*/
AttrCache mAttributeCache;
mozilla::UniquePtr<AttrCache> mAttributeCache;
void EnsureAttributeCache();
/**
* SetNamedItem() (aWithNS = false) and SetNamedItemNS() (aWithNS =

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

@ -323,7 +323,7 @@ static bool
IsMP4SupportedType(const nsACString& aType)
{
return Preferences::GetBool("media.fragmented-mp4.exposed", false) &&
MP4Decoder::GetSupportedCodecs(aType, nullptr);
MP4Decoder::CanHandleMediaType(aType);
}
#endif
@ -406,8 +406,9 @@ DecoderTraits::CanHandleMediaType(const char* aMIMEType,
}
#endif
#ifdef MOZ_FMP4
if (IsMP4SupportedType(nsDependentCString(aMIMEType))) {
result = aHaveRequestedCodecs ? CANPLAY_YES : CANPLAY_MAYBE;
if (MP4Decoder::CanHandleMediaType(nsDependentCString(aMIMEType),
aRequestedCodecs)) {
return aHaveRequestedCodecs ? CANPLAY_YES : CANPLAY_MAYBE;
}
#endif
#ifdef MOZ_GSTREAMER
@ -683,6 +684,14 @@ MediaDecoderReader* DecoderTraits::CreateReader(const nsACString& aType, Abstrac
/* static */
bool DecoderTraits::IsSupportedInVideoDocument(const nsACString& aType)
{
// Forbid playing media in video documents if the user has opted
// not to, using either the legacy WMF specific pref, or the newer
// catch-all pref.
if (!Preferences::GetBool("media.windows-media-foundation.play-stand-alone", true) ||
!Preferences::GetBool("media.play-stand-alone", true)) {
return false;
}
return
IsOggType(aType) ||
#ifdef MOZ_OMX_DECODER
@ -703,8 +712,7 @@ bool DecoderTraits::IsSupportedInVideoDocument(const nsACString& aType)
IsMP4SupportedType(aType) ||
#endif
#ifdef MOZ_WMF
(IsWMFSupportedType(aType) &&
Preferences::GetBool("media.windows-media-foundation.play-stand-alone", true)) ||
IsWMFSupportedType(aType) ||
#endif
#ifdef MOZ_DIRECTSHOW
IsDirectShowSupportedType(aType) ||

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

@ -198,4 +198,36 @@ TemporaryRef<SharedThreadPool> GetMediaDecodeThreadPool()
Preferences::GetUint("media.num-decode-threads", 25));
}
bool
ExtractH264CodecDetails(const nsAString& aCodec,
int16_t& aProfile,
int16_t& aLevel)
{
// H.264 codecs parameters have a type defined as avc1.PPCCLL, where
// PP = profile_idc, CC = constraint_set flags, LL = level_idc.
// We ignore the constraint_set flags, as it's not clear from any
// documentation what constraints the platform decoders support.
// See http://blog.pearce.org.nz/2013/11/what-does-h264avc1-codecs-parameters.html
// for more details.
if (aCodec.Length() != strlen("avc1.PPCCLL")) {
return false;
}
// Verify the codec starts with "avc1.".
const nsAString& sample = Substring(aCodec, 0, 5);
if (!sample.EqualsASCII("avc1.")) {
return false;
}
// Extract the profile_idc, constrains, and level_idc.
nsresult rv = NS_OK;
aProfile = PromiseFlatString(Substring(aCodec, 5, 2)).ToInteger(&rv, 16);
NS_ENSURE_SUCCESS(rv, false);
aLevel = PromiseFlatString(Substring(aCodec, 9, 2)).ToInteger(&rv, 16);
NS_ENSURE_SUCCESS(rv, false);
return true;
}
} // end namespace mozilla

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

@ -215,6 +215,45 @@ class SharedThreadPool;
// for decoding streams.
TemporaryRef<SharedThreadPool> GetMediaDecodeThreadPool();
enum H264_PROFILE {
H264_PROFILE_UNKNOWN = 0,
H264_PROFILE_BASE = 0x42,
H264_PROFILE_MAIN = 0x4D,
H264_PROFILE_EXTENDED = 0x58,
H264_PROFILE_HIGH = 0x64,
};
enum H264_LEVEL {
H264_LEVEL_1 = 10,
H264_LEVEL_1_b = 11,
H264_LEVEL_1_1 = 11,
H264_LEVEL_1_2 = 12,
H264_LEVEL_1_3 = 13,
H264_LEVEL_2 = 20,
H264_LEVEL_2_1 = 21,
H264_LEVEL_2_2 = 22,
H264_LEVEL_3 = 30,
H264_LEVEL_3_1 = 31,
H264_LEVEL_3_2 = 32,
H264_LEVEL_4 = 40,
H264_LEVEL_4_1 = 41,
H264_LEVEL_4_2 = 42,
H264_LEVEL_5 = 50,
H264_LEVEL_5_1 = 51,
H264_LEVEL_5_2 = 52
};
// Extracts the H.264/AVC profile and level from an H.264 codecs string.
// H.264 codecs parameters have a type defined as avc1.PPCCLL, where
// PP = profile_idc, CC = constraint_set flags, LL = level_idc.
// See http://blog.pearce.org.nz/2013/11/what-does-h264avc1-codecs-parameters.html
// for more details.
// Returns false on failure.
bool
ExtractH264CodecDetails(const nsAString& aCodecs,
int16_t& aProfile,
int16_t& aLevel);
} // end namespace mozilla
#endif

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

@ -8,6 +8,7 @@
#include "MP4Reader.h"
#include "MediaDecoderStateMachine.h"
#include "mozilla/Preferences.h"
#include "nsCharSeparatedTokenizer.h"
#ifdef MOZ_EME
#include "mozilla/CDMProxy.h"
#endif
@ -50,48 +51,77 @@ MP4Decoder::SetCDMProxy(CDMProxy* aProxy)
}
#endif
static bool
IsSupportedAudioCodec(const nsAString& aCodec)
{
// AAC-LC, HE-AAC or MP3 in M4A.
return aCodec.EqualsASCII("mp4a.40.2") ||
#ifndef MOZ_GONK_MEDIACODEC // B2G doesn't support MP3 in MP4 yet.
aCodec.EqualsASCII("mp3") ||
#endif
aCodec.EqualsASCII("mp4a.40.5");
}
static bool
IsSupportedH264Codec(const nsAString& aCodec)
{
int16_t profile = 0, level = 0;
if (!ExtractH264CodecDetails(aCodec, profile, level)) {
return false;
}
// Just assume what we can play on all platforms the codecs/formats that
// WMF can play, since we don't have documentation about what other
// platforms can play... According to the WMF documentation:
// http://msdn.microsoft.com/en-us/library/windows/desktop/dd797815%28v=vs.85%29.aspx
// "The Media Foundation H.264 video decoder is a Media Foundation Transform
// that supports decoding of Baseline, Main, and High profiles, up to level
// 5.1.". We also report that we can play Extended profile, as there are
// bitstreams that are Extended compliant that are also Baseline compliant.
return level >= H264_LEVEL_1 &&
level <= H264_LEVEL_5_1 &&
(profile == H264_PROFILE_BASE ||
profile == H264_PROFILE_MAIN ||
profile == H264_PROFILE_EXTENDED ||
profile == H264_PROFILE_HIGH);
}
/* static */
bool
MP4Decoder::GetSupportedCodecs(const nsACString& aType,
char const *const ** aCodecList)
MP4Decoder::CanHandleMediaType(const nsACString& aType,
const nsAString& aCodecs)
{
if (!IsEnabled()) {
return false;
}
// AAC in M4A.
static char const *const aacAudioCodecs[] = {
"mp4a.40.2", // AAC-LC
// TODO: AAC-HE ?
nullptr
};
if (aType.EqualsASCII("audio/mp4") ||
aType.EqualsASCII("audio/x-m4a")) {
if (aCodecList) {
*aCodecList = aacAudioCodecs;
}
return true;
if (aType.EqualsASCII("audio/mp4") || aType.EqualsASCII("audio/x-m4a")) {
return aCodecs.IsEmpty() || IsSupportedAudioCodec(aCodecs);
}
// H.264 + AAC in MP4.
static char const *const h264Codecs[] = {
"avc1.42E01E", // H.264 Constrained Baseline Profile Level 3.0
"avc1.42001E", // H.264 Baseline Profile Level 3.0
"avc1.58A01E", // H.264 Extended Profile Level 3.0
"avc1.4D401E", // H.264 Main Profile Level 3.0
"avc1.64001E", // H.264 High Profile Level 3.0
"avc1.64001F", // H.264 High Profile Level 3.1
"mp4a.40.2", // AAC-LC
// TODO: There must be more profiles here?
nullptr
};
if (aType.EqualsASCII("video/mp4")) {
if (aCodecList) {
*aCodecList = h264Codecs;
}
return true;
if (!aType.EqualsASCII("video/mp4")) {
return false;
}
return false;
// Verify that all the codecs specifed are ones that we expect that
// we can play.
nsCharSeparatedTokenizer tokenizer(aCodecs, ',');
bool expectMoreTokens = false;
while (tokenizer.hasMoreTokens()) {
const nsSubstring& token = tokenizer.nextToken();
expectMoreTokens = tokenizer.separatorAfterCurrentToken();
if (IsSupportedAudioCodec(token) || IsSupportedH264Codec(token)) {
continue;
}
return false;
}
if (expectMoreTokens) {
// Last codec name was empty
return false;
}
return true;
}
static bool
@ -151,7 +181,7 @@ HavePlatformMPEGDecoders()
#endif
IsFFmpegAvailable() ||
IsAppleAvailable() ||
IsGonkMP4DecoderAvailable() ||
IsGonkMP4DecoderAvailable() ||
// TODO: Other platforms...
false;
}
@ -160,8 +190,8 @@ HavePlatformMPEGDecoders()
bool
MP4Decoder::IsEnabled()
{
return HavePlatformMPEGDecoders() &&
Preferences::GetBool("media.fragmented-mp4.enabled");
return Preferences::GetBool("media.fragmented-mp4.enabled") &&
HavePlatformMPEGDecoders();
}
} // namespace mozilla

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

@ -28,12 +28,11 @@ public:
virtual nsresult SetCDMProxy(CDMProxy* aProxy) MOZ_OVERRIDE;
#endif
// Returns true if aType is a MIME type that we can render with the
// a MP4 platform decoder backend. If aCodecList is non null,
// it is filled with a (static const) null-terminated list of strings
// denoting the codecs we'll playback.
static bool GetSupportedCodecs(const nsACString& aType,
char const *const ** aCodecList);
// Returns true if aMIMEType is a type that we think we can render with the
// a MP4 platform decoder backend. If aCodecs is non emtpy, it is filled
// with a comma-delimited list of codecs to check support for.
static bool CanHandleMediaType(const nsACString& aMIMEType,
const nsAString& aCodecs = EmptyString());
// Returns true if the MP4 backend is preffed on, and we're running on a
// platform that is likely to have decoders for the contained formats.

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

@ -774,7 +774,10 @@ MP4Reader::NotifyDataArrived(const char* aBuffer, uint32_t aLength,
int64_t aOffset)
{
if (NS_IsMainThread()) {
GetTaskQueue()->Dispatch(NS_NewRunnableMethod(this, &MP4Reader::UpdateIndex));
if (GetTaskQueue()) {
GetTaskQueue()->Dispatch(
NS_NewRunnableMethod(this, &MP4Reader::UpdateIndex));
}
} else {
UpdateIndex();
}

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

@ -145,7 +145,8 @@ AppleVTDecoder::Drain()
// Context object to hold a copy of sample metadata.
class FrameRef {
public:
Microseconds timestamp;
Microseconds decode_timestamp;
Microseconds composition_timestamp;
Microseconds duration;
int64_t byte_offset;
bool is_sync_point;
@ -153,7 +154,8 @@ public:
explicit FrameRef(mp4_demuxer::MP4Sample* aSample)
{
MOZ_ASSERT(aSample);
timestamp = aSample->composition_timestamp;
decode_timestamp = aSample->decode_timestamp;
composition_timestamp = aSample->composition_timestamp;
duration = aSample->duration;
byte_offset = aSample->byte_offset;
is_sync_point = aSample->is_sync_point;
@ -180,9 +182,10 @@ PlatformCallback(void* decompressionOutputRefCon,
nsAutoPtr<FrameRef> frameRef =
nsAutoPtr<FrameRef>(static_cast<FrameRef*>(sourceFrameRefCon));
LOG("mp4 output frame %lld pts %lld duration %lld us%s",
LOG("mp4 output frame %lld dts %lld pts %lld duration %lld us%s",
frameRef->byte_offset,
frameRef->timestamp,
frameRef->decode_timestamp,
frameRef->composition_timestamp,
frameRef->duration,
frameRef->is_sync_point ? " keyframe" : ""
);
@ -302,11 +305,11 @@ AppleVTDecoder::OutputFrame(CVPixelBufferRef aImage,
mImageContainer,
nullptr,
aFrameRef->byte_offset,
aFrameRef->timestamp,
aFrameRef->composition_timestamp,
aFrameRef->duration,
buffer,
aFrameRef->is_sync_point,
aFrameRef->timestamp,
aFrameRef->decode_timestamp,
visible);
// Unlock the returned image data.
CVPixelBufferUnlockBaseAddress(aImage, kCVPixelBufferLock_ReadOnly);
@ -320,10 +323,21 @@ AppleVTDecoder::OutputFrame(CVPixelBufferRef aImage,
// Frames come out in DTS order but we need to output them
// in composition order.
mReorderQueue.Push(data.forget());
if (mReorderQueue.Length() > 2) {
// Assume a frame with a PTS <= current DTS is ready.
while (mReorderQueue.Length() > 0) {
VideoData* readyData = mReorderQueue.Pop();
mCallback->Output(readyData);
if (readyData->mTime <= aFrameRef->decode_timestamp) {
LOG("returning queued frame with pts %lld", readyData->mTime);
mCallback->Output(readyData);
} else {
LOG("requeued frame with pts %lld > %lld",
readyData->mTime, aFrameRef->decode_timestamp);
mReorderQueue.Push(readyData);
break;
}
}
LOG("%llu decoded frames queued",
static_cast<unsigned long long>(mReorderQueue.Length()));
return NS_OK;
}
@ -337,8 +351,8 @@ TimingInfoFromSample(mp4_demuxer::MP4Sample* aSample)
timestamp.duration = CMTimeMake(aSample->duration, USECS_PER_S);
timestamp.presentationTimeStamp =
CMTimeMake(aSample->composition_timestamp, USECS_PER_S);
// No DTS value available from libstagefright.
timestamp.decodeTimeStamp = CMTimeMake(0, USECS_PER_S);
timestamp.decodeTimeStamp =
CMTimeMake(aSample->decode_timestamp, USECS_PER_S);
return timestamp;
}

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

@ -56,6 +56,7 @@ FFmpegH264Decoder<LIBAV_VER>::DecodeFrame(mp4_demuxer::MP4Sample* aSample)
aSample->Pad(FF_INPUT_BUFFER_PADDING_SIZE);
packet.data = aSample->data;
packet.size = aSample->size;
packet.dts = aSample->decode_timestamp;
packet.pts = aSample->composition_timestamp;
packet.flags = aSample->is_sync_point ? AV_PKT_FLAG_KEY : 0;
packet.pos = aSample->byte_offset;

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

@ -1,51 +0,0 @@
function check_mp4(v, enabled) {
function check(type, expected) {
var ex = enabled ? expected : "";
is(v.canPlayType(type), ex, type + "='" + ex + "'");
}
check("video/mp4", "maybe");
check("audio/mp4", "maybe");
check("audio/x-m4a", "maybe");
// Not the MIME type that other browsers respond to, so we won't either.
check("audio/m4a", "");
// Only Safari responds affirmatively to "audio/aac",
// so we'll let x-m4a cover aac support.
check("audio/aac", "");
check("video/mp4; codecs=\"avc1.42E01E, mp4a.40.2\"", "probably");
check("video/mp4; codecs=\"avc1.42001E, mp4a.40.2\"", "probably");
check("video/mp4; codecs=\"avc1.58A01E, mp4a.40.2\"", "probably");
check("video/mp4; codecs=\"avc1.4D401E, mp4a.40.2\"", "probably");
check("video/mp4; codecs=\"avc1.64001E, mp4a.40.2\"", "probably");
check("video/mp4; codecs=\"avc1.64001F, mp4a.40.2\"", "probably");
check("video/mp4; codecs=\"avc1.42E01E\"", "probably");
check("video/mp4; codecs=\"avc1.42001E\"", "probably");
check("video/mp4; codecs=\"avc1.58A01E\"", "probably");
check("video/mp4; codecs=\"avc1.4D401E\"", "probably");
check("video/mp4; codecs=\"avc1.64001E\"", "probably");
check("video/mp4; codecs=\"avc1.64001F\"", "probably");
check("audio/mp4; codecs=\"mp4a.40.2\"", "probably");
check("audio/mp4; codecs=mp4a.40.2", "probably");
check("audio/x-m4a; codecs=\"mp4a.40.2\"", "probably");
check("audio/x-m4a; codecs=mp4a.40.2", "probably");
}
function check_mp3(v, enabled) {
function check(type, expected) {
var ex = enabled ? expected : "";
is(v.canPlayType(type), ex, type + "='" + ex + "'");
}
check("audio/mpeg", "maybe");
check("audio/mp3", "maybe");
check("audio/mpeg; codecs=\"mp3\"", "probably");
check("audio/mpeg; codecs=mp3", "probably");
check("audio/mp3; codecs=\"mp3\"", "probably");
check("audio/mp3; codecs=mp3", "probably");
}

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

@ -108,7 +108,6 @@ support-files =
bug604067.webm^headers^
bug883173.vtt
can_play_type_dash.js
can_play_type_mpeg.js
can_play_type_ogg.js
can_play_type_wave.js
can_play_type_webm.js

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

@ -17,9 +17,82 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=799315
<video id="v"></video>
<pre id="test">
<script src="can_play_type_mpeg.js"></script>
<script>
function check_mp4(v, enabled) {
function check(type, expected) {
var ex = enabled ? expected : "";
is(v.canPlayType(type), ex, type + "='" + ex + "'");
}
check("video/mp4", "maybe");
check("audio/mp4", "maybe");
check("audio/x-m4a", "maybe");
// Not the MIME type that other browsers respond to, so we won't either.
check("audio/m4a", "");
// Only Safari responds affirmatively to "audio/aac",
// so we'll let x-m4a cover aac support.
check("audio/aac", "");
// H.264 Constrained Baseline Profile Level 3.0, AAC-LC
check("video/mp4; codecs=\"avc1.42E01E, mp4a.40.2\"", "probably");
// H.264 Constrained Baseline Profile Level 3.0, mp3
check("video/mp4; codecs=\"avc1.42E01E, mp3\"", "probably");
check("video/mp4; codecs=\"avc1.42001E, mp4a.40.2\"", "probably");
check("video/mp4; codecs=\"avc1.58A01E, mp4a.40.2\"", "probably");
const ProbablyIfNotLinux = !IsLinuxGStreamer() ? "probably" : "";
// H.264 Main Profile Level 3.0, AAC-LC
check("video/mp4; codecs=\"avc1.4D401E, mp4a.40.2\"", "probably");
// H.264 Main Profile Level 3.1, AAC-LC
check("video/mp4; codecs=\"avc1.4D401F, mp4a.40.2\"", ProbablyIfNotLinux);
// H.264 Main Profile Level 4.0, AAC-LC
check("video/mp4; codecs=\"avc1.4D4028, mp4a.40.2\"", ProbablyIfNotLinux);
// H.264 High Profile Level 3.0, AAC-LC
check("video/mp4; codecs=\"avc1.64001E, mp4a.40.2\"", "probably");
// H.264 High Profile Level 3.1, AAC-LC
check("video/mp4; codecs=\"avc1.64001F, mp4a.40.2\"", "probably");
check("video/mp4; codecs=\"avc1.42E01E\"", "probably");
check("video/mp4; codecs=\"avc1.42001E\"", "probably");
check("video/mp4; codecs=\"avc1.58A01E\"", "probably");
check("video/mp4; codecs=\"avc1.4D401E\"", "probably");
check("video/mp4; codecs=\"avc1.64001F\"", "probably");
// AAC-LC
check("audio/mp4; codecs=\"mp4a.40.2\"", "probably");
check("audio/mp4; codecs=mp4a.40.2", "probably");
check("audio/x-m4a; codecs=\"mp4a.40.2\"", "probably");
check("audio/x-m4a; codecs=mp4a.40.2", "probably");
// HE-AAC v1
check("audio/mp4; codecs=\"mp4a.40.5\"", ProbablyIfNotLinux);
check("audio/mp4; codecs=mp4a.40.5", ProbablyIfNotLinux);
check("audio/x-m4a; codecs=\"mp4a.40.5\"", ProbablyIfNotLinux);
check("audio/x-m4a; codecs=mp4a.40.5", ProbablyIfNotLinux);
}
function check_mp3(v, enabled) {
function check(type, expected) {
var ex = enabled ? expected : "";
is(v.canPlayType(type), ex, type + "='" + ex + "'");
}
check("audio/mpeg", "maybe");
check("audio/mp3", "maybe");
check("audio/mpeg; codecs=\"mp3\"", "probably");
check("audio/mpeg; codecs=mp3", "probably");
check("audio/mp3; codecs=\"mp3\"", "probably");
check("audio/mp3; codecs=mp3", "probably");
}
function IsWindowsVistaOrLater() {
var re = /Windows NT (\d+\.\d)/;
var winver = navigator.userAgent.match(re);
@ -45,6 +118,11 @@ function getPref(name) {
return pref;
}
function IsLinuxGStreamer() {
return /Linux/.test(navigator.userAgent) &&
getPref("media.gstreamer.enabled");
}
// Check whether we should expect the new MP4Reader-based support to work.
function IsMP4ReaderAvailable() {
var prefs = getPref("media.fragmented-mp4.enabled") &&

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

@ -54,38 +54,17 @@ IsSupportedH264Codec(const nsAString& aCodec)
// 5.1.". We also report that we can play Extended profile, as there are
// bitstreams that are Extended compliant that are also Baseline compliant.
// H.264 codecs parameters have a type defined as avc1.PPCCLL, where
// PP = profile_idc, CC = constraint_set flags, LL = level_idc.
// We ignore the constraint_set flags, as it's not clear from the WMF
// documentation what constraints the WMF H.264 decoder supports.
// See http://blog.pearce.org.nz/2013/11/what-does-h264avc1-codecs-parameters.html
// for more details.
if (aCodec.Length() != strlen("avc1.PPCCLL")) {
int16_t profile = 0, level = 0;
if (!ExtractH264CodecDetails(aCodec, profile, level)) {
return false;
}
// Verify the codec starts with "avc1.".
const nsAString& sample = Substring(aCodec, 0, 5);
if (!sample.EqualsASCII("avc1.")) {
return false;
}
// Extract the profile_idc and level_idc. Note: the constraint_set flags
// are ignored, it's not clear from the WMF documentation if they make a
// difference.
nsresult rv = NS_OK;
const int32_t profile = PromiseFlatString(Substring(aCodec, 5, 2)).ToInteger(&rv, 16);
NS_ENSURE_SUCCESS(rv, false);
const int32_t level = PromiseFlatString(Substring(aCodec, 9, 2)).ToInteger(&rv, 16);
NS_ENSURE_SUCCESS(rv, false);
return level >= eAVEncH264VLevel1 &&
level <= eAVEncH264VLevel5_1 &&
(profile == eAVEncH264VProfile_Base ||
profile == eAVEncH264VProfile_Main ||
profile == eAVEncH264VProfile_Extended ||
profile == eAVEncH264VProfile_High);
return level >= H264_LEVEL_1 &&
level <= H264_LEVEL_5_1 &&
(profile == H264_PROFILE_BASE ||
profile == H264_PROFILE_MAIN ||
profile == H264_PROFILE_EXTENDED ||
profile == H264_PROFILE_HIGH);
}
bool

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

@ -624,6 +624,7 @@ METHOD(Warn, "warn")
METHOD(Error, "error")
METHOD(Exception, "exception")
METHOD(Debug, "debug")
METHOD(Table, "table")
void
Console::Trace(JSContext* aCx)

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

@ -66,6 +66,9 @@ public:
void
Debug(JSContext* aCx, const Sequence<JS::Value>& aData);
void
Table(JSContext* aCx, const Sequence<JS::Value>& aData);
void
Trace(JSContext* aCx);
@ -111,6 +114,7 @@ private:
MethodError,
MethodException,
MethodDebug,
MethodTable,
MethodTrace,
MethodDir,
MethodGroup,

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

@ -15,6 +15,7 @@
ok("console" in window, "Console exists");
window.console.log(42);
ok("table" in console, "Console has the 'table' method.");
window.console = 42;
is(window.console, 42, "Console is replacable");

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

@ -29,8 +29,7 @@ DefineStaticJSVals(JSContext* cx)
return InternJSString(cx, s_length_id, "length");
}
const char HandlerFamily = 0;
const char DOMProxyHandler::family = 0;
js::DOMProxyShadowsResult
DOMProxyShadows(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id)
@ -60,7 +59,7 @@ DOMProxyShadows(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id)
struct SetDOMProxyInformation
{
SetDOMProxyInformation() {
js::SetDOMProxyInformation((const void*) &HandlerFamily,
js::SetDOMProxyInformation((const void*) &DOMProxyHandler::family,
js::PROXY_EXTRA_SLOT + JSPROXYSLOT_EXPANDO, DOMProxyShadows);
}
};
@ -363,5 +362,25 @@ DOMProxyHandler::setCustom(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handl
return true;
}
//static
JSObject *
DOMProxyHandler::GetExpandoObject(JSObject *obj)
{
MOZ_ASSERT(IsDOMProxy(obj), "expected a DOM proxy object");
JS::Value v = js::GetProxyExtra(obj, JSPROXYSLOT_EXPANDO);
if (v.isObject()) {
return &v.toObject();
}
if (v.isUndefined()) {
return nullptr;
}
js::ExpandoAndGeneration* expandoAndGeneration =
static_cast<js::ExpandoAndGeneration*>(v.toPrivate());
v = expandoAndGeneration->expando;
return v.isUndefined() ? nullptr : &v.toObject();
}
} // namespace dom
} // namespace mozilla

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

@ -24,17 +24,6 @@ enum {
template<typename T> struct Prefable;
// This variable exists solely to provide a unique address for use as an identifier.
extern const char HandlerFamily;
inline const void* ProxyFamily() { return &HandlerFamily; }
inline bool IsDOMProxy(JSObject *obj)
{
const js::Class* clasp = js::GetObjectClass(obj);
return clasp->isProxy() &&
js::GetProxyHandler(obj)->family() == ProxyFamily();
}
class BaseDOMProxyHandler : public js::BaseProxyHandler
{
public:
@ -89,7 +78,7 @@ class DOMProxyHandler : public BaseDOMProxyHandler
{
public:
DOMProxyHandler()
: BaseDOMProxyHandler(ProxyFamily())
: BaseDOMProxyHandler(&family)
{
}
@ -121,29 +110,23 @@ public:
virtual bool setCustom(JSContext* cx, JS::Handle<JSObject*> proxy, JS::Handle<jsid> id,
JS::MutableHandle<JS::Value> vp, bool *done) const;
static JSObject* GetExpandoObject(JSObject* obj)
{
MOZ_ASSERT(IsDOMProxy(obj), "expected a DOM proxy object");
JS::Value v = js::GetProxyExtra(obj, JSPROXYSLOT_EXPANDO);
if (v.isObject()) {
return &v.toObject();
}
static JSObject* GetExpandoObject(JSObject* obj);
if (v.isUndefined()) {
return nullptr;
}
js::ExpandoAndGeneration* expandoAndGeneration =
static_cast<js::ExpandoAndGeneration*>(v.toPrivate());
v = expandoAndGeneration->expando;
return v.isUndefined() ? nullptr : &v.toObject();
}
/* GetAndClearExpandoObject does not DROP or clear the preserving wrapper flag. */
static JSObject* GetAndClearExpandoObject(JSObject* obj);
static JSObject* EnsureExpandoObject(JSContext* cx,
JS::Handle<JSObject*> obj);
static const char family;
};
inline bool IsDOMProxy(JSObject *obj)
{
const js::Class* clasp = js::GetObjectClass(obj);
return clasp->isProxy() &&
js::GetProxyHandler(obj)->family() == &DOMProxyHandler::family;
}
inline const DOMProxyHandler*
GetDOMProxyHandler(JSObject* obj)
{

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

@ -72,6 +72,8 @@
#include "mozilla/layers/ShadowLayers.h"
#endif
#include <queue>
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::gfx;
@ -435,12 +437,10 @@ WebGLContext::SetContextOptions(JSContext* aCx, JS::Handle<JS::Value> aOptions)
newOpts.premultipliedAlpha = attributes.mPremultipliedAlpha;
newOpts.antialias = attributes.mAntialias;
newOpts.preserveDrawingBuffer = attributes.mPreserveDrawingBuffer;
if (attributes.mAlpha.WasPassed()) {
newOpts.alpha = attributes.mAlpha.Value();
}
// enforce that if stencil is specified, we also give back depth
newOpts.depth |= newOpts.stencil;
if (attributes.mAlpha.WasPassed()) {
newOpts.alpha = attributes.mAlpha.Value();
}
// Don't do antialiasing if we've disabled MSAA.
if (!gfxPrefs::MSAALevel()) {
@ -471,36 +471,333 @@ WebGLContext::SetContextOptions(JSContext* aCx, JS::Handle<JS::Value> aOptions)
int32_t
WebGLContext::GetWidth() const
{
return mWidth;
return mWidth;
}
int32_t
WebGLContext::GetHeight() const
{
return mHeight;
return mHeight;
}
#endif
/* So there are a number of points of failure here. We might fail based
* on EGL vs. WGL, or we might fail to alloc a too-large size, or we
* might not be able to create a context with a certain combo of context
* creation attribs.
*
* We don't want to test the complete fallback matrix. (for now, at
* least) Instead, attempt creation in this order:
* 1. By platform API. (e.g. EGL vs. WGL)
* 2. By context creation attribs.
* 3. By size.
*
* That is, try to create headless contexts based on the platform API.
* Next, create dummy-sized backbuffers for the contexts with the right
* caps. Finally, resize the backbuffer to an acceptable size given the
* requested size.
*/
static bool
IsFeatureInBlacklist(const nsCOMPtr<nsIGfxInfo>& gfxInfo, int32_t feature)
{
int32_t status;
if (!NS_SUCCEEDED(gfxInfo->GetFeatureStatus(feature, &status)))
return false;
return status != nsIGfxInfo::FEATURE_STATUS_OK;
}
static already_AddRefed<GLContext>
CreateHeadlessNativeGL(bool forceEnabled,
const nsCOMPtr<nsIGfxInfo>& gfxInfo,
WebGLContext* webgl)
{
if (!forceEnabled &&
IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_OPENGL))
{
webgl->GenerateWarning("Refused to create native OpenGL context"
" because of blacklisting.");
return nullptr;
}
nsRefPtr<GLContext> gl = gl::GLContextProvider::CreateHeadless();
if (!gl) {
webgl->GenerateWarning("Error during native OpenGL init.");
return nullptr;
}
MOZ_ASSERT(!gl->IsANGLE());
return gl.forget();
}
// Note that we have a separate call for ANGLE and EGL, even though
// right now, we get ANGLE implicitly by using EGL on Windows.
// Eventually, we want to be able to pick ANGLE-EGL or native EGL.
static already_AddRefed<GLContext>
CreateHeadlessANGLE(bool forceEnabled,
const nsCOMPtr<nsIGfxInfo>& gfxInfo,
WebGLContext* webgl)
{
nsRefPtr<GLContext> gl;
#ifdef XP_WIN
if (!forceEnabled &&
IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_ANGLE))
{
webgl->GenerateWarning("Refused to create ANGLE OpenGL context"
" because of blacklisting.");
return nullptr;
}
gl = gl::GLContextProviderEGL::CreateHeadless();
if (!gl) {
webgl->GenerateWarning("Error during ANGLE OpenGL init.");
return nullptr;
}
MOZ_ASSERT(gl->IsANGLE());
#endif
return gl.forget();
}
static already_AddRefed<GLContext>
CreateHeadlessEGL(bool forceEnabled,
const nsCOMPtr<nsIGfxInfo>& gfxInfo,
WebGLContext* webgl)
{
nsRefPtr<GLContext> gl;
#ifdef ANDROID
gl = gl::GLContextProviderEGL::CreateHeadless();
if (!gl) {
webgl->GenerateWarning("Error during EGL OpenGL init.");
return nullptr;
}
MOZ_ASSERT(!gl->IsANGLE());
#endif
return gl.forget();
}
static already_AddRefed<GLContext>
CreateHeadlessGL(bool forceEnabled,
const nsCOMPtr<nsIGfxInfo>& gfxInfo,
WebGLContext* webgl)
{
bool preferEGL = PR_GetEnv("MOZ_WEBGL_PREFER_EGL");
bool disableANGLE = Preferences::GetBool("webgl.disable-angle", false);
if (PR_GetEnv("MOZ_WEBGL_FORCE_OPENGL")) {
disableANGLE = true;
}
nsRefPtr<GLContext> gl;
if (preferEGL)
gl = CreateHeadlessEGL(forceEnabled, gfxInfo, webgl);
if (!gl && !disableANGLE)
gl = CreateHeadlessANGLE(forceEnabled, gfxInfo, webgl);
if (!gl)
gl = CreateHeadlessNativeGL(forceEnabled, gfxInfo, webgl);
return gl.forget();
}
// Try to create a dummy offscreen with the given caps.
static bool
CreateOffscreenWithCaps(GLContext* gl, const SurfaceCaps& caps)
{
gfx::IntSize dummySize(16, 16);
return gl->InitOffscreen(dummySize, caps);
}
static void
PopulateCapFallbackQueue(const SurfaceCaps& baseCaps,
std::queue<SurfaceCaps>* fallbackCaps)
{
fallbackCaps->push(baseCaps);
// Dropping antialias drops our quality, but not our correctness.
// The user basically doesn't have to handle if this fails, they
// just get reduced quality.
if (baseCaps.antialias) {
SurfaceCaps nextCaps(baseCaps);
nextCaps.antialias = false;
PopulateCapFallbackQueue(nextCaps, fallbackCaps);
}
// If we have to drop one of depth or stencil, we'd prefer to keep
// depth. However, the client app will need to handle if this
// doesn't work.
if (baseCaps.stencil) {
SurfaceCaps nextCaps(baseCaps);
nextCaps.stencil = false;
PopulateCapFallbackQueue(nextCaps, fallbackCaps);
}
if (baseCaps.depth) {
SurfaceCaps nextCaps(baseCaps);
nextCaps.depth = false;
PopulateCapFallbackQueue(nextCaps, fallbackCaps);
}
}
static bool
CreateOffscreen(GLContext* gl,
const WebGLContextOptions& options,
const nsCOMPtr<nsIGfxInfo>& gfxInfo,
WebGLContext* webgl,
layers::ISurfaceAllocator* surfAllocator)
{
SurfaceCaps baseCaps;
baseCaps.color = true;
baseCaps.alpha = options.alpha;
baseCaps.antialias = options.antialias;
baseCaps.depth = options.depth;
baseCaps.preserve = options.preserveDrawingBuffer;
baseCaps.stencil = options.stencil;
// we should really have this behind a
// |gfxPlatform::GetPlatform()->GetScreenDepth() == 16| check, but
// for now it's just behind a pref for testing/evaluation.
baseCaps.bpp16 = Preferences::GetBool("webgl.prefer-16bpp", false);
#ifdef MOZ_WIDGET_GONK
baseCaps.surfaceAllocator = surfAllocator;
#endif
// Done with baseCaps construction.
bool forceAllowAA = Preferences::GetBool("webgl.msaa-force", false);
if (!forceAllowAA &&
IsFeatureInBlacklist(gfxInfo, nsIGfxInfo::FEATURE_WEBGL_MSAA))
{
webgl->GenerateWarning("Disallowing antialiased backbuffers due"
" to blacklisting.");
baseCaps.antialias = false;
}
std::queue<SurfaceCaps> fallbackCaps;
PopulateCapFallbackQueue(baseCaps, &fallbackCaps);
bool created = false;
while (!fallbackCaps.empty()) {
SurfaceCaps& caps = fallbackCaps.front();
created = CreateOffscreenWithCaps(gl, caps);
if (created)
break;
fallbackCaps.pop();
}
return created;
}
bool
WebGLContext::CreateOffscreenGL(bool forceEnabled)
{
nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
layers::ISurfaceAllocator* surfAllocator = nullptr;
#ifdef MOZ_WIDGET_GONK
nsIWidget* docWidget = nsContentUtils::WidgetForDocument(mCanvasElement->OwnerDoc());
if (docWidget) {
layers::LayerManager* layerManager = docWidget->GetLayerManager();
if (layerManager) {
// XXX we really want "AsSurfaceAllocator" here for generality
layers::ShadowLayerForwarder* forwarder = layerManager->AsShadowForwarder();
if (forwarder) {
surfAllocator = static_cast<layers::ISurfaceAllocator*>(forwarder);
}
}
}
#endif
gl = CreateHeadlessGL(forceEnabled, gfxInfo, this);
do {
if (!gl)
break;
if (!CreateOffscreen(gl, mOptions, gfxInfo, this, surfAllocator))
break;
if (!InitAndValidateGL())
break;
return true;
} while (false);
gl = nullptr;
return false;
}
// Fallback for resizes:
bool
WebGLContext::ResizeBackbuffer(uint32_t requestedWidth, uint32_t requestedHeight)
{
uint32_t width = requestedWidth;
uint32_t height = requestedHeight;
bool resized = false;
while (width || height) {
width = width ? width : 1;
height = height ? height : 1;
gfx::IntSize curSize(width, height);
if (gl->ResizeOffscreen(curSize)) {
resized = true;
break;
}
width /= 2;
height /= 2;
}
if (!resized)
return false;
mWidth = gl->OffscreenSize().width;
mHeight = gl->OffscreenSize().height;
MOZ_ASSERT((uint32_t)mWidth == width);
MOZ_ASSERT((uint32_t)mHeight == height);
if (width != requestedWidth ||
height != requestedHeight)
{
GenerateWarning("Requested size %dx%d was too large, but resize"
" to %dx%d succeeded.",
requestedWidth, requestedHeight,
width, height);
}
return true;
}
NS_IMETHODIMP
WebGLContext::SetDimensions(int32_t width, int32_t height)
WebGLContext::SetDimensions(int32_t sWidth, int32_t sHeight)
{
// Early error return cases
if (!GetCanvas())
return NS_ERROR_FAILURE;
if (width < 0 || height < 0) {
if (sWidth < 0 || sHeight < 0) {
GenerateWarning("Canvas size is too large (seems like a negative value wrapped)");
return NS_ERROR_OUT_OF_MEMORY;
}
if (!GetCanvas())
return NS_ERROR_FAILURE;
uint32_t width = sWidth;
uint32_t height = sHeight;
// Early success return cases
GetCanvas()->InvalidateCanvas();
if (gl && mWidth == width && mHeight == height)
return NS_OK;
// Zero-sized surfaces can cause problems.
if (width == 0) {
width = 1;
@ -511,20 +808,29 @@ WebGLContext::SetDimensions(int32_t width, int32_t height)
// If we already have a gl context, then we just need to resize it
if (gl) {
if ((uint32_t)mWidth == width &&
(uint32_t)mHeight == height)
{
return NS_OK;
}
if (IsContextLost())
return NS_OK;
MakeContextCurrent();
// If we've already drawn, we should commit the current buffer.
PresentScreenBuffer();
// ResizeOffscreen scraps the current prod buffer before making a new one.
gl->ResizeOffscreen(gfx::IntSize(width, height)); // Doesn't matter if it succeeds (soft-fail)
// It's unlikely that we'll get a proper-sized context if we recreate if we didn't on resize
if (!ResizeBackbuffer(width, height)) {
GenerateWarning("WebGL context failed to resize.");
ForceLoseContext();
return NS_OK;
}
// everything's good, we're done here
mWidth = gl->OffscreenSize().width;
mHeight = gl->OffscreenSize().height;
mResetLayer = true;
mBackbufferNeedsClear = true;
return NS_OK;
@ -541,27 +847,6 @@ WebGLContext::SetDimensions(int32_t width, int32_t height)
// and that is what can fail if we already have too many.
LoseOldestWebGLContextIfLimitExceeded();
// Get some prefs for some preferred/overriden things
NS_ENSURE_TRUE(Preferences::GetRootBranch(), NS_ERROR_FAILURE);
#ifdef XP_WIN
bool preferEGL =
Preferences::GetBool("webgl.prefer-egl", false);
bool preferOpenGL =
Preferences::GetBool("webgl.prefer-native-gl", false);
#endif
bool forceEnabled =
Preferences::GetBool("webgl.force-enabled", false);
bool disabled =
Preferences::GetBool("webgl.disabled", false);
bool prefer16bit =
Preferences::GetBool("webgl.prefer-16bpp", false);
ScopedGfxFeatureReporter reporter("WebGL", forceEnabled);
if (disabled)
return NS_ERROR_FAILURE;
// We're going to create an entirely new context. If our
// generation is not 0 right now (that is, if this isn't the first
// context we're creating), we may have to dispatch a context lost
@ -570,111 +855,32 @@ WebGLContext::SetDimensions(int32_t width, int32_t height)
// If incrementing the generation would cause overflow,
// don't allow it. Allowing this would allow us to use
// resource handles created from older context generations.
if (!(mGeneration + 1).isValid())
if (!(mGeneration + 1).isValid()) {
GenerateWarning("Too many WebGL contexts created this run.");
return NS_ERROR_FAILURE; // exit without changing the value of mGeneration
SurfaceCaps caps;
caps.color = true;
caps.alpha = mOptions.alpha;
caps.depth = mOptions.depth;
caps.stencil = mOptions.stencil;
// we should really have this behind a
// |gfxPlatform::GetPlatform()->GetScreenDepth() == 16| check, but
// for now it's just behind a pref for testing/evaluation.
caps.bpp16 = prefer16bit;
caps.preserve = mOptions.preserveDrawingBuffer;
#ifdef MOZ_WIDGET_GONK
nsIWidget *docWidget = nsContentUtils::WidgetForDocument(mCanvasElement->OwnerDoc());
if (docWidget) {
layers::LayerManager *layerManager = docWidget->GetLayerManager();
if (layerManager) {
// XXX we really want "AsSurfaceAllocator" here for generality
layers::ShadowLayerForwarder *forwarder = layerManager->AsShadowForwarder();
if (forwarder) {
caps.surfaceAllocator = static_cast<layers::ISurfaceAllocator*>(forwarder);
}
}
}
#endif
bool forceMSAA =
Preferences::GetBool("webgl.msaa-force", false);
int32_t status;
nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
if (mOptions.antialias &&
gfxInfo &&
NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_WEBGL_MSAA, &status))) {
if (status == nsIGfxInfo::FEATURE_STATUS_OK || forceMSAA) {
caps.antialias = true;
}
}
#ifdef XP_WIN
if (PR_GetEnv("MOZ_WEBGL_PREFER_EGL")) {
preferEGL = true;
}
#endif
// Get some prefs for some preferred/overriden things
NS_ENSURE_TRUE(Preferences::GetRootBranch(), NS_ERROR_FAILURE);
// Ask GfxInfo about what we should use
bool useOpenGL = true;
#ifdef XP_WIN
bool useANGLE = true;
#endif
if (gfxInfo && !forceEnabled) {
if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_WEBGL_OPENGL, &status))) {
if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
useOpenGL = false;
}
}
#ifdef XP_WIN
if (NS_SUCCEEDED(gfxInfo->GetFeatureStatus(nsIGfxInfo::FEATURE_WEBGL_ANGLE, &status))) {
if (status != nsIGfxInfo::FEATURE_STATUS_OK) {
useANGLE = false;
}
}
#endif
bool disabled = Preferences::GetBool("webgl.disabled", false);
if (disabled) {
GenerateWarning("WebGL creation is disabled, and so disallowed here.");
return NS_ERROR_FAILURE;
}
#ifdef XP_WIN
// allow forcing GL and not EGL/ANGLE
if (PR_GetEnv("MOZ_WEBGL_FORCE_OPENGL")) {
preferEGL = false;
useANGLE = false;
useOpenGL = true;
// Alright, now let's start trying.
bool forceEnabled = Preferences::GetBool("webgl.force-enabled", false);
ScopedGfxFeatureReporter reporter("WebGL", forceEnabled);
if (!CreateOffscreenGL(forceEnabled)) {
GenerateWarning("WebGL creation failed.");
return NS_ERROR_FAILURE;
}
#endif
MOZ_ASSERT(gl);
gfxIntSize size(width, height);
#ifdef XP_WIN
// if we want EGL, try it now
if (!gl && (preferEGL || useANGLE) && !preferOpenGL) {
gl = gl::GLContextProviderEGL::CreateOffscreen(size, caps);
if (!gl || !InitAndValidateGL()) {
GenerateWarning("Error during ANGLE OpenGL ES initialization");
return NS_ERROR_FAILURE;
}
}
#endif
// try the default provider, whatever that is
if (!gl && useOpenGL) {
gl = gl::GLContextProvider::CreateOffscreen(size, caps);
if (gl && !InitAndValidateGL()) {
GenerateWarning("Error during OpenGL initialization");
return NS_ERROR_FAILURE;
}
}
if (!gl) {
GenerateWarning("Can't get a usable WebGL context");
if (!ResizeBackbuffer(width, height)) {
GenerateWarning("Initializing WebGL backbuffer failed.");
return NS_ERROR_FAILURE;
}
@ -684,23 +890,18 @@ WebGLContext::SetDimensions(int32_t width, int32_t height)
}
#endif
mWidth = width;
mHeight = height;
mViewportWidth = width;
mViewportHeight = height;
mResetLayer = true;
mOptionsFrozen = true;
// increment the generation number
++mGeneration;
#if 0
if (mGeneration > 0) {
// XXX dispatch context lost event
}
#endif
MakeContextCurrent();
gl->fViewport(0, 0, mWidth, mHeight);
mViewportWidth = mWidth;
mViewportHeight = mHeight;
// Make sure that we clear this out, otherwise
// we'll end up displaying random memory
gl->fBindFramebuffer(LOCAL_GL_FRAMEBUFFER, 0);
@ -715,12 +916,12 @@ WebGLContext::SetDimensions(int32_t width, int32_t height)
mShouldPresent = true;
MOZ_ASSERT(gl->Caps().color == caps.color);
MOZ_ASSERT(gl->Caps().alpha == caps.alpha);
MOZ_ASSERT(gl->Caps().depth == caps.depth || !gl->Caps().depth);
MOZ_ASSERT(gl->Caps().stencil == caps.stencil || !gl->Caps().stencil);
MOZ_ASSERT(gl->Caps().antialias == caps.antialias || !gl->Caps().antialias);
MOZ_ASSERT(gl->Caps().preserve == caps.preserve);
MOZ_ASSERT(gl->Caps().color);
MOZ_ASSERT(gl->Caps().alpha == mOptions.alpha);
MOZ_ASSERT(gl->Caps().depth == mOptions.depth || !gl->Caps().depth);
MOZ_ASSERT(gl->Caps().stencil == mOptions.stencil || !gl->Caps().stencil);
MOZ_ASSERT(gl->Caps().antialias == mOptions.antialias || !gl->Caps().antialias);
MOZ_ASSERT(gl->Caps().preserve == mOptions.preserveDrawingBuffer);
AssertCachedBindings();
AssertCachedState();
@ -1211,7 +1412,7 @@ WebGLContext::PresentScreenBuffer()
gl->MakeCurrent();
MOZ_ASSERT(!mBackbufferNeedsClear);
if (!gl->PublishFrame()) {
this->ForceLoseContext();
ForceLoseContext();
return false;
}

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

@ -1036,7 +1036,9 @@ protected:
// Validation functions (implemented in WebGLContextValidate.cpp)
GLenum BaseTexFormat(GLenum internalFormat) const;
bool CreateOffscreenGL(bool forceEnabled);
bool InitAndValidateGL();
bool ResizeBackbuffer(uint32_t width, uint32_t height);
bool ValidateBlendEquationEnum(GLenum cap, const char *info);
bool ValidateBlendFuncDstEnum(GLenum mode, const char *info);
bool ValidateBlendFuncSrcEnum(GLenum mode, const char *info);

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

@ -175,10 +175,10 @@ skip-if(winWidget) pref(webgl.prefer-16bpp,true)
skip-if(winWidget) pref(webgl.prefer-16bpp,true) pref(webgl.force-layers-readback,true) random-if(Android&&AndroidVersion<15) == webgl-color-test.html?16bpp&readback wrapper.html?colors.png
# Force native GL (Windows):
skip-if(!winWidget) pref(webgl.prefer-native-gl,true) == webgl-clear-test.html?native-gl wrapper.html?green.png
skip-if(!winWidget) pref(webgl.prefer-native-gl,true) == webgl-orientation-test.html?native-gl wrapper.html?white-top-left.png
skip-if(!winWidget) pref(webgl.prefer-native-gl,true) == webgl-color-test.html?native-gl wrapper.html?colors.png
skip-if(!winWidget) pref(webgl.prefer-native-gl,true) pref(webgl.prefer-16bpp,true) == webgl-color-test.html?native-gl&16bpp wrapper.html?colors.png
skip-if(!winWidget) pref(webgl.disable-angle,true) == webgl-clear-test.html?native-gl wrapper.html?green.png
skip-if(!winWidget) pref(webgl.disable-angle,true) == webgl-orientation-test.html?native-gl wrapper.html?white-top-left.png
skip-if(!winWidget) pref(webgl.disable-angle,true) == webgl-color-test.html?native-gl wrapper.html?colors.png
skip-if(!winWidget) pref(webgl.disable-angle,true) pref(webgl.prefer-16bpp,true) == webgl-color-test.html?native-gl&16bpp wrapper.html?colors.png
# Non-WebGL Reftests!

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

@ -2280,6 +2280,34 @@ PeerConnectionWrapper.prototype = {
}
},
/**
* Property-matching function for finding a certain stat in passed-in stats
*
* @param {object} stats
* The stats to check from this PeerConnectionWrapper
* @param {object} props
* The properties to look for
* @returns {boolean} Whether an entry containing all match-props was found.
*/
hasStat : function PCW_hasStat(stats, props) {
for (var key in stats) {
if (stats.hasOwnProperty(key)) {
var res = stats[key];
var match = true;
for (var prop in props) {
if (res[prop] !== props[prop]) {
match = false;
break;
}
}
if (match) {
return true;
}
}
}
return false;
},
/**
* Closes the connection
*/

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

@ -413,6 +413,174 @@ var commandsPeerConnection = [
test.next();
});
}
],
[
'PC_LOCAL_CHECK_GETSTATS_AUDIOTRACK_OUTBOUND',
function (test) {
var pc = test.pcLocal;
var stream = pc._pc.getLocalStreams()[0];
var track = stream && stream.getAudioTracks()[0];
if (track) {
var msg = "pcLocal.HasStat outbound audio rtp ";
pc.getStats(track, function(stats) {
ok(pc.hasStat(stats,
{ type:"outboundrtp", isRemote:false, mediaType:"audio" }),
msg + "1");
ok(!pc.hasStat(stats, { type:"inboundrtp", isRemote:false }), msg + "2");
ok(!pc.hasStat(stats, { mediaType:"video" }), msg + "3");
test.next();
});
} else {
test.next();
}
}
],
[
'PC_LOCAL_CHECK_GETSTATS_VIDEOTRACK_OUTBOUND',
function (test) {
var pc = test.pcLocal;
var stream = pc._pc.getLocalStreams()[0];
var track = stream && stream.getVideoTracks()[0];
if (track) {
var msg = "pcLocal.HasStat outbound video rtp ";
pc.getStats(track, function(stats) {
ok(pc.hasStat(stats,
{ type:"outboundrtp", isRemote:false, mediaType:"video" }),
msg + "1");
ok(!pc.hasStat(stats, { type:"inboundrtp", isRemote:false }), msg + "2");
ok(!pc.hasStat(stats, { mediaType:"audio" }), msg + "3");
test.next();
});
} else {
test.next();
}
}
],
[
'PC_LOCAL_CHECK_GETSTATS_AUDIOTRACK_INBOUND',
function (test) {
var pc = test.pcLocal;
var stream = pc._pc.getRemoteStreams()[0];
var track = stream && stream.getAudioTracks()[0];
if (track) {
var msg = "pcLocal.HasStat inbound audio rtp ";
pc.getStats(track, function(stats) {
ok(pc.hasStat(stats,
{ type:"inboundrtp", isRemote:false, mediaType:"audio" }),
msg + "1");
ok(!pc.hasStat(stats, { type:"outboundrtp", isRemote:false }), msg + "2");
ok(!pc.hasStat(stats, { mediaType:"video" }), msg + "3");
test.next();
});
} else {
test.next();
}
}
],
[
'PC_LOCAL_CHECK_GETSTATS_VIDEOTRACK_INBOUND',
function (test) {
var pc = test.pcLocal;
var stream = pc._pc.getRemoteStreams()[0];
var track = stream && stream.getVideoTracks()[0];
if (track) {
var msg = "pcLocal.HasStat inbound video rtp ";
pc.getStats(track, function(stats) {
ok(pc.hasStat(stats,
{ type:"inboundrtp", isRemote:false, mediaType:"video" }),
msg + "1");
ok(!pc.hasStat(stats, { type:"outboundrtp", isRemote:false }), msg + "2");
ok(!pc.hasStat(stats, { mediaType:"audio" }), msg + "3");
test.next();
});
} else {
test.next();
}
}
],
[
'PC_REMOTE_CHECK_GETSTATS_AUDIOTRACK_OUTBOUND',
function (test) {
var pc = test.pcRemote;
var stream = pc._pc.getLocalStreams()[0];
var track = stream && stream.getAudioTracks()[0];
if (track) {
var msg = "pcRemote.HasStat outbound audio rtp ";
pc.getStats(track, function(stats) {
ok(pc.hasStat(stats,
{ type:"outboundrtp", isRemote:false, mediaType:"audio" }),
msg + "1");
ok(!pc.hasStat(stats, { type:"inboundrtp", isRemote:false }), msg + "2");
ok(!pc.hasStat(stats, { mediaType:"video" }), msg + "3");
test.next();
});
} else {
test.next();
}
}
],
[
'PC_REMOTE_CHECK_GETSTATS_VIDEOTRACK_OUTBOUND',
function (test) {
var pc = test.pcRemote;
var stream = pc._pc.getLocalStreams()[0];
var track = stream && stream.getVideoTracks()[0];
if (track) {
var msg = "pcRemote.HasStat outbound audio rtp ";
pc.getStats(track, function(stats) {
ok(pc.hasStat(stats,
{ type:"outboundrtp", isRemote:false, mediaType:"video" }),
msg + "1");
ok(!pc.hasStat(stats, { type:"inboundrtp", isRemote:false }), msg + "2");
ok(!pc.hasStat(stats, { mediaType:"audio" }), msg + "3");
test.next();
});
} else {
test.next();
}
}
],
[
'PC_REMOTE_CHECK_GETSTATS_AUDIOTRACK_INBOUND',
function (test) {
var pc = test.pcRemote;
var stream = pc._pc.getRemoteStreams()[0];
var track = stream && stream.getAudioTracks()[0];
if (track) {
var msg = "pcRemote.HasStat inbound audio rtp ";
pc.getStats(track, function(stats) {
ok(pc.hasStat(stats,
{ type:"inboundrtp", isRemote:false, mediaType:"audio" }),
msg + "1");
ok(!pc.hasStat(stats, { type:"outboundrtp", isRemote:false }), msg + "2");
ok(!pc.hasStat(stats, { mediaType:"video" }), msg + "3");
test.next();
});
} else {
test.next();
}
}
],
[
'PC_REMOTE_CHECK_GETSTATS_VIDEOTRACK_INBOUND',
function (test) {
var pc = test.pcRemote;
var stream = pc._pc.getRemoteStreams()[0];
var track = stream && stream.getVideoTracks()[0];
if (track) {
var msg = "pcRemote.HasStat inbound video rtp ";
pc.getStats(track, function(stats) {
ok(pc.hasStat(stats,
{ type:"inboundrtp", isRemote:false, mediaType:"video" }),
msg + "1");
ok(!pc.hasStat(stats, { type:"outboundrtp", isRemote:false }), msg + "2");
ok(!pc.hasStat(stats, { mediaType:"audio" }), msg + "3");
test.next();
});
} else {
test.next();
}
}
]
];

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

@ -18,6 +18,7 @@ DEFINES['NS_NO_XPCOM'] = True
DEFINES['_HAS_EXCEPTIONS'] = 0
DISABLE_STL_WRAPPING = True
USE_STATIC_LIBS = True
if CONFIG['GNU_CC']:
WIN32_EXE_LDFLAGS += ['-municode']

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

@ -97,12 +97,22 @@ DialogWatcher.prototype.init = function() {
ctypes.jschar.ptr,
ctypes.int);
}
if (!this.messageBox) {
// Handy for debugging this code
this.messageBox = user32.declare("MessageBoxW",
ctypes.winapi_abi,
ctypes.int,
ctypes.uintptr_t,
ctypes.jschar.ptr,
ctypes.jschar.ptr,
ctypes.uint32_t);
}
};
DialogWatcher.prototype.getWindowText = function(hwnd) {
var bufType = ctypes.ArrayType(ctypes.jschar);
var buffer = new bufType(256);
if (this.getWindowTextW(hwnd, buffer, buffer.length)) {
return buffer.readString();
}
@ -154,13 +164,15 @@ DialogWatcher.prototype.processWindowEvents = function(timeout) {
var waitStatus = WAIT_OBJECT_0;
var expectingStart = this.onDialogStart && this.hwnd === undefined;
var startWaitTime = Date.now();
while (this.hwnd === undefined || this.onDialogEnd && this.hwnd) {
waitStatus = this.msgWaitForMultipleObjects(0, null, 0, expectingStart ?
INFINITE : timeout, 0);
if (waitStatus == WAIT_OBJECT_0) {
var msg = new this.msgType;
this.peekMessage(msg.address(), 0, 0, 0, PM_NOREMOVE);
} else if (waitStatus == WAIT_TIMEOUT) {
}
if (waitStatus == WAIT_TIMEOUT || (Date.now() - startWaitTime) >= timeout) {
break;
}
}

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

@ -8,6 +8,8 @@
<title>Plugin Hang UI Test</title>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
<script type="application/javascript"
src="utils.js" />
<script type="application/javascript"
src="http://mochi.test:8888/chrome/dom/plugins/test/mochitest/hang_test.js" />
<script type="application/javascript"
@ -19,6 +21,7 @@
<script class="testbody" type="application/javascript">
<![CDATA[
SimpleTest.waitForExplicitFinish();
setTestPluginEnabledState(SpecialPowers.Ci.nsIPluginTag.STATE_ENABLED);
Components.utils.import("resource://gre/modules/Services.jsm");
@ -100,7 +103,8 @@ function runTests() {
resetVars();
hanguiExpect("Prime ChromeWorker", false, false, "test1");
hanguiOperation("Prime ChromeWorker", 0, false, false, HANGUIOP_NOTHING, 0,
false, "test1");
}
window.frameLoaded = runTests;
@ -244,7 +248,7 @@ function test3() {
}
function test2() {
// This test is identical to test1 because there were some bugs where the
// This test is identical to test1 because there were some bugs where the
// Hang UI would show on the first hang but not on subsequent hangs
hanguiExpect("test2: Plugin Hang UI is showing", true, true, "test3");
p.stall(STALL_DURATION);

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

@ -496,6 +496,17 @@ nsGeolocationRequest::SendLocation(nsIDOMGeoPosition* aPosition)
return;
}
if (mOptions && mOptions->mMaximumAge > 0) {
DOMTimeStamp positionTime_ms;
aPosition->GetTimestamp(&positionTime_ms);
const uint32_t maximumAge_ms = mOptions->mMaximumAge;
const bool isTooOld =
DOMTimeStamp(PR_Now() / PR_USEC_PER_MSEC - maximumAge_ms) > positionTime_ms;
if (isTooOld) {
return;
}
}
nsRefPtr<Position> wrapped;
if (aPosition) {

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

@ -19,6 +19,7 @@
#include <pthread.h>
#include <hardware/gps.h>
#include "mozilla/Constants.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "nsContentUtils.h"
@ -81,8 +82,8 @@ GonkGPSGeolocationProvider::LocationCallback(GpsLocation* location)
NS_IMETHOD Run() {
nsRefPtr<GonkGPSGeolocationProvider> provider =
GonkGPSGeolocationProvider::GetSingleton();
provider->mLastGPSDerivedLocationTime = PR_Now();
nsCOMPtr<nsIGeolocationUpdate> callback = provider->mLocationCallback;
provider->mLastGPSPosition = mPosition;
if (callback) {
callback->Update(mPosition);
}
@ -101,7 +102,14 @@ GonkGPSGeolocationProvider::LocationCallback(GpsLocation* location)
location->accuracy,
location->bearing,
location->speed,
location->timestamp);
PR_Now() / PR_USEC_PER_MSEC);
// Note above: Can't use location->timestamp as the time from the satellite is a
// minimum of 16 secs old (see http://leapsecond.com/java/gpsclock.htm).
// All code from this point on expects the gps location to be timestamped with the
// current time, most notably: the geolocation service which respects maximumAge
// set in the DOM JS.
NS_DispatchToMainThread(new UpdateLocationEvent(somewhere));
}
@ -699,7 +707,7 @@ GonkGPSGeolocationProvider::NetworkLocationUpdate::Update(nsIDOMGeoPosition *pos
coords->GetLongitude(&lon);
coords->GetAccuracy(&acc);
double delta = MAXFLOAT;
double delta = -1.0;
static double sLastMLSPosLat = 0;
static double sLastMLSPosLon = 0;
@ -708,15 +716,20 @@ GonkGPSGeolocationProvider::NetworkLocationUpdate::Update(nsIDOMGeoPosition *pos
// Use spherical law of cosines to calculate difference
// Not quite as correct as the Haversine but simpler and cheaper
// Should the following be a utility function? Others might need this calc.
const double radsInDeg = 3.14159265 / 180.0;
const double radsInDeg = M_PI / 180.0;
const double rNewLat = lat * radsInDeg;
const double rNewLon = lon * radsInDeg;
const double rOldLat = sLastMLSPosLat * radsInDeg;
const double rOldLon = sLastMLSPosLon * radsInDeg;
// WGS84 equatorial radius of earth = 6378137m
delta = acos( (sin(rNewLat) * sin(rOldLat)) +
(cos(rNewLat) * cos(rOldLat) * cos(rOldLon - rNewLon)) )
* 6378137;
double cosDelta = (sin(rNewLat) * sin(rOldLat)) +
(cos(rNewLat) * cos(rOldLat) * cos(rOldLon - rNewLon));
if (cosDelta > 1.0) {
cosDelta = 1.0;
} else if (cosDelta < -1.0) {
cosDelta = -1.0;
}
delta = acos(cosDelta) * 6378137;
}
sLastMLSPosLat = lat;
@ -726,14 +739,40 @@ GonkGPSGeolocationProvider::NetworkLocationUpdate::Update(nsIDOMGeoPosition *pos
// assume the MLS coord is unchanged, and stick with the GPS location
const double kMinMLSCoordChangeInMeters = 10;
// if we haven't seen anything from the GPS device for 10s,
// use this network derived location.
const int kMaxGPSDelayBeforeConsideringMLS = 10000;
int64_t diff = PR_Now() - provider->mLastGPSDerivedLocationTime;
if (provider->mLocationCallback && diff > kMaxGPSDelayBeforeConsideringMLS
&& delta > kMinMLSCoordChangeInMeters)
{
provider->mLocationCallback->Update(position);
DOMTimeStamp time_ms = 0;
if (provider->mLastGPSPosition) {
provider->mLastGPSPosition->GetTimestamp(&time_ms);
}
const int64_t diff_ms = (PR_Now() / PR_USEC_PER_MSEC) - time_ms;
// We want to distinguish between the GPS being inactive completely
// and temporarily inactive. In the former case, we would use a low
// accuracy network location; in the latter, we only want a network
// location that appears to updating with movement.
const bool isGPSFullyInactive = diff_ms > 1000 * 60 * 2; // two mins
const bool isGPSTempInactive = diff_ms > 1000 * 10; // 10 secs
if (provider->mLocationCallback) {
if (isGPSFullyInactive ||
(isGPSTempInactive && delta > kMinMLSCoordChangeInMeters))
{
if (gGPSDebugging) {
nsContentUtils::LogMessageToConsole("geo: Using MLS, GPS age:%fs, MLS Delta:%fm\n",
diff_ms / 1000.0, delta);
}
provider->mLocationCallback->Update(position);
} else if (provider->mLastGPSPosition) {
if (gGPSDebugging) {
nsContentUtils::LogMessageToConsole("geo: Using old GPS age:%fs\n",
diff_ms / 1000.0);
}
// This is a fallback case so that the GPS provider responds with its last
// location rather than waiting for a more recent GPS or network location.
// The service decides if the location is too old, not the provider.
provider->mLocationCallback->Update(provider->mLastGPSPosition);
}
}
provider->InjectLocation(lat, lon, acc);
@ -779,7 +818,6 @@ GonkGPSGeolocationProvider::Startup()
}
}
mLastGPSDerivedLocationTime = 0;
mStarted = true;
return NS_OK;
}

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

@ -21,6 +21,7 @@
#include "nsCOMPtr.h"
#include "nsIGeolocationProvider.h"
#include "nsIObserver.h"
#include "nsIDOMGeoPosition.h"
#ifdef MOZ_B2G_RIL
#include "nsIRadioInterfaceLayer.h"
#endif
@ -111,9 +112,9 @@ private:
nsCOMPtr<nsIRadioInterface> mRadioInterface;
#endif
nsCOMPtr<nsIGeolocationUpdate> mLocationCallback;
PRTime mLastGPSDerivedLocationTime;
nsCOMPtr<nsIThread> mInitThread;
nsCOMPtr<nsIGeolocationProvider> mNetworkLocationProvider;
nsCOMPtr<nsIDOMGeoPosition> mLastGPSPosition;
class NetworkLocationUpdate : public nsIGeolocationUpdate
{

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

@ -37,6 +37,7 @@ function doTest() {
"profileEnd": "function",
"assert": "function",
"count": "function",
"table": "function",
"__noSuchMethod__": "function"
};

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

@ -13,6 +13,7 @@ interface Console {
void error(any... data);
void _exception(any... data);
void debug(any... data);
void table(any... data);
void trace();
void dir(any... data);
void group(any... data);

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

@ -27,6 +27,7 @@ dictionary RTCStats {
dictionary RTCRTPStreamStats : RTCStats {
DOMString ssrc;
DOMString mediaType;
DOMString remoteId;
boolean isRemote = false;
DOMString mediaTrackId;

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

@ -80,7 +80,9 @@ RenderTarget9::RenderTarget9(Renderer *renderer, GLsizei width, GLsizei height,
0, FALSE, &mRenderTarget, NULL);
}
if (result == D3DERR_OUTOFVIDEOMEMORY || result == E_OUTOFMEMORY)
if (result == D3DERR_OUTOFVIDEOMEMORY ||
result == E_INVALIDARG ||
result == E_OUTOFMEMORY)
{
gl::error(GL_OUT_OF_MEMORY);

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

@ -38,7 +38,6 @@ RenderbufferStorageBySamples(GLContext* aGL, GLsizei aSamples,
}
}
GLuint
CreateTexture(GLContext* aGL, GLenum aInternalFormat, GLenum aFormat,
GLenum aType, const gfx::IntSize& aSize, bool linear)
@ -47,10 +46,16 @@ CreateTexture(GLContext* aGL, GLenum aInternalFormat, GLenum aFormat,
aGL->fGenTextures(1, &tex);
ScopedBindTexture autoTex(aGL, tex);
aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MIN_FILTER, linear ? LOCAL_GL_LINEAR : LOCAL_GL_NEAREST);
aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_MAG_FILTER, linear ? LOCAL_GL_LINEAR : LOCAL_GL_NEAREST);
aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S, LOCAL_GL_CLAMP_TO_EDGE);
aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T, LOCAL_GL_CLAMP_TO_EDGE);
aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D,
LOCAL_GL_TEXTURE_MIN_FILTER, linear ? LOCAL_GL_LINEAR
: LOCAL_GL_NEAREST);
aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D,
LOCAL_GL_TEXTURE_MAG_FILTER, linear ? LOCAL_GL_LINEAR
: LOCAL_GL_NEAREST);
aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_S,
LOCAL_GL_CLAMP_TO_EDGE);
aGL->fTexParameteri(LOCAL_GL_TEXTURE_2D, LOCAL_GL_TEXTURE_WRAP_T,
LOCAL_GL_CLAMP_TO_EDGE);
aGL->fTexImage2D(LOCAL_GL_TEXTURE_2D,
0,

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

@ -277,7 +277,7 @@ GLContext::GLContext(const SurfaceCaps& caps,
mRenderer(GLRenderer::Other),
mHasRobustness(false),
#ifdef DEBUG
mGLError(LOCAL_GL_NO_ERROR),
mIsInLocalErrorCheck(false),
#endif
mSharedContext(sharedContext),
mCaps(caps),
@ -1112,6 +1112,7 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
raw_fGetIntegerv(LOCAL_GL_MAX_TEXTURE_SIZE, &mMaxTextureSize);
raw_fGetIntegerv(LOCAL_GL_MAX_CUBE_MAP_TEXTURE_SIZE, &mMaxCubeMapTextureSize);
raw_fGetIntegerv(LOCAL_GL_MAX_RENDERBUFFER_SIZE, &mMaxRenderbufferSize);
raw_fGetIntegerv(LOCAL_GL_MAX_VIEWPORT_DIMS, mMaxViewportDims);
#ifdef XP_MACOSX
if (mWorkAroundDriverBugs) {
@ -1127,8 +1128,7 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
// See bug 879656. 8192 fails, 8191 works.
mMaxTextureSize = std::min(mMaxTextureSize, 8191);
mMaxRenderbufferSize = std::min(mMaxRenderbufferSize, 8191);
}
else {
} else {
// See bug 877949.
mMaxTextureSize = std::min(mMaxTextureSize, 4096);
mMaxRenderbufferSize = std::min(mMaxRenderbufferSize, 4096);

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

@ -12,6 +12,7 @@
#include <ctype.h>
#include <map>
#include <bitset>
#include <queue>
#ifdef DEBUG
#include <string.h>
@ -505,7 +506,6 @@ private:
// -----------------------------------------------------------------------------
// Robustness handling
public:
bool HasRobustness() const {
return mHasRobustness;
}
@ -516,17 +516,13 @@ public:
*/
virtual bool SupportsRobustness() const = 0;
private:
bool mHasRobustness;
// -----------------------------------------------------------------------------
// Error handling
public:
static const char* GLErrorToString(GLenum aError)
{
static const char* GLErrorToString(GLenum aError) {
switch (aError) {
case LOCAL_GL_INVALID_ENUM:
return "GL_INVALID_ENUM";
@ -549,12 +545,10 @@ public:
}
}
/** \returns the first GL error, and guarantees that all GL error flags are cleared,
* i.e. that a subsequent GetError call will return NO_ERROR
*/
GLenum GetAndClearError()
{
GLenum GetAndClearError() {
// the first error is what we want to return
GLenum error = fGetError();
@ -566,30 +560,99 @@ public:
return error;
}
/*** In GL debug mode, we completely override glGetError ***/
GLenum fGetError()
{
#ifdef DEBUG
// debug mode ends up eating the error in AFTER_GL_CALL
if (DebugMode()) {
GLenum err = mGLError;
mGLError = LOCAL_GL_NO_ERROR;
return err;
}
#endif // DEBUG
private:
GLenum raw_fGetError() {
return mSymbols.fGetError();
}
std::queue<GLenum> mGLErrorQueue;
public:
GLenum fGetError() {
if (!mGLErrorQueue.empty()) {
GLenum err = mGLErrorQueue.front();
mGLErrorQueue.pop();
return err;
}
return GetUnpushedError();
}
#ifdef DEBUG
private:
GLenum GetUnpushedError() {
return raw_fGetError();
}
GLenum mGLError;
#endif // DEBUG
void ClearUnpushedErrors() {
while (GetUnpushedError()) {
// Discard errors.
}
}
GLenum GetAndClearUnpushedErrors() {
GLenum err = GetUnpushedError();
if (err) {
ClearUnpushedErrors();
}
return err;
}
void PushError(GLenum err) {
mGLErrorQueue.push(err);
}
void GetAndPushAllErrors() {
while (true) {
GLenum err = GetUnpushedError();
if (!err)
break;
PushError(err);
}
}
////////////////////////////////////
// Use this safer option.
private:
#ifdef DEBUG
bool mIsInLocalErrorCheck;
#endif
public:
class ScopedLocalErrorCheck {
GLContext* const mGL;
bool mHasBeenChecked;
public:
ScopedLocalErrorCheck(GLContext* gl)
: mGL(gl)
, mHasBeenChecked(false)
{
#ifdef DEBUG
MOZ_ASSERT(!mGL->mIsInLocalErrorCheck);
mGL->mIsInLocalErrorCheck = true;
#endif
mGL->GetAndPushAllErrors();
}
GLenum GetLocalError() {
#ifdef DEBUG
MOZ_ASSERT(mGL->mIsInLocalErrorCheck);
mGL->mIsInLocalErrorCheck = false;
#endif
MOZ_ASSERT(!mHasBeenChecked);
mHasBeenChecked = true;
return mGL->GetAndClearUnpushedErrors();
}
~ScopedLocalErrorCheck() {
MOZ_ASSERT(mHasBeenChecked);
}
};
private:
static void GLAPIENTRY StaticDebugCallback(GLenum source,
GLenum type,
GLuint id,
@ -624,8 +687,7 @@ private:
# endif
#endif
void BeforeGLCall(const char* glFunction)
{
void BeforeGLCall(const char* glFunction) {
MOZ_ASSERT(IsCurrent());
if (DebugMode()) {
GLContext *currentGLContext = nullptr;
@ -643,21 +705,23 @@ private:
}
}
void AfterGLCall(const char* glFunction)
{
void AfterGLCall(const char* glFunction) {
if (DebugMode()) {
// calling fFinish() immediately after every GL call makes sure that if this GL command crashes,
// the stack trace will actually point to it. Otherwise, OpenGL being an asynchronous API, stack traces
// tend to be meaningless
mSymbols.fFinish();
mGLError = mSymbols.fGetError();
GLenum err = GetUnpushedError();
PushError(err);
if (DebugMode() & DebugTrace)
printf_stderr("[gl:%p] < %s [0x%04x]\n", this, glFunction, mGLError);
if (mGLError != LOCAL_GL_NO_ERROR) {
printf_stderr("[gl:%p] < %s [0x%04x]\n", this, glFunction, err);
if (err != LOCAL_GL_NO_ERROR) {
printf_stderr("GL ERROR: %s generated GL error %s(0x%04x)\n",
glFunction,
GLErrorToString(mGLError),
mGLError);
GLErrorToString(err),
err);
if (DebugMode() & DebugAbortOnError)
NS_ABORT();
}
@ -2985,6 +3049,7 @@ protected:
GLint mMaxCubeMapTextureSize;
GLint mMaxTextureImageSize;
GLint mMaxRenderbufferSize;
GLint mMaxViewportDims[2];
GLsizei mMaxSamples;
bool mNeedsTextureSizeChecks;
bool mWorkAroundDriverBugs;

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

@ -247,25 +247,33 @@ CreateOffscreenFBOContext(bool aShare = true)
return glContext.forget();
}
already_AddRefed<GLContext>
GLContextProviderCGL::CreateHeadless()
{
nsRefPtr<GLContextCGL> glContext = CreateOffscreenFBOContext();
if (!glContext)
return nullptr;
if (!glContext->Init())
return nullptr;
return glContext.forget();
}
already_AddRefed<GLContext>
GLContextProviderCGL::CreateOffscreen(const gfxIntSize& size,
const SurfaceCaps& caps)
{
nsRefPtr<GLContextCGL> glContext = CreateOffscreenFBOContext();
if (glContext &&
glContext->Init() &&
glContext->InitOffscreen(ToIntSize(size), caps))
{
return glContext.forget();
}
nsRefPtr<GLContext> glContext = CreateHeadless();
if (!glContext->InitOffscreen(ToIntSize(size), caps))
return nullptr;
// everything failed
return nullptr;
return glContext.forget();
}
static nsRefPtr<GLContext> gGlobalContext;
GLContext *
GLContext*
GLContextProviderCGL::GetGlobalContext()
{
if (!sCGLLibrary.EnsureInitialized()) {

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

@ -878,20 +878,29 @@ GLContextEGL::CreateEGLPixmapOffscreenContext(const gfxIntSize& size)
return glContext.forget();
}
// Under EGL, on Android, pbuffers are supported fine, though
// often without the ability to texture from them directly.
already_AddRefed<GLContext>
GLContextProviderEGL::CreateOffscreen(const gfxIntSize& size,
const SurfaceCaps& caps)
GLContextProviderEGL::CreateHeadless()
{
if (!sEGLLibrary.EnsureInitialized()) {
return nullptr;
}
gfxIntSize dummySize = gfxIntSize(16, 16);
nsRefPtr<GLContextEGL> glContext;
nsRefPtr<GLContext> glContext;
glContext = GLContextEGL::CreateEGLPBufferOffscreenContext(dummySize);
if (!glContext)
return nullptr;
return glContext.forget();
}
// Under EGL, on Android, pbuffers are supported fine, though
// often without the ability to texture from them directly.
already_AddRefed<GLContext>
GLContextProviderEGL::CreateOffscreen(const gfxIntSize& size,
const SurfaceCaps& caps)
{
nsRefPtr<GLContext> glContext = CreateHeadless();
if (!glContext)
return nullptr;
@ -904,7 +913,7 @@ GLContextProviderEGL::CreateOffscreen(const gfxIntSize& size,
// Don't want a global context on Android as 1) share groups across 2 threads fail on many Tegra drivers (bug 759225)
// and 2) some mobile devices have a very strict limit on global number of GL contexts (bug 754257)
// and 3) each EGL context eats 750k on B2G (bug 813783)
GLContext *
GLContext*
GLContextProviderEGL::GetGlobalContext()
{
return nullptr;

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

@ -1212,14 +1212,22 @@ DONE_CREATING_PIXMAP:
return glContext.forget();
}
already_AddRefed<GLContext>
GLContextProviderGLX::CreateHeadless()
{
gfxIntSize dummySize = gfxIntSize(16, 16);
nsRefPtr<GLContext> glContext = CreateOffscreenPixmapContext(dummySize);
if (!glContext)
return nullptr;
return glContext.forget();
}
already_AddRefed<GLContext>
GLContextProviderGLX::CreateOffscreen(const gfxIntSize& size,
const SurfaceCaps& caps)
{
gfxIntSize dummySize = gfxIntSize(16, 16);
nsRefPtr<GLContextGLX> glContext =
CreateOffscreenPixmapContext(dummySize);
nsRefPtr<GLContext> glContext = CreateHeadless();
if (!glContext)
return nullptr;

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

@ -60,6 +60,10 @@ public:
CreateOffscreen(const gfxIntSize& size,
const SurfaceCaps& caps);
// Just create a context. We'll add offscreen stuff ourselves.
static already_AddRefed<GLContext>
CreateHeadless();
/**
* Create wrapping Gecko GLContext for external gl context.
*

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

@ -22,8 +22,13 @@ GLContextProviderNull::CreateWrappingExisting(void*, void*)
already_AddRefed<GLContext>
GLContextProviderNull::CreateOffscreen(const gfxIntSize&,
const SurfaceCaps&,
ContextFlags)
const SurfaceCaps&)
{
return nullptr;
}
already_AddRefed<GLContext>
GLContextProviderNull::CreateHeadless()
{
return nullptr;
}

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

@ -607,8 +607,7 @@ CreateWindowOffscreenContext()
}
already_AddRefed<GLContext>
GLContextProviderWGL::CreateOffscreen(const gfxIntSize& size,
const SurfaceCaps& caps)
GLContextProviderWGL::CreateHeadless()
{
if (!sWGLLib.EnsureInitialized()) {
return nullptr;
@ -636,6 +635,18 @@ GLContextProviderWGL::CreateOffscreen(const gfxIntSize& size,
return nullptr;
}
nsRefPtr<GLContext> retGL = glContext;
return retGL.forget();
}
already_AddRefed<GLContext>
GLContextProviderWGL::CreateOffscreen(const gfxIntSize& size,
const SurfaceCaps& caps)
{
nsRefPtr<GLContext> glContext = CreateHeadless();
if (!glContext)
return nullptr;
if (!glContext->InitOffscreen(ToIntSize(size), caps))
return nullptr;

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

@ -568,6 +568,8 @@ DrawBuffer::Create(GLContext* const gl,
pStencilRB = nullptr;
}
GLContext::ScopedLocalErrorCheck localError(gl);
CreateRenderbuffersForOffscreen(gl, formats, size, caps.antialias,
pColorMSRB, pDepthRB, pStencilRB);
@ -578,7 +580,8 @@ DrawBuffer::Create(GLContext* const gl,
UniquePtr<DrawBuffer> ret( new DrawBuffer(gl, size, fb, colorMSRB,
depthRB, stencilRB) );
if (!gl->IsFramebufferComplete(fb))
GLenum err = localError.GetLocalError();
if (err || !gl->IsFramebufferComplete(fb))
return false;
*out_buffer = Move(ret);
@ -624,6 +627,8 @@ ReadBuffer::Create(GLContext* gl,
GLuint* pDepthRB = caps.depth ? &depthRB : nullptr;
GLuint* pStencilRB = caps.stencil ? &stencilRB : nullptr;
GLContext::ScopedLocalErrorCheck localError(gl);
CreateRenderbuffersForOffscreen(gl, formats, surf->mSize, caps.antialias,
nullptr, pDepthRB, pStencilRB);
@ -651,7 +656,9 @@ ReadBuffer::Create(GLContext* gl,
UniquePtr<ReadBuffer> ret( new ReadBuffer(gl, fb, depthRB,
stencilRB, surf) );
if (!gl->IsFramebufferComplete(fb)) {
GLenum err = localError.GetLocalError();
if (err || !gl->IsFramebufferComplete(fb)) {
ret = nullptr;
}

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

@ -144,20 +144,28 @@ ChooseConfig(GLContext* gl,
return config;
}
// Returns EGL_NO_SURFACE on error.
// Returns `EGL_NO_SURFACE` (`0`) on error.
static EGLSurface
CreatePBufferSurface(GLLibraryEGL* egl,
EGLDisplay display,
EGLConfig config,
const gfx::IntSize& size)
{
auto width = size.width;
auto height = size.height;
EGLint attribs[] = {
LOCAL_EGL_WIDTH, size.width,
LOCAL_EGL_HEIGHT, size.height,
LOCAL_EGL_WIDTH, width,
LOCAL_EGL_HEIGHT, height,
LOCAL_EGL_NONE
};
DebugOnly<EGLint> preCallErr = egl->fGetError();
MOZ_ASSERT(preCallErr == LOCAL_EGL_SUCCESS);
EGLSurface surface = egl->fCreatePbufferSurface(display, config, attribs);
EGLint err = egl->fGetError();
if (err != LOCAL_EGL_SUCCESS)
return 0;
return surface;
}

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

@ -23,11 +23,19 @@ SharedSurface_Basic::Create(GLContext* gl,
const IntSize& size,
bool hasAlpha)
{
UniquePtr<SharedSurface_Basic> ret;
gl->MakeCurrent();
GLContext::ScopedLocalErrorCheck localError(gl);
GLuint tex = CreateTexture(gl, formats.color_texInternalFormat,
formats.color_texFormat,
formats.color_texType,
size);
GLenum err = localError.GetLocalError();
if (err) {
gl->fDeleteTextures(1, &tex);
return Move(ret);
}
SurfaceFormat format = SurfaceFormat::B8G8R8X8;
switch (formats.color_texInternalFormat) {
@ -46,8 +54,7 @@ SharedSurface_Basic::Create(GLContext* gl,
MOZ_CRASH("Unhandled Tex format.");
}
typedef SharedSurface_Basic ptrT;
UniquePtr<ptrT> ret( new ptrT(gl, size, hasAlpha, format, tex) );
ret.reset( new SharedSurface_Basic(gl, size, hasAlpha, format, tex) );
return Move(ret);
}
@ -74,11 +81,8 @@ SharedSurface_Basic::SharedSurface_Basic(GLContext* gl,
mTex,
0);
GLenum status = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
mGL->fDeleteFramebuffers(1, &mFB);
mFB = 0;
}
DebugOnly<GLenum> status = mGL->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
MOZ_ASSERT(status == LOCAL_GL_FRAMEBUFFER_COMPLETE);
int32_t stride = gfx::GetAlignedStride<4>(size.width * BytesPerPixel(format));
mData = gfx::Factory::CreateDataSourceSurfaceWithStride(size, format, stride);
@ -133,14 +137,24 @@ SharedSurface_GLTexture::Create(GLContext* prodGL,
bool ownsTex = false;
UniquePtr<SharedSurface_GLTexture> ret;
if (!tex) {
GLContext::ScopedLocalErrorCheck localError(prodGL);
tex = CreateTextureForOffscreen(prodGL, formats, size);
GLenum err = localError.GetLocalError();
if (err) {
prodGL->fDeleteTextures(1, &tex);
return Move(ret);
}
ownsTex = true;
}
typedef SharedSurface_GLTexture ptrT;
UniquePtr<ptrT> ret( new ptrT(prodGL, consGL, size, hasAlpha, tex,
ownsTex) );
ret.reset( new SharedSurface_GLTexture(prodGL, consGL, size,
hasAlpha, tex, ownsTex) );
return Move(ret);
}

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

@ -12,42 +12,42 @@ namespace gl {
SurfaceCaps::SurfaceCaps()
{
Clear();
Clear();
}
SurfaceCaps::SurfaceCaps(const SurfaceCaps& other)
{
*this = other;
*this = other;
}
SurfaceCaps&
SurfaceCaps::operator=(const SurfaceCaps& other)
{
any = other.any;
color = other.color;
alpha = other.alpha;
bpp16 = other.bpp16;
depth = other.depth;
stencil = other.stencil;
antialias = other.antialias;
preserve = other.preserve;
surfaceAllocator = other.surfaceAllocator;
any = other.any;
color = other.color;
alpha = other.alpha;
bpp16 = other.bpp16;
depth = other.depth;
stencil = other.stencil;
antialias = other.antialias;
preserve = other.preserve;
surfaceAllocator = other.surfaceAllocator;
return *this;
return *this;
}
void
SurfaceCaps::Clear()
{
any = false;
color = false;
alpha = false;
bpp16 = false;
depth = false;
stencil = false;
antialias = false;
preserve = false;
surfaceAllocator = nullptr;
any = false;
color = false;
alpha = false;
bpp16 = false;
depth = false;
stencil = false;
antialias = false;
preserve = false;
surfaceAllocator = nullptr;
}
SurfaceCaps::~SurfaceCaps()

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

@ -105,10 +105,17 @@ Compositor::DrawDiagnostics(DiagnosticFlags aFlags,
}
RenderTargetRect
Compositor::ClipRectInLayersCoordinates(RenderTargetIntRect aClip) const {
Compositor::ClipRectInLayersCoordinates(Layer* aLayer, RenderTargetIntRect aClip) const {
ContainerLayer* parent = aLayer->AsContainerLayer() ? aLayer->AsContainerLayer() : aLayer->GetParent();
while (!parent->UseIntermediateSurface() && parent->GetParent()) {
parent = parent->GetParent();
}
RenderTargetIntPoint renderTargetOffset = RenderTargetIntRect::FromUntyped(
parent->GetEffectiveVisibleRegion().GetBounds()).TopLeft();
RenderTargetRect result;
aClip = aClip + RenderTargetIntPoint(GetCurrentRenderTarget()->GetOrigin().x,
GetCurrentRenderTarget()->GetOrigin().y);
aClip = aClip + renderTargetOffset;
RenderTargetIntSize destSize = RenderTargetIntSize(GetWidgetSize().width,
GetWidgetSize().height);

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

@ -498,7 +498,7 @@ public:
// at the OS level rather than in Gecko.
// In addition, the clip rect needs to be offset by the rendering origin.
// This becomes important if intermediate surfaces are used.
RenderTargetRect ClipRectInLayersCoordinates(RenderTargetIntRect aClip) const;
RenderTargetRect ClipRectInLayersCoordinates(Layer* aLayer, RenderTargetIntRect aClip) const;
protected:
void DrawDiagnosticsInternal(DiagnosticFlags aFlags,

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

@ -345,6 +345,8 @@ ClientTiledThebesLayer::RenderLayer()
TILING_LOG("TILING %p: Initial low-precision valid region %s\n", this, Stringify(mLowPrecisionValidRegion).c_str());
nsIntRegion neededRegion = mVisibleRegion;
#ifndef MOZ_GFX_OPTIMIZE_MOBILE
// This is handled by PadDrawTargetOutFromRegion in TiledContentClient for mobile
if (MayResample()) {
// If we're resampling then bilinear filtering can read up to 1 pixel
// outside of our texture coords. Make the visible region a single rect,
@ -358,6 +360,7 @@ ClientTiledThebesLayer::RenderLayer()
padded.IntersectRect(padded, wholeTiles);
neededRegion = padded;
}
#endif
nsIntRegion invalidRegion;
invalidRegion.Sub(neededRegion, mValidRegion);

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

@ -320,6 +320,7 @@ ClientTiledLayerBuffer::GetContentType(SurfaceMode* aMode) const
if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
#if defined(MOZ_GFX_OPTIMIZE_MOBILE) || defined(MOZ_WIDGET_GONK)
mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
}
#else
if (!mThebesLayer->GetParent() ||
!mThebesLayer->GetParent()->SupportsComponentAlphaChildren() ||
@ -328,13 +329,13 @@ ClientTiledLayerBuffer::GetContentType(SurfaceMode* aMode) const
} else {
content = gfxContentType::COLOR;
}
#endif
} else if (mode == SurfaceMode::SURFACE_OPAQUE) {
if (mThebesLayer->MayResample()) {
mode = SurfaceMode::SURFACE_SINGLE_CHANNEL_ALPHA;
content = gfxContentType::COLOR_ALPHA;
}
}
#endif
if (aMode) {
*aMode = mode;
@ -1154,12 +1155,6 @@ ClientTiledLayerBuffer::ValidateTile(TileClient aTile,
}
}
if (backBuffer->HasInternalBuffer()) {
// If our new buffer has an internal buffer, we don't want to keep another
// TextureClient around unnecessarily, so discard the back-buffer.
aTile.DiscardBackBuffer();
}
// prepare an array of Moz2D tiles that will be painted into in PostValidate
gfx::Tile moz2DTile;
RefPtr<DrawTarget> dt = backBuffer->BorrowDrawTarget();
@ -1191,8 +1186,8 @@ ClientTiledLayerBuffer::ValidateTile(TileClient aTile,
drawRect.width,
drawRect.height);
gfx::IntPoint copyTarget(NS_roundf(drawRect.x), NS_roundf(drawRect.y));
// Mark the newly updated area as invalid in the front buffer
aTile.mInvalidFront.Or(aTile.mInvalidFront, nsIntRect(copyTarget.x, copyTarget.y, copyRect.width, copyRect.height));
// Mark the newly updated area as invalid in the back buffer
aTile.mInvalidBack.Or(aTile.mInvalidBack, nsIntRect(copyTarget.x, copyTarget.y, copyRect.width, copyRect.height));
if (mode == SurfaceMode::SURFACE_COMPONENT_ALPHA) {
dt->FillRect(drawRect, ColorPattern(Color(0.0, 0.0, 0.0, 1.0)));

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

@ -176,6 +176,16 @@ ContainerPrepare(ContainerT* aContainer,
continue;
}
RenderTargetRect quad = layerToRender->GetLayer()->
TransformRectToRenderTarget(LayerPixel::FromUntyped(
layerToRender->GetLayer()->GetEffectiveVisibleRegion().GetBounds()));
Compositor* compositor = aManager->GetCompositor();
if (!layerToRender->GetLayer()->AsContainerLayer() &&
!quad.Intersects(compositor->ClipRectInLayersCoordinates(layerToRender->GetLayer(), clipRect))) {
continue;
}
CULLING_LOG("Preparing sublayer %p\n", layerToRender->GetLayer());
nsIntRegion savedVisibleRegion;
@ -269,7 +279,7 @@ RenderLayers(ContainerT* aContainer,
gfx::Rect clipRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height);
compositor->DrawQuad(
RenderTargetPixel::ToUnknown(
compositor->ClipRectInLayersCoordinates(aClipRect)),
compositor->ClipRectInLayersCoordinates(aContainer, aClipRect)),
clipRect, effectChain, opacity, Matrix4x4());
}
}
@ -363,7 +373,6 @@ RenderIntermediate(ContainerT* aContainer,
if (!surface) {
return;
}
compositor->SetRenderTarget(surface);
// pre-render all of the layers into our temporary
RenderLayers(aContainer, aManager, RenderTargetPixel::FromUntyped(aClipRect));

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

@ -379,16 +379,16 @@ TiledContentHost::Composite(EffectChain& aEffectChain,
? gfxPrefs::LowPrecisionOpacity() : 1.0f;
nsIntRegion tmpRegion;
const nsIntRegion* renderRegion;
const nsIntRegion* renderRegion = aVisibleRegion;
#ifndef MOZ_GFX_OPTIMIZE_MOBILE
if (PaintWillResample()) {
// If we're resampling, then the texture image will contain exactly the
// entire visible region's bounds, and we should draw it all in one quad
// to avoid unexpected aliasing.
tmpRegion = aVisibleRegion->GetBounds();
renderRegion = &tmpRegion;
} else {
renderRegion = aVisibleRegion;
}
#endif
// Render the low and high precision buffers.
RenderLayerBuffer(mLowPrecisionTiledBuffer,
@ -435,8 +435,8 @@ TiledContentHost::RenderTile(const TileHost& aTile,
Rect layerQuad(screenBounds.x, screenBounds.y, screenBounds.width, screenBounds.height);
RenderTargetRect quad = RenderTargetRect::FromUnknown(aTransform.TransformBounds(layerQuad));
if (!quad.Intersects(mCompositor->ClipRectInLayersCoordinates(
RenderTargetIntRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height)))) {
if (!quad.Intersects(mCompositor->ClipRectInLayersCoordinates(mLayer,
RenderTargetIntRect(aClipRect.x, aClipRect.y, aClipRect.width, aClipRect.height)))) {
return;
}

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

@ -1113,23 +1113,25 @@ nsRect nsRegion::GetLargestRectangle (const nsRect& aContainingRect) const {
return bestRect;
}
std::ostream& operator<<(std::ostream& stream, const nsRegion& m) {
stream << "[";
int n;
pixman_box32_t *boxes = pixman_region32_rectangles(const_cast<pixman_region32_t*>(&m.mImpl), &n);
for (int i=0; i<n; i++) {
if (i != 0) {
stream << "; ";
}
stream << boxes[i].x1 << "," << boxes[i].y1 << "," << boxes[i].x2 << "," << boxes[i].y2;
}
stream << "]";
return stream;
}
nsCString
nsRegion::ToString() const {
nsCString result;
result.Append('[');
int n;
pixman_box32_t *boxes = pixman_region32_rectangles(const_cast<pixman_region32_t*>(&mImpl), &n);
for (int i=0; i<n; i++) {
if (i != 0) {
result.AppendLiteral("; ");
}
result.Append(nsPrintfCString("%d,%d,%d,%d", boxes[i].x1, boxes[i].y1, boxes[i].x2, boxes[i].y2));
}
result.Append(']');
return result;
return nsCString(mozilla::ToString(this).c_str());
}

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

@ -10,6 +10,7 @@
#include <stdint.h> // for uint32_t, uint64_t
#include <sys/types.h> // for int32_t
#include "gfxCore.h" // for NS_GFX
#include "mozilla/ToString.h" // for mozilla::ToString
#include "nsCoord.h" // for nscoord
#include "nsError.h" // for nsresult
#include "nsPoint.h" // for nsIntPoint, nsPoint
@ -68,6 +69,8 @@ public:
return IsEqual(aRgn);
}
friend std::ostream& operator<<(std::ostream& stream, const nsRegion& m);
void Swap(nsRegion* aOther)
{
pixman_region32_t tmp = mImpl;
@ -462,6 +465,10 @@ public:
return IsEqual(aRgn);
}
friend std::ostream& operator<<(std::ostream& stream, const nsIntRegion& m) {
return stream << m.mImpl;
}
void Swap(nsIntRegion* aOther)
{
mImpl.Swap(&aOther->mImpl);

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

@ -282,3 +282,5 @@
// moz-apperance style used in setting proper glass margins
#define NS_THEME_WIN_EXCLUDE_GLASS 242
#define NS_THEME_MAC_VIBRANCY_LIGHT 243
#define NS_THEME_MAC_VIBRANCY_DARK 244

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

@ -36,6 +36,27 @@ public:
*/
gfx3DMatrix(void);
friend std::ostream& operator<<(std::ostream& stream, const gfx3DMatrix& m) {
if (m.IsIdentity()) {
return stream << "[ I ]";
}
if (m.Is2D()) {
return stream << "["
<< m._11 << " " << m._12 << "; "
<< m._21 << " " << m._22 << "; "
<< m._41 << " " << m._42
<< "]";
}
return stream << "["
<< m._11 << " " << m._12 << " " << m._13 << " " << m._14 << "; "
<< m._21 << " " << m._22 << " " << m._23 << " " << m._24 << "; "
<< m._31 << " " << m._32 << " " << m._33 << " " << m._34 << "; "
<< m._41 << " " << m._42 << " " << m._43 << " " << m._44
<< "]";
}
/**
* Matrix multiplication.
*/

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

@ -50,6 +50,18 @@ public:
_21(c), _22(d),
_31(tx), _32(ty) { }
friend std::ostream& operator<<(std::ostream& stream, const gfxMatrix& m) {
if (m.IsIdentity()) {
return stream << "[identity]";
}
return stream << "["
<< m._11 << " " << m._12
<< m._21 << " " << m._22
<< m._31 << " " << m._32
<< "]";
}
/**
* Post-multiplies m onto the matrix.
*/

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

@ -36,8 +36,14 @@ if CONFIG['MOZ_SANDBOX'] and CONFIG['OS_ARCH'] == 'WINNT':
'/security/sandbox/chromium',
]
USE_LIBS += [
'sandbox_s',
'sandbox_staticruntime_s',
]
DELAYLOAD_DLLS += [
'mozalloc.dll',
'nss3.dll',
'xul.dll'
]
USE_STATIC_LIBS = True
if CONFIG['_MSC_VER']:
# Always enter a Windows program through wmain, whether or not we're
@ -57,7 +63,9 @@ LDFLAGS += [CONFIG['MOZ_ALLOW_HEAP_EXECUTE_FLAGS']]
if CONFIG['OS_ARCH'] == 'WINNT' and not CONFIG['GNU_CC']:
LDFLAGS += ['/HEAP:0x40000']
FAIL_ON_WARNINGS = True
# Windows builds have dll linkage warnings due to USE_STATIC_LIBS
if CONFIG['OS_ARCH'] != 'WINNT':
FAIL_ON_WARNINGS = True
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'gonk':
OS_LIBS += [

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

@ -42,7 +42,7 @@ typedef mozilla::ipc::SharedMemoryBasic::Handle CrossProcessMutexHandle;
typedef uintptr_t CrossProcessMutexHandle;
#endif
class NS_COM_GLUE CrossProcessMutex
class CrossProcessMutex
{
public:
/**

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

@ -6,6 +6,7 @@
#if defined(XP_WIN)
#include <windows.h>
#define XRE_DONT_SUPPORT_XPSP2 // this app doesn't ship
#include "nsWindowsWMain.cpp"
#endif

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

@ -45,13 +45,11 @@ WrapperOwner::idOf(JSObject *obj)
return objId;
}
int sCPOWProxyHandler;
class CPOWProxyHandler : public BaseProxyHandler
{
public:
CPOWProxyHandler()
: BaseProxyHandler(&sCPOWProxyHandler) {}
: BaseProxyHandler(&family) {}
virtual ~CPOWProxyHandler() {}
virtual bool finalizeInBackground(Value priv) const MOZ_OVERRIDE {
@ -86,9 +84,11 @@ class CPOWProxyHandler : public BaseProxyHandler
virtual const char* className(JSContext *cx, HandleObject proxy) const MOZ_OVERRIDE;
virtual void finalize(JSFreeOp *fop, JSObject *proxy) const MOZ_OVERRIDE;
static const char family;
static const CPOWProxyHandler singleton;
};
const char CPOWProxyHandler::family = 0;
const CPOWProxyHandler CPOWProxyHandler::singleton;
#define FORWARD(call, args) \

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

@ -601,7 +601,7 @@ JS_IsDeadWrapper(JSObject *obj)
return false;
}
return obj->as<ProxyObject>().handler()->family() == &DeadObjectProxy::sDeadObjectFamily;
return obj->as<ProxyObject>().handler()->family() == &DeadObjectProxy::family;
}
void

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

@ -797,6 +797,7 @@ class ScriptedIndirectProxyHandler : public BaseProxyHandler
virtual JSString *fun_toString(JSContext *cx, HandleObject proxy, unsigned indent) const MOZ_OVERRIDE;
virtual bool isScripted() const MOZ_OVERRIDE { return true; }
static const char family;
static const ScriptedIndirectProxyHandler singleton;
};
@ -818,10 +819,10 @@ static const Class CallConstructHolder = {
} /* anonymous namespace */
// This variable exists solely to provide a unique address for use as an identifier.
static const char sScriptedIndirectProxyHandlerFamily = 0;
const char ScriptedIndirectProxyHandler::family = 0;
ScriptedIndirectProxyHandler::ScriptedIndirectProxyHandler()
: BaseProxyHandler(&sScriptedIndirectProxyHandlerFamily)
: BaseProxyHandler(&family)
{
}
@ -1118,6 +1119,7 @@ class ScriptedDirectProxyHandler : public DirectProxyHandler {
virtual bool construct(JSContext *cx, HandleObject proxy, const CallArgs &args) const MOZ_OVERRIDE;
virtual bool isScripted() const MOZ_OVERRIDE { return true; }
static const char family;
static const ScriptedDirectProxyHandler singleton;
// The "proxy extra" slot index in which the handler is stored. Revocable proxies need to set
@ -1128,9 +1130,6 @@ class ScriptedDirectProxyHandler : public DirectProxyHandler {
static const int REVOKE_SLOT = 0;
};
// This variable exists solely to provide a unique address for use as an identifier.
static const char sScriptedDirectProxyHandlerFamily = 0;
static inline bool
IsDataDescriptor(const PropertyDescriptor &desc)
{
@ -1389,7 +1388,7 @@ ArrayToIdVector(JSContext *cx, HandleObject proxy, HandleObject target, HandleVa
}
ScriptedDirectProxyHandler::ScriptedDirectProxyHandler()
: DirectProxyHandler(&sScriptedDirectProxyHandlerFamily)
: DirectProxyHandler(&family)
{
}
@ -2208,6 +2207,7 @@ ScriptedDirectProxyHandler::construct(JSContext *cx, HandleObject proxy, const C
return true;
}
const char ScriptedDirectProxyHandler::family = 0;
const ScriptedDirectProxyHandler ScriptedDirectProxyHandler::singleton;
#define INVOKE_ON_PROTOTYPE(cx, handler, proxy, protoCall) \

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

@ -87,6 +87,14 @@ class JS_FRIEND_API(Wrapper);
*/
class JS_FRIEND_API(BaseProxyHandler)
{
/*
* Sometimes it's desirable to designate groups of proxy handlers as "similar".
* For this, we use the notion of a "family": A consumer-provided opaque pointer
* that designates the larger group to which this proxy belongs.
*
* If it will never be important to differentiate this proxy from others as
* part of a distinct group, nullptr may be used instead.
*/
const void *mFamily;
/*

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