Merge m-c to fx-team.

This commit is contained in:
Ryan VanderMeulen 2013-08-19 11:54:12 -04:00
commit 4dbf69049f
26 changed files with 778 additions and 37 deletions

View File

@ -35,6 +35,7 @@ pref("prompts.tab_modal.enabled", true);
// Enable off main thread compositing
pref("layers.offmainthreadcomposition.enabled", true);
pref("layers.async-pan-zoom.enabled", false);
pref("layers.componentalpha.enabled", false);
pref("gfx.axis.fling_friction", "0.002");
// Enable Microsoft TSF support by default for imes.

View File

@ -615,6 +615,8 @@ MOCHITEST_FILES_C= \
file_mixed_content_frameNavigation_secure.html \
file_mixed_content_frameNavigation_secure_grandchild.html \
file_mixed_content_frameNavigation_blankTarget.html \
file_bug902350.html \
file_bug902350_frame.html \
test_bug789856.html \
file_bug804395.jar \
test_bug804395.html \
@ -705,6 +707,7 @@ MOCHITEST_FILES_PARTS = $(foreach s,A B C,MOCHITEST_FILES_$(s))
MOCHITEST_BROWSER_FILES = \
browser_bug593387.js \
browser_bug902350.js \
$(NULL)
include $(topsrcdir)/config/rules.mk

View File

@ -0,0 +1,65 @@
/*
* Mixed Content Block frame navigates for target="_top" - Test for Bug 902350
*/
const PREF_ACTIVE = "security.mixed_content.block_active_content";
const gHttpTestRoot = "https://example.com/tests/content/base/test/";
var origBlockActive;
var gTestBrowser = null;
registerCleanupFunction(function() {
// Set preferences back to their original values
Services.prefs.setBoolPref(PREF_ACTIVE, origBlockActive);
});
function MixedTestsCompleted() {
gBrowser.removeCurrentTab();
window.focus();
finish();
}
function test() {
waitForExplicitFinish();
origBlockActive = Services.prefs.getBoolPref(PREF_ACTIVE);
Services.prefs.setBoolPref(PREF_ACTIVE, true);
var newTab = gBrowser.addTab();
gBrowser.selectedTab = newTab;
gTestBrowser = gBrowser.selectedBrowser;
newTab.linkedBrowser.stop()
gTestBrowser.addEventListener("load", MixedTest1A, true);
var url = gHttpTestRoot + "file_bug902350.html";
gTestBrowser.contentWindow.location = url;
}
// Need to capture 2 loads, one for the main page and one for the iframe
function MixedTest1A() {
gTestBrowser.removeEventListener("load", MixedTest1A, true);
gTestBrowser.addEventListener("load", MixedTest1B, true);
}
// Find the iframe and click the link in it
function MixedTest1B() {
gTestBrowser.removeEventListener("load", MixedTest1B, true);
gTestBrowser.addEventListener("load", MixedTest1C, true);
var frame = content.document.getElementById("testing_frame");
var topTarget = frame.contentWindow.document.getElementById("topTarget");
topTarget.click();
// The link click should have caused a load and should not invoke the Mixed Content Blocker
var notification = PopupNotifications.getNotification("mixed-content-blocked", gTestBrowser);
ok(!notification, "Mixed Content Doorhanger appears when trying to navigate top");
}
function MixedTest1C() {
gTestBrowser.removeEventListener("load", MixedTest1C, true);
ok(gTestBrowser.contentWindow.location == "http://example.com/", "Navigating to insecure domain through target='_top' failed.")
MixedTestsCompleted();
}

View File

@ -0,0 +1,19 @@
<DOCTYPE HTML>
<html>
<!--
Test for Mixed Content Blocker target="_top" frame navigation
https://bugzilla.mozilla.org/show_bug.cgi?id=902350
-->
<head>
<meta charset="utf-8">
<title>Test for Bug 902350</title>
</head>
<body>
<div id="framediv">
<iframe src="https://example.com/tests/content/base/test/file_bug902350_frame.html" id="testing_frame"></iframe>
</div>
</body>
</html>

View File

@ -0,0 +1,14 @@
<!DOCTYPE HTML>
<html>
<!--
Tests for Mixed Content Blocker - Opening link with _top target from an https iframe.
https://bugzilla.mozilla.org/show_bug.cgi?id=902350
-->
<head>
<meta charset="utf-8">
<title>Tests for Mixed Content Frame Navigation</title>
</head>
<body>
<a href="http://example.com/" id="topTarget" target="_top">Go to http site</a>
</body>
</html>

View File

