import changes from `dev' branch of rmottola/Arctic-Fox:

- code style, spacing (d4f024213a)
- Bug 1205586 - new Date().toLocale{,Date,Time}String() should return appropriately differing strings as the local time zone/default locale change. r=till (cf46706e94)
- Bug 1204025 - Change Symbol.length to be 0 instead of 1. r=jorendorff (f1e3f45756)
- remove some PM esr38 diffs (f38809c3fa)
- Bug 1177018 - Send mouse move events generated via nsIPresShell::SynthesizeMouseMove() to the child process through a different IPDL message than real mouse move events. r=smaug (7029fe2d3b)
- Bug 1186135 - change active flag per channel. r=ehsan (239d99b7cc)
- Bug 1175940 - UIResolutionChanged should not trigger sync messages from content to chrome. r=mconley (147fbfd33a)
- Bug 1156662 - Identical code for different branches. r=bz (8487a27847)
- Bug 1183954 - Fix Notification.data structured cloning on workers. r=robertbindar,mccr8 (82187ef6c2)
- Bug 1189389 - nsIStructuredCloneContainer should use StructuredCloneHelper, r=smaug (6cddb9453a)
This commit is contained in:
2022-03-10 14:34:01 +08:00
parent 721a898225
commit 80aa647a5d
26 changed files with 444 additions and 177 deletions
+1 -1
View File
@@ -26,7 +26,7 @@ namespace dom {
class SpeakerManagerService;
#endif
#define NUMBER_OF_AUDIO_CHANNELS (uint32_t)AudioChannel::Publicnotification + 1
#define NUMBER_OF_AUDIO_CHANNELS (uint32_t)AudioChannel::EndGuard_
class AudioChannelService final : public nsIAudioChannelService
, public nsIObserver
+20 -6
View File
@@ -125,7 +125,6 @@ void
StructuredCloneHelperInternal::Shutdown()
{
#ifdef DEBUG
MOZ_ASSERT(!mShutdownCalled, "Shutdown already called!");
mShutdownCalled = true;
#endif
@@ -163,7 +162,6 @@ StructuredCloneHelperInternal::Read(JSContext* aCx,
MOZ_ASSERT(!mShutdownCalled, "This method cannot be called after Shutdown.");
bool ok = mBuffer->read(aCx, aValue, &gCallbacks, this);
mBuffer = nullptr;
return ok;
}
@@ -247,7 +245,11 @@ StructuredCloneHelper::Read(nsISupports* aParent,
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
}
mBlobImplArray.Clear();
// If we are tranferring something, we cannot call 'Read()' more than once.
if (mSupportsTransferring) {
mBlobImplArray.Clear();
Shutdown();
}
}
void
@@ -257,6 +259,19 @@ StructuredCloneHelper::ReadFromBuffer(nsISupports* aParent,
size_t aBufferLength,
JS::MutableHandle<JS::Value> aValue,
ErrorResult& aRv)
{
ReadFromBuffer(aParent, aCx, aBuffer, aBufferLength,
JS_STRUCTURED_CLONE_VERSION, aValue, aRv);
}
void
StructuredCloneHelper::ReadFromBuffer(nsISupports* aParent,
JSContext* aCx,
uint64_t* aBuffer,
size_t aBufferLength,
uint32_t aAlgorithmVersion,
JS::MutableHandle<JS::Value> aValue,
ErrorResult& aRv)
{
MOZ_ASSERT(!mBuffer, "ReadFromBuffer() must be called without a Write().");
MOZ_ASSERT(aBuffer);
@@ -264,9 +279,8 @@ StructuredCloneHelper::ReadFromBuffer(nsISupports* aParent,
mozilla::AutoRestore<nsISupports*> guard(mParent);
mParent = aParent;
if (!JS_ReadStructuredClone(aCx, aBuffer, aBufferLength,
JS_STRUCTURED_CLONE_VERSION, aValue,
&gCallbacks, this)) {
if (!JS_ReadStructuredClone(aCx, aBuffer, aBufferLength, aAlgorithmVersion,
aValue, &gCallbacks, this)) {
JS_ClearPendingException(aCx);
aRv.Throw(NS_ERROR_DOM_DATA_CLONE_ERR);
}
+14
View File
@@ -159,10 +159,24 @@ public:
JS::MutableHandle<JS::Value> aValue,
ErrorResult &aRv);
void ReadFromBuffer(nsISupports* aParent,
JSContext* aCx,
uint64_t* aBuffer,
size_t aBufferLength,
uint32_t aAlgorithmVersion,
JS::MutableHandle<JS::Value> aValue,
ErrorResult &aRv);
// Use this method to free a buffer generated by MoveToBuffer().
void FreeBuffer(uint64_t* aBuffer,
size_t aBufferLength);
bool HasClonedDOMObjects() const
{
return !mBlobImplArray.IsEmpty() ||
!mClonedImages.IsEmpty();
}
nsTArray<nsRefPtr<BlobImpl>>& BlobImpls()
{
MOZ_ASSERT(mSupportsCloning, "Blobs cannot be taken/set if cloning is not supported.");
+115 -60
View File
@@ -13,14 +13,14 @@
#include "nsServiceManagerUtils.h"
#include "nsContentUtils.h"
#include "jsapi.h"
#include "jsfriendapi.h"
#include "js/StructuredClone.h"
#include "xpcpublic.h"
#include "mozilla/Base64.h"
#include "mozilla/dom/StructuredCloneHelper.h"
#include "mozilla/dom/ScriptSettings.h"
using namespace mozilla;
using namespace mozilla::dom;
NS_IMPL_ADDREF(nsStructuredCloneContainer)
NS_IMPL_RELEASE(nsStructuredCloneContainer)
@@ -31,60 +31,44 @@ NS_INTERFACE_MAP_BEGIN(nsStructuredCloneContainer)
NS_INTERFACE_MAP_END
nsStructuredCloneContainer::nsStructuredCloneContainer()
: mData(nullptr), mSize(0), mVersion(0)
: StructuredCloneHelper(CloningSupported, TransferringNotSupported)
, mState(eNotInitialized) , mData(nullptr), mSize(0), mVersion(0)
{
}
nsStructuredCloneContainer::~nsStructuredCloneContainer()
{
free(mData);
if (mData) {
free(mData);
}
}
nsresult
NS_IMETHODIMP
nsStructuredCloneContainer::InitFromJSVal(JS::Handle<JS::Value> aData,
JSContext* aCx)
{
NS_ENSURE_STATE(!mData);
uint64_t* jsBytes = nullptr;
bool success = false;
if (aData.isPrimitive()) {
success = JS_WriteStructuredClone(aCx, aData, &jsBytes, &mSize,
nullptr, nullptr,
JS::UndefinedHandleValue);
} else {
success = JS_WriteStructuredClone(aCx, aData, &jsBytes, &mSize,
nullptr, nullptr,
JS::UndefinedHandleValue);
}
NS_ENSURE_STATE(success);
NS_ENSURE_STATE(jsBytes);
// Copy jsBytes into our own buffer.
mData = (uint64_t*) malloc(mSize);
if (!mData) {
mSize = 0;
mVersion = 0;
JS_ClearStructuredClone(jsBytes, mSize, nullptr, nullptr);
if (mState != eNotInitialized) {
return NS_ERROR_FAILURE;
}
else {
mVersion = JS_STRUCTURED_CLONE_VERSION;
ErrorResult rv;
Write(aCx, aData, rv);
if (NS_WARN_IF(rv.Failed())) {
return rv.StealNSResult();
}
memcpy(mData, jsBytes, mSize);
JS_ClearStructuredClone(jsBytes, mSize, nullptr, nullptr);
mState = eInitializedFromJSVal;
return NS_OK;
}
nsresult
NS_IMETHODIMP
nsStructuredCloneContainer::InitFromBase64(const nsAString &aData,
uint32_t aFormatVersion,
JSContext *aCx)
JSContext* aCx)
{
NS_ENSURE_STATE(!mData);
if (mState != eNotInitialized) {
return NS_ERROR_FAILURE;
}
NS_ConvertUTF16toUTF8 data(aData);
@@ -99,28 +83,56 @@ nsStructuredCloneContainer::InitFromBase64(const nsAString &aData,
mSize = binaryData.Length();
mVersion = aFormatVersion;
mState = eInitializedFromBase64;
return NS_OK;
}
nsresult
nsStructuredCloneContainer::DeserializeToVariant(JSContext *aCx,
nsIVariant **aData)
nsStructuredCloneContainer::DeserializeToJsval(JSContext* aCx,
JS::MutableHandle<JS::Value> aValue)
{
aValue.setNull();
JS::Rooted<JS::Value> jsStateObj(aCx);
if (mState == eInitializedFromJSVal) {
ErrorResult rv;
Read(nullptr, aCx, &jsStateObj, rv);
if (NS_WARN_IF(rv.Failed())) {
return rv.StealNSResult();
}
} else {
MOZ_ASSERT(mState == eInitializedFromBase64);
MOZ_ASSERT(mData);
ErrorResult rv;
ReadFromBuffer(nullptr, aCx, mData, mSize, mVersion, &jsStateObj, rv);
if (NS_WARN_IF(rv.Failed())) {
return rv.StealNSResult();
}
}
aValue.set(jsStateObj);
return NS_OK;
}
NS_IMETHODIMP
nsStructuredCloneContainer::DeserializeToVariant(JSContext* aCx,
nsIVariant** aData)
{
NS_ENSURE_STATE(mData);
NS_ENSURE_ARG_POINTER(aData);
*aData = nullptr;
if (mState == eNotInitialized) {
return NS_ERROR_FAILURE;
}
// Deserialize to a JS::Value.
JS::Rooted<JS::Value> jsStateObj(aCx);
bool hasTransferable = false;
bool success = JS_ReadStructuredClone(aCx, mData, mSize, mVersion,
&jsStateObj, nullptr, nullptr) &&
JS_StructuredCloneHasTransferables(mData, mSize,
&hasTransferable);
// We want to be sure that mData doesn't contain transferable objects
MOZ_ASSERT(!hasTransferable);
NS_ENSURE_STATE(success && !hasTransferable);
nsresult rv = DeserializeToJsval(aCx, &jsStateObj);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
// Now wrap the JS::Value as an nsIVariant.
nsCOMPtr<nsIVariant> varStateObj;
@@ -129,31 +141,64 @@ nsStructuredCloneContainer::DeserializeToVariant(JSContext *aCx,
xpconnect->JSValToVariant(aCx, jsStateObj, getter_AddRefs(varStateObj));
NS_ENSURE_STATE(varStateObj);
NS_ADDREF(*aData = varStateObj);
varStateObj.forget(aData);
return NS_OK;
}
nsresult
NS_IMETHODIMP
nsStructuredCloneContainer::GetDataAsBase64(nsAString &aOut)
{
NS_ENSURE_STATE(mData);
aOut.Truncate();
nsAutoCString binaryData(reinterpret_cast<char*>(mData), mSize);
if (mState == eNotInitialized) {
return NS_ERROR_FAILURE;
}
uint64_t* data;
size_t size;
if (mState == eInitializedFromJSVal) {
if (HasClonedDOMObjects()) {
return NS_ERROR_FAILURE;
}
data = BufferData();
size = BufferSize();
} else {
MOZ_ASSERT(mState == eInitializedFromBase64);
MOZ_ASSERT(mData);
data = mData;
size = mSize;
}
nsAutoCString binaryData(reinterpret_cast<char*>(data), size);
nsAutoCString base64Data;
nsresult rv = Base64Encode(binaryData, base64Data);
NS_ENSURE_SUCCESS(rv, rv);
if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
}
aOut.Assign(NS_ConvertASCIItoUTF16(base64Data));
CopyASCIItoUTF16(base64Data, aOut);
return NS_OK;
}
nsresult
nsStructuredCloneContainer::GetSerializedNBytes(uint64_t *aSize)
NS_IMETHODIMP
nsStructuredCloneContainer::GetSerializedNBytes(uint64_t* aSize)
{
NS_ENSURE_STATE(mData);
NS_ENSURE_ARG_POINTER(aSize);
if (mState == eNotInitialized) {
return NS_ERROR_FAILURE;
}
if (mState == eInitializedFromJSVal) {
*aSize = BufferSize();
return NS_OK;
}
MOZ_ASSERT(mState == eInitializedFromBase64);
// mSize is a size_t, while aSize is a uint64_t. We rely on an implicit cast
// here so that we'll get a compile error if a size_t-to-uint64_t cast is
// narrowing.
@@ -162,11 +207,21 @@ nsStructuredCloneContainer::GetSerializedNBytes(uint64_t *aSize)
return NS_OK;
}
nsresult
nsStructuredCloneContainer::GetFormatVersion(uint32_t *aFormatVersion)
NS_IMETHODIMP
nsStructuredCloneContainer::GetFormatVersion(uint32_t* aFormatVersion)
{
NS_ENSURE_STATE(mData);
NS_ENSURE_ARG_POINTER(aFormatVersion);
if (mState == eNotInitialized) {
return NS_ERROR_FAILURE;
}
if (mState == eInitializedFromJSVal) {
*aFormatVersion = JS_STRUCTURED_CLONE_VERSION;
return NS_OK;
}
MOZ_ASSERT(mState == eInitializedFromBase64);
*aFormatVersion = mVersion;
return NS_OK;
}
+10 -1
View File
@@ -9,6 +9,7 @@
#include "nsIStructuredCloneContainer.h"
#include "mozilla/Attributes.h"
#include "mozilla/dom/StructuredCloneHelper.h"
#define NS_STRUCTUREDCLONECONTAINER_CONTRACTID \
"@mozilla.org/docshell/structured-clone-container;1"
@@ -20,7 +21,9 @@
{0xb8, 0x5f, 0x13, 0xce, 0xd8, 0x89, 0xee, 0xec} \
}
class nsStructuredCloneContainer final : public nsIStructuredCloneContainer
class nsStructuredCloneContainer final
: public nsIStructuredCloneContainer
, public mozilla::dom::StructuredCloneHelper
{
public:
nsStructuredCloneContainer();
@@ -31,6 +34,12 @@ class nsStructuredCloneContainer final : public nsIStructuredCloneContainer
private:
~nsStructuredCloneContainer();
enum {
eNotInitialized = 0,
eInitializedFromJSVal,
eInitializedFromBase64,
} mState;
uint64_t* mData;
// This needs to be size_t rather than a PR-type so it matches the JS API.
@@ -27,7 +27,7 @@ interface nsIDocument;
* string containing a copy of the container's serialized data, using
* getDataAsBase64.
*/
[scriptable, uuid(63eeafec-63f5-42c3-aea9-5c04678784e7)]
[scriptable, uuid(c664aae7-0d67-4155-a2dd-a3861778626f)]
interface nsIStructuredCloneContainer : nsISupports
{
/**
@@ -45,9 +45,17 @@ interface nsIStructuredCloneContainer : nsISupports
[implicit_jscontext]
void initFromBase64(in AString aData,in unsigned long aFormatVersion);
/**
* Deserializes this structured clone container returning it as a jsval.
* Can be called on main and worker threads.
*/
[implicit_jscontext]
jsval deserializeToJsval();
/**
* Deserialize the object this container holds, returning it wrapped as
* an nsIVariant.
* Main thread only!
*/
[implicit_jscontext]
nsIVariant deserializeToVariant();
+14 -1
View File
@@ -621,6 +621,14 @@ child:
* they are 'compressed' by dumping the oldest one.
*/
RealMouseMoveEvent(WidgetMouseEvent event) compress;
/**
* Mouse move events with |reason == eSynthesized| are sent via a separate
* message because they do not generate DOM 'mousemove' events, and the
* 'compress' attribute on RealMouseMoveEvent() could result in a
* |reason == eReal| event being dropped in favour of an |eSynthesized|
* event, and thus a DOM 'mousemove' event to be lost.
*/
SynthMouseMoveEvent(WidgetMouseEvent event);
RealMouseButtonEvent(WidgetMouseEvent event);
RealKeyEvent(WidgetKeyboardEvent event, MaybeNativeKeyBinding keyBinding);
MouseWheelEvent(WidgetWheelEvent event, ScrollableLayerGuid aGuid, uint64_t aInputBlockId);
@@ -713,8 +721,13 @@ child:
/**
* Tell the child that the UI resolution changed for the containing
* window.
* To avoid some sync messages from child to parent, we also send the dpi
* and default scale with the notification.
* If we don't know the dpi and default scale, we just pass in a negative
* value (-1) but in the majority of the cases this saves us from two
* sync requests from the child to the parent.
*/
UIResolutionChanged();
UIResolutionChanged(float dpi, double scale);
/**
* Tell the child that the system theme has changed, and that a repaint
+15 -7
View File
@@ -8,7 +8,6 @@
#include "TabChild.h"
#include "AudioChannelService.h"
#include "gfxPrefs.h"
#ifdef ACCESSIBILITY
#include "mozilla/a11y/DocAccessibleChild.h"
@@ -601,7 +600,6 @@ TabChild::TabChild(nsIContentChild* aManager,
, mDefaultScale(0)
, mIPCOpen(true)
, mParentIsActive(false)
, mAudioChannelActive(false)
{
// In the general case having the TabParent tell us if APZ is enabled or not
// doesn't really work because the TabParent itself may not have a reference
@@ -631,6 +629,10 @@ TabChild::TabChild(nsIContentChild* aManager,
observerService->AddObserver(this, topic.get(), false);
}
}
for (uint32_t idx = 0; idx < NUMBER_OF_AUDIO_CHANNELS; idx++) {
mAudioChannelsActive.AppendElement(false);
}
}
NS_IMETHODIMP
@@ -714,8 +716,8 @@ TabChild::Observe(nsISupports *aSubject,
nsAutoString activeStr(aData);
bool active = activeStr.EqualsLiteral("active");
if (active != mAudioChannelActive) {
mAudioChannelActive = active;
if (active != mAudioChannelsActive[audioChannel]) {
mAudioChannelsActive[audioChannel] = active;
unused << SendAudioChannelActivityNotification(audioChannel, active);
}
}
@@ -755,7 +757,7 @@ TabChild::Init()
nsCOMPtr<nsIDocShellTreeItem> docShellItem(do_QueryInterface(WebNavigation()));
docShellItem->SetItemType(nsIDocShellTreeItem::typeContentWrapper);
nsCOMPtr<nsIBaseWindow> baseWindow = do_QueryInterface(WebNavigation());
if (!baseWindow) {
NS_ERROR("mWebNav doesn't QI to nsIBaseWindow");
@@ -1875,6 +1877,12 @@ TabChild::RecvRealMouseMoveEvent(const WidgetMouseEvent& event)
return RecvRealMouseButtonEvent(event);
}
bool
TabChild::RecvSynthMouseMoveEvent(const WidgetMouseEvent& event)
{
return RecvRealMouseButtonEvent(event);
}
bool
TabChild::RecvRealMouseButtonEvent(const WidgetMouseEvent& event)
{
@@ -2939,12 +2947,12 @@ TabChild::RecvRequestNotifyAfterRemotePaint()
}
bool
TabChild::RecvUIResolutionChanged()
TabChild::RecvUIResolutionChanged(const float& aDpi, const double& aScale)
{
ScreenIntSize oldScreenSize = GetInnerSize();
mDPI = 0;
mDefaultScale = 0;
static_cast<PuppetWidget*>(mPuppetWidget.get())->ClearBackingScaleCache();
static_cast<PuppetWidget*>(mPuppetWidget.get())->UpdateBackingScaleCache(aDpi, aScale);
nsCOMPtr<nsIDocument> document(GetDocument());
nsCOMPtr<nsIPresShell> presShell = document->GetShell();
if (presShell) {
+10 -7
View File
@@ -34,6 +34,7 @@
#include "mozilla/layers/CompositorTypes.h"
#include "nsIWebBrowserChrome3.h"
#include "mozilla/dom/ipc/IdType.h"
#include "AudioChannelService.h"
#include "PuppetWidget.h"
class nsICachedFileDescriptorListener;
@@ -42,22 +43,22 @@ class nsIDOMWindowUtils;
namespace mozilla {
namespace layout {
class RenderFrameChild;
}
} // namespace layout
namespace layers {
class APZEventState;
class ImageCompositeNotification;
struct SetTargetAPZCCallback;
struct SetAllowedTouchBehaviorCallback;
}
} // namespace layers
namespace widget {
struct AutoCacheNativeKeyCommands;
}
} // namespace widget
namespace plugins {
class PluginWidgetChild;
}
} // namespace plugins
namespace dom {
@@ -241,7 +242,7 @@ public:
static already_AddRefed<TabChild> FindTabChild(const TabId& aTabId);
public:
/**
/**
* This is expected to be called off the critical path to content
* startup. This is an opportunity to load things that are slow
* on the critical path.
@@ -333,6 +334,7 @@ public:
const int32_t& aModifiers,
const bool& aIgnoreRootScrollFrame) override;
virtual bool RecvRealMouseMoveEvent(const mozilla::WidgetMouseEvent& event) override;
virtual bool RecvSynthMouseMoveEvent(const mozilla::WidgetMouseEvent& event) override;
virtual bool RecvRealMouseButtonEvent(const mozilla::WidgetMouseEvent& event) override;
virtual bool RecvRealDragEvent(const WidgetDragEvent& aEvent,
const uint32_t& aDragAction,
@@ -471,7 +473,7 @@ public:
return GetFrom(docShell);
}
virtual bool RecvUIResolutionChanged() override;
virtual bool RecvUIResolutionChanged(const float& aDpi, const double& aScale) override;
virtual bool RecvThemeChanged(nsTArray<LookAndFeelInt>&& aLookAndFeelIntCache) override;
@@ -637,10 +639,11 @@ private:
double mDefaultScale;
bool mIPCOpen;
bool mParentIsActive;
bool mAudioChannelActive;
bool mAsyncPanZoomEnabled;
CSSSize mUnscaledInnerSize;
nsAutoTArray<bool, NUMBER_OF_AUDIO_CHANNELS> mAudioChannelsActive;
DISALLOW_EVIL_CONSTRUCTORS(TabChild);
};
+10 -2
View File
@@ -1092,7 +1092,11 @@ TabParent::UIResolutionChanged()
// mDPI being greater than 0, so this invalidates it.
mDPI = -1;
TryCacheDPIAndScale();
unused << SendUIResolutionChanged();
// If mDPI was set to -1 to invalidate it and then TryCacheDPIAndScale
// fails to cache the values, then mDefaultScale.scale might be invalid.
// We don't want to send that value to content. Just send -1 for it too in
// that case.
unused << SendUIResolutionChanged(mDPI, mDPI < 0 ? -1.0 : mDefaultScale.scale);
}
}
@@ -1391,7 +1395,11 @@ bool TabParent::SendRealMouseEvent(WidgetMouseEvent& event)
}
if (NS_MOUSE_MOVE == event.mMessage) {
return SendRealMouseMoveEvent(event);
if (event.reason == WidgetMouseEvent::eSynthesized) {
return SendSynthMouseMoveEvent(event);
} else {
return SendRealMouseMoveEvent(event);
}
}
return SendRealMouseButtonEvent(event);
}
+47 -37
View File
@@ -701,8 +701,8 @@ Notification::Notification(nsIGlobalObject* aGlobal, const nsAString& aID,
: DOMEventTargetHelper(),
mWorkerPrivate(nullptr), mObserver(nullptr),
mID(aID), mTitle(aTitle), mBody(aBody), mDir(aDir), mLang(aLang),
mTag(aTag), mIconUrl(aIconUrl), mBehavior(aBehavior), mIsClosed(false),
mIsStored(false), mTaskCount(0)
mTag(aTag), mIconUrl(aIconUrl), mBehavior(aBehavior), mData(JS::NullValue()),
mIsClosed(false), mIsStored(false), mTaskCount(0)
{
if (NS_IsMainThread()) {
// We can only call this on the main thread because
@@ -832,13 +832,6 @@ Notification::PersistNotification()
nsString alertName;
GetAlertName(alertName);
nsString dataString;
nsCOMPtr<nsIStructuredCloneContainer> scContainer;
scContainer = GetDataCloneContainer();
if (scContainer) {
scContainer->GetDataAsBase64(dataString);
}
nsAutoString behavior;
if (!mBehavior.ToJSON(behavior)) {
return NS_ERROR_FAILURE;
@@ -853,7 +846,7 @@ Notification::PersistNotification()
mTag,
mIconUrl,
alertName,
dataString,
mDataAsBase64,
behavior,
mScope);
@@ -918,6 +911,8 @@ Notification::CreateInternal(nsIGlobalObject* aGlobal,
Notification::~Notification()
{
mData.setUndefined();
mozilla::DropJSObjects(this);
AssertIsOnTargetThread();
MOZ_ASSERT(!mFeature);
MOZ_ASSERT(!mTempRef);
@@ -925,15 +920,16 @@ Notification::~Notification()
NS_IMPL_CYCLE_COLLECTION_CLASS(Notification)
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(Notification, DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mData)
NS_IMPL_CYCLE_COLLECTION_UNLINK(mDataObjectContainer)
tmp->mData.setUndefined();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(Notification, DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mData)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDataObjectContainer)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN_INHERITED(Notification, DOMEventTargetHelper)
NS_IMPL_CYCLE_COLLECTION_TRACE_JSVAL_MEMBER_CALLBACK(mData);
NS_IMPL_CYCLE_COLLECTION_TRACE_END
NS_IMPL_ADDREF_INHERITED(Notification, DOMEventTargetHelper)
NS_IMPL_RELEASE_INHERITED(Notification, DOMEventTargetHelper)
@@ -1389,13 +1385,6 @@ Notification::ShowInternal()
}
MOZ_ASSERT(observer);
// mDataObjectContainer might be uninitialized here because the notification
// was constructed with an undefined data property.
nsString dataStr;
if (mDataObjectContainer) {
mDataObjectContainer->GetDataAsBase64(dataStr);
}
#ifdef MOZ_B2G
nsCOMPtr<nsIAppNotificationService> appNotifier =
do_GetService("@mozilla.org/system-alerts-service;1");
@@ -1423,7 +1412,7 @@ Notification::ShowInternal()
ops.mDir = DirectionToString(mDir);
ops.mLang = mLang;
ops.mTag = mTag;
ops.mData = dataStr;
ops.mData = mDataAsBase64;
ops.mMozbehavior = mBehavior;
ops.mMozbehavior.mSoundFile = soundUrl;
@@ -1466,7 +1455,7 @@ Notification::ShowInternal()
alertService->ShowAlertNotification(iconUrl, mTitle, mBody, true,
uniqueCookie, observer, alertName,
DirectionToString(mDir), mLang,
dataStr, GetPrincipal(),
mDataAsBase64, GetPrincipal(),
inPrivateBrowsing);
}
@@ -1972,52 +1961,73 @@ Notification::GetOrigin(nsIPrincipal* aPrincipal, nsString& aOrigin)
return NS_OK;
}
nsIStructuredCloneContainer* Notification::GetDataCloneContainer()
{
return mDataObjectContainer;
}
void
Notification::GetData(JSContext* aCx,
JS::MutableHandle<JS::Value> aRetval)
{
if (!mData && mDataObjectContainer) {
if (mData.isNull() && !mDataAsBase64.IsEmpty()) {
nsresult rv;
rv = mDataObjectContainer->DeserializeToVariant(aCx, getter_AddRefs(mData));
auto container = new nsStructuredCloneContainer();
rv = container->InitFromBase64(mDataAsBase64, JS_STRUCTURED_CLONE_VERSION,
aCx);
if (NS_WARN_IF(NS_FAILED(rv))) {
aRetval.setNull();
return;
}
JS::Rooted<JS::Value> data(aCx);
rv = container->DeserializeToJsval(aCx, &data);
if (NS_WARN_IF(NS_FAILED(rv))) {
aRetval.setNull();
return;
}
if (data.isGCThing()) {
mozilla::HoldJSObjects(this);
}
mData = data;
}
if (!mData) {
if (mData.isNull()) {
aRetval.setNull();
return;
}
VariantToJsval(aCx, mData, aRetval);
JS::ExposeValueToActiveJS(mData);
aRetval.set(mData);
}
void
Notification::InitFromJSVal(JSContext* aCx, JS::Handle<JS::Value> aData,
ErrorResult& aRv)
{
if (mDataObjectContainer || aData.isNull()) {
if (!mDataAsBase64.IsEmpty() || aData.isNull()) {
return;
}
mDataObjectContainer = new nsStructuredCloneContainer();
aRv = mDataObjectContainer->InitFromJSVal(aData, aCx);
auto dataObjectContainer = new nsStructuredCloneContainer();
aRv = dataObjectContainer->InitFromJSVal(aData, aCx);
if (NS_WARN_IF(aRv.Failed())) {
return;
}
dataObjectContainer->GetDataAsBase64(mDataAsBase64);
}
void Notification::InitFromBase64(JSContext* aCx, const nsAString& aData,
ErrorResult& aRv)
{
if (mDataObjectContainer || aData.IsEmpty()) {
if (!mDataAsBase64.IsEmpty() || aData.IsEmpty()) {
return;
}
// To and fro to ensure it is valid base64.
auto container = new nsStructuredCloneContainer();
aRv = container->InitFromBase64(aData, JS_STRUCTURED_CLONE_VERSION,
aCx);
mDataObjectContainer = container;
if (NS_WARN_IF(aRv.Failed())) {
return;
}
container->GetDataAsBase64(mDataAsBase64);
}
bool
+3 -6
View File
@@ -17,7 +17,6 @@
#include "nsCycleCollectionParticipant.h"
class nsIPrincipal;
class nsIStructuredCloneContainer;
class nsIVariant;
namespace mozilla {
@@ -126,7 +125,7 @@ public:
IMPL_EVENT_HANDLER(close)
NS_DECL_ISUPPORTS_INHERITED
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(Notification, DOMEventTargetHelper)
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS_INHERITED(Notification, DOMEventTargetHelper)
static bool PrefEnabled(JSContext* aCx, JSObject* aObj);
// Returns if Notification.get() is allowed for the current global.
@@ -205,8 +204,6 @@ public:
return mIsStored;
}
nsIStructuredCloneContainer* GetDataCloneContainer();
static bool RequestPermissionEnabledForScope(JSContext* aCx, JSObject* /* unused */);
static void RequestPermission(const GlobalObject& aGlobal,
@@ -359,11 +356,11 @@ protected:
const nsString mLang;
const nsString mTag;
const nsString mIconUrl;
nsCOMPtr<nsIStructuredCloneContainer> mDataObjectContainer;
nsString mDataAsBase64;
const NotificationBehavior mBehavior;
// It's null until GetData is first called
nsCOMPtr<nsIVariant> mData;
JS::Heap<JS::Value> mData;
nsString mAlertName;
nsString mScope;
+5 -1
View File
@@ -20,7 +20,9 @@ if (self.Notification) {
lang: "",
body: "This is a notification body",
tag: "sometag",
icon: "icon.png"
icon: "icon.png",
data: ["a complex object that should be", { "structured": "cloned" }],
mozbehavior: { vibrationPattern: [30, 200, 30] },
};
var notification = new Notification("This is a title", options);
@@ -36,6 +38,8 @@ if (self.Notification) {
is(notification.body, options.body, "body should get set");
is(notification.tag, options.tag, "tag should get set");
is(notification.icon, options.icon, "icon should get set");
is(notification.data[0], "a complex object that should be", "data item 0 should be a matching string");
is(notification.data[1]["structured"], "cloned", "data item 1 should be a matching object literal");
// store notification in test context
this.notification = notification;
@@ -13,11 +13,11 @@
}
navigator.serviceWorker.ready.then(function(swr) {
swr.showNotification("Hi there. The ServiceWorker should receive a click event for this.");
swr.showNotification("Hi there. The ServiceWorker should receive a click event for this.", { data: { complex: ["jsval", 5] }});
});
navigator.serviceWorker.onmessage = function(msg) {
testWindow.callback();
testWindow.callback(msg.data.result);
};
</script>
@@ -9,7 +9,11 @@ onnotificationclick = function(e) {
}
clients.forEach(function(client) {
client.postMessage("done");
client.postMessage({ result: e.notification.data &&
e.notification.data['complex'] &&
e.notification.data['complex'][0] == "jsval" &&
e.notification.data['complex'][1] == 5 });
});
});
}
@@ -23,11 +23,11 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=916893
function testFrame(src) {
var iframe = document.createElement("iframe");
iframe.src = src;
window.callback = function() {
window.callback = function(result) {
window.callback = null;
document.body.removeChild(iframe);
iframe = null;
ok(true, "Got notificationclick event.");
ok(result, "Got notificationclick event with correct data.");
MockServices.unregister();
SimpleTest.finish();
};
+67 -15
View File
@@ -5,9 +5,73 @@
/*global intl_DateTimeFormat: false, */
// This cache, once primed, has these properties:
//
// runtimeDefaultLocale:
// Locale information provided by the embedding, guiding SpiderMonkey's
// selection of a default locale. See RuntimeDefaultLocale(), whose
// value controls the value returned by DefaultLocale() that's what's
// *actually* used.
// localTZA:
// The local time zone's adjustment from UTC. See LocalTZA().
// formatters:
// A Record storing formatters consistent with the above
// runtimeDefaultLocale/localTZA values, for use with the appropriate
// ES6 toLocale*String Date method when called with its first two
// arguments having the value |undefined|.
//
// The "formatters" Record has (some subset of) these properties, as determined
// by all values of the first argument passed to |GetCachedFormat|:
//
// dateTimeFormat: for Date's toLocaleString operation
// dateFormat: for Date's toLocaleDateString operation
// timeFormat: for Date's toLocaleTimeString operation
//
// Using this cache, then, requires 1) verifying the current
// runtimeDefaultLocale/localTZA are consistent with cached values, then
// 2) seeing if the desired formatter is cached and returning it if so, or else
// 3) create the desired formatter and store and return it.
var dateTimeFormatCache = new Record();
/**
* Get a cached DateTimeFormat formatter object, created like so:
*
* var opts = ToDateTimeOptions(undefined, required, defaults);
* return new Intl.DateTimeFormat(undefined, opts);
*
* |format| must be a key from the "formatters" Record described above.
*/
function GetCachedFormat(format, required, defaults) {
assert(format === "dateTimeFormat" ||
format === "dateFormat" ||
format === "timeFormat",
"unexpected format key: please update the comment by " +
"dateTimeFormatCache");
var runtimeDefaultLocale = RuntimeDefaultLocale();
var localTZA = LocalTZA();
var formatters;
if (dateTimeFormatCache.runtimeDefaultLocale !== runtimeDefaultLocale ||
dateTimeFormatCache.localTZA !== localTZA)
{
formatters = dateTimeFormatCache.formatters = new Record();
dateTimeFormatCache.runtimeDefaultLocale = runtimeDefaultLocale;
dateTimeFormatCache.localTZA = localTZA;
} else {
formatters = dateTimeFormatCache.formatters;
}
var fmt = formatters[format];
if (fmt === undefined) {
var options = ToDateTimeOptions(undefined, required, defaults);
fmt = formatters[format] = intl_DateTimeFormat(undefined, options);
}
return fmt;
}
/**
* Format this Date object into a date and time string, using the locale and
* formatting options provided.
@@ -30,11 +94,7 @@ function Date_toLocaleString() {
if (locales === undefined && options === undefined) {
// This cache only optimizes for the old ES5 toLocaleString without
// locales and options.
if (dateTimeFormatCache.dateTimeFormat === undefined) {
options = ToDateTimeOptions(options, "any", "all");
dateTimeFormatCache.dateTimeFormat = intl_DateTimeFormat(locales, options);
}
dateTimeFormat = dateTimeFormatCache.dateTimeFormat;
dateTimeFormat = GetCachedFormat("dateTimeFormat", "any", "all");
} else {
options = ToDateTimeOptions(options, "any", "all");
dateTimeFormat = intl_DateTimeFormat(locales, options);
@@ -67,11 +127,7 @@ function Date_toLocaleDateString() {
if (locales === undefined && options === undefined) {
// This cache only optimizes for the old ES5 toLocaleDateString without
// locales and options.
if (dateTimeFormatCache.dateFormat === undefined) {
options = ToDateTimeOptions(options, "date", "date");
dateTimeFormatCache.dateFormat = intl_DateTimeFormat(locales, options);
}
dateTimeFormat = dateTimeFormatCache.dateFormat;
dateTimeFormat = GetCachedFormat("dateFormat", "date", "date");
} else {
options = ToDateTimeOptions(options, "date", "date");
dateTimeFormat = intl_DateTimeFormat(locales, options);
@@ -104,11 +160,7 @@ function Date_toLocaleTimeString() {
if (locales === undefined && options === undefined) {
// This cache only optimizes for the old ES5 toLocaleTimeString without
// locales and options.
if (dateTimeFormatCache.timeFormat === undefined) {
options = ToDateTimeOptions(options, "time", "time");
dateTimeFormatCache.timeFormat = intl_DateTimeFormat(locales, options);
}
dateTimeFormat = dateTimeFormatCache.timeFormat;
dateTimeFormat = GetCachedFormat("timeFormat", "time", "time");
} else {
options = ToDateTimeOptions(options, "time", "time");
dateTimeFormat = intl_DateTimeFormat(locales, options);
+1 -1
View File
@@ -62,7 +62,7 @@ SymbolObject::initClass(JSContext* cx, HandleObject obj)
return nullptr;
RootedFunction ctor(cx, global->createConstructor(cx, construct,
ClassName(JSProto_Symbol, cx), 1));
ClassName(JSProto_Symbol, cx), 0));
if (!ctor)
return nullptr;
+1
View File
@@ -18,6 +18,7 @@ UNIFIED_SOURCES += [
'testClassGetter.cpp',
'testCloneScript.cpp',
'testContexts.cpp',
'testDateToLocaleString.cpp',
'testDebugger.cpp',
'testDeepFreeze.cpp',
'testDefineGetterSetterNonEnumerable.cpp',
@@ -0,0 +1,54 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
* vim: set ts=8 sts=4 et sw=4 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 "jsapi-tests/tests.h"
BEGIN_TEST(testDateToLocaleString)
{
// This test should only attempt to run if we have Intl support: necessary
// to properly assume that changes to the default locale will predictably
// affect the behavior of the locale-sensitive Date methods tested here.
JS::Rooted<JS::Value> haveIntl(cx);
EVAL("typeof Intl !== 'undefined'", &haveIntl);
if (!haveIntl.toBoolean())
return true;
// Pervasive assumption: our Intl support includes "de" (German) and
// "en" (English) and treats them differently for purposes of
// Date.prototype.toLocale{,Date,Time}String behavior.
// Start with German.
CHECK(JS_SetDefaultLocale(rt, "de"));
// The (constrained) Date object we'll use to test behavior.
EXEC("var d = new Date(Date.UTC(2015, 9 - 1, 17));");
// Test that toLocaleString behavior changes with default locale changes.
EXEC("var deAll = d.toLocaleString();");
CHECK(JS_SetDefaultLocale(rt, "en"));
EXEC("if (d.toLocaleString() === deAll) \n"
" throw 'toLocaleString results should have changed with system locale change';");
// Test that toLocaleDateString behavior changes with default locale changes.
EXEC("var enDate = d.toLocaleDateString();");
CHECK(JS_SetDefaultLocale(rt, "de"));
EXEC("if (d.toLocaleDateString() === enDate) \n"
" throw 'toLocaleDateString results should have changed with system locale change';");
// Test that toLocaleTimeString behavior changes with default locale changes.
EXEC("var deTime = d.toLocaleTimeString();");
CHECK(JS_SetDefaultLocale(rt, "en"));
EXEC("if (d.toLocaleTimeString() === deTime) \n"
" throw 'toLocaleTimeString results should have changed with system locale change';");
JS_ResetDefaultLocale(rt);
return true;
}
END_TEST(testDateToLocaleString)
+13 -13
View File
@@ -556,10 +556,10 @@ XDRRelazificationInfo(XDRState<mode>* xdr, HandleFunction fun, HandleScript scri
}
static inline uint32_t
FindScopeObjectIndex(JSScript *script, NestedScopeObject& scope)
FindScopeObjectIndex(JSScript* script, NestedScopeObject& scope)
{
ObjectArray *objects = script->objects();
HeapPtrObject *vector = objects->vector;
ObjectArray* objects = script->objects();
HeapPtrObject* vector = objects->vector;
unsigned length = objects->length;
for (unsigned i = 0; i < length; ++i) {
if (vector[i] == &scope)
@@ -965,11 +965,11 @@ js::XDRScript(XDRState<mode>* xdr, HandleObject enclosingScopeArg, HandleScript
* after the enclosing block has been XDR'd.
*/
for (i = 0; i != nobjects; ++i) {
HeapPtrObject *objp = &script->objects()->vector[i];
HeapPtrObject* objp = &script->objects()->vector[i];
XDRClassKind classk;
if (mode == XDR_ENCODE) {
JSObject *obj = *objp;
JSObject* obj = *objp;
if (obj->is<BlockObject>())
classk = CK_BlockObject;
else if (obj->is<StaticWithObject>())
@@ -2655,19 +2655,19 @@ JSScript::partiallyInit(ExclusiveContext* cx, HandleScript script, uint32_t ncon
if (nobjects != 0) {
script->objects()->length = nobjects;
script->objects()->vector = (HeapPtrObject *)cursor;
script->objects()->vector = (HeapPtrObject*)cursor;
cursor += nobjects * sizeof(script->objects()->vector[0]);
}
if (nregexps != 0) {
script->regexps()->length = nregexps;
script->regexps()->vector = (HeapPtrObject *)cursor;
script->regexps()->vector = (HeapPtrObject*)cursor;
cursor += nregexps * sizeof(script->regexps()->vector[0]);
}
if (ntrynotes != 0) {
script->trynotes()->length = ntrynotes;
script->trynotes()->vector = reinterpret_cast<JSTryNote *>(cursor);
script->trynotes()->vector = reinterpret_cast<JSTryNote*>(cursor);
size_t vectorSize = ntrynotes * sizeof(script->trynotes()->vector[0]);
#ifdef DEBUG
memset(cursor, 0, vectorSize);
@@ -3250,7 +3250,7 @@ js::detail::CopyScript(JSContext* cx, HandleObject scriptStaticScope, HandleScri
AutoObjectVector objects(cx);
if (nobjects != 0) {
HeapPtrObject *vector = src->objects()->vector;
HeapPtrObject* vector = src->objects()->vector;
for (unsigned i = 0; i < nobjects; i++) {
RootedObject obj(cx, vector[i]);
RootedObject clone(cx);
@@ -3360,13 +3360,13 @@ js::detail::CopyScript(JSContext* cx, HandleObject scriptStaticScope, HandleScri
MOZ_ASSERT_IF(vector[i].isMarkable(), vector[i].toString()->isAtom());
}
if (nobjects != 0) {
HeapPtrObject *vector = Rebase<HeapPtrObject>(dst, src, src->objects()->vector);
HeapPtrObject* vector = Rebase<HeapPtrObject>(dst, src, src->objects()->vector);
dst->objects()->vector = vector;
for (unsigned i = 0; i < nobjects; ++i)
vector[i].init(&objects[i]->as<NativeObject>());
}
if (nregexps != 0) {
HeapPtrObject *vector = Rebase<HeapPtrObject>(dst, src, src->regexps()->vector);
HeapPtrObject* vector = Rebase<HeapPtrObject>(dst, src, src->regexps()->vector);
dst->regexps()->vector = vector;
for (unsigned i = 0; i < nregexps; ++i)
vector[i].init(&regexps[i]->as<NativeObject>());
@@ -4064,8 +4064,8 @@ LazyScript::CreateRaw(ExclusiveContext* cx, HandleFunction fun,
return new (res) LazyScript(fun, table.forget(), packed, begin, end, lineno, column);
}
/* static */ LazyScript *
LazyScript::CreateRaw(ExclusiveContext *cx, HandleFunction fun,
/* static */ LazyScript*
LazyScript::CreateRaw(ExclusiveContext* cx, HandleFunction fun,
uint32_t numFreeVariables, uint32_t numInnerFunctions, JSVersion version,
uint32_t begin, uint32_t end, uint32_t lineno, uint32_t column)
{
+2 -3
View File
@@ -1525,7 +1525,6 @@ RopeMatch(JSContext* cx, JSRope* text, JSLinearString* pat, int* match)
return true;
}
/* ES6 draft rc4 21.1.3.7. */
static bool
str_includes(JSContext* cx, unsigned argc, Value* vp)
@@ -2274,8 +2273,8 @@ DoMatchLocal(JSContext* cx, const CallArgs& args, RegExpStatics* res, HandleLine
/* ES5 15.5.4.10 step 8. */
static bool
DoMatchGlobal(JSContext* cx, const CallArgs& args, RegExpStatics* res,
HandleLinearString input, StringRegExpGuard& g)
DoMatchGlobal(JSContext* cx, const CallArgs& args, RegExpStatics* res, HandleLinearString input,
StringRegExpGuard& g)
{
// Step 8a.
//
+1 -1
View File
@@ -8,7 +8,7 @@ assertEq(desc.configurable, true);
assertEq(desc.enumerable, false);
assertEq(desc.writable, true);
assertEq(typeof Symbol, "function");
assertEq(Symbol.length, 1);
assertEq(Symbol.length, 0);
desc = Object.getOwnPropertyDescriptor(Symbol, "prototype");
assertEq(desc.configurable, false);
+11
View File
@@ -1261,6 +1261,16 @@ intrinsic_RuntimeDefaultLocale(JSContext* cx, unsigned argc, Value* vp)
return true;
}
static bool
intrinsic_LocalTZA(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 0, "the LocalTZA intrinsic takes no arguments");
args.rval().setDouble(cx->runtime()->dateTimeInfo.localTZA());
return true;
}
static bool
intrinsic_IsConstructing(JSContext* cx, unsigned argc, Value* vp)
{
@@ -1382,6 +1392,7 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_FN("_ConstructorForTypedArray", intrinsic_ConstructorForTypedArray, 1,0),
JS_FN("DecompileArg", intrinsic_DecompileArg, 2,0),
JS_FN("RuntimeDefaultLocale", intrinsic_RuntimeDefaultLocale, 0,0),
JS_FN("LocalTZA", intrinsic_LocalTZA, 0,0),
JS_INLINABLE_FN("_IsConstructing", intrinsic_IsConstructing, 0,0,
IntrinsicIsConstructing),
@@ -105,18 +105,20 @@ this.BrowserTestUtils = {
* @resolves The tab switched to.
*/
switchTab(tabbrowser, tab) {
let promise = new Promise(resolve => {
tabbrowser.addEventListener("TabSwitchDone", function onSwitch() {
tabbrowser.removeEventListener("TabSwitchDone", onSwitch);
TestUtils.executeSoon(() => resolve(tabbrowser.selectedTab));
});
});
if (typeof tab == "function") {
tab();
}
else {
tabbrowser.selectedTab = tab;
}
//XXX this is esr38, we do not have e10s, this is never async, we do not pass go
// and do not collect, err, I mean, we continue without waiting for an event:
return new Promise(resolve => {
TestUtils.executeSoon(() => resolve(tabbrowser.selectedTab));
});
return promise;
},
/**
+4 -3
View File
@@ -196,10 +196,11 @@ public:
virtual bool NeedsPaint() override;
virtual TabChild* GetOwningTabChild() override { return mTabChild; }
virtual void ClearBackingScaleCache()
void UpdateBackingScaleCache(float aDpi, double aScale)
{
mDPI = -1;
mDefaultScale = -1;
mDPI = aDpi;
mDefaultScale = aScale;
}
nsIntSize GetScreenDimensions();