mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
merge mozilla-inbound to mozilla-central a=merge
This commit is contained in:
commit
6ae1b98d2e
@ -148,6 +148,9 @@ XPCOMUtils.defineLazyModuleGetter(this, "WebChannel",
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "ReaderParent",
|
||||
"resource:///modules/ReaderParent.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "AddonWatcher",
|
||||
"resource://gre/modules/AddonWatcher.jsm");
|
||||
|
||||
const PREF_PLUGINS_NOTIFYUSER = "plugins.update.notifyUser";
|
||||
const PREF_PLUGINS_UPDATEURL = "plugins.update.url";
|
||||
|
||||
@ -587,6 +590,76 @@ BrowserGlue.prototype = {
|
||||
this._distributionCustomizer.applyPrefDefaults();
|
||||
},
|
||||
|
||||
_notifySlowAddon: function BG_notifySlowAddon(addonId) {
|
||||
let addonCallback = function(addon) {
|
||||
if (!addon) {
|
||||
Cu.reportError("couldn't look up addon: " + addonId);
|
||||
return;
|
||||
}
|
||||
let win = RecentWindow.getMostRecentBrowserWindow();
|
||||
|
||||
if (!win) {
|
||||
return;
|
||||
}
|
||||
|
||||
let brandBundle = win.document.getElementById("bundle_brand");
|
||||
let brandShortName = brandBundle.getString("brandShortName");
|
||||
let message = win.gNavigatorBundle.getFormattedString("addonwatch.slow", [addon.name, brandShortName]);
|
||||
let notificationBox = win.document.getElementById("global-notificationbox");
|
||||
let notificationId = 'addon-slow:' + addonId;
|
||||
let notification = notificationBox.getNotificationWithValue(notificationId);
|
||||
if(notification) {
|
||||
notification.label = message;
|
||||
} else {
|
||||
let buttons = [
|
||||
{
|
||||
label: win.gNavigatorBundle.getFormattedString("addonwatch.disable.label", [addon.name]),
|
||||
accessKey: win.gNavigatorBundle.getString("addonwatch.disable.accesskey"),
|
||||
callback: function() {
|
||||
addon.userDisabled = true;
|
||||
if (addon.pendingOperations != addon.PENDING_NONE) {
|
||||
let restartMessage = win.gNavigatorBundle.getFormattedString("addonwatch.restart.message", [addon.name, brandShortName]);
|
||||
let restartButton = [
|
||||
{
|
||||
label: win.gNavigatorBundle.getFormattedString("addonwatch.restart.label", [brandShortName]),
|
||||
accessKey: win.gNavigatorBundle.getString("addonwatch.restart.accesskey"),
|
||||
callback: function() {
|
||||
let appStartup = Cc["@mozilla.org/toolkit/app-startup;1"]
|
||||
.getService(Ci.nsIAppStartup);
|
||||
appStartup.quit(appStartup.eForceQuit | appStartup.eRestart);
|
||||
}
|
||||
}
|
||||
];
|
||||
const priority = notificationBox.PRIORITY_WARNING_MEDIUM;
|
||||
notificationBox.appendNotification(restartMessage, "restart-" + addonId, "",
|
||||
priority, restartButton);
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
label: win.gNavigatorBundle.getString("addonwatch.ignoreSession.label"),
|
||||
accessKey: win.gNavigatorBundle.getString("addonwatch.ignoreSession.accesskey"),
|
||||
callback: function() {
|
||||
AddonWatcher.ignoreAddonForSession(addonId);
|
||||
}
|
||||
},
|
||||
{
|
||||
label: win.gNavigatorBundle.getString("addonwatch.ignorePerm.label"),
|
||||
accessKey: win.gNavigatorBundle.getString("addonwatch.ignorePerm.accesskey"),
|
||||
callback: function() {
|
||||
AddonWatcher.ignoreAddonPermanently(addonId);
|
||||
}
|
||||
},
|
||||
];
|
||||
|
||||
const priority = notificationBox.PRIORITY_WARNING_MEDIUM;
|
||||
notificationBox.appendNotification(message, notificationId, "",
|
||||
priority, buttons);
|
||||
}
|
||||
};
|
||||
AddonManager.getAddonByID(addonId, addonCallback);
|
||||
},
|
||||
|
||||
// runs on startup, before the first command line handler is invoked
|
||||
// (i.e. before the first window is opened)
|
||||
_finalUIStartup: function BG__finalUIStartup() {
|
||||
@ -642,6 +715,8 @@ BrowserGlue.prototype = {
|
||||
#endif
|
||||
|
||||
Services.obs.notifyObservers(null, "browser-ui-startup-complete", "");
|
||||
|
||||
AddonWatcher.init(this._notifySlowAddon);
|
||||
},
|
||||
|
||||
_checkForOldBuildUpdates: function () {
|
||||
@ -907,6 +982,7 @@ BrowserGlue.prototype = {
|
||||
#endif
|
||||
webrtcUI.uninit();
|
||||
FormValidationHandler.uninit();
|
||||
AddonWatcher.uninit();
|
||||
},
|
||||
|
||||
_initServiceDiscovery: function () {
|
||||
|
@ -103,71 +103,45 @@ support-files =
|
||||
[browser_dbg_aaa_run_first_leaktest.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_addonactor.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_addon-sources.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_addon-modules.js]
|
||||
skip-if = e10s # TODO
|
||||
[browser_dbg_addon-modules-unpacked.js]
|
||||
skip-if = e10s # TODO
|
||||
[browser_dbg_addon-panels.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_addon-console.js]
|
||||
skip-if = e10s && debug || os == 'win' # bug 1005274
|
||||
[browser_dbg_auto-pretty-print-01.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_auto-pretty-print-02.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_bfcache.js]
|
||||
skip-if = e10s || true # bug 1113935
|
||||
[browser_dbg_blackboxing-01.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_blackboxing-02.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_blackboxing-03.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_blackboxing-04.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_blackboxing-05.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_blackboxing-06.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_breadcrumbs-access.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_break-on-dom-01.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_break-on-dom-02.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_break-on-dom-03.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_break-on-dom-04.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_break-on-dom-05.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_break-on-dom-06.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_break-on-dom-07.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_break-on-dom-08.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_break-on-dom-event-01.js]
|
||||
skip-if = e10s || os == "mac" || e10s # Bug 895426
|
||||
[browser_dbg_break-on-dom-event-02.js]
|
||||
skip-if = e10s # TODO
|
||||
[browser_dbg_breakpoints-actual-location.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_breakpoints-actual-location2.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_breakpoints-break-on-last-line-of-script-on-reload.js]
|
||||
skip-if = e10s # Bug 1093535
|
||||
[browser_dbg_breakpoints-button-01.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_breakpoints-button-02.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_breakpoints-contextmenu-add.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_breakpoints-contextmenu.js]
|
||||
skip-if = e10s && debug
|
||||
[browser_dbg_breakpoints-disabled-reload.js]
|
||||
skip-if = e10s # Bug 1093535
|
||||
[browser_dbg_breakpoints-editor.js]
|
||||
|
@ -40,6 +40,17 @@ addonDownloadRestart=Restart Download;Restart Downloads
|
||||
addonDownloadRestart.accessKey=R
|
||||
addonDownloadCancelTooltip=Cancel
|
||||
|
||||
addonwatch.slow=%1$S might be making %2$S run slowly
|
||||
addonwatch.disable.label=Disable %S
|
||||
addonwatch.disable.accesskey=D
|
||||
addonwatch.ignoreSession.label=Ignore for now
|
||||
addonwatch.ignoreSession.accesskey=I
|
||||
addonwatch.ignorePerm.label=Ignore permanently
|
||||
addonwatch.ignorePerm.accesskey=p
|
||||
addonwatch.restart.message=To disable %1$S you must restart %2$S
|
||||
addonwatch.restart.label=Restart %S
|
||||
addonwatch.restart.accesskey=R
|
||||
|
||||
# LOCALIZATION NOTE (addonsInstalled, addonsInstalledNeedsRestart):
|
||||
# Semicolon-separated list of plural forms. See:
|
||||
# http://developer.mozilla.org/en/docs/Localization_and_Plurals
|
||||
|
@ -42,16 +42,11 @@ endif
|
||||
|
||||
endif
|
||||
|
||||
# Put a useful .gdbinit in the bin directory, to be picked up automatically
|
||||
# by GDB when we debug executables there.
|
||||
# NOTE: Keep .gdbinit in the topsrcdir for people who run gdb from the topsrcdir.
|
||||
GDBINIT_FILES := $(topsrcdir)/.gdbinit
|
||||
GDBINIT_OBJDIR_FILES = $(topsrcdir)/.gdbinit
|
||||
GDBINIT_DEST = $(FINAL_TARGET)
|
||||
|
||||
# needs to be absolute to be distinct from $(topsrcdir)/.gdbinit
|
||||
GDBINIT_OBJDIR_FILES = $(topsrcdir)/.gdbinit
|
||||
GDBINIT_OBJDIR_DEST = $(abspath $(DEPTH))
|
||||
INSTALL_TARGETS += GDBINIT GDBINIT_OBJDIR
|
||||
INSTALL_TARGETS += GDBINIT_OBJDIR
|
||||
|
||||
# Put a .lldbinit in the bin directory and the objdir, to be picked up
|
||||
# automatically by LLDB when we debug executables using either of those two
|
||||
@ -66,13 +61,6 @@ LLDBINIT_FINAL_TARGET_FILES := $(DEPTH)/.lldbinit
|
||||
LLDBINIT_FINAL_TARGET_DEST = $(FINAL_TARGET)
|
||||
INSTALL_TARGETS += LLDBINIT_FINAL_TARGET
|
||||
|
||||
ifeq (1_1,$(MOZ_ASAN)_$(CLANG_CL))
|
||||
# Install the clang-cl runtime library for ASAN next to the binaries we produce.
|
||||
CLANG_RT_ASAN_FILES := $(MOZ_CLANG_RT_ASAN_LIB_PATH)
|
||||
CLANG_RT_ASAN_DEST = $(FINAL_TARGET)
|
||||
INSTALL_TARGETS += CLANG_RT_ASAN
|
||||
endif
|
||||
|
||||
ifdef MOZTTDIR
|
||||
# Install the Firefox OS fonts.
|
||||
include $(MOZTTDIR)/fonts.mk
|
||||
@ -81,6 +69,19 @@ MOZTT_FILES = $(patsubst external/moztt/%,$(MOZTTDIR)/%,$(filter external/moztt/
|
||||
INSTALL_TARGETS += MOZTT
|
||||
endif
|
||||
|
||||
ifdef MOZ_VALGRIND
|
||||
_VALGRIND_DIR = $(DEPTH)/_valgrind
|
||||
GARBAGE_DIRS += $(_VALGRIND_DIR)
|
||||
|
||||
_VALGRIND_FILES = \
|
||||
$(topsrcdir)/build/valgrind/cross-architecture.sup \
|
||||
$(topsrcdir)/build/valgrind/i386-redhat-linux-gnu.sup \
|
||||
$(topsrcdir)/build/valgrind/x86_64-redhat-linux-gnu.sup \
|
||||
$(NULL)
|
||||
_VALGRIND_DEST = $(_VALGRIND_DIR)
|
||||
INSTALL_TARGETS += _VALGRIND
|
||||
endif
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
|
||||
TARGET_DEPTH = ..
|
||||
@ -99,41 +100,6 @@ endif
|
||||
|
||||
libs:: automation.py
|
||||
|
||||
ifdef MOZ_VALGRIND
|
||||
_VALGRIND_DIR = $(DEPTH)/_valgrind
|
||||
GARBAGE_DIRS += $(_VALGRIND_DIR)
|
||||
|
||||
_VALGRIND_FILES = \
|
||||
$(topsrcdir)/build/valgrind/cross-architecture.sup \
|
||||
$(topsrcdir)/build/valgrind/i386-redhat-linux-gnu.sup \
|
||||
$(topsrcdir)/build/valgrind/x86_64-redhat-linux-gnu.sup \
|
||||
$(NULL)
|
||||
|
||||
libs:: $(_VALGRIND_FILES)
|
||||
$(INSTALL) $^ $(_VALGRIND_DIR)
|
||||
endif
|
||||
|
||||
ifneq (,$(ENABLE_TESTS)$(MOZ_DMD))
|
||||
libs:: $(topsrcdir)/tools/rb/fix_stack_using_bpsyms.py
|
||||
$(INSTALL) $< $(DIST)/bin
|
||||
|
||||
ifeq ($(OS_ARCH),Darwin)
|
||||
libs:: $(topsrcdir)/tools/rb/fix_macosx_stack.py
|
||||
$(INSTALL) $< $(DIST)/bin
|
||||
endif
|
||||
|
||||
ifeq ($(OS_ARCH),Linux)
|
||||
libs:: $(topsrcdir)/tools/rb/fix_linux_stack.py
|
||||
$(INSTALL) $< $(DIST)/bin
|
||||
endif
|
||||
endif # ENABLE_TESTS or MOZ_DMD
|
||||
|
||||
ifdef ENABLE_TESTS
|
||||
GARBAGE += $(srcdir)/automationutils.pyc
|
||||
endif # ENABLE_TESTS
|
||||
|
||||
ifdef MOZ_DMD
|
||||
libs:: $(topsrcdir)/memory/replace/dmd/dmd.py
|
||||
$(INSTALL) $< $(DIST)/bin
|
||||
endif
|
||||
|
||||
|
@ -445,7 +445,7 @@ class ShutdownLeaks(object):
|
||||
self.leakedWindows = {}
|
||||
self.leakedDocShells = set()
|
||||
self.currentTest = None
|
||||
self.seenShutdown = False
|
||||
self.seenShutdown = set()
|
||||
|
||||
def log(self, message):
|
||||
if message['action'] == 'log':
|
||||
@ -454,8 +454,9 @@ class ShutdownLeaks(object):
|
||||
self._logWindow(line)
|
||||
elif line[2:10] == "DOCSHELL":
|
||||
self._logDocShell(line)
|
||||
elif line.startswith("TEST-START | Shutdown"):
|
||||
self.seenShutdown = True
|
||||
elif line.startswith("Completed ShutdownLeaks collections in process"):
|
||||
pid = int(line.split()[-1])
|
||||
self.seenShutdown.add(pid)
|
||||
elif message['action'] == 'test_start':
|
||||
fileName = message['test'].replace("chrome://mochitests/content/browser/", "")
|
||||
self.currentTest = {"fileName": fileName, "windows": set(), "docShells": set()}
|
||||
@ -499,7 +500,7 @@ class ShutdownLeaks(object):
|
||||
windows.add(key)
|
||||
else:
|
||||
windows.discard(key)
|
||||
elif self.seenShutdown and not created:
|
||||
elif int(pid) in self.seenShutdown and not created:
|
||||
self.leakedWindows[key] = self._parseValue(line, "url")
|
||||
|
||||
def _logDocShell(self, line):
|
||||
@ -520,7 +521,7 @@ class ShutdownLeaks(object):
|
||||
docShells.add(key)
|
||||
else:
|
||||
docShells.discard(key)
|
||||
elif self.seenShutdown and not created:
|
||||
elif int(pid) in self.seenShutdown and not created:
|
||||
self.leakedDocShells.add(key)
|
||||
|
||||
def _parseValue(self, line, name):
|
||||
|
@ -48,3 +48,22 @@ if CONFIG['MOZ_BUILD_APP'] == 'browser':
|
||||
PYTHON_UNIT_TESTS += [
|
||||
'compare-mozconfig/compare-mozconfigs-wrapper.py',
|
||||
]
|
||||
|
||||
if CONFIG['ENABLE_TESTS'] or CONFIG['MOZ_DMD']:
|
||||
tools_dir = TOPSRCDIR + '/tools/rb/'
|
||||
FINAL_TARGET_FILES += [tools_dir + 'fix_stack_using_bpsyms.py']
|
||||
if CONFIG['OS_ARCH'] == 'Darwin':
|
||||
FINAL_TARGET_FILES += [tools_dir + 'fix_macosx_stack.py']
|
||||
if CONFIG['OS_ARCH'] == 'Linux':
|
||||
FINAL_TARGET_FILES += [tools_dir + 'fix_linux_stack.py']
|
||||
|
||||
if CONFIG['MOZ_DMD']:
|
||||
FINAL_TARGET_FILES += [TOPSRCDIR + '/memory/replace/dmd/dmd.py']
|
||||
|
||||
# Put a useful .gdbinit in the bin directory, to be picked up automatically
|
||||
# by GDB when we debug executables there.
|
||||
FINAL_TARGET_FILES += [TOPSRCDIR + '/.gdbinit']
|
||||
|
||||
# Install the clang-cl runtime library for ASAN next to the binaries we produce.
|
||||
if CONFIG['MOZ_ASAN'] and CONFIG['CLANG_CL']:
|
||||
FINAL_TARGET_FILES += [CONFIG['MOZ_CLANG_RT_ASAN_LIB_PATH']]
|
||||
|
@ -17,6 +17,7 @@ XPIDL_MODULE = 'caps'
|
||||
EXPORTS += [
|
||||
'nsJSPrincipals.h',
|
||||
'nsNullPrincipal.h',
|
||||
'nsNullPrincipalURI.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
@ -36,6 +37,8 @@ LOCAL_INCLUDES += [
|
||||
'/js/xpconnect/src',
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
FAIL_ON_WARNINGS = True
|
||||
|
@ -1,4 +1,5 @@
|
||||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set sw=2 sts=2 ts=2 et 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/. */
|
||||
@ -86,6 +87,24 @@ nsNullPrincipal::Init(uint32_t aAppId, bool aInMozBrowser)
|
||||
mAppId = aAppId;
|
||||
mInMozBrowser = aInMozBrowser;
|
||||
|
||||
nsCString str;
|
||||
nsresult rv = GenerateNullPrincipalURI(str);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
mURI = new nsNullPrincipalURI(str);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsNullPrincipal::GetScriptLocation(nsACString &aStr)
|
||||
{
|
||||
mURI->GetSpec(aStr);
|
||||
}
|
||||
|
||||
nsresult
|
||||
nsNullPrincipal::GenerateNullPrincipalURI(nsACString &aStr)
|
||||
{
|
||||
// FIXME: bug 327161 -- make sure the uuid generator is reseeding-resistant.
|
||||
nsresult rv;
|
||||
nsCOMPtr<nsIUUIDGenerator> uuidgen =
|
||||
@ -104,28 +123,19 @@ nsNullPrincipal::Init(uint32_t aAppId, bool aInMozBrowser)
|
||||
|
||||
// Use an nsCString so we only do the allocation once here and then share
|
||||
// with nsJSPrincipals
|
||||
nsCString str;
|
||||
str.SetCapacity(prefixLen + suffixLen);
|
||||
aStr.SetCapacity(prefixLen + suffixLen);
|
||||
|
||||
str.Append(NS_NULLPRINCIPAL_PREFIX);
|
||||
str.Append(chars);
|
||||
aStr.Append(NS_NULLPRINCIPAL_PREFIX);
|
||||
aStr.Append(chars);
|
||||
|
||||
if (str.Length() != prefixLen + suffixLen) {
|
||||
if (aStr.Length() != prefixLen + suffixLen) {
|
||||
NS_WARNING("Out of memory allocating null-principal URI");
|
||||
return NS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
mURI = new nsNullPrincipalURI(str);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
void
|
||||
nsNullPrincipal::GetScriptLocation(nsACString &aStr)
|
||||
{
|
||||
mURI->GetSpec(aStr);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
void nsNullPrincipal::dumpImpl()
|
||||
{
|
||||
|
@ -31,7 +31,7 @@ class nsNullPrincipal MOZ_FINAL : public nsJSPrincipals
|
||||
{
|
||||
public:
|
||||
nsNullPrincipal();
|
||||
|
||||
|
||||
// Our refcount is managed by nsJSPrincipals. Use this macro to avoid an
|
||||
// extra refcount member.
|
||||
|
||||
@ -49,6 +49,8 @@ public:
|
||||
|
||||
virtual void GetScriptLocation(nsACString &aStr) MOZ_OVERRIDE;
|
||||
|
||||
static nsresult GenerateNullPrincipalURI(nsACString &aStr);
|
||||
|
||||
#ifdef DEBUG
|
||||
virtual void dumpImpl() MOZ_OVERRIDE;
|
||||
#endif
|
||||
|
@ -9,6 +9,8 @@
|
||||
#include "mozilla/DebugOnly.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
|
||||
#include "mozilla/ipc/URIParams.h"
|
||||
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsEscape.h"
|
||||
#include "nsCRT.h"
|
||||
@ -17,6 +19,12 @@
|
||||
//// nsNullPrincipalURI
|
||||
|
||||
nsNullPrincipalURI::nsNullPrincipalURI(const nsCString &aSpec)
|
||||
{
|
||||
InitializeFromSpec(aSpec);
|
||||
}
|
||||
|
||||
void
|
||||
nsNullPrincipalURI::InitializeFromSpec(const nsCString &aSpec)
|
||||
{
|
||||
int32_t dividerPosition = aSpec.FindChar(':');
|
||||
NS_ASSERTION(dividerPosition != -1, "Malformed URI!");
|
||||
@ -44,6 +52,7 @@ NS_INTERFACE_MAP_BEGIN(nsNullPrincipalURI)
|
||||
else
|
||||
NS_INTERFACE_MAP_ENTRY(nsIURI)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISizeOf)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIIPCSerializableURI)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
@ -272,6 +281,31 @@ nsNullPrincipalURI::SchemeIs(const char *aScheme, bool *_schemeIs)
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// nsIIPCSerializableURI
|
||||
|
||||
void
|
||||
nsNullPrincipalURI::Serialize(mozilla::ipc::URIParams &aParams)
|
||||
{
|
||||
aParams = mozilla::ipc::NullPrincipalURIParams();
|
||||
}
|
||||
|
||||
bool
|
||||
nsNullPrincipalURI::Deserialize(const mozilla::ipc::URIParams &aParams)
|
||||
{
|
||||
if (aParams.type() != mozilla::ipc::URIParams::TNullPrincipalURIParams) {
|
||||
MOZ_ASSERT_UNREACHABLE("unexpected URIParams type");
|
||||
return false;
|
||||
}
|
||||
|
||||
nsCString str;
|
||||
nsresult rv = nsNullPrincipal::GenerateNullPrincipalURI(str);
|
||||
NS_ENSURE_SUCCESS(rv, false);
|
||||
|
||||
InitializeFromSpec(str);
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//// nsISizeOf
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "nsAutoPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsIIPCSerializableURI.h"
|
||||
#include "mozilla/MemoryReporting.h"
|
||||
|
||||
// {51fcd543-3b52-41f7-b91b-6b54102236e6}
|
||||
@ -25,10 +26,12 @@
|
||||
|
||||
class nsNullPrincipalURI MOZ_FINAL : public nsIURI
|
||||
, public nsISizeOf
|
||||
, public nsIIPCSerializableURI
|
||||
{
|
||||
public:
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
NS_DECL_NSIURI
|
||||
NS_DECL_NSIIPCSERIALIZABLEURI
|
||||
|
||||
// nsISizeOf
|
||||
virtual size_t SizeOfExcludingThis(mozilla::MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE;
|
||||
@ -36,9 +39,14 @@ public:
|
||||
|
||||
explicit nsNullPrincipalURI(const nsCString &aSpec);
|
||||
|
||||
// NB: This constructor exists only for deserialization.
|
||||
nsNullPrincipalURI() { }
|
||||
|
||||
private:
|
||||
~nsNullPrincipalURI() {}
|
||||
|
||||
void InitializeFromSpec(const nsCString &aSpec);
|
||||
|
||||
nsCString mScheme;
|
||||
nsCString mPath;
|
||||
};
|
||||
|
@ -13,13 +13,11 @@
|
||||
# Valid fields for all descriptors:
|
||||
# * nativeType - The native type (concrete class or XPCOM interface) that
|
||||
# instances of this interface will unwrap to. If not
|
||||
# specified, defaults to 'mozilla::dom::InterfaceName' for
|
||||
# non-worker non-external-or-callback interfaces, to
|
||||
# specified, defaults to 'nsIDOM' followed by the interface
|
||||
# name for external interfaces,
|
||||
# 'mozilla::dom::workers::InterfaceName' for worker
|
||||
# non-external interfaces, to 'nsIDOM' followed by the
|
||||
# interface name for non-worker external-or-callback
|
||||
# interfaces, and to 'JSObject' for worker external-or-callback
|
||||
# interfaces.
|
||||
# non-callback interfaces, and 'mozilla::dom::InterfaceName'
|
||||
# for everything else.
|
||||
# * headerFile - The file in which the nativeType is declared (defaults
|
||||
# to an educated guess).
|
||||
# * concrete - Indicates whether there exist JS objects with this interface as
|
||||
@ -31,6 +29,7 @@
|
||||
# will not be made available on the main thread.
|
||||
# * notflattened - The native type does not have nsIClassInfo, so when
|
||||
# wrapping it the right IID needs to be passed in.
|
||||
# Only relevant for callback interfaces.
|
||||
# * register - True if this binding should be registered. Defaults to true.
|
||||
# * binaryNames - Dict for mapping method and attribute names to different
|
||||
# names when calling the native methods (defaults to an empty
|
||||
@ -606,14 +605,10 @@ DOMInterfaces = {
|
||||
'headerFile': 'IDBEvents.h',
|
||||
},
|
||||
|
||||
'IID': [
|
||||
{
|
||||
'IID': {
|
||||
'nativeType': 'nsIJSID',
|
||||
'headerFile': 'xpcjsid.h',
|
||||
},
|
||||
{
|
||||
'workers': True,
|
||||
}],
|
||||
|
||||
'ImageCapture': {
|
||||
'binaryNames': { 'videoStreamTrack': 'GetVideoStreamTrack' }
|
||||
@ -623,14 +618,10 @@ DOMInterfaces = {
|
||||
'wrapperCache': False,
|
||||
},
|
||||
|
||||
'InputStream': [
|
||||
{
|
||||
'InputStream': {
|
||||
'nativeType': 'nsIInputStream',
|
||||
'notflattened': True
|
||||
},
|
||||
{
|
||||
'workers': True,
|
||||
}],
|
||||
|
||||
'InstallEvent': {
|
||||
'headerFile': 'ServiceWorkerEvents.h',
|
||||
@ -1484,16 +1475,10 @@ DOMInterfaces = {
|
||||
},
|
||||
},
|
||||
|
||||
'WindowProxy': [
|
||||
{
|
||||
'WindowProxy': {
|
||||
'nativeType': 'nsIDOMWindow',
|
||||
'concrete': False
|
||||
},
|
||||
{
|
||||
# We need a worker descriptor for WindowProxy because EventTarget exists in
|
||||
# workers. But it's an external interface, so it'll just map to JSObject*.
|
||||
'workers': True
|
||||
}],
|
||||
|
||||
'WindowRoot': {
|
||||
'nativeType': 'nsWindowRoot'
|
||||
|
@ -381,7 +381,7 @@ class CGDOMJSClass(CGThing):
|
||||
classFlags += "JSCLASS_DOM_GLOBAL | JSCLASS_GLOBAL_FLAGS_WITH_SLOTS(DOM_GLOBAL_SLOTS) | JSCLASS_IMPLEMENTS_BARRIERS"
|
||||
traceHook = "JS_GlobalObjectTraceHook"
|
||||
reservedSlots = "JSCLASS_GLOBAL_APPLICATION_SLOTS"
|
||||
if not self.descriptor.workers:
|
||||
if self.descriptor.interface.identifier.name == "Window":
|
||||
classExtensionAndObjectOps = fill(
|
||||
"""
|
||||
{
|
||||
@ -4635,10 +4635,7 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
descriptor = descriptorProvider.getDescriptor(
|
||||
type.unroll().inner.identifier.name)
|
||||
|
||||
if descriptor.nativeType == 'JSObject':
|
||||
# XXXbz Workers code does this sometimes
|
||||
assert descriptor.workers
|
||||
return handleJSObjectType(type, isMember, failureCode, exceptionCode, sourceDescription)
|
||||
assert descriptor.nativeType != 'JSObject'
|
||||
|
||||
if descriptor.interface.isCallback():
|
||||
name = descriptor.interface.identifier.name
|
||||
@ -4715,9 +4712,10 @@ def getJSToNativeConversionInfo(type, descriptorProvider, failureCode=None,
|
||||
exceptionCode,
|
||||
isCallbackReturnValue,
|
||||
firstCap(sourceDescription)))
|
||||
elif descriptor.workers:
|
||||
return handleJSObjectType(type, isMember, failureCode, exceptionCode, sourceDescription)
|
||||
else:
|
||||
# Worker descriptors can't end up here, because all of our
|
||||
# "external" stuff is not exposed in workers.
|
||||
assert not descriptor.workers
|
||||
# Either external, or new-binding non-castable. We always have a
|
||||
# holder for these, because we don't actually know whether we have
|
||||
# to addref when unwrapping or not. So we just pass an
|
||||
|
@ -305,10 +305,8 @@ class Descriptor(DescriptorProvider):
|
||||
# Read the desc, and fill in the relevant defaults.
|
||||
ifaceName = self.interface.identifier.name
|
||||
if self.interface.isExternal():
|
||||
if self.workers:
|
||||
nativeTypeDefault = "JSObject"
|
||||
else:
|
||||
nativeTypeDefault = "nsIDOM" + ifaceName
|
||||
assert not self.workers
|
||||
nativeTypeDefault = "nsIDOM" + ifaceName
|
||||
elif self.interface.isCallback():
|
||||
nativeTypeDefault = "mozilla::dom::" + ifaceName
|
||||
else:
|
||||
|
@ -1852,6 +1852,12 @@ WebGLContext::TexImageFromVideoElement(const TexImageTarget texImageTarget,
|
||||
return ok;
|
||||
}
|
||||
|
||||
size_t mozilla::RoundUpToMultipleOf(size_t value, size_t multiple)
|
||||
{
|
||||
size_t overshoot = value + multiple - 1;
|
||||
return overshoot - (overshoot % multiple);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
WebGLContext::ScopedMaskWorkaround::ScopedMaskWorkaround(WebGLContext& webgl)
|
||||
@ -1875,6 +1881,7 @@ WebGLContext::ScopedMaskWorkaround::~ScopedMaskWorkaround()
|
||||
mWebGL.mColorWriteMask[3]);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// XPCOM goop
|
||||
|
||||
|
@ -1092,9 +1092,7 @@ protected:
|
||||
GLenum pname);
|
||||
|
||||
// Returns x rounded to the next highest multiple of y.
|
||||
static CheckedUint32 RoundedToNextMultipleOf(CheckedUint32 x,
|
||||
CheckedUint32 y)
|
||||
{
|
||||
static CheckedUint32 RoundedToNextMultipleOf(CheckedUint32 x, CheckedUint32 y) {
|
||||
return ((x + y - 1) / y) * y;
|
||||
}
|
||||
|
||||
@ -1693,6 +1691,8 @@ private:
|
||||
WebGLContext* mWebGL;
|
||||
};
|
||||
|
||||
size_t RoundUpToMultipleOf(size_t value, size_t multiple);
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
||||
|
@ -49,8 +49,8 @@ WebGLContext::Clear(GLbitfield mask)
|
||||
mShouldPresent = true;
|
||||
}
|
||||
|
||||
static GLclampf
|
||||
GLClampFloat(GLclampf val)
|
||||
static GLfloat
|
||||
GLClampFloat(GLfloat val)
|
||||
{
|
||||
if (val < 0.0)
|
||||
return 0.0;
|
||||
@ -62,18 +62,28 @@ GLClampFloat(GLclampf val)
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::ClearColor(GLclampf r, GLclampf g,
|
||||
GLclampf b, GLclampf a)
|
||||
WebGLContext::ClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a)
|
||||
{
|
||||
if (IsContextLost())
|
||||
return;
|
||||
|
||||
MakeContextCurrent();
|
||||
mColorClearValue[0] = GLClampFloat(r);
|
||||
mColorClearValue[1] = GLClampFloat(g);
|
||||
mColorClearValue[2] = GLClampFloat(b);
|
||||
mColorClearValue[3] = GLClampFloat(a);
|
||||
|
||||
const bool supportsFloatColorBuffers = (IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float) ||
|
||||
IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float));
|
||||
if (!supportsFloatColorBuffers) {
|
||||
r = GLClampFloat(r);
|
||||
g = GLClampFloat(g);
|
||||
b = GLClampFloat(b);
|
||||
a = GLClampFloat(a);
|
||||
}
|
||||
|
||||
gl->fClearColor(r, g, b, a);
|
||||
|
||||
mColorClearValue[0] = r;
|
||||
mColorClearValue[1] = g;
|
||||
mColorClearValue[2] = b;
|
||||
mColorClearValue[3] = a;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -1863,6 +1863,84 @@ SetFullAlpha(void* data, GLenum format, GLenum type, size_t width,
|
||||
return false;
|
||||
}
|
||||
|
||||
static void
|
||||
ReadPixelsAndConvert(gl::GLContext* gl, GLint x, GLint y, GLsizei width, GLsizei height,
|
||||
GLenum readFormat, GLenum readType, size_t pixelStorePackAlignment,
|
||||
GLenum destFormat, GLenum destType, void* destBytes)
|
||||
{
|
||||
if (readFormat == destFormat && readType == destType) {
|
||||
gl->fReadPixels(x, y, width, height, destFormat, destType, destBytes);
|
||||
return;
|
||||
}
|
||||
|
||||
if (readFormat == LOCAL_GL_RGBA &&
|
||||
readType == LOCAL_GL_HALF_FLOAT &&
|
||||
destFormat == LOCAL_GL_RGBA &&
|
||||
destType == LOCAL_GL_FLOAT)
|
||||
{
|
||||
size_t readBytesPerPixel = sizeof(uint16_t) * 4;
|
||||
size_t destBytesPerPixel = sizeof(float) * 4;
|
||||
|
||||
size_t readBytesPerRow = readBytesPerPixel * width;
|
||||
|
||||
size_t readStride = RoundUpToMultipleOf(readBytesPerRow, pixelStorePackAlignment);
|
||||
size_t destStride = RoundUpToMultipleOf(destBytesPerPixel * width,
|
||||
pixelStorePackAlignment);
|
||||
|
||||
size_t bytesNeeded = ((height - 1) * readStride) + readBytesPerRow;
|
||||
UniquePtr<uint8_t[]> readBuffer(new uint8_t[bytesNeeded]);
|
||||
|
||||
gl->fReadPixels(x, y, width, height, readFormat, readType, readBuffer.get());
|
||||
|
||||
size_t channelsPerRow = width * 4;
|
||||
for (size_t j = 0; j < (size_t)height; j++) {
|
||||
uint16_t* src = (uint16_t*)(readBuffer.get()) + j*readStride;
|
||||
float* dst = (float*)(destBytes) + j*destStride;
|
||||
|
||||
uint16_t* srcEnd = src + channelsPerRow;
|
||||
while (src != srcEnd) {
|
||||
*dst = unpackFromFloat16(*src);
|
||||
|
||||
++src;
|
||||
++dst;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
MOZ_CRASH("bad format/type");
|
||||
}
|
||||
|
||||
static bool
|
||||
IsFormatAndTypeUnpackable(GLenum format, GLenum type)
|
||||
{
|
||||
switch (type) {
|
||||
case LOCAL_GL_UNSIGNED_BYTE:
|
||||
case LOCAL_GL_FLOAT:
|
||||
case LOCAL_GL_HALF_FLOAT:
|
||||
case LOCAL_GL_HALF_FLOAT_OES:
|
||||
switch (format) {
|
||||
case LOCAL_GL_ALPHA:
|
||||
case LOCAL_GL_RGB:
|
||||
case LOCAL_GL_RGBA:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
|
||||
case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
|
||||
return format == LOCAL_GL_RGBA;
|
||||
|
||||
case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
|
||||
return format == LOCAL_GL_RGB;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
|
||||
GLsizei height, GLenum format,
|
||||
@ -1883,59 +1961,61 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
|
||||
if (pixels.IsNull())
|
||||
return ErrorInvalidValue("readPixels: null destination buffer");
|
||||
|
||||
if (!IsFormatAndTypeUnpackable(format, type))
|
||||
return ErrorInvalidEnum("readPixels: Bad format or type.");
|
||||
|
||||
const WebGLRectangleObject* framebufferRect = CurValidReadFBRectObject();
|
||||
GLsizei framebufferWidth = framebufferRect ? framebufferRect->Width() : 0;
|
||||
GLsizei framebufferHeight = framebufferRect ? framebufferRect->Height() : 0;
|
||||
|
||||
uint32_t channels = 0;
|
||||
int channels = 0;
|
||||
|
||||
// Check the format param
|
||||
switch (format) {
|
||||
case LOCAL_GL_ALPHA:
|
||||
channels = 1;
|
||||
break;
|
||||
case LOCAL_GL_RGB:
|
||||
channels = 3;
|
||||
break;
|
||||
case LOCAL_GL_RGBA:
|
||||
channels = 4;
|
||||
break;
|
||||
default:
|
||||
return ErrorInvalidEnum("readPixels: Bad format");
|
||||
case LOCAL_GL_ALPHA:
|
||||
channels = 1;
|
||||
break;
|
||||
case LOCAL_GL_RGB:
|
||||
channels = 3;
|
||||
break;
|
||||
case LOCAL_GL_RGBA:
|
||||
channels = 4;
|
||||
break;
|
||||
default:
|
||||
MOZ_CRASH("bad `format`");
|
||||
}
|
||||
|
||||
uint32_t bytesPerPixel = 0;
|
||||
int requiredDataType = 0;
|
||||
|
||||
// Check the type param
|
||||
bool isReadTypeValid = false;
|
||||
bool isReadTypeFloat = false;
|
||||
int bytesPerPixel;
|
||||
int requiredDataType;
|
||||
switch (type) {
|
||||
case LOCAL_GL_UNSIGNED_BYTE:
|
||||
isReadTypeValid = true;
|
||||
bytesPerPixel = 1*channels;
|
||||
requiredDataType = js::Scalar::Uint8;
|
||||
break;
|
||||
case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
|
||||
case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
|
||||
case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
|
||||
isReadTypeValid = true;
|
||||
bytesPerPixel = 2;
|
||||
requiredDataType = js::Scalar::Uint16;
|
||||
break;
|
||||
case LOCAL_GL_FLOAT:
|
||||
if (IsExtensionEnabled(WebGLExtensionID::WEBGL_color_buffer_float) ||
|
||||
IsExtensionEnabled(WebGLExtensionID::EXT_color_buffer_half_float))
|
||||
{
|
||||
isReadTypeValid = true;
|
||||
isReadTypeFloat = true;
|
||||
bytesPerPixel = 4*channels;
|
||||
requiredDataType = js::Scalar::Float32;
|
||||
}
|
||||
break;
|
||||
case LOCAL_GL_UNSIGNED_BYTE:
|
||||
bytesPerPixel = 1*channels;
|
||||
requiredDataType = js::Scalar::Uint8;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_UNSIGNED_SHORT_4_4_4_4:
|
||||
case LOCAL_GL_UNSIGNED_SHORT_5_5_5_1:
|
||||
case LOCAL_GL_UNSIGNED_SHORT_5_6_5:
|
||||
bytesPerPixel = 2;
|
||||
requiredDataType = js::Scalar::Uint16;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_FLOAT:
|
||||
bytesPerPixel = 4*channels;
|
||||
requiredDataType = js::Scalar::Float32;
|
||||
break;
|
||||
|
||||
case LOCAL_GL_HALF_FLOAT:
|
||||
case LOCAL_GL_HALF_FLOAT_OES:
|
||||
bytesPerPixel = 2*channels;
|
||||
requiredDataType = js::Scalar::Uint16;
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("bad `type`");
|
||||
}
|
||||
if (!isReadTypeValid)
|
||||
return ErrorInvalidEnum("readPixels: Bad type", type);
|
||||
|
||||
const ArrayBufferView& pixbuf = pixels.Value();
|
||||
int dataType = JS_GetArrayBufferViewType(pixbuf.Obj());
|
||||
@ -1988,43 +2068,38 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
|
||||
isSourceTypeFloat = false;
|
||||
}
|
||||
|
||||
if (isReadTypeFloat != isSourceTypeFloat)
|
||||
return ErrorInvalidOperation("readPixels: Invalid type floatness");
|
||||
|
||||
// Check the format and type params to assure they are an acceptable pair (as per spec)
|
||||
|
||||
bool isFormatAndTypeValid = false;
|
||||
const GLenum mainReadFormat = LOCAL_GL_RGBA;
|
||||
const GLenum mainReadType = isSourceTypeFloat ? LOCAL_GL_FLOAT
|
||||
: LOCAL_GL_UNSIGNED_BYTE;
|
||||
|
||||
GLenum auxReadFormat = mainReadFormat;
|
||||
GLenum auxReadType = mainReadType;
|
||||
|
||||
// OpenGL ES 2.0 $4.3.1 - IMPLEMENTATION_COLOR_READ_{TYPE/FORMAT} is a valid
|
||||
// combination for glReadPixels().
|
||||
if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) {
|
||||
GLenum implType = 0;
|
||||
GLenum implFormat = 0;
|
||||
|
||||
gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE,
|
||||
reinterpret_cast<GLint*>(&implType));
|
||||
gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT,
|
||||
reinterpret_cast<GLint*>(&implFormat));
|
||||
|
||||
if (type == implType && format == implFormat) {
|
||||
isFormatAndTypeValid = true;
|
||||
}
|
||||
reinterpret_cast<GLint*>(&auxReadFormat));
|
||||
gl->fGetIntegerv(LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE,
|
||||
reinterpret_cast<GLint*>(&auxReadType));
|
||||
}
|
||||
|
||||
switch (format) {
|
||||
case LOCAL_GL_RGBA: {
|
||||
switch (type) {
|
||||
case LOCAL_GL_UNSIGNED_BYTE:
|
||||
case LOCAL_GL_FLOAT:
|
||||
isFormatAndTypeValid = true;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!isFormatAndTypeValid) {
|
||||
const bool mainMatches = (format == mainReadFormat && type == mainReadType);
|
||||
const bool auxMatches = (format == auxReadFormat && type == auxReadType);
|
||||
const bool isValid = mainMatches || auxMatches;
|
||||
if (!isValid)
|
||||
return ErrorInvalidOperation("readPixels: Invalid format/type pair");
|
||||
|
||||
GLenum readType = type;
|
||||
if (gl->WorkAroundDriverBugs() && gl->IsANGLE()) {
|
||||
if (type == LOCAL_GL_FLOAT &&
|
||||
auxReadFormat == format &&
|
||||
auxReadType == LOCAL_GL_HALF_FLOAT)
|
||||
{
|
||||
readType = auxReadType;
|
||||
}
|
||||
}
|
||||
|
||||
// Now that the errors are out of the way, on to actually reading
|
||||
@ -2035,7 +2110,10 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
|
||||
|
||||
if (CanvasUtils::CheckSaneSubrectSize(x, y, width, height, framebufferWidth, framebufferHeight)) {
|
||||
// the easy case: we're not reading out-of-range pixels
|
||||
gl->fReadPixels(x, y, width, height, format, type, data);
|
||||
|
||||
// Effectively: gl->fReadPixels(x, y, width, height, format, type, dest);
|
||||
ReadPixelsAndConvert(gl, x, y, width, height, format, readType,
|
||||
mPixelStorePackAlignment, format, type, data);
|
||||
} else {
|
||||
// the rectangle doesn't fit entirely in the bound buffer. We then have to set to zero the part
|
||||
// of the buffer that correspond to out-of-range pixels. We don't want to rely on system OpenGL
|
||||
@ -2084,8 +2162,11 @@ WebGLContext::ReadPixels(GLint x, GLint y, GLsizei width,
|
||||
if (!subrect_data)
|
||||
return ErrorOutOfMemory("readPixels: subrect_data");
|
||||
|
||||
gl->fReadPixels(subrect_x, subrect_y, subrect_width, subrect_height,
|
||||
format, type, subrect_data.get());
|
||||
// Effectively: gl->fReadPixels(subrect_x, subrect_y, subrect_width,
|
||||
// subrect_height, format, type, subrect_data.get());
|
||||
ReadPixelsAndConvert(gl, subrect_x, subrect_y, subrect_width, subrect_height,
|
||||
format, readType, mPixelStorePackAlignment, format, type,
|
||||
subrect_data.get());
|
||||
|
||||
// notice that this for loop terminates because we already checked that subrect_height is at most height
|
||||
for (GLint y_inside_subrect = 0; y_inside_subrect < subrect_height; ++y_inside_subrect) {
|
||||
@ -3597,7 +3678,7 @@ mozilla::GetWebGLTexelFormat(TexInternalFormat effectiveInternalFormat)
|
||||
}
|
||||
|
||||
void
|
||||
WebGLContext::BlendColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a) {
|
||||
WebGLContext::BlendColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) {
|
||||
if (IsContextLost())
|
||||
return;
|
||||
MakeContextCurrent();
|
||||
|
@ -266,6 +266,16 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
|
||||
return JS::NumberValue(uint32_t(i));
|
||||
}
|
||||
case LOCAL_GL_IMPLEMENTATION_COLOR_READ_TYPE: {
|
||||
if (mBoundReadFramebuffer) {
|
||||
FBStatus status = mBoundReadFramebuffer->CheckFramebufferStatus();
|
||||
if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
|
||||
ErrorInvalidOperation("getParameter: Read framebuffer must be"
|
||||
" complete before querying"
|
||||
" IMPLEMENTATION_COLOR_READ_TYPE.");
|
||||
return JS::NullValue();
|
||||
}
|
||||
}
|
||||
|
||||
GLint i = 0;
|
||||
if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) {
|
||||
gl->fGetIntegerv(pname, &i);
|
||||
@ -275,6 +285,16 @@ WebGLContext::GetParameter(JSContext* cx, GLenum pname, ErrorResult& rv)
|
||||
return JS::NumberValue(uint32_t(i));
|
||||
}
|
||||
case LOCAL_GL_IMPLEMENTATION_COLOR_READ_FORMAT: {
|
||||
if (mBoundReadFramebuffer) {
|
||||
FBStatus status = mBoundReadFramebuffer->CheckFramebufferStatus();
|
||||
if (status != LOCAL_GL_FRAMEBUFFER_COMPLETE) {
|
||||
ErrorInvalidOperation("getParameter: Read framebuffer must be"
|
||||
" complete before querying"
|
||||
" IMPLEMENTATION_COLOR_READ_FORMAT.");
|
||||
return JS::NullValue();
|
||||
}
|
||||
}
|
||||
|
||||
GLint i = 0;
|
||||
if (gl->IsSupported(gl::GLFeature::ES2_compatibility)) {
|
||||
gl->fGetIntegerv(pname, &i);
|
||||
|
@ -26,7 +26,8 @@ WebGLExtensionColorBufferHalfFloat::IsSupported(const WebGLContext* webgl)
|
||||
gl::GLContext* gl = webgl->GL();
|
||||
|
||||
// ANGLE doesn't support ReadPixels from a RGBA16F with RGBA/FLOAT.
|
||||
return gl->IsSupported(gl::GLFeature::renderbuffer_color_half_float);
|
||||
return gl->IsSupported(gl::GLFeature::renderbuffer_color_half_float) ||
|
||||
gl->IsANGLE();
|
||||
}
|
||||
|
||||
IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionColorBufferHalfFloat)
|
||||
|
@ -129,6 +129,7 @@ WebGLFramebuffer::Attachment::IsReadableFloat() const
|
||||
MOZ_ASSERT(internalformat != LOCAL_GL_NONE);
|
||||
TexType type = TypeFromInternalFormat(internalformat);
|
||||
return type == LOCAL_GL_FLOAT ||
|
||||
type == LOCAL_GL_HALF_FLOAT_OES ||
|
||||
type == LOCAL_GL_HALF_FLOAT;
|
||||
}
|
||||
|
||||
@ -803,6 +804,7 @@ WebGLFramebuffer::CheckFramebufferStatus() const
|
||||
// Ok, attach our chosen flavor of {DEPTH, STENCIL, DEPTH_STENCIL}.
|
||||
FinalizeAttachments();
|
||||
|
||||
// TODO: This should not be unconditionally GL_FRAMEBUFFER.
|
||||
mStatus = mContext->gl->fCheckFramebufferStatus(LOCAL_GL_FRAMEBUFFER);
|
||||
return mStatus;
|
||||
}
|
||||
|
@ -105,7 +105,7 @@ unpackFromFloat16(uint16_t v)
|
||||
uint16_t exp = (v >> 10) & 0x001F;
|
||||
uint16_t mantissa = v & 0x03FF;
|
||||
|
||||
if (exp) {
|
||||
if (!exp) {
|
||||
// Handle denormalized numbers
|
||||
// Adapted from: OpenGL ES 2.0 Programming Guide Appx.
|
||||
// Converting Float to Half-Float
|
||||
|
@ -22,6 +22,8 @@ skip-if = android_version == '10' #Android 2.3 aws only; bug 1030942
|
||||
[webgl-mochitest/test_texsubimage_float.html]
|
||||
[webgl-mochitest/test_webgl_available.html]
|
||||
skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
|
||||
#[webgl-mochitest/test_webgl_color_buffer_float.html]
|
||||
# We haven't cleaned up the Try results yet, but let's get this on the books first.
|
||||
[webgl-mochitest/test_webgl_conformance.html]
|
||||
skip-if = buildapp == 'mulet' || toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
|
||||
[webgl-mochitest/test_webgl_request_context.html]
|
||||
|
@ -0,0 +1,486 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset='UTF-8'>
|
||||
<script src='/tests/SimpleTest/SimpleTest.js'></script>
|
||||
<link rel='stylesheet' href='/tests/SimpleTest/test.css'>
|
||||
</head>
|
||||
<body>
|
||||
<script id='vs' type='x-shader/x-vertex'>
|
||||
|
||||
attribute vec2 aVertCoord;
|
||||
|
||||
void main(void) {
|
||||
gl_Position = vec4(aVertCoord, 0.0, 1.0);
|
||||
}
|
||||
|
||||
</script>
|
||||
<script id='fs' type='x-shader/x-fragment'>
|
||||
|
||||
precision mediump float; // 💩
|
||||
|
||||
uniform vec4 uFragColor;
|
||||
|
||||
void main(void) {
|
||||
gl_FragColor = uFragColor;
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<canvas id='c' width='200' height='200'></canvas>
|
||||
|
||||
<script>
|
||||
|
||||
function GetGLSLByElemId(elemId) {
|
||||
var elem = document.getElementById(elemId);
|
||||
if (!elem)
|
||||
throw 'Bad `elemId`: ' + elemId;
|
||||
|
||||
return elem.innerHTML.trim();
|
||||
}
|
||||
|
||||
function ProgramByElemIds(gl, vsId, fsId) {
|
||||
var vs = gl.createShader(gl.VERTEX_SHADER);
|
||||
gl.shaderSource(vs, GetGLSLByElemId(vsId));
|
||||
gl.compileShader(vs);
|
||||
|
||||
var fs = gl.createShader(gl.FRAGMENT_SHADER);
|
||||
gl.shaderSource(fs, GetGLSLByElemId(fsId));
|
||||
gl.compileShader(fs);
|
||||
|
||||
var prog = gl.createProgram();
|
||||
gl.attachShader(prog, vs);
|
||||
gl.attachShader(prog, fs);
|
||||
|
||||
gl.linkProgram(prog);
|
||||
|
||||
var success = gl.getProgramParameter(prog, gl.LINK_STATUS);
|
||||
if (success)
|
||||
return prog;
|
||||
|
||||
console.log('Error linking program for \'' + vsId + '\' and \'' + fsId + '\'.');
|
||||
console.log('\nLink log: ' + gl.getProgramInfoLog(prog));
|
||||
console.log('\nVert shader log: ' + gl.getShaderInfoLog(vs));
|
||||
console.log('\nFrag shader log: ' + gl.getShaderInfoLog(fs));
|
||||
return null;
|
||||
}
|
||||
|
||||
var RGBA = 0x1908;
|
||||
var UNSIGNED_BYTE = 0x1401;
|
||||
var FLOAT = 0x1406;
|
||||
var HALF_FLOAT_OES = 0x8D61;
|
||||
var HALF_FLOAT = 0x140B;
|
||||
var RGBA4 = 0x8056;
|
||||
var RGBA8 = 0x8058;
|
||||
var RGBA32F = 0x8814;
|
||||
var RGBA16F = 0x881A;
|
||||
|
||||
function EnumName(val) {
|
||||
switch (val) {
|
||||
case RGBA:
|
||||
return 'RGBA';
|
||||
case UNSIGNED_BYTE:
|
||||
return 'UNSIGNED_BYTE';
|
||||
case FLOAT:
|
||||
return 'FLOAT';
|
||||
case HALF_FLOAT_OES:
|
||||
return 'HALF_FLOAT_OES';
|
||||
case HALF_FLOAT:
|
||||
return 'HALF_FLOAT';
|
||||
case RGBA4:
|
||||
return 'RGBA4';
|
||||
case RGBA32F:
|
||||
return 'RGBA32F';
|
||||
default:
|
||||
throw 'Unknown enum: 0x' + val.toString(16);
|
||||
}
|
||||
}
|
||||
|
||||
var gl;
|
||||
|
||||
function RGBAToString(arr) {
|
||||
return '[' + arr[0].toPrecision(4) + ', ' +
|
||||
arr[1].toPrecision(4) + ', ' +
|
||||
arr[2].toPrecision(4) + ', ' +
|
||||
arr[3].toPrecision(4) + ']';
|
||||
}
|
||||
|
||||
function TestScreenColor(gl, isFBFloat, r, g, b, a) {
|
||||
var readType = isFBFloat ? FLOAT : UNSIGNED_BYTE;
|
||||
|
||||
var arr;
|
||||
switch (readType) {
|
||||
case gl.UNSIGNED_BYTE:
|
||||
arr = new Uint8Array(4);
|
||||
break;
|
||||
|
||||
case gl.FLOAT:
|
||||
arr = new Float32Array(4);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw 'Bad `readType`.';
|
||||
}
|
||||
|
||||
gl.readPixels(0, 0, 1, 1, gl.RGBA, readType, arr);
|
||||
|
||||
var err = gl.getError();
|
||||
ok(err == 0, 'Should be no errors.');
|
||||
if (err)
|
||||
return;
|
||||
|
||||
var floatArr;
|
||||
switch (readType) {
|
||||
case gl.UNSIGNED_BYTE:
|
||||
floatArr = new Float32Array(4);
|
||||
floatArr[0] = arr[0] / 255.0;
|
||||
floatArr[1] = arr[1] / 255.0;
|
||||
floatArr[2] = arr[2] / 255.0;
|
||||
floatArr[3] = arr[3] / 255.0;
|
||||
break;
|
||||
|
||||
case gl.FLOAT:
|
||||
floatArr = arr;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw 'Bad `readType`.';
|
||||
}
|
||||
|
||||
var testText = RGBAToString(floatArr);
|
||||
var refText = RGBAToString([r, g, b, a]);
|
||||
|
||||
var eps = 1.0 / 255.0;
|
||||
var isSame = (Math.abs(floatArr[0] - r) < eps &&
|
||||
Math.abs(floatArr[1] - g) < eps &&
|
||||
Math.abs(floatArr[2] - b) < eps &&
|
||||
Math.abs(floatArr[3] - a) < eps);
|
||||
|
||||
ok(isSame, 'Should be ' + refText + ', was ' + testText + ',');
|
||||
}
|
||||
|
||||
function TestReadFormat(gl, isFBFloat, format, type) {
|
||||
var err = gl.getError();
|
||||
if (err) {
|
||||
ok(false, 'Should be no error at start of TestReadFormat(). (0x' + err.toString(16) + ')');
|
||||
return;
|
||||
}
|
||||
var implFormat = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT);
|
||||
var implType = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE);
|
||||
|
||||
var err = gl.getError();
|
||||
if (err) {
|
||||
ok(false, 'Should be no error at start2 of TestReadFormat(). (0x' + err.toString(16) + ')');
|
||||
return;
|
||||
}
|
||||
|
||||
var defaultReadType = isFBFloat ? FLOAT : UNSIGNED_BYTE;
|
||||
|
||||
var formatOk = (format == gl.RGBA &&
|
||||
type == defaultReadType);
|
||||
|
||||
if (format == implFormat &&
|
||||
type == implType)
|
||||
{
|
||||
formatOk = true;
|
||||
}
|
||||
|
||||
var w = 1;
|
||||
var h = 1;
|
||||
var channels = 4;
|
||||
var arrSize = w * h * channels;
|
||||
|
||||
var arr;
|
||||
switch (type) {
|
||||
case UNSIGNED_BYTE:
|
||||
arr = new Uint8Array(arrSize);
|
||||
break;
|
||||
|
||||
case FLOAT:
|
||||
arr = new Float32Array(arrSize);
|
||||
break;
|
||||
|
||||
case HALF_FLOAT_OES:
|
||||
case HALF_FLOAT:
|
||||
arr = new Uint16Array(arrSize);
|
||||
break;
|
||||
|
||||
default:
|
||||
throw 'Bad `type`: 0x' + type.toString(16);
|
||||
}
|
||||
|
||||
gl.readPixels(0, 0, 1, 1, format, type, arr);
|
||||
var wasOk = gl.getError() == 0;
|
||||
|
||||
var text = 'Should ' + (formatOk ? '' : 'not ') + 'allow reading with ' +
|
||||
EnumName(format) + '/' + EnumName(type) + '.'
|
||||
ok(wasOk == formatOk, text);
|
||||
}
|
||||
|
||||
function TestError(gl, expectedErr, descText) {
|
||||
var err = gl.getError();
|
||||
|
||||
while (gl.getError()) {}
|
||||
|
||||
ok(err == expectedErr,
|
||||
descText + ': Error should be 0x' + expectedErr.toString(16) + ', was 0x' +
|
||||
err.toString(16) + '.');
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
function AttachRBToCurFB(gl, sizedFormat) {
|
||||
var isSupported;
|
||||
switch (sizedFormat) {
|
||||
case RGBA4:
|
||||
isSupported = true;
|
||||
break;
|
||||
|
||||
case RGBA16F:
|
||||
isSupported = !!gl.getExtension('EXT_color_buffer_half_float');
|
||||
break;
|
||||
|
||||
case RGBA32F:
|
||||
isSupported = !!gl.getExtension('WEBGL_color_buffer_float');
|
||||
break;
|
||||
|
||||
default:
|
||||
throw 'Bad `sizedFormat`.';
|
||||
}
|
||||
|
||||
var rb = gl.createRenderbuffer();
|
||||
gl.bindRenderbuffer(gl.RENDERBUFFER, rb);
|
||||
gl.renderbufferStorage(gl.RENDERBUFFER, sizedFormat, 1, 1);
|
||||
|
||||
var correctError = isSupported ? 0 : gl.INVALID_ENUM;
|
||||
var err = TestError(gl, correctError, 'RB specification with supported format');
|
||||
if (err)
|
||||
return false;
|
||||
|
||||
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rb);
|
||||
|
||||
var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
|
||||
var isComplete = (status == gl.FRAMEBUFFER_COMPLETE);
|
||||
ok(isComplete, 'Framebuffer should be complete after RB attachment.');
|
||||
return isComplete;
|
||||
}
|
||||
|
||||
function AttachTexToCurFB(gl, sizedFormat) {
|
||||
var canCreate;
|
||||
var isAttachGuaranteed;
|
||||
var format;
|
||||
var type;
|
||||
|
||||
switch (sizedFormat) {
|
||||
case RGBA8:
|
||||
canCreate = true;
|
||||
isAttachGuaranteed = true;
|
||||
format = RGBA;
|
||||
type = UNSIGNED_BYTE;
|
||||
break;
|
||||
|
||||
case RGBA16F:
|
||||
canCreate = !!gl.getExtension('OES_texture_half_float');
|
||||
isAttachGuaranteed = !!gl.getExtension('EXT_color_buffer_half_float');
|
||||
format = RGBA;
|
||||
type = HALF_FLOAT_OES;
|
||||
break;
|
||||
|
||||
case RGBA32F:
|
||||
canCreate = !!gl.getExtension('OES_texture_float');
|
||||
isAttachGuaranteed = !!gl.getExtension('WEBGL_color_buffer_float');
|
||||
format = RGBA;
|
||||
type = FLOAT;
|
||||
break;
|
||||
|
||||
default:
|
||||
throw 'Bad `sizedFormat`.';
|
||||
}
|
||||
|
||||
var tex = gl.createTexture();
|
||||
gl.bindTexture(gl.TEXTURE_2D, tex);
|
||||
gl.texImage2D(gl.TEXTURE_2D, 0, format, 1, 1, 0, format, type, null);
|
||||
|
||||
var correctError = canCreate ? 0 : gl.INVALID_ENUM;
|
||||
var err = TestError(gl, correctError, 'Tex specification with supported format');
|
||||
if (err)
|
||||
return false;
|
||||
|
||||
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
|
||||
|
||||
var status = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
|
||||
var isComplete = (status == gl.FRAMEBUFFER_COMPLETE);
|
||||
|
||||
if (!isAttachGuaranteed && !isComplete)
|
||||
todo(false, 'Framebuffer needn\'t be complete after tex attachment.');
|
||||
else
|
||||
ok(isComplete, 'Framebuffer should be complete after tex attachment.');
|
||||
|
||||
return isComplete;
|
||||
}
|
||||
|
||||
function IsFormatFloat(sizedFormat) {
|
||||
switch (sizedFormat) {
|
||||
case RGBA4:
|
||||
case RGBA8:
|
||||
return false;
|
||||
|
||||
case RGBA16F:
|
||||
case RGBA32F:
|
||||
return true;
|
||||
|
||||
default:
|
||||
throw 'Bad `sizedFormat`.';
|
||||
}
|
||||
}
|
||||
|
||||
function TestType(gl, prog, isTex, sizedFormat) {
|
||||
TestError(gl, 0, 'At start of TestRB()');
|
||||
|
||||
var isAttached = isTex ? AttachTexToCurFB(gl, sizedFormat)
|
||||
: AttachRBToCurFB(gl, sizedFormat);
|
||||
if (!isAttached)
|
||||
return;
|
||||
|
||||
var isFormatFloat = IsFormatFloat(sizedFormat);
|
||||
|
||||
TestReadFormat(gl, isFormatFloat, gl.RGBA, gl.UNSIGNED_BYTE);
|
||||
TestReadFormat(gl, isFormatFloat, gl.RGBA, gl.FLOAT);
|
||||
TestReadFormat(gl, isFormatFloat, gl.RGBA, HALF_FLOAT);
|
||||
TestReadFormat(gl, isFormatFloat, gl.RGBA, HALF_FLOAT_OES);
|
||||
|
||||
//////////////////////////////////////
|
||||
|
||||
ok(true, 'Drawing:');
|
||||
|
||||
gl.clearColor(0.0, 1.5, 0.5, 1.0);
|
||||
gl.clear(gl.COLOR_BUFFER_BIT);
|
||||
|
||||
if (isFormatFloat)
|
||||
TestScreenColor(gl, isFormatFloat, 0, 1.5, 0.5, 1);
|
||||
else
|
||||
TestScreenColor(gl, isFormatFloat, 0, 1, 0.5, 1);
|
||||
|
||||
////////
|
||||
|
||||
ok(true, 'Clearing:');
|
||||
|
||||
gl.uniform4f(prog.uFragColor, 0, 0.5, 1.5, 1);
|
||||
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
if (isFormatFloat)
|
||||
TestScreenColor(gl, isFormatFloat, 0, 0.5, 1.5, 1);
|
||||
else
|
||||
TestScreenColor(gl, isFormatFloat, 0, 0.5, 1.0, 1);
|
||||
|
||||
////////
|
||||
|
||||
ok(true, 'Blending:');
|
||||
|
||||
gl.enable(gl.BLEND);
|
||||
gl.blendFunc(gl.CONSTANT_COLOR, gl.ZERO);
|
||||
gl.blendColor(0, 10, 0.1, 1);
|
||||
|
||||
gl.uniform4f(prog.uFragColor, 0, 0.5, 15.0, 1);
|
||||
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
if (isFormatFloat)
|
||||
TestScreenColor(gl, isFormatFloat, 0, 5.0, 1.5, 1);
|
||||
else
|
||||
TestScreenColor(gl, isFormatFloat, 0, 0.5, 0.1, 1);
|
||||
|
||||
gl.disable(gl.BLEND);
|
||||
|
||||
//////////////////////////////////////
|
||||
}
|
||||
|
||||
// Give ourselves a scope to return early from:
|
||||
(function() {
|
||||
var canvas = document.getElementById('c');
|
||||
var attribs = {
|
||||
antialias: false,
|
||||
depth: false,
|
||||
};
|
||||
gl = canvas.getContext('experimental-webgl', attribs);
|
||||
if (!gl) {
|
||||
todo(false, 'WebGL is unavailable.');
|
||||
return;
|
||||
}
|
||||
|
||||
var cbf = gl.getExtension('WEBGL_color_buffer_float');
|
||||
var cbhf = gl.getExtension('EXT_color_buffer_half_float');
|
||||
|
||||
//////////////////////////////////////
|
||||
|
||||
gl.viewport(0, 0, 1, 1);
|
||||
|
||||
var prog = ProgramByElemIds(gl, 'vs', 'fs');
|
||||
ok(prog, 'Program should link.');
|
||||
if (!prog)
|
||||
return;
|
||||
|
||||
prog.aVertCoord = gl.getAttribLocation(prog, 'aVertCoord');
|
||||
prog.uFragColor = gl.getUniformLocation(prog, 'uFragColor');
|
||||
|
||||
gl.useProgram(prog);
|
||||
|
||||
var arr = new Float32Array([
|
||||
-1, -1,
|
||||
1, -1,
|
||||
-1, 1,
|
||||
1, 1,
|
||||
]);
|
||||
var vb = gl.createBuffer();
|
||||
gl.bindBuffer(gl.ARRAY_BUFFER, vb);
|
||||
gl.bufferData(gl.ARRAY_BUFFER, arr, gl.STATIC_DRAW);
|
||||
|
||||
gl.enableVertexAttribArray(0);
|
||||
gl.vertexAttribPointer(0, 2, gl.FLOAT, false, 0, 0);
|
||||
|
||||
//////////////////////////////////////
|
||||
|
||||
var fb = gl.createFramebuffer();
|
||||
gl.bindFramebuffer(gl.FRAMEBUFFER, fb);
|
||||
|
||||
error = gl.getError();
|
||||
ok(error == 0, 'Should be no errors after setup. (0x' + error.toString(16) + ')');
|
||||
|
||||
//////////////////////////////////////
|
||||
ok(true, '---------------------------------------------------------------------------');
|
||||
ok(true, 'RGBA8 texture');
|
||||
TestType(gl, prog, true, RGBA8);
|
||||
|
||||
ok(true, '---------------------------------------------------------------------------');
|
||||
ok(true, 'RGBA16F texture');
|
||||
TestType(gl, prog, true, RGBA16F);
|
||||
|
||||
ok(true, '---------------------------------------------------------------------------');
|
||||
ok(true, 'RGBA32F texture');
|
||||
TestType(gl, prog, true, RGBA32F);
|
||||
|
||||
////////
|
||||
|
||||
ok(true, '---------------------------------------------------------------------------');
|
||||
ok(true, 'RGBA4 renderbuffer');
|
||||
TestType(gl, prog, false, RGBA4);
|
||||
|
||||
ok(true, '---------------------------------------------------------------------------');
|
||||
ok(true, 'RGBA16F renderbuffer');
|
||||
TestType(gl, prog, false, RGBA16F);
|
||||
|
||||
ok(true, '---------------------------------------------------------------------------');
|
||||
ok(true, 'RGBA32F renderbuffer');
|
||||
TestType(gl, prog, false, RGBA32F);
|
||||
|
||||
ok(true, '---------------------------------------------------------------------------');
|
||||
//////////////////////////////////////
|
||||
|
||||
error = gl.getError();
|
||||
ok(error == 0, 'Should be no errors after test.');
|
||||
|
||||
ok(true, 'TEST COMPLETE');
|
||||
})();
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
@ -4,6 +4,8 @@ skip-if = buildapp == 'b2g' || buildapp == 'mulet' || e10s
|
||||
[test_blob_sliced_from_parent_process.html]
|
||||
# This test is only supposed to run in the main process.
|
||||
skip-if = buildapp == 'b2g' || buildapp == 'mulet' || e10s
|
||||
[test_cpow_cookies.html]
|
||||
skip-if = buildapp == 'b2g' || buildapp == 'mulet'
|
||||
[test_NuwaProcessCreation.html]
|
||||
skip-if = toolkit != 'gonk'
|
||||
[test_NuwaProcessDeadlock.html]
|
||||
|
89
dom/ipc/tests/test_cpow_cookies.html
Normal file
89
dom/ipc/tests/test_cpow_cookies.html
Normal file
@ -0,0 +1,89 @@
|
||||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<title>Test for recursive CPOW-getting-cookie bug</title>
|
||||
<script type="application/javascript"
|
||||
src="/tests/SimpleTest/SimpleTest.js">
|
||||
</script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<script type="application/javascript;version=1.8">
|
||||
"use strict";
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
const childFrameURL =
|
||||
"data:text/html,<!DOCTYPE HTML><html><body></body></html>";
|
||||
|
||||
function childFrameScript() {
|
||||
"use strict";
|
||||
|
||||
const Ci = Components.interfaces;
|
||||
|
||||
function test1(message) {
|
||||
// NB: This is a no-op because we're a data: document with a null
|
||||
// principal.
|
||||
content.document.cookie = "a=b";
|
||||
message.target.sendAsyncMessage("testCPOWCookies:test1Finished", { pass: true });
|
||||
}
|
||||
|
||||
addMessageListener("testCPOWCookies:test1", function(message) {
|
||||
test1(message);
|
||||
});
|
||||
}
|
||||
|
||||
let test;
|
||||
function* testStructure(mm) {
|
||||
let lastResult;
|
||||
|
||||
function testDone(msg) {
|
||||
test.next(msg.data);
|
||||
}
|
||||
|
||||
mm.addMessageListener("testCPOWCookies:test1Finished", testDone);
|
||||
|
||||
mm.sendAsyncMessage("testCPOWCookies:test1", {});
|
||||
lastResult = yield;
|
||||
ok(lastResult.pass, "got the right answer and didn't crash");
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
function runTests() {
|
||||
info("Browser prefs set.");
|
||||
|
||||
let iframe = document.createElement("iframe");
|
||||
SpecialPowers.wrap(iframe).mozbrowser = true;
|
||||
iframe.id = "iframe";
|
||||
iframe.src = childFrameURL;
|
||||
|
||||
iframe.addEventListener("mozbrowserloadend", function() {
|
||||
info("Got iframe load event.");
|
||||
let mm = SpecialPowers.getBrowserFrameMessageManager(iframe);
|
||||
mm.loadFrameScript("data:,(" + encodeURI(childFrameScript.toString()) + ")();",
|
||||
false);
|
||||
|
||||
test = testStructure(mm);
|
||||
test.next();
|
||||
});
|
||||
|
||||
document.body.appendChild(iframe);
|
||||
}
|
||||
|
||||
addEventListener("load", function() {
|
||||
info("Got load event.");
|
||||
|
||||
SpecialPowers.addPermission("browser", true, document);
|
||||
SpecialPowers.pushPrefEnv({
|
||||
"set": [
|
||||
["dom.ipc.browser_frames.oop_by_default", true],
|
||||
["dom.mozBrowserFramesEnabled", true],
|
||||
["browser.pagethumbnails.capturing_disabled", true]
|
||||
]
|
||||
}, runTests);
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -43,6 +43,6 @@ partial interface EventTarget {
|
||||
// chrome easier. This returns the window which can be used to create
|
||||
// events to fire at this EventTarget, or null if there isn't one.
|
||||
partial interface EventTarget {
|
||||
[ChromeOnly]
|
||||
[ChromeOnly, Exposed=Window]
|
||||
readonly attribute WindowProxy? ownerGlobal;
|
||||
};
|
||||
|
@ -520,7 +520,7 @@ interface WebGLRenderingContext {
|
||||
void bindFramebuffer(GLenum target, WebGLFramebuffer? framebuffer);
|
||||
void bindRenderbuffer(GLenum target, WebGLRenderbuffer? renderbuffer);
|
||||
void bindTexture(GLenum target, WebGLTexture? texture);
|
||||
void blendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
|
||||
void blendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
|
||||
void blendEquation(GLenum mode);
|
||||
void blendEquationSeparate(GLenum modeRGB, GLenum modeAlpha);
|
||||
void blendFunc(GLenum sfactor, GLenum dfactor);
|
||||
@ -535,7 +535,7 @@ interface WebGLRenderingContext {
|
||||
|
||||
[WebGLHandlesContextLoss] GLenum checkFramebufferStatus(GLenum target);
|
||||
void clear(GLbitfield mask);
|
||||
void clearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
|
||||
void clearColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
|
||||
void clearDepth(GLclampf depth);
|
||||
void clearStencil(GLint s);
|
||||
void colorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
|
||||
|
@ -42,55 +42,21 @@ NS_IMETHODIMP nsPrintProgress::OpenProgressDialog(nsIDOMWindow *parent,
|
||||
nsIObserver *openDialogObserver,
|
||||
bool *notifyOnOpen)
|
||||
{
|
||||
m_observer = openDialogObserver;
|
||||
|
||||
nsresult rv = NS_ERROR_FAILURE;
|
||||
|
||||
if (m_dialog)
|
||||
return NS_ERROR_ALREADY_INITIALIZED;
|
||||
|
||||
if (!dialogURL || !*dialogURL)
|
||||
return NS_ERROR_INVALID_ARG;
|
||||
|
||||
if (parent)
|
||||
{
|
||||
// Set up window.arguments[0]...
|
||||
nsCOMPtr<nsISupportsArray> array;
|
||||
rv = NS_NewISupportsArray(getter_AddRefs(array));
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
nsCOMPtr<nsISupportsInterfacePointer> ifptr =
|
||||
do_CreateInstance(NS_SUPPORTS_INTERFACE_POINTER_CONTRACTID, &rv);
|
||||
NS_ENSURE_SUCCESS(rv, rv);
|
||||
|
||||
ifptr->SetData(static_cast<nsIPrintProgress*>(this));
|
||||
ifptr->SetDataIID(&NS_GET_IID(nsIPrintProgress));
|
||||
|
||||
array->AppendElement(ifptr);
|
||||
|
||||
array->AppendElement(parameters);
|
||||
|
||||
// Open the dialog.
|
||||
nsCOMPtr<nsIDOMWindow> newWindow;
|
||||
rv = parent->OpenDialog(NS_ConvertASCIItoUTF16(dialogURL),
|
||||
NS_LITERAL_STRING("_blank"),
|
||||
NS_LITERAL_STRING("chrome,titlebar,dependent,centerscreen"),
|
||||
array, getter_AddRefs(newWindow));
|
||||
if (NS_SUCCEEDED(rv)) {
|
||||
*notifyOnOpen = true;
|
||||
}
|
||||
}
|
||||
|
||||
return rv;
|
||||
MOZ_ASSERT_UNREACHABLE("The nsPrintingPromptService::ShowProgress "
|
||||
"implementation for OS X returns "
|
||||
"NS_ERROR_NOT_IMPLEMENTED, so we should never get "
|
||||
"here.");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* void closeProgressDialog (in boolean forceClose); */
|
||||
NS_IMETHODIMP nsPrintProgress::CloseProgressDialog(bool forceClose)
|
||||
{
|
||||
m_closeProgress = true;
|
||||
// XXX Casting bool to nsresult
|
||||
return OnStateChange(nullptr, nullptr, nsIWebProgressListener::STATE_STOP,
|
||||
static_cast<nsresult>(forceClose));
|
||||
MOZ_ASSERT_UNREACHABLE("The nsPrintingPromptService::ShowProgress "
|
||||
"implementation for OS X returns "
|
||||
"NS_ERROR_NOT_IMPLEMENTED, so we should never get "
|
||||
"here.");
|
||||
return NS_ERROR_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* nsIPrompt GetPrompter (); */
|
||||
|
@ -6,10 +6,16 @@
|
||||
#include "nsPrintProgress.h"
|
||||
|
||||
#include "nsIBaseWindow.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIDocShellTreeOwner.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsISupportsArray.h"
|
||||
#include "nsIXULWindow.h"
|
||||
#include "nsXPCOM.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
||||
|
||||
NS_IMPL_ADDREF(nsPrintProgress)
|
||||
NS_IMPL_RELEASE(nsPrintProgress)
|
||||
@ -71,12 +77,29 @@ NS_IMETHODIMP nsPrintProgress::OpenProgressDialog(nsIDOMWindow *parent,
|
||||
|
||||
array->AppendElement(parameters);
|
||||
|
||||
// We will set the opener of the dialog to be the nsIDOMWindow for the
|
||||
// browser XUL window itself, as opposed to the content. That way, the
|
||||
// progress window has access to the opener.
|
||||
nsCOMPtr<nsPIDOMWindow> pParentWindow = do_QueryInterface(parent);
|
||||
NS_ENSURE_STATE(pParentWindow);
|
||||
|
||||
nsCOMPtr<nsIDocShell> docShell = pParentWindow->GetDocShell();
|
||||
NS_ENSURE_STATE(docShell);
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeOwner> owner;
|
||||
docShell->GetTreeOwner(getter_AddRefs(owner));
|
||||
|
||||
nsCOMPtr<nsIXULWindow> ownerXULWindow = do_GetInterface(owner);
|
||||
nsCOMPtr<nsIDOMWindow> ownerWindow = do_GetInterface(ownerXULWindow);
|
||||
NS_ENSURE_STATE(ownerWindow);
|
||||
|
||||
// Open the dialog.
|
||||
nsCOMPtr<nsIDOMWindow> newWindow;
|
||||
rv = parent->OpenDialog(NS_ConvertASCIItoUTF16(dialogURL),
|
||||
NS_LITERAL_STRING("_blank"),
|
||||
NS_LITERAL_STRING("chrome,titlebar,dependent,centerscreen"),
|
||||
array, getter_AddRefs(newWindow));
|
||||
|
||||
rv = ownerWindow->OpenDialog(NS_ConvertASCIItoUTF16(dialogURL),
|
||||
NS_LITERAL_STRING("_blank"),
|
||||
NS_LITERAL_STRING("chrome,titlebar,dependent,centerscreen"),
|
||||
array, getter_AddRefs(newWindow));
|
||||
}
|
||||
|
||||
return rv;
|
||||
|
@ -6,11 +6,16 @@
|
||||
#include "nsPrintProgress.h"
|
||||
|
||||
#include "nsIBaseWindow.h"
|
||||
#include "nsIDocShell.h"
|
||||
#include "nsIDocShellTreeOwner.h"
|
||||
#include "nsIInterfaceRequestorUtils.h"
|
||||
#include "nsISupportsArray.h"
|
||||
#include "nsIXULWindow.h"
|
||||
#include "nsXPCOM.h"
|
||||
#include "nsISupportsPrimitives.h"
|
||||
#include "nsIComponentManager.h"
|
||||
#include "nsIServiceManager.h"
|
||||
#include "nsPIDOMWindow.h"
|
||||
|
||||
#if 0
|
||||
NS_IMPL_ADDREF(nsPrintProgress)
|
||||
@ -100,12 +105,28 @@ NS_IMETHODIMP nsPrintProgress::OpenProgressDialog(nsIDOMWindow *parent,
|
||||
|
||||
array->AppendElement(parameters);
|
||||
|
||||
// We will set the opener of the dialog to be the nsIDOMWindow for the
|
||||
// browser XUL window itself, as opposed to the content. That way, the
|
||||
// progress window has access to the opener.
|
||||
nsCOMPtr<nsPIDOMWindow> pParentWindow = do_QueryInterface(parent);
|
||||
NS_ENSURE_STATE(pParentWindow);
|
||||
|
||||
nsCOMPtr<nsIDocShell> docShell = pParentWindow->GetDocShell();
|
||||
NS_ENSURE_STATE(docShell);
|
||||
|
||||
nsCOMPtr<nsIDocShellTreeOwner> owner;
|
||||
docShell->GetTreeOwner(getter_AddRefs(owner));
|
||||
|
||||
nsCOMPtr<nsIXULWindow> ownerXULWindow = do_GetInterface(owner);
|
||||
nsCOMPtr<nsIDOMWindow> ownerWindow = do_GetInterface(ownerXULWindow);
|
||||
NS_ENSURE_STATE(ownerWindow);
|
||||
|
||||
// Open the dialog.
|
||||
nsCOMPtr<nsIDOMWindow> newWindow;
|
||||
rv = parent->OpenDialog(NS_ConvertASCIItoUTF16(dialogURL),
|
||||
NS_LITERAL_STRING("_blank"),
|
||||
NS_LITERAL_STRING("chrome,titlebar,dependent,centerscreen"),
|
||||
array, getter_AddRefs(newWindow));
|
||||
rv = ownerWindow->OpenDialog(NS_ConvertASCIItoUTF16(dialogURL),
|
||||
NS_LITERAL_STRING("_blank"),
|
||||
NS_LITERAL_STRING("chrome,titlebar,dependent,centerscreen"),
|
||||
array, getter_AddRefs(newWindow));
|
||||
}
|
||||
|
||||
return rv;
|
||||
|
@ -1166,6 +1166,8 @@ public:
|
||||
// This is a little hacky at the moment, but we want to have this data. Bug 1068613.
|
||||
static void SetLogForwarder(LogForwarder* aLogFwd);
|
||||
|
||||
static uint32_t GetMaxSurfaceSize(BackendType aType);
|
||||
|
||||
static LogForwarder* GetLogForwarder() { return mLogForwarder; }
|
||||
|
||||
private:
|
||||
|
@ -111,8 +111,8 @@ struct BaseRect {
|
||||
Sub result;
|
||||
result.x = std::max<T>(x, aRect.x);
|
||||
result.y = std::max<T>(y, aRect.y);
|
||||
result.width = std::min<T>(XMost(), aRect.XMost()) - result.x;
|
||||
result.height = std::min<T>(YMost(), aRect.YMost()) - result.y;
|
||||
result.width = std::min<T>(x - result.x + width, aRect.x - result.x + aRect.width);
|
||||
result.height = std::min<T>(y - result.y + height, aRect.y - result.y + aRect.height);
|
||||
if (result.width < 0 || result.height < 0) {
|
||||
result.SizeTo(0, 0);
|
||||
}
|
||||
|
@ -1693,10 +1693,11 @@ DrawTargetCG::Init(BackendType aType,
|
||||
{
|
||||
// XXX: we should come up with some consistent semantics for dealing
|
||||
// with zero area drawtargets
|
||||
if (aSize.width <= 0 || aSize.height <= 0 ||
|
||||
// 32767 is the maximum size supported by cairo
|
||||
// we clamp to that to make it easier to interoperate
|
||||
aSize.width > 32767 || aSize.height > 32767) {
|
||||
if (aSize.width <= 0 ||
|
||||
aSize.height <= 0 ||
|
||||
size_t(aSize.width) > GetMaxSurfaceSize() ||
|
||||
size_t(aSize.height) > GetMaxSurfaceSize())
|
||||
{
|
||||
gfxWarning() << "Failed to Init() DrawTargetCG because of bad size.";
|
||||
mColorSpace = nullptr;
|
||||
mCg = nullptr;
|
||||
|
@ -183,6 +183,13 @@ public:
|
||||
CGContextRef GetCGContext() {
|
||||
return mCg;
|
||||
}
|
||||
|
||||
// 32767 is the maximum size supported by cairo. We clamp to that to make it
|
||||
// easier to interoperate.
|
||||
static size_t GetMaxSurfaceSize() {
|
||||
return 32767;
|
||||
}
|
||||
|
||||
private:
|
||||
void MarkChanged();
|
||||
|
||||
|
@ -170,6 +170,11 @@ public:
|
||||
|
||||
static cairo_surface_t *GetDummySurface();
|
||||
|
||||
// Cairo hardcodes this as its maximum surface size.
|
||||
static size_t GetMaxSurfaceSize() {
|
||||
return 32767;
|
||||
}
|
||||
|
||||
private: // methods
|
||||
// Init cairo surface without doing a cairo_surface_reference() call.
|
||||
bool InitAlreadyReferenced(cairo_surface_t* aSurface, const IntSize& aSize, SurfaceFormat* aFormat = nullptr);
|
||||
|
@ -145,6 +145,10 @@ public:
|
||||
static IDWriteFactory *GetDWriteFactory();
|
||||
ID2D1RenderTarget *GetRT() { return mRT; }
|
||||
|
||||
static uint32_t GetMaxSurfaceSize() {
|
||||
return D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION;
|
||||
}
|
||||
|
||||
operator std::string() const {
|
||||
std::stringstream stream;
|
||||
stream << "DrawTargetD2D(" << this << ")";
|
||||
|
@ -144,6 +144,10 @@ public:
|
||||
return stream.str();
|
||||
}
|
||||
|
||||
static uint32_t GetMaxSurfaceSize() {
|
||||
return D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION;
|
||||
}
|
||||
|
||||
static uint64_t mVRAMUsageDT;
|
||||
static uint64_t mVRAMUsageSS;
|
||||
|
||||
|
@ -449,6 +449,30 @@ Factory::DoesBackendSupportDataDrawtarget(BackendType aType)
|
||||
return false;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
Factory::GetMaxSurfaceSize(BackendType aType)
|
||||
{
|
||||
switch (aType) {
|
||||
case BackendType::CAIRO:
|
||||
case BackendType::COREGRAPHICS:
|
||||
return DrawTargetCairo::GetMaxSurfaceSize();
|
||||
#ifdef XP_MACOSX
|
||||
case BackendType::COREGRAPHICS_ACCELERATED:
|
||||
return DrawTargetCG::GetMaxSurfaceSize();
|
||||
#endif
|
||||
case BackendType::SKIA:
|
||||
return INT_MAX;
|
||||
#ifdef WIN32
|
||||
case BackendType::DIRECT2D:
|
||||
return DrawTargetD2D::GetMaxSurfaceSize();
|
||||
case BackendType::DIRECT2D1_1:
|
||||
return DrawTargetD2D1::GetMaxSurfaceSize();
|
||||
#endif
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
TemporaryRef<ScaledFont>
|
||||
Factory::CreateScaledFontForNativeFont(const NativeFont &aNativeFont, Float aSize)
|
||||
{
|
||||
|
@ -295,7 +295,7 @@ void GL_APIENTRY glBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLcla
|
||||
|
||||
if (context)
|
||||
{
|
||||
context->getState().setBlendColor(gl::clamp01(red), gl::clamp01(green), gl::clamp01(blue), gl::clamp01(alpha));
|
||||
context->getState().setBlendColor(red, green, blue, alpha);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -886,7 +886,7 @@ public:
|
||||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
void fBlendColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
|
||||
void fBlendColor(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha) {
|
||||
BEFORE_GL_CALL;
|
||||
mSymbols.fBlendColor(red, green, blue, alpha);
|
||||
AFTER_GL_CALL;
|
||||
@ -986,7 +986,7 @@ public:
|
||||
AFTER_GL_CALL;
|
||||
}
|
||||
|
||||
void fClearColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a) {
|
||||
void fClearColor(GLfloat r, GLfloat g, GLfloat b, GLfloat a) {
|
||||
BEFORE_GL_CALL;
|
||||
mSymbols.fClearColor(r, g, b, a);
|
||||
AFTER_GL_CALL;
|
||||
|
@ -49,7 +49,7 @@ struct GLContextSymbols
|
||||
PFNGLBINDTEXTUREPROC fBindTexture;
|
||||
typedef void (GLAPIENTRY * PFNGLBINDVERTEXARRAYPROC) (GLuint array);
|
||||
PFNGLBINDVERTEXARRAYPROC fBindVertexArray;
|
||||
typedef void (GLAPIENTRY * PFNGLBLENDCOLORPROC) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
|
||||
typedef void (GLAPIENTRY * PFNGLBLENDCOLORPROC) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha);
|
||||
PFNGLBLENDCOLORPROC fBlendColor;
|
||||
typedef void (GLAPIENTRY * PFNGLBLENDEQUATIONPROC) (GLenum mode);
|
||||
PFNGLBLENDEQUATIONPROC fBlendEquation;
|
||||
@ -73,7 +73,7 @@ struct GLContextSymbols
|
||||
PFNGLCLEARBUFFERIVPROC fClearBufferiv;
|
||||
typedef void (GLAPIENTRY * PFNGLCLEARBUFFERUIVPROC) (GLenum buffer, GLint drawbuffer, const GLuint* value);
|
||||
PFNGLCLEARBUFFERUIVPROC fClearBufferuiv;
|
||||
typedef void (GLAPIENTRY * PFNGLCLEARCOLORPROC) (GLclampf, GLclampf, GLclampf, GLclampf);
|
||||
typedef void (GLAPIENTRY * PFNGLCLEARCOLORPROC) (GLfloat, GLfloat, GLfloat, GLfloat);
|
||||
PFNGLCLEARCOLORPROC fClearColor;
|
||||
typedef void (GLAPIENTRY * PFNGLCLEARSTENCILPROC) (GLint);
|
||||
PFNGLCLEARSTENCILPROC fClearStencil;
|
||||
|
@ -67,6 +67,9 @@ BasicCompositor::BasicCompositor(nsIWidget *aWidget)
|
||||
{
|
||||
MOZ_COUNT_CTOR(BasicCompositor);
|
||||
SetBackend(LayersBackend::LAYERS_BASIC);
|
||||
|
||||
mMaxTextureSize =
|
||||
Factory::GetMaxSurfaceSize(gfxPlatform::GetPlatform()->GetContentBackend());
|
||||
}
|
||||
|
||||
BasicCompositor::~BasicCompositor()
|
||||
@ -74,6 +77,12 @@ BasicCompositor::~BasicCompositor()
|
||||
MOZ_COUNT_DTOR(BasicCompositor);
|
||||
}
|
||||
|
||||
int32_t
|
||||
BasicCompositor::GetMaxTextureSize() const
|
||||
{
|
||||
return mMaxTextureSize;
|
||||
}
|
||||
|
||||
void
|
||||
BasicCompositingRenderTarget::BindRenderTarget()
|
||||
{
|
||||
|
@ -103,7 +103,7 @@ public:
|
||||
|
||||
virtual bool SupportsPartialTextureUpdate() MOZ_OVERRIDE { return true; }
|
||||
virtual bool CanUseCanvasLayerForSize(const gfx::IntSize &aSize) MOZ_OVERRIDE { return true; }
|
||||
virtual int32_t GetMaxTextureSize() const MOZ_OVERRIDE { return INT32_MAX; }
|
||||
virtual int32_t GetMaxTextureSize() const MOZ_OVERRIDE;
|
||||
virtual void SetDestinationSurfaceSize(const gfx::IntSize& aSize) MOZ_OVERRIDE { }
|
||||
|
||||
virtual void SetScreenRenderOffset(const ScreenPoint& aOffset) MOZ_OVERRIDE {
|
||||
@ -140,6 +140,8 @@ private:
|
||||
|
||||
gfx::IntRect mInvalidRect;
|
||||
nsIntRegion mInvalidRegion;
|
||||
|
||||
uint32_t mMaxTextureSize;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
|
@ -219,6 +219,12 @@ ClientTiledPaintedLayer::IsScrollingOnCompositor(const FrameMetrics& aParentMetr
|
||||
bool
|
||||
ClientTiledPaintedLayer::UseFastPath()
|
||||
{
|
||||
// The fast path doesn't allow rendering at low resolution. It will draw the low-res
|
||||
// area at full resolution and cause OOM.
|
||||
if (gfxPrefs::UseLowPrecisionBuffer()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LayerMetricsWrapper scrollAncestor;
|
||||
GetAncestorLayers(&scrollAncestor, nullptr);
|
||||
if (!scrollAncestor) {
|
||||
@ -227,16 +233,35 @@ ClientTiledPaintedLayer::UseFastPath()
|
||||
const FrameMetrics& parentMetrics = scrollAncestor.Metrics();
|
||||
|
||||
bool multipleTransactionsNeeded = gfxPlatform::GetPlatform()->UseProgressivePaint()
|
||||
|| gfxPrefs::UseLowPrecisionBuffer()
|
||||
|| !parentMetrics.GetCriticalDisplayPort().IsEmpty();
|
||||
bool isFixed = GetIsFixedPosition() || GetParent()->GetIsFixedPosition();
|
||||
bool isScrollable = parentMetrics.IsScrollable();
|
||||
|
||||
return !multipleTransactionsNeeded || isFixed || !isScrollable
|
||||
#if !defined(MOZ_WIDGET_ANDROID) || defined(MOZ_ANDROID_APZ)
|
||||
|| !IsScrollingOnCompositor(parentMetrics)
|
||||
return !multipleTransactionsNeeded || isFixed || !isScrollable;
|
||||
}
|
||||
|
||||
bool
|
||||
ClientTiledPaintedLayer::UseProgressiveDraw() {
|
||||
// Don't draw progressively in a reftest scenario (that's what the HasShadowTarget() check is for).
|
||||
if (!gfxPlatform::GetPlatform()->UseProgressivePaint() || ClientManager()->HasShadowTarget()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// XXX We probably want to disable progressive drawing for non active APZ layers in the future
|
||||
// but we should wait for a proper test case before making this change.
|
||||
|
||||
#if 0 //!defined(MOZ_WIDGET_ANDROID) || defined(MOZ_ANDROID_APZ)
|
||||
LayerMetricsWrapper scrollAncestor;
|
||||
GetAncestorLayers(&scrollAncestor, nullptr);
|
||||
if (!scrollAncestor) {
|
||||
return true;
|
||||
}
|
||||
const FrameMetrics& parentMetrics = scrollAncestor.Metrics();
|
||||
|
||||
return !IsScrollingOnCompositor(parentMetrics);
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
;
|
||||
}
|
||||
|
||||
bool
|
||||
@ -251,10 +276,8 @@ ClientTiledPaintedLayer::RenderHighPrecision(nsIntRegion& aInvalidRegion,
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only draw progressively when the resolution is unchanged, and we're not
|
||||
// in a reftest scenario (that's what the HasShadowManager() check is for).
|
||||
if (gfxPlatform::GetPlatform()->UseProgressivePaint() &&
|
||||
!ClientManager()->HasShadowTarget() &&
|
||||
// Only draw progressively when the resolution is unchanged
|
||||
if (UseProgressiveDraw() &&
|
||||
mContentClient->mTiledBuffer.GetFrameResolution() == mPaintData.mResolution) {
|
||||
// Store the old valid region, then clear it before painting.
|
||||
// We clip the old valid region to the visible region, as it only gets
|
||||
@ -418,36 +441,20 @@ ClientTiledPaintedLayer::RenderLayer()
|
||||
ToClientLayer(GetMaskLayer())->RenderLayer();
|
||||
}
|
||||
|
||||
// For more complex cases we need to calculate a bunch of metrics before we
|
||||
// can do the paint.
|
||||
BeginPaint();
|
||||
if (mPaintData.mPaintFinished) {
|
||||
return;
|
||||
}
|
||||
|
||||
// In some cases we can take a fast path and just be done with it.
|
||||
if (UseFastPath()) {
|
||||
TILING_LOG("TILING %p: Taking fast-path\n", this);
|
||||
mValidRegion = neededRegion;
|
||||
|
||||
// Make sure that tiles that fall outside of the visible region or outside of the
|
||||
// critical displayport are discarded on the first update. Also make sure that we
|
||||
// only draw stuff inside the critical displayport on the first update.
|
||||
if (!mPaintData.mCriticalDisplayPort.IsEmpty()) {
|
||||
mValidRegion.And(mValidRegion, LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort));
|
||||
invalidRegion.And(invalidRegion, LayerIntRect::ToUntyped(mPaintData.mCriticalDisplayPort));
|
||||
}
|
||||
|
||||
if (invalidRegion.IsEmpty()) {
|
||||
EndPaint();
|
||||
return;
|
||||
}
|
||||
|
||||
mContentClient->mTiledBuffer.SetFrameResolution(mPaintData.mResolution);
|
||||
mContentClient->mTiledBuffer.PaintThebes(mValidRegion, invalidRegion, callback, data);
|
||||
ClientManager()->Hold(this);
|
||||
mContentClient->UseTiledLayerBuffer(TiledContentClient::TILED_BUFFER);
|
||||
EndPaint();
|
||||
return;
|
||||
}
|
||||
|
||||
// For more complex cases we need to calculate a bunch of metrics before we
|
||||
// can do the paint.
|
||||
BeginPaint();
|
||||
if (mPaintData.mPaintFinished) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -106,6 +106,13 @@ private:
|
||||
*/
|
||||
bool IsScrollingOnCompositor(const FrameMetrics& aParentMetrics);
|
||||
|
||||
/**
|
||||
* Check if we should use progressive draw on this layer. We will
|
||||
* disable progressive draw based on a preference or if the layer
|
||||
* is not being scrolled.
|
||||
*/
|
||||
bool UseProgressiveDraw();
|
||||
|
||||
/**
|
||||
* Helper function to do the high-precision paint.
|
||||
* This function returns true if it updated the paint buffer.
|
||||
|
@ -745,7 +745,7 @@ BufferTextureClient::AllocateForSurface(gfx::IntSize aSize, TextureAllocationFla
|
||||
}
|
||||
|
||||
uint32_t bufSize = ImageDataSerializer::ComputeMinBufferSize(aSize, mFormat);
|
||||
if (!Allocate(bufSize)) {
|
||||
if (!bufSize || !Allocate(bufSize)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -547,7 +547,7 @@ static struct lutmABType *read_tag_lutmABType(struct mem_source *src, struct tag
|
||||
}
|
||||
|
||||
num_in_channels = read_u8(src, offset + 8);
|
||||
num_out_channels = read_u8(src, offset + 8);
|
||||
num_out_channels = read_u8(src, offset + 9);
|
||||
if (num_in_channels > MAX_CHANNELS || num_out_channels > MAX_CHANNELS)
|
||||
return NULL;
|
||||
|
||||
|
@ -400,6 +400,25 @@ TestFiniteGfx()
|
||||
return true;
|
||||
}
|
||||
|
||||
// We want to test nsRect values that are still in range but where
|
||||
// the implementation is at risk of overflowing
|
||||
template <class RectType>
|
||||
static bool
|
||||
TestBug1135677()
|
||||
{
|
||||
RectType rect1(1073741344, 1073741344, 1073756696, 1073819936);
|
||||
RectType rect2(1073741820, 1073741820, 14400, 77640);
|
||||
RectType dest;
|
||||
|
||||
dest = rect1.Intersect(rect2);
|
||||
|
||||
EXPECT_TRUE(dest.x == 1073741820 && dest.y == 1073741820 &&
|
||||
dest.width == 14400 && dest.height == 77640) <<
|
||||
"[1] Operation should not overflow internally.";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
TEST(Gfx, nsRect) {
|
||||
TestConstructors<nsRect>();
|
||||
TestEqualityOperator<nsRect>();
|
||||
@ -407,6 +426,7 @@ TEST(Gfx, nsRect) {
|
||||
TestIntersects<nsRect>();
|
||||
TestIntersection<nsRect>();
|
||||
TestUnion<nsRect>();
|
||||
TestBug1135677<nsRect>();
|
||||
}
|
||||
|
||||
TEST(Gfx, nsIntRect) {
|
||||
@ -416,6 +436,7 @@ TEST(Gfx, nsIntRect) {
|
||||
TestIntersects<nsIntRect>();
|
||||
TestIntersection<nsIntRect>();
|
||||
TestUnion<nsIntRect>();
|
||||
TestBug1135677<nsIntRect>();
|
||||
}
|
||||
|
||||
TEST(Gfx, gfxRect) {
|
||||
@ -425,5 +446,6 @@ TEST(Gfx, gfxRect) {
|
||||
TestIntersects<gfxRect>();
|
||||
TestIntersection<gfxRect>();
|
||||
TestUnion<gfxRect>();
|
||||
TestBug1135677<gfxRect>();
|
||||
TestFiniteGfx();
|
||||
}
|
||||
|
@ -312,7 +312,7 @@ private:
|
||||
DECL_GFX_PREF(Once, "layers.d3d11.force-warp", LayersD3D11ForceWARP, bool, false);
|
||||
DECL_GFX_PREF(Once, "layers.prefer-d3d9", LayersPreferD3D9, bool, false);
|
||||
DECL_GFX_PREF(Once, "layers.prefer-opengl", LayersPreferOpenGL, bool, false);
|
||||
DECL_GFX_PREF(Once, "layers.progressive-paint", ProgressivePaintDoNotUseDirectly, bool, false);
|
||||
DECL_GFX_PREF(Live, "layers.progressive-paint", ProgressivePaintDoNotUseDirectly, bool, false);
|
||||
DECL_GFX_PREF(Once, "layers.uniformity-info", UniformityInfo, bool, false);
|
||||
DECL_GFX_PREF(Once, "layers.gralloc.disable", DisableGralloc, bool, false);
|
||||
|
||||
|
@ -64,12 +64,18 @@ struct IconURIParams
|
||||
int32_t iconState;
|
||||
};
|
||||
|
||||
struct NullPrincipalURIParams
|
||||
{
|
||||
// Purposefully empty. Null principal URIs do not round-trip.
|
||||
};
|
||||
|
||||
union URIParams
|
||||
{
|
||||
SimpleURIParams;
|
||||
StandardURLParams;
|
||||
JARURIParams;
|
||||
IconURIParams;
|
||||
NullPrincipalURIParams;
|
||||
};
|
||||
|
||||
union OptionalURIParams
|
||||
|
@ -13,6 +13,7 @@
|
||||
#include "nsID.h"
|
||||
#include "nsJARURI.h"
|
||||
#include "nsIIconURI.h"
|
||||
#include "nsNullPrincipalURI.h"
|
||||
#include "nsNetCID.h"
|
||||
#include "nsNetUtil.h"
|
||||
#include "nsThreadUtils.h"
|
||||
@ -41,7 +42,7 @@ SerializeURI(nsIURI* aURI,
|
||||
|
||||
nsCOMPtr<nsIIPCSerializableURI> serializable = do_QueryInterface(aURI);
|
||||
if (!serializable) {
|
||||
MOZ_CRASH("All IPDL URIs must be serializable scheme!");
|
||||
MOZ_CRASH("All IPDL URIs must be serializable!");
|
||||
}
|
||||
|
||||
serializable->Serialize(aParams);
|
||||
@ -90,6 +91,10 @@ DeserializeURI(const URIParams& aParams)
|
||||
serializable = do_CreateInstance(kIconURICID);
|
||||
break;
|
||||
|
||||
case URIParams::TNullPrincipalURIParams:
|
||||
serializable = new nsNullPrincipalURI();
|
||||
break;
|
||||
|
||||
default:
|
||||
MOZ_CRASH("Unknown params!");
|
||||
}
|
||||
|
@ -355,7 +355,7 @@ class JS_FRIEND_API(BaseProxyHandler)
|
||||
* to add an override in CrossCompartmentWrapper. If you don't, you risk
|
||||
* compartment mismatches. See bug 945826 comment 0.
|
||||
*/
|
||||
class JS_PUBLIC_API(DirectProxyHandler) : public BaseProxyHandler
|
||||
class JS_FRIEND_API(DirectProxyHandler) : public BaseProxyHandler
|
||||
{
|
||||
public:
|
||||
explicit MOZ_CONSTEXPR DirectProxyHandler(const void *aFamily, bool aHasPrototype = false,
|
||||
|
@ -29,7 +29,7 @@ const Class SymbolObject::class_ = {
|
||||
};
|
||||
|
||||
SymbolObject *
|
||||
SymbolObject::create(JSContext *cx, JS::Symbol *symbol)
|
||||
SymbolObject::create(JSContext *cx, JS::HandleSymbol symbol)
|
||||
{
|
||||
JSObject *obj = NewBuiltinClassInstance(cx, &class_);
|
||||
if (!obj)
|
||||
|
@ -28,7 +28,7 @@ class SymbolObject : public NativeObject
|
||||
* Creates a new Symbol object boxing the given primitive Symbol. The
|
||||
* object's [[Prototype]] is determined from context.
|
||||
*/
|
||||
static SymbolObject *create(JSContext *cx, JS::Symbol *symbol);
|
||||
static SymbolObject *create(JSContext *cx, JS::HandleSymbol symbol);
|
||||
|
||||
JS::Symbol *unbox() const {
|
||||
return getFixedSlot(PRIMITIVE_VALUE_SLOT).toSymbol();
|
||||
|
@ -183,6 +183,18 @@ GetBuildConfiguration(JSContext *cx, unsigned argc, jsval *vp)
|
||||
if (!JS_SetProperty(cx, info, "intl-api", value))
|
||||
return false;
|
||||
|
||||
#if defined(XP_WIN)
|
||||
value = BooleanValue(false);
|
||||
#elif defined(SOLARIS)
|
||||
value = BooleanValue(false);
|
||||
#elif defined(XP_UNIX)
|
||||
value = BooleanValue(true);
|
||||
#else
|
||||
value = BooleanValue(false);
|
||||
#endif
|
||||
if (!JS_SetProperty(cx, info, "mapped-array-buffer", value))
|
||||
return false;
|
||||
|
||||
args.rval().setObject(*info);
|
||||
return true;
|
||||
}
|
||||
|
@ -2568,7 +2568,7 @@ Parser<ParseHandler>::functionArgsAndBodyGeneric(Node pn, HandleFunction fun, Fu
|
||||
}
|
||||
funbox->bufEnd = pos().begin + 1;
|
||||
} else {
|
||||
#if not JS_HAS_EXPR_CLOSURES
|
||||
#if !JS_HAS_EXPR_CLOSURES
|
||||
MOZ_ASSERT(kind == Arrow);
|
||||
#endif
|
||||
if (tokenStream.hadError())
|
||||
|
@ -1612,8 +1612,8 @@ RegExpCompiler::Assemble(JSContext *cx,
|
||||
return RegExpCode();
|
||||
|
||||
if (reg_exp_too_big_) {
|
||||
JS_ReportError(cx, "regexp too big");
|
||||
code.destroy();
|
||||
JS_ReportError(cx, "regexp too big");
|
||||
return RegExpCode();
|
||||
}
|
||||
|
||||
|
@ -33,6 +33,7 @@
|
||||
|
||||
#include "jit/arm/Simulator-arm.h"
|
||||
#include "jit/mips/Simulator-mips.h"
|
||||
#include "js/GCAPI.h"
|
||||
#include "js/HashTable.h"
|
||||
#include "js/Vector.h"
|
||||
|
||||
@ -250,8 +251,11 @@ class ExecutableAllocator {
|
||||
|
||||
void releasePoolPages(ExecutablePool *pool) {
|
||||
MOZ_ASSERT(pool->m_allocation.pages);
|
||||
if (destroyCallback)
|
||||
if (destroyCallback) {
|
||||
// Do not allow GC during the page release callback.
|
||||
JS::AutoSuppressGCAnalysis nogc;
|
||||
destroyCallback(pool->m_allocation.pages, pool->m_allocation.size);
|
||||
}
|
||||
systemRelease(pool->m_allocation);
|
||||
MOZ_ASSERT(m_pools.initialized());
|
||||
m_pools.remove(m_pools.lookup(pool)); // this asserts if |pool| is not in m_pools
|
||||
|
@ -34,7 +34,7 @@ OptimizationInfo::initNormalOptimizationInfo()
|
||||
loopUnrolling_ = true;
|
||||
autoTruncate_ = true;
|
||||
sink_ = true;
|
||||
registerAllocator_ = RegisterAllocator_LSRA;
|
||||
registerAllocator_ = RegisterAllocator_Backtracking;
|
||||
|
||||
inlineMaxTotalBytecodeLength_ = 1000;
|
||||
inliningMaxCallerBytecodeLength_ = 10000;
|
||||
|
@ -145,6 +145,14 @@ JS_NewObjectWithUniqueType(JSContext *cx, const JSClass *clasp, HandleObject pro
|
||||
return obj;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSObject *)
|
||||
JS_NewObjectWithoutMetadata(JSContext *cx, const JSClass *clasp, JS::Handle<JSObject*> proto)
|
||||
{
|
||||
// Use an AutoEnterAnalysis to suppress invocation of the metadata callback.
|
||||
AutoEnterAnalysis enter(cx);
|
||||
return JS_NewObjectWithGivenProto(cx, clasp, proto);
|
||||
}
|
||||
|
||||
JS_FRIEND_API(JSPrincipals *)
|
||||
JS_GetCompartmentPrincipals(JSCompartment *compartment)
|
||||
{
|
||||
|
@ -60,6 +60,13 @@ extern JS_FRIEND_API(JSObject *)
|
||||
JS_NewObjectWithUniqueType(JSContext *cx, const JSClass *clasp, JS::HandleObject proto,
|
||||
JS::HandleObject parent);
|
||||
|
||||
// Allocate an object in exactly the same way as JS_NewObjectWithGivenProto, but
|
||||
// without invoking the metadata callback on it. This allows creation of
|
||||
// internal bookkeeping objects that are guaranteed to not have metadata
|
||||
// attached to them.
|
||||
extern JS_FRIEND_API(JSObject *)
|
||||
JS_NewObjectWithoutMetadata(JSContext *cx, const JSClass *clasp, JS::Handle<JSObject*> proto);
|
||||
|
||||
extern JS_FRIEND_API(uint32_t)
|
||||
JS_ObjectCountDynamicSlots(JS::HandleObject obj);
|
||||
|
||||
@ -144,6 +151,24 @@ extern JS_FRIEND_API(JSObject *)
|
||||
JS_CloneObject(JSContext *cx, JS::HandleObject obj, JS::HandleObject proto,
|
||||
JS::HandleObject parent);
|
||||
|
||||
/*
|
||||
* Copy the own properties of src to dst in a fast way. src and dst must both
|
||||
* be native and must be in the compartment of cx. They must have the same
|
||||
* class, the same parent, and the same prototype. Class reserved slots will
|
||||
* NOT be copied.
|
||||
*
|
||||
* dst must not have any properties on it before this function is called.
|
||||
*
|
||||
* src must have been allocated via JS_NewObjectWithoutMetadata so that we can
|
||||
* be sure it has no metadata that needs copying to dst. This also means that
|
||||
* dst needs to have the compartment global as its parent. This function will
|
||||
* preserve the existing metadata on dst, if any.
|
||||
*/
|
||||
extern JS_FRIEND_API(bool)
|
||||
JS_InitializePropertiesFromCompatibleNativeObject(JSContext *cx,
|
||||
JS::HandleObject dst,
|
||||
JS::HandleObject src);
|
||||
|
||||
extern JS_FRIEND_API(JSString *)
|
||||
JS_BasicObjectToString(JSContext *cx, JS::HandleObject obj);
|
||||
|
||||
|
@ -1267,11 +1267,16 @@ js::NewObjectWithGivenTaggedProto(ExclusiveContext *cxArg, const Class *clasp,
|
||||
|
||||
/*
|
||||
* Default parent to the parent of the prototype, which was set from
|
||||
* the parent of the prototype's constructor.
|
||||
* the parent of the prototype's constructor. If there is no
|
||||
* prototype, use the global.
|
||||
*/
|
||||
RootedObject parent(cxArg, parentArg);
|
||||
if (!parent && proto.isObject())
|
||||
parent = proto.toObject()->getParent();
|
||||
if (!parent) {
|
||||
if (proto.isObject())
|
||||
parent = proto.toObject()->getParent();
|
||||
else
|
||||
parent = cxArg->global();
|
||||
}
|
||||
|
||||
RootedObject obj(cxArg, NewObject(cxArg, group, parent, allocKind, newKind));
|
||||
if (!obj)
|
||||
@ -1864,7 +1869,8 @@ js::DeepCloneObjectLiteral(JSContext *cx, HandleNativeObject obj, NewObjectKind
|
||||
MOZ_ASSERT(!obj->hasPrivate());
|
||||
RootedShape shape(cx, obj->lastProperty());
|
||||
size_t span = shape->slotSpan();
|
||||
clone->setLastProperty(cx, shape);
|
||||
if (!clone->setLastProperty(cx, shape))
|
||||
return nullptr;
|
||||
for (size_t i = 0; i < span; i++) {
|
||||
v = obj->getSlot(i);
|
||||
if (v.isObject()) {
|
||||
@ -1894,6 +1900,58 @@ js::DeepCloneObjectLiteral(JSContext *cx, HandleNativeObject obj, NewObjectKind
|
||||
return clone;
|
||||
}
|
||||
|
||||
static bool
|
||||
InitializePropertiesFromCompatibleNativeObject(JSContext *cx,
|
||||
HandleNativeObject dst,
|
||||
HandleNativeObject src)
|
||||
{
|
||||
assertSameCompartment(cx, src, dst);
|
||||
MOZ_ASSERT(src->getClass() == dst->getClass());
|
||||
MOZ_ASSERT(src->getParent() == dst->getParent());
|
||||
MOZ_ASSERT(dst->getParent() == cx->global());
|
||||
MOZ_ASSERT(src->getProto() == dst->getProto());
|
||||
MOZ_ASSERT(dst->lastProperty()->getObjectFlags() == 0);
|
||||
MOZ_ASSERT(!src->getMetadata());
|
||||
MOZ_ASSERT(!src->isSingleton());
|
||||
|
||||
// Save the dst metadata, if any, before we start messing with its shape.
|
||||
RootedObject dstMetadata(cx, dst->getMetadata());
|
||||
|
||||
if (!dst->ensureElements(cx, src->getDenseInitializedLength()))
|
||||
return false;
|
||||
|
||||
uint32_t initialized = src->getDenseInitializedLength();
|
||||
for (uint32_t i = 0; i < initialized; ++i) {
|
||||
dst->setDenseInitializedLength(i + 1);
|
||||
dst->initDenseElement(i, src->getDenseElement(i));
|
||||
}
|
||||
|
||||
MOZ_ASSERT(!src->hasPrivate());
|
||||
RootedShape shape(cx, src->lastProperty());
|
||||
size_t span = shape->slotSpan();
|
||||
if (!dst->setLastProperty(cx, shape))
|
||||
return false;
|
||||
for (size_t i = JSCLASS_RESERVED_SLOTS(src->getClass()); i < span; i++)
|
||||
dst->setSlot(i, src->getSlot(i));
|
||||
|
||||
if (dstMetadata) {
|
||||
if (!js::SetObjectMetadata(cx, dst, dstMetadata))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
JS_FRIEND_API(bool)
|
||||
JS_InitializePropertiesFromCompatibleNativeObject(JSContext *cx,
|
||||
HandleObject dst,
|
||||
HandleObject src)
|
||||
{
|
||||
return InitializePropertiesFromCompatibleNativeObject(cx,
|
||||
dst.as<NativeObject>(),
|
||||
src.as<NativeObject>());
|
||||
}
|
||||
|
||||
template<XDRMode mode>
|
||||
bool
|
||||
js::XDRObjectLiteral(XDRState<mode> *xdr, MutableHandleNativeObject obj)
|
||||
@ -3556,7 +3614,8 @@ js::PrimitiveToObject(JSContext *cx, const Value &v)
|
||||
if (v.isBoolean())
|
||||
return BooleanObject::create(cx, v.toBoolean());
|
||||
MOZ_ASSERT(v.isSymbol());
|
||||
return SymbolObject::create(cx, v.toSymbol());
|
||||
RootedSymbol symbol(cx, v.toSymbol());
|
||||
return SymbolObject::create(cx, symbol);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -494,6 +494,11 @@ if CONFIG['_MSC_VER']:
|
||||
# Prevent floating point errors caused by VC++ optimizations
|
||||
# XXX We should add this to CXXFLAGS, too?
|
||||
CFLAGS += ['-fp:precise']
|
||||
# C4805 warns mixing bool with other integral types in computation.
|
||||
# But given the conversion from bool is specified, and this is a
|
||||
# pattern widely used in code in js/src, suppress this warning here.
|
||||
CXXFLAGS += ['-wd4805']
|
||||
CXXFLAGS += ['-we4067', '-we4258', '-we4275']
|
||||
|
||||
if CONFIG['OS_ARCH'] not in ('WINNT', 'HP-UX'):
|
||||
OS_LIBS += [
|
||||
|
@ -36,5 +36,6 @@ function test() {
|
||||
assertThrows(() => createMappedArrayBuffer("empty.txt", 0, 8), Error);
|
||||
}
|
||||
|
||||
test();
|
||||
if (getBuildConfiguration()["mapped-array-buffer"])
|
||||
test();
|
||||
reportCompare(0, 0, 'ok');
|
||||
|
@ -252,7 +252,7 @@ class ObjectGroup : public gc::TenuredCell
|
||||
}
|
||||
|
||||
TypeNewScript *anyNewScript();
|
||||
void detachNewScript(bool writeBarrier);
|
||||
void detachNewScript(bool writeBarrier, ObjectGroup *replacement);
|
||||
|
||||
ObjectGroupFlags flagsDontCheckGeneration() {
|
||||
return flags_;
|
||||
@ -480,7 +480,7 @@ class ObjectGroup : public gc::TenuredCell
|
||||
void setFlags(ExclusiveContext *cx, ObjectGroupFlags flags);
|
||||
void markUnknown(ExclusiveContext *cx);
|
||||
void maybeClearNewScriptOnOOM();
|
||||
void clearNewScript(ExclusiveContext *cx);
|
||||
void clearNewScript(ExclusiveContext *cx, ObjectGroup *replacement = nullptr);
|
||||
bool isPropertyNonData(jsid id);
|
||||
bool isPropertyNonWritable(jsid id);
|
||||
|
||||
|
@ -2765,7 +2765,7 @@ ObjectGroup::anyNewScript()
|
||||
}
|
||||
|
||||
void
|
||||
ObjectGroup::detachNewScript(bool writeBarrier)
|
||||
ObjectGroup::detachNewScript(bool writeBarrier, ObjectGroup *replacement)
|
||||
{
|
||||
// Clear the TypeNewScript from this ObjectGroup and, if it has been
|
||||
// analyzed, remove it from the newObjectGroups table so that it will not be
|
||||
@ -2775,8 +2775,16 @@ ObjectGroup::detachNewScript(bool writeBarrier)
|
||||
MOZ_ASSERT(newScript);
|
||||
|
||||
if (newScript->analyzed()) {
|
||||
newScript->function()->compartment()->objectGroups.removeDefaultNewGroup(nullptr, proto(),
|
||||
newScript->function());
|
||||
ObjectGroupCompartment &objectGroups = newScript->function()->compartment()->objectGroups;
|
||||
if (replacement) {
|
||||
MOZ_ASSERT(replacement->newScript()->function() == newScript->function());
|
||||
objectGroups.replaceDefaultNewGroup(nullptr, proto(), newScript->function(),
|
||||
replacement);
|
||||
} else {
|
||||
objectGroups.removeDefaultNewGroup(nullptr, proto(), newScript->function());
|
||||
}
|
||||
} else {
|
||||
MOZ_ASSERT(!replacement);
|
||||
}
|
||||
|
||||
if (this->newScript())
|
||||
@ -2800,13 +2808,13 @@ ObjectGroup::maybeClearNewScriptOnOOM()
|
||||
addFlags(OBJECT_FLAG_NEW_SCRIPT_CLEARED);
|
||||
|
||||
// This method is called during GC sweeping, so don't trigger pre barriers.
|
||||
detachNewScript(/* writeBarrier = */ false);
|
||||
detachNewScript(/* writeBarrier = */ false, nullptr);
|
||||
|
||||
js_delete(newScript);
|
||||
}
|
||||
|
||||
void
|
||||
ObjectGroup::clearNewScript(ExclusiveContext *cx)
|
||||
ObjectGroup::clearNewScript(ExclusiveContext *cx, ObjectGroup *replacement /* = nullptr*/)
|
||||
{
|
||||
TypeNewScript *newScript = anyNewScript();
|
||||
if (!newScript)
|
||||
@ -2814,15 +2822,17 @@ ObjectGroup::clearNewScript(ExclusiveContext *cx)
|
||||
|
||||
AutoEnterAnalysis enter(cx);
|
||||
|
||||
// Invalidate any Ion code constructing objects of this type.
|
||||
setFlags(cx, OBJECT_FLAG_NEW_SCRIPT_CLEARED);
|
||||
if (!replacement) {
|
||||
// Invalidate any Ion code constructing objects of this type.
|
||||
setFlags(cx, OBJECT_FLAG_NEW_SCRIPT_CLEARED);
|
||||
|
||||
// Mark the constructing function as having its 'new' script cleared, so we
|
||||
// will not try to construct another one later.
|
||||
if (!newScript->function()->setNewScriptCleared(cx))
|
||||
cx->recoverFromOutOfMemory();
|
||||
// Mark the constructing function as having its 'new' script cleared, so we
|
||||
// will not try to construct another one later.
|
||||
if (!newScript->function()->setNewScriptCleared(cx))
|
||||
cx->recoverFromOutOfMemory();
|
||||
}
|
||||
|
||||
detachNewScript(/* writeBarrier = */ true);
|
||||
detachNewScript(/* writeBarrier = */ true, replacement);
|
||||
|
||||
if (cx->isJSContext()) {
|
||||
bool found = newScript->rollbackPartiallyInitializedObjects(cx->asJSContext(), this);
|
||||
@ -3268,6 +3278,33 @@ TypeNewScript::make(JSContext *cx, ObjectGroup *group, JSFunction *fun)
|
||||
gc::TraceTypeNewScript(group);
|
||||
}
|
||||
|
||||
// Make a TypeNewScript with the same initializer list as |newScript| but with
|
||||
// a new template object.
|
||||
/* static */ TypeNewScript *
|
||||
TypeNewScript::makeNativeVersion(JSContext *cx, TypeNewScript *newScript,
|
||||
PlainObject *templateObject)
|
||||
{
|
||||
MOZ_ASSERT(cx->zone()->types.activeAnalysis);
|
||||
|
||||
ScopedJSDeletePtr<TypeNewScript> nativeNewScript(cx->new_<TypeNewScript>());
|
||||
if (!nativeNewScript)
|
||||
return nullptr;
|
||||
|
||||
nativeNewScript->function_ = newScript->function();
|
||||
nativeNewScript->templateObject_ = templateObject;
|
||||
|
||||
Initializer *cursor = newScript->initializerList;
|
||||
while (cursor->kind != Initializer::DONE) { cursor++; }
|
||||
size_t initializerLength = cursor - newScript->initializerList + 1;
|
||||
|
||||
nativeNewScript->initializerList = cx->zone()->pod_calloc<Initializer>(initializerLength);
|
||||
if (!nativeNewScript->initializerList)
|
||||
return nullptr;
|
||||
PodCopy(nativeNewScript->initializerList, newScript->initializerList, initializerLength);
|
||||
|
||||
return nativeNewScript.forget();
|
||||
}
|
||||
|
||||
size_t
|
||||
TypeNewScript::sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const
|
||||
{
|
||||
|
@ -827,8 +827,6 @@ class TypeNewScript
|
||||
|
||||
private:
|
||||
// Scripted function which this information was computed for.
|
||||
// If instances of the associated group are created without calling
|
||||
// 'new' on this function, the new script information is cleared.
|
||||
HeapPtrFunction function_;
|
||||
|
||||
// Any preliminary objects with the type. The analyses are not performed
|
||||
@ -902,6 +900,8 @@ class TypeNewScript
|
||||
bool rollbackPartiallyInitializedObjects(JSContext *cx, ObjectGroup *group);
|
||||
|
||||
static void make(JSContext *cx, ObjectGroup *group, JSFunction *fun);
|
||||
static TypeNewScript *makeNativeVersion(JSContext *cx, TypeNewScript *newScript,
|
||||
PlainObject *templateObject);
|
||||
|
||||
size_t sizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
|
||||
};
|
||||
|
@ -35,6 +35,9 @@ UnboxedLayout::trace(JSTracer *trc)
|
||||
|
||||
if (nativeShape_)
|
||||
MarkShape(trc, &nativeShape_, "unboxed_layout_nativeShape");
|
||||
|
||||
if (replacementNewGroup_)
|
||||
MarkObjectGroup(trc, &replacementNewGroup_, "unboxed_layout_replacementNewGroup");
|
||||
}
|
||||
|
||||
size_t
|
||||
@ -172,18 +175,49 @@ UnboxedPlainObject::trace(JSTracer *trc, JSObject *obj)
|
||||
/* static */ bool
|
||||
UnboxedLayout::makeNativeGroup(JSContext *cx, ObjectGroup *group)
|
||||
{
|
||||
AutoEnterAnalysis enter(cx);
|
||||
|
||||
UnboxedLayout &layout = group->unboxedLayout();
|
||||
Rooted<TaggedProto> proto(cx, group->proto());
|
||||
|
||||
MOZ_ASSERT(!layout.nativeGroup());
|
||||
|
||||
// Immediately clear any new script on the group, as
|
||||
// rollbackPartiallyInitializedObjects() will be confused by the type
|
||||
// changes we make later on.
|
||||
group->clearNewScript(cx);
|
||||
// Immediately clear any new script on the group. This is done by replacing
|
||||
// the existing new script with one for a replacement default new group.
|
||||
// This is done so that the size of the replacment group's objects is the
|
||||
// same as that for the unboxed group, so that we do not see polymorphic
|
||||
// slot accesses later on for sites that see converted objects from this
|
||||
// group and objects that were allocated using the replacement new group.
|
||||
RootedObjectGroup replacementNewGroup(cx);
|
||||
if (layout.newScript()) {
|
||||
replacementNewGroup = ObjectGroupCompartment::makeGroup(cx, &PlainObject::class_, proto);
|
||||
if (!replacementNewGroup)
|
||||
return false;
|
||||
|
||||
AutoEnterAnalysis enter(cx);
|
||||
PlainObject *templateObject = NewObjectWithGroup<PlainObject>(cx, replacementNewGroup,
|
||||
cx->global(), layout.getAllocKind(),
|
||||
MaybeSingletonObject);
|
||||
if (!templateObject)
|
||||
return false;
|
||||
|
||||
Rooted<TaggedProto> proto(cx, group->proto());
|
||||
for (size_t i = 0; i < layout.properties().length(); i++) {
|
||||
const UnboxedLayout::Property &property = layout.properties()[i];
|
||||
if (!templateObject->addDataProperty(cx, NameToId(property.name), i, JSPROP_ENUMERATE))
|
||||
return false;
|
||||
MOZ_ASSERT(templateObject->slotSpan() == i + 1);
|
||||
MOZ_ASSERT(!templateObject->inDictionaryMode());
|
||||
}
|
||||
|
||||
TypeNewScript *replacementNewScript =
|
||||
TypeNewScript::makeNativeVersion(cx, layout.newScript(), templateObject);
|
||||
if (!replacementNewScript)
|
||||
return false;
|
||||
|
||||
replacementNewGroup->setNewScript(replacementNewScript);
|
||||
gc::TraceTypeNewScript(replacementNewGroup);
|
||||
|
||||
group->clearNewScript(cx, replacementNewGroup);
|
||||
}
|
||||
|
||||
size_t nfixed = gc::GetGCKindSlots(layout.getAllocKind());
|
||||
RootedShape shape(cx, EmptyShape::getInitialShape(cx, &PlainObject::class_, proto,
|
||||
@ -214,8 +248,8 @@ UnboxedLayout::makeNativeGroup(JSContext *cx, ObjectGroup *group)
|
||||
TypeSet::TypeList types;
|
||||
if (!property->types.enumerateTypes(&types))
|
||||
return false;
|
||||
for (size_t i = 0; i < types.length(); i++)
|
||||
AddTypePropertyId(cx, nativeGroup, property->id, types[i]);
|
||||
for (size_t j = 0; j < types.length(); j++)
|
||||
AddTypePropertyId(cx, nativeGroup, property->id, types[j]);
|
||||
HeapTypeSet *nativeProperty = nativeGroup->maybeGetProperty(property->id);
|
||||
if (nativeProperty->canSetDefinite(i))
|
||||
nativeProperty->setDefinite(i);
|
||||
@ -224,6 +258,7 @@ UnboxedLayout::makeNativeGroup(JSContext *cx, ObjectGroup *group)
|
||||
|
||||
layout.nativeGroup_ = nativeGroup;
|
||||
layout.nativeShape_ = shape;
|
||||
layout.replacementNewGroup_ = replacementNewGroup;
|
||||
|
||||
nativeGroup->setOriginalUnboxedGroup(group);
|
||||
|
||||
|
@ -71,10 +71,18 @@ class UnboxedLayout : public mozilla::LinkedListElement<UnboxedLayout>
|
||||
HeapPtrObjectGroup nativeGroup_;
|
||||
HeapPtrShape nativeShape_;
|
||||
|
||||
// If nativeGroup is set and this object originally had a TypeNewScript,
|
||||
// this points to the default 'new' group which replaced this one (and
|
||||
// which might itself have been cleared since). This link is only needed to
|
||||
// keep the replacement group from being GC'ed. If it were GC'ed and a new
|
||||
// one regenerated later, that new group might have a different allocation
|
||||
// kind from this group.
|
||||
HeapPtrObjectGroup replacementNewGroup_;
|
||||
|
||||
public:
|
||||
UnboxedLayout(const PropertyVector &properties, size_t size)
|
||||
: size_(size), newScript_(nullptr), traceList_(nullptr),
|
||||
nativeGroup_(nullptr), nativeShape_(nullptr)
|
||||
nativeGroup_(nullptr), nativeShape_(nullptr), replacementNewGroup_(nullptr)
|
||||
{
|
||||
properties_.appendAll(properties);
|
||||
}
|
||||
|
@ -4319,9 +4319,8 @@ FrameLayerBuilder::PaintItems(nsTArray<ClippedDisplayItem>& aItems,
|
||||
float aXScale, float aYScale,
|
||||
int32_t aCommonClipCount)
|
||||
{
|
||||
#ifdef MOZ_DUMP_PAINTING
|
||||
DrawTarget& aDrawTarget = *aRC->GetDrawTarget();
|
||||
#endif
|
||||
|
||||
int32_t appUnitsPerDevPixel = aPresContext->AppUnitsPerDevPixel();
|
||||
nsRect boundRect = aRect.ToAppUnits(appUnitsPerDevPixel);
|
||||
boundRect.MoveBy(NSIntPixelsToAppUnits(aOffset.x, appUnitsPerDevPixel),
|
||||
@ -4371,7 +4370,9 @@ FrameLayerBuilder::PaintItems(nsTArray<ClippedDisplayItem>& aItems,
|
||||
}
|
||||
|
||||
if (cdi->mInactiveLayerManager) {
|
||||
bool saved = aDrawTarget.GetPermitSubpixelAA();
|
||||
PaintInactiveLayer(aBuilder, cdi->mInactiveLayerManager, cdi->mItem, aContext, aRC);
|
||||
aDrawTarget.SetPermitSubpixelAA(saved);
|
||||
} else {
|
||||
nsIFrame* frame = cdi->mItem->Frame();
|
||||
frame->AddStateBits(NS_FRAME_PAINTED_THEBES);
|
||||
|
@ -433,7 +433,7 @@ load 835056.html
|
||||
load 836990-1.html
|
||||
load 840480.html
|
||||
load 847242.html
|
||||
load 852293.html
|
||||
pref(layers.progressive-paint,false) pref(layers.low-precision-buffer,false) load 852293.html
|
||||
load 860579-1.html
|
||||
pref(layers.force-active,true) load 859526-1.html
|
||||
pref(layers.force-active,true) load 859630-1.html
|
||||
|
@ -2773,12 +2773,40 @@ nsTreeBodyFrame::HandleEvent(nsPresContext* aPresContext,
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
PaintTreeBody(nsIFrame* aFrame, nsRenderingContext* aCtx,
|
||||
const nsRect& aDirtyRect, nsPoint aPt)
|
||||
{
|
||||
static_cast<nsTreeBodyFrame*>(aFrame)->PaintTreeBody(*aCtx, aDirtyRect, aPt);
|
||||
}
|
||||
class nsDisplayTreeBody MOZ_FINAL : public nsDisplayItem {
|
||||
public:
|
||||
nsDisplayTreeBody(nsDisplayListBuilder* aBuilder, nsFrame* aFrame) :
|
||||
nsDisplayItem(aBuilder, aFrame),
|
||||
mDisableSubpixelAA(false) {
|
||||
MOZ_COUNT_CTOR(nsDisplayTreeBody);
|
||||
}
|
||||
#ifdef NS_BUILD_REFCNT_LOGGING
|
||||
virtual ~nsDisplayTreeBody() {
|
||||
MOZ_COUNT_DTOR(nsDisplayTreeBody);
|
||||
}
|
||||
#endif
|
||||
|
||||
virtual void Paint(nsDisplayListBuilder* aBuilder,
|
||||
nsRenderingContext* aCtx) MOZ_OVERRIDE
|
||||
{
|
||||
gfxContext* ctx = aCtx->ThebesContext();
|
||||
gfxContextAutoDisableSubpixelAntialiasing disable(ctx, mDisableSubpixelAA);
|
||||
static_cast<nsTreeBodyFrame*>(mFrame)->
|
||||
PaintTreeBody(*aCtx, mVisibleRect, ToReferenceFrame());
|
||||
}
|
||||
NS_DISPLAY_DECL_NAME("XULTreeBody", TYPE_XUL_TREE_BODY)
|
||||
|
||||
virtual nsRect GetComponentAlphaBounds(nsDisplayListBuilder* aBuilder) MOZ_OVERRIDE
|
||||
{
|
||||
bool snap;
|
||||
return GetBounds(aBuilder, &snap);
|
||||
}
|
||||
virtual void DisableComponentAlpha() MOZ_OVERRIDE {
|
||||
mDisableSubpixelAA = true;
|
||||
}
|
||||
|
||||
bool mDisableSubpixelAA;
|
||||
};
|
||||
|
||||
// Painting routines
|
||||
void
|
||||
@ -2799,8 +2827,7 @@ nsTreeBodyFrame::BuildDisplayList(nsDisplayListBuilder* aBuilder,
|
||||
return;
|
||||
|
||||
aLists.Content()->AppendNewToTop(new (aBuilder)
|
||||
nsDisplayGeneric(aBuilder, this, ::PaintTreeBody, "XULTreeBody",
|
||||
nsDisplayItem::TYPE_XUL_TREE_BODY));
|
||||
nsDisplayTreeBody(aBuilder, this));
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -5,15 +5,3 @@
|
||||
#else
|
||||
#define SOUNDTOUCH_INTEGER_SAMPLES 1
|
||||
#endif
|
||||
|
||||
#ifndef MOZILLA_PRESUME_SSE
|
||||
#ifdef MOZ_SAMPLE_TYPE_FLOAT32
|
||||
#define SOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifndef MOZILLA_PRESUME_MMX
|
||||
#ifdef MOZ_SAMPLE_TYPE_S16
|
||||
#define SOUNDTOUCH_DISABLE_X86_OPTIMIZATIONS 1
|
||||
#endif
|
||||
#endif
|
||||
|
@ -265,7 +265,13 @@ public:
|
||||
explicit Fake_DOMMediaStream(Fake_MediaStream *stream = nullptr)
|
||||
: mMediaStream(stream ? stream : new Fake_MediaStream())
|
||||
, mVideoTrack(new Fake_MediaStreamTrack(true, this))
|
||||
, mAudioTrack(new Fake_MediaStreamTrack(false, this)) {}
|
||||
, mAudioTrack(new Fake_MediaStreamTrack(false, this))
|
||||
{
|
||||
static size_t counter = 0;
|
||||
std::ostringstream os;
|
||||
os << counter++;
|
||||
mID = os.str();
|
||||
}
|
||||
|
||||
NS_DECL_THREADSAFE_ISUPPORTS
|
||||
|
||||
|
@ -4477,6 +4477,16 @@ pref("dom.mozSettings.SettingsService.verbose.enabled", false);
|
||||
// readwrite.
|
||||
pref("dom.mozSettings.allowForceReadOnly", false);
|
||||
|
||||
// The interval at which to check for slow running addons
|
||||
#ifdef NIGHTLY_BUILD
|
||||
pref("browser.addon-watch.interval", 15000);
|
||||
#else
|
||||
pref("browser.addon-watch.interval", -1);
|
||||
#endif
|
||||
pref("browser.addon-watch.ignore", "[\"mochikit@mozilla.org\",\"special-powers@mozilla.org\"]");
|
||||
// the percentage of time addons are allowed to use without being labeled slow
|
||||
pref("browser.addon-watch.percentage-limit", 5);
|
||||
|
||||
// RequestSync API is disabled by default.
|
||||
pref("dom.requestSync.enabled", false);
|
||||
|
||||
|
@ -109,6 +109,13 @@ CookieServiceChild::GetCookieStringInternal(nsIURI *aHostURI,
|
||||
|
||||
*aCookieString = nullptr;
|
||||
|
||||
// Fast past: don't bother sending IPC messages about nullprincipal'd
|
||||
// documents.
|
||||
nsAutoCString scheme;
|
||||
aHostURI->GetScheme(scheme);
|
||||
if (scheme.EqualsLiteral("moz-nullprincipal"))
|
||||
return NS_OK;
|
||||
|
||||
// Determine whether the request is foreign. Failure is acceptable.
|
||||
bool isForeign = true;
|
||||
if (RequireThirdPartyCheck())
|
||||
@ -137,6 +144,13 @@ CookieServiceChild::SetCookieStringInternal(nsIURI *aHostURI,
|
||||
NS_ENSURE_ARG(aHostURI);
|
||||
NS_ENSURE_ARG_POINTER(aCookieString);
|
||||
|
||||
// Fast past: don't bother sending IPC messages about nullprincipal'd
|
||||
// documents.
|
||||
nsAutoCString scheme;
|
||||
aHostURI->GetScheme(scheme);
|
||||
if (scheme.EqualsLiteral("moz-nullprincipal"))
|
||||
return NS_OK;
|
||||
|
||||
// Determine whether the request is foreign. Failure is acceptable.
|
||||
bool isForeign = true;
|
||||
if (RequireThirdPartyCheck())
|
||||
|
@ -60,11 +60,11 @@ class Context(KeyedDefaultDict):
|
||||
lots of empty/default values, you have a data structure with only the
|
||||
values that were read or touched.
|
||||
|
||||
Instances of variables classes are created by invoking class_name(),
|
||||
except when class_name derives from ContextDerivedValue, in which
|
||||
case class_name(instance_of_the_context) is invoked.
|
||||
A value is added to those calls when instances are created during
|
||||
assignment (setitem).
|
||||
Instances of variables classes are created by invoking ``class_name()``,
|
||||
except when class_name derives from ``ContextDerivedValue`` or
|
||||
``SubContext``, in which case ``class_name(instance_of_the_context)`` or
|
||||
``class_name(self)`` is invoked. A value is added to those calls when
|
||||
instances are created during assignment (setitem).
|
||||
|
||||
allowed_variables is a dict of the variables that can be set and read in
|
||||
this context instance. Keys in this dict are the strings representing keys
|
||||
@ -84,6 +84,7 @@ class Context(KeyedDefaultDict):
|
||||
self._all_paths = []
|
||||
self.config = config
|
||||
self.execution_time = 0
|
||||
self._sandbox = None
|
||||
KeyedDefaultDict.__init__(self, self._factory)
|
||||
|
||||
def push_source(self, path):
|
||||
@ -272,6 +273,35 @@ class TemplateContext(Context):
|
||||
return Context._validate(self, key, value, True)
|
||||
|
||||
|
||||
class SubContext(Context, ContextDerivedValue):
|
||||
"""A Context derived from another Context.
|
||||
|
||||
Sub-contexts are intended to be used as context managers.
|
||||
|
||||
Sub-contexts inherit paths and other relevant state from the parent
|
||||
context.
|
||||
"""
|
||||
def __init__(self, parent):
|
||||
assert isinstance(parent, Context)
|
||||
|
||||
Context.__init__(self, allowed_variables=self.VARIABLES,
|
||||
config=parent.config)
|
||||
|
||||
# Copy state from parent.
|
||||
for p in parent.source_stack:
|
||||
self.push_source(p)
|
||||
self._sandbox = parent._sandbox
|
||||
|
||||
def __enter__(self):
|
||||
if not self._sandbox or self._sandbox() is None:
|
||||
raise Exception('a sandbox is required')
|
||||
|
||||
self._sandbox().push_subcontext(self)
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
self._sandbox().pop_subcontext(self)
|
||||
|
||||
|
||||
class FinalTargetValue(ContextDerivedValue, unicode):
|
||||
def __new__(cls, context, value=""):
|
||||
if not value:
|
||||
@ -366,6 +396,27 @@ def ContextDerivedTypedList(type, base_class=List):
|
||||
return _TypedList
|
||||
|
||||
|
||||
# This defines functions that create sub-contexts.
|
||||
#
|
||||
# Values are classes that are SubContexts. The class name will be turned into
|
||||
# a function that when called emits an instance of that class.
|
||||
#
|
||||
# Arbitrary arguments can be passed to the class constructor. The first
|
||||
# argument is always the parent context. It is up to each class to perform
|
||||
# argument validation.
|
||||
SUBCONTEXTS = [
|
||||
]
|
||||
|
||||
for cls in SUBCONTEXTS:
|
||||
if not issubclass(cls, SubContext):
|
||||
raise ValueError('SUBCONTEXTS entry not a SubContext class: %s' % cls)
|
||||
|
||||
if not hasattr(cls, 'VARIABLES'):
|
||||
raise ValueError('SUBCONTEXTS entry does not have VARIABLES: %s' % cls)
|
||||
|
||||
SUBCONTEXTS = {cls.__name__: cls for cls in SUBCONTEXTS}
|
||||
|
||||
|
||||
# This defines the set of mutable global variables.
|
||||
#
|
||||
# Each variable is a tuple of:
|
||||
|
@ -62,6 +62,7 @@ from .context import (
|
||||
VARIABLES,
|
||||
DEPRECATION_HINTS,
|
||||
SPECIAL_VARIABLES,
|
||||
SUBCONTEXTS,
|
||||
TemplateContext,
|
||||
)
|
||||
|
||||
@ -140,12 +141,14 @@ class MozbuildSandbox(Sandbox):
|
||||
return SPECIAL_VARIABLES[key][0](self._context)
|
||||
if key in FUNCTIONS:
|
||||
return self._create_function(FUNCTIONS[key])
|
||||
if key in SUBCONTEXTS:
|
||||
return self._create_subcontext(SUBCONTEXTS[key])
|
||||
if key in self.templates:
|
||||
return self._create_template_function(self.templates[key])
|
||||
return Sandbox.__getitem__(self, key)
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
if key in SPECIAL_VARIABLES or key in FUNCTIONS:
|
||||
if key in SPECIAL_VARIABLES or key in FUNCTIONS or key in SUBCONTEXTS:
|
||||
raise KeyError()
|
||||
if key in self.exports:
|
||||
self._context[key] = value
|
||||
@ -310,6 +313,14 @@ class MozbuildSandbox(Sandbox):
|
||||
|
||||
self.templates[name] = func, code, self._context.current_path
|
||||
|
||||
@memoize
|
||||
def _create_subcontext(self, cls):
|
||||
"""Return a function object that creates SubContext instances."""
|
||||
def fn(*args, **kwargs):
|
||||
return cls(self._context, *args, **kwargs)
|
||||
|
||||
return fn
|
||||
|
||||
@memoize
|
||||
def _create_function(self, function_def):
|
||||
"""Returns a function object for use within the sandbox for the given
|
||||
@ -736,7 +747,7 @@ class BuildReader(object):
|
||||
read, a new Context is created and emitted.
|
||||
"""
|
||||
path = mozpath.join(self.config.topsrcdir, 'moz.build')
|
||||
return self.read_mozbuild(path, self.config, read_tiers=True)
|
||||
return self.read_mozbuild(path, self.config)
|
||||
|
||||
def all_mozbuild_paths(self):
|
||||
"""Iterator over all available moz.build files.
|
||||
@ -872,8 +883,7 @@ class BuildReader(object):
|
||||
for name, key, value in assignments:
|
||||
yield p, name, key, value
|
||||
|
||||
def read_mozbuild(self, path, config, read_tiers=False, descend=True,
|
||||
metadata={}):
|
||||
def read_mozbuild(self, path, config, descend=True, metadata={}):
|
||||
"""Read and process a mozbuild file, descending into children.
|
||||
|
||||
This starts with a single mozbuild file, executes it, and descends into
|
||||
@ -884,10 +894,6 @@ class BuildReader(object):
|
||||
directory, we will open the moz.build file located in that
|
||||
directory in a new Sandbox and process it.
|
||||
|
||||
If read_tiers is True (it should only be True for the top-level
|
||||
mozbuild file in a project), the TIERS variable will be used for
|
||||
traversal as well.
|
||||
|
||||
If descend is True (the default), we will descend into child
|
||||
directories and files per variable values.
|
||||
|
||||
@ -900,8 +906,8 @@ class BuildReader(object):
|
||||
"""
|
||||
self._execution_stack.append(path)
|
||||
try:
|
||||
for s in self._read_mozbuild(path, config, read_tiers=read_tiers,
|
||||
descend=descend, metadata=metadata):
|
||||
for s in self._read_mozbuild(path, config, descend=descend,
|
||||
metadata=metadata):
|
||||
yield s
|
||||
|
||||
except BuildReaderError as bre:
|
||||
@ -927,7 +933,7 @@ class BuildReader(object):
|
||||
raise BuildReaderError(list(self._execution_stack),
|
||||
sys.exc_info()[2], other_error=e)
|
||||
|
||||
def _read_mozbuild(self, path, config, read_tiers, descend, metadata):
|
||||
def _read_mozbuild(self, path, config, descend, metadata):
|
||||
path = mozpath.normpath(path)
|
||||
log(self._log, logging.DEBUG, 'read_mozbuild', {'path': path},
|
||||
'Reading file: {path}')
|
||||
@ -1008,11 +1014,12 @@ class BuildReader(object):
|
||||
|
||||
for gyp_context in gyp_contexts:
|
||||
context['DIRS'].append(mozpath.relpath(gyp_context.objdir, context.objdir))
|
||||
sandbox.subcontexts.append(gyp_context)
|
||||
|
||||
yield context
|
||||
|
||||
for gyp_context in gyp_contexts:
|
||||
yield gyp_context
|
||||
for subcontext in sandbox.subcontexts:
|
||||
yield subcontext
|
||||
|
||||
# Traverse into referenced files.
|
||||
|
||||
@ -1051,7 +1058,7 @@ class BuildReader(object):
|
||||
continue
|
||||
|
||||
for res in self.read_mozbuild(child_path, context.config,
|
||||
read_tiers=False, metadata=child_metadata):
|
||||
metadata=child_metadata):
|
||||
yield res
|
||||
|
||||
self._execution_stack.pop()
|
||||
|
@ -22,6 +22,7 @@ from __future__ import unicode_literals
|
||||
import copy
|
||||
import os
|
||||
import sys
|
||||
import weakref
|
||||
|
||||
from contextlib import contextmanager
|
||||
|
||||
@ -116,12 +117,22 @@ class Sandbox(dict):
|
||||
assert isinstance(self._builtins, ReadOnlyDict)
|
||||
assert isinstance(context, Context)
|
||||
|
||||
self._context = context
|
||||
# Contexts are modeled as a stack because multiple context managers
|
||||
# may be active.
|
||||
self._active_contexts = [context]
|
||||
|
||||
# Seen sub-contexts. Will be populated with other Context instances
|
||||
# that were related to execution of this instance.
|
||||
self.subcontexts = []
|
||||
|
||||
# We need to record this because it gets swallowed as part of
|
||||
# evaluation.
|
||||
self._last_name_error = None
|
||||
|
||||
@property
|
||||
def _context(self):
|
||||
return self._active_contexts[-1]
|
||||
|
||||
def exec_file(self, path):
|
||||
"""Execute code at a path in the sandbox.
|
||||
|
||||
@ -153,6 +164,9 @@ class Sandbox(dict):
|
||||
if path:
|
||||
self._context.push_source(path)
|
||||
|
||||
old_sandbox = self._context._sandbox
|
||||
self._context._sandbox = weakref.ref(self)
|
||||
|
||||
# We don't have to worry about bytecode generation here because we are
|
||||
# too low-level for that. However, we could add bytecode generation via
|
||||
# the marshall module if parsing performance were ever an issue.
|
||||
@ -190,9 +204,31 @@ class Sandbox(dict):
|
||||
raise SandboxExecutionError(self._context.source_stack, exc[0],
|
||||
exc[1], exc[2])
|
||||
finally:
|
||||
self._context._sandbox = old_sandbox
|
||||
if path:
|
||||
self._context.pop_source()
|
||||
|
||||
def push_subcontext(self, context):
|
||||
"""Push a SubContext onto the execution stack.
|
||||
|
||||
When called, the active context will be set to the specified context,
|
||||
meaning all variable accesses will go through it. We also record this
|
||||
SubContext as having been executed as part of this sandbox.
|
||||
"""
|
||||
self._active_contexts.append(context)
|
||||
if context not in self.subcontexts:
|
||||
self.subcontexts.append(context)
|
||||
|
||||
def pop_subcontext(self, context):
|
||||
"""Pop a SubContext off the execution stack.
|
||||
|
||||
SubContexts must be pushed and popped in opposite order. This is
|
||||
validated as part of the function call to ensure proper consumer API
|
||||
use.
|
||||
"""
|
||||
popped = self._active_contexts.pop()
|
||||
assert popped == context
|
||||
|
||||
def __getitem__(self, key):
|
||||
if key.isupper():
|
||||
try:
|
||||
|
@ -101,6 +101,21 @@ def special_reference(v, func, typ, doc):
|
||||
|
||||
def format_module(m):
|
||||
lines = []
|
||||
|
||||
for subcontext, cls in sorted(m.SUBCONTEXTS.items()):
|
||||
lines.extend([
|
||||
'.. _mozbuild_subcontext_%s:' % subcontext,
|
||||
'',
|
||||
'Sub-Context: %s' % subcontext,
|
||||
'=============' + '=' * len(subcontext),
|
||||
'',
|
||||
prepare_docstring(cls.__doc__)[0],
|
||||
'',
|
||||
])
|
||||
|
||||
for k, v in sorted(cls.VARIABLES.items()):
|
||||
lines.extend(variable_reference(k, *v))
|
||||
|
||||
lines.extend([
|
||||
'Variables',
|
||||
'=========',
|
||||
|
@ -11,6 +11,7 @@ from mozbuild.frontend.context import (
|
||||
Context,
|
||||
FUNCTIONS,
|
||||
SPECIAL_VARIABLES,
|
||||
SUBCONTEXTS,
|
||||
VARIABLES,
|
||||
)
|
||||
|
||||
@ -256,6 +257,12 @@ class TestSymbols(unittest.TestCase):
|
||||
for func, typ, doc in SPECIAL_VARIABLES.values():
|
||||
self._verify_doc(doc)
|
||||
|
||||
for name, cls in SUBCONTEXTS.items():
|
||||
self._verify_doc(cls.__doc__)
|
||||
|
||||
for name, v in cls.VARIABLES.items():
|
||||
self._verify_doc(v[2])
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
@ -99,12 +99,12 @@ def match(path, pattern):
|
||||
'''
|
||||
if not pattern:
|
||||
return True
|
||||
if not pattern in re_cache:
|
||||
pattern = re.escape(pattern)
|
||||
pattern = re.sub(r'(^|\\\/)\\\*\\\*\\\/', r'\1(?:.+/)?', pattern)
|
||||
pattern = re.sub(r'(^|\\\/)\\\*\\\*$', r'(?:\1.+)?', pattern)
|
||||
pattern = pattern.replace(r'\*', '[^/]*') + '(?:/.*)?$'
|
||||
re_cache[pattern] = re.compile(pattern)
|
||||
if pattern not in re_cache:
|
||||
p = re.escape(pattern)
|
||||
p = re.sub(r'(^|\\\/)\\\*\\\*\\\/', r'\1(?:.+/)?', p)
|
||||
p = re.sub(r'(^|\\\/)\\\*\\\*$', r'(?:\1.+)?', p)
|
||||
p = p.replace(r'\*', '[^/]*') + '(?:/.*)?$'
|
||||
re_cache[pattern] = re.compile(p)
|
||||
return re_cache[pattern].match(path) is not None
|
||||
|
||||
|
||||
|
@ -1447,16 +1447,11 @@ MarionetteServerConnection.prototype = {
|
||||
return this._browserIds.get(permKey);
|
||||
}
|
||||
|
||||
let contentWindow = browser.contentWindowAsCPOW;
|
||||
if (contentWindow !== null && !Cu.isDeadWrapper(contentWindow)) {
|
||||
let winId = contentWindow.QueryInterface(Ci.nsIInterfaceRequestor)
|
||||
.getInterface(Ci.nsIDOMWindowUtils)
|
||||
.outerWindowID;
|
||||
if (winId) {
|
||||
winId += "";
|
||||
this._browserIds.set(permKey, winId);
|
||||
return winId;
|
||||
}
|
||||
let winId = browser.outerWindowID;
|
||||
if (winId) {
|
||||
winId += "";
|
||||
this._browserIds.set(permKey, winId);
|
||||
return winId;
|
||||
}
|
||||
return null;
|
||||
},
|
||||
|
48
testing/mochitest/ShutdownLeaksCollector.jsm
Normal file
48
testing/mochitest/ShutdownLeaksCollector.jsm
Normal file
@ -0,0 +1,48 @@
|
||||
/* 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/. */
|
||||
|
||||
var Ci = Components.interfaces;
|
||||
var Cc = Components.classes;
|
||||
var Cu = Components.utils;
|
||||
|
||||
Cu.import("resource://gre/modules/Services.jsm");
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["ContentCollector"];
|
||||
|
||||
// This listens for the message "browser-test:collect-request". When it gets it,
|
||||
// it runs some GCs and CCs, then prints out a message indicating the collections
|
||||
// are complete. Mochitest uses this information to determine when windows and
|
||||
// docshells should be destroyed.
|
||||
|
||||
var ContentCollector = {
|
||||
init: function() {
|
||||
let cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
|
||||
.getService(Ci.nsISyncMessageSender);
|
||||
cpmm.addMessageListener("browser-test:collect-request", this);
|
||||
},
|
||||
|
||||
receiveMessage: function(aMessage) {
|
||||
switch (aMessage.name) {
|
||||
case "browser-test:collect-request":
|
||||
Services.obs.notifyObservers(null, "memory-pressure", "heap-minimize");
|
||||
|
||||
Cu.forceGC();
|
||||
Cu.forceCC();
|
||||
|
||||
Cu.schedulePreciseShrinkingGC(() => {
|
||||
Cu.forceCC();
|
||||
|
||||
let pid = Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULRuntime).processID;
|
||||
dump("Completed ShutdownLeaks collections in process " + pid + "\n")});
|
||||
|
||||
let cpmm = Cc["@mozilla.org/childprocessmessagemanager;1"]
|
||||
.getService(Ci.nsISyncMessageSender);
|
||||
cpmm.removeMessageListener("browser-test:collect-request", this);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
ContentCollector.init();
|
@ -88,6 +88,12 @@ function testInit() {
|
||||
}
|
||||
if (gConfig.e10s) {
|
||||
e10s_init();
|
||||
let globalMM = Cc["@mozilla.org/globalmessagemanager;1"]
|
||||
.getService(Ci.nsIMessageListenerManager);
|
||||
globalMM.loadFrameScript("chrome://mochikit/content/shutdown-leaks-collector.js", true);
|
||||
} else {
|
||||
// In non-e10s, only run the ShutdownLeaksCollector in the parent process.
|
||||
Components.utils.import("chrome://mochikit/content/ShutdownLeaksCollector.jsm");
|
||||
}
|
||||
}
|
||||
|
||||
@ -575,6 +581,10 @@ Tester.prototype = {
|
||||
// and thus get rid of more false leaks like already terminated workers.
|
||||
Services.obs.notifyObservers(null, "memory-pressure", "heap-minimize");
|
||||
|
||||
let ppmm = Cc["@mozilla.org/parentprocessmessagemanager;1"]
|
||||
.getService(Ci.nsIMessageBroadcaster);
|
||||
ppmm.broadcastAsyncMessage("browser-test:collect-request");
|
||||
|
||||
checkForLeakedGlobalWindows(aResults => {
|
||||
if (aResults.length == 0) {
|
||||
this.finish();
|
||||
|
@ -10,6 +10,8 @@ mochikit.jar:
|
||||
content/cc-analyzer.js (cc-analyzer.js)
|
||||
content/chrome-harness.js (chrome-harness.js)
|
||||
content/mochitest-e10s-utils.js (mochitest-e10s-utils.js)
|
||||
content/shutdown-leaks-collector.js (shutdown-leaks-collector.js)
|
||||
content/ShutdownLeaksCollector.jsm (ShutdownLeaksCollector.jsm)
|
||||
content/harness.xul (harness.xul)
|
||||
content/redirect.html (redirect.html)
|
||||
content/server.js (server.js)
|
||||
|
7
testing/mochitest/shutdown-leaks-collector.js
Normal file
7
testing/mochitest/shutdown-leaks-collector.js
Normal file
@ -0,0 +1,7 @@
|
||||
/* 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/. */
|
||||
|
||||
// We run this code in a .jsm rather than here to avoid keeping the current
|
||||
// compartment alive.
|
||||
Components.utils.import("chrome://mochikit/content/ShutdownLeaksCollector.jsm");
|
@ -30,10 +30,12 @@ required_files = [("testharness_runner.html", "", False),
|
||||
|
||||
def do_delayed_imports():
|
||||
global marionette
|
||||
global errors
|
||||
try:
|
||||
import marionette
|
||||
from marionette import errors
|
||||
except ImportError:
|
||||
import marionette_driver.marionette as marionette
|
||||
from marionette_driver import marionette, errors
|
||||
|
||||
|
||||
class MarionetteTestExecutor(TestExecutor):
|
||||
@ -153,13 +155,13 @@ class MarionetteTestExecutor(TestExecutor):
|
||||
|
||||
try:
|
||||
self.marionette.set_script_timeout((timeout + extra_timeout) * 1000)
|
||||
except IOError, marionette.errors.InvalidResponseException:
|
||||
except IOError, errors.InvalidResponseException:
|
||||
self.logger.error("Lost marionette connection before starting test")
|
||||
return Stop
|
||||
|
||||
try:
|
||||
result = self.convert_result(test, self.do_test(test, timeout))
|
||||
except marionette.errors.ScriptTimeoutException:
|
||||
except errors.ScriptTimeoutException:
|
||||
with result_lock:
|
||||
if not result_flag.is_set():
|
||||
result_flag.set()
|
||||
@ -179,7 +181,7 @@ class MarionetteTestExecutor(TestExecutor):
|
||||
# else:
|
||||
# break
|
||||
# Now need to check if the browser is still responsive and restart it if not
|
||||
except (socket.timeout, marionette.errors.InvalidResponseException, IOError):
|
||||
except (socket.timeout, errors.InvalidResponseException, IOError):
|
||||
# This can happen on a crash
|
||||
# Also, should check after the test if the firefox process is still running
|
||||
# and otherwise ignore any other result and set it to crash
|
||||
@ -250,7 +252,7 @@ class MarionetteReftestExecutor(MarionetteTestExecutor):
|
||||
full_url = urlparse.urljoin(self.http_server_url, url)
|
||||
try:
|
||||
self.marionette.navigate(full_url)
|
||||
except marionette.errors.MarionetteException:
|
||||
except errors.MarionetteException:
|
||||
return {"status": "ERROR",
|
||||
"message": "Failed to load url %s" % (full_url,)}
|
||||
if url_type == "test":
|
||||
|
@ -124,6 +124,13 @@ class HgTree(object):
|
||||
def commit_patch(self):
|
||||
self.hg("qfinish")
|
||||
|
||||
def contains_commit(self, commit):
|
||||
try:
|
||||
self.hg("identify", "-r", commit.sha1)
|
||||
return True
|
||||
except subprocess.CalledProcessError:
|
||||
return False
|
||||
|
||||
|
||||
class GitTree(object):
|
||||
name = "git"
|
||||
|
96
toolkit/modules/AddonWatcher.jsm
Normal file
96
toolkit/modules/AddonWatcher.jsm
Normal file
@ -0,0 +1,96 @@
|
||||
// -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
|
||||
/* 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/. */
|
||||
|
||||
"use strict";
|
||||
|
||||
this.EXPORTED_SYMBOLS = ["AddonWatcher"];
|
||||
|
||||
const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
|
||||
|
||||
Cu.import("resource://gre/modules/XPCOMUtils.jsm");
|
||||
|
||||
XPCOMUtils.defineLazyModuleGetter(this, "Preferences",
|
||||
"resource://gre/modules/Preferences.jsm");
|
||||
|
||||
let AddonWatcher = {
|
||||
_lastAddonTime: {},
|
||||
_timer: Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer),
|
||||
_callback: null,
|
||||
_interval: 1500,
|
||||
_ignoreList: null,
|
||||
init: function(callback) {
|
||||
if (!callback) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._callback) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._interval = Preferences.get("browser.addon-watch.interval", 15000);
|
||||
if (this._interval == -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
this._callback = callback;
|
||||
try {
|
||||
this._ignoreList = new Set(JSON.parse(Preferences.get("browser.addon-watch.ignore", null)));
|
||||
} catch (ex) {
|
||||
// probably some malformed JSON, ignore and carry on
|
||||
this._ignoreList = new Set();
|
||||
}
|
||||
this._timer.initWithCallback(this._checkAddons.bind(this), this._interval, Ci.nsITimer.TYPE_REPEATING_SLACK);
|
||||
},
|
||||
uninit: function() {
|
||||
if (this._timer) {
|
||||
this._timer.cancel();
|
||||
this._timer = null;
|
||||
}
|
||||
},
|
||||
_checkAddons: function() {
|
||||
let compartmentInfo = Cc["@mozilla.org/compartment-info;1"]
|
||||
.getService(Ci.nsICompartmentInfo);
|
||||
let compartments = compartmentInfo.getCompartments();
|
||||
let count = compartments.length;
|
||||
let addons = {};
|
||||
for (let i = 0; i < count; i++) {
|
||||
let compartment = compartments.queryElementAt(i, Ci.nsICompartment);
|
||||
if (compartment.addonId) {
|
||||
if (addons[compartment.addonId]) {
|
||||
addons[compartment.addonId] += compartment.time;
|
||||
} else {
|
||||
addons[compartment.addonId] = compartment.time;
|
||||
}
|
||||
}
|
||||
}
|
||||
let limit = this._interval * Preferences.get("browser.addon-watch.percentage-limit", 75) * 10;
|
||||
for (let addonId in addons) {
|
||||
if (!this._ignoreList.has(addonId)) {
|
||||
if (!this._lastAddonTime[addonId]) {
|
||||
this._lastAddonTime[addonId] = 0;
|
||||
}
|
||||
if ((addons[addonId] - this._lastAddonTime[addonId]) > limit) {
|
||||
this._callback(addonId);
|
||||
}
|
||||
this._lastAddonTime[addonId] = addons[addonId];
|
||||
}
|
||||
}
|
||||
},
|
||||
ignoreAddonForSession: function(addonid) {
|
||||
this._ignoreList.add(addonid);
|
||||
},
|
||||
ignoreAddonPermanently: function(addonid) {
|
||||
this._ignoreList.add(addonid);
|
||||
try {
|
||||
let ignoreList = JSON.parse(Preferences.get("browser.addon-watch.ignore", "[]"))
|
||||
if (!ignoreList.includes(addonid)) {
|
||||
ignoreList.push(addonid);
|
||||
Preferences.set("browser.addon-watch.ignore", JSON.stringify(ignoreList));
|
||||
}
|
||||
} catch (ex) {
|
||||
Preferences.set("browser.addon-watch.ignore", JSON.stringify([addonid]));
|
||||
}
|
||||
}
|
||||
};
|
@ -12,6 +12,7 @@ MOCHITEST_CHROME_MANIFESTS += ['tests/chrome/chrome.ini']
|
||||
SPHINX_TREES['toolkit_modules'] = 'docs'
|
||||
|
||||
EXTRA_JS_MODULES += [
|
||||
'AddonWatcher.jsm',
|
||||
'Battery.jsm',
|
||||
'BinarySearch.jsm',
|
||||
'BrowserUtils.jsm',
|
||||
|
@ -83,9 +83,20 @@ XPCOMUtils.defineLazyGetter(this, "gPref", function bls_gPref() {
|
||||
QueryInterface(Ci.nsIPrefBranch);
|
||||
});
|
||||
|
||||
// From appinfo in Services.jsm. It is not possible to use the one in
|
||||
// Services.jsm since it will not successfully QueryInterface nsIXULAppInfo in
|
||||
// xpcshell tests due to other code calling Services.appinfo before the
|
||||
// nsIXULAppInfo is created by the tests.
|
||||
XPCOMUtils.defineLazyGetter(this, "gApp", function bls_gApp() {
|
||||
return Cc["@mozilla.org/xre/app-info;1"].getService(Ci.nsIXULAppInfo).
|
||||
QueryInterface(Ci.nsIXULRuntime);
|
||||
let appinfo = Cc["@mozilla.org/xre/app-info;1"]
|
||||
.getService(Ci.nsIXULRuntime);
|
||||
try {
|
||||
appinfo.QueryInterface(Ci.nsIXULAppInfo);
|
||||
} catch (ex if ex instanceof Components.Exception &&
|
||||
ex.result == Cr.NS_NOINTERFACE) {
|
||||
// Not all applications implement nsIXULAppInfo (e.g. xpcshell doesn't).
|
||||
}
|
||||
return appinfo;
|
||||
});
|
||||
|
||||
XPCOMUtils.defineLazyGetter(this, "gABI", function bls_gABI() {
|
||||
@ -396,6 +407,10 @@ Blocklist.prototype = {
|
||||
if (!gBlocklistEnabled)
|
||||
return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
|
||||
|
||||
// Not all applications implement nsIXULAppInfo (e.g. xpcshell doesn't).
|
||||
if (!appVersion && !gApp.version)
|
||||
return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
|
||||
|
||||
if (!appVersion)
|
||||
appVersion = gApp.version;
|
||||
if (!toolkitVersion)
|
||||
@ -529,9 +544,13 @@ Blocklist.prototype = {
|
||||
pingCountTotal = 1;
|
||||
|
||||
dsURI = dsURI.replace(/%APP_ID%/g, gApp.ID);
|
||||
dsURI = dsURI.replace(/%APP_VERSION%/g, gApp.version);
|
||||
// Not all applications implement nsIXULAppInfo (e.g. xpcshell doesn't).
|
||||
if (gApp.version)
|
||||
dsURI = dsURI.replace(/%APP_VERSION%/g, gApp.version);
|
||||
dsURI = dsURI.replace(/%PRODUCT%/g, gApp.name);
|
||||
dsURI = dsURI.replace(/%VERSION%/g, gApp.version);
|
||||
// Not all applications implement nsIXULAppInfo (e.g. xpcshell doesn't).
|
||||
if (gApp.version)
|
||||
dsURI = dsURI.replace(/%VERSION%/g, gApp.version);
|
||||
dsURI = dsURI.replace(/%BUILD_ID%/g, gApp.appBuildID);
|
||||
dsURI = dsURI.replace(/%BUILD_TARGET%/g, gApp.OS + "_" + gABI);
|
||||
dsURI = dsURI.replace(/%OS_VERSION%/g, gOSVersion);
|
||||
@ -1048,6 +1067,10 @@ Blocklist.prototype = {
|
||||
if (!gBlocklistEnabled)
|
||||
return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
|
||||
|
||||
// Not all applications implement nsIXULAppInfo (e.g. xpcshell doesn't).
|
||||
if (!appVersion && !gApp.version)
|
||||
return Ci.nsIBlocklistService.STATE_NOT_BLOCKED;
|
||||
|
||||
if (!appVersion)
|
||||
appVersion = gApp.version;
|
||||
if (!toolkitVersion)
|
||||
|
Loading…
Reference in New Issue
Block a user