mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 15:52:07 +00:00
Merge m-c to fx-team. a=merge
This commit is contained in:
commit
d75108d3fe
@ -255,8 +255,8 @@ nsAccUtils::TableFor(Accessible* aRow)
|
||||
tableRole = table->Role();
|
||||
}
|
||||
|
||||
return tableRole == roles::TABLE || tableRole == roles::TREE_TABLE ?
|
||||
table : nullptr;
|
||||
return (tableRole == roles::TABLE || tableRole == roles::TREE_TABLE ||
|
||||
tableRole == roles::MATHML_TABLE) ? table : nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -823,6 +823,8 @@ ConvertToNSArray(nsTArray<Accessible*>& aArray)
|
||||
return @"AXMathSubscriptSuperscript";
|
||||
|
||||
case roles::MATHML_ROW:
|
||||
case roles::MATHML_STYLE:
|
||||
case roles::MATHML_ERROR:
|
||||
return @"AXMathRow";
|
||||
|
||||
case roles::MATHML_UNDER:
|
||||
|
@ -6,6 +6,8 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
window.performance.mark('gecko-settings-loadstart');
|
||||
|
||||
const Cc = Components.classes;
|
||||
const Ci = Components.interfaces;
|
||||
const Cu = Components.utils;
|
||||
|
@ -16,7 +16,10 @@
|
||||
#ifdef FXOS_SIMULATOR
|
||||
<link rel="stylesheet" href="desktop.css" type="text/css">
|
||||
#endif
|
||||
|
||||
<script type="text/javascript">
|
||||
<!-- Add raptor performance marker -->
|
||||
window.performance.mark('gecko-shell-html-load');
|
||||
</script>
|
||||
<script type="application/javascript;version=1.8"
|
||||
src="chrome://b2g/content/settings.js"> </script>
|
||||
<script type="application/javascript;version=1.8"
|
||||
|
@ -4,6 +4,8 @@
|
||||
* 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/. */
|
||||
|
||||
window.performance.mark('gecko-shell-loadstart');
|
||||
|
||||
Cu.import('resource://gre/modules/ContactService.jsm');
|
||||
Cu.import('resource://gre/modules/DataStoreChangeNotifier.jsm');
|
||||
Cu.import('resource://gre/modules/AlarmService.jsm');
|
||||
@ -75,6 +77,8 @@ XPCOMUtils.defineLazyModuleGetter(this, "SafeBrowsing",
|
||||
"resource://gre/modules/SafeBrowsing.jsm");
|
||||
#endif
|
||||
|
||||
window.performance.measure('gecko-shell-jsm-loaded', 'gecko-shell-loadstart');
|
||||
|
||||
function getContentWindow() {
|
||||
return shell.contentBrowser.contentWindow;
|
||||
}
|
||||
@ -228,6 +232,7 @@ var shell = {
|
||||
},
|
||||
|
||||
bootstrap: function() {
|
||||
window.performance.mark('gecko-shell-bootstrap');
|
||||
let startManifestURL =
|
||||
Cc['@mozilla.org/commandlinehandler/general-startup;1?type=b2gbootstrap']
|
||||
.getService(Ci.nsISupports).wrappedJSObject.startManifestURL;
|
||||
@ -242,6 +247,7 @@ var shell = {
|
||||
},
|
||||
|
||||
start: function shell_start() {
|
||||
window.performance.mark('gecko-shell-start');
|
||||
this._started = true;
|
||||
|
||||
// This forces the initialization of the cookie service before we hit the
|
||||
@ -372,6 +378,8 @@ var shell = {
|
||||
this.contentBrowser.src = homeURL;
|
||||
this.isHomeLoaded = false;
|
||||
|
||||
window.performance.mark('gecko-shell-system-frame-set');
|
||||
|
||||
ppmm.addMessageListener("content-handler", this);
|
||||
ppmm.addMessageListener("dial-handler", this);
|
||||
ppmm.addMessageListener("sms-handler", this);
|
||||
@ -647,6 +655,7 @@ var shell = {
|
||||
},
|
||||
|
||||
notifyContentStart: function shell_notifyContentStart() {
|
||||
window.performance.mark('gecko-shell-notify-content-start');
|
||||
this.contentBrowser.removeEventListener('mozbrowserloadstart', this, true);
|
||||
this.contentBrowser.removeEventListener('mozbrowserlocationchange', this, true);
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="26b853b7cf94ea9e9ac6f20c55db462bd213a959"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="858764a56982eb558259ccc689bbee855f090085"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="26b853b7cf94ea9e9ac6f20c55db462bd213a959"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="858764a56982eb558259ccc689bbee855f090085"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="26b853b7cf94ea9e9ac6f20c55db462bd213a959"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="858764a56982eb558259ccc689bbee855f090085"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="87a2d8ab9248540910e56921654367b78a587095"/>
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="26b853b7cf94ea9e9ac6f20c55db462bd213a959"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="858764a56982eb558259ccc689bbee855f090085"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="49192a4e48d080e44a0d66f059e6897f07cf67f8"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="26b853b7cf94ea9e9ac6f20c55db462bd213a959"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="858764a56982eb558259ccc689bbee855f090085"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="26b853b7cf94ea9e9ac6f20c55db462bd213a959"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="858764a56982eb558259ccc689bbee855f090085"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -19,7 +19,7 @@
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="fake-dalvik" path="dalvik" remote="b2g" revision="ca1f327d5acc198bb4be62fa51db2c039032c9ce"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="26b853b7cf94ea9e9ac6f20c55db462bd213a959"/>
|
||||
<project name="gaia.git" path="gaia" remote="mozillaorg" revision="858764a56982eb558259ccc689bbee855f090085"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="platform_hardware_ril" path="hardware/ril" remote="b2g" revision="87a2d8ab9248540910e56921654367b78a587095"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="e862ab9177af664f00b4522e2350f4cb13866d73">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="26b853b7cf94ea9e9ac6f20c55db462bd213a959"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="858764a56982eb558259ccc689bbee855f090085"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -1,9 +1,9 @@
|
||||
{
|
||||
"git": {
|
||||
"git_revision": "26b853b7cf94ea9e9ac6f20c55db462bd213a959",
|
||||
"git_revision": "858764a56982eb558259ccc689bbee855f090085",
|
||||
"remote": "https://git.mozilla.org/releases/gaia.git",
|
||||
"branch": ""
|
||||
},
|
||||
"revision": "f7729852bdfb3f7051829e28463868a151c8ae62",
|
||||
"revision": "d43e6298ab2fc2d3033dac41d38138f9117ab9d3",
|
||||
"repo_path": "integration/gaia-central"
|
||||
}
|
||||
|
@ -17,7 +17,7 @@
|
||||
</project>
|
||||
<project name="rilproxy" path="rilproxy" remote="b2g" revision="5ef30994f4778b4052e58a4383dbe7890048c87e"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="26b853b7cf94ea9e9ac6f20c55db462bd213a959"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="858764a56982eb558259ccc689bbee855f090085"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
|
||||
<project name="moztt" path="external/moztt" remote="b2g" revision="46da1a05ac04157669685246d70ac59d48699c9e"/>
|
||||
<project name="apitrace" path="external/apitrace" remote="apitrace" revision="49192a4e48d080e44a0d66f059e6897f07cf67f8"/>
|
||||
|
@ -15,7 +15,7 @@
|
||||
<project name="platform_build" path="build" remote="b2g" revision="61e82f99bb8bc78d52b5717e9a2481ec7267fa33">
|
||||
<copyfile dest="Makefile" src="core/root.mk"/>
|
||||
</project>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="26b853b7cf94ea9e9ac6f20c55db462bd213a959"/>
|
||||
<project name="gaia" path="gaia" remote="mozillaorg" revision="858764a56982eb558259ccc689bbee855f090085"/>
|
||||
<project name="fake-libdvm" path="dalvik" remote="b2g" revision="d50ae982b19f42f0b66d08b9eb306be81687869f"/>
|
||||
<project name="gonk-misc" path="gonk-misc" remote="b2g" revision="3477513bcd385571aa01c0d074849e35bd5e2376"/>
|
||||
<project name="librecovery" path="librecovery" remote="b2g" revision="1b3591a50ed352fc6ddb77462b7b35d0bfa555a3"/>
|
||||
|
@ -23,42 +23,42 @@ AUTOMATION_UPLOAD_OUTPUT = $(DIST)/automation-upload.txt
|
||||
|
||||
# Helper variables to convert from MOZ_AUTOMATION_* variables to the
|
||||
# corresponding the make target
|
||||
tier_BUILD_SYMBOLS = buildsymbols
|
||||
tier_L10N_CHECK = l10n-check
|
||||
tier_PRETTY_L10N_CHECK = pretty-l10n-check
|
||||
tier_INSTALLER = installer
|
||||
tier_PRETTY_INSTALLER = pretty-installer
|
||||
tier_PACKAGE = package
|
||||
tier_PRETTY_PACKAGE = pretty-package
|
||||
tier_PACKAGE_TESTS = package-tests
|
||||
tier_PRETTY_PACKAGE_TESTS = pretty-package-tests
|
||||
tier_UPDATE_PACKAGING = update-packaging
|
||||
tier_PRETTY_UPDATE_PACKAGING = pretty-update-packaging
|
||||
tier_UPLOAD_SYMBOLS = uploadsymbols
|
||||
tier_UPLOAD = upload
|
||||
tier_SDK = sdk
|
||||
tier_MOZ_AUTOMATION_BUILD_SYMBOLS = buildsymbols
|
||||
tier_MOZ_AUTOMATION_L10N_CHECK = l10n-check
|
||||
tier_MOZ_AUTOMATION_PRETTY_L10N_CHECK = pretty-l10n-check
|
||||
tier_MOZ_AUTOMATION_INSTALLER = installer
|
||||
tier_MOZ_AUTOMATION_PRETTY_INSTALLER = pretty-installer
|
||||
tier_MOZ_AUTOMATION_PACKAGE = package
|
||||
tier_MOZ_AUTOMATION_PRETTY_PACKAGE = pretty-package
|
||||
tier_MOZ_AUTOMATION_PACKAGE_TESTS = package-tests
|
||||
tier_MOZ_AUTOMATION_PRETTY_PACKAGE_TESTS = pretty-package-tests
|
||||
tier_MOZ_AUTOMATION_UPDATE_PACKAGING = update-packaging
|
||||
tier_MOZ_AUTOMATION_PRETTY_UPDATE_PACKAGING = pretty-update-packaging
|
||||
tier_MOZ_AUTOMATION_UPLOAD_SYMBOLS = uploadsymbols
|
||||
tier_MOZ_AUTOMATION_UPLOAD = upload
|
||||
tier_MOZ_AUTOMATION_SDK = sdk
|
||||
|
||||
# Automation build steps. Everything in MOZ_AUTOMATION_TIERS also gets used in
|
||||
# TIERS for mach display. As such, the MOZ_AUTOMATION_TIERS are roughly sorted
|
||||
# here in the order that they will be executed (since mach doesn't know of the
|
||||
# dependencies between them).
|
||||
moz_automation_symbols = \
|
||||
PACKAGE_TESTS \
|
||||
PRETTY_PACKAGE_TESTS \
|
||||
BUILD_SYMBOLS \
|
||||
UPLOAD_SYMBOLS \
|
||||
PACKAGE \
|
||||
PRETTY_PACKAGE \
|
||||
INSTALLER \
|
||||
PRETTY_INSTALLER \
|
||||
UPDATE_PACKAGING \
|
||||
PRETTY_UPDATE_PACKAGING \
|
||||
L10N_CHECK \
|
||||
PRETTY_L10N_CHECK \
|
||||
UPLOAD \
|
||||
SDK \
|
||||
MOZ_AUTOMATION_PACKAGE_TESTS \
|
||||
MOZ_AUTOMATION_PRETTY_PACKAGE_TESTS \
|
||||
MOZ_AUTOMATION_BUILD_SYMBOLS \
|
||||
MOZ_AUTOMATION_UPLOAD_SYMBOLS \
|
||||
MOZ_AUTOMATION_PACKAGE \
|
||||
MOZ_AUTOMATION_PRETTY_PACKAGE \
|
||||
MOZ_AUTOMATION_INSTALLER \
|
||||
MOZ_AUTOMATION_PRETTY_INSTALLER \
|
||||
MOZ_AUTOMATION_UPDATE_PACKAGING \
|
||||
MOZ_AUTOMATION_PRETTY_UPDATE_PACKAGING \
|
||||
MOZ_AUTOMATION_L10N_CHECK \
|
||||
MOZ_AUTOMATION_PRETTY_L10N_CHECK \
|
||||
MOZ_AUTOMATION_UPLOAD \
|
||||
MOZ_AUTOMATION_SDK \
|
||||
$(NULL)
|
||||
MOZ_AUTOMATION_TIERS := $(foreach sym,$(moz_automation_symbols),$(if $(filter 1,$(MOZ_AUTOMATION_$(sym))),$(tier_$(sym))))
|
||||
MOZ_AUTOMATION_TIERS := $(foreach sym,$(moz_automation_symbols),$(if $(filter 1,$($(sym))),$(tier_$(sym))))
|
||||
|
||||
# Dependencies between automation build steps
|
||||
automation/uploadsymbols: automation/buildsymbols
|
||||
@ -119,10 +119,14 @@ AUTOMATION_EXTRA_CMDLINE-pretty-package-tests = -j1
|
||||
# However, the target automation/buildsymbols will still be executed in this
|
||||
# case because it is a prerequisite of automation/upload.
|
||||
define automation_commands
|
||||
$(call BUILDSTATUS,TIER_START $1)
|
||||
@$(MAKE) $1 $(AUTOMATION_EXTRA_CMDLINE-$1)
|
||||
$(call BUILDSTATUS,TIER_FINISH $1)
|
||||
endef
|
||||
|
||||
automation/%:
|
||||
# The tier start message is in a separate target so make doesn't buffer it
|
||||
# until the step completes with output syncing enabled.
|
||||
automation-start/%:
|
||||
$(if $(filter $*,$(MOZ_AUTOMATION_TIERS)),$(call BUILDSTATUS,TIER_START $*))
|
||||
|
||||
automation/%: automation-start/%
|
||||
$(if $(filter $*,$(MOZ_AUTOMATION_TIERS)),$(call automation_commands,$*))
|
||||
|
@ -499,7 +499,14 @@ function runTest() {
|
||||
var chromeDoc = SpecialPowers.wrap(document);
|
||||
ok(chromeDoc.documentURI.indexOf("pushStateTest") > -1);
|
||||
|
||||
SimpleTest.executeSoon(function() { gen.next(); });
|
||||
|
||||
yield undefined;
|
||||
|
||||
history.back();
|
||||
SimpleTest.executeSoon(function() { gen.next(); });
|
||||
|
||||
yield undefined;
|
||||
|
||||
SimpleTest.finish();
|
||||
SpecialPowers.removePermission("systemXHR", document);
|
||||
|
@ -8,6 +8,7 @@
|
||||
#include "mozilla/IMEStateManager.h"
|
||||
#include "mozilla/TextEvents.h"
|
||||
#include "mozilla/dom/Element.h"
|
||||
#include "mozilla/dom/Selection.h"
|
||||
#include "nsCaret.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsContentUtils.h"
|
||||
@ -19,8 +20,6 @@
|
||||
#include "nsIPresShell.h"
|
||||
#include "nsISelection.h"
|
||||
#include "nsISelectionController.h"
|
||||
#include "nsISelectionPrivate.h"
|
||||
#include "nsIDOMRange.h"
|
||||
#include "nsIFrame.h"
|
||||
#include "nsIObjectFrame.h"
|
||||
#include "nsLayoutUtils.h"
|
||||
@ -75,16 +74,19 @@ ContentEventHandler::InitCommon()
|
||||
nsresult rv = InitBasic();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsISelection> sel;
|
||||
nsCopySupport::GetSelectionForCopy(mPresShell->GetDocument(),
|
||||
getter_AddRefs(mSelection));
|
||||
|
||||
nsCOMPtr<nsIDOMRange> firstRange;
|
||||
rv = mSelection->GetRangeAt(0, getter_AddRefs(firstRange));
|
||||
// This shell doesn't support selection.
|
||||
if (NS_FAILED(rv)) {
|
||||
getter_AddRefs(sel));
|
||||
mSelection = static_cast<Selection*>(sel.get());
|
||||
if (NS_WARN_IF(!mSelection)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
mFirstSelectedRange = static_cast<nsRange*>(firstRange.get());
|
||||
|
||||
// This shell doesn't support selection.
|
||||
if (NS_WARN_IF(!mSelection->RangeCount())) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
mFirstSelectedRange = mSelection->GetRangeAt(0);
|
||||
|
||||
nsINode* startNode = mFirstSelectedRange->GetStartParent();
|
||||
NS_ENSURE_TRUE(startNode, NS_ERROR_FAILURE);
|
||||
@ -114,15 +116,16 @@ ContentEventHandler::Init(WidgetQueryContentEvent* aEvent)
|
||||
|
||||
aEvent->mReply.mContentsRoot = mRootContent.get();
|
||||
|
||||
bool isCollapsed;
|
||||
rv = mSelection->GetIsCollapsed(&isCollapsed);
|
||||
NS_ENSURE_SUCCESS(rv, NS_ERROR_NOT_AVAILABLE);
|
||||
aEvent->mReply.mHasSelection = !isCollapsed;
|
||||
aEvent->mReply.mHasSelection = !mSelection->IsCollapsed();
|
||||
|
||||
nsRect r;
|
||||
nsIFrame* frame = nsCaret::GetGeometry(mSelection, &r);
|
||||
NS_ENSURE_TRUE(frame, NS_ERROR_FAILURE);
|
||||
|
||||
if (!frame) {
|
||||
frame = mRootContent->GetPrimaryFrame();
|
||||
if (NS_WARN_IF(!frame)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
aEvent->mReply.mFocusedWidget = frame->GetNearestWidget();
|
||||
|
||||
return NS_OK;
|
||||
@ -750,7 +753,7 @@ ContentEventHandler::SetRangeFromFlatTextOffset(nsRange* aRange,
|
||||
}
|
||||
}
|
||||
rv = aRange->SetEnd(mRootContent, int32_t(mRootContent->GetChildCount()));
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "nsIDOMRange::SetEnd failed");
|
||||
NS_ASSERTION(NS_SUCCEEDED(rv), "nsRange::SetEnd failed");
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -806,21 +809,17 @@ ContentEventHandler::OnQuerySelectedText(WidgetQueryContentEvent* aEvent)
|
||||
&aEvent->mReply.mOffset, lineBreakType);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsIDOMNode> anchorDomNode, focusDomNode;
|
||||
rv = mSelection->GetAnchorNode(getter_AddRefs(anchorDomNode));
|
||||
NS_ENSURE_TRUE(anchorDomNode, NS_ERROR_FAILURE);
|
||||
rv = mSelection->GetFocusNode(getter_AddRefs(focusDomNode));
|
||||
NS_ENSURE_TRUE(focusDomNode, NS_ERROR_FAILURE);
|
||||
nsCOMPtr<nsINode> anchorNode = mSelection->GetAnchorNode();
|
||||
nsCOMPtr<nsINode> focusNode = mSelection->GetFocusNode();
|
||||
if (NS_WARN_IF(!anchorNode) || NS_WARN_IF(!focusNode)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
int32_t anchorOffset, focusOffset;
|
||||
rv = mSelection->GetAnchorOffset(&anchorOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
rv = mSelection->GetFocusOffset(&focusOffset);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsINode> anchorNode(do_QueryInterface(anchorDomNode));
|
||||
nsCOMPtr<nsINode> focusNode(do_QueryInterface(focusDomNode));
|
||||
NS_ENSURE_TRUE(anchorNode && focusNode, NS_ERROR_UNEXPECTED);
|
||||
int32_t anchorOffset = static_cast<int32_t>(mSelection->AnchorOffset());
|
||||
int32_t focusOffset = static_cast<int32_t>(mSelection->FocusOffset());
|
||||
if (NS_WARN_IF(anchorOffset < 0) || NS_WARN_IF(focusOffset < 0)) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
int16_t compare = nsContentUtils::ComparePoints(anchorNode, anchorOffset,
|
||||
focusNode, focusOffset);
|
||||
@ -1032,32 +1031,29 @@ ContentEventHandler::OnQueryCaretRect(WidgetQueryContentEvent* aEvent)
|
||||
|
||||
LineBreakType lineBreakType = GetLineBreakType(aEvent);
|
||||
|
||||
nsRect caretRect;
|
||||
|
||||
// When the selection is collapsed and the queried offset is current caret
|
||||
// position, we should return the "real" caret rect.
|
||||
bool selectionIsCollapsed;
|
||||
rv = mSelection->GetIsCollapsed(&selectionIsCollapsed);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsRect caretRect;
|
||||
nsIFrame* caretFrame = nsCaret::GetGeometry(mSelection, &caretRect);
|
||||
|
||||
if (selectionIsCollapsed) {
|
||||
uint32_t offset;
|
||||
rv = GetFlatTextOffsetOfRange(mRootContent, mFirstSelectedRange, &offset,
|
||||
lineBreakType);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (offset == aEvent->mInput.mOffset) {
|
||||
if (!caretFrame) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
rv = ConvertToRootViewRelativeOffset(caretFrame, caretRect);
|
||||
if (mSelection->IsCollapsed()) {
|
||||
nsIFrame* caretFrame = nsCaret::GetGeometry(mSelection, &caretRect);
|
||||
if (caretFrame) {
|
||||
uint32_t offset;
|
||||
rv = GetFlatTextOffsetOfRange(mRootContent, mFirstSelectedRange, &offset,
|
||||
lineBreakType);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
aEvent->mReply.mRect = LayoutDevicePixel::FromUntyped(
|
||||
caretRect.ToOutsidePixels(caretFrame->PresContext()->AppUnitsPerDevPixel()));
|
||||
aEvent->mReply.mWritingMode = caretFrame->GetWritingMode();
|
||||
aEvent->mReply.mOffset = aEvent->mInput.mOffset;
|
||||
aEvent->mSucceeded = true;
|
||||
return NS_OK;
|
||||
if (offset == aEvent->mInput.mOffset) {
|
||||
rv = ConvertToRootViewRelativeOffset(caretFrame, caretRect);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
nscoord appUnitsPerDevPixel =
|
||||
caretFrame->PresContext()->AppUnitsPerDevPixel();
|
||||
aEvent->mReply.mRect = LayoutDevicePixel::FromUntyped(
|
||||
caretRect.ToOutsidePixels(appUnitsPerDevPixel));
|
||||
aEvent->mReply.mWritingMode = caretFrame->GetWritingMode();
|
||||
aEvent->mReply.mOffset = aEvent->mInput.mOffset;
|
||||
aEvent->mSucceeded = true;
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1527,9 +1523,11 @@ ContentEventHandler::OnSelectionEvent(WidgetSelectionEvent* aEvent)
|
||||
// Get selection to manipulate
|
||||
// XXX why do we need to get them from ISM? This method should work fine
|
||||
// without ISM.
|
||||
nsCOMPtr<nsISelection> sel;
|
||||
nsresult rv =
|
||||
IMEStateManager::GetFocusSelectionAndRoot(getter_AddRefs(mSelection),
|
||||
IMEStateManager::GetFocusSelectionAndRoot(getter_AddRefs(sel),
|
||||
getter_AddRefs(mRootContent));
|
||||
mSelection = static_cast<Selection*>(sel.get());
|
||||
if (rv != NS_ERROR_NOT_AVAILABLE) {
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else {
|
||||
@ -1550,36 +1548,35 @@ ContentEventHandler::OnSelectionEvent(WidgetSelectionEvent* aEvent)
|
||||
int32_t endNodeOffset = range->EndOffset();
|
||||
AdjustRangeForSelection(mRootContent, &startNode, &startNodeOffset);
|
||||
AdjustRangeForSelection(mRootContent, &endNode, &endNodeOffset);
|
||||
if (NS_WARN_IF(!startNode) || NS_WARN_IF(!endNode) ||
|
||||
NS_WARN_IF(startNodeOffset < 0) || NS_WARN_IF(endNodeOffset < 0)) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDOMNode> startDomNode(do_QueryInterface(startNode));
|
||||
nsCOMPtr<nsIDOMNode> endDomNode(do_QueryInterface(endNode));
|
||||
NS_ENSURE_TRUE(startDomNode && endDomNode, NS_ERROR_UNEXPECTED);
|
||||
|
||||
nsCOMPtr<nsISelectionPrivate> selPrivate(do_QueryInterface(mSelection));
|
||||
selPrivate->StartBatchChanges();
|
||||
mSelection->StartBatchChanges();
|
||||
|
||||
// Clear selection first before setting
|
||||
rv = mSelection->RemoveAllRanges();
|
||||
// Need to call EndBatchChanges at the end even if call failed
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (aEvent->mReversed) {
|
||||
rv = mSelection->Collapse(endDomNode, endNodeOffset);
|
||||
rv = mSelection->Collapse(endNode, endNodeOffset);
|
||||
} else {
|
||||
rv = mSelection->Collapse(startDomNode, startNodeOffset);
|
||||
rv = mSelection->Collapse(startNode, startNodeOffset);
|
||||
}
|
||||
if (NS_SUCCEEDED(rv) &&
|
||||
(startDomNode != endDomNode || startNodeOffset != endNodeOffset)) {
|
||||
(startNode != endNode || startNodeOffset != endNodeOffset)) {
|
||||
if (aEvent->mReversed) {
|
||||
rv = mSelection->Extend(startDomNode, startNodeOffset);
|
||||
rv = mSelection->Extend(startNode, startNodeOffset);
|
||||
} else {
|
||||
rv = mSelection->Extend(endDomNode, endNodeOffset);
|
||||
rv = mSelection->Extend(endNode, endNodeOffset);
|
||||
}
|
||||
}
|
||||
}
|
||||
selPrivate->EndBatchChanges();
|
||||
mSelection->EndBatchChanges();
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
selPrivate->ScrollIntoViewInternal(
|
||||
mSelection->ScrollIntoViewInternal(
|
||||
nsISelectionController::SELECTION_FOCUS_REGION,
|
||||
false, nsIPresShell::ScrollAxis(), nsIPresShell::ScrollAxis());
|
||||
aEvent->mSucceeded = true;
|
||||
|
@ -8,8 +8,8 @@
|
||||
#define mozilla_ContentEventHandler_h_
|
||||
|
||||
#include "mozilla/EventForwards.h"
|
||||
#include "mozilla/dom/Selection.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsISelection.h"
|
||||
#include "nsRange.h"
|
||||
|
||||
class nsPresContext;
|
||||
@ -35,6 +35,8 @@ enum LineBreakType
|
||||
class MOZ_STACK_CLASS ContentEventHandler
|
||||
{
|
||||
public:
|
||||
typedef dom::Selection Selection;
|
||||
|
||||
explicit ContentEventHandler(nsPresContext* aPresContext);
|
||||
|
||||
// NS_QUERY_SELECTED_TEXT event handler
|
||||
@ -62,7 +64,7 @@ public:
|
||||
protected:
|
||||
nsPresContext* mPresContext;
|
||||
nsCOMPtr<nsIPresShell> mPresShell;
|
||||
nsCOMPtr<nsISelection> mSelection;
|
||||
nsRefPtr<Selection> mSelection;
|
||||
nsRefPtr<nsRange> mFirstSelectedRange;
|
||||
nsCOMPtr<nsIContent> mRootContent;
|
||||
|
||||
|
@ -3385,7 +3385,7 @@ EventStateManager::RemoteQueryContentEvent(WidgetEvent* aEvent)
|
||||
TabParent*
|
||||
EventStateManager::GetCrossProcessTarget()
|
||||
{
|
||||
return TabParent::GetIMETabParent();
|
||||
return IMEStateManager::GetActiveTabParent();
|
||||
}
|
||||
|
||||
bool
|
||||
@ -3396,7 +3396,7 @@ EventStateManager::IsTargetCrossProcess(WidgetGUIEvent* aEvent)
|
||||
nsIContent *focusedContent = GetFocusedContent();
|
||||
if (focusedContent && focusedContent->IsEditable())
|
||||
return false;
|
||||
return TabParent::GetIMETabParent() != nullptr;
|
||||
return IMEStateManager::GetActiveTabParent() != nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "mozilla/Services.h"
|
||||
#include "mozilla/TextComposition.h"
|
||||
#include "mozilla/TextEvents.h"
|
||||
#include "mozilla/unused.h"
|
||||
#include "mozilla/dom/HTMLFormElement.h"
|
||||
#include "mozilla/dom/TabParent.h"
|
||||
|
||||
@ -180,19 +181,17 @@ GetNotifyIMEMessageName(IMEMessage aMessage)
|
||||
}
|
||||
}
|
||||
|
||||
nsIContent* IMEStateManager::sContent = nullptr;
|
||||
StaticRefPtr<nsIContent> IMEStateManager::sContent;
|
||||
nsPresContext* IMEStateManager::sPresContext = nullptr;
|
||||
StaticRefPtr<nsIWidget> IMEStateManager::sFocusedIMEWidget;
|
||||
StaticRefPtr<TabParent> IMEStateManager::sActiveTabParent;
|
||||
StaticRefPtr<IMEContentObserver> IMEStateManager::sActiveIMEContentObserver;
|
||||
TextCompositionArray* IMEStateManager::sTextCompositions = nullptr;
|
||||
bool IMEStateManager::sInstalledMenuKeyboardListener = false;
|
||||
bool IMEStateManager::sIsGettingNewIMEState = false;
|
||||
bool IMEStateManager::sCheckForIMEUnawareWebApps = false;
|
||||
bool IMEStateManager::sRemoteHasFocus = false;
|
||||
|
||||
// sActiveIMEContentObserver points to the currently active IMEContentObserver.
|
||||
// sActiveIMEContentObserver is null if there is no focused editor.
|
||||
IMEContentObserver* IMEStateManager::sActiveIMEContentObserver = nullptr;
|
||||
TextCompositionArray* IMEStateManager::sTextCompositions = nullptr;
|
||||
|
||||
// static
|
||||
void
|
||||
IMEStateManager::Init()
|
||||
@ -221,6 +220,43 @@ IMEStateManager::Shutdown()
|
||||
sTextCompositions = nullptr;
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
IMEStateManager::OnTabParentDestroying(TabParent* aTabParent)
|
||||
{
|
||||
if (sActiveTabParent != aTabParent) {
|
||||
return;
|
||||
}
|
||||
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||
("ISM: IMEStateManager::OnTabParentDestroying(aTabParent=0x%p), "
|
||||
"The active TabParent is being destroyed", aTabParent));
|
||||
|
||||
// The active remote process might have crashed.
|
||||
sActiveTabParent = nullptr;
|
||||
|
||||
// TODO: Need to cancel composition without TextComposition and make
|
||||
// disable IME.
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
IMEStateManager::StopIMEStateManagement()
|
||||
{
|
||||
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||
("ISM: IMEStateManager::StopIMEStateManagement()"));
|
||||
|
||||
// NOTE: Don't set input context from here since this has already lost
|
||||
// the rights to change input context.
|
||||
|
||||
if (sTextCompositions && sPresContext) {
|
||||
NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, sPresContext);
|
||||
}
|
||||
sPresContext = nullptr;
|
||||
sContent = nullptr;
|
||||
sActiveTabParent = nullptr;
|
||||
DestroyIMEContentObserver();
|
||||
}
|
||||
|
||||
// static
|
||||
nsresult
|
||||
IMEStateManager::OnDestroyPresContext(nsPresContext* aPresContext)
|
||||
@ -255,7 +291,7 @@ IMEStateManager::OnDestroyPresContext(nsPresContext* aPresContext)
|
||||
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||
("ISM: IMEStateManager::OnDestroyPresContext(aPresContext=0x%p), "
|
||||
"sPresContext=0x%p, sContent=0x%p, sTextCompositions=0x%p",
|
||||
aPresContext, sPresContext, sContent, sTextCompositions));
|
||||
aPresContext, sPresContext, sContent.get(), sTextCompositions));
|
||||
|
||||
DestroyIMEContentObserver();
|
||||
|
||||
@ -266,8 +302,9 @@ IMEStateManager::OnDestroyPresContext(nsPresContext* aPresContext)
|
||||
InputContextAction::LOST_FOCUS);
|
||||
SetIMEState(newState, nullptr, widget, action);
|
||||
}
|
||||
NS_IF_RELEASE(sContent);
|
||||
sContent = nullptr;
|
||||
sPresContext = nullptr;
|
||||
sActiveTabParent = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -310,7 +347,7 @@ IMEStateManager::OnRemoveContent(nsPresContext* aPresContext,
|
||||
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||
("ISM: IMEStateManager::OnRemoveContent(aPresContext=0x%p, "
|
||||
"aContent=0x%p), sPresContext=0x%p, sContent=0x%p, sTextCompositions=0x%p",
|
||||
aPresContext, aContent, sPresContext, sContent, sTextCompositions));
|
||||
aPresContext, aContent, sPresContext, sContent.get(), sTextCompositions));
|
||||
|
||||
DestroyIMEContentObserver();
|
||||
|
||||
@ -323,8 +360,9 @@ IMEStateManager::OnRemoveContent(nsPresContext* aPresContext,
|
||||
SetIMEState(newState, nullptr, widget, action);
|
||||
}
|
||||
|
||||
NS_IF_RELEASE(sContent);
|
||||
sContent = nullptr;
|
||||
sPresContext = nullptr;
|
||||
sActiveTabParent = nullptr;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -350,16 +388,23 @@ IMEStateManager::OnChangeFocusInternal(nsPresContext* aPresContext,
|
||||
nsIContent* aContent,
|
||||
InputContextAction aAction)
|
||||
{
|
||||
nsRefPtr<TabParent> newTabParent = TabParent::GetFrom(aContent);
|
||||
|
||||
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||
("ISM: IMEStateManager::OnChangeFocusInternal(aPresContext=0x%p, "
|
||||
"aContent=0x%p, aAction={ mCause=%s, mFocusChange=%s }), "
|
||||
"sPresContext=0x%p, sContent=0x%p, sActiveIMEContentObserver=0x%p",
|
||||
aPresContext, aContent, GetActionCauseName(aAction.mCause),
|
||||
"aContent=0x%p (TabParent=0x%p), aAction={ mCause=%s, mFocusChange=%s }), "
|
||||
"sPresContext=0x%p, sContent=0x%p, sActiveTabParent=0x%p, "
|
||||
"sActiveIMEContentObserver=0x%p, sInstalledMenuKeyboardListener=%s",
|
||||
aPresContext, aContent, newTabParent.get(),
|
||||
GetActionCauseName(aAction.mCause),
|
||||
GetActionFocusChangeName(aAction.mFocusChange),
|
||||
sPresContext, sContent, sActiveIMEContentObserver));
|
||||
sPresContext, sContent.get(), sActiveTabParent.get(),
|
||||
sActiveIMEContentObserver.get(),
|
||||
GetBoolName(sInstalledMenuKeyboardListener)));
|
||||
|
||||
bool focusActuallyChanging =
|
||||
(sContent != aContent || sPresContext != aPresContext);
|
||||
(sContent != aContent || sPresContext != aPresContext ||
|
||||
sActiveTabParent != newTabParent);
|
||||
|
||||
nsCOMPtr<nsIWidget> oldWidget =
|
||||
sPresContext ? sPresContext->GetRootWidget() : nullptr;
|
||||
@ -384,6 +429,18 @@ IMEStateManager::OnChangeFocusInternal(nsPresContext* aPresContext,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIContentParent* currentContentParent =
|
||||
sActiveTabParent ? sActiveTabParent->Manager() : nullptr;
|
||||
nsIContentParent* newContentParent =
|
||||
newTabParent ? newTabParent->Manager() : nullptr;
|
||||
if (sActiveTabParent && currentContentParent != newContentParent) {
|
||||
MOZ_LOG(sISMLog, LogLevel::Debug,
|
||||
("ISM: IMEStateManager::OnChangeFocusInternal(), notifying previous "
|
||||
"focused child process of parent process or another child process "
|
||||
"getting focus"));
|
||||
unused << sActiveTabParent->SendStopIMEStateManagement();
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIWidget> widget =
|
||||
(sPresContext == aPresContext) ? oldWidget.get() :
|
||||
aPresContext->GetRootWidget();
|
||||
@ -394,61 +451,85 @@ IMEStateManager::OnChangeFocusInternal(nsPresContext* aPresContext,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
IMEState newState = GetNewIMEState(aPresContext, aContent);
|
||||
// If a child process has focus, we should disable IME state until the child
|
||||
// process actually gets focus because if user types keys before that they
|
||||
// are handled by IME.
|
||||
IMEState newState =
|
||||
newTabParent ? IMEState(IMEState::DISABLED) :
|
||||
GetNewIMEState(aPresContext, aContent);
|
||||
bool setIMEState = true;
|
||||
|
||||
// In e10s, remote content may have IME focus. The main process (i.e. this process)
|
||||
// would attempt to set state to DISABLED if, for example, the user clicks
|
||||
// some other remote content. The content process would later re-ENABLE IME, meaning
|
||||
// that all state-changes were unnecessary.
|
||||
// Here we filter the common case where the main process knows that the remote
|
||||
// process controls IME focus. The DISABLED->re-ENABLED progression can
|
||||
// still happen since remote content may be concurrently communicating its claim
|
||||
// on focus to the main process... but this cannot cause bugs like missed keypresses.
|
||||
// (It just means a lot of needless IPC.)
|
||||
if ((newState.mEnabled == IMEState::DISABLED) && TabParent::GetIMETabParent()) {
|
||||
MOZ_LOG(sISMLog, LogLevel::Debug,
|
||||
("ISM: IMEStateManager::OnChangeFocusInternal(), "
|
||||
"Parent process cancels to set DISABLED state because the content process "
|
||||
"has IME focus and has already sets IME state"));
|
||||
MOZ_ASSERT(XRE_IsParentProcess(),
|
||||
"TabParent::GetIMETabParent() should never return non-null value "
|
||||
"in the content process");
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!focusActuallyChanging) {
|
||||
// actual focus isn't changing, but if IME enabled state is changing,
|
||||
// we should do it.
|
||||
InputContext context = widget->GetInputContext();
|
||||
if (context.mIMEState.mEnabled == newState.mEnabled) {
|
||||
if (newTabParent) {
|
||||
if (aAction.mFocusChange == InputContextAction::MENU_GOT_PSEUDO_FOCUS ||
|
||||
aAction.mFocusChange == InputContextAction::MENU_LOST_PSEUDO_FOCUS) {
|
||||
// XXX When menu keyboard listener is being uninstalled, IME state needs
|
||||
// to be restored by the child process asynchronously. Therefore,
|
||||
// some key events which are fired immediately after closing menu
|
||||
// may not be handled by IME.
|
||||
unused << newTabParent->
|
||||
SendMenuKeyboardListenerInstalled(sInstalledMenuKeyboardListener);
|
||||
setIMEState = sInstalledMenuKeyboardListener;
|
||||
} else if (focusActuallyChanging) {
|
||||
InputContext context = widget->GetInputContext();
|
||||
if (context.mIMEState.mEnabled == IMEState::DISABLED) {
|
||||
setIMEState = false;
|
||||
MOZ_LOG(sISMLog, LogLevel::Debug,
|
||||
("ISM: IMEStateManager::OnChangeFocusInternal(), doesn't set IME "
|
||||
"state because focused element (or document) is in a child process "
|
||||
"and the IME state is already disabled"));
|
||||
} else {
|
||||
MOZ_LOG(sISMLog, LogLevel::Debug,
|
||||
("ISM: IMEStateManager::OnChangeFocusInternal(), will disable IME "
|
||||
"until new focused element (or document) in the child process "
|
||||
"will get focus actually"));
|
||||
}
|
||||
} else {
|
||||
// When focus is NOT changed actually, we shouldn't set IME state since
|
||||
// that means that the window is being activated and the child process
|
||||
// may have composition. Then, we shouldn't commit the composition with
|
||||
// making IME state disabled.
|
||||
setIMEState = false;
|
||||
MOZ_LOG(sISMLog, LogLevel::Debug,
|
||||
("ISM: IMEStateManager::OnChangeFocusInternal(), "
|
||||
"neither focus nor IME state is changing"));
|
||||
return NS_OK;
|
||||
("ISM: IMEStateManager::OnChangeFocusInternal(), doesn't set IME "
|
||||
"state because focused element (or document) is already in the child "
|
||||
"process"));
|
||||
}
|
||||
aAction.mFocusChange = InputContextAction::FOCUS_NOT_CHANGED;
|
||||
|
||||
// Even if focus isn't changing actually, we should commit current
|
||||
// composition here since the IME state is changing.
|
||||
if (sPresContext && oldWidget && !focusActuallyChanging) {
|
||||
NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, oldWidget);
|
||||
}
|
||||
} else if (aAction.mFocusChange == InputContextAction::FOCUS_NOT_CHANGED) {
|
||||
// If aContent isn't null or aContent is null but editable, somebody gets
|
||||
// focus.
|
||||
bool gotFocus = aContent || (newState.mEnabled == IMEState::ENABLED);
|
||||
aAction.mFocusChange =
|
||||
gotFocus ? InputContextAction::GOT_FOCUS : InputContextAction::LOST_FOCUS;
|
||||
}
|
||||
|
||||
// Update IME state for new focus widget
|
||||
SetIMEState(newState, aContent, widget, aAction);
|
||||
if (setIMEState) {
|
||||
if (!focusActuallyChanging) {
|
||||
// actual focus isn't changing, but if IME enabled state is changing,
|
||||
// we should do it.
|
||||
InputContext context = widget->GetInputContext();
|
||||
if (context.mIMEState.mEnabled == newState.mEnabled) {
|
||||
MOZ_LOG(sISMLog, LogLevel::Debug,
|
||||
("ISM: IMEStateManager::OnChangeFocusInternal(), "
|
||||
"neither focus nor IME state is changing"));
|
||||
return NS_OK;
|
||||
}
|
||||
aAction.mFocusChange = InputContextAction::FOCUS_NOT_CHANGED;
|
||||
|
||||
// Even if focus isn't changing actually, we should commit current
|
||||
// composition here since the IME state is changing.
|
||||
if (sPresContext && oldWidget && !focusActuallyChanging) {
|
||||
NotifyIME(REQUEST_TO_COMMIT_COMPOSITION, oldWidget);
|
||||
}
|
||||
} else if (aAction.mFocusChange == InputContextAction::FOCUS_NOT_CHANGED) {
|
||||
// If aContent isn't null or aContent is null but editable, somebody gets
|
||||
// focus.
|
||||
bool gotFocus = aContent || (newState.mEnabled == IMEState::ENABLED);
|
||||
aAction.mFocusChange =
|
||||
gotFocus ? InputContextAction::GOT_FOCUS :
|
||||
InputContextAction::LOST_FOCUS;
|
||||
}
|
||||
|
||||
// Update IME state for new focus widget
|
||||
SetIMEState(newState, aContent, widget, aAction);
|
||||
}
|
||||
|
||||
sActiveTabParent = newTabParent;
|
||||
sPresContext = aPresContext;
|
||||
if (sContent != aContent) {
|
||||
NS_IF_RELEASE(sContent);
|
||||
NS_IF_ADDREF(sContent = aContent);
|
||||
}
|
||||
sContent = aContent;
|
||||
|
||||
// Don't call CreateIMEContentObserver() here, it should be called from
|
||||
// focus event handler of editor.
|
||||
@ -482,7 +563,7 @@ IMEStateManager::OnMouseButtonEventInEditor(nsPresContext* aPresContext,
|
||||
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||
("ISM: IMEStateManager::OnMouseButtonEventInEditor(aPresContext=0x%p, "
|
||||
"aContent=0x%p, aMouseEvent=0x%p), sPresContext=0x%p, sContent=0x%p",
|
||||
aPresContext, aContent, aMouseEvent, sPresContext, sContent));
|
||||
aPresContext, aContent, aMouseEvent, sPresContext, sContent.get()));
|
||||
|
||||
if (sPresContext != aPresContext || sContent != aContent) {
|
||||
MOZ_LOG(sISMLog, LogLevel::Debug,
|
||||
@ -539,7 +620,7 @@ IMEStateManager::OnClickInEditor(nsPresContext* aPresContext,
|
||||
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||
("ISM: IMEStateManager::OnClickInEditor(aPresContext=0x%p, aContent=0x%p, "
|
||||
"aMouseEvent=0x%p), sPresContext=0x%p, sContent=0x%p",
|
||||
aPresContext, aContent, aMouseEvent, sPresContext, sContent));
|
||||
aPresContext, aContent, aMouseEvent, sPresContext, sContent.get()));
|
||||
|
||||
if (sPresContext != aPresContext || sContent != aContent) {
|
||||
MOZ_LOG(sISMLog, LogLevel::Debug,
|
||||
@ -597,8 +678,8 @@ IMEStateManager::OnFocusInEditor(nsPresContext* aPresContext,
|
||||
("ISM: IMEStateManager::OnFocusInEditor(aPresContext=0x%p, aContent=0x%p, "
|
||||
"aEditor=0x%p), sPresContext=0x%p, sContent=0x%p, "
|
||||
"sActiveIMEContentObserver=0x%p",
|
||||
aPresContext, aContent, aEditor, sPresContext, sContent,
|
||||
sActiveIMEContentObserver));
|
||||
aPresContext, aContent, aEditor, sPresContext, sContent.get(),
|
||||
sActiveIMEContentObserver.get()));
|
||||
|
||||
if (sPresContext != aPresContext || sContent != aContent) {
|
||||
MOZ_LOG(sISMLog, LogLevel::Debug,
|
||||
@ -669,7 +750,7 @@ IMEStateManager::UpdateIMEState(const IMEState& aNewIMEState,
|
||||
"sIsGettingNewIMEState=%s",
|
||||
GetIMEStateEnabledName(aNewIMEState.mEnabled),
|
||||
GetIMEStateSetOpenName(aNewIMEState.mOpen), aContent, aEditor,
|
||||
sPresContext, sContent, sActiveIMEContentObserver,
|
||||
sPresContext, sContent.get(), sActiveIMEContentObserver.get(),
|
||||
GetBoolName(sIsGettingNewIMEState)));
|
||||
|
||||
if (sIsGettingNewIMEState) {
|
||||
@ -842,6 +923,55 @@ MayBeIMEUnawareWebApp(nsINode* aNode)
|
||||
return haveKeyEventsListener;
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
IMEStateManager::SetInputContextForChildProcess(
|
||||
TabParent* aTabParent,
|
||||
const InputContext& aInputContext,
|
||||
const InputContextAction& aAction)
|
||||
{
|
||||
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||
("ISM: IMEStateManager::SetInputContextForChildProcess(aTabParent=0x%p, "
|
||||
"aInputContext={ mIMEState={ mEnabled=%s, mOpen=%s }, "
|
||||
"mHTMLInputType=\"%s\", mHTMLInputInputmode=\"%s\", mActionHint=\"%s\" }, "
|
||||
"aAction={ mCause=%s, mAction=%s }, aTabParent=0x%p), sPresContext=0x%p, "
|
||||
"sActiveTabParent=0x%p",
|
||||
aTabParent, GetIMEStateEnabledName(aInputContext.mIMEState.mEnabled),
|
||||
GetIMEStateSetOpenName(aInputContext.mIMEState.mOpen),
|
||||
NS_ConvertUTF16toUTF8(aInputContext.mHTMLInputType).get(),
|
||||
NS_ConvertUTF16toUTF8(aInputContext.mHTMLInputInputmode).get(),
|
||||
NS_ConvertUTF16toUTF8(aInputContext.mActionHint).get(),
|
||||
GetActionCauseName(aAction.mCause),
|
||||
GetActionFocusChangeName(aAction.mFocusChange),
|
||||
sPresContext, sActiveTabParent.get()));
|
||||
|
||||
if (NS_WARN_IF(aTabParent != sActiveTabParent)) {
|
||||
MOZ_LOG(sISMLog, LogLevel::Error,
|
||||
("ISM: IMEStateManager::SetInputContextForChildProcess(), FAILED, "
|
||||
"because non-focused tab parent tries to set input context"));
|
||||
return;
|
||||
}
|
||||
|
||||
if (NS_WARN_IF(!sPresContext)) {
|
||||
MOZ_LOG(sISMLog, LogLevel::Error,
|
||||
("ISM: IMEStateManager::SetInputContextForChildProcess(), FAILED, "
|
||||
"due to no focused presContext"));
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIWidget> widget = sPresContext->GetRootWidget();
|
||||
if (NS_WARN_IF(!widget)) {
|
||||
MOZ_LOG(sISMLog, LogLevel::Error,
|
||||
("ISM: IMEStateManager::SetInputContextForChildProcess(), FAILED, "
|
||||
"due to no widget in the focused presContext"));
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aInputContext.mOrigin == InputContext::ORIGIN_CONTENT);
|
||||
|
||||
SetInputContext(widget, aInputContext, aAction);
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
IMEStateManager::SetIMEState(const IMEState& aState,
|
||||
@ -851,9 +981,11 @@ IMEStateManager::SetIMEState(const IMEState& aState,
|
||||
{
|
||||
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||
("ISM: IMEStateManager::SetIMEState(aState={ mEnabled=%s, mOpen=%s }, "
|
||||
"aContent=0x%p, aWidget=0x%p, aAction={ mCause=%s, mFocusChange=%s })",
|
||||
"aContent=0x%p (TabParent=0x%p), aWidget=0x%p, aAction={ mCause=%s, "
|
||||
"mFocusChange=%s })",
|
||||
GetIMEStateEnabledName(aState.mEnabled),
|
||||
GetIMEStateSetOpenName(aState.mOpen), aContent, aWidget,
|
||||
GetIMEStateSetOpenName(aState.mOpen), aContent,
|
||||
TabParent::GetFrom(aContent), aWidget,
|
||||
GetActionCauseName(aAction.mCause),
|
||||
GetActionFocusChangeName(aAction.mFocusChange)));
|
||||
|
||||
@ -936,27 +1068,41 @@ IMEStateManager::SetIMEState(const IMEState& aState,
|
||||
aAction.mCause = InputContextAction::CAUSE_UNKNOWN_CHROME;
|
||||
}
|
||||
|
||||
SetInputContext(aWidget, context, aAction);
|
||||
}
|
||||
|
||||
MOZ_LOG(sISMLog, LogLevel::Debug,
|
||||
("ISM: IMEStateManager::SetIMEState(), "
|
||||
"calling nsIWidget::SetInputContext(context={ mIMEState={ mEnabled=%s, "
|
||||
"mOpen=%s }, mHTMLInputType=\"%s\", mHTMLInputInputmode=\"%s\", "
|
||||
"mActionHint=\"%s\" }, aAction={ mCause=%s, mAction=%s })",
|
||||
GetIMEStateEnabledName(context.mIMEState.mEnabled),
|
||||
GetIMEStateSetOpenName(context.mIMEState.mOpen),
|
||||
NS_ConvertUTF16toUTF8(context.mHTMLInputType).get(),
|
||||
NS_ConvertUTF16toUTF8(context.mHTMLInputInputmode).get(),
|
||||
NS_ConvertUTF16toUTF8(context.mActionHint).get(),
|
||||
// static
|
||||
void
|
||||
IMEStateManager::SetInputContext(nsIWidget* aWidget,
|
||||
const InputContext& aInputContext,
|
||||
const InputContextAction& aAction)
|
||||
{
|
||||
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||
("ISM: IMEStateManager::SetInputContext(aWidget=0x%p, aInputContext={ "
|
||||
"mIMEState={ mEnabled=%s, mOpen=%s }, mHTMLInputType=\"%s\", "
|
||||
"mHTMLInputInputmode=\"%s\", mActionHint=\"%s\" }, "
|
||||
"aAction={ mCause=%s, mAction=%s }), sActiveTabParent=0x%p",
|
||||
aWidget,
|
||||
GetIMEStateEnabledName(aInputContext.mIMEState.mEnabled),
|
||||
GetIMEStateSetOpenName(aInputContext.mIMEState.mOpen),
|
||||
NS_ConvertUTF16toUTF8(aInputContext.mHTMLInputType).get(),
|
||||
NS_ConvertUTF16toUTF8(aInputContext.mHTMLInputInputmode).get(),
|
||||
NS_ConvertUTF16toUTF8(aInputContext.mActionHint).get(),
|
||||
GetActionCauseName(aAction.mCause),
|
||||
GetActionFocusChangeName(aAction.mFocusChange)));
|
||||
GetActionFocusChangeName(aAction.mFocusChange),
|
||||
sActiveTabParent.get()));
|
||||
|
||||
aWidget->SetInputContext(context, aAction);
|
||||
if (oldContext.mIMEState.mEnabled == context.mIMEState.mEnabled) {
|
||||
MOZ_RELEASE_ASSERT(aWidget);
|
||||
|
||||
InputContext oldContext = aWidget->GetInputContext();
|
||||
|
||||
aWidget->SetInputContext(aInputContext, aAction);
|
||||
if (oldContext.mIMEState.mEnabled == aInputContext.mIMEState.mEnabled) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsContentUtils::AddScriptRunner(
|
||||
new IMEEnabledStateChangedEvent(context.mIMEState.mEnabled));
|
||||
new IMEEnabledStateChangedEvent(aInputContext.mIMEState.mEnabled));
|
||||
}
|
||||
|
||||
// static
|
||||
@ -1334,7 +1480,7 @@ IMEStateManager::DestroyIMEContentObserver()
|
||||
MOZ_LOG(sISMLog, LogLevel::Info,
|
||||
("ISM: IMEStateManager::DestroyIMEContentObserver(), "
|
||||
"sActiveIMEContentObserver=0x%p",
|
||||
sActiveIMEContentObserver));
|
||||
sActiveIMEContentObserver.get()));
|
||||
|
||||
if (!sActiveIMEContentObserver) {
|
||||
MOZ_LOG(sISMLog, LogLevel::Debug,
|
||||
@ -1345,8 +1491,8 @@ IMEStateManager::DestroyIMEContentObserver()
|
||||
MOZ_LOG(sISMLog, LogLevel::Debug,
|
||||
("ISM: IMEStateManager::DestroyIMEContentObserver(), destroying "
|
||||
"the active IMEContentObserver..."));
|
||||
nsRefPtr<IMEContentObserver> tsm;
|
||||
tsm.swap(sActiveIMEContentObserver);
|
||||
nsRefPtr<IMEContentObserver> tsm = sActiveIMEContentObserver.get();
|
||||
sActiveIMEContentObserver = nullptr;
|
||||
tsm->Destroy();
|
||||
}
|
||||
|
||||
@ -1358,7 +1504,7 @@ IMEStateManager::CreateIMEContentObserver(nsIEditor* aEditor)
|
||||
("ISM: IMEStateManager::CreateIMEContentObserver(aEditor=0x%p), "
|
||||
"sPresContext=0x%p, sContent=0x%p, sActiveIMEContentObserver=0x%p, "
|
||||
"sActiveIMEContentObserver->IsManaging(sPresContext, sContent)=%s",
|
||||
aEditor, sPresContext, sContent, sActiveIMEContentObserver,
|
||||
aEditor, sPresContext, sContent.get(), sActiveIMEContentObserver.get(),
|
||||
GetBoolName(sActiveIMEContentObserver ?
|
||||
sActiveIMEContentObserver->IsManaging(sPresContext, sContent) : false)));
|
||||
|
||||
@ -1390,7 +1536,6 @@ IMEStateManager::CreateIMEContentObserver(nsIEditor* aEditor)
|
||||
("ISM: IMEStateManager::CreateIMEContentObserver() is creating an "
|
||||
"IMEContentObserver instance..."));
|
||||
sActiveIMEContentObserver = new IMEContentObserver();
|
||||
NS_ADDREF(sActiveIMEContentObserver);
|
||||
|
||||
// IMEContentObserver::Init() might create another IMEContentObserver
|
||||
// instance. So, sActiveIMEContentObserver would be replaced with new one.
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
#include "mozilla/EventForwards.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/dom/TabParent.h"
|
||||
#include "nsIWidget.h"
|
||||
|
||||
class nsIContent;
|
||||
@ -33,6 +34,7 @@ class TextComposition;
|
||||
|
||||
class IMEStateManager
|
||||
{
|
||||
typedef dom::TabParent TabParent;
|
||||
typedef widget::IMEMessage IMEMessage;
|
||||
typedef widget::IMENotification IMENotification;
|
||||
typedef widget::IMEState IMEState;
|
||||
@ -43,6 +45,39 @@ public:
|
||||
static void Init();
|
||||
static void Shutdown();
|
||||
|
||||
/**
|
||||
* GetActiveTabParent() returns a pointer to a TabParent instance which is
|
||||
* managed by the focused content (sContent). If the focused content isn't
|
||||
* managing another process, this returns nullptr.
|
||||
*/
|
||||
static TabParent* GetActiveTabParent()
|
||||
{
|
||||
// If menu has pseudo focus, we should ignore active child process.
|
||||
if (sInstalledMenuKeyboardListener) {
|
||||
return nullptr;
|
||||
}
|
||||
return sActiveTabParent.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* OnTabParentDestroying() is called when aTabParent is being destroyed.
|
||||
*/
|
||||
static void OnTabParentDestroying(TabParent* aTabParent);
|
||||
|
||||
/**
|
||||
* SetIMEContextForChildProcess() is called when aTabParent receives
|
||||
* SetInputContext() from the remote process.
|
||||
*/
|
||||
static void SetInputContextForChildProcess(TabParent* aTabParent,
|
||||
const InputContext& aInputContext,
|
||||
const InputContextAction& aAction);
|
||||
|
||||
/**
|
||||
* StopIMEStateManagement() is called when the process should stop managing
|
||||
* IME state.
|
||||
*/
|
||||
static void StopIMEStateManagement();
|
||||
|
||||
static nsresult OnDestroyPresContext(nsPresContext* aPresContext);
|
||||
static nsresult OnRemoveContent(nsPresContext* aPresContext,
|
||||
nsIContent* aContent);
|
||||
@ -163,6 +198,9 @@ protected:
|
||||
nsIContent* aContent,
|
||||
nsIWidget* aWidget,
|
||||
InputContextAction aAction);
|
||||
static void SetInputContext(nsIWidget* aWidget,
|
||||
const InputContext& aInputContext,
|
||||
const InputContextAction& aAction);
|
||||
static IMEState GetNewIMEState(nsPresContext* aPresContext,
|
||||
nsIContent* aContent);
|
||||
|
||||
@ -174,9 +212,20 @@ protected:
|
||||
|
||||
static bool IsIMEObserverNeeded(const IMEState& aState);
|
||||
|
||||
static nsIContent* sContent;
|
||||
static StaticRefPtr<nsIContent> sContent;
|
||||
static nsPresContext* sPresContext;
|
||||
static StaticRefPtr<nsIWidget> sFocusedIMEWidget;
|
||||
static StaticRefPtr<TabParent> sActiveTabParent;
|
||||
// sActiveIMEContentObserver points to the currently active
|
||||
// IMEContentObserver. This is null if there is no focused editor.
|
||||
static StaticRefPtr<IMEContentObserver> sActiveIMEContentObserver;
|
||||
|
||||
// All active compositions in the process are stored by this array.
|
||||
// When you get an item of this array and use it, please be careful.
|
||||
// The instances in this array can be destroyed automatically if you do
|
||||
// something to cause committing or canceling the composition.
|
||||
static TextCompositionArray* sTextCompositions;
|
||||
|
||||
static bool sInstalledMenuKeyboardListener;
|
||||
static bool sIsGettingNewIMEState;
|
||||
static bool sCheckForIMEUnawareWebApps;
|
||||
@ -197,14 +246,6 @@ protected:
|
||||
private:
|
||||
bool mOldValue;
|
||||
};
|
||||
|
||||
static IMEContentObserver* sActiveIMEContentObserver;
|
||||
|
||||
// All active compositions in the process are stored by this array.
|
||||
// When you get an item of this array and use it, please be careful.
|
||||
// The instances in this array can be destroyed automatically if you do
|
||||
// something to cause committing or canceling the composition.
|
||||
static TextCompositionArray* sTextCompositions;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
@ -435,7 +435,14 @@ const kEventConstructors = {
|
||||
return new SpeechRecognitionEvent(aName, aProps);
|
||||
},
|
||||
},
|
||||
SpeechSynthesisErrorEvent: { create: function (aName, aProps) {
|
||||
aProps.error = "synthesis-unavailable";
|
||||
aProps.utterance = new SpeechSynthesisUtterance("Hello World");
|
||||
return new SpeechSynthesisErrorEvent(aName, aProps);
|
||||
},
|
||||
},
|
||||
SpeechSynthesisEvent: { create: function (aName, aProps) {
|
||||
aProps.utterance = new SpeechSynthesisUtterance("Hello World");
|
||||
return new SpeechSynthesisEvent(aName, aProps);
|
||||
},
|
||||
},
|
||||
|
@ -576,6 +576,18 @@ child:
|
||||
|
||||
ParentActivated(bool aActivated);
|
||||
|
||||
/**
|
||||
* StopIMEStateManagement() is called when the process loses focus and
|
||||
* should stop managing IME state.
|
||||
*/
|
||||
StopIMEStateManagement();
|
||||
|
||||
/**
|
||||
* MenuKeyboardListenerInstalled() is called when menu keyboard listener
|
||||
* is installed in the parent process.
|
||||
*/
|
||||
MenuKeyboardListenerInstalled(bool aInstalled);
|
||||
|
||||
/**
|
||||
* @see nsIDOMWindowUtils sendMouseEvent.
|
||||
*/
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "mozilla/dom/workers/ServiceWorkerManager.h"
|
||||
#include "mozilla/dom/indexedDB/PIndexedDBPermissionRequestChild.h"
|
||||
#include "mozilla/plugins/PluginWidgetChild.h"
|
||||
#include "mozilla/IMEStateManager.h"
|
||||
#include "mozilla/ipc/DocumentRendererChild.h"
|
||||
#include "mozilla/ipc/FileDescriptorUtils.h"
|
||||
#include "mozilla/layers/APZCCallbackHelper.h"
|
||||
@ -2199,6 +2200,20 @@ bool TabChild::RecvParentActivated(const bool& aActivated)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabChild::RecvStopIMEStateManagement()
|
||||
{
|
||||
IMEStateManager::StopIMEStateManagement();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabChild::RecvMenuKeyboardListenerInstalled(const bool& aInstalled)
|
||||
{
|
||||
IMEStateManager::OnInstalledMenuKeyboardListener(aInstalled);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabChild::RecvMouseEvent(const nsString& aType,
|
||||
const float& aX,
|
||||
|
@ -529,6 +529,10 @@ protected:
|
||||
|
||||
virtual bool RecvParentActivated(const bool& aActivated) override;
|
||||
|
||||
virtual bool RecvStopIMEStateManagement() override;
|
||||
virtual bool RecvMenuKeyboardListenerInstalled(
|
||||
const bool& aInstalled) override;
|
||||
|
||||
#ifdef MOZ_WIDGET_GONK
|
||||
void MaybeRequestPreinitCamera();
|
||||
#endif
|
||||
|
@ -248,7 +248,6 @@ private:
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
TabParent *TabParent::mIMETabParent = nullptr;
|
||||
TabParent::LayerToTabParentTable* TabParent::sLayerToTabParentTable = nullptr;
|
||||
|
||||
NS_IMPL_ISUPPORTS(TabParent,
|
||||
@ -481,9 +480,8 @@ TabParent::Recv__delete__()
|
||||
void
|
||||
TabParent::ActorDestroy(ActorDestroyReason why)
|
||||
{
|
||||
if (mIMETabParent == this) {
|
||||
mIMETabParent = nullptr;
|
||||
}
|
||||
IMEStateManager::OnTabParentDestroying(this);
|
||||
|
||||
nsRefPtr<nsFrameLoader> frameLoader = GetFrameLoader(true);
|
||||
nsCOMPtr<nsIObserverService> os = services::GetObserverService();
|
||||
if (frameLoader) {
|
||||
@ -1934,7 +1932,6 @@ TabParent::RecvNotifyIMEFocus(const bool& aFocus,
|
||||
return true;
|
||||
}
|
||||
|
||||
mIMETabParent = aFocus ? this : nullptr;
|
||||
IMENotification notification(aFocus ? NOTIFY_IME_OF_FOCUS :
|
||||
NOTIFY_IME_OF_BLUR);
|
||||
mContentCache.AssignContent(aContentCache, ¬ification);
|
||||
@ -2388,26 +2385,6 @@ TabParent::RecvSetInputContext(const int32_t& aIMEEnabled,
|
||||
const int32_t& aCause,
|
||||
const int32_t& aFocusChange)
|
||||
{
|
||||
nsCOMPtr<nsIWidget> widget = GetWidget();
|
||||
if (!widget || !AllowContentIME()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
InputContext oldContext = widget->GetInputContext();
|
||||
|
||||
// Ignore if current widget IME setting is not DISABLED and didn't come
|
||||
// from remote content. Chrome content may have taken over.
|
||||
if (oldContext.mIMEState.mEnabled != IMEState::DISABLED &&
|
||||
oldContext.IsOriginMainProcess()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// mIMETabParent (which is actually static) tracks which if any TabParent has IMEFocus
|
||||
// When the input mode is set to anything but IMEState::DISABLED,
|
||||
// mIMETabParent should be set to this
|
||||
mIMETabParent =
|
||||
aIMEEnabled != static_cast<int32_t>(IMEState::DISABLED) ? this : nullptr;
|
||||
|
||||
InputContext context;
|
||||
context.mIMEState.mEnabled = static_cast<IMEState::Enabled>(aIMEEnabled);
|
||||
context.mIMEState.mOpen = static_cast<IMEState::Open>(aIMEOpen);
|
||||
@ -2419,15 +2396,8 @@ TabParent::RecvSetInputContext(const int32_t& aIMEEnabled,
|
||||
InputContextAction action(
|
||||
static_cast<InputContextAction::Cause>(aCause),
|
||||
static_cast<InputContextAction::FocusChange>(aFocusChange));
|
||||
widget->SetInputContext(context, action);
|
||||
|
||||
nsCOMPtr<nsIObserverService> observerService = mozilla::services::GetObserverService();
|
||||
if (!observerService)
|
||||
return true;
|
||||
|
||||
nsAutoString state;
|
||||
state.AppendInt(aIMEEnabled);
|
||||
observerService->NotifyObservers(nullptr, "ime-enabled-state-changed", state.get());
|
||||
IMEStateManager::SetInputContextForChildProcess(this, context, action);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -2617,19 +2587,6 @@ TabParent::RecvGetRenderFrameInfo(PRenderFrameParent* aRenderFrame,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
TabParent::AllowContentIME()
|
||||
{
|
||||
nsFocusManager* fm = nsFocusManager::GetFocusManager();
|
||||
NS_ENSURE_TRUE(fm, false);
|
||||
|
||||
nsCOMPtr<nsIContent> focusedContent = fm->GetFocusedContent();
|
||||
if (focusedContent && focusedContent->IsEditable())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
already_AddRefed<nsFrameLoader>
|
||||
TabParent::GetFrameLoader(bool aUseCachedFrameLoaderAfterDestroy) const
|
||||
{
|
||||
|
@ -366,7 +366,6 @@ public:
|
||||
NS_DECL_NSIAUTHPROMPTPROVIDER
|
||||
NS_DECL_NSISECUREBROWSERUI
|
||||
|
||||
static TabParent *GetIMETabParent() { return mIMETabParent; }
|
||||
bool HandleQueryContentEvent(mozilla::WidgetQueryContentEvent& aEvent);
|
||||
bool SendCompositionEvent(mozilla::WidgetCompositionEvent& event);
|
||||
bool SendSelectionEvent(mozilla::WidgetSelectionEvent& event);
|
||||
@ -447,8 +446,6 @@ protected:
|
||||
Element* mFrameElement;
|
||||
nsCOMPtr<nsIBrowserDOMWindow> mBrowserDOMWindow;
|
||||
|
||||
bool AllowContentIME();
|
||||
|
||||
virtual PRenderFrameParent* AllocPRenderFrameParent() override;
|
||||
virtual bool DeallocPRenderFrameParent(PRenderFrameParent* aFrame) override;
|
||||
|
||||
@ -467,8 +464,6 @@ protected:
|
||||
|
||||
void SetHasContentOpener(bool aHasContentOpener);
|
||||
|
||||
// IME
|
||||
static TabParent *mIMETabParent;
|
||||
ContentCacheInParent mContentCache;
|
||||
|
||||
nsIntRect mRect;
|
||||
|
@ -225,7 +225,9 @@ SpeechSynthesis::GetVoices(nsTArray< nsRefPtr<SpeechSynthesisVoice> >& aResult)
|
||||
uint32_t voiceCount = 0;
|
||||
|
||||
nsresult rv = nsSynthVoiceRegistry::GetInstance()->GetVoiceCount(&voiceCount);
|
||||
NS_ENSURE_SUCCESS_VOID(rv);
|
||||
if(NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < voiceCount; i++) {
|
||||
nsAutoString uri;
|
||||
|
@ -162,6 +162,7 @@ SpeechSynthesisUtterance::DispatchSpeechSynthesisEvent(const nsAString& aEventTy
|
||||
SpeechSynthesisEventInit init;
|
||||
init.mBubbles = false;
|
||||
init.mCancelable = false;
|
||||
init.mUtterance = this;
|
||||
init.mCharIndex = aCharIndex;
|
||||
init.mElapsedTime = aElapsedTime;
|
||||
init.mName = aName;
|
||||
|
@ -123,7 +123,9 @@ nsresult
|
||||
SpeechTaskParent::DispatchStartImpl(const nsAString& aUri)
|
||||
{
|
||||
MOZ_ASSERT(mActor);
|
||||
NS_ENSURE_TRUE(mActor->SendOnStart(nsString(aUri)), NS_ERROR_FAILURE);
|
||||
if(NS_WARN_IF(!(mActor->SendOnStart(nsString(aUri))))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -134,8 +136,9 @@ SpeechTaskParent::DispatchEndImpl(float aElapsedTime, uint32_t aCharIndex)
|
||||
MOZ_ASSERT(mActor);
|
||||
SpeechSynthesisRequestParent* actor = mActor;
|
||||
mActor = nullptr;
|
||||
NS_ENSURE_TRUE(actor->Send__delete__(actor, false, aElapsedTime, aCharIndex),
|
||||
NS_ERROR_FAILURE);
|
||||
if(NS_WARN_IF(!(actor->Send__delete__(actor, false, aElapsedTime, aCharIndex)))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -144,7 +147,9 @@ nsresult
|
||||
SpeechTaskParent::DispatchPauseImpl(float aElapsedTime, uint32_t aCharIndex)
|
||||
{
|
||||
MOZ_ASSERT(mActor);
|
||||
NS_ENSURE_TRUE(mActor->SendOnPause(aElapsedTime, aCharIndex), NS_ERROR_FAILURE);
|
||||
if(NS_WARN_IF(!(mActor->SendOnPause(aElapsedTime, aCharIndex)))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -153,7 +158,9 @@ nsresult
|
||||
SpeechTaskParent::DispatchResumeImpl(float aElapsedTime, uint32_t aCharIndex)
|
||||
{
|
||||
MOZ_ASSERT(mActor);
|
||||
NS_ENSURE_TRUE(mActor->SendOnResume(aElapsedTime, aCharIndex), NS_ERROR_FAILURE);
|
||||
if(NS_WARN_IF(!(mActor->SendOnResume(aElapsedTime, aCharIndex)))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -164,8 +171,9 @@ SpeechTaskParent::DispatchErrorImpl(float aElapsedTime, uint32_t aCharIndex)
|
||||
MOZ_ASSERT(mActor);
|
||||
SpeechSynthesisRequestParent* actor = mActor;
|
||||
mActor = nullptr;
|
||||
NS_ENSURE_TRUE(actor->Send__delete__(actor, true, aElapsedTime, aCharIndex),
|
||||
NS_ERROR_FAILURE);
|
||||
if(NS_WARN_IF(!(actor->Send__delete__(actor, true, aElapsedTime, aCharIndex)))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -175,8 +183,9 @@ SpeechTaskParent::DispatchBoundaryImpl(const nsAString& aName,
|
||||
float aElapsedTime, uint32_t aCharIndex)
|
||||
{
|
||||
MOZ_ASSERT(mActor);
|
||||
NS_ENSURE_TRUE(mActor->SendOnBoundary(nsString(aName), aElapsedTime, aCharIndex),
|
||||
NS_ERROR_FAILURE);
|
||||
if(NS_WARN_IF(!(mActor->SendOnBoundary(nsString(aName), aElapsedTime, aCharIndex)))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
@ -186,8 +195,9 @@ SpeechTaskParent::DispatchMarkImpl(const nsAString& aName,
|
||||
float aElapsedTime, uint32_t aCharIndex)
|
||||
{
|
||||
MOZ_ASSERT(mActor);
|
||||
NS_ENSURE_TRUE(mActor->SendOnMark(nsString(aName), aElapsedTime, aCharIndex),
|
||||
NS_ERROR_FAILURE);
|
||||
if(NS_WARN_IF(!(mActor->SendOnMark(nsString(aName), aElapsedTime, aCharIndex)))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -165,7 +165,9 @@ nsSpeechTask::Setup(nsISpeechTaskCallback* aCallback,
|
||||
mStream->AddListener(new SynthStreamListener(this));
|
||||
|
||||
// XXX: Support more than one channel
|
||||
NS_ENSURE_TRUE(aChannels == 1, NS_ERROR_FAILURE);
|
||||
if(NS_WARN_IF(!(aChannels == 1))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
mChannels = aChannels;
|
||||
|
||||
@ -197,10 +199,18 @@ nsSpeechTask::SendAudio(JS::Handle<JS::Value> aData, JS::Handle<JS::Value> aLand
|
||||
{
|
||||
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
||||
|
||||
NS_ENSURE_TRUE(mStream, NS_ERROR_NOT_AVAILABLE);
|
||||
NS_ENSURE_FALSE(mStream->IsDestroyed(), NS_ERROR_NOT_AVAILABLE);
|
||||
NS_ENSURE_TRUE(mChannels, NS_ERROR_FAILURE);
|
||||
NS_ENSURE_TRUE(aData.isObject(), NS_ERROR_INVALID_ARG);
|
||||
if(NS_WARN_IF(!(mStream))) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
if(NS_WARN_IF(mStream->IsDestroyed())) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
if(NS_WARN_IF(!(mChannels))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
if(NS_WARN_IF(!(aData.isObject()))) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
if (mIndirectAudio) {
|
||||
NS_WARNING("Can't call SendAudio from an indirect audio speech service.");
|
||||
@ -239,9 +249,15 @@ nsSpeechTask::SendAudioNative(int16_t* aData, uint32_t aDataLen)
|
||||
{
|
||||
MOZ_ASSERT(XRE_GetProcessType() == GeckoProcessType_Default);
|
||||
|
||||
NS_ENSURE_TRUE(mStream, NS_ERROR_NOT_AVAILABLE);
|
||||
NS_ENSURE_FALSE(mStream->IsDestroyed(), NS_ERROR_NOT_AVAILABLE);
|
||||
NS_ENSURE_TRUE(mChannels, NS_ERROR_FAILURE);
|
||||
if(NS_WARN_IF(!(mStream))) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
if(NS_WARN_IF(mStream->IsDestroyed())) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
if(NS_WARN_IF(!(mChannels))) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (mIndirectAudio) {
|
||||
NS_WARNING("Can't call SendAudio from an indirect audio speech service.");
|
||||
@ -293,8 +309,9 @@ nsSpeechTask::DispatchStartImpl(const nsAString& aUri)
|
||||
LOG(LogLevel::Debug, ("nsSpeechTask::DispatchStart"));
|
||||
|
||||
MOZ_ASSERT(mUtterance);
|
||||
NS_ENSURE_TRUE(mUtterance->mState == SpeechSynthesisUtterance::STATE_PENDING,
|
||||
NS_ERROR_NOT_AVAILABLE);
|
||||
if(NS_WARN_IF(!(mUtterance->mState == SpeechSynthesisUtterance::STATE_PENDING))) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
mUtterance->mState = SpeechSynthesisUtterance::STATE_SPEAKING;
|
||||
mUtterance->mChosenVoiceURI = aUri;
|
||||
@ -321,8 +338,9 @@ nsSpeechTask::DispatchEndImpl(float aElapsedTime, uint32_t aCharIndex)
|
||||
LOG(LogLevel::Debug, ("nsSpeechTask::DispatchEnd\n"));
|
||||
|
||||
MOZ_ASSERT(mUtterance);
|
||||
NS_ENSURE_FALSE(mUtterance->mState == SpeechSynthesisUtterance::STATE_ENDED,
|
||||
NS_ERROR_NOT_AVAILABLE);
|
||||
if(NS_WARN_IF(mUtterance->mState == SpeechSynthesisUtterance::STATE_ENDED)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
// XXX: This should not be here, but it prevents a crash in MSG.
|
||||
if (mStream) {
|
||||
@ -363,9 +381,12 @@ nsSpeechTask::DispatchPauseImpl(float aElapsedTime, uint32_t aCharIndex)
|
||||
{
|
||||
LOG(LogLevel::Debug, ("nsSpeechTask::DispatchPause"));
|
||||
MOZ_ASSERT(mUtterance);
|
||||
NS_ENSURE_FALSE(mUtterance->mPaused, NS_ERROR_NOT_AVAILABLE);
|
||||
NS_ENSURE_FALSE(mUtterance->mState == SpeechSynthesisUtterance::STATE_ENDED,
|
||||
NS_ERROR_NOT_AVAILABLE);
|
||||
if(NS_WARN_IF(mUtterance->mPaused)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
if(NS_WARN_IF(mUtterance->mState == SpeechSynthesisUtterance::STATE_ENDED)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
mUtterance->mPaused = true;
|
||||
mUtterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("pause"),
|
||||
@ -390,9 +411,12 @@ nsSpeechTask::DispatchResumeImpl(float aElapsedTime, uint32_t aCharIndex)
|
||||
{
|
||||
LOG(LogLevel::Debug, ("nsSpeechTask::DispatchResume"));
|
||||
MOZ_ASSERT(mUtterance);
|
||||
NS_ENSURE_TRUE(mUtterance->mPaused, NS_ERROR_NOT_AVAILABLE);
|
||||
NS_ENSURE_FALSE(mUtterance->mState == SpeechSynthesisUtterance::STATE_ENDED,
|
||||
NS_ERROR_NOT_AVAILABLE);
|
||||
if(NS_WARN_IF(!(mUtterance->mPaused))) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
if(NS_WARN_IF(mUtterance->mState == SpeechSynthesisUtterance::STATE_ENDED)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
mUtterance->mPaused = false;
|
||||
mUtterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("resume"),
|
||||
@ -416,8 +440,9 @@ nsresult
|
||||
nsSpeechTask::DispatchErrorImpl(float aElapsedTime, uint32_t aCharIndex)
|
||||
{
|
||||
MOZ_ASSERT(mUtterance);
|
||||
NS_ENSURE_FALSE(mUtterance->mState == SpeechSynthesisUtterance::STATE_ENDED,
|
||||
NS_ERROR_NOT_AVAILABLE);
|
||||
if(NS_WARN_IF(mUtterance->mState == SpeechSynthesisUtterance::STATE_ENDED)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
mUtterance->mState = SpeechSynthesisUtterance::STATE_ENDED;
|
||||
mUtterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("error"),
|
||||
@ -443,8 +468,9 @@ nsSpeechTask::DispatchBoundaryImpl(const nsAString& aName,
|
||||
float aElapsedTime, uint32_t aCharIndex)
|
||||
{
|
||||
MOZ_ASSERT(mUtterance);
|
||||
NS_ENSURE_TRUE(mUtterance->mState == SpeechSynthesisUtterance::STATE_SPEAKING,
|
||||
NS_ERROR_NOT_AVAILABLE);
|
||||
if(NS_WARN_IF(!(mUtterance->mState == SpeechSynthesisUtterance::STATE_SPEAKING))) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
mUtterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("boundary"),
|
||||
aCharIndex, aElapsedTime,
|
||||
@ -469,8 +495,9 @@ nsSpeechTask::DispatchMarkImpl(const nsAString& aName,
|
||||
float aElapsedTime, uint32_t aCharIndex)
|
||||
{
|
||||
MOZ_ASSERT(mUtterance);
|
||||
NS_ENSURE_TRUE(mUtterance->mState == SpeechSynthesisUtterance::STATE_SPEAKING,
|
||||
NS_ERROR_NOT_AVAILABLE);
|
||||
if(NS_WARN_IF(!(mUtterance->mState == SpeechSynthesisUtterance::STATE_SPEAKING))) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
mUtterance->DispatchSpeechSynthesisEvent(NS_LITERAL_STRING("mark"),
|
||||
aCharIndex, aElapsedTime,
|
||||
|
@ -236,8 +236,9 @@ nsSynthVoiceRegistry::AddVoice(nsISpeechService* aService,
|
||||
NS_ConvertUTF16toUTF8(aLang).get(),
|
||||
aLocalService ? "true" : "false"));
|
||||
|
||||
NS_ENSURE_FALSE(XRE_GetProcessType() == GeckoProcessType_Content,
|
||||
NS_ERROR_NOT_AVAILABLE);
|
||||
if(NS_WARN_IF(XRE_GetProcessType() == GeckoProcessType_Content)) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return AddVoiceImpl(aService, aUri, aName, aLang,
|
||||
aLocalService);
|
||||
@ -255,8 +256,12 @@ nsSynthVoiceRegistry::RemoveVoice(nsISpeechService* aService,
|
||||
bool found = false;
|
||||
VoiceData* retval = mUriVoiceMap.GetWeak(aUri, &found);
|
||||
|
||||
NS_ENSURE_TRUE(found, NS_ERROR_NOT_AVAILABLE);
|
||||
NS_ENSURE_TRUE(aService == retval->mService, NS_ERROR_INVALID_ARG);
|
||||
if(NS_WARN_IF(!(found))) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
if(NS_WARN_IF(!(aService == retval->mService))) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
mVoices.RemoveElement(retval);
|
||||
mDefaultVoices.RemoveElement(retval);
|
||||
@ -277,7 +282,9 @@ nsSynthVoiceRegistry::SetDefaultVoice(const nsAString& aUri,
|
||||
{
|
||||
bool found = false;
|
||||
VoiceData* retval = mUriVoiceMap.GetWeak(aUri, &found);
|
||||
NS_ENSURE_TRUE(found, NS_ERROR_NOT_AVAILABLE);
|
||||
if(NS_WARN_IF(!(found))) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
mDefaultVoices.RemoveElement(retval);
|
||||
|
||||
@ -312,7 +319,9 @@ nsSynthVoiceRegistry::GetVoiceCount(uint32_t* aRetval)
|
||||
NS_IMETHODIMP
|
||||
nsSynthVoiceRegistry::GetVoice(uint32_t aIndex, nsAString& aRetval)
|
||||
{
|
||||
NS_ENSURE_TRUE(aIndex < mVoices.Length(), NS_ERROR_INVALID_ARG);
|
||||
if(NS_WARN_IF(!(aIndex < mVoices.Length()))) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
aRetval = mVoices[aIndex]->mUri;
|
||||
|
||||
@ -324,7 +333,9 @@ nsSynthVoiceRegistry::IsDefaultVoice(const nsAString& aUri, bool* aRetval)
|
||||
{
|
||||
bool found;
|
||||
VoiceData* voice = mUriVoiceMap.GetWeak(aUri, &found);
|
||||
NS_ENSURE_TRUE(found, NS_ERROR_NOT_AVAILABLE);
|
||||
if(NS_WARN_IF(!(found))) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
for (int32_t i = mDefaultVoices.Length(); i > 0; ) {
|
||||
VoiceData* defaultVoice = mDefaultVoices[--i];
|
||||
@ -344,7 +355,9 @@ nsSynthVoiceRegistry::IsLocalVoice(const nsAString& aUri, bool* aRetval)
|
||||
{
|
||||
bool found;
|
||||
VoiceData* voice = mUriVoiceMap.GetWeak(aUri, &found);
|
||||
NS_ENSURE_TRUE(found, NS_ERROR_NOT_AVAILABLE);
|
||||
if(NS_WARN_IF(!(found))) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
*aRetval = voice->mIsLocal;
|
||||
return NS_OK;
|
||||
@ -355,7 +368,9 @@ nsSynthVoiceRegistry::GetVoiceLang(const nsAString& aUri, nsAString& aRetval)
|
||||
{
|
||||
bool found;
|
||||
VoiceData* voice = mUriVoiceMap.GetWeak(aUri, &found);
|
||||
NS_ENSURE_TRUE(found, NS_ERROR_NOT_AVAILABLE);
|
||||
if(NS_WARN_IF(!(found))) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
aRetval = voice->mLang;
|
||||
return NS_OK;
|
||||
@ -366,7 +381,9 @@ nsSynthVoiceRegistry::GetVoiceName(const nsAString& aUri, nsAString& aRetval)
|
||||
{
|
||||
bool found;
|
||||
VoiceData* voice = mUriVoiceMap.GetWeak(aUri, &found);
|
||||
NS_ENSURE_TRUE(found, NS_ERROR_NOT_AVAILABLE);
|
||||
if(NS_WARN_IF(!(found))) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
aRetval = voice->mName;
|
||||
return NS_OK;
|
||||
@ -381,7 +398,9 @@ nsSynthVoiceRegistry::AddVoiceImpl(nsISpeechService* aService,
|
||||
{
|
||||
bool found = false;
|
||||
mUriVoiceMap.GetWeak(aUri, &found);
|
||||
NS_ENSURE_FALSE(found, NS_ERROR_INVALID_ARG);
|
||||
if(NS_WARN_IF(found)) {
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
}
|
||||
|
||||
nsRefPtr<VoiceData> voice = new VoiceData(aService, aUri, aName, aLang,
|
||||
aLocalService);
|
||||
@ -477,11 +496,15 @@ nsSynthVoiceRegistry::FindBestMatch(const nsAString& aUri,
|
||||
// Try UI language.
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsILocaleService> localeService = do_GetService(NS_LOCALESERVICE_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsAutoString uiLang;
|
||||
rv = localeService->GetLocaleComponentForUserAgent(uiLang);
|
||||
NS_ENSURE_SUCCESS(rv, nullptr);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (FindVoiceByLang(uiLang, &retval)) {
|
||||
LOG(LogLevel::Debug,
|
||||
|
@ -451,7 +451,9 @@ nsPicoService::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
const char16_t* aData)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
NS_ENSURE_TRUE(!strcmp(aTopic, "profile-after-change"), NS_ERROR_UNEXPECTED);
|
||||
if(NS_WARN_IF(!(!strcmp(aTopic, "profile-after-change")))) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (!Preferences::GetBool("media.webspeech.synth.enabled") ||
|
||||
Preferences::GetBool("media.webspeech.synth.test")) {
|
||||
@ -470,12 +472,16 @@ nsPicoService::Speak(const nsAString& aText, const nsAString& aUri,
|
||||
float aVolume, float aRate, float aPitch,
|
||||
nsISpeechTask* aTask)
|
||||
{
|
||||
NS_ENSURE_TRUE(mInitialized, NS_ERROR_NOT_AVAILABLE);
|
||||
if(NS_WARN_IF(!(mInitialized))) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
MonitorAutoLock autoLock(mVoicesMonitor);
|
||||
bool found = false;
|
||||
PicoVoice* voice = mVoices.GetWeak(aUri, &found);
|
||||
NS_ENSURE_TRUE(found, NS_ERROR_NOT_AVAILABLE);
|
||||
if(NS_WARN_IF(!(found))) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
mCurrentTask = aTask;
|
||||
nsRefPtr<PicoCallbackRunnable> cb = new PicoCallbackRunnable(aText, voice, aRate, aPitch, aTask, this);
|
||||
|
@ -27,6 +27,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=525444
|
||||
|
||||
ok(SpeechSynthesis, "SpeechSynthesis exists in global scope");
|
||||
ok(SpeechSynthesisVoice, "SpeechSynthesisVoice exists in global scope");
|
||||
ok(SpeechSynthesisErrorEvent, "SpeechSynthesisErrorEvent exists in global scope");
|
||||
ok(SpeechSynthesisEvent, "SpeechSynthesisEvent exists in global scope");
|
||||
|
||||
// SpeechSynthesisUtterance is the only type that has a constructor
|
||||
|
@ -311,7 +311,9 @@ nsFakeSynthServices::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
const char16_t* aData)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
NS_ENSURE_TRUE(!strcmp(aTopic, "profile-after-change"), NS_ERROR_UNEXPECTED);
|
||||
if(NS_WARN_IF(!(!strcmp(aTopic, "profile-after-change")))) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (Preferences::GetBool("media.webspeech.synth.test")) {
|
||||
Init();
|
||||
|
@ -964,6 +964,8 @@ var interfaceNamesInGlobalScope =
|
||||
{name: "SourceBuffer", linux: false, release: false},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "SourceBufferList", linux: false, release: false},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "SpeechSynthesisErrorEvent", b2g: true},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
{name: "SpeechSynthesisEvent", b2g: true},
|
||||
// IMPORTANT: Do not change this list without review from a DOM peer!
|
||||
|
36
dom/webidl/SpeechSynthesisErrorEvent.webidl
Normal file
36
dom/webidl/SpeechSynthesisErrorEvent.webidl
Normal file
@ -0,0 +1,36 @@
|
||||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* http://dvcs.w3.org/hg/speech-api/raw-file/tip/speechapi.html
|
||||
*
|
||||
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
|
||||
* liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
enum SpeechSynthesisErrorCode {
|
||||
"canceled",
|
||||
"interrupted",
|
||||
"audio-busy",
|
||||
"audio-hardware",
|
||||
"network",
|
||||
"synthesis-unavailable",
|
||||
"synthesis-failed",
|
||||
"language-unavailable",
|
||||
"voice-unavailable",
|
||||
"text-too-long",
|
||||
"invalid-argument",
|
||||
};
|
||||
|
||||
[Constructor(DOMString type, optional SpeechSynthesisErrorEventInit eventInitDict),
|
||||
Pref="media.webspeech.synth.enabled"]
|
||||
interface SpeechSynthesisErrorEvent : SpeechSynthesisEvent {
|
||||
readonly attribute SpeechSynthesisErrorCode error;
|
||||
};
|
||||
|
||||
dictionary SpeechSynthesisErrorEventInit : SpeechSynthesisEventInit
|
||||
{
|
||||
required SpeechSynthesisErrorCode error;
|
||||
};
|
@ -14,6 +14,7 @@
|
||||
Pref="media.webspeech.synth.enabled"]
|
||||
interface SpeechSynthesisEvent : Event
|
||||
{
|
||||
readonly attribute SpeechSynthesisUtterance utterance;
|
||||
readonly attribute unsigned long charIndex;
|
||||
readonly attribute float elapsedTime;
|
||||
readonly attribute DOMString? name;
|
||||
@ -21,6 +22,7 @@ interface SpeechSynthesisEvent : Event
|
||||
|
||||
dictionary SpeechSynthesisEventInit : EventInit
|
||||
{
|
||||
required SpeechSynthesisUtterance utterance;
|
||||
unsigned long charIndex = 0;
|
||||
float elapsedTime = 0;
|
||||
DOMString name = "";
|
||||
|
@ -611,6 +611,7 @@ if CONFIG['MOZ_WEBSPEECH']:
|
||||
'SpeechRecognitionResult.webidl',
|
||||
'SpeechRecognitionResultList.webidl',
|
||||
'SpeechSynthesis.webidl',
|
||||
'SpeechSynthesisErrorEvent.webidl',
|
||||
'SpeechSynthesisEvent.webidl',
|
||||
'SpeechSynthesisUtterance.webidl',
|
||||
'SpeechSynthesisVoice.webidl',
|
||||
@ -788,6 +789,7 @@ GENERATED_EVENTS_WEBIDL_FILES = [
|
||||
if CONFIG['MOZ_WEBSPEECH']:
|
||||
GENERATED_EVENTS_WEBIDL_FILES += [
|
||||
'SpeechRecognitionEvent.webidl',
|
||||
'SpeechSynthesisErrorEvent.webidl',
|
||||
'SpeechSynthesisEvent.webidl',
|
||||
]
|
||||
|
||||
|
@ -60,11 +60,6 @@ static inline int floor_div(int a, int b)
|
||||
}
|
||||
}
|
||||
|
||||
// An abstract implementation of a tile buffer. This code covers the logic of
|
||||
// moving and reusing tiles and leaves the validation up to the implementor. To
|
||||
// avoid the overhead of virtual dispatch, we employ the curiously recurring
|
||||
// template pattern.
|
||||
//
|
||||
// Tiles are aligned to a grid with one of the grid points at (0,0) and other
|
||||
// grid points spaced evenly in the x- and y-directions by GetTileSize()
|
||||
// multiplied by mResolution. GetScaledTileSize() provides convenience for
|
||||
@ -82,30 +77,6 @@ static inline int floor_div(int a, int b)
|
||||
// the tile type should be a reference or some other type with an efficient
|
||||
// copy constructor.
|
||||
//
|
||||
// It is required that the derived class specify the base class as a friend. It
|
||||
// must also implement the following public method:
|
||||
//
|
||||
// Tile GetPlaceholderTile() const;
|
||||
//
|
||||
// Returns a temporary placeholder tile used as a marker. This placeholder tile
|
||||
// must never be returned by validateTile and must be == to every instance
|
||||
// of a placeholder tile.
|
||||
//
|
||||
// Additionally, it must implement the following protected methods:
|
||||
//
|
||||
// Tile ValidateTile(Tile aTile, const nsIntPoint& aTileOrigin,
|
||||
// const nsIntRegion& aDirtyRect);
|
||||
//
|
||||
// Validates the dirtyRect. The returned Tile will replace the tile.
|
||||
//
|
||||
// void ReleaseTile(Tile aTile);
|
||||
//
|
||||
// Destroys the given tile.
|
||||
//
|
||||
// void SwapTiles(Tile& aTileA, Tile& aTileB);
|
||||
//
|
||||
// Swaps two tiles.
|
||||
//
|
||||
// The contents of the tile buffer will be rendered at the resolution specified
|
||||
// in mResolution, which can be altered with SetResolution. The resolution
|
||||
// should always be a factor of the tile length, to avoid tiles covering
|
||||
@ -146,12 +117,23 @@ struct TilesPlacement {
|
||||
);
|
||||
}
|
||||
|
||||
bool HasTile(TileIntPoint aPosition) {
|
||||
bool HasTile(TileIntPoint aPosition) const {
|
||||
return aPosition.x >= mFirst.x && aPosition.x < mFirst.x + mSize.width &&
|
||||
aPosition.y >= mFirst.y && aPosition.y < mFirst.y + mSize.height;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// Given a position i, this function returns the position inside the current tile.
|
||||
inline int GetTileStart(int i, int aTileLength) {
|
||||
return (i >= 0) ? (i % aTileLength)
|
||||
: ((aTileLength - (-i % aTileLength)) %
|
||||
aTileLength);
|
||||
}
|
||||
|
||||
// Rounds the given coordinate down to the nearest tile boundary.
|
||||
inline int RoundDownToTileEdge(int aX, int aTileLength) { return aX - GetTileStart(aX, aTileLength); }
|
||||
|
||||
template<typename Derived, typename Tile>
|
||||
class TiledLayerBuffer
|
||||
{
|
||||
@ -165,21 +147,6 @@ public:
|
||||
|
||||
~TiledLayerBuffer() {}
|
||||
|
||||
// Given a tile origin aligned to a multiple of GetScaledTileSize,
|
||||
// return the tile that describes that region.
|
||||
// NOTE: To get the valid area of that tile you must intersect
|
||||
// (aTileOrigin.x, aTileOrigin.y,
|
||||
// GetScaledTileSize().width, GetScaledTileSize().height)
|
||||
// and GetValidRegion() to get the area of the tile that is valid.
|
||||
Tile& GetTile(const gfx::IntPoint& aTileOrigin);
|
||||
// Given a tile x, y relative to the top left of the layer, this function
|
||||
// will return the tile for
|
||||
// (x*GetScaledTileSize().width, y*GetScaledTileSize().height,
|
||||
// GetScaledTileSize().width, GetScaledTileSize().height)
|
||||
Tile& GetTile(int x, int y);
|
||||
|
||||
Tile& GetTile(size_t i) { return mRetainedTiles[i]; }
|
||||
|
||||
gfx::IntPoint GetTileOffset(TileIntPoint aPosition) const {
|
||||
gfx::IntSize scaledTileSize = GetScaledTileSize();
|
||||
return gfx::IntPoint(aPosition.x * scaledTileSize.width,
|
||||
@ -188,48 +155,18 @@ public:
|
||||
|
||||
const TilesPlacement& GetPlacement() const { return mTiles; }
|
||||
|
||||
int TileIndex(const gfx::IntPoint& aTileOrigin) const;
|
||||
int TileIndex(int x, int y) const { return x * mTiles.mSize.height + y; }
|
||||
|
||||
bool HasTile(int index) const { return index >= 0 && index < (int)mRetainedTiles.Length(); }
|
||||
bool HasTile(const gfx::IntPoint& aTileOrigin) const;
|
||||
bool HasTile(int x, int y) const {
|
||||
return x >= 0 && x < mTiles.mSize.width && y >= 0 && y < mTiles.mSize.height;
|
||||
}
|
||||
|
||||
const gfx::IntSize& GetTileSize() const { return mTileSize; }
|
||||
|
||||
gfx::IntSize GetScaledTileSize() const { return RoundedToInt(gfx::Size(mTileSize) / mResolution); }
|
||||
|
||||
unsigned int GetTileCount() const { return mRetainedTiles.Length(); }
|
||||
|
||||
Tile& GetTile(size_t i) { return mRetainedTiles[i]; }
|
||||
|
||||
const nsIntRegion& GetValidRegion() const { return mValidRegion; }
|
||||
const nsIntRegion& GetPaintedRegion() const { return mPaintedRegion; }
|
||||
void ClearPaintedRegion() { mPaintedRegion.SetEmpty(); }
|
||||
|
||||
void ResetPaintedAndValidState() {
|
||||
mPaintedRegion.SetEmpty();
|
||||
mValidRegion.SetEmpty();
|
||||
mTiles.mSize.width = 0;
|
||||
mTiles.mSize.height = 0;
|
||||
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
|
||||
if (!mRetainedTiles[i].IsPlaceholderTile()) {
|
||||
AsDerived().ReleaseTile(mRetainedTiles[i]);
|
||||
}
|
||||
}
|
||||
mRetainedTiles.Clear();
|
||||
}
|
||||
|
||||
// Given a position i, this function returns the position inside the current tile.
|
||||
int GetTileStart(int i, int aTileLength) const {
|
||||
return (i >= 0) ? (i % aTileLength)
|
||||
: ((aTileLength - (-i % aTileLength)) %
|
||||
aTileLength);
|
||||
}
|
||||
|
||||
// Rounds the given coordinate down to the nearest tile boundary.
|
||||
int RoundDownToTileEdge(int aX, int aTileLength) const { return aX - GetTileStart(aX, aTileLength); }
|
||||
|
||||
// Get and set draw scaling. mResolution affects the resolution at which the
|
||||
// contents of the buffer are drawn. mResolution has no effect on the
|
||||
// coordinate space of the valid region, but does affect the size of an
|
||||
@ -238,22 +175,9 @@ public:
|
||||
float GetResolution() const { return mResolution; }
|
||||
bool IsLowPrecision() const { return mResolution < 1; }
|
||||
|
||||
typedef Tile* Iterator;
|
||||
Iterator TilesBegin() { return mRetainedTiles.Elements(); }
|
||||
Iterator TilesEnd() { return mRetainedTiles.Elements() + mRetainedTiles.Length(); }
|
||||
|
||||
void Dump(std::stringstream& aStream, const char* aPrefix, bool aDumpHtml);
|
||||
|
||||
protected:
|
||||
// The implementor should call Update() to change
|
||||
// the new valid region. This implementation will call
|
||||
// validateTile on each tile that is dirty, which is left
|
||||
// to the implementor.
|
||||
void Update(const nsIntRegion& aNewValidRegion, const nsIntRegion& aPaintRegion);
|
||||
|
||||
// Return a reference to this tile in GetTile when the requested tile offset
|
||||
// does not exist.
|
||||
Tile mPlaceHolderTile;
|
||||
|
||||
nsIntRegion mValidRegion;
|
||||
nsIntRegion mPaintedRegion;
|
||||
@ -270,411 +194,25 @@ protected:
|
||||
TilesPlacement mTiles;
|
||||
float mResolution;
|
||||
gfx::IntSize mTileSize;
|
||||
|
||||
private:
|
||||
const Derived& AsDerived() const { return *static_cast<const Derived*>(this); }
|
||||
Derived& AsDerived() { return *static_cast<Derived*>(this); }
|
||||
};
|
||||
|
||||
class ClientTiledLayerBuffer;
|
||||
class SurfaceDescriptorTiles;
|
||||
class ISurfaceAllocator;
|
||||
|
||||
// Shadow layers may implement this interface in order to be notified when a
|
||||
// tiled layer buffer is updated.
|
||||
class TiledLayerComposer
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Update the current retained layer with the updated layer data.
|
||||
* It is expected that the tiles described by aTiledDescriptor are all in the
|
||||
* ReadLock state, so that the locks can be adopted when recreating a
|
||||
* ClientTiledLayerBuffer locally. This lock will be retained until the buffer
|
||||
* has completed uploading.
|
||||
*
|
||||
* Returns false if a deserialization error happened, in which case we will
|
||||
* have to kill the child process.
|
||||
*/
|
||||
virtual bool UseTiledLayerBuffer(ISurfaceAllocator* aAllocator,
|
||||
const SurfaceDescriptorTiles& aTiledDescriptor) = 0;
|
||||
|
||||
/**
|
||||
* If some part of the buffer is being rendered at a lower precision, this
|
||||
* returns that region. If it is not, an empty region will be returned.
|
||||
*/
|
||||
virtual const nsIntRegion& GetValidLowPrecisionRegion() const = 0;
|
||||
|
||||
virtual const nsIntRegion& GetValidRegion() const = 0;
|
||||
};
|
||||
|
||||
template<typename Derived, typename Tile> bool
|
||||
TiledLayerBuffer<Derived, Tile>::HasTile(const gfx::IntPoint& aTileOrigin) const {
|
||||
gfx::IntSize scaledTileSize = GetScaledTileSize();
|
||||
return HasTile(floor_div(aTileOrigin.x, scaledTileSize.width) - mTiles.mFirst.x,
|
||||
floor_div(aTileOrigin.y, scaledTileSize.height) - mTiles.mFirst.y);
|
||||
}
|
||||
|
||||
template<typename Derived, typename Tile> Tile&
|
||||
TiledLayerBuffer<Derived, Tile>::GetTile(const nsIntPoint& aTileOrigin)
|
||||
{
|
||||
if (HasTile(aTileOrigin)) {
|
||||
return mRetainedTiles[TileIndex(aTileOrigin)];
|
||||
}
|
||||
return mPlaceHolderTile;
|
||||
}
|
||||
|
||||
template<typename Derived, typename Tile> int
|
||||
TiledLayerBuffer<Derived, Tile>::TileIndex(const gfx::IntPoint& aTileOrigin) const
|
||||
{
|
||||
// Find the tile x/y of the first tile and the target tile relative to the (0, 0)
|
||||
// origin, the difference is the tile x/y relative to the start of the tile buffer.
|
||||
gfx::IntSize scaledTileSize = GetScaledTileSize();
|
||||
return TileIndex(floor_div(aTileOrigin.x, scaledTileSize.width) - mTiles.mFirst.x,
|
||||
floor_div(aTileOrigin.y, scaledTileSize.height) - mTiles.mFirst.y);
|
||||
}
|
||||
|
||||
template<typename Derived, typename Tile> Tile&
|
||||
TiledLayerBuffer<Derived, Tile>::GetTile(int x, int y)
|
||||
{
|
||||
if (HasTile(x, y)) {
|
||||
return mRetainedTiles[TileIndex(x, y)];
|
||||
}
|
||||
return mPlaceHolderTile;
|
||||
}
|
||||
|
||||
template<typename Derived, typename Tile> void
|
||||
TiledLayerBuffer<Derived, Tile>::Dump(std::stringstream& aStream,
|
||||
const char* aPrefix,
|
||||
bool aDumpHtml)
|
||||
{
|
||||
gfx::IntRect visibleRect = GetValidRegion().GetBounds();
|
||||
gfx::IntSize scaledTileSize = GetScaledTileSize();
|
||||
for (int32_t x = visibleRect.x; x < visibleRect.x + visibleRect.width;) {
|
||||
int32_t tileStartX = GetTileStart(x, scaledTileSize.width);
|
||||
int32_t w = scaledTileSize.width - tileStartX;
|
||||
for (size_t i = 0; i < mRetainedTiles.Length(); ++i) {
|
||||
const TileIntPoint tilePosition = mTiles.TilePosition(i);
|
||||
gfx::IntPoint tileOffset = GetTileOffset(tilePosition);
|
||||
|
||||
for (int32_t y = visibleRect.y; y < visibleRect.y + visibleRect.height;) {
|
||||
int32_t tileStartY = GetTileStart(y, scaledTileSize.height);
|
||||
nsIntPoint tileOrigin = nsIntPoint(RoundDownToTileEdge(x, scaledTileSize.width),
|
||||
RoundDownToTileEdge(y, scaledTileSize.height));
|
||||
Tile& tileTexture = GetTile(tileOrigin);
|
||||
int32_t h = scaledTileSize.height - tileStartY;
|
||||
|
||||
aStream << "\n" << aPrefix << "Tile (x=" <<
|
||||
RoundDownToTileEdge(x, scaledTileSize.width) << ", y=" <<
|
||||
RoundDownToTileEdge(y, scaledTileSize.height) << "): ";
|
||||
if (!tileTexture.IsPlaceholderTile()) {
|
||||
tileTexture.DumpTexture(aStream);
|
||||
} else {
|
||||
aStream << "empty tile";
|
||||
}
|
||||
y += h;
|
||||
}
|
||||
x += w;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Derived, typename Tile> void
|
||||
TiledLayerBuffer<Derived, Tile>::Update(const nsIntRegion& newValidRegion,
|
||||
const nsIntRegion& aPaintRegion)
|
||||
{
|
||||
gfx::IntSize scaledTileSize = GetScaledTileSize();
|
||||
|
||||
nsTArray<Tile> newRetainedTiles;
|
||||
nsTArray<Tile>& oldRetainedTiles = mRetainedTiles;
|
||||
const gfx::IntRect oldBound = mValidRegion.GetBounds();
|
||||
const gfx::IntRect newBound = newValidRegion.GetBounds();
|
||||
const nsIntPoint oldBufferOrigin(RoundDownToTileEdge(oldBound.x, scaledTileSize.width),
|
||||
RoundDownToTileEdge(oldBound.y, scaledTileSize.height));
|
||||
const nsIntPoint newBufferOrigin(RoundDownToTileEdge(newBound.x, scaledTileSize.width),
|
||||
RoundDownToTileEdge(newBound.y, scaledTileSize.height));
|
||||
|
||||
// This is the reason we break the style guide with newValidRegion instead
|
||||
// of aNewValidRegion - so that the names match better and code easier to read
|
||||
const nsIntRegion& oldValidRegion = mValidRegion;
|
||||
const int oldRetainedHeight = mTiles.mSize.height;
|
||||
|
||||
#ifdef GFX_TILEDLAYER_RETAINING_LOG
|
||||
{ // scope ss
|
||||
std::stringstream ss;
|
||||
ss << "TiledLayerBuffer " << this << " starting update"
|
||||
<< " on bounds ";
|
||||
AppendToString(ss, newBound);
|
||||
ss << " with mResolution=" << mResolution << "\n";
|
||||
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
|
||||
ss << "mRetainedTiles[" << i << "] = ";
|
||||
mRetainedTiles[i].Dump(ss);
|
||||
ss << "\n";
|
||||
}
|
||||
print_stderr(ss);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Pass 1: Recycle valid content from the old buffer
|
||||
// Recycle tiles from the old buffer that contain valid regions.
|
||||
// Insert placeholders tiles if we have no valid area for that tile
|
||||
// which we will allocate in pass 2.
|
||||
// TODO: Add a tile pool to reduce new allocation
|
||||
int tileX = 0;
|
||||
int tileY = 0;
|
||||
int tilesMissing = 0;
|
||||
// Iterate over the new drawing bounds in steps of tiles.
|
||||
for (int32_t x = newBound.x; x < newBound.XMost(); tileX++) {
|
||||
// Compute tileRect(x,y,width,height) in layer space coordinate
|
||||
// giving us the rect of the tile that hits the newBounds.
|
||||
int width = scaledTileSize.width - GetTileStart(x, scaledTileSize.width);
|
||||
if (x + width > newBound.XMost()) {
|
||||
width = newBound.x + newBound.width - x;
|
||||
}
|
||||
|
||||
tileY = 0;
|
||||
for (int32_t y = newBound.y; y < newBound.YMost(); tileY++) {
|
||||
int height = scaledTileSize.height - GetTileStart(y, scaledTileSize.height);
|
||||
if (y + height > newBound.y + newBound.height) {
|
||||
height = newBound.y + newBound.height - y;
|
||||
}
|
||||
|
||||
const gfx::IntRect tileRect(x,y,width,height);
|
||||
if (oldValidRegion.Intersects(tileRect) && newValidRegion.Intersects(tileRect)) {
|
||||
// This old tiles contains some valid area so move it to the new tile
|
||||
// buffer. Replace the tile in the old buffer with a placeholder
|
||||
// to leave the old buffer index unaffected.
|
||||
int tileX = floor_div(x - oldBufferOrigin.x, scaledTileSize.width);
|
||||
int tileY = floor_div(y - oldBufferOrigin.y, scaledTileSize.height);
|
||||
int index = tileX * oldRetainedHeight + tileY;
|
||||
|
||||
// The tile may have been removed, skip over it in this case.
|
||||
if (oldRetainedTiles.
|
||||
SafeElementAt(index, AsDerived().GetPlaceholderTile()).IsPlaceholderTile()) {
|
||||
newRetainedTiles.AppendElement(AsDerived().GetPlaceholderTile());
|
||||
} else {
|
||||
Tile tileWithPartialValidContent = oldRetainedTiles[index];
|
||||
newRetainedTiles.AppendElement(tileWithPartialValidContent);
|
||||
oldRetainedTiles[index] = AsDerived().GetPlaceholderTile();
|
||||
}
|
||||
|
||||
} else {
|
||||
// This tile is either:
|
||||
// 1) Outside the new valid region and will simply be an empty
|
||||
// placeholder forever.
|
||||
// 2) The old buffer didn't have any data for this tile. We postpone
|
||||
// the allocation of this tile after we've reused any tile with
|
||||
// valid content because then we know we can safely recycle
|
||||
// with taking from a tile that has recyclable content.
|
||||
newRetainedTiles.AppendElement(AsDerived().GetPlaceholderTile());
|
||||
|
||||
if (aPaintRegion.Intersects(tileRect)) {
|
||||
tilesMissing++;
|
||||
}
|
||||
}
|
||||
|
||||
y += height;
|
||||
}
|
||||
|
||||
x += width;
|
||||
}
|
||||
|
||||
// Keep track of the number of horizontal/vertical tiles
|
||||
// in the buffer so that we can easily look up a tile.
|
||||
mTiles.mSize.width = tileX;
|
||||
mTiles.mSize.height = tileY;
|
||||
|
||||
#ifdef GFX_TILEDLAYER_RETAINING_LOG
|
||||
{ // scope ss
|
||||
std::stringstream ss;
|
||||
ss << "TiledLayerBuffer " << this << " finished pass 1 of update;"
|
||||
<< " tilesMissing=" << tilesMissing << "\n";
|
||||
for (size_t i = 0; i < oldRetainedTiles.Length(); i++) {
|
||||
ss << "oldRetainedTiles[" << i << "] = ";
|
||||
oldRetainedTiles[i].Dump(ss);
|
||||
ss << "\n";
|
||||
}
|
||||
print_stderr(ss);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
// Pass 1.5: Release excess tiles in oldRetainedTiles
|
||||
// Tiles in oldRetainedTiles that aren't in newRetainedTiles will be recycled
|
||||
// before creating new ones, but there could still be excess unnecessary
|
||||
// tiles. As tiles may not have a fixed memory cost (for example, due to
|
||||
// double-buffering), we should release these excess tiles first.
|
||||
int oldTileCount = 0;
|
||||
for (size_t i = 0; i < oldRetainedTiles.Length(); i++) {
|
||||
Tile oldTile = oldRetainedTiles[i];
|
||||
if (oldTile.IsPlaceholderTile()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (oldTileCount >= tilesMissing) {
|
||||
oldRetainedTiles[i] = AsDerived().GetPlaceholderTile();
|
||||
AsDerived().ReleaseTile(oldTile);
|
||||
aStream << "\n" << aPrefix << "Tile (x=" <<
|
||||
tileOffset.x << ", y=" << tileOffset.y << "): ";
|
||||
if (!mRetainedTiles[i].IsPlaceholderTile()) {
|
||||
mRetainedTiles[i].DumpTexture(aStream);
|
||||
} else {
|
||||
oldTileCount ++;
|
||||
aStream << "empty tile";
|
||||
}
|
||||
}
|
||||
|
||||
if (!newValidRegion.Contains(aPaintRegion)) {
|
||||
gfxCriticalError() << "Painting outside visible:"
|
||||
<< " paint " << aPaintRegion.ToString().get()
|
||||
<< " old valid " << oldValidRegion.ToString().get()
|
||||
<< " new valid " << newValidRegion.ToString().get();
|
||||
}
|
||||
#ifdef DEBUG
|
||||
nsIntRegion oldAndPainted(oldValidRegion);
|
||||
oldAndPainted.Or(oldAndPainted, aPaintRegion);
|
||||
if (!oldAndPainted.Contains(newValidRegion)) {
|
||||
gfxCriticalError() << "Not fully painted:"
|
||||
<< " paint " << aPaintRegion.ToString().get()
|
||||
<< " old valid " << oldValidRegion.ToString().get()
|
||||
<< " old painted " << oldAndPainted.ToString().get()
|
||||
<< " new valid " << newValidRegion.ToString().get();
|
||||
}
|
||||
#endif
|
||||
|
||||
nsIntRegion regionToPaint(aPaintRegion);
|
||||
|
||||
#ifdef GFX_TILEDLAYER_RETAINING_LOG
|
||||
{ // scope ss
|
||||
std::stringstream ss;
|
||||
ss << "TiledLayerBuffer " << this << " finished pass 1.5 of update\n";
|
||||
for (size_t i = 0; i < oldRetainedTiles.Length(); i++) {
|
||||
ss << "oldRetainedTiles[" << i << "] = ";
|
||||
oldRetainedTiles[i].Dump(ss);
|
||||
ss << "\n";
|
||||
}
|
||||
for (size_t i = 0; i < newRetainedTiles.Length(); i++) {
|
||||
ss << "newRetainedTiles[" << i << "] = ";
|
||||
newRetainedTiles[i].Dump(ss);
|
||||
ss << "\n";
|
||||
}
|
||||
print_stderr(ss);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Pass 2: Validate
|
||||
// We know at this point that any tile in the new buffer that had valid content
|
||||
// from the previous buffer is placed correctly in the new buffer.
|
||||
// We know that any tile in the old buffer that isn't a place holder is
|
||||
// of no use and can be recycled.
|
||||
// We also know that any place holder tile in the new buffer must be
|
||||
// allocated.
|
||||
tileX = 0;
|
||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||
printf_stderr("Update %i, %i, %i, %i\n", newBound.x, newBound.y, newBound.width, newBound.height);
|
||||
#endif
|
||||
for (int x = newBound.x; x < newBound.x + newBound.width; tileX++) {
|
||||
// Compute tileRect(x,y,width,height) in layer space coordinate
|
||||
// giving us the rect of the tile that hits the newBounds.
|
||||
int tileStartX = RoundDownToTileEdge(x, scaledTileSize.width);
|
||||
int width = scaledTileSize.width - GetTileStart(x, scaledTileSize.width);
|
||||
if (x + width > newBound.XMost())
|
||||
width = newBound.XMost() - x;
|
||||
|
||||
tileY = 0;
|
||||
for (int y = newBound.y; y < newBound.y + newBound.height; tileY++) {
|
||||
int tileStartY = RoundDownToTileEdge(y, scaledTileSize.height);
|
||||
int height = scaledTileSize.height - GetTileStart(y, scaledTileSize.height);
|
||||
if (y + height > newBound.YMost()) {
|
||||
height = newBound.YMost() - y;
|
||||
}
|
||||
|
||||
const gfx::IntRect tileRect(x, y, width, height);
|
||||
|
||||
nsIntRegion tileDrawRegion;
|
||||
tileDrawRegion.And(tileRect, regionToPaint);
|
||||
|
||||
if (tileDrawRegion.IsEmpty()) {
|
||||
// We have a tile but it doesn't hit the draw region
|
||||
// because we can reuse all of the content from the
|
||||
// previous buffer.
|
||||
#ifdef DEBUG
|
||||
int currTileX = floor_div(x - newBufferOrigin.x, scaledTileSize.width);
|
||||
int currTileY = floor_div(y - newBufferOrigin.y, scaledTileSize.height);
|
||||
int index = TileIndex(currTileX, currTileY);
|
||||
// If allocating a tile failed we can run into this assertion.
|
||||
// Rendering is going to be glitchy but we don't want to crash.
|
||||
NS_ASSERTION(!newValidRegion.Intersects(tileRect) ||
|
||||
!newRetainedTiles.
|
||||
SafeElementAt(index, AsDerived().GetPlaceholderTile()).IsPlaceholderTile(),
|
||||
"Unexpected placeholder tile");
|
||||
|
||||
#endif
|
||||
y += height;
|
||||
continue;
|
||||
}
|
||||
|
||||
int tileX = floor_div(x - newBufferOrigin.x, scaledTileSize.width);
|
||||
int tileY = floor_div(y - newBufferOrigin.y, scaledTileSize.height);
|
||||
int index = TileIndex(tileX, tileY);
|
||||
MOZ_ASSERT(index >= 0 &&
|
||||
static_cast<unsigned>(index) < newRetainedTiles.Length(),
|
||||
"index out of range");
|
||||
|
||||
Tile newTile = newRetainedTiles[index];
|
||||
|
||||
// Try to reuse a tile from the old retained tiles that had no partially
|
||||
// valid content.
|
||||
while (newTile.IsPlaceholderTile() && oldRetainedTiles.Length() > 0) {
|
||||
AsDerived().SwapTiles(newTile, oldRetainedTiles[oldRetainedTiles.Length()-1]);
|
||||
oldRetainedTiles.RemoveElementAt(oldRetainedTiles.Length()-1);
|
||||
if (!newTile.IsPlaceholderTile()) {
|
||||
oldTileCount--;
|
||||
}
|
||||
}
|
||||
|
||||
// We've done our best effort to recycle a tile but it can be null
|
||||
// in which case it's up to the derived class's ValidateTile()
|
||||
// implementation to allocate a new tile before drawing
|
||||
nsIntPoint tileOrigin(tileStartX, tileStartY);
|
||||
newTile = AsDerived().ValidateTile(newTile, nsIntPoint(tileStartX, tileStartY),
|
||||
tileDrawRegion);
|
||||
NS_ASSERTION(!newTile.IsPlaceholderTile(), "Unexpected placeholder tile - failed to allocate?");
|
||||
#ifdef GFX_TILEDLAYER_PREF_WARNINGS
|
||||
printf_stderr("Store Validate tile %i, %i -> %i\n", tileStartX, tileStartY, index);
|
||||
#endif
|
||||
newRetainedTiles[index] = newTile;
|
||||
|
||||
y += height;
|
||||
}
|
||||
|
||||
x += width;
|
||||
}
|
||||
|
||||
AsDerived().PostValidate(aPaintRegion);
|
||||
for (unsigned int i = 0; i < newRetainedTiles.Length(); ++i) {
|
||||
AsDerived().UnlockTile(newRetainedTiles[i]);
|
||||
}
|
||||
|
||||
#ifdef GFX_TILEDLAYER_RETAINING_LOG
|
||||
{ // scope ss
|
||||
std::stringstream ss;
|
||||
ss << "TiledLayerBuffer " << this << " finished pass 2 of update;"
|
||||
<< " oldTileCount=" << oldTileCount << "\n";
|
||||
for (size_t i = 0; i < oldRetainedTiles.Length(); i++) {
|
||||
ss << "oldRetainedTiles[" << i << "] = ";
|
||||
oldRetainedTiles[i].Dump(ss);
|
||||
ss << "\n";
|
||||
}
|
||||
for (size_t i = 0; i < newRetainedTiles.Length(); i++) {
|
||||
ss << "newRetainedTiles[" << i << "] = ";
|
||||
newRetainedTiles[i].Dump(ss);
|
||||
ss << "\n";
|
||||
}
|
||||
print_stderr(ss);
|
||||
}
|
||||
#endif
|
||||
|
||||
// At this point, oldTileCount should be zero
|
||||
MOZ_ASSERT(oldTileCount == 0, "Failed to release old tiles");
|
||||
|
||||
mRetainedTiles = newRetainedTiles;
|
||||
mValidRegion = newValidRegion;
|
||||
|
||||
mTiles.mFirst.x = floor_div(mValidRegion.GetBounds().x, scaledTileSize.width);
|
||||
mTiles.mFirst.y = floor_div(mValidRegion.GetBounds().y, scaledTileSize.height);
|
||||
|
||||
mPaintedRegion.Or(mPaintedRegion, aPaintRegion);
|
||||
}
|
||||
|
||||
} // layers
|
||||
|
@ -1100,6 +1100,71 @@ ClientTiledLayerBuffer::UnlockTile(TileClient aTile)
|
||||
}
|
||||
}
|
||||
|
||||
void ClientTiledLayerBuffer::Update(const nsIntRegion& newValidRegion,
|
||||
const nsIntRegion& aPaintRegion)
|
||||
{
|
||||
const IntSize scaledTileSize = GetScaledTileSize();
|
||||
const gfx::IntRect newBounds = newValidRegion.GetBounds();
|
||||
|
||||
const TilesPlacement oldTiles = mTiles;
|
||||
const TilesPlacement newTiles(floor_div(newBounds.x, scaledTileSize.width),
|
||||
floor_div(newBounds.y, scaledTileSize.height),
|
||||
floor_div(GetTileStart(newBounds.x, scaledTileSize.width)
|
||||
+ newBounds.width, scaledTileSize.width) + 1,
|
||||
floor_div(GetTileStart(newBounds.y, scaledTileSize.height)
|
||||
+ newBounds.height, scaledTileSize.height) + 1);
|
||||
|
||||
const size_t oldTileCount = mRetainedTiles.Length();
|
||||
const size_t newTileCount = newTiles.mSize.width * newTiles.mSize.height;
|
||||
|
||||
nsTArray<TileClient> oldRetainedTiles;
|
||||
mRetainedTiles.SwapElements(oldRetainedTiles);
|
||||
mRetainedTiles.SetLength(newTileCount);
|
||||
|
||||
for (size_t oldIndex = 0; oldIndex < oldTileCount; oldIndex++) {
|
||||
const TileIntPoint tilePosition = oldTiles.TilePosition(oldIndex);
|
||||
const size_t newIndex = newTiles.TileIndex(tilePosition);
|
||||
// First, get the already existing tiles to the right place in the new array.
|
||||
// Leave placeholders (default constructor) where there was no tile.
|
||||
if (newTiles.HasTile(tilePosition)) {
|
||||
mRetainedTiles[newIndex] = oldRetainedTiles[oldIndex];
|
||||
} else {
|
||||
// release tiles that we are not going to reuse before allocating new ones
|
||||
// to avoid allocating unnecessarily.
|
||||
oldRetainedTiles[oldIndex].Release();
|
||||
}
|
||||
}
|
||||
|
||||
oldRetainedTiles.Clear();
|
||||
|
||||
for (size_t i = 0; i < newTileCount; ++i) {
|
||||
const TileIntPoint tilePosition = newTiles.TilePosition(i);
|
||||
|
||||
IntPoint tileOffset = GetTileOffset(tilePosition);
|
||||
nsIntRegion tileDrawRegion = IntRect(tileOffset, scaledTileSize);
|
||||
tileDrawRegion.AndWith(aPaintRegion);
|
||||
|
||||
if (tileDrawRegion.IsEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
TileClient tile = mRetainedTiles[i];
|
||||
tile = ValidateTile(tile, GetTileOffset(tilePosition),
|
||||
tileDrawRegion);
|
||||
|
||||
mRetainedTiles[i] = tile;
|
||||
}
|
||||
|
||||
PostValidate(aPaintRegion);
|
||||
for (size_t i = 0; i < mRetainedTiles.Length(); ++i) {
|
||||
UnlockTile(mRetainedTiles[i]);
|
||||
}
|
||||
|
||||
mTiles = newTiles;
|
||||
mValidRegion = newValidRegion;
|
||||
mPaintedRegion.OrWith(aPaintRegion);
|
||||
}
|
||||
|
||||
TileClient
|
||||
ClientTiledLayerBuffer::ValidateTile(TileClient aTile,
|
||||
const nsIntPoint& aTileOrigin,
|
||||
|
@ -419,6 +419,8 @@ public:
|
||||
LayerManager::DrawPaintedLayerCallback aCallback,
|
||||
void* aCallbackData);
|
||||
|
||||
void Update(const nsIntRegion& aNewValidRegion, const nsIntRegion& aPaintRegion);
|
||||
|
||||
void ReadLock();
|
||||
|
||||
void Release();
|
||||
@ -453,6 +455,19 @@ public:
|
||||
mResolution = aResolution;
|
||||
}
|
||||
|
||||
void ResetPaintedAndValidState() {
|
||||
mPaintedRegion.SetEmpty();
|
||||
mValidRegion.SetEmpty();
|
||||
mTiles.mSize.width = 0;
|
||||
mTiles.mSize.height = 0;
|
||||
for (size_t i = 0; i < mRetainedTiles.Length(); i++) {
|
||||
if (!mRetainedTiles[i].IsPlaceholderTile()) {
|
||||
mRetainedTiles[i].Release();
|
||||
}
|
||||
}
|
||||
mRetainedTiles.Clear();
|
||||
}
|
||||
|
||||
protected:
|
||||
TileClient ValidateTile(TileClient aTile,
|
||||
const nsIntPoint& aTileRect,
|
||||
@ -462,10 +477,6 @@ protected:
|
||||
|
||||
void UnlockTile(TileClient aTile);
|
||||
|
||||
void ReleaseTile(TileClient aTile) { aTile.Release(); }
|
||||
|
||||
void SwapTiles(TileClient& aTileA, TileClient& aTileB) { std::swap(aTileA, aTileB); }
|
||||
|
||||
TileClient GetPlaceholderTile() const { return TileClient(); }
|
||||
|
||||
private:
|
||||
|
@ -39,7 +39,7 @@ namespace layers {
|
||||
class Layer;
|
||||
class Compositor;
|
||||
class ThebesBufferData;
|
||||
class TiledLayerComposer;
|
||||
class TiledContentHost;
|
||||
class CompositableParentManager;
|
||||
class PCompositableParent;
|
||||
struct EffectChain;
|
||||
@ -132,7 +132,7 @@ public:
|
||||
Layer* GetLayer() const { return mLayer; }
|
||||
void SetLayer(Layer* aLayer) { mLayer = aLayer; }
|
||||
|
||||
virtual TiledLayerComposer* AsTiledLayerComposer() { return nullptr; }
|
||||
virtual TiledContentHost* AsTiledContentHost() { return nullptr; }
|
||||
|
||||
typedef uint32_t AttachFlags;
|
||||
static const AttachFlags NO_FLAGS = 0;
|
||||
|
@ -40,7 +40,6 @@ class Matrix4x4;
|
||||
namespace layers {
|
||||
class Compositor;
|
||||
class ThebesBufferData;
|
||||
class TiledLayerComposer;
|
||||
struct EffectChain;
|
||||
|
||||
struct TexturedEffect;
|
||||
@ -54,10 +53,6 @@ struct TexturedEffect;
|
||||
class ContentHost : public CompositableHost
|
||||
{
|
||||
public:
|
||||
// Subclasses should implement this method if they support being used as a
|
||||
// tiling.
|
||||
virtual TiledLayerComposer* AsTiledLayerComposer() { return nullptr; }
|
||||
|
||||
virtual bool UpdateThebes(const ThebesBufferData& aData,
|
||||
const nsIntRegion& aUpdated,
|
||||
const nsIntRegion& aOldValidRegionBack,
|
||||
|
@ -19,7 +19,7 @@
|
||||
#include "LayerScope.h" // for LayerScope Tool
|
||||
#include "protobuf/LayerScopePacket.pb.h" // for protobuf (LayerScope)
|
||||
#include "PaintedLayerComposite.h" // for PaintedLayerComposite
|
||||
#include "TiledLayerBuffer.h" // for TiledLayerComposer
|
||||
#include "TiledContentHost.h"
|
||||
#include "Units.h" // for ScreenIntRect
|
||||
#include "UnitTransforms.h" // for ViewAs
|
||||
#include "gfx2DGlue.h" // for ToMatrix4x4
|
||||
@ -1016,10 +1016,10 @@ LayerManagerComposite::ComputeRenderIntegrityInternal(Layer* aLayer,
|
||||
SubtractTransformedRegion(aScreenRegion, incompleteRegion, transformToScreen);
|
||||
|
||||
// See if there's any incomplete low-precision rendering
|
||||
TiledLayerComposer* composer = nullptr;
|
||||
TiledContentHost* composer = nullptr;
|
||||
LayerComposite* shadow = aLayer->AsLayerComposite();
|
||||
if (shadow) {
|
||||
composer = shadow->GetTiledLayerComposer();
|
||||
composer = shadow->GetCompositableHost()->AsTiledContentHost();
|
||||
if (composer) {
|
||||
incompleteRegion.Sub(incompleteRegion, composer->GetValidLowPrecisionRegion());
|
||||
if (!incompleteRegion.IsEmpty()) {
|
||||
@ -1338,7 +1338,8 @@ LayerManagerComposite::AsyncPanZoomEnabled() const
|
||||
|
||||
nsIntRegion
|
||||
LayerComposite::GetFullyRenderedRegion() {
|
||||
if (TiledLayerComposer* tiled = GetTiledLayerComposer()) {
|
||||
if (TiledContentHost* tiled = GetCompositableHost() ? GetCompositableHost()->AsTiledContentHost()
|
||||
: nullptr) {
|
||||
nsIntRegion shadowVisibleRegion = GetShadowVisibleRegion();
|
||||
// Discard the region which hasn't been drawn yet when doing
|
||||
// progressive drawing. Note that if the shadow visible region
|
||||
|
@ -56,7 +56,6 @@ class ImageLayerComposite;
|
||||
class LayerComposite;
|
||||
class RefLayerComposite;
|
||||
class PaintedLayerComposite;
|
||||
class TiledLayerComposer;
|
||||
class TextRenderer;
|
||||
class CompositingRenderTarget;
|
||||
struct FPSState;
|
||||
@ -379,8 +378,6 @@ public:
|
||||
|
||||
virtual void CleanupResources() = 0;
|
||||
|
||||
virtual TiledLayerComposer* GetTiledLayerComposer() { return nullptr; }
|
||||
|
||||
virtual void DestroyFrontBuffer() { }
|
||||
|
||||
void AddBlendModeEffect(EffectChain& aEffectChain);
|
||||
|
@ -29,8 +29,6 @@
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
class TiledLayerComposer;
|
||||
|
||||
PaintedLayerComposite::PaintedLayerComposite(LayerManagerComposite *aManager)
|
||||
: PaintedLayer(aManager, nullptr)
|
||||
, LayerComposite(aManager)
|
||||
@ -91,16 +89,6 @@ PaintedLayerComposite::SetLayerManager(LayerManagerComposite* aManager)
|
||||
}
|
||||
}
|
||||
|
||||
TiledLayerComposer*
|
||||
PaintedLayerComposite::GetTiledLayerComposer()
|
||||
{
|
||||
if (!mBuffer) {
|
||||
return nullptr;
|
||||
}
|
||||
MOZ_ASSERT(mBuffer->IsAttached());
|
||||
return mBuffer->AsTiledLayerComposer();
|
||||
}
|
||||
|
||||
LayerRenderState
|
||||
PaintedLayerComposite::GetRenderState()
|
||||
{
|
||||
|
@ -28,7 +28,6 @@ namespace layers {
|
||||
|
||||
class CompositableHost;
|
||||
class ContentHost;
|
||||
class TiledLayerComposer;
|
||||
|
||||
class PaintedLayerComposite : public PaintedLayer,
|
||||
public LayerComposite
|
||||
@ -52,8 +51,6 @@ public:
|
||||
|
||||
virtual void SetLayerManager(LayerManagerComposite* aManager) override;
|
||||
|
||||
virtual TiledLayerComposer* GetTiledLayerComposer() override;
|
||||
|
||||
virtual void RenderLayer(const gfx::IntRect& aClipRect) override;
|
||||
|
||||
virtual void CleanupResources() override;
|
||||
|
@ -498,9 +498,9 @@ TiledContentHost::RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer,
|
||||
float resolution = aLayerBuffer.GetResolution();
|
||||
gfx::Size layerScale(1, 1);
|
||||
|
||||
// Make sure we don't render at low resolution where we have valid high
|
||||
// resolution content, to avoid overdraw and artifacts with semi-transparent
|
||||
// layers.
|
||||
// We assume that the current frame resolution is the one used in our high
|
||||
// precision layer buffer. Compensate for a changing frame resolution when
|
||||
// rendering the low precision buffer.
|
||||
if (aLayerBuffer.GetFrameResolution() != mTiledBuffer.GetFrameResolution()) {
|
||||
const CSSToParentLayerScale2D& layerResolution = aLayerBuffer.GetFrameResolution();
|
||||
const CSSToParentLayerScale2D& localResolution = mTiledBuffer.GetFrameResolution();
|
||||
@ -509,9 +509,9 @@ TiledContentHost::RenderLayerBuffer(TiledLayerBufferComposite& aLayerBuffer,
|
||||
aVisibleRegion.ScaleRoundOut(layerScale.width, layerScale.height);
|
||||
}
|
||||
|
||||
// If we're drawing the low precision buffer, make sure the high precision
|
||||
// buffer is masked out to avoid overdraw and rendering artifacts with
|
||||
// non-opaque layers.
|
||||
// Make sure we don't render at low resolution where we have valid high
|
||||
// resolution content, to avoid overdraw and artifacts with semi-transparent
|
||||
// layers.
|
||||
nsIntRegion maskRegion;
|
||||
if (resolution != mTiledBuffer.GetResolution()) {
|
||||
maskRegion = mTiledBuffer.GetValidRegion();
|
||||
|
@ -167,8 +167,6 @@ public:
|
||||
static void RecycleCallback(TextureHost* textureHost, void* aClosure);
|
||||
|
||||
protected:
|
||||
void SwapTiles(TileHost& aTileA, TileHost& aTileB) { std::swap(aTileA, aTileB); }
|
||||
|
||||
CSSToParentLayerScale2D mFrameResolution;
|
||||
};
|
||||
|
||||
@ -192,8 +190,7 @@ protected:
|
||||
* buffer after compositing a new one. Rendering takes us to RenderTile which
|
||||
* is similar to Composite for non-tiled ContentHosts.
|
||||
*/
|
||||
class TiledContentHost : public ContentHost,
|
||||
public TiledLayerComposer
|
||||
class TiledContentHost : public ContentHost
|
||||
{
|
||||
public:
|
||||
explicit TiledContentHost(const TextureInfo& aTextureInfo);
|
||||
@ -217,12 +214,12 @@ public:
|
||||
return false;
|
||||
}
|
||||
|
||||
const nsIntRegion& GetValidLowPrecisionRegion() const override
|
||||
const nsIntRegion& GetValidLowPrecisionRegion() const
|
||||
{
|
||||
return mLowPrecisionTiledBuffer.GetValidRegion();
|
||||
}
|
||||
|
||||
const nsIntRegion& GetValidRegion() const override
|
||||
const nsIntRegion& GetValidRegion() const
|
||||
{
|
||||
return mTiledBuffer.GetValidRegion();
|
||||
}
|
||||
@ -235,8 +232,8 @@ public:
|
||||
mLowPrecisionTiledBuffer.SetCompositor(aCompositor);
|
||||
}
|
||||
|
||||
virtual bool UseTiledLayerBuffer(ISurfaceAllocator* aAllocator,
|
||||
const SurfaceDescriptorTiles& aTiledDescriptor) override;
|
||||
bool UseTiledLayerBuffer(ISurfaceAllocator* aAllocator,
|
||||
const SurfaceDescriptorTiles& aTiledDescriptor);
|
||||
|
||||
void Composite(EffectChain& aEffectChain,
|
||||
float aOpacity,
|
||||
@ -247,7 +244,7 @@ public:
|
||||
|
||||
virtual CompositableType GetType() override { return CompositableType::CONTENT_TILED; }
|
||||
|
||||
virtual TiledLayerComposer* AsTiledLayerComposer() override { return this; }
|
||||
virtual TiledContentHost* AsTiledContentHost() override { return this; }
|
||||
|
||||
virtual void Attach(Layer* aLayer,
|
||||
Compositor* aCompositor,
|
||||
|
@ -11,7 +11,6 @@
|
||||
#include "GLContext.h" // for GLContext
|
||||
#include "Layers.h" // for Layer
|
||||
#include "RenderTrace.h" // for RenderTraceInvalidateEnd, etc
|
||||
#include "TiledLayerBuffer.h" // for TiledLayerComposer
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT, etc
|
||||
#include "mozilla/RefPtr.h" // for RefPtr
|
||||
#include "mozilla/layers/CompositorTypes.h"
|
||||
@ -23,6 +22,7 @@
|
||||
#include "mozilla/layers/LayersTypes.h" // for MOZ_LAYERS_LOG
|
||||
#include "mozilla/layers/TextureHost.h" // for TextureHost
|
||||
#include "mozilla/layers/TextureHostOGL.h" // for TextureHostOGL
|
||||
#include "mozilla/layers/TiledContentHost.h"
|
||||
#include "mozilla/layers/PaintedLayerComposite.h"
|
||||
#include "mozilla/mozalloc.h" // for operator delete
|
||||
#include "mozilla/unused.h"
|
||||
@ -112,13 +112,12 @@ CompositableParentManager::ReceiveCompositableUpdate(const CompositableOperation
|
||||
case CompositableOperation::TOpUseTiledLayerBuffer: {
|
||||
MOZ_LAYERS_LOG(("[ParentSide] Paint TiledLayerBuffer"));
|
||||
const OpUseTiledLayerBuffer& op = aEdit.get_OpUseTiledLayerBuffer();
|
||||
CompositableHost* compositable = AsCompositable(op);
|
||||
TiledContentHost* compositable = AsCompositable(op)->AsTiledContentHost();
|
||||
|
||||
TiledLayerComposer* tileComposer = compositable->AsTiledLayerComposer();
|
||||
NS_ASSERTION(tileComposer, "compositable is not a tile composer");
|
||||
NS_ASSERTION(compositable, "The compositable is not tiled");
|
||||
|
||||
const SurfaceDescriptorTiles& tileDesc = op.tileLayerDescriptor();
|
||||
bool success = tileComposer->UseTiledLayerBuffer(this, tileDesc);
|
||||
bool success = compositable->UseTiledLayerBuffer(this, tileDesc);
|
||||
if (!success) {
|
||||
return false;
|
||||
}
|
||||
|
@ -131,6 +131,7 @@ EXPORTS.mozilla.layers += [
|
||||
'composite/LayerManagerComposite.h',
|
||||
'composite/PaintedLayerComposite.h',
|
||||
'composite/TextureHost.h',
|
||||
'composite/TiledContentHost.h',
|
||||
'Compositor.h',
|
||||
'CompositorTypes.h',
|
||||
'D3D11ShareHandleImage.h',
|
||||
|
@ -41,7 +41,6 @@
|
||||
#include "ScopedGLHelpers.h"
|
||||
#include "GLReadTexImageHelper.h"
|
||||
#include "GLBlitTextureImageHelper.h"
|
||||
#include "TiledLayerBuffer.h" // for TiledLayerComposer
|
||||
#include "HeapCopyOfStackArray.h"
|
||||
|
||||
#if MOZ_WIDGET_ANDROID
|
||||
|
@ -10,81 +10,56 @@
|
||||
namespace mozilla {
|
||||
namespace layers {
|
||||
|
||||
struct TestTiledLayerTile {
|
||||
int value;
|
||||
explicit TestTiledLayerTile(int v = 0) {
|
||||
value = v;
|
||||
}
|
||||
bool operator== (const TestTiledLayerTile& o) const {
|
||||
return value == o.value;
|
||||
}
|
||||
bool operator!= (const TestTiledLayerTile& o) const {
|
||||
return value != o.value;
|
||||
}
|
||||
|
||||
bool IsPlaceholderTile() const {
|
||||
return value == -1;
|
||||
}
|
||||
};
|
||||
|
||||
class TestTiledLayerBuffer : public TiledLayerBuffer<TestTiledLayerBuffer, TestTiledLayerTile>
|
||||
{
|
||||
friend class TiledLayerBuffer<TestTiledLayerBuffer, TestTiledLayerTile>;
|
||||
|
||||
public:
|
||||
TestTiledLayerTile GetPlaceholderTile() const {
|
||||
return TestTiledLayerTile(-1);
|
||||
}
|
||||
|
||||
TestTiledLayerTile ValidateTile(TestTiledLayerTile aTile, const nsIntPoint& aTileOrigin, const nsIntRegion& aDirtyRect) {
|
||||
return TestTiledLayerTile();
|
||||
}
|
||||
|
||||
void ReleaseTile(TestTiledLayerTile aTile)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void SwapTiles(TestTiledLayerTile& aTileA, TestTiledLayerTile& aTileB)
|
||||
{
|
||||
TestTiledLayerTile oldTileA = aTileA;
|
||||
aTileA = aTileB;
|
||||
aTileB = oldTileA;
|
||||
}
|
||||
|
||||
void TestUpdate(const nsIntRegion& aNewValidRegion, const nsIntRegion& aPaintRegion)
|
||||
{
|
||||
Update(aNewValidRegion, aPaintRegion);
|
||||
}
|
||||
|
||||
void UnlockTile(TestTiledLayerTile aTile) {}
|
||||
void PostValidate(const nsIntRegion& aPaintRegion) {}
|
||||
};
|
||||
|
||||
TEST(TiledLayerBuffer, TileConstructor) {
|
||||
gfxPlatform::GetPlatform()->ComputeTileSize();
|
||||
|
||||
TestTiledLayerBuffer buffer;
|
||||
}
|
||||
|
||||
TEST(TiledLayerBuffer, TileStart) {
|
||||
gfxPlatform::GetPlatform()->ComputeTileSize();
|
||||
|
||||
TestTiledLayerBuffer buffer;
|
||||
|
||||
ASSERT_EQ(buffer.RoundDownToTileEdge(10, 256), 0);
|
||||
ASSERT_EQ(buffer.RoundDownToTileEdge(-10, 256), -256);
|
||||
ASSERT_EQ(RoundDownToTileEdge(10, 256), 0);
|
||||
ASSERT_EQ(RoundDownToTileEdge(-10, 256), -256);
|
||||
}
|
||||
|
||||
TEST(TiledLayerBuffer, EmptyUpdate) {
|
||||
gfxPlatform::GetPlatform()->ComputeTileSize();
|
||||
TEST(TiledLayerBuffer, TilesPlacement) {
|
||||
for (int firstY = -10; firstY < 10; ++firstY) {
|
||||
for (int firstX = -10; firstX < 10; ++firstX) {
|
||||
for (int height = 1; height < 10; ++height) {
|
||||
for (int width = 1; width < 10; ++width) {
|
||||
|
||||
TestTiledLayerBuffer buffer;
|
||||
const TilesPlacement p1 = TilesPlacement(firstX, firstY, width, height);
|
||||
// Check that HasTile returns false with some positions that we know
|
||||
// not to be in the rectangle of the TilesPlacement.
|
||||
ASSERT_FALSE(p1.HasTile(TileIntPoint(firstX - 1, 0)));
|
||||
ASSERT_FALSE(p1.HasTile(TileIntPoint(0, firstY - 1)));
|
||||
ASSERT_FALSE(p1.HasTile(TileIntPoint(firstX + width + 1, 0)));
|
||||
ASSERT_FALSE(p1.HasTile(TileIntPoint(0, firstY + height + 1)));
|
||||
|
||||
nsIntRegion validRegion(gfx::IntRect(0, 0, 10, 10));
|
||||
buffer.TestUpdate(validRegion, validRegion);
|
||||
// Verify that all positions within the rect that defines the
|
||||
// TilesPlacement map to indices between 0 and width*height.
|
||||
for (int y = firstY; y < (firstY+height); ++y) {
|
||||
for (int x = firstX; x < (firstX+width); ++x) {
|
||||
ASSERT_TRUE(p1.HasTile(TileIntPoint(x,y)));
|
||||
ASSERT_TRUE(p1.TileIndex(TileIntPoint(x, y)) >= 0);
|
||||
ASSERT_TRUE(p1.TileIndex(TileIntPoint(x, y)) < width * height);
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT_EQ(buffer.GetValidRegion(), validRegion);
|
||||
// XXX - This causes some versions of gcc to warn that it optimizes
|
||||
// away the test, which gets caught in -WError in PGO builds.
|
||||
// The lazy thing to do is to just comment this out since this specific
|
||||
// test isn't critically important, but we should remove the warning instead.
|
||||
// cf. bug 1179287
|
||||
//
|
||||
// Verify that indices map to positions that are within the rect that
|
||||
// defines the TilesPlacement.
|
||||
// for (int i = 0; i < width * height; ++i) {
|
||||
// ASSERT_TRUE(p1.TilePosition(i).x >= firstX);
|
||||
// ASSERT_TRUE(p1.TilePosition(i).x < firstX + width);
|
||||
// ASSERT_TRUE(p1.TilePosition(i).y >= firstY);
|
||||
// ASSERT_TRUE(p1.TilePosition(i).y < firstY + height);
|
||||
// }
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -24,7 +24,8 @@ UNIFIED_SOURCES += [
|
||||
'TestTextures.cpp',
|
||||
# Test works but it doesn't assert anything
|
||||
#'gfxTextRunPerfTest.cpp',
|
||||
'TestTiledLayerBuffer.cpp',
|
||||
# Bug 1179287 - PGO bustage on Linux
|
||||
#'TestTiledLayerBuffer.cpp',
|
||||
'TestVsync.cpp',
|
||||
]
|
||||
|
||||
|
8
layout/reftests/bugs/1179078-1-ref.html
Normal file
8
layout/reftests/bugs/1179078-1-ref.html
Normal file
@ -0,0 +1,8 @@
|
||||
<!DOCTYPE html>
|
||||
<style>
|
||||
p {
|
||||
border: 2px solid transparent;
|
||||
border-image: linear-gradient(to right, orange, blue) 1 1;
|
||||
}
|
||||
</style>
|
||||
<p>This paragraph must have an orange/blue gradient border.</p>
|
9
layout/reftests/bugs/1179078-1.html
Normal file
9
layout/reftests/bugs/1179078-1.html
Normal file
@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<style>
|
||||
p {
|
||||
border: 2px solid transparent;
|
||||
border-image: linear-gradient(to right, orange, blue) 1 1;
|
||||
border-image: linear-gradient(to right, garbage) 1 1;
|
||||
}
|
||||
</style>
|
||||
<p>This paragraph must have an orange/blue gradient border.</p>
|
@ -1927,4 +1927,5 @@ skip-if(B2G||Mulet) == 1150021-1.xul 1150021-1-ref.xul
|
||||
== 1155828-1.html 1155828-1-ref.html
|
||||
== 1156129-1.html 1156129-1-ref.html
|
||||
== 1169331-1.html 1169331-1-ref.html
|
||||
== 1179078-1.html 1179078-1-ref.html
|
||||
fuzzy(1,74) == 1174332-1.html 1174332-1-ref.html
|
||||
|
@ -104,6 +104,7 @@ default-preferences pref(layout.css.variables.enabled,true)
|
||||
== variable-reference-37.html variable-reference-37-ref.html
|
||||
== variable-reference-38.html variable-reference-38-ref.html
|
||||
== variable-reference-39.html support/color-green-ref.html
|
||||
== variable-reference-40.html variable-reference-40-ref.html
|
||||
== variable-supports-01.html support/color-green-ref.html
|
||||
== variable-supports-02.html support/color-green-ref.html
|
||||
== variable-supports-03.html support/color-green-ref.html
|
||||
|
@ -0,0 +1,14 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<title>CSS Reftest Reference</title>
|
||||
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
|
||||
<style>
|
||||
p {
|
||||
border: 2px solid transparent;
|
||||
border-image: linear-gradient(to right, orange, blue) 1 1;
|
||||
}
|
||||
</style>
|
||||
<p>This paragraph must have an orange/blue gradient border.</p>
|
@ -0,0 +1,17 @@
|
||||
<!--
|
||||
Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/
|
||||
-->
|
||||
<!DOCTYPE html>
|
||||
<title>CSS Test: Test that a variable reference within a gradient value in a border-image shorthand parses correctly.</title>
|
||||
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
|
||||
<link rel="help" href="http://www.w3.org/TR/css-variables-1/#using-variables">
|
||||
<link rel="match" href="variable-reference-40-ref.html">
|
||||
<style>
|
||||
p {
|
||||
--orange: orange;
|
||||
border: 2px solid transparent;
|
||||
border-image: linear-gradient(to right, var(--orange), blue) 1 1;
|
||||
}
|
||||
</style>
|
||||
<p>This paragraph must have an orange/blue gradient border.</p>
|
@ -11347,10 +11347,14 @@ CSSParserImpl::ParseBorderImage()
|
||||
nsCSSValue imageSourceValue;
|
||||
while (!CheckEndProperty()) {
|
||||
// <border-image-source>
|
||||
if (!foundSource && ParseVariant(imageSourceValue, VARIANT_IMAGE, nullptr)) {
|
||||
AppendValue(eCSSProperty_border_image_source, imageSourceValue);
|
||||
foundSource = true;
|
||||
continue;
|
||||
if (!foundSource) {
|
||||
nsAutoCSSParserInputStateRestorer stateRestorer(this);
|
||||
if (ParseVariant(imageSourceValue, VARIANT_IMAGE, nullptr)) {
|
||||
AppendValue(eCSSProperty_border_image_source, imageSourceValue);
|
||||
foundSource = true;
|
||||
stateRestorer.DoNotRestore();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// <border-image-slice>
|
||||
|
@ -286,7 +286,7 @@ nsBaseChannel::ClassifyURI()
|
||||
if (mLoadFlags & LOAD_CLASSIFY_URI) {
|
||||
nsRefPtr<nsChannelClassifier> classifier = new nsChannelClassifier();
|
||||
if (classifier) {
|
||||
classifier->Start(this, false);
|
||||
classifier->Start(this);
|
||||
} else {
|
||||
Cancel(NS_ERROR_OUT_OF_MEMORY);
|
||||
}
|
||||
|
@ -237,12 +237,9 @@ nsChannelClassifier::NotifyTrackingProtectionDisabled(nsIChannel *aChannel)
|
||||
}
|
||||
|
||||
void
|
||||
nsChannelClassifier::Start(nsIChannel *aChannel, bool aContinueBeginConnect)
|
||||
nsChannelClassifier::Start(nsIChannel *aChannel)
|
||||
{
|
||||
mChannel = aChannel;
|
||||
if (aContinueBeginConnect) {
|
||||
mChannelInternal = do_QueryInterface(aChannel);
|
||||
}
|
||||
|
||||
nsresult rv = StartInternal();
|
||||
if (NS_FAILED(rv)) {
|
||||
@ -530,13 +527,7 @@ nsChannelClassifier::OnClassifyComplete(nsresult aErrorCode)
|
||||
mChannel->Resume();
|
||||
}
|
||||
|
||||
// Even if we have cancelled the channel, we may need to call
|
||||
// ContinueBeginConnect so that we abort appropriately.
|
||||
if (mChannelInternal) {
|
||||
mChannelInternal->ContinueBeginConnect();
|
||||
}
|
||||
mChannel = nullptr;
|
||||
mChannelInternal = nullptr;
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -21,10 +21,8 @@ public:
|
||||
NS_DECL_NSIURICLASSIFIERCALLBACK
|
||||
|
||||
// Calls nsIURIClassifier.Classify with the principal of the given channel,
|
||||
// and cancels the channel on a bad verdict. If callContinueBeginConnect is true,
|
||||
// and aChannel is an nsIHttpChannelInternal, nsChannelClassifier must call
|
||||
// nsIHttpChannelInternal.ContinueBeginConnect once Start has returned.
|
||||
void Start(nsIChannel *aChannel, bool aContinueBeginConnect);
|
||||
// and cancels the channel on a bad verdict.
|
||||
void Start(nsIChannel *aChannel);
|
||||
// Whether or not tracking protection should be enabled on this channel.
|
||||
nsresult ShouldEnableTrackingProtection(nsIChannel *aChannel, bool *result);
|
||||
|
||||
@ -34,7 +32,6 @@ private:
|
||||
// True if the channel has been suspended.
|
||||
bool mSuspendedChannel;
|
||||
nsCOMPtr<nsIChannel> mChannel;
|
||||
nsCOMPtr<nsIHttpChannelInternal> mChannelInternal;
|
||||
|
||||
~nsChannelClassifier() {}
|
||||
// Caches good classifications for the channel principal.
|
||||
|
@ -1535,15 +1535,6 @@ HttpBaseChannel::RedirectTo(nsIURI *newURI)
|
||||
// HttpBaseChannel::nsIHttpChannelInternal
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
NS_IMETHODIMP
|
||||
HttpBaseChannel::ContinueBeginConnect()
|
||||
{
|
||||
MOZ_ASSERT(XRE_GetProcessType() != GeckoProcessType_Default,
|
||||
"The parent overrides this");
|
||||
MOZ_ASSERT(false, "This method must be overridden");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
HttpBaseChannel::GetTopWindowURI(nsIURI **aTopWindowURI)
|
||||
{
|
||||
|
@ -197,7 +197,6 @@ public:
|
||||
NS_IMETHOD GetCorsMode(uint32_t* aCorsMode) override;
|
||||
NS_IMETHOD SetCorsMode(uint32_t aCorsMode) override;
|
||||
NS_IMETHOD GetTopWindowURI(nsIURI **aTopWindowURI) override;
|
||||
NS_IMETHOD ContinueBeginConnect() override;
|
||||
NS_IMETHOD GetProxyURI(nsIURI **proxyURI) override;
|
||||
|
||||
inline void CleanRedirectCacheChainIfNecessary()
|
||||
|
@ -4782,6 +4782,11 @@ nsHttpChannel::GetSecurityInfo(nsISupports **securityInfo)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// If any of the functions that AsyncOpen calls returns immediately an error
|
||||
// AsyncAbort(which calls onStart/onStopRequest) does not need to be call.
|
||||
// To be sure that they are not call ReleaseListeners() is called.
|
||||
// If AsyncOpen returns NS_OK, after that point AsyncAbort must be called on
|
||||
// any error.
|
||||
NS_IMETHODIMP
|
||||
nsHttpChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *context)
|
||||
{
|
||||
@ -4855,8 +4860,11 @@ nsHttpChannel::AsyncOpen(nsIStreamListener *listener, nsISupports *context)
|
||||
return rv;
|
||||
}
|
||||
|
||||
// On error BeginConnect() should call AsyncAbort() before exiting until
|
||||
// ContineBeginConnect after that it should not call it.
|
||||
// BeginConnect() will not call AsyncAbort() on an error and if AsyncAbort needs
|
||||
// to be called the function calling BeginConnect will need to call AsyncAbort.
|
||||
// If BeginConnect is called from AsyncOpen, AsyncnAbort doesn't need to be
|
||||
// called. If it is called form another function (e.g. the function is called
|
||||
// from OnProxyAvailable) that function should call AsyncOpen.
|
||||
nsresult
|
||||
nsHttpChannel::BeginConnect()
|
||||
{
|
||||
@ -4881,14 +4889,12 @@ nsHttpChannel::BeginConnect()
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = mURI->GetAsciiSpec(mSpec);
|
||||
if (NS_FAILED(rv)) {
|
||||
AsyncAbort(rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Reject the URL if it doesn't specify a host
|
||||
if (host.IsEmpty()) {
|
||||
rv = NS_ERROR_MALFORMED_URI;
|
||||
AsyncAbort(rv);
|
||||
return rv;
|
||||
}
|
||||
LOG(("host=%s port=%d\n", host.get(), port));
|
||||
@ -4964,7 +4970,6 @@ nsHttpChannel::BeginConnect()
|
||||
if (NS_SUCCEEDED(rv))
|
||||
rv = mAuthProvider->Init(this);
|
||||
if (NS_FAILED(rv)) {
|
||||
AsyncAbort(rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
@ -4977,11 +4982,7 @@ nsHttpChannel::BeginConnect()
|
||||
// Check to see if we should redirect this channel elsewhere by
|
||||
// nsIHttpChannel.redirectTo API request
|
||||
if (mAPIRedirectToURI) {
|
||||
rv = AsyncCall(&nsHttpChannel::HandleAsyncAPIRedirect);
|
||||
if (NS_FAILED(rv)) {
|
||||
AsyncAbort(rv);
|
||||
}
|
||||
return rv;
|
||||
return AsyncCall(&nsHttpChannel::HandleAsyncAPIRedirect);
|
||||
}
|
||||
// Check to see if this principal exists on local blocklists.
|
||||
nsRefPtr<nsChannelClassifier> channelClassifier = new nsChannelClassifier();
|
||||
@ -5094,33 +5095,43 @@ nsHttpChannel::BeginConnect()
|
||||
}
|
||||
mCaps &= ~NS_HTTP_ALLOW_PIPELINING;
|
||||
}
|
||||
if (!(mLoadFlags & LOAD_CLASSIFY_URI)) {
|
||||
// On error ContinueBeginConnect() will call AsyncAbort so do not do it
|
||||
// here
|
||||
return ContinueBeginConnect();
|
||||
|
||||
// We may have been cancelled already, either by on-modify-request
|
||||
// listeners or load group observers; in that case, we should not send the
|
||||
// request to the server
|
||||
if (mCanceled) {
|
||||
return mStatus;
|
||||
}
|
||||
|
||||
if (!(mLoadFlags & LOAD_CLASSIFY_URI)) {
|
||||
ContinueBeginConnect();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// mLocalBlocklist is true only if tracking protection is enabled and the
|
||||
// URI is a tracking domain, it makes no guarantees about phishing or
|
||||
// malware, so if LOAD_CLASSIFY_URI is true we must call
|
||||
// nsChannelClassifier to catch phishing and malware URIs.
|
||||
bool callContinueBeginConnect = true;
|
||||
if (mCanceled || !mLocalBlocklist) {
|
||||
rv = ContinueBeginConnect();
|
||||
if (NS_FAILED(rv)) {
|
||||
// On error ContinueBeginConnect() will call AsyncAbort so do not do
|
||||
// it here
|
||||
return rv;
|
||||
}
|
||||
callContinueBeginConnect = false;
|
||||
if (!mLocalBlocklist) {
|
||||
// Here we call ContinueBeginConnectWithResult and not
|
||||
// ContinueBeginConnect so that in the case of an error we do not start
|
||||
// channelClassifier.
|
||||
rv = ContinueBeginConnectWithResult();
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
callContinueBeginConnect = false;
|
||||
}
|
||||
// nsChannelClassifier calls ContinueBeginConnect if it has not already
|
||||
// been called, after optionally cancelling the channel once we have a
|
||||
// remote verdict. We call a concrete class instead of an nsI* that might
|
||||
// be overridden.
|
||||
if (!mCanceled) {
|
||||
LOG(("nsHttpChannel::Starting nsChannelClassifier %p [this=%p]",
|
||||
channelClassifier.get(), this));
|
||||
channelClassifier->Start(this, callContinueBeginConnect);
|
||||
LOG(("nsHttpChannel::Starting nsChannelClassifier %p [this=%p]",
|
||||
channelClassifier.get(), this));
|
||||
channelClassifier->Start(this);
|
||||
if (callContinueBeginConnect) {
|
||||
ContinueBeginConnect();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
@ -5158,28 +5169,39 @@ nsHttpChannel::SetPriority(int32_t value)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsHttpChannel::nsIHttpChannelInternal
|
||||
//-----------------------------------------------------------------------------
|
||||
NS_IMETHODIMP
|
||||
nsHttpChannel::ContinueBeginConnect()
|
||||
nsresult
|
||||
nsHttpChannel::ContinueBeginConnectWithResult()
|
||||
{
|
||||
LOG(("nsHttpChannel::ContinueBeginConnect [this=%p]", this));
|
||||
LOG(("nsHttpChannel::ContinueBeginConnectWithResult [this=%p]", this));
|
||||
NS_PRECONDITION(!mCallOnResume, "How did that happen?");
|
||||
|
||||
nsresult rv;
|
||||
// We may have been cancelled already, either by on-modify-request
|
||||
// listeners or load group observers or nsChannelClassifier; in that case,
|
||||
// we should not send the request to the server
|
||||
if (mCanceled) {
|
||||
|
||||
if (mSuspendCount) {
|
||||
LOG(("Waiting until resume to do async connect [this=%p]\n", this));
|
||||
mCallOnResume = &nsHttpChannel::ContinueBeginConnect;
|
||||
rv = NS_OK;
|
||||
} else if (mCanceled) {
|
||||
// We may have been cancelled already, by nsChannelClassifier in that
|
||||
// case, we should not send the request to the server
|
||||
rv = mStatus;
|
||||
} else {
|
||||
rv = Connect();
|
||||
}
|
||||
|
||||
LOG(("nsHttpChannel::ContinueBeginConnectWithResult result [this=%p rv=%x "
|
||||
"mCanceled=%i]\n", this, rv, mCanceled));
|
||||
return rv;
|
||||
}
|
||||
|
||||
void
|
||||
nsHttpChannel::ContinueBeginConnect()
|
||||
{
|
||||
nsresult rv = ContinueBeginConnectWithResult();
|
||||
if (NS_FAILED(rv)) {
|
||||
LOG(("Calling AsyncAbort [rv=%x mCanceled=%i]\n", rv, mCanceled));
|
||||
CloseCacheEntry(true);
|
||||
AsyncAbort(rv);
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -5232,14 +5254,13 @@ nsHttpChannel::OnProxyAvailable(nsICancelable *request, nsIChannel *channel,
|
||||
LOG(("nsHttpChannel::OnProxyAvailable [this=%p] "
|
||||
"Handler no longer active.\n", this));
|
||||
rv = NS_ERROR_NOT_AVAILABLE;
|
||||
AsyncAbort(rv);
|
||||
}
|
||||
else {
|
||||
// On error BeginConnect() will call AsyncAbort.
|
||||
rv = BeginConnect();
|
||||
}
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
AsyncAbort(rv);
|
||||
Cancel(rv);
|
||||
}
|
||||
return rv;
|
||||
|
@ -126,7 +126,6 @@ public:
|
||||
NS_IMETHOD AsyncOpen(nsIStreamListener *listener, nsISupports *aContext) override;
|
||||
// nsIHttpChannelInternal
|
||||
NS_IMETHOD SetupFallbackChannel(const char *aFallbackKey) override;
|
||||
NS_IMETHOD ContinueBeginConnect() override;
|
||||
// nsISupportsPriority
|
||||
NS_IMETHOD SetPriority(int32_t value) override;
|
||||
// nsIClassOfService
|
||||
@ -241,6 +240,8 @@ private:
|
||||
|
||||
bool RequestIsConditional();
|
||||
nsresult BeginConnect();
|
||||
nsresult ContinueBeginConnectWithResult();
|
||||
void ContinueBeginConnect();
|
||||
nsresult Connect();
|
||||
void SpeculativeConnect();
|
||||
nsresult SetupTransaction();
|
||||
|
@ -38,7 +38,7 @@ interface nsIHttpUpgradeListener : nsISupports
|
||||
* using any feature exposed by this interface, be aware that this interface
|
||||
* will change and you will be broken. You have been warned.
|
||||
*/
|
||||
[scriptable, uuid(26833ec7-4555-4f23-9281-3a12d4b76db1)]
|
||||
[scriptable, uuid(c025c35a-dda3-4a1d-9e6c-e02d7149ac79)]
|
||||
|
||||
interface nsIHttpChannelInternal : nsISupports
|
||||
{
|
||||
@ -253,12 +253,6 @@ interface nsIHttpChannelInternal : nsISupports
|
||||
*/
|
||||
attribute ACString networkInterfaceId;
|
||||
|
||||
/**
|
||||
* Used only by nsChannelClassifier to resume connecting or abort the
|
||||
* channel after a remote classification verdict.
|
||||
*/
|
||||
void continueBeginConnect();
|
||||
|
||||
/**
|
||||
* Read the proxy URI, which, if non-null, will be used to resolve
|
||||
* proxies for this channel.
|
||||
|
108
netwerk/test/unit/test_suspend_channel_before_connect.js
Normal file
108
netwerk/test/unit/test_suspend_channel_before_connect.js
Normal file
@ -0,0 +1,108 @@
|
||||
|
||||
const CC = Components.Constructor;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
const ServerSocket = CC("@mozilla.org/network/server-socket;1",
|
||||
"nsIServerSocket",
|
||||
"init");
|
||||
|
||||
var obs = Cc["@mozilla.org/observer-service;1"]
|
||||
.getService(Ci.nsIObserverService);
|
||||
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"]
|
||||
.getService(Components.interfaces.nsIIOService);
|
||||
|
||||
// A server that waits for a connect. If a channel is suspended it should not
|
||||
// try to connect to the server until it is is resumed or not try at all if it
|
||||
// is cancelled as in this test.
|
||||
function TestServer() {
|
||||
this.listener = ServerSocket(-1, true, -1);
|
||||
this.port = this.listener.port;
|
||||
this.listener.asyncListen(this);
|
||||
}
|
||||
|
||||
TestServer.prototype = {
|
||||
onSocketAccepted: function(socket, trans) {
|
||||
do_check_true(false, "Socket should not have tried to connect!");
|
||||
},
|
||||
|
||||
onStopListening: function(socket) {
|
||||
},
|
||||
|
||||
stop: function() {
|
||||
try { this.listener.close(); } catch(ignore) {}
|
||||
}
|
||||
}
|
||||
|
||||
var requestListenerObserver = {
|
||||
|
||||
QueryInterface: function queryinterface(iid) {
|
||||
if (iid.equals(Ci.nsISupports) ||
|
||||
iid.equals(Ci.nsIObserver))
|
||||
return this;
|
||||
throw Components.results.NS_ERROR_NO_INTERFACE;
|
||||
},
|
||||
|
||||
observe: function(subject, topic, data) {
|
||||
if (topic === "http-on-modify-request" &&
|
||||
subject instanceof Ci.nsIHttpChannel) {
|
||||
|
||||
var chan = subject.QueryInterface(Ci.nsIHttpChannel);
|
||||
chan.suspend();
|
||||
var obs = Cc["@mozilla.org/observer-service;1"].getService();
|
||||
obs = obs.QueryInterface(Ci.nsIObserverService);
|
||||
obs.removeObserver(this, "http-on-modify-request");
|
||||
|
||||
// Timers are bad, but we need to wait to see that we are not trying to
|
||||
// connect to the server. There are no other event since nothing should
|
||||
// happen until we resume the channel.
|
||||
let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
|
||||
timer.initWithCallback(() => {
|
||||
chan.cancel(Cr.NS_BINDING_ABORTED);
|
||||
chan.resume();
|
||||
}, 1000, Ci.nsITimer.TYPE_ONE_SHOT);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var listener = {
|
||||
onStartRequest: function test_onStartR(request, ctx) {
|
||||
},
|
||||
|
||||
onDataAvailable: function test_ODA() {
|
||||
do_throw("Should not get any data!");
|
||||
},
|
||||
|
||||
onStopRequest: function test_onStopR(request, ctx, status) {
|
||||
do_execute_soon(run_next_test);
|
||||
}
|
||||
};
|
||||
|
||||
// Add observer and start a channel. Observer is going to suspend the channel on
|
||||
// "http-on-modify-request" even. If a channel is suspended so early it should
|
||||
// not try to connect at all until it is resumed. In this case we are going to
|
||||
// wait for some time and cancel the channel before resuming it.
|
||||
add_test(function testNoConnectChannelCanceledEarly() {
|
||||
|
||||
serv = new TestServer();
|
||||
|
||||
obs.addObserver(requestListenerObserver, "http-on-modify-request", false);
|
||||
|
||||
var chan = ios.newChannel2("http://localhost:" + serv.port,
|
||||
"",
|
||||
null,
|
||||
null, // aLoadingNode
|
||||
Services.scriptSecurityManager.getSystemPrincipal(),
|
||||
null, // aTriggeringPrincipal
|
||||
Ci.nsILoadInfo.SEC_NORMAL,
|
||||
Ci.nsIContentPolicy.TYPE_OTHER);
|
||||
|
||||
chan.asyncOpen(listener, chan);
|
||||
|
||||
do_register_cleanup(function(){ serv.stop(); });
|
||||
});
|
||||
|
||||
function run_test() {
|
||||
run_next_test();
|
||||
}
|
@ -319,3 +319,4 @@ skip-if = os == "android"
|
||||
[test_multipart_streamconv_application_package.js]
|
||||
[test_safeoutputstream_append.js]
|
||||
[test_packaged_app_service.js]
|
||||
[test_suspend_channel_before_connect.js]
|
||||
|
@ -6,7 +6,18 @@ COPY releng.repo /etc/yum.repos.d/releng.repo
|
||||
RUN yum install -y epel-release && \
|
||||
yum update -y && \
|
||||
yum makecache && \
|
||||
yum install -y \
|
||||
yum install -y wget
|
||||
|
||||
# Install updated curl libraries
|
||||
RUN cd /tmp && \
|
||||
wget https://s3-us-west-2.amazonaws.com/test-caching/libcurl-7.29.0-19.el6.x86_64.rpm && \
|
||||
wget https://s3-us-west-2.amazonaws.com/test-caching/libcurl-devel-7.29.0-19.el6.x86_64.rpm && \
|
||||
wget https://s3-us-west-2.amazonaws.com/test-caching/curl-7.29.0-19.el6.x86_64.rpm && \
|
||||
yum install -y libcurl-7.29.0-19.el6.x86_64.rpm libcurl-devel-7.29.0-19.el6.x86_64.rpm curl-7.29.0-19.el6.x86_64.rpm && \
|
||||
rm -f libcurl-7.29.0-19.el6.x86_64.rpm libcurl-devel-7.29.0-19.el6.x86_64.rpm curl-7.29.0-19.el6.x86_64.rpm && \
|
||||
cd -
|
||||
|
||||
RUN yum install -y \
|
||||
# From Building B2G docs
|
||||
# cmake \
|
||||
# cmake: is disabled intentionally to work around: bug 1141417
|
||||
@ -17,8 +28,6 @@ RUN yum install -y epel-release && \
|
||||
bison \
|
||||
bzip2 \
|
||||
ccache \
|
||||
curl \
|
||||
curl-devel \
|
||||
dbus-devel \
|
||||
dbus-glib-devel \
|
||||
dbus-glib-devel \
|
||||
@ -41,7 +50,6 @@ RUN yum install -y epel-release && \
|
||||
libX11-devel.i686 \
|
||||
libXrandr.i686 \
|
||||
libXt-devel \
|
||||
libcurl-devel \
|
||||
libnotify-devel \
|
||||
libstdc++-static \
|
||||
libstdc++-static \
|
||||
@ -72,7 +80,6 @@ RUN yum install -y epel-release && \
|
||||
unzip \
|
||||
uuid \
|
||||
vim \
|
||||
wget \
|
||||
wireless-tools-devel \
|
||||
xorg-x11-server-Xvfb \
|
||||
xorg-x11-server-utils \
|
||||
|
@ -1 +1 @@
|
||||
0.2.8
|
||||
0.2.9
|
||||
|
@ -1,4 +1,4 @@
|
||||
FROM quay.io/mozilla/b2g-build:0.2.8
|
||||
FROM quay.io/mozilla/b2g-build:0.2.9
|
||||
MAINTAINER Dustin J. Mitchell <dustin@mozilla.com>
|
||||
|
||||
ENV PYTHONPATH /tools/tools/lib/python:$PYTHONPATH
|
||||
@ -21,7 +21,7 @@ RUN git config --global user.email "mozilla@example.com" && \
|
||||
git config --global user.name "mozilla"
|
||||
|
||||
# VCS Tools
|
||||
RUN npm install -g taskcluster-vcs@2.3.5
|
||||
RUN npm install -g taskcluster-vcs@2.3.6
|
||||
|
||||
# TODO enable worker
|
||||
# TODO volume mount permissions will be an issue
|
||||
|
@ -1 +1 @@
|
||||
0.5.5
|
||||
0.5.6
|
||||
|
@ -1,4 +1,4 @@
|
||||
FROM quay.io/mozilla/builder:0.5.5
|
||||
FROM taskcluster/builder:0.5.6
|
||||
MAINTAINER Wander Lairson Costa <wcosta@mozilla.com>
|
||||
|
||||
ENV SOCORRO_SYMBOL_UPLOAD_TOKEN_FILE /home/worker/socorro.token
|
||||
|
@ -1 +1 @@
|
||||
0.0.15
|
||||
0.0.16
|
||||
|
@ -1078,7 +1078,7 @@
|
||||
if (cell.childElt == "twisty")
|
||||
return;
|
||||
|
||||
if (cell.col) {
|
||||
if (cell.col && event.button == 0) {
|
||||
if (cell.col.cycler) {
|
||||
view.cycleCell(cell.row, cell.col);
|
||||
return;
|
||||
|
@ -365,8 +365,12 @@ uint32_t UniqueStacks::Stack::GetOrAddIndex() const
|
||||
uint32_t UniqueStacks::FrameKey::Hash() const
|
||||
{
|
||||
uint32_t hash = 0;
|
||||
if (!mLocation.empty()) {
|
||||
if (!mLocation.IsEmpty()) {
|
||||
#ifdef SPS_STANDALONE
|
||||
hash = mozilla::HashString(mLocation.c_str());
|
||||
#else
|
||||
hash = mozilla::HashString(mLocation.get());
|
||||
#endif
|
||||
}
|
||||
if (mLine.isSome()) {
|
||||
hash = mozilla::AddToHash(hash, *mLine);
|
||||
@ -539,7 +543,11 @@ void UniqueStacks::StreamFrame(const OnStackFrameKey& aFrame)
|
||||
#else
|
||||
{
|
||||
#endif
|
||||
#ifdef SPS_STANDALONE
|
||||
mUniqueStrings.WriteElement(mFrameTableWriter, aFrame.mLocation.c_str());
|
||||
#else
|
||||
mUniqueStrings.WriteElement(mFrameTableWriter, aFrame.mLocation.get());
|
||||
#endif
|
||||
if (aFrame.mLine.isSome()) {
|
||||
mFrameTableWriter.NullElement(); // implementation
|
||||
mFrameTableWriter.NullElement(); // optimizations
|
||||
|
@ -148,7 +148,13 @@ class UniqueStacks
|
||||
{
|
||||
public:
|
||||
struct FrameKey {
|
||||
#ifdef SPS_STANDALONE
|
||||
std::string mLocation;
|
||||
#else
|
||||
// This cannot be a std::string, as it is not memmove compatible, which
|
||||
// is used by nsHashTable
|
||||
nsCString mLocation;
|
||||
#endif
|
||||
mozilla::Maybe<unsigned> mLine;
|
||||
mozilla::Maybe<unsigned> mCategory;
|
||||
mozilla::Maybe<void*> mJITAddress;
|
||||
|
@ -49,7 +49,7 @@ pref("dom.mozTCPSocket.enabled", true);
|
||||
pref("general.smoothScroll", true);
|
||||
|
||||
// WebPayment
|
||||
pref("dom.mozPay.enabled", true);
|
||||
pref("dom.mozPay.enabled", false);
|
||||
|
||||
// System messages
|
||||
pref("dom.sysmsg.enabled", true);
|
||||
|
@ -19,9 +19,6 @@ function test() {
|
||||
ok(aResponse.tabs[0].styleEditorActor, "styleEditorActor set");
|
||||
ok(aResponse.tabs[0].inspectorActor, "inspectorActor set");
|
||||
ok(aResponse.tabs[0].traceActor, "traceActor set");
|
||||
ok(aResponse.chromeDebugger, "chromeDebugger set");
|
||||
ok(aResponse.consoleActor, "consoleActor set");
|
||||
ok(aResponse.profilerActor, "profilerActor set");
|
||||
ok(aResponse.deviceActor, "deviceActor set");
|
||||
|
||||
client.close(() => {
|
||||
|
@ -12,10 +12,10 @@ function test() {
|
||||
providerUri: "https://example.com:443/webapprtChrome/webapprt/test/chrome/mozpay-success.html?req=",
|
||||
message: "Success."
|
||||
});
|
||||
tests.push({
|
||||
providerUri: "https://example.com:443/webapprtChrome/webapprt/test/chrome/mozpay-failure.html?req=",
|
||||
message: "Chocolate rejected."
|
||||
});
|
||||
// tests.push({
|
||||
// providerUri: "https://example.com:443/webapprtChrome/webapprt/test/chrome/mozpay-failure.html?req=",
|
||||
// message: "Chocolate rejected."
|
||||
// });
|
||||
|
||||
let jwt = "eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJhdWQiOiAibW9j" +
|
||||
"a3BheXByb3ZpZGVyLnBocGZvZ2FwcC5jb20iLCAiaXNzIjogIkVudGVyI" +
|
||||
@ -36,23 +36,25 @@ function test() {
|
||||
requestMethod: "GET"
|
||||
};
|
||||
|
||||
let providerWindow;
|
||||
|
||||
let winObserver = function(win, topic) {
|
||||
if (topic == "domwindowopened") {
|
||||
win.addEventListener("load", function onLoadWindow() {
|
||||
win.removeEventListener("load", onLoadWindow, false);
|
||||
|
||||
if (win.document.getElementById("content").getAttribute("src") ==
|
||||
(tests[curTest].providerUri + jwt)) {
|
||||
ok(true, "Payment provider window shown.");
|
||||
providerWindow = win;
|
||||
}
|
||||
}, false);
|
||||
}
|
||||
}
|
||||
|
||||
Services.ww.registerNotification(winObserver);
|
||||
// Disabled because the mozPay API is disabled, so the provider window
|
||||
// won't be shown.
|
||||
//
|
||||
// let providerWindow;
|
||||
// let winObserver = function(win, topic) {
|
||||
// if (topic == "domwindowopened") {
|
||||
// win.addEventListener("load", function onLoadWindow() {
|
||||
// win.removeEventListener("load", onLoadWindow, false);
|
||||
//
|
||||
// if (win.document.getElementById("content") &&
|
||||
// win.document.getElementById("content").getAttribute("src") ==
|
||||
// (tests[curTest].providerUri + jwt)) {
|
||||
// ok(true, "Payment provider window shown.");
|
||||
// providerWindow = win;
|
||||
// }
|
||||
// }, false);
|
||||
// }
|
||||
// }
|
||||
// Services.ww.registerNotification(winObserver);
|
||||
|
||||
let mutObserver = null;
|
||||
|
||||
@ -61,12 +63,12 @@ function test() {
|
||||
mutObserver = new MutationObserver(function(mutations) {
|
||||
is(msg.textContent, tests[curTest].message, "Got: " + tests[curTest].message);
|
||||
|
||||
if (!providerWindow) {
|
||||
ok(false, "Payment provider window shown.");
|
||||
} else {
|
||||
providerWindow.close();
|
||||
providerWindow = null;
|
||||
}
|
||||
// if (!providerWindow) {
|
||||
// ok(false, "Payment provider window shown.");
|
||||
// } else {
|
||||
// providerWindow.close();
|
||||
// providerWindow = null;
|
||||
// }
|
||||
|
||||
runNextTest();
|
||||
});
|
||||
@ -76,7 +78,7 @@ function test() {
|
||||
loadWebapp("mozpay.webapp", undefined, onLoad);
|
||||
|
||||
function runNextTest() {
|
||||
providerWindow = null;
|
||||
// providerWindow = null;
|
||||
if (mutObserver) {
|
||||
mutObserver.disconnect();
|
||||
}
|
||||
@ -97,7 +99,7 @@ function test() {
|
||||
}
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
Services.ww.unregisterNotification(winObserver);
|
||||
// Services.ww.unregisterNotification(winObserver);
|
||||
mutObserver.disconnect();
|
||||
});
|
||||
}
|
||||
|
@ -32,13 +32,21 @@
|
||||
"gInR5cCI6ICJtb2NrL3BheW1lbnRzL2luYXBwL3YxIn0.QZxc62USCy4U" +
|
||||
"IyKIC1TKelVhNklvk-Ou1l_daKntaFI";
|
||||
|
||||
var request = navigator.mozPay(jwt);
|
||||
request.onsuccess = function onsuccess() {
|
||||
document.getElementById("msg").textContent = "Success.";
|
||||
};
|
||||
request.onerror = function onerror() {
|
||||
document.getElementById("msg").textContent = request.error.name;
|
||||
};
|
||||
// mozPay is currently disabled in the desktop runtime, so we check
|
||||
// that the property is set to null on the navigator object.
|
||||
window.addEventListener("load", function() {
|
||||
document.getElementById("msg").textContent =
|
||||
(navigator.mozPay === null) ? "Success." : "navigator.mozPay defined";
|
||||
}, false);
|
||||
|
||||
// This is the old code for checking the behavior of the API when enabled:
|
||||
// var request = navigator.mozPay(jwt);
|
||||
// request.onsuccess = function onsuccess() {
|
||||
// document.getElementById("msg").textContent = "Success.";
|
||||
// };
|
||||
// request.onerror = function onerror() {
|
||||
// document.getElementById("msg").textContent = request.error.name;
|
||||
// };
|
||||
</script>
|
||||
<p id="msg">Webapp waiting to be paid...</p>
|
||||
</body>
|
||||
|
Loading…
Reference in New Issue
Block a user