This commit is contained in:
Ryan VanderMeulen 2015-08-18 10:33:13 -04:00
Родитель 98569ceeff 4b7506a72d
Коммит 93215ef261
255 изменённых файлов: 10255 добавлений и 4863 удалений

Просмотреть файл

@ -19,7 +19,7 @@ DocAccessibleParent::RecvShowEvent(const ShowEventData& aData)
if (mShutdown)
return true;
CheckDocTree();
MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
if (aData.NewTree().IsEmpty()) {
NS_ERROR("no children being added");
@ -50,7 +50,7 @@ DocAccessibleParent::RecvShowEvent(const ShowEventData& aData)
}
#endif
CheckDocTree();
MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
return true;
}
@ -104,7 +104,7 @@ DocAccessibleParent::RecvHideEvent(const uint64_t& aRootID)
if (mShutdown)
return true;
CheckDocTree();
MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
ProxyEntry* rootEntry = mAccessibles.GetEntry(aRootID);
if (!rootEntry) {
@ -122,7 +122,7 @@ DocAccessibleParent::RecvHideEvent(const uint64_t& aRootID)
parent->RemoveChild(root);
root->Shutdown();
CheckDocTree();
MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
return true;
}
@ -196,12 +196,12 @@ DocAccessibleParent::RecvBindChildDoc(PDocAccessibleParent* aChildDoc, const uin
if (!aID)
return false;
CheckDocTree();
MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
auto childDoc = static_cast<DocAccessibleParent*>(aChildDoc);
bool result = AddChildDoc(childDoc, aID, false);
MOZ_ASSERT(result);
CheckDocTree();
MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
return result;
}
@ -265,16 +265,20 @@ DocAccessibleParent::Destroy()
GetAccService()->RemoteDocShutdown(this);
}
void
bool
DocAccessibleParent::CheckDocTree() const
{
size_t childDocs = mChildDocs.Length();
for (size_t i = 0; i < childDocs; i++) {
if (!mChildDocs[i] || mChildDocs[i]->mParentDoc != this)
MOZ_CRASH("document tree is broken!");
return false;
mChildDocs[i]->CheckDocTree();
if (!mChildDocs[i]->CheckDocTree()) {
return false;
}
}
return true;
}
} // a11y

Просмотреть файл

@ -72,7 +72,7 @@ public:
void Destroy();
virtual void ActorDestroy(ActorDestroyReason aWhy) override
{
CheckDocTree();
MOZ_DIAGNOSTIC_ASSERT(CheckDocTree());
if (!mShutdown)
Destroy();
}
@ -151,7 +151,7 @@ private:
uint32_t AddSubtree(ProxyAccessible* aParent,
const nsTArray<AccessibleData>& aNewTree, uint32_t aIdx,
uint32_t aIdxInParent);
void CheckDocTree() const;
MOZ_WARN_UNUSED_RESULT bool CheckDocTree() const;
nsTArray<DocAccessibleParent*> mChildDocs;
DocAccessibleParent* mParentDoc;

Просмотреть файл

@ -70,6 +70,12 @@ function* test_mute_tab(tab, icon, expectMuted) {
return mutedPromise;
}
function get_tab_attributes(tab) {
const ss = Cc["@mozilla.org/browser/sessionstore;1"].getService(Ci.nsISessionStore);
let {attributes} = JSON.parse(ss.getTabState(tab));
return attributes;
}
function* test_playing_icon_on_tab(tab, browser, isPinned) {
let icon = document.getAnonymousElementByAttribute(tab, "anonid",
isPinned ? "overlay-icon" : "soundplaying-icon");
@ -83,12 +89,18 @@ function* test_playing_icon_on_tab(tab, browser, isPinned) {
yield test_tooltip(icon, "Mute tab");
ok(!("muted" in get_tab_attributes(tab)), "No muted attribute should be persisted");
yield test_mute_tab(tab, icon, true);
ok("muted" in get_tab_attributes(tab), "Muted attribute should be persisted");
yield test_tooltip(icon, "Unmute tab");
yield test_mute_tab(tab, icon, false);
ok(!("muted" in get_tab_attributes(tab)), "No muted attribute should be persisted");
yield test_tooltip(icon, "Mute tab");
yield test_mute_tab(tab, icon, true);

Просмотреть файл

@ -24,7 +24,7 @@ this.TabAttributes = Object.freeze({
});
let TabAttributesInternal = {
_attrs: new Set(),
_attrs: new Set(["muted"]),
// We never want to directly read or write those attributes.
// 'image' should not be accessed directly but handled by using the

Просмотреть файл

@ -455,6 +455,7 @@ frame/log.h
frame/req.h
freetype/freetype.h
freetype/ftcache.h
freetype/ftfntfmt.h
freetype/ftglyph.h
freetype/ftsynth.h
freetype/ftoutln.h

Просмотреть файл

@ -2317,6 +2317,7 @@ ia64*-hpux*)
dnl Probably also a compiler bug, but what can you do?
PROFILE_USE_LDFLAGS="-LTCG:PGUPDATE"
LDFLAGS="$LDFLAGS -DYNAMICBASE"
RCFLAGS="-nologo"
if test "$_CC_MAJOR_VERSION" = "18" -a "$_CC_BUILD_VERSION" = "31101"; then
dnl Use MaxILKSize as a workaround for LNK1248 in VS2013update4
dnl See https://connect.microsoft.com/VisualStudio/feedback/details/1044914/fatal-error-lnk1248
@ -9133,6 +9134,11 @@ if test -z "$MOZ_NATIVE_JEMALLOC" -a "$MOZ_MEMORY" && test -n "$MOZ_JEMALLOC3" -
if test -n "$MOZ_REPLACE_MALLOC"; then
# When using replace_malloc, we always want valloc exported from jemalloc.
ac_configure_args="$ac_configure_args ac_cv_func_valloc=yes"
if test "${OS_ARCH}" = Darwin; then
# We also need to enable pointer validation on Mac because jemalloc's
# zone allocator is not used.
ac_configure_args="$ac_configure_args --enable-ivsalloc"
fi
fi
if test -n "$MOZ_JEMALLOC3"; then
case "${OS_ARCH}" in
@ -9142,6 +9148,11 @@ if test -z "$MOZ_NATIVE_JEMALLOC" -a "$MOZ_MEMORY" && test -n "$MOZ_JEMALLOC3" -
ac_configure_args="$ac_configure_args --without-export"
;;
esac
if test "${OS_ARCH}" = WINNT; then
# Lazy lock initialization doesn't play well with lazy linking of
# mozglue.dll on Windows XP (leads to startup crash), so disable it.
ac_configure_args="$ac_configure_args --disable-lazy-lock"
fi
elif test "${OS_ARCH}" = Darwin; then
# When building as a replace-malloc lib, disabling the zone allocator
# forces to use pthread_atfork.
@ -9178,20 +9189,27 @@ if test -z "$MOZ_NATIVE_JEMALLOC" -a "$MOZ_MEMORY" && test -n "$MOZ_JEMALLOC3" -
for var in AS CC CXX CPP LD AR RANLIB STRIP CPPFLAGS EXTRA_CFLAGS LDFLAGS; do
ac_configure_args="$ac_configure_args $var='`eval echo \\${${var}}`'"
done
if test "$CROSS_COMPILE"; then
ac_configure_args="$ac_configure_args je_cv_static_page_shift=12"
fi
# Force disable DSS support in jemalloc.
ac_configure_args="$ac_configure_args ac_cv_func_sbrk=false"
# Make Linux builds munmap freed chunks instead of recycling them.
ac_configure_args="$ac_configure_args --enable-munmap"
# Disable cache oblivious behavior that appears to have a performance
# impact on Firefox.
ac_configure_args="$ac_configure_args --disable-cache-oblivious"
if ! test -e memory/jemalloc; then
mkdir -p memory/jemalloc
fi
# jemalloc's configure runs git to determine the version. But when building
# from a gecko git clone, the git commands it uses is going to pick gecko's
# information, not jemalloc's, which is useless. So pretend we don't have git
# at all. That will make jemalloc's configure pick the in-tree VERSION file.
(PATH="$srcdir/memory/jemalloc/helper:$PATH";
AC_OUTPUT_SUBDIRS(memory/jemalloc/src)
) || exit 1
ac_configure_args="$_SUBDIR_CONFIG_ARGS"
fi

Просмотреть файл

@ -665,7 +665,7 @@ nsDefaultURIFixup::ConvertFileToStringURI(const nsACString& aIn,
#if defined(XP_WIN)
// Check for \ in the url-string or just a drive (PC)
if (kNotFound != aIn.FindChar('\\') ||
if (aIn.Contains('\\') ||
(aIn.Length() == 2 && (aIn.Last() == ':' || aIn.Last() == '|'))) {
attemptFixup = true;
}

Просмотреть файл

@ -374,6 +374,16 @@ Animation::Tick()
}
UpdateTiming(SeekFlag::NoSeek, SyncNotifyFlag::Async);
// FIXME: Detect the no-change case and don't request a restyle at all
// FIXME: Detect changes to IsPlaying() state and request RestyleType::Layer
// so that layers get updated immediately
AnimationCollection* collection = GetCollection();
if (collection) {
collection->RequestRestyle(CanThrottle() ?
AnimationCollection::RestyleType::Throttled :
AnimationCollection::RestyleType::Standard);
}
}
void
@ -945,7 +955,7 @@ Animation::PostUpdate()
{
AnimationCollection* collection = GetCollection();
if (collection) {
collection->NotifyAnimationUpdated();
collection->RequestRestyle(AnimationCollection::RestyleType::Layer);
}
}

Просмотреть файл

@ -1262,7 +1262,7 @@ BlobSet::AppendString(const nsAString& aString, bool nativeEOL, JSContext* aCx)
nsCString utf8Str = NS_ConvertUTF16toUTF8(aString);
if (nativeEOL) {
if (utf8Str.FindChar('\r') != kNotFound) {
if (utf8Str.Contains('\r')) {
utf8Str.ReplaceSubstring("\r\n", "\n");
utf8Str.ReplaceSubstring("\r", "\n");
}

Просмотреть файл

@ -15,6 +15,7 @@ class nsISupports;
namespace mozilla {
namespace dom {
class PerformanceResourceTiming;
// http://www.w3.org/TR/performance-timeline/#performanceentry
class PerformanceEntry : public nsISupports,
@ -78,6 +79,11 @@ public:
return 0;
}
virtual const PerformanceResourceTiming* ToResourceTiming() const
{
return nullptr;
}
protected:
nsCOMPtr<nsISupports> mParent;
nsString mName;

Просмотреть файл

@ -0,0 +1,154 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "PerformanceObserver.h"
#include "mozilla/dom/PerformanceBinding.h"
#include "mozilla/dom/PerformanceEntryBinding.h"
#include "mozilla/dom/PerformanceObserverBinding.h"
#include "mozilla/dom/workers/bindings/Performance.h"
#include "nsPerformance.h"
#include "nsPIDOMWindow.h"
#include "nsQueryObject.h"
#include "nsString.h"
#include "PerformanceEntry.h"
#include "PerformanceObserverEntryList.h"
#include "WorkerPrivate.h"
#include "WorkerScope.h"
using namespace mozilla;
using namespace mozilla::dom;
using namespace mozilla::dom::workers;
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PerformanceObserver,
mOwner,
mPerformance,
mCallback)
NS_IMPL_CYCLE_COLLECTING_ADDREF(PerformanceObserver)
NS_IMPL_CYCLE_COLLECTING_RELEASE(PerformanceObserver)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PerformanceObserver)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
PerformanceObserver::PerformanceObserver(nsPIDOMWindow* aOwner,
PerformanceObserverCallback& aCb)
: mOwner(aOwner)
, mCallback(&aCb)
{
MOZ_ASSERT(mOwner);
mPerformance = aOwner->GetPerformance();
}
PerformanceObserver::PerformanceObserver(WorkerPrivate* aWorkerPrivate,
PerformanceObserverCallback& aCb)
: mCallback(&aCb)
{
MOZ_ASSERT(aWorkerPrivate);
mPerformance = aWorkerPrivate->GlobalScope()->GetPerformance();
}
PerformanceObserver::~PerformanceObserver()
{
}
// static
already_AddRefed<PerformanceObserver>
PerformanceObserver::Constructor(const GlobalObject& aGlobal,
PerformanceObserverCallback& aCb,
ErrorResult& aRv)
{
if (NS_IsMainThread()) {
nsCOMPtr<nsPIDOMWindow> ownerWindow =
do_QueryInterface(aGlobal.GetAsSupports());
if (!ownerWindow) {
aRv.Throw(NS_ERROR_FAILURE);
return nullptr;
}
MOZ_ASSERT(ownerWindow->IsInnerWindow());
nsRefPtr<PerformanceObserver> observer =
new PerformanceObserver(ownerWindow, aCb);
return observer.forget();
}
JSContext* cx = aGlobal.Context();
WorkerPrivate* workerPrivate = GetWorkerPrivateFromContext(cx);
MOZ_ASSERT(workerPrivate);
nsRefPtr<PerformanceObserver> observer =
new PerformanceObserver(workerPrivate, aCb);
return observer.forget();
}
JSObject*
PerformanceObserver::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return PerformanceObserverBinding::Wrap(aCx, this, aGivenProto);
}
void
PerformanceObserver::Notify(PerformanceEntry* aEntry)
{
MOZ_ASSERT(aEntry);
nsAutoString entryType;
aEntry->GetEntryType(entryType);
if (!mEntryTypes.Contains<nsString>(entryType)) {
return;
}
nsRefPtr<PerformanceObserverEntryList> list = new PerformanceObserverEntryList(this);
list->AppendEntry(aEntry);
ErrorResult rv;
mCallback->Call(this, *list, *this, rv);
NS_WARN_IF(rv.Failed());
}
static nsString sValidTypeNames[7] = {
NS_LITERAL_STRING("composite"),
NS_LITERAL_STRING("mark"),
NS_LITERAL_STRING("measure"),
NS_LITERAL_STRING("navigation"),
NS_LITERAL_STRING("render"),
NS_LITERAL_STRING("resource"),
NS_LITERAL_STRING("server")
};
void
PerformanceObserver::Observe(const PerformanceObserverInit& aOptions,
ErrorResult& aRv)
{
if (aOptions.mEntryTypes.IsEmpty()) {
aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
return;
}
nsTArray<nsString> validEntryTypes;
for (const nsString& validTypeName : sValidTypeNames) {
if (aOptions.mEntryTypes.Contains<nsString>(validTypeName) &&
!validEntryTypes.Contains<nsString>(validTypeName)) {
validEntryTypes.AppendElement(validTypeName);
}
}
if (validEntryTypes.IsEmpty()) {
aRv.Throw(NS_ERROR_DOM_TYPE_ERR);
return;
}
mEntryTypes = validEntryTypes;
mPerformance->AddObserver(this);
}
void
PerformanceObserver::Disconnect()
{
mPerformance->RemoveObserver(this);
}

Просмотреть файл

@ -0,0 +1,76 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_PerformanceObserver_h__
#define mozilla_dom_PerformanceObserver_h__
#include "nsCOMPtr.h"
#include "nsISupports.h"
#include "mozilla/nsRefPtr.h"
#include "nsString.h"
#include "nsTArray.h"
#include "nsWrapperCache.h"
class nsPIDOMWindow;
class PerformanceBase;
namespace mozilla {
class ErrorResult;
namespace dom {
class GlobalObject;
class PerformanceEntry;
class PerformanceObserverCallback;
struct PerformanceObserverInit;
namespace workers {
class WorkerPrivate;
} // namespace workers
class PerformanceObserver final : public nsISupports,
public nsWrapperCache
{
public:
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(PerformanceObserver)
static already_AddRefed<PerformanceObserver>
Constructor(const GlobalObject& aGlobal,
PerformanceObserverCallback& aCb,
ErrorResult& aRv);
PerformanceObserver(nsPIDOMWindow* aOwner,
PerformanceObserverCallback& aCb);
PerformanceObserver(workers::WorkerPrivate* aWorkerPrivate,
PerformanceObserverCallback& aCb);
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
nsISupports* GetParentObject() const { return mOwner; }
void Observe(const PerformanceObserverInit& aOptions,
mozilla::ErrorResult& aRv);
void Disconnect();
void Notify(PerformanceEntry* entry);
private:
~PerformanceObserver();
nsCOMPtr<nsISupports> mOwner;
nsRefPtr<PerformanceObserverCallback> mCallback;
nsRefPtr<PerformanceBase> mPerformance;
nsTArray<nsString> mEntryTypes;
};
} // namespace dom
} // namespace mozilla
#endif

Просмотреть файл

@ -0,0 +1,103 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "PerformanceObserverEntryList.h"
#include "mozilla/dom/PerformanceObserverEntryListBinding.h"
#include "nsPerformance.h"
#include "nsString.h"
#include "PerformanceResourceTiming.h"
using namespace mozilla;
using namespace mozilla::dom;
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(PerformanceObserverEntryList,
mOwner,
mEntries)
NS_IMPL_CYCLE_COLLECTING_ADDREF(PerformanceObserverEntryList)
NS_IMPL_CYCLE_COLLECTING_RELEASE(PerformanceObserverEntryList)
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(PerformanceObserverEntryList)
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
NS_INTERFACE_MAP_ENTRY(nsISupports)
NS_INTERFACE_MAP_END
PerformanceObserverEntryList::~PerformanceObserverEntryList()
{
}
JSObject*
PerformanceObserverEntryList::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
{
return PerformanceObserverEntryListBinding::Wrap(aCx, this, aGivenProto);
}
void
PerformanceObserverEntryList::GetEntries(
const PerformanceEntryFilterOptions& aFilter,
nsTArray<nsRefPtr<PerformanceEntry>>& aRetval)
{
aRetval.Clear();
for (const nsRefPtr<PerformanceEntry>& entry : mEntries) {
if (aFilter.mInitiatorType.WasPassed()) {
const PerformanceResourceTiming* resourceEntry =
entry->ToResourceTiming();
if (!resourceEntry) {
continue;
}
nsAutoString initiatorType;
resourceEntry->GetInitiatorType(initiatorType);
if (!initiatorType.Equals(aFilter.mInitiatorType.Value())) {
continue;
}
}
if (aFilter.mName.WasPassed() &&
!entry->GetName().Equals(aFilter.mName.Value())) {
continue;
}
if (aFilter.mEntryType.WasPassed() &&
!entry->GetEntryType().Equals(aFilter.mEntryType.Value())) {
continue;
}
aRetval.AppendElement(entry);
}
}
void
PerformanceObserverEntryList::GetEntriesByType(
const nsAString& aEntryType,
nsTArray<nsRefPtr<PerformanceEntry>>& aRetval)
{
aRetval.Clear();
for (const nsRefPtr<PerformanceEntry>& entry : mEntries) {
if (entry->GetEntryType().Equals(aEntryType)) {
aRetval.AppendElement(entry);
}
}
}
void
PerformanceObserverEntryList::GetEntriesByName(
const nsAString& aName,
const Optional<nsAString>& aEntryType,
nsTArray<nsRefPtr<PerformanceEntry>>& aRetval)
{
aRetval.Clear();
for (const nsRefPtr<PerformanceEntry>& entry : mEntries) {
if (entry->GetName().Equals(aName)) {
aRetval.AppendElement(entry);
}
}
}
void
PerformanceObserverEntryList::AppendEntry(PerformanceEntry* aEntry)
{
mEntries.AppendElement(aEntry);
}

Просмотреть файл

@ -0,0 +1,64 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef mozilla_dom_PerformanceObserverEntryList_h__
#define mozilla_dom_PerformanceObserverEntryList_h__
#include "nsCOMPtr.h"
#include "nsISupports.h"
#include "nsTArray.h"
#include "nsWrapperCache.h"
#include "mozilla/dom/PerformanceEntryBinding.h"
namespace mozilla {
namespace dom {
struct PerformanceEntryFilterOptions;
class PerformanceEntry;
template<typename T> class Optional;
class PerformanceObserverEntryList final : public nsISupports,
public nsWrapperCache
{
~PerformanceObserverEntryList();
public:
explicit PerformanceObserverEntryList(nsISupports* aOwner)
: mOwner(aOwner)
{
}
nsISupports* GetParentObject() const
{
return mOwner;
}
virtual JSObject* WrapObject(JSContext* aCx,
JS::Handle<JSObject*> aGivenProto) override;
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(PerformanceObserverEntryList)
void GetEntries(const PerformanceEntryFilterOptions& aFilter,
nsTArray<nsRefPtr<PerformanceEntry>>& aRetval);
void GetEntriesByType(const nsAString& aEntryType,
nsTArray<nsRefPtr<PerformanceEntry>>& aRetval);
void GetEntriesByName(const nsAString& aName,
const Optional<nsAString>& aEntryType,
nsTArray<nsRefPtr<PerformanceEntry>>& aRetval);
void AppendEntry(PerformanceEntry* aEntry);
private:
nsCOMPtr<nsISupports> mOwner;
nsTArray<nsRefPtr<PerformanceEntry>> mEntries;
};
} // namespace dom
} // namespace mozilla
#endif

Просмотреть файл

@ -123,6 +123,11 @@ public:
return 0;
}
virtual const PerformanceResourceTiming* ToResourceTiming() const override
{
return this;
}
protected:
virtual ~PerformanceResourceTiming();

Просмотреть файл

@ -189,6 +189,8 @@ EXPORTS.mozilla.dom += [
'PerformanceEntry.h',
'PerformanceMark.h',
'PerformanceMeasure.h',
'PerformanceObserver.h',
'PerformanceObserverEntryList.h',
'PerformanceResourceTiming.h',
'ProcessGlobal.h',
'ResponsiveImageSelector.h',
@ -328,6 +330,8 @@ UNIFIED_SOURCES += [
'PerformanceEntry.cpp',
'PerformanceMark.cpp',
'PerformanceMeasure.cpp',
'PerformanceObserver.cpp',
'PerformanceObserverEntryList.cpp',
'PerformanceResourceTiming.cpp',
'PostMessageEvent.cpp',
'ProcessGlobal.cpp',

Просмотреть файл

@ -29,6 +29,11 @@
#include "nsIDocument.h"
#include <algorithm>
#ifdef LoadImage
// Undefine LoadImage to prevent naming conflict with Windows.
#undef LoadImage
#endif
using namespace mozilla;
#define MISC_STR_PTR(_cont) \

Просмотреть файл

@ -1729,7 +1729,7 @@ nsContentUtils::GetOfflineAppManifest(nsIDocument *aDocument, nsIURI **aURI)
// Manifest URIs can't have fragment identifiers.
if (manifestSpec.IsEmpty() ||
manifestSpec.FindChar('#') != kNotFound) {
manifestSpec.Contains('#')) {
return;
}

Просмотреть файл

@ -13,8 +13,8 @@ class nsICSSLoaderObserver;
class nsIURI;
#define NS_ISTYLESHEETLINKINGELEMENT_IID \
{ 0xe5855604, 0x8a9a, 0x4181, \
{ 0xbe, 0x41, 0xdd, 0xf7, 0x08, 0x70, 0x3f, 0xbe } }
{ 0xa8b79f3b, 0x9d18, 0x4f9c, \
{ 0xb1, 0xaa, 0x8c, 0x9b, 0x1b, 0xaa, 0xac, 0xad } }
namespace mozilla {
class CSSStyleSheet;
@ -97,6 +97,14 @@ public:
// some types of linking elements, but it's a better place than
// anywhere else.
virtual void SetLineNumber(uint32_t aLineNumber) = 0;
/**
* Get the line number, as previously set by SetLineNumber.
*
* @return the line number of this element; or 1 if no line number
* was set
*/
virtual uint32_t GetLineNumber() = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(nsIStyleSheetLinkingElement,

Просмотреть файл

@ -18,12 +18,14 @@
#include "PerformanceEntry.h"
#include "PerformanceMark.h"
#include "PerformanceMeasure.h"
#include "PerformanceObserver.h"
#include "PerformanceResourceTiming.h"
#include "mozilla/ErrorResult.h"
#include "mozilla/dom/PerformanceBinding.h"
#include "mozilla/dom/PerformanceEntryEvent.h"
#include "mozilla/dom/PerformanceTimingBinding.h"
#include "mozilla/dom/PerformanceNavigationBinding.h"
#include "mozilla/dom/PerformanceObserverBinding.h"
#include "mozilla/Preferences.h"
#include "mozilla/IntegerPrintfMacros.h"
#include "mozilla/TimeStamp.h"
@ -692,15 +694,17 @@ public:
class PrefEnabledRunnable final : public WorkerMainThreadRunnable
{
public:
explicit PrefEnabledRunnable(WorkerPrivate* aWorkerPrivate)
PrefEnabledRunnable(WorkerPrivate* aWorkerPrivate,
const nsCString& aPrefName)
: WorkerMainThreadRunnable(aWorkerPrivate)
, mEnabled(false)
, mPrefName(aPrefName)
{ }
bool MainThreadRun() override
{
MOZ_ASSERT(NS_IsMainThread());
mEnabled = Preferences::GetBool("dom.enable_user_timing", false);
mEnabled = Preferences::GetBool(mPrefName.get(), false);
return true;
}
@ -711,6 +715,7 @@ public:
private:
bool mEnabled;
nsCString mPrefName;
};
} // namespace
@ -727,7 +732,27 @@ nsPerformance::IsEnabled(JSContext* aCx, JSObject* aGlobal)
workerPrivate->AssertIsOnWorkerThread();
nsRefPtr<PrefEnabledRunnable> runnable =
new PrefEnabledRunnable(workerPrivate);
new PrefEnabledRunnable(workerPrivate,
NS_LITERAL_CSTRING("dom.enable_user_timing"));
runnable->Dispatch(workerPrivate->GetJSContext());
return runnable->IsEnabled();
}
/* static */ bool
nsPerformance::IsObserverEnabled(JSContext* aCx, JSObject* aGlobal)
{
if (NS_IsMainThread()) {
return Preferences::GetBool("dom.enable_performance_observer", false);
}
WorkerPrivate* workerPrivate = GetCurrentThreadWorkerPrivate();
MOZ_ASSERT(workerPrivate);
workerPrivate->AssertIsOnWorkerThread();
nsRefPtr<PrefEnabledRunnable> runnable =
new PrefEnabledRunnable(workerPrivate,
NS_LITERAL_CSTRING("dom.enable_performance_observer"));
runnable->Dispatch(workerPrivate->GetJSContext());
return runnable->IsEnabled();
@ -1024,6 +1049,10 @@ PerformanceBase::InsertUserEntry(PerformanceEntry* aEntry)
{
mUserEntries.InsertElementSorted(aEntry,
PerformanceEntryComparator());
NS_OBSERVER_ARRAY_NOTIFY_XPCOM_OBSERVERS(mObservers,
PerformanceObserver,
Notify, (aEntry));
}
void
@ -1047,4 +1076,19 @@ PerformanceBase::InsertResourceEntry(PerformanceEntry* aEntry)
// call onresourcetimingbufferfull
DispatchBufferFullEvent();
}
NS_OBSERVER_ARRAY_NOTIFY_XPCOM_OBSERVERS(mObservers,
PerformanceObserver,
Notify, (aEntry));
}
void
PerformanceBase::AddObserver(PerformanceObserver* aObserver)
{
mObservers.AppendElementUnlessExists(aObserver);
}
void
PerformanceBase::RemoveObserver(PerformanceObserver* aObserver)
{
mObservers.RemoveElement(aObserver);
}

Просмотреть файл

@ -26,6 +26,7 @@ namespace mozilla {
class ErrorResult;
namespace dom {
class PerformanceEntry;
class PerformanceObserver;
} // namespace dom
} // namespace mozilla
@ -300,6 +301,7 @@ public:
explicit PerformanceBase(nsPIDOMWindow* aWindow);
typedef mozilla::dom::PerformanceEntry PerformanceEntry;
typedef mozilla::dom::PerformanceObserver PerformanceObserver;
void GetEntries(nsTArray<nsRefPtr<PerformanceEntry>>& aRetval);
void GetEntriesByType(const nsAString& aEntryType,
@ -321,6 +323,9 @@ public:
void SetResourceTimingBufferSize(uint64_t aMaxSize);
void AddObserver(PerformanceObserver* aObserver);
void RemoveObserver(PerformanceObserver* aObserver);
protected:
virtual ~PerformanceBase();
@ -353,6 +358,8 @@ protected:
void LogEntry(PerformanceEntry* aEntry, const nsACString& aOwner) const;
void TimingNotification(PerformanceEntry* aEntry, const nsACString& aOwner, uint64_t epoch);
nsTObserverArray<PerformanceObserver*> mObservers;
private:
nsTArray<nsRefPtr<PerformanceEntry>> mUserEntries;
nsTArray<nsRefPtr<PerformanceEntry>> mResourceEntries;
@ -376,6 +383,8 @@ public:
static bool IsEnabled(JSContext* aCx, JSObject* aGlobal);
static bool IsObserverEnabled(JSContext* aCx, JSObject* aGlobal);
nsDOMNavigationTiming* GetDOMTiming() const
{
return mDOMTiming;

Просмотреть файл

@ -119,6 +119,12 @@ nsStyleLinkElement::SetLineNumber(uint32_t aLineNumber)
mLineNumber = aLineNumber;
}
/* virtual */ uint32_t
nsStyleLinkElement::GetLineNumber()
{
return mLineNumber;
}
/* static */ bool
nsStyleLinkElement::IsImportEnabled()
{

Просмотреть файл

@ -52,6 +52,7 @@ public:
virtual void OverrideBaseURI(nsIURI* aNewBaseURI) override;
virtual void SetLineNumber(uint32_t aLineNumber) override;
virtual uint32_t GetLineNumber() override;
enum RelValue {
ePREFETCH = 0x00000001,

Просмотреть файл

@ -247,6 +247,8 @@ support-files =
referrer_testserver.sjs
script_postmessages_fileList.js
iframe_postMessages.html
test_performance_observer.js
performance_observer.html
[test_anonymousContent_api.html]
[test_anonymousContent_append_after_reflow.html]
@ -805,6 +807,7 @@ skip-if = buildapp == 'mulet' || buildapp == 'b2g' || toolkit == 'android'
skip-if = buildapp == 'b2g' || toolkit == 'android' || e10s
[test_window_define_nonconfigurable.html]
[test_root_iframe.html]
[test_performance_observer.html]
[test_performance_user_timing.html]
[test_bug1126851.html]
skip-if = buildapp == 'mulet' || buildapp == 'b2g'

Просмотреть файл

@ -0,0 +1,79 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
<meta charset=utf-8>
<html>
<head>
<title>Test for performance observer</title>
<script>
'use strict';
[
"async_test", "test", "setup",
"assert_true", "assert_equals", "assert_array_equals",
"assert_throws"
].forEach(func => {
window[func] = opener[func].bind(opener);
});
function done() {
opener.add_completion_callback(() => {
self.close();
});
opener.done();
}
</script>
<script src="test_performance_observer.js"></script>
</head>
<body>
<div id="log"></div>
<script>
function promiseXHR(aUrl) {
return new Promise(resolve => {
var xmlhttp = new XMLHttpRequest();
xmlhttp.onload = resolve;
xmlhttp.open("get", aUrl, true);
xmlhttp.send();
});
}
async_test(t => {
performance.clearResourceTimings();
var observedEntryList;
var observedEntries = [];
var observer = new PerformanceObserver(list => {
list.getEntries().forEach(entry => observedEntries.push(entry));
observedEntryList = list;
});
observer.observe({entryTypes: ['resource']});
assert_equals(observedEntries.length, 0);
promiseXHR("test-data.json").then(t.step_func_done(() => {
assert_equals(observedEntries.length, 1);
assert_array_equals(observedEntries,
performance.getEntriesByType("resource"),
"Observed 'resource' entries should equal to entries obtained by getEntriesByType.");
// getEntries filtering tests
assert_array_equals(observedEntryList.getEntries({name: "http://mochi.test:8888/tests/dom/base/test/test-data.json"}),
performance.getEntriesByName("http://mochi.test:8888/tests/dom/base/test/test-data.json"),
"getEntries with name filter should return correct results.");
assert_array_equals(observedEntryList.getEntries({entryType: "resource"}),
performance.getEntriesByType("resource"),
"getEntries with entryType filter should return correct results.");
assert_array_equals(observedEntryList.getEntries({initiatorType: "xmlhttprequest"}),
performance.getEntriesByType("resource"),
"getEntries with initiatorType filter should return correct results.");
assert_array_equals(observedEntryList.getEntries({initiatorType: "link"}),
[],
"getEntries with non-existent initiatorType filter should return an empty array.");
}));
}, "resource-timing test");
done();
</script>
</body>

Просмотреть файл

@ -0,0 +1,17 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
<meta charset=utf-8>
<title>Test for performance observer</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id=log></div>
<script>
'use strict';
SpecialPowers.pushPrefEnv({"set": [["dom.enable_performance_observer", true]]},
function() {
window.open("performance_observer.html");
});
</script>

Просмотреть файл

@ -0,0 +1,240 @@
setup({ explicit_done: true });
test(t => {
assert_throws({name: "TypeError"}, function() {
new PerformanceObserver();
}, "PerformanceObserver constructor should throw TypeError if no argument is specified.");
assert_throws({name: "TypeError"}, function() {
new PerformanceObserver({});
}, "PerformanceObserver constructor should throw TypeError if the argument is not a function.");
}, "Test that PerformanceObserver constructor throws exception");
test(t => {
var observer = new PerformanceObserver(() => {
});
assert_throws({name: "TypeError"}, function() {
observer.observe();
}, "observe() should throw TypeError exception if no option specified.");
assert_throws({name: "TypeError"}, function() {
observer.observe({ unsupportedAttribute: "unsupported" });
}, "obsrve() should throw TypeError exception if the option has no 'entryTypes' attribute.");
assert_throws({name: "TypeError"}, function() {
observer.observe({ entryTypes: [] });
}, "obsrve() should throw TypeError exception if 'entryTypes' attribute is an empty sequence.");
assert_throws({name: "TypeError"}, function() {
observer.observe({ entryTypes: null });
}, "obsrve() should throw TypeError exception if 'entryTypes' attribute is null.");
assert_throws({name: "TypeError"}, function() {
observer.observe({ entryTypes: ["invalid"]});
}, "obsrve() should throw TypeError exception if 'entryTypes' attribute value is invalid.");
}, "Test that PerformanceObserver.observe throws exception");
test(t => {
performance.clearMarks();
performance.clearMeasures();
var observedEntries = [];
var observer = new PerformanceObserver(list => {
list.getEntries().forEach(entry => observedEntries.push(entry));
});
observer.observe({entryTypes: ['mark', 'measure']});
assert_equals(observedEntries.length, 0,
"User timing entries should never be observed.");
assert_equals(performance.getEntriesByType("mark").length, 0,
"There should be no 'mark' entries.");
assert_equals(performance.getEntriesByType("measure").length, 0,
"There should be no 'measure' entries.");
performance.mark("test-start");
performance.mark("test-end");
performance.measure("test-measure", "test-start", "test-end");
assert_equals(observedEntries.length, 3,
"There should be three observed entries.");
var markEntries = observedEntries.filter(entry => {
return entry.entryType == "mark";
});
assert_array_equals(markEntries, performance.getEntriesByType("mark"),
"Observed 'mark' entries should equal to entries obtained by getEntriesByType.");
var measureEntries = observedEntries.filter(entry => {
return entry.entryType == "measure";
});
assert_array_equals(measureEntries, performance.getEntriesByType("measure"),
"Observed 'measure' entries should equal to entries obtained by getEntriesByType.");
}, "Test for user-timing with PerformanceObserver");
test(t => {
performance.clearMarks();
performance.clearMeasures();
var observedEntries = [];
var observer = new PerformanceObserver(list => {
list.getEntries().forEach(entry => observedEntries.push(entry));
});
observer.observe({entryTypes: ['mark', 'measure']});
observer.disconnect();
assert_equals(observedEntries.length, 0,
"User timing entries should be never observed.");
performance.mark("test-start");
performance.mark("test-end");
performance.measure("test-measure", "test-start", "test-end");
assert_equals(performance.getEntriesByType("mark").length, 2);
assert_equals(performance.getEntriesByType("measure").length, 1);
assert_equals(observedEntries.length, 0,
"User timing entries should be never observed after disconnecting observer.");
}, "Nothing should be notified after disconnecting observer");
test(t => {
performance.clearMarks();
performance.clearMeasures();
var observedEntryList;
var observer = new PerformanceObserver(list => {
observedEntryList = list;
});
observer.observe({entryTypes: ['mark']});
performance.mark("test");
assert_array_equals(observedEntryList.getEntries({"entryType": "mark"}),
performance.getEntriesByType("mark"),
"getEntries with entryType filter should return correct results.");
assert_array_equals(observedEntryList.getEntries({"name": "test"}),
performance.getEntriesByName("test"),
"getEntries with name filter should return correct results.");
assert_array_equals(observedEntryList.getEntries({"name": "test",
"entryType": "mark"}),
performance.getEntriesByName("test"),
"getEntries with name and entryType filter should return correct results.");
assert_array_equals(observedEntryList.getEntries({"name": "invalid"}),
[],
"getEntries with non-existent name filter should return an empty array.");
assert_array_equals(observedEntryList.getEntries({"name": "test",
"entryType": "measure"}),
[],
"getEntries with name filter and non-existent entryType should return an empty array.");
assert_array_equals(observedEntryList.getEntries({"name": "invalid",
"entryType": "mark"}),
[],
"getEntries with non-existent name and entryType filter should return an empty array.");
assert_array_equals(observedEntryList.getEntries({initiatorType: "xmlhttprequest"}),
[],
"getEntries with initiatorType filter should return an empty array.");
}, "Test for PerformanceObserverEntryList.getEntries");
test(t => {
performance.clearMarks();
performance.clearMeasures();
var observedEntryList;
var observer = new PerformanceObserver(list => {
observedEntryList = list;
});
observer.observe({entryTypes: ['mark', 'measure']});
performance.mark("test");
assert_array_equals(observedEntryList.getEntriesByType("mark"),
performance.getEntriesByType("mark"));
performance.measure("test-measure", "test", "test");
assert_array_equals(observedEntryList.getEntriesByType("measure"),
performance.getEntriesByType("measure"));
}, "Test for PerformanceObserverEntryList.getEntriesByType");
test(t => {
performance.clearMarks();
performance.clearMeasures();
var observedEntryList;
var observer = new PerformanceObserver(list => {
observedEntryList = list;
});
observer.observe({entryTypes: ['mark', 'measure']});
performance.mark("test");
assert_array_equals(observedEntryList.getEntriesByName("test"),
performance.getEntriesByName("test"));
performance.measure("test-measure", "test", "test");
assert_array_equals(observedEntryList.getEntriesByName("test-measure"),
performance.getEntriesByName("test-measure"));
}, "Test for PerformanceObserverEntryList.getEntriesByName");
test(t => {
performance.clearMarks();
performance.clearMeasures();
var observedEntries = [];
var observer = new PerformanceObserver(list => {
list.getEntries().forEach(entry => observedEntries.push(entry));
});
observer.observe({entryTypes: ['mark', 'measure']});
observer.observe({entryTypes: ['mark', 'measure']});
performance.mark("test-start");
performance.mark("test-end");
performance.measure("test-measure", "test-start", "test-end");
assert_equals(observedEntries.length, 3,
"Observed user timing entries should have only three entries.");
}, "Test that invoking observe method twice affects nothing");
test(t => {
performance.clearMarks();
performance.clearMeasures();
var observedEntries = [];
var observer = new PerformanceObserver(list => {
list.getEntries().forEach(entry => observedEntries.push(entry));
});
observer.observe({entryTypes: ['mark', 'measure']});
observer.observe({entryTypes: ['mark']});
performance.mark("test-start");
performance.mark("test-end");
performance.measure("test-measure", "test-start", "test-end");
assert_equals(observedEntries.length, 2,
"Observed user timing entries should have only two entries.");
}, "Test that observing filter is replaced by a new filter");
test(t => {
performance.clearMarks();
performance.clearMeasures();
var observedEntries = [];
var observer = new PerformanceObserver(list => {
list.getEntries().forEach(entry => observedEntries.push(entry));
});
observer.observe({entryTypes: ['mark']});
observer.observe({entryTypes: ['measure']});
performance.mark("test-start");
performance.mark("test-end");
performance.measure("test-measure", "test-start", "test-end");
assert_equals(observedEntries.length, 1,
"Observed user timing entries should have only 1 entries.");
}, "Test that observing filter is replaced by a new filter");

Просмотреть файл

@ -672,6 +672,7 @@ PopulateCapFallbackQueue(const SurfaceCaps& baseCaps,
static bool
CreateOffscreen(GLContext* gl, const WebGLContextOptions& options,
const nsCOMPtr<nsIGfxInfo>& gfxInfo, WebGLContext* webgl,
layers::LayersBackend layersBackend,
layers::ISurfaceAllocator* surfAllocator)
{
SurfaceCaps baseCaps;
@ -689,7 +690,7 @@ CreateOffscreen(GLContext* gl, const WebGLContextOptions& options,
if (gl->IsANGLE() ||
(gl->GetContextType() == GLContextType::GLX &&
gfxPlatform::GetPlatform()->GetCompositorBackend() == LayersBackend::LAYERS_OPENGL))
layersBackend == LayersBackend::LAYERS_OPENGL))
{
// We can't use no-alpha formats on ANGLE yet because of:
// https://code.google.com/p/angleproject/issues/detail?id=764
@ -763,7 +764,8 @@ WebGLContext::CreateOffscreenGL(bool forceEnabled)
if (!gl)
break;
if (!CreateOffscreen(gl, mOptions, gfxInfo, this, surfAllocator))
if (!CreateOffscreen(gl, mOptions, gfxInfo, this,
GetCompositorBackendType(), surfAllocator))
break;
if (!InitAndValidateGL())
@ -1292,6 +1294,17 @@ WebGLContext::GetCanvasLayer(nsDisplayListBuilder* builder,
return canvasLayer.forget();
}
layers::LayersBackend
WebGLContext::GetCompositorBackendType() const
{
nsIWidget* docWidget = nsContentUtils::WidgetForDocument(mCanvasElement->OwnerDoc());
if (docWidget) {
layers::LayerManager* layerManager = docWidget->GetLayerManager();
return layerManager->GetCompositorBackendType();
}
return LayersBackend::LAYERS_NONE;
}
void
WebGLContext::GetContextAttributes(dom::Nullable<dom::WebGLContextAttributes>& retval)
{

Просмотреть файл

@ -363,6 +363,8 @@ public:
return IsContextLost() ? 0 : mHeight;
}
layers::LayersBackend GetCompositorBackendType() const;
void
GetContextAttributes(dom::Nullable<dom::WebGLContextAttributes>& retval);

Просмотреть файл

@ -675,10 +675,10 @@ HangMonitoredProcess::GetHangType(uint32_t* aHangType)
*aHangType = PLUGIN_HANG;
break;
default:
MOZ_ASSERT(false);
MOZ_ASSERT_UNREACHABLE("Unexpected HangData type");
return NS_ERROR_UNEXPECTED;
break;
}
return NS_OK;
}

Просмотреть файл

@ -197,8 +197,7 @@ DecodedStreamData::SetPlaying(bool aPlaying)
class OutputStreamListener : public MediaStreamListener {
typedef MediaStreamListener::MediaStreamGraphEvent MediaStreamGraphEvent;
public:
OutputStreamListener(DecodedStream* aDecodedStream, MediaStream* aStream)
: mDecodedStream(aDecodedStream), mStream(aStream) {}
explicit OutputStreamListener(OutputStreamData* aOwner) : mOwner(aOwner) {}
void NotifyEvent(MediaStreamGraph* aGraph, MediaStreamGraphEvent event) override
{
@ -212,37 +211,142 @@ public:
void Forget()
{
MOZ_ASSERT(NS_IsMainThread());
mDecodedStream = nullptr;
mOwner = nullptr;
}
private:
void DoNotifyFinished()
{
MOZ_ASSERT(NS_IsMainThread());
if (mDecodedStream) {
if (mOwner) {
// Remove the finished stream so it won't block the decoded stream.
mDecodedStream->Remove(mStream);
mOwner->Remove();
}
}
// Main thread only
DecodedStream* mDecodedStream;
nsRefPtr<MediaStream> mStream;
OutputStreamData* mOwner;
};
OutputStreamData::~OutputStreamData()
{
MOZ_ASSERT(NS_IsMainThread());
mListener->Forget();
// Break the connection to the input stream if necessary.
if (mPort) {
mPort->Destroy();
}
}
void
OutputStreamData::Init(DecodedStream* aDecodedStream, ProcessedMediaStream* aStream)
OutputStreamData::Init(OutputStreamManager* aOwner, ProcessedMediaStream* aStream)
{
mOwner = aOwner;
mStream = aStream;
mListener = new OutputStreamListener(aDecodedStream, aStream);
mListener = new OutputStreamListener(this);
aStream->AddListener(mListener);
}
void
OutputStreamData::Connect(MediaStream* aStream)
{
MOZ_ASSERT(NS_IsMainThread());
MOZ_ASSERT(!mPort, "Already connected?");
MOZ_ASSERT(!mStream->IsDestroyed(), "Can't connect a destroyed stream.");
// The output stream must stay in sync with the input stream, so if
// either stream is blocked, we block the other.
mPort = mStream->AllocateInputPort(aStream,
MediaInputPort::FLAG_BLOCK_INPUT | MediaInputPort::FLAG_BLOCK_OUTPUT);
// Unblock the output stream now. The input stream is responsible for
// controlling blocking from now on.
mStream->ChangeExplicitBlockerCount(-1);
}
bool
OutputStreamData::Disconnect()
{
MOZ_ASSERT(NS_IsMainThread());
// During cycle collection, DOMMediaStream can be destroyed and send
// its Destroy message before this decoder is destroyed. So we have to
// be careful not to send any messages after the Destroy().
if (mStream->IsDestroyed()) {
return false;
}
// Disconnect the existing port if necessary.
if (mPort) {
mPort->Destroy();
mPort = nullptr;
}
// Block the stream again. It will be unlocked when connecting
// to the input stream.
mStream->ChangeExplicitBlockerCount(1);
return true;
}
void
OutputStreamData::Remove()
{
MOZ_ASSERT(NS_IsMainThread());
mOwner->Remove(mStream);
}
void
OutputStreamManager::Add(ProcessedMediaStream* aStream, bool aFinishWhenEnded)
{
MOZ_ASSERT(NS_IsMainThread());
// Ensure that aStream finishes the moment mDecodedStream does.
if (aFinishWhenEnded) {
aStream->SetAutofinish(true);
}
OutputStreamData* p = mStreams.AppendElement();
p->Init(this, aStream);
// Connect to the input stream if we have one. Otherwise the output stream
// will be connected in Connect().
if (mInputStream) {
p->Connect(mInputStream);
}
}
void
OutputStreamManager::Remove(MediaStream* aStream)
{
MOZ_ASSERT(NS_IsMainThread());
for (int32_t i = mStreams.Length() - 1; i >= 0; --i) {
if (mStreams[i].Equals(aStream)) {
mStreams.RemoveElementAt(i);
break;
}
}
}
void
OutputStreamManager::Connect(MediaStream* aStream)
{
MOZ_ASSERT(NS_IsMainThread());
mInputStream = aStream;
for (auto&& os : mStreams) {
os.Connect(aStream);
}
}
void
OutputStreamManager::Disconnect()
{
MOZ_ASSERT(NS_IsMainThread());
mInputStream = nullptr;
for (int32_t i = mStreams.Length() - 1; i >= 0; --i) {
if (!mStreams[i].Disconnect()) {
// Probably the DOMMediaStream was GCed. Clean up.
mStreams.RemoveElementAt(i);
}
}
}
DecodedStream::DecodedStream(MediaQueue<MediaData>& aAudioQueue,
MediaQueue<MediaData>& aVideoQueue)
: mMonitor("DecodedStream::mMonitor")
@ -289,27 +393,7 @@ DecodedStream::DestroyData()
return;
}
// All streams are having their SourceMediaStream disconnected, so they
// need to be explicitly blocked again.
auto& outputStreams = OutputStreams();
for (int32_t i = outputStreams.Length() - 1; i >= 0; --i) {
OutputStreamData& os = outputStreams[i];
// Explicitly remove all existing ports.
// This is not strictly necessary but it's good form.
MOZ_ASSERT(os.mPort, "Double-delete of the ports!");
os.mPort->Destroy();
os.mPort = nullptr;
// During cycle collection, nsDOMMediaStream can be destroyed and send
// its Destroy message before this decoder is destroyed. So we have to
// be careful not to send any messages after the Destroy().
if (os.mStream->IsDestroyed()) {
// Probably the DOM MediaStream was GCed. Clean up.
outputStreams.RemoveElementAt(i);
} else {
os.mStream->ChangeExplicitBlockerCount(1);
}
}
mOutputStreamManager.Disconnect();
mData = nullptr;
}
@ -328,7 +412,7 @@ DecodedStream::RecreateData(MediaStreamGraph* aGraph)
{
MOZ_ASSERT(NS_IsMainThread());
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
MOZ_ASSERT((aGraph && !mData && OutputStreams().IsEmpty()) || // first time
MOZ_ASSERT((aGraph && !mData && !HasConsumers()) || // first time
(!aGraph && mData)); // 2nd time and later
if (!aGraph) {
@ -338,31 +422,16 @@ DecodedStream::RecreateData(MediaStreamGraph* aGraph)
DestroyData();
mData.reset(new DecodedStreamData(source, mPlaying));
// Note that the delay between removing ports in DestroyDecodedStream
// Note that the delay between removing ports in DestroyData
// and adding new ones won't cause a glitch since all graph operations
// between main-thread stable states take effect atomically.
auto& outputStreams = OutputStreams();
for (int32_t i = outputStreams.Length() - 1; i >= 0; --i) {
OutputStreamData& os = outputStreams[i];
MOZ_ASSERT(!os.mStream->IsDestroyed(), "Should've been removed in DestroyData()");
Connect(&os);
}
}
nsTArray<OutputStreamData>&
DecodedStream::OutputStreams()
{
MOZ_ASSERT(NS_IsMainThread());
GetReentrantMonitor().AssertCurrentThreadIn();
return mOutputStreams;
mOutputStreamManager.Connect(mData->mStream);
}
bool
DecodedStream::HasConsumers() const
{
MOZ_ASSERT(NS_IsMainThread());
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
return mOutputStreams.IsEmpty();
return !mOutputStreamManager.IsEmpty();
}
ReentrantMonitor&
@ -371,22 +440,6 @@ DecodedStream::GetReentrantMonitor() const
return mMonitor;
}
void
DecodedStream::Connect(OutputStreamData* aStream)
{
MOZ_ASSERT(NS_IsMainThread());
GetReentrantMonitor().AssertCurrentThreadIn();
NS_ASSERTION(!aStream->mPort, "Already connected?");
// The output stream must stay in sync with the decoded stream, so if
// either stream is blocked, we block the other.
aStream->mPort = aStream->mStream->AllocateInputPort(mData->mStream,
MediaInputPort::FLAG_BLOCK_INPUT | MediaInputPort::FLAG_BLOCK_OUTPUT);
// Unblock the output stream now. While it's connected to DecodedStream,
// DecodedStream is responsible for controlling blocking.
aStream->mStream->ChangeExplicitBlockerCount(-1);
}
void
DecodedStream::Connect(ProcessedMediaStream* aStream, bool aFinishWhenEnded)
{
@ -397,34 +450,13 @@ DecodedStream::Connect(ProcessedMediaStream* aStream, bool aFinishWhenEnded)
RecreateData(aStream->Graph());
}
OutputStreamData* os = OutputStreams().AppendElement();
os->Init(this, aStream);
Connect(os);
if (aFinishWhenEnded) {
// Ensure that aStream finishes the moment mDecodedStream does.
aStream->SetAutofinish(true);
}
mOutputStreamManager.Add(aStream, aFinishWhenEnded);
}
void
DecodedStream::Remove(MediaStream* aStream)
{
MOZ_ASSERT(NS_IsMainThread());
ReentrantMonitorAutoEnter mon(GetReentrantMonitor());
auto& streams = OutputStreams();
for (int32_t i = streams.Length() - 1; i >= 0; --i) {
auto& os = streams[i];
MediaStream* p = os.mStream.get();
if (p == aStream) {
if (os.mPort) {
os.mPort->Destroy();
os.mPort = nullptr;
}
streams.RemoveElementAt(i);
break;
}
}
mOutputStreamManager.Remove(aStream);
}
void

Просмотреть файл

@ -27,6 +27,7 @@ class MediaInputPort;
class MediaStream;
class MediaStreamGraph;
class OutputStreamListener;
class OutputStreamManager;
class ProcessedMediaStream;
class ReentrantMonitor;
@ -39,13 +40,55 @@ class Image;
class OutputStreamData {
public:
~OutputStreamData();
void Init(DecodedStream* aDecodedStream, ProcessedMediaStream* aStream);
void Init(OutputStreamManager* aOwner, ProcessedMediaStream* aStream);
// Connect mStream to the input stream.
void Connect(MediaStream* aStream);
// Disconnect mStream from its input stream.
// Return false is mStream is already destroyed, otherwise true.
bool Disconnect();
// Called by OutputStreamListener to remove self from the output streams
// managed by OutputStreamManager.
void Remove();
// Return true if aStream points to the same object as mStream.
// Used by OutputStreamManager to remove an output stream.
bool Equals(MediaStream* aStream)
{
return mStream == aStream;
}
private:
OutputStreamManager* mOwner;
nsRefPtr<ProcessedMediaStream> mStream;
// mPort connects DecodedStreamData::mStream to our mStream.
// mPort connects our mStream to an input stream.
nsRefPtr<MediaInputPort> mPort;
nsRefPtr<OutputStreamListener> mListener;
};
class OutputStreamManager {
public:
// Add the output stream to the collection.
void Add(ProcessedMediaStream* aStream, bool aFinishWhenEnded);
// Remove the output stream from the collection.
void Remove(MediaStream* aStream);
// Return true if the collection empty.
bool IsEmpty() const
{
MOZ_ASSERT(NS_IsMainThread());
return mStreams.IsEmpty();
}
// Connect all output streams in the collection to the input stream.
void Connect(MediaStream* aStream);
// Disconnect all output streams from the input stream.
void Disconnect();
private:
// Keep the input stream so we can connect the output streams that
// are added after Connect().
nsRefPtr<MediaStream> mInputStream;
nsTArray<OutputStreamData> mStreams;
};
class DecodedStream {
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DecodedStream);
public:
@ -84,8 +127,6 @@ protected:
private:
ReentrantMonitor& GetReentrantMonitor() const;
void RecreateData(MediaStreamGraph* aGraph);
void Connect(OutputStreamData* aStream);
nsTArray<OutputStreamData>& OutputStreams();
void InitTracks();
void AdvanceTracks();
void SendAudio(double aVolume, bool aIsSameOrigin);
@ -93,7 +134,7 @@ private:
UniquePtr<DecodedStreamData> mData;
// Data about MediaStreams that are being fed by the decoder.
nsTArray<OutputStreamData> mOutputStreams;
OutputStreamManager mOutputStreamManager;
// TODO: This is a temp solution to get rid of decoder monitor on the main
// thread in MDSM::AddOutputStream and MDSM::RecreateDecodedStream as

Просмотреть файл

@ -619,9 +619,9 @@ void MediaDecoder::CallSeek(const SeekTarget& aTarget)
{
MOZ_ASSERT(NS_IsMainThread());
mSeekRequest.DisconnectIfExists();
mSeekRequest.Begin(ProxyMediaCall(mDecoderStateMachine->OwnerThread(),
mDecoderStateMachine.get(), __func__,
&MediaDecoderStateMachine::Seek, aTarget)
mSeekRequest.Begin(InvokeAsync(mDecoderStateMachine->OwnerThread(),
mDecoderStateMachine.get(), __func__,
&MediaDecoderStateMachine::Seek, aTarget)
->Then(AbstractThread::MainThread(), __func__, this,
&MediaDecoder::OnSeekResolved, &MediaDecoder::OnSeekRejected));
}

Просмотреть файл

@ -719,8 +719,8 @@ MediaDecoderStateMachine::OnNotDecoded(MediaData::Type aType,
MOZ_ASSERT(mReader->IsWaitForDataSupported(),
"Readers that send WAITING_FOR_DATA need to implement WaitForData");
nsRefPtr<MediaDecoderStateMachine> self = this;
WaitRequestRef(aType).Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
&MediaDecoderReader::WaitForData, aType)
WaitRequestRef(aType).Begin(InvokeAsync(DecodeTaskQueue(), mReader.get(), __func__,
&MediaDecoderReader::WaitForData, aType)
->Then(OwnerThread(), __func__,
[self] (MediaData::Type aType) -> void {
ReentrantMonitorAutoEnter mon(self->mDecoder->GetReentrantMonitor());
@ -1277,7 +1277,7 @@ void MediaDecoderStateMachine::Shutdown()
// Put a task in the decode queue to shutdown the reader.
// the queue to spin down.
ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__, &MediaDecoderReader::Shutdown)
InvokeAsync(DecodeTaskQueue(), mReader.get(), __func__, &MediaDecoderReader::Shutdown)
->Then(OwnerThread(), __func__, this,
&MediaDecoderStateMachine::FinishShutdown,
&MediaDecoderStateMachine::FinishShutdown);
@ -1578,9 +1578,9 @@ MediaDecoderStateMachine::InitiateSeek()
// Do the seek.
nsRefPtr<MediaDecoderStateMachine> self = this;
mSeekRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
&MediaDecoderReader::Seek, mCurrentSeek.mTarget.mTime,
Duration().ToMicroseconds())
mSeekRequest.Begin(InvokeAsync(DecodeTaskQueue(), mReader.get(), __func__,
&MediaDecoderReader::Seek, mCurrentSeek.mTarget.mTime,
Duration().ToMicroseconds())
->Then(OwnerThread(), __func__,
[self] (int64_t) -> void {
ReentrantMonitorAutoEnter mon(self->mDecoder->GetReentrantMonitor());
@ -1648,15 +1648,15 @@ MediaDecoderStateMachine::RequestAudioData()
AudioQueue().GetSize(), mReader->SizeOfAudioQueueInFrames());
if (mSentFirstFrameLoadedEvent) {
mAudioDataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(),
__func__, &MediaDecoderReader::RequestAudioData)
mAudioDataRequest.Begin(InvokeAsync(DecodeTaskQueue(), mReader.get(),
__func__, &MediaDecoderReader::RequestAudioData)
->Then(OwnerThread(), __func__, this,
&MediaDecoderStateMachine::OnAudioDecoded,
&MediaDecoderStateMachine::OnAudioNotDecoded));
} else {
mAudioDataRequest.Begin(
ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
&MediaDecoderReader::RequestAudioData)
InvokeAsync(DecodeTaskQueue(), mReader.get(), __func__,
&MediaDecoderReader::RequestAudioData)
->Then(OwnerThread(), __func__, mStartTimeRendezvous.get(),
&StartTimeRendezvous::ProcessFirstSample<AudioDataPromise>,
&StartTimeRendezvous::FirstSampleRejected<AudioData>)
@ -1732,17 +1732,17 @@ MediaDecoderStateMachine::RequestVideoData()
if (mSentFirstFrameLoadedEvent) {
mVideoDataRequest.Begin(
ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
&MediaDecoderReader::RequestVideoData,
skipToNextKeyFrame, currentTime, forceDecodeAhead)
InvokeAsync(DecodeTaskQueue(), mReader.get(), __func__,
&MediaDecoderReader::RequestVideoData,
skipToNextKeyFrame, currentTime, forceDecodeAhead)
->Then(OwnerThread(), __func__, this,
&MediaDecoderStateMachine::OnVideoDecoded,
&MediaDecoderStateMachine::OnVideoNotDecoded));
} else {
mVideoDataRequest.Begin(
ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
&MediaDecoderReader::RequestVideoData,
skipToNextKeyFrame, currentTime, forceDecodeAhead)
InvokeAsync(DecodeTaskQueue(), mReader.get(), __func__,
&MediaDecoderReader::RequestVideoData,
skipToNextKeyFrame, currentTime, forceDecodeAhead)
->Then(OwnerThread(), __func__, mStartTimeRendezvous.get(),
&StartTimeRendezvous::ProcessFirstSample<VideoDataPromise>,
&StartTimeRendezvous::FirstSampleRejected<VideoData>)
@ -2278,8 +2278,8 @@ nsresult MediaDecoderStateMachine::RunStateMachine()
DECODER_LOG("Dispatching AsyncReadMetadata");
// Set mode to METADATA since we are about to read metadata.
mResource->SetReadMode(MediaCacheStream::MODE_METADATA);
mMetadataRequest.Begin(ProxyMediaCall(DecodeTaskQueue(), mReader.get(), __func__,
&MediaDecoderReader::AsyncReadMetadata)
mMetadataRequest.Begin(InvokeAsync(DecodeTaskQueue(), mReader.get(), __func__,
&MediaDecoderReader::AsyncReadMetadata)
->Then(OwnerThread(), __func__, this,
&MediaDecoderStateMachine::OnMetadataRead,
&MediaDecoderStateMachine::OnMetadataNotRead));

Просмотреть файл

@ -280,7 +280,12 @@ MediaFormatReader::AsyncReadMetadata()
return p;
}
MOZ_ASSERT(!mDecodersInitRequest.Exists());
EnsureDecodersInitialized();
if (EnsureDecodersInitialized()) {
nsRefPtr<MetadataHolder> metadata = new MetadataHolder();
metadata->mInfo = mInfo;
metadata->mTags = nullptr;
mMetadataPromise.Resolve(metadata, __func__);
}
return p;
}

Просмотреть файл

@ -14,6 +14,7 @@
#include "mozilla/CDMProxy.h"
#endif
#include "mozilla/Logging.h"
#include "nsMimeTypes.h"
#ifdef XP_WIN
#include "mozilla/WindowsVersion.h"
@ -141,6 +142,12 @@ MP4Decoder::CanHandleMediaType(const nsACString& aType,
aOutContainsMP3));
}
#ifdef MOZ_GONK_MEDIACODEC
if (aType.EqualsASCII(VIDEO_3GPP)) {
return Preferences::GetBool("media.fragmented-mp4.gonk.enabled", false);
}
#endif
if (!aType.EqualsASCII("video/mp4") ||
!MP4Decoder::CanCreateH264Decoder()) {
return false;

Просмотреть файл

@ -873,6 +873,9 @@ GStreamerReader::Seek(int64_t aTarget, int64_t aEndTime)
media::TimeIntervals GStreamerReader::GetBuffered()
{
MOZ_ASSERT(OnTaskQueue());
if (!HaveStartTime()) {
return media::TimeIntervals();
}
media::TimeIntervals buffered;
if (!mInfo.HasValidMedia()) {
return buffered;
@ -885,9 +888,10 @@ media::TimeIntervals GStreamerReader::GetBuffered()
nsTArray<MediaByteRange> ranges;
resource->GetCachedRanges(ranges);
if (resource->IsDataCachedToEndOfResource(0) && mDuration.Ref().isSome()) {
if (resource->IsDataCachedToEndOfResource(0)) {
/* fast path for local or completely cached files */
gint64 duration = mDuration.Ref().ref().ToMicroseconds();
gint64 duration =
mDuration.Ref().refOr(media::TimeUnit::FromMicroseconds(0)).ToMicroseconds();
LOG(LogLevel::Debug, "complete range [0, %f] for [0, %li]",
(double) duration / GST_MSECOND, GetDataLength());
buffered +=

Просмотреть файл

@ -6,7 +6,7 @@
#include "gtest/gtest.h"
#include "MP4Demuxer.h"
#include "MP4Stream.h"
#include "MozPromise.h"
#include "mozilla/MozPromise.h"
#include "MediaDataDemuxer.h"
#include "mozilla/SharedThreadPool.h"
#include "mozilla/TaskQueue.h"

Просмотреть файл

@ -35,8 +35,8 @@ MediaSourceDemuxer::MediaSourceDemuxer()
nsRefPtr<MediaSourceDemuxer::InitPromise>
MediaSourceDemuxer::Init()
{
return ProxyMediaCall(GetTaskQueue(), this, __func__,
&MediaSourceDemuxer::AttemptInit);
return InvokeAsync(GetTaskQueue(), this, __func__,
&MediaSourceDemuxer::AttemptInit);
}
nsRefPtr<MediaSourceDemuxer::InitPromise>
@ -272,16 +272,16 @@ nsRefPtr<MediaSourceTrackDemuxer::SeekPromise>
MediaSourceTrackDemuxer::Seek(media::TimeUnit aTime)
{
MOZ_ASSERT(mParent, "Called after BreackCycle()");
return ProxyMediaCall(mParent->GetTaskQueue(), this, __func__,
&MediaSourceTrackDemuxer::DoSeek, aTime);
return InvokeAsync(mParent->GetTaskQueue(), this, __func__,
&MediaSourceTrackDemuxer::DoSeek, aTime);
}
nsRefPtr<MediaSourceTrackDemuxer::SamplesPromise>
MediaSourceTrackDemuxer::GetSamples(int32_t aNumSamples)
{
MOZ_ASSERT(mParent, "Called after BreackCycle()");
return ProxyMediaCall(mParent->GetTaskQueue(), this, __func__,
&MediaSourceTrackDemuxer::DoGetSamples, aNumSamples);
return InvokeAsync(mParent->GetTaskQueue(), this, __func__,
&MediaSourceTrackDemuxer::DoGetSamples, aNumSamples);
}
void
@ -312,9 +312,9 @@ MediaSourceTrackDemuxer::GetNextRandomAccessPoint(media::TimeUnit* aTime)
nsRefPtr<MediaSourceTrackDemuxer::SkipAccessPointPromise>
MediaSourceTrackDemuxer::SkipToNextRandomAccessPoint(media::TimeUnit aTimeThreshold)
{
return ProxyMediaCall(mParent->GetTaskQueue(), this, __func__,
&MediaSourceTrackDemuxer::DoSkipToNextRandomAccessPoint,
aTimeThreshold);
return InvokeAsync(mParent->GetTaskQueue(), this, __func__,
&MediaSourceTrackDemuxer::DoSkipToNextRandomAccessPoint,
aTimeThreshold);
}
int64_t

Просмотреть файл

@ -268,9 +268,9 @@ TrackBuffer::BufferAppend()
nsRefPtr<TrackBuffer> self = this;
ProxyMediaCall(mParentDecoder->GetReader()->OwnerThread(), this, __func__,
&TrackBuffer::UpdateBufferedRanges,
mLastAppendRange, /* aNotifyParent */ true)
InvokeAsync(mParentDecoder->GetReader()->OwnerThread(), this, __func__,
&TrackBuffer::UpdateBufferedRanges,
mLastAppendRange, /* aNotifyParent */ true)
->Then(mParentDecoder->GetReader()->OwnerThread(), __func__,
[self] {
self->mInitializationPromise.ResolveIfExists(self->HasInitSegment(), __func__);
@ -942,9 +942,9 @@ TrackBuffer::CompleteInitializeDecoder(SourceBufferDecoder* aDecoder)
MSE_DEBUG("Reader %p activated",
aDecoder->GetReader());
nsRefPtr<TrackBuffer> self = this;
ProxyMediaCall(mParentDecoder->GetReader()->OwnerThread(), this, __func__,
&TrackBuffer::UpdateBufferedRanges,
Interval<int64_t>(), /* aNotifyParent */ true)
InvokeAsync(mParentDecoder->GetReader()->OwnerThread(), this, __func__,
&TrackBuffer::UpdateBufferedRanges,
Interval<int64_t>(), /* aNotifyParent */ true)
->Then(mParentDecoder->GetReader()->OwnerThread(), __func__,
[self] {
self->mInitializationPromise.ResolveIfExists(self->HasInitSegment(), __func__);
@ -1274,9 +1274,9 @@ TrackBuffer::RangeRemoval(TimeUnit aStart, TimeUnit aEnd)
// Make sure our buffered ranges got updated before resolving promise.
nsRefPtr<TrackBuffer> self = this;
ProxyMediaCall(mParentDecoder->GetReader()->OwnerThread(), this, __func__,
&TrackBuffer::UpdateBufferedRanges,
Interval<int64_t>(), /* aNotifyParent */ false)
InvokeAsync(mParentDecoder->GetReader()->OwnerThread(), this, __func__,
&TrackBuffer::UpdateBufferedRanges,
Interval<int64_t>(), /* aNotifyParent */ false)
->Then(mParentDecoder->GetReader()->OwnerThread(), __func__,
[self] {
self->mRangeRemovalPromise.ResolveIfExists(true, __func__);

Просмотреть файл

@ -156,8 +156,8 @@ TrackBuffersManager::BufferAppend()
MOZ_ASSERT(NS_IsMainThread());
MSE_DEBUG("");
return ProxyMediaCall(GetTaskQueue(), this,
__func__, &TrackBuffersManager::InitSegmentParserLoop);
return InvokeAsync(GetTaskQueue(), this,
__func__, &TrackBuffersManager::InitSegmentParserLoop);
}
// Abort any pending AppendData.
@ -211,9 +211,9 @@ TrackBuffersManager::RangeRemoval(TimeUnit aStart, TimeUnit aEnd)
mEnded = false;
return ProxyMediaCall(GetTaskQueue(), this, __func__,
&TrackBuffersManager::CodedFrameRemovalWithPromise,
TimeInterval(aStart, aEnd));
return InvokeAsync(GetTaskQueue(), this, __func__,
&TrackBuffersManager::CodedFrameRemovalWithPromise,
TimeInterval(aStart, aEnd));
}
TrackBuffersManager::EvictDataResult

Просмотреть файл

@ -152,7 +152,6 @@ EXPORTS += [
EXPORTS.mozilla += [
'MediaManager.h',
'MozPromise.h',
'StateMirroring.h',
'StateWatching.h',
]

Просмотреть файл

@ -34,8 +34,8 @@ MediaDataDecoderProxy::Init()
{
MOZ_ASSERT(!mIsShutdown);
return ProxyMediaCall(mProxyThreadWrapper, this, __func__,
&MediaDataDecoderProxy::InternalInit);
return InvokeAsync(mProxyThreadWrapper, this, __func__,
&MediaDataDecoderProxy::InternalInit);
}
nsresult

Просмотреть файл

@ -737,6 +737,8 @@ skip-if = toolkit == 'gonk' # bug 1128845
skip-if = (toolkit == 'android' && processor == 'x86') #bug 845162
[test_playback_rate_playpause.html]
skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
[test_playback_reactivate.html]
#skip-if = (toolkit == 'android' && processor == 'x86') #x86 only bug 914439
[test_played.html]
[test_preload_actions.html]
[test_preload_attribute.html]

Просмотреть файл

@ -0,0 +1,98 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test playback with dormant of media files that should play OK</title>
<script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
<script type="text/javascript" src="manifest.js"></script>
</head>
<body>
<pre id="test">
<script class="testbody" type="text/javascript">
/* This testcase wants to test a video element's playback is not break
by dormant.
When the metadata is loaded, we remove the video element to trigger dormant.
Then set a timer to append the video element back and play it.
Test pass if the video plays to the end.
*/
// longer timeout for slow platforms
if (isSlowPlatform()) {
SimpleTest.requestLongerTimeout(1.5);
SimpleTest.requestCompleteLog();
}
var manager = new MediaTestManager;
function startTest(test, token) {
var v = document.createElement('video');
v.preload = "metadata";
v.token = token;
var handler = {
"ontimeout": function() {
Log(token, "timed out: ended=" + v.seenEnded + ", suspend=" + v.seenSuspend);
}
};
manager.started(token, handler);
v.src = test.name;
v.name = test.name;
var check = function(test, v) { return function() {
is(test.name, v.name, test.name + ": Name should match #1");
Log(v.token, "removeChild: " + v.name);
document.body.removeChild(v);
var appendAndPlayElement = function() {
Log(v.token, "appendChild: " + v.name);
document.body.appendChild(v);
Log(v.token, "Element play: " + v.name);
v.play();
}
setTimeout(appendAndPlayElement, 2000);
}}(test, v);
var finish = function() {
v.finished = true;
removeNodeAndSource(v);
manager.finished(v.token);
}
var checkEnded = function(test, v) { return function() {
is(test.name, v.name, test.name + ": Name should match #2");
checkMetadata(test.name, v, test);
is(v.readyState, v.HAVE_CURRENT_DATA, test.name + " checking readyState");
ok(v.readyState != v.NETWORK_LOADED, test.name + " shouldn't report NETWORK_LOADED");
ok(v.ended, test.name + " checking playback has ended");
finish();
}}(test, v);
v.addEventListener("loadedmetadata", check, false);
v.addEventListener("ended", checkEnded, false);
document.body.appendChild(v);
// Debug timeouts on slow platforms.
if (isSlowPlatform()) {
var events = ["suspend", "play", "canplay", "canplaythrough", "loadstart", "loadedmetadata",
"loadeddata", "playing", "ended", "error", "stalled", "emptied", "abort",
"waiting", "pause"];
function logEvent(e) {
var v = e.target;
Log(e.target.token, "got " + e.type);
}
events.forEach(function(e) {
v.addEventListener(e, logEvent, false);
});
}
}
manager.runTests(gSmallTests, startTest);
</script>
</pre>
</body>
</html>

Просмотреть файл

@ -1038,7 +1038,7 @@ NPError
_destroystream(NPP npp, NPStream *pstream, NPError reason)
{
if (!NS_IsMainThread()) {
NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_write called from the wrong thread\n"));
NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_destroystream called from the wrong thread\n"));
return NPERR_INVALID_PARAM;
}
NPN_PLUGIN_LOG(PLUGIN_LOG_NORMAL,
@ -2624,6 +2624,11 @@ NPError
_getvalueforurl(NPP instance, NPNURLVariable variable, const char *url,
char **value, uint32_t *len)
{
if (!NS_IsMainThread()) {
NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getvalueforurl called from the wrong thread\n"));
return NPERR_GENERIC_ERROR;
}
if (!instance) {
return NPERR_INVALID_PARAM;
}
@ -2670,7 +2675,6 @@ _getvalueforurl(NPP instance, NPNURLVariable variable, const char *url,
return NPERR_NO_ERROR;
}
break;
default:
// Fall through and return an error...
;
@ -2683,6 +2687,11 @@ NPError
_setvalueforurl(NPP instance, NPNURLVariable variable, const char *url,
const char *value, uint32_t len)
{
if (!NS_IsMainThread()) {
NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_setvalueforurl called from the wrong thread\n"));
return NPERR_GENERIC_ERROR;
}
if (!instance) {
return NPERR_INVALID_PARAM;
}
@ -2694,7 +2703,7 @@ _setvalueforurl(NPP instance, NPNURLVariable variable, const char *url,
switch (variable) {
case NPNURLVCookie:
{
if (!url || !value || (0 >= len))
if (!value || 0 == len)
return NPERR_INVALID_PARAM;
nsresult rv = NS_ERROR_FAILURE;
@ -2739,6 +2748,11 @@ _getauthenticationinfo(NPP instance, const char *protocol, const char *host,
char **username, uint32_t *ulen, char **password,
uint32_t *plen)
{
if (!NS_IsMainThread()) {
NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_getauthenticationinfo called from the wrong thread\n"));
return NPERR_GENERIC_ERROR;
}
if (!instance || !protocol || !host || !scheme || !realm || !username ||
!ulen || !password || !plen)
return NPERR_INVALID_PARAM;
@ -2795,6 +2809,11 @@ _getauthenticationinfo(NPP instance, const char *protocol, const char *host,
uint32_t
_scheduletimer(NPP instance, uint32_t interval, NPBool repeat, PluginTimerFunc timerFunc)
{
if (!NS_IsMainThread()) {
NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_scheduletimer called from the wrong thread\n"));
return 0;
}
nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata;
if (!inst)
return 0;
@ -2805,6 +2824,11 @@ _scheduletimer(NPP instance, uint32_t interval, NPBool repeat, PluginTimerFunc t
void
_unscheduletimer(NPP instance, uint32_t timerID)
{
if (!NS_IsMainThread()) {
NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_unscheduletimer called from the wrong thread\n"));
return;
}
#ifdef MOZ_WIDGET_ANDROID
// Sometimes Flash calls this with a dead NPP instance. Ensure the one we have
// here is valid and maps to a nsNPAPIPluginInstance.
@ -2821,6 +2845,11 @@ _unscheduletimer(NPP instance, uint32_t timerID)
NPError
_popupcontextmenu(NPP instance, NPMenu* menu)
{
if (!NS_IsMainThread()) {
NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_popupcontextmenu called from the wrong thread\n"));
return 0;
}
#ifdef MOZ_WIDGET_COCOA
nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata;
@ -2870,6 +2899,11 @@ _popupcontextmenu(NPP instance, NPMenu* menu)
NPBool
_convertpoint(NPP instance, double sourceX, double sourceY, NPCoordinateSpace sourceSpace, double *destX, double *destY, NPCoordinateSpace destSpace)
{
if (!NS_IsMainThread()) {
NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_convertpoint called from the wrong thread\n"));
return 0;
}
nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata;
if (!inst)
return false;
@ -2880,6 +2914,11 @@ _convertpoint(NPP instance, double sourceX, double sourceY, NPCoordinateSpace so
void
_urlredirectresponse(NPP instance, void* notifyData, NPBool allow)
{
if (!NS_IsMainThread()) {
NPN_PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("NPN_convertpoint called from the wrong thread\n"));
return;
}
nsNPAPIPluginInstance *inst = (nsNPAPIPluginInstance *)instance->ndata;
if (!inst) {
return;

Просмотреть файл

@ -3564,7 +3564,6 @@ nsPluginHost::AddHeadersToChannel(const char *aHeadersData,
return rv;
}
}
return rv;
}
nsresult

Просмотреть файл

@ -3610,10 +3610,9 @@ PluginInstanceChild::ReadbackDifferenceRect(const nsIntRect& rect)
#elif defined(XP_WIN)
if (!SharedDIBSurface::IsSharedDIBSurface(mBackSurface))
return false;
#else
return false;
#endif
#if defined(MOZ_X11) || defined(XP_WIN)
if (mCurrentSurface->GetContentType() != mBackSurface->GetContentType())
return false;
@ -3639,6 +3638,9 @@ PluginInstanceChild::ReadbackDifferenceRect(const nsIntRect& rect)
}
return true;
#else
return false;
#endif
}
void

Просмотреть файл

@ -42,5 +42,5 @@ LOCAL_INCLUDES += [
]
if CONFIG['GNU_CC']:
CFLAGS += ['-Wshadow']
CXXFLAGS += ['-Wshadow']
CFLAGS += ['-Wshadow', '-Wformat-security']
CXXFLAGS += ['-Wshadow', '-Wformat-security']

Просмотреть файл

@ -465,6 +465,9 @@ nsresult
DOMStorageCache::SetItem(const DOMStorage* aStorage, const nsAString& aKey,
const nsString& aValue, nsString& aOld)
{
// Size of the cache that will change after this action.
int64_t delta = 0;
if (Persist(aStorage)) {
WaitForPreload(Telemetry::LOCALDOMSTORAGE_SETVALUE_BLOCKING_MS);
if (NS_FAILED(mLoadResult)) {
@ -475,11 +478,14 @@ DOMStorageCache::SetItem(const DOMStorage* aStorage, const nsAString& aKey,
Data& data = DataSet(aStorage);
if (!data.mKeys.Get(aKey, &aOld)) {
SetDOMStringToNull(aOld);
// We only consider key size if the key doesn't exist before.
delta += static_cast<int64_t>(aKey.Length());
}
// Check the quota first
const int64_t delta = static_cast<int64_t>(aValue.Length()) -
static_cast<int64_t>(aOld.Length());
delta += static_cast<int64_t>(aValue.Length()) -
static_cast<int64_t>(aOld.Length());
if (!ProcessUsageDelta(aStorage, delta)) {
return NS_ERROR_DOM_QUOTA_REACHED;
}
@ -525,7 +531,8 @@ DOMStorageCache::RemoveItem(const DOMStorage* aStorage, const nsAString& aKey,
}
// Recalculate the cached data size
const int64_t delta = -(static_cast<int64_t>(aOld.Length()));
const int64_t delta = -(static_cast<int64_t>(aOld.Length()) +
static_cast<int64_t>(aKey.Length()));
unused << ProcessUsageDelta(aStorage, delta);
data.mKeys.Remove(aKey);

Просмотреть файл

@ -734,7 +734,7 @@ var interfaceNamesInGlobalScope =
// IMPORTANT: Do not change this list without review from a DOM peer!
"MediaRecorder",
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "MediaSource", linux: false, release: false},
"MediaSource",
// IMPORTANT: Do not change this list without review from a DOM peer!
"MediaStream",
// IMPORTANT: Do not change this list without review from a DOM peer!
@ -988,9 +988,9 @@ var interfaceNamesInGlobalScope =
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "SimpleTest", xbl: false},
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "SourceBuffer", linux: false, release: false},
"SourceBuffer",
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "SourceBufferList", linux: false, release: false},
"SourceBufferList",
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "SpeechSynthesisErrorEvent", b2g: true},
// IMPORTANT: Do not change this list without review from a DOM peer!
@ -1346,7 +1346,7 @@ var interfaceNamesInGlobalScope =
// IMPORTANT: Do not change this list without review from a DOM peer!
"ValidityState",
// IMPORTANT: Do not change this list without review from a DOM peer!
{name: "VideoPlaybackQuality", linux: false, release: false},
"VideoPlaybackQuality",
// IMPORTANT: Do not change this list without review from a DOM peer!
"VideoStreamTrack",
// IMPORTANT: Do not change this list without review from a DOM peer!

Просмотреть файл

@ -71,3 +71,4 @@ partial interface Performance {
[Func="nsPerformance::IsEnabled"]
void clearMeasures(optional DOMString measureName);
};

Просмотреть файл

@ -0,0 +1,23 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* The origin of this IDL file is
* https://w3c.github.io/performance-timeline/#the-performance-observer-interface
*/
dictionary PerformanceObserverInit {
required sequence<DOMString> entryTypes;
};
callback PerformanceObserverCallback = void (PerformanceObserverEntryList entries, PerformanceObserver observer);
[Func="nsPerformance::IsObserverEnabled",
Constructor(PerformanceObserverCallback callback),
Exposed=(Window,Worker)]
interface PerformanceObserver {
[Throws]
void observe(PerformanceObserverInit options);
void disconnect();
};

Просмотреть файл

@ -0,0 +1,24 @@
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* The origin of this IDL file is
* https://w3c.github.io/performance-timeline/#the-performanceobserverentrylist-interface
*/
// XXX should be moved into Performance.webidl.
dictionary PerformanceEntryFilterOptions {
DOMString name;
DOMString entryType;
DOMString initiatorType;
};
[Func="nsPerformance::IsObserverEnabled", Exposed=(Window,Worker)]
interface PerformanceObserverEntryList {
PerformanceEntryList getEntries(optional PerformanceEntryFilterOptions filter);
PerformanceEntryList getEntriesByType(DOMString entryType);
PerformanceEntryList getEntriesByName(DOMString name,
optional DOMString entryType);
};

Просмотреть файл

@ -353,6 +353,8 @@ WEBIDL_FILES = [
'PerformanceMark.webidl',
'PerformanceMeasure.webidl',
'PerformanceNavigation.webidl',
'PerformanceObserver.webidl',
'PerformanceObserverEntryList.webidl',
'PerformanceResourceTiming.webidl',
'PerformanceTiming.webidl',
'PeriodicWave.webidl',

Просмотреть файл

@ -106,8 +106,10 @@ support-files =
bug1132924_worker.js
empty.html
worker_performance_user_timing.js
worker_performance_observer.js
sharedworker_performance_user_timing.js
referrer.sjs
performance_observer.html
[test_404.html]
[test_atob.html]
@ -168,6 +170,7 @@ skip-if = buildapp == 'mulet'
[test_onLine.html]
skip-if = (toolkit == 'gonk' && debug) #debug-only failure
[test_performance_user_timing.html]
[test_performance_observer.html]
[test_promise.html]
[test_promise_resolved_with_string.html]
[test_recursion.html]

Просмотреть файл

@ -0,0 +1,32 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
<meta charset=utf-8>
<html>
<head>
<title>Test for performance observer in worker</title>
</head>
<body>
<div id="log"></div>
<script>
[
"async_test", "test", "setup",
"assert_true", "assert_equals", "assert_array_equals",
"assert_throws", "fetch_tests_from_worker"
].forEach(func => {
window[func] = opener[func].bind(opener);
});
function done() {
opener.add_completion_callback(() => {
self.close();
});
opener.done();
}
fetch_tests_from_worker(new Worker("worker_performance_observer.js"));
done();
</script>
</body>

Просмотреть файл

@ -0,0 +1,17 @@
<!--
Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/
-->
<!DOCTYPE html>
<meta charset=utf-8>
<title>Test for performance observer in worker</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id=log></div>
<script>
'use strict';
SpecialPowers.pushPrefEnv({"set": [["dom.enable_performance_observer", true]]},
function() {
window.open("performance_observer.html");
});
</script>

Просмотреть файл

@ -0,0 +1,4 @@
importScripts(['/resources/testharness.js']);
importScripts(['../../../dom/base/test/test_performance_observer.js']);
done();

Просмотреть файл

@ -79,7 +79,7 @@ txLiteralExpr::toString(nsAString& aStr)
static_cast<StringResult*>(static_cast<txAExprResult*>
(mValue));
char16_t ch = '\'';
if (strRes->mValue.FindChar(ch) != kNotFound) {
if (strRes->mValue.Contains(ch)) {
ch = '\"';
}
aStr.Append(ch);

Просмотреть файл

@ -377,7 +377,7 @@ txExecutionState::getEvalContext()
const txXPathNode*
txExecutionState::retrieveDocument(const nsAString& aUri)
{
NS_ASSERTION(aUri.FindChar(char16_t('#')) == kNotFound,
NS_ASSERTION(!aUri.Contains(char16_t('#')),
"Remove the fragment.");
if (mDisableLoads) {

Просмотреть файл

@ -316,7 +316,7 @@ nsHttpNegotiateAuth::TestNonFqdn(nsIURI *uri)
return false;
// return true if host does not contain a dot and is not an ip address
return !host.IsEmpty() && host.FindChar('.') == kNotFound &&
return !host.IsEmpty() && !host.Contains('.') &&
PR_StringToNetAddr(host.BeginReading(), &addr) != PR_SUCCESS;
}

Просмотреть файл

@ -17,6 +17,8 @@ class SharedDIB
public:
typedef base::SharedMemoryHandle Handle;
static const uint32_t kBytesPerPixel = 4;
public:
SharedDIB();
~SharedDIB();

Просмотреть файл

@ -12,8 +12,6 @@ namespace gfx {
static const cairo_user_data_key_t SHAREDDIB_KEY = {0};
static const long kBytesPerPixel = 4;
bool
SharedDIBSurface::Create(HDC adc, uint32_t aWidth, uint32_t aHeight,
bool aTransparent)
@ -42,7 +40,7 @@ void
SharedDIBSurface::InitSurface(uint32_t aWidth, uint32_t aHeight,
bool aTransparent)
{
long stride = long(aWidth * kBytesPerPixel);
long stride = long(aWidth * SharedDIB::kBytesPerPixel);
unsigned char* data = reinterpret_cast<unsigned char*>(mSharedDIB.GetBits());
gfxImageFormat format = aTransparent ? gfxImageFormat::ARGB32 : gfxImageFormat::RGB24;

Просмотреть файл

@ -11,7 +11,6 @@
namespace mozilla {
namespace gfx {
static const uint32_t kBytesPerPixel = 4;
static const uint32_t kByteAlign = 1 << gfxAlphaRecovery::GoodAlignmentLog2();
static const uint32_t kHeaderBytes =
(sizeof(BITMAPV4HEADER) + kByteAlign - 1) & ~(kByteAlign - 1);
@ -136,6 +135,5 @@ SharedDIBWin::SetupSurface(HDC aHdc, BITMAPV4HEADER *aHdr)
return NS_OK;
}
} // gfx
} // mozilla

Просмотреть файл

@ -17,12 +17,12 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
'SharedDIBSurface.h',
'SharedDIBWin.h',
]
SOURCES += [
UNIFIED_SOURCES += [
'SharedDIBSurface.cpp',
'SharedDIBWin.cpp',
]
SOURCES += [
UNIFIED_SOURCES += [
'SharedDIB.cpp',
]
@ -36,3 +36,5 @@ FINAL_LIBRARY = 'xul'
CXXFLAGS += CONFIG['MOZ_CAIRO_CFLAGS']
CXXFLAGS += CONFIG['TK_CFLAGS']
FAIL_ON_WARNINGS = True

Просмотреть файл

@ -483,11 +483,15 @@ CloneLayerTreePropertiesInternal(Layer* aRoot, bool aIsMask /* = false */)
return MakeUnique<ColorLayerProperties>(static_cast<ColorLayer*>(aRoot));
case Layer::TYPE_IMAGE:
return MakeUnique<ImageLayerProperties>(static_cast<ImageLayer*>(aRoot), aIsMask);
default:
case Layer::TYPE_CANVAS:
case Layer::TYPE_READBACK:
case Layer::TYPE_SHADOW:
case Layer::TYPE_PAINTED:
return MakeUnique<LayerPropertiesBase>(aRoot);
}
return UniquePtr<LayerPropertiesBase>(nullptr);
MOZ_ASSERT_UNREACHABLE("Unexpected root layer type");
return MakeUnique<LayerPropertiesBase>(aRoot);
}
/* static */ UniquePtr<LayerProperties>

Просмотреть файл

@ -660,7 +660,11 @@ public:
// Can't inline these variables due to short-circuit evaluation.
bool continueX = mApzc.mX.SampleOverscrollAnimation(aDelta);
bool continueY = mApzc.mY.SampleOverscrollAnimation(aDelta);
return continueX || continueY;
if (!continueX && !continueY) {
mApzc.OverscrollAnimationEnding();
return false;
}
return true;
}
private:
AsyncPanZoomController& mApzc;
@ -2174,17 +2178,24 @@ void AsyncPanZoomController::AcceptFling(const ParentLayerPoint& aVelocity,
}
CSSPoint predictedDestination = mFrameMetrics.GetScrollOffset() + predictedDelta / mFrameMetrics.GetZoom();
nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
if (controller) {
APZC_LOG("%p fling snapping. friction: %f velocity: %f, %f "
"predictedDelta: %f, %f position: %f, %f "
"predictedDestination: %f, %f\n",
this, friction, velocity.x, velocity.y, (float)predictedDelta.x,
(float)predictedDelta.y, (float)mFrameMetrics.GetScrollOffset().x,
(float)mFrameMetrics.GetScrollOffset().y,
(float)predictedDestination.x, (float)predictedDestination.y);
controller->RequestFlingSnap(mFrameMetrics.GetScrollId(),
predictedDestination);
// If the fling will overscroll, don't request a fling snap, because the
// resulting content scrollTo() would unnecessarily cancel the overscroll
// animation.
bool flingWillOverscroll = IsOverscrolled() && ((velocity.x * mX.GetOverscroll() >= 0) ||
(velocity.y * mY.GetOverscroll() >= 0));
if (!flingWillOverscroll) {
nsRefPtr<GeckoContentController> controller = GetGeckoContentController();
if (controller) {
APZC_LOG("%p fling snapping. friction: %f velocity: %f, %f "
"predictedDelta: %f, %f position: %f, %f "
"predictedDestination: %f, %f\n",
this, friction, velocity.x, velocity.y, (float)predictedDelta.x,
(float)predictedDelta.y, (float)mFrameMetrics.GetScrollOffset().x,
(float)mFrameMetrics.GetScrollOffset().y,
(float)predictedDestination.x, (float)predictedDestination.y);
controller->RequestFlingSnap(mFrameMetrics.GetScrollId(),
predictedDestination);
}
}
StartAnimation(fling);
@ -3319,5 +3330,19 @@ void AsyncPanZoomController::ShareCompositorFrameMetrics() {
}
}
void AsyncPanZoomController::OverscrollAnimationEnding() {
// If we got into overscroll from a fling, that fling did not request a
// fling snap to avoid a resulting scrollTo from cancelling the overscroll
// animation too early. We do still want to request a fling snap, though,
// in case the end of the axis at which we're overscrolled is not a valid
// snap point, so we request one now. If there are no snap points, this will
// do nothing. If there are snap points, we'll get a scrollTo that snaps us
// back to the nearest valid snap point.
if (nsRefPtr<GeckoContentController> controller = GetGeckoContentController()) {
controller->RequestFlingSnap(mFrameMetrics.GetScrollId(),
mFrameMetrics.GetScrollOffset());
}
}
} // namespace layers
} // namespace mozilla

Просмотреть файл

@ -644,6 +644,10 @@ protected:
// Common processing at the end of a touch block.
void OnTouchEndOrCancel();
// This is called by OverscrollAnimation to notify us when the overscroll
// animation is ending.
void OverscrollAnimationEnding();
uint64_t mLayersId;
nsRefPtr<CompositorParent> mCompositorParent;
TaskThrottler mPaintThrottler;

Просмотреть файл

@ -844,6 +844,12 @@ gfxDWriteFontList::MakePlatformFont(const nsAString& aFontName,
return entry;
}
enum DWriteInitError {
errGDIInterop = 1,
errSystemFontCollection = 2,
errNoFonts = 3
};
nsresult
gfxDWriteFontList::InitFontList()
{
@ -874,6 +880,8 @@ gfxDWriteFontList::InitFontList()
hr = gfxWindowsPlatform::GetPlatform()->GetDWriteFactory()->
GetGdiInterop(getter_AddRefs(mGDIInterop));
if (FAILED(hr)) {
Telemetry::Accumulate(Telemetry::DWRITEFONT_INIT_PROBLEM,
uint32_t(errGDIInterop));
return NS_ERROR_FAILURE;
}
@ -886,6 +894,8 @@ gfxDWriteFontList::InitFontList()
NS_ASSERTION(SUCCEEDED(hr), "GetSystemFontCollection failed!");
if (FAILED(hr)) {
Telemetry::Accumulate(Telemetry::DWRITEFONT_INIT_PROBLEM,
uint32_t(errSystemFontCollection));
return NS_ERROR_FAILURE;
}
@ -897,6 +907,8 @@ gfxDWriteFontList::InitFontList()
NS_ASSERTION(mFontFamilies.Count() != 0,
"no fonts found in the system fontlist -- holy crap batman!");
if (mFontFamilies.Count() == 0) {
Telemetry::Accumulate(Telemetry::DWRITEFONT_INIT_PROBLEM,
uint32_t(errNoFonts));
return NS_ERROR_FAILURE;
}

Просмотреть файл

@ -2065,26 +2065,19 @@ gfxPlatform::GetLog(eGfxLog aWhichLog)
switch (aWhichLog) {
case eGfxLog_fontlist:
return sFontlistLog;
break;
case eGfxLog_fontinit:
return sFontInitLog;
break;
case eGfxLog_textrun:
return sTextrunLog;
break;
case eGfxLog_textrunui:
return sTextrunuiLog;
break;
case eGfxLog_cmapdata:
return sCmapDataLog;
break;
case eGfxLog_textperf:
return sTextPerfLog;
break;
default:
break;
}
MOZ_ASSERT_UNREACHABLE("Unexpected log type");
return nullptr;
}

Просмотреть файл

@ -3269,7 +3269,7 @@ gfxMissingFontRecorder::Flush()
}
mNotifiedFonts[i] |= (1 << j);
if (!fontNeeded.IsEmpty()) {
fontNeeded.Append(PRUnichar(','));
fontNeeded.Append(char16_t(','));
}
uint32_t tag = GetScriptTagForCode(i * 32 + j);
fontNeeded.Append(char16_t(tag >> 24));

Просмотреть файл

@ -475,6 +475,21 @@ NextNonEmptyStatement(ParseNode* pn)
return SkipEmptyStatements(pn->pn_next);
}
static bool
GetToken(AsmJSParser& parser, TokenKind* tkp)
{
TokenStream& ts = parser.tokenStream;
TokenKind tk;
while (true) {
if (!ts.getToken(&tk, TokenStream::Operand))
return false;
if (tk != TOK_SEMI)
break;
}
*tkp = tk;
return true;
}
static bool
PeekToken(AsmJSParser& parser, TokenKind* tkp)
{
@ -1108,6 +1123,7 @@ class MOZ_STACK_CLASS ModuleCompiler
Signature sig_;
PropertyName* name_;
Label* entry_;
uint32_t firstUseOffset_;
uint32_t funcIndex_;
uint32_t srcBegin_;
uint32_t srcEnd_;
@ -1115,12 +1131,14 @@ class MOZ_STACK_CLASS ModuleCompiler
bool defined_;
public:
Func(PropertyName* name, Signature&& sig, Label* entry, uint32_t funcIndex)
: sig_(Move(sig)), name_(name), entry_(entry), funcIndex_(funcIndex), srcBegin_(0),
srcEnd_(0), compileTime_(0), defined_(false)
Func(PropertyName* name, uint32_t firstUseOffset, Signature&& sig, Label* entry,
uint32_t funcIndex)
: sig_(Move(sig)), name_(name), entry_(entry), firstUseOffset_(firstUseOffset),
funcIndex_(funcIndex), srcBegin_(0), srcEnd_(0), compileTime_(0), defined_(false)
{}
PropertyName* name() const { return name_; }
uint32_t firstUseOffset() const { return firstUseOffset_; }
bool defined() const { return defined_; }
uint32_t funcIndex() const { return funcIndex_; }
@ -1287,25 +1305,30 @@ class MOZ_STACK_CLASS ModuleCompiler
class FuncPtrTable
{
Signature sig_;
FuncPtrVector elems_;
PropertyName* name_;
uint32_t firstUseOffset_;
uint32_t mask_;
uint32_t globalDataOffset_;
uint32_t tableIndex_;
FuncPtrVector elems_;
public:
FuncPtrTable(ExclusiveContext* cx, Signature&& sig, uint32_t mask, uint32_t gdo,
uint32_t tableIndex)
: sig_(Move(sig)), mask_(mask), globalDataOffset_(gdo), tableIndex_(tableIndex),
elems_(cx)
FuncPtrTable(ExclusiveContext* cx, PropertyName* name, uint32_t firstUseOffset, Signature&& sig,
uint32_t mask, uint32_t gdo, uint32_t tableIndex)
: sig_(Move(sig)), elems_(cx), name_(name), firstUseOffset_(firstUseOffset), mask_(mask),
globalDataOffset_(gdo), tableIndex_(tableIndex)
{}
FuncPtrTable(FuncPtrTable&& rhs)
: sig_(Move(rhs.sig_)), mask_(rhs.mask_), globalDataOffset_(rhs.globalDataOffset_),
elems_(Move(rhs.elems_))
: sig_(Move(rhs.sig_)), elems_(Move(rhs.elems_)), name_(rhs.name()),
firstUseOffset_(rhs.firstUseOffset()), mask_(rhs.mask_),
globalDataOffset_(rhs.globalDataOffset_)
{}
Signature& sig() { return sig_; }
const Signature& sig() const { return sig_; }
PropertyName* name() const { return name_; }
uint32_t firstUseOffset() const { return firstUseOffset_; }
unsigned mask() const { return mask_; }
unsigned globalDataOffset() const { return globalDataOffset_; }
unsigned tableIndex() const { return tableIndex_; }
@ -1596,47 +1619,47 @@ class MOZ_STACK_CLASS ModuleCompiler
}
bool fail(ParseNode* pn, const char* str) {
if (pn)
return failOffset(pn->pn_pos.begin, str);
// The exact rooting static analysis does not perform dataflow analysis, so it believes
// that unrooted things on the stack during compilation may still be accessed after this.
// Since pn is typically only null under OOM, this suppression simply forces any GC to be
// delayed until the compilation is off the stack and more memory can be freed.
gc::AutoSuppressGC nogc(cx_);
TokenPos pos;
TokenStream::Modifier modifier = tokenStream().hasLookahead() ? tokenStream().getLookaheadModifier() : TokenStream::None;
if (!tokenStream().peekTokenPos(&pos, modifier))
return false;
return failOffset(pos.begin, str);
return failOffset(pn->pn_pos.begin, str);
}
bool failfVA(ParseNode* pn, const char* fmt, va_list ap) {
bool failfVAOffset(uint32_t offset, const char* fmt, va_list ap) {
MOZ_ASSERT(!errorString_);
MOZ_ASSERT(errorOffset_ == UINT32_MAX);
MOZ_ASSERT(fmt);
errorOffset_ = pn ? pn->pn_pos.begin : tokenStream().currentToken().pos.end;
errorOffset_ = offset;
errorString_.reset(JS_vsmprintf(fmt, ap));
return false;
}
bool failfOffset(uint32_t offset, const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
failfVAOffset(offset, fmt, ap);
va_end(ap);
return false;
}
bool failf(ParseNode* pn, const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
failfVA(pn, fmt, ap);
failfVAOffset(pn->pn_pos.begin, fmt, ap);
va_end(ap);
return false;
}
bool failName(ParseNode* pn, const char* fmt, PropertyName* name) {
bool failNameOffset(uint32_t offset, const char* fmt, PropertyName* name) {
// This function is invoked without the caller properly rooting its locals.
gc::AutoSuppressGC suppress(cx_);
JSAutoByteString bytes;
if (AtomToPrintableString(cx_, name, &bytes))
failf(pn, fmt, bytes.ptr());
failfOffset(offset, fmt, bytes.ptr());
return false;
}
bool failName(ParseNode* pn, const char* fmt, PropertyName* name) {
return failNameOffset(pn->pn_pos.begin, fmt, name);
}
bool failOverRecursed() {
errorOverRecursed_ = true;
return false;
@ -1767,7 +1790,8 @@ class MOZ_STACK_CLASS ModuleCompiler
global->u.varOrConst.type_ = VarType(coercion).toType().which();
return globalsVector_.append(global) && globals_.putNew(varName, global);
}
bool addFunction(PropertyName* name, Signature&& sig, Func** func, uint32_t* outFuncIndex) {
bool addFunction(PropertyName* name, uint32_t firstUseOffset, Signature&& sig, Func** func,
uint32_t* outFuncIndex) {
MOZ_ASSERT(!finishedFunctionBodies_);
uint32_t funcIndex = functions_.length();
if (outFuncIndex)
@ -1781,13 +1805,13 @@ class MOZ_STACK_CLASS ModuleCompiler
Label* entry = moduleLifo_.new_<Label>();
if (!entry)
return false;
*func = moduleLifo_.new_<Func>(name, Move(sig), entry, funcIndex);
*func = moduleLifo_.new_<Func>(name, firstUseOffset, Move(sig), entry, funcIndex);
if (!*func)
return false;
return functions_.append(*func);
}
bool addFuncPtrTable(PropertyName* name, Signature&& sig, uint32_t mask, FuncPtrTable** table,
uint32_t* tableIndexOut)
bool addFuncPtrTable(PropertyName* name, uint32_t offset, Signature&& sig, uint32_t mask,
FuncPtrTable** table, uint32_t* tableIndexOut)
{
uint32_t tableIndex = funcPtrTables_.length();
if (tableIndexOut)
@ -1801,7 +1825,7 @@ class MOZ_STACK_CLASS ModuleCompiler
uint32_t globalDataOffset;
if (!module_->addFuncPtrTable(/* numElems = */ mask + 1, &globalDataOffset))
return false;
FuncPtrTable tmpTable(cx_, Move(sig), mask, globalDataOffset, tableIndex);
FuncPtrTable tmpTable(cx_, name, offset, Move(sig), mask, globalDataOffset, tableIndex);
if (!funcPtrTables_.append(Move(tmpTable)))
return false;
*table = &funcPtrTables_.back();
@ -2972,7 +2996,7 @@ class FunctionBuilder
{
va_list ap;
va_start(ap, fmt);
m_.failfVA(pn, fmt, ap);
m_.failfVAOffset(pn->pn_pos.begin, fmt, ap);
va_end(ap);
return false;
}
@ -4713,6 +4737,11 @@ CheckNewArrayView(ModuleCompiler& m, PropertyName* varName, ParseNode* newExpr)
shared = global->viewIsSharedView();
}
#if !defined(ENABLE_SHARED_ARRAY_BUFFER)
if (shared)
return m.fail(ctorExpr, "shared views not supported by this build");
#endif
if (!CheckNewArrayViewArgs(m, ctorExpr, bufferName))
return false;
@ -4857,6 +4886,11 @@ CheckGlobalDotImport(ModuleCompiler& m, PropertyName* varName, ParseNode* initNo
Scalar::Type type;
bool shared = false;
if (IsArrayViewCtorName(m, field, &type, &shared)) {
#if !defined(ENABLE_SHARED_ARRAY_BUFFER)
if (shared)
return m.fail(initNode, "shared views not supported by this build");
#endif
if (!m.module().isValidViewSharedness(shared))
return m.failName(initNode, "'%s' has different sharedness than previous view constructors", field);
return m.addArrayViewCtor(varName, type, field, shared);
@ -4918,12 +4952,15 @@ CheckModuleProcessingDirectives(ModuleCompiler& m)
return true;
if (!IsIgnoredDirectiveName(m.cx(), ts.currentToken().atom()))
return m.fail(nullptr, "unsupported processing directive");
return m.failOffset(ts.currentToken().pos.begin, "unsupported processing directive");
if (!ts.matchToken(&matched, TOK_SEMI))
TokenKind tt;
if (!ts.getToken(&tt))
return false;
if (!matched)
return m.fail(nullptr, "expected semicolon after string literal");
if (tt != TOK_SEMI) {
return m.failOffset(ts.currentToken().pos.begin,
"expected semicolon after string literal");
}
}
}
@ -6309,7 +6346,7 @@ CheckFunctionSignature(ModuleCompiler& m, ParseNode* usepn, Signature&& sig, Pro
if (!existing) {
if (!CheckModuleLevelName(m, usepn, name))
return false;
return m.addFunction(name, Move(sig), func, funcIndex);
return m.addFunction(name, usepn->pn_pos.begin, Move(sig), func, funcIndex);
}
if (!CheckSignatureAgainstExisting(m, usepn, sig, existing->sig()))
@ -6411,7 +6448,7 @@ CheckFuncPtrTableAgainstExisting(ModuleCompiler& m, ParseNode* usepn,
if (!CheckModuleLevelName(m, usepn, name))
return false;
return m.addFuncPtrTable(name, Move(sig), mask, tableOut, tableIndex);
return m.addFuncPtrTable(name, usepn->pn_pos.begin, Move(sig), mask, tableOut, tableIndex);
}
static bool
@ -9643,12 +9680,12 @@ CheckHeapLengthCondition(ModuleCompiler& m, ParseNode* cond, PropertyName* newBu
static bool
CheckReturnBoolLiteral(ModuleCompiler& m, ParseNode* stmt, bool retval)
{
if (!stmt)
return m.fail(stmt, "expected return statement");
if (stmt->isKind(PNK_STATEMENTLIST)) {
stmt = SkipEmptyStatements(ListHead(stmt));
if (!stmt || NextNonEmptyStatement(stmt))
ParseNode* next = SkipEmptyStatements(ListHead(stmt));
if (!next)
return m.fail(stmt, "expected return statement");
stmt = next;
if (NextNonEmptyStatement(stmt))
return m.fail(stmt, "expected single return statement");
}
@ -9665,7 +9702,7 @@ CheckReturnBoolLiteral(ModuleCompiler& m, ParseNode* stmt, bool retval)
static bool
CheckReassignmentTo(ModuleCompiler& m, ParseNode* stmt, PropertyName* lhsName, ParseNode** rhs)
{
if (!stmt || !stmt->isKind(PNK_SEMI))
if (!stmt->isKind(PNK_SEMI))
return m.fail(stmt, "missing reassignment");
ParseNode* assign = UnaryKid(stmt);
@ -9729,9 +9766,13 @@ CheckChangeHeap(ModuleCompiler& m, ParseNode* fn, bool* validated)
if (!CheckReturnBoolLiteral(m, thenStmt, false))
return false;
stmtIter = NextNonEmptyStatement(stmtIter);
ParseNode* next = NextNonEmptyStatement(stmtIter);
for (unsigned i = 0; i < m.numArrayViews(); i++, next = NextNonEmptyStatement(stmtIter)) {
if (!next)
return m.failOffset(stmtIter->pn_pos.end, "missing reassignment");
stmtIter = next;
for (unsigned i = 0; i < m.numArrayViews(); i++, stmtIter = NextNonEmptyStatement(stmtIter)) {
const ModuleCompiler::ArrayView& view = m.arrayView(i);
ParseNode* rhs;
@ -9755,13 +9796,20 @@ CheckChangeHeap(ModuleCompiler& m, ParseNode* fn, bool* validated)
return false;
}
if (!next)
return m.failOffset(stmtIter->pn_pos.end, "missing reassignment");
stmtIter = next;
ParseNode* rhs;
if (!CheckReassignmentTo(m, stmtIter, bufferName, &rhs))
return false;
if (!IsUseOfName(rhs, newBufferName))
return m.failName(stmtIter, "expecting assignment of new buffer to %s", bufferName);
stmtIter = NextNonEmptyStatement(stmtIter);
next = NextNonEmptyStatement(stmtIter);
if (!next)
return m.failOffset(stmtIter->pn_pos.end, "expected return statement");
stmtIter = next;
if (!CheckReturnBoolLiteral(m, stmtIter, true))
return false;
@ -9824,7 +9872,7 @@ ParseFunction(ModuleCompiler& m, ParseNode** fnOut)
if (tokenStream.hadError() || directives == newDirectives)
return false;
return m.fail(nullptr, "encountered new directive");
return m.fail(fn, "encountered new directive in function");
}
MOZ_ASSERT(!tokenStream.hadError());
@ -10378,8 +10426,11 @@ static bool
CheckAllFunctionsDefined(ModuleCompiler& m)
{
for (unsigned i = 0; i < m.numFunctions(); i++) {
if (!m.function(i).entry().bound())
return m.failName(nullptr, "missing definition of function %s", m.function(i).name());
if (!m.function(i).entry().bound()) {
ModuleCompiler::Func& f = m.function(i);
return m.failNameOffset(f.firstUseOffset(),
"missing definition of function %s", f.name());
}
}
return true;
@ -10764,8 +10815,12 @@ CheckFuncPtrTables(ModuleCompiler& m)
}
for (unsigned i = 0; i < m.numFuncPtrTables(); i++) {
if (!m.funcPtrTable(i).initialized())
return m.fail(nullptr, "expecting function-pointer table");
ModuleCompiler::FuncPtrTable& funcPtrTable = m.funcPtrTable(i);
if (!funcPtrTable.initialized()) {
return m.failNameOffset(funcPtrTable.firstUseOffset(),
"function-pointer table %s wasn't defined",
funcPtrTable.name());
}
}
return true;
@ -10817,13 +10872,16 @@ static bool
CheckModuleReturn(ModuleCompiler& m)
{
TokenKind tk;
if (!PeekToken(m.parser(), &tk))
if (!GetToken(m.parser(), &tk))
return false;
TokenStream& ts = m.parser().tokenStream;
if (tk != TOK_RETURN) {
if (tk == TOK_RC || tk == TOK_EOF)
return m.fail(nullptr, "expecting return statement");
return m.fail(nullptr, "invalid asm.js statement");
const char* msg = (tk == TOK_RC || tk == TOK_EOF)
? "expecting return statement"
: "invalid asm.js. statement";
return m.failOffset(ts.currentToken().pos.begin, msg);
}
ts.ungetToken();
ParseNode* returnStmt = m.parser().statement(YieldIsName);
if (!returnStmt)
@ -12020,8 +12078,7 @@ CheckModule(ExclusiveContext* cx, AsmJSParser& parser, ParseNode* stmtList,
m.startFunctionBodies();
#if !defined(ENABLE_SHARED_ARRAY_BUFFER)
if (m.module().hasArrayView() && m.module().isSharedView())
return m.fail(nullptr, "shared views not supported by this build");
MOZ_ASSERT(!m.module().hasArrayView() || !m.module().isSharedView());
#endif
if (!CheckFunctions(m))
@ -12036,10 +12093,15 @@ CheckModule(ExclusiveContext* cx, AsmJSParser& parser, ParseNode* stmtList,
return false;
TokenKind tk;
if (!PeekToken(m.parser(), &tk))
if (!GetToken(m.parser(), &tk))
return false;
if (tk != TOK_EOF && tk != TOK_RC)
return m.fail(nullptr, "top-level export (return) must be the last statement");
TokenStream& ts = m.parser().tokenStream;
if (tk == TOK_EOF || tk == TOK_RC) {
ts.ungetToken();
} else {
return m.failOffset(ts.currentToken().pos.begin,
"top-level export (return) must be the last statement");
}
// Delay flushing until dynamic linking. The inhibited range is set by the
// masm.executableCopy() called transitively by FinishModule.

Просмотреть файл

@ -1795,6 +1795,7 @@ ia64*-hpux*)
dnl Probably also a compiler bug, but what can you do?
PROFILE_USE_LDFLAGS="-LTCG:PGUPDATE"
LDFLAGS="$LDFLAGS -DYNAMICBASE"
RCFLAGS="-nologo"
fi
AC_DEFINE(HAVE_SNPRINTF)
AC_DEFINE(HAVE__MSIZE)

Просмотреть файл

@ -428,17 +428,10 @@ BytecodeCompiler::checkArgumentsWithinEval(JSContext* cx, HandleFunction fun)
return false;
}
// Force construction of arguments objects for functions that use
// |arguments| within an eval.
RootedScript script(cx, fun->getOrCreateScript(cx));
if (!script)
return false;
if (script->argumentsHasVarBinding()) {
if (!JSScript::argumentsOptimizationFailed(cx, script))
return false;
}
// It's an error to use |arguments| in a legacy generator expression.
if (script->isGeneratorExp() && script->isLegacyGenerator()) {
parser->report(ParseError, false, nullptr, JSMSG_BAD_GENEXP_BODY, js_arguments_str);

Просмотреть файл

@ -956,14 +956,8 @@ Parser<FullParseHandler>::checkFunctionArguments()
FunctionBox* funbox = pc->sc->asFunctionBox();
funbox->setArgumentsHasLocalBinding();
/*
* If a script has both explicit mentions of 'arguments' and dynamic
* name lookups which could access the arguments, an arguments object
* must be created eagerly. The SSA analysis used for lazy arguments
* cannot cope with dynamic name accesses, so any 'arguments' accessed
* via a NAME opcode must force construction of the arguments object.
*/
if (pc->sc->bindingsAccessedDynamically() && maybeArgDef)
/* Dynamic scope access destroys all hope of optimization. */
if (pc->sc->bindingsAccessedDynamically())
funbox->setDefinitelyNeedsArgsObj();
/*
@ -991,9 +985,6 @@ Parser<FullParseHandler>::checkFunctionArguments()
funbox->setDefinitelyNeedsArgsObj();
}
}
/* Watch for mutation of arguments through e.g. eval(). */
if (pc->sc->bindingsAccessedDynamically())
funbox->setDefinitelyNeedsArgsObj();
}
}

Просмотреть файл

@ -489,16 +489,6 @@ class MOZ_STACK_CLASS TokenStream
#endif
}
bool hasLookahead() { return lookahead > 0; }
Modifier getLookaheadModifier() {
#ifdef DEBUG
return nextToken().modifier;
#else
return None;
#endif
}
void
verifyConsistentModifier(Modifier modifier, Token lookaheadToken) {
#ifdef DEBUG
@ -991,6 +981,8 @@ class MOZ_STACK_CLASS TokenStream
return tokens[(cursor + 1) & ntokensMask];
}
bool hasLookahead() { return lookahead > 0; }
// Options used for parsing/tokenizing.
const ReadOnlyCompileOptions& options_;

Просмотреть файл

@ -3500,45 +3500,6 @@ CodeGenerator::visitGetDynamicName(LGetDynamicName* lir)
bailoutFrom(&undefined, lir->snapshot());
}
void
CodeGenerator::emitFilterArgumentsOrEval(LInstruction* lir, Register string,
Register temp1, Register temp2)
{
masm.loadJSContext(temp2);
masm.setupUnalignedABICall(temp1);
masm.passABIArg(temp2);
masm.passABIArg(string);
masm.callWithABI(JS_FUNC_TO_DATA_PTR(void*, FilterArgumentsOrEval));
Label bail;
masm.branchIfFalseBool(ReturnReg, &bail);
bailoutFrom(&bail, lir->snapshot());
}
void
CodeGenerator::visitFilterArgumentsOrEvalS(LFilterArgumentsOrEvalS* lir)
{
emitFilterArgumentsOrEval(lir, ToRegister(lir->getString()),
ToRegister(lir->temp1()),
ToRegister(lir->temp2()));
}
void
CodeGenerator::visitFilterArgumentsOrEvalV(LFilterArgumentsOrEvalV* lir)
{
ValueOperand input = ToValue(lir, LFilterArgumentsOrEvalV::Input);
// Act as nop on non-strings.
Label done;
masm.branchTestString(Assembler::NotEqual, input, &done);
emitFilterArgumentsOrEval(lir, masm.extractString(input, ToRegister(lir->temp3())),
ToRegister(lir->temp1()), ToRegister(lir->temp2()));
masm.bind(&done);
}
typedef bool (*DirectEvalSFn)(JSContext*, HandleObject, HandleScript, HandleValue, HandleValue,
HandleString, jsbytecode*, MutableHandleValue);
static const VMFunction DirectEvalStringInfo = FunctionInfo<DirectEvalSFn>(DirectEvalStringFromIon);

Просмотреть файл

@ -149,8 +149,6 @@ class CodeGenerator : public CodeGeneratorSpecific
void visitUnreachable(LUnreachable* unreachable);
void visitEncodeSnapshot(LEncodeSnapshot* lir);
void visitGetDynamicName(LGetDynamicName* lir);
void visitFilterArgumentsOrEvalS(LFilterArgumentsOrEvalS* lir);
void visitFilterArgumentsOrEvalV(LFilterArgumentsOrEvalV* lir);
void visitCallDirectEval(LCallDirectEval* lir);
void visitDoubleToInt32(LDoubleToInt32* lir);
void visitFloat32ToInt32(LFloat32ToInt32* lir);

Просмотреть файл

@ -236,7 +236,11 @@ class ExecutableAllocator
}
systemRelease(pool->m_allocation);
MOZ_ASSERT(m_pools.initialized());
m_pools.remove(m_pools.lookup(pool)); // this asserts if |pool| is not in m_pools
// Pool may not be present in m_pools if we hit OOM during creation.
auto ptr = m_pools.lookup(pool);
if (ptr)
m_pools.remove(ptr);
}
void addSizeOfCode(JS::CodeSizes* sizes) const;
@ -299,7 +303,13 @@ class ExecutableAllocator
systemRelease(a);
return nullptr;
}
m_pools.put(pool);
if (!m_pools.put(pool)) {
js_delete(pool);
systemRelease(a);
return nullptr;
}
return pool;
}

Просмотреть файл

@ -3470,26 +3470,14 @@ jit::AnalyzeArgumentsUsage(JSContext* cx, JSScript* scriptArg)
// and also simplifies handling of early returns.
script->setNeedsArgsObj(true);
// Always construct arguments objects when in debug mode and for generator
// scripts (generators can be suspended when speculation fails).
// Always construct arguments objects when in debug mode, for generator
// scripts (generators can be suspended when speculation fails) or when
// direct eval is present.
//
// FIXME: Don't build arguments for ES6 generator expressions.
if (scriptArg->isDebuggee() || script->isGenerator())
if (scriptArg->isDebuggee() || script->isGenerator() || script->bindingsAccessedDynamically())
return true;
// If the script has dynamic name accesses which could reach 'arguments',
// the parser will already have checked to ensure there are no explicit
// uses of 'arguments' in the function. If there are such uses, the script
// will be marked as definitely needing an arguments object.
//
// New accesses on 'arguments' can occur through 'eval' or the debugger
// statement. In the former case, we will dynamically detect the use and
// mark the arguments optimization as having failed.
if (script->bindingsAccessedDynamically()) {
script->setNeedsArgsObj(false);
return true;
}
if (!jit::IsIonEnabled(cx))
return true;

Просмотреть файл

@ -6599,9 +6599,6 @@ IonBuilder::jsop_eval(uint32_t argc)
}
}
MInstruction* filterArguments = MFilterArgumentsOrEval::New(alloc(), string);
current->add(filterArguments);
MInstruction* ins = MCallDirectEval::New(alloc(), scopeChain, string,
thisValue, newTargetValue, pc);
current->add(ins);

Просмотреть файл

@ -855,7 +855,7 @@ JitcodeGlobalTable::sweep(JSRuntime* rt)
if (entry->baseEntry().isJitcodeAboutToBeFinalized())
e.removeFront();
else
entry->sweep(rt);
entry->sweepChildren(rt);
}
}
@ -895,7 +895,7 @@ JitcodeGlobalEntry::BaselineEntry::mark(JSTracer* trc)
}
void
JitcodeGlobalEntry::BaselineEntry::sweep()
JitcodeGlobalEntry::BaselineEntry::sweepChildren()
{
MOZ_ALWAYS_FALSE(IsAboutToBeFinalizedUnbarriered(&script_));
}
@ -946,7 +946,7 @@ JitcodeGlobalEntry::IonEntry::mark(JSTracer* trc)
}
void
JitcodeGlobalEntry::IonEntry::sweep()
JitcodeGlobalEntry::IonEntry::sweepChildren()
{
for (unsigned i = 0; i < numScripts(); i++)
MOZ_ALWAYS_FALSE(IsAboutToBeFinalizedUnbarriered(&sizedScriptList()->pairs[i].script));
@ -1004,11 +1004,11 @@ JitcodeGlobalEntry::IonCacheEntry::mark(JSTracer* trc)
}
void
JitcodeGlobalEntry::IonCacheEntry::sweep(JSRuntime* rt)
JitcodeGlobalEntry::IonCacheEntry::sweepChildren(JSRuntime* rt)
{
JitcodeGlobalEntry entry;
RejoinEntry(rt, *this, nativeStartAddr(), &entry);
entry.sweep(rt);
entry.sweepChildren(rt);
}
bool

Просмотреть файл

@ -369,7 +369,7 @@ class JitcodeGlobalEntry
IonTrackedOptimizationsTypeInfo::ForEachOpAdapter& op);
template <class ShouldMarkProvider> bool mark(JSTracer* trc);
void sweep();
void sweepChildren();
bool isMarkedFromAnyThread();
};
@ -427,7 +427,7 @@ class JitcodeGlobalEntry
JSScript** script, jsbytecode** pc) const;
template <class ShouldMarkProvider> bool mark(JSTracer* trc);
void sweep();
void sweepChildren();
bool isMarkedFromAnyThread();
};
@ -476,7 +476,7 @@ class JitcodeGlobalEntry
IonTrackedOptimizationsTypeInfo::ForEachOpAdapter& op);
template <class ShouldMarkProvider> bool mark(JSTracer* trc);
void sweep(JSRuntime* rt);
void sweepChildren(JSRuntime* rt);
bool isMarkedFromAnyThread(JSRuntime* rt);
};
@ -931,16 +931,16 @@ class JitcodeGlobalEntry
return markedAny;
}
void sweep(JSRuntime* rt) {
void sweepChildren(JSRuntime* rt) {
switch (kind()) {
case Ion:
ionEntry().sweep();
ionEntry().sweepChildren();
break;
case Baseline:
baselineEntry().sweep();
baselineEntry().sweepChildren();
break;
case IonCache:
ionCacheEntry().sweep(rt);
ionCacheEntry().sweepChildren(rt);
case Dummy:
break;
default:

Просмотреть файл

@ -585,30 +585,6 @@ LIRGenerator::visitGetDynamicName(MGetDynamicName* ins)
defineReturn(lir, ins);
}
void
LIRGenerator::visitFilterArgumentsOrEval(MFilterArgumentsOrEval* ins)
{
MDefinition* string = ins->getString();
MOZ_ASSERT(string->type() == MIRType_String || string->type() == MIRType_Value);
LInstruction* lir;
if (string->type() == MIRType_String) {
lir = new(alloc()) LFilterArgumentsOrEvalS(useFixed(string, CallTempReg0),
tempFixed(CallTempReg1),
tempFixed(CallTempReg2));
} else {
lir = new(alloc()) LFilterArgumentsOrEvalV(tempFixed(CallTempReg0),
tempFixed(CallTempReg1),
tempFixed(CallTempReg2));
useBoxFixed(lir, LFilterArgumentsOrEvalV::Input, string,
CallTempReg3, CallTempReg4);
}
assignSnapshot(lir, Bailout_StringArgumentsEval);
add(lir, ins);
assignSafepoint(lir, ins);
}
void
LIRGenerator::visitCallDirectEval(MCallDirectEval* ins)
{

Просмотреть файл

@ -106,7 +106,6 @@ class LIRGenerator : public LIRGeneratorSpecific
void visitAssertFloat32(MAssertFloat32* ins);
void visitAssertRecoveredOnBailout(MAssertRecoveredOnBailout* ins);
void visitGetDynamicName(MGetDynamicName* ins);
void visitFilterArgumentsOrEval(MFilterArgumentsOrEval* ins);
void visitCallDirectEval(MCallDirectEval* ins);
void visitTest(MTest* test);
void visitGotoWithFake(MGotoWithFake* ins);

Просмотреть файл

@ -4051,34 +4051,6 @@ class MGetDynamicName
}
};
// Bailout if the input string contains 'arguments' or 'eval'.
class MFilterArgumentsOrEval
: public MAryInstruction<1>,
public BoxExceptPolicy<0, MIRType_String>::Data
{
protected:
explicit MFilterArgumentsOrEval(MDefinition* string)
{
initOperand(0, string);
setGuard();
setResultType(MIRType_None);
}
public:
INSTRUCTION_HEADER(FilterArgumentsOrEval)
static MFilterArgumentsOrEval* New(TempAllocator& alloc, MDefinition* string) {
return new(alloc) MFilterArgumentsOrEval(string);
}
MDefinition* getString() const {
return getOperand(0);
}
bool possiblyCalls() const override {
return true;
}
};
class MCallDirectEval
: public MAryInstruction<4>,
public Mix4Policy<ObjectPolicy<0>,

Просмотреть файл

@ -69,7 +69,6 @@ namespace jit {
_(AssertFloat32) \
_(AssertRecoveredOnBailout) \
_(GetDynamicName) \
_(FilterArgumentsOrEval) \
_(CallDirectEval) \
_(BitNot) \
_(TypeOf) \

Просмотреть файл

@ -588,25 +588,6 @@ GetDynamicName(JSContext* cx, JSObject* scopeChain, JSString* str, Value* vp)
vp->setUndefined();
}
bool
FilterArgumentsOrEval(JSContext* cx, JSString* str)
{
// ensureLinear() is fallible, but cannot GC: it can only allocate a
// character buffer for the flattened string. If this call fails then the
// calling Ion code will bailout, resume in Baseline and likely fail again
// when trying to flatten the string and unwind the stack.
JS::AutoCheckCannotGC nogc;
JSLinearString* linear = str->ensureLinear(cx);
if (!linear)
return false;
static const char16_t arguments[] = {'a', 'r', 'g', 'u', 'm', 'e', 'n', 't', 's'};
static const char16_t eval[] = {'e', 'v', 'a', 'l'};
return !StringHasPattern(linear, arguments, mozilla::ArrayLength(arguments)) &&
!StringHasPattern(linear, eval, mozilla::ArrayLength(eval));
}
void
PostWriteBarrier(JSRuntime* rt, JSObject* obj)
{

Просмотреть файл

@ -637,8 +637,6 @@ bool CreateThis(JSContext* cx, HandleObject callee, MutableHandleValue rval);
void GetDynamicName(JSContext* cx, JSObject* scopeChain, JSString* str, Value* vp);
bool FilterArgumentsOrEval(JSContext* cx, JSString* str);
void PostWriteBarrier(JSRuntime* rt, JSObject* obj);
void PostGlobalWriteBarrier(JSRuntime* rt, JSObject* obj);

Просмотреть файл

@ -1874,64 +1874,6 @@ class LGetDynamicName : public LCallInstructionHelper<BOX_PIECES, 2, 3>
}
};
class LFilterArgumentsOrEvalS : public LCallInstructionHelper<0, 1, 2>
{
public:
LIR_HEADER(FilterArgumentsOrEvalS)
LFilterArgumentsOrEvalS(const LAllocation& string, const LDefinition& temp1,
const LDefinition& temp2)
{
setOperand(0, string);
setTemp(0, temp1);
setTemp(1, temp2);
}
MFilterArgumentsOrEval* mir() const {
return mir_->toFilterArgumentsOrEval();
}
const LAllocation* getString() {
return getOperand(0);
}
const LDefinition* temp1() {
return getTemp(0);
}
const LDefinition* temp2() {
return getTemp(1);
}
};
class LFilterArgumentsOrEvalV : public LCallInstructionHelper<0, BOX_PIECES, 3>
{
public:
LIR_HEADER(FilterArgumentsOrEvalV)
LFilterArgumentsOrEvalV(const LDefinition& temp1, const LDefinition& temp2,
const LDefinition& temp3)
{
setTemp(0, temp1);
setTemp(1, temp2);
setTemp(2, temp3);
}
static const size_t Input = 0;
MFilterArgumentsOrEval* mir() const {
return mir_->toFilterArgumentsOrEval();
}
const LDefinition* temp1() {
return getTemp(0);
}
const LDefinition* temp2() {
return getTemp(1);
}
const LDefinition* temp3() {
return getTemp(2);
}
};
class LCallDirectEval : public LCallInstructionHelper<BOX_PIECES, 2 + (2 * BOX_PIECES), 0>
{
public:

Просмотреть файл

@ -77,8 +77,6 @@
_(Unreachable) \
_(EncodeSnapshot) \
_(GetDynamicName) \
_(FilterArgumentsOrEvalS) \
_(FilterArgumentsOrEvalV) \
_(CallDirectEval) \
_(StackArgT) \
_(StackArgV) \

Просмотреть файл

@ -2368,7 +2368,7 @@ nsIFrame::BuildDisplayListForChild(nsDisplayListBuilder* aBuilder,
bool isPositioned = disp->IsAbsPosContainingBlock(child);
bool isStackingContext =
(isPositioned && (disp->mPosition == NS_STYLE_POSITION_STICKY ||
(isPositioned && (disp->IsPositionForcingStackingContext() ||
pos->mZIndex.GetUnit() == eStyleUnit_Integer)) ||
(disp->mWillChangeBitField & NS_STYLE_WILL_CHANGE_STACKING_CONTEXT) ||
disp->mIsolation != NS_STYLE_ISOLATION_AUTO ||

Просмотреть файл

@ -12,6 +12,7 @@
#include "nsIServiceManager.h"
#include "nsISupportsArray.h"
#include "nsString.h"
#include "nsIStyleSheetLinkingElement.h"
#include "nsIDOMElement.h"
#include "nsIDocument.h"
#include "nsIPresShell.h"
@ -301,6 +302,33 @@ inDOMUtils::GetRuleColumn(nsIDOMCSSRule* aRule, uint32_t* _retval)
return NS_OK;
}
NS_IMETHODIMP
inDOMUtils::GetRelativeRuleLine(nsIDOMCSSRule* aRule, uint32_t* _retval)
{
NS_ENSURE_ARG_POINTER(aRule);
Rule* rule = aRule->GetCSSRule();
if (!rule) {
return NS_ERROR_FAILURE;
}
uint32_t lineNumber = rule->GetLineNumber();
CSSStyleSheet* sheet = rule->GetStyleSheet();
if (sheet) {
nsINode* owningNode = sheet->GetOwnerNode();
if (owningNode) {
nsCOMPtr<nsIStyleSheetLinkingElement> link =
do_QueryInterface(owningNode);
if (link) {
lineNumber -= link->GetLineNumber() - 1;
}
}
}
*_retval = lineNumber;
return NS_OK;
}
NS_IMETHODIMP
inDOMUtils::GetCSSLexer(const nsAString& aText, JSContext* aCx,
JS::MutableHandleValue aResult)

Просмотреть файл

@ -17,7 +17,7 @@ interface nsIDOMFontFaceList;
interface nsIDOMRange;
interface nsIDOMCSSStyleSheet;
[scriptable, uuid(60b4cbf7-2a08-4419-8937-6ef495417824)]
[scriptable, uuid(d67c0463-592e-4d7c-b67e-923ee3f6c643)]
interface inIDOMUtils : nsISupports
{
// CSS utilities
@ -28,6 +28,16 @@ interface inIDOMUtils : nsISupports
unsigned long getRuleLine(in nsIDOMCSSRule aRule);
unsigned long getRuleColumn(in nsIDOMCSSRule aRule);
/**
* Like getRuleLine, but if the rule is in a <style> element,
* returns a line number relative to the start of the element.
*
* @param nsIDOMCSSRule aRule the rule to examine
* @return the line number of the rule, possibly relative to the
* <style> element
*/
unsigned long getRelativeRuleLine(in nsIDOMCSSRule aRule);
[implicit_jscontext]
jsval getCSSLexer(in DOMString aText);

Просмотреть файл

@ -16,6 +16,7 @@ support-files =
[test_bug1006595.html]
[test_color_to_rgba.html]
[test_css_property_is_valid.html]
[test_getRelativeRuleLine.html]
[test_get_all_style_sheets.html]
[test_is_valid_css_color.html]
[test_isinheritableproperty.html]

Просмотреть файл

@ -0,0 +1,67 @@
<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test inDOMUtils::getRelativeRuleLine</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
<style>
@supports (not (whatever: 72 zq)) {
#test {
background-color: #f0c;
}
}
#test {
color: #f0c;
}
</style>
<style>#test { color: red; }</style>
<style>
@invalidatkeyword {
}
#test {
color: blue;
}
</style>
<script type="application/javascript;version=1.8">
let utils = SpecialPowers.Cc["@mozilla.org/inspector/dom-utils;1"]
.getService(SpecialPowers.Ci.inIDOMUtils);
let tests = [
{ sheetNo: 0, ruleNo: 0, lineNo: 1, columnNo: 1 },
{ sheetNo: 1, ruleNo: 0, lineNo: 2, columnNo: 15 },
{ sheetNo: 1, ruleNo: 1, lineNo: 8, columnNo: 5 },
{ sheetNo: 2, ruleNo: 0, lineNo: 1, columnNo: 1 },
{ sheetNo: 3, ruleNo: 0, lineNo: 5, columnNo: 6 },
];
function doTest() {
for (let test of tests) {
let sheet = document.styleSheets[test.sheetNo];
let rule = sheet.cssRules[test.ruleNo];
let line = utils.getRelativeRuleLine(rule);
let column = utils.getRuleColumn(rule);
info("testing sheet " + test.sheetNo + ", rule " + test.ruleNo);
is(line, test.lineNo, "line number is correct");
is(column, test.columnNo, "column number is correct");
}
SimpleTest.finish();
}
SimpleTest.waitForExplicitFinish();
addLoadEvent(doTest);
</script>
</head>
<body>
<h1>Test inDOMUtils::getRelativeRuleLine</h1>
<p id="display"></p>
<div id="content" style="display: none">
</div>
<pre id="test">
</pre>
</body>
</html>

Просмотреть файл

@ -61,7 +61,7 @@ struct nsGlyphCode {
bool IsGlyphID() const { return font == -1; }
int32_t Length() const {
return (IsGlyphID() || code[1] == PRUnichar('\0') ? 1 : 2);
return (IsGlyphID() || code[1] == char16_t('\0') ? 1 : 2);
}
bool Exists() const
{

Просмотреть файл

@ -0,0 +1,3 @@
<!DOCTYPE HTML>
<body>
<div style="position:absolute; left:0; top:0; width:100px; height:100px; background:lime"></div>

Просмотреть файл

@ -0,0 +1,6 @@
<!DOCTYPE HTML>
<body>
<div style="position:fixed; left:0; top:0">
<div style="position:absolute; z-index:2; left:0; top:0; width:100px; height:100px; background:red"></div>
</div>
<div style="position:absolute; z-index:1; left:0; top:0; width:100px; height:100px; background:lime"></div>

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше