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 1ffd79274e
116 changed files with 2066 additions and 962 deletions

View File

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

View File

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

View File

@ -31,11 +31,8 @@ DEFINES += \
-DNEWWINDOW_ICO=\"$(DIST)/branding/newwindow.ico\" \ -DNEWWINDOW_ICO=\"$(DIST)/branding/newwindow.ico\" \
-DNEWTAB_ICO=\"$(DIST)/branding/newtab.ico\" \ -DNEWTAB_ICO=\"$(DIST)/branding/newtab.ico\" \
-DPBMODE_ICO=\"$(DIST)/branding/pbmode.ico\" \ -DPBMODE_ICO=\"$(DIST)/branding/pbmode.ico\" \
$(NULL)
ifdef MOZILLA_OFFICIAL $(NULL)
DEFINES += -DMOZILLA_OFFICIAL
endif
ifdef LIBXUL_SDK #{ ifdef LIBXUL_SDK #{
PREF_JS_EXPORTS += $(srcdir)/profile/channel-prefs.js 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.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.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 // Name of the about: page contributed by safebrowsing to handle display of error
// pages on phishing/malware hits. (bug 399233) // pages on phishing/malware hits. (bug 399233)
pref("urlclassifier.alternate_error_page", "blocked"); pref("urlclassifier.alternate_error_page", "blocked");

View File

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

View File

@ -31,4 +31,4 @@ browser.jar:
content/browser/places/moveBookmarks.js (content/moveBookmarks.js) content/browser/places/moveBookmarks.js (content/moveBookmarks.js)
content/browser/places/editBookmarkOverlay.xul (content/editBookmarkOverlay.xul) content/browser/places/editBookmarkOverlay.xul (content/editBookmarkOverlay.xul)
content/browser/places/editBookmarkOverlay.js (content/editBookmarkOverlay.js) 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/nsDownloadManagerUI.js
@BINPATH@/components/NetworkGeolocationProvider.manifest @BINPATH@/components/NetworkGeolocationProvider.manifest
@BINPATH@/components/NetworkGeolocationProvider.js @BINPATH@/components/NetworkGeolocationProvider.js
@BINPATH@/components/GPSDGeolocationProvider.manifest
@BINPATH@/components/GPSDGeolocationProvider.js
@BINPATH@/components/nsSidebar.manifest @BINPATH@/components/nsSidebar.manifest
@BINPATH@/components/nsSidebar.js @BINPATH@/components/nsSidebar.js
@BINPATH@/components/extensions.manifest @BINPATH@/components/extensions.manifest

View File

@ -318,8 +318,10 @@ toolbar[iconsize="large"] > #downloads-indicator[attention] > #downloads-indicat
-moz-appearance: none; -moz-appearance: none;
min-width: 0; min-width: 0;
min-height: 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-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: 1px solid;
border-color: rgba(0,43,86,.6) rgba(0,43,86,.4) rgba(0,43,86,.4); border-color: rgba(0,43,86,.6) rgba(0,43,86,.4) rgba(0,43,86,.4);
border-radius: 2px 0 0 2px; border-radius: 2px 0 0 2px;

View File

@ -492,8 +492,10 @@ richlistitem[type="download"]:hover > stack > .downloadButton.downloadRetry:acti
-moz-appearance: none; -moz-appearance: none;
min-width: 0; min-width: 0;
min-height: 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-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: 1px solid;
border-color: rgba(0,43,86,.6) rgba(0,43,86,.4) rgba(0,43,86,.4); border-color: rgba(0,43,86,.6) rgba(0,43,86,.4) rgba(0,43,86,.4);
border-radius: 2px 0 0 2px; border-radius: 2px 0 0 2px;

View File

@ -343,8 +343,10 @@ richlistitem[type="download"]:hover > stack > .downloadButton.downloadRetry:acti
-moz-appearance: none; -moz-appearance: none;
min-width: 0; min-width: 0;
min-height: 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-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: 1px solid;
border-color: rgba(0,43,86,.6) rgba(0,43,86,.4) rgba(0,43,86,.4); border-color: rgba(0,43,86,.6) rgba(0,43,86,.4) rgba(0,43,86,.4);
border-radius: 2px 0 0 2px; border-radius: 2px 0 0 2px;

View File

