mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-08 10:44:56 +00:00
Merge m-c to autoland, a=merge
This commit is contained in:
commit
85c761efaa
@ -659,9 +659,7 @@ TextAttrsMgr::FontWeightTextAttr::
|
||||
// font->GetStyle()->weight will give the absolute weight requested of the
|
||||
// font face. The gfxPangoFontGroup code uses the gfxFontEntry constructor
|
||||
// which doesn't initialize the weight field.
|
||||
#if defined(MOZ_WIDGET_QT)
|
||||
useFontEntryWeight = false;
|
||||
#elif defined(MOZ_WIDGET_GTK)
|
||||
#if defined(MOZ_WIDGET_GTK)
|
||||
useFontEntryWeight = gfxPlatformGtk::UseFcFontList();
|
||||
#endif
|
||||
|
||||
|
@ -11,6 +11,10 @@
|
||||
#include "ARIAMap.h"
|
||||
#include "nsCoreUtils.h"
|
||||
|
||||
#ifdef A11Y_LOG
|
||||
#include "Logging.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
namespace a11y {
|
||||
|
||||
@ -76,6 +80,30 @@ Accessible::ScrollTo(uint32_t aHow) const
|
||||
nsCoreUtils::ScrollTo(mDoc->PresShell(), mContent, aHow);
|
||||
}
|
||||
|
||||
inline bool
|
||||
Accessible::InsertAfter(Accessible* aNewChild, Accessible* aRefChild)
|
||||
{
|
||||
MOZ_ASSERT(aNewChild, "No new child to insert");
|
||||
|
||||
if (aRefChild && aRefChild->Parent() != this) {
|
||||
#ifdef A11Y_LOG
|
||||
logging::TreeInfo("broken accessible tree", 0,
|
||||
"parent", this, "prev sibling parent",
|
||||
aRefChild->Parent(), "child", aNewChild, nullptr);
|
||||
if (logging::IsEnabled(logging::eVerbose)) {
|
||||
logging::Tree("TREE", "Document tree", mDoc);
|
||||
logging::DOMTree("TREE", "DOM document tree", mDoc);
|
||||
}
|
||||
#endif
|
||||
MOZ_ASSERT_UNREACHABLE("Broken accessible tree");
|
||||
mDoc->UnbindFromDocument(aNewChild);
|
||||
return false;
|
||||
}
|
||||
|
||||
return InsertChildAt(aRefChild ? aRefChild->IndexInParent() + 1 : 0,
|
||||
aNewChild);
|
||||
}
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
||||
|
@ -18,7 +18,6 @@
|
||||
#include "nsTextEquivUtils.h"
|
||||
#include "DocAccessibleChild.h"
|
||||
#include "EventTree.h"
|
||||
#include "Logging.h"
|
||||
#include "Relation.h"
|
||||
#include "Role.h"
|
||||
#include "RootAccessible.h"
|
||||
|
@ -393,12 +393,12 @@ public:
|
||||
{ return InsertChildAt(mChildren.Length(), aChild); }
|
||||
virtual bool InsertChildAt(uint32_t aIndex, Accessible* aChild);
|
||||
|
||||
bool InsertAfter(Accessible* aNewChild, Accessible* aRefChild)
|
||||
{
|
||||
MOZ_ASSERT(aNewChild, "No new child to insert");
|
||||
return InsertChildAt(aRefChild ? aRefChild->IndexInParent() + 1 : 0,
|
||||
aNewChild);
|
||||
}
|
||||
/**
|
||||
* Inserts a child after given sibling. If the child cannot be inserted,
|
||||
* then the child is unbound from the document, and false is returned. Make
|
||||
* sure to null out any references on the child object as it may be destroyed.
|
||||
*/
|
||||
bool InsertAfter(Accessible* aNewChild, Accessible* aRefChild);
|
||||
|
||||
virtual bool RemoveChild(Accessible* aChild);
|
||||
|
||||
|
@ -1681,6 +1681,12 @@ public:
|
||||
*/
|
||||
bool Next();
|
||||
|
||||
void Rejected()
|
||||
{
|
||||
mChild = nullptr;
|
||||
mChildBefore = nullptr;
|
||||
}
|
||||
|
||||
private:
|
||||
Accessible* mChild;
|
||||
Accessible* mChildBefore;
|
||||
@ -1815,6 +1821,7 @@ DocAccessible::ProcessContentInserted(Accessible* aContainer,
|
||||
}
|
||||
|
||||
MOZ_ASSERT_UNREACHABLE("accessible was rejected");
|
||||
iter.Rejected();
|
||||
} while (iter.Next());
|
||||
|
||||
mt.Done();
|
||||
@ -1852,7 +1859,9 @@ DocAccessible::ProcessContentInserted(Accessible* aContainer, nsIContent* aNode)
|
||||
|
||||
if (child) {
|
||||
TreeMutation mt(aContainer);
|
||||
aContainer->InsertAfter(child, walker.Prev());
|
||||
if (!aContainer->InsertAfter(child, walker.Prev())) {
|
||||
return;
|
||||
}
|
||||
mt.AfterInsertion(child);
|
||||
mt.Done();
|
||||
|
||||
|
@ -98,10 +98,10 @@ xpcAccessibleSelectable::Intl()
|
||||
return static_cast<xpcAccessibleGeneric*>(this)->mIntl.AsAccessible();
|
||||
}
|
||||
|
||||
inline Accessible*
|
||||
inline AccessibleOrProxy
|
||||
xpcAccessibleValue::Intl()
|
||||
{
|
||||
return static_cast<xpcAccessibleGeneric*>(this)->mIntl.AsAccessible();
|
||||
return static_cast<xpcAccessibleGeneric*>(this)->mIntl;
|
||||
}
|
||||
|
||||
} // namespace a11y
|
||||
|
@ -16,10 +16,19 @@ xpcAccessibleValue::GetMaximumValue(double* aValue)
|
||||
NS_ENSURE_ARG_POINTER(aValue);
|
||||
*aValue = 0;
|
||||
|
||||
if (Intl()->IsDefunct())
|
||||
if (Intl().IsNull())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
double value = Intl()->MaxValue();
|
||||
if (Intl().IsAccessible() && Intl().AsAccessible()->IsDefunct())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
double value;
|
||||
if (Intl().IsAccessible()) {
|
||||
value = Intl().AsAccessible()->MaxValue();
|
||||
} else {
|
||||
value = Intl().AsProxy()->MaxValue();
|
||||
}
|
||||
|
||||
if (!IsNaN(value))
|
||||
*aValue = value;
|
||||
|
||||
@ -32,10 +41,19 @@ xpcAccessibleValue::GetMinimumValue(double* aValue)
|
||||
NS_ENSURE_ARG_POINTER(aValue);
|
||||
*aValue = 0;
|
||||
|
||||
if (Intl()->IsDefunct())
|
||||
if (Intl().IsNull())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
double value = Intl()->MinValue();
|
||||
if (Intl().IsAccessible() && Intl().AsAccessible()->IsDefunct())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
double value;
|
||||
if (Intl().IsAccessible()) {
|
||||
value = Intl().AsAccessible()->MinValue();
|
||||
} else {
|
||||
value = Intl().AsProxy()->MinValue();
|
||||
}
|
||||
|
||||
if (!IsNaN(value))
|
||||
*aValue = value;
|
||||
|
||||
@ -48,10 +66,19 @@ xpcAccessibleValue::GetCurrentValue(double* aValue)
|
||||
NS_ENSURE_ARG_POINTER(aValue);
|
||||
*aValue = 0;
|
||||
|
||||
if (Intl()->IsDefunct())
|
||||
if (Intl().IsNull())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
double value = Intl()->CurValue();
|
||||
if (Intl().IsAccessible() && Intl().AsAccessible()->IsDefunct())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
double value;
|
||||
if (Intl().IsAccessible()) {
|
||||
value = Intl().AsAccessible()->CurValue();
|
||||
} else {
|
||||
value = Intl().AsProxy()->MinValue();
|
||||
}
|
||||
|
||||
if (!IsNaN(value))
|
||||
*aValue = value;
|
||||
|
||||
@ -61,10 +88,18 @@ xpcAccessibleValue::GetCurrentValue(double* aValue)
|
||||
NS_IMETHODIMP
|
||||
xpcAccessibleValue::SetCurrentValue(double aValue)
|
||||
{
|
||||
if (Intl()->IsDefunct())
|
||||
if (Intl().IsNull())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
Intl()->SetCurValue(aValue);
|
||||
if (Intl().IsAccessible() && Intl().AsAccessible()->IsDefunct())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
if (Intl().IsAccessible()) {
|
||||
Intl().AsAccessible()->SetCurValue(aValue);
|
||||
} else {
|
||||
Intl().AsProxy()->SetCurValue(aValue);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -74,10 +109,19 @@ xpcAccessibleValue::GetMinimumIncrement(double* aValue)
|
||||
NS_ENSURE_ARG_POINTER(aValue);
|
||||
*aValue = 0;
|
||||
|
||||
if (Intl()->IsDefunct())
|
||||
if (Intl().IsNull())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
double value = Intl()->Step();
|
||||
if (Intl().IsAccessible() && Intl().AsAccessible()->IsDefunct())
|
||||
return NS_ERROR_FAILURE;
|
||||
|
||||
double value = Intl().AsAccessible()->Step();
|
||||
if (Intl().IsAccessible()) {
|
||||
value = Intl().AsAccessible()->Step();
|
||||
} else {
|
||||
value = Intl().AsProxy()->Step();
|
||||
}
|
||||
|
||||
if (!IsNaN(value))
|
||||
*aValue = value;
|
||||
|
||||
|
@ -32,7 +32,7 @@ protected:
|
||||
virtual ~xpcAccessibleValue() {}
|
||||
|
||||
private:
|
||||
Accessible* Intl();
|
||||
AccessibleOrProxy Intl();
|
||||
|
||||
xpcAccessibleValue(const xpcAccessibleValue&) = delete;
|
||||
xpcAccessibleValue& operator =(const xpcAccessibleValue&) = delete;
|
||||
@ -40,5 +40,4 @@ private:
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
|
@ -136,7 +136,7 @@ ident:
|
||||
merge-%:
|
||||
ifdef LOCALE_MERGEDIR
|
||||
$(RM) -rf $(LOCALE_MERGEDIR)
|
||||
MACOSX_DEPLOYMENT_TARGET= compare-locales -m $(LOCALE_MERGEDIR) $(srcdir)/l10n.ini $(L10NBASEDIR) $*
|
||||
$(topsrcdir)/mach compare-locales --merge-dir $(LOCALE_MERGEDIR) $*
|
||||
endif
|
||||
@echo
|
||||
|
||||
|
@ -75,7 +75,7 @@
|
||||
accesskey="&emailPageCmd.accesskey;"
|
||||
command="Browser:SendLink"/>
|
||||
<menuseparator/>
|
||||
#if !defined(MOZ_WIDGET_GTK) && !defined(MOZ_WIDGET_QT)
|
||||
#if !defined(MOZ_WIDGET_GTK)
|
||||
<menuitem id="menu_printSetup"
|
||||
label="&printSetupCmd.label;"
|
||||
accesskey="&printSetupCmd.accesskey;"
|
||||
|
@ -273,7 +273,7 @@ toolbar[customizing] > .overflow-button {
|
||||
}
|
||||
%endif
|
||||
|
||||
%if !defined(MOZ_WIDGET_GTK) && !defined(MOZ_WIDGET_QT)
|
||||
%if !defined(MOZ_WIDGET_GTK)
|
||||
#TabsToolbar > .private-browsing-indicator {
|
||||
-moz-box-ordinal-group: 1000;
|
||||
}
|
||||
|
@ -561,7 +561,7 @@
|
||||
#ifdef MENUBAR_CAN_AUTOHIDE
|
||||
toolbarname="&menubarCmd.label;"
|
||||
accesskey="&menubarCmd.accesskey;"
|
||||
#if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)
|
||||
#if defined(MOZ_WIDGET_GTK)
|
||||
autohide="true"
|
||||
#endif
|
||||
#endif
|
||||
@ -590,7 +590,7 @@
|
||||
context="toolbar-context-menu"
|
||||
collapsed="true">
|
||||
|
||||
#if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)
|
||||
#if defined(MOZ_WIDGET_GTK)
|
||||
<hbox id="private-browsing-indicator"
|
||||
skipintoolbarset="true"/>
|
||||
#endif
|
||||
@ -640,7 +640,7 @@
|
||||
</menupopup>
|
||||
</toolbarbutton>
|
||||
|
||||
#if !defined(MOZ_WIDGET_GTK) && !defined(MOZ_WIDGET_QT)
|
||||
#if !defined(MOZ_WIDGET_GTK)
|
||||
<hbox class="private-browsing-indicator" skipintoolbarset="true"/>
|
||||
#endif
|
||||
#ifdef CAN_DRAW_IN_TITLEBAR
|
||||
|
@ -9,16 +9,6 @@
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Use inverted spinner icon on the dark background */
|
||||
.update-throbber {
|
||||
list-style-image: url("chrome://global/skin/icons/loading-inverted.png");
|
||||
}
|
||||
@media (min-resolution: 1.1dppx) {
|
||||
.update-throbber {
|
||||
list-style-image: url("chrome://global/skin/icons/loading-inverted@2x.png");
|
||||
}
|
||||
}
|
||||
|
||||
.text-link {
|
||||
color: #fff !important;
|
||||
text-decoration: underline;
|
||||
|
@ -9,16 +9,6 @@
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Use inverted spinner icon on the dark background */
|
||||
.update-throbber {
|
||||
list-style-image: url("chrome://global/skin/icons/loading-inverted.png");
|
||||
}
|
||||
@media (min-resolution: 1.1dppx) {
|
||||
.update-throbber {
|
||||
list-style-image: url("chrome://global/skin/icons/loading-inverted@2x.png");
|
||||
}
|
||||
}
|
||||
|
||||
.text-link {
|
||||
color: #fff !important;
|
||||
text-decoration: underline;
|
||||
|
@ -9,16 +9,6 @@
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* Use inverted spinner icon on the dark background */
|
||||
.update-throbber {
|
||||
list-style-image: url("chrome://global/skin/icons/loading-inverted.png");
|
||||
}
|
||||
@media (min-resolution: 1.1dppx) {
|
||||
.update-throbber {
|
||||
list-style-image: url("chrome://global/skin/icons/loading-inverted@2x.png");
|
||||
}
|
||||
}
|
||||
|
||||
.text-link {
|
||||
color: #fff !important;
|
||||
text-decoration: underline;
|
||||
|
@ -143,7 +143,6 @@
|
||||
<radio id="networkProxySOCKSVersion4" value="4" label="&socks4.label;" accesskey="&socks4.accesskey;" />
|
||||
<radio id="networkProxySOCKSVersion5" value="5" label="&socks5.label;" accesskey="&socks5.accesskey;" />
|
||||
</radiogroup>
|
||||
<checkbox id="networkProxySOCKSRemoteDNS" preference="network.proxy.socks_remote_dns" label="&socksRemoteDNS.label;" accesskey="&socksRemoteDNS.accesskey;" />
|
||||
</box>
|
||||
</row>
|
||||
<label value="&noproxy.label;" accesskey="&noproxy.accesskey;" control="networkProxyNone"/>
|
||||
@ -168,6 +167,7 @@
|
||||
accesskey="&autologinproxy.accesskey;"
|
||||
preference="signon.autologin.proxy"
|
||||
tooltiptext="&autologinproxy.tooltip;"/>
|
||||
<checkbox id="networkProxySOCKSRemoteDNS" preference="network.proxy.socks_remote_dns" label="&socksRemoteDNS.label2;" accesskey="&socksRemoteDNS.accesskey;" />
|
||||
<separator/>
|
||||
</prefpane>
|
||||
</prefwindow>
|
||||
|
@ -16,9 +16,9 @@
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"version": "gecko rust 1.9.0 (commit e4e8b666850a763fdf1c3c2c142856ab51e32779)",
|
||||
"size": 96854912,
|
||||
"digest": "d613d5528e83bb73917372948c05a766912a9dd0ec4e8a5fab69161a515c1545d52e9ed3394716df96a9dcdf1c086b6f970413e97c2df78a11e5f9151573921a",
|
||||
"version": "gecko rustc 1.10.0 (cfcb716cf 2016-07-03)",
|
||||
"size": 102276708,
|
||||
"digest": "8cc9ea8347fc7e6e6fdb15a8fd1faae977f1235a426b879b3f9128ec91d8f2b6268297ce80bf4eceb47738bd40bfeda13f143dc3fe85f1434b13adfbc095ab90",
|
||||
"algorithm": "sha512",
|
||||
"filename": "rustc.tar.xz",
|
||||
"unpack": true
|
||||
|
@ -16,9 +16,9 @@
|
||||
"unpack": true
|
||||
},
|
||||
{
|
||||
"version": "gecko rust 1.9.0 (commit e4e8b666850a763fdf1c3c2c142856ab51e32779)",
|
||||
"size": 96854912,
|
||||
"digest": "d613d5528e83bb73917372948c05a766912a9dd0ec4e8a5fab69161a515c1545d52e9ed3394716df96a9dcdf1c086b6f970413e97c2df78a11e5f9151573921a",
|
||||
"version": "gecko rustc 1.10.0 (cfcb716cf 2016-07-03)",
|
||||
"size": 102276708,
|
||||
"digest": "8cc9ea8347fc7e6e6fdb15a8fd1faae977f1235a426b879b3f9128ec91d8f2b6268297ce80bf4eceb47738bd40bfeda13f143dc3fe85f1434b13adfbc095ab90",
|
||||
"algorithm": "sha512",
|
||||
"filename": "rustc.tar.xz",
|
||||
"unpack": true
|
||||
|
@ -188,7 +188,7 @@ ident:
|
||||
merge-%:
|
||||
ifdef LOCALE_MERGEDIR
|
||||
$(RM) -rf $(LOCALE_MERGEDIR)
|
||||
MACOSX_DEPLOYMENT_TARGET= compare-locales -m $(LOCALE_MERGEDIR) $(srcdir)/l10n.ini $(L10NBASEDIR) $*
|
||||
$(topsrcdir)/mach compare-locales --merge-dir $(LOCALE_MERGEDIR) $*
|
||||
endif
|
||||
@echo
|
||||
|
||||
|
@ -32,7 +32,7 @@
|
||||
<!ENTITY socks4.accesskey "K">
|
||||
<!ENTITY socks5.label "SOCKS v5">
|
||||
<!ENTITY socks5.accesskey "v">
|
||||
<!ENTITY socksRemoteDNS.label "Remote DNS">
|
||||
<!ENTITY socksRemoteDNS.label2 "Proxy DNS when using SOCKS v5">
|
||||
<!ENTITY socksRemoteDNS.accesskey "d">
|
||||
<!ENTITY port.label "Port:">
|
||||
<!ENTITY HTTPport.accesskey "P">
|
||||
|
@ -1,62 +0,0 @@
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
import sys
|
||||
import re
|
||||
import codecs
|
||||
try:
|
||||
from Mozilla.Parser import getParser
|
||||
except ImportError:
|
||||
sys.exit('''extract-bookmarks needs compare-locales
|
||||
|
||||
Find that on http://pypi.python.org/pypi/compare-locales.
|
||||
This script has been tested with version 0.6, and might work with future
|
||||
versions.''')
|
||||
|
||||
ll=re.compile('\.(title|a|dd|h[0-9])$')
|
||||
|
||||
p = getParser(sys.argv[1])
|
||||
p.readFile(sys.argv[1])
|
||||
|
||||
template = '''#filter emptyLines
|
||||
|
||||
# LOCALIZATION NOTE: The 'en-US' strings in the URLs will be replaced with
|
||||
# your locale code, and link to your translated pages as soon as they're
|
||||
# live.
|
||||
|
||||
#define bookmarks_title %s
|
||||
#define bookmarks_heading %s
|
||||
|
||||
#define bookmarks_toolbarfolder %s
|
||||
#define bookmarks_toolbarfolder_description %s
|
||||
|
||||
# LOCALIZATION NOTE (getting_started):
|
||||
# link title for https://www.mozilla.org/en-US/firefox/central/
|
||||
#define getting_started %s
|
||||
|
||||
# LOCALIZATION NOTE (firefox_heading):
|
||||
# Firefox links folder name
|
||||
#define firefox_heading %s
|
||||
|
||||
# LOCALIZATION NOTE (firefox_help):
|
||||
# link title for https://www.mozilla.org/en-US/firefox/help/
|
||||
#define firefox_help %s
|
||||
|
||||
# LOCALIZATION NOTE (firefox_customize):
|
||||
# link title for https://www.mozilla.org/en-US/firefox/customize/
|
||||
#define firefox_customize %s
|
||||
|
||||
# LOCALIZATION NOTE (firefox_community):
|
||||
# link title for https://www.mozilla.org/en-US/contribute/
|
||||
#define firefox_community %s
|
||||
|
||||
# LOCALIZATION NOTE (firefox_about):
|
||||
# link title for https://www.mozilla.org/en-US/about/
|
||||
#define firefox_about %s
|
||||
|
||||
#unfilter emptyLines'''
|
||||
|
||||
strings = tuple(e.val for e in p if ll.search(e.key))
|
||||
|
||||
print codecs.utf_8_encode(template % strings)[0]
|
@ -450,16 +450,8 @@ TabWindow.prototype = {
|
||||
let preview = AeroPeek.taskbar.createTaskbarTabPreview(docShell, controller);
|
||||
preview.visible = AeroPeek.enabled;
|
||||
preview.active = this.tabbrowser.selectedTab == controller.tab;
|
||||
// Grab the default favicon
|
||||
getFaviconAsImage(
|
||||
null,
|
||||
PrivateBrowsingUtils.isWindowPrivate(this.win),
|
||||
function (img) {
|
||||
// It is possible that we've already gotten the real favicon, so make sure
|
||||
// we have not set one before setting this default one.
|
||||
if (!preview.icon)
|
||||
preview.icon = img;
|
||||
});
|
||||
this.onLinkIconAvailable(controller.tab.linkedBrowser,
|
||||
controller.tab.getAttribute("image"));
|
||||
return preview;
|
||||
},
|
||||
|
||||
@ -610,21 +602,20 @@ TabWindow.prototype = {
|
||||
"file", "chrome", "resource", "about"
|
||||
]),
|
||||
onLinkIconAvailable: function (aBrowser, aIconURL) {
|
||||
if (!aIconURL) {
|
||||
return;
|
||||
let requestURL = null;
|
||||
if (aIconURL) {
|
||||
let shouldRequestFaviconURL = true;
|
||||
try {
|
||||
urlObject = NetUtil.newURI(aIconURL);
|
||||
shouldRequestFaviconURL =
|
||||
!this.directRequestProtocols.has(urlObject.scheme);
|
||||
} catch (ex) {}
|
||||
|
||||
requestURL = shouldRequestFaviconURL ?
|
||||
"moz-anno:favicon:" + aIconURL :
|
||||
aIconURL;
|
||||
}
|
||||
let tab = this.tabbrowser.getTabForBrowser(aBrowser);
|
||||
let shouldRequestFaviconURL = true;
|
||||
try {
|
||||
urlObject = NetUtil.newURI(aIconURL);
|
||||
shouldRequestFaviconURL =
|
||||
!this.directRequestProtocols.has(urlObject.scheme);
|
||||
} catch (ex) {}
|
||||
|
||||
let requestURL = shouldRequestFaviconURL ?
|
||||
"moz-anno:favicon:" + aIconURL :
|
||||
aIconURL;
|
||||
|
||||
let isDefaultFavicon = !requestURL;
|
||||
getFaviconAsImage(
|
||||
requestURL,
|
||||
PrivateBrowsingUtils.isWindowPrivate(this.win),
|
||||
@ -635,8 +626,10 @@ TabWindow.prototype = {
|
||||
// will have finished fetching 'in order'.
|
||||
if (index != -1) {
|
||||
let tab = this.tabbrowser.tabs[index];
|
||||
if (tab.getAttribute("image") == aIconURL) {
|
||||
this.previews.get(tab).icon = img;
|
||||
let preview = this.previews.get(tab);
|
||||
if (tab.getAttribute("image") == aIconURL ||
|
||||
(!preview.icon && isDefaultFavicon)) {
|
||||
preview.icon = img;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -654,10 +647,12 @@ TabWindow.prototype = {
|
||||
this.AeroPeek = {
|
||||
available: false,
|
||||
// Does the pref say we're enabled?
|
||||
_prefenabled: true,
|
||||
__prefenabled: false,
|
||||
|
||||
_enabled: true,
|
||||
|
||||
initialized: false,
|
||||
|
||||
// nsITaskbarTabPreview array
|
||||
previews: [],
|
||||
|
||||
@ -681,25 +676,14 @@ this.AeroPeek = {
|
||||
if (!this.available)
|
||||
return;
|
||||
|
||||
this.prefs.addObserver(TOGGLE_PREF_NAME, this, false);
|
||||
this.prefs.addObserver(DISABLE_THRESHOLD_PREF_NAME, this, false);
|
||||
this.prefs.addObserver(CACHE_EXPIRATION_TIME_PREF_NAME, this, false);
|
||||
PlacesUtils.history.addObserver(this, true);
|
||||
|
||||
this.cacheLifespan = this.prefs.getIntPref(CACHE_EXPIRATION_TIME_PREF_NAME);
|
||||
|
||||
this.maxpreviews = this.prefs.getIntPref(DISABLE_THRESHOLD_PREF_NAME);
|
||||
|
||||
this.prefs.addObserver(TOGGLE_PREF_NAME, this, true);
|
||||
this.enabled = this._prefenabled = this.prefs.getBoolPref(TOGGLE_PREF_NAME);
|
||||
this.initialized = true;
|
||||
},
|
||||
|
||||
destroy: function destroy() {
|
||||
this._enabled = false;
|
||||
|
||||
this.prefs.removeObserver(TOGGLE_PREF_NAME, this);
|
||||
this.prefs.removeObserver(DISABLE_THRESHOLD_PREF_NAME, this);
|
||||
this.prefs.removeObserver(CACHE_EXPIRATION_TIME_PREF_NAME, this);
|
||||
|
||||
if (this.cacheTimer)
|
||||
this.cacheTimer.cancel();
|
||||
},
|
||||
@ -719,6 +703,61 @@ this.AeroPeek = {
|
||||
});
|
||||
},
|
||||
|
||||
get _prefenabled() {
|
||||
return this.__prefenabled;
|
||||
},
|
||||
|
||||
set _prefenabled(enable) {
|
||||
if (enable == this.__prefenabled) {
|
||||
return;
|
||||
}
|
||||
this.__prefenabled = enable;
|
||||
|
||||
if (enable) {
|
||||
this.enable();
|
||||
} else {
|
||||
this.disable();
|
||||
}
|
||||
},
|
||||
|
||||
_observersAdded: false,
|
||||
|
||||
enable() {
|
||||
if (!this._observersAdded) {
|
||||
this.prefs.addObserver(DISABLE_THRESHOLD_PREF_NAME, this, true);
|
||||
this.prefs.addObserver(CACHE_EXPIRATION_TIME_PREF_NAME, this, true);
|
||||
PlacesUtils.history.addObserver(this, true);
|
||||
this._observersAdded = true;
|
||||
}
|
||||
|
||||
this.cacheLifespan = this.prefs.getIntPref(CACHE_EXPIRATION_TIME_PREF_NAME);
|
||||
|
||||
this.maxpreviews = this.prefs.getIntPref(DISABLE_THRESHOLD_PREF_NAME);
|
||||
|
||||
// If the user toggled us on/off while the browser was already up
|
||||
// (rather than this code running on startup because the pref was
|
||||
// already set to true), we must initialize previews for open windows:
|
||||
if (this.initialized) {
|
||||
let browserWindows = Services.wm.getEnumerator("navigator:browser");
|
||||
while (browserWindows.hasMoreElements()) {
|
||||
let win = browserWindows.getNext();
|
||||
if (!win.closed) {
|
||||
this.onOpenWindow(win);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
disable() {
|
||||
while (this.windows.length) {
|
||||
// We can't call onCloseWindow here because it'll bail if we're not
|
||||
// enabled.
|
||||
let tabWinObject = this.windows[0];
|
||||
tabWinObject.destroy(); // This will remove us from the array.
|
||||
delete tabWinObject.win.gTaskbarTabGroup; // Tidy up the window.
|
||||
}
|
||||
},
|
||||
|
||||
addPreview: function (preview) {
|
||||
this.previews.push(preview);
|
||||
this.checkPreviewCount();
|
||||
@ -731,15 +770,15 @@ this.AeroPeek = {
|
||||
},
|
||||
|
||||
checkPreviewCount: function () {
|
||||
if (this.previews.length > this.maxpreviews)
|
||||
this.enabled = false;
|
||||
else
|
||||
this.enabled = this._prefenabled;
|
||||
if (!this._prefenabled) {
|
||||
return;
|
||||
}
|
||||
this.enabled = this.previews.length <= this.maxpreviews;
|
||||
},
|
||||
|
||||
onOpenWindow: function (win) {
|
||||
// This occurs when the taskbar service is not available (xp, vista)
|
||||
if (!this.available)
|
||||
if (!this.available || !this._prefenabled)
|
||||
return;
|
||||
|
||||
win.gTaskbarTabGroup = new TabWindow(win);
|
||||
@ -747,7 +786,7 @@ this.AeroPeek = {
|
||||
|
||||
onCloseWindow: function (win) {
|
||||
// This occurs when the taskbar service is not available (xp, vista)
|
||||
if (!this.available)
|
||||
if (!this.available || !this._prefenabled)
|
||||
return;
|
||||
|
||||
win.gTaskbarTabGroup.destroy();
|
||||
@ -764,14 +803,18 @@ this.AeroPeek = {
|
||||
|
||||
//// nsIObserver
|
||||
observe: function (aSubject, aTopic, aData) {
|
||||
if (aTopic == "nsPref:changed" && aData == TOGGLE_PREF_NAME) {
|
||||
this._prefenabled = this.prefs.getBoolPref(TOGGLE_PREF_NAME);
|
||||
}
|
||||
if (!this._prefenabled) {
|
||||
return;
|
||||
}
|
||||
switch (aTopic) {
|
||||
case "nsPref:changed":
|
||||
if (aData == CACHE_EXPIRATION_TIME_PREF_NAME)
|
||||
break;
|
||||
|
||||
if (aData == TOGGLE_PREF_NAME)
|
||||
this._prefenabled = this.prefs.getBoolPref(TOGGLE_PREF_NAME);
|
||||
else if (aData == DISABLE_THRESHOLD_PREF_NAME)
|
||||
if (aData == DISABLE_THRESHOLD_PREF_NAME)
|
||||
this.maxpreviews = this.prefs.getIntPref(DISABLE_THRESHOLD_PREF_NAME);
|
||||
// Might need to enable/disable ourselves
|
||||
this.checkPreviewCount();
|
||||
@ -796,7 +839,7 @@ this.AeroPeek = {
|
||||
onClearHistory() {},
|
||||
onDeleteVisits() {},
|
||||
onPageChanged(uri, changedConst, newValue) {
|
||||
if (this._enabled && changedConst == Ci.nsINavHistoryObserver.ATTRIBUTE_FAVICON) {
|
||||
if (this.enabled && changedConst == Ci.nsINavHistoryObserver.ATTRIBUTE_FAVICON) {
|
||||
for (let win of this.windows) {
|
||||
for (let [tab, preview] of win.previews) {
|
||||
if (tab.getAttribute("image") == newValue) {
|
||||
@ -807,7 +850,11 @@ this.AeroPeek = {
|
||||
}
|
||||
},
|
||||
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsISupportsWeakReference, Ci.nsINavHistoryObserver]),
|
||||
QueryInterface: XPCOMUtils.generateQI([
|
||||
Ci.nsISupportsWeakReference,
|
||||
Ci.nsINavHistoryObserver,
|
||||
Ci.nsIObserver
|
||||
]),
|
||||
};
|
||||
|
||||
XPCOMUtils.defineLazyGetter(AeroPeek, "cacheTimer", () =>
|
||||
|
@ -35,13 +35,10 @@ function test() {
|
||||
ok(preview.visible, "Preview is shown as expected");
|
||||
|
||||
gPrefService.setBoolPref(ENABLE_PREF_NAME, false);
|
||||
checkPreviews(4, "Previews are unchanged when disabling");
|
||||
|
||||
for (let preview of AeroPeek.previews)
|
||||
ok(!preview.visible, "Preview is not shown as expected after disabling");
|
||||
is(0, AeroPeek.previews.length, "Should have 0 previews when disabled");
|
||||
|
||||
gPrefService.setBoolPref(ENABLE_PREF_NAME, true);
|
||||
checkPreviews(4, "Previews are unchanged when re-enabling");
|
||||
checkPreviews(4, "Previews are back when re-enabling");
|
||||
for (let preview of AeroPeek.previews)
|
||||
ok(preview.visible, "Preview is shown as expected after re-enabling");
|
||||
|
||||
@ -82,14 +79,14 @@ function test() {
|
||||
checkPreviews(1);
|
||||
|
||||
if (gPrefService.prefHasUserValue(ENABLE_PREF_NAME))
|
||||
gPrefService.clearUserPref(ENABLE_PREF_NAME);
|
||||
gPrefService.setBoolPref(ENABLE_PREF_NAME, !gPrefService.getBoolPref(ENABLE_PREF_NAME));
|
||||
|
||||
finish();
|
||||
|
||||
function checkPreviews(aPreviews, msg) {
|
||||
let nPreviews = AeroPeek.previews.length;
|
||||
is(aPreviews, gBrowser.tabs.length, "Browser has expected number of tabs");
|
||||
is(nPreviews, gBrowser.tabs.length, "Browser has one preview per tab");
|
||||
is(aPreviews, gBrowser.tabs.length, "Browser has expected number of tabs - " + msg);
|
||||
is(nPreviews, gBrowser.tabs.length, "Browser has one preview per tab - " + msg);
|
||||
is(nPreviews, aPreviews, msg || "Got expected number of previews");
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@ toolkit = CONFIG['MOZ_WIDGET_TOOLKIT']
|
||||
|
||||
if toolkit == 'cocoa':
|
||||
DIRS += ['osx']
|
||||
elif toolkit in ('gtk2', 'gtk3', 'qt'):
|
||||
elif toolkit in ('gtk2', 'gtk3'):
|
||||
DIRS += ['linux']
|
||||
else:
|
||||
DIRS += ['windows']
|
||||
|
@ -91,7 +91,7 @@
|
||||
.geo-icon {
|
||||
%ifdef XP_MACOSX
|
||||
list-style-image: url(chrome://browser/skin/permissions.svg#geo-osx);
|
||||
%elif defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)
|
||||
%elif defined(MOZ_WIDGET_GTK)
|
||||
list-style-image: url(chrome://browser/skin/permissions.svg#geo-linux);
|
||||
%else
|
||||
list-style-image: url(chrome://browser/skin/permissions.svg#geo-windows);
|
||||
@ -101,7 +101,7 @@
|
||||
.geo-icon.blocked {
|
||||
%ifdef XP_MACOSX
|
||||
list-style-image: url(chrome://browser/skin/permissions.svg#geo-osx-blocked);
|
||||
%elif defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)
|
||||
%elif defined(MOZ_WIDGET_GTK)
|
||||
list-style-image: url(chrome://browser/skin/permissions.svg#geo-linux-blocked);
|
||||
%else
|
||||
list-style-image: url(chrome://browser/skin/permissions.svg#geo-windows-blocked);
|
||||
@ -111,7 +111,7 @@
|
||||
.popup-notification-icon[popupid="geolocation"] {
|
||||
%ifdef XP_MACOSX
|
||||
list-style-image: url(chrome://browser/skin/permissions.svg#geo-osx);
|
||||
%elif defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)
|
||||
%elif defined(MOZ_WIDGET_GTK)
|
||||
list-style-image: url(chrome://browser/skin/permissions.svg#geo-linux-detailed);
|
||||
%else
|
||||
list-style-image: url(chrome://browser/skin/permissions.svg#geo-windows-detailed);
|
||||
|
@ -7,7 +7,7 @@
|
||||
%filter substitution
|
||||
%ifdef XP_MACOSX
|
||||
%include ../osx/shared.inc
|
||||
%elif defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)
|
||||
%elif defined(MOZ_WIDGET_GTK)
|
||||
%include ../linux/linuxShared.inc
|
||||
%else
|
||||
%include ../windows/windowsShared.inc
|
||||
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
@ -7,6 +7,8 @@
|
||||
# Avoid duplication if the file happens to be included twice.
|
||||
if test -z "$bucket" -a -z "$NO_CACHE"; then
|
||||
|
||||
# buildbot (or builders that use buildprops.json):
|
||||
if [ -f $topsrcdir/../buildprops.json ]; then
|
||||
read branch platform master <<EOF
|
||||
$(python2.7 -c 'import json; p = json.loads(open("'"$topsrcdir"'/../buildprops.json").read())["properties"]; print p["branch"], p["platform"], p["master"]' 2> /dev/null)
|
||||
EOF
|
||||
@ -40,6 +42,53 @@ if test -z "$SCCACHE_DISABLE" -a -z "$no_sccache" -a -z "$MOZ_PGO_IS_SET" -a -z
|
||||
esac
|
||||
fi
|
||||
|
||||
# builds without buildprops (eg: taskcluster or non-buildbot) and without ccache env config and without sccache disabled:
|
||||
elif test -z "$CCACHE_DIR" -a -z "$SCCACHE_DISABLE" -a -z "$no_sccache" -a -z "$MOZ_PGO_IS_SET" -a -z "$MOZ_PGO"; then
|
||||
|
||||
# prevent rerun if az is set, or wget is not available
|
||||
if test -z "$availability_zone" -a -x "$(command -v wget)"; then
|
||||
# timeout after 1 second, and don't retry (failure indicates instance is not in ec2 or network issue)
|
||||
# availability_zone is of the form <region><letter> where region is e.g. us-west-2, and az is us-west-2a
|
||||
availability_zone=$(wget -T 1 -t 1 -q -O - http://169.254.169.254/latest/meta-data/placement/availability-zone || true)
|
||||
if test -z "$availability_zone" -o "$availability_zone" = "not-ec2"; then
|
||||
availability_zone=not-ec2
|
||||
else
|
||||
# region is az with last letter trimmed
|
||||
region=${availability_zone%?}
|
||||
# set S3 bucket according to tree (level)
|
||||
case "${GECKO_HEAD_REPOSITORY}" in
|
||||
*hg.mozilla.org/try*)
|
||||
bucket=taskcluster-level-1-sccache-${region}
|
||||
;;
|
||||
*hg.mozilla.org/integration/mozilla-inbound*|*hg.mozilla.org/integration/fx-team*)
|
||||
bucket=taskcluster-level-3-sccache-${region}
|
||||
;;
|
||||
esac
|
||||
|
||||
# set a dummy master
|
||||
case "${region}" in
|
||||
us-east-1)
|
||||
master=dummy.use1.mozilla.com
|
||||
;;
|
||||
us-west-1)
|
||||
master=dummy.usw1.mozilla.com
|
||||
;;
|
||||
us-west-2)
|
||||
master=dummy.usw2.mozilla.com
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
fi
|
||||
|
||||
|
||||
# set platform based on the SYSTEMROOT env var
|
||||
case "${SYSTEMROOT}" in
|
||||
*Windows)
|
||||
platform=windows
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
if test -z "$bucket"; then
|
||||
case "$platform" in
|
||||
win*) : ;;
|
||||
@ -53,7 +102,7 @@ else
|
||||
fi
|
||||
mk_add_options "export SCCACHE_BUCKET=$bucket"
|
||||
case "$master" in
|
||||
*use1.mozilla.com*|*usw2.mozilla.com*)
|
||||
*us[ew][12].mozilla.com*)
|
||||
mk_add_options "export SCCACHE_NAMESERVER=169.254.169.253"
|
||||
;;
|
||||
esac
|
||||
|
@ -284,6 +284,8 @@ skip-if = e10s && debug
|
||||
skip-if = e10s # TODO
|
||||
[browser_dbg_instruments-pane-collapse.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_instruments-pane-collapse_keyboard.js]
|
||||
skip-if = (os == 'mac' && e10s && debug) # Full keyboard navigation on OSX only works if Full Keyboard Access setting is set to All Control
|
||||
[browser_dbg_interrupts.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_listaddons.js]
|
||||
|
@ -0,0 +1,40 @@
|
||||
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
/**
|
||||
* Tests that the debugger panes collapse properly.
|
||||
*/
|
||||
|
||||
const TAB_URL = EXAMPLE_URL + "doc_recursion-stack.html";
|
||||
|
||||
function test() {
|
||||
initDebugger(TAB_URL).then(([aTab,, aPanel]) => {
|
||||
Task.spawn(function* () {
|
||||
let doc = aPanel.panelWin.document;
|
||||
let panel = doc.getElementById("instruments-pane");
|
||||
let button = doc.getElementById("instruments-pane-toggle");
|
||||
ok(panel.classList.contains("pane-collapsed"),
|
||||
"The instruments panel is initially in collapsed state");
|
||||
|
||||
yield togglePane(button, "Press on the toggle button to expand", panel, "VK_RETURN");
|
||||
ok(!panel.classList.contains("pane-collapsed"),
|
||||
"The instruments panel is in the expanded state");
|
||||
|
||||
yield togglePane(button, "Press on the toggle button to collapse", panel, "VK_SPACE");
|
||||
ok(panel.classList.contains("pane-collapsed"),
|
||||
"The instruments panel is in the collapsed state");
|
||||
|
||||
closeDebuggerAndFinish(aPanel);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function* togglePane(button, message, pane, keycode) {
|
||||
let onTransitionEnd = once(pane, "transitionend");
|
||||
info(message);
|
||||
button.focus();
|
||||
EventUtils.synthesizeKey(keycode, {});
|
||||
yield onTransitionEnd;
|
||||
}
|
@ -21,6 +21,7 @@ function ToolbarView(DebuggerController, DebuggerView) {
|
||||
this.DebuggerController = DebuggerController;
|
||||
this.DebuggerView = DebuggerView;
|
||||
|
||||
this._onTogglePanesActivated = this._onTogglePanesActivated.bind(this);
|
||||
this._onTogglePanesPressed = this._onTogglePanesPressed.bind(this);
|
||||
this._onResumePressed = this._onResumePressed.bind(this);
|
||||
this._onStepOverPressed = this._onStepOverPressed.bind(this);
|
||||
@ -62,7 +63,10 @@ ToolbarView.prototype = {
|
||||
this._stepInTooltip = L10N.getFormatStr("stepInTooltip", stepInKey);
|
||||
this._stepOutTooltip = L10N.getFormatStr("stepOutTooltip", stepOutKey);
|
||||
|
||||
this._instrumentsPaneToggleButton.addEventListener("mousedown", this._onTogglePanesPressed, false);
|
||||
this._instrumentsPaneToggleButton.addEventListener("mousedown",
|
||||
this._onTogglePanesActivated, false);
|
||||
this._instrumentsPaneToggleButton.addEventListener("keydown",
|
||||
this._onTogglePanesPressed, false);
|
||||
this._resumeButton.addEventListener("mousedown", this._onResumePressed, false);
|
||||
this._stepOverButton.addEventListener("mousedown", this._onStepOverPressed, false);
|
||||
this._stepInButton.addEventListener("mousedown", this._onStepInPressed, false);
|
||||
@ -82,7 +86,10 @@ ToolbarView.prototype = {
|
||||
destroy: function () {
|
||||
dumpn("Destroying the ToolbarView");
|
||||
|
||||
this._instrumentsPaneToggleButton.removeEventListener("mousedown", this._onTogglePanesPressed, false);
|
||||
this._instrumentsPaneToggleButton.removeEventListener("mousedown",
|
||||
this._onTogglePanesActivated, false);
|
||||
this._instrumentsPaneToggleButton.removeEventListener("keydown",
|
||||
this._onTogglePanesPressed, false);
|
||||
this._resumeButton.removeEventListener("mousedown", this._onResumePressed, false);
|
||||
this._stepOverButton.removeEventListener("mousedown", this._onStepOverPressed, false);
|
||||
this._stepInButton.removeEventListener("mousedown", this._onStepInPressed, false);
|
||||
@ -168,10 +175,19 @@ ToolbarView.prototype = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Listener handling the toggle button space and return key event.
|
||||
*/
|
||||
_onTogglePanesPressed: function (event) {
|
||||
if (ViewHelpers.isSpaceOrReturn(event)) {
|
||||
this._onTogglePanesActivated();
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Listener handling the toggle button click event.
|
||||
*/
|
||||
_onTogglePanesPressed: function () {
|
||||
_onTogglePanesActivated: function() {
|
||||
DebuggerView.toggleInstrumentsPane({
|
||||
visible: DebuggerView.instrumentsPaneHidden,
|
||||
animated: true,
|
||||
|
@ -99,7 +99,8 @@ function InspectorPanel(iframeWindow, toolbox) {
|
||||
this.onNewSelection = this.onNewSelection.bind(this);
|
||||
this.onBeforeNewSelection = this.onBeforeNewSelection.bind(this);
|
||||
this.onDetached = this.onDetached.bind(this);
|
||||
this.onPaneToggleButtonClicked = this.onPaneToggleButtonClicked.bind(this);
|
||||
this.onPaneToggleButtonActivated = this.onPaneToggleButtonActivated.bind(this);
|
||||
this.onPaneToggleButtonPressed = this.onPaneToggleButtonPressed.bind(this);
|
||||
this._onMarkupFrameLoad = this._onMarkupFrameLoad.bind(this);
|
||||
|
||||
let doc = this.panelDoc;
|
||||
@ -447,7 +448,8 @@ InspectorPanel.prototype = {
|
||||
"devtools/client/shared/components/sidebar-toggle"));
|
||||
|
||||
let sidebarToggle = SidebarToggle({
|
||||
onClick: this.onPaneToggleButtonClicked,
|
||||
onClick: this.onPaneToggleButtonActivated,
|
||||
onKeyDown: this.onPaneToggleButtonPressed,
|
||||
collapsed: false,
|
||||
expandPaneTitle: strings.GetStringFromName("inspector.expandPane"),
|
||||
collapsePaneTitle: strings.GetStringFromName("inspector.collapsePane"),
|
||||
@ -1153,11 +1155,21 @@ InspectorPanel.prototype = {
|
||||
return destroyPromise;
|
||||
},
|
||||
|
||||
/**
|
||||
* When the pane toggle button is pressed with space and return keys toggle
|
||||
* the pane, change the button state and tooltip.
|
||||
*/
|
||||
onPaneToggleButtonPressed: function (event) {
|
||||
if (ViewHelpers.isSpaceOrReturn(event)) {
|
||||
this.onPaneToggleButtonActivated(event);
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* When the pane toggle button is clicked, toggle the pane, change the button
|
||||
* state and tooltip.
|
||||
*/
|
||||
onPaneToggleButtonClicked: function (e) {
|
||||
onPaneToggleButtonActivated: function (e) {
|
||||
let sidePane = this.panelDoc.querySelector("#inspector-sidebar");
|
||||
let isVisible = !this._sidebarToggle.state.collapsed;
|
||||
|
||||
|
@ -172,7 +172,7 @@ MarkupView.prototype = {
|
||||
this.eventDetailsTooltip = new HTMLTooltip(this._inspector.toolbox,
|
||||
{type: "arrow"});
|
||||
this.imagePreviewTooltip = new HTMLTooltip(this._inspector.toolbox,
|
||||
{type: "arrow"});
|
||||
{type: "arrow", useXulWrapper: "true"});
|
||||
this._enableImagePreviewTooltip();
|
||||
},
|
||||
|
||||
|
@ -125,7 +125,8 @@ skip-if = e10s # Bug 1036409 - The last selected node isn't reselected
|
||||
[browser_markup_tag_edit_01.js]
|
||||
[browser_markup_tag_edit_02.js]
|
||||
[browser_markup_tag_edit_03.js]
|
||||
[browser_markup_tag_edit_04.js]
|
||||
[browser_markup_tag_edit_04-backspace.js]
|
||||
[browser_markup_tag_edit_04-delete.js]
|
||||
[browser_markup_tag_edit_05.js]
|
||||
[browser_markup_tag_edit_06.js]
|
||||
[browser_markup_tag_edit_07.js]
|
||||
|
@ -0,0 +1,59 @@
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Tests that a node can be deleted from the markup-view with the backspace key.
|
||||
// Also checks that after deletion the correct element is highlighted.
|
||||
// The previous sibling is preferred, but the parent is a fallback.
|
||||
|
||||
const HTML = `<style type="text/css">
|
||||
#pseudo::before { content: 'before'; }
|
||||
#pseudo::after { content: 'after'; }
|
||||
</style>
|
||||
<div id="parent">
|
||||
<div id="first"></div>
|
||||
<div id="second"></div>
|
||||
<div id="third"></div>
|
||||
</div>
|
||||
<div id="only-child">
|
||||
<div id="fourth"></div>
|
||||
</div>
|
||||
<div id="pseudo">
|
||||
<div id="fifth"></div>
|
||||
</div>`;
|
||||
const TEST_URL = "data:text/html;charset=utf-8," + encodeURIComponent(HTML);
|
||||
|
||||
// List of all the test cases. Each item is an object with the following props:
|
||||
// - selector: the css selector of the node that should be selected
|
||||
// - focusedSelector: the css selector of the node we expect to be selected as
|
||||
// a result of the deletion
|
||||
// - pseudo: (optional) if the focused node is actually supposed to be a pseudo element
|
||||
// of the specified selector.
|
||||
// Note that after each test case, undo is called.
|
||||
const TEST_DATA = [{
|
||||
selector: "#first",
|
||||
focusedSelector: "#second"
|
||||
}, {
|
||||
selector: "#second",
|
||||
focusedSelector: "#first"
|
||||
}, {
|
||||
selector: "#third",
|
||||
focusedSelector: "#second"
|
||||
}, {
|
||||
selector: "#fourth",
|
||||
focusedSelector: "#only-child"
|
||||
}, {
|
||||
selector: "#fifth",
|
||||
focusedSelector: "#pseudo",
|
||||
pseudo: "before"
|
||||
}];
|
||||
|
||||
add_task(function* () {
|
||||
let {inspector} = yield openInspectorForURL(TEST_URL);
|
||||
|
||||
for (let data of TEST_DATA) {
|
||||
yield checkDeleteAndSelection(inspector, "back_space", data);
|
||||
}
|
||||
});
|
@ -0,0 +1,59 @@
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Tests that a node can be deleted from the markup-view with the delete key.
|
||||
// Also checks that after deletion the correct element is highlighted.
|
||||
// The next sibling is preferred, but the parent is a fallback.
|
||||
|
||||
const HTML = `<style type="text/css">
|
||||
#pseudo::before { content: 'before'; }
|
||||
#pseudo::after { content: 'after'; }
|
||||
</style>
|
||||
<div id="parent">
|
||||
<div id="first"></div>
|
||||
<div id="second"></div>
|
||||
<div id="third"></div>
|
||||
</div>
|
||||
<div id="only-child">
|
||||
<div id="fourth"></div>
|
||||
</div>
|
||||
<div id="pseudo">
|
||||
<div id="fifth"></div>
|
||||
</div>`;
|
||||
const TEST_URL = "data:text/html;charset=utf-8," + encodeURIComponent(HTML);
|
||||
|
||||
// List of all the test cases. Each item is an object with the following props:
|
||||
// - selector: the css selector of the node that should be selected
|
||||
// - focusedSelector: the css selector of the node we expect to be selected as
|
||||
// a result of the deletion
|
||||
// - pseudo: (optional) if the focused node is actually supposed to be a pseudo element
|
||||
// of the specified selector.
|
||||
// Note that after each test case, undo is called.
|
||||
const TEST_DATA = [{
|
||||
selector: "#first",
|
||||
focusedSelector: "#second"
|
||||
}, {
|
||||
selector: "#second",
|
||||
focusedSelector: "#third"
|
||||
}, {
|
||||
selector: "#third",
|
||||
focusedSelector: "#second"
|
||||
}, {
|
||||
selector: "#fourth",
|
||||
focusedSelector: "#only-child"
|
||||
}, {
|
||||
selector: "#fifth",
|
||||
focusedSelector: "#pseudo",
|
||||
pseudo: "after"
|
||||
}];
|
||||
|
||||
add_task(function* () {
|
||||
let {inspector} = yield openInspectorForURL(TEST_URL);
|
||||
|
||||
for (let data of TEST_DATA) {
|
||||
yield checkDeleteAndSelection(inspector, "delete", data);
|
||||
}
|
||||
});
|
@ -1,121 +0,0 @@
|
||||
/* vim: set ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
// Tests that a node can be deleted from the markup-view with the delete key.
|
||||
// Also checks that after deletion the correct element is highlighted.
|
||||
// The next sibling is preferred, but the parent is a fallback.
|
||||
|
||||
const HTML = `<style type="text/css">
|
||||
#pseudo::before { content: 'before'; }
|
||||
#pseudo::after { content: 'after'; }
|
||||
</style>
|
||||
<div id="parent">
|
||||
<div id="first"></div>
|
||||
<div id="second"></div>
|
||||
<div id="third"></div>
|
||||
</div>
|
||||
<div id="only-child">
|
||||
<div id="fourth"></div>
|
||||
</div>
|
||||
<div id="pseudo">
|
||||
<div id="fifth"></div>
|
||||
</div>`;
|
||||
const TEST_URL = "data:text/html;charset=utf-8," + encodeURIComponent(HTML);
|
||||
|
||||
// List of all the test cases. Each item is an object with the following props:
|
||||
// - selector: the css selector of the node that should be selected
|
||||
// - key: the key to press to delete the node (delete or back_space)
|
||||
// - focusedSelector: the css selector of the node we expect to be selected as
|
||||
// a result of the deletion
|
||||
// - pseudo: (optional) if the focused node is actually supposed to be a pseudo element
|
||||
// of the specified selector.
|
||||
// Note that after each test case, undo is called.
|
||||
const TEST_DATA = [{
|
||||
selector: "#first",
|
||||
key: "delete",
|
||||
focusedSelector: "#second"
|
||||
}, {
|
||||
selector: "#second",
|
||||
key: "delete",
|
||||
focusedSelector: "#third"
|
||||
}, {
|
||||
selector: "#third",
|
||||
key: "delete",
|
||||
focusedSelector: "#second"
|
||||
}, {
|
||||
selector: "#fourth",
|
||||
key: "delete",
|
||||
focusedSelector: "#only-child"
|
||||
}, {
|
||||
selector: "#fifth",
|
||||
key: "delete",
|
||||
focusedSelector: "#pseudo",
|
||||
pseudo: "after"
|
||||
}, {
|
||||
selector: "#first",
|
||||
key: "back_space",
|
||||
focusedSelector: "#second"
|
||||
}, {
|
||||
selector: "#second",
|
||||
key: "back_space",
|
||||
focusedSelector: "#first"
|
||||
}, {
|
||||
selector: "#third",
|
||||
key: "back_space",
|
||||
focusedSelector: "#second"
|
||||
}, {
|
||||
selector: "#fourth",
|
||||
key: "back_space",
|
||||
focusedSelector: "#only-child"
|
||||
}, {
|
||||
selector: "#fifth",
|
||||
key: "back_space",
|
||||
focusedSelector: "#pseudo",
|
||||
pseudo: "before"
|
||||
}];
|
||||
|
||||
add_task(function* () {
|
||||
let {inspector} = yield openInspectorForURL(TEST_URL);
|
||||
|
||||
for (let data of TEST_DATA) {
|
||||
yield checkDeleteAndSelection(inspector, data);
|
||||
}
|
||||
});
|
||||
|
||||
function* checkDeleteAndSelection(inspector, {key, selector, focusedSelector, pseudo}) {
|
||||
info("Test deleting node " + selector + " with " + key + ", " +
|
||||
"expecting " + focusedSelector + " to be focused");
|
||||
|
||||
info("Select node " + selector + " and make sure it is focused");
|
||||
yield selectNode(selector, inspector);
|
||||
yield clickContainer(selector, inspector);
|
||||
|
||||
info("Delete the node with: " + key);
|
||||
let mutated = inspector.once("markupmutation");
|
||||
EventUtils.sendKey(key, inspector.panelWin);
|
||||
yield Promise.all([mutated, inspector.once("inspector-updated")]);
|
||||
|
||||
let nodeFront = yield getNodeFront(focusedSelector, inspector);
|
||||
if (pseudo) {
|
||||
// Update the selector for logging in case of failure.
|
||||
focusedSelector = focusedSelector + "::" + pseudo;
|
||||
// Retrieve the :before or :after pseudo element of the nodeFront.
|
||||
let {nodes} = yield inspector.walker.children(nodeFront);
|
||||
nodeFront = pseudo === "before" ? nodes[0] : nodes[nodes.length - 1];
|
||||
}
|
||||
|
||||
is(inspector.selection.nodeFront, nodeFront,
|
||||
focusedSelector + " is selected after deletion");
|
||||
|
||||
info("Check that the node was really removed");
|
||||
let node = yield getNodeFront(selector, inspector);
|
||||
ok(!node, "The node can't be found in the page anymore");
|
||||
|
||||
info("Undo the deletion to restore the original markup");
|
||||
yield undoChange(inspector);
|
||||
node = yield getNodeFront(selector, inspector);
|
||||
ok(node, "The node is back");
|
||||
}
|
@ -610,3 +610,53 @@ function* waitForScrollStop(doc) {
|
||||
|
||||
return lastScrollTop;
|
||||
}
|
||||
|
||||
/**
|
||||
* Select a node in the inspector and try to delete it using the provided key. After that,
|
||||
* check that the expected element is focused.
|
||||
*
|
||||
* @param {InspectorPanel} inspector
|
||||
* The current inspector-panel instance.
|
||||
* @param {String} key
|
||||
* The key to simulate to delete the node
|
||||
* @param {Object}
|
||||
* - {String} selector: selector of the element to delete.
|
||||
* - {String} focusedSelector: selector of the element that should be selected
|
||||
* after deleting the node.
|
||||
* - {String} pseudo: optional, "before" or "after" if the element focused after
|
||||
* deleting the node is supposed to be a before/after pseudo-element.
|
||||
*/
|
||||
function* checkDeleteAndSelection(inspector, key, {selector, focusedSelector, pseudo}) {
|
||||
info("Test deleting node " + selector + " with " + key + ", " +
|
||||
"expecting " + focusedSelector + " to be focused");
|
||||
|
||||
info("Select node " + selector + " and make sure it is focused");
|
||||
yield selectNode(selector, inspector);
|
||||
yield clickContainer(selector, inspector);
|
||||
|
||||
info("Delete the node with: " + key);
|
||||
let mutated = inspector.once("markupmutation");
|
||||
EventUtils.sendKey(key, inspector.panelWin);
|
||||
yield Promise.all([mutated, inspector.once("inspector-updated")]);
|
||||
|
||||
let nodeFront = yield getNodeFront(focusedSelector, inspector);
|
||||
if (pseudo) {
|
||||
// Update the selector for logging in case of failure.
|
||||
focusedSelector = focusedSelector + "::" + pseudo;
|
||||
// Retrieve the :before or :after pseudo element of the nodeFront.
|
||||
let {nodes} = yield inspector.walker.children(nodeFront);
|
||||
nodeFront = pseudo === "before" ? nodes[0] : nodes[nodes.length - 1];
|
||||
}
|
||||
|
||||
is(inspector.selection.nodeFront, nodeFront,
|
||||
focusedSelector + " is selected after deletion");
|
||||
|
||||
info("Check that the node was really removed");
|
||||
let node = yield getNodeFront(selector, inspector);
|
||||
ok(!node, "The node can't be found in the page anymore");
|
||||
|
||||
info("Undo the deletion to restore the original markup");
|
||||
yield undoChange(inspector);
|
||||
node = yield getNodeFront(selector, inspector);
|
||||
ok(node, "The node is back");
|
||||
}
|
||||
|
@ -280,7 +280,8 @@ TooltipsOverlay.prototype = {
|
||||
|
||||
// Image, fonts, ... preview tooltip
|
||||
this.previewTooltip = new HTMLTooltip(this.view.inspector.toolbox, {
|
||||
type: "arrow"
|
||||
type: "arrow",
|
||||
useXulWrapper: true
|
||||
});
|
||||
this.previewTooltip.startTogglingOnHover(this.view.element,
|
||||
this._onPreviewTooltipTargetHover.bind(this));
|
||||
|
@ -114,6 +114,8 @@ subsuite = clipboard
|
||||
[browser_inspector_pane-toggle-02.js]
|
||||
[browser_inspector_pane-toggle-03.js]
|
||||
[browser_inspector_pane-toggle-04.js]
|
||||
[browser_inspector_pane-toggle-05.js]
|
||||
skip-if = os == "mac" # Full keyboard navigation on OSX only works if Full Keyboard Access setting is set to All Control in System Keyboard
|
||||
[browser_inspector_picker-stop-on-destroy.js]
|
||||
[browser_inspector_picker-stop-on-tool-change.js]
|
||||
[browser_inspector_pseudoclass-lock.js]
|
||||
|
@ -0,0 +1,32 @@
|
||||
/* vim: set ft=javascript ts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* Test the keyboard navigation for the pane toggle using
|
||||
* space and enter
|
||||
*/
|
||||
|
||||
add_task(function* () {
|
||||
let {inspector} = yield openInspectorForURL("about:blank", "side");
|
||||
let panel = inspector.panelDoc.querySelector("#inspector-sidebar");
|
||||
let button = inspector.panelDoc.querySelector(".sidebar-toggle");
|
||||
|
||||
ok(!panel.classList.contains("pane-collapsed"), "The panel is in expanded state");
|
||||
|
||||
yield togglePane(button, "Press on the toggle button", panel, "VK_RETURN");
|
||||
ok(panel.classList.contains("pane-collapsed"), "The panel is in collapsed state");
|
||||
|
||||
yield togglePane(button, "Press on the toggle button to expand the panel again",
|
||||
panel, "VK_SPACE");
|
||||
ok(!panel.classList.contains("pane-collapsed"), "The panel is in expanded state");
|
||||
});
|
||||
|
||||
function* togglePane(button, message, panel, keycode) {
|
||||
let onTransitionEnd = once(panel, "transitionend");
|
||||
info(message);
|
||||
button.focus();
|
||||
EventUtils.synthesizeKey(keycode, {});
|
||||
yield onTransitionEnd;
|
||||
}
|
@ -493,7 +493,10 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
||||
window.addEventListener("resize", this._onResize, false);
|
||||
|
||||
this.requestsMenuSortEvent = getKeyWithEvent(this.sortBy.bind(this));
|
||||
this.requestsMenuSortKeyboardEvent = getKeyWithEvent(this.sortBy.bind(this), true);
|
||||
this.requestsMenuFilterEvent = getKeyWithEvent(this.filterOn.bind(this));
|
||||
this.requestsMenuFilterKeyboardEvent = getKeyWithEvent(
|
||||
this.filterOn.bind(this), true);
|
||||
this.reqeustsMenuClearEvent = this.clear.bind(this);
|
||||
this._onContextShowing = this._onContextShowing.bind(this);
|
||||
this._onContextNewTabCommand = this.openRequestInTab.bind(this);
|
||||
@ -525,8 +528,12 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
||||
|
||||
$("#toolbar-labels").addEventListener("click",
|
||||
this.requestsMenuSortEvent, false);
|
||||
$("#toolbar-labels").addEventListener("keydown",
|
||||
this.requestsMenuSortKeyboardEvent, false);
|
||||
$("#requests-menu-filter-buttons").addEventListener("click",
|
||||
this.requestsMenuFilterEvent, false);
|
||||
$("#requests-menu-filter-buttons").addEventListener("keydown",
|
||||
this.requestsMenuFilterKeyboardEvent, false);
|
||||
$("#requests-menu-clear-button").addEventListener("click",
|
||||
this.reqeustsMenuClearEvent, false);
|
||||
$("#network-request-popup").addEventListener("popupshowing",
|
||||
@ -605,8 +612,12 @@ RequestsMenuView.prototype = Heritage.extend(WidgetMethods, {
|
||||
|
||||
$("#toolbar-labels").removeEventListener("click",
|
||||
this.requestsMenuSortEvent, false);
|
||||
$("#toolbar-labels").removeEventListener("keydown",
|
||||
this.requestsMenuSortKeyboardEvent, false);
|
||||
$("#requests-menu-filter-buttons").removeEventListener("click",
|
||||
this.requestsMenuFilterEvent, false);
|
||||
$("#requests-menu-filter-buttons").removeEventListener("keydown",
|
||||
this.requestsMenuFilterKeyboardEvent, false);
|
||||
$("#requests-menu-clear-button").removeEventListener("click",
|
||||
this.reqeustsMenuClearEvent, false);
|
||||
this.freetextFilterBox.removeEventListener("input",
|
||||
@ -4017,13 +4028,19 @@ function responseIsFresh({ responseHeaders, status }) {
|
||||
* @param function callback
|
||||
* Function to execute execute when data-key
|
||||
* is present in event.target.
|
||||
* @param bool onlySpaceOrReturn
|
||||
* Flag to indicate if callback should only be called
|
||||
when the space or return button is pressed
|
||||
* @return function
|
||||
* Wrapped function with the target data-key as the first argument.
|
||||
* Wrapped function with the target data-key as the first argument
|
||||
* and the event as the second argument.
|
||||
*/
|
||||
function getKeyWithEvent(callback) {
|
||||
function getKeyWithEvent(callback, onlySpaceOrReturn) {
|
||||
return function (event) {
|
||||
let key = event.target.getAttribute("data-key");
|
||||
if (key) {
|
||||
let filterKeyboardEvent = onlySpaceOrReturn
|
||||
? ViewHelpers.isSpaceOrReturn(event) : true;
|
||||
if (key && filterKeyboardEvent) {
|
||||
callback.call(null, key);
|
||||
}
|
||||
};
|
||||
|
@ -15,6 +15,7 @@ support-files =
|
||||
[test_reps_grip-array.html]
|
||||
[test_reps_null.html]
|
||||
[test_reps_number.html]
|
||||
[test_reps_object.html]
|
||||
[test_reps_object-with-text.html]
|
||||
[test_reps_object-with-url.html]
|
||||
[test_reps_string.html]
|
||||
|
@ -0,0 +1,190 @@
|
||||
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
Test Obj rep
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Rep test - Obj</title>
|
||||
<script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css">
|
||||
</head>
|
||||
<body>
|
||||
<pre id="test">
|
||||
<script src="head.js" type="application/javascript;version=1.8"></script>
|
||||
<script type="application/javascript;version=1.8">
|
||||
window.onload = Task.async(function* () {
|
||||
let { Rep } = browserRequire("devtools/client/shared/components/reps/rep");
|
||||
let { Obj } = browserRequire("devtools/client/shared/components/reps/object");
|
||||
|
||||
const componentUnderTest = Obj;
|
||||
|
||||
try {
|
||||
yield testBasic();
|
||||
|
||||
// Test property iterator
|
||||
yield testMaxProps();
|
||||
yield testMoreThanMaxProps();
|
||||
yield testUninterestingProps();
|
||||
|
||||
// Test that properties are rendered as expected by PropRep
|
||||
yield testNested();
|
||||
} catch(e) {
|
||||
ok(false, "Got an error: " + DevToolsUtils.safeErrorString(e));
|
||||
} finally {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function testBasic() {
|
||||
const stub = {};
|
||||
|
||||
// Test that correct rep is chosen
|
||||
const renderedRep = shallowRenderComponent(Rep, { object: stub });
|
||||
is(renderedRep.type, Obj.rep, `Rep correctly selects ${Obj.rep.displayName}`);
|
||||
|
||||
// Test rendering
|
||||
const defaultOutput = `Object`;
|
||||
|
||||
const modeTests = [
|
||||
{
|
||||
mode: undefined,
|
||||
expectedOutput: defaultOutput,
|
||||
},
|
||||
{
|
||||
mode: "tiny",
|
||||
expectedOutput: defaultOutput,
|
||||
},
|
||||
{
|
||||
mode: "short",
|
||||
expectedOutput: defaultOutput,
|
||||
},
|
||||
{
|
||||
mode: "long",
|
||||
expectedOutput: defaultOutput,
|
||||
}
|
||||
];
|
||||
|
||||
testRepRenderModes(modeTests, "testBasic", componentUnderTest, stub);
|
||||
}
|
||||
|
||||
function testMaxProps() {
|
||||
const testName = "testMaxProps";
|
||||
|
||||
const stub = {a: "a", b: "b", c: "c"};
|
||||
const defaultOutput = `Object{a: "a", b: "b", c: "c"}`;
|
||||
|
||||
const modeTests = [
|
||||
{
|
||||
mode: undefined,
|
||||
expectedOutput: defaultOutput,
|
||||
},
|
||||
{
|
||||
mode: "tiny",
|
||||
expectedOutput: `Object`,
|
||||
},
|
||||
{
|
||||
mode: "short",
|
||||
expectedOutput: defaultOutput,
|
||||
},
|
||||
{
|
||||
mode: "long",
|
||||
expectedOutput: defaultOutput,
|
||||
}
|
||||
];
|
||||
|
||||
testRepRenderModes(modeTests, "testMaxProps", componentUnderTest, stub);
|
||||
}
|
||||
|
||||
function testMoreThanMaxProps() {
|
||||
let stub = {};
|
||||
for (let i = 0; i<100; i++) {
|
||||
stub[`p${i}`] = i
|
||||
}
|
||||
const defaultOutput = `Object{p0: 0, p1: 1, p2: 2, more...}`;
|
||||
|
||||
const modeTests = [
|
||||
{
|
||||
mode: undefined,
|
||||
expectedOutput: defaultOutput,
|
||||
},
|
||||
{
|
||||
mode: "tiny",
|
||||
expectedOutput: `Object`,
|
||||
},
|
||||
{
|
||||
mode: "short",
|
||||
expectedOutput: defaultOutput,
|
||||
},
|
||||
{
|
||||
mode: "long",
|
||||
expectedOutput: defaultOutput,
|
||||
}
|
||||
];
|
||||
|
||||
testRepRenderModes(modeTests, "testMoreThanMaxProps", componentUnderTest, stub);
|
||||
}
|
||||
|
||||
function testUninterestingProps() {
|
||||
const stub = {a:undefined, b:undefined, c:"c", d:0};
|
||||
const defaultOutput = `Object{c: "c", d: 0, a: undefined, more...}`;
|
||||
|
||||
const modeTests = [
|
||||
{
|
||||
mode: undefined,
|
||||
expectedOutput: defaultOutput,
|
||||
},
|
||||
{
|
||||
mode: "tiny",
|
||||
expectedOutput: `Object`,
|
||||
},
|
||||
{
|
||||
mode: "short",
|
||||
expectedOutput: defaultOutput,
|
||||
},
|
||||
{
|
||||
mode: "long",
|
||||
expectedOutput: defaultOutput,
|
||||
}
|
||||
];
|
||||
|
||||
testRepRenderModes(modeTests, "testUninterestingProps", componentUnderTest, stub);
|
||||
}
|
||||
|
||||
function testNested() {
|
||||
const stub = {
|
||||
objProp: {
|
||||
id: 1,
|
||||
arr: [2]
|
||||
},
|
||||
strProp: "test string",
|
||||
arrProp: [1]
|
||||
};
|
||||
const defaultOutput = `Object{strProp: "test string", objProp: Object{id: 1, arr: [2]}, arrProp: [1]}`;
|
||||
|
||||
const modeTests = [
|
||||
{
|
||||
mode: undefined,
|
||||
expectedOutput: defaultOutput,
|
||||
},
|
||||
{
|
||||
mode: "tiny",
|
||||
expectedOutput: `Object`,
|
||||
},
|
||||
{
|
||||
mode: "short",
|
||||
expectedOutput: defaultOutput,
|
||||
},
|
||||
{
|
||||
mode: "long",
|
||||
expectedOutput: defaultOutput,
|
||||
}
|
||||
];
|
||||
|
||||
testRepRenderModes(modeTests, "testNestedObject", componentUnderTest, stub);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
@ -10,6 +10,7 @@ const defer = require("devtools/shared/defer");
|
||||
const Services = require("Services");
|
||||
const { TargetFactory } = require("devtools/client/framework/target");
|
||||
const Telemetry = require("devtools/client/shared/telemetry");
|
||||
const {ViewHelpers} = require("devtools/client/shared/widgets/view-helpers");
|
||||
|
||||
const NS_XHTML = "http://www.w3.org/1999/xhtml";
|
||||
const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul";
|
||||
@ -109,6 +110,13 @@ var CommandUtils = {
|
||||
requisition.updateExec(typed);
|
||||
}, false);
|
||||
|
||||
button.addEventListener("keypress", (event) => {
|
||||
if (ViewHelpers.isSpaceOrReturn(event)) {
|
||||
event.preventDefault();
|
||||
requisition.updateExec(typed);
|
||||
}
|
||||
}, false);
|
||||
|
||||
// Allow the command button to be toggleable
|
||||
if (command.state) {
|
||||
button.setAttribute("autocheck", false);
|
||||
|
@ -22,15 +22,13 @@ const TEST_URI = `data:text/xml;charset=UTF-8,<?xml version="1.0"?>
|
||||
</vbox>
|
||||
</window>`;
|
||||
|
||||
const CONTAINER_HEIGHT = 200;
|
||||
const CONTAINER_HEIGHT = 300;
|
||||
const CONTAINER_WIDTH = 200;
|
||||
const TOOLTIP_HEIGHT = 50;
|
||||
|
||||
const {HTMLTooltip} = require("devtools/client/shared/widgets/HTMLTooltip");
|
||||
loadHelperScript("helper_html_tooltip.js");
|
||||
|
||||
let useXulWrapper;
|
||||
|
||||
add_task(function* () {
|
||||
// Force the toolbox to be 400px tall => 50px for each box.
|
||||
yield pushPref("devtools.toolbox.footer.height", 400);
|
||||
@ -38,21 +36,11 @@ add_task(function* () {
|
||||
yield addTab("about:blank");
|
||||
let [,, doc] = yield createHost("bottom", TEST_URI);
|
||||
|
||||
info("Run tests for a Tooltip without using a XUL panel");
|
||||
useXulWrapper = false;
|
||||
yield runTests(doc);
|
||||
|
||||
info("Run tests for a Tooltip with a XUL panel");
|
||||
useXulWrapper = true;
|
||||
yield runTests(doc);
|
||||
});
|
||||
|
||||
function* runTests(doc) {
|
||||
let tooltip = new HTMLTooltip({doc}, {useXulWrapper});
|
||||
let tooltip = new HTMLTooltip({doc}, {useXulWrapper: false});
|
||||
info("Set tooltip content 50px tall, but request a container 200px tall");
|
||||
let tooltipContent = doc.createElementNS(HTML_NS, "div");
|
||||
tooltipContent.style.cssText = "height: " + TOOLTIP_HEIGHT + "px; background: red;";
|
||||
tooltip.setContent(tooltipContent, {width: CONTAINER_WIDTH, height: CONTAINER_HEIGHT});
|
||||
tooltip.setContent(tooltipContent, {width: CONTAINER_WIDTH, height: Infinity});
|
||||
|
||||
info("Show the tooltip and check the container and panel height.");
|
||||
yield showTooltip(tooltip, doc.getElementById("box1"));
|
||||
@ -78,11 +66,10 @@ function* runTests(doc) {
|
||||
yield onPanelClick;
|
||||
is(tooltip.isVisible(), true, "Tooltip is still visible");
|
||||
|
||||
info("Click below the tooltip container, the tooltip should be closed.");
|
||||
info("Click above the tooltip container, the tooltip should be closed.");
|
||||
onHidden = once(tooltip, "hidden");
|
||||
EventUtils.synthesizeMouse(tooltip.container, 100, CONTAINER_HEIGHT + 10,
|
||||
{}, doc.defaultView);
|
||||
EventUtils.synthesizeMouse(tooltip.container, 100, -10, {}, doc.defaultView);
|
||||
yield onHidden;
|
||||
|
||||
tooltip.destroy();
|
||||
}
|
||||
});
|
||||
|
@ -211,7 +211,7 @@ function HTMLTooltip(toolbox, {
|
||||
this.type = type;
|
||||
this.autofocus = autofocus;
|
||||
this.consumeOutsideClicks = consumeOutsideClicks;
|
||||
this.useXulWrapper = useXulWrapper;
|
||||
this.useXulWrapper = this._isXUL() && useXulWrapper;
|
||||
|
||||
this._position = null;
|
||||
|
||||
@ -229,7 +229,7 @@ function HTMLTooltip(toolbox, {
|
||||
if (stylesheet) {
|
||||
this._applyStylesheet(stylesheet);
|
||||
}
|
||||
if (this._isXUL() && this.useXulWrapper) {
|
||||
if (this.useXulWrapper) {
|
||||
// When using a XUL panel as the wrapper, the actual markup for the tooltip is as
|
||||
// follows :
|
||||
// <panel> <!-- XUL panel used to position the tooltip anywhere on screen -->
|
||||
@ -285,9 +285,8 @@ HTMLTooltip.prototype = {
|
||||
* - {Number} width: preferred width for the tooltip container. If not specified
|
||||
* the tooltip container will be measured before being displayed, and the
|
||||
* measured width will be used as preferred width.
|
||||
* - {Number} height: optional, preferred height for the tooltip container. This
|
||||
* parameter acts as a max-height for the tooltip content. If not specified,
|
||||
* the tooltip will be able to use all the height available.
|
||||
* - {Number} height: optional, preferred height for the tooltip container. If
|
||||
* not specified, the tooltip will be able to use all the height available.
|
||||
*/
|
||||
setContent: function (content, {width = "auto", height = Infinity} = {}) {
|
||||
this.preferredWidth = width;
|
||||
@ -332,6 +331,12 @@ HTMLTooltip.prototype = {
|
||||
let isTop = computedPosition === POSITION.TOP;
|
||||
this.container.classList.toggle("tooltip-top", isTop);
|
||||
this.container.classList.toggle("tooltip-bottom", !isTop);
|
||||
|
||||
// If the preferred height is set to Infinity, the tooltip container should grow based
|
||||
// on its content's height and use as much height as possible.
|
||||
this.container.classList.toggle("tooltip-flexible-height",
|
||||
this.preferredHeight === Infinity);
|
||||
|
||||
this.container.style.height = height + "px";
|
||||
|
||||
let preferredWidth;
|
||||
@ -550,6 +555,9 @@ HTMLTooltip.prototype = {
|
||||
panel.setAttribute("noautofocus", true);
|
||||
panel.setAttribute("ignorekeys", true);
|
||||
|
||||
// Use type="arrow" to prevent side effects (see Bug 1285206)
|
||||
panel.setAttribute("type", "arrow");
|
||||
|
||||
panel.setAttribute("level", "float");
|
||||
panel.setAttribute("class", "tooltip-xul-wrapper");
|
||||
|
||||
|
@ -218,6 +218,17 @@ const ViewHelpers = exports.ViewHelpers = {
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Check if the enter key or space was pressed
|
||||
*
|
||||
* @param event event
|
||||
* The event triggered by a keypress on an element
|
||||
*/
|
||||
isSpaceOrReturn: function (event) {
|
||||
return event.keyCode === event.DOM_VK_SPACE ||
|
||||
event.keyCode === event.DOM_VK_RETURN;
|
||||
},
|
||||
|
||||
/**
|
||||
* Sets a toggled pane hidden or visible. The pane can either be displayed on
|
||||
* the side (right or left depending on the locale) or at the bottom.
|
||||
|
@ -79,9 +79,10 @@
|
||||
}
|
||||
|
||||
/* Add element toolbar button */
|
||||
|
||||
#inspector-element-add-button::before {
|
||||
background-image: url("chrome://devtools/skin/images/add.svg");
|
||||
list-style-image: url("chrome://devtools/skin/images/add.svg");
|
||||
-moz-user-focus: normal;
|
||||
}
|
||||
|
||||
/* "no results" warning message displayed in the ruleview and in the computed view */
|
||||
|
@ -131,6 +131,7 @@
|
||||
.tooltip-panel{
|
||||
background-color: var(--theme-tooltip-background);
|
||||
pointer-events: all;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.tooltip-visible {
|
||||
@ -142,6 +143,35 @@
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
/* Tooltip : flexible height styles */
|
||||
|
||||
.tooltip-flexible-height .tooltip-panel {
|
||||
/* In flexible mode the tooltip panel should only grow according to its content. */
|
||||
flex-grow: 0;
|
||||
}
|
||||
|
||||
.tooltip-flexible-height .tooltip-filler {
|
||||
/* In flexible mode the filler should grow as much as possible. */
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
/* type="arrow" overrides: remove arrow decorations for the xul <panel> wrapper */
|
||||
|
||||
.tooltip-xul-wrapper[type="arrow"] {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
/* The arrow image is hidden because the panel is opened using openPopupAtScreen(). */
|
||||
|
||||
/* Remove all decorations on .panel-arrowcontent is the tooltip content container. */
|
||||
.tooltip-xul-wrapper[type="arrow"] .panel-arrowcontent {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background: transparent;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
/* Tooltip : arrow style */
|
||||
|
||||
.tooltip-xul-wrapper .tooltip-container {
|
||||
@ -151,7 +181,6 @@
|
||||
|
||||
.tooltip-container[type="arrow"] > .tooltip-panel {
|
||||
position: relative;
|
||||
flex-grow: 0;
|
||||
min-height: 10px;
|
||||
box-sizing: border-box;
|
||||
width: 100%;
|
||||
@ -180,10 +209,6 @@
|
||||
align-self: flex-end;
|
||||
}
|
||||
|
||||
.tooltip-filler {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.tooltip-top .tooltip-arrow {
|
||||
margin-top: -3px;
|
||||
}
|
||||
|
@ -21,6 +21,8 @@
|
||||
return Cu.import("resource://gre/modules/Promise.jsm", {}).Promise.defer;
|
||||
case "Services":
|
||||
return Cu.import("resource://gre/modules/Services.jsm", {}).Services;
|
||||
case "resource://gre/modules/Console.jsm":
|
||||
return Cu.import("resource://gre/modules/Console.jsm", {});
|
||||
case "chrome":
|
||||
return {
|
||||
Cu,
|
||||
@ -42,13 +44,18 @@
|
||||
const defer = require("devtools/shared/defer");
|
||||
let loggingEnabled = true;
|
||||
|
||||
let console = {};
|
||||
if (!isWorker) {
|
||||
console = require("resource://gre/modules/Console.jsm").console;
|
||||
loggingEnabled = Services.prefs.getBoolPref("devtools.dump.emit");
|
||||
Services.prefs.addObserver("devtools.dump.emit", {
|
||||
observe: () => {
|
||||
loggingEnabled = Services.prefs.getBoolPref("devtools.dump.emit");
|
||||
}
|
||||
}, false);
|
||||
} else {
|
||||
// Workers can't load JSMs, so we can't import Console.jsm here.
|
||||
console.error = () => {};
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -74,10 +74,25 @@
|
||||
}
|
||||
|
||||
function onlyOnce() {
|
||||
ok(!beenHere2, "\"once\" listner has been called once");
|
||||
ok(!beenHere2, "\"once\" listener has been called once");
|
||||
beenHere2 = true;
|
||||
emitter.emit("onlyonce");
|
||||
|
||||
testThrowingExceptionInListener();
|
||||
}
|
||||
|
||||
function testThrowingExceptionInListener() {
|
||||
function throwListener() {
|
||||
emitter.off("throw-exception");
|
||||
throw {
|
||||
toString: () => "foo",
|
||||
stack: "bar",
|
||||
};
|
||||
}
|
||||
|
||||
emitter.on("throw-exception", throwListener);
|
||||
emitter.emit("throw-exception");
|
||||
|
||||
killItWhileEmitting();
|
||||
}
|
||||
|
||||
|
@ -429,8 +429,6 @@ var testcases = [ {
|
||||
protocolChange: true,
|
||||
}, {
|
||||
input: "?'.com",
|
||||
fixedURI: "http:///?%27.com",
|
||||
alternateURI: "http://www..com/?%27.com",
|
||||
keywordLookup: true,
|
||||
protocolChange: true,
|
||||
}, {
|
||||
@ -439,14 +437,10 @@ var testcases = [ {
|
||||
protocolChange: true
|
||||
}, {
|
||||
input: "?mozilla",
|
||||
fixedURI: "http:///?mozilla",
|
||||
alternateURI: "http://www..com/?mozilla",
|
||||
keywordLookup: true,
|
||||
protocolChange: true,
|
||||
}, {
|
||||
input: "??mozilla",
|
||||
fixedURI: "http:///??mozilla",
|
||||
alternateURI: "http://www..com/??mozilla",
|
||||
keywordLookup: true,
|
||||
protocolChange: true,
|
||||
}, {
|
||||
|
@ -776,7 +776,11 @@ BlobImplBase::GetSendInfo(nsIInputStream** aBody, uint64_t* aContentLength,
|
||||
nsAutoString contentType;
|
||||
GetType(contentType);
|
||||
|
||||
CopyUTF16toUTF8(contentType, aContentType);
|
||||
if (contentType.IsEmpty()) {
|
||||
aContentType.SetIsVoid(true);
|
||||
} else {
|
||||
CopyUTF16toUTF8(contentType, aContentType);
|
||||
}
|
||||
|
||||
aCharset.Truncate();
|
||||
|
||||
|
@ -30,6 +30,7 @@
|
||||
#include "mozilla/dom/StructuredCloneTags.h"
|
||||
#include "mozilla/dom/SubtleCryptoBinding.h"
|
||||
#include "mozilla/dom/ToJSValue.h"
|
||||
#include "mozilla/dom/URLSearchParams.h"
|
||||
#include "mozilla/dom/WebCryptoCommon.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/ipc/BackgroundChild.h"
|
||||
@ -395,7 +396,7 @@ StructuredCloneHolder::ReadFullySerializableObjects(JSContext* aCx,
|
||||
return ReadStructuredCloneImageData(aCx, aReader);
|
||||
}
|
||||
|
||||
if (aTag == SCTAG_DOM_WEBCRYPTO_KEY) {
|
||||
if (aTag == SCTAG_DOM_WEBCRYPTO_KEY || aTag == SCTAG_DOM_URLSEARCHPARAMS) {
|
||||
nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
|
||||
if (!global) {
|
||||
return nullptr;
|
||||
@ -404,11 +405,20 @@ StructuredCloneHolder::ReadFullySerializableObjects(JSContext* aCx,
|
||||
// Prevent the return value from being trashed by a GC during ~nsRefPtr.
|
||||
JS::Rooted<JSObject*> result(aCx);
|
||||
{
|
||||
RefPtr<CryptoKey> key = new CryptoKey(global);
|
||||
if (!key->ReadStructuredClone(aReader)) {
|
||||
result = nullptr;
|
||||
} else {
|
||||
result = key->WrapObject(aCx, nullptr);
|
||||
if (aTag == SCTAG_DOM_WEBCRYPTO_KEY) {
|
||||
RefPtr<CryptoKey> key = new CryptoKey(global);
|
||||
if (!key->ReadStructuredClone(aReader)) {
|
||||
result = nullptr;
|
||||
} else {
|
||||
result = key->WrapObject(aCx, nullptr);
|
||||
}
|
||||
} else if (aTag == SCTAG_DOM_URLSEARCHPARAMS) {
|
||||
RefPtr<URLSearchParams> usp = new URLSearchParams(global);
|
||||
if (!usp->ReadStructuredClone(aReader)) {
|
||||
result = nullptr;
|
||||
} else {
|
||||
result = usp->WrapObject(aCx, nullptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
@ -504,6 +514,15 @@ StructuredCloneHolder::WriteFullySerializableObjects(JSContext* aCx,
|
||||
}
|
||||
}
|
||||
|
||||
// Handle URLSearchParams cloning
|
||||
{
|
||||
URLSearchParams* usp = nullptr;
|
||||
if (NS_SUCCEEDED(UNWRAP_OBJECT(URLSearchParams, aObj, usp))) {
|
||||
return JS_WriteUint32Pair(aWriter, SCTAG_DOM_URLSEARCHPARAMS, 0) &&
|
||||
usp->WriteStructuredClone(aWriter);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle Key cloning
|
||||
{
|
||||
CryptoKey* key = nullptr;
|
||||
|
@ -54,6 +54,9 @@ enum StructuredCloneTags {
|
||||
|
||||
SCTAG_DOM_DIRECTORY,
|
||||
|
||||
// This tag is used by both main thread and workers.
|
||||
SCTAG_DOM_URLSEARCHPARAMS,
|
||||
|
||||
SCTAG_DOM_MAX
|
||||
};
|
||||
|
||||
|
@ -223,7 +223,6 @@
|
||||
#include "nsDOMCaretPosition.h"
|
||||
#include "nsIDOMHTMLTextAreaElement.h"
|
||||
#include "nsViewportInfo.h"
|
||||
#include "nsIContentPermissionPrompt.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "nsITextControlElement.h"
|
||||
#include "nsIDOMNSEditableElement.h"
|
||||
@ -241,7 +240,6 @@
|
||||
#include "nsIDocumentActivity.h"
|
||||
#include "nsIStructuredCloneContainer.h"
|
||||
#include "nsIMutableArray.h"
|
||||
#include "nsContentPermissionHelper.h"
|
||||
#include "mozilla/dom/DOMStringList.h"
|
||||
#include "nsWindowMemoryReporter.h"
|
||||
#include "nsLocation.h"
|
||||
@ -11878,27 +11876,11 @@ FullscreenRequest::FullscreenRequest(Element* aElement)
|
||||
, mDocument(static_cast<nsDocument*>(aElement->OwnerDoc()))
|
||||
{
|
||||
MOZ_COUNT_CTOR(FullscreenRequest);
|
||||
mDocument->mPendingFullscreenRequests++;
|
||||
if (MOZ_UNLIKELY(!mDocument->mPendingFullscreenRequests)) {
|
||||
NS_WARNING("Pending fullscreen request counter overflow");
|
||||
}
|
||||
}
|
||||
|
||||
static void RedispatchPendingPointerLockRequest(nsIDocument* aDocument);
|
||||
|
||||
FullscreenRequest::~FullscreenRequest()
|
||||
{
|
||||
MOZ_COUNT_DTOR(FullscreenRequest);
|
||||
if (MOZ_UNLIKELY(!mDocument->mPendingFullscreenRequests)) {
|
||||
NS_WARNING("Pending fullscreen request counter underflow");
|
||||
return;
|
||||
}
|
||||
mDocument->mPendingFullscreenRequests--;
|
||||
if (!mDocument->mPendingFullscreenRequests) {
|
||||
// There may be pointer lock request be blocked because of pending
|
||||
// fullscreen requests. Re-dispatch it to ensure it gets handled.
|
||||
RedispatchPendingPointerLockRequest(mDocument);
|
||||
}
|
||||
}
|
||||
|
||||
// Any fullscreen request waiting for the widget to finish being full-
|
||||
@ -12301,7 +12283,7 @@ DispatchPointerLockChange(nsIDocument* aTarget)
|
||||
}
|
||||
|
||||
static void
|
||||
DispatchPointerLockError(nsIDocument* aTarget)
|
||||
DispatchPointerLockError(nsIDocument* aTarget, const char* aMessage)
|
||||
{
|
||||
if (!aTarget) {
|
||||
return;
|
||||
@ -12313,178 +12295,117 @@ DispatchPointerLockError(nsIDocument* aTarget)
|
||||
true,
|
||||
false);
|
||||
asyncDispatcher->PostDOMEvent();
|
||||
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
|
||||
NS_LITERAL_CSTRING("DOM"), aTarget,
|
||||
nsContentUtils::eDOM_PROPERTIES,
|
||||
aMessage);
|
||||
}
|
||||
|
||||
static const uint8_t kPointerLockRequestLimit = 2;
|
||||
|
||||
class nsPointerLockPermissionRequest;
|
||||
mozilla::StaticRefPtr<nsPointerLockPermissionRequest> gPendingPointerLockRequest;
|
||||
|
||||
class nsPointerLockPermissionRequest : public Runnable,
|
||||
public nsIContentPermissionRequest
|
||||
class PointerLockRequest final : public Runnable
|
||||
{
|
||||
public:
|
||||
nsPointerLockPermissionRequest(Element* aElement, bool aUserInputOrChromeCaller)
|
||||
: mElement(do_GetWeakReference(aElement)),
|
||||
mDocument(do_GetWeakReference(aElement->OwnerDoc())),
|
||||
mUserInputOrChromeCaller(aUserInputOrChromeCaller)
|
||||
{
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
|
||||
if (doc && doc->GetInnerWindow()) {
|
||||
mRequester = new nsContentPermissionRequester(doc->GetInnerWindow());
|
||||
}
|
||||
}
|
||||
PointerLockRequest(Element* aElement, bool aUserInputOrChromeCaller)
|
||||
: mElement(do_GetWeakReference(aElement))
|
||||
, mDocument(do_GetWeakReference(aElement->OwnerDoc()))
|
||||
, mUserInputOrChromeCaller(aUserInputOrChromeCaller)
|
||||
{}
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_NSICONTENTPERMISSIONREQUEST
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
nsCOMPtr<Element> e = do_QueryReferent(mElement);
|
||||
nsCOMPtr<nsIDocument> d = do_QueryReferent(mDocument);
|
||||
if (!e || !d || gPendingPointerLockRequest != this ||
|
||||
e->GetUncomposedDoc() != d) {
|
||||
Handled();
|
||||
DispatchPointerLockError(d);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsDocument* doc = static_cast<nsDocument*>(d.get());
|
||||
if (doc->mPendingFullscreenRequests > 0) {
|
||||
// We're still entering fullscreen.
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (doc->GetFullscreenElement() || doc->mAllowRelocking) {
|
||||
Allow(JS::UndefinedHandleValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// In non-fullscreen mode user input (or chrome caller) is required!
|
||||
// Also, don't let the page to try to get the permission too many times.
|
||||
if (!mUserInputOrChromeCaller ||
|
||||
doc->mCancelledPointerLockRequests > kPointerLockRequestLimit) {
|
||||
Handled();
|
||||
DispatchPointerLockError(d);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
Allow(JS::UndefinedHandleValue);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void Handled()
|
||||
{
|
||||
mElement = nullptr;
|
||||
mDocument = nullptr;
|
||||
if (gPendingPointerLockRequest == this) {
|
||||
gPendingPointerLockRequest = nullptr;
|
||||
}
|
||||
}
|
||||
NS_IMETHOD Run() final;
|
||||
|
||||
private:
|
||||
nsWeakPtr mElement;
|
||||
nsWeakPtr mDocument;
|
||||
bool mUserInputOrChromeCaller;
|
||||
|
||||
protected:
|
||||
virtual ~nsPointerLockPermissionRequest() {}
|
||||
nsCOMPtr<nsIContentPermissionRequester> mRequester;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS_INHERITED(nsPointerLockPermissionRequest,
|
||||
Runnable,
|
||||
nsIContentPermissionRequest)
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPointerLockPermissionRequest::GetTypes(nsIArray** aTypes)
|
||||
static const char*
|
||||
GetPointerLockError(Element* aElement, Element* aCurrentLock,
|
||||
bool aNoFocusCheck = false)
|
||||
{
|
||||
nsTArray<nsString> emptyOptions;
|
||||
return nsContentPermissionUtils::CreatePermissionArray(NS_LITERAL_CSTRING("pointerLock"),
|
||||
NS_LITERAL_CSTRING("unused"),
|
||||
emptyOptions,
|
||||
aTypes);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPointerLockPermissionRequest::GetPrincipal(nsIPrincipal** aPrincipal)
|
||||
{
|
||||
nsCOMPtr<nsIDocument> d = do_QueryReferent(mDocument);
|
||||
if (d) {
|
||||
NS_ADDREF(*aPrincipal = d->NodePrincipal());
|
||||
// Check if pointer lock pref is enabled
|
||||
if (!Preferences::GetBool("full-screen-api.pointer-lock.enabled")) {
|
||||
return "PointerLockDeniedDisabled";
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPointerLockPermissionRequest::GetWindow(mozIDOMWindow** aWindow)
|
||||
{
|
||||
nsCOMPtr<nsIDocument> d = do_QueryReferent(mDocument);
|
||||
if (d) {
|
||||
NS_IF_ADDREF(*aWindow = d->GetInnerWindow());
|
||||
nsCOMPtr<nsIDocument> ownerDoc = aElement->OwnerDoc();
|
||||
if (aCurrentLock && aCurrentLock->OwnerDoc() != ownerDoc) {
|
||||
return "PointerLockDeniedInUse";
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPointerLockPermissionRequest::GetElement(nsIDOMElement** aElement)
|
||||
{
|
||||
// It is enough to implement GetWindow.
|
||||
*aElement = nullptr;
|
||||
return NS_OK;
|
||||
}
|
||||
if (!aElement->IsInUncomposedDoc()) {
|
||||
return "PointerLockDeniedNotInDocument";
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPointerLockPermissionRequest::Cancel()
|
||||
{
|
||||
nsCOMPtr<nsIDocument> d = do_QueryReferent(mDocument);
|
||||
Handled();
|
||||
if (d) {
|
||||
auto doc = static_cast<nsDocument*>(d.get());
|
||||
if (doc->mCancelledPointerLockRequests <= kPointerLockRequestLimit) {
|
||||
doc->mCancelledPointerLockRequests++;
|
||||
if (ownerDoc->GetSandboxFlags() & SANDBOXED_POINTER_LOCK) {
|
||||
return "PointerLockDeniedSandboxed";
|
||||
}
|
||||
|
||||
// Check if the element is in a document with a docshell.
|
||||
if (!ownerDoc->GetContainer()) {
|
||||
return "PointerLockDeniedHidden";
|
||||
}
|
||||
nsCOMPtr<nsPIDOMWindowOuter> ownerWindow = ownerDoc->GetWindow();
|
||||
if (!ownerWindow) {
|
||||
return "PointerLockDeniedHidden";
|
||||
}
|
||||
nsCOMPtr<nsPIDOMWindowInner> ownerInnerWindow = ownerDoc->GetInnerWindow();
|
||||
if (!ownerInnerWindow) {
|
||||
return "PointerLockDeniedHidden";
|
||||
}
|
||||
if (ownerWindow->GetCurrentInnerWindow() != ownerInnerWindow) {
|
||||
return "PointerLockDeniedHidden";
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowOuter> top = ownerWindow->GetScriptableTop();
|
||||
if (!top || !top->GetExtantDoc() || top->GetExtantDoc()->Hidden()) {
|
||||
return "PointerLockDeniedHidden";
|
||||
}
|
||||
|
||||
if (!aNoFocusCheck) {
|
||||
mozilla::ErrorResult rv;
|
||||
if (!top->GetExtantDoc()->HasFocus(rv)) {
|
||||
return "PointerLockDeniedNotFocused";
|
||||
}
|
||||
DispatchPointerLockError(d);
|
||||
}
|
||||
return NS_OK;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPointerLockPermissionRequest::Allow(JS::HandleValue aChoices)
|
||||
PointerLockRequest::Run()
|
||||
{
|
||||
MOZ_ASSERT(aChoices.isUndefined());
|
||||
|
||||
nsCOMPtr<Element> e = do_QueryReferent(mElement);
|
||||
nsCOMPtr<nsIDocument> doc = do_QueryReferent(mDocument);
|
||||
nsDocument* d = static_cast<nsDocument*>(doc.get());
|
||||
if (!e || !d || gPendingPointerLockRequest != this ||
|
||||
e->GetUncomposedDoc() != d) {
|
||||
Handled();
|
||||
DispatchPointerLockError(d);
|
||||
const char* error = nullptr;
|
||||
if (!e || !d || !e->GetUncomposedDoc()) {
|
||||
error = "PointerLockDeniedNotInDocument";
|
||||
} else if (e->GetUncomposedDoc() != d) {
|
||||
error = "PointerLockDeniedMovedDocument";
|
||||
}
|
||||
if (!error) {
|
||||
nsCOMPtr<Element> pointerLockedElement =
|
||||
do_QueryReferent(EventStateManager::sPointerLockedElement);
|
||||
if (e == pointerLockedElement) {
|
||||
DispatchPointerLockChange(d);
|
||||
return NS_OK;
|
||||
}
|
||||
// Note, we must bypass focus change, so pass true as the last parameter!
|
||||
error = GetPointerLockError(e, pointerLockedElement, true);
|
||||
}
|
||||
// If it is neither user input initiated, nor requested in fullscreen,
|
||||
// it should be rejected.
|
||||
if (!error && !mUserInputOrChromeCaller && !doc->GetFullscreenElement()) {
|
||||
error = "PointerLockDeniedNotInputDriven";
|
||||
}
|
||||
if (!error && !d->SetPointerLock(e, NS_STYLE_CURSOR_NONE)) {
|
||||
error = "PointerLockDeniedFailedToLock";
|
||||
}
|
||||
if (error) {
|
||||
DispatchPointerLockError(d, error);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Mark handled here so that we don't need to call it everywhere below.
|
||||
Handled();
|
||||
|
||||
nsCOMPtr<Element> pointerLockedElement =
|
||||
do_QueryReferent(EventStateManager::sPointerLockedElement);
|
||||
if (e == pointerLockedElement) {
|
||||
DispatchPointerLockChange(d);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// Note, we must bypass focus change, so pass true as the last parameter!
|
||||
if (!d->ShouldLockPointer(e, pointerLockedElement, true)) {
|
||||
DispatchPointerLockError(d);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!d->SetPointerLock(e, NS_STYLE_CURSOR_NONE)) {
|
||||
DispatchPointerLockError(d);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
d->mCancelledPointerLockRequests = 0;
|
||||
e->SetPointerLock();
|
||||
EventStateManager::sPointerLockedElement = do_GetWeakReference(e);
|
||||
EventStateManager::sPointerLockedDoc = do_GetWeakReference(doc);
|
||||
@ -12500,43 +12421,148 @@ nsPointerLockPermissionRequest::Allow(JS::HandleValue aChoices)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsPointerLockPermissionRequest::GetRequester(nsIContentPermissionRequester** aRequester)
|
||||
void
|
||||
nsDocument::RequestPointerLock(Element* aElement)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aRequester);
|
||||
NS_ASSERTION(aElement,
|
||||
"Must pass non-null element to nsDocument::RequestPointerLock");
|
||||
|
||||
nsCOMPtr<nsIContentPermissionRequester> requester = mRequester;
|
||||
requester.forget(aRequester);
|
||||
nsCOMPtr<Element> pointerLockedElement =
|
||||
do_QueryReferent(EventStateManager::sPointerLockedElement);
|
||||
if (aElement == pointerLockedElement) {
|
||||
DispatchPointerLockChange(this);
|
||||
return;
|
||||
}
|
||||
|
||||
if (const char* msg = GetPointerLockError(aElement, pointerLockedElement)) {
|
||||
DispatchPointerLockError(this, msg);
|
||||
return;
|
||||
}
|
||||
|
||||
bool userInputOrChromeCaller = EventStateManager::IsHandlingUserInput() ||
|
||||
nsContentUtils::IsCallerChrome();
|
||||
NS_DispatchToMainThread(new PointerLockRequest(aElement,
|
||||
userInputOrChromeCaller));
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocument::SetPointerLock(Element* aElement, int aCursorStyle)
|
||||
{
|
||||
MOZ_ASSERT(!aElement || aElement->OwnerDoc() == this,
|
||||
"We should be either unlocking pointer (aElement is nullptr), "
|
||||
"or locking pointer to an element in this document");
|
||||
#ifdef DEBUG
|
||||
if (!aElement) {
|
||||
nsCOMPtr<nsIDocument> pointerLockedDoc =
|
||||
do_QueryReferent(EventStateManager::sPointerLockedDoc);
|
||||
MOZ_ASSERT(pointerLockedDoc == this);
|
||||
}
|
||||
#endif
|
||||
|
||||
nsIPresShell* shell = GetShell();
|
||||
if (!shell) {
|
||||
NS_WARNING("SetPointerLock(): No PresShell");
|
||||
return false;
|
||||
}
|
||||
nsPresContext* presContext = shell->GetPresContext();
|
||||
if (!presContext) {
|
||||
NS_WARNING("SetPointerLock(): Unable to get PresContext");
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIWidget> widget;
|
||||
nsIFrame* rootFrame = shell->GetRootFrame();
|
||||
if (!NS_WARN_IF(!rootFrame)) {
|
||||
widget = rootFrame->GetNearestWidget();
|
||||
NS_WARN_IF_FALSE(widget, "SetPointerLock(): Unable to find widget "
|
||||
"in shell->GetRootFrame()->GetNearestWidget();");
|
||||
if (aElement && !widget) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Hide the cursor and set pointer lock for future mouse events
|
||||
RefPtr<EventStateManager> esm = presContext->EventStateManager();
|
||||
esm->SetCursor(aCursorStyle, nullptr, false,
|
||||
0.0f, 0.0f, widget, true);
|
||||
esm->SetPointerLock(widget, aElement);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::UnlockPointer(nsIDocument* aDoc)
|
||||
{
|
||||
if (!EventStateManager::sIsPointerLocked) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocument> pointerLockedDoc =
|
||||
do_QueryReferent(EventStateManager::sPointerLockedDoc);
|
||||
if (!pointerLockedDoc || (aDoc && aDoc != pointerLockedDoc)) {
|
||||
return;
|
||||
}
|
||||
nsDocument* doc = static_cast<nsDocument*>(pointerLockedDoc.get());
|
||||
if (!doc->SetPointerLock(nullptr, NS_STYLE_CURSOR_AUTO)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<Element> pointerLockedElement =
|
||||
do_QueryReferent(EventStateManager::sPointerLockedElement);
|
||||
if (pointerLockedElement) {
|
||||
pointerLockedElement->ClearPointerLock();
|
||||
}
|
||||
|
||||
EventStateManager::sPointerLockedElement = nullptr;
|
||||
EventStateManager::sPointerLockedDoc = nullptr;
|
||||
|
||||
nsContentUtils::DispatchEventOnlyToChrome(
|
||||
doc, ToSupports(pointerLockedElement),
|
||||
NS_LITERAL_STRING("MozDOMPointerLock:Exited"),
|
||||
/* Bubbles */ true, /* Cancelable */ false, /* DefaultAction */ nullptr);
|
||||
|
||||
DispatchPointerLockChange(pointerLockedDoc);
|
||||
}
|
||||
|
||||
void
|
||||
nsIDocument::UnlockPointer(nsIDocument* aDoc)
|
||||
{
|
||||
nsDocument::UnlockPointer(aDoc);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocument::MozExitPointerLock()
|
||||
{
|
||||
nsIDocument::MozExitPointerLock();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
RedispatchPendingPointerLockRequest(nsIDocument* aDocument)
|
||||
NS_IMETHODIMP
|
||||
nsDocument::GetMozPointerLockElement(nsIDOMElement** aPointerLockedElement)
|
||||
{
|
||||
if (!gPendingPointerLockRequest) {
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<nsIDocument> doc =
|
||||
do_QueryReferent(gPendingPointerLockRequest->mDocument);
|
||||
if (doc != aDocument) {
|
||||
return;
|
||||
}
|
||||
nsCOMPtr<Element> elem =
|
||||
do_QueryReferent(gPendingPointerLockRequest->mElement);
|
||||
if (!elem || elem->GetUncomposedDoc() != aDocument) {
|
||||
gPendingPointerLockRequest->Handled();
|
||||
return;
|
||||
Element* el = nsIDocument::GetMozPointerLockElement();
|
||||
nsCOMPtr<nsIDOMElement> retval = do_QueryInterface(el);
|
||||
retval.forget(aPointerLockedElement);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
Element*
|
||||
nsIDocument::GetMozPointerLockElement()
|
||||
{
|
||||
nsCOMPtr<Element> pointerLockedElement =
|
||||
do_QueryReferent(EventStateManager::sPointerLockedElement);
|
||||
if (!pointerLockedElement) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// We have a request pending on the document which may previously be
|
||||
// blocked for fullscreen change. Create a clone and re-dispatch it
|
||||
// to guarantee that Run() method gets called again.
|
||||
bool userInputOrChromeCaller =
|
||||
gPendingPointerLockRequest->mUserInputOrChromeCaller;
|
||||
gPendingPointerLockRequest->Handled();
|
||||
gPendingPointerLockRequest =
|
||||
new nsPointerLockPermissionRequest(elem, userInputOrChromeCaller);
|
||||
NS_DispatchToMainThread(gPendingPointerLockRequest);
|
||||
// Make sure pointer locked element is in the same document.
|
||||
nsCOMPtr<nsIDocument> pointerLockedDoc =
|
||||
do_QueryReferent(EventStateManager::sPointerLockedDoc);
|
||||
if (pointerLockedDoc != this) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return pointerLockedElement;
|
||||
}
|
||||
|
||||
nsresult
|
||||
@ -12612,218 +12638,9 @@ nsDocument::OnAppThemeChanged()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::RequestPointerLock(Element* aElement)
|
||||
{
|
||||
NS_ASSERTION(aElement,
|
||||
"Must pass non-null element to nsDocument::RequestPointerLock");
|
||||
|
||||
nsCOMPtr<Element> pointerLockedElement =
|
||||
do_QueryReferent(EventStateManager::sPointerLockedElement);
|
||||
if (aElement == pointerLockedElement) {
|
||||
DispatchPointerLockChange(this);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!ShouldLockPointer(aElement, pointerLockedElement)) {
|
||||
DispatchPointerLockError(this);
|
||||
return;
|
||||
}
|
||||
|
||||
bool userInputOrChromeCaller = EventStateManager::IsHandlingUserInput() ||
|
||||
nsContentUtils::IsCallerChrome();
|
||||
|
||||
gPendingPointerLockRequest =
|
||||
new nsPointerLockPermissionRequest(aElement, userInputOrChromeCaller);
|
||||
nsCOMPtr<nsIRunnable> r = gPendingPointerLockRequest.get();
|
||||
NS_DispatchToMainThread(r);
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocument::ShouldLockPointer(Element* aElement, Element* aCurrentLock,
|
||||
bool aNoFocusCheck)
|
||||
{
|
||||
// Check if pointer lock pref is enabled
|
||||
if (!Preferences::GetBool("full-screen-api.pointer-lock.enabled")) {
|
||||
NS_WARNING("ShouldLockPointer(): Pointer Lock pref not enabled");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aCurrentLock && aCurrentLock->OwnerDoc() != aElement->OwnerDoc()) {
|
||||
NS_WARNING("ShouldLockPointer(): Existing pointer lock element in a different document");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!aElement->IsInUncomposedDoc()) {
|
||||
NS_WARNING("ShouldLockPointer(): Element without Document");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mSandboxFlags & SANDBOXED_POINTER_LOCK) {
|
||||
NS_WARNING("ShouldLockPointer(): Document is sandboxed and doesn't allow pointer-lock");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the element is in a document with a docshell.
|
||||
nsCOMPtr<nsIDocument> ownerDoc = aElement->OwnerDoc();
|
||||
if (!ownerDoc->GetContainer()) {
|
||||
return false;
|
||||
}
|
||||
nsCOMPtr<nsPIDOMWindowOuter> ownerWindow = ownerDoc->GetWindow();
|
||||
if (!ownerWindow) {
|
||||
return false;
|
||||
}
|
||||
nsCOMPtr<nsPIDOMWindowInner> ownerInnerWindow = ownerDoc->GetInnerWindow();
|
||||
if (!ownerInnerWindow) {
|
||||
return false;
|
||||
}
|
||||
if (ownerWindow->GetCurrentInnerWindow() != ownerInnerWindow) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsPIDOMWindowOuter> top = ownerWindow->GetScriptableTop();
|
||||
if (!top || !top->GetExtantDoc() || top->GetExtantDoc()->Hidden()) {
|
||||
NS_WARNING("ShouldLockPointer(): Top document isn't visible.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!aNoFocusCheck) {
|
||||
mozilla::ErrorResult rv;
|
||||
if (!top->GetExtantDoc()->HasFocus(rv)) {
|
||||
NS_WARNING("ShouldLockPointer(): Top document isn't focused.");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
nsDocument::SetPointerLock(Element* aElement, int aCursorStyle)
|
||||
{
|
||||
MOZ_ASSERT(!aElement || aElement->OwnerDoc() == this,
|
||||
"We should be either unlocking pointer (aElement is nullptr), "
|
||||
"or locking pointer to an element in this document");
|
||||
#ifdef DEBUG
|
||||
if (!aElement) {
|
||||
nsCOMPtr<nsIDocument> pointerLockedDoc =
|
||||
do_QueryReferent(EventStateManager::sPointerLockedDoc);
|
||||
MOZ_ASSERT(pointerLockedDoc == this);
|
||||
}
|
||||
#endif
|
||||
|
||||
nsIPresShell* shell = GetShell();
|
||||
if (!shell) {
|
||||
NS_WARNING("SetPointerLock(): No PresShell");
|
||||
return false;
|
||||
}
|
||||
nsPresContext* presContext = shell->GetPresContext();
|
||||
if (!presContext) {
|
||||
NS_WARNING("SetPointerLock(): Unable to get PresContext");
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIWidget> widget;
|
||||
nsIFrame* rootFrame = shell->GetRootFrame();
|
||||
if (!NS_WARN_IF(!rootFrame)) {
|
||||
widget = rootFrame->GetNearestWidget();
|
||||
NS_WARN_IF_FALSE(widget, "SetPointerLock(): Unable to find widget "
|
||||
"in shell->GetRootFrame()->GetNearestWidget();");
|
||||
if (aElement && !widget) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Hide the cursor and set pointer lock for future mouse events
|
||||
RefPtr<EventStateManager> esm = presContext->EventStateManager();
|
||||
esm->SetCursor(aCursorStyle, nullptr, false,
|
||||
0.0f, 0.0f, widget, true);
|
||||
esm->SetPointerLock(widget, aElement);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::UnlockPointer(nsIDocument* aDoc)
|
||||
{
|
||||
if (!EventStateManager::sIsPointerLocked) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocument> pointerLockedDoc =
|
||||
do_QueryReferent(EventStateManager::sPointerLockedDoc);
|
||||
if (!pointerLockedDoc || (aDoc && aDoc != pointerLockedDoc)) {
|
||||
return;
|
||||
}
|
||||
nsDocument* doc = static_cast<nsDocument*>(pointerLockedDoc.get());
|
||||
if (!doc->SetPointerLock(nullptr, NS_STYLE_CURSOR_AUTO)) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<Element> pointerLockedElement =
|
||||
do_QueryReferent(EventStateManager::sPointerLockedElement);
|
||||
if (pointerLockedElement) {
|
||||
pointerLockedElement->ClearPointerLock();
|
||||
}
|
||||
|
||||
EventStateManager::sPointerLockedElement = nullptr;
|
||||
EventStateManager::sPointerLockedDoc = nullptr;
|
||||
static_cast<nsDocument*>(pointerLockedDoc.get())->mAllowRelocking = !!aDoc;
|
||||
gPendingPointerLockRequest = nullptr;
|
||||
|
||||
nsContentUtils::DispatchEventOnlyToChrome(
|
||||
doc, ToSupports(pointerLockedElement),
|
||||
NS_LITERAL_STRING("MozDOMPointerLock:Exited"),
|
||||
/* Bubbles */ true, /* Cancelable */ false, /* DefaultAction */ nullptr);
|
||||
|
||||
DispatchPointerLockChange(pointerLockedDoc);
|
||||
}
|
||||
|
||||
void
|
||||
nsIDocument::UnlockPointer(nsIDocument* aDoc)
|
||||
{
|
||||
nsDocument::UnlockPointer(aDoc);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocument::MozExitPointerLock()
|
||||
{
|
||||
nsIDocument::MozExitPointerLock();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsDocument::GetMozPointerLockElement(nsIDOMElement** aPointerLockedElement)
|
||||
{
|
||||
Element* el = nsIDocument::GetMozPointerLockElement();
|
||||
nsCOMPtr<nsIDOMElement> retval = do_QueryInterface(el);
|
||||
retval.forget(aPointerLockedElement);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
Element*
|
||||
nsIDocument::GetMozPointerLockElement()
|
||||
{
|
||||
nsCOMPtr<Element> pointerLockedElement =
|
||||
do_QueryReferent(EventStateManager::sPointerLockedElement);
|
||||
if (!pointerLockedElement) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
// Make sure pointer locked element is in the same document.
|
||||
nsCOMPtr<nsIDocument> pointerLockedDoc =
|
||||
do_QueryReferent(EventStateManager::sPointerLockedDoc);
|
||||
if (pointerLockedDoc != this) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return pointerLockedElement;
|
||||
}
|
||||
|
||||
void
|
||||
nsDocument::XPCOMShutdown()
|
||||
{
|
||||
gPendingPointerLockRequest = nullptr;
|
||||
sProcessingStack.reset();
|
||||
}
|
||||
|
||||
|
@ -1268,8 +1268,6 @@ public:
|
||||
Element* GetFullscreenElement() override;
|
||||
|
||||
void RequestPointerLock(Element* aElement) override;
|
||||
bool ShouldLockPointer(Element* aElement, Element* aCurrentLock,
|
||||
bool aNoFocusCheck = false);
|
||||
bool SetPointerLock(Element* aElement, int aCursorStyle);
|
||||
static void UnlockPointer(nsIDocument* aDoc = nullptr);
|
||||
|
||||
@ -1651,11 +1649,7 @@ public:
|
||||
// terminated instead of letting it finish at its own pace.
|
||||
bool mParserAborted:1;
|
||||
|
||||
friend class nsPointerLockPermissionRequest;
|
||||
friend class nsCallRequestFullScreen;
|
||||
// When set, trying to lock the pointer doesn't require permission from the
|
||||
// user.
|
||||
bool mAllowRelocking:1;
|
||||
|
||||
// ScreenOrientation "pending promise" as described by
|
||||
// http://www.w3.org/TR/screen-orientation/
|
||||
@ -1674,10 +1668,6 @@ public:
|
||||
// 'style-sheet-applicable-state-changed' notification.
|
||||
bool mSSApplicableStateNotificationPending:1;
|
||||
|
||||
// The number of pointer lock requests which are cancelled by the user.
|
||||
// The value is saturated to kPointerLockRequestLimit+1 = 3.
|
||||
uint8_t mCancelledPointerLockRequests:2;
|
||||
|
||||
// Whether we have reported use counters for this document with Telemetry yet.
|
||||
// Normally this is only done at document destruction time, but for image
|
||||
// documents (SVG documents) that are not guaranteed to be destroyed, we
|
||||
|
@ -131,6 +131,13 @@ IsJavaMIME(const nsACString & aMIMEType)
|
||||
nsPluginHost::GetSpecialType(aMIMEType) == nsPluginHost::eSpecialType_Java;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsFlashMIME(const nsACString & aMIMEType)
|
||||
{
|
||||
return
|
||||
nsPluginHost::GetSpecialType(aMIMEType) == nsPluginHost::eSpecialType_Flash;
|
||||
}
|
||||
|
||||
static bool
|
||||
InActiveDocument(nsIContent *aContent)
|
||||
{
|
||||
@ -465,11 +472,10 @@ private:
|
||||
///
|
||||
|
||||
static bool
|
||||
IsSuccessfulRequest(nsIRequest* aRequest)
|
||||
IsSuccessfulRequest(nsIRequest* aRequest, nsresult* aStatus)
|
||||
{
|
||||
nsresult status;
|
||||
nsresult rv = aRequest->GetStatus(&status);
|
||||
if (NS_FAILED(rv) || NS_FAILED(status)) {
|
||||
nsresult rv = aRequest->GetStatus(aStatus);
|
||||
if (NS_FAILED(rv) || NS_FAILED(*aStatus)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -719,6 +725,7 @@ nsObjectLoadingContent::nsObjectLoadingContent()
|
||||
, mInstantiating(false)
|
||||
, mNetworkCreated(true)
|
||||
, mActivated(false)
|
||||
, mContentBlockingDisabled(false)
|
||||
, mIsStopping(false)
|
||||
, mIsLoading(false)
|
||||
, mScriptRequested(false)
|
||||
@ -1123,13 +1130,31 @@ nsObjectLoadingContent::OnStartRequest(nsIRequest *aRequest,
|
||||
nsCOMPtr<nsIChannel> chan(do_QueryInterface(aRequest));
|
||||
NS_ASSERTION(chan, "Why is our request not a channel?");
|
||||
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
nsresult status;
|
||||
bool success = IsSuccessfulRequest(aRequest, &status);
|
||||
|
||||
if (IsSuccessfulRequest(aRequest)) {
|
||||
chan->GetURI(getter_AddRefs(uri));
|
||||
if (status == NS_ERROR_BLOCKED_URI) {
|
||||
nsCOMPtr<nsIConsoleService> console(
|
||||
do_GetService("@mozilla.org/consoleservice;1"));
|
||||
if (console) {
|
||||
nsCOMPtr<nsIURI> uri;
|
||||
chan->GetURI(getter_AddRefs(uri));
|
||||
nsAutoCString spec;
|
||||
uri->GetSpec(spec);
|
||||
nsString message = NS_LITERAL_STRING("Blocking ") +
|
||||
NS_ConvertASCIItoUTF16(spec.get()) +
|
||||
NS_LITERAL_STRING(" since it was found on an internal Firefox blocklist.");
|
||||
console->LogStringMessage(message.get());
|
||||
}
|
||||
Telemetry::Accumulate(Telemetry::PLUGIN_BLOCKED_FOR_STABILITY, 1);
|
||||
return NS_ERROR_FAILURE;
|
||||
} else if (status == NS_ERROR_TRACKING_URI) {
|
||||
return NS_ERROR_FAILURE;
|
||||
} else {
|
||||
mContentBlockingDisabled = true;
|
||||
}
|
||||
|
||||
if (!uri) {
|
||||
if (!success) {
|
||||
LOG(("OBJLC [%p]: OnStartRequest: Request failed\n", this));
|
||||
// If the request fails, we still call LoadObject() to handle fallback
|
||||
// content and notifying of failure. (mChannelLoaded && !mChannel) indicates
|
||||
@ -2280,32 +2305,6 @@ nsObjectLoadingContent::LoadObject(bool aNotify,
|
||||
allowLoad = CheckProcessPolicy(&contentPolicy);
|
||||
}
|
||||
|
||||
// This needs to be reverted once the plugin stability experiment is over (see bug #1268120).
|
||||
if (allowLoad && Preferences::GetBool(kPrefBlockURIs)) {
|
||||
RefPtr<nsChannelClassifier> channelClassifier = new nsChannelClassifier();
|
||||
nsCOMPtr<nsIURIClassifier> classifier = do_GetService(NS_URICLASSIFIERSERVICE_CONTRACTID);
|
||||
if (classifier) {
|
||||
nsAutoCString tables;
|
||||
Preferences::GetCString("urlclassifier.blockedTable", &tables);
|
||||
nsAutoCString results;
|
||||
rv = classifier->ClassifyLocalWithTables(mURI, tables, results);
|
||||
if (NS_SUCCEEDED(rv) && !results.IsEmpty()) {
|
||||
nsAutoCString uri;
|
||||
mURI->GetSpec(uri);
|
||||
nsCOMPtr<nsIConsoleService> console(
|
||||
do_GetService("@mozilla.org/consoleservice;1"));
|
||||
if (console) {
|
||||
nsString message = NS_LITERAL_STRING("Blocking ") +
|
||||
NS_ConvertASCIItoUTF16(uri) +
|
||||
NS_LITERAL_STRING(" since it was found on an internal Firefox blocklist.");
|
||||
console->LogStringMessage(message.get());
|
||||
}
|
||||
Telemetry::Accumulate(Telemetry::PLUGIN_BLOCKED_FOR_STABILITY, 1);
|
||||
allowLoad = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Content policy implementations can mutate the DOM, check for re-entry
|
||||
if (!mIsLoading) {
|
||||
LOG(("OBJLC [%p]: We re-entered in content policy, leaving original load",
|
||||
@ -2353,6 +2352,13 @@ nsObjectLoadingContent::LoadObject(bool aNotify,
|
||||
}
|
||||
}
|
||||
|
||||
// Items resolved as Image/Document are no candidates for content blocking,
|
||||
// as well as invalid plugins (they will not have the mContentType set).
|
||||
if ((mType == eType_Null || mType == eType_Plugin) && ShouldBlockContent()) {
|
||||
LOG(("OBJLC [%p]: Enable content blocking", this));
|
||||
mType = eType_Loading;
|
||||
}
|
||||
|
||||
// If we're a plugin but shouldn't start yet, load fallback with
|
||||
// reason click-to-play instead. Items resolved as Image/Document
|
||||
// will not be checked for previews, as well as invalid plugins
|
||||
@ -3362,6 +3368,20 @@ static bool sPrefsInitialized;
|
||||
static uint32_t sSessionTimeoutMinutes;
|
||||
static uint32_t sPersistentTimeoutDays;
|
||||
|
||||
bool
|
||||
nsObjectLoadingContent::ShouldBlockContent()
|
||||
{
|
||||
if (mContentBlockingDisabled)
|
||||
return false;
|
||||
|
||||
if (!IsFlashMIME(mContentType) || !Preferences::GetBool(kPrefBlockURIs)) {
|
||||
mContentBlockingDisabled = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
nsObjectLoadingContent::ShouldPlay(FallbackType &aReason, bool aIgnoreCurrentType)
|
||||
{
|
||||
|
@ -445,6 +445,11 @@ class nsObjectLoadingContent : public nsImageLoadingContent
|
||||
*/
|
||||
nsresult CloseChannel();
|
||||
|
||||
/**
|
||||
* If this object should be tested against blocking list.
|
||||
*/
|
||||
bool ShouldBlockContent();
|
||||
|
||||
/**
|
||||
* If this object is allowed to play plugin content, or if it would display
|
||||
* click-to-play instead.
|
||||
@ -653,6 +658,9 @@ class nsObjectLoadingContent : public nsImageLoadingContent
|
||||
// activated by PlayPlugin(). (see ShouldPlay())
|
||||
bool mActivated : 1;
|
||||
|
||||
// Whether content blocking is enabled or not for this object.
|
||||
bool mContentBlockingDisabled : 1;
|
||||
|
||||
// Protects DoStopPlugin from reentry (bug 724781).
|
||||
bool mIsStopping : 1;
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -9,6 +9,7 @@
|
||||
#include "GLContextTypes.h"
|
||||
#include "GLTypes.h"
|
||||
#include "WebGLStrongTypes.h"
|
||||
#include "WebGLTypes.h"
|
||||
|
||||
|
||||
template <class T>
|
||||
@ -56,66 +57,72 @@ public:
|
||||
const uint32_t mWidth;
|
||||
const uint32_t mHeight;
|
||||
const uint32_t mDepth;
|
||||
const bool mHasData;
|
||||
const bool mIsSrcPremult;
|
||||
|
||||
protected:
|
||||
TexUnpackBlob(const WebGLContext* webgl, uint32_t alignment, uint32_t rowLength,
|
||||
uint32_t imageHeight, uint32_t width, uint32_t height, uint32_t depth,
|
||||
bool hasData);
|
||||
TexUnpackBlob(const WebGLContext* webgl, TexImageTarget target, uint32_t rowLength,
|
||||
uint32_t width, uint32_t height, uint32_t depth, bool isSrcPremult);
|
||||
|
||||
public:
|
||||
virtual ~TexUnpackBlob() { }
|
||||
|
||||
virtual bool TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
|
||||
WebGLTexture* tex, TexImageTarget target, GLint level,
|
||||
const webgl::DriverUnpackInfo* dui, GLint xOffset,
|
||||
GLint yOffset, GLint zOffset,
|
||||
GLenum* const out_error) const = 0;
|
||||
protected:
|
||||
bool ConvertIfNeeded(WebGLContext* webgl, const char* funcName, const void* srcBytes,
|
||||
uint32_t srcStride, uint8_t srcBPP, WebGLTexelFormat srcFormat,
|
||||
const webgl::DriverUnpackInfo* dstDUI,
|
||||
const void** const out_bytes,
|
||||
UniqueBuffer* const out_anchoredBuffer) const;
|
||||
|
||||
static void OriginsForDOM(WebGLContext* webgl, gl::OriginPos* const out_src,
|
||||
gl::OriginPos* const out_dst);
|
||||
public:
|
||||
virtual bool HasData() const { return true; }
|
||||
|
||||
virtual bool TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
|
||||
WebGLTexture* tex, TexImageTarget target, GLint level,
|
||||
const webgl::DriverUnpackInfo* dui, GLint xOffset,
|
||||
GLint yOffset, GLint zOffset,
|
||||
GLenum* const out_error) const = 0;
|
||||
};
|
||||
|
||||
class TexUnpackBytes : public TexUnpackBlob
|
||||
class TexUnpackBytes final : public TexUnpackBlob
|
||||
{
|
||||
public:
|
||||
const void* const mBytes;
|
||||
|
||||
TexUnpackBytes(const WebGLContext* webgl, uint32_t width, uint32_t height,
|
||||
uint32_t depth, const void* bytes);
|
||||
TexUnpackBytes(const WebGLContext* webgl, TexImageTarget target, uint32_t width,
|
||||
uint32_t height, uint32_t depth, const void* bytes);
|
||||
|
||||
virtual bool HasData() const override { return bool(mBytes); }
|
||||
|
||||
virtual bool TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
|
||||
WebGLTexture* tex, TexImageTarget target, GLint level,
|
||||
const webgl::DriverUnpackInfo* dui, GLint xOffset,
|
||||
GLint yOffset, GLint zOffset,
|
||||
GLenum* const out_error) const override;
|
||||
WebGLTexture* tex, TexImageTarget target, GLint level,
|
||||
const webgl::DriverUnpackInfo* dui, GLint xOffset,
|
||||
GLint yOffset, GLint zOffset,
|
||||
GLenum* const out_error) const override;
|
||||
};
|
||||
|
||||
class TexUnpackImage : public TexUnpackBlob
|
||||
class TexUnpackImage final : public TexUnpackBlob
|
||||
{
|
||||
public:
|
||||
const RefPtr<layers::Image> mImage;
|
||||
const bool mIsAlphaPremult;
|
||||
|
||||
TexUnpackImage(const WebGLContext* webgl, uint32_t imageHeight, uint32_t width,
|
||||
uint32_t height, uint32_t depth, const RefPtr<layers::Image>& image,
|
||||
TexUnpackImage(const WebGLContext* webgl, TexImageTarget target, uint32_t width,
|
||||
uint32_t height, uint32_t depth, layers::Image* image,
|
||||
bool isAlphaPremult);
|
||||
|
||||
virtual bool TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
|
||||
WebGLTexture* tex, TexImageTarget target, GLint level,
|
||||
const webgl::DriverUnpackInfo* dui, GLint xOffset,
|
||||
GLint yOffset, GLint zOffset,
|
||||
GLenum* const out_error) const override;
|
||||
WebGLTexture* tex, TexImageTarget target, GLint level,
|
||||
const webgl::DriverUnpackInfo* dui, GLint xOffset,
|
||||
GLint yOffset, GLint zOffset,
|
||||
GLenum* const out_error) const override;
|
||||
};
|
||||
|
||||
class TexUnpackSurface : public TexUnpackBlob
|
||||
class TexUnpackSurface final : public TexUnpackBlob
|
||||
{
|
||||
public:
|
||||
const RefPtr<gfx::SourceSurface> mSurf;
|
||||
const bool mIsAlphaPremult;
|
||||
const RefPtr<gfx::DataSourceSurface> mSurf;
|
||||
|
||||
TexUnpackSurface(const WebGLContext* webgl, uint32_t imageHeight, uint32_t width,
|
||||
uint32_t height, uint32_t depth, gfx::SourceSurface* surf,
|
||||
TexUnpackSurface(const WebGLContext* webgl, TexImageTarget target, uint32_t width,
|
||||
uint32_t height, uint32_t depth, gfx::DataSourceSurface* surf,
|
||||
bool isAlphaPremult);
|
||||
|
||||
virtual bool TexOrSubImage(bool isSubImage, bool needsRespec, const char* funcName,
|
||||
@ -123,19 +130,6 @@ public:
|
||||
const webgl::DriverUnpackInfo* dui, GLint xOffset,
|
||||
GLint yOffset, GLint zOffset,
|
||||
GLenum* const out_error) const override;
|
||||
|
||||
protected:
|
||||
static bool ConvertSurface(WebGLContext* webgl, const webgl::DriverUnpackInfo* dui,
|
||||
gfx::DataSourceSurface* surf, bool isSurfAlphaPremult,
|
||||
UniqueBuffer* const out_convertedBuffer,
|
||||
uint8_t* const out_convertedAlignment,
|
||||
bool* const out_wasTrivial, bool* const out_outOfMemory);
|
||||
static bool UploadDataSurface(bool isSubImage, WebGLContext* webgl,
|
||||
TexImageTarget target, GLint level,
|
||||
const webgl::DriverUnpackInfo* dui, GLint xOffset,
|
||||
GLint yOffset, GLint zOffset, GLsizei width,
|
||||
GLsizei height, gfx::DataSourceSurface* surf,
|
||||
bool isSurfAlphaPremult, GLenum* const out_glError);
|
||||
};
|
||||
|
||||
} // namespace webgl
|
||||
|
@ -288,6 +288,7 @@ public:
|
||||
void ErrorInvalidEnumInfo(const char* info, const char* funcName,
|
||||
GLenum enumValue);
|
||||
void ErrorOutOfMemory(const char* fmt = 0, ...);
|
||||
void ErrorImplementationBug(const char* fmt = 0, ...);
|
||||
|
||||
const char* ErrorName(GLenum error);
|
||||
|
||||
@ -963,10 +964,6 @@ protected:
|
||||
WebGLTexture** const out_texture,
|
||||
WebGLTexture::ImageInfo** const out_imageInfo);
|
||||
|
||||
bool GetUnpackValuesForImage(const char* funcName, uint32_t srcImageWidth,
|
||||
uint32_t srcImageHeight, uint32_t* const out_rowLength,
|
||||
uint32_t* const out_imageHeight);
|
||||
|
||||
bool ValidateUnpackInfo(const char* funcName, GLenum format, GLenum type,
|
||||
webgl::PackingInfo* const out);
|
||||
|
||||
@ -1334,24 +1331,8 @@ protected:
|
||||
WebGLTexelFormat dstFormat, bool dstPremultiplied,
|
||||
size_t dstTexelSize);
|
||||
|
||||
public:
|
||||
nsLayoutUtils::SurfaceFromElementResult
|
||||
SurfaceFromElement(dom::Element* elem)
|
||||
{
|
||||
uint32_t flags = nsLayoutUtils::SFE_WANT_IMAGE_SURFACE |
|
||||
nsLayoutUtils::SFE_USE_ELEMENT_SIZE_IF_VECTOR;
|
||||
//////
|
||||
|
||||
if (mPixelStore_ColorspaceConversion == LOCAL_GL_NONE)
|
||||
flags |= nsLayoutUtils::SFE_NO_COLORSPACE_CONVERSION;
|
||||
|
||||
if (!mPixelStore_PremultiplyAlpha)
|
||||
flags |= nsLayoutUtils::SFE_PREFER_NO_PREMULTIPLY_ALPHA;
|
||||
|
||||
RefPtr<gfx::DrawTarget> idealDrawTarget = nullptr; // Don't care for now.
|
||||
return nsLayoutUtils::SurfaceFromElement(elem, flags, idealDrawTarget);
|
||||
}
|
||||
|
||||
protected:
|
||||
// Returns false if `object` is null or not valid.
|
||||
template<class ObjectType>
|
||||
bool ValidateObject(const char* info, ObjectType* object);
|
||||
@ -1629,6 +1610,7 @@ public:
|
||||
friend class ScopedUnpackReset;
|
||||
friend class webgl::TexUnpackBlob;
|
||||
friend class webgl::TexUnpackBytes;
|
||||
friend class webgl::TexUnpackImage;
|
||||
friend class webgl::TexUnpackSurface;
|
||||
friend class WebGLTexture;
|
||||
friend class WebGLFBAttachPoint;
|
||||
|
@ -3,6 +3,7 @@
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "WebGLContextUtils.h"
|
||||
#include "WebGLContext.h"
|
||||
|
||||
#include "GLContext.h"
|
||||
@ -23,7 +24,6 @@
|
||||
#include "WebGLProgram.h"
|
||||
#include "WebGLTexture.h"
|
||||
#include "WebGLVertexArray.h"
|
||||
#include "WebGLContextUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
@ -207,6 +207,22 @@ WebGLContext::ErrorOutOfMemory(const char* fmt, ...)
|
||||
return SynthesizeGLError(LOCAL_GL_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::ErrorImplementationBug(const char* fmt, ...)
|
||||
{
|
||||
const nsPrintfCString warning("Implementation bug, please file at %s! %s",
|
||||
"https://bugzilla.mozilla.org/", fmt);
|
||||
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
GenerateWarning(warning.BeginReading(), va);
|
||||
va_end(va);
|
||||
|
||||
MOZ_ASSERT(false, "WebGLContext::ErrorImplementationBug");
|
||||
NS_ERROR("WebGLContext::ErrorImplementationBug");
|
||||
return SynthesizeGLError(LOCAL_GL_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
const char*
|
||||
WebGLContext::ErrorName(GLenum error)
|
||||
{
|
||||
|
@ -412,6 +412,9 @@ TexImageTargetForTargetAndFace(TexTarget target, uint8_t face)
|
||||
already_AddRefed<mozilla::layers::Image>
|
||||
ImageFromVideo(dom::HTMLVideoElement* elem);
|
||||
|
||||
bool
|
||||
IsTarget3D(TexImageTarget target);
|
||||
|
||||
GLenum
|
||||
DoTexImage(gl::GLContext* gl, TexImageTarget target, GLint level,
|
||||
const webgl::DriverUnpackInfo* dui, GLsizei width, GLsizei height,
|
||||
|
@ -178,11 +178,12 @@ WebGLContext::ValidateUnpackPixels(const char* funcName, uint32_t fullRows,
|
||||
}
|
||||
|
||||
static UniquePtr<webgl::TexUnpackBlob>
|
||||
BlobFromView(WebGLContext* webgl, const char* funcName, uint32_t width, uint32_t height,
|
||||
uint32_t depth, const webgl::PackingInfo& pi,
|
||||
BlobFromView(WebGLContext* webgl, const char* funcName, TexImageTarget target,
|
||||
uint32_t width, uint32_t height, uint32_t depth,
|
||||
const webgl::PackingInfo& pi,
|
||||
const dom::Nullable<dom::ArrayBufferView>& maybeView)
|
||||
{
|
||||
const void* bytes = nullptr;
|
||||
const uint8_t* bytes = nullptr;
|
||||
uint32_t byteCount = 0;
|
||||
|
||||
if (!maybeView.IsNull()) {
|
||||
@ -203,8 +204,8 @@ BlobFromView(WebGLContext* webgl, const char* funcName, uint32_t width, uint32_t
|
||||
}
|
||||
}
|
||||
|
||||
UniquePtr<webgl::TexUnpackBlob> blob(new webgl::TexUnpackBytes(webgl, width, height,
|
||||
depth, bytes));
|
||||
UniquePtr<webgl::TexUnpackBlob> blob(new webgl::TexUnpackBytes(webgl, target, width,
|
||||
height, depth, bytes));
|
||||
|
||||
//////
|
||||
|
||||
@ -268,7 +269,7 @@ WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarge
|
||||
if (!mContext->ValidateUnpackInfo(funcName, unpackFormat, unpackType, &pi))
|
||||
return;
|
||||
|
||||
const auto blob = BlobFromView(mContext, funcName, width, height, depth, pi,
|
||||
const auto blob = BlobFromView(mContext, funcName, target, width, height, depth, pi,
|
||||
maybeView);
|
||||
if (!blob)
|
||||
return;
|
||||
@ -280,7 +281,7 @@ WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarge
|
||||
////////////////////////////////////////
|
||||
// ImageData
|
||||
|
||||
static already_AddRefed<gfx::SourceSurface>
|
||||
static already_AddRefed<gfx::DataSourceSurface>
|
||||
FromImageData(WebGLContext* webgl, const char* funcName, GLenum unpackType,
|
||||
dom::ImageData* imageData, dom::Uint8ClampedArray* scopedArr)
|
||||
{
|
||||
@ -299,7 +300,7 @@ FromImageData(WebGLContext* webgl, const char* funcName, GLenum unpackType,
|
||||
|
||||
uint8_t* wrappableData = (uint8_t*)data;
|
||||
|
||||
RefPtr<gfx::SourceSurface> surf =
|
||||
RefPtr<gfx::DataSourceSurface> surf =
|
||||
gfx::Factory::CreateWrappingDataSourceSurface(wrappableData,
|
||||
stride,
|
||||
size,
|
||||
@ -312,35 +313,6 @@ FromImageData(WebGLContext* webgl, const char* funcName, GLenum unpackType,
|
||||
return surf.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
WebGLContext::GetUnpackValuesForImage(const char* funcName, uint32_t srcImageWidth,
|
||||
uint32_t srcImageHeight,
|
||||
uint32_t* const out_rowLength,
|
||||
uint32_t* const out_imageHeight)
|
||||
{
|
||||
uint32_t rowLength = mPixelStore_UnpackRowLength;
|
||||
if (!rowLength) {
|
||||
rowLength = srcImageWidth;
|
||||
} else if (rowLength != srcImageWidth) {
|
||||
ErrorInvalidOperation("%s: UNPACK_ROW_LENGTH, if set, must be == width of"
|
||||
" object.");
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t imageHeight = mPixelStore_UnpackImageHeight;
|
||||
if (!imageHeight) {
|
||||
imageHeight = srcImageHeight;
|
||||
} else if (imageHeight > srcImageHeight) {
|
||||
ErrorInvalidOperation("%s: UNPACK_IMAGE_HEIGHT, if set, must be <= height of"
|
||||
" object");
|
||||
return false;
|
||||
}
|
||||
|
||||
*out_rowLength = rowLength;
|
||||
*out_imageHeight = imageHeight;
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarget target,
|
||||
GLint level, GLenum internalFormat, GLint xOffset,
|
||||
@ -362,27 +334,20 @@ WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarge
|
||||
const uint32_t height = imageData->Height();
|
||||
const uint32_t depth = 1;
|
||||
|
||||
uint32_t rowLength, imageHeight;
|
||||
if (!mContext->GetUnpackValuesForImage(funcName, imageData->Width(),
|
||||
imageData->Height(), &rowLength, &imageHeight))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
dom::RootedTypedArray<dom::Uint8ClampedArray> scopedArr(
|
||||
nsContentUtils::RootingCx());
|
||||
const RefPtr<gfx::SourceSurface> surf = FromImageData(mContext, funcName, unpackType,
|
||||
imageData, &scopedArr);
|
||||
dom::RootedTypedArray<dom::Uint8ClampedArray> scopedArr(nsContentUtils::RootingCx());
|
||||
const RefPtr<gfx::DataSourceSurface> surf = FromImageData(mContext, funcName,
|
||||
unpackType, imageData,
|
||||
&scopedArr);
|
||||
if (!surf)
|
||||
return;
|
||||
|
||||
// WhatWG "HTML Living Standard" (30 October 2015):
|
||||
// "The getImageData(sx, sy, sw, sh) method [...] Pixels must be returned as
|
||||
// non-premultiplied alpha values."
|
||||
const bool surfIsAlphaPremult = false;
|
||||
const bool isAlphaPremult = false;
|
||||
|
||||
const webgl::TexUnpackSurface blob(mContext, imageHeight, width, height, depth, surf,
|
||||
surfIsAlphaPremult);
|
||||
const webgl::TexUnpackSurface blob(mContext, target, width, height, depth, surf,
|
||||
isAlphaPremult);
|
||||
|
||||
const uint32_t fullRows = imageData->Height();
|
||||
const uint32_t tailPixels = 0;
|
||||
@ -407,7 +372,21 @@ WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarge
|
||||
if (!mContext->ValidateUnpackInfo(funcName, unpackFormat, unpackType, &pi))
|
||||
return;
|
||||
|
||||
auto sfer = mContext->SurfaceFromElement(elem);
|
||||
//////
|
||||
|
||||
uint32_t flags = nsLayoutUtils::SFE_WANT_IMAGE_SURFACE |
|
||||
nsLayoutUtils::SFE_USE_ELEMENT_SIZE_IF_VECTOR;
|
||||
|
||||
if (mContext->mPixelStore_ColorspaceConversion == LOCAL_GL_NONE)
|
||||
flags |= nsLayoutUtils::SFE_NO_COLORSPACE_CONVERSION;
|
||||
|
||||
if (!mContext->mPixelStore_PremultiplyAlpha)
|
||||
flags |= nsLayoutUtils::SFE_PREFER_NO_PREMULTIPLY_ALPHA;
|
||||
|
||||
RefPtr<gfx::DrawTarget> idealDrawTarget = nullptr; // Don't care for now.
|
||||
auto sfer = nsLayoutUtils::SurfaceFromElement(elem, flags, idealDrawTarget);
|
||||
|
||||
//////
|
||||
|
||||
uint32_t elemWidth = 0;
|
||||
uint32_t elemHeight = 0;
|
||||
@ -418,23 +397,25 @@ WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarge
|
||||
elemHeight = layersImage->GetSize().height;
|
||||
}
|
||||
|
||||
gfx::SourceSurface* surf = nullptr;
|
||||
RefPtr<gfx::DataSourceSurface> dataSurf;
|
||||
if (!layersImage && sfer.GetSourceSurface()) {
|
||||
surf = sfer.GetSourceSurface();
|
||||
const auto surf = sfer.GetSourceSurface();
|
||||
elemWidth = surf->GetSize().width;
|
||||
elemHeight = surf->GetSize().height;
|
||||
|
||||
// WARNING: OSX can lose our MakeCurrent here.
|
||||
dataSurf = surf->GetDataSurface();
|
||||
}
|
||||
|
||||
//////
|
||||
|
||||
// Eventually, these will be args.
|
||||
const uint32_t width = elemWidth;
|
||||
const uint32_t height = elemHeight;
|
||||
const uint32_t depth = 1;
|
||||
|
||||
// While it's counter-intuitive, the shape of the SFEResult API means that we should
|
||||
// try to pull out a surface first, and then, if we do pull out a surface, check
|
||||
// CORS/write-only/etc..
|
||||
if (!layersImage && !surf) {
|
||||
webgl::TexUnpackBytes blob(mContext, width, height, depth, nullptr);
|
||||
if (!layersImage && !dataSurf) {
|
||||
const webgl::TexUnpackBytes blob(mContext, target, width, height, depth, nullptr);
|
||||
TexOrSubImageBlob(isSubImage, funcName, target, level, internalFormat, xOffset,
|
||||
yOffset, zOffset, pi, &blob);
|
||||
return;
|
||||
@ -442,6 +423,10 @@ WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarge
|
||||
|
||||
//////
|
||||
|
||||
// While it's counter-intuitive, the shape of the SFEResult API means that we should
|
||||
// try to pull out a surface first, and then, if we do pull out a surface, check
|
||||
// CORS/write-only/etc..
|
||||
|
||||
if (!sfer.mCORSUsed) {
|
||||
auto& srcPrincipal = sfer.mPrincipal;
|
||||
nsIPrincipal* dstPrincipal = mContext->GetCanvas()->NodePrincipal();
|
||||
@ -468,23 +453,16 @@ WebGLTexture::TexOrSubImage(bool isSubImage, const char* funcName, TexImageTarge
|
||||
//////
|
||||
// Ok, we're good!
|
||||
|
||||
uint32_t rowLength, imageHeight;
|
||||
if (!mContext->GetUnpackValuesForImage(funcName, elemWidth, elemHeight, &rowLength,
|
||||
&imageHeight))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
UniquePtr<const webgl::TexUnpackBlob> blob;
|
||||
const bool isAlphaPremult = sfer.mIsPremultiplied;
|
||||
|
||||
if (layersImage) {
|
||||
blob.reset(new webgl::TexUnpackImage(mContext, imageHeight, width, height, depth,
|
||||
blob.reset(new webgl::TexUnpackImage(mContext, target, width, height, depth,
|
||||
layersImage, isAlphaPremult));
|
||||
} else {
|
||||
MOZ_ASSERT(surf);
|
||||
blob.reset(new webgl::TexUnpackSurface(mContext, imageHeight, width, height,
|
||||
depth, surf, isAlphaPremult));
|
||||
MOZ_ASSERT(dataSurf);
|
||||
blob.reset(new webgl::TexUnpackSurface(mContext, target, width, height, depth,
|
||||
dataSurf, isAlphaPremult));
|
||||
}
|
||||
|
||||
const uint32_t fullRows = elemHeight;
|
||||
@ -836,8 +814,8 @@ DoTexStorage(gl::GLContext* gl, TexTarget target, GLsizei levels, GLenum sizedFo
|
||||
return errorScope.GetError();
|
||||
}
|
||||
|
||||
static bool
|
||||
Is3D(TexImageTarget target)
|
||||
bool
|
||||
IsTarget3D(TexImageTarget target)
|
||||
{
|
||||
switch (target.get()) {
|
||||
case LOCAL_GL_TEXTURE_2D:
|
||||
@ -867,7 +845,7 @@ DoTexImage(gl::GLContext* gl, TexImageTarget target, GLint level,
|
||||
|
||||
gl::GLContext::LocalErrorScope errorScope(*gl);
|
||||
|
||||
if (Is3D(target)) {
|
||||
if (IsTarget3D(target)) {
|
||||
gl->fTexImage3D(target.get(), level, dui->internalFormat, width, height, depth,
|
||||
border, dui->unpackFormat, dui->unpackType, data);
|
||||
} else {
|
||||
@ -886,7 +864,7 @@ DoTexSubImage(gl::GLContext* gl, TexImageTarget target, GLint level, GLint xOffs
|
||||
{
|
||||
gl::GLContext::LocalErrorScope errorScope(*gl);
|
||||
|
||||
if (Is3D(target)) {
|
||||
if (IsTarget3D(target)) {
|
||||
gl->fTexSubImage3D(target.get(), level, xOffset, yOffset, zOffset, width, height,
|
||||
depth, pi.format, pi.type, data);
|
||||
} else {
|
||||
@ -908,7 +886,7 @@ DoCompressedTexImage(gl::GLContext* gl, TexImageTarget target, GLint level,
|
||||
|
||||
gl::GLContext::LocalErrorScope errorScope(*gl);
|
||||
|
||||
if (Is3D(target)) {
|
||||
if (IsTarget3D(target)) {
|
||||
gl->fCompressedTexImage3D(target.get(), level, internalFormat, width, height,
|
||||
depth, border, dataSize, data);
|
||||
} else {
|
||||
@ -928,7 +906,7 @@ DoCompressedTexSubImage(gl::GLContext* gl, TexImageTarget target, GLint level,
|
||||
{
|
||||
gl::GLContext::LocalErrorScope errorScope(*gl);
|
||||
|
||||
if (Is3D(target)) {
|
||||
if (IsTarget3D(target)) {
|
||||
gl->fCompressedTexSubImage3D(target.get(), level, xOffset, yOffset, zOffset,
|
||||
width, height, depth, sizedUnpackFormat, dataSize,
|
||||
data);
|
||||
@ -950,7 +928,7 @@ DoCopyTexImage2D(gl::GLContext* gl, TexImageTarget target, GLint level,
|
||||
|
||||
gl::GLContext::LocalErrorScope errorScope(*gl);
|
||||
|
||||
MOZ_ASSERT(!Is3D(target));
|
||||
MOZ_ASSERT(!IsTarget3D(target));
|
||||
gl->fCopyTexImage2D(target.get(), level, internalFormat, x, y, width, height,
|
||||
border);
|
||||
|
||||
@ -964,7 +942,7 @@ DoCopyTexSubImage(gl::GLContext* gl, TexImageTarget target, GLint level, GLint x
|
||||
{
|
||||
gl::GLContext::LocalErrorScope errorScope(*gl);
|
||||
|
||||
if (Is3D(target)) {
|
||||
if (IsTarget3D(target)) {
|
||||
gl->fCopyTexSubImage3D(target.get(), level, xOffset, yOffset, zOffset, x, y,
|
||||
width, height);
|
||||
} else {
|
||||
@ -1263,7 +1241,7 @@ WebGLTexture::TexImage(const char* funcName, TexImageTarget target, GLint level,
|
||||
|
||||
if (!mContext->IsWebGL2() && dstFormat->d) {
|
||||
if (target != LOCAL_GL_TEXTURE_2D ||
|
||||
blob->mHasData ||
|
||||
blob->HasData() ||
|
||||
level != 0)
|
||||
{
|
||||
mContext->ErrorInvalidOperation("%s: With format %s, this function may only"
|
||||
@ -1284,7 +1262,7 @@ WebGLTexture::TexImage(const char* funcName, TexImageTarget target, GLint level,
|
||||
// slower.
|
||||
|
||||
const ImageInfo newImageInfo(dstUsage, blob->mWidth, blob->mHeight, blob->mDepth,
|
||||
blob->mHasData);
|
||||
blob->HasData());
|
||||
|
||||
const bool isSubImage = false;
|
||||
const bool needsRespec = (imageInfo->mWidth != newImageInfo.mWidth ||
|
||||
|
@ -123,7 +123,7 @@ function testColorConversions() {
|
||||
testColorConversion("RGBA32", "GRAY8"),
|
||||
testColorConversion("RGBA32", "YUV444P"),
|
||||
testColorConversion("RGBA32", "YUV422P"),
|
||||
testColorConversion("RGBA32", "YUV420P"),
|
||||
testColorConversion("RGBA32", "YUV420P", 2),
|
||||
testColorConversion("RGBA32", "YUV420SP_NV12"),
|
||||
testColorConversion("RGBA32", "YUV420SP_NV21"),
|
||||
testColorConversion("RGBA32", "HSV", 0.01),
|
||||
@ -136,10 +136,10 @@ function testColorConversions() {
|
||||
testColorConversion("BGRA32", "BGR24"),
|
||||
testColorConversion("BGRA32", "GRAY8"),
|
||||
testColorConversion("BGRA32", "YUV444P", 3),
|
||||
testColorConversion("BGRA32", "YUV422P"),
|
||||
testColorConversion("BGRA32", "YUV420P"),
|
||||
testColorConversion("BGRA32", "YUV420SP_NV12"),
|
||||
testColorConversion("BGRA32", "YUV420SP_NV21"),
|
||||
testColorConversion("BGRA32", "YUV422P", 2),
|
||||
testColorConversion("BGRA32", "YUV420P", 2),
|
||||
testColorConversion("BGRA32", "YUV420SP_NV12", 2),
|
||||
testColorConversion("BGRA32", "YUV420SP_NV21", 2),
|
||||
testColorConversion("BGRA32", "HSV", 0.01),
|
||||
testColorConversion("BGRA32", "Lab", 0.5),
|
||||
|
||||
@ -178,7 +178,7 @@ function testColorConversions() {
|
||||
testColorConversion("YUV444P", "BGR24"),
|
||||
testColorConversion("YUV444P", "GRAY8"),
|
||||
testColorConversion("YUV444P", "YUV444P"),
|
||||
testColorConversion("YUV444P", "YUV422P", 3),
|
||||
testColorConversion("YUV444P", "YUV422P", 4),
|
||||
testColorConversion("YUV444P", "YUV420P", 3),
|
||||
testColorConversion("YUV444P", "YUV420SP_NV12", 3),
|
||||
testColorConversion("YUV444P", "YUV420SP_NV21", 3),
|
||||
@ -187,7 +187,7 @@ function testColorConversions() {
|
||||
|
||||
// From YUV422P
|
||||
testColorConversion("YUV422P", "RGBA32"),
|
||||
testColorConversion("YUV422P", "BGRA32"),
|
||||
testColorConversion("YUV422P", "BGRA32", 2),
|
||||
testColorConversion("YUV422P", "RGB24"),
|
||||
testColorConversion("YUV422P", "BGR24"),
|
||||
testColorConversion("YUV422P", "GRAY8"),
|
||||
@ -200,13 +200,13 @@ function testColorConversions() {
|
||||
testColorConversion("YUV422P", "Lab", 0.01),
|
||||
|
||||
// From YUV420P
|
||||
testColorConversion("YUV420P", "RGBA32"),
|
||||
testColorConversion("YUV420P", "BGRA32"),
|
||||
testColorConversion("YUV420P", "RGBA32", 2),
|
||||
testColorConversion("YUV420P", "BGRA32", 2),
|
||||
testColorConversion("YUV420P", "RGB24"),
|
||||
testColorConversion("YUV420P", "BGR24"),
|
||||
testColorConversion("YUV420P", "GRAY8"),
|
||||
testColorConversion("YUV420P", "YUV444P", 3),
|
||||
testColorConversion("YUV420P", "YUV422P"),
|
||||
testColorConversion("YUV420P", "YUV422P", 1),
|
||||
testColorConversion("YUV420P", "YUV420P"),
|
||||
testColorConversion("YUV420P", "YUV420SP_NV12"),
|
||||
testColorConversion("YUV420P", "YUV420SP_NV21"),
|
||||
@ -215,12 +215,12 @@ function testColorConversions() {
|
||||
|
||||
// From NV12
|
||||
testColorConversion("YUV420SP_NV12", "RGBA32"),
|
||||
testColorConversion("YUV420SP_NV12", "BGRA32"),
|
||||
testColorConversion("YUV420SP_NV12", "BGRA32", 2),
|
||||
testColorConversion("YUV420SP_NV12", "RGB24"),
|
||||
testColorConversion("YUV420SP_NV12", "BGR24"),
|
||||
testColorConversion("YUV420SP_NV12", "GRAY8"),
|
||||
testColorConversion("YUV420SP_NV12", "YUV444P", 3),
|
||||
testColorConversion("YUV420SP_NV12", "YUV422P"),
|
||||
testColorConversion("YUV420SP_NV12", "YUV422P", 1),
|
||||
testColorConversion("YUV420SP_NV12", "YUV420P"),
|
||||
testColorConversion("YUV420SP_NV12", "YUV420SP_NV12"),
|
||||
testColorConversion("YUV420SP_NV12", "YUV420SP_NV21"),
|
||||
@ -229,12 +229,12 @@ function testColorConversions() {
|
||||
|
||||
// From NV21
|
||||
testColorConversion("YUV420SP_NV21", "RGBA32"),
|
||||
testColorConversion("YUV420SP_NV21", "BGRA32"),
|
||||
testColorConversion("YUV420SP_NV21", "BGRA32", 2),
|
||||
testColorConversion("YUV420SP_NV21", "RGB24"),
|
||||
testColorConversion("YUV420SP_NV21", "BGR24"),
|
||||
testColorConversion("YUV420SP_NV21", "GRAY8"),
|
||||
testColorConversion("YUV420SP_NV21", "YUV444P", 3),
|
||||
testColorConversion("YUV420SP_NV21", "YUV422P"),
|
||||
testColorConversion("YUV420SP_NV21", "YUV422P", 1),
|
||||
testColorConversion("YUV420SP_NV21", "YUV420P"),
|
||||
testColorConversion("YUV420SP_NV21", "YUV420SP_NV12"),
|
||||
testColorConversion("YUV420SP_NV21", "YUV420SP_NV21"),
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "mozilla/Telemetry.h"
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsISettingsService.h"
|
||||
|
||||
#include "nsGeolocation.h"
|
||||
#include "nsDOMClassInfoID.h"
|
||||
@ -31,6 +32,7 @@
|
||||
#include "mozilla/dom/Event.h"
|
||||
#include "mozilla/WeakPtr.h"
|
||||
#include "mozilla/dom/PermissionMessageUtils.h"
|
||||
#include "mozilla/dom/SettingChangeNotificationBinding.h"
|
||||
#include "mozilla/dom/WakeLock.h"
|
||||
|
||||
class nsIPrincipal;
|
||||
@ -56,6 +58,9 @@ class nsIPrincipal;
|
||||
// that a window can make.
|
||||
#define MAX_GEO_REQUESTS_PER_WINDOW 1500
|
||||
|
||||
// The settings key.
|
||||
#define GEO_SETTINGS_ENABLED "geolocation.enabled"
|
||||
|
||||
using mozilla::Unused; // <snicker>
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::dom;
|
||||
@ -141,6 +146,53 @@ CreatePositionOptionsCopy(const PositionOptions& aOptions)
|
||||
return geoOptions.forget();
|
||||
}
|
||||
|
||||
class GeolocationSettingsCallback : public nsISettingsServiceCallback
|
||||
{
|
||||
virtual ~GeolocationSettingsCallback() {
|
||||
MOZ_COUNT_DTOR(GeolocationSettingsCallback);
|
||||
}
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
GeolocationSettingsCallback() {
|
||||
MOZ_COUNT_CTOR(GeolocationSettingsCallback);
|
||||
}
|
||||
|
||||
NS_IMETHOD Handle(const nsAString& aName, JS::Handle<JS::Value> aResult) override
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// The geolocation is enabled by default:
|
||||
bool value = true;
|
||||
if (aResult.isBoolean()) {
|
||||
value = aResult.toBoolean();
|
||||
}
|
||||
|
||||
MozSettingValue(value);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD HandleError(const nsAString& aName) override
|
||||
{
|
||||
NS_WARNING("Unable to get value for '" GEO_SETTINGS_ENABLED "'");
|
||||
|
||||
// Default it's enabled:
|
||||
MozSettingValue(true);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void MozSettingValue(const bool aValue)
|
||||
{
|
||||
RefPtr<nsGeolocationService> gs = nsGeolocationService::GetGeolocationService();
|
||||
if (gs) {
|
||||
gs->HandleMozsettingValue(aValue);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(GeolocationSettingsCallback, nsISettingsServiceCallback)
|
||||
|
||||
class RequestPromptEvent : public Runnable
|
||||
{
|
||||
public:
|
||||
@ -326,14 +378,12 @@ NS_INTERFACE_MAP_END
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGeolocationRequest)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGeolocationRequest)
|
||||
NS_IMPL_CYCLE_COLLECTION(nsGeolocationRequest, mCallback, mErrorCallback, mLocator)
|
||||
|
||||
void
|
||||
nsGeolocationRequest::Notify()
|
||||
{
|
||||
SetTimeoutTimer();
|
||||
NotifyErrorAndShutdown(nsIDOMGeoPositionError::TIMEOUT);
|
||||
}
|
||||
|
||||
void
|
||||
nsGeolocationRequest::NotifyErrorAndShutdown(uint16_t aErrorCode)
|
||||
{
|
||||
@ -505,7 +555,6 @@ nsGeolocationRequest::GetRequester(nsIContentPermissionRequester** aRequester)
|
||||
|
||||
nsCOMPtr<nsIContentPermissionRequester> requester = mRequester;
|
||||
requester.forget(aRequester);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -593,7 +642,6 @@ nsGeolocationRequest::SendLocation(nsIDOMGeoPosition* aPosition)
|
||||
MOZ_ASSERT(mShutdown || mIsWatchPositionRequest,
|
||||
"non-shutdown getCurrentPosition request after callback!");
|
||||
}
|
||||
|
||||
nsIPrincipal*
|
||||
nsGeolocationRequest::GetPrincipal()
|
||||
{
|
||||
@ -610,7 +658,6 @@ nsGeolocationRequest::Update(nsIDOMGeoPosition* aPosition)
|
||||
NS_DispatchToMainThread(ev);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGeolocationRequest::NotifyError(uint16_t aErrorCode)
|
||||
{
|
||||
@ -652,7 +699,6 @@ nsGeolocationRequest::TimerCallbackHolder::Notify(nsITimer*)
|
||||
RefPtr<nsGeolocationRequest> request(mRequest);
|
||||
request->Notify();
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -671,6 +717,7 @@ NS_IMPL_RELEASE(nsGeolocationService)
|
||||
|
||||
|
||||
static bool sGeoEnabled = true;
|
||||
static bool sGeoInitPending = true;
|
||||
static int32_t sProviderTimeout = 6000; // Time, in milliseconds, to wait for the location provider to spin up.
|
||||
|
||||
nsresult nsGeolocationService::Init()
|
||||
@ -683,9 +730,28 @@ nsresult nsGeolocationService::Init()
|
||||
}
|
||||
|
||||
if (XRE_IsContentProcess()) {
|
||||
sGeoInitPending = false;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// check if the geolocation service is enable from settings
|
||||
nsCOMPtr<nsISettingsService> settings =
|
||||
do_GetService("@mozilla.org/settingsService;1");
|
||||
|
||||
if (settings) {
|
||||
nsCOMPtr<nsISettingsServiceLock> settingsLock;
|
||||
nsresult rv = settings->CreateLock(nullptr, getter_AddRefs(settingsLock));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
RefPtr<GeolocationSettingsCallback> callback = new GeolocationSettingsCallback();
|
||||
rv = settingsLock->Get(GEO_SETTINGS_ENABLED, callback);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
} else {
|
||||
// If we cannot obtain the settings service, we continue
|
||||
// assuming that the geolocation is enabled:
|
||||
sGeoInitPending = false;
|
||||
}
|
||||
|
||||
// geolocation service can be enabled -> now register observer
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
if (!obs) {
|
||||
@ -693,6 +759,7 @@ nsresult nsGeolocationService::Init()
|
||||
}
|
||||
|
||||
obs->AddObserver(this, "xpcom-shutdown", false);
|
||||
obs->AddObserver(this, "mozsettings-changed", false);
|
||||
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
mProvider = new AndroidLocationProvider();
|
||||
@ -745,6 +812,47 @@ nsGeolocationService::~nsGeolocationService()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
nsGeolocationService::HandleMozsettingChanged(nsISupports* aSubject)
|
||||
{
|
||||
// The string that we're interested in will be a JSON string that looks like:
|
||||
// {"key":"gelocation.enabled","value":true}
|
||||
|
||||
RootedDictionary<SettingChangeNotification> setting(nsContentUtils::RootingCx());
|
||||
if (!WrappedJSToDictionary(aSubject, setting)) {
|
||||
return;
|
||||
}
|
||||
if (!setting.mKey.EqualsASCII(GEO_SETTINGS_ENABLED)) {
|
||||
return;
|
||||
}
|
||||
if (!setting.mValue.isBoolean()) {
|
||||
return;
|
||||
}
|
||||
|
||||
HandleMozsettingValue(setting.mValue.toBoolean());
|
||||
}
|
||||
|
||||
void
|
||||
nsGeolocationService::HandleMozsettingValue(const bool aValue)
|
||||
{
|
||||
if (!aValue) {
|
||||
// turn things off
|
||||
StopDevice();
|
||||
Update(nullptr);
|
||||
mLastPosition.position = nullptr;
|
||||
sGeoEnabled = false;
|
||||
} else {
|
||||
sGeoEnabled = true;
|
||||
}
|
||||
|
||||
if (sGeoInitPending) {
|
||||
sGeoInitPending = false;
|
||||
for (uint32_t i = 0, length = mGeolocators.Length(); i < length; ++i) {
|
||||
mGeolocators[i]->ServiceReady();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGeolocationService::Observe(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
@ -754,6 +862,7 @@ nsGeolocationService::Observe(nsISupports* aSubject,
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
if (obs) {
|
||||
obs->RemoveObserver(this, "xpcom-shutdown");
|
||||
obs->RemoveObserver(this, "mozsettings-changed");
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i< mGeolocators.Length(); i++) {
|
||||
@ -764,6 +873,11 @@ nsGeolocationService::Observe(nsISupports* aSubject,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!strcmp("mozsettings-changed", aTopic)) {
|
||||
HandleMozsettingChanged(aSubject);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!strcmp("timer-callback", aTopic)) {
|
||||
// decide if we can close down the service.
|
||||
for (uint32_t i = 0; i< mGeolocators.Length(); i++)
|
||||
@ -787,21 +901,17 @@ nsGeolocationService::Update(nsIDOMGeoPosition *aSomewhere)
|
||||
if (aSomewhere) {
|
||||
SetCachedPosition(aSomewhere);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i< mGeolocators.Length(); i++) {
|
||||
mGeolocators[i]->Update(aSomewhere);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsGeolocationService::NotifyError(uint16_t aErrorCode)
|
||||
{
|
||||
for (uint32_t i = 0; i < mGeolocators.Length(); i++) {
|
||||
mGeolocators[i]->NotifyError(aErrorCode);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
@ -821,7 +931,7 @@ nsGeolocationService::GetCachedPosition()
|
||||
nsresult
|
||||
nsGeolocationService::StartDevice(nsIPrincipal *aPrincipal)
|
||||
{
|
||||
if (!sGeoEnabled) {
|
||||
if (!sGeoEnabled || sGeoInitPending) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
@ -872,6 +982,7 @@ nsGeolocationService::StopDisconnectTimer()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
nsGeolocationService::SetDisconnectTimer()
|
||||
{
|
||||
@ -894,7 +1005,6 @@ nsGeolocationService::HighAccuracyRequested()
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -908,11 +1018,17 @@ nsGeolocationService::UpdateAccuracy(bool aForceHigh)
|
||||
if (cpc->IsAlive()) {
|
||||
cpc->SendSetGeolocationHigherAccuracy(highRequired);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
mProvider->SetHighAccuracy(!mHigherAccuracy && highRequired);
|
||||
if (!mHigherAccuracy && highRequired) {
|
||||
mProvider->SetHighAccuracy(true);
|
||||
}
|
||||
|
||||
if (mHigherAccuracy && !highRequired) {
|
||||
mProvider->SetHighAccuracy(false);
|
||||
}
|
||||
|
||||
mHigherAccuracy = highRequired;
|
||||
}
|
||||
|
||||
@ -924,7 +1040,6 @@ nsGeolocationService::StopDevice()
|
||||
if (XRE_IsContentProcess()) {
|
||||
ContentChild* cpc = ContentChild::GetSingleton();
|
||||
cpc->SendRemoveGeolocationListener();
|
||||
|
||||
return; // bail early
|
||||
}
|
||||
|
||||
@ -960,10 +1075,8 @@ nsGeolocationService::GetGeolocationService()
|
||||
if (NS_FAILED(result->Init())) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ClearOnShutdown(&nsGeolocationService::sService);
|
||||
nsGeolocationService::sService = result;
|
||||
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
@ -1066,21 +1179,21 @@ Geolocation::Init(nsPIDOMWindowInner* aContentDom)
|
||||
if (mService) {
|
||||
mService->AddLocator(this);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
bool
|
||||
Geolocation::ContainsRequest(nsGeolocationRequest* aRequest)
|
||||
{
|
||||
if (aRequest->IsWatch() && mWatchingCallbacks.Contains(aRequest)) {
|
||||
if (aRequest->IsWatch()) {
|
||||
if (mWatchingCallbacks.Contains(aRequest)) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
if (mPendingCallbacks.Contains(aRequest)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (mPendingCallbacks.Contains(aRequest)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1104,27 +1217,23 @@ Geolocation::HandleEvent(nsIDOMEvent* aEvent)
|
||||
|
||||
MOZ_ASSERT(XRE_IsContentProcess());
|
||||
ContentChild* cpc = ContentChild::GetSingleton();
|
||||
|
||||
if (!info.lockingProcesses().Contains(cpc->GetID())) {
|
||||
cpc->SendRemoveGeolocationListener();
|
||||
mService->StopDisconnectTimer();
|
||||
}
|
||||
} else {
|
||||
mService->SetDisconnectTimer();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mService->SetDisconnectTimer();
|
||||
|
||||
// We will unconditionally allow all the requests in the callbacks
|
||||
// because if a request is put into either of these two callbacks,
|
||||
// it means that it has been allowed before.
|
||||
// That's why when we resume them, we unconditionally allow them again.
|
||||
for (uint32_t i = 0, length = mWatchingCallbacks.Length(); i < length; ++i) {
|
||||
mWatchingCallbacks[i]->Allow(JS::UndefinedHandleValue);
|
||||
}
|
||||
|
||||
for (uint32_t i = 0, length = mPendingCallbacks.Length(); i < length; ++i) {
|
||||
mPendingCallbacks[i]->Allow(JS::UndefinedHandleValue);
|
||||
// We will unconditionally allow all the requests in the callbacks
|
||||
// because if a request is put into either of these two callbacks,
|
||||
// it means that it has been allowed before.
|
||||
// That's why when we resume them, we unconditionally allow them again.
|
||||
for (uint32_t i = 0, length = mWatchingCallbacks.Length(); i < length; ++i) {
|
||||
mWatchingCallbacks[i]->Allow(JS::UndefinedHandleValue);
|
||||
}
|
||||
for (uint32_t i = 0, length = mPendingCallbacks.Length(); i < length; ++i) {
|
||||
mPendingCallbacks[i]->Allow(JS::UndefinedHandleValue);
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
@ -1225,10 +1334,8 @@ Geolocation::Update(nsIDOMGeoPosition *aSomewhere)
|
||||
for (uint32_t i = 0; i < mWatchingCallbacks.Length(); i++) {
|
||||
mWatchingCallbacks[i]->Update(aSomewhere);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
Geolocation::NotifyError(uint16_t aErrorCode)
|
||||
{
|
||||
@ -1236,7 +1343,6 @@ Geolocation::NotifyError(uint16_t aErrorCode)
|
||||
Shutdown();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
mozilla::Telemetry::Accumulate(mozilla::Telemetry::GEOLOCATION_ERROR, true);
|
||||
|
||||
for (uint32_t i = mPendingCallbacks.Length(); i > 0; i--) {
|
||||
@ -1260,7 +1366,6 @@ Geolocation::IsAlreadyCleared(nsGeolocationRequest* aRequest)
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1272,7 +1377,6 @@ Geolocation::ClearPendingRequest(nsGeolocationRequest* aRequest)
|
||||
this->ClearWatch(aRequest->WatchId());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -1335,6 +1439,11 @@ Geolocation::GetCurrentPosition(GeoPositionCallback& callback,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (sGeoInitPending) {
|
||||
mPendingRequests.AppendElement(request);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return GetCurrentPositionReady(request);
|
||||
}
|
||||
|
||||
@ -1424,6 +1533,11 @@ Geolocation::WatchPosition(GeoPositionCallback& aCallback,
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (sGeoInitPending) {
|
||||
mPendingRequests.AppendElement(request);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return WatchPositionReady(request);
|
||||
}
|
||||
|
||||
|
@ -72,6 +72,9 @@ public:
|
||||
|
||||
nsresult Init();
|
||||
|
||||
void HandleMozsettingChanged(nsISupports* aSubject);
|
||||
void HandleMozsettingValue(const bool aValue);
|
||||
|
||||
// Management of the Geolocation objects
|
||||
void AddLocator(mozilla::dom::Geolocation* locator);
|
||||
void RemoveLocator(mozilla::dom::Geolocation* locator);
|
||||
|
@ -154,13 +154,14 @@ function checkInputURL()
|
||||
sendString("ttp://mozilla.org");
|
||||
checkValidApplies(element);
|
||||
|
||||
for (var i=0; i<13; ++i) {
|
||||
for (var i=0; i<10; ++i) {
|
||||
synthesizeKey("VK_BACK_SPACE", {});
|
||||
checkValidApplies(element);
|
||||
}
|
||||
|
||||
synthesizeKey("VK_BACK_SPACE", {});
|
||||
for (var i=0; i<4; ++i) {
|
||||
// "http://" is now invalid
|
||||
for (var i=0; i<7; ++i) {
|
||||
checkInvalidApplies(element);
|
||||
synthesizeKey("VK_BACK_SPACE", {});
|
||||
}
|
||||
|
@ -8,10 +8,6 @@
|
||||
#include <gtk/gtk.h>
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WIDGET_QT
|
||||
#include "nsQAppInstance.h"
|
||||
#endif
|
||||
|
||||
#include "ContentChild.h"
|
||||
|
||||
#include "BlobChild.h"
|
||||
@ -619,11 +615,6 @@ ContentChild::Init(MessageLoop* aIOLoop,
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WIDGET_QT
|
||||
// sigh, seriously
|
||||
nsQAppInstance::AddRef();
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_X11
|
||||
// Do this after initializing GDK, or GDK will install its own handler.
|
||||
XRE_InstallX11ErrorHandler();
|
||||
@ -1041,14 +1032,6 @@ ContentChild::InitXPCOM()
|
||||
global->SetInitialProcessData(data);
|
||||
}
|
||||
|
||||
// Loading the ServiceWorker configuration.
|
||||
ServiceWorkerConfiguration configuration;
|
||||
SendGetServiceWorkerConfiguration(&configuration);
|
||||
|
||||
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
|
||||
MOZ_ASSERT(swm);
|
||||
swm->LoadRegistrations(configuration.serviceWorkerRegistrations());
|
||||
|
||||
InitOnContentProcessCreated();
|
||||
}
|
||||
|
||||
@ -2642,6 +2625,15 @@ ContentChild::RecvAppInit()
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::RecvInitServiceWorkers(const ServiceWorkerConfiguration& aConfig)
|
||||
{
|
||||
RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
|
||||
MOZ_ASSERT(swm);
|
||||
swm->LoadRegistrations(aConfig.serviceWorkerRegistrations());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentChild::RecvLastPrivateDocShellDestroyed()
|
||||
{
|
||||
|
@ -457,6 +457,9 @@ public:
|
||||
|
||||
virtual bool RecvAppInit() override;
|
||||
|
||||
virtual bool
|
||||
RecvInitServiceWorkers(const ServiceWorkerConfiguration& aConfig) override;
|
||||
|
||||
virtual bool RecvLastPrivateDocShellDestroyed() override;
|
||||
|
||||
virtual bool RecvVolumes(InfallibleTArray<VolumeInfo>&& aVolumes) override;
|
||||
|
@ -2511,6 +2511,14 @@ ContentParent::InitInternal(ProcessPriority aInitialPriority,
|
||||
Unused << SendSetAudioSessionData(id, sessionName, iconPath);
|
||||
}
|
||||
#endif
|
||||
|
||||
RefPtr<ServiceWorkerRegistrar> swr = ServiceWorkerRegistrar::Get();
|
||||
MOZ_ASSERT(swr);
|
||||
|
||||
nsTArray<ServiceWorkerRegistrationData> registrations;
|
||||
swr->GetRegistrations(registrations);
|
||||
|
||||
Unused << SendInitServiceWorkers(ServiceWorkerConfiguration(registrations));
|
||||
}
|
||||
|
||||
bool
|
||||
@ -5485,18 +5493,6 @@ ContentParent::PermissionManagerRelease(const ContentParentId& aCpId,
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvGetServiceWorkerConfiguration(ServiceWorkerConfiguration* aConfig)
|
||||
{
|
||||
MOZ_ASSERT(XRE_IsParentProcess());
|
||||
|
||||
RefPtr<ServiceWorkerRegistrar> swr = ServiceWorkerRegistrar::Get();
|
||||
MOZ_ASSERT(swr);
|
||||
|
||||
swr->GetRegistrations(aConfig->serviceWorkerRegistrations());
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
ContentParent::RecvProfile(const nsCString& aProfile)
|
||||
{
|
||||
|
@ -1135,9 +1135,6 @@ private:
|
||||
virtual bool RecvUpdateDropEffect(const uint32_t& aDragAction,
|
||||
const uint32_t& aDropEffect) override;
|
||||
|
||||
virtual bool
|
||||
RecvGetServiceWorkerConfiguration(ServiceWorkerConfiguration* aConfig) override;
|
||||
|
||||
virtual bool RecvProfile(const nsCString& aProfile) override;
|
||||
|
||||
virtual bool RecvGetGraphicsDeviceInitData(DeviceInitData* aOut) override;
|
||||
|
@ -526,6 +526,11 @@ child:
|
||||
nsCString ID, nsCString vendor);
|
||||
async AppInit();
|
||||
|
||||
/**
|
||||
* Send ServiceWorkerRegistrationData to child process.
|
||||
*/
|
||||
async InitServiceWorkers(ServiceWorkerConfiguration aConfig);
|
||||
|
||||
// Notify child that last-pb-context-exited notification was observed
|
||||
async LastPrivateDocShellDestroyed();
|
||||
|
||||
@ -1084,12 +1089,6 @@ parent:
|
||||
async PContentPermissionRequest(PermissionRequest[] aRequests, Principal aPrincipal,
|
||||
TabId tabId);
|
||||
|
||||
/**
|
||||
* Send ServiceWorkerRegistrationData to child process.
|
||||
*/
|
||||
sync GetServiceWorkerConfiguration()
|
||||
returns (ServiceWorkerConfiguration aConfig);
|
||||
|
||||
async Profile(nsCString aProfile);
|
||||
|
||||
/**
|
||||
|
@ -168,7 +168,7 @@ if CONFIG['OS_ARCH'] != 'WINNT':
|
||||
|
||||
DEFINES['BIN_SUFFIX'] = '"%s"' % CONFIG['BIN_SUFFIX']
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gtk2', 'gonk', 'qt'):
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('android', 'gtk2', 'gonk'):
|
||||
DEFINES['MOZ_ENABLE_FREETYPE'] = True
|
||||
|
||||
if CONFIG['MOZ_TOOLKIT_SEARCH']:
|
||||
|
@ -78,6 +78,15 @@ FullscreenDeniedNotDescendant=Request for fullscreen was denied because requesti
|
||||
FullscreenDeniedNotFocusedTab=Request for fullscreen was denied because requesting element is not in the currently focused tab.
|
||||
RemovedFullscreenElement=Exited fullscreen because fullscreen element was removed from document.
|
||||
FocusedWindowedPluginWhileFullscreen=Exited fullscreen because windowed plugin was focused.
|
||||
PointerLockDeniedDisabled=Request for pointer lock was denied because Pointer Lock API is disabled by user preference.
|
||||
PointerLockDeniedInUse=Request for pointer lock was denied because the pointer is currently controlled by a different document.
|
||||
PointerLockDeniedNotInDocument=Request for pointer lock was denied because the requesting element is not in a document.
|
||||
PointerLockDeniedSandboxed=Request for pointer lock was denied because Pointer Lock API is restricted via sandbox.
|
||||
PointerLockDeniedHidden=Request for pointer lock was denied because the document is not visible.
|
||||
PointerLockDeniedNotFocused=Request for pointer lock was denied because the document is not focused.
|
||||
PointerLockDeniedMovedDocument=Request for pointer lock was denied because the requesting element has moved document.
|
||||
PointerLockDeniedNotInputDriven=Request for pointer lock was denied because Element.requestPointerLock() was not called from inside a short running user-generated event handler, and the document is not in full screen.
|
||||
PointerLockDeniedFailedToLock=Request for pointer lock was denied because the browser failed to lock the pointer.
|
||||
HTMLSyncXHRWarning=HTML parsing in XMLHttpRequest is not supported in the synchronous mode.
|
||||
InvalidRedirectChannelWarning=Unable to redirect to %S because the channel doesn’t implement nsIWritablePropertyBag2.
|
||||
ResponseTypeSyncXHRWarning=Use of XMLHttpRequest’s responseType attribute is no longer supported in the synchronous mode in window context.
|
||||
|
@ -160,6 +160,6 @@ TEST_DIRS += [
|
||||
'imptests',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3', 'cocoa', 'windows', 'android', 'qt'):
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] in ('gtk2', 'gtk3', 'cocoa', 'windows', 'android'):
|
||||
TEST_DIRS += ['plugins/test']
|
||||
|
||||
|
@ -77,10 +77,6 @@ else:
|
||||
SOURCES += [
|
||||
'nsPluginNativeWindowGtk.cpp',
|
||||
]
|
||||
elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'qt':
|
||||
UNIFIED_SOURCES += [
|
||||
'nsPluginNativeWindowQt.cpp',
|
||||
]
|
||||
else:
|
||||
UNIFIED_SOURCES += [
|
||||
'nsPluginNativeWindow.cpp',
|
||||
|
@ -1811,7 +1811,7 @@ _getvalue(NPP npp, NPNVariable variable, void *result)
|
||||
return NPERR_GENERIC_ERROR;
|
||||
#endif
|
||||
|
||||
#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)
|
||||
#if defined(XP_WIN) || defined(MOZ_WIDGET_GTK)
|
||||
case NPNVnetscapeWindow: {
|
||||
if (!npp || !npp->ndata)
|
||||
return NPERR_INVALID_INSTANCE_ERROR;
|
||||
@ -1860,10 +1860,6 @@ _getvalue(NPP npp, NPNVariable variable, void *result)
|
||||
*((NPNToolkitType*)result) = NPNVGtk2;
|
||||
#endif
|
||||
|
||||
#ifdef MOZ_WIDGET_QT
|
||||
/* Fake toolkit so flash plugin works */
|
||||
*((NPNToolkitType*)result) = NPNVGtk2;
|
||||
#endif
|
||||
if (*(NPNToolkitType*)result)
|
||||
return NPERR_NO_ERROR;
|
||||
|
||||
@ -1873,11 +1869,6 @@ _getvalue(NPP npp, NPNVariable variable, void *result)
|
||||
case NPNVSupportsXEmbedBool: {
|
||||
#ifdef MOZ_WIDGET_GTK
|
||||
*(NPBool*)result = true;
|
||||
#elif defined(MOZ_WIDGET_QT)
|
||||
// Desktop Flash fail to initialize if browser does not support NPNVSupportsXEmbedBool
|
||||
// even when wmode!=windowed, lets return fake support
|
||||
fprintf(stderr, "Fake support for XEmbed plugins in Qt port\n");
|
||||
*(NPBool*)result = true;
|
||||
#else
|
||||
*(NPBool*)result = false;
|
||||
#endif
|
||||
@ -1898,7 +1889,7 @@ _getvalue(NPP npp, NPNVariable variable, void *result)
|
||||
|
||||
case NPNVSupportsWindowless: {
|
||||
#if defined(XP_WIN) || defined(XP_MACOSX) || \
|
||||
(defined(MOZ_X11) && (defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)))
|
||||
(defined(MOZ_X11) && defined(MOZ_WIDGET_GTK))
|
||||
*(NPBool*)result = true;
|
||||
#else
|
||||
*(NPBool*)result = false;
|
||||
|
@ -763,7 +763,7 @@ NS_IMETHODIMP nsPluginInstanceOwner::GetNetscapeWindow(void *value)
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
#elif (defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)) && defined(MOZ_X11)
|
||||
#elif defined(MOZ_WIDGET_GTK) && defined(MOZ_X11)
|
||||
// X11 window managers want the toplevel window for WM_TRANSIENT_FOR.
|
||||
nsIWidget* win = mPluginFrame->GetNearestWidget();
|
||||
if (!win)
|
||||
@ -2616,8 +2616,6 @@ nsEventStatus nsPluginInstanceOwner::ProcessEvent(const WidgetGUIEvent& anEvent)
|
||||
}
|
||||
#ifdef MOZ_WIDGET_GTK
|
||||
Window root = GDK_ROOT_WINDOW();
|
||||
#elif defined(MOZ_WIDGET_QT)
|
||||
Window root = RootWindowOfScreen(DefaultScreenOfDisplay(mozilla::DefaultXDisplay()));
|
||||
#else
|
||||
Window root = None; // Could XQueryTree, but this is not important.
|
||||
#endif
|
||||
|
@ -46,12 +46,8 @@ class PuppetWidget;
|
||||
using mozilla::widget::PuppetWidget;
|
||||
|
||||
#ifdef MOZ_X11
|
||||
#ifdef MOZ_WIDGET_QT
|
||||
#include "gfxQtNativeRenderer.h"
|
||||
#else
|
||||
#include "gfxXlibNativeRenderer.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
class nsPluginInstanceOwner final : public nsIPluginInstanceOwner
|
||||
, public nsIDOMEventListener
|
||||
@ -395,12 +391,7 @@ private:
|
||||
int mLastMouseDownButtonType;
|
||||
|
||||
#ifdef MOZ_X11
|
||||
class Renderer
|
||||
#if defined(MOZ_WIDGET_QT)
|
||||
: public gfxQtNativeRenderer
|
||||
#else
|
||||
: public gfxXlibNativeRenderer
|
||||
#endif
|
||||
class Renderer : public gfxXlibNativeRenderer
|
||||
{
|
||||
public:
|
||||
Renderer(NPWindow* aWindow, nsPluginInstanceOwner* aInstanceOwner,
|
||||
|
@ -1,89 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:expandtab:shiftwidth=2:tabstop=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/. */
|
||||
|
||||
/**
|
||||
* This file is the Qt implementation of plugin native window.
|
||||
*/
|
||||
|
||||
#include "nsDebug.h"
|
||||
#include "nsPluginNativeWindow.h"
|
||||
#include "npapi.h"
|
||||
|
||||
/**
|
||||
* Qt implementation of plugin window
|
||||
*/
|
||||
class nsPluginNativeWindowQt : public nsPluginNativeWindow
|
||||
{
|
||||
public:
|
||||
nsPluginNativeWindowQt();
|
||||
virtual ~nsPluginNativeWindowQt();
|
||||
|
||||
virtual nsresult CallSetWindow(RefPtr<nsNPAPIPluginInstance> &aPluginInstance);
|
||||
private:
|
||||
|
||||
NPSetWindowCallbackStruct mWsInfo;
|
||||
};
|
||||
|
||||
nsPluginNativeWindowQt::nsPluginNativeWindowQt() : nsPluginNativeWindow()
|
||||
{
|
||||
//Initialize member variables
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,"\n\n\nCreating plugin native window %p\n\n\n", (void *) this);
|
||||
#endif
|
||||
window = nullptr;
|
||||
x = 0;
|
||||
y = 0;
|
||||
width = 0;
|
||||
height = 0;
|
||||
memset(&clipRect, 0, sizeof(clipRect));
|
||||
ws_info = &mWsInfo;
|
||||
type = NPWindowTypeWindow;
|
||||
mWsInfo.type = 0;
|
||||
#if defined(MOZ_X11)
|
||||
mWsInfo.display = nullptr;
|
||||
mWsInfo.visual = nullptr;
|
||||
mWsInfo.colormap = 0;
|
||||
mWsInfo.depth = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
nsPluginNativeWindowQt::~nsPluginNativeWindowQt()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
fprintf(stderr,"\n\n\nDestoying plugin native window %p\n\n\n", (void *) this);
|
||||
#endif
|
||||
}
|
||||
|
||||
nsresult PLUG_NewPluginNativeWindow(nsPluginNativeWindow **aPluginNativeWindow)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aPluginNativeWindow);
|
||||
*aPluginNativeWindow = new nsPluginNativeWindowQt();
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult PLUG_DeletePluginNativeWindow(nsPluginNativeWindow * aPluginNativeWindow)
|
||||
{
|
||||
NS_ENSURE_ARG_POINTER(aPluginNativeWindow);
|
||||
nsPluginNativeWindowQt *p = (nsPluginNativeWindowQt *)aPluginNativeWindow;
|
||||
delete p;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult nsPluginNativeWindowQt::CallSetWindow(RefPtr<nsNPAPIPluginInstance> &aPluginInstance)
|
||||
{
|
||||
if (aPluginInstance) {
|
||||
if (type == NPWindowTypeWindow) {
|
||||
return NS_ERROR_FAILURE;
|
||||
} // NPWindowTypeWindow
|
||||
aPluginInstance->SetWindow(this);
|
||||
}
|
||||
else if (mPluginInstance)
|
||||
mPluginInstance->SetWindow(nullptr);
|
||||
|
||||
SetPluginInstance(aPluginInstance);
|
||||
return NS_OK;
|
||||
}
|
@ -841,7 +841,7 @@ nsresult nsPluginStreamListenerPeer::ServeStreamAsFile(nsIRequest *request,
|
||||
if (owner) {
|
||||
NPWindow* window = nullptr;
|
||||
owner->GetWindow(window);
|
||||
#if (MOZ_WIDGET_GTK == 2) || defined(MOZ_WIDGET_QT)
|
||||
#if (MOZ_WIDGET_GTK == 2)
|
||||
// Should call GetPluginPort() here.
|
||||
// This part is copied from nsPluginInstanceOwner::GetPluginPort().
|
||||
nsCOMPtr<nsIWidget> widget;
|
||||
|
@ -1,16 +0,0 @@
|
||||
/* -*- Mode: C++; tab-width: 3; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef PluginHelperQt_h_
|
||||
#define PluginHelperQt_h_
|
||||
|
||||
class PluginHelperQt
|
||||
{
|
||||
public:
|
||||
static bool AnswerProcessSomeEvents();
|
||||
};
|
||||
|
||||
#endif // PluginHelperQt_h_
|
@ -54,9 +54,6 @@ using namespace std;
|
||||
#include <gdk/gdk.h>
|
||||
#include "gtk2xtbin.h"
|
||||
|
||||
#elif defined(MOZ_WIDGET_QT)
|
||||
#undef KeyPress
|
||||
#undef KeyRelease
|
||||
#elif defined(OS_WIN)
|
||||
|
||||
#include <windows.h>
|
||||
@ -1386,8 +1383,6 @@ PluginInstanceChild::AnswerNPP_SetWindow(const NPRemoteWindow& aWindow)
|
||||
|
||||
#elif defined(ANDROID)
|
||||
// TODO: Need Android impl
|
||||
#elif defined(MOZ_WIDGET_QT)
|
||||
// TODO: Need QT-nonX impl
|
||||
#elif defined(MOZ_WIDGET_UIKIT)
|
||||
// Don't care
|
||||
#else
|
||||
|
@ -287,9 +287,6 @@ PluginInstanceParent::AnswerNPN_GetValue_NPNVnetscapeWindow(NativeWindowHandle*
|
||||
#elif defined(ANDROID)
|
||||
// TODO: Need Android impl
|
||||
int id;
|
||||
#elif defined(MOZ_WIDGET_QT)
|
||||
// TODO: Need Qt non X impl
|
||||
int id;
|
||||
#else
|
||||
#warning Implement me
|
||||
#endif
|
||||
|
@ -102,7 +102,7 @@ struct NPRemoteWindow
|
||||
typedef HWND NativeWindowHandle;
|
||||
#elif defined(MOZ_X11)
|
||||
typedef XID NativeWindowHandle;
|
||||
#elif defined(XP_DARWIN) || defined(ANDROID) || defined(MOZ_WIDGET_QT)
|
||||
#elif defined(XP_DARWIN) || defined(ANDROID)
|
||||
typedef intptr_t NativeWindowHandle; // never actually used, will always be 0
|
||||
#else
|
||||
#error Need NativeWindowHandle for this platform
|
||||
|
@ -4,12 +4,6 @@
|
||||
* 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/. */
|
||||
|
||||
#ifdef MOZ_WIDGET_QT
|
||||
#include <QtCore/QTimer>
|
||||
#include "nsQAppInstance.h"
|
||||
#include "NestedLoopTimer.h"
|
||||
#endif
|
||||
|
||||
#include "mozilla/plugins/PluginModuleChild.h"
|
||||
|
||||
/* This must occur *after* plugins/PluginModuleChild.h to avoid typedefs conflicts. */
|
||||
@ -73,12 +67,6 @@ namespace {
|
||||
PluginModuleChild* gChromeInstance = nullptr;
|
||||
} // namespace
|
||||
|
||||
#ifdef MOZ_WIDGET_QT
|
||||
typedef void (*_gtk_init_fn)(int argc, char **argv);
|
||||
static _gtk_init_fn s_gtk_init = nullptr;
|
||||
static PRLibrary *sGtkLib = nullptr;
|
||||
#endif
|
||||
|
||||
#ifdef XP_WIN
|
||||
// Hooking CreateFileW for protected-mode magic
|
||||
static WindowsDllInterceptor sKernel32Intercept;
|
||||
@ -131,8 +119,6 @@ PluginModuleChild::PluginModuleChild(bool aIsChrome)
|
||||
, mGetEntryPointsFunc(0)
|
||||
#elif defined(MOZ_WIDGET_GTK)
|
||||
, mNestedLoopTimerId(0)
|
||||
#elif defined(MOZ_WIDGET_QT)
|
||||
, mNestedLoopTimerObject(0)
|
||||
#endif
|
||||
#ifdef OS_WIN
|
||||
, mNestedEventHook(nullptr)
|
||||
@ -325,6 +311,7 @@ PluginModuleChild::InitForChrome(const std::string& aPluginFilename,
|
||||
}
|
||||
|
||||
#if defined(MOZ_WIDGET_GTK)
|
||||
|
||||
typedef void (*GObjectDisposeFn)(GObject*);
|
||||
typedef gboolean (*GtkWidgetScrollEventFn)(GtkWidget*, GdkEventScroll*);
|
||||
typedef void (*GtkPlugEmbeddedFn)(GtkPlug*);
|
||||
@ -548,26 +535,6 @@ PluginModuleChild::ExitedCxxStack()
|
||||
g_source_remove(mNestedLoopTimerId);
|
||||
mNestedLoopTimerId = 0;
|
||||
}
|
||||
#elif defined (MOZ_WIDGET_QT)
|
||||
|
||||
void
|
||||
PluginModuleChild::EnteredCxxStack()
|
||||
{
|
||||
MOZ_ASSERT(mNestedLoopTimerObject == nullptr,
|
||||
"previous timer not descheduled");
|
||||
mNestedLoopTimerObject = new NestedLoopTimer(this);
|
||||
QTimer::singleShot(kNestedLoopDetectorIntervalMs,
|
||||
mNestedLoopTimerObject, SLOT(timeOut()));
|
||||
}
|
||||
|
||||
void
|
||||
PluginModuleChild::ExitedCxxStack()
|
||||
{
|
||||
MOZ_ASSERT(mNestedLoopTimerObject != nullptr,
|
||||
"nested loop timeout not scheduled");
|
||||
delete mNestedLoopTimerObject;
|
||||
mNestedLoopTimerObject = nullptr;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@ -628,19 +595,6 @@ PluginModuleChild::InitGraphics()
|
||||
real_gtk_plug_embedded = *embedded;
|
||||
*embedded = wrap_gtk_plug_embedded;
|
||||
|
||||
#elif defined(MOZ_WIDGET_QT)
|
||||
nsQAppInstance::AddRef();
|
||||
// Work around plugins that don't interact well without gtk initialized
|
||||
// see bug 566845
|
||||
#if defined(MOZ_X11)
|
||||
if (!sGtkLib)
|
||||
sGtkLib = PR_LoadLibrary("libgtk-x11-2.0.so.0");
|
||||
#endif
|
||||
if (sGtkLib) {
|
||||
s_gtk_init = (_gtk_init_fn)PR_FindFunctionSymbol(sGtkLib, "gtk_init");
|
||||
if (s_gtk_init)
|
||||
s_gtk_init(0, 0);
|
||||
}
|
||||
#else
|
||||
// may not be necessary on all platforms
|
||||
#endif
|
||||
@ -654,15 +608,6 @@ PluginModuleChild::InitGraphics()
|
||||
void
|
||||
PluginModuleChild::DeinitGraphics()
|
||||
{
|
||||
#ifdef MOZ_WIDGET_QT
|
||||
nsQAppInstance::Release();
|
||||
if (sGtkLib) {
|
||||
PR_UnloadLibrary(sGtkLib);
|
||||
sGtkLib = nullptr;
|
||||
s_gtk_init = nullptr;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(MOZ_X11) && defined(NS_FREE_PERMANENT_DATA)
|
||||
// We free some data off of XDisplay close hooks, ensure they're
|
||||
// run. Closing the display is pretty scary, so we only do it to
|
||||
@ -1149,7 +1094,7 @@ _getvalue(NPP aNPP,
|
||||
switch (aVariable) {
|
||||
// Copied from nsNPAPIPlugin.cpp
|
||||
case NPNVToolkit:
|
||||
#if defined(MOZ_WIDGET_GTK) || defined(MOZ_WIDGET_QT)
|
||||
#if defined(MOZ_WIDGET_GTK)
|
||||
*static_cast<NPNToolkitType*>(aValue) = NPNVGtk2;
|
||||
return NPERR_NO_ERROR;
|
||||
#endif
|
||||
|
@ -52,11 +52,6 @@ class PCrashReporterChild;
|
||||
|
||||
namespace plugins {
|
||||
|
||||
#ifdef MOZ_WIDGET_QT
|
||||
class NestedLoopTimer;
|
||||
static const int kNestedLoopDetectorIntervalMs = 90;
|
||||
#endif
|
||||
|
||||
class PluginInstanceChild;
|
||||
|
||||
class PluginModuleChild : public PPluginModuleChild
|
||||
@ -261,10 +256,6 @@ private:
|
||||
static gboolean DetectNestedEventLoop(gpointer data);
|
||||
static gboolean ProcessBrowserEvents(gpointer data);
|
||||
|
||||
virtual void EnteredCxxStack() override;
|
||||
virtual void ExitedCxxStack() override;
|
||||
#elif defined(MOZ_WIDGET_QT)
|
||||
|
||||
virtual void EnteredCxxStack() override;
|
||||
virtual void ExitedCxxStack() override;
|
||||
#endif
|
||||
@ -328,8 +319,6 @@ private:
|
||||
// MessagePumpForUI.
|
||||
int mTopLoopDepth;
|
||||
# endif
|
||||
#elif defined (MOZ_WIDGET_QT)
|
||||
NestedLoopTimer *mNestedLoopTimerObject;
|
||||
#endif
|
||||
|
||||
public: // called by PluginInstanceChild
|
||||
|
@ -4,10 +4,6 @@
|
||||
* 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/. */
|
||||
|
||||
#ifdef MOZ_WIDGET_QT
|
||||
#include "PluginHelperQt.h"
|
||||
#endif
|
||||
|
||||
#include "mozilla/plugins/PluginModuleParent.h"
|
||||
|
||||
#include "base/process_util.h"
|
||||
@ -2859,18 +2855,7 @@ PluginModuleParent::ContentsScaleFactorChanged(NPP instance, double aContentsSca
|
||||
}
|
||||
#endif // #if defined(XP_MACOSX)
|
||||
|
||||
#if defined(MOZ_WIDGET_QT)
|
||||
bool
|
||||
PluginModuleParent::AnswerProcessSomeEvents()
|
||||
{
|
||||
PLUGIN_LOG_DEBUG(("Spinning mini nested loop ..."));
|
||||
PluginHelperQt::AnswerProcessSomeEvents();
|
||||
PLUGIN_LOG_DEBUG(("... quitting mini nested loop"));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#elif defined(XP_MACOSX)
|
||||
#if defined(XP_MACOSX)
|
||||
bool
|
||||
PluginModuleParent::AnswerProcessSomeEvents()
|
||||
{
|
||||
|
@ -90,17 +90,10 @@ PresentationConnection::Init()
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsILoadGroup> loadGroup;
|
||||
GetLoadGroup(getter_AddRefs(loadGroup));
|
||||
if(NS_WARN_IF(!loadGroup)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
rv = loadGroup->AddRequest(this, nullptr);
|
||||
rv = AddIntoLoadGroup();
|
||||
if(NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return false;
|
||||
}
|
||||
mWeakLoadGroup = do_GetWeakReference(loadGroup);
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -117,11 +110,8 @@ PresentationConnection::Shutdown()
|
||||
nsresult rv = service->UnregisterSessionListener(mId, mRole);
|
||||
NS_WARN_IF(NS_FAILED(rv));
|
||||
|
||||
nsCOMPtr<nsILoadGroup> loadGroup = do_QueryReferent(mWeakLoadGroup);
|
||||
if (loadGroup) {
|
||||
loadGroup->RemoveRequest(this, nullptr, NS_OK);
|
||||
mWeakLoadGroup = nullptr;
|
||||
}
|
||||
rv = RemoveFromLoadGroup();
|
||||
NS_WARN_IF(NS_FAILED(rv));
|
||||
}
|
||||
|
||||
/* virtual */ void
|
||||
@ -176,20 +166,31 @@ PresentationConnection::Send(const nsAString& aData,
|
||||
void
|
||||
PresentationConnection::Close(ErrorResult& aRv)
|
||||
{
|
||||
// It only works when the state is CONNECTED.
|
||||
if (NS_WARN_IF(mState != PresentationConnectionState::Connected)) {
|
||||
// It only works when the state is CONNECTED or CONNECTING.
|
||||
if (NS_WARN_IF(mState != PresentationConnectionState::Connected &&
|
||||
mState != PresentationConnectionState::Connecting)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// TODO Bug 1210340 - Support close semantics.
|
||||
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
|
||||
nsCOMPtr<nsIPresentationService> service =
|
||||
do_GetService(PRESENTATION_SERVICE_CONTRACTID);
|
||||
if(NS_WARN_IF(!service)) {
|
||||
aRv.Throw(NS_ERROR_DOM_OPERATION_ERR);
|
||||
return;
|
||||
}
|
||||
|
||||
NS_WARN_IF(NS_FAILED(
|
||||
service->CloseSession(mId,
|
||||
mRole,
|
||||
nsIPresentationService::CLOSED_REASON_CLOSED)));
|
||||
}
|
||||
|
||||
void
|
||||
PresentationConnection::Terminate(ErrorResult& aRv)
|
||||
{
|
||||
// It only works when the state is CONNECTED.
|
||||
if (NS_WARN_IF(mState != PresentationConnectionState::Connected)) {
|
||||
// It only works when the state is CONNECTED or CONNECTING.
|
||||
if (NS_WARN_IF(mState != PresentationConnectionState::Connected &&
|
||||
mState != PresentationConnectionState::Connecting)) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -276,7 +277,9 @@ PresentationConnection::ProcessStateChanged(nsresult aReason)
|
||||
CopyUTF8toUTF16(message, errorMsg);
|
||||
}
|
||||
|
||||
return DispatchConnectionClosedEvent(reason, errorMsg);
|
||||
NS_WARN_IF(NS_FAILED(DispatchConnectionClosedEvent(reason, errorMsg)));
|
||||
|
||||
return RemoveFromLoadGroup();
|
||||
}
|
||||
case PresentationConnectionState::Terminated: {
|
||||
nsCOMPtr<nsIPresentationService> service =
|
||||
@ -292,7 +295,9 @@ PresentationConnection::ProcessStateChanged(nsresult aReason)
|
||||
|
||||
RefPtr<AsyncEventDispatcher> asyncDispatcher =
|
||||
new AsyncEventDispatcher(this, NS_LITERAL_STRING("terminate"), false);
|
||||
return asyncDispatcher->PostDOMEvent();
|
||||
NS_WARN_IF(NS_FAILED(asyncDispatcher->PostDOMEvent()));
|
||||
|
||||
return RemoveFromLoadGroup();
|
||||
}
|
||||
default:
|
||||
MOZ_CRASH("Unknown presentation session state.");
|
||||
@ -475,3 +480,42 @@ PresentationConnection::SetLoadFlags(nsLoadFlags aLoadFlags)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresentationConnection::AddIntoLoadGroup()
|
||||
{
|
||||
// Avoid adding to loadgroup multiple times
|
||||
if (mWeakLoadGroup) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsILoadGroup> loadGroup;
|
||||
nsresult rv = GetLoadGroup(getter_AddRefs(loadGroup));
|
||||
if(NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = loadGroup->AddRequest(this, nullptr);
|
||||
if(NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
mWeakLoadGroup = do_GetWeakReference(loadGroup);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsresult
|
||||
PresentationConnection::RemoveFromLoadGroup()
|
||||
{
|
||||
if (!mWeakLoadGroup) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsILoadGroup> loadGroup = do_QueryReferent(mWeakLoadGroup);
|
||||
if (loadGroup) {
|
||||
mWeakLoadGroup = nullptr;
|
||||
return loadGroup->RemoveRequest(this, nullptr, NS_OK);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -79,6 +79,10 @@ private:
|
||||
|
||||
nsresult ProcessConnectionWentAway();
|
||||
|
||||
nsresult AddIntoLoadGroup();
|
||||
|
||||
nsresult RemoveFromLoadGroup();
|
||||
|
||||
nsString mId;
|
||||
uint8_t mRole;
|
||||
PresentationConnectionState mState;
|
||||
|
@ -105,9 +105,6 @@ function testSendMessage() {
|
||||
});
|
||||
}
|
||||
|
||||
// Currently, PresentationSessionInfo::NotifyTransportClosed only set the state to
|
||||
// STATE_CLOSED. So, when sender call connection.terminate(), we can only get STATE_CLOSED
|
||||
// at receiver side. This should be fixed in bu 1210340.
|
||||
function testConnectionClosed() {
|
||||
return new Promise(function(aResolve, aReject) {
|
||||
info('Receiver: --- testConnectionClosed ---');
|
||||
@ -116,7 +113,7 @@ function testConnectionClosed() {
|
||||
is(connection.state, "closed", "Receiver: Connection should be closed.");
|
||||
aResolve();
|
||||
};
|
||||
command('forward-command', JSON.stringify({ name: 'ready-to-terminate' }));
|
||||
command('forward-command', JSON.stringify({ name: 'ready-to-close' }));
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -121,15 +121,15 @@ function testIncomingMessage() {
|
||||
});
|
||||
}
|
||||
|
||||
function testTerminateConnection() {
|
||||
function testCloseConnection() {
|
||||
return new Promise(function(aResolve, aReject) {
|
||||
connection.onterminate = function() {
|
||||
connection.onterminate = null;
|
||||
is(connection.state, "terminated", "Connection should be terminated.");
|
||||
connection.onclose = function() {
|
||||
connection.onclose = null;
|
||||
is(connection.state, "closed", "Connection should be closed.");
|
||||
aResolve();
|
||||
};
|
||||
|
||||
connection.terminate();
|
||||
connection.close();
|
||||
});
|
||||
}
|
||||
|
||||
@ -139,7 +139,7 @@ then(testConnectionAvailableSameOriginInnerIframe).
|
||||
then(testConnectionUnavailableDiffOriginInnerIframe).
|
||||
then(testConnectionListSameObject).
|
||||
then(testIncomingMessage).
|
||||
then(testTerminateConnection).
|
||||
then(testCloseConnection).
|
||||
then(finish);
|
||||
|
||||
</script>
|
||||
|
@ -177,17 +177,17 @@ function testIncomingMessage() {
|
||||
});
|
||||
}
|
||||
|
||||
function testTerminateConnection() {
|
||||
function testCloseConnection() {
|
||||
return new Promise(function(aResolve, aReject) {
|
||||
info('Sender: --- testTerminateConnection ---');
|
||||
connection.onterminate = function() {
|
||||
connection.onterminate = null;
|
||||
is(connection.state, "terminated", "Sender: Connection should be terminated.");
|
||||
info('Sender: --- testCloseConnection ---');
|
||||
connection.onclose = function() {
|
||||
connection.onclose = null;
|
||||
is(connection.state, "closed", "Sender: Connection should be closed.");
|
||||
aResolve();
|
||||
};
|
||||
gScript.addMessageListener('ready-to-terminate', function onReadyToTerminate() {
|
||||
gScript.removeMessageListener('ready-to-terminate', onReadyToTerminate);
|
||||
connection.terminate();
|
||||
gScript.addMessageListener('ready-to-close', function onReadyToClose() {
|
||||
gScript.removeMessageListener('ready-to-close', onReadyToClose);
|
||||
connection.close();
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -208,7 +208,7 @@ function runTests() {
|
||||
.then(testStartConnection)
|
||||
.then(testSendMessage)
|
||||
.then(testIncomingMessage)
|
||||
.then(testTerminateConnection);
|
||||
.then(testCloseConnection);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
@ -184,17 +184,17 @@ function testIncomingMessage() {
|
||||
});
|
||||
}
|
||||
|
||||
function testTerminateConnection() {
|
||||
function testCloseConnection() {
|
||||
return new Promise(function(aResolve, aReject) {
|
||||
info('Sender: --- testTerminateConnection ---');
|
||||
connection.onterminate = function() {
|
||||
connection.onterminate = null;
|
||||
is(connection.state, "terminated", "Sender: Connection should be terminated.");
|
||||
info('Sender: --- testCloseConnection ---');
|
||||
connection.onclose = function() {
|
||||
connection.onclose = null;
|
||||
is(connection.state, "closed", "Sender: Connection should be closed.");
|
||||
aResolve();
|
||||
};
|
||||
gScript.addMessageListener('ready-to-terminate', function onReadyToTerminate() {
|
||||
gScript.removeMessageListener('ready-to-terminate', onReadyToTerminate);
|
||||
connection.terminate();
|
||||
gScript.addMessageListener('ready-to-close', function onReadyToClose() {
|
||||
gScript.removeMessageListener('ready-to-close', onReadyToClose);
|
||||
connection.close();
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -215,7 +215,7 @@ function runTests() {
|
||||
.then(testStartConnection)
|
||||
.then(testSendMessage)
|
||||
.then(testIncomingMessage)
|
||||
.then(testTerminateConnection);
|
||||
.then(testCloseConnection);
|
||||
}
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
@ -157,20 +157,20 @@ function testIncomingMessage() {
|
||||
});
|
||||
}
|
||||
|
||||
function testTerminateConnection() {
|
||||
function testCloseConnection() {
|
||||
return new Promise(function(aResolve, aReject) {
|
||||
frameScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
|
||||
frameScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
|
||||
info("The data transport is closed. " + aReason);
|
||||
});
|
||||
|
||||
connection.onterminate = function() {
|
||||
connection.onterminate = null;
|
||||
is(connection.state, "terminated", "Connection should be terminated.");
|
||||
connection.onclose = function() {
|
||||
connection.onclose = null;
|
||||
is(connection.state, "closed", "Connection should be closed.");
|
||||
aResolve();
|
||||
};
|
||||
|
||||
connection.terminate();
|
||||
connection.close();
|
||||
});
|
||||
}
|
||||
|
||||
@ -192,7 +192,7 @@ function runTests() {
|
||||
then(testStartConnection).
|
||||
then(testSend).
|
||||
then(testIncomingMessage).
|
||||
then(testTerminateConnection).
|
||||
then(testCloseConnection).
|
||||
then(teardown);
|
||||
}
|
||||
|
||||
|
@ -151,20 +151,20 @@ function testIncomingMessage() {
|
||||
});
|
||||
}
|
||||
|
||||
function testTerminateConnection() {
|
||||
function testCloseConnection() {
|
||||
return new Promise(function(aResolve, aReject) {
|
||||
gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
|
||||
gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
|
||||
info("The data transport is closed. " + aReason);
|
||||
});
|
||||
|
||||
connection.onterminate = function() {
|
||||
connection.onterminate = null;
|
||||
is(connection.state, "terminated", "Connection should be terminated.");
|
||||
connection.onclose = function() {
|
||||
connection.onclose = null;
|
||||
is(connection.state, "closed", "Connection should be closed.");
|
||||
aResolve();
|
||||
};
|
||||
|
||||
connection.terminate();
|
||||
connection.close();
|
||||
});
|
||||
}
|
||||
|
||||
@ -185,7 +185,7 @@ function runTests() {
|
||||
then(testStartConnection).
|
||||
then(testSend).
|
||||
then(testIncomingMessage).
|
||||
then(testTerminateConnection).
|
||||
then(testCloseConnection).
|
||||
then(teardown);
|
||||
}
|
||||
|
||||
|
@ -101,20 +101,20 @@ function testStartConnection() {
|
||||
});
|
||||
}
|
||||
|
||||
function testTerminateConnection() {
|
||||
function testCloseConnection() {
|
||||
return new Promise(function(aResolve, aReject) {
|
||||
gScript.addMessageListener('data-transport-closed', function dataTransportClosedHandler(aReason) {
|
||||
gScript.removeMessageListener('data-transport-closed', dataTransportClosedHandler);
|
||||
info("The data transport is closed. " + aReason);
|
||||
});
|
||||
|
||||
connection.onterminate = function() {
|
||||
connection.onterminate = null;
|
||||
is(connection.state, "terminated", "Connection should be terminated.");
|
||||
connection.onclose = function() {
|
||||
connection.onclose = null;
|
||||
is(connection.state, "closed", "Connection should be closed.");
|
||||
aResolve();
|
||||
};
|
||||
|
||||
connection.terminate();
|
||||
connection.close();
|
||||
});
|
||||
}
|
||||
|
||||
@ -134,7 +134,7 @@ function runTests() {
|
||||
|
||||
testSetup().
|
||||
then(testStartConnection).
|
||||
then(testTerminateConnection).
|
||||
then(testCloseConnection).
|
||||
then(teardown);
|
||||
}
|
||||
|
||||
|
@ -648,7 +648,7 @@ nsCSPContext::SetRequestContext(nsIDOMDocument* aDOMDocument,
|
||||
doc->SetHasCSP(true);
|
||||
}
|
||||
else {
|
||||
NS_WARNING("No Document in SetRequestContext; can not query loadgroup; sending reports may fail.");
|
||||
CSPCONTEXTLOG(("No Document in SetRequestContext; can not query loadgroup; sending reports may fail."));
|
||||
mLoadingPrincipal = aPrincipal;
|
||||
mLoadingPrincipal->GetURI(getter_AddRefs(mSelfURI));
|
||||
// if no document is available, then it also does not make sense to queue console messages
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user