--- a/content/html/content/src/HTMLTrackElement.cpp
+++ b/content/html/content/src/HTMLTrackElement.cpp
@@ -56,16 +56,26 @@ NS_NewHTMLTrackElement(already_AddRefed<
}
return new mozilla::dom::HTMLTrackElement(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;
/** HTMLTrackElement */
HTMLTrackElement::HTMLTrackElement(already_AddRefed<nsINodeInfo> aNodeInfo)
: nsGenericHTMLElement(aNodeInfo)
{
#ifdef PR_LOGGING
--- a/content/html/content/src/HTMLTrackElement.h
+++ b/content/html/content/src/HTMLTrackElement.h
@@ -16,26 +16,16 @@
#include "nsIDocument.h"
#include "nsIDOMHTMLElement.h"
#include "nsIDOMEventTarget.h"
#include "nsIHttpChannel.h"
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
{
public:
HTMLTrackElement(already_AddRefed<nsINodeInfo> aNodeInfo);
virtual ~HTMLTrackElement();
--- a/dom/base/test/mochitest.ini
+++ b/dom/base/test/mochitest.ini
@@ -4,16 +4,17 @@ support-files =
iframe_messageChannel_pingpong.html
iframe_messageChannel_post.html
file_empty.html
iframe_postMessage_solidus.html
[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]
[test_domcursor.html]
[test_domrequest.html]
[test_e4x_for_each.html]
[test_error.html]
[test_gsp-qualified.html]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/test_clearTimeoutIntervalNoArg.html
@@ -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>
--- a/dom/bluetooth/Makefile.in
+++ b/dom/bluetooth/Makefile.in
@@ -17,12 +17,12 @@ ifneq (,$(MOZ_B2G_BT))
ifeq (gonk,$(MOZ_WIDGET_TOOLKIT))
ifdef MOZ_B2G_BT_BLUEZ
LOCAL_INCLUDES += $(MOZ_DBUS_CFLAGS)
endif #MOZ_B2G_BT_BLUEZ
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
--- a/dom/bluetooth/moz.build
+++ b/dom/bluetooth/moz.build
@@ -61,16 +61,17 @@ if CONFIG['MOZ_B2G_BT']:
'bluez/BluetoothHfpManager.cpp',
'bluez/linux/BluetoothDBusService.cpp',
]
LOCAL_INCLUDES += [
'bluez',
'bluez/linux',
]
DEFINES['MOZ_BLUETOOTH_DBUS'] = True
+ DEFINES['HAVE_PTHREADS'] = True
FINAL_LIBRARY = 'gklayout'
LOCAL_INCLUDES += [
'ipc',
]
EXPORTS.mozilla.dom.bluetooth.ipc += [
--- a/dom/interfaces/base/nsIContentPrefService2.idl
+++ b/dom/interfaces/base/nsIContentPrefService2.idl
@@ -62,20 +62,33 @@ interface nsIContentPref;
* The methods of callback objects are always called asynchronously.
*
* Observers are called after callbacks are called, but they are called in the
* same turn of the event loop as callbacks.
*
* 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.
*
* @param domain The preference's domain.
* @param name The preference's name.
* @param context The private-browsing context, if any.
* @param callback handleResult is called once unless no such preference
* exists, in which case handleResult is not called at all.
*/
--- a/dom/ipc/TabChild.cpp
+++ b/dom/ipc/TabChild.cpp
@@ -311,16 +311,42 @@ TabChild::HandleEvent(nsIDOMEvent* aEven
// This meta data may or may not have been a meta viewport tag. If it was,
// we should handle it immediately.
HandlePossibleViewportChange();
}
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,
const char16_t *aData)
{
if (!strcmp(aTopic, BROWSER_ZOOM_TO_RECT)) {
nsCOMPtr<nsIDocShell> docShell(do_QueryInterface(aSubject));
nsCOMPtr<nsITabChild> tabChild(TabChild::GetFrom(docShell));
@@ -347,36 +373,26 @@ TabChild::Observe(nsISupports *aSubject,
mContentDocumentIsDisplayed = true;
// Reset CSS viewport and zoom to default on new page, then
// calculate them properly using the actual metadata from the
// 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();
+ }
}
}
}
return NS_OK;
}
NS_IMETHODIMP
@@ -1453,26 +1469,37 @@ TabChild::RecvUpdateDimensions(const nsR
return true;
}
mOuterRect.x = rect.x;
mOuterRect.y = rect.y;
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));
mWidget->Resize(0, 0, size.width, size.height,
true);
nsCOMPtr<nsIBaseWindow> baseWin = do_QueryInterface(mWebNav);
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;
}
void
TabChild::DispatchMessageManagerMessage(const nsAString& aMessageName,
const nsACString& aJSONData)
--- a/dom/ipc/TabChild.h
+++ b/dom/ipc/TabChild.h
@@ -406,16 +406,19 @@ private:
* frame in the hierarchy which contains us.
*
* |aIsBrowserElement| indicates whether we're a browser (but not an app).
*/
TabChild(ContentChild* aManager, const TabContext& aContext, uint32_t aChromeFlags);
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.)
//
// You should call this after calling TabContext::SetTabContext(). We also
// call this during Init().
void NotifyTabContextUpdated();
bool UseDirectCompositor();
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -1,10 +1,8 @@
-/* -*- 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/. */
#include "MediaManager.h"
#include "MediaStreamGraph.h"
#include "GetUserMediaRequest.h"
@@ -237,20 +235,18 @@ public:
, mWindowID(aWindowID)
, mManager(MediaManager::GetInstance()) {}
NS_IMETHOD
Run()
{
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)) {
return NS_OK;
}
nsCOMPtr<nsIWritableVariant> devices =
do_CreateInstance("@mozilla.org/variant;1");
@@ -277,18 +273,18 @@ public:
static_cast<const void*>(tmp.Elements())
));
success->OnSuccess(devices);
return NS_OK;
}
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;
};
// Handle removing GetUserMediaCallbackMediaStreamListener from main thread
class GetUserMediaListenerRemove: public nsRunnable
{
@@ -1086,26 +1082,25 @@ public:
mLoopbackVideoDevice));
{
ScopedDeletePtr<SourceSet> s (GetSources(backend, mConstraints.mAudiom,
&MediaEngine::EnumerateAudioDevices,
mLoopbackAudioDevice));
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;
// Audio & Video loopback devices to be used based on
// the preference settings. This is currently used for
// automated media tests only.
char* mLoopbackAudioDevice;
char* mLoopbackVideoDevice;
--- a/dom/webidl/Window.webidl
+++ b/dom/webidl/Window.webidl
@@ -83,20 +83,20 @@ typedef any Transferable;
Window implements GlobalEventHandlers;
Window implements WindowEventHandlers;
// http://www.whatwg.org/specs/web-apps/current-work/
[NoInterfaceObject]
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;
// http://www.whatwg.org/specs/web-apps/current-work/
[NoInterfaceObject]
interface WindowBase64 {
[Throws] DOMString btoa(DOMString btoa);
[Throws] DOMString atob(DOMString atob);
--- a/dom/xbl/nsXBLBinding.cpp
+++ b/dom/xbl/nsXBLBinding.cpp
@@ -949,17 +949,17 @@ nsXBLBinding::DoInitJSClass(JSContext *c
return NS_ERROR_FAILURE;
}
if (parent_proto) {
// We need to create a unique classname based on aClassName and
// id. Append a space (an invalid URI character) to ensure that
// 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;
}
// One space, maybe "0x", at most 16 chars (on a 64-bit system) of long,
// and a null-terminator (which PR_snprintf ensures is there even if the
// string representation of what we're printing does not fit in the buffer
// provided).
--- a/gfx/2d/GenericRefCounted.h
+++ b/gfx/2d/GenericRefCounted.h
@@ -48,21 +48,22 @@ class GenericRefCounted : public Generic
GenericRefCounted() : refCnt(0) { }
virtual ~GenericRefCounted() {
MOZ_ASSERT(refCnt == detail::DEAD);
}
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;
#endif
delete this;
}
}
--- a/gfx/gl/GLContext.cpp
+++ b/gfx/gl/GLContext.cpp
@@ -10,34 +10,33 @@
#include <ctype.h>
#include "GLContext.h"
#include "GLBlitHelper.h"
#include "GLBlitTextureImageHelper.h"
#include "GLReadTexImageHelper.h"
#include "gfxCrashReporterUtils.h"
-#include "gfxPlatform.h"
#include "gfxUtils.h"
#include "GLContextProvider.h"
#include "GLTextureImage.h"
#include "nsPrintfCString.h"
#include "nsThreadUtils.h"
#include "prenv.h"
#include "prlink.h"
#include "ScopedGLHelpers.h"
#include "SurfaceStream.h"
#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>
#include "gfxColor.h"
#endif
#if defined(MOZ_WIDGET_COCOA)
#include "nsCocoaFeatures.h"
@@ -303,17 +302,17 @@ GLContext::InitWithPrefix(const char *pr
{
ScopedGfxFeatureReporter reporter("GL Context");
if (mInitialized) {
reporter.SetSuccessful();
return true;
}
- mWorkAroundDriverBugs = gfxPlatform::GetPlatform()->WorkAroundDriverBugs();
+ mWorkAroundDriverBugs = gfxPrefs::WorkAroundDriverBugs();
SymLoadStruct symbols[] = {
{ (PRFuncPtr*) &mSymbols.fActiveTexture, { "ActiveTexture", "ActiveTextureARB", nullptr } },
{ (PRFuncPtr*) &mSymbols.fAttachShader, { "AttachShader", "AttachShaderARB", nullptr } },
{ (PRFuncPtr*) &mSymbols.fBindAttribLocation, { "BindAttribLocation", "BindAttribLocationARB", nullptr } },
{ (PRFuncPtr*) &mSymbols.fBindBuffer, { "BindBuffer", "BindBufferARB", nullptr } },
{ (PRFuncPtr*) &mSymbols.fBindTexture, { "BindTexture", "BindTextureARB", nullptr } },
{ (PRFuncPtr*) &mSymbols.fBlendColor, { "BlendColor", nullptr } },
@@ -1328,17 +1327,17 @@ GLContext::ChooseGLFormats(const Surface
formats.color_rbFormat = LOCAL_GL_RGBA8;
} else {
formats.color_texInternalFormat = IsGLES2() ? LOCAL_GL_RGB : LOCAL_GL_RGB8;
formats.color_texFormat = LOCAL_GL_RGB;
formats.color_rbFormat = LOCAL_GL_RGB8;
}
}
- uint32_t msaaLevel = Preferences::GetUint("gl.msaa-level", 2);
+ uint32_t msaaLevel = gfxPrefs::MSAALevel();
GLsizei samples = msaaLevel * msaaLevel;
samples = std::min(samples, mMaxSamples);
// Bug 778765.
if (WorkAroundDriverBugs() && samples == 1) {
samples = 0;
}
formats.samples = samples;
--- a/gfx/qcms/Makefile.in
+++ b/gfx/qcms/Makefile.in
@@ -36,18 +36,16 @@ ifdef GNU_CC
CSRCS += transform-altivec.c
ALTIVEC_FLAGS=-maltivec
endif
endif
endif
include $(topsrcdir)/config/rules.mk
-CFLAGS += -DMOZ_QCMS
-
# Disable spammy "missing initializer" GCC warning
ifdef GNU_CC
CFLAGS += -Wno-missing-field-initializers
endif # GNU_CC
# special rules for transform-sse*.c to get the right cflags. (taken from pixman/src/Makefile.in)
transform-sse1.$(OBJ_SUFFIX): COMPILE_CFLAGS += $(SSE1_FLAGS)
--- a/gfx/thebes/gfxPlatform.cpp
+++ b/gfx/thebes/gfxPlatform.cpp
@@ -450,18 +450,16 @@ gfxPlatform::Init()
Preferences::AddWeakObserver(gPlatform->mSRGBOverrideObserver, GFX_PREF_CMS_FORCE_SRGB);
gPlatform->mFontPrefsObserver = new FontPrefsObserver();
Preferences::AddStrongObservers(gPlatform->mFontPrefsObserver, kObservedPrefs);
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");
mozilla::gl::GLContext::PlatformStartup();
#ifdef MOZ_WIDGET_ANDROID
// Texture pool init
mozilla::gl::TexturePoolOGL::Init();
--- a/gfx/thebes/gfxPlatform.h
+++ b/gfx/thebes/gfxPlatform.h
@@ -598,18 +598,16 @@ public:
virtual gfxImageFormat GetOffscreenFormat()
{ return gfxImageFormat::RGB24; }
/**
* Returns a logger if one is available and logging is enabled
*/
static PRLogModuleInfo* GetLog(eGfxLog aWhichLog);
- bool WorkAroundDriverBugs() const { return mWorkAroundDriverBugs; }
-
virtual int GetScreenDepth() const;
bool WidgetUpdateFlashing() const { return mWidgetUpdateFlashing; }
uint32_t GetOrientationSyncMillis() const;
/**
* Return the layer debugging options to use browser-wide.
@@ -737,17 +735,16 @@ private:
// The fallback draw target backend to use for canvas, if the preferred backend fails
mozilla::gfx::BackendType mFallbackCanvasBackend;
// The backend to use for content
mozilla::gfx::BackendType mContentBackend;
// Bitmask of backend types we can use to render content
uint32_t mContentBackendBitmask;
mozilla::widget::GfxInfoCollector<gfxPlatform> mAzureCanvasBackendCollector;
- bool mWorkAroundDriverBugs;
mozilla::RefPtr<mozilla::gfx::DrawEventRecorder> mRecorder;
bool mWidgetUpdateFlashing;
uint32_t mOrientationSyncMillis;
bool mLayersPreferMemoryOverShmem;
bool mLayersUseDeprecated;
bool mDrawLayerBorders;
bool mDrawTileBorders;
--- a/gfx/thebes/gfxPrefs.h
+++ b/gfx/thebes/gfxPrefs.h
@@ -13,50 +13,50 @@
// First time gfxPrefs::One() needs to be called on the main thread,
// before any of the methods accessing the values are used, but after
// the Preferences system has been initialized.
// The static methods to access the preference value are safe to call
// 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.
// Pref is the string with the preference name.
// Name argument is the name of the static function to create.
// Type is the type of the preference - bool, int32_t, uint32_t.
// 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
// "layers.dump" as it was set at the start of the session. If the value
// 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
// "gl.msaa-level". If the value is not set, the default would be 2.
// Note that changing a preference from Live to Once is now as simple
// as changing the Update argument. If your code worked before, it will
// keep working, and behave as if the user never changes the preference.
// Things are a bit more complicated and perhaps even dangerous when
// going from Once to Live, or indeed setting a preference to be Live
// in the first place, so be careful. You need to be ready for the
// 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: \
static const char* Get##Name##PrefName() { return Pref; } \
PrefTemplate<UpdatePolicy::Update, Type, Default, Get##Name##PrefName> mPref##Name
class gfxPrefs;
class gfxPrefs MOZ_FINAL
@@ -94,24 +94,28 @@ private:
MOZ_CRASH();
break;
}
}
T mValue;
};
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;
}
return *sInstance;
}
static void Destroy();
static bool Exists();
@@ -128,11 +132,11 @@ private:
static uint32_t PrefGet(const char*, uint32_t);
gfxPrefs();
~gfxPrefs();
gfxPrefs(const gfxPrefs&) MOZ_DELETE;
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 */
--- a/js/public/GCAPI.h
+++ b/js/public/GCAPI.h
@@ -319,16 +319,32 @@ extern JS_FRIEND_API(void)
DisableGenerationalGC(JSRuntime *rt);
/*
* Generational GC may be re-enabled at runtime.
*/
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.
*/
extern JS_FRIEND_API(bool)
IsGenerationalGCEnabled(JSRuntime *rt);
/*
--- a/js/public/Id.h
+++ b/js/public/Id.h
@@ -16,19 +16,20 @@
// such as in JS_NextProperty. Embeddings must not pass JSID_VOID into JSAPI
// entry points expecting a jsid and do not need to handle JSID_VOID in hooks
// receiving a jsid except when explicitly noted in the API contract.
//
// A jsid is not implicitly convertible to or from a jsval; JS_ValueToId or
// 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"
struct jsid
{
size_t asBits;
bool operator==(jsid rhs) const { return asBits == rhs.asBits; }
@@ -111,16 +112,17 @@ JSID_TO_OBJECT(jsid id)
}
static MOZ_ALWAYS_INLINE jsid
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;
}
static MOZ_ALWAYS_INLINE bool
JSID_IS_GCTHING(jsid id)
{
return JSID_IS_STRING(id) || JSID_IS_OBJECT(id);
--- a/js/src/builtin/Utilities.js
+++ b/js/src/builtin/Utilities.js
@@ -163,49 +163,16 @@ function IsObject(v) {
return (typeof v === "object" && v !== null) ||
typeof v === "function" ||
(typeof v === "undefined" && v !== undefined);
}
/********** 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
/**
* Internal debugging tool: checks that the given `mode` permits
* sequential execution
*/
function AssertSequentialIsOK(mode) {
if (mode && mode.mode && mode.mode !== "seq" && ParallelTestsShouldPass())
--- a/js/src/frontend/BytecodeCompiler.cpp
+++ b/js/src/frontend/BytecodeCompiler.cpp
@@ -159,35 +159,38 @@ frontend::MaybeCallSourceHandler(JSConte
if (listener) {
void *listenerTSData;
listener(options.filename(), options.lineno, chars, length,
&listenerTSData, listenerData);
}
}
-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 *
frontend::CompileScript(ExclusiveContext *cx, LifoAlloc *alloc, HandleObject scopeChain,
HandleScript evalCaller,
const ReadOnlyCompileOptions &options,
const jschar *chars, size_t length,
JSString *source_ /* = nullptr */,
@@ -213,26 +216,22 @@ frontend::CompileScript(ExclusiveContext
*/
JS_ASSERT_IF(evalCaller, options.compileAndGo);
JS_ASSERT_IF(evalCaller, options.forEval);
JS_ASSERT_IF(staticLevel != 0, evalCaller);
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)
+
+ RootedScriptSource sourceObject(cx, CreateScriptSourceObject(cx, options));
+ if (!sourceObject)
return nullptr;
- if (!SetScriptSourceFilename(cx, ss, options))
- return nullptr;
-
- RootedScriptSource sourceObject(cx, ScriptSourceObject::create(cx, ss, options));
- if (!sourceObject)
- return nullptr;
+ ScriptSource *ss = sourceObject->source();
SourceCompressionTask mysct(cx);
SourceCompressionTask *sct = extraSct ? extraSct : &mysct;
switch (options.sourcePolicy) {
case CompileOptions::SAVE_SOURCE:
if (!ss->setSourceCopy(cx, chars, length, false, sct))
return nullptr;
@@ -509,24 +508,22 @@ CompileFunctionBody(JSContext *cx, Mutab
// FIXME: make Function pass in two strings and parse them as arguments and
// ProgramElements respectively.
SkipRoot skip(cx, &chars);
MaybeCallSourceHandler(cx, options, chars, length);
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) {
if (!ss->setSourceCopy(cx, chars, length, true, &sct))
return false;
}
bool canLazilyParse = CanLazilyParse(cx, options);
--- a/js/src/frontend/BytecodeCompiler.h
+++ b/js/src/frontend/BytecodeCompiler.h
@@ -34,16 +34,19 @@ bool
CompileFunctionBody(JSContext *cx, MutableHandleFunction fun,
const ReadOnlyCompileOptions &options,
const AutoNameVector &formals, const jschar *chars, size_t length);
bool
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.
*/
void
MaybeCallSourceHandler(JSContext *cx, const ReadOnlyCompileOptions &options,
const jschar *chars, size_t length);
--- a/js/src/jit-test/tests/TypedObject/neutertypedobj.js
+++ b/js/src/jit-test/tests/TypedObject/neutertypedobj.js
@@ -1,8 +1,11 @@
+// FIXME bug 975456
+quit();
+
if (!this.hasOwnProperty("TypedObject"))
quit();
var {StructType, uint32, storage} = TypedObject;
var S = new StructType({f: uint32, g: uint32});
function readFromS(s) {
return s.f + s.g;
--- a/js/src/jit-test/tests/TypedObject/neutertypedobjsizedarray.js
+++ b/js/src/jit-test/tests/TypedObject/neutertypedobjsizedarray.js
@@ -1,8 +1,11 @@
+// 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
// directly from the type.
if (!this.hasOwnProperty("TypedObject"))
quit();
--- a/js/src/jit-test/tests/parallel/spew.js
+++ b/js/src/jit-test/tests/parallel/spew.js
@@ -1,9 +1,11 @@
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,
function (i) { spew(i + ""); }); },
function (r) { return true; });
}
deleted file mode 100644
--- a/js/src/jit-test/tests/self-hosting/makewrappable.js
+++ /dev/null
@@ -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);
--- a/js/src/jit/BaselineIC.cpp
+++ b/js/src/jit/BaselineIC.cpp
@@ -692,27 +692,33 @@ ICStubCompiler::guardProfilingEnabled(Ma
// Check if profiling is enabled
uint32_t *enabledAddr = cx->runtime()->spsProfiler.addressOfEnabled();
masm.branch32(Assembler::Equal, AbsoluteAddress(enabledAddr), Imm32(0), skip);
}
#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);
#endif
saveRegs = GeneralRegisterSet::Intersect(saveRegs, GeneralRegisterSet::Volatile());
masm.PushRegsInMask(saveRegs);
masm.setupUnalignedABICall(2, scratch);
masm.movePtr(ImmPtr(cx->runtime()), scratch);
@@ -5210,27 +5216,23 @@ ICSetElem_Dense::Compiler::generateStubC
// Don't overwrite R0 becuase |obj| might overlap with it, and it's needed
// for post-write barrier later.
ValueOperand tmpVal = regs.takeAnyValue();
masm.loadValue(valueAddr, tmpVal);
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);
// Failure case - fail but first unstow R0 and R1
masm.bind(&failureUnstow);
EmitUnstowICValues(masm, 2);
@@ -5397,27 +5399,23 @@ ICSetElemDenseAddCompiler::generateStubC
masm.bind(&dontConvertDoubles);
// Write the value. No need for pre-barrier since we're not overwriting an old value.
ValueOperand tmpVal = regs.takeAnyValue();
BaseIndex element(scratchReg, key, TimesEight);
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);
// Failure case - fail but first unstow R0 and R1
masm.bind(&failureUnstow);
EmitUnstowICValues(masm, 2);
// Failure case - jump to next stub
@@ -7392,26 +7390,23 @@ ICSetProp_Native::Compiler::generateStub
// Perform the store.
masm.load32(Address(BaselineStubReg, ICSetProp_Native::offsetOfOffset()), scratch);
EmitPreBarrier(masm, BaseIndex(holderReg, scratch, TimesOne), MIRType_Value);
masm.storeValue(R1, BaseIndex(holderReg, scratch, TimesOne));
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.
masm.moveValue(R1, R0);
EmitReturnFromIC(masm);
// Failure case - jump to next stub
masm.bind(&failure);
@@ -7517,25 +7512,22 @@ ICSetPropNativeAddCompiler::generateStub
// initialization.
masm.load32(Address(BaselineStubReg, ICSetProp_NativeAdd::offsetOfOffset()), scratch);
masm.storeValue(R1, BaseIndex(holderReg, scratch, TimesOne));
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);
- }
- masm.bind(&skipBarrier);
+ emitPostWriteBarrierSlot(masm, objReg, R1, scr, saveRegs);
+ }
#endif
// The RHS has to be in R0.
masm.moveValue(R1, R0);
EmitReturnFromIC(masm);
// Failure case - jump to next stub
masm.bind(&failureUnstow);
--- a/js/src/jit/BaselineIC.h
+++ b/js/src/jit/BaselineIC.h
@@ -1072,18 +1072,18 @@ class ICStubCompiler
default:
MOZ_ASSUME_UNREACHABLE("Invalid numInputs");
}
return regs;
}
#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:
virtual ICStub *getStub(ICStubSpace *space) = 0;
ICStubSpace *getStubSpace(JSScript *script) {
if (ICStub::CanMakeCalls(kind))
return script->baselineScript()->fallbackStubSpace();
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1347,23 +1347,16 @@ JS_GetClassObject(JSContext *cx, JSProto
JS_PUBLIC_API(bool)
JS_GetClassPrototype(JSContext *cx, JSProtoKey key, MutableHandleObject objp)
{
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
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)
{
AssertHeapIsIdle(cx);
CHECK_REQUEST(cx);
if (!JSID_IS_ATOM(id))
return JSProto_Null;
@@ -2414,21 +2407,30 @@ JS_GetConstructor(JSContext *cx, HandleO
JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr, JSMSG_NO_CONSTRUCTOR,
proto->getClass()->name);
return nullptr;
}
return &cval.toObject();
}
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;
}
namespace {
class AutoHoldZone
{
public:
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1765,18 +1765,33 @@ extern JS_PUBLIC_API(bool)
JS_EnumerateStandardClasses(JSContext *cx, JS::HandleObject obj);
extern JS_PUBLIC_API(bool)
JS_GetClassObject(JSContext *cx, JSProtoKey key, JS::MutableHandle<JSObject*> objp);
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);
/*
* Returns the original value of |Function.prototype| from the global object in
* which |forObj| was created.
*/
@@ -2550,17 +2565,17 @@ extern JS_PUBLIC_API(JSObject *)
JS_GetConstructor(JSContext *cx, JS::Handle<JSObject*> proto);
/*
* Get a unique identifier for obj, good for the lifetime of obj (even if it
* is moved by a copying GC). Return false on failure (likely out of memory),
* 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 {
enum ZoneSpecifier {
FreshZone = 0,
SystemZone = 1
};
--- a/js/src/jscompartment.cpp
+++ b/js/src/jscompartment.cpp
@@ -17,17 +17,16 @@
#include "jswatchpoint.h"
#include "jswrapper.h"
#include "gc/Marking.h"
#ifdef JS_ION
#include "jit/JitCompartment.h"
#endif
#include "js/RootingAPI.h"
-#include "vm/SelfHosting.h"
#include "vm/StopIterationObject.h"
#include "vm/WrapperObject.h"
#include "jsatominlines.h"
#include "jsfuninlines.h"
#include "jsgcinlines.h"
#include "jsinferinlines.h"
#include "jsobjinlines.h"
@@ -52,16 +51,17 @@ JSCompartment::JSCompartment(Zone *zone,
enterCompartmentDepth(0),
data(nullptr),
objectMetadataCallback(nullptr),
lastAnimationTime(0),
regExps(runtime_),
typeReprs(runtime_),
globalWriteBarriered(false),
propertyTree(thisForCtor()),
+ selfHostingScriptSource(nullptr),
gcIncomingGrayPointers(nullptr),
gcLiveArrayBuffers(nullptr),
gcWeakMapList(nullptr),
debugModeBits(runtime_->debugMode ? DebugFromC : 0),
rngState(0),
watchpointMap(nullptr),
scriptCountsMap(nullptr),
debugScriptMap(nullptr),
@@ -360,22 +360,20 @@ JSCompartment::wrap(JSContext *cx, Mutab
* we parent all wrappers to the global object in their home compartment.
* This loses us some transparency, and is generally very cheesy.
*/
HandleObject global = cx->global();
RootedObject objGlobal(cx, &obj->global());
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);
/* Unwrap the object, but don't unwrap outer windows. */
unsigned flags = 0;
obj.set(UncheckedUnwrap(obj, /* stopAtOuter = */ true, &flags));
@@ -576,16 +574,22 @@ JSCompartment::sweep(FreeOp *fop, bool r
sweepInitialShapeTable();
sweepNewTypeObjectTable(newTypeObjects);
sweepNewTypeObjectTable(lazyTypeObjects);
sweepCallsiteClones();
if (global_ && IsObjectAboutToBeFinalized(global_.unsafeGet()))
global_ = nullptr;
+ if (selfHostingScriptSource &&
+ IsObjectAboutToBeFinalized((JSObject **) selfHostingScriptSource.unsafeGet()))
+ {
+ selfHostingScriptSource = nullptr;
+ }
+
#ifdef JS_ION
if (jitCompartment_)
jitCompartment_->sweep(fop);
#endif
/*
* JIT code increments activeUseCount for any RegExpShared used by jit
* code for the lifetime of the JIT script. Thus, we must perform
--- a/js/src/jscompartment.h
+++ b/js/src/jscompartment.h
@@ -258,16 +258,22 @@ struct JSCompartment
/*
* Hash table of all manually call site-cloned functions from within
* self-hosted code. Cloning according to call site provides extra
* sensitivity for type specialization and inlining.
*/
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;
/*
* During GC, stores the head of a list of incoming pointers from gray cells.
*
* The objects in the list are either cross-compartment wrappers, or
* debugger wrapper objects. The list link is either in the second extra
--- a/js/src/jsfun.h
+++ b/js/src/jsfun.h
@@ -44,17 +44,16 @@ class JSFunction : public JSObject
SELF_HOSTED = 0x0100, /* function is self-hosted builtin and must not be
decompilable nor constructible. */
SELF_HOSTED_CTOR = 0x0200, /* function is self-hosted builtin constructor and
must be constructible but not decompilable. */
HAS_REST = 0x0400, /* function has a rest (...) parameter */
// 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,
INTERPRETED_LAMBDA = INTERPRETED | LAMBDA,
INTERPRETED_LAMBDA_ARROW = INTERPRETED | LAMBDA | ARROW
};
static void staticAsserts() {
@@ -122,20 +121,16 @@ class JSFunction : public JSObject
/* Possible attributes of an interpreted function: */
bool isFunctionPrototype() const { return flags() & IS_FUN_PROTO; }
bool isExprClosure() const { return flags() & EXPR_CLOSURE; }
bool hasGuessedAtom() const { return flags() & HAS_GUESSED_ATOM; }
bool isLambda() const { return flags() & LAMBDA; }
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;
}
bool hasScript() const {
return flags() & INTERPRETED;
}
@@ -202,22 +197,16 @@ class JSFunction : public JSObject
flags_ |= SELF_HOSTED;
}
void setIsSelfHostedConstructor() {
JS_ASSERT(!isSelfHostedConstructor());
flags_ |= SELF_HOSTED_CTOR;
}
- void makeWrappable() {
- JS_ASSERT(isSelfHostedBuiltin());
- JS_ASSERT(!isWrappable());
- flags_ |= SH_WRAPPABLE;
- }
-
void setIsFunctionPrototype() {
JS_ASSERT(!isFunctionPrototype());
flags_ |= IS_FUN_PROTO;
}
// Can be called multiple times by the parser.
void setIsExprClosure() {
flags_ |= EXPR_CLOSURE;
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -3249,39 +3249,52 @@ js_GetClassPrototype(ExclusiveContext *c
return false;
Value v = global->getPrototype(key);
if (v.isObject())
protop.set(&v.toObject());
return true;
}
-JSProtoKey
-js_IdentifyClassPrototype(JSObject *obj)
-{
- // 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).
+static bool
+IsStandardPrototype(JSObject *obj, JSProtoKey key)
+{
GlobalObject &global = obj->global();
Value v = global.getPrototype(key);
- if (v.isObject() && obj == &v.toObject())
+ return v.isObject() && obj == &v.toObject();
+}
+
+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;
-
- // False alarm - just an instance.
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)
{
MOZ_ASSERT(clasp);
JSProtoKey protoKey = GetClassProtoKey(clasp);
RootedId id(cx);
if (protoKey != JSProto_Null) {
JS_ASSERT(JSProto_Null < protoKey);
--- a/js/src/jsobj.h
+++ b/js/src/jsobj.h
@@ -1324,23 +1324,16 @@ extern bool
js_GetClassObject(js::ExclusiveContext *cx, JSProtoKey key,
js::MutableHandleObject objp);
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
* js_GetClass{Object,Prototype}.
*/
bool
js_FindClassObject(js::ExclusiveContext *cx, js::MutableHandleObject protop,
const js::Class *clasp);
--- a/js/src/jsproxy.cpp
+++ b/js/src/jsproxy.cpp
@@ -2538,38 +2538,35 @@ bool
Proxy::set(JSContext *cx, HandleObject proxy, HandleObject receiver, HandleId id, bool strict,
MutableHandleValue vp)
{
JS_CHECK_RECURSION(cx, return false);
BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
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
Proxy::keys(JSContext *cx, HandleObject proxy, AutoIdVector &props)
{
JS_CHECK_RECURSION(cx, return false);
BaseProxyHandler *handler = proxy->as<ProxyObject>().handler();
AutoEnterPolicy policy(cx, handler, proxy, JSID_VOIDHANDLE, BaseProxyHandler::ENUMERATE, true);
--- a/js/src/jsscript.cpp
+++ b/js/src/jsscript.cpp
@@ -24,26 +24,28 @@
#include "jsgc.h"
#include "jsobj.h"
#include "jsopcode.h"
#include "jsprf.h"
#include "jstypes.h"
#include "jsutil.h"
#include "jswrapper.h"
+#include "frontend/BytecodeCompiler.h"
#include "frontend/BytecodeEmitter.h"
#include "frontend/SharedContext.h"
#include "gc/Marking.h"
#include "jit/BaselineJIT.h"
#include "jit/IonCode.h"
#include "js/OldDebugAPI.h"
#include "vm/ArgumentsObject.h"
#include "vm/Compression.h"
#include "vm/Debugger.h"
#include "vm/Opcodes.h"
+#include "vm/SelfHosting.h"
#include "vm/Shape.h"
#include "vm/Xdr.h"
#include "jsfuninlines.h"
#include "jsinferinlines.h"
#include "jsobjinlines.h"
#include "vm/ScopeObject-inl.h"
@@ -2780,20 +2782,38 @@ js::CloneScript(JSContext *cx, HandleObj
HeapPtrObject *vector = src->regexps()->vector;
for (unsigned i = 0; i < nregexps; i++) {
JSObject *clone = CloneScriptRegExpObject(cx, vector[i]->as<RegExpObject>());
if (!clone || !regexps.append(clone))
return nullptr;
}
}
- /* 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. */
CompileOptions options(cx);
options.setPrincipals(cx->compartment()->principals)
.setOriginPrincipals(src->originPrincipals())
.setCompileAndGo(src->compileAndGo())
.setSelfHostingMode(src->selfHosted())
--- a/js/src/jsworkers.cpp
+++ b/js/src/jsworkers.cpp
@@ -635,17 +635,17 @@ GlobalWorkerThreadState::finishParseTask
!iter.done();
iter.next())
{
types::TypeObject *object = iter.get<types::TypeObject>();
TaggedProto proto(object->proto());
if (!proto.isObject())
continue;
- JSProtoKey key = js_IdentifyClassPrototype(proto.toObject());
+ JSProtoKey key = JS::IdentifyStandardPrototype(proto.toObject());
if (key == JSProto_Null)
continue;
JSObject *newProto = GetClassPrototypePure(&parseTask->scopeChain->global(), key);
JS_ASSERT(newProto);
object->setProtoUnchecked(newProto);
}
--- a/js/src/vm/GlobalObject.cpp
+++ b/js/src/vm/GlobalObject.cpp
@@ -762,21 +762,16 @@ GlobalObject::getSelfHostedFunction(JSCo
unsigned nargs, MutableHandleValue funVal)
{
RootedId shId(cx, AtomToId(selfHostedName));
RootedObject holder(cx, cx->global()->intrinsicsHolder());
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)
return false;
fun->setIsSelfHostedBuiltin();
fun->setExtendedSlot(0, StringValue(selfHostedName));
funVal.setObject(*fun);
--- a/js/src/vm/Runtime.h
+++ b/js/src/vm/Runtime.h
@@ -836,16 +836,20 @@ struct JSRuntime : public JS::shadow::Ru
/*
* Both of these allocators are used for regular expression code which is shared at the
* thread-data level.
*/
JSC::ExecutableAllocator *execAlloc_;
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. */
js::InterpreterStack interpreterStack_;
JSC::ExecutableAllocator *createExecutableAllocator(JSContext *cx);
WTF::BumpPointerAllocator *createBumpPointerAllocator(JSContext *cx);
js::jit::JitRuntime *createJitRuntime(JSContext *cx);
@@ -879,25 +883,24 @@ struct JSRuntime : public JS::shadow::Ru
//-------------------------------------------------------------------------
// Self-hosting support
//-------------------------------------------------------------------------
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
//-------------------------------------------------------------------------
/*
* Set the default locale for the ECMAScript Internationalization API
* (Intl.Collator, Intl.NumberFormat, Intl.DateTimeFormat).
--- a/js/src/vm/SelfHosting.cpp
+++ b/js/src/vm/SelfHosting.cpp
@@ -159,28 +159,16 @@ intrinsic_MakeConstructible(JSContext *c
return false;
}
ctor->as<JSFunction>().setIsSelfHostedConstructor();
args.rval().setUndefined();
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
* function arguments.
*
* The user must supply the argument number of the value in question; it
* _cannot_ be automatically determined.
*/
@@ -657,17 +645,16 @@ intrinsic_RuntimeDefaultLocale(JSContext
static const JSFunctionSpec intrinsic_functions[] = {
JS_FN("ToObject", intrinsic_ToObject, 1,0),
JS_FN("ToInteger", intrinsic_ToInteger, 1,0),
JS_FN("IsCallable", intrinsic_IsCallable, 1,0),
JS_FN("ThrowError", intrinsic_ThrowError, 4,0),
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),
JS_FN("UnsafePutElements", intrinsic_UnsafePutElements, 3,0),
JS_FN("UnsafeSetReservedSlot", intrinsic_UnsafeSetReservedSlot, 3,0),
JS_FN("UnsafeGetReservedSlot", intrinsic_UnsafeGetReservedSlot, 2,0),
JS_FN("HaveSameClass", intrinsic_HaveSameClass, 2,0),
JS_FN("IsPackedArray", intrinsic_IsPackedArray, 1,0),
@@ -772,21 +759,62 @@ static const JSFunctionSpec intrinsic_fu
JS_FNINFO("ParallelSpew",
JSNativeThreadSafeWrapper<intrinsic_ParallelSpew>,
&intrinsic_ParallelSpew_jitInfo, 1,0),
#endif
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)
: nullptr);
if (!(selfHostingGlobal_ = JS_NewGlobalObject(cx, &self_hosting_global_class,
nullptr, JS::DontFireOnNewGlobalHook)))
return false;
JSAutoCompartment ac(cx, selfHostingGlobal_);
@@ -803,42 +831,18 @@ JSRuntime::initSelfHosting(JSContext *cx
if (!GlobalObject::initStandardClasses(cx, shg))
return false;
if (!JS_DefineFunctions(cx, shg, intrinsic_functions))
return false;
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
* early in the startup process for any other reporter to be registered
* and we don't want errors in self-hosted code to be silently swallowed.
*/
JSErrorReporter oldReporter = JS_SetErrorReporter(cx, selfHosting_ErrorReporter);
RootedValue rv(cx);
@@ -877,163 +881,202 @@ void
JSRuntime::finishSelfHosting()
{
selfHostingGlobal_ = nullptr;
}
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
+CloneValue(JSContext *cx, const Value &selfHostedValue, MutableHandleValue vp, CloneMemory &clonedObjects);
static bool
-GetUnclonedValue(JSContext *cx, Handle<JSObject*> src, HandleId id, MutableHandleValue vp)
+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)
{
+ 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);
- AutoIdVector ids(cx);
- {
- AutoCompartment ac(cx, obj);
- if (!GetPropertyNames(cx, obj, JSITER_OWNONLY, &ids))
- return false;
- }
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;
}
}
return true;
}
-static gc::AllocKind
-GetObjectAllocKindForClone(JSRuntime *rt, JSObject *obj)
+static JSObject *
+CloneObject(JSContext *cx, JSObject *selfHostedObject, CloneMemory &clonedObjects)
{
- 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)
-{
- 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);
} else {
MOZ_ASSUME_UNREACHABLE("Self-hosting CloneValue can't clone given value.");
}
return true;
}
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>());
// JSFunction::generatorKind can't handle lazy self-hosted functions, so we make sure there
// aren't any.
JS_ASSERT(!sourceFun->isGenerator());
RootedScript sourceScript(cx, sourceFun->getOrCreateScript(cx));
if (!sourceScript)
@@ -1051,109 +1094,35 @@ JSRuntime::cloneSelfHostedFunctionScript
targetFun->setScript(cscript);
JS_ASSERT(targetFun->isExtended());
return true;
}
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
* means we're currently executing the self-hosting script while
* 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;
- }
- 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;
+ } else {
+ vp.set(selfHostedValue);
}
- 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);
+ return true;
}
JSFunction *
js::SelfHostedFunction(JSContext *cx, HandlePropertyName propName)
{
RootedValue func(cx);
if (!GlobalObject::getIntrinsicValue(cx, cx->global(), propName, &func))
return nullptr;
--- a/js/src/vm/SelfHosting.h
+++ b/js/src/vm/SelfHosting.h
@@ -9,25 +9,20 @@
#include "jsapi.h"
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_ */
--- a/js/xpconnect/wrappers/AccessCheck.cpp
+++ b/js/xpconnect/wrappers/AccessCheck.cpp
@@ -200,17 +200,17 @@ AccessCheck::isCrossOriginAccessPermitte
// For XOWs, we generally want to deny enumerate-like operations, but fail
// silently (see CrossOriginAccessiblePropertiesOnly::deny).
if (act == Wrapper::ENUMERATE)
return false;
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
name = clasp->name;
if (JSID_IS_STRING(id)) {
if (IsPermitted(name, JSID_TO_FLAT_STRING(id), act == Wrapper::SET))
return true;
--- a/js/xpconnect/wrappers/ChromeObjectWrapper.cpp
+++ b/js/xpconnect/wrappers/ChromeObjectWrapper.cpp
@@ -31,17 +31,17 @@ AllowedByBase(JSContext *cx, HandleObjec
}
static bool
PropIsFromStandardPrototype(JSContext *cx, JS::MutableHandle<JSPropertyDescriptor> desc)
{
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
// ChromeObjectWrapperBase and get an unfiltered view of the underlying object.
// This lets us determine whether the property we would have found (given a
// transparent wrapper) would have come off a standard prototype.
static bool
PropIsFromStandardPrototype(JSContext *cx, HandleObject wrapper,
--- a/js/xpconnect/wrappers/WrapperFactory.cpp
+++ b/js/xpconnect/wrappers/WrapperFactory.cpp
@@ -169,17 +169,17 @@ WrapperFactory::PrepareForWrapping(JSCon
// subsumes call below.
bool subsumes = AccessCheck::subsumes(js::GetContextCompartment(cx),
js::GetObjectCompartment(obj));
XrayType xrayType = GetXrayType(obj);
if (!subsumes && xrayType == NotXray) {
JSProtoKey key = JSProto_Null;
{
JSAutoCompartment ac(cx, obj);
- key = JS_IdentifyClassPrototype(obj);
+ key = IdentifyStandardPrototype(obj);
}
if (key != JSProto_Null) {
RootedObject homeProto(cx);
if (!JS_GetClassPrototype(cx, key, &homeProto))
return nullptr;
MOZ_ASSERT(homeProto);
// No need to double-wrap here. We should never have waivers to
// COWs.
@@ -369,17 +369,17 @@ JSObject *
WrapperFactory::Rewrap(JSContext *cx, HandleObject existing, HandleObject obj,
HandleObject wrappedProto, HandleObject parent,
unsigned flags)
{
MOZ_ASSERT(!IsWrapper(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.
MOZ_ASSERT(XPCJSRuntime::Get()->GetJSContextStack()->Peek() == cx);
// Compute the information we need to select the right wrapper.
JSCompartment *origin = js::GetObjectCompartment(obj);
JSCompartment *target = js::GetContextCompartment(cx);
--- a/js/xpconnect/wrappers/XrayWrapper.cpp
+++ b/js/xpconnect/wrappers/XrayWrapper.cpp
@@ -32,44 +32,33 @@ using namespace mozilla;
using js::Wrapper;
using js::BaseProxyHandler;
using js::IsCrossCompartmentWrapper;
using js::UncheckedUnwrap;
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
GetXrayType(JSObject *obj)
{
obj = js::UncheckedUnwrap(obj, /* stopAtOuter = */ false);
if (mozilla::dom::UseDOMXray(obj))
return XrayForDOMObject;
const js::Class* clasp = js::GetObjectClass(obj);
if (IS_WN_CLASS(clasp) || clasp->ext.innerObject)
return XrayForWrappedNative;
return NotXray;
}
+const uint32_t JSSLOT_RESOLVING = 0;
ResolvingId::ResolvingId(JSContext *cx, HandleObject wrapper, HandleId id)
: mId(id),
mHolder(cx, getHolderObject(wrapper)),
mPrev(getResolvingId(mHolder)),
mXrayShadowing(false)
{
js::SetReservedSlot(mHolder, JSSLOT_RESOLVING, js::PrivateValue(this));
}
@@ -188,16 +177,20 @@ private:
JSObject* attachExpandoObject(JSContext *cx, HandleObject target,
nsIPrincipal *origin,
HandleObject exclusiveGlobal);
};
class XPCWrappedNativeXrayTraits : public XrayTraits
{
public:
+ enum {
+ HasPrototype = 0
+ };
+
static const XrayType Type = XrayForWrappedNative;
virtual bool resolveNativeProperty(JSContext *cx, HandleObject wrapper,
HandleObject holder, HandleId id,
MutableHandle<JSPropertyDescriptor> desc, unsigned flags);
virtual bool resolveOwnProperty(JSContext *cx, Wrapper &jsWrapper, HandleObject wrapper,
HandleObject holder, HandleId id,
MutableHandle<JSPropertyDescriptor> desc, unsigned flags);
@@ -222,22 +215,33 @@ public:
}
virtual void preserveWrapper(JSObject *target);
typedef ResolvingId ResolvingIdImpl;
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,
HandleObject holder, HandleId id,
MutableHandle<JSPropertyDescriptor> desc, unsigned flags);
virtual bool resolveOwnProperty(JSContext *cx, Wrapper &jsWrapper, HandleObject wrapper,
HandleObject holder, HandleId id,
MutableHandle<JSPropertyDescriptor> desc, unsigned flags);
@@ -522,16 +526,27 @@ XPCWrappedNativeXrayTraits::isResolving(
jsid id)
{
ResolvingId *cur = ResolvingId::getResolvingId(holder);
if (!cur)
return false;
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.
bool
holder_get(JSContext *cx, HandleObject wrapper, HandleId id, MutableHandleValue vp)
{
// JSClass::getProperty is wacky enough that it's hard to be sure someone
// can't inherit this getter by prototyping a random object to an
@@ -864,16 +879,35 @@ XrayTraits::resolveOwnProperty(JSContext
if (found) {
if (!JS_WrapPropertyDescriptor(cx, desc))
return false;
// Pretend the property lives on the wrapper.
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;
}
bool
XPCWrappedNativeXrayTraits::resolveOwnProperty(JSContext *cx, Wrapper &jsWrapper,
HandleObject wrapper, HandleObject holder,
HandleId id, MutableHandle<JSPropertyDescriptor> desc,
unsigned flags)
@@ -1234,16 +1268,17 @@ DOMXrayTraits::createHolder(JSContext *c
RootedObject global(cx, JS_GetGlobalForObject(cx, wrapper));
return JS_NewObjectWithGivenProto(cx, nullptr, JS::NullPtr(), global);
}
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>
XrayWrapper<Base, Traits>::~XrayWrapper()
{
}
namespace XrayUtils {
@@ -1437,30 +1472,16 @@ XrayWrapper<Base, Traits>::getPropertyDe
return true;
}
typename Traits::ResolvingIdImpl resolving(cx, wrapper, id);
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,
// because there might be a new dynamic |own| property that appears and
// shadows a previously-resolved non-own property that we cached on the
// holder. This can happen with indexed properties on NodeLists, for example,
// which are |own| value props.
//
@@ -1763,29 +1784,29 @@ template <typename Base, typename Traits
bool
XrayWrapper<Base, Traits>::get(JSContext *cx, HandleObject wrapper,
HandleObject receiver, HandleId id,
MutableHandleValue vp)
{
// 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>
bool
XrayWrapper<Base, Traits>::set(JSContext *cx, HandleObject wrapper,
HandleObject receiver, HandleId id,
bool strict, MutableHandleValue vp)
{
// 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>
bool
XrayWrapper<Base, Traits>::has(JSContext *cx, HandleObject wrapper,
HandleId id, bool *bp)
{
// Skip our Base if it isn't already ProxyHandler.
@@ -1858,34 +1879,27 @@ XrayWrapper<Base, Traits>::getPrototypeO
// specializations (and therefore a helper class), which is all more trouble
// than it's worth. Do a dynamic check.
if (Base::hasSecurityPolicy())
return Base::getPrototypeOf(cx, wrapper, protop);
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);
}
template <typename Base, typename Traits>
bool
XrayWrapper<Base, Traits>::setPrototypeOf(JSContext *cx, JS::HandleObject wrapper,
--- a/js/xpconnect/wrappers/XrayWrapper.h
+++ b/js/xpconnect/wrappers/XrayWrapper.h
@@ -23,17 +23,17 @@ namespace xpc {
bool
holder_get(JSContext *cx, JS::HandleObject holder, JS::HandleId id, JS::MutableHandleValue vp);
bool
holder_set(JSContext *cx, JS::HandleObject holder, JS::HandleId id, bool strict,
JS::MutableHandleValue vp);
namespace XrayUtils {
-extern const JSClass HolderClass;
+bool IsXPCWNHolderClass(const JSClass *clasp);
bool CloneExpandoChain(JSContext *cx, JSObject *src, JSObject *dst);
bool
IsTransparent(JSContext *cx, JS::HandleObject wrapper, JS::HandleId id);
JSObject *
GetNativePropertiesObject(JSContext *cx, JSObject *wrapper);
@@ -109,16 +109,37 @@ class XrayWrapper : public Base {
virtual bool getPrototypeOf(JSContext *cx, JS::HandleObject wrapper,
JS::MutableHandleObject protop) MOZ_OVERRIDE;
virtual bool setPrototypeOf(JSContext *cx, JS::HandleObject wrapper,
JS::HandleObject proto, bool *bp) MOZ_OVERRIDE;
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);
};
#define PermissiveXrayXPCWN xpc::XrayWrapper<js::CrossCompartmentWrapper, xpc::XPCWrappedNativeXrayTraits>
#define SecurityXrayXPCWN xpc::XrayWrapper<js::CrossCompartmentSecurityWrapper, xpc::XPCWrappedNativeXrayTraits>
#define PermissiveXrayDOM xpc::XrayWrapper<js::CrossCompartmentWrapper, xpc::DOMXrayTraits>
#define SecurityXrayDOM xpc::XrayWrapper<js::CrossCompartmentSecurityWrapper, xpc::DOMXrayTraits>
--- a/layout/base/nsPresShell.cpp
+++ b/layout/base/nsPresShell.cpp
@@ -3481,17 +3481,23 @@ PresShell::ScrollFrameRectIntoView(nsIFr
nsRect rect = aRect;
nsIFrame* container = aFrame;
// Walk up the frame hierarchy scrolling the rect into view and
// keeping rect relative to container
do {
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,
// so our rect's offset should decrease
rect += oldPosition - newPosition;
if (oldPosition != newPosition) {
didScroll = true;
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/bug966992-1-ref.html
@@ -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>
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/bug966992-1.html
@@ -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>
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/bug966992-2-ref.html
@@ -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>
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/bug966992-2.html
@@ -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>
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/bug966992-3-ref.html
@@ -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>
new file mode 100644
--- /dev/null
+++ b/layout/base/tests/bug966992-3.html
@@ -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>
--- a/layout/base/tests/mochitest.ini
+++ b/layout/base/tests/mochitest.ini
@@ -139,16 +139,22 @@ support-files =
bug664087-1.html
bug664087-1-ref.html
bug664087-2.html
bug664087-2-ref.html
bug682712-1.html
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]
[test_bug558663.html]
[test_bug559499.html]
[test_bug569520.html]
[test_bug582181-1.html]
[test_bug582181-2.html]
--- a/layout/base/tests/test_reftests_with_caret.html
+++ b/layout/base/tests/test_reftests_with_caret.html
@@ -137,16 +137,21 @@ var tests = [
function() {SpecialPowers.clearUserPref("bidi.browser.ui");} ,
[ 'bug746993-1.html' , 'bug746993-1-ref.html' ] ,
];
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");
}
var testIndex = 0;
function nextTest() {
if (testIndex < tests.length) {
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -1604,21 +1604,30 @@ ApplyOverflowClipping(nsDisplayListBuild
// Only -moz-hidden-unscrollable is handled here (and 'hidden' for table
// frames, and any non-visible value for blocks in a paginated context).
// We allow -moz-hidden-unscrollable to apply to any kind of frame. This
// is required by comboboxes which make their display text (an inline frame)
// have clipping.
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
static void PaintDebugBorder(nsIFrame* aFrame, nsRenderingContext* aCtx,
const nsRect& aDirtyRect, nsPoint aPt) {
nsRect r(aPt, aFrame->GetSize());
if (aFrame->HasView()) {
aCtx->SetColor(NS_RGB(0,0,255));
--- a/layout/generic/nsGfxScrollFrame.cpp
+++ b/layout/generic/nsGfxScrollFrame.cpp
@@ -3,16 +3,17 @@
* 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/. */
/* rendering object to wrap rendering objects that should be scrollable */
#include "nsGfxScrollFrame.h"
#include "base/compiler_specific.h"
+#include "DisplayItemClip.h"
#include "nsCOMPtr.h"
#include "nsPresContext.h"
#include "nsView.h"
#include "nsIScrollable.h"
#include "nsContainerFrame.h"
#include "nsGkAtoms.h"
#include "nsINameSpaceManager.h"
#include "nsContentList.h"
@@ -396,37 +397,38 @@ nsresult
nsHTMLScrollFrame::ReflowScrolledFrame(ScrollReflowState* aState,
bool aAssumeHScroll,
bool aAssumeVScroll,
nsHTMLReflowMetrics* aMetrics,
bool aFirstPass)
{
// 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();
nscoord computedMaxHeight = aState->mReflowState.ComputedMaxHeight();
if (!ShouldPropagateComputedHeightToScrolledContent()) {
computedHeight = NS_UNCONSTRAINEDSIZE;
computedMinHeight = 0;
computedMaxHeight = NS_UNCONSTRAINEDSIZE;
}
if (aAssumeHScroll) {
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) {
nsSize vScrollbarPrefSize;
GetScrollbarMetrics(aState->mBoxState, mHelper.mVScrollbarBox,
nullptr, &vScrollbarPrefSize, true);
availWidth = std::max(0, availWidth - vScrollbarPrefSize.width);
}
@@ -434,17 +436,17 @@ nsHTMLScrollFrame::ReflowScrolledFrame(S
nsPresContext* presContext = PresContext();
// Pass false for aInit so we can pass in the correct padding.
nsHTMLReflowState kidReflowState(presContext, aState->mReflowState,
mHelper.mScrolledFrame,
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);
kidReflowState.ComputedMinHeight() = computedMinHeight;
kidReflowState.ComputedMaxHeight() = computedMaxHeight;
// Temporarily set mHasHorizontalScrollbar/mHasVerticalScrollbar to
// reflect our assumptions while we reflow the child.
@@ -474,16 +476,28 @@ nsHTMLScrollFrame::ReflowScrolledFrame(S
// setting their mOverflowArea. This is wrong because every frame should
// always set mOverflowArea. In fact nsObjectFrame and nsFrameFrame don't
// support the 'outline' property because of this. Rather than fix the world
// right now, just fix up the overflow area if necessary. Note that we don't
// check HasOverflowRect() because it could be set even though the
// 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;
return rv;
}
bool
@@ -2267,20 +2281,84 @@ static bool IsFocused(nsIContent* aConte
// walk up the tree until we reach a non-anonymous element.
while (aContent && aContent->IsInAnonymousSubtree()) {
aContent = aContent->GetParent();
}
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();
}
mOuter->DisplayBorderBackgroundOutline(aBuilder, aLists);
if (aBuilder->IsPaintingToWindow()) {
@@ -2325,23 +2403,22 @@ ScrollFrameHelper::BuildDisplayList(nsDi
// in the positioned-elements layer on top of everything else by the call
// to AppendScrollPartsTo(..., true) further down.
AppendScrollPartsTo(aBuilder, aDirtyRect, aLists, createLayersForScrollbars,
false);
// 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;
bool usingDisplayport =
nsLayoutUtils::GetDisplayPort(mOuter->GetContent(), &displayPort) &&
!aBuilder->IsForEventDelivery();
if (usingDisplayport) {
dirtyRect = displayPort;
@@ -2393,16 +2470,35 @@ ScrollFrameHelper::BuildDisplayList(nsDi
} else {
clipState.ClipContainingBlockDescendants(clip, haveRadii ? radii : nullptr);
}
}
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
// parent process as well).
// When a displayport is being used, force building of a layer so that
// CompositorParent can always find the scrollable layer for the root content
// document.
// If the element is marked 'scrollgrab', also force building of a layer
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/966992-1-ref.html
@@ -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>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/bugs/966992-1.html
@@ -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>
--- a/layout/reftests/bugs/reftest.list
+++ b/layout/reftests/bugs/reftest.list
@@ -234,17 +234,17 @@ skip-if(B2G) fails-if(Android) != 192767
== 234686-19.html 234686-ref.html
skip-if(B2G) == 234964-1.html 234964-1-ref.html
== 234964-2.html 234964-2-ref.html
== 235593-1.html 235593-1-ref.html
== 236539-1.html 236539-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
== 243519-2.html 243519-2-ref.html
== 243519-3.html 243519-3-ref.html
== 243519-4a.html 243519-4-ref.html
== 243519-4b.html 243519-4-ref.html
== 243519-4c.html 243519-4-ref.html
@@ -1791,10 +1791,11 @@ fuzzy-if(OSX==10.6,2,30) == 933264-1.htm
== 941940-1.html 941940-1-ref.html
== 942017.html 942017-ref.html
== 942672-1.html 942672-1-ref.html
== 953334-win32-clipping.html 953334-win32-clipping-ref.html
== 956513-1.svg 956513-1-ref.svg
== 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
--- a/layout/reftests/forms/placeholder/reftest.list
+++ b/layout/reftests/forms/placeholder/reftest.list
@@ -11,17 +11,17 @@
== placeholder-1-text.html placeholder-visible-ref.html
== placeholder-1-password.html placeholder-visible-ref.html
== placeholder-1-textarea.html placeholder-visible-textarea-ref.html
== placeholder-2.html placeholder-visible-ref.html
== placeholder-2-textarea.html placeholder-visible-textarea-ref.html
== 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
# needs-focus == placeholder-9.html placeholder-focus-ref.html
needs-focus == placeholder-10.html placeholder-visible-ref.html
== placeholder-11.html placeholder-visible-ref.html
== placeholder-12.html placeholder-visible-ref.html
== placeholder-13.html placeholder-visible-ref.html
--- a/layout/reftests/forms/textarea/padding-scrollbar-placement-ref.html
+++ b/layout/reftests/forms/textarea/padding-scrollbar-placement-ref.html
@@ -23,21 +23,29 @@
#cover {
position: absolute;
left: 400px;
top: 50px;
width: 100px;
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>
<script>
var ss = [];
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>
</html>
--- a/layout/reftests/svg/text/multiple-x-percentages-3.html
+++ b/layout/reftests/svg/text/multiple-x-percentages-3.html
@@ -17,10 +17,9 @@ function doTest() {
var text = iframe.contentDocument.querySelectorAll("text");
text[0].firstChild.nodeValue += "!";
text[1].firstChild.nodeValue += "!";
document.documentElement.removeAttribute("class");
}
window.addEventListener("MozReftestInvalidate", doTest, false);
-setTimeout(doTest, 4000); // fallback for running outside reftest
</script>
--- a/layout/style/forms.css
+++ b/layout/style/forms.css
@@ -110,16 +110,17 @@ textarea {
cursor: text;
resize: both;
-moz-binding: url("chrome://global/content/platformHTMLBindings.xml#textAreas");
-moz-appearance: textfield-multiline;
text-indent: 0;
-moz-user-select: text;
text-shadow: none;
word-wrap: break-word;
+ overflow-clip-box: content-box;
}
textarea > scrollbar {
cursor: default;
}
textarea > .anonymous-div,
input > .anonymous-div,
@@ -132,16 +133,17 @@ textarea::-moz-placeholder {
margin: 0px;
text-decoration: inherit;
-moz-text-decoration-color: inherit;
-moz-text-decoration-style: inherit;
display: inline-block;
ime-mode: inherit;
resize: inherit;
-moz-control-character-visibility: visible;
+ overflow-clip-box: inherit;
}
textarea > .anonymous-div.wrap,
input > .anonymous-div.wrap {
white-space: pre-wrap;
}
textarea > .anonymous-div.inherit-overflow,
input > .anonymous-div.inherit-overflow {
@@ -373,16 +375,21 @@ textarea:disabled {
cursor: default;
}
option:disabled,
optgroup:disabled {
background-color: transparent;
}
+input[type="text"],
+input[type="password"] {
+ overflow-clip-box: content-box;
+}
+
/* hidden inputs */
input[type="hidden"] {
-moz-appearance: none;
display: none !important;
padding: 0;
border: 0;
cursor: auto;
-moz-user-focus: ignore;
@@ -894,16 +901,17 @@ input[type=range]::-moz-range-thumb {
-moz-user-select: none ! important;
}
input[type="number"] {
-moz-appearance: number-input;
/* 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 {
/* Prevent styling that would change the type of frame we construct. */
display: flex;
float: none !important;
position: static !important;
height: 100%;
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -242,16 +242,22 @@ public:
nsRuleData* aRuleData,
nsIURI* aDocURL,
nsIURI* aBaseURL,
nsIPrincipal* aDocPrincipal,
nsCSSStyleSheet* aSheet,
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;
class nsAutoFailingSupportsRule;
friend class nsAutoFailingSupportsRule;
class nsAutoSuppressErrors;
@@ -1300,17 +1306,21 @@ CSSParserImpl::ParseProperty(const nsCSS
css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aSheetURI);
InitScanner(scanner, reporter, aSheetURI, aBaseURI, aSheetPrincipal);
mSection = eCSSSection_General;
scanner.SetSVGMode(aIsSVGMode);
*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);
OUTPUT_ERROR();
ReleaseScanner();
return NS_OK;
}
@@ -1555,18 +1565,17 @@ CSSParserImpl::ParseKeyframeSelectorStri
bool
CSSParserImpl::EvaluateSupportsDeclaration(const nsAString& aProperty,
const nsAString& aValue,
nsIURI* aDocURL,
nsIURI* aBaseURL,
nsIPrincipal* aDocPrincipal)
{
- nsCSSProperty propID = nsCSSProps::LookupProperty(aProperty,
- nsCSSProps::eEnabled);
+ nsCSSProperty propID = LookupEnabledProperty(aProperty);
if (propID == eCSSProperty_UNKNOWN) {
return false;
}
nsCSSScanner scanner(aValue, 0);
css::ErrorReporter reporter(scanner, mSheet, mChildLoader, aDocURL);
InitScanner(scanner, reporter, aDocURL, aBaseURL, aDocPrincipal);
nsAutoSuppressErrors suppressErrors(this);
@@ -3696,18 +3705,17 @@ CSSParserImpl::ParseSupportsConditionInP
if (mToken.mType == eCSSToken_Ident) {
if (!mToken.mIdent.LowerCaseEqualsLiteral("not")) {
nsAutoString propertyName = mToken.mIdent;
if (!ExpectSymbol(':', true)) {
return false;
}
- nsCSSProperty propID = nsCSSProps::LookupProperty(propertyName,
- nsCSSProps::eEnabled);
+ nsCSSProperty propID = LookupEnabledProperty(propertyName);
if (propID == eCSSProperty_UNKNOWN) {
if (ExpectSymbol(')', true)) {
UngetToken();
return false;
}
aConditionMet = false;
SkipUntil(')');
UngetToken();
@@ -5738,17 +5746,17 @@ CSSParserImpl::ParseDeclaration(css::Dec
if (!ParseVariableDeclaration(&variableType, variableValue)) {
REPORT_UNEXPECTED_P(PEValueParsingError, propertyName);
REPORT_UNEXPECTED(PEDeclDropped);
OUTPUT_ERROR();
return false;
}
} 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,
CSS_PROPERTY_APPLIES_TO_PAGE_RULE))) { // unknown property
if (!NonMozillaVendorIdentifier(propertyName)) {
REPORT_UNEXPECTED_P(PEUnknownProperty, propertyName);
REPORT_UNEXPECTED(PEDeclDropped);
OUTPUT_ERROR();
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -2476,16 +2476,28 @@ CSS_PROP_OUTLINE(
eStyleAnimType_nscoord)
CSS_PROP_SHORTHAND(
overflow,
overflow,
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,
OverflowX,
CSS_PROPERTY_PARSE_VALUE |
// This is required by the UA stylesheet and can't be overridden.
CSS_PROPERTY_APPLIES_TO_PLACEHOLDER,
"",
VARIANT_HK,
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -382,65 +382,69 @@ nsCSSProps::LookupProperty(const nsACStr
NS_ABORT_IF_FALSE(gPropertyTable, "no lookup table, needs addref");
if (nsLayoutUtils::CSSVariablesEnabled() &&
IsCustomPropertyName(aProperty)) {
return eCSSPropertyExtra_variable;
}
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
nsCSSProps::LookupProperty(const nsAString& aProperty, EnabledState aEnabled)
{
if (nsLayoutUtils::CSSVariablesEnabled() &&
IsCustomPropertyName(aProperty)) {
return eCSSPropertyExtra_variable;
}
// This is faster than converting and calling
// LookupProperty(nsACString&). The table will do its own
// 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
nsCSSProps::LookupFontDesc(const nsACString& aFontDesc)
{
NS_ABORT_IF_FALSE(gFontDescTable, "no lookup table, needs addref");
return nsCSSFontDesc(gFontDescTable->Lookup(aFontDesc));
}
@@ -1417,16 +1421,22 @@ const KTableValue nsCSSProps::kOverflowK
// Deprecated:
eCSSKeyword__moz_scrollbars_none, NS_STYLE_OVERFLOW_HIDDEN,
eCSSKeyword__moz_scrollbars_horizontal, NS_STYLE_OVERFLOW_SCROLLBARS_HORIZONTAL,
eCSSKeyword__moz_scrollbars_vertical, NS_STYLE_OVERFLOW_SCROLLBARS_VERTICAL,
eCSSKeyword__moz_hidden_unscrollable, NS_STYLE_OVERFLOW_CLIP,
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,
eCSSKeyword_hidden, NS_STYLE_OVERFLOW_HIDDEN,
eCSSKeyword_scroll, NS_STYLE_OVERFLOW_SCROLL,
// Deprecated:
eCSSKeyword__moz_hidden_unscrollable, NS_STYLE_OVERFLOW_CLIP,
eCSSKeyword_UNKNOWN,-1
--- a/layout/style/nsCSSProps.h
+++ b/layout/style/nsCSSProps.h
@@ -189,16 +189,23 @@ static_assert((CSS_PROPERTY_PARSE_PROPER
// This property's getComputedStyle implementation requires layout to be
// flushed.
#define CSS_PROPERTY_GETCS_NEEDS_LAYOUT_FLUSH (1<<20)
// 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.
*/
enum nsStyleAnimType {
// requires a custom implementation in
// nsStyleAnimation::ExtractComputedValue
eStyleAnimType_Custom,
@@ -249,16 +256,17 @@ public:
typedef int16_t KTableValue;
static void AddRefTable(void);
static void ReleaseTable(void);
// Given a property string, return the enum value
enum EnabledState {
eEnabled,
+ eEnabledInUASheets,
eAny
};
// Looks up the property with name aProperty and returns its corresponding
// nsCSSProperty value. If aProperty is the name of a custom property,
// then eCSSPropertyExtra_variable will be returned.
static nsCSSProperty LookupProperty(const nsAString& aProperty,
EnabledState aEnabled);
static nsCSSProperty LookupProperty(const nsACString& aProperty,
@@ -434,16 +442,23 @@ public:
static bool IsEnabled(nsCSSProperty aProperty) {
NS_ABORT_IF_FALSE(0 <= aProperty &&
aProperty < eCSSProperty_COUNT_with_aliases,
"out of range");
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_) \
for (const nsCSSProperty* iter_ = nsCSSProps::SubpropertyEntryFor(prop_); \
*iter_ != eCSSProperty_UNKNOWN; ++iter_) \
if (nsCSSProps::IsEnabled(*iter_))
// Keyword/Enum value tables
@@ -535,16 +550,17 @@ public:
static const KTableValue kMathDisplayKTable[];
static const KTableValue kContextOpacityKTable[];
static const KTableValue kContextPatternKTable[];
static const KTableValue kOrientKTable[];
static const KTableValue kOutlineStyleKTable[];
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[];
static const KTableValue kPageSizeKTable[];
static const KTableValue kPitchKTable[];
static const KTableValue kPointerEventsKTable[];
// Not const because we modify its entries when the pref
// "layout.css.sticky.enabled" changes:
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -3748,16 +3748,26 @@ nsComputedDOMStyle::DoGetOverflowY()
nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
val->SetIdent(
nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverflowY,
nsCSSProps::kOverflowSubKTable));
return val;
}
CSSValue*
+nsComputedDOMStyle::DoGetOverflowClipBox()
+{
+ nsROCSSPrimitiveValue* val = new nsROCSSPrimitiveValue;
+ val->SetIdent(
+ nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mOverflowClipBox,
+ nsCSSProps::kOverflowClipBoxKTable));
+ return val;
+}
+
+CSSValue*
nsComputedDOMStyle::DoGetResize()
{
nsROCSSPrimitiveValue *val = new nsROCSSPrimitiveValue;
val->SetIdent(nsCSSProps::ValueToKeywordEnum(StyleDisplay()->mResize,
nsCSSProps::kResizeKTable));
return val;
}
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -393,16 +393,17 @@ private:
mozilla::dom::CSSValue* DoGetDisplay();
mozilla::dom::CSSValue* DoGetPosition();
mozilla::dom::CSSValue* DoGetClip();
mozilla::dom::CSSValue* DoGetImageOrientation();
mozilla::dom::CSSValue* DoGetWillChange();
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();
mozilla::dom::CSSValue* DoGetPageBreakInside();
mozilla::dom::CSSValue* DoGetTouchAction();
mozilla::dom::CSSValue* DoGetTransform();
mozilla::dom::CSSValue* DoGetTransformOrigin();
mozilla::dom::CSSValue* DoGetPerspective();
--- a/layout/style/nsComputedDOMStylePropertyList.h
+++ b/layout/style/nsComputedDOMStylePropertyList.h
@@ -157,16 +157,17 @@ COMPUTED_STYLE_PROP(opacity,
// COMPUTED_STYLE_PROP(orphans, Orphans)
//// COMPUTED_STYLE_PROP(outline, Outline)
COMPUTED_STYLE_PROP(order, Order)
COMPUTED_STYLE_PROP(outline_color, OutlineColor)
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)
COMPUTED_STYLE_PROP(padding_bottom, PaddingBottom)
COMPUTED_STYLE_PROP(padding_left, PaddingLeft)
COMPUTED_STYLE_PROP(padding_right, PaddingRight)
COMPUTED_STYLE_PROP(padding_top, PaddingTop)
// COMPUTED_STYLE_PROP(page, Page)
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -5299,16 +5299,22 @@ nsRuleNode::ComputeDisplayData(void* aSt
// If 'visible' is specified but doesn't match the other dimension, it
// turns into 'auto'.
if (display->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE)
display->mOverflowX = NS_STYLE_OVERFLOW_AUTO;
if (display->mOverflowY == NS_STYLE_OVERFLOW_VISIBLE)
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,
NS_STYLE_RESIZE_NONE, 0, 0, 0, 0);
// clip property: length, auto, inherit
const nsCSSValue* clipValue = aRuleData->ValueForClip();
switch (clipValue->GetUnit()) {
--- a/layout/style/nsStyleConsts.h
+++ b/layout/style/nsStyleConsts.h
@@ -565,24 +565,24 @@ static inline mozilla::css::Side operato
#define NS_MATHML_DISPLAYSTYLE_BLOCK 1
// See nsStylePosition::mWidth, mMinWidth, mMaxWidth
#define NS_STYLE_WIDTH_MAX_CONTENT 0
#define NS_STYLE_WIDTH_MIN_CONTENT 1
#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
#define NS_STYLE_CLIP_LEFT_AUTO 0x10
#define NS_STYLE_CLIP_TOP_AUTO 0x20
#define NS_STYLE_CLIP_RIGHT_AUTO 0x40
#define NS_STYLE_CLIP_BOTTOM_AUTO 0x80
@@ -593,25 +593,29 @@ static inline mozilla::css::Side operato
#define NS_STYLE_FRAME_0 2
#define NS_STYLE_FRAME_1 3
#define NS_STYLE_FRAME_ON 4
#define NS_STYLE_FRAME_OFF 5
#define NS_STYLE_FRAME_AUTO 6
#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
#define NS_STYLE_OVERFLOW_AUTO 3
#define NS_STYLE_OVERFLOW_CLIP 4
#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
#define NS_STYLE_LIST_STYLE_CIRCLE 2
#define NS_STYLE_LIST_STYLE_SQUARE 3
#define NS_STYLE_LIST_STYLE_DECIMAL 4
#define NS_STYLE_LIST_STYLE_DECIMAL_LEADING_ZERO 5
#define NS_STYLE_LIST_STYLE_LOWER_ROMAN 6
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -2273,16 +2273,17 @@ nsStyleDisplay::nsStyleDisplay()
mFloats = NS_STYLE_FLOAT_NONE;
mOriginalFloats = mFloats;
mBreakType = NS_STYLE_CLEAR_NONE;
mBreakInside = NS_STYLE_PAGE_BREAK_AUTO;
mBreakBefore = false;
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);
mOpacity = 1.0f;
mSpecifiedTransform = nullptr;
mTransformOrigin[0].SetPercentValue(0.5f); // Transform is centered on origin
mTransformOrigin[1].SetPercentValue(0.5f);
mTransformOrigin[2].SetCoordValue(0);
@@ -2329,16 +2330,17 @@ nsStyleDisplay::nsStyleDisplay(const nsS
, mFloats(aSource.mFloats)
, mOriginalFloats(aSource.mOriginalFloats)
, mBreakType(aSource.mBreakType)
, mBreakInside(aSource.mBreakInside)
, mBreakBefore(aSource.mBreakBefore)
, mBreakAfter(aSource.mBreakAfter)
, mOverflowX(aSource.mOverflowX)
, mOverflowY(aSource.mOverflowY)
+ , mOverflowClipBox(aSource.mOverflowClipBox)
, mResize(aSource.mResize)
, mClipFlags(aSource.mClipFlags)
, mOrient(aSource.mOrient)
, mMixBlendMode(aSource.mMixBlendMode)
, mWillChangeBitField(aSource.mWillChangeBitField)
, mWillChange(aSource.mWillChange)
, mTouchAction(aSource.mTouchAction)
, mBackfaceVisibility(aSource.mBackfaceVisibility)
@@ -2407,16 +2409,17 @@ nsChangeHint nsStyleDisplay::CalcDiffere
// XXX the following is conservative, for now: changing float breaking shouldn't
// necessarily require a repaint, reflow should suffice.
if (mBreakType != aOther.mBreakType
|| mBreakInside != aOther.mBreakInside
|| mBreakBefore != aOther.mBreakBefore
|| 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));
if (mOpacity != aOther.mOpacity) {
NS_UpdateHint(hint, nsChangeHint_UpdateOpacityLayer);
}
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -1792,16 +1792,17 @@ struct nsStyleDisplay {
uint8_t mOriginalFloats; // [reset] saved mFloats for position:absolute/fixed;
// otherwise equal to mFloats
uint8_t mBreakType; // [reset] see nsStyleConsts.h NS_STYLE_CLEAR_*
uint8_t mBreakInside; // [reset] NS_STYLE_PAGE_BREAK_AUTO/AVOID
bool mBreakBefore; // [reset]
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
uint8_t mMixBlendMode; // [reset] see nsStyleConsts.h
uint8_t mWillChangeBitField; // [reset] see nsStyleConsts.h. Stores a
// bitfield representation of the properties
// that are frequently queried. This should
// match mWillChange. Also tracks if any of the
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -4910,16 +4910,27 @@ if (SpecialPowers.getBoolPref("layout.cs
inherited: false,
type: CSS_TYPE_LONGHAND,
initial_values: [ "auto" ],
other_values: [ "scroll-position", "contents", "transform", "opacity", "scroll-position, transform", "transform, opacity", "contents, transform", "property-that-doesnt-exist-yet" ],
invalid_values: [ "none", "all", "default", "auto, scroll-position", "scroll-position, auto", "transform scroll-position", ",", "trailing," ]
};
}
+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");
gCSSProperties["-moz-border-bottom-colors"].invalid_values.push("red unset", "unset red");
gCSSProperties["-moz-border-left-colors"].invalid_values.push("red unset", "unset red");
gCSSProperties["border-radius"].invalid_values.push("unset 2px", "unset / 2px", "2px unset", "2px / unset");
gCSSProperties["border-bottom-left-radius"].invalid_values.push("unset 2px", "2px unset");
gCSSProperties["border-bottom-right-radius"].invalid_values.push("unset 2px", "2px unset");
--- a/layout/style/ua.css
+++ b/layout/style/ua.css
@@ -98,36 +98,39 @@
/* Miscellaneous */
*|*::-moz-anonymous-block, *|*::-moz-cell-content {
display: block !important;
position: static !important;
unicode-bidi: inherit;
text-overflow: inherit;
+ overflow-clip-box: inherit;
}
*|*::-moz-anonymous-block, *|*::-moz-anonymous-positioned-block {
/* we currently inherit from the inline that is split */
outline: inherit;
outline-offset: inherit;
clip-path: inherit;
filter: inherit;
mask: inherit;
opacity: inherit;
text-decoration: inherit;
-moz-box-ordinal-group: inherit !important;
+ overflow-clip-box: inherit;
}
*|*::-moz-xul-anonymous-block {
display: block ! important;
position: static ! important;
float: none ! important;
-moz-box-ordinal-group: inherit !important;
text-overflow: inherit;
+ overflow-clip-box: inherit;
}
*|*::-moz-scrolled-content, *|*::-moz-scrolled-canvas,
*|*::-moz-scrolled-page-sequence {
/* e.g., text inputs, select boxes */
padding: inherit;
/* The display doesn't affect the kind of frame constructed here. This just
affects auto-width sizing of the block we create. */
@@ -146,16 +149,17 @@
align-items: inherit;
flex-direction: inherit;
flex-wrap: inherit;
justify-content: inherit;
/* Do not change these. nsCSSFrameConstructor depends on them to create a good
frame tree. */
position: static !important;
float: none !important;
+ overflow-clip-box: inherit;
}
*|*::-moz-viewport, *|*::-moz-viewport-scroll, *|*::-moz-canvas, *|*::-moz-scrolled-canvas {
display: block !important;
background-color: inherit;
}
*|*::-moz-viewport-scroll {
--- a/mfbt/RefPtr.h
+++ b/mfbt/RefPtr.h
@@ -69,21 +69,22 @@ class RefCounted
RefCounted() : refCnt(0) { }
~RefCounted() {
MOZ_ASSERT(refCnt == detail::DEAD);
}
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;
#endif
delete static_cast<const T*>(this);
}
}
--- a/modules/libmar/sign/Makefile.in
+++ b/modules/libmar/sign/Makefile.in
@@ -1,12 +1,10 @@
# 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/.
# 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...
# disable parallel builds
.NOTPARALLEL:
--- a/modules/libmar/sign/moz.build
+++ b/modules/libmar/sign/moz.build
@@ -13,11 +13,12 @@ UNIFIED_SOURCES += [
FORCE_STATIC_LIB = True
LOCAL_INCLUDES += [
'../src',
'../verify',
]
+DEFINES['MAR_NSS'] = True
if CONFIG['OS_ARCH'] == 'WINNT':
USE_STATIC_LIBS = True
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -1825,16 +1825,19 @@ pref("layout.css.all-shorthand.enabled",
// Is support for CSS variables enabled?
#ifdef RELEASE_BUILD
pref("layout.css.variables.enabled", false);
#else
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
// 2 = right
// 3 = left
pref("layout.scrollbar.side", 0);
// pref to control browser frame rate, in Hz. A value <= 0 means choose
--- a/testing/mozbase/mozrunner/setup.py
+++ b/testing/mozbase/mozrunner/setup.py
@@ -1,17 +1,17 @@
# 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/.
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.)"""
deps = ['mozcrash >= 0.11',
'mozdevice >= 0.30',
'mozfile >= 1.0',
'mozinfo >= 0.7',
'mozlog >= 1.5',
--- a/toolkit/components/contentprefs/ContentPrefService2.jsm
+++ b/toolkit/components/contentprefs/ContentPrefService2.jsm
@@ -35,16 +35,71 @@ Cu.import("resource://gre/modules/Conten
function ContentPrefService2(cps) {
this._cps = cps;
this._cache = cps._cache;
this._pbStore = cps._privModeStorage;
}
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);
this._get(group, name, false, context, callback);
},
getBySubdomainAndName: function CPS2_getBySubdomainAndName(group, name,
context,
--- a/toolkit/components/contentprefs/tests/unit_cps2/test_setGet.js
+++ b/toolkit/components/contentprefs/tests/unit_cps2/test_setGet.js
@@ -165,9 +165,31 @@ let tests = [
do_check_true(!!fetchedPref);
do_check_eq(fetchedPref.value, 2);
next();
},
});
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}
+ ]);
+ }
];
--- a/widget/windows/winrt/FrameworkView.cpp
+++ b/widget/windows/winrt/FrameworkView.cpp
@@ -34,16 +34,18 @@ using namespace Microsoft::WRL::Wrappers
namespace mozilla {
namespace widget {
namespace winrt {
// statics
bool FrameworkView::sKeyboardIsVisible = false;
Rect FrameworkView::sKeyboardRect;
+HSTRING FrameworkView::sActivationURI = NULL;
+ApplicationExecutionState FrameworkView::sPreviousExecutionState;
nsTArray<nsString>* sSettingsArray;
FrameworkView::FrameworkView(MetroApp* aMetroApp) :
mDPI(-1.0f),
mWidget(nullptr),
mShuttingDown(false),
mMetroApp(aMetroApp),
mWindow(nullptr),
@@ -108,16 +110,17 @@ FrameworkView::Run()
// Initialize XPCOM, create mWidget and go! We get a
// callback in MetroAppShell::Run, in which we kick
// off normal browser execution / event dispatching.
mMetroApp->Run();
// Gecko is completely shut down at this point.
WinUtils::Log("Exiting FrameworkView::Run()");
+ WindowsDeleteString(sActivationURI);
return S_OK;
}
HRESULT
FrameworkView::ActivateView()
{
LogFunction();
@@ -386,30 +389,24 @@ FrameworkView::OnActivated(ICoreApplicat
IActivatedEventArgs* aArgs)
{
LogFunction();
if (mShuttingDown) {
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)
{
LogFunction();
sKeyboardIsVisible = false;
memset(&sKeyboardRect, 0, sizeof(Rect));
MetroUtils::FireObserver("metro_softkeyboard_hidden");
--- a/widget/windows/winrt/FrameworkView.h
+++ b/widget/windows/winrt/FrameworkView.h
@@ -75,28 +75,33 @@ public:
STDMETHODIMP SetWindow(ICoreWindow* aWindow);
STDMETHODIMP Load(HSTRING aEntryPoint);
STDMETHODIMP Run();
STDMETHODIMP Uninitialize();
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; }
// MetroApp apis
void SetupContracts();
void Shutdown();
@@ -170,30 +175,31 @@ private:
EventRegistrationToken mAutomationProviderRequested;
EventRegistrationToken mDataTransferRequested;
EventRegistrationToken mSearchQuerySubmitted;
EventRegistrationToken mPlayToRequested;
EventRegistrationToken mSettingsPane;
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;
// Private critical section protects D2D device context for on-screen
// rendering from that for print/preview in the different thread.
//Microsoft::WRL::ComPtr<IWICImagingFactory2> mWicFactory;
Microsoft::WRL::ComPtr<MetroApp> mMetroApp;
Microsoft::WRL::ComPtr<ICoreWindow> mWindow;
Microsoft::WRL::ComPtr<MetroWidget> mWidget;
Microsoft::WRL::ComPtr<MetroInput> mMetroInput;
+ bool mWinVisible;
+ bool mWinActiveState;
+
static bool sKeyboardIsVisible;
static Rect sKeyboardRect;
- bool mWinVisible;
- bool mWinActiveState;
+ static HSTRING sActivationURI;
+ static ABI::Windows::ApplicationModel::Activation::ApplicationExecutionState sPreviousExecutionState;
};
} } }
--- a/widget/windows/winrt/MetroApp.cpp
+++ b/widget/windows/winrt/MetroApp.cpp
@@ -46,22 +46,27 @@ bool MetroApp::sGeckoShuttingDown = fals
////////////////////////////////////////////////////
// IFrameworkViewSource impl.
// Called after CoreApplication::Run(app)
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;
}
////////////////////////////////////////////////////
// MetroApp impl.
@@ -129,16 +134,41 @@ MetroApp::CoreExit()
HStringReference className(RuntimeClass_Windows_ApplicationModel_Core_CoreApplication);
hr = GetActivationFactory(className.Get(), coreExit.GetAddressOf());
NS_ASSERTION(SUCCEEDED(hr), "Activation of ICoreApplicationExit");
if (SUCCEEDED(hr)) {
coreExit->Exit();
}
}
+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
HRESULT
MetroApp::OnSuspending(IInspectable* aSender, ISuspendingEventArgs* aArgs)
{
LogThread();
PostSuspendResumeProcessNotification(true);
@@ -159,29 +189,16 @@ MetroApp::OnAsyncTileCreated(ABI::Window
{
WinUtils::Log("Async operation status: %d", aStatus);
MetroUtils::FireObserver("metro_on_async_tile_created");
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)
{
static bool isSuspend = false;
if (isSuspend == aIsSuspend) {
return;
}
isSuspend = aIsSuspend;
MetroUtils::FireObserver(aIsSuspend ? "suspend_process_notification" :
@@ -246,19 +263,17 @@ XRE_MetroCoreApplicationRun()
sessionBAK->AppendNative(nsDependentCString("sessionstore.bak"));
bool exists;
if (NS_SUCCEEDED(sessionBAK->Exists(&exists)) && exists) {
sessionBAK->Remove(false);
}
return false;
}
- sFrameworkView = Make<FrameworkView>(sMetroApp.Get());
hr = sCoreApp->Run(sMetroApp.Get());
- sFrameworkView = nullptr;
WinUtils::Log("Exiting CoreApplication::Run");
sCoreApp = nullptr;
sMetroApp = nullptr;
return true;
}
--- a/widget/windows/winrt/MetroApp.h
+++ b/widget/windows/winrt/MetroApp.h
@@ -14,18 +14,16 @@
#include <Windows.Applicationmodel.Activation.h>
class MetroWidget;
namespace mozilla {
namespace widget {
namespace winrt {
-class FrameworkView;
-
class MetroApp : public Microsoft::WRL::RuntimeClass<ABI::Windows::ApplicationModel::Core::IFrameworkViewSource>
{
InspectableClass(L"MetroApp", TrustLevel::BaseTrust)
typedef ABI::Windows::UI::Core::CoreDispatcherPriority CoreDispatcherPriority;
typedef ABI::Windows::ApplicationModel::Activation::LaunchActivatedEventArgs LaunchActivatedEventArgs;
typedef ABI::Windows::ApplicationModel::ISuspendingEventArgs ISuspendingEventArgs;
typedef ABI::Windows::ApplicationModel::Core::IFrameworkView IFrameworkView;
@@ -40,22 +38,24 @@ public:
HRESULT OnResuming(IInspectable* aSender, IInspectable* aArgs);
// nsIWinMetroUtils tile related async callbacks
HRESULT OnAsyncTileCreated(ABI::Windows::Foundation::IAsyncOperation<bool>* aOperation, AsyncStatus aStatus);
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);
private:
EventRegistrationToken mSuspendEvent;
EventRegistrationToken mResumeEvent;
};
--- a/widget/windows/winrt/MetroAppShell.cpp
+++ b/widget/windows/winrt/MetroAppShell.cpp
@@ -37,17 +37,16 @@ using namespace ABI::Windows::Foundation
// up to date. This is the maximum amount of time we'll agree to spend in
// NS_ProcessPendingEvents.
#define PURGE_MAX_TIMEOUT 50
namespace mozilla {
namespace widget {
namespace winrt {
extern ComPtr<MetroApp> sMetroApp;
-extern ComPtr<FrameworkView> sFrameworkView;
} } }
namespace mozilla {
namespace widget {
// pulled from win32 app shell
extern UINT sAppShellGeckoMsgId;
} }
@@ -237,17 +236,17 @@ MetroAppShell::Run(void)
sWakeLockListener = new WakeLockListener();
sPowerManagerService->AddWakeLockListener(sWakeLockListener);
}
else {
NS_WARNING("Failed to retrieve PowerManagerService, wakelocks will be broken!");
}
mozilla::widget::StartAudioSession();
- sFrameworkView->ActivateView();
+ sMetroApp->ActivateBaseView();
rv = nsBaseAppShell::Run();
mozilla::widget::StopAudioSession();
if (sPowerManagerService) {
sPowerManagerService->RemoveWakeLockListener(sWakeLockListener);
sPowerManagerService = nullptr;
sWakeLockListener = nullptr;
--- a/widget/windows/winrt/MetroContracts.cpp
+++ b/widget/windows/winrt/MetroContracts.cpp
@@ -56,17 +56,17 @@ FrameworkView::SearchActivated(ComPtr<IS
HString data;
AssertHRESULT(aArgs->get_QueryText(data.GetAddressOf()));
if (WindowsIsStringEmpty(data.Get()))
return;
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);
}
}
void
FrameworkView::FileActivated(ComPtr<IFileActivatedEventArgs>& aArgs, bool aStartup)
{
@@ -76,41 +76,40 @@ FrameworkView::FileActivated(ComPtr<IFil
ComPtr<IVectorView<ABI::Windows::Storage::IStorageItem*>> list;
AssertHRESULT(aArgs->get_Files(list.GetAddressOf()));
ComPtr<ABI::Windows::Storage::IStorageItem> item;
AssertHRESULT(list->GetAt(0, item.GetAddressOf()));
HString filePath;
AssertHRESULT(item->get_Path(filePath.GetAddressOf()));
if (aStartup) {
- unsigned int length;
- mActivationURI = filePath.GetRawBuffer(&length);
+ WindowsDuplicateString(filePath.Get(), &sActivationURI);
} else {
PerformURILoad(filePath);
}
}
void
FrameworkView::LaunchActivated(ComPtr<ILaunchActivatedEventArgs>& aArgs, bool aStartup)
{
if (!aArgs)
return;
HString data;
AssertHRESULT(aArgs->get_Arguments(data.GetAddressOf()));
if (WindowsIsStringEmpty(data.Get()))
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.
mActivationCommandLine = data.GetRawBuffer(&length);
if (!aStartup) {
ProcessLaunchArguments();
}
}
@@ -172,18 +171,17 @@ FrameworkView::ProcessActivationArgs(IAc
return;
HString data;
AssertHRESULT(uri->get_AbsoluteUri(data.GetAddressOf()));
if (WindowsIsStringEmpty(data.Get()))
return;
if (aStartup) {
- unsigned int length;
- mActivationURI = data.GetRawBuffer(&length);
+ WindowsDuplicateString(data.Get(), &sActivationURI);
} else {
PerformURILoad(data);
}
} else if (kind == ActivationKind::ActivationKind_Search) {
WinUtils::Log("Activation argument kind: Search");
ComPtr<ISearchActivatedEventArgs> searchArgs;
args.As(&searchArgs);
SearchActivated(searchArgs, aStartup);
--- a/widget/windows/winrt/MetroWidget.cpp
+++ b/widget/windows/winrt/MetroWidget.cpp
@@ -77,16 +77,17 @@ UINT sDefaultBrowserMsgId = RegisterWind
} }
// WM_GETOBJECT id pulled from uia headers
#define UiaRootObjectId -25
namespace mozilla {
namespace widget {
namespace winrt {
+extern ComPtr<MetroApp> sMetroApp;
extern ComPtr<IUIABridge> gProviderRoot;
} } }
namespace {
void SendInputs(uint32_t aModifiers, INPUT* aExtraInputs, uint32_t aExtraInputsLen)
{
// keySequence holds the virtual key values of each of the keys we intend
@@ -248,17 +249,17 @@ MetroWidget::Create(nsIWidget *aParent,
// can be created.
NS_WARNING("New eWindowType_toplevel window requested after FrameworkView widget created.");
NS_WARNING("Widget created but the physical window does not exist! Fix me!");
return NS_OK;
}
// the main widget gets created first
gTopLevelAssigned = true;
- MetroApp::SetBaseWidget(this);
+ sMetroApp->SetWidget(this);
WinUtils::SetNSWindowBasePtr(mWnd, this);
if (mWidgetListener) {
mWidgetListener->WindowActivated();
}
return NS_OK;
}
--- a/widget/windows/winrt/nsWinMetroUtils.cpp
+++ b/widget/windows/winrt/nsWinMetroUtils.cpp
@@ -22,17 +22,16 @@ using namespace Microsoft::WRL;
using namespace Microsoft::WRL::Wrappers;
using namespace mozilla::widget::winrt;
namespace mozilla {
namespace widget {
namespace winrt {
extern ComPtr<MetroApp> sMetroApp;
extern nsTArray<nsString>* sSettingsArray;
-extern ComPtr<FrameworkView> sFrameworkView;
} } }
namespace mozilla {
namespace widget {
bool nsWinMetroUtils::sUpdatePending = false;
NS_IMPL_ISUPPORTS1(nsWinMetroUtils, nsIWinMetroUtils)
@@ -59,17 +58,17 @@ nsWinMetroUtils::~nsWinMetroUtils()
NS_IMETHODIMP
nsWinMetroUtils::PinTileAsync(const nsAString &aTileID,
const nsAString &aShortName,
const nsAString &aDisplayName,
const nsAString &aActivationArgs,
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;
}
HRESULT hr;
HString logoStr, smallLogoStr, displayName, shortName;
logoStr.Set(aTileImage.BeginReading());
@@ -112,17 +111,17 @@ nsWinMetroUtils::PinTileAsync(const nsAS
/**
* Unpins a tile from the Windows 8 start screen.
*
* @param aTileID An existing ID which was previously pinned
*/
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;
}
HRESULT hr;
HString tileIdStr;
tileIdStr.Set(aTileID.BeginReading());
ComPtr<ISecondaryTileFactory> tileFactory;
@@ -146,17 +145,17 @@ nsWinMetroUtils::UnpinTileAsync(const ns
* Determines if a tile is pinned to the Windows 8 start screen.
*
* @param aTileID An ID which may have been pinned with pinTileAsync
* @param aIsPinned Out parameter for determining if the tile is pinned or not
*/
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;
}
NS_ENSURE_ARG_POINTER(aIsPinned);
HRESULT hr;
HString tileIdStr;
tileIdStr.Set(aTileID.BeginReading());
@@ -225,17 +224,17 @@ nsWinMetroUtils::ShowNativeToast(const n
}
return NS_OK;
}
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;
}
HRESULT hr = MetroUtils::ShowSettingsFlyout();
return SUCCEEDED(hr) ? NS_OK : NS_ERROR_FAILURE;
}
@@ -245,67 +244,65 @@ nsWinMetroUtils::GetImmersive(bool *aIme
*aImersive =
XRE_GetWindowsEnvironment() == WindowsEnvironmentType_Metro;
return NS_OK;
}
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;
}
NS_IMETHODIMP
nsWinMetroUtils::AddSettingsPanelEntry(const nsAString &aLabel, uint32_t *aId)
{
NS_ENSURE_ARG_POINTER(aId);
if (!sSettingsArray)
--- a/xpcom/base/CycleCollectedJSRuntime.cpp
+++ b/xpcom/base/CycleCollectedJSRuntime.cpp
@@ -872,25 +872,17 @@ nsCycleCollectionParticipant*
CycleCollectedJSRuntime::ZoneParticipant()
{
return &mJSZoneCycleCollectorGlobal;
}
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);
NoteWeakMapsTracer trc(mJSRuntime, TraceWeakMapping, aCb);
js::TraceWeakMaps(&trc);
return NS_OK;
}