Merge inbound and m-c. IGNORE BAD COMMIT MESSAGES

This commit is contained in:
Ryan VanderMeulen 2013-06-18 19:04:48 -04:00
commit a6fa56a5d3
180 changed files with 2657 additions and 1205 deletions

View File

@ -1150,3 +1150,7 @@ function closeBrowserWindow(window, callback) {
}, false);
window.close();
}
// Test disabled on Linux because of bug 882867
if (require("sdk/system/runtime").OS == "Linux")
module.exports = {};

View File

@ -488,17 +488,22 @@
<handlers>
<handler event="command"><![CDATA[
const target = event.originalTarget;
if (target.classList.contains("addengine-item")) {
if (target.engine) {
this.currentEngine = target.engine;
} else if (target.classList.contains("addengine-item")) {
var searchService =
Components.classes["@mozilla.org/browser/search-service;1"]
.getService(Components.interfaces.nsIBrowserSearchService);
// We only detect OpenSearch files
var type = Components.interfaces.nsISearchEngine.DATA_XML;
// Select the installed engine if the installation succeeds
var installCallback = {
onSuccess: engine => this.currentEngine = engine
}
searchService.addEngine(target.getAttribute("uri"), type,
target.getAttribute("src"), false);
target.getAttribute("src"), false,
installCallback);
}
else if (target.engine)
this.currentEngine = target.engine;
else
return;

View File

@ -30,8 +30,7 @@ function test() {
case "engine-added":
var engine = ss.getEngineByName("Bug 426329");
ok(engine, "Engine was added.");
//XXX Bug 493051
//ss.currentEngine = engine;
ss.currentEngine = engine;
break;
case "engine-current":
ok(ss.currentEngine.name == "Bug 426329", "currentEngine set");

View File

@ -16,8 +16,7 @@ function test() {
case "engine-added":
var engine = ss.getEngineByName(ENGINE_NAME);
ok(engine, "Engine was added.");
//XXX Bug 493051
//ss.currentEngine = engine;
ss.currentEngine = engine;
break;
case "engine-current":
is(ss.currentEngine.name, ENGINE_NAME, "currentEngine set");

View File

@ -42,20 +42,18 @@ function test() {
}
function addEngine(aCallback) {
function observer(aSub, aTopic, aData) {
switch (aData) {
case "engine-current":
ok(Services.search.currentEngine.name == "Bug 426329",
"currentEngine set");
aCallback();
break;
let installCallback = {
onSuccess: function (engine) {
Services.search.currentEngine = engine;
aCallback();
},
onError: function (errorCode) {
ok(false, "failed to install engine: " + errorCode);
}
}
Services.obs.addObserver(observer, "browser-search-engine-modified", false);
Services.search.addEngine(
engineURL + "426329.xml", Ci.nsISearchEngine.DATA_XML,
"data:image/x-icon,%00", false);
};
Services.search.addEngine(engineURL + "426329.xml",
Ci.nsISearchEngine.DATA_XML,
"data:image/x-icon,%00", false, installCallback);
}
function testOnWindow(aIsPrivate, aCallback) {

View File

@ -832,16 +832,7 @@ var SelectionHelperUI = {
return;
}
let selectionTap = this._hitTestSelection(aEvent);
// If the tap is in the selection, just ignore it. We disallow this
// since we always get a single tap before a double, and double tap
// copies selected text.
if (selectionTap) {
if (!this._targetIsEditable) {
this.closeEditSession(false);
return;
}
if (this._hitTestSelection(aEvent) && this._targetIsEditable) {
// Attach to the newly placed caret position
this._sendAsyncMessage("Browser:CaretAttach", {
xPos: aEvent.clientX,
@ -855,12 +846,11 @@ var SelectionHelperUI = {
if (this.startMark.visible && pointInTargetElement &&
this._targetIsEditable) {
this._transitionFromSelectionToCaret(clientCoords.x, clientCoords.y);
return;
}
// If we have active selection in anything else don't let the event get
// to content. Prevents random taps from killing active selection.
aEvent.stopPropagation();
aEvent.preventDefault();
// Close when we get a single tap in content.
this.closeEditSession(false);
},
_onKeypress: function _onKeypress() {

View File

@ -306,11 +306,9 @@ gTests.push({
},
});
/*
disable until bug 860248 is addressed.
gTests.push({
desc: "double-tap copy text in content",
setUp: setUpHelper,
desc: "tap on selection clears selection in content",
setUp: setUpAndTearDown,
run: function test() {
sendContextMenuClick(30, 20);
@ -319,102 +317,35 @@ gTests.push({
return SelectionHelperUI.isSelectionUIVisible;
}, kCommonWaitMs, kCommonPollMs);
sendDoubleTap(gWindow, 30, 20);
sendTap(gWindow, 30, 20);
yield waitForCondition(function () {
return !SelectionHelperUI.isSelectionUIVisible;
}, kCommonWaitMs, kCommonPollMs);
// check copy text results
let text = SpecialPowers.getClipboardData("text/unicode").trim();
is(text, "There", "copy text test");
// check for active selection
is(getTrimmedSelection(gWindow).toString(), "", "selection test");
},
tearDown: tearDownHelper,
tearDown: setUpAndTearDown,
});
gTests.push({
desc: "double-tap copy text in scrolled content",
setUp: setUpHelper,
desc: "tap off selection clears selection in content",
setUp: setUpAndTearDown,
run: function test() {
let scrollPromise = waitForEvent(gWindow, "scroll");
gWindow.scrollBy(0, 200);
yield scrollPromise;
ok(scrollPromise && !(scrollPromise instanceof Error), "scrollPromise error");
sendContextMenuClick(30, 100);
sendContextMenuClick(30, 20);
yield waitForCondition(function () {
return SelectionHelperUI.isSelectionUIVisible;
}, kCommonWaitMs, kCommonPollMs);
sendDoubleTap(gWindow, 42, 100);
sendTap(gWindow, 30, 100);
yield waitForCondition(function () {
return !SelectionHelperUI.isSelectionUIVisible;
}, kCommonWaitMs, kCommonPollMs);
// check copy text results
let text = SpecialPowers.getClipboardData("text/unicode");
is(text, "suddenly", "copy text test");
// check for active selection
is(getTrimmedSelection(gWindow).toString(), "", "selection test");
},
tearDown: function tearDown() {
emptyClipboard();
clearSelection(gWindow);
let scrollPromise = waitForEvent(gWindow, "scroll");
gWindow.scrollBy(0, -200);
yield scrollPromise;
yield waitForCondition(function () {
return !SelectionHelperUI.isSelectionUIVisible;
}, kCommonWaitMs, kCommonPollMs);
},
tearDown: setUpAndTearDown,
});
gTests.push({
desc: "single clicks on selection in non-editable content",
setUp: setUpHelper,
run: function test() {
sendContextMenuClick(100, 20);
yield waitForCondition(function () {
return SelectionHelperUI.isSelectionUIVisible;
}, kCommonWaitMs, kCommonPollMs);
// active state
is(SelectionHelperUI.isActive, true, "selection active");
let ypos = SelectionHelperUI.endMark.yPos + kMarkerOffsetY;
let touchdrag = new TouchDragAndHold();
yield touchdrag.start(gWindow, SelectionHelperUI.endMark.xPos, ypos, 190, ypos);
touchdrag.end();
yield waitForCondition(function () {
return !SelectionHelperUI.hasActiveDrag;
}, kCommonWaitMs, kCommonPollMs);
yield SelectionHelperUI.pingSelectionHandler();
// active state
is(SelectionHelperUI.isActive, true, "selection active");
// click on selected text - nothing should change
sendTap(gWindow, 240, 20);
is(SelectionHelperUI.isActive, true, "selection active");
// click outside the text - nothing should change
sendTap(gWindow, 197, 119);
is(SelectionHelperUI.isActive, true, "selection active");
},
tearDown: tearDownHelper,
});
*/
function test() {
if (!isLandscapeMode()) {
todo(false, "browser_selection_tests need landscape mode to run.");

View File

@ -40,6 +40,14 @@ CString sFirefoxPath;
// startup command line paramters.
#define kMetroTestFile "tests.ini"
// Process exit codes for buildbotcustom logic. These are currently ignored, but
// at some point releng expects to use these.
#define SUCCESS 0
#define WARNINGS 1
#define FAILURE 2
#define EXCEPTION 3
#define RETRY 4
static void Log(const wchar_t *fmt, ...)
{
va_list a = NULL;
@ -56,7 +64,7 @@ static void Log(const wchar_t *fmt, ...)
fflush(stdout);
}
static void Fail(const wchar_t *fmt, ...)
static void Fail(bool aRequestRetry, const wchar_t *fmt, ...)
{
va_list a = NULL;
wchar_t szDebugString[1024];
@ -67,8 +75,11 @@ static void Fail(const wchar_t *fmt, ...)
va_end(a);
if(!lstrlenW(szDebugString))
return;
wprintf(L"TEST-UNEXPECTED-FAIL | metrotestharness.exe | %s\n", szDebugString);
if (aRequestRetry) {
wprintf(L"FAIL-SHOULD-RETRY | metrotestharness.exe | %s\n", szDebugString);
} else {
wprintf(L"TEST-UNEXPECTED-FAIL | metrotestharness.exe | %s\n", szDebugString);
}
fflush(stdout);
}
@ -83,7 +94,7 @@ static bool GetModulePath(CStringW& aPathBuffer)
memset(buffer, 0, sizeof(buffer));
if (!GetModuleFileName(NULL, buffer, MAX_PATH)) {
Fail(L"GetModuleFileName failed.");
Fail(false, L"GetModuleFileName failed.");
return false;
}
@ -190,13 +201,6 @@ static void ReadPipe()
}
}
// From buildbotcustom logic:
#define SUCCESS 0
#define WARNINGS 1
#define FAILURE 2
#define EXCEPTION 3
#define RETRY 4 /* will retry endlessly on new slaves, be careful with this! */
static int Launch()
{
Log(L"Launching browser...");
@ -209,7 +213,7 @@ static int Launch()
CLSCTX_LOCAL_SERVER,
IID_IApplicationActivationManager,
(void**)&activateMgr))) {
Fail(L"CoCreateInstance CLSID_ApplicationActivationManager failed.");
Fail(false, L"CoCreateInstance CLSID_ApplicationActivationManager failed.");
return FAILURE;
}
@ -217,7 +221,7 @@ static int Launch()
WCHAR appModelID[256];
// Activation is based on the browser's registered app model id
if (!GetDefaultBrowserAppModelID(appModelID, (sizeof(appModelID)/sizeof(WCHAR)))) {
Fail(L"GetDefaultBrowserAppModelID failed.");
Fail(false, L"GetDefaultBrowserAppModelID failed.");
return FAILURE;
}
Log(L"App model id='%s'", appModelID);
@ -251,7 +255,7 @@ static int Launch()
// Use the firefoxpath passed to us by the test harness
int index = sFirefoxPath.ReverseFind('\\');
if (index == -1) {
Fail(L"Bad firefoxpath path");
Fail(false, L"Bad firefoxpath path");
return FAILURE;
}
testFilePath = sFirefoxPath.Mid(0, index);
@ -261,7 +265,7 @@ static int Launch()
// Use the module path
char path[MAX_PATH];
if (!GetModuleFileNameA(NULL, path, MAX_PATH)) {
Fail(L"GetModuleFileNameA errorno=%d", GetLastError());
Fail(false, L"GetModuleFileNameA errorno=%d", GetLastError());
return FAILURE;
}
char* slash = strrchr(path, '\\');
@ -277,7 +281,7 @@ static int Launch()
// Make sure the firefox bin exists
if (GetFileAttributesW(sFirefoxPath) == INVALID_FILE_ATTRIBUTES) {
Fail(L"Invalid bin path: '%s'", sFirefoxPath);
Fail(false, L"Invalid bin path: '%s'", sFirefoxPath);
return FAILURE;
}
@ -289,7 +293,7 @@ static int Launch()
FILE_ATTRIBUTE_NORMAL,
NULL);
if (hTestFile == INVALID_HANDLE_VALUE) {
Fail(L"CreateFileA errorno=%d", GetLastError());
Fail(false, L"CreateFileA errorno=%d", GetLastError());
return FAILURE;
}
@ -304,7 +308,7 @@ static int Launch()
Log(L"Browser command line args: '%s'", CString(asciiParams));
if (!WriteFile(hTestFile, asciiParams, asciiParams.GetLength(), NULL, 0)) {
CloseHandle(hTestFile);
Fail(L"WriteFile errorno=%d", GetLastError());
Fail(false, L"WriteFile errorno=%d", GetLastError());
return FAILURE;
}
FlushFileBuffers(hTestFile);
@ -312,14 +316,14 @@ static int Launch()
// Create a named stdout pipe for the browser
if (!SetupTestOutputPipe()) {
Fail(L"SetupTestOutputPipe failed (errno=%d)", GetLastError());
Fail(false, L"SetupTestOutputPipe failed (errno=%d)", GetLastError());
return FAILURE;
}
// Launch firefox
hr = activateMgr->ActivateApplication(appModelID, L"", AO_NOERRORUI, &processID);
if (FAILED(hr)) {
Fail(L"ActivateApplication result %X", hr);
Fail(true, L"ActivateApplication result %X", hr);
return RETRY;
}
@ -327,7 +331,7 @@ static int Launch()
HANDLE child = OpenProcess(SYNCHRONIZE, FALSE, processID);
if (!child) {
Fail(L"Couldn't find child process. (%d)", GetLastError());
Fail(false, L"Couldn't find child process. (%d)", GetLastError());
return FAILURE;
}

View File

@ -305,6 +305,19 @@ case "$target" in
if test ! -d "$android_platform_tools" ; then
android_platform_tools="$android_sdk"/tools # SDK Tools < r8
fi
# The build tools got moved around to different directories in
# SDK Tools r22. Try to locate them.
android_build_tools=""
for suffix in 17.0.0 android-4.2.2; do
tools_directory="$android_sdk/../../build-tools/$suffix"
if test -d "$tools_directory" ; then
android_build_tools="$tools_directory"
break
fi
done
if test -z "$android_build_tools" ; then
android_build_tools="$android_platform_tools" # SDK Tools < r22
fi
ANDROID_SDK="${android_sdk}"
if test -e "${android_sdk}/../../extras/android/compatibility/v4/android-support-v4.jar" ; then
ANDROID_COMPAT_LIB="${android_sdk}/../../extras/android/compatibility/v4/android-support-v4.jar"
@ -312,12 +325,14 @@ case "$target" in
ANDROID_COMPAT_LIB="${android_sdk}/../../extras/android/support/v4/android-support-v4.jar";
fi
ANDROID_PLATFORM_TOOLS="${android_platform_tools}"
ANDROID_BUILD_TOOLS="${android_build_tools}"
AC_SUBST(ANDROID_SDK)
AC_SUBST(ANDROID_COMPAT_LIB)
if ! test -e $ANDROID_COMPAT_LIB ; then
AC_MSG_ERROR([You must download the Android support library when targeting Android. Run the Android SDK tool and install Android Support Library under Extras. See https://developer.android.com/tools/extras/support-library.html for more info. (looked for $ANDROID_COMPAT_LIB)])
fi
AC_SUBST(ANDROID_PLATFORM_TOOLS)
AC_SUBST(ANDROID_BUILD_TOOLS)
;;
esac

View File

@ -13,6 +13,8 @@ dir-tests := $(DEPTH)/$(mobile-tests)
include $(DEPTH)/config/autoconf.mk
ANDROID_APK_NAME := robocop-debug
ROBOTIUM_PATH = $(srcdir)/robotium-solo-3.6.jar
JAVAFILES = \
@ -81,9 +83,10 @@ GARBAGE += \
$(java-tests-dep) \
$(_JAVA_HARNESS) \
classes.dex \
robocop.ap_ \
robocop-debug-signed.apk \
robocop-debug-signed-unaligned.apk \
$(ANDROID_APK_NAME).ap_ \
$(ANDROID_APK_NAME)-unsigned-unaligned.apk \
$(ANDROID_APK_NAME)-unaligned.apk \
$(ANDROID_APK_NAME).apk \
$(robocop-deps) \
$(NULL)
@ -100,23 +103,28 @@ include $(topsrcdir)/config/android-common.mk
GENERATED_DIRS_tools = classes $(dir-tests)
libs:: robocop-debug-signed.apk
tools:: $(ANDROID_APK_NAME).apk
classes.dex: robocop.ap_
classes.dex: $(ANDROID_APK_NAME).ap_
classes.dex: $(robocop-deps)
classes.dex: $(java-harness-dep)
classes.dex: $(java-tests-dep)
$(JAVAC) $(JAVAC_FLAGS) -d classes $(JAVAFILES) $(_JAVA_HARNESS) $(java-tests-dep)
$(DX) --dex --output=$@ classes $(ROBOTIUM_PATH) $(ANDROID_COMPT_LIB)
robocop.ap_: AndroidManifest.xml $(TESTPATH)/assets/*
$(ANDROID_APK_NAME).ap_: AndroidManifest.xml $(TESTPATH)/assets/*
$(AAPT) package -f -M $< -I $(ANDROID_SDK)/android.jar -I . -S res -A $(TESTPATH)/assets -F $@ -J ./
robocop-debug-signed-unaligned.apk: robocop.ap_ classes.dex
$(APKBUILDER) $@ -v $(APKBUILDER_FLAGS) -z robocop.ap_ -f classes.dex
$(ANDROID_APK_NAME)-unsigned-unaligned.apk: $(ANDROID_APK_NAME).ap_ classes.dex
cp $< $@
$(ZIP) -v0 $@ classes.dex
robocop-debug-signed.apk: robocop-debug-signed-unaligned.apk
$(ZIPALIGN) -f -v 4 $^ $@
$(ANDROID_APK_NAME)-unaligned.apk: $(ANDROID_APK_NAME)-unsigned-unaligned.apk
cp $< $@
$(DEBUG_JARSIGNER) $@
$(ANDROID_APK_NAME).apk: $(ANDROID_APK_NAME)-unaligned.apk
$(ZIPALIGN) -f -v 4 $< $@
# PP_java-tests not fully usable here
# Intermediate step toward a library rule.

View File

@ -9,6 +9,8 @@ VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
ANDROID_APK_NAME := sutAgentAndroid
JAVAFILES = \
AlertLooperThread.java \
ASMozStub.java \
@ -39,10 +41,10 @@ RES_FILES = \
GARBAGE += \
AndroidManifest.xml \
classes.dex \
sutAgentAndroid.apk \
sutAgentAndroid.ap_ \
sutAgentAndroid-unsigned-unaligned.apk \
sutAgentAndroid-unaligned.apk \
$(ANDROID_APK_NAME).ap_ \
$(ANDROID_APK_NAME)-unsigned-unaligned.apk \
$(ANDROID_APK_NAME)-unaligned.apk \
$(ANDROID_APK_NAME).apk \
$(NULL)
GARBAGE_DIRS += network-libs
@ -56,23 +58,22 @@ include $(topsrcdir)/config/rules.mk
# include Android specific java flags - using these instead of what's in rules.mk
include $(topsrcdir)/config/android-common.mk
tools:: sutAgentAndroid.apk
tools:: $(ANDROID_APK_NAME).apk
classes.dex: $(JAVAFILES)
$(JAVAC) $(JAVAC_FLAGS) -d classes $(addprefix $(srcdir)/,$(JAVAFILES))
$(DX) --dex --output=$@ classes $(subst :, ,$(EXTRA_JARS))
sutAgentAndroid.ap_: $(srcdir)/AndroidManifest.xml
$(ANDROID_APK_NAME).ap_: AndroidManifest.xml
$(AAPT) package -f -M $< -I $(ANDROID_SDK)/android.jar -S res -F $@
sutAgentAndroid-unsigned-unaligned.apk: sutAgentAndroid.ap_ classes.dex
$(APKBUILDER) $@ -v $(APKBUILDER_FLAGS) -z sutAgentAndroid.ap_ -f classes.dex
sutAgentAndroid-unaligned.apk: sutAgentAndroid-unsigned-unaligned.apk
$(ANDROID_APK_NAME)-unsigned-unaligned.apk: $(ANDROID_APK_NAME).ap_ classes.dex
cp $< $@
ifdef JARSIGNER
$(JARSIGNER) $@
endif
$(ZIP) -v0 $@ classes.dex
sutAgentAndroid.apk: sutAgentAndroid-unaligned.apk
$(ZIPALIGN) -f -v 4 sutAgentAndroid-unaligned.apk $@
$(ANDROID_APK_NAME)-unaligned.apk: $(ANDROID_APK_NAME)-unsigned-unaligned.apk
cp $< $@
$(DEBUG_JARSIGNER) $@
$(ANDROID_APK_NAME).apk: $(ANDROID_APK_NAME)-unaligned.apk
$(ZIPALIGN) -f -v 4 $< $@

View File

@ -9,6 +9,8 @@ VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
ANDROID_APK_NAME := FenCP
JAVAFILES = \
DirCursor.java \
FenCP.java \
@ -28,7 +30,10 @@ RES_FILES = \
GARBAGE += \
AndroidManifest.xml \
classes.dex \
FenCP.apk \
$(ANDROID_APK_NAME).ap_ \
$(ANDROID_APK_NAME)-unsigned-unaligned.apk \
$(ANDROID_APK_NAME)-unaligned.apk \
$(ANDROID_APK_NAME).apk \
$(NULL)
GARBAGE_DIRS += network-libs
@ -40,23 +45,22 @@ include $(topsrcdir)/config/rules.mk
# include Android specific java flags - using these instead of what's in rules.mk
include $(topsrcdir)/config/android-common.mk
tools:: FenCP.apk
tools:: $(ANDROID_APK_NAME).apk
classes.dex: $(JAVAFILES)
$(JAVAC) $(JAVAC_FLAGS) -d classes $(addprefix $(srcdir)/,$(JAVAFILES))
$(DX) --dex --output=$@ classes
FenCP.ap_: $(srcdir)/AndroidManifest.xml
$(AAPT) package -f -M $(srcdir)/AndroidManifest.xml -I $(ANDROID_SDK)/android.jar -S res -F $@
$(ANDROID_APK_NAME).ap_: AndroidManifest.xml
$(AAPT) package -f -M $< -I $(ANDROID_SDK)/android.jar -S res -F $@
FenCP-unsigned-unaligned.apk: FenCP.ap_ classes.dex
$(APKBUILDER) $@ -v $(APKBUILDER_FLAGS) -z FenCP.ap_ -f classes.dex
$(ANDROID_APK_NAME)-unsigned-unaligned.apk: $(ANDROID_APK_NAME).ap_ classes.dex
cp $< $@
$(ZIP) -v0 $@ classes.dex
FenCP-unaligned.apk: FenCP-unsigned-unaligned.apk
cp FenCP-unsigned-unaligned.apk $@
ifdef JARSIGNER
$(JARSIGNER) $@
endif
$(ANDROID_APK_NAME)-unaligned.apk: $(ANDROID_APK_NAME)-unsigned-unaligned.apk
cp $< $@
$(DEBUG_JARSIGNER) $@
FenCP.apk: FenCP-unaligned.apk
$(ZIPALIGN) -f -v 4 FenCP-unaligned.apk $@
$(ANDROID_APK_NAME).apk: $(ANDROID_APK_NAME)-unaligned.apk
$(ZIPALIGN) -f -v 4 $< $@

View File

@ -9,6 +9,8 @@ VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
ANDROID_APK_NAME := FfxCP
JAVAFILES = \
DirCursor.java \
ffxcp.java \
@ -28,7 +30,10 @@ RES_FILES = \
GARBAGE += \
AndroidManifest.xml \
classes.dex \
FfxCP.apk \
$(ANDROID_APK_NAME).ap_ \
$(ANDROID_APK_NAME)-unsigned-unaligned.apk \
$(ANDROID_APK_NAME)-unaligned.apk \
$(ANDROID_APK_NAME).apk \
$(NULL)
GARBAGE_DIRS += network-libs
@ -40,23 +45,22 @@ include $(topsrcdir)/config/rules.mk
# include Android specific java flags - using these instead of what's in rules.mk
include $(topsrcdir)/config/android-common.mk
tools:: FfxCP.apk
tools:: $(ANDROID_APK_NAME).apk
classes.dex: $(JAVAFILES)
$(JAVAC) $(JAVAC_FLAGS) -d classes $(addprefix $(srcdir)/,$(JAVAFILES))
$(DX) --dex --output=$@ classes
FfxCP.ap_: $(srcdir)/AndroidManifest.xml
$(AAPT) package -f -M $(srcdir)/AndroidManifest.xml -I $(ANDROID_SDK)/android.jar -S res -F $@
$(ANDROID_APK_NAME).ap_: AndroidManifest.xml
$(AAPT) package -f -M $< -I $(ANDROID_SDK)/android.jar -S res -F $@
FfxCP-unsigned-unaligned.apk: FfxCP.ap_ classes.dex
$(APKBUILDER) $@ -v $(APKBUILDER_FLAGS) -z FfxCP.ap_ -f classes.dex
$(ANDROID_APK_NAME)-unsigned-unaligned.apk: $(ANDROID_APK_NAME).ap_ classes.dex
cp $< $@
$(ZIP) -v0 $@ classes.dex
FfxCP-unaligned.apk: FfxCP-unsigned-unaligned.apk
cp FfxCP-unsigned-unaligned.apk $@
ifdef JARSIGNER
$(JARSIGNER) $@
endif
$(ANDROID_APK_NAME)-unaligned.apk: $(ANDROID_APK_NAME)-unsigned-unaligned.apk
cp $< $@
$(DEBUG_JARSIGNER) $@
FfxCP.apk: FfxCP-unaligned.apk
$(ZIPALIGN) -f -v 4 FfxCP-unaligned.apk $@
$(ANDROID_APK_NAME).apk: $(ANDROID_APK_NAME)-unaligned.apk
$(ZIPALIGN) -f -v 4 $< $@

View File

@ -9,6 +9,8 @@ VPATH = @srcdir@
include $(DEPTH)/config/autoconf.mk
ANDROID_APK_NAME := Watcher
JAVAFILES = \
IWatcherService.java \
RedirOutputThread.java \
@ -32,7 +34,10 @@ RES_FILES = \
GARBAGE += \
AndroidManifest.xml \
classes.dex \
Watcher.apk \
$(ANDROID_APK_NAME).ap_ \
$(ANDROID_APK_NAME)-unsigned-unaligned.apk \
$(ANDROID_APK_NAME)-unaligned.apk \
$(ANDROID_APK_NAME).apk \
$(NULL)
GARBAGE_DIRS += res classes network-libs
@ -44,29 +49,23 @@ include $(topsrcdir)/config/rules.mk
# include Android specific java flags - using these instead of what's in rules.mk
include $(topsrcdir)/config/android-common.mk
tools:: Watcher.apk
tools:: $(ANDROID_APK_NAME).apk
classes.dex: $(JAVAFILES)
$(NSINSTALL) -D classes
$(JAVAC) $(JAVAC_FLAGS) -d classes $(addprefix $(srcdir)/,$(JAVAFILES))
$(DX) --dex --output=$@ classes
Watcher.ap_: $(srcdir)/AndroidManifest.xml
$(AAPT) package -f -M $(srcdir)/AndroidManifest.xml -I $(ANDROID_SDK)/android.jar -S res -F $@
$(ANDROID_APK_NAME).ap_: AndroidManifest.xml
$(AAPT) package -f -M $< -I $(ANDROID_SDK)/android.jar -S res -F $@
Watcher-unsigned-unaligned.apk: Watcher.ap_ classes.dex
$(APKBUILDER) $@ -v $(APKBUILDER_FLAGS) -z Watcher.ap_ -f classes.dex
$(ANDROID_APK_NAME)-unsigned-unaligned.apk: $(ANDROID_APK_NAME).ap_ classes.dex
cp $< $@
$(ZIP) -v0 $@ classes.dex
Watcher-unaligned.apk: Watcher-unsigned-unaligned.apk
cp Watcher-unsigned-unaligned.apk $@
ifdef JARSIGNER
$(JARSIGNER) $@
endif
Watcher.apk: Watcher-unaligned.apk
$(ZIPALIGN) -f -v 4 Watcher-unaligned.apk $@
export::
$(NSINSTALL) -D res
@(cd $(srcdir)/res && tar $(TAR_CREATE_FLAGS) - *) | (cd $(DEPTH)/build/mobile/sutagent/android/watcher/res && tar -xf -)
$(ANDROID_APK_NAME)-unaligned.apk: $(ANDROID_APK_NAME)-unsigned-unaligned.apk
cp $< $@
$(DEBUG_JARSIGNER) $@
$(ANDROID_APK_NAME).apk: $(ANDROID_APK_NAME)-unaligned.apk
$(ZIPALIGN) -f -v 4 $< $@

View File

@ -21,7 +21,6 @@ STDCXX_COMPAT =
ifneq (WINNT,$(HOST_OS_ARCH))
HOST_PROGRAM = nsinstall_real$(HOST_BIN_SUFFIX)
DISABLED_HOST_CSRCS = nsinstall.c pathsub.c
endif
ifndef CROSS_COMPILE

View File

@ -12,14 +12,11 @@ ifndef JAVA_CLASSPATH
$(error JAVA_CLASSPATH must be defined before including android-common.mk)
endif
DX=$(ANDROID_PLATFORM_TOOLS)/dx
AAPT=$(ANDROID_PLATFORM_TOOLS)/aapt
APKBUILDER=$(ANDROID_SDK)/../../tools/apkbuilder
DX=$(ANDROID_BUILD_TOOLS)/dx
AAPT=$(ANDROID_BUILD_TOOLS)/aapt
ZIPALIGN=$(ANDROID_SDK)/../../tools/zipalign
ifdef JARSIGNER
APKBUILDER_FLAGS += -u
endif
# DEBUG_JARSIGNER always debug signs.
DEBUG_JARSIGNER=$(PYTHON) $(call core_abspath,$(topsrcdir)/mobile/android/debug_sign_tool.py)
# For Android, this defaults to $(ANDROID_SDK)/android.jar
ifndef JAVA_BOOTCLASSPATH

View File

@ -16,6 +16,7 @@ endif
# responsibility between Makefile.in and mozbuild files.
_MOZBUILD_EXTERNAL_VARIABLES := \
DIRS \
HOST_CSRCS \
MODULE \
PARALLEL_DIRS \
TEST_DIRS \

View File

@ -510,17 +510,6 @@ public:
static nsresult GuessCharset(const char *aData, uint32_t aDataLen,
nsACString &aCharset);
/**
* Determine whether aContent is in some way associated with aForm. If the
* form is a container the only elements that are considered to be associated
* with a form are the elements that are contained within the form. If the
* form is a leaf element then all elements will be accepted into this list,
* since this can happen due to content fixup when a form spans table rows or
* table cells.
*/
static bool BelongsInForm(nsIContent *aForm,
nsIContent *aContent);
static nsresult CheckQName(const nsAString& aQualifiedName,
bool aNamespaceAware = true,
const PRUnichar** aColon = nullptr);

View File

@ -140,26 +140,6 @@ nsSimpleContentList::WrapObject(JSContext *cx, JS::Handle<JSObject*> scope)
return NodeListBinding::Wrap(cx, scope, this);
}
// nsFormContentList
nsFormContentList::nsFormContentList(nsIContent *aForm,
nsBaseContentList& aContentList)
: nsSimpleContentList(aForm)
{
// move elements that belong to mForm into this content list
uint32_t i, length = 0;
aContentList.GetLength(&length);
for (i = 0; i < length; i++) {
nsIContent *c = aContentList.Item(i);
if (c && nsContentUtils::BelongsInForm(aForm, c)) {
AppendElement(c);
}
}
}
// Hashtable for storing nsContentLists
static PLDHashTable gContentListHashTable;

View File

@ -124,16 +124,6 @@ private:
nsCOMPtr<nsINode> mRoot;
};
// This class is used only by form element code and this is a static
// list of elements. NOTE! This list holds strong references to
// the elements in the list.
class nsFormContentList : public nsSimpleContentList
{
public:
nsFormContentList(nsIContent *aForm,
nsBaseContentList& aContentList);
};
/**
* Class that's used as the key to hash nsContentList implementations
* for fast retrieval

View File

@ -2365,62 +2365,6 @@ nsContentUtils::NewURIWithDocumentCharset(nsIURI** aResult,
aBaseURI, sIOService);
}
// static
bool
nsContentUtils::BelongsInForm(nsIContent *aForm,
nsIContent *aContent)
{
NS_PRECONDITION(aForm, "Must have a form");
NS_PRECONDITION(aContent, "Must have a content node");
if (aForm == aContent) {
// A form does not belong inside itself, so we return false here
return false;
}
nsIContent* content = aContent->GetParent();
while (content) {
if (content == aForm) {
// aContent is contained within the form so we return true.
return true;
}
if (content->Tag() == nsGkAtoms::form &&
content->IsHTML()) {
// The child is contained within a form, but not the right form
// so we ignore it.
return false;
}
content = content->GetParent();
}
if (aForm->GetChildCount() > 0) {
// The form is a container but aContent wasn't inside the form,
// return false
return false;
}
// The form is a leaf and aContent wasn't inside any other form so
// we check whether the content comes after the form. If it does,
// return true. If it does not, then it couldn't have been inside
// the form in the HTML.
if (PositionIsBefore(aForm, aContent)) {
// We could be in this form!
// In the future, we may want to get document.forms, look at the
// form after aForm, and if aContent is after that form after
// aForm return false here....
return true;
}
return false;
}
// static
nsresult
nsContentUtils::CheckQName(const nsAString& aQualifiedName,

View File

@ -145,7 +145,7 @@ protected:
nsString mResult;
nsCOMPtr<nsIPrincipal> mPrincipal;
JSObject* mResultArrayBuffer;
JS::Heap<JSObject*> mResultArrayBuffer;
};
#endif

View File

@ -1786,7 +1786,7 @@ struct CustomPrototypeTraceArgs {
static PLDHashOperator
CustomPrototypeTrace(const nsAString& aName, JSObject*& aObject, void *aArg)
CustomPrototypeTrace(const nsAString& aName, JS::Heap<JSObject*>& aObject, void *aArg)
{
CustomPrototypeTraceArgs* traceArgs = static_cast<CustomPrototypeTraceArgs*>(aArg);
MOZ_ASSERT(aObject, "Protocol object value must not be null");

View File

@ -31,6 +31,7 @@
#include "nsBindingManager.h"
#include "nsINodeInfo.h"
#include "nsInterfaceHashtable.h"
#include "nsJSThingHashtable.h"
#include "nsIBoxObject.h"
#include "nsPIBoxObject.h"
#include "nsIScriptObjectPrincipal.h"
@ -1203,7 +1204,7 @@ protected:
// Hashtable for custom element prototypes in web components.
// Custom prototypes are in the document's compartment.
nsDataHashtable<nsStringHashKey, JSObject*> mCustomPrototypes;
nsJSThingHashtable<nsStringHashKey, JSObject*> mCustomPrototypes;
nsRefPtr<nsEventListenerManager> mListenerManager;
nsCOMPtr<nsIDOMStyleSheetList> mDOMStyleSheets;

View File

@ -25,6 +25,7 @@
#endif
#include "nsBindingManager.h"
#include "nsGenericHTMLElement.h"
#include "mozilla/dom/HTMLImageElement.h"
#include "mozilla/dom/HTMLMediaElement.h"
#include "nsWrapperCacheInlines.h"
#include "nsObjectLoadingContent.h"
@ -216,6 +217,11 @@ nsNodeUtils::LastRelease(nsINode* aNode)
// notify, since we're being destroyed in any case.
static_cast<nsGenericHTMLFormElement*>(aNode)->ClearForm(true);
}
if (aNode->IsElement() && aNode->AsElement()->IsHTML(nsGkAtoms::img)) {
HTMLImageElement* imageElem = static_cast<HTMLImageElement*>(aNode);
imageElem->ClearForm(true);
}
}
aNode->UnsetFlags(NODE_HAS_PROPERTIES);

View File

@ -782,12 +782,14 @@ nsXMLHttpRequest::CreateResponseParsedJSON(JSContext* aCx)
RootJSResultObjects();
// The Unicode converter has already zapped the BOM if there was one
JS::Rooted<JS::Value> value(aCx);
if (!JS_ParseJSON(aCx,
static_cast<const jschar*>(mResponseText.get()), mResponseText.Length(),
JS::MutableHandle<JS::Value>::fromMarkedLocation(&mResultJSON))) {
&value)) {
return NS_ERROR_FAILURE;
}
mResultJSON = value;
return NS_OK;
}

View File

@ -657,14 +657,14 @@ protected:
bool mFirstStartRequestSeen;
bool mInLoadProgressEvent;
nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
nsCOMPtr<nsIChannel> mNewRedirectChannel;
JS::Value mResultJSON;
JS::Heap<JS::Value> mResultJSON;
js::ArrayBufferBuilder mArrayBufferBuilder;
JSObject* mResultArrayBuffer;
JS::Heap<JSObject*> mResultArrayBuffer;
void ResetResponse();

View File

@ -69,7 +69,7 @@ private:
ImageData() MOZ_DELETE;
uint32_t mWidth, mHeight;
JSObject* mData;
JS::Heap<JSObject*> mData;
};
} // namespace dom

View File

@ -65,7 +65,7 @@ public:
}
private:
JS::Value mData;
JS::Heap<JS::Value> mData;
nsString mOrigin;
nsString mLastEventId;
nsCOMPtr<nsIDOMWindow> mSource;

View File

@ -70,7 +70,7 @@ private:
nsAutoArrayPtr<float> mFrameBuffer;
uint32_t mFrameBufferLength;
float mTime;
JSObject* mCachedArray;
JS::Heap<JSObject*> mCachedArray;
bool mAllowAudioData;
};

View File

@ -25,6 +25,7 @@
#include "nsContentPolicyUtils.h"
#include "nsIDOMWindow.h"
#include "nsFocusManager.h"
#include "nsHTMLFormElement.h"
#include "imgIContainer.h"
#include "imgILoader.h"
@ -67,6 +68,7 @@ namespace dom {
HTMLImageElement::HTMLImageElement(already_AddRefed<nsINodeInfo> aNodeInfo)
: nsGenericHTMLElement(aNodeInfo)
, mForm(nullptr)
{
// We start out broken
AddStatesSilently(NS_EVENT_STATE_BROKEN);
@ -84,7 +86,7 @@ NS_IMPL_RELEASE_INHERITED(HTMLImageElement, Element)
// QueryInterface implementation for HTMLImageElement
NS_INTERFACE_TABLE_HEAD(HTMLImageElement)
NS_INTERFACE_TABLE_HEAD_CYCLE_COLLECTION_INHERITED(HTMLImageElement)
NS_HTML_CONTENT_INTERFACES(nsGenericHTMLElement)
NS_INTERFACE_TABLE_INHERITED4(HTMLImageElement,
nsIDOMHTMLImageElement,
@ -296,6 +298,47 @@ HTMLImageElement::GetAttributeMappingFunction() const
}
nsresult
HTMLImageElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValueOrString* aValue,
bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None && mForm &&
(aName == nsGkAtoms::name || aName == nsGkAtoms::id)) {
// remove the image from the hashtable as needed
nsAutoString tmp;
GetAttr(kNameSpaceID_None, aName, tmp);
if (!tmp.IsEmpty()) {
mForm->RemoveImageElementFromTable(this, tmp,
nsHTMLFormElement::AttributeUpdated);
}
}
return nsGenericHTMLElement::BeforeSetAttr(aNameSpaceID, aName,
aValue, aNotify);
}
nsresult
HTMLImageElement::AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValue* aValue, bool aNotify)
{
if (aNameSpaceID == kNameSpaceID_None && mForm &&
(aName == nsGkAtoms::name || aName == nsGkAtoms::id) &&
aValue && !aValue->IsEmptyString()) {
// add the image to the hashtable as needed
NS_ABORT_IF_FALSE(aValue->Type() == nsAttrValue::eAtom,
"Expected atom value for name/id");
mForm->AddImageElementToTable(this,
nsDependentAtomString(aValue->GetAtomValue()));
}
return nsGenericHTMLElement::AfterSetAttr(aNameSpaceID, aName,
aValue, aNotify);
}
nsresult
HTMLImageElement::PreHandleEvent(nsEventChainPreVisitor& aVisitor)
{
@ -414,6 +457,10 @@ HTMLImageElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
nsImageLoadingContent::BindToTree(aDocument, aParent, aBindingParent,
aCompileEventHandlers);
if (aParent) {
UpdateFormOwner();
}
if (HasAttr(kNameSpaceID_None, nsGkAtoms::src)) {
// FIXME: Bug 660963 it would be nice if we could just have
// ClearBrokenState update our state and do it fast...
@ -434,10 +481,45 @@ HTMLImageElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
void
HTMLImageElement::UnbindFromTree(bool aDeep, bool aNullParent)
{
if (mForm) {
if (aNullParent || !FindAncestorForm(mForm)) {
ClearForm(true);
} else {
UnsetFlags(MAYBE_ORPHAN_FORM_ELEMENT);
}
}
nsImageLoadingContent::UnbindFromTree(aDeep, aNullParent);
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
}
void
HTMLImageElement::UpdateFormOwner()
{
if (!mForm) {
mForm = FindAncestorForm();
}
if (mForm && !HasFlag(ADDED_TO_FORM)) {
// Now we need to add ourselves to the form
nsAutoString nameVal, idVal;
GetAttr(kNameSpaceID_None, nsGkAtoms::name, nameVal);
GetAttr(kNameSpaceID_None, nsGkAtoms::id, idVal);
SetFlags(ADDED_TO_FORM);
mForm->AddImageElement(this);
if (!nameVal.IsEmpty()) {
mForm->AddImageElementToTable(this, nameVal);
}
if (!idVal.IsEmpty()) {
mForm->AddImageElementToTable(this, idVal);
}
}
}
void
HTMLImageElement::MaybeLoadImage()
{
@ -577,5 +659,55 @@ HTMLImageElement::WrapNode(JSContext* aCx, JS::Handle<JSObject*> aScope)
return HTMLImageElementBinding::Wrap(aCx, aScope, this);
}
#ifdef DEBUG
nsIDOMHTMLFormElement*
HTMLImageElement::GetForm() const
{
return mForm;
}
#endif
void
HTMLImageElement::SetForm(nsIDOMHTMLFormElement* aForm)
{
NS_PRECONDITION(aForm, "Don't pass null here");
NS_ASSERTION(!mForm,
"We don't support switching from one non-null form to another.");
mForm = static_cast<nsHTMLFormElement*>(aForm);
}
void
HTMLImageElement::ClearForm(bool aRemoveFromForm)
{
NS_ASSERTION((mForm != nullptr) == HasFlag(ADDED_TO_FORM),
"Form control should have had flag set correctly");
if (!mForm) {
return;
}
if (aRemoveFromForm) {
nsAutoString nameVal, idVal;
GetAttr(kNameSpaceID_None, nsGkAtoms::name, nameVal);
GetAttr(kNameSpaceID_None, nsGkAtoms::id, idVal);
mForm->RemoveImageElement(this);
if (!nameVal.IsEmpty()) {
mForm->RemoveImageElementFromTable(this, nameVal,
nsHTMLFormElement::ElementRemoved);
}
if (!idVal.IsEmpty()) {
mForm->RemoveImageElementFromTable(this, idVal,
nsHTMLFormElement::ElementRemoved);
}
}
UnsetFlags(ADDED_TO_FORM);
mForm = nullptr;
}
} // namespace dom
} // namespace mozilla

View File

@ -174,12 +174,30 @@ public:
SetHTMLAttr(nsGkAtoms::lowsrc, aLowsrc, aError);
}
#ifdef DEBUG
nsIDOMHTMLFormElement* GetForm() const;
#endif
void SetForm(nsIDOMHTMLFormElement* aForm);
void ClearForm(bool aRemoveFromForm);
protected:
CSSIntPoint GetXY();
virtual void GetItemValueText(nsAString& text) MOZ_OVERRIDE;
virtual void SetItemValueText(const nsAString& text) MOZ_OVERRIDE;
virtual JSObject* WrapNode(JSContext *aCx,
JS::Handle<JSObject*> aScope) MOZ_OVERRIDE;
void UpdateFormOwner();
virtual nsresult BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValueOrString* aValue,
bool aNotify) MOZ_OVERRIDE;
virtual nsresult AfterSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
const nsAttrValue* aValue, bool aNotify) MOZ_OVERRIDE;
// This is a weak reference that this element and the HTMLFormElement
// cooperate in maintaining.
nsHTMLFormElement* mForm;
};
} // namespace dom

View File

@ -2179,11 +2179,13 @@ nsGenericHTMLFormElement::ClearForm(bool aRemoveFromForm)
mForm->RemoveElement(this, true);
if (!nameVal.IsEmpty()) {
mForm->RemoveElementFromTable(this, nameVal);
mForm->RemoveElementFromTable(this, nameVal,
nsHTMLFormElement::ElementRemoved);
}
if (!idVal.IsEmpty()) {
mForm->RemoveElementFromTable(this, idVal);
mForm->RemoveElementFromTable(this, idVal,
nsHTMLFormElement::ElementRemoved);
}
}
@ -2314,7 +2316,8 @@ nsGenericHTMLFormElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
GetAttr(kNameSpaceID_None, aName, tmp);
if (!tmp.IsEmpty()) {
mForm->RemoveElementFromTable(this, tmp);
mForm->RemoveElementFromTable(this, tmp,
nsHTMLFormElement::AttributeUpdated);
}
}
@ -2322,13 +2325,15 @@ nsGenericHTMLFormElement::BeforeSetAttr(int32_t aNameSpaceID, nsIAtom* aName,
GetAttr(kNameSpaceID_None, nsGkAtoms::name, tmp);
if (!tmp.IsEmpty()) {
mForm->RemoveElementFromTable(this, tmp);
mForm->RemoveElementFromTable(this, tmp,
nsHTMLFormElement::AttributeUpdated);
}
GetAttr(kNameSpaceID_None, nsGkAtoms::id, tmp);
if (!tmp.IsEmpty()) {
mForm->RemoveElementFromTable(this, tmp);
mForm->RemoveElementFromTable(this, tmp,
nsHTMLFormElement::AttributeUpdated);
}
mForm->RemoveElement(this, false);

View File

@ -1047,15 +1047,16 @@ class HTMLFieldSetElement;
// Form element specific bits
enum {
// If this flag is set on an nsGenericHTMLFormElement, that means that we have
// added ourselves to our mForm. It's possible to have a non-null mForm, but
// not have this flag set. That happens when the form is set via the content
// sink.
// If this flag is set on an nsGenericHTMLFormElement or an HTMLImageElement,
// that means that we have added ourselves to our mForm. It's possible to
// have a non-null mForm, but not have this flag set. That happens when the
// form is set via the content sink.
ADDED_TO_FORM = FORM_ELEMENT_FLAG_BIT(0),
// If this flag is set on an nsGenericHTMLFormElement, that means that its form
// is in the process of being unbound from the tree, and this form element
// hasn't re-found its form in nsGenericHTMLFormElement::UnbindFromTree yet.
// If this flag is set on an nsGenericHTMLFormElement or an HTMLImageElement,
// that means that its form is in the process of being unbound from the tree,
// and this form element hasn't re-found its form in
// nsGenericHTMLFormElement::UnbindFromTree yet.
MAYBE_ORPHAN_FORM_ELEMENT = FORM_ELEMENT_FLAG_BIT(1)
};

View File

@ -54,6 +54,9 @@
#include "mozilla/dom/BindingUtils.h"
#include "nsSandboxFlags.h"
// images
#include "mozilla/dom/HTMLImageElement.h"
using namespace mozilla::dom;
static const int NS_FORM_CONTROL_LIST_HASHTABLE_SIZE = 16;
@ -104,6 +107,8 @@ public:
nsresult AddElementToTable(nsGenericHTMLFormElement* aChild,
const nsAString& aName);
nsresult AddImageElementToTable(HTMLImageElement* aChild,
const nsAString& aName);
nsresult RemoveElementFromTable(nsGenericHTMLFormElement* aChild,
const nsAString& aName);
nsresult IndexOfControl(nsIFormControl* aControl,
@ -241,6 +246,8 @@ nsHTMLFormElement::nsHTMLFormElement(already_AddRefed<nsINodeInfo> aNodeInfo)
mInvalidElementsCount(0),
mEverTriedInvalidSubmit(false)
{
mImageNameLookupTable.Init(NS_FORM_CONTROL_LIST_HASHTABLE_SIZE);
mPastNameLookupTable.Init(NS_FORM_CONTROL_LIST_HASHTABLE_SIZE);
}
nsHTMLFormElement::~nsHTMLFormElement()
@ -248,6 +255,8 @@ nsHTMLFormElement::~nsHTMLFormElement()
if (mControls) {
mControls->DropFormReference();
}
Clear();
}
nsresult
@ -290,9 +299,16 @@ ElementTraverser(const nsAString& key, nsIDOMHTMLInputElement* element,
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN_INHERITED(nsHTMLFormElement,
nsGenericHTMLElement)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mControls)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mImageNameLookupTable)
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mPastNameLookupTable)
tmp->mSelectedRadioButtons.EnumerateRead(ElementTraverser, &cb);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN_INHERITED(nsHTMLFormElement,
nsGenericHTMLElement)
tmp->Clear();
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
NS_IMPL_ADDREF_INHERITED(nsHTMLFormElement, Element)
NS_IMPL_RELEASE_INHERITED(nsHTMLFormElement, Element)
@ -455,8 +471,9 @@ nsHTMLFormElement::BindToTree(nsIDocument* aDocument, nsIContent* aParent,
return rv;
}
template<typename T>
static void
MarkOrphans(const nsTArray<nsGenericHTMLFormElement*>& aArray)
MarkOrphans(const nsTArray<T*>& aArray)
{
uint32_t length = aArray.Length();
for (uint32_t i = 0; i < length; ++i) {
@ -483,8 +500,7 @@ CollectOrphans(nsINode* aRemovalRoot,
// Now if MAYBE_ORPHAN_FORM_ELEMENT is not set, that would mean that the
// node is in fact a descendant of the form and hence should stay in the
// form. If it _is_ set, then we need to check whether the node is a
// descendant of aRemovalRoot. If it is, we leave it in the form. See
// also the code in nsGenericHTMLFormElement::FindForm.
// descendant of aRemovalRoot. If it is, we leave it in the form.
#ifdef DEBUG
bool removed = false;
#endif
@ -511,6 +527,46 @@ CollectOrphans(nsINode* aRemovalRoot,
}
}
static void
CollectOrphans(nsINode* aRemovalRoot,
const nsTArray<HTMLImageElement*>& aArray
#ifdef DEBUG
, nsIDOMHTMLFormElement* aThisForm
#endif
)
{
// Walk backwards so that if we remove elements we can just keep iterating
uint32_t length = aArray.Length();
for (uint32_t i = length; i > 0; --i) {
HTMLImageElement* node = aArray[i-1];
// Now if MAYBE_ORPHAN_FORM_ELEMENT is not set, that would mean that the
// node is in fact a descendant of the form and hence should stay in the
// form. If it _is_ set, then we need to check whether the node is a
// descendant of aRemovalRoot. If it is, we leave it in the form.
#ifdef DEBUG
bool removed = false;
#endif
if (node->HasFlag(MAYBE_ORPHAN_FORM_ELEMENT)) {
node->UnsetFlags(MAYBE_ORPHAN_FORM_ELEMENT);
if (!nsContentUtils::ContentIsDescendantOf(node, aRemovalRoot)) {
node->ClearForm(true);
#ifdef DEBUG
removed = true;
#endif
}
}
#ifdef DEBUG
if (!removed) {
nsCOMPtr<nsIDOMHTMLFormElement> form = node->GetForm();
NS_ASSERTION(form == aThisForm, "How did that happen?");
}
#endif /* DEBUG */
}
}
void
nsHTMLFormElement::UnbindFromTree(bool aDeep, bool aNullParent)
{
@ -519,6 +575,7 @@ nsHTMLFormElement::UnbindFromTree(bool aDeep, bool aNullParent)
// Mark all of our controls as maybe being orphans
MarkOrphans(mControls->mElements);
MarkOrphans(mControls->mNotInElements);
MarkOrphans(mImageElements);
nsGenericHTMLElement::UnbindFromTree(aDeep, aNullParent);
@ -535,17 +592,22 @@ nsHTMLFormElement::UnbindFromTree(bool aDeep, bool aNullParent)
CollectOrphans(ancestor, mControls->mElements
#ifdef DEBUG
, this
#endif
#endif
);
CollectOrphans(ancestor, mControls->mNotInElements
#ifdef DEBUG
, this
#endif
#endif
);
CollectOrphans(ancestor, mImageElements
#ifdef DEBUG
, this
#endif
);
if (oldDocument) {
oldDocument->RemovedForm();
}
}
ForgetCurrentSubmission();
}
@ -1034,18 +1096,17 @@ nsHTMLFormElement::GetElementAt(int32_t aIndex) const
* 0 otherwise
*/
static inline int32_t
CompareFormControlPosition(nsGenericHTMLFormElement *aControl1,
nsGenericHTMLFormElement *aControl2,
CompareFormControlPosition(Element *aElement1, Element *aElement2,
const nsIContent* aForm)
{
NS_ASSERTION(aControl1 != aControl2, "Comparing a form control to itself");
NS_ASSERTION(aElement1 != aElement2, "Comparing a form control to itself");
// If an element has a @form, we can assume it *might* be able to not have
// a parent and still be in the form.
NS_ASSERTION((aControl1->HasAttr(kNameSpaceID_None, nsGkAtoms::form) ||
aControl1->GetParent()) &&
(aControl2->HasAttr(kNameSpaceID_None, nsGkAtoms::form) ||
aControl2->GetParent()),
NS_ASSERTION((aElement1->HasAttr(kNameSpaceID_None, nsGkAtoms::form) ||
aElement1->GetParent()) &&
(aElement2->HasAttr(kNameSpaceID_None, nsGkAtoms::form) ||
aElement2->GetParent()),
"Form controls should always have parents");
// If we pass aForm, we are assuming both controls are form descendants which
@ -1054,15 +1115,15 @@ CompareFormControlPosition(nsGenericHTMLFormElement *aControl1,
// TODO: remove the prevent asserts fix, see bug 598468.
#ifdef DEBUG
nsLayoutUtils::gPreventAssertInCompareTreePosition = true;
int32_t rVal = nsLayoutUtils::CompareTreePosition(aControl1, aControl2, aForm);
int32_t rVal = nsLayoutUtils::CompareTreePosition(aElement1, aElement2, aForm);
nsLayoutUtils::gPreventAssertInCompareTreePosition = false;
return rVal;
#else // DEBUG
return nsLayoutUtils::CompareTreePosition(aControl1, aControl2, aForm);
return nsLayoutUtils::CompareTreePosition(aElement1, aElement2, aForm);
#endif // DEBUG
}
#ifdef DEBUG
/**
* Checks that all form elements are in document order. Asserts if any pair of
@ -1106,6 +1167,57 @@ nsHTMLFormElement::PostPasswordEvent()
event->PostDOMEvent();
}
// This function return true if the element, once appended, is the last one in
// the array.
template<typename ElementType>
static bool
AddElementToList(nsTArray<ElementType*>& aList, ElementType* aChild,
nsHTMLFormElement* aForm)
{
NS_ASSERTION(aList.IndexOf(aChild) == aList.NoIndex,
"aChild already in aList");
uint32_t count = aList.Length();
ElementType* element;
bool lastElement = false;
// Optimize most common case where we insert at the end.
int32_t position = -1;
if (count > 0) {
element = aList[count - 1];
position = CompareFormControlPosition(aChild, element, aForm);
}
// If this item comes after the last element, or the elements array is
// empty, we append to the end. Otherwise, we do a binary search to
// determine where the element should go.
if (position >= 0 || count == 0) {
// WEAK - don't addref
aList.AppendElement(aChild);
lastElement = true;
}
else {
int32_t low = 0, mid, high;
high = count - 1;
while (low <= high) {
mid = (low + high) / 2;
element = aList[mid];
position = CompareFormControlPosition(aChild, element, aForm);
if (position >= 0)
low = mid + 1;
else
high = mid - 1;
}
// WEAK - don't addref
aList.InsertElementAt(low, aChild);
}
return lastElement;
}
nsresult
nsHTMLFormElement::AddElement(nsGenericHTMLFormElement* aChild,
bool aUpdateValidity, bool aNotify)
@ -1121,47 +1233,8 @@ nsHTMLFormElement::AddElement(nsGenericHTMLFormElement* aChild,
bool childInElements = ShouldBeInElements(aChild);
nsTArray<nsGenericHTMLFormElement*>& controlList = childInElements ?
mControls->mElements : mControls->mNotInElements;
NS_ASSERTION(controlList.IndexOf(aChild) == controlList.NoIndex,
"Form control already in form");
uint32_t count = controlList.Length();
nsGenericHTMLFormElement* element;
// Optimize most common case where we insert at the end.
bool lastElement = false;
int32_t position = -1;
if (count > 0) {
element = controlList[count - 1];
position = CompareFormControlPosition(aChild, element, this);
}
// If this item comes after the last element, or the elements array is
// empty, we append to the end. Otherwise, we do a binary search to
// determine where the element should go.
if (position >= 0 || count == 0) {
// WEAK - don't addref
controlList.AppendElement(aChild);
lastElement = true;
}
else {
int32_t low = 0, mid, high;
high = count - 1;
while (low <= high) {
mid = (low + high) / 2;
element = controlList[mid];
position = CompareFormControlPosition(aChild, element, this);
if (position >= 0)
low = mid + 1;
else
high = mid - 1;
}
// WEAK - don't addref
controlList.InsertElementAt(low, aChild);
}
bool lastElement = AddElementToList(controlList, aChild, this);
#ifdef DEBUG
AssertDocumentOrder(controlList, this);
@ -1359,10 +1432,74 @@ nsHTMLFormElement::HandleDefaultSubmitRemoval()
}
}
static nsresult
RemoveElementFromTableInternal(
nsInterfaceHashtable<nsStringHashKey,nsISupports>& aTable,
nsIContent* aChild, const nsAString& aName)
{
nsCOMPtr<nsISupports> supports;
if (!aTable.Get(aName, getter_AddRefs(supports)))
return NS_OK;
// Single element in the hash, just remove it if it's the one
// we're trying to remove...
if (supports == aChild) {
aTable.Remove(aName);
return NS_OK;
}
nsCOMPtr<nsIContent> content(do_QueryInterface(supports));
if (content) {
return NS_OK;
}
nsCOMPtr<nsIDOMNodeList> nodeList(do_QueryInterface(supports));
NS_ENSURE_TRUE(nodeList, NS_ERROR_FAILURE);
// Upcast, uggly, but it works!
nsBaseContentList *list = static_cast<nsBaseContentList*>(nodeList.get());
list->RemoveElement(aChild);
uint32_t length = 0;
list->GetLength(&length);
if (!length) {
// If the list is empty we remove if from our hash, this shouldn't
// happen tho
aTable.Remove(aName);
} else if (length == 1) {
// Only one element left, replace the list in the hash with the
// single element.
nsIContent* node = list->Item(0);
if (node) {
aTable.Put(aName, node);
}
}
return NS_OK;
}
static PLDHashOperator
RemovePastNames(const nsAString& aName,
nsCOMPtr<nsISupports>& aData,
void* aClosure)
{
return aClosure == aData ? PL_DHASH_REMOVE : PL_DHASH_NEXT;
}
nsresult
nsHTMLFormElement::RemoveElementFromTable(nsGenericHTMLFormElement* aElement,
const nsAString& aName)
const nsAString& aName,
RemoveElementReason aRemoveReason)
{
// If the element is being removed from the form, we have to remove it from
// the past names map.
if (aRemoveReason == ElementRemoved) {
mPastNameLookupTable.Enumerate(RemovePastNames, aElement);
}
return mControls->RemoveElementFromTable(aElement, aName);
}
@ -1374,16 +1511,24 @@ nsHTMLFormElement::FindNamedItem(const nsAString& aName,
if (result) {
// FIXME Get the wrapper cache from DoResolveName.
*aCache = nullptr;
AddToPastNamesMap(aName, result);
return result.forget();
}
nsCOMPtr<nsIHTMLDocument> htmlDoc = do_QueryInterface(GetCurrentDoc());
if (!htmlDoc) {
result = mImageNameLookupTable.GetWeak(aName);
if (result) {
*aCache = nullptr;
return nullptr;
AddToPastNamesMap(aName, result);
return result.forget();
}
return htmlDoc->ResolveName(aName, this, aCache);
result = mPastNameLookupTable.GetWeak(aName);
if (result) {
*aCache = nullptr;
return result.forget();
}
return nullptr;
}
already_AddRefed<nsISupports>
@ -1910,7 +2055,7 @@ nsHTMLFormElement::OnSecurityChange(nsIWebProgress* aWebProgress,
NS_NOTREACHED("notification excluded in AddProgressListener(...)");
return NS_OK;
}
NS_IMETHODIMP_(int32_t)
nsHTMLFormElement::IndexOfControl(nsIFormControl* aControl)
{
@ -2141,6 +2286,17 @@ nsHTMLFormElement::IntrinsicState() const
return state;
}
void
nsHTMLFormElement::Clear()
{
for (int32_t i = mImageElements.Length() - 1; i >= 0; i--) {
mImageElements[i]->ClearForm(false);
}
mImageElements.Clear();
mImageNameLookupTable.Clear();
mPastNameLookupTable.Clear();
}
//----------------------------------------------------------------------
// nsFormControlList implementation, this could go away if there were
// a lightweight collection implementation somewhere
@ -2229,7 +2385,7 @@ NS_IMPL_CYCLE_COLLECTING_RELEASE(nsFormControlList)
// nsIDOMHTMLCollection interface
NS_IMETHODIMP
NS_IMETHODIMP
nsFormControlList::GetLength(uint32_t* aLength)
{
FlushPendingNotifications();
@ -2298,20 +2454,17 @@ nsFormControlList::NamedItemInternal(const nsAString& aName,
return mNameLookupTable.GetWeak(aName);
}
nsresult
nsFormControlList::AddElementToTable(nsGenericHTMLFormElement* aChild,
const nsAString& aName)
static nsresult
AddElementToTableInternal(
nsInterfaceHashtable<nsStringHashKey,nsISupports>& aTable,
nsIContent* aChild, const nsAString& aName, nsHTMLFormElement* aForm)
{
if (!ShouldBeInElements(aChild)) {
return NS_OK;
}
nsCOMPtr<nsISupports> supports;
mNameLookupTable.Get(aName, getter_AddRefs(supports));
aTable.Get(aName, getter_AddRefs(supports));
if (!supports) {
// No entry found, add the form control
mNameLookupTable.Put(aName, NS_ISUPPORTS_CAST(nsIContent*, aChild));
// No entry found, add the element
aTable.Put(aName, aChild);
} else {
// Found something in the hash, check its type
nsCOMPtr<nsIContent> content = do_QueryInterface(supports);
@ -2327,7 +2480,7 @@ nsFormControlList::AddElementToTable(nsGenericHTMLFormElement* aChild,
// Found an element, create a list, add the element to the list and put
// the list in the hash
nsSimpleContentList *list = new nsSimpleContentList(mForm);
nsSimpleContentList *list = new nsSimpleContentList(aForm);
// If an element has a @form, we can assume it *might* be able to not have
// a parent and still be in the form.
@ -2337,14 +2490,14 @@ nsFormControlList::AddElementToTable(nsGenericHTMLFormElement* aChild,
// Determine the ordering between the new and old element.
bool newFirst = nsContentUtils::PositionIsBefore(aChild, content);
list->AppendElement(newFirst ? aChild : content);
list->AppendElement(newFirst ? content : aChild);
list->AppendElement(newFirst ? aChild : content.get());
list->AppendElement(newFirst ? content.get() : aChild);
nsCOMPtr<nsISupports> listSupports = do_QueryObject(list);
// Replace the element with the list.
mNameLookupTable.Put(aName, listSupports);
aTable.Put(aName, listSupports);
} else {
// There's already a list in the hash, add the child to the list
nsCOMPtr<nsIDOMNodeList> nodeList = do_QueryInterface(supports);
@ -2395,6 +2548,17 @@ nsFormControlList::AddElementToTable(nsGenericHTMLFormElement* aChild,
return NS_OK;
}
nsresult
nsFormControlList::AddElementToTable(nsGenericHTMLFormElement* aChild,
const nsAString& aName)
{
if (!ShouldBeInElements(aChild)) {
return NS_OK;
}
return AddElementToTableInternal(mNameLookupTable, aChild, aName, mForm);
}
nsresult
nsFormControlList::IndexOfControl(nsIFormControl* aControl,
int32_t* aIndex)
@ -2416,48 +2580,7 @@ nsFormControlList::RemoveElementFromTable(nsGenericHTMLFormElement* aChild,
return NS_OK;
}
nsCOMPtr<nsISupports> supports;
if (!mNameLookupTable.Get(aName, getter_AddRefs(supports)))
return NS_OK;
nsCOMPtr<nsIFormControl> fctrl(do_QueryInterface(supports));
if (fctrl) {
// Single element in the hash, just remove it if it's the one
// we're trying to remove...
if (fctrl == aChild) {
mNameLookupTable.Remove(aName);
}
return NS_OK;
}
nsCOMPtr<nsIDOMNodeList> nodeList(do_QueryInterface(supports));
NS_ENSURE_TRUE(nodeList, NS_ERROR_FAILURE);
// Upcast, uggly, but it works!
nsBaseContentList *list = static_cast<nsBaseContentList*>(nodeList.get());
list->RemoveElement(aChild);
uint32_t length = 0;
list->GetLength(&length);
if (!length) {
// If the list is empty we remove if from our hash, this shouldn't
// happen tho
mNameLookupTable.Remove(aName);
} else if (length == 1) {
// Only one element left, replace the list in the hash with the
// single element.
nsIContent* node = list->Item(0);
if (node) {
mNameLookupTable.Put(aName, node);
}
}
return NS_OK;
return RemoveElementFromTableInternal(mNameLookupTable, aChild, aName);
}
nsresult
@ -2581,3 +2704,55 @@ nsFormControlList::GetSupportedNames(nsTArray<nsString>& aNames)
// this enumeration.
mNameLookupTable.EnumerateRead(CollectNames, &aNames);
}
nsresult
nsHTMLFormElement::AddImageElement(HTMLImageElement* aChild)
{
AddElementToList(mImageElements, aChild, this);
return NS_OK;
}
nsresult
nsHTMLFormElement::AddImageElementToTable(HTMLImageElement* aChild,
const nsAString& aName)
{
return AddElementToTableInternal(mImageNameLookupTable, aChild, aName, this);
}
nsresult
nsHTMLFormElement::RemoveImageElement(HTMLImageElement* aChild)
{
uint32_t index = mImageElements.IndexOf(aChild);
NS_ENSURE_STATE(index != mImageElements.NoIndex);
mImageElements.RemoveElementAt(index);
return NS_OK;
}
nsresult
nsHTMLFormElement::RemoveImageElementFromTable(HTMLImageElement* aElement,
const nsAString& aName,
RemoveElementReason aRemoveReason)
{
// If the element is being removed from the form, we have to remove it from
// the past names map.
if (aRemoveReason == ElementRemoved) {
mPastNameLookupTable.Enumerate(RemovePastNames, aElement);
}
return RemoveElementFromTableInternal(mImageNameLookupTable, aElement, aName);
}
void
nsHTMLFormElement::AddToPastNamesMap(const nsAString& aName,
nsISupports* aChild)
{
// If candidates contains exactly one node. Add a mapping from name to the
// node in candidates in the form element's past names map, replacing the
// previous entry with the same name, if any.
nsCOMPtr<nsIContent> node = do_QueryInterface(aChild);
if (node) {
mPastNameLookupTable.Put(aName, aChild);
}
}

View File

@ -32,6 +32,12 @@ class nsFormControlList;
class nsIMutableArray;
class nsIURI;
namespace mozilla {
namespace dom {
class HTMLImageElement;
}
}
class nsHTMLFormElement : public nsGenericHTMLElement,
public nsIDOMHTMLFormElement,
public nsIWebProgressListener,
@ -121,8 +127,8 @@ public:
virtual nsresult Clone(nsINodeInfo *aNodeInfo, nsINode **aResult) const MOZ_OVERRIDE;
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED_NO_UNLINK(nsHTMLFormElement,
nsGenericHTMLElement)
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(nsHTMLFormElement,
nsGenericHTMLElement)
/**
* Remove an element from this form's list of elements
@ -143,10 +149,20 @@ public:
*
* @param aElement the element to remove
* @param aName the name or id of the element to remove
* @param aRemoveReason describe why this element is removed. If the element
* is removed because it's removed from the form, it will be removed
* from the past names map too, otherwise it will stay in the past
* names map.
* @return NS_OK if the element was successfully removed.
*/
enum RemoveElementReason {
AttributeUpdated,
ElementRemoved
};
nsresult RemoveElementFromTable(nsGenericHTMLFormElement* aElement,
const nsAString& aName);
const nsAString& aName,
RemoveElementReason aRemoveReason);
/**
* Add an element to end of this form's list of elements
*
@ -158,7 +174,7 @@ public:
nsresult AddElement(nsGenericHTMLFormElement* aElement, bool aUpdateValidity,
bool aNotify);
/**
/**
* Add an element to the lookup table maintained by the form.
*
* We can't fold this method into AddElement() because when
@ -168,6 +184,47 @@ public:
*/
nsresult AddElementToTable(nsGenericHTMLFormElement* aChild,
const nsAString& aName);
/**
* Remove an image element from this form's list of image elements
*
* @param aElement the image element to remove
* @return NS_OK if the element was successfully removed.
*/
nsresult RemoveImageElement(mozilla::dom::HTMLImageElement* aElement);
/**
* Remove an image element from the lookup table maintained by the form.
* We can't fold this method into RemoveImageElement() because when
* RemoveImageElement() is called it doesn't know if the element is
* removed because the id attribute has changed, or because the
* name attribute has changed.
*
* @param aElement the image element to remove
* @param aName the name or id of the element to remove
* @return NS_OK if the element was successfully removed.
*/
nsresult RemoveImageElementFromTable(mozilla::dom::HTMLImageElement* aElement,
const nsAString& aName,
RemoveElementReason aRemoveReason);
/**
* Add an image element to the end of this form's list of image elements
*
* @param aElement the element to add
* @return NS_OK if the element was successfully added
*/
nsresult AddImageElement(mozilla::dom::HTMLImageElement* aElement);
/**
* Add an image element to the lookup table maintained by the form.
*
* We can't fold this method into AddImageElement() because when
* AddImageElement() is called, the image attributes can change.
* The name or id attributes of the image are used as a key into the table.
*/
nsresult AddImageElementToTable(mozilla::dom::HTMLImageElement* aChild,
const nsAString& aName);
/**
* Return whether there is one and only one input text control.
*
@ -363,6 +420,12 @@ protected:
*/
bool CheckFormValidity(nsIMutableArray* aInvalidElements) const;
// Clear the mImageNameLookupTable and mImageElements.
void Clear();
// Insert a element into the past names map.
void AddToPastNamesMap(const nsAString& aName, nsISupports* aChild);
public:
/**
* Flush a possible pending submission. If there was a scripted submission
@ -417,6 +480,25 @@ protected:
/** The first submit element in mNotInElements -- WEAK */
nsGenericHTMLFormElement* mFirstSubmitNotInElements;
// This array holds on to all HTMLImageElement(s).
// This is needed to properly clean up the bi-directional references
// (both weak and strong) between the form and its HTMLImageElements.
nsTArray<mozilla::dom::HTMLImageElement*> mImageElements; // Holds WEAK references
// A map from an ID or NAME attribute to the HTMLImageElement(s), this
// hash holds strong references either to the named HTMLImageElement, or
// to a list of named HTMLImageElement(s), in the case where this hash
// holds on to a list of named HTMLImageElement(s) the list has weak
// references to the HTMLImageElement.
nsInterfaceHashtable<nsStringHashKey,nsISupports> mImageNameLookupTable;
// A map from names to elements that were gotten by those names from this
// form in that past. See "past names map" in the HTML5 specification.
nsInterfaceHashtable<nsStringHashKey,nsISupports> mPastNameLookupTable;
/**
* Number of invalid and candidate for constraint validation elements in the
* form the last time UpdateValidity has been called.

View File

@ -378,6 +378,8 @@ MOCHITEST_FILES = \
wakelock.ogg \
wakelock.ogv \
test_bug869040.html \
test_bug870787.html \
test_bug879319.html \
allowMedia.sjs \
test_bug874758.html \
$(NULL)

View File

@ -0,0 +1,84 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=870787
-->
<head>
<title>Test for Bug 870787</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="reflect.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=870787">Mozilla Bug 870787</a>
<p id="msg"></p>
<form id="form0"></form>
<img name="img0" id="img0id">
<img name="img1" id="img1id" />
<form id="form1">
<img name="img2" id="img2id" />
</form>
<img name="img3" id="img3id" />
<table>
<form id="form2">
<tr><td>
<button name="input1" id="input1id" />
<input name="input2" id="input2id" />
</form>
</table>
<table>
<form id="form3">
<tr><td>
<img name="img4" id="img4id" />
<img name="img5" id="img5id" />
</form>
</table>
<form id="form4"><img id="img6"></form>
<pre id="test">
<script type="application/javascript">
/** Test for Bug 870787 **/
var form0 = document.getElementById("form0");
ok(form0, "Form0 exists");
ok(!form0.img0, "Form0.img0 doesn't exist");
ok(!form0.img0id, "Form0.img0id doesn't exist");
var form1 = document.getElementById("form1");
ok(form1, "Form1 exists");
ok(!form1.img1, "Form1.img1 doesn't exist");
ok(!form1.img1id, "Form1.img1id doesn't exist");
is(form1.img2, document.getElementById("img2id"), "Form1.img2 exists");
is(form1.img2id, document.getElementById("img2id"), "Form1.img2id exists");
ok(!form1.img3, "Form1.img3 doesn't exist");
ok(!form1.img3id, "Form1.img3id doesn't exist");
var form2 = document.getElementById("form2");
ok(form2, "Form2 exists");
is(form2.input1, document.getElementById("input1id"), "Form2.input1 exists");
is(form2.input1id, document.getElementById("input1id"), "Form2.input1id exists");
is(form2.input2, document.getElementById("input2id"), "Form2.input2 exists");
is(form2.input2id, document.getElementById("input2id"), "Form2.input2id exists");
var form3 = document.getElementById("form3");
ok(form3, "Form3 exists");
is(form3.img4, document.getElementById("img4id"), "Form3.img4 doesn't exists");
is(form3.img4id, document.getElementById("img4id"), "Form3.img4id doesn't exists");
is(form3.img5, document.getElementById("img5id"), "Form3.img5 doesn't exists");
is(form3.img5id, document.getElementById("img5id"), "Form3.img5id doesn't exists");
var form4 = document.getElementById("form4");
ok(form4, "Form4 exists");
is(Object.getOwnPropertyNames(form4.elements).indexOf("img6"), -1, "Form4.elements should not contain img6");
</script>
</pre>
</body>
</html>

View File

@ -0,0 +1,91 @@
<!DOCTYPE HTML>
<html>
<!--
https://bugzilla.mozilla.org/show_bug.cgi?id=879319
-->
<head>
<title>Test for Bug 879319</title>
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
<script type="application/javascript" src="reflect.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=879319">Mozilla Bug 879319</a>
<p id="msg"></p>
<form id="form">
<img id="img0" name="bar0" />
</form>
<input id="input0" name="foo0" form="form" />
<input id="input1" name="foo1" form="form" />
<input id="input2" name="foo2" form="form" />
<pre id="test">
<script type="application/javascript">
/** Test for Bug 879319 **/
var input0 = document.getElementById("input0");
ok(input0, "input0 exists");
var form = document.getElementById("form");
ok(form, "form exists");
is(form.foo0, input0, "Form.foo0 should exist");
ok("foo0" in form.elements, "foo0 in form.elements");
is(input0.form, form, "input0.form is form");
input0.setAttribute("name", "tmp0");
ok("tmp0" in form.elements, "tmp0 is in form.elements");
ok(!("foo0" in form.elements), "foo0 is not in form.elements");
is(form.tmp0, input0, "Form.tmp0 == input0");
is(form.foo0, input0, "Form.foo0 is still here");
input0.setAttribute("name", "tmp1");
ok("tmp1" in form.elements, "tmp1 is in form.elements");
ok(!("tmp0" in form.elements), "tmp0 is not in form.elements");
ok(!("foo0" in form.elements), "foo0 is not in form.elements");
is(form.tmp0, input0, "Form.tmp0 == input0");
is(form.tmp1, input0, "Form.tmp1 == input0");
is(form.foo0, input0, "Form.foo0 is still here");
input0.setAttribute("form", "");
ok(!("foo0" in form.elements), "foo0 is not in form.elements");
todo_is(form.foo0, undefined, "Form.foo0 should not still be here");
todo_is(form.tmp0, undefined, "Form.tmp0 should not still be here");
todo_is(form.tmp1, undefined, "Form.tmp1 should not still be here");
var input1 = document.getElementById("input1");
ok(input1, "input1 exists");
is(form.foo1, input1, "Form.foo1 should exist");
ok("foo1" in form.elements, "foo1 in form.elements");
is(input1.form, form, "input1.form is form");
input1.setAttribute("name", "foo0");
ok("foo0" in form.elements, "foo0 is in form.elements");
is(form.foo0, input1, "Form.foo0 should be input1");
is(form.foo1, input1, "Form.foo1 should be input1");
var input2 = document.getElementById("input2");
ok(input2, "input2 exists");
is(form.foo2, input2, "Form.foo2 should exist");
input2.parentNode.removeChild(input2);
ok(!("foo2" in form.elements), "foo2 is not in form.elements");
todo_is(form.foo2, undefined, "Form.foo2 should not longer be there");
var img0 = document.getElementById("img0");
ok(img0, "img0 exists");
is(form.bar0, img0, "Form.bar0 should exist");
img0.setAttribute("name", "old_bar0");
is(form.bar0, img0, "Form.bar0 is still here");
img0.parentNode.removeChild(img0);
todo_is(form.bar0, undefined, "Form.bar0 should not be here");
</script>
</pre>
</body>
</html>

View File

@ -2295,39 +2295,6 @@ nsHTMLDocument::ResolveName(const nsAString& aName, nsWrapperCache **aCache)
return nullptr;
}
already_AddRefed<nsISupports>
nsHTMLDocument::ResolveName(const nsAString& aName,
nsIContent *aForm,
nsWrapperCache **aCache)
{
nsISupports* result = ResolveName(aName, aCache);
if (!result) {
return nullptr;
}
nsCOMPtr<nsIContent> node = do_QueryInterface(result);
if (!node) {
// We create a nsFormContentList which will filter out the elements in the
// list that don't belong to aForm.
nsRefPtr<nsBaseContentList> list =
new nsFormContentList(aForm, *static_cast<nsBaseContentList*>(result));
if (list->Length() > 1) {
*aCache = list;
return list.forget();
}
// After the nsFormContentList is done filtering there's either nothing or
// one element in the list. Return that element, or null if there's no
// element in the list.
node = list->Item(0);
} else if (!nsContentUtils::BelongsInForm(aForm, node)) {
node = nullptr;
}
*aCache = node;
return node.forget();
}
JSObject*
nsHTMLDocument::NamedGetter(JSContext* cx, const nsAString& aName, bool& aFound,
ErrorResult& rv)

View File

@ -115,9 +115,6 @@ public:
JSObject* GetAll(JSContext* aCx, mozilla::ErrorResult& aRv);
nsISupports* ResolveName(const nsAString& aName, nsWrapperCache **aCache);
virtual already_AddRefed<nsISupports> ResolveName(const nsAString& aName,
nsIContent *aForm,
nsWrapperCache **aCache) MOZ_OVERRIDE;
virtual void AddedForm() MOZ_OVERRIDE;
virtual void RemovedForm() MOZ_OVERRIDE;
@ -297,7 +294,7 @@ protected:
nsRefPtr<nsContentList> mForms;
nsRefPtr<nsContentList> mFormControls;
JSObject* mAll;
JS::Heap<JSObject*> mAll;
/** # of forms in the document, synchronously set */
int32_t mNumForms;

View File

@ -33,10 +33,6 @@ public:
*/
virtual void SetCompatibilityMode(nsCompatibility aMode) = 0;
virtual already_AddRefed<nsISupports> ResolveName(const nsAString& aName,
nsIContent *aForm,
nsWrapperCache **aCache) = 0;
/**
* Called when form->BindToTree() is called so that document knows
* immediately when a form is added

View File

@ -1046,32 +1046,6 @@ void MediaDecoder::NotifyBytesConsumed(int64_t aBytes)
}
}
void MediaDecoder::NextFrameUnavailableBuffering()
{
MOZ_ASSERT(NS_IsMainThread());
if (!mOwner || mShuttingDown || !mDecoderStateMachine)
return;
mOwner->UpdateReadyStateForData(MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_BUFFERING);
}
void MediaDecoder::NextFrameAvailable()
{
MOZ_ASSERT(NS_IsMainThread());
if (!mOwner || mShuttingDown || !mDecoderStateMachine)
return;
mOwner->UpdateReadyStateForData(MediaDecoderOwner::NEXT_FRAME_AVAILABLE);
}
void MediaDecoder::NextFrameUnavailable()
{
MOZ_ASSERT(NS_IsMainThread());
if (!mOwner || mShuttingDown || !mDecoderStateMachine)
return;
mOwner->UpdateReadyStateForData(MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE);
}
void MediaDecoder::UpdateReadyStateForData()
{
MOZ_ASSERT(NS_IsMainThread());

View File

@ -710,12 +710,6 @@ public:
// This must be called on the main thread only.
void PlaybackPositionChanged();
// Calls mElement->UpdateReadyStateForData, telling it which state we have
// entered. Main thread only.
void NextFrameUnavailableBuffering();
void NextFrameAvailable();
void NextFrameUnavailable();
// Calls mElement->UpdateReadyStateForData, telling it whether we have
// data for the next frame and if we're buffering. Main thread only.
void UpdateReadyStateForData();

View File

@ -2620,21 +2620,16 @@ void MediaDecoderStateMachine::UpdateReadyState() {
}
mLastFrameStatus = nextFrameStatus;
/* This is a bit tricky. MediaDecoder::UpdateReadyStateForData will run on
* the main thread and re-evaluate GetNextFrameStatus there, passing it to
* HTMLMediaElement::UpdateReadyStateForData. It doesn't use the value of
* GetNextFrameStatus we computed here, because what we're computing here
* could be stale by the time MediaDecoder::UpdateReadyStateForData runs.
* We only compute GetNextFrameStatus here to avoid posting runnables to the main
* thread unnecessarily.
*/
nsCOMPtr<nsIRunnable> event;
switch (nextFrameStatus) {
case MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE_BUFFERING:
event = NS_NewRunnableMethod(mDecoder, &MediaDecoder::NextFrameUnavailableBuffering);
break;
case MediaDecoderOwner::NEXT_FRAME_AVAILABLE:
event = NS_NewRunnableMethod(mDecoder, &MediaDecoder::NextFrameAvailable);
break;
case MediaDecoderOwner::NEXT_FRAME_UNAVAILABLE:
event = NS_NewRunnableMethod(mDecoder, &MediaDecoder::NextFrameUnavailable);
break;
default:
PR_NOT_REACHED("unhandled frame state");
}
event = NS_NewRunnableMethod(mDecoder, &MediaDecoder::UpdateReadyStateForData);
NS_DispatchToMainThread(event, NS_DISPATCH_NORMAL);
}

View File

@ -79,7 +79,7 @@ AudioBuffer::InitializeBuffers(uint32_t aNumberOfChannels, JSContext* aJSContext
if (!array) {
return false;
}
mJSChannels.AppendElement(array);
mJSChannels.AppendElement(array.get());
}
return true;

View File

@ -116,7 +116,7 @@ protected:
nsRefPtr<AudioContext> mContext;
// Float32Arrays
AutoFallibleTArray<JSObject*,2> mJSChannels;
AutoFallibleTArray<JS::Heap<JSObject*>, 2> mJSChannels;
// mSharedChannels aggregates the data from mJSChannels. This is non-null
// if and only if the mJSChannels are neutered.

View File

@ -37,7 +37,7 @@ private:
void ClearCurve();
private:
JSObject* mCurve;
JS::Heap<JSObject*> mCurve;
};
}

View File

@ -0,0 +1,145 @@
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 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/. */
#ifndef nsXBLMaybeCompiled_h__
#define nsXBLMaybeCompiled_h__
#include "js/RootingAPI.h"
/*
* A union containing either a pointer representing uncompiled source or a
* JSObject* representing the compiled result. The class is templated on the
* source object type.
*
* The purpose of abstracting this as a separate class is to allow it to be
* wrapped in a JS::Heap<T> to correctly handle post-barriering of the JSObject
* pointer, when present.
*/
template <class UncompiledT>
class nsXBLMaybeCompiled
{
public:
nsXBLMaybeCompiled() : mUncompiled(BIT_UNCOMPILED) {}
nsXBLMaybeCompiled(UncompiledT* uncompiled)
: mUncompiled(reinterpret_cast<uintptr_t>(uncompiled) | BIT_UNCOMPILED) {}
nsXBLMaybeCompiled(JSObject* compiled) : mCompiled(compiled) {}
bool IsCompiled() const
{
return !(mUncompiled & BIT_UNCOMPILED);
}
UncompiledT* GetUncompiled() const
{
MOZ_ASSERT(!IsCompiled(), "Attempt to get compiled function as uncompiled");
uintptr_t unmasked = mUncompiled & ~BIT_UNCOMPILED;
return reinterpret_cast<UncompiledT*>(unmasked);
}
JSObject* GetJSFunction() const
{
MOZ_ASSERT(IsCompiled(), "Attempt to get uncompiled function as compiled");
return mCompiled;
}
private:
JSObject*& UnsafeGetJSFunction()
{
MOZ_ASSERT(IsCompiled(), "Attempt to get uncompiled function as compiled");
return mCompiled;
}
enum { BIT_UNCOMPILED = 1 << 0 };
union
{
// An pointer that represents the function before being compiled, with
// BIT_UNCOMPILED set.
uintptr_t mUncompiled;
// The JS object for the compiled result.
JSObject* mCompiled;
};
friend class js::RootMethods<nsXBLMaybeCompiled<UncompiledT> >;
};
/* Add support for JS::Heap<nsXBLMaybeCompiled>. */
namespace js {
template <class UncompiledT>
struct RootMethods<nsXBLMaybeCompiled<UncompiledT> > : public RootMethods<JSObject *>
{
typedef struct RootMethods<JSObject *> Base;
static nsXBLMaybeCompiled<UncompiledT> initial() { return nsXBLMaybeCompiled<UncompiledT>(); }
static bool poisoned(nsXBLMaybeCompiled<UncompiledT> function)
{
return function.IsCompiled() && Base::poisoned(function.GetJSFunction());
}
static bool needsPostBarrier(nsXBLMaybeCompiled<UncompiledT> function)
{
return function.IsCompiled() && Base::needsPostBarrier(function.GetJSFunction());
}
#ifdef JSGC_GENERATIONAL
static void postBarrier(nsXBLMaybeCompiled<UncompiledT>* functionp)
{
Base::postBarrier(&functionp->UnsafeGetJSFunction());
}
static void relocate(nsXBLMaybeCompiled<UncompiledT>* functionp)
{
Base::relocate(&functionp->UnsafeGetJSFunction());
}
#endif
};
template <class UncompiledT>
class HeapBase<nsXBLMaybeCompiled<UncompiledT> >
{
const JS::Heap<nsXBLMaybeCompiled<UncompiledT> >& wrapper() const {
return *static_cast<const JS::Heap<nsXBLMaybeCompiled<UncompiledT> >*>(this);
}
JS::Heap<nsXBLMaybeCompiled<UncompiledT> >& wrapper() {
return *static_cast<JS::Heap<nsXBLMaybeCompiled<UncompiledT> >*>(this);
}
const nsXBLMaybeCompiled<UncompiledT>* extract() const {
return wrapper().address();
}
nsXBLMaybeCompiled<UncompiledT>* extract() {
return wrapper().unsafeGet();
}
public:
bool IsCompiled() const { return extract()->IsCompiled(); }
UncompiledT* GetUncompiled() const { return extract()->GetUncompiled(); }
JSObject* GetJSFunction() const { return extract()->GetJSFunction(); }
void SetUncompiled(UncompiledT* source) {
wrapper().set(nsXBLMaybeCompiled<UncompiledT>(source));
}
void SetJSFunction(JSObject* function) {
wrapper().set(nsXBLMaybeCompiled<UncompiledT>(function));
}
JS::Heap<JSObject*>& AsHeapObject()
{
MOZ_ASSERT(extract()->IsCompiled());
return *reinterpret_cast<JS::Heap<JSObject*>*>(this);
}
};
} /* namespace js */
#endif // nsXBLMaybeCompiled_h__

View File

@ -24,8 +24,8 @@
using namespace mozilla;
nsXBLProtoImplMethod::nsXBLProtoImplMethod(const PRUnichar* aName) :
nsXBLProtoImplMember(aName),
mUncompiledMethod(BIT_UNCOMPILED)
nsXBLProtoImplMember(aName),
mMethod()
{
MOZ_COUNT_CTOR(nsXBLProtoImplMethod);
}
@ -108,12 +108,13 @@ nsXBLProtoImplMethod::InstallMember(JSContext* aCx,
NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
// now we want to reevaluate our property using aContext and the script object for this window...
if (mJSMethodObject) {
JS::Rooted<JSObject*> jsMethodObject(aCx, GetCompiledMethod());
if (jsMethodObject) {
nsDependentString name(mName);
// First, make the function in the compartment of the scope object.
JSAutoCompartment ac(aCx, scopeObject);
JS::Rooted<JSObject*> method(aCx, ::JS_CloneFunctionObject(aCx, mJSMethodObject, scopeObject));
JS::Rooted<JSObject*> method(aCx, ::JS_CloneFunctionObject(aCx, jsMethodObject, scopeObject));
if (!method) {
return NS_ERROR_OUT_OF_MEMORY;
}
@ -149,7 +150,7 @@ nsXBLProtoImplMethod::CompileMember(nsIScriptContext* aContext, const nsCString&
// No parameters or body was supplied, so don't install method.
if (!uncompiledMethod) {
// Early return after which we consider ourselves compiled.
mJSMethodObject = nullptr;
SetCompiledMethod(nullptr);
return NS_OK;
}
@ -159,7 +160,7 @@ nsXBLProtoImplMethod::CompileMember(nsIScriptContext* aContext, const nsCString&
delete uncompiledMethod;
// Early return after which we consider ourselves compiled.
mJSMethodObject = nullptr;
SetCompiledMethod(nullptr);
return NS_OK;
}
@ -219,7 +220,7 @@ nsXBLProtoImplMethod::CompileMember(nsIScriptContext* aContext, const nsCString&
return rv;
}
mJSMethodObject = methodObject;
SetCompiledMethod(methodObject);
return NS_OK;
}
@ -227,8 +228,8 @@ nsXBLProtoImplMethod::CompileMember(nsIScriptContext* aContext, const nsCString&
void
nsXBLProtoImplMethod::Trace(const TraceCallbacks& aCallbacks, void *aClosure)
{
if (IsCompiled() && mJSMethodObject) {
aCallbacks.Trace(&mJSMethodObject, "mJSMethodObject", aClosure);
if (IsCompiled() && GetCompiledMethod()) {
aCallbacks.Trace(&mMethod.AsHeapObject(), "mMethod", aClosure);
}
}
@ -243,11 +244,7 @@ nsXBLProtoImplMethod::Read(nsIScriptContext* aContext,
return rv;
}
mJSMethodObject = methodObject;
#ifdef DEBUG
mIsCompiled = true;
#endif
SetCompiledMethod(methodObject);
return NS_OK;
}
@ -256,15 +253,15 @@ nsresult
nsXBLProtoImplMethod::Write(nsIScriptContext* aContext,
nsIObjectOutputStream* aStream)
{
if (mJSMethodObject) {
MOZ_ASSERT(IsCompiled());
if (GetCompiledMethod()) {
nsresult rv = aStream->Write8(XBLBinding_Serialize_Method);
NS_ENSURE_SUCCESS(rv, rv);
rv = aStream->WriteWStringZ(mName);
NS_ENSURE_SUCCESS(rv, rv);
return XBL_SerializeFunction(aContext, aStream,
JS::Handle<JSObject*>::fromMarkedLocation(&mJSMethodObject));
return XBL_SerializeFunction(aContext, aStream, mMethod.AsHeapObject());
}
return NS_OK;
@ -275,7 +272,7 @@ nsXBLProtoImplAnonymousMethod::Execute(nsIContent* aBoundElement)
{
NS_PRECONDITION(IsCompiled(), "Can't execute uncompiled method");
if (!mJSMethodObject) {
if (!GetCompiledMethod()) {
// Nothing to do here
return NS_OK;
}
@ -327,7 +324,7 @@ nsXBLProtoImplAnonymousMethod::Execute(nsIContent* aBoundElement)
// Clone the function object, using thisObject as the parent so "this" is in
// the scope chain of the resulting function (for backwards compat to the
// days when this was an event handler).
JS::Rooted<JSObject*> method(cx, ::JS_CloneFunctionObject(cx, mJSMethodObject, thisObject));
JS::Rooted<JSObject*> method(cx, ::JS_CloneFunctionObject(cx, GetCompiledMethod(), thisObject));
if (!method)
return NS_ERROR_OUT_OF_MEMORY;
@ -364,12 +361,12 @@ nsXBLProtoImplAnonymousMethod::Write(nsIScriptContext* aContext,
nsIObjectOutputStream* aStream,
XBLBindingSerializeDetails aType)
{
if (mJSMethodObject) {
MOZ_ASSERT(IsCompiled());
if (GetCompiledMethod()) {
nsresult rv = aStream->Write8(aType);
NS_ENSURE_SUCCESS(rv, rv);
rv = XBL_SerializeFunction(aContext, aStream,
JS::Handle<JSObject*>::fromMarkedLocation(&mJSMethodObject));
rv = XBL_SerializeFunction(aContext, aStream, mMethod.AsHeapObject());
NS_ENSURE_SUCCESS(rv, rv);
}

View File

@ -11,6 +11,7 @@
#include "nsString.h"
#include "jsapi.h"
#include "nsString.h"
#include "nsXBLMaybeCompiled.h"
#include "nsXBLProtoImplMember.h"
#include "nsXBLSerialize.h"
@ -102,29 +103,31 @@ public:
bool IsCompiled() const
{
return !(mUncompiledMethod & BIT_UNCOMPILED);
return mMethod.IsCompiled();
}
void SetUncompiledMethod(nsXBLUncompiledMethod* aUncompiledMethod)
{
mUncompiledMethod = uintptr_t(aUncompiledMethod) | BIT_UNCOMPILED;
mMethod.SetUncompiled(aUncompiledMethod);
}
nsXBLUncompiledMethod* GetUncompiledMethod() const
{
uintptr_t unmasked = mUncompiledMethod & ~BIT_UNCOMPILED;
return reinterpret_cast<nsXBLUncompiledMethod*>(unmasked);
return mMethod.GetUncompiled();
}
protected:
enum { BIT_UNCOMPILED = 1 << 0 };
void SetCompiledMethod(JSObject* aCompiledMethod)
{
mMethod.SetJSFunction(aCompiledMethod);
}
union {
uintptr_t mUncompiledMethod; // An object that represents the method before being compiled.
JSObject* mJSMethodObject; // The JS object for the method (after compilation)
};
JSObject* GetCompiledMethod() const
{
return mMethod.GetJSFunction();
}
#ifdef DEBUG
bool mIsCompiled;
#endif
JS::Heap<nsXBLMaybeCompiled<nsXBLUncompiledMethod> > mMethod;
};
class nsXBLProtoImplAnonymousMethod : public nsXBLProtoImplMethod {

View File

@ -27,8 +27,6 @@ nsXBLProtoImplProperty::nsXBLProtoImplProperty(const PRUnichar* aName,
const PRUnichar* aReadOnly,
uint32_t aLineNumber) :
nsXBLProtoImplMember(aName),
mGetterText(nullptr),
mSetterText(nullptr),
mJSAttributes(JSPROP_ENUMERATE)
#ifdef DEBUG
, mIsCompiled(false)
@ -55,8 +53,6 @@ nsXBLProtoImplProperty::nsXBLProtoImplProperty(const PRUnichar* aName,
nsXBLProtoImplProperty::nsXBLProtoImplProperty(const PRUnichar* aName,
const bool aIsReadOnly)
: nsXBLProtoImplMember(aName),
mGetterText(nullptr),
mSetterText(nullptr),
mJSAttributes(JSPROP_ENUMERATE)
#ifdef DEBUG
, mIsCompiled(false)
@ -72,12 +68,20 @@ nsXBLProtoImplProperty::~nsXBLProtoImplProperty()
{
MOZ_COUNT_DTOR(nsXBLProtoImplProperty);
if (!(mJSAttributes & JSPROP_GETTER)) {
delete mGetterText;
if (!mGetter.IsCompiled()) {
delete mGetter.GetUncompiled();
}
if (!(mJSAttributes & JSPROP_SETTER)) {
delete mSetterText;
if (!mSetter.IsCompiled()) {
delete mSetter.GetUncompiled();
}
}
void nsXBLProtoImplProperty::EnsureUncompiledText(PropertyOp& aPropertyOp)
{
if (!aPropertyOp.GetUncompiled()) {
nsXBLTextWithLineNumber* text = new nsXBLTextWithLineNumber();
aPropertyOp.SetUncompiled(text);
}
}
@ -86,13 +90,8 @@ nsXBLProtoImplProperty::AppendGetterText(const nsAString& aText)
{
NS_PRECONDITION(!mIsCompiled,
"Must not be compiled when accessing getter text");
if (!mGetterText) {
mGetterText = new nsXBLTextWithLineNumber();
if (!mGetterText)
return;
}
mGetterText->AppendText(aText);
EnsureUncompiledText(mGetter);
mGetter.GetUncompiled()->AppendText(aText);
}
void
@ -100,13 +99,8 @@ nsXBLProtoImplProperty::AppendSetterText(const nsAString& aText)
{
NS_PRECONDITION(!mIsCompiled,
"Must not be compiled when accessing setter text");
if (!mSetterText) {
mSetterText = new nsXBLTextWithLineNumber();
if (!mSetterText)
return;
}
mSetterText->AppendText(aText);
EnsureUncompiledText(mSetter);
mSetter.GetUncompiled()->AppendText(aText);
}
void
@ -114,13 +108,8 @@ nsXBLProtoImplProperty::SetGetterLineNumber(uint32_t aLineNumber)
{
NS_PRECONDITION(!mIsCompiled,
"Must not be compiled when accessing getter text");
if (!mGetterText) {
mGetterText = new nsXBLTextWithLineNumber();
if (!mGetterText)
return;
}
mGetterText->SetLineNumber(aLineNumber);
EnsureUncompiledText(mGetter);
mGetter.GetUncompiled()->SetLineNumber(aLineNumber);
}
void
@ -128,13 +117,8 @@ nsXBLProtoImplProperty::SetSetterLineNumber(uint32_t aLineNumber)
{
NS_PRECONDITION(!mIsCompiled,
"Must not be compiled when accessing setter text");
if (!mSetterText) {
mSetterText = new nsXBLTextWithLineNumber();
if (!mSetterText)
return;
}
mSetterText->SetLineNumber(aLineNumber);
EnsureUncompiledText(mSetter);
mSetter.GetUncompiled()->SetLineNumber(aLineNumber);
}
const char* gPropertyArgs[] = { "val" };
@ -145,25 +129,26 @@ nsXBLProtoImplProperty::InstallMember(JSContext *aCx,
{
NS_PRECONDITION(mIsCompiled,
"Should not be installing an uncompiled property");
MOZ_ASSERT(mGetter.IsCompiled() && mSetter.IsCompiled());
MOZ_ASSERT(js::IsObjectInContextCompartment(aTargetClassObject, aCx));
JS::Rooted<JSObject*> globalObject(aCx, JS_GetGlobalForObject(aCx, aTargetClassObject));
JS::Rooted<JSObject*> scopeObject(aCx, xpc::GetXBLScope(aCx, globalObject));
NS_ENSURE_TRUE(scopeObject, NS_ERROR_OUT_OF_MEMORY);
// now we want to reevaluate our property using aContext and the script object for this window...
if (mJSGetterObject || mJSSetterObject) {
if (mGetter.GetJSFunction() || mSetter.GetJSFunction()) {
// First, enter the compartment of the scope object and clone the functions.
JSAutoCompartment ac(aCx, scopeObject);
JS::Rooted<JSObject*> getter(aCx, nullptr);
if (mJSGetterObject) {
if (!(getter = ::JS_CloneFunctionObject(aCx, mJSGetterObject, scopeObject)))
if (mGetter.GetJSFunction()) {
if (!(getter = ::JS_CloneFunctionObject(aCx, mGetter.GetJSFunction(), scopeObject)))
return NS_ERROR_OUT_OF_MEMORY;
}
JS::Rooted<JSObject*> setter(aCx, nullptr);
if (mJSSetterObject) {
if (!(setter = ::JS_CloneFunctionObject(aCx, mJSSetterObject, scopeObject)))
if (mSetter.GetJSFunction()) {
if (!(setter = ::JS_CloneFunctionObject(aCx, mSetter.GetJSFunction(), scopeObject)))
return NS_ERROR_OUT_OF_MEMORY;
}
@ -192,6 +177,7 @@ nsXBLProtoImplProperty::CompileMember(nsIScriptContext* aContext, const nsCStrin
"Trying to compile an already-compiled property");
NS_PRECONDITION(aClassObject,
"Must have class object to compile");
MOZ_ASSERT(!mGetter.IsCompiled() && !mSetter.IsCompiled());
if (!mName)
return NS_ERROR_FAILURE; // Without a valid name, we can't install the member.
@ -200,7 +186,7 @@ nsXBLProtoImplProperty::CompileMember(nsIScriptContext* aContext, const nsCStrin
nsresult rv = NS_OK;
nsAutoCString functionUri;
if (mGetterText || mSetterText) {
if (mGetter.GetUncompiled() || mSetter.GetUncompiled()) {
functionUri = aClassStr;
int32_t hash = functionUri.RFindChar('#');
if (hash != kNotFound) {
@ -209,13 +195,14 @@ nsXBLProtoImplProperty::CompileMember(nsIScriptContext* aContext, const nsCStrin
}
bool deletedGetter = false;
if (mGetterText && mGetterText->GetText()) {
nsDependentString getter(mGetterText->GetText());
nsXBLTextWithLineNumber *getterText = mGetter.GetUncompiled();
if (getterText && getterText->GetText()) {
nsDependentString getter(getterText->GetText());
if (!getter.IsEmpty()) {
AutoPushJSContext cx(aContext->GetNativeContext());
JSAutoCompartment ac(cx, aClassObject);
JS::CompileOptions options(cx);
options.setFileAndLine(functionUri.get(), mGetterText->GetLineNumber())
options.setFileAndLine(functionUri.get(), getterText->GetLineNumber())
.setVersion(JSVERSION_LATEST);
nsCString name = NS_LITERAL_CSTRING("get_") + NS_ConvertUTF16toUTF8(mName);
JS::RootedObject rootedNull(cx, nullptr); // See bug 781070.
@ -223,17 +210,16 @@ nsXBLProtoImplProperty::CompileMember(nsIScriptContext* aContext, const nsCStrin
rv = nsJSUtils::CompileFunction(cx, rootedNull, options, name, 0, nullptr,
getter, getterObject.address());
// Make sure we free mGetterText here before setting mJSGetterObject, since
// that'll overwrite mGetterText
delete mGetterText;
delete getterText;
deletedGetter = true;
mJSGetterObject = getterObject;
mGetter.SetJSFunction(getterObject);
if (mJSGetterObject && NS_SUCCEEDED(rv)) {
if (mGetter.GetJSFunction() && NS_SUCCEEDED(rv)) {
mJSAttributes |= JSPROP_GETTER | JSPROP_SHARED;
}
if (NS_FAILED(rv)) {
mJSGetterObject = nullptr;
mGetter.SetJSFunction(nullptr);
mJSAttributes &= ~JSPROP_GETTER;
/*chaining to return failure*/
}
@ -241,8 +227,8 @@ nsXBLProtoImplProperty::CompileMember(nsIScriptContext* aContext, const nsCStrin
} // if getter is not empty
if (!deletedGetter) { // Empty getter
delete mGetterText;
mJSGetterObject = nullptr;
delete getterText;
mGetter.SetJSFunction(nullptr);
}
if (NS_FAILED(rv)) {
@ -256,13 +242,14 @@ nsXBLProtoImplProperty::CompileMember(nsIScriptContext* aContext, const nsCStrin
}
bool deletedSetter = false;
if (mSetterText && mSetterText->GetText()) {
nsDependentString setter(mSetterText->GetText());
nsXBLTextWithLineNumber *setterText = mSetter.GetUncompiled();
if (setterText && setterText->GetText()) {
nsDependentString setter(setterText->GetText());
if (!setter.IsEmpty()) {
AutoPushJSContext cx(aContext->GetNativeContext());
JSAutoCompartment ac(cx, aClassObject);
JS::CompileOptions options(cx);
options.setFileAndLine(functionUri.get(), mSetterText->GetLineNumber())
options.setFileAndLine(functionUri.get(), setterText->GetLineNumber())
.setVersion(JSVERSION_LATEST);
nsCString name = NS_LITERAL_CSTRING("set_") + NS_ConvertUTF16toUTF8(mName);
JS::RootedObject rootedNull(cx, nullptr); // See bug 781070.
@ -270,17 +257,15 @@ nsXBLProtoImplProperty::CompileMember(nsIScriptContext* aContext, const nsCStrin
rv = nsJSUtils::CompileFunction(cx, rootedNull, options, name, 1,
gPropertyArgs, setter, setterObject.address());
// Make sure we free mSetterText here before setting mJSGetterObject, since
// that'll overwrite mSetterText
delete mSetterText;
delete setterText;
deletedSetter = true;
mJSSetterObject = setterObject;
mSetter.SetJSFunction(setterObject);
if (mJSSetterObject && NS_SUCCEEDED(rv)) {
if (mSetter.GetJSFunction() && NS_SUCCEEDED(rv)) {
mJSAttributes |= JSPROP_SETTER | JSPROP_SHARED;
}
if (NS_FAILED(rv)) {
mJSSetterObject = nullptr;
mSetter.SetJSFunction(nullptr);
mJSAttributes &= ~JSPROP_SETTER;
/*chaining to return failure*/
}
@ -288,8 +273,8 @@ nsXBLProtoImplProperty::CompileMember(nsIScriptContext* aContext, const nsCStrin
} // if setter wasn't empty....
if (!deletedSetter) { // Empty setter
delete mSetterText;
mJSSetterObject = nullptr;
delete setterText;
mSetter.SetJSFunction(nullptr);
}
#ifdef DEBUG
@ -303,11 +288,11 @@ void
nsXBLProtoImplProperty::Trace(const TraceCallbacks& aCallbacks, void *aClosure)
{
if (mJSAttributes & JSPROP_GETTER) {
aCallbacks.Trace(&mJSGetterObject, "mJSGetterObject", aClosure);
aCallbacks.Trace(&mGetter.AsHeapObject(), "mGetter", aClosure);
}
if (mJSAttributes & JSPROP_SETTER) {
aCallbacks.Trace(&mJSSetterObject, "mJSSetterObject", aClosure);
aCallbacks.Trace(&mSetter.AsHeapObject(), "mSetter", aClosure);
}
}
@ -316,27 +301,30 @@ nsXBLProtoImplProperty::Read(nsIScriptContext* aContext,
nsIObjectInputStream* aStream,
XBLBindingSerializeDetails aType)
{
MOZ_ASSERT(!mIsCompiled);
MOZ_ASSERT(!mGetter.GetUncompiled() && !mSetter.GetUncompiled());
JSContext *cx = aContext->GetNativeContext();
JS::Rooted<JSObject*> getterObject(cx);
if (aType == XBLBinding_Serialize_GetterProperty ||
aType == XBLBinding_Serialize_GetterSetterProperty) {
JS::Rooted<JSObject*> getterObject(cx);
nsresult rv = XBL_DeserializeFunction(aContext, aStream, &getterObject);
NS_ENSURE_SUCCESS(rv, rv);
mJSGetterObject = getterObject;
mJSAttributes |= JSPROP_GETTER | JSPROP_SHARED;
}
mGetter.SetJSFunction(getterObject);
JS::Rooted<JSObject*> setterObject(cx);
if (aType == XBLBinding_Serialize_SetterProperty ||
aType == XBLBinding_Serialize_GetterSetterProperty) {
JS::Rooted<JSObject*> setterObject(cx);
nsresult rv = XBL_DeserializeFunction(aContext, aStream, &setterObject);
NS_ENSURE_SUCCESS(rv, rv);
mJSSetterObject = setterObject;
mJSAttributes |= JSPROP_SETTER | JSPROP_SHARED;
}
mSetter.SetJSFunction(setterObject);
#ifdef DEBUG
mIsCompiled = true;
@ -370,14 +358,12 @@ nsXBLProtoImplProperty::Write(nsIScriptContext* aContext,
NS_ENSURE_SUCCESS(rv, rv);
if (mJSAttributes & JSPROP_GETTER) {
rv = XBL_SerializeFunction(aContext, aStream,
JS::Handle<JSObject*>::fromMarkedLocation(&mJSGetterObject));
rv = XBL_SerializeFunction(aContext, aStream, mGetter.AsHeapObject());
NS_ENSURE_SUCCESS(rv, rv);
}
if (mJSAttributes & JSPROP_SETTER) {
rv = XBL_SerializeFunction(aContext, aStream,
JS::Handle<JSObject*>::fromMarkedLocation(&mJSSetterObject));
rv = XBL_SerializeFunction(aContext, aStream, mSetter.AsHeapObject());
NS_ENSURE_SUCCESS(rv, rv);
}

View File

@ -12,6 +12,7 @@
#include "jsapi.h"
#include "nsString.h"
#include "nsXBLSerialize.h"
#include "nsXBLMaybeCompiled.h"
#include "nsXBLProtoImplMember.h"
class nsXBLProtoImplProperty: public nsXBLProtoImplMember
@ -48,21 +49,17 @@ public:
nsIObjectOutputStream* aStream) MOZ_OVERRIDE;
protected:
union {
// The raw text for the getter (prior to compilation).
nsXBLTextWithLineNumber* mGetterText;
// The JS object for the getter (after compilation)
JSObject * mJSGetterObject;
};
typedef JS::Heap<nsXBLMaybeCompiled<nsXBLTextWithLineNumber> > PropertyOp;
union {
// The raw text for the setter (prior to compilation).
nsXBLTextWithLineNumber* mSetterText;
// The JS object for the setter (after compilation)
JSObject * mJSSetterObject;
};
void EnsureUncompiledText(PropertyOp& aPropertyOp);
// The raw text for the getter, or the JS object (after compilation).
PropertyOp mGetter;
// The raw text for the setter, or the JS object (after compilation).
PropertyOp mSetter;
unsigned mJSAttributes; // A flag for all our JS properties (getter/setter/readonly/shared/enum)
unsigned mJSAttributes; // A flag for all our JS properties (getter/setter/readonly/shared/enum)
#ifdef DEBUG
bool mIsCompiled;

View File

@ -2383,8 +2383,7 @@ nsXULPrototypeScript::Serialize(nsIObjectOutputStream* aStream,
rv = aStream->Write32(mLangVersion);
if (NS_FAILED(rv)) return rv;
// And delegate the writing to the nsIScriptContext
rv = context->Serialize(aStream,
JS::Handle<JSScript*>::fromMarkedLocation(&mScriptObject));
rv = context->Serialize(aStream, mScriptObject);
if (NS_FAILED(rv)) return rv;
return NS_OK;

View File

@ -243,13 +243,13 @@ public:
// &mScriptObject pointer can't go stale.
JS::Handle<JSScript*> GetScriptObject()
{
return JS::Handle<JSScript*>::fromMarkedLocation(&mScriptObject);
return JS::Handle<JSScript*>(mScriptObject);
}
void TraceScriptObject(JSTracer* aTrc)
{
if (mScriptObject) {
JS_CallScriptTracer(aTrc, &mScriptObject, "active window XUL prototype script");
JS_CallHeapScriptTracer(aTrc, &mScriptObject, "active window XUL prototype script");
}
}
@ -267,7 +267,7 @@ public:
mozilla::dom::XULDocument* mSrcLoadWaiters; // [OWNER] but not COMPtr
uint32_t mLangVersion;
private:
JSScript* mScriptObject;
JS::Heap<JSScript*> mScriptObject;
};
class nsXULPrototypeText : public nsXULPrototypeNode

View File

@ -7890,17 +7890,6 @@ nsDocShell::RestoreFromHistory()
// Restart plugins, and paint the content.
if (shell) {
shell->Thaw();
newVM = shell->GetViewManager();
if (newVM) {
// When we insert the root view above the resulting invalidate is
// dropped because painting is suppressed in the presshell until we
// call Thaw. So we issue the invalidate here.
newRootView = newVM->GetRootView();
if (newRootView) {
newVM->InvalidateView(newRootView);
}
}
}
return privWin->FireDelayedDOMEvents();

View File

@ -22,7 +22,7 @@ class DOMRequest : public nsDOMEventTargetHelper,
public nsIDOMDOMRequest
{
protected:
JS::Value mResult;
JS::Heap<JS::Value> mResult;
nsRefPtr<DOMError> mError;
bool mDone;
bool mRooted;

View File

@ -94,7 +94,7 @@ CPP_SOURCES += [
'nsScriptNameSpaceManager.cpp',
'nsStructuredCloneContainer.cpp',
'nsWindowMemoryReporter.cpp',
'nsWindowRoot.cpp',
'nsWindowRoot.cpp'
]
EXTRA_COMPONENTS += [

View File

@ -1588,7 +1588,7 @@ NS_IMPL_CYCLE_COLLECTING_ADDREF(nsGlobalWindow)
NS_IMPL_CYCLE_COLLECTING_RELEASE(nsGlobalWindow)
static PLDHashOperator
MarkXBLHandlers(nsXBLPrototypeHandler* aKey, JSObject* aData, void* aClosure)
MarkXBLHandlers(nsXBLPrototypeHandler* aKey, JS::Heap<JSObject*>& aData, void* aClosure)
{
xpc_UnmarkGrayObject(aData);
return PL_DHASH_NEXT;
@ -1597,7 +1597,7 @@ MarkXBLHandlers(nsXBLPrototypeHandler* aKey, JSObject* aData, void* aClosure)
NS_IMPL_CYCLE_COLLECTION_CAN_SKIP_BEGIN(nsGlobalWindow)
if (tmp->IsBlackForCC()) {
if (tmp->mCachedXBLPrototypeHandlers.IsInitialized()) {
tmp->mCachedXBLPrototypeHandlers.EnumerateRead(MarkXBLHandlers, nullptr);
tmp->mCachedXBLPrototypeHandlers.Enumerate(MarkXBLHandlers, nullptr);
}
nsEventListenerManager* elm = tmp->GetListenerManager(false);
if (elm) {
@ -1749,7 +1749,7 @@ struct TraceData
};
static PLDHashOperator
TraceXBLHandlers(nsXBLPrototypeHandler* aKey, JSObject*& aData, void* aClosure)
TraceXBLHandlers(nsXBLPrototypeHandler* aKey, JS::Heap<JSObject*>& aData, void* aClosure)
{
TraceData* data = static_cast<TraceData*>(aClosure);
data->callbacks.Trace(&aData, "Cached XBL prototype handler", data->closure);

View File

@ -15,6 +15,7 @@
#include "nsAutoPtr.h"
#include "nsWeakReference.h"
#include "nsDataHashtable.h"
#include "nsJSThingHashtable.h"
#include "nsCycleCollectionParticipant.h"
// Interfaces Needed
@ -1234,7 +1235,7 @@ protected:
nsCOMPtr<nsIDOMOfflineResourceList> mApplicationCache;
nsDataHashtable<nsPtrHashKey<nsXBLPrototypeHandler>, JSObject*> mCachedXBLPrototypeHandlers;
nsJSThingHashtable<nsPtrHashKey<nsXBLPrototypeHandler>, JSObject*> mCachedXBLPrototypeHandlers;
nsCOMPtr<nsIDocument> mSuspendedDoc;

View File

@ -268,7 +268,7 @@ protected:
virtual void UpdateScopeObject(JS::Handle<JSObject*> aScopeObject) = 0;
nsCOMPtr<nsIScriptContext> mContext;
JSObject* mScopeObject;
JS::Heap<JSObject*> mScopeObject;
nsISupports* mTarget;
nsCOMPtr<nsIAtom> mEventName;
nsEventHandler mHandler;

View File

@ -3523,7 +3523,7 @@ public:
protected:
JSContext *mContext;
JS::Value *mArgv;
JS::Heap<JS::Value> *mArgv;
uint32_t mArgc;
};
@ -3534,9 +3534,10 @@ nsJSArgArray::nsJSArgArray(JSContext *aContext, uint32_t argc, JS::Value *argv,
mArgc(argc)
{
// copy the array - we don't know its lifetime, and ours is tied to xpcom
// refcounting. Alloc zero'd array so cleanup etc is safe.
// refcounting.
if (argc) {
mArgv = (JS::Value *) PR_CALLOC(argc * sizeof(JS::Value));
static const fallible_t fallible = fallible_t();
mArgv = new (fallible) JS::Heap<JS::Value>[argc];
if (!mArgv) {
*prv = NS_ERROR_OUT_OF_MEMORY;
return;
@ -3566,7 +3567,7 @@ void
nsJSArgArray::ReleaseJSObjects()
{
if (mArgv) {
PR_DELETE(mArgv);
delete [] mArgv;
}
if (mArgc > 0) {
mArgc = 0;

View File

@ -67,10 +67,11 @@ private:
// caller of setTimeout()
nsCString mFileName;
uint32_t mLineNo;
nsTArray<JS::Value> mArgs;
nsTArray<JS::Heap<JS::Value> > mArgs;
// The JS expression to evaluate or function to call, if !mExpr
JSFlatString *mExpr;
// Note this is always a flat string.
JS::Heap<JSString*> mExpr;
nsRefPtr<Function> mFunction;
};
@ -281,7 +282,7 @@ nsJSScriptTimeoutHandler::Init(nsGlobalWindow *aWindow, bool *aIsInterval,
NS_HOLD_JS_OBJECTS(this, nsJSScriptTimeoutHandler);
mExpr = expr;
mExpr = JS_FORGET_STRING_FLATNESS(expr);
// Get the calling location.
const char *filename;
@ -299,7 +300,8 @@ nsJSScriptTimeoutHandler::Init(nsGlobalWindow *aWindow, bool *aIsInterval,
// array.
// std::max(argc - 2, 0) wouldn't work right because argc is unsigned.
uint32_t argCount = std::max(argc, 2u) - 2;
FallibleTArray<JS::Value> args;
FallibleTArray<JS::Heap<JS::Value> > args;
if (!args.SetCapacity(argCount)) {
// No need to drop here, since we already have a non-null mFunction
return NS_ERROR_OUT_OF_MEMORY;
@ -319,7 +321,7 @@ const PRUnichar *
nsJSScriptTimeoutHandler::GetHandlerText()
{
NS_ASSERTION(mExpr, "No expression, so no handler text!");
return ::JS_GetFlatStringChars(mExpr);
return ::JS_GetFlatStringChars(JS_ASSERT_STRING_IS_FLAT(mExpr));
}
nsresult NS_CreateJSTimeoutHandler(nsGlobalWindow *aWindow,

View File

@ -8,7 +8,7 @@
#include "nsCycleCollectionParticipant.h"
#include "mozilla/Assertions.h"
#include "js/RootingAPI.h"
#include "js/Value.h"
struct JSTracer;
class JSObject;
@ -182,7 +182,7 @@ public:
void TraceWrapper(const TraceCallbacks& aCallbacks, void* aClosure)
{
if (PreservingWrapper() && mWrapper) {
aCallbacks.Trace(&mWrapper, "Preserved wrapper", aClosure);
aCallbacks.Trace(&mWrapper, "Preserved wrapper", aClosure);
}
}
@ -280,8 +280,8 @@ private:
enum { kWrapperFlagsMask = (WRAPPER_BIT_PRESERVED | WRAPPER_IS_DOM_BINDING |
WRAPPER_HAS_SOW) };
JSObject* mWrapper;
uint32_t mFlags;
JS::Heap<JSObject*> mWrapper;
uint32_t mFlags;
};
enum { WRAPPER_CACHE_FLAGS_BITS_USED = 3 };

View File

@ -50,7 +50,7 @@ nsWrapperCache::IsBlackAndDoesNotNeedTracing(nsISupports* aThis)
inline void
nsWrapperCache::TraceWrapperJSObject(JSTracer* aTrc, const char* aName)
{
JS_CallObjectTracer(aTrc, &mWrapper, aName);
JS_CallHeapObjectTracer(aTrc, &mWrapper, aName);
}
#endif /* nsWrapperCache_h___ */

View File

@ -76,7 +76,7 @@ public:
*/
JS::Handle<JSObject*> CallbackPreserveColor() const
{
return JS::Handle<JSObject*>::fromMarkedLocation(&mCallback);
return mCallback;
}
enum ExceptionHandling {
@ -111,7 +111,7 @@ protected:
}
}
JSObject* mCallback;
JS::Heap<JSObject*> mCallback;
class MOZ_STACK_CLASS CallSetup
{

View File

@ -262,10 +262,12 @@ BluetoothAdapter::SetPropertyByValue(const BluetoothNamedValue& aValue)
NS_ENSURE_SUCCESS_VOID(rv);
AutoPushJSContext cx(sc->GetNativeContext());
if (NS_FAILED(nsTArrayToJSArray(cx, mUuids, &mJsUuids))) {
JS::Rooted<JSObject*> uuids(cx);
if (NS_FAILED(nsTArrayToJSArray(cx, mUuids, uuids.address()))) {
NS_WARNING("Cannot set JS UUIDs object!");
return;
}
mJsUuids = uuids;
Root();
} else if (name.EqualsLiteral("Devices")) {
mDeviceAddresses = value.get_ArrayOfnsString();
@ -280,11 +282,13 @@ BluetoothAdapter::SetPropertyByValue(const BluetoothNamedValue& aValue)
NS_ENSURE_SUCCESS_VOID(rv);
AutoPushJSContext cx(sc->GetNativeContext());
JS::Rooted<JSObject*> deviceAddresses(cx);
if (NS_FAILED(nsTArrayToJSArray(cx, mDeviceAddresses,
&mJsDeviceAddresses))) {
deviceAddresses.address()))) {
NS_WARNING("Cannot set JS Devices object!");
return;
}
mJsDeviceAddresses = deviceAddresses;
Root();
} else {
#ifdef DEBUG

View File

@ -72,8 +72,8 @@ private:
uint32_t mClass;
nsTArray<nsString> mDeviceAddresses;
nsTArray<nsString> mUuids;
JSObject* mJsUuids;
JSObject* mJsDeviceAddresses;
JS::Heap<JSObject*> mJsUuids;
JS::Heap<JSObject*> mJsDeviceAddresses;
bool mIsRooted;
};

View File

@ -124,10 +124,12 @@ BluetoothDevice::SetPropertyByValue(const BluetoothNamedValue& aValue)
AutoPushJSContext cx(sc->GetNativeContext());
if (NS_FAILED(nsTArrayToJSArray(cx, mUuids, &mJsUuids))) {
JS::Rooted<JSObject*> uuids(cx);
if (NS_FAILED(nsTArrayToJSArray(cx, mUuids, uuids.address()))) {
NS_WARNING("Cannot set JS UUIDs object!");
return;
}
mJsUuids = uuids;
Root();
} else if (name.EqualsLiteral("Services")) {
mServices = value.get_ArrayOfnsString();
@ -137,10 +139,12 @@ BluetoothDevice::SetPropertyByValue(const BluetoothNamedValue& aValue)
AutoPushJSContext cx(sc->GetNativeContext());
if (NS_FAILED(nsTArrayToJSArray(cx, mServices, &mJsServices))) {
JS::Rooted<JSObject*> services(cx);
if (NS_FAILED(nsTArrayToJSArray(cx, mServices, services.address()))) {
NS_WARNING("Cannot set JS Services object!");
return;
}
mJsServices = services;
Root();
} else {
nsCString warningMsg;

View File

@ -58,8 +58,8 @@ private:
~BluetoothDevice();
void Root();
JSObject* mJsUuids;
JSObject* mJsServices;
JS::Heap<JSObject*> mJsUuids;
JS::Heap<JSObject*> mJsServices;
nsString mAdapterPath;
nsString mAddress;

View File

@ -107,7 +107,7 @@ private:
nsTArray<nsRefPtr<FutureCallback> > mResolveCallbacks;
nsTArray<nsRefPtr<FutureCallback> > mRejectCallbacks;
JS::Value mResult;
JS::Heap<JS::Value> mResult;
FutureState mState;
bool mTaskPending;
};

View File

@ -544,7 +544,7 @@ IDBCursor::GetKey(JSContext* aCx,
mRooted = true;
}
nsresult rv = mKey.ToJSVal(aCx, &mCachedKey);
nsresult rv = mKey.ToJSVal(aCx, mCachedKey);
NS_ENSURE_SUCCESS(rv, rv);
mHaveCachedKey = true;
@ -578,7 +578,7 @@ IDBCursor::GetPrimaryKey(JSContext* aCx,
const Key& key = mType == OBJECTSTORE ? mKey : mObjectKey;
nsresult rv = key.ToJSVal(aCx, &mCachedPrimaryKey);
nsresult rv = key.ToJSVal(aCx, mCachedPrimaryKey);
NS_ENSURE_SUCCESS(rv, rv);
mHaveCachedPrimaryKey = true;
@ -739,7 +739,7 @@ IDBCursor::Update(const jsval& aValue,
}
else {
JS::Rooted<JS::Value> keyVal(aCx);
rv = objectKey.ToJSVal(aCx, keyVal.address());
rv = objectKey.ToJSVal(aCx, &keyVal);
NS_ENSURE_SUCCESS(rv, rv);
rv = mObjectStore->Put(aValue, keyVal, aCx, 1, getter_AddRefs(request));
@ -810,7 +810,7 @@ IDBCursor::Delete(JSContext* aCx,
Key& objectKey = (mType == OBJECTSTORE) ? mKey : mObjectKey;
JS::Rooted<JS::Value> key(aCx);
nsresult rv = objectKey.ToJSVal(aCx, key.address());
nsresult rv = objectKey.ToJSVal(aCx, &key);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIIDBRequest> request;

View File

@ -168,7 +168,7 @@ protected:
nsRefPtr<IDBObjectStore> mObjectStore;
nsRefPtr<IDBIndex> mIndex;
JSObject* mScriptOwner;
JS::Heap<JSObject*> mScriptOwner;
Type mType;
Direction mDirection;
@ -176,9 +176,9 @@ protected:
nsCString mContinueToQuery;
// These are cycle-collected!
jsval mCachedKey;
jsval mCachedPrimaryKey;
jsval mCachedValue;
JS::Heap<JS::Value> mCachedKey;
JS::Heap<JS::Value> mCachedPrimaryKey;
JS::Heap<JS::Value> mCachedValue;
Key mRangeKey;

View File

@ -183,7 +183,7 @@ private:
// If this factory lives on a window then mWindow must be non-null. Otherwise
// mOwningObject must be non-null.
nsCOMPtr<nsPIDOMWindow> mWindow;
JSObject* mOwningObject;
JS::Heap<JSObject*> mOwningObject;
IndexedDBChild* mActorChild;
IndexedDBParent* mActorParent;

View File

@ -810,7 +810,7 @@ IDBIndex::GetKeyPath(JSContext* aCx,
return NS_OK;
}
nsresult rv = GetKeyPath().ToJSVal(aCx, &mCachedKeyPath);
nsresult rv = GetKeyPath().ToJSVal(aCx, mCachedKeyPath);
NS_ENSURE_SUCCESS(rv, rv);
if (JSVAL_IS_GCTHING(mCachedKeyPath)) {
@ -1180,7 +1180,12 @@ nsresult
GetKeyHelper::GetSuccessResult(JSContext* aCx,
jsval* aVal)
{
return mKey.ToJSVal(aCx, aVal);
JS::Rooted<JS::Value> value(aCx);
nsresult rv = mKey.ToJSVal(aCx, &value);
if (NS_SUCCEEDED(rv)) {
*aVal = value;
}
return rv;
}
void
@ -1508,7 +1513,7 @@ GetAllKeysHelper::GetSuccessResult(JSContext* aCx,
NS_ASSERTION(!key.IsUnset(), "Bad key!");
JS::Rooted<JS::Value> value(aCx);
nsresult rv = key.ToJSVal(aCx, value.address());
nsresult rv = key.ToJSVal(aCx, &value);
if (NS_FAILED(rv)) {
NS_WARNING("Failed to get jsval for key!");
return rv;

View File

@ -157,7 +157,7 @@ private:
int64_t mId;
nsString mName;
KeyPath mKeyPath;
JS::Value mCachedKeyPath;
JS::Heap<JS::Value> mCachedKeyPath;
IndexedDBIndexChild* mActorChild;
IndexedDBIndexParent* mActorParent;

View File

@ -363,7 +363,7 @@ IDBKeyRange::GetLower(JSContext* aCx,
mRooted = true;
}
nsresult rv = Lower().ToJSVal(aCx, &mCachedLowerVal);
nsresult rv = Lower().ToJSVal(aCx, mCachedLowerVal);
NS_ENSURE_SUCCESS(rv, rv);
mHaveCachedLowerVal = true;
@ -385,7 +385,7 @@ IDBKeyRange::GetUpper(JSContext* aCx,
mRooted = true;
}
nsresult rv = Upper().ToJSVal(aCx, &mCachedUpperVal);
nsresult rv = Upper().ToJSVal(aCx, mCachedUpperVal);
NS_ENSURE_SUCCESS(rv, rv);
mHaveCachedUpperVal = true;

View File

@ -157,8 +157,8 @@ private:
Key mLower;
Key mUpper;
jsval mCachedLowerVal;
jsval mCachedUpperVal;
JS::Heap<JS::Value> mCachedLowerVal;
JS::Heap<JS::Value> mCachedUpperVal;
bool mLowerOpen;
bool mUpperOpen;
bool mIsOnly;

View File

@ -2387,7 +2387,7 @@ IDBObjectStore::GetKeyPath(JSContext* aCx,
return NS_OK;
}
nsresult rv = GetKeyPath().ToJSVal(aCx, &mCachedKeyPath);
nsresult rv = GetKeyPath().ToJSVal(aCx, mCachedKeyPath);
NS_ENSURE_SUCCESS(rv, rv);
if (JSVAL_IS_GCTHING(mCachedKeyPath)) {
@ -3134,7 +3134,12 @@ AddHelper::GetSuccessResult(JSContext* aCx,
mCloneWriteInfo.mCloneBuffer.clear();
return mKey.ToJSVal(aCx, aVal);
JS::Rooted<JS::Value> value(aCx);
nsresult rv = mKey.ToJSVal(aCx, &value);
if (NS_SUCCEEDED(rv)) {
*aVal = value;
}
return rv;
}
void

View File

@ -287,7 +287,7 @@ private:
int64_t mId;
nsString mName;
KeyPath mKeyPath;
JS::Value mCachedKeyPath;
JS::Heap<JS::Value> mCachedKeyPath;
bool mRooted;
bool mAutoIncrement;
nsCOMPtr<nsIAtom> mDatabaseId;

View File

@ -120,13 +120,15 @@ IDBRequest::NotifyHelperCompleted(HelperBase* aHelper)
JSAutoCompartment ac(cx, global);
AssertIsRooted();
rv = aHelper->GetSuccessResult(cx, &mResultVal);
JS::Rooted<JS::Value> value(cx);
rv = aHelper->GetSuccessResult(cx, value.address());
if (NS_FAILED(rv)) {
NS_WARNING("GetSuccessResult failed!");
}
if (NS_SUCCEEDED(rv)) {
mError = nullptr;
mResultVal = value;
}
else {
SetError(rv);

View File

@ -109,7 +109,7 @@ protected:
nsCOMPtr<nsISupports> mSource;
nsRefPtr<IDBTransaction> mTransaction;
jsval mResultVal;
JS::Heap<JS::Value> mResultVal;
nsRefPtr<mozilla::dom::DOMError> mError;
IndexedDBRequestParentBase* mActorParent;
nsString mFilename;

View File

@ -62,7 +62,7 @@ protected:
virtual ~IDBWrapperCache();
private:
JSObject* mScriptOwner;
JS::Heap<JSObject*> mScriptOwner;
};
END_INDEXEDDB_NAMESPACE

View File

@ -185,7 +185,7 @@ Key::EncodeJSValInternal(JSContext* aCx, const jsval aVal,
// static
nsresult
Key::DecodeJSValInternal(const unsigned char*& aPos, const unsigned char* aEnd,
JSContext* aCx, uint8_t aTypeOffset, jsval* aVal,
JSContext* aCx, uint8_t aTypeOffset, JS::MutableHandle<JS::Value> aVal,
uint16_t aRecursionDepth)
{
NS_ENSURE_TRUE(aRecursionDepth < MaxRecursionDepth, NS_ERROR_DOM_INDEXEDDB_DATA_ERR);
@ -208,7 +208,7 @@ Key::DecodeJSValInternal(const unsigned char*& aPos, const unsigned char* aEnd,
while (aPos < aEnd && *aPos - aTypeOffset != eTerminator) {
JS::Rooted<JS::Value> val(aCx);
nsresult rv = DecodeJSValInternal(aPos, aEnd, aCx, aTypeOffset,
val.address(), aRecursionDepth + 1);
&val, aRecursionDepth + 1);
NS_ENSURE_SUCCESS(rv, rv);
aTypeOffset = 0;
@ -223,12 +223,12 @@ Key::DecodeJSValInternal(const unsigned char*& aPos, const unsigned char* aEnd,
"Should have found end-of-array marker");
++aPos;
*aVal = OBJECT_TO_JSVAL(array);
aVal.setObject(*array);
}
else if (*aPos - aTypeOffset == eString) {
nsString key;
DecodeString(aPos, aEnd, key);
if (!xpc::StringToJsval(aCx, key, aVal)) {
if (!xpc::StringToJsval(aCx, key, aVal.address())) {
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
}
@ -240,10 +240,10 @@ Key::DecodeJSValInternal(const unsigned char*& aPos, const unsigned char* aEnd,
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
*aVal = OBJECT_TO_JSVAL(date);
aVal.setObject(*date);
}
else if (*aPos - aTypeOffset == eFloat) {
*aVal = DOUBLE_TO_JSVAL(DecodeNumber(aPos, aEnd));
aVal.setDouble(DecodeNumber(aPos, aEnd));
}
else {
NS_NOTREACHED("Unknown key type!");

View File

@ -179,10 +179,10 @@ public:
}
nsresult ToJSVal(JSContext* aCx,
jsval* aVal) const
JS::MutableHandle<JS::Value> aVal) const
{
if (IsUnset()) {
*aVal = JSVAL_VOID;
aVal.set(JSVAL_VOID);
return NS_OK;
}
@ -196,6 +196,17 @@ public:
return NS_OK;
}
nsresult ToJSVal(JSContext* aCx,
JS::Heap<JS::Value>& aVal) const
{
JS::Rooted<JS::Value> value(aCx);
nsresult rv = ToJSVal(aCx, &value);
if (NS_SUCCEEDED(rv)) {
aVal = value;
}
return rv;
}
nsresult AppendItem(JSContext* aCx,
bool aFirstOfArray,
const jsval aVal)
@ -304,7 +315,7 @@ private:
// past the consumed value.
static inline nsresult DecodeJSVal(const unsigned char*& aPos,
const unsigned char* aEnd, JSContext* aCx,
uint8_t aTypeOffset, jsval* aVal)
uint8_t aTypeOffset, JS::MutableHandle<JS::Value> aVal)
{
return DecodeJSValInternal(aPos, aEnd, aCx, aTypeOffset, aVal, 0);
}
@ -324,7 +335,7 @@ private:
static nsresult DecodeJSValInternal(const unsigned char*& aPos,
const unsigned char* aEnd,
JSContext* aCx, uint8_t aTypeOffset,
jsval* aVal, uint16_t aRecursionDepth);
JS::MutableHandle<JS::Value> aVal, uint16_t aRecursionDepth);
};
END_INDEXEDDB_NAMESPACE

View File

@ -457,7 +457,7 @@ KeyPath::DeserializeFromString(const nsAString& aString)
}
nsresult
KeyPath::ToJSVal(JSContext* aCx, JS::Value* aValue) const
KeyPath::ToJSVal(JSContext* aCx, JS::MutableHandle<JS::Value> aValue) const
{
if (IsArray()) {
uint32_t len = mStrings.Length();
@ -479,22 +479,33 @@ KeyPath::ToJSVal(JSContext* aCx, JS::Value* aValue) const
}
}
*aValue = OBJECT_TO_JSVAL(array);
aValue.setObject(*array);
return NS_OK;
}
if (IsString()) {
nsString tmp(mStrings[0]);
if (!xpc::StringToJsval(aCx, tmp, aValue)) {
if (!xpc::StringToJsval(aCx, tmp, aValue.address())) {
return NS_ERROR_DOM_INDEXEDDB_UNKNOWN_ERR;
}
return NS_OK;
}
*aValue = JSVAL_NULL;
aValue.setNull();
return NS_OK;
}
nsresult
KeyPath::ToJSVal(JSContext* aCx, JS::Heap<JS::Value>& aValue) const
{
JS::Rooted<JS::Value> value(aCx);
nsresult rv = ToJSVal(aCx, &value);
if (NS_SUCCEEDED(rv)) {
aValue = value;
}
return rv;
}
bool
KeyPath::IsAllowedForObjectStore(bool aAutoIncrement) const
{

View File

@ -87,7 +87,8 @@ public:
void SerializeToString(nsAString& aString) const;
static KeyPath DeserializeFromString(const nsAString& aString);
nsresult ToJSVal(JSContext* aCx, JS::Value* aValue) const;
nsresult ToJSVal(JSContext* aCx, JS::MutableHandle<JS::Value> aValue) const;
nsresult ToJSVal(JSContext* aCx, JS::Heap<JS::Value>& aValue) const;
bool IsAllowedForObjectStore(bool aAutoIncrement) const;

View File

@ -1164,12 +1164,7 @@ public:
NS_METHOD GetFilename(nsAString& aFilename)
{
if (Preferences::GetBool("plugin.expose_full_path", false)) {
CopyUTF8toUTF16(mPluginTag.mFullPath, aFilename);
} else {
CopyUTF8toUTF16(mPluginTag.mFileName, aFilename);
}
CopyUTF8toUTF16(mPluginTag.mFileName, aFilename);
return NS_OK;
}

View File

@ -41,7 +41,7 @@ class Telephony : public nsDOMEventTargetHelper,
// Cached calls array object. Cleared whenever mCalls changes and then rebuilt
// once a page looks for the liveCalls attribute.
JSObject* mCallsArray;
JS::Heap<JSObject*> mCallsArray;
bool mRooted;
bool mEnumerated;

View File

@ -15,12 +15,13 @@ namespace mozilla {
namespace gfx {
SourceSurfaceSkia::SourceSurfaceSkia()
: mDrawTarget(nullptr)
: mDrawTarget(nullptr), mLocked(false)
{
}
SourceSurfaceSkia::~SourceSurfaceSkia()
{
MaybeUnlock();
MarkIndependent();
}
@ -85,17 +86,21 @@ SourceSurfaceSkia::InitFromData(unsigned char* aData,
unsigned char*
SourceSurfaceSkia::GetData()
{
mBitmap.lockPixels();
unsigned char *pixels = (unsigned char *)mBitmap.getPixels();
mBitmap.unlockPixels();
return pixels;
if (!mLocked) {
mBitmap.lockPixels();
mLocked = true;
}
unsigned char *pixels = (unsigned char *)mBitmap.getPixels();
return pixels;
}
void
SourceSurfaceSkia::DrawTargetWillChange()
{
if (mDrawTarget) {
MaybeUnlock();
mDrawTarget = nullptr;
SkBitmap temp = mBitmap;
mBitmap.reset();
@ -118,5 +123,14 @@ SourceSurfaceSkia::MarkIndependent()
}
}
void
SourceSurfaceSkia::MaybeUnlock()
{
if (mLocked) {
mBitmap.unlockPixels();
mLocked = false;
}
}
}
}

View File

@ -47,12 +47,14 @@ private:
void DrawTargetWillChange();
void DrawTargetDestroyed();
void MarkIndependent();
void MaybeUnlock();
SkBitmap mBitmap;
SurfaceFormat mFormat;
IntSize mSize;
int32_t mStride;
DrawTargetSkia* mDrawTarget;
bool mLocked;
};
}

View File

@ -466,6 +466,21 @@ public:
*/
virtual void SetIsFirstPaint() {}
/**
* Make sure that the previous transaction has been entirely
* completed.
*
* Note: This may sychronously wait on a remote compositor
* to complete rendering.
*/
virtual void FlushRendering() { }
/**
* Checks if we need to invalidate the OS widget to trigger
* painting when updating this layer manager.
*/
virtual bool NeedsWidgetInvalidation() { return true; }
// We always declare the following logging symbols, because it's
// extremely tricky to conditionally declare them. However, for
// ifndef MOZ_LAYERS_HAVE_LOG builds, they only have trivial

View File

@ -260,6 +260,16 @@ ClientLayerManager::MakeSnapshotIfRequired()
mShadowTarget = nullptr;
}
void
ClientLayerManager::FlushRendering()
{
if (mWidget) {
if (CompositorChild* remoteRenderer = mWidget->GetRemoteRenderer()) {
remoteRenderer->SendFlushRendering();
}
}
}
void
ClientLayerManager::ForwardTransaction()
{

View File

@ -53,6 +53,10 @@ public:
virtual already_AddRefed<ColorLayer> CreateColorLayer();
virtual already_AddRefed<RefLayer> CreateRefLayer();
virtual void FlushRendering() MOZ_OVERRIDE;
virtual bool NeedsWidgetInvalidation() MOZ_OVERRIDE { return Compositor::GetBackend() == LAYERS_BASIC; }
ShadowableLayer* Hold(Layer* aLayer);
bool HasShadowManager() const { return ShadowLayerForwarder::HasShadowManager(); }

View File

@ -249,6 +249,18 @@ CompositorParent::RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot,
return true;
}
bool
CompositorParent::RecvFlushRendering()
{
// If we're waiting to do a composite, then cancel it
// and do it immediately instead.
if (mCurrentCompositeTask) {
mCurrentCompositeTask->Cancel();
ComposeToTarget(nullptr);
}
return true;
}
void
CompositorParent::ActorDestroy(ActorDestroyReason why)
{
@ -743,6 +755,7 @@ public:
virtual bool RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot,
SurfaceDescriptor* aOutSnapshot)
{ return true; }
virtual bool RecvFlushRendering() MOZ_OVERRIDE { return true; }
virtual PLayerTransactionParent*
AllocPLayerTransaction(const LayersBackend& aBackendType,

View File

@ -55,6 +55,7 @@ public:
virtual bool RecvResume() MOZ_OVERRIDE;
virtual bool RecvMakeSnapshot(const SurfaceDescriptor& aInSnapshot,
SurfaceDescriptor* aOutSnapshot);
virtual bool RecvFlushRendering() MOZ_OVERRIDE;
virtual void ActorDestroy(ActorDestroyReason why) MOZ_OVERRIDE;

View File

@ -53,6 +53,10 @@ parent:
sync MakeSnapshot(SurfaceDescriptor inSnapshot)
returns (SurfaceDescriptor outSnapshot);
// Make sure any pending composites are started immediately and
// block until they are completed.
sync FlushRendering();
sync PLayerTransaction(LayersBackend layersBackendHint, uint64_t id)
returns (TextureFactoryIdentifier textureFactoryIdentifier);
};

View File

@ -181,18 +181,18 @@ class Heap : public js::HeapBase<T>
Heap() {
MOZ_STATIC_ASSERT(sizeof(T) == sizeof(Heap<T>),
"Heap<T> must be binary compatible with T.");
set(js::RootMethods<T>::initial());
init(js::RootMethods<T>::initial());
}
explicit Heap(T p) { set(p); }
explicit Heap(const Heap<T> &p) { set(p.ptr); }
explicit Heap(T p) { init(p); }
explicit Heap(const Heap<T> &p) { init(p.ptr); }
~Heap() {
if (js::RootMethods<T>::needsPostBarrier(ptr))
relocate();
}
bool operator!=(const T &other) { return *ptr != other; }
bool operator==(const T &other) { return *ptr == other; }
bool operator!=(const T &other) const { return ptr != other; }
bool operator==(const T &other) const { return ptr == other; }
operator T() const { return ptr; }
T operator->() const { return ptr; }
@ -220,6 +220,13 @@ class Heap : public js::HeapBase<T>
}
private:
void init(T newPtr) {
JS_ASSERT(!js::RootMethods<T>::poisoned(newPtr));
ptr = newPtr;
if (js::RootMethods<T>::needsPostBarrier(ptr))
post();
}
void post() {
#ifdef JSGC_GENERATIONAL
JS_ASSERT(js::RootMethods<T>::needsPostBarrier(ptr));
@ -320,8 +327,8 @@ class MOZ_NONHEAP_CLASS Handle : public js::HandleBase<T>
operator const T&() const { return get(); }
T operator->() const { return get(); }
bool operator!=(const T &other) { return *ptr != other; }
bool operator==(const T &other) { return *ptr == other; }
bool operator!=(const T &other) const { return *ptr != other; }
bool operator==(const T &other) const { return *ptr == other; }
private:
Handle() {}
@ -605,8 +612,8 @@ class MOZ_STACK_CLASS Rooted : public js::RootedBase<T>
ptr = value;
}
bool operator!=(const T &other) { return ptr != other; }
bool operator==(const T &other) { return ptr == other; }
bool operator!=(const T &other) const { return ptr != other; }
bool operator==(const T &other) const { return ptr == other; }
private:
void commonInit(Rooted<void*> **thingGCRooters) {
@ -766,8 +773,8 @@ class FakeRooted : public RootedBase<T>
return ptr;
}
bool operator!=(const T &other) { return ptr != other; }
bool operator==(const T &other) { return ptr == other; }
bool operator!=(const T &other) const { return ptr != other; }
bool operator==(const T &other) const { return ptr == other; }
private:
T ptr;

View File

@ -1420,6 +1420,7 @@ template <> struct RootMethods<JS::Value>
#endif
};
template <class Outer> class UnbarrieredMutableValueOperations;
template <class Outer> class MutableValueOperations;
/*
@ -1431,7 +1432,9 @@ template <class Outer> class MutableValueOperations;
template <class Outer>
class ValueOperations
{
friend class UnbarrieredMutableValueOperations<Outer>;
friend class MutableValueOperations<Outer>;
const JS::Value * value() const { return static_cast<const Outer*>(this)->extract(); }
public:
@ -1469,14 +1472,16 @@ class ValueOperations
};
/*
* A class designed for CRTP use in implementing the mutating parts of the
* Value interface in Value-like classes. Outer must be a class inheriting
* MutableValueOperations<Outer> with visible extractMutable() and extract()
* methods returning the const Value* and Value* abstracted by Outer.
* A class designed for CRTP use in implementing the mutating parts of the Value
* interface in Value-like classes that don't need post barriers. Outer must be
* a class inheriting UnbarrieredMutableValueOperations<Outer> with visible
* extractMutable() and extract() methods returning the const Value* and Value*
* abstracted by Outer.
*/
template <class Outer>
class MutableValueOperations : public ValueOperations<Outer>
class UnbarrieredMutableValueOperations : public ValueOperations<Outer>
{
friend class MutableValueOperations<Outer>;
JS::Value * value() { return static_cast<Outer*>(this)->extractMutable(); }
public:
@ -1484,26 +1489,65 @@ class MutableValueOperations : public ValueOperations<Outer>
void setUndefined() { value()->setUndefined(); }
void setInt32(int32_t i) { value()->setInt32(i); }
void setDouble(double d) { value()->setDouble(d); }
void setString(JSString *str) { value()->setString(str); }
void setString(const JS::Anchor<JSString *> &str) { value()->setString(str); }
void setObject(JSObject &obj) { value()->setObject(obj); }
void setBoolean(bool b) { value()->setBoolean(b); }
void setMagic(JSWhyMagic why) { value()->setMagic(why); }
bool setNumber(uint32_t ui) { return value()->setNumber(ui); }
bool setNumber(double d) { return value()->setNumber(d); }
void setObjectOrNull(JSObject *arg) { value()->setObjectOrNull(arg); }
};
/*
* Augment the generic Heap<T> interface when T = Value with type-querying
* and value-extracting operations.
* A class designed for CRTP use in implementing all the mutating parts of the
* Value interface in Value-like classes. Outer must be a class inheriting
* MutableValueOperations<Outer> with visible extractMutable() and extract()
* methods returning the const Value* and Value* abstracted by Outer.
*/
template <class Outer>
class MutableValueOperations : public UnbarrieredMutableValueOperations<Outer>
{
public:
void setString(JSString *str) { this->value()->setString(str); }
void setString(const JS::Anchor<JSString *> &str) { this->value()->setString(str); }
void setObject(JSObject &obj) { this->value()->setObject(obj); }
void setObjectOrNull(JSObject *arg) { this->value()->setObjectOrNull(arg); }
};
/*
* Augment the generic Heap<T> interface when T = Value with
* type-querying, value-extracting, and mutating operations.
*/
template <>
class HeapBase<JS::Value> : public ValueOperations<JS::Heap<JS::Value> >
class HeapBase<JS::Value> : public UnbarrieredMutableValueOperations<JS::Heap<JS::Value> >
{
friend class ValueOperations<JS::Heap<JS::Value> >;
const JS::Value * extract() const {
return static_cast<const JS::Heap<JS::Value>*>(this)->address();
typedef JS::Heap<JS::Value> Outer;
friend class ValueOperations<Outer>;
friend class UnbarrieredMutableValueOperations<Outer>;
const JS::Value * extract() const { return static_cast<const Outer*>(this)->address(); }
JS::Value * extractMutable() { return static_cast<Outer*>(this)->unsafeGet(); }
/*
* Setters that potentially change the value to a GC thing from a non-GC
* thing must call JS::Heap::set() to trigger the post barrier.
*
* Changing from a GC thing to a non-GC thing value will leave the heap
* value in the store buffer, but it will be ingored so this is not a
* problem.
*/
void setBarriered(const JS::Value &v) {
static_cast<JS::Heap<JS::Value> *>(this)->set(v);
}
public:
void setString(JSString *str) { setBarriered(JS::StringValue(str)); }
void setString(const JS::Anchor<JSString *> &str) { setBarriered(JS::StringValue(str.get())); }
void setObject(JSObject &obj) { setBarriered(JS::ObjectValue(obj)); }
void setObjectOrNull(JSObject *arg) {
if (arg)
setObject(*arg);
else
setNull();
}
};
@ -1532,6 +1576,7 @@ class MutableHandleBase<JS::Value> : public MutableValueOperations<JS::MutableHa
return static_cast<const JS::MutableHandle<JS::Value>*>(this)->address();
}
friend class UnbarrieredMutableValueOperations<JS::MutableHandle<JS::Value> >;
friend class MutableValueOperations<JS::MutableHandle<JS::Value> >;
JS::Value * extractMutable() {
return static_cast<JS::MutableHandle<JS::Value>*>(this)->address();
@ -1550,6 +1595,7 @@ class RootedBase<JS::Value> : public MutableValueOperations<JS::Rooted<JS::Value
return static_cast<const JS::Rooted<JS::Value>*>(this)->address();
}
friend class UnbarrieredMutableValueOperations<JS::Rooted<JS::Value> >;
friend class MutableValueOperations<JS::Rooted<JS::Value> >;
JS::Value * extractMutable() {
return static_cast<JS::Rooted<JS::Value>*>(this)->address();

View File

@ -305,6 +305,19 @@ case "$target" in
if test ! -d "$android_platform_tools" ; then
android_platform_tools="$android_sdk"/tools # SDK Tools < r8
fi
# The build tools got moved around to different directories in
# SDK Tools r22. Try to locate them.
android_build_tools=""
for suffix in 17.0.0 android-4.2.2; do
tools_directory="$android_sdk/../../build-tools/$suffix"
if test -d "$tools_directory" ; then
android_build_tools="$tools_directory"
break
fi
done
if test -z "$android_build_tools" ; then
android_build_tools="$android_platform_tools" # SDK Tools < r22
fi
ANDROID_SDK="${android_sdk}"
if test -e "${android_sdk}/../../extras/android/compatibility/v4/android-support-v4.jar" ; then
ANDROID_COMPAT_LIB="${android_sdk}/../../extras/android/compatibility/v4/android-support-v4.jar"
@ -312,12 +325,14 @@ case "$target" in
ANDROID_COMPAT_LIB="${android_sdk}/../../extras/android/support/v4/android-support-v4.jar";
fi
ANDROID_PLATFORM_TOOLS="${android_platform_tools}"
ANDROID_BUILD_TOOLS="${android_build_tools}"
AC_SUBST(ANDROID_SDK)
AC_SUBST(ANDROID_COMPAT_LIB)
if ! test -e $ANDROID_COMPAT_LIB ; then
AC_MSG_ERROR([You must download the Android support library when targeting Android. Run the Android SDK tool and install Android Support Library under Extras. See https://developer.android.com/tools/extras/support-library.html for more info. (looked for $ANDROID_COMPAT_LIB)])
fi
AC_SUBST(ANDROID_PLATFORM_TOOLS)
AC_SUBST(ANDROID_BUILD_TOOLS)
;;
esac

Some files were not shown because too many files have changed in this diff Show More