From be2d312504baaacd68d16ea57eb9b51b92873137 Mon Sep 17 00:00:00 2001 From: Mike Hommey Date: Fri, 16 Dec 2011 11:21:56 +0100 Subject: [PATCH 01/16] Bug 709721 part 3 - Only try to export gkmedias symbols that are defined wrt configuration. r=khuey --HG-- rename : layout/media/symbols.def => layout/media/symbols.def.in --- configure.in | 1 + layout/media/Makefile.in | 5 +- layout/media/{symbols.def => symbols.def.in} | 68 +++++++++++--------- 3 files changed, 44 insertions(+), 30 deletions(-) rename layout/media/{symbols.def => symbols.def.in} (92%) diff --git a/configure.in b/configure.in index 2ad4e063a0af..849e97f2992d 100644 --- a/configure.in +++ b/configure.in @@ -5705,6 +5705,7 @@ if test -n "$MOZ_WEBM"; then [return 0;], [AC_MSG_RESULT([yes]) MOZ_NATIVE_LIBVPX=1 + AC_DEFINE(MOZ_NATIVE_LIBVPX) MOZ_LIBVPX_INCLUDES="-I${LIBVPX_DIR}/include" MOZ_LIBVPX_LIBS="-L${LIBVPX_DIR}/lib -lvpx"], [AC_MSG_RESULT([no]) diff --git a/layout/media/Makefile.in b/layout/media/Makefile.in index 5cd4d0732d65..37d974deb9bc 100644 --- a/layout/media/Makefile.in +++ b/layout/media/Makefile.in @@ -93,7 +93,10 @@ SHARED_LIBRARY_LIBS += \ EXTRA_DSO_LDOPTS = $(MOZALLOC_LIB) $(NSPR_LIBS) ifeq (WINNT,$(OS_TARGET)) -DEFFILE = $(srcdir)/symbols.def +DEFFILE = symbols.def + +symbols.def: symbols.def.in + $(PYTHON) $(topsrcdir)/config/Preprocessor.py $(ACDEFINES) $< > $@ endif include $(topsrcdir)/config/rules.mk diff --git a/layout/media/symbols.def b/layout/media/symbols.def.in similarity index 92% rename from layout/media/symbols.def rename to layout/media/symbols.def.in index 5c636d478806..6146dcde79a0 100644 --- a/layout/media/symbols.def +++ b/layout/media/symbols.def.in @@ -1,5 +1,6 @@ LIBRARY gkmedias.dll EXPORTS +#ifdef MOZ_WEBM nestegg_destroy nestegg_duration nestegg_free_packet @@ -18,6 +19,16 @@ nestegg_track_seek nestegg_track_type nestegg_track_video_params nestegg_tstamp_scale +#ifndef MOZ_NATIVE_LIBVPX +vpx_codec_dec_init_ver +vpx_codec_decode +vpx_codec_destroy +vpx_codec_get_frame +vpx_codec_peek_stream_info +vpx_codec_vp8_dx +#endif +#endif +#ifdef MOZ_VORBIS ogg_page_bos ogg_page_granulepos ogg_page_serialno @@ -33,29 +44,6 @@ ogg_sync_init ogg_sync_pageseek ogg_sync_reset ogg_sync_wrote -sa_stream_create_pcm -sa_stream_destroy -sa_stream_drain -sa_stream_get_min_write -sa_stream_get_position -sa_stream_get_write_size -sa_stream_open -sa_stream_pause -sa_stream_resume -sa_stream_write -th_comment_clear -th_comment_init -th_decode_alloc -th_decode_free -th_decode_headerin -th_decode_packetin -th_decode_ycbcr_out -th_granule_frame -th_info_clear -th_info_init -th_packet_isheader -th_packet_iskeyframe -th_setup_free vorbis_block_clear vorbis_block_init vorbis_comment_clear @@ -71,12 +59,34 @@ vorbis_synthesis_init vorbis_synthesis_pcmout vorbis_synthesis_read vorbis_synthesis_restart -vpx_codec_dec_init_ver -vpx_codec_decode -vpx_codec_destroy -vpx_codec_get_frame -vpx_codec_peek_stream_info -vpx_codec_vp8_dx +#endif +#ifdef MOZ_SYDNEYAUDIO +sa_stream_create_pcm +sa_stream_destroy +sa_stream_drain +sa_stream_get_min_write +sa_stream_get_position +sa_stream_get_write_size +sa_stream_open +sa_stream_pause +sa_stream_resume +sa_stream_write +#endif +#ifdef MOZ_OGG +th_comment_clear +th_comment_init +th_decode_alloc +th_decode_free +th_decode_headerin +th_decode_packetin +th_decode_ycbcr_out +th_granule_frame +th_info_clear +th_info_init +th_packet_isheader +th_packet_iskeyframe +th_setup_free +#endif ShInitialize ShFinalize ShGetObjectCode From 5e5b8f3b5c9bd22b4ffffb1b1f67c18292a0df6a Mon Sep 17 00:00:00 2001 From: mh Date: Fri, 16 Dec 2011 11:23:34 +0100 Subject: [PATCH 02/16] Bug 710147 - Pass more targets from client.mk to the build system. r=ted --- client.mk | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/client.mk b/client.mk index d0797d860c1c..cbfde19ee674 100644 --- a/client.mk +++ b/client.mk @@ -171,6 +171,9 @@ endif # MOZ_BUILD_PROJECTS CONFIGURES := $(TOPSRCDIR)/configure CONFIGURES += $(TOPSRCDIR)/js/src/configure +# Make targets that are going to be passed to the real build system +OBJDIR_TARGETS = install export libs clean realclean distclean alldep maybe_clobber_profiledbuild upload sdk installer package package-compare stage-package source-package l10n-check + ####################################################################### # Rules @@ -259,7 +262,7 @@ endif # loop through them. ifeq (,$(MOZ_CURRENT_PROJECT)$(if $(MOZ_BUILD_PROJECTS),,1)) -configure depend realbuild install export libs clean realclean distclean alldep preflight postflight maybe_clobber_profiledbuild upload sdk:: +configure depend realbuild preflight postflight $(OBJDIR_TARGETS):: set -e; \ for app in $(MOZ_BUILD_PROJECTS); do \ $(MAKE) -f $(TOPSRCDIR)/client.mk $@ MOZ_CURRENT_PROJECT=$$app; \ @@ -370,7 +373,7 @@ realbuild:: $(OBJDIR)/Makefile $(OBJDIR)/config.status # Other targets # Pass these target onto the real build system -install export libs clean realclean distclean alldep maybe_clobber_profiledbuild upload sdk:: $(OBJDIR)/Makefile $(OBJDIR)/config.status +$(OBJDIR_TARGETS):: $(OBJDIR)/Makefile $(OBJDIR)/config.status $(MOZ_MAKE) $@ #################################### @@ -429,4 +432,4 @@ echo-variable-%: # in parallel. .NOTPARALLEL: -.PHONY: checkout real_checkout depend realbuild build profiledbuild maybe_clobber_profiledbuild export libs alldep install clean realclean distclean cleansrcdir pull_all build_all clobber clobber_all pull_and_build_all everything configure preflight_all preflight postflight postflight_all upload sdk +.PHONY: checkout real_checkout depend realbuild build profiledbuild cleansrcdir pull_all build_all clobber clobber_all pull_and_build_all everything configure preflight_all preflight postflight postflight_all $(OBJDIR_TARGETS) From efe739e3f97c946ecfebefad3dce429b70f0e46d Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Fri, 16 Dec 2011 22:38:45 +0900 Subject: [PATCH 03/16] Bug 700199 EventUtils.js should use synthesized events for sendKey(), sendChar() and sendString() rather than untrusted events r=smaug+ehsan+dolske+enndeakin --- .../test/browser_sanitizeDialog_treeView.js | 3 +- .../test/browser_ruleview_editor.js | 6 +- .../test/browser_ruleview_ui.js | 6 +- content/html/content/test/test_bug388794.html | 3 +- content/html/content/test/test_bug424698.html | 2 +- .../html/content/test/test_bug558788-1.html | 4 +- docshell/test/navigation/test_bug386782.html | 16 +-- docshell/test/navigation/test_bug430624.html | 8 +- docshell/test/navigation/test_bug430723.html | 23 ++-- editor/composer/test/test_bug389350.html | 4 +- .../libeditor/html/tests/test_bug432225.html | 7 +- .../libeditor/html/tests/test_bug455992.html | 12 +-- .../libeditor/html/tests/test_bug456244.html | 10 +- .../libeditor/html/tests/test_bug487524.html | 4 +- .../libeditor/html/tests/test_bug607584.xul | 3 +- .../libeditor/text/tests/test_bug641466.html | 8 +- layout/base/tests/bug106855-1-ref.html | 8 +- layout/base/tests/bug106855-1.html | 6 +- layout/base/tests/bug106855-2.html | 8 +- layout/base/tests/bug240933-1.html | 2 +- layout/base/tests/bug240933-2.html | 6 +- layout/base/tests/bug482484.html | 4 +- layout/base/tests/bug512295-1.html | 12 +-- layout/base/tests/bug512295-2.html | 12 +-- layout/base/tests/bug602141-1.html | 2 +- layout/base/tests/bug602141-2.html | 2 +- layout/base/tests/bug602141-3.html | 2 +- layout/base/tests/bug602141-4.html | 2 +- layout/base/tests/bug612271-1.html | 2 +- layout/base/tests/bug612271-2.html | 2 +- layout/base/tests/bug612271-3.html | 2 +- layout/base/tests/bug613433-1.html | 4 +- layout/base/tests/bug613433-2.html | 4 +- layout/base/tests/bug613433-3.html | 4 +- layout/forms/test/bug477700_subframe.html | 1 + layout/forms/test/test_bug345267.html | 2 +- layout/forms/test/test_bug365410.html | 16 +-- layout/forms/test/test_bug446663.html | 16 +-- layout/forms/test/test_bug542914.html | 8 +- layout/forms/test/test_bug563642.html | 20 ++-- layout/generic/test/test_bug633762.html | 2 +- mobile/android/chrome/tests/browser_escape.js | 2 +- mobile/android/chrome/tests/browser_select.js | 4 +- mobile/xul/chrome/tests/browser_escape.js | 2 +- mobile/xul/chrome/tests/browser_select.js | 4 +- .../mochitest/tests/SimpleTest/EventUtils.js | 102 ++++-------------- testing/mochitest/tests/test_sanity.html | 4 +- .../tests/test_sanityEventUtils.html | 8 +- .../test/test_basic_form_autocomplete.html | 12 ++- .../satchel/test/test_form_autocomplete.html | 45 +++++--- .../content/tests/chrome/test_hiddenitems.xul | 17 +-- .../tests/chrome/test_hiddenpaging.xul | 26 ++--- .../tests/chrome/test_richlist_direction.xul | 31 +++--- 53 files changed, 238 insertions(+), 287 deletions(-) diff --git a/browser/base/content/test/browser_sanitizeDialog_treeView.js b/browser/base/content/test/browser_sanitizeDialog_treeView.js index 9abe1d6a7406..654ac7bc5d45 100644 --- a/browser/base/content/test/browser_sanitizeDialog_treeView.js +++ b/browser/base/content/test/browser_sanitizeDialog_treeView.js @@ -401,8 +401,9 @@ WindowHelper.prototype = { let key = aDelta < 0 ? "UP" : "DOWN"; let abs = Math.abs(aDelta); let treechildren = this.getTree().treeBoxObject.treeBody; + treechildren.focus(); for (let i = 0; i < abs; i++) { - EventUtils.sendKey(key, treechildren); + EventUtils.sendKey(key); } }, diff --git a/browser/devtools/styleinspector/test/browser_ruleview_editor.js b/browser/devtools/styleinspector/test/browser_ruleview_editor.js index 0aad26422486..181d67eb3db8 100644 --- a/browser/devtools/styleinspector/test/browser_ruleview_editor.js +++ b/browser/devtools/styleinspector/test/browser_ruleview_editor.js @@ -41,7 +41,7 @@ function testReturnCommit() start: function() { is(span.inplaceEditor.input.value, "explicit initial", "Explicit initial value should be used."); span.inplaceEditor.input.value = "Test Value"; - EventUtils.sendKey("return", span.inplaceEditor.input); + EventUtils.sendKey("return"); }, done: expectDone("Test Value", true, testBlurCommit) }); @@ -74,7 +74,7 @@ function testAdvanceCharCommit() start: function() { let input = span.inplaceEditor.input; for each (let ch in "Test:") { - EventUtils.sendChar(ch, input); + EventUtils.sendChar(ch); } }, done: expectDone("Test", true, testEscapeCancel) @@ -91,7 +91,7 @@ function testEscapeCancel() initial: "initial text", start: function() { span.inplaceEditor.input.value = "Test Value"; - EventUtils.sendKey("escape", span.inplaceEditor.input); + EventUtils.sendKey("escape"); }, done: expectDone("initial text", false, finishTest) }); diff --git a/browser/devtools/styleinspector/test/browser_ruleview_ui.js b/browser/devtools/styleinspector/test/browser_ruleview_ui.js index 636d5dc5f891..c0767aaffe02 100644 --- a/browser/devtools/styleinspector/test/browser_ruleview_ui.js +++ b/browser/devtools/styleinspector/test/browser_ruleview_ui.js @@ -120,7 +120,7 @@ function testCreateNew() aEditor.input.blur(); }); - EventUtils.sendKey("return", input); + EventUtils.sendKey("return", ruleDialog); }); EventUtils.synthesizeMouse(elementRuleEditor.closeBrace, 1, 1, @@ -148,11 +148,11 @@ function testEditProperty() }); for each (let ch in "red;") { - EventUtils.sendChar(ch, input); + EventUtils.sendChar(ch, ruleDialog); } }); for each (let ch in "border-color:") { - EventUtils.sendChar(ch, input); + EventUtils.sendChar(ch, ruleDialog); } }); diff --git a/content/html/content/test/test_bug388794.html b/content/html/content/test/test_bug388794.html index a6cc4778c071..866adabcca98 100644 --- a/content/html/content/test/test_bug388794.html +++ b/content/html/content/test/test_bug388794.html @@ -62,7 +62,8 @@ var hrefs = { function submitForm(idNum) { $("test"+idNum).setAttribute("onload", "frameLoaded(this)"); - sendKey("return", "test" + idNum + "image"); + $("test" + idNum + "image").focus(); + sendKey("return"); } function submitFormMouse(idNum) { diff --git a/content/html/content/test/test_bug424698.html b/content/html/content/test/test_bug424698.html index a8f046d9527e..9bd6ea5ff3aa 100644 --- a/content/html/content/test/test_bug424698.html +++ b/content/html/content/test/test_bug424698.html @@ -76,7 +76,7 @@ is(i.value, "test3", "Setting textarea defaultValue after hide/show should work" i = $("target2"); i.focus(); // Otherwise editor gets confused when we send the key events is(i.value, "", "Textarea value should be empty string in second control"); -sendString("2test2", "target2"); +sendString("2test2"); is(i.value, "2test2", 'We just typed the string "2test2"'); i.defaultValue = "2test3"; is(i.value, "2test2", "Setting textarea defaultValue after typing should not work"); diff --git a/content/html/content/test/test_bug558788-1.html b/content/html/content/test/test_bug558788-1.html index 4e999b1f9650..94b7a5f00ea5 100644 --- a/content/html/content/test/test_bug558788-1.html +++ b/content/html/content/test/test_bug558788-1.html @@ -121,7 +121,7 @@ function checkInputEmail() synthesizeKey("a", {}); checkInvalidApplies(element); - sendString("@b.c", element); + sendString("@b.c"); checkValidApplies(element); synthesizeKey("VK_BACK_SPACE", {}); @@ -151,7 +151,7 @@ function checkInputURL() synthesizeKey("h", {}); checkInvalidApplies(element); - sendString("ttp://mozilla.org", element); + sendString("ttp://mozilla.org"); checkValidApplies(element); for (var i=0; i<13; ++i) { diff --git a/docshell/test/navigation/test_bug386782.html b/docshell/test/navigation/test_bug386782.html index 9d474d0a5f6b..609d7912a983 100644 --- a/docshell/test/navigation/test_bug386782.html +++ b/docshell/test/navigation/test_bug386782.html @@ -66,14 +66,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=386782 // WARNING: If the following test fails, give the setTimeout() in the onload() // a bit longer; the doc hasn't had enough time to setup its editor. is(gTest.window.document.body.innerHTML, gTest.expectedBodyBeforeEdit, "Is doc setup yet"); - - sendChar('E', gTest.window.document.body); - sendChar('D', gTest.window.document.body); - sendChar('I', gTest.window.document.body); - sendChar('T', gTest.window.document.body); - sendChar('E', gTest.window.document.body); - sendChar('D', gTest.window.document.body); - sendChar(' ', gTest.window.document.body); + sendString('EDITED ', gTest.window); is(gTest.window.document.body.innerHTML, gTest.expectedBodyAfterEdit, "Editing failed."); gTest.window.location = 'data:text/html;charset=utf-8,SomeOtherDocument'; @@ -103,12 +96,7 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=386782 // Check that we can still edit the page. gTest.window.document.body.focus(); - sendChar('T', gTest.window.document.body); - sendChar('W', gTest.window.document.body); - sendChar('I', gTest.window.document.body); - sendChar('C', gTest.window.document.body); - sendChar('E', gTest.window.document.body); - sendChar(' ', gTest.window.document.body); + sendString('TWICE ', gTest.window); is(gTest.window.document.body.innerHTML, gTest.expectedBodyAfterSecondEdit, "Can we still edit?"); gTest.window.close(); diff --git a/docshell/test/navigation/test_bug430624.html b/docshell/test/navigation/test_bug430624.html index 31c5b8648d04..9fc92e4cd305 100644 --- a/docshell/test/navigation/test_bug430624.html +++ b/docshell/test/navigation/test_bug430624.html @@ -36,12 +36,8 @@ function onReload() { function doTest() { var bodyElement = window.frames[0].frameElement.contentDocument.body; - sendChar('S', bodyElement); - sendChar('t', bodyElement); - sendChar('i', bodyElement); - sendChar('l', bodyElement); - sendChar('l', bodyElement); - sendChar(' ', bodyElement); + bodyElement.focus(); + sendString('Still ', window.frames[0].frameElement.contentWindow); is(bodyElement.innerHTML, "Still contentEditable", "Check we're contentEditable after reload"); diff --git a/docshell/test/navigation/test_bug430723.html b/docshell/test/navigation/test_bug430723.html index 5e18b10d23d5..0179f4cdb3f4 100644 --- a/docshell/test/navigation/test_bug430723.html +++ b/docshell/test/navigation/test_bug430723.html @@ -62,15 +62,20 @@ var step1 =function() { // Navigate down and up. is(testWindow.document.body.scrollTop, 0, "Page1: Ensure we scrollpane is at the top before we start scrolling."); + testWindow.focus(); sendKey('DOWN', testWindow); - sendKey('UP', testWindow); - setTimeout(function() { - is(testWindow.document.body.scrollTop, 0, - "Page1: Ensure we can scroll down and up, back to the top."); - - // Nav to blue box page. This should fire step2. - testWindow.location = gTallBlueBoxURI; - }, 0); + SimpleTest.executeSoon(function() { + isnot(testWindow.document.body.scrollTop, 0, + "Page1: Ensure we can scroll down."); + sendKey('UP', testWindow); + SimpleTest.executeSoon(function() { + is(testWindow.document.body.scrollTop, 0, + "Page1: Ensure we can scroll up, back to the top."); + + // Nav to blue box page. This should fire step2. + testWindow.location = gTallBlueBoxURI; + }); + }); } @@ -80,6 +85,7 @@ var step2 =function() { // Scroll around a bit. is(testWindow.document.body.scrollTop, 0, "Page2: Ensure we scrollpane is at the top before we start scrolling."); + testWindow.focus(); sendKey('DOWN', testWindow); sendKey('DOWN', testWindow); sendKey('DOWN', testWindow); @@ -99,6 +105,7 @@ var step3 =function() { // Check we can still scroll with the keys. is(testWindow.document.body.scrollTop, 0, "Page1Again: Ensure scroll pane at top before we scroll."); + testWindow.focus(); sendKey('DOWN', testWindow); setTimeout(function() { isnot(testWindow.document.body.scrollTop, 0, diff --git a/editor/composer/test/test_bug389350.html b/editor/composer/test/test_bug389350.html index 1400d3c1b980..bf1d514addbf 100644 --- a/editor/composer/test/test_bug389350.html +++ b/editor/composer/test/test_bug389350.html @@ -15,9 +15,7 @@ function runTest() { e.contentDocument.designMode='on'; e.style.display='block'; e.focus(); - sendChar('a', e.contentDocument); - sendChar('b', e.contentDocument); - sendChar('c', e.contentDocument); + sendString('abc'); var expected = "abc"; var result = e.contentDocument.documentElement.innerHTML; is(result, expected, "iframe with designmode on had incorrect content"); diff --git a/editor/libeditor/html/tests/test_bug432225.html b/editor/libeditor/html/tests/test_bug432225.html index 91deb43270f9..afda7fbd61fd 100644 --- a/editor/libeditor/html/tests/test_bug432225.html +++ b/editor/libeditor/html/tests/test_bug432225.html @@ -58,12 +58,7 @@ function addWords(aLimit) { return; } getEdit().focus(); - sendChar('a', editDoc()); - sendChar('a', editDoc()); - sendChar(' ', editDoc()); - sendChar('O', editDoc()); - sendChar('K', editDoc()); - sendChar(' ', editDoc()); + sendString('aa OK '); gMisspeltWords.push("aa"); setTimeout(function() { addWords(aLimit-1); }, 0); } diff --git a/editor/libeditor/html/tests/test_bug455992.html b/editor/libeditor/html/tests/test_bug455992.html index 16fb67defa83..d4f4be27ba8f 100644 --- a/editor/libeditor/html/tests/test_bug455992.html +++ b/editor/libeditor/html/tests/test_bug455992.html @@ -27,7 +27,7 @@ function runTest() { function test_begin_bs(e) { const msg = "BACKSPACE at beginning of contenteditable inline element"; var before = e.parentNode.childNodes[0].nodeValue; - sendKey("back_space", e); + sendKey("back_space"); is(e.parentNode.childNodes[0].nodeValue, before, msg + " with id=" + e.id); is(e.innerHTML, "X", msg + " with id=" + e.id); } @@ -35,7 +35,7 @@ function runTest() { function test_begin_space(e) { const msg = "SPACE at beginning of contenteditable inline element"; var before = e.parentNode.childNodes[0].nodeValue; - sendChar(" ", e); + sendChar(" "); is(e.parentNode.childNodes[0].nodeValue, before, msg + " with id=" + e.id); is(e.innerHTML, " X", msg + " with id=" + e.id); } @@ -43,8 +43,8 @@ function runTest() { function test_end_delete(e) { const msg = "DEL at end of contenteditable inline element"; var before = e.parentNode.childNodes[2].nodeValue; - sendKey("right", e); - sendKey("delete", e); + sendKey("right"); + sendKey("delete"); is(e.parentNode.childNodes[2].nodeValue, before, msg + " with id=" + e.id); is(e.innerHTML, "X", msg + " with id=" + e.id); } @@ -52,8 +52,8 @@ function runTest() { function test_end_space(e) { const msg = "SPACE at end of contenteditable inline element"; var before = e.parentNode.childNodes[2].nodeValue; - sendKey("right", e); - sendChar(" ", e); + sendKey("right"); + sendChar(" "); is(e.parentNode.childNodes[2].nodeValue, before, msg + " with id=" + e.id); is(e.innerHTML, "X" + (e.tagName=="SPAN" ? " " : "
"), msg + " with id=" + e.id); } diff --git a/editor/libeditor/html/tests/test_bug456244.html b/editor/libeditor/html/tests/test_bug456244.html index 89883b981042..d85970f3f53c 100644 --- a/editor/libeditor/html/tests/test_bug456244.html +++ b/editor/libeditor/html/tests/test_bug456244.html @@ -27,9 +27,9 @@ function runTest() { function test_end_bs(e) { const msg = "Deleting all text in contenteditable inline element"; var before = e.parentNode.childNodes[0].nodeValue; - sendKey("right", e); - sendKey("back_space", e); - sendKey("back_space", e); + sendKey("right"); + sendKey("back_space"); + sendKey("back_space"); is(e.parentNode.childNodes[0].nodeValue, before, msg + " with id=" + e.id); is(e.innerHTML, "", msg + " with id=" + e.id); } @@ -43,8 +43,8 @@ function runTest() { var doc = e.contentDocument; doc.body.setAttribute("contenteditable", "true"); doc.body.focus(); - sendKey("right", doc.body); - sendKey("back_space", doc.body); + sendKey("right"); + sendKey("back_space"); is(doc.body.innerHTML, "
", msg + " with id=" + e.id); } diff --git a/editor/libeditor/html/tests/test_bug487524.html b/editor/libeditor/html/tests/test_bug487524.html index 82c116150e35..8f4b83b812e2 100644 --- a/editor/libeditor/html/tests/test_bug487524.html +++ b/editor/libeditor/html/tests/test_bug487524.html @@ -31,7 +31,7 @@ function runTest() { range.setEnd(li1.nextSibling,0); selection.addRange(range); - sendKey('delete', li1); + sendKey('delete'); is(doc.body.innerHTML,'
  • two
    • a
','delete 1st LI'); var li2 = setupIframe(i1,'
  • two
    • a
','li2') @@ -43,7 +43,7 @@ function runTest() { range.setEnd(li2.nextSibling.firstChild,0); selection.addRange(range); - sendKey('delete', li2); + sendKey('delete'); is(doc.body.innerHTML,'
    • a
','delete 2nd LI'); SimpleTest.finish(); diff --git a/editor/libeditor/html/tests/test_bug607584.xul b/editor/libeditor/html/tests/test_bug607584.xul index dec88720550d..1bea95d760f6 100644 --- a/editor/libeditor/html/tests/test_bug607584.xul +++ b/editor/libeditor/html/tests/test_bug607584.xul @@ -57,12 +57,13 @@ https://bugzilla.mozilla.org/show_bug.cgi?id=607584 { var editor = this.mEditor.getEditor(this.mEditor.contentWindow); if (editor) { + this.mEditor.focus(); editor instanceof Components.interfaces.nsIHTMLEditor; editor.returnInParagraphCreatesNewParagraph = true; editor.insertHTML("

this is a paragraph carrying id 'foo'

"); var p = editor.document.getElementById('foo') editor.beginningOfDocument(); - sendKey("return", p); + sendKey("return"); var firstP = p.parentNode.firstElementChild; var lastP = p.parentNode.lastElementChild; var isOk = firstP.nodeName.toLowerCase() == "p" && diff --git a/editor/libeditor/text/tests/test_bug641466.html b/editor/libeditor/text/tests/test_bug641466.html index 73aff98301b8..4a77b0b8962f 100644 --- a/editor/libeditor/text/tests/test_bug641466.html +++ b/editor/libeditor/text/tests/test_bug641466.html @@ -26,10 +26,10 @@ SimpleTest.waitForFocus(function() { element.focus(); element.selectionStart = 4; element.selectionEnd = 4; - synthesizeKey("VK_BACKSPACE", {}); - synthesizeKey("VK_BACKSPACE", {}); - synthesizeKey("VK_BACKSPACE", {}); - synthesizeKey("VK_BACKSPACE", {}); + synthesizeKey("VK_BACK_SPACE", {}); + synthesizeKey("VK_BACK_SPACE", {}); + synthesizeKey("VK_BACK_SPACE", {}); + synthesizeKey("VK_BACK_SPACE", {}); ok(element.value, "", "4 backspaces should delete all of the characters in the " + element.localName); } diff --git a/layout/base/tests/bug106855-1-ref.html b/layout/base/tests/bug106855-1-ref.html index 3344ad1a4924..7bfb81815f1f 100644 --- a/layout/base/tests/bug106855-1-ref.html +++ b/layout/base/tests/bug106855-1-ref.html @@ -17,10 +17,10 @@ y var area = document.getElementById('t'); area.focus(); - sendKey('RIGHT', window); // now after "A" - sendKey('RIGHT', window); // - sendKey('RIGHT', window); // - sendKey('RIGHT', window); // now at the last line + sendKey('RIGHT'); // now after "A" + sendKey('RIGHT'); // + sendKey('RIGHT'); // + sendKey('RIGHT'); // now at the last line diff --git a/layout/base/tests/bug106855-1.html b/layout/base/tests/bug106855-1.html index 8ccb55757aaf..7d5cae7b6bd1 100644 --- a/layout/base/tests/bug106855-1.html +++ b/layout/base/tests/bug106855-1.html @@ -17,9 +17,9 @@ y var area = document.getElementById('t'); area.focus(); - sendKey('DOWN', window); // now after "A" - sendKey('DOWN', window); // - sendKey('DOWN', window); // now at the last line + sendKey('DOWN'); // now after "A" + sendKey('DOWN'); // + sendKey('DOWN'); // now at the last line diff --git a/layout/base/tests/bug106855-2.html b/layout/base/tests/bug106855-2.html index 2390169ef490..40c13f353564 100644 --- a/layout/base/tests/bug106855-2.html +++ b/layout/base/tests/bug106855-2.html @@ -17,10 +17,10 @@ y var area = document.getElementById('t'); area.focus(); - sendKey('DOWN', window); // now after "A" - sendKey('DOWN', window); // - sendKey('DOWN', window); // - sendKey('DOWN', window); // now at the last line + sendKey('DOWN'); // now after "A" + sendKey('DOWN'); // + sendKey('DOWN'); // + sendKey('DOWN'); // now at the last line diff --git a/layout/base/tests/bug240933-1.html b/layout/base/tests/bug240933-1.html index 7db3b4fca291..1872d532d732 100644 --- a/layout/base/tests/bug240933-1.html +++ b/layout/base/tests/bug240933-1.html @@ -7,7 +7,7 @@ var area = document.getElementById('t'); area.focus(); - sendKey('ENTER', "t"); // press Enter once + sendKey('ENTER'); // press Enter once diff --git a/layout/base/tests/bug240933-2.html b/layout/base/tests/bug240933-2.html index 6c2feecb4392..a685c009e89a 100644 --- a/layout/base/tests/bug240933-2.html +++ b/layout/base/tests/bug240933-2.html @@ -7,9 +7,9 @@ var area = document.getElementById('t'); area.focus(); - sendKey('ENTER', "t"); // press Enter twice - sendKey('ENTER', "t"); - sendKey('BACK_SPACE', "t"); // press Backspace once + sendKey('ENTER'); // press Enter twice + sendKey('ENTER'); + sendKey('BACK_SPACE'); // press Backspace once diff --git a/layout/base/tests/bug482484.html b/layout/base/tests/bug482484.html index f5d122e6ae31..ee65dc5d22bf 100644 --- a/layout/base/tests/bug482484.html +++ b/layout/base/tests/bug482484.html @@ -15,8 +15,8 @@ range.setEnd(p.firstChild, 0); sel.addRange(range); - sendKey('UP', div); // move UP - sendChar('A', div); // insert "A" + sendKey('UP'); // move UP + sendChar('A'); // insert "A" diff --git a/layout/base/tests/bug512295-1.html b/layout/base/tests/bug512295-1.html index 77c21e4d90be..de547e6c301f 100644 --- a/layout/base/tests/bug512295-1.html +++ b/layout/base/tests/bug512295-1.html @@ -19,12 +19,12 @@ x sel.addRange(range); p.parentNode.focus(); - sendKey('DOWN', window); // now after "1" - sendKey('DOWN', window); // now make sure we get to the end - sendKey('DOWN', window); // now make sure we get to the end - sendKey('DOWN', window); // now make sure we get to the end - sendKey('DOWN', window); // now make sure we get to the end - sendKey('DOWN', window); // now make sure we get to the end + sendKey('DOWN'); // now after "1" + sendKey('DOWN'); // now make sure we get to the end + sendKey('DOWN'); // now make sure we get to the end + sendKey('DOWN'); // now make sure we get to the end + sendKey('DOWN'); // now make sure we get to the end + sendKey('DOWN'); // now make sure we get to the end diff --git a/layout/base/tests/bug512295-2.html b/layout/base/tests/bug512295-2.html index ba0afbaa3a77..51f283f3900e 100644 --- a/layout/base/tests/bug512295-2.html +++ b/layout/base/tests/bug512295-2.html @@ -19,12 +19,12 @@ x sel.addRange(range); p.parentNode.focus(); - sendKey('DOWN', window); // now after "1" - sendKey('DOWN', window); // now below the P element - sendKey('UP', window); // now before the "1" - sendKey('UP', window); // now before the "A" - sendKey('UP', window); // now before the "A" - sendKey('UP', window); // now before the "A" + sendKey('DOWN'); // now after "1" + sendKey('DOWN'); // now below the P element + sendKey('UP'); // now before the "1" + sendKey('UP'); // now before the "A" + sendKey('UP'); // now before the "A" + sendKey('UP'); // now before the "A" diff --git a/layout/base/tests/bug602141-1.html b/layout/base/tests/bug602141-1.html index dd76e1989d2d..2e79165dc215 100644 --- a/layout/base/tests/bug602141-1.html +++ b/layout/base/tests/bug602141-1.html @@ -15,7 +15,7 @@ sel.addRange(range); x.focus(); - sendKey('RIGHT', window); // Try to move the caret one position to the right + sendKey('RIGHT'); // Try to move the caret one position to the right diff --git a/layout/base/tests/bug602141-2.html b/layout/base/tests/bug602141-2.html index 2efc8867276c..260863b7cc80 100644 --- a/layout/base/tests/bug602141-2.html +++ b/layout/base/tests/bug602141-2.html @@ -17,7 +17,7 @@ sel.addRange(range); x.focus(); - sendKey('RIGHT', window); // Try to move the caret one position to the right + sendKey('RIGHT'); // Try to move the caret one position to the right diff --git a/layout/base/tests/bug602141-3.html b/layout/base/tests/bug602141-3.html index f1e5761ddb85..5ba542677f9d 100644 --- a/layout/base/tests/bug602141-3.html +++ b/layout/base/tests/bug602141-3.html @@ -15,7 +15,7 @@ noteditablenavigable|unnavigable
diff --git a/layout/base/tests/bug602141-4.html b/layout/base/tests/bug602141-4.html index 68a0b08f0aa8..6ff5c480f9ba 100644 --- a/layout/base/tests/bug602141-4.html +++ b/layout/base/tests/bug602141-4.html @@ -15,7 +15,7 @@ sel.addRange(range); x.focus(); - sendKey('RIGHT', window); // Try to move the caret one position to the right + sendKey('RIGHT'); // Try to move the caret one position to the right diff --git a/layout/base/tests/bug612271-1.html b/layout/base/tests/bug612271-1.html index 3204bc7fee53..7b79bef2d707 100644 --- a/layout/base/tests/bug612271-1.html +++ b/layout/base/tests/bug612271-1.html @@ -8,7 +8,7 @@ var t = document.querySelector("textarea"); t.focus(); t.selectionStart = t.selectionEnd = t.value.length; - sendKey('ENTER', "target"); + sendKey('ENTER'); document.body.appendChild(document.createTextNode(t.selectionStart + " - " + t.selectionEnd)); diff --git a/layout/base/tests/bug612271-2.html b/layout/base/tests/bug612271-2.html index 3acb1ec1e165..d3801384b686 100644 --- a/layout/base/tests/bug612271-2.html +++ b/layout/base/tests/bug612271-2.html @@ -8,7 +8,7 @@ var t = document.querySelector("textarea"); t.focus(); t.selectionStart = t.selectionEnd = t.value.length; - sendKey('ENTER', "target"); + sendKey('ENTER'); document.body.appendChild(document.createTextNode(t.selectionStart + " - " + t.selectionEnd)); diff --git a/layout/base/tests/bug612271-3.html b/layout/base/tests/bug612271-3.html index 626701ef3d66..1bfe5ce0e8d0 100644 --- a/layout/base/tests/bug612271-3.html +++ b/layout/base/tests/bug612271-3.html @@ -8,7 +8,7 @@ var t = document.querySelector("textarea"); t.focus(); t.selectionStart = t.selectionEnd = t.value.length; - sendKey('ENTER', "target"); + sendKey('ENTER'); document.body.appendChild(document.createTextNode(t.selectionStart + " - " + t.selectionEnd)); diff --git a/layout/base/tests/bug613433-1.html b/layout/base/tests/bug613433-1.html index 9d9ce57aa778..37e83a78b258 100644 --- a/layout/base/tests/bug613433-1.html +++ b/layout/base/tests/bug613433-1.html @@ -12,8 +12,8 @@ function test() { document.querySelector("div").focus(); // type a character, then press backspace to delete it - sendKey("X", "div1"); - sendKey("BACK_SPACE", "div1"); + sendChar("X"); + sendKey("BACK_SPACE"); document.documentElement.removeAttribute("class"); } diff --git a/layout/base/tests/bug613433-2.html b/layout/base/tests/bug613433-2.html index ae64e4afd77e..9eb093ff445e 100644 --- a/layout/base/tests/bug613433-2.html +++ b/layout/base/tests/bug613433-2.html @@ -12,8 +12,8 @@ function test() { document.querySelector("div").focus(); // type a character, then press backspace to delete it - sendKey("X", "div1"); - sendKey("BACK_SPACE", "div1"); + sendChar("X"); + sendKey("BACK_SPACE"); document.documentElement.removeAttribute("class"); } diff --git a/layout/base/tests/bug613433-3.html b/layout/base/tests/bug613433-3.html index dcc9802aebbb..e7d1bc5609e8 100644 --- a/layout/base/tests/bug613433-3.html +++ b/layout/base/tests/bug613433-3.html @@ -12,8 +12,8 @@ function test() { document.querySelector("div").focus(); // type a character, then press backspace to delete it - sendKey("X", "div1"); - sendKey("BACK_SPACE", "div1"); + sendChar("X"); + sendKey("BACK_SPACE"); document.documentElement.removeAttribute("class"); } diff --git a/layout/forms/test/bug477700_subframe.html b/layout/forms/test/bug477700_subframe.html index 6d2c23641dd8..96f9c62ae78c 100644 --- a/layout/forms/test/bug477700_subframe.html +++ b/layout/forms/test/bug477700_subframe.html @@ -14,6 +14,7 @@ window.addEventListener("message", function(evt) { doIs(evt.data, "start", "Unexpected message"); + $("target").focus(); sendString("Test"); var t = $("target"); doIs(t.value, "Test", "Typing should work"); diff --git a/layout/forms/test/test_bug345267.html b/layout/forms/test/test_bug345267.html index 72e9b16453b7..3f01b525db74 100644 --- a/layout/forms/test/test_bug345267.html +++ b/layout/forms/test/test_bug345267.html @@ -83,7 +83,7 @@ is($("target").value, "abc", "Typing should be limited by maxlength"); $("target").value = ""; sendString("ad"); sendKey("left"); -sendString("bc") +sendString("bc"); is($("target").value, "abd", "Typing should be limited by maxlength again"); diff --git a/layout/forms/test/test_bug365410.html b/layout/forms/test/test_bug365410.html index c27c5ffbe164..19c5fb68a2af 100644 --- a/layout/forms/test/test_bug365410.html +++ b/layout/forms/test/test_bug365410.html @@ -78,10 +78,10 @@ function pageUpDownTest(id,index) { var elm = document.getElementById(id); elm.focus(); elm.selectedIndex = 0; - sendKey("page_down", elm); - sendKey("page_down", elm); - sendKey("page_up", elm); - sendKey("page_down", elm); + sendKey("page_down"); + sendKey("page_down"); + sendKey("page_up"); + sendKey("page_down"); is(elm.selectedIndex, index, "pageUpDownTest: selectedIndex for " + id + " is " + index); } @@ -89,10 +89,10 @@ function upDownTest(id,index) { var elm = document.getElementById(id); elm.focus(); elm.selectedIndex = 0; - sendKey("down", elm); - sendKey("down", elm); - sendKey("up", elm); - sendKey("down", elm); + sendKey("down"); + sendKey("down"); + sendKey("up"); + sendKey("down"); is(elm.selectedIndex, index, "upDownTest: selectedIndex for " + id + " is " + index); } diff --git a/layout/forms/test/test_bug446663.html b/layout/forms/test/test_bug446663.html index dde0d4b67516..f27b6830c602 100644 --- a/layout/forms/test/test_bug446663.html +++ b/layout/forms/test/test_bug446663.html @@ -48,11 +48,11 @@ var elm = document.getElementById(id); elm.focus(); var x = document.body.offsetHeight; $(id).addEventListener("input", inputListener, false); -sendChar('1',elm); +sendChar('1'); is(inputHappened, true, "How come no input?"); -sendChar('3',elm); -sendKey('LEFT',elm) -sendChar('2',elm); +sendChar('3'); +sendKey('LEFT') +sendChar('2'); elm.blur(); x = document.body.offsetHeight; is(elm.value, '123', id + " edit"); @@ -61,14 +61,14 @@ test_edit_cmds(id) id = 'bug446663_b' elm = document.getElementById(id); elm.focus(); -sendChar('1',elm); +sendChar('1'); elm.style.display = 'none' var x = document.body.offsetHeight; elm.style.display = 'inline' x = document.body.offsetHeight; -sendChar('3',elm); -sendKey('LEFT',elm) -sendChar('2',elm); +sendChar('3'); +sendKey('LEFT') +sendChar('2'); elm.blur(); x = document.body.offsetHeight; is(elm.value, '123', id + " edit"); diff --git a/layout/forms/test/test_bug542914.html b/layout/forms/test/test_bug542914.html index 7b1e357001a7..91ceee7ce09e 100644 --- a/layout/forms/test/test_bug542914.html +++ b/layout/forms/test/test_bug542914.html @@ -59,13 +59,14 @@ function runTests(callback, type) { // Make sure that the control accepts input events without explicit initialization is(c.value, "", "Control is empty initially"); - sendChar("a", c); + c.focus(); + sendChar("a"); is(c.value, "a", "Control accepts input without explicit initialization"); // Make sure that the control retains its caret position c.focus(); c.blur(); c.focus(); - sendChar("b", c); + sendChar("b"); is(c.value, "ab", "Control retains caret position after being re-focused"); var d = document.createElement("input"); @@ -76,8 +77,9 @@ function runTests(callback, type) { // Make sure dynamically injected inputs work as expected is(d.value, "", "Dynamic control's initial value should be empty"); d.value = "new"; + d.focus(); is(d.value, "new", "Dynamic control's value can be set before initialization"); - sendChar("x", d); + sendChar("x"); is(d.value, "xnew", "Dynamic control accepts keyboard input without explicit initialization"); $("display").removeChild(d); is(d.value, "xnew", "Dynamic control retains value after being removed from the document"); diff --git a/layout/forms/test/test_bug563642.html b/layout/forms/test/test_bug563642.html index 0cf12b6ec6da..916435c4ff56 100644 --- a/layout/forms/test/test_bug563642.html +++ b/layout/forms/test/test_bug563642.html @@ -41,11 +41,11 @@ function pageUpDownTest(id,index) { var elm = document.getElementById(id); elm.focus(); elm.selectedIndex = 0; - sendKey("page_down", elm); - sendKey("page_down", elm); - sendKey("page_down", elm); - sendKey("page_up", elm); - sendKey("page_down", elm); + sendKey("page_down"); + sendKey("page_down"); + sendKey("page_down"); + sendKey("page_up"); + sendKey("page_down"); is(elm.selectedIndex, index, "pageUpDownTest: selectedIndex for " + id + " is " + index); } @@ -53,11 +53,11 @@ function upDownTest(id,index) { var elm = document.getElementById(id); elm.focus(); elm.selectedIndex = 0; - sendKey("down", elm); - sendKey("down", elm); - sendKey("down", elm); - sendKey("up", elm); - sendKey("down", elm); + sendKey("down"); + sendKey("down"); + sendKey("down"); + sendKey("up"); + sendKey("down"); is(elm.selectedIndex, index, "upDownTest: selectedIndex for " + id + " is " + index); } diff --git a/layout/generic/test/test_bug633762.html b/layout/generic/test/test_bug633762.html index 8059c277ec57..f31b52138494 100644 --- a/layout/generic/test/test_bug633762.html +++ b/layout/generic/test/test_bug633762.html @@ -34,7 +34,7 @@ function runTests() { // record scrolltop scrollTopBefore = doc.body.scrollTop; // send up arrow key event - sendKey("UP", doc.body); + sendKey("UP"); setTimeout("finish();", 0); } diff --git a/mobile/android/chrome/tests/browser_escape.js b/mobile/android/chrome/tests/browser_escape.js index 5b17f0340f5e..a08272725c94 100644 --- a/mobile/android/chrome/tests/browser_escape.js +++ b/mobile/android/chrome/tests/browser_escape.js @@ -98,7 +98,7 @@ function testReturnToOwner() { tab1 = Browser.addTab("about:blank", true); tab2 = Browser.addTab("about:blank", true, tab1); is(Browser.selectedTab, tab2, "tab2 is selected"); - EventUtils.sendKey("ESCAPE", window); + EventUtils.sendKey("ESCAPE"); is(Browser.selectedTab, tab1, "tab1 is selected"); closeTabs(); testContextMenu(); diff --git a/mobile/android/chrome/tests/browser_select.js b/mobile/android/chrome/tests/browser_select.js index f9aca619ccc4..ccf0fd29959b 100644 --- a/mobile/android/chrome/tests/browser_select.js +++ b/mobile/android/chrome/tests/browser_select.js @@ -47,7 +47,7 @@ function closeSelect() { let selectui = document.getElementById("select-container"); is(selectui.hidden, false, "Select UI should be open"); - EventUtils.sendKey("ESCAPE", window); + EventUtils.sendKey("ESCAPE"); waitFor(tapOnMultiSelect, function() { return document.getElementById("select-container").hidden == true; }); } @@ -70,7 +70,7 @@ function onUIReady() { is(selectui.hidden, false, "Select UI should be open"); is(SelectHelperUI._selectedIndexes, 7, "Select UI should have the 8th option selected:" + SelectHelperUI._selectedIndexes); - EventUtils.sendKey("ESCAPE", window); + EventUtils.sendKey("ESCAPE"); // Close our tab when finished Browser.closeTab(new_tab); diff --git a/mobile/xul/chrome/tests/browser_escape.js b/mobile/xul/chrome/tests/browser_escape.js index 5b17f0340f5e..a08272725c94 100644 --- a/mobile/xul/chrome/tests/browser_escape.js +++ b/mobile/xul/chrome/tests/browser_escape.js @@ -98,7 +98,7 @@ function testReturnToOwner() { tab1 = Browser.addTab("about:blank", true); tab2 = Browser.addTab("about:blank", true, tab1); is(Browser.selectedTab, tab2, "tab2 is selected"); - EventUtils.sendKey("ESCAPE", window); + EventUtils.sendKey("ESCAPE"); is(Browser.selectedTab, tab1, "tab1 is selected"); closeTabs(); testContextMenu(); diff --git a/mobile/xul/chrome/tests/browser_select.js b/mobile/xul/chrome/tests/browser_select.js index f9aca619ccc4..ccf0fd29959b 100644 --- a/mobile/xul/chrome/tests/browser_select.js +++ b/mobile/xul/chrome/tests/browser_select.js @@ -47,7 +47,7 @@ function closeSelect() { let selectui = document.getElementById("select-container"); is(selectui.hidden, false, "Select UI should be open"); - EventUtils.sendKey("ESCAPE", window); + EventUtils.sendKey("ESCAPE"); waitFor(tapOnMultiSelect, function() { return document.getElementById("select-container").hidden == true; }); } @@ -70,7 +70,7 @@ function onUIReady() { is(selectui.hidden, false, "Select UI should be open"); is(SelectHelperUI._selectedIndexes, 7, "Select UI should have the 8th option selected:" + SelectHelperUI._selectedIndexes); - EventUtils.sendKey("ESCAPE", window); + EventUtils.sendKey("ESCAPE"); // Close our tab when finished Browser.closeTab(new_tab); diff --git a/testing/mochitest/tests/SimpleTest/EventUtils.js b/testing/mochitest/tests/SimpleTest/EventUtils.js index d2ea6d4bdc4f..099cb8e1a451 100644 --- a/testing/mochitest/tests/SimpleTest/EventUtils.js +++ b/testing/mochitest/tests/SimpleTest/EventUtils.js @@ -73,105 +73,39 @@ function sendMouseEvent(aEvent, aTarget, aWindow) { } /** - * Send the char aChar to the node with id aTarget. If aTarget is not - * provided, use "target". This method handles casing of chars (sends the - * right charcode, and sends a shift key for uppercase chars). No other - * modifiers are handled at this point. + * Send the char aChar to the focused element. This method handles casing of + * chars (sends the right charcode, and sends a shift key for uppercase chars). + * No other modifiers are handled at this point. * * For now this method only works for English letters (lower and upper case) * and the digits 0-9. - * - * Returns true if the keypress event was accepted (no calls to preventDefault - * or anything like that), false otherwise. */ -function sendChar(aChar, aTarget) { +function sendChar(aChar, aWindow) { // DOM event charcodes match ASCII (JS charcodes) for a-zA-Z0-9. var hasShift = (aChar == aChar.toUpperCase()); - var charCode = aChar.charCodeAt(0); - var keyCode = charCode; - if (!hasShift) { - // For lowercase letters, the keyCode is actually 32 less than the charCode - keyCode -= 0x20; - } - - return __doEventDispatch(aTarget, charCode, keyCode, hasShift); + synthesizeKey(aChar, { shiftKey: hasShift }, aWindow); } /** - * Send the string aStr to the node with id aTarget. If aTarget is not - * provided, use "target". + * Send the string aStr to the focused element. * * For now this method only works for English letters (lower and upper case) * and the digits 0-9. */ -function sendString(aStr, aTarget) { +function sendString(aStr, aWindow) { for (var i = 0; i < aStr.length; ++i) { - sendChar(aStr.charAt(i), aTarget); + sendChar(aStr.charAt(i), aWindow); } } /** - * Send the non-character key aKey to the node with id aTarget. If aTarget is - * not provided, use "target". The name of the key should be a lowercase - * version of the part that comes after "DOM_VK_" in the KeyEvent constant - * name for this key. No modifiers are handled at this point. - * - * Returns true if the keypress event was accepted (no calls to preventDefault - * or anything like that), false otherwise. + * Send the non-character key aKey to the focused node. The name of the key + * should be a lowercase version of the part that comes after "DOM_VK_" in the + * KeyEvent constant name for this key. No modifiers are handled at this point. */ -function sendKey(aKey, aTarget) { - keyName = "DOM_VK_" + aKey.toUpperCase(); - - if (!KeyEvent[keyName]) { - throw "Unknown key: " + keyName; - } - - return __doEventDispatch(aTarget, 0, KeyEvent[keyName], false); -} - -/** - * Actually perform event dispatch given a charCode, keyCode, and boolean for - * whether "shift" was pressed. Send the event to the node with id aTarget. If - * aTarget is not provided, use "target". - * - * Returns true if the keypress event was accepted (no calls to preventDefault - * or anything like that), false otherwise. - */ -function __doEventDispatch(aTarget, aCharCode, aKeyCode, aHasShift) { - if (aTarget === undefined) { - aTarget = "target"; - } - - var event = document.createEvent("KeyEvents"); - event.initKeyEvent("keydown", true, true, document.defaultView, - false, false, aHasShift, false, - aKeyCode, 0); - var accepted = SpecialPowers.dispatchEvent(window, aTarget, event); - - // Preventing the default keydown action also prevents the default - // keypress action. - event = document.createEvent("KeyEvents"); - if (aCharCode) { - event.initKeyEvent("keypress", true, true, document.defaultView, - false, false, aHasShift, false, - 0, aCharCode); - } else { - event.initKeyEvent("keypress", true, true, document.defaultView, - false, false, aHasShift, false, - aKeyCode, 0); - } - if (!accepted) { - event.preventDefault(); - } - accepted = SpecialPowers.dispatchEvent(window, aTarget, event); - - // Always send keyup - var event = document.createEvent("KeyEvents"); - event.initKeyEvent("keyup", true, true, document.defaultView, - false, false, aHasShift, false, - aKeyCode, 0); - SpecialPowers.dispatchEvent(window, aTarget, event); - return accepted; +function sendKey(aKey, aWindow) { + keyName = "VK_" + aKey.toUpperCase(); + synthesizeKey(keyName, { shiftKey: false }, aWindow); } /** @@ -393,9 +327,12 @@ function synthesizeKey(aKey, aEvent, aWindow) var utils = _getDOMWindowUtils(aWindow); if (utils) { var keyCode = 0, charCode = 0; - if (aKey.indexOf("VK_") == 0) + if (aKey.indexOf("VK_") == 0) { keyCode = KeyEvent["DOM_" + aKey]; - else { + if (!keyCode) { + throw "Unknown key: " + aKey; + } + } else { charCode = aKey.charCodeAt(0); keyCode = _computeKeyCodeFromChar(aKey.charAt(0)); } @@ -410,6 +347,7 @@ function synthesizeKey(aKey, aEvent, aWindow) } else { var keyDownDefaultHappened = utils.sendKeyEvent("keydown", keyCode, 0, modifiers); + // XXX Shouldn't dispatch keypress event if the key is a modifier key. utils.sendKeyEvent("keypress", charCode ? 0 : keyCode, charCode, modifiers, !keyDownDefaultHappened); utils.sendKeyEvent("keyup", keyCode, 0, modifiers); diff --git a/testing/mochitest/tests/test_sanity.html b/testing/mochitest/tests/test_sanity.html index 7c949f3d9fd2..6b4bcc759e57 100644 --- a/testing/mochitest/tests/test_sanity.html +++ b/testing/mochitest/tests/test_sanity.html @@ -44,13 +44,13 @@ is(press2, true, "synthesizeKey should dispatch keyPress with default prevented" var press3 = false; $("testKeyEvent3").focus(); -sendChar("x", "testKeyEvent3") +sendChar("x") is($("testKeyEvent3").value, "x", "sendChar should work"); is(press3, true, "sendChar should dispatch keyPress"); var press4 = false; $("testKeyEvent4").focus(); -sendChar("x", "testKeyEvent4") +sendChar("x") is($("testKeyEvent4").value, "", "sendChar should respect keydown preventDefault"); is(press4, true, "sendChar should dispatch keyPress with default prevented"); diff --git a/testing/mochitest/tests/test_sanityEventUtils.html b/testing/mochitest/tests/test_sanityEventUtils.html index 850e0d6113d8..47dacfb1f4ef 100644 --- a/testing/mochitest/tests/test_sanityEventUtils.html +++ b/testing/mochitest/tests/test_sanityEventUtils.html @@ -46,17 +46,19 @@ function starttest() { check = false; $("testKeyEvent").addEventListener("keypress", function() { check = true; }, false); $("testKeyEvent").focus(); - sendChar("x", "testKeyEvent"); + sendChar("x"); is($("testKeyEvent").value, "x", "sendChar should work"); is(check, true, "sendChar should dispatch keyPress"); $("testKeyEvent").value = ""; - sendString("string", "testStrEvent"); + $("testStrEvent").focus(); + sendString("string"); is($("testStrEvent").value, "string", "sendString should work"); $("testStrEvent").value = ""; check = false; - sendKey("DOWN", "testKeyEvent"); + $("testKeyEvent").focus(); + sendKey("DOWN"); is(check, true, "sendKey should dispatch keyPress"); /* test synthesizeMouse* */ diff --git a/toolkit/components/passwordmgr/test/test_basic_form_autocomplete.html b/toolkit/components/passwordmgr/test/test_basic_form_autocomplete.html index f8a68d07b603..8f2e62ebc77a 100644 --- a/toolkit/components/passwordmgr/test/test_basic_form_autocomplete.html +++ b/toolkit/components/passwordmgr/test/test_basic_form_autocomplete.html @@ -643,7 +643,7 @@ function runTest(testNum) { // the username. uname.focus(); doKey("right"); - sendChar("X", uname); + sendChar("X"); // Trigger the 'blur' event on uname pword.focus(); checkACForm("sXingleuser5", "singlepass5"); @@ -722,14 +722,15 @@ function runTest(testNum) { pwmgr.removeLogin(login7); testNum = 699; - gNextTestWillOpenPopup = false; + gNextTestWillOpenPopup = true; break; case 700: // Turn our attention to form9 to test the dropdown - bug 497541 uname = $_(9, "uname"); pword = $_(9, "pword"); - sendString("form9userAB", uname); + uname.focus(); + sendString("form9userAB"); gNextTestWillOpenPopup = true; break; @@ -737,7 +738,7 @@ function runTest(testNum) { checkACForm("form9userAB", ""); uname.focus(); doKey("left"); - sendChar("A", uname); + sendChar("A"); gNextTestWillOpenPopup = false; break; @@ -753,7 +754,8 @@ function runTest(testNum) { case 703: pwmgr.addLogin(login8C); - sendChar("z", uname); + uname.focus(); + sendChar("z"); gNextTestWillOpenPopup = false; break; diff --git a/toolkit/components/satchel/test/test_form_autocomplete.html b/toolkit/components/satchel/test/test_form_autocomplete.html index 872591b932ae..ef027ad7465e 100644 --- a/toolkit/components/satchel/test/test_form_autocomplete.html +++ b/toolkit/components/satchel/test/test_form_autocomplete.html @@ -477,19 +477,22 @@ function runTest(testNum) { input = $_(5, "field3"); restoreForm(); testNum = 199; - sendChar("a", input); + input.focus(); + sendChar("a"); break; /* Test filtering as characters are typed. */ case 200: checkMenuEntries(["a", "aa", "aaz", "aa\xe6", "az"]); - sendChar("a", input); + input.focus(); + sendChar("a"); break; case 201: checkMenuEntries(["aa", "aaz", "aa\xe6"]); - sendChar("\xc6", input); + input.focus(); + sendChar("\xc6"); break; case 202: @@ -504,27 +507,31 @@ function runTest(testNum) { case 204: checkMenuEntries(["a", "aa", "aaz", "aa\xe6", "az"]); - sendChar("z", input); + input.focus(); + sendChar("z"); break; case 205: ok(getMenuEntries().length > 0, "checking typing in middle of text"); + input.focus(); doKey("left"); - sendChar("a", input); + sendChar("a"); break; case 206: checkMenuEntries(["aaz"]); fh.addEntry("field3", "aazq"); + input.focus(); doKey("right"); - sendChar("q", input); + sendChar("q"); break; case 207: // check that results were cached checkMenuEntries([]); fh.addEntry("field3", "aazqq"); - sendChar("q", input); + input.focus(); + sendChar("q"); break; case 208: @@ -536,7 +543,8 @@ function runTest(testNum) { input = $_(6, "field4"); restoreForm(); testNum = 249; - sendChar("a", input); + input.focus(); + sendChar("a"); break; /* Test substring matches and word boundary bonuses */ @@ -544,7 +552,8 @@ function runTest(testNum) { case 250: // alphabetical results for first character checkMenuEntries(["aa a\xe6", "aba\xe6", "a\xe6"]); - sendChar("\xc6", input); + input.focus(); + sendChar("\xc6"); break; case 251: @@ -553,31 +562,36 @@ function runTest(testNum) { checkMenuEntries(["a\xe6", "aa a\xe6", "aba\xe6"]); restoreForm(); - sendChar("b", input); + input.focus(); + sendChar("b"); break; case 252: checkMenuEntries(["bc d\xe6"]); - sendChar(" ", input); + input.focus(); + sendChar(" "); break; case 253: // check that trailing space has no effect after single char. checkMenuEntries(["bc d\xe6"]); - sendChar("\xc6", input); + input.focus(); + sendChar("\xc6"); break; case 254: // check multi-word substring matches checkMenuEntries(["bc d\xe6", "aba\xe6"]); + input.focus(); doKey("left"); - sendChar("d", input); + sendChar("d"); break; case 255: // check inserting in multi-word searches checkMenuEntries(["bc d\xe6"]); - sendChar("z", input); + input.focus(); + sendChar("z"); break; case 256: @@ -630,7 +644,8 @@ function runTest(testNum) { input.maxLength = 4; // now again with a character typed - sendChar("1", input); + input.focus(); + sendChar("1"); doKey("escape"); doKey("down"); break; diff --git a/toolkit/content/tests/chrome/test_hiddenitems.xul b/toolkit/content/tests/chrome/test_hiddenitems.xul index b03780003f07..7e44852df931 100644 --- a/toolkit/content/tests/chrome/test_hiddenitems.xul +++ b/toolkit/content/tests/chrome/test_hiddenitems.xul @@ -44,19 +44,20 @@ SimpleTest.waitForExplicitFinish(); function testListbox(id) { var listbox = document.getElementById(id); + listbox.focus(); is(listbox.getRowCount(), 7, id + ": Returned the wrong number of rows"); is(listbox.getItemAtIndex(2).id, id + "_item3", id + ": Should still return hidden items"); listbox.selectedIndex = 0; is(listbox.selectedItem.id, id + "_item1", id + ": First item was not selected"); - sendKey("DOWN", id); + sendKey("DOWN"); is(listbox.selectedItem.id, id + "_item2", id + ": Down didn't move to second item"); - sendKey("DOWN", id); + sendKey("DOWN"); is(listbox.selectedItem.id, id + "_item4", id + ": Down didn't skip hidden item"); - sendKey("DOWN", id); + sendKey("DOWN"); is(listbox.selectedItem.id, id + "_item6", id + ": Down didn't skip collapsed item"); - sendKey("UP", id); + sendKey("UP"); is(listbox.selectedItem.id, id + "_item4", id + ": Up didn't skip collapsed item"); - sendKey("UP", id); + sendKey("UP"); is(listbox.selectedItem.id, id + "_item2", id + ": Up didn't skip hidden item"); listbox.selectAll(); is(listbox.selectedItems.length, 7, id + ": Should have still selected all items"); @@ -65,7 +66,7 @@ function testListbox(id) listbox.selectedIndex = 2; ok(listbox.selectedItem == listbox.getItemAtIndex(2), id + ": Should have selected the hidden item"); listbox.selectedIndex = 0; - sendKey("END", id); + sendKey("END"); is(listbox.selectedItem.id, id + "_item6", id + ": Should have moved to the last unhidden item"); sendMouseEvent({type: 'click'}, id + "_item1"); ok(listbox.selectedItem == listbox.getItemAtIndex(0), id + ": Should have selected the first item"); @@ -73,9 +74,9 @@ function testListbox(id) sendMouseEvent({type: 'click', shiftKey: true}, id + "_item6"); is(listbox.selectedItems.length, 4, id + ": Should have selected all visible items"); listbox.selectedIndex = 0; - sendKey("PAGE_DOWN", id); + sendKey("PAGE_DOWN"); is(listbox.selectedItem.id, id + "_item6", id + ": Page down should go to the last visible item"); - sendKey("PAGE_UP", id); + sendKey("PAGE_UP"); is(listbox.selectedItem.id, id + "_item1", id + ": Page up should go to the first visible item"); } diff --git a/toolkit/content/tests/chrome/test_hiddenpaging.xul b/toolkit/content/tests/chrome/test_hiddenpaging.xul index bd56385a51f5..912494b46495 100644 --- a/toolkit/content/tests/chrome/test_hiddenpaging.xul +++ b/toolkit/content/tests/chrome/test_hiddenpaging.xul @@ -71,23 +71,24 @@ function testRichlistbox() { var id = "richlistbox"; var listbox = document.getElementById(id); + listbox.focus(); listbox.selectedIndex = 0; - sendKey("PAGE_DOWN", id); + sendKey("PAGE_DOWN"); is(listbox.selectedItem.id, id + "_item7", id + ": Page down should go to the item one visible page away"); is(listbox.getIndexOfFirstVisibleRow(), 6, id + ": Page down should have scrolled down a visible page"); - sendKey("PAGE_DOWN", id); + sendKey("PAGE_DOWN"); is(listbox.selectedItem.id, id + "_item11", id + ": Second page down should go to the item two visible pages away"); is(listbox.getIndexOfFirstVisibleRow(), 9, id + ": Second page down should not scroll beyond the end"); - sendKey("PAGE_DOWN", id); + sendKey("PAGE_DOWN"); is(listbox.selectedItem.id, id + "_item14", id + ": Third page down should go to the last visible item"); is(listbox.getIndexOfFirstVisibleRow(), 9, id + ": Third page down should not have scrolled at all"); - sendKey("PAGE_UP", id); + sendKey("PAGE_UP"); is(listbox.selectedItem.id, id + "_item10", id + ": Page up should go to the item one visible page away"); is(listbox.getIndexOfFirstVisibleRow(), 5, id + ": Page up should scroll up a visible page"); - sendKey("PAGE_UP", id); + sendKey("PAGE_UP"); is(listbox.selectedItem.id, id + "_item6", id + ": Second page up should go to the item two visible pages away"); is(listbox.getIndexOfFirstVisibleRow(), 0, id + ": Second page up should not scroll beyond the start"); - sendKey("PAGE_UP", id); + sendKey("PAGE_UP"); is(listbox.selectedItem.id, id + "_item1", id + ": Third page up should return to the first visible item"); is(listbox.getIndexOfFirstVisibleRow(), 0, id + ": Third page up should not have scrolled at all"); } @@ -105,24 +106,25 @@ function testListbox() var rowHeight = listbox.firstChild.getBoundingClientRect().height; + listbox.focus(); listbox.selectedIndex = 0; - sendKey("PAGE_DOWN", id); + sendKey("PAGE_DOWN"); is(listbox.selectedItem.id, id + "_item8", id + ": Page down should go to the item one visible page away"); is(listbox.getIndexOfFirstVisibleRow(), 7, id + ": Page down should have scrolled down a visible page"); - sendKey("PAGE_DOWN", id); + sendKey("PAGE_DOWN"); is(listbox.selectedItem.id, id + "_item13", id + ": Second page down should go to the item two visible pages away"); is(listbox.getIndexOfFirstVisibleRow(), 9, id + ": Second page down should not scroll beyond the end"); - sendKey("PAGE_DOWN", id); + sendKey("PAGE_DOWN"); is(listbox.selectedItem.id, id + "_item14", id + ": Third page down should go to the last visible item"); is(listbox.getIndexOfFirstVisibleRow(), 9, id + ": Third page down should not have scrolled at all"); - sendKey("PAGE_UP", id); + sendKey("PAGE_UP"); is(listbox.selectedItem.id, id + "_item9", id + ": Page up should go to the item one visible page away"); // the listScrollbox seems to go haywire when scrolling up with hidden listitems todo_is(listbox.getIndexOfFirstVisibleRow(), 3, id + ": Page up should scroll up a visible page"); - sendKey("PAGE_UP", id); + sendKey("PAGE_UP"); is(listbox.selectedItem.id, id + "_item2", id + ": Second page up should go to the item two visible pages away"); is(listbox.getIndexOfFirstVisibleRow(), 0, id + ": Second page up should not scroll beyond the start"); - sendKey("PAGE_UP", id); + sendKey("PAGE_UP"); is(listbox.selectedItem.id, id + "_item1", id + ": Third page up should return to the first visible item"); is(listbox.getIndexOfFirstVisibleRow(), 0, id + ": Third page up should not have scrolled at all"); diff --git a/toolkit/content/tests/chrome/test_richlist_direction.xul b/toolkit/content/tests/chrome/test_richlist_direction.xul index 3d03a9da922a..05e31fa61a8d 100644 --- a/toolkit/content/tests/chrome/test_richlist_direction.xul +++ b/toolkit/content/tests/chrome/test_richlist_direction.xul @@ -46,24 +46,25 @@ function test_richlistbox() // richlistboxes respond differently when a user initiates a selection richListBox.dir = "reverse"; var count = richListBox.itemCount; + richListBox.focus(); richListBox.selectedIndex = count - 1; - sendKey("DOWN", richListBox); + sendKey("DOWN"); is(richListBox.currentIndex, count - 2, "Selection should move to the next item"); - sendKey("UP", richListBox); + sendKey("UP"); is(richListBox.currentIndex, count - 1, "Selection should move to the previous item"); - sendKey("END", richListBox); + sendKey("END"); is(richListBox.currentIndex, 0, "Selection should move to the last item"); - sendKey("HOME", richListBox); + sendKey("HOME"); is(richListBox.currentIndex, count - 1, "Selection should move to the first item"); var currentIndex = richListBox.currentIndex; var index = getScrollIndexAmount(-1); - sendKey("PAGE_DOWN", richListBox); + sendKey("PAGE_DOWN"); is(richListBox.currentIndex, index, "Selection should move to one page down"); ok(richListBox.currentIndex < currentIndex, "Selection should move downwards"); - sendKey("END", richListBox); + sendKey("END"); currentIndex = richListBox.currentIndex; index = getScrollIndexAmount(1); - sendKey("PAGE_UP", richListBox); + sendKey("PAGE_UP"); is(richListBox.currentIndex, index, "Selection should move to one page up"); ok(richListBox.currentIndex > currentIndex, "Selection should move upwards"); richListBox.selectedItem = richListBox.lastChild; @@ -87,29 +88,29 @@ function test_richlistbox() aEvent.preventDefault(); }, true); richListBox.selectedIndex = 1; - sendKey("HOME", richListBox); + sendKey("HOME"); is(richListBox.selectedIndex, 1, "A stopped event should return indexing to normal"); // direction = "normal" richListBox.dir = "normal"; richListBox.selectedIndex = 0; - sendKey("DOWN", richListBox); + sendKey("DOWN"); is(richListBox.currentIndex, 1, "Selection should move to the next item"); - sendKey("UP", richListBox); + sendKey("UP"); is(richListBox.currentIndex, 0, "Selection should move to the previous item"); - sendKey("END", richListBox); + sendKey("END"); is(richListBox.currentIndex, count - 1, "Selection should move to the last item"); - sendKey("HOME", richListBox); + sendKey("HOME"); is(richListBox.currentIndex, 0, "Selection should move to the first item"); var currentIndex = richListBox.currentIndex; var index = richListBox.scrollOnePage(1); - sendKey("PAGE_DOWN", richListBox); + sendKey("PAGE_DOWN"); is(richListBox.currentIndex, index, "Selection should move to one page down"); ok(richListBox.currentIndex > currentIndex, "Selection should move downwards"); - sendKey("END", richListBox); + sendKey("END"); currentIndex = richListBox.currentIndex; index = richListBox.scrollOnePage(-1) + richListBox.currentIndex; - sendKey("PAGE_UP", richListBox); + sendKey("PAGE_UP"); is(richListBox.currentIndex, index, "Selection should move to one page up"); ok(richListBox.currentIndex < currentIndex, "Selection should move upwards"); richListBox.selectedItem = richListBox.firstChild; From fa47ebe749879b4a2734a53ca425ae9b3214002e Mon Sep 17 00:00:00 2001 From: Masayuki Nakano Date: Fri, 16 Dec 2011 22:38:45 +0900 Subject: [PATCH 04/16] Bug 504586 test_bug430723.html should listen to scroll event after sending key events r=smaug --- docshell/test/navigation/test_bug430723.html | 55 ++++++++++++-------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/docshell/test/navigation/test_bug430723.html b/docshell/test/navigation/test_bug430723.html index 0179f4cdb3f4..95d77257e02f 100644 --- a/docshell/test/navigation/test_bug430723.html +++ b/docshell/test/navigation/test_bug430723.html @@ -62,20 +62,25 @@ var step1 =function() { // Navigate down and up. is(testWindow.document.body.scrollTop, 0, "Page1: Ensure we scrollpane is at the top before we start scrolling."); - testWindow.focus(); - sendKey('DOWN', testWindow); - SimpleTest.executeSoon(function() { + testWindow.addEventListener("scroll", function () { + testWindow.removeEventListener("scroll", arguments.callee, true); isnot(testWindow.document.body.scrollTop, 0, "Page1: Ensure we can scroll down."); - sendKey('UP', testWindow); - SimpleTest.executeSoon(function() { + SimpleTest.executeSoon(step1_2); + }, true); + sendKey('DOWN', testWindow); + + function step1_2() { + testWindow.addEventListener("scroll", function () { + testWindow.removeEventListener("scroll", arguments.callee, true); is(testWindow.document.body.scrollTop, 0, "Page1: Ensure we can scroll up, back to the top."); // Nav to blue box page. This should fire step2. testWindow.location = gTallBlueBoxURI; - }); - }); + }, true); + sendKey('UP', testWindow); + } } @@ -85,17 +90,22 @@ var step2 =function() { // Scroll around a bit. is(testWindow.document.body.scrollTop, 0, "Page2: Ensure we scrollpane is at the top before we start scrolling."); - testWindow.focus(); + + var count = 0; + testWindow.addEventListener("scroll", function () { + if (++count < 4) { + SimpleTest.executeSoon(function () { sendKey('DOWN', testWindow); }); + } else { + testWindow.removeEventListener("scroll", arguments.callee, true); + + isnot(testWindow.document.body.scrollTop, 0, + "Page2: Ensure we could scroll."); + + // Navigate backwards. This should fire step3. + testWindow.history.back(); + } + }, true); sendKey('DOWN', testWindow); - sendKey('DOWN', testWindow); - sendKey('DOWN', testWindow); - setTimeout(function() { - isnot(testWindow.document.body.scrollTop, 0, - "Page2: Ensure we could scrol."); - - // Navigate backwards. This should fire step3. - testWindow.history.back(); - }, 0); } var step3 =function() { @@ -105,15 +115,16 @@ var step3 =function() { // Check we can still scroll with the keys. is(testWindow.document.body.scrollTop, 0, "Page1Again: Ensure scroll pane at top before we scroll."); - testWindow.focus(); - sendKey('DOWN', testWindow); - setTimeout(function() { + testWindow.addEventListener("scroll", function () { + testWindow.removeEventListener("scroll", arguments.callee, true); + isnot(testWindow.document.body.scrollTop, 0, "Page2Again: Ensure we can still scroll."); - + testWindow.close(); window.SimpleTest.finish(); - }, 0); + }, true); + sendKey('DOWN', testWindow); } SimpleTest.waitForExplicitFinish(); From d6b7c6710ccda8d971db540997e95e082f96e399 Mon Sep 17 00:00:00 2001 From: Bill McCloskey Date: Fri, 16 Dec 2011 10:31:56 -0800 Subject: [PATCH 05/16] Bug 711158 - Avoid triggering write barrier during verifier (r=luke) --- js/src/jsgc.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/js/src/jsgc.cpp b/js/src/jsgc.cpp index 48ab45cf8891..10956fcd8dfb 100644 --- a/js/src/jsgc.cpp +++ b/js/src/jsgc.cpp @@ -3494,15 +3494,16 @@ EndVerifyBarriers(JSContext *cx) JS_ASSERT(trc->number == rt->gcNumber); + for (CompartmentsIter c(rt); !c.done(); c.next()) { + c->gcIncrementalTracer = NULL; + c->needsBarrier_ = false; + } + if (rt->gcIncrementalTracer->hasDelayedChildren()) rt->gcIncrementalTracer->markDelayedChildren(); rt->gcVerifyData = NULL; rt->gcIncrementalTracer = NULL; - for (CompartmentsIter c(rt); !c.done(); c.next()) { - c->gcIncrementalTracer = NULL; - c->needsBarrier_ = false; - } JS_TRACER_INIT(trc, cx, CheckAutorooter); From 22a311615c200ad7e1e143c0df7448f081c985af Mon Sep 17 00:00:00 2001 From: Mike Conley Date: Fri, 16 Dec 2011 13:42:17 -0500 Subject: [PATCH 06/16] Bug 711508 - Ensure that external toolbars are not duplicated for associated toolboxes. r=enndeakin. --- toolkit/content/widgets/toolbar.xml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/toolkit/content/widgets/toolbar.xml b/toolkit/content/widgets/toolbar.xml index bd49782918de..ae4a27155f4e 100644 --- a/toolkit/content/widgets/toolbar.xml +++ b/toolkit/content/widgets/toolbar.xml @@ -111,7 +111,9 @@ if (!toolbox) throw("toolboxid attribute points to a toolbox which doesn't exist"); - toolbox.externalToolbars.push(this); + if (toolbox.externalToolbars.indexOf(this) == -1) + toolbox.externalToolbars.push(this); + return this._toolbox = toolbox; } From 8efa6b018a849cd0b16c09b94a17a4f3611915ae Mon Sep 17 00:00:00 2001 From: Ali Juma Date: Fri, 16 Dec 2011 14:02:03 -0500 Subject: [PATCH 07/16] Bug 705641 - Add even more output to framebuffer incompleteness abort message. r=jrmuizel --- gfx/layers/opengl/LayerManagerOGL.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gfx/layers/opengl/LayerManagerOGL.cpp b/gfx/layers/opengl/LayerManagerOGL.cpp index 6e35329b6743..748523aa98e9 100644 --- a/gfx/layers/opengl/LayerManagerOGL.cpp +++ b/gfx/layers/opengl/LayerManagerOGL.cpp @@ -1171,6 +1171,10 @@ LayerManagerOGL::CreateFBOWithTexture(const nsIntRect& aRect, InitMode aInit, msg.AppendInt(result, 16); msg.Append(", mFBOTextureTarget 0x"); msg.AppendInt(mFBOTextureTarget, 16); + msg.Append(", aRect.width "); + msg.AppendInt(aRect.width); + msg.Append(", aRect.height "); + msg.AppendInt(aRect.height); NS_RUNTIMEABORT(msg.get()); } From 41962bb189e022767f86e11c6e7e851bafc93f4a Mon Sep 17 00:00:00 2001 From: James Willcox Date: Fri, 16 Dec 2011 10:54:08 -0500 Subject: [PATCH 08/16] Bug 670930 - Add Android direct texture implementation --HG-- extra : rebase_source : eb3f095e2663c0ebc0a03117ec8883d66dd8f1b5 --- mobile/android/base/GeckoAppShell.java | 31 +- widget/src/android/AndroidDirectTexture.cpp | 149 +++++++ widget/src/android/AndroidDirectTexture.h | 90 ++++ widget/src/android/AndroidGraphicBuffer.cpp | 433 ++++++++++++++++++++ widget/src/android/AndroidGraphicBuffer.h | 99 +++++ 5 files changed, 794 insertions(+), 8 deletions(-) create mode 100644 widget/src/android/AndroidDirectTexture.cpp create mode 100644 widget/src/android/AndroidDirectTexture.h create mode 100644 widget/src/android/AndroidGraphicBuffer.cpp create mode 100644 widget/src/android/AndroidGraphicBuffer.h diff --git a/mobile/android/base/GeckoAppShell.java b/mobile/android/base/GeckoAppShell.java index 6ce81de2bf98..8d326e1c202f 100644 --- a/mobile/android/base/GeckoAppShell.java +++ b/mobile/android/base/GeckoAppShell.java @@ -1229,17 +1229,32 @@ public class GeckoAppShell return accessibilityManager.isEnabled(); } - public static void addPluginView(View view, - double x, double y, - double w, double h) - { + public static void addPluginView(final View view, + final double x, final double y, + final double w, final double h) { Log.i(LOGTAG, "addPluginView:" + view + " @ x:" + x + " y:" + y + " w:" + w + " h:" + h ) ; - GeckoApp.mAppContext.addPluginView(view, x, y, w, h); + getMainHandler().post(new Runnable() { + public void run() { + try { + GeckoApp.mAppContext.addPluginView(view, x, y, w, h); + } catch (Exception e) { + Log.e(LOGTAG, "Failed to add plugin view: ", e); + } + } + }); } - public static void removePluginView(View view) { - Log.i(LOGTAG, "remove view:" + view); - GeckoApp.mAppContext.removePluginView(view); + public static void removePluginView(final View view) { + Log.i(LOGTAG, "removePluginView:" + view); + getMainHandler().post(new Runnable() { + public void run() { + try { + GeckoApp.mAppContext.removePluginView(view); + } catch (Exception e) { + Log.e(LOGTAG, "Failed to remove plugin view: ", e); + } + } + }); } public static Class loadPluginClass(String className, String libName) { diff --git a/widget/src/android/AndroidDirectTexture.cpp b/widget/src/android/AndroidDirectTexture.cpp new file mode 100644 index 000000000000..5a118e4bf4c8 --- /dev/null +++ b/widget/src/android/AndroidDirectTexture.cpp @@ -0,0 +1,149 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * James Willcox + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include "AndroidDirectTexture.h" + +typedef gfxASurface::gfxImageFormat gfxImageFormat; + +namespace mozilla { + +AndroidDirectTexture::AndroidDirectTexture(PRUint32 width, PRUint32 height, PRUint32 usage, + gfxImageFormat format) : + mLock("AndroidDirectTexture.mLock") + , mNeedFlip(false) + , mWidth(width) + , mHeight(height) + , mFormat(format) + , mPendingReallocBuffer(NULL) +{ + mFrontBuffer = new AndroidGraphicBuffer(width, height, usage, format); + mBackBuffer = new AndroidGraphicBuffer(width, height, usage, format); +} + +AndroidDirectTexture::~AndroidDirectTexture() +{ + if (mFrontBuffer) { + delete mFrontBuffer; + mFrontBuffer = NULL; + } + + if (mBackBuffer) { + delete mBackBuffer; + mBackBuffer = NULL; + } +} + +void +AndroidDirectTexture::ReallocPendingBuffer() +{ + // We may have reallocated while the current back buffer was being + // used as the front buffer. If we have such a reallocation pending + // and the current back buffer is the target buffer, do it now. + // + // It is assumed that mLock is already acquired + if (mPendingReallocBuffer == mBackBuffer) { + mBackBuffer->Reallocate(mWidth, mHeight, mFormat); + mPendingReallocBuffer = NULL; + } +} + +bool +AndroidDirectTexture::Lock(PRUint32 aUsage, unsigned char **bits) +{ + mLock.Lock(); + ReallocPendingBuffer(); + return mBackBuffer->Lock(aUsage, bits); +} + +bool +AndroidDirectTexture::Lock(PRUint32 aUsage, const nsIntRect& aRect, unsigned char **bits) +{ + mLock.Lock(); + ReallocPendingBuffer(); + return mBackBuffer->Lock(aUsage, aRect, bits); +} + +bool +AndroidDirectTexture::Unlock(bool aFlip) +{ + if (aFlip) { + mNeedFlip = true; + } + + bool result = mBackBuffer->Unlock(); + mLock.Unlock(); + + return result; +} + +bool +AndroidDirectTexture::Reallocate(PRUint32 aWidth, PRUint32 aHeight) { + return Reallocate(aWidth, aHeight, mFormat); +} + +bool +AndroidDirectTexture::Reallocate(PRUint32 aWidth, PRUint32 aHeight, gfxASurface::gfxImageFormat aFormat) +{ + MutexAutoLock lock(mLock); + + // We only reallocate the current back buffer. The front buffer is likely + // in use, so we'll reallocate it on the first Lock() after it is rotated + // to the back. + bool result = mBackBuffer->Reallocate(aWidth, aHeight, aFormat); + if (result) { + mPendingReallocBuffer = mFrontBuffer; + } + + return result; +} + +bool +AndroidDirectTexture::Bind() +{ + MutexAutoLock lock(mLock); + + if (mNeedFlip) { + AndroidGraphicBuffer* tmp = mBackBuffer; + mBackBuffer = mFrontBuffer; + mFrontBuffer = tmp; + mNeedFlip = false; + } + + return mFrontBuffer->Bind(); +} + +} /* mozilla */ diff --git a/widget/src/android/AndroidDirectTexture.h b/widget/src/android/AndroidDirectTexture.h new file mode 100644 index 000000000000..f4914e1aae66 --- /dev/null +++ b/widget/src/android/AndroidDirectTexture.h @@ -0,0 +1,90 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * James Willcox + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef AndroidDirectTexture_h_ +#define AndroidDirectTexture_h_ + +#include "gfxASurface.h" +#include "nsRect.h" +#include "mozilla/Mutex.h" +#include "AndroidGraphicBuffer.h" + +namespace mozilla { + +/** + * This is a thread safe wrapper around AndroidGraphicBuffer that handles + * double buffering. Each call to Bind() flips the buffer when necessary. + * + * You need to be careful when destroying an instance of this class. If either + * buffer is locked by the application of the driver/hardware, bad things will + * happen. Be sure that the OpenGL texture is no longer on the screen. + */ +class AndroidDirectTexture +{ +public: + AndroidDirectTexture(PRUint32 width, PRUint32 height, PRUint32 usage, gfxASurface::gfxImageFormat format); + virtual ~AndroidDirectTexture(); + + bool Lock(PRUint32 usage, unsigned char **bits); + bool Lock(PRUint32 usage, const nsIntRect& rect, unsigned char **bits); + bool Unlock(bool aFlip = true); + + bool Reallocate(PRUint32 aWidth, PRUint32 aHeight); + bool Reallocate(PRUint32 aWidth, PRUint32 aHeight, gfxASurface::gfxImageFormat aFormat); + + PRUint32 Width() { return mWidth; } + PRUint32 Height() { return mHeight; } + + bool Bind(); + +private: + mozilla::Mutex mLock; + bool mNeedFlip; + + PRUint32 mWidth; + PRUint32 mHeight; + gfxASurface::gfxImageFormat mFormat; + + AndroidGraphicBuffer* mFrontBuffer; + AndroidGraphicBuffer* mBackBuffer; + + AndroidGraphicBuffer* mPendingReallocBuffer; + void ReallocPendingBuffer(); +}; + +} /* mozilla */ +#endif /* AndroidDirectTexture_h_ */ diff --git a/widget/src/android/AndroidGraphicBuffer.cpp b/widget/src/android/AndroidGraphicBuffer.cpp new file mode 100644 index 000000000000..91e6b8fec334 --- /dev/null +++ b/widget/src/android/AndroidGraphicBuffer.cpp @@ -0,0 +1,433 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * James Willcox + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#include +#include +#include +#include "AndroidGraphicBuffer.h" + +#define LOG(args...) __android_log_print(ANDROID_LOG_INFO, "AndroidGraphicBuffer" , ## args) + +#define EGL_NATIVE_BUFFER_ANDROID 0x3140 +#define EGL_IMAGE_PRESERVED_KHR 0x30D2 + +typedef void* EGLContext; +typedef void* EGLImageKHR; +typedef void* EGLClientBuffer; +typedef void* EGLDisplay; + +typedef PRUint32 EGLenum; +typedef PRInt32 EGLint; +typedef PRUint32 EGLBoolean; + +typedef gfxASurface::gfxImageFormat gfxImageFormat; + +#define EGL_TRUE 1 +#define EGL_FALSE 0 +#define EGL_NONE 0x3038 +#define EGL_NO_CONTEXT (EGLContext)0 +#define EGL_DEFAULT_DISPLAY (void*)0 +#define ANDROID_LIBUI_PATH "/system/lib/libui.so" +#define ANDROID_GLES_PATH "/system/lib/libGLESv2.so" +#define ANDROID_EGL_PATH "/system/lib/libEGL.so" + +// Really I have no idea, but this should be big enough +#define GRAPHIC_BUFFER_SIZE 1024 + +enum { + /* buffer is never read in software */ + GRALLOC_USAGE_SW_READ_NEVER = 0x00000000, + /* buffer is rarely read in software */ + GRALLOC_USAGE_SW_READ_RARELY = 0x00000002, + /* buffer is often read in software */ + GRALLOC_USAGE_SW_READ_OFTEN = 0x00000003, + /* mask for the software read values */ + GRALLOC_USAGE_SW_READ_MASK = 0x0000000F, + + /* buffer is never written in software */ + GRALLOC_USAGE_SW_WRITE_NEVER = 0x00000000, + /* buffer is never written in software */ + GRALLOC_USAGE_SW_WRITE_RARELY = 0x00000020, + /* buffer is never written in software */ + GRALLOC_USAGE_SW_WRITE_OFTEN = 0x00000030, + /* mask for the software write values */ + GRALLOC_USAGE_SW_WRITE_MASK = 0x000000F0, + + /* buffer will be used as an OpenGL ES texture */ + GRALLOC_USAGE_HW_TEXTURE = 0x00000100, + /* buffer will be used as an OpenGL ES render target */ + GRALLOC_USAGE_HW_RENDER = 0x00000200, + /* buffer will be used by the 2D hardware blitter */ + GRALLOC_USAGE_HW_2D = 0x00000400, + /* buffer will be used with the framebuffer device */ + GRALLOC_USAGE_HW_FB = 0x00001000, + /* mask for the software usage bit-mask */ + GRALLOC_USAGE_HW_MASK = 0x00001F00, +}; + +enum { + HAL_PIXEL_FORMAT_RGBA_8888 = 1, + HAL_PIXEL_FORMAT_RGBX_8888 = 2, + HAL_PIXEL_FORMAT_RGB_888 = 3, + HAL_PIXEL_FORMAT_RGB_565 = 4, + HAL_PIXEL_FORMAT_BGRA_8888 = 5, + HAL_PIXEL_FORMAT_RGBA_5551 = 6, + HAL_PIXEL_FORMAT_RGBA_4444 = 7, +}; + +typedef struct AndroidRect { + int32_t left; + int32_t top; + int32_t right; + int32_t bottom; +} AndroidRect; + +static bool gTryRealloc = true; + +static class GLFunctions +{ +public: + GLFunctions() : mInitialized(false) + { + } + + typedef EGLDisplay (* pfnGetDisplay)(void *display_id); + pfnGetDisplay fGetDisplay; + typedef EGLint (* pfnEGLGetError)(void); + pfnEGLGetError fEGLGetError; + + typedef EGLImageKHR (* pfnCreateImageKHR)(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list); + pfnCreateImageKHR fCreateImageKHR; + typedef EGLBoolean (* pfnDestroyImageKHR)(EGLDisplay dpy, EGLImageKHR image); + pfnDestroyImageKHR fDestroyImageKHR; + + typedef void (* pfnImageTargetTexture2DOES)(GLenum target, EGLImageKHR image); + pfnImageTargetTexture2DOES fImageTargetTexture2DOES; + + typedef void (* pfnBindTexture)(GLenum target, GLuint texture); + pfnBindTexture fBindTexture; + + typedef GLenum (* pfnGLGetError)(); + pfnGLGetError fGLGetError; + + typedef void (*pfnGraphicBufferCtor)(void*, PRUint32 w, PRUint32 h, PRUint32 format, PRUint32 usage); + pfnGraphicBufferCtor fGraphicBufferCtor; + + typedef void (*pfnGraphicBufferDtor)(void*); + pfnGraphicBufferDtor fGraphicBufferDtor; + + typedef int (*pfnGraphicBufferLock)(void*, PRUint32 usage, unsigned char **addr); + pfnGraphicBufferLock fGraphicBufferLock; + + typedef int (*pfnGraphicBufferLockRect)(void*, PRUint32 usage, const AndroidRect&, unsigned char **addr); + pfnGraphicBufferLockRect fGraphicBufferLockRect; + + typedef int (*pfnGraphicBufferUnlock)(void*); + pfnGraphicBufferUnlock fGraphicBufferUnlock; + + typedef void* (*pfnGraphicBufferGetNativeBuffer)(void*); + pfnGraphicBufferGetNativeBuffer fGraphicBufferGetNativeBuffer; + + typedef int (*pfnGraphicBufferReallocate)(void*, PRUint32 w, PRUint32 h, PRUint32 format); + pfnGraphicBufferReallocate fGraphicBufferReallocate; + + bool EnsureInitialized() + { + if (mInitialized) { + return true; + } + + void *handle = dlopen(ANDROID_EGL_PATH, RTLD_LAZY); + if (!handle) { + LOG("Couldn't load EGL library"); + return false; + } + + fGetDisplay = (pfnGetDisplay)dlsym(handle, "eglGetDisplay"); + fEGLGetError = (pfnEGLGetError)dlsym(handle, "eglGetError"); + fCreateImageKHR = (pfnCreateImageKHR)dlsym(handle, "eglCreateImageKHR"); + fDestroyImageKHR = (pfnDestroyImageKHR)dlsym(handle, "eglDestroyImageKHR"); + + if (!fGetDisplay || !fEGLGetError || !fCreateImageKHR || !fDestroyImageKHR) { + LOG("Failed to find some EGL functions"); + return false; + } + + handle = dlopen(ANDROID_GLES_PATH, RTLD_LAZY); + if (!handle) { + LOG("Couldn't load GL library"); + return false; + } + + fImageTargetTexture2DOES = (pfnImageTargetTexture2DOES)dlsym(handle, "glEGLImageTargetTexture2DOES"); + fBindTexture = (pfnBindTexture)dlsym(handle, "glBindTexture"); + fGLGetError = (pfnGLGetError)dlsym(handle, "glGetError"); + + if (!fImageTargetTexture2DOES || !fBindTexture || !fGLGetError) { + LOG("Failed to find some GL functions"); + return false; + } + + handle = dlopen(ANDROID_LIBUI_PATH, RTLD_LAZY); + if (!handle) { + LOG("Couldn't load libui.so"); + return false; + } + + fGraphicBufferCtor = (pfnGraphicBufferCtor)dlsym(handle, "_ZN7android13GraphicBufferC1Ejjij"); + fGraphicBufferDtor = (pfnGraphicBufferDtor)dlsym(handle, "_ZN7android13GraphicBufferD1Ev"); + fGraphicBufferLock = (pfnGraphicBufferLock)dlsym(handle, "_ZN7android13GraphicBuffer4lockEjPPv"); + fGraphicBufferLockRect = (pfnGraphicBufferLockRect)dlsym(handle, "_ZN7android13GraphicBuffer4lockEjRKNS_4RectEPPv"); + fGraphicBufferUnlock = (pfnGraphicBufferUnlock)dlsym(handle, "_ZN7android13GraphicBuffer6unlockEv"); + fGraphicBufferGetNativeBuffer = (pfnGraphicBufferGetNativeBuffer)dlsym(handle, "_ZNK7android13GraphicBuffer15getNativeBufferEv"); + fGraphicBufferReallocate = (pfnGraphicBufferReallocate)dlsym(handle, "_ZN7android13GraphicBuffer10reallocateEjjij"); + + if (!fGraphicBufferCtor || !fGraphicBufferDtor || !fGraphicBufferLock || + !fGraphicBufferUnlock || !fGraphicBufferGetNativeBuffer) { + LOG("Failed to lookup some GraphicBuffer functions"); + return false; + } + + mInitialized = true; + return true; + } + +private: + bool mInitialized; + +} sGLFunctions; + +namespace mozilla { + +static bool ensureNoGLError(const char* name) +{ + bool result = true; + GLuint error; + + while ((error = glGetError()) != GL_NO_ERROR) { + LOG("GL error [%s]: %40x\n", name, error); + result = false; + } + + return result; +} + +AndroidGraphicBuffer::AndroidGraphicBuffer(PRUint32 width, PRUint32 height, PRUint32 usage, + gfxImageFormat format) : + mWidth(width) + , mHeight(height) + , mUsage(usage) + , mFormat(format) + , mHandle(0) + , mEGLImage(0) +{ +} + +AndroidGraphicBuffer::~AndroidGraphicBuffer() +{ + DestroyBuffer(); +} + +void +AndroidGraphicBuffer::DestroyBuffer() +{ + if (mHandle) { + if (sGLFunctions.EnsureInitialized()) { + sGLFunctions.fGraphicBufferDtor(mHandle); + } + free(mHandle); + mHandle = NULL; + } + + if (mEGLImage) { + if (sGLFunctions.EnsureInitialized()) { + sGLFunctions.fDestroyImageKHR(sGLFunctions.fGetDisplay(EGL_DEFAULT_DISPLAY), mEGLImage); + mEGLImage = NULL; + } + } +} + +bool +AndroidGraphicBuffer::EnsureBufferCreated(PRUint32 aWidth, PRUint32 aHeight, PRUint32 aUsage, gfxImageFormat aFormat) +{ + if (!mHandle) { + mHandle = malloc(GRAPHIC_BUFFER_SIZE); + sGLFunctions.fGraphicBufferCtor(mHandle, mWidth, mHeight, GetAndroidFormat(aFormat), GetAndroidUsage(aUsage)); + } + + return true; +} + +bool +AndroidGraphicBuffer::EnsureInitialized() +{ + if (!sGLFunctions.EnsureInitialized()) { + return false; + } + + EnsureBufferCreated(mWidth, mHeight, mUsage, mFormat); + return true; +} + +bool +AndroidGraphicBuffer::Lock(PRUint32 aUsage, unsigned char **bits) +{ + if (!EnsureInitialized()) + return true; + + return sGLFunctions.fGraphicBufferLock(mHandle, GetAndroidUsage(aUsage), bits) == 0; +} + +bool +AndroidGraphicBuffer::Lock(PRUint32 aUsage, const nsIntRect& aRect, unsigned char **bits) +{ + if (!EnsureInitialized()) + return false; + + AndroidRect rect; + rect.left = aRect.x; + rect.top = aRect.y; + rect.right = aRect.x + aRect.width; + rect.bottom = aRect.y + aRect.height; + + return sGLFunctions.fGraphicBufferLockRect(mHandle, GetAndroidUsage(aUsage), rect, bits) == 0; +} + +bool +AndroidGraphicBuffer::Unlock() +{ + if (!EnsureInitialized()) + return false; + + return sGLFunctions.fGraphicBufferUnlock(mHandle) == 0; +} + +bool +AndroidGraphicBuffer::Reallocate(PRUint32 aWidth, PRUint32 aHeight, gfxImageFormat aFormat) +{ + if (!EnsureInitialized()) + return false; + + // Sometimes GraphicBuffer::reallocate just doesn't work. In those cases we'll just allocate a brand + // new buffer. If reallocate fails once, never try it again. + if (!gTryRealloc || sGLFunctions.fGraphicBufferReallocate(mHandle, aWidth, aHeight, GetAndroidFormat(aFormat)) != 0) { + DestroyBuffer(); + EnsureBufferCreated(aWidth, aHeight, mUsage, aFormat); + + gTryRealloc = false; + } + + mWidth = aWidth; + mHeight = aHeight; + mFormat = aFormat; + + return true; +} + +PRUint32 +AndroidGraphicBuffer::GetAndroidUsage(PRUint32 aUsage) +{ + PRUint32 flags = 0; + + if (aUsage & UsageSoftwareRead) { + flags |= GRALLOC_USAGE_SW_READ_OFTEN; + } + + if (aUsage & UsageSoftwareWrite) { + flags |= GRALLOC_USAGE_SW_WRITE_OFTEN; + } + + if (aUsage & UsageTexture) { + flags |= GRALLOC_USAGE_HW_TEXTURE; + } + + if (aUsage & UsageTarget) { + flags |= GRALLOC_USAGE_HW_RENDER; + } + + if (aUsage & Usage2D) { + flags |= GRALLOC_USAGE_HW_2D; + } + + return flags; +} + +PRUint32 +AndroidGraphicBuffer::GetAndroidFormat(gfxImageFormat aFormat) +{ + switch (aFormat) { + case gfxImageFormat::ImageFormatRGB24: + return HAL_PIXEL_FORMAT_RGBX_8888; + case gfxImageFormat::ImageFormatRGB16_565: + return HAL_PIXEL_FORMAT_RGB_565; + default: + return 0; + } +} + +bool +AndroidGraphicBuffer::EnsureEGLImage() +{ + if (mEGLImage) + return true; + + if (!EnsureInitialized()) + return false; + + EGLint eglImgAttrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE, EGL_NONE }; + void* nativeBuffer = sGLFunctions.fGraphicBufferGetNativeBuffer(mHandle); + + mEGLImage = sGLFunctions.fCreateImageKHR(sGLFunctions.fGetDisplay(EGL_DEFAULT_DISPLAY), EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID, (EGLClientBuffer)nativeBuffer, eglImgAttrs); + return mEGLImage != NULL; +} + +bool +AndroidGraphicBuffer::Bind() +{ + if (!EnsureInitialized()) + return false; + + if (!EnsureEGLImage()) { + LOG("No valid EGLImage!"); + return false; + } + + sGLFunctions.fImageTargetTexture2DOES(GL_TEXTURE_2D, mEGLImage); + return ensureNoGLError("glEGLImageTargetTexture2DOES"); +} + +} /* mozilla */ diff --git a/widget/src/android/AndroidGraphicBuffer.h b/widget/src/android/AndroidGraphicBuffer.h new file mode 100644 index 000000000000..961c7e29d3bf --- /dev/null +++ b/widget/src/android/AndroidGraphicBuffer.h @@ -0,0 +1,99 @@ +/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Corporation code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * James Willcox + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +#ifndef AndroidGraphicBuffer_h_ +#define AndroidGraphicBuffer_h_ + +#include "gfxASurface.h" +#include "nsRect.h" + +namespace mozilla { + +/** + * This class allows access to Android's direct texturing mechanism. Locking + * the buffer gives you a pointer you can read/write to directly. It is fully + * threadsafe, but you probably really want to use the AndroidDirectTexture + * class which will handle double buffering. + * + * In order to use the buffer in OpenGL, just call Bind() and it will attach + * to whatever texture is bound to GL_TEXTURE_2D. + */ +class AndroidGraphicBuffer +{ +public: + enum { + UsageSoftwareRead = 1, + UsageSoftwareWrite = 1 << 1, + UsageTexture = 1 << 2, + UsageTarget = 1 << 3, + Usage2D = 1 << 4 + }; + + AndroidGraphicBuffer(PRUint32 width, PRUint32 height, PRUint32 usage, gfxASurface::gfxImageFormat format); + virtual ~AndroidGraphicBuffer(); + + bool Lock(PRUint32 usage, unsigned char **bits); + bool Lock(PRUint32 usage, const nsIntRect& rect, unsigned char **bits); + bool Unlock(); + bool Reallocate(PRUint32 aWidth, PRUint32 aHeight, gfxASurface::gfxImageFormat aFormat); + + PRUint32 Width() { return mWidth; } + PRUint32 Height() { return mHeight; } + + bool Bind(); + +private: + PRUint32 mWidth; + PRUint32 mHeight; + PRUint32 mUsage; + gfxASurface::gfxImageFormat mFormat; + + bool EnsureInitialized(); + bool EnsureEGLImage(); + + void DestroyBuffer(); + bool EnsureBufferCreated(PRUint32 aWidth, PRUint32 aHeight, PRUint32 aUsage, gfxASurface::gfxImageFormat aFormat); + + PRUint32 GetAndroidUsage(PRUint32 aUsage); + PRUint32 GetAndroidFormat(gfxASurface::gfxImageFormat aFormat); + + void *mHandle; + void *mEGLImage; +}; + +} /* mozilla */ +#endif /* AndroidGraphicBuffer_h_ */ From e1fd7358b3547bcd68d879f234569e113d4d5a4e Mon Sep 17 00:00:00 2001 From: James Willcox Date: Fri, 16 Dec 2011 10:54:10 -0500 Subject: [PATCH 09/16] Bug 670930 - Use asynchronous direct texturing on Android when available --HG-- extra : rebase_source : 116b2882092d11b17046bdec5ca4d142d088d6cf --- mobile/android/base/GeckoAppShell.java | 10 ++ mobile/android/base/Makefile.in | 1 + .../base/gfx/GeckoSoftwareLayerClient.java | 11 +- mobile/android/base/gfx/LayerClient.java | 12 +- mobile/android/base/gfx/WidgetTileLayer.java | 116 ++++++++++++++++++ other-licenses/android/APKOpen.cpp | 6 +- widget/src/android/AndroidJNI.cpp | 15 +++ widget/src/android/Makefile.in | 2 + widget/src/android/nsWindow.cpp | 90 +++++++++++++- widget/src/android/nsWindow.h | 5 + 10 files changed, 256 insertions(+), 12 deletions(-) create mode 100644 mobile/android/base/gfx/WidgetTileLayer.java diff --git a/mobile/android/base/GeckoAppShell.java b/mobile/android/base/GeckoAppShell.java index 8d326e1c202f..5b45086e6f7b 100644 --- a/mobile/android/base/GeckoAppShell.java +++ b/mobile/android/base/GeckoAppShell.java @@ -138,6 +138,8 @@ public class GeckoAppShell public static native void notifySmsReceived(String aSender, String aBody, long aTimestamp); public static native ByteBuffer allocateDirectBuffer(long size); public static native void freeDirectBuffer(ByteBuffer buf); + public static native void bindWidgetTexture(); + public static native boolean testDirectTexture(); // A looper thread, accessed by GeckoAppShell.getHandler private static class LooperThread extends Thread { @@ -425,6 +427,14 @@ public class GeckoAppShell Log.i(LOGTAG, "post native init"); + // If we have direct texture available, use it + if (GeckoAppShell.testDirectTexture()) { + Log.i(LOGTAG, "Using direct texture for widget layer"); + GeckoApp.mAppContext.getSoftwareLayerClient().installWidgetLayer(); + } else { + Log.i(LOGTAG, "Falling back to traditional texture upload"); + } + // Tell Gecko where the target byte buffer is for rendering GeckoAppShell.setSoftwareLayerClient(GeckoApp.mAppContext.getSoftwareLayerClient()); diff --git a/mobile/android/base/Makefile.in b/mobile/android/base/Makefile.in index 1ae1885fb044..11fff62252dd 100644 --- a/mobile/android/base/Makefile.in +++ b/mobile/android/base/Makefile.in @@ -107,6 +107,7 @@ JAVAFILES = \ gfx/TextureReaper.java \ gfx/TileLayer.java \ gfx/ViewportMetrics.java \ + gfx/WidgetTileLayer.java \ ui/PanZoomController.java \ $(NULL) diff --git a/mobile/android/base/gfx/GeckoSoftwareLayerClient.java b/mobile/android/base/gfx/GeckoSoftwareLayerClient.java index 84187ea276f0..d57ec3fe3142 100644 --- a/mobile/android/base/gfx/GeckoSoftwareLayerClient.java +++ b/mobile/android/base/gfx/GeckoSoftwareLayerClient.java @@ -45,6 +45,7 @@ import org.mozilla.gecko.gfx.LayerController; import org.mozilla.gecko.gfx.LayerRenderer; import org.mozilla.gecko.gfx.PointUtils; import org.mozilla.gecko.gfx.SingleTileLayer; +import org.mozilla.gecko.gfx.WidgetTileLayer; import org.mozilla.gecko.FloatUtils; import org.mozilla.gecko.GeckoApp; import org.mozilla.gecko.GeckoAppShell; @@ -76,7 +77,7 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL private IntSize mScreenSize, mViewportSize; private IntSize mBufferSize; private ByteBuffer mBuffer; - private final SingleTileLayer mTileLayer; + private Layer mTileLayer; /* The viewport rect that Gecko is currently displaying. */ private ViewportMetrics mGeckoViewport; @@ -125,6 +126,10 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL } } + public void installWidgetLayer() { + mTileLayer = new WidgetTileLayer(mCairoImage); + } + /** Attaches the root layer to the layer controller so that Gecko appears. */ @Override public void setLayerController(LayerController layerController) { @@ -188,7 +193,9 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL updateViewport(metadata, !mUpdateViewportOnEndDraw); mUpdateViewportOnEndDraw = false; Rect rect = new Rect(x, y, x + width, y + height); - mTileLayer.invalidate(rect); + + if (mTileLayer instanceof SingleTileLayer) + ((SingleTileLayer)mTileLayer).invalidate(rect); } finally { endTransaction(mTileLayer); } diff --git a/mobile/android/base/gfx/LayerClient.java b/mobile/android/base/gfx/LayerClient.java index f7263021ce91..1afaca3799ea 100644 --- a/mobile/android/base/gfx/LayerClient.java +++ b/mobile/android/base/gfx/LayerClient.java @@ -53,24 +53,24 @@ public abstract class LayerClient { } /** - * A utility function for calling TileLayer.beginTransaction with the + * A utility function for calling Layer.beginTransaction with the * appropriate LayerView. */ - public void beginTransaction(TileLayer aTileLayer) { + public void beginTransaction(Layer aLayer) { if (mLayerController != null) { LayerView view = mLayerController.getView(); if (view != null) { - aTileLayer.beginTransaction(view); + aLayer.beginTransaction(view); return; } } - aTileLayer.beginTransaction(); + aLayer.beginTransaction(); } // Included for symmetry. - public void endTransaction(TileLayer aTileLayer) { - aTileLayer.endTransaction(); + public void endTransaction(Layer aLayer) { + aLayer.endTransaction(); } } diff --git a/mobile/android/base/gfx/WidgetTileLayer.java b/mobile/android/base/gfx/WidgetTileLayer.java new file mode 100644 index 000000000000..f77fda204239 --- /dev/null +++ b/mobile/android/base/gfx/WidgetTileLayer.java @@ -0,0 +1,116 @@ +/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Mozilla Android code. + * + * The Initial Developer of the Original Code is Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2009-2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * James Willcox + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +package org.mozilla.gecko.gfx; + +import org.mozilla.gecko.gfx.LayerController; +import org.mozilla.gecko.gfx.SingleTileLayer; +import org.mozilla.gecko.GeckoAppShell; +import android.opengl.GLES11; +import android.opengl.GLES11Ext; +import android.graphics.RectF; +import android.util.Log; +import javax.microedition.khronos.opengles.GL10; + +/** + * Encapsulates the logic needed to draw the single-tiled Gecko texture + */ +public class WidgetTileLayer extends Layer { + + private int[] mTextureIDs; + private CairoImage mImage; + + public WidgetTileLayer(CairoImage image) { + mImage = image; + } + + protected boolean initialized() { return mTextureIDs != null; } + + @Override + public IntSize getSize() { return mImage.getSize(); } + + protected void bindAndSetGLParameters() { + GLES11.glBindTexture(GL10.GL_TEXTURE_2D, mTextureIDs[0]); + GLES11.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST); + GLES11.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); + } + + @Override + protected void finalize() throws Throwable { + if (mTextureIDs != null) + TextureReaper.get().add(mTextureIDs); + } + + @Override + protected void performUpdates(GL10 gl) { + super.performUpdates(gl); + + if (mTextureIDs == null) { + mTextureIDs = new int[1]; + GLES11.glGenTextures(1, mTextureIDs, 0); + } + + bindAndSetGLParameters(); + GeckoAppShell.bindWidgetTexture(); + } + + @Override + public void draw(RenderContext context) { + // mTextureIDs may be null here during startup if Layer.java's draw method + // failed to acquire the transaction lock and call performUpdates. + if (!initialized()) + return; + + GLES11.glBindTexture(GL10.GL_TEXTURE_2D, mTextureIDs[0]); + + RectF bounds; + int[] cropRect; + IntSize size = getSize(); + RectF viewport = context.viewport; + + bounds = getBounds(context, new FloatSize(size)); + cropRect = new int[] { 0, size.height, size.width, -size.height }; + bounds.offset(-viewport.left, -viewport.top); + + GLES11.glTexParameteriv(GL10.GL_TEXTURE_2D, GLES11Ext.GL_TEXTURE_CROP_RECT_OES, cropRect, + 0); + + float top = viewport.height() - (bounds.top + bounds.height()); + GLES11Ext.glDrawTexfOES(bounds.left, top, 0.0f, bounds.width(), bounds.height()); + } +} + diff --git a/other-licenses/android/APKOpen.cpp b/other-licenses/android/APKOpen.cpp index 6cc23c016df8..bb1a69800948 100644 --- a/other-licenses/android/APKOpen.cpp +++ b/other-licenses/android/APKOpen.cpp @@ -299,6 +299,8 @@ SHELL_WRAPPER1(cameraCallbackBridge, jbyteArray) SHELL_WRAPPER1(notifyUriVisited, jstring) SHELL_WRAPPER3(notifyBatteryChange, jdouble, jboolean, jdouble); SHELL_WRAPPER3(notifySmsReceived, jstring, jstring, jlong); +SHELL_WRAPPER0(bindWidgetTexture); +SHELL_WRAPPER0_WITH_RETURN(testDirectTexture, bool); static void * xul_handle = NULL; static time_t apk_mtime = 0; @@ -638,7 +640,7 @@ loadLibs(const char *apkName) gettimeofday(&t0, 0); struct rusage usage1; getrusage(RUSAGE_THREAD, &usage1); - + void *zip = map_file(apkName); struct cdir_end *dirend = (struct cdir_end *)((char *)zip + zip_size - sizeof(*dirend)); while ((void *)dirend > zip && @@ -704,6 +706,8 @@ loadLibs(const char *apkName) GETFUNC(notifyUriVisited); GETFUNC(notifyBatteryChange); GETFUNC(notifySmsReceived); + GETFUNC(bindWidgetTexture); + GETFUNC(testDirectTexture); #undef GETFUNC sStartupTimeline = (uint64_t *)__wrap_dlsym(xul_handle, "_ZN7mozilla15StartupTimeline16sStartupTimelineE"); gettimeofday(&t1, 0); diff --git a/widget/src/android/AndroidJNI.cpp b/widget/src/android/AndroidJNI.cpp index 3a1762eb128a..5d363ad520ec 100644 --- a/widget/src/android/AndroidJNI.cpp +++ b/widget/src/android/AndroidJNI.cpp @@ -40,6 +40,7 @@ #include "nsString.h" #include "AndroidBridge.h" +#include "AndroidGraphicBuffer.h" #include #include @@ -88,6 +89,8 @@ extern "C" { NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_notifyUriVisited(JNIEnv *, jclass, jstring uri); NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_notifyBatteryChange(JNIEnv* jenv, jclass, jdouble, jboolean, jdouble); NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_notifySmsReceived(JNIEnv* jenv, jclass, jstring, jstring, jlong); + NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_bindWidgetTexture(JNIEnv* jenv, jclass); + NS_EXPORT bool JNICALL Java_org_mozilla_gecko_GeckoAppShell_testDirectTexture(JNIEnv* jenv, jclass); } @@ -278,3 +281,15 @@ Java_org_mozilla_gecko_GeckoAppShell_notifySmsReceived(JNIEnv* jenv, jclass, nsCOMPtr runnable = new NotifySmsReceivedRunnable(message); NS_DispatchToMainThread(runnable); } + +NS_EXPORT void JNICALL +Java_org_mozilla_gecko_GeckoAppShell_bindWidgetTexture(JNIEnv* jenv, jclass) +{ + nsWindow::BindToTexture(); +} + +NS_EXPORT bool JNICALL +Java_org_mozilla_gecko_GeckoAppShell_testDirectTexture(JNIEnv* jenv, jclass) +{ + return nsWindow::HasDirectTexture(); +} diff --git a/widget/src/android/Makefile.in b/widget/src/android/Makefile.in index 865142727ab2..91e345e92011 100644 --- a/widget/src/android/Makefile.in +++ b/widget/src/android/Makefile.in @@ -61,6 +61,8 @@ CPPSRCS = \ nsAppShell.cpp \ AndroidJavaWrappers.cpp \ AndroidBridge.cpp \ + AndroidDirectTexture.cpp \ + AndroidGraphicBuffer.cpp \ AndroidJNI.cpp \ nsWindow.cpp \ nsLookAndFeel.cpp \ diff --git a/widget/src/android/nsWindow.cpp b/widget/src/android/nsWindow.cpp index d5b1fc5abd30..cce5147829e4 100644 --- a/widget/src/android/nsWindow.cpp +++ b/widget/src/android/nsWindow.cpp @@ -39,6 +39,7 @@ #include #include +#include #include "mozilla/dom/ContentParent.h" #include "mozilla/dom/ContentChild.h" @@ -92,6 +93,20 @@ static gfxIntSize gAndroidScreenBounds; bool nsWindow::sAccessibilityEnabled = false; #endif +#ifdef MOZ_JAVA_COMPOSITOR +#include "mozilla/Mutex.h" +#include "nsThreadUtils.h" +#include "AndroidDirectTexture.h" + +static AndroidDirectTexture* sDirectTexture = new AndroidDirectTexture(2048, 2048, + AndroidGraphicBuffer::UsageSoftwareWrite | AndroidGraphicBuffer::UsageTexture, + gfxASurface::ImageFormatRGB16_565); + +static bool sHasDirectTexture = true; + +#endif + + class ContentCreationNotifier; static nsCOMPtr gContentCreationNotifier; // A helper class to send updates when content processes @@ -808,6 +823,49 @@ nsWindow::GetThebesSurface() return new gfxImageSurface(gfxIntSize(5,5), gfxImageSurface::ImageFormatRGB24); } +void +nsWindow::BindToTexture() +{ + sDirectTexture->Bind(); +} + +bool +nsWindow::HasDirectTexture() +{ + // If we already tested, return early + if (!sHasDirectTexture) + return false; + + AndroidGraphicBuffer* buffer = new AndroidGraphicBuffer(512, 512, + AndroidGraphicBuffer::UsageSoftwareWrite | AndroidGraphicBuffer::UsageTexture, + gfxASurface::ImageFormatRGB16_565); + + unsigned char* bits = NULL; + if (!buffer->Lock(AndroidGraphicBuffer::UsageSoftwareWrite, &bits) || !bits) { + ALOG("failed to lock graphic buffer"); + buffer->Unlock(); + sHasDirectTexture = false; + goto cleanup; + } + + if (!buffer->Unlock()) { + ALOG("failed to unlock graphic buffer"); + sHasDirectTexture = false; + goto cleanup; + } + + if (!buffer->Reallocate(1024, 1024, gfxASurface::ImageFormatRGB16_565)) { + ALOG("failed to reallocate graphic buffer"); + sHasDirectTexture = false; + goto cleanup; + } + +cleanup: + delete buffer; + + return sHasDirectTexture; +} + void nsWindow::OnGlobalAndroidEvent(AndroidGeckoEvent *ae) { @@ -1111,9 +1169,26 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae) client.BeginDrawing(); nsAutoString metadata; - unsigned char *bits = client.LockBufferBits(); + unsigned char *bits = NULL; + if (sHasDirectTexture) { + if ((sDirectTexture->Width() != gAndroidBounds.width || + sDirectTexture->Height() != gAndroidBounds.height) && + gAndroidBounds.width != 0 && gAndroidBounds.height != 0) { + sDirectTexture->Reallocate(gAndroidBounds.width, gAndroidBounds.height); + } + + sDirectTexture->Lock(AndroidGraphicBuffer::UsageSoftwareWrite, &bits); + } else { + bits = client.LockBufferBits(); + } if (!bits) { ALOG("### Failed to lock buffer"); + + if (sHasDirectTexture) { + sDirectTexture->Unlock(); + } else { + client.UnlockBuffer(); + } } else { nsRefPtr targetSurface = new gfxImageSurface(bits, gfxIntSize(gAndroidBounds.width, gAndroidBounds.height), gAndroidBounds.width * 2, @@ -1121,7 +1196,12 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae) if (targetSurface->CairoStatus()) { ALOG("### Failed to create a valid surface from the bitmap"); } else { - DrawTo(targetSurface, ae->Rect()); + if (sHasDirectTexture) { + // XXX: lock only the dirty rect above and pass it in here + DrawTo(targetSurface); + } else { + DrawTo(targetSurface, ae->Rect()); + } { nsCOMPtr metadataProvider = @@ -1130,7 +1210,11 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae) metadataProvider->GetDrawMetadata(metadata); } } - client.UnlockBuffer(); + if (sHasDirectTexture) { + sDirectTexture->Unlock(); + } else { + client.UnlockBuffer(); + } } client.EndDrawing(ae->Rect(), metadata); return; diff --git a/widget/src/android/nsWindow.h b/widget/src/android/nsWindow.h index fb557ac63a25..0a3d5f688443 100644 --- a/widget/src/android/nsWindow.h +++ b/widget/src/android/nsWindow.h @@ -177,6 +177,11 @@ public: static bool sAccessibilityEnabled; #endif +#ifdef MOZ_JAVA_COMPOSITOR + static void BindToTexture(); + static bool HasDirectTexture(); +#endif + protected: void BringToFront(); nsWindow *FindTopLevel(); From 2b13c975ad528c044da3e8df01adb67e8c45c484 Mon Sep 17 00:00:00 2001 From: Jim Mathies Date: Fri, 16 Dec 2011 08:53:07 -0600 Subject: [PATCH 10/16] Bug 710995 - (pvs-studio) Possible bad null-check in ShortcutResolver::Init(). False positive, no bug. Code cleanup patch. r=rstrong --- xpcom/io/nsLocalFileWin.cpp | 71 ++++++++++++------------------------- 1 file changed, 23 insertions(+), 48 deletions(-) diff --git a/xpcom/io/nsLocalFileWin.cpp b/xpcom/io/nsLocalFileWin.cpp index 8e368bdad8f7..3a05f57cf25e 100644 --- a/xpcom/io/nsLocalFileWin.cpp +++ b/xpcom/io/nsLocalFileWin.cpp @@ -43,6 +43,7 @@ #include "mozilla/Util.h" #include "nsCOMPtr.h" +#include "nsAutoPtr.h" #include "nsMemory.h" #include "nsLocalFile.h" @@ -142,52 +143,36 @@ public: nsresult Resolve(const WCHAR* in, WCHAR* out); private: - Mutex mLock; - IPersistFile* mPersistFile; - // Win 95 and 98 don't have IShellLinkW - IShellLinkW* mShellLink; + Mutex mLock; + nsRefPtr mPersistFile; + nsRefPtr mShellLink; }; -ShortcutResolver::ShortcutResolver() : mLock("ShortcutResolver.mLock") +ShortcutResolver::ShortcutResolver() : + mLock("ShortcutResolver.mLock") { - mPersistFile = nsnull; - mShellLink = nsnull; + CoInitialize(NULL); } ShortcutResolver::~ShortcutResolver() { - // Release the pointer to the IPersistFile interface. - if (mPersistFile) - mPersistFile->Release(); - - // Release the pointer to the IShellLink interface. - if (mShellLink) - mShellLink->Release(); - CoUninitialize(); } nsresult ShortcutResolver::Init() { - CoInitialize(NULL); // FIX: we should probably move somewhere higher up during startup - - HRESULT hres; - hres = CoCreateInstance(CLSID_ShellLink, - NULL, - CLSCTX_INPROC_SERVER, - IID_IShellLinkW, - (void**)&(mShellLink)); - if (SUCCEEDED(hres)) - { - // Get a pointer to the IPersistFile interface. - hres = mShellLink->QueryInterface(IID_IPersistFile, - (void**)&mPersistFile); - } - - if (mPersistFile == nsnull || mShellLink == nsnull) + // Get a pointer to the IPersistFile interface. + if (FAILED(CoCreateInstance(CLSID_ShellLink, + NULL, + CLSCTX_INPROC_SERVER, + IID_IShellLinkW, + getter_AddRefs(mShellLink))) || + FAILED(mShellLink->QueryInterface(IID_IPersistFile, + getter_AddRefs(mPersistFile)))) { + mShellLink = nsnull; return NS_ERROR_FAILURE; - + } return NS_OK; } @@ -195,24 +180,14 @@ ShortcutResolver::Init() nsresult ShortcutResolver::Resolve(const WCHAR* in, WCHAR* out) { + if (!mShellLink) + return NS_ERROR_FAILURE; + MutexAutoLock lock(mLock); - // see if we can Load the path. - HRESULT hres = mPersistFile->Load(in, STGM_READ); - - if (FAILED(hres)) - return NS_ERROR_FAILURE; - - // Resolve the link. - hres = mShellLink->Resolve(nsnull, SLR_NO_UI); - - if (FAILED(hres)) - return NS_ERROR_FAILURE; - - // Get the path to the link target. - hres = mShellLink->GetPath(out, MAX_PATH, NULL, SLGP_UNCPRIORITY); - - if (FAILED(hres)) + if (FAILED(mPersistFile->Load(in, STGM_READ)) || + FAILED(mShellLink->Resolve(nsnull, SLR_NO_UI)) || + FAILED(mShellLink->GetPath(out, MAX_PATH, NULL, SLGP_UNCPRIORITY))) return NS_ERROR_FAILURE; return NS_OK; } From b74a3a59599c78a02c800d467872cd3901a5318d Mon Sep 17 00:00:00 2001 From: Jim Mathies Date: Fri, 16 Dec 2011 09:10:16 -0600 Subject: [PATCH 11/16] Bug 661991 - follow up, make sure and clear file lists before calling file picker's Show. r=bbondy. --- widget/src/windows/nsFilePicker.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/widget/src/windows/nsFilePicker.cpp b/widget/src/windows/nsFilePicker.cpp index d191a380a090..8de6580122b4 100644 --- a/widget/src/windows/nsFilePicker.cpp +++ b/widget/src/windows/nsFilePicker.cpp @@ -813,9 +813,6 @@ nsFilePicker::ShowXPFilePicker(const nsString& aInitialDir) return true; } - // Clear previous file selection list - mFiles.Clear(); - // Set user-selected location of file or directory. From msdn's "Open and // Save As Dialog Boxes" section: // If you specify OFN_EXPLORER, the directory and file name strings are NULL @@ -1040,7 +1037,9 @@ nsFilePicker::ShowW(PRInt16 *aReturnVal) initialDir = mLastUsedUnicodeDirectory; } + // Clear previous file selections mUnicodeFile.Truncate(); + mFiles.Clear(); bool result = false; if (mMode == modeGetFolder) { From a48bdecde5d6ec88d6607a4c9560755e7be3a7eb Mon Sep 17 00:00:00 2001 From: Geoff Brown Date: Fri, 16 Dec 2011 14:27:51 -0500 Subject: [PATCH 12/16] Bug 710827 - add robotium.jar to m-c under build/mobile/robocop; r=jmaher --- build/mobile/robocop/README | 9 +++++++++ build/mobile/robocop/robotium-solo-3.0.jar | Bin 0 -> 49323 bytes 2 files changed, 9 insertions(+) create mode 100644 build/mobile/robocop/README create mode 100644 build/mobile/robocop/robotium-solo-3.0.jar diff --git a/build/mobile/robocop/README b/build/mobile/robocop/README new file mode 100644 index 000000000000..6ac55829f7b8 --- /dev/null +++ b/build/mobile/robocop/README @@ -0,0 +1,9 @@ +Robocop is a Mozilla project which uses Robotium to test Firefox on Android devices. + +Robotium is an open source tool licensed under the Apache 2.0 license and the original +source can be found here: +http://code.google.com/p/robotium/ + +We are including robotium-solo-3.0.jar as a binary and are not modifying it in anyway +from the original download found at: +http://code.google.com/p/robotium/ diff --git a/build/mobile/robocop/robotium-solo-3.0.jar b/build/mobile/robocop/robotium-solo-3.0.jar new file mode 100644 index 0000000000000000000000000000000000000000..3305251f61d61702e0f3dd61f67eb11e984ac587 GIT binary patch literal 49323 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

Z+EFu|M14tZhZAZ6z9Z_vun%yGFss+D4k+u1oYk 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 feNsQIJ literal 0 HcmV?d00001 From 90498fe0fa10a960bcfb1ab14e27b718523b5dfc Mon Sep 17 00:00:00 2001 From: Joel Maher Date: Fri, 16 Dec 2011 14:27:52 -0500 Subject: [PATCH 13/16] Bug 701076 - [tests] Robotium integration into mozilla-central. r=mfinkle,dburns --- .../android/base/tests/testAwesomebar.java.in | 108 ++++++++++++++++ .../android/base/tests/testBookmark.java.in | 109 ++++++++++++++++ mobile/android/base/tests/testLoad.java.in | 96 ++++++++++++++ mobile/android/base/tests/testNewTab.java.in | 111 ++++++++++++++++ mobile/android/base/tests/testPan.java.in | 120 ++++++++++++++++++ 5 files changed, 544 insertions(+) create mode 100644 mobile/android/base/tests/testAwesomebar.java.in create mode 100644 mobile/android/base/tests/testBookmark.java.in create mode 100644 mobile/android/base/tests/testLoad.java.in create mode 100644 mobile/android/base/tests/testNewTab.java.in create mode 100644 mobile/android/base/tests/testPan.java.in diff --git a/mobile/android/base/tests/testAwesomebar.java.in b/mobile/android/base/tests/testAwesomebar.java.in new file mode 100644 index 000000000000..aa223cea4d64 --- /dev/null +++ b/mobile/android/base/tests/testAwesomebar.java.in @@ -0,0 +1,108 @@ +#filter substitution +package @ANDROID_PACKAGE_NAME@.tests; + +import com.jayway.android.robotium.solo.Solo; +import @ANDROID_PACKAGE_NAME@.*; + +import android.app.Activity; +import android.test.ActivityInstrumentationTestCase2; +import android.test.PerformanceTestCase; +import android.util.Log; +import android.widget.Button; +import android.content.Intent; +import java.util.HashMap; + +@SuppressWarnings("unused") +public class testAwesomebar extends ActivityInstrumentationTestCase2 { + + @SuppressWarnings("unchecked") + public testAwesomebar(Class activityClass) { + super(activityClass); + // TODO Auto-generated constructor stub + } + private static final String TARGET_PACKAGE_ID = "org.mozilla.gecko"; + private static final String LAUNCH_ACTIVITY_FULL_CLASSNAME="@ANDROID_PACKAGE_NAME@.App"; + private Solo solo; + private Activity activity; + private Driver driver; + private Actions actions; + private static Class launcherActivityClass; + + static{ + try{ + launcherActivityClass = Class.forName(LAUNCH_ACTIVITY_FULL_CLASSNAME); + } catch (ClassNotFoundException e){ + throw new RuntimeException(e); + } + } + + @SuppressWarnings("unchecked") + public testAwesomebar() throws ClassNotFoundException { + super(TARGET_PACKAGE_ID, launcherActivityClass); + } + + @Override + protected void setUp() throws Exception + { + // Load config file from sdcard (setup by python script) + String configFile = FennecNativeDriver.getFile("/mnt/sdcard/robotium.config"); + HashMap config = FennecNativeDriver.convertTextToTable(configFile); + + // Create the intent to be used with all the important arguments. + Intent i = new Intent(Intent.ACTION_MAIN); + String argsList = "-no-remote -profile " + (String)config.get("profile"); + i.putExtra("args", argsList); + + //Start the activity + setActivityIntent(i); + activity = getActivity(); + + //Set up Robotium.solo and Driver objects + solo = new Solo(getInstrumentation(), getActivity()); + driver = new FennecNativeDriver(activity, solo); + actions = new FennecNativeActions(activity, solo, getInstrumentation()); + driver.setLogFile((String)config.get("logfile")); + } + + public void testAwesomebar() { + // TODO: find a better way to not hardcode this url + String url = "http://mochi.test:8888/tests/robocop/robocop.html"; + Element awesomebar = driver.findElement("awesome_bar"); + awesomebar.click(); + + Element urlbar = driver.findElement("awesomebar_text"); + actions.sendKeys(url); + driver.is(url, urlbar.getText(), "Awesomebar URL Typed Properly"); + //could also use: urlbar.clickSpecialKey(Element.SpecialKey.ENTER) + actions.sendKeys("\n"); + //wait for screen to load + actions.waitForGeckoEvent("DOMContentLoaded"); + driver.setupScrollHandling(); + //Calculate where we should be dragging. + int midX = driver.getGeckoLeft() + driver.getGeckoWidth()/2; + int midY = driver.getGeckoTop() + driver.getGeckoHeight()/2; + int endY = driver.getGeckoTop() + driver.getGeckoHeight()/10; + for(int i = 0; i < 10; i++) { + actions.drag(midX,midX,midY,endY); + try { + Thread.sleep(200); + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + //Click the awesomebar again + awesomebar.click(); + driver.is(url, urlbar.getText(), "Aweosmebar URL stayed the same"); + } + + @Override + public void tearDown() throws Exception { + try { + solo.finalize(); + }catch (Throwable e){ + e.printStackTrace(); + } + getActivity().finish(); + super.tearDown(); + } +} diff --git a/mobile/android/base/tests/testBookmark.java.in b/mobile/android/base/tests/testBookmark.java.in new file mode 100644 index 000000000000..011c07163e49 --- /dev/null +++ b/mobile/android/base/tests/testBookmark.java.in @@ -0,0 +1,109 @@ +#filter substitution +package @ANDROID_PACKAGE_NAME@.tests; + +import com.jayway.android.robotium.solo.Solo; +import @ANDROID_PACKAGE_NAME@.*; + +import android.app.Activity; +import android.test.ActivityInstrumentationTestCase2; +import android.test.PerformanceTestCase; +import android.util.Log; +import android.widget.Button; +import android.content.Intent; +import java.util.HashMap; + +@SuppressWarnings("unused") +public class testBookmark extends ActivityInstrumentationTestCase2 { + + @SuppressWarnings("unchecked") + public testBookmark(Class activityClass) { + super(activityClass); + // TODO Auto-generated constructor stub + } + private static final String TARGET_PACKAGE_ID = "org.mozilla.gecko"; + private static final String LAUNCH_ACTIVITY_FULL_CLASSNAME="@ANDROID_PACKAGE_NAME@.App"; + private Solo solo; + private Activity activity; + private Driver driver; + private Actions actions; + private static Class launcherActivityClass; + + static{ + try{ + launcherActivityClass = Class.forName(LAUNCH_ACTIVITY_FULL_CLASSNAME); + } catch (ClassNotFoundException e){ + throw new RuntimeException(e); + } + } + + @SuppressWarnings("unchecked") + public testBookmark() throws ClassNotFoundException { + super(TARGET_PACKAGE_ID, launcherActivityClass); + } + + @Override + protected void setUp() throws Exception + { + //Load config file + String configFile = FennecNativeDriver.getFile("/mnt/sdcard/robotium.config"); + HashMap config = FennecNativeDriver.convertTextToTable(configFile); + + //Create the intent to be used with all the important arguments + Intent i = new Intent(Intent.ACTION_MAIN); + String argsList = "-no-remote -profile " + (String)config.get("profile"); + i.putExtra("args", argsList); + + //Start the activity + setActivityIntent(i); + activity = getActivity(); + + //Set up Robotium.solo and Driver objects + solo = new Solo(getInstrumentation(), getActivity()); + driver = new FennecNativeDriver(activity, solo); + actions = new FennecNativeActions(activity, solo, getInstrumentation()); + driver.setLogFile((String)config.get("logfile")); + } + + public void testBookmark(){ + // TODO: find a better way to not hardcode this url + String url = "http://mochi.test:8888/tests/robocop/robocop.html"; + Element awesomebar = driver.findElement("awesome_bar"); + awesomebar.click(); + + Element urlbar = driver.findElement("awesomebar_text"); + actions.sendKeys(url); + driver.is(url, urlbar.getText(), "Awesomebar url typed properly"); + + //Click the top item in the list. + actions.sendSpecialKey(Actions.SpecialKey.DOWN); + actions.sendSpecialKey(Actions.SpecialKey.ENTER); + actions.waitForGeckoEvent("DOMContentLoaded"); + + awesomebar.click(); + driver.is(url, urlbar.getText(),"Awesomebar URL still on"); + + + //Click the Top item in the history list. + actions.sendSpecialKey(Actions.SpecialKey.RIGHT); + actions.sendSpecialKey(Actions.SpecialKey.RIGHT); + actions.sendSpecialKey(Actions.SpecialKey.DOWN); + actions.sendSpecialKey(Actions.SpecialKey.DOWN); + actions.sendSpecialKey(Actions.SpecialKey.ENTER); + actions.waitForGeckoEvent("DOMContentLoaded"); + + awesomebar.click(); + //Unfortunately, the item isn't constant so can't be tested. + //driver.is(url, urlbar.getText(),"Shouldn't this be the last url in the history?"); + } + + @Override + public void tearDown() throws Exception { + try { + solo.finalize(); + }catch (Throwable e){ + e.printStackTrace(); + } + getActivity().finish(); + super.tearDown(); + } +} diff --git a/mobile/android/base/tests/testLoad.java.in b/mobile/android/base/tests/testLoad.java.in new file mode 100644 index 000000000000..64443c4f2ea7 --- /dev/null +++ b/mobile/android/base/tests/testLoad.java.in @@ -0,0 +1,96 @@ +#filter substitution +package @ANDROID_PACKAGE_NAME@.tests; + +import com.jayway.android.robotium.solo.Solo; +import @ANDROID_PACKAGE_NAME@.*; + +import android.app.Activity; +import android.test.ActivityInstrumentationTestCase2; +import android.test.PerformanceTestCase; +import android.util.Log; +import android.widget.Button; +import android.content.Intent; +import java.util.HashMap; + +@SuppressWarnings("unused") +public class testLoad extends ActivityInstrumentationTestCase2 { + + @SuppressWarnings("unchecked") + public testLoad(Class activityClass) { + super(activityClass); + // TODO Auto-generated constructor stub + } + private static final String TARGET_PACKAGE_ID = "org.mozilla.gecko"; + private static final String LAUNCH_ACTIVITY_FULL_CLASSNAME="@ANDROID_PACKAGE_NAME@.App"; + private Solo solo; + private Activity activity; + private Driver driver; + private Actions actions; + private static Class launcherActivityClass; + + static{ + try{ + launcherActivityClass = Class.forName(LAUNCH_ACTIVITY_FULL_CLASSNAME); + } catch (ClassNotFoundException e){ + throw new RuntimeException(e); + } + } + + @SuppressWarnings("unchecked") + public testLoad() throws ClassNotFoundException { + super(TARGET_PACKAGE_ID, launcherActivityClass); + } + + @Override + protected void setUp() throws Exception + { + //Load config file + String configFile = FennecNativeDriver.getFile("/mnt/sdcard/robotium.config"); + HashMap config = FennecNativeDriver.convertTextToTable(configFile); + + //Create the intent to be used with all the important arguments + Intent i = new Intent(Intent.ACTION_MAIN); + String argsList = "-no-remote -profile " + (String)config.get("profile"); + i.putExtra("args", argsList); + + //Start the activity + setActivityIntent(i); + activity = getActivity(); + + //Set up Robotium.solo and Driver objects + solo = new Solo(getInstrumentation(), getActivity()); + driver = new FennecNativeDriver(activity, solo); + actions = new FennecNativeActions(activity, solo, getInstrumentation()); + driver.setLogFile((String)config.get("logfile")); + } + + public void testLoad(){ + // TODO: find a better way to not hardcode this url + String url = "http://mochi.test:8888/tests/robocop/robocop.html"; + Element awesomebar = driver.findElement("awesome_bar"); + awesomebar.click(); + + Element urlbar = driver.findElement("awesomebar_text"); + actions.sendKeys(url); + driver.is(url, urlbar.getText(),"Awesomebar URL Correct"); + + //Select top item in the list. + actions.sendSpecialKey(Actions.SpecialKey.DOWN); + actions.sendKeys("\n"); + actions.waitForGeckoEvent("DOMContentLoaded"); + + awesomebar.click(); + driver.is(url, urlbar.getText(), "Awesomebar URL is still correct"); + } + + @Override + public void tearDown() throws Exception { + try { + solo.finalize(); + }catch (Throwable e){ + e.printStackTrace(); + } + getActivity().finish(); + super.tearDown(); + } +} diff --git a/mobile/android/base/tests/testNewTab.java.in b/mobile/android/base/tests/testNewTab.java.in new file mode 100644 index 000000000000..cd38dfd1a56b --- /dev/null +++ b/mobile/android/base/tests/testNewTab.java.in @@ -0,0 +1,111 @@ +#filter substitution +package @ANDROID_PACKAGE_NAME@.tests; + +import com.jayway.android.robotium.solo.Solo; +import @ANDROID_PACKAGE_NAME@.*; + +import android.app.Activity; +import android.test.ActivityInstrumentationTestCase2; +import android.test.PerformanceTestCase; +import android.util.Log; +import android.widget.Button; +import android.content.Intent; +import java.util.HashMap; + +@SuppressWarnings("unused") +public class testNewTab extends ActivityInstrumentationTestCase2 { + + @SuppressWarnings("unchecked") + public testNewTab(Class activityClass) { + super(activityClass); + // TODO Auto-generated constructor stub + } + private static final String TARGET_PACKAGE_ID = "org.mozilla.gecko"; + private static final String LAUNCH_ACTIVITY_FULL_CLASSNAME="@ANDROID_PACKAGE_NAME@.App"; + private Solo solo; + private Activity activity; + private Actions actions; + private Driver driver; + private static Class launcherActivityClass; + + static{ + try{ + launcherActivityClass = Class.forName(LAUNCH_ACTIVITY_FULL_CLASSNAME); + } catch (ClassNotFoundException e){ + throw new RuntimeException(e); + } + } + + @SuppressWarnings("unchecked") + public testNewTab() throws ClassNotFoundException { + super(TARGET_PACKAGE_ID, launcherActivityClass); + } + + @Override + protected void setUp() throws Exception + { + // Load config file from sdcard (setup by python script) + String configFile = FennecNativeDriver.getFile("/mnt/sdcard/robotium.config"); + HashMap config = FennecNativeDriver.convertTextToTable(configFile); + + // Create the intent to be used with all the important arguments. + Intent i = new Intent(Intent.ACTION_MAIN); + String argsList = "-no-remote -profile " + (String)config.get("profile"); + i.putExtra("args", argsList); + + //Start the activity + setActivityIntent(i); + activity = getActivity(); + + //Set up Robotium.solo and Driver objects + solo = new Solo(getInstrumentation(), getActivity()); + driver = new FennecNativeDriver(activity, solo); + actions = new FennecNativeActions(activity, solo, getInstrumentation()); + driver.setLogFile((String)config.get("logfile")); + } + + public void testNewTab(){ + // TODO: find a better way to not hardcode this url + String url = "http://mochi.test:8888/tests/robocop/robocop.html"; + Element tabs = driver.findElement("tabs"); + //Add one tab + tabs.click(); + + Element urlbar = driver.findElement("awesomebar_text"); + actions.sendKeys(url); + driver.is(url, urlbar.getText(),"Awesomebar url is fine"); + actions.sendSpecialKey(Actions.SpecialKey.ENTER); + actions.waitForGeckoEvent("DOMContentLoaded"); + + try{Thread.sleep(5000);}catch(Throwable e){}; + //See tab count + Element tabCount = driver.findElement("tabs_count"); + driver.is("2", tabCount.getText(),"Number of tabs has increased"); + + //Click tab list + tabs.click(); + Element addTab = driver.findElement("add_tab"); + + //Add another tab + addTab.click(); + actions.sendKeys(url); + driver.is(url, urlbar.getText(),"URL is still fine"); + + actions.sendSpecialKey(Actions.SpecialKey.ENTER); + actions.waitForGeckoEvent("DOMContentLoaded"); + //Check tab count another time. + driver.is("3", tabCount.getText(),"Number of tabs has increased"); + + } + + @Override + public void tearDown() throws Exception { + try { + solo.finalize(); + }catch (Throwable e){ + e.printStackTrace(); + } + getActivity().finish(); + super.tearDown(); + } +} diff --git a/mobile/android/base/tests/testPan.java.in b/mobile/android/base/tests/testPan.java.in new file mode 100644 index 000000000000..29b6643389ca --- /dev/null +++ b/mobile/android/base/tests/testPan.java.in @@ -0,0 +1,120 @@ +#filter substitution +package @ANDROID_PACKAGE_NAME@.tests; + + +import com.jayway.android.robotium.solo.Solo; +import @ANDROID_PACKAGE_NAME@.*; + +import android.app.Activity; +import android.test.ActivityInstrumentationTestCase2; +import android.test.PerformanceTestCase; +import android.util.Log; +import android.widget.Button; +import android.content.Intent; +import java.util.HashMap; +import java.util.List; + +@SuppressWarnings("unused") +public class testPan extends ActivityInstrumentationTestCase2 { + + @SuppressWarnings("unchecked") + public testPan(Class activityClass) { + super(activityClass); + // TODO Auto-generated constructor stub + } + private static final String TARGET_PACKAGE_ID = "org.mozilla.gecko"; + private static final String LAUNCH_ACTIVITY_FULL_CLASSNAME="@ANDROID_PACKAGE_NAME@.App"; + private Solo solo; + private Activity activity; + private Driver driver; + private Actions actions; + private static Class launcherActivityClass; + + static{ + try{ + launcherActivityClass = Class.forName(LAUNCH_ACTIVITY_FULL_CLASSNAME); + } catch (ClassNotFoundException e){ + throw new RuntimeException(e); + } + } + + @SuppressWarnings("unchecked") + public testPan() throws ClassNotFoundException { + super(TARGET_PACKAGE_ID, launcherActivityClass); + } + + @Override + protected void setUp() throws Exception + { + // Load config file from sdcard (setup by python script) + String configFile = FennecNativeDriver.getFile("/mnt/sdcard/robotium.config"); + HashMap config = FennecNativeDriver.convertTextToTable(configFile); + + // Create the intent to be used with all the important arguments. + Intent i = new Intent(Intent.ACTION_MAIN); + String argsList = "-no-remote -profile " + (String)config.get("profile"); + i.putExtra("args", argsList); + + //Start the activity + setActivityIntent(i); + activity = getActivity(); + + //Set up Robotium.solo and Driver objects + solo = new Solo(getInstrumentation(), getActivity()); + driver = new FennecNativeDriver(activity, solo); + actions = new FennecNativeActions(activity, solo, getInstrumentation()); + driver.setLogFile((String)config.get("logfile")); + } + + public void testPan() { + // TODO: find a better way to not hardcode this url + String url = "http://mochi.test:8888/tests/robocop/robocop.html"; + Element awesomebar = driver.findElement("awesome_bar"); + awesomebar.click(); + + Element urlbar = driver.findElement("awesomebar_text"); + actions.sendKeys(url); + driver.is(url, urlbar.getText(),"Asserting Awesomebar typing works"); + + actions.sendSpecialKey(Actions.SpecialKey.ENTER); + actions.waitForGeckoEvent("DOMContentLoaded"); + driver.setupScrollHandling(); + + // Setup scrolling coordinates. + int midX = driver.getGeckoLeft() + driver.getGeckoWidth()/2; + int midY = driver.getGeckoTop() + driver.getGeckoHeight()/2; + int endY = driver.getGeckoTop() + driver.getGeckoHeight()/10; + + driver.startFrameRecording(); + + int i = 0; + // Scroll a thousand times or until the end of the page. + do { + actions.drag(midX, midX, midY, endY); + try { + Thread.sleep(200); + } + catch (InterruptedException e) { + e.printStackTrace(); + } + i++; + } while( i < 1000 && driver.getScrollHeight() + 2*driver.getHeight() < driver.getPageHeight() ); + driver.ok(i < 1000, "Less than 1000", "Should take less than 1000 drags to get to bottom of the page."); + + int frames = driver.stopFrameRecording(); + driver.dumpLog("__start_report" + Integer.toString(frames) + "__end_report"); + Long msecs = System.currentTimeMillis(); + driver.dumpLog("__startTimestamp" + msecs.toString() + "__endTimestamp"); + } + + @Override + public void tearDown() throws Exception { + try { + solo.finalize(); + }catch (Throwable e){ + e.printStackTrace(); + } + getActivity().finish(); + super.tearDown(); + } +} From 581a72d7fb8948bb222ec2fa009d047055282c1b Mon Sep 17 00:00:00 2001 From: Ehsan Akhgari Date: Fri, 16 Dec 2011 14:30:44 -0500 Subject: [PATCH 14/16] Bug 711195 - Perform the range checks for non-boolean telemetry pings at compile time; r=taras --- toolkit/components/telemetry/Telemetry.cpp | 11 +++++++++++ toolkit/components/telemetry/TelemetryHistograms.h | 4 ++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/toolkit/components/telemetry/Telemetry.cpp b/toolkit/components/telemetry/Telemetry.cpp index 147c98d6cbe2..ebbad28434eb 100644 --- a/toolkit/components/telemetry/Telemetry.cpp +++ b/toolkit/components/telemetry/Telemetry.cpp @@ -111,6 +111,17 @@ struct TelemetryHistogram { PRUint32 histogramType; }; +// Perform the checks at the beginning of HistogramGet at compile time, so +// that if people add incorrect histogram definitions, they get compiler +// errors. +#define HISTOGRAM(id, min, max, bucket_count, histogram_type, b) \ + PR_STATIC_ASSERT(nsITelemetry::HISTOGRAM_ ## histogram_type == nsITelemetry::HISTOGRAM_BOOLEAN || \ + (min < max && bucket_count > 2 && min >= 1)); + +#include "TelemetryHistograms.h" + +#undef HISTOGRAM + const TelemetryHistogram gHistograms[] = { #define HISTOGRAM(id, min, max, bucket_count, histogram_type, b) \ { NULL, NS_STRINGIFY(id), min, max, bucket_count, nsITelemetry::HISTOGRAM_ ## histogram_type }, diff --git a/toolkit/components/telemetry/TelemetryHistograms.h b/toolkit/components/telemetry/TelemetryHistograms.h index 980a918b257e..9386f0f39560 100644 --- a/toolkit/components/telemetry/TelemetryHistograms.h +++ b/toolkit/components/telemetry/TelemetryHistograms.h @@ -70,7 +70,7 @@ HISTOGRAM(CYCLE_COLLECTOR_COLLECTED, 1, 100000, 50, EXPONENTIAL, "Number of obje /** * GC telemetry */ -HISTOGRAM(GC_REASON, 0, 20, 20, LINEAR, "Reason (enum value) for initiating a GC") +HISTOGRAM(GC_REASON, 1, 20, 20, LINEAR, "Reason (enum value) for initiating a GC") HISTOGRAM_BOOLEAN(GC_IS_COMPARTMENTAL, "Is it a compartmental GC?") HISTOGRAM_BOOLEAN(GC_IS_SHAPE_REGEN, "Is it a shape regenerating GC?") HISTOGRAM(GC_MS, 1, 10000, 50, EXPONENTIAL, "Time spent running JS GC (ms)") @@ -273,7 +273,7 @@ HISTOGRAM(PLACES_AUTOCOMPLETE_1ST_RESULT_TIME_MS, 50, 500, 10, EXPONENTIAL, "PLA /** * Updater telemetry. */ -HISTOGRAM(UPDATE_STATUS, 0, 16004, 18, LINEAR, "Updater: the status of the latest update performed") +HISTOGRAM(UPDATE_STATUS, 1, 16004, 18, LINEAR, "Updater: the status of the latest update performed") /** * Thunderbird-specific telemetry. From f36486c31bf206e8602335dc394a5326b16209c2 Mon Sep 17 00:00:00 2001 From: Mark Finkle Date: Fri, 16 Dec 2011 14:32:32 -0500 Subject: [PATCH 15/16] Bug 703378 - Native Fennec executes javascript: urls pasted or typed into the awesome bar [r=mbrubeck] --- mobile/android/base/GeckoApp.java | 29 +++++++++- mobile/android/chrome/content/browser.js | 71 ++++++++++++++++++++---- 2 files changed, 85 insertions(+), 15 deletions(-) diff --git a/mobile/android/base/GeckoApp.java b/mobile/android/base/GeckoApp.java index cd21ea93e8cd..a708353f5f7a 100644 --- a/mobile/android/base/GeckoApp.java +++ b/mobile/android/base/GeckoApp.java @@ -744,6 +744,24 @@ abstract public class GeckoApp }); } + void handleLoadError(final int tabId, final String uri, final String title) { + final Tab tab = Tabs.getInstance().getTab(tabId); + if (tab == null) + return; + + // When a load error occurs, the URLBar can get corrupt so we reset it + mMainHandler.post(new Runnable() { + public void run() { + if (Tabs.getInstance().isSelectedTab(tab)) { + mBrowserToolbar.setTitle(tab.getDisplayTitle()); + mBrowserToolbar.setFavicon(tab.getFavicon()); + mBrowserToolbar.setSecurityMode(tab.getSecurityMode()); + mBrowserToolbar.setProgressVisibility(tab.isLoading()); + } + } + }); + } + public File getProfileDir() { // XXX: TO-DO read profiles.ini to get the default profile return getProfileDir("default"); @@ -880,6 +898,11 @@ abstract public class GeckoApp handleDocumentStop(tabId); } } + } else if (event.equals("Content:LoadError")) { + final int tabId = message.getInt("tabID"); + final String uri = message.getString("uri"); + final String title = message.getString("title"); + handleLoadError(tabId, uri, title); } else if (event.equals("onCameraCapture")) { //GeckoApp.mAppContext.doCameraCapture(message.getString("path")); doCameraCapture(); @@ -1423,6 +1446,7 @@ abstract public class GeckoApp GeckoAppShell.registerGeckoEventListener("Content:LocationChange", GeckoApp.mAppContext); GeckoAppShell.registerGeckoEventListener("Content:SecurityChange", GeckoApp.mAppContext); GeckoAppShell.registerGeckoEventListener("Content:StateChange", GeckoApp.mAppContext); + GeckoAppShell.registerGeckoEventListener("Content:LoadError", GeckoApp.mAppContext); GeckoAppShell.registerGeckoEventListener("onCameraCapture", GeckoApp.mAppContext); GeckoAppShell.registerGeckoEventListener("Tab:Added", GeckoApp.mAppContext); GeckoAppShell.registerGeckoEventListener("Tab:Closed", GeckoApp.mAppContext); @@ -1653,6 +1677,7 @@ abstract public class GeckoApp GeckoAppShell.unregisterGeckoEventListener("Content:LocationChange", GeckoApp.mAppContext); GeckoAppShell.unregisterGeckoEventListener("Content:SecurityChange", GeckoApp.mAppContext); GeckoAppShell.unregisterGeckoEventListener("Content:StateChange", GeckoApp.mAppContext); + GeckoAppShell.unregisterGeckoEventListener("Content:LoadError", GeckoApp.mAppContext); GeckoAppShell.unregisterGeckoEventListener("onCameraCapture", GeckoApp.mAppContext); GeckoAppShell.unregisterGeckoEventListener("Tab:Added", GeckoApp.mAppContext); GeckoAppShell.unregisterGeckoEventListener("Tab:Closed", GeckoApp.mAppContext); @@ -1979,10 +2004,8 @@ abstract public class GeckoApp String url = data.getStringExtra(AwesomeBar.URL_KEY); AwesomeBar.Type type = AwesomeBar.Type.valueOf(data.getStringExtra(AwesomeBar.TYPE_KEY)); String searchEngine = data.getStringExtra(AwesomeBar.SEARCH_KEY); - if (url != null && url.length() > 0) { - mBrowserToolbar.setProgressVisibility(true); + if (url != null && url.length() > 0) loadRequest(url, type, searchEngine); - } } break; case CAMERA_CAPTURE_REQUEST: diff --git a/mobile/android/chrome/content/browser.js b/mobile/android/chrome/content/browser.js index 5906e01e7d45..897a46bf13f6 100644 --- a/mobile/android/chrome/content/browser.js +++ b/mobile/android/chrome/content/browser.js @@ -332,20 +332,37 @@ var BrowserApp = { return null; }, - loadURI: function loadURI(aURI, aParams) { - let browser = this.selectedBrowser; - if (!browser) + loadURI: function loadURI(aURI, aBrowser, aParams) { + aBrowser = aBrowser || this.selectedBrowser; + if (!aBrowser) return; - let flags = aParams.flags || Ci.nsIWebNavigation.LOAD_FLAGS_NONE; + let flags = "flags" in aParams ? aParams.flags : Ci.nsIWebNavigation.LOAD_FLAGS_NONE; let postData = ("postData" in aParams && aParams.postData) ? aParams.postData.value : null; let referrerURI = "referrerURI" in aParams ? aParams.referrerURI : null; let charset = "charset" in aParams ? aParams.charset : null; - browser.loadURIWithFlags(aURI, flags, referrerURI, charset, postData); + + try { + aBrowser.loadURIWithFlags(aURI, flags, referrerURI, charset, postData); + } catch(e) { + let tab = this.getTabForBrowser(aBrowser); + if (tab) { + let message = { + gecko: { + type: "Content:LoadError", + tabID: tab.id, + uri: aBrowser.currentURI.spec, + title: aBrowser.contentTitle + } + }; + sendMessageToJava(message); + dump("Handled load error: " + e) + } + } }, addTab: function addTab(aURI, aParams) { - aParams = aParams || { selected: true }; + aParams = aParams || { selected: true, flags: Ci.nsIWebNavigation.LOAD_FLAGS_NONE }; let newTab = new Tab(aURI, aParams); this._tabs.push(newTab); if ("selected" in aParams && aParams.selected) @@ -604,10 +621,19 @@ var BrowserApp = { browser.reload(); } else if (aTopic == "Session:Stop") { browser.stop(); - } else if (aTopic == "Tab:Add") { - let newTab = this.addTab(this.getSearchOrFixupURI(aData)); - } else if (aTopic == "Tab:Load") { - browser.loadURI(this.getSearchOrFixupURI(aData)); + } else if (aTopic == "Tab:Add" || aTopic == "Tab:Load") { + // Pass LOAD_FLAGS_DISALLOW_INHERIT_OWNER to prevent any loads from + // inheriting the currently loaded document's principal. + let params = { + selected: true, + flags: Ci.nsIWebNavigation.LOAD_FLAGS_DISALLOW_INHERIT_OWNER + }; + + let url = this.getSearchOrFixupURI(aData); + if (aTopic == "Tab:Add") + this.addTab(url, params); + else + this.loadURI(url, browser, params); } else if (aTopic == "Tab:Select") { this.selectTab(this.getTabForId(parseInt(aData))); } else if (aTopic == "Tab:Close") { @@ -963,7 +989,7 @@ nsBrowserAccess.prototype = { // Why does returning the browser.contentWindow not work here? Services.io.offline = false; - browser.loadURI(aURI.spec, null, null); + BrowserApp.loadURI(aURI.spec, browser); return null; }, @@ -1043,14 +1069,35 @@ Tab.prototype = { Ci.nsIWebProgress.NOTIFY_SECURITY; this.browser.addProgressListener(this, flags); this.browser.sessionHistory.addSHistoryListener(this); + this.browser.addEventListener("DOMContentLoaded", this, true); this.browser.addEventListener("DOMLinkAdded", this, true); this.browser.addEventListener("DOMTitleChanged", this, true); this.browser.addEventListener("scroll", this, true); this.browser.addEventListener("PluginClickToPlay", this, true); this.browser.addEventListener("pagehide", this, true); + Services.obs.addObserver(this, "http-on-modify-request", false); - this.browser.loadURI(aURL); + + let flags = "flags" in aParams ? aParams.flags : Ci.nsIWebNavigation.LOAD_FLAGS_NONE; + let postData = ("postData" in aParams && aParams.postData) ? aParams.postData.value : null; + let referrerURI = "referrerURI" in aParams ? aParams.referrerURI : null; + let charset = "charset" in aParams ? aParams.charset : null; + + try { + this.browser.loadURIWithFlags(aURL, flags, referrerURI, charset, postData); + } catch(e) { + let message = { + gecko: { + type: "Content:LoadError", + tabID: this.id, + uri: this.browser.currentURI.spec, + title: this.browser.contentTitle + } + }; + sendMessageToJava(message); + dump("Handled load error: " + e) + } }, setAgentMode: function(aMode) { From 72ede3876a01916eb9ee82f9e158d6244ebfb1aa Mon Sep 17 00:00:00 2001 From: James Willcox Date: Fri, 16 Dec 2011 14:45:58 -0500 Subject: [PATCH 16/16] back out 8a5cc33141a3 due to android-xul build failure --- mobile/android/base/GeckoAppShell.java | 10 -- mobile/android/base/Makefile.in | 1 - .../base/gfx/GeckoSoftwareLayerClient.java | 11 +- mobile/android/base/gfx/LayerClient.java | 12 +- mobile/android/base/gfx/WidgetTileLayer.java | 116 ------------------ other-licenses/android/APKOpen.cpp | 6 +- widget/src/android/AndroidJNI.cpp | 15 --- widget/src/android/Makefile.in | 2 - widget/src/android/nsWindow.cpp | 90 +------------- widget/src/android/nsWindow.h | 5 - 10 files changed, 12 insertions(+), 256 deletions(-) delete mode 100644 mobile/android/base/gfx/WidgetTileLayer.java diff --git a/mobile/android/base/GeckoAppShell.java b/mobile/android/base/GeckoAppShell.java index 5b45086e6f7b..8d326e1c202f 100644 --- a/mobile/android/base/GeckoAppShell.java +++ b/mobile/android/base/GeckoAppShell.java @@ -138,8 +138,6 @@ public class GeckoAppShell public static native void notifySmsReceived(String aSender, String aBody, long aTimestamp); public static native ByteBuffer allocateDirectBuffer(long size); public static native void freeDirectBuffer(ByteBuffer buf); - public static native void bindWidgetTexture(); - public static native boolean testDirectTexture(); // A looper thread, accessed by GeckoAppShell.getHandler private static class LooperThread extends Thread { @@ -427,14 +425,6 @@ public class GeckoAppShell Log.i(LOGTAG, "post native init"); - // If we have direct texture available, use it - if (GeckoAppShell.testDirectTexture()) { - Log.i(LOGTAG, "Using direct texture for widget layer"); - GeckoApp.mAppContext.getSoftwareLayerClient().installWidgetLayer(); - } else { - Log.i(LOGTAG, "Falling back to traditional texture upload"); - } - // Tell Gecko where the target byte buffer is for rendering GeckoAppShell.setSoftwareLayerClient(GeckoApp.mAppContext.getSoftwareLayerClient()); diff --git a/mobile/android/base/Makefile.in b/mobile/android/base/Makefile.in index 11fff62252dd..1ae1885fb044 100644 --- a/mobile/android/base/Makefile.in +++ b/mobile/android/base/Makefile.in @@ -107,7 +107,6 @@ JAVAFILES = \ gfx/TextureReaper.java \ gfx/TileLayer.java \ gfx/ViewportMetrics.java \ - gfx/WidgetTileLayer.java \ ui/PanZoomController.java \ $(NULL) diff --git a/mobile/android/base/gfx/GeckoSoftwareLayerClient.java b/mobile/android/base/gfx/GeckoSoftwareLayerClient.java index d57ec3fe3142..84187ea276f0 100644 --- a/mobile/android/base/gfx/GeckoSoftwareLayerClient.java +++ b/mobile/android/base/gfx/GeckoSoftwareLayerClient.java @@ -45,7 +45,6 @@ import org.mozilla.gecko.gfx.LayerController; import org.mozilla.gecko.gfx.LayerRenderer; import org.mozilla.gecko.gfx.PointUtils; import org.mozilla.gecko.gfx.SingleTileLayer; -import org.mozilla.gecko.gfx.WidgetTileLayer; import org.mozilla.gecko.FloatUtils; import org.mozilla.gecko.GeckoApp; import org.mozilla.gecko.GeckoAppShell; @@ -77,7 +76,7 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL private IntSize mScreenSize, mViewportSize; private IntSize mBufferSize; private ByteBuffer mBuffer; - private Layer mTileLayer; + private final SingleTileLayer mTileLayer; /* The viewport rect that Gecko is currently displaying. */ private ViewportMetrics mGeckoViewport; @@ -126,10 +125,6 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL } } - public void installWidgetLayer() { - mTileLayer = new WidgetTileLayer(mCairoImage); - } - /** Attaches the root layer to the layer controller so that Gecko appears. */ @Override public void setLayerController(LayerController layerController) { @@ -193,9 +188,7 @@ public class GeckoSoftwareLayerClient extends LayerClient implements GeckoEventL updateViewport(metadata, !mUpdateViewportOnEndDraw); mUpdateViewportOnEndDraw = false; Rect rect = new Rect(x, y, x + width, y + height); - - if (mTileLayer instanceof SingleTileLayer) - ((SingleTileLayer)mTileLayer).invalidate(rect); + mTileLayer.invalidate(rect); } finally { endTransaction(mTileLayer); } diff --git a/mobile/android/base/gfx/LayerClient.java b/mobile/android/base/gfx/LayerClient.java index 1afaca3799ea..f7263021ce91 100644 --- a/mobile/android/base/gfx/LayerClient.java +++ b/mobile/android/base/gfx/LayerClient.java @@ -53,24 +53,24 @@ public abstract class LayerClient { } /** - * A utility function for calling Layer.beginTransaction with the + * A utility function for calling TileLayer.beginTransaction with the * appropriate LayerView. */ - public void beginTransaction(Layer aLayer) { + public void beginTransaction(TileLayer aTileLayer) { if (mLayerController != null) { LayerView view = mLayerController.getView(); if (view != null) { - aLayer.beginTransaction(view); + aTileLayer.beginTransaction(view); return; } } - aLayer.beginTransaction(); + aTileLayer.beginTransaction(); } // Included for symmetry. - public void endTransaction(Layer aLayer) { - aLayer.endTransaction(); + public void endTransaction(TileLayer aTileLayer) { + aTileLayer.endTransaction(); } } diff --git a/mobile/android/base/gfx/WidgetTileLayer.java b/mobile/android/base/gfx/WidgetTileLayer.java deleted file mode 100644 index f77fda204239..000000000000 --- a/mobile/android/base/gfx/WidgetTileLayer.java +++ /dev/null @@ -1,116 +0,0 @@ -/* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*- - * ***** BEGIN LICENSE BLOCK ***** - * Version: MPL 1.1/GPL 2.0/LGPL 2.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Mozilla Android code. - * - * The Initial Developer of the Original Code is Mozilla Foundation. - * Portions created by the Initial Developer are Copyright (C) 2009-2010 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * James Willcox - * - * Alternatively, the contents of this file may be used under the terms of - * either the GNU General Public License Version 2 or later (the "GPL"), or - * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - * in which case the provisions of the GPL or the LGPL are applicable instead - * of those above. If you wish to allow use of your version of this file only - * under the terms of either the GPL or the LGPL, and not to allow others to - * use your version of this file under the terms of the MPL, indicate your - * decision by deleting the provisions above and replace them with the notice - * and other provisions required by the GPL or the LGPL. If you do not delete - * the provisions above, a recipient may use your version of this file under - * the terms of any one of the MPL, the GPL or the LGPL. - * - * ***** END LICENSE BLOCK ***** */ - -package org.mozilla.gecko.gfx; - -import org.mozilla.gecko.gfx.LayerController; -import org.mozilla.gecko.gfx.SingleTileLayer; -import org.mozilla.gecko.GeckoAppShell; -import android.opengl.GLES11; -import android.opengl.GLES11Ext; -import android.graphics.RectF; -import android.util.Log; -import javax.microedition.khronos.opengles.GL10; - -/** - * Encapsulates the logic needed to draw the single-tiled Gecko texture - */ -public class WidgetTileLayer extends Layer { - - private int[] mTextureIDs; - private CairoImage mImage; - - public WidgetTileLayer(CairoImage image) { - mImage = image; - } - - protected boolean initialized() { return mTextureIDs != null; } - - @Override - public IntSize getSize() { return mImage.getSize(); } - - protected void bindAndSetGLParameters() { - GLES11.glBindTexture(GL10.GL_TEXTURE_2D, mTextureIDs[0]); - GLES11.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST); - GLES11.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR); - } - - @Override - protected void finalize() throws Throwable { - if (mTextureIDs != null) - TextureReaper.get().add(mTextureIDs); - } - - @Override - protected void performUpdates(GL10 gl) { - super.performUpdates(gl); - - if (mTextureIDs == null) { - mTextureIDs = new int[1]; - GLES11.glGenTextures(1, mTextureIDs, 0); - } - - bindAndSetGLParameters(); - GeckoAppShell.bindWidgetTexture(); - } - - @Override - public void draw(RenderContext context) { - // mTextureIDs may be null here during startup if Layer.java's draw method - // failed to acquire the transaction lock and call performUpdates. - if (!initialized()) - return; - - GLES11.glBindTexture(GL10.GL_TEXTURE_2D, mTextureIDs[0]); - - RectF bounds; - int[] cropRect; - IntSize size = getSize(); - RectF viewport = context.viewport; - - bounds = getBounds(context, new FloatSize(size)); - cropRect = new int[] { 0, size.height, size.width, -size.height }; - bounds.offset(-viewport.left, -viewport.top); - - GLES11.glTexParameteriv(GL10.GL_TEXTURE_2D, GLES11Ext.GL_TEXTURE_CROP_RECT_OES, cropRect, - 0); - - float top = viewport.height() - (bounds.top + bounds.height()); - GLES11Ext.glDrawTexfOES(bounds.left, top, 0.0f, bounds.width(), bounds.height()); - } -} - diff --git a/other-licenses/android/APKOpen.cpp b/other-licenses/android/APKOpen.cpp index bb1a69800948..6cc23c016df8 100644 --- a/other-licenses/android/APKOpen.cpp +++ b/other-licenses/android/APKOpen.cpp @@ -299,8 +299,6 @@ SHELL_WRAPPER1(cameraCallbackBridge, jbyteArray) SHELL_WRAPPER1(notifyUriVisited, jstring) SHELL_WRAPPER3(notifyBatteryChange, jdouble, jboolean, jdouble); SHELL_WRAPPER3(notifySmsReceived, jstring, jstring, jlong); -SHELL_WRAPPER0(bindWidgetTexture); -SHELL_WRAPPER0_WITH_RETURN(testDirectTexture, bool); static void * xul_handle = NULL; static time_t apk_mtime = 0; @@ -640,7 +638,7 @@ loadLibs(const char *apkName) gettimeofday(&t0, 0); struct rusage usage1; getrusage(RUSAGE_THREAD, &usage1); - + void *zip = map_file(apkName); struct cdir_end *dirend = (struct cdir_end *)((char *)zip + zip_size - sizeof(*dirend)); while ((void *)dirend > zip && @@ -706,8 +704,6 @@ loadLibs(const char *apkName) GETFUNC(notifyUriVisited); GETFUNC(notifyBatteryChange); GETFUNC(notifySmsReceived); - GETFUNC(bindWidgetTexture); - GETFUNC(testDirectTexture); #undef GETFUNC sStartupTimeline = (uint64_t *)__wrap_dlsym(xul_handle, "_ZN7mozilla15StartupTimeline16sStartupTimelineE"); gettimeofday(&t1, 0); diff --git a/widget/src/android/AndroidJNI.cpp b/widget/src/android/AndroidJNI.cpp index 5d363ad520ec..3a1762eb128a 100644 --- a/widget/src/android/AndroidJNI.cpp +++ b/widget/src/android/AndroidJNI.cpp @@ -40,7 +40,6 @@ #include "nsString.h" #include "AndroidBridge.h" -#include "AndroidGraphicBuffer.h" #include #include @@ -89,8 +88,6 @@ extern "C" { NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_notifyUriVisited(JNIEnv *, jclass, jstring uri); NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_notifyBatteryChange(JNIEnv* jenv, jclass, jdouble, jboolean, jdouble); NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_notifySmsReceived(JNIEnv* jenv, jclass, jstring, jstring, jlong); - NS_EXPORT void JNICALL Java_org_mozilla_gecko_GeckoAppShell_bindWidgetTexture(JNIEnv* jenv, jclass); - NS_EXPORT bool JNICALL Java_org_mozilla_gecko_GeckoAppShell_testDirectTexture(JNIEnv* jenv, jclass); } @@ -281,15 +278,3 @@ Java_org_mozilla_gecko_GeckoAppShell_notifySmsReceived(JNIEnv* jenv, jclass, nsCOMPtr runnable = new NotifySmsReceivedRunnable(message); NS_DispatchToMainThread(runnable); } - -NS_EXPORT void JNICALL -Java_org_mozilla_gecko_GeckoAppShell_bindWidgetTexture(JNIEnv* jenv, jclass) -{ - nsWindow::BindToTexture(); -} - -NS_EXPORT bool JNICALL -Java_org_mozilla_gecko_GeckoAppShell_testDirectTexture(JNIEnv* jenv, jclass) -{ - return nsWindow::HasDirectTexture(); -} diff --git a/widget/src/android/Makefile.in b/widget/src/android/Makefile.in index 91e345e92011..865142727ab2 100644 --- a/widget/src/android/Makefile.in +++ b/widget/src/android/Makefile.in @@ -61,8 +61,6 @@ CPPSRCS = \ nsAppShell.cpp \ AndroidJavaWrappers.cpp \ AndroidBridge.cpp \ - AndroidDirectTexture.cpp \ - AndroidGraphicBuffer.cpp \ AndroidJNI.cpp \ nsWindow.cpp \ nsLookAndFeel.cpp \ diff --git a/widget/src/android/nsWindow.cpp b/widget/src/android/nsWindow.cpp index cce5147829e4..d5b1fc5abd30 100644 --- a/widget/src/android/nsWindow.cpp +++ b/widget/src/android/nsWindow.cpp @@ -39,7 +39,6 @@ #include #include -#include #include "mozilla/dom/ContentParent.h" #include "mozilla/dom/ContentChild.h" @@ -93,20 +92,6 @@ static gfxIntSize gAndroidScreenBounds; bool nsWindow::sAccessibilityEnabled = false; #endif -#ifdef MOZ_JAVA_COMPOSITOR -#include "mozilla/Mutex.h" -#include "nsThreadUtils.h" -#include "AndroidDirectTexture.h" - -static AndroidDirectTexture* sDirectTexture = new AndroidDirectTexture(2048, 2048, - AndroidGraphicBuffer::UsageSoftwareWrite | AndroidGraphicBuffer::UsageTexture, - gfxASurface::ImageFormatRGB16_565); - -static bool sHasDirectTexture = true; - -#endif - - class ContentCreationNotifier; static nsCOMPtr gContentCreationNotifier; // A helper class to send updates when content processes @@ -823,49 +808,6 @@ nsWindow::GetThebesSurface() return new gfxImageSurface(gfxIntSize(5,5), gfxImageSurface::ImageFormatRGB24); } -void -nsWindow::BindToTexture() -{ - sDirectTexture->Bind(); -} - -bool -nsWindow::HasDirectTexture() -{ - // If we already tested, return early - if (!sHasDirectTexture) - return false; - - AndroidGraphicBuffer* buffer = new AndroidGraphicBuffer(512, 512, - AndroidGraphicBuffer::UsageSoftwareWrite | AndroidGraphicBuffer::UsageTexture, - gfxASurface::ImageFormatRGB16_565); - - unsigned char* bits = NULL; - if (!buffer->Lock(AndroidGraphicBuffer::UsageSoftwareWrite, &bits) || !bits) { - ALOG("failed to lock graphic buffer"); - buffer->Unlock(); - sHasDirectTexture = false; - goto cleanup; - } - - if (!buffer->Unlock()) { - ALOG("failed to unlock graphic buffer"); - sHasDirectTexture = false; - goto cleanup; - } - - if (!buffer->Reallocate(1024, 1024, gfxASurface::ImageFormatRGB16_565)) { - ALOG("failed to reallocate graphic buffer"); - sHasDirectTexture = false; - goto cleanup; - } - -cleanup: - delete buffer; - - return sHasDirectTexture; -} - void nsWindow::OnGlobalAndroidEvent(AndroidGeckoEvent *ae) { @@ -1169,26 +1111,9 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae) client.BeginDrawing(); nsAutoString metadata; - unsigned char *bits = NULL; - if (sHasDirectTexture) { - if ((sDirectTexture->Width() != gAndroidBounds.width || - sDirectTexture->Height() != gAndroidBounds.height) && - gAndroidBounds.width != 0 && gAndroidBounds.height != 0) { - sDirectTexture->Reallocate(gAndroidBounds.width, gAndroidBounds.height); - } - - sDirectTexture->Lock(AndroidGraphicBuffer::UsageSoftwareWrite, &bits); - } else { - bits = client.LockBufferBits(); - } + unsigned char *bits = client.LockBufferBits(); if (!bits) { ALOG("### Failed to lock buffer"); - - if (sHasDirectTexture) { - sDirectTexture->Unlock(); - } else { - client.UnlockBuffer(); - } } else { nsRefPtr targetSurface = new gfxImageSurface(bits, gfxIntSize(gAndroidBounds.width, gAndroidBounds.height), gAndroidBounds.width * 2, @@ -1196,12 +1121,7 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae) if (targetSurface->CairoStatus()) { ALOG("### Failed to create a valid surface from the bitmap"); } else { - if (sHasDirectTexture) { - // XXX: lock only the dirty rect above and pass it in here - DrawTo(targetSurface); - } else { - DrawTo(targetSurface, ae->Rect()); - } + DrawTo(targetSurface, ae->Rect()); { nsCOMPtr metadataProvider = @@ -1210,11 +1130,7 @@ nsWindow::OnDraw(AndroidGeckoEvent *ae) metadataProvider->GetDrawMetadata(metadata); } } - if (sHasDirectTexture) { - sDirectTexture->Unlock(); - } else { - client.UnlockBuffer(); - } + client.UnlockBuffer(); } client.EndDrawing(ae->Rect(), metadata); return; diff --git a/widget/src/android/nsWindow.h b/widget/src/android/nsWindow.h index 0a3d5f688443..fb557ac63a25 100644 --- a/widget/src/android/nsWindow.h +++ b/widget/src/android/nsWindow.h @@ -177,11 +177,6 @@ public: static bool sAccessibilityEnabled; #endif -#ifdef MOZ_JAVA_COMPOSITOR - static void BindToTexture(); - static bool HasDirectTexture(); -#endif - protected: void BringToFront(); nsWindow *FindTopLevel();