Merge mozilla-central to tracemonkey.

This commit is contained in:
Robert Sayre 2010-04-02 10:10:27 -04:00
Родитель 0fb98b223d 72f3029722
Коммит 7d438a554a
290 изменённых файлов: 10845 добавлений и 8588 удалений

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

@ -1179,6 +1179,9 @@ nsDocAccessible::ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute)
if (!targetNode)
return;
// Note: For universal/global ARIA states and properties we don't care if
// there is an ARIA role present or not.
if (aAttribute == nsAccessibilityAtoms::aria_required) {
nsRefPtr<nsAccEvent> event =
new nsAccStateChangeEvent(targetNode,
@ -1209,6 +1212,24 @@ nsDocAccessible::ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute)
return;
}
// For aria drag and drop changes we fire a generic attribute change event;
// at least until native API comes up with a more meaningful event.
if (aAttribute == nsAccessibilityAtoms::aria_grabbed ||
aAttribute == nsAccessibilityAtoms::aria_dropeffect) {
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_OBJECT_ATTRIBUTE_CHANGED,
targetNode);
}
// We treat aria-expanded as a global ARIA state for historical reasons
if (aAttribute == nsAccessibilityAtoms::aria_expanded) {
nsRefPtr<nsAccEvent> event =
new nsAccStateChangeEvent(targetNode,
nsIAccessibleStates::STATE_EXPANDED,
PR_FALSE);
FireDelayedAccessibleEvent(event);
return;
}
if (!aContent->HasAttr(kNameSpaceID_None, nsAccessibilityAtoms::role)) {
// We don't care about these other ARIA attribute changes unless there is
// an ARIA role set for the element
@ -1249,15 +1270,6 @@ nsDocAccessible::ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute)
return;
}
if (aAttribute == nsAccessibilityAtoms::aria_expanded) {
nsRefPtr<nsAccEvent> event =
new nsAccStateChangeEvent(targetNode,
nsIAccessibleStates::STATE_EXPANDED,
PR_FALSE);
FireDelayedAccessibleEvent(event);
return;
}
if (aAttribute == nsAccessibilityAtoms::aria_readonly) {
nsRefPtr<nsAccEvent> event =
new nsAccStateChangeEvent(targetNode,
@ -1290,14 +1302,6 @@ nsDocAccessible::ARIAAttributeChanged(nsIContent* aContent, nsIAtom* aAttribute)
nsIAccessibilityService::NODE_SIGNIFICANT_CHANGE);
return;
}
// For aria drag and drop changes we fire a generic attribute change event;
// at least until native API comes up with a more meaningful event.
if (aAttribute == nsAccessibilityAtoms::aria_grabbed ||
aAttribute == nsAccessibilityAtoms::aria_dropeffect) {
FireDelayedAccessibleEvent(nsIAccessibleEvent::EVENT_OBJECT_ATTRIBUTE_CHANGED,
targetNode);
}
}
void nsDocAccessible::ContentAppended(nsIDocument *aDocument,

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

@ -48,6 +48,7 @@ include $(topsrcdir)/config/rules.mk
_TEST_FILES =\
focus.html \
scroll.html \
test_aria_statechange.html \
test_attrs.html \
test_caretmove.html \
$(warning test_coalescence.html temporarily disabled) \

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

@ -0,0 +1,85 @@
<html>
<head>
<title>ARIA state change event testing</title>
<link rel="stylesheet" type="text/css"
href="chrome://mochikit/content/tests/SimpleTest/test.css" />
<script type="application/javascript"
src="chrome://mochikit/content/MochiKit/packed.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/a11y/accessible/common.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/a11y/accessible/states.js"></script>
<script type="application/javascript"
src="chrome://mochikit/content/a11y/accessible/events.js"></script>
<script type="application/javascript">
/**
* Do tests.
*/
var gQueue = null;
function expandNode(aNodeOrID, bExpand)
{
this.DOMNode = getNode(aNodeOrID);
this.invoke = function expand_invoke() {
// Note: this should fire an EVENT_STATE_CHANGE
this.DOMNode.setAttribute("aria-expanded", bExpand);
};
this.check = function expand_check() {
testStates(aNodeOrID,
bExpand ? STATE_EXPANDED : STATE_COLLAPSED,
EXT_STATE_EXPANDABLE);
};
this.getID = function changeValue_getID() {
return prettyName(aNodeOrID) + " aria-expanded changed";
};
}
function doTests()
{
gQueue = new eventQueue(nsIAccessibleEvent.EVENT_STATE_CHANGE);
gQueue.push(new expandNode("section", true));
gQueue.push(new expandNode("section", false));
gQueue.push(new expandNode("div", true));
gQueue.push(new expandNode("div", false));
gQueue.invoke(); // Will call SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addA11yLoadEvent(doTests);
</script>
</head>
<body>
<a target="_blank"
href="https://bugzilla.mozilla.org/show_bug.cgi?id=551684"
title="No statechange event for aria-expanded on native HTML elements, is fired on ARIA widgets">
Mozilla Bug 551684
</a>
<p id="display"></p>
<div id="content" style="display: none"></div>
<pre id="test">
</pre>
<div id="eventdump"></div>
<!-- aria-expanded -->
<div id="section" role="section" aria-expanded="false">expandable section</div>
<div id="div" aria-expanded="false">expandable native div</div>
</body>
</html>

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

@ -844,9 +844,6 @@ pref("browser.zoom.siteSpecific", true);
// Whether or not to update background tabs to the current zoom level.
pref("browser.zoom.updateBackgroundTabs", true);
// replace newlines with spaces when pasting into <input type="text"> fields
pref("editor.singleLine.pasteNewlines", 2);
// The breakpad report server to link to in about:crashes
pref("breakpad.reportURL", "http://crash-stats.mozilla.com/report/index/");

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

@ -44,18 +44,26 @@
var tabPreviews = {
aspectRatio: 0.5625, // 16:9
init: function tabPreviews_init() {
if (this._selectedTab)
return;
this._selectedTab = gBrowser.selectedTab;
this.width = Math.ceil(screen.availWidth / 5.75);
this.height = Math.round(this.width * this.aspectRatio);
window.addEventListener("unload", this, false);
gBrowser.tabContainer.addEventListener("TabSelect", this, false);
gBrowser.tabContainer.addEventListener("SSTabRestored", this, false);
},
uninit: function tabPreviews_uninit() {
window.removeEventListener("unload", this, false);
gBrowser.tabContainer.removeEventListener("TabSelect", this, false);
gBrowser.tabContainer.removeEventListener("SSTabRestored", this, false);
this._selectedTab = null;
},
get: function tabPreviews_get(aTab) {
this.init();
if (aTab.__thumbnail_lastURI &&
aTab.__thumbnail_lastURI != aTab.linkedBrowser.currentURI.spec) {
aTab.__thumbnail = null;
@ -64,6 +72,8 @@ var tabPreviews = {
return aTab.__thumbnail || this.capture(aTab, !aTab.hasAttribute("busy"));
},
capture: function tabPreviews_capture(aTab, aStore) {
this.init();
var thumbnail = document.createElementNS("http://www.w3.org/1999/xhtml", "canvas");
thumbnail.mozOpaque = true;
thumbnail.height = this.height;
@ -105,6 +115,9 @@ var tabPreviews = {
case "SSTabRestored":
this.capture(event.target, true);
break;
case "unload":
this.uninit();
break;
}
}
};
@ -225,6 +238,8 @@ var ctrlTab = {
init: function ctrlTab_init() {
if (!this._recentlyUsedTabs) {
tabPreviews.init();
this._recentlyUsedTabs = [gBrowser.selectedTab];
this._init(true);
}
@ -577,6 +592,8 @@ var allTabs = {
return;
this._initiated = true;
tabPreviews.init();
Array.forEach(gBrowser.tabs, function (tab) {
this._addPreview(tab);
}, this);

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

@ -1307,7 +1307,6 @@ function delayedStartup(isLoadingBlank, mustLoadSidebar) {
// themselves.
gBrowser.addEventListener("command", BrowserOnCommand, false);
tabPreviews.init();
ctrlTab.readPref();
gPrefService.addObserver(ctrlTab.prefName, ctrlTab, false);
gPrefService.addObserver(allTabs.prefName, allTabs, false);
@ -1373,7 +1372,6 @@ function BrowserShutdown()
gPrefService.removeObserver(ctrlTab.prefName, ctrlTab);
gPrefService.removeObserver(allTabs.prefName, allTabs);
tabPreviews.uninit();
ctrlTab.uninit();
allTabs.uninit();
@ -7341,6 +7339,10 @@ let gPrivateBrowsingUI = {
}
}
if (gURLBar) {
gURLBar.editor.transactionManager.clear();
}
document.getElementById("menu_import").removeAttribute("disabled");
// Re-enable the Clear Recent History... menu item on exit of PB mode

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

@ -100,10 +100,6 @@ function nsContextMenu(aXulMenu, aBrowser) {
// Prototype for nsContextMenu "class."
nsContextMenu.prototype = {
// onDestroy is a no-op at this point.
onDestroy: function () {
},
// Initialize context menu.
initMenu: function CM_initMenu(aPopup, aBrowser) {
this.menu = aPopup;

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

@ -1,8 +1,6 @@
function test() {
var contentWin = window.open("about:blank", "", "width=100,height=100");
var enumerator = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator)
.getEnumerator("navigator:browser");
var enumerator = Services.wm.getEnumerator("navigator:browser");
while (enumerator.hasMoreElements()) {
let win = enumerator.getNext();

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

@ -100,8 +100,6 @@ function test() {
var gBMFolder = null;
var gAddedEngines = [];
function setupKeywords() {
var searchService = Cc["@mozilla.org/browser/search-service;1"].
getService(Ci.nsIBrowserSearchService);
gBMFolder = Application.bookmarks.menu.addFolder("keyword-test");
for each (var item in testData) {
var data = item[0];
@ -113,8 +111,8 @@ function setupKeywords() {
}
if (data instanceof searchKeywordData) {
searchService.addEngineWithDetails(data.keyword, "", data.keyword, "", data.method, data.uri.spec);
var addedEngine = searchService.getEngineByName(data.keyword);
Services.search.addEngineWithDetails(data.keyword, "", data.keyword, "", data.method, data.uri.spec);
var addedEngine = Services.search.getEngineByName(data.keyword);
if (data.postData) {
var [paramName, paramValue] = data.postData.split("=");
addedEngine.addParam(paramName, paramValue, null);
@ -126,8 +124,6 @@ function setupKeywords() {
}
function cleanupKeywords() {
var searchService = Cc["@mozilla.org/browser/search-service;1"].
getService(Ci.nsIBrowserSearchService);
gBMFolder.remove();
gAddedEngines.map(searchService.removeEngine);
gAddedEngines.map(Services.search.removeEngine);
}

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

@ -1,5 +1,3 @@
var obs = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
function test() {
waitForExplicitFinish();
@ -8,7 +6,7 @@ function test() {
gBrowser.selectedBrowser.addEventListener("load", function () {
gBrowser.selectedBrowser.removeEventListener("load", arguments.callee, true);
pageInfo = BrowserPageInfo();
obs.addObserver(observer, "page-info-dialog-loaded", false);
Services.obs.addObserver(observer, "page-info-dialog-loaded", false);
}, true);
content.location =
"https://example.com/browser/browser/base/content/test/feed_tab.html";
@ -29,7 +27,7 @@ function test() {
break;
case 2:
atTest++;
obs.removeObserver(observer, "page-info-dialog-loaded");
Services.obs.removeObserver(observer, "page-info-dialog-loaded");
testLockDoubleClick();
break;
}
@ -76,9 +74,7 @@ function test() {
}
function testLockDoubleClick() {
var pageInfoDialogs = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator)
.getEnumerator("Browser:page-info");
var pageInfoDialogs = Services.wm.getEnumerator("Browser:page-info");
var i = 0;
while (pageInfoDialogs.hasMoreElements()) {
i++;

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

@ -4,8 +4,7 @@ var gTestBrowser = null;
var gNextTest = null;
function get_test_plugin() {
var ph = Components.classes["@mozilla.org/plugin/host;1"]
.getService(Components.interfaces.nsIPluginHost);
var ph = Cc["@mozilla.org/plugin/host;1"].getService(Ci.nsIPluginHost);
var tags = ph.getPluginTags();
// Find the test plugin
@ -23,9 +22,7 @@ function WindowOpenListener(url, opencallback, closecallback) {
this.opencallback = opencallback;
this.closecallback = closecallback;
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
.getService(Components.interfaces.nsIWindowMediator);
wm.addListener(this);
Services.wm.addListener(this);
}
WindowOpenListener.prototype = {
@ -61,9 +58,7 @@ WindowOpenListener.prototype = {
if (this.window != window)
return;
var wm = Components.classes["@mozilla.org/appshell/window-mediator;1"]
.getService(Components.interfaces.nsIWindowMediator);
wm.removeListener(this);
Services.wm.removeListener(this);
this.opencallback = null;
this.window = null;
this.domwindow = null;

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

@ -71,13 +71,11 @@ function test()
let history = doc.getElementById("history-checkbox");
// Add download to DB
let ios = Cc["@mozilla.org/network/io-service;1"].
getService(Ci.nsIIOService);
let file = Cc["@mozilla.org/file/directory_service;1"].
getService(Ci.nsIProperties).get("TmpD", Ci.nsIFile);
file.append("satitize-dm-test.file");
file.createUnique(Ci.nsIFile.NORMAL_FILE_TYPE, 0666);
let testPath = ios.newFileURI(file).spec;
let testPath = Services.io.newFileURI(file).spec;
let data = {
name: "381603.patch",
source: "https://bugzilla.mozilla.org/attachment.cgi?id=266520",
@ -142,22 +140,20 @@ function test()
db.executeSimpleSQL("DELETE FROM moz_downloads");
// Close the UI if necessary
let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
getService(Ci.nsIWindowWatcher);
let win = ww.getWindowByName("Sanatize", null);
let win = Services.ww.getWindowByName("Sanatize", null);
if (win && (win instanceof Ci.nsIDOMWindowInternal))
win.close();
// Start the test when the sanitize window loads
ww.registerNotification(function (aSubject, aTopic, aData) {
ww.unregisterNotification(arguments.callee);
Services.ww.registerNotification(function (aSubject, aTopic, aData) {
Services.ww.unregisterNotification(arguments.callee);
aSubject.QueryInterface(Ci.nsIDOMEventTarget)
.addEventListener("DOMContentLoaded", doTest, false);
});
// Let the methods that run onload finish before we test
let doTest = function() setTimeout(function() {
let win = ww.getWindowByName("Sanitize", null)
let win = Services.ww.getWindowByName("Sanitize", null)
.QueryInterface(Ci.nsIDOMWindowInternal);
for (let i = 0; i < tests.length; i++)
@ -168,11 +164,11 @@ function test()
}, 0);
// Show the UI
ww.openWindow(window,
"chrome://browser/content/sanitize.xul",
"Sanitize",
"chrome,titlebar,centerscreen",
null);
Services.ww.openWindow(window,
"chrome://browser/content/sanitize.xul",
"Sanitize",
"chrome,titlebar,centerscreen",
null);
waitForExplicitFinish();
}

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

@ -51,15 +51,13 @@
*/
Cc["@mozilla.org/moz/jssubscript-loader;1"].
getService(Components.interfaces.mozIJSSubScriptLoader).
getService(Ci.mozIJSSubScriptLoader).
loadSubScript("chrome://mochikit/content/MochiKit/packed.js");
Cc["@mozilla.org/moz/jssubscript-loader;1"].
getService(Components.interfaces.mozIJSSubScriptLoader).
getService(Ci.mozIJSSubScriptLoader).
loadSubScript("chrome://browser/content/sanitize.js");
const winWatch = Cc["@mozilla.org/embedcomp/window-watcher;1"].
getService(Ci.nsIWindowWatcher);
const dm = Cc["@mozilla.org/download-manager;1"].
getService(Ci.nsIDownloadManager);
const bhist = Cc["@mozilla.org/browser/global-history;2"].
@ -540,7 +538,7 @@ WindowHelper.prototype = {
if (aTopic != "domwindowopened")
return;
winWatch.unregisterNotification(windowObserver);
Services.ww.unregisterNotification(windowObserver);
var loaded = false;
let win = aSubject.QueryInterface(Ci.nsIDOMWindow);
@ -597,12 +595,12 @@ WindowHelper.prototype = {
});
}, false);
}
winWatch.registerNotification(windowObserver);
winWatch.openWindow(null,
"chrome://browser/content/sanitize.xul",
"SanitizeDialog",
"chrome,titlebar,dialog,centerscreen,modal",
null);
Services.ww.registerNotification(windowObserver);
Services.ww.openWindow(null,
"chrome://browser/content/sanitize.xul",
"SanitizeDialog",
"chrome,titlebar,dialog,centerscreen,modal",
null);
},
/**

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

@ -50,15 +50,13 @@
*/
Cc["@mozilla.org/moz/jssubscript-loader;1"].
getService(Components.interfaces.mozIJSSubScriptLoader).
getService(Ci.mozIJSSubScriptLoader).
loadSubScript("chrome://mochikit/content/MochiKit/packed.js");
Cc["@mozilla.org/moz/jssubscript-loader;1"].
getService(Components.interfaces.mozIJSSubScriptLoader).
getService(Ci.mozIJSSubScriptLoader).
loadSubScript("chrome://browser/content/sanitize.js");
const winWatch = Cc["@mozilla.org/embedcomp/window-watcher;1"].
getService(Ci.nsIWindowWatcher);
const dm = Cc["@mozilla.org/download-manager;1"].
getService(Ci.nsIDownloadManager);
const bhist = Cc["@mozilla.org/browser/global-history;2"].
@ -622,7 +620,7 @@ function openWindow(aOnloadCallback) {
if (aTopic != "domwindowopened")
return;
winWatch.unregisterNotification(windowObserver);
Services.ww.unregisterNotification(windowObserver);
let win = aSubject.QueryInterface(Ci.nsIDOMWindow);
win.addEventListener("load", function onload(event) {
win.removeEventListener("load", onload, false);
@ -641,12 +639,12 @@ function openWindow(aOnloadCallback) {
});
}, false);
}
winWatch.registerNotification(windowObserver);
winWatch.openWindow(null,
"chrome://browser/content/sanitize.xul",
"Sanitize",
"chrome,titlebar,dialog,centerscreen,modal",
null);
Services.ww.registerNotification(windowObserver);
Services.ww.openWindow(null,
"chrome://browser/content/sanitize.xul",
"Sanitize",
"chrome,titlebar,dialog,centerscreen,modal",
null);
}
///////////////////////////////////////////////////////////////////////////////

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

@ -37,48 +37,24 @@
*
* ***** END LICENSE BLOCK ***** */
version(170);
const Ci = Components.interfaces;
const Cc = Components.classes;
const Cr = Components.results;
const Cu = Components.utils;
const NS_APP_USER_PROFILE_50_DIR = "ProfD";
const NS_APP_PROFILE_DIR_STARTUP = "ProfDS";
const NS_APP_BOOKMARKS_50_FILE = "BMarks";
Cu.import("resource://gre/modules/Services.jsm");
var Ci = Components.interfaces;
var Cc = Components.classes;
var Cr = Components.results;
function LOG(aMsg) {
aMsg = ("*** PLACES TESTS: " + aMsg);
Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService).
logStringMessage(aMsg);
print(aMsg);
// Import common head.
let (commonFile = do_get_file("../../test_places/head_common.js", false)) {
let uri = Services.io.newFileURI(commonFile);
Services.scriptloader.loadSubScript(uri.spec, this);
}
var gProfD = do_get_profile();
var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
getService(Ci.nsIProperties);
// Put any other stuff relative to this test folder below.
var dirProvider = {
getFile: function(prop, persistent) {
persistent.value = true;
if (prop == NS_APP_BOOKMARKS_50_FILE) {
var bmarks = gProfD.clone();
bmarks.append("bookmarks.html");
return bmarks;
}
return null;
},
QueryInterface: function(iid) {
if (iid.equals(Ci.nsIDirectoryServiceProvider) ||
iid.equals(Ci.nsISupports)) {
return this;
}
throw Cr.NS_ERROR_NO_INTERFACE;
}
};
dirSvc.QueryInterface(Ci.nsIDirectoryService).registerProvider(dirProvider);
var XULAppInfo = {
// Needed by some test that relies on having an app registered.
let (XULAppInfo = {
vendor: "Mozilla",
name: "PlacesTest",
ID: "{230de50e-4cd1-11dc-8314-0800200c9a66}",
@ -91,80 +67,29 @@ var XULAppInfo = {
OS: "XPCShell",
XPCOMABI: "noarch-spidermonkey",
QueryInterface: function QueryInterface(iid) {
if (iid.equals(Ci.nsIXULAppInfo) ||
iid.equals(Ci.nsIXULRuntime) ||
iid.equals(Ci.nsISupports))
return this;
throw Cr.NS_ERROR_NO_INTERFACE;
}
};
var XULAppInfoFactory = {
createInstance: function (outer, iid) {
if (outer != null)
throw Cr.NS_ERROR_NO_AGGREGATION;
return XULAppInfo.QueryInterface(iid);
}
};
var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
registrar.registerFactory(Components.ID("{fbfae60b-64a4-44ef-a911-08ceb70b9f31}"),
"XULAppInfo", "@mozilla.org/xre/app-info;1",
XULAppInfoFactory);
var iosvc = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
function uri(spec) {
return iosvc.newURI(spec, null, null);
QueryInterface: XPCOMUtils.generateQI([
Ci.nsIXULAppInfo,
Ci.nsIXULRuntime,
])
}) {
let XULAppInfoFactory = {
createInstance: function (outer, iid) {
if (outer != null)
throw Cr.NS_ERROR_NO_AGGREGATION;
return XULAppInfo.QueryInterface(iid);
}
};
let registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
registrar.registerFactory(Components.ID("{fbfae60b-64a4-44ef-a911-08ceb70b9f31}"),
"XULAppInfo", "@mozilla.org/xre/app-info;1",
XULAppInfoFactory);
}
/*
* Removes all bookmarks and checks for correct cleanup
*/
function remove_all_bookmarks() {
var bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
getService(Ci.nsINavBookmarksService);
// Clear all bookmarks.
bs.removeFolderChildren(bs.bookmarksMenuFolder);
bs.removeFolderChildren(bs.toolbarFolder);
bs.removeFolderChildren(bs.unfiledBookmarksFolder);
// Check for correct cleanup.
dump_table("moz_bookmarks");
dump_table("moz_places");
check_no_bookmarks()
}
/*
* Checks that we don't have any bookmark
*/
function check_no_bookmarks() {
var hs = Cc["@mozilla.org/browser/nav-history-service;1"].
getService(Ci.nsINavHistoryService);
var bs = Cc["@mozilla.org/browser/nav-bookmarks-service;1"].
getService(Ci.nsINavBookmarksService);
var query = hs.getNewQuery();
query.setFolders([bs.toolbarFolder, bs.bookmarksMenuFolder, bs.unfiledBookmarksFolder], 3);
var options = hs.getNewQueryOptions();
options.queryType = Ci.nsINavHistoryQueryOptions.QUERY_TYPE_BOOKMARKS;
var result = hs.executeQuery(query, options);
var root = result.root;
root.containerOpen = true;
var cc = root.childCount;
// Dump contents if found.
for (var i = 0; i < cc ; i++) {
var node = root.getChild(i);
print("Found unexpected child at " + i + ": " + node.title);
}
do_check_eq(cc, 0);
root.containerOpen = false;
}
let gTestDir = do_get_cwd();
const FILENAME_BOOKMARKS_HTML = "bookmarks.html";
let backup_date = new Date().toLocaleFormat("%Y-%m-%d");
const FILENAME_BOOKMARKS_JSON = "bookmarks-" + backup_date + ".json";
let (backup_date = new Date().toLocaleFormat("%Y-%m-%d")) {
const FILENAME_BOOKMARKS_JSON = "bookmarks-" + backup_date + ".json";
}
// Smart bookmarks constants.
const SMART_BOOKMARKS_VERSION = 2;
@ -174,179 +99,3 @@ const SMART_BOOKMARKS_ON_MENU = 3; // Takes in count the additional separator.
// Default bookmarks constants.
const DEFAULT_BOOKMARKS_ON_TOOLBAR = 2;
const DEFAULT_BOOKMARKS_ON_MENU = 3;
/**
* Creates a bookmarks.html file in the profile folder from a given source file.
*
* @param aFilename
* Name of the file to copy to the profile folder. This file must
* exist in the directory that contains the test files.
*
* @return nsIFile object for the file.
*/
function create_bookmarks_html(aFilename) {
if (!aFilename)
do_throw("you must pass a filename to create_bookmarks_html function");
remove_bookmarks_html();
let bookmarksHTMLFile = gTestDir.clone();
bookmarksHTMLFile.append(aFilename);
do_check_true(bookmarksHTMLFile.exists());
bookmarksHTMLFile.copyTo(gProfD, FILENAME_BOOKMARKS_HTML);
let profileBookmarksHTMLFile = gProfD.clone();
profileBookmarksHTMLFile.append(FILENAME_BOOKMARKS_HTML);
do_check_true(profileBookmarksHTMLFile.exists());
return profileBookmarksHTMLFile;
}
/**
* Remove bookmarks.html file from the profile folder.
*/
function remove_bookmarks_html() {
let profileBookmarksHTMLFile = gProfD.clone();
profileBookmarksHTMLFile.append(FILENAME_BOOKMARKS_HTML);
if (profileBookmarksHTMLFile.exists()) {
profileBookmarksHTMLFile.remove(false);
do_check_false(profileBookmarksHTMLFile.exists());
}
}
/**
* Check bookmarks.html file exists in the profile folder.
*
* @return nsIFile object for the file.
*/
function check_bookmarks_html() {
let profileBookmarksHTMLFile = gProfD.clone();
profileBookmarksHTMLFile.append(FILENAME_BOOKMARKS_HTML);
do_check_true(profileBookmarksHTMLFile.exists());
return profileBookmarksHTMLFile;
}
/**
* Creates a JSON backup in the profile folder folder from a given source file.
*
* @param aFilename
* Name of the file to copy to the profile folder. This file must
* exist in the directory that contains the test files.
*
* @return nsIFile object for the file.
*/
function create_JSON_backup(aFilename) {
if (!aFilename)
do_throw("you must pass a filename to create_JSON_backup function");
remove_all_JSON_backups();
let bookmarksBackupDir = gProfD.clone();
bookmarksBackupDir.append("bookmarkbackups");
if (!bookmarksBackupDir.exists()) {
bookmarksBackupDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0777);
do_check_true(bookmarksBackupDir.exists());
}
let bookmarksJSONFile = gTestDir.clone();
bookmarksJSONFile.append(aFilename);
do_check_true(bookmarksJSONFile.exists());
bookmarksJSONFile.copyTo(bookmarksBackupDir, FILENAME_BOOKMARKS_JSON);
let profileBookmarksJSONFile = bookmarksBackupDir.clone();
profileBookmarksJSONFile.append(FILENAME_BOOKMARKS_JSON);
do_check_true(profileBookmarksJSONFile.exists());
return profileBookmarksJSONFile;
}
/**
* Remove bookmarksbackup dir and all backups from the profile folder.
*/
function remove_all_JSON_backups() {
let bookmarksBackupDir = gProfD.clone();
bookmarksBackupDir.append("bookmarkbackups");
if (bookmarksBackupDir.exists()) {
bookmarksBackupDir.remove(true);
do_check_false(bookmarksBackupDir.exists());
}
}
/**
* Check a JSON backup file for today exists in the profile folder.
*
* @return nsIFile object for the file.
*/
function check_JSON_backup() {
let profileBookmarksJSONFile = gProfD.clone();
profileBookmarksJSONFile.append("bookmarkbackups");
profileBookmarksJSONFile.append(FILENAME_BOOKMARKS_JSON);
do_check_true(profileBookmarksJSONFile.exists());
return profileBookmarksJSONFile;
}
/**
* Dumps the rows of a table out to the console.
*
* @param aName
* The name of the table or view to output.
*/
function dump_table(aName)
{
let db = Cc["@mozilla.org/browser/nav-history-service;1"].
getService(Ci.nsPIPlacesDatabase).
DBConnection;
let stmt = db.createStatement("SELECT * FROM " + aName);
dump("\n*** Printing data from " + aName + ":\n");
let count = 0;
while (stmt.executeStep()) {
let columns = stmt.numEntries;
if (count == 0) {
// print the column names
for (let i = 0; i < columns; i++)
dump(stmt.getColumnName(i) + "\t");
dump("\n");
}
// print the row
for (let i = 0; i < columns; i++) {
switch (stmt.getTypeOfIndex(i)) {
case Ci.mozIStorageValueArray.VALUE_TYPE_NULL:
dump("NULL\t");
break;
case Ci.mozIStorageValueArray.VALUE_TYPE_INTEGER:
dump(stmt.getInt64(i) + "\t");
break;
case Ci.mozIStorageValueArray.VALUE_TYPE_FLOAT:
dump(stmt.getDouble(i) + "\t");
break;
case Ci.mozIStorageValueArray.VALUE_TYPE_TEXT:
dump(stmt.getString(i) + "\t");
break;
}
}
dump("\n");
count++;
}
dump("*** There were a total of " + count + " rows of data.\n\n");
stmt.reset();
stmt.finalize();
stmt = null;
}
/**
* Flushes any events in the event loop of the main thread.
*/
function flush_main_thread_events()
{
let tm = Cc["@mozilla.org/thread-manager;1"].getService(Ci.nsIThreadManager);
while (tm.mainThread.hasPendingEvents())
tm.mainThread.processNextEvent(false);
}
// These tests are known to randomly fail due to bug 507790 when database
// flushes are active, so we turn off syncing for them.
let randomFailingSyncTests = [
"test_browserGlue_smartBookmarks.js",
];
let currentTestFilename = do_get_file(_TEST_FILE[0], true).leafName;
if (randomFailingSyncTests.indexOf(currentTestFilename) != -1) {
print("Test " + currentTestFilename + " is known random due to bug 507790, disabling PlacesDBFlush component.");
let sync = Cc["@mozilla.org/places/sync;1"].getService(Ci.nsIObserver);
sync.observe(null, "places-debug-stop-sync", null);
}

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

@ -73,7 +73,7 @@ function run_test() {
//var bookmarksFileOld = do_get_file("bookmarks.large.html");
var bookmarksFileOld = do_get_file("bookmarks.preplaces.html");
// file pointer to a new places-exported json file
var jsonFile = dirSvc.get("ProfD", Ci.nsILocalFile);
var jsonFile = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
jsonFile.append("bookmarks.exported.json");
// create bookmarks.exported.json

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

@ -90,7 +90,7 @@ function run_test() {
stmt.finalize();
// Export bookmarks
var bookmarksFile = dirSvc.get("ProfD", Ci.nsILocalFile);
var bookmarksFile = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
bookmarksFile.append("bookmarks.exported.html");
if (bookmarksFile.exists())
bookmarksFile.remove(false);

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

@ -115,7 +115,7 @@ var tests = [
data: NSIOBSERVER_DATA_JSON,
folderId: null,
run: function () {
this.file = dirSvc.get("ProfD", Ci.nsILocalFile);
this.file = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
this.file.append("this file doesn't exist because nobody created it");
try {
PlacesUtils.restoreBookmarksFromJSONFile(this.file);
@ -169,7 +169,7 @@ var tests = [
data: NSIOBSERVER_DATA_HTML,
folderId: null,
run: function () {
this.file = dirSvc.get("ProfD", Ci.nsILocalFile);
this.file = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
this.file.append("this file doesn't exist because nobody created it");
try {
importer.importHTMLFromFile(this.file, false);
@ -223,7 +223,7 @@ var tests = [
data: NSIOBSERVER_DATA_HTML_INIT,
folderId: null,
run: function () {
this.file = dirSvc.get("ProfD", Ci.nsILocalFile);
this.file = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
this.file.append("this file doesn't exist because nobody created it");
try {
importer.importHTMLFromFile(this.file, true);
@ -284,7 +284,7 @@ var tests = [
finalTopic: NSIOBSERVER_TOPIC_FAILED,
data: NSIOBSERVER_DATA_HTML,
run: function () {
this.file = dirSvc.get("ProfD", Ci.nsILocalFile);
this.file = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
this.file.append("this file doesn't exist because nobody created it");
this.folderId = bmsvc.createFolder(bmsvc.unfiledBookmarksFolder,
"test folder",
@ -407,7 +407,7 @@ function checkBookmarksExist() {
* @return The nsILocalFile
*/
function createFile(aBasename) {
var file = dirSvc.get("ProfD", Ci.nsILocalFile);
var file = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
file.append(aBasename);
if (file.exists())
file.remove(false);

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

@ -104,7 +104,7 @@ function run_test() {
// file pointer to legacy bookmarks file
var bookmarksFileOld = do_get_file("bookmarks.preplaces.html");
// file pointer to a new places-exported bookmarks file
var bookmarksFileNew = dirSvc.get("ProfD", Ci.nsILocalFile);
var bookmarksFileNew = Services.dirsvc.get("ProfD", Ci.nsILocalFile);
bookmarksFileNew.append("bookmarks.exported.html");
// create bookmarks.exported.html

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

@ -47,14 +47,13 @@ const PREF_BMPROCESSED = "distribution.516444.bookmarksProcessed";
const PREF_DISTRIBUTION_ID = "distribution.id";
const TOPIC_FINAL_UI_STARTUP = "final-ui-startup";
const TOPIC_PLACES_INIT_COMPLETE = "places-init-complete";
const TOPIC_CUSTOMIZATION_COMPLETE = "distribution-customization-complete";
function run_test() {
do_test_pending();
// Copy distribution.ini file to our app dir.
let distroDir = dirSvc.get("XCurProcD", Ci.nsIFile);
let distroDir = Services.dirsvc.get("XCurProcD", Ci.nsIFile);
distroDir.append("distribution");
let iniFile = distroDir.clone();
iniFile.append("distribution.ini");
@ -97,13 +96,13 @@ function run_test() {
TOPIC_FINAL_UI_STARTUP,
null);
// Test will continue on customization complete notification.
let observer = {
let cObserver = {
observe: function(aSubject, aTopic, aData) {
os.removeObserver(this, TOPIC_CUSTOMIZATION_COMPLETE);
continue_test();
do_execute_soon(continue_test);
}
}
os.addObserver(observer, TOPIC_CUSTOMIZATION_COMPLETE, false);
os.addObserver(cObserver, TOPIC_CUSTOMIZATION_COMPLETE, false);
}
}
os.addObserver(observer, TOPIC_PLACES_INIT_COMPLETE, false);
@ -145,7 +144,7 @@ function continue_test() {
do_register_cleanup(function() {
// Remove the distribution file, even if the test failed, otherwise all
// next tests will import it.
let iniFile = dirSvc.get("XCurProcD", Ci.nsIFile);
let iniFile = Services.dirsvc.get("XCurProcD", Ci.nsIFile);
iniFile.append("distribution");
iniFile.append("distribution.ini");
iniFile.remove(false);

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

@ -63,8 +63,7 @@ const PREF_IMPORT_BOOKMARKS_HTML = "browser.places.importBookmarksHTML";
const PREF_RESTORE_DEFAULT_BOOKMARKS = "browser.bookmarks.restore_default_bookmarks";
const PREF_SMART_BOOKMARKS_VERSION = "browser.places.smartBookmarksVersion";
const PREF_AUTO_EXPORT_HTML = "browser.bookmarks.autoExportHTML";
const TOPIC_PLACES_INIT_COMPLETE = "places-init-complete";
const TOPIC_PLACES_DATABASE_LOCKED = "places-database-locked";
let tests = [];
//------------------------------------------------------------------------------

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

@ -16,17 +16,14 @@ function test() {
getService(Ci.nsIHandlerService);
hserv.store(info);
var obs = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
function observer(win, topic, data) {
if (topic != "app-handler-pane-loaded")
return;
obs.removeObserver(observer, "app-handler-pane-loaded");
Services.obs.removeObserver(observer, "app-handler-pane-loaded");
runTest(win);
}
obs.addObserver(observer, "app-handler-pane-loaded", false);
Services.obs.addObserver(observer, "app-handler-pane-loaded", false);
openDialog("chrome://browser/content/preferences/preferences.xul", "Preferences",
"chrome,titlebar,toolbar,centerscreen,dialog=no", "paneApplications");

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

@ -36,28 +36,26 @@
* ***** END LICENSE BLOCK ***** */
function runTestOnPrivacyPrefPane(testFunc) {
let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
getService(Ci.nsIWindowWatcher);
let observer = {
observe: function(aSubject, aTopic, aData) {
if (aTopic == "domwindowopened") {
ww.unregisterNotification(this);
Services.ww.unregisterNotification(this);
let win = aSubject.QueryInterface(Ci.nsIDOMEventTarget);
win.addEventListener("load", function() {
win.removeEventListener("load", arguments.callee, false);
testFunc(dialog.document.defaultView);
ww.registerNotification(observer);
Services.ww.registerNotification(observer);
dialog.close();
}, false);
} else if (aTopic == "domwindowclosed") {
ww.unregisterNotification(this);
Services.ww.unregisterNotification(this);
testRunner.runNext();
}
}
};
ww.registerNotification(observer);
Services.ww.registerNotification(observer);
let dialog = openDialog("chrome://browser/content/preferences/preferences.xul", "Preferences",
"chrome,titlebar,toolbar,centerscreen,dialog=no", "panePrivacy");
@ -528,10 +526,8 @@ function reset_preferences(win) {
let testRunner;
function run_test_subset(subset) {
let psvc = Cc["@mozilla.org/preferences-service;1"].
getService(Ci.nsIPrefBranch);
let instantApplyOrig = psvc.getBoolPref("browser.preferences.instantApply");
psvc.setBoolPref("browser.preferences.instantApply", true);
let instantApplyOrig = Services.prefs.getBoolPref("browser.preferences.instantApply");
Services.prefs.setBoolPref("browser.preferences.instantApply", true);
waitForExplicitFinish();
@ -541,7 +537,7 @@ function run_test_subset(subset) {
runNext: function() {
if (this.counter == this.tests.length) {
// cleanup
psvc.setBoolPref("browser.preferences.instantApply", instantApplyOrig);
Services.prefs.setBoolPref("browser.preferences.instantApply", instantApplyOrig);
finish();
} else {
let self = this;

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

@ -72,6 +72,7 @@ _BROWSER_TEST_FILES = \
browser_privatebrowsing_transition.js \
browser_privatebrowsing_ui.js \
browser_privatebrowsing_urlbarfocus.js \
browser_privatebrowsing_urlbarundo.js \
browser_privatebrowsing_viewsource.js \
browser_privatebrowsing_windowtitle.js \
browser_privatebrowsing_windowtitle_page.html \

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

@ -57,9 +57,7 @@ function test() {
dialogWin.document.documentElement.getButton("cancel").click();
}
Cc["@mozilla.org/observer-service;1"]
.getService(Ci.nsIObserverService)
.addObserver(promptObserver, "common-dialog-loaded", false);
Services.obs.addObserver(promptObserver, "common-dialog-loaded", false);
waitForExplicitFinish();
let browser1 = gBrowser.getBrowserForTab(gBrowser.addTab());
@ -150,9 +148,7 @@ function test() {
gBrowser.removeTab(gBrowser.tabContainer.lastChild);
gBrowser.removeTab(gBrowser.tabContainer.lastChild);
Cc["@mozilla.org/observer-service;1"]
.getService(Ci.nsIObserverService)
.removeObserver(promptObserver, "common-dialog-loaded", false);
Services.obs.removeObserver(promptObserver, "common-dialog-loaded", false);
finish();
}
for (let i = 0; i < gBrowser.browsers.length; ++i)

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

@ -63,10 +63,8 @@ function test() {
prefetchCert: true,
};
function testCheckbox() {
let obsSvc = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
obsSvc.addObserver(function (aSubject, aTopic, aData) {
obsSvc.removeObserver(arguments.callee, "cert-exception-ui-ready", false);
Services.obs.addObserver(function (aSubject, aTopic, aData) {
Services.obs.removeObserver(arguments.callee, "cert-exception-ui-ready", false);
ok(win.gCert, "The certificate information should be available now");
let checkbox = win.document.getElementById("permanent");
@ -90,10 +88,8 @@ function test() {
prefetchCert: true,
};
function testCheckbox() {
let obsSvc = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
obsSvc.addObserver(function (aSubject, aTopic, aData) {
obsSvc.removeObserver(arguments.callee, "cert-exception-ui-ready", false);
Services.obs.addObserver(function (aSubject, aTopic, aData) {
Services.obs.removeObserver(arguments.callee, "cert-exception-ui-ready", false);
ok(win.gCert, "The certificate information should be available now");
let checkbox = win.document.getElementById("permanent");

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

@ -42,8 +42,6 @@ function test() {
// initialization
let pb = Cc["@mozilla.org/privatebrowsing;1"].
getService(Ci.nsIPrivateBrowsingService);
let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
getService(Ci.nsIWindowWatcher);
waitForExplicitFinish();
@ -120,7 +118,7 @@ function test() {
function observer(aSubject, aTopic, aData) {
isnot(aTopic, "domwindowopened", "The -private-toggle argument should be silent");
}
ww.registerNotification(observer);
Services.ww.registerNotification(observer);
let tab = gBrowser.selectedTab;
let browser = gBrowser.getBrowserForTab(tab);
@ -149,7 +147,7 @@ function test() {
let newTab = gBrowser.addTab();
gBrowser.removeTab(tab);
ww.unregisterNotification(observer);
Services.ww.unregisterNotification(observer);
finish();
}, true);
}, true);

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

@ -42,8 +42,6 @@ function test() {
// initialization
let pb = Cc["@mozilla.org/privatebrowsing;1"].
getService(Ci.nsIPrivateBrowsingService);
let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
getService(Ci.nsIWindowWatcher);
let cp = Cc["@mozilla.org/embedcomp/cookieprompt-service;1"].
getService(Ci.nsICookiePromptService);
@ -54,7 +52,7 @@ function test() {
if (aTopic != "domwindowopened")
return;
ww.unregisterNotification(observer);
Services.ww.unregisterNotification(observer);
let win = aSubject.QueryInterface(Ci.nsIDOMWindow);
win.addEventListener("load", function onLoad(event) {
win.removeEventListener("load", onLoad, false);
@ -76,7 +74,7 @@ function test() {
});
}, false);
}
ww.registerNotification(observer);
Services.ww.registerNotification(observer);
let remember = {};
const time = (new Date("Jan 1, 2030")).getTime() / 1000;

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

@ -46,8 +46,6 @@ function test() {
getService(Ci.nsIDownloadManager);
if (!gDownloadMgr)
gDownloadMgr = dm;
let iosvc = Cc["@mozilla.org/network/io-service;1"].
getService(Ci.nsIIOService);
let panel = document.getElementById("download-monitor");
waitForExplicitFinish();
@ -159,10 +157,8 @@ function addDownload(dm, aParams)
return dl;
}
function createURI(aObj)
{
let ios = Cc["@mozilla.org/network/io-service;1"].
getService(Ci.nsIIOService);
function createURI(aObj) {
let ios = Services.io;
return (aObj instanceof Ci.nsIFile) ? ios.newFileURI(aObj) :
ios.newURI(aObj, null, null);
}

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

@ -42,8 +42,6 @@ function test() {
// initialization
let pb = Cc["@mozilla.org/privatebrowsing;1"].
getService(Ci.nsIPrivateBrowsingService);
let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
getService(Ci.nsIWindowWatcher);
waitForExplicitFinish();
// Add a history entry.
@ -59,7 +57,7 @@ function test() {
if (aTopic != "domwindowopened")
return;
ww.unregisterNotification(observer);
Services.ww.unregisterNotification(observer);
let organizer = aSubject.QueryInterface(Ci.nsIDOMWindow);
organizer.addEventListener("load", function onLoad(event) {
organizer.removeEventListener("load", onLoad, false);
@ -103,12 +101,12 @@ function test() {
}, false);
}
ww.registerNotification(observer);
ww.openWindow(null,
"chrome://browser/content/places/places.xul",
"",
"chrome,toolbar=yes,dialog=no,resizable",
null);
Services.ww.registerNotification(observer);
Services.ww.openWindow(null,
"chrome://browser/content/places/places.xul",
"",
"chrome,toolbar=yes,dialog=no,resizable",
null);
}
testForgetThisSiteVisibility(true, function() {

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

@ -42,8 +42,6 @@ let cookieManager = Cc["@mozilla.org/cookiemanager;1"].
getService(Ci.nsICookieManager2);
let pb = Cc["@mozilla.org/privatebrowsing;1"].
getService(Ci.nsIPrivateBrowsingService);
let _obs = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
let observerNotified = 0, firstUnloadFired = 0, secondUnloadFired = 0;
function pbObserver(aSubject, aTopic, aData) {
@ -56,7 +54,7 @@ function pbObserver(aSubject, aTopic, aData) {
is(firstUnloadFired, 1, "The first unload event should have been processed by now");
break;
case "exit":
_obs.removeObserver(pbObserver, "private-browsing");
Services.obs.removeObserver(pbObserver, "private-browsing");
observerNotified++;
is(observerNotified, 2, "This should be the second notification");
is(secondUnloadFired, 1, "The second unload event should have been processed by now");
@ -66,7 +64,7 @@ function pbObserver(aSubject, aTopic, aData) {
function test() {
waitForExplicitFinish();
_obs.addObserver(pbObserver, "private-browsing", false);
Services.obs.addObserver(pbObserver, "private-browsing", false);
is(gBrowser.tabs.length, 1, "There should only be one tab");
let testTab = gBrowser.addTab();
gBrowser.selectedTab = testTab;

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

@ -48,9 +48,7 @@ function test() {
if (aTopic == "private-browsing")
observerData = aData;
}
let os = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
os.addObserver(observer, "private-browsing", false);
Services.obs.addObserver(observer, "private-browsing", false);
let pbMenuItem = document.getElementById("privateBrowsingItem");
// add a new blank tab to ensure the title can be meaningfully compared later
gBrowser.selectedTab = gBrowser.addTab();
@ -92,6 +90,6 @@ function test() {
// cleanup
gBrowser.removeCurrentTab();
os.removeObserver(observer, "private-browsing");
Services.obs.removeObserver(observer, "private-browsing");
gPrefService.clearUserPref("browser.privatebrowsing.keep_current_session");
}

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

@ -0,0 +1,64 @@
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Private Browsing Tests.
*
* The Initial Developer of the Original Code is Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Ehsan Akhgari <ehsan.akhgari@gmail.com> (Original Author)
*
* Alternatively, the contents of this file may be used under the terms of
* either of the GNU General Public License Version 2 or later (the "GPL"),
* or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
// This test makes sure that the undo history of the URL bar is cleared when
// leaving the private browsing mode.
function test() {
// initialization
Services.prefs.setBoolPref("browser.privatebrowsing.keep_current_session", true);
let pb = Cc["@mozilla.org/privatebrowsing;1"].
getService(Ci.nsIPrivateBrowsingService);
// enter private browsing mode
pb.privateBrowsingEnabled = true;
// fill in the URL bar with something
gURLBar.value = "some test value";
ok(gURLBar.editor.transactionManager.numberOfUndoItems > 0,
"The undo history for the URL bar should not be empty");
// leave private browsing mode
pb.privateBrowsingEnabled = false;
is(gURLBar.editor.transactionManager.numberOfUndoItems, 0,
"The undo history of the URL bar should be cleared after leaving the private browsing mode");
// cleanup
Services.prefs.clearUserPref("browser.privatebrowsing.keep_current_session");
}

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

@ -50,13 +50,11 @@ function test() {
aboutBrowser.addEventListener("load", function () {
aboutBrowser.removeEventListener("load", arguments.callee, true);
let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
getService(Ci.nsIWindowWatcher);
function observer(aSubject, aTopic, aData) {
if (aTopic != "domwindowopened")
return;
ww.unregisterNotification(observer);
Services.ww.unregisterNotification(observer);
let win = aSubject.QueryInterface(Ci.nsIDOMEventTarget);
win.addEventListener("load", function () {
@ -71,7 +69,7 @@ function test() {
}, true);
}, false);
}
ww.registerNotification(observer);
Services.ww.registerNotification(observer);
openViewSource();
@ -84,14 +82,14 @@ function test() {
function observer(aSubject, aTopic, aData) {
if (aTopic == "domwindowclosed") {
ok(true, "Entering the private browsing mode should close the view source window");
ww.unregisterNotification(observer);
Services.ww.unregisterNotification(observer);
step2();
}
else if (aTopic == "domwindowopened")
ok(false, "Entering the private browsing mode should not open any view source window");
}
ww.registerNotification(observer);
Services.ww.registerNotification(observer);
gBrowser.addTabsProgressListener({
onLocationChange: function() {},
@ -124,7 +122,7 @@ function test() {
if (aTopic != "domwindowopened")
return;
ww.unregisterNotification(observer);
Services.ww.unregisterNotification(observer);
let win = aSubject.QueryInterface(Ci.nsIDOMEventTarget);
win.addEventListener("load", function () {
@ -139,7 +137,7 @@ function test() {
}, true);
}, false);
}
ww.registerNotification(observer);
Services.ww.registerNotification(observer);
openViewSource();
}
@ -151,12 +149,12 @@ function test() {
if (aTopic == "domwindowclosed") {
ok(true, "Leaving the private browsing mode should close the existing view source window");
if (++events == 2)
ww.unregisterNotification(observer);
Services.ww.unregisterNotification(observer);
}
else if (aTopic == "domwindowopened") {
ok(true, "Leaving the private browsing mode should restore the previous view source window");
if (++events == 2)
ww.unregisterNotification(observer);
Services.ww.unregisterNotification(observer);
let win = aSubject.QueryInterface(Ci.nsIDOMEventTarget);
win.addEventListener("load", function () {
@ -177,7 +175,7 @@ function test() {
}, false);
}
}
ww.registerNotification(observer);
Services.ww.registerNotification(observer);
// exit private browsing mode
pb.privateBrowsingEnabled = false;

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

@ -33,10 +33,7 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
var gSS = Cc["@mozilla.org/browser/search-service;1"].
getService(Ci.nsIBrowserSearchService);
var gObs = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
var gSS = Services.search;
function observers(aSubject, aTopic, aData) {
switch (aData) {
@ -54,7 +51,7 @@ function observers(aSubject, aTopic, aData) {
function test() {
waitForExplicitFinish();
gObs.addObserver(observers, "browser-search-engine-modified", false);
Services.obs.addObserver(observers, "browser-search-engine-modified", false);
gSS.addEngine("http://mochi.test:8888/browser/browser/components/search/test/testEngine.xml",
Ci.nsISearchEngine.DATA_XML, "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAABGklEQVQoz2NgGB6AnZ1dUlJSXl4eSDIyMhLW4Ovr%2B%2Fr168uXL69Zs4YoG%2BLi4i5dusTExMTGxsbNzd3f37937976%2BnpmZmagbHR09J49e5YvX66kpATVEBYW9ubNm2nTphkbG7e2tp44cQLIuHfvXm5urpaWFlDKysqqu7v73LlzECMYIiIiHj58mJCQoKKicvXq1bS0NKBgW1vbjh074uPjgeqAXE1NzSdPnvDz84M0AEUvXLgAsW379u1z5swBen3jxo2zZ892cHB4%2BvQp0KlAfwI1cHJyghQFBwfv2rULokFXV%2FfixYu7d%2B8GGqGgoMDKyrpu3br9%2B%2FcDuXl5eVA%2FAEWBfoWHAdAYoNuAYQ0XAeoUERFhGDYAAPoUaT2dfWJuAAAAAElFTkSuQmCC",
@ -83,6 +80,6 @@ function test4() {
ok(engine, "An engine is present.");
isnot(engine.name, "Foo", "Current engine reset after removal");
gObs.removeObserver(observers, "browser-search-engine-modified");
Services.obs.removeObserver(observers, "browser-search-engine-modified");
finish();
}

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

@ -8,10 +8,7 @@ function test() {
searchBar.value = "test";
var obs = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
var ss = Cc["@mozilla.org/browser/search-service;1"].
getService(Ci.nsIBrowserSearchService);
var ss = Services.search;
function observer(aSub, aTopic, aData) {
switch (aData) {
@ -26,13 +23,13 @@ function test() {
testReturn();
break;
case "engine-removed":
obs.removeObserver(observer, "browser-search-engine-modified");
Services.obs.removeObserver(observer, "browser-search-engine-modified");
finish();
break;
}
}
obs.addObserver(observer, "browser-search-engine-modified", false);
Services.obs.addObserver(observer, "browser-search-engine-modified", false);
ss.addEngine("http://mochi.test:8888/browser/browser/components/search/test/426329.xml",
Ci.nsISearchEngine.DATA_XML, "data:image/x-icon,%00",
false);

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

@ -33,8 +33,7 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
let gSS = Cc["@mozilla.org/browser/search-service;1"].
getService(Ci.nsIBrowserSearchService);
let gSS = Services.search;
let gObs = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
@ -51,13 +50,13 @@ function test() {
gSS.removeEngine(engine);
break;
case "engine-removed":
gObs.removeObserver(observer, "browser-search-engine-modified");
Services.obs.removeObserver(observer, "browser-search-engine-modified");
test2();
break;
}
}
gObs.addObserver(observer, "browser-search-engine-modified", false);
Services.obs.addObserver(observer, "browser-search-engine-modified", false);
gSS.addEngine("http://mochi.test:8888/browser/browser/components/search/test/483086-1.xml",
Ci.nsISearchEngine.DATA_XML, "data:image/x-icon;%00",
false);
@ -73,13 +72,13 @@ function test2() {
gSS.removeEngine(engine);
break;
case "engine-removed":
gObs.removeObserver(observer, "browser-search-engine-modified");
Services.obs.removeObserver(observer, "browser-search-engine-modified");
finish();
break;
}
}
gObs.addObserver(observer, "browser-search-engine-modified", false);
Services.obs.addObserver(observer, "browser-search-engine-modified", false);
gSS.addEngine("http://mochi.test:8888/browser/browser/components/search/test/483086-2.xml",
Ci.nsISearchEngine.DATA_XML, "data:image/x-icon;%00",
false);

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

@ -63,13 +63,11 @@ function test() {
return -1;
}
let os = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
function waitForFileExistence(aMessage, aDoNext) {
const TOPIC = "sessionstore-state-write-complete";
os.addObserver(function (aSubject, aTopic, aData) {
Services.obs.addObserver(function (aSubject, aTopic, aData) {
// Remove the observer so we do not leak.
os.removeObserver(arguments.callee, TOPIC);
Services.obs.removeObserver(arguments.callee, TOPIC);
// Check that the file exists.
ok(getSessionstoreFile().exists(), aMessage);

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

@ -109,9 +109,7 @@ function browserWindowsCount(expected, msg) {
if (typeof expected == "number")
expected = [expected, expected];
let count = 0;
let e = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator)
.getEnumerator("navigator:browser");
let e = Services.wm.getEnumerator("navigator:browser");
while (e.hasMoreElements()) {
if (!e.getNext().closed)
++count;
@ -172,8 +170,6 @@ function test() {
aCancel.QueryInterface(Ci.nsISupportsPRBool).data = true;
}
}
let observerService = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
/**
* Helper: Sets prefs as the testsuite requires
@ -194,7 +190,7 @@ function test() {
function setupTestsuite(testFn) {
// Register our observers
for (let o in observing)
observerService.addObserver(observer, o, false);
Services.obs.addObserver(observer, o, false);
// Make the main test window not count as a browser window any longer
oldWinType = document.documentElement.getAttribute("windowtype");
@ -207,7 +203,7 @@ function test() {
function cleanupTestsuite(callback) {
// Finally remove observers again
for (let o in observing)
observerService.removeObserver(observer, o, false);
Services.obs.removeObserver(observer, o, false);
// Reset the prefs we touched
[

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

@ -37,9 +37,7 @@
function browserWindowsCount() {
let count = 0;
let e = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator)
.getEnumerator("navigator:browser");
let e = Services.wm.getEnumerator("navigator:browser");
while (e.hasMoreElements()) {
if (!e.getNext().closed)
++count;

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

@ -39,9 +39,7 @@
function browserWindowsCount() {
let count = 0;
let e = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator)
.getEnumerator("navigator:browser");
let e = Services.wm.getEnumerator("navigator:browser");
while (e.hasMoreElements()) {
if (!e.getNext().closed)
++count;
@ -74,10 +72,8 @@ function test() {
// Wait for the sessionstore.js file to be written before going on.
// Note: we don't wait for the complete event, since if asyncCopy fails we
// would timeout.
let os = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
os.addObserver(function (aSubject, aTopic, aData) {
os.removeObserver(arguments.callee, aTopic);
Services.obs.addObserver(function (aSubject, aTopic, aData) {
Services.obs.removeObserver(arguments.callee, aTopic);
info("sessionstore.js is being written");
executeSoon(continue_test);
}, "sessionstore-state-write", false);

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

@ -36,9 +36,7 @@
function browserWindowsCount() {
let count = 0;
let e = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator)
.getEnumerator("navigator:browser");
let e = Services.wm.getEnumerator("navigator:browser");
while (e.hasMoreElements()) {
if (!e.getNext().closed)
++count;

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

@ -39,7 +39,6 @@ function test() {
// test setup
let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
let os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
waitForExplicitFinish();
let uniqueName = "bug 448741";
@ -71,7 +70,7 @@ function test() {
ok(valueWasCleaned, "found and removed the specific tab value");
aSubject.data = uneval(state);
os.removeObserver(cleaningObserver, aTopic, false);
Services.obs.removeObserver(cleaningObserver, aTopic, false);
}
// make sure that all later observers don't see that value any longer
@ -82,15 +81,15 @@ function test() {
// clean up
gBrowser.removeTab(tab);
os.removeObserver(checkingObserver, aTopic, false);
Services.obs.removeObserver(checkingObserver, aTopic, false);
if (gPrefService.prefHasUserValue("browser.sessionstore.interval"))
gPrefService.clearUserPref("browser.sessionstore.interval");
finish();
}
// last added observers are invoked first
os.addObserver(checkingObserver, "sessionstore-state-write", false);
os.addObserver(cleaningObserver, "sessionstore-state-write", false);
Services.obs.addObserver(checkingObserver, "sessionstore-state-write", false);
Services.obs.addObserver(cleaningObserver, "sessionstore-state-write", false);
// trigger an immediate save operation
gPrefService.setIntPref("browser.sessionstore.interval", 0);

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

@ -37,9 +37,7 @@
function browserWindowsCount() {
let count = 0;
let e = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator)
.getEnumerator("navigator:browser");
let e = Services.wm.getEnumerator("navigator:browser");
while (e.hasMoreElements()) {
if (!e.getNext().closed)
++count;

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

@ -36,9 +36,7 @@
function browserWindowsCount() {
let count = 0;
let e = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator)
.getEnumerator("navigator:browser");
let e = Services.wm.getEnumerator("navigator:browser");
while (e.hasMoreElements()) {
if (!e.getNext().closed)
++count;

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

@ -36,9 +36,7 @@
function browserWindowsCount() {
let count = 0;
let e = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator)
.getEnumerator("navigator:browser");
let e = Services.wm.getEnumerator("navigator:browser");
while (e.hasMoreElements()) {
if (!e.getNext().closed)
++count;

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

@ -36,9 +36,7 @@
function browserWindowsCount() {
let count = 0;
let e = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator)
.getEnumerator("navigator:browser");
let e = Services.wm.getEnumerator("navigator:browser");
while (e.hasMoreElements()) {
if (!e.getNext().closed)
++count;

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

@ -36,9 +36,7 @@
function browserWindowsCount() {
let count = 0;
let e = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator)
.getEnumerator("navigator:browser");
let e = Services.wm.getEnumerator("navigator:browser");
while (e.hasMoreElements()) {
if (!e.getNext().closed)
++count;

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

@ -37,9 +37,7 @@
function browserWindowsCount() {
let count = 0;
let e = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator)
.getEnumerator("navigator:browser");
let e = Services.wm.getEnumerator("navigator:browser");
while (e.hasMoreElements()) {
if (!e.getNext().closed)
++count;
@ -53,10 +51,6 @@ function test() {
let ss = Cc["@mozilla.org/browser/sessionstore;1"].
getService(Ci.nsISessionStore);
let os = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
getService(Ci.nsIWindowWatcher);
waitForExplicitFinish();
@ -98,7 +92,7 @@ function test() {
break;
case "domwindowclosed":
ww.unregisterNotification(windowObserver);
Services.ww.unregisterNotification(windowObserver);
// Use executeSoon to ensure this happens after SS observer.
executeSoon(function () {
is(ss.getClosedWindowCount(),
@ -110,12 +104,12 @@ function test() {
break;
}
}
ww.registerNotification(windowObserver);
ww.openWindow(null,
location,
"_blank",
"chrome,all,dialog=no",
null);
Services.ww.registerNotification(windowObserver);
Services.ww.openWindow(null,
location,
"_blank",
"chrome,all,dialog=no",
null);
}
// Only windows with open tabs are restorable. Windows where a lone tab is

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

@ -36,9 +36,7 @@
function browserWindowsCount() {
let count = 0;
let e = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator)
.getEnumerator("navigator:browser");
let e = Services.wm.getEnumerator("navigator:browser");
while (e.hasMoreElements()) {
if (!e.getNext().closed)
++count;
@ -52,7 +50,6 @@ function test() {
// test setup
let ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
let ioService = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
waitForExplicitFinish();
@ -91,6 +88,6 @@ function test() {
}, true);
},true);
let referrerURI = ioService.newURI(REFERRER1, null, null);
let referrerURI = Services.io.newURI(REFERRER1, null, null);
browser.loadURI("http://example.org", referrerURI, null);
}

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

@ -37,9 +37,7 @@
function browserWindowsCount() {
let count = 0;
let e = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator)
.getEnumerator("navigator:browser");
let e = Services.wm.getEnumerator("navigator:browser");
while (e.hasMoreElements()) {
if (!e.getNext().closed)
++count;

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

@ -36,9 +36,7 @@
function browserWindowsCount() {
let count = 0;
let e = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator)
.getEnumerator("navigator:browser");
let e = Services.wm.getEnumerator("navigator:browser");
while (e.hasMoreElements()) {
if (!e.getNext().closed)
++count;

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

@ -36,9 +36,7 @@
function browserWindowsCount() {
let count = 0;
let e = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator)
.getEnumerator("navigator:browser");
let e = Services.wm.getEnumerator("navigator:browser");
while (e.hasMoreElements()) {
if (!e.getNext().closed)
++count;

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

@ -36,9 +36,7 @@
function browserWindowsCount() {
let count = 0;
let e = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator)
.getEnumerator("navigator:browser");
let e = Services.wm.getEnumerator("navigator:browser");
while (e.hasMoreElements()) {
if (!e.getNext().closed)
++count;

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

@ -37,9 +37,7 @@
function browserWindowsCount() {
let count = 0;
let e = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator)
.getEnumerator("navigator:browser");
let e = Services.wm.getEnumerator("navigator:browser");
while (e.hasMoreElements()) {
if (!e.getNext().closed)
++count;

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

@ -37,9 +37,7 @@
function browserWindowsCount() {
let count = 0;
let e = Cc["@mozilla.org/appshell/window-mediator;1"]
.getService(Ci.nsIWindowMediator)
.getEnumerator("navigator:browser");
let e = Services.wm.getEnumerator("navigator:browser");
while (e.hasMoreElements()) {
if (!e.getNext().closed)
++count;
@ -53,8 +51,6 @@ function test() {
let ss = Cc["@mozilla.org/browser/sessionstore;1"].
getService(Ci.nsISessionStore);
let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"].
getService(Ci.nsIWindowWatcher);
let uniqKey = "bug524745";
let uniqVal = Date.now();

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

@ -41,15 +41,11 @@ function test() {
// test setup
let ss = Cc["@mozilla.org/browser/sessionstore;1"].
getService(Ci.nsISessionStore);
let os = Cc["@mozilla.org/observer-service;1"].
getService(Ci.nsIObserverService);
let wm = Cc["@mozilla.org/appshell/window-mediator;1"].
getService(Ci.nsIWindowMediator);
waitForExplicitFinish();
function browserWindowsCount(expected) {
let count = 0;
let e = wm.getEnumerator("navigator:browser");
let e = Services.wm.getEnumerator("navigator:browser");
while (e.hasMoreElements()) {
if (!e.getNext().closed)
++count;
@ -87,7 +83,7 @@ function test() {
// let the first window be focused (see above)
function pollMostRecentWindow() {
if (wm.getMostRecentWindow("navigator:browser") == window) {
if (Services.wm.getMostRecentWindow("navigator:browser") == window) {
ss.setBrowserState(oldState);
} else {
info("waiting for the current window to become active");
@ -100,11 +96,11 @@ function test() {
else {
browserWindowsCount(1);
ok(!window.closed, "Restoring the old state should have left this window open");
os.removeObserver(observer, "sessionstore-browser-state-restored");
Services.obs.removeObserver(observer, "sessionstore-browser-state-restored");
finish();
}
}
os.addObserver(observer, "sessionstore-browser-state-restored", false);
Services.obs.addObserver(observer, "sessionstore-browser-state-restored", false);
// set browser to test state
ss.setBrowserState(JSON.stringify(testState));

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

@ -1,9 +1,8 @@
var ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
var wm = Cc["@mozilla.org/appshell/window-mediator;1"].getService(Ci.nsIWindowMediator);
function browserWindowsCount(expected) {
var count = 0;
var e = wm.getEnumerator("navigator:browser");
var e = Services.wm.getEnumerator("navigator:browser");
while (e.hasMoreElements()) {
if (!e.getNext().closed)
++count;

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

@ -180,6 +180,12 @@ PreviewController.prototype = {
this.linkedBrowser.removeEventListener("pageshow", this, false);
this.linkedBrowser.removeEventListener("DOMTitleChanged", this, false);
this.linkedBrowser.removeEventListener("MozAfterPaint", this, false);
// Break cycles, otherwise we end up leaking the window with everything
// attached to it.
delete this.win;
delete this.preview;
delete this.dirtyRegion;
},
get wrappedJSObject() {
return this;
@ -383,7 +389,6 @@ function TabWindow(win) {
this.tabbrowser.tabContainer.addEventListener(this.events[i], this, false);
this.tabbrowser.addTabsProgressListener(this);
AeroPeek.windows.push(this);
let tabs = this.tabbrowser.tabs;
for (let i = 0; i < tabs.length; i++)
@ -402,6 +407,8 @@ TabWindow.prototype = {
let tabs = this.tabbrowser.tabs;
this.tabbrowser.removeTabsProgressListener(this);
for (let i = 0; i < this.events.length; i++)
this.tabbrowser.tabContainer.removeEventListener(this.events[i], this, false);
@ -589,6 +596,17 @@ var AeroPeek = {
this.enabled = this._prefenabled = this.prefs.getBoolPref(TOGGLE_PREF_NAME);
},
destroy: function destroy() {
this._enabled = false;
this.prefs.removeObserver(TOGGLE_PREF_NAME, this);
this.prefs.removeObserver(DISABLE_THRESHOLD_PREF_NAME, this);
this.prefs.removeObserver(CACHE_EXPIRATION_TIME_PREF_NAME, this);
if (this.cacheTimer)
this.cacheTimer.cancel();
},
get enabled() {
return this._enabled;
},
@ -636,7 +654,10 @@ var AeroPeek = {
return;
win.gTaskbarTabGroup.destroy();
win.gTaskbarTabGroup = null;
delete win.gTaskbarTabGroup;
if (this.windows.length == 0)
this.destroy();
},
resetCacheTimer: function () {

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

@ -1,6 +1,3 @@
const Ci = Components.interfaces;
const Cc = Components.classes;
// This listens for the next opened window and checks it is of the right url.
// opencallback is called when the new window is fully loaded
// closecallback is called when the window is closed
@ -9,9 +6,7 @@ function WindowOpenListener(url, opencallback, closecallback) {
this.opencallback = opencallback;
this.closecallback = closecallback;
var wm = Cc["@mozilla.org/appshell/window-mediator;1"].
getService(Ci.nsIWindowMediator);
wm.addListener(this);
Services.wm.addListener(this);
}
WindowOpenListener.prototype = {
@ -47,9 +42,7 @@ WindowOpenListener.prototype = {
if (this.window != window)
return;
var wm = Cc["@mozilla.org/appshell/window-mediator;1"].
getService(Ci.nsIWindowMediator);
wm.removeListener(this);
Services.wm.removeListener(this);
this.opencallback = null;
this.window = null;
this.domwindow = null;

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

@ -5,14 +5,13 @@ function test() {
"Received a quit request we're going to deny");
aSubject.data = true;
}
// ensure that we don't accidentally quit
let os = Cc["@mozilla.org/observer-service;1"].getService(Ci.nsIObserverService);
os.addObserver(quitRequestObserver, "quit-application-requested", false);
Services.obs.addObserver(quitRequestObserver, "quit-application-requested", false);
ok(!Application.quit(), "Tried to quit - and didn't succeed");
ok(!Application.restart(), "Tried to restart - and didn't succeed");
// clean up
os.removeObserver(quitRequestObserver, "quit-application-requested", false);
Services.obs.removeObserver(quitRequestObserver, "quit-application-requested", false);
}

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

@ -1,12 +1,8 @@
const Ci = Components.interfaces;
const Cc = Components.classes;
var gLastFolderAction = "";
var gLastBookmarkAction = "";
function url(spec) {
var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
return ios.newURI(spec, null, null);
return Services.io.newURI(spec, null, null);
}
function test() {

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

@ -132,7 +132,7 @@ GCONF_VERSION=1.2.1
GIO_VERSION=2.0
STARTUP_NOTIFICATION_VERSION=0.8
DBUS_VERSION=0.60
SQLITE_VERSION=3.6.23
SQLITE_VERSION=3.6.23.1
LIBNOTIFY_VERSION=0.4
MSMANIFEST_TOOL=
@ -6595,6 +6595,13 @@ if test $MOZ_PLATFORM_MAEMO; then
if test -z "$_LIB_FOUND"; then
AC_MSG_ERROR([Hildon FM-2 is required when building for Maemo])
fi
PKG_CHECK_MODULES(LIBLOCATION,liblocation, _LIB_FOUND=1, _LIB_FOUND=)
MOZ_PLATFORM_MAEMO_LIBS="$MOZ_PLATFORM_MAEMO_LIBS $LIBLOCATION_LIBS"
MOZ_PLATFORM_MAEMO_CFLAGS="$MOZ_PLATFORM_MAEMO_CFLAGS $LIBLOCATION_CFLAGS"
if test -z "$_LIB_FOUND"; then
AC_MSG_ERROR([liblocation is required when building for Maemo])
fi
fi
AC_SUBST(MOZ_PLATFORM_MAEMO_LIBS)

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

@ -310,12 +310,12 @@ nsICanvasRenderingContextWebGL_TexSubImage2D(JSContext *cx, uintN argc, jsval *v
if (!xpc_qsUnwrapThis(cx, obj, nsnull, &self, &selfref.ptr, tvr.addr(), nsnull))
return JS_FALSE;
if (argc < 7 || (argc > 7 && argc < 9))
if (argc < 7)
return xpc_qsThrow(cx, NS_ERROR_XPC_NOT_ENOUGH_ARGS);
jsval *argv = JS_ARGV(cx, vp);
int32 intargs[8];
int32 intargs[9];
// convert the first six args, they must be ints
for (jsuint i = 0; i < 6; ++i) {

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

@ -788,7 +788,10 @@ nsContentEventHandler::OnQueryCharacterAtPoint(nsQueryContentEvent* aEvent)
nsLayoutUtils::GetEventCoordinatesRelativeTo(&eventOnRoot, rootFrame);
nsIFrame* targetFrame = nsLayoutUtils::GetFrameForPoint(rootFrame, ptInRoot);
if (!targetFrame || targetFrame->GetType() != nsGkAtoms::textFrame) {
if (!targetFrame || targetFrame->GetType() != nsGkAtoms::textFrame ||
!targetFrame->GetContent() ||
!nsContentUtils::ContentIsDescendantOf(targetFrame->GetContent(),
mRootContent)) {
// there is no character at the point.
aEvent->mReply.mOffset = nsQueryContentEvent::NOT_FOUND;
aEvent->mSucceeded = PR_TRUE;

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

@ -35,6 +35,9 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#if !defined(nsHTMLAudioElement_h__)
#define nsHTMLAudioElement_h__
#include "nsIDOMHTMLAudioElement.h"
#include "nsIJSNativeInitializer.h"
#include "nsHTMLMediaElement.h"
@ -74,3 +77,5 @@ public:
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const;
};
#endif

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

@ -35,6 +35,9 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#if !defined(nsHTMLMediaElement_h__)
#define nsHTMLMediaElement_h__
#include "nsIDOMHTMLMediaElement.h"
#include "nsGenericHTMLElement.h"
#include "nsMediaDecoder.h"
@ -538,3 +541,5 @@ protected:
nsRefPtr<gfxASurface> mPrintSurface;
};
#endif

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

@ -35,6 +35,9 @@
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#if !defined(nsHTMLVideoElement_h__)
#define nsHTMLVideoElement_h__
#include "nsIDOMHTMLVideoElement.h"
#include "nsHTMLMediaElement.h"
@ -76,3 +79,5 @@ public:
// If there is no video frame, returns the given default size.
nsIntSize GetVideoSize(nsIntSize defaultSize);
};
#endif

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

@ -84,6 +84,7 @@
#include "nsLayoutUtils.h"
#include "nsVideoFrame.h"
#include "BasicLayers.h"
#include <limits>
#ifdef MOZ_OGG
#include "nsOggDecoder.h"
@ -819,7 +820,7 @@ NS_IMETHODIMP nsHTMLMediaElement::SetCurrentTime(float aCurrentTime)
/* readonly attribute float duration; */
NS_IMETHODIMP nsHTMLMediaElement::GetDuration(float *aDuration)
{
*aDuration = mDecoder ? mDecoder->GetDuration() : 0.0;
*aDuration = mDecoder ? mDecoder->GetDuration() : std::numeric_limits<float>::quiet_NaN();
return NS_OK;
}

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

@ -1849,7 +1849,7 @@ nsHTMLDocument::OpenCommon(const nsACString& aContentType, PRBool aReplace)
if (!IsHTML() || mDisableDocWrite) {
// No calling document.open() on XHTML
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
return NS_ERROR_DOM_INVALID_STATE_ERR;
}
PRBool loadAsHtml5 = nsHtml5Module::sEnabled;
@ -2099,7 +2099,7 @@ nsHTMLDocument::Close()
if (!IsHTML()) {
// No calling document.close() on XHTML!
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
return NS_ERROR_DOM_INVALID_STATE_ERR;
}
nsresult rv = NS_OK;
@ -2164,7 +2164,7 @@ nsHTMLDocument::WriteCommon(const nsAString& aText,
if (!IsHTML() || mDisableDocWrite) {
// No calling document.write*() on XHTML!
return NS_ERROR_DOM_INVALID_ACCESS_ERR;
return NS_ERROR_DOM_INVALID_STATE_ERR;
}
nsresult rv = NS_OK;

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

@ -134,7 +134,6 @@ public:
nsIContent* aContent);
nsresult AddText(const nsAString& aString);
nsresult AddTextToContent(nsIContent* aContent, const nsAString& aText);
nsresult FlushText();
void ProcessBaseTag(nsIContent* aContent);
@ -763,26 +762,6 @@ nsHTMLFragmentContentSink::AddText(const nsAString& aString)
return NS_OK;
}
nsresult
nsHTMLFragmentContentSink::AddTextToContent(nsIContent* aContent, const nsAString& aText) {
NS_ASSERTION(aContent !=nsnull, "can't add text w/o a content");
nsresult result=NS_OK;
if(aContent) {
if (!aText.IsEmpty()) {
nsCOMPtr<nsIContent> text;
result = NS_NewTextNode(getter_AddRefs(text), mNodeInfoManager);
if (NS_SUCCEEDED(result)) {
text->SetText(aText, PR_TRUE);
result = aContent->AppendChildTo(text, PR_FALSE);
}
}
}
return result;
}
nsresult
nsHTMLFragmentContentSink::FlushText()
{

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

@ -28,7 +28,7 @@ function test() {
document.open();
is(0, 1, "document.open succeeded");
} catch (e) {
is (e.code, DOMException.INVALID_ACCESS_ERR,
is (e.code, DOMException.INVALID_STATE_ERR,
"Wrong exception from document.open");
}
@ -36,7 +36,15 @@ function test() {
document.write("aaa");
is(0, 1, "document.write succeeded");
} catch (e) {
is (e.code, DOMException.INVALID_ACCESS_ERR,
is (e.code, DOMException.INVALID_STATE_ERR,
"Wrong exception from document.write");
}
try {
document.writeln("aaa");
is(0, 1, "document.write succeeded");
} catch (e) {
is (e.code, DOMException.INVALID_STATE_ERR,
"Wrong exception from document.write");
}
@ -44,7 +52,7 @@ function test() {
document.close();
is(0, 1, "document.close succeeded");
} catch (e) {
is (e.code, DOMException.INVALID_ACCESS_ERR,
is (e.code, DOMException.INVALID_STATE_ERR,
"Wrong exception from document.close");
}
}

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

@ -45,6 +45,9 @@
extern "C" {
#include "sydneyaudio/sydney_audio.h"
}
#include "mozilla/TimeStamp.h"
using mozilla::TimeStamp;
#ifdef PR_LOGGING
PRLogModuleInfo* gAudioStreamLog = nsnull;
@ -68,7 +71,8 @@ nsAudioStream::nsAudioStream() :
mAudioHandle(0),
mRate(0),
mChannels(0),
mFormat(FORMAT_S16_LE)
mFormat(FORMAT_S16_LE),
mPaused(PR_FALSE)
{
}
@ -110,13 +114,14 @@ void nsAudioStream::Shutdown()
mAudioHandle = nsnull;
}
void nsAudioStream::Write(const void* aBuf, PRUint32 aCount)
void nsAudioStream::Write(const void* aBuf, PRUint32 aCount, PRBool aBlocking)
{
NS_ABORT_IF_FALSE(aCount % mChannels == 0,
"Buffer size must be divisible by channel count");
NS_ASSERTION(!mPaused, "Don't write audio when paused, you'll block");
PRUint32 offset = mBufferOverflow.Length();
PRInt32 count = aCount + offset;
PRUint32 count = aCount + offset;
if (!mAudioHandle)
return;
@ -168,21 +173,28 @@ void nsAudioStream::Write(const void* aBuf, PRUint32 aCount)
}
}
PRInt32 available = Available();
if (available < count) {
mBufferOverflow.AppendElements(s_data.get() + available, (count - available));
count = available;
if (!aBlocking) {
// We're running in non-blocking mode, crop the data to the amount
// which is available in the audio buffer, and save the rest for
// subsequent calls.
PRUint32 available = Available();
if (available < count) {
mBufferOverflow.AppendElements(s_data.get() + available, (count - available));
count = available;
}
}
if (sa_stream_write(static_cast<sa_stream_t*>(mAudioHandle),
s_data.get(), count * sizeof(short)) != SA_SUCCESS) {
s_data.get(),
count * sizeof(short)) != SA_SUCCESS)
{
PR_LOG(gAudioStreamLog, PR_LOG_ERROR, ("nsAudioStream: sa_stream_write error"));
Shutdown();
}
}
}
PRInt32 nsAudioStream::Available()
PRUint32 nsAudioStream::Available()
{
// If the audio backend failed to open, lie and say we'll accept some
// data.
@ -225,7 +237,7 @@ void nsAudioStream::Pause()
{
if (!mAudioHandle)
return;
mPaused = PR_TRUE;
sa_stream_pause(static_cast<sa_stream_t*>(mAudioHandle));
}
@ -233,14 +245,14 @@ void nsAudioStream::Resume()
{
if (!mAudioHandle)
return;
mPaused = PR_FALSE;
sa_stream_resume(static_cast<sa_stream_t*>(mAudioHandle));
}
float nsAudioStream::GetPosition()
PRInt64 nsAudioStream::GetPosition()
{
if (!mAudioHandle)
return -1.0;
return -1;
sa_position_t positionType = SA_POSITION_WRITE_SOFTWARE;
#if defined(XP_WIN)
@ -249,9 +261,9 @@ float nsAudioStream::GetPosition()
PRInt64 position = 0;
if (sa_stream_get_position(static_cast<sa_stream_t*>(mAudioHandle),
positionType, &position) == SA_SUCCESS) {
return (position / float(mRate) / mChannels / sizeof(short));
return ((1000 * position) / mRate / mChannels / sizeof(short));
}
return -1.0;
return -1;
}

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

@ -76,11 +76,14 @@ class nsAudioStream
// Write sound data to the audio hardware. aBuf is an array of samples in
// the format specified by mFormat of length aCount. aCount should be
// evenly divisible by the number of channels in this audio stream.
void Write(const void* aBuf, PRUint32 aCount);
// When aBlocking is PR_TRUE, we'll block until the write has completed,
// otherwise we'll buffer any data we can't write immediately, and write
// it in a later call.
void Write(const void* aBuf, PRUint32 aCount, PRBool aBlocking);
// Return the number of sound samples that can be written to the audio device
// without blocking.
PRInt32 Available();
PRUint32 Available();
// Set the current volume of the audio playback. This is a value from
// 0 (meaning muted) to 1 (meaning full volume).
@ -95,9 +98,12 @@ class nsAudioStream
// Resume audio playback
void Resume();
// Return the position in seconds of the sample being played by the
// Return the position in milliseconds of the sample being played by the
// audio hardware.
float GetPosition();
PRInt64 GetPosition();
// Returns PR_TRUE when the audio stream is paused.
PRBool IsPaused() { return mPaused; }
private:
double mVolume;
@ -112,5 +118,8 @@ class nsAudioStream
// backend, the remaining samples are stored in this variable. They
// will be written on the next Write() request.
nsTArray<short> mBufferOverflow;
// PR_TRUE if this audio stream is paused.
PRPackedBool mPaused;
};
#endif

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

@ -49,11 +49,15 @@ LIBXUL_LIBRARY = 1
EXPORTS += \
nsChannelReader.h \
nsOggDecoder.h \
nsOggCodecState.h \
$(NULL)
CPPSRCS = \
nsChannelReader.cpp \
nsOggDecoder.cpp \
nsOggCodecState.cpp \
nsOggReader.cpp \
nsOggPlayStateMachine.cpp \
$(NULL)
FORCE_STATIC_LIB = 1

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

@ -0,0 +1,509 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla code.
*
* The Initial Developer of the Original Code is the Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Chris Double <chris.double@double.co.nz>
* Chris Pearce <chris@pearce.org.nz>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#include "nsDebug.h"
#include "nsOggCodecState.h"
#include "nsOggDecoder.h"
#include <string.h>
#include "nsTraceRefcnt.h"
#include "nsOggHacks.h"
/*
The maximum height and width of the video. Used for
sanitizing the memory allocation of the RGB buffer.
The maximum resolution we anticipate encountering in the
wild is 2160p - 3840x2160 pixels.
*/
#define MAX_VIDEO_WIDTH 4000
#define MAX_VIDEO_HEIGHT 3000
// Adds two 64bit numbers, retuns PR_TRUE if addition succeeded, or PR_FALSE
// if addition would result in an overflow.
static PRBool AddOverflow(PRInt64 a, PRInt64 b, PRInt64& aResult);
// 64 bit integer multiplication with overflow checking. Returns PR_TRUE
// if the multiplication was successful, or PR_FALSE if the operation resulted
// in an integer overflow.
static PRBool MulOverflow(PRInt64 a, PRInt64 b, PRInt64& aResult);
// Defined in nsOggReader.cpp.
extern PRBool MulOverflow32(PRUint32 a, PRUint32 b, PRUint32& aResult);
nsOggCodecState*
nsOggCodecState::Create(ogg_page* aPage)
{
nsAutoPtr<nsOggCodecState> codecState;
if (aPage->body_len > 6 && memcmp(aPage->body+1, "theora", 6) == 0) {
codecState = new nsTheoraState(aPage);
} else if (aPage->body_len > 6 && memcmp(aPage->body+1, "vorbis", 6) == 0) {
codecState = new nsVorbisState(aPage);
} else if (aPage->body_len > 8 && memcmp(aPage->body, "fishead\0", 8) == 0) {
codecState = new nsSkeletonState(aPage);
} else {
codecState = new nsOggCodecState(aPage);
}
return codecState->nsOggCodecState::Init() ? codecState.forget() : nsnull;
}
nsOggCodecState::nsOggCodecState(ogg_page* aBosPage) :
mPacketCount(0),
mSerial(ogg_page_serialno(aBosPage)),
mActive(PR_FALSE),
mDoneReadingHeaders(PR_FALSE)
{
MOZ_COUNT_CTOR(nsOggCodecState);
memset(&mState, 0, sizeof(ogg_stream_state));
}
nsOggCodecState::~nsOggCodecState() {
MOZ_COUNT_DTOR(nsOggCodecState);
int ret = ogg_stream_clear(&mState);
NS_ASSERTION(ret == 0, "ogg_stream_clear failed");
}
nsresult nsOggCodecState::Reset() {
if (ogg_stream_reset(&mState) != 0) {
return NS_ERROR_FAILURE;
}
mBuffer.Erase();
return NS_OK;
}
PRBool nsOggCodecState::Init() {
int ret = ogg_stream_init(&mState, mSerial);
return ret == 0;
}
void nsPageQueue::Append(ogg_page* aPage) {
ogg_page* p = new ogg_page();
p->header_len = aPage->header_len;
p->body_len = aPage->body_len;
p->header = new unsigned char[p->header_len + p->body_len];
p->body = p->header + p->header_len;
memcpy(p->header, aPage->header, p->header_len);
memcpy(p->body, aPage->body, p->body_len);
nsDeque::Push(p);
}
PRBool nsOggCodecState::PageInFromBuffer() {
if (mBuffer.IsEmpty())
return PR_FALSE;
ogg_page *p = mBuffer.PeekFront();
int ret = ogg_stream_pagein(&mState, p);
NS_ENSURE_TRUE(ret == 0, PR_FALSE);
mBuffer.PopFront();
delete p->header;
delete p;
return PR_TRUE;
}
nsTheoraState::nsTheoraState(ogg_page* aBosPage) :
nsOggCodecState(aBosPage),
mSetup(0),
mCtx(0),
mFrameDuration(0),
mFrameRate(0),
mAspectRatio(0)
{
MOZ_COUNT_CTOR(nsTheoraState);
th_info_init(&mInfo);
th_comment_init(&mComment);
}
nsTheoraState::~nsTheoraState() {
MOZ_COUNT_DTOR(nsTheoraState);
th_setup_free(mSetup);
th_decode_free(mCtx);
th_comment_clear(&mComment);
th_info_clear(&mInfo);
}
PRBool nsTheoraState::Init() {
if (!mActive)
return PR_FALSE;
mCtx = th_decode_alloc(&mInfo, mSetup);
if (mCtx == NULL) {
return mActive = PR_FALSE;
}
PRUint32 n = mInfo.fps_numerator;
PRUint32 d = mInfo.fps_denominator;
mFrameRate = (n == 0 || d == 0) ?
0.0 : static_cast<float>(n) / static_cast<float>(d);
PRUint32 c;
if (!MulOverflow32(1000, d, c)) {
return mActive = PR_FALSE;
}
mFrameDuration = c / n;
n = mInfo.aspect_numerator;
d = mInfo.aspect_denominator;
mAspectRatio = (n == 0 || d == 0) ?
1.0 : static_cast<float>(n) / static_cast<float>(d);
// Ensure the frame isn't larger than our prescribed maximum.
PRUint32 pixels;
if (!MulOverflow32(mInfo.pic_width, mInfo.pic_height, pixels) ||
pixels > MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT ||
pixels == 0)
{
return mActive = PR_FALSE;
}
return PR_TRUE;
}
PRBool
nsTheoraState::DecodeHeader(ogg_packet* aPacket)
{
mPacketCount++;
int ret = th_decode_headerin(&mInfo,
&mComment,
&mSetup,
aPacket);
// We must determine when we've read the last header packet.
// th_decode_headerin() does not tell us when it's read the last header, so
// we must keep track of the headers externally.
//
// There are 3 header packets, the Identification, Comment, and Setup
// headers, which must be in that order. If they're out of order, the file
// is invalid. If we've successfully read a header, and it's the setup
// header, then we're done reading headers. The first byte of each packet
// determines it's type as follows:
// 0x80 -> Identification header
// 0x81 -> Comment header
// 0x82 -> Setup header
// See http://www.theora.org/doc/Theora.pdf Chapter 6, "Bitstream Headers",
// for more details of the Ogg/Theora containment scheme.
PRBool isSetupHeader = aPacket->bytes > 0 && aPacket->packet[0] == 0x82;
if (ret < 0 || mPacketCount > 3) {
// We've received an error, or the first three packets weren't valid
// header packets, assume bad input, and don't activate the bitstream.
mDoneReadingHeaders = PR_TRUE;
} else if (ret > 0 && isSetupHeader && mPacketCount == 3) {
// Successfully read the three header packets.
mDoneReadingHeaders = PR_TRUE;
mActive = PR_TRUE;
}
return mDoneReadingHeaders;
}
PRInt64
nsTheoraState::Time(PRInt64 granulepos) {
if (granulepos < 0 || !mActive || mInfo.fps_numerator == 0) {
return -1;
}
PRInt64 t = 0;
PRInt64 frameno = th_granule_frame(mCtx, granulepos);
if (!AddOverflow(frameno, 1, t))
return -1;
if (!MulOverflow(t, 1000, t))
return -1;
if (!MulOverflow(t, mInfo.fps_denominator, t))
return -1;
return t / mInfo.fps_numerator;
}
PRInt64 nsTheoraState::StartTime(PRInt64 granulepos) {
if (granulepos < 0 || !mActive || mInfo.fps_numerator == 0) {
return -1;
}
PRInt64 t = 0;
PRInt64 frameno = th_granule_frame(mCtx, granulepos);
if (!MulOverflow(frameno, 1000, t))
return -1;
if (!MulOverflow(t, mInfo.fps_denominator, t))
return -1;
return t / mInfo.fps_numerator;
}
PRInt64
nsTheoraState::MaxKeyframeOffset()
{
// Determine the maximum time in milliseconds by which a key frame could
// offset for the theora bitstream. Theora granulepos encode time as:
// ((key_frame_number << granule_shift) + frame_offset).
// Therefore the maximum possible time by which any frame could be offset
// from a keyframe is the duration of (1 << granule_shift) - 1) frames.
PRInt64 frameDuration;
PRInt64 keyframeDiff;
PRInt64 shift = mInfo.keyframe_granule_shift;
// Max number of frames keyframe could possibly be offset.
keyframeDiff = (1 << shift) - 1;
// Length of frame in ms.
PRInt64 d = 0; // d will be 0 if multiplication overflows.
MulOverflow(1000, mInfo.fps_denominator, d);
frameDuration = d / mInfo.fps_numerator;
// Total time in ms keyframe can be offset from any given frame.
return frameDuration * keyframeDiff;
}
nsresult nsVorbisState::Reset()
{
nsresult res = NS_OK;
if (mActive && vorbis_synthesis_restart(&mDsp) != 0) {
res = NS_ERROR_FAILURE;
}
if (NS_FAILED(nsOggCodecState::Reset())) {
return NS_ERROR_FAILURE;
}
return res;
}
nsVorbisState::nsVorbisState(ogg_page* aBosPage) :
nsOggCodecState(aBosPage)
{
MOZ_COUNT_CTOR(nsVorbisState);
vorbis_info_init(&mInfo);
vorbis_comment_init(&mComment);
memset(&mDsp, 0, sizeof(vorbis_dsp_state));
memset(&mBlock, 0, sizeof(vorbis_block));
}
nsVorbisState::~nsVorbisState() {
MOZ_COUNT_DTOR(nsVorbisState);
vorbis_block_clear(&mBlock);
vorbis_dsp_clear(&mDsp);
vorbis_info_clear(&mInfo);
vorbis_comment_clear(&mComment);
}
PRBool nsVorbisState::DecodeHeader(ogg_packet* aPacket) {
mPacketCount++;
int ret = vorbis_synthesis_headerin(&mInfo,
&mComment,
aPacket);
// We must determine when we've read the last header packet.
// vorbis_synthesis_headerin() does not tell us when it's read the last
// header, so we must keep track of the headers externally.
//
// There are 3 header packets, the Identification, Comment, and Setup
// headers, which must be in that order. If they're out of order, the file
// is invalid. If we've successfully read a header, and it's the setup
// header, then we're done reading headers. The first byte of each packet
// determines it's type as follows:
// 0x1 -> Identification header
// 0x3 -> Comment header
// 0x5 -> Setup header
// For more details of the Vorbis/Ogg containment scheme, see the Vorbis I
// Specification, Chapter 4, Codec Setup and Packet Decode:
// http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html#x1-580004
PRBool isSetupHeader = aPacket->bytes > 0 && aPacket->packet[0] == 0x5;
if (ret < 0 || mPacketCount > 3) {
// We've received an error, or the first three packets weren't valid
// header packets, assume bad input, and don't activate the bitstream.
mDoneReadingHeaders = PR_TRUE;
} else if (ret == 0 && isSetupHeader && mPacketCount == 3) {
// Successfully read the three header packets, activate the bitstream.
mDoneReadingHeaders = PR_TRUE;
mActive = PR_TRUE;
}
return mDoneReadingHeaders;
}
PRBool nsVorbisState::Init()
{
if (!mActive)
return PR_FALSE;
int ret = vorbis_synthesis_init(&mDsp, &mInfo);
if (ret != 0) {
NS_WARNING("vorbis_synthesis_init() failed initializing vorbis bitstream");
return mActive = PR_FALSE;
}
ret = vorbis_block_init(&mDsp, &mBlock);
if (ret != 0) {
NS_WARNING("vorbis_block_init() failed initializing vorbis bitstream");
if (mActive) {
vorbis_dsp_clear(&mDsp);
}
return mActive = PR_FALSE;
}
return PR_TRUE;
}
PRInt64 nsVorbisState::Time(PRInt64 granulepos) {
if (granulepos == -1 || !mActive || mDsp.vi->rate == 0) {
return -1;
}
PRInt64 t = 0;
MulOverflow(1000, granulepos, t);
return t / mDsp.vi->rate;
}
nsSkeletonState::nsSkeletonState(ogg_page* aBosPage)
: nsOggCodecState(aBosPage)
{
MOZ_COUNT_CTOR(nsSkeletonState);
}
nsSkeletonState::~nsSkeletonState()
{
MOZ_COUNT_DTOR(nsSkeletonState);
}
PRBool nsSkeletonState::DecodeHeader(ogg_packet* aPacket)
{
if (aPacket->e_o_s) {
mActive = PR_TRUE;
mDoneReadingHeaders = PR_TRUE;
}
return mDoneReadingHeaders;
}
// Adds two 64bit numbers, retuns PR_TRUE if addition succeeded, or PR_FALSE
// if addition would result in an overflow.
static PRBool AddOverflow(PRInt64 a, PRInt64 b, PRInt64& aResult) {
if (b < 1) {
if (PR_INT64_MIN - b <= a) {
aResult = a + b;
return PR_TRUE;
}
} else if (PR_INT64_MAX - b >= a) {
aResult = a + b;
return PR_TRUE;
}
return PR_FALSE;
}
// 64 bit integer multiplication with overflow checking. Returns PR_TRUE
// if the multiplication was successful, or PR_FALSE if the operation resulted
// in an integer overflow.
static PRBool MulOverflow(PRInt64 a, PRInt64 b, PRInt64& aResult) {
// We break a multiplication a * b into of sign_a * sign_b * abs(a) * abs(b)
//
// This is equivalent to:
//
// (sign_a * sign_b) * ((a_hi * 2^32) + a_lo) * ((b_hi * 2^32) + b_lo)
//
// Which is equivalent to:
//
// (sign_a * sign_b) *
// ((a_hi * b_hi << 64) +
// (a_hi * b_lo << 32) + (a_lo * b_hi << 32) +
// a_lo * b_lo)
//
// So to check if a*b overflows, we must check each sub part of the above
// sum.
//
// Note: -1 * PR_INT64_MIN == PR_INT64_MIN ; we can't negate PR_INT64_MIN!
// Note: Shift of negative numbers is undefined.
//
// Figure out the sign after multiplication. Then we can just work with
// unsigned numbers.
PRInt64 sign = (!(a < 0) == !(b < 0)) ? 1 : -1;
PRInt64 abs_a = (a < 0) ? -a : a;
PRInt64 abs_b = (b < 0) ? -b : b;
if (abs_a < 0) {
NS_ASSERTION(a == PR_INT64_MIN, "How else can this happen?");
if (b == 0 || b == 1) {
aResult = a * b;
return PR_TRUE;
} else {
return PR_FALSE;
}
}
if (abs_b < 0) {
NS_ASSERTION(b == PR_INT64_MIN, "How else can this happen?");
if (a == 0 || a == 1) {
aResult = a * b;
return PR_TRUE;
} else {
return PR_FALSE;
}
}
NS_ASSERTION(abs_a >= 0 && abs_b >= 0, "abs values must be non-negative");
PRInt64 a_hi = abs_a >> 32;
PRInt64 a_lo = abs_a & 0xFFFFFFFF;
PRInt64 b_hi = abs_b >> 32;
PRInt64 b_lo = abs_b & 0xFFFFFFFF;
NS_ASSERTION((a_hi<<32) + a_lo == abs_a, "Partition must be correct");
NS_ASSERTION((b_hi<<32) + b_lo == abs_b, "Partition must be correct");
// In the sub-equation (a_hi * b_hi << 64), if a_hi or b_hi
// are non-zero, this will overflow as it's shifted by 64.
// Abort if this overflows.
if (a_hi != 0 && b_hi != 0) {
return PR_FALSE;
}
// We can now assume that either a_hi or b_hi is 0.
NS_ASSERTION(a_hi == 0 || b_hi == 0, "One of these must be 0");
// Next we calculate:
// (a_hi * b_lo << 32) + (a_lo * b_hi << 32)
// We can factor this as:
// (a_hi * b_lo + a_lo * b_hi) << 32
PRInt64 q = a_hi * b_lo + a_lo * b_hi;
if (q > PR_INT32_MAX) {
// q will overflow when we shift by 32; abort.
return PR_FALSE;
}
q <<= 32;
// Both a_lo and b_lo are less than INT32_MAX, so can't overflow.
PRUint64 lo = a_lo * b_lo;
if (lo > PR_INT64_MAX) {
return PR_FALSE;
}
// Add the final result. We must check for overflow during addition.
if (!AddOverflow(q, static_cast<PRInt64>(lo), aResult)) {
return PR_FALSE;
}
aResult *= sign;
NS_ASSERTION(a * b == aResult, "We didn't overflow, but result is wrong!");
return PR_TRUE;
}

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

@ -0,0 +1,206 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: ML 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla code.
*
* The Initial Developer of the Original Code is the Mozilla Corporation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Chris Double <chris.double@double.co.nz>
* Chris Pearce <chris@pearce.org.nz>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#if !defined(nsOggCodecState_h_)
#define nsOggCodecState_h_
#include <ogg/ogg.h>
#include <theora/theoradec.h>
#include <vorbis/codec.h>
#include <nsDeque.h>
class OggPageDeallocator : public nsDequeFunctor {
virtual void* operator() (void* aPage) {
ogg_page* p = static_cast<ogg_page*>(aPage);
delete p->header;
delete p;
return nsnull;
}
};
// A queue of ogg_pages. When we read a page, and it's not from the bitstream
// which we're looking for a page for, we buffer the page in the nsOggCodecState,
// rather than pushing it immediately into the ogg_stream_state object. This
// is because if we're skipping up to the next keyframe in very large frame
// sized videos, there may be several megabytes of data between keyframes,
// and the ogg_stream_state would end up resizing its buffer every time we
// added a new 4K page to the bitstream, which kills performance on Windows.
class nsPageQueue : private nsDeque {
public:
nsPageQueue() : nsDeque(new OggPageDeallocator()) {}
~nsPageQueue() { Erase(); }
PRBool IsEmpty() { return nsDeque::GetSize() == 0; }
void Append(ogg_page* aPage);
ogg_page* PopFront() { return static_cast<ogg_page*>(nsDeque::PopFront()); }
ogg_page* PeekFront() { return static_cast<ogg_page*>(nsDeque::PeekFront()); }
void Erase() { nsDeque::Erase(); }
};
// Encapsulates the data required for decoding an ogg bitstream and for
// converting granulepos to timestamps.
class nsOggCodecState {
public:
// Ogg types we know about
enum CodecType {
TYPE_VORBIS=0,
TYPE_THEORA=1,
TYPE_SKELETON=2,
TYPE_UNKNOWN=3
};
public:
nsOggCodecState(ogg_page* aBosPage);
virtual ~nsOggCodecState();
// Factory for creating nsCodecStates.
static nsOggCodecState* Create(ogg_page* aPage);
virtual CodecType GetType() { return TYPE_UNKNOWN; }
// Reads a header packet. Returns PR_TRUE when last header has been read.
virtual PRBool DecodeHeader(ogg_packet* aPacket) {
return (mDoneReadingHeaders = PR_TRUE);
}
// Returns the end time that a granulepos represents.
virtual PRInt64 Time(PRInt64 granulepos) { return -1; }
// Returns the start time that a granulepos represents.
virtual PRInt64 StartTime(PRInt64 granulepos) { return -1; }
// Initializes the codec state.
virtual PRBool Init();
// Returns PR_TRUE when this bitstream has finished reading all its
// header packets.
PRBool DoneReadingHeaders() { return mDoneReadingHeaders; }
// Deactivates the bitstream. Only the primary video and audio bitstreams
// should be active.
void Deactivate() { mActive = PR_FALSE; }
// Resets decoding state.
virtual nsresult Reset();
// Clones a page and adds it to our buffer of pages which we'll insert to
// the bitstream at a later time (using PageInFromBuffer()). Memory stored in
// cloned pages is freed when Reset() or PageInFromBuffer() are called.
inline void AddToBuffer(ogg_page* aPage) { mBuffer.Append(aPage); }
// Returns PR_TRUE if we had a buffered page and we successfully inserted it
// into the bitstream.
PRBool PageInFromBuffer();
public:
// Number of packets read.
PRUint64 mPacketCount;
// Serial number of the bitstream.
PRUint32 mSerial;
// Ogg specific state.
ogg_stream_state mState;
// Buffer of pages which we've not yet inserted into the ogg_stream_state.
nsPageQueue mBuffer;
// Is the bitstream active; whether we're decoding and playing this bitstream.
PRPackedBool mActive;
// PR_TRUE when all headers packets have been read.
PRPackedBool mDoneReadingHeaders;
};
class nsVorbisState : public nsOggCodecState {
public:
nsVorbisState(ogg_page* aBosPage);
virtual ~nsVorbisState();
virtual CodecType GetType() { return TYPE_VORBIS; }
virtual PRBool DecodeHeader(ogg_packet* aPacket);
virtual PRInt64 Time(PRInt64 granulepos);
virtual PRBool Init();
virtual nsresult Reset();
vorbis_info mInfo;
vorbis_comment mComment;
vorbis_dsp_state mDsp;
vorbis_block mBlock;
};
class nsTheoraState : public nsOggCodecState {
public:
nsTheoraState(ogg_page* aBosPage);
virtual ~nsTheoraState();
virtual CodecType GetType() { return TYPE_THEORA; }
virtual PRBool DecodeHeader(ogg_packet* aPacket);
virtual PRInt64 Time(PRInt64 granulepos);
virtual PRInt64 StartTime(PRInt64 granulepos);
virtual PRBool Init();
// Returns the maximum number of milliseconds which a keyframe can be offset
// from any given interframe.
PRInt64 MaxKeyframeOffset();
th_info mInfo;
th_comment mComment;
th_setup_info *mSetup;
th_dec_ctx* mCtx;
// Frame duration in ms.
PRUint32 mFrameDuration;
// Number of frames per second.
float mFrameRate;
float mAspectRatio;
};
class nsSkeletonState : public nsOggCodecState {
public:
nsSkeletonState(ogg_page* aBosPage);
virtual ~nsSkeletonState();
virtual CodecType GetType() { return TYPE_SKELETON; }
virtual PRBool DecodeHeader(ogg_packet* aPacket);
virtual PRInt64 Time(PRInt64 granulepos) { return -1; }
virtual PRBool Init() { return PR_TRUE; }
};
#endif

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

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

@ -21,6 +21,7 @@
*
* Contributor(s):
* Chris Double <chris.double@double.co.nz>
* Chris Pearce <chris@pearce.org.nz>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
@ -36,55 +37,67 @@
*
* ***** END LICENSE BLOCK ***** */
/*
Each video element has two threads. The first thread, called the Decode thread,
owns the resources for downloading and reading the video file. It goes through the
file, prcessing any decoded theora and vorbis data. It handles the sending of the
audio data to the sound device and the presentation of the video data at the correct
frame rate.
Each video element has three threads.
The second thread is the step decode thread. It uses OggPlay to decode the video and
audio data. It indirectly uses an nsMediaStream to do the file reading and seeking via
Oggplay.
1) The state machine thread owns the resources for downloading and reading
the media file. It controls the lifetime of the other two threads
and renders the video data at the correct time during playback.
All file reads and seeks must occur on these two threads. Synchronisation is done via
liboggplay internal mutexes to ensure that access to the liboggplay structures is
done correctly in the presence of the threads.
2) The Audio thread writes the decoded audio data to the audio
hardware. This is done in a seperate thread to ensure that the
audio hardware gets a constant stream of data without
interruption due to decoding or diplay. At some point
libsydneyaudio will be refactored to have a callback interface
where it asks for data and an extra thread will no longer be
needed.
The step decode thread is created and destroyed in the decode thread. When decoding
needs to be done it is created and event dispatched to it to start the decode loop.
This event exits when decoding is completed or no longer required (during seeking
or shutdown).
3) The decode thread. This thread reads from the media stream and decodes
the Theora and Vorbis data. It places the decoded data in a queue
for the other threads to pull from.
All file reads and seeks must occur on either the state machine thread
or the decode thread. Synchronisation is done via a monitor owned by
nsOggDecoder.
The decode thread and the audio thread are created and destroyed in the
state machine thread. When playback needs to occur they are created and
events dispatched to them to start them. These events exit when
decoding is completed or no longer required (during seeking or
shutdown).
When the decode thread is created an event is dispatched to it. The event
runs for the lifetime of the playback of the resource. The decode thread
synchronises with the main thread via a single monitor held by the
nsOggDecoder object.
All threads have one event that is dispatched to it and that event
runs for the lifetime of the playback of the resource. State shared
between them is synchronised with the main thread via a monitor
held by the nsOggDecoder object. The decode thread also has its own
monitor to ensure that its internal state is independent of the other
threads, and to ensure that it's not hogging the monitor while decoding.
The event contains a Run method which consists of an infinite loop
that checks the state that the state machine is in and processes
operations on that state.
The events consist of a Run method which is an infinite loop that
perform the threads operation and checks the state that the state
machine is in and processes operations on that state.
The nsOggDecodeStateMachine class is the event that gets dispatched to
the decode thread. It has the following states:
The nsOggPlayStateMachine class is the event that gets dispatched to
the state machine thread. It has the following states:
DECODING_METADATA
The Ogg headers are being loaded, and things like framerate, etc are
being determined, and the first frame of audio/video data is being decoded.
DECODING
Video/Audio frames are being decoded.
The decode and audio threads are started and video frames displayed at
the required time.
SEEKING
A seek operation is in progress.
BUFFERING
Decoding is paused while data is buffered for smooth playback.
COMPLETED
The resource has completed decoding.
The resource has completed decoding, but not finished playback.
SHUTDOWN
The decoder object is about to be destroyed.
The following result in state transitions.
Shutdown()
Clean up any resources the nsOggDecodeStateMachine owns.
Clean up any resources the nsOggPlayStateMachine owns.
Decode()
Start decoding video frames.
Buffer
@ -163,7 +176,7 @@ player SHUTDOWN decoder SHUTDOWN
The general sequence of events with these objects is:
1) The video element calls Load on nsMediaDecoder. This creates the
decode thread and starts the channel for downloading the file. It
state machine thread and starts the channel for downloading the file. It
instantiates and starts the Decode state machine. The high level
LOADING state is entered, which results in the decode state machine
to start decoding metadata. These are the headers that give the
@ -188,66 +201,52 @@ The general sequence of events with these objects is:
video, if the correct frame time comes around and the decoder
play state is PLAYING.
a/v synchronisation is done by a combination of liboggplay and the
Decoder state machine. liboggplay ensures that a decoded frame of data
has both the audio samples and the YUV data for that period of time.
a/v synchronisation is handled by the stete machine thread. It examines the
audio playback time and compares this to the next frame in the queue
of frames. If it is time to play the video frame it is then displayed.
When a frame is decoded by the decode state machine it converts the
YUV encoded video to RGB and copies the sound data to an internal
FrameData object. This is stored in a queue of available decoded frames.
Included in the FrameData object is the time that that frame should
be displayed.
Frame skipping is done in the following ways:
The display state machine keeps track of the time since the last frame it
played. After decoding a frame it checks if it is time to display the next
item in the decoded frame queue. If so, it pops the item off the queue
and displays it.
1) The state machine thread will skip all frames in the video queue whose
display time is less than the current audio time. This ensures
the correct frame for the current time is always displayed.
Ideally a/v sync would take into account the actual audio clock of the
audio hardware for the sync rather than using the system clock.
Unfortunately getting valid time data out of the audio hardware has proven
to be unreliable across platforms (and even distributions in Linux) depending
on audio hardware, audio backend etc. The current approach works fine in practice
and is a compromise until this issue can be sorted. The plan is to eventually
move to synchronising using the audio hardware.
2) The decode thread will stop decoding interframes and read to the
next keyframe if it determines that decoding the remaining
interframes will cause playback issues. It detects this by:
a) If the amount of audio data in the audio queue drops
below a threshold whereby audio may start to skip.
b) If the video queue drops below a threshold where it
will be decoding video data that won't be displayed due
to the decode thread dropping the frame immediately.
To prevent audio skipping and framerate dropping it is very important to
make sure no blocking occurs during the decoding process and minimise
expensive time operations at the time a frame is to be displayed. This is
managed by immediately converting video data to RGB on decode (an expensive
operation to do at frame display time) and checking if the sound device will
not block before writing sound data to it.
YCbCr conversion is done on the decode thread when it is time to display
the video frame. This means frames that are skipped will not have the
YCbCr conversion done, improving playback.
Shutdown needs to ensure that the event posted to the decode
thread is completed. The decode thread can potentially block internally
inside liboggplay when reading, seeking, or its internal buffers containing
decoded data are full. When blocked in this manner a call from the main thread
to Shutdown() will hang.
The decode thread pushes decoded audio and videos frames into two
separate queues - one for audio and one for video. These are kept
separate to make it easy to constantly feed audio data to the sound
hardware while allowing frame skipping of video data. These queues are
threadsafe, and neither the decode, audio, or state machine thread should
be able to monopolize them, and cause starvation of the other threads.
This is fixed with a protocol to ensure that the decode event cleanly
completes. The nsMediaStream that the nsChannelReader uses has a
Cancel() method. Calling this before Shutdown() will close any
internal streams or listeners resulting in blocked i/o completing with
an error, and all future i/o on the stream having an error.
Both queues are bounded by a maximum size. When this size is reached
the decode thread will no longer decode video or audio depending on the
queue that has reached the threshold.
This causes the decode thread to exit and Shutdown() can occur.
During playback the audio thread will be idle (via a Wait() on the
monitor) if the audio queue is empty. Otherwise it constantly pops an
item off the queue and plays it with a blocking write to the audio
hardware (via nsAudioStream and libsydneyaudio).
If the decode thread is seeking then the same Cancel() operation
causes an error to be returned from the seek call to liboggplay which
exits out of the seek operation, and stops the seek state running on the
decode thread.
If the decode thread is blocked due to internal decode buffers being
full, it is unblocked during the shutdown process by calling
oggplay_prepare_for_close.
In practice the OggPlay internal buffer should never fill as we retrieve and
process the frame immediately on decoding.
The decode thread idles if the video queue is empty or if it is
not yet time to display the next frame.
The Shutdown method on nsOggDecoder can spin the event loop as it waits
for threads to complete. Spinning the event loop is a bad thing to happen
during certain times like destruction of the media element. To work around
this the Shutdown method does nothing by queue an event to the main thread
this the Shutdown method does nothing but queue an event to the main thread
to perform the actual Shutdown. This way the shutdown can occur at a safe
time.
@ -263,25 +262,27 @@ when destroying the nsOggDecoder object.
#include "nsCOMPtr.h"
#include "nsIThread.h"
#include "nsIChannel.h"
#include "nsChannelReader.h"
#include "nsIObserver.h"
#include "nsIFrame.h"
#include "nsAutoPtr.h"
#include "nsSize.h"
#include "prlog.h"
#include "prmon.h"
#include "gfxContext.h"
#include "gfxRect.h"
#include "oggplay/oggplay.h"
#include "nsMediaStream.h"
#include "nsMediaDecoder.h"
#include "mozilla/Monitor.h"
using mozilla::Monitor;
class nsAudioStream;
class nsOggDecodeStateMachine;
class nsOggStepDecodeEvent;
class nsOggPlayStateMachine;
class nsOggReader;
class nsOggDecoder : public nsMediaDecoder
{
friend class nsOggDecodeStateMachine;
friend class nsOggStepDecodeEvent;
friend class nsOggReader;
friend class nsOggPlayStateMachine;
// ISupports
NS_DECL_ISUPPORTS
@ -336,7 +337,8 @@ class nsOggDecoder : public nsMediaDecoder
virtual void NotifySuspendedStatusChanged();
virtual void NotifyBytesDownloaded();
virtual void NotifyDownloadEnded(nsresult aStatus);
// Called by nsChannelReader on the decoder thread
// Called by the decode thread to keep track of the number of bytes read
// from the resource.
void NotifyBytesConsumed(PRInt64 aBytes);
// Called when the video file has completed downloading.
@ -366,9 +368,6 @@ class nsOggDecoder : public nsMediaDecoder
// Return PR_TRUE if seeking is supported.
virtual PRBool GetSeekable();
// Returns the channel reader.
nsChannelReader* GetReader() { return mReader; }
virtual Statistics GetStatistics();
// Suspend any media downloads that are in progress. Called by the
@ -384,23 +383,25 @@ class nsOggDecoder : public nsMediaDecoder
// Tells our nsMediaStream to put all loads in the background.
virtual void MoveLoadsToBackground();
// Stop the state machine thread and drop references to the thread,
// state machine and channel reader.
// Stop the state machine thread and drop references to the thread and
// state machine.
void Stop();
// Called by the state machine to notify the decoder that the duration
// has changed.
void DurationChanged();
protected:
// Returns the monitor for other threads to synchronise access to
// state.
PRMonitor* GetMonitor()
{
Monitor& GetMonitor() {
return mMonitor;
}
// Return the current state. Can be called on any thread. If called from
// a non-main thread, the decoder monitor must be held.
PlayState GetState()
{
PlayState GetState() {
return mPlayState;
}
@ -496,8 +497,8 @@ private:
// time of the last decoded video frame).
nsChannelStatistics mPlaybackStatistics;
// Thread to handle decoding of Ogg data.
nsCOMPtr<nsIThread> mDecodeThread;
// Thread to manage playback state machine.
nsCOMPtr<nsIThread> mStateMachineThread;
// The current playback position of the media resource in units of
// seconds. This is updated approximately at the framerate of the
@ -506,14 +507,12 @@ private:
float mCurrentTime;
// Volume that playback should start at. 0.0 = muted. 1.0 = full
// volume. Readable/Writeable from the main thread. Read from the
// audio thread when it is first started to get the initial volume
// level.
// volume. Readable/Writeable from the main thread.
float mInitialVolume;
// Position to seek to when the seek notification is received by the
// decoding thread. Written by the main thread and read via the
// decoding thread. Synchronised using mPlayStateMonitor. If the
// decode thread. Written by the main thread and read via the
// decode thread. Synchronised using mMonitor. If the
// value is negative then no seek has been requested. When a seek is
// started this is reset to negative.
float mRequestedSeekTime;
@ -531,26 +530,20 @@ private:
* The following member variables can be accessed from any thread.
******/
// The state machine object for handling the decoding via
// oggplay. It is safe to call methods of this object from other
// threads. Its internal data is synchronised on a monitor. The
// lifetime of this object is after mPlayState is LOADING and before
// mPlayState is SHUTDOWN. It is safe to access it during this
// period.
nsCOMPtr<nsOggDecodeStateMachine> mDecodeStateMachine;
// The state machine object for handling the decoding. It is safe to
// call methods of this object from other threads. Its internal data
// is synchronised on a monitor. The lifetime of this object is
// after mPlayState is LOADING and before mPlayState is SHUTDOWN. It
// is safe to access it during this period.
nsCOMPtr<nsOggPlayStateMachine> mDecodeStateMachine;
// OggPlay object used to read data from a channel. Created on main
// thread. Passed to liboggplay and the locking for multithreaded
// access is handled by that library. Some methods are called from
// the decoder thread, and the state machine for that thread keeps
// a pointer to this reader. This is safe as the only methods called
// are threadsafe (via the threadsafe nsMediaStream).
nsAutoPtr<nsChannelReader> mReader;
// Stream of media data.
nsAutoPtr<nsMediaStream> mStream;
// Monitor for detecting when the video play state changes. A call
// to Wait on this monitor will block the thread until the next
// state change.
PRMonitor* mMonitor;
Monitor mMonitor;
// Set to one of the valid play states. It is protected by the
// monitor mMonitor. This monitor must be acquired when reading or

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

@ -0,0 +1,109 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: ML 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla code.
*
* The Initial Developer of the Original Code is the Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Chris Pearce <chris@pearce.org.nz>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#ifndef nsOggHacks_h
#define nsOggHacks_h
// This file contains stuff we'd rather put elsewhere, but which is
// dependent on other changes which we don't want to wait for. We plan to
// remove this file in the near future.
// This belongs in prtypes.h
/************************************************************************
* MACROS: PR_INT64_MAX
* PR_INT64_MIN
* PR_UINT64_MAX
* DESCRIPTION:
* The maximum and minimum values of a PRInt64 or PRUint64.
************************************************************************/
#define PR_INT64_MAX (~((PRInt64)(1) << 63))
#define PR_INT64_MIN (-PR_INT64_MAX - 1)
#define PR_UINT64_MAX (~(PRUint64)(0))
// This belongs in xpcom/monitor/Monitor.h, once we've made
// mozilla::Monitor non-reentrant.
namespace mozilla {
/**
* MonitorAutoExit
* Exit the Monitor when it enters scope, and enters it when it leaves
* scope.
*
* MUCH PREFERRED to bare calls to Monitor.Exit and Enter.
*/
class NS_COM_GLUE NS_STACK_CLASS MonitorAutoExit
{
public:
/**
* Constructor
* The constructor releases the given lock. The destructor
* acquires the lock. The lock must be held before constructing
* this object!
*
* @param aMonitor A valid mozilla::Monitor* returned by
* mozilla::Monitor::NewMonitor. It must be
* already locked.
**/
MonitorAutoExit(mozilla::Monitor &aMonitor) :
mMonitor(&aMonitor)
{
NS_ASSERTION(mMonitor, "null monitor");
mMonitor->AssertCurrentThreadIn();
mMonitor->Exit();
}
~MonitorAutoExit(void)
{
mMonitor->Enter();
}
private:
MonitorAutoExit();
MonitorAutoExit(const MonitorAutoExit&);
MonitorAutoExit& operator =(const MonitorAutoExit&);
static void* operator new(size_t) CPP_THROW_NEW;
static void operator delete(void*);
mozilla::Monitor* mMonitor;
};
} // namespace mozilla
#endif

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

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

@ -0,0 +1,419 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: ML 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla code.
*
* The Initial Developer of the Original Code is the Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Chris Double <chris.double@double.co.nz>
* Chris Pearce <chris@pearce.org.nz>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#if !defined(nsOggPlayStateMachine_h__)
#define nsOggPlayStateMachine_h__
#include "prmem.h"
#include "nsThreadUtils.h"
#include "nsOggReader.h"
#include "nsOggDecoder.h"
#include "nsHTMLMediaElement.h"
#include "mozilla/Monitor.h"
using mozilla::TimeDuration;
using mozilla::TimeStamp;
class nsOggDecoder;
// Checks if we're on a specific thread or not. Used in assertions to
// verify thread safety.
static inline PRBool IsThread(nsIThread* aThread) {
return NS_GetCurrentThread() == aThread;
}
/*
The playback state machine class. This manages the decoding in the
nsOggReader on the decode thread, seeking and in-sync-playback on the
state machine thread, and controls the audio "push" thread.
All internal state is synchronised via the decoder monitor. NotifyAll
on the monitor is called when the state of the state machine is changed
by the main thread. The following changes to state cause a notify:
mState and data related to that state changed (mSeekTime, etc)
Ogg Metadata Loaded
First Frame Loaded
Frame decoded
data pushed or popped from the video and audio queues
See nsOggDecoder.h for more details.
*/
class nsOggPlayStateMachine : public nsRunnable
{
public:
// Enumeration for the valid states
enum State {
DECODER_STATE_DECODING_METADATA,
DECODER_STATE_DECODING,
DECODER_STATE_SEEKING,
DECODER_STATE_BUFFERING,
DECODER_STATE_COMPLETED,
DECODER_STATE_SHUTDOWN
};
nsOggPlayStateMachine(nsOggDecoder* aDecoder);
~nsOggPlayStateMachine();
// Initializes the state machine, returns NS_OK on success, or
// NS_ERROR_FAILURE on failure.
nsresult Init();
// Cause state transitions. These methods obtain the decoder monitor
// to synchronise the change of state, and to notify other threads
// that the state has changed.
void Shutdown();
void Decode();
// Seeks to aTime seconds.
void Seek(float aTime);
// State machine thread run function. Polls the state, sends frames to be
// displayed at appropriate times, and generally manages the decode.
NS_IMETHOD Run();
// This is called on the state machine thread and audio thread.
// The decoder monitor must be obtained before calling this.
PRBool HasAudio() const {
mDecoder->GetMonitor().AssertCurrentThreadIn();
return mInfo.mHasAudio;
}
// This is called on the state machine thread and audio thread.
// The decoder monitor must be obtained before calling this.
PRBool HasVideo() const {
mDecoder->GetMonitor().AssertCurrentThreadIn();
return mInfo.mHasVideo;
}
// Returns the current playback position in seconds.
// Called from the main thread to get the current frame time. The decoder
// monitor must be obtained before calling this.
float GetCurrentTime();
// Called from the main thread to get the duration. The decoder monitor
// must be obtained before calling this. It is in units of milliseconds.
PRInt64 GetDuration();
// Called from the main thread to set the duration of the media resource
// if it is able to be obtained via HTTP headers. The decoder monitor
// must be obtained before calling this.
void SetDuration(PRInt64 aDuration);
// Called from the main thread to set whether the media resource can
// be seeked. The decoder monitor must be obtained before calling this.
void SetSeekable(PRBool aSeekable);
// Set the audio volume. The decoder monitor must be obtained before
// calling this.
void SetVolume(float aVolume);
// Clear the flag indicating that a playback position change event
// is currently queued. This is called from the main thread and must
// be called with the decode monitor held.
void ClearPositionChangeFlag();
// Should be called by main thread.
PRBool HaveNextFrameData() const {
PRUint32 audioQueueSize = mReader->mAudioQueue.GetSize();
return (mReader->mVideoQueue.GetSize() > 0 &&
(!HasAudio() || audioQueueSize > 0)) ||
audioQueueSize > 0;
}
// Must be called with the decode monitor held.
PRBool IsBuffering() const {
mDecoder->GetMonitor().AssertCurrentThreadIn();
return mState == nsOggPlayStateMachine::DECODER_STATE_BUFFERING;
}
// Must be called with the decode monitor held.
PRBool IsSeeking() const {
mDecoder->GetMonitor().AssertCurrentThreadIn();
return mState == nsOggPlayStateMachine::DECODER_STATE_SEEKING;
}
// Functions used by assertions to ensure we're calling things
// on the appropriate threads.
PRBool OnStateMachineThread() {
return IsThread(mDecoder->mStateMachineThread);
}
PRBool OnDecodeThread() {
return IsThread(mDecodeThread);
}
PRBool OnAudioThread() {
return IsThread(mAudioThread);
}
// Decode loop, called on the decode thread.
void DecodeLoop();
// The decoder object that created this state machine. The decoder
// always outlives us since it controls our lifetime. This is accessed
// read only on the AV, state machine, audio and main thread.
nsOggDecoder* mDecoder;
// Update the playback position. This can result in a timeupdate event
// and an invalidate of the frame being dispatched asynchronously if
// there is no such event currently queued.
// Only called on the decoder thread. Must be called with
// the decode monitor held.
void UpdatePlaybackPosition(PRInt64 aTime);
nsHTMLMediaElement::NextFrameStatus GetNextFrameStatus();
// The decoder monitor must be obtained before modifying this state.
// NotifyAll on the monitor must be called when the state is changed by
// the main thread so the decoder thread can wake up.
// Accessed on state machine, audio, main, and AV thread.
State mState;
private:
// Waits on the decoder Monitor for aMs. If the decoder monitor is awoken
// by a Notify() call, we'll continue waiting, unless we've moved into
// shutdown state. This enables us to ensure that we wait for a specified
// time, and that the myriad of Notify()s we do an the decoder monitor
// don't cause the audio thread to be starved. The decoder monitor must
// be locked.
void Wait(PRUint32 aMs);
// Dispatches an asynchronous event to update the media element's ready state.
void UpdateReadyState();
// Resets playback timing data. Called when we seek, on the state machine
// thread.
void ResetPlayback();
// Returns the audio clock, if we have audio, or -1 if we don't.
// Called on the state machine thread.
PRInt64 GetAudioClock();
// Returns the presentation time of the first sample or frame in the media.
// If the media has video, it returns the first video frame. The decoder
// monitor must be held with exactly one lock count. Called on the state
// machine thread.
VideoData* FindStartTime();
// Finds the end time of the last page in the Ogg file, storing the value
// in mEndTime if successful. The decoder must be held with exactly one lock
// count. Called on the state machine thread.
void FindEndTime();
// Performs YCbCr to RGB conversion, and pushes the image down the
// rendering pipeline. Called on the state machine thread.
void RenderVideoFrame(VideoData* aData);
// If we have video, display a video frame if it's time for display has
// arrived, otherwise sleep until it's time for the next sample. Update
// the current frame time as appropriate, and trigger ready state update.
// The decoder monitor must be held with exactly one lock count. Called
// on the state machine thread.
void AdvanceFrame();
// Stops the decode threads. The decoder monitor must be held with exactly
// one lock count. Called on the state machine thread.
void StopDecodeThreads();
// Starts the decode threads. The decoder monitor must be held with exactly
// one lock count. Called on the state machine thread.
nsresult StartDecodeThreads();
// Reads the Ogg headers using the nsOggReader, and initializes playback.
// Called on the state machine thread. The decoder monitor must be held with
// exactly one lock count.
void LoadOggHeaders();
// The main loop for the audio thread. Sent to the thread as
// an NS_NEW_RUNNABLE_METHOD. This continually does blocking writes to
// to audio stream to play audio data.
void AudioLoop();
// Stop or pause playback of media. This has two modes, denoted by
// aMode being either AUDIO_PAUSE or AUDIO_SHUTDOWN.
//
// AUDIO_PAUSE: Suspends the audio stream to be resumed later.
// This does not close the OS based audio stream
//
// AUDIO_SHUTDOWN: Closes and destroys the audio stream and
// releases any OS resources.
//
// The decoder monitor must be held with exactly one lock count. Called
// on the state machine thread.
enum eStopMode {AUDIO_PAUSE, AUDIO_SHUTDOWN};
void StopPlayback(eStopMode aMode);
// Resume playback of media. Must be called with the decode monitor held.
// This resumes a paused audio stream. The decoder monitor must be held with
// exactly one lock count. Called on the state machine thread.
void StartPlayback();
// Returns PR_TRUE if we're currently playing. The decoder monitor must
// be held.
PRBool IsPlaying();
// Stores presentation info about required for playback of the media.
nsOggInfo mInfo;
// Monitor on mAudioStream. This monitor must be held in order to delete
// or use the audio stream. This stops us destroying the audio stream
// while it's being used on another thread (typically when it's being
// written to on the audio thread).
Monitor mAudioMonitor;
// The reader, don't call its methods with the decoder monitor held.
// This is created in the play state machine's constructor, and destroyed
// in the play state machine's destructor.
nsAutoPtr<nsOggReader> mReader;
// The size of the decoded YCbCr frame.
// Accessed on state machine thread.
PRUint32 mCbCrSize;
// Accessed on state machine thread.
nsAutoArrayPtr<unsigned char> mCbCrBuffer;
// Thread for pushing audio onto the audio hardware.
// The "audio push thread".
nsCOMPtr<nsIThread> mAudioThread;
// Thread for decoding video in background. The "decode thread".
nsCOMPtr<nsIThread> mDecodeThread;
// The time that playback started from the system clock. This is used
// for timing the display of audio frames when there's no audio.
// Accessed only via the state machine thread.
TimeStamp mPlayStartTime;
// The amount of time we've spent playing already the media. The current
// playback position is therefore (mPlayDuration + (now - mPlayStartTime)).
// Accessed only via the state machine thread.
TimeDuration mPlayDuration;
// Time that buffering started. Used for buffering timeout and only
// accessed on the state machine thread.
TimeStamp mBufferingStart;
// Download position where we should stop buffering. Only
// accessed on the state machine thread.
PRInt64 mBufferingEndOffset;
// Start time of the media, in milliseconds. This is the presentation
// time of the first sample decoded from the media, and is used to calculate
// duration and as a bounds for seeking. Accessed on state machine and
// main thread. Access controlled by decoder monitor.
PRInt64 mStartTime;
// Time of the last page in the media, in milliseconds. This is the
// end time of the last sample in the media. Accessed on state
// machine and main thread. Access controlled by decoder monitor.
PRInt64 mEndTime;
// Position to seek to in milliseconds when the seek state transition occurs.
// The decoder monitor lock must be obtained before reading or writing
// this value. Accessed on main and state machine thread.
PRInt64 mSeekTime;
// The audio stream resource. Used on the state machine, audio, and main
// threads. You must hold the mAudioMonitor, and must NOT hold the decoder
// monitor when using the audio stream!
nsAutoPtr<nsAudioStream> mAudioStream;
// The time of the current frame in milliseconds. This is referenced from
// 0 which is the initial playback position. Set by the state machine
// thread, and read-only from the main thread to get the current
// time value. Synchronised via decoder monitor.
PRInt64 mCurrentFrameTime;
// The presentation time of the first audio sample that was played. We can
// add this to the audio stream position to determine the current audio time.
// Accessed on audio and state machine thread. Synchronized by decoder monitor.
PRInt64 mAudioStartTime;
// The end time of the last audio sample that's been pushed onto the audio
// hardware. This will approximately be the end time of the audio stream,
// unless another sample is pushed to the hardware.
PRInt64 mAudioEndTime;
// The presentation time of the last video frame which has been displayed.
// Accessed from the state machine thread.
PRInt64 mVideoFrameTime;
// Volume of playback. 0.0 = muted. 1.0 = full volume. Read/Written
// from the state machine and main threads. Synchronised via decoder
// monitor.
float mVolume;
// PR_TRUE if the media resource can be seeked. Accessed from the state
// machine and main threads. Synchronised via decoder monitor.
PRPackedBool mSeekable;
// PR_TRUE if an event to notify about a change in the playback
// position has been queued, but not yet run. It is set to PR_FALSE when
// the event is run. This allows coalescing of these events as they can be
// produced many times per second. Synchronised via decoder monitor.
// Accessed on main and state machine threads.
PRPackedBool mPositionChangeQueued;
// PR_TRUE if the audio playback thread has finished. It is finished
// when either all the audio samples in the Vorbis bitstream have completed
// playing, or we've moved into shutdown state, and the threads are to be
// destroyed. Written by the audio playback thread and read and written by
// the state machine thread. Synchronised via decoder monitor.
PRPackedBool mAudioCompleted;
// PR_TRUE if the decode thread has indicated that we need to buffer.
// Accessed by the decode thread and the state machine thread.
// Synchronised via the decoder monitor.
PRPackedBool mBufferExhausted;
// PR_TRUE if mDuration has a value obtained from an HTTP header.
// Accessed on the state machine thread.
PRPackedBool mGotDurationFromHeader;
// PR_FALSE while decode threads should be running. Accessed on audio,
// state machine and decode threads. Syncrhonised by decoder monitor.
PRPackedBool mStopDecodeThreads;
};
#endif

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

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

@ -0,0 +1,531 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim:set ts=2 sw=2 sts=2 et cindent: */
/* ***** BEGIN LICENSE BLOCK *****
* Version: ML 1.1/GPL 2.0/LGPL 2.1
*
* The contents of this file are subject to the Mozilla Public License Version
* 1.1 (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS" basis,
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
* for the specific language governing rights and limitations under the
* License.
*
* The Original Code is Mozilla code.
*
* The Initial Developer of the Original Code is the Mozilla Foundation.
* Portions created by the Initial Developer are Copyright (C) 2010
* the Initial Developer. All Rights Reserved.
*
* Contributor(s):
* Chris Double <chris.double@double.co.nz>
* Chris Pearce <chris@pearce.org.nz>
*
* Alternatively, the contents of this file may be used under the terms of
* either the GNU General Public License Version 2 or later (the "GPL"), or
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
* in which case the provisions of the GPL or the LGPL are applicable instead
* of those above. If you wish to allow use of your version of this file only
* under the terms of either the GPL or the LGPL, and not to allow others to
* use your version of this file under the terms of the MPL, indicate your
* decision by deleting the provisions above and replace them with the notice
* and other provisions required by the GPL or the LGPL. If you do not delete
* the provisions above, a recipient may use your version of this file under
* the terms of any one of the MPL, the GPL or the LGPL.
*
* ***** END LICENSE BLOCK ***** */
#if !defined(nsOggReader_h_)
#define nsOggReader_h_
#include <nsDeque.h>
#include "nsOggCodecState.h"
#include <ogg/ogg.h>
#include <theora/theoradec.h>
#include <vorbis/codec.h>
#include "prmon.h"
#include "nsAutoLock.h"
#include "nsClassHashtable.h"
#include "mozilla/TimeStamp.h"
#include "nsSize.h"
#include "nsRect.h"
#include "mozilla/Monitor.h"
class nsOggPlayStateMachine;
using mozilla::Monitor;
using mozilla::MonitorAutoEnter;
using mozilla::TimeDuration;
using mozilla::TimeStamp;
// Holds chunk a decoded sound samples.
class SoundData {
public:
SoundData(PRInt64 aTime,
PRInt64 aDuration,
PRUint32 aSamples,
float* aData,
PRUint32 aChannels)
: mTime(aTime),
mDuration(aDuration),
mSamples(aSamples),
mAudioData(aData),
mChannels(aChannels)
{
MOZ_COUNT_CTOR(SoundData);
}
SoundData(PRInt64 aDuration,
PRUint32 aSamples,
float* aData,
PRUint32 aChannels)
: mTime(-1),
mDuration(aDuration),
mSamples(aSamples),
mAudioData(aData),
mChannels(aChannels)
{
MOZ_COUNT_CTOR(SoundData);
}
~SoundData()
{
MOZ_COUNT_DTOR(SoundData);
}
PRUint32 AudioDataLength() {
return mChannels * mSamples;
}
PRInt64 mTime; // Start time of samples in ms.
const PRInt64 mDuration; // In ms.
const PRUint32 mSamples;
const PRUint32 mChannels;
nsAutoArrayPtr<float> mAudioData;
};
// Holds a decoded Theora frame, in YCbCr format. These are queued in the reader.
class VideoData {
public:
// Constructs a VideoData object. Makes a copy of YCbCr data in aBuffer.
// This may return nsnull if we run out of memory when allocating buffers
// to store the frame.
static VideoData* Create(PRInt64 aTime,
th_ycbcr_buffer aBuffer,
PRBool aKeyframe,
PRInt64 aGranulepos);
// Constructs a duplicate VideoData object. This intrinsically tells the
// player that it does not need to update the displayed frame when this
// frame is played; this frame is identical to the previous.
static VideoData* CreateDuplicate(PRInt64 aTime,
PRInt64 aGranulepos)
{
return new VideoData(aTime, aGranulepos);
}
~VideoData()
{
MOZ_COUNT_DTOR(VideoData);
for (PRUint32 i = 0; i < 3; ++i) {
delete mBuffer[i].data;
}
}
// Start time of frame in milliseconds.
PRInt64 mTime;
PRInt64 mGranulepos;
th_ycbcr_buffer mBuffer;
// When PR_TRUE, denotes that this frame is identical to the frame that
// came before; it's a duplicate. mBuffer will be empty.
PRPackedBool mDuplicate;
PRPackedBool mKeyframe;
private:
VideoData(PRInt64 aTime, PRInt64 aGranulepos) :
mTime(aTime),
mGranulepos(aGranulepos),
mDuplicate(PR_TRUE),
mKeyframe(PR_FALSE)
{
MOZ_COUNT_CTOR(VideoData);
memset(&mBuffer, 0, sizeof(th_ycbcr_buffer));
}
VideoData(PRInt64 aTime,
PRBool aKeyframe,
PRInt64 aGranulepos)
: mTime(aTime),
mGranulepos(aGranulepos),
mDuplicate(PR_FALSE),
mKeyframe(aKeyframe)
{
MOZ_COUNT_CTOR(VideoData);
}
};
// Thread and type safe wrapper around nsDeque.
template <class T>
class MediaQueueDeallocator : public nsDequeFunctor {
virtual void* operator() (void* anObject) {
delete static_cast<T*>(anObject);
return nsnull;
}
};
template <class T> class MediaQueue : private nsDeque {
public:
MediaQueue()
: nsDeque(new MediaQueueDeallocator<T>()),
mMonitor("mediaqueue"),
mEndOfStream(0)
{}
~MediaQueue() {
Reset();
}
inline PRInt32 GetSize() {
MonitorAutoEnter mon(mMonitor);
return nsDeque::GetSize();
}
inline void Push(T* aItem) {
MonitorAutoEnter mon(mMonitor);
nsDeque::Push(aItem);
}
inline void PushFront(T* aItem) {
MonitorAutoEnter mon(mMonitor);
nsDeque::PushFront(aItem);
}
inline T* Pop() {
MonitorAutoEnter mon(mMonitor);
return static_cast<T*>(nsDeque::Pop());
}
inline T* PopFront() {
MonitorAutoEnter mon(mMonitor);
return static_cast<T*>(nsDeque::PopFront());
}
inline T* Peek() {
MonitorAutoEnter mon(mMonitor);
return static_cast<T*>(nsDeque::Peek());
}
inline T* PeekFront() {
MonitorAutoEnter mon(mMonitor);
return static_cast<T*>(nsDeque::PeekFront());
}
inline void Empty() {
MonitorAutoEnter mon(mMonitor);
nsDeque::Empty();
}
inline void Erase() {
MonitorAutoEnter mon(mMonitor);
nsDeque::Erase();
}
void Reset() {
MonitorAutoEnter mon(mMonitor);
while (GetSize() > 0) {
T* x = PopFront();
delete x;
}
mEndOfStream = PR_FALSE;
}
PRBool AtEndOfStream() {
MonitorAutoEnter mon(mMonitor);
return GetSize() == 0 && mEndOfStream;
}
void Finish() {
MonitorAutoEnter mon(mMonitor);
mEndOfStream = PR_TRUE;
}
// Returns the approximate number of milliseconds of samples in the queue.
PRInt64 Duration() {
MonitorAutoEnter mon(mMonitor);
if (GetSize() < 2) {
return 0;
}
T* last = Peek();
T* first = PeekFront();
return last->mTime - first->mTime;
}
private:
Monitor mMonitor;
// PR_TRUE when we've decoded the last packet in the bitstream for which
// we're queueing sample-data.
PRBool mEndOfStream;
};
// Represents a section of contiguous media, with a start and end offset,
// and the timestamps of the start and end of that range. Used to denote the
// extremities of a range to seek in.
class ByteRange {
public:
ByteRange() :
mOffsetStart(0),
mOffsetEnd(0),
mTimeStart(0),
mTimeEnd(0)
{}
ByteRange(PRInt64 aOffsetStart,
PRInt64 aOffsetEnd,
PRInt64 aTimeStart,
PRInt64 aTimeEnd)
: mOffsetStart(aOffsetStart),
mOffsetEnd(aOffsetEnd),
mTimeStart(aTimeStart),
mTimeEnd(aTimeEnd)
{}
PRBool IsNull() {
return mOffsetStart == 0 &&
mOffsetEnd == 0 &&
mTimeStart == 0 &&
mTimeEnd == 0;
}
PRInt64 mOffsetStart, mOffsetEnd; // in bytes.
PRInt64 mTimeStart, mTimeEnd; // in ms.
};
// Stores info relevant to presenting media samples.
class nsOggInfo {
public:
nsOggInfo()
: mFramerate(0.0),
mAspectRatio(1.0),
mCallbackPeriod(1),
mAudioRate(0),
mAudioChannels(0),
mFrame(0,0),
mHasAudio(PR_FALSE),
mHasVideo(PR_FALSE)
{}
// Frames per second.
float mFramerate;
// Aspect ratio, as stored in the video header packet.
float mAspectRatio;
// Length of a video frame in milliseconds, or the callback period if
// there's no audio.
PRUint32 mCallbackPeriod;
// Samples per second.
PRUint32 mAudioRate;
// Number of audio channels.
PRUint32 mAudioChannels;
// Dimensions of the video frame.
nsIntSize mFrame;
// The picture region inside the video frame to be displayed.
nsIntRect mPicture;
// The offset of the first non-header page in the file, in bytes.
// Used to seek to the start of the media.
PRInt64 mDataOffset;
// PR_TRUE if we have an active audio bitstream.
PRPackedBool mHasAudio;
// PR_TRUE if we have an active video bitstream.
PRPackedBool mHasVideo;
};
// Encapsulates the decoding and reading of Ogg data. Reading can be done
// on either the state machine thread (when loading and seeking) or on
// the reader thread (when it's reading and decoding). The reader encapsulates
// the reading state and maintains it's own monitor to ensure thread safety
// and correctness. Never hold the nsOggDecoder's monitor when calling into
// this class.
class nsOggReader : public nsRunnable {
public:
nsOggReader(nsOggPlayStateMachine* aStateMachine);
~nsOggReader();
PRBool HasAudio()
{
MonitorAutoEnter mon(mMonitor);
return mVorbisState != 0 && mVorbisState->mActive;
}
PRBool HasVideo()
{
MonitorAutoEnter mon(mMonitor);
return mTheoraState != 0 && mTheoraState->mActive;
}
// Read header data for all bitstreams in the Ogg file. Fills aInfo with
// the data required to present the media. Returns NS_OK on success,
// or NS_ERROR_FAILURE on failure.
nsresult ReadOggHeaders(nsOggInfo& aInfo);
// Stores the presentation time of the first sample in the stream in
// aOutStartTime, and returns the first video sample, if we have video.
VideoData* FindStartTime(PRInt64 aOffset,
PRInt64& aOutStartTime);
// Returns the end time of the last page which occurs before aEndOffset.
// This will not read past aEndOffset. Returns -1 on failure.
PRInt64 FindEndTime(PRInt64 aEndOffset);
// Decodes one Vorbis page, enqueuing the audio data in mAudioQueue.
// Returns PR_TRUE when there's more audio to decode, PR_FALSE if the
// audio is finished, end of file has been reached, or an un-recoverable
// read error has occured.
PRBool DecodeAudioPage();
// Reads and decodes one video frame. If the Theora granulepos has not
// been captured, it may read several packets until one with a granulepos
// has been captured, to ensure that all packets read have valid time info.
// Packets with a timestamp less than aTimeThreshold will be decoded (unless
// they're not keyframes and aKeyframeSkip is PR_TRUE), but will not be
// added to the queue.
PRBool DecodeVideoPage(PRBool &aKeyframeSkip,
PRInt64 aTimeThreshold);
// Moves the decode head to aTime milliseconds. aStartTime and aEndTime
// denote the start and end times of the media.
nsresult Seek(PRInt64 aTime, PRInt64 aStartTime, PRInt64 aEndTime);
// Queue of audio samples. This queue is threadsafe.
MediaQueue<SoundData> mAudioQueue;
// Queue of video samples. This queue is threadsafe.
MediaQueue<VideoData> mVideoQueue;
// Initializes the reader, returns NS_OK on success, or NS_ERROR_FAILURE
// on failure.
nsresult Init();
private:
// Ogg reader decode function. Matches DecodeVideoPage() and
// DecodeAudioPage().
typedef PRBool (nsOggReader::*DecodeFn)();
// Calls aDecodeFn on *this until aQueue has a sample, whereupon
// we return the first sample.
template<class Data>
Data* DecodeToFirstData(DecodeFn aDecodeFn,
MediaQueue<Data>& aQueue);
// Wrapper so that DecodeVideoPage(PRBool&,PRInt64) can be called from
// DecodeToFirstData().
PRBool DecodeVideoPage() {
PRBool f = PR_FALSE;
return DecodeVideoPage(f, 0);
}
// Decodes one packet of Vorbis data, storing the resulting chunks of
// PCM samples in aChunks.
nsresult DecodeVorbis(nsTArray<SoundData*>& aChunks,
ogg_packet* aPacket);
// May return NS_ERROR_OUT_OF_MEMORY.
nsresult DecodeTheora(nsTArray<VideoData*>& aFrames,
ogg_packet* aPacket);
// Resets all state related to decoding, emptying all buffers etc.
nsresult ResetDecode();
// Read a page of data from the Ogg file. Returns the offset of the start
// of the page, or -1 if the page read failed.
PRInt64 ReadOggPage(ogg_page* aPage);
// Read a packet for an Ogg bitstream/codec state. Returns PR_TRUE on
// success, or PR_FALSE if the read failed.
PRBool ReadOggPacket(nsOggCodecState* aCodecState, ogg_packet* aPacket);
// Performs a seek bisection to move the media stream's read cursor to the
// last ogg page boundary which has end time before aTarget ms on both the
// Theora and Vorbis bitstreams. Limits its search to data inside aRange;
// i.e. it will only read inside of the aRange's start and end offsets.
// aFuzz is the number of ms of leniency we'll allow; we'll terminate the
// seek when we land in the range (aTime - aFuzz, aTime) ms.
nsresult SeekBisection(PRInt64 aTarget,
const ByteRange& aRange,
PRUint32 aFuzz);
// Fills aRanges with ByteRanges denoting the sections of the media which
// have been downloaded and are stored in the media cache. The reader
// monitor must must be held with exactly one lock count. The nsMediaStream
// must be pinned while calling this.
nsresult GetBufferedBytes(nsTArray<ByteRange>& aRanges);
// Returns the range in which you should perform a seek bisection if
// you wish to seek to aTarget ms, given the known (buffered) byte ranges
// in aRanges. If aExact is PR_TRUE, we only return an exact copy of a
// range in which aTarget lies, or a null range if aTarget isn't contained
// in any of the (buffered) ranges. Otherwise, when aExact is PR_FALSE,
// we'll construct the smallest possible range we can, based on the times
// and byte offsets known in aRanges. We can then use this to minimize our
// bisection's search space when the target isn't in a known buffered range.
ByteRange GetSeekRange(const nsTArray<ByteRange>& aRanges,
PRInt64 aTarget,
PRInt64 aStartTime,
PRInt64 aEndTime,
PRBool aExact);
// The lock which we hold whenever we read or decode. This ensures the thread
// safety of the reader and its data fields.
Monitor mMonitor;
// Reference to the owning player state machine object. Do not hold the
// reader's monitor when accessing the player.
nsOggPlayStateMachine* mPlayer;
// Maps Ogg serialnos to nsOggStreams.
nsClassHashtable<nsUint32HashKey, nsOggCodecState> mCodecStates;
// Decode state of the Theora bitstream we're decoding, if we have video.
nsTheoraState* mTheoraState;
// Decode state of the Vorbis bitstream we're decoding, if we have audio.
nsVorbisState* mVorbisState;
// Ogg decoding state.
ogg_sync_state mOggState;
// The offset of the end of the last page we've read, or the start of
// the page we're about to read.
PRInt64 mPageOffset;
// The offset of the start of the first non-header page in the file.
// Used to seek to media start time.
PRInt64 mDataOffset;
// The granulepos of the last decoded Theora frame.
PRInt64 mTheoraGranulepos;
// The granulepos of the last decoded Vorbis sample.
PRInt64 mVorbisGranulepos;
// Number of milliseconds of data video/audio data held in a frame.
PRUint32 mCallbackPeriod;
};
#endif

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

@ -104,6 +104,7 @@ _TEST_FILES = \
test_playback_errors.html \
test_reactivate.html \
test_readyState.html \
test_seek.html \
test_seek2.html \
test_volume.html \
use_large_cache.js \
@ -113,23 +114,17 @@ _TEST_FILES = \
# test_resume.html \
#
ifneq ($(OS_ARCH),WINNT)
# These tests are disabled on windows until we
# figure out the random failures. See bug 475369.
_TEST_FILES += \
test_seek.html \
$(NULL)
endif
# Ogg sample files
_TEST_FILES += \
320x240.ogv \
320x240.allow-origin.ogv \
320x240.allow-origin.ogv^headers^ \
448636.ogv \
audio-overhang.ogg \
beta-phrasebook.ogg \
bogus.ogv \
bug495129.ogv \
bug495794.ogg \
bug461281.ogg \
bug482461.ogv \
bug498380.ogv \
@ -157,6 +152,7 @@ _TEST_FILES += \
short-video.ogv \
small-shot.ogg \
sound.ogg \
video-overhang.ogg \
$(NULL)
# Wave sample files

Двоичные данные
content/media/test/audio-overhang.ogg Normal file

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

Двоичные данные
content/media/test/bug495794.ogg Normal file

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

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

@ -40,7 +40,7 @@ var gPlayTests = [
// Ogg stream with eof marker
{ name:"bug461281.ogg", type:"application/ogg" },
// oggz-chop stream
{ name:"bug482461.ogv", type:"video/ogg", duration:4.24 },
{ name:"bug482461.ogv", type:"video/ogg", duration:4.34 },
// With first frame a "duplicate" (empty) frame.
{ name:"bug500311.ogv", type:"video/ogg", duration:1.96 },
// Small audio file
@ -50,9 +50,10 @@ var gPlayTests = [
// First Theora data packet is zero bytes.
{ name:"bug504613.ogv", type:"video/ogg" },
// Multiple audio streams.
{ name:"bug516323.ogv", type:"video/ogg", duration:4.424 },
{ name:"bug516323.ogv", type:"video/ogg", duration:4.208 },
// Encoded with vorbis beta1, includes unusually sized codebooks
{ name:"beta-phrasebook.ogg", type:"audio/ogg", duration:4 },
{ name:"beta-phrasebook.ogg", type:"audio/ogg", duration:4.01 },
// Small file, only 1 frame with audio only.
{ name:"bug520493.ogg", type:"audio/ogg", duration:0.458 },
// Small file with vorbis comments with 0 length values and names.
@ -61,13 +62,17 @@ var gPlayTests = [
// Various weirdly formed Ogg files
{ name:"bug499519.ogv", type:"video/ogg", duration:0.24 },
{ name:"bug506094.ogv", type:"video/ogg", duration:0 },
{ name:"bug501279.ogg", type:"audio/ogg", duration:0 },
{ name:"bug498855-1.ogv", type:"video/ogg", duration:0.2 },
{ name:"bug498855-2.ogv", type:"video/ogg", duration:0.2 },
{ name:"bug498855-3.ogv", type:"video/ogg", duration:0.2 },
{ name:"bug504644.ogv", type:"video/ogg", duration:1.56 },
{ name:"bug498855-1.ogv", type:"video/ogg", duration:0.24 },
{ name:"bug498855-2.ogv", type:"video/ogg", duration:0.24 },
{ name:"bug498855-3.ogv", type:"video/ogg", duration:0.24 },
{ name:"bug504644.ogv", type:"video/ogg", duration:1.6 },
{ name:"chain.ogv", type:"video/ogg", duration:Number.NaN },
{ name:"bug523816.ogv", type:"video/ogg", duration:0.5 },
{ name:"bug523816.ogv", type:"video/ogg", duration:0.533 },
{ name:"bug495129.ogv", type:"video/ogg", duration:2.41 },
{ name:"bug498380.ogv", type:"video/ogg" },
{ name:"bug495794.ogg", type:"audio/ogg", duration:0.3},
{ name:"audio-overhang.ogg", type:"audio/ogg", duration:2.3},
{ name:"video-overhang.ogg", type:"audio/ogg", duration:3.966},
{ name:"bogus.duh", type:"bogus/duh" }
];
@ -82,9 +87,8 @@ var gErrorTests = [
{ name:"bogus.wav", type:"audio/x-wav" },
{ name:"bogus.ogv", type:"video/ogg" },
{ name:"448636.ogv", type:"video/ogg" },
{ name:"bug495129.ogv", type:"video/ogg", duration:2.52 },
{ name:"bug504843.ogv", type:"video/ogg", duration:1.233 },
{ name:"bug498380.ogv", type:"video/ogg" },
{ name:"bug504843.ogv", type:"video/ogg" },
{ name:"bug501279.ogg", type:"audio/ogg" },
{ name:"bogus.duh", type:"bogus/duh" }
];

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

@ -17,7 +17,7 @@ function startTest() {
if (completed)
return false;
var v = document.getElementById('v');
is(Math.round(v.duration*1000), 3966, "Check duration of video: " + v.duration);
is(Math.round(v.duration*1000), 3999, "Check duration of video: " + v.duration);
completed = true;
clearTimeout(timeout);
SimpleTest.finish();

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

@ -158,7 +158,7 @@ function checkState() {
"Ready state of " + gMedia.readyState + " was leaked");
test_is(gMedia.seeking, false, "Seeking leaked");
test_is(gMedia.currentTime, 0, "Leaked currentTime");
test_is(gMedia.duration, 0, "Leaked duration");
test_ok(isNaN(gMedia.duration), "Leaked duration");
test_is(gMedia.paused, true, "Paused leaked");
test_is(gMedia.ended, false, "Ended leaked");
test_is(gMedia.autoplay, false, "Autoplay leaked");

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

@ -30,7 +30,9 @@ function startTests() {
continue;
v.src = test.name;
v.name = test.name;
var check = function(test, v) { return function() {
is(test.name, v.name, "Name should match test.name #1");
checkMetadata(test.name, v, test);
}}(test, v);
var noLoad = function(test, v) { return function() {
@ -39,8 +41,9 @@ function startTests() {
var checkEnded = function(test, v) { return function() {
if (test.duration) {
ok(Math.abs(v.currentTime - test.duration) < 0.1,
test.name + " current time at end: " + v.currentTime);
test.name + " current time at end: " + v.currentTime + " should be: " + test.duration);
}
is(test.name, v.name, "Name should match test.name #2");
is(v.readyState, v.HAVE_CURRENT_DATA, test.name + " checking readyState");
ok(v.readyState != v.NETWORK_LOADED, test.name + " shouldn't report NETWORK_LOADED");
ok(v.ended, test.name + " checking playback has ended");
@ -50,6 +53,7 @@ function startTests() {
}
}}(test, v);
var checkSuspended = function(test, v) { return function() {
is(test.name, v.name, "Name should match test.name #3");
if (v.seenSuspend)
return;
@ -61,12 +65,13 @@ function startTests() {
}
}}(test, v);
v.prevTime = 0;
var timeUpdate = function(v) { return function() {
var timeUpdate = function(test, v) { return function() {
is(test.name, v.name, "Name should match test.name #4");
ok(v.prevTime <= v.currentTime,
test.name + " time should run forwards: p=" +
v.prevTime + " c=" + v.currentTime);
v.prevTime = v.currentTime;
}}(v);
}}(test, v);
v.addEventListener("load", noLoad, false);
v.addEventListener("loadedmetadata", check, false);
v.addEventListener("timeupdate", timeUpdate, false);

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

@ -29,10 +29,8 @@ function timeUpdated() {
var v = document.getElementById('v');
ok(v.currentTime > lastTime,
"Check currentTime of " +
v.currentTime +
" is greater than last time of " +
lastTime);
"currentTime (" + v.currentTime +
") should be greater than last time (" + lastTime + ")");
lastTime = v.currentTime;
return false;
}

Двоичные данные
content/media/test/video-overhang.ogg Normal file

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

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

@ -648,7 +648,7 @@ nsWaveStateMachine::Run()
PRUint32 lengthInSamples = got / sampleSize;
monitor.Exit();
mAudioStream->Write(buf.get(), lengthInSamples);
mAudioStream->Write(buf.get(), lengthInSamples, PR_FALSE);
monitor.Enter();
FirePositionChanged(PR_FALSE);

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

@ -124,36 +124,7 @@ public:
PRUint32 Serial() const { return mSerial; }
void SetSerial(PRUint32 aIndex) { mSerial = aIndex; }
nsrefcnt AddRef()
{
if (mRefCnt == PR_UINT32_MAX) {
NS_WARNING("refcount overflow, leaking nsSMILInstanceTime");
return mRefCnt;
}
NS_ASSERT_OWNINGTHREAD(_class);
NS_ABORT_IF_FALSE(_mOwningThread.GetThread() == PR_GetCurrentThread(),
"nsSMILInstanceTime addref isn't thread-safe!");
++mRefCnt;
NS_LOG_ADDREF(this, mRefCnt, "nsSMILInstanceTime", sizeof(*this));
return mRefCnt;
}
nsrefcnt Release()
{
if (mRefCnt == PR_UINT32_MAX) {
NS_WARNING("refcount overflow, leaking nsSMILInstanceTime");
return mRefCnt;
}
NS_ABORT_IF_FALSE(_mOwningThread.GetThread() == PR_GetCurrentThread(),
"nsSMILInstanceTime release isn't thread-safe!");
--mRefCnt;
NS_LOG_RELEASE(this, mRefCnt, "nsSMILInstanceTime");
if (mRefCnt == 0) {
delete this;
return 0;
}
return mRefCnt;
}
NS_INLINE_DECL_REFCOUNTING(nsSMILInstanceTime)
protected:
void SetBaseInterval(nsSMILInterval* aBaseInterval);
@ -162,9 +133,6 @@ protected:
nsSMILTimeValue mTime;
nsAutoRefCnt mRefCnt;
NS_DECL_OWNINGTHREAD
// Internal flags used for represent behaviour of different instance times`
enum {
// Indicates if this instance time should be removed when the owning timed

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

@ -1132,7 +1132,7 @@ MappedAttrParser::ParseMappedAttrValue(nsIAtom* aMappedAttrName,
nsCSSProps::LookupProperty(nsAtomString(aMappedAttrName));
PRBool changed; // outparam for ParseProperty. (ignored)
mParser.ParseProperty(propertyID, aMappedAttrValue, mDocURI, mBaseURI,
mNodePrincipal, mDecl, &changed);
mNodePrincipal, mDecl, &changed, PR_FALSE);
}
already_AddRefed<nsICSSStyleRule>

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

@ -41,6 +41,7 @@
#include "nsSVGValue.h"
#include <math.h>
#include "nsContentUtils.h"
#include "nsISupportsImpl.h"
const double radPerDegree = 2.0*3.1415926535 / 360.0;

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

@ -71,6 +71,7 @@
#include "nsIDOMSVGMatrix.h"
#include "gfxMatrix.h"
#include "nsAutoPtr.h"
nsresult
NS_NewSVGMatrix(nsIDOMSVGMatrix** result,

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

@ -24,6 +24,7 @@ load 415192-1.xul
load 420233-1.xhtml
load 421997-1.xhtml
load 432813-1.xhtml
load 454820-1.html
load 460665-1.xhtml
load 464863-1.xhtml
load 472260-1.xhtml

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

@ -46,6 +46,7 @@
#include "nsClassHashtable.h"
#include "nsTArray.h"
#include "nsCycleCollectionParticipant.h"
#include "nsISupportsImpl.h"
class nsXBLPrototypeBinding;
class nsIContent;
@ -77,24 +78,7 @@ public:
* which are queued to fire their constructors.
*/
nsrefcnt AddRef()
{
++mRefCnt;
NS_LOG_ADDREF(this, mRefCnt, "nsXBLBinding", sizeof(nsXBLBinding));
return mRefCnt;
}
nsrefcnt Release()
{
--mRefCnt;
NS_LOG_RELEASE(this, mRefCnt, "nsXBLBinding");
if (mRefCnt == 0) {
mRefCnt = 1;
delete this;
return 0;
}
return mRefCnt;
}
NS_INLINE_DECL_REFCOUNTING(nsXBLBinding)
NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(nsXBLBinding)
@ -172,7 +156,6 @@ public:
// MEMBER VARIABLES
protected:
nsAutoRefCnt mRefCnt;
nsXBLPrototypeBinding* mPrototypeBinding; // Weak, but we're holding a ref to the docinfo
nsCOMPtr<nsIContent> mContent; // Strong. Our anonymous content stays around with us.
nsRefPtr<nsXBLBinding> mNextBinding; // Strong. The derived binding owns the base class bindings.

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