mirror of
https://github.com/roytam1/basilisk55.git
synced 2026-05-26 15:02:46 +00:00
cherry-picked mozilla upstream changes:
bug1359051, bug1343256, bug1356179, bug1334097, bug1355520, bug1359142, bug1358469, bug1345910, bug1331335, bug1367267, bug1366140, bug1359837, bug1348791, bug1339826
This commit is contained in:
@@ -136,6 +136,12 @@ var gEditItemOverlay = {
|
||||
throw new Error("_initKeywordField called unexpectedly");
|
||||
}
|
||||
|
||||
// Reset the field status synchronously now, eventually we'll reinit it
|
||||
// later if we find an existing keyword. This way we can ensure to be in a
|
||||
// consistent status when reusing the panel across different bookmarks.
|
||||
this._keyword = newKeyword;
|
||||
this._initTextField(this._keywordField, newKeyword);
|
||||
|
||||
if (!newKeyword) {
|
||||
let entries = [];
|
||||
yield PlacesUtils.keywords.fetch({ url: this._paneInfo.uri.spec },
|
||||
@@ -150,11 +156,12 @@ var gEditItemOverlay = {
|
||||
existingKeyword = sameEntry ? sameEntry.keyword : "";
|
||||
}
|
||||
if (existingKeyword) {
|
||||
this._keyword = newKeyword = existingKeyword;
|
||||
this._keyword = existingKeyword;
|
||||
// Update the text field to the existing keyword.
|
||||
this._initTextField(this._keywordField, this._keyword);
|
||||
}
|
||||
}
|
||||
}
|
||||
this._initTextField(this._keywordField, newKeyword);
|
||||
}),
|
||||
|
||||
_initLoadInSidebar: Task.async(function* () {
|
||||
|
||||
+99
@@ -0,0 +1,99 @@
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<!-- Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ -->
|
||||
|
||||
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
|
||||
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
|
||||
type="text/css"?>
|
||||
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/editBookmarkOverlay.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/content/places/places.css"?>
|
||||
<?xml-stylesheet href="chrome://browser/skin/places/places.css"?>
|
||||
|
||||
<?xul-overlay href="chrome://browser/content/places/placesOverlay.xul"?>
|
||||
<?xul-overlay href="chrome://browser/content/places/editBookmarkOverlay.xul"?>
|
||||
|
||||
<!DOCTYPE window [
|
||||
<!ENTITY % editBookmarkOverlayDTD SYSTEM "chrome://browser/locale/places/editBookmarkOverlay.dtd">
|
||||
%editBookmarkOverlayDTD;
|
||||
]>
|
||||
|
||||
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
|
||||
title="Bug 1343256 - Bookmark keywords disappear from one bookmark when adding a keyword to another bookmark"
|
||||
onload="runTest();">
|
||||
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js" />
|
||||
<script type="application/javascript"
|
||||
src="chrome://mochikit/content/tests/SimpleTest/EventUtils.js"/>
|
||||
<script type="application/javascript"
|
||||
src="chrome://browser/content/places/editBookmarkOverlay.js"/>
|
||||
|
||||
<body xmlns="http://www.w3.org/1999/xhtml" />
|
||||
|
||||
<vbox id="editBookmarkPanelContent"/>
|
||||
|
||||
<script type="application/javascript">
|
||||
<![CDATA[
|
||||
function runTest() {
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
Task.spawn(test.bind(this))
|
||||
.catch(ex => ok(false, ex))
|
||||
.then(() => PlacesUtils.bookmarks.eraseEverything())
|
||||
.then(SimpleTest.finish);
|
||||
}
|
||||
|
||||
function promiseOnItemChanged() {
|
||||
return new Promise(resolve => {
|
||||
PlacesUtils.bookmarks.addObserver({
|
||||
onBeginUpdateBatch() {},
|
||||
onEndUpdateBatch() {},
|
||||
onItemAdded() {},
|
||||
onItemRemoved() {},
|
||||
onItemVisited() {},
|
||||
onItemMoved() {},
|
||||
onItemChanged(id, property, isAnno, value) {
|
||||
PlacesUtils.bookmarks.removeObserver(this);
|
||||
resolve({ property, value });
|
||||
},
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsINavBookmarkObserver])
|
||||
}, false);
|
||||
});
|
||||
}
|
||||
|
||||
function* test() {
|
||||
ok(gEditItemOverlay, "Sanity check: gEditItemOverlay is in context");
|
||||
let keywordField = document.getElementById("editBMPanel_keywordField");
|
||||
|
||||
for (let i = 0; i < 2; ++i) {
|
||||
let bm = yield PlacesUtils.bookmarks.insert({
|
||||
url: `http://www.test${i}.me/`,
|
||||
parentGuid: PlacesUtils.bookmarks.unfiledGuid,
|
||||
});
|
||||
info(`Init panel on bookmark #${i+1}`);
|
||||
let node = yield PlacesUIUtils.promiseNodeLikeFromFetchInfo(bm);
|
||||
gEditItemOverlay.initPanel({ node });
|
||||
is(document.getElementById("editBMPanel_keywordField").value, "",
|
||||
"The keyword field should be empty");
|
||||
info("Add a keyword to the bookmark");
|
||||
let promise = promiseOnItemChanged();
|
||||
keywordField.focus();
|
||||
keywordField.value = "kw";
|
||||
synthesizeKey(i.toString(), {});
|
||||
synthesizeKey("VK_RETURN", {});
|
||||
keywordField.blur();
|
||||
let {property, value} = yield promise;
|
||||
is(property, "keyword", "The keyword should have been changed");
|
||||
is(value, `kw${i}`, "The new keyword value is correct");
|
||||
}
|
||||
|
||||
for (let i = 0; i < 2; ++i) {
|
||||
let entry = yield PlacesUtils.keywords.fetch({ url: `http://www.test${i}.me/` });
|
||||
is(entry.keyword, `kw${i}`, `The keyword for http://www.test${i}.me/ is correct`);
|
||||
}
|
||||
};
|
||||
]]>
|
||||
</script>
|
||||
|
||||
</window>
|
||||
@@ -289,7 +289,7 @@ MOZ_ARG_ENABLE_BOOL(pie,
|
||||
if test "$GNU_CC" -a -n "$MOZ_PIE"; then
|
||||
AC_MSG_CHECKING([for PIE support])
|
||||
_SAVE_LDFLAGS=$LDFLAGS
|
||||
LDFLAGS="$LDFLAGS -pie"
|
||||
LDFLAGS="$LDFLAGS $DSO_PIC_CFLAGS -pie"
|
||||
AC_TRY_LINK(,,AC_MSG_RESULT([yes])
|
||||
[MOZ_PROGRAM_LDFLAGS="$MOZ_PROGRAM_LDFLAGS -pie"],
|
||||
AC_MSG_RESULT([no])
|
||||
|
||||
@@ -9812,8 +9812,12 @@ nsDocShell::InternalLoad(nsIURI* aURI,
|
||||
if (!aWindowTarget.IsEmpty()) {
|
||||
// Locate the target DocShell.
|
||||
nsCOMPtr<nsIDocShellTreeItem> targetItem;
|
||||
// Only _self, _parent, and _top are supported in noopener case.
|
||||
if (!(aFlags & INTERNAL_LOAD_FLAGS_NO_OPENER) ||
|
||||
// Only _self, _parent, and _top are supported in noopener case. But we
|
||||
// have to be careful to not apply that to the noreferrer case. See bug
|
||||
// 1358469.
|
||||
bool allowNamedTarget = !(aFlags & INTERNAL_LOAD_FLAGS_NO_OPENER) ||
|
||||
(aFlags & INTERNAL_LOAD_FLAGS_DONT_SEND_REFERRER);
|
||||
if (allowNamedTarget ||
|
||||
aWindowTarget.LowerCaseEqualsLiteral("_self") ||
|
||||
aWindowTarget.LowerCaseEqualsLiteral("_parent") ||
|
||||
aWindowTarget.LowerCaseEqualsLiteral("_top")) {
|
||||
|
||||
+131
-33
@@ -23,6 +23,7 @@
|
||||
#include "mozilla/AutoRestore.h"
|
||||
#include "mozilla/Casting.h"
|
||||
#include "mozilla/EndianUtils.h"
|
||||
#include "mozilla/ErrorNames.h"
|
||||
#include "mozilla/LazyIdleThread.h"
|
||||
#include "mozilla/Maybe.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
@@ -9335,6 +9336,7 @@ class Maintenance final
|
||||
RefPtr<DirectoryLock> mDirectoryLock;
|
||||
nsTArray<DirectoryInfo> mDirectoryInfos;
|
||||
nsDataHashtable<nsStringHashKey, DatabaseMaintenance*> mDatabaseMaintenances;
|
||||
nsresult mResultCode;
|
||||
Atomic<bool> mAborted;
|
||||
State mState;
|
||||
|
||||
@@ -9342,6 +9344,7 @@ public:
|
||||
explicit Maintenance(QuotaClient* aQuotaClient)
|
||||
: mQuotaClient(aQuotaClient)
|
||||
, mStartTime(PR_Now())
|
||||
, mResultCode(NS_OK)
|
||||
, mAborted(false)
|
||||
, mState(State::Initial)
|
||||
{
|
||||
@@ -18463,21 +18466,32 @@ Maintenance::DirectoryWork()
|
||||
QuotaManager* quotaManager = QuotaManager::Get();
|
||||
MOZ_ASSERT(quotaManager);
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(quotaManager->EnsureStorageIsInitialized()))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
nsresult rv = quotaManager->EnsureStorageIsInitialized();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> storageDir = GetFileForPath(quotaManager->GetStoragePath());
|
||||
MOZ_ASSERT(storageDir);
|
||||
if (NS_WARN_IF(!storageDir)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
bool exists;
|
||||
MOZ_ALWAYS_SUCCEEDS(storageDir->Exists(&exists));
|
||||
rv = storageDir->Exists(&exists);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!exists) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
bool isDirectory;
|
||||
MOZ_ALWAYS_SUCCEEDS(storageDir->IsDirectory(&isDirectory));
|
||||
rv = storageDir->IsDirectory(&isDirectory);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!isDirectory)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
@@ -18512,25 +18526,41 @@ Maintenance::DirectoryWork()
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> persistenceDir;
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
storageDir->Clone(getter_AddRefs(persistenceDir)));
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
persistenceDir->Append(NS_ConvertASCIItoUTF16(persistenceTypeString)));
|
||||
rv = storageDir->Clone(getter_AddRefs(persistenceDir));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = persistenceDir->Append(NS_ConvertASCIItoUTF16(persistenceTypeString));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = persistenceDir->Exists(&exists);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(persistenceDir->Exists(&exists));
|
||||
if (!exists) {
|
||||
continue;
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(persistenceDir->IsDirectory(&isDirectory));
|
||||
rv = persistenceDir->IsDirectory(&isDirectory);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!isDirectory)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISimpleEnumerator> persistenceDirEntries;
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
persistenceDir->GetDirectoryEntries(
|
||||
getter_AddRefs(persistenceDirEntries)));
|
||||
rv = persistenceDir->GetDirectoryEntries(
|
||||
getter_AddRefs(persistenceDirEntries));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!persistenceDirEntries) {
|
||||
continue;
|
||||
}
|
||||
@@ -18542,46 +18572,76 @@ Maintenance::DirectoryWork()
|
||||
}
|
||||
|
||||
bool persistenceDirHasMoreEntries;
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
persistenceDirEntries->HasMoreElements(&persistenceDirHasMoreEntries));
|
||||
rv = persistenceDirEntries->HasMoreElements(
|
||||
&persistenceDirHasMoreEntries);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!persistenceDirHasMoreEntries) {
|
||||
break;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> persistenceDirEntry;
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
persistenceDirEntries->GetNext(getter_AddRefs(persistenceDirEntry)));
|
||||
rv = persistenceDirEntries->GetNext(getter_AddRefs(persistenceDirEntry));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> originDir = do_QueryInterface(persistenceDirEntry);
|
||||
MOZ_ASSERT(originDir);
|
||||
|
||||
MOZ_ASSERT(NS_SUCCEEDED(originDir->Exists(&exists)));
|
||||
rv = originDir->Exists(&exists);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(exists);
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(originDir->IsDirectory(&isDirectory));
|
||||
rv = originDir->IsDirectory(&isDirectory);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!isDirectory) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> idbDir;
|
||||
MOZ_ALWAYS_SUCCEEDS(originDir->Clone(getter_AddRefs(idbDir)));
|
||||
rv = originDir->Clone(getter_AddRefs(idbDir));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(idbDir->Append(idbDirName));
|
||||
rv = idbDir->Append(idbDirName);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = idbDir->Exists(&exists);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(idbDir->Exists(&exists));
|
||||
if (!exists) {
|
||||
continue;
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(idbDir->IsDirectory(&isDirectory));
|
||||
rv = idbDir->IsDirectory(&isDirectory);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!isDirectory)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISimpleEnumerator> idbDirEntries;
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
idbDir->GetDirectoryEntries(getter_AddRefs(idbDirEntries)));
|
||||
rv = idbDir->GetDirectoryEntries(getter_AddRefs(idbDirEntries));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!idbDirEntries) {
|
||||
continue;
|
||||
}
|
||||
@@ -18597,31 +18657,46 @@ Maintenance::DirectoryWork()
|
||||
}
|
||||
|
||||
bool idbDirHasMoreEntries;
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
idbDirEntries->HasMoreElements(&idbDirHasMoreEntries));
|
||||
rv = idbDirEntries->HasMoreElements(&idbDirHasMoreEntries);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!idbDirHasMoreEntries) {
|
||||
break;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsISupports> idbDirEntry;
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
idbDirEntries->GetNext(getter_AddRefs(idbDirEntry)));
|
||||
rv = idbDirEntries->GetNext(getter_AddRefs(idbDirEntry));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> idbDirFile = do_QueryInterface(idbDirEntry);
|
||||
MOZ_ASSERT(idbDirFile);
|
||||
|
||||
nsString idbFilePath;
|
||||
MOZ_ALWAYS_SUCCEEDS(idbDirFile->GetPath(idbFilePath));
|
||||
rv = idbDirFile->GetPath(idbFilePath);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!StringEndsWith(idbFilePath, sqliteExtension)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(NS_SUCCEEDED(idbDirFile->Exists(&exists)));
|
||||
rv = idbDirFile->Exists(&exists);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(exists);
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(idbDirFile->IsDirectory(&isDirectory));
|
||||
rv = idbDirFile->IsDirectory(&isDirectory);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (isDirectory) {
|
||||
continue;
|
||||
}
|
||||
@@ -18750,8 +18825,19 @@ Maintenance::Finish()
|
||||
AssertIsOnBackgroundThread();
|
||||
MOZ_ASSERT(mState == State::Finishing);
|
||||
|
||||
if (NS_FAILED(mResultCode)) {
|
||||
nsCString errorName;
|
||||
GetErrorName(mResultCode, errorName);
|
||||
|
||||
IDB_WARNING("Maintenance finished with error: %s", errorName.get());
|
||||
}
|
||||
|
||||
mDirectoryLock = nullptr;
|
||||
|
||||
// It can happen that we are only referenced by mCurrentMaintenance which is
|
||||
// cleared in NoteFinishedMaintenance()
|
||||
RefPtr<Maintenance> kungFuDeathGrip = this;
|
||||
|
||||
mQuotaClient->NoteFinishedMaintenance(this);
|
||||
|
||||
mState = State::Complete;
|
||||
@@ -18796,6 +18882,10 @@ Maintenance::Run()
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(NS_FAILED(rv)) && mState != State::Finishing) {
|
||||
if (NS_SUCCEEDED(mResultCode)) {
|
||||
mResultCode = rv;
|
||||
}
|
||||
|
||||
// Must set mState before dispatching otherwise we will race with the owning
|
||||
// thread.
|
||||
mState = State::Finishing;
|
||||
@@ -18822,6 +18912,10 @@ Maintenance::DirectoryLockAcquired(DirectoryLock* aLock)
|
||||
|
||||
nsresult rv = DirectoryOpen();
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
if (NS_SUCCEEDED(mResultCode)) {
|
||||
mResultCode = rv;
|
||||
}
|
||||
|
||||
mState = State::Finishing;
|
||||
Finish();
|
||||
|
||||
@@ -18836,6 +18930,10 @@ Maintenance::DirectoryLockFailed()
|
||||
MOZ_ASSERT(mState == State::DirectoryOpenPending);
|
||||
MOZ_ASSERT(!mDirectoryLock);
|
||||
|
||||
if (NS_SUCCEEDED(mResultCode)) {
|
||||
mResultCode = NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mState = State::Finishing;
|
||||
Finish();
|
||||
}
|
||||
|
||||
@@ -11,9 +11,12 @@
|
||||
|
||||
#include "IndexedDatabase.h"
|
||||
|
||||
#define IDB_WARNING(x) \
|
||||
mozilla::dom::indexedDB::ReportInternalError(__FILE__, __LINE__, x); \
|
||||
NS_WARNING(x)
|
||||
#define IDB_WARNING(...) \
|
||||
do { \
|
||||
nsPrintfCString s(__VA_ARGS__); \
|
||||
mozilla::dom::indexedDB::ReportInternalError(__FILE__, __LINE__, s.get()); \
|
||||
NS_WARNING(s.get()); \
|
||||
} while (0)
|
||||
|
||||
#define IDB_REPORT_INTERNAL_ERR() \
|
||||
mozilla::dom::indexedDB::ReportInternalError(__FILE__, __LINE__, \
|
||||
|
||||
@@ -332,6 +332,7 @@ if CONFIG['MOZ_HAS_WINSDK_WITH_D3D']:
|
||||
'renderer/d3d/d3d11/win32/NativeWindow11Win32.cpp',
|
||||
]
|
||||
|
||||
CXXFLAGS += CONFIG['SSE2_FLAGS']
|
||||
|
||||
if CONFIG['GNU_CXX']:
|
||||
CXXFLAGS += [
|
||||
|
||||
@@ -1822,7 +1822,6 @@ MessageChannel::ShouldDeferInterruptMessage(const Message& aMsg, size_t aStackDe
|
||||
// Interrupt in-calls have raced. The winner, if there is one, gets to defer
|
||||
// processing of the other side's in-call.
|
||||
bool defer;
|
||||
const char* winner;
|
||||
const MessageInfo parentMsgInfo =
|
||||
(mSide == ChildSide) ? MessageInfo(aMsg) : mInterruptStack.top();
|
||||
const MessageInfo childMsgInfo =
|
||||
@@ -1830,11 +1829,9 @@ MessageChannel::ShouldDeferInterruptMessage(const Message& aMsg, size_t aStackDe
|
||||
switch (mListener->MediateInterruptRace(parentMsgInfo, childMsgInfo))
|
||||
{
|
||||
case RIPChildWins:
|
||||
winner = "child";
|
||||
defer = (mSide == ChildSide);
|
||||
break;
|
||||
case RIPParentWins:
|
||||
winner = "parent";
|
||||
defer = (mSide != ChildSide);
|
||||
break;
|
||||
case RIPError:
|
||||
|
||||
@@ -259,7 +259,7 @@ class ExecutableAllocator
|
||||
{
|
||||
__clear_cache(code, reinterpret_cast<char*>(code) + size);
|
||||
}
|
||||
#elif defined(JS_CODEGEN_ARM) && defined(XP_IOS)
|
||||
#elif (defined(JS_CODEGEN_ARM) || defined(JS_CODEGEN_ARM64)) && defined(XP_IOS)
|
||||
static void cacheFlush(void* code, size_t size)
|
||||
{
|
||||
sys_icache_invalidate(code, size);
|
||||
|
||||
@@ -117,7 +117,19 @@ class AutoSetHandlingSegFault
|
||||
# define R12_sig(p) ((p)->sc_r12)
|
||||
# define R13_sig(p) ((p)->sc_r13)
|
||||
# define R14_sig(p) ((p)->sc_r14)
|
||||
# define R15_sig(p) ((p)->sc_r15)
|
||||
# if defined(__arm__)
|
||||
# define R15_sig(p) ((p)->sc_pc)
|
||||
# else
|
||||
# define R15_sig(p) ((p)->sc_r15)
|
||||
# endif
|
||||
# if defined(__aarch64__)
|
||||
# define EPC_sig(p) ((p)->sc_elr)
|
||||
# define RFP_sig(p) ((p)->sc_x[29])
|
||||
# endif
|
||||
# if defined(__mips__)
|
||||
# define EPC_sig(p) ((p)->sc_pc)
|
||||
# define RFP_sig(p) ((p)->sc_regs[30])
|
||||
# endif
|
||||
#elif defined(__linux__) || defined(SOLARIS)
|
||||
# if defined(__linux__)
|
||||
# define XMM_sig(p,i) ((p)->uc_mcontext.fpregs->_xmm[i])
|
||||
@@ -175,6 +187,14 @@ class AutoSetHandlingSegFault
|
||||
# define R13_sig(p) ((p)->uc_mcontext.__gregs[_REG_R13])
|
||||
# define R14_sig(p) ((p)->uc_mcontext.__gregs[_REG_R14])
|
||||
# define R15_sig(p) ((p)->uc_mcontext.__gregs[_REG_R15])
|
||||
# if defined(__aarch64__)
|
||||
# define EPC_sig(p) ((p)->uc_mcontext.__gregs[_REG_PC])
|
||||
# define RFP_sig(p) ((p)->uc_mcontext.__gregs[_REG_X29])
|
||||
# endif
|
||||
# if defined(__mips__)
|
||||
# define EPC_sig(p) ((p)->uc_mcontext.__gregs[_REG_EPC])
|
||||
# define RFP_sig(p) ((p)->uc_mcontext.__gregs[_REG_S8])
|
||||
# endif
|
||||
#elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
||||
# if defined(__DragonFly__)
|
||||
# define XMM_sig(p,i) (((union savefpu*)(p)->uc_mcontext.mc_fpregs)->sv_xmm.sv_xmm[i])
|
||||
@@ -203,6 +223,14 @@ class AutoSetHandlingSegFault
|
||||
# else
|
||||
# define R15_sig(p) ((p)->uc_mcontext.mc_r15)
|
||||
# endif
|
||||
# if defined(__FreeBSD__) && defined(__aarch64__)
|
||||
# define EPC_sig(p) ((p)->uc_mcontext.mc_gpregs.gp_elr)
|
||||
# define RFP_sig(p) ((p)->uc_mcontext.mc_gpregs.gp_x[29])
|
||||
# endif
|
||||
# if defined(__FreeBSD__) && defined(__mips__)
|
||||
# define EPC_sig(p) ((p)->uc_mcontext.mc_pc)
|
||||
# define RFP_sig(p) ((p)->uc_mcontext.mc_regs[30])
|
||||
# endif
|
||||
#elif defined(XP_DARWIN)
|
||||
# define EIP_sig(p) ((p)->uc_mcontext->__ss.__eip)
|
||||
# define RIP_sig(p) ((p)->uc_mcontext->__ss.__rip)
|
||||
|
||||
@@ -7430,9 +7430,11 @@ nsDisplayMask::PaintAsLayer(nsDisplayListBuilder* aBuilder,
|
||||
// Clip the drawing target by mVisibleRect, which contains the visible
|
||||
// region of the target frame and its out-of-flow and inflow descendants.
|
||||
gfxContext* context = aCtx->ThebesContext();
|
||||
context->Clip(NSRectToSnappedRect(mVisibleRect,
|
||||
mFrame->PresContext()->AppUnitsPerDevPixel(),
|
||||
*aCtx->GetDrawTarget()));
|
||||
|
||||
Rect bounds =
|
||||
NSRectToRect(mVisibleRect, mFrame->PresContext()->AppUnitsPerDevPixel());
|
||||
bounds.RoundOut();
|
||||
context->Clip(bounds);
|
||||
|
||||
ComputeMaskGeometry(params);
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="500" height="500">
|
||||
<defs>
|
||||
<clipPath clipPathUnits="objectBoundingBox" id="myPath">
|
||||
<rect x="0" y="0" height="1" width="1"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
|
||||
<!-- You should see a thin horizontal light lime line. -->
|
||||
<path d="M0 99.6 L500 99.6 L500 100.3 L0 100.3 Z" fill="lime" clip-path="url(#myPath)"/>
|
||||
<!-- You should see a vertical light lime line. -->
|
||||
<path d="M199.9 0 L199.9 500 L200.4 500 L200.4 0 Z" fill="lime" clip-path="url(#myPath)"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 555 B |
@@ -41,6 +41,7 @@ fuzzy-if(/^Windows\x20NT\x2010\.0/.test(http.oscpu)||/^Windows\x20NT\x206\.[12]/
|
||||
== clipPath-basic-05.svg pass.svg
|
||||
== clipPath-basic-06.svg pass.svg
|
||||
== clipPath-basic-07.svg pass.svg
|
||||
!= clipPath-on-thin-object.svg about:blank
|
||||
== clipPath-winding-01.svg pass.svg
|
||||
== clip-surface-clone-01.svg clip-surface-clone-01-ref.svg
|
||||
== conditions-01.svg pass.svg
|
||||
@@ -411,7 +412,7 @@ fuzzy-if(skiaContent,1,100) == tspan-xy-anchor-end-01.svg tspan-xy-anchor-end-re
|
||||
== svg-effects-area-zoomed-in.xhtml svg-effects-area-zoomed-in-ref.xhtml
|
||||
== svg-effects-area-zoomed-out.xhtml svg-effects-area-zoomed-out-ref.xhtml
|
||||
== href-attr-change-restyles.svg href-attr-change-restyles-ref.svg
|
||||
== mask-img.html mask-img-ref.html
|
||||
fuzzy(128,141) == mask-img.html mask-img-ref.html
|
||||
|
||||
skip-if(Android) pref(layout.css.mix-blend-mode.enabled,true) == blend-color-burn.svg blend-color-burn-ref.svg
|
||||
skip-if(Android) pref(layout.css.mix-blend-mode.enabled,true) == blend-color-dodge.svg blend-color-dodge-ref.svg
|
||||
|
||||
@@ -557,10 +557,10 @@ static int audiounit_stream_get_volume(cubeb_stream * stm, float * volume);
|
||||
static int audiounit_stream_set_volume(cubeb_stream * stm, float volume);
|
||||
|
||||
static int
|
||||
audiounit_reinit_stream(cubeb_stream * stm, bool is_started)
|
||||
audiounit_reinit_stream(cubeb_stream * stm)
|
||||
{
|
||||
auto_lock context_lock(stm->context->mutex);
|
||||
if (is_started) {
|
||||
if (!stm->shutdown) {
|
||||
audiounit_stream_stop_internal(stm);
|
||||
}
|
||||
|
||||
@@ -585,7 +585,7 @@ audiounit_reinit_stream(cubeb_stream * stm, bool is_started)
|
||||
stm->frames_read = 0;
|
||||
|
||||
// If the stream was running, start it again.
|
||||
if (is_started) {
|
||||
if (!stm->shutdown) {
|
||||
audiounit_stream_start_internal(stm);
|
||||
}
|
||||
}
|
||||
@@ -599,8 +599,6 @@ audiounit_property_listener_callback(AudioObjectID /* id */, UInt32 address_coun
|
||||
{
|
||||
cubeb_stream * stm = (cubeb_stream*) user;
|
||||
stm->switching_device = true;
|
||||
// Note if the stream was running or not
|
||||
bool was_running = !stm->shutdown;
|
||||
|
||||
LOG("(%p) Audio device changed, %u events.", stm, (unsigned int) address_count);
|
||||
for (UInt32 i = 0; i < address_count; i++) {
|
||||
@@ -629,9 +627,10 @@ audiounit_property_listener_callback(AudioObjectID /* id */, UInt32 address_coun
|
||||
stm->input_device = 0;
|
||||
}
|
||||
break;
|
||||
case kAudioDevicePropertyDataSource:
|
||||
LOG("Event[%u] - mSelector == kAudioHardwarePropertyDataSource", (unsigned int) i);
|
||||
break;
|
||||
case kAudioDevicePropertyDataSource: {
|
||||
LOG("Event[%d] - mSelector == kAudioHardwarePropertyDataSource", i);
|
||||
return noErr;
|
||||
}
|
||||
default:
|
||||
LOG("Event[%u] - mSelector == Unexpected Event id %d, return", (unsigned int) i, addresses[i].mSelector);
|
||||
return noErr;
|
||||
@@ -657,7 +656,7 @@ audiounit_property_listener_callback(AudioObjectID /* id */, UInt32 address_coun
|
||||
// Use a new thread, through the queue, to avoid deadlock when calling
|
||||
// Get/SetProperties method from inside notify callback
|
||||
dispatch_async(stm->context->serial_queue, ^() {
|
||||
if (audiounit_reinit_stream(stm, was_running) != CUBEB_OK) {
|
||||
if (audiounit_reinit_stream(stm) != CUBEB_OK) {
|
||||
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STOPPED);
|
||||
LOG("(%p) Could not reopen the stream after switching.", stm);
|
||||
}
|
||||
@@ -718,17 +717,6 @@ audiounit_install_device_changed_callback(cubeb_stream * stm)
|
||||
PRINT_ERROR_CODE("AudioObjectAddPropertyListener/output/kAudioDevicePropertyDataSource", r);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
/* This event will notify us when the default audio device changes,
|
||||
* for example when the user plugs in a USB headset and the system chooses it
|
||||
* automatically as the default, or when another device is chosen in the
|
||||
* dropdown list. */
|
||||
r = audiounit_add_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultOutputDevice,
|
||||
kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
|
||||
if (r != noErr) {
|
||||
PRINT_ERROR_CODE("AudioObjectAddPropertyListener/output/kAudioHardwarePropertyDefaultOutputDevice", r);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (stm->input_unit) {
|
||||
@@ -746,14 +734,6 @@ audiounit_install_device_changed_callback(cubeb_stream * stm)
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
/* This event will notify us when the default input device changes. */
|
||||
r = audiounit_add_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultInputDevice,
|
||||
kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
|
||||
if (r != noErr) {
|
||||
PRINT_ERROR_CODE("AudioObjectAddPropertyListener/input/kAudioHardwarePropertyDefaultInputDevice", r);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
/* Event to notify when the input is going away. */
|
||||
AudioDeviceID dev = stm->input_device ? stm->input_device :
|
||||
audiounit_get_default_device_id(CUBEB_DEVICE_TYPE_INPUT);
|
||||
@@ -768,6 +748,37 @@ audiounit_install_device_changed_callback(cubeb_stream * stm)
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
audiounit_install_system_changed_callback(cubeb_stream * stm)
|
||||
{
|
||||
OSStatus r;
|
||||
|
||||
if (stm->output_unit) {
|
||||
/* This event will notify us when the default audio device changes,
|
||||
* for example when the user plugs in a USB headset and the system chooses it
|
||||
* automatically as the default, or when another device is chosen in the
|
||||
* dropdown list. */
|
||||
r = audiounit_add_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultOutputDevice,
|
||||
kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
|
||||
if (r != noErr) {
|
||||
LOG("AudioObjectAddPropertyListener/output/kAudioHardwarePropertyDefaultOutputDevice rv=%d", r);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (stm->input_unit) {
|
||||
/* This event will notify us when the default input device changes. */
|
||||
r = audiounit_add_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultInputDevice,
|
||||
kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
|
||||
if (r != noErr) {
|
||||
LOG("AudioObjectAddPropertyListener/input/kAudioHardwarePropertyDefaultInputDevice rv=%d", r);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
audiounit_uninstall_device_changed_callback(cubeb_stream * stm)
|
||||
{
|
||||
@@ -785,12 +796,6 @@ audiounit_uninstall_device_changed_callback(cubeb_stream * stm)
|
||||
if (r != noErr) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
r = audiounit_remove_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultOutputDevice,
|
||||
kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
|
||||
if (r != noErr) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (stm->input_unit) {
|
||||
@@ -806,8 +811,26 @@ audiounit_uninstall_device_changed_callback(cubeb_stream * stm)
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
}
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
audiounit_uninstall_system_changed_callback(cubeb_stream * stm)
|
||||
{
|
||||
OSStatus r;
|
||||
|
||||
if (stm->output_unit) {
|
||||
r = audiounit_remove_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultOutputDevice,
|
||||
kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
|
||||
if (r != noErr) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (stm->input_unit) {
|
||||
r = audiounit_remove_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultInputDevice,
|
||||
kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
|
||||
kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
|
||||
if (r != noErr) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
@@ -1717,6 +1740,12 @@ audiounit_setup_stream(cubeb_stream * stm)
|
||||
stm->expected_output_callbacks_in_a_row = ceilf(stm->output_hw_rate / stm->input_hw_rate);
|
||||
}
|
||||
|
||||
r = audiounit_install_device_changed_callback(stm);
|
||||
if (r != CUBEB_OK) {
|
||||
LOG("(%p) Could not install the device change callback.", stm);
|
||||
return r;
|
||||
}
|
||||
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
@@ -1786,7 +1815,7 @@ audiounit_stream_init(cubeb * context,
|
||||
return r;
|
||||
}
|
||||
|
||||
r = audiounit_install_device_changed_callback(stm.get());
|
||||
r = audiounit_install_system_changed_callback(stm);
|
||||
if (r != CUBEB_OK) {
|
||||
LOG("(%p) Could not install the device change callback.", stm.get());
|
||||
return r;
|
||||
@@ -1801,6 +1830,12 @@ static void
|
||||
audiounit_close_stream(cubeb_stream *stm)
|
||||
{
|
||||
stm->mutex.assert_current_thread_owns();
|
||||
|
||||
int r = audiounit_uninstall_device_changed_callback(stm);
|
||||
if (r != CUBEB_OK) {
|
||||
LOG("(%p) Could not uninstall the device changed callback", stm);
|
||||
}
|
||||
|
||||
if (stm->input_unit) {
|
||||
AudioUnitUninitialize(stm->input_unit);
|
||||
AudioComponentInstanceDispose(stm->input_unit);
|
||||
@@ -1821,6 +1856,11 @@ audiounit_stream_destroy(cubeb_stream * stm)
|
||||
{
|
||||
stm->shutdown = true;
|
||||
|
||||
int r = audiounit_uninstall_system_changed_callback(stm);
|
||||
if (r != CUBEB_OK) {
|
||||
LOG("(%p) Could not uninstall the device changed callback", stm);
|
||||
}
|
||||
|
||||
auto_lock context_lock(stm->context->mutex);
|
||||
audiounit_stream_stop_internal(stm);
|
||||
|
||||
@@ -1829,13 +1869,6 @@ audiounit_stream_destroy(cubeb_stream * stm)
|
||||
audiounit_close_stream(stm);
|
||||
}
|
||||
|
||||
#if !TARGET_OS_IPHONE
|
||||
int r = audiounit_uninstall_device_changed_callback(stm);
|
||||
if (r != CUBEB_OK) {
|
||||
LOG("(%p) Could not uninstall the device changed callback", stm);
|
||||
}
|
||||
#endif
|
||||
|
||||
assert(stm->context->active_streams >= 1);
|
||||
stm->context->active_streams -= 1;
|
||||
|
||||
@@ -1860,10 +1893,10 @@ audiounit_stream_start_internal(cubeb_stream * stm)
|
||||
static int
|
||||
audiounit_stream_start(cubeb_stream * stm)
|
||||
{
|
||||
auto_lock context_lock(stm->context->mutex);
|
||||
stm->shutdown = false;
|
||||
stm->draining = false;
|
||||
|
||||
auto_lock context_lock(stm->context->mutex);
|
||||
audiounit_stream_start_internal(stm);
|
||||
|
||||
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STARTED);
|
||||
@@ -1889,9 +1922,9 @@ audiounit_stream_stop_internal(cubeb_stream * stm)
|
||||
static int
|
||||
audiounit_stream_stop(cubeb_stream * stm)
|
||||
{
|
||||
auto_lock context_lock(stm->context->mutex);
|
||||
stm->shutdown = true;
|
||||
|
||||
auto_lock context_lock(stm->context->mutex);
|
||||
audiounit_stream_stop_internal(stm);
|
||||
|
||||
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STOPPED);
|
||||
|
||||
@@ -0,0 +1,402 @@
|
||||
diff --git a/media/libcubeb/src/cubeb_audiounit.cpp b/media/libcubeb/src/cubeb_audiounit.cpp
|
||||
--- a/media/libcubeb/src/cubeb_audiounit.cpp
|
||||
+++ b/media/libcubeb/src/cubeb_audiounit.cpp
|
||||
@@ -594,20 +594,20 @@ audiounit_get_input_device_id(AudioDevic
|
||||
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
static int audiounit_stream_get_volume(cubeb_stream * stm, float * volume);
|
||||
static int audiounit_stream_set_volume(cubeb_stream * stm, float volume);
|
||||
|
||||
static int
|
||||
-audiounit_reinit_stream(cubeb_stream * stm, bool is_started)
|
||||
+audiounit_reinit_stream(cubeb_stream * stm)
|
||||
{
|
||||
auto_lock context_lock(stm->context->mutex);
|
||||
- if (is_started) {
|
||||
+ if (!stm->shutdown) {
|
||||
audiounit_stream_stop_internal(stm);
|
||||
}
|
||||
|
||||
{
|
||||
auto_lock lock(stm->mutex);
|
||||
float volume = 0.0;
|
||||
int vol_rv = audiounit_stream_get_volume(stm, &volume);
|
||||
|
||||
@@ -622,32 +622,30 @@ audiounit_reinit_stream(cubeb_stream * s
|
||||
audiounit_stream_set_volume(stm, volume);
|
||||
}
|
||||
|
||||
// Reset input frames to force new stream pre-buffer
|
||||
// silence if needed, check `is_extra_input_needed()`
|
||||
stm->frames_read = 0;
|
||||
|
||||
// If the stream was running, start it again.
|
||||
- if (is_started) {
|
||||
+ if (!stm->shutdown) {
|
||||
audiounit_stream_start_internal(stm);
|
||||
}
|
||||
}
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
static OSStatus
|
||||
audiounit_property_listener_callback(AudioObjectID /* id */, UInt32 address_count,
|
||||
const AudioObjectPropertyAddress * addresses,
|
||||
void * user)
|
||||
{
|
||||
cubeb_stream * stm = (cubeb_stream*) user;
|
||||
stm->switching_device = true;
|
||||
- // Note if the stream was running or not
|
||||
- bool was_running = !stm->shutdown;
|
||||
|
||||
LOG("(%p) Audio device changed, %d events.", stm, address_count);
|
||||
for (UInt32 i = 0; i < address_count; i++) {
|
||||
switch(addresses[i].mSelector) {
|
||||
case kAudioHardwarePropertyDefaultOutputDevice: {
|
||||
LOG("Event[%d] - mSelector == kAudioHardwarePropertyDefaultOutputDevice", i);
|
||||
// Allow restart to choose the new default
|
||||
stm->output_device = nullptr;
|
||||
@@ -666,19 +664,20 @@ audiounit_property_listener_callback(Aud
|
||||
if (stm->is_default_input) {
|
||||
LOG("It's the default input device, ignore the event");
|
||||
return noErr;
|
||||
}
|
||||
// Allow restart to choose the new default. Event register only for input.
|
||||
stm->input_device = nullptr;
|
||||
}
|
||||
break;
|
||||
- case kAudioDevicePropertyDataSource:
|
||||
- LOG("Event[%d] - mSelector == kAudioHardwarePropertyDataSource", i);
|
||||
- break;
|
||||
+ case kAudioDevicePropertyDataSource: {
|
||||
+ LOG("Event[%d] - mSelector == kAudioHardwarePropertyDataSource", i);
|
||||
+ return noErr;
|
||||
+ }
|
||||
}
|
||||
}
|
||||
|
||||
for (UInt32 i = 0; i < address_count; i++) {
|
||||
switch(addresses[i].mSelector) {
|
||||
case kAudioHardwarePropertyDefaultOutputDevice:
|
||||
case kAudioHardwarePropertyDefaultInputDevice:
|
||||
case kAudioDevicePropertyDeviceIsAlive:
|
||||
@@ -691,17 +690,17 @@ audiounit_property_listener_callback(Aud
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use a new thread, through the queue, to avoid deadlock when calling
|
||||
// Get/SetProperties method from inside notify callback
|
||||
dispatch_async(stm->context->serial_queue, ^() {
|
||||
- if (audiounit_reinit_stream(stm, was_running) != CUBEB_OK) {
|
||||
+ if (audiounit_reinit_stream(stm) != CUBEB_OK) {
|
||||
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STOPPED);
|
||||
LOG("(%p) Could not reopen the stream after switching.", stm);
|
||||
}
|
||||
stm->switching_device = false;
|
||||
});
|
||||
|
||||
return noErr;
|
||||
}
|
||||
@@ -752,27 +751,16 @@ audiounit_install_device_changed_callbac
|
||||
}
|
||||
|
||||
r = audiounit_add_listener(stm, output_dev_id, kAudioDevicePropertyDataSource,
|
||||
kAudioDevicePropertyScopeOutput, &audiounit_property_listener_callback);
|
||||
if (r != noErr) {
|
||||
PRINT_ERROR_CODE("AudioObjectAddPropertyListener/output/kAudioDevicePropertyDataSource", r);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
-
|
||||
- /* This event will notify us when the default audio device changes,
|
||||
- * for example when the user plugs in a USB headset and the system chooses it
|
||||
- * automatically as the default, or when another device is chosen in the
|
||||
- * dropdown list. */
|
||||
- r = audiounit_add_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultOutputDevice,
|
||||
- kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
|
||||
- if (r != noErr) {
|
||||
- PRINT_ERROR_CODE("AudioObjectAddPropertyListener/output/kAudioHardwarePropertyDefaultOutputDevice", r);
|
||||
- return CUBEB_ERROR;
|
||||
- }
|
||||
}
|
||||
|
||||
if (stm->input_unit) {
|
||||
/* This event will notify us when the data source on the input device changes. */
|
||||
AudioDeviceID input_dev_id;
|
||||
r = audiounit_get_input_device_id(&input_dev_id);
|
||||
if (r != noErr) {
|
||||
return CUBEB_ERROR;
|
||||
@@ -780,78 +768,112 @@ audiounit_install_device_changed_callbac
|
||||
|
||||
r = audiounit_add_listener(stm, input_dev_id, kAudioDevicePropertyDataSource,
|
||||
kAudioDevicePropertyScopeInput, &audiounit_property_listener_callback);
|
||||
if (r != noErr) {
|
||||
PRINT_ERROR_CODE("AudioObjectAddPropertyListener/input/kAudioDevicePropertyDataSource", r);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
- /* This event will notify us when the default input device changes. */
|
||||
- r = audiounit_add_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultInputDevice,
|
||||
- kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
|
||||
- if (r != noErr) {
|
||||
- PRINT_ERROR_CODE("AudioObjectAddPropertyListener/input/kAudioHardwarePropertyDefaultInputDevice", r);
|
||||
- return CUBEB_ERROR;
|
||||
- }
|
||||
-
|
||||
/* Event to notify when the input is going away. */
|
||||
AudioDeviceID dev = stm->input_device ? reinterpret_cast<intptr_t>(stm->input_device) :
|
||||
audiounit_get_default_device_id(CUBEB_DEVICE_TYPE_INPUT);
|
||||
r = audiounit_add_listener(stm, dev, kAudioDevicePropertyDeviceIsAlive,
|
||||
kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
|
||||
if (r != noErr) {
|
||||
PRINT_ERROR_CODE("AudioObjectAddPropertyListener/input/kAudioDevicePropertyDeviceIsAlive", r);
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
+audiounit_install_system_changed_callback(cubeb_stream * stm)
|
||||
+{
|
||||
+ OSStatus r;
|
||||
+
|
||||
+ if (stm->output_unit) {
|
||||
+ /* This event will notify us when the default audio device changes,
|
||||
+ * for example when the user plugs in a USB headset and the system chooses it
|
||||
+ * automatically as the default, or when another device is chosen in the
|
||||
+ * dropdown list. */
|
||||
+ r = audiounit_add_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultOutputDevice,
|
||||
+ kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
|
||||
+ if (r != noErr) {
|
||||
+ LOG("AudioObjectAddPropertyListener/output/kAudioHardwarePropertyDefaultOutputDevice rv=%d", r);
|
||||
+ return CUBEB_ERROR;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (stm->input_unit) {
|
||||
+ /* This event will notify us when the default input device changes. */
|
||||
+ r = audiounit_add_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultInputDevice,
|
||||
+ kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
|
||||
+ if (r != noErr) {
|
||||
+ LOG("AudioObjectAddPropertyListener/input/kAudioHardwarePropertyDefaultInputDevice rv=%d", r);
|
||||
+ return CUBEB_ERROR;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ return CUBEB_OK;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
audiounit_uninstall_device_changed_callback(cubeb_stream * stm)
|
||||
{
|
||||
OSStatus r;
|
||||
|
||||
if (stm->output_unit) {
|
||||
AudioDeviceID output_dev_id;
|
||||
r = audiounit_get_output_device_id(&output_dev_id);
|
||||
if (r != noErr) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
r = audiounit_remove_listener(stm, output_dev_id, kAudioDevicePropertyDataSource,
|
||||
kAudioDevicePropertyScopeOutput, &audiounit_property_listener_callback);
|
||||
if (r != noErr) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
-
|
||||
- r = audiounit_remove_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultOutputDevice,
|
||||
- kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
|
||||
- if (r != noErr) {
|
||||
- return CUBEB_ERROR;
|
||||
- }
|
||||
}
|
||||
|
||||
if (stm->input_unit) {
|
||||
AudioDeviceID input_dev_id;
|
||||
r = audiounit_get_input_device_id(&input_dev_id);
|
||||
if (r != noErr) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
|
||||
r = audiounit_remove_listener(stm, input_dev_id, kAudioDevicePropertyDataSource,
|
||||
kAudioDevicePropertyScopeInput, &audiounit_property_listener_callback);
|
||||
if (r != noErr) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
-
|
||||
+ }
|
||||
+ return CUBEB_OK;
|
||||
+}
|
||||
+
|
||||
+static int
|
||||
+audiounit_uninstall_system_changed_callback(cubeb_stream * stm)
|
||||
+{
|
||||
+ OSStatus r;
|
||||
+
|
||||
+ if (stm->output_unit) {
|
||||
+ r = audiounit_remove_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultOutputDevice,
|
||||
+ kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
|
||||
+ if (r != noErr) {
|
||||
+ return CUBEB_ERROR;
|
||||
+ }
|
||||
+ }
|
||||
+
|
||||
+ if (stm->input_unit) {
|
||||
r = audiounit_remove_listener(stm, kAudioObjectSystemObject, kAudioHardwarePropertyDefaultInputDevice,
|
||||
- kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
|
||||
+ kAudioObjectPropertyScopeGlobal, &audiounit_property_listener_callback);
|
||||
if (r != noErr) {
|
||||
return CUBEB_ERROR;
|
||||
}
|
||||
}
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
/* Get the acceptable buffer size (in frames) that this device can work with. */
|
||||
@@ -1764,16 +1786,22 @@ audiounit_setup_stream(cubeb_stream * st
|
||||
|
||||
if (stm->input_unit && stm->output_unit) {
|
||||
// According to the I/O hardware rate it is expected a specific pattern of callbacks
|
||||
// for example is input is 44100 and output is 48000 we expected no more than 2
|
||||
// out callback in a row.
|
||||
stm->expected_output_callbacks_in_a_row = ceilf(stm->output_hw_rate / stm->input_hw_rate);
|
||||
}
|
||||
|
||||
+ r = audiounit_install_device_changed_callback(stm);
|
||||
+ if (r != CUBEB_OK) {
|
||||
+ LOG("(%p) Could not install the device change callback.", stm);
|
||||
+ return r;
|
||||
+ }
|
||||
+
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
static int
|
||||
audiounit_stream_init(cubeb * context,
|
||||
cubeb_stream ** stream,
|
||||
char const * /* stream_name */,
|
||||
cubeb_devid input_device,
|
||||
@@ -1838,31 +1866,37 @@ audiounit_stream_init(cubeb * context,
|
||||
}
|
||||
|
||||
if (r != CUBEB_OK) {
|
||||
LOG("(%p) Could not setup the audiounit stream.", stm);
|
||||
audiounit_stream_destroy(stm);
|
||||
return r;
|
||||
}
|
||||
|
||||
- r = audiounit_install_device_changed_callback(stm);
|
||||
+ r = audiounit_install_system_changed_callback(stm);
|
||||
if (r != CUBEB_OK) {
|
||||
LOG("(%p) Could not install the device change callback.", stm);
|
||||
return r;
|
||||
}
|
||||
|
||||
*stream = stm;
|
||||
LOG("Cubeb stream (%p) init successful.", stm);
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
audiounit_close_stream(cubeb_stream *stm)
|
||||
{
|
||||
stm->mutex.assert_current_thread_owns();
|
||||
+
|
||||
+ int r = audiounit_uninstall_device_changed_callback(stm);
|
||||
+ if (r != CUBEB_OK) {
|
||||
+ LOG("(%p) Could not uninstall the device changed callback", stm);
|
||||
+ }
|
||||
+
|
||||
if (stm->input_unit) {
|
||||
AudioUnitUninitialize(stm->input_unit);
|
||||
AudioComponentInstanceDispose(stm->input_unit);
|
||||
}
|
||||
|
||||
audiounit_destroy_input_linear_buffer(stm);
|
||||
|
||||
if (stm->output_unit) {
|
||||
@@ -1873,31 +1907,29 @@ audiounit_close_stream(cubeb_stream *stm
|
||||
cubeb_resampler_destroy(stm->resampler);
|
||||
}
|
||||
|
||||
static void
|
||||
audiounit_stream_destroy(cubeb_stream * stm)
|
||||
{
|
||||
stm->shutdown = true;
|
||||
|
||||
+ int r = audiounit_uninstall_system_changed_callback(stm);
|
||||
+ if (r != CUBEB_OK) {
|
||||
+ LOG("(%p) Could not uninstall the device changed callback", stm);
|
||||
+ }
|
||||
+
|
||||
auto_lock context_lock(stm->context->mutex);
|
||||
audiounit_stream_stop_internal(stm);
|
||||
|
||||
{
|
||||
auto_lock lock(stm->mutex);
|
||||
audiounit_close_stream(stm);
|
||||
}
|
||||
|
||||
-#if !TARGET_OS_IPHONE
|
||||
- int r = audiounit_uninstall_device_changed_callback(stm);
|
||||
- if (r != CUBEB_OK) {
|
||||
- LOG("(%p) Could not uninstall the device changed callback", stm);
|
||||
- }
|
||||
-#endif
|
||||
-
|
||||
assert(stm->context->active_streams >= 1);
|
||||
stm->context->active_streams -= 1;
|
||||
|
||||
LOG("Cubeb stream (%p) destroyed successful.", stm);
|
||||
|
||||
stm->~cubeb_stream();
|
||||
free(stm);
|
||||
}
|
||||
@@ -1914,20 +1946,20 @@ audiounit_stream_start_internal(cubeb_st
|
||||
r = AudioOutputUnitStart(stm->output_unit);
|
||||
assert(r == 0);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
audiounit_stream_start(cubeb_stream * stm)
|
||||
{
|
||||
+ auto_lock context_lock(stm->context->mutex);
|
||||
stm->shutdown = false;
|
||||
stm->draining = false;
|
||||
|
||||
- auto_lock context_lock(stm->context->mutex);
|
||||
audiounit_stream_start_internal(stm);
|
||||
|
||||
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STARTED);
|
||||
|
||||
LOG("Cubeb stream (%p) started successfully.", stm);
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
@@ -1943,19 +1975,19 @@ audiounit_stream_stop_internal(cubeb_str
|
||||
r = AudioOutputUnitStop(stm->output_unit);
|
||||
assert(r == 0);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
audiounit_stream_stop(cubeb_stream * stm)
|
||||
{
|
||||
+ auto_lock context_lock(stm->context->mutex);
|
||||
stm->shutdown = true;
|
||||
|
||||
- auto_lock context_lock(stm->context->mutex);
|
||||
audiounit_stream_stop_internal(stm);
|
||||
|
||||
stm->state_callback(stm, stm->user_ptr, CUBEB_STATE_STOPPED);
|
||||
|
||||
LOG("Cubeb stream (%p) stopped successfully.", stm);
|
||||
return CUBEB_OK;
|
||||
}
|
||||
|
||||
@@ -4347,6 +4347,8 @@ pref("signon.storeWhenAutocompleteOff", true);
|
||||
pref("signon.debug", false);
|
||||
pref("signon.recipes.path", "chrome://passwordmgr/content/recipes.json");
|
||||
pref("signon.schemeUpgrades", false);
|
||||
// This temporarily prevents the master password to reprompt for autocomplete.
|
||||
pref("signon.masterPasswordReprompt.timeout_ms", 900000); // 15 Minutes
|
||||
|
||||
// Satchel (Form Manager) prefs
|
||||
pref("browser.formfill.debug", false);
|
||||
|
||||
@@ -93,6 +93,12 @@ typedef uint8_t nsHttpVersion;
|
||||
// interop problems with critical infrastructure
|
||||
#define NS_HTTP_BE_CONSERVATIVE (1<<11)
|
||||
|
||||
// (1<<12) is used for NS_HTTP_URGENT_START on a newer branch
|
||||
|
||||
// A sticky connection of the transaction is explicitly allowed to be restarted
|
||||
// on ERROR_NET_RESET.
|
||||
#define NS_HTTP_CONNECTION_RESTARTABLE (1<<13)
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// some default values
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
@@ -327,6 +327,7 @@ nsHttpChannel::nsHttpChannel()
|
||||
, mIsCorsPreflightDone(0)
|
||||
, mStronglyFramed(false)
|
||||
, mUsedNetwork(0)
|
||||
, mAuthConnectionRestartable(0)
|
||||
, mPushedStream(nullptr)
|
||||
, mLocalBlocklist(false)
|
||||
, mWarningReporter(nullptr)
|
||||
@@ -5660,6 +5661,14 @@ NS_IMETHODIMP nsHttpChannel::CloseStickyConnection()
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP nsHttpChannel::ConnectionRestartable(bool aRestartable)
|
||||
{
|
||||
LOG(("nsHttpChannel::ConnectionRestartable this=%p, restartable=%d",
|
||||
this, aRestartable));
|
||||
mAuthConnectionRestartable = aRestartable;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpChannel::nsISupports
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -7622,9 +7631,17 @@ nsHttpChannel::DoAuthRetry(nsAHttpConnection *conn)
|
||||
seekable->Seek(nsISeekableStream::NS_SEEK_SET, 0);
|
||||
}
|
||||
|
||||
// set sticky connection flag and disable pipelining.
|
||||
mCaps |= NS_HTTP_STICKY_CONNECTION;
|
||||
mCaps &= ~NS_HTTP_ALLOW_PIPELINING;
|
||||
// always set sticky connection flag
|
||||
mCaps |= NS_HTTP_STICKY_CONNECTION;
|
||||
// and when needed, allow restart regardless the sticky flag
|
||||
if (mAuthConnectionRestartable) {
|
||||
LOG((" connection made restartable"));
|
||||
mCaps |= NS_HTTP_CONNECTION_RESTARTABLE;
|
||||
mAuthConnectionRestartable = false;
|
||||
} else {
|
||||
LOG((" connection made non-restartable"));
|
||||
mCaps &= ~NS_HTTP_CONNECTION_RESTARTABLE;
|
||||
}
|
||||
|
||||
// and create a new one...
|
||||
rv = SetupTransaction();
|
||||
|
||||
@@ -111,6 +111,7 @@ public:
|
||||
NS_IMETHOD OnAuthAvailable() override;
|
||||
NS_IMETHOD OnAuthCancelled(bool userCancel) override;
|
||||
NS_IMETHOD CloseStickyConnection() override;
|
||||
NS_IMETHOD ConnectionRestartable(bool) override;
|
||||
// Functions we implement from nsIHttpAuthenticableChannel but are
|
||||
// declared in HttpBaseChannel must be implemented in this class. We
|
||||
// just call the HttpBaseChannel:: impls.
|
||||
@@ -581,6 +582,9 @@ private:
|
||||
// true if an HTTP transaction is created for the socket thread
|
||||
uint32_t mUsedNetwork : 1;
|
||||
|
||||
// the next authentication request can be sent on a whole new connection
|
||||
uint32_t mAuthConnectionRestartable : 1;
|
||||
|
||||
nsCOMPtr<nsIChannel> mPreflightChannel;
|
||||
|
||||
nsTArray<nsContinueRedirectionFunc> mRedirectFuncStack;
|
||||
|
||||
@@ -782,6 +782,11 @@ nsHttpChannelAuthProvider::GetCredentialsForChallenge(const char *challenge,
|
||||
if (entry)
|
||||
sessionStateGrip = entry->mMetaData;
|
||||
|
||||
// remember if we already had the continuation state. it means we are in
|
||||
// the middle of the authentication exchange and the connection must be
|
||||
// kept sticky then (and only then).
|
||||
bool authAtProgress = !!*continuationState;
|
||||
|
||||
// for digest auth, maybe our cached nonce value simply timed out...
|
||||
bool identityInvalid;
|
||||
nsISupports *sessionState = sessionStateGrip;
|
||||
@@ -816,11 +821,16 @@ nsHttpChannelAuthProvider::GetCredentialsForChallenge(const char *challenge,
|
||||
// use of the cached identity and not asking the user again
|
||||
mProxyIdent.Clear();
|
||||
}
|
||||
mConnectionBased = false;
|
||||
}
|
||||
|
||||
mConnectionBased = !!(authFlags & nsIHttpAuthenticator::CONNECTION_BASED);
|
||||
|
||||
// It's legal if the peer closes the connection after the first 401/7.
|
||||
// Making the connection sticky will prevent its restart giving the user
|
||||
// a 'network reset' error every time. Hence, we mark the connection
|
||||
// as restartable.
|
||||
mAuthChannel->ConnectionRestartable(mConnectionBased && !authAtProgress);
|
||||
|
||||
if (identityInvalid) {
|
||||
if (entry) {
|
||||
if (ident->Equals(entry->Identity())) {
|
||||
|
||||
@@ -1003,7 +1003,7 @@ nsHttpTransaction::Close(nsresult reason)
|
||||
if ((reason == NS_ERROR_NET_RESET ||
|
||||
reason == NS_OK ||
|
||||
reason == psm::GetXPCOMFromNSSError(SSL_ERROR_DOWNGRADE_WITH_EARLY_DATA)) &&
|
||||
!(mCaps & NS_HTTP_STICKY_CONNECTION)) {
|
||||
(!(mCaps & NS_HTTP_STICKY_CONNECTION) || (mCaps & NS_HTTP_CONNECTION_RESTARTABLE))) {
|
||||
|
||||
if (mForceRestart && NS_SUCCEEDED(Restart())) {
|
||||
if (mResponseHead) {
|
||||
|
||||
@@ -112,4 +112,11 @@ interface nsIHttpAuthenticableChannel : nsIProxiedChannel
|
||||
* the same connection.
|
||||
*/
|
||||
void closeStickyConnection();
|
||||
|
||||
/**
|
||||
* Tells the channel to mark the connection as allowed to restart on
|
||||
* authentication retry. This is allowed when the request is a start
|
||||
* of a new authentication round.
|
||||
*/
|
||||
void connectionRestartable(in boolean restartable);
|
||||
};
|
||||
|
||||
@@ -36,5 +36,50 @@
|
||||
|
||||
hyperlink1.click()
|
||||
hyperlink2.click()
|
||||
})
|
||||
}, "Following a noreferrer link with a named target should not cause creation of a window that can be targeted by another noreferrer link with the same named target");
|
||||
|
||||
async_test(function(t) {
|
||||
var ifr = document.createElement("iframe");
|
||||
ifr.name = "sufficientlyrandomwindownameamiright2";
|
||||
ifr.onload = t.step_func(function() {
|
||||
var hyperlink = document.body.appendChild(document.createElement("a"));
|
||||
t.add_cleanup(function() {
|
||||
hyperlink.remove();
|
||||
});
|
||||
hyperlink.rel = "noreferrer";
|
||||
hyperlink.href = URL.createObjectURL(new Blob(["hello subframe"],
|
||||
{ type: "text/html"}));
|
||||
hyperlink.target = "sufficientlyrandomwindownameamiright2";
|
||||
ifr.onload = t.step_func_done(function() {
|
||||
assert_equals(ifr.contentDocument.documentElement.textContent,
|
||||
"hello subframe");
|
||||
});
|
||||
hyperlink.click();
|
||||
});
|
||||
document.body.appendChild(ifr);
|
||||
t.add_cleanup(function() {
|
||||
ifr.remove();
|
||||
});
|
||||
}, "Targeting a rel=noreferrer link at an existing named subframe should work");
|
||||
|
||||
async_test(function(t) {
|
||||
var win = window.open("", "sufficientlyrandomwindownameamiright3");
|
||||
t.add_cleanup(function() {
|
||||
win.close();
|
||||
});
|
||||
|
||||
var hyperlink = document.body.appendChild(document.createElement("a"));
|
||||
t.add_cleanup(function() {
|
||||
hyperlink.remove();
|
||||
});
|
||||
hyperlink.rel = "noreferrer";
|
||||
hyperlink.href = URL.createObjectURL(new Blob(["hello window"],
|
||||
{ type: "text/html"}));
|
||||
hyperlink.target = "sufficientlyrandomwindownameamiright3";
|
||||
win.onload = t.step_func_done(function() {
|
||||
assert_equals(win.document.documentElement.textContent,
|
||||
"hello window");
|
||||
});
|
||||
hyperlink.click();
|
||||
}, "Targeting a rel=noreferrer link at an existing named window should work");
|
||||
</script>
|
||||
|
||||
@@ -38,6 +38,37 @@ var LoginManagerParent = {
|
||||
*/
|
||||
_recipeManager: null,
|
||||
|
||||
// Tracks the last time the user cancelled the master password prompt,
|
||||
// to avoid spamming master password prompts on autocomplete searches.
|
||||
_lastMPLoginCancelled: Math.NEGATIVE_INFINITY,
|
||||
|
||||
_searchAndDedupeLogins: function (formOrigin, actionOrigin) {
|
||||
let logins;
|
||||
try {
|
||||
logins = LoginHelper.searchLoginsWithObject({
|
||||
hostname: formOrigin,
|
||||
formSubmitURL: actionOrigin,
|
||||
schemeUpgrades: LoginHelper.schemeUpgrades,
|
||||
});
|
||||
} catch (e) {
|
||||
// Record the last time the user cancelled the MP prompt
|
||||
// to avoid spamming them with MP prompts for autocomplete.
|
||||
if (e.result == Cr.NS_ERROR_ABORT) {
|
||||
log("User cancelled master password prompt.");
|
||||
this._lastMPLoginCancelled = Date.now();
|
||||
return [];
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
|
||||
// Dedupe so the length checks below still make sense with scheme upgrades.
|
||||
let resolveBy = [
|
||||
"scheme",
|
||||
"timePasswordChanged",
|
||||
];
|
||||
return LoginHelper.dedupeLogins(logins, ["username"], resolveBy, formOrigin);
|
||||
},
|
||||
|
||||
init() {
|
||||
let mm = Cc["@mozilla.org/globalmessagemanager;1"]
|
||||
.getService(Ci.nsIMessageListenerManager);
|
||||
@@ -204,15 +235,8 @@ var LoginManagerParent = {
|
||||
return;
|
||||
}
|
||||
|
||||
let logins = LoginHelper.searchLoginsWithObject({
|
||||
formSubmitURL: actionOrigin,
|
||||
hostname: formOrigin,
|
||||
schemeUpgrades: LoginHelper.schemeUpgrades,
|
||||
});
|
||||
let resolveBy = [
|
||||
"scheme",
|
||||
"timePasswordChanged",
|
||||
];
|
||||
let logins = this._searchAndDedupeLogins(formOrigin, actionOrigin);
|
||||
|
||||
logins = LoginHelper.dedupeLogins(logins, ["username"], resolveBy, formOrigin);
|
||||
log("sendLoginDataToChild:", logins.length, "deduped logins");
|
||||
// Convert the array of nsILoginInfo to vanilla JS objects since nsILoginInfo
|
||||
@@ -232,6 +256,22 @@ var LoginManagerParent = {
|
||||
// Note: previousResult is a regular object, not an
|
||||
// nsIAutoCompleteResult.
|
||||
|
||||
// Cancel if we unsuccessfully prompted for the master password too recently.
|
||||
if (!Services.logins.isLoggedIn) {
|
||||
let timeDiff = Date.now() - this._lastMPLoginCancelled;
|
||||
if (timeDiff < this._repromptTimeout) {
|
||||
log("Not searching logins for autocomplete since the master password " +
|
||||
`prompt was last cancelled ${Math.round(timeDiff / 1000)} seconds ago.`);
|
||||
// Send an empty array to make LoginManagerContent clear the
|
||||
// outstanding request it has temporarily saved.
|
||||
target.messageManager.sendAsyncMessage("RemoteLogins:loginsAutoCompleted", {
|
||||
requestId,
|
||||
logins: [],
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
let searchStringLower = searchString.toLowerCase();
|
||||
let logins;
|
||||
if (previousResult &&
|
||||
@@ -244,17 +284,7 @@ var LoginManagerParent = {
|
||||
} else {
|
||||
log("Creating new autocomplete search result.");
|
||||
|
||||
// Grab the logins from the database.
|
||||
logins = LoginHelper.searchLoginsWithObject({
|
||||
formSubmitURL: actionOrigin,
|
||||
hostname: formOrigin,
|
||||
schemeUpgrades: LoginHelper.schemeUpgrades,
|
||||
});
|
||||
let resolveBy = [
|
||||
"scheme",
|
||||
"timePasswordChanged",
|
||||
];
|
||||
logins = LoginHelper.dedupeLogins(logins, ["username"], resolveBy, formOrigin);
|
||||
logins = this._searchAndDedupeLogins(formOrigin, actionOrigin);
|
||||
}
|
||||
|
||||
let matchingLogins = logins.filter(function(fullMatch) {
|
||||
@@ -323,20 +353,9 @@ var LoginManagerParent = {
|
||||
(usernameField ? usernameField.name : ""),
|
||||
newPasswordField.name);
|
||||
|
||||
let logins = LoginHelper.searchLoginsWithObject({
|
||||
formSubmitURL,
|
||||
hostname,
|
||||
schemeUpgrades: LoginHelper.schemeUpgrades,
|
||||
});
|
||||
|
||||
// Dedupe so the length checks below still make sense with scheme upgrades.
|
||||
// Below here we have one login per hostPort + action + username with the
|
||||
// matching scheme being preferred.
|
||||
let resolveBy = [
|
||||
"scheme",
|
||||
"timePasswordChanged",
|
||||
];
|
||||
logins = LoginHelper.dedupeLogins(logins, ["username"], resolveBy, hostname);
|
||||
let logins = this._searchAndDedupeLogins(hostname, formSubmitURL);
|
||||
|
||||
// If we didn't find a username field, but seem to be changing a
|
||||
// password, allow the user to select from a list of applicable
|
||||
@@ -488,3 +507,6 @@ var LoginManagerParent = {
|
||||
.CustomEvent("InsecureLoginFormsStateChange"));
|
||||
},
|
||||
};
|
||||
|
||||
XPCOMUtils.defineLazyPreferenceGetter(LoginManagerParent, "_repromptTimeout",
|
||||
"signon.masterPasswordReprompt.timeout_ms", 900000); // 15 Minutes
|
||||
|
||||
@@ -53,6 +53,7 @@ support-files =
|
||||
[browser_insecurePasswordConsoleWarning.js]
|
||||
support-files =
|
||||
form_cross_origin_insecure_action.html
|
||||
[browser_master_password_autocomplete.js]
|
||||
[browser_notifications.js]
|
||||
[browser_notifications_username.js]
|
||||
[browser_notifications_password.js]
|
||||
|
||||
@@ -0,0 +1,59 @@
|
||||
const HOST = "https://example.com";
|
||||
const URL = HOST + "/browser/toolkit/components/passwordmgr/test/browser/form_basic.html";
|
||||
const TIMEOUT_PREF = "signon.masterPasswordReprompt.timeout_ms";
|
||||
|
||||
// Waits for the master password prompt and cancels it.
|
||||
function waitForDialog() {
|
||||
let dialogShown = TestUtils.topicObserved("common-dialog-loaded");
|
||||
return dialogShown.then(function([subject]) {
|
||||
let dialog = subject.Dialog;
|
||||
is(dialog.args.title, "Password Required");
|
||||
dialog.ui.button1.click();
|
||||
});
|
||||
}
|
||||
|
||||
// Test that autocomplete does not trigger a master password prompt
|
||||
// for a certain time after it was cancelled.
|
||||
add_task(function* test_mpAutocompleteTimeout() {
|
||||
let login = LoginTestUtils.testData.formLogin({
|
||||
hostname: "https://example.com",
|
||||
formSubmitURL: "https://example.com",
|
||||
username: "username",
|
||||
password: "password",
|
||||
});
|
||||
Services.logins.addLogin(login);
|
||||
LoginTestUtils.masterPassword.enable();
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
LoginTestUtils.masterPassword.disable();
|
||||
Services.logins.removeAllLogins();
|
||||
});
|
||||
|
||||
// Set master password prompt timeout to 3s.
|
||||
// If this test goes intermittent, you likely have to increase this value.
|
||||
yield SpecialPowers.pushPrefEnv({set: [[TIMEOUT_PREF, 3000]]});
|
||||
|
||||
// Wait for initial master password dialog after opening the tab.
|
||||
let dialogShown = waitForDialog();
|
||||
|
||||
yield BrowserTestUtils.withNewTab(URL, function*(browser) {
|
||||
yield dialogShown;
|
||||
|
||||
yield ContentTask.spawn(browser, null, function*() {
|
||||
// Focus the password field to trigger autocompletion.
|
||||
content.document.getElementById("form-basic-password").focus();
|
||||
});
|
||||
|
||||
// Wait 4s, dialog should not have been shown
|
||||
// (otherwise the code below will not work).
|
||||
yield new Promise((c) => setTimeout(c, 4000));
|
||||
|
||||
dialogShown = waitForDialog();
|
||||
yield ContentTask.spawn(browser, null, function*() {
|
||||
// Re-focus the password field to trigger autocompletion.
|
||||
content.document.getElementById("form-basic-username").focus();
|
||||
content.document.getElementById("form-basic-password").focus();
|
||||
});
|
||||
yield dialogShown;
|
||||
});
|
||||
});
|
||||
@@ -676,10 +676,10 @@ var Bookmarks = Object.freeze({
|
||||
* @resolves once the removal is complete.
|
||||
*/
|
||||
eraseEverything(options = {}) {
|
||||
const folderGuids = [this.toolbarGuid, this.menuGuid, this.unfiledGuid,
|
||||
this.mobileGuid];
|
||||
return PlacesUtils.withConnectionWrapper("Bookmarks.jsm: eraseEverything",
|
||||
db => db.executeTransaction(function* () {
|
||||
const folderGuids = [this.toolbarGuid, this.menuGuid, this.unfiledGuid,
|
||||
this.mobileGuid];
|
||||
yield removeFoldersContents(db, folderGuids, options);
|
||||
const time = PlacesUtils.toPRTime(new Date());
|
||||
const syncChangeDelta =
|
||||
@@ -691,7 +691,7 @@ var Bookmarks = Object.freeze({
|
||||
WHERE id IN (SELECT id FROM moz_bookmarks WHERE guid = :folderGuid )
|
||||
`, { folderGuid, time, syncChangeDelta });
|
||||
}
|
||||
}.bind(this))
|
||||
})
|
||||
);
|
||||
},
|
||||
|
||||
|
||||
@@ -20,6 +20,22 @@ using namespace mozilla::dom;
|
||||
|
||||
static bool
|
||||
IsValidHost(const nsACString& host) {
|
||||
// This is ugly, but Preferences.h doesn't have support
|
||||
// for default prefs or locked prefs
|
||||
nsCOMPtr<nsIPrefService> prefService (do_GetService(NS_PREFSERVICE_CONTRACTID));
|
||||
nsCOMPtr<nsIPrefBranch> prefs;
|
||||
if (prefService) {
|
||||
prefService->GetDefaultBranch(nullptr, getter_AddRefs(prefs));
|
||||
bool isEnabled;
|
||||
if (NS_SUCCEEDED(prefs->GetBoolPref("xpinstall.enabled", &isEnabled)) && !isEnabled) {
|
||||
bool isLocked;
|
||||
prefs->PrefIsLocked("xpinstall.enabled", &isLocked);
|
||||
if (isLocked) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (host.Equals("addons.mozilla.org") ||
|
||||
host.Equals("discovery.addons.mozilla.org") ||
|
||||
host.Equals("testpilot.firefox.com")) {
|
||||
|
||||
+172
-58
@@ -1323,6 +1323,14 @@ TSFTextStore::Init(nsWindowBase* aWidget,
|
||||
("0x%p TSFTextStore::Init(aWidget=0x%p)",
|
||||
this, aWidget));
|
||||
|
||||
if (NS_WARN_IF(!aWidget) || NS_WARN_IF(aWidget->Destroyed())) {
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Error,
|
||||
("0x%p TSFTextStore::Init() FAILED due to being initialized with "
|
||||
"destroyed widget",
|
||||
this));
|
||||
return false;
|
||||
}
|
||||
|
||||
TSFStaticSink::GetInstance()->EnsureInitActiveTIPKeyboard();
|
||||
|
||||
if (mDocumentMgr) {
|
||||
@@ -1332,14 +1340,6 @@ TSFTextStore::Init(nsWindowBase* aWidget,
|
||||
return false;
|
||||
}
|
||||
|
||||
// Create document manager
|
||||
HRESULT hr = sThreadMgr->CreateDocumentMgr(getter_AddRefs(mDocumentMgr));
|
||||
if (FAILED(hr)) {
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Error,
|
||||
("0x%p TSFTextStore::Init() FAILED to create DocumentMgr "
|
||||
"(0x%08X)", this, hr));
|
||||
return false;
|
||||
}
|
||||
mWidget = aWidget;
|
||||
if (NS_WARN_IF(!mWidget)) {
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Error,
|
||||
@@ -1355,30 +1355,62 @@ TSFTextStore::Init(nsWindowBase* aWidget,
|
||||
return false;
|
||||
}
|
||||
|
||||
SetInputScope(aContext.mHTMLInputType, aContext.mHTMLInputInputmode);
|
||||
|
||||
// Create document manager
|
||||
RefPtr<ITfThreadMgr> threadMgr = sThreadMgr;
|
||||
RefPtr<ITfDocumentMgr> documentMgr;
|
||||
HRESULT hr = threadMgr->CreateDocumentMgr(getter_AddRefs(documentMgr));
|
||||
if (NS_WARN_IF(FAILED(hr))) {
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Error,
|
||||
("0x%p TSFTextStore::Init() FAILED to create ITfDocumentMgr "
|
||||
"(0x%08X)", this, hr));
|
||||
return false;
|
||||
}
|
||||
if (NS_WARN_IF(mDestroyed)) {
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Error,
|
||||
("0x%p TSFTextStore::Init() FAILED to create ITfDocumentMgr due to "
|
||||
"TextStore being destroyed during calling "
|
||||
"ITfThreadMgr::CreateDocumentMgr()", this));
|
||||
return false;
|
||||
}
|
||||
// Create context and add it to document manager
|
||||
hr = mDocumentMgr->CreateContext(sClientId, 0,
|
||||
static_cast<ITextStoreACP*>(this),
|
||||
getter_AddRefs(mContext), &mEditCookie);
|
||||
if (FAILED(hr)) {
|
||||
RefPtr<ITfContext> context;
|
||||
hr = documentMgr->CreateContext(sClientId, 0,
|
||||
static_cast<ITextStoreACP*>(this),
|
||||
getter_AddRefs(context), &mEditCookie);
|
||||
if (NS_WARN_IF(FAILED(hr))) {
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Error,
|
||||
("0x%p TSFTextStore::Init() FAILED to create the context "
|
||||
"(0x%08X)", this, hr));
|
||||
mDocumentMgr = nullptr;
|
||||
return false;
|
||||
}
|
||||
if (NS_WARN_IF(mDestroyed)) {
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Error,
|
||||
("0x%p TSFTextStore::Init() FAILED to create ITfContext due to "
|
||||
"TextStore being destroyed during calling "
|
||||
"ITfDocumentMgr::CreateContext()", this));
|
||||
return false;
|
||||
}
|
||||
|
||||
SetInputScope(aContext.mHTMLInputType, aContext.mHTMLInputInputmode);
|
||||
|
||||
hr = mDocumentMgr->Push(mContext);
|
||||
if (FAILED(hr)) {
|
||||
hr = documentMgr->Push(context);
|
||||
if (NS_WARN_IF(FAILED(hr))) {
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Error,
|
||||
("0x%p TSFTextStore::Init() FAILED to push the context (0x%08X)",
|
||||
this, hr));
|
||||
// XXX Why don't we use NS_IF_RELEASE() here??
|
||||
mContext = nullptr;
|
||||
mDocumentMgr = nullptr;
|
||||
return false;
|
||||
}
|
||||
if (NS_WARN_IF(mDestroyed)) {
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Error,
|
||||
("0x%p TSFTextStore::Init() FAILED to create ITfContext due to "
|
||||
"TextStore being destroyed during calling ITfDocumentMgr::Push()",
|
||||
this));
|
||||
documentMgr->Pop(TF_POPF_ALL);
|
||||
return false;
|
||||
}
|
||||
|
||||
mDocumentMgr = documentMgr;
|
||||
mContext = context;
|
||||
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Info,
|
||||
("0x%p TSFTextStore::Init() succeeded: "
|
||||
@@ -1428,7 +1460,8 @@ TSFTextStore::Destroy()
|
||||
("0x%p TSFTextStore::Destroy(), calling "
|
||||
"ITextStoreACPSink::OnLayoutChange(TS_LC_DESTROY)...",
|
||||
this));
|
||||
mSink->OnLayoutChange(TS_LC_DESTROY, TEXTSTORE_DEFAULT_VIEW);
|
||||
RefPtr<ITextStoreACPSink> sink = mSink;
|
||||
sink->OnLayoutChange(TS_LC_DESTROY, TEXTSTORE_DEFAULT_VIEW);
|
||||
}
|
||||
|
||||
// If this is called during handling a keydown or keyup message, we should
|
||||
@@ -1452,8 +1485,8 @@ TSFTextStore::ReleaseTSFObjects()
|
||||
|
||||
mContext = nullptr;
|
||||
if (mDocumentMgr) {
|
||||
mDocumentMgr->Pop(TF_POPF_ALL);
|
||||
mDocumentMgr = nullptr;
|
||||
RefPtr<ITfDocumentMgr> documentMgr = mDocumentMgr.forget();
|
||||
documentMgr->Pop(TF_POPF_ALL);
|
||||
}
|
||||
mSink = nullptr;
|
||||
mWidget = nullptr;
|
||||
@@ -1620,7 +1653,8 @@ TSFTextStore::RequestLock(DWORD dwLockFlags,
|
||||
// Don't release this instance during this lock because this is called by
|
||||
// TSF but they don't grab us during this call.
|
||||
RefPtr<TSFTextStore> kungFuDeathGrip(this);
|
||||
*phrSession = mSink->OnLockGranted(mLock);
|
||||
RefPtr<ITextStoreACPSink> sink = mSink;
|
||||
*phrSession = sink->OnLockGranted(mLock);
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Info,
|
||||
("0x%p Unlocked (%s) <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
|
||||
"<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<",
|
||||
@@ -1633,7 +1667,7 @@ TSFTextStore::RequestLock(DWORD dwLockFlags,
|
||||
("0x%p Locking for the request in the queue (%s) >>>>>>>>>>>>>>"
|
||||
">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>",
|
||||
this, GetLockFlagNameStr(mLock).get()));
|
||||
mSink->OnLockGranted(mLock);
|
||||
sink->OnLockGranted(mLock);
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Info,
|
||||
("0x%p Unlocked (%s) <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
|
||||
"<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<",
|
||||
@@ -1957,6 +1991,8 @@ TSFTextStore::MaybeFlushPendingNotifications()
|
||||
|
||||
// When there is no cached content, we can sync actual contents and TSF/TIP
|
||||
// expecting contents.
|
||||
RefPtr<TSFTextStore> kungFuDeathGrip = this;
|
||||
Unused << kungFuDeathGrip;
|
||||
if (!mContentForTSF.IsInitialized()) {
|
||||
if (mPendingTextChangeData.IsValid()) {
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Info,
|
||||
@@ -4717,29 +4753,47 @@ TSFTextStore::OnFocusChange(bool aGotFocus,
|
||||
}
|
||||
|
||||
RefPtr<ITfDocumentMgr> prevFocusedDocumentMgr;
|
||||
RefPtr<TSFTextStore> oldTextStore = sEnabledTextStore.forget();
|
||||
|
||||
// If currently sEnableTextStore has focus, notifies TSF of losing focus.
|
||||
if (ThinksHavingFocus()) {
|
||||
RefPtr<ITfThreadMgr> threadMgr = sThreadMgr;
|
||||
DebugOnly<HRESULT> hr =
|
||||
sThreadMgr->AssociateFocus(
|
||||
sEnabledTextStore->mWidget->GetWindowHandle(),
|
||||
threadMgr->AssociateFocus(
|
||||
oldTextStore->mWidget->GetWindowHandle(),
|
||||
nullptr, getter_AddRefs(prevFocusedDocumentMgr));
|
||||
NS_ASSERTION(SUCCEEDED(hr), "Disassociating focus failed");
|
||||
NS_ASSERTION(prevFocusedDocumentMgr == sEnabledTextStore->mDocumentMgr,
|
||||
NS_ASSERTION(prevFocusedDocumentMgr == oldTextStore->mDocumentMgr,
|
||||
"different documentMgr has been associated with the window");
|
||||
}
|
||||
|
||||
// If there is sEnabledTextStore, we don't use it in the new focused editor.
|
||||
// Release it now.
|
||||
if (sEnabledTextStore) {
|
||||
sEnabledTextStore->Destroy();
|
||||
sEnabledTextStore = nullptr;
|
||||
if (oldTextStore) {
|
||||
oldTextStore->Destroy();
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!sThreadMgr)) {
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Error,
|
||||
(" TSFTextStore::OnFocusChange() FAILED, due to "
|
||||
"sThreadMgr being destroyed during calling "
|
||||
"ITfThreadMgr::AssociateFocus()"));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if (NS_WARN_IF(sEnabledTextStore)) {
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Error,
|
||||
(" TSFTextStore::OnFocusChange() FAILED, due to "
|
||||
"nested event handling has created another focused TextStore during "
|
||||
"calling ITfThreadMgr::AssociateFocus()"));
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
// If this is a notification of blur, move focus to the dummy document
|
||||
// manager.
|
||||
if (!aGotFocus || !aContext.mIMEState.IsEditable()) {
|
||||
HRESULT hr = sThreadMgr->SetFocus(sDisabledDocumentMgr);
|
||||
RefPtr<ITfThreadMgr> threadMgr = sThreadMgr;
|
||||
RefPtr<ITfDocumentMgr> disabledDocumentMgr = sDisabledDocumentMgr;
|
||||
HRESULT hr = threadMgr->SetFocus(disabledDocumentMgr);
|
||||
if (NS_WARN_IF(FAILED(hr))) {
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Error,
|
||||
(" TSFTextStore::OnFocusChange() FAILED due to "
|
||||
@@ -4754,17 +4808,23 @@ TSFTextStore::OnFocusChange(bool aGotFocus,
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Error,
|
||||
(" TSFTextStore::OnFocusChange() FAILED due to "
|
||||
"ITfThreadMgr::CreateAndSetFocus() failure"));
|
||||
// If setting focus, we should destroy the TextStore completely because
|
||||
// it causes memory leak.
|
||||
if (sEnabledTextStore) {
|
||||
sEnabledTextStore->Destroy();
|
||||
sEnabledTextStore = nullptr;
|
||||
}
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
TSFTextStore::EnsureToDestroyAndReleaseEnabledTextStoreIf(
|
||||
RefPtr<TSFTextStore>& aTextStore)
|
||||
{
|
||||
aTextStore->Destroy();
|
||||
if (sEnabledTextStore == aTextStore) {
|
||||
sEnabledTextStore = nullptr;
|
||||
}
|
||||
aTextStore = nullptr;
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
TSFTextStore::CreateAndSetFocus(nsWindowBase* aFocusedWidget,
|
||||
@@ -4779,49 +4839,87 @@ TSFTextStore::CreateAndSetFocus(nsWindowBase* aFocusedWidget,
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Error,
|
||||
(" TSFTextStore::CreateAndSetFocus() FAILED due to "
|
||||
"TSFTextStore::Init() failure"));
|
||||
EnsureToDestroyAndReleaseEnabledTextStoreIf(textStore);
|
||||
return false;
|
||||
}
|
||||
if (NS_WARN_IF(!textStore->mDocumentMgr)) {
|
||||
RefPtr<ITfDocumentMgr> newDocMgr = textStore->mDocumentMgr;
|
||||
if (NS_WARN_IF(!newDocMgr)) {
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Error,
|
||||
(" TSFTextStore::CreateAndSetFocus() FAILED due to "
|
||||
"invalid TSFTextStore::mDocumentMgr"));
|
||||
EnsureToDestroyAndReleaseEnabledTextStoreIf(textStore);
|
||||
return false;
|
||||
}
|
||||
if (aContext.mIMEState.mEnabled == IMEState::PASSWORD) {
|
||||
MarkContextAsKeyboardDisabled(textStore->mContext);
|
||||
RefPtr<ITfContext> topContext;
|
||||
textStore->mDocumentMgr->GetTop(getter_AddRefs(topContext));
|
||||
newDocMgr->GetTop(getter_AddRefs(topContext));
|
||||
if (topContext && topContext != textStore->mContext) {
|
||||
MarkContextAsKeyboardDisabled(topContext);
|
||||
}
|
||||
}
|
||||
|
||||
HRESULT hr;
|
||||
RefPtr<ITfThreadMgr> threadMgr = sThreadMgr;
|
||||
{
|
||||
// Windows 10's softwware keyboard requires that SetSelection must be
|
||||
// always successful into SetFocus. If returning error, it might crash
|
||||
// into TextInputFramework.dll.
|
||||
AutoSetTemporarySelection setSelection(textStore->SelectionForTSFRef());
|
||||
|
||||
hr = sThreadMgr->SetFocus(textStore->mDocumentMgr);
|
||||
hr = threadMgr->SetFocus(newDocMgr);
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(FAILED(hr))) {
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Error,
|
||||
(" TSFTextStore::CreateAndSetFocus() FAILED due to "
|
||||
"ITfTheadMgr::SetFocus() failure"));
|
||||
EnsureToDestroyAndReleaseEnabledTextStoreIf(textStore);
|
||||
return false;
|
||||
}
|
||||
if (NS_WARN_IF(!sThreadMgr)) {
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Error,
|
||||
(" TSFTextStore::CreateAndSetFocus() FAILED due to "
|
||||
"sThreadMgr being destroyed during calling "
|
||||
"ITfTheadMgr::SetFocus()"));
|
||||
EnsureToDestroyAndReleaseEnabledTextStoreIf(textStore);
|
||||
return false;
|
||||
}
|
||||
if (NS_WARN_IF(sEnabledTextStore != textStore)) {
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Error,
|
||||
(" TSFTextStore::CreateAndSetFocus() FAILED due to "
|
||||
"creating TextStore has lost focus during calling "
|
||||
"ITfThreadMgr::SetFocus()"));
|
||||
EnsureToDestroyAndReleaseEnabledTextStoreIf(textStore);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Use AssociateFocus() for ensuring that any native focus event
|
||||
// never steal focus from our documentMgr.
|
||||
RefPtr<ITfDocumentMgr> prevFocusedDocumentMgr;
|
||||
hr = sThreadMgr->AssociateFocus(aFocusedWidget->GetWindowHandle(),
|
||||
textStore->mDocumentMgr,
|
||||
getter_AddRefs(prevFocusedDocumentMgr));
|
||||
hr = threadMgr->AssociateFocus(aFocusedWidget->GetWindowHandle(), newDocMgr,
|
||||
getter_AddRefs(prevFocusedDocumentMgr));
|
||||
if (NS_WARN_IF(FAILED(hr))) {
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Error,
|
||||
(" TSFTextStore::CreateAndSetFocus() FAILED due to "
|
||||
"ITfTheadMgr::AssociateFocus() failure"));
|
||||
EnsureToDestroyAndReleaseEnabledTextStoreIf(textStore);
|
||||
return false;
|
||||
}
|
||||
if (NS_WARN_IF(!sThreadMgr)) {
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Error,
|
||||
(" TSFTextStore::CreateAndSetFocus() FAILED due to "
|
||||
"sThreadMgr being destroyed during calling "
|
||||
"ITfTheadMgr::AssociateFocus()"));
|
||||
EnsureToDestroyAndReleaseEnabledTextStoreIf(textStore);
|
||||
return false;
|
||||
}
|
||||
if (NS_WARN_IF(sEnabledTextStore != textStore)) {
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Error,
|
||||
(" TSFTextStore::CreateAndSetFocus() FAILED due to "
|
||||
"creating TextStore has lost focus during calling "
|
||||
"ITfTheadMgr::AssociateFocus()"));
|
||||
EnsureToDestroyAndReleaseEnabledTextStoreIf(textStore);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -4830,7 +4928,16 @@ TSFTextStore::CreateAndSetFocus(nsWindowBase* aFocusedWidget,
|
||||
(" TSFTextStore::CreateAndSetFocus(), calling "
|
||||
"ITextStoreACPSink::OnLayoutChange(TS_LC_CREATE) for 0x%p...",
|
||||
textStore.get()));
|
||||
textStore->mSink->OnLayoutChange(TS_LC_CREATE, TEXTSTORE_DEFAULT_VIEW);
|
||||
RefPtr<ITextStoreACPSink> sink = textStore->mSink;
|
||||
sink->OnLayoutChange(TS_LC_CREATE, TEXTSTORE_DEFAULT_VIEW);
|
||||
if (NS_WARN_IF(sEnabledTextStore != textStore)) {
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Error,
|
||||
(" TSFTextStore::CreateAndSetFocus() FAILED due to "
|
||||
"creating TextStore has lost focus during calling "
|
||||
"ITextStoreACPSink::OnLayoutChange(TS_LC_CREATE)"));
|
||||
EnsureToDestroyAndReleaseEnabledTextStoreIf(textStore);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -4955,7 +5062,8 @@ TSFTextStore::NotifyTSFOfTextChange()
|
||||
"ITextStoreACPSink::OnTextChange(0, { acpStart=%ld, acpOldEnd=%ld, "
|
||||
"acpNewEnd=%ld })...", this, textChange.acpStart,
|
||||
textChange.acpOldEnd, textChange.acpNewEnd));
|
||||
mSink->OnTextChange(0, &textChange);
|
||||
RefPtr<ITextStoreACPSink> sink = mSink;
|
||||
sink->OnTextChange(0, &textChange);
|
||||
}
|
||||
|
||||
nsresult
|
||||
@@ -5034,7 +5142,8 @@ TSFTextStore::NotifyTSFOfSelectionChange()
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Info,
|
||||
("0x%p TSFTextStore::NotifyTSFOfSelectionChange(), calling "
|
||||
"ITextStoreACPSink::OnSelectionChange()...", this));
|
||||
mSink->OnSelectionChange();
|
||||
RefPtr<ITextStoreACPSink> sink = mSink;
|
||||
sink->OnSelectionChange();
|
||||
}
|
||||
|
||||
nsresult
|
||||
@@ -5106,7 +5215,8 @@ TSFTextStore::NotifyTSFOfLayoutChange()
|
||||
("0x%p TSFTextStore::NotifyTSFOfLayoutChange(), "
|
||||
"calling ITextStoreACPSink::OnLayoutChange()...",
|
||||
this));
|
||||
HRESULT hr = mSink->OnLayoutChange(TS_LC_CHANGE, TEXTSTORE_DEFAULT_VIEW);
|
||||
RefPtr<ITextStoreACPSink> sink = mSink;
|
||||
HRESULT hr = sink->OnLayoutChange(TS_LC_CHANGE, TEXTSTORE_DEFAULT_VIEW);
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Info,
|
||||
("0x%p TSFTextStore::NotifyTSFOfLayoutChange(), "
|
||||
"called ITextStoreACPSink::OnLayoutChange()",
|
||||
@@ -5466,7 +5576,8 @@ TSFTextStore::CommitCompositionInternal(bool aDiscard)
|
||||
"mSink->OnTextChange(0, { acpStart=%ld, acpOldEnd=%ld, "
|
||||
"acpNewEnd=%ld })...", this, textChange.acpStart,
|
||||
textChange.acpOldEnd, textChange.acpNewEnd));
|
||||
mSink->OnTextChange(0, &textChange);
|
||||
RefPtr<ITextStoreACPSink> sink = mSink;
|
||||
sink->OnTextChange(0, &textChange);
|
||||
}
|
||||
}
|
||||
// Terminate two contexts, the base context (mContext) and the top
|
||||
@@ -5869,35 +5980,37 @@ TSFTextStore::ProcessRawKeyMessage(const MSG& aMsg)
|
||||
|
||||
if (aMsg.message == WM_KEYDOWN) {
|
||||
BOOL eaten;
|
||||
HRESULT hr = sKeystrokeMgr->TestKeyDown(aMsg.wParam, aMsg.lParam, &eaten);
|
||||
if (FAILED(hr) || !eaten) {
|
||||
RefPtr<ITfKeystrokeMgr> keystrokeMgr = sKeystrokeMgr;
|
||||
HRESULT hr = keystrokeMgr->TestKeyDown(aMsg.wParam, aMsg.lParam, &eaten);
|
||||
if (FAILED(hr) || !sKeystrokeMgr || !eaten) {
|
||||
return false;
|
||||
}
|
||||
RefPtr<TSFTextStore> textStore(sEnabledTextStore);
|
||||
if (textStore) {
|
||||
textStore->OnStartToHandleKeyMessage();
|
||||
}
|
||||
hr = sKeystrokeMgr->KeyDown(aMsg.wParam, aMsg.lParam, &eaten);
|
||||
hr = keystrokeMgr->KeyDown(aMsg.wParam, aMsg.lParam, &eaten);
|
||||
if (textStore) {
|
||||
textStore->OnEndHandlingKeyMessage();
|
||||
}
|
||||
return SUCCEEDED(hr) && eaten;
|
||||
return SUCCEEDED(hr) && (eaten || !sKeystrokeMgr);
|
||||
}
|
||||
if (aMsg.message == WM_KEYUP) {
|
||||
BOOL eaten;
|
||||
HRESULT hr = sKeystrokeMgr->TestKeyUp(aMsg.wParam, aMsg.lParam, &eaten);
|
||||
if (FAILED(hr) || !eaten) {
|
||||
RefPtr<ITfKeystrokeMgr> keystrokeMgr = sKeystrokeMgr;
|
||||
HRESULT hr = keystrokeMgr->TestKeyUp(aMsg.wParam, aMsg.lParam, &eaten);
|
||||
if (FAILED(hr) || !sKeystrokeMgr || !eaten) {
|
||||
return false;
|
||||
}
|
||||
RefPtr<TSFTextStore> textStore(sEnabledTextStore);
|
||||
if (textStore) {
|
||||
textStore->OnStartToHandleKeyMessage();
|
||||
}
|
||||
hr = sKeystrokeMgr->KeyUp(aMsg.wParam, aMsg.lParam, &eaten);
|
||||
hr = keystrokeMgr->KeyUp(aMsg.wParam, aMsg.lParam, &eaten);
|
||||
if (textStore) {
|
||||
textStore->OnEndHandlingKeyMessage();
|
||||
}
|
||||
return SUCCEEDED(hr) && eaten;
|
||||
return SUCCEEDED(hr) && (eaten || !sKeystrokeMgr);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -6254,7 +6367,8 @@ TSFTextStore::MouseTracker::OnMouseButtonEvent(ULONG aEdge,
|
||||
MOZ_ASSERT(IsUsing(), "The caller must check before calling OnMouseEvent()");
|
||||
|
||||
BOOL eaten = FALSE;
|
||||
HRESULT hr = mSink->OnMouseEvent(aEdge, aQuadrant, aButtonStatus, &eaten);
|
||||
RefPtr<ITfMouseSink> sink = mSink;
|
||||
HRESULT hr = sink->OnMouseEvent(aEdge, aQuadrant, aButtonStatus, &eaten);
|
||||
|
||||
MOZ_LOG(sTextStoreLog, LogLevel::Debug,
|
||||
("0x%p TSFTextStore::MouseTracker::OnMouseEvent(aEdge=%d, "
|
||||
|
||||
@@ -264,6 +264,8 @@ protected:
|
||||
|
||||
static bool CreateAndSetFocus(nsWindowBase* aFocusedWidget,
|
||||
const InputContext& aContext);
|
||||
static void EnsureToDestroyAndReleaseEnabledTextStoreIf(
|
||||
RefPtr<TSFTextStore>& aTextStore);
|
||||
static void MarkContextAsKeyboardDisabled(ITfContext* aContext);
|
||||
static void MarkContextAsEmpty(ITfContext* aContext);
|
||||
|
||||
|
||||
@@ -723,7 +723,7 @@ WinUtils::PeekMessage(LPMSG aMsg, HWND aWnd, UINT aFirstMessage,
|
||||
}
|
||||
#endif
|
||||
#ifdef NS_ENABLE_TSF
|
||||
ITfMessagePump* msgPump = TSFTextStore::GetMessagePump();
|
||||
RefPtr<ITfMessagePump> msgPump = TSFTextStore::GetMessagePump();
|
||||
if (msgPump) {
|
||||
BOOL ret = FALSE;
|
||||
HRESULT hr = msgPump->PeekMessageW(aMsg, aWnd, aFirstMessage, aLastMessage,
|
||||
@@ -741,7 +741,7 @@ WinUtils::GetMessage(LPMSG aMsg, HWND aWnd, UINT aFirstMessage,
|
||||
UINT aLastMessage)
|
||||
{
|
||||
#ifdef NS_ENABLE_TSF
|
||||
ITfMessagePump* msgPump = TSFTextStore::GetMessagePump();
|
||||
RefPtr<ITfMessagePump> msgPump = TSFTextStore::GetMessagePump();
|
||||
if (msgPump) {
|
||||
BOOL ret = FALSE;
|
||||
HRESULT hr = msgPump->GetMessageW(aMsg, aWnd, aFirstMessage, aLastMessage,
|
||||
|
||||
Reference in New Issue
Block a user