merge mozilla-inbound to mozilla-central a=merge

This commit is contained in:
Carsten "Tomcat" Book 2017-04-11 10:17:24 +02:00
commit ee9da45454
149 changed files with 1956 additions and 2876 deletions

View File

@ -307,13 +307,23 @@ nsScriptSecurityManager::GetChannelResultPrincipal(nsIChannel* aChannel,
if (!principalToInherit) { if (!principalToInherit) {
principalToInherit = loadInfo->TriggeringPrincipal(); principalToInherit = loadInfo->TriggeringPrincipal();
} }
nsCOMPtr<nsIContentSecurityPolicy> originalCsp; nsCOMPtr<nsIContentSecurityPolicy> originalCSP;
principalToInherit->GetCsp(getter_AddRefs(originalCsp)); principalToInherit->GetCsp(getter_AddRefs(originalCSP));
// if the principalToInherit had a CSP, if (originalCSP) {
// add it to the newly created NullPrincipal. // if the principalToInherit had a CSP,
if (originalCsp) { // add it to the newly created NullPrincipal
nsresult rv = (*aPrincipal)->SetCsp(originalCsp); // (unless it already has one)
NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIContentSecurityPolicy> nullPrincipalCSP;
(*aPrincipal)->GetCsp(getter_AddRefs(nullPrincipalCSP));
if (nullPrincipalCSP) {
MOZ_ASSERT(nullPrincipalCSP == originalCSP,
"There should be no other CSP here.");
// CSPs are equal, no need to set it again.
return NS_OK;
} else {
nsresult rv = (*aPrincipal)->SetCsp(originalCSP);
NS_ENSURE_SUCCESS(rv, rv);
}
} }
} }
} }

View File

@ -425,7 +425,7 @@ public:
mLoadGroup = aLoadGroup; mLoadGroup = aLoadGroup;
} }
nsresult StartTimeout(Dispatcher* aDispatcher); nsresult StartTimeout(DocGroup* aDocGroup);
private: private:
~nsPingListener(); ~nsPingListener();
@ -445,12 +445,12 @@ nsPingListener::~nsPingListener()
} }
nsresult nsresult
nsPingListener::StartTimeout(Dispatcher* aDispatcher) nsPingListener::StartTimeout(DocGroup* aDocGroup)
{ {
NS_ENSURE_ARG(aDispatcher); NS_ENSURE_ARG(aDocGroup);
nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID); nsCOMPtr<nsITimer> timer = do_CreateInstance(NS_TIMER_CONTRACTID);
timer->SetTarget(aDispatcher->EventTargetFor(TaskCategory::Network)); timer->SetTarget(aDocGroup->EventTargetFor(TaskCategory::Network));
if (timer) { if (timer) {
nsresult rv = timer->InitWithFuncCallback(OnPingTimeout, mLoadGroup, nsresult rv = timer->InitWithFuncCallback(OnPingTimeout, mLoadGroup,

View File

@ -7,7 +7,7 @@
#include "mozilla/dom/DispatcherTrait.h" #include "mozilla/dom/DispatcherTrait.h"
#include "mozilla/AbstractThread.h" #include "mozilla/AbstractThread.h"
#include "mozilla/Dispatcher.h" #include "mozilla/SchedulerGroup.h"
#include "nsINamed.h" #include "nsINamed.h"
using namespace mozilla; using namespace mozilla;
@ -18,7 +18,7 @@ DispatcherTrait::Dispatch(const char* aName,
TaskCategory aCategory, TaskCategory aCategory,
already_AddRefed<nsIRunnable>&& aRunnable) already_AddRefed<nsIRunnable>&& aRunnable)
{ {
return Dispatcher::UnlabeledDispatch(aName, aCategory, Move(aRunnable)); return SchedulerGroup::UnlabeledDispatch(aName, aCategory, Move(aRunnable));
} }
nsIEventTarget* nsIEventTarget*

View File

@ -70,7 +70,7 @@ DocGroup::EventTargetFor(TaskCategory aCategory) const
} }
AbstractThread* AbstractThread*
DocGroup::AbstractMainThreadForImpl(TaskCategory aCategory) DocGroup::AbstractMainThreadFor(TaskCategory aCategory)
{ {
MOZ_RELEASE_ASSERT(NS_IsMainThread()); MOZ_RELEASE_ASSERT(NS_IsMainThread());
return mTabGroup->AbstractMainThreadFor(aCategory); return mTabGroup->AbstractMainThreadFor(aCategory);

View File

@ -13,7 +13,6 @@
#include "nsString.h" #include "nsString.h"
#include "mozilla/dom/TabGroup.h" #include "mozilla/dom/TabGroup.h"
#include "mozilla/Dispatcher.h"
#include "mozilla/RefPtr.h" #include "mozilla/RefPtr.h"
#include "mozilla/dom/CustomElementRegistry.h" #include "mozilla/dom/CustomElementRegistry.h"
@ -36,13 +35,13 @@ namespace dom {
// (through its DocGroups) the documents from one or more tabs related by // (through its DocGroups) the documents from one or more tabs related by
// window.opener. A DocGroup is a member of exactly one TabGroup. // window.opener. A DocGroup is a member of exactly one TabGroup.
class DocGroup final : public Dispatcher class DocGroup final
{ {
public: public:
typedef nsTArray<nsIDocument*>::iterator Iterator; typedef nsTArray<nsIDocument*>::iterator Iterator;
friend class TabGroup; friend class TabGroup;
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DocGroup, override) NS_INLINE_DECL_THREADSAFE_REFCOUNTING(DocGroup)
// Returns NS_ERROR_FAILURE and sets |aString| to an empty string if the TLD // Returns NS_ERROR_FAILURE and sets |aString| to an empty string if the TLD
// service isn't available. Returns NS_OK on success, but may still set // service isn't available. Returns NS_OK on success, but may still set
@ -81,11 +80,14 @@ public:
return mDocuments.end(); return mDocuments.end();
} }
virtual nsresult Dispatch(const char* aName, nsresult Dispatch(const char* aName,
TaskCategory aCategory, TaskCategory aCategory,
already_AddRefed<nsIRunnable>&& aRunnable) override; already_AddRefed<nsIRunnable>&& aRunnable);
virtual nsIEventTarget* EventTargetFor(TaskCategory aCategory) const override; nsIEventTarget* EventTargetFor(TaskCategory aCategory) const;
AbstractThread*
AbstractMainThreadFor(TaskCategory aCategory);
// Ensure that it's valid to access the DocGroup at this time. // Ensure that it's valid to access the DocGroup at this time.
void ValidateAccess() const void ValidateAccess() const
@ -99,9 +101,6 @@ public:
bool* GetValidAccessPtr(); bool* GetValidAccessPtr();
private: private:
virtual AbstractThread*
AbstractMainThreadForImpl(TaskCategory aCategory) override;
DocGroup(TabGroup* aTabGroup, const nsACString& aKey); DocGroup(TabGroup* aTabGroup, const nsACString& aKey);
~DocGroup(); ~DocGroup();

View File

@ -103,10 +103,10 @@ TabGroup::GetFromWindowActor(mozIDOMWindowProxy* aWindow)
// We have an event target. We assume the IPC code created it via // We have an event target. We assume the IPC code created it via
// TabGroup::CreateEventTarget. // TabGroup::CreateEventTarget.
RefPtr<ValidatingDispatcher> dispatcher = RefPtr<SchedulerGroup> group =
ValidatingDispatcher::FromEventTarget(target); SchedulerGroup::FromEventTarget(target);
MOZ_RELEASE_ASSERT(dispatcher); MOZ_RELEASE_ASSERT(group);
auto tabGroup = dispatcher->AsTabGroup(); auto tabGroup = group->AsTabGroup();
MOZ_RELEASE_ASSERT(tabGroup); MOZ_RELEASE_ASSERT(tabGroup);
// We delay creating the event targets until now since the TabGroup // We delay creating the event targets until now since the TabGroup
@ -241,7 +241,7 @@ TabGroup::EventTargetFor(TaskCategory aCategory) const
if (aCategory == TaskCategory::Worker || aCategory == TaskCategory::Timer) { if (aCategory == TaskCategory::Worker || aCategory == TaskCategory::Timer) {
MOZ_RELEASE_ASSERT(mThrottledQueuesInitialized || mIsChrome); MOZ_RELEASE_ASSERT(mThrottledQueuesInitialized || mIsChrome);
} }
return ValidatingDispatcher::EventTargetFor(aCategory); return SchedulerGroup::EventTargetFor(aCategory);
} }
AbstractThread* AbstractThread*
@ -255,7 +255,7 @@ TabGroup::AbstractMainThreadForImpl(TaskCategory aCategory)
return AbstractThread::MainThread(); return AbstractThread::MainThread();
} }
return ValidatingDispatcher::AbstractMainThreadForImpl(aCategory); return SchedulerGroup::AbstractMainThreadForImpl(aCategory);
} }
} // namespace dom } // namespace dom

View File

@ -13,7 +13,7 @@
#include "nsString.h" #include "nsString.h"
#include "mozilla/Atomics.h" #include "mozilla/Atomics.h"
#include "mozilla/Dispatcher.h" #include "mozilla/SchedulerGroup.h"
#include "mozilla/RefPtr.h" #include "mozilla/RefPtr.h"
class mozIDOMWindowProxy; class mozIDOMWindowProxy;
@ -43,7 +43,7 @@ namespace dom {
class DocGroup; class DocGroup;
class TabGroup final : public ValidatingDispatcher class TabGroup final : public SchedulerGroup
{ {
private: private:
class HashEntry : public nsCStringHashKey class HashEntry : public nsCStringHashKey

View File

@ -10172,8 +10172,8 @@ nsContentUtils::HtmlObjectContentTypeForMIMEType(const nsCString& aMIMEType,
return nsIObjectLoadingContent::TYPE_NULL; return nsIObjectLoadingContent::TYPE_NULL;
} }
/* static */ already_AddRefed<Dispatcher> /* static */ already_AddRefed<nsIEventTarget>
nsContentUtils::GetDispatcherByLoadInfo(nsILoadInfo* aLoadInfo) nsContentUtils::GetEventTargetByLoadInfo(nsILoadInfo* aLoadInfo, TaskCategory aCategory)
{ {
if (NS_WARN_IF(!aLoadInfo)) { if (NS_WARN_IF(!aLoadInfo)) {
return nullptr; return nullptr;
@ -10182,9 +10182,11 @@ nsContentUtils::GetDispatcherByLoadInfo(nsILoadInfo* aLoadInfo)
nsCOMPtr<nsIDOMDocument> domDoc; nsCOMPtr<nsIDOMDocument> domDoc;
aLoadInfo->GetLoadingDocument(getter_AddRefs(domDoc)); aLoadInfo->GetLoadingDocument(getter_AddRefs(domDoc));
nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc); nsCOMPtr<nsIDocument> doc = do_QueryInterface(domDoc);
RefPtr<Dispatcher> dispatcher; nsCOMPtr<nsIEventTarget> target;
if (doc) { if (doc) {
dispatcher = doc->GetDocGroup(); if (DocGroup* group = doc->GetDocGroup()) {
target = group->EventTargetFor(aCategory);
}
} else { } else {
// There's no document yet, but this might be a top-level load where we can // There's no document yet, but this might be a top-level load where we can
// find a TabGroup. // find a TabGroup.
@ -10199,8 +10201,8 @@ nsContentUtils::GetDispatcherByLoadInfo(nsILoadInfo* aLoadInfo)
return nullptr; return nullptr;
} }
dispatcher = window->TabGroup(); target = window->TabGroup()->EventTargetFor(aCategory);
} }
return dispatcher.forget(); return target.forget();
} }

View File

@ -22,6 +22,7 @@
#include "js/RootingAPI.h" #include "js/RootingAPI.h"
#include "mozilla/EventForwards.h" #include "mozilla/EventForwards.h"
#include "mozilla/GuardObjects.h" #include "mozilla/GuardObjects.h"
#include "mozilla/TaskCategory.h"
#include "mozilla/TimeStamp.h" #include "mozilla/TimeStamp.h"
#include "nsContentListDeclarations.h" #include "nsContentListDeclarations.h"
#include "nsMathUtils.h" #include "nsMathUtils.h"
@ -66,6 +67,7 @@ class nsIDOMKeyEvent;
class nsIDOMNode; class nsIDOMNode;
class nsIDragSession; class nsIDragSession;
class nsIEditor; class nsIEditor;
class nsIEventTarget;
class nsIFragmentContentSink; class nsIFragmentContentSink;
class nsIFrame; class nsIFrame;
class nsIImageLoadingContent; class nsIImageLoadingContent;
@ -2858,8 +2860,8 @@ public:
HtmlObjectContentTypeForMIMEType(const nsCString& aMIMEType, HtmlObjectContentTypeForMIMEType(const nsCString& aMIMEType,
nsIContent* aContent); nsIContent* aContent);
static already_AddRefed<mozilla::Dispatcher> static already_AddRefed<nsIEventTarget>
GetDispatcherByLoadInfo(nsILoadInfo* aLoadInfo); GetEventTargetByLoadInfo(nsILoadInfo* aLoadInfo, mozilla::TaskCategory aCategory);
private: private:
static bool InitializeEventTable(); static bool InitializeEventTable();

View File

@ -448,7 +448,7 @@ class CGDOMJSClass(CGThing):
classFlags += "JSCLASS_HAS_RESERVED_SLOTS(%d)" % slotCount classFlags += "JSCLASS_HAS_RESERVED_SLOTS(%d)" % slotCount
traceHook = 'nullptr' traceHook = 'nullptr'
reservedSlots = slotCount reservedSlots = slotCount
if self.descriptor.interface.isProbablyShortLivingObject(): if self.descriptor.interface.hasProbablyShortLivingWrapper():
classFlags += " | JSCLASS_SKIP_NURSERY_FINALIZE" classFlags += " | JSCLASS_SKIP_NURSERY_FINALIZE"
if self.descriptor.interface.getExtendedAttribute("NeedResolve"): if self.descriptor.interface.getExtendedAttribute("NeedResolve"):
resolveHook = RESOLVE_HOOK_NAME resolveHook = RESOLVE_HOOK_NAME

View File

@ -584,7 +584,7 @@ class IDLExternalInterface(IDLObjectWithIdentifier, IDLExposureMixins):
def isJSImplemented(self): def isJSImplemented(self):
return False return False
def isProbablyShortLivingObject(self): def hasProbablyShortLivingWrapper(self):
return False return False
def isNavigatorProperty(self): def isNavigatorProperty(self):
@ -1498,10 +1498,10 @@ class IDLInterfaceOrNamespace(IDLObjectWithScope, IDLExposureMixins):
def isJSImplemented(self): def isJSImplemented(self):
return bool(self.getJSImplementation()) return bool(self.getJSImplementation())
def isProbablyShortLivingObject(self): def hasProbablyShortLivingWrapper(self):
current = self current = self
while current: while current:
if current.getExtendedAttribute("ProbablyShortLivingObject"): if current.getExtendedAttribute("ProbablyShortLivingWrapper"):
return True return True
current = current.parent current = current.parent
return False return False
@ -1725,7 +1725,7 @@ class IDLInterface(IDLInterfaceOrNamespace):
identifier == "Unforgeable" or identifier == "Unforgeable" or
identifier == "UnsafeInPrerendering" or identifier == "UnsafeInPrerendering" or
identifier == "LegacyEventInit" or identifier == "LegacyEventInit" or
identifier == "ProbablyShortLivingObject" or identifier == "ProbablyShortLivingWrapper" or
identifier == "LegacyUnenumerableNamedProperties" or identifier == "LegacyUnenumerableNamedProperties" or
identifier == "NonOrdinaryGetPrototypeOf"): identifier == "NonOrdinaryGetPrototypeOf"):
# Known extended attributes that do not take values # Known extended attributes that do not take values

View File

@ -2089,7 +2089,7 @@ mozilla::ipc::IPCResult
ContentChild::RecvDataStoragePut(const nsString& aFilename, ContentChild::RecvDataStoragePut(const nsString& aFilename,
const DataStorageItem& aItem) const DataStorageItem& aItem)
{ {
RefPtr<DataStorage> storage = DataStorage::GetIfExists(aFilename); RefPtr<DataStorage> storage = DataStorage::GetFromRawFileName(aFilename);
if (storage) { if (storage) {
storage->Put(aItem.key(), aItem.value(), aItem.type()); storage->Put(aItem.key(), aItem.value(), aItem.type());
} }
@ -2101,7 +2101,7 @@ ContentChild::RecvDataStorageRemove(const nsString& aFilename,
const nsCString& aKey, const nsCString& aKey,
const DataStorageType& aType) const DataStorageType& aType)
{ {
RefPtr<DataStorage> storage = DataStorage::GetIfExists(aFilename); RefPtr<DataStorage> storage = DataStorage::GetFromRawFileName(aFilename);
if (storage) { if (storage) {
storage->Remove(aKey, aType); storage->Remove(aKey, aType);
} }
@ -2111,7 +2111,7 @@ ContentChild::RecvDataStorageRemove(const nsString& aFilename,
mozilla::ipc::IPCResult mozilla::ipc::IPCResult
ContentChild::RecvDataStorageClear(const nsString& aFilename) ContentChild::RecvDataStorageClear(const nsString& aFilename)
{ {
RefPtr<DataStorage> storage = DataStorage::GetIfExists(aFilename); RefPtr<DataStorage> storage = DataStorage::GetFromRawFileName(aFilename);
if (storage) { if (storage) {
storage->Clear(); storage->Clear();
} }

View File

@ -2236,18 +2236,8 @@ ContentParent::InitInternal(ProcessPriority aInitialPriority,
} }
} }
// Ensure the SSS is initialized before we try to use its storage. DataStorage::GetAllChildProcessData(xpcomInit.dataStorage());
nsCOMPtr<nsISiteSecurityService> sss = do_GetService("@mozilla.org/ssservice;1");
nsTArray<nsString> storageFiles;
DataStorage::GetAllFileNames(storageFiles);
for (auto& file : storageFiles) {
dom::DataStorageEntry entry;
entry.filename() = file;
RefPtr<DataStorage> storage = DataStorage::Get(file);
storage->GetAll(&entry.items());
xpcomInit.dataStorage().AppendElement(Move(entry));
}
// Must send screen info before send initialData // Must send screen info before send initialData
ScreenManager& screenManager = ScreenManager::GetSingleton(); ScreenManager& screenManager = ScreenManager::GetSingleton();
screenManager.CopyScreensToRemote(this); screenManager.CopyScreensToRemote(this);

View File

@ -2909,10 +2909,6 @@ PluginInstanceChild::NPN_FinalizeAsyncSurface(NPAsyncSurface *surface)
return NPERR_GENERIC_ERROR; return NPERR_GENERIC_ERROR;
} }
// The API forbids this. If it becomes a problem we can revoke the current
// surface instead.
MOZ_ASSERT(!surface || mCurrentDirectSurface != surface);
switch (mDrawingModel) { switch (mDrawingModel) {
case NPDrawingModelAsyncBitmapSurface: { case NPDrawingModelAsyncBitmapSurface: {
RefPtr<DirectBitmap> bitmap; RefPtr<DirectBitmap> bitmap;

View File

@ -108,6 +108,11 @@ PushNotifier::Dispatch(PushDispatcher& aDispatcher)
// At least one content process is active, so e10s must be enabled. // At least one content process is active, so e10s must be enabled.
// Broadcast a message to notify observers and service workers. // Broadcast a message to notify observers and service workers.
for (uint32_t i = 0; i < contentActors.Length(); ++i) { for (uint32_t i = 0; i < contentActors.Length(); ++i) {
// Ensure that the content actor has the permissions avaliable for the
// principal the push is being sent for before sending the push message
// down.
Unused << contentActors[i]->
TransmitPermissionsForPrincipal(aDispatcher.GetPrincipal());
if (aDispatcher.SendToChild(contentActors[i])) { if (aDispatcher.SendToChild(contentActors[i])) {
// Only send the push message to the first content process to avoid // Only send the push message to the first content process to avoid
// multiple SWs showing the same notification. See bug 1300112. // multiple SWs showing the same notification. See bug 1300112.

View File

@ -51,6 +51,10 @@ public:
// are no active content processes. The default behavior is a no-op. // are no active content processes. The default behavior is a no-op.
virtual nsresult HandleNoChildProcesses(); virtual nsresult HandleNoChildProcesses();
nsIPrincipal* GetPrincipal() {
return mPrincipal;
}
protected: protected:
PushDispatcher(const nsACString& aScope, PushDispatcher(const nsACString& aScope,
nsIPrincipal* aPrincipal); nsIPrincipal* aPrincipal);

View File

@ -20,6 +20,7 @@ interface DOMRect : DOMRectReadOnly {
inherit attribute unrestricted double height; inherit attribute unrestricted double height;
}; };
[ProbablyShortLivingWrapper]
interface DOMRectReadOnly { interface DOMRectReadOnly {
readonly attribute unrestricted double x; readonly attribute unrestricted double x;
readonly attribute unrestricted double y; readonly attribute unrestricted double y;

View File

@ -11,7 +11,7 @@
*/ */
[Constructor(DOMString type, optional EventInit eventInitDict), [Constructor(DOMString type, optional EventInit eventInitDict),
Exposed=(Window,Worker,System), ProbablyShortLivingObject] Exposed=(Window,Worker,System), ProbablyShortLivingWrapper]
interface Event { interface Event {
[Pure] [Pure]
readonly attribute DOMString type; readonly attribute DOMString type;

View File

@ -7,7 +7,7 @@
* https://wicg.github.io/IntersectionObserver/ * https://wicg.github.io/IntersectionObserver/
*/ */
[ProbablyShortLivingObject, Pref="dom.IntersectionObserver.enabled"] [ProbablyShortLivingWrapper, Pref="dom.IntersectionObserver.enabled"]
interface IntersectionObserverEntry { interface IntersectionObserverEntry {
[Constant] [Constant]
readonly attribute DOMHighResTimeStamp time; readonly attribute DOMHighResTimeStamp time;

View File

@ -7,7 +7,7 @@
* http://dom.spec.whatwg.org * http://dom.spec.whatwg.org
*/ */
[ProbablyShortLivingObject] [ProbablyShortLivingWrapper]
interface MutationRecord { interface MutationRecord {
[Constant] [Constant]
readonly attribute DOMString type; readonly attribute DOMString type;

View File

@ -380,11 +380,6 @@ public:
return RejectPromise(NS_ERROR_TYPE_ERR); return RejectPromise(NS_ERROR_TYPE_ERR);
} }
rv = principal->CheckMayLoad(url, true, false);
if (NS_WARN_IF(NS_FAILED(rv))) {
return RejectPromise(rv);
}
nsGlobalWindow* window; nsGlobalWindow* window;
rv = Navigate(url, principal, &window); rv = Navigate(url, principal, &window);
if (NS_WARN_IF(NS_FAILED(rv))) { if (NS_WARN_IF(NS_FAILED(rv))) {
@ -499,19 +494,18 @@ private:
nsCOMPtr<nsIDocShellLoadInfo> loadInfo; nsCOMPtr<nsIDocShellLoadInfo> loadInfo;
nsresult rv = docShell->CreateLoadInfo(getter_AddRefs(loadInfo)); nsresult rv = docShell->CreateLoadInfo(getter_AddRefs(loadInfo));
if (NS_WARN_IF(NS_FAILED(rv))) { if (NS_WARN_IF(NS_FAILED(rv))) {
return rv; return NS_ERROR_TYPE_ERR;
} }
loadInfo->SetTriggeringPrincipal(aPrincipal); loadInfo->SetTriggeringPrincipal(aPrincipal);
loadInfo->SetReferrer(doc->GetOriginalURI());
loadInfo->SetReferrerPolicy(doc->GetReferrerPolicy()); loadInfo->SetReferrerPolicy(doc->GetReferrerPolicy());
loadInfo->SetLoadType(nsIDocShellLoadInfo::loadStopContentAndReplace); loadInfo->SetLoadType(nsIDocShellLoadInfo::loadStopContent);
loadInfo->SetSourceDocShell(docShell); loadInfo->SetSourceDocShell(docShell);
rv = rv =
docShell->LoadURI(aUrl, loadInfo, nsIWebNavigation::LOAD_FLAGS_NONE, true); docShell->LoadURI(aUrl, loadInfo, nsIWebNavigation::LOAD_FLAGS_NONE, true);
if (NS_WARN_IF(NS_FAILED(rv))) { if (NS_WARN_IF(NS_FAILED(rv))) {
return rv; return NS_ERROR_TYPE_ERR;
} }
*aWindow = window; *aWindow = window;

View File

@ -10,9 +10,14 @@
#include "txNodeSetContext.h" #include "txNodeSetContext.h"
#include "txExpr.h" #include "txExpr.h"
#include "txStringUtils.h" #include "txStringUtils.h"
#include "prmem.h"
#include "nsQuickSort.h" #include "nsQuickSort.h"
#include "mozilla/CheckedInt.h"
#include "mozilla/UniquePtrExtensions.h"
using mozilla::CheckedUint32;
using mozilla::MakeUniqueFallible;
/* /*
* Sorts Nodes as specified by the W3C XSLT 1.0 Recommendation * Sorts Nodes as specified by the W3C XSLT 1.0 Recommendation
*/ */
@ -122,7 +127,8 @@ txNodeSorter::sortNodeSet(txNodeSet* aNodes, txExecutionState* aEs,
txNodeSet** aResult) txNodeSet** aResult)
{ {
if (mNKeys == 0 || aNodes->isEmpty()) { if (mNKeys == 0 || aNodes->isEmpty()) {
NS_ADDREF(*aResult = aNodes); RefPtr<txNodeSet> ref(aNodes);
ref.forget(aResult);
return NS_OK; return NS_OK;
} }
@ -140,62 +146,56 @@ txNodeSorter::sortNodeSet(txNodeSet* aNodes, txExecutionState* aEs,
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
// Create and set up memoryblock for sort-values and indexarray // Create and set up memoryblock for sort-values and indexarray
uint32_t len = static_cast<uint32_t>(aNodes->size()); CheckedUint32 len = aNodes->size();
CheckedUint32 numSortValues = len * mNKeys;
// Limit resource use to something sane. CheckedUint32 sortValuesSize = numSortValues * sizeof(txObject*);
uint32_t itemSize = sizeof(uint32_t) + mNKeys * sizeof(txObject*); if (!sortValuesSize.isValid()) {
if (mNKeys > (UINT32_MAX - sizeof(uint32_t)) / sizeof(txObject*) ||
len >= UINT32_MAX / itemSize) {
return NS_ERROR_OUT_OF_MEMORY; return NS_ERROR_OUT_OF_MEMORY;
} }
void* mem = PR_Malloc(len * itemSize); auto indexes = MakeUniqueFallible<uint32_t[]>(len.value());
NS_ENSURE_TRUE(mem, NS_ERROR_OUT_OF_MEMORY); auto sortValues = MakeUniqueFallible<txObject*[]>(numSortValues.value());
if (!indexes || !sortValues) {
uint32_t* indexes = static_cast<uint32_t*>(mem); return NS_ERROR_OUT_OF_MEMORY;
txObject** sortValues = reinterpret_cast<txObject**>(indexes + len); }
uint32_t i; uint32_t i;
for (i = 0; i < len; ++i) { for (i = 0; i < len.value(); ++i) {
indexes[i] = i; indexes[i] = i;
} }
memset(sortValues, 0, len * mNKeys * sizeof(txObject*)); memset(sortValues.get(), 0, sortValuesSize.value());
// Sort the indexarray // Sort the indexarray
SortData sortData; SortData sortData;
sortData.mNodeSorter = this; sortData.mNodeSorter = this;
sortData.mContext = evalContext; sortData.mContext = evalContext;
sortData.mSortValues = sortValues; sortData.mSortValues = sortValues.get();
sortData.mRv = NS_OK; sortData.mRv = NS_OK;
NS_QuickSort(indexes, len, sizeof(uint32_t), compareNodes, &sortData); NS_QuickSort(indexes.get(), len.value(), sizeof(uint32_t), compareNodes, &sortData);
// Delete these here so we don't have to deal with them at every possible // Delete these here so we don't have to deal with them at every possible
// failurepoint // failurepoint
uint32_t numSortValues = len * mNKeys; for (i = 0; i < numSortValues.value(); ++i) {
for (i = 0; i < numSortValues; ++i) {
delete sortValues[i]; delete sortValues[i];
} }
if (NS_FAILED(sortData.mRv)) { if (NS_FAILED(sortData.mRv)) {
PR_Free(mem);
// The txExecutionState owns the evalcontext so no need to handle it // The txExecutionState owns the evalcontext so no need to handle it
return sortData.mRv; return sortData.mRv;
} }
// Insert nodes in sorted order in new nodeset // Insert nodes in sorted order in new nodeset
for (i = 0; i < len; ++i) { for (i = 0; i < len.value(); ++i) {
rv = sortedNodes->append(aNodes->get(indexes[i])); rv = sortedNodes->append(aNodes->get(indexes[i]));
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
PR_Free(mem);
// The txExecutionState owns the evalcontext so no need to handle it // The txExecutionState owns the evalcontext so no need to handle it
return rv; return rv;
} }
} }
PR_Free(mem);
delete aEs->popEvalContext(); delete aEs->popEvalContext();
NS_ADDREF(*aResult = sortedNodes); sortedNodes.forget(aResult);
return NS_OK; return NS_OK;
} }

View File

@ -6,6 +6,7 @@
#include "mozilla/layers/Compositor.h" #include "mozilla/layers/Compositor.h"
#include "base/message_loop.h" // for MessageLoop #include "base/message_loop.h" // for MessageLoop
#include "mozilla/layers/CompositorBridgeParent.h" // for CompositorBridgeParent #include "mozilla/layers/CompositorBridgeParent.h" // for CompositorBridgeParent
#include "mozilla/layers/Diagnostics.h"
#include "mozilla/layers/Effects.h" // for Effect, EffectChain, etc #include "mozilla/layers/Effects.h" // for Effect, EffectChain, etc
#include "mozilla/layers/TextureClient.h" #include "mozilla/layers/TextureClient.h"
#include "mozilla/layers/TextureHost.h" #include "mozilla/layers/TextureHost.h"
@ -639,5 +640,12 @@ Compositor::NotifyNotUsedAfterComposition(TextureHost* aTextureHost)
return TextureSourceProvider::NotifyNotUsedAfterComposition(aTextureHost); return TextureSourceProvider::NotifyNotUsedAfterComposition(aTextureHost);
} }
void
Compositor::GetFrameStats(GPUStats* aStats)
{
aStats->mInvalidPixels = mPixelsPerFrame;
aStats->mPixelsFilled = mPixelsFilled;
}
} // namespace layers } // namespace layers
} // namespace mozilla } // namespace mozilla

View File

@ -134,6 +134,7 @@ class CompositorOGL;
class CompositorD3D11; class CompositorD3D11;
class BasicCompositor; class BasicCompositor;
class TextureReadLock; class TextureReadLock;
struct GPUStats;
enum SurfaceInitMode enum SurfaceInitMode
{ {
@ -404,6 +405,12 @@ public:
gfx::IntRect* aClipRectOut = nullptr, gfx::IntRect* aClipRectOut = nullptr,
gfx::IntRect* aRenderBoundsOut = nullptr) = 0; gfx::IntRect* aRenderBoundsOut = nullptr) = 0;
/**
* Notification that we've finished issuing draw commands for normal
* layers (as opposed to the diagnostic overlay which comes after).
*/
virtual void NormalDrawingDone() {}
/** /**
* Flush the current frame to the screen and tidy up. * Flush the current frame to the screen and tidy up.
* *
@ -512,16 +519,8 @@ public:
*/ */
static void AssertOnCompositorThread(); static void AssertOnCompositorThread();
size_t GetFillRatio() { // Return statistics for the most recent frame we computed statistics for.
float fillRatio = 0; virtual void GetFrameStats(GPUStats* aStats);
if (mPixelsFilled > 0 && mPixelsPerFrame > 0) {
fillRatio = 100.0f * float(mPixelsFilled) / float(mPixelsPerFrame);
if (fillRatio > 999.0f) {
fillRatio = 999.0f;
}
}
return fillRatio;
}
ScreenRotation GetScreenRotation() const { ScreenRotation GetScreenRotation() const {
return mScreenRotation; return mScreenRotation;

View File

@ -1150,17 +1150,19 @@ nsEventStatus AsyncPanZoomController::OnTouchMove(const MultiTouchInput& aEvent)
return nsEventStatus_eIgnore; return nsEventStatus_eIgnore;
} }
ParentLayerPoint touchPoint = GetFirstTouchPoint(aEvent);
MOZ_ASSERT(GetCurrentTouchBlock()); MOZ_ASSERT(GetCurrentTouchBlock());
if (gfxPrefs::TouchActionEnabled() && GetCurrentTouchBlock()->TouchActionAllowsPanningXY()) { if (gfxPrefs::TouchActionEnabled() && GetCurrentTouchBlock()->TouchActionAllowsPanningXY()) {
// User tries to trigger a touch behavior. If allowed touch behavior is vertical pan // User tries to trigger a touch behavior. If allowed touch behavior is vertical pan
// + horizontal pan (touch-action value is equal to AUTO) we can return ConsumeNoDefault // + horizontal pan (touch-action value is equal to AUTO) we can return ConsumeNoDefault
// status immediately to trigger cancel event further. It should happen independent of // status immediately to trigger cancel event further. It should happen independent of
// the parent type (whether it is scrolling or not). // the parent type (whether it is scrolling or not).
StartPanning(aEvent); StartPanning(touchPoint);
return nsEventStatus_eConsumeNoDefault; return nsEventStatus_eConsumeNoDefault;
} }
return StartPanning(aEvent); return StartPanning(touchPoint);
} }
case PANNING: case PANNING:
@ -1251,43 +1253,9 @@ nsEventStatus AsyncPanZoomController::OnTouchEnd(const MultiTouchInput& aEvent)
case PAN_MOMENTUM: case PAN_MOMENTUM:
{ {
MOZ_ASSERT(GetCurrentTouchBlock()); MOZ_ASSERT(GetCurrentTouchBlock());
GetCurrentTouchBlock()->GetOverscrollHandoffChain()->FlushRepaints();
mX.EndTouch(aEvent.mTime); mX.EndTouch(aEvent.mTime);
mY.EndTouch(aEvent.mTime); mY.EndTouch(aEvent.mTime);
ParentLayerPoint flingVelocity = GetVelocityVector(); return HandleEndOfPan();
// Clear our velocities; if DispatchFling() gives the fling to us,
// the fling velocity gets *added* to our existing velocity in
// AcceptFling().
mX.SetVelocity(0);
mY.SetVelocity(0);
// Clear our state so that we don't stay in the PANNING state
// if DispatchFling() gives the fling to somone else. However,
// don't send the state change notification until we've determined
// what our final state is to avoid notification churn.
StateChangeNotificationBlocker blocker(this);
SetState(NOTHING);
APZC_LOG("%p starting a fling animation if %f >= %f\n", this,
flingVelocity.Length().value, gfxPrefs::APZFlingMinVelocityThreshold());
if (flingVelocity.Length() < gfxPrefs::APZFlingMinVelocityThreshold()) {
// Relieve overscroll now if needed, since we will not transition to a fling
// animation and then an overscroll animation, and relieve it then.
GetCurrentTouchBlock()->GetOverscrollHandoffChain()->SnapBackOverscrolledApzc(this);
return nsEventStatus_eConsumeNoDefault;
}
// Make a local copy of the tree manager pointer and check that it's not
// null before calling DispatchFling(). This is necessary because Destroy(),
// which nulls out mTreeManager, could be called concurrently.
if (APZCTreeManager* treeManagerLocal = GetApzcTreeManager()) {
FlingHandoffState handoffState{flingVelocity,
GetCurrentTouchBlock()->GetOverscrollHandoffChain(),
false /* not handoff */,
GetCurrentTouchBlock()->GetScrolledApzc()};
treeManagerLocal->DispatchFling(this, handoffState);
}
return nsEventStatus_eConsumeNoDefault;
} }
case PINCHING: case PINCHING:
SetState(NOTHING); SetState(NOTHING);
@ -1318,6 +1286,8 @@ nsEventStatus AsyncPanZoomController::OnScaleBegin(const PinchGestureInput& aEve
APZC_LOG("%p got a scale-begin in state %d\n", this, mState); APZC_LOG("%p got a scale-begin in state %d\n", this, mState);
mPinchPaintTimerSet = false; mPinchPaintTimerSet = false;
mX.StartTouch(aEvent.mLocalFocusPoint.x, aEvent.mTime);
mY.StartTouch(aEvent.mLocalFocusPoint.y, aEvent.mTime);
// Note that there may not be a touch block at this point, if we received the // Note that there may not be a touch block at this point, if we received the
// PinchGestureEvent directly from widget code without any touch events. // PinchGestureEvent directly from widget code without any touch events.
if (HasReadyTouchBlock() && !GetCurrentTouchBlock()->TouchActionAllowsPinchZoom()) { if (HasReadyTouchBlock() && !GetCurrentTouchBlock()->TouchActionAllowsPinchZoom()) {
@ -1342,6 +1312,8 @@ nsEventStatus AsyncPanZoomController::OnScaleBegin(const PinchGestureInput& aEve
nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) { nsEventStatus AsyncPanZoomController::OnScale(const PinchGestureInput& aEvent) {
APZC_LOG("%p got a scale in state %d\n", this, mState); APZC_LOG("%p got a scale in state %d\n", this, mState);
mX.UpdateWithTouchAtDevicePoint(aEvent.mLocalFocusPoint.x, 0, aEvent.mTime);
mY.UpdateWithTouchAtDevicePoint(aEvent.mLocalFocusPoint.y, 0, aEvent.mTime);
if (HasReadyTouchBlock() && !GetCurrentTouchBlock()->TouchActionAllowsPinchZoom()) { if (HasReadyTouchBlock() && !GetCurrentTouchBlock()->TouchActionAllowsPinchZoom()) {
return nsEventStatus_eIgnore; return nsEventStatus_eIgnore;
@ -1477,8 +1449,6 @@ nsEventStatus AsyncPanZoomController::OnScaleEnd(const PinchGestureInput& aEvent
} }
} }
SetState(NOTHING);
{ {
ReentrantMonitorAutoEnter lock(mMonitor); ReentrantMonitorAutoEnter lock(mMonitor);
ScheduleComposite(); ScheduleComposite();
@ -1488,32 +1458,86 @@ nsEventStatus AsyncPanZoomController::OnScaleEnd(const PinchGestureInput& aEvent
// Non-negative focus point would indicate that one finger is still down // Non-negative focus point would indicate that one finger is still down
if (aEvent.mLocalFocusPoint.x != -1 && aEvent.mLocalFocusPoint.y != -1) { if (aEvent.mLocalFocusPoint.x != -1 && aEvent.mLocalFocusPoint.y != -1) {
mPanDirRestricted = false; if (mZoomConstraints.mAllowZoom) {
mX.StartTouch(aEvent.mLocalFocusPoint.x, aEvent.mTime); mPanDirRestricted = false;
mY.StartTouch(aEvent.mLocalFocusPoint.y, aEvent.mTime); SetState(TOUCHING);
SetState(TOUCHING); } else {
StartPanning(aEvent.mLocalFocusPoint);
}
} else { } else {
// Otherwise, handle the fingers being lifted. // Otherwise, handle the fingers being lifted.
ReentrantMonitorAutoEnter lock(mMonitor); mX.EndTouch(aEvent.mTime);
mY.EndTouch(aEvent.mTime);
if (mZoomConstraints.mAllowZoom) {
ReentrantMonitorAutoEnter lock(mMonitor);
// We can get into a situation where we are overscrolled at the end of a // We can get into a situation where we are overscrolled at the end of a
// pinch if we go into overscroll with a two-finger pan, and then turn // pinch if we go into overscroll with a two-finger pan, and then turn
// that into a pinch by increasing the span sufficiently. In such a case, // that into a pinch by increasing the span sufficiently. In such a case,
// there is no snap-back animation to get us out of overscroll, so we need // there is no snap-back animation to get us out of overscroll, so we need
// to get out of it somehow. // to get out of it somehow.
// Moreover, in cases of scroll handoff, the overscroll can be on an APZC // Moreover, in cases of scroll handoff, the overscroll can be on an APZC
// further up in the handoff chain rather than on the current APZC, so // further up in the handoff chain rather than on the current APZC, so
// we need to clear overscroll along the entire handoff chain. // we need to clear overscroll along the entire handoff chain.
if (HasReadyTouchBlock()) { if (HasReadyTouchBlock()) {
GetCurrentTouchBlock()->GetOverscrollHandoffChain()->ClearOverscroll(); GetCurrentTouchBlock()->GetOverscrollHandoffChain()->ClearOverscroll();
} else {
ClearOverscroll();
}
// Along with clearing the overscroll, we also want to snap to the nearest
// snap point as appropriate.
ScrollSnap();
} else { } else {
ClearOverscroll(); // when zoom is not allowed
if (mState == PINCHING) {
// still pinching
if (HasReadyTouchBlock()) {
return HandleEndOfPan();
}
}
} }
// Along with clearing the overscroll, we also want to snap to the nearest }
// snap point as appropriate. return nsEventStatus_eConsumeNoDefault;
ScrollSnap(); }
nsEventStatus AsyncPanZoomController::HandleEndOfPan()
{
MOZ_ASSERT(GetCurrentTouchBlock());
GetCurrentTouchBlock()->GetOverscrollHandoffChain()->FlushRepaints();
ParentLayerPoint flingVelocity = GetVelocityVector();
// Clear our velocities; if DispatchFling() gives the fling to us,
// the fling velocity gets *added* to our existing velocity in
// AcceptFling().
mX.SetVelocity(0);
mY.SetVelocity(0);
// Clear our state so that we don't stay in the PANNING state
// if DispatchFling() gives the fling to somone else. However,
// don't send the state change notification until we've determined
// what our final state is to avoid notification churn.
StateChangeNotificationBlocker blocker(this);
SetState(NOTHING);
APZC_LOG("%p starting a fling animation if %f >= %f\n", this,
flingVelocity.Length().value, gfxPrefs::APZFlingMinVelocityThreshold());
if (flingVelocity.Length() < gfxPrefs::APZFlingMinVelocityThreshold()) {
// Relieve overscroll now if needed, since we will not transition to a fling
// animation and then an overscroll animation, and relieve it then.
GetCurrentTouchBlock()->GetOverscrollHandoffChain()->SnapBackOverscrolledApzc(this);
return nsEventStatus_eConsumeNoDefault;
} }
// Make a local copy of the tree manager pointer and check that it's not
// null before calling DispatchFling(). This is necessary because Destroy(),
// which nulls out mTreeManager, could be called concurrently.
if (APZCTreeManager* treeManagerLocal = GetApzcTreeManager()) {
FlingHandoffState handoffState{flingVelocity,
GetCurrentTouchBlock()->GetOverscrollHandoffChain(),
false /* not handoff */,
GetCurrentTouchBlock()->GetScrolledApzc()};
treeManagerLocal->DispatchFling(this, handoffState);
}
return nsEventStatus_eConsumeNoDefault; return nsEventStatus_eConsumeNoDefault;
} }
@ -2324,12 +2348,12 @@ void AsyncPanZoomController::HandlePanningUpdate(const ScreenPoint& aPanDistance
} }
} }
nsEventStatus AsyncPanZoomController::StartPanning(const MultiTouchInput& aEvent) { nsEventStatus
AsyncPanZoomController::StartPanning(const ParentLayerPoint& aStartPoint) {
ReentrantMonitorAutoEnter lock(mMonitor); ReentrantMonitorAutoEnter lock(mMonitor);
ParentLayerPoint point = GetFirstTouchPoint(aEvent); float dx = mX.PanDistance(aStartPoint.x);
float dx = mX.PanDistance(point.x); float dy = mY.PanDistance(aStartPoint.y);
float dy = mY.PanDistance(point.y);
double angle = atan2(dy, dx); // range [-pi, pi] double angle = atan2(dy, dx); // range [-pi, pi]
angle = fabs(angle); // range [0, pi] angle = fabs(angle); // range [0, pi]

View File

@ -457,6 +457,7 @@ protected:
nsEventStatus OnPanEnd(const PanGestureInput& aEvent); nsEventStatus OnPanEnd(const PanGestureInput& aEvent);
nsEventStatus OnPanMomentumStart(const PanGestureInput& aEvent); nsEventStatus OnPanMomentumStart(const PanGestureInput& aEvent);
nsEventStatus OnPanMomentumEnd(const PanGestureInput& aEvent); nsEventStatus OnPanMomentumEnd(const PanGestureInput& aEvent);
nsEventStatus HandleEndOfPan();
/** /**
* Helper methods for handling scroll wheel events. * Helper methods for handling scroll wheel events.
@ -576,7 +577,7 @@ protected:
* Sets up anything needed for panning. This takes us out of the "TOUCHING" * Sets up anything needed for panning. This takes us out of the "TOUCHING"
* state and starts actually panning us. * state and starts actually panning us.
*/ */
nsEventStatus StartPanning(const MultiTouchInput& aStartPoint); nsEventStatus StartPanning(const ParentLayerPoint& aStartPoint);
/** /**
* Wrapper for Axis::UpdateWithTouchAtDevicePoint(). Calls this function for * Wrapper for Axis::UpdateWithTouchAtDevicePoint(). Calls this function for

View File

@ -138,7 +138,7 @@ PinchWithPinchInput(const RefPtr<InputReceiver>& aTarget,
CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_END, CreatePinchGestureInput(PinchGestureInput::PINCHGESTURE_END,
// note: negative values here tell APZC // note: negative values here tell APZC
// not to turn the pinch into a pan // not to turn the pinch into a pan
aFocus, -1.0, -1.0), ScreenIntPoint(-1, -1), 10.0 * aScale, 10.0 * aScale),
nullptr); nullptr);
if (aOutEventStatuses) { if (aOutEventStatuses) {
(*aOutEventStatuses)[2] = actualStatus; (*aOutEventStatuses)[2] = actualStatus;

View File

@ -316,6 +316,11 @@ ClientLayerManager::EndTransactionInternal(DrawPaintedLayerCallback aCallback,
PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::Rasterization); PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::Rasterization);
GeckoProfilerTracingRAII tracer("Paint", "Rasterize"); GeckoProfilerTracingRAII tracer("Paint", "Rasterize");
Maybe<TimeStamp> startTime;
if (gfxPrefs::LayersDrawFPS()) {
startTime = Some(TimeStamp::Now());
}
#ifdef WIN32 #ifdef WIN32
if (aCallbackData) { if (aCallbackData) {
// Content processes don't get OnPaint called. So update here whenever we // Content processes don't get OnPaint called. So update here whenever we
@ -384,6 +389,11 @@ ClientLayerManager::EndTransactionInternal(DrawPaintedLayerCallback aCallback,
FrameLayerBuilder::InvalidateAllLayers(this); FrameLayerBuilder::InvalidateAllLayers(this);
} }
if (startTime) {
PaintTiming& pt = mForwarder->GetPaintTiming();
pt.rasterMs() = (TimeStamp::Now() - startTime.value()).ToMilliseconds();
}
return !mTransactionIncomplete; return !mTransactionIncomplete;
} }

View File

@ -240,6 +240,16 @@ public:
virtual already_AddRefed<PersistentBufferProvider> virtual already_AddRefed<PersistentBufferProvider>
CreatePersistentBufferProvider(const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat) override; CreatePersistentBufferProvider(const gfx::IntSize& aSize, gfx::SurfaceFormat aFormat) override;
static PaintTiming* MaybeGetPaintTiming(LayerManager* aManager) {
if (!aManager) {
return nullptr;
}
if (ClientLayerManager* lm = aManager->AsClientLayerManager()) {
return &lm->AsShadowForwarder()->GetPaintTiming();
}
return nullptr;
}
protected: protected:
enum TransactionPhase { enum TransactionPhase {
PHASE_NONE, PHASE_CONSTRUCTION, PHASE_DRAWING, PHASE_FORWARD PHASE_NONE, PHASE_CONSTRUCTION, PHASE_DRAWING, PHASE_FORWARD

File diff suppressed because one or more lines are too long

View File

@ -72,9 +72,12 @@ DrawLayerInfo(const RenderTargetIntRect& aClipRect,
uint32_t maxWidth = std::min<uint32_t>(visibleRegion.GetBounds().width, 500); uint32_t maxWidth = std::min<uint32_t>(visibleRegion.GetBounds().width, 500);
IntPoint topLeft = visibleRegion.ToUnknownRegion().GetBounds().TopLeft(); IntPoint topLeft = visibleRegion.ToUnknownRegion().GetBounds().TopLeft();
aManager->GetTextRenderer()->RenderText(ss.str().c_str(), topLeft, aManager->GetTextRenderer()->RenderText(
aLayer->GetEffectiveTransform(), 16, aManager->GetCompositor(),
maxWidth); ss.str().c_str(),
topLeft,
aLayer->GetEffectiveTransform(), 16,
maxWidth);
} }
static void static void

View File

@ -0,0 +1,106 @@
/* -*- Mode: C++; tab-width: 20; 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/. */
#include "Diagnostics.h"
#include "mozilla/layers/LayersMessages.h"
#include "nsPrintfCString.h"
namespace mozilla {
namespace layers {
float
TimedMetric::Average() const
{
// We take at most 2 seconds of history.
TimeStamp latest = TimeStamp::Now();
float total = 0.0f;
size_t count = 0;
for (auto iter = mHistory.rbegin(); iter != mHistory.rend(); iter++) {
if ((latest - iter->second).ToSeconds() > 2.0f) {
break;
}
total += iter->first;
count++;
}
if (!count) {
return 0.0f;
}
return total / float(count);
}
Diagnostics::Diagnostics()
: mCompositeFps("Compositor"),
mTransactionFps("LayerTransactions")
{
}
void
Diagnostics::RecordPaintTimes(const PaintTiming& aPaintTimes)
{
mDlbMs.Add(aPaintTimes.dlMs());
mFlbMs.Add(aPaintTimes.flbMs());
mRasterMs.Add(aPaintTimes.rasterMs());
mSerializeMs.Add(aPaintTimes.serializeMs());
mSendMs.Add(aPaintTimes.sendMs());
}
std::string
Diagnostics::GetFrameOverlayString(const GPUStats& aStats)
{
TimeStamp now = TimeStamp::Now();
unsigned fps = unsigned(mCompositeFps.AddFrameAndGetFps(now));
unsigned txnFps = unsigned(mTransactionFps.GetFPS(now));
float pixelFillRatio = aStats.mInvalidPixels
? float(aStats.mPixelsFilled) / float(aStats.mInvalidPixels)
: 0.0f;
float screenFillRatio = aStats.mScreenPixels
? float(aStats.mPixelsFilled) / float(aStats.mScreenPixels)
: 0.0f;
if (aStats.mDrawTime) {
mGPUDrawMs.Add(aStats.mDrawTime.value());
}
std::string gpuTimeString;
if (mGPUDrawMs.Empty()) {
gpuTimeString = "N/A";
} else {
gpuTimeString = nsPrintfCString("%0.1fms", mGPUDrawMs.Average()).get();
}
// DL = nsDisplayListBuilder
// FLB = FrameLayerBuilder
// R = ClientLayerManager::EndTransaction
// CP = ShadowLayerForwarder::EndTransaction (txn build)
// TX = LayerTransactionChild::SendUpdate (IPDL serialize+send)
// UP = LayerTransactionParent::RecvUpdate (IPDL deserialize, update, APZ update)
// CC_BUILD = Container prepare/composite frame building
// CC_EXEC = Container render/composite drawing
nsPrintfCString line1("FPS: %d (TXN: %d)", fps, txnFps);
nsPrintfCString line2("[CC] Build: %0.1fms Exec: %0.1fms GPU: %s Fill Ratio: %0.1f/%0.1f",
mPrepareMs.Average(),
mCompositeMs.Average(),
gpuTimeString.c_str(),
pixelFillRatio,
screenFillRatio);
nsPrintfCString line3("[Content] DL: %0.1fms FLB: %0.1fms Raster: %0.1fms",
mDlbMs.Average(),
mFlbMs.Average(),
mRasterMs.Average());
nsPrintfCString line4("[IPDL] Build: %0.1fms Send: %0.1fms Update: %0.1fms",
mSerializeMs.Average(),
mSendMs.Average(),
mUpdateMs.Average());
return std::string(line1.get()) + "\n" +
std::string(line2.get()) + "\n" +
std::string(line3.get()) + "\n" +
std::string(line4.get());
}
} // namespace layers
} // namespace mozilla

View File

@ -0,0 +1,117 @@
/* -*- Mode: C++; tab-width: 20; 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/. */
#ifndef mozilla_gfx_layers_composite_Diagnostics_h
#define mozilla_gfx_layers_composite_Diagnostics_h
#include "FPSCounter.h"
#include "gfxPrefs.h"
#include "mozilla/Maybe.h"
#include "mozilla/TimeStamp.h"
#include <deque>
#include <string>
#include <utility>
namespace mozilla {
namespace layers {
class PaintTiming;
class TimedMetric
{
typedef std::pair<float, TimeStamp> Entry;
public:
void Add(float aValue) {
if (mHistory.size() > kMaxHistory) {
mHistory.pop_front();
}
mHistory.push_back(Entry(aValue, TimeStamp::Now()));
}
float Average() const;
bool Empty() const {
return mHistory.empty();
}
private:
static const size_t kMaxHistory = 60;
std::deque<Entry> mHistory;
};
// These statistics are collected by layers backends, preferably by the GPU
struct GPUStats
{
GPUStats()
: mInvalidPixels(0),
mScreenPixels(0),
mPixelsFilled(0)
{}
uint32_t mInvalidPixels;
uint32_t mScreenPixels;
uint32_t mPixelsFilled;
Maybe<float> mDrawTime;
};
// Collects various diagnostics about layers performance.
class Diagnostics
{
public:
Diagnostics();
void RecordPaintTimes(const PaintTiming& aPaintTimes);
void RecordUpdateTime(float aValue) {
mUpdateMs.Add(aValue);
}
void RecordPrepareTime(float aValue) {
mPrepareMs.Add(aValue);
}
void RecordCompositeTime(float aValue) {
mCompositeMs.Add(aValue);
}
void AddTxnFrame() {
mTransactionFps.AddFrame(TimeStamp::Now());
}
std::string GetFrameOverlayString(const GPUStats& aStats);
class Record {
public:
Record() {
if (gfxPrefs::LayersDrawFPS()) {
mStart = TimeStamp::Now();
}
}
bool Recording() const {
return !mStart.IsNull();
}
float Duration() const {
return (TimeStamp::Now() - mStart).ToMilliseconds();
}
private:
TimeStamp mStart;
};
private:
FPSCounter mCompositeFps;
FPSCounter mTransactionFps;
TimedMetric mDlbMs;
TimedMetric mFlbMs;
TimedMetric mRasterMs;
TimedMetric mSerializeMs;
TimedMetric mSendMs;
TimedMetric mUpdateMs;
TimedMetric mPrepareMs;
TimedMetric mCompositeMs;
TimedMetric mGPUDrawMs;
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_gfx_layers_composite_Diagnostics_h

View File

@ -356,95 +356,5 @@ FPSCounter::WriteFrameTimeStamps()
return NS_OK; return NS_OK;
} }
FPSState::FPSState()
: mCompositionFps("Compositor")
, mTransactionFps("LayerTransactions")
{
}
// Size of the builtin font.
static const float FontHeight = 7.f;
static const float FontWidth = 4.f;
// Scale the font when drawing it to the viewport for better readability.
static const float FontScaleX = 2.f;
static const float FontScaleY = 3.f;
static void DrawDigits(unsigned int aValue,
int aOffsetX, int aOffsetY,
Compositor* aCompositor,
EffectChain& aEffectChain)
{
if (aValue > 999) {
aValue = 999;
}
unsigned int divisor = 100;
float textureWidth = FontWidth * 10;
gfx::Float opacity = 1;
gfx::Matrix4x4 transform;
transform.PreScale(FontScaleX, FontScaleY, 1);
for (size_t n = 0; n < 3; ++n) {
unsigned int digit = aValue % (divisor * 10) / divisor;
divisor /= 10;
RefPtr<TexturedEffect> texturedEffect = static_cast<TexturedEffect*>(aEffectChain.mPrimaryEffect.get());
texturedEffect->mTextureCoords = Rect(float(digit * FontWidth) / textureWidth, 0, FontWidth / textureWidth, 1.0f);
Rect drawRect = Rect(aOffsetX + n * FontWidth, aOffsetY, FontWidth, FontHeight);
IntRect clipRect = IntRect(0, 0, 300, 100);
aCompositor->DrawQuad(drawRect, clipRect, aEffectChain, opacity, transform);
}
}
void FPSState::DrawFPS(TimeStamp aNow,
int aOffsetX, int aOffsetY,
unsigned int aFillRatio,
Compositor* aCompositor)
{
if (!mFPSTextureSource) {
const char *text =
" "
" XXX XX XXX XXX X X XXX XXX XXX XXX XXX"
" X X X X X X X X X X X X X X"
" X X X XXX XXX XXX XXX XXX X XXX XXX"
" X X X X X X X X X X X X X"
" XXX XXX XXX XXX X XXX XXX X XXX X"
" ";
// Convert the text encoding above to RGBA.
int w = FontWidth * 10;
int h = FontHeight;
uint32_t* buf = (uint32_t *) malloc(w * h * sizeof(uint32_t));
for (int i = 0; i < h; i++) {
for (int j = 0; j < w; j++) {
uint32_t purple = 0xfff000ff;
uint32_t white = 0xffffffff;
buf[i * w + j] = (text[i * w + j] == ' ') ? purple : white;
}
}
int bytesPerPixel = 4;
RefPtr<DataSourceSurface> fpsSurface = Factory::CreateWrappingDataSourceSurface(
reinterpret_cast<uint8_t*>(buf), w * bytesPerPixel, IntSize(w, h), SurfaceFormat::B8G8R8A8);
mFPSTextureSource = aCompositor->CreateDataTextureSource();
mFPSTextureSource->Update(fpsSurface);
}
EffectChain effectChain;
effectChain.mPrimaryEffect = CreateTexturedEffect(SurfaceFormat::B8G8R8A8,
mFPSTextureSource,
SamplingFilter::POINT,
true);
unsigned int fps = unsigned(mCompositionFps.AddFrameAndGetFps(aNow));
unsigned int txnFps = unsigned(mTransactionFps.GetFPS(aNow));
DrawDigits(fps, aOffsetX + 0, aOffsetY, aCompositor, effectChain);
DrawDigits(txnFps, aOffsetX + FontWidth * 4, aOffsetY, aCompositor, effectChain);
DrawDigits(aFillRatio, aOffsetX + FontWidth * 8, aOffsetY, aCompositor, effectChain);
}
} // end namespace layers } // end namespace layers
} // end namespace mozilla } // end namespace mozilla

View File

@ -94,20 +94,6 @@ private:
TimeStamp mLastInterval; TimeStamp mLastInterval;
}; };
struct FPSState {
FPSState();
void DrawFPS(TimeStamp, int offsetX, int offsetY, unsigned, Compositor* aCompositor);
void NotifyShadowTreeTransaction() {
mTransactionFps.AddFrame(TimeStamp::Now());
}
FPSCounter mCompositionFps;
FPSCounter mTransactionFps;
private:
RefPtr<DataTextureSource> mFPSTextureSource;
};
} // namespace layers } // namespace layers
} // namespace mozilla } // namespace mozilla

File diff suppressed because one or more lines are too long

View File

@ -10,6 +10,7 @@
#include "ColorLayerComposite.h" // for ColorLayerComposite #include "ColorLayerComposite.h" // for ColorLayerComposite
#include "CompositableHost.h" // for CompositableHost #include "CompositableHost.h" // for CompositableHost
#include "ContainerLayerComposite.h" // for ContainerLayerComposite, etc #include "ContainerLayerComposite.h" // for ContainerLayerComposite, etc
#include "Diagnostics.h"
#include "FPSCounter.h" // for FPSState, FPSCounter #include "FPSCounter.h" // for FPSState, FPSCounter
#include "FrameMetrics.h" // for FrameMetrics #include "FrameMetrics.h" // for FrameMetrics
#include "GeckoProfiler.h" // for profiler_set_frame_number, etc #include "GeckoProfiler.h" // for profiler_set_frame_number, etc
@ -124,6 +125,18 @@ HostLayerManager::HostLayerManager()
HostLayerManager::~HostLayerManager() HostLayerManager::~HostLayerManager()
{} {}
void
HostLayerManager::RecordPaintTimes(const PaintTiming& aTiming)
{
mDiagnostics->RecordPaintTimes(aTiming);
}
void
HostLayerManager::RecordUpdateTime(float aValue)
{
mDiagnostics->RecordUpdateTime(aValue);
}
/** /**
* LayerManagerComposite * LayerManagerComposite
*/ */
@ -135,7 +148,8 @@ LayerManagerComposite::LayerManagerComposite(Compositor* aCompositor)
, mIsCompositorReady(false) , mIsCompositorReady(false)
, mGeometryChanged(true) , mGeometryChanged(true)
{ {
mTextRenderer = new TextRenderer(aCompositor); mTextRenderer = new TextRenderer();
mDiagnostics = MakeUnique<Diagnostics>();
MOZ_ASSERT(aCompositor); MOZ_ASSERT(aCompositor);
#ifdef USE_SKIA #ifdef USE_SKIA
@ -539,7 +553,7 @@ LayerManagerComposite::InvalidateDebugOverlay(nsIntRegion& aInvalidRegion, const
bool drawFrameColorBars = gfxPrefs::CompositorDrawColorBars(); bool drawFrameColorBars = gfxPrefs::CompositorDrawColorBars();
if (drawFps || drawFrameCounter) { if (drawFps || drawFrameCounter) {
aInvalidRegion.Or(aInvalidRegion, nsIntRect(0, 0, 256, 256)); aInvalidRegion.Or(aInvalidRegion, nsIntRect(0, 0, 650, 400));
} }
if (drawFrameColorBars) { if (drawFrameColorBars) {
aInvalidRegion.Or(aInvalidRegion, nsIntRect(0, 0, 10, aBounds.height)); aInvalidRegion.Or(aInvalidRegion, nsIntRect(0, 0, 10, aBounds.height));
@ -574,18 +588,14 @@ LayerManagerComposite::RenderDebugOverlay(const IntRect& aBounds)
bool drawFrameCounter = gfxPrefs::DrawFrameCounter(); bool drawFrameCounter = gfxPrefs::DrawFrameCounter();
bool drawFrameColorBars = gfxPrefs::CompositorDrawColorBars(); bool drawFrameColorBars = gfxPrefs::CompositorDrawColorBars();
TimeStamp now = TimeStamp::Now();
if (drawFps) { if (drawFps) {
if (!mFPS) {
mFPS = MakeUnique<FPSState>();
}
float alpha = 1; float alpha = 1;
#ifdef ANDROID #ifdef ANDROID
// Draw a translation delay warning overlay // Draw a translation delay warning overlay
int width; int width;
int border; int border;
TimeStamp now = TimeStamp::Now();
if (!mWarnTime.IsNull() && (now - mWarnTime).ToMilliseconds() < kVisualWarningDuration) { if (!mWarnTime.IsNull() && (now - mWarnTime).ToMilliseconds() < kVisualWarningDuration) {
EffectChain effects; EffectChain effects;
@ -618,8 +628,19 @@ LayerManagerComposite::RenderDebugOverlay(const IntRect& aBounds)
} }
#endif #endif
float fillRatio = mCompositor->GetFillRatio(); GPUStats stats;
mFPS->DrawFPS(now, drawFrameColorBars ? 10 : 1, 2, unsigned(fillRatio), mCompositor); stats.mScreenPixels = mRenderBounds.width * mRenderBounds.height;
mCompositor->GetFrameStats(&stats);
std::string text = mDiagnostics->GetFrameOverlayString(stats);
mTextRenderer->RenderText(
mCompositor,
text,
IntPoint(2, 5),
Matrix4x4(),
24,
600,
TextRenderer::FontType::FixedWidth);
if (mUnusedApzTransformWarning) { if (mUnusedApzTransformWarning) {
// If we have an unused APZ transform on this composite, draw a 20x20 red box // If we have an unused APZ transform on this composite, draw a 20x20 red box
@ -644,11 +665,6 @@ LayerManagerComposite::RenderDebugOverlay(const IntRect& aBounds)
mDisabledApzWarning = false; mDisabledApzWarning = false;
SetDebugOverlayWantsNextFrame(true); SetDebugOverlayWantsNextFrame(true);
} }
// Each frame is invalidate by the previous frame for simplicity
} else {
mFPS = nullptr;
} }
if (drawFrameColorBars) { if (drawFrameColorBars) {
@ -925,8 +941,21 @@ LayerManagerComposite::Render(const nsIntRegion& aInvalidRegion, const nsIntRegi
} }
// Render our layers. // Render our layers.
RootLayer()->Prepare(ViewAs<RenderTargetPixel>(clipRect, PixelCastJustification::RenderTargetIsParentLayerForRoot)); {
RootLayer()->RenderLayer(clipRect.ToUnknownRect(), Nothing()); Diagnostics::Record record;
RootLayer()->Prepare(ViewAs<RenderTargetPixel>(clipRect, PixelCastJustification::RenderTargetIsParentLayerForRoot));
if (record.Recording()) {
mDiagnostics->RecordPrepareTime(record.Duration());
}
}
// Execute draw commands.
{
Diagnostics::Record record;
RootLayer()->RenderLayer(clipRect.ToUnknownRect(), Nothing());
if (record.Recording()) {
mDiagnostics->RecordCompositeTime(record.Duration());
}
}
RootLayer()->Cleanup(); RootLayer()->Cleanup();
if (!mRegionToClear.IsEmpty()) { if (!mRegionToClear.IsEmpty()) {
@ -946,6 +975,8 @@ LayerManagerComposite::Render(const nsIntRegion& aInvalidRegion, const nsIntRegi
mCompositor->GetWidget()->DrawWindowOverlay( mCompositor->GetWidget()->DrawWindowOverlay(
&widgetContext, LayoutDeviceIntRect::FromUnknownRect(actualBounds)); &widgetContext, LayoutDeviceIntRect::FromUnknownRect(actualBounds));
mCompositor->NormalDrawingDone();
// Debugging // Debugging
RenderDebugOverlay(actualBounds); RenderDebugOverlay(actualBounds);
@ -1341,7 +1372,6 @@ LayerManagerComposite::ChangeCompositor(Compositor* aNewCompositor)
mCompositor->CancelFrame(); mCompositor->CancelFrame();
} }
mCompositor = aNewCompositor; mCompositor = aNewCompositor;
mTextRenderer = new TextRenderer(aNewCompositor);
mTwoPassTmpTarget = nullptr; mTwoPassTmpTarget = nullptr;
} }
@ -1388,8 +1418,8 @@ LayerManagerComposite::CanUseCanvasLayerForSize(const IntSize &aSize)
void void
LayerManagerComposite::NotifyShadowTreeTransaction() LayerManagerComposite::NotifyShadowTreeTransaction()
{ {
if (mFPS) { if (gfxPrefs::LayersDrawFPS()) {
mFPS->NotifyShadowTreeTransaction(); mDiagnostics->AddTxnFrame();
} }
} }

View File

@ -52,6 +52,7 @@ class CanvasLayerComposite;
class ColorLayerComposite; class ColorLayerComposite;
class Compositor; class Compositor;
class ContainerLayerComposite; class ContainerLayerComposite;
class Diagnostics;
struct EffectChain; struct EffectChain;
class ImageLayer; class ImageLayer;
class ImageLayerComposite; class ImageLayerComposite;
@ -169,6 +170,9 @@ public:
return false; return false;
} }
void RecordPaintTimes(const PaintTiming& aTiming);
void RecordUpdateTime(float aValue);
TimeStamp GetCompositionTime() const { TimeStamp GetCompositionTime() const {
return mCompositionTime; return mCompositionTime;
} }
@ -196,6 +200,7 @@ protected:
// true if the last frame was deemed 'too complicated' to be rendered. // true if the last frame was deemed 'too complicated' to be rendered.
float mWarningLevel; float mWarningLevel;
mozilla::TimeStamp mWarnTime; mozilla::TimeStamp mWarnTime;
UniquePtr<Diagnostics> mDiagnostics;
bool mWindowOverlayChanged; bool mWindowOverlayChanged;
TimeDuration mLastPaintTime; TimeDuration mLastPaintTime;
@ -463,8 +468,6 @@ private:
CSSIntRegion> VisibleRegions; CSSIntRegion> VisibleRegions;
VisibleRegions mVisibleRegions; VisibleRegions mVisibleRegions;
UniquePtr<FPSState> mFPS;
bool mInTransaction; bool mInTransaction;
bool mIsCompositorReady; bool mIsCompositorReady;

View File

@ -5,6 +5,7 @@
#include "TextRenderer.h" #include "TextRenderer.h"
#include "FontData.h" #include "FontData.h"
#include "ConsolasFontData.h"
#include "png.h" #include "png.h"
#include "mozilla/Base64.h" #include "mozilla/Base64.h"
#include "mozilla/layers/Compositor.h" #include "mozilla/layers/Compositor.h"
@ -17,7 +18,7 @@ namespace layers {
using namespace gfx; using namespace gfx;
using namespace std; using namespace std;
const Float sBackgroundOpacity = 0.6f; const Float sBackgroundOpacity = 0.8f;
const SurfaceFormat sTextureFormat = SurfaceFormat::B8G8R8A8; const SurfaceFormat sTextureFormat = SurfaceFormat::B8G8R8A8;
static void PNGAPI info_callback(png_structp png_ptr, png_infop info_ptr) static void PNGAPI info_callback(png_structp png_ptr, png_infop info_ptr)
@ -29,11 +30,12 @@ static void PNGAPI row_callback(png_structp png_ptr, png_bytep new_row, png_uint
{ {
MOZ_ASSERT(sTextureFormat == SurfaceFormat::B8G8R8A8); MOZ_ASSERT(sTextureFormat == SurfaceFormat::B8G8R8A8);
DataSourceSurface::MappedSurface map = static_cast<TextRenderer*>(png_get_progressive_ptr(png_ptr))->GetSurfaceMap(); TextRenderer::FontCache* cache =
static_cast<TextRenderer::FontCache*>(png_get_progressive_ptr(png_ptr));
uint32_t* dst = (uint32_t*)(map.mData + map.mStride * row_num); uint32_t* dst = (uint32_t*)(cache->mMap.mData + cache->mMap.mStride * row_num);
for (uint32_t x = 0; x < sTextureWidth; x++) { for (uint32_t x = 0; x < cache->mInfo->mTextureWidth; x++) {
// We blend to a transparent white background, this will make text readable // We blend to a transparent white background, this will make text readable
// even if it's on a dark background. Without hurting our ability to // even if it's on a dark background. Without hurting our ability to
// interact with the content behind the text. // interact with the content behind the text.
@ -46,24 +48,64 @@ static void PNGAPI row_callback(png_structp png_ptr, png_bytep new_row, png_uint
TextRenderer::~TextRenderer() TextRenderer::~TextRenderer()
{ {
if (mGlyphBitmaps) { }
mGlyphBitmaps->Unmap();
} TextRenderer::FontCache::~FontCache()
{
mGlyphBitmaps->Unmap();
} }
void void
TextRenderer::RenderText(const string& aText, const IntPoint& aOrigin, TextRenderer::RenderText(Compositor* aCompositor,
const string& aText,
const IntPoint& aOrigin,
const Matrix4x4& aTransform, uint32_t aTextSize, const Matrix4x4& aTransform, uint32_t aTextSize,
uint32_t aTargetPixelWidth) uint32_t aTargetPixelWidth,
FontType aFontType)
{ {
EnsureInitialized(); const FontBitmapInfo* info = GetFontInfo(aFontType);
// For now we only have a bitmap font with a 16px cell size, so we just // For now we only have a bitmap font with a 24px cell size, so we just
// scale it up if the user wants larger text. // scale it up if the user wants larger text.
Float scaleFactor = Float(aTextSize) / Float(sCellHeight); Float scaleFactor = Float(aTextSize) / Float(info->mCellHeight);
aTargetPixelWidth /= scaleFactor; aTargetPixelWidth /= scaleFactor;
RefPtr<TextureSource> src = RenderText(
aCompositor,
aText,
aTextSize,
aTargetPixelWidth,
aFontType);
if (!src) {
return;
}
RefPtr<EffectRGB> effect = new EffectRGB(src, true, SamplingFilter::LINEAR);
EffectChain chain;
chain.mPrimaryEffect = effect;
Matrix4x4 transform = aTransform;
transform.PreScale(scaleFactor, scaleFactor, 1.0f);
IntRect drawRect(aOrigin, src->GetSize());
IntRect clip(-10000, -10000, 20000, 20000);
aCompositor->DrawQuad(Rect(drawRect), clip, chain, 1.0f, transform);
}
RefPtr<TextureSource>
TextRenderer::RenderText(TextureSourceProvider* aProvider,
const string& aText,
uint32_t aTextSize,
uint32_t aTargetPixelWidth,
FontType aFontType)
{
if (!EnsureInitialized(aFontType)) {
return nullptr;
}
FontCache* cache = mFonts[aFontType].get();
const FontBitmapInfo* info = cache->mInfo;
uint32_t numLines = 1; uint32_t numLines = 1;
uint32_t maxWidth = 0; uint32_t maxWidth = 0;
uint32_t lineWidth = 0; uint32_t lineWidth = 0;
@ -78,95 +120,119 @@ TextRenderer::RenderText(const string& aText, const IntPoint& aOrigin,
continue; continue;
} }
lineWidth += sGlyphWidths[uint32_t(aText[i])]; lineWidth += info->GetGlyphWidth(aText[i]);
maxWidth = std::max(lineWidth, maxWidth); maxWidth = std::max(lineWidth, maxWidth);
} }
// Create a surface to draw our glyphs to. // Create a surface to draw our glyphs to.
RefPtr<DataSourceSurface> textSurf = RefPtr<DataSourceSurface> textSurf =
Factory::CreateDataSourceSurface(IntSize(maxWidth, numLines * sCellHeight), sTextureFormat); Factory::CreateDataSourceSurface(IntSize(maxWidth, numLines * info->mCellHeight), sTextureFormat);
if (NS_WARN_IF(!textSurf)) { if (NS_WARN_IF(!textSurf)) {
return; return nullptr;
} }
DataSourceSurface::MappedSurface map; DataSourceSurface::MappedSurface map;
if (NS_WARN_IF(!textSurf->Map(DataSourceSurface::MapType::READ_WRITE, &map))) { if (NS_WARN_IF(!textSurf->Map(DataSourceSurface::MapType::READ_WRITE, &map))) {
return; return nullptr;
} }
// Initialize the surface to transparent white. // Initialize the surface to transparent white.
memset(map.mData, uint8_t(sBackgroundOpacity * 255.0f), memset(map.mData, uint8_t(sBackgroundOpacity * 255.0f),
numLines * sCellHeight * map.mStride); numLines * info->mCellHeight * map.mStride);
uint32_t currentXPos = 0; uint32_t currentXPos = 0;
uint32_t currentYPos = 0; uint32_t currentYPos = 0;
const unsigned int kGlyphsPerLine = info->mTextureWidth / info->mCellWidth;
// Copy our glyphs onto the surface. // Copy our glyphs onto the surface.
for (uint32_t i = 0; i < aText.length(); i++) { for (uint32_t i = 0; i < aText.length(); i++) {
if (aText[i] == '\n' || (aText[i] == ' ' && currentXPos > aTargetPixelWidth)) { if (aText[i] == '\n' || (aText[i] == ' ' && currentXPos > aTargetPixelWidth)) {
currentYPos += sCellHeight; currentYPos += info->mCellHeight;
currentXPos = 0; currentXPos = 0;
continue; continue;
} }
uint32_t glyphXOffset = aText[i] % (sTextureWidth / sCellWidth) * sCellWidth * BytesPerPixel(sTextureFormat); uint32_t index = aText[i] - info->mFirstChar;
uint32_t truncatedLine = aText[i] / (sTextureWidth / sCellWidth); uint32_t glyphXOffset = (index % kGlyphsPerLine) * info->mCellWidth * BytesPerPixel(sTextureFormat);
uint32_t glyphYOffset = truncatedLine * sCellHeight * mMap.mStride; uint32_t truncatedLine = index / kGlyphsPerLine;
uint32_t glyphYOffset = truncatedLine * info->mCellHeight * cache->mMap.mStride;
for (int y = 0; y < 16; y++) { uint32_t glyphWidth = info->GetGlyphWidth(aText[i]);
for (uint32_t y = 0; y < info->mCellHeight; y++) {
memcpy(map.mData + (y + currentYPos) * map.mStride + currentXPos * BytesPerPixel(sTextureFormat), memcpy(map.mData + (y + currentYPos) * map.mStride + currentXPos * BytesPerPixel(sTextureFormat),
mMap.mData + glyphYOffset + y * mMap.mStride + glyphXOffset, cache->mMap.mData + glyphYOffset + y * cache->mMap.mStride + glyphXOffset,
sGlyphWidths[uint32_t(aText[i])] * BytesPerPixel(sTextureFormat)); glyphWidth * BytesPerPixel(sTextureFormat));
} }
currentXPos += sGlyphWidths[uint32_t(aText[i])]; currentXPos += glyphWidth;
} }
textSurf->Unmap(); textSurf->Unmap();
RefPtr<DataTextureSource> src = mCompositor->CreateDataTextureSource(); RefPtr<DataTextureSource> src = aProvider->CreateDataTextureSource();
if (!src->Update(textSurf)) { if (!src->Update(textSurf)) {
// Upload failed. // Upload failed.
return; return nullptr;
} }
RefPtr<EffectRGB> effect = new EffectRGB(src, true, SamplingFilter::LINEAR); return src;
EffectChain chain;
chain.mPrimaryEffect = effect;
Matrix4x4 transform = aTransform;
transform.PreScale(scaleFactor, scaleFactor, 1.0f);
mCompositor->DrawQuad(Rect(aOrigin.x, aOrigin.y, maxWidth, numLines * 16),
IntRect(-10000, -10000, 20000, 20000), chain, 1.0f, transform);
} }
void /* static */ const FontBitmapInfo*
TextRenderer::EnsureInitialized() TextRenderer::GetFontInfo(FontType aType)
{ {
if (mGlyphBitmaps) { switch (aType) {
return; case FontType::Default:
return &sDefaultCompositorFont;
case FontType::FixedWidth:
return &sFixedWidthCompositorFont;
default:
MOZ_ASSERT_UNREACHABLE("unknown font type");
return nullptr;
}
}
bool
TextRenderer::EnsureInitialized(FontType aType)
{
if (mFonts[aType]) {
return true;
} }
mGlyphBitmaps = Factory::CreateDataSourceSurface(IntSize(sTextureWidth, sTextureHeight), sTextureFormat); const FontBitmapInfo* info = GetFontInfo(aType);
if (NS_WARN_IF(!mGlyphBitmaps)) {
return; IntSize size(info->mTextureWidth, info->mTextureHeight);
RefPtr<DataSourceSurface> surface = Factory::CreateDataSourceSurface(size, sTextureFormat);
if (NS_WARN_IF(!surface)) {
return false;
} }
if (NS_WARN_IF(!mGlyphBitmaps->Map(DataSourceSurface::MapType::READ_WRITE, &mMap))) { DataSourceSurface::MappedSurface map;
return; if (NS_WARN_IF(!surface->Map(DataSourceSurface::MapType::READ_WRITE, &map))) {
return false;
} }
UniquePtr<FontCache> cache = MakeUnique<FontCache>();
cache->mGlyphBitmaps = surface;
cache->mMap = map;
cache->mInfo = info;
png_structp png_ptr = NULL; png_structp png_ptr = NULL;
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr);
png_set_progressive_read_fn(png_ptr, this, info_callback, row_callback, nullptr); png_set_progressive_read_fn(png_ptr, cache.get(), info_callback, row_callback, nullptr);
png_infop info_ptr = NULL; png_infop info_ptr = NULL;
info_ptr = png_create_info_struct(png_ptr); info_ptr = png_create_info_struct(png_ptr);
png_process_data(png_ptr, info_ptr, (uint8_t*)sFontPNG, sizeof(sFontPNG)); png_process_data(png_ptr, info_ptr, (uint8_t*)info->mPNG, info->mPNGLength);
png_destroy_read_struct(&png_ptr, &info_ptr, nullptr); png_destroy_read_struct(&png_ptr, &info_ptr, nullptr);
mFonts[aType] = Move(cache);
return true;
} }
} // namespace layers } // namespace layers

View File

@ -6,6 +6,7 @@
#ifndef GFX_TextRenderer_H #ifndef GFX_TextRenderer_H
#define GFX_TextRenderer_H #define GFX_TextRenderer_H
#include "mozilla/EnumeratedArray.h"
#include "mozilla/gfx/2D.h" #include "mozilla/gfx/2D.h"
#include "nsISupportsImpl.h" #include "nsISupportsImpl.h"
#include <string> #include <string>
@ -14,6 +15,9 @@ namespace mozilla {
namespace layers { namespace layers {
class Compositor; class Compositor;
class TextureSource;
class TextureSourceProvider;
struct FontBitmapInfo;
class TextRenderer class TextRenderer
{ {
@ -22,26 +26,65 @@ class TextRenderer
public: public:
NS_INLINE_DECL_REFCOUNTING(TextRenderer) NS_INLINE_DECL_REFCOUNTING(TextRenderer)
explicit TextRenderer(Compositor *aCompositor) enum class FontType {
: mCompositor(aCompositor), mMap({nullptr, 0}) Default,
{ FixedWidth,
} NumTypes
};
void RenderText(const std::string& aText, const gfx::IntPoint& aOrigin, explicit TextRenderer()
{}
RefPtr<TextureSource>
RenderText(TextureSourceProvider* aProvider,
const std::string& aText,
uint32_t aTextSize,
uint32_t aTargetPixelWidth,
FontType aFontType);
void RenderText(Compositor* aCompositor,
const std::string& aText,
const gfx::IntPoint& aOrigin,
const gfx::Matrix4x4& aTransform, uint32_t aTextSize, const gfx::Matrix4x4& aTransform, uint32_t aTextSize,
uint32_t aTargetPixelWidth); uint32_t aTargetPixelWidth,
FontType aFontType = FontType::Default);
gfx::DataSourceSurface::MappedSurface& GetSurfaceMap() { return mMap; } struct FontCache {
~FontCache();
private: RefPtr<gfx::DataSourceSurface> mGlyphBitmaps;
gfx::DataSourceSurface::MappedSurface mMap;
const FontBitmapInfo* mInfo;
};
protected:
// Note that this may still fail to set mGlyphBitmaps to a valid value // Note that this may still fail to set mGlyphBitmaps to a valid value
// if the underlying CreateDataSourceSurface fails for some reason. // if the underlying CreateDataSourceSurface fails for some reason.
void EnsureInitialized(); bool EnsureInitialized(FontType aType);
RefPtr<Compositor> mCompositor; static const FontBitmapInfo* GetFontInfo(FontType aType);
RefPtr<gfx::DataSourceSurface> mGlyphBitmaps;
gfx::DataSourceSurface::MappedSurface mMap; private:
EnumeratedArray<FontType, FontType::NumTypes, UniquePtr<FontCache>> mFonts;
};
struct FontBitmapInfo {
Maybe<unsigned int> mGlyphWidth;
Maybe<const unsigned short*> mGlyphWidths;
unsigned int mTextureWidth;
unsigned int mTextureHeight;
unsigned int mCellWidth;
unsigned int mCellHeight;
unsigned int mFirstChar;
const unsigned char* mPNG;
size_t mPNGLength;
unsigned int GetGlyphWidth(char aGlyph) const {
if (mGlyphWidth) {
return mGlyphWidth.value();
}
MOZ_ASSERT(unsigned(aGlyph) >= mFirstChar);
return mGlyphWidths.value()[unsigned(aGlyph) - mFirstChar];
}
}; };
} // namespace layers } // namespace layers

View File

@ -15,7 +15,10 @@
#include "mozilla/gfx/GPUParent.h" #include "mozilla/gfx/GPUParent.h"
#include "mozilla/layers/ImageHost.h" #include "mozilla/layers/ImageHost.h"
#include "mozilla/layers/ContentHost.h" #include "mozilla/layers/ContentHost.h"
#include "mozilla/layers/Diagnostics.h"
#include "mozilla/layers/DiagnosticsD3D11.h"
#include "mozilla/layers/Effects.h" #include "mozilla/layers/Effects.h"
#include "mozilla/layers/HelpersD3D11.h"
#include "nsWindowsHelpers.h" #include "nsWindowsHelpers.h"
#include "gfxPrefs.h" #include "gfxPrefs.h"
#include "gfxConfig.h" #include "gfxConfig.h"
@ -286,6 +289,7 @@ CompositorD3D11::Initialize(nsCString* const out_failureReason)
return false; return false;
} }
mDiagnostics = MakeUnique<DiagnosticsD3D11>(mDevice, mContext);
mFeatureLevel = mDevice->GetFeatureLevel(); mFeatureLevel = mDevice->GetFeatureLevel();
mHwnd = mWidget->AsWindows()->GetHwnd(); mHwnd = mWidget->AsWindows()->GetHwnd();
@ -864,6 +868,9 @@ CompositorD3D11::ClearRect(const gfx::Rect& aRect)
} }
mContext->Draw(4, 0); mContext->Draw(4, 0);
// Restore the default blend state.
mContext->OMSetBlendState(mAttachments->mPremulBlendState, sBlendFactor, 0xFFFFFFFF);
} }
static inline bool static inline bool
@ -1398,6 +1405,21 @@ CompositorD3D11::BeginFrame(const nsIntRegion& aInvalidRegion,
} }
} }
} }
if (gfxPrefs::LayersDrawFPS()) {
uint32_t pixelsPerFrame = 0;
for (auto iter = mBackBufferInvalid.RectIter(); !iter.Done(); iter.Next()) {
pixelsPerFrame += iter.Get().width * iter.Get().height;
}
mDiagnostics->Start(pixelsPerFrame);
}
}
void
CompositorD3D11::NormalDrawingDone()
{
mDiagnostics->End();
} }
void void
@ -1429,6 +1451,34 @@ CompositorD3D11::EndFrame()
mContext->End(query); mContext->End(query);
} }
if (oldSize == mSize) {
Present();
} else {
mDiagnostics->Cancel();
}
// Block until the previous frame's work has been completed.
if (mQuery) {
BOOL result;
WaitForGPUQuery(mDevice, mContext, mQuery, &result);
}
// Store the query for this frame so we can flush it next time.
mQuery = query;
Compositor::EndFrame();
mCurrentRT = nullptr;
}
void
CompositorD3D11::GetFrameStats(GPUStats* aStats)
{
mDiagnostics->Query(aStats);
}
void
CompositorD3D11::Present()
{
UINT presentInterval = 0; UINT presentInterval = 0;
bool isWARP = DeviceManagerDx::Get()->IsWARP(); bool isWARP = DeviceManagerDx::Get()->IsWARP();
@ -1439,71 +1489,48 @@ CompositorD3D11::EndFrame()
presentInterval = 1; presentInterval = 1;
} }
if (oldSize == mSize) { // This must be called before present so our back buffer has the validated window content.
// This must be called before present so our back buffer has the validated window content. if (mTarget) {
if (mTarget) { PaintToTarget();
PaintToTarget();
}
RefPtr<IDXGISwapChain1> chain;
HRESULT hr = mSwapChain->QueryInterface((IDXGISwapChain1**)getter_AddRefs(chain));
if (SUCCEEDED(hr) && mAllowPartialPresents) {
DXGI_PRESENT_PARAMETERS params;
PodZero(&params);
params.DirtyRectsCount = mBackBufferInvalid.GetNumRects();
StackArray<RECT, 4> rects(params.DirtyRectsCount);
uint32_t i = 0;
for (auto iter = mBackBufferInvalid.RectIter(); !iter.Done(); iter.Next()) {
const IntRect& r = iter.Get();
rects[i].left = r.x;
rects[i].top = r.y;
rects[i].bottom = r.YMost();
rects[i].right = r.XMost();
i++;
}
params.pDirtyRects = params.DirtyRectsCount ? rects.data() : nullptr;
chain->Present1(presentInterval, mDisableSequenceForNextFrame ? DXGI_PRESENT_DO_NOT_SEQUENCE : 0, &params);
} else {
HRESULT hr = mSwapChain->Present(0, mDisableSequenceForNextFrame ? DXGI_PRESENT_DO_NOT_SEQUENCE : 0);
if (FAILED(hr)) {
gfxCriticalNote << "D3D11 swap chain preset failed " << hexa(hr);
HandleError(hr);
}
}
if (mIsDoubleBuffered) {
mBackBufferInvalid = mFrontBufferInvalid;
mFrontBufferInvalid.SetEmpty();
} else {
mBackBufferInvalid.SetEmpty();
}
mDisableSequenceForNextFrame = false;
} }
// Block until the previous frame's work has been completed. RefPtr<IDXGISwapChain1> chain;
if (mQuery) { HRESULT hr = mSwapChain->QueryInterface((IDXGISwapChain1**)getter_AddRefs(chain));
TimeStamp start = TimeStamp::Now();
BOOL result; if (SUCCEEDED(hr) && mAllowPartialPresents) {
while (mContext->GetData(mQuery, &result, sizeof(BOOL), 0) != S_OK) { DXGI_PRESENT_PARAMETERS params;
if (mDevice->GetDeviceRemovedReason() != S_OK) { PodZero(&params);
break; params.DirtyRectsCount = mBackBufferInvalid.GetNumRects();
} StackArray<RECT, 4> rects(params.DirtyRectsCount);
if ((TimeStamp::Now() - start) > TimeDuration::FromSeconds(2)) {
break; uint32_t i = 0;
} for (auto iter = mBackBufferInvalid.RectIter(); !iter.Done(); iter.Next()) {
Sleep(0); const IntRect& r = iter.Get();
rects[i].left = r.x;
rects[i].top = r.y;
rects[i].bottom = r.YMost();
rects[i].right = r.XMost();
i++;
}
params.pDirtyRects = params.DirtyRectsCount ? rects.data() : nullptr;
chain->Present1(presentInterval, mDisableSequenceForNextFrame ? DXGI_PRESENT_DO_NOT_SEQUENCE : 0, &params);
} else {
HRESULT hr = mSwapChain->Present(0, mDisableSequenceForNextFrame ? DXGI_PRESENT_DO_NOT_SEQUENCE : 0);
if (FAILED(hr)) {
gfxCriticalNote << "D3D11 swap chain preset failed " << hexa(hr);
HandleError(hr);
} }
} }
// Store the query for this frame so we can flush it next time.
mQuery = query;
Compositor::EndFrame(); if (mIsDoubleBuffered) {
mBackBufferInvalid = mFrontBufferInvalid;
mFrontBufferInvalid.SetEmpty();
} else {
mBackBufferInvalid.SetEmpty();
}
mCurrentRT = nullptr; mDisableSequenceForNextFrame = false;
} }
void void

