mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-09 19:35:51 +00:00
Merge from mozilla-central.
This commit is contained in:
commit
f34bcf8448
@ -853,6 +853,11 @@ nsAccessible::ChildAtPoint(PRInt32 aX, PRInt32 aY,
|
||||
// the DOM parent chain.
|
||||
nsDocAccessible* contentDocAcc = GetAccService()->
|
||||
GetDocAccessible(content->OwnerDoc());
|
||||
|
||||
// contentDocAcc in some circumstances can be NULL
|
||||
// See https://bugzilla.mozilla.org/show_bug.cgi?id=729861
|
||||
NS_ENSURE_TRUE(contentDocAcc, fallbackAnswer);
|
||||
|
||||
nsAccessible* accessible = contentDocAcc->GetAccessibleOrContainer(content);
|
||||
if (!accessible)
|
||||
return fallbackAnswer;
|
||||
|
@ -106,6 +106,7 @@ pref("mozilla.widget.force-24bpp", true);
|
||||
pref("mozilla.widget.use-buffer-pixmap", true);
|
||||
pref("mozilla.widget.disable-native-theme", true);
|
||||
pref("layout.reflow.synthMouseMove", false);
|
||||
pref("dom.send_after_paint_to_content", true);
|
||||
|
||||
/* download manager (don't show the window or alert) */
|
||||
pref("browser.download.useDownloadDir", true);
|
||||
@ -353,9 +354,6 @@ pref("urlclassifier.gethashtables", "goog-phish-shavar,goog-malware-shavar");
|
||||
// the database.
|
||||
pref("urlclassifier.confirm-age", 2700);
|
||||
|
||||
// Maximum size of the sqlite3 cache during an update, in bytes
|
||||
pref("urlclassifier.updatecachemax", 4194304);
|
||||
|
||||
// URL for checking the reason for a malware warning.
|
||||
pref("browser.safebrowsing.malware.reportURL", "http://safebrowsing.clients.google.com/safebrowsing/diagnostic?client=%NAME%&hl=%LOCALE%&site=");
|
||||
#endif
|
||||
@ -392,6 +390,7 @@ pref("layers.acceleration.force-enabled", true);
|
||||
// screen.enabled and screen.brightness properties.
|
||||
pref("dom.screenEnabledProperty.enabled", true);
|
||||
pref("dom.screenBrightnessProperty.enabled", true);
|
||||
pref("dom.mozScreenWhitelist", "http://localhost:7777");
|
||||
|
||||
// handle links targeting new windows
|
||||
// 1=current window/tab, 2=new window, 3=new tab in most recent window
|
||||
@ -430,6 +429,10 @@ pref("layout.frame_rate.precise", true);
|
||||
pref("b2g.remote-js.enabled", true);
|
||||
pref("b2g.remote-js.port", 9999);
|
||||
|
||||
// Handle hardware buttons in the b2g chrome package
|
||||
pref("b2g.keys.menu.enabled", true);
|
||||
pref("b2g.keys.search.enabled", false);
|
||||
|
||||
// Screen timeout in minutes
|
||||
pref("power.screen.timeout", 60);
|
||||
|
||||
|
@ -37,6 +37,23 @@ XPCOMUtils.defineLazyServiceGetter(Services, 'fm', function(){
|
||||
.getService(Ci.nsFocusManager);
|
||||
});
|
||||
|
||||
|
||||
#ifndef MOZ_WIDGET_GONK
|
||||
// In order to use http:// scheme instead of file:// scheme
|
||||
// (that is much more restricted) the following code kick-off
|
||||
// a local http server listening on http://127.0.0.1:7777 and
|
||||
// http://localhost:7777.
|
||||
function startupHttpd(baseDir, port) {
|
||||
const httpdURL = 'chrome://browser/content/httpd.js';
|
||||
let httpd = {};
|
||||
Services.scriptloader.loadSubScript(httpdURL, httpd);
|
||||
let server = new httpd.nsHttpServer();
|
||||
server.registerDirectory('/', new LocalFile(baseDir));
|
||||
server.registerContentType('appcache', 'text/cache-manifest');
|
||||
server.start(port);
|
||||
}
|
||||
#endif
|
||||
|
||||
// FIXME Bug 707625
|
||||
// until we have a proper security model, add some rights to
|
||||
// the pre-installed web applications
|
||||
@ -105,7 +122,21 @@ var shell = {
|
||||
|
||||
let fileScheme = 'file://';
|
||||
if (homeURL.substring(0, fileScheme.length) == fileScheme) {
|
||||
#ifndef MOZ_WIDGET_GONK
|
||||
homeURL = homeURL.replace(fileScheme, '');
|
||||
|
||||
let baseDir = homeURL.split('/');
|
||||
baseDir.pop();
|
||||
baseDir = baseDir.join('/');
|
||||
|
||||
const SERVER_PORT = 7777;
|
||||
startupHttpd(baseDir, SERVER_PORT);
|
||||
|
||||
let baseHost = 'http://localhost';
|
||||
homeURL = homeURL.replace(baseDir, baseHost + ':' + SERVER_PORT);
|
||||
#else
|
||||
homeURL = 'http://localhost:7777' + homeURL.replace(fileScheme, '');
|
||||
#endif
|
||||
}
|
||||
addPermissions([homeURL]);
|
||||
} catch (e) {
|
||||
@ -213,10 +244,12 @@ var shell = {
|
||||
case 'AppCommand':
|
||||
switch (evt.command) {
|
||||
case 'Menu':
|
||||
this.sendEvent(content, 'menu');
|
||||
if (Services.prefs.getBoolPref('b2g.keys.menu.enabled'))
|
||||
this.sendEvent(content, 'menu');
|
||||
break;
|
||||
case 'Search':
|
||||
this.toggleDebug();
|
||||
if (Services.prefs.getBoolPref('b2g.keys.search.enabled'))
|
||||
this.toggleDebug();
|
||||
break;
|
||||
case 'VolumeUp':
|
||||
this.changeVolume(1);
|
||||
|
@ -20,11 +20,18 @@
|
||||
#ifndef MOZ_TOUCH
|
||||
<script type="application/javascript" src="chrome://browser/content/touch.js"/>
|
||||
#endif
|
||||
#ifndef MOZ_WIDGET_GONK
|
||||
<script type="application/javascript" src="chrome://browser/content/httpd.js"/>
|
||||
#endif
|
||||
|
||||
<commandset id="mainCommandSet">
|
||||
<command id="cmd_close" oncommand="CommandUpdater.doCommand(this.id);"/>
|
||||
</commandset>
|
||||
|
||||
<browser id="homescreen" type="content-primary" flex="1" style="overflow: hidden;"/>
|
||||
<browser id="homescreen"
|
||||
type="content-primary"
|
||||
flex="1"
|
||||
style="overflow: hidden;"
|
||||
src="data:text/html;base64,PCFET0NUWVBFIGh0bWw+PGh0bWw+PGJvZHkgc3R5bGU9ImJhY2tncm91bmQ6YmxhY2s7Ij48L2JvZHk+PC9odG1sPgo="/>
|
||||
</window>
|
||||
|
||||
|
@ -84,6 +84,18 @@ XPCOMUtils.defineLazyGetter(Services, 'fm', function() {
|
||||
content.dispatchEvent(event);
|
||||
}
|
||||
|
||||
function maybeShowIme(targetElement) {
|
||||
// FIXME/bug 729623: work around apparent bug in the IME manager
|
||||
// in gecko.
|
||||
let readonly = targetElement.getAttribute('readonly');
|
||||
if (readonly)
|
||||
return false;
|
||||
|
||||
let type = targetElement.type;
|
||||
fireEvent('showime', { type: type });
|
||||
return true;
|
||||
}
|
||||
|
||||
let constructor = {
|
||||
handleEvent: function vkm_handleEvent(evt) {
|
||||
switch (evt.type) {
|
||||
@ -102,9 +114,7 @@ XPCOMUtils.defineLazyGetter(Services, 'fm', function() {
|
||||
if (evt.target != activeElement || isKeyboardOpened)
|
||||
return;
|
||||
|
||||
let type = activeElement.type;
|
||||
fireEvent('showime', { type: type });
|
||||
isKeyboardOpened = true;
|
||||
isKeyboardOpened = maybeShowIme(activeElement);
|
||||
break;
|
||||
}
|
||||
},
|
||||
@ -112,11 +122,10 @@ XPCOMUtils.defineLazyGetter(Services, 'fm', function() {
|
||||
let shouldOpen = parseInt(data);
|
||||
if (shouldOpen && !isKeyboardOpened) {
|
||||
activeElement = Services.fm.focusedElement;
|
||||
if (!activeElement)
|
||||
if (!activeElement || !maybeShowIme(activeElement)) {
|
||||
activeElement = null;
|
||||
return;
|
||||
|
||||
let type = activeElement.type;
|
||||
fireEvent('showime', { type: type });
|
||||
}
|
||||
} else if (!shouldOpen && isKeyboardOpened) {
|
||||
fireEvent('hideime');
|
||||
}
|
||||
@ -313,7 +322,7 @@ const KineticPanning = {
|
||||
return this.target !== null;
|
||||
},
|
||||
|
||||
_target: null,
|
||||
target: null,
|
||||
start: function kp_start(target) {
|
||||
this.target = target;
|
||||
|
||||
|
@ -5,12 +5,14 @@ chrome.jar:
|
||||
% content browser %content/
|
||||
|
||||
* content/shell.xul (content/shell.xul)
|
||||
content/shell.js (content/shell.js)
|
||||
* content/shell.js (content/shell.js)
|
||||
#ifndef MOZ_TOUCH
|
||||
content/touch.js (content/touch.js)
|
||||
#endif
|
||||
content/commandUtil.js (content/commandUtil.js)
|
||||
#ifndef MOZ_WIDGET_GONK
|
||||
content/httpd.js (content/httpd.js)
|
||||
#endif
|
||||
content/webapi.js (content/webapi.js)
|
||||
content/content.css (content/content.css)
|
||||
|
||||
|
@ -759,12 +759,6 @@ pref("urlclassifier.gethashtables", "goog-phish-shavar,goog-malware-shavar");
|
||||
// the database.
|
||||
pref("urlclassifier.confirm-age", 2700);
|
||||
|
||||
// Maximum size of the sqlite3 cache during an update, in bytes
|
||||
pref("urlclassifier.updatecachemax", 41943040);
|
||||
|
||||
// Maximum size of the sqlite3 cache for lookups, in bytes
|
||||
pref("urlclassifier.lookupcachemax", 1048576);
|
||||
|
||||
// URL for checking the reason for a malware warning.
|
||||
pref("browser.safebrowsing.malware.reportURL", "http://safebrowsing.clients.google.com/safebrowsing/diagnostic?client=%NAME%&hl=%LOCALE%&site=");
|
||||
|
||||
|
@ -165,24 +165,25 @@ var StarUI = {
|
||||
return;
|
||||
}
|
||||
|
||||
var loadObserver = {
|
||||
_self: this,
|
||||
_itemId: aItemId,
|
||||
_anchorElement: aAnchorElement,
|
||||
_position: aPosition,
|
||||
observe: function (aSubject, aTopic, aData) {
|
||||
this._overlayLoading = true;
|
||||
document.loadOverlay(
|
||||
"chrome://browser/content/places/editBookmarkOverlay.xul",
|
||||
(function (aSubject, aTopic, aData) {
|
||||
//XXX We just caused localstore.rdf to be re-applied (bug 640158)
|
||||
retrieveToolbarIconsizesFromTheme();
|
||||
|
||||
this._self._overlayLoading = false;
|
||||
this._self._overlayLoaded = true;
|
||||
this._self._doShowEditBookmarkPanel(this._itemId, this._anchorElement,
|
||||
this._position);
|
||||
}
|
||||
};
|
||||
this._overlayLoading = true;
|
||||
document.loadOverlay("chrome://browser/content/places/editBookmarkOverlay.xul",
|
||||
loadObserver);
|
||||
// Move the header (star, title, button) into the grid,
|
||||
// so that it aligns nicely with the other items (bug 484022).
|
||||
let header = this._element("editBookmarkPanelHeader");
|
||||
let rows = this._element("editBookmarkPanelGrid").lastChild;
|
||||
rows.insertBefore(header, rows.firstChild);
|
||||
header.hidden = false;
|
||||
|
||||
this._overlayLoading = false;
|
||||
this._overlayLoaded = true;
|
||||
this._doShowEditBookmarkPanel(aItemId, aAnchorElement, aPosition);
|
||||
}).bind(this)
|
||||
);
|
||||
},
|
||||
|
||||
_doShowEditBookmarkPanel:
|
||||
@ -192,13 +193,6 @@ var StarUI = {
|
||||
|
||||
this._blockCommands(); // un-done in the popuphiding handler
|
||||
|
||||
// Move the header (star, title, possibly a button) into the grid,
|
||||
// so that it aligns nicely with the other items (bug 484022).
|
||||
var rows = this._element("editBookmarkPanelGrid").lastChild;
|
||||
var header = this._element("editBookmarkPanelHeader");
|
||||
rows.insertBefore(header, rows.firstChild);
|
||||
header.hidden = false;
|
||||
|
||||
// Set panel title:
|
||||
// if we are batching, i.e. the bookmark has been added now,
|
||||
// then show Page Bookmarked, else if the bookmark did already exist,
|
||||
|
@ -3573,7 +3573,6 @@ const BrowserSearch = {
|
||||
loadAddEngines: function BrowserSearch_loadAddEngines() {
|
||||
var newWindowPref = gPrefService.getIntPref("browser.link.open_newwindow");
|
||||
var where = newWindowPref == 3 ? "tab" : "window";
|
||||
var regionBundle = document.getElementById("bundle_browser_region");
|
||||
var searchEnginesURL = formatURL("browser.search.searchEnginesURL", true);
|
||||
openUILinkIn(searchEnginesURL, where);
|
||||
}
|
||||
|
@ -224,7 +224,6 @@ FirefoxProfileMigrator.prototype = {
|
||||
migrate : function Firefox_migrate(aItems, aStartup, aProfile)
|
||||
{
|
||||
if (aStartup) {
|
||||
aStartup.doStartup();
|
||||
this._replaceBookmarks = true;
|
||||
}
|
||||
|
||||
@ -246,6 +245,11 @@ FirefoxProfileMigrator.prototype = {
|
||||
if (aItems & MIGRATOR.PASSWORDS)
|
||||
this._migratePasswords();
|
||||
|
||||
// The password manager encryption key must be copied before startup.
|
||||
if (aStartup) {
|
||||
aStartup.doStartup();
|
||||
}
|
||||
|
||||
if (aItems & MIGRATOR.FORMDATA)
|
||||
this._migrateFormData();
|
||||
|
||||
|
@ -153,6 +153,7 @@ var gEngineManagerDialog = {
|
||||
while (Services.prompt.prompt(window, title, msg, alias, null, {})) {
|
||||
var bduplicate = false;
|
||||
var eduplicate = false;
|
||||
var dupName = "";
|
||||
|
||||
if (alias.value != "") {
|
||||
try {
|
||||
@ -168,6 +169,7 @@ var gEngineManagerDialog = {
|
||||
if (engine.alias == alias.value &&
|
||||
engine.name != selectedEngine.name) {
|
||||
eduplicate = true;
|
||||
dupName = engine.name;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -177,8 +179,7 @@ var gEngineManagerDialog = {
|
||||
if (eduplicate || bduplicate) {
|
||||
var dtitle = strings.getString("duplicateTitle");
|
||||
var bmsg = strings.getString("duplicateBookmarkMsg");
|
||||
var emsg = strings.getFormattedString("duplicateEngineMsg",
|
||||
[engine.name]);
|
||||
var emsg = strings.getFormattedString("duplicateEngineMsg", [dupName]);
|
||||
|
||||
Services.prompt.alert(window, dtitle, eduplicate ? emsg : bmsg);
|
||||
} else {
|
||||
|
@ -50,9 +50,9 @@
|
||||
]>
|
||||
|
||||
<bindings id="SearchBindings"
|
||||
xmlns="http://www.mozilla.org/xbl"
|
||||
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
xmlns:xbl="http://www.mozilla.org/xbl">
|
||||
xmlns="http://www.mozilla.org/xbl"
|
||||
xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
xmlns:xbl="http://www.mozilla.org/xbl">
|
||||
|
||||
<binding id="searchbar">
|
||||
<resources>
|
||||
@ -96,13 +96,12 @@
|
||||
<xul:image class="search-go-button"
|
||||
anonid="search-go-button"
|
||||
onclick="handleSearchCommand(event);"
|
||||
tooltiptext="&searchEndCap.label;" />
|
||||
tooltiptext="&searchEndCap.label;"/>
|
||||
</xul:hbox>
|
||||
</xul:textbox>
|
||||
</content>
|
||||
|
||||
<implementation implements="nsIObserver">
|
||||
|
||||
<constructor><![CDATA[
|
||||
if (this.parentNode.parentNode.localName == "toolbarpaletteitem")
|
||||
return;
|
||||
@ -164,7 +163,7 @@
|
||||
<getter><![CDATA[
|
||||
var currentEngine = this.searchService.currentEngine;
|
||||
// Return a dummy engine if there is no currentEngine
|
||||
return currentEngine || {name:"", uri:null};
|
||||
return currentEngine || {name: "", uri: null};
|
||||
]]></getter>
|
||||
</property>
|
||||
|
||||
@ -335,7 +334,8 @@
|
||||
// indexes as items are removed.
|
||||
var items = popup.childNodes;
|
||||
for (var i = items.length - 1; i >= 0; i--) {
|
||||
if (items[i].getAttribute("class").indexOf("addengine") != -1)
|
||||
if (items[i].classList.contains("addengine-item") ||
|
||||
items[i].classList.contains("addengine-separator"))
|
||||
popup.removeChild(items[i]);
|
||||
}
|
||||
|
||||
@ -444,7 +444,7 @@
|
||||
<body><![CDATA[
|
||||
// Find the new index
|
||||
var newIndex = this.engines.indexOf(this.currentEngine);
|
||||
newIndex += (isNextEngine) ? 1 : -1;
|
||||
newIndex += isNextEngine ? 1 : -1;
|
||||
|
||||
if (newIndex >= 0 && newIndex < this.engines.length)
|
||||
this.currentEngine = this.engines[newIndex];
|
||||
@ -495,13 +495,12 @@
|
||||
openUILinkIn(submission.uri.spec, aWhere, null, submission.postData);
|
||||
]]></body>
|
||||
</method>
|
||||
|
||||
</implementation>
|
||||
|
||||
<handlers>
|
||||
<handler event="command"><![CDATA[
|
||||
const target = event.originalTarget;
|
||||
if (target.getAttribute("class").indexOf("addengine-item") != -1) {
|
||||
if (target.classList.contains("addengine-item")) {
|
||||
var searchService =
|
||||
Components.classes["@mozilla.org/browser/search-service;1"]
|
||||
.getService(Components.interfaces.nsIBrowserSearchService);
|
||||
@ -719,7 +718,7 @@
|
||||
</body>
|
||||
</method>
|
||||
|
||||
<!-- overload |onTextEntered| in autocomplete.xml -->
|
||||
<!-- override |onTextEntered| in autocomplete.xml -->
|
||||
<method name="onTextEntered">
|
||||
<parameter name="aEvent"/>
|
||||
<body><![CDATA[
|
||||
|
@ -164,6 +164,7 @@
|
||||
@BINPATH@/components/dom_indexeddb.xpt
|
||||
@BINPATH@/components/dom_offline.xpt
|
||||
@BINPATH@/components/dom_json.xpt
|
||||
@BINPATH@/components/dom_power.xpt
|
||||
@BINPATH@/components/dom_range.xpt
|
||||
@BINPATH@/components/dom_sidebar.xpt
|
||||
@BINPATH@/components/dom_sms.xpt
|
||||
|
@ -169,11 +169,11 @@ libs:: $(addsuffix .xml,$(SEARCH_PLUGINS))
|
||||
done
|
||||
|
||||
install:: $(addsuffix .xml,$(SEARCH_PLUGINS))
|
||||
$(NSINSTALL) -D $(DESTDIR)$mozappdir/searchplugins
|
||||
$(NSINSTALL) -D $(DESTDIR)$(mozappdir)/searchplugins
|
||||
for i in $^; do \
|
||||
SEARCH_PLUGIN_BASE=`basename $$SEARCH_PLUGIN`;\
|
||||
$(PYTHON) $(topsrcdir)/config/Preprocessor.py $(DEFINES) $(ACDEFINES) \
|
||||
$$SEARCH_PLUGIN > $(DESTDIR)$mozappdir/searchplugins/$$SEARCH_PLUGIN_BASE; \
|
||||
$$SEARCH_PLUGIN > $(DESTDIR)$(mozappdir)/searchplugins/$$SEARCH_PLUGIN_BASE; \
|
||||
done
|
||||
|
||||
|
||||
|
@ -75,13 +75,13 @@ OrganizerQueryAllBookmarks=All Bookmarks
|
||||
OrganizerQueryTags=Tags
|
||||
|
||||
# LOCALIZATION NOTE (tagResultLabel) :
|
||||
# This is what we use to form the label (for screen readers)
|
||||
# for url bar autocomplete results of type "tag"
|
||||
# Noun used to describe the location bar autocomplete result type
|
||||
# to users with screen readers
|
||||
# See createResultLabel() in urlbarBindings.xml
|
||||
tagResultLabel=Tag
|
||||
# LOCALIZATION NOTE (bookmarkResultLabel) :
|
||||
# This is what we use to form the label (for screen readers)
|
||||
# for url bar autocomplete results of type "bookmark"
|
||||
# Noun used to describe the location bar autocomplete result type
|
||||
# to users with screen readers
|
||||
# See createResultLabel() in urlbarBindings.xml
|
||||
bookmarkResultLabel=Bookmark
|
||||
|
||||
|
@ -61,7 +61,6 @@ class DMError(Exception):
|
||||
def __str__(self):
|
||||
return self.msg
|
||||
|
||||
|
||||
def abstractmethod(method):
|
||||
line = method.func_code.co_firstlineno
|
||||
filename = method.func_code.co_filename
|
||||
@ -70,9 +69,18 @@ def abstractmethod(method):
|
||||
'should be implemented by a concrete class' %
|
||||
(repr(method), filename,line))
|
||||
return not_implemented
|
||||
|
||||
|
||||
class DeviceManager:
|
||||
|
||||
|
||||
@abstractmethod
|
||||
def shell(self, cmd, outputfile, env=None, cwd=None):
|
||||
"""
|
||||
executes shell command on device
|
||||
returns:
|
||||
success: Return code from command
|
||||
failure: None
|
||||
"""
|
||||
|
||||
@abstractmethod
|
||||
def pushFile(self, localname, destname):
|
||||
"""
|
||||
@ -168,25 +176,27 @@ class DeviceManager:
|
||||
success: array of process tuples
|
||||
failure: None
|
||||
"""
|
||||
|
||||
|
||||
@abstractmethod
|
||||
def fireProcess(self, appname, failIfRunning=False):
|
||||
"""
|
||||
external function
|
||||
DEPRECATED: Use shell() or launchApplication() for new code
|
||||
returns:
|
||||
success: pid
|
||||
failure: None
|
||||
"""
|
||||
|
||||
|
||||
@abstractmethod
|
||||
def launchProcess(self, cmd, outputFile = "process.txt", cwd = '', env = '', failIfRunning=False):
|
||||
"""
|
||||
external function
|
||||
DEPRECATED: Use shell() or launchApplication() for new code
|
||||
returns:
|
||||
success: output filename
|
||||
failure: None
|
||||
"""
|
||||
|
||||
|
||||
def communicate(self, process, timeout = 600, interval = 5):
|
||||
"""
|
||||
loops until 'process' has exited or 'timeout' seconds is reached
|
||||
@ -581,3 +591,35 @@ class NetworkTools:
|
||||
print "Socket error trying to find open port"
|
||||
|
||||
return seed
|
||||
|
||||
def _pop_last_line(file):
|
||||
'''
|
||||
Utility function to get the last line from a file (shared between ADB and
|
||||
SUT device managers). Function also removes it from the file. Intended to
|
||||
strip off the return code from a shell command.
|
||||
'''
|
||||
bytes_from_end = 1
|
||||
file.seek(0, 2)
|
||||
length = file.tell() + 1
|
||||
while bytes_from_end <= length:
|
||||
file.seek((-1)*bytes_from_end, 2)
|
||||
data = file.read()
|
||||
|
||||
if bytes_from_end == length and len(data) == 0: # no data, return None
|
||||
return None
|
||||
|
||||
if data[0] == '\n' or bytes_from_end == length:
|
||||
# found the last line, which should have the return value
|
||||
if data[0] == '\n':
|
||||
data = data[1:]
|
||||
|
||||
# truncate off the return code line
|
||||
file.truncate(length - bytes_from_end)
|
||||
file.seek(0,2)
|
||||
file.write('\0')
|
||||
|
||||
return data
|
||||
|
||||
bytes_from_end += 1
|
||||
|
||||
return None
|
||||
|
@ -1,5 +1,5 @@
|
||||
import subprocess
|
||||
from devicemanager import DeviceManager, DMError
|
||||
from devicemanager import DeviceManager, DMError, _pop_last_line
|
||||
import re
|
||||
import os
|
||||
import sys
|
||||
@ -63,6 +63,47 @@ class DeviceManagerADB(DeviceManager):
|
||||
else:
|
||||
print "restarting as root failed"
|
||||
|
||||
# external function: executes shell command on device
|
||||
# returns:
|
||||
# success: <return code>
|
||||
# failure: None
|
||||
def shell(self, cmd, outputfile, env=None, cwd=None):
|
||||
# need to quote special characters here
|
||||
for (index, arg) in enumerate(cmd):
|
||||
if arg.find(" ") or arg.find("(") or arg.find(")") or arg.find("\""):
|
||||
cmd[index] = '\'%s\'' % arg
|
||||
|
||||
# This is more complex than you'd think because adb doesn't actually
|
||||
# return the return code from a process, so we have to capture the output
|
||||
# to get it
|
||||
# FIXME: this function buffers all output of the command into memory,
|
||||
# always. :(
|
||||
cmdline = subprocess.list2cmdline(cmd) + "; echo $?"
|
||||
|
||||
# prepend cwd and env to command if necessary
|
||||
if cwd:
|
||||
cmdline = "cd %s; %s" % (cwd, cmdline)
|
||||
if env:
|
||||
envstr = '; '.join(map(lambda x: 'export %s=%s' % (x[0], x[1]), env.iteritems()))
|
||||
cmdline = envstr + "; " + cmdline
|
||||
|
||||
# all output should be in stdout
|
||||
proc = subprocess.Popen(["adb", "shell", cmdline],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
(stdout, stderr) = proc.communicate()
|
||||
outputfile.write(stdout.rstrip('\n'))
|
||||
|
||||
lastline = _pop_last_line(outputfile)
|
||||
if lastline:
|
||||
m = re.search('([0-9]+)', lastline)
|
||||
if m:
|
||||
return_code = m.group(1)
|
||||
outputfile.seek(-2, 2)
|
||||
outputfile.truncate() # truncate off the return code
|
||||
return return_code
|
||||
|
||||
return None
|
||||
|
||||
# external function
|
||||
# returns:
|
||||
# success: True
|
||||
@ -264,6 +305,7 @@ class DeviceManagerADB(DeviceManager):
|
||||
return ret
|
||||
|
||||
# external function
|
||||
# DEPRECATED: Use shell() or launchApplication() for new code
|
||||
# returns:
|
||||
# success: pid
|
||||
# failure: None
|
||||
@ -275,6 +317,7 @@ class DeviceManagerADB(DeviceManager):
|
||||
return self.launchProcess(parts, failIfRunning)
|
||||
|
||||
# external function
|
||||
# DEPRECATED: Use shell() or launchApplication() for new code
|
||||
# returns:
|
||||
# success: output filename
|
||||
# failure: None
|
||||
@ -327,6 +370,7 @@ class DeviceManagerADB(DeviceManager):
|
||||
if name == appname:
|
||||
p = self.runCmdAs(["shell", "kill", pid])
|
||||
return p.stdout.read()
|
||||
|
||||
return None
|
||||
|
||||
# external function
|
||||
@ -611,7 +655,7 @@ class DeviceManagerADB(DeviceManager):
|
||||
args.insert(1, "run-as")
|
||||
args.insert(2, self.packageName)
|
||||
args.insert(0, "adb")
|
||||
return subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
return subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
|
||||
|
||||
def runCmdAs(self, args):
|
||||
if self.useRunAs:
|
||||
|
@ -47,7 +47,18 @@ import subprocess
|
||||
from threading import Thread
|
||||
import traceback
|
||||
import sys
|
||||
from devicemanager import DeviceManager, DMError, FileError, NetworkTools
|
||||
import StringIO
|
||||
from devicemanager import DeviceManager, DMError, FileError, NetworkTools, _pop_last_line
|
||||
|
||||
class AgentError(Exception):
|
||||
"SUTAgent-specific exception."
|
||||
|
||||
def __init__(self, msg= '', fatal = False):
|
||||
self.msg = msg
|
||||
self.fatal = fatal
|
||||
|
||||
def __str__(self):
|
||||
return self.msg
|
||||
|
||||
class DeviceManagerSUT(DeviceManager):
|
||||
host = ''
|
||||
@ -76,7 +87,7 @@ class DeviceManagerSUT(DeviceManager):
|
||||
self._sock = None
|
||||
self.getDeviceRoot()
|
||||
|
||||
def cmdNeedsResponse(self, cmd):
|
||||
def _cmdNeedsResponse(self, cmd):
|
||||
""" Not all commands need a response from the agent:
|
||||
* if the cmd matches the pushRE then it is the first half of push
|
||||
and therefore we want to wait until the second half before looking
|
||||
@ -93,18 +104,44 @@ class DeviceManagerSUT(DeviceManager):
|
||||
for c in noResponseCmds:
|
||||
if (c.match(cmd)):
|
||||
return False
|
||||
|
||||
|
||||
# If the command is not in our list, then it gets a response
|
||||
return True
|
||||
|
||||
def shouldCmdCloseSocket(self, cmd):
|
||||
def _stripPrompt(self, data):
|
||||
'''
|
||||
internal function
|
||||
take a data blob and strip instances of the prompt '$>\x00'
|
||||
'''
|
||||
promptre = re.compile(self.prompt_regex + '.*')
|
||||
retVal = []
|
||||
lines = data.split('\n')
|
||||
for line in lines:
|
||||
foundPrompt = False
|
||||
try:
|
||||
while (promptre.match(line)):
|
||||
foundPrompt = True
|
||||
pieces = line.split(self.prompt_sep)
|
||||
index = pieces.index('$>')
|
||||
pieces.pop(index)
|
||||
line = self.prompt_sep.join(pieces)
|
||||
except(ValueError):
|
||||
pass
|
||||
|
||||
# we don't want to append lines that are blank after stripping the
|
||||
# prompt (those are basically "prompts")
|
||||
if not foundPrompt or line:
|
||||
retVal.append(line)
|
||||
|
||||
return '\n'.join(retVal)
|
||||
|
||||
def _shouldCmdCloseSocket(self, cmd):
|
||||
""" Some commands need to close the socket after they are sent:
|
||||
* push
|
||||
* rebt
|
||||
* uninst
|
||||
* quit
|
||||
"""
|
||||
|
||||
socketClosingCmds = [re.compile('^push .*$'),
|
||||
re.compile('^quit.*'),
|
||||
re.compile('^rebt.*'),
|
||||
@ -116,85 +153,86 @@ class DeviceManagerSUT(DeviceManager):
|
||||
|
||||
return False
|
||||
|
||||
# convenience function to enable checks for agent errors
|
||||
def verifySendCMD(self, cmdline, newline = True):
|
||||
return self.sendCMD(cmdline, newline, False)
|
||||
|
||||
|
||||
#
|
||||
# create a wrapper for sendCMD that loops up to self.retrylimit iterations.
|
||||
# this allows us to move the retry logic outside of the _doCMD() to make it
|
||||
# easier for debugging in the future.
|
||||
# note that since cmdline is a list of commands, they will all be retried if
|
||||
# one fails. this is necessary in particular for pushFile(), where we don't want
|
||||
# to accidentally send extra data if a failure occurs during data transmission.
|
||||
#
|
||||
def sendCMD(self, cmdline, newline = True, ignoreAgentErrors = True):
|
||||
def sendCmds(self, cmdlist, outputfile, timeout = None, newline = True):
|
||||
'''
|
||||
a wrapper for _doCmds that loops up to self.retrylimit iterations.
|
||||
this allows us to move the retry logic outside of the _doCmds() to make it
|
||||
easier for debugging in the future.
|
||||
note that since cmdlist is a list of commands, they will all be retried if
|
||||
one fails. this is necessary in particular for pushFile(), where we don't want
|
||||
to accidentally send extra data if a failure occurs during data transmission.
|
||||
'''
|
||||
done = False
|
||||
while (not done):
|
||||
retVal = self._doCMD(cmdline, newline)
|
||||
if (retVal is None):
|
||||
while self.retries < self.retrylimit:
|
||||
try:
|
||||
self._doCmds(cmdlist, outputfile, timeout, newline)
|
||||
return
|
||||
except AgentError, err:
|
||||
# re-raise error if it's fatal (i.e. the device got the command but
|
||||
# couldn't execute it). retry otherwise
|
||||
if err.fatal:
|
||||
raise err
|
||||
if self.debug >= 2:
|
||||
print err
|
||||
self.retries += 1
|
||||
else:
|
||||
self.retries = 0
|
||||
if ignoreAgentErrors == False:
|
||||
if (self.agentErrorRE.match(retVal)):
|
||||
raise DMError("error on the agent executing '%s'" % cmdline)
|
||||
return retVal
|
||||
|
||||
if (self.retries >= self.retrylimit):
|
||||
done = True
|
||||
raise AgentError("unable to connect to %s after %s attempts" % (self.host, self.retrylimit))
|
||||
|
||||
raise DMError("unable to connect to %s after %s attempts" % (self.host, self.retrylimit))
|
||||
def runCmds(self, cmdlist, timeout = None, newline = True):
|
||||
'''
|
||||
similar to sendCmds, but just returns any output as a string instead of
|
||||
writing to a file. this is normally what you want to call to send a set
|
||||
of commands to the agent
|
||||
'''
|
||||
outputfile = StringIO.StringIO()
|
||||
self.sendCmds(cmdlist, outputfile, timeout, newline)
|
||||
outputfile.seek(0)
|
||||
return outputfile.read()
|
||||
|
||||
def _doCMD(self, cmdline, newline = True):
|
||||
def _doCmds(self, cmdlist, outputfile, timeout, newline):
|
||||
promptre = re.compile(self.prompt_regex + '$')
|
||||
data = ""
|
||||
shouldCloseSocket = False
|
||||
recvGuard = 1000
|
||||
|
||||
if (self._sock == None):
|
||||
if not self._sock:
|
||||
try:
|
||||
if (self.debug >= 1):
|
||||
if self.debug >= 1:
|
||||
print "reconnecting socket"
|
||||
self._sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
except:
|
||||
self._sock = None
|
||||
if (self.debug >= 2):
|
||||
print "unable to create socket"
|
||||
return None
|
||||
|
||||
raise AgentError("unable to create socket")
|
||||
|
||||
try:
|
||||
self._sock.connect((self.host, int(self.port)))
|
||||
self._sock.recv(1024)
|
||||
except:
|
||||
self._sock.close()
|
||||
self._sock = None
|
||||
if (self.debug >= 2):
|
||||
print "unable to connect socket"
|
||||
return None
|
||||
|
||||
for cmd in cmdline:
|
||||
raise AgentError("unable to connect socket")
|
||||
|
||||
for cmd in cmdlist:
|
||||
if newline: cmd += '\r\n'
|
||||
|
||||
|
||||
try:
|
||||
numbytes = self._sock.send(cmd)
|
||||
if (numbytes != len(cmd)):
|
||||
print "ERROR: our cmd was " + str(len(cmd)) + " bytes and we only sent " + str(numbytes)
|
||||
return None
|
||||
raise AgentError("ERROR: our cmd was %s bytes and we only sent %s" % (len(cmd),
|
||||
numbytes))
|
||||
if (self.debug >= 4): print "send cmd: " + str(cmd)
|
||||
except:
|
||||
self._sock.close()
|
||||
self._sock = None
|
||||
return None
|
||||
|
||||
return False
|
||||
|
||||
# Check if the command should close the socket
|
||||
shouldCloseSocket = self.shouldCmdCloseSocket(cmd)
|
||||
shouldCloseSocket = self._shouldCmdCloseSocket(cmd)
|
||||
|
||||
# Handle responses from commands
|
||||
if (self.cmdNeedsResponse(cmd)):
|
||||
if (self._cmdNeedsResponse(cmd)):
|
||||
found = False
|
||||
loopguard = 0
|
||||
data = ""
|
||||
|
||||
while (found == False and (loopguard < recvGuard)):
|
||||
temp = ''
|
||||
@ -207,14 +245,14 @@ class DeviceManagerSUT(DeviceManager):
|
||||
except:
|
||||
self._sock.close()
|
||||
self._sock = None
|
||||
return None
|
||||
raise AgentError("Error receiving data from socket")
|
||||
|
||||
data += temp
|
||||
|
||||
# If something goes wrong in the agent it will send back a string that
|
||||
# starts with '##AGENT-ERROR##'
|
||||
if self.agentErrorRE.match(data):
|
||||
break
|
||||
raise AgentError("Agent Error processing command: %s" % cmd, fatal=True)
|
||||
|
||||
for line in data.splitlines():
|
||||
if promptre.match(line):
|
||||
@ -222,40 +260,54 @@ class DeviceManagerSUT(DeviceManager):
|
||||
data = self._stripPrompt(data)
|
||||
break
|
||||
|
||||
# periodically flush data to output file to make sure it doesn't get
|
||||
# too big/unwieldly
|
||||
if len(data) > 1024:
|
||||
outputfile.write(data[0:1024])
|
||||
data = data[1024:]
|
||||
|
||||
# If we violently lose the connection to the device, this loop tends to spin,
|
||||
# this guard prevents that
|
||||
if (temp == ''):
|
||||
loopguard += 1
|
||||
|
||||
if (shouldCloseSocket == True):
|
||||
# Write any remaining data to outputfile
|
||||
outputfile.write(data)
|
||||
|
||||
if shouldCloseSocket:
|
||||
try:
|
||||
self._sock.close()
|
||||
self._sock = None
|
||||
except:
|
||||
self._sock = None
|
||||
return None
|
||||
raise AgentError("Error closing socket")
|
||||
|
||||
return data
|
||||
|
||||
# internal function
|
||||
# take a data blob and strip instances of the prompt '$>\x00'
|
||||
def _stripPrompt(self, data):
|
||||
promptre = re.compile(self.prompt_regex + '.*')
|
||||
retVal = []
|
||||
lines = data.split('\n')
|
||||
for line in lines:
|
||||
try:
|
||||
while (promptre.match(line)):
|
||||
pieces = line.split(self.prompt_sep)
|
||||
index = pieces.index('$>')
|
||||
pieces.pop(index)
|
||||
line = self.prompt_sep.join(pieces)
|
||||
except(ValueError):
|
||||
pass
|
||||
retVal.append(line)
|
||||
# external function: executes shell command on device
|
||||
# returns:
|
||||
# success: <return code>
|
||||
# failure: None
|
||||
def shell(self, cmd, outputfile, env=None, cwd=None):
|
||||
cmdline = subprocess.list2cmdline(cmd)
|
||||
if env:
|
||||
cmdline = '%s %s' % (self.formatEnvString(env), cmdline)
|
||||
|
||||
return '\n'.join(retVal)
|
||||
|
||||
try:
|
||||
if cwd:
|
||||
self.sendCmds(['execcwd %s %s' % (cwd, cmdline)], outputfile)
|
||||
else:
|
||||
self.sendCmds(['exec %s' % cmdline], outputfile)
|
||||
except AgentError:
|
||||
return None
|
||||
|
||||
# dig through the output to get the return code
|
||||
lastline = _pop_last_line(outputfile)
|
||||
if lastline:
|
||||
m = re.search('return code \[([0-9]+)\]', lastline)
|
||||
if m:
|
||||
return m.group(1)
|
||||
|
||||
# woops, we couldn't find an end of line/return value
|
||||
return None
|
||||
|
||||
# external function
|
||||
# returns:
|
||||
@ -286,8 +338,8 @@ class DeviceManagerSUT(DeviceManager):
|
||||
f.close()
|
||||
|
||||
try:
|
||||
retVal = self.verifySendCMD(['push ' + destname + ' ' + str(filesize) + '\r\n', data], newline = False)
|
||||
except(DMError):
|
||||
retVal = self.runCmds(['push ' + destname + ' ' + str(filesize) + '\r\n', data], newline = False)
|
||||
except AgentError:
|
||||
retVal = False
|
||||
|
||||
if (self.debug >= 3): print "push returned: " + str(retVal)
|
||||
@ -323,8 +375,8 @@ class DeviceManagerSUT(DeviceManager):
|
||||
return name
|
||||
else:
|
||||
try:
|
||||
retVal = self.verifySendCMD(['mkdr ' + name])
|
||||
except(DMError):
|
||||
retVal = self.runCmds(['mkdr ' + name])
|
||||
except AgentError:
|
||||
retVal = None
|
||||
return retVal
|
||||
|
||||
@ -376,8 +428,8 @@ class DeviceManagerSUT(DeviceManager):
|
||||
match = ".*" + dirname + "$"
|
||||
dirre = re.compile(match)
|
||||
try:
|
||||
data = self.verifySendCMD(['cd ' + dirname, 'cwd'])
|
||||
except(DMError):
|
||||
data = self.runCmds(['cd ' + dirname, 'cwd'])
|
||||
except AgentError:
|
||||
return False
|
||||
|
||||
found = False
|
||||
@ -412,8 +464,8 @@ class DeviceManagerSUT(DeviceManager):
|
||||
if (self.dirExists(rootdir) == False):
|
||||
return []
|
||||
try:
|
||||
data = self.verifySendCMD(['cd ' + rootdir, 'ls'])
|
||||
except(DMError):
|
||||
data = self.runCmds(['cd ' + rootdir, 'ls'])
|
||||
except AgentError:
|
||||
return []
|
||||
|
||||
files = filter(lambda x: x, data.splitlines())
|
||||
@ -429,8 +481,8 @@ class DeviceManagerSUT(DeviceManager):
|
||||
def removeFile(self, filename):
|
||||
if (self.debug>= 2): print "removing file: " + filename
|
||||
try:
|
||||
retVal = self.verifySendCMD(['rm ' + filename])
|
||||
except(DMError):
|
||||
retVal = self.runCmds(['rm ' + filename])
|
||||
except AgentError:
|
||||
return None
|
||||
|
||||
return retVal
|
||||
@ -442,8 +494,8 @@ class DeviceManagerSUT(DeviceManager):
|
||||
# failure: None
|
||||
def removeDir(self, remoteDir):
|
||||
try:
|
||||
retVal = self.verifySendCMD(['rmdr ' + remoteDir])
|
||||
except(DMError):
|
||||
retVal = self.runCmds(['rmdr ' + remoteDir])
|
||||
except AgentError:
|
||||
return None
|
||||
|
||||
return retVal
|
||||
@ -454,8 +506,8 @@ class DeviceManagerSUT(DeviceManager):
|
||||
# failure: []
|
||||
def getProcessList(self):
|
||||
try:
|
||||
data = self.verifySendCMD(['ps'])
|
||||
except DMError:
|
||||
data = self.runCmds(['ps'])
|
||||
except AgentError:
|
||||
return []
|
||||
|
||||
files = []
|
||||
@ -470,6 +522,7 @@ class DeviceManagerSUT(DeviceManager):
|
||||
return files
|
||||
|
||||
# external function
|
||||
# DEPRECATED: Use shell() or launchApplication() for new code
|
||||
# returns:
|
||||
# success: pid
|
||||
# failure: None
|
||||
@ -486,8 +539,8 @@ class DeviceManagerSUT(DeviceManager):
|
||||
return None
|
||||
|
||||
try:
|
||||
data = self.verifySendCMD(['exec ' + appname])
|
||||
except(DMError):
|
||||
data = self.runCmds(['exec ' + appname])
|
||||
except AgentError:
|
||||
return None
|
||||
|
||||
# wait up to 30 seconds for process to start up
|
||||
@ -503,6 +556,7 @@ class DeviceManagerSUT(DeviceManager):
|
||||
return process
|
||||
|
||||
# external function
|
||||
# DEPRECATED: Use shell() or launchApplication() for new code
|
||||
# returns:
|
||||
# success: output filename
|
||||
# failure: None
|
||||
@ -532,8 +586,8 @@ class DeviceManagerSUT(DeviceManager):
|
||||
# failure: None
|
||||
def killProcess(self, appname):
|
||||
try:
|
||||
data = self.verifySendCMD(['kill ' + appname])
|
||||
except(DMError):
|
||||
data = self.runCmds(['kill ' + appname])
|
||||
except AgentError:
|
||||
return None
|
||||
|
||||
return data
|
||||
@ -544,8 +598,8 @@ class DeviceManagerSUT(DeviceManager):
|
||||
# failure: None
|
||||
def getTempDir(self):
|
||||
try:
|
||||
data = self.verifySendCMD(['tmpd'])
|
||||
except(DMError):
|
||||
data = self.runCmds(['tmpd'])
|
||||
except AgentError:
|
||||
return None
|
||||
|
||||
return data.strip()
|
||||
@ -556,12 +610,12 @@ class DeviceManagerSUT(DeviceManager):
|
||||
# failure: None
|
||||
def catFile(self, remoteFile):
|
||||
try:
|
||||
data = self.verifySendCMD(['cat ' + remoteFile])
|
||||
except(DMError):
|
||||
data = self.runCmds(['cat ' + remoteFile])
|
||||
except AgentError:
|
||||
return None
|
||||
|
||||
return data
|
||||
|
||||
|
||||
# external function
|
||||
# returns:
|
||||
# success: output of pullfile, string
|
||||
@ -625,8 +679,8 @@ class DeviceManagerSUT(DeviceManager):
|
||||
# or, if error,
|
||||
# <filename>,-1\n<error message>
|
||||
try:
|
||||
data = self.verifySendCMD(['pull ' + remoteFile])
|
||||
except(DMError):
|
||||
data = self.runCmds(['pull ' + remoteFile])
|
||||
except AgentError:
|
||||
return None
|
||||
|
||||
# read metadata; buffer the rest
|
||||
@ -744,8 +798,8 @@ class DeviceManagerSUT(DeviceManager):
|
||||
# Throws a FileError exception when null (invalid dir/filename)
|
||||
def isDir(self, remotePath):
|
||||
try:
|
||||
data = self.verifySendCMD(['isdir ' + remotePath])
|
||||
except(DMError):
|
||||
data = self.runCmds(['isdir ' + remotePath])
|
||||
except AgentError:
|
||||
# normally there should be no error here; a nonexistent file/directory will
|
||||
# return the string "<filename>: No such file or directory".
|
||||
# However, I've seen AGENT-WARNING returned before.
|
||||
@ -780,8 +834,8 @@ class DeviceManagerSUT(DeviceManager):
|
||||
# failure: None
|
||||
def getRemoteHash(self, filename):
|
||||
try:
|
||||
data = self.verifySendCMD(['hash ' + filename])
|
||||
except(DMError):
|
||||
data = self.runCmds(['hash ' + filename])
|
||||
except AgentError:
|
||||
return None
|
||||
|
||||
retVal = None
|
||||
@ -809,7 +863,7 @@ class DeviceManagerSUT(DeviceManager):
|
||||
# failure: None
|
||||
def getDeviceRoot(self):
|
||||
try:
|
||||
data = self.verifySendCMD(['testroot'])
|
||||
data = self.runCmds(['testroot'])
|
||||
except:
|
||||
return None
|
||||
|
||||
@ -823,7 +877,7 @@ class DeviceManagerSUT(DeviceManager):
|
||||
|
||||
def getAppRoot(self, packageName):
|
||||
try:
|
||||
data = self.verifySendCMD(['getapproot '+packageName])
|
||||
data = self.runCmds(['getapproot '+packageName])
|
||||
except:
|
||||
return None
|
||||
|
||||
@ -851,8 +905,8 @@ class DeviceManagerSUT(DeviceManager):
|
||||
return None
|
||||
|
||||
try:
|
||||
data = self.verifySendCMD(['cd ' + dir, 'unzp ' + filename])
|
||||
except(DMError):
|
||||
data = self.runCmds(['cd ' + dir, 'unzp ' + filename])
|
||||
except AgentError:
|
||||
return None
|
||||
|
||||
return data
|
||||
@ -872,8 +926,8 @@ class DeviceManagerSUT(DeviceManager):
|
||||
try:
|
||||
destname = '/data/data/com.mozilla.SUTAgentAndroid/files/update.info'
|
||||
data = "%s,%s\rrebooting\r" % (ipAddr, port)
|
||||
self.verifySendCMD(['push ' + destname + ' ' + str(len(data)) + '\r\n', data], newline = False)
|
||||
except(DMError):
|
||||
self.runCmds(['push ' + destname + ' ' + str(len(data)) + '\r\n', data], newline = False)
|
||||
except AgentError:
|
||||
return None
|
||||
|
||||
ip, port = self.getCallbackIpAndPort(ipAddr, port)
|
||||
@ -882,8 +936,8 @@ class DeviceManagerSUT(DeviceManager):
|
||||
callbacksvr = callbackServer(ip, port, self.debug)
|
||||
|
||||
try:
|
||||
status = self.verifySendCMD([cmd])
|
||||
except(DMError):
|
||||
status = self.runCmds([cmd])
|
||||
except AgentError:
|
||||
return None
|
||||
|
||||
if (ipAddr is not None):
|
||||
@ -918,7 +972,7 @@ class DeviceManagerSUT(DeviceManager):
|
||||
directives = [directive]
|
||||
|
||||
for d in directives:
|
||||
data = self.verifySendCMD(['info ' + d])
|
||||
data = self.runCmds(['info ' + d])
|
||||
if (data is None):
|
||||
continue
|
||||
data = collapseSpaces.sub(' ', data)
|
||||
@ -955,8 +1009,8 @@ class DeviceManagerSUT(DeviceManager):
|
||||
if destPath:
|
||||
cmd += ' ' + destPath
|
||||
try:
|
||||
data = self.verifySendCMD([cmd])
|
||||
except(DMError):
|
||||
data = self.runCmds([cmd])
|
||||
except AgentError:
|
||||
return None
|
||||
|
||||
f = re.compile('Failure')
|
||||
@ -981,8 +1035,8 @@ class DeviceManagerSUT(DeviceManager):
|
||||
if installPath:
|
||||
cmd += ' ' + installPath
|
||||
try:
|
||||
data = self.verifySendCMD([cmd])
|
||||
except(DMError):
|
||||
data = self.runCmds([cmd])
|
||||
except AgentError:
|
||||
return None
|
||||
|
||||
if (self.debug > 3): print "uninstallAppAndReboot: " + str(data)
|
||||
@ -1026,8 +1080,8 @@ class DeviceManagerSUT(DeviceManager):
|
||||
if (self.debug >= 3): print "INFO: updateApp using command: " + str(cmd)
|
||||
|
||||
try:
|
||||
status = self.verifySendCMD([cmd])
|
||||
except(DMError):
|
||||
status = self.runCmds([cmd])
|
||||
except AgentError:
|
||||
return None
|
||||
|
||||
if ipAddr is not None:
|
||||
@ -1046,8 +1100,8 @@ class DeviceManagerSUT(DeviceManager):
|
||||
# failure: None
|
||||
def getCurrentTime(self):
|
||||
try:
|
||||
data = self.verifySendCMD(['clok'])
|
||||
except(DMError):
|
||||
data = self.runCmds(['clok'])
|
||||
except AgentError:
|
||||
return None
|
||||
|
||||
return data.strip()
|
||||
@ -1079,8 +1133,8 @@ class DeviceManagerSUT(DeviceManager):
|
||||
return None
|
||||
|
||||
try:
|
||||
data = self.verifySendCMD(['cd ' + dir, 'unzp ' + filename])
|
||||
except(DMError):
|
||||
data = self.runCmds(['cd ' + dir, 'unzp ' + filename])
|
||||
except AgentError:
|
||||
return None
|
||||
|
||||
return data
|
||||
@ -1150,9 +1204,9 @@ class DeviceManagerSUT(DeviceManager):
|
||||
|
||||
if (self.debug >= 3): print "INFO: adjusting screen resolution to %s, %s and rebooting" % (width, height)
|
||||
try:
|
||||
self.verifySendCMD(["exec setprop persist.tegra.dpy%s.mode.width %s" % (screentype, width)])
|
||||
self.verifySendCMD(["exec setprop persist.tegra.dpy%s.mode.height %s" % (screentype, height)])
|
||||
except(DMError):
|
||||
self.runCmds(["exec setprop persist.tegra.dpy%s.mode.width %s" % (screentype, width)])
|
||||
self.runCmds(["exec setprop persist.tegra.dpy%s.mode.height %s" % (screentype, height)])
|
||||
except AgentError:
|
||||
return False
|
||||
|
||||
return True
|
||||
|
87
build/mobile/droid.py
Normal file
87
build/mobile/droid.py
Normal file
@ -0,0 +1,87 @@
|
||||
# ***** 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 Test Automation Framework.
|
||||
#
|
||||
# The Initial Developer of the Original Code is
|
||||
# Mozilla foundation
|
||||
#
|
||||
# Portions created by the Initial Developer are Copyright (C) 2009
|
||||
# the Initial Developer. All Rights Reserved.
|
||||
#
|
||||
# Contributor(s):
|
||||
# Joel Maher <joel.maher@gmail.com> (Original Developer)
|
||||
# William Lachance <wlachance@mozilla.com>
|
||||
#
|
||||
# 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 *****
|
||||
|
||||
from devicemanagerADB import DeviceManagerADB
|
||||
from devicemanagerSUT import DeviceManagerSUT
|
||||
|
||||
class DroidMixin(object):
|
||||
"""Mixin to extend DeviceManager with Android-specific functionality"""
|
||||
|
||||
def launchApplication(self, app, activity="App",
|
||||
intent="android.intent.action.VIEW", env=None,
|
||||
url=None, extra_args=None):
|
||||
"""
|
||||
Launches an Android application
|
||||
returns:
|
||||
success: True
|
||||
failure: False
|
||||
"""
|
||||
# only one instance of an application may be running at once
|
||||
if self.processExist(app):
|
||||
return False
|
||||
|
||||
acmd = [ "am", "start", "-a", intent, "-W", "-n", "%s/.%s" % (app, activity)]
|
||||
|
||||
if extra_args:
|
||||
acmd.extend(["--es", "args", " ".join(args)])
|
||||
|
||||
if env:
|
||||
envCnt = 0
|
||||
# env is expected to be a dict of environment variables
|
||||
for envkey, envval in env.iteritems():
|
||||
acmd.extend(["--es", "env" + str(envCnt), envkey + "=" + envval])
|
||||
envCnt += 1
|
||||
|
||||
if url:
|
||||
acmd.extend(["-d", ''.join(['"', url, '"'])])
|
||||
|
||||
# shell output not that interesting and debugging logs should already
|
||||
# show what's going on here... so just create an empty memory buffer
|
||||
# and ignore
|
||||
shellOutput = StringIO.StringIO()
|
||||
if self.shell(acmd, shellOutput) == 0:
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
class DroidADB(DeviceManagerADB, DroidMixin):
|
||||
pass
|
||||
|
||||
class DroidSUT(DeviceManagerSUT, DroidMixin):
|
||||
pass
|
@ -136,12 +136,13 @@ public class DoCommand {
|
||||
String ffxProvider = "org.mozilla.ffxcp";
|
||||
String fenProvider = "org.mozilla.fencp";
|
||||
|
||||
private final String prgVersion = "SUTAgentAndroid Version 1.05";
|
||||
private final String prgVersion = "SUTAgentAndroid Version 1.06";
|
||||
|
||||
public enum Command
|
||||
{
|
||||
RUN ("run"),
|
||||
EXEC ("exec"),
|
||||
EXECCWD ("execcwd"),
|
||||
ENVRUN ("envrun"),
|
||||
KILL ("kill"),
|
||||
PS ("ps"),
|
||||
@ -692,7 +693,25 @@ public class DoCommand {
|
||||
theArgs[lcv - 1] = Argv[lcv];
|
||||
}
|
||||
|
||||
strReturn = StartPrg2(theArgs, cmdOut);
|
||||
strReturn = StartPrg2(theArgs, cmdOut, null);
|
||||
}
|
||||
else
|
||||
{
|
||||
strReturn = sErrorPrefix + "Wrong number of arguments for " + Argv[0] + " command!";
|
||||
}
|
||||
break;
|
||||
|
||||
case EXECCWD:
|
||||
if (Argc >= 3)
|
||||
{
|
||||
String [] theArgs = new String [Argc - 2];
|
||||
|
||||
for (int lcv = 2; lcv < Argc; lcv++)
|
||||
{
|
||||
theArgs[lcv - 2] = Argv[lcv];
|
||||
}
|
||||
|
||||
strReturn = StartPrg2(theArgs, cmdOut, Argv[1]);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1262,6 +1281,11 @@ private void CancelNotification()
|
||||
{
|
||||
String sRet = null;
|
||||
|
||||
File tmpFile = new java.io.File("/data/local/tests");
|
||||
if (tmpFile.exists() && tmpFile.isDirectory())
|
||||
{
|
||||
return("/data/local");
|
||||
}
|
||||
if (Environment.getExternalStorageState().equalsIgnoreCase(Environment.MEDIA_MOUNTED))
|
||||
{
|
||||
sRet = Environment.getExternalStorageDirectory().getAbsolutePath();
|
||||
@ -3463,7 +3487,7 @@ private void CancelNotification()
|
||||
return (sRet);
|
||||
}
|
||||
|
||||
public String StartPrg2(String [] progArray, OutputStream out)
|
||||
public String StartPrg2(String [] progArray, OutputStream out, String cwd)
|
||||
{
|
||||
String sRet = "";
|
||||
|
||||
@ -3553,7 +3577,15 @@ private void CancelNotification()
|
||||
|
||||
if (theArgs[0].contains("/") || theArgs[0].contains("\\") || !theArgs[0].contains("."))
|
||||
{
|
||||
pProc = Runtime.getRuntime().exec(theArgs, envArray);
|
||||
if (cwd != null)
|
||||
{
|
||||
File f = new File(cwd);
|
||||
pProc = Runtime.getRuntime().exec(theArgs, envArray, f);
|
||||
}
|
||||
else
|
||||
{
|
||||
pProc = Runtime.getRuntime().exec(theArgs, envArray);
|
||||
}
|
||||
|
||||
RedirOutputThread outThrd = new RedirOutputThread(pProc, out);
|
||||
outThrd.start();
|
||||
|
@ -52,7 +52,7 @@ interface nsIContentSecurityPolicy;
|
||||
[ptr] native JSContext(JSContext);
|
||||
[ptr] native JSPrincipals(JSPrincipals);
|
||||
|
||||
[scriptable, uuid(B406A2DB-E547-4C95-B8E2-AD09ECB54CE0)]
|
||||
[scriptable, uuid(1f83b0e0-6b63-4bdc-a50a-b9afe256bd25)]
|
||||
interface nsIPrincipal : nsISerializable
|
||||
{
|
||||
/**
|
||||
@ -206,6 +206,12 @@ interface nsIPrincipal : nsISerializable
|
||||
*/
|
||||
boolean subsumes(in nsIPrincipal other);
|
||||
|
||||
/**
|
||||
* Same as the previous method, subsumes(), but for codebase principals
|
||||
* ignores changes to document.domain.
|
||||
*/
|
||||
boolean subsumesIgnoringDomain(in nsIPrincipal other);
|
||||
|
||||
/**
|
||||
* Checks whether this principal is allowed to load the network resource
|
||||
* located at the given URI under the same-origin policy. This means that
|
||||
|
@ -336,6 +336,12 @@ nsNullPrincipal::Subsumes(nsIPrincipal *aOther, bool *aResult)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNullPrincipal::SubsumesIgnoringDomain(nsIPrincipal *aOther, bool *aResult)
|
||||
{
|
||||
return Subsumes(aOther, aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsNullPrincipal::CheckMayLoad(nsIURI* aURI, bool aReport)
|
||||
{
|
||||
|
@ -377,6 +377,12 @@ nsPrincipal::Subsumes(nsIPrincipal *aOther, bool *aResult)
|
||||
return Equals(aOther, aResult);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPrincipal::SubsumesIgnoringDomain(nsIPrincipal *aOther, bool *aResult)
|
||||
{
|
||||
return EqualsIgnoringDomain(aOther, aResult);
|
||||
}
|
||||
|
||||
static bool
|
||||
URIIsLocalFile(nsIURI *aURI)
|
||||
{
|
||||
|
@ -125,6 +125,13 @@ nsSystemPrincipal::Subsumes(nsIPrincipal *other, bool *result)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSystemPrincipal::SubsumesIgnoringDomain(nsIPrincipal *other, bool *result)
|
||||
{
|
||||
*result = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsSystemPrincipal::CheckMayLoad(nsIURI* uri, bool aReport)
|
||||
{
|
||||
|
@ -697,6 +697,8 @@ JS_SHARED_LIBRARY = @JS_SHARED_LIBRARY@
|
||||
|
||||
MOZ_INSTRUMENT_EVENT_LOOP = @MOZ_INSTRUMENT_EVENT_LOOP@
|
||||
|
||||
MOZ_SYSTEM_PLY = @MOZ_SYSTEM_PLY@
|
||||
|
||||
# We only want to do the pymake sanity on Windows, other os's can cope
|
||||
ifeq ($(HOST_OS_ARCH),WINNT)
|
||||
# Ensure invariants between GNU Make and pymake
|
||||
|
@ -792,8 +792,10 @@ EXPAND_LD = $(EXPAND_LIBS_EXEC) --uselist $(if $(REORDER),--reorder $(REORDER))-
|
||||
EXPAND_MKSHLIB = $(EXPAND_LIBS_EXEC) --uselist $(if $(REORDER),--reorder $(REORDER))-- $(MKSHLIB)
|
||||
|
||||
ifdef STDCXX_COMPAT
|
||||
ifneq ($(OS_ARCH),Darwin)
|
||||
CHECK_STDCXX = objdump -p $(1) | grep -e 'GLIBCXX_3\.4\.\(9\|[1-9][0-9]\)' > /dev/null && echo "TEST-UNEXPECTED-FAIL | | We don't want these libstdc++ symbols to be used:" && objdump -T $(1) | grep -e 'GLIBCXX_3\.4\.\(9\|[1-9][0-9]\)' && exit 1 || exit 0
|
||||
endif
|
||||
endif
|
||||
|
||||
# autoconf.mk sets OBJ_SUFFIX to an error to avoid use before including
|
||||
# this file
|
||||
|
39
configure.in
39
configure.in
@ -1049,6 +1049,16 @@ if test -z "$PYTHON"; then
|
||||
AC_MSG_ERROR([python was not found in \$PATH])
|
||||
fi
|
||||
|
||||
MOZ_ARG_WITH_BOOL(system-ply,
|
||||
[ --with-system-ply Use system installed python ply library],
|
||||
[if $PYTHON -c 'import ply' 2>&5; then
|
||||
MOZ_SYSTEM_PLY=1
|
||||
else
|
||||
AC_MSG_ERROR([python ply library is not found but --with-system-ply was requested])
|
||||
fi])
|
||||
|
||||
AC_SUBST(MOZ_SYSTEM_PLY)
|
||||
|
||||
if test -z "$COMPILE_ENVIRONMENT"; then
|
||||
NSINSTALL_BIN='$(PYTHON) $(topsrcdir)/config/nsinstall.py'
|
||||
fi
|
||||
@ -3718,20 +3728,23 @@ AC_CHECK_FUNCS(random strerror lchown fchmod snprintf statvfs memmove rint stat6
|
||||
AC_CHECK_FUNCS(flockfile getpagesize)
|
||||
AC_CHECK_FUNCS(localtime_r strtok_r)
|
||||
|
||||
dnl check for clock_gettime(), the CLOCK_MONOTONIC clock, and -lrt
|
||||
_SAVE_LDFLAGS=$LDFLAGS
|
||||
LDFLAGS="$LDFLAGS -lrt"
|
||||
AC_CACHE_CHECK(for clock_gettime(CLOCK_MONOTONIC) and -lrt,
|
||||
ac_cv_have_clock_monotonic,
|
||||
[AC_TRY_LINK([#include <time.h>],
|
||||
[ struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts); ],
|
||||
ac_cv_have_clock_monotonic=yes,
|
||||
ac_cv_have_clock_monotonic=no)])
|
||||
LDFLAGS=$_SAVE_LDFLAGS
|
||||
if test "$ac_cv_have_clock_monotonic" = "yes"; then
|
||||
dnl check for clock_gettime(), the CLOCK_MONOTONIC clock
|
||||
AC_CACHE_CHECK(for clock_gettime(CLOCK_MONOTONIC),
|
||||
ac_cv_clock_monotonic,
|
||||
[for libs in "" -lrt; do
|
||||
_SAVE_LDFLAGS="$LDFLAGS"
|
||||
LDFLAGS="$LDFLAGS $libs"
|
||||
AC_TRY_LINK([#include <time.h>],
|
||||
[ struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts); ],
|
||||
ac_cv_clock_monotonic=$libs
|
||||
break,
|
||||
ac_cv_clock_monotonic=no)
|
||||
LDFLAGS="$_SAVE_LDFLAGS"
|
||||
done])
|
||||
if test "$ac_cv_clock_monotonic" != "no"; then
|
||||
HAVE_CLOCK_MONOTONIC=1
|
||||
REALTIME_LIBS=-lrt
|
||||
REALTIME_LIBS=$ac_cv_clock_monotonic
|
||||
AC_DEFINE(HAVE_CLOCK_MONOTONIC)
|
||||
AC_SUBST(HAVE_CLOCK_MONOTONIC)
|
||||
AC_SUBST(REALTIME_LIBS)
|
||||
|
@ -131,7 +131,6 @@ class nsIInterfaceRequestor;
|
||||
template<class E> class nsCOMArray;
|
||||
template<class K, class V> class nsRefPtrHashtable;
|
||||
struct JSRuntime;
|
||||
class nsIUGenCategory;
|
||||
class nsIWidget;
|
||||
class nsIDragSession;
|
||||
class nsIPresShell;
|
||||
@ -625,11 +624,6 @@ public:
|
||||
return sWordBreaker;
|
||||
}
|
||||
|
||||
static nsIUGenCategory* GetGenCat()
|
||||
{
|
||||
return sGenCat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Regster aObserver as a shutdown observer. A strong reference is held
|
||||
* to aObserver until UnregisterShutdownObserver is called.
|
||||
@ -2017,7 +2011,6 @@ private:
|
||||
|
||||
static nsILineBreaker* sLineBreaker;
|
||||
static nsIWordBreaker* sWordBreaker;
|
||||
static nsIUGenCategory* sGenCat;
|
||||
|
||||
static nsIScriptRuntime* sScriptRuntimes[NS_STID_ARRAY_UBOUND];
|
||||
static PRInt32 sScriptRootCount[NS_STID_ARRAY_UBOUND];
|
||||
|
@ -691,6 +691,7 @@ DragDataProducer::Produce(nsDOMDataTransfer* aDataTransfer,
|
||||
rv = nsCopySupport::GetTransferableForNode(nodeToSerialize, doc,
|
||||
getter_AddRefs(transferable));
|
||||
}
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsISupportsString> data;
|
||||
PRUint32 dataSize;
|
||||
|
@ -122,6 +122,7 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID);
|
||||
#include "nsLWBrkCIID.h"
|
||||
#include "nsILineBreaker.h"
|
||||
#include "nsIWordBreaker.h"
|
||||
#include "nsUnicodeProperties.h"
|
||||
#include "jsdbgapi.h"
|
||||
#include "nsIJSRuntimeService.h"
|
||||
#include "nsIDOMDocumentXBL.h"
|
||||
@ -154,7 +155,6 @@ static NS_DEFINE_CID(kXTFServiceCID, NS_XTFSERVICE_CID);
|
||||
#include "nsGenericHTMLElement.h"
|
||||
#include "nsAttrValue.h"
|
||||
#include "nsReferencedElement.h"
|
||||
#include "nsIUGenCategory.h"
|
||||
#include "nsIDragService.h"
|
||||
#include "nsIChannelEventSink.h"
|
||||
#include "nsIAsyncVerifyRedirectCallback.h"
|
||||
@ -260,7 +260,6 @@ nsIContentPolicy *nsContentUtils::sContentPolicyService;
|
||||
bool nsContentUtils::sTriedToGetContentPolicy = false;
|
||||
nsILineBreaker *nsContentUtils::sLineBreaker;
|
||||
nsIWordBreaker *nsContentUtils::sWordBreaker;
|
||||
nsIUGenCategory *nsContentUtils::sGenCat;
|
||||
nsIScriptRuntime *nsContentUtils::sScriptRuntimes[NS_STID_ARRAY_UBOUND];
|
||||
PRInt32 nsContentUtils::sScriptRootCount[NS_STID_ARRAY_UBOUND];
|
||||
PRUint32 nsContentUtils::sJSGCThingRootCount;
|
||||
@ -389,9 +388,6 @@ nsContentUtils::Init()
|
||||
rv = CallGetService(NS_WBRK_CONTRACTID, &sWordBreaker);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = CallGetService(NS_UNICHARCATEGORY_CONTRACTID, &sGenCat);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
if (!InitializeEventTable())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
@ -977,7 +973,7 @@ nsContentUtils::IsPunctuationMarkAt(const nsTextFragment* aFrag, PRUint32 aOffse
|
||||
// static
|
||||
bool nsContentUtils::IsAlphanumeric(PRUint32 aChar)
|
||||
{
|
||||
nsIUGenCategory::nsUGenCategory cat = sGenCat->Get(aChar);
|
||||
nsIUGenCategory::nsUGenCategory cat = mozilla::unicode::GetGenCategory(aChar);
|
||||
|
||||
return (cat == nsIUGenCategory::kLetter || cat == nsIUGenCategory::kNumber);
|
||||
}
|
||||
@ -1138,7 +1134,6 @@ nsContentUtils::Shutdown()
|
||||
NS_IF_RELEASE(sIOService);
|
||||
NS_IF_RELEASE(sLineBreaker);
|
||||
NS_IF_RELEASE(sWordBreaker);
|
||||
NS_IF_RELEASE(sGenCat);
|
||||
#ifdef MOZ_XTF
|
||||
NS_IF_RELEASE(sXTFService);
|
||||
#endif
|
||||
|
@ -480,10 +480,14 @@ nsDOMAttribute::Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDOMAttribute::CloneNode(bool aDeep, nsIDOMNode** aResult)
|
||||
nsDOMAttribute::CloneNode(bool aDeep, PRUint8 aOptionalArgc, nsIDOMNode** aResult)
|
||||
{
|
||||
OwnerDoc()->WarnOnceAbout(nsIDocument::eCloneNode);
|
||||
|
||||
if (!aOptionalArgc) {
|
||||
aDeep = true;
|
||||
}
|
||||
|
||||
return nsNodeUtils::CloneNodeImpl(this, aDeep, true, aResult);
|
||||
}
|
||||
|
||||
|
@ -5830,8 +5830,12 @@ nsDocument::AppendChild(nsIDOMNode* aNewChild, nsIDOMNode** aReturn)
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocument::CloneNode(bool aDeep, nsIDOMNode** aReturn)
|
||||
nsDocument::CloneNode(bool aDeep, PRUint8 aOptionalArgc, nsIDOMNode** aReturn)
|
||||
{
|
||||
if (!aOptionalArgc) {
|
||||
aDeep = true;
|
||||
}
|
||||
|
||||
return nsNodeUtils::CloneNodeImpl(this, aDeep, !mCreatingStaticClone, aReturn);
|
||||
}
|
||||
|
||||
@ -8062,7 +8066,7 @@ nsIDocument::CreateStaticClone(nsISupports* aCloneContainer)
|
||||
nsCOMPtr<nsISupports> originalContainer = GetContainer();
|
||||
SetContainer(aCloneContainer);
|
||||
nsCOMPtr<nsIDOMNode> clonedNode;
|
||||
nsresult rv = domDoc->CloneNode(true, getter_AddRefs(clonedNode));
|
||||
nsresult rv = domDoc->CloneNode(true, 1, getter_AddRefs(clonedNode));
|
||||
SetContainer(originalContainer);
|
||||
|
||||
nsCOMPtr<nsIDocument> clonedDoc;
|
||||
|
@ -143,8 +143,12 @@ public:
|
||||
nsresult IsSupported(const nsAString& aFeature,
|
||||
const nsAString& aVersion,
|
||||
bool* aReturn);
|
||||
nsresult CloneNode(bool aDeep, nsIDOMNode** aReturn)
|
||||
nsresult CloneNode(bool aDeep, PRUint8 aOptionalArgc, nsIDOMNode** aReturn)
|
||||
{
|
||||
if (!aOptionalArgc) {
|
||||
aDeep = true;
|
||||
}
|
||||
|
||||
return nsNodeUtils::CloneNodeImpl(this, aDeep, true, aReturn);
|
||||
}
|
||||
|
||||
|
@ -437,8 +437,12 @@ public:
|
||||
// nsIDOMElement method implementation
|
||||
NS_DECL_NSIDOMELEMENT
|
||||
|
||||
nsresult CloneNode(bool aDeep, nsIDOMNode **aResult)
|
||||
nsresult CloneNode(bool aDeep, PRUint8 aOptionalArgc, nsIDOMNode **aResult)
|
||||
{
|
||||
if (!aOptionalArgc) {
|
||||
aDeep = true;
|
||||
}
|
||||
|
||||
return nsNodeUtils::CloneNodeImpl(this, aDeep, true, aResult);
|
||||
}
|
||||
|
||||
|
@ -1596,7 +1596,7 @@ nsresult nsRange::CutContents(nsIDOMDocumentFragment** aFragment)
|
||||
cutValue);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nsCOMPtr<nsIDOMNode> clone;
|
||||
rv = charData->CloneNode(false, getter_AddRefs(clone));
|
||||
rv = charData->CloneNode(false, 1, getter_AddRefs(clone));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
clone->SetNodeValue(cutValue);
|
||||
nodeToResult = clone;
|
||||
@ -1656,7 +1656,7 @@ nsresult nsRange::CutContents(nsIDOMDocumentFragment** aFragment)
|
||||
{
|
||||
if (retval) {
|
||||
nsCOMPtr<nsIDOMNode> clone;
|
||||
rv = node->CloneNode(false, getter_AddRefs(clone));
|
||||
rv = node->CloneNode(false, 1, getter_AddRefs(clone));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nodeToResult = clone;
|
||||
}
|
||||
@ -1827,7 +1827,7 @@ nsRange::CloneParentsBetween(nsIDOMNode *aAncestor,
|
||||
{
|
||||
nsCOMPtr<nsIDOMNode> clone, tmpNode;
|
||||
|
||||
res = parent->CloneNode(false, getter_AddRefs(clone));
|
||||
res = parent->CloneNode(false, 1, getter_AddRefs(clone));
|
||||
|
||||
if (NS_FAILED(res)) return res;
|
||||
if (!clone) return NS_ERROR_FAILURE;
|
||||
@ -1928,7 +1928,7 @@ nsRange::CloneContents(nsIDOMDocumentFragment** aReturn)
|
||||
// Clone the current subtree!
|
||||
|
||||
nsCOMPtr<nsIDOMNode> clone;
|
||||
res = node->CloneNode(deepClone, getter_AddRefs(clone));
|
||||
res = node->CloneNode(deepClone, 1, getter_AddRefs(clone));
|
||||
if (NS_FAILED(res)) return res;
|
||||
|
||||
// If it's CharacterData, make sure we only clone what
|
||||
|
@ -555,6 +555,7 @@ _TEST_FILES2 = \
|
||||
file_bug717511_2.html \
|
||||
file_bug717511_2.html^headers^ \
|
||||
test_bug726364.html \
|
||||
test_bug698381.html \
|
||||
$(NULL)
|
||||
|
||||
_CHROME_FILES = \
|
||||
|
56
content/base/test/test_bug698381.html
Normal file
56
content/base/test/test_bug698381.html
Normal file
@ -0,0 +1,56 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=698381
|
||||
-->
|
||||
<head>
|
||||
<title>Test for Bug 698381</title>
|
||||
<script type="text/javascript"
|
||||
src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="/tests/SimpleTest/EventUtils.js"
|
||||
type="text/javascript"></script>
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body onload="runTests();">
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=698381">
|
||||
Mozilla Bug 698381</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none"></div>
|
||||
<div id="noChildren" style="display: none"></div>
|
||||
<div id="hasChildren" style="display: none">
|
||||
<div id="childOne" style="display: none"></div>
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="text/javascript">
|
||||
/*
|
||||
Checks to see if default parameter handling is correct when 0
|
||||
parameters are passed.
|
||||
|
||||
If none are passed, then Node.cloneNode should default aDeep
|
||||
to true.
|
||||
*/
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var hasChildren = document.getElementById("hasChildren"),
|
||||
noChildren = document.getElementById("noChildren"),
|
||||
clonedNode;
|
||||
|
||||
function runTests() {
|
||||
|
||||
// Test Node.cloneNode when no arguments are given
|
||||
clonedNode = hasChildren.cloneNode();
|
||||
is(clonedNode.hasChildNodes(), true, "Node.cloneNode with true " +
|
||||
"default on a node with children clones the child nodes.");
|
||||
|
||||
clonedNode = noChildren.cloneNode();
|
||||
is(clonedNode.hasChildNodes(), false, "Node.cloneNode with true " +
|
||||
"default on a node without children doesn't clone child nodes." );
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -71,6 +71,7 @@ CPPSRCS += \
|
||||
WebGLContextReporter.cpp \
|
||||
WebGLContextValidate.cpp \
|
||||
WebGLExtensionStandardDerivatives.cpp \
|
||||
WebGLExtensionTextureFilterAnisotropic.cpp \
|
||||
WebGLExtensionLoseContext.cpp \
|
||||
$(NULL)
|
||||
|
||||
|
@ -820,7 +820,6 @@ bool WebGLContext::IsExtensionSupported(WebGLExtensionID ei)
|
||||
|
||||
switch (ei) {
|
||||
case WebGL_OES_texture_float:
|
||||
MakeContextCurrent();
|
||||
isSupported = gl->IsExtensionSupported(gl->IsGLES2() ? GLContext::OES_texture_float
|
||||
: GLContext::ARB_texture_float);
|
||||
break;
|
||||
@ -828,6 +827,9 @@ bool WebGLContext::IsExtensionSupported(WebGLExtensionID ei)
|
||||
// We always support this extension.
|
||||
isSupported = true;
|
||||
break;
|
||||
case WebGL_EXT_texture_filter_anisotropic:
|
||||
isSupported = gl->IsExtensionSupported(GLContext::EXT_texture_filter_anisotropic);
|
||||
break;
|
||||
case WebGL_MOZ_WEBGL_lose_context:
|
||||
// We always support this extension.
|
||||
isSupported = true;
|
||||
@ -860,6 +862,10 @@ WebGLContext::GetExtension(const nsAString& aName, nsIWebGLExtension **retval)
|
||||
if (IsExtensionSupported(WebGL_OES_standard_derivatives))
|
||||
ei = WebGL_OES_standard_derivatives;
|
||||
}
|
||||
else if (aName.EqualsLiteral("MOZ_EXT_texture_filter_anisotropic")) {
|
||||
if (IsExtensionSupported(WebGL_EXT_texture_filter_anisotropic))
|
||||
ei = WebGL_EXT_texture_filter_anisotropic;
|
||||
}
|
||||
else if (aName.EqualsLiteral("MOZ_WEBGL_lose_context")) {
|
||||
if (IsExtensionSupported(WebGL_MOZ_WEBGL_lose_context))
|
||||
ei = WebGL_MOZ_WEBGL_lose_context;
|
||||
@ -871,6 +877,9 @@ WebGLContext::GetExtension(const nsAString& aName, nsIWebGLExtension **retval)
|
||||
case WebGL_OES_standard_derivatives:
|
||||
mEnabledExtensions[ei] = new WebGLExtensionStandardDerivatives(this);
|
||||
break;
|
||||
case WebGL_EXT_texture_filter_anisotropic:
|
||||
mEnabledExtensions[ei] = new WebGLExtensionTextureFilterAnisotropic(this);
|
||||
break;
|
||||
case WebGL_MOZ_WEBGL_lose_context:
|
||||
mEnabledExtensions[ei] = new WebGLExtensionLoseContext(this);
|
||||
break;
|
||||
@ -1295,6 +1304,11 @@ NS_INTERFACE_MAP_BEGIN(WebGLExtensionStandardDerivatives)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLExtensionStandardDerivatives)
|
||||
NS_INTERFACE_MAP_END_INHERITING(WebGLExtension)
|
||||
|
||||
NS_IMPL_ADDREF(WebGLExtensionTextureFilterAnisotropic)
|
||||
NS_IMPL_RELEASE(WebGLExtensionTextureFilterAnisotropic)
|
||||
|
||||
DOMCI_DATA(WebGLExtensionTextureFilterAnisotropic, WebGLExtensionTextureFilterAnisotropic)
|
||||
|
||||
NS_IMPL_ADDREF(WebGLExtensionLoseContext)
|
||||
NS_IMPL_RELEASE(WebGLExtensionLoseContext)
|
||||
|
||||
@ -1409,6 +1423,8 @@ WebGLContext::GetSupportedExtensions(nsIVariant **retval)
|
||||
extList.InsertElementAt(extList.Length(), "OES_texture_float");
|
||||
if (IsExtensionSupported(WebGL_OES_standard_derivatives))
|
||||
extList.InsertElementAt(extList.Length(), "OES_standard_derivatives");
|
||||
if (IsExtensionSupported(WebGL_EXT_texture_filter_anisotropic))
|
||||
extList.InsertElementAt(extList.Length(), "MOZ_EXT_texture_filter_anisotropic");
|
||||
if (IsExtensionSupported(WebGL_MOZ_WEBGL_lose_context))
|
||||
extList.InsertElementAt(extList.Length(), "MOZ_WEBGL_lose_context");
|
||||
|
||||
|
@ -745,6 +745,7 @@ protected:
|
||||
enum WebGLExtensionID {
|
||||
WebGL_OES_texture_float,
|
||||
WebGL_OES_standard_derivatives,
|
||||
WebGL_EXT_texture_filter_anisotropic,
|
||||
WebGL_MOZ_WEBGL_lose_context,
|
||||
WebGLExtensionID_Max
|
||||
};
|
||||
|
@ -2210,6 +2210,15 @@ WebGLContext::GetParameter(PRUint32 pname, nsIVariant **retval)
|
||||
break;
|
||||
|
||||
// float
|
||||
case LOCAL_GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT:
|
||||
if (mEnabledExtensions[WebGL_EXT_texture_filter_anisotropic]) {
|
||||
GLfloat f = 0.f;
|
||||
gl->fGetFloatv(pname, &f);
|
||||
wrval->SetAsFloat(f);
|
||||
} else {
|
||||
return ErrorInvalidEnum("getParameter: parameter", pname);
|
||||
}
|
||||
break;
|
||||
case LOCAL_GL_DEPTH_CLEAR_VALUE:
|
||||
case LOCAL_GL_LINE_WIDTH:
|
||||
case LOCAL_GL_POLYGON_OFFSET_FACTOR:
|
||||
@ -2679,6 +2688,7 @@ nsresult WebGLContext::TexParameter_base(WebGLenum target, WebGLenum pname,
|
||||
return ErrorInvalidOperation("texParameter: no texture is bound to this target");
|
||||
|
||||
bool pnameAndParamAreIncompatible = false;
|
||||
bool paramValueInvalid = false;
|
||||
|
||||
switch (pname) {
|
||||
case LOCAL_GL_TEXTURE_MIN_FILTER:
|
||||
@ -2727,18 +2737,33 @@ nsresult WebGLContext::TexParameter_base(WebGLenum target, WebGLenum pname,
|
||||
pnameAndParamAreIncompatible = true;
|
||||
}
|
||||
break;
|
||||
case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT:
|
||||
if (mEnabledExtensions[WebGL_EXT_texture_filter_anisotropic]) {
|
||||
if (floatParamPtr && floatParam < 1.f)
|
||||
paramValueInvalid = true;
|
||||
else if (intParamPtr && intParam < 1)
|
||||
paramValueInvalid = true;
|
||||
}
|
||||
else
|
||||
pnameAndParamAreIncompatible = true;
|
||||
break;
|
||||
default:
|
||||
return ErrorInvalidEnumInfo("texParameter: pname", pname);
|
||||
}
|
||||
|
||||
if (pnameAndParamAreIncompatible) {
|
||||
// note that currently all params are enums, and the tex-input-validation test wants INVALID_ENUM errors
|
||||
// even for texParameterf. why not.
|
||||
if (intParamPtr)
|
||||
return ErrorInvalidEnum("texParameteri: pname %x and param %x (decimal %d) are mutually incompatible",
|
||||
pname, intParam, intParam);
|
||||
else
|
||||
return ErrorInvalidEnum("texParameterf: pname %x and floating-point param %e are mutually incompatible",
|
||||
return ErrorInvalidEnum("texParameterf: pname %x and param %g are mutually incompatible",
|
||||
pname, floatParam);
|
||||
} else if (paramValueInvalid) {
|
||||
if (intParamPtr)
|
||||
return ErrorInvalidValue("texParameteri: pname %x and param %x (decimal %d) is invalid",
|
||||
pname, intParam, intParam);
|
||||
else
|
||||
return ErrorInvalidValue("texParameterf: pname %x and param %g is invalid",
|
||||
pname, floatParam);
|
||||
}
|
||||
|
||||
@ -2799,6 +2824,15 @@ WebGLContext::GetTexParameter(WebGLenum target, WebGLenum pname, nsIVariant **re
|
||||
wrval->SetAsInt32(i);
|
||||
}
|
||||
break;
|
||||
case LOCAL_GL_TEXTURE_MAX_ANISOTROPY_EXT:
|
||||
if (mEnabledExtensions[WebGL_EXT_texture_filter_anisotropic]) {
|
||||
GLfloat f = 0.f;
|
||||
gl->fGetTexParameterfv(target, pname, &f);
|
||||
wrval->SetAsFloat(f);
|
||||
}
|
||||
else
|
||||
return ErrorInvalidEnumInfo("getTexParameter: parameter", pname);
|
||||
break;
|
||||
|
||||
default:
|
||||
return ErrorInvalidEnumInfo("getTexParameter: parameter", pname);
|
||||
|
@ -55,4 +55,5 @@ DOMCI_DATA(WebGLShaderPrecisionFormat, void)
|
||||
DOMCI_DATA(WebGLActiveInfo, void)
|
||||
DOMCI_DATA(WebGLExtension, void)
|
||||
DOMCI_DATA(WebGLExtensionStandardDerivatives, void)
|
||||
DOMCI_DATA(WebGLExtensionTextureFilterAnisotropic, void)
|
||||
DOMCI_DATA(WebGLExtensionLoseContext, void)
|
||||
|
@ -0,0 +1,64 @@
|
||||
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* ***** 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.org code.
|
||||
*
|
||||
* The Initial Developer of the Original Code is
|
||||
* Mozilla Corporation.
|
||||
* Portions created by the Initial Developer are Copyright (C) 2009
|
||||
* the Initial Developer. All Rights Reserved.
|
||||
*
|
||||
* Contributor(s):
|
||||
* Florian Boesch <pyalot@gmail.com> (original author)
|
||||
*
|
||||
* 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 <stdarg.h>
|
||||
|
||||
#include "WebGLContext.h"
|
||||
#include "WebGLExtensions.h"
|
||||
|
||||
#include "nsContentUtils.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(WebGLExtensionTextureFilterAnisotropic)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIWebGLExtensionTextureFilterAnisotropic)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, WebGLExtension)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(WebGLExtensionTextureFilterAnisotropic)
|
||||
NS_INTERFACE_MAP_END_INHERITING(WebGLExtension)
|
||||
|
||||
WebGLExtensionTextureFilterAnisotropic::WebGLExtensionTextureFilterAnisotropic(WebGLContext* context) :
|
||||
WebGLExtension(context)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
WebGLExtensionTextureFilterAnisotropic::~WebGLExtensionTextureFilterAnisotropic()
|
||||
{
|
||||
|
||||
}
|
@ -41,9 +41,6 @@
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class WebGLExtensionLoseContext;
|
||||
class WebGLExtensionStandardDerivatives;
|
||||
|
||||
class WebGLExtensionLoseContext :
|
||||
public nsIWebGLExtensionLoseContext,
|
||||
public WebGLExtension
|
||||
@ -68,6 +65,18 @@ public:
|
||||
NS_DECL_NSIWEBGLEXTENSION
|
||||
};
|
||||
|
||||
class WebGLExtensionTextureFilterAnisotropic :
|
||||
public nsIWebGLExtensionTextureFilterAnisotropic,
|
||||
public WebGLExtension
|
||||
{
|
||||
public:
|
||||
WebGLExtensionTextureFilterAnisotropic(WebGLContext* context);
|
||||
virtual ~WebGLExtensionTextureFilterAnisotropic();
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIWEBGLEXTENSION
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif // WEBGLEXTENSIONS_H_
|
||||
|
@ -1,4 +1,5 @@
|
||||
oes-standard-derivatives.html
|
||||
ext-texture-filter-anisotropic.html
|
||||
oes-texture-float.html
|
||||
oes-vertex-array-object.html
|
||||
webgl-debug-renderer-info.html
|
||||
|
@ -0,0 +1,157 @@
|
||||
<!--
|
||||
Copyright (c) 2012 Florian Boesch <pyalot@gmail.com>. All rights reserved.
|
||||
Use of this source code is governed by a BSD-style license that can be
|
||||
found in the LICENSE file.
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>WebGL EXT_texture_filter_anisotropic Conformance Tests</title>
|
||||
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
<script src="../../resources/desktop-gl-constants.js" type="text/javascript"></script>
|
||||
<script src="../../resources/js-test-pre.js"></script>
|
||||
<script src="../resources/webgl-test.js"></script>
|
||||
<script src="../resources/webgl-test-utils.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div id="description"></div>
|
||||
<canvas id="canvas" style="width: 50px; height: 50px;"> </canvas>
|
||||
<div id="console"></div>
|
||||
|
||||
<script>
|
||||
description("This test verifies the functionality of the EXT_texture_filter_anisotropic extension, if it is available.");
|
||||
|
||||
debug("");
|
||||
|
||||
var wtu = WebGLTestUtils;
|
||||
var canvas = document.getElementById("canvas");
|
||||
var gl = create3DContext(canvas);
|
||||
var ext = null;
|
||||
|
||||
if (!gl) {
|
||||
testFailed("WebGL context does not exist");
|
||||
} else {
|
||||
testPassed("WebGL context exists");
|
||||
|
||||
// Run tests with extension disabled
|
||||
runHintTestDisabled();
|
||||
|
||||
// Query the extension and store globally so shouldBe can access it
|
||||
ext = gl.getExtension("MOZ_EXT_texture_filter_anisotropic");
|
||||
if (!ext) {
|
||||
testPassed("No EXT_texture_filter_anisotropic support -- this is legal");
|
||||
|
||||
runSupportedTest(false);
|
||||
} else {
|
||||
testPassed("Successfully enabled EXT_texture_filter_anisotropic extension");
|
||||
|
||||
runSupportedTest(true);
|
||||
runHintTestEnabled();
|
||||
}
|
||||
}
|
||||
|
||||
function runSupportedTest(extensionEnabled) {
|
||||
var supported = gl.getSupportedExtensions();
|
||||
if (supported.indexOf("MOZ_EXT_texture_filter_anisotropic") >= 0) {
|
||||
if (extensionEnabled) {
|
||||
testPassed("EXT_texture_filter_anisotropic listed as supported and getExtension succeeded");
|
||||
} else {
|
||||
testFailed("EXT_texture_filter_anisotropic listed as supported but getExtension failed");
|
||||
}
|
||||
} else {
|
||||
if (extensionEnabled) {
|
||||
testFailed("EXT_texture_filter_anisotropic not listed as supported but getExtension succeeded");
|
||||
} else {
|
||||
testPassed("EXt_texture_filter_anisotropic not listed as supported and getExtension failed -- this is legal");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function runHintTestDisabled() {
|
||||
debug("Testing MAX_TEXTURE_MAX_ANISOTROPY with extension disabled");
|
||||
|
||||
var MAX_TEXTURE_MAX_ANISOTROPY = 0x84FF;
|
||||
gl.getParameter(MAX_TEXTURE_MAX_ANISOTROPY);
|
||||
glErrorShouldBe(gl, gl.INVALID_ENUM, "MAX_TEXTURE_MAX_ANISOTROPY should not be queryable if extension is disabled");
|
||||
|
||||
debug("Testing TEXTURE_MAX_ANISOTROPY with extension disabled");
|
||||
var TEXTURE_MAX_ANISOTROPY = 0x84FE;
|
||||
var texture = gl.createTexture();
|
||||
gl.bindTexture(gl.TEXTURE_2D, texture);
|
||||
|
||||
gl.getTexParameter(gl.TEXTURE_2D, TEXTURE_MAX_ANISOTROPY);
|
||||
glErrorShouldBe(gl, gl.INVALID_ENUM, "TEXTURE_MAX_ANISOTROPY should not be queryable if extension is disabled");
|
||||
|
||||
gl.texParameterf(gl.TEXTURE_2D, TEXTURE_MAX_ANISOTROPY, 1);
|
||||
glErrorShouldBe(gl, gl.INVALID_ENUM, "TEXTURE_MAX_ANISOTROPY should not be settable if extension is disabled");
|
||||
|
||||
gl.texParameteri(gl.TEXTURE_2D, TEXTURE_MAX_ANISOTROPY, 1);
|
||||
glErrorShouldBe(gl, gl.INVALID_ENUM, "TEXTURE_MAX_ANISOTROPY should not be settable if extension is disabled");
|
||||
|
||||
gl.deleteTexture(texture);
|
||||
}
|
||||
|
||||
function runHintTestEnabled() {
|
||||
debug("Testing MAX_TEXTURE_MAX_ANISOTROPY with extension enabled");
|
||||
|
||||
shouldBe("ext.MAX_TEXTURE_MAX_ANISOTROPY", "0x84FF");
|
||||
|
||||
var max_anisotropy = gl.getParameter(ext.MAX_TEXTURE_MAX_ANISOTROPY);
|
||||
glErrorShouldBe(gl, gl.NO_ERROR, "MAX_TEXTURE_MAX_ANISOTROPY query should succeed if extension is enabled");
|
||||
|
||||
if(max_anisotropy >= 2){
|
||||
testPassed("Minimum value of MAX_TEXTURE_MAX_ANISOTROPY is 2.0");
|
||||
}
|
||||
else{
|
||||
testFailed("Minimum value of MAX_TEXTURE_MAX_ANISOTROPY is 2.0, returned values was: " + max_anisotropy);
|
||||
}
|
||||
|
||||
// TODO make a texture and verify initial value == 1 and setting to less than 1 is invalid value
|
||||
|
||||
debug("Testing TEXTURE_MAX_ANISOTROPY with extension disabled");
|
||||
shouldBe("ext.TEXTURE_MAX_ANISOTROPY", "0x84FE");
|
||||
|
||||
var texture = gl.createTexture();
|
||||
gl.bindTexture(gl.TEXTURE_2D, texture);
|
||||
|
||||
var queried_value = gl.getTexParameter(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY);
|
||||
glErrorShouldBe(gl, gl.NO_ERROR, "TEXTURE_MAX_ANISOTROPY query should succeed if extension is enabled");
|
||||
|
||||
if(queried_value == 1){
|
||||
testPassed("Initial value of TEXTURE_MAX_ANISOTROPY is 1.0");
|
||||
}
|
||||
else{
|
||||
testFailed("Initial value of TEXTURE_MAX_ANISOTROPY should be 1.0, returned value was: " + queried_value);
|
||||
}
|
||||
|
||||
gl.texParameterf(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY, 0);
|
||||
glErrorShouldBe(gl, gl.INVALID_VALUE, "texParameterf TEXTURE_MAX_ANISOTROPY set to < 1 should be an invalid value");
|
||||
|
||||
gl.texParameteri(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY, 0);
|
||||
glErrorShouldBe(gl, gl.INVALID_VALUE, "texParameteri TEXTURE_MAX_ANISOTROPY set to < 1 should be an invalid value");
|
||||
|
||||
gl.texParameterf(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY, max_anisotropy);
|
||||
glErrorShouldBe(gl, gl.NO_ERROR, "texParameterf TEXTURE_MAX_ANISOTROPY set to >= 2 should should succeed");
|
||||
|
||||
gl.texParameteri(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY, max_anisotropy);
|
||||
glErrorShouldBe(gl, gl.NO_ERROR, "texParameteri TEXTURE_MAX_ANISOTROPY set to >= 2 should should succeed");
|
||||
|
||||
var queried_value = gl.getTexParameter(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY);
|
||||
if(queried_value == max_anisotropy){
|
||||
testPassed("Set value of TEXTURE_MAX_ANISOTROPY matches expecation");
|
||||
}
|
||||
else{
|
||||
testFailed("Set value of TEXTURE_MAX_ANISOTROPY should be: " + max_anisotropy + " , returned value was: " + queried_value);
|
||||
}
|
||||
|
||||
gl.deleteTexture(texture);
|
||||
}
|
||||
|
||||
debug("");
|
||||
successfullyParsed = true;
|
||||
</script>
|
||||
<script src="../../resources/js-test-post.js"></script>
|
||||
|
||||
</body>
|
||||
</html>
|
174
content/canvas/test/webgl/ext-texture-filter-anisotropic.patch
Normal file
174
content/canvas/test/webgl/ext-texture-filter-anisotropic.patch
Normal file
@ -0,0 +1,174 @@
|
||||
diff --git a/content/canvas/test/webgl/conformance/extensions/00_test_list.txt b/content/canvas/test/webgl/conformance/extensions/00_test_list.txt
|
||||
--- a/content/canvas/test/webgl/conformance/extensions/00_test_list.txt
|
||||
+++ b/content/canvas/test/webgl/conformance/extensions/00_test_list.txt
|
||||
@@ -1,7 +1,8 @@
|
||||
oes-standard-derivatives.html
|
||||
+ext-texture-filter-anisotropic.html
|
||||
oes-texture-float.html
|
||||
oes-vertex-array-object.html
|
||||
webgl-debug-renderer-info.html
|
||||
webgl-debug-shaders.html
|
||||
--min-version 1.0.2 webgl-experimental-compressed-textures.html
|
||||
|
||||
diff --git a/content/canvas/test/webgl/conformance/extensions/ext-texture-filter-anisotropic.html b/content/canvas/test/webgl/conformance/extensions/ext-texture-filter-anisotropic.html
|
||||
new file mode 100644
|
||||
--- /dev/null
|
||||
+++ b/content/canvas/test/webgl/conformance/extensions/ext-texture-filter-anisotropic.html
|
||||
@@ -0,0 +1,157 @@
|
||||
+<!--
|
||||
+Copyright (c) 2012 Florian Boesch <pyalot@gmail.com>. All rights reserved.
|
||||
+Use of this source code is governed by a BSD-style license that can be
|
||||
+found in the LICENSE file.
|
||||
+ -->
|
||||
+<!DOCTYPE html>
|
||||
+<html>
|
||||
+<head>
|
||||
+<meta charset="utf-8">
|
||||
+<title>WebGL EXT_texture_filter_anisotropic Conformance Tests</title>
|
||||
+<link rel="stylesheet" href="../../resources/js-test-style.css"/>
|
||||
+<script src="../../resources/desktop-gl-constants.js" type="text/javascript"></script>
|
||||
+<script src="../../resources/js-test-pre.js"></script>
|
||||
+<script src="../resources/webgl-test.js"></script>
|
||||
+<script src="../resources/webgl-test-utils.js"></script>
|
||||
+</head>
|
||||
+<body>
|
||||
+<div id="description"></div>
|
||||
+<canvas id="canvas" style="width: 50px; height: 50px;"> </canvas>
|
||||
+<div id="console"></div>
|
||||
+
|
||||
+<script>
|
||||
+description("This test verifies the functionality of the EXT_texture_filter_anisotropic extension, if it is available.");
|
||||
+
|
||||
+debug("");
|
||||
+
|
||||
+var wtu = WebGLTestUtils;
|
||||
+var canvas = document.getElementById("canvas");
|
||||
+var gl = create3DContext(canvas);
|
||||
+var ext = null;
|
||||
+
|
||||
+if (!gl) {
|
||||
+ testFailed("WebGL context does not exist");
|
||||
+} else {
|
||||
+ testPassed("WebGL context exists");
|
||||
+
|
||||
+ // Run tests with extension disabled
|
||||
+ runHintTestDisabled();
|
||||
+
|
||||
+ // Query the extension and store globally so shouldBe can access it
|
||||
+ ext = gl.getExtension("MOZ_EXT_texture_filter_anisotropic");
|
||||
+ if (!ext) {
|
||||
+ testPassed("No EXT_texture_filter_anisotropic support -- this is legal");
|
||||
+
|
||||
+ runSupportedTest(false);
|
||||
+ } else {
|
||||
+ testPassed("Successfully enabled EXT_texture_filter_anisotropic extension");
|
||||
+
|
||||
+ runSupportedTest(true);
|
||||
+ runHintTestEnabled();
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+function runSupportedTest(extensionEnabled) {
|
||||
+ var supported = gl.getSupportedExtensions();
|
||||
+ if (supported.indexOf("MOZ_EXT_texture_filter_anisotropic") >= 0) {
|
||||
+ if (extensionEnabled) {
|
||||
+ testPassed("EXT_texture_filter_anisotropic listed as supported and getExtension succeeded");
|
||||
+ } else {
|
||||
+ testFailed("EXT_texture_filter_anisotropic listed as supported but getExtension failed");
|
||||
+ }
|
||||
+ } else {
|
||||
+ if (extensionEnabled) {
|
||||
+ testFailed("EXT_texture_filter_anisotropic not listed as supported but getExtension succeeded");
|
||||
+ } else {
|
||||
+ testPassed("EXt_texture_filter_anisotropic not listed as supported and getExtension failed -- this is legal");
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
+function runHintTestDisabled() {
|
||||
+ debug("Testing MAX_TEXTURE_MAX_ANISOTROPY with extension disabled");
|
||||
+
|
||||
+ var MAX_TEXTURE_MAX_ANISOTROPY = 0x84FF;
|
||||
+ gl.getParameter(MAX_TEXTURE_MAX_ANISOTROPY);
|
||||
+ glErrorShouldBe(gl, gl.INVALID_ENUM, "MAX_TEXTURE_MAX_ANISOTROPY should not be queryable if extension is disabled");
|
||||
+
|
||||
+ debug("Testing TEXTURE_MAX_ANISOTROPY with extension disabled");
|
||||
+ var TEXTURE_MAX_ANISOTROPY = 0x84FE;
|
||||
+ var texture = gl.createTexture();
|
||||
+ gl.bindTexture(gl.TEXTURE_2D, texture);
|
||||
+
|
||||
+ gl.getTexParameter(gl.TEXTURE_2D, TEXTURE_MAX_ANISOTROPY);
|
||||
+ glErrorShouldBe(gl, gl.INVALID_ENUM, "TEXTURE_MAX_ANISOTROPY should not be queryable if extension is disabled");
|
||||
+
|
||||
+ gl.texParameterf(gl.TEXTURE_2D, TEXTURE_MAX_ANISOTROPY, 1);
|
||||
+ glErrorShouldBe(gl, gl.INVALID_ENUM, "TEXTURE_MAX_ANISOTROPY should not be settable if extension is disabled");
|
||||
+
|
||||
+ gl.texParameteri(gl.TEXTURE_2D, TEXTURE_MAX_ANISOTROPY, 1);
|
||||
+ glErrorShouldBe(gl, gl.INVALID_ENUM, "TEXTURE_MAX_ANISOTROPY should not be settable if extension is disabled");
|
||||
+
|
||||
+ gl.deleteTexture(texture);
|
||||
+}
|
||||
+
|
||||
+function runHintTestEnabled() {
|
||||
+ debug("Testing MAX_TEXTURE_MAX_ANISOTROPY with extension enabled");
|
||||
+
|
||||
+ shouldBe("ext.MAX_TEXTURE_MAX_ANISOTROPY", "0x84FF");
|
||||
+
|
||||
+ var max_anisotropy = gl.getParameter(ext.MAX_TEXTURE_MAX_ANISOTROPY);
|
||||
+ glErrorShouldBe(gl, gl.NO_ERROR, "MAX_TEXTURE_MAX_ANISOTROPY query should succeed if extension is enabled");
|
||||
+
|
||||
+ if(max_anisotropy >= 2){
|
||||
+ testPassed("Minimum value of MAX_TEXTURE_MAX_ANISOTROPY is 2.0");
|
||||
+ }
|
||||
+ else{
|
||||
+ testFailed("Minimum value of MAX_TEXTURE_MAX_ANISOTROPY is 2.0, returned values was: " + max_anisotropy);
|
||||
+ }
|
||||
+
|
||||
+ // TODO make a texture and verify initial value == 1 and setting to less than 1 is invalid value
|
||||
+
|
||||
+ debug("Testing TEXTURE_MAX_ANISOTROPY with extension disabled");
|
||||
+ shouldBe("ext.TEXTURE_MAX_ANISOTROPY", "0x84FE");
|
||||
+
|
||||
+ var texture = gl.createTexture();
|
||||
+ gl.bindTexture(gl.TEXTURE_2D, texture);
|
||||
+
|
||||
+ var queried_value = gl.getTexParameter(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY);
|
||||
+ glErrorShouldBe(gl, gl.NO_ERROR, "TEXTURE_MAX_ANISOTROPY query should succeed if extension is enabled");
|
||||
+
|
||||
+ if(queried_value == 1){
|
||||
+ testPassed("Initial value of TEXTURE_MAX_ANISOTROPY is 1.0");
|
||||
+ }
|
||||
+ else{
|
||||
+ testFailed("Initial value of TEXTURE_MAX_ANISOTROPY should be 1.0, returned value was: " + queried_value);
|
||||
+ }
|
||||
+
|
||||
+ gl.texParameterf(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY, 0);
|
||||
+ glErrorShouldBe(gl, gl.INVALID_VALUE, "texParameterf TEXTURE_MAX_ANISOTROPY set to < 1 should be an invalid value");
|
||||
+
|
||||
+ gl.texParameteri(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY, 0);
|
||||
+ glErrorShouldBe(gl, gl.INVALID_VALUE, "texParameteri TEXTURE_MAX_ANISOTROPY set to < 1 should be an invalid value");
|
||||
+
|
||||
+ gl.texParameterf(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY, max_anisotropy);
|
||||
+ glErrorShouldBe(gl, gl.NO_ERROR, "texParameterf TEXTURE_MAX_ANISOTROPY set to >= 2 should should succeed");
|
||||
+
|
||||
+ gl.texParameteri(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY, max_anisotropy);
|
||||
+ glErrorShouldBe(gl, gl.NO_ERROR, "texParameteri TEXTURE_MAX_ANISOTROPY set to >= 2 should should succeed");
|
||||
+
|
||||
+ var queried_value = gl.getTexParameter(gl.TEXTURE_2D, ext.TEXTURE_MAX_ANISOTROPY);
|
||||
+ if(queried_value == max_anisotropy){
|
||||
+ testPassed("Set value of TEXTURE_MAX_ANISOTROPY matches expecation");
|
||||
+ }
|
||||
+ else{
|
||||
+ testFailed("Set value of TEXTURE_MAX_ANISOTROPY should be: " + max_anisotropy + " , returned value was: " + queried_value);
|
||||
+ }
|
||||
+
|
||||
+ gl.deleteTexture(texture);
|
||||
+}
|
||||
+
|
||||
+debug("");
|
||||
+successfullyParsed = true;
|
||||
+</script>
|
||||
+<script src="../../resources/js-test-post.js"></script>
|
||||
+
|
||||
+</body>
|
||||
+</html>
|
@ -808,7 +808,7 @@ nsHTMLSelectElement::SetLength(PRUint32 aLength)
|
||||
if (i + 1 < aLength) {
|
||||
nsCOMPtr<nsIDOMNode> newNode;
|
||||
|
||||
rv = node->CloneNode(true, getter_AddRefs(newNode));
|
||||
rv = node->CloneNode(true, 1, getter_AddRefs(newNode));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
node = newNode;
|
||||
|
@ -849,15 +849,11 @@ nsTextInputListener::EditAction()
|
||||
nsCOMPtr<nsIEditor> editor;
|
||||
frame->GetEditor(getter_AddRefs(editor));
|
||||
|
||||
nsCOMPtr<nsITransactionManager> manager;
|
||||
editor->GetTransactionManager(getter_AddRefs(manager));
|
||||
NS_ENSURE_TRUE(manager, NS_ERROR_FAILURE);
|
||||
|
||||
// Get the number of undo / redo items
|
||||
PRInt32 numUndoItems = 0;
|
||||
PRInt32 numRedoItems = 0;
|
||||
manager->GetNumberOfUndoItems(&numUndoItems);
|
||||
manager->GetNumberOfRedoItems(&numRedoItems);
|
||||
editor->GetNumberOfUndoItems(&numUndoItems);
|
||||
editor->GetNumberOfRedoItems(&numRedoItems);
|
||||
if ((numUndoItems && !mHadUndoItems) || (!numUndoItems && mHadUndoItems) ||
|
||||
(numRedoItems && !mHadRedoItems) || (!numRedoItems && mHadRedoItems)) {
|
||||
// Modify the menu if undo or redo items are different
|
||||
|
@ -94,7 +94,8 @@ nsSMILAnimationFunction::nsSMILAnimationFunction()
|
||||
mLastValue(false),
|
||||
mHasChanged(true),
|
||||
mValueNeedsReparsingEverySample(false),
|
||||
mPrevSampleWasSingleValueAnimation(false)
|
||||
mPrevSampleWasSingleValueAnimation(false),
|
||||
mWasSkippedInPrevSample(false)
|
||||
{
|
||||
}
|
||||
|
||||
@ -233,6 +234,7 @@ nsSMILAnimationFunction::ComposeResult(const nsISMILAttr& aSMILAttr,
|
||||
{
|
||||
mHasChanged = false;
|
||||
mPrevSampleWasSingleValueAnimation = false;
|
||||
mWasSkippedInPrevSample = false;
|
||||
|
||||
// Skip animations that are inactive or in error
|
||||
if (!IsActiveOrFrozen() || mErrorFlags != 0)
|
||||
|
@ -247,6 +247,24 @@ public:
|
||||
*/
|
||||
bool UpdateCachedTarget(const nsSMILTargetIdentifier& aNewTarget);
|
||||
|
||||
/**
|
||||
* Returns true if this function was skipped in the previous sample (because
|
||||
* there was a higher-priority non-additive animation). If a skipped animation
|
||||
* function is later used, then the animation sandwich must be recomposited.
|
||||
*/
|
||||
bool WasSkippedInPrevSample() const {
|
||||
return mWasSkippedInPrevSample;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark this animation function as having been skipped. By marking the
|
||||
* function as skipped, if it is used in a subsequent sample we'll know to
|
||||
* recomposite the sandwich.
|
||||
*/
|
||||
void SetWasSkipped() {
|
||||
mWasSkippedInPrevSample = true;
|
||||
}
|
||||
|
||||
// Comparator utility class, used for sorting nsSMILAnimationFunctions
|
||||
class Comparator {
|
||||
public:
|
||||
@ -466,12 +484,13 @@ protected:
|
||||
nsSMILWeakTargetIdentifier mLastTarget;
|
||||
|
||||
// Boolean flags
|
||||
bool mIsActive:1;
|
||||
bool mIsFrozen:1;
|
||||
bool mLastValue:1;
|
||||
bool mHasChanged:1;
|
||||
bool mValueNeedsReparsingEverySample:1;
|
||||
bool mPrevSampleWasSingleValueAnimation:1;
|
||||
bool mIsActive:1;
|
||||
bool mIsFrozen:1;
|
||||
bool mLastValue:1;
|
||||
bool mHasChanged:1;
|
||||
bool mValueNeedsReparsingEverySample:1;
|
||||
bool mPrevSampleWasSingleValueAnimation:1;
|
||||
bool mWasSkippedInPrevSample:1;
|
||||
};
|
||||
|
||||
#endif // NS_SMILANIMATIONFUNCTION_H_
|
||||
|
@ -173,16 +173,31 @@ nsSMILCompositor::GetFirstFuncToAffectSandwich()
|
||||
PRUint32 i;
|
||||
for (i = mAnimationFunctions.Length(); i > 0; --i) {
|
||||
nsSMILAnimationFunction* curAnimFunc = mAnimationFunctions[i-1];
|
||||
if (curAnimFunc->UpdateCachedTarget(mKey) ||
|
||||
(!mForceCompositing && curAnimFunc->HasChanged())) {
|
||||
mForceCompositing = true;
|
||||
}
|
||||
// In the following, the lack of short-circuit behavior of |= means that we
|
||||
// will ALWAYS run UpdateCachedTarget (even if mForceCompositing is true)
|
||||
// but only call HasChanged and WasSkippedInPrevSample if necessary. This
|
||||
// is important since we need UpdateCachedTarget to run in order to detect
|
||||
// changes to the target in subsequent samples.
|
||||
mForceCompositing |=
|
||||
curAnimFunc->UpdateCachedTarget(mKey) ||
|
||||
curAnimFunc->HasChanged() ||
|
||||
curAnimFunc->WasSkippedInPrevSample();
|
||||
|
||||
if (curAnimFunc->WillReplace()) {
|
||||
--i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Mark remaining animation functions as having been skipped so if we later
|
||||
// use them we'll know to force compositing.
|
||||
// Note that we only really need to do this if something has changed
|
||||
// (otherwise we would have set the flag on a previous sample) and if
|
||||
// something has changed mForceCompositing will be true.
|
||||
if (mForceCompositing) {
|
||||
for (PRUint32 j = i; j > 0; --j) {
|
||||
mAnimationFunctions[j-1]->SetWasSkipped();
|
||||
}
|
||||
}
|
||||
return i;
|
||||
}
|
||||
|
||||
|
@ -131,7 +131,7 @@ public:
|
||||
bool mForceCompositing;
|
||||
|
||||
// Cached base value, so we can detect & force-recompose when it changes
|
||||
// from one sample to the next. (nsSMILAnimationController copies this
|
||||
// from one sample to the next. (nsSMILAnimationController copies this
|
||||
// forward from the previous sample's compositor.)
|
||||
nsAutoPtr<nsSMILValue> mCachedBaseValue;
|
||||
};
|
||||
|
@ -615,11 +615,6 @@ nsSMILParserUtils::ParseValuesGeneric(const nsAString& aSpec,
|
||||
}
|
||||
}
|
||||
|
||||
// Disallow ;-terminated values lists.
|
||||
if (tokenizer.lastTokenEndedWithSeparator()) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -55,6 +55,7 @@
|
||||
#include "nsString.h"
|
||||
#include "mozilla/AutoRestore.h"
|
||||
#include "mozilla/Util.h"
|
||||
#include "nsCharSeparatedTokenizer.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
@ -1271,10 +1272,6 @@ nsSMILTimedElement::SetBeginOrEndSpec(const nsAString& aSpec,
|
||||
bool aIsBegin,
|
||||
RemovalTestFunction aRemove)
|
||||
{
|
||||
PRInt32 start;
|
||||
PRInt32 end = -1;
|
||||
PRInt32 length;
|
||||
nsresult rv = NS_OK;
|
||||
TimeValueSpecList& timeSpecsList = aIsBegin ? mBeginSpecs : mEndSpecs;
|
||||
InstanceTimeList& instances = aIsBegin ? mBeginInstances : mEndInstances;
|
||||
|
||||
@ -1282,17 +1279,20 @@ nsSMILTimedElement::SetBeginOrEndSpec(const nsAString& aSpec,
|
||||
|
||||
AutoIntervalUpdateBatcher updateBatcher(*this);
|
||||
|
||||
do {
|
||||
start = end + 1;
|
||||
end = aSpec.FindChar(';', start);
|
||||
length = (end == -1) ? -1 : end - start;
|
||||
nsCharSeparatedTokenizer tokenizer(aSpec, ';');
|
||||
if (!tokenizer.hasMoreTokens()) { // Empty list
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsresult rv = NS_OK;
|
||||
while (tokenizer.hasMoreTokens() && NS_SUCCEEDED(rv)) {
|
||||
nsAutoPtr<nsSMILTimeValueSpec>
|
||||
spec(new nsSMILTimeValueSpec(*this, aIsBegin));
|
||||
rv = spec->SetSpec(Substring(aSpec, start, length), aContextNode);
|
||||
rv = spec->SetSpec(tokenizer.nextToken(), aContextNode);
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
timeSpecsList.AppendElement(spec.forget());
|
||||
}
|
||||
} while (end != -1 && NS_SUCCEEDED(rv));
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
ClearSpecs(timeSpecsList, instances, aRemove);
|
||||
|
@ -91,6 +91,7 @@ _TEST_FILES = \
|
||||
test_smilTiming.xhtml \
|
||||
test_smilTimingZeroIntervals.xhtml \
|
||||
test_smilUpdatedInterval.xhtml \
|
||||
test_smilValues.xhtml \
|
||||
test_smilXHR.xhtml \
|
||||
$(NULL)
|
||||
|
||||
|
@ -40,6 +40,8 @@
|
||||
/* Lists of valid & invalid values for the various <animateMotion> attributes */
|
||||
const gValidValues = [
|
||||
"10 10",
|
||||
"10 10;", // Trailing semicolons are allowed
|
||||
"10 10; ",
|
||||
" 10 10em ",
|
||||
"1 2 ; 3,4",
|
||||
"1,2;3,4",
|
||||
@ -49,7 +51,6 @@ const gValidValues = [
|
||||
|
||||
const gInvalidValues = [
|
||||
";10 10",
|
||||
"10 10;", // We treat semicolon-terminated value-lists as failure cases
|
||||
"10 10;;",
|
||||
"1 2 3",
|
||||
"1 2 3 4",
|
||||
@ -128,3 +129,30 @@ const gValidPathWithErrors = [
|
||||
"m0 0 L30,,30",
|
||||
"M10 10 L50 50 abc",
|
||||
];
|
||||
|
||||
const gValidKeyPoints = [
|
||||
"0; 0.5; 1",
|
||||
"0;.5;1",
|
||||
"0; 0; 1",
|
||||
"0; 1; 1",
|
||||
"0; 0; 1;", // Trailing semicolons are allowed
|
||||
"0; 0; 1; ",
|
||||
"0; 0.000; 1",
|
||||
"0; 0.000001; 1",
|
||||
];
|
||||
|
||||
const gInvalidKeyPoints = [
|
||||
"0; 1",
|
||||
"0; 1;",
|
||||
"0",
|
||||
"1",
|
||||
"a",
|
||||
"",
|
||||
" ",
|
||||
"0; -0.1; 1",
|
||||
"0; 1.1; 1",
|
||||
"0; 0.1; 1.1",
|
||||
"-0.1; 0.1; 1",
|
||||
"0; a; 1",
|
||||
"0;;1",
|
||||
];
|
||||
|
@ -64,6 +64,13 @@ function testAttr(aAttrName, aAttrValueArray, aIsValid, aIsTodo)
|
||||
// our value is rejected.
|
||||
anim.setAttribute("rotate", Math.PI/4);
|
||||
componentsToCheck = CTMUtil.CTM_COMPONENTS_ALL;
|
||||
if (aAttrName == "keyPoints") {
|
||||
// Add three times so we can test a greater range of values for
|
||||
// keyPoints
|
||||
anim.setAttribute("values", "0 0; 25 25; 50 50");
|
||||
anim.setAttribute("keyTimes", "0; 0.5; 1");
|
||||
anim.setAttribute("calcMode", "discrete");
|
||||
}
|
||||
}
|
||||
|
||||
var curCTM = gRect.getCTM();
|
||||
@ -158,6 +165,9 @@ function main()
|
||||
testAttr("path", gInvalidPath, false, false);
|
||||
testAttr("path", gValidPathWithErrors, true, false);
|
||||
|
||||
testAttr("keyPoints", gValidKeyPoints, true, false);
|
||||
testAttr("keyPoints", gInvalidKeyPoints, false, false);
|
||||
|
||||
testMpathElem(gValidPath, true, false);
|
||||
testMpathElem(gInvalidPath, false, false);
|
||||
|
||||
|
@ -18,91 +18,268 @@
|
||||
/** Test for SMIL timing **/
|
||||
|
||||
/* Global Variables */
|
||||
const svgns="http://www.w3.org/2000/svg";
|
||||
var svg = document.getElementById("svg");
|
||||
var circle = document.getElementById('circle');
|
||||
const svgns = "http://www.w3.org/2000/svg";
|
||||
var gSvg = document.getElementById("svg");
|
||||
var gCircle = document.getElementById('circle');
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function createAnim() {
|
||||
function main() {
|
||||
ok(gSvg.animationsPaused(), "should be paused by <svg> load handler");
|
||||
is(gSvg.getCurrentTime(), 0, "should be paused at 0 in <svg> load handler");
|
||||
|
||||
var testCases = Array();
|
||||
|
||||
const secPerMin = 60;
|
||||
const secPerHour = secPerMin * 60;
|
||||
|
||||
// In the following tests that compare start times, getStartTime will round
|
||||
// the start time to three decimal places since we expect our implementation
|
||||
// to be millisecond accurate.
|
||||
|
||||
// Offset syntax
|
||||
// -- Basic tests, sign and whitespace
|
||||
testCases.push(StartTimeTest('3s', 3));
|
||||
testCases.push(StartTimeTest('0s', 0));
|
||||
testCases.push(StartTimeTest('+2s', 2));
|
||||
testCases.push(StartTimeTest('-1s\t\r', -1));
|
||||
testCases.push(StartTimeTest('- 1s', -1));
|
||||
testCases.push(StartTimeTest(' -1s', -1));
|
||||
testCases.push(StartTimeTest(' - 1s', -1));
|
||||
testCases.push(StartTimeTest(' \t\n\r-1s', -1));
|
||||
testCases.push(StartTimeTest('+\n5s', 5));
|
||||
testCases.push(StartTimeTest('-\n5s', -5));
|
||||
testCases.push(StartTimeTest('\t 5s', 5));
|
||||
// -- These tests are from SMILANIM 3.6.7
|
||||
testCases.push(StartTimeTest('02:30:03', 2*secPerHour + 30*secPerMin + 3));
|
||||
testCases.push(StartTimeTest('50:00:10.25', 50*secPerHour + 10.25));
|
||||
testCases.push(StartTimeTest('02:33', 2*secPerMin + 33));
|
||||
testCases.push(StartTimeTest('00:10.5', 10.5));
|
||||
testCases.push(StartTimeTest('3.2h', 3.2*secPerHour));
|
||||
testCases.push(StartTimeTest('45min', 45*secPerMin));
|
||||
testCases.push(StartTimeTest('30s', 30));
|
||||
testCases.push(StartTimeTest('5ms', 0.005));
|
||||
testCases.push(StartTimeTest('12.467', 12.467));
|
||||
testCases.push(StartTimeTest('00.5s', 0.5));
|
||||
testCases.push(StartTimeTest('00:00.005', 0.005));
|
||||
// -- Additional tests
|
||||
testCases.push(StartTimeTest('61:59:59', 61*secPerHour + 59*secPerMin + 59));
|
||||
testCases.push(StartTimeTest('02:59.999999999999999999999', 3*secPerMin));
|
||||
testCases.push(StartTimeTest('1234:23:45',
|
||||
1234*secPerHour + 23*secPerMin + 45));
|
||||
testCases.push(StartTimeTest('61min', 61*secPerMin));
|
||||
testCases.push(StartTimeTest('0:30:03', 30*secPerMin + 3));
|
||||
// -- Fractional precision
|
||||
testCases.push(StartTimeTest('25.4567', 25.457));
|
||||
testCases.push(StartTimeTest('0.123456789', 0.123));
|
||||
testCases.push(StartTimeTest('0.00000000000000000000001', 0));
|
||||
testCases.push(StartTimeTest('-0.00000000000000000000001', 0));
|
||||
testCases.push(StartTimeTest('0.0009', 0.001));
|
||||
testCases.push(StartTimeTest('0.99999999999999999999999999999999999999', 1));
|
||||
testCases.push(StartTimeTest('23.4567ms', 0.023));
|
||||
testCases.push(StartTimeTest('23.7ms', 0.024));
|
||||
// -- Test errors
|
||||
testCases.push(StartTimeTest(' + +3s', 'none'));
|
||||
testCases.push(StartTimeTest(' +-3s', 'none'));
|
||||
testCases.push(StartTimeTest('1:12:12:12', 'none'));
|
||||
testCases.push(StartTimeTest('4:50:60', 'none'));
|
||||
testCases.push(StartTimeTest('4:60:0', 'none'));
|
||||
testCases.push(StartTimeTest('4:60', 'none'));
|
||||
testCases.push(StartTimeTest('4:-1:00', 'none'));
|
||||
testCases.push(StartTimeTest('4 5m', 'none'));
|
||||
testCases.push(StartTimeTest('4 5ms', 'none'));
|
||||
testCases.push(StartTimeTest('02:3:03', 'none'));
|
||||
testCases.push(StartTimeTest('45.7 s', 'none'));
|
||||
testCases.push(StartTimeTest(' 3 h ', 'none'));
|
||||
testCases.push(StartTimeTest('2:33 ', 'none'));
|
||||
testCases.push(StartTimeTest('02:33 2', 'none'));
|
||||
testCases.push(StartTimeTest('\u000B 02:33', 'none'));
|
||||
testCases.push(StartTimeTest('h', 'none'));
|
||||
testCases.push(StartTimeTest('23.s', 'none'));
|
||||
testCases.push(StartTimeTest('23.', 'none'));
|
||||
testCases.push(StartTimeTest('23.54.2s', 'none'));
|
||||
testCases.push(StartTimeTest('23sec', 'none'));
|
||||
testCases.push(StartTimeTest('five', 'none'));
|
||||
testCases.push(StartTimeTest('', 'none'));
|
||||
testCases.push(StartTimeTest('02:33s', 'none'));
|
||||
testCases.push(StartTimeTest('02:33 s', 'none'));
|
||||
testCases.push(StartTimeTest('2.54e6', 'none'));
|
||||
testCases.push(StartTimeTest('02.5:33', 'none'));
|
||||
testCases.push(StartTimeTest('2:-45:33', 'none'));
|
||||
testCases.push(StartTimeTest('2:4.5:33', 'none'));
|
||||
testCases.push(StartTimeTest('45m', 'none'));
|
||||
testCases.push(StartTimeTest(':20:30', 'none'));
|
||||
testCases.push(StartTimeTest('1.5:30', 'none'));
|
||||
testCases.push(StartTimeTest('15:-30', 'none'));
|
||||
testCases.push(StartTimeTest('::30', 'none'));
|
||||
testCases.push(StartTimeTest('15:30s', 'none'));
|
||||
testCases.push(StartTimeTest('2:1.:30', 'none'));
|
||||
testCases.push(StartTimeTest('2:.1:30', 'none'));
|
||||
testCases.push(StartTimeTest('2.0:15:30', 'none'));
|
||||
testCases.push(StartTimeTest('2.:15:30', 'none'));
|
||||
testCases.push(StartTimeTest('.2:15:30', 'none'));
|
||||
testCases.push(StartTimeTest('70:15', 'none'));
|
||||
testCases.push(StartTimeTest('media', 'none'));
|
||||
testCases.push(StartTimeTest('5mi', 'none'));
|
||||
testCases.push(StartTimeTest('5hours', 'none'));
|
||||
testCases.push(StartTimeTest('h05:30', 'none'));
|
||||
testCases.push(StartTimeTest('05:40\x9A', 'none'));
|
||||
testCases.push(StartTimeTest('05:40\u30D5', 'none'));
|
||||
testCases.push(StartTimeTest('05:40β', 'none'));
|
||||
|
||||
// List syntax
|
||||
testCases.push(StartTimeTest('3', 3));
|
||||
testCases.push(StartTimeTest('3;', 3));
|
||||
testCases.push(StartTimeTest('3; ', 3));
|
||||
testCases.push(StartTimeTest('3 ; ', 3));
|
||||
testCases.push(StartTimeTest('3;;', 'none'));
|
||||
testCases.push(StartTimeTest('3;; ', 'none'));
|
||||
testCases.push(StartTimeTest(';3', 'none'));
|
||||
testCases.push(StartTimeTest(' ;3', 'none'));
|
||||
testCases.push(StartTimeTest('3;4', 3));
|
||||
testCases.push(StartTimeTest(' 3 ; 4 ', 3));
|
||||
|
||||
// List syntax on end times
|
||||
testCases.push({
|
||||
'attr' : { 'begin': '0s',
|
||||
'end': '1s; 2s' },
|
||||
'times': [ [ 0, 0 ],
|
||||
[ 1, -100 ] ]
|
||||
});
|
||||
testCases.push({
|
||||
'attr' : { 'begin': '0s',
|
||||
'end': '1s; 2s; ' },
|
||||
'times': [ [ 0, 0 ],
|
||||
[ 1, -100 ] ]
|
||||
});
|
||||
testCases.push({
|
||||
'attr' : { 'begin': '0s',
|
||||
'end': '3s; 2s' },
|
||||
'times': [ [ 0, 0 ],
|
||||
[ 1, 10 ],
|
||||
[ 2, -100 ] ]
|
||||
});
|
||||
|
||||
// Simple case
|
||||
testCases.push({
|
||||
'attr' : { 'begin': '3s' },
|
||||
'times': [ [ 0, -100 ],
|
||||
[ 4, 10 ] ]
|
||||
});
|
||||
|
||||
// Multiple begins
|
||||
testCases.push({
|
||||
'attr' : { 'begin': '2s; 6s',
|
||||
'dur': '2s' },
|
||||
'times': [ [ 0, -100 ],
|
||||
[ 3, 50 ],
|
||||
[ 4, -100 ],
|
||||
[ 7, 50 ],
|
||||
[ 8, -100 ] ]
|
||||
});
|
||||
|
||||
// Negative begins
|
||||
testCases.push({
|
||||
'attr' : { 'begin': '-3s; 1s ; 4s',
|
||||
'dur': '2s ',
|
||||
'fill': 'freeze' },
|
||||
'times': [ [ 0, -100 ],
|
||||
[ 0.5, -100 ],
|
||||
[ 1, 0 ],
|
||||
[ 2, 50 ],
|
||||
[ 3, 100 ],
|
||||
[ 5, 50 ] ]
|
||||
});
|
||||
|
||||
// Sorting
|
||||
testCases.push({
|
||||
'attr' : { 'begin': '-3s; 110s; 1s; 4s; -5s; -10s',
|
||||
'end': '111s; -5s; -15s; 6s; -5s; 1.2s',
|
||||
'dur': '2s ',
|
||||
'fill': 'freeze' },
|
||||
'times': [ [ 0, -100 ],
|
||||
[ 1, 0 ],
|
||||
[ 2, 10 ],
|
||||
[ 4, 0 ],
|
||||
[ 5, 50 ],
|
||||
[ 109, 100 ],
|
||||
[ 110, 0 ],
|
||||
[ 112, 50 ] ]
|
||||
});
|
||||
|
||||
for (var i = 0; i < testCases.length; i++) {
|
||||
gSvg.setCurrentTime(0);
|
||||
var test = testCases[i];
|
||||
|
||||
// Generate string version of params for output messages
|
||||
var params = "";
|
||||
for (var name in test.attr) {
|
||||
params += name + '="' + test.attr[name] + '" ';
|
||||
}
|
||||
params = params.trim();
|
||||
|
||||
// Create animation elements
|
||||
var anim = createAnim(test.attr);
|
||||
|
||||
// Run samples
|
||||
if ('times' in test) {
|
||||
for (var j = 0; j < test.times.length; j++) {
|
||||
var curSample = test.times[j];
|
||||
checkSample(curSample[0], curSample[1], params);
|
||||
}
|
||||
}
|
||||
|
||||
// Check start time
|
||||
if ('startTime' in test) {
|
||||
is(getStartTime(anim), test.startTime,
|
||||
"Got unexpected start time for " + params);
|
||||
}
|
||||
|
||||
anim.parentNode.removeChild(anim);
|
||||
}
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function createAnim(attr) {
|
||||
var anim = document.createElementNS(svgns,'animate');
|
||||
anim.setAttribute('attributeName','cx');
|
||||
anim.setAttribute('from','0');
|
||||
anim.setAttribute('to','100');
|
||||
anim.setAttribute('dur','10s');
|
||||
anim.setAttribute('begin','indefinite');
|
||||
return circle.appendChild(anim);
|
||||
}
|
||||
|
||||
function removeAnim(anim) {
|
||||
anim.parentNode.removeChild(anim);
|
||||
}
|
||||
|
||||
function main() {
|
||||
ok(svg.animationsPaused(), "should be paused by <svg> load handler");
|
||||
is(svg.getCurrentTime(), 0, "should be paused at 0 in <svg> load handler");
|
||||
|
||||
var tests =
|
||||
[ testOffsetStartup,
|
||||
testMultipleBegins,
|
||||
testNegativeBegins,
|
||||
testSorting
|
||||
];
|
||||
for (var i = 0; i < tests.length; i++) {
|
||||
var anim = createAnim();
|
||||
svg.setCurrentTime(0);
|
||||
tests[i](anim);
|
||||
removeAnim(anim);
|
||||
for (name in attr) {
|
||||
anim.setAttribute(name, attr[name]);
|
||||
}
|
||||
SimpleTest.finish();
|
||||
return gCircle.appendChild(anim);
|
||||
}
|
||||
|
||||
function checkSample(time, expectedValue) {
|
||||
svg.setCurrentTime(time);
|
||||
is(circle.cx.animVal.value, expectedValue);
|
||||
function checkSample(time, expectedValue, params) {
|
||||
gSvg.setCurrentTime(time);
|
||||
var msg = "Unexpected sample value for " + params +
|
||||
" at t=" + time + ": ";
|
||||
is(gCircle.cx.animVal.value, expectedValue);
|
||||
}
|
||||
|
||||
function testOffsetStartup(anim) {
|
||||
anim.setAttribute('begin', '3s');
|
||||
checkSample(0,-100);
|
||||
checkSample(4,10);
|
||||
function getStartTime(anim) {
|
||||
var startTime;
|
||||
try {
|
||||
startTime = anim.getStartTime();
|
||||
// We round start times to 3 decimal places to make comparisons simpler
|
||||
startTime = parseFloat(startTime.toFixed(3));
|
||||
} catch(e) {
|
||||
if (e.code == DOMException.INVALID_STATE_ERR) {
|
||||
startTime = 'none';
|
||||
} else {
|
||||
ok(false, "Unexpected exception: " + e);
|
||||
}
|
||||
}
|
||||
return startTime;
|
||||
}
|
||||
|
||||
function testMultipleBegins(anim) {
|
||||
anim.setAttribute('begin', '2s; 6s');
|
||||
anim.setAttribute('dur', ' 2s');
|
||||
checkSample(0,-100);
|
||||
checkSample(3,50);
|
||||
checkSample(4,-100);
|
||||
checkSample(7,50);
|
||||
checkSample(8,-100);
|
||||
}
|
||||
|
||||
function testNegativeBegins(anim) {
|
||||
anim.setAttribute('begin', '-3s; 1s ; 4s');
|
||||
anim.setAttribute('dur', '2s ');
|
||||
anim.setAttribute('fill', 'freeze');
|
||||
checkSample(0,-100);
|
||||
checkSample(0.5,-100);
|
||||
checkSample(1,0);
|
||||
checkSample(2,50);
|
||||
checkSample(3,100);
|
||||
checkSample(5,50);
|
||||
}
|
||||
|
||||
function testSorting(anim) {
|
||||
anim.setAttribute('begin', '-3s; 110s; 1s; 4s; -5s; -10s');
|
||||
anim.setAttribute('end', '111s; -5s; -15s; 6s; -5s; 1.2s');
|
||||
anim.setAttribute('dur', '2s ');
|
||||
anim.setAttribute('fill', 'freeze');
|
||||
checkSample(0,-100);
|
||||
checkSample(1,0);
|
||||
checkSample(2,10);
|
||||
checkSample(4,0);
|
||||
checkSample(5,50);
|
||||
checkSample(109,100);
|
||||
checkSample(110,0);
|
||||
checkSample(112,50);
|
||||
function StartTimeTest(beginSpec, expectedStartTime) {
|
||||
return { 'attr' : { 'begin': beginSpec },
|
||||
'startTime': expectedStartTime };
|
||||
}
|
||||
|
||||
window.addEventListener("load", main, false);
|
||||
|
170
content/smil/test/test_smilValues.xhtml
Normal file
170
content/smil/test/test_smilValues.xhtml
Normal file
@ -0,0 +1,170 @@
|
||||
<html xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<title>Test for SMIL values</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank"
|
||||
href="https://bugzilla.mozilla.org/show_bug.cgi?id=557885">Mozilla Bug
|
||||
474742</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
<svg id="svg" xmlns="http://www.w3.org/2000/svg" width="120px" height="120px">
|
||||
<circle cx="-100" cy="20" r="15" fill="blue" id="circle"/>
|
||||
</svg>
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="text/javascript">
|
||||
<![CDATA[
|
||||
/** Test for SMIL values **/
|
||||
|
||||
var gSvg = document.getElementById("svg");
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function main()
|
||||
{
|
||||
gSvg.pauseAnimations();
|
||||
|
||||
var testCases = Array();
|
||||
|
||||
// Single value
|
||||
testCases.push({
|
||||
'attr' : { 'values': 'a' },
|
||||
'times': [ [ 0, 'a' ] ]
|
||||
});
|
||||
|
||||
// The parsing below is based on the following discussion:
|
||||
//
|
||||
// http://lists.w3.org/Archives/Public/www-svg/2011Nov/0136.html
|
||||
//
|
||||
// In summary:
|
||||
// * Values lists are semi-colon delimited and semi-colon terminated.
|
||||
// * However, if there are extra non-whitespace characters after the final
|
||||
// semi-colon then there's an implied semi-colon at the end.
|
||||
//
|
||||
// This differs to what is specified in SVG 1.1 but is consistent with the
|
||||
// majority of browsers and with existing content (particularly that generated
|
||||
// by Ikivo Animator).
|
||||
|
||||
// Trailing semi-colon
|
||||
testCases.push({
|
||||
'attr' : { 'values': 'a;' },
|
||||
'times': [ [ 0, 'a' ], [ 10, 'a' ] ]
|
||||
});
|
||||
|
||||
// Trailing semi-colon + whitespace
|
||||
testCases.push({
|
||||
'attr' : { 'values': 'a; ' },
|
||||
'times': [ [ 0, 'a' ], [ 10, 'a' ] ]
|
||||
});
|
||||
|
||||
// Whitespace + trailing semi-colon
|
||||
testCases.push({
|
||||
'attr' : { 'values': 'a ;' },
|
||||
'times': [ [ 0, 'a' ], [ 10, 'a' ] ]
|
||||
});
|
||||
|
||||
// Empty at end
|
||||
testCases.push({
|
||||
'attr' : { 'values': 'a;;' },
|
||||
'times': [ [ 0, 'a' ], [ 5, '' ], [ 10, '' ] ]
|
||||
});
|
||||
|
||||
// Empty at end + whitespace
|
||||
testCases.push({
|
||||
'attr' : { 'values': 'a;; ' },
|
||||
'times': [ [ 0, 'a' ], [ 4, 'a' ], [ 5, '' ], [ 10, '' ] ]
|
||||
});
|
||||
|
||||
// Empty in middle
|
||||
testCases.push({
|
||||
'attr' : { 'values': 'a;;b' },
|
||||
'times': [ [ 0, 'a' ], [ 5, '' ], [ 10, 'b' ] ]
|
||||
});
|
||||
|
||||
// Empty in middle + trailing semi-colon
|
||||
testCases.push({
|
||||
'attr' : { 'values': 'a;;b;' },
|
||||
'times': [ [ 0, 'a' ], [ 5, '' ], [ 10, 'b' ] ]
|
||||
});
|
||||
|
||||
// Whitespace in middle
|
||||
testCases.push({
|
||||
'attr' : { 'values': 'a; ;b' },
|
||||
'times': [ [ 0, 'a' ], [ 5, '' ], [ 10, 'b' ] ]
|
||||
});
|
||||
|
||||
// Empty at start
|
||||
testCases.push({
|
||||
'attr' : { 'values': ';a' },
|
||||
'times': [ [ 0, '' ], [ 5, 'a' ], [ 10, 'a' ] ]
|
||||
});
|
||||
|
||||
// Whitespace at start
|
||||
testCases.push({
|
||||
'attr' : { 'values': ' ;a' },
|
||||
'times': [ [ 0, '' ], [ 5, 'a' ], [ 10, 'a' ] ]
|
||||
});
|
||||
|
||||
// Embedded whitespace
|
||||
testCases.push({
|
||||
'attr' : { 'values': ' a b ; c d ' },
|
||||
'times': [ [ 0, 'a b' ], [ 5, 'c d' ], [ 10, 'c d' ] ]
|
||||
});
|
||||
|
||||
// Whitespace only
|
||||
testCases.push({
|
||||
'attr' : { 'values': ' ' },
|
||||
'times': [ [ 0, '' ], [ 10, '' ] ]
|
||||
});
|
||||
|
||||
for (var i = 0; i < testCases.length; i++) {
|
||||
gSvg.setCurrentTime(0);
|
||||
var test = testCases[i];
|
||||
|
||||
// Create animation elements
|
||||
var anim = createAnim(test.attr);
|
||||
|
||||
// Run samples
|
||||
for (var j = 0; j < test.times.length; j++) {
|
||||
var curSample = test.times[j];
|
||||
gSvg.setCurrentTime(curSample[0]);
|
||||
checkSample(anim, curSample[1], curSample[0], i);
|
||||
}
|
||||
|
||||
anim.parentNode.removeChild(anim);
|
||||
}
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function createAnim(attr)
|
||||
{
|
||||
const svgns = "http://www.w3.org/2000/svg";
|
||||
var anim = document.createElementNS(svgns, 'animate');
|
||||
anim.setAttribute('attributeName','class');
|
||||
anim.setAttribute('dur','10s');
|
||||
anim.setAttribute('begin','0s');
|
||||
anim.setAttribute('fill','freeze');
|
||||
for (name in attr) {
|
||||
anim.setAttribute(name, attr[name]);
|
||||
}
|
||||
return document.getElementById('circle').appendChild(anim);
|
||||
}
|
||||
|
||||
function checkSample(anim, expectedValue, sampleTime, caseNum)
|
||||
{
|
||||
var msg = "Test case " + caseNum +
|
||||
" (values: '" + anim.getAttribute('values') + "')," +
|
||||
"t=" + sampleTime +
|
||||
": Unexpected sample value:";
|
||||
is(anim.targetElement.className.animVal, expectedValue, msg);
|
||||
}
|
||||
|
||||
window.addEventListener("load", main, false);
|
||||
]]>
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -447,7 +447,7 @@ SVGMotionSMILAnimationFunction::SetKeyPoints(const nsAString& aKeyPoints,
|
||||
void
|
||||
SVGMotionSMILAnimationFunction::UnsetKeyPoints()
|
||||
{
|
||||
mKeyTimes.Clear();
|
||||
mKeyPoints.Clear();
|
||||
SetKeyPointsErrorFlag(false);
|
||||
mHasChanged = true;
|
||||
}
|
||||
|
@ -153,7 +153,7 @@ NS_IMETHODIMP nsXPathNamespace::HasChildNodes(bool *aResult)
|
||||
}
|
||||
|
||||
/* nsIDOMNode cloneNode (in boolean deep); */
|
||||
NS_IMETHODIMP nsXPathNamespace::CloneNode(bool deep, nsIDOMNode **aResult)
|
||||
NS_IMETHODIMP nsXPathNamespace::CloneNode(bool deep, PRUint8 aOptionalArgc, nsIDOMNode **aResult)
|
||||
{
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
@ -677,7 +677,7 @@ nsXULContentBuilder::BuildContentFromTemplate(nsIContent *aTemplateNode,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
nsCOMPtr<nsIDOMNode> clonedNode;
|
||||
tmplTextNode->CloneNode(false, getter_AddRefs(clonedNode));
|
||||
tmplTextNode->CloneNode(false, 1, getter_AddRefs(clonedNode));
|
||||
nsCOMPtr<nsIContent> clonedContent = do_QueryInterface(clonedNode);
|
||||
if (!clonedContent) {
|
||||
NS_ERROR("failed to clone textnode");
|
||||
|
@ -2310,34 +2310,6 @@ nsDocShell::HistoryTransactionRemoved(PRInt32 aIndex)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static
|
||||
nsresult
|
||||
GetPrincipalDomain(nsIPrincipal* aPrincipal, nsACString& aDomain)
|
||||
{
|
||||
aDomain.Truncate();
|
||||
|
||||
nsCOMPtr<nsIURI> codebaseURI;
|
||||
nsresult rv = aPrincipal->GetDomain(getter_AddRefs(codebaseURI));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!codebaseURI) {
|
||||
rv = aPrincipal->GetURI(getter_AddRefs(codebaseURI));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
|
||||
if (!codebaseURI)
|
||||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIURI> innerURI = NS_GetInnermostURI(codebaseURI);
|
||||
NS_ASSERTION(innerURI, "Failed to get innermost URI");
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
rv = innerURI->GetAsciiHost(aDomain);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocShell::GetSessionStorageForPrincipal(nsIPrincipal* aPrincipal,
|
||||
const nsAString& aDocumentURI,
|
||||
@ -2367,15 +2339,15 @@ nsDocShell::GetSessionStorageForPrincipal(nsIPrincipal* aPrincipal,
|
||||
aCreate,
|
||||
aStorage);
|
||||
|
||||
nsCAutoString currentDomain;
|
||||
rv = GetPrincipalDomain(aPrincipal, currentDomain);
|
||||
nsXPIDLCString origin;
|
||||
rv = aPrincipal->GetOrigin(getter_Copies(origin));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
if (currentDomain.IsEmpty())
|
||||
if (origin.IsEmpty())
|
||||
return NS_OK;
|
||||
|
||||
if (!mStorages.Get(currentDomain, aStorage) && aCreate) {
|
||||
if (!mStorages.Get(origin, aStorage) && aCreate) {
|
||||
nsCOMPtr<nsIDOMStorage> newstorage =
|
||||
do_CreateInstance("@mozilla.org/dom/storage;2");
|
||||
if (!newstorage)
|
||||
@ -2384,11 +2356,12 @@ nsDocShell::GetSessionStorageForPrincipal(nsIPrincipal* aPrincipal,
|
||||
nsCOMPtr<nsPIDOMStorage> pistorage = do_QueryInterface(newstorage);
|
||||
if (!pistorage)
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
rv = pistorage->InitAsSessionStorage(aPrincipal, aDocumentURI);
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
if (!mStorages.Put(currentDomain, newstorage))
|
||||
if (!mStorages.Put(origin, newstorage))
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
newstorage.swap(*aStorage);
|
||||
@ -2399,22 +2372,32 @@ nsDocShell::GetSessionStorageForPrincipal(nsIPrincipal* aPrincipal,
|
||||
#endif
|
||||
}
|
||||
else if (*aStorage) {
|
||||
nsCOMPtr<nsPIDOMStorage> piStorage = do_QueryInterface(*aStorage);
|
||||
if (piStorage) {
|
||||
bool canAccess = piStorage->CanAccess(aPrincipal);
|
||||
NS_ASSERTION(canAccess,
|
||||
"GetSessionStorageForPrincipal got a storage "
|
||||
"that could not be accessed!");
|
||||
if (!canAccess) {
|
||||
NS_RELEASE(*aStorage);
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
}
|
||||
nsCOMPtr<nsPIDOMStorage> piStorage = do_QueryInterface(*aStorage);
|
||||
if (piStorage) {
|
||||
nsCOMPtr<nsIPrincipal> storagePrincipal = piStorage->Principal();
|
||||
|
||||
// The origin string used to map items in the hash table is
|
||||
// an implicit security check. That check is double-confirmed
|
||||
// by checking the principal a storage was demanded for
|
||||
// really is the principal for which that storage was originally
|
||||
// created. Originally, the check was hidden in the CanAccess
|
||||
// method but it's implementation has changed.
|
||||
bool equals;
|
||||
nsresult rv = aPrincipal->EqualsIgnoringDomain(storagePrincipal, &equals);
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv) && equals,
|
||||
"GetSessionStorageForPrincipal got a storage "
|
||||
"that could not be accessed!");
|
||||
|
||||
if (NS_FAILED(rv) || !equals) {
|
||||
NS_RELEASE(*aStorage);
|
||||
return NS_ERROR_DOM_SECURITY_ERR;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(PR_LOGGING) && defined(DEBUG)
|
||||
PR_LOG(gDocShellLog, PR_LOG_DEBUG,
|
||||
("nsDocShell[%p]: returns existing sessionStorage %p",
|
||||
this, *aStorage));
|
||||
PR_LOG(gDocShellLog, PR_LOG_DEBUG,
|
||||
("nsDocShell[%p]: returns existing sessionStorage %p",
|
||||
this, *aStorage));
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -2499,16 +2482,16 @@ nsDocShell::AddSessionStorage(nsIPrincipal* aPrincipal,
|
||||
if (topItem) {
|
||||
nsCOMPtr<nsIDocShell> topDocShell = do_QueryInterface(topItem);
|
||||
if (topDocShell == this) {
|
||||
nsCAutoString currentDomain;
|
||||
rv = GetPrincipalDomain(aPrincipal, currentDomain);
|
||||
nsXPIDLCString origin;
|
||||
rv = aPrincipal->GetOrigin(getter_Copies(origin));
|
||||
if (NS_FAILED(rv))
|
||||
return rv;
|
||||
|
||||
if (currentDomain.IsEmpty())
|
||||
if (origin.IsEmpty())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
// Do not replace an existing session storage.
|
||||
if (mStorages.GetWeak(currentDomain))
|
||||
if (mStorages.GetWeak(origin))
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
|
||||
#if defined(PR_LOGGING) && defined(DEBUG)
|
||||
@ -2516,7 +2499,7 @@ nsDocShell::AddSessionStorage(nsIPrincipal* aPrincipal,
|
||||
("nsDocShell[%p]: was added a sessionStorage %p",
|
||||
this, aStorage));
|
||||
#endif
|
||||
if (!mStorages.Put(currentDomain, aStorage))
|
||||
if (!mStorages.Put(origin, aStorage))
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
else {
|
||||
|
173
dom/base/DOMRequest.cpp
Normal file
173
dom/base/DOMRequest.cpp
Normal file
@ -0,0 +1,173 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "DOMRequest.h"
|
||||
|
||||
#include "mozilla/Util.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
#include "DOMError.h"
|
||||
#include "nsEventDispatcher.h"
|
||||
#include "nsIPrivateDOMEvent.h"
|
||||
#include "nsDOMEvent.h"
|
||||
|
||||
using mozilla::dom::DOMRequest;
|
||||
using mozilla::dom::DOMRequestService;
|
||||
|
||||
DOMRequest::DOMRequest(nsIDOMWindow* aWindow)
|
||||
: mDone(false)
|
||||
, mResult(JSVAL_VOID)
|
||||
, mRooted(false)
|
||||
{
|
||||
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(aWindow);
|
||||
mOwner = window->IsInnerWindow() ? window.get() :
|
||||
window->GetCurrentInnerWindow();
|
||||
|
||||
nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aWindow);
|
||||
mScriptContext = sgo->GetContext();
|
||||
}
|
||||
|
||||
DOMCI_DATA(DOMRequest, DOMRequest)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(DOMRequest)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(DOMRequest,
|
||||
nsDOMEventTargetHelper)
|
||||
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(success)
|
||||
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(error)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(DOMRequest,
|
||||
nsDOMEventTargetHelper)
|
||||
tmp->mResult = JSVAL_VOID;
|
||||
tmp->UnrootResultVal();
|
||||
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(success)
|
||||
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(error)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(DOMRequest,
|
||||
nsDOMEventTargetHelper)
|
||||
// Don't need NS_IMPL_CYCLE_COLLECTION_TRACE_PRESERVED_WRAPPER because
|
||||
// nsDOMEventTargetHelper does it for us.
|
||||
if (JSVAL_IS_GCTHING(tmp->mResult)) {
|
||||
void *gcThing = JSVAL_TO_GCTHING(tmp->mResult);
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_CALLBACK(gcThing, "mResult")
|
||||
}
|
||||
NS_IMPL_CYCLE_COLLECTION_TRACE_END
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(DOMRequest)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMDOMRequest)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(DOMRequest)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(DOMRequest, nsDOMEventTargetHelper)
|
||||
NS_IMPL_RELEASE_INHERITED(DOMRequest, nsDOMEventTargetHelper)
|
||||
|
||||
NS_IMPL_EVENT_HANDLER(DOMRequest, success);
|
||||
NS_IMPL_EVENT_HANDLER(DOMRequest, error);
|
||||
|
||||
NS_IMETHODIMP
|
||||
DOMRequest::GetReadyState(nsAString& aReadyState)
|
||||
{
|
||||
mDone ? aReadyState.AssignLiteral("done") :
|
||||
aReadyState.AssignLiteral("pending");
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DOMRequest::GetResult(jsval* aResult)
|
||||
{
|
||||
NS_ASSERTION(mDone || mResult == JSVAL_VOID,
|
||||
"Result should be undefined when pending");
|
||||
*aResult = mResult;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DOMRequest::GetError(nsIDOMDOMError** aError)
|
||||
{
|
||||
NS_ASSERTION(mDone || !mError,
|
||||
"Error should be null when pending");
|
||||
|
||||
NS_IF_ADDREF(*aError = mError);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
DOMRequest::FireSuccess(jsval aResult)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(!mDone, "Already fired success/error");
|
||||
|
||||
mDone = true;
|
||||
RootResultVal();
|
||||
mResult = aResult;
|
||||
|
||||
FireEvent(NS_LITERAL_STRING("success"));
|
||||
}
|
||||
|
||||
void
|
||||
DOMRequest::FireError(const nsAString& aError)
|
||||
{
|
||||
NS_ABORT_IF_FALSE(!mDone, "Already fired success/error");
|
||||
|
||||
mDone = true;
|
||||
mError = DOMError::CreateWithName(aError);
|
||||
|
||||
FireEvent(NS_LITERAL_STRING("error"));
|
||||
}
|
||||
|
||||
void
|
||||
DOMRequest::FireEvent(const nsAString& aType)
|
||||
{
|
||||
if (NS_FAILED(CheckInnerWindowCorrectness())) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsRefPtr<nsDOMEvent> event = new nsDOMEvent(nsnull, nsnull);
|
||||
nsresult rv = event->InitEvent(aType, false, false);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
rv = event->SetTrusted(PR_TRUE);
|
||||
if (NS_FAILED(rv)) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool dummy;
|
||||
DispatchEvent(event, &dummy);
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS1(DOMRequestService, nsIDOMRequestService)
|
||||
|
||||
NS_IMETHODIMP
|
||||
DOMRequestService::CreateRequest(nsIDOMWindow* aWindow,
|
||||
nsIDOMDOMRequest** aRequest)
|
||||
{
|
||||
NS_ADDREF(*aRequest = new DOMRequest(aWindow));
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DOMRequestService::FireSuccess(nsIDOMDOMRequest* aRequest,
|
||||
const jsval& aResult)
|
||||
{
|
||||
static_cast<DOMRequest*>(aRequest)->FireSuccess(aResult);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
DOMRequestService::FireError(nsIDOMDOMRequest* aRequest,
|
||||
const nsAString& aError)
|
||||
{
|
||||
static_cast<DOMRequest*>(aRequest)->FireError(aError);
|
||||
|
||||
return NS_OK;
|
||||
}
|
89
dom/base/DOMRequest.h
Normal file
89
dom/base/DOMRequest.h
Normal file
@ -0,0 +1,89 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_domrequest_h__
|
||||
#define mozilla_dom_domrequest_h__
|
||||
|
||||
#include "nsIDOMDOMRequest.h"
|
||||
#include "nsIDOMDOMError.h"
|
||||
#include "nsDOMEventTargetHelper.h"
|
||||
#include "nsContentUtils.h"
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class DOMRequest : public nsDOMEventTargetHelper,
|
||||
public nsIDOMDOMRequest
|
||||
{
|
||||
bool mDone;
|
||||
jsval mResult;
|
||||
nsCOMPtr<nsIDOMDOMError> mError;
|
||||
bool mRooted;
|
||||
|
||||
NS_DECL_EVENT_HANDLER(success)
|
||||
NS_DECL_EVENT_HANDLER(error)
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSIDOMDOMREQUEST
|
||||
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(DOMRequest,
|
||||
nsDOMEventTargetHelper)
|
||||
|
||||
void FireSuccess(jsval aResult);
|
||||
void FireError(const nsAString& aError);
|
||||
|
||||
DOMRequest(nsIDOMWindow* aWindow);
|
||||
|
||||
virtual ~DOMRequest()
|
||||
{
|
||||
UnrootResultVal();
|
||||
}
|
||||
|
||||
private:
|
||||
void FireEvent(const nsAString& aType);
|
||||
|
||||
void RootResultVal()
|
||||
{
|
||||
if (!mRooted) {
|
||||
NS_HOLD_JS_OBJECTS(this, DOMRequest);
|
||||
mRooted = true;
|
||||
}
|
||||
}
|
||||
|
||||
void UnrootResultVal()
|
||||
{
|
||||
if (mRooted) {
|
||||
NS_DROP_JS_OBJECTS(this, DOMRequest);
|
||||
mRooted = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class DOMRequestService : public nsIDOMRequestService
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIDOMREQUESTSERVICE
|
||||
|
||||
// Returns an owning reference! No one should call this but the factory.
|
||||
static DOMRequestService* FactoryCreate()
|
||||
{
|
||||
DOMRequestService* res = new DOMRequestService;
|
||||
NS_ADDREF(res);
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#define DOMREQUEST_SERVICE_CONTRACTID "@mozilla.org/dom/dom-request-service;1"
|
||||
|
||||
#endif // mozilla_dom_domrequest_h__
|
@ -47,6 +47,10 @@ LIBRARY_NAME = jsdombase_s
|
||||
LIBXUL_LIBRARY = 1
|
||||
FORCE_STATIC_LIB = 1
|
||||
|
||||
DIRS = \
|
||||
test \
|
||||
$(NULL)
|
||||
|
||||
EXTRA_PP_COMPONENTS = \
|
||||
ConsoleAPI.js \
|
||||
ConsoleAPI.manifest \
|
||||
@ -67,6 +71,7 @@ endif
|
||||
|
||||
XPIDLSRCS = \
|
||||
nsIDOMDOMError.idl \
|
||||
nsIDOMDOMRequest.idl \
|
||||
nsIEntropyCollector.idl \
|
||||
nsIScriptChannel.idl \
|
||||
$(NULL)
|
||||
@ -105,6 +110,7 @@ EXPORTS = \
|
||||
EXPORTS_NAMESPACES = mozilla/dom
|
||||
EXPORTS_mozilla/dom = \
|
||||
DOMError.h \
|
||||
DOMRequest.h \
|
||||
StructuredCloneTags.h \
|
||||
$(NULL)
|
||||
|
||||
@ -135,6 +141,7 @@ CPPSRCS = \
|
||||
nsPerformance.cpp \
|
||||
nsDOMMemoryReporter.cpp \
|
||||
DOMError.cpp \
|
||||
DOMRequest.cpp \
|
||||
Navigator.cpp \
|
||||
$(NULL)
|
||||
|
||||
|
@ -537,6 +537,7 @@ using mozilla::dom::indexedDB::IDBWrapperCache;
|
||||
#endif
|
||||
|
||||
#include "DOMError.h"
|
||||
#include "DOMRequest.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
@ -1543,6 +1544,8 @@ static nsDOMClassInfoData sClassInfoData[] = {
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA(WebGLExtensionStandardDerivatives, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA(WebGLExtensionTextureFilterAnisotropic, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
NS_DEFINE_CLASSINFO_DATA(WebGLExtensionLoseContext, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
|
||||
@ -1638,6 +1641,9 @@ static nsDOMClassInfoData sClassInfoData[] = {
|
||||
|
||||
NS_DEFINE_CLASSINFO_DATA(DOMError, nsDOMGenericSH,
|
||||
DOM_DEFAULT_SCRIPTABLE_FLAGS)
|
||||
|
||||
NS_DEFINE_CLASSINFO_DATA(DOMRequest, nsEventTargetSH,
|
||||
EVENTTARGET_SCRIPTABLE_FLAGS)
|
||||
};
|
||||
|
||||
// Objects that should be constructable through |new Name();|
|
||||
@ -4204,6 +4210,10 @@ nsDOMClassInfo::Init()
|
||||
DOM_CLASSINFO_MAP_BEGIN(WebGLExtensionStandardDerivatives, nsIWebGLExtensionStandardDerivatives)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIWebGLExtensionStandardDerivatives)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(WebGLExtensionTextureFilterAnisotropic, nsIWebGLExtensionTextureFilterAnisotropic)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIWebGLExtensionTextureFilterAnisotropic)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(WebGLExtensionLoseContext, nsIWebGLExtensionLoseContext)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIWebGLExtensionLoseContext)
|
||||
@ -4381,6 +4391,11 @@ nsDOMClassInfo::Init()
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMError)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
DOM_CLASSINFO_MAP_BEGIN(DOMRequest, nsIDOMDOMRequest)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMDOMRequest)
|
||||
DOM_CLASSINFO_MAP_ENTRY(nsIDOMEventTarget)
|
||||
DOM_CLASSINFO_MAP_END
|
||||
|
||||
#ifdef NS_DEBUG
|
||||
{
|
||||
PRUint32 i = ArrayLength(sClassInfoData);
|
||||
|
@ -486,6 +486,7 @@ DOMCI_CLASS(WebGLShaderPrecisionFormat)
|
||||
DOMCI_CLASS(WebGLActiveInfo)
|
||||
DOMCI_CLASS(WebGLExtension)
|
||||
DOMCI_CLASS(WebGLExtensionStandardDerivatives)
|
||||
DOMCI_CLASS(WebGLExtensionTextureFilterAnisotropic)
|
||||
DOMCI_CLASS(WebGLExtensionLoseContext)
|
||||
|
||||
DOMCI_CLASS(PaintRequest)
|
||||
@ -545,3 +546,4 @@ DOMCI_CLASS(BluetoothAdapter)
|
||||
#endif
|
||||
|
||||
DOMCI_CLASS(DOMError)
|
||||
DOMCI_CLASS(DOMRequest)
|
||||
|
@ -2343,8 +2343,17 @@ nsFocusManager::DetermineElementToMoveFocus(nsPIDOMWindow* aWindow,
|
||||
return NS_OK;
|
||||
|
||||
nsCOMPtr<nsIContent> startContent = aStartContent;
|
||||
if (!startContent && aType != MOVEFOCUS_CARET)
|
||||
startContent = aWindow->GetFocusedNode();
|
||||
if (!startContent && aType != MOVEFOCUS_CARET) {
|
||||
if (aType == MOVEFOCUS_FORWARDDOC || aType == MOVEFOCUS_BACKWARDDOC) {
|
||||
// When moving between documents, make sure to get the right
|
||||
// starting content in a descendant.
|
||||
nsCOMPtr<nsPIDOMWindow> focusedWindow;
|
||||
startContent = GetFocusedDescendant(aWindow, true, getter_AddRefs(focusedWindow));
|
||||
}
|
||||
else {
|
||||
startContent = aWindow->GetFocusedNode();
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocument> doc;
|
||||
if (startContent)
|
||||
@ -2362,11 +2371,11 @@ nsFocusManager::DetermineElementToMoveFocus(nsPIDOMWindow* aWindow,
|
||||
return NS_OK;
|
||||
}
|
||||
if (aType == MOVEFOCUS_FORWARDDOC) {
|
||||
NS_IF_ADDREF(*aNextContent = GetNextTabbableDocument(true));
|
||||
NS_IF_ADDREF(*aNextContent = GetNextTabbableDocument(startContent, true));
|
||||
return NS_OK;
|
||||
}
|
||||
if (aType == MOVEFOCUS_BACKWARDDOC) {
|
||||
NS_IF_ADDREF(*aNextContent = GetNextTabbableDocument(false));
|
||||
NS_IF_ADDREF(*aNextContent = GetNextTabbableDocument(startContent, false));
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -3136,66 +3145,192 @@ nsFocusManager::GetPreviousDocShell(nsIDocShellTreeItem* aItem,
|
||||
}
|
||||
|
||||
nsIContent*
|
||||
nsFocusManager::GetNextTabbableDocument(bool aForward)
|
||||
nsFocusManager::GetNextTabbablePanel(nsIDocument* aDocument, nsIFrame* aCurrentPopup, bool aForward)
|
||||
{
|
||||
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
||||
if (!pm)
|
||||
return nsnull;
|
||||
|
||||
// Iterate through the array backwards if aForward is false.
|
||||
nsTArray<nsIFrame *> popups = pm->GetVisiblePopups();
|
||||
PRInt32 i = aForward ? 0 : popups.Length() - 1;
|
||||
PRInt32 end = aForward ? popups.Length() : -1;
|
||||
|
||||
for (; i != end; aForward ? i++ : i--) {
|
||||
nsIFrame* popupFrame = popups[i];
|
||||
if (aCurrentPopup) {
|
||||
// If the current popup is set, then we need to skip over this popup and
|
||||
// wait until the currently focused popup is found. Once found, the
|
||||
// current popup will be cleared so that the next popup is used.
|
||||
if (aCurrentPopup == popupFrame)
|
||||
aCurrentPopup = nsnull;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip over non-panels
|
||||
if (popupFrame->GetContent()->Tag() != nsGkAtoms::panel ||
|
||||
(aDocument && popupFrame->GetContent()->GetCurrentDoc() != aDocument)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Find the first focusable content within the popup. If there isn't any
|
||||
// focusable content in the popup, skip to the next popup.
|
||||
nsIPresShell* presShell = popupFrame->PresContext()->GetPresShell();
|
||||
if (presShell) {
|
||||
nsCOMPtr<nsIContent> nextFocus;
|
||||
nsIContent* popup = popupFrame->GetContent();
|
||||
nsresult rv = GetNextTabbableContent(presShell, popup,
|
||||
nsnull, popup,
|
||||
true, 1, false,
|
||||
getter_AddRefs(nextFocus));
|
||||
if (NS_SUCCEEDED(rv) && nextFocus) {
|
||||
return nextFocus.get();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nsnull;
|
||||
}
|
||||
|
||||
nsIContent*
|
||||
nsFocusManager::GetNextTabbableDocument(nsIContent* aStartContent, bool aForward)
|
||||
{
|
||||
// If currentPopup is set, then the starting content is in a panel.
|
||||
nsIFrame* currentPopup = nsnull;
|
||||
nsCOMPtr<nsIDocument> doc;
|
||||
nsCOMPtr<nsIDocShellTreeItem> startItem;
|
||||
if (mFocusedWindow) {
|
||||
|
||||
if (aStartContent) {
|
||||
doc = aStartContent->GetCurrentDoc();
|
||||
if (doc) {
|
||||
startItem = do_QueryInterface(doc->GetWindow()->GetDocShell());
|
||||
}
|
||||
|
||||
// Check if the starting content is inside a panel. Document navigation
|
||||
// must start from this panel instead of the document root.
|
||||
nsIContent* content = aStartContent;
|
||||
while (content) {
|
||||
if (content->NodeInfo()->Equals(nsGkAtoms::panel, kNameSpaceID_XUL)) {
|
||||
currentPopup = content->GetPrimaryFrame();
|
||||
break;
|
||||
}
|
||||
content = content->GetParent();
|
||||
}
|
||||
}
|
||||
else if (mFocusedWindow) {
|
||||
startItem = do_QueryInterface(mFocusedWindow->GetDocShell());
|
||||
doc = do_QueryInterface(mFocusedWindow->GetExtantDocument());
|
||||
}
|
||||
else {
|
||||
nsCOMPtr<nsIWebNavigation> webnav = do_GetInterface(mActiveWindow);
|
||||
startItem = do_QueryInterface(webnav);
|
||||
|
||||
if (mActiveWindow) {
|
||||
doc = do_QueryInterface(mActiveWindow->GetExtantDocument());
|
||||
}
|
||||
}
|
||||
|
||||
if (!startItem)
|
||||
return nsnull;
|
||||
|
||||
// perform a depth first search (preorder) of the docshell tree
|
||||
// looking for an HTML Frame or a chrome document
|
||||
nsIContent* content = nsnull;
|
||||
nsIContent* content = aStartContent;
|
||||
nsCOMPtr<nsIDocShellTreeItem> curItem = startItem;
|
||||
nsCOMPtr<nsIDocShellTreeItem> nextItem;
|
||||
do {
|
||||
if (aForward) {
|
||||
GetNextDocShell(curItem, getter_AddRefs(nextItem));
|
||||
if (!nextItem) {
|
||||
// wrap around to the beginning, which is the top of the tree
|
||||
startItem->GetRootTreeItem(getter_AddRefs(nextItem));
|
||||
}
|
||||
}
|
||||
else {
|
||||
GetPreviousDocShell(curItem, getter_AddRefs(nextItem));
|
||||
if (!nextItem) {
|
||||
// wrap around to the end, which is the last item in the tree
|
||||
nsCOMPtr<nsIDocShellTreeItem> rootItem;
|
||||
startItem->GetRootTreeItem(getter_AddRefs(rootItem));
|
||||
GetLastDocShell(rootItem, getter_AddRefs(nextItem));
|
||||
// If moving forward, check for a panel in the starting document. If one
|
||||
// exists with focusable content, return that content instead of the next
|
||||
// document. If currentPopup is set, then, another panel may exist. If no
|
||||
// such panel exists, then continue on to check the next document.
|
||||
// When moving backwards, and the starting content is in a panel, then
|
||||
// check for additional panels in the starting document. If the starting
|
||||
// content is not in a panel, move back to the previous document and check
|
||||
// for panels there.
|
||||
|
||||
bool checkPopups = false;
|
||||
nsCOMPtr<nsPIDOMWindow> nextFrame = nsnull;
|
||||
|
||||
if (doc && (aForward || currentPopup)) {
|
||||
nsIContent* popupContent = GetNextTabbablePanel(doc, currentPopup, aForward);
|
||||
if (popupContent)
|
||||
return popupContent;
|
||||
|
||||
if (!aForward && currentPopup) {
|
||||
// The starting content was in a popup, yet no other popups were
|
||||
// found. Move onto the starting content's document.
|
||||
nextFrame = doc->GetWindow();
|
||||
}
|
||||
}
|
||||
|
||||
curItem = nextItem;
|
||||
nsCOMPtr<nsPIDOMWindow> nextFrame = do_GetInterface(nextItem);
|
||||
// Look for the next or previous document.
|
||||
if (!nextFrame) {
|
||||
if (aForward) {
|
||||
GetNextDocShell(curItem, getter_AddRefs(nextItem));
|
||||
if (!nextItem) {
|
||||
// wrap around to the beginning, which is the top of the tree
|
||||
startItem->GetRootTreeItem(getter_AddRefs(nextItem));
|
||||
}
|
||||
}
|
||||
else {
|
||||
GetPreviousDocShell(curItem, getter_AddRefs(nextItem));
|
||||
if (!nextItem) {
|
||||
// wrap around to the end, which is the last item in the tree
|
||||
nsCOMPtr<nsIDocShellTreeItem> rootItem;
|
||||
startItem->GetRootTreeItem(getter_AddRefs(rootItem));
|
||||
GetLastDocShell(rootItem, getter_AddRefs(nextItem));
|
||||
}
|
||||
|
||||
// When going back to the previous document, check for any focusable
|
||||
// popups in that previous document first.
|
||||
checkPopups = true;
|
||||
}
|
||||
|
||||
curItem = nextItem;
|
||||
nextFrame = do_GetInterface(nextItem);
|
||||
}
|
||||
|
||||
if (!nextFrame)
|
||||
return nsnull;
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryInterface(nextFrame->GetExtantDocument());
|
||||
if (doc && !doc->EventHandlingSuppressed()) {
|
||||
content = GetRootForFocus(nextFrame, doc, true, true);
|
||||
if (content && !GetRootForFocus(nextFrame, doc, false, false)) {
|
||||
// if the found content is in a chrome shell or a frameset, navigate
|
||||
// forward one tabbable item so that the first item is focused. Note
|
||||
// that we always go forward and not back here.
|
||||
nsCOMPtr<nsIContent> nextFocus;
|
||||
Element* rootElement = doc->GetRootElement();
|
||||
nsIPresShell* presShell = doc->GetShell();
|
||||
if (presShell) {
|
||||
nsresult rv = GetNextTabbableContent(presShell, rootElement,
|
||||
nsnull, rootElement,
|
||||
true, 1, false,
|
||||
getter_AddRefs(nextFocus));
|
||||
return NS_SUCCEEDED(rv) ? nextFocus.get() : nsnull;
|
||||
}
|
||||
// Clear currentPopup for the next iteration
|
||||
currentPopup = nsnull;
|
||||
|
||||
// If event handling is suppressed, move on to the next document. Set
|
||||
// content to null so that the popup check will be skipped on the next
|
||||
// loop iteration.
|
||||
doc = do_QueryInterface(nextFrame->GetExtantDocument());
|
||||
if (!doc || doc->EventHandlingSuppressed()) {
|
||||
content = nsnull;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (checkPopups) {
|
||||
// When iterating backwards, check the panels of the previous document
|
||||
// first. If a panel exists that has focusable content, focus that.
|
||||
// Otherwise, continue on to focus the document.
|
||||
nsIContent* popupContent = GetNextTabbablePanel(doc, nsnull, false);
|
||||
if (popupContent)
|
||||
return popupContent;
|
||||
}
|
||||
|
||||
content = GetRootForFocus(nextFrame, doc, true, true);
|
||||
if (content && !GetRootForFocus(nextFrame, doc, false, false)) {
|
||||
// if the found content is in a chrome shell or a frameset, navigate
|
||||
// forward one tabbable item so that the first item is focused. Note
|
||||
// that we always go forward and not back here.
|
||||
nsCOMPtr<nsIContent> nextFocus;
|
||||
Element* rootElement = doc->GetRootElement();
|
||||
nsIPresShell* presShell = doc->GetShell();
|
||||
if (presShell) {
|
||||
nsresult rv = GetNextTabbableContent(presShell, rootElement,
|
||||
nsnull, rootElement,
|
||||
true, 1, false,
|
||||
getter_AddRefs(nextFocus));
|
||||
return NS_SUCCEEDED(rv) ? nextFocus.get() : nsnull;
|
||||
}
|
||||
}
|
||||
|
||||
} while (!content);
|
||||
|
||||
return content;
|
||||
|
@ -459,16 +459,31 @@ protected:
|
||||
nsIDocShellTreeItem** aResult);
|
||||
|
||||
/**
|
||||
* Get the tabbable next document from the currently focused frame if
|
||||
* aForward is true, or the previously tabbable document if aForward is
|
||||
* false. If this document is a chrome or frameset document, returns
|
||||
* the first focusable element within this document, otherwise, returns
|
||||
* the root node of the document.
|
||||
* Determine the first panel with focusable content in document tab order
|
||||
* from the given document. aForward indicates the direction to scan. If
|
||||
* aCurrentPopup is set to a panel, the next or previous popup after
|
||||
* aCurrentPopup after it is used. If aCurrentPopup is null, then the first
|
||||
* or last popup is used. If a panel has no focusable content, it is skipped.
|
||||
* Null is returned if no panel is open or no open panel contains a focusable
|
||||
* element.
|
||||
*/
|
||||
nsIContent* GetNextTabbablePanel(nsIDocument* aDocument, nsIFrame* aCurrentPopup, bool aForward);
|
||||
|
||||
/**
|
||||
* Get the tabbable next document from aStartContent or, if null, the
|
||||
* currently focused frame if aForward is true, or the previously tabbable
|
||||
* document if aForward is false. If this document is a chrome or frameset
|
||||
* document, returns the first focusable element within this document,
|
||||
* otherwise, returns the root node of the document.
|
||||
*
|
||||
*
|
||||
* Panels with focusable content are also placed in the cycling order, just
|
||||
* after the document containing that panel.
|
||||
*
|
||||
* This method would be used for document navigation, which is typically
|
||||
* invoked by pressing F6.
|
||||
*/
|
||||
nsIContent* GetNextTabbableDocument(bool aForward);
|
||||
nsIContent* GetNextTabbableDocument(nsIContent* aStartContent, bool aForward);
|
||||
|
||||
/**
|
||||
* Retreives a focusable element within the current selection of aWindow.
|
||||
|
31
dom/base/nsIDOMDOMRequest.idl
Normal file
31
dom/base/nsIDOMDOMRequest.idl
Normal file
@ -0,0 +1,31 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsIDOMEventTarget.idl"
|
||||
|
||||
interface nsIDOMDOMError;
|
||||
interface nsIDOMWindow;
|
||||
|
||||
[scriptable, builtinclass, uuid(a3ad2846-ffb2-48d7-a786-2254cb82560d)]
|
||||
interface nsIDOMDOMRequest : nsIDOMEventTarget
|
||||
{
|
||||
readonly attribute DOMString readyState; // "pending" or "done"
|
||||
|
||||
readonly attribute jsval result;
|
||||
readonly attribute nsIDOMDOMError error;
|
||||
|
||||
attribute nsIDOMEventListener onsuccess;
|
||||
attribute nsIDOMEventListener onerror;
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(eebcdf29-f8fa-4c36-bbc7-2146b1cbaf7b)]
|
||||
interface nsIDOMRequestService : nsISupports
|
||||
{
|
||||
nsIDOMDOMRequest createRequest(in nsIDOMWindow window);
|
||||
|
||||
void fireSuccess(in nsIDOMDOMRequest request, in jsval result);
|
||||
void fireError(in nsIDOMDOMRequest request, in DOMString error);
|
||||
};
|
@ -3275,8 +3275,9 @@ nsJSContext::CycleCollectNow(nsICycleCollectorListener *aListener,
|
||||
if (!sCleanupSinceLastGC && aExtraForgetSkippableCalls >= 0) {
|
||||
nsCycleCollector_forgetSkippable();
|
||||
}
|
||||
PRUint32 collected = nsCycleCollector_collect(aListener);
|
||||
sCCollectedWaitingForGC += collected;
|
||||
nsCycleCollectorResults ccResults;
|
||||
nsCycleCollector_collect(&ccResults, aListener);
|
||||
sCCollectedWaitingForGC += ccResults.mFreedRefCounted + ccResults.mFreedGCed;
|
||||
|
||||
// If we collected a substantial amount of cycles, poke the GC since more objects
|
||||
// might be unreachable now.
|
||||
@ -3303,16 +3304,23 @@ nsJSContext::CycleCollectNow(nsICycleCollectorListener *aListener,
|
||||
sFirstCollectionTime = now;
|
||||
}
|
||||
|
||||
nsString gcmsg;
|
||||
if (ccResults.mForcedGC) {
|
||||
gcmsg.AssignLiteral(", forced a GC");
|
||||
}
|
||||
|
||||
NS_NAMED_MULTILINE_LITERAL_STRING(kFmt,
|
||||
NS_LL("CC(T+%.1f) collected: %lu (%lu waiting for GC), suspected: %lu, duration: %llu ms.\n")
|
||||
NS_LL("CC(T+%.1f) duration: %llums, suspected: %lu, visited: %lu RCed and %lu GCed, collected: %lu RCed and %lu GCed (%lu waiting for GC)%s\n")
|
||||
NS_LL("ForgetSkippable %lu times before CC, min: %lu ms, max: %lu ms, avg: %lu ms, total: %lu ms, removed: %lu"));
|
||||
nsString msg;
|
||||
PRUint32 cleanups = sForgetSkippableBeforeCC ? sForgetSkippableBeforeCC : 1;
|
||||
sMinForgetSkippableTime = (sMinForgetSkippableTime == PR_UINT32_MAX)
|
||||
? 0 : sMinForgetSkippableTime;
|
||||
msg.Adopt(nsTextFormatter::smprintf(kFmt.get(), double(delta) / PR_USEC_PER_SEC,
|
||||
collected, sCCollectedWaitingForGC, suspected,
|
||||
(now - start) / PR_USEC_PER_MSEC,
|
||||
(now - start) / PR_USEC_PER_MSEC, suspected,
|
||||
ccResults.mVisitedRefCounted, ccResults.mVisitedGCed,
|
||||
ccResults.mFreedRefCounted, ccResults.mFreedGCed,
|
||||
sCCollectedWaitingForGC, gcmsg.get(),
|
||||
sForgetSkippableBeforeCC,
|
||||
sMinForgetSkippableTime / PR_USEC_PER_MSEC,
|
||||
sMaxForgetSkippableTime / PR_USEC_PER_MSEC,
|
||||
|
@ -45,6 +45,7 @@
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsIDocShellTreeItem.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
#include "nsContentUtils.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
using namespace mozilla;
|
||||
@ -262,9 +263,7 @@ nsScreen::GetAvailRect(nsRect& aRect)
|
||||
|
||||
namespace {
|
||||
|
||||
bool
|
||||
IsChromeType(nsIDocShell *aDocShell)
|
||||
{
|
||||
bool IsWhiteListed(nsIDocShell *aDocShell) {
|
||||
nsCOMPtr<nsIDocShellTreeItem> ds = do_QueryInterface(aDocShell);
|
||||
if (!ds) {
|
||||
return false;
|
||||
@ -272,7 +271,21 @@ IsChromeType(nsIDocShell *aDocShell)
|
||||
|
||||
PRInt32 itemType;
|
||||
ds->GetItemType(&itemType);
|
||||
return itemType == nsIDocShellTreeItem::typeChrome;
|
||||
if (itemType == nsIDocShellTreeItem::typeChrome) {
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = do_GetInterface(aDocShell);
|
||||
nsIPrincipal *principal = doc->NodePrincipal();
|
||||
|
||||
nsCOMPtr<nsIURI> principalURI;
|
||||
principal->GetURI(getter_AddRefs(principalURI));
|
||||
if (nsContentUtils::URIIsChromeOrInPref(principalURI,
|
||||
"dom.mozScreenWhitelist")) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
@ -280,7 +293,7 @@ IsChromeType(nsIDocShell *aDocShell)
|
||||
nsresult
|
||||
nsScreen::GetMozEnabled(bool *aEnabled)
|
||||
{
|
||||
if (!sAllowScreenEnabledProperty || !IsChromeType(mDocShell)) {
|
||||
if (!sAllowScreenEnabledProperty || !IsWhiteListed(mDocShell)) {
|
||||
*aEnabled = true;
|
||||
return NS_OK;
|
||||
}
|
||||
@ -292,7 +305,7 @@ nsScreen::GetMozEnabled(bool *aEnabled)
|
||||
nsresult
|
||||
nsScreen::SetMozEnabled(bool aEnabled)
|
||||
{
|
||||
if (!sAllowScreenEnabledProperty || !IsChromeType(mDocShell)) {
|
||||
if (!sAllowScreenEnabledProperty || !IsWhiteListed(mDocShell)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -305,7 +318,7 @@ nsScreen::SetMozEnabled(bool aEnabled)
|
||||
nsresult
|
||||
nsScreen::GetMozBrightness(double *aBrightness)
|
||||
{
|
||||
if (!sAllowScreenBrightnessProperty || !IsChromeType(mDocShell)) {
|
||||
if (!sAllowScreenEnabledProperty || !IsWhiteListed(mDocShell)) {
|
||||
*aBrightness = 1;
|
||||
return NS_OK;
|
||||
}
|
||||
@ -317,7 +330,7 @@ nsScreen::GetMozBrightness(double *aBrightness)
|
||||
nsresult
|
||||
nsScreen::SetMozBrightness(double aBrightness)
|
||||
{
|
||||
if (!sAllowScreenBrightnessProperty || !IsChromeType(mDocShell)) {
|
||||
if (!sAllowScreenEnabledProperty || !IsWhiteListed(mDocShell)) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
53
dom/base/test/Makefile.in
Normal file
53
dom/base/test/Makefile.in
Normal file
@ -0,0 +1,53 @@
|
||||
# ***** 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 Indexed Database Test 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):
|
||||
# Shawn Wilsher <me@shawnwilsher.com>
|
||||
#
|
||||
# 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 *****
|
||||
|
||||
DEPTH = ../../..
|
||||
topsrcdir = @top_srcdir@
|
||||
srcdir = @srcdir@
|
||||
VPATH = @srcdir@
|
||||
relativesrcdir = dom/base/test
|
||||
|
||||
include $(DEPTH)/config/autoconf.mk
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
TEST_FILES = \
|
||||
test_domrequest.html \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(TEST_FILES)
|
||||
$(INSTALL) $(foreach f,$^,"$f") $(DEPTH)/_tests/testing/mochitest/tests/$(relativesrcdir)
|
||||
|
63
dom/base/test/test_domrequest.html
Normal file
63
dom/base/test/test_domrequest.html
Normal file
@ -0,0 +1,63 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for XMLHttpRequest</title>
|
||||
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
</head>
|
||||
<body>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script class="testbody" type="application/javascript;version=1.7">
|
||||
"use strict";
|
||||
|
||||
var reqserv = SpecialPowers.getDOMRequestService();
|
||||
ok("createRequest" in reqserv, "appears to be a service");
|
||||
|
||||
// create a request
|
||||
var req = reqserv.createRequest(window);
|
||||
ok("result" in req, "request has result");
|
||||
ok("error" in req, "request has error");
|
||||
ok("onsuccess" in req, "request has onsuccess");
|
||||
ok("onerror" in req, "request has onerror");
|
||||
ok("readyState" in req, "request has readyState");
|
||||
|
||||
is(req.readyState, "pending", "readyState is pending");
|
||||
is(req.result, undefined, "result is undefined");
|
||||
is(req.onsuccess, null, "onsuccess is null");
|
||||
is(req.onerror, null, "onerror is null");
|
||||
|
||||
// fire success
|
||||
var ev = null;
|
||||
req.onsuccess = function(e) {
|
||||
ev = e;
|
||||
}
|
||||
reqserv.fireSuccess(req, "my result");
|
||||
ok(ev, "got success event");
|
||||
is(ev.type, "success", "correct type during success");
|
||||
is(ev.target, req, "correct target during success");
|
||||
is(req.readyState, "done", "correct readyState after success");
|
||||
is(req.error, null, "correct error after success");
|
||||
is(req.result, "my result", "correct result after success");
|
||||
|
||||
// fire error
|
||||
req = reqserv.createRequest(window);
|
||||
ev = null;
|
||||
req.onerror = function(e) {
|
||||
ev = e;
|
||||
}
|
||||
reqserv.fireError(req, "OhMyError");
|
||||
ok(ev, "got success event");
|
||||
is(ev.type, "error", "correct type during error");
|
||||
is(ev.target, req, "correct target during error");
|
||||
is(req.readyState, "done", "correct readyState after error");
|
||||
is(req.error.name, "OhMyError", "correct error after error");
|
||||
is(req.result, undefined, "correct result after error");
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -4,36 +4,160 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "BluetoothAdapter.h"
|
||||
#include "nsDOMClassInfo.h"
|
||||
#include "nsDOMEvent.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsXPCOMCIDInternal.h"
|
||||
#include "mozilla/LazyIdleThread.h"
|
||||
|
||||
#include "BluetoothAdapter.h"
|
||||
|
||||
#if defined(MOZ_WIDGET_GONK)
|
||||
#include <bluedroid/bluetooth.h>
|
||||
#endif
|
||||
|
||||
#define POWERED_EVENT_NAME NS_LITERAL_STRING("powered")
|
||||
|
||||
BEGIN_BLUETOOTH_NAMESPACE
|
||||
|
||||
class ToggleBtResultTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
ToggleBtResultTask(bool result, nsRefPtr<BluetoothAdapter>& adapterPtr)
|
||||
: mResult(result)
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread()); // This should be running on the worker thread
|
||||
|
||||
mAdapterPtr.swap(adapterPtr);
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
MOZ_ASSERT(NS_IsMainThread()); // This method is supposed to run on the main thread!
|
||||
mAdapterPtr->FirePowered();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
bool mResult;
|
||||
nsRefPtr<BluetoothAdapter> mAdapterPtr;
|
||||
};
|
||||
|
||||
class ToggleBtTask : public nsRunnable
|
||||
{
|
||||
public:
|
||||
ToggleBtTask(bool onOff, BluetoothAdapter* adapterPtr)
|
||||
: mOnOff(onOff),
|
||||
mAdapterPtr(adapterPtr)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread()); // The constructor should be running on the main thread.
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() {
|
||||
bool result;
|
||||
|
||||
MOZ_ASSERT(!NS_IsMainThread()); // This should be running on the worker thread.
|
||||
|
||||
//Toggle BT here
|
||||
#if defined(MOZ_WIDGET_GONK)
|
||||
if (mOnOff) {
|
||||
result = bt_enable();
|
||||
} else {
|
||||
result = bt_disable();
|
||||
}
|
||||
#else
|
||||
result = true;
|
||||
#endif
|
||||
|
||||
// Create a result thread and pass it to Main Thread,
|
||||
nsCOMPtr<nsIRunnable> resultRunnable = new ToggleBtResultTask(result, mAdapterPtr);
|
||||
NS_DispatchToMainThread(resultRunnable);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsRefPtr<BluetoothAdapter> mAdapterPtr;
|
||||
bool mOnOff;
|
||||
};
|
||||
|
||||
END_BLUETOOTH_NAMESPACE
|
||||
|
||||
DOMCI_DATA(BluetoothAdapter, mozilla::dom::bluetooth::BluetoothAdapter)
|
||||
|
||||
USING_BLUETOOTH_NAMESPACE
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_CLASS(BluetoothAdapter)
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(BluetoothAdapter,
|
||||
nsDOMEventTargetHelper)
|
||||
NS_CYCLE_COLLECTION_TRAVERSE_EVENT_HANDLER(powered)
|
||||
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(BluetoothAdapter,
|
||||
nsDOMEventTargetHelper)
|
||||
NS_CYCLE_COLLECTION_UNLINK_EVENT_HANDLER(powered)
|
||||
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(BluetoothAdapter)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMBluetoothAdapter)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(BluetoothAdapter)
|
||||
NS_INTERFACE_MAP_END_INHERITING(nsDOMEventTargetHelper)
|
||||
|
||||
NS_IMPL_ADDREF_INHERITED(BluetoothAdapter, nsDOMEventTargetHelper)
|
||||
NS_IMPL_RELEASE_INHERITED(BluetoothAdapter, nsDOMEventTargetHelper)
|
||||
|
||||
BluetoothAdapter::BluetoothAdapter() : mPower(false)
|
||||
{
|
||||
}
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(BluetoothAdapter)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIDOMBluetoothAdapter)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_DOM_INTERFACE_MAP_ENTRY_CLASSINFO(BluetoothAdapter)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_ADDREF(BluetoothAdapter)
|
||||
NS_IMPL_RELEASE(BluetoothAdapter)
|
||||
|
||||
DOMCI_DATA(BluetoothAdapter, BluetoothAdapter)
|
||||
|
||||
NS_IMETHODIMP
|
||||
BluetoothAdapter::GetPower(bool* aPower)
|
||||
{
|
||||
#if defined(MOZ_WIDGET_GONK)
|
||||
*aPower = bt_is_enabled();
|
||||
#else
|
||||
*aPower = mPower;
|
||||
#endif
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
BluetoothAdapter::SetPower(bool aPower)
|
||||
{
|
||||
mPower = aPower;
|
||||
if (mPower != aPower) {
|
||||
mPower = aPower;
|
||||
|
||||
ToggleBluetoothAsync();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
BluetoothAdapter::ToggleBluetoothAsync()
|
||||
{
|
||||
if (!mToggleBtThread) {
|
||||
mToggleBtThread = new LazyIdleThread(15000);
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> r = new ToggleBtTask(mPower, this);
|
||||
|
||||
mToggleBtThread->Dispatch(r, 0);
|
||||
}
|
||||
|
||||
nsresult
|
||||
BluetoothAdapter::FirePowered()
|
||||
{
|
||||
nsRefPtr<nsDOMEvent> event = new nsDOMEvent(nsnull, nsnull);
|
||||
nsresult rv = event->InitEvent(POWERED_EVENT_NAME, false, false);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
bool dummy;
|
||||
rv = DispatchEvent(event, &dummy);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMPL_EVENT_HANDLER(BluetoothAdapter, powered)
|
||||
|
@ -8,20 +8,35 @@
|
||||
#define mozilla_dom_bluetooth_bluetoothadapter_h__
|
||||
|
||||
#include "BluetoothCommon.h"
|
||||
#include "nsDOMEventTargetHelper.h"
|
||||
#include "nsIDOMBluetoothAdapter.h"
|
||||
|
||||
BEGIN_BLUETOOTH_NAMESPACE
|
||||
|
||||
class BluetoothAdapter : public nsIDOMBluetoothAdapter
|
||||
,public nsDOMEventTargetHelper
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIDOMBLUETOOTHADAPTER
|
||||
|
||||
NS_FORWARD_NSIDOMEVENTTARGET(nsDOMEventTargetHelper::)
|
||||
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(BluetoothAdapter,
|
||||
nsDOMEventTargetHelper)
|
||||
|
||||
BluetoothAdapter();
|
||||
|
||||
nsresult FirePowered();
|
||||
|
||||
protected:
|
||||
bool mPower;
|
||||
|
||||
NS_DECL_EVENT_HANDLER(powered)
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsIEventTarget> mToggleBtThread;
|
||||
void ToggleBluetoothAsync();
|
||||
};
|
||||
|
||||
END_BLUETOOTH_NAMESPACE
|
||||
|
@ -4,10 +4,14 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
#include "nsIDOMEventTarget.idl"
|
||||
|
||||
[scriptable, builtinclass, uuid(29689a22-45ff-4ccf-b552-5364ce3a3642)]
|
||||
interface nsIDOMBluetoothAdapter : nsISupports
|
||||
interface nsIDOMEventListener;
|
||||
|
||||
[scriptable, builtinclass, uuid(3dbaa9f4-5c93-11e1-8592-ff9bfcc3ab4b)]
|
||||
interface nsIDOMBluetoothAdapter : nsIDOMEventTarget
|
||||
{
|
||||
attribute boolean power;
|
||||
|
||||
attribute nsIDOMEventListener onpowered;
|
||||
};
|
||||
|
@ -168,6 +168,13 @@ interface nsIWebGLExtensionLoseContext : nsIWebGLExtension
|
||||
void restoreContext();
|
||||
};
|
||||
|
||||
[scriptable, uuid(73bfb64d-94bd-4a7a-9eab-6b6d32e57aa0)]
|
||||
interface nsIWebGLExtensionTextureFilterAnisotropic : nsIWebGLExtension
|
||||
{
|
||||
const WebGLenum TEXTURE_MAX_ANISOTROPY = 0x84FE;
|
||||
const WebGLenum MAX_TEXTURE_MAX_ANISOTROPY = 0x84FF;
|
||||
};
|
||||
|
||||
[scriptable, builtinclass, uuid(f000afac-11b3-4c06-a35f-8db411f1cf54)]
|
||||
interface nsIDOMWebGLRenderingContext : nsISupports
|
||||
{
|
||||
|
@ -52,7 +52,7 @@ interface nsIDOMUserDataHandler;
|
||||
* http://dvcs.w3.org/hg/domcore/raw-file/tip/Overview.html
|
||||
*/
|
||||
|
||||
[scriptable, uuid(ce82fb71-60f2-4c38-be31-de5f2f90dada)]
|
||||
[scriptable, uuid(5e9bcec9-5928-4f77-8a9c-424ef01c20e1)]
|
||||
interface nsIDOMNode : nsISupports
|
||||
{
|
||||
const unsigned short ELEMENT_NODE = 1;
|
||||
@ -94,7 +94,8 @@ interface nsIDOMNode : nsISupports
|
||||
nsIDOMNode appendChild(in nsIDOMNode newChild)
|
||||
raises(DOMException);
|
||||
boolean hasChildNodes();
|
||||
nsIDOMNode cloneNode(in boolean deep);
|
||||
// Modified in DOM Level 4:
|
||||
[optional_argc] nsIDOMNode cloneNode([optional] in boolean deep);
|
||||
// Modified in DOM Level 2:
|
||||
void normalize();
|
||||
// Introduced in DOM Level 2:
|
||||
|
@ -353,16 +353,6 @@ nsNPAPIPlugin::RunPluginOOP(const nsPluginTag *aPluginTag)
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef XP_WIN
|
||||
OSVERSIONINFO osVerInfo = {0};
|
||||
osVerInfo.dwOSVersionInfoSize = sizeof(osVerInfo);
|
||||
GetVersionEx(&osVerInfo);
|
||||
// Always disabled on 2K or less. (bug 536303)
|
||||
if (osVerInfo.dwMajorVersion < 5 ||
|
||||
(osVerInfo.dwMajorVersion == 5 && osVerInfo.dwMinorVersion == 0))
|
||||
return false;
|
||||
#endif
|
||||
|
||||
nsCOMPtr<nsIPrefBranch> prefs = do_GetService(NS_PREFSERVICE_CONTRACTID);
|
||||
if (!prefs) {
|
||||
return false;
|
||||
|
@ -57,7 +57,6 @@
|
||||
#include "nsString.h"
|
||||
#include "nsILocalFile.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsSetDllDirectory.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
||||
@ -303,7 +302,7 @@ nsresult nsPluginFile::LoadPlugin(PRLibrary **outLibrary)
|
||||
}
|
||||
|
||||
if (protectCurrentDirectory) {
|
||||
mozilla::NS_SetDllDirectory(NULL);
|
||||
SetDllDirectory(NULL);
|
||||
}
|
||||
|
||||
nsresult rv = plugin->Load(outLibrary);
|
||||
@ -311,7 +310,7 @@ nsresult nsPluginFile::LoadPlugin(PRLibrary **outLibrary)
|
||||
*outLibrary = NULL;
|
||||
|
||||
if (protectCurrentDirectory) {
|
||||
mozilla::NS_SetDllDirectory(L"");
|
||||
SetDllDirectory(L"");
|
||||
}
|
||||
|
||||
if (restoreOrigDir) {
|
||||
|
@ -147,7 +147,7 @@ PluginProcessChild::Init()
|
||||
}
|
||||
if (protectCurrentDirectory) {
|
||||
SanitizeEnvironmentVariables();
|
||||
NS_SetDllDirectory(L"");
|
||||
SetDllDirectory(L"");
|
||||
}
|
||||
|
||||
#else
|
||||
|
@ -1848,8 +1848,7 @@ nsDOMStorage2::InitAsSessionStorage(nsIPrincipal *aPrincipal, const nsSubstring
|
||||
if (!mStorage)
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
|
||||
// Leave security checks only for domain (nsDOMStorage implementation)
|
||||
mStorage->mSecurityChecker = mStorage;
|
||||
mStorage->mSecurityChecker = this;
|
||||
mPrincipal = aPrincipal;
|
||||
mDocumentURI = aDocumentURI;
|
||||
|
||||
@ -1949,7 +1948,7 @@ nsDOMStorage2::CanAccess(nsIPrincipal *aPrincipal)
|
||||
|
||||
// Allow more powerful principals (e.g. system) to access the storage
|
||||
bool subsumes;
|
||||
nsresult rv = aPrincipal->Subsumes(mPrincipal, &subsumes);
|
||||
nsresult rv = aPrincipal->SubsumesIgnoringDomain(mPrincipal, &subsumes);
|
||||
if (NS_FAILED(rv))
|
||||
return false;
|
||||
|
||||
|
@ -76,6 +76,10 @@ AudioManager::SetMasterVolume(float aMasterVolume)
|
||||
if (AudioSystem::setMasterVolume(aMasterVolume)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
// For now, just set the voice volume at the same level
|
||||
if (AudioSystem::setVoiceVolume(aMasterVolume)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
|
@ -24,7 +24,6 @@ var ConsoleObserver = {
|
||||
if (aTopic == "console-storage-cache-event") {
|
||||
apiCallCount ++;
|
||||
if (apiCallCount == 4) {
|
||||
// remove the observer so we don't trigger this test again
|
||||
Services.obs.removeObserver(this, "console-storage-cache-event");
|
||||
|
||||
try {
|
||||
@ -42,12 +41,13 @@ var ConsoleObserver = {
|
||||
// make sure a closed window's events are in fact removed from the
|
||||
// storage cache
|
||||
win.console.log("adding a new event");
|
||||
|
||||
// close the window - the storage cache should now be empty
|
||||
// Close the window.
|
||||
gBrowser.removeTab(tab, {animate: false});
|
||||
|
||||
// Ensure actual window destruction is not delayed (too long).
|
||||
window.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils).garbageCollect();
|
||||
// Ensure "inner-window-destroyed" event is processed,
|
||||
// so the storage cache is cleared.
|
||||
executeSoon(function () {
|
||||
// use the old windowID again to see if we have any stray cached messages
|
||||
messages = ConsoleAPIStorage.getEvents(windowID);
|
||||
@ -71,6 +71,12 @@ function tearDown()
|
||||
|
||||
function test()
|
||||
{
|
||||
// Don't cache removed tabs, so "clear console cache on tab close" triggers.
|
||||
Services.prefs.setIntPref("browser.tabs.max_tabs_undo", 0);
|
||||
registerCleanupFunction(function() {
|
||||
Services.prefs.clearUserPref("browser.tabs.max_tabs_undo");
|
||||
});
|
||||
|
||||
registerCleanupFunction(tearDown);
|
||||
|
||||
ConsoleObserver.init();
|
||||
|
@ -74,6 +74,8 @@ _TEST_FILES = \
|
||||
test_moving_xhr.xul \
|
||||
test_nodesFromRect.html \
|
||||
489127.html \
|
||||
test_focus_docnav.xul \
|
||||
window_focus_docnav.xul \
|
||||
$(NULL)
|
||||
|
||||
ifeq (WINNT,$(OS_ARCH))
|
||||
|
@ -3,7 +3,8 @@
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script>
|
||||
SimpleTest.waitForFocus(function () opener.framesetWindowLoaded(window));
|
||||
if (opener)
|
||||
SimpleTest.waitForFocus(function () opener.framesetWindowLoaded(window));
|
||||
</script>
|
||||
|
||||
<frameset rows="30%, 70%">
|
||||
|
28
dom/tests/mochitest/chrome/test_focus_docnav.xul
Normal file
28
dom/tests/mochitest/chrome/test_focus_docnav.xul
Normal file
@ -0,0 +1,28 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css" type="text/css"?>
|
||||
|
||||
<window onload="runTest();"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"/>
|
||||
|
||||
<script>
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
function runTest()
|
||||
{
|
||||
window.open("window_focus_docnav.xul", "_blank", "chrome,width=600,height=550");
|
||||
}
|
||||
</script>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml">
|
||||
<p id="display">
|
||||
</p>
|
||||
<div id="content" style="display: none">
|
||||
</div>
|
||||
<pre id="test">
|
||||
</pre>
|
||||
</body>
|
||||
|
||||
</window>
|
104
dom/tests/mochitest/chrome/window_focus_docnav.xul
Normal file
104
dom/tests/mochitest/chrome/window_focus_docnav.xul
Normal file
@ -0,0 +1,104 @@
|
||||
<?xml version="1.0"?>
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
|
||||
<window onload="start()"
|
||||
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
|
||||
|
||||
<textbox id="textbox"/>
|
||||
|
||||
<panel id="panel2" onpopupshown="runTests(this, 2);" onpopuphidden="document.getElementById('panel').hidePopup()">
|
||||
<textbox id="p2textbox" value="Popup2"/>
|
||||
</panel>
|
||||
<panel id="panel" onpopupshown="runTests(this, 1);"
|
||||
onpopuphidden="done()">
|
||||
<textbox id="p1textbox" value="Popup1"/>
|
||||
</panel>
|
||||
|
||||
<browser id="browser" type="content" src="focus_frameset.html" width="500" height="400"/>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
|
||||
var fm = Components.classes["@mozilla.org/focus-manager;1"].
|
||||
getService(Components.interfaces.nsIFocusManager);
|
||||
|
||||
function is(l, r, n) { window.opener.wrappedJSObject.SimpleTest.is(l,r,n); }
|
||||
function ok(v, n) { window.opener.wrappedJSObject.SimpleTest.ok(v,n); }
|
||||
|
||||
function done()
|
||||
{
|
||||
var opener = window.opener;
|
||||
window.close();
|
||||
opener.wrappedJSObject.SimpleTest.finish();
|
||||
}
|
||||
|
||||
function previous(expectedWindow, expectedElement, desc)
|
||||
{
|
||||
synthesizeKey("VK_F6", { shiftKey: true });
|
||||
is(fm.focusedWindow, expectedWindow, desc);
|
||||
is(fm.focusedElement, expectedElement, desc + " element");
|
||||
}
|
||||
|
||||
function next(expectedWindow, expectedElement, desc)
|
||||
{
|
||||
synthesizeKey("VK_F6", { });
|
||||
is(fm.focusedWindow, expectedWindow, desc);
|
||||
is(fm.focusedElement, expectedElement, desc + " element" + "::" + (fm.focusedElement ? fm.focusedElement.parentNode.id : "<none>"));
|
||||
}
|
||||
|
||||
// This test runs through three cases. Document navigation forward and
|
||||
// backward using the F6 key when no popups are open, with one popup open and
|
||||
// with two popups open.
|
||||
function runTests(panel, popupCount)
|
||||
{
|
||||
if (!popupCount || popupCount > 2)
|
||||
popupCount = 0;
|
||||
|
||||
fm.clearFocus(window);
|
||||
|
||||
var childwin = document.getElementById("browser").contentWindow;
|
||||
|
||||
if (popupCount) {
|
||||
if (popupCount == 2) {
|
||||
next(window, document.getElementById("p2textbox").inputField, "First into popup 2 with " + popupCount);
|
||||
}
|
||||
|
||||
next(window, document.getElementById("p1textbox").inputField, "First into popup 1 with " + popupCount);
|
||||
}
|
||||
|
||||
next(childwin.frames[0], childwin.frames[0].document.documentElement, "First with " + popupCount);
|
||||
next(childwin.frames[1], childwin.frames[1].document.documentElement, "Second with " + popupCount);
|
||||
previous(childwin.frames[0], childwin.frames[0].document.documentElement, "Second back with " + popupCount);
|
||||
|
||||
if (popupCount) {
|
||||
previous(window, document.getElementById("p1textbox").inputField, "First back from popup 1 with " + popupCount);
|
||||
|
||||
if (popupCount == 2) {
|
||||
previous(window, document.getElementById("p2textbox").inputField, "First back from popup 2 with " + popupCount);
|
||||
}
|
||||
}
|
||||
|
||||
previous(window, document.getElementById("textbox").inputField, "First back with " + popupCount);
|
||||
|
||||
if (panel == document.getElementById("panel"))
|
||||
document.getElementById("panel2").openPopup(null, "after_start", 100, 20);
|
||||
else if (panel == document.getElementById("panel2"))
|
||||
panel.hidePopup();
|
||||
else
|
||||
document.getElementById("panel").openPopup(null, "after_start");
|
||||
}
|
||||
|
||||
function start()
|
||||
{
|
||||
window.opener.wrappedJSObject.SimpleTest.waitForExplicitFinish();
|
||||
window.opener.wrappedJSObject.SimpleTest.waitForFocus(
|
||||
function() { runTests(null, 0); },
|
||||
document.getElementById("browser").contentWindow);
|
||||
}
|
||||
|
||||
]]></script>
|
||||
|
||||
</window>
|
@ -16,7 +16,7 @@ function startTest()
|
||||
sessionStorage;
|
||||
}
|
||||
catch (e) {
|
||||
is(e.result, 2152923145,
|
||||
is(e.result, Components.results.NS_ERROR_NOT_AVAILABLE,
|
||||
"Testing that we get the expected exception.");
|
||||
exceptionCaught = true;
|
||||
}
|
||||
|
@ -55,7 +55,7 @@ interface nsIEditActionListener;
|
||||
interface nsIInlineSpellChecker;
|
||||
interface nsITransferable;
|
||||
|
||||
[scriptable, uuid(94479B76-7FD7-47D3-BB1E-5B77846339D2)]
|
||||
[scriptable, uuid(656005d2-d900-4839-81bf-6274a3c38537)]
|
||||
|
||||
interface nsIEditor : nsISupports
|
||||
{
|
||||
@ -205,6 +205,16 @@ interface nsIEditor : nsISupports
|
||||
*/
|
||||
void enableUndo(in boolean enable);
|
||||
|
||||
/**
|
||||
* The number of items on the undo stack.
|
||||
*/
|
||||
readonly attribute long numberOfUndoItems;
|
||||
|
||||
/**
|
||||
* The number of items on the redo stack.
|
||||
*/
|
||||
readonly attribute long numberOfRedoItems;
|
||||
|
||||
/** undo reverses the effects of the last Do operation,
|
||||
* if Undo is enabled in the editor.
|
||||
* It is provided here so clients need no knowledge of whether
|
||||
|
@ -98,7 +98,7 @@ NS_IMETHODIMP SplitElementTxn::DoTransaction(void)
|
||||
if (!mExistingRightNode || !mEditor) { return NS_ERROR_NOT_INITIALIZED; }
|
||||
|
||||
// create a new node
|
||||
nsresult result = mExistingRightNode->CloneNode(false, getter_AddRefs(mNewLeftNode));
|
||||
nsresult result = mExistingRightNode->CloneNode(false, 1, getter_AddRefs(mNewLeftNode));
|
||||
NS_ASSERTION(((NS_SUCCEEDED(result)) && (mNewLeftNode)), "could not create element.");
|
||||
NS_ENSURE_SUCCESS(result, result);
|
||||
NS_ENSURE_TRUE(mNewLeftNode, NS_ERROR_NULL_POINTER);
|
||||
|
@ -750,6 +750,19 @@ nsEditor::EnableUndo(bool aEnable)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEditor::GetNumberOfUndoItems(PRInt32* aNumItems)
|
||||
{
|
||||
*aNumItems = 0;
|
||||
return mTxnMgr ? mTxnMgr->GetNumberOfUndoItems(aNumItems) : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEditor::GetNumberOfRedoItems(PRInt32* aNumItems)
|
||||
{
|
||||
*aNumItems = 0;
|
||||
return mTxnMgr ? mTxnMgr->GetNumberOfRedoItems(aNumItems) : NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsEditor::GetTransactionManager(nsITransactionManager* *aTxnManager)
|
||||
|
@ -117,6 +117,12 @@ function doTest()
|
||||
// synthesizeDrop(text, textarea, [[{type: "text/plain", data: "Somewhat Longer Text"}]], "copy");
|
||||
// is(textarea.value, "Somewhat Longer Text", "Drag text/plain onto textarea");
|
||||
|
||||
// -------- Test dragging special text type of text/plain to contenteditable
|
||||
|
||||
selection.selectAllChildren(text);
|
||||
synthesizeDrop(text, input, [[{type: "text/x-moz-text-internal", data: "Some Special Text"}]], "copy");
|
||||
is(input.value, "Some Plain Text", "Drag text/x-moz-text-internal onto input");
|
||||
|
||||
// -------- Test dragging regular text of text/plain to contenteditable
|
||||
|
||||
selection.selectAllChildren(text);
|
||||
|
@ -169,12 +169,16 @@ nsresult nsPlaintextEditor::InsertFromDataTransfer(nsIDOMDataTransfer *aDataTran
|
||||
nsCOMPtr<nsIVariant> data;
|
||||
aDataTransfer->MozGetDataAt(NS_LITERAL_STRING("text/plain"), aIndex,
|
||||
getter_AddRefs(data));
|
||||
nsAutoString insertText;
|
||||
data->GetAsAString(insertText);
|
||||
nsContentUtils::PlatformToDOMLineBreaks(insertText);
|
||||
if (data) {
|
||||
nsAutoString insertText;
|
||||
data->GetAsAString(insertText);
|
||||
nsContentUtils::PlatformToDOMLineBreaks(insertText);
|
||||
|
||||
nsAutoEditBatch beginBatching(this);
|
||||
return InsertTextAt(insertText, aDestinationNode, aDestOffset, aDoDeleteSelection);
|
||||
nsAutoEditBatch beginBatching(this);
|
||||
return InsertTextAt(insertText, aDestinationNode, aDestOffset, aDoDeleteSelection);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsPlaintextEditor::InsertFromDrop(nsIDOMEvent* aDropEvent)
|
||||
|
@ -2970,7 +2970,7 @@ nsWebBrowserPersist::GetNodeToFixup(nsIDOMNode *aNodeIn, nsIDOMNode **aNodeOut)
|
||||
{
|
||||
if (!(mPersistFlags & PERSIST_FLAGS_FIXUP_ORIGINAL_DOM))
|
||||
{
|
||||
nsresult rv = aNodeIn->CloneNode(false, aNodeOut);
|
||||
nsresult rv = aNodeIn->CloneNode(false, 1, aNodeOut);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
}
|
||||
else
|
||||
|
@ -107,33 +107,14 @@ static const char *MapErrorCode(int rc)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
static HINSTANCE sspi_lib;
|
||||
static PSecurityFunctionTableW sspi;
|
||||
|
||||
static nsresult
|
||||
InitSSPI()
|
||||
{
|
||||
PSecurityFunctionTableW (*initFun)(void);
|
||||
|
||||
LOG((" InitSSPI\n"));
|
||||
|
||||
sspi_lib = LoadLibraryW(L"secur32.dll");
|
||||
if (!sspi_lib) {
|
||||
sspi_lib = LoadLibraryW(L"security.dll");
|
||||
if (!sspi_lib) {
|
||||
LOG(("SSPI library not found"));
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
}
|
||||
|
||||
initFun = (PSecurityFunctionTableW (*)(void))
|
||||
GetProcAddress(sspi_lib, "InitSecurityInterfaceW");
|
||||
if (!initFun) {
|
||||
LOG(("InitSecurityInterfaceW not found"));
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
sspi = initFun();
|
||||
sspi = InitSecurityInterfaceW();
|
||||
if (!sspi) {
|
||||
LOG(("InitSecurityInterfaceW failed"));
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
|
@ -41,6 +41,7 @@
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsUnicharUtilCIID.h"
|
||||
#include "nsUnicodeProperties.h"
|
||||
#include "nsCRT.h"
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(mozEnglishWordUtils)
|
||||
@ -52,8 +53,7 @@ NS_INTERFACE_MAP_BEGIN(mozEnglishWordUtils)
|
||||
NS_INTERFACE_MAP_ENTRIES_CYCLE_COLLECTION(mozEnglishWordUtils)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_2(mozEnglishWordUtils,
|
||||
mCategories,
|
||||
NS_IMPL_CYCLE_COLLECTION_1(mozEnglishWordUtils,
|
||||
mURLDetector)
|
||||
|
||||
mozEnglishWordUtils::mozEnglishWordUtils()
|
||||
@ -62,7 +62,6 @@ mozEnglishWordUtils::mozEnglishWordUtils()
|
||||
|
||||
nsresult rv;
|
||||
mURLDetector = do_CreateInstance(MOZ_TXTTOHTMLCONV_CONTRACTID, &rv);
|
||||
mCategories = do_GetService(NS_UNICHARCATEGORY_CONTRACTID);
|
||||
}
|
||||
|
||||
mozEnglishWordUtils::~mozEnglishWordUtils()
|
||||
@ -168,7 +167,7 @@ NS_IMETHODIMP mozEnglishWordUtils::GetRootForm(const PRUnichar *aWord, PRUint32
|
||||
bool mozEnglishWordUtils::ucIsAlpha(PRUnichar aChar)
|
||||
{
|
||||
// XXX we have to fix callers to handle the full Unicode range
|
||||
return nsIUGenCategory::kLetter == mCategories->Get(PRUint32(aChar));
|
||||
return nsIUGenCategory::kLetter == mozilla::unicode::GetGenCategory(aChar);
|
||||
}
|
||||
|
||||
/* void FindNextWord (in wstring word, in PRUint32 length, in PRUint32 offset, out PRUint32 begin, out PRUint32 end); */
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user