Merge m-i to m-c

This commit is contained in:
Phil Ringnalda 2014-02-23 08:46:03 -08:00
commit 0a4b6f1a99
95 changed files with 1347 additions and 653 deletions

View File

@ -61,6 +61,16 @@ NS_NewHTMLTrackElement(already_AddRefed<nsINodeInfo> aNodeInfo,
namespace mozilla {
namespace dom {
// Map html attribute string values to TextTrackKind enums.
static MOZ_CONSTEXPR nsAttrValue::EnumTable kKindTable[] = {
{ "subtitles", static_cast<int16_t>(TextTrackKind::Subtitles) },
{ "captions", static_cast<int16_t>(TextTrackKind::Captions) },
{ "descriptions", static_cast<int16_t>(TextTrackKind::Descriptions) },
{ "chapters", static_cast<int16_t>(TextTrackKind::Chapters) },
{ "metadata", static_cast<int16_t>(TextTrackKind::Metadata) },
{ 0 }
};
// The default value for kKindTable is "subtitles"
static MOZ_CONSTEXPR const char* kKindTableDefaultString = kKindTable->tag;

View File

@ -21,16 +21,6 @@
namespace mozilla {
namespace dom {
// Map html attribute string values to TextTrackKind enums.
static MOZ_CONSTEXPR nsAttrValue::EnumTable kKindTable[] = {
{ "subtitles", static_cast<int16_t>(TextTrackKind::Subtitles) },
{ "captions", static_cast<int16_t>(TextTrackKind::Captions) },
{ "descriptions", static_cast<int16_t>(TextTrackKind::Descriptions) },
{ "chapters", static_cast<int16_t>(TextTrackKind::Chapters) },
{ "metadata", static_cast<int16_t>(TextTrackKind::Metadata) },
{ 0 }
};
class WebVTTListener;
class HTMLTrackElement MOZ_FINAL : public nsGenericHTMLElement

View File

@ -9,6 +9,7 @@ support-files =
[test_Image_constructor.html]
[test_appname_override.html]
[test_bug913761.html]
[test_clearTimeoutIntervalNoArg.html]
[test_constructor-assignment.html]
[test_constructor.html]
[test_document.all_unqualified.html]

View File

@ -0,0 +1,14 @@
<!DOCTYPE html>
<meta charset=utf-8>
<title>Test for clearTimeout/clearInterval with no arguments not throwing</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<div id="log"></div>
<script>
test(function() {
clearTimeout();
}, "clearTimeout with no args should not throw ");
test(function() {
clearInterval();
}, "clearInterval with no args should not throw ");
</script>

View File

@ -22,7 +22,7 @@ else
ifdef MOZ_ENABLE_DBUS
LOCAL_INCLUDES += $(MOZ_DBUS_CFLAGS)
CFLAGS += $(MOZ_DBUS_GLIB_CFLAGS)
CXXFLAGS += $(MOZ_DBUS_GLIB_CFLAGS) -DHAVE_PTHREADS
CXXFLAGS += $(MOZ_DBUS_GLIB_CFLAGS)
endif #MOZ_ENABLE_DBUS
endif #MOZ_WIDGET_TOOLKIT
endif #MOZ_B2G_BT

View File

@ -66,6 +66,7 @@ if CONFIG['MOZ_B2G_BT']:
'bluez/linux',
]
DEFINES['MOZ_BLUETOOTH_DBUS'] = True
DEFINES['HAVE_PTHREADS'] = True
FINAL_LIBRARY = 'gklayout'

View File

@ -67,9 +67,22 @@ interface nsIContentPref;
* See nsIContentPrefCallback2 below for more information about callbacks.
*/
[scriptable, uuid(86279644-6b86-4875-a228-2d2ff2f3e33b)]
[scriptable, uuid(f2507add-dc39-48e0-9147-e0270376148b)]
interface nsIContentPrefService2 : nsISupports
{
/**
* Gets all the preferences with the given name.
*
* @param name The preferences' name.
* @param context The private-browsing context, if any.
* @param callback handleResult is called once for each preference unless
* no such preferences exist, in which case handleResult
* is not called at all.
*/
void getByName(in AString name,
in nsILoadContext context,
in nsIContentPrefCallback2 callback);
/**
* Gets the preference with the given domain and name.
*

View File

@ -316,6 +316,32 @@ TabChild::HandleEvent(nsIDOMEvent* aEvent)
return NS_OK;
}
void
TabChild::InitializeRootMetrics()
{
// Calculate a really simple resolution that we probably won't
// be keeping, as well as putting the scroll offset back to
// the top-left of the page.
mLastRootMetrics.mViewport = CSSRect(CSSPoint(), kDefaultViewportSize);
mLastRootMetrics.mCompositionBounds = ScreenIntRect(ScreenIntPoint(), mInnerSize);
mLastRootMetrics.mZoom = mLastRootMetrics.CalculateIntrinsicScale();
mLastRootMetrics.mDevPixelsPerCSSPixel = mWidget->GetDefaultScale();
// We use ScreenToLayerScale(1) below in order to turn the
// async zoom amount into the gecko zoom amount.
mLastRootMetrics.mCumulativeResolution =
mLastRootMetrics.mZoom / mLastRootMetrics.mDevPixelsPerCSSPixel * ScreenToLayerScale(1);
// This is the root layer, so the cumulative resolution is the same
// as the resolution.
mLastRootMetrics.mResolution = mLastRootMetrics.mCumulativeResolution / LayoutDeviceToParentLayerScale(1);
mLastRootMetrics.mScrollOffset = CSSPoint(0, 0);
}
bool
TabChild::HasValidInnerSize()
{
return (mInnerSize.width != 0) && (mInnerSize.height != 0);
}
NS_IMETHODIMP
TabChild::Observe(nsISupports *aSubject,
const char *aTopic,
@ -352,26 +378,16 @@ TabChild::Observe(nsISupports *aSubject,
// page.
SetCSSViewport(kDefaultViewportSize);
// Calculate a really simple resolution that we probably won't
// be keeping, as well as putting the scroll offset back to
// the top-left of the page.
mLastRootMetrics.mViewport = CSSRect(CSSPoint(), kDefaultViewportSize);
mLastRootMetrics.mCompositionBounds = ScreenIntRect(ScreenIntPoint(), mInnerSize);
mLastRootMetrics.mZoom = mLastRootMetrics.CalculateIntrinsicScale();
mLastRootMetrics.mDevPixelsPerCSSPixel = mWidget->GetDefaultScale();
// We use ScreenToLayerScale(1) below in order to turn the
// async zoom amount into the gecko zoom amount.
mLastRootMetrics.mCumulativeResolution =
mLastRootMetrics.mZoom / mLastRootMetrics.mDevPixelsPerCSSPixel * ScreenToLayerScale(1);
// This is the root layer, so the cumulative resolution is the same
// as the resolution.
mLastRootMetrics.mResolution = mLastRootMetrics.mCumulativeResolution / LayoutDeviceToParentLayerScale(1);
mLastRootMetrics.mScrollOffset = CSSPoint(0, 0);
utils->SetResolution(mLastRootMetrics.mResolution.scale,
mLastRootMetrics.mResolution.scale);
HandlePossibleViewportChange();
// In some cases before-first-paint gets called before
// RecvUpdateDimensions is called and therefore before we have an
// mInnerSize value set. In such cases defer initializing the viewport
// until we we get an inner size.
if (HasValidInnerSize()) {
InitializeRootMetrics();
utils->SetResolution(mLastRootMetrics.mResolution.scale,
mLastRootMetrics.mResolution.scale);
HandlePossibleViewportChange();
}
}
}
}
@ -1458,6 +1474,9 @@ TabChild::RecvUpdateDimensions(const nsRect& rect, const nsIntSize& size, const
mOuterRect.width = rect.width;
mOuterRect.height = rect.height;
bool initialSizing = !HasValidInnerSize()
&& (size.width != 0 && size.height != 0);
mOrientation = orientation;
mInnerSize = ScreenIntSize::FromUnknownSize(
gfx::IntSize(size.width, size.height));
@ -1468,6 +1487,14 @@ TabChild::RecvUpdateDimensions(const nsRect& rect, const nsIntSize& size, const
baseWin->SetPositionAndSize(0, 0, size.width, size.height,
true);
if (initialSizing && mContentDocumentIsDisplayed) {
// If this is the first time we're getting a valid mInnerSize, and the
// before-first-paint event has already been handled, then we need to set
// up our default viewport here. See the corresponding call to
// InitializeRootMetrics in the before-first-paint handler.
InitializeRootMetrics();
}
HandlePossibleViewportChange();
return true;

View File

@ -411,6 +411,9 @@ private:
nsresult Init();
void InitializeRootMetrics();
bool HasValidInnerSize();
// Notify others that our TabContext has been updated. (At the moment, this
// sets the appropriate app-id and is-browser flags on our docshell.)
//

View File

@ -1,5 +1,3 @@
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
@ -242,10 +240,8 @@ public:
{
NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> success;
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error;
success.swap(mSuccess);
error.swap(mError);
nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> success(mSuccess);
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> error(mError);
// Only run if window is still on our active list.
if (!mManager->IsWindowStillActive(mWindowID)) {
@ -282,8 +278,8 @@ public:
}
private:
nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> mSuccess;
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mError;
already_AddRefed<nsIGetUserMediaDevicesSuccessCallback> mSuccess;
already_AddRefed<nsIDOMGetUserMediaErrorCallback> mError;
nsAutoPtr<nsTArray<nsCOMPtr<nsIMediaDevice> > > mDevices;
uint64_t mWindowID;
nsRefPtr<MediaManager> mManager;
@ -1091,16 +1087,15 @@ public:
final->MoveElementsFrom(*s);
}
NS_DispatchToMainThread(new DeviceSuccessCallbackRunnable(mWindowId,
mSuccess.forget(),
mError.forget(),
mSuccess, mError,
final.forget()));
return NS_OK;
}
private:
MediaStreamConstraintsInternal mConstraints;
nsCOMPtr<nsIGetUserMediaDevicesSuccessCallback> mSuccess;
nsCOMPtr<nsIDOMGetUserMediaErrorCallback> mError;
already_AddRefed<nsIGetUserMediaDevicesSuccessCallback> mSuccess;
already_AddRefed<nsIDOMGetUserMediaErrorCallback> mError;
nsRefPtr<MediaManager> mManager;
uint64_t mWindowId;
const nsString mCallId;

View File

@ -88,10 +88,10 @@ Window implements WindowEventHandlers;
interface WindowTimers {
[Throws] long setTimeout(Function handler, optional long timeout = 0, any... arguments);
[Throws] long setTimeout(DOMString handler, optional long timeout = 0, any... unused);
[Throws] void clearTimeout(long handle);
[Throws] void clearTimeout(optional long handle = 0);
[Throws] long setInterval(Function handler, optional long timeout, any... arguments);
[Throws] long setInterval(DOMString handler, optional long timeout, any... unused);
[Throws] void clearInterval(long handle);
[Throws] void clearInterval(optional long handle = 0);
};
Window implements WindowTimers;

View File

@ -954,7 +954,7 @@ nsXBLBinding::DoInitJSClass(JSContext *cx, JS::Handle<JSObject*> global,
// we don't have accidental collisions with the case when parent_proto is
// null and aClassName ends in some bizarre numbers (yeah, it's unlikely).
JS::Rooted<jsid> parent_proto_id(cx);
if (!::JS_GetObjectId(cx, parent_proto, parent_proto_id.address())) {
if (!::JS_GetObjectId(cx, parent_proto, &parent_proto_id)) {
// Probably OOM
return NS_ERROR_OUT_OF_MEMORY;
}

View File

@ -53,11 +53,12 @@ class GenericRefCounted : public GenericRefCountedBase
public:
virtual void AddRef() {
MOZ_ASSERT(int32_t(refCnt) >= 0);
++refCnt;
}
virtual void Release() {
MOZ_ASSERT(refCnt > 0);
MOZ_ASSERT(int32_t(refCnt) > 0);
if (0 == --refCnt) {
#ifdef DEBUG
refCnt = detail::DEAD;

View File

@ -15,7 +15,6 @@
#include "GLReadTexImageHelper.h"
#include "gfxCrashReporterUtils.h"
#include "gfxPlatform.h"
#include "gfxUtils.h"
#include "GLContextProvider.h"
#include "GLTextureImage.h"
@ -28,11 +27,11 @@
#include "GfxTexturesReporter.h"
#include "TextureGarbageBin.h"
#include "gfx2DGlue.h"
#include "gfxPrefs.h"
#include "OGLShaderProgram.h" // for ShaderProgramType
#include "mozilla/DebugOnly.h"
#include "mozilla/Preferences.h"
#ifdef XP_MACOSX
#include <CoreServices/CoreServices.h>
@ -308,7 +307,7 @@ GLContext::InitWithPrefix(const char *prefix, bool trygl)
return true;
}
mWorkAroundDriverBugs = gfxPlatform::GetPlatform()->WorkAroundDriverBugs();
mWorkAroundDriverBugs = gfxPrefs::WorkAroundDriverBugs();
SymLoadStruct symbols[] = {
{ (PRFuncPtr*) &mSymbols.fActiveTexture, { "ActiveTexture", "ActiveTextureARB", nullptr } },
@ -1333,7 +1332,7 @@ GLContext::ChooseGLFormats(const SurfaceCaps& caps) const
}
}
uint32_t msaaLevel = Preferences::GetUint("gl.msaa-level", 2);
uint32_t msaaLevel = gfxPrefs::MSAALevel();
GLsizei samples = msaaLevel * msaaLevel;
samples = std::min(samples, mMaxSamples);

View File

@ -41,8 +41,6 @@ endif
include $(topsrcdir)/config/rules.mk
CFLAGS += -DMOZ_QCMS
# Disable spammy "missing initializer" GCC warning
ifdef GNU_CC
CFLAGS += -Wno-missing-field-initializers

View File

@ -455,8 +455,6 @@ gfxPlatform::Init()
gPlatform->mOrientationSyncPrefsObserver = new OrientationSyncPrefsObserver();
Preferences::AddStrongObserver(gPlatform->mOrientationSyncPrefsObserver, "layers.orientation.sync.timeout");
gPlatform->mWorkAroundDriverBugs = Preferences::GetBool("gfx.work-around-driver-bugs", true);
mozilla::Preferences::AddBoolVarCache(&gPlatform->mWidgetUpdateFlashing,
"nglayout.debug.widget_update_flashing");

View File

@ -603,8 +603,6 @@ public:
*/
static PRLogModuleInfo* GetLog(eGfxLog aWhichLog);
bool WorkAroundDriverBugs() const { return mWorkAroundDriverBugs; }
virtual int GetScreenDepth() const;
bool WidgetUpdateFlashing() const { return mWidgetUpdateFlashing; }
@ -742,7 +740,6 @@ private:
uint32_t mContentBackendBitmask;
mozilla::widget::GfxInfoCollector<gfxPlatform> mAzureCanvasBackendCollector;
bool mWorkAroundDriverBugs;
mozilla::RefPtr<mozilla::gfx::DrawEventRecorder> mRecorder;
bool mWidgetUpdateFlashing;

View File

@ -18,7 +18,7 @@
// from any thread after that first call.
// To register a preference, you need to add a line in this file using
// the DECL_GFX_PREFS macro.
// the DECL_GFX_PREF macro.
//
// Update argument controls whether we read the preference value and save it
// or connect with a callback. See UpdatePolicy enum below.
@ -28,7 +28,7 @@
// Default is the default value for the preference.
//
// For example this line in the .h:
// DECL_GFX_PREFS(Once,"layers.dump",LayersDump,bool,false);
// DECL_GFX_PREF(Once,"layers.dump",LayersDump,bool,false);
// means that you can call
// bool var = gfxPrefs::LayersDump();
// from any thread, but that you will only get the preference value of
@ -36,7 +36,7 @@
// was not set, the default would be false.
//
// In another example, this line in the .h:
// DECL_GFX_PREFS(Live,"gl.msaa-level",MSAALevel,uint32_t,2);
// DECL_GFX_PREF(Live,"gl.msaa-level",MSAALevel,uint32_t,2);
// means that every time you call
// uint32_t var = gfxPrefs::MSAALevel();
// from any thread, you will get the most up to date preference value of
@ -51,7 +51,7 @@
// values changing mid execution, and if you're using those preferences
// in any setup and initialization, you may need to do extra work.
#define DECL_GFX_PREFS(Update, Pref, Name, Type, Default) \
#define DECL_GFX_PREF(Update, Pref, Name, Type, Default) \
public: \
static Type Name() { MOZ_ASSERT(Exists()); return One().mPref##Name.mValue; } \
private: \
@ -99,14 +99,18 @@ private:
};
public:
// This is where DECL_GFX_PREFS for each of the preferences should go.
// This is where DECL_GFX_PREF for each of the preferences should go.
// We will keep these in an alphabetical order to make it easier to see if
// a method accessing a pref already exists. Just add yours in the list.
DECL_GFX_PREF(Once, "gfx.work-around-driver-bugs", WorkAroundDriverBugs, bool, true);
DECL_GFX_PREF(Live, "gl.msaa-level", MSAALevel, uint32_t, 2);
public:
// Manage the singleton:
static gfxPrefs& One()
{
{
if (!sInstance) {
sInstance = new gfxPrefs;
}
@ -133,6 +137,6 @@ private:
gfxPrefs& operator=(const gfxPrefs&) MOZ_DELETE;
};
#undef DECL_GFX_PREFS /* Don't need it outside of this file */
#undef DECL_GFX_PREF /* Don't need it outside of this file */
#endif /* GFX_PREFS_H */

View File

@ -324,6 +324,22 @@ DisableGenerationalGC(JSRuntime *rt);
extern JS_FRIEND_API(void)
EnableGenerationalGC(JSRuntime *rt);
/* Ensure that generational GC is disabled within some scope. */
class JS_FRIEND_API(AutoDisableGenerationalGC)
{
JSRuntime *runtime;
public:
AutoDisableGenerationalGC(JSRuntime *rt)
: runtime(rt)
{
DisableGenerationalGC(rt);
}
~AutoDisableGenerationalGC() {
EnableGenerationalGC(runtime);
}
};
/*
* Returns true if generational allocation and collection is currently enabled
* on the given runtime.

View File

@ -21,9 +21,10 @@
// JS_IdToValue must be used instead.
#include "mozilla/NullPtr.h"
#include "jstypes.h"
#include "js/HeapAPI.h"
#include "js/RootingAPI.h"
#include "js/TypeDecls.h"
#include "js/Utility.h"
@ -116,6 +117,7 @@ OBJECT_TO_JSID(JSObject *obj)
jsid id;
MOZ_ASSERT(obj != nullptr);
MOZ_ASSERT(((size_t)obj & JSID_TYPE_MASK) == 0);
JS_ASSERT(!js::gc::IsInsideNursery(js::gc::GetGCThingRuntime(obj), obj));
JSID_BITS(id) = ((size_t)obj | JSID_TYPE_OBJECT);
return id;
}

View File

@ -168,39 +168,6 @@ function IsObject(v) {
/********** Testing code **********/
// This code enables testing of the custom allow-nothing wrappers used for
// objects and functions crossing the self-hosting compartment boundaries.
// Functions marked as wrappable won't be cloned into content compartments;
// they're called inside the self-hosting compartment itself. Calling is the
// only valid operation on them. In turn, the only valid way they can use their
// object arguments is as keys in maps. Doing anything else with them throws.
var wrappersTestMap = new WeakMap();
function testWrappersAllowUseAsKey(o) {
wrappersTestMap.set(o, o);
var mappedO = wrappersTestMap.get(o);
wrappersTestMap.clear();
return mappedO;
}
function testWrappersForbidAccess(o, operation) {
try {
switch (operation) {
case 'get': var result = o.prop; break;
case 'set': o.prop2 = 'value'; break;
case 'call': o(); break;
case '__proto__':
Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set.call(o, new Object());
break;
}
} catch (e) {
// Got the expected exception.
return /denied/.test(e);
}
return false;
}
MakeWrappable(testWrappersAllowUseAsKey);
MakeWrappable(testWrappersForbidAccess);
#ifdef ENABLE_PARALLEL_JS
/**

View File

@ -164,25 +164,28 @@ frontend::MaybeCallSourceHandler(JSContext *cx, const ReadOnlyCompileOptions &op
}
}
static bool
SetScriptSourceFilename(ExclusiveContext *cx, ScriptSource *ss,
const ReadOnlyCompileOptions &options)
ScriptSourceObject *
frontend::CreateScriptSourceObject(ExclusiveContext *cx, const ReadOnlyCompileOptions &options)
{
ScriptSource *ss = cx->new_<ScriptSource>(options.originPrincipals());
if (!ss)
return nullptr;
if (options.hasIntroductionInfo) {
const char *filename = options.filename() ? options.filename() : "<unknown>";
JS_ASSERT(options.introductionType != nullptr);
if (!ss->setIntroducedFilename(cx, filename, options.introductionLineno,
options.introductionType, options.introducerFilename()))
return false;
return nullptr;
ss->setIntroductionOffset(options.introductionOffset);
} else {
if (options.filename() && !ss->setFilename(cx, options.filename()))
return false;
return nullptr;
}
return true;
return ScriptSourceObject::create(cx, ss, options);
}
JSScript *
@ -218,17 +221,13 @@ frontend::CompileScript(ExclusiveContext *cx, LifoAlloc *alloc, HandleObject sco
if (!CheckLength(cx, length))
return nullptr;
JS_ASSERT_IF(staticLevel != 0, options.sourcePolicy != CompileOptions::LAZY_SOURCE);
ScriptSource *ss = cx->new_<ScriptSource>(options.originPrincipals());
if (!ss)
return nullptr;
if (!SetScriptSourceFilename(cx, ss, options))
return nullptr;
RootedScriptSource sourceObject(cx, ScriptSourceObject::create(cx, ss, options));
RootedScriptSource sourceObject(cx, CreateScriptSourceObject(cx, options));
if (!sourceObject)
return nullptr;
ScriptSource *ss = sourceObject->source();
SourceCompressionTask mysct(cx);
SourceCompressionTask *sct = extraSct ? extraSct : &mysct;
@ -514,14 +513,12 @@ CompileFunctionBody(JSContext *cx, MutableHandleFunction fun, const ReadOnlyComp
if (!CheckLength(cx, length))
return false;
ScriptSource *ss = cx->new_<ScriptSource>(options.originPrincipals());
if (!ss)
return false;
if (!SetScriptSourceFilename(cx, ss, options))
return false;
RootedScriptSource sourceObject(cx, ScriptSourceObject::create(cx, ss, options));
RootedScriptSource sourceObject(cx, CreateScriptSourceObject(cx, options));
if (!sourceObject)
return false;
return nullptr;
ScriptSource *ss = sourceObject->source();
SourceCompressionTask sct(cx);
JS_ASSERT(options.sourcePolicy != CompileOptions::LAZY_SOURCE);
if (options.sourcePolicy == CompileOptions::SAVE_SOURCE) {

View File

@ -39,6 +39,9 @@ CompileStarGeneratorBody(JSContext *cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions &options,
const AutoNameVector &formals, const jschar *chars, size_t length);
ScriptSourceObject *
CreateScriptSourceObject(ExclusiveContext *cx, const ReadOnlyCompileOptions &options);
/*
* This should be called while still on the main thread if compilation will
* occur on a worker thread.

View File

@ -1,3 +1,6 @@
// FIXME bug 975456
quit();
if (!this.hasOwnProperty("TypedObject"))
quit();

View File

@ -1,3 +1,6 @@
// FIXME bug 975456
quit();
// Test the case where we neuter an instance of a fixed-sized array.
// This is a bit of a tricky case because we cannot (necessarily) fold
// the neuter check into the bounds check, as we obtain the bounds

View File

@ -1,6 +1,8 @@
load(libdir + "parallelarray-helpers.js");
var spew = getSelfHostedValue("ParallelSpew");
try {
var spew = getSelfHostedValue("ParallelSpew");
} catch (e) {}
if (getBuildConfiguration().parallelJS && spew) {
assertParallelExecSucceeds(
function (m) { Array.buildPar(minItemsTestingThreshold,

View File

@ -1,36 +0,0 @@
var testObject = {prop:'value'};
var testWrappersAllowUseAsKey = getSelfHostedValue('testWrappersAllowUseAsKey');
assertEq(typeof testWrappersAllowUseAsKey, 'function');
assertEq(testWrappersAllowUseAsKey(testObject), testObject);
var testWrappersForbidAccess = getSelfHostedValue('testWrappersForbidAccess');
assertEq(typeof testWrappersForbidAccess, 'function');
assertEq(testWrappersForbidAccess(testObject, 'get'), true);
assertEq(testWrappersForbidAccess(testObject, 'set'), true);
assertEq(testWrappersForbidAccess(function(){}, 'call'), true);
assertEq(testWrappersForbidAccess(testObject, '__proto__'), true);
var wrappedFunction = testWrappersForbidAccess;
function testWrappersAllowCallsOnly(fun, operation) {
try {
switch (operation) {
case 'get': var result = fun.prop; break;
case 'set': fun.prop2 = 'value'; break;
case 'call': o(); break;
case '__proto__':
Object.getOwnPropertyDescriptor(Object.prototype, '__proto__').set.call(fun, new Object());
break;
}
} catch (e) {
// Got the expected exception.
return /denied/.test(e);
}
return false;
}
assertEq(testWrappersAllowCallsOnly(wrappedFunction, 'get'), true);
assertEq(testWrappersAllowCallsOnly(wrappedFunction, 'set'), true);
assertEq(testWrappersAllowCallsOnly(wrappedFunction, '__proto__'), true);
assertEq(testWrappersAllowCallsOnly(wrappedFunction, 'call'), false);

View File

@ -697,17 +697,23 @@ ICStubCompiler::guardProfilingEnabled(MacroAssembler &masm, Register scratch, La
#ifdef JSGC_GENERATIONAL
inline bool
ICStubCompiler::emitPostWriteBarrierSlot(MacroAssembler &masm, Register obj, Register scratch,
GeneralRegisterSet saveRegs)
ICStubCompiler::emitPostWriteBarrierSlot(MacroAssembler &masm, Register obj, ValueOperand val,
Register scratch, GeneralRegisterSet saveRegs)
{
Nursery &nursery = cx->runtime()->gcNursery;
Label skipBarrier;
masm.branchTestObject(Assembler::NotEqual, val, &skipBarrier);
Label isTenured;
masm.branchPtr(Assembler::Below, obj, ImmWord(nursery.start()), &isTenured);
masm.branchPtr(Assembler::Below, obj, ImmWord(nursery.heapEnd()), &skipBarrier);
masm.bind(&isTenured);
Register valReg = masm.extractObject(val, scratch);
masm.branchPtr(Assembler::Below, valReg, ImmWord(nursery.start()), &skipBarrier);
masm.branchPtr(Assembler::AboveOrEqual, valReg, ImmWord(nursery.heapEnd()), &skipBarrier);
// void PostWriteBarrier(JSRuntime *rt, JSObject *obj);
#ifdef JS_CODEGEN_ARM
saveRegs.add(BaselineTailCallReg);
@ -5215,17 +5221,13 @@ ICSetElem_Dense::Compiler::generateStubCode(MacroAssembler &masm)
EmitPreBarrier(masm, element, MIRType_Value);
masm.storeValue(tmpVal, element);
regs.add(key);
regs.add(tmpVal);
#ifdef JSGC_GENERATIONAL
Label skipBarrier;
masm.branchTestObject(Assembler::NotEqual, tmpVal, &skipBarrier);
{
Register r = regs.takeAny();
GeneralRegisterSet saveRegs;
emitPostWriteBarrierSlot(masm, obj, r, saveRegs);
emitPostWriteBarrierSlot(masm, obj, tmpVal, r, saveRegs);
regs.add(r);
}
masm.bind(&skipBarrier);
#endif
EmitReturnFromIC(masm);
@ -5402,17 +5404,13 @@ ICSetElemDenseAddCompiler::generateStubCode(MacroAssembler &masm)
masm.loadValue(valueAddr, tmpVal);
masm.storeValue(tmpVal, element);
regs.add(key);
regs.add(tmpVal);
#ifdef JSGC_GENERATIONAL
Label skipBarrier;
masm.branchTestObject(Assembler::NotEqual, tmpVal, &skipBarrier);
{
Register r = regs.takeAny();
GeneralRegisterSet saveRegs;
emitPostWriteBarrierSlot(masm, obj, r, saveRegs);
emitPostWriteBarrierSlot(masm, obj, tmpVal, r, saveRegs);
regs.add(r);
}
masm.bind(&skipBarrier);
#endif
EmitReturnFromIC(masm);
@ -7397,16 +7395,13 @@ ICSetProp_Native::Compiler::generateStubCode(MacroAssembler &masm)
if (holderReg != objReg)
regs.add(holderReg);
#ifdef JSGC_GENERATIONAL
Label skipBarrier;
masm.branchTestObject(Assembler::NotEqual, R1, &skipBarrier);
{
Register scr = regs.takeAny();
GeneralRegisterSet saveRegs;
saveRegs.add(R1);
emitPostWriteBarrierSlot(masm, objReg, scr, saveRegs);
emitPostWriteBarrierSlot(masm, objReg, R1, scr, saveRegs);
regs.add(scr);
}
masm.bind(&skipBarrier);
#endif
// The RHS has to be in R0.
@ -7522,15 +7517,12 @@ ICSetPropNativeAddCompiler::generateStubCode(MacroAssembler &masm)
regs.add(holderReg);
#ifdef JSGC_GENERATIONAL
Label skipBarrier;
masm.branchTestObject(Assembler::NotEqual, R1, &skipBarrier);
{
Register scr = regs.takeAny();
GeneralRegisterSet saveRegs;
saveRegs.add(R1);
emitPostWriteBarrierSlot(masm, objReg, scr, saveRegs);
emitPostWriteBarrierSlot(masm, objReg, R1, scr, saveRegs);
}
masm.bind(&skipBarrier);
#endif
// The RHS has to be in R0.

View File

@ -1077,8 +1077,8 @@ class ICStubCompiler
}
#ifdef JSGC_GENERATIONAL
inline bool emitPostWriteBarrierSlot(MacroAssembler &masm, Register obj, Register scratch,
GeneralRegisterSet saveRegs);
inline bool emitPostWriteBarrierSlot(MacroAssembler &masm, Register obj, ValueOperand val,
Register scratch, GeneralRegisterSet saveRegs);
#endif
public:

View File

@ -1352,13 +1352,6 @@ JS_GetClassPrototype(JSContext *cx, JSProtoKey key, MutableHandleObject objp)
return js_GetClassPrototype(cx, key, objp);
}
JS_PUBLIC_API(JSProtoKey)
JS_IdentifyClassPrototype(JSObject *obj)
{
JS_ASSERT(!obj->is<CrossCompartmentWrapperObject>());
return js_IdentifyClassPrototype(obj);
}
extern JS_PUBLIC_API(JSProtoKey)
JS_IdToProtoKey(JSContext *cx, HandleId id)
{
@ -2419,11 +2412,20 @@ JS_GetConstructor(JSContext *cx, HandleObject proto)
}
JS_PUBLIC_API(bool)
JS_GetObjectId(JSContext *cx, JSObject *obj, jsid *idp)
JS_GetObjectId(JSContext *cx, HandleObject obj, MutableHandleId idp)
{
AssertHeapIsIdle(cx);
assertSameCompartment(cx, obj);
*idp = OBJECT_TO_JSID(obj);
#ifdef JSGC_GENERATIONAL
// Ensure that the object is tenured before returning it.
if (IsInsideNursery(cx->runtime(), obj)) {
MinorGC(cx, JS::gcreason::EVICT_NURSERY);
MOZ_ASSERT(!IsInsideNursery(cx->runtime(), obj));
}
#endif
idp.set(OBJECT_TO_JSID(obj));
return true;
}

View File

@ -1770,8 +1770,23 @@ JS_GetClassObject(JSContext *cx, JSProtoKey key, JS::MutableHandle<JSObject*> ob
extern JS_PUBLIC_API(bool)
JS_GetClassPrototype(JSContext *cx, JSProtoKey key, JS::MutableHandle<JSObject*> objp);
namespace JS {
/*
* Determine if the given object is an instance or prototype for a standard
* class. If so, return the associated JSProtoKey. If not, return JSProto_Null.
*/
extern JS_PUBLIC_API(JSProtoKey)
JS_IdentifyClassPrototype(JSObject *obj);
IdentifyStandardInstance(JSObject *obj);
extern JS_PUBLIC_API(JSProtoKey)
IdentifyStandardPrototype(JSObject *obj);
extern JS_PUBLIC_API(JSProtoKey)
IdentifyStandardInstanceOrPrototype(JSObject *obj);
} /* namespace JS */
extern JS_PUBLIC_API(JSProtoKey)
JS_IdToProtoKey(JSContext *cx, JS::HandleId id);
@ -2555,7 +2570,7 @@ JS_GetConstructor(JSContext *cx, JS::Handle<JSObject*> proto);
* and true with *idp containing the unique id on success.
*/
extern JS_PUBLIC_API(bool)
JS_GetObjectId(JSContext *cx, JSObject *obj, jsid *idp);
JS_GetObjectId(JSContext *cx, JS::HandleObject obj, JS::MutableHandleId idp);
namespace JS {

View File

@ -22,7 +22,6 @@
#include "jit/JitCompartment.h"
#endif
#include "js/RootingAPI.h"
#include "vm/SelfHosting.h"
#include "vm/StopIterationObject.h"
#include "vm/WrapperObject.h"
@ -57,6 +56,7 @@ JSCompartment::JSCompartment(Zone *zone, const JS::CompartmentOptions &options =
typeReprs(runtime_),
globalWriteBarriered(false),
propertyTree(thisForCtor()),
selfHostingScriptSource(nullptr),
gcIncomingGrayPointers(nullptr),
gcLiveArrayBuffers(nullptr),
gcWeakMapList(nullptr),
@ -365,12 +365,10 @@ JSCompartment::wrap(JSContext *cx, MutableHandleObject obj, HandleObject existin
JS_ASSERT(global);
JS_ASSERT(objGlobal);
const JSWrapObjectCallbacks *cb;
JS_ASSERT(!cx->runtime()->isSelfHostingGlobal(global) &&
!cx->runtime()->isSelfHostingGlobal(objGlobal));
if (cx->runtime()->isSelfHostingGlobal(global) || cx->runtime()->isSelfHostingGlobal(objGlobal))
cb = &SelfHostingWrapObjectCallbacks;
else
cb = cx->runtime()->wrapObjectCallbacks;
const JSWrapObjectCallbacks *cb = cx->runtime()->wrapObjectCallbacks;
if (obj->compartment() == this)
return WrapForSameCompartment(cx, obj, cb);
@ -581,6 +579,12 @@ JSCompartment::sweep(FreeOp *fop, bool releaseTypes)
if (global_ && IsObjectAboutToBeFinalized(global_.unsafeGet()))
global_ = nullptr;
if (selfHostingScriptSource &&
IsObjectAboutToBeFinalized((JSObject **) selfHostingScriptSource.unsafeGet()))
{
selfHostingScriptSource = nullptr;
}
#ifdef JS_ION
if (jitCompartment_)
jitCompartment_->sweep(fop);

View File

@ -263,6 +263,12 @@ struct JSCompartment
js::CallsiteCloneTable callsiteClones;
void sweepCallsiteClones();
/*
* Lazily initialized script source object to use for scripts cloned
* from the self-hosting global.
*/
js::ReadBarriered<js::ScriptSourceObject> selfHostingScriptSource;
/* During GC, stores the index of this compartment in rt->compartments. */
unsigned gcIndex;

View File

@ -49,7 +49,6 @@ class JSFunction : public JSObject
// 0x0800 is available
INTERPRETED_LAZY = 0x1000, /* function is interpreted but doesn't have a script yet */
ARROW = 0x2000, /* ES6 '(args) => body' syntax */
SH_WRAPPABLE = 0x4000, /* self-hosted function is wrappable, doesn't need to be cloned */
/* Derived Flags values for convenience: */
NATIVE_FUN = 0,
@ -127,10 +126,6 @@ class JSFunction : public JSObject
bool isSelfHostedBuiltin() const { return flags() & SELF_HOSTED; }
bool isSelfHostedConstructor() const { return flags() & SELF_HOSTED_CTOR; }
bool hasRest() const { return flags() & HAS_REST; }
bool isWrappable() const {
JS_ASSERT_IF(flags() & SH_WRAPPABLE, isSelfHostedBuiltin());
return flags() & SH_WRAPPABLE;
}
bool isInterpretedLazy() const {
return flags() & INTERPRETED_LAZY;
@ -207,12 +202,6 @@ class JSFunction : public JSObject
flags_ |= SELF_HOSTED_CTOR;
}
void makeWrappable() {
JS_ASSERT(isSelfHostedBuiltin());
JS_ASSERT(!isWrappable());
flags_ |= SH_WRAPPABLE;
}
void setIsFunctionPrototype() {
JS_ASSERT(!isFunctionPrototype());
flags_ |= IS_FUN_PROTO;

View File

@ -3254,29 +3254,42 @@ js_GetClassPrototype(ExclusiveContext *cx, JSProtoKey key, MutableHandleObject p
return true;
}
JSProtoKey
js_IdentifyClassPrototype(JSObject *obj)
static bool
IsStandardPrototype(JSObject *obj, JSProtoKey key)
{
// First, get the key off the JSClass. This tells us which prototype we
// _might_ be. But we still don't know for sure, since the prototype shares
// its JSClass with instances.
JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(obj->getClass());
if (key == JSProto_Null)
return JSProto_Null;
// Now, see if the cached object matches |obj|.
//
// Note that standard class objects are cached in the range [0, JSProto_LIMIT),
// and the prototypes are cached in [JSProto_LIMIT, 2*JSProto_LIMIT).
GlobalObject &global = obj->global();
Value v = global.getPrototype(key);
if (v.isObject() && obj == &v.toObject())
return key;
return v.isObject() && obj == &v.toObject();
}
// False alarm - just an instance.
JSProtoKey
JS::IdentifyStandardInstance(JSObject *obj)
{
// Note: The prototype shares its JSClass with instances.
JS_ASSERT(!obj->is<CrossCompartmentWrapperObject>());
JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(obj->getClass());
if (key != JSProto_Null && !IsStandardPrototype(obj, key))
return key;
return JSProto_Null;
}
JSProtoKey
JS::IdentifyStandardPrototype(JSObject *obj)
{
// Note: The prototype shares its JSClass with instances.
JS_ASSERT(!obj->is<CrossCompartmentWrapperObject>());
JSProtoKey key = JSCLASS_CACHED_PROTO_KEY(obj->getClass());
if (key != JSProto_Null && IsStandardPrototype(obj, key))
return key;
return JSProto_Null;
}
JSProtoKey
JS::IdentifyStandardInstanceOrPrototype(JSObject *obj)
{
return JSCLASS_CACHED_PROTO_KEY(obj->getClass());
}
bool
js_FindClassObject(ExclusiveContext *cx, MutableHandleObject protop, const Class *clasp)
{

View File

@ -1328,13 +1328,6 @@ extern bool
js_GetClassPrototype(js::ExclusiveContext *cx, JSProtoKey key,
js::MutableHandleObject objp);
/*
* Determine if the given object is a prototype for a standard class. If so,
* return the associated JSProtoKey. If not, return JSProto_Null.
*/
extern JSProtoKey
js_IdentifyClassPrototype(JSObject *obj);
/*
* Property-lookup-based access to interface and prototype objects for classes.
* If the class is built-in (and has a non-null JSProtoKey), these forward to

View File

@ -2543,28 +2543,25 @@ Proxy::set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id
AutoEnterPolicy policy(cx, handler, proxy, id, BaseProxyHandler::SET, true);
if (!policy.allowed())
return policy.returnValue();
if (handler->hasPrototype()) {
// If we're using a prototype, we still want to use the proxy trap unless
// we have a non-own property with a setter.
bool hasOwn;
if (!handler->hasOwn(cx, proxy, id, &hasOwn))
return false;
if (!hasOwn) {
RootedObject proto(cx);
// Proxies might still use the normal prototype mechanism, rather than
// a hook, so query the engine proper
if (!JSObject::getProto(cx, proxy, &proto))
return false;
if (proto) {
Rooted<PropertyDescriptor> desc(cx);
if (!JS_GetPropertyDescriptorById(cx, proto, id, 0, &desc))
return false;
if (desc.object() && desc.setter())
return JSObject::setGeneric(cx, proto, receiver, id, vp, strict);
}
}
}
return handler->set(cx, proxy, receiver, id, strict, vp);
// If the proxy doesn't require that we consult its prototype for the
// non-own cases, we can sink to the |set| trap.
if (!handler->hasPrototype())
return handler->set(cx, proxy, receiver, id, strict, vp);
// If we have an existing (own or non-own) property with a setter, we want
// to invoke that.
Rooted<PropertyDescriptor> desc(cx);
if (!Proxy::getPropertyDescriptor(cx, proxy, id, &desc, JSRESOLVE_ASSIGNING))
return false;
if (desc.object() && desc.setter() && desc.setter() != JS_StrictPropertyStub)
return CallSetter(cx, receiver, id, desc.setter(), desc.attributes(), strict, vp);
// Ok. Either there was no pre-existing property, or it was a value prop
// that we're going to shadow. Make a property descriptor and define it.
Rooted<PropertyDescriptor> newDesc(cx);
newDesc.value().set(vp);
return handler->defineProperty(cx, receiver, id, &newDesc);
}
bool

View File

@ -29,6 +29,7 @@
#include "jsutil.h"
#include "jswrapper.h"
#include "frontend/BytecodeCompiler.h"
#include "frontend/BytecodeEmitter.h"
#include "frontend/SharedContext.h"
#include "gc/Marking.h"
@ -39,6 +40,7 @@
#include "vm/Compression.h"
#include "vm/Debugger.h"
#include "vm/Opcodes.h"
#include "vm/SelfHosting.h"
#include "vm/Shape.h"
#include "vm/Xdr.h"
@ -2785,10 +2787,28 @@ js::CloneScript(JSContext *cx, HandleObject enclosingScope, HandleFunction fun,
}
}
/* Wrap the script source object as needed. */
RootedObject sourceObject(cx, src->sourceObject());
if (!cx->compartment()->wrap(cx, &sourceObject))
return nullptr;
/*
* Wrap the script source object as needed. Self-hosted scripts may be
* in another runtime, so lazily create a new script source object to
* use for them.
*/
RootedObject sourceObject(cx);
if (cx->runtime()->isSelfHostingCompartment(src->compartment())) {
if (!cx->compartment()->selfHostingScriptSource) {
CompileOptions options(cx);
FillSelfHostingCompileOptions(options);
ScriptSourceObject *obj = frontend::CreateScriptSourceObject(cx, options);
if (!obj)
return nullptr;
cx->compartment()->selfHostingScriptSource = obj;
}
sourceObject = cx->compartment()->selfHostingScriptSource;
} else {
sourceObject = src->sourceObject();
if (!cx->compartment()->wrap(cx, &sourceObject))
return nullptr;
}
/* Now that all fallible allocation is complete, create the GC thing. */

View File

@ -640,7 +640,7 @@ GlobalWorkerThreadState::finishParseTask(JSContext *maybecx, JSRuntime *rt, void
if (!proto.isObject())
continue;
JSProtoKey key = js_IdentifyClassPrototype(proto.toObject());
JSProtoKey key = JS::IdentifyStandardPrototype(proto.toObject());
if (key == JSProto_Null)
continue;

View File

@ -767,11 +767,6 @@ GlobalObject::getSelfHostedFunction(JSContext *cx, HandleAtom selfHostedName, Ha
if (cx->global()->maybeGetIntrinsicValue(shId, funVal.address()))
return true;
if (!cx->runtime()->maybeWrappedSelfHostedFunction(cx, shId, funVal))
return false;
if (!funVal.isUndefined())
return true;
JSFunction *fun = NewFunction(cx, NullPtr(), nullptr, nargs, JSFunction::INTERPRETED_LAZY,
holder, name, JSFunction::ExtendedFinalizeKind, SingletonObject);
if (!fun)

View File

@ -841,6 +841,10 @@ struct JSRuntime : public JS::shadow::Runtime,
WTF::BumpPointerAllocator *bumpAlloc_;
js::jit::JitRuntime *jitRuntime_;
/*
* Self-hosting state cloned on demand into other compartments. Shared with the parent
* runtime if there is one.
*/
JSObject *selfHostingGlobal_;
/* Space for interpreter frames. */
@ -884,15 +888,14 @@ struct JSRuntime : public JS::shadow::Runtime,
bool initSelfHosting(JSContext *cx);
void finishSelfHosting();
void markSelfHostingGlobal(JSTracer *trc);
bool isSelfHostingGlobal(js::HandleObject global) {
bool isSelfHostingGlobal(JSObject *global) {
return global == selfHostingGlobal_;
}
bool isSelfHostingCompartment(JSCompartment *comp);
bool cloneSelfHostedFunctionScript(JSContext *cx, js::Handle<js::PropertyName*> name,
js::Handle<JSFunction*> targetFun);
bool cloneSelfHostedValue(JSContext *cx, js::Handle<js::PropertyName*> name,
js::MutableHandleValue vp);
bool maybeWrappedSelfHostedFunction(JSContext *cx, js::HandleId name,
js::MutableHandleValue funVal);
//-------------------------------------------------------------------------
// Locale information

View File

@ -164,18 +164,6 @@ intrinsic_MakeConstructible(JSContext *cx, unsigned argc, Value *vp)
return true;
}
static bool
intrinsic_MakeWrappable(JSContext *cx, unsigned argc, Value *vp)
{
CallArgs args = CallArgsFromVp(argc, vp);
JS_ASSERT(args.length() >= 1);
JS_ASSERT(args[0].isObject());
JS_ASSERT(args[0].toObject().is<JSFunction>());
args[0].toObject().as<JSFunction>().makeWrappable();
args.rval().setUndefined();
return true;
}
/*
* Used to decompile values in the nearest non-builtin stack frame, falling
* back to decompiling in the current frame. Helpful for printing higher-order
@ -662,7 +650,6 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_FN("AssertionFailed", intrinsic_AssertionFailed, 1,0),
JS_FN("SetScriptHints", intrinsic_SetScriptHints, 2,0),
JS_FN("MakeConstructible", intrinsic_MakeConstructible, 1,0),
JS_FN("MakeWrappable", intrinsic_MakeWrappable, 1,0),
JS_FN("DecompileArg", intrinsic_DecompileArg, 2,0),
JS_FN("RuntimeDefaultLocale", intrinsic_RuntimeDefaultLocale, 0,0),
@ -777,11 +764,52 @@ static const JSFunctionSpec intrinsic_functions[] = {
JS_FS_END
};
void
js::FillSelfHostingCompileOptions(CompileOptions &options)
{
/*
* In self-hosting mode, scripts emit JSOP_CALLINTRINSIC instead of
* JSOP_NAME or JSOP_GNAME to access unbound variables. JSOP_CALLINTRINSIC
* does a name lookup in a special object, whose properties are filled in
* lazily upon first access for a given global.
*
* As that object is inaccessible to client code, the lookups are
* guaranteed to return the original objects, ensuring safe implementation
* of self-hosted builtins.
*
* Additionally, the special syntax callFunction(fun, receiver, ...args)
* is supported, for which bytecode is emitted that invokes |fun| with
* |receiver| as the this-object and ...args as the arguments.
*/
options.setFileAndLine("self-hosted", 1);
options.setSelfHostingMode(true);
options.setCanLazilyParse(false);
options.setSourcePolicy(CompileOptions::NO_SOURCE);
options.setVersion(JSVERSION_LATEST);
options.werrorOption = true;
#ifdef DEBUG
options.strictOption = true;
options.extraWarningsOption = true;
#endif
}
bool
JSRuntime::initSelfHosting(JSContext *cx)
{
JS_ASSERT(!selfHostingGlobal_);
if (cx->runtime()->parentRuntime) {
selfHostingGlobal_ = cx->runtime()->parentRuntime->selfHostingGlobal_;
return true;
}
/*
* Self hosted state can be accessed from threads for other runtimes
* parented to this one, so cannot include state in the nursery.
*/
JS::AutoDisableGenerationalGC disable(cx->runtime());
bool receivesDefaultObject = !cx->options().noDefaultCompartmentObject();
RootedObject savedGlobal(cx, receivesDefaultObject
? js::DefaultObjectForContextOrNull(cx)
@ -808,32 +836,8 @@ JSRuntime::initSelfHosting(JSContext *cx)
JS_FireOnNewGlobalObject(cx, shg);
/*
* In self-hosting mode, scripts emit JSOP_CALLINTRINSIC instead of
* JSOP_NAME or JSOP_GNAME to access unbound variables. JSOP_CALLINTRINSIC
* does a name lookup in a special object, whose properties are filled in
* lazily upon first access for a given global.
*
* As that object is inaccessible to client code, the lookups are
* guaranteed to return the original objects, ensuring safe implementation
* of self-hosted builtins.
*
* Additionally, the special syntax _CallFunction(receiver, ...args, fun)
* is supported, for which bytecode is emitted that invokes |fun| with
* |receiver| as the this-object and ...args as the arguments..
*/
CompileOptions options(cx);
options.setFileAndLine("self-hosted", 1);
options.setSelfHostingMode(true);
options.setCanLazilyParse(false);
options.setSourcePolicy(CompileOptions::NO_SOURCE);
options.setVersion(JSVERSION_LATEST);
options.werrorOption = true;
#ifdef DEBUG
options.strictOption = true;
options.extraWarningsOption = true;
#endif
FillSelfHostingCompileOptions(options);
/*
* Set a temporary error reporter printing to stderr because it is too
@ -882,35 +886,89 @@ JSRuntime::finishSelfHosting()
void
JSRuntime::markSelfHostingGlobal(JSTracer *trc)
{
if (selfHostingGlobal_)
if (selfHostingGlobal_ && !parentRuntime)
MarkObjectRoot(trc, &selfHostingGlobal_, "self-hosting global");
}
typedef AutoObjectObjectHashMap CloneMemory;
static bool CloneValue(JSContext *cx, MutableHandleValue vp, CloneMemory &clonedObjects);
bool
JSRuntime::isSelfHostingCompartment(JSCompartment *comp)
{
return selfHostingGlobal_->compartment() == comp;
}
// CloneMemory maps objects to each other which may be in different
// runtimes. This class should only be used within an AutoSuppressGC,
// so that issues of managing which objects should be traced can be ignored.
typedef HashMap<JSObject *, JSObject *> CloneMemory;
static bool
GetUnclonedValue(JSContext *cx, Handle<JSObject*> src, HandleId id, MutableHandleValue vp)
CloneValue(JSContext *cx, const Value &selfHostedValue, MutableHandleValue vp, CloneMemory &clonedObjects);
static bool
GetUnclonedValue(JSContext *cx, JSObject *selfHostedObject, jsid id, Value *vp)
{
AutoCompartment ac(cx, src);
return JSObject::getGeneric(cx, src, src, id, vp);
*vp = UndefinedValue();
if (JSID_IS_INT(id)) {
size_t index = JSID_TO_INT(id);
if (index < selfHostedObject->getDenseInitializedLength() &&
!selfHostedObject->getDenseElement(index).isMagic(JS_ELEMENTS_HOLE))
{
*vp = selfHostedObject->getDenseElement(JSID_TO_INT(id));
return true;
}
}
// Since all atoms used by self hosting are marked as permanent, any
// attempt to look up a non-permanent atom will fail. We should only
// see such atoms when code is looking for properties on the self
// hosted global which aren't present.
if (JSID_IS_STRING(id) && !JSID_TO_STRING(id)->isPermanentAtom()) {
JS_ASSERT(selfHostedObject->is<GlobalObject>());
gc::AutoSuppressGC suppress(cx);
JS_ReportError(cx, "No such property on self hosted object");
return false;
}
Shape *shape = selfHostedObject->nativeLookupPure(id);
if (!shape) {
gc::AutoSuppressGC suppress(cx);
JS_ReportError(cx, "No such property on self hosted object");
return false;
}
JS_ASSERT(shape->hasSlot() && shape->hasDefaultGetter());
*vp = selfHostedObject->getSlot(shape->slot());
return true;
}
static bool
CloneProperties(JSContext *cx, HandleObject obj, HandleObject clone, CloneMemory &clonedObjects)
CloneProperties(JSContext *cx, JSObject *selfHostedObject,
HandleObject clone, CloneMemory &clonedObjects)
{
RootedId id(cx);
RootedValue val(cx);
AutoIdVector ids(cx);
{
AutoCompartment ac(cx, obj);
if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, &ids))
Vector<jsid> ids(cx);
for (size_t i = 0; i < selfHostedObject->getDenseInitializedLength(); i++) {
if (!selfHostedObject->getDenseElement(i).isMagic(JS_ELEMENTS_HOLE)) {
if (!ids.append(INT_TO_JSID(i)))
return false;
}
}
for (Shape::Range<NoGC> range(selfHostedObject->lastProperty()); !range.empty(); range.popFront()) {
Shape &shape = range.front();
if (shape.enumerable() && !ids.append(shape.propid()))
return false;
}
RootedId id(cx);
RootedValue val(cx);
for (uint32_t i = 0; i < ids.length(); i++) {
id = ids[i];
if (!GetUnclonedValue(cx, obj, id, &val) ||
!CloneValue(cx, &val, clonedObjects) ||
Value selfHostedValue;
if (!GetUnclonedValue(cx, selfHostedObject, id, &selfHostedValue))
return false;
if (!CloneValue(cx, selfHostedValue, &val, clonedObjects) ||
!JS_DefinePropertyById(cx, clone, id, val.get(), nullptr, nullptr, 0))
{
return false;
@ -920,98 +978,84 @@ CloneProperties(JSContext *cx, HandleObject obj, HandleObject clone, CloneMemory
return true;
}
static gc::AllocKind
GetObjectAllocKindForClone(JSRuntime *rt, JSObject *obj)
{
if (!gc::IsInsideNursery(rt, (void *)obj))
return obj->tenuredGetAllocKind();
if (obj->is<JSFunction>())
return obj->as<JSFunction>().getAllocKind();
gc::AllocKind kind = gc::GetGCObjectFixedSlotsKind(obj->numFixedSlots());
if (CanBeFinalizedInBackground(kind, obj->getClass()))
kind = GetBackgroundAllocKind(kind);
return kind;
}
static JSObject *
CloneObject(JSContext *cx, HandleObject srcObj, CloneMemory &clonedObjects)
CloneObject(JSContext *cx, JSObject *selfHostedObject, CloneMemory &clonedObjects)
{
DependentAddPtr<CloneMemory> p(cx, clonedObjects, srcObj.get());
DependentAddPtr<CloneMemory> p(cx, clonedObjects, selfHostedObject);
if (p)
return p->value();
RootedObject clone(cx);
if (srcObj->is<JSFunction>()) {
if (srcObj->as<JSFunction>().isWrappable()) {
clone = srcObj;
if (!cx->compartment()->wrap(cx, &clone))
return nullptr;
} else {
RootedFunction fun(cx, &srcObj->as<JSFunction>());
bool hasName = fun->atom() != nullptr;
js::gc::AllocKind kind = hasName
? JSFunction::ExtendedFinalizeKind
: fun->getAllocKind();
clone = CloneFunctionObject(cx, fun, cx->global(), kind, TenuredObject);
// To be able to re-lazify the cloned function, its name in the
// self-hosting compartment has to be stored on the clone.
if (clone && hasName)
clone->as<JSFunction>().setExtendedSlot(0, StringValue(fun->atom()));
}
} else if (srcObj->is<RegExpObject>()) {
RegExpObject &reobj = srcObj->as<RegExpObject>();
if (selfHostedObject->is<JSFunction>()) {
JSFunction *selfHostedFunction = &selfHostedObject->as<JSFunction>();
bool hasName = selfHostedFunction->atom() != nullptr;
js::gc::AllocKind kind = hasName
? JSFunction::ExtendedFinalizeKind
: selfHostedFunction->getAllocKind();
clone = CloneFunctionObject(cx, HandleFunction::fromMarkedLocation(&selfHostedFunction),
cx->global(), kind, TenuredObject);
// To be able to re-lazify the cloned function, its name in the
// self-hosting compartment has to be stored on the clone.
if (clone && hasName)
clone->as<JSFunction>().setExtendedSlot(0, StringValue(selfHostedFunction->atom()));
} else if (selfHostedObject->is<RegExpObject>()) {
RegExpObject &reobj = selfHostedObject->as<RegExpObject>();
RootedAtom source(cx, reobj.getSource());
JS_ASSERT(source->isPermanentAtom());
clone = RegExpObject::createNoStatics(cx, source, reobj.getFlags(), nullptr);
} else if (srcObj->is<DateObject>()) {
clone = JS_NewDateObjectMsec(cx, srcObj->as<DateObject>().UTCTime().toNumber());
} else if (srcObj->is<BooleanObject>()) {
clone = BooleanObject::create(cx, srcObj->as<BooleanObject>().unbox());
} else if (srcObj->is<NumberObject>()) {
clone = NumberObject::create(cx, srcObj->as<NumberObject>().unbox());
} else if (srcObj->is<StringObject>()) {
Rooted<JSFlatString*> str(cx, srcObj->as<StringObject>().unbox()->ensureFlat(cx));
if (!str)
return nullptr;
str = js_NewStringCopyN<CanGC>(cx, str->chars(), str->length());
} else if (selfHostedObject->is<DateObject>()) {
clone = JS_NewDateObjectMsec(cx, selfHostedObject->as<DateObject>().UTCTime().toNumber());
} else if (selfHostedObject->is<BooleanObject>()) {
clone = BooleanObject::create(cx, selfHostedObject->as<BooleanObject>().unbox());
} else if (selfHostedObject->is<NumberObject>()) {
clone = NumberObject::create(cx, selfHostedObject->as<NumberObject>().unbox());
} else if (selfHostedObject->is<StringObject>()) {
JSString *selfHostedString = selfHostedObject->as<StringObject>().unbox();
if (!selfHostedString->isFlat())
MOZ_CRASH();
RootedString str(cx, js_NewStringCopyN<CanGC>(cx,
selfHostedString->asFlat().chars(),
selfHostedString->asFlat().length()));
if (!str)
return nullptr;
clone = StringObject::create(cx, str);
} else if (srcObj->is<ArrayObject>()) {
} else if (selfHostedObject->is<ArrayObject>()) {
clone = NewDenseEmptyArray(cx, nullptr, TenuredObject);
} else {
JS_ASSERT(srcObj->isNative());
clone = NewObjectWithGivenProto(cx, srcObj->getClass(), nullptr, cx->global(),
GetObjectAllocKindForClone(cx->runtime(), srcObj),
JS_ASSERT(selfHostedObject->isNative());
clone = NewObjectWithGivenProto(cx, selfHostedObject->getClass(), nullptr, cx->global(),
selfHostedObject->tenuredGetAllocKind(),
SingletonObject);
}
if (!clone)
return nullptr;
if (!p.add(cx, clonedObjects, srcObj, clone))
if (!p.add(cx, clonedObjects, selfHostedObject, clone))
return nullptr;
if (!CloneProperties(cx, srcObj, clone, clonedObjects)) {
clonedObjects.remove(srcObj);
if (!CloneProperties(cx, selfHostedObject, clone, clonedObjects)) {
clonedObjects.remove(selfHostedObject);
return nullptr;
}
return clone;
}
static bool
CloneValue(JSContext *cx, MutableHandleValue vp, CloneMemory &clonedObjects)
CloneValue(JSContext *cx, const Value &selfHostedValue, MutableHandleValue vp, CloneMemory &clonedObjects)
{
if (vp.isObject()) {
RootedObject obj(cx, &vp.toObject());
RootedObject clone(cx, CloneObject(cx, obj, clonedObjects));
if (selfHostedValue.isObject()) {
JSObject *selfHostedObject = &selfHostedValue.toObject();
RootedObject clone(cx, CloneObject(cx, selfHostedObject, clonedObjects));
if (!clone)
return false;
vp.setObject(*clone);
} else if (vp.isBoolean() || vp.isNumber() || vp.isNullOrUndefined()) {
// Nothing to do here: these are represented inline in the value
} else if (vp.isString()) {
Rooted<JSFlatString*> str(cx, vp.toString()->ensureFlat(cx));
if (!str)
return false;
RootedString clone(cx, js_NewStringCopyN<CanGC>(cx, str->chars(), str->length()));
} else if (selfHostedValue.isBoolean() || selfHostedValue.isNumber() || selfHostedValue.isNullOrUndefined()) {
// Nothing to do here: these are represented inline in the value.
vp.set(selfHostedValue);
} else if (selfHostedValue.isString()) {
if (!selfHostedValue.toString()->isFlat())
MOZ_CRASH();
JSFlatString *selfHostedString = &selfHostedValue.toString()->asFlat();
RootedString clone(cx, js_NewStringCopyN<CanGC>(cx,
selfHostedString->chars(),
selfHostedString->length()));
if (!clone)
return false;
vp.setString(clone);
@ -1025,10 +1069,9 @@ bool
JSRuntime::cloneSelfHostedFunctionScript(JSContext *cx, Handle<PropertyName*> name,
Handle<JSFunction*> targetFun)
{
RootedObject shg(cx, selfHostingGlobal_);
RootedValue funVal(cx);
RootedId id(cx, NameToId(name));
if (!GetUnclonedValue(cx, shg, id, &funVal))
Value funVal;
if (!GetUnclonedValue(cx, selfHostingGlobal_, id, &funVal))
return false;
RootedFunction sourceFun(cx, &funVal.toObject().as<JSFunction>());
@ -1056,11 +1099,10 @@ JSRuntime::cloneSelfHostedFunctionScript(JSContext *cx, Handle<PropertyName*> na
bool
JSRuntime::cloneSelfHostedValue(JSContext *cx, Handle<PropertyName*> name, MutableHandleValue vp)
{
RootedObject shg(cx, selfHostingGlobal_);
RootedValue val(cx);
RootedId id(cx, NameToId(name));
if (!GetUnclonedValue(cx, shg, id, &val))
return false;
Value selfHostedValue;
if (!GetUnclonedValue(cx, selfHostingGlobal_, id, &selfHostedValue))
return false;
/*
* We don't clone if we're operating in the self-hosting global, as that
@ -1068,89 +1110,16 @@ JSRuntime::cloneSelfHostedValue(JSContext *cx, Handle<PropertyName*> name, Mutab
* initializing the runtime (see JSRuntime::initSelfHosting).
*/
if (cx->global() != selfHostingGlobal_) {
gc::AutoSuppressGC suppress(cx);
CloneMemory clonedObjects(cx);
if (!clonedObjects.init() || !CloneValue(cx, &val, clonedObjects))
if (!clonedObjects.init() || !CloneValue(cx, selfHostedValue, vp, clonedObjects))
return false;
} else {
vp.set(selfHostedValue);
}
vp.set(val);
return true;
}
class OpaqueWrapper : public CrossCompartmentSecurityWrapper
{
public:
OpaqueWrapper() : CrossCompartmentSecurityWrapper(0) {}
virtual bool enter(JSContext *cx, HandleObject wrapper, HandleId id,
Wrapper::Action act, bool *bp) MOZ_OVERRIDE
{
*bp = false;
return false;
}
static OpaqueWrapper singleton;
};
OpaqueWrapper OpaqueWrapper::singleton;
class OpaqueWrapperWithCall : public OpaqueWrapper
{
public:
OpaqueWrapperWithCall() : OpaqueWrapper() {}
virtual bool enter(JSContext *cx, HandleObject wrapper, HandleId id,
Wrapper::Action act, bool *bp) MOZ_OVERRIDE
{
if (act != Wrapper::CALL) {
*bp = false;
return false;
}
return true;
}
static OpaqueWrapperWithCall singleton;
};
OpaqueWrapperWithCall OpaqueWrapperWithCall::singleton;
static JSObject *
SelfHostingWrapObjectCallback(JSContext *cx, HandleObject existing, HandleObject obj,
HandleObject proto, HandleObject parent, unsigned flags)
{
RootedObject objGlobal(cx, &obj->global());
bool wrappingSelfHostedFunction = cx->runtime()->isSelfHostingGlobal(objGlobal);
JS_ASSERT_IF(!wrappingSelfHostedFunction, cx->runtime()->isSelfHostingGlobal(cx->global()));
OpaqueWrapper *handler = wrappingSelfHostedFunction
? &OpaqueWrapperWithCall::singleton
: &OpaqueWrapper::singleton;
if (existing)
return Wrapper::Renew(cx, existing, obj, handler);
else
return Wrapper::New(cx, obj, parent, handler);
}
const JSWrapObjectCallbacks
js::SelfHostingWrapObjectCallbacks = {
SelfHostingWrapObjectCallback,
nullptr,
nullptr
};
bool
JSRuntime::maybeWrappedSelfHostedFunction(JSContext *cx, HandleId id, MutableHandleValue funVal)
{
RootedObject shg(cx, selfHostingGlobal_);
if (!GetUnclonedValue(cx, shg, id, funVal))
return false;
JS_ASSERT(funVal.isObject());
JS_ASSERT(funVal.toObject().isCallable());
if (!funVal.toObject().as<JSFunction>().isWrappable()) {
funVal.setUndefined();
return true;
}
return cx->compartment()->wrap(cx, funVal);
}
JSFunction *
js::SelfHostedFunction(JSContext *cx, HandlePropertyName propName)
{

View File

@ -13,21 +13,16 @@ class JSAtom;
namespace js {
/*
* When wrapping objects for use by self-hosted code, we skip all checks and
* always create an OpaqueWrapper that allows nothing.
* When wrapping functions from the self-hosting compartment for use in other
* compartments, we create an OpaqueWrapperWithCall that only allows calls,
* nothing else.
*/
extern const JSWrapObjectCallbacks SelfHostingWrapObjectCallbacks;
/*
* Check whether the given JSFunction is a self-hosted function whose
* self-hosted name is the given name.
*/
bool IsSelfHostedFunctionWithName(JSFunction *fun, JSAtom *name);
/* Get the compile options used when compiling self hosted code. */
void
FillSelfHostingCompileOptions(JS::CompileOptions &options);
} /* namespace js */
#endif /* vm_SelfHosting_h_ */

View File

@ -205,7 +205,7 @@ AccessCheck::isCrossOriginAccessPermitted(JSContext *cx, JSObject *wrapperArg, j
const char *name;
const js::Class *clasp = js::GetObjectClass(obj);
MOZ_ASSERT(Jsvalify(clasp) != &XrayUtils::HolderClass, "shouldn't have a holder here");
MOZ_ASSERT(!XrayUtils::IsXPCWNHolderClass(Jsvalify(clasp)), "shouldn't have a holder here");
if (clasp->ext.innerObject)
name = "Window";
else

View File

@ -36,7 +36,7 @@ PropIsFromStandardPrototype(JSContext *cx, JS::MutableHandle<JSPropertyDescripto
MOZ_ASSERT(desc.object());
RootedObject unwrapped(cx, js::UncheckedUnwrap(desc.object()));
JSAutoCompartment ac(cx, unwrapped);
return JS_IdentifyClassPrototype(unwrapped) != JSProto_Null;
return IdentifyStandardPrototype(unwrapped) != JSProto_Null;
}
// Note that we're past the policy enforcement stage, here, so we can query

View File

@ -174,7 +174,7 @@ WrapperFactory::PrepareForWrapping(JSContext *cx, HandleObject scope,
JSProtoKey key = JSProto_Null;
{
JSAutoCompartment ac(cx, obj);
key = JS_IdentifyClassPrototype(obj);
key = IdentifyStandardPrototype(obj);
}
if (key != JSProto_Null) {
RootedObject homeProto(cx);
@ -374,7 +374,7 @@ WrapperFactory::Rewrap(JSContext *cx, HandleObject existing, HandleObject obj,
GetProxyHandler(obj) == &XrayWaiver ||
js::GetObjectClass(obj)->ext.innerObject,
"wrapped object passed to rewrap");
MOZ_ASSERT(JS_GetClass(obj) != &XrayUtils::HolderClass, "trying to wrap a holder");
MOZ_ASSERT(!XrayUtils::IsXPCWNHolderClass(JS_GetClass(obj)), "trying to wrap a holder");
MOZ_ASSERT(!js::IsInnerObject(obj));
// We sometimes end up here after nsContentUtils has been shut down but before
// XPConnect has been shut down, so check the context stack the roundabout way.

View File

@ -37,18 +37,6 @@ using js::CheckedUnwrap;
namespace xpc {
static const uint32_t JSSLOT_RESOLVING = 0;
namespace XrayUtils {
const JSClass HolderClass = {
"NativePropertyHolder",
JSCLASS_HAS_RESERVED_SLOTS(2),
JS_PropertyStub, JS_DeletePropertyStub, holder_get, holder_set,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
};
}
using namespace XrayUtils;
XrayType
@ -65,6 +53,7 @@ GetXrayType(JSObject *obj)
return NotXray;
}
const uint32_t JSSLOT_RESOLVING = 0;
ResolvingId::ResolvingId(JSContext *cx, HandleObject wrapper, HandleId id)
: mId(id),
mHolder(cx, getHolderObject(wrapper)),
@ -193,6 +182,10 @@ private:
class XPCWrappedNativeXrayTraits : public XrayTraits
{
public:
enum {
HasPrototype = 0
};
static const XrayType Type = XrayForWrappedNative;
virtual bool resolveNativeProperty(JSContext *cx, HandleObject wrapper,
@ -227,12 +220,23 @@ public:
virtual JSObject* createHolder(JSContext *cx, JSObject *wrapper);
static const JSClass HolderClass;
static XPCWrappedNativeXrayTraits singleton;
};
const JSClass XPCWrappedNativeXrayTraits::HolderClass = {
"NativePropertyHolder", JSCLASS_HAS_RESERVED_SLOTS(2),
JS_PropertyStub, JS_DeletePropertyStub, holder_get, holder_set,
JS_EnumerateStub, JS_ResolveStub, JS_ConvertStub
};
class DOMXrayTraits : public XrayTraits
{
public:
enum {
HasPrototype = 0
};
static const XrayType Type = XrayForDOMObject;
virtual bool resolveNativeProperty(JSContext *cx, HandleObject wrapper,
@ -527,6 +531,17 @@ XPCWrappedNativeXrayTraits::isResolving(JSContext *cx, JSObject *holder,
return cur->isResolving(id);
}
namespace XrayUtils {
bool
IsXPCWNHolderClass(const JSClass *clasp)
{
return clasp == &XPCWrappedNativeXrayTraits::HolderClass;
}
}
// Some DOM objects have shared properties that don't have an explicit
// getter/setter and rely on the class getter/setter. We install a
// class getter/setter on the holder object to trigger them.
@ -869,6 +884,25 @@ XrayTraits::resolveOwnProperty(JSContext *cx, Wrapper &jsWrapper,
desc.object().set(wrapper);
return true;
}
// Handle .wrappedJSObject for subsuming callers. This should move once we
// sort out own-ness for the holder.
if (id == GetRTIdByIndex(cx, XPCJSRuntime::IDX_WRAPPED_JSOBJECT) &&
AccessCheck::wrapperSubsumes(wrapper))
{
if (!JS_AlreadyHasOwnPropertyById(cx, holder, id, &found))
return false;
if (!found && !JS_DefinePropertyById(cx, holder, id, UndefinedValue(),
wrappedJSObject_getter, nullptr,
JSPROP_ENUMERATE | JSPROP_SHARED)) {
return false;
}
if (!JS_GetPropertyDescriptorById(cx, holder, id, 0, desc))
return false;
desc.object().set(wrapper);
return true;
}
return true;
}
@ -1239,6 +1273,7 @@ template <typename Base, typename Traits>
XrayWrapper<Base, Traits>::XrayWrapper(unsigned flags)
: Base(flags | WrapperFactory::IS_XRAY_WRAPPER_FLAG)
{
Base::setHasPrototype(Traits::HasPrototype);
}
template <typename Base, typename Traits>
@ -1442,20 +1477,6 @@ XrayWrapper<Base, Traits>::getPropertyDescriptor(JSContext *cx, HandleObject wra
if (!holder)
return false;
// Only chrome wrappers and same-origin xrays (used by jetpack sandboxes)
// get .wrappedJSObject. We can check this by determining if the compartment
// of the wrapper subsumes that of the wrappee.
XPCJSRuntime* rt = nsXPConnect::GetRuntimeInstance();
if (AccessCheck::wrapperSubsumes(wrapper) &&
id == rt->GetStringID(XPCJSRuntime::IDX_WRAPPED_JSOBJECT)) {
desc.object().set(wrapper);
desc.setAttributes(JSPROP_ENUMERATE|JSPROP_SHARED);
desc.setGetter(wrappedJSObject_getter);
desc.setSetter(nullptr);
desc.value().set(JSVAL_VOID);
return true;
}
// Ordering is important here.
//
// We first need to call resolveOwnProperty, even before checking the holder,
@ -1768,7 +1789,7 @@ XrayWrapper<Base, Traits>::get(JSContext *cx, HandleObject wrapper,
// Skip our Base if it isn't already ProxyHandler.
// NB: None of the functions we call are prepared for the receiver not
// being the wrapper, so ignore the receiver here.
return js::BaseProxyHandler::get(cx, wrapper, wrapper, id, vp);
return js::BaseProxyHandler::get(cx, wrapper, Traits::HasPrototype ? receiver : wrapper, id, vp);
}
template <typename Base, typename Traits>
@ -1780,7 +1801,7 @@ XrayWrapper<Base, Traits>::set(JSContext *cx, HandleObject wrapper,
// Skip our Base if it isn't already BaseProxyHandler.
// NB: None of the functions we call are prepared for the receiver not
// being the wrapper, so ignore the receiver here.
return js::BaseProxyHandler::set(cx, wrapper, wrapper, id, strict, vp);
return js::BaseProxyHandler::set(cx, wrapper, Traits::HasPrototype ? receiver : wrapper, id, strict, vp);
}
template <typename Base, typename Traits>
@ -1863,24 +1884,17 @@ XrayWrapper<Base, Traits>::getPrototypeOf(JSContext *cx, JS::HandleObject wrappe
RootedObject target(cx, Traits::getTargetObject(wrapper));
RootedObject expando(cx, Traits::singleton.getExpandoObject(cx, target, wrapper));
// We want to keep the Xray's prototype distinct from that of content, but only
// if there's been a set. If there's not an expando, or the expando slot is |undefined|,
// hand back content's proto, appropriately wrapped.
//
// NB: Our baseclass's getPrototypeOf() will appropriately wrap its return value, so there is
// no need for us to.
if (!expando)
return Base::getPrototypeOf(cx, wrapper, protop);
// We want to keep the Xray's prototype distinct from that of content, but
// only if there's been a set. If there's not an expando, or the expando
// slot is |undefined|, hand back the default proto, appropriately wrapped.
RootedValue v(cx);
{
if (expando) {
JSAutoCompartment ac(cx, expando);
v = JS_GetReservedSlot(expando, JSSLOT_EXPANDO_PROTOTYPE);
}
if (v.isUndefined())
return Base::getPrototypeOf(cx, wrapper, protop);
return getPrototypeOfHelper(cx, wrapper, target, protop);
protop.set(v.toObjectOrNull());
return JS_WrapObject(cx, protop);

View File

@ -28,7 +28,7 @@ holder_set(JSContext *cx, JS::HandleObject holder, JS::HandleId id, bool strict,
namespace XrayUtils {
extern const JSClass HolderClass;
bool IsXPCWNHolderClass(const JSClass *clasp);
bool CloneExpandoChain(JSContext *cx, JSObject *src, JSObject *dst);
@ -114,6 +114,27 @@ class XrayWrapper : public Base {
static XrayWrapper singleton;
private:
template <bool HasPrototype>
typename mozilla::EnableIf<HasPrototype, bool>::Type
getPrototypeOfHelper(JSContext *cx, JS::HandleObject wrapper,
JS::HandleObject target, JS::MutableHandleObject protop)
{
return Traits::singleton.getPrototypeOf(cx, wrapper, target, protop);
}
template <bool HasPrototype>
typename mozilla::EnableIf<!HasPrototype, bool>::Type
getPrototypeOfHelper(JSContext *cx, JS::HandleObject wrapper,
JS::HandleObject target, JS::MutableHandleObject protop)
{
return Base::getPrototypeOf(cx, wrapper, protop);
}
bool getPrototypeOfHelper(JSContext *cx, JS::HandleObject wrapper,
JS::HandleObject target, JS::MutableHandleObject protop)
{
return getPrototypeOfHelper<Traits::HasPrototype>(cx, wrapper, target,
protop);
}
bool enumerate(JSContext *cx, JS::Handle<JSObject*> wrapper, unsigned flags,
JS::AutoIdVector &props);
};

View File

@ -3486,7 +3486,13 @@ PresShell::ScrollFrameRectIntoView(nsIFrame* aFrame,
nsIScrollableFrame* sf = do_QueryFrame(container);
if (sf) {
nsPoint oldPosition = sf->GetScrollPosition();
ScrollToShowRect(container, sf, rect - sf->GetScrolledFrame()->GetPosition(),
nsRect targetRect = rect;
if (container->StyleDisplay()->mOverflowClipBox ==
NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX) {
nsMargin padding = container->GetUsedPadding();
targetRect.Inflate(padding);
}
ScrollToShowRect(container, sf, targetRect - sf->GetScrolledFrame()->GetPosition(),
aVertical, aHorizontal, aFlags);
nsPoint newPosition = sf->GetScrollPosition();
// If the scroll position increased, that means our content moved up,

View File

@ -0,0 +1,40 @@
<!DOCTYPE HTML>
<html><head>
<meta charset="utf-8">
<title>Testcases for overflow-clip-box:content-box</title>
<style type="text/css">
html,body {
color:black; background-color:white; font:16px monospace; padding:0; margin:7px;
}
.block {
border:1px solid grey; height:50px; width:200px; padding:20px;
overflow:auto; overflow-clip-box:padding-box;
}
.rel { position:relative; }
.mask1 { position:absolute; width:20px; background:white; top:0; bottom:0; right:0; }
mask {
display:block;
position:absolute;
left: -1px;
bottom: -1px;
height: 25px;
width: 80%;
background:black;
}
</style>
</head>
<body>
<div style="position:relative;">
<div contenteditable=true spellcheck=false tabindex=0 id=x class="rel block">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<span style="padding-right:20px">X</span><div class=mask1></div></div>
<mask></mask>
</div>
<script>
var x = document.getElementById('x');
x.focus();
window.getSelection().collapse(x,0);
</script>
</body>
</html>

View File

@ -0,0 +1,36 @@
<!DOCTYPE HTML>
<html><head>
<meta charset="utf-8">
<title>Testcases for overflow-clip-box:content-box</title>
<style type="text/css">
html,body {
color:black; background-color:white; font:16px monospace; padding:0; margin:7px;
}
.block {
border:1px solid grey; height:50px; width:200px; padding:20px;
overflow:auto; overflow-clip-box:content-box;
}
mask {
display:block;
position:absolute;
left: -1px;
bottom: -1px;
height: 25px;
width: 80%;
background:black;
}
</style>
</head>
<body>
<div style="position:relative;">
<div contenteditable=true spellcheck=false tabindex=0 id=x class="block">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</div>
<mask></mask>
</div>
<script>
var x = document.getElementById('x');
x.focus();
window.getSelection().collapse(x,0);
</script>
</body>
</html>

View File

@ -0,0 +1,42 @@
<!DOCTYPE HTML>
<html><head>
<meta charset="utf-8">
<title>Testcases for overflow-clip-box:content-box</title>
<style type="text/css">
html,body {
color:black; background-color:white; font:16px monospace; padding:0; margin:7px;
}
.block {
border:1px solid grey; height:50px; width:200px; padding:20px;
overflow:auto; overflow-clip-box:padding-box;
line-height:1px;
}
.rel { position:relative; }
.mask1 { position:absolute; width:20px; background:white; top:0; bottom:0; right:0; }
.mask2 { position:absolute; height:20px; background:white; top:0; left:40px; right:0; }
mask {
display:block;
position:absolute;
left: -1px;
bottom: -1px;
height: 25px;
width: 80%;
background:black;
}
</style>
</head>
<body>
<div style="position:relative;">
<div contenteditable=true spellcheck=false tabindex=0 id=x class="rel block">&nbsp;&nbsp;&nbsp;&nbsp;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<span style="padding-right:20px">X</span><div class=mask2></div><div class=mask1></div></div>
<mask></mask>
</div>
<script>
var x = document.getElementById('x');
x.focus();
window.getSelection().collapse(x,0);
</script>
</body>
</html>

View File

@ -0,0 +1,38 @@
<!DOCTYPE HTML>
<html><head>
<meta charset="utf-8">
<title>Testcases for overflow-clip-box:content-box</title>
<style type="text/css">
html,body {
color:black; background-color:white; font:16px monospace; padding:0; margin:7px;
}
.block {
border:1px solid grey; height:50px; width:200px; padding:20px;
overflow:auto; overflow-clip-box:content-box;
line-height:1px;
}
.rel { position:relative; }
mask {
display:block;
position:absolute;
left: -1px;
bottom: -1px;
height: 25px;
width: 80%;
background:black;
}
</style>
</head>
<body>
<div style="position:relative;">
<div contenteditable=true spellcheck=false tabindex=0 id=x class="block">&nbsp;&nbsp;&nbsp;&nbsp;XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</div>
<mask></mask>
</div>
<script>
var x = document.getElementById('x');
x.focus();
window.getSelection().collapse(x,0);
</script>
</body>
</html>

View File

@ -0,0 +1,28 @@
<!DOCTYPE HTML>
<html><head>
<meta charset="utf-8">
<title>Testcases for overflow-clip-box:content-box</title>
<style type="text/css">
html,body {
color:black; background-color:white; font:16px monospace; padding:0; margin:7px;
}
div {
width: 100px; padding-right:50px; overflow-clip-box:padding-box;
overflow:hidden;
}
.rel { position:relative; }
.mask5 { position:absolute; height:40px; background:white; top:3px; left:0px; width:50px; }
</style>
</head>
<body>
<div contenteditable=true spellcheck=false tabindex=0 id=x class="block"><span style="padding-right:50px">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</span></div>
<script>
var x = document.getElementById('x');
x.focus();
x.scrollLeft=100000
window.getSelection().collapse(x,1);
</script>
</body>
</html>

View File

@ -0,0 +1,26 @@
<!DOCTYPE HTML>
<html><head>
<meta charset="utf-8">
<title>Testcases for overflow-clip-box:content-box</title>
<style type="text/css">
html,body {
color:black; background-color:white; font:16px monospace; padding:0; margin:7px;
}
div {
width: 100px; padding-right:50px; overflow-clip-box:content-box;
overflow:hidden;
}
</style>
</head>
<body>
<div contenteditable=true spellcheck=false tabindex=0 id=x class="block">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</div>
<script>
var x = document.getElementById('x');
x.focus();
x.scrollLeft=100000
window.getSelection().collapse(x,1);
</script>
</body>
</html>

View File

@ -144,6 +144,12 @@ support-files =
bug682712-1-ref.html
bug746993-1.html
bug746993-1-ref.html
bug966992-1.html
bug966992-1-ref.html
bug966992-2.html
bug966992-2-ref.html
bug966992-3.html
bug966992-3-ref.html
[test_bug514127.html]
[test_bug518777.html]
[test_bug548545.xhtml]

View File

@ -142,6 +142,11 @@ if (navigator.appVersion.indexOf("Android") == -1 &&
SpecialPowers.Services.appinfo.name != "B2G") {
tests.push([ 'bug512295-1.html' , 'bug512295-1-ref.html' ]);
tests.push([ 'bug512295-2.html' , 'bug512295-2-ref.html' ]);
tests.push(function() {SpecialPowers.setBoolPref("layout.css.overflow-clip-box.enabled", true);});
tests.push([ 'bug966992-1.html' , 'bug966992-1-ref.html' ]);
tests.push([ 'bug966992-2.html' , 'bug966992-2-ref.html' ]);
tests.push([ 'bug966992-3.html' , 'bug966992-3-ref.html' ]);
tests.push(function() {SpecialPowers.setBoolPref("layout.css.overflow-clip-box.enabled", false);});
} else {
is(SpecialPowers.getIntPref("layout.spellcheckDefault"), 0, "Spellcheck should be turned off for this platrom or this if..else check removed");
}

View File

@ -1609,11 +1609,20 @@ ApplyOverflowClipping(nsDisplayListBuilder* aBuilder,
if (!nsFrame::ShouldApplyOverflowClipping(aFrame, aDisp)) {
return;
}
nsRect rect = aFrame->GetPaddingRectRelativeToSelf() +
aBuilder->ToReferenceFrame(aFrame);
nsRect clipRect;
bool haveRadii = false;
nscoord radii[8];
bool haveRadii = aFrame->GetPaddingBoxBorderRadii(radii);
aClipState.ClipContainingBlockDescendantsExtra(rect, haveRadii ? radii : nullptr);
if (aFrame->StyleDisplay()->mOverflowClipBox ==
NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX) {
clipRect = aFrame->GetPaddingRectRelativeToSelf() +
aBuilder->ToReferenceFrame(aFrame);
haveRadii = aFrame->GetPaddingBoxBorderRadii(radii);
} else {
clipRect = aFrame->GetContentRectRelativeToSelf() +
aBuilder->ToReferenceFrame(aFrame);
// XXX border-radius
}
aClipState.ClipContainingBlockDescendantsExtra(clipRect, haveRadii ? radii : nullptr);
}
#ifdef DEBUG

View File

@ -8,6 +8,7 @@
#include "nsGfxScrollFrame.h"
#include "base/compiler_specific.h"
#include "DisplayItemClip.h"
#include "nsCOMPtr.h"
#include "nsPresContext.h"
#include "nsView.h"
@ -401,9 +402,8 @@ nsHTMLScrollFrame::ReflowScrolledFrame(ScrollReflowState* aState,
{
// these could be NS_UNCONSTRAINEDSIZE ... std::min arithmetic should
// be OK
nscoord paddingLR = aState->mReflowState.ComputedPhysicalPadding().LeftRight();
nscoord availWidth = aState->mReflowState.ComputedWidth() + paddingLR;
const nsMargin& padding = aState->mReflowState.ComputedPhysicalPadding();
nscoord availWidth = aState->mReflowState.ComputedWidth() + padding.LeftRight();
nscoord computedHeight = aState->mReflowState.ComputedHeight();
nscoord computedMinHeight = aState->mReflowState.ComputedMinHeight();
@ -417,11 +417,13 @@ nsHTMLScrollFrame::ReflowScrolledFrame(ScrollReflowState* aState,
nsSize hScrollbarPrefSize;
GetScrollbarMetrics(aState->mBoxState, mHelper.mHScrollbarBox,
nullptr, &hScrollbarPrefSize, false);
if (computedHeight != NS_UNCONSTRAINEDSIZE)
if (computedHeight != NS_UNCONSTRAINEDSIZE) {
computedHeight = std::max(0, computedHeight - hScrollbarPrefSize.height);
}
computedMinHeight = std::max(0, computedMinHeight - hScrollbarPrefSize.height);
if (computedMaxHeight != NS_UNCONSTRAINEDSIZE)
if (computedMaxHeight != NS_UNCONSTRAINEDSIZE) {
computedMaxHeight = std::max(0, computedMaxHeight - hScrollbarPrefSize.height);
}
}
if (aAssumeVScroll) {
@ -439,7 +441,7 @@ nsHTMLScrollFrame::ReflowScrolledFrame(ScrollReflowState* aState,
nsSize(availWidth, NS_UNCONSTRAINEDSIZE),
-1, -1, nsHTMLReflowState::CALLER_WILL_INIT);
kidReflowState.Init(presContext, -1, -1, nullptr,
&aState->mReflowState.ComputedPhysicalPadding());
&padding);
kidReflowState.mFlags.mAssumingHScrollbar = aAssumeHScroll;
kidReflowState.mFlags.mAssumingVScrollbar = aAssumeVScroll;
kidReflowState.SetComputedHeight(computedHeight);
@ -479,6 +481,18 @@ nsHTMLScrollFrame::ReflowScrolledFrame(ScrollReflowState* aState,
// overflow area doesn't include the frame bounds.
aMetrics->UnionOverflowAreasWithDesiredBounds();
if (MOZ_UNLIKELY(StyleDisplay()->mOverflowClipBox ==
NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX)) {
nsOverflowAreas childOverflow;
nsLayoutUtils::UnionChildOverflow(mHelper.mScrolledFrame, childOverflow);
nsRect childScrollableOverflow = childOverflow.ScrollableOverflow();
childScrollableOverflow.Inflate(padding);
nsRect contentArea = nsRect(0, 0, availWidth, computedHeight);
if (!contentArea.Contains(childScrollableOverflow)) {
aMetrics->mOverflowAreas.ScrollableOverflow() = childScrollableOverflow;
}
}
aState->mContentsOverflowAreas = aMetrics->mOverflowAreas;
aState->mReflowedContentsWithHScrollbar = aAssumeHScroll;
aState->mReflowedContentsWithVScrollbar = aAssumeVScroll;
@ -2272,10 +2286,74 @@ static bool IsFocused(nsIContent* aContent)
return aContent ? nsContentUtils::IsFocusedContent(aContent) : false;
}
static bool
ShouldBeClippedByFrame(nsIFrame* aClipFrame, nsIFrame* aClippedFrame)
{
return nsLayoutUtils::IsProperAncestorFrame(aClipFrame, aClippedFrame);
}
static void
ClipItemsExceptCaret(nsDisplayList* aList, nsDisplayListBuilder* aBuilder,
nsIFrame* aClipFrame, const DisplayItemClip& aClip)
{
nsDisplayItem* i = aList->GetBottom();
for (; i; i = i->GetAbove()) {
if (!::ShouldBeClippedByFrame(aClipFrame, i->Frame())) {
continue;
}
bool unused;
nsRect bounds = i->GetBounds(aBuilder, &unused);
bool isAffectedByClip = aClip.IsRectAffectedByClip(bounds);
if (isAffectedByClip && nsDisplayItem::TYPE_CARET == i->GetType()) {
// Don't clip the caret if it overflows vertically only, and by half
// its height at most. This is to avoid clipping it when the line-height
// is small.
auto half = bounds.height / 2;
bounds.y += half;
bounds.height -= half;
isAffectedByClip = aClip.IsRectAffectedByClip(bounds);
if (isAffectedByClip) {
// Don't clip the caret if it's just outside on the right side.
nsRect rightSide(bounds.x - 1, bounds.y, 1, bounds.height);
isAffectedByClip = aClip.IsRectAffectedByClip(rightSide);
// Also, avoid clipping it in a zero-height line box (heuristic only).
if (isAffectedByClip) {
isAffectedByClip = i->Frame()->GetRect().height != 0;
}
}
}
if (isAffectedByClip) {
DisplayItemClip newClip;
newClip.IntersectWith(i->GetClip());
newClip.IntersectWith(aClip);
i->SetClip(aBuilder, newClip);
}
nsDisplayList* children = i->GetSameCoordinateSystemChildren();
if (children) {
ClipItemsExceptCaret(children, aBuilder, aClipFrame, aClip);
}
}
}
static void
ClipListsExceptCaret(nsDisplayListCollection* aLists,
nsDisplayListBuilder* aBuilder,
nsIFrame* aClipFrame,
const DisplayItemClip& aClip)
{
::ClipItemsExceptCaret(aLists->BorderBackground(), aBuilder, aClipFrame, aClip);
::ClipItemsExceptCaret(aLists->BlockBorderBackgrounds(), aBuilder, aClipFrame, aClip);
::ClipItemsExceptCaret(aLists->Floats(), aBuilder, aClipFrame, aClip);
::ClipItemsExceptCaret(aLists->PositionedDescendants(), aBuilder, aClipFrame, aClip);
::ClipItemsExceptCaret(aLists->Outlines(), aBuilder, aClipFrame, aClip);
::ClipItemsExceptCaret(aLists->Content(), aBuilder, aClipFrame, aClip);
}
void
ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists)
const nsRect& aDirtyRect,
const nsDisplayListSet& aLists)
{
if (aBuilder->IsForImageVisibility()) {
mLastUpdateImagesPos = GetScrollPosition();
@ -2330,13 +2408,12 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
// Overflow clipping can never clip frames outside our subtree, so there
// is no need to worry about whether we are a moving frame that might clip
// non-moving frames.
nsRect dirtyRect;
// Not all our descendants will be clipped by overflow clipping, but all
// the ones that aren't clipped will be out of flow frames that have already
// had dirty rects saved for them by their parent frames calling
// MarkOutOfFlowChildrenForDisplayList, so it's safe to restrict our
// dirty rect here.
dirtyRect.IntersectRect(aDirtyRect, mScrollPort);
nsRect dirtyRect = aDirtyRect.Intersect(mScrollPort);
// Override the dirty rectangle if the displayport has been set.
nsRect displayPort;
@ -2398,6 +2475,25 @@ ScrollFrameHelper::BuildDisplayList(nsDisplayListBuilder* aBuilder,
mOuter->BuildDisplayListForChild(aBuilder, mScrolledFrame, dirtyRect, scrolledContent);
}
if (MOZ_UNLIKELY(mOuter->StyleDisplay()->mOverflowClipBox ==
NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX)) {
// We only clip if there is *scrollable* overflow, to avoid clipping
// *visual* overflow unnecessarily.
nsRect clipRect = mScrollPort + aBuilder->ToReferenceFrame(mOuter);
nsRect so = mScrolledFrame->GetScrollableOverflowRect();
if (clipRect.width != so.width || clipRect.height != so.height ||
so.x < 0 || so.y < 0) {
// The 'scrolledContent' items are clipped to the padding-box at this point.
// Now clip them again to the content-box, except the nsDisplayCaret item
// which we allow to overflow the content-box in various situations --
// see ::ClipItemsExceptCaret.
clipRect.Deflate(mOuter->GetUsedPadding());
DisplayItemClip clip;
clip.SetTo(clipRect);
::ClipListsExceptCaret(&scrolledContent, aBuilder, mScrolledFrame, clip);
}
}
// Since making new layers is expensive, only use nsDisplayScrollLayer
// if the area is scrollable and we're the content process (unless we're on
// B2G, where we support async scrolling for scrollable elements in the

View File

@ -0,0 +1,73 @@
<!DOCTYPE HTML>
<html class="reftest-wait"><head>
<meta charset="utf-8">
<title>Testcases for overflow-clip-box:content-box</title>
<style type="text/css">
font-face {
font-family: DejaVuSansMono;
src: url(../fonts/DejaVuSansMono.woff),url(DejaVuSansMono.woff);
}
html,body {
color:black; background-color:white; font:16px DejaVuSansMono!important; padding:0; margin:7px;
}
input {
width: 100px; padding:50px; -moz-appearance:none; overflow-clip-box:padding-box;
border: 3px solid black;
}
textarea, #textarea {
width: 160px; height:110px; padding:40px; overflow:scroll; -moz-appearance:none; overflow-clip-box:padding-box;
border: 3px solid black;
}
#textarea { word-break: break-all; font:14px DejaVuSansMono!important; }
p {
position:absolute;
margin:0;
width:70%;
height: 1px;
background:magenta;
}
.rel p { width:200%; }
.block {
border:1px solid grey; height:50px; width:200px; padding:20px;
overflow:auto; overflow-clip-box:padding-box;
}
.rel { position:relative; }
.mask1 { position:absolute; width:20px; background:white; top:0; bottom:0; right:0; }
.mask2 { position:absolute; width:20px; background:white; top:0px; bottom:-15px; right:220px; z-index:99; }
.mask3 { position:absolute; width:20px; background:white; top:0; bottom:0; left:200px; }
.mask4 { position:absolute; height:40px; background:white; top:4px; left:3px; width:210px; z-index:99; }
.mask5 { position:absolute; height:40px; background:white; top:3px; right:3px; width:50px; }
</style>
<script>
function runTest() {
// the timeout is for avoiding differences in scrollbar fading
document.documentElement.removeAttribute("class");
}
</script>
</head>
<body onload="setTimeout(runTest,5000)">
<div class="rel block">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<p style="padding-right:20px"></p><div class=mask1></div></div>
<div style="float:right">
<div class="rel block" style="box-sizing:border-box;height:90px"><span style="padding-right:20px">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</span><div class=mask1></div></div>
</div>
<div class="rel block"><span style="padding-right:20px">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</span><p></p><div class=mask1></div></div>
<div id="d1" class="rel block"><span style="padding-right:20px">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</span><span style="position:relative;"><div class=mask2></div><div class=mask1></div></span><p></p></div>
<script>
document.getElementById("d1").scrollLeft = "100000";
</script>
<div class="block"><span style="padding-right:20px"><span style="position:relative;"><div class=mask3></div>XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</span></span><p></p></div>
<span style="position:relative"><input spellcheck=false type="text" placeholder="someveryveryveryveryverylongvalue"><div class=mask5></div></span>
<span style="position:relative"><input spellcheck=false type="text" value="someveryveryveryveryverylongvalue"><div class=mask5></div></span><br>
<span style="position:relative"><input spellcheck=false type="password" value="someveryveryveryveryverylongpassword"><div class=mask5></div></span>
</body>
</html>

View File

@ -0,0 +1,65 @@
<!DOCTYPE HTML>
<html class="reftest-wait"><head>
<meta charset="utf-8">
<title>Testcases for overflow-clip-box:content-box</title>
<style type="text/css">
font-face {
font-family: DejaVuSansMono;
src: url(../fonts/DejaVuSansMono.woff),url(DejaVuSansMono.woff);
}
html,body {
color:black; background-color:white; font:16px DejaVuSansMono!important; padding:0; margin:7px;
}
input {
width: 100px; padding:50px; -moz-appearance:none; overflow-clip-box:content-box;
border: 3px solid black;
}
textarea {
width: 160px; height:110px; padding:40px; overflow:scroll; -moz-appearance:none; overflow-clip-box:content-box;
border: 3px solid black;font:14px DejaVuSansMono!important;
}
p {
position:absolute;
margin:0;
width:70%;
height: 1px;
background:magenta;
}
.rel p { width:200%; }
.block {
border:1px solid grey; height:50px; width:200px; padding:20px;
overflow:auto; overflow-clip-box:content-box;
}
.rel { position:relative; }
</style>
<script>
function runTest() {
// the timeout is for avoiding differences in scrollbar fading
document.documentElement.removeAttribute("class");
}
</script>
</head>
<body onload="setTimeout(runTest,5000)">
<div class="rel block">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<p></p></div>
<div style="float:right">
<div class="block" style="-moz-box-sizing:border-box;height:90px">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</div>
</div>
<div class="rel block">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<p></p></div>
<div id="d1" class="rel block">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<p></p></div>
<script>
document.getElementById("d1").scrollLeft = "100000";
</script>
<div class="block">XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX<p></p></div>
<input spellcheck=false type="text" placeholder="someveryveryveryveryverylongvalue">
<input spellcheck=false type="text" value="someveryveryveryveryverylongvalue"><br>
<input spellcheck=false type="password" value="someveryveryveryveryverylongpassword">
</body>
</html>

View File

@ -239,7 +239,7 @@ skip-if(B2G) == 234964-1.html 234964-1-ref.html
== 240029-1.html 240029-1-ref.html
== 240470-1.html 240470-1-ref.html
skip-if(B2G) == 240933-1.html 240933-1-ref.html
skip-if(B2G) == 240933-2.html 240933-2-ref.html
skip-if(Android||B2G) == 240933-2.html 240933-2-ref.html
== 243266-1.html 243266-1-ref.html
== 243302-1.html 243302-1-ref.html
skip-if(B2G) == 243519-1.html 243519-1-ref.html
@ -1796,5 +1796,6 @@ fuzzy-if(OSX==10.6,2,30) == 933264-1.html 933264-1-ref.html
== 944291-1.html 944291-1-ref.html
== 957770-1.svg 957770-1-ref.svg
== 960277-1.html 960277-1-ref.html
pref(layout.css.overflow-clip-box.enabled,true) fuzzy(50,10) == 966992-1.html 966992-1-ref.html
skip-if(Android) == 966510-1.html 966510-1-ref.html # scrollable elements other than the root probably won't work well on android until bug 776030 is fixed
skip-if(Android) == 966510-2.html 966510-2-ref.html # same as above

View File

@ -16,7 +16,7 @@
== placeholder-3.html placeholder-overridden-ref.html
== placeholder-4.html placeholder-overridden-ref.html
== placeholder-5.html placeholder-visible-ref.html
== placeholder-6.html placeholder-overflow-ref.html
fuzzy-if(winWidget,160,6) == placeholder-6.html placeholder-overflow-ref.html
skip-if(B2G) == placeholder-6-textarea.html placeholder-overflow-textarea-ref.html
# needs-focus == placeholder-7.html placeholder-focus-ref.html
# needs-focus == placeholder-8.html placeholder-focus-ref.html

View File

@ -28,6 +28,14 @@
height: 300px;
background: black;
}
#cover2 { /* corresponds to the bottom padding inside the textarea */
position: absolute;
left: 0px;
bottom: 0px;
width: 100%;
height: 50px;
background: white;
}
</style>
</head>
<body>
@ -36,7 +44,7 @@
for (var i = 0; i < 1000; ++i) {
ss.push(i);
}
document.write("<div id='t'>" + ss.join(" ") + "</div>");
document.write("<div id='t'><div id=cover2></div>" + ss.join(" ") + "</div>");
</script>
<div id="cover"></div>
</body>

View File

@ -22,5 +22,4 @@ function doTest() {
}
window.addEventListener("MozReftestInvalidate", doTest, false);
setTimeout(doTest, 4000); // fallback for running outside reftest
</script>

View File

@ -115,6 +115,7 @@ textarea {
-moz-user-select: text;
text-shadow: none;
word-wrap: break-word;
overflow-clip-box: content-box;
}
textarea > scrollbar {
@ -137,6 +138,7 @@ textarea::-moz-placeholder {
ime-mode: inherit;
resize: inherit;
-moz-control-character-visibility: visible;
overflow-clip-box: inherit;
}
textarea > .anonymous-div.wrap,
@ -378,6 +380,11 @@ optgroup:disabled {
background-color: transparent;
}
input[type="text"],
input[type="password"] {
overflow-clip-box: content-box;
}
/* hidden inputs */
input[type="hidden"] {
-moz-appearance: none;
@ -899,6 +906,7 @@ input[type="number"] {
/* Has to revert some properties applied by the generic input rule. */
-moz-binding: none;
width: 149px; /* to match type=text */
overflow-clip-box: content-box;
}
input[type=number]::-moz-number-wrapper {

View File

@ -247,6 +247,12 @@ public:
uint32_t aLineNumber,
uint32_t aLineOffset);
nsCSSProperty LookupEnabledProperty(const nsAString& aProperty) {
return nsCSSProps::LookupProperty(aProperty, mUnsafeRulesEnabled ?
nsCSSProps::eEnabledInUASheets :
nsCSSProps::eEnabled);
}
protected:
class nsAutoParseCompoundProperty;
friend class nsAutoParseCompoundProperty;
@ -1305,7 +1311,11 @@ CSSParserImpl::ParseProperty(const nsCSSProperty aPropID,
*aChanged = false;
// Check for unknown or preffed off properties
if (eCSSProperty_UNKNOWN == aPropID || !nsCSSProps::IsEnabled(aPropID)) {
if (eCSSProperty_UNKNOWN == aPropID ||
!(nsCSSProps::IsEnabled(aPropID) ||
(mUnsafeRulesEnabled &&
nsCSSProps::PropHasFlags(aPropID,
CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS)))) {
NS_ConvertASCIItoUTF16 propName(nsCSSProps::GetStringValue(aPropID));
REPORT_UNEXPECTED_P(PEUnknownProperty, propName);
REPORT_UNEXPECTED(PEDeclDropped);
@ -1560,8 +1570,7 @@ CSSParserImpl::EvaluateSupportsDeclaration(const nsAString& aProperty,
nsIURI* aBaseURL,
nsIPrincipal* aDocPrincipal)
{
nsCSSProperty propID = nsCSSProps::LookupProperty(aProperty,
nsCSSProps::eEnabled);
nsCSSProperty propID = LookupEnabledProperty(aProperty);
if (propID == eCSSProperty_UNKNOWN) {
return false;
}
@ -3701,8 +3710,7 @@ CSSParserImpl::ParseSupportsConditionInParensInsideParens(bool& aConditionMet)
return false;
}
nsCSSProperty propID = nsCSSProps::LookupProperty(propertyName,
nsCSSProps::eEnabled);
nsCSSProperty propID = LookupEnabledProperty(propertyName);
if (propID == eCSSProperty_UNKNOWN) {
if (ExpectSymbol(')', true)) {
UngetToken();
@ -5743,7 +5751,7 @@ CSSParserImpl::ParseDeclaration(css::Declaration* aDeclaration,
}
} else {
// Map property name to its ID.
propID = nsCSSProps::LookupProperty(propertyName, nsCSSProps::eEnabled);
propID = LookupEnabledProperty(propertyName);
if (eCSSProperty_UNKNOWN == propID ||
(aContext == eCSSContext_Page &&
!nsCSSProps::PropHasFlags(propID,

View File

@ -2480,6 +2480,18 @@ CSS_PROP_SHORTHAND(
Overflow,
CSS_PROPERTY_PARSE_FUNCTION,
"")
CSS_PROP_DISPLAY(
overflow-clip-box,
overflow_clip_box,
OverflowClipBox,
CSS_PROPERTY_PARSE_VALUE |
CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS |
CSS_PROPERTY_APPLIES_TO_PLACEHOLDER,
"layout.css.overflow-clip-box.enabled",
VARIANT_HK,
kOverflowClipBoxKTable,
CSS_PROP_NO_OFFSET,
eStyleAnimType_None)
CSS_PROP_DISPLAY(
overflow-x,
overflow_x,

View File

@ -387,23 +387,25 @@ nsCSSProps::LookupProperty(const nsACString& aProperty,
}
nsCSSProperty res = nsCSSProperty(gPropertyTable->Lookup(aProperty));
// Check eCSSAliasCount against 0 to make it easy for the
// compiler to optimize away the 0-aliases case.
if (eCSSAliasCount != 0 && res >= eCSSProperty_COUNT) {
static_assert(eCSSProperty_UNKNOWN < eCSSProperty_COUNT,
"assuming eCSSProperty_UNKNOWN doesn't hit this code");
if (IsEnabled(res) || aEnabled == eAny) {
res = gAliases[res - eCSSProperty_COUNT];
NS_ABORT_IF_FALSE(0 <= res && res < eCSSProperty_COUNT,
"aliases must not point to other aliases");
} else {
if (MOZ_LIKELY(res < eCSSProperty_COUNT)) {
if (res != eCSSProperty_UNKNOWN && !IsEnabled(res, aEnabled)) {
res = eCSSProperty_UNKNOWN;
}
return res;
}
if (res != eCSSProperty_UNKNOWN && aEnabled == eEnabled && !IsEnabled(res)) {
res = eCSSProperty_UNKNOWN;
MOZ_ASSERT(eCSSAliasCount != 0,
"'res' must be an alias at this point so we better have some!");
// We intentionally don't support eEnabledInUASheets for aliases yet
// because it's unlikely there will be a need for it.
if (IsEnabled(res) || aEnabled == eAny) {
res = gAliases[res - eCSSProperty_COUNT];
NS_ABORT_IF_FALSE(0 <= res && res < eCSSProperty_COUNT,
"aliases must not point to other aliases");
if (IsEnabled(res) || aEnabled == eAny) {
return res;
}
}
return res;
return eCSSProperty_UNKNOWN;
}
nsCSSProperty
@ -419,23 +421,25 @@ nsCSSProps::LookupProperty(const nsAString& aProperty, EnabledState aEnabled)
// converting and avoid a PromiseFlatCString() call.
NS_ABORT_IF_FALSE(gPropertyTable, "no lookup table, needs addref");
nsCSSProperty res = nsCSSProperty(gPropertyTable->Lookup(aProperty));
// Check eCSSAliasCount against 0 to make it easy for the
// compiler to optimize away the 0-aliases case.
if (eCSSAliasCount != 0 && res >= eCSSProperty_COUNT) {
static_assert(eCSSProperty_UNKNOWN < eCSSProperty_COUNT,
"assuming eCSSProperty_UNKNOWN doesn't hit this code");
if (IsEnabled(res) || aEnabled == eAny) {
res = gAliases[res - eCSSProperty_COUNT];
NS_ABORT_IF_FALSE(0 <= res && res < eCSSProperty_COUNT,
"aliases must not point to other aliases");
} else {
if (MOZ_LIKELY(res < eCSSProperty_COUNT)) {
if (res != eCSSProperty_UNKNOWN && !IsEnabled(res, aEnabled)) {
res = eCSSProperty_UNKNOWN;
}
return res;
}
if (res != eCSSProperty_UNKNOWN && aEnabled == eEnabled && !IsEnabled(res)) {
res = eCSSProperty_UNKNOWN;
MOZ_ASSERT(eCSSAliasCount != 0,
"'res' must be an alias at this point so we better have some!");
// We intentionally don't support eEnabledInUASheets for aliases yet
// because it's unlikely there will be a need for it.
if (IsEnabled(res) || aEnabled == eAny) {
res = gAliases[res - eCSSProperty_COUNT];
NS_ABORT_IF_FALSE(0 <= res && res < eCSSProperty_COUNT,
"aliases must not point to other aliases");
if (IsEnabled(res) || aEnabled == eAny) {
return res;
}
}
return res;
return eCSSProperty_UNKNOWN;
}
nsCSSFontDesc
@ -1422,6 +1426,12 @@ const KTableValue nsCSSProps::kOverflowKTable[] = {
eCSSKeyword_UNKNOWN,-1
};
const KTableValue nsCSSProps::kOverflowClipBoxKTable[] = {
eCSSKeyword_padding_box, NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX,
eCSSKeyword_content_box, NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX,
eCSSKeyword_UNKNOWN,-1
};
const KTableValue nsCSSProps::kOverflowSubKTable[] = {
eCSSKeyword_auto, NS_STYLE_OVERFLOW_AUTO,
eCSSKeyword_visible, NS_STYLE_OVERFLOW_VISIBLE,

View File

@ -194,6 +194,13 @@ static_assert((CSS_PROPERTY_PARSE_PROPERTY_MASK &
// This property requires a stacking context.
#define CSS_PROPERTY_CREATES_STACKING_CONTEXT (1<<21)
// This property is always enabled in UA sheets. This is meant to be used
// together with a pref that enables the property for non-UA sheets.
// Note that if such a property has an alias, then any use of that alias
// in an UA sheet will still be ignored unless the pref is enabled.
// In other words, this bit has no effect on the use of aliases.
#define CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS (1<<22)
/**
* Types of animatable values.
*/
@ -254,6 +261,7 @@ public:
// Given a property string, return the enum value
enum EnabledState {
eEnabled,
eEnabledInUASheets,
eAny
};
// Looks up the property with name aProperty and returns its corresponding
@ -439,6 +447,13 @@ public:
return gPropertyEnabled[aProperty];
}
static bool IsEnabled(nsCSSProperty aProperty, EnabledState aEnabled) {
return IsEnabled(aProperty) ||
(aEnabled == eEnabledInUASheets &&
PropHasFlags(aProperty, CSS_PROPERTY_ALWAYS_ENABLED_IN_UA_SHEETS)) ||
aEnabled == eAny;
}
public:
#define CSSPROPS_FOR_SHORTHAND_SUBPROPERTIES(iter_, prop_) \
@ -540,6 +555,7 @@ public:
static const KTableValue kOutlineColorKTable[];
static const KTableValue kOverflowKTable[];
static const KTableValue kOverflowSubKTable[];
static const KTableValue kOverflowClipBoxKTable[];
static const KTableValue kPageBreakKTable[];
static const KTableValue kPageBreakInsideKTable[];
static const KTableValue kPageMarksKTable[];

View File

@ -3752,6 +3752,16 @@ nsComputedDOMStyle::DoGetOverflowY()
return val;
}
CSSValue*
nsComputedDOMStyle::DoGetOverflowClipBox()
{
nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverflowClipBox,
nsCSSProps::kOverflowClipBoxKTable));
return val;
}
CSSValue*
nsComputedDOMStyle::DoGetResize()
{

View File

@ -398,6 +398,7 @@ private:
mozilla::dom::CSSValue* DoGetOverflow();
mozilla::dom::CSSValue* DoGetOverflowX();
mozilla::dom::CSSValue* DoGetOverflowY();
mozilla::dom::CSSValue* DoGetOverflowClipBox();
mozilla::dom::CSSValue* DoGetResize();
mozilla::dom::CSSValue* DoGetPageBreakAfter();
mozilla::dom::CSSValue* DoGetPageBreakBefore();

View File

@ -162,6 +162,7 @@ COMPUTED_STYLE_PROP(outline_offset, OutlineOffset)
COMPUTED_STYLE_PROP(outline_style, OutlineStyle)
COMPUTED_STYLE_PROP(outline_width, OutlineWidth)
COMPUTED_STYLE_PROP(overflow, Overflow)
COMPUTED_STYLE_PROP(overflow_clip_box, OverflowClipBox)
COMPUTED_STYLE_PROP(overflow_x, OverflowX)
COMPUTED_STYLE_PROP(overflow_y, OverflowY)
//// COMPUTED_STYLE_PROP(padding, Padding)

View File

@ -5304,6 +5304,12 @@ nsRuleNode::ComputeDisplayData(void* aStartStruct,
display->mOverflowY = NS_STYLE_OVERFLOW_AUTO;
}
SetDiscrete(*aRuleData->ValueForOverflowClipBox(), display->mOverflowClipBox,
canStoreInRuleTree,
SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
parentDisplay->mOverflowClipBox,
NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX, 0, 0, 0, 0);
SetDiscrete(*aRuleData->ValueForResize(), display->mResize, canStoreInRuleTree,
SETDSC_ENUMERATED | SETDSC_UNSET_INITIAL,
parentDisplay->mResize,

View File

@ -570,14 +570,14 @@ static inline mozilla::css::Side operator++(mozilla::css::Side& side, int) {
#define NS_STYLE_WIDTH_FIT_CONTENT 2
#define NS_STYLE_WIDTH_AVAILABLE 3
// See nsStylePosition.mPosition
// See nsStyleDisplay.mPosition
#define NS_STYLE_POSITION_STATIC 0
#define NS_STYLE_POSITION_RELATIVE 1
#define NS_STYLE_POSITION_ABSOLUTE 2
#define NS_STYLE_POSITION_FIXED 3
#define NS_STYLE_POSITION_STICKY 4
// See nsStylePosition.mClip
// See nsStyleDisplay.mClip
#define NS_STYLE_CLIP_AUTO 0x00
#define NS_STYLE_CLIP_RECT 0x01
#define NS_STYLE_CLIP_TYPE_MASK 0x0F
@ -598,7 +598,7 @@ static inline mozilla::css::Side operator++(mozilla::css::Side& side, int) {
#define NS_STYLE_FRAME_SCROLL 7
#define NS_STYLE_FRAME_NOSCROLL 8
// See nsStylePosition.mOverflow
// See nsStyleDisplay.mOverflow
#define NS_STYLE_OVERFLOW_VISIBLE 0
#define NS_STYLE_OVERFLOW_HIDDEN 1
#define NS_STYLE_OVERFLOW_SCROLL 2
@ -607,6 +607,10 @@ static inline mozilla::css::Side operator++(mozilla::css::Side& side, int) {
#define NS_STYLE_OVERFLOW_SCROLLBARS_HORIZONTAL 5
#define NS_STYLE_OVERFLOW_SCROLLBARS_VERTICAL 6
// See nsStyleDisplay.mOverflowClipBox
#define NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX 0
#define NS_STYLE_OVERFLOW_CLIP_BOX_CONTENT_BOX 1
// See nsStyleList
#define NS_STYLE_LIST_STYLE_NONE 0
#define NS_STYLE_LIST_STYLE_DISC 1

View File

@ -2278,6 +2278,7 @@ nsStyleDisplay::nsStyleDisplay()
mBreakAfter = false;
mOverflowX = NS_STYLE_OVERFLOW_VISIBLE;
mOverflowY = NS_STYLE_OVERFLOW_VISIBLE;
mOverflowClipBox = NS_STYLE_OVERFLOW_CLIP_BOX_PADDING_BOX;
mResize = NS_STYLE_RESIZE_NONE;
mClipFlags = NS_STYLE_CLIP_AUTO;
mClip.SetRect(0,0,0,0);
@ -2334,6 +2335,7 @@ nsStyleDisplay::nsStyleDisplay(const nsStyleDisplay& aSource)
, mBreakAfter(aSource.mBreakAfter)
, mOverflowX(aSource.mOverflowX)
, mOverflowY(aSource.mOverflowY)
, mOverflowClipBox(aSource.mOverflowClipBox)
, mResize(aSource.mResize)
, mClipFlags(aSource.mClipFlags)
, mOrient(aSource.mOrient)
@ -2412,6 +2414,7 @@ nsChangeHint nsStyleDisplay::CalcDifference(const nsStyleDisplay& aOther) const
|| mBreakAfter != aOther.mBreakAfter
|| mAppearance != aOther.mAppearance
|| mOrient != aOther.mOrient
|| mOverflowClipBox != aOther.mOverflowClipBox
|| mClipFlags != aOther.mClipFlags || !mClip.IsEqualInterior(aOther.mClip))
NS_UpdateHint(hint, NS_CombineHint(nsChangeHint_AllReflowHints,
nsChangeHint_RepaintFrame));

View File

@ -1797,6 +1797,7 @@ struct nsStyleDisplay {
bool mBreakAfter; // [reset]
uint8_t mOverflowX; // [reset] see nsStyleConsts.h
uint8_t mOverflowY; // [reset] see nsStyleConsts.h
uint8_t mOverflowClipBox; // [reset] see nsStyleConsts.h
uint8_t mResize; // [reset] see nsStyleConsts.h
uint8_t mClipFlags; // [reset] see nsStyleConsts.h
uint8_t mOrient; // [reset] see nsStyleConsts.h

View File

@ -4915,6 +4915,17 @@ if (SpecialPowers.getBoolPref("layout.css.will-change.enabled")) {
};
}
if (SpecialPowers.getBoolPref("layout.css.overflow-clip-box.enabled")) {
gCSSProperties["overflow-clip-box"] = {
domProp: "overflowClipBox",
inherited: false,
type: CSS_TYPE_LONGHAND,
initial_values: [ "padding-box" ],
other_values: [ "content-box" ],
invalid_values: [ "none", "auto", "border-box", "0" ]
};
}
if (SpecialPowers.getBoolPref("layout.css.unset-value.enabled")) {
gCSSProperties["animation-direction"].invalid_values.push("normal, unset");
gCSSProperties["animation-name"].invalid_values.push("bounce, unset", "unset, bounce");

View File

@ -103,6 +103,7 @@
position: static !important;
unicode-bidi: inherit;
text-overflow: inherit;
overflow-clip-box: inherit;
}
*|*::-moz-anonymous-block, *|*::-moz-anonymous-positioned-block {
@ -115,6 +116,7 @@
opacity: inherit;
text-decoration: inherit;
-moz-box-ordinal-group: inherit !important;
overflow-clip-box: inherit;
}
*|*::-moz-xul-anonymous-block {
@ -123,6 +125,7 @@
float: none ! important;
-moz-box-ordinal-group: inherit !important;
text-overflow: inherit;
overflow-clip-box: inherit;
}
*|*::-moz-scrolled-content, *|*::-moz-scrolled-canvas,
@ -151,6 +154,7 @@
frame tree. */
position: static !important;
float: none !important;
overflow-clip-box: inherit;
}
*|*::-moz-viewport, *|*::-moz-viewport-scroll, *|*::-moz-canvas, *|*::-moz-scrolled-canvas {

View File

@ -74,11 +74,12 @@ class RefCounted
public:
// Compatibility with nsRefPtr.
void AddRef() const {
MOZ_ASSERT(int32_t(refCnt) >= 0);
++refCnt;
}
void Release() const {
MOZ_ASSERT(refCnt > 0);
MOZ_ASSERT(int32_t(refCnt) > 0);
if (0 == --refCnt) {
#ifdef DEBUG
refCnt = detail::DEAD;

View File

@ -3,8 +3,6 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
# This makefile just builds support for reading archives.
CFLAGS += -DMAR_NSS
include $(topsrcdir)/config/rules.mk
# The intermediate (.ii/.s) files for host and target can have the same name...

View File

@ -18,6 +18,7 @@ LOCAL_INCLUDES += [
'../verify',
]
DEFINES['MAR_NSS'] = True
if CONFIG['OS_ARCH'] == 'WINNT':
USE_STATIC_LIBS = True

View File

@ -1830,6 +1830,9 @@ pref("layout.css.variables.enabled", false);
pref("layout.css.variables.enabled", true);
#endif
// Is support for CSS overflow-clip-box enabled for non-UA sheets?
pref("layout.css.overflow-clip-box.enabled", false);
// pref for which side vertical scrollbars should be on
// 0 = end-side in UI direction
// 1 = end-side in document/content direction

View File

@ -6,7 +6,7 @@ import sys
from setuptools import setup
PACKAGE_NAME = 'mozrunner'
PACKAGE_VERSION = '5.34'
PACKAGE_VERSION = '5.35'
desc = """Reliable start/stop/configuration of Mozilla Applications (Firefox, Thunderbird, etc.)"""

View File

@ -40,6 +40,61 @@ function ContentPrefService2(cps) {
ContentPrefService2.prototype = {
getByName: function CPS2_getByName(name, context, callback) {
checkNameArg(name);
checkCallbackArg(callback, true);
// Some prefs may be in both the database and the private browsing store.
// Notify the caller of such prefs only once, using the values from private
// browsing.
let pbPrefs = new ContentPrefStore();
if (context && context.usePrivateBrowsing) {
for (let [sgroup, sname, val] in this._pbStore) {
if (sname == name) {
pbPrefs.set(sgroup, sname, val);
}
}
}
let stmt1 = this._stmt(
"SELECT groups.name AS grp, prefs.value AS value",
"FROM prefs",
"JOIN settings ON settings.id = prefs.settingID",
"JOIN groups ON groups.id = prefs.groupID",
"WHERE settings.name = :name"
);
stmt1.params.name = name;
let stmt2 = this._stmt(
"SELECT NULL AS grp, prefs.value AS value",
"FROM prefs",
"JOIN settings ON settings.id = prefs.settingID",
"WHERE settings.name = :name AND prefs.groupID ISNULL"
);
stmt2.params.name = name;
this._execStmts([stmt1, stmt2], {
onRow: function onRow(row) {
let grp = row.getResultByName("grp");
let val = row.getResultByName("value");
this._cache.set(grp, name, val);
if (!pbPrefs.has(grp, name))
cbHandleResult(callback, new ContentPref(grp, name, val));
},
onDone: function onDone(reason, ok, gotRow) {
if (ok) {
for (let [pbGroup, pbName, pbVal] in pbPrefs) {
cbHandleResult(callback, new ContentPref(pbGroup, pbName, pbVal));
}
}
cbHandleCompletion(callback, reason);
},
onError: function onError(nsresult) {
cbHandleError(callback, nsresult);
}
});
},
getByDomainAndName: function CPS2_getByDomainAndName(group, name, context,
callback) {
checkGroupArg(group);

View File

@ -170,4 +170,26 @@ let tests = [
yield;
},
function get_nameOnly() {
yield set("a.com", "foo", 1);
yield set("a.com", "bar", 2);
yield set("b.com", "foo", 3);
yield setGlobal("foo", 4);
yield getOKEx("getByName", ["foo", undefined], [
{"domain": "a.com", "name": "foo", "value": 1},
{"domain": "b.com", "name": "foo", "value": 3},
{"domain": null, "name": "foo", "value": 4}
]);
let context = { usePrivateBrowsing: true };
yield set("b.com", "foo", 5, context);
yield getOKEx("getByName", ["foo", context], [
{"domain": "a.com", "name": "foo", "value": 1},
{"domain": null, "name": "foo", "value": 4},
{"domain": "b.com", "name": "foo", "value": 5}
]);
}
];

View File

@ -39,6 +39,8 @@ namespace winrt {
// statics
bool FrameworkView::sKeyboardIsVisible = false;
Rect FrameworkView::sKeyboardRect;
HSTRING FrameworkView::sActivationURI = NULL;
ApplicationExecutionState FrameworkView::sPreviousExecutionState;
nsTArray<nsString>* sSettingsArray;
FrameworkView::FrameworkView(MetroApp* aMetroApp) :
@ -113,6 +115,7 @@ FrameworkView::Run()
// Gecko is completely shut down at this point.
WinUtils::Log("Exiting FrameworkView::Run()");
WindowsDeleteString(sActivationURI);
return S_OK;
}
@ -391,20 +394,14 @@ FrameworkView::OnActivated(ICoreApplicationView* aApplicationView,
return S_OK;
}
aArgs->get_PreviousExecutionState(&mPreviousExecutionState);
bool startup = mPreviousExecutionState == ApplicationExecutionState::ApplicationExecutionState_Terminated ||
mPreviousExecutionState == ApplicationExecutionState::ApplicationExecutionState_ClosedByUser ||
mPreviousExecutionState == ApplicationExecutionState::ApplicationExecutionState_NotRunning;
aArgs->get_PreviousExecutionState(&sPreviousExecutionState);
bool startup = sPreviousExecutionState == ApplicationExecutionState::ApplicationExecutionState_Terminated ||
sPreviousExecutionState == ApplicationExecutionState::ApplicationExecutionState_ClosedByUser ||
sPreviousExecutionState == ApplicationExecutionState::ApplicationExecutionState_NotRunning;
ProcessActivationArgs(aArgs, startup);
return S_OK;
}
int
FrameworkView::GetPreviousExecutionState()
{
return mPreviousExecutionState;
}
HRESULT
FrameworkView::OnSoftkeyboardHidden(IInputPane* aSender,
IInputPaneVisibilityEventArgs* aArgs)

View File

@ -80,18 +80,23 @@ public:
HRESULT ActivateView();
// Public apis for MetroWidget
int GetPreviousExecutionState();
float GetDPI() { return mDPI; }
ICoreWindow* GetCoreWindow() { return mWindow.Get(); }
void SetWidget(MetroWidget* aWidget);
MetroWidget* GetWidget() { return mWidget.Get(); }
void GetBounds(nsIntRect &aRect);
void GetActivationURI(nsAString &aActivationURI) { aActivationURI = mActivationURI; }
void SetCursor(ABI::Windows::UI::Core::CoreCursorType aCursorType, DWORD aCustomId = 0);
void ClearCursor();
bool IsEnabled() const;
bool IsVisible() const;
// Activation apis for nsIWinMetroUtils
static int GetPreviousExecutionState() { return sPreviousExecutionState; }
static void GetActivationURI(nsAString &aActivationURI) {
unsigned int length;
aActivationURI = WindowsGetStringRawBuffer(sActivationURI, &length);
}
// Soft keyboard info for nsIWinMetroUtils
static bool IsKeyboardVisible() { return sKeyboardIsVisible; }
static ABI::Windows::Foundation::Rect KeyboardVisibleRect() { return sKeyboardRect; }
@ -175,11 +180,9 @@ private:
EventRegistrationToken mPrintManager;
private:
ABI::Windows::ApplicationModel::Activation::ApplicationExecutionState mPreviousExecutionState;
nsIntRect mWindowBounds; // in device-pixel coordinates
float mDPI;
bool mShuttingDown;
nsAutoString mActivationURI;
nsAutoString mActivationCommandLine;
Microsoft::WRL::ComPtr<IInspectable> mAutomationProvider;
//Microsoft::WRL::ComPtr<ID2D1PrintControl> mD2DPrintControl;
@ -190,10 +193,13 @@ private:
Microsoft::WRL::ComPtr<ICoreWindow> mWindow;
Microsoft::WRL::ComPtr<MetroWidget> mWidget;
Microsoft::WRL::ComPtr<MetroInput> mMetroInput;
static bool sKeyboardIsVisible;
static Rect sKeyboardRect;
bool mWinVisible;
bool mWinActiveState;
static bool sKeyboardIsVisible;
static Rect sKeyboardRect;
static HSTRING sActivationURI;
static ABI::Windows::ApplicationModel::Activation::ApplicationExecutionState sPreviousExecutionState;
};
} } }

View File

@ -51,12 +51,17 @@ bool MetroApp::sGeckoShuttingDown = false;
HRESULT
MetroApp::CreateView(ABI::Windows::ApplicationModel::Core::IFrameworkView **aViewProvider)
{
// This entry point is called on the metro main thread, but the thread won't be
// recognized as such until after Initialize is called below. XPCOM has not gone
// through startup at this point.
// This entry point is called on the metro main thread, but the thread won't
// be recognized as such until after Run() is called below. XPCOM has not
// gone through startup at this point.
// Note that we create the view which creates our native window for us. The
// gecko widget gets created by gecko, and the two get hooked up later in
// MetroWidget::Create().
LogFunction();
sFrameworkView = Make<FrameworkView>(this);
sFrameworkView.Get()->AddRef();
*aViewProvider = sFrameworkView.Get();
return !sFrameworkView ? E_FAIL : S_OK;
@ -134,6 +139,31 @@ MetroApp::CoreExit()
}
}
void
MetroApp::ActivateBaseView()
{
if (sFrameworkView) {
sFrameworkView->ActivateView();
}
}
/*
* TBD: when we support multiple widgets, we'll need a way to sync up the view
* created in CreateView with the widget gecko creates. Currently we only have
* one view (sFrameworkView) and one main widget.
*/
void
MetroApp::SetWidget(MetroWidget* aPtr)
{
LogThread();
NS_ASSERTION(aPtr, "setting null base widget?");
// Both of these calls AddRef the ptr we pass in
aPtr->SetView(sFrameworkView.Get());
sFrameworkView->SetWidget(aPtr);
}
////////////////////////////////////////////////////
// MetroApp events
@ -162,19 +192,6 @@ MetroApp::OnAsyncTileCreated(ABI::Windows::Foundation::IAsyncOperation<bool>* aO
return S_OK;
}
// static
void
MetroApp::SetBaseWidget(MetroWidget* aPtr)
{
LogThread();
NS_ASSERTION(aPtr, "setting null base widget?");
// Both of these calls AddRef the ptr we pass in
aPtr->SetView(sFrameworkView.Get());
sFrameworkView->SetWidget(aPtr);
}
// static
void
MetroApp::PostSuspendResumeProcessNotification(const bool aIsSuspend)
@ -251,9 +268,7 @@ XRE_MetroCoreApplicationRun()
return false;
}
sFrameworkView = Make<FrameworkView>(sMetroApp.Get());
hr = sCoreApp->Run(sMetroApp.Get());
sFrameworkView = nullptr;
WinUtils::Log("Exiting CoreApplication::Run");

View File

@ -19,8 +19,6 @@ namespace mozilla {
namespace widget {
namespace winrt {
class FrameworkView;
class MetroApp : public Microsoft::WRL::RuntimeClass<ABI::Windows::ApplicationModel::Core::IFrameworkViewSource>
{
InspectableClass(L"MetroApp", TrustLevel::BaseTrust)
@ -45,12 +43,14 @@ public:
void Run();
void CoreExit();
void Shutdown();
void ActivateBaseView();
// Set when gecko enters xpcom shutdown.
static bool sGeckoShuttingDown;
// Shared pointers between framework and widget
static void SetBaseWidget(MetroWidget* aPtr);
void SetWidget(MetroWidget* aPtr);
static void PostSuspendResumeProcessNotification(bool aIsSuspend);
static void PostSleepWakeNotification(bool aIsSuspend);

View File

@ -42,7 +42,6 @@ namespace mozilla {
namespace widget {
namespace winrt {
extern ComPtr<MetroApp> sMetroApp;
extern ComPtr<FrameworkView> sFrameworkView;
} } }
namespace mozilla {
@ -242,7 +241,7 @@ MetroAppShell::Run(void)
}
mozilla::widget::StartAudioSession();
sFrameworkView->ActivateView();
sMetroApp->ActivateBaseView();
rv = nsBaseAppShell::Run();
mozilla::widget::StopAudioSession();

View File

@ -61,7 +61,7 @@ FrameworkView::SearchActivated(ComPtr<ISearchActivatedEventArgs>& aArgs, bool aS
unsigned int length;
WinUtils::LogW(L"SearchActivated text=%s", data.GetRawBuffer(&length));
if (aStartup) {
mActivationURI = data.GetRawBuffer(&length);
WindowsDuplicateString(data.Get(), &sActivationURI);
} else {
PerformURILoadOrSearch(data);
}
@ -81,8 +81,7 @@ FrameworkView::FileActivated(ComPtr<IFileActivatedEventArgs>& aArgs, bool aStart
AssertHRESULT(item->get_Path(filePath.GetAddressOf()));
if (aStartup) {
unsigned int length;
mActivationURI = filePath.GetRawBuffer(&length);
WindowsDuplicateString(filePath.Get(), &sActivationURI);
} else {
PerformURILoad(filePath);
}
@ -99,13 +98,13 @@ FrameworkView::LaunchActivated(ComPtr<ILaunchActivatedEventArgs>& aArgs, bool aS
return;
// If we're being launched from a secondary tile then we have a 2nd command line param of -url
// and a third of the secondary tile. We want it in mActivationURI so that browser.js will
// and a third of the secondary tile. We want it in sActivationURI so that browser.js will
// load it in without showing the start UI.
int argc;
unsigned int length;
LPWSTR* argv = CommandLineToArgvW(data.GetRawBuffer(&length), &argc);
if (aStartup && argc == 2 && !wcsicmp(argv[0], L"-url")) {
mActivationURI = argv[1];
WindowsCreateString(argv[1], wcslen(argv[1]), &sActivationURI);
} else {
// Some other command line or this is not a startup.
// If it is startup we process it later when XPCOM is initialilzed.
@ -177,8 +176,7 @@ FrameworkView::ProcessActivationArgs(IActivatedEventArgs* aArgs, bool aStartup)
return;
if (aStartup) {
unsigned int length;
mActivationURI = data.GetRawBuffer(&length);
WindowsDuplicateString(data.Get(), &sActivationURI);
} else {
PerformURILoad(data);
}

View File

@ -82,6 +82,7 @@ UINT sDefaultBrowserMsgId = RegisterWindowMessageW(L"DefaultBrowserClosing");
namespace mozilla {
namespace widget {
namespace winrt {
extern ComPtr<MetroApp> sMetroApp;
extern ComPtr<IUIABridge> gProviderRoot;
} } }
@ -253,7 +254,7 @@ MetroWidget::Create(nsIWidget *aParent,
// the main widget gets created first
gTopLevelAssigned = true;
MetroApp::SetBaseWidget(this);
sMetroApp->SetWidget(this);
WinUtils::SetNSWindowBasePtr(mWnd, this);
if (mWidgetListener) {

View File

@ -27,7 +27,6 @@ namespace widget {
namespace winrt {
extern ComPtr<MetroApp> sMetroApp;
extern nsTArray<nsString>* sSettingsArray;
extern ComPtr<FrameworkView> sFrameworkView;
} } }
namespace mozilla {
@ -64,7 +63,7 @@ nsWinMetroUtils::PinTileAsync(const nsAString &aTileID,
const nsAString &aTileImage,
const nsAString &aSmallTileImage)
{
if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Desktop) {
if (XRE_GetWindowsEnvironment() != WindowsEnvironmentType_Metro) {
NS_WARNING("PinTileAsync can't be called on the desktop.");
return NS_ERROR_FAILURE;
}
@ -117,7 +116,7 @@ nsWinMetroUtils::PinTileAsync(const nsAString &aTileID,
NS_IMETHODIMP
nsWinMetroUtils::UnpinTileAsync(const nsAString &aTileID)
{
if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Desktop) {
if (XRE_GetWindowsEnvironment() != WindowsEnvironmentType_Metro) {
NS_WARNING("UnpinTileAsync can't be called on the desktop.");
return NS_ERROR_FAILURE;
}
@ -151,7 +150,7 @@ nsWinMetroUtils::UnpinTileAsync(const nsAString &aTileID)
NS_IMETHODIMP
nsWinMetroUtils::IsTilePinned(const nsAString &aTileID, bool *aIsPinned)
{
if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Desktop) {
if (XRE_GetWindowsEnvironment() != WindowsEnvironmentType_Metro) {
NS_WARNING("IsTilePinned can't be called on the desktop.");
return NS_ERROR_FAILURE;
}
@ -230,7 +229,7 @@ nsWinMetroUtils::ShowNativeToast(const nsAString &aTitle,
NS_IMETHODIMP
nsWinMetroUtils::ShowSettingsFlyout()
{
if (XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Desktop) {
if (XRE_GetWindowsEnvironment() != WindowsEnvironmentType_Metro) {
NS_WARNING("Settings flyout can't be shown on the desktop.");
return NS_ERROR_FAILURE;
}
@ -250,57 +249,55 @@ nsWinMetroUtils::GetImmersive(bool *aImersive)
NS_IMETHODIMP
nsWinMetroUtils::GetActivationURI(nsAString &aActivationURI)
{
if (!sFrameworkView) {
NS_WARNING("GetActivationURI used before view is created!");
return NS_OK;
if (XRE_GetWindowsEnvironment() != WindowsEnvironmentType_Metro) {
return NS_ERROR_FAILURE;
}
sFrameworkView->GetActivationURI(aActivationURI);
FrameworkView::GetActivationURI(aActivationURI);
return NS_OK;
}
NS_IMETHODIMP
nsWinMetroUtils::GetPreviousExecutionState(int32_t *out)
{
if (!sFrameworkView) {
NS_WARNING("GetPreviousExecutionState used before view is created!");
return NS_OK;
if (XRE_GetWindowsEnvironment() != WindowsEnvironmentType_Metro) {
return NS_ERROR_FAILURE;
}
*out = sFrameworkView->GetPreviousExecutionState();
*out = FrameworkView::GetPreviousExecutionState();
return NS_OK;
}
NS_IMETHODIMP
nsWinMetroUtils::GetKeyboardVisible(bool *aImersive)
{
*aImersive = mozilla::widget::winrt::FrameworkView::IsKeyboardVisible();
*aImersive = FrameworkView::IsKeyboardVisible();
return NS_OK;
}
NS_IMETHODIMP
nsWinMetroUtils::GetKeyboardX(uint32_t *aX)
{
*aX = (uint32_t)floor(mozilla::widget::winrt::FrameworkView::KeyboardVisibleRect().X);
*aX = static_cast<uint32_t>(floor(FrameworkView::KeyboardVisibleRect().X));
return NS_OK;
}
NS_IMETHODIMP
nsWinMetroUtils::GetKeyboardY(uint32_t *aY)
{
*aY = (uint32_t)floor(mozilla::widget::winrt::FrameworkView::KeyboardVisibleRect().Y);
*aY = static_cast<uint32_t>(floor(FrameworkView::KeyboardVisibleRect().Y));
return NS_OK;
}
NS_IMETHODIMP
nsWinMetroUtils::GetKeyboardWidth(uint32_t *aWidth)
{
*aWidth = (uint32_t)ceil(mozilla::widget::winrt::FrameworkView::KeyboardVisibleRect().Width);
*aWidth = static_cast<uint32_t>(ceil(FrameworkView::KeyboardVisibleRect().Width));
return NS_OK;
}
NS_IMETHODIMP
nsWinMetroUtils::GetKeyboardHeight(uint32_t *aHeight)
{
*aHeight = (uint32_t)ceil(mozilla::widget::winrt::FrameworkView::KeyboardVisibleRect().Height);
*aHeight = static_cast<uint32_t>(ceil(FrameworkView::KeyboardVisibleRect().Height));
return NS_OK;
}

View File

@ -877,15 +877,7 @@ CycleCollectedJSRuntime::ZoneParticipant()
nsresult
CycleCollectedJSRuntime::TraverseRoots(nsCycleCollectionNoteRootCallback &aCb)
{
static bool gcHasRun = false;
if (!gcHasRun) {
uint32_t gcNumber = JS_GetGCParameter(mJSRuntime, JSGC_NUMBER);
if (!gcNumber) {
// Cannot cycle collect if GC has not run first!
MOZ_CRASH();
}
gcHasRun = true;
}
MOZ_ASSERT(!NeedCollect(), "Cannot cycle collect if GC has not run first!");
TraverseNativeRoots(aCb);