зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to autoland
This commit is contained in:
Коммит
2178a22de4
|
@ -1414,6 +1414,22 @@ Accessible::SetCurValue(double aValue)
|
|||
role
|
||||
Accessible::ARIATransformRole(role aRole)
|
||||
{
|
||||
// Beginning with ARIA 1.1, user agents are expected to use the native host
|
||||
// language role of the element when the region role is used without a name.
|
||||
// https://rawgit.com/w3c/aria/master/core-aam/core-aam.html#role-map-region
|
||||
//
|
||||
// XXX: While the name computation algorithm can be non-trivial in the general
|
||||
// case, it should not be especially bad here: If the author hasn't used the
|
||||
// region role, this calculation won't occur. And the region role's name
|
||||
// calculation rule excludes name from content. That said, this use case is
|
||||
// another example of why we should consider caching the accessible name. See:
|
||||
// https://bugzilla.mozilla.org/show_bug.cgi?id=1378235.
|
||||
if (aRole == roles::REGION) {
|
||||
nsAutoString name;
|
||||
Name(name);
|
||||
return name.IsEmpty() ? NativeRole() : aRole;
|
||||
}
|
||||
|
||||
// XXX: these unfortunate exceptions don't fit into the ARIA table. This is
|
||||
// where the accessible role depends on both the role and ARIA state.
|
||||
if (aRole == roles::PUSHBUTTON) {
|
||||
|
|
|
@ -4,10 +4,10 @@
|
|||
* 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 "mozilla/a11y/Compatibility.h"
|
||||
#include "mozilla/a11y/PlatformChild.h"
|
||||
#include "mozilla/mscom/EnsureMTA.h"
|
||||
#include "mozilla/mscom/InterceptorLog.h"
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
|
||||
#include "Accessible2.h"
|
||||
#include "Accessible2_2.h"
|
||||
|
@ -49,20 +49,7 @@ PlatformChild::PlatformChild()
|
|||
, mMiscTypelib(mozilla::mscom::RegisterTypelib(L"Accessible.tlb"))
|
||||
, mSdnTypelib(mozilla::mscom::RegisterTypelib(L"AccessibleMarshal.dll"))
|
||||
{
|
||||
// The manifest for 32-bit Windows is embedded with resource ID 32.
|
||||
// The manifest for 64-bit Windows is embedded with resource ID 64.
|
||||
// Beginning with Windows 10 Creators Update, 32-bit builds use the 64-bit
|
||||
// manifest.
|
||||
WORD actCtxResourceId;
|
||||
#if defined(HAVE_64BIT_BUILD)
|
||||
actCtxResourceId = 64;
|
||||
#else
|
||||
if (IsWin10CreatorsUpdateOrLater()) {
|
||||
actCtxResourceId = 64;
|
||||
} else {
|
||||
actCtxResourceId = 32;
|
||||
}
|
||||
#endif
|
||||
WORD actCtxResourceId = Compatibility::GetActCtxResourceId();
|
||||
|
||||
mozilla::mscom::MTADeletePtr<mozilla::mscom::ActivationContextRegion> tmpActCtxMTA;
|
||||
mozilla::mscom::EnsureMTA([actCtxResourceId, &tmpActCtxMTA]() -> void {
|
||||
|
|
|
@ -222,17 +222,12 @@ AccessibleHandler::ReadHandlerPayload(IStream* aStream, REFIID aIid)
|
|||
return S_OK;
|
||||
}
|
||||
|
||||
long pid = static_cast<long>(::GetCurrentProcessId());
|
||||
|
||||
RefPtr<IHandlerControl> ctl;
|
||||
HRESULT hr = gControlFactory.CreateInstance(nullptr, IID_IHandlerControl,
|
||||
getter_AddRefs(ctl));
|
||||
if (SUCCEEDED(hr)) {
|
||||
hr = mCachedData.mGeckoBackChannel->put_HandlerControl(pid, ctl);
|
||||
MOZ_ASSERT(SUCCEEDED(hr));
|
||||
RefPtr<AccessibleHandlerControl> ctl(gControlFactory.GetOrCreateSingleton());
|
||||
if (!ctl) {
|
||||
return E_OUTOFMEMORY;
|
||||
}
|
||||
|
||||
return hr;
|
||||
return ctl->Register(WrapNotNull(mCachedData.mGeckoBackChannel));
|
||||
}
|
||||
|
||||
REFIID
|
||||
|
|
|
@ -132,7 +132,8 @@ AccessibleHandlerControl::Create(AccessibleHandlerControl** aOutObject)
|
|||
}
|
||||
|
||||
AccessibleHandlerControl::AccessibleHandlerControl()
|
||||
: mCacheGen(0)
|
||||
: mIsRegistered(false)
|
||||
, mCacheGen(0)
|
||||
, mIA2Proxy(mscom::RegisterProxy(L"ia2marshal.dll"))
|
||||
, mHandlerProxy(mscom::RegisterProxy())
|
||||
{
|
||||
|
@ -189,5 +190,19 @@ AccessibleHandlerControl::GetHandlerTypeInfo(ITypeInfo** aOutTypeInfo)
|
|||
aOutTypeInfo);
|
||||
}
|
||||
|
||||
HRESULT
|
||||
AccessibleHandlerControl::Register(NotNull<IGeckoBackChannel*> aGecko)
|
||||
{
|
||||
if (mIsRegistered) {
|
||||
return S_OK;
|
||||
}
|
||||
|
||||
long pid = static_cast<long>(::GetCurrentProcessId());
|
||||
HRESULT hr = aGecko->put_HandlerControl(pid, this);
|
||||
mIsRegistered = SUCCEEDED(hr);
|
||||
MOZ_ASSERT(mIsRegistered);
|
||||
return hr;
|
||||
}
|
||||
|
||||
} // namespace a11y
|
||||
} // namespace mozilla
|
||||
|
|
|
@ -71,10 +71,13 @@ public:
|
|||
|
||||
HRESULT GetHandlerTypeInfo(ITypeInfo** aOutTypeInfo);
|
||||
|
||||
HRESULT Register(NotNull<IGeckoBackChannel*> aGecko);
|
||||
|
||||
private:
|
||||
AccessibleHandlerControl();
|
||||
~AccessibleHandlerControl() = default;
|
||||
|
||||
bool mIsRegistered;
|
||||
uint32_t mCacheGen;
|
||||
detail::TextChange mTextChange;
|
||||
UniquePtr<mscom::RegisteredProxy> mIA2Proxy;
|
||||
|
|
|
@ -798,7 +798,7 @@ ConvertToNSArray(nsTArray<ProxyAccessible*>& aArray)
|
|||
if (roleAtom == nsGkAtoms::note_)
|
||||
return @"AXDocumentNote";
|
||||
if (roleAtom == nsGkAtoms::region)
|
||||
return @"AXLandmarkRegion";
|
||||
return mRole == roles::REGION ? @"AXLandmarkRegion" : nil;
|
||||
if (roleAtom == nsGkAtoms::status)
|
||||
return @"AXApplicationStatus";
|
||||
if (roleAtom == nsGkAtoms::tabpanel)
|
||||
|
|
|
@ -54,7 +54,11 @@
|
|||
testRole("aria_progressbar", ROLE_PROGRESSBAR);
|
||||
testRole("aria_radio", ROLE_RADIOBUTTON);
|
||||
testRole("aria_radiogroup", ROLE_RADIO_GROUP);
|
||||
testRole("aria_region", ROLE_REGION);
|
||||
testRole("aria_region_no_name", ROLE_TEXT);
|
||||
testRole("aria_region_has_label", ROLE_REGION);
|
||||
testRole("aria_region_has_labelledby", ROLE_REGION);
|
||||
testRole("aria_region_has_title", ROLE_REGION);
|
||||
testRole("aria_region_empty_name", ROLE_TEXT);
|
||||
testRole("aria_row", ROLE_ROW);
|
||||
testRole("aria_rowheader", ROLE_ROWHEADER);
|
||||
testRole("aria_scrollbar", ROLE_SCROLLBAR);
|
||||
|
@ -238,7 +242,11 @@
|
|||
<span id="aria_progressbar" role="progressbar"/>
|
||||
<span id="aria_radio" role="radio"/>
|
||||
<span id="aria_radiogroup" role="radiogroup"/>
|
||||
<span id="aria_region" role="region"/>
|
||||
<span id="aria_region_no_name" role="region"/>
|
||||
<span id="aria_region_has_label" role="region" aria-label="label"/>
|
||||
<span id="aria_region_has_labelledby" role="region" aria-labelledby="label"/><span id="label" aria-label="label">
|
||||
<span id="aria_region_has_title" role="region" title="title"/>
|
||||
<span id="aria_region_empty_name" role="region" aria-label="" title="" aria-labelledby="empty"/><span id="empty"/>
|
||||
<span id="aria_row" role="row"/>
|
||||
<span id="aria_rowheader" role="rowheader"/>
|
||||
<span id="aria_scrollbar" role="scrollbar"/>
|
||||
|
|
|
@ -6,12 +6,17 @@
|
|||
|
||||
#include "Compatibility.h"
|
||||
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
#include "nsExceptionHandler.h"
|
||||
#include "nsUnicharUtils.h"
|
||||
#include "nsWindowsDllInterceptor.h"
|
||||
#include "nsWinUtils.h"
|
||||
#include "Statistics.h"
|
||||
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
#include <shlobj.h>
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::a11y;
|
||||
|
||||
|
@ -203,3 +208,178 @@ Compatibility::Init()
|
|||
}
|
||||
}
|
||||
|
||||
#if !defined(HAVE_64BIT_BUILD)
|
||||
|
||||
static bool
|
||||
ReadCOMRegDefaultString(const nsString& aRegPath, nsAString& aOutBuf)
|
||||
{
|
||||
aOutBuf.Truncate();
|
||||
|
||||
// Get the required size and type of the registry value.
|
||||
// We expect either REG_SZ or REG_EXPAND_SZ.
|
||||
DWORD type;
|
||||
DWORD bufLen = 0;
|
||||
LONG result = ::RegGetValue(HKEY_CLASSES_ROOT, aRegPath.get(),
|
||||
nullptr, RRF_RT_ANY, &type, nullptr, &bufLen);
|
||||
if (result != ERROR_SUCCESS || (type != REG_SZ && type != REG_EXPAND_SZ)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now obtain the value
|
||||
DWORD flags = type == REG_SZ ? RRF_RT_REG_SZ : RRF_RT_REG_EXPAND_SZ;
|
||||
|
||||
aOutBuf.SetLength((bufLen + 1) / sizeof(char16_t));
|
||||
|
||||
result = ::RegGetValue(HKEY_CLASSES_ROOT, aRegPath.get(), nullptr,
|
||||
flags, nullptr, aOutBuf.BeginWriting(), &bufLen);
|
||||
if (result != ERROR_SUCCESS) {
|
||||
aOutBuf.Truncate();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Truncate terminator
|
||||
aOutBuf.Truncate((bufLen + 1) / sizeof(char16_t) - 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsSystemOleAcc(nsCOMPtr<nsIFile>& aFile)
|
||||
{
|
||||
// Use FOLDERID_SystemX86 so that Windows doesn't give us a redirected
|
||||
// system32 if we're a 32-bit process running on a 64-bit OS. This is
|
||||
// necessary because the values that we are reading from the registry
|
||||
// are not redirected; they reference SysWOW64 directly.
|
||||
PWSTR systemPath = nullptr;
|
||||
HRESULT hr = ::SHGetKnownFolderPath(FOLDERID_SystemX86, 0, nullptr,
|
||||
&systemPath);
|
||||
if (FAILED(hr)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> oleAcc;
|
||||
nsresult rv = NS_NewLocalFile(nsDependentString(systemPath), false,
|
||||
getter_AddRefs(oleAcc));
|
||||
|
||||
::CoTaskMemFree(systemPath);
|
||||
systemPath = nullptr;
|
||||
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
rv = oleAcc->Append(NS_LITERAL_STRING("oleacc.dll"));
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isEqual;
|
||||
rv = oleAcc->Equals(aFile, &isEqual);
|
||||
return NS_SUCCEEDED(rv) && isEqual;
|
||||
}
|
||||
|
||||
static bool
|
||||
IsTypelibPreferred()
|
||||
{
|
||||
// If IAccessible's Proxy/Stub CLSID is kUniversalMarshalerClsid, then any
|
||||
// external a11y clients are expecting to use a typelib.
|
||||
NS_NAMED_LITERAL_STRING(kUniversalMarshalerClsid,
|
||||
"{00020424-0000-0000-C000-000000000046}");
|
||||
|
||||
NS_NAMED_LITERAL_STRING(kIAccessiblePSClsidPath,
|
||||
"Interface\\{618736E0-3C3D-11CF-810C-00AA00389B71}\\ProxyStubClsid32");
|
||||
|
||||
nsAutoString psClsid;
|
||||
if (!ReadCOMRegDefaultString(kIAccessiblePSClsidPath, psClsid)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return psClsid.Equals(kUniversalMarshalerClsid,
|
||||
nsCaseInsensitiveStringComparator());
|
||||
}
|
||||
|
||||
static bool
|
||||
IsIAccessibleTypelibRegistered()
|
||||
{
|
||||
// The system default IAccessible typelib is always registered with version
|
||||
// 1.1, under the neutral locale (LCID 0).
|
||||
NS_NAMED_LITERAL_STRING(kIAccessibleTypelibRegPath,
|
||||
"TypeLib\\{1EA4DBF0-3C3B-11CF-810C-00AA00389B71}\\1.1\\0\\win32");
|
||||
|
||||
nsAutoString typelibPath;
|
||||
if (!ReadCOMRegDefaultString(kIAccessibleTypelibRegPath, typelibPath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> libTestFile;
|
||||
nsresult rv = NS_NewLocalFile(typelibPath, false, getter_AddRefs(libTestFile));
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return IsSystemOleAcc(libTestFile);
|
||||
}
|
||||
|
||||
static bool
|
||||
IsIAccessiblePSRegistered()
|
||||
{
|
||||
NS_NAMED_LITERAL_STRING(kIAccessiblePSRegPath,
|
||||
"CLSID\\{03022430-ABC4-11D0-BDE2-00AA001A1953}\\InProcServer32");
|
||||
|
||||
nsAutoString proxyStubPath;
|
||||
if (!ReadCOMRegDefaultString(kIAccessiblePSRegPath, proxyStubPath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> libTestFile;
|
||||
nsresult rv = NS_NewLocalFile(proxyStubPath, false, getter_AddRefs(libTestFile));
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return IsSystemOleAcc(libTestFile);
|
||||
}
|
||||
|
||||
static bool
|
||||
UseIAccessibleProxyStub()
|
||||
{
|
||||
// If a typelib is preferred then external clients are expecting to use
|
||||
// typelib marshaling, so we should use that whenever available.
|
||||
if (IsTypelibPreferred() && IsIAccessibleTypelibRegistered()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Otherwise we try the proxy/stub
|
||||
if (IsIAccessiblePSRegistered()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// If we reach this point then something is seriously wrong with the
|
||||
// IAccessible configuration in the computer's registry. Let's annotate this
|
||||
// so that we can easily determine this condition during crash analysis.
|
||||
CrashReporter::AnnotateCrashReport(NS_LITERAL_CSTRING("IAccessibleConfig"),
|
||||
NS_LITERAL_CSTRING("NoSystemTypeLibOrPS"));
|
||||
return false;
|
||||
}
|
||||
|
||||
#endif // !defined(HAVE_64BIT_BUILD)
|
||||
|
||||
uint16_t
|
||||
Compatibility::GetActCtxResourceId()
|
||||
{
|
||||
#if defined(HAVE_64BIT_BUILD)
|
||||
// The manifest for 64-bit Windows is embedded with resource ID 64.
|
||||
return 64;
|
||||
#else
|
||||
// The manifest for 32-bit Windows is embedded with resource ID 32.
|
||||
// Beginning with Windows 10 Creators Update, 32-bit builds always use the
|
||||
// 64-bit manifest. Older builds of Windows may or may not require the 64-bit
|
||||
// manifest: UseIAccessibleProxyStub() determines the course of action.
|
||||
if (mozilla::IsWin10CreatorsUpdateOrLater() ||
|
||||
UseIAccessibleProxyStub()) {
|
||||
return 64;
|
||||
}
|
||||
|
||||
return 32;
|
||||
#endif // defined(HAVE_64BIT_BUILD)
|
||||
}
|
||||
|
||||
|
|
|
@ -39,6 +39,12 @@ public:
|
|||
*/
|
||||
static bool IsDolphin() { return !!(sConsumers & DOLPHIN); }
|
||||
|
||||
/**
|
||||
* @return ID of a11y manifest resource to be passed to
|
||||
* mscom::ActivationContext
|
||||
*/
|
||||
static uint16_t GetActCtxResourceId();
|
||||
|
||||
private:
|
||||
Compatibility();
|
||||
Compatibility(const Compatibility&);
|
||||
|
|
|
@ -5121,7 +5121,7 @@ nsBrowserAccess.prototype = {
|
|||
return browser;
|
||||
},
|
||||
|
||||
openURI(aURI, aOpener, aWhere, aFlags) {
|
||||
openURI(aURI, aOpener, aWhere, aFlags, aTriggeringPrincipal) {
|
||||
// This function should only ever be called if we're opening a URI
|
||||
// from a non-remote browser window (via nsContentTreeOwner).
|
||||
if (aOpener && Cu.isCrossProcessWrapper(aOpener)) {
|
||||
|
@ -5153,11 +5153,9 @@ nsBrowserAccess.prototype = {
|
|||
}
|
||||
|
||||
let referrer = aOpener ? makeURI(aOpener.location.href) : null;
|
||||
let triggeringPrincipal = null;
|
||||
let referrerPolicy = Ci.nsIHttpChannel.REFERRER_POLICY_UNSET;
|
||||
if (aOpener && aOpener.document) {
|
||||
referrerPolicy = aOpener.document.referrerPolicy;
|
||||
triggeringPrincipal = aOpener.document.nodePrincipal;
|
||||
}
|
||||
let isPrivate = aOpener
|
||||
? PrivateBrowsingUtils.isContentWindowPrivate(aOpener)
|
||||
|
@ -5191,7 +5189,7 @@ nsBrowserAccess.prototype = {
|
|||
let browser = this._openURIInNewTab(aURI, referrer, referrerPolicy,
|
||||
isPrivate, isExternal,
|
||||
forceNotRemote, userContextId,
|
||||
openerWindow, triggeringPrincipal);
|
||||
openerWindow, aTriggeringPrincipal);
|
||||
if (browser)
|
||||
newWindow = browser.contentWindow;
|
||||
break;
|
||||
|
@ -5202,7 +5200,7 @@ nsBrowserAccess.prototype = {
|
|||
Ci.nsIWebNavigation.LOAD_FLAGS_FROM_EXTERNAL :
|
||||
Ci.nsIWebNavigation.LOAD_FLAGS_NONE;
|
||||
gBrowser.loadURIWithFlags(aURI.spec, {
|
||||
triggeringPrincipal,
|
||||
aTriggeringPrincipal,
|
||||
flags: loadflags,
|
||||
referrerURI: referrer,
|
||||
referrerPolicy,
|
||||
|
|
|
@ -4,7 +4,8 @@ function test() {
|
|||
window.browserDOMWindow.openURI(makeURI("about:blank"),
|
||||
null,
|
||||
Ci.nsIBrowserDOMWindow.OPEN_NEWTAB,
|
||||
Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL);
|
||||
Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL,
|
||||
Services.scriptSecurityManager.getSystemPrincipal());
|
||||
is(gBrowser.tabs.length, tabCount + 1,
|
||||
"'--new-tab about:blank' opens a new tab");
|
||||
is(gBrowser.selectedTab, gBrowser.tabs[tabCount],
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
add_task(async function() {
|
||||
let browserLoadedPromise = BrowserTestUtils.browserLoaded(gBrowser.selectedBrowser);
|
||||
window.browserDOMWindow.openURI(makeURI("about:"), null,
|
||||
Ci.nsIBrowserDOMWindow.OPEN_CURRENTWINDOW, null)
|
||||
Ci.nsIBrowserDOMWindow.OPEN_CURRENTWINDOW, null,
|
||||
Services.scriptSecurityManager.getSystemPrincipal())
|
||||
await browserLoadedPromise;
|
||||
is(gBrowser.currentURI.spec, "about:", "page loads in the current content window");
|
||||
});
|
||||
|
|
|
@ -3,7 +3,8 @@ function test() {
|
|||
window.browserDOMWindow.openURI(makeURI(URI),
|
||||
null,
|
||||
Ci.nsIBrowserDOMWindow.OPEN_NEWTAB,
|
||||
Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL);
|
||||
Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL,
|
||||
Services.scriptSecurityManager.getSystemPrincipal());
|
||||
|
||||
is(gBrowser.userTypedValue, URI, "userTypedValue matches test URI");
|
||||
is(gURLBar.value, URI, "location bar value matches test URI");
|
||||
|
|
|
@ -343,7 +343,8 @@ nsBrowserContentHandler.prototype = {
|
|||
try {
|
||||
while ((uriparam = cmdLine.handleFlagWithParam("new-tab", false))) {
|
||||
let uri = resolveURIInternal(cmdLine, uriparam);
|
||||
handURIToExistingBrowser(uri, nsIBrowserDOMWindow.OPEN_NEWTAB, cmdLine);
|
||||
handURIToExistingBrowser(uri, nsIBrowserDOMWindow.OPEN_NEWTAB, cmdLine, false,
|
||||
Services.scriptSecurityManager.getSystemPrincipal());
|
||||
cmdLine.preventDefault = true;
|
||||
}
|
||||
} catch (e) {
|
||||
|
@ -391,7 +392,8 @@ nsBrowserContentHandler.prototype = {
|
|||
var privateWindowParam = cmdLine.handleFlagWithParam("private-window", false);
|
||||
if (privateWindowParam) {
|
||||
let resolvedURI = resolveURIInternal(cmdLine, privateWindowParam);
|
||||
handURIToExistingBrowser(resolvedURI, nsIBrowserDOMWindow.OPEN_NEWTAB, cmdLine, true);
|
||||
handURIToExistingBrowser(resolvedURI, nsIBrowserDOMWindow.OPEN_NEWTAB, cmdLine, true,
|
||||
Services.scriptSecurityManager.getSystemPrincipal());
|
||||
cmdLine.preventDefault = true;
|
||||
}
|
||||
} catch (e) {
|
||||
|
@ -607,8 +609,8 @@ nsBrowserContentHandler.prototype = {
|
|||
}
|
||||
|
||||
request.QueryInterface(nsIChannel);
|
||||
handURIToExistingBrowser(request.URI,
|
||||
nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW, null);
|
||||
handURIToExistingBrowser(request.URI, nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW, null, false,
|
||||
request.loadInfo.triggeringPrincipal);
|
||||
request.cancel(NS_BINDING_ABORTED);
|
||||
},
|
||||
|
||||
|
@ -642,7 +644,7 @@ nsBrowserContentHandler.prototype = {
|
|||
};
|
||||
var gBrowserContentHandler = new nsBrowserContentHandler();
|
||||
|
||||
function handURIToExistingBrowser(uri, location, cmdLine, forcePrivate) {
|
||||
function handURIToExistingBrowser(uri, location, cmdLine, forcePrivate, triggeringPrincipal) {
|
||||
if (!shouldLoadURI(uri))
|
||||
return;
|
||||
|
||||
|
@ -667,7 +669,7 @@ function handURIToExistingBrowser(uri, location, cmdLine, forcePrivate) {
|
|||
.getInterface(nsIDOMWindow);
|
||||
var bwin = rootWin.QueryInterface(nsIDOMChromeWindow).browserDOMWindow;
|
||||
bwin.openURI(uri, null, location,
|
||||
nsIBrowserDOMWindow.OPEN_EXTERNAL);
|
||||
nsIBrowserDOMWindow.OPEN_EXTERNAL, triggeringPrincipal);
|
||||
}
|
||||
|
||||
function nsDefaultCommandLineHandler() {
|
||||
|
@ -742,7 +744,8 @@ nsDefaultCommandLineHandler.prototype = {
|
|||
// Try to find an existing window and load our URI into the
|
||||
// current tab, new tab, or new window as prefs determine.
|
||||
try {
|
||||
handURIToExistingBrowser(urilist[0], nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW, cmdLine);
|
||||
handURIToExistingBrowser(urilist[0], nsIBrowserDOMWindow.OPEN_DEFAULTWINDOW, cmdLine, false,
|
||||
Services.scriptSecurityManager.getSystemPrincipal());
|
||||
return;
|
||||
} catch (e) {
|
||||
}
|
||||
|
|
|
@ -241,13 +241,18 @@ function tunnelToInnerBrowser(outer, inner) {
|
|||
let { detail } = event;
|
||||
event.preventDefault();
|
||||
let uri = Services.io.newURI(detail.url);
|
||||
let sourceNode = event.dataTransfer.mozSourceNode;
|
||||
let triggeringPrincipal = sourceNode
|
||||
? sourceNode.nodePrincipal
|
||||
: Services.scriptSecurityManager.getSystemPrincipal();
|
||||
// This API is used mainly because it's near the path used for <a target/> with
|
||||
// regular browser tabs (which calls `openURIInFrame`). The more elaborate APIs
|
||||
// that support openers, window features, etc. didn't seem callable from JS and / or
|
||||
// this event doesn't give enough info to use them.
|
||||
browserWindow.browserDOMWindow
|
||||
.openURI(uri, null, Ci.nsIBrowserDOMWindow.OPEN_NEWTAB,
|
||||
Ci.nsIBrowserDOMWindow.OPEN_NEW);
|
||||
Ci.nsIBrowserDOMWindow.OPEN_NEW,
|
||||
triggeringPrincipal);
|
||||
},
|
||||
|
||||
stop() {
|
||||
|
|
|
@ -40,6 +40,21 @@ nsOpenURIInFrameParams::GetIsPrivate(bool* aIsPrivate)
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsOpenURIInFrameParams::GetTriggeringPrincipal(nsIPrincipal** aTriggeringPrincipal)
|
||||
{
|
||||
NS_ADDREF(*aTriggeringPrincipal = mTriggeringPrincipal);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsOpenURIInFrameParams::SetTriggeringPrincipal(nsIPrincipal* aTriggeringPrincipal)
|
||||
{
|
||||
NS_ENSURE_TRUE(aTriggeringPrincipal, NS_ERROR_INVALID_ARG);
|
||||
mTriggeringPrincipal = aTriggeringPrincipal;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsOpenURIInFrameParams::GetOpenerOriginAttributes(JSContext* aCx,
|
||||
JS::MutableHandle<JS::Value> aValue)
|
||||
|
|
|
@ -25,4 +25,5 @@ private:
|
|||
|
||||
mozilla::OriginAttributes mOpenerOriginAttributes;
|
||||
nsString mReferrer;
|
||||
nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
|
||||
};
|
||||
|
|
|
@ -9,12 +9,14 @@ interface mozIDOMWindowProxy;
|
|||
interface nsIDOMWindow;
|
||||
interface nsIURI;
|
||||
interface nsIFrameLoaderOwner;
|
||||
interface nsIPrincipal;
|
||||
|
||||
[scriptable, uuid(e774db14-79ac-4156-a7a3-aa3fd0a22c10)]
|
||||
interface nsIOpenURIInFrameParams : nsISupports
|
||||
{
|
||||
attribute DOMString referrer;
|
||||
readonly attribute boolean isPrivate;
|
||||
attribute nsIPrincipal triggeringPrincipal;
|
||||
|
||||
[implicit_jscontext]
|
||||
readonly attribute jsval openerOriginAttributes;
|
||||
|
@ -97,11 +99,12 @@ interface nsIBrowserDOMWindow : nsISupports
|
|||
* @param aFlags flags which control the behavior of the load. The
|
||||
* OPEN_EXTERNAL/OPEN_NEW flag is only used when
|
||||
* aWhere == OPEN_DEFAULTWINDOW.
|
||||
* @param aTriggeringPrincipal the principal that triggered the load of aURI
|
||||
* @return the window into which the URI was opened.
|
||||
*/
|
||||
mozIDOMWindowProxy
|
||||
openURI(in nsIURI aURI, in mozIDOMWindowProxy aOpener,
|
||||
in short aWhere, in long aFlags);
|
||||
in short aWhere, in long aFlags, in nsIPrincipal aTriggeringPrincipal);
|
||||
|
||||
/**
|
||||
* As above, but return the nsIFrameLoaderOwner for the new window.
|
||||
|
|
|
@ -72,6 +72,7 @@
|
|||
#include "mozilla/WebBrowserPersistDocumentChild.h"
|
||||
#include "imgLoader.h"
|
||||
#include "GMPServiceChild.h"
|
||||
#include "NullPrincipal.h"
|
||||
|
||||
#ifdef MOZ_GECKO_PROFILER
|
||||
#include "ChildProfilerController.h"
|
||||
|
@ -690,15 +691,19 @@ ContentChild::ProvideWindow(mozIDOMWindowProxy* aParent,
|
|||
|
||||
static nsresult
|
||||
GetWindowParamsFromParent(mozIDOMWindowProxy* aParent,
|
||||
nsACString& aBaseURIString, float* aFullZoom)
|
||||
nsACString& aBaseURIString, float* aFullZoom,
|
||||
nsIPrincipal** aTriggeringPrincipal)
|
||||
{
|
||||
*aFullZoom = 1.0f;
|
||||
auto* opener = nsPIDOMWindowOuter::From(aParent);
|
||||
if (!opener) {
|
||||
nsCOMPtr<nsIPrincipal> nullPrincipal = NullPrincipal::Create();
|
||||
NS_ADDREF(*aTriggeringPrincipal = nullPrincipal);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIDocument> doc = opener->GetDoc();
|
||||
NS_ADDREF(*aTriggeringPrincipal = doc->NodePrincipal());
|
||||
nsCOMPtr<nsIURI> baseURI = doc->GetDocBaseURI();
|
||||
if (!baseURI) {
|
||||
NS_ERROR("nsIDocument didn't return a base URI");
|
||||
|
@ -778,7 +783,9 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
|
|||
if (loadInDifferentProcess) {
|
||||
nsAutoCString baseURIString;
|
||||
float fullZoom;
|
||||
rv = GetWindowParamsFromParent(aParent, baseURIString, &fullZoom);
|
||||
nsCOMPtr<nsIPrincipal> triggeringPrincipal;
|
||||
rv = GetWindowParamsFromParent(aParent, baseURIString, &fullZoom,
|
||||
getter_AddRefs(triggeringPrincipal));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -794,7 +801,8 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
|
|||
features,
|
||||
baseURIString,
|
||||
fullZoom,
|
||||
name);
|
||||
name,
|
||||
Principal(triggeringPrincipal));
|
||||
|
||||
// We return NS_ERROR_ABORT, so that the caller knows that we've abandoned
|
||||
// the window open as far as it is concerned.
|
||||
|
@ -890,7 +898,9 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
|
|||
} else {
|
||||
nsAutoCString baseURIString;
|
||||
float fullZoom;
|
||||
rv = GetWindowParamsFromParent(aParent, baseURIString, &fullZoom);
|
||||
nsCOMPtr<nsIPrincipal> triggeringPrincipal;
|
||||
rv = GetWindowParamsFromParent(aParent, baseURIString, &fullZoom,
|
||||
getter_AddRefs(triggeringPrincipal));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -901,7 +911,8 @@ ContentChild::ProvideWindowCommon(TabChild* aTabOpener,
|
|||
aSizeSpecified,
|
||||
features,
|
||||
baseURIString,
|
||||
fullZoom);
|
||||
fullZoom,
|
||||
Principal(triggeringPrincipal));
|
||||
}
|
||||
|
||||
// Await the promise being resolved. When the promise is resolved, we'll set
|
||||
|
@ -2748,29 +2759,6 @@ ContentChild::DeallocPOfflineCacheUpdateChild(POfflineCacheUpdateChild* actor)
|
|||
return true;
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentChild::RecvLoadPluginResult(const uint32_t& aPluginId,
|
||||
const bool& aResult)
|
||||
{
|
||||
nsresult rv;
|
||||
Endpoint<PPluginModuleParent> endpoint;
|
||||
bool finalResult = aResult &&
|
||||
SendConnectPluginBridge(aPluginId, &rv, &endpoint) &&
|
||||
NS_SUCCEEDED(rv);
|
||||
plugins::PluginModuleContentParent::OnLoadPluginResult(aPluginId,
|
||||
finalResult,
|
||||
Move(endpoint));
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentChild::RecvAssociatePluginId(const uint32_t& aPluginId,
|
||||
const base::ProcessId& aProcessId)
|
||||
{
|
||||
plugins::PluginModuleContentParent::AssociatePluginId(aPluginId, aProcessId);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
ContentChild::RecvDomainSetChanged(const uint32_t& aSetType,
|
||||
const uint32_t& aChangeType,
|
||||
|
|
|
@ -438,12 +438,6 @@ public:
|
|||
const nsCString& aTopic,
|
||||
const nsString& aData) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvAssociatePluginId(const uint32_t& aPluginId,
|
||||
const base::ProcessId& aProcessId) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvLoadPluginResult(const uint32_t& aPluginId,
|
||||
const bool& aResult) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvUpdateWindow(const uintptr_t& aChildId) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvDomainSetChanged(const uint32_t& aSetType,
|
||||
|
|
|
@ -1104,8 +1104,7 @@ ContentParent::RecvLoadPlugin(const uint32_t& aPluginId,
|
|||
Endpoint<PPluginModuleParent>* aEndpoint)
|
||||
{
|
||||
*aRv = NS_OK;
|
||||
if (!mozilla::plugins::SetupBridge(aPluginId, this, false, aRv, aRunID,
|
||||
aEndpoint)) {
|
||||
if (!mozilla::plugins::SetupBridge(aPluginId, this, aRv, aRunID, aEndpoint)) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
return IPC_OK();
|
||||
|
@ -1141,7 +1140,7 @@ ContentParent::RecvConnectPluginBridge(const uint32_t& aPluginId,
|
|||
// in the first call to SetupBridge in RecvLoadPlugin, so we pass in a dummy
|
||||
// pointer and just throw it away.
|
||||
uint32_t dummy = 0;
|
||||
if (!mozilla::plugins::SetupBridge(aPluginId, this, true, aRv, &dummy, aEndpoint)) {
|
||||
if (!mozilla::plugins::SetupBridge(aPluginId, this, aRv, &dummy, aEndpoint)) {
|
||||
return IPC_FAIL(this, "SetupBridge failed");
|
||||
}
|
||||
return IPC_OK();
|
||||
|
@ -4504,7 +4503,8 @@ ContentParent::CommonCreateWindow(PBrowserParent* aThisTab,
|
|||
const nsString& aName,
|
||||
nsresult& aResult,
|
||||
nsCOMPtr<nsITabParent>& aNewTabParent,
|
||||
bool* aWindowIsNew)
|
||||
bool* aWindowIsNew,
|
||||
nsIPrincipal* aTriggeringPrincipal)
|
||||
|
||||
{
|
||||
// The content process should never be in charge of computing whether or
|
||||
|
@ -4582,6 +4582,8 @@ ContentParent::CommonCreateWindow(PBrowserParent* aThisTab,
|
|||
nsCOMPtr<nsIOpenURIInFrameParams> params =
|
||||
new nsOpenURIInFrameParams(openerOriginAttributes);
|
||||
params->SetReferrer(NS_ConvertUTF8toUTF16(aBaseURI));
|
||||
MOZ_ASSERT(aTriggeringPrincipal, "need a valid triggeringPrincipal");
|
||||
params->SetTriggeringPrincipal(aTriggeringPrincipal);
|
||||
|
||||
nsCOMPtr<nsIFrameLoaderOwner> frameLoaderOwner;
|
||||
aResult = browserDOMWin->OpenURIInFrame(aURIToLoad, params, openLocation,
|
||||
|
@ -4647,6 +4649,7 @@ ContentParent::CommonCreateWindow(PBrowserParent* aThisTab,
|
|||
aResult = newBrowserDOMWin->OpenURI(aURIToLoad, openerWindow,
|
||||
nsIBrowserDOMWindow::OPEN_CURRENTWINDOW,
|
||||
nsIBrowserDOMWindow::OPEN_NEW,
|
||||
aTriggeringPrincipal,
|
||||
getter_AddRefs(win));
|
||||
}
|
||||
|
||||
|
@ -4664,6 +4667,7 @@ ContentParent::RecvCreateWindow(PBrowserParent* aThisTab,
|
|||
const nsCString& aFeatures,
|
||||
const nsCString& aBaseURI,
|
||||
const float& aFullZoom,
|
||||
const IPC::Principal& aTriggeringPrincipal,
|
||||
CreateWindowResolver&& aResolve)
|
||||
{
|
||||
nsresult rv = NS_OK;
|
||||
|
@ -4708,7 +4712,8 @@ ContentParent::RecvCreateWindow(PBrowserParent* aThisTab,
|
|||
aCalledFromJS, aPositionSpecified, aSizeSpecified,
|
||||
nullptr, aFeatures, aBaseURI, aFullZoom,
|
||||
nextTabParentId, NullString(), rv,
|
||||
newRemoteTab, &cwi.windowOpened());
|
||||
newRemoteTab, &cwi.windowOpened(),
|
||||
aTriggeringPrincipal);
|
||||
if (!ipcResult) {
|
||||
return ipcResult;
|
||||
}
|
||||
|
@ -4751,7 +4756,8 @@ ContentParent::RecvCreateWindowInDifferentProcess(
|
|||
const nsCString& aFeatures,
|
||||
const nsCString& aBaseURI,
|
||||
const float& aFullZoom,
|
||||
const nsString& aName)
|
||||
const nsString& aName,
|
||||
const IPC::Principal& aTriggeringPrincipal)
|
||||
{
|
||||
nsCOMPtr<nsITabParent> newRemoteTab;
|
||||
bool windowIsNew;
|
||||
|
@ -4762,7 +4768,7 @@ ContentParent::RecvCreateWindowInDifferentProcess(
|
|||
aCalledFromJS, aPositionSpecified, aSizeSpecified,
|
||||
uriToLoad, aFeatures, aBaseURI, aFullZoom,
|
||||
/* aNextTabParentId = */ 0, aName, rv,
|
||||
newRemoteTab, &windowIsNew);
|
||||
newRemoteTab, &windowIsNew, aTriggeringPrincipal);
|
||||
if (!ipcResult) {
|
||||
return ipcResult;
|
||||
}
|
||||
|
|
|
@ -536,6 +536,7 @@ public:
|
|||
const nsCString& aFeatures,
|
||||
const nsCString& aBaseURI,
|
||||
const float& aFullZoom,
|
||||
const IPC::Principal& aTriggeringPrincipal,
|
||||
CreateWindowResolver&& aResolve) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvCreateWindowInDifferentProcess(
|
||||
|
@ -548,7 +549,8 @@ public:
|
|||
const nsCString& aFeatures,
|
||||
const nsCString& aBaseURI,
|
||||
const float& aFullZoom,
|
||||
const nsString& aName) override;
|
||||
const nsString& aName,
|
||||
const IPC::Principal& aTriggeringPrincipal) override;
|
||||
|
||||
static bool AllocateLayerTreeId(TabParent* aTabParent, uint64_t* aId);
|
||||
|
||||
|
@ -709,7 +711,8 @@ private:
|
|||
const nsString& aName,
|
||||
nsresult& aResult,
|
||||
nsCOMPtr<nsITabParent>& aNewTabParent,
|
||||
bool* aWindowIsNew);
|
||||
bool* aWindowIsNew,
|
||||
nsIPrincipal* aTriggeringPrincipal);
|
||||
|
||||
FORWARD_SHMEM_ALLOCATOR_TO(PContentParent)
|
||||
|
||||
|
|
|
@ -489,19 +489,6 @@ child:
|
|||
*/
|
||||
async NotifyIdleObserver(uint64_t observerId, nsCString topic, nsString str);
|
||||
|
||||
/**
|
||||
* Called during plugin initialization to map a plugin id to a child process
|
||||
* id.
|
||||
*/
|
||||
async AssociatePluginId(uint32_t aPluginId, ProcessId aProcessId);
|
||||
|
||||
/**
|
||||
* This call is used by async plugin initialization to notify the
|
||||
* PluginModuleContentParent that the PluginModuleChromeParent's async
|
||||
* init has completed.
|
||||
*/
|
||||
async LoadPluginResult(uint32_t aPluginId, bool aResult);
|
||||
|
||||
async InvokeDragSession(IPCDataTransfer[] transfers, uint32_t action);
|
||||
|
||||
async EndDragSession(bool aDoneDrag, bool aUserCancelled,
|
||||
|
@ -991,7 +978,8 @@ parent:
|
|||
bool aSizeSpecified,
|
||||
nsCString aFeatures,
|
||||
nsCString aBaseURI,
|
||||
float aFullZoom)
|
||||
float aFullZoom,
|
||||
Principal aTriggeringPrincipal)
|
||||
returns (CreatedWindowInfo window);
|
||||
|
||||
async CreateWindowInDifferentProcess(
|
||||
|
@ -1004,7 +992,8 @@ parent:
|
|||
nsCString aFeatures,
|
||||
nsCString aBaseURI,
|
||||
float aFullZoom,
|
||||
nsString aName);
|
||||
nsString aName,
|
||||
Principal aTriggeringPrincipal);
|
||||
|
||||
sync GetAndroidSystemInfo()
|
||||
returns (AndroidSystemInfo info);
|
||||
|
|
|
@ -3444,7 +3444,7 @@ TabChildSHistoryListener::OnRequestCrossBrowserNavigation(uint32_t aIndex)
|
|||
NS_OK : NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
TabChildGlobal::TabChildGlobal(TabChildBase* aTabChild)
|
||||
TabChildGlobal::TabChildGlobal(TabChild* aTabChild)
|
||||
: mTabChild(aTabChild)
|
||||
{
|
||||
SetIsNotDOMBinding();
|
||||
|
@ -3546,3 +3546,32 @@ TabChildGlobal::GetGlobalJSObject()
|
|||
NS_ENSURE_TRUE(mTabChild, nullptr);
|
||||
return mTabChild->GetGlobal();
|
||||
}
|
||||
|
||||
nsresult
|
||||
TabChildGlobal::Dispatch(const char* aName,
|
||||
TaskCategory aCategory,
|
||||
already_AddRefed<nsIRunnable>&& aRunnable)
|
||||
{
|
||||
if (mTabChild && mTabChild->TabGroup()) {
|
||||
return mTabChild->TabGroup()->Dispatch(aName, aCategory, Move(aRunnable));
|
||||
}
|
||||
return DispatcherTrait::Dispatch(aName, aCategory, Move(aRunnable));
|
||||
}
|
||||
|
||||
nsISerialEventTarget*
|
||||
TabChildGlobal::EventTargetFor(TaskCategory aCategory) const
|
||||
{
|
||||
if (mTabChild && mTabChild->TabGroup()) {
|
||||
return mTabChild->TabGroup()->EventTargetFor(aCategory);
|
||||
}
|
||||
return DispatcherTrait::EventTargetFor(aCategory);
|
||||
}
|
||||
|
||||
AbstractThread*
|
||||
TabChildGlobal::AbstractMainThreadFor(TaskCategory aCategory)
|
||||
{
|
||||
if (mTabChild && mTabChild->TabGroup()) {
|
||||
return mTabChild->TabGroup()->AbstractMainThreadFor(aCategory);
|
||||
}
|
||||
return DispatcherTrait::AbstractMainThreadFor(aCategory);
|
||||
}
|
||||
|
|
|
@ -45,8 +45,10 @@
|
|||
|
||||
class nsIDOMWindowUtils;
|
||||
class nsIHttpChannel;
|
||||
class nsISerialEventTarget;
|
||||
|
||||
namespace mozilla {
|
||||
class AbstractThread;
|
||||
namespace layout {
|
||||
class RenderFrameChild;
|
||||
} // namespace layout
|
||||
|
@ -69,7 +71,6 @@ class TabChild;
|
|||
class TabGroup;
|
||||
class ClonedMessageData;
|
||||
class CoalescedWheelData;
|
||||
class TabChildBase;
|
||||
|
||||
class TabChildGlobal : public DOMEventTargetHelper,
|
||||
public nsIContentFrameMessageManager,
|
||||
|
@ -78,7 +79,7 @@ class TabChildGlobal : public DOMEventTargetHelper,
|
|||
public nsSupportsWeakReference
|
||||
{
|
||||
public:
|
||||
explicit TabChildGlobal(TabChildBase* aTabChild);
|
||||
explicit TabChildGlobal(TabChild* aTabChild);
|
||||
void Init();
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(TabChildGlobal, DOMEventTargetHelper)
|
||||
|
@ -149,8 +150,19 @@ public:
|
|||
MOZ_CRASH("TabChildGlobal doesn't use DOM bindings!");
|
||||
}
|
||||
|
||||
// Dispatch a runnable related to the global.
|
||||
virtual nsresult Dispatch(const char* aName,
|
||||
mozilla::TaskCategory aCategory,
|
||||
already_AddRefed<nsIRunnable>&& aRunnable) override;
|
||||
|
||||
virtual nsISerialEventTarget*
|
||||
EventTargetFor(mozilla::TaskCategory aCategory) const override;
|
||||
|
||||
virtual AbstractThread*
|
||||
AbstractMainThreadFor(mozilla::TaskCategory aCategory) override;
|
||||
|
||||
nsCOMPtr<nsIContentFrameMessageManager> mMessageManager;
|
||||
RefPtr<TabChildBase> mTabChild;
|
||||
RefPtr<TabChild> mTabChild;
|
||||
|
||||
protected:
|
||||
~TabChildGlobal();
|
||||
|
|
|
@ -28,7 +28,7 @@ class MediaDrmCDMCallbackProxy;
|
|||
class MediaDrmCDMProxy : public CDMProxy {
|
||||
public:
|
||||
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDrmCDMProxy)
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MediaDrmCDMProxy, override)
|
||||
|
||||
MediaDrmCDMProxy(dom::MediaKeys* aKeys,
|
||||
const nsAString& aKeySystem,
|
||||
|
|
|
@ -589,6 +589,12 @@ PaymentRequest::UpdateShippingAddress(const nsAString& aCountry,
|
|||
return DispatchUpdateEvent(NS_LITERAL_STRING("shippingaddresschange"));
|
||||
}
|
||||
|
||||
void
|
||||
PaymentRequest::SetShippingOption(const nsAString& aShippingOption)
|
||||
{
|
||||
mShippingOption = aShippingOption;
|
||||
}
|
||||
|
||||
void
|
||||
PaymentRequest::GetShippingOption(nsAString& aRetVal) const
|
||||
{
|
||||
|
@ -604,10 +610,16 @@ PaymentRequest::UpdateShippingOption(const nsAString& aShippingOption)
|
|||
return DispatchUpdateEvent(NS_LITERAL_STRING("shippingoptionchange"));
|
||||
}
|
||||
|
||||
void
|
||||
PaymentRequest::SetShippingType(const Nullable<PaymentShippingType>& aShippingType)
|
||||
{
|
||||
mShippingType = aShippingType;
|
||||
}
|
||||
|
||||
Nullable<PaymentShippingType>
|
||||
PaymentRequest::GetShippingType() const
|
||||
{
|
||||
return nullptr;
|
||||
return mShippingType;
|
||||
}
|
||||
|
||||
PaymentRequest::~PaymentRequest()
|
||||
|
|
|
@ -106,12 +106,15 @@ public:
|
|||
const nsAString& aRecipient,
|
||||
const nsAString& aPhone);
|
||||
|
||||
|
||||
void SetShippingOption(const nsAString& aShippingOption);
|
||||
void GetShippingOption(nsAString& aRetVal) const;
|
||||
nsresult UpdateShippingOption(const nsAString& aShippingOption);
|
||||
|
||||
nsresult UpdatePayment(const PaymentDetailsUpdate& aDetails);
|
||||
void AbortUpdate(nsresult aRv);
|
||||
|
||||
void SetShippingType(const Nullable<PaymentShippingType>& aShippingType);
|
||||
Nullable<PaymentShippingType> GetShippingType() const;
|
||||
|
||||
IMPL_EVENT_HANDLER(shippingaddresschange);
|
||||
|
@ -143,6 +146,8 @@ protected:
|
|||
// It is populated when the user chooses a shipping option.
|
||||
nsString mShippingOption;
|
||||
|
||||
Nullable<PaymentShippingType> mShippingType;
|
||||
|
||||
// "true" when there is a pending updateWith() call to update the payment request
|
||||
// and "false" otherwise.
|
||||
bool mUpdating;
|
||||
|
|
|
@ -103,7 +103,8 @@ nsresult
|
|||
ConvertDetailsBase(const PaymentDetailsBase& aDetails,
|
||||
nsTArray<IPCPaymentItem>& aDisplayItems,
|
||||
nsTArray<IPCPaymentShippingOption>& aShippingOptions,
|
||||
nsTArray<IPCPaymentDetailsModifier>& aModifiers)
|
||||
nsTArray<IPCPaymentDetailsModifier>& aModifiers,
|
||||
bool aResetShippingOptions)
|
||||
{
|
||||
if (aDetails.mDisplayItems.WasPassed()) {
|
||||
for (const PaymentItem& item : aDetails.mDisplayItems.Value()) {
|
||||
|
@ -112,7 +113,7 @@ ConvertDetailsBase(const PaymentDetailsBase& aDetails,
|
|||
aDisplayItems.AppendElement(displayItem);
|
||||
}
|
||||
}
|
||||
if (aDetails.mShippingOptions.WasPassed()) {
|
||||
if (aDetails.mShippingOptions.WasPassed() && !aResetShippingOptions) {
|
||||
for (const PaymentShippingOption& option : aDetails.mShippingOptions.Value()) {
|
||||
IPCPaymentShippingOption shippingOption;
|
||||
ConvertShippingOption(option, shippingOption);
|
||||
|
@ -134,13 +135,14 @@ ConvertDetailsBase(const PaymentDetailsBase& aDetails,
|
|||
|
||||
nsresult
|
||||
ConvertDetailsInit(const PaymentDetailsInit& aDetails,
|
||||
IPCPaymentDetails& aIPCDetails)
|
||||
IPCPaymentDetails& aIPCDetails,
|
||||
bool aResetShippingOptions)
|
||||
{
|
||||
// Convert PaymentDetailsBase members
|
||||
nsTArray<IPCPaymentItem> displayItems;
|
||||
nsTArray<IPCPaymentShippingOption> shippingOptions;
|
||||
nsTArray<IPCPaymentDetailsModifier> modifiers;
|
||||
nsresult rv = ConvertDetailsBase(aDetails, displayItems, shippingOptions, modifiers);
|
||||
nsresult rv = ConvertDetailsBase(aDetails, displayItems, shippingOptions, modifiers, aResetShippingOptions);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -175,7 +177,10 @@ ConvertDetailsUpdate(const PaymentDetailsUpdate& aDetails,
|
|||
nsTArray<IPCPaymentItem> displayItems;
|
||||
nsTArray<IPCPaymentShippingOption> shippingOptions;
|
||||
nsTArray<IPCPaymentDetailsModifier> modifiers;
|
||||
nsresult rv = ConvertDetailsBase(aDetails, displayItems, shippingOptions, modifiers);
|
||||
// [TODO] Populate a boolean flag as aResetShippingOptions based on the
|
||||
// result of processing details.shippingOptions in UpdatePayment method.
|
||||
nsresult rv = ConvertDetailsBase(
|
||||
aDetails, displayItems, shippingOptions, modifiers, false);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -352,6 +357,37 @@ PaymentRequestManager::GetPaymentRequestById(const nsAString& aRequestId)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
GetSelectedShippingOption(const PaymentDetailsInit& aDetails,
|
||||
nsAString& aOption,
|
||||
bool* aResetOptions)
|
||||
{
|
||||
SetDOMStringToNull(aOption);
|
||||
if (!aDetails.mShippingOptions.WasPassed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsTArray<nsString> seenIDs;
|
||||
const Sequence<PaymentShippingOption>& shippingOptions =
|
||||
aDetails.mShippingOptions.Value();
|
||||
for (const PaymentShippingOption& shippingOption : shippingOptions) {
|
||||
// If there are duplicate IDs present in the shippingOptions, reset aOption
|
||||
// to null and set resetOptions flag to reset details.shippingOptions later
|
||||
// when converting to IPC structure.
|
||||
if (seenIDs.Contains(shippingOption.mId)) {
|
||||
SetDOMStringToNull(aOption);
|
||||
*aResetOptions = true;
|
||||
return;
|
||||
}
|
||||
seenIDs.AppendElement(shippingOption.mId);
|
||||
|
||||
// set aOption to last selected option's ID
|
||||
if (shippingOption.mSelected) {
|
||||
aOption = shippingOption.mId;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nsresult
|
||||
PaymentRequestManager::CreatePayment(nsPIDOMWindowInner* aWindow,
|
||||
const Sequence<PaymentMethodData>& aMethodData,
|
||||
|
@ -362,26 +398,7 @@ PaymentRequestManager::CreatePayment(nsPIDOMWindowInner* aWindow,
|
|||
MOZ_ASSERT(NS_IsMainThread());
|
||||
NS_ENSURE_ARG_POINTER(aRequest);
|
||||
*aRequest = nullptr;
|
||||
|
||||
nsresult rv;
|
||||
nsTArray<IPCPaymentMethodData> methodData;
|
||||
for (const PaymentMethodData& data : aMethodData) {
|
||||
IPCPaymentMethodData ipcMethodData;
|
||||
rv = ConvertMethodData(data, ipcMethodData);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
methodData.AppendElement(ipcMethodData);
|
||||
}
|
||||
|
||||
IPCPaymentDetails details;
|
||||
rv = ConvertDetailsInit(aDetails, details);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
IPCPaymentOptions options;
|
||||
ConvertOptions(aOptions, options);
|
||||
|
||||
RefPtr<PaymentRequest> request = PaymentRequest::CreatePaymentRequest(aWindow, rv);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
|
@ -400,8 +417,48 @@ PaymentRequestManager::CreatePayment(nsPIDOMWindowInner* aWindow,
|
|||
}
|
||||
request->SetId(requestId);
|
||||
|
||||
/*
|
||||
* Set request's mShippingOption to last selected option's ID if
|
||||
* details.shippingOptions exists and IDs of all options are unique.
|
||||
* Otherwise, set mShippingOption to null and set the resetShippingOptions
|
||||
* flag to reset details.shippingOptions to an empty array later when
|
||||
* converting details to IPC structure.
|
||||
*/
|
||||
nsAutoString shippingOption;
|
||||
bool resetShippingOptions = false;
|
||||
GetSelectedShippingOption(aDetails, shippingOption, &resetShippingOptions);
|
||||
request->SetShippingOption(shippingOption);
|
||||
|
||||
/*
|
||||
* Set request's |mShippingType| if shipping is required.
|
||||
*/
|
||||
if (aOptions.mRequestShipping) {
|
||||
request->SetShippingType(
|
||||
Nullable<PaymentShippingType>(aOptions.mShippingType));
|
||||
}
|
||||
|
||||
nsAutoString internalId;
|
||||
request->GetInternalId(internalId);
|
||||
|
||||
nsTArray<IPCPaymentMethodData> methodData;
|
||||
for (const PaymentMethodData& data : aMethodData) {
|
||||
IPCPaymentMethodData ipcMethodData;
|
||||
rv = ConvertMethodData(data, ipcMethodData);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
methodData.AppendElement(ipcMethodData);
|
||||
}
|
||||
|
||||
IPCPaymentDetails details;
|
||||
rv = ConvertDetailsInit(aDetails, details, resetShippingOptions);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
IPCPaymentOptions options;
|
||||
ConvertOptions(aOptions, options);
|
||||
|
||||
IPCPaymentCreateActionRequest action(internalId,
|
||||
methodData,
|
||||
details,
|
||||
|
@ -489,6 +546,12 @@ PaymentRequestManager::UpdatePayment(const nsAString& aRequestId,
|
|||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
// [TODO] Process details.shippingOptions if presented.
|
||||
// 1) Check if there are duplicate IDs in details.shippingOptions,
|
||||
// if so, reset details.shippingOptions to an empty sequence.
|
||||
// 2) Set request's selectedShippingOption to the ID of last selected
|
||||
// option.
|
||||
|
||||
IPCPaymentDetails details;
|
||||
nsresult rv = ConvertDetailsUpdate(aDetails, details);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
|
|
|
@ -227,6 +227,67 @@ function checkComplexRequest(payRequest) {
|
|||
}
|
||||
}
|
||||
|
||||
function checkDuplicateShippingOptionsRequest(payRequest) {
|
||||
if (payRequest.paymentMethods.length != 1) {
|
||||
emitTestFail("paymentMethods' length should be 1.");
|
||||
}
|
||||
|
||||
const methodData = payRequest.paymentMethods.queryElementAt(0, Ci.nsIPaymentMethodData);
|
||||
if (!methodData) {
|
||||
emitTestFail("Fail to get payment methodData.");
|
||||
}
|
||||
let supportedMethod = methodData.supportedMethods;
|
||||
if (supportedMethod != "basic-card") {
|
||||
emitTestFail("supported method should be 'basic-card'.");
|
||||
}
|
||||
// checking the passed PaymentDetails parameter
|
||||
const details = payRequest.paymentDetails;
|
||||
if (details.id != "duplicate shipping options details" ) {
|
||||
emitTestFail("details.id should be 'duplicate shipping options details'.");
|
||||
}
|
||||
if (details.totalItem.label != "Total") {
|
||||
emitTestFail("total item's label should be 'Total'.");
|
||||
}
|
||||
if (details.totalItem.amount.currency != "USD") {
|
||||
emitTestFail("total item's currency should be 'USD'.");
|
||||
}
|
||||
if (details.totalItem.amount.value != "1.00") {
|
||||
emitTestFail("total item's value should be '1.00'.");
|
||||
}
|
||||
|
||||
if (details.displayItems) {
|
||||
emitTestFail("details.displayItems should be undefined.");
|
||||
}
|
||||
if (details.modifiers) {
|
||||
emitTestFail("details.displayItems should be undefined.");
|
||||
}
|
||||
const shippingOptions = details.shippingOptions;
|
||||
if (!shippingOptions) {
|
||||
emitTestFail("details.shippingOptions should not be undefined.");
|
||||
}
|
||||
if (shippingOptions.length != 0) {
|
||||
emitTestFail("shippingOptions' length should be 0.");
|
||||
}
|
||||
|
||||
// checking the default generated PaymentOptions parameter
|
||||
const paymentOptions = payRequest.paymentOptions;
|
||||
if (paymentOptions.requestPayerName) {
|
||||
emitTestFail("requestPayerName option should be false.");
|
||||
}
|
||||
if (paymentOptions.requestPayerEmail) {
|
||||
emitTestFail("requestPayerEmail option should be false.");
|
||||
}
|
||||
if (paymentOptions.requestPayerPhone) {
|
||||
emitTestFail("requestPayerPhone option should be false.");
|
||||
}
|
||||
if (paymentOptions.requestShipping) {
|
||||
emitTestFail("requestShipping option should be false.");
|
||||
}
|
||||
if (paymentOptions.shippingType != "shipping") {
|
||||
emitTestFail("shippingType option should be 'shipping'.")
|
||||
}
|
||||
}
|
||||
|
||||
function checkSimplestRequestHandler() {
|
||||
const paymentEnum = paymentSrv.enumerate();
|
||||
if (!paymentEnum.hasMoreElements()) {
|
||||
|
@ -261,6 +322,23 @@ function checkComplexRequestHandler() {
|
|||
sendAsyncMessage("check-complete");
|
||||
}
|
||||
|
||||
function checkDuplicateShippingOptionsRequestHandler() {
|
||||
const paymentEnum = paymentSrv.enumerate();
|
||||
if (!paymentEnum.hasMoreElements()) {
|
||||
emitTestFail("PaymentRequestService should have at least one payment request.");
|
||||
}
|
||||
while (paymentEnum.hasMoreElements()) {
|
||||
let payRequest = paymentEnum.getNext().QueryInterface(Ci.nsIPaymentRequest);
|
||||
if (!payRequest) {
|
||||
emitTestFail("Fail to get existing payment request.");
|
||||
break;
|
||||
}
|
||||
checkDuplicateShippingOptionsRequest(payRequest);
|
||||
}
|
||||
paymentSrv.cleanup();
|
||||
sendAsyncMessage("check-complete");
|
||||
}
|
||||
|
||||
function checkMultipleRequestsHandler () {
|
||||
const paymentEnum = paymentSrv.enumerate();
|
||||
if (!paymentEnum.hasMoreElements()) {
|
||||
|
@ -272,10 +350,12 @@ function checkMultipleRequestsHandler () {
|
|||
emitTestFail("Fail to get existing payment request.");
|
||||
break;
|
||||
}
|
||||
if (payRequest.paymentDetails.id != "payment details") {
|
||||
checkSimplestRequest(payRequest);
|
||||
} else {
|
||||
if (payRequest.paymentDetails.id == "payment details") {
|
||||
checkComplexRequest(payRequest);
|
||||
} else if (payRequest.paymentDetails.id == "duplicate shipping options details") {
|
||||
checkDuplicateShippingOptionsRequest(payRequest);
|
||||
} else {
|
||||
checkSimplestRequest(payRequest);
|
||||
}
|
||||
}
|
||||
paymentSrv.cleanup();
|
||||
|
@ -284,6 +364,7 @@ function checkMultipleRequestsHandler () {
|
|||
|
||||
addMessageListener("check-simplest-request", checkSimplestRequestHandler);
|
||||
addMessageListener("check-complex-request", checkComplexRequestHandler);
|
||||
addMessageListener("check-duplicate-shipping-options-request", checkDuplicateShippingOptionsRequestHandler);
|
||||
addMessageListener("check-multiple-requests", checkMultipleRequestsHandler);
|
||||
|
||||
addMessageListener("teardown", function() {
|
||||
|
|
|
@ -22,6 +22,8 @@ add_task(async function() {
|
|||
checkComplexPayment(payment);
|
||||
} else if (payment.paymentDetails.id == "simple details") {
|
||||
checkSimplePayment(payment);
|
||||
} else if (payment.paymentDetails.id == "duplicate shipping options details") {
|
||||
checkDupShippingOptionsPayment(payment);
|
||||
} else {
|
||||
ok(false, "Unknown payment.");
|
||||
}
|
||||
|
|
|
@ -101,6 +101,34 @@ function checkComplexPayment(aPayment) {
|
|||
is(paymentOptions.shippingType, "shipping", "shippingType option should be 'shipping'");
|
||||
}
|
||||
|
||||
function checkDupShippingOptionsPayment(aPayment) {
|
||||
// checking the passed PaymentMethods parameter
|
||||
is(aPayment.paymentMethods.length, 1, "paymentMethods' length should be 1.");
|
||||
|
||||
const methodData = aPayment.paymentMethods.queryElementAt(0, Ci.nsIPaymentMethodData);
|
||||
ok(methodData, "Fail to get payment methodData.");
|
||||
is(methodData.supportedMethods, "MyPay", "modifier's supported method name should be 'MyPay'.");
|
||||
is(methodData.data, "", "method data should be empty");
|
||||
|
||||
// checking the passed PaymentDetails parameter
|
||||
const details = aPayment.paymentDetails;
|
||||
is(details.id, "duplicate shipping options details", "details.id should be 'duplicate shipping options details'.");
|
||||
is(details.totalItem.label, "Donation", "total item's label should be 'Donation'.");
|
||||
is(details.totalItem.amount.currency, "USD", "total item's currency should be 'USD'.");
|
||||
is(details.totalItem.amount.value, "55.00", "total item's value should be '55.00'.");
|
||||
|
||||
const shippingOptions = details.shippingOptions;
|
||||
is(shippingOptions.length, 0, "shippingOptions' length should be 0.");
|
||||
|
||||
// checking the passed PaymentOptions parameter
|
||||
const paymentOptions = aPayment.paymentOptions;
|
||||
ok(paymentOptions.requestPayerName, "payerName option should be true");
|
||||
ok(paymentOptions.requestPayerEmail, "payerEmail option should be true");
|
||||
ok(paymentOptions.requestPayerPhone, "payerPhone option should be true");
|
||||
ok(paymentOptions.requestShipping, "requestShipping option should be true");
|
||||
is(paymentOptions.shippingType, "shipping", "shippingType option should be 'shipping'");
|
||||
}
|
||||
|
||||
function cleanup() {
|
||||
const paymentSrv = Cc["@mozilla.org/dom/payments/payment-request-service;1"].getService(Ci.nsIPaymentRequestService);
|
||||
if (paymentSrv) {
|
||||
|
|
|
@ -66,6 +66,28 @@
|
|||
},
|
||||
};
|
||||
|
||||
const dupShippingOptionsDetails = {
|
||||
id: "duplicate shipping options details",
|
||||
total: {
|
||||
label: "Donation",
|
||||
amount: { currency: "USD", value: "55.00" }
|
||||
},
|
||||
shippingOptions: [
|
||||
{
|
||||
id: "dupShipping",
|
||||
label: "NormalShipping",
|
||||
amount: { currency: "USD", value: "10.00", },
|
||||
selected: true,
|
||||
},
|
||||
{
|
||||
id: "dupShipping",
|
||||
label: "FastShipping",
|
||||
amount: { currency: "USD", value: "30.00", },
|
||||
selected: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const options = {
|
||||
requestPayerName: true,
|
||||
requestPayerEmail: true,
|
||||
|
@ -79,6 +101,9 @@
|
|||
options);
|
||||
const paymentRequest2 = new PaymentRequest(supportedInstruments,
|
||||
simpleDetails);
|
||||
const paymentRequest3 = new PaymentRequest(supportedInstruments,
|
||||
dupShippingOptionsDetails,
|
||||
options);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -121,6 +121,37 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1345361
|
|||
shippingType: "shipping"
|
||||
};
|
||||
|
||||
const duplicateShippingOptionsDetails = {
|
||||
id: "duplicate shipping options details",
|
||||
total: {
|
||||
label: "Total",
|
||||
amount: {
|
||||
currency: "USD",
|
||||
value: "1.00"
|
||||
}
|
||||
},
|
||||
shippingOptions: [
|
||||
{
|
||||
id: "dupShipping",
|
||||
label: "NormalShipping",
|
||||
amount: {
|
||||
currency: "USD",
|
||||
value: "10.00"
|
||||
},
|
||||
selected: true,
|
||||
},
|
||||
{
|
||||
id: "dupShipping",
|
||||
label: "FastShipping",
|
||||
amount: {
|
||||
currency: "USD",
|
||||
value: "30.00"
|
||||
},
|
||||
selected: false,
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
|
||||
function testWithSimplestParameters() {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
@ -146,12 +177,26 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1345361
|
|||
});
|
||||
}
|
||||
|
||||
function testWithDuplicateShippingOptionsParameters() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const payRequest = new PaymentRequest(simplestMethods, duplicateShippingOptionsDetails);
|
||||
ok(payRequest, "PaymentRequest should be created");
|
||||
gScript.addMessageListener("check-complete", function checkCompleteHandler() {
|
||||
gScript.removeMessageListener("check-complete", checkCompleteHandler);
|
||||
resolve();
|
||||
});
|
||||
gScript.sendAsyncMessage("check-duplicate-shipping-options-request");
|
||||
});
|
||||
}
|
||||
|
||||
function testMultipleRequests() {
|
||||
return new Promise((resolve, reject) => {
|
||||
const payRequest1 = new PaymentRequest(complexMethods, complexDetails, complexOptions);
|
||||
const payRequest2 = new PaymentRequest(simplestMethods, simplestDetails);
|
||||
const payRequest3 = new PaymentRequest(simplestMethods, duplicateShippingOptionsDetails);
|
||||
ok(payRequest1, "PaymentRequest with complex parameters should be created");
|
||||
ok(payRequest2, "PaymentRequest with simplest parameters should be created");
|
||||
ok(payRequest3, "PaymentRequest with duplicate shipping options parameters should be created");
|
||||
gScript.addMessageListener("check-complete", function checkCompleteHandler() {
|
||||
gScript.removeMessageListener("check-complete", checkCompleteHandler);
|
||||
resolve();
|
||||
|
@ -173,6 +218,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=1345361
|
|||
function runTests() {
|
||||
testWithSimplestParameters()
|
||||
.then(testWithComplexParameters)
|
||||
.then(testWithDuplicateShippingOptionsParameters)
|
||||
.then(testMultipleRequests)
|
||||
.then(teardown)
|
||||
.catch( e => {
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
@ -29,10 +30,6 @@
|
|||
#include "js/TracingAPI.h"
|
||||
#include "mozilla/HashFunctions.h"
|
||||
#include "mozilla/dom/ScriptSettings.h"
|
||||
#include "mozilla/plugins/PluginAsyncSurrogate.h"
|
||||
|
||||
using mozilla::plugins::AsyncNPObject;
|
||||
using mozilla::plugins::PluginAsyncSurrogate;
|
||||
|
||||
#define NPRUNTIME_JSCLASS_NAME "NPObject JS wrapper class"
|
||||
|
||||
|
@ -109,24 +106,10 @@ static nsTArray<NPObject*>* sDelayedReleases;
|
|||
|
||||
namespace {
|
||||
|
||||
inline void
|
||||
CastNPObject(NPObject *aObj, PluginScriptableObjectParent*& aActor,
|
||||
PluginAsyncSurrogate*& aSurrogate)
|
||||
{
|
||||
aActor = nullptr;
|
||||
aSurrogate = nullptr;
|
||||
if (aObj->_class == PluginScriptableObjectParent::GetClass()) {
|
||||
aActor = static_cast<ParentNPObject*>(aObj)->parent;
|
||||
} else if (aObj->_class == PluginAsyncSurrogate::GetClass()) {
|
||||
aSurrogate = static_cast<AsyncNPObject*>(aObj)->mSurrogate;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
NPObjectIsOutOfProcessProxy(NPObject *obj)
|
||||
{
|
||||
return obj->_class == PluginScriptableObjectParent::GetClass() ||
|
||||
obj->_class == PluginAsyncSurrogate::GetClass();
|
||||
return obj->_class == PluginScriptableObjectParent::GetClass();
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
@ -1097,17 +1080,6 @@ nsJSObjWrapper::GetNewOrUsed(NPP npp, JS::Handle<JSObject*> obj)
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
// If we're running out-of-process and initializing asynchronously, and if
|
||||
// the plugin has been asked to destroy itself during initialization,
|
||||
// don't return any new NPObjects.
|
||||
nsNPAPIPluginInstance* inst = static_cast<nsNPAPIPluginInstance*>(npp->ndata);
|
||||
if (inst->GetPlugin()->GetLibrary()->IsOOP()) {
|
||||
PluginAsyncSurrogate* surrogate = PluginAsyncSurrogate::Cast(npp);
|
||||
if (surrogate && surrogate->IsDestroyPending()) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
// No need to enter the right compartment here as we only get the
|
||||
// class and private from the JSObject, neither of which cares about
|
||||
// compartments.
|
||||
|
@ -1404,22 +1376,15 @@ NPObjWrapper_GetProperty(JSContext *cx, JS::Handle<JSObject*> obj, JS::Handle<js
|
|||
NPIdentifier identifier = JSIdToNPIdentifier(id);
|
||||
|
||||
if (NPObjectIsOutOfProcessProxy(npobj)) {
|
||||
PluginScriptableObjectParent* actor = nullptr;
|
||||
PluginAsyncSurrogate* surrogate = nullptr;
|
||||
CastNPObject(npobj, actor, surrogate);
|
||||
PluginScriptableObjectParent* actor =
|
||||
static_cast<ParentNPObject*>(npobj)->parent;
|
||||
|
||||
// actor and surrogate may be null if the plugin crashed.
|
||||
if (!actor && !surrogate)
|
||||
// actor may be null if the plugin crashed.
|
||||
if (!actor)
|
||||
return false;
|
||||
|
||||
bool success = false;
|
||||
if (surrogate) {
|
||||
success = surrogate->GetPropertyHelper(npobj, identifier, &hasProperty,
|
||||
&hasMethod, &npv);
|
||||
} else if (actor) {
|
||||
success = actor->GetPropertyHelper(identifier, &hasProperty, &hasMethod,
|
||||
&npv);
|
||||
}
|
||||
bool success = actor->GetPropertyHelper(identifier, &hasProperty,
|
||||
&hasMethod, &npv);
|
||||
|
||||
if (!ReportExceptionIfPending(cx)) {
|
||||
if (success)
|
||||
|
|
|
@ -53,7 +53,6 @@
|
|||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/dom/FakePluginTagInitBinding.h"
|
||||
#include "mozilla/LoadInfo.h"
|
||||
#include "mozilla/plugins/PluginAsyncSurrogate.h"
|
||||
#include "mozilla/plugins/PluginBridge.h"
|
||||
#include "mozilla/plugins/PluginTypes.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
@ -119,7 +118,6 @@ using namespace mozilla;
|
|||
using mozilla::TimeStamp;
|
||||
using mozilla::plugins::FakePluginTag;
|
||||
using mozilla::plugins::PluginTag;
|
||||
using mozilla::plugins::PluginAsyncSurrogate;
|
||||
using mozilla::dom::FakePluginTagInit;
|
||||
using mozilla::dom::FakePluginMimeEntry;
|
||||
|
||||
|
@ -758,7 +756,6 @@ nsPluginHost::InstantiatePluginInstance(const nsACString& aMimeType, nsIURI* aUR
|
|||
instanceOwner->Destroy();
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
const bool isAsyncInit = (rv == NS_PLUGIN_INIT_PENDING);
|
||||
|
||||
RefPtr<nsNPAPIPluginInstance> instance;
|
||||
rv = instanceOwner->GetInstance(getter_AddRefs(instance));
|
||||
|
@ -767,8 +764,7 @@ nsPluginHost::InstantiatePluginInstance(const nsACString& aMimeType, nsIURI* aUR
|
|||
return rv;
|
||||
}
|
||||
|
||||
// Async init plugins will initiate their own widget creation.
|
||||
if (!isAsyncInit && instance) {
|
||||
if (instance) {
|
||||
CreateWidget(instanceOwner);
|
||||
}
|
||||
|
||||
|
@ -2383,7 +2379,6 @@ nsPluginHost::SetPluginsInContent(uint32_t aPluginEpoch,
|
|||
nsTArray<nsCString>(tag.extensions()),
|
||||
tag.isJavaPlugin(),
|
||||
tag.isFlashPlugin(),
|
||||
tag.supportsAsyncInit(),
|
||||
tag.supportsAsyncRender(),
|
||||
tag.lastModifiedTime(),
|
||||
tag.isFromExtension(),
|
||||
|
@ -2624,7 +2619,6 @@ nsPluginHost::SendPluginsToContent()
|
|||
tag->Extensions(),
|
||||
tag->mIsJavaPlugin,
|
||||
tag->mIsFlashPlugin,
|
||||
tag->mSupportsAsyncInit,
|
||||
tag->mSupportsAsyncRender,
|
||||
tag->FileName(),
|
||||
tag->Version(),
|
||||
|
@ -4023,12 +4017,6 @@ PluginDestructionGuard::PluginDestructionGuard(nsNPAPIPluginInstance *aInstance)
|
|||
Init();
|
||||
}
|
||||
|
||||
PluginDestructionGuard::PluginDestructionGuard(PluginAsyncSurrogate *aSurrogate)
|
||||
: mInstance(static_cast<nsNPAPIPluginInstance*>(aSurrogate->GetNPP()->ndata))
|
||||
{
|
||||
InitAsync();
|
||||
}
|
||||
|
||||
PluginDestructionGuard::PluginDestructionGuard(NPP npp)
|
||||
: mInstance(npp ? static_cast<nsNPAPIPluginInstance*>(npp->ndata) : nullptr)
|
||||
{
|
||||
|
|
|
@ -35,7 +35,6 @@
|
|||
namespace mozilla {
|
||||
namespace plugins {
|
||||
class FakePluginTag;
|
||||
class PluginAsyncSurrogate;
|
||||
class PluginTag;
|
||||
} // namespace plugins
|
||||
} // namespace mozilla
|
||||
|
@ -425,7 +424,6 @@ class PluginDestructionGuard : public mozilla::LinkedListElement<PluginDestructi
|
|||
{
|
||||
public:
|
||||
explicit PluginDestructionGuard(nsNPAPIPluginInstance *aInstance);
|
||||
explicit PluginDestructionGuard(mozilla::plugins::PluginAsyncSurrogate *aSurrogate);
|
||||
explicit PluginDestructionGuard(NPP npp);
|
||||
|
||||
~PluginDestructionGuard();
|
||||
|
@ -442,17 +440,6 @@ protected:
|
|||
sList.insertBack(this);
|
||||
}
|
||||
|
||||
void InitAsync()
|
||||
{
|
||||
NS_ASSERTION(NS_IsMainThread(), "Should be on the main thread");
|
||||
|
||||
mDelayedDestroy = false;
|
||||
|
||||
// Instances with active surrogates must be inserted *in front of* sList so
|
||||
// that they appear to be at the bottom of the stack
|
||||
sList.insertFront(this);
|
||||
}
|
||||
|
||||
RefPtr<nsNPAPIPluginInstance> mInstance;
|
||||
bool mDelayedDestroy;
|
||||
|
||||
|
|
|
@ -1668,45 +1668,6 @@ void nsPluginInstanceOwner::ExitFullScreen(jobject view) {
|
|||
|
||||
#endif
|
||||
|
||||
void
|
||||
nsPluginInstanceOwner::NotifyHostAsyncInitFailed()
|
||||
{
|
||||
nsCOMPtr<nsIObjectLoadingContent> content = do_QueryReferent(mContent);
|
||||
content->StopPluginInstance();
|
||||
}
|
||||
|
||||
void
|
||||
nsPluginInstanceOwner::NotifyHostCreateWidget()
|
||||
{
|
||||
mPluginHost->CreateWidget(this);
|
||||
#ifdef XP_MACOSX
|
||||
FixUpPluginWindow(ePluginPaintEnable);
|
||||
#else
|
||||
if (mPluginFrame) {
|
||||
mPluginFrame->InvalidateFrame();
|
||||
} else {
|
||||
CallSetWindow();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
nsPluginInstanceOwner::NotifyDestroyPending()
|
||||
{
|
||||
if (!mInstance) {
|
||||
return;
|
||||
}
|
||||
bool isOOP = false;
|
||||
if (NS_FAILED(mInstance->GetIsOOP(&isOOP)) || !isOOP) {
|
||||
return;
|
||||
}
|
||||
NPP npp = nullptr;
|
||||
if (NS_FAILED(mInstance->GetNPP(&npp)) || !npp) {
|
||||
return;
|
||||
}
|
||||
PluginAsyncSurrogate::NotifyDestroyPending(npp);
|
||||
}
|
||||
|
||||
nsresult nsPluginInstanceOwner::DispatchFocusToPlugin(nsIDOMEvent* aFocusEvent)
|
||||
{
|
||||
#ifdef MOZ_WIDGET_ANDROID
|
||||
|
|
|
@ -269,10 +269,6 @@ public:
|
|||
static void ExitFullScreen(jobject view);
|
||||
#endif
|
||||
|
||||
void NotifyHostAsyncInitFailed();
|
||||
void NotifyHostCreateWidget();
|
||||
void NotifyDestroyPending();
|
||||
|
||||
bool GetCompositionString(uint32_t aIndex, nsTArray<uint8_t>* aString,
|
||||
int32_t* aLength);
|
||||
bool SetCandidateWindow(
|
||||
|
|
|
@ -233,7 +233,6 @@ nsPluginTag::nsPluginTag(nsPluginInfo* aPluginInfo,
|
|||
mLibrary(nullptr),
|
||||
mIsJavaPlugin(false),
|
||||
mIsFlashPlugin(false),
|
||||
mSupportsAsyncInit(false),
|
||||
mSupportsAsyncRender(false),
|
||||
mFullPath(aPluginInfo->fFullPath),
|
||||
mLastModifiedTime(aLastModifiedTime),
|
||||
|
@ -270,7 +269,6 @@ nsPluginTag::nsPluginTag(const char* aName,
|
|||
mLibrary(nullptr),
|
||||
mIsJavaPlugin(false),
|
||||
mIsFlashPlugin(false),
|
||||
mSupportsAsyncInit(false),
|
||||
mSupportsAsyncRender(false),
|
||||
mFullPath(aFullPath),
|
||||
mLastModifiedTime(aLastModifiedTime),
|
||||
|
@ -298,7 +296,6 @@ nsPluginTag::nsPluginTag(uint32_t aId,
|
|||
nsTArray<nsCString> aExtensions,
|
||||
bool aIsJavaPlugin,
|
||||
bool aIsFlashPlugin,
|
||||
bool aSupportsAsyncInit,
|
||||
bool aSupportsAsyncRender,
|
||||
int64_t aLastModifiedTime,
|
||||
bool aFromExtension,
|
||||
|
@ -310,7 +307,6 @@ nsPluginTag::nsPluginTag(uint32_t aId,
|
|||
mLibrary(nullptr),
|
||||
mIsJavaPlugin(aIsJavaPlugin),
|
||||
mIsFlashPlugin(aIsFlashPlugin),
|
||||
mSupportsAsyncInit(aSupportsAsyncInit),
|
||||
mSupportsAsyncRender(aSupportsAsyncRender),
|
||||
mLastModifiedTime(aLastModifiedTime),
|
||||
mSandboxLevel(aSandboxLevel),
|
||||
|
@ -356,25 +352,17 @@ void nsPluginTag::InitMime(const char* const* aMimeTypes,
|
|||
switch (nsPluginHost::GetSpecialType(mimeType)) {
|
||||
case nsPluginHost::eSpecialType_Java:
|
||||
mIsJavaPlugin = true;
|
||||
mSupportsAsyncInit = true;
|
||||
break;
|
||||
case nsPluginHost::eSpecialType_Flash:
|
||||
// VLC sometimes claims to implement the Flash MIME type, and we want
|
||||
// to allow users to control that separately from Adobe Flash.
|
||||
if (Name().EqualsLiteral("Shockwave Flash")) {
|
||||
mIsFlashPlugin = true;
|
||||
mSupportsAsyncInit = true;
|
||||
}
|
||||
break;
|
||||
case nsPluginHost::eSpecialType_Test:
|
||||
mSupportsAsyncInit = true;
|
||||
break;
|
||||
case nsPluginHost::eSpecialType_None:
|
||||
default:
|
||||
#ifndef RELEASE_OR_BETA
|
||||
// Allow async init for all plugins on Nightly and Aurora
|
||||
mSupportsAsyncInit = true;
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -132,7 +132,6 @@ public:
|
|||
nsTArray<nsCString> aExtensions,
|
||||
bool aIsJavaPlugin,
|
||||
bool aIsFlashPlugin,
|
||||
bool aSupportsAsyncInit,
|
||||
bool aSupportsAsyncRender,
|
||||
int64_t aLastModifiedTime,
|
||||
bool aFromExtension,
|
||||
|
@ -169,7 +168,6 @@ public:
|
|||
RefPtr<nsNPAPIPlugin> mPlugin;
|
||||
bool mIsJavaPlugin;
|
||||
bool mIsFlashPlugin;
|
||||
bool mSupportsAsyncInit;
|
||||
bool mSupportsAsyncRender;
|
||||
nsCString mFullPath; // UTF-8
|
||||
int64_t mLastModifiedTime;
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
|
||||
|
||||
#include "BrowserStreamParent.h"
|
||||
#include "PluginAsyncSurrogate.h"
|
||||
#include "PluginInstanceParent.h"
|
||||
#include "nsNPAPIPlugin.h"
|
||||
|
||||
|
@ -23,7 +22,6 @@ BrowserStreamParent::BrowserStreamParent(PluginInstanceParent* npp,
|
|||
NPStream* stream)
|
||||
: mNPP(npp)
|
||||
, mStream(stream)
|
||||
, mDeferredDestroyReason(NPRES_DONE)
|
||||
, mState(INITIALIZING)
|
||||
{
|
||||
mStream->pdata = static_cast<AStream*>(this);
|
||||
|
@ -45,41 +43,6 @@ BrowserStreamParent::ActorDestroy(ActorDestroyReason aWhy)
|
|||
// Implement me! Bug 1005159
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
BrowserStreamParent::RecvAsyncNPP_NewStreamResult(const NPError& rv,
|
||||
const uint16_t& stype)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_FUNCTION;
|
||||
PluginAsyncSurrogate* surrogate = mNPP->GetAsyncSurrogate();
|
||||
MOZ_ASSERT(surrogate);
|
||||
surrogate->AsyncCallArriving();
|
||||
if (mState == DEFERRING_DESTROY) {
|
||||
// We've been asked to destroy ourselves before init was complete.
|
||||
mState = DYING;
|
||||
Unused << SendNPP_DestroyStream(mDeferredDestroyReason);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
NPError error = rv;
|
||||
if (error == NPERR_NO_ERROR) {
|
||||
if (!mStreamListener) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
if (mStreamListener->SetStreamType(stype)) {
|
||||
mState = ALIVE;
|
||||
} else {
|
||||
error = NPERR_GENERIC_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
if (error != NPERR_NO_ERROR) {
|
||||
surrogate->DestroyAsyncStream(mStream);
|
||||
Unused << PBrowserStreamParent::Send__delete__(this);
|
||||
}
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
BrowserStreamParent::AnswerNPN_RequestRead(const IPCByteRanges& ranges,
|
||||
NPError* result)
|
||||
|
@ -149,7 +112,6 @@ BrowserStreamParent::NPP_DestroyStream(NPReason reason)
|
|||
bool stillInitializing = INITIALIZING == mState;
|
||||
if (stillInitializing) {
|
||||
mState = DEFERRING_DESTROY;
|
||||
mDeferredDestroyReason = reason;
|
||||
} else {
|
||||
mState = DYING;
|
||||
Unused << SendNPP_DestroyStream(reason);
|
||||
|
|
|
@ -30,10 +30,6 @@ public:
|
|||
|
||||
virtual void ActorDestroy(ActorDestroyReason aWhy) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult RecvAsyncNPP_NewStreamResult(
|
||||
const NPError& rv,
|
||||
const uint16_t& stype) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult AnswerNPN_RequestRead(const IPCByteRanges& ranges,
|
||||
NPError* result) override;
|
||||
|
||||
|
@ -61,7 +57,6 @@ private:
|
|||
NPStream* mStream;
|
||||
nsCOMPtr<nsISupports> mStreamPeer;
|
||||
RefPtr<nsNPAPIPluginStreamListener> mStreamListener;
|
||||
NPReason mDeferredDestroyReason;
|
||||
|
||||
enum {
|
||||
INITIALIZING,
|
||||
|
|
|
@ -36,7 +36,6 @@ child:
|
|||
async __delete__();
|
||||
|
||||
parent:
|
||||
async AsyncNPP_NewStreamResult(NPError rv, uint16_t stype);
|
||||
intr NPN_RequestRead(IPCByteRanges ranges)
|
||||
returns (NPError result);
|
||||
async NPN_DestroyStream(NPReason reason);
|
||||
|
|
|
@ -254,9 +254,6 @@ parent:
|
|||
|
||||
async RedrawPlugin();
|
||||
|
||||
// Notifies the parent of its NPP_New result code.
|
||||
async AsyncNPP_NewResult(NPError aResult);
|
||||
|
||||
// Sends a native window to be adopted by the native window that would be
|
||||
// returned by NPN_GetValue_NPNVnetscapeWindow. Only used on Windows.
|
||||
async SetNetscapeWindowAsParent(NativeWindowHandle childWindow);
|
||||
|
@ -293,9 +290,6 @@ child:
|
|||
returns (NPError rv,
|
||||
uint16_t stype);
|
||||
|
||||
// Implements the async plugin init version of NPP_NewStream.
|
||||
async AsyncNPP_NewStream(PBrowserStream actor, nsCString mimeType, bool seekable);
|
||||
|
||||
parent:
|
||||
/* NPN_NewStream */
|
||||
intr PPluginStream(nsCString mimeType,
|
||||
|
|
|
@ -62,8 +62,6 @@ child:
|
|||
intr NP_Initialize(PluginSettings settings)
|
||||
returns (NPError rv);
|
||||
|
||||
async AsyncNP_Initialize(PluginSettings settings);
|
||||
|
||||
async PPluginInstance(nsCString aMimeType,
|
||||
nsCString[] aNames,
|
||||
nsCString[] aValues);
|
||||
|
@ -73,9 +71,6 @@ child:
|
|||
intr SyncNPP_New(PPluginInstance aActor)
|
||||
returns (NPError rv);
|
||||
|
||||
// Implements the async plugin init version of NPP_New.
|
||||
async AsyncNPP_New(PPluginInstance aActor);
|
||||
|
||||
intr NP_Shutdown()
|
||||
returns (NPError rv);
|
||||
|
||||
|
@ -104,8 +99,6 @@ child:
|
|||
async InitPluginModuleChild(Endpoint<PPluginModuleChild> endpoint);
|
||||
|
||||
parent:
|
||||
async NP_InitializeResult(NPError aError);
|
||||
|
||||
/**
|
||||
* This message is only used on X11 platforms.
|
||||
*
|
||||
|
|
|
@ -1,996 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "PluginAsyncSurrogate.h"
|
||||
|
||||
#include "base/message_loop.h"
|
||||
#include "base/message_pump_default.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/plugins/PluginInstanceParent.h"
|
||||
#include "mozilla/plugins/PluginModuleParent.h"
|
||||
#include "mozilla/plugins/PluginScriptableObjectParent.h"
|
||||
#include "mozilla/Telemetry.h"
|
||||
#include "nsJSNPRuntime.h"
|
||||
#include "nsNPAPIPlugin.h"
|
||||
#include "nsNPAPIPluginInstance.h"
|
||||
#include "nsNPAPIPluginStreamListener.h"
|
||||
#include "nsPluginInstanceOwner.h"
|
||||
#include "nsPluginStreamListenerPeer.h"
|
||||
#include "npruntime.h"
|
||||
#include "nsThreadUtils.h"
|
||||
#include "PluginMessageUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace plugins {
|
||||
|
||||
AsyncNPObject::AsyncNPObject(PluginAsyncSurrogate* aSurrogate)
|
||||
: NPObject()
|
||||
, mSurrogate(aSurrogate)
|
||||
, mRealObject(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
AsyncNPObject::~AsyncNPObject()
|
||||
{
|
||||
if (mRealObject) {
|
||||
--mRealObject->asyncWrapperCount;
|
||||
parent::_releaseobject(mRealObject);
|
||||
mRealObject = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
NPObject*
|
||||
AsyncNPObject::GetRealObject()
|
||||
{
|
||||
if (mRealObject) {
|
||||
return mRealObject;
|
||||
}
|
||||
PluginInstanceParent* instance = PluginInstanceParent::Cast(mSurrogate->GetNPP());
|
||||
if (!instance) {
|
||||
return nullptr;
|
||||
}
|
||||
NPObject* realObject = nullptr;
|
||||
NPError err = instance->NPP_GetValue(NPPVpluginScriptableNPObject,
|
||||
&realObject);
|
||||
if (err != NPERR_NO_ERROR) {
|
||||
return nullptr;
|
||||
}
|
||||
if (realObject->_class != PluginScriptableObjectParent::GetClass()) {
|
||||
NS_ERROR("Don't know what kind of object this is!");
|
||||
parent::_releaseobject(realObject);
|
||||
return nullptr;
|
||||
}
|
||||
mRealObject = static_cast<ParentNPObject*>(realObject);
|
||||
++mRealObject->asyncWrapperCount;
|
||||
return mRealObject;
|
||||
}
|
||||
|
||||
class MOZ_STACK_CLASS RecursionGuard
|
||||
{
|
||||
public:
|
||||
RecursionGuard()
|
||||
: mIsRecursive(sHasEntered)
|
||||
{
|
||||
if (!mIsRecursive) {
|
||||
sHasEntered = true;
|
||||
}
|
||||
}
|
||||
|
||||
~RecursionGuard()
|
||||
{
|
||||
if (!mIsRecursive) {
|
||||
sHasEntered = false;
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
IsRecursive()
|
||||
{
|
||||
return mIsRecursive;
|
||||
}
|
||||
|
||||
private:
|
||||
bool mIsRecursive;
|
||||
static bool sHasEntered;
|
||||
};
|
||||
|
||||
bool RecursionGuard::sHasEntered = false;
|
||||
|
||||
PluginAsyncSurrogate::PluginAsyncSurrogate(PluginModuleParent* aParent)
|
||||
: mParent(aParent)
|
||||
, mWindow(nullptr)
|
||||
, mAcceptCalls(false)
|
||||
, mInstantiated(false)
|
||||
, mAsyncSetWindow(false)
|
||||
, mInitCancelled(false)
|
||||
, mDestroyPending(false)
|
||||
, mAsyncCallsInFlight(0)
|
||||
{
|
||||
MOZ_ASSERT(aParent);
|
||||
}
|
||||
|
||||
PluginAsyncSurrogate::~PluginAsyncSurrogate()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
PluginAsyncSurrogate::Init(NPMIMEType aPluginType, NPP aInstance,
|
||||
int16_t aArgc, char* aArgn[], char* aArgv[])
|
||||
{
|
||||
mMimeType = aPluginType;
|
||||
nsNPAPIPluginInstance* instance =
|
||||
static_cast<nsNPAPIPluginInstance*>(aInstance->ndata);
|
||||
MOZ_ASSERT(instance);
|
||||
mInstance = instance;
|
||||
for (int i = 0; i < aArgc; ++i) {
|
||||
mNames.AppendElement(NullableString(aArgn[i]));
|
||||
mValues.AppendElement(NullableString(aArgv[i]));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
PluginAsyncSurrogate::Create(PluginModuleParent* aParent, NPMIMEType aPluginType,
|
||||
NPP aInstance, int16_t aArgc,
|
||||
char* aArgn[], char* aArgv[])
|
||||
{
|
||||
RefPtr<PluginAsyncSurrogate> surrogate(new PluginAsyncSurrogate(aParent));
|
||||
if (!surrogate->Init(aPluginType, aInstance, aArgc, aArgn, aArgv)) {
|
||||
return false;
|
||||
}
|
||||
PluginAsyncSurrogate* rawSurrogate = nullptr;
|
||||
surrogate.forget(&rawSurrogate);
|
||||
aInstance->pdata = static_cast<PluginDataResolver*>(rawSurrogate);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* static */ PluginAsyncSurrogate*
|
||||
PluginAsyncSurrogate::Cast(NPP aInstance)
|
||||
{
|
||||
MOZ_ASSERT(aInstance);
|
||||
PluginDataResolver* resolver =
|
||||
reinterpret_cast<PluginDataResolver*>(aInstance->pdata);
|
||||
if (!resolver) {
|
||||
return nullptr;
|
||||
}
|
||||
return resolver->GetAsyncSurrogate();
|
||||
}
|
||||
|
||||
nsresult
|
||||
PluginAsyncSurrogate::NPP_New(NPError* aError)
|
||||
{
|
||||
if (!mInstance) {
|
||||
return NS_ERROR_NULL_POINTER;
|
||||
}
|
||||
|
||||
nsresult rv = mParent->NPP_NewInternal(mMimeType.BeginWriting(), GetNPP(),
|
||||
mNames, mValues, nullptr,
|
||||
aError);
|
||||
if (NS_FAILED(rv)) {
|
||||
return rv;
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
PluginAsyncSurrogate::NP_GetEntryPoints(NPPluginFuncs* aFuncs)
|
||||
{
|
||||
aFuncs->version = (NP_VERSION_MAJOR << 8) | NP_VERSION_MINOR;
|
||||
aFuncs->destroy = &NPP_Destroy;
|
||||
aFuncs->getvalue = &NPP_GetValue;
|
||||
aFuncs->setvalue = &NPP_SetValue;
|
||||
aFuncs->newstream = &NPP_NewStream;
|
||||
aFuncs->setwindow = &NPP_SetWindow;
|
||||
aFuncs->writeready = &NPP_WriteReady;
|
||||
aFuncs->event = &NPP_HandleEvent;
|
||||
aFuncs->destroystream = &NPP_DestroyStream;
|
||||
// We need to set these so that content code doesn't make assumptions
|
||||
// about these operations not being supported
|
||||
aFuncs->write = &PluginModuleParent::NPP_Write;
|
||||
aFuncs->asfile = &PluginModuleParent::NPP_StreamAsFile;
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
PluginAsyncSurrogate::NotifyDestroyPending(NPP aInstance)
|
||||
{
|
||||
PluginAsyncSurrogate* surrogate = Cast(aInstance);
|
||||
if (!surrogate) {
|
||||
return;
|
||||
}
|
||||
surrogate->NotifyDestroyPending();
|
||||
}
|
||||
|
||||
NPP
|
||||
PluginAsyncSurrogate::GetNPP()
|
||||
{
|
||||
MOZ_ASSERT(mInstance);
|
||||
NPP npp;
|
||||
DebugOnly<nsresult> rv = mInstance->GetNPP(&npp);
|
||||
MOZ_ASSERT(NS_SUCCEEDED(rv));
|
||||
return npp;
|
||||
}
|
||||
|
||||
void
|
||||
PluginAsyncSurrogate::NotifyDestroyPending()
|
||||
{
|
||||
mDestroyPending = true;
|
||||
nsJSNPRuntime::OnPluginDestroyPending(GetNPP());
|
||||
}
|
||||
|
||||
NPError
|
||||
PluginAsyncSurrogate::NPP_Destroy(NPSavedData** aSave)
|
||||
{
|
||||
NotifyDestroyPending();
|
||||
if (!WaitForInit()) {
|
||||
return NPERR_GENERIC_ERROR;
|
||||
}
|
||||
return PluginModuleParent::NPP_Destroy(GetNPP(), aSave);
|
||||
}
|
||||
|
||||
NPError
|
||||
PluginAsyncSurrogate::NPP_GetValue(NPPVariable aVariable, void* aRetval)
|
||||
{
|
||||
if (aVariable != NPPVpluginScriptableNPObject) {
|
||||
if (!WaitForInit()) {
|
||||
return NPERR_GENERIC_ERROR;
|
||||
}
|
||||
|
||||
PluginInstanceParent* instance = PluginInstanceParent::Cast(GetNPP());
|
||||
MOZ_ASSERT(instance);
|
||||
return instance->NPP_GetValue(aVariable, aRetval);
|
||||
}
|
||||
|
||||
NPObject* npobject = parent::_createobject(GetNPP(),
|
||||
const_cast<NPClass*>(GetClass()));
|
||||
MOZ_ASSERT(npobject);
|
||||
MOZ_ASSERT(npobject->_class == GetClass());
|
||||
MOZ_ASSERT(npobject->referenceCount == 1);
|
||||
*(NPObject**)aRetval = npobject;
|
||||
return npobject ? NPERR_NO_ERROR : NPERR_GENERIC_ERROR;
|
||||
}
|
||||
|
||||
NPError
|
||||
PluginAsyncSurrogate::NPP_SetValue(NPNVariable aVariable, void* aValue)
|
||||
{
|
||||
if (!WaitForInit()) {
|
||||
return NPERR_GENERIC_ERROR;
|
||||
}
|
||||
return PluginModuleParent::NPP_SetValue(GetNPP(), aVariable, aValue);
|
||||
}
|
||||
|
||||
NPError
|
||||
PluginAsyncSurrogate::NPP_NewStream(NPMIMEType aType, NPStream* aStream,
|
||||
NPBool aSeekable, uint16_t* aStype)
|
||||
{
|
||||
mPendingNewStreamCalls.AppendElement(PendingNewStreamCall(aType, aStream,
|
||||
aSeekable));
|
||||
if (aStype) {
|
||||
*aStype = nsPluginStreamListenerPeer::STREAM_TYPE_UNKNOWN;
|
||||
}
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
||||
NPError
|
||||
PluginAsyncSurrogate::NPP_SetWindow(NPWindow* aWindow)
|
||||
{
|
||||
mWindow = aWindow;
|
||||
mAsyncSetWindow = false;
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
||||
nsresult
|
||||
PluginAsyncSurrogate::AsyncSetWindow(NPWindow* aWindow)
|
||||
{
|
||||
mWindow = aWindow;
|
||||
mAsyncSetWindow = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
PluginAsyncSurrogate::NPP_Print(NPPrint* aPrintInfo)
|
||||
{
|
||||
// Do nothing, we've got nothing to print right now
|
||||
}
|
||||
|
||||
int16_t
|
||||
PluginAsyncSurrogate::NPP_HandleEvent(void* event)
|
||||
{
|
||||
// Drop the event -- the plugin isn't around to handle it
|
||||
return false;
|
||||
}
|
||||
|
||||
int32_t
|
||||
PluginAsyncSurrogate::NPP_WriteReady(NPStream* aStream)
|
||||
{
|
||||
// We'll tell the browser to retry in a bit. Eventually NPP_WriteReady
|
||||
// will resolve to the plugin's NPP_WriteReady and this should all just work.
|
||||
return 0;
|
||||
}
|
||||
|
||||
NPError
|
||||
PluginAsyncSurrogate::NPP_DestroyStream(NPStream* aStream, NPReason aReason)
|
||||
{
|
||||
for (uint32_t idx = 0, len = mPendingNewStreamCalls.Length(); idx < len; ++idx) {
|
||||
PendingNewStreamCall& curPendingCall = mPendingNewStreamCalls[idx];
|
||||
if (curPendingCall.mStream == aStream) {
|
||||
mPendingNewStreamCalls.RemoveElementAt(idx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
|
||||
/* static */ NPError
|
||||
PluginAsyncSurrogate::NPP_Destroy(NPP aInstance, NPSavedData** aSave)
|
||||
{
|
||||
PluginAsyncSurrogate* rawSurrogate = Cast(aInstance);
|
||||
MOZ_ASSERT(rawSurrogate);
|
||||
PluginModuleParent* module = rawSurrogate->GetParent();
|
||||
if (module && !module->IsInitialized()) {
|
||||
// Take ownership of pdata's surrogate since we're going to release it
|
||||
RefPtr<PluginAsyncSurrogate> surrogate(dont_AddRef(rawSurrogate));
|
||||
aInstance->pdata = nullptr;
|
||||
// We haven't actually called NPP_New yet, so we should remove the
|
||||
// surrogate for this instance.
|
||||
bool removeOk = module->RemovePendingSurrogate(surrogate);
|
||||
MOZ_ASSERT(removeOk);
|
||||
if (!removeOk) {
|
||||
return NPERR_GENERIC_ERROR;
|
||||
}
|
||||
surrogate->mInitCancelled = true;
|
||||
return NPERR_NO_ERROR;
|
||||
}
|
||||
return rawSurrogate->NPP_Destroy(aSave);
|
||||
}
|
||||
|
||||
/* static */ NPError
|
||||
PluginAsyncSurrogate::NPP_GetValue(NPP aInstance, NPPVariable aVariable,
|
||||
void* aRetval)
|
||||
{
|
||||
PluginAsyncSurrogate* surrogate = Cast(aInstance);
|
||||
MOZ_ASSERT(surrogate);
|
||||
return surrogate->NPP_GetValue(aVariable, aRetval);
|
||||
}
|
||||
|
||||
/* static */ NPError
|
||||
PluginAsyncSurrogate::NPP_SetValue(NPP aInstance, NPNVariable aVariable,
|
||||
void* aValue)
|
||||
{
|
||||
PluginAsyncSurrogate* surrogate = Cast(aInstance);
|
||||
MOZ_ASSERT(surrogate);
|
||||
return surrogate->NPP_SetValue(aVariable, aValue);
|
||||
}
|
||||
|
||||
/* static */ NPError
|
||||
PluginAsyncSurrogate::NPP_NewStream(NPP aInstance, NPMIMEType aType,
|
||||
NPStream* aStream, NPBool aSeekable,
|
||||
uint16_t* aStype)
|
||||
{
|
||||
PluginAsyncSurrogate* surrogate = Cast(aInstance);
|
||||
MOZ_ASSERT(surrogate);
|
||||
return surrogate->NPP_NewStream(aType, aStream, aSeekable, aStype);
|
||||
}
|
||||
|
||||
/* static */ NPError
|
||||
PluginAsyncSurrogate::NPP_SetWindow(NPP aInstance, NPWindow* aWindow)
|
||||
{
|
||||
PluginAsyncSurrogate* surrogate = Cast(aInstance);
|
||||
MOZ_ASSERT(surrogate);
|
||||
return surrogate->NPP_SetWindow(aWindow);
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
PluginAsyncSurrogate::NPP_Print(NPP aInstance, NPPrint* aPrintInfo)
|
||||
{
|
||||
PluginAsyncSurrogate* surrogate = Cast(aInstance);
|
||||
MOZ_ASSERT(surrogate);
|
||||
surrogate->NPP_Print(aPrintInfo);
|
||||
}
|
||||
|
||||
/* static */ int16_t
|
||||
PluginAsyncSurrogate::NPP_HandleEvent(NPP aInstance, void* aEvent)
|
||||
{
|
||||
PluginAsyncSurrogate* surrogate = Cast(aInstance);
|
||||
MOZ_ASSERT(surrogate);
|
||||
return surrogate->NPP_HandleEvent(aEvent);
|
||||
}
|
||||
|
||||
/* static */ int32_t
|
||||
PluginAsyncSurrogate::NPP_WriteReady(NPP aInstance, NPStream* aStream)
|
||||
{
|
||||
PluginAsyncSurrogate* surrogate = Cast(aInstance);
|
||||
MOZ_ASSERT(surrogate);
|
||||
return surrogate->NPP_WriteReady(aStream);
|
||||
}
|
||||
|
||||
/* static */ NPError
|
||||
PluginAsyncSurrogate::NPP_DestroyStream(NPP aInstance,
|
||||
NPStream* aStream,
|
||||
NPReason aReason)
|
||||
{
|
||||
PluginAsyncSurrogate* surrogate = Cast(aInstance);
|
||||
MOZ_ASSERT(surrogate);
|
||||
return surrogate->NPP_DestroyStream(aStream, aReason);
|
||||
}
|
||||
|
||||
PluginAsyncSurrogate::PendingNewStreamCall::PendingNewStreamCall(
|
||||
NPMIMEType aType, NPStream* aStream, NPBool aSeekable)
|
||||
: mType(NullableString(aType))
|
||||
, mStream(aStream)
|
||||
, mSeekable(aSeekable)
|
||||
{
|
||||
}
|
||||
|
||||
/* static */ nsNPAPIPluginStreamListener*
|
||||
PluginAsyncSurrogate::GetStreamListener(NPStream* aStream)
|
||||
{
|
||||
nsNPAPIStreamWrapper* wrapper =
|
||||
reinterpret_cast<nsNPAPIStreamWrapper*>(aStream->ndata);
|
||||
if (!wrapper) {
|
||||
return nullptr;
|
||||
}
|
||||
return wrapper->GetStreamListener();
|
||||
}
|
||||
|
||||
void
|
||||
PluginAsyncSurrogate::DestroyAsyncStream(NPStream* aStream)
|
||||
{
|
||||
MOZ_ASSERT(aStream);
|
||||
nsNPAPIPluginStreamListener* streamListener = GetStreamListener(aStream);
|
||||
MOZ_ASSERT(streamListener);
|
||||
// streamListener was suspended during async init. We must resume the stream
|
||||
// request prior to calling _destroystream for cleanup to work correctly.
|
||||
streamListener->ResumeRequest();
|
||||
if (!mInstance) {
|
||||
return;
|
||||
}
|
||||
parent::_destroystream(GetNPP(), aStream, NPRES_DONE);
|
||||
}
|
||||
|
||||
/* static */ bool
|
||||
PluginAsyncSurrogate::SetStreamType(NPStream* aStream, uint16_t aStreamType)
|
||||
{
|
||||
nsNPAPIPluginStreamListener* streamListener = GetStreamListener(aStream);
|
||||
if (!streamListener) {
|
||||
return false;
|
||||
}
|
||||
return streamListener->SetStreamType(aStreamType);
|
||||
}
|
||||
|
||||
void
|
||||
PluginAsyncSurrogate::OnInstanceCreated(PluginInstanceParent* aInstance)
|
||||
{
|
||||
if (!mDestroyPending) {
|
||||
// If NPP_Destroy has already been called then these streams have already
|
||||
// been cleaned up on the browser side and are no longer valid.
|
||||
for (uint32_t i = 0, len = mPendingNewStreamCalls.Length(); i < len; ++i) {
|
||||
PendingNewStreamCall& curPendingCall = mPendingNewStreamCalls[i];
|
||||
uint16_t streamType = NP_NORMAL;
|
||||
NPError curError = aInstance->NPP_NewStream(
|
||||
const_cast<char*>(NullableStringGet(curPendingCall.mType)),
|
||||
curPendingCall.mStream, curPendingCall.mSeekable,
|
||||
&streamType);
|
||||
if (curError != NPERR_NO_ERROR) {
|
||||
// If we failed here then the send failed and we need to clean up
|
||||
DestroyAsyncStream(curPendingCall.mStream);
|
||||
}
|
||||
}
|
||||
}
|
||||
mPendingNewStreamCalls.Clear();
|
||||
mInstantiated = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* During asynchronous initialization it might be necessary to wait for the
|
||||
* plugin to complete its initialization. This typically occurs when the result
|
||||
* of a plugin call depends on the plugin being fully instantiated. For example,
|
||||
* if some JS calls into the plugin, the call must be executed synchronously to
|
||||
* preserve correctness.
|
||||
*
|
||||
* This function works by pumping the plugin's IPC channel for events until
|
||||
* initialization has completed.
|
||||
*/
|
||||
bool
|
||||
PluginAsyncSurrogate::WaitForInit()
|
||||
{
|
||||
if (mInitCancelled) {
|
||||
return false;
|
||||
}
|
||||
if (mAcceptCalls) {
|
||||
return true;
|
||||
}
|
||||
Telemetry::AutoTimer<Telemetry::BLOCKED_ON_PLUGINASYNCSURROGATE_WAITFORINIT_MS>
|
||||
timer(mParent->GetHistogramKey());
|
||||
bool result = false;
|
||||
MOZ_ASSERT(mParent);
|
||||
if (mParent->IsChrome()) {
|
||||
PluginProcessParent* process = static_cast<PluginModuleChromeParent*>(mParent)->Process();
|
||||
MOZ_ASSERT(process);
|
||||
process->SetCallRunnableImmediately(true);
|
||||
if (!process->WaitUntilConnected()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!mParent->WaitForIPCConnection()) {
|
||||
return false;
|
||||
}
|
||||
if (!mParent->IsChrome()) {
|
||||
// For e10s content processes, we need to spin the content channel until the
|
||||
// protocol bridging has occurred.
|
||||
dom::ContentChild* cp = dom::ContentChild::GetSingleton();
|
||||
mozilla::ipc::MessageChannel* contentChannel = cp->GetIPCChannel();
|
||||
MOZ_ASSERT(contentChannel);
|
||||
while (!mParent->mNPInitialized) {
|
||||
if (mParent->mShutdown) {
|
||||
// Since we are pumping the message channel for events, it may be
|
||||
// possible for module initialization to fail during this loop. We must
|
||||
// return false if this happens or else we'll be permanently stuck.
|
||||
return false;
|
||||
}
|
||||
result = contentChannel->WaitForIncomingMessage();
|
||||
if (!result) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
mozilla::ipc::MessageChannel* channel = mParent->GetIPCChannel();
|
||||
MOZ_ASSERT(channel);
|
||||
while (!mAcceptCalls) {
|
||||
if (mInitCancelled) {
|
||||
// Since we are pumping the message channel for events, it may be
|
||||
// possible for plugin instantiation to fail during this loop. We must
|
||||
// return false if this happens or else we'll be permanently stuck.
|
||||
return false;
|
||||
}
|
||||
result = channel->WaitForIncomingMessage();
|
||||
if (!result) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
PluginAsyncSurrogate::AsyncCallDeparting()
|
||||
{
|
||||
++mAsyncCallsInFlight;
|
||||
if (!mPluginDestructionGuard) {
|
||||
mPluginDestructionGuard = MakeUnique<PluginDestructionGuard>(this);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PluginAsyncSurrogate::AsyncCallArriving()
|
||||
{
|
||||
MOZ_ASSERT(mAsyncCallsInFlight > 0);
|
||||
if (--mAsyncCallsInFlight == 0) {
|
||||
mPluginDestructionGuard.reset(nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PluginAsyncSurrogate::NotifyAsyncInitFailed()
|
||||
{
|
||||
if (!mDestroyPending) {
|
||||
// Clean up any pending NewStream requests
|
||||
for (uint32_t i = 0, len = mPendingNewStreamCalls.Length(); i < len; ++i) {
|
||||
PendingNewStreamCall& curPendingCall = mPendingNewStreamCalls[i];
|
||||
DestroyAsyncStream(curPendingCall.mStream);
|
||||
}
|
||||
}
|
||||
mPendingNewStreamCalls.Clear();
|
||||
|
||||
// Make sure that any WaitForInit calls on this surrogate will fail, or else
|
||||
// we'll be perma-blocked
|
||||
mInitCancelled = true;
|
||||
|
||||
if (!mInstance) {
|
||||
return;
|
||||
}
|
||||
nsPluginInstanceOwner* owner = mInstance->GetOwner();
|
||||
if (owner) {
|
||||
owner->NotifyHostAsyncInitFailed();
|
||||
}
|
||||
}
|
||||
|
||||
// static
|
||||
NPObject*
|
||||
PluginAsyncSurrogate::ScriptableAllocate(NPP aInstance, NPClass* aClass)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_FUNCTION;
|
||||
if (aClass != GetClass()) {
|
||||
NS_ERROR("Huh?! Wrong class!");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return new AsyncNPObject(Cast(aInstance));
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
PluginAsyncSurrogate::ScriptableInvalidate(NPObject* aObject)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_FUNCTION;
|
||||
if (aObject->_class != GetClass()) {
|
||||
NS_ERROR("Don't know what kind of object this is!");
|
||||
return;
|
||||
}
|
||||
|
||||
AsyncNPObject* object = static_cast<AsyncNPObject*>(aObject);
|
||||
if (!object->mSurrogate->WaitForInit()) {
|
||||
return;
|
||||
}
|
||||
NPObject* realObject = object->GetRealObject();
|
||||
if (!realObject) {
|
||||
return;
|
||||
}
|
||||
realObject->_class->invalidate(realObject);
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
PluginAsyncSurrogate::ScriptableDeallocate(NPObject* aObject)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_FUNCTION;
|
||||
if (aObject->_class != GetClass()) {
|
||||
NS_ERROR("Don't know what kind of object this is!");
|
||||
return;
|
||||
}
|
||||
|
||||
AsyncNPObject* object = static_cast<AsyncNPObject*>(aObject);
|
||||
delete object;
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
PluginAsyncSurrogate::ScriptableHasMethod(NPObject* aObject,
|
||||
NPIdentifier aName)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_FUNCTION;
|
||||
if (aObject->_class != GetClass()) {
|
||||
NS_ERROR("Don't know what kind of object this is!");
|
||||
return false;
|
||||
}
|
||||
|
||||
RecursionGuard guard;
|
||||
if (guard.IsRecursive()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AsyncNPObject* object = static_cast<AsyncNPObject*>(aObject);
|
||||
MOZ_ASSERT(object);
|
||||
bool checkPluginObject = !object->mSurrogate->mInstantiated &&
|
||||
!object->mSurrogate->mAcceptCalls;
|
||||
|
||||
if (!object->mSurrogate->WaitForInit()) {
|
||||
return false;
|
||||
}
|
||||
NPObject* realObject = object->GetRealObject();
|
||||
if (!realObject) {
|
||||
return false;
|
||||
}
|
||||
bool result = realObject->_class->hasMethod(realObject, aName);
|
||||
if (!result && checkPluginObject) {
|
||||
// We may be calling into this object because properties in the WebIDL
|
||||
// object hadn't been set yet. Now that we're further along in
|
||||
// initialization, we should try again.
|
||||
const NPNetscapeFuncs* npn = object->mSurrogate->mParent->GetNetscapeFuncs();
|
||||
NPObject* pluginObject = nullptr;
|
||||
NPError nperror = npn->getvalue(object->mSurrogate->GetNPP(),
|
||||
NPNVPluginElementNPObject,
|
||||
(void*)&pluginObject);
|
||||
if (nperror == NPERR_NO_ERROR) {
|
||||
NPPAutoPusher nppPusher(object->mSurrogate->GetNPP());
|
||||
result = pluginObject->_class->hasMethod(pluginObject, aName);
|
||||
npn->releaseobject(pluginObject);
|
||||
NPUTF8* idstr = npn->utf8fromidentifier(aName);
|
||||
npn->memfree(idstr);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
PluginAsyncSurrogate::GetPropertyHelper(NPObject* aObject, NPIdentifier aName,
|
||||
bool* aHasProperty, bool* aHasMethod,
|
||||
NPVariant* aResult)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_FUNCTION;
|
||||
|
||||
if (!aObject) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RecursionGuard guard;
|
||||
if (guard.IsRecursive()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!WaitForInit()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AsyncNPObject* object = static_cast<AsyncNPObject*>(aObject);
|
||||
NPObject* realObject = object->GetRealObject();
|
||||
if (!realObject) {
|
||||
return false;
|
||||
}
|
||||
if (realObject->_class != PluginScriptableObjectParent::GetClass()) {
|
||||
NS_ERROR("Don't know what kind of object this is!");
|
||||
return false;
|
||||
}
|
||||
|
||||
PluginScriptableObjectParent* actor =
|
||||
static_cast<ParentNPObject*>(realObject)->parent;
|
||||
if (!actor) {
|
||||
return false;
|
||||
}
|
||||
bool success = actor->GetPropertyHelper(aName, aHasProperty, aHasMethod, aResult);
|
||||
if (!success) {
|
||||
const NPNetscapeFuncs* npn = mParent->GetNetscapeFuncs();
|
||||
NPObject* pluginObject = nullptr;
|
||||
NPError nperror = npn->getvalue(GetNPP(), NPNVPluginElementNPObject,
|
||||
(void*)&pluginObject);
|
||||
if (nperror == NPERR_NO_ERROR) {
|
||||
NPPAutoPusher nppPusher(GetNPP());
|
||||
bool hasProperty = nsJSObjWrapper::HasOwnProperty(pluginObject, aName);
|
||||
NPUTF8* idstr = npn->utf8fromidentifier(aName);
|
||||
npn->memfree(idstr);
|
||||
bool hasMethod = false;
|
||||
if (hasProperty) {
|
||||
hasMethod = pluginObject->_class->hasMethod(pluginObject, aName);
|
||||
success = pluginObject->_class->getProperty(pluginObject, aName, aResult);
|
||||
idstr = npn->utf8fromidentifier(aName);
|
||||
npn->memfree(idstr);
|
||||
}
|
||||
*aHasProperty = hasProperty;
|
||||
*aHasMethod = hasMethod;
|
||||
npn->releaseobject(pluginObject);
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
PluginAsyncSurrogate::ScriptableInvoke(NPObject* aObject,
|
||||
NPIdentifier aName,
|
||||
const NPVariant* aArgs,
|
||||
uint32_t aArgCount,
|
||||
NPVariant* aResult)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_FUNCTION;
|
||||
if (aObject->_class != GetClass()) {
|
||||
NS_ERROR("Don't know what kind of object this is!");
|
||||
return false;
|
||||
}
|
||||
|
||||
AsyncNPObject* object = static_cast<AsyncNPObject*>(aObject);
|
||||
if (!object->mSurrogate->WaitForInit()) {
|
||||
return false;
|
||||
}
|
||||
NPObject* realObject = object->GetRealObject();
|
||||
if (!realObject) {
|
||||
return false;
|
||||
}
|
||||
return realObject->_class->invoke(realObject, aName, aArgs, aArgCount, aResult);
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
PluginAsyncSurrogate::ScriptableInvokeDefault(NPObject* aObject,
|
||||
const NPVariant* aArgs,
|
||||
uint32_t aArgCount,
|
||||
NPVariant* aResult)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_FUNCTION;
|
||||
if (aObject->_class != GetClass()) {
|
||||
NS_ERROR("Don't know what kind of object this is!");
|
||||
return false;
|
||||
}
|
||||
|
||||
AsyncNPObject* object = static_cast<AsyncNPObject*>(aObject);
|
||||
if (!object->mSurrogate->WaitForInit()) {
|
||||
return false;
|
||||
}
|
||||
NPObject* realObject = object->GetRealObject();
|
||||
if (!realObject) {
|
||||
return false;
|
||||
}
|
||||
return realObject->_class->invokeDefault(realObject, aArgs, aArgCount, aResult);
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
PluginAsyncSurrogate::ScriptableHasProperty(NPObject* aObject,
|
||||
NPIdentifier aName)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_FUNCTION;
|
||||
if (aObject->_class != GetClass()) {
|
||||
NS_ERROR("Don't know what kind of object this is!");
|
||||
return false;
|
||||
}
|
||||
|
||||
RecursionGuard guard;
|
||||
if (guard.IsRecursive()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
AsyncNPObject* object = static_cast<AsyncNPObject*>(aObject);
|
||||
MOZ_ASSERT(object);
|
||||
bool checkPluginObject = !object->mSurrogate->mInstantiated &&
|
||||
!object->mSurrogate->mAcceptCalls;
|
||||
|
||||
if (!object->mSurrogate->WaitForInit()) {
|
||||
return false;
|
||||
}
|
||||
NPObject* realObject = object->GetRealObject();
|
||||
if (!realObject) {
|
||||
return false;
|
||||
}
|
||||
bool result = realObject->_class->hasProperty(realObject, aName);
|
||||
const NPNetscapeFuncs* npn = object->mSurrogate->mParent->GetNetscapeFuncs();
|
||||
NPUTF8* idstr = npn->utf8fromidentifier(aName);
|
||||
npn->memfree(idstr);
|
||||
if (!result && checkPluginObject) {
|
||||
// We may be calling into this object because properties in the WebIDL
|
||||
// object hadn't been set yet. Now that we're further along in
|
||||
// initialization, we should try again.
|
||||
NPObject* pluginObject = nullptr;
|
||||
NPError nperror = npn->getvalue(object->mSurrogate->GetNPP(),
|
||||
NPNVPluginElementNPObject,
|
||||
(void*)&pluginObject);
|
||||
if (nperror == NPERR_NO_ERROR) {
|
||||
NPPAutoPusher nppPusher(object->mSurrogate->GetNPP());
|
||||
result = nsJSObjWrapper::HasOwnProperty(pluginObject, aName);
|
||||
npn->releaseobject(pluginObject);
|
||||
idstr = npn->utf8fromidentifier(aName);
|
||||
npn->memfree(idstr);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
PluginAsyncSurrogate::ScriptableGetProperty(NPObject* aObject,
|
||||
NPIdentifier aName,
|
||||
NPVariant* aResult)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_FUNCTION;
|
||||
// See GetPropertyHelper below.
|
||||
NS_NOTREACHED("Shouldn't ever call this directly!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
PluginAsyncSurrogate::ScriptableSetProperty(NPObject* aObject,
|
||||
NPIdentifier aName,
|
||||
const NPVariant* aValue)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_FUNCTION;
|
||||
if (aObject->_class != GetClass()) {
|
||||
NS_ERROR("Don't know what kind of object this is!");
|
||||
return false;
|
||||
}
|
||||
|
||||
AsyncNPObject* object = static_cast<AsyncNPObject*>(aObject);
|
||||
if (!object->mSurrogate->WaitForInit()) {
|
||||
return false;
|
||||
}
|
||||
NPObject* realObject = object->GetRealObject();
|
||||
if (!realObject) {
|
||||
return false;
|
||||
}
|
||||
return realObject->_class->setProperty(realObject, aName, aValue);
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
PluginAsyncSurrogate::ScriptableRemoveProperty(NPObject* aObject,
|
||||
NPIdentifier aName)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_FUNCTION;
|
||||
if (aObject->_class != GetClass()) {
|
||||
NS_ERROR("Don't know what kind of object this is!");
|
||||
return false;
|
||||
}
|
||||
|
||||
AsyncNPObject* object = static_cast<AsyncNPObject*>(aObject);
|
||||
if (!object->mSurrogate->WaitForInit()) {
|
||||
return false;
|
||||
}
|
||||
NPObject* realObject = object->GetRealObject();
|
||||
if (!realObject) {
|
||||
return false;
|
||||
}
|
||||
return realObject->_class->removeProperty(realObject, aName);
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
PluginAsyncSurrogate::ScriptableEnumerate(NPObject* aObject,
|
||||
NPIdentifier** aIdentifiers,
|
||||
uint32_t* aCount)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_FUNCTION;
|
||||
if (aObject->_class != GetClass()) {
|
||||
NS_ERROR("Don't know what kind of object this is!");
|
||||
return false;
|
||||
}
|
||||
|
||||
AsyncNPObject* object = static_cast<AsyncNPObject*>(aObject);
|
||||
if (!object->mSurrogate->WaitForInit()) {
|
||||
return false;
|
||||
}
|
||||
NPObject* realObject = object->GetRealObject();
|
||||
if (!realObject) {
|
||||
return false;
|
||||
}
|
||||
return realObject->_class->enumerate(realObject, aIdentifiers, aCount);
|
||||
}
|
||||
|
||||
// static
|
||||
bool
|
||||
PluginAsyncSurrogate::ScriptableConstruct(NPObject* aObject,
|
||||
const NPVariant* aArgs,
|
||||
uint32_t aArgCount,
|
||||
NPVariant* aResult)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_FUNCTION;
|
||||
if (aObject->_class != GetClass()) {
|
||||
NS_ERROR("Don't know what kind of object this is!");
|
||||
return false;
|
||||
}
|
||||
|
||||
AsyncNPObject* object = static_cast<AsyncNPObject*>(aObject);
|
||||
if (!object->mSurrogate->WaitForInit()) {
|
||||
return false;
|
||||
}
|
||||
NPObject* realObject = object->GetRealObject();
|
||||
if (!realObject) {
|
||||
return false;
|
||||
}
|
||||
return realObject->_class->construct(realObject, aArgs, aArgCount, aResult);
|
||||
}
|
||||
|
||||
const NPClass PluginAsyncSurrogate::sNPClass = {
|
||||
NP_CLASS_STRUCT_VERSION,
|
||||
PluginAsyncSurrogate::ScriptableAllocate,
|
||||
PluginAsyncSurrogate::ScriptableDeallocate,
|
||||
PluginAsyncSurrogate::ScriptableInvalidate,
|
||||
PluginAsyncSurrogate::ScriptableHasMethod,
|
||||
PluginAsyncSurrogate::ScriptableInvoke,
|
||||
PluginAsyncSurrogate::ScriptableInvokeDefault,
|
||||
PluginAsyncSurrogate::ScriptableHasProperty,
|
||||
PluginAsyncSurrogate::ScriptableGetProperty,
|
||||
PluginAsyncSurrogate::ScriptableSetProperty,
|
||||
PluginAsyncSurrogate::ScriptableRemoveProperty,
|
||||
PluginAsyncSurrogate::ScriptableEnumerate,
|
||||
PluginAsyncSurrogate::ScriptableConstruct
|
||||
};
|
||||
|
||||
PushSurrogateAcceptCalls::PushSurrogateAcceptCalls(PluginInstanceParent* aInstance)
|
||||
: mSurrogate(nullptr)
|
||||
, mPrevAcceptCallsState(false)
|
||||
{
|
||||
MOZ_ASSERT(aInstance);
|
||||
mSurrogate = aInstance->GetAsyncSurrogate();
|
||||
if (mSurrogate) {
|
||||
mPrevAcceptCallsState = mSurrogate->SetAcceptingCalls(true);
|
||||
}
|
||||
}
|
||||
|
||||
PushSurrogateAcceptCalls::~PushSurrogateAcceptCalls()
|
||||
{
|
||||
if (mSurrogate) {
|
||||
mSurrogate->SetAcceptingCalls(mPrevAcceptCallsState);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace plugins
|
||||
} // namespace mozilla
|
|
@ -1,187 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef dom_plugins_ipc_PluginAsyncSurrogate_h
|
||||
#define dom_plugins_ipc_PluginAsyncSurrogate_h
|
||||
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "npapi.h"
|
||||
#include "npfunctions.h"
|
||||
#include "npruntime.h"
|
||||
#include "nsISupportsImpl.h"
|
||||
#include "nsPluginHost.h"
|
||||
#include "nsString.h"
|
||||
#include "nsTArray.h"
|
||||
#include "PluginDataResolver.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace plugins {
|
||||
|
||||
struct ParentNPObject;
|
||||
class PluginInstanceParent;
|
||||
class PluginModuleParent;
|
||||
|
||||
class PluginAsyncSurrogate : public PluginDataResolver
|
||||
{
|
||||
public:
|
||||
NS_INLINE_DECL_REFCOUNTING(PluginAsyncSurrogate)
|
||||
|
||||
bool Init(NPMIMEType aPluginType, NPP aInstance,
|
||||
int16_t aArgc, char* aArgn[], char* aArgv[]);
|
||||
nsresult NPP_New(NPError* aError);
|
||||
NPError NPP_Destroy(NPSavedData** aSave);
|
||||
NPError NPP_GetValue(NPPVariable aVariable, void* aRetval);
|
||||
NPError NPP_SetValue(NPNVariable aVariable, void* aValue);
|
||||
NPError NPP_NewStream(NPMIMEType aType, NPStream* aStream, NPBool aSeekable,
|
||||
uint16_t* aStype);
|
||||
NPError NPP_SetWindow(NPWindow* aWindow);
|
||||
nsresult AsyncSetWindow(NPWindow* aWindow);
|
||||
void NPP_Print(NPPrint* aPrintInfo);
|
||||
int16_t NPP_HandleEvent(void* aEvent);
|
||||
int32_t NPP_WriteReady(NPStream* aStream);
|
||||
NPError NPP_DestroyStream(NPStream* aStream, NPReason aReason);
|
||||
void OnInstanceCreated(PluginInstanceParent* aInstance);
|
||||
static bool Create(PluginModuleParent* aParent, NPMIMEType aPluginType,
|
||||
NPP aInstance, int16_t aArgc,
|
||||
char* aArgn[], char* aArgv[]);
|
||||
static const NPClass* GetClass() { return &sNPClass; }
|
||||
static void NP_GetEntryPoints(NPPluginFuncs* aFuncs);
|
||||
static PluginAsyncSurrogate* Cast(NPP aInstance);
|
||||
static void NotifyDestroyPending(NPP aInstance);
|
||||
void NotifyDestroyPending();
|
||||
|
||||
virtual PluginAsyncSurrogate*
|
||||
GetAsyncSurrogate() { return this; }
|
||||
|
||||
virtual PluginInstanceParent*
|
||||
GetInstance() { return nullptr; }
|
||||
|
||||
NPP GetNPP();
|
||||
|
||||
bool GetPropertyHelper(NPObject* aObject, NPIdentifier aName,
|
||||
bool* aHasProperty, bool* aHasMethod,
|
||||
NPVariant* aResult);
|
||||
|
||||
PluginModuleParent* GetParent() { return mParent; }
|
||||
|
||||
bool IsDestroyPending() const { return mDestroyPending; }
|
||||
|
||||
bool SetAcceptingCalls(bool aAccept)
|
||||
{
|
||||
bool prevState = mAcceptCalls;
|
||||
if (mInstantiated) {
|
||||
aAccept = true;
|
||||
}
|
||||
mAcceptCalls = aAccept;
|
||||
return prevState;
|
||||
}
|
||||
|
||||
void AsyncCallDeparting();
|
||||
void AsyncCallArriving();
|
||||
|
||||
void NotifyAsyncInitFailed();
|
||||
void DestroyAsyncStream(NPStream* aStream);
|
||||
|
||||
private:
|
||||
explicit PluginAsyncSurrogate(PluginModuleParent* aParent);
|
||||
virtual ~PluginAsyncSurrogate();
|
||||
|
||||
bool WaitForInit();
|
||||
|
||||
static bool SetStreamType(NPStream* aStream, uint16_t aStreamType);
|
||||
|
||||
static NPError NPP_Destroy(NPP aInstance, NPSavedData** aSave);
|
||||
static NPError NPP_GetValue(NPP aInstance, NPPVariable aVariable, void* aRetval);
|
||||
static NPError NPP_SetValue(NPP aInstance, NPNVariable aVariable, void* aValue);
|
||||
static NPError NPP_NewStream(NPP aInstance, NPMIMEType aType, NPStream* aStream,
|
||||
NPBool aSeekable, uint16_t* aStype);
|
||||
static NPError NPP_SetWindow(NPP aInstance, NPWindow* aWindow);
|
||||
static void NPP_Print(NPP aInstance, NPPrint* aPrintInfo);
|
||||
static int16_t NPP_HandleEvent(NPP aInstance, void* aEvent);
|
||||
static int32_t NPP_WriteReady(NPP aInstance, NPStream* aStream);
|
||||
static NPError NPP_DestroyStream(NPP aInstance, NPStream* aStream,
|
||||
NPReason aReason);
|
||||
|
||||
static NPObject* ScriptableAllocate(NPP aInstance, NPClass* aClass);
|
||||
static void ScriptableInvalidate(NPObject* aObject);
|
||||
static void ScriptableDeallocate(NPObject* aObject);
|
||||
static bool ScriptableHasMethod(NPObject* aObject, NPIdentifier aName);
|
||||
static bool ScriptableInvoke(NPObject* aObject, NPIdentifier aName,
|
||||
const NPVariant* aArgs, uint32_t aArgCount,
|
||||
NPVariant* aResult);
|
||||
static bool ScriptableInvokeDefault(NPObject* aObject, const NPVariant* aArgs,
|
||||
uint32_t aArgCount, NPVariant* aResult);
|
||||
static bool ScriptableHasProperty(NPObject* aObject, NPIdentifier aName);
|
||||
static bool ScriptableGetProperty(NPObject* aObject, NPIdentifier aName,
|
||||
NPVariant* aResult);
|
||||
static bool ScriptableSetProperty(NPObject* aObject, NPIdentifier aName,
|
||||
const NPVariant* aValue);
|
||||
static bool ScriptableRemoveProperty(NPObject* aObject, NPIdentifier aName);
|
||||
static bool ScriptableEnumerate(NPObject* aObject, NPIdentifier** aIdentifiers,
|
||||
uint32_t* aCount);
|
||||
static bool ScriptableConstruct(NPObject* aObject, const NPVariant* aArgs,
|
||||
uint32_t aArgCount, NPVariant* aResult);
|
||||
static nsNPAPIPluginStreamListener* GetStreamListener(NPStream* aStream);
|
||||
|
||||
private:
|
||||
struct PendingNewStreamCall
|
||||
{
|
||||
PendingNewStreamCall(NPMIMEType aType, NPStream* aStream, NPBool aSeekable);
|
||||
~PendingNewStreamCall() {}
|
||||
nsCString mType;
|
||||
NPStream* mStream;
|
||||
NPBool mSeekable;
|
||||
};
|
||||
|
||||
private:
|
||||
PluginModuleParent* mParent;
|
||||
// These values are used to construct the plugin instance
|
||||
nsCString mMimeType;
|
||||
mozilla::WeakPtr<nsNPAPIPluginInstance> mInstance;
|
||||
InfallibleTArray<nsCString> mNames;
|
||||
InfallibleTArray<nsCString> mValues;
|
||||
// This is safe to store as a pointer because the spec says it will remain
|
||||
// valid until destruction or a subsequent NPP_SetWindow call.
|
||||
NPWindow* mWindow;
|
||||
nsTArray<PendingNewStreamCall> mPendingNewStreamCalls;
|
||||
UniquePtr<PluginDestructionGuard> mPluginDestructionGuard;
|
||||
|
||||
bool mAcceptCalls;
|
||||
bool mInstantiated;
|
||||
bool mAsyncSetWindow;
|
||||
bool mInitCancelled;
|
||||
bool mDestroyPending;
|
||||
int32_t mAsyncCallsInFlight;
|
||||
|
||||
static const NPClass sNPClass;
|
||||
};
|
||||
|
||||
struct AsyncNPObject : NPObject
|
||||
{
|
||||
explicit AsyncNPObject(PluginAsyncSurrogate* aSurrogate);
|
||||
~AsyncNPObject();
|
||||
|
||||
NPObject* GetRealObject();
|
||||
|
||||
RefPtr<PluginAsyncSurrogate> mSurrogate;
|
||||
ParentNPObject* mRealObject;
|
||||
};
|
||||
|
||||
class MOZ_STACK_CLASS PushSurrogateAcceptCalls
|
||||
{
|
||||
public:
|
||||
explicit PushSurrogateAcceptCalls(PluginInstanceParent* aInstance);
|
||||
~PushSurrogateAcceptCalls();
|
||||
|
||||
private:
|
||||
PluginAsyncSurrogate* mSurrogate;
|
||||
bool mPrevAcceptCallsState;
|
||||
};
|
||||
|
||||
} // namespace plugins
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // dom_plugins_ipc_PluginAsyncSurrogate_h
|
|
@ -28,7 +28,7 @@ class PPluginModuleParent;
|
|||
|
||||
bool
|
||||
SetupBridge(uint32_t aPluginId, dom::ContentParent* aContentParent,
|
||||
bool aForceBridgeNow, nsresult* aResult, uint32_t* aRunID,
|
||||
nsresult* aResult, uint32_t* aRunID,
|
||||
ipc::Endpoint<PPluginModuleParent>* aEndpoint);
|
||||
|
||||
nsresult
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef dom_plugins_ipc_PluginDataResolver_h
|
||||
#define dom_plugins_ipc_PluginDataResolver_h
|
||||
|
||||
namespace mozilla {
|
||||
namespace plugins {
|
||||
|
||||
class PluginAsyncSurrogate;
|
||||
class PluginInstanceParent;
|
||||
|
||||
class PluginDataResolver
|
||||
{
|
||||
public:
|
||||
virtual PluginAsyncSurrogate* GetAsyncSurrogate() = 0;
|
||||
virtual PluginInstanceParent* GetInstance() = 0;
|
||||
};
|
||||
|
||||
} // namespace plugins
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // dom_plugins_ipc_PluginDataResolver_h
|
|
@ -2508,52 +2508,6 @@ PluginInstanceChild::AnswerNPP_NewStream(PBrowserStreamChild* actor,
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
class NewStreamAsyncCall : public ChildAsyncCall
|
||||
{
|
||||
public:
|
||||
NewStreamAsyncCall(PluginInstanceChild* aInstance,
|
||||
BrowserStreamChild* aBrowserStreamChild,
|
||||
const nsCString& aMimeType,
|
||||
const bool aSeekable)
|
||||
: ChildAsyncCall(aInstance, nullptr, nullptr)
|
||||
, mBrowserStreamChild(aBrowserStreamChild)
|
||||
, mMimeType(aMimeType)
|
||||
, mSeekable(aSeekable)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
RemoveFromAsyncList();
|
||||
|
||||
uint16_t stype = NP_NORMAL;
|
||||
NPError rv = mInstance->DoNPP_NewStream(mBrowserStreamChild, mMimeType,
|
||||
mSeekable, &stype);
|
||||
DebugOnly<bool> sendOk =
|
||||
mBrowserStreamChild->SendAsyncNPP_NewStreamResult(rv, stype);
|
||||
MOZ_ASSERT(sendOk);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
BrowserStreamChild* mBrowserStreamChild;
|
||||
const nsCString mMimeType;
|
||||
const bool mSeekable;
|
||||
};
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
PluginInstanceChild::RecvAsyncNPP_NewStream(PBrowserStreamChild* actor,
|
||||
const nsCString& mimeType,
|
||||
const bool& seekable)
|
||||
{
|
||||
// Reusing ChildAsyncCall so that the task is cancelled properly on Destroy
|
||||
BrowserStreamChild* child = static_cast<BrowserStreamChild*>(actor);
|
||||
RefPtr<NewStreamAsyncCall> task =
|
||||
new NewStreamAsyncCall(this, child, mimeType, seekable);
|
||||
PostChildAsyncCall(task.forget());
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
PBrowserStreamChild*
|
||||
PluginInstanceChild::AllocPBrowserStreamChild(const nsCString& url,
|
||||
const uint32_t& length,
|
||||
|
|
|
@ -165,12 +165,6 @@ protected:
|
|||
NPError* rv,
|
||||
uint16_t* stype) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvAsyncNPP_NewStream(
|
||||
PBrowserStreamChild* actor,
|
||||
const nsCString& mimeType,
|
||||
const bool& seekable) override;
|
||||
|
||||
virtual PBrowserStreamChild*
|
||||
AllocPBrowserStreamChild(const nsCString& url,
|
||||
const uint32_t& length,
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include "mozilla/Telemetry.h"
|
||||
#include "PluginInstanceParent.h"
|
||||
#include "BrowserStreamParent.h"
|
||||
#include "PluginAsyncSurrogate.h"
|
||||
#include "PluginBackgroundDestroyer.h"
|
||||
#include "PluginModuleParent.h"
|
||||
#include "PluginStreamParent.h"
|
||||
|
@ -115,8 +114,6 @@ PluginInstanceParent::PluginInstanceParent(PluginModuleParent* parent,
|
|||
const nsCString& aMimeType,
|
||||
const NPNetscapeFuncs* npniface)
|
||||
: mParent(parent)
|
||||
, mSurrogate(PluginAsyncSurrogate::Cast(npp))
|
||||
, mUseSurrogate(true)
|
||||
, mNPP(npp)
|
||||
, mNPNIface(npniface)
|
||||
, mWindowType(NPWindowTypeWindow)
|
||||
|
@ -1223,12 +1220,6 @@ PluginInstanceParent::GetScrollCaptureContainer(ImageContainer** aContainer)
|
|||
}
|
||||
#endif // XP_WIN
|
||||
|
||||
PluginAsyncSurrogate*
|
||||
PluginInstanceParent::GetAsyncSurrogate()
|
||||
{
|
||||
return mSurrogate;
|
||||
}
|
||||
|
||||
bool
|
||||
PluginInstanceParent::CreateBackground(const nsIntSize& aSize)
|
||||
{
|
||||
|
@ -1775,22 +1766,12 @@ PluginInstanceParent::NPP_NewStream(NPMIMEType type, NPStream* stream,
|
|||
timer(Module()->GetHistogramKey());
|
||||
|
||||
NPError err = NPERR_NO_ERROR;
|
||||
if (mParent->IsStartingAsync()) {
|
||||
MOZ_ASSERT(mSurrogate);
|
||||
mSurrogate->AsyncCallDeparting();
|
||||
if (SendAsyncNPP_NewStream(bs, NullableString(type), seekable)) {
|
||||
*stype = nsPluginStreamListenerPeer::STREAM_TYPE_UNKNOWN;
|
||||
} else {
|
||||
err = NPERR_GENERIC_ERROR;
|
||||
}
|
||||
} else {
|
||||
bs->SetAlive();
|
||||
if (!CallNPP_NewStream(bs, NullableString(type), seekable, &err, stype)) {
|
||||
err = NPERR_GENERIC_ERROR;
|
||||
}
|
||||
if (NPERR_NO_ERROR != err) {
|
||||
Unused << PBrowserStreamParent::Send__delete__(bs);
|
||||
}
|
||||
bs->SetAlive();
|
||||
if (!CallNPP_NewStream(bs, NullableString(type), seekable, &err, stype)) {
|
||||
err = NPERR_GENERIC_ERROR;
|
||||
}
|
||||
if (NPERR_NO_ERROR != err) {
|
||||
Unused << PBrowserStreamParent::Send__delete__(bs);
|
||||
}
|
||||
|
||||
return err;
|
||||
|
@ -2051,42 +2032,6 @@ PluginInstanceParent::GetOwner()
|
|||
return inst->GetOwner();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
PluginInstanceParent::RecvAsyncNPP_NewResult(const NPError& aResult)
|
||||
{
|
||||
// NB: mUseSurrogate must be cleared before doing anything else, especially
|
||||
// calling NPP_SetWindow!
|
||||
mUseSurrogate = false;
|
||||
|
||||
mSurrogate->AsyncCallArriving();
|
||||
if (aResult == NPERR_NO_ERROR) {
|
||||
mSurrogate->SetAcceptingCalls(true);
|
||||
}
|
||||
|
||||
// It is possible for a plugin instance to outlive its owner (eg. When a
|
||||
// PluginDestructionGuard was on the stack at the time the owner was being
|
||||
// destroyed). We need to handle that case.
|
||||
nsPluginInstanceOwner* owner = GetOwner();
|
||||
if (!owner) {
|
||||
// We can't do anything at this point, just return. Any pending browser
|
||||
// streams will be cleaned up when the plugin instance is destroyed.
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
if (aResult != NPERR_NO_ERROR) {
|
||||
mSurrogate->NotifyAsyncInitFailed();
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
// Now we need to do a bunch of exciting post-NPP_New housekeeping.
|
||||
owner->NotifyHostCreateWidget();
|
||||
|
||||
MOZ_ASSERT(mSurrogate);
|
||||
mSurrogate->OnInstanceCreated(this);
|
||||
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
PluginInstanceParent::RecvSetNetscapeWindowAsParent(const NativeWindowHandle& childWindow)
|
||||
{
|
||||
|
@ -2335,28 +2280,21 @@ PluginInstanceParent::AnswerPluginFocusChange(const bool& gotFocus)
|
|||
}
|
||||
|
||||
PluginInstanceParent*
|
||||
PluginInstanceParent::Cast(NPP aInstance, PluginAsyncSurrogate** aSurrogate)
|
||||
PluginInstanceParent::Cast(NPP aInstance)
|
||||
{
|
||||
PluginDataResolver* resolver =
|
||||
static_cast<PluginDataResolver*>(aInstance->pdata);
|
||||
auto ip = static_cast<PluginInstanceParent*>(aInstance->pdata);
|
||||
|
||||
// If the plugin crashed and the PluginInstanceParent was deleted,
|
||||
// aInstance->pdata will be nullptr.
|
||||
if (!resolver) {
|
||||
if (!ip) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
PluginInstanceParent* instancePtr = resolver->GetInstance();
|
||||
|
||||
if (instancePtr && aInstance != instancePtr->mNPP) {
|
||||
if (aInstance != ip->mNPP) {
|
||||
MOZ_CRASH("Corrupted plugin data.");
|
||||
}
|
||||
|
||||
if (aSurrogate) {
|
||||
*aSurrogate = resolver->GetAsyncSurrogate();
|
||||
}
|
||||
|
||||
return instancePtr;
|
||||
return ip;
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include "nsDataHashtable.h"
|
||||
#include "nsHashKeys.h"
|
||||
#include "nsRect.h"
|
||||
#include "PluginDataResolver.h"
|
||||
|
||||
#include "mozilla/Unused.h"
|
||||
#include "mozilla/EventForwards.h"
|
||||
|
@ -43,7 +42,6 @@ class PluginModuleParent;
|
|||
class D3D11SurfaceHolder;
|
||||
|
||||
class PluginInstanceParent : public PPluginInstanceParent
|
||||
, public PluginDataResolver
|
||||
{
|
||||
friend class PluginModuleParent;
|
||||
friend class BrowserStreamParent;
|
||||
|
@ -241,9 +239,6 @@ public:
|
|||
virtual mozilla::ipc::IPCResult
|
||||
RecvRedrawPlugin() override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvAsyncNPP_NewResult(const NPError& aResult) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvSetNetscapeWindowAsParent(const NativeWindowHandle& childWindow) override;
|
||||
|
||||
|
@ -291,12 +286,6 @@ public:
|
|||
return mNPP;
|
||||
}
|
||||
|
||||
bool
|
||||
UseSurrogate() const
|
||||
{
|
||||
return mUseSurrogate;
|
||||
}
|
||||
|
||||
void
|
||||
GetSrcAttribute(nsACString& aOutput) const
|
||||
{
|
||||
|
@ -327,12 +316,7 @@ public:
|
|||
|
||||
bool IsUsingDirectDrawing();
|
||||
|
||||
virtual PluginAsyncSurrogate* GetAsyncSurrogate() override;
|
||||
|
||||
virtual PluginInstanceParent* GetInstance() override { return this; }
|
||||
|
||||
static PluginInstanceParent* Cast(NPP instance,
|
||||
PluginAsyncSurrogate** aSurrogate = nullptr);
|
||||
static PluginInstanceParent* Cast(NPP instance);
|
||||
|
||||
// for IME hook
|
||||
virtual mozilla::ipc::IPCResult
|
||||
|
@ -382,8 +366,6 @@ private:
|
|||
|
||||
private:
|
||||
PluginModuleParent* mParent;
|
||||
RefPtr<PluginAsyncSurrogate> mSurrogate;
|
||||
bool mUseSurrogate;
|
||||
NPP mNPP;
|
||||
const NPNetscapeFuncs* mNPNIface;
|
||||
nsCString mSrcAttribute;
|
||||
|
|
|
@ -1842,16 +1842,6 @@ PluginModuleChild::AnswerNP_Initialize(const PluginSettings& aSettings, NPError*
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
PluginModuleChild::RecvAsyncNP_Initialize(const PluginSettings& aSettings)
|
||||
{
|
||||
NPError error = DoNP_Initialize(aSettings);
|
||||
if (!SendNP_InitializeResult(error)) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
NPError
|
||||
PluginModuleChild::DoNP_Initialize(const PluginSettings& aSettings)
|
||||
{
|
||||
|
@ -2386,51 +2376,6 @@ PluginModuleChild::AnswerSyncNPP_New(PPluginInstanceChild* aActor, NPError* rv)
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
class AsyncNewResultSender : public ChildAsyncCall
|
||||
{
|
||||
public:
|
||||
AsyncNewResultSender(PluginInstanceChild* aInstance, NPError aResult)
|
||||
: ChildAsyncCall(aInstance, nullptr, nullptr)
|
||||
, mResult(aResult)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
RemoveFromAsyncList();
|
||||
DebugOnly<bool> sendOk = mInstance->SendAsyncNPP_NewResult(mResult);
|
||||
MOZ_ASSERT(sendOk);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
NPError mResult;
|
||||
};
|
||||
|
||||
static void
|
||||
RunAsyncNPP_New(void* aChildInstance)
|
||||
{
|
||||
MOZ_ASSERT(aChildInstance);
|
||||
PluginInstanceChild* childInstance =
|
||||
static_cast<PluginInstanceChild*>(aChildInstance);
|
||||
NPError rv = childInstance->DoNPP_New();
|
||||
RefPtr<AsyncNewResultSender> task =
|
||||
new AsyncNewResultSender(childInstance, rv);
|
||||
childInstance->PostChildAsyncCall(task.forget());
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
PluginModuleChild::RecvAsyncNPP_New(PPluginInstanceChild* aActor)
|
||||
{
|
||||
PLUGIN_LOG_DEBUG_METHOD;
|
||||
PluginInstanceChild* childInstance =
|
||||
reinterpret_cast<PluginInstanceChild*>(aActor);
|
||||
AssertPluginThread();
|
||||
// We don't want to run NPP_New async from within nested calls
|
||||
childInstance->AsyncCall(&RunAsyncNPP_New, childInstance);
|
||||
return IPC_OK();
|
||||
}
|
||||
|
||||
bool
|
||||
PluginModuleChild::DeallocPPluginInstanceChild(PPluginInstanceChild* aActor)
|
||||
{
|
||||
|
|
|
@ -72,10 +72,8 @@ protected:
|
|||
virtual mozilla::ipc::IPCResult RecvDisableFlashProtectedMode() override;
|
||||
virtual mozilla::ipc::IPCResult AnswerNP_GetEntryPoints(NPError* rv) override;
|
||||
virtual mozilla::ipc::IPCResult AnswerNP_Initialize(const PluginSettings& aSettings, NPError* rv) override;
|
||||
virtual mozilla::ipc::IPCResult RecvAsyncNP_Initialize(const PluginSettings& aSettings) override;
|
||||
virtual mozilla::ipc::IPCResult AnswerSyncNPP_New(PPluginInstanceChild* aActor, NPError* rv)
|
||||
override;
|
||||
virtual mozilla::ipc::IPCResult RecvAsyncNPP_New(PPluginInstanceChild* aActor) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvInitPluginModuleChild(Endpoint<PPluginModuleChild>&& endpoint) override;
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -47,7 +47,6 @@ namespace plugins {
|
|||
//-----------------------------------------------------------------------------
|
||||
|
||||
class BrowserStreamParent;
|
||||
class PluginAsyncSurrogate;
|
||||
class PluginInstanceParent;
|
||||
|
||||
#ifdef XP_WIN
|
||||
|
@ -94,16 +93,9 @@ protected:
|
|||
DeallocPPluginInstanceParent(PPluginInstanceParent* aActor) override;
|
||||
|
||||
public:
|
||||
explicit PluginModuleParent(bool aIsChrome, bool aAllowAsyncInit);
|
||||
explicit PluginModuleParent(bool aIsChrome);
|
||||
virtual ~PluginModuleParent();
|
||||
|
||||
bool RemovePendingSurrogate(const RefPtr<PluginAsyncSurrogate>& aSurrogate);
|
||||
|
||||
/** @return the state of the pref that controls async plugin init */
|
||||
bool IsStartingAsync() const { return mIsStartingAsync; }
|
||||
/** @return whether this modules NP_Initialize has successfully completed
|
||||
executing */
|
||||
bool IsInitialized() const { return mNPInitialized; }
|
||||
bool IsChrome() const { return mIsChrome; }
|
||||
|
||||
virtual void SetPlugin(nsNPAPIPlugin* plugin) override
|
||||
|
@ -123,8 +115,6 @@ public:
|
|||
|
||||
void ProcessRemoteNativeEventsInInterruptCall() override;
|
||||
|
||||
virtual bool WaitForIPCConnection() { return true; }
|
||||
|
||||
nsCString GetHistogramKey() const {
|
||||
return mPluginName + mPluginVersion;
|
||||
}
|
||||
|
@ -180,11 +170,7 @@ protected:
|
|||
virtual mozilla::ipc::IPCResult
|
||||
RecvNPN_ReloadPlugins(const bool& aReloadPages) override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvNP_InitializeResult(const NPError& aError) override;
|
||||
|
||||
static BrowserStreamParent* StreamCast(NPP instance, NPStream* s,
|
||||
PluginAsyncSurrogate** aSurrogate = nullptr);
|
||||
static BrowserStreamParent* StreamCast(NPP instance, NPStream* s);
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
AnswerNPN_SetValue_NPPVpluginRequiresAudioDeviceChanges(
|
||||
|
@ -315,8 +301,6 @@ public:
|
|||
virtual nsresult ContentsScaleFactorChanged(NPP instance, double aContentsScaleFactor) override;
|
||||
#endif
|
||||
|
||||
void InitAsyncSurrogates();
|
||||
|
||||
layers::TextureClientRecycleAllocator* EnsureTextureAllocatorForDirectBitmap();
|
||||
layers::TextureClientRecycleAllocator* EnsureTextureAllocatorForDXGISurface();
|
||||
|
||||
|
@ -324,7 +308,6 @@ protected:
|
|||
void NotifyFlashHang();
|
||||
void NotifyPluginCrashed();
|
||||
void OnInitFailure();
|
||||
bool MaybeRunDeferredShutdown();
|
||||
bool DoShutdown(NPError* error);
|
||||
|
||||
bool GetSetting(NPNVariable aVariable);
|
||||
|
@ -355,13 +338,6 @@ protected:
|
|||
bool
|
||||
GetPluginDetails();
|
||||
|
||||
friend class mozilla::plugins::PluginAsyncSurrogate;
|
||||
|
||||
bool mIsStartingAsync;
|
||||
bool mNPInitialized;
|
||||
bool mIsNPShutdownPending;
|
||||
nsTArray<RefPtr<PluginAsyncSurrogate>> mSurrogateInstances;
|
||||
nsresult mAsyncNewRv;
|
||||
uint32_t mRunID;
|
||||
|
||||
RefPtr<layers::TextureClientRecycleAllocator> mTextureAllocatorForDirectBitmap;
|
||||
|
@ -382,16 +358,10 @@ protected:
|
|||
class PluginModuleContentParent : public PluginModuleParent
|
||||
{
|
||||
public:
|
||||
explicit PluginModuleContentParent(bool aAllowAsyncInit);
|
||||
explicit PluginModuleContentParent();
|
||||
|
||||
static PluginLibrary* LoadModule(uint32_t aPluginId, nsPluginTag* aPluginTag);
|
||||
|
||||
static void OnLoadPluginResult(const uint32_t& aPluginId,
|
||||
const bool& aResult,
|
||||
Endpoint<PPluginModuleParent>&& aEndpoint);
|
||||
|
||||
static void AssociatePluginId(uint32_t aPluginId, base::ProcessId aProcessId);
|
||||
|
||||
virtual ~PluginModuleContentParent();
|
||||
|
||||
#if defined(XP_WIN) || defined(XP_MACOSX)
|
||||
|
@ -432,14 +402,6 @@ class PluginModuleChromeParent
|
|||
static PluginLibrary* LoadModule(const char* aFilePath, uint32_t aPluginId,
|
||||
nsPluginTag* aPluginTag);
|
||||
|
||||
/**
|
||||
* The following two functions are called by SetupBridge to determine
|
||||
* whether an existing plugin module was reused, or whether a new module
|
||||
* was instantiated by the plugin host.
|
||||
*/
|
||||
static void ClearInstantiationFlag() { sInstantiated = false; }
|
||||
static bool DidInstantiate() { return sInstantiated; }
|
||||
|
||||
virtual ~PluginModuleChromeParent();
|
||||
|
||||
/*
|
||||
|
@ -535,17 +497,6 @@ class PluginModuleChromeParent
|
|||
EvaluateHangUIState(const bool aReset);
|
||||
#endif // XP_WIN
|
||||
|
||||
virtual bool WaitForIPCConnection() override;
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
RecvNP_InitializeResult(const NPError& aError) override;
|
||||
|
||||
void
|
||||
SetContentParent(dom::ContentParent* aContentParent);
|
||||
|
||||
bool
|
||||
SendAssociatePluginId();
|
||||
|
||||
void CachedSettingChanged();
|
||||
|
||||
virtual mozilla::ipc::IPCResult
|
||||
|
@ -600,8 +551,7 @@ private:
|
|||
|
||||
// aFilePath is UTF8, not native!
|
||||
explicit PluginModuleChromeParent(const char* aFilePath, uint32_t aPluginId,
|
||||
int32_t aSandboxLevel,
|
||||
bool aAllowAsyncInit);
|
||||
int32_t aSandboxLevel);
|
||||
|
||||
void CleanupFromTimeout(const bool aByHangUI);
|
||||
|
||||
|
@ -657,8 +607,6 @@ private:
|
|||
FinishHangUI();
|
||||
#endif
|
||||
|
||||
friend class mozilla::plugins::PluginAsyncSurrogate;
|
||||
|
||||
#ifdef MOZ_CRASHREPORTER_INJECTOR
|
||||
friend class mozilla::plugins::FinishInjectorInitTask;
|
||||
|
||||
|
@ -696,17 +644,8 @@ private:
|
|||
|
||||
friend class LaunchedTask;
|
||||
|
||||
bool mInitOnAsyncConnect;
|
||||
nsresult mAsyncInitRv;
|
||||
NPError mAsyncInitError;
|
||||
// mContentParent is to be used ONLY during the IPC dance that occurs
|
||||
// when ContentParent::RecvLoadPlugin is called under async plugin init!
|
||||
// In other contexts it is *unsafe*, as there might be multiple content
|
||||
// processes in existence!
|
||||
dom::ContentParent* mContentParent;
|
||||
nsCOMPtr<nsIObserver> mPluginOfflineObserver;
|
||||
bool mIsBlocklisted;
|
||||
static bool sInstantiated;
|
||||
#if defined(XP_WIN) && defined(MOZ_SANDBOX)
|
||||
mozilla::SandboxPermissions mSandboxPermissions;
|
||||
#endif
|
||||
|
|
|
@ -32,7 +32,6 @@ PluginProcessParent::PluginProcessParent(const std::string& aPluginFilePath) :
|
|||
, mPluginFilePath(aPluginFilePath)
|
||||
, mTaskFactory(this)
|
||||
, mMainMsgLoop(MessageLoop::current())
|
||||
, mRunCompleteTaskImmediately(false)
|
||||
#ifdef XP_WIN
|
||||
, mChildPid(0)
|
||||
#endif
|
||||
|
@ -130,12 +129,6 @@ PluginProcessParent::Delete()
|
|||
&PluginProcessParent::Delete));
|
||||
}
|
||||
|
||||
void
|
||||
PluginProcessParent::SetCallRunnableImmediately(bool aCallImmediately)
|
||||
{
|
||||
mRunCompleteTaskImmediately = aCallImmediately;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function exists so that we may provide an additional level of
|
||||
* indirection between the task being posted to main event loop (a
|
||||
|
@ -156,7 +149,7 @@ bool
|
|||
PluginProcessParent::WaitUntilConnected(int32_t aTimeoutMs)
|
||||
{
|
||||
bool result = GeckoChildProcessHost::WaitUntilConnected(aTimeoutMs);
|
||||
if (mRunCompleteTaskImmediately && mLaunchCompleteTask) {
|
||||
if (mLaunchCompleteTask) {
|
||||
if (result) {
|
||||
mLaunchCompleteTask->SetLaunchSucceeded();
|
||||
}
|
||||
|
@ -177,21 +170,12 @@ PluginProcessParent::OnChannelConnected(int32_t peer_pid)
|
|||
#endif
|
||||
|
||||
GeckoChildProcessHost::OnChannelConnected(peer_pid);
|
||||
if (mLaunchCompleteTask && !mRunCompleteTaskImmediately) {
|
||||
mLaunchCompleteTask->SetLaunchSucceeded();
|
||||
mMainMsgLoop->PostTask(mTaskFactory.NewRunnableMethod(
|
||||
&PluginProcessParent::RunLaunchCompleteTask));
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PluginProcessParent::OnChannelError()
|
||||
{
|
||||
GeckoChildProcessHost::OnChannelError();
|
||||
if (mLaunchCompleteTask && !mRunCompleteTaskImmediately) {
|
||||
mMainMsgLoop->PostTask(mTaskFactory.NewRunnableMethod(
|
||||
&PluginProcessParent::RunLaunchCompleteTask));
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
|
|
|
@ -68,7 +68,6 @@ public:
|
|||
|
||||
using mozilla::ipc::GeckoChildProcessHost::GetChannel;
|
||||
|
||||
void SetCallRunnableImmediately(bool aCallImmediately);
|
||||
virtual bool WaitUntilConnected(int32_t aTimeoutMs = 0) override;
|
||||
|
||||
virtual void OnChannelConnected(int32_t peer_pid) override;
|
||||
|
@ -85,7 +84,6 @@ private:
|
|||
ipc::TaskFactory<PluginProcessParent> mTaskFactory;
|
||||
UniquePtr<LaunchCompleteTask> mLaunchCompleteTask;
|
||||
MessageLoop* mMainMsgLoop;
|
||||
bool mRunCompleteTaskImmediately;
|
||||
#ifdef XP_WIN
|
||||
typedef nsTHashtable<nsUint32HashKey> PidSet;
|
||||
// Set of PIDs for all plugin child processes or NULL if empty.
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#include "mozilla/plugins/PluginTypes.h"
|
||||
#include "mozilla/Unused.h"
|
||||
#include "nsNPAPIPlugin.h"
|
||||
#include "PluginAsyncSurrogate.h"
|
||||
#include "PluginScriptableObjectUtils.h"
|
||||
|
||||
using namespace mozilla;
|
||||
|
@ -111,7 +110,6 @@ inline void
|
|||
ReleaseVariant(NPVariant& aVariant,
|
||||
PluginInstanceParent* aInstance)
|
||||
{
|
||||
PushSurrogateAcceptCalls acceptCalls(aInstance);
|
||||
const NPNetscapeFuncs* npn = GetNetscapeFuncs(aInstance);
|
||||
if (npn) {
|
||||
npn->releasevariantvalue(&aVariant);
|
||||
|
@ -654,7 +652,6 @@ PluginScriptableObjectParent::CreateProxyObject()
|
|||
NS_ASSERTION(mInstance, "Must have an instance!");
|
||||
NS_ASSERTION(mType == Proxy, "Shouldn't call this for non-proxy object!");
|
||||
|
||||
PushSurrogateAcceptCalls acceptCalls(mInstance);
|
||||
const NPNetscapeFuncs* npn = GetNetscapeFuncs(mInstance);
|
||||
|
||||
NPObject* npobject = npn->createobject(mInstance->GetNPP(),
|
||||
|
@ -773,7 +770,6 @@ PluginScriptableObjectParent::AnswerHasMethod(const PluginIdentifier& aId,
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
PushSurrogateAcceptCalls acceptCalls(instance);
|
||||
const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance);
|
||||
if (!npn) {
|
||||
NS_ERROR("No netscape funcs?!");
|
||||
|
@ -814,7 +810,6 @@ PluginScriptableObjectParent::AnswerInvoke(const PluginIdentifier& aId,
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
PushSurrogateAcceptCalls acceptCalls(instance);
|
||||
const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance);
|
||||
if (!npn) {
|
||||
NS_ERROR("No netscape funcs?!");
|
||||
|
@ -904,7 +899,6 @@ PluginScriptableObjectParent::AnswerInvokeDefault(InfallibleTArray<Variant>&& aA
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
PushSurrogateAcceptCalls acceptCalls(instance);
|
||||
const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance);
|
||||
if (!npn) {
|
||||
NS_ERROR("No netscape funcs?!");
|
||||
|
@ -985,7 +979,6 @@ PluginScriptableObjectParent::AnswerHasProperty(const PluginIdentifier& aId,
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
PushSurrogateAcceptCalls acceptCalls(instance);
|
||||
const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance);
|
||||
if (!npn) {
|
||||
NS_ERROR("No netscape funcs?!");
|
||||
|
@ -1028,7 +1021,6 @@ PluginScriptableObjectParent::AnswerGetParentProperty(
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
PushSurrogateAcceptCalls acceptCalls(instance);
|
||||
const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance);
|
||||
if (!npn) {
|
||||
NS_ERROR("No netscape funcs?!");
|
||||
|
@ -1085,7 +1077,6 @@ PluginScriptableObjectParent::AnswerSetProperty(const PluginIdentifier& aId,
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
PushSurrogateAcceptCalls acceptCalls(instance);
|
||||
const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance);
|
||||
if (!npn) {
|
||||
NS_ERROR("No netscape funcs?!");
|
||||
|
@ -1132,7 +1123,6 @@ PluginScriptableObjectParent::AnswerRemoveProperty(const PluginIdentifier& aId,
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
PushSurrogateAcceptCalls acceptCalls(instance);
|
||||
const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance);
|
||||
if (!npn) {
|
||||
NS_ERROR("No netscape funcs?!");
|
||||
|
@ -1171,7 +1161,6 @@ PluginScriptableObjectParent::AnswerEnumerate(InfallibleTArray<PluginIdentifier>
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
PushSurrogateAcceptCalls acceptCalls(instance);
|
||||
const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance);
|
||||
if (!npn) {
|
||||
NS_WARNING("No netscape funcs?!");
|
||||
|
@ -1224,7 +1213,6 @@ PluginScriptableObjectParent::AnswerConstruct(InfallibleTArray<Variant>&& aArgs,
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
PushSurrogateAcceptCalls acceptCalls(instance);
|
||||
const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance);
|
||||
if (!npn) {
|
||||
NS_ERROR("No netscape funcs?!");
|
||||
|
@ -1317,7 +1305,6 @@ PluginScriptableObjectParent::AnswerNPN_Evaluate(const nsCString& aScript,
|
|||
return IPC_OK();
|
||||
}
|
||||
|
||||
PushSurrogateAcceptCalls acceptCalls(instance);
|
||||
const NPNetscapeFuncs* npn = GetNetscapeFuncs(instance);
|
||||
if (!npn) {
|
||||
NS_ERROR("No netscape funcs?!");
|
||||
|
|
|
@ -18,7 +18,6 @@ struct PluginTag
|
|||
nsCString[] extensions;
|
||||
bool isJavaPlugin;
|
||||
bool isFlashPlugin;
|
||||
bool supportsAsyncInit;
|
||||
bool supportsAsyncRender; // flash specific
|
||||
nsCString filename;
|
||||
nsCString version;
|
||||
|
|
|
@ -21,9 +21,7 @@ EXPORTS.mozilla.plugins += [
|
|||
'NPEventOSX.h',
|
||||
'NPEventUnix.h',
|
||||
'NPEventWindows.h',
|
||||
'PluginAsyncSurrogate.h',
|
||||
'PluginBridge.h',
|
||||
'PluginDataResolver.h',
|
||||
'PluginInstanceChild.h',
|
||||
'PluginInstanceParent.h',
|
||||
'PluginMessageUtils.h',
|
||||
|
@ -70,7 +68,6 @@ UNIFIED_SOURCES += [
|
|||
'BrowserStreamParent.cpp',
|
||||
'ChildAsyncCall.cpp',
|
||||
'ChildTimer.cpp',
|
||||
'PluginAsyncSurrogate.cpp',
|
||||
'PluginBackgroundDestroyer.cpp',
|
||||
'PluginInstanceParent.cpp',
|
||||
'PluginMessageUtils.cpp',
|
||||
|
|
|
@ -754,10 +754,14 @@ private:
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIPrincipal> triggeringPrincipal = workerPrivate->GetPrincipal();
|
||||
MOZ_DIAGNOSTIC_ASSERT(triggeringPrincipal);
|
||||
|
||||
nsCOMPtr<mozIDOMWindowProxy> win;
|
||||
rv = bwin->OpenURI(uri, nullptr,
|
||||
nsIBrowserDOMWindow::OPEN_DEFAULTWINDOW,
|
||||
nsIBrowserDOMWindow::OPEN_NEW,
|
||||
triggeringPrincipal,
|
||||
getter_AddRefs(win));
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
|
|
|
@ -165,7 +165,7 @@ public:
|
|||
|
||||
void ClearById(const uint64_t& aId);
|
||||
private:
|
||||
~CompositorAnimationStorage() { Clear(); };
|
||||
~CompositorAnimationStorage() { };
|
||||
|
||||
private:
|
||||
AnimatedValueTable mAnimatedValues;
|
||||
|
|
|
@ -6,7 +6,11 @@
|
|||
|
||||
#include "PaintThread.h"
|
||||
|
||||
#include "base/task.h"
|
||||
#include "gfxPrefs.h"
|
||||
#include "mozilla/layers/CompositorBridgeChild.h"
|
||||
#include "mozilla/gfx/2D.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/SyncRunnable.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -15,6 +19,8 @@ namespace layers {
|
|||
using namespace gfx;
|
||||
|
||||
StaticAutoPtr<PaintThread> PaintThread::sSingleton;
|
||||
StaticRefPtr<nsIThread> PaintThread::sThread;
|
||||
PlatformThreadId PaintThread::sThreadId;
|
||||
|
||||
void
|
||||
PaintThread::Release()
|
||||
|
@ -30,24 +36,25 @@ void
|
|||
PaintThread::InitOnPaintThread()
|
||||
{
|
||||
MOZ_ASSERT(!NS_IsMainThread());
|
||||
mThreadId = PlatformThread::CurrentId();
|
||||
sThreadId = PlatformThread::CurrentId();
|
||||
}
|
||||
|
||||
bool
|
||||
PaintThread::Init()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
nsresult rv = NS_NewNamedThread("PaintThread", getter_AddRefs(mThread));
|
||||
|
||||
RefPtr<nsIThread> thread;
|
||||
nsresult rv = NS_NewNamedThread("PaintThread", getter_AddRefs(thread));
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
sThread = thread;
|
||||
|
||||
nsCOMPtr<nsIRunnable> paintInitTask =
|
||||
NewRunnableMethod("PaintThread::InitOnPaintThread",
|
||||
this, &PaintThread::InitOnPaintThread);
|
||||
|
||||
SyncRunnable::DispatchToThread(PaintThread::sSingleton->mThread, paintInitTask);
|
||||
SyncRunnable::DispatchToThread(sThread, paintInitTask);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -69,49 +76,84 @@ PaintThread::Get()
|
|||
return PaintThread::sSingleton.get();
|
||||
}
|
||||
|
||||
void
|
||||
DestroyPaintThread(UniquePtr<PaintThread>&& pt)
|
||||
{
|
||||
MOZ_ASSERT(PaintThread::IsOnPaintThread());
|
||||
pt->ShutdownOnPaintThread();
|
||||
}
|
||||
|
||||
/* static */ void
|
||||
PaintThread::Shutdown()
|
||||
{
|
||||
if (!PaintThread::sSingleton) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
UniquePtr<PaintThread> pt(sSingleton.forget());
|
||||
if (!pt) {
|
||||
return;
|
||||
}
|
||||
|
||||
PaintThread::sSingleton->ShutdownImpl();
|
||||
PaintThread::sSingleton = nullptr;
|
||||
sThread->Dispatch(NewRunnableFunction(DestroyPaintThread, Move(pt)));
|
||||
sThread->Shutdown();
|
||||
sThread = nullptr;
|
||||
}
|
||||
|
||||
void
|
||||
PaintThread::ShutdownImpl()
|
||||
PaintThread::ShutdownOnPaintThread()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
PaintThread::sSingleton->mThread->AsyncShutdown();
|
||||
MOZ_ASSERT(IsOnPaintThread());
|
||||
}
|
||||
|
||||
bool
|
||||
/* static */ bool
|
||||
PaintThread::IsOnPaintThread()
|
||||
{
|
||||
MOZ_ASSERT(mThread);
|
||||
return PlatformThread::CurrentId() == mThreadId;
|
||||
return sThreadId == PlatformThread::CurrentId();
|
||||
}
|
||||
|
||||
void
|
||||
PaintThread::PaintContentsAsync(CompositorBridgeChild* aBridge,
|
||||
gfx::DrawTargetCapture* aCapture,
|
||||
gfx::DrawTarget* aTarget)
|
||||
{
|
||||
MOZ_ASSERT(IsOnPaintThread());
|
||||
|
||||
// Draw all the things into the actual dest target.
|
||||
aTarget->DrawCapturedDT(aCapture, Matrix());
|
||||
|
||||
if (aBridge) {
|
||||
aBridge->NotifyFinishedAsyncPaint();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PaintThread::PaintContents(DrawTargetCapture* aCapture,
|
||||
DrawTarget* aTarget)
|
||||
{
|
||||
if (!IsOnPaintThread()) {
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
nsCOMPtr<nsIRunnable> paintTask =
|
||||
NewRunnableMethod<DrawTargetCapture*, DrawTarget*>("PaintThread::PaintContents",
|
||||
this,
|
||||
&PaintThread::PaintContents,
|
||||
aCapture, aTarget);
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
SyncRunnable::DispatchToThread(mThread, paintTask);
|
||||
return;
|
||||
// If painting asynchronously, we need to acquire the compositor bridge which
|
||||
// owns the underlying MessageChannel. Otherwise we leave it null and use
|
||||
// synchronous dispatch.
|
||||
RefPtr<CompositorBridgeChild> cbc;
|
||||
if (!gfxPrefs::LayersOMTPForceSync()) {
|
||||
cbc = CompositorBridgeChild::Get();
|
||||
cbc->NotifyBeginAsyncPaint();
|
||||
}
|
||||
RefPtr<DrawTargetCapture> capture(aCapture);
|
||||
RefPtr<DrawTarget> target(aTarget);
|
||||
|
||||
// Draw all the things into the actual dest target.
|
||||
aTarget->DrawCapturedDT(aCapture, Matrix());
|
||||
RefPtr<PaintThread> self = this;
|
||||
RefPtr<Runnable> task = NS_NewRunnableFunction("PaintThread::PaintContents",
|
||||
[self, cbc, capture, target]() -> void
|
||||
{
|
||||
self->PaintContentsAsync(cbc, capture, target);
|
||||
});
|
||||
|
||||
if (cbc) {
|
||||
sThread->Dispatch(task.forget());
|
||||
} else {
|
||||
SyncRunnable::DispatchToThread(sThread, task);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
|
||||
#include "base/platform_thread.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -19,14 +20,19 @@ class DrawTargetCapture;
|
|||
|
||||
namespace layers {
|
||||
|
||||
class CompositorBridgeChild;
|
||||
|
||||
class PaintThread final
|
||||
{
|
||||
friend void DestroyPaintThread(UniquePtr<PaintThread>&& aPaintThread);
|
||||
|
||||
public:
|
||||
static void Start();
|
||||
static void Shutdown();
|
||||
static PaintThread* Get();
|
||||
void PaintContents(gfx::DrawTargetCapture* aCapture,
|
||||
gfx::DrawTarget* aTarget);
|
||||
|
||||
// Sync Runnables need threads to be ref counted,
|
||||
// But this thread lives through the whole process.
|
||||
// We're only temporarily using sync runnables so
|
||||
|
@ -34,15 +40,20 @@ public:
|
|||
void Release();
|
||||
void AddRef();
|
||||
|
||||
// Helper for asserts.
|
||||
static bool IsOnPaintThread();
|
||||
|
||||
private:
|
||||
bool IsOnPaintThread();
|
||||
bool Init();
|
||||
void ShutdownImpl();
|
||||
void ShutdownOnPaintThread();
|
||||
void InitOnPaintThread();
|
||||
void PaintContentsAsync(CompositorBridgeChild* aBridge,
|
||||
gfx::DrawTargetCapture* aCapture,
|
||||
gfx::DrawTarget* aTarget);
|
||||
|
||||
static StaticAutoPtr<PaintThread> sSingleton;
|
||||
RefPtr<nsIThread> mThread;
|
||||
PlatformThreadId mThreadId;
|
||||
static StaticRefPtr<nsIThread> sThread;
|
||||
static PlatformThreadId sThreadId;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
|
|
|
@ -226,6 +226,9 @@ ClientLayerManager::CreateReadbackLayer()
|
|||
bool
|
||||
ClientLayerManager::BeginTransactionWithTarget(gfxContext* aTarget)
|
||||
{
|
||||
// Wait for any previous async paints to complete before starting to paint again.
|
||||
GetCompositorBridgeChild()->FlushAsyncPaints();
|
||||
|
||||
MOZ_ASSERT(mForwarder, "ClientLayerManager::BeginTransaction without forwarder");
|
||||
if (!mForwarder->IPCOpen()) {
|
||||
gfxCriticalNote << "ClientLayerManager::BeginTransaction with IPC channel down. GPU process may have died.";
|
||||
|
|
|
@ -313,6 +313,7 @@ public:
|
|||
virtual already_AddRefed<RefLayer> CreateRefLayer() override;
|
||||
|
||||
virtual bool AreComponentAlphaLayersEnabled() override;
|
||||
virtual bool SupportsBackdropCopyForComponentAlpha() override { return false; }
|
||||
|
||||
virtual already_AddRefed<DrawTarget>
|
||||
CreateOptimalMaskDrawTarget(const IntSize &aSize) override;
|
||||
|
@ -514,7 +515,7 @@ private:
|
|||
#endif
|
||||
#if defined(MOZ_WIDGET_ANDROID)
|
||||
public:
|
||||
virtual void RequestScreenPixels(UiCompositorControllerParent* aController)
|
||||
virtual void RequestScreenPixels(UiCompositorControllerParent* aController) override
|
||||
{
|
||||
mScreenPixelsTarget = aController;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include "mozilla/layers/IAPZCTreeManager.h"
|
||||
#include "mozilla/layers/APZCTreeManagerChild.h"
|
||||
#include "mozilla/layers/LayerTransactionChild.h"
|
||||
#include "mozilla/layers/PaintThread.h"
|
||||
#include "mozilla/layers/PLayerTransactionChild.h"
|
||||
#include "mozilla/layers/PTextureChild.h"
|
||||
#include "mozilla/layers/TextureClient.h"// for TextureClient
|
||||
|
@ -89,6 +90,9 @@ CompositorBridgeChild::CompositorBridgeChild(CompositorManagerChild *aManager)
|
|||
, mMessageLoop(MessageLoop::current())
|
||||
, mProcessToken(0)
|
||||
, mSectionAllocator(nullptr)
|
||||
, mPaintLock("CompositorBridgeChild.mPaintLock")
|
||||
, mOutstandingAsyncPaints(0)
|
||||
, mIsWaitingForPaint(false)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
}
|
||||
|
@ -542,8 +546,20 @@ CompositorBridgeChild::ActorDestroy(ActorDestroyReason aWhy)
|
|||
gfxCriticalNote << "Receive IPC close with reason=AbnormalShutdown";
|
||||
}
|
||||
|
||||
mCanSend = false;
|
||||
mActorDestroyed = true;
|
||||
{
|
||||
// We take the lock to update these fields, since they are read from the
|
||||
// paint thread. We don't need the lock to init them, since that happens
|
||||
// on the main thread before the paint thread can ever grab a reference
|
||||
// to the CompositorBridge object.
|
||||
//
|
||||
// Note that it is useful to take this lock for one other reason: It also
|
||||
// tells us whether GetIPCChannel is safe to call. If we access the IPC
|
||||
// channel within this lock, when mCanSend is true, then we know it has not
|
||||
// been zapped by IPDL.
|
||||
MonitorAutoLock lock(mPaintLock);
|
||||
mCanSend = false;
|
||||
mActorDestroyed = true;
|
||||
}
|
||||
|
||||
if (mProcessToken && XRE_IsParentProcess()) {
|
||||
GPUProcessManager::Get()->NotifyRemoteActorDestroyed(mProcessToken);
|
||||
|
@ -1114,6 +1130,86 @@ CompositorBridgeChild::GetNextPipelineId()
|
|||
return wr::AsPipelineId(GetNextResourceId());
|
||||
}
|
||||
|
||||
void
|
||||
CompositorBridgeChild::NotifyBeginAsyncPaint()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
MonitorAutoLock lock(mPaintLock);
|
||||
|
||||
// We must not be waiting for paints to complete yet. This would imply we
|
||||
// started a new paint without waiting for a previous one, which could lead to
|
||||
// incorrect rendering or IPDL deadlocks.
|
||||
MOZ_ASSERT(!mIsWaitingForPaint);
|
||||
|
||||
mOutstandingAsyncPaints++;
|
||||
}
|
||||
|
||||
void
|
||||
CompositorBridgeChild::NotifyFinishedAsyncPaint()
|
||||
{
|
||||
MOZ_ASSERT(PaintThread::IsOnPaintThread());
|
||||
|
||||
MonitorAutoLock lock(mPaintLock);
|
||||
|
||||
mOutstandingAsyncPaints--;
|
||||
|
||||
// It's possible that we painted so fast that the main thread never reached
|
||||
// the code that starts delaying messages. If so, mIsWaitingForPaint will be
|
||||
// false, and we can safely return.
|
||||
if (mIsWaitingForPaint && mOutstandingAsyncPaints == 0) {
|
||||
ResumeIPCAfterAsyncPaint();
|
||||
|
||||
// Notify the main thread in case it's blocking. We do this unconditionally
|
||||
// to avoid deadlocking.
|
||||
lock.Notify();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CompositorBridgeChild::PostponeMessagesIfAsyncPainting()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
MonitorAutoLock lock(mPaintLock);
|
||||
|
||||
MOZ_ASSERT(!mIsWaitingForPaint);
|
||||
|
||||
if (mOutstandingAsyncPaints > 0) {
|
||||
mIsWaitingForPaint = true;
|
||||
GetIPCChannel()->BeginPostponingSends();
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CompositorBridgeChild::ResumeIPCAfterAsyncPaint()
|
||||
{
|
||||
// Note: the caller is responsible for holding the lock.
|
||||
mPaintLock.AssertCurrentThreadOwns();
|
||||
MOZ_ASSERT(PaintThread::IsOnPaintThread());
|
||||
MOZ_ASSERT(mOutstandingAsyncPaints == 0);
|
||||
MOZ_ASSERT(mIsWaitingForPaint);
|
||||
|
||||
mIsWaitingForPaint = false;
|
||||
|
||||
// It's also possible that the channel has shut down already.
|
||||
if (!mCanSend || mActorDestroyed) {
|
||||
return;
|
||||
}
|
||||
|
||||
GetIPCChannel()->StopPostponingSends();
|
||||
}
|
||||
|
||||
void
|
||||
CompositorBridgeChild::FlushAsyncPaints()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
MonitorAutoLock lock(mPaintLock);
|
||||
while (mIsWaitingForPaint) {
|
||||
lock.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace layers
|
||||
} // namespace mozilla
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "base/basictypes.h" // for DISALLOW_EVIL_CONSTRUCTORS
|
||||
#include "mozilla/Assertions.h" // for MOZ_ASSERT_HELPER2
|
||||
#include "mozilla/Attributes.h" // for override
|
||||
#include "mozilla/Monitor.h"
|
||||
#include "mozilla/ipc/ProtocolUtils.h"
|
||||
#include "mozilla/layers/PCompositorBridgeChild.h"
|
||||
#include "mozilla/layers/TextureForwarder.h" // for TextureForwarder
|
||||
|
@ -220,10 +221,33 @@ public:
|
|||
|
||||
wr::PipelineId GetNextPipelineId();
|
||||
|
||||
// Must only be called from the main thread. Notifies the CompositorBridge
|
||||
// that the paint thread is going to begin painting asynchronously.
|
||||
void NotifyBeginAsyncPaint();
|
||||
|
||||
// Must only be called from the paint thread. Notifies the CompositorBridge
|
||||
// that the paint thread has finished an asynchronous paint request.
|
||||
void NotifyFinishedAsyncPaint();
|
||||
|
||||
// Must only be called from the main thread. Notifies the CompoistorBridge
|
||||
// that a transaction is about to be sent, and if the paint thread is
|
||||
// currently painting, to begin delaying IPC messages.
|
||||
void PostponeMessagesIfAsyncPainting();
|
||||
|
||||
// Must only be called from the main thread. Ensures that any paints from
|
||||
// previous frames have been flushed. The main thread blocks until the
|
||||
// operation completes.
|
||||
void FlushAsyncPaints();
|
||||
|
||||
private:
|
||||
// Private destructor, to discourage deletion outside of Release():
|
||||
virtual ~CompositorBridgeChild();
|
||||
|
||||
// Must only be called from the paint thread. If the main thread is delaying
|
||||
// IPC messages, this forwards all such delayed IPC messages to the I/O thread
|
||||
// and resumes IPC.
|
||||
void ResumeIPCAfterAsyncPaint();
|
||||
|
||||
void AfterDestroy();
|
||||
|
||||
virtual PLayerTransactionChild*
|
||||
|
@ -328,6 +352,20 @@ private:
|
|||
uint64_t mProcessToken;
|
||||
|
||||
FixedSizeSmallShmemSectionAllocator* mSectionAllocator;
|
||||
|
||||
// Off-Main-Thread Painting state. This covers access to the OMTP-related
|
||||
// state below.
|
||||
Monitor mPaintLock;
|
||||
|
||||
// Contains the number of outstanding asynchronous paints tied to a
|
||||
// PLayerTransaction on this bridge. This is R/W on both the main and paint
|
||||
// threads, and must be accessed within the paint lock.
|
||||
size_t mOutstandingAsyncPaints;
|
||||
|
||||
// True if this CompositorBridge is currently delaying its messages until the
|
||||
// paint thread completes. This is R/W on both the main and paint threads, and
|
||||
// must be accessed within the paint lock.
|
||||
bool mIsWaitingForPaint;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
|
|
|
@ -1515,14 +1515,14 @@ CompositorBridgeParent::AllocPLayerTransactionParent(const nsTArray<LayersBacken
|
|||
|
||||
if (!mLayerManager) {
|
||||
NS_WARNING("Failed to initialise Compositor");
|
||||
LayerTransactionParent* p = new LayerTransactionParent(nullptr, this, 0);
|
||||
LayerTransactionParent* p = new LayerTransactionParent(/* aManager */ nullptr, this, /* aAnimStorage */ nullptr, 0);
|
||||
p->AddIPDLReference();
|
||||
return p;
|
||||
}
|
||||
|
||||
mCompositionManager = new AsyncCompositionManager(this, mLayerManager);
|
||||
|
||||
LayerTransactionParent* p = new LayerTransactionParent(mLayerManager, this, 0);
|
||||
LayerTransactionParent* p = new LayerTransactionParent(mLayerManager, this, GetAnimationStorage(0), 0);
|
||||
p->AddIPDLReference();
|
||||
return p;
|
||||
}
|
||||
|
@ -1644,7 +1644,7 @@ CompositorBridgeParent::RecvAdoptChild(const uint64_t& child)
|
|||
MOZ_ASSERT(sIndirectLayerTrees[child].mParent->mOptions == mOptions);
|
||||
NotifyChildCreated(child);
|
||||
if (sIndirectLayerTrees[child].mLayerTree) {
|
||||
sIndirectLayerTrees[child].mLayerTree->SetLayerManager(mLayerManager);
|
||||
sIndirectLayerTrees[child].mLayerTree->SetLayerManager(mLayerManager, GetAnimationStorage(0));
|
||||
// Trigger composition to handle a case that mLayerTree was not composited yet
|
||||
// by previous CompositorBridgeParent, since nsRefreshDriver might wait composition complete.
|
||||
ScheduleComposition();
|
||||
|
|
|
@ -88,14 +88,15 @@ CrossProcessCompositorBridgeParent::AllocPLayerTransactionParent(
|
|||
if (state && state->mLayerManager) {
|
||||
state->mCrossProcessParent = this;
|
||||
HostLayerManager* lm = state->mLayerManager;
|
||||
LayerTransactionParent* p = new LayerTransactionParent(lm, this, aId);
|
||||
CompositorAnimationStorage* animStorage = state->mParent ? state->mParent->GetAnimationStorage(0) : nullptr;
|
||||
LayerTransactionParent* p = new LayerTransactionParent(lm, this, animStorage, aId);
|
||||
p->AddIPDLReference();
|
||||
sIndirectLayerTrees[aId].mLayerTree = p;
|
||||
return p;
|
||||
}
|
||||
|
||||
NS_WARNING("Created child without a matching parent?");
|
||||
LayerTransactionParent* p = new LayerTransactionParent(nullptr, this, aId);
|
||||
LayerTransactionParent* p = new LayerTransactionParent(/* aManager */ nullptr, this, /* aAnimStorage */ nullptr, aId);
|
||||
p->AddIPDLReference();
|
||||
return p;
|
||||
}
|
||||
|
|
|
@ -51,9 +51,11 @@ namespace layers {
|
|||
// LayerTransactionParent
|
||||
LayerTransactionParent::LayerTransactionParent(HostLayerManager* aManager,
|
||||
CompositorBridgeParentBase* aBridge,
|
||||
CompositorAnimationStorage* aAnimStorage,
|
||||
uint64_t aId)
|
||||
: mLayerManager(aManager)
|
||||
, mCompositorBridge(aBridge)
|
||||
, mAnimStorage(aAnimStorage)
|
||||
, mId(aId)
|
||||
, mChildEpoch(0)
|
||||
, mParentEpoch(0)
|
||||
|
@ -68,13 +70,21 @@ LayerTransactionParent::~LayerTransactionParent()
|
|||
}
|
||||
|
||||
void
|
||||
LayerTransactionParent::SetLayerManager(HostLayerManager* aLayerManager)
|
||||
LayerTransactionParent::SetLayerManager(HostLayerManager* aLayerManager, CompositorAnimationStorage* aAnimStorage)
|
||||
{
|
||||
if (mDestroyed) {
|
||||
return;
|
||||
}
|
||||
mLayerManager = aLayerManager;
|
||||
for (auto iter = mLayerMap.Iter(); !iter.Done(); iter.Next()) {
|
||||
auto layer = iter.Data();
|
||||
if (mAnimStorage &&
|
||||
layer->GetCompositorAnimationsId()) {
|
||||
mAnimStorage->ClearById(layer->GetCompositorAnimationsId());
|
||||
}
|
||||
layer->AsHostLayer()->SetLayerManager(aLayerManager);
|
||||
}
|
||||
mAnimStorage = aAnimStorage;
|
||||
}
|
||||
|
||||
mozilla::ipc::IPCResult
|
||||
|
@ -101,7 +111,16 @@ LayerTransactionParent::Destroy()
|
|||
return;
|
||||
}
|
||||
mDestroyed = true;
|
||||
if (mAnimStorage) {
|
||||
for (auto iter = mLayerMap.Iter(); !iter.Done(); iter.Next()) {
|
||||
auto layer = iter.Data();
|
||||
if (layer->GetCompositorAnimationsId()) {
|
||||
mAnimStorage->ClearById(layer->GetCompositorAnimationsId());
|
||||
}
|
||||
}
|
||||
}
|
||||
mCompositables.clear();
|
||||
mAnimStorage = nullptr;
|
||||
}
|
||||
|
||||
class MOZ_STACK_CLASS AutoLayerTransactionParentAsyncMessageSender
|
||||
|
@ -535,14 +554,10 @@ LayerTransactionParent::SetLayerAttributes(const OpSetLayerAttributes& aOp)
|
|||
layer->SetCompositorAnimations(common.compositorAnimations());
|
||||
// Clean up the Animations by id in the CompositorAnimationStorage
|
||||
// if there are no active animations on the layer
|
||||
if (layer->GetCompositorAnimationsId() &&
|
||||
if (mAnimStorage &&
|
||||
layer->GetCompositorAnimationsId() &&
|
||||
layer->GetAnimations().IsEmpty()) {
|
||||
CompositorAnimationStorage* storage =
|
||||
mCompositorBridge->GetAnimationStorage(GetId());
|
||||
|
||||
if (storage) {
|
||||
storage->ClearById(layer->GetCompositorAnimationsId());
|
||||
}
|
||||
mAnimStorage->ClearById(layer->GetCompositorAnimationsId());
|
||||
}
|
||||
if (common.scrollMetadata() != layer->GetAllScrollMetadata()) {
|
||||
UpdateHitTestingTree(layer, "scroll metadata changed");
|
||||
|
@ -727,14 +742,11 @@ LayerTransactionParent::RecvGetAnimationOpacity(const uint64_t& aCompositorAnima
|
|||
|
||||
mCompositorBridge->ApplyAsyncProperties(this);
|
||||
|
||||
CompositorAnimationStorage* storage =
|
||||
mCompositorBridge->GetAnimationStorage(GetId());
|
||||
|
||||
if (!storage) {
|
||||
if (!mAnimStorage) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
Maybe<float> opacity = storage->GetAnimationOpacity(aCompositorAnimationsId);
|
||||
Maybe<float> opacity = mAnimStorage->GetAnimationOpacity(aCompositorAnimationsId);
|
||||
if (opacity) {
|
||||
*aOpacity = *opacity;
|
||||
*aHasAnimationOpacity = true;
|
||||
|
@ -756,14 +768,11 @@ LayerTransactionParent::RecvGetAnimationTransform(const uint64_t& aCompositorAni
|
|||
// the value.
|
||||
mCompositorBridge->ApplyAsyncProperties(this);
|
||||
|
||||
CompositorAnimationStorage* storage =
|
||||
mCompositorBridge->GetAnimationStorage(GetId());
|
||||
|
||||
if (!storage) {
|
||||
if (!mAnimStorage) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
|
||||
Maybe<Matrix4x4> transform = storage->GetAnimationTransform(aCompositorAnimationsId);
|
||||
Maybe<Matrix4x4> transform = mAnimStorage->GetAnimationTransform(aCompositorAnimationsId);
|
||||
if (transform) {
|
||||
*aTransform = *transform;
|
||||
} else {
|
||||
|
@ -1008,6 +1017,10 @@ LayerTransactionParent::RecvReleaseLayer(const LayerHandle& aHandle)
|
|||
if (!aHandle || !mLayerMap.Remove(aHandle.Value(), getter_AddRefs(layer))) {
|
||||
return IPC_FAIL_NO_REASON(this);
|
||||
}
|
||||
if (mAnimStorage &&
|
||||
layer->GetCompositorAnimationsId()) {
|
||||
mAnimStorage->ClearById(layer->GetCompositorAnimationsId());
|
||||
}
|
||||
layer->Disconnect();
|
||||
return IPC_OK();
|
||||
}
|
||||
|
|
|
@ -33,6 +33,7 @@ class Layer;
|
|||
class HostLayerManager;
|
||||
class ShadowLayerParent;
|
||||
class CompositableParent;
|
||||
class CompositorAnimationStorage;
|
||||
class CompositorBridgeParentBase;
|
||||
|
||||
class LayerTransactionParent final : public PLayerTransactionParent,
|
||||
|
@ -48,6 +49,7 @@ class LayerTransactionParent final : public PLayerTransactionParent,
|
|||
public:
|
||||
LayerTransactionParent(HostLayerManager* aManager,
|
||||
CompositorBridgeParentBase* aBridge,
|
||||
CompositorAnimationStorage* aAnimStorage,
|
||||
uint64_t aId);
|
||||
|
||||
protected:
|
||||
|
@ -58,7 +60,7 @@ public:
|
|||
|
||||
HostLayerManager* layer_manager() const { return mLayerManager; }
|
||||
|
||||
void SetLayerManager(HostLayerManager* aLayerManager);
|
||||
void SetLayerManager(HostLayerManager* aLayerManager, CompositorAnimationStorage* aAnimStorage);
|
||||
|
||||
uint64_t GetId() const { return mId; }
|
||||
Layer* GetRoot() const { return mRoot; }
|
||||
|
@ -174,6 +176,7 @@ private:
|
|||
private:
|
||||
RefPtr<HostLayerManager> mLayerManager;
|
||||
CompositorBridgeParentBase* mCompositorBridge;
|
||||
RefPtr<CompositorAnimationStorage> mAnimStorage;
|
||||
|
||||
// Hold the root because it might be grafted under various
|
||||
// containers in the "real" layer tree
|
||||
|
|
|
@ -764,6 +764,10 @@ ShadowLayerForwarder::EndTransaction(const nsIntRegion& aRegionToClear,
|
|||
}
|
||||
}
|
||||
|
||||
// We delay at the last possible minute, to give the paint thread a chance to
|
||||
// finish. If it does we don't have to delay messages at all.
|
||||
GetCompositorBridgeChild()->PostponeMessagesIfAsyncPainting();
|
||||
|
||||
MOZ_LAYERS_LOG(("[LayersForwarder] sending transaction..."));
|
||||
RenderTraceScope rendertrace3("Forward Transaction", "000093");
|
||||
if (!mShadowManager->SendUpdate(info)) {
|
||||
|
|
|
@ -348,6 +348,10 @@ ShaderRenderPass::SetupPSBuffer0(float aOpacity)
|
|||
void
|
||||
ShaderRenderPass::ExecuteRendering()
|
||||
{
|
||||
if (mVertices.IsEmpty() && mInstances.IsEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
mDevice->SetPSConstantBuffer(0, &mPSBuffer0);
|
||||
if (MaskOperation* mask = GetMask()) {
|
||||
mDevice->SetPSTexture(kMaskLayerTextureSlot, mask->GetTexture());
|
||||
|
@ -881,6 +885,10 @@ RenderViewPass::AddToPass(LayerMLGPU* aLayer, ItemInfo& aInfo)
|
|||
}
|
||||
|
||||
mSource = mAssignedLayer->GetRenderTarget();
|
||||
if (!mSource) {
|
||||
return false;
|
||||
}
|
||||
|
||||
mParentView = aInfo.view;
|
||||
|
||||
Txn txn(this);
|
||||
|
|
|
@ -127,14 +127,14 @@ public:
|
|||
virtual gfxFontEntry* LookupLocalFont(const nsAString& aFontName,
|
||||
uint16_t aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle);
|
||||
uint8_t aStyle) override;
|
||||
|
||||
virtual gfxFontEntry* MakePlatformFont(const nsAString& aFontName,
|
||||
uint16_t aWeight,
|
||||
int16_t aStretch,
|
||||
uint8_t aStyle,
|
||||
const uint8_t* aFontData,
|
||||
uint32_t aLength);
|
||||
uint32_t aLength) override;
|
||||
|
||||
void GetSystemFontList(InfallibleTArray<FontListEntry>* retValue);
|
||||
|
||||
|
@ -142,7 +142,7 @@ public:
|
|||
return static_cast<gfxFT2FontList*>(gfxPlatformFontList::PlatformFontList());
|
||||
}
|
||||
|
||||
virtual void GetFontFamilyList(nsTArray<RefPtr<gfxFontFamily> >& aFamilyArray);
|
||||
virtual void GetFontFamilyList(nsTArray<RefPtr<gfxFontFamily> >& aFamilyArray) override;
|
||||
|
||||
void WillShutdown();
|
||||
|
||||
|
|
|
@ -585,6 +585,7 @@ private:
|
|||
DECL_GFX_PREF(Once, "layers.mlgpu.enable-container-resizing", AdvancedLayersEnableContainerResizing, bool, true);
|
||||
DECL_GFX_PREF(Once, "layers.offmainthreadcomposition.force-disabled", LayersOffMainThreadCompositionForceDisabled, bool, false);
|
||||
DECL_GFX_PREF(Live, "layers.offmainthreadcomposition.frame-rate", LayersCompositionFrameRate, int32_t,-1);
|
||||
DECL_GFX_PREF(Live, "layers.omtp.force-sync", LayersOMTPForceSync, bool, true);
|
||||
DECL_GFX_PREF(Live, "layers.orientation.sync.timeout", OrientationSyncMillis, uint32_t, (uint32_t)0);
|
||||
DECL_GFX_PREF(Once, "layers.prefer-opengl", LayersPreferOpenGL, bool, false);
|
||||
DECL_GFX_PREF(Live, "layers.progressive-paint", ProgressivePaint, bool, false);
|
||||
|
|
|
@ -541,7 +541,7 @@ public:
|
|||
|
||||
void AddProxy(imgRequestProxy* aProxy);
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER
|
||||
NS_DECL_NSISTREAMLISTENER
|
||||
NS_DECL_NSIREQUESTOBSERVER
|
||||
|
|
|
@ -6,11 +6,13 @@
|
|||
|
||||
#include "mozilla/mscom/MainThreadRuntime.h"
|
||||
|
||||
#if defined(ACCESSIBILITY)
|
||||
#include "mozilla/a11y/Compatibility.h"
|
||||
#endif
|
||||
#include "mozilla/ArrayUtils.h"
|
||||
#include "mozilla/Assertions.h"
|
||||
#include "mozilla/RefPtr.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "mozilla/WindowsVersion.h"
|
||||
#include "nsWindowsHelpers.h"
|
||||
#include "nsXULAppAPI.h"
|
||||
|
||||
|
@ -34,29 +36,6 @@ struct LocalFreeDeleter
|
|||
// This API from oleaut32.dll is not declared in Windows SDK headers
|
||||
extern "C" void __cdecl SetOaNoCache(void);
|
||||
|
||||
#if defined(ACCESSIBILITY)
|
||||
static WORD
|
||||
GetActCtxResourceId()
|
||||
{
|
||||
// The manifest for 32-bit Windows is embedded with resource ID 32.
|
||||
// The manifest for 64-bit Windows is embedded with resource ID 64.
|
||||
// Beginning with Windows 10 Creators Update, 32-bit builds use the 64-bit
|
||||
// manifest.
|
||||
WORD actCtxResourceId;
|
||||
#if defined(HAVE_64BIT_BUILD)
|
||||
actCtxResourceId = 64;
|
||||
#else
|
||||
if (mozilla::IsWin10CreatorsUpdateOrLater()) {
|
||||
actCtxResourceId = 64;
|
||||
} else {
|
||||
actCtxResourceId = 32;
|
||||
}
|
||||
#endif // defined(HAVE_64BIT_BUILD)
|
||||
|
||||
return actCtxResourceId;
|
||||
}
|
||||
#endif // defined(ACCESSIBILITY)
|
||||
|
||||
namespace mozilla {
|
||||
namespace mscom {
|
||||
|
||||
|
@ -65,7 +44,7 @@ MainThreadRuntime* MainThreadRuntime::sInstance = nullptr;
|
|||
MainThreadRuntime::MainThreadRuntime()
|
||||
: mInitResult(E_UNEXPECTED)
|
||||
#if defined(ACCESSIBILITY)
|
||||
, mActCtxRgn(::GetActCtxResourceId())
|
||||
, mActCtxRgn(a11y::Compatibility::GetActCtxResourceId())
|
||||
#endif // defined(ACCESSIBILITY)
|
||||
{
|
||||
// We must be the outermost COM initialization on this thread. The COM runtime
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
getLcovInfo();
|
||||
getLcovInfo();
|
|
@ -7169,9 +7169,6 @@ PresShell::HandleEvent(nsIFrame* aFrame,
|
|||
// Update the latest focus sequence number with this new sequence number
|
||||
if (mAPZFocusSequenceNumber < aEvent->mFocusSequenceNumber) {
|
||||
mAPZFocusSequenceNumber = aEvent->mFocusSequenceNumber;
|
||||
|
||||
// Schedule an empty transaction to transmit this focus update
|
||||
aFrame->SchedulePaint(nsIFrame::PAINT_COMPOSITE_ONLY);
|
||||
}
|
||||
|
||||
if (sPointerEventEnabled) {
|
||||
|
|
|
@ -857,8 +857,10 @@ AddAndRemoveImageAssociations(nsFrame* aFrame,
|
|||
continue;
|
||||
}
|
||||
|
||||
if (imgRequestProxy* req = oldImage.GetImageData()) {
|
||||
imageLoader->DisassociateRequestFromFrame(req, aFrame);
|
||||
if (aFrame->HasImageRequest()) {
|
||||
if (imgRequestProxy* req = oldImage.GetImageData()) {
|
||||
imageLoader->DisassociateRequestFromFrame(req, aFrame);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -972,7 +974,7 @@ nsFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
|
|||
// they won't have the correct size for the border either.
|
||||
if (oldBorderImage != newBorderImage) {
|
||||
// stop and restart the image loading/notification
|
||||
if (oldBorderImage) {
|
||||
if (oldBorderImage && HasImageRequest()) {
|
||||
imageLoader->DisassociateRequestFromFrame(oldBorderImage, this);
|
||||
}
|
||||
if (newBorderImage) {
|
||||
|
|
|
@ -4749,6 +4749,7 @@ nsGridContainerFrame::Tracks::AlignJustifyContent(
|
|||
default:
|
||||
MOZ_ASSERT_UNREACHABLE("unknown align-/justify-content value");
|
||||
between = 0; // just to avoid a compiler warning
|
||||
roundingError = 0; // just to avoid a compiler warning
|
||||
}
|
||||
between += mGridGap;
|
||||
for (TrackSize& sz : mSizes) {
|
||||
|
|
|
@ -5137,8 +5137,7 @@ nsDisplayText::nsDisplayText(nsDisplayListBuilder* aBuilder, nsTextFrame* aFrame
|
|||
Color color;
|
||||
if (!capture->ContainsOnlyColoredGlyphs(mFont, color, glyphs)
|
||||
|| !mFont
|
||||
|| !mFont->CanSerialize()
|
||||
|| XRE_IsParentProcess()) {
|
||||
|| !mFont->CanSerialize()) {
|
||||
mFont = nullptr;
|
||||
mGlyphs.Clear();
|
||||
} else {
|
||||
|
|
|
@ -95,6 +95,11 @@ public:
|
|||
mBits |= eUncacheable;
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
*this = RuleNodeCacheConditions();
|
||||
}
|
||||
|
||||
bool Cacheable() const
|
||||
{
|
||||
return !(mBits & eUncacheable);
|
||||
|
|
|
@ -2678,6 +2678,42 @@ nsRuleNode::WalkRuleTree(const nsStyleStructID aSID,
|
|||
"not forcing detail to eRulePartialMixed just below is no "
|
||||
"longer valid");
|
||||
|
||||
if (detail == eRuleNone && isReset) {
|
||||
// We specified absolutely no rule information for a reset struct, and we
|
||||
// may or may not have found a parent rule in the tree that specified all
|
||||
// the rule information. Regardless, we don't need to use any cache
|
||||
// conditions if we cache this struct in the rule tree.
|
||||
//
|
||||
// Normally ruleData.mConditions would already indicate that the struct
|
||||
// is cacheable without conditions if detail is eRuleNone, but because
|
||||
// of the UnsetPropertiesWithoutFlags call above, we may have encountered
|
||||
// some rules with dependencies, which we then cleared out of ruleData.
|
||||
//
|
||||
// ruleData.mConditions could also indicate we are not cacheable at all,
|
||||
// such as when AnimValuesStyleRule prevents us from caching structs
|
||||
// when attempting to apply animations to pseudos.
|
||||
//
|
||||
// So if we we are uncacheable, we leave it, but if we are cacheable
|
||||
// with dependencies, we convert that to cacheable without dependencies.
|
||||
if (ruleData.mConditions.CacheableWithDependencies()) {
|
||||
MOZ_ASSERT(pseudoRestriction,
|
||||
"should only be cacheable with dependencies if we had a "
|
||||
"pseudo restriction");
|
||||
ruleData.mConditions.Clear();
|
||||
} else {
|
||||
// XXXheycam We shouldn't have `|| GetLevel() == SheetType::Transition`
|
||||
// in the assertion condition, but rule nodes created by
|
||||
// ResolveStyleByAddingRules don't call SetIsAnimationRule().
|
||||
MOZ_ASSERT(ruleData.mConditions.CacheableWithoutDependencies() ||
|
||||
((HasAnimationData() ||
|
||||
GetLevel() == SheetType::Transition) &&
|
||||
aContext->GetParent() &&
|
||||
aContext->GetParent()->HasPseudoElementData()),
|
||||
"should only be uncacheable if we had an animation rule "
|
||||
"and we're inside a pseudo");
|
||||
}
|
||||
}
|
||||
|
||||
if (!ruleData.mConditions.CacheableWithoutDependencies() &&
|
||||
aSID != eStyleStruct_Variables) {
|
||||
// Treat as though some data is specified to avoid the optimizations and
|
||||
|
|
|
@ -193,6 +193,7 @@ public:
|
|||
MOZ_ASSERT(!(mConditionalBits & GetBitForSID(aSID)),
|
||||
"rule node should not have unconditional and conditional style "
|
||||
"data for a given struct");
|
||||
mConditionalBits &= ~GetBitForSID(aSID);
|
||||
mEntries[aSID] = aStyleStruct;
|
||||
}
|
||||
|
||||
|
@ -200,13 +201,17 @@ public:
|
|||
nsPresContext* aPresContext,
|
||||
void* aStyleStruct,
|
||||
const mozilla::RuleNodeCacheConditions& aConditions) {
|
||||
MOZ_ASSERT((mConditionalBits & GetBitForSID(aSID)) ||
|
||||
!mEntries[aSID],
|
||||
"rule node should not have unconditional and conditional style "
|
||||
"data for a given struct");
|
||||
if (!(mConditionalBits & GetBitForSID(aSID))) {
|
||||
MOZ_ASSERT(!mEntries[aSID],
|
||||
"rule node should not have unconditional and conditional "
|
||||
"style data for a given struct");
|
||||
mEntries[aSID] = nullptr;
|
||||
}
|
||||
|
||||
MOZ_ASSERT(aConditions.CacheableWithDependencies(),
|
||||
"don't call SetStyleData with a cache key that has no "
|
||||
"conditions or is uncacheable");
|
||||
|
||||
#ifdef DEBUG
|
||||
for (Entry* e = static_cast<Entry*>(mEntries[aSID]); e; e = e->mNext) {
|
||||
NS_WARNING_ASSERTION(e->mConditions != aConditions,
|
||||
|
|
|
@ -3351,7 +3351,7 @@ function nsBrowserAccess() {
|
|||
nsBrowserAccess.prototype = {
|
||||
QueryInterface: XPCOMUtils.generateQI([Ci.nsIBrowserDOMWindow]),
|
||||
|
||||
_getBrowser: function _getBrowser(aURI, aOpener, aWhere, aFlags) {
|
||||
_getBrowser: function _getBrowser(aURI, aOpener, aWhere, aFlags, aTriggeringPrincipal) {
|
||||
let isExternal = !!(aFlags & Ci.nsIBrowserDOMWindow.OPEN_EXTERNAL);
|
||||
if (isExternal && aURI && aURI.schemeIs("chrome"))
|
||||
return null;
|
||||
|
@ -3427,7 +3427,8 @@ nsBrowserAccess.prototype = {
|
|||
opener: openerWindow,
|
||||
selected: true,
|
||||
isPrivate: isPrivate,
|
||||
pinned: pinned });
|
||||
pinned: pinned,
|
||||
triggeringPrincipal: aTriggeringPrincipal});
|
||||
|
||||
return tab.browser;
|
||||
}
|
||||
|
@ -3435,14 +3436,18 @@ nsBrowserAccess.prototype = {
|
|||
// OPEN_CURRENTWINDOW and illegal values
|
||||
let browser = BrowserApp.selectedBrowser;
|
||||
if (aURI && browser) {
|
||||
browser.loadURIWithFlags(aURI.spec, loadflags, referrer, null, null);
|
||||
browser.loadURIWithFlags(aURI.spec, {
|
||||
flags: loadflags,
|
||||
referrerURI: referrer,
|
||||
triggeringPrincipal: aTriggeringPrincipal,
|
||||
});
|
||||
}
|
||||
|
||||
return browser;
|
||||
},
|
||||
|
||||
openURI: function browser_openURI(aURI, aOpener, aWhere, aFlags) {
|
||||
let browser = this._getBrowser(aURI, aOpener, aWhere, aFlags);
|
||||
openURI: function browser_openURI(aURI, aOpener, aWhere, aFlags, aTriggeringPrincipal) {
|
||||
let browser = this._getBrowser(aURI, aOpener, aWhere, aFlags, aTriggeringPrincipal);
|
||||
return browser ? browser.contentWindow : null;
|
||||
},
|
||||
|
||||
|
@ -3454,7 +3459,7 @@ nsBrowserAccess.prototype = {
|
|||
//
|
||||
// We also ignore aName if it is set, as it is currently only used on the
|
||||
// e10s codepath.
|
||||
let browser = this._getBrowser(aURI, null, aWhere, aFlags);
|
||||
let browser = this._getBrowser(aURI, null, aWhere, aFlags, null);
|
||||
if (browser)
|
||||
return browser.QueryInterface(Ci.nsIFrameLoaderOwner);
|
||||
return null;
|
||||
|
|
|
@ -3158,9 +3158,6 @@ pref("dom.ipc.plugins.reportCrashURL", true);
|
|||
// Defaults to 30 seconds.
|
||||
pref("dom.ipc.plugins.unloadTimeoutSecs", 30);
|
||||
|
||||
// Asynchronous plugin initialization is on hold.
|
||||
pref("dom.ipc.plugins.asyncInit.enabled", false);
|
||||
|
||||
// Allow Flash async drawing mode in 64-bit release builds
|
||||
pref("dom.ipc.plugins.asyncdrawing.enabled", true);
|
||||
// Force the accelerated direct path for a subset of Flash wmode values
|
||||
|
|
|
@ -779,38 +779,6 @@ continue_loading:
|
|||
return stub_LdrLoadDll(filePath, flags, moduleFileName, handle);
|
||||
}
|
||||
|
||||
#ifdef _M_AMD64
|
||||
typedef NTSTATUS (NTAPI *LdrUnloadDll_func)(HMODULE module);
|
||||
static LdrUnloadDll_func stub_LdrUnloadDll;
|
||||
|
||||
static NTSTATUS NTAPI
|
||||
patched_LdrUnloadDll(HMODULE module)
|
||||
{
|
||||
// Prevent the stack walker from suspending this thread when LdrUnloadDll
|
||||
// holds the RtlLookupFunctionEntry lock.
|
||||
AutoSuppressStackWalking suppress;
|
||||
return stub_LdrUnloadDll(module);
|
||||
}
|
||||
|
||||
// These pointers are disguised as PVOID to avoid pulling in obscure headers
|
||||
typedef PVOID (WINAPI *LdrResolveDelayLoadedAPI_func)(PVOID ParentModuleBase,
|
||||
PVOID DelayloadDescriptor, PVOID FailureDllHook, PVOID FailureSystemHook,
|
||||
PVOID ThunkAddress, ULONG Flags);
|
||||
static LdrResolveDelayLoadedAPI_func stub_LdrResolveDelayLoadedAPI;
|
||||
|
||||
static PVOID WINAPI patched_LdrResolveDelayLoadedAPI(PVOID ParentModuleBase,
|
||||
PVOID DelayloadDescriptor, PVOID FailureDllHook, PVOID FailureSystemHook,
|
||||
PVOID ThunkAddress, ULONG Flags)
|
||||
{
|
||||
// Prevent the stack walker from suspending this thread when
|
||||
// LdrResolveDelayLoadAPI holds the RtlLookupFunctionEntry lock.
|
||||
AutoSuppressStackWalking suppress;
|
||||
return stub_LdrResolveDelayLoadedAPI(ParentModuleBase, DelayloadDescriptor,
|
||||
FailureDllHook, FailureSystemHook,
|
||||
ThunkAddress, Flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef _M_IX86
|
||||
static bool
|
||||
ShouldBlockThread(void* aStartAddress)
|
||||
|
@ -890,14 +858,6 @@ DllBlocklist_Initialize(uint32_t aInitFlags)
|
|||
Kernel32Intercept.Init("kernel32.dll");
|
||||
|
||||
#ifdef _M_AMD64
|
||||
NtDllIntercept.AddHook("LdrUnloadDll",
|
||||
reinterpret_cast<intptr_t>(patched_LdrUnloadDll),
|
||||
(void**)&stub_LdrUnloadDll);
|
||||
if (IsWin8OrLater()) { // LdrResolveDelayLoadedAPI was introduced in Win8
|
||||
NtDllIntercept.AddHook("LdrResolveDelayLoadedAPI",
|
||||
reinterpret_cast<intptr_t>(patched_LdrResolveDelayLoadedAPI),
|
||||
(void**)&stub_LdrResolveDelayLoadedAPI);
|
||||
}
|
||||
if (!IsWin8OrLater()) {
|
||||
// The crash that this hook works around is only seen on Win7.
|
||||
Kernel32Intercept.AddHook("RtlInstallFunctionTableCallback",
|
||||
|
|
|
@ -1598,15 +1598,17 @@ HttpChannelChild::SetupRedirect(nsIURI* uri,
|
|||
|
||||
void
|
||||
HttpChannelChild::Redirect1Begin(const uint32_t& registrarId,
|
||||
const URIParams& newUri,
|
||||
const URIParams& newOriginalURI,
|
||||
const uint32_t& redirectFlags,
|
||||
const nsHttpResponseHead& responseHead,
|
||||
const nsACString& securityInfoSerialization,
|
||||
const uint64_t& channelId)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
LOG(("HttpChannelChild::Redirect1Begin [this=%p]\n", this));
|
||||
|
||||
nsCOMPtr<nsIURI> uri = DeserializeURI(newUri);
|
||||
nsCOMPtr<nsIURI> uri = DeserializeURI(newOriginalURI);
|
||||
|
||||
if (!securityInfoSerialization.IsEmpty()) {
|
||||
NS_DeserializeObject(securityInfoSerialization,
|
||||
|
@ -1614,10 +1616,10 @@ HttpChannelChild::Redirect1Begin(const uint32_t& registrarId,
|
|||
}
|
||||
|
||||
nsCOMPtr<nsIChannel> newChannel;
|
||||
nsresult rv = SetupRedirect(uri,
|
||||
&responseHead,
|
||||
redirectFlags,
|
||||
getter_AddRefs(newChannel));
|
||||
rv = SetupRedirect(uri,
|
||||
&responseHead,
|
||||
redirectFlags,
|
||||
getter_AddRefs(newChannel));
|
||||
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
if (mRedirectChannelChild) {
|
||||
|
|
|
@ -1754,6 +1754,8 @@ HttpChannelParent::StartRedirect(uint32_t registrarId,
|
|||
uint32_t redirectFlags,
|
||||
nsIAsyncVerifyRedirectCallback* callback)
|
||||
{
|
||||
nsresult rv;
|
||||
|
||||
LOG(("HttpChannelParent::StartRedirect [this=%p, registrarId=%" PRIu32 " "
|
||||
"newChannel=%p callback=%p]\n", this, registrarId, newChannel,
|
||||
callback));
|
||||
|
@ -1761,11 +1763,16 @@ HttpChannelParent::StartRedirect(uint32_t registrarId,
|
|||
if (mIPCClosed)
|
||||
return NS_BINDING_ABORTED;
|
||||
|
||||
nsCOMPtr<nsIURI> newURI;
|
||||
newChannel->GetURI(getter_AddRefs(newURI));
|
||||
// Sending down the original URI, because that is the URI we have
|
||||
// to construct the channel from - this is the URI we've been actually
|
||||
// redirected to. URI of the channel may be an inner channel URI.
|
||||
// URI of the channel will be reconstructed by the protocol handler
|
||||
// on the child process, no need to send it then.
|
||||
nsCOMPtr<nsIURI> newOriginalURI;
|
||||
newChannel->GetOriginalURI(getter_AddRefs(newOriginalURI));
|
||||
|
||||
URIParams uriParams;
|
||||
SerializeURI(newURI, uriParams);
|
||||
SerializeURI(newOriginalURI, uriParams);
|
||||
|
||||
nsCString secInfoSerialization;
|
||||
UpdateAndSerializeSecurityInfo(secInfoSerialization);
|
||||
|
@ -1776,7 +1783,7 @@ HttpChannelParent::StartRedirect(uint32_t registrarId,
|
|||
uint64_t channelId;
|
||||
nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(newChannel);
|
||||
if (httpChannel) {
|
||||
nsresult rv = httpChannel->GetChannelId(&channelId);
|
||||
rv = httpChannel->GetChannelId(&channelId);
|
||||
NS_ENSURE_SUCCESS(rv, NS_BINDING_ABORTED);
|
||||
}
|
||||
|
||||
|
|
|
@ -117,7 +117,7 @@ child:
|
|||
// Called to initiate content channel redirect, starts talking to sinks
|
||||
// on the content process and reports result via Redirect2Verify above
|
||||
async Redirect1Begin(uint32_t registrarId,
|
||||
URIParams newUri,
|
||||
URIParams newOriginalUri,
|
||||
uint32_t redirectFlags,
|
||||
nsHttpResponseHead responseHead,
|
||||
nsCString securityInfoSerialization,
|
||||
|
|
|
@ -83,7 +83,11 @@ DWORD CreateRestrictedToken(TokenLevel security_level,
|
|||
sid_exceptions.push_back(WinWorldSid);
|
||||
sid_exceptions.push_back(WinInteractiveSid);
|
||||
privilege_exceptions.push_back(SE_CHANGE_NOTIFY_NAME);
|
||||
restricted_token.AddUserSidForDenyOnly();
|
||||
// This breaks web audio, so we don't want to do this in the restricting
|
||||
// SIDs (normal) case. See bug 1378061.
|
||||
if (!gUseRestricting) {
|
||||
restricted_token.AddUserSidForDenyOnly();
|
||||
}
|
||||
restricted_token.AddRestrictingSid(WinBuiltinUsersSid);
|
||||
restricted_token.AddRestrictingSid(WinWorldSid);
|
||||
restricted_token.AddRestrictingSid(WinRestrictedCodeSid);
|
||||
|
|
|
@ -70,7 +70,7 @@ config = {
|
|||
},
|
||||
"check_test_env": {
|
||||
'MINIDUMP_STACKWALK': '%(abs_tools_dir)s\\breakpad\\win32\\minidump_stackwalk.exe',
|
||||
'MINIDUMP_SAVE_PATH': '%(base_work_dir)s\\minidumps',
|
||||
'MINIDUMP_SAVE_PATH': os.path.join(os.getcwd(), 'public', 'build'),
|
||||
},
|
||||
'src_mozconfig': 'browser\\config\\mozconfigs\\win32\\clang',
|
||||
'artifact_flag_build_variant_in_try': None,
|
||||
|
|
|
@ -72,7 +72,7 @@ config = {
|
|||
},
|
||||
"check_test_env": {
|
||||
'MINIDUMP_STACKWALK': '%(abs_tools_dir)s\\breakpad\\win32\\minidump_stackwalk.exe',
|
||||
'MINIDUMP_SAVE_PATH': '%(base_work_dir)s\\minidumps',
|
||||
'MINIDUMP_SAVE_PATH': os.path.join(os.getcwd(), 'public', 'build'),
|
||||
},
|
||||
'src_mozconfig': 'browser\\config\\mozconfigs\\win32\\clang-debug',
|
||||
'artifact_flag_build_variant_in_try': None,
|
||||
|
|
|
@ -74,7 +74,7 @@ config = {
|
|||
},
|
||||
"check_test_env": {
|
||||
'MINIDUMP_STACKWALK': '%(abs_tools_dir)s\\breakpad\\win32\\minidump_stackwalk.exe',
|
||||
'MINIDUMP_SAVE_PATH': '%(base_work_dir)s\\minidumps',
|
||||
'MINIDUMP_SAVE_PATH': os.path.join(os.getcwd(), 'public', 'build'),
|
||||
},
|
||||
'src_mozconfig': 'browser\\config\\mozconfigs\\win32\\noopt-debug',
|
||||
'artifact_flag_build_variant_in_try': None,
|
||||
|
|
|
@ -68,7 +68,7 @@ config = {
|
|||
},
|
||||
"check_test_env": {
|
||||
'MINIDUMP_STACKWALK': '%(abs_tools_dir)s\\breakpad\\win64\\minidump_stackwalk.exe',
|
||||
'MINIDUMP_SAVE_PATH': '%(base_work_dir)s\\minidumps',
|
||||
'MINIDUMP_SAVE_PATH': os.path.join(os.getcwd(), 'public', 'build'),
|
||||
},
|
||||
'src_mozconfig': 'browser\\config\\mozconfigs\\win64\\debug-asan',
|
||||
#########################################################################
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче