Back out bug 813978 on a CLOSED TREE.

This commit is contained in:
Philipp von Weitershausen 2013-01-14 17:38:11 -08:00
commit 50df8610b4
116 changed files with 2066 additions and 962 deletions

View File

@ -11,7 +11,7 @@
],
"zip_files": [
["{workdir}/out/target/product/otoro/*.img", "out/target/product/otoro/"],
"{workdir}/boot.img",
["{workdir}/boot.img", "out/target/product/otoro/"],
"{workdir}/flash.sh",
"{workdir}/load-config.sh",
"{workdir}/.config",

View File

@ -12,7 +12,7 @@
],
"zip_files": [
["{workdir}/out/target/product/unagi/*.img", "out/target/product/unagi/"],
"{workdir}/boot.img",
["{workdir}/boot.img", "out/target/product/unagi/"],
"{workdir}/flash.sh",
"{workdir}/load-config.sh",
"{workdir}/.config",

View File

@ -31,11 +31,8 @@ DEFINES += \
-DNEWWINDOW_ICO=\"$(DIST)/branding/newwindow.ico\" \
-DNEWTAB_ICO=\"$(DIST)/branding/newtab.ico\" \
-DPBMODE_ICO=\"$(DIST)/branding/pbmode.ico\" \
$(NULL)
ifdef MOZILLA_OFFICIAL
DEFINES += -DMOZILLA_OFFICIAL
endif
$(NULL)
ifdef LIBXUL_SDK #{
PREF_JS_EXPORTS += $(srcdir)/profile/channel-prefs.js

View File

@ -734,12 +734,6 @@ pref("browser.safebrowsing.reportMalwareErrorURL", "http://%LOCALE%.malware-erro
pref("browser.safebrowsing.warning.infoURL", "http://www.mozilla.com/%LOCALE%/firefox/phishing-protection/");
pref("browser.safebrowsing.malware.reportURL", "http://safebrowsing.clients.google.com/safebrowsing/diagnostic?client=%NAME%&hl=%LOCALE%&site=");
#ifdef MOZILLA_OFFICIAL
// Normally the "client ID" sent in updates is appinfo.name, but for
// official Firefox releases from Mozilla we use a special identifier.
pref("browser.safebrowsing.id", "navclient-auto-ffox");
#endif
// Name of the about: page contributed by safebrowsing to handle display of error
// pages on phishing/malware hits. (bug 399233)
pref("urlclassifier.alternate_error_page", "blocked");

View File

@ -35,6 +35,9 @@
<toolbar id="placesToolbar">
<toolbarbutton id="clearDownloadsButton"
#ifdef XP_MACOSX
class="tabbable"
#endif
insertbefore="libraryToolbarSpacer"
label="&clearDownloadsButton.label;"
command="downloadsCmd_clearDownloads"

View File

@ -31,4 +31,4 @@ browser.jar:
content/browser/places/moveBookmarks.js (content/moveBookmarks.js)
content/browser/places/editBookmarkOverlay.xul (content/editBookmarkOverlay.xul)
content/browser/places/editBookmarkOverlay.js (content/editBookmarkOverlay.js)
content/browser/places/downloadsViewOverlay.xul (content/downloadsViewOverlay.xul)
* content/browser/places/downloadsViewOverlay.xul (content/downloadsViewOverlay.xul)

View File

@ -374,8 +374,6 @@
@BINPATH@/components/nsDownloadManagerUI.js
@BINPATH@/components/NetworkGeolocationProvider.manifest
@BINPATH@/components/NetworkGeolocationProvider.js
@BINPATH@/components/GPSDGeolocationProvider.manifest
@BINPATH@/components/GPSDGeolocationProvider.js
@BINPATH@/components/nsSidebar.manifest
@BINPATH@/components/nsSidebar.js
@BINPATH@/components/extensions.manifest

View File

@ -318,8 +318,10 @@ toolbar[iconsize="large"] > #downloads-indicator[attention] > #downloads-indicat
-moz-appearance: none;
min-width: 0;
min-height: 0;
/* The background-clip: border-box; and background-image: none; are there to expand the background-color behind the border */
background-clip: padding-box, border-box;
background-color: rgb(255, 135, 94);
background-image: linear-gradient(transparent 1px, rgba(255, 255, 255, 0.4) 1px, rgba(255, 255, 255, 0.4) 2px, transparent 2px);
background-image: linear-gradient(transparent 1px, rgba(255, 255, 255, 0.4) 1px, rgba(255, 255, 255, 0.4) 2px, transparent 2px), none;
border: 1px solid;
border-color: rgba(0,43,86,.6) rgba(0,43,86,.4) rgba(0,43,86,.4);
border-radius: 2px 0 0 2px;

View File

@ -492,8 +492,10 @@ richlistitem[type="download"]:hover > stack > .downloadButton.downloadRetry:acti
-moz-appearance: none;
min-width: 0;
min-height: 0;
/* The background-clip: border-box; and background-image: none; are there to expand the background-color behind the border */
background-clip: padding-box, border-box;
background-color: rgb(90, 185, 255);
background-image: linear-gradient(transparent 1px, rgba(255, 255, 255, 0.4) 1px, rgba(255, 255, 255, 0.4) 2px, transparent 2px);
background-image: linear-gradient(transparent 1px, rgba(255, 255, 255, 0.4) 1px, rgba(255, 255, 255, 0.4) 2px, transparent 2px), none;
border: 1px solid;
border-color: rgba(0,43,86,.6) rgba(0,43,86,.4) rgba(0,43,86,.4);
border-radius: 2px 0 0 2px;

View File

@ -343,8 +343,10 @@ richlistitem[type="download"]:hover > stack > .downloadButton.downloadRetry:acti
-moz-appearance: none;
min-width: 0;
min-height: 0;
/* The background-clip: border-box; and background-image: none; are there to expand the background-color behind the border */
background-clip: padding-box, border-box;
background-color: rgb(90, 201, 66);
background-image: linear-gradient(transparent 1px, rgba(255, 255, 255, 0.4) 1px, rgba(255, 255, 255, 0.4) 2px, transparent 2px);
background-image: linear-gradient(transparent 1px, rgba(255, 255, 255, 0.4) 1px, rgba(255, 255, 255, 0.4) 2px, transparent 2px), none;
border: 1px solid;
border-color: rgba(0,43,86,.6) rgba(0,43,86,.4) rgba(0,43,86,.4);
border-radius: 2px 0 0 2px;

View File

@ -9,6 +9,7 @@
from __future__ import with_statement
from optparse import OptionParser
import sys, re, os, posixpath, ntpath
import errno
from StringIO import StringIO
# Standalone js doesn't have virtualenv.
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'config'))

View File

@ -274,38 +274,37 @@ class Automation(object):
cursor.execute("PRAGMA user_version=3");
# SQL copied from nsPermissionManager.cpp
cursor.execute("""CREATE TABLE moz_hosts (
id INTEGER PRIMARY KEY,
host TEXT,
type TEXT,
permission INTEGER,
expireType INTEGER,
expireTime INTEGER,
appId INTEGER,
isInBrowserElement INTEGER)""")
cursor.execute("""CREATE TABLE IF NOT EXISTS moz_hosts (
id INTEGER PRIMARY KEY,
host TEXT,
type TEXT,
permission INTEGER,
expireType INTEGER,
expireTime INTEGER,
appId INTEGER,
isInBrowserElement INTEGER)""")
# Insert desired permissions
c = 0
for perm in permissions.keys():
for host,allow in permissions[perm]:
c += 1
cursor.execute("INSERT INTO moz_hosts values(?, ?, ?, ?, 0, 0, 0, 0)",
(c, host, perm, 1 if allow else 2))
cursor.execute("INSERT INTO moz_hosts values(NULL, ?, ?, ?, 0, 0, 0, 0)",
(host, perm, 1 if allow else 2))
# Commit and close
permDB.commit()
cursor.close()
def setupTestApps(self, profileDir, apps):
webappJSONTemplate = Template(""""$name": {
"origin": "$origin",
"installOrigin": "$origin",
"receipt": null,
"installTime": 132333986000,
"manifestURL": "$manifestURL",
"localId": $localId,
"appStatus": $appStatus,
"csp": "$csp"
webappJSONTemplate = Template(""""$id": {
"origin": "$origin",
"installOrigin": "$origin",
"receipt": null,
"installTime": 132333986000,
"manifestURL": "$manifestURL",
"localId": $localId,
"id": "$id",
"appStatus": $appStatus,
"csp": "$csp"
}""")
manifestTemplate = Template("""{
@ -333,16 +332,73 @@ class Automation(object):
# Create webapps/webapps.json
webappsDir = os.path.join(profileDir, "webapps")
os.mkdir(webappsDir);
if not os.access(webappsDir, os.F_OK):
os.mkdir(webappsDir)
lineRe = re.compile(r'(.*?)"(.*?)": (.*)')
webappsJSONFilename = os.path.join(webappsDir, "webapps.json")
webappsJSON = []
for localId, app in enumerate(apps):
app['localId'] = localId + 1 # Has to be 1..n
webappsJSON.append(webappJSONTemplate.substitute(app))
webappsJSON = '{\n' + ',\n'.join(webappsJSON) + '\n}\n'
if os.access(webappsJSONFilename, os.F_OK):
# If there is an existing webapps.json file (which will be the case for
# b2g), we parse the data in the existing file before appending test
# test apps to it.
startId = 1
webappsJSONFile = open(webappsJSONFilename, "r")
contents = webappsJSONFile.read()
webappsJSONFile = open(os.path.join(webappsDir, "webapps.json"), "a")
webappsJSONFile.write(webappsJSON)
for app_content in contents.split('},'):
app = {}
# ghetto json parser needed due to lack of json/simplejson on test slaves
for line in app_content.split('\n'):
m = lineRe.match(line)
if m:
value = m.groups()[2]
# remove any trailing commas
if value[-1:] == ',':
value = value[:-1]
# set the app name from a line that looks like this:
# "name.gaiamobile.org": {
if value == '{':
app['id'] = m.groups()[1]
# parse string, None, bool and int types
elif value[0:1] == '"':
app[m.groups()[1]] = value[1:-1]
elif value == "null":
app[m.groups()[1]] = None
elif value == "true":
app[m.groups()[1]] = True
elif value == "false":
app[m.groups()[1]] = False
else:
app[m.groups()[1]] = int(value)
if app:
webappsJSON.append(app)
webappsJSONFile.close()
startId = 1
for app in webappsJSON:
if app['localId'] >= startId:
startId = app['localId'] + 1
if not app.get('csp'):
app['csp'] = ''
if not app.get('appStatus'):
app['appStatus'] = 3
for localId, app in enumerate(apps):
app['localId'] = localId + startId # localId must be from 1..N
if not app.get('id'):
app['id'] = app['name']
webappsJSON.append(app)
contents = []
for app in webappsJSON:
contents.append(webappJSONTemplate.substitute(app))
contents = '{\n' + ',\n'.join(contents) + '\n}\n'
webappsJSONFile = open(webappsJSONFilename, "w")
webappsJSONFile.write(contents)
webappsJSONFile.close()
# Create manifest file for each app.
@ -356,13 +412,19 @@ class Automation(object):
manifestFile.write(manifest)
manifestFile.close()
def initializeProfile(self, profileDir, extraPrefs = [], useServerLocations = False):
def initializeProfile(self, profileDir, extraPrefs=[],
useServerLocations=False,
initialProfile=None):
" Sets up the standard testing profile."
prefs = []
# Start with a clean slate.
shutil.rmtree(profileDir, True)
os.mkdir(profileDir)
if initialProfile:
shutil.copytree(initialProfile, profileDir)
else:
os.mkdir(profileDir)
# Set up permissions database
locations = self.readLocations()
@ -600,7 +662,7 @@ user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless t
'manifestURL': 'https://example.com/manifest_csp_cert.webapp',
'description': 'https://example.com Certified App with manifest policy',
'appStatus': _APP_STATUS_CERTIFIED
},
},
{
'name': 'https_example_csp_installed',
'csp': "default-src *; script-src 'self'; object-src 'none'; style-src 'self' 'unsafe-inline'",
@ -608,7 +670,7 @@ user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless t
'manifestURL': 'https://example.com/manifest_csp_inst.webapp',
'description': 'https://example.com Installed App with manifest policy',
'appStatus': _APP_STATUS_INSTALLED
},
},
{
'name': 'https_example_csp_privileged',
'csp': "default-src *; script-src 'self'; object-src 'none'; style-src 'self' 'unsafe-inline'",
@ -616,15 +678,15 @@ user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless t
'manifestURL': 'https://example.com/manifest_csp_priv.webapp',
'description': 'https://example.com Privileged App with manifest policy',
'appStatus': _APP_STATUS_PRIVILEGED
},
},
{
'name': 'https_a_domain_certified',
'csp' : "",
'csp': "",
'origin': 'https://acertified.com',
'manifestURL': 'https://acertified.com/manifest.webapp',
'description': 'https://acertified.com Certified App',
'appStatus': _APP_STATUS_CERTIFIED
},
},
{
'name': 'https_a_domain_privileged',
'csp': "",
@ -632,7 +694,7 @@ user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless t
'manifestURL': 'https://aprivileged.com/manifest.webapp',
'description': 'https://aprivileged.com Privileged App ',
'appStatus': _APP_STATUS_PRIVILEGED
},
},
];
self.setupTestApps(profileDir, apps)
@ -1033,7 +1095,7 @@ user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless t
runSSLTunnel = False, utilityPath = None,
xrePath = None, certPath = None,
debuggerInfo = None, symbolsPath = None,
timeout = -1, maxTime = None):
timeout = -1, maxTime = None, onLaunch = None):
"""
Run the app, log the duration it took to execute, return the status code.
Kills the app if it runs for longer than |maxTime| seconds, or outputs nothing for |timeout| seconds.
@ -1090,6 +1152,11 @@ user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless t
stderr = subprocess.STDOUT)
self.log.info("INFO | automation.py | Application pid: %d", proc.pid)
if onLaunch is not None:
# Allow callers to specify an onLaunch callback to be fired after the
# app is launched.
onLaunch()
status = self.waitForFinish(proc, utilityPath, timeout, maxTime, startTime, debuggerInfo, symbolsPath)
self.log.info("INFO | automation.py | Application ran for: %s", str(datetime.now() - startTime))

View File

@ -48,7 +48,7 @@ class B2GRemoteAutomation(Automation):
self._product = "b2g"
self.lastTestSeen = "b2gautomation.py"
# Default log finish to mochitest standard
self.logFinish = 'INFO SimpleTest FINISHED'
self.logFinish = 'INFO SimpleTest FINISHED'
Automation.__init__(self)
def setEmulator(self, is_emulator):
@ -85,7 +85,7 @@ class B2GRemoteAutomation(Automation):
env['MOZ_HIDE_RESULTS_TABLE'] = '1'
return env
def waitForNet(self):
def waitForNet(self):
active = False
time_out = 0
while not active and time_out < 40:
@ -106,15 +106,20 @@ class B2GRemoteAutomation(Automation):
self._devicemanager.getDirectory(self._remoteProfile + '/minidumps/', dumpDir)
crashed = automationutils.checkForCrashes(dumpDir, symbolsPath, self.lastTestSeen)
try:
shutil.rmtree(dumpDir)
shutil.rmtree(dumpDir)
except:
print "WARNING: unable to remove directory: %s" % (dumpDir)
print "WARNING: unable to remove directory: %s" % (dumpDir)
return crashed
def initializeProfile(self, profileDir, extraPrefs = [], useServerLocations = False):
def initializeProfile(self, profileDir, extraPrefs=[],
useServerLocations=False,
initialProfile=None):
# add b2g specific prefs
extraPrefs.extend(["browser.manifestURL='dummy (bug 772307)'"])
return Automation.initializeProfile(self, profileDir, extraPrefs, useServerLocations)
return Automation.initializeProfile(self, profileDir,
extraPrefs,
useServerLocations,
initialProfile)
def buildCommandLine(self, app, debuggerInfo, profileDir, testURL, extraArgs):
# if remote profile is specified, use that instead
@ -165,7 +170,7 @@ class B2GRemoteAutomation(Automation):
status = 'unknown'
for line in self._devicemanager._runCmd(['devices']).stdout.readlines():
result = re.match('(.*?)\t(.*)', line)
result = re.match('(.*?)\t(.*)', line)
if result:
thisSerial = result.group(1)
if not serial or thisSerial == serial:
@ -223,9 +228,9 @@ class B2GRemoteAutomation(Automation):
if not self._is_emulator:
self.rebootDevice()
time.sleep(5)
#wait for wlan to come up
#wait for wlan to come up
if not self.waitForNet():
raise Exception("network did not come up, please configure the network" +
raise Exception("network did not come up, please configure the network" +
" prior to running before running the automation framework")
# stop b2g
@ -334,10 +339,33 @@ class B2GRemoteAutomation(Automation):
break
return '\n'.join(lines)
def wait(self, timeout = None):
def wait(self, timeout=None):
# this should never happen
raise Exception("'wait' called on B2GInstance")
def kill(self):
# this should never happen
raise Exception("'kill' called on B2GInstance")
class B2GDesktopAutomation(Automation):
def buildCommandLine(self, app, debuggerInfo, profileDir, testURL, extraArgs):
""" build the application command line """
cmd = os.path.abspath(app)
args = []
if debuggerInfo:
args.extend(debuggerInfo["args"])
args.append(cmd)
cmd = os.path.abspath(debuggerInfo["path"])
if self.IS_MAC:
args.append("-foreground")
profileDirectory = profileDir + "/"
args.extend(("-profile", profileDirectory))
args.extend(extraArgs)
return cmd, args

View File

@ -73,7 +73,7 @@ GCONF_VERSION=1.2.1
GIO_VERSION=2.20
STARTUP_NOTIFICATION_VERSION=0.8
DBUS_VERSION=0.60
SQLITE_VERSION=3.7.15.1
SQLITE_VERSION=3.7.15.2
MSMANIFEST_TOOL=

View File

@ -13,6 +13,7 @@ include $(DEPTH)/config/autoconf.mk
MOCHITEST_FILES := \
webaudio.js \
test_bug808374.html \
test_bug827541.html \
test_AudioBuffer.html \
test_AudioContext.html \
test_AudioListener.html \

View File

@ -0,0 +1,25 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Tell the cycle collector about the audio contexts owned by nsGlobalWindow</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
SpecialPowers.setBoolPref("media.webaudio.enabled", true);
var iframe = document.createElementNS("http://www.w3.org/1999/xhtml", "iframe");
document.body.appendChild(iframe);
var frameWin = iframe.contentWindow;
frameWin.mozAudioContext;
document.body.removeChild(iframe);
frameWin.mozAudioContext();
ok(true, "This test should not leak");
SpecialPowers.clearUserPref("media.webaudio.enabled");
</script>
</pre>
</body>
</html>

View File

@ -1,6 +1,6 @@
This is sqlite 3.7.15.1
This is sqlite 3.7.15.2
-- Ryan VanderMeulen <ryanvm@gmail.com>, 12/2012
-- Ryan VanderMeulen <ryanvm@gmail.com>, 01/2013
See http://www.sqlite.org/ for more info.

View File

@ -1,6 +1,6 @@
/******************************************************************************
** This file is an amalgamation of many separate C source files from SQLite
** version 3.7.15.1. By combining all the individual C code files into this
** version 3.7.15.2. By combining all the individual C code files into this
** single large file, the entire code can be compiled as a single translation
** unit. This allows many compilers to do optimizations that would not be
** possible if the files were compiled separately. Performance improvements
@ -673,9 +673,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION "3.7.15.1"
#define SQLITE_VERSION "3.7.15.2"
#define SQLITE_VERSION_NUMBER 3007015
#define SQLITE_SOURCE_ID "2012-12-19 20:39:10 6b85b767d0ff7975146156a99ad673f2c1a23318"
#define SQLITE_SOURCE_ID "2013-01-09 11:53:05 c0e09560d26f0a6456be9dd3447f5311eb4f238f"
/*
** CAPI3REF: Run-Time Library Version Numbers
@ -105723,7 +105723,7 @@ static void bestBtreeIndex(WhereBestIdx *p){
pc.plan.nOBSat = isSortingIndex(p, pProbe, iCur, &bRev);
WHERETRACE((" --> after isSortingIndex: bRev=%d nOBSat=%d\n",
bRev, pc.plan.nOBSat));
if( nPriorSat<pc.plan.nOBSat || (pc.plan.wsFlags & WHERE_UNIQUE)!=0 ){
if( nPriorSat<pc.plan.nOBSat || (pc.plan.wsFlags & WHERE_ALL_UNIQUE)!=0 ){
pc.plan.wsFlags |= WHERE_ORDERED;
}
if( nOrderBy==pc.plan.nOBSat ){

View File

@ -107,9 +107,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()].
*/
#define SQLITE_VERSION "3.7.15.1"
#define SQLITE_VERSION "3.7.15.2"
#define SQLITE_VERSION_NUMBER 3007015
#define SQLITE_SOURCE_ID "2012-12-19 20:39:10 6b85b767d0ff7975146156a99ad673f2c1a23318"
#define SQLITE_SOURCE_ID "2013-01-09 11:53:05 c0e09560d26f0a6456be9dd3447f5311eb4f238f"
/*
** CAPI3REF: Run-Time Library Version Numbers

View File

@ -1228,15 +1228,19 @@ this.DOMApplicationRegistry = {
// "downloadapplied".
let updateObserver = {
observe: function(aSubject, aTopic, aObsData) {
debug("updateHostedApp: updateSvc.checkForUpdate return for " +
app.manifestURL + " - event is " + aTopic);
aData.event =
aTopic == "offline-cache-update-available" ? "downloadavailable"
: "downloadapplied";
aData.app.downloadAvailable = (aTopic == "downloadavailable");
aData.app.downloadAvailable = (aData.event == "downloadavailable");
DOMApplicationRegistry.broadcastMessage("Webapps:CheckForUpdate:Return:OK",
aData);
}
}
updateSvc.checkForUpdate(Services.io.newURI(aData.manifestURL, null, null),
debug("updateHostedApp: updateSvc.checkForUpdate for " +
manifest.fullAppcachePath());
updateSvc.checkForUpdate(Services.io.newURI(manifest.fullAppcachePath(), null, null),
app.localId, false, updateObserver);
}
delete app.manifest;
@ -1287,7 +1291,9 @@ this.DOMApplicationRegistry = {
// "downloadapplied".
let updateObserver = {
observe: function(aSubject, aTopic, aObsData) {
if (aData.event == "offline-cache-update-available") {
debug("onlyCheckAppCache updateSvc.checkForUpdate return for " +
app.manifestURL + " - event is " + aTopic);
if (aTopic == "offline-cache-update-available") {
aData.event = "downloadavailable";
app.downloadAvailable = true;
aData.app = app;
@ -1299,7 +1305,10 @@ this.DOMApplicationRegistry = {
}
}
}
updateSvc.checkForUpdate(Services.io.newURI(aData.manifestURL, null, null),
let helper = new ManifestHelper(manifest);
debug("onlyCheckAppCache - launch updateSvc.checkForUpdate for " +
helper.fullAppcachePath());
updateSvc.checkForUpdate(Services.io.newURI(helper.fullAppcachePath(), null, null),
app.localId, false, updateObserver);
});
return;
@ -1312,6 +1321,7 @@ this.DOMApplicationRegistry = {
xhr.channel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;
xhr.responseType = "json";
if (app.etag) {
debug("adding manifest etag:" + app.etag);
xhr.setRequestHeader("If-None-Match", app.etag);
}
xhr.channel.notificationCallbacks =
@ -1333,6 +1343,7 @@ this.DOMApplicationRegistry = {
return;
} else {
app.etag = xhr.getResponseHeader("Etag");
debug("at update got app etag=" + app.etag);
app.lastCheckedUpdate = Date.now();
if (app.origin.startsWith("app://")) {
updatePackagedApp.call(this, manifest);
@ -1509,6 +1520,7 @@ this.DOMApplicationRegistry = {
sendError("INSTALL_FROM_DENIED");
} else {
app.etag = xhr.getResponseHeader("Etag");
debug("at install package got app etag=" + app.etag);
Services.obs.notifyObservers(aMm, "webapps-ask-install",
JSON.stringify(aData));
}
@ -1832,7 +1844,7 @@ this.DOMApplicationRegistry = {
.QueryInterface(Ci.nsIHttpChannel);
requestChannel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;
if (app.packageEtag) {
debug('Add If-None-Match header: ' + app.packageEtag);
debug("Add If-None-Match header: " + app.packageEtag);
requestChannel.setRequestHeader("If-None-Match", app.packageEtag, false);
}

View File

@ -1293,18 +1293,16 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INTERNAL(nsGlobalWindow)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocumentPrincipal)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleService)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingStorageEvents)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleObservers)
// Traverse stuff from nsPIDOMWindow
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeEventHandler)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentTarget)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameElement)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFocusedNode)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingStorageEvents)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleObservers)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAudioContexts)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow)
@ -1333,20 +1331,17 @@ NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mApplicationCache)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPrincipal)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDoc)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleService)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingStorageEvents)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleObservers)
// Unlink stuff from nsPIDOMWindow
NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeEventHandler)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mParentTarget)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameElement)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFocusedNode)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleService)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingStorageEvents)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleObservers)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mAudioContexts)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
struct TraceData

View File

@ -56,13 +56,20 @@ GlobalPCList.prototype = {
addPC: function(pc) {
let winID = pc._winID;
if (this._list[winID]) {
this._list[winID].push(pc);
this._list[winID].push(Components.utils.getWeakReference(pc));
} else {
this._list[winID] = [pc];
this._list[winID] = [Components.utils.getWeakReference(pc)];
}
this.removeNullRefs(winID);
},
removeNullRefs: function(winID) {
this._list[winID] = this._list[winID].filter(
function (e,i,a) { return e.get() !== null; });
},
hasActivePeerConnection: function(winID) {
this.removeNullRefs(winID);
return this._list[winID] ? true : false;
},
@ -70,10 +77,13 @@ GlobalPCList.prototype = {
if (topic == "inner-window-destroyed") {
let winID = subject.QueryInterface(Ci.nsISupportsPRUint64).data;
if (this._list[winID]) {
this._list[winID].forEach(function(pc) {
pc._pc.close(false);
delete pc._observer;
pc._pc = null;
this._list[winID].forEach(function(pcref) {
let pc = pcref.get();
if (pc !== null) {
pc._pc.close(false);
delete pc._observer;
pc._pc = null;
}
});
delete this._list[winID];
}
@ -85,10 +95,13 @@ GlobalPCList.prototype = {
// while offline, but attempts to connect them should fail.
let array;
while ((array = this._list.pop()) != undefined) {
array.forEach(function(pc) {
pc._pc.close(true);
delete pc._observer;
pc._pc = null;
array.forEach(function(pcref) {
let pc = pcref.get();
if (pc !== null) {
pc._pc.close(true);
delete pc._observer;
pc._pc = null;
}
});
};
this._networkdown = true;
@ -230,7 +243,9 @@ PeerConnection.prototype = {
flags: Ci.nsIClassInfo.DOM_OBJECT}),
QueryInterface: XPCOMUtils.generateQI([
Ci.nsIDOMRTCPeerConnection, Ci.nsIDOMGlobalObjectConstructor
Ci.nsIDOMRTCPeerConnection,
Ci.nsIDOMGlobalObjectConstructor,
Ci.nsISupportsWeakReference,
]),
// Constructor is an explicit function, because of nsIDOMGlobalObjectConstructor.
@ -546,7 +561,8 @@ function PeerConnectionObserver(dompc) {
this._dompc = dompc;
}
PeerConnectionObserver.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.IPeerConnectionObserver]),
QueryInterface: XPCOMUtils.generateQI([Ci.IPeerConnectionObserver,
Ci.nsISupportsWeakReference]),
onCreateOfferSuccess: function(offer) {
if (this._dompc._onCreateOfferSuccess) {

View File

@ -39,7 +39,7 @@ const kMessages =["SystemMessageManager:GetPendingMessages",
"child-process-shutdown"]
function debug(aMsg) {
//dump("-- SystemMessageInternal " + Date.now() + " : " + aMsg + "\n");
dump("-- SystemMessageInternal " + Date.now() + " : " + aMsg + "\n");
}
// Implementation of the component used by internal users.
@ -48,6 +48,12 @@ function SystemMessageInternal() {
// The set of pages registered by installed apps. We keep the
// list of pending messages for each page here also.
this._pages = [];
// The set of listeners. This is a multi-dimensional object. The _listeners
// object itself is a map from manifest ID -> an array mapping proccesses to
// windows. We do this so that we can track both what processes we have to
// send system messages to as well as supporting the single-process case
// where we track windows instead.
this._listeners = {};
this._webappsRegistryReady = false;
@ -63,6 +69,16 @@ function SystemMessageInternal() {
Services.obs.notifyObservers(this, "system-message-internal-ready", null);
}
function findTarget(aListeners, aTarget) {
for (let i = 0; i < aListeners.length; ++i) {
let listener = aListeners[i];
if (listener.target === aTarget)
return listener;
}
return null;
}
SystemMessageInternal.prototype = {
sendMessage: function sendMessage(aType, aMessage, aPageURI, aManifestURI) {
// Buffer system messages until the webapps' registration is ready,
@ -189,10 +205,19 @@ SystemMessageInternal.prototype = {
case "SystemMessageManager:Register":
{
debug("Got Register from " + msg.manifest);
if (!this._listeners[msg.manifest]) {
this._listeners[msg.manifest] = {};
let targets, target;
if (!(targets = this._listeners[msg.manifest])) {
this._listeners[msg.manifest] =
[ { target: aMessage.target, winCount: 1 } ];
} else if (!(target = findTarget(targets, aMessage.target))) {
targets[msg.manifest].push({
target: aMessage.target,
winCount: 1
});
} else {
target.winCount++;
}
this._listeners[msg.manifest][msg.innerWindowID] = aMessage.target;
debug("listeners for " + msg.manifest + " innerWinID " + msg.innerWindowID);
break;
}
@ -200,11 +225,20 @@ SystemMessageInternal.prototype = {
{
debug("Got child-process-shutdown from " + aMessage.target);
for (let manifest in this._listeners) {
for (let winID in this._listeners[manifest]) {
if (aMessage.target === this._listeners[manifest][winID]) {
debug("remove " + manifest );
delete this._listeners[manifest];
return;
// See if any processes in this manifest have this target.
let targets = this._listeners[manifest];
for (let target = 0; target < targets.length; ++target) {
if (targets[target].target === aMessage.target) {
// One does: if it's the only one, get rid of this manifest
// entirely.
if (targets.length === 1) {
debug("remove " + manifest );
delete this._listeners[manifest];
} else {
// There are other targets for this manifest, get rid of this
// one.
targets.splice(target, 1);
}
}
}
}
@ -213,7 +247,22 @@ SystemMessageInternal.prototype = {
case "SystemMessageManager:Unregister":
{
debug("Got Unregister from " + aMessage.target + "innerWinID " + msg.innerWindowID);
delete this._listeners[msg.manifest][msg.innerWindowID];
let targets = this._listeners[msg.manifest];
for (let i = 0; i < targets.length; ++i) {
if (targets[i].target === aMessage.target) {
if (--targets[i].winCount === 0) {
if (targets.length === 1) {
// Only one listener left, remove the target.
delete this._listeners[msg.manifest];
} else {
// More than one left, remove this one and leave the rest.
targets.splice(i, 1);
}
}
}
}
debug("Removing " + aMessage.target + "innerWinID " + msg.innerWindowID );
break;
@ -391,13 +440,14 @@ SystemMessageInternal.prototype = {
let winTargets = this._listeners[aManifestURI];
if (winTargets) {
for (let winID in winTargets) {
winTargets[winID].sendAsyncMessage("SystemMessageManager:Message",
{ type: aType,
msg: aMessage,
manifest: aManifestURI,
uri: aPageURI,
msgID: aMessageID });
for (let target = 0; target < winTargets.length; ++target) {
let manager = winTargets[target].target;
manager.sendAsyncMessage("SystemMessageManager:Message",
{ type: aType,
msg: aMessage,
manifest: aManifestURI,
uri: aPageURI,
msgID: aMessageID });
}
}

View File

@ -1,204 +0,0 @@
/* 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/. */
Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
const Ci = Components.interfaces;
const Cc = Components.classes;
var gLoggingEnabled = false;
function LOG(aMsg) {
if (gLoggingEnabled)
{
aMsg = ("*** GPSD GEO: " + aMsg);
Cc["@mozilla.org/consoleservice;1"].getService(Ci.nsIConsoleService).logStringMessage(aMsg);
dump(aMsg);
}
}
function GeoPositionCoordsObject(latitude, longitude, altitude, accuracy, altitudeAccuracy, heading, speed) {
this.latitude = latitude;
this.longitude = longitude;
this.altitude = altitude;
this.accuracy = accuracy;
this.altitudeAccuracy = altitudeAccuracy;
this.heading = heading;
this.speed = speed;
};
GeoPositionCoordsObject.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMGeoPositionCoords]),
// Class Info is required to be able to pass objects back into the DOM.
classInfo: XPCOMUtils.generateCI({interfaces: [Ci.nsIDOMGeoPositionCoords],
flags: Ci.nsIClassInfo.DOM_OBJECT,
classDescription: "Geoposition Coordinate Object"}),
latitude: null,
longitude: null,
altitude: null,
accuracy: null,
altitudeAccuracy: null,
heading: null,
speed: null,
};
function GeoPositionObject(latitude, longitude, altitude, accuracy, altitudeAccuracy, heading, speed, timestamp) {
this.coords = new GeoPositionCoordsObject(latitude, longitude, altitude, accuracy, altitudeAccuracy, heading, speed);
this.timestamp = timestamp;
};
GeoPositionObject.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIDOMGeoPosition]),
// Class Info is required to be able to pass objects back into the DOM.
classInfo: XPCOMUtils.generateCI({interfaces: [Ci.nsIDOMGeoPosition],
flags: Ci.nsIClassInfo.DOM_OBJECT,
classDescription: "Geoposition Object"}),
coords: null,
timestamp: null,
};
function GPSDProvider() {
this.prefService = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch).QueryInterface(Ci.nsIPrefService);
try {
gLoggingEnabled = this.prefService.getBoolPref("geo.gpsd.logging.enabled");
} catch (e) {}
};
GPSDProvider.prototype = {
QueryInterface: XPCOMUtils.generateQI([Ci.nsIGeolocationProvider]),
classID: Components.ID("{0A3BE523-0F2A-32CC-CCD8-1E5986D5A79D}"),
prefService: null,
transport: null,
outputStream: null,
inputStream: null,
startup: function() {
LOG("startup called\n");
var socketTransportService = Cc["@mozilla.org/network/socket-transport-service;1"].getService(Ci.nsISocketTransportService);
var hostIPAddr = "127.0.0.1";
var hostPort = "2947";
try {
hostIPAddr = this.prefService.getCharPref("geo.gpsd.host.ipaddr");
} catch (e) {}
try {
hostPort = this.prefService.getCharPref("geo.gpsd.host.port");
} catch (e) {}
LOG("Host info: " + hostIPAddr + ":" + hostPort + "\n");
this.transport = socketTransportService.createTransport(null, 0, hostIPAddr, hostPort, null);
// Alright to open streams here as they are non-blocking by default
this.outputStream = this.transport.openOutputStream(0,0,0);
this.inputStream = this.transport.openInputStream(0,0,0);
},
shutdown: function() {
LOG("shutdown called\n");
this.outputStream.close();
this.inputStream.close();
this.transport.close(Components.results.NS_OK);
},
watch: function(c, isPrivate) {
LOG("watch called\n");
try {
// Go into "watcher" mode
var mode = '?WATCH={"enable":true,"json":true}';
this.outputStream.write(mode, mode.length);
} catch (e) { return; }
var dataListener = {
onStartRequest: function(request, context) {},
onStopRequest: function(request, context, status) {},
onDataAvailable: function(request, context, inputStream, offset, count) {
var sInputStream = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(Ci.nsIScriptableInputStream);
sInputStream.init(inputStream);
var responseSentence = sInputStream.read(count);
var response = null;
try {
response = JSON.parse(responseSentence);
} catch (e) { return; }
// is the right kind of sentence?
if (response.class != 'TPV') {
//don't do anything
return;
}
// is there a fix?
if (response.mode == '1') {
// don't do anything
return;
}
LOG("Got info: " + responseSentence);
// The API requires these values, if one is missing
// we return without updating the position.
if (response.time && response.lat && response.lon
&& response.epx && response.epy) {
var timestamp = response.time; // UTC
var latitude = response.lat; // degrees
var longitude = response.lon; // degrees
var horizontalError = Math.max(response.epx,response.epy); } // meters
else { return; }
// Altitude is optional, but if it's present, so must be vertical precision.
var altitude = null;
var verticalError = null;
if (response.alt && response.epv) {
altitude = response.alt; // meters
verticalError = response.epv; // meters
}
var speed = null;
if (response.speed) { var speed = response.speed; } // meters/sec
var course = null;
if (response.track) { var course = response.track; } // degrees
var geoPos = new GeoPositionObject(latitude, longitude, altitude, horizontalError, verticalError, course, speed, timestamp);
c.update(geoPos);
LOG("Position updated:" + timestamp + "," + latitude + "," + longitude + ","
+ horizontalError + "," + altitude + "," + verticalError + "," + course
+ "," + speed);
}
};
var pump = Cc["@mozilla.org/network/input-stream-pump;1"].createInstance(Ci.nsIInputStreamPump);
pump.init(this.inputStream, -1, -1, 0, 0, false);
pump.asyncRead(dataListener, null);
},
};
this.NSGetFactory = XPCOMUtils.generateNSGetFactory([GPSDProvider]);

View File

@ -1,3 +0,0 @@
component {0A3BE523-0F2A-32CC-CCD8-1E5986D5A79D} GPSDGeolocationProvider.js
contract @mozilla.org/geolocation/gpsd/provider;1 {0A3BE523-0F2A-32CC-CCD8-1E5986D5A79D}
category geolocation-provider GPSDProvider @mozilla.org/geolocation/gpsd/provider;1

View File

@ -55,8 +55,6 @@ ifneq (Android,$(OS_TARGET))
EXTRA_COMPONENTS = \
NetworkGeolocationProvider.js \
NetworkGeolocationProvider.manifest \
GPSDGeolocationProvider.js \
GPSDGeolocationProvider.manifest \
$(NULL)
endif

View File

@ -2799,7 +2799,7 @@ DrawTargetD2D::PushD2DLayer(ID2D1RenderTarget *aRT, ID2D1Geometry *aGeometry, ID
D2D1_LAYER_OPTIONS options = D2D1_LAYER_OPTIONS_NONE;
D2D1_LAYER_OPTIONS1 options1 = D2D1_LAYER_OPTIONS1_NONE;
if (mFormat == FORMAT_B8G8R8X8) {
if (aRT->GetPixelFormat().alphaMode == D2D1_ALPHA_MODE_IGNORE) {
options = D2D1_LAYER_OPTIONS_INITIALIZE_FOR_CLEARTYPE;
options1 = D2D1_LAYER_OPTIONS1_IGNORE_ALPHA | D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND;
}

View File

@ -183,7 +183,7 @@ ImageContainer::SetCurrentImage(Image *aImage)
if (aImage) {
mImageContainerChild->SendImageAsync(this, aImage);
} else {
mImageContainerChild->DispatchSetIdle();
mImageContainerChild->SetIdle();
}
}

View File

@ -73,12 +73,33 @@ void ImageContainerChild::SetIdleNow()
mImageQueue.Clear();
}
void ImageContainerChild::DispatchSetIdle()
void ImageContainerChild::SetIdleSync(Monitor* aBarrier, bool* aDone)
{
MonitorAutoLock autoMon(*aBarrier);
SetIdleNow();
*aDone = true;
aBarrier->NotifyAll();
}
void ImageContainerChild::SetIdle()
{
if (mStop) return;
if (InImageBridgeChildThread()) {
return SetIdleNow();
}
Monitor barrier("SetIdle Lock");
MonitorAutoLock autoMon(barrier);
bool done = false;
GetMessageLoop()->PostTask(FROM_HERE,
NewRunnableMethod(this, &ImageContainerChild::SetIdleNow));
NewRunnableMethod(this, &ImageContainerChild::SetIdleSync, &barrier, &done));
while (!done) {
barrier.Wait();
}
}
void ImageContainerChild::StopChildAndParent()

View File

@ -106,16 +106,9 @@ public:
void DispatchDestroy();
/**
* Dispatches a task on the ImageBridgeChild's thread that will call SendFlush
* and deallocate the shared images in the pool.
* Can be called on any thread.
* Flush and deallocate the shared images in the pool.
*/
void DispatchSetIdle();
/**
* Must be called on the ImageBridgeChild's thread.
*/
void SetIdleNow();
void SetIdle();
/**
* Can be called from any thread.
@ -168,9 +161,21 @@ protected:
}
/**
* Must be called on the ImageBridgeCHild's thread.
* Must be called on the ImageBridgeChild's thread.
*/
void DestroyNow();
/**
* Dispatches a task on the ImageBridgeChild's thread that will call SendFlush
* and deallocate the shared images in the pool.
* Can be called on any thread.
*/
void SetIdleSync(Monitor* aBarrier, bool* aDone);
/**
* Must be called on the ImageBridgeChild's thread.
*/
void SetIdleNow();
inline void SetID(uint64_t id)
{

View File

@ -44,7 +44,7 @@ parent:
// Tells the parent side to dispose of its shared images (most likely because the
// video element is still alive but will not be displayed for a moment).
async Flush();
sync Flush();
// After receiving this message, the ImageContainerParent will not return images
// back to the child side (to avoid a race between ReturnImage and __delete__)

View File

@ -915,19 +915,20 @@ jsdProperty::GetValue(jsdIValue **_rval)
NS_IMPL_THREADSAFE_ISUPPORTS2(jsdScript, jsdIScript, jsdIEphemeral)
static NS_IMETHODIMP
AssignToJSString(nsACString *x, JSString *str)
AssignToJSString(JSDContext *aCx, nsACString *x, JSString *str)
{
if (!str) {
x->SetLength(0);
return NS_OK;
}
size_t length = JS_GetStringEncodingLength(NULL, str);
JSContext *cx = JSD_GetDefaultJSContext(aCx);
size_t length = JS_GetStringEncodingLength(cx, str);
if (length == size_t(-1))
return NS_ERROR_FAILURE;
x->SetLength(uint32_t(length));
if (x->Length() != uint32_t(length))
return NS_ERROR_OUT_OF_MEMORY;
JS_EncodeStringToBuffer(str, x->BeginWriting(), length);
JS_EncodeStringToBuffer(cx, str, x->BeginWriting(), length);
return NS_OK;
}
@ -953,7 +954,7 @@ jsdScript::jsdScript (JSDContext *aCx, JSDScript *aScript) : mValid(false),
if (mFunctionName) {
JSString *str = JSD_GetScriptFunctionId(mCx, mScript);
if (str)
AssignToJSString(mFunctionName, str);
AssignToJSString(mCx, mFunctionName, str);
}
mBaseLineNumber = JSD_GetScriptBaseLineNumber(mCx, mScript);
mLineExtent = JSD_GetScriptLineExtent(mCx, mScript);
@ -1908,7 +1909,7 @@ jsdStackFrame::GetFunctionName(nsACString &_rval)
ASSERT_VALID_EPHEMERAL;
JSString *str = JSD_GetIdForStackFrame(mCx, mThreadState, mStackFrameInfo);
if (str)
return AssignToJSString(&_rval, str);
return AssignToJSString(mCx, &_rval, str);
_rval.Assign("anonymous");
return NS_OK;
@ -2238,7 +2239,7 @@ NS_IMETHODIMP
jsdValue::GetJsFunctionName(nsACString &_rval)
{
ASSERT_VALID_EPHEMERAL;
return AssignToJSString(&_rval, JSD_GetValueFunctionId(mCx, mValue));
return AssignToJSString(mCx, &_rval, JSD_GetValueFunctionId(mCx, mValue));
}
NS_IMETHODIMP

View File

@ -0,0 +1,126 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sw=4 et tw=78:
*
* 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 js_CharacterEncoding_h___
#define js_CharacterEncoding_h___
#include "mozilla/Range.h"
#include "js/Utility.h"
#include "jspubtd.h"
namespace JS {
/*
* By default, all C/C++ 1-byte-per-character strings passed into the JSAPI
* are treated as ISO/IEC 8859-1, also known as Latin-1. That is, each
* byte is treated as a 2-byte character, and there is no way to pass in a
* string containing characters beyond U+00FF.
*/
class Latin1Chars : public mozilla::Range<unsigned char>
{
typedef mozilla::Range<unsigned char> Base;
public:
Latin1Chars() : Base() {}
Latin1Chars(char *bytes, size_t length) : Base(reinterpret_cast<unsigned char *>(bytes), length) {}
};
/*
* A Latin1Chars, but with \0 termination for C compatibility.
*/
class Latin1CharsZ : public mozilla::RangedPtr<unsigned char>
{
typedef mozilla::RangedPtr<unsigned char> Base;
public:
Latin1CharsZ() : Base(NULL, 0) {}
Latin1CharsZ(char *bytes, size_t length)
: Base(reinterpret_cast<unsigned char *>(bytes), length)
{
JS_ASSERT(bytes[length] == '\0');
}
Latin1CharsZ(unsigned char *bytes, size_t length)
: Base(bytes, length)
{
JS_ASSERT(bytes[length] == '\0');
}
char *c_str() { return reinterpret_cast<char *>(get()); }
};
/*
* SpiderMonkey also deals directly with UTF-8 encoded text in some places.
*/
class UTF8CharsZ : public mozilla::RangedPtr<unsigned char>
{
typedef mozilla::RangedPtr<unsigned char> Base;
public:
UTF8CharsZ() : Base(NULL, 0) {}
UTF8CharsZ(char *bytes, size_t length)
: Base(reinterpret_cast<unsigned char *>(bytes), length)
{
JS_ASSERT(bytes[length] == '\0');
}
};
/*
* SpiderMonkey uses a 2-byte character representation: it is a
* 2-byte-at-a-time view of a UTF-16 byte stream. This is similar to UCS-2,
* but unlike UCS-2, we do not strip UTF-16 extension bytes. This allows a
* sufficiently dedicated JavaScript program to be fully unicode-aware by
* manually interpreting UTF-16 extension characters embedded in the JS
* string.
*/
class TwoByteChars : public mozilla::Range<jschar>
{
typedef mozilla::Range<jschar> Base;
public:
TwoByteChars() : Base() {}
TwoByteChars(jschar *chars, size_t length) : Base(chars, length) {}
TwoByteChars(const jschar *chars, size_t length) : Base(const_cast<jschar *>(chars), length) {}
};
/*
* A TwoByteChars, but \0 terminated for compatibility with JSFlatString.
*/
class TwoByteCharsZ : public mozilla::RangedPtr<jschar>
{
typedef mozilla::RangedPtr<jschar> Base;
public:
TwoByteCharsZ(jschar *chars, size_t length)
: Base(chars, length)
{
JS_ASSERT(chars[length] = '\0');
}
};
/*
* Convert a 2-byte character sequence to "ISO-Latin-1". This works by
* truncating each 2-byte pair in the sequence to a 1-byte pair. If the source
* contains any UTF-16 extension characters, then this may give invalid Latin1
* output. The returned string is zero terminated. The returned string or the
* returned string's |start()| must be freed with JS_free or js_free,
* respectively. If allocation fails, an OOM error will be set and the method
* will return a NULL chars (which can be tested for with the ! operator).
* This method cannot trigger GC.
*/
extern Latin1CharsZ
LossyTwoByteCharsToNewLatin1CharsZ(JSContext *cx, TwoByteChars tbchars);
} // namespace JS
inline void JS_free(JS::Latin1CharsZ &ptr) { js_free((void*)ptr.get()); }
#endif // js_CharacterEncoding_h___

View File

@ -127,6 +127,7 @@ CPPSRCS = \
String.cpp \
BytecodeCompiler.cpp \
BytecodeEmitter.cpp \
CharacterEncoding.cpp \
FoldConstants.cpp \
Intl.cpp \
NameFunctions.cpp \
@ -216,6 +217,7 @@ EXPORTS_NAMESPACES += js
# that we ensure we don't over-expose our internal integer typedefs. Note that
# LegacyIntTypes.h below is deliberately exempted from this requirement.
EXPORTS_js = \
CharacterEncoding.h \
HashTable.h \
HeapAPI.h \
LegacyIntTypes.h \

View File

@ -9,6 +9,7 @@
from __future__ import with_statement
from optparse import OptionParser
import sys, re, os, posixpath, ntpath
import errno
from StringIO import StringIO
# Standalone js doesn't have virtualenv.
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'config'))

View File

@ -159,7 +159,7 @@ obj_toSource(JSContext *cx, unsigned argc, Value *vp)
int valcnt = 0;
if (shape) {
bool doGet = true;
if (obj2->isNative() && !IsImplicitProperty(shape)) {
if (obj2->isNative() && !IsImplicitDenseElement(shape)) {
unsigned attrs = shape->attributes();
if (attrs & JSPROP_GETTER) {
doGet = false;
@ -456,7 +456,7 @@ obj_lookupGetter(JSContext *cx, unsigned argc, Value *vp)
return JS_FALSE;
args.rval().setUndefined();
if (shape) {
if (pobj->isNative() && !IsImplicitProperty(shape)) {
if (pobj->isNative() && !IsImplicitDenseElement(shape)) {
if (shape->hasGetterValue())
args.rval().set(shape->getterValue());
}
@ -492,7 +492,7 @@ obj_lookupSetter(JSContext *cx, unsigned argc, Value *vp)
return JS_FALSE;
args.rval().setUndefined();
if (shape) {
if (pobj->isNative() && !IsImplicitProperty(shape)) {
if (pobj->isNative() && !IsImplicitDenseElement(shape)) {
if (shape->hasSetterValue())
args.rval().set(shape->setterValue());
}

View File

@ -1747,7 +1747,7 @@ ParallelArrayObject::lookupElement(JSContext *cx, HandleObject obj, uint32_t ind
{
// No prototype walking for elements.
if (index < as(obj)->outermostDimension()) {
MarkImplicitPropertyFound(propp);
MarkNonNativePropertyFound(propp);
objp.set(obj);
return true;
}

View File

@ -114,7 +114,7 @@ js::CreateRegExpMatchResult(JSContext *cx, HandleString string, MatchPairs &matc
}
RegExpRunStatus
ExecuteRegExpImpl(JSContext *cx, RegExpStatics *res, RegExpShared &re, RegExpObject &regexp,
ExecuteRegExpImpl(JSContext *cx, RegExpStatics *res, RegExpShared &re,
JSLinearString *input, StableCharPtr chars, size_t length,
size_t *lastIndex, MatchConduit &matches)
{
@ -126,7 +126,7 @@ ExecuteRegExpImpl(JSContext *cx, RegExpStatics *res, RegExpShared &re, RegExpObj
/* Only one MatchPair slot provided: execute short-circuiting regexp. */
status = re.executeMatchOnly(cx, chars, length, lastIndex, *matches.u.pair);
if (status == RegExpRunStatus_Success && res)
res->updateLazily(cx, input, &regexp, lastIndex_orig);
res->updateLazily(cx, input, &re, lastIndex_orig);
} else {
/* Vector of MatchPairs provided: execute full regexp. */
status = re.execute(cx, chars, length, lastIndex, *matches.u.pairs);
@ -151,7 +151,7 @@ js::ExecuteRegExpLegacy(JSContext *cx, RegExpStatics *res, RegExpObject &reobj,
MatchConduit conduit(&matches);
RegExpRunStatus status =
ExecuteRegExpImpl(cx, res, *shared, reobj, input, chars, length, lastIndex, conduit);
ExecuteRegExpImpl(cx, res, *shared, input, chars, length, lastIndex, conduit);
if (status == RegExpRunStatus_Error)
return false;
@ -580,7 +580,7 @@ js::ExecuteRegExp(JSContext *cx, HandleObject regexp, HandleString string, Match
/* Steps 8-21. */
size_t lastIndexInt(i);
RegExpRunStatus status =
ExecuteRegExpImpl(cx, res, *re, *reobj, stableInput, chars, length, &lastIndexInt, matches);
ExecuteRegExpImpl(cx, res, *re, stableInput, chars, length, &lastIndexInt, matches);
if (status == RegExpRunStatus_Error)
return RegExpRunStatus_Error;

View File

@ -32,6 +32,7 @@
#include "frontend/Parser.h"
#include "frontend/TokenStream.h"
#include "js/CharacterEncoding.h"
#include "vm/Keywords.h"
#include "vm/RegExpObject.h"
#include "vm/StringBuffer.h"
@ -564,7 +565,8 @@ TokenStream::reportCompileErrorNumberVA(ParseNode *pn, unsigned flags, unsigned
err.report.uclinebuf = windowBuf.extractWellSized();
if (!err.report.uclinebuf)
return false;
err.report.linebuf = DeflateString(cx, err.report.uclinebuf, windowLength);
TwoByteChars tbchars(err.report.uclinebuf, windowLength);
err.report.linebuf = LossyTwoByteCharsToNewLatin1CharsZ(cx, tbchars).c_str();
if (!err.report.linebuf)
return false;
@ -728,7 +730,8 @@ TokenStream::getXMLEntity()
bad:
/* No match: throw a TypeError per ECMA-357 10.3.2.1 step 8(a). */
JS_ASSERT((tb.end() - bp) >= 1);
bytes = DeflateString(cx, bp + 1, (tb.end() - bp) - 1);
TwoByteChars tbchars(bp + 1, (tb.end() - bp) - 1);
bytes = LossyTwoByteCharsToNewLatin1CharsZ(cx, tbchars).c_str();
if (bytes) {
reportError(msg, bytes);
js_free(bytes);

View File

@ -339,7 +339,6 @@ DeclMarkerImpl(Object, DebugScopeObject)
DeclMarkerImpl(Object, GlobalObject)
DeclMarkerImpl(Object, JSObject)
DeclMarkerImpl(Object, JSFunction)
DeclMarkerImpl(Object, RegExpObject)
DeclMarkerImpl(Object, ScopeObject)
DeclMarkerImpl(Script, JSScript)
DeclMarkerImpl(Shape, Shape)

View File

@ -97,7 +97,6 @@ DeclMarker(Object, DebugScopeObject)
DeclMarker(Object, GlobalObject)
DeclMarker(Object, JSObject)
DeclMarker(Object, JSFunction)
DeclMarker(Object, RegExpObject)
DeclMarker(Object, ScopeObject)
DeclMarker(Script, JSScript)
DeclMarker(Shape, Shape)

View File

@ -562,10 +562,8 @@ AutoGCRooter::trace(JSTracer *trc)
}
case REGEXPSTATICS: {
/*
RegExpStatics::AutoRooter *rooter = static_cast<RegExpStatics::AutoRooter *>(this);
rooter->trace(trc);
*/
return;
}
@ -646,15 +644,14 @@ Shape::Range::AutoRooter::trace(JSTracer *trc)
void
RegExpStatics::AutoRooter::trace(JSTracer *trc)
{
if (statics->regexp)
MarkObjectRoot(trc, reinterpret_cast<JSObject**>(&statics->regexp),
"RegExpStatics::AutoRooter regexp");
if (statics->matchesInput)
MarkStringRoot(trc, reinterpret_cast<JSString**>(&statics->matchesInput),
"RegExpStatics::AutoRooter matchesInput");
if (statics->pendingInput)
MarkStringRoot(trc, reinterpret_cast<JSString**>(&statics->pendingInput),
"RegExpStatics::AutoRooter pendingInput");
if (statics->regexp.initialized())
statics->regexp->trace(trc);
}
void

View File

@ -1435,6 +1435,9 @@ IsPropertySetterCallInlineable(JSContext *cx, HandleObject obj, HandleObject hol
if (!shape)
return false;
if (!holder->isNative())
return false;
if (shape->hasSlot())
return false;

View File

@ -0,0 +1,5 @@
// Don't assert.
verifyprebarriers();
r = /()()()\3/.test();
gc();
RegExp().test();

View File

@ -0,0 +1,3 @@
// Don't assert.
'123456'.replace(/1(\d+)3/, '');
RegExp.lastMatch.toString();

View File

@ -0,0 +1,8 @@
// Don't assert.
eval("\
x = RegExp(\"()\", \"y\");\
x.test();\
x = {};\
")
gc()
RegExp.$6

View File

@ -0,0 +1,8 @@
// Don't assert.
eval("\
r = RegExp(\"(?!()(((!))))\", \"g\");\
\"^\".replace(r, '');\
r = (\"1+\")\
")
gc()
RegExp.$8

View File

@ -0,0 +1,7 @@
// |jit-test| error: TypeError
try {
x = [];
Array.prototype.forEach()
} catch (e) {}
x.forEach()

View File

@ -0,0 +1,10 @@
// |jit-test| error: InternalError
p = Proxy.create({
has: function() function r() s += ''
})
Object.prototype.__proto__ = p
function TestCase(n) {
this.name = n
}
new TestCase()

View File

@ -68,6 +68,7 @@ CPPSRCS = \
testStringBuffer.cpp \
testTrap.cpp \
testTypedArrays.cpp \
testUTF8.cpp \
testVersion.cpp \
testXDR.cpp \
$(NULL)

View File

@ -0,0 +1,46 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sw=4 et tw=99:
*/
/* 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 "tests.h"
#include "jsapi.h"
#include "jsstr.h"
#include "js/CharacterEncoding.h"
BEGIN_TEST(testUTF8_badUTF8)
{
static const char badUTF8[] = "...\xC0...";
JSString *str = JS_NewStringCopyZ(cx, badUTF8);
CHECK(str);
const jschar *chars = JS_GetStringCharsZ(cx, str);
CHECK(chars);
CHECK(chars[3] == 0x00C0);
return true;
}
END_TEST(testUTF8_badUTF8)
BEGIN_TEST(testUTF8_bigUTF8)
{
static const char bigUTF8[] = "...\xFB\xBF\xBF\xBF\xBF...";
JSString *str = JS_NewStringCopyZ(cx, bigUTF8);
CHECK(str);
const jschar *chars = JS_GetStringCharsZ(cx, str);
CHECK(chars);
CHECK(chars[3] == 0x00FB);
return true;
}
END_TEST(testUTF8_bigUTF8)
BEGIN_TEST(testUTF8_badSurrogate)
{
static const jschar badSurrogate[] = { 'A', 'B', 'C', 0xDEEE, 'D', 'E', 0 };
JS::TwoByteChars tbchars(badSurrogate, js_strlen(badSurrogate));
JS::Latin1CharsZ latin1 = JS::LossyTwoByteCharsToNewLatin1CharsZ(cx, tbchars);
CHECK(latin1);
CHECK(latin1[3] == 0x00EE);
return true;
}
END_TEST(testUTF8_badSurrogate)

View File

@ -64,6 +64,7 @@
#include "frontend/BytecodeCompiler.h"
#include "gc/Marking.h"
#include "gc/Memory.h"
#include "js/CharacterEncoding.h"
#include "js/MemoryMetrics.h"
#include "vm/Debugger.h"
#include "vm/NumericConversions.h"
@ -3572,7 +3573,7 @@ LookupResult(JSContext *cx, HandleObject obj, HandleObject obj2, jsid id,
return JS_TRUE;
}
if (IsImplicitProperty(shape)) {
if (!obj2->isNative()) {
if (obj2->isProxy()) {
AutoPropertyDescriptorRooter desc(cx);
if (!Proxy::getPropertyDescriptor(cx, obj2, id, &desc, 0))
@ -3581,10 +3582,10 @@ LookupResult(JSContext *cx, HandleObject obj, HandleObject obj2, jsid id,
*vp = desc.value;
return true;
}
} else if (obj2->isNative()) {
*vp = obj2->getDenseElement(JSID_TO_INT(id));
return true;
}
} else if (IsImplicitDenseElement(shape)) {
*vp = obj2->getDenseElement(JSID_TO_INT(id));
return true;
} else {
/* Peek at the native property's slot value, without doing a Get. */
if (shape->hasSlot()) {
@ -4062,7 +4063,7 @@ GetPropertyDescriptorById(JSContext *cx, HandleObject obj, HandleId id, unsigned
desc->obj = obj2;
if (obj2->isNative()) {
if (IsImplicitProperty(shape)) {
if (IsImplicitDenseElement(shape)) {
desc->attrs = JSPROP_ENUMERATE;
desc->getter = NULL;
desc->setter = NULL;
@ -6231,27 +6232,24 @@ JS_DecodeBytes(JSContext *cx, const char *src, size_t srclen, jschar *dst, size_
}
JS_PUBLIC_API(char *)
JS_EncodeString(JSContext *cx, JSRawString strArg)
JS_EncodeString(JSContext *cx, JSRawString str)
{
RootedString str(cx, strArg);
AutoAssertNoGC nogc;
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
const jschar *chars = str->getChars(cx);
if (!chars)
JSLinearString *linear = str->ensureLinear(cx);
if (!linear)
return NULL;
return DeflateString(cx, chars, str->length());
return LossyTwoByteCharsToNewLatin1CharsZ(cx, linear->range()).c_str();
}
JS_PUBLIC_API(size_t)
JS_GetStringEncodingLength(JSContext *cx, JSString *str)
{
/* jsd calls us with a NULL cx. Ugh. */
if (cx) {
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
}
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
const jschar *chars = str->getChars(cx);
if (!chars)
@ -6260,8 +6258,11 @@ JS_GetStringEncodingLength(JSContext *cx, JSString *str)
}
JS_PUBLIC_API(size_t)
JS_EncodeStringToBuffer(JSString *str, char *buffer, size_t length)
JS_EncodeStringToBuffer(JSContext *cx, JSString *str, char *buffer, size_t length)
{
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
/*
* FIXME bug 612141 - fix DeflateStringToBuffer interface so the result
* would allow to distinguish between insufficient buffer and encoding

View File

@ -5554,7 +5554,7 @@ JS_GetStringEncodingLength(JSContext *cx, JSString *str);
* written into the buffer.
*/
JS_PUBLIC_API(size_t)
JS_EncodeStringToBuffer(JSString *str, char *buffer, size_t length);
JS_EncodeStringToBuffer(JSContext *cx, JSString *str, char *buffer, size_t length);
class JSAutoByteString
{

View File

@ -23,6 +23,8 @@
# include <string>
#endif // ANDROID
#include "mozilla/Util.h"
#include "jstypes.h"
#include "jsutil.h"
#include "jsclist.h"
@ -55,6 +57,7 @@
# include "methodjit/MethodJIT.h"
#endif
#include "gc/Marking.h"
#include "js/CharacterEncoding.h"
#include "js/MemoryMetrics.h"
#include "frontend/TokenStream.h"
#include "frontend/ParseMaps.h"
@ -69,6 +72,7 @@ using namespace js;
using namespace js::gc;
using mozilla::DebugOnly;
using mozilla::PointerRangeSize;
bool
js::AutoCycleDetector::init()
@ -832,8 +836,10 @@ js_ExpandErrorArguments(JSContext *cx, JSErrorCallback callback,
JS_ASSERT(expandedArgs == argCount);
*out = 0;
js_free(buffer);
*messagep = DeflateString(cx, reportp->ucmessage,
size_t(out - reportp->ucmessage));
TwoByteChars ucmsg(reportp->ucmessage,
PointerRangeSize(static_cast<const jschar *>(reportp->ucmessage),
static_cast<const jschar *>(out)));
*messagep = LossyTwoByteCharsToNewLatin1CharsZ(cx, ucmsg).c_str();
if (!*messagep)
goto error;
}

View File

@ -291,13 +291,13 @@ MakeTypeId(JSContext *cx, jsid id)
*/
if (JSID_IS_STRING(id)) {
JSFlatString *str = JSID_TO_FLAT_STRING(id);
const jschar *cp = str->getCharsZ(cx);
if (JS7_ISDEC(*cp) || *cp == '-') {
cp++;
while (JS7_ISDEC(*cp))
cp++;
if (*cp == 0)
return JSID_VOID;
TwoByteChars cp = str->range();
if (JS7_ISDEC(cp[0]) || cp[0] == '-') {
for (size_t i = 1; i < cp.length(); ++i) {
if (!JS7_ISDEC(cp[i]))
return id;
}
return JSID_VOID;
}
return id;
}

View File

@ -1103,7 +1103,7 @@ SuppressDeletedPropertyHelper(JSContext *cx, HandleObject obj, StringPredicate p
if (prop) {
unsigned attrs;
if (obj2->isNative())
attrs = IsImplicitProperty(prop) ? JSPROP_ENUMERATE : prop->attributes();
attrs = GetShapeAttributes(prop);
else if (!JSObject::getGenericAttributes(cx, obj2, id, &attrs))
return false;

View File

@ -631,7 +631,7 @@ DefinePropertyOnObject(JSContext *cx, HandleObject obj, HandleId id, const PropD
shapeHasGetterValue = false,
shapeHasSetterValue = false;
uint8_t shapeAttributes = JSPROP_ENUMERATE;
if (!IsImplicitProperty(shape)) {
if (!IsImplicitDenseElement(shape)) {
shapeDataDescriptor = shape->isDataDescriptor();
shapeAccessorDescriptor = shape->isAccessorDescriptor();
shapeWritable = shape->writable();
@ -672,7 +672,7 @@ DefinePropertyOnObject(JSContext *cx, HandleObject obj, HandleId id, const PropD
* avoid calling a getter; we won't need the value if it's not a
* data descriptor.
*/
if (IsImplicitProperty(shape)) {
if (IsImplicitDenseElement(shape)) {
v = obj->getDenseElement(JSID_TO_INT(id));
} else if (shape->isDataDescriptor()) {
/*
@ -814,8 +814,8 @@ DefinePropertyOnObject(JSContext *cx, HandleObject obj, HandleId id, const PropD
changed |= JSPROP_ENUMERATE;
attrs = (shapeAttributes & ~changed) | (desc.attributes() & changed);
getter = IsImplicitProperty(shape) ? JS_PropertyStub : shape->getter();
setter = IsImplicitProperty(shape) ? JS_StrictPropertyStub : shape->setter();
getter = IsImplicitDenseElement(shape) ? JS_PropertyStub : shape->getter();
setter = IsImplicitDenseElement(shape) ? JS_StrictPropertyStub : shape->setter();
} else if (desc.isDataDescriptor()) {
unsigned unchanged = 0;
if (!desc.hasConfigurable())
@ -3064,7 +3064,7 @@ js::DefineNativeProperty(JSContext *cx, HandleObject obj, HandleId id, HandleVal
if (!baseops::LookupProperty(cx, obj, id, &pobj, &shape))
return false;
if (shape && pobj == obj) {
if (IsImplicitProperty(shape)) {
if (IsImplicitDenseElement(shape)) {
if (!JSObject::sparsifyDenseElement(cx, obj, JSID_TO_INT(id)))
return false;
shape = obj->nativeLookup(cx, id);
@ -3237,7 +3237,7 @@ CallResolveOp(JSContext *cx, HandleObject obj, HandleId id, unsigned flags,
}
if (JSID_IS_INT(id) && objp->containsDenseElement(JSID_TO_INT(id))) {
MarkImplicitPropertyFound(propp);
MarkDenseElementFound(propp);
return true;
}
@ -3263,7 +3263,7 @@ LookupPropertyWithFlagsInline(JSContext *cx, HandleObject obj, HandleId id, unsi
{
if (JSID_IS_INT(id) && current->containsDenseElement(JSID_TO_INT(id))) {
objp.set(current);
MarkImplicitPropertyFound(propp);
MarkDenseElementFound(propp);
return true;
}
@ -3549,7 +3549,7 @@ js_GetPropertyHelperInline(JSContext *cx, HandleObject obj, HandleObject receive
: JSObject::getGeneric(cx, obj2, obj2, id, vp);
}
if (IsImplicitProperty(shape)) {
if (IsImplicitDenseElement(shape)) {
vp.set(obj2->getDenseElement(JSID_TO_INT(id)));
return true;
}
@ -3804,7 +3804,7 @@ baseops::SetPropertyHelper(JSContext *cx, HandleObject obj, HandleObject receive
getter = clasp->getProperty;
setter = clasp->setProperty;
if (IsImplicitProperty(shape)) {
if (IsImplicitDenseElement(shape)) {
/* ES5 8.12.4 [[Put]] step 2, for a dense data property on pobj. */
if (pobj != obj)
shape = NULL;
@ -3877,7 +3877,7 @@ baseops::SetPropertyHelper(JSContext *cx, HandleObject obj, HandleObject receive
}
}
if (IsImplicitProperty(shape)) {
if (IsImplicitDenseElement(shape)) {
JSObject::setDenseElementWithType(cx, obj, JSID_TO_INT(id), vp);
return true;
}
@ -4006,7 +4006,7 @@ baseops::SetAttributes(JSContext *cx, HandleObject obj, HandleId id, unsigned *a
return false;
if (!shape)
return true;
if (nobj->isNative() && IsImplicitProperty(shape)) {
if (nobj->isNative() && IsImplicitDenseElement(shape)) {
if (!JSObject::sparsifyDenseElement(cx, nobj, JSID_TO_INT(id)))
return false;
shape = obj->nativeLookup(cx, id);
@ -4025,7 +4025,7 @@ baseops::SetElementAttributes(JSContext *cx, HandleObject obj, uint32_t index, u
return false;
if (!shape)
return true;
if (nobj->isNative() && IsImplicitProperty(shape)) {
if (nobj->isNative() && IsImplicitDenseElement(shape)) {
if (!JSObject::sparsifyDenseElement(cx, obj, index))
return false;
shape = obj->nativeLookup(cx, INT_TO_JSID(index));
@ -4054,7 +4054,7 @@ baseops::DeleteGeneric(JSContext *cx, HandleObject obj, HandleId id, MutableHand
GCPoke(cx->runtime);
if (IsImplicitProperty(shape)) {
if (IsImplicitDenseElement(shape)) {
if (!CallJSPropertyOp(cx, obj->getClass()->delProperty, obj, id, rval))
return false;
if (rval.isFalse())
@ -4295,7 +4295,7 @@ js::CheckAccess(JSContext *cx, JSObject *obj_, HandleId id, JSAccessMode mode,
*attrsp = GetShapeAttributes(shape);
if (!writing) {
if (IsImplicitProperty(shape)) {
if (IsImplicitDenseElement(shape)) {
vp.set(pobj->getDenseElement(JSID_TO_INT(id)));
} else {
if (shape->hasSlot())

View File

@ -38,9 +38,9 @@
#include "jsstr.h"
#include "ds/Sort.h"
#include "frontend/BytecodeEmitter.h"
#include "frontend/TokenStream.h"
#include "js/CharacterEncoding.h"
#include "vm/Debugger.h"
#include "vm/StringBuffer.h"
@ -6262,10 +6262,11 @@ js::DecompileValueGenerator(JSContext *cx, int spindex, HandleValue v,
return NULL;
}
Rooted<JSStableString *> stable(cx, fallback->ensureStable(cx));
if (!stable)
Rooted<JSLinearString *> linear(cx, fallback->ensureLinear(cx));
if (!linear)
return NULL;
return DeflateString(cx, stable->chars().get(), stable->length());
TwoByteChars tbchars(linear->chars(), linear->length());
return LossyTwoByteCharsToNewLatin1CharsZ(cx, tbchars).c_str();
}
static bool
@ -6352,10 +6353,10 @@ js::DecompileArgument(JSContext *cx, int formalIndex, HandleValue v)
if (!fallback)
return NULL;
Rooted<JSStableString *> stable(cx, fallback->ensureStable(cx));
if (!stable)
Rooted<JSLinearString *> linear(cx, fallback->ensureLinear(cx));
if (!linear)
return NULL;
return DeflateString(cx, stable->chars().get(), stable->length());
return LossyTwoByteCharsToNewLatin1CharsZ(cx, linear->range()).c_str();
}
static char *

View File

@ -17,6 +17,8 @@
#include "jspubtd.h"
#include "jsstr.h"
#include "js/CharacterEncoding.h"
using namespace js;
/*
@ -360,8 +362,8 @@ static int cvt_s(SprintfState *ss, const char *s, int width, int prec,
return fill2(ss, s ? s : "(null)", slen, width, flags);
}
static int cvt_ws(SprintfState *ss, const jschar *ws, int width, int prec,
int flags)
static int
cvt_ws(SprintfState *ss, const jschar *ws, int width, int prec, int flags)
{
int result;
/*
@ -369,12 +371,15 @@ static int cvt_ws(SprintfState *ss, const jschar *ws, int width, int prec,
* and malloc() is used to allocate the buffer buffer.
*/
if (ws) {
int slen = js_strlen(ws);
char *s = DeflateString(NULL, ws, slen);
if (!s)
size_t wslen = js_strlen(ws);
char *latin1 = js_pod_malloc<char>(wslen + 1);
if (!latin1)
return -1; /* JSStuffFunc error indicator. */
result = cvt_s(ss, s, width, prec, flags);
js_free(s);
for (size_t i = 0; i < wslen; ++i)
latin1[i] = (char)ws[i];
latin1[wslen] = '\0';
result = cvt_s(ss, latin1, width, prec, flags);
js_free(latin1);
} else {
result = cvt_s(ss, NULL, width, prec, flags);
}

View File

@ -2551,7 +2551,7 @@ proxy_LookupGeneric(JSContext *cx, HandleObject obj, HandleId id,
return false;
if (found) {
MarkImplicitPropertyFound(propp);
MarkNonNativePropertyFound(propp);
objp.set(obj);
} else {
objp.set(NULL);

View File

@ -27,6 +27,7 @@
#include "frontend/Parser.h"
#include "frontend/TokenStream.h"
#include "js/CharacterEncoding.h"
#include "vm/RegExpObject.h"
#include "jsscriptinlines.h"
@ -3442,7 +3443,8 @@ reflect_parse(JSContext *cx, uint32_t argc, jsval *vp)
if (!chars)
return JS_FALSE;
filename = DeflateString(cx, chars, length);
TwoByteChars tbchars(chars, length);
filename = LossyTwoByteCharsToNewLatin1CharsZ(cx, tbchars).c_str();
if (!filename)
return JS_FALSE;
}

View File

@ -496,17 +496,25 @@ BaseShape::markChildren(JSTracer *trc)
/*
* Property lookup hooks on objects are required to return a non-NULL shape to
* signify that the property has been found. For cases where the property is
* not actually represented by a Shape (dense elements, properties of
* non-native objects), use a dummy value.
* not actually represented by a Shape, use a dummy value. This includes all
* properties of non-native objects, and dense elements for native objects.
* Use separate APIs for these two cases.
*/
static inline void
MarkImplicitPropertyFound(MutableHandleShape propp)
MarkNonNativePropertyFound(MutableHandleShape propp)
{
propp.set(reinterpret_cast<Shape*>(1));
}
static inline void
MarkDenseElementFound(MutableHandleShape propp)
{
propp.set(reinterpret_cast<Shape*>(1));
}
static inline bool
IsImplicitProperty(HandleShape prop)
IsImplicitDenseElement(HandleShape prop)
{
return prop.get() == reinterpret_cast<Shape*>(1);
}
@ -514,7 +522,7 @@ IsImplicitProperty(HandleShape prop)
static inline uint8_t
GetShapeAttributes(HandleShape shape)
{
return IsImplicitProperty(shape) ? JSPROP_ENUMERATE : shape->attributes();
return IsImplicitDenseElement(shape) ? JSPROP_ENUMERATE : shape->attributes();
}
} /* namespace js */

View File

@ -2342,6 +2342,116 @@ BuildDollarReplacement(JSContext *cx, JSString *textstrArg, JSLinearString *reps
return true;
}
struct StringRange
{
size_t start;
size_t length;
StringRange(size_t s, size_t l)
: start(s), length(l)
{ }
};
static JSString *
AppendSubstrings(JSContext *cx, Handle<JSStableString*> stableStr,
const StringRange *ranges, size_t rangesLen)
{
JS_ASSERT(rangesLen);
/* For single substrings, construct a dependent string. */
if (rangesLen == 1)
return js_NewDependentString(cx, stableStr, ranges[0].start, ranges[0].length);
/* Collect substrings into a rope. */
RopeBuilder rope(cx);
for (size_t i = 0; i < rangesLen; i++) {
const StringRange &sr = ranges[i];
RootedString substr(cx, js_NewDependentString(cx, stableStr, sr.start, sr.length));
if (!substr)
return NULL;
/* Appending to the rope permanently roots the substring. */
rope.append(substr);
}
return rope.result();
}
static bool
str_replace_regexp_remove(JSContext *cx, CallArgs args, HandleString str, RegExpShared &re)
{
Rooted<JSStableString*> stableStr(cx, str->ensureStable(cx));
if (!stableStr)
return false;
Vector<StringRange, 16, SystemAllocPolicy> ranges;
StableCharPtr chars = stableStr->chars();
size_t charsLen = stableStr->length();
MatchPair match;
size_t startIndex = 0; /* Index used for iterating through the string. */
size_t lastIndex = 0; /* Index after last successful match. */
size_t lazyIndex = 0; /* Index before last successful match. */
/* Accumulate StringRanges for unmatched substrings. */
while (startIndex <= charsLen) {
if (!JS_CHECK_OPERATION_LIMIT(cx))
return false;
RegExpRunStatus status = re.executeMatchOnly(cx, chars, charsLen, &startIndex, match);
if (status == RegExpRunStatus_Error)
return false;
if (status == RegExpRunStatus_Success_NotFound)
break;
/* Include the latest unmatched substring. */
if (size_t(match.start) > lastIndex) {
if (!ranges.append(StringRange(lastIndex, match.start - lastIndex)))
return false;
}
lazyIndex = lastIndex;
lastIndex = startIndex;
/* Non-global removal executes at most once. */
if (!re.global())
break;
if (match.isEmpty())
startIndex++;
}
/* If unmatched, return the input string. */
if (!lastIndex) {
args.rval().setString(str);
return true;
}
/* The last successful match updates the RegExpStatics. */
cx->regExpStatics()->updateLazily(cx, stableStr, &re, lazyIndex);
/* Include any remaining part of the string. */
if (lastIndex < charsLen) {
if (!ranges.append(StringRange(lastIndex, charsLen - lastIndex)))
return false;
}
/* Handle the empty string before calling .begin(). */
if (ranges.empty()) {
args.rval().setString(cx->runtime->emptyString);
return true;
}
JSString *result = AppendSubstrings(cx, stableStr, ranges.begin(), ranges.length());
if (!result)
return false;
args.rval().setString(result);
return true;
}
static inline bool
str_replace_regexp(JSContext *cx, CallArgs args, ReplaceData &rdata)
{
@ -2354,6 +2464,12 @@ str_replace_regexp(JSContext *cx, CallArgs args, ReplaceData &rdata)
RegExpStatics *res = cx->regExpStatics();
RegExpShared &re = rdata.g.regExp();
/* Optimize removal. */
if (rdata.repstr && rdata.repstr->length() == 0 && !rdata.dollar) {
JS_ASSERT(!rdata.lambda && !rdata.elembase);
return str_replace_regexp_remove(cx, args, rdata.str, re);
}
Value tmp;
if (!DoMatch(cx, res, rdata.str, re, ReplaceRegExpCallback, &rdata, REPLACE_ARGS, &tmp))
return false;
@ -3726,25 +3842,6 @@ js::InflateUTF8String(JSContext *cx, const char *bytes, size_t *lengthp)
return NULL;
}
/*
* May be called with null cx.
*/
char *
js::DeflateString(JSContext *maybecx, const jschar *chars, size_t nchars)
{
AutoAssertNoGC nogc;
size_t nbytes = nchars;
char *bytes = maybecx
? maybecx->pod_malloc<char>(nbytes + 1)
: js_pod_malloc<char>(nbytes + 1);
if (!bytes)
return NULL;
for (size_t i = 0; i < nbytes; i++)
bytes[i] = (char) chars[i];
bytes[nbytes] = 0;
return bytes;
}
size_t
js::GetDeflatedStringLength(JSContext *cx, const jschar *chars, size_t nchars)
{

View File

@ -224,9 +224,6 @@ InflateString(JSContext *cx, const char *bytes, size_t *length);
extern jschar *
InflateUTF8String(JSContext *cx, const char *bytes, size_t *length);
extern char *
DeflateString(JSContext *cx, const jschar *chars, size_t length);
/*
* Inflate bytes to JS chars in an existing buffer. 'chars' must be large
* enough for 'length' jschars. The buffer is NOT null-terminated.

View File

@ -1015,7 +1015,7 @@ TypedArray::obj_lookupGeneric(JSContext *cx, HandleObject tarray, HandleId id,
JS_ASSERT(tarray->isTypedArray());
if (isArrayIndex(tarray, id)) {
MarkImplicitPropertyFound(propp);
MarkNonNativePropertyFound(propp);
objp.set(tarray);
return true;
}
@ -1045,7 +1045,7 @@ TypedArray::obj_lookupElement(JSContext *cx, HandleObject tarray, uint32_t index
JS_ASSERT(tarray->isTypedArray());
if (index < length(tarray)) {
MarkImplicitPropertyFound(propp);
MarkNonNativePropertyFound(propp);
objp.set(tarray);
return true;
}

View File

@ -5086,6 +5086,7 @@ mjit::Compiler::jsop_getprop(HandlePropertyName name, JSValueType knownType,
* must fit in an int32_t.
*/
if (!types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY)) {
frame.forgetMismatchedObject(top);
bool isObject = top->isTypeKnown();
if (!isObject) {
Jump notObject = frame.testObject(Assembler::NotEqual, top);
@ -7593,6 +7594,7 @@ mjit::Compiler::jsop_in()
!types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_DENSE_ARRAY) &&
!types::ArrayPrototypeHasIndexedProperty(cx, outerScript))
{
frame.forgetMismatchedObject(obj);
bool isPacked = !types->hasObjectFlags(cx, types::OBJECT_FLAG_NON_PACKED_ARRAY);
if (!obj->isTypeKnown()) {

View File

@ -605,6 +605,9 @@ CompileStatus
mjit::Compiler::compileArrayConcat(types::TypeSet *thisTypes, types::TypeSet *argTypes,
FrameEntry *thisValue, FrameEntry *argValue)
{
frame.forgetMismatchedObject(thisValue);
frame.forgetMismatchedObject(argValue);
/*
* Require the 'this' types to have a specific type matching the current
* global, so we can create the result object inline.

View File

@ -20,6 +20,8 @@
#include "jsinterpinlines.h"
#include "jsautooplen.h"
#include "js/CharacterEncoding.h"
#include "vm/ScopeObject-inl.h"
#include "vm/StringObject-inl.h"
@ -2409,12 +2411,12 @@ GetElementIC::attachGetProp(VMFrame &f, HandleObject obj, HandleValue v, HandleP
CodeLocationLabel cs = buffer.finalize(f);
#if DEBUG
char *chars = DeflateString(cx, v.toString()->getChars(cx), v.toString()->length());
Latin1CharsZ latin1 = LossyTwoByteCharsToNewLatin1CharsZ(cx, v.toString()->ensureLinear(cx)->range());
JaegerSpew(JSpew_PICs, "generated %s stub at %p for atom %p (\"%s\") shape %p (%s: %d)\n",
js_CodeName[JSOp(*f.pc())], cs.executableAddress(), (void*)name, chars,
js_CodeName[JSOp(*f.pc())], cs.executableAddress(), (void*)name, latin1.get(),
(void*)holder->lastProperty(), cx->fp()->script()->filename,
CurrentLine(cx));
js_free(chars);
JS_free(latin1);
#endif
// Update the inline guards, if needed.

View File

@ -2440,47 +2440,6 @@ ToInt32(JSContext *cx, unsigned argc, jsval *vp)
return true;
}
static const char* badUTF8 = "...\xC0...";
static const char* bigUTF8 = "...\xFB\xBF\xBF\xBF\xBF...";
static const jschar badSurrogate[] = { 'A', 'B', 'C', 0xDEEE, 'D', 'E', 0 };
static JSBool
TestUTF8(JSContext *cx, unsigned argc, jsval *vp)
{
int32_t mode = 1;
jschar chars[20];
size_t charsLength = 5;
char bytes[20];
size_t bytesLength = 20;
if (argc && !JS_ValueToInt32(cx, *JS_ARGV(cx, vp), &mode))
return false;
/* The following throw errors if compiled with UTF-8. */
switch (mode) {
/* mode 1: malformed UTF-8 string. */
case 1:
JS_NewStringCopyZ(cx, badUTF8);
break;
/* mode 2: big UTF-8 character. */
case 2:
JS_NewStringCopyZ(cx, bigUTF8);
break;
/* mode 3: bad surrogate character. */
case 3:
DeflateStringToBuffer(cx, badSurrogate, 6, bytes, &bytesLength);
break;
/* mode 4: use a too small buffer. */
case 4:
JS_DecodeBytes(cx, "1234567890", 10, chars, &charsLength);
break;
default:
JS_ReportError(cx, "invalid mode parameter");
return false;
}
JS_SET_RVAL(cx, vp, JSVAL_VOID);
return !JS_IsExceptionPending (cx);
}
static JSBool
ThrowError(JSContext *cx, unsigned argc, jsval *vp)
{
@ -3740,10 +3699,6 @@ static JSFunctionSpecWithHelp shell_functions[] = {
"pc2line(fun[, pc])",
" Map PC to line number."),
JS_FN_HELP("testUTF8", TestUTF8, 1, 0,
"testUTF8(mode)",
" Perform UTF-8 tests (modes are 1 to 4)."),
JS_FN_HELP("throwError", ThrowError, 0, 0,
"throwError()",
" Throw an error from JS_ReportError."),

View File

@ -1,122 +0,0 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* 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/. */
//-----------------------------------------------------------------------------
var BUGNUMBER = 232182;
var summary = 'Display non-ascii characters in JS exceptions';
var actual = '';
var expect = 'no error';
printBugNumber(BUGNUMBER);
printStatus (summary);
/*
* This test accesses an undefined Unicode symbol. If the code has not been
* compiled with JS_C_STRINGS_ARE_UTF8, the thrown error truncates Unicode
* characters to bytes. Accessing \u0440\u0441, therefore, results in a
* message talking about an undefined variable 'AB' (\x41\x42).
*/
var utf8Enabled = false;
try
{
\u0441\u0442;
}
catch (e)
{
utf8Enabled = (e.message.charAt (0) == '\u0441');
}
// Run the tests only if UTF-8 is enabled
printStatus('UTF-8 is ' + (utf8Enabled?'':'not ') + 'enabled');
if (!utf8Enabled)
{
reportCompare('Not run', 'Not run', 'utf8 is not enabled');
}
else
{
status = summary + ': Throw Error with Unicode message';
expect = 'test \u0440\u0441';
try
{
throw Error (expect);
}
catch (e)
{
actual = e.message;
}
reportCompare(expect, actual, status);
var inShell = (typeof stringsAreUTF8 == "function");
if (!inShell)
{
inShell = (typeof stringsAreUtf8 == "function");
if (inShell)
{
this.stringsAreUTF8 = stringsAreUtf8;
this.testUTF8 = testUtf8;
}
}
if (inShell && stringsAreUTF8())
{
status = summary + ': UTF-8 test: bad UTF-08 sequence';
expect = 'Error';
actual = 'No error!';
try
{
testUTF8(1);
}
catch (e)
{
actual = 'Error';
}
reportCompare(expect, actual, status);
status = summary + ': UTF-8 character too big to fit into Unicode surrogate pairs';
expect = 'Error';
actual = 'No error!';
try
{
testUTF8(2);
}
catch (e)
{
actual = 'Error';
}
reportCompare(expect, actual, status);
status = summary + ': bad Unicode surrogate character';
expect = 'Error';
actual = 'No error!';
try
{
testUTF8(3);
}
catch (e)
{
actual = 'Error';
}
reportCompare(expect, actual, status);
}
if (inShell)
{
status = summary + ': conversion target buffer overrun';
expect = 'Error';
actual = 'No error!';
try
{
testUTF8(4);
}
catch (e)
{
actual = 'Error';
}
reportCompare(expect, actual, status);
}
}

View File

@ -0,0 +1,28 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sw=4 et tw=78:
*
* 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 "jscntxt.h"
#include "js/CharacterEncoding.h"
using namespace JS;
Latin1CharsZ
JS::LossyTwoByteCharsToNewLatin1CharsZ(JSContext *cx, TwoByteChars tbchars)
{
AutoAssertNoGC nogc;
JS_ASSERT(cx);
size_t len = tbchars.length();
unsigned char *latin1 = cx->pod_malloc<unsigned char>(len + 1);
if (!latin1)
return Latin1CharsZ();
for (size_t i = 0; i < len; ++i)
latin1[i] = static_cast<unsigned char>(tbchars[i]);
latin1[len] = '\0';
return Latin1CharsZ(latin1, len);
}

View File

@ -405,12 +405,6 @@ RegExpShared::~RegExpShared()
js_delete<BytecodePattern>(bytecode);
}
void
RegExpShared::trace(JSTracer *trc)
{
MarkStringUnbarriered(trc, &source, "regexpshared source");
}
void
RegExpShared::reportYarrError(JSContext *cx, TokenStream *ts, ErrorCode error)
{
@ -651,6 +645,18 @@ RegExpCompartment::RegExpCompartment(JSRuntime *rt)
RegExpCompartment::~RegExpCompartment()
{
JS_ASSERT(map_.empty());
/*
* RegExpStatics may have prevented a single RegExpShared from
* being collected during RegExpCompartment::sweep().
*/
if (!inUse_.empty()) {
PendingSet::Enum e(inUse_);
RegExpShared *shared = e.front();
JS_ASSERT(shared->activeUseCount == 0);
js_delete(shared);
e.removeFront();
}
JS_ASSERT(inUse_.empty());
}

View File

@ -14,6 +14,8 @@
#include "jscntxt.h"
#include "jsobj.h"
#include "gc/Barrier.h"
#include "gc/Marking.h"
#include "js/TemplateLib.h"
#include "vm/MatchPairs.h"
@ -120,11 +122,12 @@ class RegExpShared
#endif
/*
* Source to the RegExp. The RegExpShared must either be protected by a
* RegExpGuard, which handles rooting for stacky RegExpShareds,
* or trace() must be explicitly called during marking.
* Source to the RegExp, for lazy compilation.
* The source must be rooted while activeUseCount is non-zero
* via RegExpGuard, RegExpHeapGuard, or explicit calls to trace().
*/
JSAtom * source;
RegExpFlag flags;
unsigned parenCount;
@ -149,7 +152,10 @@ class RegExpShared
RegExpShared(JSRuntime *rt, JSAtom *source, RegExpFlag flags);
~RegExpShared();
void trace(JSTracer *trc);
/* Explicit trace function for use by the RegExpStatics and JITs. */
void trace(JSTracer *trc) {
MarkStringUnbarriered(trc, &source, "regexpshared source");
}
/* Static functions to expose some Yarr logic. */
static inline bool isJITRuntimeEnabled(JSContext *cx);
@ -222,17 +228,58 @@ class RegExpGuard
re_->incRef();
}
~RegExpGuard() {
if (re_)
re_->decRef();
}
~RegExpGuard() { release(); }
public:
void init(RegExpShared &re) {
JS_ASSERT(!re_);
JS_ASSERT(!initialized());
re_ = &re;
re_->incRef();
source_ = re.source;
source_ = re_->source;
}
void release() {
if (re_) {
re_->decRef();
re_ = NULL;
source_ = NULL;
}
}
bool initialized() const { return !!re_; }
RegExpShared *re() const { JS_ASSERT(initialized()); return re_; }
RegExpShared *operator->() { return re(); }
RegExpShared &operator*() { return *re(); }
};
/* Equivalent of RegExpGuard, heap-allocated, with explicit tracing. */
class RegExpHeapGuard
{
RegExpShared *re_;
RegExpHeapGuard(const RegExpGuard &) MOZ_DELETE;
void operator=(const RegExpHeapGuard &) MOZ_DELETE;
public:
RegExpHeapGuard() : re_(NULL) { }
RegExpHeapGuard(RegExpShared &re) { init(re); }
~RegExpHeapGuard() { release(); }
public:
void init(RegExpShared &re) {
JS_ASSERT(!initialized());
re_ = &re;
re_->incRef();
}
void release() {
if (re_) {
re_->decRef();
re_ = NULL;
}
}
void trace(JSTracer *trc) {
if (initialized())
re_->trace(trc);
}
bool initialized() const { return !!re_; }
@ -246,9 +293,12 @@ class RegExpCompartment
struct Key {
JSAtom *atom;
uint16_t flag;
Key() {}
Key(JSAtom *atom, RegExpFlag flag)
: atom(atom), flag(flag) {}
: atom(atom), flag(flag)
{ }
typedef Key Lookup;
static HashNumber hash(const Lookup &l) {
return DefaultHasher<JSAtom *>::hash(l.atom) ^ (l.flag << 1);

View File

@ -27,15 +27,6 @@ SizeOfRegExpStaticsData(const JSObject *obj, JSMallocSizeOfFun mallocSizeOf)
return mallocSizeOf(obj->getPrivate());
}
inline
RegExpStatics::RegExpStatics()
: pendingLazyEvaluation(false),
bufferLink(NULL),
copied(false)
{
clear();
}
inline bool
RegExpStatics::createDependent(JSContext *cx, size_t start, size_t end, Value *out)
{
@ -231,15 +222,20 @@ RegExpStatics::copyTo(RegExpStatics &dst)
if (!pendingLazyEvaluation)
dst.matches.initArrayFrom(matches);
if (regexp.initialized())
dst.regexp.init(*regexp);
else
dst.regexp.release();
dst.matchesInput = matchesInput;
dst.regexp = regexp;
dst.lastIndex = lastIndex;
dst.pendingInput = pendingInput;
dst.flags = flags;
dst.pendingLazyEvaluation = pendingLazyEvaluation;
JS_ASSERT_IF(pendingLazyEvaluation, regexp);
JS_ASSERT_IF(pendingLazyEvaluation, regexp.initialized());
JS_ASSERT_IF(pendingLazyEvaluation, matchesInput);
JS_ASSERT(regexp.initialized() == dst.regexp.initialized());
}
inline void
@ -261,17 +257,20 @@ RegExpStatics::restore()
inline void
RegExpStatics::updateLazily(JSContext *cx, JSLinearString *input,
RegExpObject *regexp, size_t lastIndex)
RegExpShared *shared, size_t lastIndex)
{
JS_ASSERT(input && regexp);
JS_ASSERT(input && shared);
aboutToWrite();
BarrieredSetPair<JSString, JSLinearString>(cx->compartment,
pendingInput, input,
matchesInput, input);
pendingLazyEvaluation = true;
this->regexp = regexp;
if (regexp.initialized())
regexp.release();
regexp.init(*shared);
this->lastIndex = lastIndex;
pendingLazyEvaluation = true;
}
inline bool
@ -282,7 +281,7 @@ RegExpStatics::updateFromMatchPairs(JSContext *cx, JSLinearString *input, MatchP
/* Unset all lazy state. */
pendingLazyEvaluation = false;
this->regexp = NULL;
this->regexp.release();
this->lastIndex = size_t(-1);
BarrieredSetPair<JSString, JSLinearString>(cx->compartment,
@ -301,11 +300,14 @@ inline void
RegExpStatics::clear()
{
aboutToWrite();
flags = RegExpFlag(0);
pendingInput = NULL;
pendingLazyEvaluation = false;
matchesInput = NULL;
matches.forgetArray();
matchesInput = NULL;
regexp.release();
lastIndex = size_t(-1);
pendingInput = NULL;
flags = RegExpFlag(0);
pendingLazyEvaluation = false;
}
inline void
@ -363,8 +365,9 @@ RegExpStatics::checkInvariants()
{
#ifdef DEBUG
if (pendingLazyEvaluation) {
JS_ASSERT(regexp);
JS_ASSERT(regexp.initialized());
JS_ASSERT(pendingInput);
JS_ASSERT(lastIndex != size_t(-1));
return;
}

View File

@ -74,7 +74,7 @@ RegExpStatics::executeLazy(JSContext *cx)
if (!pendingLazyEvaluation)
return true;
JS_ASSERT(regexp);
JS_ASSERT(regexp.initialized());
JS_ASSERT(matchesInput);
JS_ASSERT(lastIndex != size_t(-1));
@ -87,17 +87,20 @@ RegExpStatics::executeLazy(JSContext *cx)
StableCharPtr chars(matchesInput->chars(), length);
/* Execute the full regular expression. */
RegExpGuard shared(cx);
if (!regexp->getShared(cx, &shared))
return false;
RegExpRunStatus status = shared->execute(cx, chars, length, &this->lastIndex, this->matches);
RegExpRunStatus status = regexp->execute(cx, chars, length, &this->lastIndex, this->matches);
if (status == RegExpRunStatus_Error)
return false;
/*
* RegExpStatics are only updated on successful (matching) execution.
* Re-running the same expression must therefore produce a matching result.
*/
JS_ASSERT(status == RegExpRunStatus_Success);
/* Unset lazy state and remove rooted values that now have no use. */
pendingLazyEvaluation = false;
regexp = NULL;
regexp.release();
lastIndex = size_t(-1);
return true;
}

View File

@ -17,6 +17,7 @@
#include "js/Vector.h"
#include "vm/MatchPairs.h"
#include "vm/RegExpObject.h"
namespace js {
@ -27,7 +28,7 @@ class RegExpStatics
HeapPtr<JSLinearString> matchesInput;
/* The previous RegExp input, used to resolve lazy state. */
HeapPtr<RegExpObject> regexp;
RegExpHeapGuard regexp;
size_t lastIndex;
/* The latest RegExp input, set before execution. */
@ -44,6 +45,10 @@ class RegExpStatics
RegExpStatics *bufferLink;
bool copied;
public:
RegExpStatics() : bufferLink(NULL), copied(false) { clear(); }
static JSObject *create(JSContext *cx, GlobalObject *parent);
private:
bool executeLazy(JSContext *cx);
@ -80,14 +85,9 @@ class RegExpStatics
friend class PreserveRegExpStatics;
public:
inline RegExpStatics();
static JSObject *create(JSContext *cx, GlobalObject *parent);
/* Mutators. */
inline void updateLazily(JSContext *cx, JSLinearString *input,
RegExpObject *regexp, size_t lastIndex);
RegExpShared *shared, size_t lastIndex);
inline bool updateFromMatchPairs(JSContext *cx, JSLinearString *input, MatchPairs &newPairs);
inline void setMultiline(JSContext *cx, bool enabled);
@ -120,12 +120,16 @@ class RegExpStatics
}
void mark(JSTracer *trc) {
if (regexp)
gc::MarkObject(trc, &regexp, "res->regexp");
/*
* Changes to this function must also be reflected in
* RegExpStatics::AutoRooter::trace().
*/
if (pendingInput)
MarkString(trc, &pendingInput, "res->pendingInput");
if (matchesInput)
MarkString(trc, &matchesInput, "res->matchesInput");
if (regexp.initialized())
regexp->trace(trc);
}
/* Value creators. */

View File

@ -11,6 +11,8 @@
#include "mozilla/Attributes.h"
#include "mozilla/GuardObjects.h"
#include "js/CharacterEncoding.h"
#include "jsapi.h"
#include "jsatom.h"
#include "jsfriendapi.h"
@ -477,6 +479,11 @@ class JSLinearString : public JSString
JS_ASSERT(JSString::isLinear());
return d.u1.chars;
}
JS::TwoByteChars range() const {
JS_ASSERT(JSString::isLinear());
return JS::TwoByteChars(d.u1.chars, length());
}
};
JS_STATIC_ASSERT(sizeof(JSLinearString) == sizeof(JSString));

View File

@ -575,7 +575,7 @@ XPCConvert::JSData2Native(JSContext* cx, void* d, jsval s,
if (!buffer) {
return false;
}
JS_EncodeStringToBuffer(str, buffer, length);
JS_EncodeStringToBuffer(cx, str, buffer, length);
buffer[length] = '\0';
*((void**)d) = buffer;
return true;
@ -701,7 +701,7 @@ XPCConvert::JSData2Native(JSContext* cx, void* d, jsval s,
if (rs->Length() != uint32_t(length)) {
return false;
}
JS_EncodeStringToBuffer(str, rs->BeginWriting(), length);
JS_EncodeStringToBuffer(cx, str, rs->BeginWriting(), length);
return true;
}
@ -1875,7 +1875,7 @@ XPCConvert::JSStringWithSize2Native(XPCCallContext& ccx, void* d, jsval s,
if (!buffer) {
return false;
}
JS_EncodeStringToBuffer(str, buffer, len);
JS_EncodeStringToBuffer(cx, str, buffer, len);
buffer[len] = '\0';
*((char**)d) = buffer;

View File

@ -122,7 +122,7 @@ XPCJSStackFrame::CreateStack(JSContext* cx, XPCJSStackFrame** stack)
if (length != size_t(-1)) {
self->mFunname = static_cast<char *>(nsMemory::Alloc(length + 1));
if (self->mFunname) {
JS_EncodeStringToBuffer(funid, self->mFunname, length);
JS_EncodeStringToBuffer(cx, funid, self->mFunname, length);
self->mFunname[length] = '\0';
}
}

View File

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta charset="utf-8" />
<title></title>
<script type="text/javascript">
function paintCanvas() {
var elem = document.getElementById("mycanv");
var ctx = elem.getContext('2d');
ctx.fillStyle = 'white';
ctx.fillRect(0, 0, 200, 200);
ctx.beginPath();
ctx.arc(150, 150, 100, 0, Math.PI * 2, true);
ctx.closePath();
ctx.clip();
// create radial gradient
var grd = ctx.createRadialGradient(110, 110, 42, 110, 110, 121);
grd.addColorStop(0, '#FFFFFF');
grd.addColorStop(1, '#E5E5E5');
ctx.fillStyle = grd;
// This should be completely clipped out!
ctx.fillRect(0, 0, 1, 1);
}
</script>
</head>
<body onload="paintCanvas();">
<canvas width=200 height=200 moz-opaque="true" id="mycanv"></canvas>
</body>
</html>

View File

@ -1740,3 +1740,4 @@ skip-if(B2G) == 814952-1.html 814952-1-ref.html
skip-if(B2G) == 818276-1.html 818276-1-ref.html
== 827577-1a.html 827577-1-ref.html
== 827577-1b.html 827577-1-ref.html
== 817019-1.html about:blank

View File

@ -2,5 +2,4 @@ This source is from the Speex library (http://git.xiph.org/speex.git/), from
commit a6d05eb5.
It consists in the audio resampling code (resampler.c) and its header files
dependancies. No changes have been made to those files, imported in the tree
using the update.sh script.
dependancies, imported into the tree using the update.sh script.

View File

@ -960,13 +960,15 @@ EXPORT int speex_resampler_process_interleaved_float(SpeexResamplerState *st, co
{
spx_uint32_t i;
int istride_save, ostride_save;
spx_uint32_t bak_len = *out_len;
spx_uint32_t bak_out_len = *out_len;
spx_uint32_t bak_in_len = *in_len;
istride_save = st->in_stride;
ostride_save = st->out_stride;
st->in_stride = st->out_stride = st->nb_channels;
for (i=0;i<st->nb_channels;i++)
{
*out_len = bak_len;
*out_len = bak_out_len;
*in_len = bak_in_len;
if (in != NULL)
speex_resampler_process_float(st, i, in+i, in_len, out+i, out_len);
else
@ -981,13 +983,15 @@ EXPORT int speex_resampler_process_interleaved_int(SpeexResamplerState *st, cons
{
spx_uint32_t i;
int istride_save, ostride_save;
spx_uint32_t bak_len = *out_len;
spx_uint32_t bak_out_len = *out_len;
spx_uint32_t bak_in_len = *in_len;
istride_save = st->in_stride;
ostride_save = st->out_stride;
st->in_stride = st->out_stride = st->nb_channels;
for (i=0;i<st->nb_channels;i++)
{
*out_len = bak_len;
*out_len = bak_out_len;
*in_len = bak_in_len;
if (in != NULL)
speex_resampler_process_int(st, i, in+i, in_len, out+i, out_len);
else

View File

@ -0,0 +1,54 @@
From 5adadc5626ee2d5d3a3ca21e70fd195b9d002a0b Mon Sep 17 00:00:00 2001
From: Jean-Marc Valin <jmvalin@jmvalin.ca>
Date: Wed, 1 Aug 2012 13:19:38 -0400
Subject: [PATCH] Properly save in_len for multiple channels in the resampler.
This fixes issues with clicking in one channel and/or truncation
with some unusual sample rates.
---
src/resample.c | 12 ++++++++----
1 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/src/resample.c b/src/resample.c
index 84aaf59..6e92bd0 100644
--- a/src/resample.c
+++ b/src/resample.c
@@ -966,13 +966,15 @@ SPX_RESAMPLE_EXPORT int speex_resampler_process_interleaved_float(SpeexResampler
{
spx_uint32_t i;
int istride_save, ostride_save;
- spx_uint32_t bak_len = *out_len;
+ spx_uint32_t bak_out_len = *out_len;
+ spx_uint32_t bak_in_len = *in_len;
istride_save = st->in_stride;
ostride_save = st->out_stride;
st->in_stride = st->out_stride = st->nb_channels;
for (i=0;i<st->nb_channels;i++)
{
- *out_len = bak_len;
+ *out_len = bak_out_len;
+ *in_len = bak_in_len;
if (in != NULL)
speex_resampler_process_float(st, i, in+i, in_len, out+i, out_len);
else
@@ -987,13 +989,15 @@ SPX_RESAMPLE_EXPORT int speex_resampler_process_interleaved_int(SpeexResamplerSt
{
spx_uint32_t i;
int istride_save, ostride_save;
- spx_uint32_t bak_len = *out_len;
+ spx_uint32_t bak_out_len = *out_len;
+ spx_uint32_t bak_in_len = *in_len;
istride_save = st->in_stride;
ostride_save = st->out_stride;
st->in_stride = st->out_stride = st->nb_channels;
for (i=0;i<st->nb_channels;i++)
{
- *out_len = bak_len;
+ *out_len = bak_out_len;
+ *in_len = bak_in_len;
if (in != NULL)
speex_resampler_process_int(st, i, in+i, in_len, out+i, out_len);
else
--
1.7.2.5

View File

@ -6,6 +6,7 @@
#
# Copies the needed files from a directory containing the original
# libspeex sources that we need for HTML5 media playback rate change.
cp $1/libspeex/resample.c src
cp $1/libspeex/arch.h src
cp $1/libspeex/stack_alloc.h src
@ -15,3 +16,6 @@ cp $1/include/speex/speex_types.h src
sed -e 's/unsigned @SIZE16@/uint16_t/g' -e 's/unsigned @SIZE32@/uint32_t/g' -e 's/@SIZE16@/int16_t/g' -e 's/@SIZE32@/int32_t/g' < $1/include/speex/speex_config_types.h.in > src/speex_config_types.h
cp $1/AUTHORS .
cp $1/COPYING .
# apply outstanding local patches
patch -p1 < truncation.patch

View File

@ -41,10 +41,14 @@ public:
if (!observerService)
return;
nsresult rv = observerService->AddObserver(this,
NS_XPCOM_SHUTDOWN_OBSERVER_ID,
false);
MOZ_ASSERT(rv == NS_OK);
nsresult rv = NS_OK;
#ifdef MOZILLA_INTERNAL_API
rv = observerService->AddObserver(this,
NS_XPCOM_SHUTDOWN_OBSERVER_ID,
false);
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(rv));
#endif
(void) rv;
}

View File

@ -222,7 +222,9 @@ PeerConnectionImpl::PeerConnectionImpl()
, mIdentity(NULL)
, mSTSThread(NULL)
, mMedia(new PeerConnectionMedia(this)) {
#ifdef MOZILLA_INTERNAL_API
MOZ_ASSERT(NS_IsMainThread());
#endif
}
PeerConnectionImpl::~PeerConnectionImpl()
@ -288,10 +290,13 @@ NS_IMETHODIMP
PeerConnectionImpl::Initialize(IPeerConnectionObserver* aObserver,
nsIDOMWindow* aWindow,
nsIThread* aThread) {
#ifdef MOZILLA_INTERNAL_API
MOZ_ASSERT(NS_IsMainThread());
#endif
MOZ_ASSERT(aObserver);
MOZ_ASSERT(aThread);
mPCObserver = aObserver;
mPCObserver = do_GetWeakReference(aObserver);
nsresult res;
@ -521,8 +526,12 @@ PeerConnectionImpl::NotifyConnection()
CSFLogDebugS(logTag, __FUNCTION__);
#ifdef MOZILLA_INTERNAL_API
nsCOMPtr<IPeerConnectionObserver> pco = do_QueryReferent(mPCObserver);
if (!pco) {
return;
}
RUN_ON_THREAD(mThread,
WrapRunnable(mPCObserver,
WrapRunnable(pco,
&IPeerConnectionObserver::NotifyConnection),
NS_DISPATCH_NORMAL);
#endif
@ -536,10 +545,13 @@ PeerConnectionImpl::NotifyClosedConnection()
CSFLogDebugS(logTag, __FUNCTION__);
#ifdef MOZILLA_INTERNAL_API
nsCOMPtr<IPeerConnectionObserver> pco = do_QueryReferent(mPCObserver);
if (!pco) {
return;
}
RUN_ON_THREAD(mThread,
WrapRunnable(mPCObserver,
&IPeerConnectionObserver::NotifyClosedConnection),
NS_DISPATCH_NORMAL);
WrapRunnable(pco, &IPeerConnectionObserver::NotifyClosedConnection),
NS_DISPATCH_NORMAL);
#endif
}
@ -565,15 +577,20 @@ PeerConnectionImpl::NotifyDataChannel(already_AddRefed<mozilla::DataChannel> aCh
CSFLogDebugS(logTag, __FUNCTION__ << ": channel: " << static_cast<void*>(aChannel.get()));
#ifdef MOZILLA_INTERNAL_API
nsCOMPtr<nsIDOMDataChannel> domchannel;
nsresult rv = NS_NewDOMDataChannel(aChannel, mWindow,
getter_AddRefs(domchannel));
nsCOMPtr<nsIDOMDataChannel> domchannel;
nsresult rv = NS_NewDOMDataChannel(aChannel, mWindow,
getter_AddRefs(domchannel));
NS_ENSURE_SUCCESS_VOID(rv);
nsCOMPtr<IPeerConnectionObserver> pco = do_QueryReferent(mPCObserver);
if (!pco) {
return;
}
RUN_ON_THREAD(mThread,
WrapRunnableNM(NotifyDataChannel_m,
domchannel.get(),
mPCObserver),
pco),
NS_DISPATCH_NORMAL);
#endif
}
@ -996,16 +1013,20 @@ PeerConnectionImpl::onCallEvent(ccapi_call_event_e aCallEvent,
break;
}
if (mPCObserver) {
PeerConnectionObserverDispatch* runnable =
new PeerConnectionObserverDispatch(aInfo, this, mPCObserver);
if (mThread) {
mThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
return;
}
runnable->Run();
nsCOMPtr<IPeerConnectionObserver> pco = do_QueryReferent(mPCObserver);
if (!pco) {
return;
}
PeerConnectionObserverDispatch* runnable =
new PeerConnectionObserverDispatch(aInfo, this, pco);
if (mThread) {
mThread->Dispatch(runnable, NS_DISPATCH_NORMAL);
return;
}
runnable->Run();
delete runnable;
}
void
@ -1016,7 +1037,11 @@ PeerConnectionImpl::ChangeReadyState(PeerConnectionImpl::ReadyState aReadyState)
// Note that we are passing an nsRefPtr<IPeerConnectionObserver> which
// keeps the observer live.
RUN_ON_THREAD(mThread, WrapRunnable(mPCObserver,
nsCOMPtr<IPeerConnectionObserver> pco = do_QueryReferent(mPCObserver);
if (!pco) {
return;
}
RUN_ON_THREAD(mThread, WrapRunnable(pco,
&IPeerConnectionObserver::OnStateChange,
// static_cast needed to work around old Android NDK r5c compiler
static_cast<int>(IPeerConnectionObserver::kReadyState)),
@ -1070,14 +1095,16 @@ PeerConnectionImpl::IceGatheringCompleted_m(NrIceCtx *aCtx)
mIceState = kIceWaiting;
#ifdef MOZILLA_INTERNAL_API
if (mPCObserver) {
RUN_ON_THREAD(mThread,
WrapRunnable(mPCObserver,
&IPeerConnectionObserver::OnStateChange,
// static_cast required to work around old C++ compiler on Android NDK r5c
static_cast<int>(IPeerConnectionObserver::kIceState)),
NS_DISPATCH_NORMAL);
nsCOMPtr<IPeerConnectionObserver> pco = do_QueryReferent(mPCObserver);
if (!pco) {
return NS_OK;
}
RUN_ON_THREAD(mThread,
WrapRunnable(pco,
&IPeerConnectionObserver::OnStateChange,
// static_cast required to work around old C++ compiler on Android NDK r5c
static_cast<int>(IPeerConnectionObserver::kIceState)),
NS_DISPATCH_NORMAL);
#endif
return NS_OK;
}
@ -1105,14 +1132,16 @@ PeerConnectionImpl::IceCompleted_m(NrIceCtx *aCtx)
mIceState = kIceConnected;
#ifdef MOZILLA_INTERNAL_API
if (mPCObserver) {
RUN_ON_THREAD(mThread,
WrapRunnable(mPCObserver,
&IPeerConnectionObserver::OnStateChange,
// static_cast required to work around old C++ compiler on Android NDK r5c
static_cast<int>(IPeerConnectionObserver::kIceState)),
NS_DISPATCH_NORMAL);
nsCOMPtr<IPeerConnectionObserver> pco = do_QueryReferent(mPCObserver);
if (!pco) {
return NS_OK;
}
RUN_ON_THREAD(mThread,
WrapRunnable(pco,
&IPeerConnectionObserver::OnStateChange,
// static_cast required to work around old C++ compiler on Android NDK r5c
static_cast<int>(IPeerConnectionObserver::kIceState)),
NS_DISPATCH_NORMAL);
#endif
return NS_OK;
}

View File

@ -12,6 +12,8 @@
#include "prlock.h"
#include "mozilla/RefPtr.h"
#include "nsWeakPtr.h"
#include "nsIWeakReferenceUtils.h" // for the definition of nsWeakPtr
#include "IPeerConnection.h"
#include "nsComponentManagerUtils.h"
#include "nsPIDOMWindow.h"
@ -230,7 +232,9 @@ private:
IceState mIceState;
nsCOMPtr<nsIThread> mThread;
nsCOMPtr<IPeerConnectionObserver> mPCObserver;
// Weak pointer to IPeerConnectionObserver
// This is only safe to use on the main thread
nsWeakPtr mPCObserver;
nsCOMPtr<nsPIDOMWindow> mWindow;
// The SDP sent in from JS - here for debugging.

View File

@ -1779,6 +1779,8 @@ gsmsdp_get_remote_sdp_direction (fsmdef_dcb_t *dcb_p, uint16_t level,
cc_sdp_t *sdp_p = dcb_p->sdp;
uint16_t media_attr;
uint16_t i;
uint32 port;
int sdpmode = 0;
static const sdp_attr_e dir_attr_array[] = {
SDP_ATTR_INACTIVE,
SDP_ATTR_RECVONLY,
@ -1791,6 +1793,8 @@ gsmsdp_get_remote_sdp_direction (fsmdef_dcb_t *dcb_p, uint16_t level,
return direction;
}
config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
media_attr = 0; /* media level attr. count */
/*
* Now check for direction as a media attribute. If found, the
@ -1842,6 +1846,17 @@ gsmsdp_get_remote_sdp_direction (fsmdef_dcb_t *dcb_p, uint16_t level,
if (dest_addr->type == CPR_IP_ADDR_IPV4 &&
dest_addr->u.ip4 == 0) {
/*
* For WebRTC, we allow active media sections with IP=0.0.0.0, iff
* port != 0. This is to allow interop with existing Trickle ICE
* implementations. TODO: This may need to be updated to match the
* spec once the Trickle ICE spec is finalized.
*/
port = sdp_get_media_portnum(sdp_p->dest_sdp, level);
if (sdpmode && port != 0) {
return direction;
}
direction = SDP_DIRECTION_INACTIVE;
} else {

View File

@ -133,6 +133,7 @@ LOCAL_INCLUDES += \
-I$(topsrcdir)/media/webrtc/signaling/src/peerconnection \
-I$(topsrcdir)/media/webrtc/signaling/media-conduit\
-I$(topsrcdir)/media/webrtc/trunk/third_party/libjingle/source/ \
-I$(topsrcdir)/xpcom/base/ \
$(NULL)
ifneq ($(OS_TARGET),WINNT)

View File

@ -23,9 +23,11 @@ using namespace std;
#include "FakeMediaStreams.h"
#include "FakeMediaStreamsImpl.h"
#include "PeerConnectionImpl.h"
#include "PeerConnectionCtx.h"
#include "runnable_utils.h"
#include "nsStaticComponents.h"
#include "nsIDOMRTCPeerConnection.h"
#include "nsWeakReference.h"
#include "mtransport_test_utils.h"
MtransportTestUtils *test_utils;
@ -118,7 +120,8 @@ enum offerAnswerFlags
};
class TestObserver : public IPeerConnectionObserver
class TestObserver : public IPeerConnectionObserver,
public nsSupportsWeakReference
{
public:
enum Action {
@ -163,7 +166,9 @@ private:
std::vector<nsDOMMediaStream *> streams;
};
NS_IMPL_THREADSAFE_ISUPPORTS1(TestObserver, IPeerConnectionObserver)
NS_IMPL_THREADSAFE_ISUPPORTS2(TestObserver,
IPeerConnectionObserver,
nsISupportsWeakReference)
NS_IMETHODIMP
TestObserver::OnCreateOfferSuccess(const char* offer)
@ -489,7 +494,7 @@ class SignalingAgent {
NS_DISPATCH_SYNC);
}
void Init(nsCOMPtr<nsIThread> thread)
void Init_m(nsCOMPtr<nsIThread> thread)
{
size_t found = 2;
ASSERT_TRUE(found > 0);
@ -502,6 +507,14 @@ class SignalingAgent {
ASSERT_EQ(pc->Initialize(pObserver, nullptr, thread), NS_OK);
}
void Init(nsCOMPtr<nsIThread> thread)
{
thread->Dispatch(
WrapRunnable(this, &SignalingAgent::Init_m, thread),
NS_DISPATCH_SYNC);
ASSERT_TRUE_WAIT(sipcc_state() == sipcc::PeerConnectionImpl::kStarted,
kDefaultTimeout);
ASSERT_TRUE_WAIT(ice_state() == sipcc::PeerConnectionImpl::kIceWaiting, 5000);
@ -592,14 +605,18 @@ class SignalingAgent {
// Now call CreateOffer as JS would
pObserver->state = TestObserver::stateNoResponse;
ASSERT_EQ(pc->CreateOffer(constraints), NS_OK);
ASSERT_TRUE_WAIT(pObserver->state == TestObserver::stateSuccess, kDefaultTimeout);
ASSERT_TRUE_WAIT(pObserver->state != TestObserver::stateNoResponse,
kDefaultTimeout);
ASSERT_TRUE(pObserver->state == TestObserver::stateSuccess);
SDPSanityCheck(pObserver->lastString, sdpCheck, true);
offer_ = pObserver->lastString;
}
void CreateOfferExpectError(sipcc::MediaConstraints& constraints) {
ASSERT_EQ(pc->CreateOffer(constraints), NS_OK);
ASSERT_TRUE_WAIT(pObserver->state == TestObserver::stateError, kDefaultTimeout);
ASSERT_TRUE_WAIT(pObserver->state != TestObserver::stateNoResponse,
kDefaultTimeout);
ASSERT_TRUE(pObserver->state == TestObserver::stateSuccess);
}
void CreateAnswer(sipcc::MediaConstraints& constraints, std::string offer,
@ -628,7 +645,9 @@ void CreateAnswer(sipcc::MediaConstraints& constraints, std::string offer,
pObserver->state = TestObserver::stateNoResponse;
ASSERT_EQ(pc->CreateAnswer(constraints), NS_OK);
ASSERT_TRUE_WAIT(pObserver->state == TestObserver::stateSuccess, kDefaultTimeout);
ASSERT_TRUE_WAIT(pObserver->state != TestObserver::stateNoResponse,
kDefaultTimeout);
ASSERT_TRUE(pObserver->state == TestObserver::stateSuccess);
SDPSanityCheck(pObserver->lastString, sdpCheck, false);
answer_ = pObserver->lastString;
@ -653,7 +672,9 @@ void CreateAnswer(sipcc::MediaConstraints& constraints, std::string offer,
// Now call CreateOffer as JS would
pObserver->state = TestObserver::stateNoResponse;
ASSERT_EQ(pc->CreateOffer(constraints), NS_OK);
ASSERT_TRUE_WAIT(pObserver->state == TestObserver::stateSuccess, kDefaultTimeout);
ASSERT_TRUE_WAIT(pObserver->state != TestObserver::stateNoResponse,
kDefaultTimeout);
ASSERT_TRUE(pObserver->state == TestObserver::stateSuccess);
SDPSanityCheck(pObserver->lastString, sdpCheck, true);
offer_ = pObserver->lastString;
}
@ -661,13 +682,17 @@ void CreateAnswer(sipcc::MediaConstraints& constraints, std::string offer,
void SetRemote(TestObserver::Action action, std::string remote) {
pObserver->state = TestObserver::stateNoResponse;
ASSERT_EQ(pc->SetRemoteDescription(action, remote.c_str()), NS_OK);
ASSERT_TRUE_WAIT(pObserver->state == TestObserver::stateSuccess, kDefaultTimeout);
ASSERT_TRUE_WAIT(pObserver->state != TestObserver::stateNoResponse,
kDefaultTimeout);
ASSERT_TRUE(pObserver->state == TestObserver::stateSuccess);
}
void SetLocal(TestObserver::Action action, std::string local) {
pObserver->state = TestObserver::stateNoResponse;
ASSERT_EQ(pc->SetLocalDescription(action, local.c_str()), NS_OK);
ASSERT_TRUE_WAIT(pObserver->state == TestObserver::stateSuccess, kDefaultTimeout);
ASSERT_TRUE_WAIT(pObserver->state != TestObserver::stateNoResponse,
kDefaultTimeout);
ASSERT_TRUE(pObserver->state == TestObserver::stateSuccess);
}
void DoTrickleIce(ParsedSDP &sdp) {
@ -734,6 +759,7 @@ public:
private:
void SDPSanityCheck(std::string sdp, uint32_t flags, bool offer)
{
ASSERT_TRUE(pObserver->state == TestObserver::stateSuccess);
ASSERT_NE(sdp.find("v=0"), std::string::npos);
ASSERT_NE(sdp.find("c=IN IP4"), std::string::npos);
ASSERT_NE(sdp.find("a=fingerprint:sha-256"), std::string::npos);
@ -1700,6 +1726,32 @@ TEST_F(SignalingTest, CheckTrickleSdpChange)
ASSERT_EQ(a2_.getLocalDescription(),a1_.getRemoteDescription());
}
TEST_F(SignalingTest, ipAddrAnyOffer)
{
sipcc::MediaConstraints constraints;
std::string offer =
"v=0\r\n"
"o=- 1 1 IN IP4 127.0.0.1\r\n"
"s=-\r\n"
"b=AS:64\r\n"
"t=0 0\r\n"
"a=fingerprint:sha-256 F3:FA:20:C0:CD:48:C4:5F:02:5F:A5:D3:21:D0:2D:48:"
"7B:31:60:5C:5A:D8:0D:CD:78:78:6C:6D:CE:CC:0C:67\r\n"
"m=audio 9000 RTP/AVP 99\r\n"
"c=IN IP4 0.0.0.0\r\n"
"a=rtpmap:99 opus/48000/2\r\n"
"a=ice-ufrag:cYuakxkEKH+RApYE\r\n"
"a=ice-pwd:bwtpzLZD+3jbu8vQHvEa6Xuq\r\n"
"a=sendrecv\r\n";
a2_.SetRemote(TestObserver::OFFER, offer);
ASSERT_TRUE(a2_.pObserver->state == TestObserver::stateSuccess);
a2_.CreateAnswer(constraints, offer, OFFER_AUDIO | ANSWER_AUDIO);
ASSERT_TRUE(a2_.pObserver->state == TestObserver::stateSuccess);
std::string answer = a2_.answer();
ASSERT_NE(answer.find("a=sendrecv"), std::string::npos);
}
} // End namespace test.
int main(int argc, char **argv) {
@ -1720,6 +1772,13 @@ int main(int argc, char **argv) {
::testing::AddGlobalTestEnvironment(new test::SignalingEnvironment);
int result = RUN_ALL_TESTS();
// Because we don't initialize on the main thread, we can't register for
// XPCOM shutdown callbacks (where the context is usually shut down) --
// so we need to explictly destroy the context.
sipcc::PeerConnectionCtx::Destroy();
delete test_utils;
return result;
}

49
mfbt/Range.h Normal file
View File

@ -0,0 +1,49 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sw=4 et tw=78:
*
* 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_Range_h_
#define mozilla_Range_h_
#include "mozilla/NullPtr.h"
#include "mozilla/RangedPtr.h"
#include <stddef.h>
namespace mozilla {
// Range<T> is a tuple containing a pointer and a length.
template <typename T>
class Range
{
RangedPtr<T> mStart;
RangedPtr<T> mEnd;
typedef void (Range::* ConvertibleToBool)();
void nonNull() {}
public:
Range() : mStart(nullptr, 0), mEnd(nullptr, 0) {}
Range(T* p, size_t len)
: mStart(p, p, p + len),
mEnd(p + len, p, p + len)
{}
RangedPtr<T> start() const { return mStart; }
RangedPtr<T> end() const { return mEnd; }
size_t length() const { return mEnd - mStart; }
T& operator[](size_t offset) {
return mStart[offset];
}
operator ConvertibleToBool() const { return mStart ? &Range::nonNull : 0; }
};
} // namespace mozilla
#endif // mozilla_Range_h_

View File

@ -46,6 +46,9 @@ class RangedPtr
T* const rangeEnd;
#endif
typedef void (RangedPtr::* ConvertibleToBool)();
void nonNull() {}
void checkSanity() {
MOZ_ASSERT(rangeStart <= ptr);
MOZ_ASSERT(ptr <= rangeEnd);
@ -97,7 +100,7 @@ class RangedPtr
/* Equivalent to RangedPtr(arr, arr, N). */
template<size_t N>
RangedPtr(T arr[N])
RangedPtr(T (&arr)[N])
: ptr(arr)
#ifdef DEBUG
, rangeStart(arr), rangeEnd(arr + N)
@ -110,6 +113,8 @@ class RangedPtr
return ptr;
}
operator ConvertibleToBool() const { return ptr ? &RangedPtr::nonNull : 0; }
/*
* You can only assign one RangedPtr into another if the two pointers have
* the same valid range:
@ -242,7 +247,6 @@ class RangedPtr
private:
RangedPtr() MOZ_DELETE;
T* operator&() MOZ_DELETE;
operator T*() const MOZ_DELETE;
};
} /* namespace mozilla */

View File

@ -25,6 +25,7 @@ EXPORTS_mozilla += \
MathAlgorithms.h \
MSStdInt.h \
NullPtr.h \
Range.h \
RangedPtr.h \
RefPtr.h \
Scoped.h \

View File

@ -46,7 +46,6 @@ DEFINES += \
-DAPP_NAME=$(MOZ_APP_NAME) \
-DAPP_VERSION=$(MOZ_APP_VERSION) \
-DMOZ_UPDATER=$(MOZ_UPDATER) \
-DMOZ_APP_UA_NAME=$(MOZ_APP_UA_NAME) \
$(NULL)
ifdef MOZ_PKG_SPECIAL

View File

@ -573,8 +573,6 @@ pref("browser.safebrowsing.reportMalwareErrorURL", "http://%LOCALE%.malware-erro
pref("browser.safebrowsing.warning.infoURL", "http://www.mozilla.com/%LOCALE%/firefox/phishing-protection/");
pref("browser.safebrowsing.malware.reportURL", "http://safebrowsing.clients.google.com/safebrowsing/diagnostic?client=%NAME%&hl=%LOCALE%&site=");
pref("browser.safebrowsing.id", "@MOZ_APP_UA_NAME@");
// Name of the about: page contributed by safebrowsing to handle display of error
// pages on phishing/malware hits. (bug 399233)
pref("urlclassifier.alternate_error_page", "blocked");

View File

@ -39,4 +39,14 @@ EXTRA_COMPONENTS = \
BlocklistPrompt.js \
$(NULL)
ifdef MOZ_SAFE_BROWSING
DEFINES += \
-DMOZ_APP_UA_NAME=$(MOZ_APP_UA_NAME) \
$(NULL)
EXTRA_PP_JS_MODULES = \
SafeBrowsing.jsm \
$(NULL)
endif
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,182 @@
/* 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/. */
this.EXPORTED_SYMBOLS = ["SafeBrowsing"];
const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;
Cu.import("resource://gre/modules/Services.jsm");
const phishingList = "goog-phish-shavar";
const malwareList = "goog-malware-shavar";
var debug = false;
function log(...stuff) {
if (!debug)
return;
let msg = "SafeBrowsing: " + stuff.join(" ");
Services.console.logStringMessage(msg);
dump(msg + "\n");
}
this.SafeBrowsing = {
init: function() {
if (this.initialized) {
log("Already initialized");
return;
}
Services.prefs.addObserver("browser.safebrowsing", this.readPrefs, false);
this.readPrefs();
// Register our two types of tables, and add custom Mozilla entries
let listManager = Cc["@mozilla.org/url-classifier/listmanager;1"].
getService(Ci.nsIUrlListManager);
listManager.registerTable(phishingList, false);
listManager.registerTable(malwareList, false);
this.addMozEntries();
this.controlUpdateChecking();
this.initialized = true;
log("init() finished");
},
initialized: false,
phishingEnabled: false,
malwareEnabled: false,
updateURL: null,
keyURL: null,
gethashURL: null,
reportURL: null,
reportGenericURL: null,
reportErrorURL: null,
reportPhishURL: null,
reportMalwareURL: null,
reportMalwareErrorURL: null,
getReportURL: function(kind) {
return this["report" + kind + "URL"];
},
readPrefs: function() {
log("reading prefs");
debug = Services.prefs.getBoolPref("browser.safebrowsing.debug");
this.phishingEnabled = Services.prefs.getBoolPref("browser.safebrowsing.enabled");
this.malwareEnabled = Services.prefs.getBoolPref("browser.safebrowsing.malware.enabled");
this.updateProviderURLs();
// XXX The listManager backend gets confused if this is called before the
// lists are registered. So only call it here when a pref changes, and not
// when doing initialization. I expect to refactor this later, so pardon the hack.
if (this.initialized)
this.controlUpdateChecking();
},
updateProviderURLs: function() {
#ifdef USE_HISTORIC_SAFEBROWSING_ID
let clientID = "navclient-auto-ffox";
#else
#expand let clientID = __MOZ_APP_UA_NAME__;
#endif
log("initializing safe browsing URLs");
let basePref = "browser.safebrowsing.";
// Urls to HTML report pages
this.reportURL = Services.urlFormatter.formatURLPref(basePref + "reportURL");
this.reportGenericURL = Services.urlFormatter.formatURLPref(basePref + "reportGenericURL");
this.reportErrorURL = Services.urlFormatter.formatURLPref(basePref + "reportErrorURL");
this.reportPhishURL = Services.urlFormatter.formatURLPref(basePref + "reportPhishURL");
this.reportMalwareURL = Services.urlFormatter.formatURLPref(basePref + "reportMalwareURL");
this.reportMalwareErrorURL = Services.urlFormatter.formatURLPref(basePref + "reportMalwareErrorURL");
// Urls used to update DB
this.updateURL = Services.urlFormatter.formatURLPref(basePref + "updateURL");
this.keyURL = Services.urlFormatter.formatURLPref(basePref + "keyURL");
this.gethashURL = Services.urlFormatter.formatURLPref(basePref + "gethashURL");
this.updateURL = this.updateURL.replace("SAFEBROWSING_ID", clientID);
this.keyURL = this.keyURL.replace("SAFEBROWSING_ID", clientID);
this.gethashURL = this.gethashURL.replace("SAFEBROWSING_ID", clientID);
let listManager = Cc["@mozilla.org/url-classifier/listmanager;1"].
getService(Ci.nsIUrlListManager);
listManager.setUpdateUrl(this.updateURL);
// XXX Bug 779317 - setKeyUrl has the side effect of fetching a key from the server.
// This shouldn't happen if anti-phishing/anti-malware is disabled.
if (this.phishingEnabled || this.malwareEnabled)
listManager.setKeyUrl(this.keyURL);
listManager.setGethashUrl(this.gethashURL);
},
controlUpdateChecking: function() {
log("phishingEnabled:", this.phishingEnabled, "malwareEnabled:", this.malwareEnabled);
let listManager = Cc["@mozilla.org/url-classifier/listmanager;1"].
getService(Ci.nsIUrlListManager);
if (this.phishingEnabled)
listManager.enableUpdate(phishingList);
else
listManager.disableUpdate(phishingList);
if (this.malwareEnabled)
listManager.enableUpdate(malwareList);
else
listManager.disableUpdate(malwareList);
},
addMozEntries: function() {
// Add test entries to the DB.
// XXX bug 779008 - this could be done by DB itself?
const phishURL = "mozilla.org/firefox/its-a-trap.html";
const malwareURL = "mozilla.org/firefox/its-an-attack.html";
let update = "n:1000\ni:test-malware-simple\nad:1\n" +
"a:1:32:" + malwareURL.length + "\n" +
malwareURL;
update += "n:1000\ni:test-phish-simple\nad:1\n" +
"a:1:32:" + phishURL.length + "\n" +
phishURL;
log("addMozEntries:", update);
let db = Cc["@mozilla.org/url-classifier/dbservice;1"].
getService(Ci.nsIUrlClassifierDBService);
// nsIUrlClassifierUpdateObserver
let dummyListener = {
updateUrlRequested: function() { },
streamFinished: function() { },
updateError: function() { },
updateSuccess: function() { }
};
try {
db.beginUpdate(dummyListener, "test-malware-simple,test-phish-simple", "");
db.beginStream("", "");
db.updateStream(update);
db.finishStream();
db.finishUpdate();
} catch(ex) {
// beginUpdate will throw harmlessly if there's an existing update in progress, ignore failures.
log("addMozEntries failed!", ex);
}
},
};

View File

@ -297,8 +297,6 @@
@BINPATH@/components/nsDownloadManagerUI.js
@BINPATH@/components/NetworkGeolocationProvider.manifest
@BINPATH@/components/NetworkGeolocationProvider.js
@BINPATH@/components/GPSDGeolocationProvider.manifest
@BINPATH@/components/GPSDGeolocationProvider.js
@BINPATH@/components/nsSidebar.manifest
@BINPATH@/components/nsSidebar.js
@BINPATH@/components/extensions.manifest

View File

@ -345,8 +345,6 @@
@BINPATH@/components/nsDownloadManagerUI.js
@BINPATH@/components/NetworkGeolocationProvider.manifest
@BINPATH@/components/NetworkGeolocationProvider.js
@BINPATH@/components/GPSDGeolocationProvider.manifest
@BINPATH@/components/GPSDGeolocationProvider.js
@BINPATH@/components/nsSidebar.manifest
@BINPATH@/components/nsSidebar.js
@BINPATH@/components/extensions.manifest

Some files were not shown because too many files have changed in this diff Show More