mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Merge m-i to m-c
This commit is contained in:
commit
0a4b6f1a99
@ -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;
|
||||
|
||||
|
@ -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
|
||||
|
@ -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]
|
||||
|
14
dom/base/test/test_clearTimeoutIntervalNoArg.html
Normal file
14
dom/base/test/test_clearTimeoutIntervalNoArg.html
Normal 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>
|
@ -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
|
||||
|
@ -66,6 +66,7 @@ if CONFIG['MOZ_B2G_BT']:
|
||||
'bluez/linux',
|
||||
]
|
||||
DEFINES['MOZ_BLUETOOTH_DBUS'] = True
|
||||
DEFINES['HAVE_PTHREADS'] = True
|
||||
|
||||
FINAL_LIBRARY = 'gklayout'
|
||||
|
||||
|
@ -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.
|
||||
*
|
||||
|
@ -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;
|
||||
|
@ -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.)
|
||||
//
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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 */
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
||||
/**
|
||||
|
@ -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) {
|
||||
|
@ -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.
|
||||
|
@ -1,3 +1,6 @@
|
||||
// FIXME bug 975456
|
||||
quit();
|
||||
|
||||
if (!this.hasOwnProperty("TypedObject"))
|
||||
quit();
|
||||
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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);
|
@ -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.
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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 {
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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. */
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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_ */
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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,
|
||||
|
40
layout/base/tests/bug966992-1-ref.html
Normal file
40
layout/base/tests/bug966992-1-ref.html
Normal 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>
|
36
layout/base/tests/bug966992-1.html
Normal file
36
layout/base/tests/bug966992-1.html
Normal 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>
|
42
layout/base/tests/bug966992-2-ref.html
Normal file
42
layout/base/tests/bug966992-2-ref.html
Normal 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"> 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>
|
38
layout/base/tests/bug966992-2.html
Normal file
38
layout/base/tests/bug966992-2.html
Normal 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"> XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX</div>
|
||||
<mask></mask>
|
||||
</div>
|
||||
<script>
|
||||
var x = document.getElementById('x');
|
||||
x.focus();
|
||||
window.getSelection().collapse(x,0);
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
28
layout/base/tests/bug966992-3-ref.html
Normal file
28
layout/base/tests/bug966992-3-ref.html
Normal 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>
|
26
layout/base/tests/bug966992-3.html
Normal file
26
layout/base/tests/bug966992-3.html
Normal 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>
|
@ -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]
|
||||
|
@ -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");
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
73
layout/reftests/bugs/966992-1-ref.html
Normal file
73
layout/reftests/bugs/966992-1-ref.html
Normal 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>
|
65
layout/reftests/bugs/966992-1.html
Normal file
65
layout/reftests/bugs/966992-1.html
Normal 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>
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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>
|
||||
|
@ -22,5 +22,4 @@ function doTest() {
|
||||
}
|
||||
|
||||
window.addEventListener("MozReftestInvalidate", doTest, false);
|
||||
setTimeout(doTest, 4000); // fallback for running outside reftest
|
||||
</script>
|
||||
|
@ -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 {
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
@ -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[];
|
||||
|
@ -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()
|
||||
{
|
||||
|
@ -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();
|
||||
|
@ -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)
|
||||
|
@ -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,
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
|
@ -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");
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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...
|
||||
|
@ -18,6 +18,7 @@ LOCAL_INCLUDES += [
|
||||
'../verify',
|
||||
]
|
||||
|
||||
DEFINES['MAR_NSS'] = True
|
||||
|
||||
if CONFIG['OS_ARCH'] == 'WINNT':
|
||||
USE_STATIC_LIBS = True
|
||||
|
@ -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
|
||||
|
@ -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.)"""
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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}
|
||||
]);
|
||||
}
|
||||
];
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
} } }
|
||||
|
@ -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");
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user