зеркало из https://github.com/mozilla/gecko-dev.git
Merge inbound to m-c. a=merge
This commit is contained in:
Коммит
fd0387315e
|
@ -34,3 +34,4 @@ phishingBlocked=The website at %S has been reported as a web forgery designed to
|
|||
cspBlocked=This page has a content security policy that prevents it from being loaded in this way.
|
||||
corruptedContentError=The page you are trying to view cannot be shown because an error in the data transmission was detected.
|
||||
remoteXUL=This page uses an unsupported technology that is no longer available by default in Firefox.
|
||||
sslv3Used=Firefox cannot guarantee the safety of your data on %S because it uses SSLv3, a broken security protocol.
|
||||
|
|
|
@ -1168,6 +1168,12 @@ pref("toolbar.customization.usesheet", false);
|
|||
// Disable Flash protected mode to reduce hang/crash rates.
|
||||
pref("dom.ipc.plugins.flash.disable-protected-mode", true);
|
||||
|
||||
// Feature-disable the protected-mode auto-flip
|
||||
pref("browser.flash-protected-mode-flip.enable", true);
|
||||
|
||||
// Whether we've already flipped protected mode automatically
|
||||
pref("browser.flash-protected-mode-flip.done", false);
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
// On mac, the default pref is per-architecture
|
||||
pref("dom.ipc.plugins.enabled.i386", true);
|
||||
|
@ -1214,6 +1220,18 @@ pref("security.sandbox.windows.log.stackTraceDepth", 0);
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(XP_MACOSX) && defined(MOZ_SANDBOX) && defined(MOZ_CONTENT_SANDBOX)
|
||||
// This pref is discussed in bug 1083344, the naming is inspired from its Windows
|
||||
// counterpart, but on Mac it's an integer which means:
|
||||
// 0 -> "no sandbox"
|
||||
// 1 -> "an imperfect sandbox designed to allow firefox to run reasonably well"
|
||||
// 2 -> "an ideal sandbox which may break many things"
|
||||
// This setting is read when the content process is started. On Mac the content
|
||||
// process is killed when all windows are closed, so a change will take effect
|
||||
// when the 1st window is opened. It was decided to default this setting to 1.
|
||||
pref("security.sandbox.macos.content.level", 1);
|
||||
#endif
|
||||
|
||||
// This pref governs whether we attempt to work around problems caused by
|
||||
// plugins using OS calls to manipulate the cursor while running out-of-
|
||||
// process. These workarounds all involve intercepting (hooking) certain
|
||||
|
|
|
@ -156,24 +156,10 @@
|
|||
errDesc.id = "errorLongDesc";
|
||||
}
|
||||
|
||||
if (err == "nssFailure2" &&
|
||||
sd.textContent.contains("ssl_error_unsupported_version")) {
|
||||
var ssl3ErrorTitle = document.getElementById("et_ssl3");
|
||||
var ssl3ErrorDesc = document.getElementById("ed_ssl3");
|
||||
var ssl3ShortDesc = document.getElementById("esd_ssl3");
|
||||
if (err == "sslv3Used") {
|
||||
var learnMoreText = document.getElementById("learn_more_ssl3");
|
||||
|
||||
errTitle.parentNode.replaceChild(ssl3ErrorTitle, errTitle);
|
||||
ssl3ErrorTitle.id = "errorTitleText";
|
||||
ssl3ErrorTitle.setAttribute("sslv3", "true");
|
||||
errTitle = ssl3ErrorTitle;
|
||||
|
||||
sd.innerHTML = ssl3ShortDesc.innerHTML;
|
||||
sd.querySelector('span').textContent = location.hostname;
|
||||
|
||||
errDesc.parentNode.replaceChild(ssl3ErrorDesc, errDesc);
|
||||
ssl3ErrorDesc.id = "errorLongDesc";
|
||||
ssl3ErrorDesc.querySelector('span').textContent = "ssl_error_unsupported_version";
|
||||
errTitle.setAttribute("sslv3", "true");
|
||||
|
||||
var retryBtn = document.getElementById("errorTryAgain");
|
||||
retryBtn.textContent = learnMoreText.textContent;
|
||||
|
@ -218,7 +204,7 @@
|
|||
|
||||
window.addEventListener("AboutNetErrorOptions", function(evt) {
|
||||
// Pinning errors are of type nssFailure2
|
||||
if (getErrorCode() == "nssFailure2" && !errTitle.hasAttribute("sslv3")) {
|
||||
if (getErrorCode() == "nssFailure2") {
|
||||
var learnMoreLink = document.getElementById("learnMoreLink");
|
||||
// nssFailure2 also gets us other non-overrideable errors. Choose
|
||||
// a "learn more" link based on description:
|
||||
|
@ -391,7 +377,7 @@
|
|||
<h1 id="et_cspBlocked">&cspBlocked.title;</h1>
|
||||
<h1 id="et_remoteXUL">&remoteXUL.title;</h1>
|
||||
<h1 id="et_corruptedContentError">&corruptedContentError.title;</h1>
|
||||
<h1 id="et_ssl3">&oldSecurityProtocol.title;</h1>
|
||||
<h1 id="et_sslv3Used">&sslv3Used.title;</h1>
|
||||
</div>
|
||||
<div id="errorDescriptionsContainer">
|
||||
<div id="ed_generic">&generic.longDesc;</div>
|
||||
|
@ -418,9 +404,8 @@
|
|||
<div id="ed_cspBlocked">&cspBlocked.longDesc;</div>
|
||||
<div id="ed_remoteXUL">&remoteXUL.longDesc;</div>
|
||||
<div id="ed_corruptedContentError">&corruptedContentError.longDesc;</div>
|
||||
<div id="esd_ssl3">&oldSecurityProtocol.longDesc2;</div>
|
||||
<div id="ed_ssl3">&oldSecurityProtocol.advancedInfo;</div>
|
||||
<div id="learn_more_ssl3">&oldSecurityProtocol.learnMore;</div>
|
||||
<div id="ed_sslv3Used">&sslv3Used.longDesc;</div>
|
||||
<div id="learn_more_ssl3">&sslv3Used.learnMore;</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -476,7 +476,11 @@ BrowserGlue.prototype = {
|
|||
Services.prefs.clearUserPref("privacy.trackingprotection.ui.enabled");
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case "flash-plugin-hang":
|
||||
this._handleFlashHang();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -524,6 +528,9 @@ BrowserGlue.prototype = {
|
|||
os.addObserver(this, "browser-search-engine-modified", false);
|
||||
os.addObserver(this, "browser-search-service", false);
|
||||
os.addObserver(this, "restart-in-safe-mode", false);
|
||||
os.addObserver(this, "flash-plugin-hang", false);
|
||||
|
||||
this._flashHangCount = 0;
|
||||
},
|
||||
|
||||
// cleanup (called on application shutdown)
|
||||
|
@ -568,6 +575,7 @@ BrowserGlue.prototype = {
|
|||
#ifdef NIGHTLY_BUILD
|
||||
Services.prefs.removeObserver(POLARIS_ENABLED, this);
|
||||
#endif
|
||||
os.removeObserver(this, "flash-plugin-hang");
|
||||
},
|
||||
|
||||
_onAppDefaults: function BG__onAppDefaults() {
|
||||
|
@ -2086,6 +2094,49 @@ BrowserGlue.prototype = {
|
|||
},
|
||||
#endif
|
||||
|
||||
_handleFlashHang: function() {
|
||||
++this._flashHangCount;
|
||||
if (this._flashHangCount < 2) {
|
||||
return;
|
||||
}
|
||||
// protected mode only applies to win32
|
||||
if (Services.appinfo.XPCOMABI != "x86-msvc") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Services.prefs.getBoolPref("dom.ipc.plugins.flash.disable-protected-mode")) {
|
||||
return;
|
||||
}
|
||||
if (!Services.prefs.getBoolPref("browser.flash-protected-mode-flip.enable")) {
|
||||
return;
|
||||
}
|
||||
if (Services.prefs.getBoolPref("browser.flash-protected-mode-flip.done")) {
|
||||
return;
|
||||
}
|
||||
Services.prefs.setBoolPref("dom.ipc.plugins.flash.disable-protected-mode", true);
|
||||
Services.prefs.setBoolPref("browser.flash-protected-mode-flip.done", true);
|
||||
|
||||
let win = this.getMostRecentBrowserWindow();
|
||||
if (!win) {
|
||||
return;
|
||||
}
|
||||
let productName = Services.strings
|
||||
.createBundle("chrome://branding/locale/brand.properties")
|
||||
.GetStringFromName("brandShortName");
|
||||
let message = win.gNavigatorBundle.
|
||||
getFormattedString("flashHang.message", [productName]);
|
||||
let buttons = [{
|
||||
label: win.gNavigatorBundle.getString("flashHang.helpButton.label"),
|
||||
accessKey: win.gNavigatorBundle.getString("flashHang.helpButton.accesskey"),
|
||||
callback: function() {
|
||||
win.openUILinkIn("https://support.mozilla.org/kb/flash-protected-mode-autodisabled", "tab");
|
||||
}
|
||||
}];
|
||||
let nb = win.document.getElementById("global-notificationbox");
|
||||
nb.appendNotification(message, "flash-hang", null,
|
||||
nb.PRIORITY_INFO_MEDIUM, buttons);
|
||||
},
|
||||
|
||||
// for XPCOM
|
||||
classID: Components.ID("{eab9012e-5f74-4cbc-b2b5-a590235513cc}"),
|
||||
|
||||
|
|
|
@ -626,6 +626,10 @@ slowStartup.helpButton.accesskey = L
|
|||
slowStartup.disableNotificationButton.label = Don't Tell Me Again
|
||||
slowStartup.disableNotificationButton.accesskey = A
|
||||
|
||||
# LOCALIZATION NOTE - %S is brandShortName
|
||||
flashHang.message = %S changed some Adobe Flash settings improve performance.
|
||||
flashHang.helpButton.label = Learn More…
|
||||
flashHang.helpButton.accesskey = L
|
||||
|
||||
# LOCALIZATION NOTE(customizeTips.tip0): %1$S will be replaced with the text defined
|
||||
# in customizeTips.tip0.hint, %2$S will be replaced with brandShortName, %3$S will
|
||||
|
|
|
@ -34,3 +34,5 @@ phishingBlocked=The website at %S has been reported as a web forgery designed to
|
|||
cspBlocked=This page has a content security policy that prevents it from being loaded in this way.
|
||||
corruptedContentError=The page you are trying to view cannot be shown because an error in the data transmission was detected.
|
||||
remoteXUL=This page uses an unsupported technology that is no longer available by default in Firefox.
|
||||
## LOCALIZATION NOTE (sslv3Used) - Do not translate "%S".
|
||||
sslv3Used=Firefox cannot guarantee the safety of your data on %S because it uses SSLv3, a broken security protocol.
|
||||
|
|
|
@ -205,11 +205,8 @@ functionality specific to firefox. -->
|
|||
<!ENTITY remoteXUL.title "Remote XUL">
|
||||
<!ENTITY remoteXUL.longDesc "<p><ul><li>Please contact the website owners to inform them of this problem.</li></ul></p>">
|
||||
|
||||
<!ENTITY oldSecurityProtocol.title "Unable to Connect Securely">
|
||||
<!-- LOCALIZATION NOTE (oldSecurityProtocol.longDesc) - Do not translate the
|
||||
<span id='hostname'></span>. -->
|
||||
<!ENTITY oldSecurityProtocol.longDesc2 "&brandShortName; cannot guarantee the safety of your data on <span id='hostname'></span> because it uses SSLv3, a broken security protocol.">
|
||||
<!-- LOCALIZATION NOTE (oldSecurityProtocol.advancedInfo) - Do not translate
|
||||
the <span id='errorcode'></span>. -->
|
||||
<!ENTITY oldSecurityProtocol.advancedInfo "Advanced info: <span id='errorcode'></span>">
|
||||
<!ENTITY oldSecurityProtocol.learnMore "Learn More…">
|
||||
<!ENTITY sslv3Used.title "Unable to Connect Securely">
|
||||
<!-- LOCALIZATION NOTE (sslv3Used.longDesc) - Do not translate
|
||||
"ssl_error_unsupported_version". -->
|
||||
<!ENTITY sslv3Used.longDesc "Advanced info: ssl_error_unsupported_version">
|
||||
<!ENTITY sslv3Used.learnMore "Learn More…">
|
||||
|
|
|
@ -2307,7 +2307,7 @@ ia64*-hpux*)
|
|||
if test "$_CC_MAJOR_VERSION" = "18" -a "$_CC_BUILD_VERSION" = "31101"; then
|
||||
dnl Use MaxILKSize as a workaround for LNK1248 in VS2013update4
|
||||
dnl See https://connect.microsoft.com/VisualStudio/feedback/details/1044914/fatal-error-lnk1248
|
||||
LDFLAGS="$LDFLAGS -MaxILKSize:2147483647"
|
||||
LDFLAGS="$LDFLAGS -MaxILKSize:0x7FF00000"
|
||||
fi
|
||||
dnl Minimum reqiurement of Gecko is VS2010 or later which supports
|
||||
dnl both SSSE3 and SSE4.1.
|
||||
|
|
|
@ -11,7 +11,7 @@ namespace mozilla {
|
|||
|
||||
NS_IMPL_ISUPPORTS(LoadContext, nsILoadContext, nsIInterfaceRequestor)
|
||||
|
||||
LoadContext::LoadContext(nsIPrincipal* aPrincipal)
|
||||
LoadContext::LoadContext(nsIPrincipal* aPrincipal, nsILoadContext* aOptionalBase)
|
||||
: mTopFrameElement(nullptr)
|
||||
, mNestedFrameId(0)
|
||||
, mIsContent(true)
|
||||
|
@ -24,6 +24,15 @@ LoadContext::LoadContext(nsIPrincipal* aPrincipal)
|
|||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(aPrincipal->GetAppId(&mAppId)));
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
|
||||
aPrincipal->GetIsInBrowserElement(&mIsInBrowserElement)));
|
||||
|
||||
if (!aOptionalBase) {
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(aOptionalBase->GetIsContent(&mIsContent)));
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
|
||||
aOptionalBase->GetUsePrivateBrowsing(&mUsePrivateBrowsing)));
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(aOptionalBase->GetUseRemoteTabs(&mUseRemoteTabs)));
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
@ -108,7 +108,8 @@ public:
|
|||
|
||||
// Constructor for creating a LoadContext with a given principal's appId and
|
||||
// browser flag.
|
||||
explicit LoadContext(nsIPrincipal* aPrincipal);
|
||||
explicit LoadContext(nsIPrincipal* aPrincipal,
|
||||
nsILoadContext* aOptionalBase = nullptr);
|
||||
|
||||
private:
|
||||
~LoadContext() {}
|
||||
|
|
|
@ -4975,8 +4975,15 @@ nsDocShell::DisplayLoadError(nsresult aError, nsIURI* aURI,
|
|||
}
|
||||
tsi = do_QueryInterface(securityInfo);
|
||||
if (tsi) {
|
||||
// Usually we should have aFailedChannel and get a detailed message
|
||||
tsi->GetErrorMessage(getter_Copies(messageStr));
|
||||
uint32_t securityState;
|
||||
tsi->GetSecurityState(&securityState);
|
||||
if (securityState & nsIWebProgressListener::STATE_USES_SSL_3) {
|
||||
error.AssignLiteral("sslv3Used");
|
||||
addHostPort = true;
|
||||
} else {
|
||||
// Usually we should have aFailedChannel and get a detailed message
|
||||
tsi->GetErrorMessage(getter_Copies(messageStr));
|
||||
}
|
||||
} else {
|
||||
// No channel, let's obtain the generic error message
|
||||
if (nsserr) {
|
||||
|
|
|
@ -49,6 +49,7 @@ public:
|
|||
, mIsDetached(false)
|
||||
, mMaySpanAnonymousSubtrees(false)
|
||||
, mInSelection(false)
|
||||
, mIsGenerated(false)
|
||||
, mStartOffsetWasIncremented(false)
|
||||
, mEndOffsetWasIncremented(false)
|
||||
, mEnableGravitationOnElementRemoval(true)
|
||||
|
@ -153,6 +154,27 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if this range was generated.
|
||||
* @see SetIsGenerated
|
||||
*/
|
||||
bool IsGenerated() const
|
||||
{
|
||||
return mIsGenerated;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark this range as being generated or not.
|
||||
* Currently it is used for marking ranges that are created when splitting up
|
||||
* a range to exclude a -moz-user-select:none region.
|
||||
* @see Selection::AddItem
|
||||
* @see ExcludeNonSelectableNodes
|
||||
*/
|
||||
void SetIsGenerated(bool aIsGenerated)
|
||||
{
|
||||
mIsGenerated = aIsGenerated;
|
||||
}
|
||||
|
||||
nsINode* GetCommonAncestor() const;
|
||||
void Reset();
|
||||
nsresult SetStart(nsINode* aParent, int32_t aOffset);
|
||||
|
@ -333,6 +355,7 @@ protected:
|
|||
bool mIsDetached;
|
||||
bool mMaySpanAnonymousSubtrees;
|
||||
bool mInSelection;
|
||||
bool mIsGenerated;
|
||||
bool mStartOffsetWasIncremented;
|
||||
bool mEndOffsetWasIncremented;
|
||||
bool mEnableGravitationOnElementRemoval;
|
||||
|
|
|
@ -2622,6 +2622,9 @@ ConvertExceptionToPromise(JSContext* cx,
|
|||
|
||||
JS::Rooted<JS::Value> exn(cx);
|
||||
if (!JS_GetPendingException(cx, &exn)) {
|
||||
// This is very important: if there is no pending exception here but we're
|
||||
// ending up in this code, that means the callee threw an uncatchable
|
||||
// exception. Just propagate that out as-is.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -103,6 +103,13 @@ ThrowMethodFailedWithDetails(JSContext* cx, ErrorResult& rv,
|
|||
const char* memberName,
|
||||
bool reportJSContentExceptions = false)
|
||||
{
|
||||
if (rv.IsUncatchableException()) {
|
||||
// Nuke any existing exception on aCx, to make sure we're uncatchable.
|
||||
JS_ClearPendingException(cx);
|
||||
// Don't do any reporting. Just return false, to create an
|
||||
// uncatchable exception.
|
||||
return false;
|
||||
}
|
||||
if (rv.IsErrorWithMessage()) {
|
||||
rv.ReportErrorWithMessage(cx);
|
||||
return false;
|
||||
|
|
|
@ -97,6 +97,14 @@ public:
|
|||
const char* memberName);
|
||||
bool IsNotEnoughArgsError() const { return ErrorCode() == NS_ERROR_XPC_NOT_ENOUGH_ARGS; }
|
||||
|
||||
// Support for uncatchable exceptions.
|
||||
void ThrowUncatchableException() {
|
||||
Throw(NS_ERROR_UNCATCHABLE_EXCEPTION);
|
||||
}
|
||||
bool IsUncatchableException() const {
|
||||
return ErrorCode() == NS_ERROR_UNCATCHABLE_EXCEPTION;
|
||||
}
|
||||
|
||||
// StealJSException steals the JS Exception from the object. This method must
|
||||
// be called only if IsJSException() returns true. This method also resets the
|
||||
// ErrorCode() to NS_OK. The value will be ensured to be sanitized wrt to the
|
||||
|
|
|
@ -88,6 +88,12 @@ ThrowExceptionObject(JSContext* aCx, Exception* aException)
|
|||
bool
|
||||
Throw(JSContext* aCx, nsresult aRv, const char* aMessage)
|
||||
{
|
||||
if (aRv == NS_ERROR_UNCATCHABLE_EXCEPTION) {
|
||||
// Nuke any existing exception on aCx, to make sure we're uncatchable.
|
||||
JS_ClearPendingException(aCx);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (JS_IsExceptionPending(aCx)) {
|
||||
// Don't clobber the existing exception.
|
||||
return false;
|
||||
|
@ -128,6 +134,8 @@ Throw(JSContext* aCx, nsresult aRv, const char* aMessage)
|
|||
void
|
||||
ThrowAndReport(nsPIDOMWindow* aWindow, nsresult aRv, const char* aMessage)
|
||||
{
|
||||
MOZ_ASSERT(aRv != NS_ERROR_UNCATCHABLE_EXCEPTION,
|
||||
"Doesn't make sense to report uncatchable exceptions!");
|
||||
AutoJSAPI jsapi;
|
||||
if (NS_WARN_IF(!jsapi.InitWithLegacyErrorReporting(aWindow))) {
|
||||
return;
|
||||
|
|
|
@ -66,6 +66,8 @@ ToJSValue(JSContext* aCx,
|
|||
JS::MutableHandle<JS::Value> aValue)
|
||||
{
|
||||
MOZ_ASSERT(aArgument.Failed());
|
||||
MOZ_ASSERT(!aArgument.IsUncatchableException(),
|
||||
"Doesn't make sense to convert uncatchable exception to a JS value!");
|
||||
AutoForceSetExceptionOnContext forceExn(aCx);
|
||||
DebugOnly<bool> throwResult = ThrowMethodFailedWithDetails(aCx, aArgument, "", "");
|
||||
MOZ_ASSERT(!throwResult);
|
||||
|
|
|
@ -93,6 +93,8 @@
|
|||
#include "nsISpellChecker.h"
|
||||
#include "nsClipboardProxy.h"
|
||||
#include "nsISystemMessageCache.h"
|
||||
#include "nsDirectoryServiceUtils.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
|
||||
#include "IHistory.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
@ -1081,8 +1083,11 @@ ContentChild::CleanUpSandboxEnvironment()
|
|||
#endif
|
||||
|
||||
#if defined(XP_MACOSX) && defined(MOZ_CONTENT_SANDBOX)
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
static bool
|
||||
GetAppPaths(nsCString &aAppPath, nsCString &aAppBinaryPath)
|
||||
GetAppPaths(nsCString &aAppPath, nsCString &aAppBinaryPath, nsCString &aAppDir)
|
||||
{
|
||||
nsAutoCString appPath;
|
||||
nsAutoCString appBinaryPath(
|
||||
|
@ -1112,6 +1117,23 @@ GetAppPaths(nsCString &aAppPath, nsCString &aAppBinaryPath)
|
|||
return false;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIFile> appDir;
|
||||
nsCOMPtr<nsIProperties> dirSvc =
|
||||
do_GetService(NS_DIRECTORY_SERVICE_CONTRACTID);
|
||||
if (!dirSvc) {
|
||||
return false;
|
||||
}
|
||||
rv = dirSvc->Get(NS_XPCOM_CURRENT_PROCESS_DIR,
|
||||
NS_GET_IID(nsIFile), getter_AddRefs(appDir));
|
||||
if (NS_FAILED(rv)) {
|
||||
return false;
|
||||
}
|
||||
bool exists;
|
||||
rv = appDir->Exists(&exists);
|
||||
if (NS_FAILED(rv) || !exists) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool isLink;
|
||||
app->IsSymlink(&isLink);
|
||||
if (isLink) {
|
||||
|
@ -1125,6 +1147,12 @@ GetAppPaths(nsCString &aAppPath, nsCString &aAppBinaryPath)
|
|||
} else {
|
||||
appBinary->GetNativePath(aAppBinaryPath);
|
||||
}
|
||||
appDir->IsSymlink(&isLink);
|
||||
if (isLink) {
|
||||
appDir->GetNativeTarget(aAppDir);
|
||||
} else {
|
||||
appDir->GetNativePath(aAppDir);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -1132,8 +1160,8 @@ GetAppPaths(nsCString &aAppPath, nsCString &aAppBinaryPath)
|
|||
static void
|
||||
StartMacOSContentSandbox()
|
||||
{
|
||||
nsAutoCString appPath, appBinaryPath;
|
||||
if (!GetAppPaths(appPath, appBinaryPath)) {
|
||||
nsAutoCString appPath, appBinaryPath, appDir;
|
||||
if (!GetAppPaths(appPath, appBinaryPath, appDir)) {
|
||||
MOZ_CRASH("Error resolving child process path");
|
||||
}
|
||||
|
||||
|
@ -1141,6 +1169,7 @@ StartMacOSContentSandbox()
|
|||
info.type = MacSandboxType_Content;
|
||||
info.appPath.Assign(appPath);
|
||||
info.appBinaryPath.Assign(appBinaryPath);
|
||||
info.appDir.Assign(appDir);
|
||||
|
||||
nsAutoCString err;
|
||||
if (!mozilla::StartMacSandbox(info, err)) {
|
||||
|
|
|
@ -33,3 +33,4 @@ phishingBlocked=The website at %S has been reported as a web forgery designed to
|
|||
cspBlocked=This page has a content security policy that prevents it from being loaded in this way.
|
||||
corruptedContentError=The page you are trying to view cannot be shown because an error in the data transmission was detected.
|
||||
remoteXUL=This page uses an unsupported technology that is no longer available by default.
|
||||
sslv3Used=The safety of your data on %S could not be guaranteed because it uses SSLv3, a broken security protocol.
|
||||
|
|
|
@ -364,6 +364,29 @@ nsresult MediaCodecDataDecoder::InitDecoder(Surface::Param aSurface)
|
|||
break; \
|
||||
}
|
||||
|
||||
nsresult MediaCodecDataDecoder::GetInputBuffer(JNIEnv* env, int index, jni::Object::LocalRef* buffer)
|
||||
{
|
||||
bool retried = false;
|
||||
while (!*buffer) {
|
||||
*buffer = jni::Object::LocalRef::Adopt(env->GetObjectArrayElement(mInputBuffers.Get(), index));
|
||||
if (!*buffer) {
|
||||
if (!retried) {
|
||||
// Reset the input buffers and then try again
|
||||
nsresult res = ResetInputBuffers();
|
||||
if (NS_FAILED(res)) {
|
||||
return res;
|
||||
}
|
||||
retried = true;
|
||||
} else {
|
||||
// We already tried resetting the input buffers, return an error
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void MediaCodecDataDecoder::DecoderLoop()
|
||||
{
|
||||
bool outputDone = false;
|
||||
|
@ -433,8 +456,10 @@ void MediaCodecDataDecoder::DecoderLoop()
|
|||
HANDLE_DECODER_ERROR();
|
||||
|
||||
if (inputIndex >= 0) {
|
||||
auto buffer = jni::Object::LocalRef::Adopt(
|
||||
frame.GetEnv()->GetObjectArrayElement(mInputBuffers.Get(), inputIndex));
|
||||
jni::Object::LocalRef buffer(frame.GetEnv());
|
||||
res = GetInputBuffer(frame.GetEnv(), inputIndex, &buffer);
|
||||
HANDLE_DECODER_ERROR();
|
||||
|
||||
void* directBuffer = frame.GetEnv()->GetDirectBufferAddress(buffer.Get());
|
||||
|
||||
MOZ_ASSERT(frame.GetEnv()->GetDirectBufferCapacity(buffer.Get()) >= sample->size,
|
||||
|
|
|
@ -92,6 +92,7 @@ protected:
|
|||
nsresult ResetOutputBuffers();
|
||||
|
||||
void DecoderLoop();
|
||||
nsresult GetInputBuffer(JNIEnv* env, int index, jni::Object::LocalRef* buffer);
|
||||
virtual void ClearQueue();
|
||||
};
|
||||
|
||||
|
|
|
@ -897,6 +897,13 @@ CreateFlashMinidump(DWORD processId, ThreadId childThread,
|
|||
bool
|
||||
PluginModuleChromeParent::ShouldContinueFromReplyTimeout()
|
||||
{
|
||||
if (mIsFlashPlugin) {
|
||||
MessageLoop::current()->PostTask(
|
||||
FROM_HERE,
|
||||
mTaskFactory.NewRunnableMethod(
|
||||
&PluginModuleChromeParent::NotifyFlashHang));
|
||||
}
|
||||
|
||||
#ifdef XP_WIN
|
||||
if (LaunchHangUI()) {
|
||||
return true;
|
||||
|
@ -1279,6 +1286,15 @@ PluginModuleChromeParent::ActorDestroy(ActorDestroyReason why)
|
|||
PluginModuleParent::ActorDestroy(why);
|
||||
}
|
||||
|
||||
void
|
||||
PluginModuleParent::NotifyFlashHang()
|
||||
{
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
if (obs) {
|
||||
obs->NotifyObservers(nullptr, "flash-plugin-hang", nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
PluginModuleParent::NotifyPluginCrashed()
|
||||
{
|
||||
|
|
|
@ -259,6 +259,7 @@ protected:
|
|||
void InitAsyncSurrogates();
|
||||
|
||||
protected:
|
||||
void NotifyFlashHang();
|
||||
void NotifyPluginCrashed();
|
||||
void OnInitFailure();
|
||||
|
||||
|
|
|
@ -2260,7 +2260,9 @@ RuntimeService::CreateSharedWorkerInternal(const GlobalObject& aGlobal,
|
|||
|
||||
WorkerPrivate::LoadInfo loadInfo;
|
||||
nsresult rv = WorkerPrivate::GetLoadInfo(cx, window, nullptr, aScriptURL,
|
||||
false, &loadInfo);
|
||||
false,
|
||||
WorkerPrivate::OverrideLoadGroup,
|
||||
&loadInfo);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
return CreateSharedWorkerFromLoadInfo(cx, &loadInfo, aScriptURL, aName, aType,
|
||||
|
@ -2314,6 +2316,11 @@ RuntimeService::CreateSharedWorkerFromLoadInfo(JSContext* aCx,
|
|||
NS_ENSURE_TRUE(workerPrivate, rv.ErrorCode());
|
||||
|
||||
created = true;
|
||||
} else {
|
||||
// If we're attaching to an existing SharedWorker private, then we
|
||||
// must update the overriden load group to account for our document's
|
||||
// load group.
|
||||
workerPrivate->UpdateOverridenLoadGroup(aLoadInfo->mLoadGroup);
|
||||
}
|
||||
|
||||
nsRefPtr<SharedWorker> sharedWorker = new SharedWorker(window, workerPrivate);
|
||||
|
|
|
@ -2483,10 +2483,7 @@ ServiceWorkerManager::CreateServiceWorker(nsIPrincipal* aPrincipal,
|
|||
// - use remote tabs = false
|
||||
// Alternatively we could persist the original load group values and use
|
||||
// them here.
|
||||
rv = NS_NewLoadGroup(getter_AddRefs(info.mLoadGroup), info.mPrincipal);
|
||||
if (NS_WARN_IF(NS_FAILED(rv))) {
|
||||
return rv;
|
||||
}
|
||||
WorkerPrivate::OverrideLoadInfoLoadGroup(info);
|
||||
|
||||
nsRefPtr<ServiceWorker> serviceWorker;
|
||||
RuntimeService* rs = RuntimeService::GetOrCreateService();
|
||||
|
|
|
@ -15,16 +15,19 @@
|
|||
#include "nsIDOMMessageEvent.h"
|
||||
#include "nsIDocument.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIInterfaceRequestor.h"
|
||||
#include "nsIMemoryReporter.h"
|
||||
#include "nsIPermissionManager.h"
|
||||
#include "nsIScriptError.h"
|
||||
#include "nsIScriptGlobalObject.h"
|
||||
#include "nsIScriptSecurityManager.h"
|
||||
#include "nsITabChild.h"
|
||||
#include "nsITextToSubURI.h"
|
||||
#include "nsIThreadInternal.h"
|
||||
#include "nsITimer.h"
|
||||
#include "nsIURI.h"
|
||||
#include "nsIURL.h"
|
||||
#include "nsIWeakReferenceUtils.h"
|
||||
#include "nsIWorkerDebugger.h"
|
||||
#include "nsIXPConnect.h"
|
||||
#include "nsPerformance.h"
|
||||
|
@ -704,13 +707,16 @@ class MainThreadReleaseRunnable MOZ_FINAL : public nsRunnable
|
|||
{
|
||||
nsTArray<nsCOMPtr<nsISupports>> mDoomed;
|
||||
nsTArray<nsCString> mHostObjectURIs;
|
||||
nsCOMPtr<nsILoadGroup> mLoadGroupToCancel;
|
||||
|
||||
public:
|
||||
MainThreadReleaseRunnable(nsTArray<nsCOMPtr<nsISupports>>& aDoomed,
|
||||
nsTArray<nsCString>& aHostObjectURIs)
|
||||
nsTArray<nsCString>& aHostObjectURIs,
|
||||
nsCOMPtr<nsILoadGroup>& aLoadGroupToCancel)
|
||||
{
|
||||
mDoomed.SwapElements(aDoomed);
|
||||
mHostObjectURIs.SwapElements(aHostObjectURIs);
|
||||
mLoadGroupToCancel.swap(aLoadGroupToCancel);
|
||||
}
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
|
@ -718,6 +724,11 @@ public:
|
|||
NS_IMETHOD
|
||||
Run() MOZ_OVERRIDE
|
||||
{
|
||||
if (mLoadGroupToCancel) {
|
||||
mLoadGroupToCancel->Cancel(NS_BINDING_ABORTED);
|
||||
mLoadGroupToCancel = nullptr;
|
||||
}
|
||||
|
||||
mDoomed.Clear();
|
||||
|
||||
for (uint32_t index = 0; index < mHostObjectURIs.Length(); index++) {
|
||||
|
@ -761,6 +772,9 @@ private:
|
|||
virtual bool
|
||||
WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) MOZ_OVERRIDE
|
||||
{
|
||||
nsCOMPtr<nsILoadGroup> loadGroupToCancel;
|
||||
mFinishedWorker->ForgetOverridenLoadGroup(loadGroupToCancel);
|
||||
|
||||
nsTArray<nsCOMPtr<nsISupports>> doomed;
|
||||
mFinishedWorker->ForgetMainThreadObjects(doomed);
|
||||
|
||||
|
@ -768,7 +782,7 @@ private:
|
|||
mFinishedWorker->StealHostObjectURIs(hostObjectURIs);
|
||||
|
||||
nsRefPtr<MainThreadReleaseRunnable> runnable =
|
||||
new MainThreadReleaseRunnable(doomed, hostObjectURIs);
|
||||
new MainThreadReleaseRunnable(doomed, hostObjectURIs, loadGroupToCancel);
|
||||
if (NS_FAILED(NS_DispatchToMainThread(runnable))) {
|
||||
NS_WARNING("Failed to dispatch, going to leak!");
|
||||
}
|
||||
|
@ -816,6 +830,9 @@ private:
|
|||
|
||||
runtime->UnregisterWorker(cx, mFinishedWorker);
|
||||
|
||||
nsCOMPtr<nsILoadGroup> loadGroupToCancel;
|
||||
mFinishedWorker->ForgetOverridenLoadGroup(loadGroupToCancel);
|
||||
|
||||
nsTArray<nsCOMPtr<nsISupports> > doomed;
|
||||
mFinishedWorker->ForgetMainThreadObjects(doomed);
|
||||
|
||||
|
@ -823,7 +840,7 @@ private:
|
|||
mFinishedWorker->StealHostObjectURIs(hostObjectURIs);
|
||||
|
||||
nsRefPtr<MainThreadReleaseRunnable> runnable =
|
||||
new MainThreadReleaseRunnable(doomed, hostObjectURIs);
|
||||
new MainThreadReleaseRunnable(doomed, hostObjectURIs, loadGroupToCancel);
|
||||
if (NS_FAILED(NS_DispatchToCurrentThread(runnable))) {
|
||||
NS_WARNING("Failed to dispatch, going to leak!");
|
||||
}
|
||||
|
@ -1982,6 +1999,129 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
template <class Derived>
|
||||
class WorkerPrivateParent<Derived>::InterfaceRequestor MOZ_FINAL
|
||||
: public nsIInterfaceRequestor
|
||||
{
|
||||
NS_DECL_ISUPPORTS
|
||||
|
||||
public:
|
||||
InterfaceRequestor(nsIPrincipal* aPrincipal, nsILoadGroup* aLoadGroup)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(aPrincipal);
|
||||
|
||||
// Look for an existing LoadContext. This is optional and it's ok if
|
||||
// we don't find one.
|
||||
nsCOMPtr<nsILoadContext> baseContext;
|
||||
if (aLoadGroup) {
|
||||
nsCOMPtr<nsIInterfaceRequestor> callbacks;
|
||||
aLoadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
|
||||
if (callbacks) {
|
||||
callbacks->GetInterface(NS_GET_IID(nsILoadContext),
|
||||
getter_AddRefs(baseContext));
|
||||
}
|
||||
}
|
||||
|
||||
mLoadContext = new LoadContext(aPrincipal, baseContext);
|
||||
}
|
||||
|
||||
void
|
||||
MaybeAddTabChild(nsILoadGroup* aLoadGroup)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
if (!aLoadGroup) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIInterfaceRequestor> callbacks;
|
||||
aLoadGroup->GetNotificationCallbacks(getter_AddRefs(callbacks));
|
||||
if (!callbacks) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsITabChild> tabChild;
|
||||
callbacks->GetInterface(NS_GET_IID(nsITabChild), getter_AddRefs(tabChild));
|
||||
if (!tabChild) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Use weak references to the tab child. Holding a strong reference will
|
||||
// not prevent an ActorDestroy() from being called on the TabChild.
|
||||
// Therefore, we should let the TabChild destroy itself as soon as possible.
|
||||
mTabChildList.AppendElement(do_GetWeakReference(tabChild));
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
GetInterface(const nsIID& aIID, void** aSink) MOZ_OVERRIDE
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
MOZ_ASSERT(mLoadContext);
|
||||
|
||||
if (aIID.Equals(NS_GET_IID(nsILoadContext))) {
|
||||
nsCOMPtr<nsILoadContext> ref = mLoadContext;
|
||||
ref.forget(aSink);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// If we still have an active nsITabChild, then return it. Its possible,
|
||||
// though, that all of the TabChild objects have been destroyed. In that
|
||||
// case we return NS_NOINTERFACE.
|
||||
if(aIID.Equals(NS_GET_IID(nsITabChild))) {
|
||||
nsCOMPtr<nsITabChild> tabChild = GetAnyLiveTabChild();
|
||||
if (!tabChild) {
|
||||
return NS_NOINTERFACE;
|
||||
}
|
||||
tabChild.forget(aSink);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
return NS_NOINTERFACE;
|
||||
}
|
||||
|
||||
private:
|
||||
~InterfaceRequestor() { }
|
||||
|
||||
already_AddRefed<nsITabChild>
|
||||
GetAnyLiveTabChild()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
|
||||
// Search our list of known TabChild objects for one that still exists.
|
||||
while (!mTabChildList.IsEmpty()) {
|
||||
nsCOMPtr<nsITabChild> tabChild =
|
||||
do_QueryReferent(mTabChildList.LastElement());
|
||||
|
||||
// Does this tab child still exist? If so, return it. We are done.
|
||||
if (tabChild) {
|
||||
return tabChild.forget();
|
||||
}
|
||||
|
||||
// Otherwise remove the stale weak reference and check the next one
|
||||
mTabChildList.RemoveElementAt(mTabChildList.Length() - 1);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsILoadContext> mLoadContext;
|
||||
|
||||
// Array of weak references to nsITabChild. We do not want to keep TabChild
|
||||
// actors alive for long after their ActorDestroy() methods are called.
|
||||
nsTArray<nsWeakPtr> mTabChildList;
|
||||
};
|
||||
|
||||
template <class Derived>
|
||||
NS_IMPL_ADDREF(WorkerPrivateParent<Derived>::InterfaceRequestor)
|
||||
|
||||
template <class Derived>
|
||||
NS_IMPL_RELEASE(WorkerPrivateParent<Derived>::InterfaceRequestor)
|
||||
|
||||
template <class Derived>
|
||||
NS_IMPL_QUERY_INTERFACE(WorkerPrivateParent<Derived>::InterfaceRequestor,
|
||||
nsIInterfaceRequestor)
|
||||
|
||||
template <class Derived>
|
||||
class WorkerPrivateParent<Derived>::EventTarget MOZ_FINAL
|
||||
: public nsIEventTarget
|
||||
|
@ -2833,6 +2973,22 @@ WorkerPrivateParent<Derived>::ModifyBusyCount(JSContext* aCx, bool aIncrease)
|
|||
return true;
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
void
|
||||
WorkerPrivateParent<Derived>::ForgetOverridenLoadGroup(
|
||||
nsCOMPtr<nsILoadGroup>& aLoadGroupOut)
|
||||
{
|
||||
AssertIsOnParentThread();
|
||||
|
||||
// If we're not overriden, then do nothing here. Let the load group get
|
||||
// handled in ForgetMainThreadObjects().
|
||||
if (!mLoadInfo.mInterfaceRequestor) {
|
||||
return;
|
||||
}
|
||||
|
||||
mLoadInfo.mLoadGroup.swap(aLoadGroupOut);
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
void
|
||||
WorkerPrivateParent<Derived>::ForgetMainThreadObjects(
|
||||
|
@ -2841,7 +2997,7 @@ WorkerPrivateParent<Derived>::ForgetMainThreadObjects(
|
|||
AssertIsOnParentThread();
|
||||
MOZ_ASSERT(!mMainThreadObjectsForgotten);
|
||||
|
||||
static const uint32_t kDoomedCount = 8;
|
||||
static const uint32_t kDoomedCount = 9;
|
||||
|
||||
aDoomed.SetCapacity(kDoomedCount);
|
||||
|
||||
|
@ -2853,6 +3009,7 @@ WorkerPrivateParent<Derived>::ForgetMainThreadObjects(
|
|||
SwapToISupportsArray(mLoadInfo.mChannel, aDoomed);
|
||||
SwapToISupportsArray(mLoadInfo.mCSP, aDoomed);
|
||||
SwapToISupportsArray(mLoadInfo.mLoadGroup, aDoomed);
|
||||
SwapToISupportsArray(mLoadInfo.mInterfaceRequestor, aDoomed);
|
||||
// Before adding anything here update kDoomedCount above!
|
||||
|
||||
MOZ_ASSERT(aDoomed.Length() == kDoomedCount);
|
||||
|
@ -3631,6 +3788,16 @@ WorkerPrivateParent<Derived>::StealHostObjectURIs(nsTArray<nsCString>& aArray)
|
|||
aArray.SwapElements(mHostObjectURIs);
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
void
|
||||
WorkerPrivateParent<Derived>::UpdateOverridenLoadGroup(nsILoadGroup* aBaseLoadGroup)
|
||||
{
|
||||
AssertIsOnMainThread();
|
||||
|
||||
// The load group should have been overriden at init time.
|
||||
mLoadInfo.mInterfaceRequestor->MaybeAddTabChild(aBaseLoadGroup);
|
||||
}
|
||||
|
||||
template <class Derived>
|
||||
NS_IMPL_ADDREF_INHERITED(WorkerPrivateParent<Derived>, DOMEventTargetHelper)
|
||||
|
||||
|
@ -4062,7 +4229,8 @@ WorkerPrivate::Constructor(JSContext* aCx,
|
|||
stackLoadInfo.emplace();
|
||||
|
||||
nsresult rv = GetLoadInfo(aCx, nullptr, parent, aScriptURL,
|
||||
aIsChromeWorker, stackLoadInfo.ptr());
|
||||
aIsChromeWorker, InheritLoadGroup,
|
||||
stackLoadInfo.ptr());
|
||||
if (NS_FAILED(rv)) {
|
||||
scriptloader::ReportLoadError(aCx, aScriptURL, rv, !parent);
|
||||
aRv.Throw(rv);
|
||||
|
@ -4117,7 +4285,9 @@ WorkerPrivate::Constructor(JSContext* aCx,
|
|||
nsresult
|
||||
WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow,
|
||||
WorkerPrivate* aParent, const nsAString& aScriptURL,
|
||||
bool aIsChromeWorker, LoadInfo* aLoadInfo)
|
||||
bool aIsChromeWorker,
|
||||
LoadGroupBehavior aLoadGroupBehavior,
|
||||
LoadInfo* aLoadInfo)
|
||||
{
|
||||
using namespace mozilla::dom::workers::scriptloader;
|
||||
using mozilla::dom::indexedDB::IDBFactory;
|
||||
|
@ -4350,10 +4520,8 @@ WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow,
|
|||
loadInfo.mReportCSPViolations = false;
|
||||
}
|
||||
|
||||
if (!loadInfo.mLoadGroup) {
|
||||
rv = NS_NewLoadGroup(getter_AddRefs(loadInfo.mLoadGroup),
|
||||
loadInfo.mPrincipal);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (!loadInfo.mLoadGroup || aLoadGroupBehavior == OverrideLoadGroup) {
|
||||
OverrideLoadInfoLoadGroup(loadInfo);
|
||||
}
|
||||
MOZ_ASSERT(NS_LoadGroupMatchesPrincipal(loadInfo.mLoadGroup,
|
||||
loadInfo.mPrincipal));
|
||||
|
@ -4373,6 +4541,26 @@ WorkerPrivate::GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
// static
|
||||
void
|
||||
WorkerPrivate::OverrideLoadInfoLoadGroup(LoadInfo& aLoadInfo)
|
||||
{
|
||||
MOZ_ASSERT(!aLoadInfo.mInterfaceRequestor);
|
||||
|
||||
aLoadInfo.mInterfaceRequestor = new InterfaceRequestor(aLoadInfo.mPrincipal,
|
||||
aLoadInfo.mLoadGroup);
|
||||
aLoadInfo.mInterfaceRequestor->MaybeAddTabChild(aLoadInfo.mLoadGroup);
|
||||
|
||||
nsCOMPtr<nsILoadGroup> loadGroup =
|
||||
do_CreateInstance(NS_LOADGROUP_CONTRACTID);
|
||||
|
||||
nsresult rv =
|
||||
loadGroup->SetNotificationCallbacks(aLoadInfo.mInterfaceRequestor);
|
||||
MOZ_ALWAYS_TRUE(NS_SUCCEEDED(rv));
|
||||
|
||||
aLoadInfo.mLoadGroup = loadGroup.forget();
|
||||
}
|
||||
|
||||
void
|
||||
WorkerPrivate::DoRunLoop(JSContext* aCx)
|
||||
{
|
||||
|
|
|
@ -132,6 +132,7 @@ class WorkerPrivateParent : public DOMEventTargetHelper
|
|||
class SynchronizeAndResumeRunnable;
|
||||
|
||||
protected:
|
||||
class InterfaceRequestor;
|
||||
class EventTarget;
|
||||
friend class EventTarget;
|
||||
|
||||
|
@ -163,6 +164,9 @@ public:
|
|||
nsCOMPtr<nsIChannel> mChannel;
|
||||
nsCOMPtr<nsILoadGroup> mLoadGroup;
|
||||
|
||||
// Only set if we have a custom overriden load group
|
||||
nsRefPtr<InterfaceRequestor> mInterfaceRequestor;
|
||||
|
||||
nsAutoPtr<PrincipalInfo> mPrincipalInfo;
|
||||
nsCString mDomain;
|
||||
|
||||
|
@ -207,6 +211,9 @@ public:
|
|||
MOZ_ASSERT(!mLoadGroup);
|
||||
aOther.mLoadGroup.swap(mLoadGroup);
|
||||
|
||||
MOZ_ASSERT(!mInterfaceRequestor);
|
||||
aOther.mInterfaceRequestor.swap(mInterfaceRequestor);
|
||||
|
||||
MOZ_ASSERT(!mPrincipalInfo);
|
||||
mPrincipalInfo = aOther.mPrincipalInfo.forget();
|
||||
|
||||
|
@ -393,6 +400,9 @@ public:
|
|||
bool
|
||||
ModifyBusyCount(JSContext* aCx, bool aIncrease);
|
||||
|
||||
void
|
||||
ForgetOverridenLoadGroup(nsCOMPtr<nsILoadGroup>& aLoadGroupOut);
|
||||
|
||||
void
|
||||
ForgetMainThreadObjects(nsTArray<nsCOMPtr<nsISupports> >& aDoomed);
|
||||
|
||||
|
@ -763,6 +773,9 @@ public:
|
|||
void
|
||||
StealHostObjectURIs(nsTArray<nsCString>& aArray);
|
||||
|
||||
void
|
||||
UpdateOverridenLoadGroup(nsILoadGroup* aBaseLoadGroup);
|
||||
|
||||
IMPL_EVENT_HANDLER(message)
|
||||
IMPL_EVENT_HANDLER(error)
|
||||
|
||||
|
@ -921,10 +934,19 @@ public:
|
|||
static bool
|
||||
WorkerAvailable(JSContext* /* unused */, JSObject* /* unused */);
|
||||
|
||||
enum LoadGroupBehavior
|
||||
{
|
||||
InheritLoadGroup,
|
||||
OverrideLoadGroup
|
||||
};
|
||||
|
||||
static nsresult
|
||||
GetLoadInfo(JSContext* aCx, nsPIDOMWindow* aWindow, WorkerPrivate* aParent,
|
||||
const nsAString& aScriptURL, bool aIsChromeWorker,
|
||||
LoadInfo* aLoadInfo);
|
||||
LoadGroupBehavior aLoadGroupBehavior, LoadInfo* aLoadInfo);
|
||||
|
||||
static void
|
||||
OverrideLoadInfoLoadGroup(LoadInfo& aLoadInfo);
|
||||
|
||||
WorkerDebugger*
|
||||
Debugger() const
|
||||
|
|
|
@ -32,9 +32,6 @@ using namespace mozilla;
|
|||
using namespace mozilla::dom;
|
||||
USING_WORKERS_NAMESPACE
|
||||
|
||||
// XXX Need to figure this out...
|
||||
#define UNCATCHABLE_EXCEPTION NS_ERROR_OUT_OF_MEMORY
|
||||
|
||||
/**
|
||||
* XMLHttpRequest in workers
|
||||
*
|
||||
|
@ -1907,7 +1904,7 @@ XMLHttpRequest::Open(const nsACString& aMethod, const nsAString& aUrl,
|
|||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
if (mCanceled) {
|
||||
aRv.Throw(UNCATCHABLE_EXCEPTION);
|
||||
aRv.ThrowUncatchableException();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1944,7 +1941,7 @@ XMLHttpRequest::SetRequestHeader(const nsACString& aHeader,
|
|||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
if (mCanceled) {
|
||||
aRv.Throw(UNCATCHABLE_EXCEPTION);
|
||||
aRv.ThrowUncatchableException();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1967,7 +1964,7 @@ XMLHttpRequest::SetTimeout(uint32_t aTimeout, ErrorResult& aRv)
|
|||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
if (mCanceled) {
|
||||
aRv.Throw(UNCATCHABLE_EXCEPTION);
|
||||
aRv.ThrowUncatchableException();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -1993,7 +1990,7 @@ XMLHttpRequest::SetWithCredentials(bool aWithCredentials, ErrorResult& aRv)
|
|||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
if (mCanceled) {
|
||||
aRv.Throw(UNCATCHABLE_EXCEPTION);
|
||||
aRv.ThrowUncatchableException();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2020,7 +2017,7 @@ XMLHttpRequest::SetMozBackgroundRequest(bool aBackgroundRequest,
|
|||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
if (mCanceled) {
|
||||
aRv.Throw(UNCATCHABLE_EXCEPTION);
|
||||
aRv.ThrowUncatchableException();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2047,7 +2044,7 @@ XMLHttpRequest::GetUpload(ErrorResult& aRv)
|
|||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
if (mCanceled) {
|
||||
aRv.Throw(UNCATCHABLE_EXCEPTION);
|
||||
aRv.ThrowUncatchableException();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -2069,7 +2066,7 @@ XMLHttpRequest::Send(ErrorResult& aRv)
|
|||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
if (mCanceled) {
|
||||
aRv.Throw(UNCATCHABLE_EXCEPTION);
|
||||
aRv.ThrowUncatchableException();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2091,7 +2088,7 @@ XMLHttpRequest::Send(const nsAString& aBody, ErrorResult& aRv)
|
|||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
if (mCanceled) {
|
||||
aRv.Throw(UNCATCHABLE_EXCEPTION);
|
||||
aRv.ThrowUncatchableException();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2117,7 +2114,7 @@ XMLHttpRequest::Send(JS::Handle<JSObject*> aBody, ErrorResult& aRv)
|
|||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
if (mCanceled) {
|
||||
aRv.Throw(UNCATCHABLE_EXCEPTION);
|
||||
aRv.ThrowUncatchableException();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2163,7 +2160,7 @@ XMLHttpRequest::Send(File& aBody, ErrorResult& aRv)
|
|||
JSContext* cx = mWorkerPrivate->GetJSContext();
|
||||
|
||||
if (mCanceled) {
|
||||
aRv.Throw(UNCATCHABLE_EXCEPTION);
|
||||
aRv.ThrowUncatchableException();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2230,7 +2227,7 @@ XMLHttpRequest::Abort(ErrorResult& aRv)
|
|||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
if (mCanceled) {
|
||||
aRv.Throw(UNCATCHABLE_EXCEPTION);
|
||||
aRv.ThrowUncatchableException();
|
||||
}
|
||||
|
||||
if (!mProxy) {
|
||||
|
@ -2258,7 +2255,7 @@ XMLHttpRequest::GetResponseHeader(const nsACString& aHeader,
|
|||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
if (mCanceled) {
|
||||
aRv.Throw(UNCATCHABLE_EXCEPTION);
|
||||
aRv.ThrowUncatchableException();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2285,7 +2282,7 @@ XMLHttpRequest::GetAllResponseHeaders(nsACString& aResponseHeaders,
|
|||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
if (mCanceled) {
|
||||
aRv.Throw(UNCATCHABLE_EXCEPTION);
|
||||
aRv.ThrowUncatchableException();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2311,7 +2308,7 @@ XMLHttpRequest::OverrideMimeType(const nsAString& aMimeType, ErrorResult& aRv)
|
|||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
if (mCanceled) {
|
||||
aRv.Throw(UNCATCHABLE_EXCEPTION);
|
||||
aRv.ThrowUncatchableException();
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -2342,7 +2339,7 @@ XMLHttpRequest::SetResponseType(XMLHttpRequestResponseType aResponseType,
|
|||
mWorkerPrivate->AssertIsOnWorkerThread();
|
||||
|
||||
if (mCanceled) {
|
||||
aRv.Throw(UNCATCHABLE_EXCEPTION);
|
||||
aRv.ThrowUncatchableException();
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
#define ANGLE_COMMIT_HASH "180bf375fb42"
|
||||
#define ANGLE_COMMIT_HASH "040a674b6d67"
|
||||
#define ANGLE_COMMIT_HASH_SIZE 12
|
||||
#define ANGLE_COMMIT_DATE "2015-02-05 14:21:03 -0500"
|
||||
#define ANGLE_COMMIT_DATE "2015-02-18 11:50:36 -0500"
|
||||
|
|
|
@ -234,5 +234,6 @@ DEFFILE = SRCDIR + '/libGLESv2.def'
|
|||
|
||||
SOURCES['renderer/d3d/HLSLCompiler.cpp'].flags += ['-DANGLE_PRELOADED_D3DCOMPILER_MODULE_NAMES=\'{ TEXT("d3dcompiler_47.dll"), TEXT("d3dcompiler_46.dll"), TEXT("d3dcompiler_43.dll") }\'']
|
||||
|
||||
SOURCES['renderer/d3d/d3d11/SwapChain11.cpp'].flags += ['-DANGLE_RESOURCE_SHARE_TYPE=D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX']
|
||||
if CONFIG['MOZ_HAS_WINSDK_WITH_D3D']:
|
||||
SOURCES['renderer/d3d/d3d11/SwapChain11.cpp'].flags += ['-DANGLE_RESOURCE_SHARE_TYPE=D3D11_RESOURCE_MISC_SHARED_KEYEDMUTEX']
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
var x = "wrong";
|
||||
var t = {x: "x"};
|
||||
var p = new Proxy(t, {
|
||||
has(t, id) {
|
||||
var found = id in t;
|
||||
delete t[id];
|
||||
return found;
|
||||
},
|
||||
get(t, id) { return t[id]; }
|
||||
});
|
||||
with (p)
|
||||
x += " x";
|
||||
assertEq(t.x, "undefined x");
|
|
@ -0,0 +1,12 @@
|
|||
enableOsiPointRegisterChecks()
|
||||
function f() {}
|
||||
f.__defineGetter__("x", (function() {
|
||||
this._
|
||||
}))
|
||||
for (var i = 0; i < 3; i++) {
|
||||
(function() {
|
||||
for (var j = 0; j < 1; j++) {
|
||||
f.x + 1
|
||||
}
|
||||
})()
|
||||
}
|
|
@ -6823,8 +6823,13 @@ ComputeGetPropResult(JSContext *cx, BaselineFrame *frame, JSOp op, HandlePropert
|
|||
return false;
|
||||
|
||||
RootedId id(cx, NameToId(name));
|
||||
if (!GetProperty(cx, obj, obj, id, res))
|
||||
return false;
|
||||
if (op == JSOP_GETXPROP) {
|
||||
if (!GetPropertyForNameLookup(cx, obj, id, res))
|
||||
return false;
|
||||
} else {
|
||||
if (!GetProperty(cx, obj, obj, id, res))
|
||||
return false;
|
||||
}
|
||||
|
||||
#if JS_HAS_NO_SUCH_METHOD
|
||||
// Handle objects with __noSuchMethod__.
|
||||
|
|
|
@ -2459,6 +2459,11 @@ InvalidateActivation(FreeOp *fop, const JitActivationIterator &activations, bool
|
|||
{
|
||||
JitSpew(JitSpew_IonInvalidate, "BEGIN invalidating activation");
|
||||
|
||||
#ifdef CHECK_OSIPOINT_REGISTERS
|
||||
if (js_JitOptions.checkOsiPointRegisters)
|
||||
activations->asJit()->setCheckRegs(false);
|
||||
#endif
|
||||
|
||||
size_t frameno = 1;
|
||||
|
||||
for (JitFrameIterator it(activations); !it.done(); ++it, ++frameno) {
|
||||
|
|
|
@ -747,6 +747,11 @@ HandleException(ResumeFromException *rfe)
|
|||
|
||||
JitActivation *activation = cx->runtime()->activation()->asJit();
|
||||
|
||||
#ifdef CHECK_OSIPOINT_REGISTERS
|
||||
if (js_JitOptions.checkOsiPointRegisters)
|
||||
activation->setCheckRegs(false);
|
||||
#endif
|
||||
|
||||
// The Debugger onExceptionUnwind hook (reachable via
|
||||
// HandleExceptionBaseline below) may cause on-stack recompilation of
|
||||
// baseline scripts, which may patch return addresses on the stack. Since
|
||||
|
|
|
@ -1167,6 +1167,10 @@ CodeGeneratorShared::verifyOsiPointRegs(LSafepoint *safepoint)
|
|||
// before the return address.
|
||||
masm.branch32(Assembler::NotEqual, checkRegs, Imm32(1), &failure);
|
||||
|
||||
// Set checkRegs to 0, so that we don't try to verify registers after we
|
||||
// return from this script to the caller.
|
||||
masm.store32(Imm32(0), checkRegs);
|
||||
|
||||
// Ignore clobbered registers. Some instructions (like LValueToInt32) modify
|
||||
// temps after calling into the VM. This is fine because no other
|
||||
// instructions (including this OsiPoint) will depend on them. Also
|
||||
|
|
|
@ -460,8 +460,11 @@ JSContext::currentScript(jsbytecode **ppc,
|
|||
if (act->isJit()) {
|
||||
JSScript *script = nullptr;
|
||||
js::jit::GetPcScript(const_cast<JSContext *>(this), &script, ppc);
|
||||
if (!allowCrossCompartment && script->compartment() != compartment())
|
||||
if (!allowCrossCompartment && script->compartment() != compartment()) {
|
||||
if (ppc)
|
||||
*ppc = nullptr;
|
||||
return nullptr;
|
||||
}
|
||||
return script;
|
||||
}
|
||||
|
||||
|
|
|
@ -228,8 +228,10 @@ function testSharedTypedArrayMethods() {
|
|||
assertEq(v[9], -5);
|
||||
}
|
||||
|
||||
testSharedArrayBuffer();
|
||||
testSharedTypedArray();
|
||||
testSharedTypedArrayMethods();
|
||||
if (typeof SharedArrayBuffer === "function") {
|
||||
testSharedArrayBuffer();
|
||||
testSharedTypedArray();
|
||||
testSharedTypedArrayMethods();
|
||||
}
|
||||
|
||||
reportCompare(0, 0, 'ok');
|
||||
|
|
|
@ -2411,11 +2411,9 @@ CASE(JSOP_THIS)
|
|||
END_CASE(JSOP_THIS)
|
||||
|
||||
CASE(JSOP_GETPROP)
|
||||
CASE(JSOP_GETXPROP)
|
||||
CASE(JSOP_LENGTH)
|
||||
CASE(JSOP_CALLPROP)
|
||||
{
|
||||
|
||||
MutableHandleValue lval = REGS.stackHandleAt(-1);
|
||||
if (!GetPropertyOperation(cx, REGS.fp(), script, REGS.pc, lval, lval))
|
||||
goto error;
|
||||
|
@ -2425,6 +2423,21 @@ CASE(JSOP_CALLPROP)
|
|||
}
|
||||
END_CASE(JSOP_GETPROP)
|
||||
|
||||
CASE(JSOP_GETXPROP)
|
||||
{
|
||||
RootedObject &obj = rootObject0;
|
||||
obj = ®S.sp[-1].toObject();
|
||||
RootedId &id = rootId0;
|
||||
id = NameToId(script->getName(REGS.pc));
|
||||
MutableHandleValue rval = REGS.stackHandleAt(-1);
|
||||
if (!GetPropertyForNameLookup(cx, obj, id, rval))
|
||||
goto error;
|
||||
|
||||
TypeScript::Monitor(cx, script, REGS.pc, rval);
|
||||
assertSameCompartmentDebugOnly(cx, rval);
|
||||
}
|
||||
END_CASE(JSOP_GETXPROP)
|
||||
|
||||
CASE(JSOP_SETINTRINSIC)
|
||||
{
|
||||
HandleValue value = REGS.stackHandleAt(-1);
|
||||
|
|
|
@ -1733,6 +1733,8 @@ Detecting(JSContext *cx, JSScript *script, jsbytecode *pc)
|
|||
return false;
|
||||
}
|
||||
|
||||
enum IsNameLookup { NotNameLookup = false, NameLookup = true };
|
||||
|
||||
/*
|
||||
* Finish getting the property `receiver[id]` after looking at every object on
|
||||
* the prototype chain and not finding any such property.
|
||||
|
@ -1752,7 +1754,7 @@ Detecting(JSContext *cx, JSScript *script, jsbytecode *pc)
|
|||
*/
|
||||
static bool
|
||||
GetNonexistentProperty(JSContext *cx, HandleNativeObject obj, HandleId id,
|
||||
HandleObject receiver, MutableHandleValue vp)
|
||||
HandleObject receiver, IsNameLookup nameLookup, MutableHandleValue vp)
|
||||
{
|
||||
vp.setUndefined();
|
||||
|
||||
|
@ -1768,12 +1770,7 @@ GetNonexistentProperty(JSContext *cx, HandleNativeObject obj, HandleId id,
|
|||
}
|
||||
|
||||
// If we are doing a name lookup, this is a ReferenceError.
|
||||
jsbytecode *pc = nullptr;
|
||||
RootedScript script(cx, cx->currentScript(&pc));
|
||||
if (!pc)
|
||||
return true;
|
||||
JSOp op = (JSOp) *pc;
|
||||
if (op == JSOP_GETXPROP) {
|
||||
if (nameLookup) {
|
||||
JSAutoByteString printable;
|
||||
if (js_ValueToPrintable(cx, IdToValue(id), &printable))
|
||||
js_ReportIsNotDefined(cx, printable.ptr());
|
||||
|
@ -1785,11 +1782,19 @@ GetNonexistentProperty(JSContext *cx, HandleNativeObject obj, HandleId id,
|
|||
//
|
||||
// Don't warn if extra warnings not enabled or for random getprop
|
||||
// operations.
|
||||
if (!cx->compartment()->options().extraWarnings(cx) || (op != JSOP_GETPROP && op != JSOP_GETELEM))
|
||||
if (!cx->compartment()->options().extraWarnings(cx))
|
||||
return true;
|
||||
|
||||
jsbytecode *pc;
|
||||
RootedScript script(cx, cx->currentScript(&pc));
|
||||
if (!script)
|
||||
return true;
|
||||
|
||||
if (*pc != JSOP_GETPROP && *pc != JSOP_GETELEM)
|
||||
return true;
|
||||
|
||||
// Don't warn repeatedly for the same script.
|
||||
if (!script || script->warnedAboutUndefinedProp())
|
||||
if (script->warnedAboutUndefinedProp())
|
||||
return true;
|
||||
|
||||
// Don't warn in self-hosted code (where the further presence of
|
||||
|
@ -1803,7 +1808,7 @@ GetNonexistentProperty(JSContext *cx, HandleNativeObject obj, HandleId id,
|
|||
return true;
|
||||
|
||||
// Do not warn about tests like (obj[prop] == undefined).
|
||||
pc += js_CodeSpec[op].length;
|
||||
pc += js_CodeSpec[*pc].length;
|
||||
if (Detecting(cx, script, pc))
|
||||
return true;
|
||||
|
||||
|
@ -1819,7 +1824,7 @@ GetNonexistentProperty(JSContext *cx, HandleNativeObject obj, HandleId id,
|
|||
/* The NoGC version of GetNonexistentProperty, present only to make types line up. */
|
||||
bool
|
||||
GetNonexistentProperty(JSContext *cx, NativeObject *obj, jsid id, JSObject *receiver,
|
||||
FakeMutableHandle<Value> vp)
|
||||
IsNameLookup nameLookup, FakeMutableHandle<Value> vp)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@ -1846,6 +1851,7 @@ NativeGetPropertyInline(JSContext *cx,
|
|||
typename MaybeRooted<NativeObject*, allowGC>::HandleType obj,
|
||||
typename MaybeRooted<JSObject*, allowGC>::HandleType receiver,
|
||||
typename MaybeRooted<jsid, allowGC>::HandleType id,
|
||||
IsNameLookup nameLookup,
|
||||
typename MaybeRooted<Value, allowGC>::MutableHandleType vp)
|
||||
{
|
||||
typename MaybeRooted<NativeObject*, allowGC>::RootType pobj(cx, obj);
|
||||
|
@ -1882,7 +1888,7 @@ NativeGetPropertyInline(JSContext *cx,
|
|||
// Step 4.c. The spec algorithm simply returns undefined if proto is
|
||||
// null, but see the comment on GetNonexistentProperty.
|
||||
if (!proto)
|
||||
return GetNonexistentProperty(cx, obj, id, receiver, vp);
|
||||
return GetNonexistentProperty(cx, obj, id, receiver, nameLookup, vp);
|
||||
|
||||
// Step 4.d. If the prototype is also native, this step is a
|
||||
// recursive tail call, and we don't need to go through all the
|
||||
|
@ -1900,16 +1906,23 @@ bool
|
|||
js::NativeGetProperty(JSContext *cx, HandleNativeObject obj, HandleObject receiver, HandleId id,
|
||||
MutableHandleValue vp)
|
||||
{
|
||||
return NativeGetPropertyInline<CanGC>(cx, obj, receiver, id, vp);
|
||||
return NativeGetPropertyInline<CanGC>(cx, obj, receiver, id, NotNameLookup, vp);
|
||||
}
|
||||
|
||||
bool
|
||||
js::NativeGetPropertyNoGC(JSContext *cx, NativeObject *obj, JSObject *receiver, jsid id, Value *vp)
|
||||
{
|
||||
AutoAssertNoException noexc(cx);
|
||||
return NativeGetPropertyInline<NoGC>(cx, obj, receiver, id, vp);
|
||||
return NativeGetPropertyInline<NoGC>(cx, obj, receiver, id, NotNameLookup, vp);
|
||||
}
|
||||
|
||||
bool
|
||||
js::GetPropertyForNameLookup(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp)
|
||||
{
|
||||
if (GetPropertyOp op = obj->getOps()->getProperty)
|
||||
return op(cx, obj, obj, id, vp);
|
||||
return NativeGetPropertyInline<CanGC>(cx, obj.as<NativeObject>(), obj, id, NameLookup, vp);
|
||||
}
|
||||
|
||||
/*** [[Set]] *************************************************************************************/
|
||||
|
||||
|
|
|
@ -1367,6 +1367,9 @@ HasDataProperty(JSContext *cx, NativeObject *obj, PropertyName *name, Value *vp)
|
|||
return HasDataProperty(cx, obj, NameToId(name), vp);
|
||||
}
|
||||
|
||||
extern bool
|
||||
GetPropertyForNameLookup(JSContext *cx, HandleObject obj, HandleId id, MutableHandleValue vp);
|
||||
|
||||
} /* namespace js */
|
||||
|
||||
template <>
|
||||
|
|
|
@ -100,7 +100,10 @@ XPCThrower::ThrowBadResult(nsresult rv, nsresult result, XPCCallContext& ccx)
|
|||
* If there is a pending exception when the native call returns and
|
||||
* it has the same error result as returned by the native call, then
|
||||
* the native call may be passing through an error from a previous JS
|
||||
* call. So we'll just throw that exception into our JS.
|
||||
* call. So we'll just throw that exception into our JS. Note that
|
||||
* we don't need to worry about NS_ERROR_UNCATCHABLE_EXCEPTION,
|
||||
* because presumably there would be no pending exception for that
|
||||
* nsresult!
|
||||
*/
|
||||
|
||||
if (CheckForPendingException(result, ccx))
|
||||
|
|
Двоичный файл не отображается.
|
@ -2,6 +2,7 @@
|
|||
# Android: SLOW_DIRECTORY; Mulet: bug 1048441, bug 1087611, bug 1112988, etc.
|
||||
skip-if = toolkit == 'android' || buildapp == 'mulet'
|
||||
support-files =
|
||||
Ahem.ttf
|
||||
border_radius_hit_testing_iframe.html
|
||||
preserve3d_sorting_hit_testing_iframe.html
|
||||
image_rgrg-256x256.png
|
||||
|
@ -69,6 +70,11 @@ support-files =
|
|||
bug1123067-2.html
|
||||
bug1123067-3.html
|
||||
bug1123067-ref.html
|
||||
selection-utils.js
|
||||
multi-range-user-select.html
|
||||
multi-range-user-select-ref.html
|
||||
multi-range-script-select.html
|
||||
multi-range-script-select-ref.html
|
||||
|
||||
[test_preserve3d_sorting_hit_testing.html]
|
||||
[test_after_paint_pref.html]
|
||||
|
|
|
@ -0,0 +1,173 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait"><head>
|
||||
<meta charset="utf-8">
|
||||
<title>Testcase #1 for bug 1129078</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="selection-utils.js"></script>
|
||||
|
||||
<style type="text/css">
|
||||
@font-face {
|
||||
font-family: Ahem;
|
||||
src: url("Ahem.ttf");
|
||||
}
|
||||
html,body { margin:0; padding: 0; }
|
||||
body,pre { font-family: Ahem; font-size: 20px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<pre id="select">
|
||||
2af45494-ak7e-11e4-a0c6-a7e7
|
||||
38222880-bj6d-11e4-8064-fb7b
|
||||
3d649ae4-ci5c-11e4-995d-17b2
|
||||
434351bc-dh4b-11e4-9971-4fc8
|
||||
4dc0e0b4-eg4a-11e4-8c28-5319
|
||||
a96319c8-ad7d-11e4-b312-039c
|
||||
</pre>
|
||||
|
||||
<pre id="log" style="border:1px solid green"></pre>
|
||||
|
||||
<script>
|
||||
|
||||
var sel = window.getSelection();
|
||||
var e = document.querySelector('#select');
|
||||
function setupSelectionPrev3() {
|
||||
addChildRanges([[0,150,0,160], [0,65,0,70], [0,15,0,15]], e);
|
||||
sel.extend(e.firstChild, 10); // to get eDirPrevious direction
|
||||
}
|
||||
function setupSelectionPrev2() {
|
||||
addChildRanges([[0,150,0,160], [0,70,0,70]], e);
|
||||
sel.extend(e.firstChild, 65); // to get eDirPrevious direction
|
||||
}
|
||||
function setupSelectionPrev1() {
|
||||
addChildRanges([[0,160,0,160]], e);
|
||||
sel.extend(e.firstChild, 150); // to get eDirPrevious direction
|
||||
}
|
||||
|
||||
function setupSelectionNext3() {
|
||||
addChildRanges([[0,10,0,15], [0,65,0,70], [0,150,0,160]], e);
|
||||
}
|
||||
function setupSelectionNext2() {
|
||||
addChildRanges([[0,10,0,15], [0,65,0,70]], e);
|
||||
}
|
||||
function setupSelectionNext2b() {
|
||||
addChildRanges([[0,15,0,80], [0,150,0,160]], e);
|
||||
}
|
||||
function setupSelectionNext1() {
|
||||
addChildRanges([[0,10,0,15]], e);
|
||||
}
|
||||
function setupSelectionNext1b() {
|
||||
addChildRanges([[0,15,0,170]], e);
|
||||
}
|
||||
function setupSelectionNext1c() {
|
||||
addChildRanges([[0,150,0,160]], e);
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
var hash = window.location.hash
|
||||
var op = hash.substring(6,8);
|
||||
var test = hash.substring(0,6);
|
||||
if (hash.substring(0,5) == "#prev") {
|
||||
if (test == "#prev1") {
|
||||
setupSelectionPrev3();
|
||||
if (op == "SL") {
|
||||
sel.extend(e.firstChild, 8);
|
||||
} else if (op == "SR") {
|
||||
sel.extend(e.firstChild, 12);
|
||||
} else if (op == "AD") {
|
||||
addChildRanges([[0,1,0,2]], e);
|
||||
} else {
|
||||
sel.extend(e.firstChild, 1);
|
||||
}
|
||||
} else if (test == "#prev2") {
|
||||
setupSelectionPrev3();
|
||||
sel.extend(e.firstChild, 13);
|
||||
} else if (test == "#prev3") {
|
||||
if (op == "S_") {
|
||||
setupSelectionPrev3();
|
||||
sel.extend(e.firstChild, 20);
|
||||
} else if (op == "SA") {
|
||||
setupSelectionPrev3();
|
||||
sel.extend(e.firstChild, 20);
|
||||
}
|
||||
} else if (test == "#prev4") {
|
||||
addChildRanges([[0,67,0,70], [0,150,0,160], [0,15,0,67]], e);
|
||||
} else if (test == "#prev5") {
|
||||
if (op == "S_") {
|
||||
setupSelectionNext2b();
|
||||
} else if (op == "SA") {
|
||||
setupSelectionNext2b();
|
||||
}
|
||||
} else if (test == "#prev6") {
|
||||
addChildRanges([[0,152,0,160], [0,15,0,152]], e);
|
||||
} else if (test == "#prev7") {
|
||||
if (op == "AD") {
|
||||
setupSelectionPrev3();
|
||||
addChildRanges([[0,168,0,170]], e);
|
||||
} else if (op == "S_") {
|
||||
setupSelectionNext1b();
|
||||
} else if (op == "SA") {
|
||||
setupSelectionNext1b();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (test == "#next1") {
|
||||
if (op == "SL") {
|
||||
setupSelectionNext3();
|
||||
sel.extend(e.firstChild, 158);
|
||||
} else if (op == "SR") {
|
||||
setupSelectionNext3();
|
||||
sel.extend(e.firstChild, 162);
|
||||
} else if (op == "AD") {
|
||||
setupSelectionNext3();
|
||||
addChildRanges([[0,1,0,2]], e);
|
||||
} else if (op == "S_") {
|
||||
setupSelectionNext1c();
|
||||
sel.extend(e.firstChild, 1);
|
||||
} else if (op == "SA") {
|
||||
setupSelectionNext1c();
|
||||
sel.extend(e.firstChild, 1);
|
||||
}
|
||||
} else if (test == "#next2") {
|
||||
addChildRanges([[0,10,0,13], [0,150,0,151]], e);
|
||||
sel.extend(e.firstChild, 13);
|
||||
} else if (test == "#next3") {
|
||||
if (op == "S_") {
|
||||
addChildRanges([[0,10,0,15], [0,150,0,151]], e);
|
||||
sel.extend(e.firstChild, 20);
|
||||
} else if (op == "SA") {
|
||||
setupSelectionNext3();
|
||||
sel.extend(e.firstChild, 20);
|
||||
}
|
||||
} else if (test == "#next4") {
|
||||
setupSelectionNext3();
|
||||
sel.extend(e.firstChild, 67);
|
||||
} else if (test == "#next5") {
|
||||
if (op == "S_") {
|
||||
setupSelectionNext3();
|
||||
sel.extend(e.firstChild, 80);
|
||||
} else if (op == "SA") {
|
||||
setupSelectionNext3();
|
||||
sel.extend(e.firstChild, 80);
|
||||
}
|
||||
} else if (test == "#next6") {
|
||||
setupSelectionNext3();
|
||||
sel.extend(e.firstChild, 152);
|
||||
} else if (test == "#next7") {
|
||||
setupSelectionNext3();
|
||||
if (op == "AD") {
|
||||
addChildRanges([[0,168,0,170]], e);
|
||||
} else {
|
||||
sel.extend(e.firstChild, 170);
|
||||
}
|
||||
}
|
||||
}
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
|
||||
SimpleTest.waitForFocus(runTest);
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,185 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait"><head>
|
||||
<meta charset="utf-8">
|
||||
<title>Testcase #1 for bug 1129078</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script src="selection-utils.js"></script>
|
||||
|
||||
<style type="text/css">
|
||||
@font-face {
|
||||
font-family: Ahem;
|
||||
src: url("Ahem.ttf");
|
||||
}
|
||||
html,body { margin:0; padding: 0; }
|
||||
body,pre { font-family: Ahem; font-size: 20px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<pre id="select">
|
||||
2af45494-ak7e-11e4-a0c6-a7e7
|
||||
38222880-bj6d-11e4-8064-fb7b
|
||||
3d649ae4-ci5c-11e4-995d-17b2
|
||||
434351bc-dh4b-11e4-9971-4fc8
|
||||
4dc0e0b4-eg4a-11e4-8c28-5319
|
||||
a96319c8-ad7d-11e4-b312-039c
|
||||
</pre>
|
||||
|
||||
<pre id="log" style="border:1px solid green"></pre>
|
||||
|
||||
<script>
|
||||
window.info = parent.info;
|
||||
window.is = parent.is;
|
||||
window.isnot = parent.isnot;
|
||||
window.ok = parent.ok;
|
||||
|
||||
function setupPrevSelection() {
|
||||
var sel = window.getSelection();
|
||||
var e = document.querySelector('#select');
|
||||
addChildRanges([[0,150,0,160], [0,65,0,70], [0,15,0,15]], e);
|
||||
sel.extend(e.firstChild, 10); // to get eDirPrevious direction
|
||||
}
|
||||
|
||||
function setupNextSelection() {
|
||||
var sel = window.getSelection();
|
||||
var e = document.querySelector('#select');
|
||||
addChildRanges([[0,10,0,15], [0,65,0,70], [0,150,0,160]], e);
|
||||
}
|
||||
|
||||
var ops = {
|
||||
S_ : shiftClick,
|
||||
SA : shiftAccelClick,
|
||||
AD : accelDragSelect,
|
||||
SL : keyLeft,
|
||||
SR : keyRight
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
var e = document.querySelector('#select');
|
||||
var hash = window.location.hash
|
||||
if (hash.substring(0,5)=="#prev")
|
||||
setupPrevSelection();
|
||||
else
|
||||
setupNextSelection();
|
||||
var op = hash.substring(6,8);
|
||||
var action = ops[op];
|
||||
var test = hash.substring(0,6);
|
||||
if (hash.substring(0,5) == "#prev") {
|
||||
if (test == "#prev1") {
|
||||
if (action == keyLeft) {
|
||||
keyLeft({shiftKey:true}, 2)
|
||||
checkRanges([[0,8,0,15], [0,65,0,70], [0,150,0,160]], e);
|
||||
} else if (action == keyRight) {
|
||||
keyRight({shiftKey:true}, 2)
|
||||
checkRanges([[0,12,0,15], [0,65,0,70], [0,150,0,160]], e);
|
||||
} else if (action == accelDragSelect) {
|
||||
accelDragSelect(e, 30, 50);
|
||||
checkRanges([[0,1,0,2], [0,10,0,15], [0,65,0,70], [0,150,0,160]], e);
|
||||
} else {
|
||||
action(e, 30);
|
||||
checkRanges([[0,1,0,15], [0,65,0,70], [0,150,0,160]], e);
|
||||
}
|
||||
} else if (test == "#prev2") {
|
||||
action(e, 260);
|
||||
checkRanges([[0,13,0,15], [0,65,0,70], [0,150,0,160]], e);
|
||||
} else if (test == "#prev3") {
|
||||
action(e, 400);
|
||||
if (action == shiftClick)
|
||||
checkRanges([[0,15,0,20], [0,65,0,70], [0,150,0,160]], e);
|
||||
else if (action == shiftAccelClick)
|
||||
checkRanges([[0,15,0,20], [0,65,0,70], [0,150,0,160]], e);
|
||||
} else if (test == "#prev4") {
|
||||
action(e, 180, 65);
|
||||
if (action == shiftClick)
|
||||
checkRanges([[0,15,0,67], [0,67,0,70], [0,150,0,160]], e);
|
||||
else if (action == shiftAccelClick)
|
||||
checkRanges([[0,15,0,67], [0,67,0,70], [0,150,0,160]], e);
|
||||
} else if (test == "#prev5") {
|
||||
action(e, 440, 65);
|
||||
if (action == shiftClick)
|
||||
checkRanges([[0,15,0,80], [0,150,0,160]], e);
|
||||
else if (action == shiftAccelClick)
|
||||
checkRanges([[0,15,0,80], [0,150,0,160]], e);
|
||||
} else if (test == "#prev6") {
|
||||
action(e, 140, 125);
|
||||
if (action == shiftClick)
|
||||
checkRanges([[0,15,0,152], [0,152,0,160]], e);
|
||||
else if (action == shiftAccelClick)
|
||||
checkRanges([[0,15,0,152], [0,152,0,160]], e);
|
||||
} else if (test == "#prev7") {
|
||||
if (action == accelDragSelect) {
|
||||
accelDragSelect(e, 460, 500, 125);
|
||||
checkRanges([[0,10,0,15], [0,65,0,70], [0,150,0,160], [0,168,0,170]], e);
|
||||
} else if (action == shiftClick) {
|
||||
action(e, 500, 125);
|
||||
checkRanges([[0,15,0,170]], e);
|
||||
} else if (action == shiftAccelClick) {
|
||||
action(e, 500, 125);
|
||||
checkRanges([[0,15,0,170]], e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (test == "#next1") {
|
||||
if (action == keyLeft) {
|
||||
keyLeft({shiftKey:true}, 2)
|
||||
checkRanges([[0,10,0,15], [0,65,0,70], [0,150,0,158]], e);
|
||||
} else if (action == keyRight) {
|
||||
keyRight({shiftKey:true}, 2)
|
||||
checkRanges([[0,10,0,15], [0,65,0,70], [0,150,0,162]], e);
|
||||
} else if (action == accelDragSelect) {
|
||||
accelDragSelect(e, 30, 50);
|
||||
checkRanges([[0,1,0,2], [0,10,0,15], [0,65,0,70], [0,150,0,160]], e);
|
||||
} else {
|
||||
action(e, 30);
|
||||
checkRanges([[0,1,0,150]], e);
|
||||
}
|
||||
} else if (test == "#next2") {
|
||||
action(e, 260);
|
||||
checkRanges([[0,10,0,13], [0,13,0,150]], e);
|
||||
} else if (test == "#next3") {
|
||||
action(e, 400);
|
||||
if (action == shiftClick)
|
||||
checkRanges([[0,10,0,15], [0,20,0,150]], e);
|
||||
else if (action == shiftAccelClick)
|
||||
checkRanges([[0,10,0,15], [0,20,0,150]], e);
|
||||
} else if (test == "#next4") {
|
||||
action(e, 180, 65);
|
||||
if (action == shiftClick)
|
||||
checkRanges([[0,10,0,15], [0,65,0,67], [0,67,0,150]], e);
|
||||
else if (action == shiftAccelClick)
|
||||
checkRanges([[0,10,0,15], [0,65,0,67], [0,67,0,150]], e);
|
||||
} else if (test == "#next5") {
|
||||
action(e, 440, 65);
|
||||
if (action == shiftClick)
|
||||
checkRanges([[0,10,0,15], [0,65,0,70], [0,80,0,150]], e);
|
||||
else if (action == shiftAccelClick)
|
||||
checkRanges([[0,10,0,15], [0,65,0,70], [0,80,0,150]], e);
|
||||
} else if (test == "#next6") {
|
||||
action(e, 140, 125);
|
||||
if (action == shiftClick)
|
||||
checkRanges([[0,10,0,15], [0,65,0,70], [0,150,0,152]], e);
|
||||
else if (action == shiftAccelClick)
|
||||
checkRanges([[0,10,0,15], [0,65,0,70], [0,150,0,152]], e);
|
||||
} else if (test == "#next7") {
|
||||
if (action == accelDragSelect) {
|
||||
accelDragSelect(e, 460, 500, 125);
|
||||
checkRanges([[0,10,0,15], [0,65,0,70], [0,150,0,160], [0,168,0,170]], e);
|
||||
} else if (action == shiftClick) {
|
||||
action(e, 500, 125);
|
||||
checkRanges([[0,10,0,15], [0,65,0,70], [0,150,0,170]], e);
|
||||
} else if (action == shiftAccelClick) {
|
||||
action(e, 500, 125);
|
||||
checkRanges([[0,10,0,15], [0,65,0,70], [0,150,0,170]], e);
|
||||
}
|
||||
}
|
||||
}
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
|
||||
SimpleTest.waitForFocus(runTest);
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,166 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait"><head>
|
||||
<meta charset="utf-8">
|
||||
<title>Testcase #1 for bug 1129078</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script src="selection-utils.js"></script>
|
||||
|
||||
<style type="text/css">
|
||||
@font-face {
|
||||
font-family: Ahem;
|
||||
src: url("Ahem.ttf");
|
||||
}
|
||||
html,body { margin:0; padding: 0; }
|
||||
body,pre { font-family: Ahem; font-size: 20px; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<pre id="select">
|
||||
2af45494-ak7e-11e4-a0c6-a7e7
|
||||
38222880-bj6d-11e4-8064-fb7b
|
||||
3d649ae4-ci5c-11e4-995d-17b2
|
||||
434351bc-dh4b-11e4-9971-4fc8
|
||||
4dc0e0b4-eg4a-11e4-8c28-5319
|
||||
a96319c8-ad7d-11e4-b312-039c
|
||||
</pre>
|
||||
|
||||
<pre id="log" style="border:1px solid green"></pre>
|
||||
|
||||
<script>
|
||||
|
||||
var sel = window.getSelection();
|
||||
var e = document.querySelector('#select');
|
||||
function setupSelectionPrev3() {
|
||||
addChildRanges([[0,150,0,160], [0,65,0,70], [0,15,0,15]], e);
|
||||
sel.extend(e.firstChild, 10); // to get eDirPrevious direction
|
||||
}
|
||||
function setupSelectionPrev2() {
|
||||
addChildRanges([[0,150,0,160], [0,70,0,70]], e);
|
||||
sel.extend(e.firstChild, 65); // to get eDirPrevious direction
|
||||
}
|
||||
function setupSelectionPrev1() {
|
||||
addChildRanges([[0,160,0,160]], e);
|
||||
sel.extend(e.firstChild, 150); // to get eDirPrevious direction
|
||||
}
|
||||
|
||||
function setupSelectionNext3() {
|
||||
addChildRanges([[0,10,0,15], [0,65,0,70], [0,150,0,160]], e);
|
||||
}
|
||||
function setupSelectionNext2() {
|
||||
addChildRanges([[0,10,0,15], [0,65,0,70]], e);
|
||||
}
|
||||
function setupSelectionNext2b() {
|
||||
addChildRanges([[0,15,0,80], [0,150,0,160]], e);
|
||||
}
|
||||
function setupSelectionNext1() {
|
||||
addChildRanges([[0,10,0,15]], e);
|
||||
}
|
||||
function setupSelectionNext1b() {
|
||||
addChildRanges([[0,15,0,170]], e);
|
||||
}
|
||||
function setupSelectionNext1c() {
|
||||
addChildRanges([[0,150,0,160]], e);
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
sel = window.getSelection();
|
||||
sel.removeAllRanges();
|
||||
document.body.offsetHeight;
|
||||
var hash = window.location.hash
|
||||
var op = hash.substring(6,8);
|
||||
var test = hash.substring(0,6);
|
||||
if (hash.substring(0,5) == "#prev") {
|
||||
if (test == "#prev1") {
|
||||
setupSelectionPrev3();
|
||||
if (op == "SL") {
|
||||
sel.extend(e.firstChild, 8);
|
||||
} else if (op == "SR") {
|
||||
sel.extend(e.firstChild, 12);
|
||||
} else if (op == "AD") {
|
||||
addChildRanges([[0,1,0,2]], e);
|
||||
} else {
|
||||
sel.extend(e.firstChild, 1);
|
||||
}
|
||||
} else if (test == "#prev2") {
|
||||
setupSelectionPrev3();
|
||||
sel.extend(e.firstChild, 14); // now eDirNext
|
||||
sel.extend(e.firstChild, 13); // now eDirPrevious again
|
||||
} else if (test == "#prev3") {
|
||||
setupSelectionPrev2();
|
||||
sel.extend(e.firstChild, 20);
|
||||
} else if (test == "#prev4") {
|
||||
setupSelectionPrev2();
|
||||
sel.extend(e.firstChild, 68); // now eDirNext
|
||||
sel.extend(e.firstChild, 67); // now eDirPrevious again
|
||||
} else if (test == "#prev5") {
|
||||
setupSelectionPrev1();
|
||||
sel.extend(e.firstChild, 80);
|
||||
} else if (test == "#prev6") {
|
||||
setupSelectionPrev1();
|
||||
sel.extend(e.firstChild, 153); // now eDirNext
|
||||
sel.extend(e.firstChild, 152); // now eDirPrevious again
|
||||
} else if (test == "#prev7") {
|
||||
if (op == "AD") {
|
||||
setupSelectionPrev3();
|
||||
addChildRanges([[0,168,0,170]], e);
|
||||
} else {
|
||||
addChildRanges([[0,160,0,170]], e);
|
||||
}
|
||||
} else if (test == "#prev8") {
|
||||
if (op == "AD") {
|
||||
addChildRanges([[0,150,0,155], [0,68,0,70]], e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (test == "#next1") {
|
||||
if (op == "SL") {
|
||||
setupSelectionNext3();
|
||||
sel.extend(e.firstChild, 158);
|
||||
} else if (op == "SR") {
|
||||
setupSelectionNext3();
|
||||
sel.extend(e.firstChild, 162);
|
||||
} else if (op == "AD") {
|
||||
setupSelectionNext3();
|
||||
addChildRanges([[0,1,0,2]], e);
|
||||
} else {
|
||||
setupSelectionNext1();
|
||||
sel.extend(e.firstChild, 1);
|
||||
}
|
||||
} else if (test == "#next2") {
|
||||
setupSelectionNext1();
|
||||
sel.extend(e.firstChild, 13);
|
||||
} else if (test == "#next3") {
|
||||
setupSelectionNext1();
|
||||
sel.extend(e.firstChild, 20);
|
||||
} else if (test == "#next4") {
|
||||
setupSelectionNext2();
|
||||
sel.extend(e.firstChild, 67);
|
||||
} else if (test == "#next5") {
|
||||
setupSelectionNext2();
|
||||
sel.extend(e.firstChild, 80);
|
||||
} else if (test == "#next6") {
|
||||
setupSelectionNext3();
|
||||
sel.extend(e.firstChild, 152);
|
||||
} else if (test == "#next7") {
|
||||
setupSelectionNext3();
|
||||
if (op == "AD") {
|
||||
addChildRanges([[0,168,0,170]], e);
|
||||
} else {
|
||||
sel.extend(e.firstChild, 170);
|
||||
}
|
||||
} else if (test == "#next8") {
|
||||
if (op == "AD") {
|
||||
addChildRanges([[0,68,0,70], [0,150,0,155]], e);
|
||||
}
|
||||
}
|
||||
}
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
|
||||
SimpleTest.waitForFocus(function(){setTimeout(runTest,0)});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,229 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html class="reftest-wait"><head>
|
||||
<meta charset="utf-8">
|
||||
<title>Testcase #1 for bug 1129078</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/EventUtils.js"></script>
|
||||
<script src="selection-utils.js"></script>
|
||||
|
||||
<style type="text/css">
|
||||
@font-face {
|
||||
font-family: Ahem;
|
||||
src: url("Ahem.ttf");
|
||||
}
|
||||
html,body { margin:0; padding: 0; }
|
||||
body,pre { font-family: Ahem; font-size: 20px; }
|
||||
span { -moz-user-select:none; }
|
||||
x { -moz-user-select:text; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<pre id="select">
|
||||
2af45494-a<x>k7e-1</x><span id="span2">1e4-a0c6-a7e7
|
||||
38222880-bj6d-11e4-8064-fb7b
|
||||
3d649ae</span><x>4-ci5</x><span id="span3">c-11e4-995d-17b2
|
||||
434351bc-dh4b-11e4-9971-4fc8
|
||||
4dc0e0b4-eg4a-11e4-8c28-5319
|
||||
a9631</span><x>9c8-ad7d-1</x>1e4-b312-039c
|
||||
</pre>
|
||||
|
||||
<pre id="log" style="border:1px solid green"></pre>
|
||||
|
||||
<script>
|
||||
window.info = parent.info;
|
||||
window.is = parent.is;
|
||||
window.isnot = parent.isnot;
|
||||
window.ok = parent.ok;
|
||||
|
||||
var sel = window.getSelection();
|
||||
|
||||
function enableSelection(id) {
|
||||
var span = document.getElementById(id);
|
||||
span.style.MozUserSelect = 'text';
|
||||
}
|
||||
|
||||
function setupPrevSelection() {
|
||||
var e = document.querySelector('#select');
|
||||
dragSelectPoints(e, 300, 125, 200, 5);
|
||||
}
|
||||
|
||||
function setupNextSelection() {
|
||||
var e = document.querySelector('#select');
|
||||
dragSelectPoints(e, 199, 5, 300, 125);
|
||||
}
|
||||
|
||||
var ops = {
|
||||
S_ : shiftClick,
|
||||
SA : shiftAccelClick,
|
||||
AD : accelDragSelect,
|
||||
SL : keyLeft,
|
||||
SR : keyRight
|
||||
}
|
||||
|
||||
function runTest() {
|
||||
sel = window.getSelection();
|
||||
sel.removeAllRanges();
|
||||
document.body.offsetHeight;
|
||||
var e = document.querySelector('#select');
|
||||
var hash = window.location.hash
|
||||
if (hash.substring(0,5)=="#prev")
|
||||
setupPrevSelection();
|
||||
else
|
||||
setupNextSelection();
|
||||
var op = hash.substring(6,8);
|
||||
var action = ops[op];
|
||||
var test = hash.substring(0,6);
|
||||
if (hash.substring(0,5) == "#prev") {
|
||||
if (test == "#prev1") {
|
||||
if (action == keyLeft) {
|
||||
keyLeft({shiftKey:true}, 2)
|
||||
checkRanges([[0,8,-1,2], [3,0,-1,4], [5,0,6,0]], e);
|
||||
} else if (action == keyRight) {
|
||||
keyRight({shiftKey:true}, 2)
|
||||
checkRanges([[e.childNodes[1].firstChild,2,-1,2], [3,0,-1,4], [5,0,6,0]], e);
|
||||
} else if (action == accelDragSelect) {
|
||||
accelDragSelect(e, 30, 50);
|
||||
checkRanges([[0,1,0,2], [e.childNodes[1].firstChild,0,-1,2], [3,0,-1,4], [5,0,6,0]], e);
|
||||
} else {
|
||||
action(e, 30);
|
||||
checkRanges([[0,1,-1,2], [3,0,-1,4], [5,0,6,0]], e);
|
||||
}
|
||||
} else if (test == "#prev2") {
|
||||
action(e, 260);
|
||||
checkRangeCount(3, e);
|
||||
checkRange(0, [0,3,-2,2], e.childNodes[1]);
|
||||
checkRange(1, [3,0,-1,4], e);
|
||||
checkRange(2, [5,0,6,0], e);
|
||||
} else if (test == "#prev3") {
|
||||
enableSelection('span2');
|
||||
action(e, 400);
|
||||
checkRangeCount(2, e);
|
||||
checkRange(0, [0,5,-2,4], e.childNodes[2]);
|
||||
checkRange(1, [5,0,6,0], e);
|
||||
} else if (test == "#prev4") {
|
||||
action(e, 180, 65);
|
||||
checkRangeCount(2, e);
|
||||
checkRange(0, [0,2,-2,4], e.childNodes[3]);
|
||||
checkRange(1, [5,0,6,0], e);
|
||||
} else if (test == "#prev5") {
|
||||
enableSelection('span3');
|
||||
action(e, 440, 65);
|
||||
checkRangeCount(1, e);
|
||||
var r = sel.getRangeAt(0);
|
||||
checkRangePoints(r, [e.childNodes[4].firstChild,10,e.childNodes[6],0], e);
|
||||
} else if (test == "#prev6") {
|
||||
action(e, 140, 125);
|
||||
checkRangeCount(1, e);
|
||||
var r = sel.getRangeAt(0);
|
||||
checkRangePoints(r, [e.childNodes[5].firstChild,2,e.childNodes[6],0], e);
|
||||
} else if (test == "#prev7") {
|
||||
if (action == accelDragSelect) {
|
||||
accelDragSelect(e, 460, 500, 125);
|
||||
checkRanges([[e.childNodes[1].firstChild,0,-1,2], [3,0,-1,4], [5,0,6,0], [6,8,6,10]], e);
|
||||
} else {
|
||||
action(e, 500, 125);
|
||||
checkRanges([[6,0,6,10]], e);
|
||||
}
|
||||
} else if (test == "#prev8") {
|
||||
if (action == accelDragSelect) {
|
||||
sel.removeAllRanges();
|
||||
var e = document.querySelector('#select');
|
||||
synthesizeMouse(e, 200, 125, {type: "mousedown", accelKey: true});
|
||||
synthesizeMouse(e, 200, 120, {type: "mousemove", accelKey: true});
|
||||
synthesizeMouse(e, 200, 100, {type: "mousemove", accelKey: true});
|
||||
synthesizeMouse(e, 200, 80, {type: "mousemove", accelKey: true});
|
||||
synthesizeMouse(e, 210, 60, {type: "mousemove", accelKey: true});
|
||||
synthesizeMouse(e, 200, 60, {type: "mousemove", accelKey: true});
|
||||
synthesizeMouse(e, 200, 60, {type: "mouseup", accelKey: true});
|
||||
var x3t = e.childNodes[3].firstChild;
|
||||
var x5 = e.childNodes[5];
|
||||
checkRanges([[x3t,3,-1,4], [x5,0,x5.firstChild,5]], e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (test == "#next1") {
|
||||
if (action == keyLeft) {
|
||||
keyLeft({shiftKey:true}, 2)
|
||||
checkRanges([[0,10,-1,2], [3,0,-1,4], [5,0,e.childNodes[5].firstChild,8]], e);
|
||||
} else if (action == keyRight) {
|
||||
keyRight({shiftKey:true}, 2)
|
||||
checkRanges([[0,10,-1,2], [3,0,-1,4], [5,0,6,2]], e);
|
||||
} else if (action == accelDragSelect) {
|
||||
accelDragSelect(e, 30, 50);
|
||||
checkRanges([[0,1,0,2], [0,10,-1,2], [3,0,-1,4], [5,0,e.childNodes[5].firstChild,10]], e);
|
||||
} else {
|
||||
action(e, 30);
|
||||
checkRanges([[0,1,0,10]], e);
|
||||
}
|
||||
} else if (test == "#next2") {
|
||||
action(e, 260);
|
||||
checkRangeCount(1, e);
|
||||
var r = sel.getRangeAt(0);
|
||||
checkRangePoints(r, [e.childNodes[0],10,e.childNodes[1].firstChild,3], e);
|
||||
} else if (test == "#next3") {
|
||||
enableSelection('span2');
|
||||
action(e, 400);
|
||||
checkRangeCount(1, e);
|
||||
var r = sel.getRangeAt(0);
|
||||
checkRangePoints(r, [e.childNodes[0],10,e.childNodes[2].firstChild,5], e);
|
||||
} else if (test == "#next4") {
|
||||
action(e, 180, 65);
|
||||
checkRangeCount(2, e);
|
||||
checkRange(0, [0,10,-1,2], e);
|
||||
checkRange(1, [-1,0,0,2], e.childNodes[3]);
|
||||
} else if (test == "#next5") {
|
||||
enableSelection('span3');
|
||||
action(e, 440, 65);
|
||||
checkRangeCount(2, e);
|
||||
checkRange(0, [0,10,-1,2], e);
|
||||
var r = sel.getRangeAt(1);
|
||||
checkRangePoints(r, [e.childNodes[3],0,e.childNodes[4].firstChild,10], e);
|
||||
} else if (test == "#next6") {
|
||||
action(e, 140, 125);
|
||||
checkRangeCount(3, e);
|
||||
checkRange(0, [0,10,-1,2], e);
|
||||
checkRange(1, [3,0,-1,4], e);
|
||||
checkRange(2, [-1,0,0,2], e.childNodes[5]);
|
||||
} else if (test == "#next7") {
|
||||
if (action == keyRight) {
|
||||
keyRight({shiftKey:true}, 2)
|
||||
checkRanges([[0,10,-1,2], [3,0,-1,4], [5,0,6,2]], e);
|
||||
} else if (action == accelDragSelect) {
|
||||
accelDragSelect(e, 460, 500, 125);
|
||||
checkRanges([[0,10,-1,2], [3,0,-1,4], [5,0,e.childNodes[5].firstChild,10], [6,8,6,10]], e);
|
||||
} else {
|
||||
action(e, 500, 125);
|
||||
checkRangeCount(3, e);
|
||||
checkRange(0, [0,10,-1,2], e);
|
||||
checkRange(1, [3,0,-1,4], e);
|
||||
var r = sel.getRangeAt(2);
|
||||
checkRangePoints(r, [e.childNodes[5],0,e.childNodes[6],10], e);
|
||||
}
|
||||
} else if (test == "#next8") {
|
||||
if (action == accelDragSelect) {
|
||||
sel.removeAllRanges();
|
||||
var e = document.querySelector('#select');
|
||||
synthesizeMouse(e, 200, 60, {type: "mousedown", accelKey: true});
|
||||
synthesizeMouse(e, 180, 60, {type: "mousemove", accelKey: true});
|
||||
synthesizeMouse(e, 200, 80, {type: "mousemove", accelKey: true});
|
||||
synthesizeMouse(e, 200, 100, {type: "mousemove", accelKey: true});
|
||||
synthesizeMouse(e, 200, 120, {type: "mousemove", accelKey: true});
|
||||
synthesizeMouse(e, 190, 125, {type: "mousemove", accelKey: true});
|
||||
synthesizeMouse(e, 200, 125, {type: "mousemove", accelKey: true});
|
||||
synthesizeMouse(e, 200, 125, {type: "mouseup", accelKey: true});
|
||||
var x3t = e.childNodes[3].firstChild;
|
||||
var x5 = e.childNodes[5];
|
||||
checkRanges([[x3t,3,-1,4], [x5,0,x5.firstChild,5]], e);
|
||||
}
|
||||
}
|
||||
}
|
||||
document.documentElement.removeAttribute("class");
|
||||
}
|
||||
|
||||
SimpleTest.waitForFocus(function(){setTimeout(runTest,0)});
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,151 @@
|
|||
// -*- Mode: Javascript; tab-width: 2; indent-tabs-mode: nil; js-indent-level: 2 -*-
|
||||
// vim: set ts=2 sw=2 et tw=78:
|
||||
function clearSelection(w)
|
||||
{
|
||||
var sel = (w ? w : window).getSelection();
|
||||
sel.removeAllRanges();
|
||||
}
|
||||
|
||||
function getNode(e, index) {
|
||||
if (!(typeof index==='number')) return index;
|
||||
if (index >= 0) return e.childNodes[index];
|
||||
while (++index != 0) e = e.parentNode;
|
||||
return e;
|
||||
}
|
||||
|
||||
function dragSelectPointsWithData()
|
||||
{
|
||||
var event = arguments[0];
|
||||
var e = arguments[1];
|
||||
var x1 = arguments[2];
|
||||
var y1 = arguments[3];
|
||||
var x2 = arguments[4];
|
||||
var y2 = arguments[5];
|
||||
dir = x2 > x1 ? 1 : -1;
|
||||
event['type'] = "mousedown";
|
||||
synthesizeMouse(e, x1, y1, event);
|
||||
event['type'] = "mousemove";
|
||||
synthesizeMouse(e, x1 + dir, y1, event);
|
||||
for (var i = 6; i < arguments.length; ++i)
|
||||
synthesizeMouse(e, arguments[i], y1, event);
|
||||
synthesizeMouse(e, x2 - dir, y2, event);
|
||||
event['type'] = "mouseup";
|
||||
synthesizeMouse(e, x2, y2, event);
|
||||
}
|
||||
|
||||
function dragSelectPoints()
|
||||
{
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
dragSelectPointsWithData.apply(this, [{}].concat(args));
|
||||
}
|
||||
|
||||
function dragSelect()
|
||||
{
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
var e = args.shift();
|
||||
var x1 = args.shift();
|
||||
var x2 = args.shift();
|
||||
dragSelectPointsWithData.apply(this, [{},e,x1,5,x2,5].concat(args));
|
||||
}
|
||||
|
||||
function accelDragSelect()
|
||||
{
|
||||
var args = Array.prototype.slice.call(arguments);
|
||||
var e = args.shift();
|
||||
var x1 = args.shift();
|
||||
var x2 = args.shift();
|
||||
var y = args.length != 0 ? args.shift() : 5;
|
||||
dragSelectPointsWithData.apply(this, [{accelKey: true},e,x1,y,x2,y].concat(args));
|
||||
}
|
||||
|
||||
function shiftClick(e, x, y)
|
||||
{
|
||||
function pos(p) { return (typeof p === "undefined") ? 5 : p }
|
||||
synthesizeMouse(e, pos(x), pos(y), { shiftKey: true });
|
||||
}
|
||||
|
||||
function keyRepeat(key,data,repeat)
|
||||
{
|
||||
while (repeat-- > 0)
|
||||
synthesizeKey(key, data);
|
||||
}
|
||||
|
||||
function keyRight(data)
|
||||
{
|
||||
var repeat = arguments.length > 1 ? arguments[1] : 1;
|
||||
keyRepeat("VK_RIGHT", data, repeat);
|
||||
}
|
||||
|
||||
function keyLeft(data)
|
||||
{
|
||||
var repeat = arguments.length > 1 ? arguments[1] : 1;
|
||||
keyRepeat("VK_LEFT", data, repeat);
|
||||
}
|
||||
|
||||
function shiftAccelClick(e, x, y)
|
||||
{
|
||||
function pos(p) { return (typeof p === "undefined") ? 5 : p }
|
||||
synthesizeMouse(e, pos(x), pos(y), { shiftKey: true, accelKey: true });
|
||||
}
|
||||
|
||||
function accelClick(e, x, y)
|
||||
{
|
||||
function pos(p) { return (typeof p === "undefined") ? 5 : p }
|
||||
synthesizeMouse(e, pos(x), pos(y), { accelKey: true });
|
||||
}
|
||||
|
||||
function addChildRanges(arr, e)
|
||||
{
|
||||
var sel = window.getSelection();
|
||||
for (i = 0; i < arr.length; ++i) {
|
||||
var data = arr[i];
|
||||
var r = new Range()
|
||||
r.setStart(getNode(e, data[0]), data[1]);
|
||||
r.setEnd(getNode(e, data[2]), data[3]);
|
||||
sel.addRange(r);
|
||||
}
|
||||
}
|
||||
|
||||
function checkText(text, e)
|
||||
{
|
||||
var sel = window.getSelection();
|
||||
is(sel.toString(), text, e.id + ": selected text")
|
||||
}
|
||||
|
||||
function checkRangeText(text, index)
|
||||
{
|
||||
var r = window.getSelection().getRangeAt(index);
|
||||
is(r.toString(), text, e.id + ": range["+index+"].toString()")
|
||||
}
|
||||
|
||||
function checkRangeCount(n, e)
|
||||
{
|
||||
var sel = window.getSelection();
|
||||
is(sel.rangeCount, n, e.id + ": Selection range count");
|
||||
}
|
||||
|
||||
function checkRangePoints(r, expected, e) {
|
||||
is(r.startContainer, expected[0], e.id + ": range.startContainer");
|
||||
is(r.startOffset, expected[1], e.id + ": range.startOffset");
|
||||
is(r.endContainer, expected[2], e.id + ": range.endContainer");
|
||||
is(r.endOffset, expected[3], e.id + ": range.endOffset");
|
||||
}
|
||||
|
||||
function checkRange(i, expected, e) {
|
||||
var sel = window.getSelection();
|
||||
if (i >= sel.rangeCount) return;
|
||||
var r = sel.getRangeAt(i);
|
||||
is(r.startContainer, getNode(e, expected[0]), e.id + ": range["+i+"].startContainer");
|
||||
is(r.startOffset, expected[1], e.id + ": range["+i+"].startOffset");
|
||||
is(r.endContainer, getNode(e, expected[2]), e.id + ": range["+i+"].endContainer");
|
||||
is(r.endOffset, expected[3], e.id + ": range["+i+"].endOffset");
|
||||
}
|
||||
|
||||
function checkRanges(arr, e)
|
||||
{
|
||||
checkRangeCount(arr.length, e);
|
||||
for (i = 0; i < arr.length; ++i) {
|
||||
var expected = arr[i];
|
||||
checkRange(i, expected, e);
|
||||
}
|
||||
}
|
|
@ -8,8 +8,9 @@
|
|||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
|
||||
<style>
|
||||
iframe {
|
||||
border: none;
|
||||
width: 600px;
|
||||
height: 600px;
|
||||
height: 400px;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript">
|
||||
|
@ -92,6 +93,8 @@ function refTest(test,ref) {
|
|||
|
||||
var caretBlinkTime = null;
|
||||
function endTest() {
|
||||
var parentDoc = window.parent.document;
|
||||
parentDoc.styleSheets[parentDoc.styleSheets.length-1].deleteRule(0);
|
||||
// finish(), yet let the test actually end first, to be safe.
|
||||
SimpleTest.executeSoon(SimpleTest.finish);
|
||||
}
|
||||
|
@ -168,6 +171,106 @@ if (navigator.appVersion.indexOf("Android") == -1 &&
|
|||
is(SpecialPowers.getIntPref("layout.spellcheckDefault"), 0, "Spellcheck should be turned off for this platrom or this if..else check removed");
|
||||
}
|
||||
|
||||
if (navigator.platform.indexOf("Linux") >= 0 &&
|
||||
SpecialPowers.Services.appinfo.name != "B2G") {
|
||||
tests = tests.concat([
|
||||
function() {SpecialPowers.pushPrefEnv({'set': [['touchcaret.enabled', false]]}, nextTest);} ,
|
||||
// eDirPrevious, Shift+click
|
||||
[ 'multi-range-user-select.html#prev1S_' , 'multi-range-user-select-ref.html#prev1S_' ] ,
|
||||
[ 'multi-range-user-select.html#prev2S_' , 'multi-range-user-select-ref.html#prev2S_' ] ,
|
||||
[ 'multi-range-user-select.html#prev3S_' , 'multi-range-user-select-ref.html#prev3S_' ] ,
|
||||
[ 'multi-range-user-select.html#prev4S_' , 'multi-range-user-select-ref.html#prev4S_' ] ,
|
||||
[ 'multi-range-user-select.html#prev5S_' , 'multi-range-user-select-ref.html#prev5S_' ] ,
|
||||
[ 'multi-range-user-select.html#prev6S_' , 'multi-range-user-select-ref.html#prev6S_' ] ,
|
||||
[ 'multi-range-user-select.html#prev7S_' , 'multi-range-user-select-ref.html#prev7S_' ] ,
|
||||
// eDirPrevious, Shift+Accel+click
|
||||
[ 'multi-range-user-select.html#prev1SA' , 'multi-range-user-select-ref.html#prev1SA' ] ,
|
||||
[ 'multi-range-user-select.html#prev2SA' , 'multi-range-user-select-ref.html#prev2SA' ] ,
|
||||
[ 'multi-range-user-select.html#prev3SA' , 'multi-range-user-select-ref.html#prev3SA' ] ,
|
||||
[ 'multi-range-user-select.html#prev4SA' , 'multi-range-user-select-ref.html#prev4SA' ] ,
|
||||
[ 'multi-range-user-select.html#prev5SA' , 'multi-range-user-select-ref.html#prev5SA' ] ,
|
||||
[ 'multi-range-user-select.html#prev6SA' , 'multi-range-user-select-ref.html#prev6SA' ] ,
|
||||
[ 'multi-range-user-select.html#prev7SA' , 'multi-range-user-select-ref.html#prev7SA' ] ,
|
||||
// eDirPrevious, Accel+drag-select (adding an additional range)
|
||||
[ 'multi-range-user-select.html#prev1AD' , 'multi-range-user-select-ref.html#prev1AD' ] ,
|
||||
[ 'multi-range-user-select.html#prev7AD' , 'multi-range-user-select-ref.html#prev7AD' ] ,
|
||||
// eDirPrevious, Accel+drag-select (bug 1128722)
|
||||
[ 'multi-range-user-select.html#prev8AD' , 'multi-range-user-select-ref.html#prev8AD' ] ,
|
||||
// eDirPrevious, VK_RIGHT / LEFT
|
||||
[ 'multi-range-user-select.html#prev1SR' , 'multi-range-user-select-ref.html#prev1SR' ] ,
|
||||
[ 'multi-range-user-select.html#prev1SL' , 'multi-range-user-select-ref.html#prev1SL' ] ,
|
||||
// eDirNext, Shift+click
|
||||
[ 'multi-range-user-select.html#next1S_' , 'multi-range-user-select-ref.html#next1S_' ] ,
|
||||
[ 'multi-range-user-select.html#next2S_' , 'multi-range-user-select-ref.html#next2S_' ] ,
|
||||
[ 'multi-range-user-select.html#next3S_' , 'multi-range-user-select-ref.html#next3S_' ] ,
|
||||
[ 'multi-range-user-select.html#next4S_' , 'multi-range-user-select-ref.html#next4S_' ] ,
|
||||
[ 'multi-range-user-select.html#next5S_' , 'multi-range-user-select-ref.html#next5S_' ] ,
|
||||
[ 'multi-range-user-select.html#next6S_' , 'multi-range-user-select-ref.html#next6S_' ] ,
|
||||
[ 'multi-range-user-select.html#next7S_' , 'multi-range-user-select-ref.html#next7S_' ] ,
|
||||
// eDirNext, Shift+Accel+click
|
||||
[ 'multi-range-user-select.html#next1SA' , 'multi-range-user-select-ref.html#next1SA' ] ,
|
||||
[ 'multi-range-user-select.html#next2SA' , 'multi-range-user-select-ref.html#next2SA' ] ,
|
||||
[ 'multi-range-user-select.html#next3SA' , 'multi-range-user-select-ref.html#next3SA' ] ,
|
||||
[ 'multi-range-user-select.html#next4SA' , 'multi-range-user-select-ref.html#next4SA' ] ,
|
||||
[ 'multi-range-user-select.html#next5SA' , 'multi-range-user-select-ref.html#next5SA' ] ,
|
||||
[ 'multi-range-user-select.html#next6SA' , 'multi-range-user-select-ref.html#next6SA' ] ,
|
||||
[ 'multi-range-user-select.html#next7SA' , 'multi-range-user-select-ref.html#next7SA' ] ,
|
||||
// eDirNext, Accel+drag-select (adding an additional range)
|
||||
[ 'multi-range-user-select.html#next1AD' , 'multi-range-user-select-ref.html#next1AD' ] ,
|
||||
[ 'multi-range-user-select.html#next7AD' , 'multi-range-user-select-ref.html#next7AD' ] ,
|
||||
// eDirNext, Accel+drag-select (bug 1128722)
|
||||
[ 'multi-range-user-select.html#next8AD' , 'multi-range-user-select-ref.html#next8AD' ] ,
|
||||
// eDirNext, VK_RIGHT / LEFT
|
||||
[ 'multi-range-user-select.html#next1SR' , 'multi-range-user-select-ref.html#next1SR' ] ,
|
||||
[ 'multi-range-user-select.html#next1SL' , 'multi-range-user-select-ref.html#next1SL' ] ,
|
||||
// eDirPrevious, Shift+click
|
||||
[ 'multi-range-script-select.html#prev1S_' , 'multi-range-script-select-ref.html#prev1S_' ] ,
|
||||
[ 'multi-range-script-select.html#prev2S_' , 'multi-range-script-select-ref.html#prev2S_' ] ,
|
||||
[ 'multi-range-script-select.html#prev3S_' , 'multi-range-script-select-ref.html#prev3S_' ] ,
|
||||
[ 'multi-range-script-select.html#prev4S_' , 'multi-range-script-select-ref.html#prev4S_' ] ,
|
||||
[ 'multi-range-script-select.html#prev5S_' , 'multi-range-script-select-ref.html#prev5S_' ] ,
|
||||
[ 'multi-range-script-select.html#prev6S_' , 'multi-range-script-select-ref.html#prev6S_' ] ,
|
||||
[ 'multi-range-script-select.html#prev7S_' , 'multi-range-script-select-ref.html#prev7S_' ] ,
|
||||
// eDirPrevious, Shift+Accel+click
|
||||
[ 'multi-range-script-select.html#prev1SA' , 'multi-range-script-select-ref.html#prev1SA' ] ,
|
||||
[ 'multi-range-script-select.html#prev2SA' , 'multi-range-script-select-ref.html#prev2SA' ] ,
|
||||
[ 'multi-range-script-select.html#prev3SA' , 'multi-range-script-select-ref.html#prev3SA' ] ,
|
||||
[ 'multi-range-script-select.html#prev4SA' , 'multi-range-script-select-ref.html#prev4SA' ] ,
|
||||
[ 'multi-range-script-select.html#prev5SA' , 'multi-range-script-select-ref.html#prev5SA' ] ,
|
||||
[ 'multi-range-script-select.html#prev6SA' , 'multi-range-script-select-ref.html#prev6SA' ] ,
|
||||
[ 'multi-range-script-select.html#prev7SA' , 'multi-range-script-select-ref.html#prev7SA' ] ,
|
||||
// eDirPrevious, Accel+drag-select (adding an additional range)
|
||||
[ 'multi-range-script-select.html#prev1AD' , 'multi-range-script-select-ref.html#prev1AD' ] ,
|
||||
[ 'multi-range-script-select.html#prev7AD' , 'multi-range-script-select-ref.html#prev7AD' ] ,
|
||||
// eDirPrevious, VK_RIGHT / LEFT
|
||||
[ 'multi-range-script-select.html#prev1SR' , 'multi-range-script-select-ref.html#prev1SR' ] ,
|
||||
[ 'multi-range-script-select.html#prev1SL' , 'multi-range-script-select-ref.html#prev1SL' ] ,
|
||||
// eDirNext, Shift+click
|
||||
[ 'multi-range-script-select.html#next1S_' , 'multi-range-script-select-ref.html#next1S_' ] ,
|
||||
[ 'multi-range-script-select.html#next2S_' , 'multi-range-script-select-ref.html#next2S_' ] ,
|
||||
[ 'multi-range-script-select.html#next3S_' , 'multi-range-script-select-ref.html#next3S_' ] ,
|
||||
[ 'multi-range-script-select.html#next4S_' , 'multi-range-script-select-ref.html#next4S_' ] ,
|
||||
[ 'multi-range-script-select.html#next5S_' , 'multi-range-script-select-ref.html#next5S_' ] ,
|
||||
[ 'multi-range-script-select.html#next6S_' , 'multi-range-script-select-ref.html#next6S_' ] ,
|
||||
[ 'multi-range-script-select.html#next7S_' , 'multi-range-script-select-ref.html#next7S_' ] ,
|
||||
// eDirNext, Shift+Accel+click
|
||||
[ 'multi-range-script-select.html#next1SA' , 'multi-range-script-select-ref.html#next1SA' ] ,
|
||||
[ 'multi-range-script-select.html#next2SA' , 'multi-range-script-select-ref.html#next2SA' ] ,
|
||||
[ 'multi-range-script-select.html#next3SA' , 'multi-range-script-select-ref.html#next3SA' ] ,
|
||||
[ 'multi-range-script-select.html#next4SA' , 'multi-range-script-select-ref.html#next4SA' ] ,
|
||||
[ 'multi-range-script-select.html#next5SA' , 'multi-range-script-select-ref.html#next5SA' ] ,
|
||||
[ 'multi-range-script-select.html#next6SA' , 'multi-range-script-select-ref.html#next6SA' ] ,
|
||||
[ 'multi-range-script-select.html#next7SA' , 'multi-range-script-select-ref.html#next7SA' ] ,
|
||||
// eDirNext, Accel+drag-select (adding an additional range)
|
||||
[ 'multi-range-script-select.html#next1AD' , 'multi-range-script-select-ref.html#next1AD' ] ,
|
||||
[ 'multi-range-script-select.html#next7AD' , 'multi-range-script-select-ref.html#next7AD' ] ,
|
||||
// eDirNext, VK_RIGHT / LEFT
|
||||
[ 'multi-range-script-select.html#next1SR' , 'multi-range-script-select-ref.html#next1SR' ] ,
|
||||
[ 'multi-range-script-select.html#next1SL' , 'multi-range-script-select-ref.html#next1SL' ] ,
|
||||
function() {SpecialPowers.pushPrefEnv({'clear': [['touchcaret.enabled']]}, nextTest);} ,
|
||||
]);
|
||||
}
|
||||
|
||||
var testIndex = 0;
|
||||
|
||||
function nextTest() {
|
||||
|
@ -184,6 +287,11 @@ function nextTest() {
|
|||
}
|
||||
function runTests() {
|
||||
try {
|
||||
if (window.parent) {
|
||||
var parentDoc = window.parent.document;
|
||||
extraCSSRule = parentDoc.styleSheets[parentDoc.styleSheets.length-1]
|
||||
.insertRule("iframe#testframe{width:600px;height:400px}",0);
|
||||
}
|
||||
try {
|
||||
caretBlinkTime = SpecialPowers.getIntPref("ui.caretBlinkTime");
|
||||
} catch (e) {}
|
||||
|
|
|
@ -242,11 +242,7 @@ nsLayoutStatics::Initialize()
|
|||
return rv;
|
||||
}
|
||||
|
||||
rv = nsCSSRuleProcessor::Startup();
|
||||
if (NS_FAILED(rv)) {
|
||||
NS_ERROR("Could not initialize nsCSSRuleProcessor");
|
||||
return rv;
|
||||
}
|
||||
nsCSSRuleProcessor::Startup();
|
||||
|
||||
#ifdef MOZ_XUL
|
||||
rv = nsXULPopupManager::Init();
|
||||
|
|
|
@ -27,6 +27,7 @@ struct SelectionDetails;
|
|||
|
||||
namespace mozilla {
|
||||
class ErrorResult;
|
||||
struct AutoPrepareFocusRange;
|
||||
}
|
||||
|
||||
struct RangeData
|
||||
|
@ -226,7 +227,7 @@ public:
|
|||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
private:
|
||||
|
||||
friend struct mozilla::AutoPrepareFocusRange;
|
||||
class ScrollSelectionIntoViewEvent;
|
||||
friend class ScrollSelectionIntoViewEvent;
|
||||
|
||||
|
|
|
@ -164,14 +164,18 @@ BRFrame::Reflow(nsPresContext* aPresContext,
|
|||
BRFrame::AddInlineMinISize(nsRenderingContext *aRenderingContext,
|
||||
nsIFrame::InlineMinISizeData *aData)
|
||||
{
|
||||
aData->ForceBreak(aRenderingContext);
|
||||
if (!StyleContext()->IsInlineDescendantOfRuby()) {
|
||||
aData->ForceBreak(aRenderingContext);
|
||||
}
|
||||
}
|
||||
|
||||
/* virtual */ void
|
||||
BRFrame::AddInlinePrefISize(nsRenderingContext *aRenderingContext,
|
||||
nsIFrame::InlinePrefISizeData *aData)
|
||||
{
|
||||
aData->ForceBreak(aRenderingContext);
|
||||
if (!StyleContext()->IsInlineDescendantOfRuby()) {
|
||||
aData->ForceBreak(aRenderingContext);
|
||||
}
|
||||
}
|
||||
|
||||
/* virtual */ nscoord
|
||||
|
|
|
@ -3917,6 +3917,7 @@ nsFrame::AddInlineMinISize(nsRenderingContext *aRenderingContext,
|
|||
NS_ASSERTION(GetParent(), "Must have a parent if we get here!");
|
||||
nsIFrame* parent = GetParent();
|
||||
bool canBreak = !CanContinueTextRun() &&
|
||||
!parent->StyleContext()->IsInlineDescendantOfRuby() &&
|
||||
parent->StyleText()->WhiteSpaceCanWrap(parent);
|
||||
|
||||
if (canBreak)
|
||||
|
|
|
@ -642,6 +642,7 @@ private:
|
|||
}
|
||||
|
||||
friend class mozilla::dom::Selection;
|
||||
friend struct mozilla::AutoPrepareFocusRange;
|
||||
#ifdef DEBUG
|
||||
void printSelection(); // for debugging
|
||||
#endif /* DEBUG */
|
||||
|
|
|
@ -200,6 +200,73 @@ RubyColumnEnumerator::GetColumn(RubyColumn& aColumn) const
|
|||
aColumn.mIsIntraLevelWhitespace = mAtIntraLevelWhitespace;
|
||||
}
|
||||
|
||||
static gfxBreakPriority
|
||||
LineBreakBefore(nsIFrame* aFrame,
|
||||
nsRenderingContext* aRenderingContext,
|
||||
nsIFrame* aLineContainerFrame,
|
||||
const nsLineList::iterator* aLine)
|
||||
{
|
||||
for (nsIFrame* child = aFrame; child;
|
||||
child = child->GetFirstPrincipalChild()) {
|
||||
if (!child->CanContinueTextRun()) {
|
||||
// It is not an inline element. We can break before it.
|
||||
return gfxBreakPriority::eNormalBreak;
|
||||
}
|
||||
if (child->GetType() != nsGkAtoms::textFrame) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto textFrame = static_cast<nsTextFrame*>(child);
|
||||
gfxSkipCharsIterator iter =
|
||||
textFrame->EnsureTextRun(nsTextFrame::eInflated,
|
||||
aRenderingContext->ThebesContext(),
|
||||
aLineContainerFrame, aLine);
|
||||
iter.SetOriginalOffset(textFrame->GetContentOffset());
|
||||
uint32_t pos = iter.GetSkippedOffset();
|
||||
gfxTextRun* textRun = textFrame->GetTextRun(nsTextFrame::eInflated);
|
||||
if (pos >= textRun->GetLength()) {
|
||||
// The text frame contains no character at all.
|
||||
return gfxBreakPriority::eNoBreak;
|
||||
}
|
||||
// Return whether we can break before the first character.
|
||||
if (textRun->CanBreakLineBefore(pos)) {
|
||||
return gfxBreakPriority::eNormalBreak;
|
||||
}
|
||||
// Check whether we can wrap word here.
|
||||
const nsStyleText* textStyle = textFrame->StyleText();
|
||||
if (textStyle->WordCanWrap(textFrame) && textRun->IsClusterStart(pos)) {
|
||||
return gfxBreakPriority::eWordWrapBreak;
|
||||
}
|
||||
// We cannot break before.
|
||||
return gfxBreakPriority::eNoBreak;
|
||||
}
|
||||
// Neither block, nor text frame is found as a leaf. We won't break
|
||||
// before this base frame. It is the behavior of empty spans.
|
||||
return gfxBreakPriority::eNoBreak;
|
||||
}
|
||||
|
||||
static void
|
||||
GetIsLineBreakAllowed(nsIFrame* aFrame, bool aIsLineBreakable,
|
||||
bool* aAllowInitialLineBreak, bool* aAllowLineBreak)
|
||||
{
|
||||
nsIFrame* parent = aFrame->GetParent();
|
||||
bool inNestedRuby = parent->StyleContext()->IsInlineDescendantOfRuby();
|
||||
// Allow line break between ruby bases when white-space allows,
|
||||
// we are not inside a nested ruby, and there is no span.
|
||||
bool allowLineBreak = !inNestedRuby &&
|
||||
aFrame->StyleText()->WhiteSpaceCanWrap(aFrame);
|
||||
bool allowInitialLineBreak = allowLineBreak;
|
||||
if (!aFrame->GetPrevInFlow()) {
|
||||
allowInitialLineBreak = !inNestedRuby &&
|
||||
parent->StyleText()->WhiteSpaceCanWrap(parent);
|
||||
}
|
||||
if (!aIsLineBreakable) {
|
||||
allowInitialLineBreak = false;
|
||||
}
|
||||
*aAllowInitialLineBreak = allowInitialLineBreak;
|
||||
*aAllowLineBreak = allowLineBreak;
|
||||
}
|
||||
|
||||
static nscoord
|
||||
CalculateColumnPrefISize(nsRenderingContext* aRenderingContext,
|
||||
const RubyColumnEnumerator& aEnumerator)
|
||||
|
@ -209,15 +276,21 @@ CalculateColumnPrefISize(nsRenderingContext* aRenderingContext,
|
|||
for (uint32_t i = 0; i < levelCount; i++) {
|
||||
nsIFrame* frame = aEnumerator.GetFrameAtLevel(i);
|
||||
if (frame) {
|
||||
max = std::max(max, frame->GetPrefISize(aRenderingContext));
|
||||
nsIFrame::InlinePrefISizeData data;
|
||||
frame->AddInlinePrefISize(aRenderingContext, &data);
|
||||
MOZ_ASSERT(data.prevLines == 0, "Shouldn't have prev lines");
|
||||
max = std::max(max, data.currentLine);
|
||||
}
|
||||
}
|
||||
return max;
|
||||
}
|
||||
|
||||
// FIXME Currently we use pref isize of ruby content frames for
|
||||
// computing min isize of ruby frame, which may cause problem.
|
||||
// See bug 1134945.
|
||||
/* virtual */ void
|
||||
nsRubyBaseContainerFrame::AddInlineMinISize(
|
||||
nsRenderingContext *aRenderingContext, nsIFrame::InlineMinISizeData *aData)
|
||||
nsRenderingContext *aRenderingContext, nsIFrame::InlineMinISizeData *aData)
|
||||
{
|
||||
AutoTextContainerArray textContainers;
|
||||
GetTextContainers(textContainers);
|
||||
|
@ -226,38 +299,66 @@ nsRubyBaseContainerFrame::AddInlineMinISize(
|
|||
if (textContainers[i]->IsSpanContainer()) {
|
||||
// Since spans are not breakable internally, use our pref isize
|
||||
// directly if there is any span.
|
||||
aData->currentLine += GetPrefISize(aRenderingContext);
|
||||
nsIFrame::InlinePrefISizeData data;
|
||||
AddInlinePrefISize(aRenderingContext, &data);
|
||||
aData->currentLine += data.currentLine;
|
||||
if (data.currentLine > 0) {
|
||||
aData->atStartOfLine = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
nscoord max = 0;
|
||||
RubyColumnEnumerator enumerator(this, textContainers);
|
||||
for (; !enumerator.AtEnd(); enumerator.Next()) {
|
||||
// We use *pref* isize for computing the min isize of columns
|
||||
// because ruby bases and texts are unbreakable internally.
|
||||
max = std::max(max, CalculateColumnPrefISize(aRenderingContext,
|
||||
enumerator));
|
||||
bool firstFrame = true;
|
||||
bool allowInitialLineBreak, allowLineBreak;
|
||||
GetIsLineBreakAllowed(this, !aData->atStartOfLine,
|
||||
&allowInitialLineBreak, &allowLineBreak);
|
||||
for (nsIFrame* frame = this; frame; frame = frame->GetNextInFlow()) {
|
||||
RubyColumnEnumerator enumerator(
|
||||
static_cast<nsRubyBaseContainerFrame*>(frame), textContainers);
|
||||
for (; !enumerator.AtEnd(); enumerator.Next()) {
|
||||
if (firstFrame ? allowInitialLineBreak : allowLineBreak) {
|
||||
nsIFrame* baseFrame = enumerator.GetFrameAtLevel(0);
|
||||
if (baseFrame) {
|
||||
gfxBreakPriority breakPriority =
|
||||
LineBreakBefore(baseFrame, aRenderingContext, nullptr, nullptr);
|
||||
if (breakPriority != gfxBreakPriority::eNoBreak) {
|
||||
aData->OptionallyBreak(aRenderingContext);
|
||||
}
|
||||
}
|
||||
}
|
||||
firstFrame = false;
|
||||
nscoord isize = CalculateColumnPrefISize(aRenderingContext, enumerator);
|
||||
aData->currentLine += isize;
|
||||
if (isize > 0) {
|
||||
aData->atStartOfLine = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
aData->currentLine += max;
|
||||
}
|
||||
|
||||
/* virtual */ void
|
||||
nsRubyBaseContainerFrame::AddInlinePrefISize(
|
||||
nsRenderingContext *aRenderingContext, nsIFrame::InlinePrefISizeData *aData)
|
||||
nsRenderingContext *aRenderingContext, nsIFrame::InlinePrefISizeData *aData)
|
||||
{
|
||||
AutoTextContainerArray textContainers;
|
||||
GetTextContainers(textContainers);
|
||||
|
||||
nscoord sum = 0;
|
||||
RubyColumnEnumerator enumerator(this, textContainers);
|
||||
for (; !enumerator.AtEnd(); enumerator.Next()) {
|
||||
sum += CalculateColumnPrefISize(aRenderingContext, enumerator);
|
||||
for (nsIFrame* frame = this; frame; frame = frame->GetNextInFlow()) {
|
||||
RubyColumnEnumerator enumerator(
|
||||
static_cast<nsRubyBaseContainerFrame*>(frame), textContainers);
|
||||
for (; !enumerator.AtEnd(); enumerator.Next()) {
|
||||
sum += CalculateColumnPrefISize(aRenderingContext, enumerator);
|
||||
}
|
||||
}
|
||||
for (uint32_t i = 0, iend = textContainers.Length(); i < iend; i++) {
|
||||
if (textContainers[i]->IsSpanContainer()) {
|
||||
nsIFrame* frame = textContainers[i]->GetFirstPrincipalChild();
|
||||
sum = std::max(sum, frame->GetPrefISize(aRenderingContext));
|
||||
nsIFrame::InlinePrefISizeData data;
|
||||
frame->AddInlinePrefISize(aRenderingContext, &data);
|
||||
MOZ_ASSERT(data.prevLines == 0, "Shouldn't have prev lines");
|
||||
sum = std::max(sum, data.currentLine);
|
||||
}
|
||||
}
|
||||
aData->currentLine += sum;
|
||||
|
@ -399,19 +500,9 @@ nsRubyBaseContainerFrame::Reflow(nsPresContext* aPresContext,
|
|||
0, aReflowState.AvailableISize(),
|
||||
&mBaseline);
|
||||
|
||||
nsIFrame* parent = GetParent();
|
||||
bool inNestedRuby = parent->StyleContext()->IsInlineDescendantOfRuby();
|
||||
// Allow line break between ruby bases when white-space allows,
|
||||
// we are not inside a nested ruby, and there is no span.
|
||||
bool allowLineBreak = !inNestedRuby && StyleText()->WhiteSpaceCanWrap(this);
|
||||
bool allowInitialLineBreak = allowLineBreak;
|
||||
if (!GetPrevInFlow()) {
|
||||
allowInitialLineBreak = !inNestedRuby &&
|
||||
parent->StyleText()->WhiteSpaceCanWrap(parent);
|
||||
}
|
||||
if (!aReflowState.mLineLayout->LineIsBreakable()) {
|
||||
allowInitialLineBreak = false;
|
||||
}
|
||||
bool allowInitialLineBreak, allowLineBreak;
|
||||
GetIsLineBreakAllowed(this, aReflowState.mLineLayout->LineIsBreakable(),
|
||||
&allowInitialLineBreak, &allowLineBreak);
|
||||
|
||||
nscoord isize = 0;
|
||||
// Reflow columns excluding any span
|
||||
|
@ -601,49 +692,6 @@ nsRubyBaseContainerFrame::ReflowColumns(const ReflowState& aReflowState,
|
|||
return icoord;
|
||||
}
|
||||
|
||||
static gfxBreakPriority
|
||||
LineBreakBefore(const nsHTMLReflowState& aReflowState, nsRubyBaseFrame* aFrame)
|
||||
{
|
||||
for (nsIFrame* child = aFrame; child;
|
||||
child = child->GetFirstPrincipalChild()) {
|
||||
if (!child->CanContinueTextRun()) {
|
||||
// It is not an inline element. We can break before it.
|
||||
return gfxBreakPriority::eNormalBreak;
|
||||
}
|
||||
if (child->GetType() != nsGkAtoms::textFrame) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto textFrame = static_cast<nsTextFrame*>(child);
|
||||
gfxSkipCharsIterator iter =
|
||||
textFrame->EnsureTextRun(nsTextFrame::eInflated,
|
||||
aReflowState.rendContext->ThebesContext(),
|
||||
aReflowState.mLineLayout->LineContainerFrame(),
|
||||
aReflowState.mLineLayout->GetLine());
|
||||
iter.SetOriginalOffset(textFrame->GetContentOffset());
|
||||
uint32_t pos = iter.GetSkippedOffset();
|
||||
gfxTextRun* textRun = textFrame->GetTextRun(nsTextFrame::eInflated);
|
||||
if (pos >= textRun->GetLength()) {
|
||||
// The text frame contains no character at all.
|
||||
return gfxBreakPriority::eNoBreak;
|
||||
}
|
||||
// Return whether we can break before the first character.
|
||||
if (textRun->CanBreakLineBefore(pos)) {
|
||||
return gfxBreakPriority::eNormalBreak;
|
||||
}
|
||||
// Check whether we can wrap word here.
|
||||
const nsStyleText* textStyle = textFrame->StyleText();
|
||||
if (textStyle->WordCanWrap(textFrame) && textRun->IsClusterStart(pos)) {
|
||||
return gfxBreakPriority::eWordWrapBreak;
|
||||
}
|
||||
// We cannot break before.
|
||||
return gfxBreakPriority::eNoBreak;
|
||||
}
|
||||
// Neither block, nor text frame is found as a leaf. We won't break
|
||||
// before this base frame. It is the behavior of empty spans.
|
||||
return gfxBreakPriority::eNoBreak;
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsRubyBaseContainerFrame::ReflowOneColumn(const ReflowState& aReflowState,
|
||||
uint32_t aColumnIndex,
|
||||
|
@ -730,8 +778,10 @@ nsRubyBaseContainerFrame::ReflowOneColumn(const ReflowState& aReflowState,
|
|||
aReflowState.mAllowLineBreak : aReflowState.mAllowInitialLineBreak;
|
||||
if (allowBreakBefore) {
|
||||
bool shouldBreakBefore = false;
|
||||
gfxBreakPriority breakPriority =
|
||||
LineBreakBefore(baseReflowState, aColumn.mBaseFrame);
|
||||
gfxBreakPriority breakPriority = LineBreakBefore(
|
||||
aColumn.mBaseFrame, baseReflowState.rendContext,
|
||||
baseReflowState.mLineLayout->LineContainerFrame(),
|
||||
baseReflowState.mLineLayout->GetLine());
|
||||
if (breakPriority != gfxBreakPriority::eNoBreak) {
|
||||
int32_t offset;
|
||||
gfxBreakPriority lastBreakPriority;
|
||||
|
|
|
@ -106,22 +106,24 @@ SegmentEnumerator::Next()
|
|||
nsRubyFrame::AddInlineMinISize(nsRenderingContext *aRenderingContext,
|
||||
nsIFrame::InlineMinISizeData *aData)
|
||||
{
|
||||
nscoord max = 0;
|
||||
for (SegmentEnumerator e(this); !e.AtEnd(); e.Next()) {
|
||||
max = std::max(max, e.GetBaseContainer()->GetMinISize(aRenderingContext));
|
||||
for (nsIFrame* frame = this; frame; frame = frame->GetNextInFlow()) {
|
||||
for (SegmentEnumerator e(static_cast<nsRubyFrame*>(frame));
|
||||
!e.AtEnd(); e.Next()) {
|
||||
e.GetBaseContainer()->AddInlineMinISize(aRenderingContext, aData);
|
||||
}
|
||||
}
|
||||
aData->currentLine += max;
|
||||
}
|
||||
|
||||
/* virtual */ void
|
||||
nsRubyFrame::AddInlinePrefISize(nsRenderingContext *aRenderingContext,
|
||||
nsIFrame::InlinePrefISizeData *aData)
|
||||
{
|
||||
nscoord sum = 0;
|
||||
for (SegmentEnumerator e(this); !e.AtEnd(); e.Next()) {
|
||||
sum += e.GetBaseContainer()->GetPrefISize(aRenderingContext);
|
||||
for (nsIFrame* frame = this; frame; frame = frame->GetNextInFlow()) {
|
||||
for (SegmentEnumerator e(static_cast<nsRubyFrame*>(frame));
|
||||
!e.AtEnd(); e.Next()) {
|
||||
e.GetBaseContainer()->AddInlinePrefISize(aRenderingContext, aData);
|
||||
}
|
||||
}
|
||||
aData->currentLine += sum;
|
||||
}
|
||||
|
||||
/* virtual */ void
|
||||
|
|
|
@ -326,6 +326,101 @@ IsValidSelectionPoint(nsFrameSelection *aFrameSel, nsINode *aNode)
|
|||
return !limiter || nsContentUtils::ContentIsDescendantOf(aNode, limiter);
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
struct MOZ_STACK_CLASS AutoPrepareFocusRange
|
||||
{
|
||||
AutoPrepareFocusRange(Selection* aSelection,
|
||||
bool aContinueSelection,
|
||||
bool aMultipleSelection
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
|
||||
{
|
||||
MOZ_GUARD_OBJECT_NOTIFIER_INIT;
|
||||
|
||||
if (aSelection->mRanges.Length() <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (aSelection->mFrameSelection->IsUserSelectionReason()) {
|
||||
mUserSelect.emplace(aSelection);
|
||||
}
|
||||
bool userSelection = aSelection->mApplyUserSelectStyle;
|
||||
|
||||
nsTArray<RangeData>& ranges = aSelection->mRanges;
|
||||
if (!userSelection ||
|
||||
(!aContinueSelection && aMultipleSelection)) {
|
||||
// Scripted command or the user is starting a new explicit multi-range
|
||||
// selection.
|
||||
for (RangeData& entry : ranges) {
|
||||
entry.mRange->SetIsGenerated(false);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
int16_t reason = aSelection->mFrameSelection->mSelectionChangeReason;
|
||||
bool isAnchorRelativeOp = (reason & (nsISelectionListener::DRAG_REASON |
|
||||
nsISelectionListener::MOUSEDOWN_REASON |
|
||||
nsISelectionListener::MOUSEUP_REASON |
|
||||
nsISelectionListener::COLLAPSETOSTART_REASON));
|
||||
if (!isAnchorRelativeOp) {
|
||||
return;
|
||||
}
|
||||
|
||||
// This operation is against the anchor but our current mAnchorFocusRange
|
||||
// represents the focus in a multi-range selection. The anchor from a user
|
||||
// perspective is the most distant generated range on the opposite side.
|
||||
// Find that range and make it the mAnchorFocusRange.
|
||||
const size_t len = ranges.Length();
|
||||
size_t newAnchorFocusIndex = size_t(-1);
|
||||
if (aSelection->GetDirection() == eDirNext) {
|
||||
for (size_t i = 0; i < len; ++i) {
|
||||
if (ranges[i].mRange->IsGenerated()) {
|
||||
newAnchorFocusIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
size_t i = len;
|
||||
while (i--) {
|
||||
if (ranges[i].mRange->IsGenerated()) {
|
||||
newAnchorFocusIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newAnchorFocusIndex == size_t(-1)) {
|
||||
// There are no generated ranges - that's fine.
|
||||
return;
|
||||
}
|
||||
|
||||
// Setup the new mAnchorFocusRange and mark the old one as generated.
|
||||
if (aSelection->mAnchorFocusRange) {
|
||||
aSelection->mAnchorFocusRange->SetIsGenerated(true);
|
||||
}
|
||||
nsRange* range = ranges[newAnchorFocusIndex].mRange;
|
||||
range->SetIsGenerated(false);
|
||||
aSelection->mAnchorFocusRange = range;
|
||||
|
||||
// Remove all generated ranges (including the old mAnchorFocusRange).
|
||||
nsRefPtr<nsPresContext> presContext = aSelection->GetPresContext();
|
||||
size_t i = len;
|
||||
while (i--) {
|
||||
range = aSelection->mRanges[i].mRange;
|
||||
if (range->IsGenerated()) {
|
||||
range->SetInSelection(false);
|
||||
aSelection->selectFrames(presContext, range, false);
|
||||
aSelection->mRanges.RemoveElementAt(i);
|
||||
}
|
||||
}
|
||||
if (aSelection->mFrameSelection) {
|
||||
aSelection->mFrameSelection->InvalidateDesiredPos();
|
||||
}
|
||||
}
|
||||
|
||||
Maybe<Selection::AutoApplyUserSelectStyle> mUserSelect;
|
||||
MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
|
||||
};
|
||||
}
|
||||
|
||||
////////////BEGIN nsFrameSelection methods
|
||||
|
||||
|
@ -774,13 +869,6 @@ nsFrameSelection::MoveCaret(nsDirection aDirection,
|
|||
if (NS_FAILED(result)) {
|
||||
return result;
|
||||
}
|
||||
if (aAmount == eSelectLine) {
|
||||
result = FetchDesiredPos(desiredPos);
|
||||
if (NS_FAILED(result)) {
|
||||
return result;
|
||||
}
|
||||
SetDesiredPos(desiredPos);
|
||||
}
|
||||
|
||||
int32_t caretStyle = Preferences::GetInt("layout.selection.caret_style", 0);
|
||||
if (caretStyle == 0
|
||||
|
@ -792,39 +880,48 @@ nsFrameSelection::MoveCaret(nsDirection aDirection,
|
|||
caretStyle = 2;
|
||||
}
|
||||
|
||||
if (!isCollapsed && !aContinueSelection && caretStyle == 2 &&
|
||||
aAmount <= eSelectLine) {
|
||||
switch (aDirection) {
|
||||
case eDirPrevious:
|
||||
{
|
||||
const nsRange* anchorFocusRange = sel->GetAnchorFocusRange();
|
||||
if (anchorFocusRange) {
|
||||
PostReason(nsISelectionListener::COLLAPSETOSTART_REASON);
|
||||
sel->Collapse(anchorFocusRange->GetStartParent(),
|
||||
anchorFocusRange->StartOffset());
|
||||
}
|
||||
mHint = CARET_ASSOCIATE_AFTER;
|
||||
sel->ScrollIntoView(nsISelectionController::SELECTION_FOCUS_REGION,
|
||||
nsIPresShell::ScrollAxis(),
|
||||
nsIPresShell::ScrollAxis(), scrollFlags);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
case eDirNext:
|
||||
{
|
||||
const nsRange* anchorFocusRange = sel->GetAnchorFocusRange();
|
||||
if (anchorFocusRange) {
|
||||
PostReason(nsISelectionListener::COLLAPSETOEND_REASON);
|
||||
sel->Collapse(anchorFocusRange->GetEndParent(),
|
||||
anchorFocusRange->EndOffset());
|
||||
}
|
||||
mHint = CARET_ASSOCIATE_BEFORE;
|
||||
sel->ScrollIntoView(nsISelectionController::SELECTION_FOCUS_REGION,
|
||||
nsIPresShell::ScrollAxis(),
|
||||
nsIPresShell::ScrollAxis(), scrollFlags);
|
||||
return NS_OK;
|
||||
}
|
||||
bool doCollapse = !isCollapsed && !aContinueSelection && caretStyle == 2 &&
|
||||
aAmount <= eSelectLine;
|
||||
if (doCollapse) {
|
||||
if (aDirection == eDirPrevious) {
|
||||
PostReason(nsISelectionListener::COLLAPSETOSTART_REASON);
|
||||
mHint = CARET_ASSOCIATE_AFTER;
|
||||
} else {
|
||||
PostReason(nsISelectionListener::COLLAPSETOEND_REASON);
|
||||
mHint = CARET_ASSOCIATE_BEFORE;
|
||||
}
|
||||
} else {
|
||||
PostReason(nsISelectionListener::KEYPRESS_REASON);
|
||||
}
|
||||
|
||||
AutoPrepareFocusRange prep(sel, aContinueSelection, false);
|
||||
|
||||
if (aAmount == eSelectLine) {
|
||||
result = FetchDesiredPos(desiredPos);
|
||||
if (NS_FAILED(result)) {
|
||||
return result;
|
||||
}
|
||||
SetDesiredPos(desiredPos);
|
||||
}
|
||||
|
||||
if (doCollapse) {
|
||||
const nsRange* anchorFocusRange = sel->GetAnchorFocusRange();
|
||||
if (anchorFocusRange) {
|
||||
nsINode* node;
|
||||
int32_t offset;
|
||||
if (aDirection == eDirPrevious) {
|
||||
node = anchorFocusRange->GetStartParent();
|
||||
offset = anchorFocusRange->StartOffset();
|
||||
} else {
|
||||
node = anchorFocusRange->GetEndParent();
|
||||
offset = anchorFocusRange->EndOffset();
|
||||
}
|
||||
sel->Collapse(node, offset);
|
||||
}
|
||||
sel->ScrollIntoView(nsISelectionController::SELECTION_FOCUS_REGION,
|
||||
nsIPresShell::ScrollAxis(),
|
||||
nsIPresShell::ScrollAxis(), scrollFlags);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsIFrame *frame;
|
||||
|
@ -868,7 +965,7 @@ nsFrameSelection::MoveCaret(nsDirection aDirection,
|
|||
default:
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
PostReason(nsISelectionListener::KEYPRESS_REASON);
|
||||
|
||||
if (NS_SUCCEEDED(result = frame->PeekOffset(&pos)) && pos.mResultContent)
|
||||
{
|
||||
nsIFrame *theFrame;
|
||||
|
@ -1376,6 +1473,8 @@ nsFrameSelection::HandleClick(nsIContent* aNewFocus,
|
|||
AdjustForMaintainedSelection(aNewFocus, aContentOffset))
|
||||
return NS_OK; //shift clicked to maintained selection. rejected.
|
||||
|
||||
int8_t index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
|
||||
AutoPrepareFocusRange prep(mDomSelections[index], aContinueSelection, aMultipleSelection);
|
||||
return TakeFocus(aNewFocus, aContentOffset, aContentEndOffset, aHint,
|
||||
aContinueSelection, aMultipleSelection);
|
||||
}
|
||||
|
@ -2050,6 +2149,8 @@ nsFrameSelection::SelectAll()
|
|||
}
|
||||
int32_t numChildren = rootContent->GetChildCount();
|
||||
PostReason(nsISelectionListener::NO_REASON);
|
||||
int8_t index = GetIndexFromSelectionType(nsISelectionController::SELECTION_NORMAL);
|
||||
AutoPrepareFocusRange prep(mDomSelections[index], false, false);
|
||||
return TakeFocus(rootContent, 0, numChildren, CARET_ASSOCIATE_BEFORE, false, false);
|
||||
}
|
||||
|
||||
|
@ -3512,9 +3613,19 @@ Selection::AddItem(nsRange* aItem, int32_t* aOutIndex)
|
|||
rangesToAdd.AppendElement(aItem);
|
||||
}
|
||||
}
|
||||
*aOutIndex = -1;
|
||||
size_t newAnchorFocusIndex =
|
||||
GetDirection() == eDirPrevious ? 0 : rangesToAdd.Length() - 1;
|
||||
for (size_t i = 0; i < rangesToAdd.Length(); ++i) {
|
||||
nsresult rv = AddItemInternal(rangesToAdd[i], aOutIndex);
|
||||
int32_t index;
|
||||
nsresult rv = AddItemInternal(rangesToAdd[i], &index);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
if (i == newAnchorFocusIndex) {
|
||||
*aOutIndex = index;
|
||||
rangesToAdd[i]->SetIsGenerated(false);
|
||||
} else {
|
||||
rangesToAdd[i]->SetIsGenerated(true);
|
||||
}
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
@ -5000,49 +5111,9 @@ Selection::Extend(nsINode& aParentNode, uint32_t aOffset, ErrorResult& aRv)
|
|||
return;
|
||||
}
|
||||
|
||||
nsDirection dir = GetDirection();
|
||||
|
||||
// If aParentNode is inside a range in a multi-range selection we need
|
||||
// to remove the ranges that follows in the selection direction and
|
||||
// make that range the mAnchorFocusRange.
|
||||
if (mRanges.Length() > 1) {
|
||||
for (size_t i = 0; i < mRanges.Length(); ++i) {
|
||||
nsRange* range = mRanges[i].mRange;
|
||||
bool disconnected1 = false;
|
||||
bool disconnected2 = false;
|
||||
const bool isBeforeStart =
|
||||
nsContentUtils::ComparePoints(range->GetStartParent(),
|
||||
range->StartOffset(),
|
||||
&aParentNode, aOffset,
|
||||
&disconnected1) > 0;
|
||||
const bool isAfterEnd =
|
||||
nsContentUtils::ComparePoints(range->GetEndParent(),
|
||||
range->EndOffset(),
|
||||
&aParentNode, aOffset,
|
||||
&disconnected2) < 0;
|
||||
if (!isBeforeStart && !isAfterEnd && !disconnected1 && !disconnected2) {
|
||||
// aParentNode/aOffset is inside 'range'.
|
||||
mAnchorFocusRange = range;
|
||||
if (dir == eDirNext) {
|
||||
for (size_t j = i + 1; j < mRanges.Length(); ++j) {
|
||||
nsRange* r = mRanges[j].mRange;
|
||||
r->SetInSelection(false);
|
||||
selectFrames(presContext, r, false);
|
||||
}
|
||||
mRanges.TruncateLength(i + 1);
|
||||
} else {
|
||||
for (size_t j = 0; j < i; ++j) {
|
||||
nsRange* r = mRanges[j].mRange;
|
||||
r->SetInSelection(false);
|
||||
selectFrames(presContext, r, false);
|
||||
}
|
||||
mRanges.RemoveElementsAt(0, i);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DEBUG_SELECTION
|
||||
nsDirection oldDirection = GetDirection();
|
||||
#endif
|
||||
nsINode* anchorNode = GetAnchorNode();
|
||||
nsINode* focusNode = GetFocusNode();
|
||||
uint32_t anchorOffset = AnchorOffset();
|
||||
|
@ -5094,7 +5165,7 @@ Selection::Extend(nsINode& aParentNode, uint32_t aOffset, ErrorResult& aRv)
|
|||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
dir = eDirNext;
|
||||
SetDirection(eDirNext);
|
||||
res = difRange->SetEnd(range->GetEndParent(), range->EndOffset());
|
||||
nsresult tmp = difRange->SetStart(focusNode, focusOffset);
|
||||
if (NS_FAILED(tmp)) {
|
||||
|
@ -5113,7 +5184,7 @@ Selection::Extend(nsINode& aParentNode, uint32_t aOffset, ErrorResult& aRv)
|
|||
}
|
||||
else if (result1 == 0 && result3 > 0){//2, a1
|
||||
//select from 2 to 1a
|
||||
dir = eDirPrevious;
|
||||
SetDirection(eDirPrevious);
|
||||
range->SetStart(aParentNode, aOffset, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
|
@ -5158,7 +5229,7 @@ Selection::Extend(nsINode& aParentNode, uint32_t aOffset, ErrorResult& aRv)
|
|||
return;
|
||||
}
|
||||
}
|
||||
dir = eDirNext;
|
||||
SetDirection(eDirNext);
|
||||
range->SetEnd(aParentNode, aOffset, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
|
@ -5203,7 +5274,7 @@ Selection::Extend(nsINode& aParentNode, uint32_t aOffset, ErrorResult& aRv)
|
|||
aRv.Throw(res);
|
||||
return;
|
||||
}
|
||||
dir = eDirPrevious;
|
||||
SetDirection(eDirPrevious);
|
||||
range->SetStart(aParentNode, aOffset, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
|
@ -5222,7 +5293,7 @@ Selection::Extend(nsINode& aParentNode, uint32_t aOffset, ErrorResult& aRv)
|
|||
if (GetDirection() == eDirNext){
|
||||
range->SetEnd(startNode, startOffset);
|
||||
}
|
||||
dir = eDirPrevious;
|
||||
SetDirection(eDirPrevious);
|
||||
range->SetStart(aParentNode, aOffset, aRv);
|
||||
if (aRv.Failed()) {
|
||||
return;
|
||||
|
@ -5261,7 +5332,7 @@ Selection::Extend(nsINode& aParentNode, uint32_t aOffset, ErrorResult& aRv)
|
|||
if (aRv.Failed()) {
|
||||
return;
|
||||
}
|
||||
dir = eDirPrevious;
|
||||
SetDirection(eDirPrevious);
|
||||
res = difRange->SetEnd(focusNode, focusOffset);
|
||||
nsresult tmp = difRange->SetStart(range->GetStartParent(), range->StartOffset());
|
||||
if (NS_FAILED(tmp)) {
|
||||
|
@ -5290,15 +5361,11 @@ Selection::Extend(nsINode& aParentNode, uint32_t aOffset, ErrorResult& aRv)
|
|||
|
||||
DEBUG_OUT_RANGE(range);
|
||||
#ifdef DEBUG_SELECTION
|
||||
if (eDirNext == mDirection)
|
||||
printf(" direction = 1 LEFT TO RIGHT\n");
|
||||
else
|
||||
printf(" direction = 0 RIGHT TO LEFT\n");
|
||||
#endif
|
||||
SetDirection(dir);
|
||||
#ifdef DEBUG_SELECTION
|
||||
if (GetDirection() != oldDirection) {
|
||||
printf(" direction changed to %s\n",
|
||||
GetDirection() == eDirNext? "eDirNext":"eDirPrevious");
|
||||
}
|
||||
nsCOMPtr<nsIContent> content = do_QueryInterface(&aParentNode);
|
||||
|
||||
printf ("Sel. Extend to %p %s %d\n", content.get(),
|
||||
nsAtomCString(content->Tag()).get(), aOffset);
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,49 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="ja">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Bug 1134432 - Intrinsic ISize calculation of ruby</title>
|
||||
<style>
|
||||
div {
|
||||
display: inline-block;
|
||||
border: 1px solid black;
|
||||
}
|
||||
span {
|
||||
white-space: nowrap;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width: -moz-min-content">
|
||||
<span>ABC</span><span>DEF</span>
|
||||
</div>
|
||||
<div style="width: -moz-max-content">
|
||||
<span>ABC</span><span>DEF</span>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div style="width: -moz-min-content">
|
||||
XYZ<span>ABC</span><span>DEF</span>XYZ
|
||||
</div>
|
||||
<div style="width: -moz-max-content">
|
||||
XYZ<span>ABC</span><span>DEF</span>XYZ
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div style="width: -moz-min-content">
|
||||
<span>あい</span><span>うえ</span>
|
||||
</div>
|
||||
<div style="width: -moz-max-content">
|
||||
<span>あい</span><span>うえ</span>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div style="width: -moz-min-content">
|
||||
お<span>あい</span><span>うえ</span>お
|
||||
</div>
|
||||
<div style="width: -moz-max-content">
|
||||
お<span>あい</span><span>うえ</span>お
|
||||
</div>
|
||||
<br>
|
||||
</body>
|
||||
</html>
|
|
@ -0,0 +1,46 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="ja">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Bug 1134432 - Intrinsic ISize calculation of ruby</title>
|
||||
<style>
|
||||
div {
|
||||
display: inline-block;
|
||||
border: 1px solid black;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div style="width: -moz-min-content">
|
||||
<ruby><rb>ABC<rb>DEF</ruby>
|
||||
</div>
|
||||
<div style="width: -moz-max-content">
|
||||
<ruby><rb>ABC<rb>DEF</ruby>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div style="width: -moz-min-content">
|
||||
XYZ<ruby><rb>ABC<rb>DEF</ruby>XYZ
|
||||
</div>
|
||||
<div style="width: -moz-max-content">
|
||||
XYZ<ruby><rb>ABC<rb>DEF</ruby>XYZ
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div style="width: -moz-min-content">
|
||||
<ruby><rb>あい<rb>うえ</ruby>
|
||||
</div>
|
||||
<div style="width: -moz-max-content">
|
||||
<ruby><rb>あい<rb>うえ</ruby>
|
||||
</div>
|
||||
<br>
|
||||
|
||||
<div style="width: -moz-min-content">
|
||||
お<ruby><rb>あい<rb>うえ</ruby>お
|
||||
</div>
|
||||
<div style="width: -moz-max-content">
|
||||
お<ruby><rb>あい<rb>うえ</ruby>お
|
||||
</div>
|
||||
<br>
|
||||
</body>
|
||||
</html>
|
|
@ -19,6 +19,7 @@ default-preferences pref(layout.css.ruby.enabled,true)
|
|||
== intra-level-whitespace-1.html intra-level-whitespace-1-ref.html
|
||||
== intra-level-whitespace-2.html intra-level-whitespace-2-ref.html
|
||||
== intra-level-whitespace-3.html intra-level-whitespace-3-ref.html
|
||||
== intrinsic-isize-1.html intrinsic-isize-1-ref.html
|
||||
== justification-1.html justification-1-ref.html
|
||||
== justification-2.html justification-2-ref.html
|
||||
== line-breaking-1.html line-breaking-1-ref.html
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<meta charset="UTF-8">
|
||||
<title>CSS Test: Autohide ruby annotations which are identical to their bases</title>
|
||||
<link rel="author" title="Xidorn Quan" href="mailto:quanxunzhen@gmail.com">
|
||||
<link rel="help" href="http://dev.w3.org/csswg/css-ruby/#autohide">
|
||||
<link rel="help" href="http://dev.w3.org/csswg/css-ruby-1/#autohide">
|
||||
<link rel="match" href="ruby-autohide-001-ref.html">
|
||||
</head>
|
||||
<body>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<meta charset="UTF-8">
|
||||
<title>CSS Test: Autohide ruby annotations which are identical to their bases</title>
|
||||
<link rel="author" title="Xidorn Quan" href="mailto:quanxunzhen@gmail.com">
|
||||
<link rel="help" href="http://dev.w3.org/csswg/css-ruby/#autohide">
|
||||
<link rel="help" href="http://dev.w3.org/csswg/css-ruby-1/#autohide">
|
||||
<link rel="match" href="ruby-autohide-002-ref.html">
|
||||
<script>
|
||||
window.onload = function() {
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<meta charset="UTF-8">
|
||||
<title>CSS Test: Autohide ruby annotations which are identical to their bases</title>
|
||||
<link rel="author" title="Xidorn Quan" href="mailto:quanxunzhen@gmail.com">
|
||||
<link rel="help" href="http://dev.w3.org/csswg/css-ruby/#autohide">
|
||||
<link rel="help" href="http://dev.w3.org/csswg/css-ruby-1/#autohide">
|
||||
<link rel="match" href="ruby-autohide-003-ref.html">
|
||||
<style>
|
||||
body { line-height: 5em; }
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<meta charset="UTF-8">
|
||||
<title>CSS Test: Inlinize block-level boxes inside ruby</title>
|
||||
<link rel="author" title="Xidorn Quan" href="mailto:quanxunzhen@gmail.com">
|
||||
<link rel="help" href="http://dev.w3.org/csswg/css-ruby/#anon-gen-inlinize">
|
||||
<link rel="help" href="http://dev.w3.org/csswg/css-ruby-1/#anon-gen-inlinize">
|
||||
<link rel="match" href="ruby-inlinize-blocks-001-ref.html">
|
||||
<link rel="stylesheet" href="support/rbc.css">
|
||||
<style>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<meta charset="UTF-8">
|
||||
<title>CSS Test: Inlinize block-level boxes inside ruby</title>
|
||||
<link rel="author" title="Xidorn Quan" href="mailto:quanxunzhen@gmail.com">
|
||||
<link rel="help" href="http://dev.w3.org/csswg/css-ruby/#anon-gen-inlinize">
|
||||
<link rel="help" href="http://dev.w3.org/csswg/css-ruby-1/#anon-gen-inlinize">
|
||||
<link rel="match" href="ruby-inlinize-blocks-002-ref.html">
|
||||
<link rel="stylesheet" href="common.css">
|
||||
<style>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<meta charset="UTF-8">
|
||||
<title>CSS Test: Inlinize block-level boxes inside ruby</title>
|
||||
<link rel="author" title="Xidorn Quan" href="mailto:quanxunzhen@gmail.com">
|
||||
<link rel="help" href="http://dev.w3.org/csswg/css-ruby/#anon-gen-inlinize">
|
||||
<link rel="help" href="http://dev.w3.org/csswg/css-ruby-1/#anon-gen-inlinize">
|
||||
<link rel="match" href="ruby-inlinize-blocks-003-ref.html">
|
||||
<link rel="stylesheet" href="support/rbc.css">
|
||||
<style>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<meta charset="UTF-8">
|
||||
<title>CSS Test: Inlinize block-level boxes inside ruby</title>
|
||||
<link rel="author" title="Xidorn Quan" href="mailto:quanxunzhen@gmail.com">
|
||||
<link rel="help" href="http://dev.w3.org/csswg/css-ruby/#anon-gen-inlinize">
|
||||
<link rel="help" href="http://dev.w3.org/csswg/css-ruby-1/#anon-gen-inlinize">
|
||||
<link rel="match" href="ruby-inlinize-blocks-004-ref.html">
|
||||
<link rel="stylesheet" href="support/rbc.css">
|
||||
<style>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<meta charset="UTF-8">
|
||||
<title>CSS Test: Inlinize block-level boxes inside ruby</title>
|
||||
<link rel="author" title="Xidorn Quan" href="mailto:quanxunzhen@gmail.com">
|
||||
<link rel="help" href="http://dev.w3.org/csswg/css-ruby/#anon-gen-inlinize">
|
||||
<link rel="help" href="http://dev.w3.org/csswg/css-ruby-1/#anon-gen-inlinize">
|
||||
<link rel="match" href="ruby-inlinize-blocks-005-ref.html">
|
||||
<link rel="stylesheet" href="support/rbc.css">
|
||||
<style>
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
<title>CSS Test: text-decoration on rubies</title>
|
||||
<link rel="author" title="Xidorn Quan" href="http://www.upsuper.org/">
|
||||
<link rel="help" href="http://www.w3.org/TR/css-text-decor-3/#line-decoration">
|
||||
<link rel="match" href="ruby-text-decoration-01-ref.html">
|
||||
</head>
|
||||
<style type="text/css">
|
||||
ruby { display: ruby; }
|
||||
|
|
|
@ -1101,13 +1101,11 @@ nsCSSRuleProcessor::ClearSheets()
|
|||
mSheets.Clear();
|
||||
}
|
||||
|
||||
/* static */ nsresult
|
||||
/* static */ void
|
||||
nsCSSRuleProcessor::Startup()
|
||||
{
|
||||
Preferences::AddBoolVarCache(&gSupportVisitedPseudo, VISITED_PSEUDO_PREF,
|
||||
true);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static bool
|
||||
|
|
|
@ -65,7 +65,7 @@ public:
|
|||
public:
|
||||
nsresult ClearRuleCascades();
|
||||
|
||||
static nsresult Startup();
|
||||
static void Startup();
|
||||
static void Shutdown();
|
||||
static void FreeSystemMetrics();
|
||||
static bool HasSystemMetric(nsIAtom* aMetric);
|
||||
|
|
|
@ -34,3 +34,4 @@ phishingBlocked=The website at %S has been reported as a web forgery designed to
|
|||
cspBlocked=This page has a content security policy that prevents it from being loaded in this way.
|
||||
corruptedContentError=The page you are trying to view cannot be shown because an error in the data transmission was detected.
|
||||
remoteXUL=This page uses an unsupported technology that is no longer available by default in Firefox.
|
||||
sslv3Used=Firefox cannot guarantee the safety of your data on %S because it uses SSLv3, a broken security protocol.
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
#!/usr/bin/env python
|
||||
#!/usr/bin/env python2.7
|
||||
#
|
||||
# Copyright 2014 Adobe Systems Incorporated. All Rights Reserved.
|
||||
#
|
||||
# Adobe permits you to use, modify, and distribute this file in accordance
|
||||
|
@ -6,17 +7,18 @@
|
|||
# a copy of the MPL was not distributed with this file, You can obtain one
|
||||
# at http://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# Create perforce changelist of modules from FTP server
|
||||
# Creates an Adobe Access signed voucher for any executable
|
||||
# Notes: This is currently python2.7 due to mozilla build system requirements
|
||||
|
||||
import io, argparse,pyasn1, bitstring
|
||||
from pyasn1.codec.der import encoder, decoder
|
||||
import argparse, bitstring, pprint, hashlib, os, subprocess, sys, tempfile
|
||||
from pyasn1.codec.der import encoder as der_encoder
|
||||
from pyasn1.type import univ, namedtype, namedval, constraint
|
||||
import hashlib
|
||||
|
||||
|
||||
# CodeSectionDigest ::= SEQUENCE {
|
||||
# offset INTEGER -- section's file offset in the signed binary
|
||||
# digestAlgorithm OBJECT IDENTIFIER -- algorithm identifier for the hash value below. For now only supports SHA256.
|
||||
# digestValue OCTET STRING -- hash value of the TEXT segment.
|
||||
# offset INTEGER -- section's file offset in the signed binary
|
||||
# digestAlgorithm OBJECT IDENTIFIER -- algorithm identifier for the hash value below. For now only supports SHA256.
|
||||
# digestValue OCTET STRING -- hash value of the TEXT segment.
|
||||
# }
|
||||
class CodeSectionDigest(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
|
@ -24,6 +26,7 @@ class CodeSectionDigest(univ.Sequence):
|
|||
namedtype.NamedType('digestAlgorithm', univ.ObjectIdentifier()),
|
||||
namedtype.NamedType('digest', univ.OctetString()))
|
||||
|
||||
|
||||
# CodeSegmentDigest ::= SEQUENCE {
|
||||
# offset INTEGER -- TEXT segment's file offset in the signed binary
|
||||
# codeSectionDigests SET OF CodeSectionDigests
|
||||
|
@ -32,20 +35,22 @@ class CodeSectionDigest(univ.Sequence):
|
|||
class SetOfCodeSectionDigest(univ.SetOf):
|
||||
componentType = CodeSectionDigest()
|
||||
|
||||
|
||||
class CodeSegmentDigest(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('offset', univ.Integer()),
|
||||
namedtype.NamedType('codeSectionDigests', SetOfCodeSectionDigest()))
|
||||
|
||||
|
||||
# ArchitectureDigest ::= SEQUENCE {
|
||||
# cpuType ENUMERATED CpuType
|
||||
# cpuSubType ENUMERATED CpuSubType
|
||||
# CodeSegmentDigests SET OF CodeSegmentDigests
|
||||
# }
|
||||
|
||||
class SetOfCodeSegmentDigest(univ.SetOf):
|
||||
componentType = CodeSegmentDigest()
|
||||
|
||||
|
||||
class CPUType(univ.Enumerated):
|
||||
namedValues = namedval.NamedValues(
|
||||
('IMAGE_FILE_MACHINE_I386', 0x14c),
|
||||
|
@ -55,34 +60,46 @@ class CPUType(univ.Enumerated):
|
|||
constraint.SingleValueConstraint(0x14c, 0x8664)
|
||||
|
||||
|
||||
class CPUSubType(univ.Enumerated):
|
||||
namedValues = namedval.NamedValues(
|
||||
('IMAGE_UNUSED', 0x0),
|
||||
)
|
||||
subtypeSpec = univ.Enumerated.subtypeSpec + \
|
||||
constraint.SingleValueConstraint(0)
|
||||
|
||||
|
||||
class ArchitectureDigest(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('cpuType', CPUType()),
|
||||
namedtype.NamedType('cpuSubType', univ.Integer()),
|
||||
namedtype.NamedType('cpuSubType', CPUSubType()),
|
||||
namedtype.NamedType('CodeSegmentDigests', SetOfCodeSegmentDigest())
|
||||
)
|
||||
|
||||
# ApplicationDigest ::= SEQUENCE {
|
||||
# version INTEGER
|
||||
# digests SET OF ArchitectureDigest
|
||||
# }
|
||||
|
||||
# ApplicationDigest ::= SEQUENCE {
|
||||
# version INTEGER
|
||||
# digests SET OF ArchitectureDigest
|
||||
# }
|
||||
class SetOfArchitectureDigest(univ.SetOf):
|
||||
componentType = ArchitectureDigest()
|
||||
|
||||
|
||||
class ApplicationDigest(univ.Sequence):
|
||||
componentType = namedtype.NamedTypes(
|
||||
namedtype.NamedType('version', univ.Integer()),
|
||||
namedtype.NamedType('digests', SetOfArchitectureDigest())
|
||||
)
|
||||
|
||||
def meetsRequirements(items, requirements):
|
||||
|
||||
def meets_requirements(items, requirements):
|
||||
for r in requirements:
|
||||
for n, v in r.items():
|
||||
if n not in items or items[n] != v: return False
|
||||
return True
|
||||
|
||||
|
||||
# return total number of bytes read from items_in excluding leaves
|
||||
def parseItems(stream, items_in, items_out):
|
||||
def parse_items(stream, items_in, items_out):
|
||||
bits_read = 0
|
||||
total_bits_read = 0
|
||||
|
||||
|
@ -102,7 +119,7 @@ def parseItems(stream, items_in, items_out):
|
|||
requirements = list(filter(lambda x: isinstance(x, dict), item[2]))
|
||||
sub_items = list(filter(lambda x: isinstance(x, tuple), item[2]))
|
||||
|
||||
if not meetsRequirements(items_out, requirements): continue
|
||||
if not meets_requirements(items_out, requirements): continue
|
||||
|
||||
# has sub-items based on length
|
||||
items_out[name] = stream.read(t)
|
||||
|
@ -113,7 +130,7 @@ def parseItems(stream, items_in, items_out):
|
|||
bit_length = items_out[name] * 8
|
||||
|
||||
if bit_length > 0:
|
||||
sub_read, sub_total_read = parseItems(stream, sub_items, items_out)
|
||||
sub_read, sub_total_read = parse_items(stream, sub_items, items_out)
|
||||
bit_length -= sub_read
|
||||
total_bits_read += sub_total_read
|
||||
|
||||
|
@ -127,6 +144,7 @@ def parseItems(stream, items_in, items_out):
|
|||
return bits_read, total_bits_read
|
||||
|
||||
|
||||
# TODO: perhaps switch to pefile module when it officially supports python3
|
||||
class SectionHeader:
|
||||
def __init__(self, stream):
|
||||
items = [
|
||||
|
@ -141,15 +159,115 @@ class SectionHeader:
|
|||
('NumberOfLineNumbers', 'uintle:16'),
|
||||
('Characteristics', 'uintle:32')
|
||||
]
|
||||
self.items = {}
|
||||
_, self.bits_read = parseItems(stream, items, self.items)
|
||||
self.items = dict()
|
||||
self.relocs = dict()
|
||||
|
||||
_, self.bits_read = parse_items(stream, items, self.items)
|
||||
|
||||
self.sectionName = self.items['Name'].decode('utf-8')
|
||||
self.offset = self.items['PointerToRawData']
|
||||
|
||||
COFF_DATA_DIRECTORY_TYPES = [
|
||||
"Export Table",
|
||||
"Import Table",
|
||||
"Resource Table",
|
||||
"Exception Table",
|
||||
"Certificate Tble",
|
||||
"Base Relocation Table",
|
||||
"Debug",
|
||||
"Architecture",
|
||||
"Global Ptr",
|
||||
"TLS Table",
|
||||
"Load Config Table",
|
||||
"Bound Import",
|
||||
"IAT",
|
||||
"Delay Import Descriptor",
|
||||
"CLR Runtime Header",
|
||||
"Reserved",
|
||||
]
|
||||
|
||||
|
||||
def chained_safe_get(obj, names, default=None):
|
||||
if obj is None: return default
|
||||
|
||||
for n in names:
|
||||
if n in obj:
|
||||
obj = obj[n]
|
||||
else:
|
||||
return default
|
||||
|
||||
return obj
|
||||
|
||||
|
||||
class OptionalHeader:
|
||||
def __init__(self, stream, size):
|
||||
self.items = {}
|
||||
items = []
|
||||
|
||||
if size:
|
||||
items += [
|
||||
('Magic', 'uintle:16'),
|
||||
('MajorLinkerVersion', 'uintle:8'),
|
||||
('MinorLinkerVersion', 'uintle:8'),
|
||||
('SizeOfCode', 'uintle:32'),
|
||||
('SizeOfInitializedData', 'uintle:32'),
|
||||
('SizeOfUninitializedData', 'uintle:32'),
|
||||
('AddressOfEntryPoint', 'uintle:32'),
|
||||
('BaseOfCode', 'uintle:32'),
|
||||
]
|
||||
|
||||
_, self.bits_read = parse_items(stream, items, self.items)
|
||||
|
||||
items = []
|
||||
if self.items['Magic'] == 0x10b: # PE32
|
||||
items += [('BaseOfData', 'uintle:32')]
|
||||
|
||||
address_size = 'uintle:64' if self.items['Magic'] == 0x20b else 'uintle:32'
|
||||
|
||||
items += [
|
||||
('ImageBase', address_size),
|
||||
('SectionAlignment', 'uintle:32'),
|
||||
('FileAlignment', 'uintle:32'),
|
||||
('MajorOperatingSystemVersion', 'uintle:16'),
|
||||
('MinorOperatingSystemVersion', 'uintle:16'),
|
||||
('MajorImageVersion', 'uintle:16'),
|
||||
('MinorImageVersion', 'uintle:16'),
|
||||
('MajorSubsystemVersion', 'uintle:16'),
|
||||
('MinorSubsystemVersion', 'uintle:16'),
|
||||
('Win32VersionValue', 'uintle:32'),
|
||||
('SizeOfImage', 'uintle:32'),
|
||||
('SizeOfHeaders', 'uintle:32'),
|
||||
('CheckSum', 'uintle:32'),
|
||||
('Subsystem', 'uintle:16'),
|
||||
('DllCharacteristics', 'uintle:16'),
|
||||
('SizeOfStackReserve', address_size),
|
||||
('SizeOfStackCommit', address_size),
|
||||
('SizeOfHeapReserve', address_size),
|
||||
('SizeOfHeapCommit', address_size),
|
||||
('LoaderFlags', 'uintle:32'),
|
||||
('NumberOfRvaAndSizes', 'uintle:32'),
|
||||
]
|
||||
|
||||
if size > 28:
|
||||
_, bits_read = parse_items(stream, items, self.items)
|
||||
self.bits_read += bits_read
|
||||
|
||||
if 'NumberOfRvaAndSizes' in self.items:
|
||||
index = 0
|
||||
self.items['Data Directories'] = dict()
|
||||
while self.bits_read / 8 < size:
|
||||
d = self.items['Data Directories'][COFF_DATA_DIRECTORY_TYPES[index]] = dict()
|
||||
|
||||
_, bits_read = parse_items(stream, [('VirtualAddress', 'uintle:32'), ('Size', 'uintle:32')], d)
|
||||
self.bits_read += bits_read
|
||||
index += 1
|
||||
|
||||
|
||||
class COFFFileHeader:
|
||||
def __init__(self, stream):
|
||||
self.items = {}
|
||||
self.section_headers = []
|
||||
|
||||
items = [
|
||||
('Machine', 'uintle:16'),
|
||||
('NumberOfSections', 'uintle:16'),
|
||||
|
@ -159,106 +277,178 @@ class COFFFileHeader:
|
|||
('SizeOfOptionalHeader', 'uintle:16'),
|
||||
('Characteristics', 'uintle:16')
|
||||
]
|
||||
self.items = {}
|
||||
_, self.bits_read = parseItems(stream, items, self.items)
|
||||
_, self.bits_read = parse_items(stream, items, self.items)
|
||||
|
||||
#skip over optional header.
|
||||
if self.items['SizeOfOptionalHeader'] > 0:
|
||||
stream.read(self.items['SizeOfOptionalHeader'] * 8)
|
||||
self.bits_read += self.items['SizeOfOptionalHeader'] * 8
|
||||
self.OptionalHeader = OptionalHeader(stream, self.items['SizeOfOptionalHeader'])
|
||||
self.bits_read += self.OptionalHeader.bits_read
|
||||
|
||||
#start reading section headers
|
||||
numberOfSections = self.items['NumberOfSections']
|
||||
self.codeSectionHeaders = []
|
||||
# start reading section headers
|
||||
num_sections = self.items['NumberOfSections']
|
||||
|
||||
while numberOfSections > 0 :
|
||||
sectionHeader = SectionHeader(stream)
|
||||
if (sectionHeader.items['Characteristics'] & 0x20000000) == 0x20000000:
|
||||
self.codeSectionHeaders.append(sectionHeader)
|
||||
numberOfSections -= 1
|
||||
while num_sections > 0 :
|
||||
section_header = SectionHeader(stream)
|
||||
self.bits_read += section_header.bits_read
|
||||
self.section_headers.append(section_header)
|
||||
num_sections -= 1
|
||||
|
||||
self.codeSectionHeaders.sort(key=lambda header: header.offset)
|
||||
self.section_headers.sort(key=lambda header: header.offset)
|
||||
|
||||
# Read Relocations
|
||||
self.process_relocs(stream)
|
||||
|
||||
def process_relocs(self, stream):
|
||||
reloc_table = chained_safe_get(self.OptionalHeader.items, ['Data Directories', 'Base Relocation Table'])
|
||||
if reloc_table is None: return
|
||||
|
||||
orig_pos = stream.bitpos
|
||||
_, stream.bytepos = self.get_rva_section(reloc_table['VirtualAddress'])
|
||||
end_pos = stream.bitpos + reloc_table['Size'] * 8
|
||||
|
||||
while stream.bitpos < end_pos:
|
||||
page_rva = stream.read('uintle:32')
|
||||
block_size = stream.read('uintle:32')
|
||||
|
||||
for i in range(0, int((block_size - 8) / 2)):
|
||||
data = stream.read('uintle:16')
|
||||
typ = data >> 12
|
||||
offset = data & 0xFFF
|
||||
|
||||
if offset == 0 and i > 0: continue
|
||||
|
||||
assert(typ == 3)
|
||||
|
||||
cur_pos = stream.bitpos
|
||||
sh, value_bytepos = self.get_rva_section(page_rva + offset)
|
||||
stream.bytepos = value_bytepos
|
||||
value = stream.read('uintle:32')
|
||||
|
||||
# remove BaseAddress
|
||||
value -= self.OptionalHeader.items['ImageBase']
|
||||
|
||||
stream.overwrite(bitstring.BitArray(uint=value, length=4 * 8), pos=value_bytepos * 8)
|
||||
stream.pos = cur_pos
|
||||
|
||||
stream.bitpos = orig_pos
|
||||
|
||||
def get_rva_section(self, rva):
|
||||
for sh in self.section_headers:
|
||||
if rva < sh.items['VirtualAddress'] or rva >= sh.items['VirtualAddress'] + sh.items['VirtualSize']:
|
||||
continue
|
||||
|
||||
file_pointer = rva - sh.items['VirtualAddress'] + sh.items['PointerToRawData']
|
||||
return sh, file_pointer
|
||||
|
||||
raise Exception('Could not match RVA to section')
|
||||
|
||||
|
||||
def create_temp_file(suffix=""):
|
||||
fd, path = tempfile.mkstemp(suffix=suffix)
|
||||
os.close(fd)
|
||||
return path
|
||||
|
||||
# TIPS:
|
||||
# How to convert PFX to PEM: openssl pkcs12 -in build/certificates/testPKI/IV.pfx -out build/certificates/testPKI/IV.cert.pem
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description='PE/COFF Parser.')
|
||||
parser = argparse.ArgumentParser(description='PE/COFF Signer')
|
||||
parser.add_argument('-input', required=True, help="File to parse.")
|
||||
parser.add_argument('-output', required=True, help="File to write to.")
|
||||
parser.add_argument('-openssl_path',help="Path to OpenSSL to create signed voucher")
|
||||
parser.add_argument('-signer_cert',help="Path to certificate to use to sign voucher. Must be PEM encoded.")
|
||||
parser.add_argument('-verbose', action='store_true', help="Verbose output.")
|
||||
app_args = parser.parse_args()
|
||||
|
||||
stream = bitstring.ConstBitStream(filename=app_args.input)
|
||||
# to simplify relocation handling we use a mutable BitStream so we can remove
|
||||
# the BaseAddress from each relocation
|
||||
stream = bitstring.BitStream(filename=app_args.input)
|
||||
|
||||
# find the COFF header.
|
||||
# skip forward past the MSDOS stub header to 0x3c.
|
||||
|
||||
stream.bytepos = 0x3c
|
||||
|
||||
# read 4 bytes, this is the file offset of the PE signature.
|
||||
peSignatureOffset = stream.read('uintle:32')
|
||||
stream.bytepos = peSignatureOffset
|
||||
pe_sig_offset = stream.read('uintle:32')
|
||||
stream.bytepos = pe_sig_offset
|
||||
|
||||
#read 4 bytes, make sure it's a PE signature.
|
||||
# read 4 bytes, make sure it's a PE signature.
|
||||
signature = stream.read('uintle:32')
|
||||
if signature != 0x00004550 :
|
||||
return
|
||||
if signature != 0x00004550:
|
||||
raise Exception("Invalid File")
|
||||
|
||||
# after signature is the actual COFF file header.
|
||||
coff_header = COFFFileHeader(stream)
|
||||
|
||||
archDigest = ArchitectureDigest()
|
||||
arch_digest = ArchitectureDigest()
|
||||
if coff_header.items['Machine'] == 0x14c:
|
||||
arch_digest.setComponentByName('cpuType', CPUType('IMAGE_FILE_MACHINE_I386'))
|
||||
elif coff_header.items['Machine'] == 0x8664:
|
||||
arch_digest.setComponentByName('cpuType', CPUType('IMAGE_FILE_MACHINE_AMD64'))
|
||||
|
||||
codeSegmentDigests = SetOfCodeSegmentDigest()
|
||||
codeSegmentIdx = 0
|
||||
arch_digest.setComponentByName('cpuSubType', CPUSubType('IMAGE_UNUSED'))
|
||||
|
||||
#after signature is the actual COFF file header.
|
||||
coffFileHeader = COFFFileHeader(stream)
|
||||
text_section_headers = list(filter(lambda x: (x.items['Characteristics'] & 0x20000000) == 0x20000000, coff_header.section_headers))
|
||||
|
||||
if coffFileHeader.items['Machine'] == 0x14c:
|
||||
archDigest.setComponentByName('cpuType', CPUType('IMAGE_FILE_MACHINE_I386'))
|
||||
elif coffFileHeader.items['Machine'] == 0x8664:
|
||||
archDigest.setComponentByName('cpuType', CPUType('IMAGE_FILE_MACHINE_AMD64'))
|
||||
|
||||
archDigest.setComponentByName('cpuSubType', 0)
|
||||
|
||||
|
||||
for codeSectionHeader in coffFileHeader.codeSectionHeaders:
|
||||
stream.bytepos = codeSectionHeader.offset
|
||||
codeSectionBytes = stream.read('bytes:'+ str(codeSectionHeader.items['SizeOfRawData']))
|
||||
if codeSectionHeader.items['SizeOfRawData'] < codeSectionHeader.items['VirtualSize']:
|
||||
#zero pad up to virtualSize
|
||||
codeSectionBytes += "\0" * (codeSectionHeader.items['VirtualSize']-codeSectionHeader.items['SizeOfRawData'])
|
||||
code_segment_digests = SetOfCodeSegmentDigest()
|
||||
code_segment_idx = 0
|
||||
for code_sect_header in text_section_headers:
|
||||
stream.bytepos = code_sect_header.offset
|
||||
code_sect_bytes = stream.read('bytes:' + str(code_sect_header.items['VirtualSize']))
|
||||
|
||||
digester = hashlib.sha256()
|
||||
digester.update(codeSectionBytes)
|
||||
digester.update(code_sect_bytes)
|
||||
digest = digester.digest()
|
||||
|
||||
codeSectionDigest = CodeSectionDigest()
|
||||
codeSectionDigest.setComponentByName('offset', codeSectionHeader.offset)
|
||||
codeSectionDigest.setComponentByName('digestAlgorithm', univ.ObjectIdentifier('2.16.840.1.101.3.4.2.1'))
|
||||
codeSectionDigest.setComponentByName('digest', univ.OctetString(digest))
|
||||
# with open('segment_' + str(code_sect_header.offset) + ".bin", 'wb') as f:
|
||||
# f.write(code_sect_bytes)
|
||||
|
||||
setOfDigest = SetOfCodeSectionDigest()
|
||||
setOfDigest.setComponentByPosition(0, codeSectionDigest)
|
||||
code_section_digest = CodeSectionDigest()
|
||||
code_section_digest.setComponentByName('offset', code_sect_header.offset)
|
||||
code_section_digest.setComponentByName('digestAlgorithm', univ.ObjectIdentifier('2.16.840.1.101.3.4.2.1'))
|
||||
code_section_digest.setComponentByName('digest', univ.OctetString(digest))
|
||||
|
||||
set_of_digest = SetOfCodeSectionDigest()
|
||||
set_of_digest.setComponentByPosition(0, code_section_digest)
|
||||
|
||||
codeSegmentDigest = CodeSegmentDigest()
|
||||
codeSegmentDigest.setComponentByName('offset', codeSectionHeader.offset)
|
||||
codeSegmentDigest.setComponentByName('codeSectionDigests', setOfDigest)
|
||||
codeSegmentDigest.setComponentByName('offset', code_sect_header.offset)
|
||||
codeSegmentDigest.setComponentByName('codeSectionDigests', set_of_digest)
|
||||
|
||||
codeSegmentDigests.setComponentByPosition(codeSegmentIdx, codeSegmentDigest)
|
||||
codeSegmentIdx += 1
|
||||
code_segment_digests.setComponentByPosition(code_segment_idx, codeSegmentDigest)
|
||||
code_segment_idx += 1
|
||||
|
||||
archDigest.setComponentByName('CodeSegmentDigests', codeSegmentDigests)
|
||||
arch_digest.setComponentByName('CodeSegmentDigests', code_segment_digests)
|
||||
|
||||
setOfArchDigests = SetOfArchitectureDigest()
|
||||
setOfArchDigests.setComponentByPosition(0, archDigest)
|
||||
setOfArchDigests.setComponentByPosition(0, arch_digest)
|
||||
|
||||
appDigest = ApplicationDigest()
|
||||
|
||||
appDigest.setComponentByName('version', 1)
|
||||
appDigest.setComponentByName('digests', setOfArchDigests)
|
||||
|
||||
binaryDigest = encoder.encode(appDigest)
|
||||
binaryDigest = der_encoder.encode(appDigest)
|
||||
|
||||
outFile = open(app_args.output, 'wb')
|
||||
outFile.write(binaryDigest)
|
||||
with open(app_args.output, 'wb') as f:
|
||||
f.write(binaryDigest)
|
||||
|
||||
# sign with openssl if specified
|
||||
if app_args.openssl_path is not None:
|
||||
assert app_args.signer_cert is not None
|
||||
|
||||
out_base, out_ext = os.path.splitext(app_args.output)
|
||||
signed_path = out_base + ".signed" + out_ext
|
||||
|
||||
# http://stackoverflow.com/questions/12507277/how-to-fix-unable-to-write-random-state-in-openssl
|
||||
temp_file = None
|
||||
if sys.platform == "win32" and "RANDFILE" not in os.environ:
|
||||
temp_file = create_temp_file()
|
||||
os.environ["RANDFILE"] = temp_file
|
||||
|
||||
try:
|
||||
subprocess.check_call([app_args.openssl_path, "cms", "-sign", "-nodetach", "-md", "sha256", "-binary", "-in", app_args.output, "-outform", "der", "-out", signed_path, "-signer", app_args.signer_cert], )
|
||||
finally:
|
||||
if temp_file is not None:
|
||||
del os.environ["RANDFILE"]
|
||||
os.unlink(temp_file)
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
|
|
@ -1209,6 +1209,12 @@ retryDueToTLSIntolerance(PRErrorCode err, nsNSSSocketInfo* socketInfo)
|
|||
SSLVersionRange range = socketInfo->GetTLSVersionRange();
|
||||
nsSSLIOLayerHelpers& helpers = socketInfo->SharedState().IOLayerHelpers();
|
||||
|
||||
if (err == SSL_ERROR_UNSUPPORTED_VERSION &&
|
||||
range.min == SSL_LIBRARY_VERSION_TLS_1_0) {
|
||||
socketInfo->SetSecurityState(nsIWebProgressListener::STATE_IS_INSECURE |
|
||||
nsIWebProgressListener::STATE_USES_SSL_3);
|
||||
}
|
||||
|
||||
if (err == SSL_ERROR_INAPPROPRIATE_FALLBACK_ALERT) {
|
||||
// This is a clear signal that we've fallen back too many versions. Treat
|
||||
// this as a hard failure, but forget any intolerance so that later attempts
|
||||
|
|
|
@ -600,7 +600,7 @@ OptionalExtensions(Reader& input, uint8_t tag,
|
|||
Result DigestAlgorithmIdentifier(Reader& input,
|
||||
/*out*/ DigestAlgorithm& algorithm);
|
||||
|
||||
enum PublicKeyAlgorithm
|
||||
enum class PublicKeyAlgorithm
|
||||
{
|
||||
RSA_PKCS1,
|
||||
ECDSA,
|
||||
|
|
|
@ -370,20 +370,6 @@ GenerateDSSKeyPair()
|
|||
privateKey.release());
|
||||
}
|
||||
|
||||
ByteString
|
||||
SHA1(const ByteString& toHash)
|
||||
{
|
||||
InitNSSIfNeeded();
|
||||
|
||||
uint8_t digestBuf[SHA1_LENGTH];
|
||||
SECStatus srv = PK11_HashBuf(SEC_OID_SHA1, digestBuf, toHash.data(),
|
||||
static_cast<int32_t>(toHash.length()));
|
||||
if (srv != SECSuccess) {
|
||||
return ByteString();
|
||||
}
|
||||
return ByteString(digestBuf, sizeof(digestBuf));
|
||||
}
|
||||
|
||||
Result
|
||||
TestVerifyECDSASignedDigest(const SignedDigest& signedDigest,
|
||||
Input subjectPublicKeyInfo)
|
||||
|
|
|
@ -172,6 +172,22 @@ static ByteString SingleResponse(OCSPResponseContext& context);
|
|||
static ByteString CertID(OCSPResponseContext& context);
|
||||
static ByteString CertStatus(OCSPResponseContext& context);
|
||||
|
||||
static ByteString
|
||||
SHA1(const ByteString& toHash)
|
||||
{
|
||||
uint8_t digestBuf[20];
|
||||
Input input;
|
||||
if (input.Init(toHash.data(), toHash.length()) != Success) {
|
||||
abort();
|
||||
}
|
||||
Result rv = TestDigestBuf(input, DigestAlgorithm::sha1, digestBuf,
|
||||
sizeof(digestBuf));
|
||||
if (rv != Success) {
|
||||
abort();
|
||||
}
|
||||
return ByteString(digestBuf, sizeof(digestBuf));
|
||||
}
|
||||
|
||||
static ByteString
|
||||
HashedOctetString(const ByteString& bytes)
|
||||
{
|
||||
|
|
|
@ -270,8 +270,6 @@ TestKeyPair* GenerateDSSKeyPair();
|
|||
inline void DeleteTestKeyPair(TestKeyPair* keyPair) { delete keyPair; }
|
||||
typedef ScopedPtr<TestKeyPair, DeleteTestKeyPair> ScopedTestKeyPair;
|
||||
|
||||
ByteString SHA1(const ByteString& toHash);
|
||||
|
||||
Result TestVerifyECDSASignedDigest(const SignedDigest& signedDigest,
|
||||
Input subjectPublicKeyInfo);
|
||||
Result TestVerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest,
|
||||
|
|
|
@ -38,6 +38,7 @@ typedef struct _MacSandboxInfo {
|
|||
MacSandboxPluginInfo pluginInfo;
|
||||
nsCString appPath;
|
||||
nsCString appBinaryPath;
|
||||
nsCString appDir;
|
||||
} MacSandboxInfo;
|
||||
|
||||
namespace mozilla {
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include "Sandbox.h"
|
||||
|
||||
#include "nsCocoaFeatures.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
|
||||
// XXX There are currently problems with the /usr/include/sandbox.h file on
|
||||
// some/all of the Macs in Mozilla's build system. For the time being (until
|
||||
|
@ -44,7 +45,236 @@ static const char pluginSandboxRules[] =
|
|||
|
||||
static const char contentSandboxRules[] =
|
||||
"(version 1)\n"
|
||||
"(allow default)\n";
|
||||
"\n"
|
||||
"(define sandbox-level %d)\n"
|
||||
"(define macosMajorVersion %d)\n"
|
||||
"(define macosMinorVersion %d)\n"
|
||||
"(define appPath \"%s\")\n"
|
||||
"(define appBinaryPath \"%s\")\n"
|
||||
"(define appDir \"%s\")\n"
|
||||
"(define home-path \"%s\")\n"
|
||||
"\n"
|
||||
"(import \"/System/Library/Sandbox/Profiles/system.sb\")\n"
|
||||
"\n"
|
||||
"(if \n"
|
||||
" (or\n"
|
||||
" (< macosMinorVersion 9)\n"
|
||||
" (= sandbox-level 0))\n"
|
||||
" (allow default)\n"
|
||||
" (begin\n"
|
||||
" (deny default)\n"
|
||||
" (debug deny)\n"
|
||||
"\n"
|
||||
" (define resolving-literal literal)\n"
|
||||
" (define resolving-subpath subpath)\n"
|
||||
" (define resolving-regex regex)\n"
|
||||
"\n"
|
||||
" (define container-path appPath)\n"
|
||||
" (define appdir-path appDir)\n"
|
||||
" (define var-folders-re \"^/private/var/folders/[^/][^/]\")\n"
|
||||
" (define var-folders2-re (string-append var-folders-re \"/[^/]*/[^/]\"))\n"
|
||||
"\n"
|
||||
" (define (home-regex home-relative-regex)\n"
|
||||
" (resolving-regex (string-append \"^\" (regex-quote home-path) home-relative-regex)))\n"
|
||||
" (define (home-subpath home-relative-subpath)\n"
|
||||
" (resolving-subpath (string-append home-path home-relative-subpath)))\n"
|
||||
" (define (home-literal home-relative-literal)\n"
|
||||
" (resolving-literal (string-append home-path home-relative-literal)))\n"
|
||||
"\n"
|
||||
" (define (container-regex container-relative-regex)\n"
|
||||
" (resolving-regex (string-append \"^\" (regex-quote container-path) container-relative-regex)))\n"
|
||||
" (define (container-subpath container-relative-subpath)\n"
|
||||
" (resolving-subpath (string-append container-path container-relative-subpath)))\n"
|
||||
" (define (container-literal container-relative-literal)\n"
|
||||
" (resolving-literal (string-append container-path container-relative-literal)))\n"
|
||||
"\n"
|
||||
" (define (var-folders-regex var-folders-relative-regex)\n"
|
||||
" (resolving-regex (string-append var-folders-re var-folders-relative-regex)))\n"
|
||||
" (define (var-folders2-regex var-folders2-relative-regex)\n"
|
||||
" (resolving-regex (string-append var-folders2-re var-folders2-relative-regex)))\n"
|
||||
"\n"
|
||||
" (define (appdir-regex appdir-relative-regex)\n"
|
||||
" (resolving-regex (string-append \"^\" (regex-quote appdir-path) appdir-relative-regex)))\n"
|
||||
" (define (appdir-subpath appdir-relative-subpath)\n"
|
||||
" (resolving-subpath (string-append appdir-path appdir-relative-subpath)))\n"
|
||||
" (define (appdir-literal appdir-relative-literal)\n"
|
||||
" (resolving-literal (string-append appdir-path appdir-relative-literal)))\n"
|
||||
"\n"
|
||||
" (define (allow-shared-preferences-read domain)\n"
|
||||
" (begin\n"
|
||||
" (if (defined? `user-preference-read)\n"
|
||||
" (allow user-preference-read (preference-domain domain)))\n"
|
||||
" (allow file-read*\n"
|
||||
" (home-literal (string-append \"/Library/Preferences/\" domain \".plist\"))\n"
|
||||
" (home-regex (string-append \"/Library/Preferences/ByHost/\" (regex-quote domain) \"\\..*\\.plist$\")))\n"
|
||||
" ))\n"
|
||||
"\n"
|
||||
" (define (allow-shared-list domain)\n"
|
||||
" (allow file-read*\n"
|
||||
" (home-regex (string-append \"/Library/Preferences/\" (regex-quote domain)))))\n"
|
||||
"\n"
|
||||
" (allow file-read-metadata)\n"
|
||||
"\n"
|
||||
" (allow ipc-posix-shm\n"
|
||||
" (ipc-posix-name-regex \"^/tmp/com.apple.csseed:\")\n"
|
||||
" (ipc-posix-name-regex \"^CFPBS:\")\n"
|
||||
" (ipc-posix-name-regex \"^AudioIO\"))\n"
|
||||
"\n"
|
||||
" (allow file-read-metadata\n"
|
||||
" (literal \"/home\")\n"
|
||||
" (literal \"/net\")\n"
|
||||
" (regex \"^/private/tmp/KSInstallAction\\.\")\n"
|
||||
" (var-folders-regex \"/\")\n"
|
||||
" (home-subpath \"/Library\"))\n"
|
||||
" \n"
|
||||
" (allow signal (target self))\n"
|
||||
" (allow job-creation (literal \"/Library/CoreMediaIO/Plug-Ins/DAL\"))\n"
|
||||
"\n"
|
||||
" (allow mach-lookup\n"
|
||||
" (global-name \"com.apple.coreservices.launchservicesd\")\n"
|
||||
" (global-name \"com.apple.coreservices.appleevents\")\n"
|
||||
" (global-name \"com.apple.pasteboard.1\")\n"
|
||||
" (global-name \"com.apple.window_proxies\")\n"
|
||||
" (global-name \"com.apple.windowserver.active\")\n"
|
||||
" (global-name \"com.apple.cvmsServ\")\n"
|
||||
" (global-name \"com.apple.audio.coreaudiod\")\n"
|
||||
" (global-name \"com.apple.audio.audiohald\")\n"
|
||||
" (global-name \"com.apple.PowerManagement.control\")\n"
|
||||
" (global-name \"com.apple.cmio.VDCAssistant\")\n"
|
||||
" (global-name \"com.apple.SystemConfiguration.configd\")\n"
|
||||
" (global-name \"com.apple.iconservices\")\n"
|
||||
" (global-name \"com.apple.cookied\")\n"
|
||||
" (global-name \"com.apple.printuitool.agent\")\n"
|
||||
" (global-name \"com.apple.printtool.agent\")\n"
|
||||
" (global-name \"com.apple.cache_delete\")\n"
|
||||
" (global-name \"com.apple.pluginkit.pkd\")\n"
|
||||
" (global-name \"com.apple.bird\")\n"
|
||||
" (global-name \"com.apple.DesktopServicesHelper\")\n"
|
||||
" (global-name \"com.apple.printtool.daemon\"))\n"
|
||||
" \n"
|
||||
" (allow iokit-open\n"
|
||||
" (iokit-user-client-class \"AppleGraphicsControlClient\")\n"
|
||||
" (iokit-user-client-class \"IOHIDParamUserClient\")\n"
|
||||
" (iokit-user-client-class \"IOAudioControlUserClient\")\n"
|
||||
" (iokit-user-client-class \"IOAudioEngineUserClient\")\n"
|
||||
" (iokit-user-client-class \"IGAccelDevice\")\n"
|
||||
" (iokit-user-client-class \"nvDevice\")\n"
|
||||
" (iokit-user-client-class \"nvSharedUserClient\")\n"
|
||||
" (iokit-user-client-class \"nvFermiGLContext\")\n"
|
||||
" (iokit-user-client-class \"IGAccelGLContext\")\n"
|
||||
" (iokit-user-client-class \"AGPMClient\")\n"
|
||||
" (iokit-user-client-class \"IOSurfaceRootUserClient\")\n"
|
||||
" (iokit-user-client-class \"IGAccelSharedUserClient\")\n"
|
||||
" (iokit-user-client-class \"IGAccelVideoContextMain\")\n"
|
||||
" (iokit-user-client-class \"IGAccelVideoContextMedia\")\n"
|
||||
" (iokit-user-client-class \"IGAccelVideoContextVEBox\")\n"
|
||||
" (iokit-user-client-class \"RootDomainUserClient\")\n"
|
||||
" (iokit-user-client-class \"IOUSBDeviceUserClientV2\")\n"
|
||||
" (iokit-user-client-class \"IOUSBInterfaceUserClientV2\"))\n"
|
||||
"\n"
|
||||
"; depending on systems, the 1st, 2nd or both rules are necessary\n"
|
||||
" (allow-shared-preferences-read \"com.apple.HIToolbox\")\n"
|
||||
" (allow file-read-data (literal \"/Library/Preferences/com.apple.HIToolbox.plist\"))\n"
|
||||
" \n"
|
||||
" (allow file-read*\n"
|
||||
" (subpath \"/Library/Fonts\")\n"
|
||||
" (subpath \"/Library/Audio/Plug-Ins\")\n"
|
||||
" (subpath \"/Library/CoreMediaIO/Plug-Ins/DAL\")\n"
|
||||
" (subpath \"/Library/Spelling\")\n"
|
||||
" (subpath \"/private/etc/cups/ppd\")\n"
|
||||
" (subpath \"/private/var/run/cupsd\")\n"
|
||||
" (literal \"/\")\n"
|
||||
" (literal \"/private/tmp\")\n"
|
||||
" (literal \"/private/var/tmp\")\n"
|
||||
"\n"
|
||||
" (home-literal \"/.CFUserTextEncoding\")\n"
|
||||
" (home-literal \"/Library/Preferences/com.apple.DownloadAssessment.plist\")\n"
|
||||
" (home-subpath \"/Library/Colors\")\n"
|
||||
" (home-subpath \"/Library/Fonts\")\n"
|
||||
" (home-subpath \"/Library/FontCollections\")\n"
|
||||
" (home-subpath \"/Library/Keyboard Layouts\")\n"
|
||||
" (home-subpath \"/Library/Input Methods\")\n"
|
||||
" (home-subpath \"/Library/PDF Services\")\n"
|
||||
" (home-subpath \"/Library/Spelling\")\n"
|
||||
"\n"
|
||||
" (subpath appdir-path)\n"
|
||||
"\n"
|
||||
" (literal appPath)\n"
|
||||
" (literal appBinaryPath))\n"
|
||||
"\n"
|
||||
" (allow-shared-list \"org.mozilla.plugincontainer\")\n"
|
||||
"\n"
|
||||
"; the following 2 rules should be removed when microphone and camera access\n"
|
||||
"; are brokered through the content process\n"
|
||||
" (allow device-microphone)\n"
|
||||
" (allow device-camera)\n"
|
||||
"\n"
|
||||
" (allow file* (var-folders2-regex \"/com\\.apple\\.IntlDataCache\\.le$\"))\n"
|
||||
" (allow file-read* (var-folders2-regex \"/com\\.apple\\.IconServices/\"))\n"
|
||||
"\n"
|
||||
" (allow file-write* (var-folders2-regex \"/org\\.chromium\\.[a-zA-Z0-9]*$\"))\n"
|
||||
" \n"
|
||||
"; the following rules should be removed when printing and \n"
|
||||
"; opening a file from disk are brokered through the main process\n"
|
||||
" (allow file*\n"
|
||||
" (require-all\n"
|
||||
" (subpath home-path)\n"
|
||||
" (require-not\n"
|
||||
" (home-subpath \"/Library\"))))\n"
|
||||
" \n"
|
||||
"; printing\n"
|
||||
" (allow authorization-right-obtain\n"
|
||||
" (right-name \"system.print.operator\")\n"
|
||||
" (right-name \"system.printingmanager\"))\n"
|
||||
" (allow mach-lookup\n"
|
||||
" (global-name \"com.apple.printuitool.agent\")\n"
|
||||
" (global-name \"com.apple.printtool.agent\")\n"
|
||||
" (global-name \"com.apple.printtool.daemon\")\n"
|
||||
" (global-name \"com.apple.sharingd\")\n"
|
||||
" (global-name \"com.apple.metadata.mds\")\n"
|
||||
" (global-name \"com.apple.mtmd.xpc\")\n"
|
||||
" (global-name \"com.apple.FSEvents\")\n"
|
||||
" (global-name \"com.apple.locum\")\n"
|
||||
" (global-name \"com.apple.ImageCaptureExtension2.presence\"))\n"
|
||||
" (allow file-read*\n"
|
||||
" (home-literal \"/.cups/lpoptions\")\n"
|
||||
" (home-literal \"/.cups/client.conf\")\n"
|
||||
" (literal \"/private/etc/cups/lpoptions\")\n"
|
||||
" (literal \"/private/etc/cups/client.conf\")\n"
|
||||
" (subpath \"/private/etc/cups/ppd\")\n"
|
||||
" (literal \"/private/var/run/cupsd\"))\n"
|
||||
" (allow-shared-preferences-read \"org.cups.PrintingPrefs\")\n"
|
||||
" (allow-shared-preferences-read \"com.apple.finder\")\n"
|
||||
" (allow-shared-preferences-read \"com.apple.LaunchServices\")\n"
|
||||
" (allow-shared-preferences-read \".GlobalPreferences\")\n"
|
||||
" (allow network-outbound\n"
|
||||
" (literal \"/private/var/run/cupsd\")\n"
|
||||
" (literal \"/private/var/run/mDNSResponder\"))\n"
|
||||
"\n"
|
||||
"; print preview\n"
|
||||
" (if (> macosMinorVersion 9)\n"
|
||||
" (allow lsopen))\n"
|
||||
" (allow file-write* file-issue-extension (var-folders2-regex \"/\"))\n"
|
||||
" (allow file-read-xattr (literal \"/Applications/Preview.app\"))\n"
|
||||
" (allow mach-task-name)\n"
|
||||
" (allow mach-register)\n"
|
||||
" (allow file-read-data\n"
|
||||
" (regex \"^/Library/Printers/[^/]+/PDEs/[^/]+.plugin\")\n"
|
||||
" (subpath \"/Library/PDF Services\")\n"
|
||||
" (subpath \"/Applications/Preview.app\")\n"
|
||||
" (home-literal \"/Library/Preferences/com.apple.ServicesMenu.Services.plist\"))\n"
|
||||
" (allow mach-lookup\n"
|
||||
" (global-name \"com.apple.pbs.fetch_services\")\n"
|
||||
" (global-name \"com.apple.tsm.uiserver\")\n"
|
||||
" (global-name \"com.apple.ls.boxd\")\n"
|
||||
" (global-name \"com.apple.coreservices.quarantine-resolver\")\n"
|
||||
" (global-name-regex \"_OpenStep$\"))\n"
|
||||
" (allow appleevent-send\n"
|
||||
" (appleevent-destination \"com.apple.preview\")\n"
|
||||
" (appleevent-destination \"com.apple.imagecaptureextension2\"))\n"
|
||||
"\n"
|
||||
" )\n"
|
||||
")\n";
|
||||
|
||||
bool StartMacSandbox(MacSandboxInfo aInfo, nsCString &aErrorMessage)
|
||||
{
|
||||
|
@ -65,7 +295,14 @@ bool StartMacSandbox(MacSandboxInfo aInfo, nsCString &aErrorMessage)
|
|||
}
|
||||
}
|
||||
else if (aInfo.type == MacSandboxType_Content) {
|
||||
profile.AppendPrintf(contentSandboxRules);
|
||||
profile.AppendPrintf(contentSandboxRules,
|
||||
Preferences::GetInt("security.sandbox.macos.content.level"),
|
||||
nsCocoaFeatures::OSXVersionMajor(),
|
||||
nsCocoaFeatures::OSXVersionMinor(),
|
||||
aInfo.appPath.get(),
|
||||
aInfo.appBinaryPath.get(),
|
||||
aInfo.appDir.get(),
|
||||
getenv("HOME"));
|
||||
}
|
||||
else {
|
||||
aErrorMessage.AppendPrintf("Unexpected sandbox type %u", aInfo.type);
|
||||
|
|
|
@ -49,6 +49,14 @@ config = {
|
|||
"run_filename": "test.py",
|
||||
"testsdir": "mozbase"
|
||||
},
|
||||
"mozmill": {
|
||||
"options": [
|
||||
"--binary=%(binary_path)s",
|
||||
"--symbols-path=%(symbols_path)s"
|
||||
],
|
||||
"run_filename": "runtestlist.py",
|
||||
"testsdir": "mozmill"
|
||||
},
|
||||
"reftest": {
|
||||
"options": [
|
||||
"--appname=%(binary_path)s",
|
||||
|
@ -85,4 +93,4 @@ config = {
|
|||
"testsdir": "xpcshell"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,6 +47,14 @@ config = {
|
|||
"run_filename": "test.py",
|
||||
"testsdir": "mozbase"
|
||||
},
|
||||
"mozmill": {
|
||||
"options": [
|
||||
"--binary=%(binary_path)s",
|
||||
"--symbols-path=%(symbols_path)s"
|
||||
],
|
||||
"run_filename": "runtestlist.py",
|
||||
"testsdir": "mozmill"
|
||||
},
|
||||
"reftest": {
|
||||
"options": [
|
||||
"--appname=%(binary_path)s",
|
||||
|
|
|
@ -47,6 +47,14 @@ config = {
|
|||
"run_filename": "test.py",
|
||||
"testsdir": "mozbase"
|
||||
},
|
||||
"mozmill": {
|
||||
"options": [
|
||||
"--binary=%(binary_path)s",
|
||||
"--symbols-path=%(symbols_path)s"
|
||||
],
|
||||
"run_filename": "runtestlist.py",
|
||||
"testsdir": "mozmill"
|
||||
},
|
||||
"reftest": {
|
||||
"options": [
|
||||
"--appname=%(binary_path)s",
|
||||
|
@ -83,4 +91,4 @@ config = {
|
|||
"testsdir": "xpcshell"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,15 +28,6 @@ class HTMLElement(object):
|
|||
Represents a DOM Element.
|
||||
"""
|
||||
|
||||
CLASS = "class name"
|
||||
SELECTOR = "css selector"
|
||||
ID = "id"
|
||||
NAME = "name"
|
||||
LINK_TEXT = "link text"
|
||||
PARTIAL_LINK_TEXT = "partial link text"
|
||||
TAG = "tag name"
|
||||
XPATH = "xpath"
|
||||
|
||||
def __init__(self, marionette, id):
|
||||
self.marionette = marionette
|
||||
assert(id is not None)
|
||||
|
|
|
@ -107,8 +107,9 @@ var LoginManagerParent = {
|
|||
return;
|
||||
}
|
||||
|
||||
let allLoginsCount = Services.logins.countLogins(formOrigin, "", null);
|
||||
// If there are no logins for this site, bail out now.
|
||||
if (!Services.logins.countLogins(formOrigin, "", null)) {
|
||||
if (!allLoginsCount) {
|
||||
target.sendAsyncMessage("RemoteLogins:loginsFound",
|
||||
{ requestId: requestId, logins: [] });
|
||||
return;
|
||||
|
@ -152,6 +153,16 @@ var LoginManagerParent = {
|
|||
var logins = Services.logins.findLogins({}, formOrigin, actionOrigin, null);
|
||||
target.sendAsyncMessage("RemoteLogins:loginsFound",
|
||||
{ requestId: requestId, logins: logins });
|
||||
|
||||
const PWMGR_FORM_ACTION_EFFECT = Services.telemetry.getHistogramById("PWMGR_FORM_ACTION_EFFECT");
|
||||
if (logins.length == 0) {
|
||||
PWMGR_FORM_ACTION_EFFECT.add(2);
|
||||
} else if (logins.length == allLoginsCount) {
|
||||
PWMGR_FORM_ACTION_EFFECT.add(0);
|
||||
} else {
|
||||
// logins.length < allLoginsCount
|
||||
PWMGR_FORM_ACTION_EFFECT.add(1);
|
||||
}
|
||||
},
|
||||
|
||||
doAutocompleteSearch: function({ formOrigin, actionOrigin,
|
||||
|
|
|
@ -7360,6 +7360,12 @@
|
|||
"extended_statistics_ok": true,
|
||||
"description": "The number of sites for which the user has explicitly rejected saving logins"
|
||||
},
|
||||
"PWMGR_FORM_ACTION_EFFECT": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "enumerated",
|
||||
"n_values" : 5,
|
||||
"description": "The effect of the form action on signon autofill. (0=No effect, 1=Fewer logins after considering the form action, 2=No logins match form origin and action."
|
||||
},
|
||||
"PWMGR_FORM_AUTOFILL_RESULT": {
|
||||
"expires_in_version": "never",
|
||||
"kind": "enumerated",
|
||||
|
|
|
@ -229,3 +229,5 @@
|
|||
<!ENTITY experiment.info.learnmore.accesskey "L">
|
||||
<!ENTITY experiment.info.changetelemetry "Telemetry Settings">
|
||||
<!ENTITY experiment.info.changetelemetry.accesskey "T">
|
||||
|
||||
<!ENTITY setting.learnmore "Learn More…">
|
||||
|
|
|
@ -39,3 +39,4 @@
|
|||
|
||||
<!ENTITY plugin.file "File">
|
||||
<!ENTITY plugin.mimeTypes "MIME Types">
|
||||
<!ENTITY plugin.flashProtectedMode.label "Enable Adobe Flash protected mode">
|
||||
|
|
|
@ -74,6 +74,10 @@ setting[type="bool"][localized="true"] {
|
|||
-moz-binding: url("chrome://mozapps/content/extensions/setting.xml#setting-localized-bool");
|
||||
}
|
||||
|
||||
setting[type="bool"]:not([learnmore]) .preferences-learnmore {
|
||||
visibility: collapse;
|
||||
}
|
||||
|
||||
setting[type="boolint"] {
|
||||
display: -moz-grid-line;
|
||||
-moz-binding: url("chrome://mozapps/content/extensions/setting.xml#setting-boolint");
|
||||
|
|
|
@ -13,4 +13,8 @@
|
|||
<setting type="control" title="&plugin.mimeTypes;">
|
||||
<label class="text-list" id="pluginMimeTypes"/>
|
||||
</setting>
|
||||
<setting type="bool" pref="dom.ipc.plugins.flash.disable-protected-mode"
|
||||
inverted="true" title="&plugin.flashProtectedMode.label;"
|
||||
id="pluginEnableProtectedMode"
|
||||
learnmore="https://support.mozilla.org/kb/flash-protected-mode-settings" />
|
||||
</vbox>
|
||||
|
|
|
@ -144,6 +144,8 @@
|
|||
<xul:label class="preferences-title" flex="1" xbl:inherits="xbl:text=title"/>
|
||||
</xul:hbox>
|
||||
<xul:description class="preferences-description" flex="1" xbl:inherits="xbl:text=desc"/>
|
||||
<xul:label class="preferences-learnmore text-link"
|
||||
onclick="document.getBindingParent(this).openLearnMore()">&setting.learnmore;</xul:label>
|
||||
</xul:vbox>
|
||||
<xul:hbox class="preferences-alignment">
|
||||
<xul:checkbox anonid="input" xbl:inherits="disabled,onlabel,offlabel,label=checkboxlabel" oncommand="inputChanged();"/>
|
||||
|
@ -171,6 +173,14 @@
|
|||
|
||||
<property name="value" onget="return this.input.checked;" onset="return this.input.setChecked(val);"/>
|
||||
<property name="inverted" readonly="true" onget="return this.getAttribute('inverted');"/>
|
||||
|
||||
<method name="openLearnMore">
|
||||
<body>
|
||||
<![CDATA[
|
||||
window.open(this.getAttribute("learnmore"), "_blank");
|
||||
]]>
|
||||
</body>
|
||||
</method>
|
||||
</implementation>
|
||||
</binding>
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ Cu.import("resource://gre/modules/Services.jsm");
|
|||
const URI_EXTENSION_STRINGS = "chrome://mozapps/locale/extensions/extensions.properties";
|
||||
const STRING_TYPE_NAME = "type.%ID%.name";
|
||||
const LIST_UPDATED_TOPIC = "plugins-list-updated";
|
||||
const FLASH_MIME_TYPE = "application/x-shockwave-flash";
|
||||
|
||||
Cu.import("resource://gre/modules/Log.jsm");
|
||||
const LOGGER_ID = "addons.plugins";
|
||||
|
@ -85,6 +86,9 @@ var PluginProvider = {
|
|||
types.push(type.type + (extras ? " (" + extras + ")" : ""));
|
||||
}
|
||||
typeLabel.textContent = types.join(",\n");
|
||||
let showProtectedModePref = canDisableFlashProtectedMode(plugin);
|
||||
aSubject.getElementById("pluginEnableProtectedMode")
|
||||
.setAttribute("collapsed", showProtectedModePref ? "" : "true");
|
||||
});
|
||||
break;
|
||||
case LIST_UPDATED_TOPIC:
|
||||
|
@ -276,6 +280,19 @@ var PluginProvider = {
|
|||
}
|
||||
};
|
||||
|
||||
function isFlashPlugin(aPlugin) {
|
||||
for (let type of aPlugin.pluginMimeTypes) {
|
||||
if (type.type == FLASH_MIME_TYPE) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// Protected mode is win32-only, not win64
|
||||
function canDisableFlashProtectedMode(aPlugin) {
|
||||
return isFlashPlugin(aPlugin) && Services.appinfo.XPCOMABI == "x86-msvc";
|
||||
}
|
||||
|
||||
/**
|
||||
* The PluginWrapper wraps a set of nsIPluginTags to provide the data visible to
|
||||
* public callers through the API.
|
||||
|
@ -488,10 +505,16 @@ function PluginWrapper(aId, aName, aDescription, aTags) {
|
|||
}
|
||||
return permissions;
|
||||
});
|
||||
|
||||
this.__defineGetter__("optionsType", function() {
|
||||
if (canDisableFlashProtectedMode(this)) {
|
||||
return AddonManager.OPTIONS_TYPE_INLINE;
|
||||
}
|
||||
return AddonManager.OPTIONS_TYPE_INLINE_INFO;
|
||||
});
|
||||
}
|
||||
|
||||
PluginWrapper.prototype = {
|
||||
optionsType: AddonManager.OPTIONS_TYPE_INLINE_INFO,
|
||||
optionsURL: "chrome://mozapps/content/extensions/pluginPrefs.xul",
|
||||
|
||||
get updateDate() {
|
||||
|
|
|
@ -117,6 +117,7 @@ add_task(function* initializeState() {
|
|||
|
||||
// Start out with plugins not being installed, disabled and automatic updates
|
||||
// disabled.
|
||||
gPrefs.setBoolPref(GMPScope.KEY_EME_ENABLED, true);
|
||||
for (let addon of gMockAddons) {
|
||||
gPrefs.setBoolPref(getKey(GMPScope.KEY_PLUGIN_ENABLED, addon.id), false);
|
||||
gPrefs.setIntPref(getKey(GMPScope.KEY_PLUGIN_LAST_UPDATE, addon.id), 0);
|
||||
|
@ -257,7 +258,7 @@ add_task(function* testInstalledGlobalEmeDisabled() {
|
|||
let neverActivate = item.ownerDocument.getAnonymousElementByAttribute(item, "anonid", "never-activate-menuitem");
|
||||
is(menu.selectedItem, neverActivate, "Plugin state should be never-activate.");
|
||||
}
|
||||
gPrefs.clearUserPref(GMPScope.KEY_EME_ENABLED);
|
||||
gPrefs.setBoolPref(GMPScope.KEY_EME_ENABLED, true);
|
||||
});
|
||||
|
||||
add_task(function* testInstalledGlobalEmeDisabledDetails() {
|
||||
|
@ -289,7 +290,7 @@ add_task(function* testInstalledGlobalEmeDisabledDetails() {
|
|||
is_element_hidden(menuSep, "Menu separator is hidden.");
|
||||
contextMenu.hidePopup();
|
||||
}
|
||||
gPrefs.clearUserPref(GMPScope.KEY_EME_ENABLED);
|
||||
gPrefs.setBoolPref(GMPScope.KEY_EME_ENABLED, true);
|
||||
});
|
||||
|
||||
add_task(function* testPreferencesButton() {
|
||||
|
|
|
@ -49,6 +49,7 @@ function run_test() {
|
|||
|
||||
gPrefs.setBoolPref(GMPScope.KEY_LOGGING_DUMP, true);
|
||||
gPrefs.setIntPref(GMPScope.KEY_LOGGING_LEVEL, 0);
|
||||
gPrefs.setBoolPref(GMPScope.KEY_EME_ENABLED, true);
|
||||
for (let addon of gMockAddons.values()) {
|
||||
gPrefs.setBoolPref(gGetKey(GMPScope.KEY_PLUGIN_HIDDEN, addon.id), false);
|
||||
}
|
||||
|
@ -190,7 +191,7 @@ add_task(function* test_globalEmeDisabled() {
|
|||
Assert.equal(addon.permissions, AddonManager.PERM_CAN_UPGRADE |
|
||||
AddonManager.PERM_CAN_ENABLE);
|
||||
}
|
||||
gPrefs.clearUserPref(GMPScope.KEY_EME_ENABLED);
|
||||
gPrefs.setBoolPref(GMPScope.KEY_EME_ENABLED, true);
|
||||
GMPScope.GMPProvider.shutdown();
|
||||
GMPScope.GMPProvider.startup();
|
||||
});
|
||||
|
|
|
@ -6,9 +6,11 @@ include $(MOZILLA_DIR)/toolkit/mozapps/installer/signing.mk
|
|||
|
||||
ifdef MOZ_SIGN_CMD
|
||||
ifeq ($(OS_ARCH),WINNT)
|
||||
# The argument to this macro is the directory where plugin-container.exe
|
||||
# exists, and where voucher.bin will be generated.
|
||||
MAKE_SIGN_EME_VOUCHER = $(PYTHON) $(MOZILLA_DIR)/python/eme/gen-eme-voucher.py -input $(1)/plugin-container.exe -output $(1)/voucher.bin && \
|
||||
$(MOZ_SIGN_CMD) -f emevoucher "$(1)/voucher.bin"
|
||||
ifneq ($(TARGET_CPU),x86_64)
|
||||
# The argument to this macro is the directory where plugin-container.exe
|
||||
# exists, and where voucher.bin will be generated.
|
||||
MAKE_SIGN_EME_VOUCHER = $(PYTHON) $(MOZILLA_DIR)/python/eme/gen-eme-voucher.py -input $(1)/plugin-container.exe -output $(1)/voucher.bin && \
|
||||
$(MOZ_SIGN_CMD) -f emevoucher "$(1)/voucher.bin"
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
|
|
@ -33,3 +33,4 @@ phishingBlocked=The website at %S has been reported as a web forgery designed to
|
|||
cspBlocked=This application tried to access a resource that has a content security policy that prevents it from being loaded in this way.
|
||||
corruptedContentError=The application cannot continue loading because an error in the data transmission was detected.
|
||||
remoteXUL=This application tried to use an unsupported technology that is no longer available.
|
||||
sslv3Used=This application cannot guarantee the safety of your data on %S because it uses SSLv3, a broken security protocol.
|
||||
|
|
|
@ -519,6 +519,9 @@
|
|||
ERROR(NS_ERROR_DOM_QUOTA_REACHED, FAILURE(1014)),
|
||||
ERROR(NS_ERROR_DOM_JS_EXCEPTION, FAILURE(1015)),
|
||||
|
||||
/* A way to represent uncatchable exceptions */
|
||||
ERROR(NS_ERROR_UNCATCHABLE_EXCEPTION, FAILURE(1016)),
|
||||
|
||||
/* May be used to indicate when e.g. setting a property value didn't
|
||||
* actually change the value, like for obj.foo = "bar"; obj.foo = "bar";
|
||||
* the second assignment throws NS_SUCCESS_DOM_NO_OPERATION.
|
||||
|
|
|
@ -54,6 +54,22 @@ class nsPipeEvents;
|
|||
class nsPipeInputStream;
|
||||
class nsPipeOutputStream;
|
||||
|
||||
namespace {
|
||||
|
||||
enum MonitorAction
|
||||
{
|
||||
DoNotNotifyMonitor,
|
||||
NotifyMonitor
|
||||
};
|
||||
|
||||
enum SegmentChangeResult
|
||||
{
|
||||
SegmentNotChanged,
|
||||
SegmentDeleted
|
||||
};
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// this class is used to delay notifications until the end of a particular
|
||||
|
@ -160,10 +176,8 @@ public:
|
|||
// synchronously wait for the pipe to become readable.
|
||||
nsresult Wait();
|
||||
|
||||
// these functions return true to indicate that the pipe's monitor should
|
||||
// be notified, to wake up a blocked reader if any.
|
||||
bool OnInputReadable(uint32_t aBytesWritten, nsPipeEvents&);
|
||||
bool OnInputException(nsresult, nsPipeEvents&);
|
||||
MonitorAction OnInputReadable(uint32_t aBytesWritten, nsPipeEvents&);
|
||||
MonitorAction OnInputException(nsresult, nsPipeEvents&);
|
||||
|
||||
nsPipeReadState& ReadState()
|
||||
{
|
||||
|
@ -239,10 +253,8 @@ public:
|
|||
// synchronously wait for the pipe to become writable.
|
||||
nsresult Wait();
|
||||
|
||||
// these functions return true to indicate that the pipe's monitor should
|
||||
// be notified, to wake up a blocked writer if any.
|
||||
bool OnOutputWritable(nsPipeEvents&);
|
||||
bool OnOutputException(nsresult, nsPipeEvents&);
|
||||
MonitorAction OnOutputWritable(nsPipeEvents&);
|
||||
MonitorAction OnOutputException(nsresult, nsPipeEvents&);
|
||||
|
||||
private:
|
||||
nsPipe* mPipe;
|
||||
|
@ -292,6 +304,10 @@ public:
|
|||
const char*& aSegment, uint32_t& aSegmentLen);
|
||||
void AdvanceReadCursor(nsPipeReadState& aReadState, uint32_t aCount,
|
||||
uint32_t* aAvailableOut);
|
||||
SegmentChangeResult AdvanceReadSegment(nsPipeReadState& aReadState);
|
||||
void DrainInputStream(nsPipeReadState& aReadState, nsPipeEvents& aEvents,
|
||||
uint32_t* aAvailableOut);
|
||||
bool ReadSegmentBeingWritten(nsPipeReadState& aReadState);
|
||||
|
||||
nsresult GetWriteSegment(char*& aSegment, uint32_t& aSegmentLen);
|
||||
void AdvanceWriteCursor(uint32_t aCount);
|
||||
|
@ -540,60 +556,110 @@ nsPipe::AdvanceReadCursor(nsPipeReadState& aReadState, uint32_t aBytesRead,
|
|||
|
||||
// if still writing in this segment then bail because we're not done
|
||||
// with the segment and have to wait for now...
|
||||
if (mWriteSegment == aReadState.mSegment && mWriteLimit > mWriteCursor) {
|
||||
NS_ASSERTION(aReadState.mReadLimit == mWriteCursor, "unexpected state");
|
||||
if (ReadSegmentBeingWritten(aReadState)) {
|
||||
return;
|
||||
}
|
||||
|
||||
uint32_t currentSegment = aReadState.mSegment;
|
||||
|
||||
// Move to the next segment to read
|
||||
aReadState.mSegment += 1;
|
||||
|
||||
// If this was the last reference to the first segment, then remove it.
|
||||
if (currentSegment == 0 && CountSegmentReferences(currentSegment) == 0) {
|
||||
|
||||
// shift write and read segment index (-1 indicates an empty buffer).
|
||||
mWriteSegment -= 1;
|
||||
|
||||
for (uint32_t i = 0; i < mInputList.Length(); ++i) {
|
||||
mInputList[i]->ReadState().mSegment -= 1;
|
||||
}
|
||||
|
||||
// done with this segment
|
||||
mBuffer.DeleteFirstSegment();
|
||||
LOG(("III deleting first segment\n"));
|
||||
}
|
||||
|
||||
if (mWriteSegment < aReadState.mSegment) {
|
||||
// read cursor has hit the end of written data, so reset it
|
||||
MOZ_ASSERT(mWriteSegment == (aReadState.mSegment - 1));
|
||||
aReadState.mReadCursor = nullptr;
|
||||
aReadState.mReadLimit = nullptr;
|
||||
// also, the buffer is completely empty, so reset the write cursor
|
||||
if (mWriteSegment == -1) {
|
||||
mWriteCursor = nullptr;
|
||||
mWriteLimit = nullptr;
|
||||
}
|
||||
} else {
|
||||
// advance read cursor and limit to next buffer segment
|
||||
aReadState.mReadCursor = mBuffer.GetSegment(aReadState.mSegment);
|
||||
if (mWriteSegment == aReadState.mSegment) {
|
||||
aReadState.mReadLimit = mWriteCursor;
|
||||
} else {
|
||||
aReadState.mReadLimit = aReadState.mReadCursor + mBuffer.GetSegmentSize();
|
||||
}
|
||||
}
|
||||
|
||||
// we've free'd up a segment, so notify output stream that pipe has
|
||||
// room for a new segment.
|
||||
if (mOutput.OnOutputWritable(events)) {
|
||||
mon.Notify();
|
||||
// Check to see if we can free up any segments. If we can, then notify
|
||||
// the output stream that the pipe has room for a new segment.
|
||||
if (AdvanceReadSegment(aReadState) == SegmentDeleted &&
|
||||
mOutput.OnOutputWritable(events) == NotifyMonitor) {
|
||||
mon.NotifyAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SegmentChangeResult
|
||||
nsPipe::AdvanceReadSegment(nsPipeReadState& aReadState)
|
||||
{
|
||||
int32_t currentSegment = aReadState.mSegment;
|
||||
|
||||
// Move to the next segment to read
|
||||
aReadState.mSegment += 1;
|
||||
|
||||
SegmentChangeResult result = SegmentNotChanged;
|
||||
|
||||
// If this was the last reference to the first segment, then remove it.
|
||||
if (currentSegment == 0 && CountSegmentReferences(currentSegment) == 0) {
|
||||
|
||||
// shift write and read segment index (-1 indicates an empty buffer).
|
||||
mWriteSegment -= 1;
|
||||
|
||||
for (uint32_t i = 0; i < mInputList.Length(); ++i) {
|
||||
mInputList[i]->ReadState().mSegment -= 1;
|
||||
}
|
||||
|
||||
// done with this segment
|
||||
mBuffer.DeleteFirstSegment();
|
||||
LOG(("III deleting first segment\n"));
|
||||
|
||||
result = SegmentDeleted;
|
||||
}
|
||||
|
||||
if (mWriteSegment < aReadState.mSegment) {
|
||||
// read cursor has hit the end of written data, so reset it
|
||||
MOZ_ASSERT(mWriteSegment == (aReadState.mSegment - 1));
|
||||
aReadState.mReadCursor = nullptr;
|
||||
aReadState.mReadLimit = nullptr;
|
||||
// also, the buffer is completely empty, so reset the write cursor
|
||||
if (mWriteSegment == -1) {
|
||||
mWriteCursor = nullptr;
|
||||
mWriteLimit = nullptr;
|
||||
}
|
||||
} else {
|
||||
// advance read cursor and limit to next buffer segment
|
||||
aReadState.mReadCursor = mBuffer.GetSegment(aReadState.mSegment);
|
||||
if (mWriteSegment == aReadState.mSegment) {
|
||||
aReadState.mReadLimit = mWriteCursor;
|
||||
} else {
|
||||
aReadState.mReadLimit = aReadState.mReadCursor + mBuffer.GetSegmentSize();
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
nsPipe::DrainInputStream(nsPipeReadState& aReadState, nsPipeEvents& aEvents,
|
||||
uint32_t* aAvailableOut)
|
||||
{
|
||||
ReentrantMonitorAutoEnter mon(mReentrantMonitor);
|
||||
|
||||
*aAvailableOut = 0;
|
||||
|
||||
SegmentChangeResult result = SegmentNotChanged;
|
||||
while(mWriteSegment >= aReadState.mSegment) {
|
||||
|
||||
// If the last segment to free is still being written to, we're done
|
||||
// draining. We can't free any more.
|
||||
if (ReadSegmentBeingWritten(aReadState)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (AdvanceReadSegment(aReadState) == SegmentDeleted) {
|
||||
result = SegmentDeleted;
|
||||
}
|
||||
}
|
||||
|
||||
// if we've free'd up a segment, notify output stream that pipe has
|
||||
// room for a new segment.
|
||||
if (result == SegmentDeleted &&
|
||||
mOutput.OnOutputWritable(aEvents) == NotifyMonitor) {
|
||||
mon.NotifyAll();
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
nsPipe::ReadSegmentBeingWritten(nsPipeReadState& aReadState)
|
||||
{
|
||||
bool beingWritten = mWriteSegment == aReadState.mSegment &&
|
||||
mWriteLimit > mWriteCursor;
|
||||
NS_ASSERTION(!beingWritten || aReadState.mReadLimit == mWriteCursor,
|
||||
"unexpected state");
|
||||
return beingWritten;
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsPipe::GetWriteSegment(char*& aSegment, uint32_t& aSegmentLen)
|
||||
{
|
||||
|
@ -664,7 +730,7 @@ nsPipe::AdvanceWriteCursor(uint32_t aBytesWritten)
|
|||
// notify input stream that pipe now contains additional data
|
||||
bool needNotify = false;
|
||||
for (uint32_t i = 0; i < mInputList.Length(); ++i) {
|
||||
if (mInputList[i]->OnInputReadable(aBytesWritten, events)) {
|
||||
if (mInputList[i]->OnInputReadable(aBytesWritten, events) == NotifyMonitor) {
|
||||
needNotify = true;
|
||||
}
|
||||
}
|
||||
|
@ -705,12 +771,12 @@ nsPipe::OnInputStreamException(nsPipeInputStream* aStream, nsresult aReason)
|
|||
continue;
|
||||
}
|
||||
|
||||
bool needNotify = mInputList[i]->OnInputException(aReason, events);
|
||||
MonitorAction action = mInputList[i]->OnInputException(aReason, events);
|
||||
mInputList.RemoveElementAt(i);
|
||||
|
||||
// Notify after element is removed in case we re-enter as a result.
|
||||
if (needNotify) {
|
||||
mon.Notify();
|
||||
if (action == NotifyMonitor) {
|
||||
mon.NotifyAll();
|
||||
}
|
||||
|
||||
return;
|
||||
|
@ -746,13 +812,13 @@ nsPipe::OnPipeException(nsresult aReason, bool aOutputOnly)
|
|||
continue;
|
||||
}
|
||||
|
||||
if (mInputList[i]->OnInputException(aReason, events)) {
|
||||
if (mInputList[i]->OnInputException(aReason, events) == NotifyMonitor) {
|
||||
needNotify = true;
|
||||
}
|
||||
}
|
||||
mInputList = tmpInputList;
|
||||
|
||||
if (mOutput.OnOutputException(aReason, events)) {
|
||||
if (mOutput.OnOutputException(aReason, events) == NotifyMonitor) {
|
||||
needNotify = true;
|
||||
}
|
||||
|
||||
|
@ -941,10 +1007,10 @@ nsPipeInputStream::Wait()
|
|||
return Status() == NS_BASE_STREAM_CLOSED ? NS_OK : Status();
|
||||
}
|
||||
|
||||
bool
|
||||
MonitorAction
|
||||
nsPipeInputStream::OnInputReadable(uint32_t aBytesWritten, nsPipeEvents& aEvents)
|
||||
{
|
||||
bool result = false;
|
||||
MonitorAction result = DoNotNotifyMonitor;
|
||||
|
||||
mAvailable += aBytesWritten;
|
||||
|
||||
|
@ -953,19 +1019,19 @@ nsPipeInputStream::OnInputReadable(uint32_t aBytesWritten, nsPipeEvents& aEvents
|
|||
mCallback = 0;
|
||||
mCallbackFlags = 0;
|
||||
} else if (mBlocked) {
|
||||
result = true;
|
||||
result = NotifyMonitor;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
MonitorAction
|
||||
nsPipeInputStream::OnInputException(nsresult aReason, nsPipeEvents& aEvents)
|
||||
{
|
||||
LOG(("nsPipeInputStream::OnInputException [this=%x reason=%x]\n",
|
||||
this, aReason));
|
||||
|
||||
bool result = false;
|
||||
MonitorAction result = DoNotNotifyMonitor;
|
||||
|
||||
NS_ASSERTION(NS_FAILED(aReason), "huh? successful exception");
|
||||
|
||||
|
@ -974,14 +1040,14 @@ nsPipeInputStream::OnInputException(nsresult aReason, nsPipeEvents& aEvents)
|
|||
}
|
||||
|
||||
// force count of available bytes to zero.
|
||||
mAvailable = 0;
|
||||
mPipe->DrainInputStream(mReadState, aEvents, &mAvailable);
|
||||
|
||||
if (mCallback) {
|
||||
aEvents.NotifyInputReady(this, mCallback);
|
||||
mCallback = 0;
|
||||
mCallbackFlags = 0;
|
||||
} else if (mBlocked) {
|
||||
result = true;
|
||||
result = NotifyMonitor;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
@ -1322,10 +1388,10 @@ nsPipeOutputStream::Wait()
|
|||
return mPipe->mStatus == NS_BASE_STREAM_CLOSED ? NS_OK : mPipe->mStatus;
|
||||
}
|
||||
|
||||
bool
|
||||
MonitorAction
|
||||
nsPipeOutputStream::OnOutputWritable(nsPipeEvents& aEvents)
|
||||
{
|
||||
bool result = false;
|
||||
MonitorAction result = DoNotNotifyMonitor;
|
||||
|
||||
mWritable = true;
|
||||
|
||||
|
@ -1334,19 +1400,19 @@ nsPipeOutputStream::OnOutputWritable(nsPipeEvents& aEvents)
|
|||
mCallback = 0;
|
||||
mCallbackFlags = 0;
|
||||
} else if (mBlocked) {
|
||||
result = true;
|
||||
result = NotifyMonitor;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
MonitorAction
|
||||
nsPipeOutputStream::OnOutputException(nsresult aReason, nsPipeEvents& aEvents)
|
||||
{
|
||||
LOG(("nsPipeOutputStream::OnOutputException [this=%x reason=%x]\n",
|
||||
this, aReason));
|
||||
|
||||
bool result = false;
|
||||
MonitorAction result = DoNotNotifyMonitor;
|
||||
|
||||
NS_ASSERTION(NS_FAILED(aReason), "huh? successful exception");
|
||||
mWritable = false;
|
||||
|
@ -1356,7 +1422,7 @@ nsPipeOutputStream::OnOutputException(nsresult aReason, nsPipeEvents& aEvents)
|
|||
mCallback = 0;
|
||||
mCallbackFlags = 0;
|
||||
} else if (mBlocked) {
|
||||
result = true;
|
||||
result = NotifyMonitor;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
|
|
@ -94,4 +94,22 @@ ConsumeAndValidateStream(nsIInputStream* aStream,
|
|||
ASSERT_TRUE(aExpectedData.Equals(outputData));
|
||||
}
|
||||
|
||||
NS_IMPL_ISUPPORTS(OutputStreamCallback, nsIOutputStreamCallback);
|
||||
|
||||
OutputStreamCallback::OutputStreamCallback()
|
||||
: mCalled(false)
|
||||
{
|
||||
}
|
||||
|
||||
OutputStreamCallback::~OutputStreamCallback()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
OutputStreamCallback::OnOutputStreamReady(nsIAsyncOutputStream* aStream)
|
||||
{
|
||||
mCalled = true;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
} // namespace testing
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче