зеркало из https://github.com/mozilla/gecko-dev.git
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
Коммит
9c1c7106ee
|
@ -520,6 +520,9 @@
|
|||
@RESPATH@/components/remotebrowserutils.manifest
|
||||
@RESPATH@/components/RemoteWebNavigation.js
|
||||
|
||||
@RESPATH@/components/ProcessSelector.js
|
||||
@RESPATH@/components/ProcessSelector.manifest
|
||||
|
||||
@RESPATH@/components/SlowScriptDebug.manifest
|
||||
@RESPATH@/components/SlowScriptDebug.js
|
||||
|
||||
|
|
|
@ -0,0 +1,62 @@
|
|||
/* 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/. */
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
Cu.import('resource://gre/modules/Services.jsm');
|
||||
|
||||
const BASE_PREF = "dom.ipc.processCount"
|
||||
const PREF_BRANCH = BASE_PREF + ".";
|
||||
|
||||
// Utilities:
|
||||
function getMaxContentParents(processType) {
|
||||
let maxContentParents = -1;
|
||||
try {
|
||||
maxContentParents = Services.prefs.getIntPref(PREF_BRANCH + processType);
|
||||
} catch (e) {
|
||||
// Pref probably didn't exist, get the default number of processes.
|
||||
try {
|
||||
maxContentParents = Services.prefs.getIntPref(BASE_PREF);
|
||||
} catch (e) {
|
||||
// No prefs? That's odd, use only one process.
|
||||
maxContentParents = 1;
|
||||
}
|
||||
}
|
||||
|
||||
return maxContentParents;
|
||||
}
|
||||
|
||||
// Fills up aProcesses until max and then selects randomly from the available
|
||||
// ones.
|
||||
function RandomSelector() {
|
||||
}
|
||||
|
||||
RandomSelector.prototype = {
|
||||
classID: Components.ID("{c616fcfd-9737-41f1-aa74-cee72a38f91b}"),
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIContentProcessProvider]),
|
||||
|
||||
provideProcess(aType, aOpener, aProcesses, aCount) {
|
||||
let maxContentParents = getMaxContentParents(aType);
|
||||
if (aCount < maxContentParents) {
|
||||
return Ci.nsIContentProcessProvider.NEW_PROCESS;
|
||||
}
|
||||
|
||||
let startIdx = Math.floor(Math.random() * maxContentParents);
|
||||
let curIdx = startIdx;
|
||||
|
||||
do {
|
||||
if (aProcesses[curIdx].opener === aOpener) {
|
||||
return curIdx;
|
||||
}
|
||||
|
||||
curIdx = (curIdx + 1) % maxContentParents;
|
||||
} while (curIdx !== startIdx);
|
||||
|
||||
return Ci.nsIContentProcessProvider.NEW_PROCESS;
|
||||
},
|
||||
};
|
||||
|
||||
var components = [RandomSelector];
|
||||
this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
|
|
@ -0,0 +1,2 @@
|
|||
component {c616fcfd-9737-41f1-aa74-cee72a38f91b} ProcessSelector.js
|
||||
contract @mozilla.org/ipc/processselector;1 {c616fcfd-9737-41f1-aa74-cee72a38f91b}
|
|
@ -71,6 +71,11 @@ uint32_t TimeoutManager::sNestingLevel = 0;
|
|||
|
||||
namespace {
|
||||
|
||||
// The maximum number of timer callbacks we will try to run in a single event
|
||||
// loop runnable.
|
||||
#define DEFAULT_TARGET_MAX_CONSECUTIVE_CALLBACKS 5
|
||||
uint32_t gTargetMaxConsecutiveCallbacks;
|
||||
|
||||
// The number of queued runnables within the TabGroup ThrottledEventQueue
|
||||
// at which to begin applying back pressure to the window.
|
||||
#define DEFAULT_THROTTLED_EVENT_QUEUE_BACK_PRESSURE 5000
|
||||
|
@ -182,6 +187,10 @@ TimeoutManager::Initialize()
|
|||
Preferences::AddUintVarCache(&gBackPressureDelayMinimumMS,
|
||||
"dom.timeout.back_pressure_delay_minimum_ms",
|
||||
DEFAULT_BACK_PRESSURE_DELAY_MINIMUM_MS);
|
||||
|
||||
Preferences::AddUintVarCache(&gTargetMaxConsecutiveCallbacks,
|
||||
"dom.timeout.max_consecutive_callbacks",
|
||||
DEFAULT_TARGET_MAX_CONSECUTIVE_CALLBACKS);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
|
@ -444,6 +453,10 @@ TimeoutManager::RunTimeout(Timeout* aTimeout)
|
|||
mTrackingTimeouts,
|
||||
nullptr,
|
||||
nullptr);
|
||||
|
||||
uint32_t numTimersToRun = 0;
|
||||
bool targetTimerSeen = false;
|
||||
|
||||
while (true) {
|
||||
Timeout* timeout = expiredIter.Next();
|
||||
if (!timeout || timeout->When() > deadline) {
|
||||
|
@ -461,19 +474,29 @@ TimeoutManager::RunTimeout(Timeout* aTimeout)
|
|||
last_expired_tracking_timeout = timeout;
|
||||
}
|
||||
|
||||
// Run available timers until we see our target timer. After
|
||||
// that, however, stop coalescing timers so we can yield the
|
||||
// main thread. Further timers that are ready will get picked
|
||||
// up by their own nsITimer runnables when they execute.
|
||||
// Note that we have seen our target timer. This means we can now
|
||||
// stop processing timers once we hit our threshold below.
|
||||
if (timeout == aTimeout) {
|
||||
targetTimerSeen = true;
|
||||
}
|
||||
|
||||
// Run only a limited number of timers based on the configured
|
||||
// maximum. Note, we must always run our target timer however.
|
||||
// Further timers that are ready will get picked up by their own
|
||||
// nsITimer runnables when they execute.
|
||||
//
|
||||
// For chrome windows, however, we do coalesce all timers and
|
||||
// do not yield the main thread. This is partly because we
|
||||
// trust chrome windows not to misbehave and partly because a
|
||||
// number of browser chrome tests have races that depend on this
|
||||
// coalescing.
|
||||
if (timeout == aTimeout && !mWindow.IsChromeWindow()) {
|
||||
if (targetTimerSeen &&
|
||||
numTimersToRun >= gTargetMaxConsecutiveCallbacks &&
|
||||
!mWindow.IsChromeWindow()) {
|
||||
break;
|
||||
}
|
||||
|
||||
numTimersToRun += 1;
|
||||
}
|
||||
|
||||
expiredIter.UpdateIterator();
|
||||
|
|
|
@ -62,6 +62,12 @@ attribute OfflineResourceList.onupdateready
|
|||
attribute OfflineResourceList.oncached
|
||||
attribute OfflineResourceList.onobsolete
|
||||
|
||||
// Non-standard IndexedDB API
|
||||
method IDBDatabase.createMutableFile
|
||||
method IDBDatabase.mozCreateFileHandle
|
||||
method IDBMutableFile.open
|
||||
method IDBMutableFile.getFile
|
||||
|
||||
// DataTransfer API (gecko-only methods)
|
||||
method DataTransfer.addElement
|
||||
attribute DataTransfer.mozItemCount
|
||||
|
|
|
@ -401,6 +401,8 @@ EXTRA_COMPONENTS += [
|
|||
'contentAreaDropListener.manifest',
|
||||
'messageWakeupService.js',
|
||||
'messageWakeupService.manifest',
|
||||
'ProcessSelector.js',
|
||||
'ProcessSelector.manifest',
|
||||
'SlowScriptDebug.js',
|
||||
'SlowScriptDebug.manifest',
|
||||
]
|
||||
|
|
|
@ -11,6 +11,7 @@ XPIDL_SOURCES += [
|
|||
'nsIContentPermissionPrompt.idl',
|
||||
'nsIContentPrefService.idl',
|
||||
'nsIContentPrefService2.idl',
|
||||
'nsIContentProcess.idl',
|
||||
'nsIContentURIGrouper.idl',
|
||||
'nsIDOMChromeWindow.idl',
|
||||
'nsIDOMClientRect.idl',
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/* 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 "nsISupports.idl"
|
||||
|
||||
interface nsIDOMElement;
|
||||
interface nsIMessageSender;
|
||||
interface nsIURI;
|
||||
|
||||
[scriptable, builtinclass, uuid(456f58be-29dd-4973-885b-95aece1c9a8a)]
|
||||
interface nsIContentProcessInfo : nsISupports
|
||||
{
|
||||
/**
|
||||
* Is this content process alive?
|
||||
*/
|
||||
readonly attribute boolean isAlive;
|
||||
|
||||
/**
|
||||
* The content process's PID.
|
||||
* Throws if the process is not alive.
|
||||
*/
|
||||
readonly attribute int32_t processId;
|
||||
|
||||
/**
|
||||
* This content process's opener.
|
||||
*/
|
||||
readonly attribute nsIContentProcessInfo opener;
|
||||
|
||||
/**
|
||||
* The process manager for this ContentParent (so a process message manager
|
||||
* as opposed to a frame message manager.
|
||||
*/
|
||||
readonly attribute nsIMessageSender messageManager;
|
||||
};
|
||||
|
||||
[scriptable, uuid(83ffb063-5f65-4c45-ae07-3f553e0809bb)]
|
||||
interface nsIContentProcessProvider : nsISupports
|
||||
{
|
||||
/**
|
||||
* Return this from provideProcess to create a new process.
|
||||
*/
|
||||
const int32_t NEW_PROCESS = -1;
|
||||
|
||||
/**
|
||||
* Given aAliveProcesses (with an opener aOpener), choose which process of
|
||||
* aType to use. Return nsIContentProcessProvider.NEW_PROCESS to ask the
|
||||
* caller to create a new content process.
|
||||
*/
|
||||
int32_t provideProcess(in AString aType, in nsIContentProcessInfo aOpener,
|
||||
[array, size_is(aCount)] in nsIContentProcessInfo aAliveProcesses,
|
||||
in uint32_t aCount);
|
||||
};
|
|
@ -112,6 +112,7 @@
|
|||
#include "nsIAlertsService.h"
|
||||
#include "nsIClipboard.h"
|
||||
#include "nsContentPermissionHelper.h"
|
||||
#include "nsIContentProcess.h"
|
||||
#include "nsICycleCollectorListener.h"
|
||||
#include "nsIDocShellTreeOwner.h"
|
||||
#include "nsIDocument.h"
|
||||
|
@ -435,6 +436,90 @@ ContentParentsMemoryReporter::CollectReports(
|
|||
}
|
||||
|
||||
nsClassHashtable<nsStringHashKey, nsTArray<ContentParent*>>* ContentParent::sBrowserContentParents;
|
||||
|
||||
namespace {
|
||||
|
||||
class ScriptableCPInfo final : public nsIContentProcessInfo
|
||||
{
|
||||
public:
|
||||
explicit ScriptableCPInfo(ContentParent* aParent)
|
||||
: mContentParent(aParent)
|
||||
{
|
||||
MOZ_ASSERT(mContentParent);
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSICONTENTPROCESSINFO
|
||||
|
||||
void ProcessDied()
|
||||
{
|
||||
mContentParent = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
~ScriptableCPInfo()
|
||||
{
|
||||
MOZ_ASSERT(!mContentParent, "must call ProcessDied");
|
||||
}
|
||||
|
||||
ContentParent* mContentParent;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(ScriptableCPInfo, nsIContentProcessInfo)
|
||||
|
||||
NS_IMETHODIMP
|
||||
ScriptableCPInfo::GetIsAlive(bool* aIsAlive)
|
||||
{
|
||||
*aIsAlive = mContentParent != nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ScriptableCPInfo::GetProcessId(int32_t* aPID)
|
||||
{
|
||||
if (!mContentParent) {
|
||||
*aPID = -1;
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
*aPID = mContentParent->Pid();
|
||||
if (*aPID == -1) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ScriptableCPInfo::GetOpener(nsIContentProcessInfo** aInfo)
|
||||
{
|
||||
*aInfo = nullptr;
|
||||
if (!mContentParent) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
if (ContentParent* opener = mContentParent->Opener()) {
|
||||
nsCOMPtr<nsIContentProcessInfo> info = opener->ScriptableHelper();
|
||||
info.forget(aInfo);
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
ScriptableCPInfo::GetMessageManager(nsIMessageSender** aMessenger)
|
||||
{
|
||||
*aMessenger = nullptr;
|
||||
if (!mContentParent) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIMessageSender> manager = mContentParent->GetMessageManager();
|
||||
manager.forget(aMessenger);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
nsTArray<ContentParent*>* ContentParent::sPrivateContent;
|
||||
StaticAutoPtr<LinkedList<ContentParent> > ContentParent::sContentParents;
|
||||
#if defined(XP_LINUX) && defined(MOZ_CONTENT_SANDBOX)
|
||||
|
@ -697,38 +782,65 @@ ContentParent::GetNewOrUsedBrowserProcess(const nsAString& aRemoteType,
|
|||
ContentParent* aOpener)
|
||||
{
|
||||
nsTArray<ContentParent*>& contentParents = GetOrCreatePool(aRemoteType);
|
||||
|
||||
uint32_t maxContentParents = GetMaxProcessCount(aRemoteType);
|
||||
|
||||
RefPtr<ContentParent> p;
|
||||
if (contentParents.Length() >= maxContentParents) {
|
||||
if (aRemoteType.EqualsLiteral(LARGE_ALLOCATION_REMOTE_TYPE)) {
|
||||
// We never want to re-use Large-Allocation processes.
|
||||
if (aRemoteType.EqualsLiteral(LARGE_ALLOCATION_REMOTE_TYPE)) {
|
||||
if (contentParents.Length() >= maxContentParents) {
|
||||
return GetNewOrUsedBrowserProcess(NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE),
|
||||
aPriority,
|
||||
aOpener);
|
||||
}
|
||||
} else {
|
||||
nsTArray<nsIContentProcessInfo*> infos(contentParents.Length());
|
||||
for (auto* cp : contentParents) {
|
||||
infos.AppendElement(cp->mScriptableHelper);
|
||||
}
|
||||
|
||||
if ((p = RandomSelect(contentParents, aOpener, maxContentParents))) {
|
||||
nsCOMPtr<nsIContentProcessProvider> cpp =
|
||||
do_GetService("@mozilla.org/ipc/processselector;1");
|
||||
nsIContentProcessInfo* openerInfo = aOpener ? aOpener->mScriptableHelper.get() : nullptr;
|
||||
int32_t index;
|
||||
if (cpp &&
|
||||
NS_SUCCEEDED(cpp->ProvideProcess(aRemoteType, openerInfo,
|
||||
infos.Elements(), infos.Length(),
|
||||
&index))) {
|
||||
// If the provider returned an existing ContentParent, use that one.
|
||||
if (0 <= index && static_cast<uint32_t>(index) <= maxContentParents) {
|
||||
RefPtr<ContentParent> retval = contentParents[index];
|
||||
return retval.forget();
|
||||
}
|
||||
} else {
|
||||
// If there was a problem with the JS chooser, fall back to a random
|
||||
// selection.
|
||||
NS_WARNING("nsIContentProcessProvider failed to return a process");
|
||||
RefPtr<ContentParent> random;
|
||||
if (contentParents.Length() >= maxContentParents &&
|
||||
(random = RandomSelect(contentParents, aOpener, maxContentParents))) {
|
||||
return random.forget();
|
||||
}
|
||||
}
|
||||
|
||||
// Try to take the preallocated process only for the default process type.
|
||||
RefPtr<ContentParent> p;
|
||||
if (aRemoteType.EqualsLiteral(DEFAULT_REMOTE_TYPE) &&
|
||||
(p = PreallocatedProcessManager::Take())) {
|
||||
// For pre-allocated process we have not set the opener yet.
|
||||
p->mOpener = aOpener;
|
||||
contentParents.AppendElement(p);
|
||||
return p.forget();
|
||||
}
|
||||
}
|
||||
|
||||
// Try to take the preallocated process only for the default process type.
|
||||
if (aRemoteType.Equals(NS_LITERAL_STRING(DEFAULT_REMOTE_TYPE)) &&
|
||||
(p = PreallocatedProcessManager::Take())) {
|
||||
// For pre-allocated process we have not set the opener yet.
|
||||
p->mOpener = aOpener;
|
||||
} else {
|
||||
p = new ContentParent(aOpener, aRemoteType);
|
||||
// Create a new process from scratch.
|
||||
RefPtr<ContentParent> p = new ContentParent(aOpener, aRemoteType);
|
||||
|
||||
if (!p->LaunchSubprocess(aPriority)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
p->Init();
|
||||
if (!p->LaunchSubprocess(aPriority)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
p->Init();
|
||||
|
||||
contentParents.AppendElement(p);
|
||||
return p.forget();
|
||||
}
|
||||
|
@ -1204,6 +1316,8 @@ ContentParent::Init()
|
|||
|
||||
RefPtr<GeckoMediaPluginServiceParent> gmps(GeckoMediaPluginServiceParent::GetSingleton());
|
||||
gmps->UpdateContentProcessGMPCapabilities();
|
||||
|
||||
mScriptableHelper = new ScriptableCPInfo(this);
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
@ -1274,6 +1388,11 @@ ContentParent::SetPriorityAndCheckIsAlive(ProcessPriority aPriority)
|
|||
void
|
||||
ContentParent::ShutDownProcess(ShutDownMethod aMethod)
|
||||
{
|
||||
if (mScriptableHelper) {
|
||||
static_cast<ScriptableCPInfo*>(mScriptableHelper.get())->ProcessDied();
|
||||
mScriptableHelper = nullptr;
|
||||
}
|
||||
|
||||
// Shutting down by sending a shutdown message works differently than the
|
||||
// other methods. We first call Shutdown() in the child. After the child is
|
||||
// ready, it calls FinishShutdown() on us. Then we close the channel.
|
||||
|
|
|
@ -45,6 +45,7 @@
|
|||
#define LARGE_ALLOCATION_REMOTE_TYPE "webLargeAllocation"
|
||||
|
||||
class nsConsoleService;
|
||||
class nsIContentProcessInfo;
|
||||
class nsICycleCollectorLogSink;
|
||||
class nsIDumpGCAndCCLogsCallback;
|
||||
class nsITabParent;
|
||||
|
@ -371,6 +372,10 @@ public:
|
|||
{
|
||||
return mOpener;
|
||||
}
|
||||
nsIContentProcessInfo* ScriptableHelper() const
|
||||
{
|
||||
return mScriptableHelper;
|
||||
}
|
||||
|
||||
bool NeedsPermissionsUpdate() const
|
||||
{
|
||||
|
@ -1173,6 +1178,7 @@ private:
|
|||
|
||||
RefPtr<nsConsoleService> mConsoleService;
|
||||
nsConsoleService* GetConsoleService();
|
||||
nsCOMPtr<nsIContentProcessInfo> mScriptableHelper;
|
||||
|
||||
nsTArray<nsCOMPtr<nsIObserver>> mIdleListeners;
|
||||
|
||||
|
|
|
@ -39,10 +39,10 @@ partial interface IDBDatabase {
|
|||
[Func="mozilla::dom::IndexedDatabaseManager::ExperimentalFeaturesEnabled"]
|
||||
readonly attribute StorageType storage;
|
||||
|
||||
[Exposed=Window, Throws]
|
||||
[Exposed=Window, Throws, UseCounter]
|
||||
IDBRequest createMutableFile (DOMString name, optional DOMString type);
|
||||
|
||||
// this is deprecated due to renaming in the spec
|
||||
[Exposed=Window, Throws]
|
||||
[Exposed=Window, Throws, UseCounter]
|
||||
IDBRequest mozCreateFileHandle (DOMString name, optional DOMString type); // now createMutableFile
|
||||
};
|
||||
|
|
|
@ -10,10 +10,10 @@ interface IDBMutableFile : EventTarget {
|
|||
|
||||
readonly attribute IDBDatabase database;
|
||||
|
||||
[Throws]
|
||||
[Throws, UseCounter]
|
||||
IDBFileHandle open(optional FileMode mode = "readonly");
|
||||
|
||||
[Throws]
|
||||
[Throws, UseCounter]
|
||||
DOMRequest getFile();
|
||||
|
||||
attribute EventHandler onabort;
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
2014-09-18 Hyphen 2.8.8:
|
||||
- remove last coverity warning, 0 remaining
|
||||
|
||||
2014-06-27 Hyphen 2.8.7:
|
||||
- various clang scan-build warning fixes
|
||||
|
||||
2012-09-13 Hyphen 2.8.6:
|
||||
- righthyphenmin fix for 3-byte or more UTF-8
|
||||
multibyte characters by Steven Dickson
|
||||
- fix for fdo#43931 (removing hard hyphen hyphenation for LibreOffice)
|
||||
|
||||
2012-07-12 Hyphen 2.8.5:
|
||||
- fix short alloc
|
||||
|
||||
2012-06-29 Hyphen 2.8.4:
|
||||
- coverity warnings
|
||||
|
||||
2011-10-10 Hyphen 2.8.3:
|
||||
- fix NOHYPHEN
|
||||
- fix unbalanced hyphenation of LibreOffice/OOo
|
||||
- set default COMPOUNDHYPHENMIN=3 at hyphens and apostrophes
|
||||
- fix VERBOSE in hyphen.c
|
||||
- new ./example option: -n to print hyphenation vector
|
||||
|
||||
2011-10-07 Hyphen 2.8.2:
|
||||
- fix for explicite COMPOUNDHYPHENMIN values
|
||||
|
||||
2011-10-06 Hyphen 2.8.1:
|
||||
- force minimal lefthyphenmin and righthyphenmin values of the dictionary
|
||||
(eg. righthyphenmin=3 of English dictionaries in LibreOffice/OOo,
|
||||
also the original TeX hyphenation patterns are correct only with this
|
||||
righthyphenmin value).
|
||||
|
||||
2011-10-04 Hyphen 2.8:
|
||||
- Ignore leading and ending numbers (eg. manual/field based indexes
|
||||
in LibreOffice/OOo)
|
||||
|
||||
- Fix LibreOffice/OpenOffice.org hyphenation errors at apostrophes and
|
||||
hyphens, n-dashes with default NOHYPHEN separators.
|
||||
Eg. *o'c=lock -> o'clock.
|
||||
|
||||
2010-12-01 Hyphen 2.7.1 bug fix release
|
||||
|
||||
2010-11-27 Hyphen 2.7 release:
|
||||
- The new hyphenation problem of OpenOffice.org 3.2, related to its
|
||||
modified word breaking of words with hyphen characters, can be fixed
|
||||
with the new NOHYPHEN feature. Also it's possible to solve the similar old
|
||||
problem with apostrophes. More information: README.compound.
|
||||
|
||||
- improved English dictionaries
|
||||
|
||||
2010-08-10 Hyphen 2.6 release:
|
||||
- maintainance release, fix all warnings, tidy up
|
||||
make check with VALGRIND=memcheck, etc.
|
||||
|
||||
2010-02-23 Hyphen 2.5 release:
|
||||
- add Unicode ligature support for correct hyphenmin calculation
|
||||
(ff, fi, fl, St, st are 1-character, ffi and ffl are 2-character length for
|
||||
hyphenation)
|
||||
- fix lefthyphenmin calculation for UTF-8 encoded input
|
||||
|
||||
- en_US hyphenation dictionary:
|
||||
- add OpenOffice.org patch to fix apostrophe handling
|
||||
- add correct hyphenation for words with Unicode f-ligatures
|
||||
(NOTE: hyphenation within ligatures is not supported yet
|
||||
because of an implementation problem of OpenOffice.org,
|
||||
see OOo issue 71608.)
|
||||
|
||||
- small patches from OpenOffice.org
|
||||
|
||||
2008-05-01 Hyphen 2.4 release:
|
||||
- compound word hyphenation support by recursive pattern matching
|
||||
based on two hyphenation pattern sets, see README.compound.
|
||||
Especially useful for languages with arbitrary number of compounds (Danish,
|
||||
Dutch, Finnish, German, Hungarian, Icelandic, Norwegian, Swedish etc.).
|
||||
|
||||
- new dictionary parameters (minimal character numbers for hyph. distances):
|
||||
LEFTHYPHENMIN: minimal hyphenation distance from the left end of the word
|
||||
RIGHTHYPHENMIN: minimal hyphenation distance from the right end of the word
|
||||
COMPOUNDLEFTHYPHENMIN: min. hyph. dist. from the left compound word boundary
|
||||
COMPOUNDRIGHTHYPHENMIN: min. hyph. dist. from the right comp. word boundary
|
||||
|
||||
- new API function: hnj_hyphen_hyphenate3() (like hyphenate2(), but
|
||||
with hyphenmin options)
|
||||
|
||||
en_US hyphenation patterns:
|
||||
|
||||
- extended hyph_en_US.dic with TugBoat hyphenation log (fix thousand
|
||||
incompletely or badly hyphenated words, for example acad-e-my, acro-nym,
|
||||
acryl-amide, adren-a-line, aero-space, am-phet-a-mine, anom-aly etc.)
|
||||
|
||||
- fixed hyph_en_US.dic: set the right default hyphenation distance of
|
||||
the original TeX hyphenation patterns:
|
||||
LEFTHYPHENMIN 2
|
||||
RIGHTHYPHENMIN 3 (not 2!)
|
||||
It is not only a typographical issue. It seems, TeX hyphenation
|
||||
patterns are right only with these settings, for example,
|
||||
the bad "anoma-ly" is restricted in TeX only by the default
|
||||
\righthyphenmin=3 (but not restricted in OpenOffice.org, until now).
|
||||
|
||||
- documentation (README_hyph_en_US.dic)
|
||||
|
||||
- fixes for automake configuration, compiling and checking, see ChangeLog
|
||||
|
||||
2008-02-19: Hyphen 2.3.1 release:
|
||||
- fix obsolete API function hnj_hyphen_hyphenate()
|
|
@ -78,6 +78,7 @@ enum class DeclarationKind : uint8_t
|
|||
Const,
|
||||
Import,
|
||||
BodyLevelFunction,
|
||||
ModuleBodyLevelFunction,
|
||||
LexicalFunction,
|
||||
VarForAnnexBLexicalFunction,
|
||||
SimpleCatchParameter,
|
||||
|
@ -95,6 +96,7 @@ DeclarationKindToBindingKind(DeclarationKind kind)
|
|||
|
||||
case DeclarationKind::Var:
|
||||
case DeclarationKind::BodyLevelFunction:
|
||||
case DeclarationKind::ModuleBodyLevelFunction:
|
||||
case DeclarationKind::VarForAnnexBLexicalFunction:
|
||||
case DeclarationKind::ForOfVar:
|
||||
return BindingKind::Var;
|
||||
|
|
|
@ -117,6 +117,7 @@ DeclarationKindString(DeclarationKind kind)
|
|||
case DeclarationKind::Import:
|
||||
return "import";
|
||||
case DeclarationKind::BodyLevelFunction:
|
||||
case DeclarationKind::ModuleBodyLevelFunction:
|
||||
case DeclarationKind::LexicalFunction:
|
||||
return "function";
|
||||
case DeclarationKind::VarForAnnexBLexicalFunction:
|
||||
|
@ -1379,6 +1380,24 @@ Parser<ParseHandler>::noteDeclaredName(HandlePropertyName name, DeclarationKind
|
|||
break;
|
||||
}
|
||||
|
||||
case DeclarationKind::ModuleBodyLevelFunction: {
|
||||
MOZ_ASSERT(pc->atModuleLevel());
|
||||
|
||||
AddDeclaredNamePtr p = pc->varScope().lookupDeclaredNameForAdd(name);
|
||||
if (p) {
|
||||
reportRedeclaration(name, p->value()->kind(), pos, p->value()->pos());
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!pc->varScope().addDeclaredName(pc, p, name, kind, pos.begin))
|
||||
return false;
|
||||
|
||||
// Body-level functions in modules are always closed over.
|
||||
pc->varScope().lookupDeclaredName(name)->value()->setClosedOver();
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case DeclarationKind::FormalParameter: {
|
||||
// It is an early error if any non-positional formal parameter name
|
||||
// (e.g., destructuring formal parameter) is duplicated.
|
||||
|
@ -3718,12 +3737,11 @@ Parser<ParseHandler>::functionStmt(YieldHandling yieldHandling, DefaultHandling
|
|||
if (!noteDeclaredName(name, DeclarationKind::LexicalFunction, pos()))
|
||||
return null();
|
||||
} else {
|
||||
if (!noteDeclaredName(name, DeclarationKind::BodyLevelFunction, pos()))
|
||||
DeclarationKind kind = pc->atModuleLevel()
|
||||
? DeclarationKind::ModuleBodyLevelFunction
|
||||
: DeclarationKind::BodyLevelFunction;
|
||||
if (!noteDeclaredName(name, kind, pos()))
|
||||
return null();
|
||||
|
||||
// Body-level functions in modules are always closed over.
|
||||
if (pc->atModuleLevel())
|
||||
pc->varScope().lookupDeclaredName(name)->value()->setClosedOver();
|
||||
}
|
||||
|
||||
Node pn = handler.newFunctionStatement();
|
||||
|
|
|
@ -1,4 +1,2 @@
|
|||
function async() { return 42; } // overwritten by subsequent declaration
|
||||
|
||||
export default async // ASI occurs here due to the [no LineTerminator here] restriction on default-exporting an async function
|
||||
function async() { return 17; }
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
load(libdir + "asserts.js");
|
||||
|
||||
var functionDeclarations = [
|
||||
"function f(){}",
|
||||
"function* f(){}",
|
||||
"async function f(){}",
|
||||
];
|
||||
|
||||
var varDeclarations = [
|
||||
"var f",
|
||||
"{ var f; }",
|
||||
"for (var f in null);",
|
||||
"for (var f of null);",
|
||||
"for (var f; ;);",
|
||||
];
|
||||
|
||||
var lexicalDeclarations = [
|
||||
"let f;",
|
||||
"const f = 0;",
|
||||
"class f {};",
|
||||
];
|
||||
|
||||
var imports = [
|
||||
"import f from '';",
|
||||
"import f, {} from '';",
|
||||
"import d, {f} from '';",
|
||||
"import d, {f as f} from '';",
|
||||
"import d, {foo as f} from '';",
|
||||
"import f, * as d from '';",
|
||||
"import d, * as f from '';",
|
||||
"import {f} from '';",
|
||||
"import {f as f} from '';",
|
||||
"import {foo as f} from '';",
|
||||
"import* as f from '';",
|
||||
];
|
||||
|
||||
var exports = [
|
||||
"export var f;",
|
||||
...functionDeclarations.map(fn => `export ${fn};`),
|
||||
...lexicalDeclarations.map(ld => `export ${ld};`),
|
||||
...functionDeclarations.map(fn => `export default ${fn};`),
|
||||
"export default class f {};",
|
||||
];
|
||||
|
||||
var redeclarations = [
|
||||
...functionDeclarations,
|
||||
...varDeclarations,
|
||||
...lexicalDeclarations,
|
||||
...imports,
|
||||
...exports,
|
||||
];
|
||||
|
||||
var noredeclarations = [
|
||||
...functionDeclarations.map(fn => `{ ${fn} }`),
|
||||
...lexicalDeclarations.map(ld => `{ ${ld} }`),
|
||||
...["let", "const"].map(ld => `for (${ld} f in null);`),
|
||||
...["let", "const"].map(ld => `for (${ld} f of null);`),
|
||||
...["let", "const"].map(ld => `for (${ld} f = 0; ;);`),
|
||||
"export {f};",
|
||||
"export {f as f};",
|
||||
"export {foo as f}; var foo;",
|
||||
"export {f} from '';",
|
||||
"export {f as f} from '';",
|
||||
"export {foo as f} from '';",
|
||||
];
|
||||
|
||||
for (var decl of functionDeclarations) {
|
||||
for (var redecl of redeclarations) {
|
||||
assertThrowsInstanceOf(() => {
|
||||
parseModule(`
|
||||
${decl}
|
||||
${redecl}
|
||||
`);
|
||||
}, SyntaxError);
|
||||
|
||||
assertThrowsInstanceOf(() => {
|
||||
parseModule(`
|
||||
${redecl}
|
||||
${decl}
|
||||
`);
|
||||
}, SyntaxError);
|
||||
}
|
||||
|
||||
for (var redecl of noredeclarations) {
|
||||
parseModule(`
|
||||
${decl}
|
||||
${redecl}
|
||||
`);
|
||||
parseModule(`
|
||||
${redecl}
|
||||
${decl}
|
||||
`);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
// Tests that function imports and function exports descriptors have
|
||||
// signatures, in the test mode only, for fuzzers.
|
||||
|
||||
var module = new WebAssembly.Module(wasmTextToBinary(`(module
|
||||
(import $vv "env" "v_v")
|
||||
(export "v_v" $vv)
|
||||
|
||||
(import $vi "env" "v_i" (param i32))
|
||||
(export "v_i" $vi)
|
||||
|
||||
(import $vI "env" "v_I" (param i64))
|
||||
(export "v_I" $vI)
|
||||
|
||||
(import $vf "env" "v_f" (param f32))
|
||||
(export "v_f" $vf)
|
||||
|
||||
(import $mem "env" "memory" (memory 0))
|
||||
(export "mem" (memory $mem))
|
||||
|
||||
(import $vd "env" "v_d" (param f64))
|
||||
(export "v_d" $vd)
|
||||
|
||||
(import $vfd "env" "v_fd" (param f32) (param f64))
|
||||
(export "v_fd" $vfd)
|
||||
|
||||
(import $vIfifd "env" "v_Ififd" (param i64) (param f32) (param i32) (param f32) (param f64))
|
||||
(export "v_Ififd" $vIfifd)
|
||||
|
||||
(import $iv "env" "i_v" (result i32))
|
||||
(export "i_v" $iv)
|
||||
|
||||
(import $Ii "env" "I_i" (result i64) (param i32))
|
||||
(export "I_i" $Ii)
|
||||
|
||||
(import $table "env" "table" (table 0 anyfunc))
|
||||
(export "table" (table $table))
|
||||
|
||||
(import $fd "env" "f_d" (result f32) (param f64))
|
||||
(export "f_d" $fd)
|
||||
|
||||
(import $dffd "env" "d_ffd" (result f64) (param f32) (param f32) (param f64))
|
||||
(export "d_ffd" $dffd)
|
||||
)`));
|
||||
|
||||
for (let desc of WebAssembly.Module.imports(module)) {
|
||||
assertEq(typeof desc.signature, 'undefined');
|
||||
}
|
||||
for (let desc of WebAssembly.Module.exports(module)) {
|
||||
assertEq(typeof desc.signature, 'undefined');
|
||||
}
|
||||
|
||||
setJitCompilerOption('wasm.test-mode', 1);
|
||||
|
||||
function shortToType(s) {
|
||||
switch (s) {
|
||||
case 'v': return "";
|
||||
case 'i': return "i32";
|
||||
case 'I': return "i64";
|
||||
case 'f': return "f32";
|
||||
case 'd': return "f64";
|
||||
}
|
||||
throw new Error("unexpected shorthand type");
|
||||
}
|
||||
|
||||
function expectedSignature(name) {
|
||||
let [ret, args] = name.split('_');
|
||||
|
||||
args = args.split('').map(shortToType).join(', ');
|
||||
ret = shortToType(ret);
|
||||
|
||||
return `(${args}) -> (${ret})`;
|
||||
}
|
||||
|
||||
for (let desc of WebAssembly.Module.imports(module)) {
|
||||
if (desc.kind !== 'function') {
|
||||
assertEq(typeof desc.signature, 'undefined');
|
||||
} else {
|
||||
assertEq(desc.signature, expectedSignature(desc.name))
|
||||
}
|
||||
}
|
||||
|
||||
for (let desc of WebAssembly.Module.exports(module)) {
|
||||
if (desc.kind !== 'function') {
|
||||
assertEq(typeof desc.signature, 'undefined');
|
||||
} else {
|
||||
assertEq(desc.signature, expectedSignature(desc.name))
|
||||
}
|
||||
}
|
|
@ -3,5 +3,12 @@
|
|||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
// Call the shell helper to add experimental features to the Intl object.
|
||||
if (typeof addIntlExtras === "function")
|
||||
addIntlExtras(Intl);
|
||||
if (typeof addIntlExtras === "function") {
|
||||
let intlExtras = {};
|
||||
addIntlExtras(intlExtras);
|
||||
|
||||
Object.defineProperty(Intl, "PluralRules", {
|
||||
value: intlExtras.PluralRules,
|
||||
writable: true, enumerable: false, configurable: true
|
||||
});
|
||||
}
|
||||
|
|
|
@ -4,5 +4,12 @@
|
|||
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
// Call the shell helper to add experimental features to the Intl object.
|
||||
if (typeof addIntlExtras === "function")
|
||||
addIntlExtras(Intl);
|
||||
if (typeof addIntlExtras === "function") {
|
||||
let intlExtras = {};
|
||||
addIntlExtras(intlExtras);
|
||||
|
||||
Object.defineProperty(Intl, "PluralRules", {
|
||||
value: intlExtras.PluralRules,
|
||||
writable: true, enumerable: false, configurable: true
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1500,8 +1500,19 @@ SetObjectElementOperation(JSContext* cx, HandleObject obj, HandleId id, HandleVa
|
|||
}
|
||||
}
|
||||
|
||||
if (obj->isNative() && !JSID_IS_INT(id) && !JSObject::setHadElementsAccess(cx, obj))
|
||||
return false;
|
||||
// Set the HadElementsAccess flag on the object if needed. This flag is
|
||||
// used to do more eager dictionary-mode conversion for objects that are
|
||||
// used as hashmaps. Set this flag only for objects with many properties,
|
||||
// to avoid unnecessary Shape changes.
|
||||
if (obj->isNative() &&
|
||||
JSID_IS_ATOM(id) &&
|
||||
!obj->as<NativeObject>().inDictionaryMode() &&
|
||||
!obj->hadElementsAccess() &&
|
||||
obj->as<NativeObject>().slotSpan() > PropertyTree::MAX_HEIGHT_WITH_ELEMENTS_ACCESS / 3)
|
||||
{
|
||||
if (!JSObject::setHadElementsAccess(cx, obj))
|
||||
return false;
|
||||
}
|
||||
|
||||
ObjectOpResult result;
|
||||
return SetProperty(cx, obj, id, value, receiver, result) &&
|
||||
|
|
|
@ -28,6 +28,7 @@
|
|||
#include "jit/JitOptions.h"
|
||||
#include "vm/Interpreter.h"
|
||||
#include "vm/String.h"
|
||||
#include "vm/StringBuffer.h"
|
||||
#include "wasm/WasmCompile.h"
|
||||
#include "wasm/WasmInstance.h"
|
||||
#include "wasm/WasmModule.h"
|
||||
|
@ -554,8 +555,9 @@ struct KindNames
|
|||
RootedPropertyName kind;
|
||||
RootedPropertyName table;
|
||||
RootedPropertyName memory;
|
||||
RootedPropertyName signature;
|
||||
|
||||
explicit KindNames(JSContext* cx) : kind(cx), table(cx), memory(cx) {}
|
||||
explicit KindNames(JSContext* cx) : kind(cx), table(cx), memory(cx), signature(cx) {}
|
||||
};
|
||||
|
||||
static bool
|
||||
|
@ -576,6 +578,11 @@ InitKindNames(JSContext* cx, KindNames* names)
|
|||
return false;
|
||||
names->memory = memory->asPropertyName();
|
||||
|
||||
JSAtom* signature = Atomize(cx, "signature", strlen("signature"));
|
||||
if (!signature)
|
||||
return false;
|
||||
names->signature = signature->asPropertyName();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -596,6 +603,40 @@ KindToString(JSContext* cx, const KindNames& names, DefinitionKind kind)
|
|||
MOZ_CRASH("invalid kind");
|
||||
}
|
||||
|
||||
static JSString*
|
||||
SigToString(JSContext* cx, const Sig& sig)
|
||||
{
|
||||
StringBuffer buf(cx);
|
||||
if (!buf.append('('))
|
||||
return nullptr;
|
||||
|
||||
bool first = true;
|
||||
for (ValType arg : sig.args()) {
|
||||
if (!first && !buf.append(", ", strlen(", ")))
|
||||
return nullptr;
|
||||
|
||||
const char* argStr = ToCString(arg);
|
||||
if (!buf.append(argStr, strlen(argStr)))
|
||||
return nullptr;
|
||||
|
||||
first = false;
|
||||
}
|
||||
|
||||
if (!buf.append(") -> (", strlen(") -> (")))
|
||||
return nullptr;
|
||||
|
||||
if (sig.ret() != ExprType::Void) {
|
||||
const char* retStr = ToCString(sig.ret());
|
||||
if (!buf.append(retStr, strlen(retStr)))
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!buf.append(')'))
|
||||
return nullptr;
|
||||
|
||||
return buf.finishString();
|
||||
}
|
||||
|
||||
static JSString*
|
||||
UTF8CharsToString(JSContext* cx, const char* chars)
|
||||
{
|
||||
|
@ -619,6 +660,7 @@ WasmModuleObject::imports(JSContext* cx, unsigned argc, Value* vp)
|
|||
if (!elems.reserve(module->imports().length()))
|
||||
return false;
|
||||
|
||||
size_t numFuncImport = 0;
|
||||
for (const Import& import : module->imports()) {
|
||||
Rooted<IdValueVector> props(cx, IdValueVector(cx));
|
||||
if (!props.reserve(3))
|
||||
|
@ -639,6 +681,14 @@ WasmModuleObject::imports(JSContext* cx, unsigned argc, Value* vp)
|
|||
return false;
|
||||
props.infallibleAppend(IdValuePair(NameToId(names.kind), StringValue(kindStr)));
|
||||
|
||||
if (JitOptions.wasmTestMode && import.kind == DefinitionKind::Function) {
|
||||
JSString* sigStr = SigToString(cx, module->metadata().funcImports[numFuncImport++].sig());
|
||||
if (!sigStr)
|
||||
return false;
|
||||
if (!props.append(IdValuePair(NameToId(names.signature), StringValue(sigStr))))
|
||||
return false;
|
||||
}
|
||||
|
||||
JSObject* obj = ObjectGroup::newPlainObject(cx, props.begin(), props.length(), GenericObject);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
@ -671,6 +721,7 @@ WasmModuleObject::exports(JSContext* cx, unsigned argc, Value* vp)
|
|||
if (!elems.reserve(module->exports().length()))
|
||||
return false;
|
||||
|
||||
size_t numFuncExport = 0;
|
||||
for (const Export& exp : module->exports()) {
|
||||
Rooted<IdValueVector> props(cx, IdValueVector(cx));
|
||||
if (!props.reserve(2))
|
||||
|
@ -686,6 +737,14 @@ WasmModuleObject::exports(JSContext* cx, unsigned argc, Value* vp)
|
|||
return false;
|
||||
props.infallibleAppend(IdValuePair(NameToId(names.kind), StringValue(kindStr)));
|
||||
|
||||
if (JitOptions.wasmTestMode && exp.kind() == DefinitionKind::Function) {
|
||||
JSString* sigStr = SigToString(cx, module->metadata().funcExports[numFuncExport++].sig());
|
||||
if (!sigStr)
|
||||
return false;
|
||||
if (!props.append(IdValuePair(NameToId(names.signature), StringValue(sigStr))))
|
||||
return false;
|
||||
}
|
||||
|
||||
JSObject* obj = ObjectGroup::newPlainObject(cx, props.begin(), props.length(), GenericObject);
|
||||
if (!obj)
|
||||
return false;
|
||||
|
|
|
@ -21,8 +21,20 @@ function loadHandler() {
|
|||
inner.height = "5px";
|
||||
inner.offsetTop;
|
||||
}
|
||||
|
||||
// This function is a hack to avoid sporadic test-failures with...
|
||||
// "...timed out waiting for reftest-wait to be removed".
|
||||
// Occasionally, it seems this test loses a race condition of some sort, and
|
||||
// its resize handler isn't invoked. When that happens (and specifically, when
|
||||
// the test runs for longer than 500ms), we clear reftest-wait and call the
|
||||
// run a "pass" (which is kind of valid, because we didn't crash!) and move on.
|
||||
function setupFailsafe() {
|
||||
setTimeout(() => {
|
||||
document.documentElement.removeAttribute("class");
|
||||
}, 500);
|
||||
}
|
||||
</script>
|
||||
<body>
|
||||
<body onload="setupFailsafe()">
|
||||
<iframe id="outer"
|
||||
src="data:text/html,<html><body>"
|
||||
onload="loadHandler()">
|
||||
|
|
|
@ -5,4 +5,4 @@ Makefile.in build files for the Mozilla build system.
|
|||
|
||||
The cubeb git repository is: git://github.com/kinetiknz/cubeb.git
|
||||
|
||||
The git commit ID used was 25b593fa59d0c284ff2de54b10db927d48579f5e.
|
||||
The git commit ID used was 25b593fa59d0c284ff2de54b10db927d48579f5e (2017-02-23 14:05:03 +0200)
|
||||
|
|
|
@ -48,6 +48,7 @@ cp $1/test/test_mixer.cpp gtest
|
|||
|
||||
if [ -d $1/.git ]; then
|
||||
rev=$(cd $1 && git rev-parse --verify HEAD)
|
||||
date=$(cd $1 && git show -s --format=%ci HEAD)
|
||||
dirty=$(cd $1 && git diff-index --name-only HEAD)
|
||||
fi
|
||||
|
||||
|
@ -57,7 +58,7 @@ if [ -n "$rev" ]; then
|
|||
version=$version-dirty
|
||||
echo "WARNING: updating from a dirty git repository."
|
||||
fi
|
||||
sed -i.bak -e "/The git commit ID used was/ s/[0-9a-f]\{40\}\(-dirty\)\{0,1\}\./$version./" README_MOZILLA
|
||||
sed -i.bak -e "/The git commit ID used was/ s/[0-9a-f]\{40\}\(-dirty\)\{0,1\} .\{1,100\}/$version ($date)/" README_MOZILLA
|
||||
rm README_MOZILLA.bak
|
||||
else
|
||||
echo "Remember to update README_MOZILLA with the version details."
|
||||
|
|
|
@ -5,10 +5,12 @@
|
|||
package org.mozilla.gecko;
|
||||
|
||||
import org.mozilla.gecko.GeckoAppShell;
|
||||
import org.mozilla.gecko.permissions.Permissions;
|
||||
import org.mozilla.gecko.util.BundleEventListener;
|
||||
import org.mozilla.gecko.util.EventCallback;
|
||||
import org.mozilla.gecko.util.GeckoBundle;
|
||||
|
||||
import android.Manifest;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
|
@ -61,15 +63,42 @@ public class FilePicker implements BundleEventListener {
|
|||
mimeType = GeckoAppShell.getMimeTypeFromExtensions(message.getString("extensions", ""));
|
||||
}
|
||||
|
||||
showFilePickerAsync(title, mimeType, new ResultHandler() {
|
||||
@Override
|
||||
public void gotFile(final String filename) {
|
||||
callback.sendSuccess(filename);
|
||||
}
|
||||
}, tabId);
|
||||
final String[] requiredPermission = getPermissionsForMimeType(mimeType);
|
||||
final String finalMimeType = mimeType;
|
||||
// Use activity context cause we want to prompt for runtime permission. (bug 1337692)
|
||||
Permissions.from(GeckoAppShell.getGeckoInterface().getActivity())
|
||||
.withPermissions(requiredPermission)
|
||||
.andFallback(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
callback.sendError(null);
|
||||
}
|
||||
})
|
||||
.run(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
showFilePickerAsync(title, finalMimeType, new ResultHandler() {
|
||||
@Override
|
||||
public void gotFile(final String filename) {
|
||||
callback.sendSuccess(filename);
|
||||
}
|
||||
}, tabId);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private static String[] getPermissionsForMimeType(final String mimeType) {
|
||||
if (mimeType.startsWith("audio/")) {
|
||||
return new String[] { Manifest.permission.RECORD_AUDIO };
|
||||
} else if (mimeType.startsWith("image/")) {
|
||||
return new String[] { Manifest.permission.CAMERA };
|
||||
} else if (mimeType.startsWith("video/")) {
|
||||
return new String[] { Manifest.permission.CAMERA };
|
||||
}
|
||||
return new String[] { Manifest.permission.CAMERA, Manifest.permission.RECORD_AUDIO };
|
||||
}
|
||||
|
||||
private void addActivities(Intent intent, HashMap<String, Intent> intents, HashMap<String, Intent> filters) {
|
||||
PackageManager pm = context.getPackageManager();
|
||||
List<ResolveInfo> lri = pm.queryIntentActivities(intent, 0);
|
||||
|
|
|
@ -17,11 +17,11 @@ import android.util.DisplayMetrics;
|
|||
|
||||
public class PresentationView extends GeckoView {
|
||||
private static final String LOGTAG = "PresentationView";
|
||||
private static final String presentationViewURI = "chrome://browser/content/PresentationView.xul";
|
||||
private static final String PRESENTATION_VIEW_URI = "chrome://browser/content/PresentationView.xul";
|
||||
|
||||
public PresentationView(Context context, String deviceId, int screenId) {
|
||||
super(context);
|
||||
this.chromeURI = presentationViewURI + "#" + deviceId;
|
||||
this.screenId = screenId;
|
||||
this.mChromeUri = PRESENTATION_VIEW_URI + "#" + deviceId;
|
||||
this.mScreenId = screenId;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,9 @@ var { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
|||
|
||||
var dump = Cu.import("resource://gre/modules/AndroidLog.jsm", {}).AndroidLog.d.bind(null, "ViewContent");
|
||||
|
||||
var DEBUG = false;
|
||||
function debug(aMsg) {
|
||||
// dump(aMsg);
|
||||
}
|
||||
|
||||
// This is copied from desktop's tab-content.js. See bug 1153485 about sharing this code somehow.
|
||||
var DOMTitleChangedListener = {
|
||||
|
@ -15,10 +17,8 @@ var DOMTitleChangedListener = {
|
|||
addEventListener("DOMTitleChanged", this, false);
|
||||
},
|
||||
|
||||
receiveMessage: function(message) {
|
||||
if (DEBUG) {
|
||||
dump("receiveMessage " + message.name);
|
||||
}
|
||||
receiveMessage: function(aMsg) {
|
||||
debug("receiveMessage " + aMsg.name);
|
||||
},
|
||||
|
||||
handleEvent: function(aEvent) {
|
||||
|
@ -26,13 +26,12 @@ var DOMTitleChangedListener = {
|
|||
return;
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
dump("handleEvent " + aEvent.type);
|
||||
}
|
||||
debug("handleEvent " + aEvent.type);
|
||||
|
||||
switch (aEvent.type) {
|
||||
case "DOMTitleChanged":
|
||||
sendAsyncMessage("GeckoView:DOMTitleChanged", { title: content.document.title });
|
||||
sendAsyncMessage("GeckoView:DOMTitleChanged",
|
||||
{ title: content.document.title });
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
|
|
@ -29,19 +29,20 @@ var ModuleManager = {
|
|||
this.modules = {};
|
||||
},
|
||||
|
||||
add: function(resource, type, ...args) {
|
||||
this.remove(type);
|
||||
add: function(aResource, aType, ...aArgs) {
|
||||
this.remove(aType);
|
||||
let scope = {};
|
||||
Cu.import(resource, scope);
|
||||
this.modules[type] = new scope[type](
|
||||
window, this.browser, WindowEventDispatcher, ...args);
|
||||
Cu.import(aResource, scope);
|
||||
this.modules[aType] = new scope[aType](
|
||||
window, this.browser, WindowEventDispatcher, ...aArgs
|
||||
);
|
||||
},
|
||||
|
||||
remove: function(type) {
|
||||
if (!(type in this.modules)) {
|
||||
remove: function(aType) {
|
||||
if (!(aType in this.modules)) {
|
||||
return;
|
||||
}
|
||||
delete this.modules[type];
|
||||
delete this.modules[aType];
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ public class GeckoView extends LayerView
|
|||
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
private final EventDispatcher eventDispatcher = new EventDispatcher();
|
||||
private final EventDispatcher mEventDispatcher = new EventDispatcher();
|
||||
|
||||
private ChromeDelegate mChromeDelegate;
|
||||
/* package */ ContentListener mContentListener;
|
||||
|
@ -53,9 +53,9 @@ public class GeckoView extends LayerView
|
|||
|
||||
private GeckoViewSettings mSettings;
|
||||
|
||||
protected boolean onAttachedToWindowCalled;
|
||||
protected String chromeURI;
|
||||
protected int screenId = 0; // default to the primary screen
|
||||
protected boolean mOnAttachedToWindowCalled;
|
||||
protected String mChromeUri;
|
||||
protected int mScreenId = 0; // default to the primary screen
|
||||
|
||||
@WrapForJNI(dispatchTo = "proxy")
|
||||
protected static final class Window extends JNIObject {
|
||||
|
@ -64,7 +64,7 @@ public class GeckoView extends LayerView
|
|||
|
||||
static native void open(Window instance, GeckoView view,
|
||||
Object compositor, EventDispatcher dispatcher,
|
||||
String chromeURI, GeckoBundle settings,
|
||||
String chromeUri, GeckoBundle settings,
|
||||
int screenId);
|
||||
|
||||
@Override protected native void disposeNative();
|
||||
|
@ -142,7 +142,7 @@ public class GeckoView extends LayerView
|
|||
} else if ("GeckoView:LocationChange".equals(event)) {
|
||||
if (mNavigationListener == null) {
|
||||
// We shouldn't be getting this event.
|
||||
eventDispatcher.dispatch("GeckoViewNavigation:Inactive", null);
|
||||
mEventDispatcher.dispatch("GeckoViewNavigation:Inactive", null);
|
||||
} else {
|
||||
mNavigationListener.onLocationChange(GeckoView.this, message.getString("uri"));
|
||||
mNavigationListener.onCanGoBack(GeckoView.this, message.getBoolean("canGoBack"));
|
||||
|
@ -200,16 +200,14 @@ public class GeckoView extends LayerView
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Parcelable onSaveInstanceState()
|
||||
{
|
||||
protected Parcelable onSaveInstanceState() {
|
||||
final Parcelable superState = super.onSaveInstanceState();
|
||||
stateSaved = true;
|
||||
return new StateBinder(superState, this.window);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(final Parcelable state)
|
||||
{
|
||||
protected void onRestoreInstanceState(final Parcelable state) {
|
||||
final StateBinder stateBinder = (StateBinder) state;
|
||||
|
||||
if (stateBinder.window != null) {
|
||||
|
@ -217,7 +215,7 @@ public class GeckoView extends LayerView
|
|||
}
|
||||
stateSaved = false;
|
||||
|
||||
if (onAttachedToWindowCalled) {
|
||||
if (mOnAttachedToWindowCalled) {
|
||||
reattachWindow();
|
||||
}
|
||||
|
||||
|
@ -227,39 +225,38 @@ public class GeckoView extends LayerView
|
|||
}
|
||||
|
||||
protected void openWindow() {
|
||||
if (chromeURI == null) {
|
||||
chromeURI = getGeckoInterface().getDefaultChromeURI();
|
||||
if (mChromeUri == null) {
|
||||
mChromeUri = getGeckoInterface().getDefaultChromeURI();
|
||||
}
|
||||
|
||||
if (GeckoThread.isStateAtLeast(GeckoThread.State.PROFILE_READY)) {
|
||||
Window.open(window, this, getCompositor(), eventDispatcher,
|
||||
chromeURI, mSettings.asBundle(), screenId);
|
||||
Window.open(window, this, getCompositor(), mEventDispatcher,
|
||||
mChromeUri, mSettings.asBundle(), mScreenId);
|
||||
} else {
|
||||
GeckoThread.queueNativeCallUntil(
|
||||
GeckoThread.State.PROFILE_READY,
|
||||
Window.class, "open", window,
|
||||
GeckoView.class, this,
|
||||
Object.class, getCompositor(),
|
||||
EventDispatcher.class, eventDispatcher,
|
||||
String.class, chromeURI,
|
||||
EventDispatcher.class, mEventDispatcher,
|
||||
String.class, mChromeUri,
|
||||
GeckoBundle.class, mSettings.asBundle(),
|
||||
screenId);
|
||||
mScreenId);
|
||||
}
|
||||
}
|
||||
|
||||
protected void reattachWindow() {
|
||||
if (GeckoThread.isStateAtLeast(GeckoThread.State.PROFILE_READY)) {
|
||||
window.reattach(this, getCompositor(), eventDispatcher);
|
||||
window.reattach(this, getCompositor(), mEventDispatcher);
|
||||
} else {
|
||||
GeckoThread.queueNativeCallUntil(GeckoThread.State.PROFILE_READY,
|
||||
window, "reattach", GeckoView.class, this,
|
||||
Object.class, getCompositor(), EventDispatcher.class, eventDispatcher);
|
||||
Object.class, getCompositor(), EventDispatcher.class, mEventDispatcher);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachedToWindow()
|
||||
{
|
||||
public void onAttachedToWindow() {
|
||||
final DisplayMetrics metrics = getContext().getResources().getDisplayMetrics();
|
||||
|
||||
if (window == null) {
|
||||
|
@ -272,12 +269,11 @@ public class GeckoView extends LayerView
|
|||
|
||||
super.onAttachedToWindow();
|
||||
|
||||
onAttachedToWindowCalled = true;
|
||||
mOnAttachedToWindowCalled = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachedFromWindow()
|
||||
{
|
||||
public void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
super.destroy();
|
||||
|
||||
|
@ -296,7 +292,7 @@ public class GeckoView extends LayerView
|
|||
window, "disposeNative");
|
||||
}
|
||||
|
||||
onAttachedToWindowCalled = false;
|
||||
mOnAttachedToWindowCalled = false;
|
||||
}
|
||||
|
||||
@WrapForJNI public static final int LOAD_DEFAULT = 0;
|
||||
|
@ -320,6 +316,13 @@ public class GeckoView extends LayerView
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reload the current URI.
|
||||
*/
|
||||
public void reload() {
|
||||
mEventDispatcher.dispatch("GeckoView:Reload", null);
|
||||
}
|
||||
|
||||
/* package */ void setInputConnectionListener(final InputConnectionListener icl) {
|
||||
mInputConnectionListener = icl;
|
||||
}
|
||||
|
@ -328,14 +331,14 @@ public class GeckoView extends LayerView
|
|||
* Go back in history.
|
||||
*/
|
||||
public void goBack() {
|
||||
eventDispatcher.dispatch("GeckoView:GoBack", null);
|
||||
mEventDispatcher.dispatch("GeckoView:GoBack", null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Go forward in history.
|
||||
*/
|
||||
public void goForward() {
|
||||
eventDispatcher.dispatch("GeckoView:GoForward", null);
|
||||
mEventDispatcher.dispatch("GeckoView:GoForward", null);
|
||||
}
|
||||
|
||||
public GeckoViewSettings getSettings() {
|
||||
|
@ -470,9 +473,9 @@ public class GeckoView extends LayerView
|
|||
return;
|
||||
}
|
||||
if (listener == null) {
|
||||
eventDispatcher.dispatch("GeckoViewNavigation:Inactive", null);
|
||||
mEventDispatcher.dispatch("GeckoViewNavigation:Inactive", null);
|
||||
} else if (mNavigationListener == null) {
|
||||
eventDispatcher.dispatch("GeckoViewNavigation:Active", null);
|
||||
mEventDispatcher.dispatch("GeckoViewNavigation:Active", null);
|
||||
}
|
||||
|
||||
mNavigationListener = listener;
|
||||
|
@ -504,7 +507,7 @@ public class GeckoView extends LayerView
|
|||
}
|
||||
|
||||
public EventDispatcher getEventDispatcher() {
|
||||
return eventDispatcher;
|
||||
return mEventDispatcher;
|
||||
}
|
||||
|
||||
/* Provides a means for the client to indicate whether a JavaScript
|
||||
|
|
|
@ -17,9 +17,9 @@ import android.view.ViewGroup;
|
|||
public class GeckoViewFragment extends android.support.v4.app.Fragment {
|
||||
private static final String LOGTAG = "GeckoViewFragment";
|
||||
|
||||
private static Parcelable state = null;
|
||||
private static GeckoViewFragment lastUsed = null;
|
||||
private GeckoView geckoView = null;
|
||||
private static Parcelable mSavedState = null;
|
||||
private static GeckoViewFragment mLastUsed = null;
|
||||
private GeckoView mGeckoView = null;
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
|
@ -29,24 +29,24 @@ public class GeckoViewFragment extends android.support.v4.app.Fragment {
|
|||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
geckoView = new GeckoView(getContext());
|
||||
return geckoView;
|
||||
mGeckoView = new GeckoView(getContext());
|
||||
return mGeckoView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
if (state != null && lastUsed != this) {
|
||||
if (mSavedState != null && mLastUsed != this) {
|
||||
// "Restore" the window from the previously used GeckoView to this GeckoView and attach it
|
||||
geckoView.onRestoreInstanceState(state);
|
||||
state = null;
|
||||
mGeckoView.onRestoreInstanceState(mSavedState);
|
||||
mSavedState = null;
|
||||
}
|
||||
super.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
state = geckoView.onSaveInstanceState();
|
||||
lastUsed = this;
|
||||
mSavedState = mGeckoView.onSaveInstanceState();
|
||||
mLastUsed = this;
|
||||
super.onPause();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,9 @@ Cu.import("resource://gre/modules/GeckoViewModule.jsm");
|
|||
var dump = Cu.import("resource://gre/modules/AndroidLog.jsm", {})
|
||||
.AndroidLog.d.bind(null, "ViewContent");
|
||||
|
||||
var DEBUG = false;
|
||||
function debug(aMsg) {
|
||||
// dump(aMsg);
|
||||
}
|
||||
|
||||
class GeckoViewContent extends GeckoViewModule {
|
||||
init() {
|
||||
|
@ -23,21 +25,20 @@ class GeckoViewContent extends GeckoViewModule {
|
|||
this.messageManager.addMessageListener("GeckoView:DOMTitleChanged", this);
|
||||
}
|
||||
|
||||
handleEvent(event) {
|
||||
if (DEBUG) {
|
||||
dump("handleEvent: event.type=" + event.type);
|
||||
}
|
||||
handleEvent(aEvent) {
|
||||
debug("handleEvent: aEvent.type=" + aEvent.type);
|
||||
}
|
||||
|
||||
// Message manager event handler.
|
||||
receiveMessage(msg) {
|
||||
if (DEBUG) {
|
||||
dump("receiveMessage " + msg.name);
|
||||
}
|
||||
receiveMessage(aMsg) {
|
||||
debug("receiveMessage " + aMsg.name);
|
||||
|
||||
switch (msg.name) {
|
||||
switch (aMsg.name) {
|
||||
case "GeckoView:DOMTitleChanged":
|
||||
this.eventDispatcher.sendRequest({ type: "GeckoView:DOMTitleChanged", title: msg.data.title });
|
||||
this.eventDispatcher.sendRequest({
|
||||
type: "GeckoView:DOMTitleChanged",
|
||||
title: aMsg.data.title
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,15 +11,15 @@ const { classes: Cc, interfaces: Ci, utils: Cu, results: Cr } = Components;
|
|||
var dump = Cu.import("resource://gre/modules/AndroidLog.jsm", {})
|
||||
.AndroidLog.d.bind(null, "ViewModule");
|
||||
|
||||
function debug(msg) {
|
||||
// dump(msg);
|
||||
function debug(aMsg) {
|
||||
// dump(aMsg);
|
||||
}
|
||||
|
||||
class GeckoViewModule {
|
||||
constructor(window, browser, eventDispatcher) {
|
||||
this.window = window;
|
||||
this.browser = browser;
|
||||
this.eventDispatcher = eventDispatcher;
|
||||
constructor(aWindow, aBrowser, aEventDispatcher) {
|
||||
this.window = aWindow;
|
||||
this.browser = aBrowser;
|
||||
this.eventDispatcher = aEventDispatcher;
|
||||
|
||||
this.eventDispatcher.registerListener(
|
||||
() => this.onSettingsUpdate(),
|
||||
|
|
|
@ -17,8 +17,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "EventDispatcher",
|
|||
var dump = Cu.import("resource://gre/modules/AndroidLog.jsm", {})
|
||||
.AndroidLog.d.bind(null, "ViewNavigation");
|
||||
|
||||
function debug(msg) {
|
||||
// dump(msg);
|
||||
function debug(aMsg) {
|
||||
// dump(aMsg);
|
||||
}
|
||||
|
||||
// Handles navigation requests between Gecko and a GeckoView.
|
||||
|
@ -42,14 +42,15 @@ class GeckoViewNavigation extends GeckoViewModule {
|
|||
"GeckoViewNavigation:Inactive",
|
||||
"GeckoView:GoBack",
|
||||
"GeckoView:GoForward",
|
||||
"GeckoView:Reload",
|
||||
]);
|
||||
}
|
||||
|
||||
// Bundle event handler.
|
||||
onEvent(event, data, callback) {
|
||||
debug("onEvent: event=" + event + ", data=" + JSON.stringify(data));
|
||||
onEvent(aEvent, aData, aCallback) {
|
||||
debug("onEvent: aEvent=" + aEvent + ", aData=" + JSON.stringify(aData));
|
||||
|
||||
switch (event) {
|
||||
switch (aEvent) {
|
||||
case "GeckoViewNavigation:Active":
|
||||
this.registerProgressListener();
|
||||
break;
|
||||
|
@ -62,19 +63,22 @@ class GeckoViewNavigation extends GeckoViewModule {
|
|||
case "GeckoView:GoForward":
|
||||
this.browser.goForward();
|
||||
break;
|
||||
case "GeckoView:Reload":
|
||||
this.browser.reload();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Message manager event handler.
|
||||
receiveMessage(msg) {
|
||||
debug("receiveMessage " + msg.name);
|
||||
receiveMessage(aMsg) {
|
||||
debug("receiveMessage " + aMsg.name);
|
||||
}
|
||||
|
||||
// nsIBrowserDOMWindow::openURI implementation.
|
||||
openURI(uri, opener, where, flags) {
|
||||
debug("openURI: uri.spec=" + uri.spec);
|
||||
openURI(aUri, aOpener, aWhere, aFlags) {
|
||||
debug("openURI: aUri.spec=" + aUri.spec);
|
||||
// nsIWebNavigation::loadURI(URI, loadFlags, referrer, postData, headers).
|
||||
this.browser.loadURI(uri.spec, null, null, null);
|
||||
this.browser.loadURI(aUri.spec, null, null, null);
|
||||
}
|
||||
|
||||
// nsIBrowserDOMWindow::canClose implementation.
|
||||
|
@ -103,13 +107,13 @@ class GeckoViewNavigation extends GeckoViewModule {
|
|||
}
|
||||
|
||||
// WebProgress event handler.
|
||||
onLocationChange(webProgress, request, locationURI, flags) {
|
||||
onLocationChange(aWebProgress, aRequest, aLocationURI, aFlags) {
|
||||
debug("onLocationChange");
|
||||
|
||||
let fixedURI = locationURI;
|
||||
let fixedURI = aLocationURI;
|
||||
|
||||
try {
|
||||
fixedURI = URIFixup.createExposableURI(locationURI);
|
||||
fixedURI = URIFixup.createExposableURI(aLocationURI);
|
||||
} catch (ex) { }
|
||||
|
||||
let message = {
|
||||
|
|
|
@ -17,7 +17,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "EventDispatcher",
|
|||
var dump = Cu.import("resource://gre/modules/AndroidLog.jsm", {})
|
||||
.AndroidLog.d.bind(null, "ViewNavigation");
|
||||
|
||||
var DEBUG = false;
|
||||
function debug(aMsg) {
|
||||
// dump(aMsg);
|
||||
}
|
||||
|
||||
class GeckoViewProgress extends GeckoViewModule {
|
||||
init() {
|
||||
|
@ -27,9 +29,7 @@ class GeckoViewProgress extends GeckoViewModule {
|
|||
}
|
||||
|
||||
registerProgressListener() {
|
||||
if (DEBUG) {
|
||||
dump("registerProgressListeners()");
|
||||
}
|
||||
debug("registerProgressListeners()");
|
||||
|
||||
let flags = Ci.nsIWebProgress.NOTIFY_STATE_NETWORK | Ci.nsIWebProgress.NOTIFY_SECURITY;
|
||||
this.progressFilter =
|
||||
|
@ -40,9 +40,7 @@ class GeckoViewProgress extends GeckoViewModule {
|
|||
}
|
||||
|
||||
onStateChange(aWebProgress, aRequest, aStateFlags, aStatus) {
|
||||
if (DEBUG) {
|
||||
dump("onStateChange()");
|
||||
}
|
||||
debug("onStateChange()");
|
||||
|
||||
if (!aWebProgress.isTopLevel) {
|
||||
return;
|
||||
|
@ -56,7 +54,8 @@ class GeckoViewProgress extends GeckoViewModule {
|
|||
};
|
||||
|
||||
this.eventDispatcher.sendRequest(message);
|
||||
} else if ((aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) && !aWebProgress.isLoadingDocument) {
|
||||
} else if ((aStateFlags & Ci.nsIWebProgressListener.STATE_STOP) &&
|
||||
!aWebProgress.isLoadingDocument) {
|
||||
let message = {
|
||||
type: "GeckoView:PageStop",
|
||||
success: aStatus ? false : true
|
||||
|
@ -67,9 +66,7 @@ class GeckoViewProgress extends GeckoViewModule {
|
|||
}
|
||||
|
||||
onSecurityChange(aWebProgress, aRequest, aState) {
|
||||
if (DEBUG) {
|
||||
dump("onSecurityChange()");
|
||||
}
|
||||
debug("onSecurityChange()");
|
||||
|
||||
let message = {
|
||||
type: "GeckoView:SecurityChanged",
|
||||
|
|
|
@ -17,8 +17,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "SafeBrowsing",
|
|||
var dump = Cu.import("resource://gre/modules/AndroidLog.jsm", {})
|
||||
.AndroidLog.d.bind(null, "ViewSettings");
|
||||
|
||||
function debug(msg) {
|
||||
// dump(msg);
|
||||
function debug(aMsg) {
|
||||
// dump(aMsg);
|
||||
}
|
||||
|
||||
// Handles GeckoView settings including:
|
||||
|
@ -39,17 +39,17 @@ class GeckoViewSettings extends GeckoViewModule {
|
|||
return this._useTrackingProtection;
|
||||
}
|
||||
|
||||
set useTrackingProtection(use) {
|
||||
if (use && !this._isSafeBrowsingInit) {
|
||||
set useTrackingProtection(aUse) {
|
||||
if (aUse && !this._isSafeBrowsingInit) {
|
||||
SafeBrowsing.init();
|
||||
this._isSafeBrowsingInit = true;
|
||||
}
|
||||
if (use != this._useTrackingProtection) {
|
||||
if (aUse != this._useTrackingProtection) {
|
||||
this.messageManager.loadFrameScript('data:,' +
|
||||
'docShell.useTrackingProtection = ' + use,
|
||||
'docShell.useTrackingProtection = ' + aUse,
|
||||
true
|
||||
);
|
||||
this._useTrackingProtection = use;
|
||||
this._useTrackingProtection = aUse;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,6 +57,21 @@ public class TestStringUtils {
|
|||
assertEquals(StringUtils.stripRef("https://mozilla.org/#BBBB"), "https://mozilla.org/");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStripScheme() {
|
||||
assertEquals("mozilla.org", StringUtils.stripScheme("http://mozilla.org"));
|
||||
assertEquals("mozilla.org", StringUtils.stripScheme("http://mozilla.org/"));
|
||||
assertEquals("https://mozilla.org", StringUtils.stripScheme("https://mozilla.org"));
|
||||
assertEquals("https://mozilla.org", StringUtils.stripScheme("https://mozilla.org/"));
|
||||
assertEquals("mozilla.org", StringUtils.stripScheme("https://mozilla.org/", StringUtils.UrlFlags.STRIP_HTTPS));
|
||||
assertEquals("mozilla.org", StringUtils.stripScheme("https://mozilla.org", StringUtils.UrlFlags.STRIP_HTTPS));
|
||||
assertEquals("", StringUtils.stripScheme("http://"));
|
||||
assertEquals("", StringUtils.stripScheme("https://", StringUtils.UrlFlags.STRIP_HTTPS));
|
||||
// This edge case is not handled properly yet
|
||||
// assertEquals(StringUtils.stripScheme("https://"), "");
|
||||
assertEquals(null, StringUtils.stripScheme(null));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsRTL() {
|
||||
assertFalse(StringUtils.isRTL("mozilla.org"));
|
||||
|
|
|
@ -1480,8 +1480,8 @@ bool
|
|||
Http2Stream::Do0RTT()
|
||||
{
|
||||
MOZ_ASSERT(mTransaction);
|
||||
mAttempting0RTT = true;
|
||||
return mTransaction->Do0RTT();
|
||||
mAttempting0RTT = mTransaction->Do0RTT();
|
||||
return mAttempting0RTT;
|
||||
}
|
||||
|
||||
nsresult
|
||||
|
|
|
@ -19,9 +19,7 @@ ProfilerBacktrace::ProfilerBacktrace(SyncProfile* aProfile)
|
|||
ProfilerBacktrace::~ProfilerBacktrace()
|
||||
{
|
||||
MOZ_COUNT_DTOR(ProfilerBacktrace);
|
||||
if (mProfile->ShouldDestroy()) {
|
||||
delete mProfile;
|
||||
}
|
||||
delete mProfile;
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -9,7 +9,6 @@
|
|||
SyncProfile::SyncProfile(int aThreadId, PseudoStack* aStack)
|
||||
: ThreadInfo("SyncProfile", aThreadId, /* isMainThread = */ false, aStack,
|
||||
/* stackTop = */ nullptr)
|
||||
, mOwnerState(REFERENCED)
|
||||
{
|
||||
MOZ_COUNT_CTOR(SyncProfile);
|
||||
SetProfile(new ProfileBuffer(GET_BACKTRACE_DEFAULT_ENTRIES));
|
||||
|
@ -20,32 +19,6 @@ SyncProfile::~SyncProfile()
|
|||
MOZ_COUNT_DTOR(SyncProfile);
|
||||
}
|
||||
|
||||
bool
|
||||
SyncProfile::ShouldDestroy()
|
||||
{
|
||||
mozilla::MutexAutoLock lock(GetMutex());
|
||||
if (mOwnerState == OWNED) {
|
||||
mOwnerState = OWNER_DESTROYING;
|
||||
return true;
|
||||
}
|
||||
mOwnerState = ORPHANED;
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
SyncProfile::EndUnwind()
|
||||
{
|
||||
if (mOwnerState != ORPHANED) {
|
||||
mOwnerState = OWNED;
|
||||
}
|
||||
// Save mOwnerState before we release the mutex
|
||||
OwnerState ownerState = mOwnerState;
|
||||
ThreadInfo::EndUnwind();
|
||||
if (ownerState == ORPHANED) {
|
||||
delete this;
|
||||
}
|
||||
}
|
||||
|
||||
// SyncProfiles' stacks are deduplicated in the context of the containing
|
||||
// profile in which the backtrace is as a marker payload.
|
||||
void
|
||||
|
|
|
@ -19,22 +19,8 @@ public:
|
|||
// profile in which the backtrace is as a marker payload.
|
||||
void StreamJSON(SpliceableJSONWriter& aWriter, UniqueStacks& aUniqueStacks);
|
||||
|
||||
virtual void EndUnwind();
|
||||
|
||||
private:
|
||||
friend class ProfilerBacktrace;
|
||||
|
||||
enum OwnerState
|
||||
{
|
||||
REFERENCED, // ProfilerBacktrace has a pointer to this but doesn't own
|
||||
OWNED, // ProfilerBacktrace is responsible for destroying this
|
||||
OWNER_DESTROYING, // ProfilerBacktrace owns this and is destroying
|
||||
ORPHANED // No owner, we must destroy ourselves
|
||||
};
|
||||
|
||||
bool ShouldDestroy();
|
||||
|
||||
OwnerState mOwnerState;
|
||||
};
|
||||
|
||||
#endif // __SYNCPROFILE_H
|
||||
|
|
|
@ -237,18 +237,6 @@ ThreadInfo::FlushSamplesAndMarkers()
|
|||
mBuffer->reset();
|
||||
}
|
||||
|
||||
void
|
||||
ThreadInfo::BeginUnwind()
|
||||
{
|
||||
mMutex->Lock();
|
||||
}
|
||||
|
||||
void
|
||||
ThreadInfo::EndUnwind()
|
||||
{
|
||||
mMutex->Unlock();
|
||||
}
|
||||
|
||||
mozilla::Mutex&
|
||||
ThreadInfo::GetMutex()
|
||||
{
|
||||
|
|
|
@ -70,9 +70,6 @@ public:
|
|||
// become invalid, i.e., just before JS shutdown.
|
||||
void FlushSamplesAndMarkers();
|
||||
|
||||
void BeginUnwind();
|
||||
virtual void EndUnwind();
|
||||
|
||||
void DuplicateLastSample(const mozilla::TimeStamp& aStartTime);
|
||||
|
||||
ThreadResponsiveness* GetThreadResponsiveness() { return &mRespInfo; }
|
||||
|
|
|
@ -181,18 +181,17 @@ SigprofHandler(int signal, siginfo_t* info, void* context)
|
|||
// Avoid TSan warning about clobbering errno.
|
||||
int savedErrno = errno;
|
||||
|
||||
TickSample sample_obj;
|
||||
TickSample* sample = &sample_obj;
|
||||
sample->context = context;
|
||||
TickSample sample;
|
||||
sample.context = context;
|
||||
|
||||
// Extract the current pc and sp.
|
||||
SetSampleContext(sample, context);
|
||||
sample->threadInfo = gCurrentThreadInfo;
|
||||
sample->timestamp = mozilla::TimeStamp::Now();
|
||||
sample->rssMemory = gRssMemory;
|
||||
sample->ussMemory = gUssMemory;
|
||||
SetSampleContext(&sample, context);
|
||||
sample.threadInfo = gCurrentThreadInfo;
|
||||
sample.timestamp = mozilla::TimeStamp::Now();
|
||||
sample.rssMemory = gRssMemory;
|
||||
sample.ussMemory = gUssMemory;
|
||||
|
||||
Tick(sample);
|
||||
Tick(&sample);
|
||||
|
||||
sem_post(&gSignalHandlingDone);
|
||||
errno = savedErrno;
|
||||
|
|
|
@ -190,15 +190,14 @@ public:
|
|||
thread_act_t profiled_thread =
|
||||
aThreadInfo->GetPlatformData()->profiled_thread();
|
||||
|
||||
TickSample sample_obj;
|
||||
TickSample* sample = &sample_obj;
|
||||
TickSample sample;
|
||||
|
||||
// Unique Set Size is not supported on Mac.
|
||||
sample->ussMemory = 0;
|
||||
sample->rssMemory = 0;
|
||||
sample.ussMemory = 0;
|
||||
sample.rssMemory = 0;
|
||||
|
||||
if (isFirstProfiledThread && gProfileMemory) {
|
||||
sample->rssMemory = nsMemoryReporterManager::ResidentFast();
|
||||
sample.rssMemory = nsMemoryReporterManager::ResidentFast();
|
||||
}
|
||||
|
||||
// We're using thread_suspend on OS X because pthread_kill (which is what
|
||||
|
@ -233,15 +232,15 @@ public:
|
|||
flavor,
|
||||
reinterpret_cast<natural_t*>(&state),
|
||||
&count) == KERN_SUCCESS) {
|
||||
sample->pc = reinterpret_cast<Address>(state.REGISTER_FIELD(ip));
|
||||
sample->sp = reinterpret_cast<Address>(state.REGISTER_FIELD(sp));
|
||||
sample->fp = reinterpret_cast<Address>(state.REGISTER_FIELD(bp));
|
||||
sample->timestamp = mozilla::TimeStamp::Now();
|
||||
sample->threadInfo = aThreadInfo;
|
||||
sample.pc = reinterpret_cast<Address>(state.REGISTER_FIELD(ip));
|
||||
sample.sp = reinterpret_cast<Address>(state.REGISTER_FIELD(sp));
|
||||
sample.fp = reinterpret_cast<Address>(state.REGISTER_FIELD(bp));
|
||||
sample.timestamp = mozilla::TimeStamp::Now();
|
||||
sample.threadInfo = aThreadInfo;
|
||||
|
||||
#undef REGISTER_FIELD
|
||||
|
||||
Tick(sample);
|
||||
Tick(&sample);
|
||||
}
|
||||
thread_resume(profiled_thread);
|
||||
}
|
||||
|
|
|
@ -202,21 +202,20 @@ class SamplerThread
|
|||
CONTEXT context;
|
||||
memset(&context, 0, sizeof(context));
|
||||
|
||||
TickSample sample_obj;
|
||||
TickSample* sample = &sample_obj;
|
||||
TickSample sample;
|
||||
|
||||
// Grab the timestamp before pausing the thread, to avoid deadlocks.
|
||||
sample->timestamp = mozilla::TimeStamp::Now();
|
||||
sample->threadInfo = aThreadInfo;
|
||||
sample.timestamp = mozilla::TimeStamp::Now();
|
||||
sample.threadInfo = aThreadInfo;
|
||||
|
||||
if (isFirstProfiledThread && gProfileMemory) {
|
||||
sample->rssMemory = nsMemoryReporterManager::ResidentFast();
|
||||
sample.rssMemory = nsMemoryReporterManager::ResidentFast();
|
||||
} else {
|
||||
sample->rssMemory = 0;
|
||||
sample.rssMemory = 0;
|
||||
}
|
||||
|
||||
// Unique Set Size is not supported on Windows.
|
||||
sample->ussMemory = 0;
|
||||
sample.ussMemory = 0;
|
||||
|
||||
static const DWORD kSuspendFailed = static_cast<DWORD>(-1);
|
||||
if (SuspendThread(profiled_thread) == kSuspendFailed)
|
||||
|
@ -239,18 +238,18 @@ class SamplerThread
|
|||
}
|
||||
|
||||
#if defined(GP_ARCH_amd64)
|
||||
sample->pc = reinterpret_cast<Address>(context.Rip);
|
||||
sample->sp = reinterpret_cast<Address>(context.Rsp);
|
||||
sample->fp = reinterpret_cast<Address>(context.Rbp);
|
||||
sample.pc = reinterpret_cast<Address>(context.Rip);
|
||||
sample.sp = reinterpret_cast<Address>(context.Rsp);
|
||||
sample.fp = reinterpret_cast<Address>(context.Rbp);
|
||||
#else
|
||||
sample->pc = reinterpret_cast<Address>(context.Eip);
|
||||
sample->sp = reinterpret_cast<Address>(context.Esp);
|
||||
sample->fp = reinterpret_cast<Address>(context.Ebp);
|
||||
sample.pc = reinterpret_cast<Address>(context.Eip);
|
||||
sample.sp = reinterpret_cast<Address>(context.Esp);
|
||||
sample.fp = reinterpret_cast<Address>(context.Ebp);
|
||||
#endif
|
||||
|
||||
sample->context = &context;
|
||||
sample.context = &context;
|
||||
|
||||
Tick(sample);
|
||||
Tick(&sample);
|
||||
|
||||
ResumeThread(profiled_thread);
|
||||
}
|
||||
|
|
|
@ -2459,9 +2459,7 @@ profiler_get_backtrace()
|
|||
sample.isSamplingCurrentThread = true;
|
||||
sample.timestamp = mozilla::TimeStamp::Now();
|
||||
|
||||
profile->BeginUnwind();
|
||||
Tick(&sample);
|
||||
profile->EndUnwind();
|
||||
|
||||
return UniqueProfilerBacktrace(new ProfilerBacktrace(profile));
|
||||
}
|
||||
|
|
Загрузка…
Ссылка в новой задаче