@ -9,6 +9,7 @@
from __future__ import with_statement from __future__ import with_statement
from optparse import OptionParser from optparse import OptionParser
import sys, re, os, posixpath, ntpath import sys, re, os, posixpath, ntpath
import errno
from StringIO import StringIO from StringIO import StringIO
# Standalone js doesn't have virtualenv. # Standalone js doesn't have virtualenv.
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'config')) 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"); cursor.execute("PRAGMA user_version=3");
# SQL copied from nsPermissionManager.cpp # SQL copied from nsPermissionManager.cpp
cursor.execute("""CREATE TABLE moz_hosts ( cursor.execute("""CREATE TABLE IF NOT EXISTS moz_hosts (
id INTEGER PRIMARY KEY, id INTEGER PRIMARY KEY,
host TEXT, host TEXT,
type TEXT, type TEXT,
permission INTEGER, permission INTEGER,
expireType INTEGER, expireType INTEGER,
expireTime INTEGER, expireTime INTEGER,
appId INTEGER, appId INTEGER,
isInBrowserElement INTEGER)""") isInBrowserElement INTEGER)""")
# Insert desired permissions # Insert desired permissions
c = 0
for perm in permissions.keys(): for perm in permissions.keys():
for host,allow in permissions[perm]: for host,allow in permissions[perm]:
c += 1 cursor.execute("INSERT INTO moz_hosts values(NULL, ?, ?, ?, 0, 0, 0, 0)",
cursor.execute("INSERT INTO moz_hosts values(?, ?, ?, ?, 0, 0, 0, 0)", (host, perm, 1 if allow else 2))
(c, host, perm, 1 if allow else 2))
# Commit and close # Commit and close
permDB.commit() permDB.commit()
cursor.close() cursor.close()
def setupTestApps(self, profileDir, apps): def setupTestApps(self, profileDir, apps):
webappJSONTemplate = Template(""""$name": { webappJSONTemplate = Template(""""$id": {
"origin": "$origin", "origin": "$origin",
"installOrigin": "$origin", "installOrigin": "$origin",
"receipt": null, "receipt": null,
"installTime": 132333986000, "installTime": 132333986000,
"manifestURL": "$manifestURL", "manifestURL": "$manifestURL",
"localId": $localId, "localId": $localId,
"appStatus": $appStatus, "id": "$id",
"csp": "$csp" "appStatus": $appStatus,
"csp": "$csp"
}""") }""")
manifestTemplate = Template("""{ manifestTemplate = Template("""{
@ -333,16 +332,73 @@ class Automation(object):
# Create webapps/webapps.json # Create webapps/webapps.json
webappsDir = os.path.join(profileDir, "webapps") 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 = [] webappsJSON = []
for localId, app in enumerate(apps): if os.access(webappsJSONFilename, os.F_OK):
app['localId'] = localId + 1 # Has to be 1..n # If there is an existing webapps.json file (which will be the case for
webappsJSON.append(webappJSONTemplate.substitute(app)) # b2g), we parse the data in the existing file before appending test
webappsJSON = '{\n' + ',\n'.join(webappsJSON) + '\n}\n' # test apps to it.
startId = 1
webappsJSONFile = open(webappsJSONFilename, "r")
contents = webappsJSONFile.read()
webappsJSONFile = open(os.path.join(webappsDir, "webapps.json"), "a") for app_content in contents.split('},'):
webappsJSONFile.write(webappsJSON) 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() webappsJSONFile.close()
# Create manifest file for each app. # Create manifest file for each app.
@ -356,13 +412,19 @@ class Automation(object):
manifestFile.write(manifest) manifestFile.write(manifest)
manifestFile.close() manifestFile.close()
def initializeProfile(self, profileDir, extraPrefs = [], useServerLocations = False): def initializeProfile(self, profileDir, extraPrefs=[],
useServerLocations=False,
initialProfile=None):
" Sets up the standard testing profile." " Sets up the standard testing profile."
prefs = [] prefs = []
# Start with a clean slate. # Start with a clean slate.
shutil.rmtree(profileDir, True) shutil.rmtree(profileDir, True)
os.mkdir(profileDir)
if initialProfile:
shutil.copytree(initialProfile, profileDir)
else:
os.mkdir(profileDir)
# Set up permissions database # Set up permissions database
locations = self.readLocations() 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', 'manifestURL': 'https://example.com/manifest_csp_cert.webapp',
'description': 'https://example.com Certified App with manifest policy', 'description': 'https://example.com Certified App with manifest policy',
'appStatus': _APP_STATUS_CERTIFIED 'appStatus': _APP_STATUS_CERTIFIED
}, },
{ {
'name': 'https_example_csp_installed', 'name': 'https_example_csp_installed',
'csp': "default-src *; script-src 'self'; object-src 'none'; style-src 'self' 'unsafe-inline'", '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', 'manifestURL': 'https://example.com/manifest_csp_inst.webapp',
'description': 'https://example.com Installed App with manifest policy', 'description': 'https://example.com Installed App with manifest policy',
'appStatus': _APP_STATUS_INSTALLED 'appStatus': _APP_STATUS_INSTALLED
}, },
{ {
'name': 'https_example_csp_privileged', 'name': 'https_example_csp_privileged',
'csp': "default-src *; script-src 'self'; object-src 'none'; style-src 'self' 'unsafe-inline'", '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', 'manifestURL': 'https://example.com/manifest_csp_priv.webapp',
'description': 'https://example.com Privileged App with manifest policy', 'description': 'https://example.com Privileged App with manifest policy',
'appStatus': _APP_STATUS_PRIVILEGED 'appStatus': _APP_STATUS_PRIVILEGED
}, },
{ {
'name': 'https_a_domain_certified', 'name': 'https_a_domain_certified',
'csp' : "", 'csp': "",
'origin': 'https://acertified.com', 'origin': 'https://acertified.com',
'manifestURL': 'https://acertified.com/manifest.webapp', 'manifestURL': 'https://acertified.com/manifest.webapp',
'description': 'https://acertified.com Certified App', 'description': 'https://acertified.com Certified App',
'appStatus': _APP_STATUS_CERTIFIED 'appStatus': _APP_STATUS_CERTIFIED
}, },
{ {
'name': 'https_a_domain_privileged', 'name': 'https_a_domain_privileged',
'csp': "", 'csp': "",
@ -632,7 +694,7 @@ user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless t
'manifestURL': 'https://aprivileged.com/manifest.webapp', 'manifestURL': 'https://aprivileged.com/manifest.webapp',
'description': 'https://aprivileged.com Privileged App ', 'description': 'https://aprivileged.com Privileged App ',
'appStatus': _APP_STATUS_PRIVILEGED 'appStatus': _APP_STATUS_PRIVILEGED
}, },
]; ];
self.setupTestApps(profileDir, apps) self.setupTestApps(profileDir, apps)
@ -1033,7 +1095,7 @@ user_pref("camino.use_system_proxy_settings", false); // Camino-only, harmless t
runSSLTunnel = False, utilityPath = None, runSSLTunnel = False, utilityPath = None,
xrePath = None, certPath = None, xrePath = None, certPath = None,
debuggerInfo = None, symbolsPath = 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. 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. 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) stderr = subprocess.STDOUT)
self.log.info("INFO | automation.py | Application pid: %d", proc.pid) 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) status = self.waitForFinish(proc, utilityPath, timeout, maxTime, startTime, debuggerInfo, symbolsPath)
self.log.info("INFO | automation.py | Application ran for: %s", str(datetime.now() - startTime)) 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._product = "b2g"
self.lastTestSeen = "b2gautomation.py" self.lastTestSeen = "b2gautomation.py"
# Default log finish to mochitest standard # Default log finish to mochitest standard
self.logFinish = 'INFO SimpleTest FINISHED' self.logFinish = 'INFO SimpleTest FINISHED'
Automation.__init__(self) Automation.__init__(self)
def setEmulator(self, is_emulator): def setEmulator(self, is_emulator):
@ -85,7 +85,7 @@ class B2GRemoteAutomation(Automation):
env['MOZ_HIDE_RESULTS_TABLE'] = '1' env['MOZ_HIDE_RESULTS_TABLE'] = '1'
return env return env
def waitForNet(self): def waitForNet(self):
active = False active = False
time_out = 0 time_out = 0
while not active and time_out < 40: while not active and time_out < 40:
@ -106,15 +106,20 @@ class B2GRemoteAutomation(Automation):
self._devicemanager.getDirectory(self._remoteProfile + '/minidumps/', dumpDir) self._devicemanager.getDirectory(self._remoteProfile + '/minidumps/', dumpDir)
crashed = automationutils.checkForCrashes(dumpDir, symbolsPath, self.lastTestSeen) crashed = automationutils.checkForCrashes(dumpDir, symbolsPath, self.lastTestSeen)
try: try:
shutil.rmtree(dumpDir) shutil.rmtree(dumpDir)
except: except:
print "WARNING: unable to remove directory: %s" % (dumpDir) print "WARNING: unable to remove directory: %s" % (dumpDir)
return crashed return crashed
def initializeProfile(self, profileDir, extraPrefs = [], useServerLocations = False): def initializeProfile(self, profileDir, extraPrefs=[],
useServerLocations=False,
initialProfile=None):
# add b2g specific prefs # add b2g specific prefs
extraPrefs.extend(["browser.manifestURL='dummy (bug 772307)'"]) 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): def buildCommandLine(self, app, debuggerInfo, profileDir, testURL, extraArgs):
# if remote profile is specified, use that instead # if remote profile is specified, use that instead
@ -165,7 +170,7 @@ class B2GRemoteAutomation(Automation):
status = 'unknown' status = 'unknown'
for line in self._devicemanager._runCmd(['devices']).stdout.readlines(): for line in self._devicemanager._runCmd(['devices']).stdout.readlines():
result = re.match('(.*?)\t(.*)', line) result = re.match('(.*?)\t(.*)', line)
if result: if result:
thisSerial = result.group(1) thisSerial = result.group(1)
if not serial or thisSerial == serial: if not serial or thisSerial == serial:
@ -223,9 +228,9 @@ class B2GRemoteAutomation(Automation):
if not self._is_emulator: if not self._is_emulator:
self.rebootDevice() self.rebootDevice()
time.sleep(5) time.sleep(5)
#wait for wlan to come up #wait for wlan to come up
if not self.waitForNet(): 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") " prior to running before running the automation framework")
# stop b2g # stop b2g
@ -334,10 +339,33 @@ class B2GRemoteAutomation(Automation):
break break
return '\n'.join(lines) return '\n'.join(lines)
def wait(self, timeout = None): def wait(self, timeout=None):
# this should never happen # this should never happen
raise Exception("'wait' called on B2GInstance") raise Exception("'wait' called on B2GInstance")
def kill(self): def kill(self):
# this should never happen # this should never happen
raise Exception("'kill' called on B2GInstance") 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 GIO_VERSION=2.20
STARTUP_NOTIFICATION_VERSION=0.8 STARTUP_NOTIFICATION_VERSION=0.8
DBUS_VERSION=0.60 DBUS_VERSION=0.60
SQLITE_VERSION=3.7.15.1 SQLITE_VERSION=3.7.15.2
MSMANIFEST_TOOL= MSMANIFEST_TOOL=

View File

@ -13,6 +13,7 @@ include $(DEPTH)/config/autoconf.mk
MOCHITEST_FILES := \ MOCHITEST_FILES := \
webaudio.js \ webaudio.js \
test_bug808374.html \ test_bug808374.html \
test_bug827541.html \
test_AudioBuffer.html \ test_AudioBuffer.html \
test_AudioContext.html \ test_AudioContext.html \
test_AudioListener.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. 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 ** 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 ** 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 ** unit. This allows many compilers to do optimizations that would not be
** possible if the files were compiled separately. Performance improvements ** possible if the files were compiled separately. Performance improvements
@ -673,9 +673,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()]. ** [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_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 ** CAPI3REF: Run-Time Library Version Numbers
@ -105723,7 +105723,7 @@ static void bestBtreeIndex(WhereBestIdx *p){
pc.plan.nOBSat = isSortingIndex(p, pProbe, iCur, &bRev); pc.plan.nOBSat = isSortingIndex(p, pProbe, iCur, &bRev);
WHERETRACE((" --> after isSortingIndex: bRev=%d nOBSat=%d\n", WHERETRACE((" --> after isSortingIndex: bRev=%d nOBSat=%d\n",
bRev, pc.plan.nOBSat)); 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; pc.plan.wsFlags |= WHERE_ORDERED;
} }
if( nOrderBy==pc.plan.nOBSat ){ if( nOrderBy==pc.plan.nOBSat ){

View File

@ -107,9 +107,9 @@ extern "C" {
** [sqlite3_libversion_number()], [sqlite3_sourceid()], ** [sqlite3_libversion_number()], [sqlite3_sourceid()],
** [sqlite_version()] and [sqlite_source_id()]. ** [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_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 ** CAPI3REF: Run-Time Library Version Numbers

View File

@ -1228,15 +1228,19 @@ this.DOMApplicationRegistry = {
// "downloadapplied". // "downloadapplied".
let updateObserver = { let updateObserver = {
observe: function(aSubject, aTopic, aObsData) { observe: function(aSubject, aTopic, aObsData) {
debug("updateHostedApp: updateSvc.checkForUpdate return for " +
app.manifestURL + " - event is " + aTopic);
aData.event = aData.event =
aTopic == "offline-cache-update-available" ? "downloadavailable" aTopic == "offline-cache-update-available" ? "downloadavailable"
: "downloadapplied"; : "downloadapplied";
aData.app.downloadAvailable = (aTopic == "downloadavailable"); aData.app.downloadAvailable = (aData.event == "downloadavailable");
DOMApplicationRegistry.broadcastMessage("Webapps:CheckForUpdate:Return:OK", DOMApplicationRegistry.broadcastMessage("Webapps:CheckForUpdate:Return:OK",
aData); 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); app.localId, false, updateObserver);
} }
delete app.manifest; delete app.manifest;
@ -1287,7 +1291,9 @@ this.DOMApplicationRegistry = {
// "downloadapplied". // "downloadapplied".
let updateObserver = { let updateObserver = {
observe: function(aSubject, aTopic, aObsData) { 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"; aData.event = "downloadavailable";
app.downloadAvailable = true; app.downloadAvailable = true;
aData.app = app; 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); app.localId, false, updateObserver);
}); });
return; return;
@ -1312,6 +1321,7 @@ this.DOMApplicationRegistry = {
xhr.channel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING; xhr.channel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;
xhr.responseType = "json"; xhr.responseType = "json";
if (app.etag) { if (app.etag) {
debug("adding manifest etag:" + app.etag);
xhr.setRequestHeader("If-None-Match", app.etag); xhr.setRequestHeader("If-None-Match", app.etag);
} }
xhr.channel.notificationCallbacks = xhr.channel.notificationCallbacks =
@ -1333,6 +1343,7 @@ this.DOMApplicationRegistry = {
return; return;
} else { } else {
app.etag = xhr.getResponseHeader("Etag"); app.etag = xhr.getResponseHeader("Etag");
debug("at update got app etag=" + app.etag);
app.lastCheckedUpdate = Date.now(); app.lastCheckedUpdate = Date.now();
if (app.origin.startsWith("app://")) { if (app.origin.startsWith("app://")) {
updatePackagedApp.call(this, manifest); updatePackagedApp.call(this, manifest);
@ -1509,6 +1520,7 @@ this.DOMApplicationRegistry = {
sendError("INSTALL_FROM_DENIED"); sendError("INSTALL_FROM_DENIED");
} else { } else {
app.etag = xhr.getResponseHeader("Etag"); app.etag = xhr.getResponseHeader("Etag");
debug("at install package got app etag=" + app.etag);
Services.obs.notifyObservers(aMm, "webapps-ask-install", Services.obs.notifyObservers(aMm, "webapps-ask-install",
JSON.stringify(aData)); JSON.stringify(aData));
} }
@ -1832,7 +1844,7 @@ this.DOMApplicationRegistry = {
.QueryInterface(Ci.nsIHttpChannel); .QueryInterface(Ci.nsIHttpChannel);
requestChannel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING; requestChannel.loadFlags |= Ci.nsIRequest.INHIBIT_CACHING;
if (app.packageEtag) { 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); 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(mDocumentPrincipal)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDoc)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleService) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleService)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingStorageEvents)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleObservers)
// Traverse stuff from nsPIDOMWindow // Traverse stuff from nsPIDOMWindow
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeEventHandler) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mChromeEventHandler)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentTarget) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParentTarget)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameElement) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameElement)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFocusedNode) NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFocusedNode)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mAudioContexts)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPendingStorageEvents)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mIdleObservers)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsGlobalWindow) 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(mApplicationCache)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPrincipal) NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocumentPrincipal)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDoc) 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 // Unlink stuff from nsPIDOMWindow
NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeEventHandler) NS_IMPL_CYCLE_COLLECTION_UNLINK(mChromeEventHandler)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mParentTarget) NS_IMPL_CYCLE_COLLECTION_UNLINK(mParentTarget)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument) NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameElement) NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameElement)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFocusedNode) NS_IMPL_CYCLE_COLLECTION_UNLINK(mFocusedNode)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleService) NS_IMPL_CYCLE_COLLECTION_UNLINK(mAudioContexts)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPendingStorageEvents)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mIdleObservers)
NS_IMPL_CYCLE_COLLECTION_UNLINK_END NS_IMPL_CYCLE_COLLECTION_UNLINK_END
struct TraceData struct TraceData

View File

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

View File

@ -39,7 +39,7 @@ const kMessages =["SystemMessageManager:GetPendingMessages",
"child-process-shutdown"] "child-process-shutdown"]
function debug(aMsg) { function debug(aMsg) {
//dump("-- SystemMessageInternal " + Date.now() + " : " + aMsg + "\n"); dump("-- SystemMessageInternal " + Date.now() + " : " + aMsg + "\n");
} }
// Implementation of the component used by internal users. // 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 // The set of pages registered by installed apps. We keep the
// list of pending messages for each page here also. // list of pending messages for each page here also.
this._pages = []; 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._listeners = {};
this._webappsRegistryReady = false; this._webappsRegistryReady = false;
@ -63,6 +69,16 @@ function SystemMessageInternal() {
Services.obs.notifyObservers(this, "system-message-internal-ready", null); 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 = { SystemMessageInternal.prototype = {
sendMessage: function sendMessage(aType, aMessage, aPageURI, aManifestURI) { sendMessage: function sendMessage(aType, aMessage, aPageURI, aManifestURI) {
// Buffer system messages until the webapps' registration is ready, // Buffer system messages until the webapps' registration is ready,
@ -189,10 +205,19 @@ SystemMessageInternal.prototype = {
case "SystemMessageManager:Register": case "SystemMessageManager:Register":
{ {
debug("Got Register from " + msg.manifest); debug("Got Register from " + msg.manifest);
if (!this._listeners[msg.manifest]) { let targets, target;
this._listeners[msg.manifest] = {}; 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); debug("listeners for " + msg.manifest + " innerWinID " + msg.innerWindowID);
break; break;
} }
@ -200,11 +225,20 @@ SystemMessageInternal.prototype = {
{ {
debug("Got child-process-shutdown from " + aMessage.target); debug("Got child-process-shutdown from " + aMessage.target);
for (let manifest in this._listeners) { for (let manifest in this._listeners) {
for (let winID in this._listeners[manifest]) { // See if any processes in this manifest have this target.
if (aMessage.target === this._listeners[manifest][winID]) { let targets = this._listeners[manifest];
debug("remove " + manifest ); for (let target = 0; target < targets.length; ++target) {
delete this._listeners[manifest]; if (targets[target].target === aMessage.target) {
return; // 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": case "SystemMessageManager:Unregister":
{ {
debug("Got Unregister from " + aMessage.target + "innerWinID " + msg.innerWindowID); 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 ); debug("Removing " + aMessage.target + "innerWinID " + msg.innerWindowID );
break; break;
@ -391,13 +440,14 @@ SystemMessageInternal.prototype = {
let winTargets = this._listeners[aManifestURI]; let winTargets = this._listeners[aManifestURI];
if (winTargets) { if (winTargets) {
for (let winID in winTargets) { for (let target = 0; target < winTargets.length; ++target) {
winTargets[winID].sendAsyncMessage("SystemMessageManager:Message", let manager = winTargets[target].target;
{ type: aType, manager.sendAsyncMessage("SystemMessageManager:Message",
msg: aMessage, { type: aType,
manifest: aManifestURI, msg: aMessage,
uri: aPageURI, manifest: aManifestURI,
msgID: aMessageID }); 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 = \ EXTRA_COMPONENTS = \
NetworkGeolocationProvider.js \ NetworkGeolocationProvider.js \
NetworkGeolocationProvider.manifest \ NetworkGeolocationProvider.manifest \
GPSDGeolocationProvider.js \
GPSDGeolocationProvider.manifest \
$(NULL) $(NULL)
endif endif

View File

@ -2799,7 +2799,7 @@ DrawTargetD2D::PushD2DLayer(ID2D1RenderTarget *aRT, ID2D1Geometry *aGeometry, ID
D2D1_LAYER_OPTIONS options = D2D1_LAYER_OPTIONS_NONE; D2D1_LAYER_OPTIONS options = D2D1_LAYER_OPTIONS_NONE;
D2D1_LAYER_OPTIONS1 options1 = D2D1_LAYER_OPTIONS1_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; options = D2D1_LAYER_OPTIONS_INITIALIZE_FOR_CLEARTYPE;
options1 = D2D1_LAYER_OPTIONS1_IGNORE_ALPHA | D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND; options1 = D2D1_LAYER_OPTIONS1_IGNORE_ALPHA | D2D1_LAYER_OPTIONS1_INITIALIZE_FROM_BACKGROUND;
} }

View File

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

View File

@ -73,12 +73,33 @@ void ImageContainerChild::SetIdleNow()
mImageQueue.Clear(); 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 (mStop) return;
if (InImageBridgeChildThread()) {
return SetIdleNow();
}
Monitor barrier("SetIdle Lock");
MonitorAutoLock autoMon(barrier);
bool done = false;
GetMessageLoop()->PostTask(FROM_HERE, GetMessageLoop()->PostTask(FROM_HERE,
NewRunnableMethod(this, &ImageContainerChild::SetIdleNow)); NewRunnableMethod(this, &ImageContainerChild::SetIdleSync, &barrier, &done));
while (!done) {
barrier.Wait();
}
} }
void ImageContainerChild::StopChildAndParent() void ImageContainerChild::StopChildAndParent()

View File

@ -106,16 +106,9 @@ public:
void DispatchDestroy(); void DispatchDestroy();
/** /**
* Dispatches a task on the ImageBridgeChild's thread that will call SendFlush * Flush and deallocate the shared images in the pool.
* and deallocate the shared images in the pool.
* Can be called on any thread.
*/ */
void DispatchSetIdle(); void SetIdle();
/**
* Must be called on the ImageBridgeChild's thread.
*/
void SetIdleNow();
/** /**
* Can be called from any thread. * 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(); 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) 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 // 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). // 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 // After receiving this message, the ImageContainerParent will not return images
// back to the child side (to avoid a race between ReturnImage and __delete__) // 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) NS_IMPL_THREADSAFE_ISUPPORTS2(jsdScript, jsdIScript, jsdIEphemeral)
static NS_IMETHODIMP static NS_IMETHODIMP
AssignToJSString(nsACString *x, JSString *str) AssignToJSString(JSDContext *aCx, nsACString *x, JSString *str)
{ {
if (!str) { if (!str) {
x->SetLength(0); x->SetLength(0);
return NS_OK; 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)) if (length == size_t(-1))
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
x->SetLength(uint32_t(length)); x->SetLength(uint32_t(length));
if (x->Length() != uint32_t(length)) if (x->Length() != uint32_t(length))
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
JS_EncodeStringToBuffer(str, x->BeginWriting(), length); JS_EncodeStringToBuffer(cx, str, x->BeginWriting(), length);
return NS_OK; return NS_OK;
} }
@ -953,7 +954,7 @@ jsdScript::jsdScript (JSDContext *aCx, JSDScript *aScript) : mValid(false),
if (mFunctionName) { if (mFunctionName) {
JSString *str = JSD_GetScriptFunctionId(mCx, mScript); JSString *str = JSD_GetScriptFunctionId(mCx, mScript);
if (str) if (str)
AssignToJSString(mFunctionName, str); AssignToJSString(mCx, mFunctionName, str);
} }
mBaseLineNumber = JSD_GetScriptBaseLineNumber(mCx, mScript); mBaseLineNumber = JSD_GetScriptBaseLineNumber(mCx, mScript);
mLineExtent = JSD_GetScriptLineExtent(mCx, mScript); mLineExtent = JSD_GetScriptLineExtent(mCx, mScript);
@ -1908,7 +1909,7 @@ jsdStackFrame::GetFunctionName(nsACString &_rval)
ASSERT_VALID_EPHEMERAL; ASSERT_VALID_EPHEMERAL;
JSString *str = JSD_GetIdForStackFrame(mCx, mThreadState, mStackFrameInfo); JSString *str = JSD_GetIdForStackFrame(mCx, mThreadState, mStackFrameInfo);
if (str) if (str)
return AssignToJSString(&_rval, str); return AssignToJSString(mCx, &_rval, str);
_rval.Assign("anonymous"); _rval.Assign("anonymous");
return NS_OK; return NS_OK;
@ -2238,7 +2239,7 @@ NS_IMETHODIMP
jsdValue::GetJsFunctionName(nsACString &_rval) jsdValue::GetJsFunctionName(nsACString &_rval)
{ {
ASSERT_VALID_EPHEMERAL; ASSERT_VALID_EPHEMERAL;
return AssignToJSString(&_rval, JSD_GetValueFunctionId(mCx, mValue)); return AssignToJSString(mCx, &_rval, JSD_GetValueFunctionId(mCx, mValue));
} }
NS_IMETHODIMP 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 \ String.cpp \
BytecodeCompiler.cpp \ BytecodeCompiler.cpp \
BytecodeEmitter.cpp \ BytecodeEmitter.cpp \
CharacterEncoding.cpp \
FoldConstants.cpp \ FoldConstants.cpp \
Intl.cpp \ Intl.cpp \
NameFunctions.cpp \ NameFunctions.cpp \
@ -216,6 +217,7 @@ EXPORTS_NAMESPACES += js
# that we ensure we don't over-expose our internal integer typedefs. Note that # that we ensure we don't over-expose our internal integer typedefs. Note that
# LegacyIntTypes.h below is deliberately exempted from this requirement. # LegacyIntTypes.h below is deliberately exempted from this requirement.
EXPORTS_js = \ EXPORTS_js = \
CharacterEncoding.h \
HashTable.h \ HashTable.h \
HeapAPI.h \ HeapAPI.h \
LegacyIntTypes.h \ LegacyIntTypes.h \

View File

@ -9,6 +9,7 @@
from __future__ import with_statement from __future__ import with_statement
from optparse import OptionParser from optparse import OptionParser
import sys, re, os, posixpath, ntpath import sys, re, os, posixpath, ntpath
import errno
from StringIO import StringIO from StringIO import StringIO
# Standalone js doesn't have virtualenv. # Standalone js doesn't have virtualenv.
sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'config')) 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; int valcnt = 0;
if (shape) { if (shape) {
bool doGet = true; bool doGet = true;
if (obj2->isNative() && !IsImplicitProperty(shape)) { if (obj2->isNative() && !IsImplicitDenseElement(shape)) {
unsigned attrs = shape->attributes(); unsigned attrs = shape->attributes();
if (attrs & JSPROP_GETTER) { if (attrs & JSPROP_GETTER) {
doGet = false; doGet = false;
@ -456,7 +456,7 @@ obj_lookupGetter(JSContext *cx, unsigned argc, Value *vp)
return JS_FALSE; return JS_FALSE;
args.rval().setUndefined(); args.rval().setUndefined();
if (shape) { if (shape) {
if (pobj->isNative() && !IsImplicitProperty(shape)) { if (pobj->isNative() && !IsImplicitDenseElement(shape)) {
if (shape->hasGetterValue()) if (shape->hasGetterValue())
args.rval().set(shape->getterValue()); args.rval().set(shape->getterValue());
} }
@ -492,7 +492,7 @@ obj_lookupSetter(JSContext *cx, unsigned argc, Value *vp)
return JS_FALSE; return JS_FALSE;
args.rval().setUndefined(); args.rval().setUndefined();
if (shape) { if (shape) {
if (pobj->isNative() && !IsImplicitProperty(shape)) { if (pobj->isNative() && !IsImplicitDenseElement(shape)) {
if (shape->hasSetterValue()) if (shape->hasSetterValue())
args.rval().set(shape->setterValue()); 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. // No prototype walking for elements.
if (index < as(obj)->outermostDimension()) { if (index < as(obj)->outermostDimension()) {
MarkImplicitPropertyFound(propp); MarkNonNativePropertyFound(propp);
objp.set(obj); objp.set(obj);
return true; return true;
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -1435,6 +1435,9 @@ IsPropertySetterCallInlineable(JSContext *cx, HandleObject obj, HandleObject hol
if (!shape) if (!shape)
return false; return false;
if (!holder->isNative())
return false;
if (shape->hasSlot()) if (shape->hasSlot())
return false; 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 \ testStringBuffer.cpp \
testTrap.cpp \ testTrap.cpp \
testTypedArrays.cpp \ testTypedArrays.cpp \
testUTF8.cpp \
testVersion.cpp \ testVersion.cpp \
testXDR.cpp \ testXDR.cpp \
$(NULL) $(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 "frontend/BytecodeCompiler.h"
#include "gc/Marking.h" #include "gc/Marking.h"
#include "gc/Memory.h" #include "gc/Memory.h"
#include "js/CharacterEncoding.h"
#include "js/MemoryMetrics.h" #include "js/MemoryMetrics.h"
#include "vm/Debugger.h" #include "vm/Debugger.h"
#include "vm/NumericConversions.h" #include "vm/NumericConversions.h"
@ -3572,7 +3573,7 @@ LookupResult(JSContext *cx, HandleObject obj, HandleObject obj2, jsid id,
return JS_TRUE; return JS_TRUE;
} }
if (IsImplicitProperty(shape)) { if (!obj2->isNative()) {
if (obj2->isProxy()) { if (obj2->isProxy()) {
AutoPropertyDescriptorRooter desc(cx); AutoPropertyDescriptorRooter desc(cx);
if (!Proxy::getPropertyDescriptor(cx, obj2, id, &desc, 0)) if (!Proxy::getPropertyDescriptor(cx, obj2, id, &desc, 0))
@ -3581,10 +3582,10 @@ LookupResult(JSContext *cx, HandleObject obj, HandleObject obj2, jsid id,
*vp = desc.value; *vp = desc.value;
return true; 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 { } else {
/* Peek at the native property's slot value, without doing a Get. */ /* Peek at the native property's slot value, without doing a Get. */
if (shape->hasSlot()) { if (shape->hasSlot()) {
@ -4062,7 +4063,7 @@ GetPropertyDescriptorById(JSContext *cx, HandleObject obj, HandleId id, unsigned
desc->obj = obj2; desc->obj = obj2;
if (obj2->isNative()) { if (obj2->isNative()) {
if (IsImplicitProperty(shape)) { if (IsImplicitDenseElement(shape)) {
desc->attrs = JSPROP_ENUMERATE; desc->attrs = JSPROP_ENUMERATE;
desc->getter = NULL; desc->getter = NULL;
desc->setter = 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_PUBLIC_API(char *)
JS_EncodeString(JSContext *cx, JSRawString strArg) JS_EncodeString(JSContext *cx, JSRawString str)
{ {
RootedString str(cx, strArg); AutoAssertNoGC nogc;
AssertHeapIsIdle(cx); AssertHeapIsIdle(cx);
CHECK_REQUEST(cx); CHECK_REQUEST(cx);
const jschar *chars = str->getChars(cx); JSLinearString *linear = str->ensureLinear(cx);
if (!chars) if (!linear)
return NULL; return NULL;
return DeflateString(cx, chars, str->length());
return LossyTwoByteCharsToNewLatin1CharsZ(cx, linear->range()).c_str();
} }
JS_PUBLIC_API(size_t) JS_PUBLIC_API(size_t)
JS_GetStringEncodingLength(JSContext *cx, JSString *str) JS_GetStringEncodingLength(JSContext *cx, JSString *str)
{ {
/* jsd calls us with a NULL cx. Ugh. */ AssertHeapIsIdle(cx);
if (cx) { CHECK_REQUEST(cx);
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
}
const jschar *chars = str->getChars(cx); const jschar *chars = str->getChars(cx);
if (!chars) if (!chars)
@ -6260,8 +6258,11 @@ JS_GetStringEncodingLength(JSContext *cx, JSString *str)
} }
JS_PUBLIC_API(size_t) 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 * FIXME bug 612141 - fix DeflateStringToBuffer interface so the result
* would allow to distinguish between insufficient buffer and encoding * 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. * written into the buffer.
*/ */
JS_PUBLIC_API(size_t) 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 class JSAutoByteString
{ {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -27,6 +27,7 @@
#include "frontend/Parser.h" #include "frontend/Parser.h"
#include "frontend/TokenStream.h" #include "frontend/TokenStream.h"
#include "js/CharacterEncoding.h"
#include "vm/RegExpObject.h" #include "vm/RegExpObject.h"
#include "jsscriptinlines.h" #include "jsscriptinlines.h"
@ -3442,7 +3443,8 @@ reflect_parse(JSContext *cx, uint32_t argc, jsval *vp)
if (!chars) if (!chars)
return JS_FALSE; return JS_FALSE;
filename = DeflateString(cx, chars, length); TwoByteChars tbchars(chars, length);
filename = LossyTwoByteCharsToNewLatin1CharsZ(cx, tbchars).c_str();
if (!filename) if (!filename)
return JS_FALSE; 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 * 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 * signify that the property has been found. For cases where the property is
* not actually represented by a Shape (dense elements, properties of * not actually represented by a Shape, use a dummy value. This includes all
* non-native objects), use a dummy value. * properties of non-native objects, and dense elements for native objects.
* Use separate APIs for these two cases.
*/ */
static inline void 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)); propp.set(reinterpret_cast<Shape*>(1));
} }
static inline bool static inline bool
IsImplicitProperty(HandleShape prop) IsImplicitDenseElement(HandleShape prop)
{ {
return prop.get() == reinterpret_cast<Shape*>(1); return prop.get() == reinterpret_cast<Shape*>(1);
} }
@ -514,7 +522,7 @@ IsImplicitProperty(HandleShape prop)
static inline uint8_t static inline uint8_t
GetShapeAttributes(HandleShape shape) GetShapeAttributes(HandleShape shape)
{ {
return IsImplicitProperty(shape) ? JSPROP_ENUMERATE : shape->attributes(); return IsImplicitDenseElement(shape) ? JSPROP_ENUMERATE : shape->attributes();
} }
} /* namespace js */ } /* namespace js */

View File

@ -2342,6 +2342,116 @@ BuildDollarReplacement(JSContext *cx, JSString *textstrArg, JSLinearString *reps
return true; 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 static inline bool
str_replace_regexp(JSContext *cx, CallArgs args, ReplaceData &rdata) 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(); RegExpStatics *res = cx->regExpStatics();
RegExpShared &re = rdata.g.regExp(); 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; Value tmp;
if (!DoMatch(cx, res, rdata.str, re, ReplaceRegExpCallback, &rdata, REPLACE_ARGS, &tmp)) if (!DoMatch(cx, res, rdata.str, re, ReplaceRegExpCallback, &rdata, REPLACE_ARGS, &tmp))
return false; return false;
@ -3726,25 +3842,6 @@ js::InflateUTF8String(JSContext *cx, const char *bytes, size_t *lengthp)
return NULL; 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 size_t
js::GetDeflatedStringLength(JSContext *cx, const jschar *chars, size_t nchars) 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 * extern jschar *
InflateUTF8String(JSContext *cx, const char *bytes, size_t *length); 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 * Inflate bytes to JS chars in an existing buffer. 'chars' must be large
* enough for 'length' jschars. The buffer is NOT null-terminated. * 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()); JS_ASSERT(tarray->isTypedArray());
if (isArrayIndex(tarray, id)) { if (isArrayIndex(tarray, id)) {
MarkImplicitPropertyFound(propp); MarkNonNativePropertyFound(propp);
objp.set(tarray); objp.set(tarray);
return true; return true;
} }
@ -1045,7 +1045,7 @@ TypedArray::obj_lookupElement(JSContext *cx, HandleObject tarray, uint32_t index
JS_ASSERT(tarray->isTypedArray()); JS_ASSERT(tarray->isTypedArray());
if (index < length(tarray)) { if (index < length(tarray)) {
MarkImplicitPropertyFound(propp); MarkNonNativePropertyFound(propp);
objp.set(tarray); objp.set(tarray);
return true; return true;
} }

View File

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

View File

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

View File

@ -20,6 +20,8 @@
#include "jsinterpinlines.h" #include "jsinterpinlines.h"
#include "jsautooplen.h" #include "jsautooplen.h"
#include "js/CharacterEncoding.h"
#include "vm/ScopeObject-inl.h" #include "vm/ScopeObject-inl.h"
#include "vm/StringObject-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); CodeLocationLabel cs = buffer.finalize(f);
#if DEBUG #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", 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, (void*)holder->lastProperty(), cx->fp()->script()->filename,
CurrentLine(cx)); CurrentLine(cx));
js_free(chars); JS_free(latin1);
#endif #endif
// Update the inline guards, if needed. // Update the inline guards, if needed.

View File

@ -2440,47 +2440,6 @@ ToInt32(JSContext *cx, unsigned argc, jsval *vp)
return true; 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 static JSBool
ThrowError(JSContext *cx, unsigned argc, jsval *vp) ThrowError(JSContext *cx, unsigned argc, jsval *vp)
{ {
@ -3740,10 +3699,6 @@ static JSFunctionSpecWithHelp shell_functions[] = {
"pc2line(fun[, pc])", "pc2line(fun[, pc])",
" Map PC to line number."), " 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, JS_FN_HELP("throwError", ThrowError, 0, 0,
"throwError()", "throwError()",
" Throw an error from JS_ReportError."), " 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); js_delete<BytecodePattern>(bytecode);
} }
void
RegExpShared::trace(JSTracer *trc)
{
MarkStringUnbarriered(trc, &source, "regexpshared source");
}
void void
RegExpShared::reportYarrError(JSContext *cx, TokenStream *ts, ErrorCode error) RegExpShared::reportYarrError(JSContext *cx, TokenStream *ts, ErrorCode error)
{ {
@ -651,6 +645,18 @@ RegExpCompartment::RegExpCompartment(JSRuntime *rt)
RegExpCompartment::~RegExpCompartment() RegExpCompartment::~RegExpCompartment()
{ {
JS_ASSERT(map_.empty()); 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()); JS_ASSERT(inUse_.empty());
} }

View File

@ -14,6 +14,8 @@
#include "jscntxt.h" #include "jscntxt.h"
#include "jsobj.h" #include "jsobj.h"
#include "gc/Barrier.h"
#include "gc/Marking.h"
#include "js/TemplateLib.h" #include "js/TemplateLib.h"
#include "vm/MatchPairs.h" #include "vm/MatchPairs.h"
@ -120,11 +122,12 @@ class RegExpShared
#endif #endif
/* /*
* Source to the RegExp. The RegExpShared must either be protected by a * Source to the RegExp, for lazy compilation.
* RegExpGuard, which handles rooting for stacky RegExpShareds, * The source must be rooted while activeUseCount is non-zero
* or trace() must be explicitly called during marking. * via RegExpGuard, RegExpHeapGuard, or explicit calls to trace().
*/ */
JSAtom * source; JSAtom * source;
RegExpFlag flags; RegExpFlag flags;
unsigned parenCount; unsigned parenCount;
@ -149,7 +152,10 @@ class RegExpShared
RegExpShared(JSRuntime *rt, JSAtom *source, RegExpFlag flags); RegExpShared(JSRuntime *rt, JSAtom *source, RegExpFlag flags);
~RegExpShared(); ~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 functions to expose some Yarr logic. */
static inline bool isJITRuntimeEnabled(JSContext *cx); static inline bool isJITRuntimeEnabled(JSContext *cx);
@ -222,17 +228,58 @@ class RegExpGuard
re_->incRef(); re_->incRef();
} }
~RegExpGuard() { ~RegExpGuard() { release(); }
if (re_)
re_->decRef();
}
public: public:
void init(RegExpShared &re) { void init(RegExpShared &re) {
JS_ASSERT(!re_); JS_ASSERT(!initialized());
re_ = &re; re_ = &re;
re_->incRef(); 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_; } bool initialized() const { return !!re_; }
@ -246,9 +293,12 @@ class RegExpCompartment
struct Key { struct Key {
JSAtom *atom; JSAtom *atom;
uint16_t flag; uint16_t flag;
Key() {} Key() {}
Key(JSAtom *atom, RegExpFlag flag) Key(JSAtom *atom, RegExpFlag flag)
: atom(atom), flag(flag) {} : atom(atom), flag(flag)
{ }
typedef Key Lookup; typedef Key Lookup;
static HashNumber hash(const Lookup &l) { static HashNumber hash(const Lookup &l) {
return DefaultHasher<JSAtom *>::hash(l.atom) ^ (l.flag << 1); 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()); return mallocSizeOf(obj->getPrivate());
} }
inline
RegExpStatics::RegExpStatics()
: pendingLazyEvaluation(false),
bufferLink(NULL),
copied(false)
{
clear();
}
inline bool inline bool
RegExpStatics::createDependent(JSContext *cx, size_t start, size_t end, Value *out) RegExpStatics::createDependent(JSContext *cx, size_t start, size_t end, Value *out)
{ {
@ -231,15 +222,20 @@ RegExpStatics::copyTo(RegExpStatics &dst)
if (!pendingLazyEvaluation) if (!pendingLazyEvaluation)
dst.matches.initArrayFrom(matches); dst.matches.initArrayFrom(matches);
if (regexp.initialized())
dst.regexp.init(*regexp);
else
dst.regexp.release();
dst.matchesInput = matchesInput; dst.matchesInput = matchesInput;
dst.regexp = regexp;
dst.lastIndex = lastIndex; dst.lastIndex = lastIndex;
dst.pendingInput = pendingInput; dst.pendingInput = pendingInput;
dst.flags = flags; dst.flags = flags;
dst.pendingLazyEvaluation = pendingLazyEvaluation; dst.pendingLazyEvaluation = pendingLazyEvaluation;
JS_ASSERT_IF(pendingLazyEvaluation, regexp); JS_ASSERT_IF(pendingLazyEvaluation, regexp.initialized());
JS_ASSERT_IF(pendingLazyEvaluation, matchesInput); JS_ASSERT_IF(pendingLazyEvaluation, matchesInput);
JS_ASSERT(regexp.initialized() == dst.regexp.initialized());
} }
inline void inline void
@ -261,17 +257,20 @@ RegExpStatics::restore()
inline void inline void
RegExpStatics::updateLazily(JSContext *cx, JSLinearString *input, 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(); aboutToWrite();
BarrieredSetPair<JSString, JSLinearString>(cx->compartment, BarrieredSetPair<JSString, JSLinearString>(cx->compartment,
pendingInput, input, pendingInput, input,
matchesInput, input); matchesInput, input);
pendingLazyEvaluation = true; if (regexp.initialized())
this->regexp = regexp; regexp.release();
regexp.init(*shared);
this->lastIndex = lastIndex; this->lastIndex = lastIndex;
pendingLazyEvaluation = true;
} }
inline bool inline bool
@ -282,7 +281,7 @@ RegExpStatics::updateFromMatchPairs(JSContext *cx, JSLinearString *input, MatchP
/* Unset all lazy state. */ /* Unset all lazy state. */
pendingLazyEvaluation = false; pendingLazyEvaluation = false;
this->regexp = NULL; this->regexp.release();
this->lastIndex = size_t(-1); this->lastIndex = size_t(-1);
BarrieredSetPair<JSString, JSLinearString>(cx->compartment, BarrieredSetPair<JSString, JSLinearString>(cx->compartment,
@ -301,11 +300,14 @@ inline void
RegExpStatics::clear() RegExpStatics::clear()
{ {
aboutToWrite(); aboutToWrite();
flags = RegExpFlag(0);
pendingInput = NULL;
pendingLazyEvaluation = false;
matchesInput = NULL;
matches.forgetArray(); matches.forgetArray();
matchesInput = NULL;
regexp.release();
lastIndex = size_t(-1);
pendingInput = NULL;
flags = RegExpFlag(0);
pendingLazyEvaluation = false;
} }
inline void inline void
@ -363,8 +365,9 @@ RegExpStatics::checkInvariants()
{ {
#ifdef DEBUG #ifdef DEBUG
if (pendingLazyEvaluation) { if (pendingLazyEvaluation) {
JS_ASSERT(regexp); JS_ASSERT(regexp.initialized());
JS_ASSERT(pendingInput); JS_ASSERT(pendingInput);
JS_ASSERT(lastIndex != size_t(-1));
return; return;
} }

View File

@ -74,7 +74,7 @@ RegExpStatics::executeLazy(JSContext *cx)
if (!pendingLazyEvaluation) if (!pendingLazyEvaluation)
return true; return true;
JS_ASSERT(regexp); JS_ASSERT(regexp.initialized());
JS_ASSERT(matchesInput); JS_ASSERT(matchesInput);
JS_ASSERT(lastIndex != size_t(-1)); JS_ASSERT(lastIndex != size_t(-1));
@ -87,17 +87,20 @@ RegExpStatics::executeLazy(JSContext *cx)
StableCharPtr chars(matchesInput->chars(), length); StableCharPtr chars(matchesInput->chars(), length);
/* Execute the full regular expression. */ /* Execute the full regular expression. */
RegExpGuard shared(cx); RegExpRunStatus status = regexp->execute(cx, chars, length, &this->lastIndex, this->matches);
if (!regexp->getShared(cx, &shared))
return false;
RegExpRunStatus status = shared->execute(cx, chars, length, &this->lastIndex, this->matches);
if (status == RegExpRunStatus_Error) if (status == RegExpRunStatus_Error)
return false; 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. */ /* Unset lazy state and remove rooted values that now have no use. */
pendingLazyEvaluation = false; pendingLazyEvaluation = false;
regexp = NULL; regexp.release();
lastIndex = size_t(-1);
return true; return true;
} }

View File

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

View File

@ -11,6 +11,8 @@
#include "mozilla/Attributes.h" #include "mozilla/Attributes.h"
#include "mozilla/GuardObjects.h" #include "mozilla/GuardObjects.h"
#include "js/CharacterEncoding.h"
#include "jsapi.h" #include "jsapi.h"
#include "jsatom.h" #include "jsatom.h"
#include "jsfriendapi.h" #include "jsfriendapi.h"
@ -477,6 +479,11 @@ class JSLinearString : public JSString
JS_ASSERT(JSString::isLinear()); JS_ASSERT(JSString::isLinear());
return d.u1.chars; 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)); JS_STATIC_ASSERT(sizeof(JSLinearString) == sizeof(JSString));

View File

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

View File

@ -122,7 +122,7 @@ XPCJSStackFrame::CreateStack(JSContext* cx, XPCJSStackFrame** stack)
if (length != size_t(-1)) { if (length != size_t(-1)) {
self->mFunname = static_cast<char *>(nsMemory::Alloc(length + 1)); self->mFunname = static_cast<char *>(nsMemory::Alloc(length + 1));
if (self->mFunname) { if (self->mFunname) {
JS_EncodeStringToBuffer(funid, self->mFunname, length); JS_EncodeStringToBuffer(cx, funid, self->mFunname, length);
self->mFunname[length] = '\0'; 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 skip-if(B2G) == 818276-1.html 818276-1-ref.html
== 827577-1a.html 827577-1-ref.html == 827577-1a.html 827577-1-ref.html
== 827577-1b.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. commit a6d05eb5.
It consists in the audio resampling code (resampler.c) and its header files 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 dependancies, imported into the tree using the update.sh script.
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; spx_uint32_t i;
int istride_save, ostride_save; 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; istride_save = st->in_stride;
ostride_save = st->out_stride; ostride_save = st->out_stride;
st->in_stride = st->out_stride = st->nb_channels; st->in_stride = st->out_stride = st->nb_channels;
for (i=0;i<st->nb_channels;i++) 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) if (in != NULL)
speex_resampler_process_float(st, i, in+i, in_len, out+i, out_len); speex_resampler_process_float(st, i, in+i, in_len, out+i, out_len);
else else
@ -981,13 +983,15 @@ EXPORT int speex_resampler_process_interleaved_int(SpeexResamplerState *st, cons
{ {
spx_uint32_t i; spx_uint32_t i;
int istride_save, ostride_save; 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; istride_save = st->in_stride;
ostride_save = st->out_stride; ostride_save = st->out_stride;
st->in_stride = st->out_stride = st->nb_channels; st->in_stride = st->out_stride = st->nb_channels;
for (i=0;i<st->nb_channels;i++) 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) if (in != NULL)
speex_resampler_process_int(st, i, in+i, in_len, out+i, out_len); speex_resampler_process_int(st, i, in+i, in_len, out+i, out_len);
else 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 # Copies the needed files from a directory containing the original
# libspeex sources that we need for HTML5 media playback rate change. # libspeex sources that we need for HTML5 media playback rate change.
cp $1/libspeex/resample.c src cp $1/libspeex/resample.c src
cp $1/libspeex/arch.h src cp $1/libspeex/arch.h src
cp $1/libspeex/stack_alloc.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 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/AUTHORS .
cp $1/COPYING . cp $1/COPYING .
# apply outstanding local patches
patch -p1 < truncation.patch

View File

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

View File

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

View File

@ -12,6 +12,8 @@
#include "prlock.h" #include "prlock.h"
#include "mozilla/RefPtr.h" #include "mozilla/RefPtr.h"
#include "nsWeakPtr.h"
#include "nsIWeakReferenceUtils.h" // for the definition of nsWeakPtr
#include "IPeerConnection.h" #include "IPeerConnection.h"
#include "nsComponentManagerUtils.h" #include "nsComponentManagerUtils.h"
#include "nsPIDOMWindow.h" #include "nsPIDOMWindow.h"
@ -230,7 +232,9 @@ private:
IceState mIceState; IceState mIceState;
nsCOMPtr<nsIThread> mThread; 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; nsCOMPtr<nsPIDOMWindow> mWindow;
// The SDP sent in from JS - here for debugging. // 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; cc_sdp_t *sdp_p = dcb_p->sdp;
uint16_t media_attr; uint16_t media_attr;
uint16_t i; uint16_t i;
uint32 port;
int sdpmode = 0;
static const sdp_attr_e dir_attr_array[] = { static const sdp_attr_e dir_attr_array[] = {
SDP_ATTR_INACTIVE, SDP_ATTR_INACTIVE,
SDP_ATTR_RECVONLY, SDP_ATTR_RECVONLY,
@ -1791,6 +1793,8 @@ gsmsdp_get_remote_sdp_direction (fsmdef_dcb_t *dcb_p, uint16_t level,
return direction; return direction;
} }
config_get_value(CFGID_SDPMODE, &sdpmode, sizeof(sdpmode));
media_attr = 0; /* media level attr. count */ media_attr = 0; /* media level attr. count */
/* /*
* Now check for direction as a media attribute. If found, the * 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 && if (dest_addr->type == CPR_IP_ADDR_IPV4 &&
dest_addr->u.ip4 == 0) { 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; direction = SDP_DIRECTION_INACTIVE;
} else { } else {

View File

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

View File

@ -23,9 +23,11 @@ using namespace std;
#include "FakeMediaStreams.h" #include "FakeMediaStreams.h"
#include "FakeMediaStreamsImpl.h" #include "FakeMediaStreamsImpl.h"
#include "PeerConnectionImpl.h" #include "PeerConnectionImpl.h"
#include "PeerConnectionCtx.h"
#include "runnable_utils.h" #include "runnable_utils.h"
#include "nsStaticComponents.h" #include "nsStaticComponents.h"
#include "nsIDOMRTCPeerConnection.h" #include "nsIDOMRTCPeerConnection.h"
#include "nsWeakReference.h"
#include "mtransport_test_utils.h" #include "mtransport_test_utils.h"
MtransportTestUtils *test_utils; MtransportTestUtils *test_utils;
@ -118,7 +120,8 @@ enum offerAnswerFlags
}; };
class TestObserver : public IPeerConnectionObserver class TestObserver : public IPeerConnectionObserver,
public nsSupportsWeakReference
{ {
public: public:
enum Action { enum Action {
@ -163,7 +166,9 @@ private:
std::vector<nsDOMMediaStream *> streams; std::vector<nsDOMMediaStream *> streams;
}; };
NS_IMPL_THREADSAFE_ISUPPORTS1(TestObserver, IPeerConnectionObserver) NS_IMPL_THREADSAFE_ISUPPORTS2(TestObserver,
IPeerConnectionObserver,
nsISupportsWeakReference)
NS_IMETHODIMP NS_IMETHODIMP
TestObserver::OnCreateOfferSuccess(const char* offer) TestObserver::OnCreateOfferSuccess(const char* offer)
@ -489,7 +494,7 @@ class SignalingAgent {
NS_DISPATCH_SYNC); NS_DISPATCH_SYNC);
} }
void Init(nsCOMPtr<nsIThread> thread) void Init_m(nsCOMPtr<nsIThread> thread)
{ {
size_t found = 2; size_t found = 2;
ASSERT_TRUE(found > 0); ASSERT_TRUE(found > 0);
@ -502,6 +507,14 @@ class SignalingAgent {
ASSERT_EQ(pc->Initialize(pObserver, nullptr, thread), NS_OK); 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, ASSERT_TRUE_WAIT(sipcc_state() == sipcc::PeerConnectionImpl::kStarted,
kDefaultTimeout); kDefaultTimeout);
ASSERT_TRUE_WAIT(ice_state() == sipcc::PeerConnectionImpl::kIceWaiting, 5000); ASSERT_TRUE_WAIT(ice_state() == sipcc::PeerConnectionImpl::kIceWaiting, 5000);
@ -592,14 +605,18 @@ class SignalingAgent {
// Now call CreateOffer as JS would // Now call CreateOffer as JS would
pObserver->state = TestObserver::stateNoResponse; pObserver->state = TestObserver::stateNoResponse;
ASSERT_EQ(pc->CreateOffer(constraints), NS_OK); 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); SDPSanityCheck(pObserver->lastString, sdpCheck, true);
offer_ = pObserver->lastString; offer_ = pObserver->lastString;
} }
void CreateOfferExpectError(sipcc::MediaConstraints& constraints) { void CreateOfferExpectError(sipcc::MediaConstraints& constraints) {
ASSERT_EQ(pc->CreateOffer(constraints), NS_OK); 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, void CreateAnswer(sipcc::MediaConstraints& constraints, std::string offer,
@ -628,7 +645,9 @@ void CreateAnswer(sipcc::MediaConstraints& constraints, std::string offer,
pObserver->state = TestObserver::stateNoResponse; pObserver->state = TestObserver::stateNoResponse;
ASSERT_EQ(pc->CreateAnswer(constraints), NS_OK); 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); SDPSanityCheck(pObserver->lastString, sdpCheck, false);
answer_ = pObserver->lastString; answer_ = pObserver->lastString;
@ -653,7 +672,9 @@ void CreateAnswer(sipcc::MediaConstraints& constraints, std::string offer,
// Now call CreateOffer as JS would // Now call CreateOffer as JS would
pObserver->state = TestObserver::stateNoResponse; pObserver->state = TestObserver::stateNoResponse;
ASSERT_EQ(pc->CreateOffer(constraints), NS_OK); 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); SDPSanityCheck(pObserver->lastString, sdpCheck, true);
offer_ = pObserver->lastString; offer_ = pObserver->lastString;
} }
@ -661,13 +682,17 @@ void CreateAnswer(sipcc::MediaConstraints& constraints, std::string offer,
void SetRemote(TestObserver::Action action, std::string remote) { void SetRemote(TestObserver::Action action, std::string remote) {
pObserver->state = TestObserver::stateNoResponse; pObserver->state = TestObserver::stateNoResponse;
ASSERT_EQ(pc->SetRemoteDescription(action, remote.c_str()), NS_OK); 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) { void SetLocal(TestObserver::Action action, std::string local) {
pObserver->state = TestObserver::stateNoResponse; pObserver->state = TestObserver::stateNoResponse;
ASSERT_EQ(pc->SetLocalDescription(action, local.c_str()), NS_OK); 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) { void DoTrickleIce(ParsedSDP &sdp) {
@ -734,6 +759,7 @@ public:
private: private:
void SDPSanityCheck(std::string sdp, uint32_t flags, bool offer) 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("v=0"), std::string::npos);
ASSERT_NE(sdp.find("c=IN IP4"), std::string::npos); ASSERT_NE(sdp.find("c=IN IP4"), std::string::npos);
ASSERT_NE(sdp.find("a=fingerprint:sha-256"), 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()); 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. } // End namespace test.
int main(int argc, char **argv) { int main(int argc, char **argv) {
@ -1720,6 +1772,13 @@ int main(int argc, char **argv) {
::testing::AddGlobalTestEnvironment(new test::SignalingEnvironment); ::testing::AddGlobalTestEnvironment(new test::SignalingEnvironment);
int result = RUN_ALL_TESTS(); 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; delete test_utils;
return result; 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; T* const rangeEnd;
#endif #endif
typedef void (RangedPtr::* ConvertibleToBool)();
void nonNull() {}
void checkSanity() { void checkSanity() {
MOZ_ASSERT(rangeStart <= ptr); MOZ_ASSERT(rangeStart <= ptr);
MOZ_ASSERT(ptr <= rangeEnd); MOZ_ASSERT(ptr <= rangeEnd);
@ -97,7 +100,7 @@ class RangedPtr
/* Equivalent to RangedPtr(arr, arr, N). */ /* Equivalent to RangedPtr(arr, arr, N). */
template<size_t N> template<size_t N>
RangedPtr(T arr[N]) RangedPtr(T (&arr)[N])
: ptr(arr) : ptr(arr)
#ifdef DEBUG #ifdef DEBUG
, rangeStart(arr), rangeEnd(arr + N) , rangeStart(arr), rangeEnd(arr + N)
@ -110,6 +113,8 @@ class RangedPtr
return ptr; return ptr;
} }
operator ConvertibleToBool() const { return ptr ? &RangedPtr::nonNull : 0; }
/* /*
* You can only assign one RangedPtr into another if the two pointers have * You can only assign one RangedPtr into another if the two pointers have
* the same valid range: * the same valid range:
@ -242,7 +247,6 @@ class RangedPtr
private: private:
RangedPtr() MOZ_DELETE; RangedPtr() MOZ_DELETE;
T* operator&() MOZ_DELETE; T* operator&() MOZ_DELETE;
operator T*() const MOZ_DELETE;
}; };
} /* namespace mozilla */ } /* namespace mozilla */

View File

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

View File

@ -46,7 +46,6 @@ DEFINES += \
-DAPP_NAME=$(MOZ_APP_NAME) \ -DAPP_NAME=$(MOZ_APP_NAME) \
-DAPP_VERSION=$(MOZ_APP_VERSION) \ -DAPP_VERSION=$(MOZ_APP_VERSION) \
-DMOZ_UPDATER=$(MOZ_UPDATER) \ -DMOZ_UPDATER=$(MOZ_UPDATER) \
-DMOZ_APP_UA_NAME=$(MOZ_APP_UA_NAME) \
$(NULL) $(NULL)
ifdef MOZ_PKG_SPECIAL 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.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.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 // Name of the about: page contributed by safebrowsing to handle display of error
// pages on phishing/malware hits. (bug 399233) // pages on phishing/malware hits. (bug 399233)
pref("urlclassifier.alternate_error_page", "blocked"); pref("urlclassifier.alternate_error_page", "blocked");

View File

@ -39,4 +39,14 @@ EXTRA_COMPONENTS = \
BlocklistPrompt.js \ BlocklistPrompt.js \
$(NULL) $(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 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/nsDownloadManagerUI.js
@BINPATH@/components/NetworkGeolocationProvider.manifest @BINPATH@/components/NetworkGeolocationProvider.manifest
@BINPATH@/components/NetworkGeolocationProvider.js @BINPATH@/components/NetworkGeolocationProvider.js
@BINPATH@/components/GPSDGeolocationProvider.manifest
@BINPATH@/components/GPSDGeolocationProvider.js
@BINPATH@/components/nsSidebar.manifest @BINPATH@/components/nsSidebar.manifest
@BINPATH@/components/nsSidebar.js @BINPATH@/components/nsSidebar.js
@BINPATH@/components/extensions.manifest @BINPATH@/components/extensions.manifest

View File

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

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