@ -8635,6 +8635,7 @@ nsDocShell::InternalLoad(nsIURI * aURI,
int16_t shouldLoad = nsIContentPolicy::ACCEPT;
uint32_t contentType;
bool isNewDocShell = false;
bool isTargetTopLevelDocShell = false;
nsCOMPtr<nsIDocShell> targetDocShell;
if (aWindowTarget && *aWindowTarget) {
// Locate the target DocShell.
@ -8646,8 +8647,23 @@ nsDocShell::InternalLoad(nsIURI * aURI,
// If the targetDocShell doesn't exist, then this is a new docShell
// and we should consider this a TYPE_DOCUMENT load
isNewDocShell = !targetDocShell;
// If the targetDocShell and the rootDocShell are the same, then the
// targetDocShell is the top level document and hence we should
// consider this TYPE_DOCUMENT
if (targetDocShell) {
nsCOMPtr<nsIDocShellTreeItem> sameTypeRoot;
targetDocShell->GetSameTypeRootTreeItem(getter_AddRefs(sameTypeRoot));
NS_ASSERTION(sameTypeRoot, "No document shell root tree item from targetDocShell!");
nsCOMPtr<nsIDocShell> rootShell = do_QueryInterface(sameTypeRoot);
NS_ASSERTION(rootShell, "No root docshell from document shell root tree item.");
if (targetDocShell == rootShell) {
isTargetTopLevelDocShell = true;
}
}
}
if (IsFrame() && !isNewDocShell) {
if (IsFrame() && !isNewDocShell && !isTargetTopLevelDocShell) {
NS_ASSERTION(requestingElement, "A frame but no DOM element!?");
contentType = nsIContentPolicy::TYPE_SUBDOCUMENT;
} else {

View File

@ -189,6 +189,27 @@ nsJSUtils::CompileFunction(JSContext* aCx,
return NS_OK;
}
class MOZ_STACK_CLASS AutoDontReportUncaught {
JSContext* mContext;
bool mWasSet;
public:
AutoDontReportUncaught(JSContext* aContext) : mContext(aContext) {
MOZ_ASSERT(aContext);
uint32_t oldOptions = JS_GetOptions(mContext);
mWasSet = oldOptions & JSOPTION_DONT_REPORT_UNCAUGHT;
if (!mWasSet) {
JS_SetOptions(mContext, oldOptions | JSOPTION_DONT_REPORT_UNCAUGHT);
}
}
~AutoDontReportUncaught() {
if (!mWasSet) {
JS_SetOptions(mContext,
JS_GetOptions(mContext) & ~JSOPTION_DONT_REPORT_UNCAUGHT);
}
}
};
nsresult
nsJSUtils::EvaluateString(JSContext* aCx,
const nsAString& aScript,
@ -224,6 +245,13 @@ nsJSUtils::EvaluateString(JSContext* aCx,
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(ok, NS_OK);
mozilla::Maybe<AutoDontReportUncaught> dontReport;
if (!aEvaluateOptions.reportUncaught) {
// We need to prevent AutoLastFrameCheck from reporting and clearing
// any pending exceptions.
dontReport.construct(aCx);
}
// Scope the JSAutoCompartment so that we can later wrap the return value
// into the caller's cx.
{

View File

@ -184,6 +184,7 @@ AppendToString(nsACString& s, const Filter filter,
s += pfx;
switch (filter) {
case FILTER_GOOD: s += "FILTER_GOOD"; break;
case FILTER_LINEAR: s += "FILTER_LINEAR"; break;
case FILTER_POINT: s += "FILTER_POINT"; break;
}

View File

@ -320,7 +320,11 @@ DeprecatedTextureClientShmem::EnsureAllocated(gfx::IntSize aSize,
NS_WARNING("creating SurfaceDescriptor failed!");
}
if (mContentType == gfxASurface::CONTENT_COLOR_ALPHA) {
nsRefPtr<gfxContext> context = new gfxContext(GetSurface());
gfxASurface* surface = GetSurface();
if (!surface) {
return false;
}
nsRefPtr<gfxContext> context = new gfxContext(surface);
context->SetColor(gfxRGBA(0, 0, 0, 0));
context->SetOperator(gfxContext::OPERATOR_SOURCE);
context->Paint();
@ -332,16 +336,17 @@ DeprecatedTextureClientShmem::EnsureAllocated(gfx::IntSize aSize,
void
DeprecatedTextureClientShmem::SetDescriptor(const SurfaceDescriptor& aDescriptor)
{
if (IsSurfaceDescriptorValid(aDescriptor)) {
ReleaseResources();
mDescriptor = aDescriptor;
} else {
if (aDescriptor.type() == SurfaceDescriptor::Tnull_t) {
EnsureAllocated(mSize, mContentType);
return;
}
MOZ_ASSERT(!mSurface);
ReleaseResources();
mDescriptor = aDescriptor;
NS_ASSERTION(mDescriptor.type() == SurfaceDescriptor::TSurfaceDescriptorGralloc ||
MOZ_ASSERT(!mSurface);
NS_ASSERTION(mDescriptor.type() == SurfaceDescriptor::T__None ||
mDescriptor.type() == SurfaceDescriptor::TSurfaceDescriptorGralloc ||
mDescriptor.type() == SurfaceDescriptor::TShmem ||
mDescriptor.type() == SurfaceDescriptor::TMemoryImage ||
mDescriptor.type() == SurfaceDescriptor::TRGBImage,
@ -375,6 +380,10 @@ DeprecatedTextureClientShmem::LockDrawTarget()
}
gfxASurface* surface = GetSurface();
if (!surface) {
return nullptr;
}
mDrawTarget = gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(surface, mSize);
return mDrawTarget;
@ -394,7 +403,11 @@ gfxImageSurface*
DeprecatedTextureClientShmem::LockImageSurface()
{
if (!mSurfaceAsImage) {
mSurfaceAsImage = GetSurface()->GetAsImageSurface();
gfxASurface* surface = GetSurface();
if (!surface) {
return nullptr;
}
mSurfaceAsImage = surface->GetAsImageSurface();
}
return mSurfaceAsImage.get();
@ -417,13 +430,13 @@ DeprecatedTextureClientShmemYCbCr::ReleaseResources()
void
DeprecatedTextureClientShmemYCbCr::SetDescriptor(const SurfaceDescriptor& aDescriptor)
{
MOZ_ASSERT(aDescriptor.type() == SurfaceDescriptor::TYCbCrImage);
MOZ_ASSERT(aDescriptor.type() == SurfaceDescriptor::TYCbCrImage ||
aDescriptor.type() == SurfaceDescriptor::T__None);
if (IsSurfaceDescriptorValid(mDescriptor)) {
GetForwarder()->DestroySharedSurface(&mDescriptor);
}
mDescriptor = aDescriptor;
MOZ_ASSERT(IsSurfaceDescriptorValid(mDescriptor));
}
void

View File

@ -362,17 +362,18 @@ gfxPlatform::Init()
mozilla::gl::GLContext::StaticInit();
#endif
bool useOffMainThreadCompositing = GetPrefLayersOffMainThreadCompositionEnabled() ||
Preferences::GetBool("browser.tabs.remote", false);
useOffMainThreadCompositing &= GetPlatform()->SupportsOffMainThreadCompositing();
bool useOffMainThreadCompositing = OffMainThreadCompositionRequired() ||
GetPrefLayersOffMainThreadCompositionEnabled();
if (useOffMainThreadCompositing && (XRE_GetProcessType() ==
GeckoProcessType_Default)) {
if (!OffMainThreadCompositionRequired()) {
useOffMainThreadCompositing &= GetPlatform()->SupportsOffMainThreadCompositing();
}
if (useOffMainThreadCompositing && (XRE_GetProcessType() == GeckoProcessType_Default)) {
CompositorParent::StartUp();
if (Preferences::GetBool("layers.async-video.enabled",false)) {
if (Preferences::GetBool("layers.async-video.enabled", false)) {
ImageBridgeChild::StartUp();
}
}
nsresult rv;
@ -1886,6 +1887,7 @@ static bool sLayersSupportsD3D9 = true;
static int sPrefLayoutFrameRate = -1;
static bool sBufferRotationEnabled = false;
static bool sComponentAlphaEnabled = true;
static bool sPrefBrowserTabsRemote = false;
static bool sLayersAccelerationPrefsInitialized = false;
@ -1904,6 +1906,7 @@ InitLayersAccelerationPrefs()
sPrefLayoutFrameRate = Preferences::GetInt("layout.frame_rate", -1);
sBufferRotationEnabled = Preferences::GetBool("layers.bufferrotation.enabled", true);
sComponentAlphaEnabled = Preferences::GetBool("layers.componentalpha.enabled", true);
sPrefBrowserTabsRemote = Preferences::GetBool("browser.tabs.remote", false);
nsCOMPtr<nsIGfxInfo> gfxInfo = do_GetService("@mozilla.org/gfx/info;1");
if (gfxInfo) {
@ -1942,6 +1945,12 @@ gfxPlatform::GetPrefLayersAccelerationForceEnabled()
return sPrefLayersAccelerationForceEnabled;
}
bool gfxPlatform::OffMainThreadCompositionRequired()
{
InitLayersAccelerationPrefs();
return sPrefBrowserTabsRemote;
}
bool
gfxPlatform::GetPrefLayersAccelerationDisabled()
{

View File

@ -487,6 +487,8 @@ public:
static bool CanUseDirect3D9();
static int GetPrefLayoutFrameRate();
static bool OffMainThreadCompositionRequired();
/**
* Is it possible to use buffer rotation
*/

View File

@ -502,7 +502,8 @@ gfxPlatformGtk::GetScreenDepth() const
bool
gfxPlatformGtk::SupportsOffMainThreadCompositing()
{
#ifdef MOZ_X11
// Nightly builds have OMTC support by default for Electrolysis testing.
#if defined(MOZ_X11) && !defined(NIGHTLY_BUILD)
return (PR_GetEnv("MOZ_USE_OMTC") != nullptr) ||
(PR_GetEnv("MOZ_OMTC_ENABLED") != nullptr);
#else

View File

@ -228,9 +228,12 @@ InterpreterStack::purge(JSRuntime *rt)
uint8_t *
InterpreterStack::allocateFrame(JSContext *cx, size_t size)
{
size_t maxFrames = cx->compartment()->principals == cx->runtime()->trustedPrincipals()
? MAX_FRAMES_TRUSTED
: MAX_FRAMES;
size_t maxFrames;
if (cx->compartment()->principals == cx->runtime()->trustedPrincipals())
maxFrames = MAX_FRAMES_TRUSTED;
else
maxFrames = MAX_FRAMES;
if (JS_UNLIKELY(frameCount_ >= maxFrames)) {
js_ReportOverRecursed(cx);
return NULL;

View File

@ -37,6 +37,8 @@
#include "mozilla/Telemetry.h"
#include "mozilla/XPTInterfaceInfoManager.h"
#include "nsDOMClassInfoID.h"
#include "nsGlobalWindow.h"
using namespace mozilla;
using namespace js;
@ -2935,6 +2937,353 @@ CreateXMLHttpRequest(JSContext *cx, unsigned argc, jsval *vp)
return true;
}
bool
NewFunctionForwarder(JSContext *cx, HandleId id, HandleObject callable,
bool doclone, MutableHandleValue vp);
/*
* Instead of simply wrapping a function into another compartment,
* this helper function creates a native function in the target
* compartment and forwards the call to the original function.
* That call will be different than a regular JS function call in
* that, the |this| is left unbound, and all the non-native JS
* object arguments will be cloned using the structured clone
* algorithm.
* The return value is the new forwarder function, wrapped into
* the caller's compartment.
* The 3rd argument is the name of the property that will
* be set on the target scope, with the forwarder function as
* the value.
* The principal of the caller must subsume that of the target.
*
* Expected type of the arguments and the return value:
* function exportFunction(function funToExport,
* object targetScope,
* string name)
*/
static bool
ExportFunction(JSContext *cx, unsigned argc, jsval *vp)
{
MOZ_ASSERT(cx);
if (argc < 3) {
JS_ReportError(cx, "Function requires at least 3 arguments");
return false;
}
CallArgs args = CallArgsFromVp(argc, vp);
if (!args[0].isObject() || !args[1].isObject() || !args[2].isString()) {
JS_ReportError(cx, "Invalid argument");
return false;
}
RootedObject funObj(cx, &args[0].toObject());
RootedObject targetScope(cx, &args[1].toObject());
RootedString funName(cx, args[2].toString());
// We can only export functions to scopes those are transparent for us,
// so if there is a security wrapper around targetScope we must throw.
targetScope = CheckedUnwrap(targetScope);
if (!targetScope) {
JS_ReportError(cx, "Permission denied to export function into scope");
return false;
}
if (JS_GetStringLength(funName) == 0) {
JS_ReportError(cx, "3rd argument should be a non-empty string");
return false;
}
{
// We need to operate in the target scope from here on, let's enter
// its compartment.
JSAutoCompartment ac(cx, targetScope);
// Unwrapping to see if we have a callable.
funObj = UncheckedUnwrap(funObj);
if (!JS_ObjectIsCallable(cx, funObj)) {
JS_ReportError(cx, "First argument must be a function");
return false;
}
// The function forwarder will live in the target compartment. Since
// this function will be referenced from its private slot, to avoid a
// GC hazard, we must wrap it to the same compartment.
if (!JS_WrapObject(cx, funObj.address()))
return false;
RootedId id(cx);
if (!JS_ValueToId(cx, args[2], id.address()))
return false;
// And now, let's create the forwarder function in the target compartment
// for the function the be exported.
if (!NewFunctionForwarder(cx, id, funObj, /* doclone = */ true, args.rval())) {
JS_ReportError(cx, "Exporting function failed");
return false;
}
// We have the forwarder function in the target compartment, now
// we have to add it to the target scope as a property.
if (!JS_DefinePropertyById(cx, targetScope, id, args.rval(),
JS_PropertyStub, JS_StrictPropertyStub,
JSPROP_ENUMERATE))
return false;
}
// Finally we have to re-wrap the exported function back to the caller compartment.
if (!JS_WrapValue(cx, args.rval().address()))
return false;
return true;
}
static bool
GetFilenameAndLineNumber(JSContext *cx, nsACString &filename, unsigned &lineno)
{
JSScript *script;
if (JS_DescribeScriptedCaller(cx, &script, &lineno)) {
if (const char *cfilename = JS_GetScriptFilename(cx, script)) {
filename.Assign(nsDependentCString(cfilename));
return true;
}
}
return false;
}
namespace xpc {
bool
IsReflector(JSObject *obj)
{
return IS_WN_REFLECTOR(obj) || dom::IsDOMObject(obj);
}
} /* namespace xpc */
enum ForwarderCloneTags {
SCTAG_BASE = JS_SCTAG_USER_MIN,
SCTAG_REFLECTOR
};
static JSObject *
CloneNonReflectorsRead(JSContext *cx, JSStructuredCloneReader *reader, uint32_t tag,
uint32_t data, void *closure)
{
MOZ_ASSERT(closure, "Null pointer!");
AutoObjectVector *reflectors = static_cast<AutoObjectVector *>(closure);
if (tag == SCTAG_REFLECTOR) {
MOZ_ASSERT(!data);
size_t idx;
if (JS_ReadBytes(reader, &idx, sizeof(size_t))) {
RootedObject reflector(cx, reflectors->handleAt(idx));
MOZ_ASSERT(reflector, "No object pointer?");
MOZ_ASSERT(IsReflector(reflector), "Object pointer must be a reflector!");
JS_WrapObject(cx, reflector.address());
JS_ASSERT(WrapperFactory::IsXrayWrapper(reflector) ||
IsReflector(reflector));
return reflector;
}
}
JS_ReportError(cx, "CloneNonReflectorsRead error");
return nullptr;
}
static bool
CloneNonReflectorsWrite(JSContext *cx, JSStructuredCloneWriter *writer,
Handle<JSObject *> obj, void *closure)
{
MOZ_ASSERT(closure, "Null pointer!");
// We need to maintain a list of reflectors to make sure all these objects
// are properly rooter. Only their indices will be serialized.
AutoObjectVector *reflectors = static_cast<AutoObjectVector *>(closure);
if (IsReflector(obj)) {
if (!reflectors->append(obj))
return false;
size_t idx = reflectors->length()-1;
if (JS_WriteUint32Pair(writer, SCTAG_REFLECTOR, 0) &&
JS_WriteBytes(writer, &idx, sizeof(size_t))) {
return true;
}
}
JS_ReportError(cx, "CloneNonReflectorsWrite error");
return false;
}
JSStructuredCloneCallbacks gForwarderStructuredCloneCallbacks = {
CloneNonReflectorsRead,
CloneNonReflectorsWrite,
nullptr
};
/*
* This is a special structured cloning, that clones only non-reflectors.
* The function assumes the cx is already entered the compartment we want
* to clone to, and that if val is an object is from the compartment we
* clone from.
*/
bool
CloneNonReflectors(JSContext *cx, MutableHandleValue val)
{
JSAutoStructuredCloneBuffer buffer;
AutoObjectVector rootedReflectors(cx);
{
// For parsing val we have to enter its compartment.
// (unless it's a primitive)
Maybe<JSAutoCompartment> ac;
if (val.isObject()) {
ac.construct(cx, &val.toObject());
}
if (!buffer.write(cx, val,
&gForwarderStructuredCloneCallbacks,
&rootedReflectors))
{
return false;
}
}
// Now recreate the clones in the target compartment.
RootedValue rval(cx);
if (!buffer.read(cx, val.address(),
&gForwarderStructuredCloneCallbacks,
&rootedReflectors))
{
return false;
}
return true;
}
/*
* Similar to evalInSandbox except this one is used to eval a script in the
* scope of a window. Also note, that the return value and the possible exceptions
* in the script are structured cloned, unless they are natives (then they are just
* wrapped).
* Principal of the caller must subsume the target's.
*
* Expected type of the arguments:
* value evalInWindow(string script,
* object window)
*/
static bool
EvalInWindow(JSContext *cx, unsigned argc, jsval *vp)
{
MOZ_ASSERT(cx);
if (argc < 2) {
JS_ReportError(cx, "Function requires two arguments");
return false;
}
CallArgs args = CallArgsFromVp(argc, vp);
if (!args[0].isString() || !args[1].isObject()) {
JS_ReportError(cx, "Invalid arguments");
return false;
}
RootedString srcString(cx, args[0].toString());
RootedObject targetScope(cx, &args[1].toObject());
// If we cannot unwrap we must not eval in it.
targetScope = CheckedUnwrap(targetScope);
if (!targetScope) {
JS_ReportError(cx, "Permission denied to eval in target scope");
return false;
}
// Make sure that we have a window object.
RootedObject inner(cx, CheckedUnwrap(targetScope, /* stopAtOuter = */ false));
nsCOMPtr<nsIGlobalObject> global;
nsCOMPtr<nsPIDOMWindow> window;
if (!JS_IsGlobalObject(inner) ||
!(global = GetNativeForGlobal(inner)) ||
!(window = do_QueryInterface(global)))
{
JS_ReportError(cx, "Second argument must be a window");
return false;
}
nsCOMPtr<nsIScriptContext> context =
(static_cast<nsGlobalWindow*>(window.get()))->GetScriptContext();
if (!context) {
JS_ReportError(cx, "Script context needed");
return false;
}
if (!context->GetScriptsEnabled()) {
JS_ReportError(cx, "Scripts are disabled in this window");
return false;
}
nsCString filename;
unsigned lineNo;
if (!GetFilenameAndLineNumber(cx, filename, lineNo)) {
// Default values for non-scripted callers.
filename.Assign("Unknown");
lineNo = 0;
}
nsDependentJSString srcDepString;
srcDepString.init(cx, srcString);
{
// CompileOptions must be created from the context
// we will execute this script in.
JSContext *wndCx = context->GetNativeContext();
AutoCxPusher pusher(wndCx);
JS::CompileOptions compileOptions(wndCx);
compileOptions.setFileAndLine(filename.get(), lineNo);
// We don't want the JS engine to automatically report
// uncaught exceptions.
nsJSUtils::EvaluateOptions evaluateOptions;
evaluateOptions.setReportUncaught(false);
nsresult rv = nsJSUtils::EvaluateString(wndCx,
srcDepString,
targetScope,
compileOptions,
evaluateOptions,
args.rval().address());
if (NS_FAILED(rv)) {
// If there was an exception we get it as a return value, if
// the evaluation failed for some other reason, then a default
// exception is raised.
MOZ_ASSERT(!JS_IsExceptionPending(wndCx),
"Exception should be delivered as return value.");
if (args.rval().isUndefined()) {
MOZ_ASSERT(rv == NS_ERROR_OUT_OF_MEMORY);
return false;
}
// If there was an exception thrown we should set it
// on the calling context.
RootedValue exn(wndCx, args.rval());
// First we should reset the return value.
args.rval().set(UndefinedValue());
// Then clone the exception.
if (CloneNonReflectors(cx, &exn))
JS_SetPendingException(cx, exn);
return false;
}
}
// Let's clone the return value back to the callers compartment.
if (!CloneNonReflectors(cx, args.rval())) {
args.rval().set(UndefinedValue());
return false;
}
return true;
}
static bool
sandbox_enumerate(JSContext *cx, HandleObject obj)
{
@ -3350,6 +3699,12 @@ xpc_CreateSandboxObject(JSContext *cx, jsval *vp, nsISupports *prinOrSop, Sandbo
if (options.wantXHRConstructor &&
!JS_DefineFunction(cx, sandbox, "XMLHttpRequest", CreateXMLHttpRequest, 0, JSFUN_CONSTRUCTOR))
return NS_ERROR_XPC_UNEXPECTED;
if (options.wantExportHelpers &&
(!JS_DefineFunction(cx, sandbox, "exportFunction", ExportFunction, 3, 0) ||
!JS_DefineFunction(cx, sandbox, "evalInWindow", EvalInWindow, 2, 0)))
return NS_ERROR_XPC_UNEXPECTED;
}
if (vp) {
@ -3620,6 +3975,10 @@ ParseOptionsObject(JSContext *cx, jsval from, SandboxOptions &options)
"wantXHRConstructor", &options.wantXHRConstructor);
NS_ENSURE_SUCCESS(rv, rv);
rv = GetBoolPropFromOptions(cx, optionsObject,
"wantExportHelpers", &options.wantExportHelpers);
NS_ENSURE_SUCCESS(rv, rv);
rv = GetStringPropFromOptions(cx, optionsObject,
"sandboxName", options.sandboxName);
NS_ENSURE_SUCCESS(rv, rv);
@ -4205,7 +4564,7 @@ nsXPCComponents_Utils::CreateDateIn(const Value &vobj, int64_t msec, JSContext *
}
bool
FunctionWrapper(JSContext *cx, unsigned argc, Value *vp)
NonCloningFunctionForwarder(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
@ -4219,17 +4578,54 @@ FunctionWrapper(JSContext *cx, unsigned argc, Value *vp)
return JS_CallFunctionValue(cx, obj, v, args.length(), args.array(), vp);
}
/*
* Forwards the call to the exported function. Clones all the non reflectors, ignores
* the |this| argument.
*/
bool
WrapCallable(JSContext *cx, HandleObject obj, HandleId id, HandleObject propobj,
MutableHandleValue vp)
CloningFunctionForwarder(JSContext *cx, unsigned argc, Value *vp)
{
JSFunction *fun = js::NewFunctionByIdWithReserved(cx, FunctionWrapper, 0, 0,
JS_GetGlobalForObject(cx, obj), id);
CallArgs args = CallArgsFromVp(argc, vp);
RootedValue v(cx, js::GetFunctionNativeReserved(&args.callee(), 0));
NS_ASSERTION(v.isObject(), "weird function");
RootedObject origFunObj(cx, UncheckedUnwrap(&v.toObject()));
{
JSAutoCompartment ac(cx, origFunObj);
// Note: only the arguments are cloned not the |this| or the |callee|.
// Function forwarder does not use those.
for (unsigned i = 0; i < args.length(); i++) {
if (!CloneNonReflectors(cx, args[i])) {
return false;
}
}
// JS API does not support any JSObject to JSFunction conversion,
// so let's use JS_CallFunctionValue instead.
RootedValue functionVal(cx);
functionVal.setObject(*origFunObj);
if (!JS_CallFunctionValue(cx, nullptr, functionVal, args.length(), args.array(), vp))
return false;
}
// Return value must be wrapped.
return JS_WrapValue(cx, vp);
}
bool
NewFunctionForwarder(JSContext *cx, HandleId id, HandleObject callable, bool doclone,
MutableHandleValue vp)
{
JSFunction *fun = js::NewFunctionByIdWithReserved(cx, doclone ? CloningFunctionForwarder :
NonCloningFunctionForwarder,
0,0, JS::CurrentGlobalOrNull(cx), id);
if (!fun)
return false;
JSObject *funobj = JS_GetFunctionObject(fun);
js::SetFunctionNativeReserved(funobj, 0, ObjectValue(*propobj));
js::SetFunctionNativeReserved(funobj, 0, ObjectValue(*callable));
vp.setObject(*funobj);
return true;
}
@ -4267,7 +4663,7 @@ nsXPCComponents_Utils::MakeObjectPropsNormal(const Value &vobj, JSContext *cx)
if (!js::IsWrapper(propobj) || !JS_ObjectIsCallable(cx, propobj))
continue;
if (!WrapCallable(cx, obj, id, propobj, &v) ||
if (!NewFunctionForwarder(cx, id, propobj, /* doclone = */ false, &v) ||
!JS_SetPropertyById(cx, obj, id, v))
return NS_ERROR_FAILURE;
}

View File

@ -3700,6 +3700,7 @@ struct SandboxOptions {
: wantXrays(true)
, wantComponents(true)
, wantXHRConstructor(false)
, wantExportHelpers(false)
, proto(xpc_GetSafeJSContext())
, sameZoneAs(xpc_GetSafeJSContext())
{ }
@ -3707,6 +3708,7 @@ struct SandboxOptions {
bool wantXrays;
bool wantComponents;
bool wantXHRConstructor;
bool wantExportHelpers;
JS::RootedObject proto;
nsCString sandboxName;
JS::RootedObject sameZoneAs;

View File

@ -66,6 +66,8 @@ AllowXBLScope(JSCompartment *c);
bool
IsSandboxPrototypeProxy(JSObject *obj);
bool
IsReflector(JSObject *obj);
} /* namespace xpc */
namespace JS {

View File

@ -61,6 +61,7 @@ MOCHITEST_CHROME_FILES = \
test_doublewrappedcompartments.xul \
test_evalInSandbox.xul \
file_evalInSandbox.html \
test_evalInWindow.xul \
test_exnstack.xul \
test_expandosharing.xul \
file_expandosharing.jsm \

View File

@ -0,0 +1,75 @@
<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<?xml-stylesheet href="chrome://mochikit/content/tests/SimpleTest/test.css"
type="text/css"?>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=877673
-->
<window title="Mozilla Bug 877673"
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"
src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
<!-- test results are displayed in the html:body -->
<body xmlns="http://www.w3.org/1999/xhtml">
</body>
<!-- test code goes here -->
<script type="application/javascript"><![CDATA[
SimpleTest.waitForExplicitFinish();
const Cu = Components.utils;
var sb = new Cu.Sandbox("http://example.org", {wantExportHelpers: true});
sb.ok = ok;
function executeIn(frame, script, exceptionCb) {
sb.frame = frame;
sb.exceptionCb = exceptionCb;
if (exceptionCb) {
return Cu.evalInSandbox("try {evalInWindow('" + script + "',frame); ok(false, 'Exception should have been thrown.')} catch(e) {exceptionCb(e)}", sb);
}
return Cu.evalInSandbox("evalInWindow('" + script + "',frame)", sb);
}
function testSameOrigin(frame) {
frame.contentWindow.document.wrappedJSObject.str = "foobar";
is(executeIn(frame.contentWindow, "document.str"), "foobar",
"Same origin string property access.");
executeIn(frame.contentWindow, 'document.obj = {prop: "foobar"}');
is((executeIn(frame.contentWindow, "document.obj")).prop, "foobar",
"Same origin object property access (cloning).");
isnot(executeIn(frame.contentWindow, "document.obj"), frame.contentWindow.document.wrappedJSObject.obj,
"Ensure cloning for js objects.");
is(executeIn(frame.contentWindow, "document"), frame.contentWindow.document,
"Xrayables should just pass without cloning.");
is( executeIn(frame.contentWindow, "({a:{doc: document}})").a.doc, frame.contentWindow.document,
"Deep cloning works.");
executeIn(frame.contentWindow, "throw 42", function(e){is(e, 42,
"Exception was thrown from script.")});
executeIn(frame.contentDocument, "var a = 42;", function(e){ok(e.toString().indexOf("Second argument must be a window") > -1,
"Passing non-window to evalInWindow should throw.");});
testDone();
}
function testCrossOrigin(frame) {
executeIn(frame.contentWindow, "var a = 42;", function(e){ok(e.toString().indexOf("Permission denied") > -1,
"Executing script in a window from cross origin should throw.");});
testDone();
}
var testsRun = 0;
function testDone() {
if (++testsRun == 2)
SimpleTest.finish();
}
]]></script>
<iframe src="http://example.org/tests/js/xpconnect/tests/mochitest/file_empty.html"
onload="testSameOrigin(this)">
</iframe>
<iframe src="http://mochi.test:8888/tests/js/xpconnect/tests/mochitest/file_empty.html"
onload="testCrossOrigin(this)">
</iframe>
</window>

View File

@ -0,0 +1,73 @@
function run_test() {
var Cu = Components.utils;
var epsb = new Cu.Sandbox(["http://example.com", "http://example.org"], { wantExportHelpers: true });
subsb = new Cu.Sandbox("http://example.com", { wantXHRConstructor: true });
subsb2 = new Cu.Sandbox("http://example.com", { wantXHRConstructor: true });
xorigsb = new Cu.Sandbox("http://test.com");
epsb.subsb = subsb;
epsb.xorigsb = xorigsb;
epsb.do_check_true = do_check_true;
epsb.do_check_eq = do_check_eq;
epsb.do_check_neq = do_check_neq;
// Exporting should work if prinicipal of the source sandbox
// subsumes the principal of the target sandbox.
Cu.evalInSandbox("(" + function() {
Object.prototype.protoProp = "common";
var wasCalled = false;
var _this = this;
var funToExport = function(a, obj, native, mixed) {
do_check_eq(a, 42);
do_check_neq(obj, subsb.tobecloned);
do_check_eq(obj.cloned, "cloned");
do_check_eq(obj.protoProp, "common");
do_check_eq(native, subsb.native);
do_check_eq(_this, this);
do_check_eq(mixed.xrayed, subsb.xrayed);
do_check_eq(mixed.xrayed2, subsb.xrayed2);
wasCalled = true;
};
this.checkIfCalled = function() {
do_check_true(wasCalled);
wasCalled = false;
}
exportFunction(funToExport, subsb, "imported");
}.toSource() + ")()", epsb);
subsb.xrayed = Cu.evalInSandbox("(" + function () {
return new XMLHttpRequest();
}.toSource() + ")()", subsb2);
// Exported function should be able to be call from the
// target sandbox. Native arguments should be just wrapped
// every other argument should be cloned.
Cu.evalInSandbox("(" + function () {
native = new XMLHttpRequest();
xrayed2 = XPCNativeWrapper(new XMLHttpRequest());
mixed = { xrayed: xrayed, xrayed2: xrayed2 };
tobecloned = { cloned: "cloned" };
imported(42,tobecloned, native, mixed);
}.toSource() + ")()", subsb);
// Apply should work but the |this| argument should not be
// possible to be changed.
Cu.evalInSandbox("(" + function() {
imported.apply("something", [42, tobecloned, native, mixed]);
}.toSource() + ")()", subsb);
Cu.evalInSandbox("(" + function() {
checkIfCalled();
}.toSource() + ")()", epsb);
// Exporting should throw if princpal of the source sandbox does
// not subsume the principal of the target.
Cu.evalInSandbox("(" + function() {
try{
exportFunction(function(){}, this.xorigsb, "denied");
do_check_true(false);
} catch (e) {
do_check_true(e.toString().indexOf('Permission denied') > -1);
}
}.toSource() + ")()", epsb);
}

View File

@ -47,4 +47,5 @@ fail-if = os == "android"
[test_allowedDomains.js]
[test_allowedDomainsXHR.js]
[test_nuke_sandbox.js]
[test_exportFunction.js]
[test_watchdog.js]

View File

@ -568,8 +568,9 @@ Declaration::GetValue(nsCSSProperty aProperty, nsAString& aValue) const
// if font features are not enabled, pointers for fontVariant
// values above may be null since the shorthand check ignores them
// font-variant-alternates enabled ==> layout.css.font-features.enabled is true
bool fontFeaturesEnabled =
mozilla::Preferences::GetBool("layout.css.font-features.enabled");
nsCSSProps::IsEnabled(eCSSProperty_font_variant_alternates);
if (systemFont &&
systemFont->GetUnit() != eCSSUnit_None &&

View File

@ -8515,8 +8515,9 @@ CSSParserImpl::ParseFont()
eCSSProperty_font_weight
};
// font-variant-alternates enabled ==> layout.css.font-features.enabled is true
bool featuresEnabled =
mozilla::Preferences::GetBool("layout.css.font-features.enabled");
nsCSSProps::IsEnabled(eCSSProperty_font_variant_alternates);
nsCSSValue family;
if (ParseVariant(family, VARIANT_HK, nsCSSProps::kFontKTable)) {
if (ExpectEndProperty()) {

View File

@ -412,9 +412,12 @@ nsCSSProps::LookupFontDesc(const nsAString& aFontDesc)
NS_ABORT_IF_FALSE(gFontDescTable, "no lookup table, needs addref");
nsCSSFontDesc which = nsCSSFontDesc(gFontDescTable->Lookup(aFontDesc));
// font-variant-alternates enabled ==> layout.css.font-features.enabled is true
bool fontFeaturesEnabled =
nsCSSProps::IsEnabled(eCSSProperty_font_variant_alternates);
// check for unprefixed font-feature-settings/font-language-override
if (which == eCSSFontDesc_UNKNOWN &&
mozilla::Preferences::GetBool("layout.css.font-features.enabled")) {
if (which == eCSSFontDesc_UNKNOWN && fontFeaturesEnabled) {
nsAutoString prefixedProp;
prefixedProp.AppendLiteral("-moz-");
prefixedProp.Append(aFontDesc);

View File

@ -335,7 +335,11 @@ public:
static bool PrefEnabled()
{
return mozilla::Preferences::GetBool("layout.css.font-features.enabled");
// font-variant-alternates enabled ==> layout.css.font-features.enabled is true
bool fontFeaturesEnabled =
nsCSSProps::IsEnabled(eCSSProperty_font_variant_alternates);
return fontFeaturesEnabled;
}
protected:

View File

@ -3370,11 +3370,19 @@ XREMain::XRE_mainStartup(bool* aExitFlag)
// (called inside gdk_display_open). This is a requirement for off main tread compositing.
// This is done only on X11 platforms if the environment variable MOZ_USE_OMTC is set so
// as to avoid overhead when omtc is not used.
//
// On nightly builds, we call this by default to enable OMTC for Electrolysis testing. On
// aurora, beta, and release builds, there is a small tpaint regression from enabling this
// call, so it sits behind an environment variable.
//
// An environment variable is used instead of a pref on X11 platforms because we start having
// access to prefs long after the first call to XOpenDisplay which is hard to change due to
// interdependencies in the initialization.
# ifndef NIGHTLY_BUILD
if (PR_GetEnv("MOZ_USE_OMTC") ||
PR_GetEnv("MOZ_OMTC_ENABLED")) {
PR_GetEnv("MOZ_OMTC_ENABLED"))
# endif
{
XInitThreads();
}
#endif

View File

@ -1534,8 +1534,7 @@ nsChildView::ComputeShouldAccelerate(bool aDefault)
bool
nsChildView::ShouldUseOffMainThreadCompositing()
{
// Don't use OMTC (which requires OpenGL) for transparent windows or for
// popup windows.
// Don't use OMTC for transparent windows or for popup windows.
if (!mView || ![[mView window] isOpaque] ||
[[mView window] isKindOfClass:[PopupWindow class]])
return false;