Merge inbound to m-c. a=merge

This commit is contained in:
Ryan VanderMeulen 2015-02-21 16:40:27 -05:00
commit 1c4d542a01
102 changed files with 2961 additions and 490 deletions

View File

@ -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.

View File

@ -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

View File

@ -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>

View File

@ -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}"),

View File

@ -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

View File

@ -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.

View File

@ -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…">

View File

@ -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.

View File

@ -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)));
}
//-----------------------------------------------------------------------------

View File

@ -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() {}

View File

@ -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) {

View File

@ -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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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

View File

@ -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;

View File

@ -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);

View File

@ -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)) {

View File

@ -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.

View File

@ -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,

View File

@ -92,6 +92,7 @@ protected:
nsresult ResetOutputBuffers();
void DecoderLoop();
nsresult GetInputBuffer(JNIEnv* env, int index, jni::Object::LocalRef* buffer);
virtual void ClearQueue();
};

View File

@ -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()
{

View File

@ -259,6 +259,7 @@ protected:
void InitAsyncSurrogates();
protected:
void NotifyFlashHang();
void NotifyPluginCrashed();
void OnInitFailure();

View File

@ -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);

View File

@ -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();

View File

@ -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)
{

View File

@ -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

View File

@ -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;
}

View File

@ -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"

View File

@ -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']

View File

@ -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");

View File

@ -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
}
})()
}

View File

@ -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__.

View File

@ -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) {

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -228,8 +228,10 @@ function testSharedTypedArrayMethods() {
assertEq(v[9], -5);
}
testSharedArrayBuffer();
testSharedTypedArray();
testSharedTypedArrayMethods();
if (typeof SharedArrayBuffer === "function") {
testSharedArrayBuffer();
testSharedTypedArray();
testSharedTypedArrayMethods();
}
reportCompare(0, 0, 'ok');

View File

@ -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 = &REGS.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);

View File

@ -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]] *************************************************************************************/

View File

@ -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 <>

View File

@ -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))

BIN
layout/base/tests/Ahem.ttf Normal file

Binary file not shown.

View File

@ -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]

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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);
}
}

View File

@ -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) {}

View File

@ -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();

View File

@ -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;

View File

@ -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

View File

@ -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)

View File

@ -642,6 +642,7 @@ private:
}
friend class mozilla::dom::Selection;
friend struct mozilla::AutoPrepareFocusRange;
#ifdef DEBUG
void printSelection(); // for debugging
#endif /* DEBUG */

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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>

View File

@ -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() {

View File

@ -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; }

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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; }

View File

@ -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

View File

@ -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);

View File

@ -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.

View File

@ -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()

View File

@ -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

View File

@ -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,

View File

@ -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)

View File

@ -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)
{

View File

@ -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,

View File

@ -38,6 +38,7 @@ typedef struct _MacSandboxInfo {
MacSandboxPluginInfo pluginInfo;
nsCString appPath;
nsCString appBinaryPath;
nsCString appDir;
} MacSandboxInfo;
namespace mozilla {

View File

@ -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);

View File

@ -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"
}
}
}
}

View File

@ -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",

View File

@ -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"
}
}
}
}

View File

@ -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)

View File

@ -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,

View File

@ -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",

View File

@ -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…">

View File

@ -39,3 +39,4 @@
<!ENTITY plugin.file "File">
<!ENTITY plugin.mimeTypes "MIME Types">
<!ENTITY plugin.flashProtectedMode.label "Enable Adobe Flash protected mode">

View File

@ -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");

View File

@ -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>

View File

@ -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>

View File

@ -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() {

View File

@ -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() {

View File

@ -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();
});

View File

@ -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

View File

@ -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.

View File

@ -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.

View File

@ -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;

View File

@ -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

Some files were not shown because too many files have changed in this diff Show More