View File

@ -40,6 +40,7 @@ struct PixelShaderConstants
}; };
struct DeviceAttachmentsD3D11; struct DeviceAttachmentsD3D11;
class DiagnosticsD3D11;
class CompositorD3D11 : public Compositor class CompositorD3D11 : public Compositor
{ {
@ -111,6 +112,8 @@ public:
gfx::IntRect *aClipRectOut = nullptr, gfx::IntRect *aClipRectOut = nullptr,
gfx::IntRect *aRenderBoundsOut = nullptr) override; gfx::IntRect *aRenderBoundsOut = nullptr) override;
void NormalDrawingDone() override;
/** /**
* Flush the current frame to the screen. * Flush the current frame to the screen.
*/ */
@ -207,6 +210,10 @@ private:
void Draw(const gfx::Rect& aGeometry, void Draw(const gfx::Rect& aGeometry,
const gfx::Rect* aTexCoords); const gfx::Rect* aTexCoords);
void GetFrameStats(GPUStats* aStats) override;
void Present();
ID3D11VertexShader* GetVSForGeometry(const nsTArray<gfx::TexturedTriangle>& aTriangles, ID3D11VertexShader* GetVSForGeometry(const nsTArray<gfx::TexturedTriangle>& aTriangles,
const bool aUseBlendShader, const bool aUseBlendShader,
const MaskType aMaskType); const MaskType aMaskType);
@ -227,6 +234,7 @@ private:
RefPtr<ID3D11Query> mQuery; RefPtr<ID3D11Query> mQuery;
DeviceAttachmentsD3D11* mAttachments; DeviceAttachmentsD3D11* mAttachments;
UniquePtr<DiagnosticsD3D11> mDiagnostics;
LayoutDeviceIntSize mSize; LayoutDeviceIntSize mSize;

View File

@ -0,0 +1,96 @@
/* -*- Mode: C++; tab-width: 20; 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/. */
#include "DiagnosticsD3D11.h"
#include "mozilla/layers/Diagnostics.h"
#include "mozilla/layers/HelpersD3D11.h"
namespace mozilla {
namespace layers {
DiagnosticsD3D11::DiagnosticsD3D11(ID3D11Device* aDevice, ID3D11DeviceContext* aContext)
: mDevice(aDevice),
mContext(aContext)
{
}
void
DiagnosticsD3D11::Start(uint32_t aPixelsPerFrame)
{
mPrevFrame = mCurrentFrame;
mCurrentFrame = FrameQueries();
CD3D11_QUERY_DESC desc(D3D11_QUERY_PIPELINE_STATISTICS);
mDevice->CreateQuery(&desc, getter_AddRefs(mCurrentFrame.stats));
if (mCurrentFrame.stats) {
mContext->Begin(mCurrentFrame.stats);
}
mCurrentFrame.pixelsPerFrame = aPixelsPerFrame;
desc = CD3D11_QUERY_DESC(D3D11_QUERY_TIMESTAMP_DISJOINT);
mDevice->CreateQuery(&desc, getter_AddRefs(mCurrentFrame.timing));
if (mCurrentFrame.timing) {
mContext->Begin(mCurrentFrame.timing);
}
desc = CD3D11_QUERY_DESC(D3D11_QUERY_TIMESTAMP);
mDevice->CreateQuery(&desc, getter_AddRefs(mCurrentFrame.frameBegin));
if (mCurrentFrame.frameBegin) {
mContext->End(mCurrentFrame.frameBegin);
}
}
void
DiagnosticsD3D11::End()
{
if (mCurrentFrame.stats) {
mContext->End(mCurrentFrame.stats);
}
if (mCurrentFrame.frameBegin) {
CD3D11_QUERY_DESC desc(D3D11_QUERY_TIMESTAMP);
mDevice->CreateQuery(&desc, getter_AddRefs(mCurrentFrame.frameEnd));
if (mCurrentFrame.frameEnd) {
mContext->End(mCurrentFrame.frameEnd);
}
}
if (mCurrentFrame.timing) {
mContext->End(mCurrentFrame.timing);
}
}
void
DiagnosticsD3D11::Cancel()
{
mCurrentFrame = FrameQueries();
}
void
DiagnosticsD3D11::Query(GPUStats* aStats)
{
// Collect pixel shader stats.
if (mPrevFrame.stats) {
D3D11_QUERY_DATA_PIPELINE_STATISTICS stats;
if (WaitForGPUQuery(mDevice, mContext, mPrevFrame.stats, &stats)) {
aStats->mInvalidPixels = mPrevFrame.pixelsPerFrame;
aStats->mPixelsFilled = uint32_t(stats.PSInvocations);
}
}
if (mPrevFrame.timing) {
UINT64 begin, end;
D3D11_QUERY_DATA_TIMESTAMP_DISJOINT timing;
if (WaitForGPUQuery(mDevice, mContext, mPrevFrame.timing, &timing) &&
!timing.Disjoint &&
WaitForGPUQuery(mDevice, mContext, mPrevFrame.frameBegin, &begin) &&
WaitForGPUQuery(mDevice, mContext, mPrevFrame.frameEnd, &end))
{
float timeMs = float(end - begin) / float(timing.Frequency) * 1000.0f;
aStats->mDrawTime = Some(timeMs);
}
}
}
} // namespace layers
} // namespace mozilla

View File

@ -0,0 +1,52 @@
/* -*- Mode: C++; tab-width: 20; 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/. */
#ifndef mozilla_gfx_layers_d3d11_DiagnosticsD3D11_h
#define mozilla_gfx_layers_d3d11_DiagnosticsD3D11_h
#include <stdint.h>
#include "mozilla/RefPtr.h"
#include <d3d11.h>
namespace mozilla {
namespace layers {
struct GPUStats;
class DiagnosticsD3D11
{
public:
DiagnosticsD3D11(ID3D11Device* aDevice, ID3D11DeviceContext* aContext);
void Start(uint32_t aPixelsPerFrame);
void End();
void Cancel();
void Query(GPUStats* aStats);
private:
RefPtr<ID3D11Device> mDevice;
RefPtr<ID3D11DeviceContext> mContext;
// When using the diagnostic overlay, we double-buffer some queries for
// frame statistics.
struct FrameQueries {
FrameQueries() : pixelsPerFrame(0)
{}
RefPtr<ID3D11Query> stats;
RefPtr<ID3D11Query> timing;
RefPtr<ID3D11Query> frameBegin;
RefPtr<ID3D11Query> frameEnd;
uint32_t pixelsPerFrame;
};
FrameQueries mPrevFrame;
FrameQueries mCurrentFrame;
};
} // namespace layers
} // namespace mozilla
#endif // mozilla_gfx_layers_d3d11_DiagnosticsD3D11_h

View File

@ -0,0 +1,34 @@
/* -*- Mode: C++; tab-width: 20; 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/. */
#ifndef mozilla_gfx_layers_d3d11_HelpersD3D11_h
#define mozilla_gfx_layers_d3d11_HelpersD3D11_h
#include <d3d11.h>
#include "mozilla/TimeStamp.h"
namespace mozilla {
namespace layers {
template <typename T> static inline bool
WaitForGPUQuery(ID3D11Device* aDevice, ID3D11DeviceContext* aContext, ID3D11Query* aQuery, T* aOut)
{
TimeStamp start = TimeStamp::Now();
while (aContext->GetData(aQuery, aOut, sizeof(*aOut), 0) != S_OK) {
if (aDevice->GetDeviceRemovedReason() != S_OK) {
return false;
}
if (TimeStamp::Now() - start > TimeDuration::FromSeconds(2)) {
return false;
}
Sleep(0);
}
return true;
}
} // namespace layers
} // namespace gfx
#endif // mozilla_gfx_layers_d3d11_HelpersD3D11_h

View File

@ -147,6 +147,10 @@ public:
uint32_t aApzcId) override; uint32_t aApzcId) override;
bool StopSharingMetrics(FrameMetrics::ViewID aScrollId, bool StopSharingMetrics(FrameMetrics::ViewID aScrollId,
uint32_t aApzcId) override; uint32_t aApzcId) override;
virtual bool IsRemote() const {
return false;
}
}; };
class CompositorBridgeParent final : public CompositorBridgeParentBase class CompositorBridgeParent final : public CompositorBridgeParentBase

View File

@ -161,6 +161,10 @@ public:
void ObserveLayerUpdate(uint64_t aLayersId, uint64_t aEpoch, bool aActive) override; void ObserveLayerUpdate(uint64_t aLayersId, uint64_t aEpoch, bool aActive) override;
bool IsRemote() const override {
return true;
}
protected: protected:
void OnChannelConnected(int32_t pid) override { void OnChannelConnected(int32_t pid) override {
mCompositorThreadHolder = CompositorThreadHolder::GetSingleton(); mCompositorThreadHolder = CompositorThreadHolder::GetSingleton();

View File

@ -149,9 +149,7 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo)
PROFILER_LABEL("LayerTransactionParent", "RecvUpdate", PROFILER_LABEL("LayerTransactionParent", "RecvUpdate",
js::ProfileEntry::Category::GRAPHICS); js::ProfileEntry::Category::GRAPHICS);
#ifdef COMPOSITOR_PERFORMANCE_WARNING
TimeStamp updateStart = TimeStamp::Now(); TimeStamp updateStart = TimeStamp::Now();
#endif
MOZ_LAYERS_LOG(("[ParentSide] received txn with %" PRIuSIZE " edits", aInfo.cset().Length())); MOZ_LAYERS_LOG(("[ParentSide] received txn with %" PRIuSIZE " edits", aInfo.cset().Length()));
@ -506,6 +504,8 @@ LayerTransactionParent::RecvUpdate(const TransactionInfo& aInfo)
OtherPid(), OtherPid(),
latency.ToMilliseconds()); latency.ToMilliseconds());
} }
mLayerManager->RecordUpdateTime((TimeStamp::Now() - updateStart).ToMilliseconds());
} }
return IPC_OK(); return IPC_OK();
@ -843,11 +843,7 @@ LayerTransactionParent::RecvGetAPZTestData(APZTestData* aOutData)
mozilla::ipc::IPCResult mozilla::ipc::IPCResult
LayerTransactionParent::RecvRequestProperty(const nsString& aProperty, float* aValue) LayerTransactionParent::RecvRequestProperty(const nsString& aProperty, float* aValue)
{ {
if (aProperty.Equals(NS_LITERAL_STRING("overdraw"))) { *aValue = -1;
*aValue = layer_manager()->GetCompositor()->GetFillRatio();
} else {
*aValue = -1;
}
return IPC_OK(); return IPC_OK();
} }
@ -1026,5 +1022,17 @@ LayerTransactionParent::RecvReleaseCompositable(const CompositableHandle& aHandl
return IPC_OK(); return IPC_OK();
} }
mozilla::ipc::IPCResult
LayerTransactionParent::RecvRecordPaintTimes(const PaintTiming& aTiming)
{
// Currently we only add paint timings for remote layers. In the future
// we could be smarter and use paint timings from the UI process, either
// as a separate overlay or if no remote layers are attached.
if (mLayerManager && mCompositorBridge->IsRemote()) {
mLayerManager->RecordPaintTimes(aTiming);
}
return IPC_OK();
}
} // namespace layers } // namespace layers
} // namespace mozilla } // namespace mozilla

View File

@ -140,6 +140,7 @@ protected:
virtual mozilla::ipc::IPCResult RecvRequestProperty(const nsString& aProperty, float* aValue) override; virtual mozilla::ipc::IPCResult RecvRequestProperty(const nsString& aProperty, float* aValue) override;
virtual mozilla::ipc::IPCResult RecvSetConfirmedTargetAPZC(const uint64_t& aBlockId, virtual mozilla::ipc::IPCResult RecvSetConfirmedTargetAPZC(const uint64_t& aBlockId,
nsTArray<ScrollableLayerGuid>&& aTargets) override; nsTArray<ScrollableLayerGuid>&& aTargets) override;
virtual mozilla::ipc::IPCResult RecvRecordPaintTimes(const PaintTiming& aTiming) override;
bool SetLayerAttributes(const OpSetLayerAttributes& aOp); bool SetLayerAttributes(const OpSetLayerAttributes& aOp);

View File

@ -534,6 +534,14 @@ union AsyncParentMessageData {
OpNotifyNotUsed; OpNotifyNotUsed;
}; };
struct PaintTiming {
float serializeMs;
float sendMs;
float dlMs;
float flbMs;
float rasterMs;
};
struct TransactionInfo struct TransactionInfo
{ {
Edit[] cset; Edit[] cset;

View File

@ -122,6 +122,8 @@ parent:
// input event. // input event.
async SetConfirmedTargetAPZC(uint64_t aInputBlockId, ScrollableLayerGuid[] aTargets); async SetConfirmedTargetAPZC(uint64_t aInputBlockId, ScrollableLayerGuid[] aTargets);
async RecordPaintTimes(PaintTiming timing);
async Shutdown(); async Shutdown();
child: child:
async __delete__(); async __delete__();

View File

@ -15,6 +15,7 @@
#include "RenderTrace.h" // for RenderTraceScope #include "RenderTrace.h" // for RenderTraceScope
#include "gfx2DGlue.h" // for Moz2D transition helpers #include "gfx2DGlue.h" // for Moz2D transition helpers
#include "gfxPlatform.h" // for gfxImageFormat, gfxPlatform #include "gfxPlatform.h" // for gfxImageFormat, gfxPlatform
#include "gfxPrefs.h"
//#include "gfxSharedImageSurface.h" // for gfxSharedImageSurface //#include "gfxSharedImageSurface.h" // for gfxSharedImageSurface
#include "ipc/IPCMessageUtils.h" // for gfxContentType, null_t #include "ipc/IPCMessageUtils.h" // for gfxContentType, null_t
#include "IPDLActor.h" #include "IPDLActor.h"
@ -586,6 +587,11 @@ ShadowLayerForwarder::EndTransaction(const nsIntRegion& aRegionToClear,
return false; return false;
} }
Maybe<TimeStamp> startTime;
if (gfxPrefs::LayersDrawFPS()) {
startTime = Some(TimeStamp::Now());
}
GetCompositorBridgeChild()->WillEndTransaction(); GetCompositorBridgeChild()->WillEndTransaction();
MOZ_ASSERT(aId); MOZ_ASSERT(aId);
@ -724,6 +730,11 @@ ShadowLayerForwarder::EndTransaction(const nsIntRegion& aRegionToClear,
PlatformSyncBeforeUpdate(); PlatformSyncBeforeUpdate();
} }
if (startTime) {
mPaintTiming.serializeMs() = (TimeStamp::Now() - startTime.value()).ToMilliseconds();
startTime = Some(TimeStamp::Now());
}
for (ReadLockVector& locks : mTxn->mReadLocks) { for (ReadLockVector& locks : mTxn->mReadLocks) {
if (locks.Length()) { if (locks.Length()) {
if (!mShadowManager->SendInitReadLocks(locks)) { if (!mShadowManager->SendInitReadLocks(locks)) {
@ -740,6 +751,11 @@ ShadowLayerForwarder::EndTransaction(const nsIntRegion& aRegionToClear,
return false; return false;
} }
if (startTime) {
mPaintTiming.sendMs() = (TimeStamp::Now() - startTime.value()).ToMilliseconds();
mShadowManager->SendRecordPaintTimes(mPaintTiming);
}
*aSent = true; *aSent = true;
mIsFirstPaint = false; mIsFirstPaint = false;
mPaintSyncId = 0; mPaintSyncId = 0;

View File

@ -392,6 +392,10 @@ public:
return NS_IsMainThread(); return NS_IsMainThread();
} }
PaintTiming& GetPaintTiming() {
return mPaintTiming;
}
// Returns true if aSurface wraps a Shmem. // Returns true if aSurface wraps a Shmem.
static bool IsShmem(SurfaceDescriptor* aSurface); static bool IsShmem(SurfaceDescriptor* aSurface);
@ -442,6 +446,7 @@ private:
UniquePtr<ActiveResourceTracker> mActiveResourceTracker; UniquePtr<ActiveResourceTracker> mActiveResourceTracker;
uint64_t mNextLayerHandle; uint64_t mNextLayerHandle;
nsDataHashtable<nsUint64HashKey, CompositableClient*> mCompositables; nsDataHashtable<nsUint64HashKey, CompositableClient*> mCompositables;
PaintTiming mPaintTiming;
}; };
class CompositableClient; class CompositableClient;

View File

@ -62,10 +62,13 @@ if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
if CONFIG['MOZ_ENABLE_D3D10_LAYER']: if CONFIG['MOZ_ENABLE_D3D10_LAYER']:
EXPORTS.mozilla.layers += [ EXPORTS.mozilla.layers += [
'd3d11/CompositorD3D11.h', 'd3d11/CompositorD3D11.h',
'd3d11/DiagnosticsD3D11.h',
'd3d11/HelpersD3D11.h',
'd3d11/ReadbackManagerD3D11.h', 'd3d11/ReadbackManagerD3D11.h',
'd3d11/TextureD3D11.h', 'd3d11/TextureD3D11.h',
] ]
UNIFIED_SOURCES += [ UNIFIED_SOURCES += [
'd3d11/DiagnosticsD3D11.cpp',
'd3d11/TextureD3D11.cpp', 'd3d11/TextureD3D11.cpp',
] ]
SOURCES += [ SOURCES += [
@ -132,6 +135,8 @@ EXPORTS.mozilla.layers += [
'composite/ColorLayerComposite.h', 'composite/ColorLayerComposite.h',
'composite/ContainerLayerComposite.h', 'composite/ContainerLayerComposite.h',
'composite/ContentHost.h', 'composite/ContentHost.h',
'composite/Diagnostics.h',
'composite/FPSCounter.h',
'composite/FrameUniformityData.h', 'composite/FrameUniformityData.h',
'composite/GPUVideoTextureHost.h', 'composite/GPUVideoTextureHost.h',
'composite/ImageComposite.h', 'composite/ImageComposite.h',
@ -316,6 +321,7 @@ UNIFIED_SOURCES += [
'composite/CompositableHost.cpp', 'composite/CompositableHost.cpp',
'composite/ContainerLayerComposite.cpp', 'composite/ContainerLayerComposite.cpp',
'composite/ContentHost.cpp', 'composite/ContentHost.cpp',
'composite/Diagnostics.cpp',
'composite/FPSCounter.cpp', 'composite/FPSCounter.cpp',
'composite/FrameUniformityData.cpp', 'composite/FrameUniformityData.cpp',
'composite/GPUVideoTextureHost.cpp', 'composite/GPUVideoTextureHost.cpp',

View File

@ -103,5 +103,11 @@ WebRenderCanvasLayer::AttachCompositable()
mCanvasClient->Connect(); mCanvasClient->Connect();
} }
CompositableForwarder*
WebRenderCanvasLayer::GetForwarder()
{
return Manager()->WrBridge();
}
} // namespace layers } // namespace layers
} // namespace mozilla } // namespace mozilla

View File

@ -29,10 +29,7 @@ public:
virtual void Initialize(const Data& aData) override; virtual void Initialize(const Data& aData) override;
virtual CompositableForwarder* GetForwarder() override virtual CompositableForwarder* GetForwarder() override;
{
return Manager()->WrBridge();
}
virtual void AttachCompositable() override; virtual void AttachCompositable() override;

View File

@ -6,6 +6,3 @@ fail-if = (os == "win" && os_version == "5.1" && e10s) # Bug 1253862
[test_bug509244.html] [test_bug509244.html]
[test_bug513439.html] [test_bug513439.html]
[test_font_whitelist.html] [test_font_whitelist.html]
[test_overdraw.html]
# Disable test until bug 1064136 is fixed
skip-if = true

View File

@ -1,23 +0,0 @@
<!DOCTYPE HTML>
<html>
<head>
<title>Test overdraw</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="application/javascript">
var domWindowUtils = SpecialPowers.getDOMWindowUtils(window);
var overdraw = domWindowUtils.requestCompositorProperty("overdraw");
if (overdraw == -1) {
// Overdraw queries are not supported on non OMTC builds.
ok(overdraw == -1, "Platform doesn't use a compositor.");
} else {
// Overdraw may be lower than 100% like on OS X where we don't
// composite the window corners.
ok(overdraw > 0.95 && overdraw < 200, "Overdraw: " + overdraw);
}
</script>
</body>

View File

@ -23,8 +23,11 @@
#include "nsIAsyncInputStream.h" #include "nsIAsyncInputStream.h"
#include "nsIAsyncOutputStream.h" #include "nsIAsyncOutputStream.h"
#include "nsIPipe.h" #include "nsIPipe.h"
#include "nsNetCID.h"
#include "nsStreamUtils.h" #include "nsStreamUtils.h"
using namespace mozilla::dom;
namespace mozilla { namespace mozilla {
namespace ipc { namespace ipc {

View File

@ -158,19 +158,27 @@ UNIFIED_SOURCES += [
'SharedMemory.cpp', 'SharedMemory.cpp',
'Shmem.cpp', 'Shmem.cpp',
'StringUtil.cpp', 'StringUtil.cpp',
'URIUtils.cpp',
] ]
# GeckoChildProcessHost.cpp cannot be built in unified mode because it uses plarena.h.
# URIUtils.cpp cannot be built in unified mode because of name clashes on strdup.
SOURCES += [ SOURCES += [
'BackgroundChildImpl.cpp', 'BackgroundChildImpl.cpp',
'BackgroundParentImpl.cpp', 'BackgroundParentImpl.cpp',
'FileDescriptorSetChild.cpp', 'FileDescriptorSetChild.cpp',
'FileDescriptorSetParent.cpp', 'FileDescriptorSetParent.cpp',
'GeckoChildProcessHost.cpp',
'URIUtils.cpp',
] ]
if CONFIG['OS_ARCH'] == 'Darwin':
# GeckoChildProcessHost.cpp cannot be built unified due to OSX header
# clashes with TextRange.
SOURCES += [
'GeckoChildProcessHost.cpp',
]
else:
UNIFIED_SOURCES += [
'GeckoChildProcessHost.cpp',
]
if CONFIG['_MSC_VER']: if CONFIG['_MSC_VER']:
# This is intended as a temporary hack to support building with VS2015. # This is intended as a temporary hack to support building with VS2015.
# 'reinterpret_cast': conversion from 'DWORD' to 'HANDLE' of greater size # 'reinterpret_cast': conversion from 'DWORD' to 'HANDLE' of greater size

View File

@ -159,7 +159,6 @@ class DataViewObject : public NativeObject
static bool fun_setFloat64(JSContext* cx, unsigned argc, Value* vp); static bool fun_setFloat64(JSContext* cx, unsigned argc, Value* vp);
static bool initClass(JSContext* cx); static bool initClass(JSContext* cx);
static void notifyBufferDetached(JSObject* view);
template<typename NativeType> template<typename NativeType>
static bool read(JSContext* cx, Handle<DataViewObject*> obj, const CallArgs& args, static bool read(JSContext* cx, Handle<DataViewObject*> obj, const CallArgs& args,
NativeType* val); NativeType* val);

View File

@ -390,8 +390,7 @@ ModuleNamespaceObject::ProxyHandler::getOwnPropertyDescriptor(JSContext* cx, Han
{ {
Rooted<ModuleNamespaceObject*> ns(cx, &proxy->as<ModuleNamespaceObject>()); Rooted<ModuleNamespaceObject*> ns(cx, &proxy->as<ModuleNamespaceObject>());
if (JSID_IS_SYMBOL(id)) { if (JSID_IS_SYMBOL(id)) {
Rooted<JS::Symbol*> symbol(cx, JSID_TO_SYMBOL(id)); if (JSID_TO_SYMBOL(id) == cx->wellKnownSymbols().toStringTag) {
if (symbol == cx->wellKnownSymbols().toStringTag) {
RootedValue value(cx, StringValue(cx->names().Module)); RootedValue value(cx, StringValue(cx->names().Module));
desc.object().set(proxy); desc.object().set(proxy);
desc.setWritable(false); desc.setWritable(false);
@ -437,8 +436,7 @@ ModuleNamespaceObject::ProxyHandler::has(JSContext* cx, HandleObject proxy, Hand
{ {
Rooted<ModuleNamespaceObject*> ns(cx, &proxy->as<ModuleNamespaceObject>()); Rooted<ModuleNamespaceObject*> ns(cx, &proxy->as<ModuleNamespaceObject>());
if (JSID_IS_SYMBOL(id)) { if (JSID_IS_SYMBOL(id)) {
Rooted<JS::Symbol*> symbol(cx, JSID_TO_SYMBOL(id)); *bp = JSID_TO_SYMBOL(id) == cx->wellKnownSymbols().toStringTag;
*bp = symbol == cx->wellKnownSymbols().toStringTag;
return true; return true;
} }
@ -452,8 +450,7 @@ ModuleNamespaceObject::ProxyHandler::get(JSContext* cx, HandleObject proxy, Hand
{ {
Rooted<ModuleNamespaceObject*> ns(cx, &proxy->as<ModuleNamespaceObject>()); Rooted<ModuleNamespaceObject*> ns(cx, &proxy->as<ModuleNamespaceObject>());
if (JSID_IS_SYMBOL(id)) { if (JSID_IS_SYMBOL(id)) {
Rooted<JS::Symbol*> symbol(cx, JSID_TO_SYMBOL(id)); if (JSID_TO_SYMBOL(id) == cx->wellKnownSymbols().toStringTag) {
if (symbol == cx->wellKnownSymbols().toStringTag) {
vp.setString(cx->names().Module); vp.setString(cx->names().Module);
return true; return true;
} }
@ -491,8 +488,15 @@ ModuleNamespaceObject::ProxyHandler::delete_(JSContext* cx, HandleObject proxy,
ObjectOpResult& result) const ObjectOpResult& result) const
{ {
Rooted<ModuleNamespaceObject*> ns(cx, &proxy->as<ModuleNamespaceObject>()); Rooted<ModuleNamespaceObject*> ns(cx, &proxy->as<ModuleNamespaceObject>());
if (JSID_IS_SYMBOL(id)) {
if (JSID_TO_SYMBOL(id) == cx->wellKnownSymbols().toStringTag)
return result.failCantDelete();
return result.succeed();
}
if (ns->bindings().has(id)) if (ns->bindings().has(id))
return result.failReadOnly(); return result.failCantDelete();
return result.succeed(); return result.succeed();
} }

View File

@ -5440,24 +5440,22 @@ BytecodeEmitter::setOrEmitSetFunName(ParseNode* maybeFun, HandleAtom name,
if (maybeFun->isKind(PNK_FUNCTION)) { if (maybeFun->isKind(PNK_FUNCTION)) {
// Function doesn't have 'name' property at this point. // Function doesn't have 'name' property at this point.
// Set function's name at compile time. // Set function's name at compile time.
RootedFunction fun(cx, maybeFun->pn_funbox->function()); JSFunction* fun = maybeFun->pn_funbox->function();
// Single node can be emitted multiple times if it appears in // Single node can be emitted multiple times if it appears in
// array destructuring default. If function already has a name, // array destructuring default. If function already has a name,
// just return. // just return.
if (fun->hasCompileTimeName()) { if (fun->hasCompileTimeName()) {
#ifdef DEBUG #ifdef DEBUG
RootedAtom funName(cx, NameToFunctionName(cx, name, prefixKind)); RootedFunction rootedFun(cx, fun);
JSAtom* funName = NameToFunctionName(cx, name, prefixKind);
if (!funName) if (!funName)
return false; return false;
MOZ_ASSERT(funName == maybeFun->pn_funbox->function()->compileTimeName()); MOZ_ASSERT(funName == rootedFun->compileTimeName());
#endif #endif
return true; return true;
} }
RootedAtom funName(cx, NameToFunctionName(cx, name, prefixKind));
if (!funName)
return false;
fun->setCompileTimeName(name); fun->setCompileTimeName(name);
return true; return true;
} }
@ -9146,28 +9144,23 @@ BytecodeEmitter::emitSelfHostedDefineDataProperty(ParseNode* pn)
} }
bool bool
BytecodeEmitter::isRestParameter(ParseNode* pn, bool* result) BytecodeEmitter::isRestParameter(ParseNode* pn)
{ {
if (!sc->isFunctionBox()) { if (!sc->isFunctionBox())
*result = false; return false;
return true;
}
FunctionBox* funbox = sc->asFunctionBox(); FunctionBox* funbox = sc->asFunctionBox();
RootedFunction fun(cx, funbox->function()); RootedFunction fun(cx, funbox->function());
if (!funbox->hasRest()) { if (!funbox->hasRest())
*result = false; return false;
return true;
}
if (!pn->isKind(PNK_NAME)) { if (!pn->isKind(PNK_NAME)) {
if (emitterMode == BytecodeEmitter::SelfHosting && pn->isKind(PNK_CALL)) { if (emitterMode == BytecodeEmitter::SelfHosting && pn->isKind(PNK_CALL)) {
ParseNode* pn2 = pn->pn_head; ParseNode* pn2 = pn->pn_head;
if (pn2->getKind() == PNK_NAME && pn2->name() == cx->names().allowContentIter) if (pn2->getKind() == PNK_NAME && pn2->name() == cx->names().allowContentIter)
return isRestParameter(pn2->pn_next, result); return isRestParameter(pn2->pn_next);
} }
*result = false; return false;
return true;
} }
JSAtom* name = pn->name(); JSAtom* name = pn->name();
@ -9178,12 +9171,11 @@ BytecodeEmitter::isRestParameter(ParseNode* pn, bool* result)
// |paramName| can be nullptr when the rest destructuring syntax is // |paramName| can be nullptr when the rest destructuring syntax is
// used: `function f(...[]) {}`. // used: `function f(...[]) {}`.
JSAtom* paramName = bindings->names[bindings->nonPositionalFormalStart - 1].name(); JSAtom* paramName = bindings->names[bindings->nonPositionalFormalStart - 1].name();
*result = paramName && name == paramName; return paramName && name == paramName;
return true;
} }
} }
return true; return false;
} }
bool bool
@ -9200,11 +9192,7 @@ BytecodeEmitter::emitOptimizeSpread(ParseNode* arg0, JumpList* jmp, bool* emitte
// skip spread operation and pass it directly to spread call operation. // skip spread operation and pass it directly to spread call operation.
// See the comment in OptimizeSpreadCall in Interpreter.cpp for the // See the comment in OptimizeSpreadCall in Interpreter.cpp for the
// optimizable conditons. // optimizable conditons.
bool result = false; if (!isRestParameter(arg0)) {
if (!isRestParameter(arg0, &result))
return false;
if (!result) {
*emitted = false; *emitted = false;
return true; return true;
} }

View File

@ -752,7 +752,7 @@ struct MOZ_STACK_CLASS BytecodeEmitter
MOZ_MUST_USE bool emitConditionalExpression(ConditionalExpression& conditional, MOZ_MUST_USE bool emitConditionalExpression(ConditionalExpression& conditional,
ValueUsage valueUsage = ValueUsage::WantValue); ValueUsage valueUsage = ValueUsage::WantValue);
MOZ_MUST_USE bool isRestParameter(ParseNode* pn, bool* result); bool isRestParameter(ParseNode* pn);
MOZ_MUST_USE bool emitOptimizeSpread(ParseNode* arg0, JumpList* jmp, bool* emitted); MOZ_MUST_USE bool emitOptimizeSpread(ParseNode* arg0, JumpList* jmp, bool* emitted);
MOZ_MUST_USE bool emitCallOrNew(ParseNode* pn, ValueUsage valueUsage = ValueUsage::WantValue); MOZ_MUST_USE bool emitCallOrNew(ParseNode* pn, ValueUsage valueUsage = ValueUsage::WantValue);

View File

@ -234,8 +234,8 @@ ToId(JSContext* cx, double index, MutableHandleId id)
* |*hole| to false. Otherwise set |*hole| to true and |vp| to Undefined. * |*hole| to false. Otherwise set |*hole| to true and |vp| to Undefined.
*/ */
static bool static bool
GetElement(JSContext* cx, HandleObject obj, HandleObject receiver, uint32_t index, bool* hole, HasAndGetElement(JSContext* cx, HandleObject obj, HandleObject receiver, uint32_t index,
MutableHandleValue vp) bool* hole, MutableHandleValue vp)
{ {
if (index < GetAnyBoxedOrUnboxedInitializedLength(obj)) { if (index < GetAnyBoxedOrUnboxedInitializedLength(obj)) {
vp.set(GetAnyBoxedOrUnboxedDenseElement(obj, index)); vp.set(GetAnyBoxedOrUnboxedDenseElement(obj, index));
@ -270,9 +270,10 @@ GetElement(JSContext* cx, HandleObject obj, HandleObject receiver, uint32_t inde
} }
static inline bool static inline bool
GetElement(JSContext* cx, HandleObject obj, uint32_t index, bool* hole, MutableHandleValue vp) HasAndGetElement(JSContext* cx, HandleObject obj, uint32_t index, bool* hole,
MutableHandleValue vp)
{ {
return GetElement(cx, obj, obj, index, hole, vp); return HasAndGetElement(cx, obj, obj, index, hole, vp);
} }
bool bool
@ -315,7 +316,7 @@ js::GetElementsWithAdder(JSContext* cx, HandleObject obj, HandleObject receiver,
for (uint32_t i = begin; i < end; i++) { for (uint32_t i = begin; i < end; i++) {
if (adder->getBehavior() == ElementAdder::CheckHasElemPreserveHoles) { if (adder->getBehavior() == ElementAdder::CheckHasElemPreserveHoles) {
bool hole; bool hole;
if (!GetElement(cx, obj, receiver, i, &hole, &val)) if (!HasAndGetElement(cx, obj, receiver, i, &hole, &val))
return false; return false;
if (hole) { if (hole) {
adder->appendHole(); adder->appendHole();
@ -1019,7 +1020,7 @@ array_toSource(JSContext* cx, unsigned argc, Value* vp)
for (uint32_t index = 0; index < length; index++) { for (uint32_t index = 0; index < length; index++) {
bool hole; bool hole;
if (!CheckForInterrupt(cx) || if (!CheckForInterrupt(cx) ||
!GetElement(cx, obj, index, &hole, &elt)) { !HasAndGetElement(cx, obj, index, &hole, &elt)) {
return false; return false;
} }
@ -1492,8 +1493,8 @@ js::array_reverse(JSContext* cx, unsigned argc, Value* vp)
for (uint32_t i = 0, half = len / 2; i < half; i++) { for (uint32_t i = 0, half = len / 2; i < half; i++) {
bool hole, hole2; bool hole, hole2;
if (!CheckForInterrupt(cx) || if (!CheckForInterrupt(cx) ||
!GetElement(cx, obj, i, &hole, &lowval) || !HasAndGetElement(cx, obj, i, &hole, &lowval) ||
!GetElement(cx, obj, len - i - 1, &hole2, &hival)) !HasAndGetElement(cx, obj, len - i - 1, &hole2, &hival))
{ {
return false; return false;
} }
@ -2035,7 +2036,7 @@ js::array_sort(JSContext* cx, unsigned argc, Value* vp)
return false; return false;
bool hole; bool hole;
if (!GetElement(cx, obj, i, &hole, &v)) if (!HasAndGetElement(cx, obj, i, &hole, &v))
return false; return false;
if (hole) if (hole)
continue; continue;
@ -2336,7 +2337,7 @@ js::array_shift(JSContext* cx, unsigned argc, Value* vp)
if (!CheckForInterrupt(cx)) if (!CheckForInterrupt(cx))
return false; return false;
bool hole; bool hole;
if (!GetElement(cx, obj, i + 1, &hole, &value)) if (!HasAndGetElement(cx, obj, i + 1, &hole, &value))
return false; return false;
if (hole) { if (hole) {
if (!DeletePropertyOrThrow(cx, obj, i)) if (!DeletePropertyOrThrow(cx, obj, i))
@ -2417,7 +2418,7 @@ js::array_unshift(JSContext* cx, unsigned argc, Value* vp)
if (!CheckForInterrupt(cx)) if (!CheckForInterrupt(cx))
return false; return false;
bool hole; bool hole;
if (!GetElement(cx, obj, last, &hole, &value)) if (!HasAndGetElement(cx, obj, last, &hole, &value))
return false; return false;
if (hole) { if (hole) {
if (!DeletePropertyOrThrow(cx, obj, upperIndex)) if (!DeletePropertyOrThrow(cx, obj, upperIndex))
@ -2496,7 +2497,7 @@ ArraySpliceCopy(JSContext* cx, HandleObject arr, HandleObject obj,
// Steps 11.b, 11.c.i. // Steps 11.b, 11.c.i.
bool hole; bool hole;
if (!GetElement(cx, obj, actualStart + k, &hole, &fromValue)) if (!HasAndGetElement(cx, obj, actualStart + k, &hole, &fromValue))
return false; return false;
// Step 11.c. // Step 11.c.
@ -2636,7 +2637,7 @@ array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueIsUse
/* Steps 15.b.iii, 15.b.iv.1. */ /* Steps 15.b.iii, 15.b.iv.1. */
bool hole; bool hole;
if (!GetElement(cx, obj, from, &hole, &fromValue)) if (!HasAndGetElement(cx, obj, from, &hole, &fromValue))
return false; return false;
/* Steps 15.b.iv. */ /* Steps 15.b.iv. */
@ -2720,7 +2721,7 @@ array_splice_impl(JSContext* cx, unsigned argc, Value* vp, bool returnValueIsUse
/* Steps 16.b.iii, 16.b.iv.1. */ /* Steps 16.b.iii, 16.b.iv.1. */
bool hole; bool hole;
if (!GetElement(cx, obj, from, &hole, &fromValue)) if (!HasAndGetElement(cx, obj, from, &hole, &fromValue))
return false; return false;
/* Steps 16.b.iv. */ /* Steps 16.b.iv. */
@ -2873,7 +2874,7 @@ SliceSlowly(JSContext* cx, HandleObject obj, uint32_t begin, uint32_t end, Handl
for (uint32_t slot = begin; slot < end; slot++) { for (uint32_t slot = begin; slot < end; slot++) {
bool hole; bool hole;
if (!CheckForInterrupt(cx) || if (!CheckForInterrupt(cx) ||
!GetElement(cx, obj, slot, &hole, &value)) !HasAndGetElement(cx, obj, slot, &hole, &value))
{ {
return false; return false;
} }
@ -2901,7 +2902,7 @@ SliceSparse(JSContext* cx, HandleObject obj, uint32_t begin, uint32_t end, Handl
MOZ_ASSERT(begin <= index && index < end); MOZ_ASSERT(begin <= index && index < end);
bool hole; bool hole;
if (!GetElement(cx, obj, index, &hole, &value)) if (!HasAndGetElement(cx, obj, index, &hole, &value))
return false; return false;
if (!hole && !DefineElement(cx, result, index - begin, value)) if (!hole && !DefineElement(cx, result, index - begin, value))
@ -3044,7 +3045,7 @@ js::array_slice(JSContext* cx, unsigned argc, Value* vp)
/* Steps 10.a-b, and 10.c.i. */ /* Steps 10.a-b, and 10.c.i. */
bool kNotPresent; bool kNotPresent;
if (!GetElement(cx, obj, k, &kNotPresent, &kValue)) if (!HasAndGetElement(cx, obj, k, &kNotPresent, &kValue))
return false; return false;
/* Step 10.c. */ /* Step 10.c. */

View File

@ -4363,8 +4363,15 @@ GetModuleLoadPath(JSContext* cx, unsigned argc, Value* vp)
CallArgs args = CallArgsFromVp(argc, vp); CallArgs args = CallArgsFromVp(argc, vp);
ShellContext* sc = GetShellContext(cx); ShellContext* sc = GetShellContext(cx);
MOZ_ASSERT(sc->moduleLoadPath); if (sc->moduleLoadPath) {
args.rval().setString(JS_NewStringCopyZ(cx, sc->moduleLoadPath.get())); JSString* str = JS_NewStringCopyZ(cx, sc->moduleLoadPath.get());
if (!str)
return false;
args.rval().setString(str);
} else {
args.rval().setNull();
}
return true; return true;
} }

View File

@ -39,6 +39,7 @@ skip script test262/built-ins/ThrowTypeError/unique-per-realm-function-proto.js
skip-if(!Array.prototype.values) script test262/built-ins/Array/prototype/Symbol.iterator.js skip-if(!Array.prototype.values) script test262/built-ins/Array/prototype/Symbol.iterator.js
skip-if(!Array.prototype.values) include test262/built-ins/Array/prototype/values/jstests.list skip-if(!Array.prototype.values) include test262/built-ins/Array/prototype/values/jstests.list
skip-if(!String.prototype.normalize) include test262/built-ins/String/prototype/normalize/jstests.list
# Async generator is non-release-or-beta only. # Async generator is non-release-or-beta only.
skip-if(release_or_beta) include test262/language/expressions/async-generators/jstests.list skip-if(release_or_beta) include test262/language/expressions/async-generators/jstests.list
@ -859,13 +860,16 @@ skip script test262/intl402/PluralRules/prototype/select/tainting.js
skip-if(!xulRuntime.shell) script test262/language/module-code/instn-iee-err-circular.js skip-if(!xulRuntime.shell) script test262/language/module-code/instn-iee-err-circular.js
skip-if(!xulRuntime.shell) script test262/language/module-code/instn-iee-err-circular-as.js skip-if(!xulRuntime.shell) script test262/language/module-code/instn-iee-err-circular-as.js
# Async generators are now a thing.
skip script test262/language/statements/async-function/early-errors-no-async-generator-n.js
# Need to be rewritten to follow the change in https://github.com/tc39/proposal-async-iteration/pull/92 ####################################################
# Tests disabled due to invalid test expectations #
####################################################
# https://github.com/tc39/test262/pull/947
skip script test262/language/statements/async-generator/yield-star-async-next.js skip script test262/language/statements/async-generator/yield-star-async-next.js
skip script test262/language/statements/async-generator/yield-star-async-return.js skip script test262/language/statements/async-generator/yield-star-async-return.js
skip script test262/language/statements/async-generator/yield-star-async-throw.js skip script test262/language/statements/async-generator/yield-star-async-throw.js
skip script test262/language/module-code/namespace/internals/delete-non-exported.js
# https://github.com/tc39/test262/pull/947 # https://github.com/tc39/test262/pull/947
skip script test262/intl402/NumberFormat/11.1.1_32.js skip script test262/intl402/NumberFormat/11.1.1_32.js

View File

@ -540,23 +540,6 @@ intrinsic_FinishBoundFunctionInit(JSContext* cx, unsigned argc, Value* vp)
return true; return true;
} }
static bool
intrinsic_SetPrototype(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 2);
MOZ_ASSERT(args[0].isObject());
MOZ_ASSERT(args[1].isObjectOrNull());
RootedObject obj(cx, &args[0].toObject());
RootedObject proto(cx, args[1].toObjectOrNull());
if (!SetPrototype(cx, obj, proto))
return false;
args.rval().setUndefined();
return true;
}
/* /*
* Used to decompile values in the nearest non-builtin stack frame, falling * Used to decompile values in the nearest non-builtin stack frame, falling
* back to decompiling in the current frame. Helpful for printing higher-order * back to decompiling in the current frame. Helpful for printing higher-order
@ -703,34 +686,6 @@ intrinsic_UnsafeGetBooleanFromReservedSlot(JSContext* cx, unsigned argc, Value*
return true; return true;
} }
/**
* Intrinsic for creating an empty array in the compartment of the object
* passed as the first argument.
*
* Returns the array, wrapped in the default wrapper to use between the two
* compartments.
*/
static bool
intrinsic_NewArrayInCompartment(JSContext* cx, unsigned argc, Value* vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
MOZ_ASSERT(args.length() == 1);
RootedObject wrapped(cx, &args[0].toObject());
MOZ_ASSERT(IsWrapper(wrapped));
RootedObject obj(cx, UncheckedUnwrap(wrapped));
RootedArrayObject arr(cx);
{
AutoCompartment ac(cx, obj);
arr = NewDenseEmptyArray(cx);
if (!arr)
return false;
}
args.rval().setObject(*arr);
return wrapped->compartment()->wrap(cx, args.rval());
}
static bool static bool
intrinsic_IsPackedArray(JSContext* cx, unsigned argc, Value* vp) intrinsic_IsPackedArray(JSContext* cx, unsigned argc, Value* vp)
{ {
@ -2314,8 +2269,6 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_INLINABLE_FN("std_Math_max", math_max, 2,0, MathMax), JS_INLINABLE_FN("std_Math_max", math_max, 2,0, MathMax),
JS_INLINABLE_FN("std_Math_min", math_min, 2,0, MathMin), JS_INLINABLE_FN("std_Math_min", math_min, 2,0, MathMin),
JS_INLINABLE_FN("std_Math_abs", math_abs, 1,0, MathAbs), JS_INLINABLE_FN("std_Math_abs", math_abs, 1,0, MathAbs),
JS_INLINABLE_FN("std_Math_imul", math_imul, 2,0, MathImul),
JS_INLINABLE_FN("std_Math_log2", math_log2, 1,0, MathLog2),
JS_FN("std_Map_has", MapObject::has, 1,0), JS_FN("std_Map_has", MapObject::has, 1,0),
JS_FN("std_Map_iterator", MapObject::entries, 0,0), JS_FN("std_Map_iterator", MapObject::entries, 0,0),
@ -2328,7 +2281,6 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_FN("std_Object_getOwnPropertyNames", obj_getOwnPropertyNames, 1,0), JS_FN("std_Object_getOwnPropertyNames", obj_getOwnPropertyNames, 1,0),
JS_FN("std_Object_getOwnPropertyDescriptor", obj_getOwnPropertyDescriptor, 2,0), JS_FN("std_Object_getOwnPropertyDescriptor", obj_getOwnPropertyDescriptor, 2,0),
JS_FN("std_Object_hasOwnProperty", obj_hasOwnProperty, 1,0), JS_FN("std_Object_hasOwnProperty", obj_hasOwnProperty, 1,0),
JS_FN("std_Object_setPrototypeOf", intrinsic_SetPrototype, 2,0),
JS_FN("std_Object_toString", obj_toString, 0,0), JS_FN("std_Object_toString", obj_toString, 0,0),
JS_FN("std_Reflect_getPrototypeOf", Reflect_getPrototypeOf, 1,0), JS_FN("std_Reflect_getPrototypeOf", Reflect_getPrototypeOf, 1,0),
@ -2393,7 +2345,6 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_INLINABLE_FN("IsCallable", intrinsic_IsCallable, 1,0, IntrinsicIsCallable), JS_INLINABLE_FN("IsCallable", intrinsic_IsCallable, 1,0, IntrinsicIsCallable),
JS_INLINABLE_FN("IsConstructor", intrinsic_IsConstructor, 1,0, JS_INLINABLE_FN("IsConstructor", intrinsic_IsConstructor, 1,0,
IntrinsicIsConstructor), IntrinsicIsConstructor),
JS_FN("IsFunctionObject",intrinsic_IsInstanceOfBuiltin<JSFunction>, 1,0),
JS_FN("GetBuiltinConstructorImpl", intrinsic_GetBuiltinConstructor, 1,0), JS_FN("GetBuiltinConstructorImpl", intrinsic_GetBuiltinConstructor, 1,0),
JS_FN("MakeConstructible", intrinsic_MakeConstructible, 2,0), JS_FN("MakeConstructible", intrinsic_MakeConstructible, 2,0),
JS_FN("_ConstructFunction", intrinsic_ConstructFunction, 2,0), JS_FN("_ConstructFunction", intrinsic_ConstructFunction, 2,0),
@ -2432,8 +2383,6 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_INLINABLE_FN("UnsafeGetBooleanFromReservedSlot", intrinsic_UnsafeGetBooleanFromReservedSlot,2,0, JS_INLINABLE_FN("UnsafeGetBooleanFromReservedSlot", intrinsic_UnsafeGetBooleanFromReservedSlot,2,0,
IntrinsicUnsafeGetBooleanFromReservedSlot), IntrinsicUnsafeGetBooleanFromReservedSlot),
JS_FN("NewArrayInCompartment", intrinsic_NewArrayInCompartment, 1,0),
JS_FN("IsPackedArray", intrinsic_IsPackedArray, 1,0), JS_FN("IsPackedArray", intrinsic_IsPackedArray, 1,0),
JS_FN("GetIteratorPrototype", intrinsic_GetIteratorPrototype, 0,0), JS_FN("GetIteratorPrototype", intrinsic_GetIteratorPrototype, 0,0),
@ -2564,10 +2513,6 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_FN("CallWeakSetMethodIfWrapped", JS_FN("CallWeakSetMethodIfWrapped",
CallNonGenericSelfhostedMethod<Is<WeakSetObject>>, 2, 0), CallNonGenericSelfhostedMethod<Is<WeakSetObject>>, 2, 0),
JS_FN("Promise_static_resolve", Promise_static_resolve, 1, 0),
JS_FN("Promise_static_reject", Promise_reject, 1, 0),
JS_FN("Promise_then", Promise_then, 2, 0),
// See builtin/TypedObject.h for descriptors of the typedobj functions. // See builtin/TypedObject.h for descriptors of the typedobj functions.
JS_FN("NewOpaqueTypedObject", js::NewOpaqueTypedObject, 1, 0), JS_FN("NewOpaqueTypedObject", js::NewOpaqueTypedObject, 1, 0),
JS_FN("NewDerivedTypedObject", js::NewDerivedTypedObject, 3, 0), JS_FN("NewDerivedTypedObject", js::NewDerivedTypedObject, 3, 0),

View File

@ -3672,6 +3672,14 @@ nsLayoutUtils::PaintFrame(nsRenderingContext* aRenderingContext, nsIFrame* aFram
} }
builder.LeavePresShell(aFrame, &list); builder.LeavePresShell(aFrame, &list);
if (!record.GetStart().IsNull() && gfxPrefs::LayersDrawFPS()) {
if (RefPtr<LayerManager> lm = builder.GetWidgetLayerManager()) {
if (PaintTiming* pt = ClientLayerManager::MaybeGetPaintTiming(lm)) {
pt->dlMs() = (TimeStamp::Now() - record.GetStart()).ToMilliseconds();
}
}
}
} }
Telemetry::AccumulateTimeDelta(Telemetry::PAINT_BUILD_DISPLAYLIST_TIME, Telemetry::AccumulateTimeDelta(Telemetry::PAINT_BUILD_DISPLAYLIST_TIME,

View File

@ -83,6 +83,7 @@
#include "nsCSSProps.h" #include "nsCSSProps.h"
#include "nsPluginFrame.h" #include "nsPluginFrame.h"
#include "nsSVGMaskFrame.h" #include "nsSVGMaskFrame.h"
#include "ClientLayerManager.h"
#include "mozilla/layers/WebRenderBridgeChild.h" #include "mozilla/layers/WebRenderBridgeChild.h"
#include "mozilla/layers/WebRenderLayerManager.h" #include "mozilla/layers/WebRenderLayerManager.h"
#include "mozilla/layers/WebRenderDisplayItemLayer.h" #include "mozilla/layers/WebRenderDisplayItemLayer.h"
@ -2115,9 +2116,16 @@ already_AddRefed<LayerManager> nsDisplayList::PaintRoot(nsDisplayListBuilder* aB
{ {
PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::Layerization); PaintTelemetry::AutoRecord record(PaintTelemetry::Metric::Layerization);
root = layerBuilder-> root = layerBuilder->
BuildContainerLayerFor(aBuilder, layerManager, frame, nullptr, this, BuildContainerLayerFor(aBuilder, layerManager, frame, nullptr, this,
containerParameters, nullptr); containerParameters, nullptr);
if (!record.GetStart().IsNull() && gfxPrefs::LayersDrawFPS()) {
if (PaintTiming* pt = ClientLayerManager::MaybeGetPaintTiming(layerManager)) {
pt->flbMs() = (TimeStamp::Now() - record.GetStart()).ToMilliseconds();
}
}
} }
if (!root) { if (!root) {

View File

@ -4922,6 +4922,10 @@ class PaintTelemetry
public: public:
explicit AutoRecord(Metric aMetric); explicit AutoRecord(Metric aMetric);
~AutoRecord(); ~AutoRecord();
TimeStamp GetStart() const {
return mStart;
}
private: private:
Metric mMetric; Metric mMetric;
mozilla::TimeStamp mStart; mozilla::TimeStamp mStart;

View File

@ -3,6 +3,7 @@ ar
as as
ast ast
az az
bg
bn-IN bn-IN
br br
ca ca
@ -42,6 +43,7 @@ is
it it
ja ja
ka ka
kab
kk kk
kn kn
ko ko

View File

@ -50,7 +50,7 @@ RustURL::~RustURL()
NS_IMETHODIMP NS_IMETHODIMP
RustURL::GetSpec(nsACString & aSpec) RustURL::GetSpec(nsACString & aSpec)
{ {
return static_cast<nsresult>(rusturl_get_spec(mURL.get(), &aSpec)); return rusturl_get_spec(mURL.get(), &aSpec);
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -103,7 +103,7 @@ RustURL::GetPrePath(nsACString & aPrePath)
NS_IMETHODIMP NS_IMETHODIMP
RustURL::GetScheme(nsACString & aScheme) RustURL::GetScheme(nsACString & aScheme)
{ {
return static_cast<nsresult>(rusturl_get_scheme(mURL.get(), &aScheme)); return rusturl_get_scheme(mURL.get(), &aScheme);
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -111,7 +111,7 @@ RustURL::SetScheme(const nsACString & aScheme)
{ {
ENSURE_MUTABLE(); ENSURE_MUTABLE();
return static_cast<nsresult>(rusturl_set_scheme(mURL.get(), &aScheme)); return rusturl_set_scheme(mURL.get(), &aScheme);
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -152,42 +152,44 @@ RustURL::SetUserPass(const nsACString & aUserPass)
pass = Substring(aUserPass, colonPos + 1, aUserPass.Length()); pass = Substring(aUserPass, colonPos + 1, aUserPass.Length());
} }
if (rusturl_set_username(mURL.get(), &user) != 0) { nsresult rv = rusturl_set_username(mURL.get(), &user);
return NS_ERROR_FAILURE; if (NS_WARN_IF(NS_FAILED(rv))) {
return rv;
} }
return static_cast<nsresult>(rusturl_set_password(mURL.get(), &pass));
return rusturl_set_password(mURL.get(), &pass);
} }
NS_IMETHODIMP NS_IMETHODIMP
RustURL::GetUsername(nsACString & aUsername) RustURL::GetUsername(nsACString & aUsername)
{ {
return static_cast<nsresult>(rusturl_get_username(mURL.get(), &aUsername)); return rusturl_get_username(mURL.get(), &aUsername);
} }
NS_IMETHODIMP NS_IMETHODIMP
RustURL::SetUsername(const nsACString & aUsername) RustURL::SetUsername(const nsACString & aUsername)
{ {
ENSURE_MUTABLE(); ENSURE_MUTABLE();
return static_cast<nsresult>(rusturl_set_username(mURL.get(), &aUsername)); return rusturl_set_username(mURL.get(), &aUsername);
} }
NS_IMETHODIMP NS_IMETHODIMP
RustURL::GetPassword(nsACString & aPassword) RustURL::GetPassword(nsACString & aPassword)
{ {
return static_cast<nsresult>(rusturl_get_password(mURL.get(), &aPassword)); return rusturl_get_password(mURL.get(), &aPassword);
} }
NS_IMETHODIMP NS_IMETHODIMP
RustURL::SetPassword(const nsACString & aPassword) RustURL::SetPassword(const nsACString & aPassword)
{ {
ENSURE_MUTABLE(); ENSURE_MUTABLE();
return static_cast<nsresult>(rusturl_set_password(mURL.get(), &aPassword)); return rusturl_set_password(mURL.get(), &aPassword);
} }
NS_IMETHODIMP NS_IMETHODIMP
RustURL::GetHostPort(nsACString & aHostPort) RustURL::GetHostPort(nsACString & aHostPort)
{ {
nsresult rv = (nsresult) rusturl_get_host(mURL.get(), &aHostPort); nsresult rv = rusturl_get_host(mURL.get(), &aHostPort);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
return rv; return rv;
} }
@ -209,21 +211,21 @@ NS_IMETHODIMP
RustURL::SetHostPort(const nsACString & aHostPort) RustURL::SetHostPort(const nsACString & aHostPort)
{ {
ENSURE_MUTABLE(); ENSURE_MUTABLE();
return static_cast<nsresult>(rusturl_set_host_port(mURL.get(), &aHostPort)); return rusturl_set_host_port(mURL.get(), &aHostPort);
} }
NS_IMETHODIMP NS_IMETHODIMP
RustURL::SetHostAndPort(const nsACString & hostport) RustURL::SetHostAndPort(const nsACString & hostport)
{ {
ENSURE_MUTABLE(); ENSURE_MUTABLE();
return static_cast<nsresult>(rusturl_set_host_and_port(mURL.get(), &hostport)); return rusturl_set_host_and_port(mURL.get(), &hostport);
} }
NS_IMETHODIMP NS_IMETHODIMP
RustURL::GetHost(nsACString & aHost) RustURL::GetHost(nsACString & aHost)
{ {
nsAutoCString host; nsAutoCString host;
nsresult rv = (nsresult) rusturl_get_host(mURL.get(), &host); nsresult rv = rusturl_get_host(mURL.get(), &host);
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
return rv; return rv;
} }
@ -241,7 +243,7 @@ NS_IMETHODIMP
RustURL::SetHost(const nsACString & aHost) RustURL::SetHost(const nsACString & aHost)
{ {
ENSURE_MUTABLE(); ENSURE_MUTABLE();
return static_cast<nsresult>(rusturl_set_host(mURL.get(), &aHost)); return rusturl_set_host(mURL.get(), &aHost);
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -250,21 +252,21 @@ RustURL::GetPort(int32_t *aPort)
if (!mURL) { if (!mURL) {
return NS_ERROR_FAILURE; return NS_ERROR_FAILURE;
} }
*aPort = rusturl_get_port(mURL.get()); *aPort = 0;
return NS_OK; return rusturl_get_port(mURL.get(), aPort);
} }
NS_IMETHODIMP NS_IMETHODIMP
RustURL::SetPort(int32_t aPort) RustURL::SetPort(int32_t aPort)
{ {
ENSURE_MUTABLE(); ENSURE_MUTABLE();
return static_cast<nsresult>(rusturl_set_port_no(mURL.get(), aPort)); return rusturl_set_port_no(mURL.get(), aPort);
} }
NS_IMETHODIMP NS_IMETHODIMP
RustURL::GetPath(nsACString & aPath) RustURL::GetPath(nsACString & aPath)
{ {
return static_cast<nsresult>(rusturl_get_path(mURL.get(), &aPath)); return rusturl_get_path(mURL.get(), &aPath);
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -341,7 +343,7 @@ RustURL::Clone(nsIURI * *aRetVal)
NS_IMETHODIMP NS_IMETHODIMP
RustURL::Resolve(const nsACString & relativePath, nsACString & aRetVal) RustURL::Resolve(const nsACString & relativePath, nsACString & aRetVal)
{ {
return static_cast<nsresult>(rusturl_resolve(mURL.get(), &relativePath, &aRetVal)); return rusturl_resolve(mURL.get(), &relativePath, &aRetVal);
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -372,14 +374,14 @@ RustURL::GetOriginCharset(nsACString & aOriginCharset)
NS_IMETHODIMP NS_IMETHODIMP
RustURL::GetRef(nsACString & aRef) RustURL::GetRef(nsACString & aRef)
{ {
return static_cast<nsresult>(rusturl_get_fragment(mURL.get(), &aRef)); return rusturl_get_fragment(mURL.get(), &aRef);
} }
NS_IMETHODIMP NS_IMETHODIMP
RustURL::SetRef(const nsACString & aRef) RustURL::SetRef(const nsACString & aRef)
{ {
ENSURE_MUTABLE(); ENSURE_MUTABLE();
return static_cast<nsresult>(rusturl_set_fragment(mURL.get(), &aRef)); return rusturl_set_fragment(mURL.get(), &aRef);
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -444,13 +446,7 @@ NS_IMETHODIMP
RustURL::GetHasRef(bool *aHasRef) RustURL::GetHasRef(bool *aHasRef)
{ {
*aHasRef = false; *aHasRef = false;
int32_t rv = rusturl_has_fragment(mURL.get()); return rusturl_has_fragment(mURL.get(), aHasRef);
if (rv == 1) {
*aHasRef = true;
} else if (rv < 0) {
return static_cast<nsresult>(rv);
}
return NS_OK;
} }
/// nsIURL /// nsIURL
@ -458,27 +454,27 @@ RustURL::GetHasRef(bool *aHasRef)
NS_IMETHODIMP NS_IMETHODIMP
RustURL::GetFilePath(nsACString & aFilePath) RustURL::GetFilePath(nsACString & aFilePath)
{ {
return static_cast<nsresult>(rusturl_get_path(mURL.get(), &aFilePath)); return rusturl_get_path(mURL.get(), &aFilePath);
} }
NS_IMETHODIMP NS_IMETHODIMP
RustURL::SetFilePath(const nsACString & aFilePath) RustURL::SetFilePath(const nsACString & aFilePath)
{ {
ENSURE_MUTABLE(); ENSURE_MUTABLE();
return static_cast<nsresult>(rusturl_set_path(mURL.get(), &aFilePath)); return rusturl_set_path(mURL.get(), &aFilePath);
} }
NS_IMETHODIMP NS_IMETHODIMP
RustURL::GetQuery(nsACString & aQuery) RustURL::GetQuery(nsACString & aQuery)
{ {
return static_cast<nsresult>(rusturl_get_query(mURL.get(), &aQuery)); return rusturl_get_query(mURL.get(), &aQuery);
} }
NS_IMETHODIMP NS_IMETHODIMP
RustURL::SetQuery(const nsACString & aQuery) RustURL::SetQuery(const nsACString & aQuery)
{ {
ENSURE_MUTABLE(); ENSURE_MUTABLE();
return static_cast<nsresult>(rusturl_set_query(mURL.get(), &aQuery)); return rusturl_set_query(mURL.get(), &aQuery);
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -546,7 +542,7 @@ RustURL::GetCommonBaseSpec(nsIURI *aURIToCompare, nsACString & _retval)
if (NS_FAILED(rv)) { if (NS_FAILED(rv)) {
return rv; return rv;
} }
return static_cast<nsresult>(rusturl_common_base_spec(mURL.get(), url->mURL.get(), &_retval)); return rusturl_common_base_spec(mURL.get(), url->mURL.get(), &_retval);
} }
NS_IMETHODIMP NS_IMETHODIMP
@ -563,7 +559,7 @@ RustURL::GetRelativeSpec(nsIURI *aURIToCompare, nsACString & _retval)
return rv; return rv;
} }
return static_cast<nsresult>(rusturl_relative_spec(mURL.get(), url->mURL.get(), &_retval)); return rusturl_relative_spec(mURL.get(), url->mURL.get(), &_retval);
} }
// nsIFileURL // nsIFileURL

View File

@ -10,3 +10,4 @@ name = "rust_url_capi"
libc = "0.2.0" libc = "0.2.0"
url = "1.4.0" url = "1.4.0"
nsstring = { path = "../../../xpcom/rust/nsstring" } nsstring = { path = "../../../xpcom/rust/nsstring" }
nserror = { path = "../../../xpcom/rust/nserror" }

View File

@ -1,61 +0,0 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
use url::ParseError;
pub trait ErrorCode {
fn error_code(&self) -> i32;
}
impl<T: ErrorCode> ErrorCode for Result<(), T> {
fn error_code(&self) -> i32 {
match *self {
Ok(_) => 0,
Err(ref error) => error.error_code(),
}
}
}
impl ErrorCode for Result<(), ()> {
fn error_code(&self) -> i32 {
match *self {
Ok(_) => 0,
Err(_) => -255,
}
}
}
impl ErrorCode for ParseError {
fn error_code(&self) -> i32 {
match *self {
ParseError::EmptyHost => -1,
ParseError::InvalidPort => -2,
ParseError::InvalidIpv6Address => -3,
ParseError::InvalidDomainCharacter => -4,
ParseError::IdnaError => -5,
ParseError::InvalidIpv4Address => -6,
ParseError::RelativeUrlWithoutBase => -7,
ParseError::RelativeUrlWithCannotBeABaseBase => -8,
ParseError::SetHostOnCannotBeABaseUrl => -9,
ParseError::Overflow => -10,
}
}
}
pub enum NSError {
OK,
InvalidArg,
Failure,
}
impl ErrorCode for NSError {
#[allow(overflowing_literals)]
fn error_code(&self) -> i32 {
match *self {
NSError::OK => 0,
NSError::InvalidArg => 0x80070057,
NSError::Failure => 0x80004005
}
}
}

View File

@ -4,7 +4,7 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
extern crate url; extern crate url;
use url::{Url, ParseError, ParseOptions, Position}; use url::{Url, ParseOptions, Position};
use url::quirks; use url::quirks;
extern crate libc; extern crate libc;
@ -13,14 +13,13 @@ use libc::size_t;
extern crate nsstring; extern crate nsstring;
use nsstring::nsACString; use nsstring::nsACString;
extern crate nserror;
use nserror::*;
use std::mem; use std::mem;
use std::str; use std::str;
use std::ptr; use std::ptr;
mod error_mapping;
use error_mapping::*;
fn parser<'a>() -> ParseOptions<'a> { fn parser<'a>() -> ParseOptions<'a> {
Url::options() Url::options()
} }
@ -62,35 +61,35 @@ pub unsafe extern "C" fn rusturl_free(urlptr: *mut Url) {
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn rusturl_get_spec(urlptr: Option<&Url>, cont: &mut nsACString) -> i32 { pub extern "C" fn rusturl_get_spec(urlptr: Option<&Url>, cont: &mut nsACString) -> nsresult {
let url = if let Some(url) = urlptr { let url = if let Some(url) = urlptr {
url url
} else { } else {
return NSError::InvalidArg.error_code(); return NS_ERROR_INVALID_ARG;
}; };
cont.assign(url.as_ref()); cont.assign(url.as_ref());
NSError::OK.error_code() NS_OK
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn rusturl_get_scheme(urlptr: Option<&Url>, cont: &mut nsACString) -> i32 { pub extern "C" fn rusturl_get_scheme(urlptr: Option<&Url>, cont: &mut nsACString) -> nsresult {
let url = if let Some(url) = urlptr { let url = if let Some(url) = urlptr {
url url
} else { } else {
return NSError::InvalidArg.error_code(); return NS_ERROR_INVALID_ARG;
}; };
cont.assign(&url.scheme()); cont.assign(&url.scheme());
NSError::OK.error_code() NS_OK
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn rusturl_get_username(urlptr: Option<&Url>, cont: &mut nsACString) -> i32 { pub extern "C" fn rusturl_get_username(urlptr: Option<&Url>, cont: &mut nsACString) -> nsresult {
let url = if let Some(url) = urlptr { let url = if let Some(url) = urlptr {
url url
} else { } else {
return NSError::InvalidArg.error_code(); return NS_ERROR_INVALID_ARG;
}; };
if url.cannot_be_a_base() { if url.cannot_be_a_base() {
@ -98,53 +97,59 @@ pub extern "C" fn rusturl_get_username(urlptr: Option<&Url>, cont: &mut nsACStri
} else { } else {
cont.assign(url.username()); cont.assign(url.username());
} }
NSError::OK.error_code() NS_OK
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn rusturl_get_password(urlptr: Option<&Url>, cont: &mut nsACString) -> i32 { pub extern "C" fn rusturl_get_password(urlptr: Option<&Url>, cont: &mut nsACString) -> nsresult {
let url = if let Some(url) = urlptr { let url = if let Some(url) = urlptr {
url url
} else { } else {
return NSError::InvalidArg.error_code(); return NS_ERROR_INVALID_ARG;
}; };
cont.assign(url.password().unwrap_or("")); cont.assign(url.password().unwrap_or(""));
NSError::OK.error_code() NS_OK
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn rusturl_get_host(urlptr: Option<&Url>, cont: &mut nsACString) -> i32 { pub extern "C" fn rusturl_get_host(urlptr: Option<&Url>, cont: &mut nsACString) -> nsresult {
let url = if let Some(url) = urlptr { let url = if let Some(url) = urlptr {
url url
} else { } else {
return NSError::InvalidArg.error_code(); return NS_ERROR_INVALID_ARG;
}; };
cont.assign(url.host_str().unwrap_or("")); cont.assign(url.host_str().unwrap_or(""));
NSError::OK.error_code() NS_OK
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn rusturl_get_port(urlptr: Option<&Url>) -> i32 { pub extern "C" fn rusturl_get_port(urlptr: Option<&Url>, port: &mut i32) -> nsresult {
let url = if let Some(url) = urlptr { let url = if let Some(url) = urlptr {
url url
} else { } else {
return NSError::InvalidArg.error_code(); return NS_ERROR_INVALID_ARG;
}; };
match url.port() { match url.port() {
Some(port) => port as i32, Some(p) => {
None => -1 *port = p as i32;
}
None => {
// NOTE: Gecko uses -1 to represent the default port
*port = -1;
}
} }
NS_OK
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn rusturl_get_path(urlptr: Option<&Url>, cont: &mut nsACString) -> i32 { pub extern "C" fn rusturl_get_path(urlptr: Option<&Url>, cont: &mut nsACString) -> nsresult {
let url = if let Some(url) = urlptr { let url = if let Some(url) = urlptr {
url url
} else { } else {
return NSError::InvalidArg.error_code(); return NS_ERROR_INVALID_ARG;
}; };
if url.cannot_be_a_base() { if url.cannot_be_a_base() {
@ -152,250 +157,274 @@ pub extern "C" fn rusturl_get_path(urlptr: Option<&Url>, cont: &mut nsACString)
} else { } else {
cont.assign(&url[Position::BeforePath..]); cont.assign(&url[Position::BeforePath..]);
} }
NSError::OK.error_code() NS_OK
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn rusturl_get_query(urlptr: Option<&Url>, cont: &mut nsACString) -> i32 { pub extern "C" fn rusturl_get_query(urlptr: Option<&Url>, cont: &mut nsACString) -> nsresult {
let url = if let Some(url) = urlptr { let url = if let Some(url) = urlptr {
url url
} else { } else {
return NSError::InvalidArg.error_code(); return NS_ERROR_INVALID_ARG;
}; };
cont.assign(url.query().unwrap_or("")); cont.assign(url.query().unwrap_or(""));
NSError::OK.error_code() NS_OK
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn rusturl_get_fragment(urlptr: Option<&Url>, cont: &mut nsACString) -> i32 { pub extern "C" fn rusturl_get_fragment(urlptr: Option<&Url>, cont: &mut nsACString) -> nsresult {
let url = if let Some(url) = urlptr { let url = if let Some(url) = urlptr {
url url
} else { } else {
return NSError::InvalidArg.error_code(); return NS_ERROR_INVALID_ARG;
}; };
cont.assign(url.fragment().unwrap_or("")); cont.assign(url.fragment().unwrap_or(""));
NSError::OK.error_code() NS_OK
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn rusturl_has_fragment(urlptr: Option<&Url>) -> i32 { pub extern "C" fn rusturl_has_fragment(urlptr: Option<&Url>, has_fragment: &mut bool) -> nsresult {
let url = if let Some(url) = urlptr { let url = if let Some(url) = urlptr {
url url
} else { } else {
return NSError::InvalidArg.error_code(); return NS_ERROR_INVALID_ARG;
}; };
url.fragment().is_some() as i32 *has_fragment = url.fragment().is_some();
NS_OK
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn rusturl_set_scheme(urlptr: Option<&mut Url>, scheme: &nsACString) -> i32 { pub extern "C" fn rusturl_set_scheme(urlptr: Option<&mut Url>, scheme: &nsACString) -> nsresult {
let url = if let Some(url) = urlptr { let url = if let Some(url) = urlptr {
url url
} else { } else {
return NSError::InvalidArg.error_code(); return NS_ERROR_INVALID_ARG;
}; };
let scheme_ = match str::from_utf8(scheme) { let scheme_ = match str::from_utf8(scheme) {
Ok(p) => p, Ok(p) => p,
Err(_) => return ParseError::InvalidDomainCharacter.error_code() // utf-8 failed Err(_) => return NS_ERROR_MALFORMED_URI, // utf-8 failed
}; };
quirks::set_protocol(url, scheme_).error_code() match quirks::set_protocol(url, scheme_) {
Ok(()) => NS_OK,
Err(()) => NS_ERROR_MALFORMED_URI,
}
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn rusturl_set_username(urlptr: Option<&mut Url>, username: &nsACString) -> i32 { pub extern "C" fn rusturl_set_username(urlptr: Option<&mut Url>, username: &nsACString) -> nsresult {
let url = if let Some(url) = urlptr { let url = if let Some(url) = urlptr {
url url
} else { } else {
return NSError::InvalidArg.error_code(); return NS_ERROR_INVALID_ARG;
}; };
let username_ = match str::from_utf8(username) { let username_ = match str::from_utf8(username) {
Ok(p) => p, Ok(p) => p,
Err(_) => return ParseError::InvalidDomainCharacter.error_code() // utf-8 failed Err(_) => return NS_ERROR_MALFORMED_URI, // utf-8 failed
}; };
quirks::set_username(url, username_).error_code() match quirks::set_protocol(url, username_) {
Ok(()) => NS_OK,
Err(()) => NS_ERROR_MALFORMED_URI,
}
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn rusturl_set_password(urlptr: Option<&mut Url>, password: &nsACString) -> i32 { pub extern "C" fn rusturl_set_password(urlptr: Option<&mut Url>, password: &nsACString) -> nsresult {
let url = if let Some(url) = urlptr { let url = if let Some(url) = urlptr {
url url
} else { } else {
return NSError::InvalidArg.error_code(); return NS_ERROR_INVALID_ARG;
}; };
let password_ = match str::from_utf8(password) { let password_ = match str::from_utf8(password) {
Ok(p) => p, Ok(p) => p,
Err(_) => return ParseError::InvalidDomainCharacter.error_code() // utf-8 failed Err(_) => return NS_ERROR_MALFORMED_URI, // utf-8 failed
}; };
quirks::set_password(url, password_).error_code() match quirks::set_password(url, password_) {
Ok(()) => NS_OK,
Err(()) => NS_ERROR_MALFORMED_URI,
}
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn rusturl_set_host_port(urlptr: Option<&mut Url>, host_port: &nsACString) -> i32 { pub extern "C" fn rusturl_set_host_port(urlptr: Option<&mut Url>, host_port: &nsACString) -> nsresult {
let url = if let Some(url) = urlptr { let url = if let Some(url) = urlptr {
url url
} else { } else {
return NSError::InvalidArg.error_code(); return NS_ERROR_INVALID_ARG;
}; };
let host_port_ = match str::from_utf8(host_port) { let host_port_ = match str::from_utf8(host_port) {
Ok(p) => p, Ok(p) => p,
Err(_) => return ParseError::InvalidDomainCharacter.error_code() // utf-8 failed Err(_) => return NS_ERROR_MALFORMED_URI, // utf-8 failed
}; };
quirks::set_host(url, host_port_).error_code() match quirks::set_host(url, host_port_) {
Ok(()) => NS_OK,
Err(()) => NS_ERROR_MALFORMED_URI,
}
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn rusturl_set_host_and_port(urlptr: Option<&mut Url>, host_and_port: &nsACString) -> i32 { pub extern "C" fn rusturl_set_host_and_port(urlptr: Option<&mut Url>, host_and_port: &nsACString) -> nsresult {
let url = if let Some(url) = urlptr { let url = if let Some(url) = urlptr {
url url
} else { } else {
return NSError::InvalidArg.error_code(); return NS_ERROR_INVALID_ARG;
}; };
let _ = url.set_port(None); let _ = url.set_port(None);
let host_and_port_ = match str::from_utf8(host_and_port) { let host_and_port_ = match str::from_utf8(host_and_port) {
Ok(p) => p, Ok(p) => p,
Err(_) => return ParseError::InvalidDomainCharacter.error_code() // utf-8 failed Err(_) => return NS_ERROR_MALFORMED_URI, // utf-8 failed
}; };
quirks::set_host(url, host_and_port_).error_code() match quirks::set_host(url, host_and_port_) {
} Ok(()) => NS_OK,
Err(()) => NS_ERROR_MALFORMED_URI,
#[no_mangle]
pub extern "C" fn rusturl_set_host(urlptr: Option<&mut Url>, host: &nsACString) -> i32 {
let url = if let Some(url) = urlptr {
url
} else {
return NSError::InvalidArg.error_code();
};
let hostname = match str::from_utf8(host) {
Ok(h) => h,
Err(_) => return ParseError::InvalidDomainCharacter.error_code() // utf-8 failed
};
quirks::set_hostname(url, hostname).error_code()
}
#[no_mangle]
pub extern "C" fn rusturl_set_port(urlptr: Option<&mut Url>, port: &nsACString) -> i32 {
let url = if let Some(url) = urlptr {
url
} else {
return NSError::InvalidArg.error_code();
};
let port_ = match str::from_utf8(port) {
Ok(p) => p,
Err(_) => return ParseError::InvalidDomainCharacter.error_code() // utf-8 failed
};
quirks::set_port(url, port_).error_code()
}
#[no_mangle]
pub extern "C" fn rusturl_set_port_no(urlptr: Option<&mut Url>, new_port: i32) -> i32 {
let url = if let Some(url) = urlptr {
url
} else {
return NSError::InvalidArg.error_code();
};
if url.cannot_be_a_base() {
-100
} else {
if url.scheme() == "file" {
return -100;
}
match default_port(url.scheme()) {
Some(def_port) => if new_port == def_port as i32 {
let _ = url.set_port(None);
return NSError::OK.error_code();
},
None => {}
};
if new_port > std::u16::MAX as i32 || new_port < 0 {
let _ = url.set_port(None);
} else {
let _ = url.set_port(Some(new_port as u16));
}
NSError::OK.error_code()
} }
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn rusturl_set_path(urlptr: Option<&mut Url>, path: &nsACString) -> i32 { pub extern "C" fn rusturl_set_host(urlptr: Option<&mut Url>, host: &nsACString) -> nsresult {
let url = if let Some(url) = urlptr { let url = if let Some(url) = urlptr {
url url
} else { } else {
return NSError::InvalidArg.error_code(); return NS_ERROR_INVALID_ARG;
};
let hostname = match str::from_utf8(host) {
Ok(h) => h,
Err(_) => return NS_ERROR_MALFORMED_URI, // utf-8 failed
};
match quirks::set_hostname(url, hostname) {
Ok(()) => NS_OK,
Err(()) => NS_ERROR_MALFORMED_URI,
}
}
#[no_mangle]
pub extern "C" fn rusturl_set_port(urlptr: Option<&mut Url>, port: &nsACString) -> nsresult {
let url = if let Some(url) = urlptr {
url
} else {
return NS_ERROR_INVALID_ARG;
};
let port_ = match str::from_utf8(port) {
Ok(p) => p,
Err(_) => return NS_ERROR_MALFORMED_URI, // utf-8 failed
};
match quirks::set_port(url, port_) {
Ok(()) => NS_OK,
Err(()) => NS_ERROR_MALFORMED_URI,
}
}
#[no_mangle]
pub extern "C" fn rusturl_set_port_no(urlptr: Option<&mut Url>, new_port: i32) -> nsresult {
let url = if let Some(url) = urlptr {
url
} else {
return NS_ERROR_INVALID_ARG;
};
if url.cannot_be_a_base() {
return NS_ERROR_MALFORMED_URI;
}
if url.scheme() == "file" {
return NS_ERROR_MALFORMED_URI;
}
match default_port(url.scheme()) {
Some(def_port) => if new_port == def_port as i32 {
let _ = url.set_port(None);
return NS_OK;
},
None => {}
};
if new_port > std::u16::MAX as i32 || new_port < 0 {
let _ = url.set_port(None);
} else {
let _ = url.set_port(Some(new_port as u16));
}
NS_OK
}
#[no_mangle]
pub extern "C" fn rusturl_set_path(urlptr: Option<&mut Url>, path: &nsACString) -> nsresult {
let url = if let Some(url) = urlptr {
url
} else {
return NS_ERROR_INVALID_ARG;
}; };
let path_ = match str::from_utf8(path) { let path_ = match str::from_utf8(path) {
Ok(p) => p, Ok(p) => p,
Err(_) => return ParseError::InvalidDomainCharacter.error_code() // utf-8 failed Err(_) => return NS_ERROR_MALFORMED_URI, // utf-8 failed
}; };
quirks::set_pathname(url, path_); quirks::set_pathname(url, path_);
NSError::OK.error_code() NS_OK
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn rusturl_set_query(urlptr: Option<&mut Url>, query: &nsACString) -> i32 { pub extern "C" fn rusturl_set_query(urlptr: Option<&mut Url>, query: &nsACString) -> nsresult {
let url = if let Some(url) = urlptr { let url = if let Some(url) = urlptr {
url url
} else { } else {
return NSError::InvalidArg.error_code(); return NS_ERROR_INVALID_ARG;
}; };
let query_ = match str::from_utf8(query) { let query_ = match str::from_utf8(query) {
Ok(p) => p, Ok(p) => p,
Err(_) => return ParseError::InvalidDomainCharacter.error_code() // utf-8 failed Err(_) => return NS_ERROR_MALFORMED_URI, // utf-8 failed
}; };
quirks::set_search(url, query_); quirks::set_search(url, query_);
NSError::OK.error_code() NS_OK
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn rusturl_set_fragment(urlptr: Option<&mut Url>, fragment: &nsACString) -> i32 { pub extern "C" fn rusturl_set_fragment(urlptr: Option<&mut Url>, fragment: &nsACString) -> nsresult {
let url = if let Some(url) = urlptr { let url = if let Some(url) = urlptr {
url url
} else { } else {
return NSError::InvalidArg.error_code(); return NS_ERROR_INVALID_ARG;
}; };
let fragment_ = match str::from_utf8(fragment) { let fragment_ = match str::from_utf8(fragment) {
Ok(p) => p, Ok(p) => p,
Err(_) => return ParseError::InvalidDomainCharacter.error_code() // utf-8 failed Err(_) => return NS_ERROR_MALFORMED_URI, // utf-8 failed
}; };
quirks::set_hash(url, fragment_); quirks::set_hash(url, fragment_);
NSError::OK.error_code() NS_OK
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn rusturl_resolve(urlptr: Option<&Url>, resolve: &nsACString, cont: &mut nsACString) -> i32 { pub extern "C" fn rusturl_resolve(urlptr: Option<&Url>, resolve: &nsACString, cont: &mut nsACString) -> nsresult {
let url = if let Some(url) = urlptr { let url = if let Some(url) = urlptr {
url url
} else { } else {
return NSError::InvalidArg.error_code(); return NS_ERROR_INVALID_ARG;
}; };
let resolve_ = match str::from_utf8(resolve) { let resolve_ = match str::from_utf8(resolve) {
Ok(p) => p, Ok(p) => p,
Err(_) => return NSError::Failure.error_code() Err(_) => return NS_ERROR_FAILURE,
}; };
if let Ok(ref u) = parser().base_url(Some(&url)).parse(resolve_) { if let Ok(ref u) = parser().base_url(Some(&url)).parse(resolve_) {
@ -403,22 +432,22 @@ pub extern "C" fn rusturl_resolve(urlptr: Option<&Url>, resolve: &nsACString, co
} else { } else {
cont.assign(""); cont.assign("");
} }
NSError::OK.error_code() NS_OK
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn rusturl_common_base_spec(urlptr1: Option<&Url>, urlptr2: Option<&Url>, cont: &mut nsACString) -> i32 { pub extern "C" fn rusturl_common_base_spec(urlptr1: Option<&Url>, urlptr2: Option<&Url>, cont: &mut nsACString) -> nsresult {
let (url1, url2) = if let (Some(url1), Some(url2)) = (urlptr1, urlptr2) { let (url1, url2) = if let (Some(url1), Some(url2)) = (urlptr1, urlptr2) {
(url1, url2) (url1, url2)
} else { } else {
return NSError::InvalidArg.error_code(); return NS_ERROR_INVALID_ARG;
}; };
cont.assign(""); cont.assign("");
if url1 == url2 { if url1 == url2 {
cont.assign(url1.as_ref()); cont.assign(url1.as_ref());
return NSError::OK.error_code(); return NS_OK;
} }
if url1.scheme() != url2.scheme() || if url1.scheme() != url2.scheme() ||
@ -426,16 +455,16 @@ pub extern "C" fn rusturl_common_base_spec(urlptr1: Option<&Url>, urlptr2: Optio
url1.username() != url2.username() || url1.username() != url2.username() ||
url1.password() != url2.password() || url1.password() != url2.password() ||
url1.port() != url2.port() { url1.port() != url2.port() {
return NSError::OK.error_code(); return NS_OK;
} }
let path1 = match url1.path_segments() { let path1 = match url1.path_segments() {
Some(path) => path, Some(path) => path,
None => return NSError::OK.error_code(), None => return NS_OK,
}; };
let path2 = match url2.path_segments() { let path2 = match url2.path_segments() {
Some(path) => path, Some(path) => path,
None => return NSError::OK.error_code(), None => return NS_OK,
}; };
let mut url = url1.clone(); let mut url = url1.clone();
@ -445,7 +474,7 @@ pub extern "C" fn rusturl_common_base_spec(urlptr1: Option<&Url>, urlptr2: Optio
let mut new_segments = if let Ok(segments) = url.path_segments_mut() { let mut new_segments = if let Ok(segments) = url.path_segments_mut() {
segments segments
} else { } else {
return NSError::OK.error_code(); return NS_OK;
}; };
for (p1, p2) in path1.zip(path2) { for (p1, p2) in path1.zip(path2) {
@ -458,21 +487,21 @@ pub extern "C" fn rusturl_common_base_spec(urlptr1: Option<&Url>, urlptr2: Optio
} }
cont.assign(url.as_ref()); cont.assign(url.as_ref());
NSError::OK.error_code() NS_OK
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn rusturl_relative_spec(urlptr1: Option<&Url>, urlptr2: Option<&Url>, cont: &mut nsACString) -> i32 { pub extern "C" fn rusturl_relative_spec(urlptr1: Option<&Url>, urlptr2: Option<&Url>, cont: &mut nsACString) -> nsresult {
let (url1, url2) = if let (Some(url1), Some(url2)) = (urlptr1, urlptr2) { let (url1, url2) = if let (Some(url1), Some(url2)) = (urlptr1, urlptr2) {
(url1, url2) (url1, url2)
} else { } else {
return NSError::InvalidArg.error_code(); return NS_ERROR_INVALID_ARG;
}; };
cont.assign(""); cont.assign("");
if url1 == url2 { if url1 == url2 {
return NSError::OK.error_code(); return NS_OK;
} }
if url1.scheme() != url2.scheme() || if url1.scheme() != url2.scheme() ||
@ -481,21 +510,21 @@ pub extern "C" fn rusturl_relative_spec(urlptr1: Option<&Url>, urlptr2: Option<&
url1.password() != url2.password() || url1.password() != url2.password() ||
url1.port() != url2.port() { url1.port() != url2.port() {
cont.assign(url2.as_ref()); cont.assign(url2.as_ref());
return NSError::OK.error_code(); return NS_OK;
} }
let mut path1 = match url1.path_segments() { let mut path1 = match url1.path_segments() {
Some(path) => path, Some(path) => path,
None => { None => {
cont.assign(url2.as_ref()); cont.assign(url2.as_ref());
return NSError::OK.error_code() return NS_OK;
} }
}; };
let mut path2 = match url2.path_segments() { let mut path2 = match url2.path_segments() {
Some(path) => path, Some(path) => path,
None => { None => {
cont.assign(url2.as_ref()); cont.assign(url2.as_ref());
return NSError::OK.error_code() return NS_OK;
} }
}; };
@ -518,7 +547,7 @@ pub extern "C" fn rusturl_relative_spec(urlptr1: Option<&Url>, urlptr2: Option<&
} }
cont.assign(&buffer); cont.assign(&buffer);
NSError::OK.error_code() NS_OK
} }
#[no_mangle] #[no_mangle]
@ -527,17 +556,18 @@ pub extern "C" fn sizeof_rusturl() -> size_t {
} }
#[no_mangle] #[no_mangle]
pub extern "C" fn rusturl_parse_ipv6addr(input: &nsACString, cont: &mut nsACString) -> i32 { pub extern "C" fn rusturl_parse_ipv6addr(input: &nsACString, cont: &mut nsACString) -> nsresult {
let ip6 = match str::from_utf8(input) { let ip6 = match str::from_utf8(input) {
Ok(content) => content, Ok(content) => content,
Err(_) => return ParseError::InvalidDomainCharacter.error_code() Err(_) => return NS_ERROR_FAILURE,
}; };
let h = match url::Host::parse(ip6) { let h = match url::Host::parse(ip6) {
Ok(host) => host, Ok(host) => host,
Err(e) => return e.error_code() // XXX: Do we want to change our error message based on the error type?
Err(_) => return NS_ERROR_MALFORMED_URI,
}; };
cont.assign(&h.to_string()); cont.assign(&h.to_string());
NSError::OK.error_code() NS_OK
} }

View File

@ -11,6 +11,8 @@ extern "C" {
// NOTE: Preconditions // NOTE: Preconditions
// * All nsACString* pointers are unchecked, and must be non-null // * All nsACString* pointers are unchecked, and must be non-null
// * The int32_t* and bool* outparameter pointer is unchecked, and must
// be non-null.
// * All rusturl* pointers must refer to pointers which are returned // * All rusturl* pointers must refer to pointers which are returned
// by rusturl_new, and must be freed with rusturl_free. // by rusturl_new, and must be freed with rusturl_free.
@ -20,34 +22,34 @@ struct rusturl;
rusturl* rusturl_new(const nsACString* spec); rusturl* rusturl_new(const nsACString* spec);
/* unsafe */ void rusturl_free(rusturl* url); /* unsafe */ void rusturl_free(rusturl* url);
int32_t rusturl_get_spec(const rusturl* url, nsACString* cont); nsresult rusturl_get_spec(const rusturl* url, nsACString* cont);
int32_t rusturl_get_scheme(const rusturl* url, nsACString* cont); nsresult rusturl_get_scheme(const rusturl* url, nsACString* cont);
int32_t rusturl_get_username(const rusturl* url, nsACString* cont); nsresult rusturl_get_username(const rusturl* url, nsACString* cont);
int32_t rusturl_get_password(const rusturl* url, nsACString* cont); nsresult rusturl_get_password(const rusturl* url, nsACString* cont);
int32_t rusturl_get_host(const rusturl* url, nsACString* cont); nsresult rusturl_get_host(const rusturl* url, nsACString* cont);
int32_t rusturl_get_port(const rusturl* url); // returns port or -1 nsresult rusturl_get_port(const rusturl* url, int32_t* port);
int32_t rusturl_get_path(const rusturl* url, nsACString* cont); nsresult rusturl_get_path(const rusturl* url, nsACString* cont);
int32_t rusturl_get_query(const rusturl* url, nsACString* cont); nsresult rusturl_get_query(const rusturl* url, nsACString* cont);
int32_t rusturl_get_fragment(const rusturl* url, nsACString* cont); nsresult rusturl_get_fragment(const rusturl* url, nsACString* cont);
int32_t rusturl_has_fragment(const rusturl* url); // 1 true, 0 false, < 0 error nsresult rusturl_has_fragment(const rusturl* url, bool* has_fragment);
int32_t rusturl_set_scheme(rusturl* url, const nsACString* scheme); nsresult rusturl_set_scheme(rusturl* url, const nsACString* scheme);
int32_t rusturl_set_username(rusturl* url, const nsACString* user); nsresult rusturl_set_username(rusturl* url, const nsACString* user);
int32_t rusturl_set_password(rusturl* url, const nsACString* password); nsresult rusturl_set_password(rusturl* url, const nsACString* password);
int32_t rusturl_set_host_port(rusturl* url, const nsACString* hostport); nsresult rusturl_set_host_port(rusturl* url, const nsACString* hostport);
int32_t rusturl_set_host_and_port(rusturl* url, const nsACString* hostport); nsresult rusturl_set_host_and_port(rusturl* url, const nsACString* hostport);
int32_t rusturl_set_host(rusturl* url, const nsACString* host); nsresult rusturl_set_host(rusturl* url, const nsACString* host);
int32_t rusturl_set_port(rusturl* url, const nsACString* port); nsresult rusturl_set_port(rusturl* url, const nsACString* port);
int32_t rusturl_set_port_no(rusturl* url, const int32_t port); nsresult rusturl_set_port_no(rusturl* url, const int32_t port);
int32_t rusturl_set_path(rusturl* url, const nsACString* path); nsresult rusturl_set_path(rusturl* url, const nsACString* path);
int32_t rusturl_set_query(rusturl* url, const nsACString* query); nsresult rusturl_set_query(rusturl* url, const nsACString* query);
int32_t rusturl_set_fragment(rusturl* url, const nsACString* fragment); nsresult rusturl_set_fragment(rusturl* url, const nsACString* fragment);
int32_t rusturl_resolve(const rusturl* url, const nsACString* relative, nsACString* cont); nsresult rusturl_resolve(const rusturl* url, const nsACString* relative, nsACString* cont);
int32_t rusturl_common_base_spec(const rusturl* url1, const rusturl* url2, nsACString* cont); nsresult rusturl_common_base_spec(const rusturl* url1, const rusturl* url2, nsACString* cont);
int32_t rusturl_relative_spec(const rusturl* url1, const rusturl* url2, nsACString* cont); nsresult rusturl_relative_spec(const rusturl* url1, const rusturl* url2, nsACString* cont);
int32_t rusturl_parse_ipv6addr(const nsACString* input, nsACString* cont); nsresult rusturl_parse_ipv6addr(const nsACString* input, nsACString* cont);
size_t sizeof_rusturl(); size_t sizeof_rusturl();

View File

@ -202,7 +202,7 @@ FTPChannelChild::AsyncOpen(::nsIStreamListener* listener, nsISupports* aContext)
NS_ENSURE_SUCCESS(rv, rv); NS_ENSURE_SUCCESS(rv, rv);
// This must happen before the constructor message is sent. // This must happen before the constructor message is sent.
EnsureDispatcher(); EnsureNeckoTarget();
gNeckoChild-> gNeckoChild->
SendPFTPChannelConstructor(this, tabChild, IPC::SerializedLoadContext(this), SendPFTPChannelConstructor(this, tabChild, IPC::SerializedLoadContext(this),
@ -547,7 +547,8 @@ class nsFtpChildAsyncAlert : public Runnable
{ {
public: public:
nsFtpChildAsyncAlert(nsIPrompt *aPrompter, nsString aResponseMsg) nsFtpChildAsyncAlert(nsIPrompt *aPrompter, nsString aResponseMsg)
: mPrompter(aPrompter) : Runnable("nsFtpChildAsyncAlert")
, mPrompter(aPrompter)
, mResponseMsg(aResponseMsg) , mResponseMsg(aResponseMsg)
{ {
} }
@ -643,12 +644,11 @@ FTPChannelChild::DoOnStopRequest(const nsresult& aChannelStatus,
NS_ConvertASCIItoUTF16(aErrorMsg)); NS_ConvertASCIItoUTF16(aErrorMsg));
} }
if (mDispatcher) { if (mNeckoTarget) {
mDispatcher->Dispatch("FTPAlertEvent", mNeckoTarget->Dispatch(alertEvent.forget(),
TaskCategory::Other, nsIEventTarget::DISPATCH_NORMAL);
alertEvent.forget());
} else { } else {
// In case |mDispatcher| is null, dispatch by SystemGroup. // In case |mNeckoTarget| is null, dispatch by SystemGroup.
SystemGroup::Dispatch("FTPAlertEvent", SystemGroup::Dispatch("FTPAlertEvent",
TaskCategory::Other, TaskCategory::Other,
alertEvent.forget()); alertEvent.forget());
@ -886,7 +886,7 @@ FTPChannelChild::ConnectParent(uint32_t id)
} }
// This must happen before the constructor message is sent. // This must happen before the constructor message is sent.
EnsureDispatcher(); EnsureNeckoTarget();
// The socket transport in the chrome process now holds a logical ref to us // The socket transport in the chrome process now holds a logical ref to us
// until OnStopRequest, or we do a redirect, or we hit an IPDL error. // until OnStopRequest, or we do a redirect, or we hit an IPDL error.
@ -993,25 +993,21 @@ FTPChannelChild::GetDivertingToParent(bool* aDiverting)
} }
void void
FTPChannelChild::EnsureDispatcher() FTPChannelChild::EnsureNeckoTarget()
{ {
if (mDispatcher) { if (mNeckoTarget) {
return; return;
} }
nsCOMPtr<nsILoadInfo> loadInfo; nsCOMPtr<nsILoadInfo> loadInfo;
GetLoadInfo(getter_AddRefs(loadInfo)); GetLoadInfo(getter_AddRefs(loadInfo));
mDispatcher = nsContentUtils::GetDispatcherByLoadInfo(loadInfo); mNeckoTarget = nsContentUtils::GetEventTargetByLoadInfo(loadInfo, TaskCategory::Network);
if (!mDispatcher) { if (!mNeckoTarget) {
return; return;
} }
nsCOMPtr<nsIEventTarget> target = gNeckoChild->SetEventTargetForActor(this, mNeckoTarget);
mDispatcher->EventTargetFor(TaskCategory::Network);
gNeckoChild->SetEventTargetForActor(this, target);
mNeckoTarget = target;
} }
already_AddRefed<nsIEventTarget> already_AddRefed<nsIEventTarget>

View File

@ -23,9 +23,9 @@
#include "nsIStreamListener.h" #include "nsIStreamListener.h"
#include "PrivateBrowsingChannel.h" #include "PrivateBrowsingChannel.h"
namespace mozilla { class nsIEventTarget;
class Dispatcher; namespace mozilla {
namespace net { namespace net {
@ -162,9 +162,7 @@ private:
// EventTarget for labeling networking events. // EventTarget for labeling networking events.
nsCOMPtr<nsIEventTarget> mNeckoTarget; nsCOMPtr<nsIEventTarget> mNeckoTarget;
RefPtr<Dispatcher> mDispatcher; void EnsureNeckoTarget();
void EnsureDispatcher();
}; };
inline bool inline bool

View File

@ -946,7 +946,7 @@ AltSvcCache::GetAltServiceMapping(const nsACString &scheme, const nsACString &ho
// DataStorage gives synchronous access to a memory based hash table // DataStorage gives synchronous access to a memory based hash table
// that is backed by disk where those writes are done asynchronously // that is backed by disk where those writes are done asynchronously
// on another thread // on another thread
mStorage = DataStorage::Get(NS_LITERAL_STRING("AlternateServices.txt")); mStorage = DataStorage::Get(DataStorageClass::AlternateServices);
if (mStorage) { if (mStorage) {
bool storageWillPersist = false; bool storageWillPersist = false;
if (NS_FAILED(mStorage->Init(storageWillPersist))) { if (NS_FAILED(mStorage->Init(storageWillPersist))) {

View File

@ -2231,24 +2231,13 @@ HttpChannelChild::SetEventTarget()
nsCOMPtr<nsILoadInfo> loadInfo; nsCOMPtr<nsILoadInfo> loadInfo;
GetLoadInfo(getter_AddRefs(loadInfo)); GetLoadInfo(getter_AddRefs(loadInfo));
RefPtr<Dispatcher> dispatcher = nsCOMPtr<nsIEventTarget> target =
nsContentUtils::GetDispatcherByLoadInfo(loadInfo); nsContentUtils::GetEventTargetByLoadInfo(loadInfo, TaskCategory::Network);
if (!dispatcher) { if (!target) {
return; return;
} }
#ifdef DEBUG
if (dispatcher->AsTabGroup()) {
// We have a TabGroup. This must be a top-level load.
bool isMainDocumentChannel;
GetIsMainDocumentChannel(&isMainDocumentChannel);
MOZ_ASSERT(isMainDocumentChannel);
}
#endif
nsCOMPtr<nsIEventTarget> target =
dispatcher->EventTargetFor(TaskCategory::Network);
gNeckoChild->SetEventTargetForActor(this, target); gNeckoChild->SetEventTargetForActor(this, target);
{ {

View File

@ -52,7 +52,7 @@ public:
nsTArray<nsString> fileNames; nsTArray<nsString> fileNames;
DataStorage::GetAllFileNames(fileNames); DataStorage::GetAllFileNames(fileNames);
for (const auto& file: fileNames) { for (const auto& file: fileNames) {
RefPtr<DataStorage> ds = DataStorage::Get(file); RefPtr<DataStorage> ds = DataStorage::GetFromRawFileName(file);
size_t amount = ds->SizeOfIncludingThis(MallocSizeOf); size_t amount = ds->SizeOfIncludingThis(MallocSizeOf);
nsPrintfCString path("explicit/data-storage/%s", nsPrintfCString path("explicit/data-storage/%s",
NS_ConvertUTF16toUTF8(file).get()); NS_ConvertUTF16toUTF8(file).get());
@ -88,7 +88,23 @@ DataStorage::~DataStorage()
// static // static
already_AddRefed<DataStorage> already_AddRefed<DataStorage>
DataStorage::Get(const nsString& aFilename) DataStorage::Get(DataStorageClass aFilename)
{
switch (aFilename) {
#define DATA_STORAGE(_) \
case DataStorageClass::_: \
return GetFromRawFileName(NS_LITERAL_STRING(#_ ".txt"));
#include "mozilla/DataStorageList.h"
#undef DATA_STORAGE
default:
MOZ_ASSERT_UNREACHABLE("Invalid DataStorage type passed?");
return nullptr;
}
}
// static
already_AddRefed<DataStorage>
DataStorage::GetFromRawFileName(const nsString& aFilename)
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
if (!sDataStorages) { if (!sDataStorages) {
@ -105,14 +121,27 @@ DataStorage::Get(const nsString& aFilename)
// static // static
already_AddRefed<DataStorage> already_AddRefed<DataStorage>
DataStorage::GetIfExists(const nsString& aFilename) DataStorage::GetIfExists(DataStorageClass aFilename)
{ {
MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(NS_IsMainThread());
if (!sDataStorages) { if (!sDataStorages) {
sDataStorages = new DataStorages(); sDataStorages = new DataStorages();
} }
nsString name;
switch (aFilename) {
#define DATA_STORAGE(_) \
case DataStorageClass::_: \
name.AssignLiteral(#_ ".txt"); \
break;
#include "mozilla/DataStorageList.h"
#undef DATA_STORAGE
default:
MOZ_ASSERT_UNREACHABLE("Invalid DataStorages type passed?");
}
RefPtr<DataStorage> storage; RefPtr<DataStorage> storage;
sDataStorages->Get(aFilename, getter_AddRefs(storage)); if (!name.IsEmpty()) {
sDataStorages->Get(name, getter_AddRefs(storage));
}
return storage.forget(); return storage.forget();
} }
@ -124,8 +153,34 @@ DataStorage::GetAllFileNames(nsTArray<nsString>& aItems)
if (!sDataStorages) { if (!sDataStorages) {
return; return;
} }
for (auto iter = sDataStorages->Iter(); !iter.Done(); iter.Next()) { #define DATA_STORAGE(_) \
aItems.AppendElement(iter.Key()); aItems.AppendElement(NS_LITERAL_STRING(#_ ".txt"));
#include "mozilla/DataStorageList.h"
#undef DATA_STORAGE
}
// static
void
DataStorage::GetAllChildProcessData(
nsTArray<mozilla::dom::DataStorageEntry>& aEntries)
{
nsTArray<nsString> storageFiles;
GetAllFileNames(storageFiles);
for (auto& file : storageFiles) {
dom::DataStorageEntry entry;
entry.filename() = file;
RefPtr<DataStorage> storage = DataStorage::GetFromRawFileName(file);
if (!storage->mInitCalled) {
// Perhaps no consumer has initialized the DataStorage object yet,
// so do that now!
bool dataWillPersist = false;
nsresult rv = storage->Init(dataWillPersist);
if (NS_WARN_IF(NS_FAILED(rv))) {
return;
}
}
storage->GetAll(&entry.items());
aEntries.AppendElement(Move(entry));
} }
} }
@ -136,8 +191,33 @@ DataStorage::SetCachedStorageEntries(
{ {
MOZ_ASSERT(XRE_IsContentProcess()); MOZ_ASSERT(XRE_IsContentProcess());
for (auto& entry : aEntries) { // Make sure to initialize all DataStorage classes.
RefPtr<DataStorage> storage = DataStorage::Get(entry.filename()); // For each one, we look through the list of our entries and if we find
// a matching DataStorage object, we initialize it.
//
// Note that this is an O(n^2) operation, but the n here is very small
// (currently 3). There is a comment in the DataStorageList.h header
// about updating the algorithm here to something more fancy if the list
// of DataStorage items grows some day.
nsTArray<dom::DataStorageEntry> entries;
#define DATA_STORAGE(_) \
{ \
dom::DataStorageEntry entry; \
entry.filename() = NS_LITERAL_STRING(#_ ".txt"); \
for (auto& e : aEntries) { \
if (entry.filename().Equals(e.filename())) { \
entry.items() = Move(e.items()); \
break; \
} \
} \
entries.AppendElement(Move(entry)); \
}
#include "mozilla/DataStorageList.h"
#undef DATA_STORAGE
for (auto& entry : entries) {
RefPtr<DataStorage> storage =
DataStorage::GetFromRawFileName(entry.filename());
bool dataWillPersist = false; bool dataWillPersist = false;
storage->Init(dataWillPersist, &entry.items()); storage->Init(dataWillPersist, &entry.items());
} }

View File

@ -20,9 +20,13 @@
#include "nsRefPtrHashtable.h" #include "nsRefPtrHashtable.h"
#include "nsString.h" #include "nsString.h"
class psm_DataStorageTest;
namespace mozilla { namespace mozilla {
class DataStorageMemoryReporter;
namespace dom { namespace dom {
class ContentChild;
class DataStorageEntry; class DataStorageEntry;
class DataStorageItem; class DataStorageItem;
} }
@ -88,6 +92,12 @@ enum DataStorageType {
DataStorage_Private DataStorage_Private
}; };
enum class DataStorageClass {
#define DATA_STORAGE(_) _,
#include "mozilla/DataStorageList.h"
#undef DATA_STORAGE
};
class DataStorage : public nsIObserver class DataStorage : public nsIObserver
{ {
typedef dom::DataStorageItem DataStorageItem; typedef dom::DataStorageItem DataStorageItem;
@ -98,8 +108,8 @@ public:
// If there is a profile directory, there is or will eventually be a file // If there is a profile directory, there is or will eventually be a file
// by the name specified by aFilename there. // by the name specified by aFilename there.
static already_AddRefed<DataStorage> Get(const nsString& aFilename); static already_AddRefed<DataStorage> Get(DataStorageClass aFilename);
static already_AddRefed<DataStorage> GetIfExists(const nsString& aFilename); static already_AddRefed<DataStorage> GetIfExists(DataStorageClass aFilename);
// Initializes the DataStorage. Must be called before using. // Initializes the DataStorage. Must be called before using.
// aDataWillPersist returns whether or not data can be persistently saved. // aDataWillPersist returns whether or not data can be persistently saved.
@ -127,6 +137,9 @@ public:
// Read all file names that we know about. // Read all file names that we know about.
static void GetAllFileNames(nsTArray<nsString>& aItems); static void GetAllFileNames(nsTArray<nsString>& aItems);
// Read all child process data that we know about.
static void GetAllChildProcessData(nsTArray<mozilla::dom::DataStorageEntry>& aEntries);
// Read all of the data items. // Read all of the data items.
void GetAll(InfallibleTArray<DataStorageItem>* aItems); void GetAll(InfallibleTArray<DataStorageItem>* aItems);
@ -139,6 +152,12 @@ private:
explicit DataStorage(const nsString& aFilename); explicit DataStorage(const nsString& aFilename);
virtual ~DataStorage(); virtual ~DataStorage();
static already_AddRefed<DataStorage> GetFromRawFileName(const nsString& aFilename);
friend class ::psm_DataStorageTest;
friend class mozilla::dom::ContentChild;
friend class mozilla::DataStorageMemoryReporter;
class Writer; class Writer;
class Reader; class Reader;
@ -202,9 +221,10 @@ private:
uint32_t mTimerDelay; // in milliseconds uint32_t mTimerDelay; // in milliseconds
bool mPendingWrite; // true if a write is needed but hasn't been dispatched bool mPendingWrite; // true if a write is needed but hasn't been dispatched
bool mShuttingDown; bool mShuttingDown;
mozilla::Atomic<bool> mInitCalled; // Indicates that Init() has been called.
// (End list of members protected by mMutex) // (End list of members protected by mMutex)
mozilla::Atomic<bool> mInitCalled; // Indicates that Init() has been called.
Monitor mReadyMonitor; // Do not acquire this at the same time as mMutex. Monitor mReadyMonitor; // Do not acquire this at the same time as mMutex.
bool mReady; // Indicates that saved data has been read and Get can proceed. bool mReady; // Indicates that saved data has been read and Get can proceed.

View File

@ -0,0 +1,18 @@
/* -*- 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/. */
// This is the list of well-known PSM DataStorage classes that Gecko uses.
// These are key value data stores that are backed by a simple text-based
// storage in the profile directory.
//
// Please note that it is crucial for performance reasons for the number of
// these classes to remain low. If you need to add to this list, you may
// need to update the algorithm in DataStorage::SetCachedStorageEntries()
// to something faster.
DATA_STORAGE(AlternateServices)
DATA_STORAGE(SecurityPreloadState)
DATA_STORAGE(SiteSecurityServiceState)

View File

@ -81,6 +81,7 @@ EXPORTS += [
EXPORTS.mozilla += [ EXPORTS.mozilla += [
'DataStorage.h', 'DataStorage.h',
'DataStorageList.h',
'PublicSSL.h', 'PublicSSL.h',
] ]

View File

@ -378,9 +378,9 @@ nsSiteSecurityService::Init()
mozilla::Preferences::AddStrongObserver(this, mozilla::Preferences::AddStrongObserver(this,
"test.currentTimeOffsetSeconds"); "test.currentTimeOffsetSeconds");
mSiteStateStorage = mSiteStateStorage =
mozilla::DataStorage::Get(NS_LITERAL_STRING("SiteSecurityServiceState.txt")); mozilla::DataStorage::Get(DataStorageClass::SiteSecurityServiceState);
mPreloadStateStorage = mPreloadStateStorage =
mozilla::DataStorage::Get(NS_LITERAL_STRING("SecurityPreloadState.txt")); mozilla::DataStorage::Get(DataStorageClass::SecurityPreloadState);
bool storageWillPersist = false; bool storageWillPersist = false;
bool preloadStorageWillPersist = false; bool preloadStorageWillPersist = false;
nsresult rv = mSiteStateStorage->Init(storageWillPersist); nsresult rv = mSiteStateStorage->Init(storageWillPersist);

View File

@ -24,7 +24,7 @@ protected:
const ::testing::TestInfo* const testInfo = const ::testing::TestInfo* const testInfo =
::testing::UnitTest::GetInstance()->current_test_info(); ::testing::UnitTest::GetInstance()->current_test_info();
NS_ConvertUTF8toUTF16 testName(testInfo->name()); NS_ConvertUTF8toUTF16 testName(testInfo->name());
storage = DataStorage::Get(testName); storage = DataStorage::GetFromRawFileName(testName);
storage->Init(dataWillPersist); storage->Init(dataWillPersist);
} }

View File

@ -57,6 +57,7 @@
frame.contentWindow.location.href, frame.contentWindow.location.href,
new URL("resources/client-navigated-frame.html", new URL("resources/client-navigated-frame.html",
location).toString()); location).toString());
frame.remove();
}) })
.catch(unreached_rejection(t)) .catch(unreached_rejection(t))
.then(___ => service_worker_unregister(t, scope)); .then(___ => service_worker_unregister(t, scope));
@ -81,7 +82,8 @@
.then(({result, url}) => { .then(({result, url}) => {
assert_equals(result, "test_client_navigate_redirect"); assert_equals(result, "test_client_navigate_redirect");
assert_equals(url, ""); assert_equals(url, "");
assert_throws(null, function() { return frame.contentWindow.location.href }); assert_throws("SecurityError", function() { return frame.contentWindow.location.href });
frame.remove();
}) })
.catch(unreached_rejection(t)) .catch(unreached_rejection(t))
.then(___ => service_worker_unregister(t, scope)); .then(___ => service_worker_unregister(t, scope));
@ -102,16 +104,74 @@
return wait_for_message() return wait_for_message()
}) })
.then(({id}) => clientId = id) .then(({id}) => clientId = id)
.then(___ => run_test(controller, clientId, "test_client_navigate_failure")) .then(___ => run_test(controller, clientId, "test_client_navigate_cross_origin"))
.then(({result, url}) => { .then(({result, url}) => {
assert_equals(result, "test_client_navigate_failure"); assert_equals(result, "test_client_navigate_cross_origin");
assert_equals(url, "");
assert_throws("SecurityError", function() { return frame.contentWindow.location.href });
frame.remove();
})
.catch(unreached_rejection(t))
.then(___ => service_worker_unregister(t, scope));
}, "Frame location should not be accessible after cross-origin navigation");
promise_test(function(t) {
var worker = "resources/client-navigate-worker.js";
var scope = "resources/client-navigate-frame.html";
var controller, frame, clientId;
return service_worker_unregister_and_register(t, worker, scope)
.then(reg => wait_for_state(t, reg.installing, "activated"))
.then(___ => with_iframe(scope))
.then(f => {
frame = f;
controller = frame.contentWindow.navigator.serviceWorker.controller;
fetch_tests_from_worker(controller);
return wait_for_message()
})
.then(({id}) => clientId = id)
.then(___ => run_test(controller, clientId, "test_client_navigate_about_blank"))
.then(({result, url}) => {
assert_equals(result, "test_client_navigate_about_blank");
assert_equals( assert_equals(
frame.contentWindow.location.href, frame.contentWindow.location.href,
new URL("resources/client-navigate-frame.html", new URL("resources/client-navigate-frame.html",
location).toString()); location).toString());
frame.contentWindow.document.body.style = "background-color: green" frame.contentWindow.document.body.style = "background-color: green"
frame.remove();
}) })
.catch(unreached_rejection(t)) .catch(unreached_rejection(t))
.then(___ => service_worker_unregister(t, scope)); .then(___ => service_worker_unregister(t, scope));
}, "Frame location should not update on failed navigation"); }, "Frame location should not update on failed about:blank navigation");
promise_test(function(t) {
var worker = "resources/client-navigate-worker.js";
var scope = "resources/client-navigate-frame.html";
var controller, frame, clientId;
return service_worker_unregister_and_register(t, worker, scope)
.then(reg => {
return wait_for_state(t, reg.installing, "activated");
})
.then(___ => with_iframe(scope))
.then(f => {
frame = f;
controller = frame.contentWindow.navigator.serviceWorker.controller;
fetch_tests_from_worker(controller);
return wait_for_message()
})
.then(({id}) => clientId = id)
.then(___ => run_test(controller, clientId, "test_client_navigate_mixed_content"))
.then(({result, url}) => {
assert_equals(result, "test_client_navigate_mixed_content");
assert_equals(
frame.contentWindow.location.href,
new URL("resources/client-navigate-frame.html",
location).toString());
frame.contentWindow.document.body.style = "background-color: green"
frame.remove();
})
.catch(unreached_rejection(t))
.then(___ => service_worker_unregister(t, scope));
}, "Frame location should not update on failed mixed-content navigation");
</script> </script>

View File

@ -40,19 +40,38 @@ self.onmessage = function(e) {
}) })
.catch(unreached_rejection(t)); .catch(unreached_rejection(t));
}, "Return value should be instance of WindowClient"); }, "Return value should be instance of WindowClient");
} else if (test === "test_client_navigate_failure") { } else if (test === "test_client_navigate_cross_origin") {
promise_test(function(t) { promise_test(function(t) {
this.add_cleanup(() => port.postMessage(pass(test, clientUrl)));
var path = new URL('client-navigated-frame.html', self.location.href).pathname;
var url = get_host_info()['HTTPS_REMOTE_ORIGIN'] + path;
return self.clients.get(clientId) return self.clients.get(clientId)
.then(client => assert_promise_rejects(client.navigate("http://example.com"))) .then(client => client.navigate(url))
.then(client => {
clientUrl = (client && client.url) || "";
assert_equals(client, null,
'cross-origin navigate resolves with null');
})
.catch(unreached_rejection(t)); .catch(unreached_rejection(t));
}, "Navigating to different origin should reject"); }, "Navigating to different origin should resolve with null");
} else if (test === "test_client_navigate_about_blank") {
promise_test(function(t) { promise_test(function(t) {
this.add_cleanup(function() { port.postMessage(pass(test, "")); }); this.add_cleanup(function() { port.postMessage(pass(test, "")); });
return self.clients.get(clientId) return self.clients.get(clientId)
.then(client => promise_rejects(t, new TypeError(), client.navigate("about:blank"))) .then(client => promise_rejects(t, new TypeError(), client.navigate("about:blank")))
.catch(unreached_rejection(t)); .catch(unreached_rejection(t));
}, "Navigating to about:blank should reject with TypeError") }, "Navigating to about:blank should reject with TypeError");
} else if (test === "test_client_navigate_mixed_content") {
promise_test(function(t) {
this.add_cleanup(function() { port.postMessage(pass(test, "")); });
var path = new URL('client-navigated-frame.html', self.location.href).pathname;
// Insecure URL should fail since the frame is owned by a secure parent
// and navigating to http:// would create a mixed-content violation.
var url = get_host_info()['HTTP_REMOTE_ORIGIN'] + path;
return self.clients.get(clientId)
.then(client => promise_rejects(t, new TypeError(), client.navigate(url)))
.catch(unreached_rejection(t));
}, "Navigating to mixed-content iframe should reject with TypeError");
} else if (test === "test_client_navigate_redirect") { } else if (test === "test_client_navigate_redirect") {
var host_info = get_host_info(); var host_info = get_host_info();
var url = new URL(host_info['HTTPS_REMOTE_ORIGIN']).toString() + var url = new URL(host_info['HTTPS_REMOTE_ORIGIN']).toString() +

View File

@ -639,6 +639,7 @@ name = "rust_url_capi"
version = "0.0.1" version = "0.0.1"
dependencies = [ dependencies = [
"libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
"nserror 0.1.0",
"nsstring 0.1.0", "nsstring 0.1.0",
"url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]

View File

@ -626,6 +626,7 @@ name = "rust_url_capi"
version = "0.0.1" version = "0.0.1"
dependencies = [ dependencies = [
"libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
"nserror 0.1.0",
"nsstring 0.1.0", "nsstring 0.1.0",
"url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
] ]

View File

@ -1,320 +0,0 @@
UPDATE TYPE complete
PREPARE REMOVEFILE searchplugins/searchpluginstext0
PREPARE REMOVEFILE searchplugins/searchpluginspng0.png
PREPARE REMOVEFILE removed-files
PREPARE REMOVEFILE precomplete
PREPARE REMOVEFILE exe0.exe
PREPARE REMOVEFILE 2/20/20text0
PREPARE REMOVEFILE 2/20/20png0.png
PREPARE REMOVEFILE 0/0exe0.exe
PREPARE REMOVEFILE 0/00/00text0
PREPARE REMOVEDIR searchplugins/
PREPARE REMOVEDIR defaults/pref/
PREPARE REMOVEDIR defaults/
PREPARE REMOVEDIR 2/20/
PREPARE REMOVEDIR 2/
PREPARE REMOVEDIR 0/00/
PREPARE REMOVEDIR 0/
PREPARE ADD searchplugins/searchpluginstext0
PREPARE ADD searchplugins/searchpluginspng1.png
PREPARE ADD searchplugins/searchpluginspng0.png
PREPARE ADD removed-files
PREPARE ADD precomplete
PREPARE ADD exe0.exe
PREPARE ADD distribution/extensions/extensions1/extensions1text0
PREPARE ADD distribution/extensions/extensions1/extensions1png1.png
PREPARE ADD distribution/extensions/extensions1/extensions1png0.png
PREPARE ADD distribution/extensions/extensions0/extensions0text0
PREPARE ADD distribution/extensions/extensions0/extensions0png1.png
PREPARE ADD distribution/extensions/extensions0/extensions0png0.png
PREPARE ADD 1/10/10text0
PREPARE ADD 0/0exe0.exe
PREPARE ADD 0/00/00text1
PREPARE ADD 0/00/00text0
PREPARE ADD 0/00/00png0.png
PREPARE REMOVEDIR 9/99/
PREPARE REMOVEDIR 9/99/
PREPARE REMOVEDIR 9/98/
PREPARE REMOVEFILE 9/97/971/97xtext1
PREPARE REMOVEFILE 9/97/971/97xtext0
PREPARE REMOVEDIR 9/97/971/
PREPARE REMOVEFILE 9/97/970/97xtext1
PREPARE REMOVEFILE 9/97/970/97xtext0
PREPARE REMOVEDIR 9/97/970/
PREPARE REMOVEDIR 9/97/
PREPARE REMOVEFILE 9/96/96text1
PREPARE REMOVEFILE 9/96/96text0
PREPARE REMOVEDIR 9/96/
PREPARE REMOVEDIR 9/95/
PREPARE REMOVEDIR 9/95/
PREPARE REMOVEDIR 9/94/
PREPARE REMOVEDIR 9/94/
PREPARE REMOVEDIR 9/93/
PREPARE REMOVEDIR 9/92/
PREPARE REMOVEDIR 9/91/
PREPARE REMOVEDIR 9/90/
PREPARE REMOVEDIR 9/90/
PREPARE REMOVEDIR 8/89/
PREPARE REMOVEDIR 8/89/
PREPARE REMOVEDIR 8/88/
PREPARE REMOVEFILE 8/87/871/87xtext1
PREPARE REMOVEFILE 8/87/871/87xtext0
PREPARE REMOVEDIR 8/87/871/
PREPARE REMOVEFILE 8/87/870/87xtext1
PREPARE REMOVEFILE 8/87/870/87xtext0
PREPARE REMOVEDIR 8/87/870/
PREPARE REMOVEDIR 8/87/
PREPARE REMOVEFILE 8/86/86text1
PREPARE REMOVEFILE 8/86/86text0
PREPARE REMOVEDIR 8/86/
PREPARE REMOVEDIR 8/85/
PREPARE REMOVEDIR 8/85/
PREPARE REMOVEDIR 8/84/
PREPARE REMOVEDIR 8/84/
PREPARE REMOVEDIR 8/83/
PREPARE REMOVEDIR 8/82/
PREPARE REMOVEDIR 8/81/
PREPARE REMOVEDIR 8/80/
PREPARE REMOVEDIR 8/80/
PREPARE REMOVEFILE 7/71/7xtext1
PREPARE REMOVEFILE 7/71/7xtext0
PREPARE REMOVEFILE 7/71/7xtest.exe
PREPARE REMOVEDIR 7/71/
PREPARE REMOVEFILE 7/70/7xtext1
PREPARE REMOVEFILE 7/70/7xtext0
PREPARE REMOVEFILE 7/70/7xtest.exe
PREPARE REMOVEDIR 7/70/
PREPARE REMOVEFILE 7/7text1
PREPARE REMOVEFILE 7/7text0
PREPARE REMOVEDIR 7/
PREPARE REMOVEDIR 6/
PREPARE REMOVEFILE 5/5text1
PREPARE REMOVEFILE 5/5text0
PREPARE REMOVEFILE 5/5text1
PREPARE REMOVEFILE 5/5text0
PREPARE REMOVEFILE 5/5test.exe
PREPARE REMOVEDIR 5/
PREPARE REMOVEFILE 4/4text1
PREPARE REMOVEFILE 4/4text0
PREPARE REMOVEDIR 4/
PREPARE REMOVEFILE 3/3text1
PREPARE REMOVEFILE 3/3text0
EXECUTE REMOVEFILE searchplugins/searchpluginstext0
EXECUTE REMOVEFILE searchplugins/searchpluginspng0.png
EXECUTE REMOVEFILE removed-files
EXECUTE REMOVEFILE precomplete
EXECUTE REMOVEFILE exe0.exe
EXECUTE REMOVEFILE 2/20/20text0
EXECUTE REMOVEFILE 2/20/20png0.png
EXECUTE REMOVEFILE 0/0exe0.exe
EXECUTE REMOVEFILE 0/00/00text0
EXECUTE REMOVEDIR searchplugins/
EXECUTE REMOVEDIR defaults/pref/
EXECUTE REMOVEDIR defaults/
EXECUTE REMOVEDIR 2/20/
EXECUTE REMOVEDIR 2/
EXECUTE REMOVEDIR 0/00/
EXECUTE REMOVEDIR 0/
EXECUTE ADD searchplugins/searchpluginstext0
EXECUTE ADD searchplugins/searchpluginspng1.png
EXECUTE ADD searchplugins/searchpluginspng0.png
EXECUTE ADD removed-files
EXECUTE ADD precomplete
EXECUTE ADD exe0.exe
EXECUTE ADD distribution/extensions/extensions1/extensions1text0
EXECUTE ADD distribution/extensions/extensions1/extensions1png1.png
EXECUTE ADD distribution/extensions/extensions1/extensions1png0.png
EXECUTE ADD distribution/extensions/extensions0/extensions0text0
EXECUTE ADD distribution/extensions/extensions0/extensions0png1.png
EXECUTE ADD distribution/extensions/extensions0/extensions0png0.png
EXECUTE ADD 1/10/10text0
EXECUTE ADD 0/0exe0.exe
EXECUTE ADD 0/00/00text1
EXECUTE ADD 0/00/00text0
EXECUTE ADD 0/00/00png0.png
EXECUTE REMOVEDIR 9/99/
EXECUTE REMOVEDIR 9/99/
EXECUTE REMOVEDIR 9/98/
EXECUTE REMOVEFILE 9/97/971/97xtext1
EXECUTE REMOVEFILE 9/97/971/97xtext0
EXECUTE REMOVEDIR 9/97/971/
EXECUTE REMOVEFILE 9/97/970/97xtext1
EXECUTE REMOVEFILE 9/97/970/97xtext0
EXECUTE REMOVEDIR 9/97/970/
EXECUTE REMOVEDIR 9/97/
EXECUTE REMOVEFILE 9/96/96text1
EXECUTE REMOVEFILE 9/96/96text0
EXECUTE REMOVEDIR 9/96/
EXECUTE REMOVEDIR 9/95/
EXECUTE REMOVEDIR 9/95/
EXECUTE REMOVEDIR 9/94/
EXECUTE REMOVEDIR 9/94/
EXECUTE REMOVEDIR 9/93/
EXECUTE REMOVEDIR 9/92/
EXECUTE REMOVEDIR 9/91/
EXECUTE REMOVEDIR 9/90/
EXECUTE REMOVEDIR 9/90/
EXECUTE REMOVEDIR 8/89/
EXECUTE REMOVEDIR 8/89/
EXECUTE REMOVEDIR 8/88/
EXECUTE REMOVEFILE 8/87/871/87xtext1
EXECUTE REMOVEFILE 8/87/871/87xtext0
EXECUTE REMOVEDIR 8/87/871/
EXECUTE REMOVEFILE 8/87/870/87xtext1
EXECUTE REMOVEFILE 8/87/870/87xtext0
EXECUTE REMOVEDIR 8/87/870/
EXECUTE REMOVEDIR 8/87/
EXECUTE REMOVEFILE 8/86/86text1
EXECUTE REMOVEFILE 8/86/86text0
EXECUTE REMOVEDIR 8/86/
EXECUTE REMOVEDIR 8/85/
EXECUTE REMOVEDIR 8/85/
EXECUTE REMOVEDIR 8/84/
EXECUTE REMOVEDIR 8/84/
EXECUTE REMOVEDIR 8/83/
EXECUTE REMOVEDIR 8/82/
EXECUTE REMOVEDIR 8/81/
EXECUTE REMOVEDIR 8/80/
EXECUTE REMOVEDIR 8/80/
EXECUTE REMOVEFILE 7/71/7xtext1
EXECUTE REMOVEFILE 7/71/7xtext0
EXECUTE REMOVEFILE 7/71/7xtest.exe
EXECUTE REMOVEDIR 7/71/
EXECUTE REMOVEFILE 7/70/7xtext1
EXECUTE REMOVEFILE 7/70/7xtext0
EXECUTE REMOVEFILE 7/70/7xtest.exe
EXECUTE REMOVEDIR 7/70/
EXECUTE REMOVEFILE 7/7text1
EXECUTE REMOVEFILE 7/7text0
EXECUTE REMOVEDIR 7/
EXECUTE REMOVEDIR 6/
EXECUTE REMOVEFILE 5/5text1
EXECUTE REMOVEFILE 5/5text0
EXECUTE REMOVEFILE 5/5text1
file cannot be removed because it does not exist; skipping
EXECUTE REMOVEFILE 5/5text0
file cannot be removed because it does not exist; skipping
EXECUTE REMOVEFILE 5/5test.exe
EXECUTE REMOVEDIR 5/
EXECUTE REMOVEFILE 4/4text1
EXECUTE REMOVEFILE 4/4text0
EXECUTE REMOVEDIR 4/
EXECUTE REMOVEFILE 3/3text1
EXECUTE REMOVEFILE 3/3text0
FINISH REMOVEFILE searchplugins/searchpluginstext0
FINISH REMOVEFILE searchplugins/searchpluginspng0.png
FINISH REMOVEFILE removed-files
FINISH REMOVEFILE precomplete
FINISH REMOVEFILE exe0.exe
FINISH REMOVEFILE 2/20/20text0
FINISH REMOVEFILE 2/20/20png0.png
FINISH REMOVEFILE 0/0exe0.exe
FINISH REMOVEFILE 0/00/00text0
FINISH REMOVEDIR searchplugins/
removing directory: searchplugins/, rv: 0
FINISH REMOVEDIR defaults/pref/
removing directory: defaults/pref/, rv: 0
FINISH REMOVEDIR defaults/
removing directory: defaults/, rv: 0
FINISH REMOVEDIR 2/20/
FINISH REMOVEDIR 2/
FINISH REMOVEDIR 0/00/
removing directory: 0/00/, rv: 0
FINISH REMOVEDIR 0/
removing directory: 0/, rv: 0
FINISH ADD searchplugins/searchpluginstext0
FINISH ADD searchplugins/searchpluginspng1.png
FINISH ADD searchplugins/searchpluginspng0.png
FINISH ADD removed-files
FINISH ADD precomplete
FINISH ADD exe0.exe
FINISH ADD distribution/extensions/extensions1/extensions1text0
FINISH ADD distribution/extensions/extensions1/extensions1png1.png
FINISH ADD distribution/extensions/extensions1/extensions1png0.png
FINISH ADD distribution/extensions/extensions0/extensions0text0
FINISH ADD distribution/extensions/extensions0/extensions0png1.png
FINISH ADD distribution/extensions/extensions0/extensions0png0.png
FINISH ADD 1/10/10text0
FINISH ADD 0/0exe0.exe
FINISH ADD 0/00/00text1
FINISH ADD 0/00/00text0
FINISH ADD 0/00/00png0.png
FINISH REMOVEDIR 9/99/
FINISH REMOVEDIR 9/99/
directory no longer exists; skipping
FINISH REMOVEDIR 9/98/
FINISH REMOVEFILE 9/97/971/97xtext1
FINISH REMOVEFILE 9/97/971/97xtext0
FINISH REMOVEDIR 9/97/971/
FINISH REMOVEFILE 9/97/970/97xtext1
FINISH REMOVEFILE 9/97/970/97xtext0
FINISH REMOVEDIR 9/97/970/
FINISH REMOVEDIR 9/97/
FINISH REMOVEFILE 9/96/96text1
FINISH REMOVEFILE 9/96/96text0
FINISH REMOVEDIR 9/96/
FINISH REMOVEDIR 9/95/
FINISH REMOVEDIR 9/95/
directory no longer exists; skipping
FINISH REMOVEDIR 9/94/
FINISH REMOVEDIR 9/94/
directory no longer exists; skipping
FINISH REMOVEDIR 9/93/
FINISH REMOVEDIR 9/92/
removing directory: 9/92/, rv: 0
FINISH REMOVEDIR 9/91/
removing directory: 9/91/, rv: 0
FINISH REMOVEDIR 9/90/
FINISH REMOVEDIR 9/90/
directory no longer exists; skipping
FINISH REMOVEDIR 8/89/
FINISH REMOVEDIR 8/89/
directory no longer exists; skipping
FINISH REMOVEDIR 8/88/
FINISH REMOVEFILE 8/87/871/87xtext1
FINISH REMOVEFILE 8/87/871/87xtext0
FINISH REMOVEDIR 8/87/871/
FINISH REMOVEFILE 8/87/870/87xtext1
FINISH REMOVEFILE 8/87/870/87xtext0
FINISH REMOVEDIR 8/87/870/
FINISH REMOVEDIR 8/87/
FINISH REMOVEFILE 8/86/86text1
FINISH REMOVEFILE 8/86/86text0
FINISH REMOVEDIR 8/86/
FINISH REMOVEDIR 8/85/
FINISH REMOVEDIR 8/85/
directory no longer exists; skipping
FINISH REMOVEDIR 8/84/
FINISH REMOVEDIR 8/84/
directory no longer exists; skipping
FINISH REMOVEDIR 8/83/
FINISH REMOVEDIR 8/82/
removing directory: 8/82/, rv: 0
FINISH REMOVEDIR 8/81/
removing directory: 8/81/, rv: 0
FINISH REMOVEDIR 8/80/
FINISH REMOVEDIR 8/80/
directory no longer exists; skipping
FINISH REMOVEFILE 7/71/7xtext1
FINISH REMOVEFILE 7/71/7xtext0
FINISH REMOVEFILE 7/71/7xtest.exe
FINISH REMOVEDIR 7/71/
FINISH REMOVEFILE 7/70/7xtext1
FINISH REMOVEFILE 7/70/7xtext0
FINISH REMOVEFILE 7/70/7xtest.exe
FINISH REMOVEDIR 7/70/
FINISH REMOVEFILE 7/7text1
FINISH REMOVEFILE 7/7text0
FINISH REMOVEDIR 7/
FINISH REMOVEDIR 6/
FINISH REMOVEFILE 5/5text1
FINISH REMOVEFILE 5/5text0
FINISH REMOVEFILE 5/5test.exe
FINISH REMOVEDIR 5/
FINISH REMOVEFILE 4/4text1
FINISH REMOVEFILE 4/4text0
FINISH REMOVEDIR 4/
FINISH REMOVEFILE 3/3text1
FINISH REMOVEFILE 3/3text0
succeeded
calling QuitProgressUI

View File

@ -1,320 +0,0 @@
UPDATE TYPE complete
PREPARE REMOVEFILE searchplugins/searchpluginstext0
PREPARE REMOVEFILE searchplugins/searchpluginspng0.png
PREPARE REMOVEFILE removed-files
PREPARE REMOVEFILE precomplete
PREPARE REMOVEFILE exe0.exe
PREPARE REMOVEFILE 2/20/20text0
PREPARE REMOVEFILE 2/20/20png0.png
PREPARE REMOVEFILE 0/0exe0.exe
PREPARE REMOVEFILE 0/00/00text0
PREPARE REMOVEDIR searchplugins/
PREPARE REMOVEDIR defaults/pref/
PREPARE REMOVEDIR defaults/
PREPARE REMOVEDIR 2/20/
PREPARE REMOVEDIR 2/
PREPARE REMOVEDIR 0/00/
PREPARE REMOVEDIR 0/
PREPARE ADD searchplugins/searchpluginstext0
PREPARE ADD searchplugins/searchpluginspng1.png
PREPARE ADD searchplugins/searchpluginspng0.png
PREPARE ADD removed-files
PREPARE ADD precomplete
PREPARE ADD exe0.exe
PREPARE ADD distribution/extensions/extensions1/extensions1text0
PREPARE ADD distribution/extensions/extensions1/extensions1png1.png
PREPARE ADD distribution/extensions/extensions1/extensions1png0.png
PREPARE ADD distribution/extensions/extensions0/extensions0text0
PREPARE ADD distribution/extensions/extensions0/extensions0png1.png
PREPARE ADD distribution/extensions/extensions0/extensions0png0.png
PREPARE ADD 1/10/10text0
PREPARE ADD 0/0exe0.exe
PREPARE ADD 0/00/00text1
PREPARE ADD 0/00/00text0
PREPARE ADD 0/00/00png0.png
PREPARE REMOVEDIR 9/99/
PREPARE REMOVEDIR 9/99/
PREPARE REMOVEDIR 9/98/
PREPARE REMOVEFILE 9/97/970/97xtext0
PREPARE REMOVEFILE 9/97/970/97xtext1
PREPARE REMOVEDIR 9/97/970/
PREPARE REMOVEFILE 9/97/971/97xtext0
PREPARE REMOVEFILE 9/97/971/97xtext1
PREPARE REMOVEDIR 9/97/971/
PREPARE REMOVEDIR 9/97/
PREPARE REMOVEFILE 9/96/96text0
PREPARE REMOVEFILE 9/96/96text1
PREPARE REMOVEDIR 9/96/
PREPARE REMOVEDIR 9/95/
PREPARE REMOVEDIR 9/95/
PREPARE REMOVEDIR 9/94/
PREPARE REMOVEDIR 9/94/
PREPARE REMOVEDIR 9/93/
PREPARE REMOVEDIR 9/92/
PREPARE REMOVEDIR 9/91/
PREPARE REMOVEDIR 9/90/
PREPARE REMOVEDIR 9/90/
PREPARE REMOVEDIR 8/89/
PREPARE REMOVEDIR 8/89/
PREPARE REMOVEDIR 8/88/
PREPARE REMOVEFILE 8/87/870/87xtext0
PREPARE REMOVEFILE 8/87/870/87xtext1
PREPARE REMOVEDIR 8/87/870/
PREPARE REMOVEFILE 8/87/871/87xtext0
PREPARE REMOVEFILE 8/87/871/87xtext1
PREPARE REMOVEDIR 8/87/871/
PREPARE REMOVEDIR 8/87/
PREPARE REMOVEFILE 8/86/86text0
PREPARE REMOVEFILE 8/86/86text1
PREPARE REMOVEDIR 8/86/
PREPARE REMOVEDIR 8/85/
PREPARE REMOVEDIR 8/85/
PREPARE REMOVEDIR 8/84/
PREPARE REMOVEDIR 8/84/
PREPARE REMOVEDIR 8/83/
PREPARE REMOVEDIR 8/82/
PREPARE REMOVEDIR 8/81/
PREPARE REMOVEDIR 8/80/
PREPARE REMOVEDIR 8/80/
PREPARE REMOVEFILE 7/7text0
PREPARE REMOVEFILE 7/7text1
PREPARE REMOVEFILE 7/70/7xtest.exe
PREPARE REMOVEFILE 7/70/7xtext0
PREPARE REMOVEFILE 7/70/7xtext1
PREPARE REMOVEDIR 7/70/
PREPARE REMOVEFILE 7/71/7xtest.exe
PREPARE REMOVEFILE 7/71/7xtext0
PREPARE REMOVEFILE 7/71/7xtext1
PREPARE REMOVEDIR 7/71/
PREPARE REMOVEDIR 7/
PREPARE REMOVEDIR 6/
PREPARE REMOVEFILE 5/5text1
PREPARE REMOVEFILE 5/5text0
PREPARE REMOVEFILE 5/5test.exe
PREPARE REMOVEFILE 5/5text0
PREPARE REMOVEFILE 5/5text1
PREPARE REMOVEDIR 5/
PREPARE REMOVEFILE 4/4text1
PREPARE REMOVEFILE 4/4text0
PREPARE REMOVEDIR 4/
PREPARE REMOVEFILE 3/3text1
PREPARE REMOVEFILE 3/3text0
EXECUTE REMOVEFILE searchplugins/searchpluginstext0
EXECUTE REMOVEFILE searchplugins/searchpluginspng0.png
EXECUTE REMOVEFILE removed-files
EXECUTE REMOVEFILE precomplete
EXECUTE REMOVEFILE exe0.exe
EXECUTE REMOVEFILE 2/20/20text0
EXECUTE REMOVEFILE 2/20/20png0.png
EXECUTE REMOVEFILE 0/0exe0.exe
EXECUTE REMOVEFILE 0/00/00text0
EXECUTE REMOVEDIR searchplugins/
EXECUTE REMOVEDIR defaults/pref/
EXECUTE REMOVEDIR defaults/
EXECUTE REMOVEDIR 2/20/
EXECUTE REMOVEDIR 2/
EXECUTE REMOVEDIR 0/00/
EXECUTE REMOVEDIR 0/
EXECUTE ADD searchplugins/searchpluginstext0
EXECUTE ADD searchplugins/searchpluginspng1.png
EXECUTE ADD searchplugins/searchpluginspng0.png
EXECUTE ADD removed-files
EXECUTE ADD precomplete
EXECUTE ADD exe0.exe
EXECUTE ADD distribution/extensions/extensions1/extensions1text0
EXECUTE ADD distribution/extensions/extensions1/extensions1png1.png
EXECUTE ADD distribution/extensions/extensions1/extensions1png0.png
EXECUTE ADD distribution/extensions/extensions0/extensions0text0
EXECUTE ADD distribution/extensions/extensions0/extensions0png1.png
EXECUTE ADD distribution/extensions/extensions0/extensions0png0.png
EXECUTE ADD 1/10/10text0
EXECUTE ADD 0/0exe0.exe
EXECUTE ADD 0/00/00text1
EXECUTE ADD 0/00/00text0
EXECUTE ADD 0/00/00png0.png
EXECUTE REMOVEDIR 9/99/
EXECUTE REMOVEDIR 9/99/
EXECUTE REMOVEDIR 9/98/
EXECUTE REMOVEFILE 9/97/970/97xtext0
EXECUTE REMOVEFILE 9/97/970/97xtext1
EXECUTE REMOVEDIR 9/97/970/
EXECUTE REMOVEFILE 9/97/971/97xtext0
EXECUTE REMOVEFILE 9/97/971/97xtext1
EXECUTE REMOVEDIR 9/97/971/
EXECUTE REMOVEDIR 9/97/
EXECUTE REMOVEFILE 9/96/96text0
EXECUTE REMOVEFILE 9/96/96text1
EXECUTE REMOVEDIR 9/96/
EXECUTE REMOVEDIR 9/95/
EXECUTE REMOVEDIR 9/95/
EXECUTE REMOVEDIR 9/94/
EXECUTE REMOVEDIR 9/94/
EXECUTE REMOVEDIR 9/93/
EXECUTE REMOVEDIR 9/92/
EXECUTE REMOVEDIR 9/91/
EXECUTE REMOVEDIR 9/90/
EXECUTE REMOVEDIR 9/90/
EXECUTE REMOVEDIR 8/89/
EXECUTE REMOVEDIR 8/89/
EXECUTE REMOVEDIR 8/88/
EXECUTE REMOVEFILE 8/87/870/87xtext0
EXECUTE REMOVEFILE 8/87/870/87xtext1
EXECUTE REMOVEDIR 8/87/870/
EXECUTE REMOVEFILE 8/87/871/87xtext0
EXECUTE REMOVEFILE 8/87/871/87xtext1
EXECUTE REMOVEDIR 8/87/871/
EXECUTE REMOVEDIR 8/87/
EXECUTE REMOVEFILE 8/86/86text0
EXECUTE REMOVEFILE 8/86/86text1
EXECUTE REMOVEDIR 8/86/
EXECUTE REMOVEDIR 8/85/
EXECUTE REMOVEDIR 8/85/
EXECUTE REMOVEDIR 8/84/
EXECUTE REMOVEDIR 8/84/
EXECUTE REMOVEDIR 8/83/
EXECUTE REMOVEDIR 8/82/
EXECUTE REMOVEDIR 8/81/
EXECUTE REMOVEDIR 8/80/
EXECUTE REMOVEDIR 8/80/
EXECUTE REMOVEFILE 7/7text0
EXECUTE REMOVEFILE 7/7text1
EXECUTE REMOVEFILE 7/70/7xtest.exe
EXECUTE REMOVEFILE 7/70/7xtext0
EXECUTE REMOVEFILE 7/70/7xtext1
EXECUTE REMOVEDIR 7/70/
EXECUTE REMOVEFILE 7/71/7xtest.exe
EXECUTE REMOVEFILE 7/71/7xtext0
EXECUTE REMOVEFILE 7/71/7xtext1
EXECUTE REMOVEDIR 7/71/
EXECUTE REMOVEDIR 7/
EXECUTE REMOVEDIR 6/
EXECUTE REMOVEFILE 5/5text1
EXECUTE REMOVEFILE 5/5text0
EXECUTE REMOVEFILE 5/5test.exe
EXECUTE REMOVEFILE 5/5text0
file cannot be removed because it does not exist; skipping
EXECUTE REMOVEFILE 5/5text1
file cannot be removed because it does not exist; skipping
EXECUTE REMOVEDIR 5/
EXECUTE REMOVEFILE 4/4text1
EXECUTE REMOVEFILE 4/4text0
EXECUTE REMOVEDIR 4/
EXECUTE REMOVEFILE 3/3text1
EXECUTE REMOVEFILE 3/3text0
FINISH REMOVEFILE searchplugins/searchpluginstext0
FINISH REMOVEFILE searchplugins/searchpluginspng0.png
FINISH REMOVEFILE removed-files
FINISH REMOVEFILE precomplete
FINISH REMOVEFILE exe0.exe
FINISH REMOVEFILE 2/20/20text0
FINISH REMOVEFILE 2/20/20png0.png
FINISH REMOVEFILE 0/0exe0.exe
FINISH REMOVEFILE 0/00/00text0
FINISH REMOVEDIR searchplugins/
removing directory: searchplugins/, rv: 0
FINISH REMOVEDIR defaults/pref/
removing directory: defaults/pref/, rv: 0
FINISH REMOVEDIR defaults/
removing directory: defaults/, rv: 0
FINISH REMOVEDIR 2/20/
FINISH REMOVEDIR 2/
FINISH REMOVEDIR 0/00/
removing directory: 0/00/, rv: 0
FINISH REMOVEDIR 0/
removing directory: 0/, rv: 0
FINISH ADD searchplugins/searchpluginstext0
FINISH ADD searchplugins/searchpluginspng1.png
FINISH ADD searchplugins/searchpluginspng0.png
FINISH ADD removed-files
FINISH ADD precomplete
FINISH ADD exe0.exe
FINISH ADD distribution/extensions/extensions1/extensions1text0
FINISH ADD distribution/extensions/extensions1/extensions1png1.png
FINISH ADD distribution/extensions/extensions1/extensions1png0.png
FINISH ADD distribution/extensions/extensions0/extensions0text0
FINISH ADD distribution/extensions/extensions0/extensions0png1.png
FINISH ADD distribution/extensions/extensions0/extensions0png0.png
FINISH ADD 1/10/10text0
FINISH ADD 0/0exe0.exe
FINISH ADD 0/00/00text1
FINISH ADD 0/00/00text0
FINISH ADD 0/00/00png0.png
FINISH REMOVEDIR 9/99/
FINISH REMOVEDIR 9/99/
directory no longer exists; skipping
FINISH REMOVEDIR 9/98/
FINISH REMOVEFILE 9/97/970/97xtext0
FINISH REMOVEFILE 9/97/970/97xtext1
FINISH REMOVEDIR 9/97/970/
FINISH REMOVEFILE 9/97/971/97xtext0
FINISH REMOVEFILE 9/97/971/97xtext1
FINISH REMOVEDIR 9/97/971/
FINISH REMOVEDIR 9/97/
FINISH REMOVEFILE 9/96/96text0
FINISH REMOVEFILE 9/96/96text1
FINISH REMOVEDIR 9/96/
FINISH REMOVEDIR 9/95/
FINISH REMOVEDIR 9/95/
directory no longer exists; skipping
FINISH REMOVEDIR 9/94/
FINISH REMOVEDIR 9/94/
directory no longer exists; skipping
FINISH REMOVEDIR 9/93/
FINISH REMOVEDIR 9/92/
removing directory: 9/92/, rv: 0
FINISH REMOVEDIR 9/91/
removing directory: 9/91/, rv: 0
FINISH REMOVEDIR 9/90/
FINISH REMOVEDIR 9/90/
directory no longer exists; skipping
FINISH REMOVEDIR 8/89/
FINISH REMOVEDIR 8/89/
directory no longer exists; skipping
FINISH REMOVEDIR 8/88/
FINISH REMOVEFILE 8/87/870/87xtext0
FINISH REMOVEFILE 8/87/870/87xtext1
FINISH REMOVEDIR 8/87/870/
FINISH REMOVEFILE 8/87/871/87xtext0
FINISH REMOVEFILE 8/87/871/87xtext1
FINISH REMOVEDIR 8/87/871/
FINISH REMOVEDIR 8/87/
FINISH REMOVEFILE 8/86/86text0
FINISH REMOVEFILE 8/86/86text1
FINISH REMOVEDIR 8/86/
FINISH REMOVEDIR 8/85/
FINISH REMOVEDIR 8/85/
directory no longer exists; skipping
FINISH REMOVEDIR 8/84/
FINISH REMOVEDIR 8/84/
directory no longer exists; skipping
FINISH REMOVEDIR 8/83/
FINISH REMOVEDIR 8/82/
removing directory: 8/82/, rv: 0
FINISH REMOVEDIR 8/81/
removing directory: 8/81/, rv: 0
FINISH REMOVEDIR 8/80/
FINISH REMOVEDIR 8/80/
directory no longer exists; skipping
FINISH REMOVEFILE 7/7text0
FINISH REMOVEFILE 7/7text1
FINISH REMOVEFILE 7/70/7xtest.exe
FINISH REMOVEFILE 7/70/7xtext0
FINISH REMOVEFILE 7/70/7xtext1
FINISH REMOVEDIR 7/70/
FINISH REMOVEFILE 7/71/7xtest.exe
FINISH REMOVEFILE 7/71/7xtext0
FINISH REMOVEFILE 7/71/7xtext1
FINISH REMOVEDIR 7/71/
FINISH REMOVEDIR 7/
FINISH REMOVEDIR 6/
FINISH REMOVEFILE 5/5text1
FINISH REMOVEFILE 5/5text0
FINISH REMOVEFILE 5/5test.exe
FINISH REMOVEDIR 5/
FINISH REMOVEFILE 4/4text1
FINISH REMOVEFILE 4/4text0
FINISH REMOVEDIR 4/
FINISH REMOVEFILE 3/3text1
FINISH REMOVEFILE 3/3text0
succeeded
calling QuitProgressUI

View File

@ -1,192 +0,0 @@
UPDATE TYPE partial
PREPARE ADD searchplugins/searchpluginstext0
PREPARE PATCH searchplugins/searchpluginspng1.png
PREPARE PATCH searchplugins/searchpluginspng0.png
PREPARE ADD precomplete
PREPARE PATCH exe0.exe
PREPARE ADD distribution/extensions/extensions1/extensions1text0
PREPARE PATCH distribution/extensions/extensions1/extensions1png1.png
PREPARE PATCH distribution/extensions/extensions1/extensions1png0.png
PREPARE ADD distribution/extensions/extensions0/extensions0text0
PREPARE PATCH distribution/extensions/extensions0/extensions0png1.png
PREPARE PATCH distribution/extensions/extensions0/extensions0png0.png
PREPARE PATCH 0/0exe0.exe
PREPARE ADD 0/00/00text0
PREPARE PATCH 0/00/00png0.png
PREPARE ADD 2/20/20text0
PREPARE ADD 2/20/20png0.png
PREPARE ADD 0/00/00text2
PREPARE REMOVEFILE 1/10/10text0
PREPARE REMOVEFILE 0/00/00text1
PREPARE REMOVEDIR 9/99/
PREPARE REMOVEDIR 9/99/
PREPARE REMOVEDIR 9/98/
PREPARE REMOVEFILE 9/97/971/97xtext1
PREPARE REMOVEFILE 9/97/971/97xtext0
PREPARE REMOVEDIR 9/97/971/
PREPARE REMOVEFILE 9/97/970/97xtext1
PREPARE REMOVEFILE 9/97/970/97xtext0
PREPARE REMOVEDIR 9/97/970/
PREPARE REMOVEDIR 9/97/
PREPARE REMOVEFILE 9/96/96text1
PREPARE REMOVEFILE 9/96/96text0
PREPARE REMOVEDIR 9/96/
PREPARE REMOVEDIR 9/95/
PREPARE REMOVEDIR 9/95/
PREPARE REMOVEDIR 9/94/
PREPARE REMOVEDIR 9/94/
PREPARE REMOVEDIR 9/93/
PREPARE REMOVEDIR 9/92/
PREPARE REMOVEDIR 9/91/
PREPARE REMOVEDIR 9/90/
PREPARE REMOVEDIR 9/90/
PREPARE REMOVEDIR 8/89/
PREPARE REMOVEDIR 8/89/
PREPARE REMOVEDIR 8/88/
PREPARE REMOVEFILE 8/87/871/87xtext1
PREPARE REMOVEFILE 8/87/871/87xtext0
PREPARE REMOVEDIR 8/87/871/
PREPARE REMOVEFILE 8/87/870/87xtext1
PREPARE REMOVEFILE 8/87/870/87xtext0
PREPARE REMOVEDIR 8/87/870/
PREPARE REMOVEDIR 8/87/
PREPARE REMOVEFILE 8/86/86text1
PREPARE REMOVEFILE 8/86/86text0
PREPARE REMOVEDIR 8/86/
PREPARE REMOVEDIR 8/85/
PREPARE REMOVEDIR 8/85/
PREPARE REMOVEDIR 8/84/
PREPARE REMOVEDIR 8/84/
PREPARE REMOVEDIR 8/83/
PREPARE REMOVEDIR 8/82/
PREPARE REMOVEDIR 8/81/
PREPARE REMOVEDIR 8/80/
PREPARE REMOVEDIR 8/80/
PREPARE REMOVEFILE 7/71/7xtext1
PREPARE REMOVEFILE 7/71/7xtext0
PREPARE REMOVEFILE 7/71/7xtest.exe
PREPARE REMOVEDIR 7/71/
PREPARE REMOVEFILE 7/70/7xtext1
PREPARE REMOVEFILE 7/70/7xtext0
PREPARE REMOVEFILE 7/70/7xtest.exe
PREPARE REMOVEDIR 7/70/
PREPARE REMOVEFILE 7/7text1
PREPARE REMOVEFILE 7/7text0
PREPARE REMOVEDIR 7/
PREPARE REMOVEDIR 6/
PREPARE REMOVEFILE 5/5text1
PREPARE REMOVEFILE 5/5text0
PREPARE REMOVEFILE 5/5text1
PREPARE REMOVEFILE 5/5text0
PREPARE REMOVEFILE 5/5test.exe
PREPARE REMOVEDIR 5/
PREPARE REMOVEFILE 4/4text1
PREPARE REMOVEFILE 4/4text0
PREPARE REMOVEDIR 4/
PREPARE REMOVEFILE 3/3text1
PREPARE REMOVEFILE 3/3text0
PREPARE REMOVEDIR 1/10/
PREPARE REMOVEDIR 1/
EXECUTE ADD searchplugins/searchpluginstext0
EXECUTE PATCH searchplugins/searchpluginspng1.png
EXECUTE PATCH searchplugins/searchpluginspng0.png
EXECUTE ADD precomplete
EXECUTE PATCH exe0.exe
EXECUTE ADD distribution/extensions/extensions1/extensions1text0
EXECUTE PATCH distribution/extensions/extensions1/extensions1png1.png
EXECUTE PATCH distribution/extensions/extensions1/extensions1png0.png
EXECUTE ADD distribution/extensions/extensions0/extensions0text0
EXECUTE PATCH distribution/extensions/extensions0/extensions0png1.png
EXECUTE PATCH distribution/extensions/extensions0/extensions0png0.png
EXECUTE PATCH 0/0exe0.exe
LoadSourceFile: destination file size 776 does not match expected size 79872
LoadSourceFile failed
### execution failed
FINISH ADD searchplugins/searchpluginstext0
FINISH PATCH searchplugins/searchpluginspng1.png
FINISH PATCH searchplugins/searchpluginspng0.png
FINISH ADD precomplete
FINISH PATCH exe0.exe
FINISH ADD distribution/extensions/extensions1/extensions1text0
backup_restore: backup file doesn't exist: distribution/extensions/extensions1/extensions1text0.moz-backup
FINISH PATCH distribution/extensions/extensions1/extensions1png1.png
FINISH PATCH distribution/extensions/extensions1/extensions1png0.png
FINISH ADD distribution/extensions/extensions0/extensions0text0
FINISH PATCH distribution/extensions/extensions0/extensions0png1.png
FINISH PATCH distribution/extensions/extensions0/extensions0png0.png
FINISH PATCH 0/0exe0.exe
backup_restore: backup file doesn't exist: 0/0exe0.exe.moz-backup
FINISH ADD 0/00/00text0
backup_restore: backup file doesn't exist: 0/00/00text0.moz-backup
FINISH PATCH 0/00/00png0.png
backup_restore: backup file doesn't exist: 0/00/00png0.png.moz-backup
FINISH ADD 2/20/20text0
backup_restore: backup file doesn't exist: 2/20/20text0.moz-backup
FINISH ADD 2/20/20png0.png
backup_restore: backup file doesn't exist: 2/20/20png0.png.moz-backup
FINISH ADD 0/00/00text2
backup_restore: backup file doesn't exist: 0/00/00text2.moz-backup
FINISH REMOVEFILE 1/10/10text0
backup_restore: backup file doesn't exist: 1/10/10text0.moz-backup
FINISH REMOVEFILE 0/00/00text1
backup_restore: backup file doesn't exist: 0/00/00text1.moz-backup
FINISH REMOVEFILE 9/97/971/97xtext1
backup_restore: backup file doesn't exist: 9/97/971/97xtext1.moz-backup
FINISH REMOVEFILE 9/97/971/97xtext0
backup_restore: backup file doesn't exist: 9/97/971/97xtext0.moz-backup
FINISH REMOVEFILE 9/97/970/97xtext1
backup_restore: backup file doesn't exist: 9/97/970/97xtext1.moz-backup
FINISH REMOVEFILE 9/97/970/97xtext0
backup_restore: backup file doesn't exist: 9/97/970/97xtext0.moz-backup
FINISH REMOVEFILE 9/96/96text1
backup_restore: backup file doesn't exist: 9/96/96text1.moz-backup
FINISH REMOVEFILE 9/96/96text0
backup_restore: backup file doesn't exist: 9/96/96text0.moz-backup
FINISH REMOVEFILE 8/87/871/87xtext1
backup_restore: backup file doesn't exist: 8/87/871/87xtext1.moz-backup
FINISH REMOVEFILE 8/87/871/87xtext0
backup_restore: backup file doesn't exist: 8/87/871/87xtext0.moz-backup
FINISH REMOVEFILE 8/87/870/87xtext1
backup_restore: backup file doesn't exist: 8/87/870/87xtext1.moz-backup
FINISH REMOVEFILE 8/87/870/87xtext0
backup_restore: backup file doesn't exist: 8/87/870/87xtext0.moz-backup
FINISH REMOVEFILE 8/86/86text1
backup_restore: backup file doesn't exist: 8/86/86text1.moz-backup
FINISH REMOVEFILE 8/86/86text0
backup_restore: backup file doesn't exist: 8/86/86text0.moz-backup
FINISH REMOVEFILE 7/71/7xtext1
backup_restore: backup file doesn't exist: 7/71/7xtext1.moz-backup
FINISH REMOVEFILE 7/71/7xtext0
backup_restore: backup file doesn't exist: 7/71/7xtext0.moz-backup
FINISH REMOVEFILE 7/71/7xtest.exe
backup_restore: backup file doesn't exist: 7/71/7xtest.exe.moz-backup
FINISH REMOVEFILE 7/70/7xtext1
backup_restore: backup file doesn't exist: 7/70/7xtext1.moz-backup
FINISH REMOVEFILE 7/70/7xtext0
backup_restore: backup file doesn't exist: 7/70/7xtext0.moz-backup
FINISH REMOVEFILE 7/70/7xtest.exe
backup_restore: backup file doesn't exist: 7/70/7xtest.exe.moz-backup
FINISH REMOVEFILE 7/7text1
backup_restore: backup file doesn't exist: 7/7text1.moz-backup
FINISH REMOVEFILE 7/7text0
backup_restore: backup file doesn't exist: 7/7text0.moz-backup
FINISH REMOVEFILE 5/5text1
backup_restore: backup file doesn't exist: 5/5text1.moz-backup
FINISH REMOVEFILE 5/5text0
backup_restore: backup file doesn't exist: 5/5text0.moz-backup
FINISH REMOVEFILE 5/5text1
backup_restore: backup file doesn't exist: 5/5text1.moz-backup
FINISH REMOVEFILE 5/5text0
backup_restore: backup file doesn't exist: 5/5text0.moz-backup
FINISH REMOVEFILE 5/5test.exe
backup_restore: backup file doesn't exist: 5/5test.exe.moz-backup
FINISH REMOVEFILE 4/4text1
backup_restore: backup file doesn't exist: 4/4text1.moz-backup
FINISH REMOVEFILE 4/4text0
backup_restore: backup file doesn't exist: 4/4text0.moz-backup
FINISH REMOVEFILE 3/3text1
backup_restore: backup file doesn't exist: 3/3text1.moz-backup
FINISH REMOVEFILE 3/3text0
backup_restore: backup file doesn't exist: 3/3text0.moz-backup
failed: 2
calling QuitProgressUI

View File

@ -1,279 +0,0 @@
UPDATE TYPE partial
PREPARE ADD searchplugins/searchpluginstext0
PREPARE PATCH searchplugins/searchpluginspng1.png
PREPARE PATCH searchplugins/searchpluginspng0.png
PREPARE ADD precomplete
PREPARE PATCH exe0.exe
PREPARE ADD distribution/extensions/extensions1/extensions1text0
PREPARE PATCH distribution/extensions/extensions1/extensions1png1.png
PREPARE PATCH distribution/extensions/extensions1/extensions1png0.png
PREPARE ADD distribution/extensions/extensions0/extensions0text0
PREPARE PATCH distribution/extensions/extensions0/extensions0png1.png
PREPARE PATCH distribution/extensions/extensions0/extensions0png0.png
PREPARE PATCH 0/0exe0.exe
PREPARE ADD 0/00/00text0
PREPARE PATCH 0/00/00png0.png
PREPARE ADD 2/20/20text0
PREPARE ADD 2/20/20png0.png
PREPARE ADD 0/00/00text2
PREPARE REMOVEFILE 1/10/10text0
PREPARE REMOVEFILE 0/00/00text1
PREPARE REMOVEDIR 9/99/
PREPARE REMOVEDIR 9/99/
PREPARE REMOVEDIR 9/98/
PREPARE REMOVEFILE 9/97/971/97xtext1
PREPARE REMOVEFILE 9/97/971/97xtext0
PREPARE REMOVEDIR 9/97/971/
PREPARE REMOVEFILE 9/97/970/97xtext1
PREPARE REMOVEFILE 9/97/970/97xtext0
PREPARE REMOVEDIR 9/97/970/
PREPARE REMOVEDIR 9/97/
PREPARE REMOVEFILE 9/96/96text1
PREPARE REMOVEFILE 9/96/96text0
PREPARE REMOVEDIR 9/96/
PREPARE REMOVEDIR 9/95/
PREPARE REMOVEDIR 9/95/
PREPARE REMOVEDIR 9/94/
PREPARE REMOVEDIR 9/94/
PREPARE REMOVEDIR 9/93/
PREPARE REMOVEDIR 9/92/
PREPARE REMOVEDIR 9/91/
PREPARE REMOVEDIR 9/90/
PREPARE REMOVEDIR 9/90/
PREPARE REMOVEDIR 8/89/
PREPARE REMOVEDIR 8/89/
PREPARE REMOVEDIR 8/88/
PREPARE REMOVEFILE 8/87/871/87xtext1
PREPARE REMOVEFILE 8/87/871/87xtext0
PREPARE REMOVEDIR 8/87/871/
PREPARE REMOVEFILE 8/87/870/87xtext1
PREPARE REMOVEFILE 8/87/870/87xtext0
PREPARE REMOVEDIR 8/87/870/
PREPARE REMOVEDIR 8/87/
PREPARE REMOVEFILE 8/86/86text1
PREPARE REMOVEFILE 8/86/86text0
PREPARE REMOVEDIR 8/86/
PREPARE REMOVEDIR 8/85/
PREPARE REMOVEDIR 8/85/
PREPARE REMOVEDIR 8/84/
PREPARE REMOVEDIR 8/84/
PREPARE REMOVEDIR 8/83/
PREPARE REMOVEDIR 8/82/
PREPARE REMOVEDIR 8/81/
PREPARE REMOVEDIR 8/80/
PREPARE REMOVEDIR 8/80/
PREPARE REMOVEFILE 7/71/7xtext1
PREPARE REMOVEFILE 7/71/7xtext0
PREPARE REMOVEFILE 7/71/7xtest.exe
PREPARE REMOVEDIR 7/71/
PREPARE REMOVEFILE 7/70/7xtext1
PREPARE REMOVEFILE 7/70/7xtext0
PREPARE REMOVEFILE 7/70/7xtest.exe
PREPARE REMOVEDIR 7/70/
PREPARE REMOVEFILE 7/7text1
PREPARE REMOVEFILE 7/7text0
PREPARE REMOVEDIR 7/
PREPARE REMOVEDIR 6/
PREPARE REMOVEFILE 5/5text1
PREPARE REMOVEFILE 5/5text0
PREPARE REMOVEFILE 5/5text1
PREPARE REMOVEFILE 5/5text0
PREPARE REMOVEFILE 5/5test.exe
PREPARE REMOVEDIR 5/
PREPARE REMOVEFILE 4/4text1
PREPARE REMOVEFILE 4/4text0
PREPARE REMOVEDIR 4/
PREPARE REMOVEFILE 3/3text1
PREPARE REMOVEFILE 3/3text0
PREPARE REMOVEDIR 1/10/
PREPARE REMOVEDIR 1/
EXECUTE ADD searchplugins/searchpluginstext0
EXECUTE PATCH searchplugins/searchpluginspng1.png
EXECUTE PATCH searchplugins/searchpluginspng0.png
EXECUTE ADD precomplete
EXECUTE PATCH exe0.exe
EXECUTE ADD distribution/extensions/extensions1/extensions1text0
EXECUTE PATCH distribution/extensions/extensions1/extensions1png1.png
EXECUTE PATCH distribution/extensions/extensions1/extensions1png0.png
EXECUTE ADD distribution/extensions/extensions0/extensions0text0
EXECUTE PATCH distribution/extensions/extensions0/extensions0png1.png
EXECUTE PATCH distribution/extensions/extensions0/extensions0png0.png
EXECUTE PATCH 0/0exe0.exe
EXECUTE ADD 0/00/00text0
EXECUTE PATCH 0/00/00png0.png
EXECUTE ADD 2/20/20text0
EXECUTE ADD 2/20/20png0.png
EXECUTE ADD 0/00/00text2
EXECUTE REMOVEFILE 1/10/10text0
EXECUTE REMOVEFILE 0/00/00text1
EXECUTE REMOVEDIR 9/99/
EXECUTE REMOVEDIR 9/99/
EXECUTE REMOVEDIR 9/98/
EXECUTE REMOVEFILE 9/97/971/97xtext1
EXECUTE REMOVEFILE 9/97/971/97xtext0
EXECUTE REMOVEDIR 9/97/971/
EXECUTE REMOVEFILE 9/97/970/97xtext1
EXECUTE REMOVEFILE 9/97/970/97xtext0
EXECUTE REMOVEDIR 9/97/970/
EXECUTE REMOVEDIR 9/97/
EXECUTE REMOVEFILE 9/96/96text1
EXECUTE REMOVEFILE 9/96/96text0
EXECUTE REMOVEDIR 9/96/
EXECUTE REMOVEDIR 9/95/
EXECUTE REMOVEDIR 9/95/
EXECUTE REMOVEDIR 9/94/
EXECUTE REMOVEDIR 9/94/
EXECUTE REMOVEDIR 9/93/
EXECUTE REMOVEDIR 9/92/
EXECUTE REMOVEDIR 9/91/
EXECUTE REMOVEDIR 9/90/
EXECUTE REMOVEDIR 9/90/
EXECUTE REMOVEDIR 8/89/
EXECUTE REMOVEDIR 8/89/
EXECUTE REMOVEDIR 8/88/
EXECUTE REMOVEFILE 8/87/871/87xtext1
EXECUTE REMOVEFILE 8/87/871/87xtext0
EXECUTE REMOVEDIR 8/87/871/
EXECUTE REMOVEFILE 8/87/870/87xtext1
EXECUTE REMOVEFILE 8/87/870/87xtext0
EXECUTE REMOVEDIR 8/87/870/
EXECUTE REMOVEDIR 8/87/
EXECUTE REMOVEFILE 8/86/86text1
EXECUTE REMOVEFILE 8/86/86text0
EXECUTE REMOVEDIR 8/86/
EXECUTE REMOVEDIR 8/85/
EXECUTE REMOVEDIR 8/85/
EXECUTE REMOVEDIR 8/84/
EXECUTE REMOVEDIR 8/84/
EXECUTE REMOVEDIR 8/83/
EXECUTE REMOVEDIR 8/82/
EXECUTE REMOVEDIR 8/81/
EXECUTE REMOVEDIR 8/80/
EXECUTE REMOVEDIR 8/80/
EXECUTE REMOVEFILE 7/71/7xtext1
EXECUTE REMOVEFILE 7/71/7xtext0
EXECUTE REMOVEFILE 7/71/7xtest.exe
EXECUTE REMOVEDIR 7/71/
EXECUTE REMOVEFILE 7/70/7xtext1
EXECUTE REMOVEFILE 7/70/7xtext0
EXECUTE REMOVEFILE 7/70/7xtest.exe
EXECUTE REMOVEDIR 7/70/
EXECUTE REMOVEFILE 7/7text1
EXECUTE REMOVEFILE 7/7text0
EXECUTE REMOVEDIR 7/
EXECUTE REMOVEDIR 6/
EXECUTE REMOVEFILE 5/5text1
EXECUTE REMOVEFILE 5/5text0
EXECUTE REMOVEFILE 5/5text1
file cannot be removed because it does not exist; skipping
EXECUTE REMOVEFILE 5/5text0
file cannot be removed because it does not exist; skipping
EXECUTE REMOVEFILE 5/5test.exe
EXECUTE REMOVEDIR 5/
EXECUTE REMOVEFILE 4/4text1
EXECUTE REMOVEFILE 4/4text0
EXECUTE REMOVEDIR 4/
EXECUTE REMOVEFILE 3/3text1
EXECUTE REMOVEFILE 3/3text0
EXECUTE REMOVEDIR 1/10/
EXECUTE REMOVEDIR 1/
FINISH ADD searchplugins/searchpluginstext0
FINISH PATCH searchplugins/searchpluginspng1.png
FINISH PATCH searchplugins/searchpluginspng0.png
FINISH ADD precomplete
FINISH PATCH exe0.exe
FINISH ADD distribution/extensions/extensions1/extensions1text0
FINISH PATCH distribution/extensions/extensions1/extensions1png1.png
FINISH PATCH distribution/extensions/extensions1/extensions1png0.png
FINISH ADD distribution/extensions/extensions0/extensions0text0
FINISH PATCH distribution/extensions/extensions0/extensions0png1.png
FINISH PATCH distribution/extensions/extensions0/extensions0png0.png
FINISH PATCH 0/0exe0.exe
FINISH ADD 0/00/00text0
FINISH PATCH 0/00/00png0.png
FINISH ADD 2/20/20text0
FINISH ADD 2/20/20png0.png
FINISH ADD 0/00/00text2
FINISH REMOVEFILE 1/10/10text0
FINISH REMOVEFILE 0/00/00text1
FINISH REMOVEDIR 9/99/
FINISH REMOVEDIR 9/99/
directory no longer exists; skipping
FINISH REMOVEDIR 9/98/
FINISH REMOVEFILE 9/97/971/97xtext1
FINISH REMOVEFILE 9/97/971/97xtext0
FINISH REMOVEDIR 9/97/971/
FINISH REMOVEFILE 9/97/970/97xtext1
FINISH REMOVEFILE 9/97/970/97xtext0
FINISH REMOVEDIR 9/97/970/
FINISH REMOVEDIR 9/97/
FINISH REMOVEFILE 9/96/96text1
FINISH REMOVEFILE 9/96/96text0
FINISH REMOVEDIR 9/96/
FINISH REMOVEDIR 9/95/
FINISH REMOVEDIR 9/95/
directory no longer exists; skipping
FINISH REMOVEDIR 9/94/
FINISH REMOVEDIR 9/94/
directory no longer exists; skipping
FINISH REMOVEDIR 9/93/
FINISH REMOVEDIR 9/92/
removing directory: 9/92/, rv: 0
FINISH REMOVEDIR 9/91/
removing directory: 9/91/, rv: 0
FINISH REMOVEDIR 9/90/
FINISH REMOVEDIR 9/90/
directory no longer exists; skipping
FINISH REMOVEDIR 8/89/
FINISH REMOVEDIR 8/89/
directory no longer exists; skipping
FINISH REMOVEDIR 8/88/
FINISH REMOVEFILE 8/87/871/87xtext1
FINISH REMOVEFILE 8/87/871/87xtext0
FINISH REMOVEDIR 8/87/871/
FINISH REMOVEFILE 8/87/870/87xtext1
FINISH REMOVEFILE 8/87/870/87xtext0
FINISH REMOVEDIR 8/87/870/
FINISH REMOVEDIR 8/87/
FINISH REMOVEFILE 8/86/86text1
FINISH REMOVEFILE 8/86/86text0
FINISH REMOVEDIR 8/86/
FINISH REMOVEDIR 8/85/
FINISH REMOVEDIR 8/85/
directory no longer exists; skipping
FINISH REMOVEDIR 8/84/
FINISH REMOVEDIR 8/84/
directory no longer exists; skipping
FINISH REMOVEDIR 8/83/
FINISH REMOVEDIR 8/82/
removing directory: 8/82/, rv: 0
FINISH REMOVEDIR 8/81/
removing directory: 8/81/, rv: 0
FINISH REMOVEDIR 8/80/
FINISH REMOVEDIR 8/80/
directory no longer exists; skipping
FINISH REMOVEFILE 7/71/7xtext1
FINISH REMOVEFILE 7/71/7xtext0
FINISH REMOVEFILE 7/71/7xtest.exe
FINISH REMOVEDIR 7/71/
FINISH REMOVEFILE 7/70/7xtext1
FINISH REMOVEFILE 7/70/7xtext0
FINISH REMOVEFILE 7/70/7xtest.exe
FINISH REMOVEDIR 7/70/
FINISH REMOVEFILE 7/7text1
FINISH REMOVEFILE 7/7text0
FINISH REMOVEDIR 7/
FINISH REMOVEDIR 6/
FINISH REMOVEFILE 5/5text1
FINISH REMOVEFILE 5/5text0
FINISH REMOVEFILE 5/5test.exe
FINISH REMOVEDIR 5/
FINISH REMOVEFILE 4/4text1
FINISH REMOVEFILE 4/4text0
FINISH REMOVEDIR 4/
FINISH REMOVEFILE 3/3text1
FINISH REMOVEFILE 3/3text0
FINISH REMOVEDIR 1/10/
FINISH REMOVEDIR 1/
succeeded
calling QuitProgressUI

View File

@ -1,279 +0,0 @@
UPDATE TYPE partial
PREPARE ADD searchplugins/searchpluginstext0
PREPARE PATCH searchplugins/searchpluginspng1.png
PREPARE PATCH searchplugins/searchpluginspng0.png
PREPARE ADD precomplete
PREPARE PATCH exe0.exe
PREPARE ADD distribution/extensions/extensions1/extensions1text0
PREPARE PATCH distribution/extensions/extensions1/extensions1png1.png
PREPARE PATCH distribution/extensions/extensions1/extensions1png0.png
PREPARE ADD distribution/extensions/extensions0/extensions0text0
PREPARE PATCH distribution/extensions/extensions0/extensions0png1.png
PREPARE PATCH distribution/extensions/extensions0/extensions0png0.png
PREPARE PATCH 0/0exe0.exe
PREPARE ADD 0/00/00text0
PREPARE PATCH 0/00/00png0.png
PREPARE ADD 2/20/20text0
PREPARE ADD 2/20/20png0.png
PREPARE ADD 0/00/00text2
PREPARE REMOVEFILE 1/10/10text0
PREPARE REMOVEFILE 0/00/00text1
PREPARE REMOVEDIR 9/99/
PREPARE REMOVEDIR 9/99/
PREPARE REMOVEDIR 9/98/
PREPARE REMOVEFILE 9/97/970/97xtext0
PREPARE REMOVEFILE 9/97/970/97xtext1
PREPARE REMOVEDIR 9/97/970/
PREPARE REMOVEFILE 9/97/971/97xtext0
PREPARE REMOVEFILE 9/97/971/97xtext1
PREPARE REMOVEDIR 9/97/971/
PREPARE REMOVEDIR 9/97/
PREPARE REMOVEFILE 9/96/96text0
PREPARE REMOVEFILE 9/96/96text1
PREPARE REMOVEDIR 9/96/
PREPARE REMOVEDIR 9/95/
PREPARE REMOVEDIR 9/95/
PREPARE REMOVEDIR 9/94/
PREPARE REMOVEDIR 9/94/
PREPARE REMOVEDIR 9/93/
PREPARE REMOVEDIR 9/92/
PREPARE REMOVEDIR 9/91/
PREPARE REMOVEDIR 9/90/
PREPARE REMOVEDIR 9/90/
PREPARE REMOVEDIR 8/89/
PREPARE REMOVEDIR 8/89/
PREPARE REMOVEDIR 8/88/
PREPARE REMOVEFILE 8/87/870/87xtext0
PREPARE REMOVEFILE 8/87/870/87xtext1
PREPARE REMOVEDIR 8/87/870/
PREPARE REMOVEFILE 8/87/871/87xtext0
PREPARE REMOVEFILE 8/87/871/87xtext1
PREPARE REMOVEDIR 8/87/871/
PREPARE REMOVEDIR 8/87/
PREPARE REMOVEFILE 8/86/86text0
PREPARE REMOVEFILE 8/86/86text1
PREPARE REMOVEDIR 8/86/
PREPARE REMOVEDIR 8/85/
PREPARE REMOVEDIR 8/85/
PREPARE REMOVEDIR 8/84/
PREPARE REMOVEDIR 8/84/
PREPARE REMOVEDIR 8/83/
PREPARE REMOVEDIR 8/82/
PREPARE REMOVEDIR 8/81/
PREPARE REMOVEDIR 8/80/
PREPARE REMOVEDIR 8/80/
PREPARE REMOVEFILE 7/7text0
PREPARE REMOVEFILE 7/7text1
PREPARE REMOVEFILE 7/70/7xtest.exe
PREPARE REMOVEFILE 7/70/7xtext0
PREPARE REMOVEFILE 7/70/7xtext1
PREPARE REMOVEDIR 7/70/
PREPARE REMOVEFILE 7/71/7xtest.exe
PREPARE REMOVEFILE 7/71/7xtext0
PREPARE REMOVEFILE 7/71/7xtext1
PREPARE REMOVEDIR 7/71/
PREPARE REMOVEDIR 7/
PREPARE REMOVEDIR 6/
PREPARE REMOVEFILE 5/5text1
PREPARE REMOVEFILE 5/5text0
PREPARE REMOVEFILE 5/5test.exe
PREPARE REMOVEFILE 5/5text0
PREPARE REMOVEFILE 5/5text1
PREPARE REMOVEDIR 5/
PREPARE REMOVEFILE 4/4text1
PREPARE REMOVEFILE 4/4text0
PREPARE REMOVEDIR 4/
PREPARE REMOVEFILE 3/3text1
PREPARE REMOVEFILE 3/3text0
PREPARE REMOVEDIR 1/10/
PREPARE REMOVEDIR 1/
EXECUTE ADD searchplugins/searchpluginstext0
EXECUTE PATCH searchplugins/searchpluginspng1.png
EXECUTE PATCH searchplugins/searchpluginspng0.png
EXECUTE ADD precomplete
EXECUTE PATCH exe0.exe
EXECUTE ADD distribution/extensions/extensions1/extensions1text0
EXECUTE PATCH distribution/extensions/extensions1/extensions1png1.png
EXECUTE PATCH distribution/extensions/extensions1/extensions1png0.png
EXECUTE ADD distribution/extensions/extensions0/extensions0text0
EXECUTE PATCH distribution/extensions/extensions0/extensions0png1.png
EXECUTE PATCH distribution/extensions/extensions0/extensions0png0.png
EXECUTE PATCH 0/0exe0.exe
EXECUTE ADD 0/00/00text0
EXECUTE PATCH 0/00/00png0.png
EXECUTE ADD 2/20/20text0
EXECUTE ADD 2/20/20png0.png
EXECUTE ADD 0/00/00text2
EXECUTE REMOVEFILE 1/10/10text0
EXECUTE REMOVEFILE 0/00/00text1
EXECUTE REMOVEDIR 9/99/
EXECUTE REMOVEDIR 9/99/
EXECUTE REMOVEDIR 9/98/
EXECUTE REMOVEFILE 9/97/970/97xtext0
EXECUTE REMOVEFILE 9/97/970/97xtext1
EXECUTE REMOVEDIR 9/97/970/
EXECUTE REMOVEFILE 9/97/971/97xtext0
EXECUTE REMOVEFILE 9/97/971/97xtext1
EXECUTE REMOVEDIR 9/97/971/
EXECUTE REMOVEDIR 9/97/
EXECUTE REMOVEFILE 9/96/96text0
EXECUTE REMOVEFILE 9/96/96text1
EXECUTE REMOVEDIR 9/96/
EXECUTE REMOVEDIR 9/95/
EXECUTE REMOVEDIR 9/95/
EXECUTE REMOVEDIR 9/94/
EXECUTE REMOVEDIR 9/94/
EXECUTE REMOVEDIR 9/93/
EXECUTE REMOVEDIR 9/92/
EXECUTE REMOVEDIR 9/91/
EXECUTE REMOVEDIR 9/90/
EXECUTE REMOVEDIR 9/90/
EXECUTE REMOVEDIR 8/89/
EXECUTE REMOVEDIR 8/89/
EXECUTE REMOVEDIR 8/88/
EXECUTE REMOVEFILE 8/87/870/87xtext0
EXECUTE REMOVEFILE 8/87/870/87xtext1
EXECUTE REMOVEDIR 8/87/870/
EXECUTE REMOVEFILE 8/87/871/87xtext0
EXECUTE REMOVEFILE 8/87/871/87xtext1
EXECUTE REMOVEDIR 8/87/871/
EXECUTE REMOVEDIR 8/87/
EXECUTE REMOVEFILE 8/86/86text0
EXECUTE REMOVEFILE 8/86/86text1
EXECUTE REMOVEDIR 8/86/
EXECUTE REMOVEDIR 8/85/
EXECUTE REMOVEDIR 8/85/
EXECUTE REMOVEDIR 8/84/
EXECUTE REMOVEDIR 8/84/
EXECUTE REMOVEDIR 8/83/
EXECUTE REMOVEDIR 8/82/
EXECUTE REMOVEDIR 8/81/
EXECUTE REMOVEDIR 8/80/
EXECUTE REMOVEDIR 8/80/
EXECUTE REMOVEFILE 7/7text0
EXECUTE REMOVEFILE 7/7text1
EXECUTE REMOVEFILE 7/70/7xtest.exe
EXECUTE REMOVEFILE 7/70/7xtext0
EXECUTE REMOVEFILE 7/70/7xtext1
EXECUTE REMOVEDIR 7/70/
EXECUTE REMOVEFILE 7/71/7xtest.exe
EXECUTE REMOVEFILE 7/71/7xtext0
EXECUTE REMOVEFILE 7/71/7xtext1
EXECUTE REMOVEDIR 7/71/
EXECUTE REMOVEDIR 7/
EXECUTE REMOVEDIR 6/
EXECUTE REMOVEFILE 5/5text1
EXECUTE REMOVEFILE 5/5text0
EXECUTE REMOVEFILE 5/5test.exe
EXECUTE REMOVEFILE 5/5text0
file cannot be removed because it does not exist; skipping
EXECUTE REMOVEFILE 5/5text1
file cannot be removed because it does not exist; skipping
EXECUTE REMOVEDIR 5/
EXECUTE REMOVEFILE 4/4text1
EXECUTE REMOVEFILE 4/4text0
EXECUTE REMOVEDIR 4/
EXECUTE REMOVEFILE 3/3text1
EXECUTE REMOVEFILE 3/3text0
EXECUTE REMOVEDIR 1/10/
EXECUTE REMOVEDIR 1/
FINISH ADD searchplugins/searchpluginstext0
FINISH PATCH searchplugins/searchpluginspng1.png
FINISH PATCH searchplugins/searchpluginspng0.png
FINISH ADD precomplete
FINISH PATCH exe0.exe
FINISH ADD distribution/extensions/extensions1/extensions1text0
FINISH PATCH distribution/extensions/extensions1/extensions1png1.png
FINISH PATCH distribution/extensions/extensions1/extensions1png0.png
FINISH ADD distribution/extensions/extensions0/extensions0text0
FINISH PATCH distribution/extensions/extensions0/extensions0png1.png
FINISH PATCH distribution/extensions/extensions0/extensions0png0.png
FINISH PATCH 0/0exe0.exe
FINISH ADD 0/00/00text0
FINISH PATCH 0/00/00png0.png
FINISH ADD 2/20/20text0
FINISH ADD 2/20/20png0.png
FINISH ADD 0/00/00text2
FINISH REMOVEFILE 1/10/10text0
FINISH REMOVEFILE 0/00/00text1
FINISH REMOVEDIR 9/99/
FINISH REMOVEDIR 9/99/
directory no longer exists; skipping
FINISH REMOVEDIR 9/98/
FINISH REMOVEFILE 9/97/970/97xtext0
FINISH REMOVEFILE 9/97/970/97xtext1
FINISH REMOVEDIR 9/97/970/
FINISH REMOVEFILE 9/97/971/97xtext0
FINISH REMOVEFILE 9/97/971/97xtext1
FINISH REMOVEDIR 9/97/971/
FINISH REMOVEDIR 9/97/
FINISH REMOVEFILE 9/96/96text0
FINISH REMOVEFILE 9/96/96text1
FINISH REMOVEDIR 9/96/
FINISH REMOVEDIR 9/95/
FINISH REMOVEDIR 9/95/
directory no longer exists; skipping
FINISH REMOVEDIR 9/94/
FINISH REMOVEDIR 9/94/
directory no longer exists; skipping
FINISH REMOVEDIR 9/93/
FINISH REMOVEDIR 9/92/
removing directory: 9/92/, rv: 0
FINISH REMOVEDIR 9/91/
removing directory: 9/91/, rv: 0
FINISH REMOVEDIR 9/90/
FINISH REMOVEDIR 9/90/
directory no longer exists; skipping
FINISH REMOVEDIR 8/89/
FINISH REMOVEDIR 8/89/
directory no longer exists; skipping
FINISH REMOVEDIR 8/88/
FINISH REMOVEFILE 8/87/870/87xtext0
FINISH REMOVEFILE 8/87/870/87xtext1
FINISH REMOVEDIR 8/87/870/
FINISH REMOVEFILE 8/87/871/87xtext0
FINISH REMOVEFILE 8/87/871/87xtext1
FINISH REMOVEDIR 8/87/871/
FINISH REMOVEDIR 8/87/
FINISH REMOVEFILE 8/86/86text0
FINISH REMOVEFILE 8/86/86text1
FINISH REMOVEDIR 8/86/
FINISH REMOVEDIR 8/85/
FINISH REMOVEDIR 8/85/
directory no longer exists; skipping
FINISH REMOVEDIR 8/84/
FINISH REMOVEDIR 8/84/
directory no longer exists; skipping
FINISH REMOVEDIR 8/83/
FINISH REMOVEDIR 8/82/
removing directory: 8/82/, rv: 0
FINISH REMOVEDIR 8/81/
removing directory: 8/81/, rv: 0
FINISH REMOVEDIR 8/80/
FINISH REMOVEDIR 8/80/
directory no longer exists; skipping
FINISH REMOVEFILE 7/7text0
FINISH REMOVEFILE 7/7text1
FINISH REMOVEFILE 7/70/7xtest.exe
FINISH REMOVEFILE 7/70/7xtext0
FINISH REMOVEFILE 7/70/7xtext1
FINISH REMOVEDIR 7/70/
FINISH REMOVEFILE 7/71/7xtest.exe
FINISH REMOVEFILE 7/71/7xtext0
FINISH REMOVEFILE 7/71/7xtext1
FINISH REMOVEDIR 7/71/
FINISH REMOVEDIR 7/
FINISH REMOVEDIR 6/
FINISH REMOVEFILE 5/5text1
FINISH REMOVEFILE 5/5text0
FINISH REMOVEFILE 5/5test.exe
FINISH REMOVEDIR 5/
FINISH REMOVEFILE 4/4text1
FINISH REMOVEFILE 4/4text0
FINISH REMOVEDIR 4/
FINISH REMOVEFILE 3/3text1
FINISH REMOVEFILE 3/3text0
FINISH REMOVEDIR 1/10/
FINISH REMOVEDIR 1/
succeeded
calling QuitProgressUI

View File

@ -40,18 +40,6 @@ const IS_UNIX = true;
const IS_UNIX = false; const IS_UNIX = false;
#endif #endif
#ifdef ANDROID
const IS_ANDROID = true;
#else
const IS_ANDROID = false;
#endif
#ifdef MOZ_WIDGET_GONK
const IS_TOOLKIT_GONK = true;
#else
const IS_TOOLKIT_GONK = false;
#endif
#ifdef MOZ_VERIFY_MAR_SIGNATURE #ifdef MOZ_VERIFY_MAR_SIGNATURE
const MOZ_VERIFY_MAR_SIGNATURE = true; const MOZ_VERIFY_MAR_SIGNATURE = true;
#else #else

View File

@ -38,8 +38,8 @@ const URL_HTTP_UPDATE_SJS = "http://test_details/";
/* global INSTALL_LOCALE, MOZ_APP_NAME, BIN_SUFFIX, MOZ_APP_VENDOR */ /* global INSTALL_LOCALE, MOZ_APP_NAME, BIN_SUFFIX, MOZ_APP_VENDOR */
/* global MOZ_APP_BASENAME, APP_BIN_SUFFIX, APP_INFO_NAME, APP_INFO_VENDOR */ /* global MOZ_APP_BASENAME, APP_BIN_SUFFIX, APP_INFO_NAME, APP_INFO_VENDOR */
/* global IS_WIN, IS_MACOSX, IS_UNIX, IS_ANDROID, IS_TOOLKIT_GONK */ /* global IS_WIN, IS_MACOSX, IS_UNIX, MOZ_VERIFY_MAR_SIGNATURE */
/* global MOZ_VERIFY_MAR_SIGNATURE, MOZ_VERIFY_MAR_SIGNATURE, IS_AUTHENTICODE_CHECK_ENABLED */ /* global MOZ_VERIFY_MAR_SIGNATURE, IS_AUTHENTICODE_CHECK_ENABLED */
load("../data/xpcshellConstantsPP.js"); load("../data/xpcshellConstantsPP.js");
function getLogSuffix() { function getLogSuffix() {
@ -49,9 +49,6 @@ function getLogSuffix() {
if (IS_MACOSX) { if (IS_MACOSX) {
return "_mac"; return "_mac";
} }
if (IS_TOOLKIT_GONK) {
return "_gonk";
}
return "_linux"; return "_linux";
} }
@ -72,11 +69,6 @@ const COMPARE_LOG_SUFFIX = getLogSuffix();
const LOG_COMPLETE_SUCCESS = "complete_log_success" + COMPARE_LOG_SUFFIX; const LOG_COMPLETE_SUCCESS = "complete_log_success" + COMPARE_LOG_SUFFIX;
const LOG_PARTIAL_SUCCESS = "partial_log_success" + COMPARE_LOG_SUFFIX; const LOG_PARTIAL_SUCCESS = "partial_log_success" + COMPARE_LOG_SUFFIX;
const LOG_PARTIAL_FAILURE = "partial_log_failure" + COMPARE_LOG_SUFFIX; const LOG_PARTIAL_FAILURE = "partial_log_failure" + COMPARE_LOG_SUFFIX;
// Gonk sorts differently when applying and staging an update.
const LOG_COMPLETE_SUCCESS_STAGE = LOG_COMPLETE_SUCCESS +
(IS_TOOLKIT_GONK ? "_stage" : "");
const LOG_PARTIAL_SUCCESS_STAGE = LOG_PARTIAL_SUCCESS +
(IS_TOOLKIT_GONK ? "_stage" : "");
const LOG_REPLACE_SUCCESS = "replace_log_success"; const LOG_REPLACE_SUCCESS = "replace_log_success";
const USE_EXECV = IS_UNIX && !IS_MACOSX; const USE_EXECV = IS_UNIX && !IS_MACOSX;
@ -177,6 +169,7 @@ var gServiceLaunchedCallbackArgs = null;
var gCallbackBinFile = "callback_app" + BIN_SUFFIX; var gCallbackBinFile = "callback_app" + BIN_SUFFIX;
var gCallbackArgs = ["./", "callback.log", "Test Arg 2", "Test Arg 3"]; var gCallbackArgs = ["./", "callback.log", "Test Arg 2", "Test Arg 3"];
var gPostUpdateBinFile = "postup_app" + BIN_SUFFIX; var gPostUpdateBinFile = "postup_app" + BIN_SUFFIX;
var gSvcOriginalLogContents;
var gUseTestAppDir = true; var gUseTestAppDir = true;
// Some update staging failures can remove the update. This allows tests to // Some update staging failures can remove the update. This allows tests to
// specify that the status file and the active update should not be checked // specify that the status file and the active update should not be checked
@ -193,6 +186,7 @@ var gEnvXPCOMDebugBreak;
var gEnvXPCOMMemLeakLog; var gEnvXPCOMMemLeakLog;
var gEnvDyldLibraryPath; var gEnvDyldLibraryPath;
var gEnvLdLibraryPath; var gEnvLdLibraryPath;
var gASanOptions;
// Set to true to log additional information for debugging. To log additional // Set to true to log additional information for debugging. To log additional
// information for an individual test set DEBUG_AUS_TEST to true in the test's // information for an individual test set DEBUG_AUS_TEST to true in the test's
@ -929,9 +923,9 @@ function cleanupTestCommon() {
} }
} }
// The updates directory is located outside of the application directory on // The updates directory is located outside of the application directory and
// Windows, Mac OS X, and GONK and needs to be removed. // needs to be removed on Windows and Mac OS X.
if (IS_WIN || IS_MACOSX || IS_TOOLKIT_GONK) { if (IS_WIN || IS_MACOSX) {
let updatesDir = getMockUpdRootD(); let updatesDir = getMockUpdRootD();
// Try to remove the directory used to apply updates. Since the test has // Try to remove the directory used to apply updates. Since the test has
// already finished this is non-fatal for the test. // already finished this is non-fatal for the test.
@ -1013,7 +1007,7 @@ function setDefaultPrefs() {
// Enable Update logging // Enable Update logging
Services.prefs.setBoolPref(PREF_APP_UPDATE_LOG, true); Services.prefs.setBoolPref(PREF_APP_UPDATE_LOG, true);
} else { } else {
// Some apps (e.g. gonk) set this preference to true by default // Some apps set this preference to true by default
Services.prefs.setBoolPref(PREF_APP_UPDATE_LOG, false); Services.prefs.setBoolPref(PREF_APP_UPDATE_LOG, false);
} }
// In case telemetry is enabled for xpcshell tests. // In case telemetry is enabled for xpcshell tests.
@ -1412,12 +1406,6 @@ function getMockUpdRootD() {
return getMockUpdRootDMac(); return getMockUpdRootDMac();
} }
// The gonk updates directory is under /data/local but for the updater tests
// we use the following directory so the tests can run in parallel.
if (IS_TOOLKIT_GONK) {
return do_get_file(gTestID + "/", true);
}
return getApplyDirFile(DIR_MACOS, true); return getApplyDirFile(DIR_MACOS, true);
} }
@ -1661,9 +1649,17 @@ function logUpdateLog(aLogLeafName) {
} }
/** /**
* Launches the updater binary or the service to apply an update for updater * Gets the maintenance service log contents.
* tests. For non-service tests runUpdateUsingUpdater will be called and for */
* service tests runUpdateUsingService will be called. function readServiceLogFile() {
let file = getMaintSvcDir();
file.append("logs");
file.append("maintenanceservice.log");
return readFile(file);
}
/**
* Launches the updater binary to apply an update for updater tests.
* *
* @param aExpectedStatus * @param aExpectedStatus
* The expected value of update.status when the test finishes. For * The expected value of update.status when the test finishes. For
@ -1681,53 +1677,23 @@ function logUpdateLog(aLogLeafName) {
*/ */
function runUpdate(aExpectedStatus, aSwitchApp, aExpectedExitValue, function runUpdate(aExpectedStatus, aSwitchApp, aExpectedExitValue,
aCheckSvcLog) { aCheckSvcLog) {
let svcOriginalLog;
if (IS_SERVICE_TEST) { if (IS_SERVICE_TEST) {
let expectedStatus = aExpectedStatus; copyFileToTestAppDir(FILE_MAINTENANCE_SERVICE_BIN, false);
if (aExpectedStatus == STATE_PENDING) { copyFileToTestAppDir(FILE_MAINTENANCE_SERVICE_INSTALLER_BIN, false);
expectedStatus = STATE_PENDING_SVC; if (aCheckSvcLog) {
} else if (aExpectedStatus == STATE_APPLIED) { svcOriginalLog = readServiceLogFile();
expectedStatus = STATE_APPLIED_SVC;
} }
runUpdateUsingService(expectedStatus, aSwitchApp, aCheckSvcLog);
} else {
runUpdateUsingUpdater(aExpectedStatus, aSwitchApp, aExpectedExitValue);
} }
}
/**
* Launches the updater binary or the service to apply an update for updater
* tests. When completed runUpdateFinished will be called.
*
* @param aExpectedStatus
* The expected value of update.status when the test finishes.
* @param aSwitchApp
* If true the update should switch the application with an updated
* staged application and if false the update should be applied to the
* installed application.
* @param aExpectedExitValue
* The expected exit value from the updater binary.
*/
function runUpdateUsingUpdater(aExpectedStatus, aSwitchApp, aExpectedExitValue) {
// Copy the updater binary to the directory where it will apply updates. // Copy the updater binary to the directory where it will apply updates.
let updateBin = copyTestUpdaterForRunUsingUpdater(); let updateBin = copyTestUpdaterForRunUsingUpdater();
Assert.ok(updateBin.exists(), Assert.ok(updateBin.exists(),
MSG_SHOULD_EXIST + getMsgPath(updateBin.path)); MSG_SHOULD_EXIST + getMsgPath(updateBin.path));
let updatesDir = getUpdatesPatchDir(); let updatesDirPath = getUpdatesPatchDir().path;
let updatesDirPath = updatesDir.path; let applyToDirPath = getApplyDirFile(null, true).path;
let stageDirPath = getStageDirFile(null, true).path;
let applyToDir = getApplyDirFile(null, true);
let applyToDirPath = applyToDir.path;
let stageDir = getStageDirFile(null, true);
let stageDirPath = stageDir.path;
if (IS_WIN) {
// Convert to native path
updatesDirPath = updatesDirPath.replace(/\//g, "\\");
applyToDirPath = applyToDirPath.replace(/\//g, "\\");
stageDirPath = stageDirPath.replace(/\//g, "\\");
}
let callbackApp = getApplyDirFile(DIR_RESOURCES + gCallbackBinFile); let callbackApp = getApplyDirFile(DIR_RESOURCES + gCallbackBinFile);
callbackApp.permissions = PERMS_DIRECTORY; callbackApp.permissions = PERMS_DIRECTORY;
@ -1746,28 +1712,23 @@ function runUpdateUsingUpdater(aExpectedStatus, aSwitchApp, aExpectedExitValue)
args = args.concat(gCallbackArgs); args = args.concat(gCallbackArgs);
debugDump("running the updater: " + updateBin.path + " " + args.join(" ")); debugDump("running the updater: " + updateBin.path + " " + args.join(" "));
// See bug 1279108. if (aSwitchApp) {
// nsIProcess doesn't have an API to pass a separate environment to the // We want to set the env vars again
// subprocess, so we need to alter the environment of the current process gShouldResetEnv = undefined;
// before launching the updater binary.
let asan_options = null;
if (gEnv.exists("ASAN_OPTIONS")) {
asan_options = gEnv.get("ASAN_OPTIONS");
gEnv.set("ASAN_OPTIONS", asan_options + ":detect_leaks=0");
} else {
gEnv.set("ASAN_OPTIONS", "detect_leaks=0");
} }
setEnvironment();
let process = Cc["@mozilla.org/process/util;1"]. let process = Cc["@mozilla.org/process/util;1"].
createInstance(Ci.nsIProcess); createInstance(Ci.nsIProcess);
process.init(updateBin); process.init(updateBin);
process.run(true, args, args.length); process.run(true, args, args.length);
// Restore previous ASAN_OPTIONS if there were any. resetEnvironment();
gEnv.set("ASAN_OPTIONS", asan_options ? asan_options : "");
let status = readStatusFile(); let status = readStatusFile();
if (process.exitValue != aExpectedExitValue || status != aExpectedStatus) { if ((!IS_SERVICE_TEST && process.exitValue != aExpectedExitValue) ||
status != aExpectedStatus) {
if (process.exitValue != aExpectedExitValue) { if (process.exitValue != aExpectedExitValue) {
logTestInfo("updater exited with unexpected value! Got: " + logTestInfo("updater exited with unexpected value! Got: " +
process.exitValue + ", Expected: " + aExpectedExitValue); process.exitValue + ", Expected: " + aExpectedExitValue);
@ -1778,11 +1739,24 @@ function runUpdateUsingUpdater(aExpectedStatus, aSwitchApp, aExpectedExitValue)
} }
logUpdateLog(FILE_LAST_UPDATE_LOG); logUpdateLog(FILE_LAST_UPDATE_LOG);
} }
Assert.equal(process.exitValue, aExpectedExitValue,
"the process exit value" + MSG_SHOULD_EQUAL); if (!IS_SERVICE_TEST) {
Assert.equal(process.exitValue, aExpectedExitValue,
"the process exit value" + MSG_SHOULD_EQUAL);
}
Assert.equal(status, aExpectedStatus, Assert.equal(status, aExpectedStatus,
"the update status" + MSG_SHOULD_EQUAL); "the update status" + MSG_SHOULD_EQUAL);
if (IS_SERVICE_TEST && aCheckSvcLog) {
let contents = readServiceLogFile();
Assert.notEqual(contents, svcOriginalLog,
"the contents of the maintenanceservice.log should not " +
"be the same as the original contents");
Assert.notEqual(contents.indexOf(LOG_SVC_SUCCESSFUL_LAUNCH), -1,
"the contents of the maintenanceservice.log should " +
"contain the successful launch string");
}
do_execute_soon(runUpdateFinished); do_execute_soon(runUpdateFinished);
} }
@ -1905,12 +1879,15 @@ const gUpdateStagedObserver = {
/** /**
* Stages an update using nsIUpdateProcessor:processUpdate for updater tests. * Stages an update using nsIUpdateProcessor:processUpdate for updater tests.
*
* @param aCheckSvcLog
* Whether the service log should be checked for service tests.
*/ */
function stageUpdate() { function stageUpdate(aCheckSvcLog) {
debugDump("start - attempting to stage update"); debugDump("start - attempting to stage update");
if (IS_TOOLKIT_GONK) { if (IS_SERVICE_TEST && aCheckSvcLog) {
copyTestUpdaterToBinDir(); gSvcOriginalLogContents = readServiceLogFile();
} }
Services.obs.addObserver(gUpdateStagedObserver, "update-staged", false); Services.obs.addObserver(gUpdateStagedObserver, "update-staged", false);
@ -1991,6 +1968,16 @@ function checkUpdateStagedState(aUpdateState) {
MSG_SHOULD_NOT_EXIST + getMsgPath(stageDir.path)); MSG_SHOULD_NOT_EXIST + getMsgPath(stageDir.path));
} }
if (IS_SERVICE_TEST && gSvcOriginalLogContents !== undefined) {
let contents = readServiceLogFile();
Assert.notEqual(contents, gSvcOriginalLogContents,
"the contents of the maintenanceservice.log should not " +
"be the same as the original contents");
Assert.notEqual(contents.indexOf(LOG_SVC_SUCCESSFUL_LAUNCH), -1,
"the contents of the maintenanceservice.log should " +
"contain the successful launch string");
}
do_execute_soon(stageUpdateFinished); do_execute_soon(stageUpdateFinished);
} }
@ -2134,7 +2121,7 @@ function setupAppFiles() {
inGreDir: true}]; inGreDir: true}];
// On Linux the updater.png must also be copied // On Linux the updater.png must also be copied
if (IS_UNIX && !IS_MACOSX && !IS_TOOLKIT_GONK) { if (IS_UNIX && !IS_MACOSX) {
appFiles.push({relPath: "icons/updater.png", appFiles.push({relPath: "icons/updater.png",
inGreDir: true}); inGreDir: true});
} }
@ -2219,8 +2206,7 @@ function copyFileToTestAppDir(aFileRelPath, aInGreDir) {
let shouldSymlink = (pathParts[pathParts.length - 1] == "XUL" || let shouldSymlink = (pathParts[pathParts.length - 1] == "XUL" ||
fileRelPath.substr(fileRelPath.length - 3) == ".so" || fileRelPath.substr(fileRelPath.length - 3) == ".so" ||
fileRelPath.substr(fileRelPath.length - 6) == ".dylib"); fileRelPath.substr(fileRelPath.length - 6) == ".dylib");
// The tests don't support symlinks on gonk. if (!shouldSymlink) {
if (!shouldSymlink || IS_TOOLKIT_GONK) {
if (!destFile.exists()) { if (!destFile.exists()) {
try { try {
srcFile.copyToFollowingLinks(destFile.parent, destFile.leafName); srcFile.copyToFollowingLinks(destFile.parent, destFile.leafName);
@ -2380,157 +2366,6 @@ function waitForApplicationStop(aApplication) {
aApplication); aApplication);
} }
/**
* Helper function for updater tests for launching the updater using the
* maintenance service to apply a mar file. When complete runUpdateFinished
* will be called.
*
* @param aExpectedStatus
* The expected value of update.status when the test finishes.
* @param aSwitchApp
* If true the update should switch the application with an updated
* staged application and if false the update should be applied to the
* installed application.
* @param aCheckSvcLog
* Whether the service log should be checked.
*/
function runUpdateUsingService(aExpectedStatus, aSwitchApp, aCheckSvcLog) {
if (!IS_WIN) {
do_throw("Windows only function called by a different platform!");
}
let svcOriginalLog;
// Check the service logs for a successful update
function checkServiceLogs(aOriginalContents) {
let contents = readServiceLogFile();
Assert.notEqual(contents, aOriginalContents,
"the contents of the maintenanceservice.log should not " +
"be the same as the original contents");
Assert.notEqual(contents.indexOf(LOG_SVC_SUCCESSFUL_LAUNCH), -1,
"the contents of the maintenanceservice.log should " +
"contain the successful launch string");
}
function readServiceLogFile() {
let file = getMaintSvcDir();
file.append("logs");
file.append("maintenanceservice.log");
return readFile(file);
}
function checkServiceUpdateFinished() {
waitForApplicationStop(FILE_MAINTENANCE_SERVICE_BIN);
waitForApplicationStop(FILE_UPDATER_BIN);
// Wait for the expected status
let status;
try {
status = readStatusFile();
} catch (e) {
do_execute_soon(checkServiceUpdateFinished);
return;
}
// The status will probably always be equal to STATE_APPLYING but there is a
// race condition where it would be possible on slower machines where status
// could be equal to STATE_PENDING_SVC.
if (status == STATE_APPLYING) {
debugDump("still waiting to see the " + aExpectedStatus +
" status, got " + status + " for now...");
do_execute_soon(checkServiceUpdateFinished);
return;
}
// Make sure all of the logs are written out.
waitForServiceStop(false);
resetEnvironment();
if (status != aExpectedStatus) {
logTestInfo("update status is not the expected status! Got: " + status +
", Expected: " + aExpectedStatus);
logTestInfo("update.status contents: " + readStatusFile());
logUpdateLog(FILE_UPDATE_LOG);
}
Assert.equal(status, aExpectedStatus,
"the update status" + MSG_SHOULD_EQUAL);
if (aCheckSvcLog) {
checkServiceLogs(svcOriginalLog);
}
do_execute_soon(runUpdateFinished);
}
// Make sure the service from the previous test is already stopped.
waitForServiceStop(true);
// Prevent the cleanup function from begin run more than once
if (gRegisteredServiceCleanup === undefined) {
gRegisteredServiceCleanup = true;
do_register_cleanup(function RUUS_cleanup() {
resetEnvironment();
// This will delete the app arguments log file if it exists.
try {
getAppArgsLogPath();
} catch (e) {
logTestInfo("unable to remove file during cleanup. Exception: " + e);
}
});
}
if (aCheckSvcLog) {
svcOriginalLog = readServiceLogFile();
}
let appArgsLogPath = getAppArgsLogPath();
gServiceLaunchedCallbackLog = appArgsLogPath.replace(/^"|"$/g, "");
gServiceLaunchedCallbackArgs = [
"-no-remote",
"-test-process-updates",
"-dump-args",
appArgsLogPath
];
if (aSwitchApp) {
// We want to set the env vars again
gShouldResetEnv = undefined;
}
setEnvironment();
let updater = getTestDirFile(FILE_UPDATER_BIN);
if (!updater.exists()) {
do_throw("Unable to find the updater binary!");
}
let testBinDir = getGREBinDir();
updater.copyToFollowingLinks(testBinDir, updater.leafName);
// The service will execute maintenanceservice_installer.exe and
// will copy maintenanceservice.exe out of the same directory from
// the installation directory. So we need to make sure both of those
// bins always exist in the installation directory.
copyFileToTestAppDir(FILE_MAINTENANCE_SERVICE_BIN, false);
copyFileToTestAppDir(FILE_MAINTENANCE_SERVICE_INSTALLER_BIN, false);
let launchBin = getLaunchBin();
let args = getProcessArgs(["-dump-args", appArgsLogPath]);
let process = Cc["@mozilla.org/process/util;1"].
createInstance(Ci.nsIProcess);
process.init(launchBin);
debugDump("launching " + launchBin.path + " " + args.join(" "));
// Firefox does not wait for the service command to finish, but
// we still launch the process sync to avoid intermittent failures with
// the log file not being written out yet.
// We will rely on watching the update.status file and waiting for the service
// to stop to know the service command is done.
process.run(true, args, args.length);
do_execute_soon(checkServiceUpdateFinished);
}
/** /**
* Gets the platform specific shell binary that is launched using nsIProcess and * Gets the platform specific shell binary that is launched using nsIProcess and
@ -2663,7 +2498,8 @@ function waitForHelperSleep() {
do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the helper to " + do_throw("Exceeded MAX_TIMEOUT_RUNS while waiting for the helper to " +
"finish its operation. Path: " + output.path); "finish its operation. Path: " + output.path);
} }
do_execute_soon(waitForHelperSleep); // Uses do_timeout instead of do_execute_soon to lessen log spew.
do_timeout(FILE_IN_USE_TIMEOUT_MS, waitForHelperSleep);
return; return;
} }
try { try {
@ -2674,7 +2510,8 @@ function waitForHelperSleep() {
"message file to no longer be in use. Path: " + output.path); "message file to no longer be in use. Path: " + output.path);
} }
debugDump("failed to remove file. Path: " + output.path); debugDump("failed to remove file. Path: " + output.path);
do_execute_soon(waitForHelperSleep); // Uses do_timeout instead of do_execute_soon to lessen log spew.
do_timeout(FILE_IN_USE_TIMEOUT_MS, waitForHelperSleep);
return; return;
} }
waitForHelperSleepFinished(); waitForHelperSleepFinished();
@ -2690,7 +2527,8 @@ function waitForHelperFinished() {
// this test can fail intermittently on Windows debug builds. // this test can fail intermittently on Windows debug builds.
let output = getApplyDirFile(DIR_RESOURCES + "output", true); let output = getApplyDirFile(DIR_RESOURCES + "output", true);
if (readFile(output) != "finished\n") { if (readFile(output) != "finished\n") {
do_execute_soon(waitForHelperFinished); // Uses do_timeout instead of do_execute_soon to lessen log spew.
do_timeout(FILE_IN_USE_TIMEOUT_MS, waitForHelperFinished);
return; return;
} }
// Give the lock file process time to unlock the file before deleting the // Give the lock file process time to unlock the file before deleting the
@ -2828,12 +2666,7 @@ function setupUpdaterTest(aMarFile, aPostUpdateAsync) {
createUpdaterINI(aPostUpdateAsync); createUpdaterINI(aPostUpdateAsync);
} }
if (IS_TOOLKIT_GONK) { setupAppFilesAsync();
// Gonk doesn't use the app files in any of the tests.
do_execute_soon(setupUpdaterTestFinished);
} else {
setupAppFilesAsync();
}
} }
/** /**
@ -3346,30 +3179,16 @@ function checkFilesAfterUpdateCommon(aGetFileFunc, aStageDirExists,
} }
} }
/**
* Calls the appropriate callback log check for service and non-service tests.
*/
function checkCallbackLog() {
if (IS_SERVICE_TEST) {
// Prevent this check from being repeatedly logged in the xpcshell log by
// checking it here instead of in checkCallbackServiceLog.
Assert.ok(!!gServiceLaunchedCallbackLog,
"gServiceLaunchedCallbackLog should be defined");
checkCallbackServiceLog();
} else {
checkCallbackAppLog();
}
}
/** /**
* Helper function for updater binary tests for verifying the contents of the * Helper function for updater binary tests for verifying the contents of the
* updater callback application log which should contain the arguments passed to * updater callback application log which should contain the arguments passed to
* the callback application. * the callback application.
*/ */
function checkCallbackAppLog() { function checkCallbackLog() {
let appLaunchLog = getApplyDirFile(DIR_RESOURCES + gCallbackArgs[1], true); let appLaunchLog = getApplyDirFile(DIR_RESOURCES + gCallbackArgs[1], true);
if (!appLaunchLog.exists()) { if (!appLaunchLog.exists()) {
do_execute_soon(checkCallbackAppLog); // Uses do_timeout instead of do_execute_soon to lessen log spew.
do_timeout(FILE_IN_USE_TIMEOUT_MS, checkCallbackLog);
return; return;
} }
@ -3405,7 +3224,8 @@ function checkCallbackAppLog() {
// This should never happen! // This should never happen!
do_throw("Unable to find incorrect callback log contents!"); do_throw("Unable to find incorrect callback log contents!");
} }
do_execute_soon(checkCallbackAppLog); // Uses do_timeout instead of do_execute_soon to lessen log spew.
do_timeout(FILE_IN_USE_TIMEOUT_MS, checkCallbackLog);
return; return;
} }
Assert.ok(true, "the callback log contents" + MSG_SHOULD_EQUAL); Assert.ok(true, "the callback log contents" + MSG_SHOULD_EQUAL);
@ -4108,6 +3928,14 @@ function setEnvironment() {
gShouldResetEnv = true; gShouldResetEnv = true;
// See bug 1279108.
if (gEnv.exists("ASAN_OPTIONS")) {
gASanOptions = gEnv.get("ASAN_OPTIONS");
gEnv.set("ASAN_OPTIONS", gASanOptions + ":detect_leaks=0");
} else {
gEnv.set("ASAN_OPTIONS", "detect_leaks=0");
}
if (IS_WIN && !gEnv.exists("XRE_NO_WINDOWS_CRASH_DIALOG")) { if (IS_WIN && !gEnv.exists("XRE_NO_WINDOWS_CRASH_DIALOG")) {
gAddedEnvXRENoWindowsCrashDialog = true; gAddedEnvXRENoWindowsCrashDialog = true;
debugDump("setting the XRE_NO_WINDOWS_CRASH_DIALOG environment " + debugDump("setting the XRE_NO_WINDOWS_CRASH_DIALOG environment " +
@ -4171,8 +3999,10 @@ function setEnvironment() {
gEnv.set("XPCOM_DEBUG_BREAK", "warn"); gEnv.set("XPCOM_DEBUG_BREAK", "warn");
debugDump("setting MOZ_NO_SERVICE_FALLBACK environment variable to 1"); if (IS_SERVICE_TEST) {
gEnv.set("MOZ_NO_SERVICE_FALLBACK", "1"); debugDump("setting MOZ_NO_SERVICE_FALLBACK environment variable to 1");
gEnv.set("MOZ_NO_SERVICE_FALLBACK", "1");
}
} }
/** /**
@ -4187,6 +4017,9 @@ function resetEnvironment() {
gShouldResetEnv = false; gShouldResetEnv = false;
// Restore previous ASAN_OPTIONS if there were any.
gEnv.set("ASAN_OPTIONS", gASanOptions ? gASanOptions : "");
if (gEnvXPCOMMemLeakLog) { if (gEnvXPCOMMemLeakLog) {
debugDump("setting the XPCOM_MEM_LEAK_LOG environment variable back to " + debugDump("setting the XPCOM_MEM_LEAK_LOG environment variable back to " +
gEnvXPCOMMemLeakLog); gEnvXPCOMMemLeakLog);
@ -4228,6 +4061,8 @@ function resetEnvironment() {
gEnv.set("XRE_NO_WINDOWS_CRASH_DIALOG", ""); gEnv.set("XRE_NO_WINDOWS_CRASH_DIALOG", "");
} }
debugDump("removing MOZ_NO_SERVICE_FALLBACK environment variable"); if (IS_SERVICE_TEST) {
gEnv.set("MOZ_NO_SERVICE_FALLBACK", ""); debugDump("removing MOZ_NO_SERVICE_FALLBACK environment variable");
gEnv.set("MOZ_NO_SERVICE_FALLBACK", "");
}
} }

View File

@ -70,8 +70,6 @@ FINAL_TARGET_FILES += [
'data/complete.exe', 'data/complete.exe',
'data/complete.mar', 'data/complete.mar',
'data/complete.png', 'data/complete.png',
'data/complete_log_success_gonk',
'data/complete_log_success_gonk_stage',
'data/complete_log_success_mac', 'data/complete_log_success_mac',
'data/complete_log_success_win', 'data/complete_log_success_win',
'data/complete_mac.mar', 'data/complete_mac.mar',
@ -84,11 +82,8 @@ FINAL_TARGET_FILES += [
'data/partial.exe', 'data/partial.exe',
'data/partial.mar', 'data/partial.mar',
'data/partial.png', 'data/partial.png',
'data/partial_log_failure_gonk',
'data/partial_log_failure_mac', 'data/partial_log_failure_mac',
'data/partial_log_failure_win', 'data/partial_log_failure_win',
'data/partial_log_success_gonk',
'data/partial_log_success_gonk_stage',
'data/partial_log_success_mac', 'data/partial_log_success_mac',
'data/partial_log_success_win', 'data/partial_log_success_win',
'data/partial_mac.mar', 'data/partial_mac.mar',

View File

@ -20,16 +20,8 @@ function run_test() {
standardInit(); standardInit();
if (IS_TOOLKIT_GONK) { Assert.ok(!gUpdateManager.activeUpdate,
// Gonk doesn't resume downloads at boot time, so the update "there should not be an active update");
// will remain active until the user chooses a new one, at
// which point, the old update will be removed.
Assert.ok(!!gUpdateManager.activeUpdate,
"there should be an active update");
} else {
Assert.ok(!gUpdateManager.activeUpdate,
"there should not be an active update");
}
Assert.equal(gUpdateManager.updateCount, 0, Assert.equal(gUpdateManager.updateCount, 0,
"the update manager update count" + MSG_SHOULD_EQUAL); "the update manager update count" + MSG_SHOULD_EQUAL);

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