Merge mozilla-central to fx-team

This commit is contained in:
Carsten "Tomcat" Book 2014-01-24 13:44:58 +01:00
commit 53cf71f4de
79 changed files with 1170 additions and 175 deletions

View File

@ -22,4 +22,4 @@
# changes to stick? As of bug 928195, this shouldn't be necessary! Please
# don't change CLOBBER for WebIDL changes any more.
JS build system changes are apparently requiring clobbers.
Bug 948583, first part, apparently requires a clobber. (Ideas for fixing this involve removing jsopcode.tbl, which is a bit too big to do while holding up this patch.)

View File

@ -778,7 +778,7 @@ PrefCache.prototype = {
this.SettingCache = function SettingCache(aName, aCallback, aOptions = {}) {
this.value = aOptions.defaultValue;
let runCallback = () => {
if (aCallback && aOptions.callbackNow) {
if (aCallback) {
aCallback(aName, this.value);
if (aOptions.callbackOnce) {
runCallback = () => {};
@ -788,7 +788,9 @@ this.SettingCache = function SettingCache(aName, aCallback, aOptions = {}) {
let settings = Utils.win.navigator.mozSettings;
if (!settings) {
runCallback();
if (aOptions.callbackNow) {
runCallback();
}
return;
}
@ -798,7 +800,9 @@ this.SettingCache = function SettingCache(aName, aCallback, aOptions = {}) {
req.addEventListener('success', () => {
this.value = req.result[aName] == undefined ? aOptions.defaultValue : req.result[aName];
runCallback();
if (aOptions.callbackNow) {
runCallback();
}
});
settings.addObserver(aName,

View File

@ -12,7 +12,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="290efee3de3a12c9d803f4650d50bc7c7a8e1f2d"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="48637bedf20a7d1b8cc3f1638e72eeb44728f467"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eda08beb3ba9a159843c70ffde0f9660ec351eb9"/>

View File

@ -11,7 +11,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="290efee3de3a12c9d803f4650d50bc7c7a8e1f2d"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="48637bedf20a7d1b8cc3f1638e72eeb44728f467"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="96d2d00165f4561fbde62d1062706eab74b3a01f"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="a887bfabaed83c4588b40c845535c0388c8da0f3"/>

View File

@ -12,7 +12,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="290efee3de3a12c9d803f4650d50bc7c7a8e1f2d"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="48637bedf20a7d1b8cc3f1638e72eeb44728f467"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="eda08beb3ba9a159843c70ffde0f9660ec351eb9"/>

View File

@ -1,4 +1,4 @@
{
"revision": "9506ca996d28109df7dc8db6e381f54a83aa20ff",
"revision": "5116c92a2905f6646d7049ddd1e1ab68eeb278d9",
"repo_path": "/integration/gaia-central"
}

View File

@ -11,7 +11,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="290efee3de3a12c9d803f4650d50bc7c7a8e1f2d"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="48637bedf20a7d1b8cc3f1638e72eeb44728f467"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>

View File

@ -10,7 +10,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="290efee3de3a12c9d803f4650d50bc7c7a8e1f2d"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="48637bedf20a7d1b8cc3f1638e72eeb44728f467"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>

View File

@ -12,7 +12,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="290efee3de3a12c9d803f4650d50bc7c7a8e1f2d"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="48637bedf20a7d1b8cc3f1638e72eeb44728f467"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>

View File

@ -11,7 +11,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="290efee3de3a12c9d803f4650d50bc7c7a8e1f2d"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="48637bedf20a7d1b8cc3f1638e72eeb44728f467"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>

View File

@ -11,7 +11,7 @@
</project>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="290efee3de3a12c9d803f4650d50bc7c7a8e1f2d"/>
<project name="gaia" path="gaia" remote="mozillaorg" revision="48637bedf20a7d1b8cc3f1638e72eeb44728f467"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="moztt" path="external/moztt" remote="b2g" revision="96d2d00165f4561fbde62d1062706eab74b3a01f"/>
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="a887bfabaed83c4588b40c845535c0388c8da0f3"/>

View File

@ -11,7 +11,7 @@
<copyfile dest="Makefile" src="core/root.mk"/>
</project>
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="290efee3de3a12c9d803f4650d50bc7c7a8e1f2d"/>
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="48637bedf20a7d1b8cc3f1638e72eeb44728f467"/>
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="e9b6626eddbc85873eaa2a9174a9bd5101e5c05f"/>
<project name="rilproxy" path="rilproxy" remote="b2g" revision="827214fcf38d6569aeb5c6d6f31cb296d1f09272"/>
<project name="librecovery" path="librecovery" remote="b2g" revision="84f2f2fce22605e17d511ff1767e54770067b5b5"/>

View File

@ -5,7 +5,7 @@ whitelist = {
'nightly': {},
}
all_platforms = ['win32', 'linux32', 'linux64', 'macosx-universal']
all_platforms = ['win64', 'win32', 'linux32', 'linux64', 'macosx-universal']
for platform in all_platforms:
whitelist['nightly'][platform] = [
@ -19,7 +19,7 @@ for platform in ['linux32', 'linux64', 'macosx-universal']:
'mk_add_options MOZ_MAKE_FLAGS="-j4"',
]
for platform in ['linux32', 'linux64', 'macosx-universal', 'win32']:
for platform in ['linux32', 'linux64', 'macosx-universal', 'win32', 'win64']:
whitelist['nightly'][platform] += ['ac_add_options --enable-signmar']
whitelist['nightly'][platform] += ['ac_add_options --enable-js-diagnostics']
@ -62,6 +62,10 @@ whitelist['nightly']['win32'] += [
'fi',
'ac_add_options --enable-metro',
]
whitelist['nightly']['win64'] += [
'. "$topsrcdir/browser/config/mozconfigs/win64/common-win64"',
'ac_add_options --enable-metro',
]
for platform in all_platforms:
whitelist['release'][platform] = [
@ -71,6 +75,8 @@ for platform in all_platforms:
'export BUILDING_RELEASE=1',
]
whitelist['release']['win32'] += ['mk_add_options MOZ_PGO=1']
whitelist['release']['win64'] += ['mk_add_options MOZ_PGO=1']
whitelist['release']['linux32'] += [
'export MOZILLA_OFFICIAL=1',
'export MOZ_TELEMETRY_REPORTING=1',

View File

@ -1,7 +1,9 @@
. "$topsrcdir/browser/config/mozconfigs/win64/common-win64"
. "$topsrcdir/browser/config/mozconfigs/win64/common-opt"
mk_add_options MOZ_PGO=1
ac_add_options --enable-official-branding
. $topsrcdir/build/win64/mozconfig.vs2010
. "$topsrcdir/build/mozconfig.common.override"

View File

@ -1,5 +1,6 @@
# This make file should be identical to the beta mozconfig, apart from the
# safeguard below
. "$topsrcdir/browser/config/mozconfigs/win64/common-win64"
. "$topsrcdir/browser/config/mozconfigs/win64/common-opt"
mk_add_options MOZ_PGO=1
@ -9,5 +10,6 @@ ac_add_options --enable-official-branding
# safeguard against someone forgetting to re-set EARLY_BETA_OR_EARLIER in
# defines.sh during the beta cycle
export BUILDING_RELEASE=1
. $topsrcdir/build/win64/mozconfig.vs2010
. "$topsrcdir/build/mozconfig.common.override"

View File

@ -34,7 +34,7 @@ if test -d "$1"; then
(cd "$1"; $PYTHON $_topsrcdir/build/subconfigure.py dump "$_CONFIG_SHELL")
fi
$2
(cd "$1"; $PYTHON $_topsrcdir/build/subconfigure.py adjust)
(cd "$1"; $PYTHON $_topsrcdir/build/subconfigure.py adjust $ac_sub_configure)
])
define([AC_OUTPUT_SUBDIRS],

View File

@ -18,6 +18,14 @@ class File(object):
stat = os.stat(path)
self._times = (stat.st_atime, stat.st_mtime)
@property
def path(self):
return self._path
@property
def mtime(self):
return self._times[1]
def update_time(self):
'''If the file hasn't changed since the instance was created,
restore its old modification time.'''
@ -97,7 +105,7 @@ def dump(dump_file, shell):
pickle.dump(config_files, f)
def adjust(dump_file):
def adjust(dump_file, configure):
if not os.path.exists(dump_file):
return
@ -110,6 +118,11 @@ def adjust(dump_file):
pass
for f in config_files:
# Still touch config.status if configure is newer than its original
# mtime.
if configure and os.path.basename(f.path) == 'config.status' and \
os.path.getmtime(configure) > f.mtime:
continue
f.update_time()
os.remove(dump_file)
@ -121,4 +134,4 @@ if __name__ == '__main__':
if sys.argv[1] == 'dump':
dump(CONFIG_DUMP, sys.argv[2])
elif sys.argv[1] == 'adjust':
adjust(CONFIG_DUMP)
adjust(CONFIG_DUMP, sys.argv[2] if len(sys.argv) > 2 else None)

View File

@ -1158,6 +1158,10 @@ arm*)
mips|mipsel)
CPU_ARCH="mips"
;;
aarch64*)
CPU_ARCH=aarch64
;;
esac
if test -z "$OS_TARGET"; then

View File

@ -160,25 +160,6 @@ nsJSUtils::CompileFunction(JSContext* aCx,
return NS_OK;
}
class MOZ_STACK_CLASS AutoDontReportUncaught {
JSContext* mContext;
bool mWasSet;
public:
AutoDontReportUncaught(JSContext* aContext) : mContext(aContext) {
MOZ_ASSERT(aContext);
mWasSet = JS::ContextOptionsRef(mContext).dontReportUncaught();
if (!mWasSet) {
JS::ContextOptionsRef(mContext).setDontReportUncaught(true);
}
}
~AutoDontReportUncaught() {
if (!mWasSet) {
JS::ContextOptionsRef(mContext).setDontReportUncaught(false);
}
}
};
nsresult
nsJSUtils::EvaluateString(JSContext* aCx,
const nsAString& aScript,

View File

@ -90,6 +90,25 @@ public:
};
class MOZ_STACK_CLASS AutoDontReportUncaught {
JSContext* mContext;
bool mWasSet;
public:
AutoDontReportUncaught(JSContext* aContext) : mContext(aContext) {
MOZ_ASSERT(aContext);
mWasSet = JS::ContextOptionsRef(mContext).dontReportUncaught();
if (!mWasSet) {
JS::ContextOptionsRef(mContext).setDontReportUncaught(true);
}
}
~AutoDontReportUncaught() {
if (!mWasSet) {
JS::ContextOptionsRef(mContext).setDontReportUncaught(false);
}
}
};
class nsDependentJSString : public nsDependentString
{

View File

@ -151,7 +151,7 @@ CallbackObject::CallSetup::CallSetup(CallbackObject* aCallback,
mCx = cx;
// Make sure the JS engine doesn't report exceptions we want to re-throw
if (mExceptionHandling == eRethrowContentExceptions ||
if ((mCompartment && mExceptionHandling == eRethrowContentExceptions) ||
mExceptionHandling == eRethrowExceptions) {
mSavedJSContextOptions = JS::ContextOptionsRef(cx);
JS::ContextOptionsRef(cx).setDontReportUncaught(true);

View File

@ -968,6 +968,30 @@ nsGonkCameraControl::SetPictureSize(uint32_t aWidth, uint32_t aHeight)
UpdateThumbnailSize();
}
int32_t
nsGonkCameraControl::RationalizeRotation(int32_t aRotation)
{
int32_t r = aRotation;
// The result of this operation is an angle from 0..270 degrees,
// in steps of 90 degrees. Angles are rounded to the nearest
// magnitude, so 45 will be rounded to 90, and -45 will be rounded
// to -90 (not 0).
if (r >= 0) {
r += 45;
} else {
r -= 45;
}
r /= 90;
r %= 4;
r *= 90;
if (r < 0) {
r += 360;
}
return r;
}
nsresult
nsGonkCameraControl::TakePictureImpl(TakePictureTask* aTakePicture)
{
@ -991,13 +1015,10 @@ nsGonkCameraControl::TakePictureImpl(TakePictureTask* aTakePicture)
mFileFormat = aTakePicture->mFileFormat;
SetParameter(CameraParameters::KEY_PICTURE_FORMAT, NS_ConvertUTF16toUTF8(mFileFormat).get());
// Convert 'rotation' to a positive value from 0..270 degrees, in steps of 90.
uint32_t r = static_cast<uint32_t>(aTakePicture->mRotation);
// Round 'rotation' up to a positive value from 0..270 degrees, in steps of 90.
int32_t r = static_cast<uint32_t>(aTakePicture->mRotation);
r += mCameraHw->GetSensorOrientation(GonkCameraHardware::OFFSET_SENSOR_ORIENTATION);
r %= 360;
r += 45;
r /= 90;
r *= 90;
r = RationalizeRotation(r);
DOM_CAMERA_LOGI("setting picture rotation to %d degrees (mapped from %d)\n", r, aTakePicture->mRotation);
SetParameter(CameraParameters::KEY_ROTATION, nsPrintfCString("%u", r).get());
@ -1517,14 +1538,7 @@ nsGonkCameraControl::SetupRecording(int aFd, int aRotation, int64_t aMaxFileSize
// adjust rotation by camera sensor offset
int r = aRotation;
r += mCameraHw->GetSensorOrientation();
r %= 360;
r += 45;
r /= 90;
r *= 90;
if (r < 0) {
// the video recorder only supports positive rotations
r += 360;
}
r = RationalizeRotation(r);
DOM_CAMERA_LOGI("setting video rotation to %d degrees (mapped from %d)\n", r, aRotation);
snprintf(buffer, SIZE, "video-param-rotation-angle-degrees=%d", r);
CHECK_SETARG(mRecorder->setParameters(String8(buffer)));

View File

@ -96,6 +96,8 @@ protected:
void UpdateThumbnailSize();
void SetPictureSize(uint32_t aWidth, uint32_t aHeight);
int32_t RationalizeRotation(int32_t aRotation);
android::sp<android::GonkCameraHardware> mCameraHw;
double mExposureCompensationMin;
double mExposureCompensationStep;

View File

@ -610,14 +610,238 @@ Promise::Catch(const Optional<nsRefPtr<AnyCallback>>& aRejectCallback)
return Then(resolveCb, aRejectCallback);
}
/**
* The CountdownHolder class encapsulates Promise.all countdown functions and
* the countdown holder parts of the Promises spec. It maintains the result
* array and AllResolveHandlers use SetValue() to set the array indices.
*/
class CountdownHolder MOZ_FINAL : public nsISupports
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(CountdownHolder)
CountdownHolder(const GlobalObject& aGlobal, Promise* aPromise, uint32_t aCountdown)
: mPromise(aPromise), mCountdown(aCountdown)
{
MOZ_ASSERT(aCountdown != 0);
JSContext* cx = aGlobal.GetContext();
JSAutoCompartment ac(cx, aGlobal.Get());
mValues = JS_NewArrayObject(cx, aCountdown, nullptr);
mozilla::HoldJSObjects(this);
}
~CountdownHolder()
{
mozilla::DropJSObjects(this);
}
void SetValue(uint32_t index, const JS::Handle<JS::Value> aValue)
{
MOZ_ASSERT(mCountdown > 0);
JSContext* cx = nsContentUtils::GetDefaultJSContextForThread();
JSAutoCompartment ac(cx, mValues);
{
AutoDontReportUncaught silenceReporting(cx);
if (!JS_DefineElement(cx, mValues, index, aValue, nullptr, nullptr, JSPROP_ENUMERATE)) {
MOZ_ASSERT(JS_IsExceptionPending(cx));
JS::Rooted<JS::Value> exn(cx);
JS_GetPendingException(cx, &exn);
mPromise->MaybeReject(cx, exn);
}
}
--mCountdown;
if (mCountdown == 0) {
JS::Rooted<JS::Value> result(cx, JS::ObjectValue(*mValues));
mPromise->MaybeResolve(cx, result);
}
}
private:
nsRefPtr<Promise> mPromise;
uint32_t mCountdown;
JS::Heap<JSObject*> mValues;
};
NS_IMPL_CYCLE_COLLECTING_ADDREF(CountdownHolder)
NS_IMPL_CYCLE_COLLECTING_RELEASE(CountdownHolder)
NS_IMPL_CYCLE_COLLECTION_CLASS(CountdownHolder)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(CountdownHolder)
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(CountdownHolder)
NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mValues)
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(CountdownHolder)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_SCRIPT_OBJECTS
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPromise)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(CountdownHolder)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mPromise)
tmp->mValues = nullptr;
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
/**
* An AllResolveHandler is the per-promise part of the Promise.all() algorithm.
* Every Promise in the handler is handed an instance of this as a resolution
* handler and it sets the relevant index in the CountdownHolder.
*/
class AllResolveHandler MOZ_FINAL : public PromiseNativeHandler
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_CLASS(AllResolveHandler)
AllResolveHandler(CountdownHolder* aHolder, uint32_t aIndex)
: mCountdownHolder(aHolder), mIndex(aIndex)
{
MOZ_ASSERT(aHolder);
}
~AllResolveHandler()
{
}
void
ResolvedCallback(JS::Handle<JS::Value> aValue)
{
mCountdownHolder->SetValue(mIndex, aValue);
}
void
RejectedCallback(JS::Handle<JS::Value> aValue)
{
// Should never be attached to Promise as a reject handler.
MOZ_ASSERT(false, "AllResolveHandler should never be attached to a Promise's reject handler!");
}
private:
nsRefPtr<CountdownHolder> mCountdownHolder;
uint32_t mIndex;
};
NS_IMPL_CYCLE_COLLECTING_ADDREF(AllResolveHandler)
NS_IMPL_CYCLE_COLLECTING_RELEASE(AllResolveHandler)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AllResolveHandler)
NS_INTERFACE_MAP_END_INHERITING(PromiseNativeHandler)
NS_IMPL_CYCLE_COLLECTION_1(AllResolveHandler, mCountdownHolder)
/* static */ already_AddRefed<Promise>
Promise::All(const GlobalObject& aGlobal, JSContext* aCx,
const Sequence<JS::Value>& aIterable, ErrorResult& aRv)
{
nsCOMPtr<nsPIDOMWindow> window;
if (MOZ_LIKELY(NS_IsMainThread())) {
window = do_QueryInterface(aGlobal.GetAsSupports());
if (!window) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
}
if (aIterable.Length() == 0) {
JS::Rooted<JSObject*> empty(aCx, JS_NewArrayObject(aCx, 0, nullptr));
if (!empty) {
aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
return nullptr;
}
Optional<JS::Handle<JS::Value>> optValue(aCx, JS::ObjectValue(*empty));
return Promise::Resolve(aGlobal, aCx, optValue, aRv);
}
nsRefPtr<Promise> promise = new Promise(window);
nsRefPtr<CountdownHolder> holder =
new CountdownHolder(aGlobal, promise, aIterable.Length());
nsRefPtr<PromiseCallback> rejectCb = new RejectPromiseCallback(promise);
for (uint32_t i = 0; i < aIterable.Length(); ++i) {
Optional<JS::Handle<JS::Value>> optValue(aCx, aIterable.ElementAt(i));
nsRefPtr<Promise> nextPromise = Promise::Cast(aGlobal, aCx, optValue, aRv);
MOZ_ASSERT(!aRv.Failed());
nsRefPtr<PromiseNativeHandler> resolveHandler =
new AllResolveHandler(holder, i);
nsRefPtr<PromiseCallback> resolveCb =
new NativePromiseCallback(resolveHandler, Resolved);
// Every promise gets its own resolve callback, which will set the right
// index in the array to the resolution value.
nextPromise->AppendCallbacks(resolveCb, rejectCb);
}
return promise.forget();
}
/* static */ already_AddRefed<Promise>
Promise::Cast(const GlobalObject& aGlobal, JSContext* aCx,
const Optional<JS::Handle<JS::Value>>& aValue, ErrorResult& aRv)
{
// If a Promise was passed, just return it.
JS::Rooted<JS::Value> value(aCx, aValue.WasPassed() ? aValue.Value() :
JS::UndefinedValue());
if (value.isObject()) {
JS::Rooted<JSObject*> valueObj(aCx, &value.toObject());
Promise* nextPromise;
nsresult rv = UNWRAP_OBJECT(Promise, valueObj, nextPromise);
if (NS_SUCCEEDED(rv)) {
nsRefPtr<Promise> addRefed = nextPromise;
return addRefed.forget();
}
}
return Promise::Resolve(aGlobal, aCx, aValue, aRv);
}
/* static */ already_AddRefed<Promise>
Promise::Race(const GlobalObject& aGlobal, JSContext* aCx,
const Sequence<JS::Value>& aIterable, ErrorResult& aRv)
{
nsCOMPtr<nsPIDOMWindow> window;
if (MOZ_LIKELY(NS_IsMainThread())) {
window = do_QueryInterface(aGlobal.GetAsSupports());
if (!window) {
aRv.Throw(NS_ERROR_UNEXPECTED);
return nullptr;
}
}
nsRefPtr<Promise> promise = new Promise(window);
nsRefPtr<PromiseCallback> resolveCb = new ResolvePromiseCallback(promise);
nsRefPtr<PromiseCallback> rejectCb = new RejectPromiseCallback(promise);
for (uint32_t i = 0; i < aIterable.Length(); ++i) {
Optional<JS::Handle<JS::Value>> optValue(aCx, aIterable.ElementAt(i));
nsRefPtr<Promise> nextPromise = Promise::Cast(aGlobal, aCx, optValue, aRv);
// According to spec, Cast can throw, but our implementation never does.
// Remove this when subclassing is supported.
MOZ_ASSERT(!aRv.Failed());
nextPromise->AppendCallbacks(resolveCb, rejectCb);
}
return promise.forget();
}
void
Promise::AppendNativeHandler(PromiseNativeHandler* aRunnable)
{
nsRefPtr<PromiseCallback> resolveCb =
new NativePromiseCallback(aRunnable, Resolved);
new NativePromiseCallback(aRunnable, Resolved);
nsRefPtr<PromiseCallback> rejectCb =
new NativePromiseCallback(aRunnable, Rejected);
new NativePromiseCallback(aRunnable, Rejected);
AppendCallbacks(resolveCb, rejectCb);
}
@ -657,7 +881,7 @@ Promise::RunTask()
{
MOZ_ASSERT(mState != Pending);
nsTArray<nsRefPtr<PromiseCallback> > callbacks;
nsTArray<nsRefPtr<PromiseCallback>> callbacks;
callbacks.SwapElements(mState == Resolved ? mResolveCallbacks
: mRejectCallbacks);
mResolveCallbacks.Clear();
@ -756,6 +980,7 @@ Promise::ResolveInternal(JSContext* aCx,
mResolvePending = true;
if (aValue.isObject()) {
AutoDontReportUncaught silenceReporting(aCx);
JS::Rooted<JSObject*> valueObj(aCx, &aValue.toObject());
// Thenables.
@ -856,6 +1081,13 @@ Promise::RunResolveTask(JS::Handle<JS::Value> aValue,
return;
}
// Promise.all() or Promise.race() implementations will repeatedly call
// Resolve/RejectInternal rather than using the Maybe... forms. Stop SetState
// from asserting.
if (mState != Pending) {
return;
}
SetResult(aValue);
SetState(aState);
RunTask();

View File

@ -90,6 +90,20 @@ public:
already_AddRefed<Promise>
Catch(const Optional<nsRefPtr<AnyCallback>>& aRejectCallback);
// FIXME(nsm): Bug 956197
static already_AddRefed<Promise>
All(const GlobalObject& aGlobal, JSContext* aCx,
const Sequence<JS::Value>& aIterable, ErrorResult& aRv);
static already_AddRefed<Promise>
Cast(const GlobalObject& aGlobal, JSContext* aCx,
const Optional<JS::Handle<JS::Value>>& aValue, ErrorResult& aRv);
// FIXME(nsm): Bug 956197
static already_AddRefed<Promise>
Race(const GlobalObject& aGlobal, JSContext* aCx,
const Sequence<JS::Value>& aIterable, ErrorResult& aRv);
void AppendNativeHandler(PromiseNativeHandler* aRunnable);
private:

View File

@ -2,4 +2,5 @@
[test_bug883683.html]
[test_promise.html]
[test_promise_utils.html]
[test_resolve.html]

View File

@ -0,0 +1,325 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<html>
<head>
<title>Test for Promise.all, Promise.cast, Promise.race</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
<script type="application/javascript"><!--
function promiseUtilitiesDefined() {
ok(Promise.all, "Promise.all must be defined when Promise is enabled.");
ok(Promise.cast, "Promise.cast must be defined when Promise is enabled.");
ok(Promise.race, "Promise.race must be defined when Promise is enabled.");
runTest();
}
function promiseAllEmptyArray() {
var p = Promise.all([]);
ok(p instanceof Promise, "Return value of Promise.all should be a Promise.");
p.then(function(values) {
ok(Array.isArray(values), "Resolved value should be an array.");
is(values.length, 0, "Resolved array length should match iterable's length.");
runTest();
}, function() {
ok(false, "Promise.all shouldn't fail when iterable has no rejected Promises.");
runTest();
});
}
function promiseAllArray() {
var p = Promise.all([1, new Date(), Promise.resolve("firefox")]);
ok(p instanceof Promise, "Return value of Promise.all should be a Promise.");
p.then(function(values) {
ok(Array.isArray(values), "Resolved value should be an array.");
is(values.length, 3, "Resolved array length should match iterable's length.");
is(values[0], 1, "Array values should match.");
ok(values[1] instanceof Date, "Array values should match.");
is(values[2], "firefox", "Array values should match.");
runTest();
}, function() {
ok(false, "Promise.all shouldn't fail when iterable has no rejected Promises.");
runTest();
});
}
function promiseAllWaitsForAllPromises() {
var arr = [
new Promise(function(resolve) {
setTimeout(resolve.bind(undefined, 1), 50);
}),
new Promise(function(resolve) {
setTimeout(resolve.bind(undefined, 2), 10);
}),
new Promise(function(resolve) {
setTimeout(resolve.bind(undefined, new Promise(function(resolve2) {
resolve2(3);
})), 10);
}),
new Promise(function(resolve) {
setTimeout(resolve.bind(undefined, 4), 20);
})
];
var p = Promise.all(arr);
p.then(function(values) {
ok(Array.isArray(values), "Resolved value should be an array.");
is(values.length, 4, "Resolved array length should match iterable's length.");
is(values[0], 1, "Array values should match.");
is(values[1], 2, "Array values should match.");
is(values[2], 3, "Array values should match.");
is(values[3], 4, "Array values should match.");
runTest();
}, function() {
ok(false, "Promise.all shouldn't fail when iterable has no rejected Promises.");
runTest();
});
}
function promiseAllRejectFails() {
var arr = [
new Promise(function(resolve) {
setTimeout(resolve.bind(undefined, 1), 50);
}),
new Promise(function(resolve, reject) {
setTimeout(reject.bind(undefined, 2), 10);
}),
new Promise(function(resolve) {
setTimeout(resolve.bind(undefined, 3), 10);
}),
new Promise(function(resolve) {
setTimeout(resolve.bind(undefined, 4), 20);
})
];
var p = Promise.all(arr);
p.then(function(values) {
ok(false, "Promise.all shouldn't resolve when iterable has rejected Promises.");
runTest();
}, function(e) {
ok(true, "Promise.all should reject when iterable has rejected Promises.");
is(e, 2, "Rejection value should match.");
runTest();
});
}
function promiseAllCastError() {
var p = Promise.all([Promise.resolve(2), { then: function() { foo(); } }]);
ok(p instanceof Promise, "Should cast to a Promise.");
p.then(function(v) {
ok(false, "promiseAllCastError: should've rejected.");
runTest();
}, function(e) {
ok(e instanceof ReferenceError, "promiseCastThenableError");
runTest();
});
}
// Check that the resolved array is enumerable.
function promiseAllEnumerable() {
var p = Promise.all([1, new Date(), Promise.resolve("firefox")]);
p.then(function(v) {
var count = 0;
for (key in v) {
++count;
ok(v[key] === 1 || v[key] instanceof Date || v[key] === "firefox",
"Enumerated properties don't match.");
}
is(count, 3, "Resolved array from Promise.all should be enumerable");
runTest();
}, function(e) {
ok(false, "promiseAllEnumerable: should've resolved.");
runTest();
});
}
function promiseCastNoArg() {
var p = Promise.cast();
ok(p instanceof Promise, "Should cast to a Promise.");
p.then(function(v) {
is(v, undefined, "Resolved value should be undefined.");
runTest();
});
}
function promiseCastInteger() {
var p = Promise.cast(5);
ok(p instanceof Promise, "Should cast to a Promise.");
p.then(function(v) {
is(v, 5, "Resolved value should match original.");
runTest();
});
}
function promiseCastArray() {
var p = Promise.cast([1,2,3]);
ok(p instanceof Promise, "Should cast to a Promise.");
p.then(function(v) {
ok(Array.isArray(v), "Resolved value should be an Array");
is(v.length, 3, "Length should match");
is(v[0], 1, "Resolved value should match original");
is(v[1], 2, "Resolved value should match original");
is(v[2], 3, "Resolved value should match original");
runTest();
});
}
function promiseCastThenable() {
var p = Promise.cast({ then: function(resolve) { resolve(2); } });
ok(p instanceof Promise, "Should cast to a Promise.");
p.then(function(v) {
is(v, 2, "Should resolve to 2.");
runTest();
}, function(e) {
ok(false, "promiseCastThenable should've resolved");
runTest();
});
}
function promiseCastPromise() {
var original = Promise.resolve(true);
var cast = Promise.cast(original);
ok(cast instanceof Promise, "Should cast to a Promise.");
is(cast, original, "Should return original Promise.");
runTest();
}
function promiseRaceEmpty() {
var p = Promise.race([]);
ok(p instanceof Promise, "Should return a Promise.");
p.then(function() {
ok(false, "Should not resolve");
}, function() {
ok(false, "Should not reject");
});
// Per spec, An empty race never resolves or rejects.
setTimeout(function() {
ok(true);
runTest();
}, 50);
}
function promiseRaceValuesArray() {
var p = Promise.race([true, new Date(), 3]);
ok(p instanceof Promise, "Should return a Promise.");
p.then(function(winner) {
is(winner, true, "First value should win.");
runTest();
}, function(err) {
ok(false, "Should not fail " + err + ".");
runTest();
});
}
function promiseRacePromiseArray() {
function timeoutPromise(n) {
return new Promise(function(resolve) {
setTimeout(function() {
resolve(n);
}, n);
});
}
var arr = [
timeoutPromise(50),
timeoutPromise(20),
timeoutPromise(30),
timeoutPromise(100)
];
var p = Promise.race(arr);
p.then(function(winner) {
is(winner, 20, "Fastest timeout should win.");
runTest();
});
}
function promiseRaceReject() {
var p = Promise.race([
Promise.reject(new Error("Fail bad!")),
new Promise(function(resolve) {
setTimeout(resolve, 0);
})
]);
p.then(function() {
ok(false, "Should not resolve when winning Promise rejected.");
runTest();
}, function(e) {
ok(true, "Should be rejected");
ok(e instanceof Error, "Should reject with Error.");
ok(e.message == "Fail bad!", "Message should match.");
runTest();
});
}
function promiseRaceThrow() {
var p = Promise.race([
new Promise(function(resolve) {
nonExistent();
}),
new Promise(function(resolve) {
setTimeout(resolve, 0);
})
]);
p.then(function() {
ok(false, "Should not resolve when winning Promise had an error.");
runTest();
}, function(e) {
ok(true, "Should be rejected");
ok(e instanceof ReferenceError, "Should reject with ReferenceError for function nonExistent().");
runTest();
});
}
var tests = [
promiseUtilitiesDefined,
promiseAllEmptyArray,
promiseAllArray,
promiseAllWaitsForAllPromises,
promiseAllRejectFails,
promiseAllCastError,
promiseAllEnumerable,
promiseCastNoArg,
promiseCastInteger,
promiseCastArray,
promiseCastThenable,
promiseCastPromise,
promiseRaceEmpty,
promiseRaceValuesArray,
promiseRacePromiseArray,
promiseRaceReject,
promiseRaceThrow,
];
function runTest() {
if (!tests.length) {
SimpleTest.finish();
return;
}
var test = tests.shift();
test();
}
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv({"set": [["dom.promise.enabled", true]]}, runTest);
// -->
</script>
</pre>
</body>
</html>

View File

@ -33,4 +33,13 @@ interface Promise {
[NewObject]
Promise catch(optional AnyCallback? rejectCallback);
[NewObject, Throws, Func="mozilla::dom::Promise::EnabledForScope"]
static Promise all(sequence<any> iterable);
[NewObject, Throws, Func="mozilla::dom::Promise::EnabledForScope"]
static Promise cast(optional any value);
[NewObject, Throws, Func="mozilla::dom::Promise::EnabledForScope"]
static Promise race(sequence<any> iterable);
};

View File

@ -876,8 +876,7 @@ void ReportLoadError(JSContext* aCx, const nsAString& aURL,
break;
default:
JS_ReportError(aCx, "Failed to load script: %s (nsresult = 0x%x)",
url.get(), aLoadResult);
JS_ReportError(aCx, "Failed to load script (nsresult = 0x%x)", aLoadResult);
}
}

View File

@ -391,7 +391,6 @@ protected:
gfx::DrawTarget*
BorrowDrawTargetForQuadrantUpdate(const nsIntRect& aBounds,
ContextSource aSource);
void ReturnDrawTarget(gfx::DrawTarget* aReturned);
static bool IsClippingCheap(gfx::DrawTarget* aTarget, const nsIntRegion& aRegion);

View File

@ -207,7 +207,7 @@ BasicThebesLayer::Validate(LayerManager::DrawThebesLayerCallback aCallback,
MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PaintThebes", this));
Mutated();
ctx = nullptr;
mContentClient->ReturnDrawTarget(target);
mContentClient->ReturnDrawTargetToBuffer(target);
RenderTraceInvalidateEnd(this, "FFFF00");
} else {

View File

@ -70,7 +70,7 @@ ClientThebesLayer::PaintThebes()
MOZ_LAYERS_LOG_IF_SHADOWABLE(this, ("Layer::Mutated(%p) PaintThebes", this));
Mutated();
ctx = nullptr;
mContentClient->ReturnDrawTarget(target);
mContentClient->ReturnDrawTargetToBuffer(target);
} else {
// It's possible that state.mRegionToInvalidate is nonempty here,
// if we are shrinking the valid region to nothing. So use mRegionToDraw

View File

@ -656,7 +656,7 @@ ContentClientDoubleBuffered::UpdateDestinationFrom(const RotatedBuffer& aSource,
if (isClippingCheap) {
destDT->PopClip();
}
ReturnDrawTarget(destDT);
ReturnDrawTargetToBuffer(destDT);
if (aSource.HaveBufferOnWhite()) {
MOZ_ASSERT(HaveBufferOnWhite());
@ -675,7 +675,7 @@ ContentClientDoubleBuffered::UpdateDestinationFrom(const RotatedBuffer& aSource,
if (isClippingCheap) {
destDT->PopClip();
}
ReturnDrawTarget(destDT);
ReturnDrawTargetToBuffer(destDT);
}
}
@ -895,7 +895,7 @@ DeprecatedContentClientDoubleBuffered::UpdateDestinationFrom(const RotatedBuffer
if (isClippingCheap) {
destDT->PopClip();
}
ReturnDrawTarget(destDT);
ReturnDrawTargetToBuffer(destDT);
if (aSource.HaveBufferOnWhite()) {
MOZ_ASSERT(HaveBufferOnWhite());
@ -914,7 +914,7 @@ DeprecatedContentClientDoubleBuffered::UpdateDestinationFrom(const RotatedBuffer
if (isClippingCheap) {
destDT->PopClip();
}
ReturnDrawTarget(destDT);
ReturnDrawTargetToBuffer(destDT);
}
}

View File

@ -98,7 +98,7 @@ public:
uint32_t aFlags) = 0;
virtual gfx::DrawTarget* BorrowDrawTargetForPainting(ThebesLayer* aLayer,
const RotatedContentBuffer::PaintState& aPaintState) = 0;
virtual void ReturnDrawTarget(gfx::DrawTarget* aReturned) = 0;
virtual void ReturnDrawTargetToBuffer(gfx::DrawTarget*& aReturned) = 0;
virtual void PrepareFrame() {}
@ -148,7 +148,7 @@ public:
{
return RotatedContentBuffer::BorrowDrawTargetForPainting(aLayer, aPaintState);
}
virtual void ReturnDrawTarget(gfx::DrawTarget* aReturned) MOZ_OVERRIDE
virtual void ReturnDrawTargetToBuffer(gfx::DrawTarget*& aReturned) MOZ_OVERRIDE
{
BorrowDrawTarget::ReturnDrawTarget(aReturned);
}
@ -218,7 +218,7 @@ public:
{
return RotatedContentBuffer::BorrowDrawTargetForPainting(aLayer, aPaintState);
}
virtual void ReturnDrawTarget(gfx::DrawTarget* aReturned) MOZ_OVERRIDE
virtual void ReturnDrawTargetToBuffer(gfx::DrawTarget*& aReturned) MOZ_OVERRIDE
{
BorrowDrawTarget::ReturnDrawTarget(aReturned);
}
@ -328,7 +328,7 @@ public:
{
return RotatedContentBuffer::BorrowDrawTargetForPainting(aLayer, aPaintState);
}
virtual void ReturnDrawTarget(gfx::DrawTarget* aReturned) MOZ_OVERRIDE
virtual void ReturnDrawTargetToBuffer(gfx::DrawTarget*& aReturned) MOZ_OVERRIDE
{
BorrowDrawTarget::ReturnDrawTarget(aReturned);
}
@ -563,7 +563,7 @@ public:
uint32_t aFlags) MOZ_OVERRIDE;
virtual gfx::DrawTarget* BorrowDrawTargetForPainting(ThebesLayer* aLayer,
const PaintState& aPaintState) MOZ_OVERRIDE;
virtual void ReturnDrawTarget(gfx::DrawTarget* aReturned) MOZ_OVERRIDE
virtual void ReturnDrawTargetToBuffer(gfx::DrawTarget*& aReturned) MOZ_OVERRIDE
{
BorrowDrawTarget::ReturnDrawTarget(aReturned);
}

View File

@ -28,7 +28,7 @@
namespace mozilla {
namespace layers {
float APZCTreeManager::sDPI = 72.0;
float APZCTreeManager::sDPI = 160.0;
APZCTreeManager::APZCTreeManager()
: mTreeLock("APZCTreeLock"),

View File

@ -140,7 +140,7 @@ static bool gTouchActionPropertyEnabled = false;
* accidentally processing taps as touch moves, and from very short/accidental
* touches moving the screen.
*/
static float gTouchStartTolerance = 1.0f/2.0f;
static float gTouchStartTolerance = 1.0f/4.5f;
/**
* Default touch behavior (is used when not touch behavior is set).

View File

@ -574,7 +574,7 @@ struct JSClass {
// with the following flags. Failure to use JSCLASS_GLOBAL_FLAGS was
// previously allowed, but is now an ES5 violation and thus unsupported.
//
#define JSCLASS_GLOBAL_SLOT_COUNT (3 + JSProto_LIMIT * 3 + 29)
#define JSCLASS_GLOBAL_SLOT_COUNT (3 + JSProto_LIMIT * 3 + 30)
#define JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(n) \
(JSCLASS_IS_GLOBAL | JSCLASS_HAS_RESERVED_SLOTS(JSCLASS_GLOBAL_SLOT_COUNT + (n)))
#define JSCLASS_GLOBAL_FLAGS \

View File

@ -556,10 +556,8 @@ obj_watch(JSContext *cx, unsigned argc, Value *vp)
if (!obj)
return false;
#if 0 /* pending addressing Firebug's use of this method */
if (!GlobalObject::warnOnceAboutWatch(cx, obj))
return false;
#endif
if (args.length() <= 1) {
js_ReportMissingArg(cx, args.calleev(), 1);
@ -595,10 +593,8 @@ obj_unwatch(JSContext *cx, unsigned argc, Value *vp)
if (!obj)
return false;
#if 0 /* pending addressing Firebug's use of this method */
if (!GlobalObject::warnOnceAboutWatch(cx, obj))
return false;
#endif
RootedId id(cx);
if (args.length() != 0) {

View File

@ -970,6 +970,11 @@ arm*)
mips|mipsel)
CPU_ARCH="mips"
;;
aarch64*)
CPU_ARCH=aarch64
;;
esac
if test -z "$OS_TARGET"; then

View File

@ -5918,6 +5918,16 @@ EmitObject(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
}
for (ParseNode *pn2 = pn->pn_head; pn2; pn2 = pn2->pn_next) {
/* Handle __proto__ specially because it's not binary. */
if (pn2->isKind(PNK_MUTATEPROTO)) {
if (!EmitTree(cx, bce, pn2->pn_kid))
return false;
obj = nullptr;
if (!Emit1(cx, bce, JSOP_MUTATEPROTO))
return false;
continue;
}
/* Emit an index for t[2] for later consumption by JSOP_INITELEM. */
ParseNode *pn3 = pn2->pn_left;
bool isIndex = false;
@ -5966,12 +5976,9 @@ EmitObject(ExclusiveContext *cx, BytecodeEmitter *bce, ParseNode *pn)
if (!bce->makeAtomIndex(pn3->pn_atom, &index))
return false;
/*
* Disable NEWOBJECT on initializers that set __proto__, which has
* a non-standard setter on objects.
*/
if (pn3->pn_atom == cx->names().proto)
obj = nullptr;
MOZ_ASSERT((op == JSOP_INITPROP_GETTER || op == JSOP_INITPROP_SETTER) ||
pn3->pn_atom != cx->names().proto,
"__proto__ shouldn't have been generated as an initprop");
if (obj) {
JS_ASSERT(!obj->inDictionaryMode());

View File

@ -235,6 +235,14 @@ class FullParseHandler
return literal;
}
bool addPrototypeMutation(ParseNode *literal, uint32_t begin, ParseNode *expr) {
ParseNode *mutation = newUnary(PNK_MUTATEPROTO, JSOP_NOP, begin, expr);
if (!mutation)
return false;
literal->append(mutation);
return true;
}
bool addPropertyDefinition(ParseNode *literal, ParseNode *name, ParseNode *expr) {
ParseNode *propdef = newBinary(PNK_COLON, name, expr, JSOP_INITPROP);
if (!propdef)

View File

@ -139,6 +139,7 @@ class UpvarCookie
F(FORHEAD) \
F(ARGSBODY) \
F(SPREAD) \
F(MUTATEPROTO) \
\
/* Unary operators. */ \
F(TYPEOF) \

View File

@ -6807,6 +6807,7 @@ Parser<ParseHandler>::objectLiteral()
JSOp op = JSOP_INITPROP;
Node propname;
uint32_t begin;
switch (ltok) {
case TOK_NUMBER:
atom = DoubleToAtom(context, tokenStream.currentToken().number());
@ -6825,6 +6826,10 @@ Parser<ParseHandler>::objectLiteral()
propname = handler.newIdentifier(atom, pos());
if (!propname)
return null();
if (atom == context->names().proto) {
begin = pos().begin;
op = JSOP_MUTATEPROTO;
}
break;
}
@ -6893,7 +6898,7 @@ Parser<ParseHandler>::objectLiteral()
return null();
}
if (op == JSOP_INITPROP) {
if (op == JSOP_INITPROP || op == JSOP_MUTATEPROTO) {
TokenKind tt = tokenStream.getToken();
Node propexpr;
if (tt == TOK_COLON) {
@ -6909,11 +6914,15 @@ Parser<ParseHandler>::objectLiteral()
* so that we can later assume singleton objects delegate to
* the default Object.prototype.
*/
if (!handler.isConstant(propexpr) || atom == context->names().proto)
if (!handler.isConstant(propexpr) || op == JSOP_MUTATEPROTO)
handler.setListFlag(literal, PNX_NONCONST);
if (!handler.addPropertyDefinition(literal, propname, propexpr))
if (op == JSOP_MUTATEPROTO
? !handler.addPrototypeMutation(literal, begin, propexpr)
: !handler.addPropertyDefinition(literal, propname, propexpr))
{
return null();
}
}
#if JS_HAS_DESTRUCTURING_SHORTHAND
else if (ltok == TOK_NAME && (tt == TOK_COMMA || tt == TOK_RC)) {
@ -6959,7 +6968,7 @@ Parser<ParseHandler>::objectLiteral()
* any part of an accessor property.
*/
AssignmentType assignType;
if (op == JSOP_INITPROP)
if (op == JSOP_INITPROP || op == JSOP_MUTATEPROTO)
assignType = VALUE;
else if (op == JSOP_INITPROP_GETTER)
assignType = GET;

View File

@ -113,6 +113,7 @@ class SyntaxParseHandler
bool addArrayElement(Node literal, Node element) { return true; }
Node newObjectLiteral(uint32_t begin) { return NodeGeneric; }
bool addPrototypeMutation(Node literal, uint32_t begin, Node expr) { return true; }
bool addPropertyDefinition(Node literal, Node name, Node expr) { return true; }
bool addShorthandPropertyDefinition(Node literal, Node name) { return true; }
bool addAccessorPropertyDefinition(Node literal, Node name, Node fn, JSOp op) { return true; }

View File

@ -1676,6 +1676,30 @@ BaselineCompiler::emit_JSOP_INITELEM()
return true;
}
typedef bool (*MutateProtoFn)(JSContext *cx, HandleObject obj, HandleValue newProto);
static const VMFunction MutateProtoInfo = FunctionInfo<MutateProtoFn>(MutatePrototype);
bool
BaselineCompiler::emit_JSOP_MUTATEPROTO()
{
// Keep values on the stack for the decompiler.
frame.syncStack(0);
masm.extractObject(frame.addressOfStackValue(frame.peek(-2)), R0.scratchReg());
masm.loadValue(frame.addressOfStackValue(frame.peek(-1)), R1);
prepareVMCall();
pushArg(R1);
pushArg(R0.scratchReg());
if (!callVM(MutateProtoInfo))
return false;
frame.pop();
return true;
}
bool
BaselineCompiler::emit_JSOP_INITPROP()
{

View File

@ -90,6 +90,7 @@ namespace jit {
_(JSOP_INITELEM) \
_(JSOP_INITELEM_GETTER) \
_(JSOP_INITELEM_SETTER) \
_(JSOP_MUTATEPROTO) \
_(JSOP_INITPROP) \
_(JSOP_INITPROP_GETTER) \
_(JSOP_INITPROP_SETTER) \

View File

@ -3707,6 +3707,21 @@ CodeGenerator::visitInitElemGetterSetter(LInitElemGetterSetter *lir)
return callVM(InitElemGetterSetterInfo, lir);
}
typedef bool(*MutatePrototypeFn)(JSContext *cx, HandleObject obj, HandleValue value);
static const VMFunction MutatePrototypeInfo =
FunctionInfo<MutatePrototypeFn>(MutatePrototype);
bool
CodeGenerator::visitMutateProto(LMutateProto *lir)
{
Register objReg = ToRegister(lir->getObject());
pushArg(ToValue(lir, LMutateProto::ValueIndex));
pushArg(objReg);
return callVM(MutatePrototypeInfo, lir);
}
typedef bool(*InitPropFn)(JSContext *cx, HandleObject obj,
HandlePropertyName name, HandleValue value);
static const VMFunction InitPropInfo =

View File

@ -146,6 +146,7 @@ class CodeGenerator : public CodeGeneratorSpecific
bool visitAbortPar(LAbortPar *lir);
bool visitInitElem(LInitElem *lir);
bool visitInitElemGetterSetter(LInitElemGetterSetter *lir);
bool visitMutateProto(LMutateProto *lir);
bool visitInitProp(LInitProp *lir);
bool visitInitPropGetterSetter(LInitPropGetterSetter *lir);
bool visitCreateThis(LCreateThis *lir);

View File

@ -1587,6 +1587,11 @@ IonBuilder::inspectOpcode(JSOp op)
return jsop_initprop(name);
}
case JSOP_MUTATEPROTO:
{
return jsop_mutateproto();
}
case JSOP_INITPROP_GETTER:
case JSOP_INITPROP_SETTER: {
PropertyName *name = info().getAtom(pc)->asPropertyName();
@ -5523,6 +5528,17 @@ IonBuilder::jsop_initelem_array()
return true;
}
bool
IonBuilder::jsop_mutateproto()
{
MDefinition *value = current->pop();
MDefinition *obj = current->peek(-1);
MMutateProto *mutate = MMutateProto::New(alloc(), obj, value);
current->add(mutate);
return resumeAfter(mutate);
}
bool
IonBuilder::jsop_initprop(PropertyName *name)
{

View File

@ -557,6 +557,7 @@ class IonBuilder : public MIRGenerator
bool jsop_initelem();
bool jsop_initelem_array();
bool jsop_initelem_getter_setter();
bool jsop_mutateproto();
bool jsop_initprop(PropertyName *name);
bool jsop_initprop_getter_setter(PropertyName *name);
bool jsop_regexp(RegExpObject *reobj);

View File

@ -620,6 +620,26 @@ class LInitElemGetterSetter : public LCallInstructionHelper<0, 2 + BOX_PIECES, 0
}
};
// Takes in an Object and a Value.
class LMutateProto : public LCallInstructionHelper<0, 1 + BOX_PIECES, 0>
{
public:
LIR_HEADER(MutateProto)
LMutateProto(const LAllocation &object) {
setOperand(0, object);
}
static const size_t ValueIndex = 1;
const LAllocation *getObject() {
return getOperand(0);
}
const LAllocation *getValue() {
return getOperand(1);
}
};
// Takes in an Object and a Value.
class LInitProp : public LCallInstructionHelper<0, 1 + BOX_PIECES, 0>
{

View File

@ -36,6 +36,7 @@
_(AbortPar) \
_(InitElem) \
_(InitElemGetterSetter) \
_(MutateProto) \
_(InitProp) \
_(InitPropGetterSetter) \
_(CheckOverRecursed) \

View File

@ -279,6 +279,16 @@ LIRGenerator::visitInitElemGetterSetter(MInitElemGetterSetter *ins)
return add(lir, ins) && assignSafepoint(lir, ins);
}
bool
LIRGenerator::visitMutateProto(MMutateProto *ins)
{
LMutateProto *lir = new(alloc()) LMutateProto(useRegisterAtStart(ins->getObject()));
if (!useBoxAtStart(lir, LMutateProto::ValueIndex, ins->getValue()))
return false;
return add(lir, ins) && assignSafepoint(lir, ins);
}
bool
LIRGenerator::visitInitProp(MInitProp *ins)
{

View File

@ -79,6 +79,7 @@ class LIRGenerator : public LIRGeneratorSpecific
bool visitAbortPar(MAbortPar *ins);
bool visitInitElem(MInitElem *ins);
bool visitInitElemGetterSetter(MInitElemGetterSetter *ins);
bool visitMutateProto(MMutateProto *ins);
bool visitInitProp(MInitProp *ins);
bool visitInitPropGetterSetter(MInitPropGetterSetter *ins);
bool visitCheckOverRecursed(MCheckOverRecursed *ins);

View File

@ -1624,6 +1624,42 @@ class MAbortPar : public MAryControlInstruction<0, 0>
}
};
// Setting __proto__ in an object literal.
class MMutateProto
: public MAryInstruction<2>,
public MixPolicy<ObjectPolicy<0>, BoxPolicy<1> >
{
protected:
MMutateProto(MDefinition *obj, MDefinition *value)
{
setOperand(0, obj);
setOperand(1, value);
setResultType(MIRType_None);
}
public:
INSTRUCTION_HEADER(MutateProto)
static MMutateProto *New(TempAllocator &alloc, MDefinition *obj, MDefinition *value)
{
return new(alloc) MMutateProto(obj, value);
}
MDefinition *getObject() const {
return getOperand(0);
}
MDefinition *getValue() const {
return getOperand(1);
}
TypePolicy *typePolicy() {
return this;
}
bool possiblyCalls() const {
return true;
}
};
// Slow path for adding a property to an object without a known base.
class MInitProp
: public MAryInstruction<2>,

View File

@ -93,6 +93,7 @@ namespace jit {
_(NewStringObject) \
_(InitElem) \
_(InitElemGetterSetter) \
_(MutateProto) \
_(InitProp) \
_(InitPropGetterSetter) \
_(Start) \

View File

@ -186,6 +186,7 @@ class ParallelSafetyVisitor : public MInstructionVisitor
UNSAFE_OP(NewDerivedTypedObject)
UNSAFE_OP(InitElem)
UNSAFE_OP(InitElemGetterSetter)
UNSAFE_OP(MutateProto)
UNSAFE_OP(InitProp)
UNSAFE_OP(InitPropGetterSetter)
SAFE_OP(Start)

View File

@ -187,6 +187,16 @@ SetConst(JSContext *cx, HandlePropertyName name, HandleObject scopeChain, Handle
return SetConstOperation(cx, obj, name, rval);
}
bool
MutatePrototype(JSContext *cx, HandleObject obj, HandleValue value)
{
// Copy the incoming value. This may be overwritten; the return value is discarded.
RootedValue rval(cx, value);
RootedId id(cx, NameToId(cx->names().proto));
return baseops::SetPropertyHelper<SequentialExecution>(cx, obj, obj, id, 0, &rval, false);
}
bool
InitProp(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValue value)
{
@ -194,8 +204,8 @@ InitProp(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValue v
RootedValue rval(cx, value);
RootedId id(cx, NameToId(name));
if (name == cx->names().proto)
return baseops::SetPropertyHelper<SequentialExecution>(cx, obj, obj, id, 0, &rval, false);
MOZ_ASSERT(name != cx->names().proto,
"__proto__ should have been handled by JSOP_MUTATEPROTO");
return DefineNativeProperty(cx, obj, id, rval, nullptr, nullptr, JSPROP_ENUMERATE, 0, 0, 0);
}

View File

@ -575,6 +575,7 @@ bool CheckOverRecursedWithExtra(JSContext *cx, BaselineFrame *frame,
bool DefVarOrConst(JSContext *cx, HandlePropertyName dn, unsigned attrs, HandleObject scopeChain);
bool SetConst(JSContext *cx, HandlePropertyName name, HandleObject scopeChain, HandleValue rval);
bool MutatePrototype(JSContext *cx, HandleObject obj, HandleValue value);
bool InitProp(JSContext *cx, HandleObject obj, HandlePropertyName name, HandleValue value);
template<bool Equal>

View File

@ -260,7 +260,7 @@ MSG_DEF(JSMSG_USER_DEFINED_ERROR, 206, 0, JSEXN_ERR, "JS_ReportError was cal
MSG_DEF(JSMSG_WRONG_CONSTRUCTOR, 207, 1, JSEXN_TYPEERR, "wrong constructor called for {0}")
MSG_DEF(JSMSG_BAD_GENERATOR_RETURN, 208, 1, JSEXN_TYPEERR, "generator function {0} returns a value")
MSG_DEF(JSMSG_BAD_ANON_GENERATOR_RETURN, 209, 0, JSEXN_TYPEERR, "anonymous generator function returns a value")
MSG_DEF(JSMSG_UNUSED210, 210, 0, JSEXN_NONE, "")
MSG_DEF(JSMSG_PROTO_SETTING_SLOW, 210, 0, JSEXN_TYPEERR, "mutating the [[Prototype]] of an object will cause your code to run very slowly; instead create the object with the correct initial [[Prototype]] value using Object.create")
MSG_DEF(JSMSG_IN_AFTER_FOR_NAME, 211, 0, JSEXN_SYNTAXERR, "missing 'in' or 'of' after for")
MSG_DEF(JSMSG_BAD_TRAP_RETURN_VALUE, 212, 2, JSEXN_TYPEERR,"trap {1} for {0} returned a primitive value")
MSG_DEF(JSMSG_UNUSED213, 213, 0, JSEXN_NONE, "")

View File

@ -4482,8 +4482,8 @@ JS::Compile(JSContext *cx, HandleObject obj, const ReadOnlyCompileOptions &optio
JS_PUBLIC_API(bool)
JS::CanCompileOffThread(JSContext *cx, const ReadOnlyCompileOptions &options, size_t length)
{
static const unsigned TINY_LENGTH = 1000;
static const unsigned HUGE_LENGTH = 100*1000;
static const size_t TINY_LENGTH = 1000;
static const size_t HUGE_LENGTH = 100 * 1000;
// These are heuristics which the caller may choose to ignore (e.g., for
// testing purposes).
@ -4493,11 +4493,13 @@ JS::CanCompileOffThread(JSContext *cx, const ReadOnlyCompileOptions &options, si
if (length < TINY_LENGTH)
return false;
#ifdef JS_THREADSAFE
// If the parsing task would have to wait for GC to complete, it'll probably
// be faster to just start it synchronously on the main thread unless the
// script is huge.
if (OffThreadParsingMustWaitForGC(cx->runtime()) && length < HUGE_LENGTH)
return false;
#endif // JS_THREADSAFE
}
return cx->runtime()->canUseParallelParsing();

View File

@ -410,7 +410,8 @@ OPDEF(JSOP_UNUSED192, 192,"unused192", NULL, 1, 0, 0, JOF_BYTE)
OPDEF(JSOP_CALLELEM, 193, "callelem", NULL, 1, 2, 1, JOF_BYTE |JOF_ELEM|JOF_TYPESET|JOF_LEFTASSOC)
OPDEF(JSOP_UNUSED194, 194,"unused194", NULL, 1, 0, 0, JOF_BYTE)
/* __proto__: v inside an object initializer. */
OPDEF(JSOP_MUTATEPROTO, 194, "mutateproto",NULL, 1, 2, 1, JOF_BYTE)
/*
* Get an extant property value, throwing ReferenceError if the identified

View File

@ -379,10 +379,12 @@ struct ParseTask
~ParseTask();
};
#ifdef JS_THREADSAFE
// Return whether, if a new parse task was started, it would need to wait for
// an in-progress GC to complete before starting.
extern bool
OffThreadParsingMustWaitForGC(JSRuntime *rt);
#endif
// Compression tasks are allocated on the stack by their triggering thread,
// which will block on the compression completing as the task goes out of scope

View File

@ -148,6 +148,14 @@ static bool
ProtoSetter(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
// Do this here, rather than in |ProtoSetterImpl|, so even likely-buggy
// use of the __proto__ setter on unacceptable values, where no subsequent
// use occurs on an acceptable value, will trigger a warning.
RootedObject callee(cx, &args.callee());
if (!GlobalObject::warnOnceAboutPrototypeMutation(cx, callee))
return false;
return CallNonGenericMethod(cx, TestProtoThis, ProtoSetterImpl, args);
}
@ -501,18 +509,17 @@ GlobalObject::isRuntimeCodeGenEnabled(JSContext *cx, Handle<GlobalObject*> globa
}
/* static */ bool
GlobalObject::warnOnceAboutWatch(JSContext *cx, HandleObject obj)
GlobalObject::warnOnceAbout(JSContext *cx, HandleObject obj, uint32_t slot, unsigned errorNumber)
{
Rooted<GlobalObject*> global(cx, &obj->global());
HeapSlot &v = global->getSlotRef(WARNED_WATCH_DEPRECATED);
HeapSlot &v = global->getSlotRef(slot);
if (v.isUndefined()) {
// Warn only once per global object.
if (!JS_ReportErrorFlagsAndNumber(cx, JSREPORT_WARNING, js_GetErrorMessage, nullptr,
JSMSG_OBJECT_WATCH_DEPRECATED))
errorNumber))
{
return false;
}
v.init(global, HeapSlot::Slot, WARNED_WATCH_DEPRECATED, BooleanValue(true));
v.init(global, HeapSlot::Slot, slot, BooleanValue(true));
}
return true;
}

View File

@ -105,7 +105,8 @@ class GlobalObject : public JSObject
static const unsigned DATE_TIME_FORMAT_PROTO = NUMBER_FORMAT_PROTO + 1;
static const unsigned REGEXP_STATICS = DATE_TIME_FORMAT_PROTO + 1;
static const unsigned WARNED_WATCH_DEPRECATED = REGEXP_STATICS + 1;
static const unsigned RUNTIME_CODEGEN_ENABLED = WARNED_WATCH_DEPRECATED + 1;
static const unsigned WARNED_PROTO_SETTING_SLOW = WARNED_WATCH_DEPRECATED + 1;
static const unsigned RUNTIME_CODEGEN_ENABLED = WARNED_PROTO_SETTING_SLOW + 1;
static const unsigned DEBUGGERS = RUNTIME_CODEGEN_ENABLED + 1;
static const unsigned INTRINSICS = DEBUGGERS + 1;
static const unsigned FLOAT32X4_TYPE_OBJECT = INTRINSICS + 1;
@ -151,6 +152,13 @@ class GlobalObject : public JSObject
setSlot(INTRINSICS, ObjectValue(*obj));
}
// Emit the specified warning if the given slot in |obj|'s global isn't
// true, then set the slot to true. Thus calling this method warns once
// for each global object it's called on, and every other call does
// nothing.
static bool
warnOnceAbout(JSContext *cx, HandleObject obj, uint32_t slot, unsigned errorNumber);
public:
Value getConstructor(JSProtoKey key) const {
JS_ASSERT(key <= JSProto_LIMIT);
@ -605,7 +613,20 @@ class GlobalObject : public JSObject
// Warn about use of the deprecated watch/unwatch functions in the global
// in which |obj| was created, if no prior warning was given.
static bool warnOnceAboutWatch(JSContext *cx, HandleObject obj);
static bool warnOnceAboutWatch(JSContext *cx, HandleObject obj) {
// Temporarily disabled until we've provided a watch/unwatch workaround for
// debuggers like Firebug (bug 934669).
//return warnOnceAbout(cx, obj, WARNED_WATCH_DEPRECATED, JSMSG_OBJECT_WATCH_DEPRECATED);
return true;
}
// Warn about use of the given __proto__ setter to attempt to mutate an
// object's [[Prototype]], if no prior warning was given.
static bool warnOnceAboutPrototypeMutation(JSContext *cx, HandleObject protoSetter) {
// Temporarily disabled until the second half of bug 948583 lands.
//return warnOnceAbout(cx, protoSetter, WARNED_PROTO_SETTING_SLOW, JSMSG_PROTO_SETTING_SLOW);
return true;
}
static bool getOrCreateEval(JSContext *cx, Handle<GlobalObject*> global,
MutableHandleObject eval);

View File

@ -1658,7 +1658,6 @@ CASE(JSOP_UNUSED189)
CASE(JSOP_UNUSED190)
CASE(JSOP_UNUSED191)
CASE(JSOP_UNUSED192)
CASE(JSOP_UNUSED194)
CASE(JSOP_UNUSED196)
CASE(JSOP_UNUSED201)
CASE(JSOP_UNUSED205)
@ -3112,6 +3111,28 @@ CASE(JSOP_ENDINIT)
}
END_CASE(JSOP_ENDINIT)
CASE(JSOP_MUTATEPROTO)
{
/* Load the new [[Prototype]] value into rval. */
MOZ_ASSERT(REGS.stackDepth() >= 2);
RootedValue &rval = rootValue0;
rval = REGS.sp[-1];
/* Load the object being initialized into lval/obj. */
RootedObject &obj = rootObject0;
obj = &REGS.sp[-2].toObject();
MOZ_ASSERT(obj->is<JSObject>());
RootedId &id = rootId0;
id = NameToId(cx->names().proto);
if (!baseops::SetPropertyHelper<SequentialExecution>(cx, obj, obj, id, 0, &rval, false))
goto error;
REGS.sp--;
}
END_CASE(JSOP_MUTATEPROTO);
CASE(JSOP_INITPROP)
{
/* Load the property's initial value into rval. */
@ -3129,13 +3150,8 @@ CASE(JSOP_INITPROP)
RootedId &id = rootId0;
id = NameToId(name);
if (JS_UNLIKELY(name == cx->names().proto)
? !baseops::SetPropertyHelper<SequentialExecution>(cx, obj, obj, id, 0, &rval,
script->strict())
: !DefineNativeProperty(cx, obj, id, rval, nullptr, nullptr,
JSPROP_ENUMERATE, 0, 0, 0)) {
if (!DefineNativeProperty(cx, obj, id, rval, nullptr, nullptr, JSPROP_ENUMERATE, 0, 0, 0))
goto error;
}
REGS.sp--;
}

View File

@ -2075,6 +2075,8 @@ nsListControlFrame::KeyDown(nsIDOMEvent* aKeyEvent)
return NS_OK;
}
AutoIncrementalSearchResetter incrementalSearchResetter;
// Don't check defaultPrevented value because other browsers don't prevent
// the key navigation of list control even if preventDefault() is called.
@ -2124,41 +2126,45 @@ nsListControlFrame::KeyDown(nsIDOMEvent* aKeyEvent)
1, 1);
break;
case NS_VK_RETURN:
if (mComboboxFrame) {
nsWeakFrame weakFrame(this);
if (IsInDropDownMode()) {
// If the select element is a dropdown style, Enter key should be
// consumed everytime since Enter key may be pressed accidentally after
// the dropdown is closed by Enter key press.
aKeyEvent->PreventDefault();
if (mComboboxFrame->IsDroppedDown()) {
// At closing dropdown, users may not expect there is additional
// behavior for this key event. Therefore, let's consume the event.
aKeyEvent->PreventDefault();
nsWeakFrame weakFrame(this);
ComboboxFinish(mEndSelectionIndex);
if (!weakFrame.IsAlive()) {
return NS_OK;
}
}
// XXX This is strange. On other browsers, "change" event is fired
// immediately after the selected item is changed rather than
// Enter key is pressed.
FireOnChange();
if (!weakFrame.IsAlive()) {
// If the keydown event causes destroying this, fired keypress on
// another element may cause another action which may not be
// expected by the user.
aKeyEvent->PreventDefault();
}
return NS_OK;
}
// If this is single select listbox, Enter key doesn't cause anything.
if (!GetMultiple()) {
return NS_OK;
}
newIndex = mEndSelectionIndex;
break;
case NS_VK_ESCAPE: {
nsWeakFrame weakFrame(this);
// XXX When the Escape keydown causes closing dropdown, it shouldn't
// cause any additonal actions. We should call preventDefault() here.
AboutToRollup();
if (!weakFrame.IsAlive()) {
// If the keydown event causes destroying this, fired keypress on
// another element may cause another action which may not be
// expected by the user.
aKeyEvent->PreventDefault();
// If the select element is a listbox style, Escape key causes nothing.
if (!IsInDropDownMode()) {
return NS_OK;
}
break;
AboutToRollup();
// If the select element is a dropdown style, Enter key should be
// consumed everytime since Escape key may be pressed accidentally after
// the dropdown is closed by Escepe key.
aKeyEvent->PreventDefault();
return NS_OK;
}
case NS_VK_PAGE_UP: {
int32_t itemsPerPage =
@ -2194,14 +2200,12 @@ nsListControlFrame::KeyDown(nsIDOMEvent* aKeyEvent)
#endif
default: // printable key will be handled by keypress event.
incrementalSearchResetter.Cancel();
return NS_OK;
}
aKeyEvent->PreventDefault();
// Cancel incremental search if it's being performed.
GetIncrementalString().Truncate();
// Actually process the new index and let the selection code
// do the scrolling for us
PostHandleKeyEvent(newIndex, 0, keyEvent->IsShift(), isControlOrMeta);
@ -2218,6 +2222,8 @@ nsListControlFrame::KeyPress(nsIDOMEvent* aKeyEvent)
return NS_OK;
}
AutoIncrementalSearchResetter incrementalSearchResetter;
const WidgetKeyboardEvent* keyEvent =
aKeyEvent->GetInternalNSEvent()->AsKeyboardEvent();
MOZ_ASSERT(keyEvent,
@ -2250,17 +2256,25 @@ nsListControlFrame::KeyPress(nsIDOMEvent* aKeyEvent)
// NOTE: If keyCode of keypress event is not 0, charCode is always 0.
// Therefore, all non-printable keys are not handled after this block.
if (!keyEvent->charCode) {
// Backspace key will delete the last char in the string
// XXX Backspace key causes "go back the history" on Windows. Shouldn't we
// prevent its default action if incremental search is used since
// getting focus? When I tested this, it worked accidentally.
if (keyEvent->keyCode == NS_VK_BACK && !GetIncrementalString().IsEmpty()) {
GetIncrementalString().Truncate(GetIncrementalString().Length() - 1);
// Backspace key will delete the last char in the string. Otherwise,
// non-printable keypress should reset incremental search.
if (keyEvent->keyCode == NS_VK_BACK) {
incrementalSearchResetter.Cancel();
if (!GetIncrementalString().IsEmpty()) {
GetIncrementalString().Truncate(GetIncrementalString().Length() - 1);
}
aKeyEvent->PreventDefault();
} else {
// XXX When a select element has focus, even if the key causes nothing,
// it might be better to call preventDefault() here because nobody
// should expect one of other elements including chrome handles the
// key event.
}
return NS_OK;
}
incrementalSearchResetter.Cancel();
// We ate the key if we got this far.
aKeyEvent->PreventDefault();

View File

@ -445,6 +445,27 @@ private:
// for incremental typing navigation
static nsAString& GetIncrementalString ();
static DOMTimeStamp gLastKeyTime;
class MOZ_STACK_CLASS AutoIncrementalSearchResetter
{
public:
AutoIncrementalSearchResetter() :
mCancelled(false)
{
}
~AutoIncrementalSearchResetter()
{
if (!mCancelled) {
nsListControlFrame::GetIncrementalString().Truncate();
}
}
void Cancel()
{
mCancelled = true;
}
private:
bool mCancelled;
};
};
#endif /* nsListControlFrame_h___ */

View File

@ -799,7 +799,7 @@ void nsDisplayNotation::Paint(nsDisplayListBuilder* aBuilder,
rect.TopRight() + gfxPoint(std::min(e / 2.0, -w + .4*h), h + .4*w),
rect.TopRight()
};
gfxCtx->Polygon(p, sizeof(p));
gfxCtx->Polygon(p, MOZ_ARRAY_LENGTH(p));
gfxCtx->Fill();
}
break;

View File

@ -560,6 +560,7 @@ function getStreamContent(inputStream)
function BuildConditionSandbox(aURL) {
var sandbox = new Components.utils.Sandbox(aURL.spec);
var xr = CC[NS_XREAPPINFO_CONTRACTID].getService(CI.nsIXULRuntime);
var appInfo = CC[NS_XREAPPINFO_CONTRACTID].getService(CI.nsIXULAppInfo);
sandbox.isDebugBuild = gDebug.isDebugBuild;
sandbox.xulRuntime = {widgetToolkit: xr.widgetToolkit, OS: xr.OS, __exposedProps__: { widgetToolkit: "r", OS: "r", XPCOMABI: "r", shell: "r" } };
@ -600,6 +601,7 @@ function BuildConditionSandbox(aURL) {
// Shortcuts for widget toolkits.
sandbox.B2G = xr.widgetToolkit == "gonk";
sandbox.B2GDT = appInfo.name.toLowerCase() == "b2g" && !sandbox.B2G;
sandbox.Android = xr.OS == "Android" && !sandbox.B2G;
sandbox.cocoaWidget = xr.widgetToolkit == "cocoa";
sandbox.gtk2Widget = xr.widgetToolkit == "gtk2";

View File

@ -17,6 +17,10 @@ LIBS = \
$(DEPTH)/netwerk/srtp/src/$(LIB_PREFIX)nksrtp_s.$(LIB_SUFFIX) \
$(NULL)
ifdef JS_SHARED_LIBRARY
LIBS += $(MOZ_JS_LIBS)
endif
ifdef MOZ_ALSA
LIBS += \
$(MOZ_ALSA_LIBS) \

View File

@ -288,6 +288,9 @@ static const bool config_ivsalloc =
# ifdef __tile__
# define LG_QUANTUM 4
# endif
# ifdef __aarch64__
# define LG_QUANTUM 4
# endif
# ifndef LG_QUANTUM
# error "No LG_QUANTUM definition for architecture; specify via CPPFLAGS"
# endif

View File

@ -1102,7 +1102,7 @@ static unsigned ncpus;
#if (defined(SOLARIS) || defined(__FreeBSD__)) && \
(defined(__sparc) || defined(__sparcv9) || defined(__ia64))
#define pagesize_2pow ((size_t) 13)
#elif defined(__powerpc64__)
#elif defined(__powerpc64__) || defined(__aarch64__)
#define pagesize_2pow ((size_t) 16)
#else
#define pagesize_2pow ((size_t) 12)

View File

@ -122,14 +122,14 @@
defined(_POWER) || defined(__powerpc__) || \
defined(__ppc__) || defined(__hppa) || \
defined(_MIPSEB) || defined(__ARMEB__) || \
defined(__s390__) || \
defined(__s390__) || defined(__AARCH64EB__) || \
(defined(__sh__) && defined(__LITTLE_ENDIAN__)) || \
(defined(__ia64) && defined(__BIG_ENDIAN__))
# define MOZ_BIG_ENDIAN 1
#elif defined(__i386) || defined(__i386__) || \
defined(__x86_64) || defined(__x86_64__) || \
defined(_MIPSEL) || defined(__ARMEL__) || \
defined(__alpha__) || \
defined(__alpha__) || defined(__AARCH64EL__) || \
(defined(__sh__) && defined(__BIG_ENDIAN__)) || \
(defined(__ia64) && !defined(__BIG_ENDIAN__))
# define MOZ_LITTLE_ENDIAN 1

View File

@ -161,6 +161,9 @@
#elif defined __s390__
#define RETURN_INSTR 0x07fe0000 /* br %r14 */
#elif defined __aarch64__
#define RETURN_INSTR 0xd65f03c0 /* ret */
#elif defined __ia64
struct ia64_instr { uint32_t i[4]; };
static const ia64_instr _return_instr =

View File

@ -0,0 +1,7 @@
# 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/. */
ifdef JS_SHARED_LIBRARY
LIBS += $(MOZ_JS_LIBS)
endif

View File

@ -196,7 +196,8 @@ const PING_BGUC_INVALID_DEFAULT_URL = 2;
const PING_BGUC_INVALID_CUSTOM_URL = 3;
// Invalid url for app.update.url.override user preference (no notification)
const PING_BGUC_INVALID_OVERRIDE_URL = 4;
// Unable to check for updates per gCanCheckForUpdates (no notification)
// Unable to check for updates per gCanCheckForUpdates and hasUpdateMutex()
// (no notification)
const PING_BGUC_UNABLE_TO_CHECK = 5;
// Already has an active update in progress (no notification)
const PING_BGUC_HAS_ACTIVEUPDATE = 6;
@ -258,13 +259,14 @@ const PING_BGUC_ADDON_UPDATES_FOR_INCOMPAT = 29;
const PING_BGUC_ADDON_HAVE_INCOMPAT = 30;
var gLocale = null;
var gUpdateMutexHandle = null;
#ifdef MOZ_WIDGET_GONK
var gSDCardMountLock = null;
XPCOMUtils.defineLazyGetter(this, "gExtStorage", function aus_gExtStorage() {
return Services.env.get("EXTERNAL_STORAGE");
});
var gSDCardMountLock = null;
#endif
XPCOMUtils.defineLazyModuleGetter(this, "UpdateChannel",
@ -483,10 +485,13 @@ function closeHandle(handle) {
/**
* Creates a mutex.
*
* @param aAllowExisting false if the function should fail if the mutex exists
* @return The Win32 handle to the mutex
* @param aName
* The name for the mutex.
* @param aAllowExisting
* If false the function will close the handle and return null.
* @return The Win32 handle to the mutex.
*/
function createMutex(name, aAllowExisting) {
function createMutex(aName, aAllowExisting) {
if (aAllowExisting === undefined) {
aAllowExisting = true;
}
@ -501,7 +506,7 @@ function createMutex(name, aAllowExisting) {
ctypes.int32_t, /* initial owner */
ctypes.jschar.ptr); /* name */
var handle = CreateMutexW(null, INITIAL_OWN, name);
var handle = CreateMutexW(null, INITIAL_OWN, aName);
var alreadyExists = ctypes.winLastError == ERROR_ALREADY_EXISTS;
if (handle && !handle.isNull() && !aAllowExisting && alreadyExists) {
closeHandle(handle);
@ -554,11 +559,11 @@ function getPerInstallationMutexName(aGlobal) {
*/
function hasUpdateMutex() {
#ifdef XP_WIN
if (!this._updateMutexHandle) {
this._updateMutexHandle = createMutex(getPerInstallationMutexName(true), false);
if (!gUpdateMutexHandle) {
gUpdateMutexHandle = createMutex(getPerInstallationMutexName(true), false);
}
return !!this._updateMutexHandle;
return !!gUpdateMutexHandle;
#else
return true;
#endif // XP_WIN
@ -669,13 +674,6 @@ XPCOMUtils.defineLazyGetter(this, "gCanApplyUpdates", function aus_gCanApplyUpda
}
} // if (!useService)
if (!hasUpdateMutex()) {
LOG("gCanApplyUpdates - unable to apply updates because another instance" +
"of the application is already handling updates for this " +
"installation.");
return false;
}
LOG("gCanApplyUpdates - able to apply updates");
submitHasPermissionsTelemetryPing(true);
return true;
@ -795,13 +793,6 @@ XPCOMUtils.defineLazyGetter(this, "gCanCheckForUpdates", function aus_gCanCheckF
return false;
}
if (!hasUpdateMutex()) {
LOG("gCanCheckForUpdates - unable to apply updates because another " +
"instance of the application is already handling updates for this " +
"installation.");
return false;
}
LOG("gCanCheckForUpdates - able to check for updates");
return true;
});
@ -2611,7 +2602,7 @@ UpdateService.prototype = {
else if (!getPref("getBoolPref", PREF_APP_UPDATE_ENABLED, true)) {
this._backgroundUpdateCheckCodePing(PING_BGUC_PREF_DISABLED);
}
else if (!gCanCheckForUpdates) {
else if (!(gCanCheckForUpdates && hasUpdateMutex())) {
this._backgroundUpdateCheckCodePing(PING_BGUC_UNABLE_TO_CHECK);
}
else if (!this.backgroundChecker._enabled) {
@ -2759,7 +2750,7 @@ UpdateService.prototype = {
return;
}
if (!gCanApplyUpdates) {
if (!(gCanApplyUpdates && hasUpdateMutex())) {
LOG("UpdateService:_selectAndInstallUpdate - the user is unable to " +
"apply updates... prompting");
this._showPrompt(update);
@ -2970,7 +2961,8 @@ UpdateService.prototype = {
if (--this._updateCheckCount > 0)
return;
if (this._incompatibleAddons.length > 0 || !gCanApplyUpdates) {
if (this._incompatibleAddons.length > 0 ||
!(gCanApplyUpdates && hasUpdateMutex())) {
LOG("UpdateService:onUpdateEnded - prompting because there are " +
"incompatible add-ons");
this._showPrompt(this._update);
@ -3005,14 +2997,14 @@ UpdateService.prototype = {
* See nsIUpdateService.idl
*/
get canCheckForUpdates() {
return gCanCheckForUpdates;
return gCanCheckForUpdates && hasUpdateMutex();
},
/**
* See nsIUpdateService.idl
*/
get canApplyUpdates() {
return gCanApplyUpdates;
return gCanApplyUpdates && hasUpdateMutex();
},
/**
@ -3798,7 +3790,7 @@ Checker.prototype = {
}
return getPref("getBoolPref", PREF_APP_UPDATE_ENABLED, true) &&
gCanCheckForUpdates && this._enabled;
gCanCheckForUpdates && hasUpdateMutex() && this._enabled;
},
/**

View File

@ -8,21 +8,127 @@ function run_test() {
// Verify write access to the custom app dir
logTestInfo("testing write access to the application directory");
var testFile = getCurrentProcessDir();
let testFile = getCurrentProcessDir();
testFile.append("update_write_access_test");
testFile.create(AUS_Ci.nsIFile.NORMAL_FILE_TYPE, 0o644);
testFile.create(AUS_Ci.nsIFile.NORMAL_FILE_TYPE, PERMS_FILE);
do_check_true(testFile.exists());
testFile.remove(false);
do_check_false(testFile.exists());
standardInit();
if (IS_WIN) {
// Create a mutex to prevent being able to check for or apply updates.
logTestInfo("attempting to create mutex");
let handle = createMutex(getPerInstallationMutexName());
logTestInfo("testing that the mutex was successfully created");
do_check_neq(handle, null);
// Check if available updates cannot be checked for when there is a mutex
// for this installation.
logTestInfo("testing nsIApplicationUpdateService:canCheckForUpdates is " +
"false when there is a mutex");
do_check_false(gAUS.canCheckForUpdates);
// Check if updates cannot be applied when there is a mutex for this
// installation.
logTestInfo("testing nsIApplicationUpdateService:canApplyUpdates is " +
"false when there is a mutex");
do_check_false(gAUS.canApplyUpdates);
logTestInfo("destroying mutex");
closeHandle(handle)
}
// Check if available updates can be checked for
logTestInfo("testing nsIApplicationUpdateService:canCheckForUpdates");
logTestInfo("testing nsIApplicationUpdateService:canCheckForUpdates is true");
do_check_true(gAUS.canCheckForUpdates);
// Check if updates can be applied
logTestInfo("testing nsIApplicationUpdateService:canApplyUpdates");
logTestInfo("testing nsIApplicationUpdateService:canApplyUpdates is true");
do_check_true(gAUS.canApplyUpdates);
if (IS_WIN) {
// Attempt to create a mutex when application update has already created one
// with the same name.
logTestInfo("attempting to create mutex");
let handle = createMutex(getPerInstallationMutexName());
logTestInfo("testing that the mutex was not successfully created");
do_check_eq(handle, null);
}
doTestFinish();
}
if (IS_WIN) {
/**
* Determines a unique mutex name for the installation.
*
* @return Global mutex path.
*/
function getPerInstallationMutexName() {
let hasher = AUS_Cc["@mozilla.org/security/hash;1"].
createInstance(AUS_Ci.nsICryptoHash);
hasher.init(hasher.SHA1);
let exeFile = Services.dirsvc.get(XRE_EXECUTABLE_FILE, AUS_Ci.nsILocalFile);
let converter = AUS_Cc["@mozilla.org/intl/scriptableunicodeconverter"].
createInstance(AUS_Ci.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
let data = converter.convertToByteArray(exeFile.path.toLowerCase());
hasher.update(data, data.length);
return "Global\\MozillaUpdateMutex-" + hasher.finish(true);
}
/**
* Closes a Win32 handle.
*
* @param aHandle
* The handle to close.
*/
function closeHandle(aHandle) {
let lib = ctypes.open("kernel32.dll");
let CloseHandle = lib.declare("CloseHandle",
ctypes.winapi_abi,
ctypes.int32_t, /* success */
ctypes.void_t.ptr); /* handle */
CloseHandle(aHandle);
lib.close();
}
/**
* Creates a mutex.
*
* @param aName
* The name for the mutex.
* @return The Win32 handle to the mutex.
*/
function createMutex(aName) {
const INITIAL_OWN = 1;
const ERROR_ALREADY_EXISTS = 0xB7;
let lib = ctypes.open("kernel32.dll");
let CreateMutexW = lib.declare("CreateMutexW",
ctypes.winapi_abi,
ctypes.void_t.ptr, /* return handle */
ctypes.void_t.ptr, /* security attributes */
ctypes.int32_t, /* initial owner */
ctypes.jschar.ptr); /* name */
let handle = CreateMutexW(null, INITIAL_OWN, aName);
lib.close();
let alreadyExists = ctypes.winLastError == ERROR_ALREADY_EXISTS;
if (handle && !handle.isNull() && alreadyExists) {
closeHandle(handle);
handle = null;
}
if (handle && handle.isNull()) {
handle = null;
}
return handle;
}
}

View File

@ -43,6 +43,7 @@
#include "libdisplay/GonkDisplay.h"
#include "pixelflinger/format.h"
#include "mozilla/BasicEvents.h"
#include "mozilla/layers/APZCTreeManager.h"
#include "mozilla/layers/CompositorParent.h"
#include "ParentProcessController.h"
#include "nsThreadUtils.h"
@ -573,6 +574,7 @@ nsWindow::GetLayerManager(PLayerTransactionChild* aShadowManager,
if (mCompositorParent) {
uint64_t rootLayerTreeId = mCompositorParent->RootLayerTreeId();
CompositorParent::SetControllerForLayerTree(rootLayerTreeId, new ParentProcessController());
CompositorParent::GetAPZCTreeManager(rootLayerTreeId)->SetDPI(GetDPI());
}
if (mLayerManager)
return mLayerManager;