From 0ebf5bdf043a27fd3dfb7f92e0cb63d88954c44d Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Fri, 19 Apr 2024 03:47:29 +0200 Subject: Adding upstream version 115.8.0esr. Signed-off-by: Daniel Baumann --- layout/forms/HTMLSelectEventListener.cpp | 851 ++++++++++++ layout/forms/HTMLSelectEventListener.h | 103 ++ layout/forms/ListMutationObserver.cpp | 92 ++ layout/forms/ListMutationObserver.h | 67 + layout/forms/crashtests/1102791.html | 33 + layout/forms/crashtests/1140216.html | 20 + layout/forms/crashtests/1182414.html | 17 + layout/forms/crashtests/1212688.html | 27 + layout/forms/crashtests/1228670.xhtml | 7 + layout/forms/crashtests/1279354.html | 21 + layout/forms/crashtests/1388230-1.html | 3 + layout/forms/crashtests/1388230-2.html | 1 + layout/forms/crashtests/1405830.html | 19 + layout/forms/crashtests/1418477.html | 4 + layout/forms/crashtests/1432853.html | 8 + layout/forms/crashtests/1460787-1.html | 7 + layout/forms/crashtests/1464165-1.html | 14 + layout/forms/crashtests/1471157.html | 11 + layout/forms/crashtests/1488219.html | 26 + layout/forms/crashtests/1600207.html | 9 + layout/forms/crashtests/1600367.html | 8 + layout/forms/crashtests/1617753.html | 21 + layout/forms/crashtests/166750-1.html | 14 + layout/forms/crashtests/1679471.html | 8 + layout/forms/crashtests/1690166-1.html | 19 + layout/forms/crashtests/1690166-2.html | 19 + layout/forms/crashtests/200347-1.html | 8 + layout/forms/crashtests/203041-1.html | 24 + layout/forms/crashtests/213390-1.html | 23 + layout/forms/crashtests/258101-1.html | 18 + layout/forms/crashtests/266225-1.html | 7 + layout/forms/crashtests/310426-1.xhtml | 9 + layout/forms/crashtests/310520-1.xhtml | 19 + layout/forms/crashtests/315752-1.xhtml | 21 + layout/forms/crashtests/317502-1.xhtml | 13 + layout/forms/crashtests/321894.html | 17 + layout/forms/crashtests/343510-1.html | 4 + layout/forms/crashtests/363696-1.xhtml | 10 + layout/forms/crashtests/363696-2.html | 2 + layout/forms/crashtests/363696-3.html | 5 + layout/forms/crashtests/366205-1.html | 11 + layout/forms/crashtests/366537-1.xhtml | 32 + layout/forms/crashtests/367587-1.html | 37 + layout/forms/crashtests/370703-1.html | 30 + layout/forms/crashtests/370940-1.html | 28 + layout/forms/crashtests/370967.html | 13 + layout/forms/crashtests/378369.html | 19 + layout/forms/crashtests/380116-1.xhtml | 11 + layout/forms/crashtests/382610-1.html | 11 + layout/forms/crashtests/383887-1.html | 20 + layout/forms/crashtests/386554-1.html | 14 + layout/forms/crashtests/388374-1.xhtml | 22 + layout/forms/crashtests/388374-2.html | 25 + layout/forms/crashtests/393656-1.xhtml | 13 + layout/forms/crashtests/393656-2.xhtml | 22 + layout/forms/crashtests/399262.html | 50 + layout/forms/crashtests/402852-1.html | 2 + layout/forms/crashtests/403148-1.html | 22 + layout/forms/crashtests/404118-1.html | 5 + layout/forms/crashtests/404123-1.html | 12 + layout/forms/crashtests/407066.html | 1 + layout/forms/crashtests/451316.html | 7 + layout/forms/crashtests/455451-1.html | 17 + layout/forms/crashtests/457537-1.html | 17 + layout/forms/crashtests/457537-2.html | 17 + layout/forms/crashtests/498698-1.html | 6 + layout/forms/crashtests/513113-1.html | 6 + layout/forms/crashtests/538062-1.xhtml | 20 + layout/forms/crashtests/570624-1.html | 15 + layout/forms/crashtests/578604-1.html | 17 + layout/forms/crashtests/590302-1.xhtml | 4 + layout/forms/crashtests/626014.xhtml | 20 + layout/forms/crashtests/639733.xhtml | 26 + layout/forms/crashtests/669767.html | 14 + layout/forms/crashtests/682684-binding.xml | 4 + layout/forms/crashtests/682684.xhtml | 3 + layout/forms/crashtests/865602.html | 9 + layout/forms/crashtests/893331.html | 9 + layout/forms/crashtests/893332-1.html | 10 + layout/forms/crashtests/944198.html | 9 + layout/forms/crashtests/949891.xhtml | 5 + layout/forms/crashtests/959311.html | 17 + layout/forms/crashtests/960277-2.html | 14 + layout/forms/crashtests/997709-1.html | 5 + layout/forms/crashtests/crashtests.list | 79 ++ layout/forms/moz.build | 54 + layout/forms/nsButtonFrameRenderer.cpp | 476 +++++++ layout/forms/nsButtonFrameRenderer.h | 83 ++ layout/forms/nsCheckboxRadioFrame.cpp | 174 +++ layout/forms/nsCheckboxRadioFrame.h | 97 ++ layout/forms/nsColorControlFrame.cpp | 128 ++ layout/forms/nsColorControlFrame.h | 60 + layout/forms/nsComboboxControlFrame.cpp | 983 ++++++++++++++ layout/forms/nsComboboxControlFrame.h | 250 ++++ layout/forms/nsDateTimeControlFrame.cpp | 201 +++ layout/forms/nsDateTimeControlFrame.h | 71 + layout/forms/nsFieldSetFrame.cpp | 938 +++++++++++++ layout/forms/nsFieldSetFrame.h | 118 ++ layout/forms/nsFileControlFrame.cpp | 426 ++++++ layout/forms/nsFileControlFrame.h | 142 ++ layout/forms/nsGfxButtonControlFrame.cpp | 178 +++ layout/forms/nsGfxButtonControlFrame.h | 64 + layout/forms/nsHTMLButtonControlFrame.cpp | 398 ++++++ layout/forms/nsHTMLButtonControlFrame.h | 117 ++ layout/forms/nsIFormControlFrame.h | 41 + layout/forms/nsISelectControlFrame.h | 50 + layout/forms/nsITextControlFrame.h | 44 + layout/forms/nsImageControlFrame.cpp | 151 +++ layout/forms/nsListControlFrame.cpp | 1211 +++++++++++++++++ layout/forms/nsListControlFrame.h | 356 +++++ layout/forms/nsMeterFrame.cpp | 222 ++++ layout/forms/nsMeterFrame.h | 82 ++ layout/forms/nsNumberControlFrame.cpp | 175 +++ layout/forms/nsNumberControlFrame.h | 105 ++ layout/forms/nsProgressFrame.cpp | 248 ++++ layout/forms/nsProgressFrame.h | 89 ++ layout/forms/nsRangeFrame.cpp | 769 +++++++++++ layout/forms/nsRangeFrame.h | 209 +++ layout/forms/nsSearchControlFrame.cpp | 82 ++ layout/forms/nsSearchControlFrame.h | 68 + layout/forms/nsSelectsAreaFrame.cpp | 191 +++ layout/forms/nsSelectsAreaFrame.h | 52 + layout/forms/nsTextControlFrame.cpp | 1392 ++++++++++++++++++++ layout/forms/nsTextControlFrame.h | 366 +++++ layout/forms/test/bug287446_subframe.html | 38 + layout/forms/test/bug477700_subframe.html | 39 + layout/forms/test/bug536567_iframe.html | 9 + layout/forms/test/bug536567_subframe.html | 14 + layout/forms/test/bug564115_window.html | 10 + layout/forms/test/chrome.ini | 7 + layout/forms/test/mochitest.ini | 68 + layout/forms/test/test_bug1111995.html | 60 + layout/forms/test/test_bug1301290.html | 49 + layout/forms/test/test_bug1305282.html | 57 + layout/forms/test/test_bug1327129.html | 385 ++++++ layout/forms/test/test_bug1529036.html | 73 + layout/forms/test/test_bug231389.html | 55 + layout/forms/test/test_bug287446.html | 74 ++ layout/forms/test/test_bug345267.html | 97 ++ layout/forms/test/test_bug346043.html | 65 + layout/forms/test/test_bug348236.html | 123 ++ layout/forms/test/test_bug353539.html | 52 + layout/forms/test/test_bug365410.html | 132 ++ layout/forms/test/test_bug378670.html | 55 + layout/forms/test/test_bug402198.html | 77 ++ layout/forms/test/test_bug411236.html | 71 + layout/forms/test/test_bug446663.html | 80 ++ layout/forms/test/test_bug476308.html | 31 + layout/forms/test/test_bug477531.html | 65 + layout/forms/test/test_bug477700.html | 59 + layout/forms/test/test_bug534785.html | 88 ++ layout/forms/test/test_bug536567_perwindowpb.html | 215 +++ layout/forms/test/test_bug542914.html | 115 ++ layout/forms/test/test_bug549170.html | 77 ++ layout/forms/test/test_bug562447.html | 62 + layout/forms/test/test_bug563642.html | 82 ++ layout/forms/test/test_bug564115.html | 57 + layout/forms/test/test_bug571352.html | 86 ++ layout/forms/test/test_bug572406.html | 48 + layout/forms/test/test_bug572649.html | 63 + layout/forms/test/test_bug595310.html | 64 + layout/forms/test/test_bug620936.html | 35 + layout/forms/test/test_bug644542.html | 63 + layout/forms/test/test_bug672810.html | 120 ++ layout/forms/test/test_bug704049.html | 50 + layout/forms/test/test_bug717878_input_scroll.html | 107 ++ layout/forms/test/test_bug869314.html | 55 + layout/forms/test/test_bug903715.html | 81 ++ layout/forms/test/test_bug935876.html | 502 +++++++ layout/forms/test/test_bug957562.html | 43 + layout/forms/test/test_bug960277.html | 29 + layout/forms/test/test_listcontrol_search.html | 46 + layout/forms/test/test_readonly.html | 58 + .../test/test_select_collapsed_page_keys.html | 43 + .../test_select_key_navigation_bug1498769.html | 123 ++ .../test/test_select_key_navigation_bug961363.html | 131 ++ layout/forms/test/test_select_prevent_default.html | 116 ++ layout/forms/test/test_select_reframe.html | 52 + layout/forms/test/test_select_vertical.html | 75 ++ layout/forms/test/test_textarea_resize.html | 102 ++ .../forms/test/test_unstyled_control_height.html | 72 + 181 files changed, 17925 insertions(+) create mode 100644 layout/forms/HTMLSelectEventListener.cpp create mode 100644 layout/forms/HTMLSelectEventListener.h create mode 100644 layout/forms/ListMutationObserver.cpp create mode 100644 layout/forms/ListMutationObserver.h create mode 100644 layout/forms/crashtests/1102791.html create mode 100644 layout/forms/crashtests/1140216.html create mode 100644 layout/forms/crashtests/1182414.html create mode 100644 layout/forms/crashtests/1212688.html create mode 100644 layout/forms/crashtests/1228670.xhtml create mode 100644 layout/forms/crashtests/1279354.html create mode 100644 layout/forms/crashtests/1388230-1.html create mode 100644 layout/forms/crashtests/1388230-2.html create mode 100644 layout/forms/crashtests/1405830.html create mode 100644 layout/forms/crashtests/1418477.html create mode 100644 layout/forms/crashtests/1432853.html create mode 100644 layout/forms/crashtests/1460787-1.html create mode 100644 layout/forms/crashtests/1464165-1.html create mode 100644 layout/forms/crashtests/1471157.html create mode 100644 layout/forms/crashtests/1488219.html create mode 100644 layout/forms/crashtests/1600207.html create mode 100644 layout/forms/crashtests/1600367.html create mode 100644 layout/forms/crashtests/1617753.html create mode 100644 layout/forms/crashtests/166750-1.html create mode 100644 layout/forms/crashtests/1679471.html create mode 100644 layout/forms/crashtests/1690166-1.html create mode 100644 layout/forms/crashtests/1690166-2.html create mode 100644 layout/forms/crashtests/200347-1.html create mode 100644 layout/forms/crashtests/203041-1.html create mode 100644 layout/forms/crashtests/213390-1.html create mode 100644 layout/forms/crashtests/258101-1.html create mode 100644 layout/forms/crashtests/266225-1.html create mode 100644 layout/forms/crashtests/310426-1.xhtml create mode 100644 layout/forms/crashtests/310520-1.xhtml create mode 100644 layout/forms/crashtests/315752-1.xhtml create mode 100644 layout/forms/crashtests/317502-1.xhtml create mode 100644 layout/forms/crashtests/321894.html create mode 100644 layout/forms/crashtests/343510-1.html create mode 100644 layout/forms/crashtests/363696-1.xhtml create mode 100644 layout/forms/crashtests/363696-2.html create mode 100644 layout/forms/crashtests/363696-3.html create mode 100644 layout/forms/crashtests/366205-1.html create mode 100644 layout/forms/crashtests/366537-1.xhtml create mode 100644 layout/forms/crashtests/367587-1.html create mode 100644 layout/forms/crashtests/370703-1.html create mode 100644 layout/forms/crashtests/370940-1.html create mode 100644 layout/forms/crashtests/370967.html create mode 100644 layout/forms/crashtests/378369.html create mode 100644 layout/forms/crashtests/380116-1.xhtml create mode 100644 layout/forms/crashtests/382610-1.html create mode 100644 layout/forms/crashtests/383887-1.html create mode 100644 layout/forms/crashtests/386554-1.html create mode 100644 layout/forms/crashtests/388374-1.xhtml create mode 100644 layout/forms/crashtests/388374-2.html create mode 100644 layout/forms/crashtests/393656-1.xhtml create mode 100644 layout/forms/crashtests/393656-2.xhtml create mode 100644 layout/forms/crashtests/399262.html create mode 100644 layout/forms/crashtests/402852-1.html create mode 100644 layout/forms/crashtests/403148-1.html create mode 100644 layout/forms/crashtests/404118-1.html create mode 100644 layout/forms/crashtests/404123-1.html create mode 100644 layout/forms/crashtests/407066.html create mode 100644 layout/forms/crashtests/451316.html create mode 100644 layout/forms/crashtests/455451-1.html create mode 100644 layout/forms/crashtests/457537-1.html create mode 100644 layout/forms/crashtests/457537-2.html create mode 100644 layout/forms/crashtests/498698-1.html create mode 100644 layout/forms/crashtests/513113-1.html create mode 100644 layout/forms/crashtests/538062-1.xhtml create mode 100644 layout/forms/crashtests/570624-1.html create mode 100644 layout/forms/crashtests/578604-1.html create mode 100644 layout/forms/crashtests/590302-1.xhtml create mode 100644 layout/forms/crashtests/626014.xhtml create mode 100644 layout/forms/crashtests/639733.xhtml create mode 100644 layout/forms/crashtests/669767.html create mode 100644 layout/forms/crashtests/682684-binding.xml create mode 100644 layout/forms/crashtests/682684.xhtml create mode 100644 layout/forms/crashtests/865602.html create mode 100644 layout/forms/crashtests/893331.html create mode 100644 layout/forms/crashtests/893332-1.html create mode 100644 layout/forms/crashtests/944198.html create mode 100644 layout/forms/crashtests/949891.xhtml create mode 100644 layout/forms/crashtests/959311.html create mode 100644 layout/forms/crashtests/960277-2.html create mode 100644 layout/forms/crashtests/997709-1.html create mode 100644 layout/forms/crashtests/crashtests.list create mode 100644 layout/forms/moz.build create mode 100644 layout/forms/nsButtonFrameRenderer.cpp create mode 100644 layout/forms/nsButtonFrameRenderer.h create mode 100644 layout/forms/nsCheckboxRadioFrame.cpp create mode 100644 layout/forms/nsCheckboxRadioFrame.h create mode 100644 layout/forms/nsColorControlFrame.cpp create mode 100644 layout/forms/nsColorControlFrame.h create mode 100644 layout/forms/nsComboboxControlFrame.cpp create mode 100644 layout/forms/nsComboboxControlFrame.h create mode 100644 layout/forms/nsDateTimeControlFrame.cpp create mode 100644 layout/forms/nsDateTimeControlFrame.h create mode 100644 layout/forms/nsFieldSetFrame.cpp create mode 100644 layout/forms/nsFieldSetFrame.h create mode 100644 layout/forms/nsFileControlFrame.cpp create mode 100644 layout/forms/nsFileControlFrame.h create mode 100644 layout/forms/nsGfxButtonControlFrame.cpp create mode 100644 layout/forms/nsGfxButtonControlFrame.h create mode 100644 layout/forms/nsHTMLButtonControlFrame.cpp create mode 100644 layout/forms/nsHTMLButtonControlFrame.h create mode 100644 layout/forms/nsIFormControlFrame.h create mode 100644 layout/forms/nsISelectControlFrame.h create mode 100644 layout/forms/nsITextControlFrame.h create mode 100644 layout/forms/nsImageControlFrame.cpp create mode 100644 layout/forms/nsListControlFrame.cpp create mode 100644 layout/forms/nsListControlFrame.h create mode 100644 layout/forms/nsMeterFrame.cpp create mode 100644 layout/forms/nsMeterFrame.h create mode 100644 layout/forms/nsNumberControlFrame.cpp create mode 100644 layout/forms/nsNumberControlFrame.h create mode 100644 layout/forms/nsProgressFrame.cpp create mode 100644 layout/forms/nsProgressFrame.h create mode 100644 layout/forms/nsRangeFrame.cpp create mode 100644 layout/forms/nsRangeFrame.h create mode 100644 layout/forms/nsSearchControlFrame.cpp create mode 100644 layout/forms/nsSearchControlFrame.h create mode 100644 layout/forms/nsSelectsAreaFrame.cpp create mode 100644 layout/forms/nsSelectsAreaFrame.h create mode 100644 layout/forms/nsTextControlFrame.cpp create mode 100644 layout/forms/nsTextControlFrame.h create mode 100644 layout/forms/test/bug287446_subframe.html create mode 100644 layout/forms/test/bug477700_subframe.html create mode 100644 layout/forms/test/bug536567_iframe.html create mode 100644 layout/forms/test/bug536567_subframe.html create mode 100644 layout/forms/test/bug564115_window.html create mode 100644 layout/forms/test/chrome.ini create mode 100644 layout/forms/test/mochitest.ini create mode 100644 layout/forms/test/test_bug1111995.html create mode 100644 layout/forms/test/test_bug1301290.html create mode 100644 layout/forms/test/test_bug1305282.html create mode 100644 layout/forms/test/test_bug1327129.html create mode 100644 layout/forms/test/test_bug1529036.html create mode 100644 layout/forms/test/test_bug231389.html create mode 100644 layout/forms/test/test_bug287446.html create mode 100644 layout/forms/test/test_bug345267.html create mode 100644 layout/forms/test/test_bug346043.html create mode 100644 layout/forms/test/test_bug348236.html create mode 100644 layout/forms/test/test_bug353539.html create mode 100644 layout/forms/test/test_bug365410.html create mode 100644 layout/forms/test/test_bug378670.html create mode 100644 layout/forms/test/test_bug402198.html create mode 100644 layout/forms/test/test_bug411236.html create mode 100644 layout/forms/test/test_bug446663.html create mode 100644 layout/forms/test/test_bug476308.html create mode 100644 layout/forms/test/test_bug477531.html create mode 100644 layout/forms/test/test_bug477700.html create mode 100644 layout/forms/test/test_bug534785.html create mode 100644 layout/forms/test/test_bug536567_perwindowpb.html create mode 100644 layout/forms/test/test_bug542914.html create mode 100644 layout/forms/test/test_bug549170.html create mode 100644 layout/forms/test/test_bug562447.html create mode 100644 layout/forms/test/test_bug563642.html create mode 100644 layout/forms/test/test_bug564115.html create mode 100644 layout/forms/test/test_bug571352.html create mode 100644 layout/forms/test/test_bug572406.html create mode 100644 layout/forms/test/test_bug572649.html create mode 100644 layout/forms/test/test_bug595310.html create mode 100644 layout/forms/test/test_bug620936.html create mode 100644 layout/forms/test/test_bug644542.html create mode 100644 layout/forms/test/test_bug672810.html create mode 100644 layout/forms/test/test_bug704049.html create mode 100644 layout/forms/test/test_bug717878_input_scroll.html create mode 100644 layout/forms/test/test_bug869314.html create mode 100644 layout/forms/test/test_bug903715.html create mode 100644 layout/forms/test/test_bug935876.html create mode 100644 layout/forms/test/test_bug957562.html create mode 100644 layout/forms/test/test_bug960277.html create mode 100644 layout/forms/test/test_listcontrol_search.html create mode 100644 layout/forms/test/test_readonly.html create mode 100644 layout/forms/test/test_select_collapsed_page_keys.html create mode 100644 layout/forms/test/test_select_key_navigation_bug1498769.html create mode 100644 layout/forms/test/test_select_key_navigation_bug961363.html create mode 100644 layout/forms/test/test_select_prevent_default.html create mode 100644 layout/forms/test/test_select_reframe.html create mode 100644 layout/forms/test/test_select_vertical.html create mode 100644 layout/forms/test/test_textarea_resize.html create mode 100644 layout/forms/test/test_unstyled_control_height.html (limited to 'layout/forms') diff --git a/layout/forms/HTMLSelectEventListener.cpp b/layout/forms/HTMLSelectEventListener.cpp new file mode 100644 index 0000000000..dffabe1bc7 --- /dev/null +++ b/layout/forms/HTMLSelectEventListener.cpp @@ -0,0 +1,851 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "HTMLSelectEventListener.h" + +#include "nsListControlFrame.h" +#include "mozilla/dom/Event.h" +#include "mozilla/dom/MouseEvent.h" +#include "mozilla/Casting.h" +#include "mozilla/MouseEvents.h" +#include "mozilla/TextEvents.h" +#include "mozilla/PresShell.h" +#include "mozilla/dom/HTMLSelectElement.h" +#include "mozilla/dom/HTMLOptionElement.h" +#include "mozilla/StaticPrefs_ui.h" +#include "mozilla/ClearOnShutdown.h" + +using namespace mozilla; +using namespace mozilla::dom; + +static bool IsOptionInteractivelySelectable(HTMLSelectElement& aSelect, + HTMLOptionElement& aOption, + bool aIsCombobox) { + if (aSelect.IsOptionDisabled(&aOption)) { + return false; + } + if (!aIsCombobox) { + return aOption.GetPrimaryFrame(); + } + // In dropdown mode no options have frames, but we can check whether they + // are rendered / not in a display: none subtree. + if (!aOption.HasServoData() || Servo_Element_IsDisplayNone(&aOption)) { + return false; + } + // TODO(emilio): This is a bit silly and doesn't match the options that we + // show / don't show in the dropdown, but matches the frame construction we + // do for multiple selects. For backwards compat also don't allow selecting + // options in a display: contents subtree interactively. + // test_select_key_navigation_bug1498769.html tests for this and should + // probably be changed (and this loop removed) or alternatively + // SelectChild.jsm should be changed to match it. + for (Element* el = &aOption; el && el != &aSelect; + el = el->GetParentElement()) { + if (Servo_Element_IsDisplayContents(el)) { + return false; + } + } + return true; +} + +namespace mozilla { + +static StaticAutoPtr sIncrementalString; +static TimeStamp gLastKeyTime; +static uintptr_t sLastKeyListener = 0; +static constexpr int32_t kNothingSelected = -1; + +static nsString& GetIncrementalString() { + MOZ_ASSERT(sLastKeyListener != 0); + if (!sIncrementalString) { + sIncrementalString = new nsString(); + ClearOnShutdown(&sIncrementalString); + } + return *sIncrementalString; +} + +class MOZ_RAII AutoIncrementalSearchHandler { + public: + explicit AutoIncrementalSearchHandler(HTMLSelectEventListener& aListener) { + if (sLastKeyListener != uintptr_t(&aListener)) { + sLastKeyListener = uintptr_t(&aListener); + GetIncrementalString().Truncate(); + // To make it easier to handle time comparisons in the other methods, + // initialize gLastKeyTime to a value in the past. + gLastKeyTime = TimeStamp::Now() - + TimeDuration::FromMilliseconds( + StaticPrefs::ui_menu_incremental_search_timeout() * 2); + } + } + ~AutoIncrementalSearchHandler() { + if (!mResettingCancelled) { + GetIncrementalString().Truncate(); + } + } + void CancelResetting() { mResettingCancelled = true; } + + private: + bool mResettingCancelled = false; +}; + +NS_IMPL_ISUPPORTS(HTMLSelectEventListener, nsIMutationObserver, + nsIDOMEventListener) + +HTMLSelectEventListener::~HTMLSelectEventListener() { + if (sLastKeyListener == uintptr_t(this)) { + sLastKeyListener = 0; + } +} + +nsListControlFrame* HTMLSelectEventListener::GetListControlFrame() const { + if (mIsCombobox) { + MOZ_ASSERT(!mElement->GetPrimaryFrame() || + !mElement->GetPrimaryFrame()->IsListControlFrame()); + return nullptr; + } + return do_QueryFrame(mElement->GetPrimaryFrame()); +} + +int32_t HTMLSelectEventListener::GetEndSelectionIndex() const { + if (auto* lf = GetListControlFrame()) { + return lf->GetEndSelectionIndex(); + } + // Combobox selects only have one selected index, so the end and start is the + // same. + return mElement->SelectedIndex(); +} + +bool HTMLSelectEventListener::IsOptionInteractivelySelectable( + uint32_t aIndex) const { + HTMLOptionElement* option = mElement->Item(aIndex); + return option && + ::IsOptionInteractivelySelectable(*mElement, *option, mIsCombobox); +} + +//--------------------------------------------------------------------- +// Ok, the entire idea of this routine is to move to the next item that +// is suppose to be selected. If the item is disabled then we search in +// the same direction looking for the next item to select. If we run off +// the end of the list then we start at the end of the list and search +// backwards until we get back to the original item or an enabled option +// +// aStartIndex - the index to start searching from +// aNewIndex - will get set to the new index if it finds one +// aNumOptions - the total number of options in the list +// aDoAdjustInc - the initial index increment / decrement +// aDoAdjustIncNext - the subsequent index increment/decrement used to search +// for the next enabled option +// +// the aDoAdjustInc could be a "1" for a single item or +// any number greater representing a page of items +// +void HTMLSelectEventListener::AdjustIndexForDisabledOpt( + int32_t aStartIndex, int32_t& aNewIndex, int32_t aNumOptions, + int32_t aDoAdjustInc, int32_t aDoAdjustIncNext) { + // Cannot select anything if there is nothing to select + if (aNumOptions == 0) { + aNewIndex = kNothingSelected; + return; + } + + // means we reached the end of the list and now we are searching backwards + bool doingReverse = false; + // lowest index in the search range + int32_t bottom = 0; + // highest index in the search range + int32_t top = aNumOptions; + + // Start off keyboard options at selectedIndex if nothing else is defaulted to + // + // XXX Perhaps this should happen for mouse too, to start off shift click + // automatically in multiple ... to do this, we'd need to override + // OnOptionSelected and set mStartSelectedIndex if nothing is selected. Not + // sure of the effects, though, so I'm not doing it just yet. + int32_t startIndex = aStartIndex; + if (startIndex < bottom) { + startIndex = mElement->SelectedIndex(); + } + int32_t newIndex = startIndex + aDoAdjustInc; + + // make sure we start off in the range + if (newIndex < bottom) { + newIndex = 0; + } else if (newIndex >= top) { + newIndex = aNumOptions - 1; + } + + while (true) { + // if the newIndex is selectable, we are golden, bail out + if (IsOptionInteractivelySelectable(newIndex)) { + break; + } + + // it WAS disabled, so sart looking ahead for the next enabled option + newIndex += aDoAdjustIncNext; + + // well, if we reach end reverse the search + if (newIndex < bottom) { + if (doingReverse) { + return; // if we are in reverse mode and reach the end bail out + } + // reset the newIndex to the end of the list we hit + // reverse the incrementer + // set the other end of the list to our original starting index + newIndex = bottom; + aDoAdjustIncNext = 1; + doingReverse = true; + top = startIndex; + } else if (newIndex >= top) { + if (doingReverse) { + return; // if we are in reverse mode and reach the end bail out + } + // reset the newIndex to the end of the list we hit + // reverse the incrementer + // set the other end of the list to our original starting index + newIndex = top - 1; + aDoAdjustIncNext = -1; + doingReverse = true; + bottom = startIndex; + } + } + + // Looks like we found one + aNewIndex = newIndex; +} + +NS_IMETHODIMP +HTMLSelectEventListener::HandleEvent(dom::Event* aEvent) { + nsAutoString eventType; + aEvent->GetType(eventType); + if (eventType.EqualsLiteral("keydown")) { + return KeyDown(aEvent); + } + if (eventType.EqualsLiteral("keypress")) { + return KeyPress(aEvent); + } + if (eventType.EqualsLiteral("mousedown")) { + if (aEvent->DefaultPrevented()) { + return NS_OK; + } + return MouseDown(aEvent); + } + if (eventType.EqualsLiteral("mouseup")) { + // Don't try to honor defaultPrevented here - it's not web compatible. + // (bug 1194733) + return MouseUp(aEvent); + } + if (eventType.EqualsLiteral("mousemove")) { + // I don't think we want to honor defaultPrevented on mousemove + // in general, and it would only prevent highlighting here. + return MouseMove(aEvent); + } + + MOZ_ASSERT_UNREACHABLE("Unexpected eventType"); + return NS_OK; +} + +void HTMLSelectEventListener::Attach() { + mElement->AddSystemEventListener(u"keydown"_ns, this, false, false); + mElement->AddSystemEventListener(u"keypress"_ns, this, false, false); + mElement->AddSystemEventListener(u"mousedown"_ns, this, false, false); + mElement->AddSystemEventListener(u"mouseup"_ns, this, false, false); + mElement->AddSystemEventListener(u"mousemove"_ns, this, false, false); + + if (mIsCombobox) { + mElement->AddMutationObserver(this); + } +} + +void HTMLSelectEventListener::Detach() { + mElement->RemoveSystemEventListener(u"keydown"_ns, this, false); + mElement->RemoveSystemEventListener(u"keypress"_ns, this, false); + mElement->RemoveSystemEventListener(u"mousedown"_ns, this, false); + mElement->RemoveSystemEventListener(u"mouseup"_ns, this, false); + mElement->RemoveSystemEventListener(u"mousemove"_ns, this, false); + + if (mIsCombobox) { + mElement->RemoveMutationObserver(this); + if (mElement->OpenInParentProcess()) { + nsContentUtils::AddScriptRunner(NS_NewRunnableFunction( + "HTMLSelectEventListener::Detach", [element = mElement] { + // Don't hide the dropdown if the element has another frame already, + // this prevents closing dropdowns on reframe, see bug 1440506. + // + // FIXME(emilio): The flush is needed to deal with reframes started + // from DOM node removal. But perhaps we can be a bit smarter here. + if (!element->IsCombobox() || + !element->GetPrimaryFrame(FlushType::Frames)) { + nsContentUtils::DispatchChromeEvent( + element->OwnerDoc(), ToSupports(element.get()), + u"mozhidedropdown"_ns, CanBubble::eYes, Cancelable::eNo); + } + })); + } + } +} + +const uint32_t kMaxDropdownRows = 20; // matches the setting for 4.x browsers + +int32_t HTMLSelectEventListener::ItemsPerPage() const { + uint32_t size = [&] { + if (mIsCombobox) { + return kMaxDropdownRows; + } + if (auto* lf = GetListControlFrame()) { + return lf->GetNumDisplayRows(); + } + return mElement->Size(); + }(); + if (size <= 1) { + return 1; + } + if (MOZ_UNLIKELY(size > INT32_MAX)) { + return INT32_MAX - 1; + } + return AssertedCast(size - 1u); +} + +void HTMLSelectEventListener::OptionValueMightHaveChanged( + nsIContent* aMutatingNode) { +#ifdef ACCESSIBILITY + if (nsAccessibilityService* acc = GetAccService()) { + acc->ComboboxOptionMaybeChanged(mElement->OwnerDoc()->GetPresShell(), + aMutatingNode); + } +#endif +} + +void HTMLSelectEventListener::AttributeChanged(dom::Element* aElement, + int32_t aNameSpaceID, + nsAtom* aAttribute, + int32_t aModType, + const nsAttrValue* aOldValue) { + if (aElement->IsHTMLElement(nsGkAtoms::option) && + aNameSpaceID == kNameSpaceID_None && aAttribute == nsGkAtoms::label) { + // A11y has its own mutation listener for this so no need to do + // OptionValueMightHaveChanged(). + ComboboxMightHaveChanged(); + } +} + +void HTMLSelectEventListener::CharacterDataChanged( + nsIContent* aContent, const CharacterDataChangeInfo&) { + if (nsContentUtils::IsInSameAnonymousTree(mElement, aContent)) { + OptionValueMightHaveChanged(aContent); + ComboboxMightHaveChanged(); + } +} + +void HTMLSelectEventListener::ContentRemoved(nsIContent* aChild, + nsIContent* aPreviousSibling) { + if (nsContentUtils::IsInSameAnonymousTree(mElement, aChild)) { + OptionValueMightHaveChanged(aChild); + ComboboxMightHaveChanged(); + } +} + +void HTMLSelectEventListener::ContentAppended(nsIContent* aFirstNewContent) { + if (nsContentUtils::IsInSameAnonymousTree(mElement, aFirstNewContent)) { + OptionValueMightHaveChanged(aFirstNewContent); + ComboboxMightHaveChanged(); + } +} + +void HTMLSelectEventListener::ContentInserted(nsIContent* aChild) { + if (nsContentUtils::IsInSameAnonymousTree(mElement, aChild)) { + OptionValueMightHaveChanged(aChild); + ComboboxMightHaveChanged(); + } +} + +void HTMLSelectEventListener::ComboboxMightHaveChanged() { + if (nsIFrame* f = mElement->GetPrimaryFrame()) { + PresShell* ps = f->PresShell(); + // nsComoboxControlFrame::Reflow updates the selected text. AddOption / + // RemoveOption / etc takes care of keeping the displayed index up to date. + ps->FrameNeedsReflow(f, IntrinsicDirty::FrameAncestorsAndDescendants, + NS_FRAME_IS_DIRTY); +#ifdef ACCESSIBILITY + if (nsAccessibilityService* acc = GetAccService()) { + acc->ScheduleAccessibilitySubtreeUpdate(ps, mElement); + } +#endif + } +} + +void HTMLSelectEventListener::FireOnInputAndOnChange() { + RefPtr element = mElement; + // Dispatch the input event. + DebugOnly rvIgnored = nsContentUtils::DispatchInputEvent(element); + NS_WARNING_ASSERTION(NS_SUCCEEDED(rvIgnored), + "Failed to dispatch input event"); + + // Dispatch the change event. + nsContentUtils::DispatchTrustedEvent(element->OwnerDoc(), ToSupports(element), + u"change"_ns, CanBubble::eYes, + Cancelable::eNo); +} + +static void FireDropDownEvent(HTMLSelectElement* aElement, bool aShow, + bool aIsSourceTouchEvent) { + const auto eventName = [&] { + if (aShow) { + return aIsSourceTouchEvent ? u"mozshowdropdown-sourcetouch"_ns + : u"mozshowdropdown"_ns; + } + return u"mozhidedropdown"_ns; + }(); + nsContentUtils::DispatchChromeEvent(aElement->OwnerDoc(), + ToSupports(aElement), eventName, + CanBubble::eYes, Cancelable::eNo); +} + +nsresult HTMLSelectEventListener::MouseDown(dom::Event* aMouseEvent) { + NS_ASSERTION(aMouseEvent != nullptr, "aMouseEvent is null."); + + MouseEvent* mouseEvent = aMouseEvent->AsMouseEvent(); + NS_ENSURE_TRUE(mouseEvent, NS_ERROR_FAILURE); + + if (mElement->State().HasState(ElementState::DISABLED)) { + return NS_OK; + } + + // only allow selection with the left button + // if a right button click is on the combobox itself + // or on the select when in listbox mode, then let the click through + const bool isLeftButton = mouseEvent->Button() == 0; + if (!isLeftButton) { + return NS_OK; + } + + if (mIsCombobox) { + uint16_t inputSource = mouseEvent->MozInputSource(); + if (mElement->OpenInParentProcess()) { + nsCOMPtr target = do_QueryInterface(aMouseEvent->GetTarget()); + if (target && target->IsHTMLElement(nsGkAtoms::option)) { + return NS_OK; + } + } + + const bool isSourceTouchEvent = + inputSource == MouseEvent_Binding::MOZ_SOURCE_TOUCH; + FireDropDownEvent(mElement, !mElement->OpenInParentProcess(), + isSourceTouchEvent); + return NS_OK; + } + + if (nsListControlFrame* list = GetListControlFrame()) { + mButtonDown = true; + return list->HandleLeftButtonMouseDown(aMouseEvent); + } + return NS_OK; +} + +nsresult HTMLSelectEventListener::MouseUp(dom::Event* aMouseEvent) { + NS_ASSERTION(aMouseEvent != nullptr, "aMouseEvent is null."); + + MouseEvent* mouseEvent = aMouseEvent->AsMouseEvent(); + NS_ENSURE_TRUE(mouseEvent, NS_ERROR_FAILURE); + + mButtonDown = false; + + if (mElement->State().HasState(ElementState::DISABLED)) { + return NS_OK; + } + + if (nsListControlFrame* lf = GetListControlFrame()) { + lf->CaptureMouseEvents(false); + } + + // only allow selection with the left button + // if a right button click is on the combobox itself + // or on the select when in listbox mode, then let the click through + const bool isLeftButton = mouseEvent->Button() == 0; + if (!isLeftButton) { + return NS_OK; + } + + if (nsListControlFrame* lf = GetListControlFrame()) { + return lf->HandleLeftButtonMouseUp(aMouseEvent); + } + + return NS_OK; +} + +nsresult HTMLSelectEventListener::MouseMove(dom::Event* aMouseEvent) { + NS_ASSERTION(aMouseEvent != nullptr, "aMouseEvent is null."); + + MouseEvent* mouseEvent = aMouseEvent->AsMouseEvent(); + NS_ENSURE_TRUE(mouseEvent, NS_ERROR_FAILURE); + + if (!mButtonDown) { + return NS_OK; + } + + if (nsListControlFrame* lf = GetListControlFrame()) { + return lf->DragMove(aMouseEvent); + } + + return NS_OK; +} + +nsresult HTMLSelectEventListener::KeyPress(dom::Event* aKeyEvent) { + MOZ_ASSERT(aKeyEvent, "aKeyEvent is null."); + + if (mElement->State().HasState(ElementState::DISABLED)) { + return NS_OK; + } + + AutoIncrementalSearchHandler incrementalHandler(*this); + + const WidgetKeyboardEvent* keyEvent = + aKeyEvent->WidgetEventPtr()->AsKeyboardEvent(); + MOZ_ASSERT(keyEvent, + "DOM event must have WidgetKeyboardEvent for its internal event"); + + // Select option with this as the first character + // XXX Not I18N compliant + + // Don't do incremental search if the key event has already consumed. + if (keyEvent->DefaultPrevented()) { + return NS_OK; + } + + if (keyEvent->IsAlt()) { + return NS_OK; + } + + // With some keyboard layout, space key causes non-ASCII space. + // So, the check in keydown event handler isn't enough, we need to check it + // again with keypress event. + if (keyEvent->mCharCode != ' ') { + mControlSelectMode = false; + } + + bool isControlOrMeta = keyEvent->IsControl() || keyEvent->IsMeta(); + if (isControlOrMeta && keyEvent->mCharCode != ' ') { + return NS_OK; + } + + // NOTE: If mKeyCode of keypress event is not 0, mCharCode is always 0. + // Therefore, all non-printable keys are not handled after this block. + if (!keyEvent->mCharCode) { + // Backspace key will delete the last char in the string. Otherwise, + // non-printable keypress should reset incremental search. + if (keyEvent->mKeyCode == NS_VK_BACK) { + incrementalHandler.CancelResetting(); + if (!GetIncrementalString().IsEmpty()) { + GetIncrementalString().Truncate(GetIncrementalString().Length() - 1); + } + aKeyEvent->PreventDefault(); + } else { + // XXX When a select element has focus, even if the key causes nothing, + // it might be better to call preventDefault() here because nobody + // should expect one of other elements including chrome handles the + // key event. + } + return NS_OK; + } + + incrementalHandler.CancelResetting(); + + // We ate the key if we got this far. + aKeyEvent->PreventDefault(); + + // XXX Why don't we check/modify timestamp first? + + // Incremental Search: if time elapsed is below + // ui.menu.incremental_search.timeout, append this keystroke to the search + // string we will use to find options and start searching at the current + // keystroke. Otherwise, Truncate the string if it's been a long time + // since our last keypress. + if ((keyEvent->mTimeStamp - gLastKeyTime).ToMilliseconds() > + StaticPrefs::ui_menu_incremental_search_timeout()) { + // If this is ' ' and we are at the beginning of the string, treat it as + // "select this option" (bug 191543) + if (keyEvent->mCharCode == ' ') { + // Actually process the new index and let the selection code + // do the scrolling for us + PostHandleKeyEvent(GetEndSelectionIndex(), keyEvent->mCharCode, + keyEvent->IsShift(), isControlOrMeta); + + return NS_OK; + } + + GetIncrementalString().Truncate(); + } + + gLastKeyTime = keyEvent->mTimeStamp; + + // Append this keystroke to the search string. + char16_t uniChar = ToLowerCase(static_cast(keyEvent->mCharCode)); + GetIncrementalString().Append(uniChar); + + // See bug 188199, if all letters in incremental string are same, just try to + // match the first one + nsAutoString incrementalString(GetIncrementalString()); + uint32_t charIndex = 1, stringLength = incrementalString.Length(); + while (charIndex < stringLength && + incrementalString[charIndex] == incrementalString[charIndex - 1]) { + charIndex++; + } + if (charIndex == stringLength) { + incrementalString.Truncate(1); + stringLength = 1; + } + + // Determine where we're going to start reading the string + // If we have multiple characters to look for, we start looking *at* the + // current option. If we have only one character to look for, we start + // looking *after* the current option. + // Exception: if there is no option selected to start at, we always start + // *at* 0. + int32_t startIndex = mElement->SelectedIndex(); + if (startIndex == kNothingSelected) { + startIndex = 0; + } else if (stringLength == 1) { + startIndex++; + } + + // now make sure there are options or we are wasting our time + RefPtr options = mElement->Options(); + uint32_t numOptions = options->Length(); + + for (uint32_t i = 0; i < numOptions; ++i) { + uint32_t index = (i + startIndex) % numOptions; + RefPtr optionElement = options->ItemAsOption(index); + if (!optionElement || !::IsOptionInteractivelySelectable( + *mElement, *optionElement, mIsCombobox)) { + continue; + } + + nsAutoString text; + optionElement->GetRenderedLabel(text); + if (!StringBeginsWith( + nsContentUtils::TrimWhitespace< + nsContentUtils::IsHTMLWhitespaceOrNBSP>(text, false), + incrementalString, nsCaseInsensitiveStringComparator)) { + continue; + } + + if (mIsCombobox) { + if (optionElement->Selected()) { + return NS_OK; + } + optionElement->SetSelected(true); + FireOnInputAndOnChange(); + return NS_OK; + } + + if (nsListControlFrame* lf = GetListControlFrame()) { + bool wasChanged = + lf->PerformSelection(index, keyEvent->IsShift(), isControlOrMeta); + if (!wasChanged) { + return NS_OK; + } + FireOnInputAndOnChange(); + } + break; + } + + return NS_OK; +} + +nsresult HTMLSelectEventListener::KeyDown(dom::Event* aKeyEvent) { + MOZ_ASSERT(aKeyEvent, "aKeyEvent is null."); + + if (mElement->State().HasState(ElementState::DISABLED)) { + return NS_OK; + } + + AutoIncrementalSearchHandler incrementalHandler(*this); + + if (aKeyEvent->DefaultPrevented()) { + return NS_OK; + } + + const WidgetKeyboardEvent* keyEvent = + aKeyEvent->WidgetEventPtr()->AsKeyboardEvent(); + MOZ_ASSERT(keyEvent, + "DOM event must have WidgetKeyboardEvent for its internal event"); + + bool dropDownMenuOnUpDown; + bool dropDownMenuOnSpace; +#ifdef XP_MACOSX + dropDownMenuOnUpDown = mIsCombobox && !mElement->OpenInParentProcess(); + dropDownMenuOnSpace = mIsCombobox && !keyEvent->IsAlt() && + !keyEvent->IsControl() && !keyEvent->IsMeta(); +#else + dropDownMenuOnUpDown = mIsCombobox && keyEvent->IsAlt(); + dropDownMenuOnSpace = mIsCombobox && !mElement->OpenInParentProcess(); +#endif + bool withinIncrementalSearchTime = + (keyEvent->mTimeStamp - gLastKeyTime).ToMilliseconds() <= + StaticPrefs::ui_menu_incremental_search_timeout(); + if ((dropDownMenuOnUpDown && + (keyEvent->mKeyCode == NS_VK_UP || keyEvent->mKeyCode == NS_VK_DOWN)) || + (dropDownMenuOnSpace && keyEvent->mKeyCode == NS_VK_SPACE && + !withinIncrementalSearchTime)) { + FireDropDownEvent(mElement, !mElement->OpenInParentProcess(), false); + aKeyEvent->PreventDefault(); + return NS_OK; + } + if (keyEvent->IsAlt()) { + return NS_OK; + } + + // We should not change the selection if the popup is "opened in the parent + // process" (even when we're in single-process mode). + const bool shouldSelect = !mIsCombobox || !mElement->OpenInParentProcess(); + + // now make sure there are options or we are wasting our time + RefPtr options = mElement->Options(); + uint32_t numOptions = options->Length(); + + // this is the new index to set + int32_t newIndex = kNothingSelected; + + bool isControlOrMeta = keyEvent->IsControl() || keyEvent->IsMeta(); + // Don't try to handle multiple-select pgUp/pgDown in single-select lists. + if (isControlOrMeta && !mElement->Multiple() && + (keyEvent->mKeyCode == NS_VK_PAGE_UP || + keyEvent->mKeyCode == NS_VK_PAGE_DOWN)) { + return NS_OK; + } + if (isControlOrMeta && + (keyEvent->mKeyCode == NS_VK_UP || keyEvent->mKeyCode == NS_VK_LEFT || + keyEvent->mKeyCode == NS_VK_DOWN || keyEvent->mKeyCode == NS_VK_RIGHT || + keyEvent->mKeyCode == NS_VK_HOME || keyEvent->mKeyCode == NS_VK_END)) { + // Don't go into multiple-select mode unless this list can handle it. + isControlOrMeta = mControlSelectMode = mElement->Multiple(); + } else if (keyEvent->mKeyCode != NS_VK_SPACE) { + mControlSelectMode = false; + } + + switch (keyEvent->mKeyCode) { + case NS_VK_UP: + case NS_VK_LEFT: + if (shouldSelect) { + AdjustIndexForDisabledOpt(GetEndSelectionIndex(), newIndex, + int32_t(numOptions), -1, -1); + } + break; + case NS_VK_DOWN: + case NS_VK_RIGHT: + if (shouldSelect) { + AdjustIndexForDisabledOpt(GetEndSelectionIndex(), newIndex, + int32_t(numOptions), 1, 1); + } + break; + case NS_VK_RETURN: + // If this is single select listbox, Enter key doesn't cause anything. + if (!mElement->Multiple()) { + return NS_OK; + } + + newIndex = GetEndSelectionIndex(); + break; + case NS_VK_PAGE_UP: { + if (shouldSelect) { + AdjustIndexForDisabledOpt(GetEndSelectionIndex(), newIndex, + int32_t(numOptions), -ItemsPerPage(), -1); + } + break; + } + case NS_VK_PAGE_DOWN: { + if (shouldSelect) { + AdjustIndexForDisabledOpt(GetEndSelectionIndex(), newIndex, + int32_t(numOptions), ItemsPerPage(), 1); + } + break; + } + case NS_VK_HOME: + if (shouldSelect) { + AdjustIndexForDisabledOpt(0, newIndex, int32_t(numOptions), 0, 1); + } + break; + case NS_VK_END: + if (shouldSelect) { + AdjustIndexForDisabledOpt(int32_t(numOptions) - 1, newIndex, + int32_t(numOptions), 0, -1); + } + break; + default: // printable key will be handled by keypress event. + incrementalHandler.CancelResetting(); + return NS_OK; + } + + aKeyEvent->PreventDefault(); + + // Actually process the new index and let the selection code + // do the scrolling for us + PostHandleKeyEvent(newIndex, 0, keyEvent->IsShift(), isControlOrMeta); + return NS_OK; +} + +HTMLOptionElement* HTMLSelectEventListener::GetCurrentOption() const { + // The mEndSelectionIndex is what is currently being selected. Use + // the selected index if this is kNothingSelected. + int32_t endIndex = GetEndSelectionIndex(); + int32_t focusedIndex = + endIndex == kNothingSelected ? mElement->SelectedIndex() : endIndex; + if (focusedIndex != kNothingSelected) { + return mElement->Item(AssertedCast(focusedIndex)); + } + + // There is no selected option. Return the first non-disabled option, if any. + return GetNonDisabledOptionFrom(0); +} + +HTMLOptionElement* HTMLSelectEventListener::GetNonDisabledOptionFrom( + int32_t aFromIndex, int32_t* aFoundIndex) const { + const uint32_t length = mElement->Length(); + for (uint32_t i = std::max(aFromIndex, 0); i < length; ++i) { + if (IsOptionInteractivelySelectable(i)) { + if (aFoundIndex) { + *aFoundIndex = i; + } + return mElement->Item(i); + } + } + return nullptr; +} + +void HTMLSelectEventListener::PostHandleKeyEvent(int32_t aNewIndex, + uint32_t aCharCode, + bool aIsShift, + bool aIsControlOrMeta) { + if (aNewIndex == kNothingSelected) { + int32_t endIndex = GetEndSelectionIndex(); + int32_t focusedIndex = + endIndex == kNothingSelected ? mElement->SelectedIndex() : endIndex; + if (focusedIndex != kNothingSelected) { + return; + } + // No options are selected. In this case the focus ring is on the first + // non-disabled option (if any), so we should behave as if that's the option + // the user acted on. + if (!GetNonDisabledOptionFrom(0, &aNewIndex)) { + return; + } + } + + if (mIsCombobox) { + RefPtr newOption = mElement->Item(aNewIndex); + MOZ_ASSERT(newOption); + if (newOption->Selected()) { + return; + } + newOption->SetSelected(true); + FireOnInputAndOnChange(); + return; + } + if (nsListControlFrame* lf = GetListControlFrame()) { + lf->UpdateSelectionAfterKeyEvent(aNewIndex, aCharCode, aIsShift, + aIsControlOrMeta, mControlSelectMode); + } +} + +} // namespace mozilla diff --git a/layout/forms/HTMLSelectEventListener.h b/layout/forms/HTMLSelectEventListener.h new file mode 100644 index 0000000000..452610a217 --- /dev/null +++ b/layout/forms/HTMLSelectEventListener.h @@ -0,0 +1,103 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_HTMLSelectEventListener_h +#define mozilla_HTMLSelectEventListener_h + +#include "nsIDOMEventListener.h" +#include "nsStubMutationObserver.h" + +class nsIFrame; +class nsListControlFrame; + +namespace mozilla { + +namespace dom { +class HTMLSelectElement; +class HTMLOptionElement; +class Event; +} // namespace dom + +/** + * HTMLSelectEventListener + * This class is responsible for propagating events to the select element while + * it has a frame. + * Frames are not refcounted so they can't be used as event listeners. + */ + +class HTMLSelectEventListener final : public nsStubMutationObserver, + public nsIDOMEventListener { + public: + enum class SelectType : uint8_t { Listbox, Combobox }; + HTMLSelectEventListener(dom::HTMLSelectElement& aElement, + SelectType aSelectType) + : mElement(&aElement), mIsCombobox(aSelectType == SelectType::Combobox) { + Attach(); + } + + NS_DECL_ISUPPORTS + + // For comboboxes, we need to keep the list up to date when options change. + NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED + NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED + NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED + NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED + NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED + + // nsIDOMEventListener + MOZ_CAN_RUN_SCRIPT_BOUNDARY NS_IMETHOD HandleEvent(dom::Event*) override; + + void Attach(); + void Detach(); + + dom::HTMLOptionElement* GetCurrentOption() const; + + MOZ_CAN_RUN_SCRIPT void FireOnInputAndOnChange(); + + private: + // This is always guaranteed to be > 0, but callers want signed integers so we + // do the cast for them. + int32_t ItemsPerPage() const; + + nsListControlFrame* GetListControlFrame() const; + + MOZ_CAN_RUN_SCRIPT nsresult KeyDown(dom::Event*); + MOZ_CAN_RUN_SCRIPT nsresult KeyPress(dom::Event*); + MOZ_CAN_RUN_SCRIPT nsresult MouseDown(dom::Event*); + MOZ_CAN_RUN_SCRIPT nsresult MouseUp(dom::Event*); + MOZ_CAN_RUN_SCRIPT nsresult MouseMove(dom::Event*); + + void AdjustIndexForDisabledOpt(int32_t aStartIndex, int32_t& aNewIndex, + int32_t aNumOptions, int32_t aDoAdjustInc, + int32_t aDoAdjustIncNext); + bool IsOptionInteractivelySelectable(uint32_t aIndex) const; + int32_t GetEndSelectionIndex() const; + + MOZ_CAN_RUN_SCRIPT + void PostHandleKeyEvent(int32_t aNewIndex, uint32_t aCharCode, bool aIsShift, + bool aIsControlOrMeta); + + /** + * Return the first non-disabled option starting at aFromIndex (inclusive). + * @param aFoundIndex if non-null, set to the index of the returned option + */ + dom::HTMLOptionElement* GetNonDisabledOptionFrom( + int32_t aFromIndex, int32_t* aFoundIndex = nullptr) const; + + void ComboboxMightHaveChanged(); + void OptionValueMightHaveChanged(nsIContent* aMutatingNode); + + ~HTMLSelectEventListener(); + + RefPtr mElement; + const bool mIsCombobox; + bool mButtonDown = false; + bool mControlSelectMode = false; +}; + +} // namespace mozilla + +#endif // mozilla_HTMLSelectEventListener_h diff --git a/layout/forms/ListMutationObserver.cpp b/layout/forms/ListMutationObserver.cpp new file mode 100644 index 0000000000..13f9e367a0 --- /dev/null +++ b/layout/forms/ListMutationObserver.cpp @@ -0,0 +1,92 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "ListMutationObserver.h" + +#include "mozilla/dom/HTMLInputElement.h" +#include "nsIFrame.h" + +namespace mozilla { +NS_IMPL_ISUPPORTS(ListMutationObserver, nsIMutationObserver) + +ListMutationObserver::~ListMutationObserver() = default; + +void ListMutationObserver::Attach(bool aRepaint) { + nsAutoString id; + if (InputElement().GetAttr(nsGkAtoms::list_, id)) { + Unlink(); + RefPtr idAtom = NS_AtomizeMainThread(id); + ResetWithID(InputElement(), idAtom); + AddObserverIfNeeded(); + } + if (aRepaint) { + mOwningElementFrame->InvalidateFrame(); + } +} + +void ListMutationObserver::AddObserverIfNeeded() { + if (auto* list = get()) { + if (list->IsHTMLElement(nsGkAtoms::datalist)) { + list->AddMutationObserver(this); + } + } +} + +void ListMutationObserver::RemoveObserverIfNeeded(dom::Element* aList) { + if (aList && aList->IsHTMLElement(nsGkAtoms::datalist)) { + aList->RemoveMutationObserver(this); + } +} + +void ListMutationObserver::Detach() { + RemoveObserverIfNeeded(); + Unlink(); +} + +dom::HTMLInputElement& ListMutationObserver::InputElement() const { + MOZ_ASSERT(mOwningElementFrame->GetContent()->IsHTMLElement(nsGkAtoms::input), + "bad cast"); + return *static_cast( + mOwningElementFrame->GetContent()); +} + +void ListMutationObserver::AttributeChanged(dom::Element* aElement, + int32_t aNameSpaceID, + nsAtom* aAttribute, + int32_t aModType, + const nsAttrValue* aOldValue) { + if (aAttribute == nsGkAtoms::value && aNameSpaceID == kNameSpaceID_None && + aElement->IsHTMLElement(nsGkAtoms::option)) { + mOwningElementFrame->InvalidateFrame(); + } +} + +void ListMutationObserver::CharacterDataChanged( + nsIContent* aContent, const CharacterDataChangeInfo& aInfo) { + mOwningElementFrame->InvalidateFrame(); +} + +void ListMutationObserver::ContentAppended(nsIContent* aFirstNewContent) { + mOwningElementFrame->InvalidateFrame(); +} + +void ListMutationObserver::ContentInserted(nsIContent* aChild) { + mOwningElementFrame->InvalidateFrame(); +} + +void ListMutationObserver::ContentRemoved(nsIContent* aChild, + nsIContent* aPreviousSibling) { + mOwningElementFrame->InvalidateFrame(); +} + +void ListMutationObserver::ElementChanged(dom::Element* aFrom, + dom::Element* aTo) { + IDTracker::ElementChanged(aFrom, aTo); + RemoveObserverIfNeeded(aFrom); + AddObserverIfNeeded(); + mOwningElementFrame->InvalidateFrame(); +} + +} // namespace mozilla diff --git a/layout/forms/ListMutationObserver.h b/layout/forms/ListMutationObserver.h new file mode 100644 index 0000000000..8c81077fb6 --- /dev/null +++ b/layout/forms/ListMutationObserver.h @@ -0,0 +1,67 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set ts=8 sts=2 et sw=2 tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_ListMutationObserver_h +#define mozilla_ListMutationObserver_h + +#include "IDTracker.h" +#include "nsStubMutationObserver.h" + +class nsIFrame; + +namespace mozilla { + +namespace dom { +class HTMLInputElement; +} // namespace dom + +/** + * ListMutationObserver + * This class invalidates paint for the input element's frame when the content + * of its @list changes, or when the @list ID identifies a different element. It + * does *not* invalidate paint when the @list attribute itself changes. + */ + +class ListMutationObserver final : public nsStubMutationObserver, + public dom::IDTracker { + public: + explicit ListMutationObserver(nsIFrame& aOwningElementFrame, + bool aRepaint = false) + : mOwningElementFrame(&aOwningElementFrame) { + // We can skip invalidating paint if the frame is still being initialized. + Attach(aRepaint); + } + + NS_DECL_ISUPPORTS + + // We need to invalidate paint when the list or its options change. + NS_DECL_NSIMUTATIONOBSERVER_ATTRIBUTECHANGED + NS_DECL_NSIMUTATIONOBSERVER_CHARACTERDATACHANGED + NS_DECL_NSIMUTATIONOBSERVER_CONTENTAPPENDED + NS_DECL_NSIMUTATIONOBSERVER_CONTENTINSERTED + NS_DECL_NSIMUTATIONOBSERVER_CONTENTREMOVED + + /** + * Triggered when the same @list ID identifies a different element than + * before. + */ + void ElementChanged(dom::Element* aFrom, dom::Element* aTo) override; + + void Attach(bool aRepaint = true); + void Detach(); + void AddObserverIfNeeded(); + void RemoveObserverIfNeeded(dom::Element* aList); + void RemoveObserverIfNeeded() { RemoveObserverIfNeeded(get()); } + dom::HTMLInputElement& InputElement() const; + + private: + ~ListMutationObserver(); + + nsIFrame* mOwningElementFrame; +}; +} // namespace mozilla + +#endif // mozilla_ListMutationObserver_h diff --git a/layout/forms/crashtests/1102791.html b/layout/forms/crashtests/1102791.html new file mode 100644 index 0000000000..0fd64d7553 --- /dev/null +++ b/layout/forms/crashtests/1102791.html @@ -0,0 +1,33 @@ + + + + Testcase for bug 1102791 + + + + + + + + diff --git a/layout/forms/crashtests/1140216.html b/layout/forms/crashtests/1140216.html new file mode 100644 index 0000000000..72612b8b3c --- /dev/null +++ b/layout/forms/crashtests/1140216.html @@ -0,0 +1,20 @@ + + + + + + + + + diff --git a/layout/forms/crashtests/1182414.html b/layout/forms/crashtests/1182414.html new file mode 100644 index 0000000000..3aaa0bbfcc --- /dev/null +++ b/layout/forms/crashtests/1182414.html @@ -0,0 +1,17 @@ + + + + + + + + + + + + + diff --git a/layout/forms/crashtests/1212688.html b/layout/forms/crashtests/1212688.html new file mode 100644 index 0000000000..68262d907f --- /dev/null +++ b/layout/forms/crashtests/1212688.html @@ -0,0 +1,27 @@ + + diff --git a/layout/forms/crashtests/1228670.xhtml b/layout/forms/crashtests/1228670.xhtml new file mode 100644 index 0000000000..cc8d309c0e --- /dev/null +++ b/layout/forms/crashtests/1228670.xhtml @@ -0,0 +1,7 @@ + + + + + diff --git a/layout/forms/crashtests/1279354.html b/layout/forms/crashtests/1279354.html new file mode 100644 index 0000000000..5013392526 --- /dev/null +++ b/layout/forms/crashtests/1279354.html @@ -0,0 +1,21 @@ + + + + + Testcase for bug 1279354 + + + +
+1 +
+2 +
+3 +
+ + + diff --git a/layout/forms/crashtests/1388230-1.html b/layout/forms/crashtests/1388230-1.html new file mode 100644 index 0000000000..6662a6ef01 --- /dev/null +++ b/layout/forms/crashtests/1388230-1.html @@ -0,0 +1,3 @@ + + + diff --git a/layout/forms/crashtests/1388230-2.html b/layout/forms/crashtests/1388230-2.html new file mode 100644 index 0000000000..630031d750 --- /dev/null +++ b/layout/forms/crashtests/1388230-2.html @@ -0,0 +1 @@ + diff --git a/layout/forms/crashtests/1405830.html b/layout/forms/crashtests/1405830.html new file mode 100644 index 0000000000..c16eeca86a --- /dev/null +++ b/layout/forms/crashtests/1405830.html @@ -0,0 +1,19 @@ + + + + + + +0 +Q +- +w +g +k diff --git a/layout/forms/crashtests/1418477.html b/layout/forms/crashtests/1418477.html new file mode 100644 index 0000000000..0be4732d58 --- /dev/null +++ b/layout/forms/crashtests/1418477.html @@ -0,0 +1,4 @@ + + + + diff --git a/layout/forms/crashtests/1432853.html b/layout/forms/crashtests/1432853.html new file mode 100644 index 0000000000..bc0735c47f --- /dev/null +++ b/layout/forms/crashtests/1432853.html @@ -0,0 +1,8 @@ + +
+

+ + + diff --git a/layout/forms/crashtests/1488219.html b/layout/forms/crashtests/1488219.html new file mode 100644 index 0000000000..d10d3ef014 --- /dev/null +++ b/layout/forms/crashtests/1488219.html @@ -0,0 +1,26 @@ + + + + + + +A +
+
+
+
+
+ + diff --git a/layout/forms/crashtests/1600207.html b/layout/forms/crashtests/1600207.html new file mode 100644 index 0000000000..a54a0d0c7d --- /dev/null +++ b/layout/forms/crashtests/1600207.html @@ -0,0 +1,9 @@ + +
+ +

diff --git a/layout/forms/crashtests/1600367.html b/layout/forms/crashtests/1600367.html new file mode 100644 index 0000000000..7a481f814e --- /dev/null +++ b/layout/forms/crashtests/1600367.html @@ -0,0 +1,8 @@ + + +
diff --git a/layout/forms/crashtests/1617753.html b/layout/forms/crashtests/1617753.html new file mode 100644 index 0000000000..213c483451 --- /dev/null +++ b/layout/forms/crashtests/1617753.html @@ -0,0 +1,21 @@ + +
+
+ + diff --git a/layout/forms/crashtests/166750-1.html b/layout/forms/crashtests/166750-1.html new file mode 100644 index 0000000000..d873be1b29 --- /dev/null +++ b/layout/forms/crashtests/166750-1.html @@ -0,0 +1,14 @@ + + + +Killer + + + + + + \ No newline at end of file diff --git a/layout/forms/crashtests/1679471.html b/layout/forms/crashtests/1679471.html new file mode 100644 index 0000000000..8d2bbc8eb0 --- /dev/null +++ b/layout/forms/crashtests/1679471.html @@ -0,0 +1,8 @@ + + + + + + + + + + + diff --git a/layout/forms/test/test_bug231389.html b/layout/forms/test/test_bug231389.html new file mode 100644 index 0000000000..9239839247 --- /dev/null +++ b/layout/forms/test/test_bug231389.html @@ -0,0 +1,55 @@ + + + + + Test for Bug 231389 + + + + +Mozilla Bug 231389 +

+ +

+ +
+
+
+ + diff --git a/layout/forms/test/test_bug287446.html b/layout/forms/test/test_bug287446.html new file mode 100644 index 0000000000..bb9e3bec39 --- /dev/null +++ b/layout/forms/test/test_bug287446.html @@ -0,0 +1,74 @@ + + + + + Test for Bug 287446 + + + + +Mozilla Bug 287446 +

+ +

+ +
+
+
+ + diff --git a/layout/forms/test/test_bug345267.html b/layout/forms/test/test_bug345267.html new file mode 100644 index 0000000000..ba9a3bd555 --- /dev/null +++ b/layout/forms/test/test_bug345267.html @@ -0,0 +1,97 @@ + + + + + Test for Bug 345267 + + + + + +Mozilla Bug 345267 +

+ + + + + +

+ +
+
+
+ + + diff --git a/layout/forms/test/test_bug346043.html b/layout/forms/test/test_bug346043.html new file mode 100644 index 0000000000..e5db9bb8cf --- /dev/null +++ b/layout/forms/test/test_bug346043.html @@ -0,0 +1,65 @@ + + + + + + Test for Bug 346043 + + + + + + + Mozilla Bug 346043 +

+
+ + + +
+

+
+
diff --git a/layout/forms/test/test_bug348236.html b/layout/forms/test/test_bug348236.html
new file mode 100644
index 0000000000..f00f89efa7
--- /dev/null
+++ b/layout/forms/test/test_bug348236.html
@@ -0,0 +1,123 @@
+
+
+
+
+
+  Test for Bug 348236
+  
+  
+  
+  
+
+
+Mozilla Bug 348236
+

+
+ + +
+
+
+
+ + diff --git a/layout/forms/test/test_bug353539.html b/layout/forms/test/test_bug353539.html new file mode 100644 index 0000000000..593250d207 --- /dev/null +++ b/layout/forms/test/test_bug353539.html @@ -0,0 +1,52 @@ + + + + + Test for Bug 353539 + + + + +Mozilla Bug 353539 +

+ +

+ +
+
+
+ + diff --git a/layout/forms/test/test_bug365410.html b/layout/forms/test/test_bug365410.html new file mode 100644 index 0000000000..94ba8abfa0 --- /dev/null +++ b/layout/forms/test/test_bug365410.html @@ -0,0 +1,132 @@ + + + +Test for Bug 365410 + + + + + +Mozilla Bug 365410 +

+ + + + + +

+ +
+
+
+ + diff --git a/layout/forms/test/test_bug378670.html b/layout/forms/test/test_bug378670.html new file mode 100644 index 0000000000..f039cf35d6 --- /dev/null +++ b/layout/forms/test/test_bug378670.html @@ -0,0 +1,55 @@ + + + + + Test for Bug 378670 + + + + + +Mozilla Bug 378670 +

+ +Clicking on the select should not crash Mozilla + + +
+
+
+
+ + diff --git a/layout/forms/test/test_bug402198.html b/layout/forms/test/test_bug402198.html new file mode 100644 index 0000000000..f319a11976 --- /dev/null +++ b/layout/forms/test/test_bug402198.html @@ -0,0 +1,77 @@ + + + + Test for Bug 402198 + + + + + +Mozilla Bug 402198 +

+ + + + + + + + + + + + + + + + + + + +

+ +
+
+
+ + + + + diff --git a/layout/forms/test/test_bug411236.html b/layout/forms/test/test_bug411236.html new file mode 100644 index 0000000000..b2e2bee380 --- /dev/null +++ b/layout/forms/test/test_bug411236.html @@ -0,0 +1,71 @@ + + + + + Test for Bug 411236 + + + + + +Mozilla Bug 411236 +

+
+ +
+
+
+
+ + diff --git a/layout/forms/test/test_bug446663.html b/layout/forms/test/test_bug446663.html new file mode 100644 index 0000000000..bdab0b20ef --- /dev/null +++ b/layout/forms/test/test_bug446663.html @@ -0,0 +1,80 @@ + + + + + Test for Bug 446663 + + + + + +Mozilla Bug 446663 +

+ +

+ +
+
+
+ + + diff --git a/layout/forms/test/test_bug476308.html b/layout/forms/test/test_bug476308.html new file mode 100644 index 0000000000..41858d9eb8 --- /dev/null +++ b/layout/forms/test/test_bug476308.html @@ -0,0 +1,31 @@ + + + + + Test for Bug 345267 + + + + + + + + +
+
2
+ + + + + + diff --git a/layout/forms/test/test_bug477531.html b/layout/forms/test/test_bug477531.html new file mode 100644 index 0000000000..e0c7979af4 --- /dev/null +++ b/layout/forms/test/test_bug477531.html @@ -0,0 +1,65 @@ + + + + + Test for Bug 477531 + + + + + + +Mozilla Bug 477531 +

+
+ + + +
+
+
+
+ + + diff --git a/layout/forms/test/test_bug477700.html b/layout/forms/test/test_bug477700.html new file mode 100644 index 0000000000..1ab8d88321 --- /dev/null +++ b/layout/forms/test/test_bug477700.html @@ -0,0 +1,59 @@ + + + + + Test for Bug 477700 + + + + +Mozilla Bug 477700 +

+ +

+ +
+
+
+ + diff --git a/layout/forms/test/test_bug534785.html b/layout/forms/test/test_bug534785.html new file mode 100644 index 0000000000..7e43838927 --- /dev/null +++ b/layout/forms/test/test_bug534785.html @@ -0,0 +1,88 @@ + + + + + Test for Bug 534785 + + + + + +Mozilla Bug 534785 +

+ +
+ + + + +
+
+
+
+ + diff --git a/layout/forms/test/test_bug536567_perwindowpb.html b/layout/forms/test/test_bug536567_perwindowpb.html new file mode 100644 index 0000000000..224b2c74a4 --- /dev/null +++ b/layout/forms/test/test_bug536567_perwindowpb.html @@ -0,0 +1,215 @@ + + + + + Test for Bug 536567 + + + + + +Mozilla Bug 536567 +

+
+
+
+ + diff --git a/layout/forms/test/test_bug542914.html b/layout/forms/test/test_bug542914.html new file mode 100644 index 0000000000..ff7a68acea --- /dev/null +++ b/layout/forms/test/test_bug542914.html @@ -0,0 +1,115 @@ + + + + + Test for Bug 542914 + + + + + +Mozilla Bug 542914 +

+ + + +

+ +
+
+
+ + diff --git a/layout/forms/test/test_bug549170.html b/layout/forms/test/test_bug549170.html new file mode 100644 index 0000000000..a8a3f6d508 --- /dev/null +++ b/layout/forms/test/test_bug549170.html @@ -0,0 +1,77 @@ + + + + + Test for Bug 549170 + + + + + +Mozilla Bug 549170 +

+ + +
+ + +
+
+
+
+ + diff --git a/layout/forms/test/test_bug562447.html b/layout/forms/test/test_bug562447.html new file mode 100644 index 0000000000..86042bb485 --- /dev/null +++ b/layout/forms/test/test_bug562447.html @@ -0,0 +1,62 @@ + + + + + Test for Bug 562447 + + + + + +

Mozilla Bug 562447 + + + +

+
+
+ + + diff --git a/layout/forms/test/test_bug563642.html b/layout/forms/test/test_bug563642.html new file mode 100644 index 0000000000..72bb4c6858 --- /dev/null +++ b/layout/forms/test/test_bug563642.html @@ -0,0 +1,82 @@ + + + + + Test for Bug 563642 + + + + + +Mozilla Bug 563642 +

+ + + + +

+ +
+
+
+ + diff --git a/layout/forms/test/test_bug564115.html b/layout/forms/test/test_bug564115.html new file mode 100644 index 0000000000..16fb423341 --- /dev/null +++ b/layout/forms/test/test_bug564115.html @@ -0,0 +1,57 @@ + + + + + Test for Bug 564115 + + + + + +

Mozilla Bug 564115 + +

+
+
+ + + diff --git a/layout/forms/test/test_bug571352.html b/layout/forms/test/test_bug571352.html new file mode 100644 index 0000000000..73ad7454f3 --- /dev/null +++ b/layout/forms/test/test_bug571352.html @@ -0,0 +1,86 @@ + + + + + Test for Bug 571352 + + + + + +Mozilla Bug 571352 +

+ +
+
+
+ + diff --git a/layout/forms/test/test_bug572406.html b/layout/forms/test/test_bug572406.html new file mode 100644 index 0000000000..8b4d0b81ce --- /dev/null +++ b/layout/forms/test/test_bug572406.html @@ -0,0 +1,48 @@ + + + + + Test for Bug 572406 + + + + +Mozilla Bug 572406 +

+
+ +
+
+
+
+ + diff --git a/layout/forms/test/test_bug572649.html b/layout/forms/test/test_bug572649.html new file mode 100644 index 0000000000..10fa6e63f7 --- /dev/null +++ b/layout/forms/test/test_bug572649.html @@ -0,0 +1,63 @@ + + + + + Test for Bug 572649 + + + + + +Mozilla Bug 572649 +

+ +

+ +
+
+
+ + diff --git a/layout/forms/test/test_bug595310.html b/layout/forms/test/test_bug595310.html new file mode 100644 index 0000000000..47db981167 --- /dev/null +++ b/layout/forms/test/test_bug595310.html @@ -0,0 +1,64 @@ + + + + + Test for Bug 595310 + + + + + +Mozilla Bug 595310 +

+
+ + +
+
+
+
+ + diff --git a/layout/forms/test/test_bug620936.html b/layout/forms/test/test_bug620936.html new file mode 100644 index 0000000000..aa1beed01a --- /dev/null +++ b/layout/forms/test/test_bug620936.html @@ -0,0 +1,35 @@ + + + + + Test for Bug 620936 + + + + + +Mozilla Bug 620936 +

+
+ +
+
+
+
+ + diff --git a/layout/forms/test/test_bug644542.html b/layout/forms/test/test_bug644542.html new file mode 100644 index 0000000000..6c33cbe958 --- /dev/null +++ b/layout/forms/test/test_bug644542.html @@ -0,0 +1,63 @@ + + + + + Test for Bug 644542 + + + + + + +Mozilla Bug 644542 +

+ + + +

+ +
+
+
+ + diff --git a/layout/forms/test/test_bug672810.html b/layout/forms/test/test_bug672810.html new file mode 100644 index 0000000000..991fe57389 --- /dev/null +++ b/layout/forms/test/test_bug672810.html @@ -0,0 +1,120 @@ + + + + + Test for Bug 672810 + + + + + +Mozilla Bug 672810 +

+
+ + + +
+
+
+
+ + diff --git a/layout/forms/test/test_bug704049.html b/layout/forms/test/test_bug704049.html new file mode 100644 index 0000000000..1da2badea2 --- /dev/null +++ b/layout/forms/test/test_bug704049.html @@ -0,0 +1,50 @@ + + + + + Test for Bug 704049 + + + + + +Mozilla Bug 704049 +

+ + + + +
+
+
+ + diff --git a/layout/forms/test/test_bug717878_input_scroll.html b/layout/forms/test/test_bug717878_input_scroll.html new file mode 100644 index 0000000000..6bd27ddacc --- /dev/null +++ b/layout/forms/test/test_bug717878_input_scroll.html @@ -0,0 +1,107 @@ + + + + + + Test for Bug 717878 + + + + +Mozilla Bug 717878 +

+ + + + + + + + + +
+
+
+ + diff --git a/layout/forms/test/test_bug869314.html b/layout/forms/test/test_bug869314.html new file mode 100644 index 0000000000..7c786fccfc --- /dev/null +++ b/layout/forms/test/test_bug869314.html @@ -0,0 +1,55 @@ + + + + + + Test for Bug 869314 + + + + + + + +Mozilla Bug 869314 +

+
+ + + + + + + +
+
+
+ + diff --git a/layout/forms/test/test_bug903715.html b/layout/forms/test/test_bug903715.html new file mode 100644 index 0000000000..b887b2cd01 --- /dev/null +++ b/layout/forms/test/test_bug903715.html @@ -0,0 +1,81 @@ + + + + + + Test for Bug 903715 + + + + + +Mozilla Bug 903715 +

+
+
+ + + +
+
+
+
+ + + diff --git a/layout/forms/test/test_bug935876.html b/layout/forms/test/test_bug935876.html new file mode 100644 index 0000000000..4488fdf962 --- /dev/null +++ b/layout/forms/test/test_bug935876.html @@ -0,0 +1,502 @@ + + + + + + Test for Bug 935876 + + + + + +Mozilla Bug 935876 +

+
+ + + +
+
+
+ + + diff --git a/layout/forms/test/test_bug957562.html b/layout/forms/test/test_bug957562.html new file mode 100644 index 0000000000..52821d8757 --- /dev/null +++ b/layout/forms/test/test_bug957562.html @@ -0,0 +1,43 @@ + + + + + + Test for Bug 903715 + + + + + +Mozilla Bug 957562 +

+ +
+
+ + + diff --git a/layout/forms/test/test_bug960277.html b/layout/forms/test/test_bug960277.html new file mode 100644 index 0000000000..28981b121a --- /dev/null +++ b/layout/forms/test/test_bug960277.html @@ -0,0 +1,29 @@ + + + + + + Test for Bug 903715 + + + + + +Mozilla Bug 960277 +

+
+ +
+
+
+
+
+ + + diff --git a/layout/forms/test/test_listcontrol_search.html b/layout/forms/test/test_listcontrol_search.html new file mode 100644 index 0000000000..d696edae66 --- /dev/null +++ b/layout/forms/test/test_listcontrol_search.html @@ -0,0 +1,46 @@ + + + + + + Test for <select> list control search + + + + + + +Mozilla Bug 849438 +

+
+ +
+
+
+ + diff --git a/layout/forms/test/test_readonly.html b/layout/forms/test/test_readonly.html new file mode 100644 index 0000000000..3bfb768f9c --- /dev/null +++ b/layout/forms/test/test_readonly.html @@ -0,0 +1,58 @@ + + + + +
+ + + + + + + + + + + + + +
+
+ + + + + + + + + + +
+ diff --git a/layout/forms/test/test_select_collapsed_page_keys.html b/layout/forms/test/test_select_collapsed_page_keys.html new file mode 100644 index 0000000000..08c1615152 --- /dev/null +++ b/layout/forms/test/test_select_collapsed_page_keys.html @@ -0,0 +1,43 @@ + + + + +Test for page up/down in collapsed select (bug 1488828) + + + + + + +
+ + +
+
+
+ + diff --git a/layout/forms/test/test_select_key_navigation_bug1498769.html b/layout/forms/test/test_select_key_navigation_bug1498769.html new file mode 100644 index 0000000000..3574761e66 --- /dev/null +++ b/layout/forms/test/test_select_key_navigation_bug1498769.html @@ -0,0 +1,123 @@ + + + + + +Test for Bug 1498769 + + + + + + +Mozilla Bug 1498769 +
+ + + + + + + + + + + + + +
+
+
+ + diff --git a/layout/forms/test/test_select_key_navigation_bug961363.html b/layout/forms/test/test_select_key_navigation_bug961363.html new file mode 100644 index 0000000000..7815149778 --- /dev/null +++ b/layout/forms/test/test_select_key_navigation_bug961363.html @@ -0,0 +1,131 @@ + + + + + +Test for Bug 961363 + + + + + + +Mozilla Bug 961363 +
+
    +
  • + +
  • +
  • + +
  • +
  • + +
  • +
+
+
+
+ + diff --git a/layout/forms/test/test_select_prevent_default.html b/layout/forms/test/test_select_prevent_default.html new file mode 100644 index 0000000000..4ad9db0580 --- /dev/null +++ b/layout/forms/test/test_select_prevent_default.html @@ -0,0 +1,116 @@ + + + + + +Test for Bug 291082 + + + + + + +Mozilla Bug 291082 +
+
    +
  • + + select onkeydown="event.preventDefault();" +
  • +
  • + + select onkeypress="event.preventDefault();" +
  • +
  • + + li onkeydown="event.preventDefault();" +
  • +
  • + + li onkeypress="event.preventDefault();" +
  • +
  • + + select.addEventListener("keydown", function(event) { event.preventDefault(); }); +
  • +
  • + + select.addEventListener("keypress", function(event) { event.preventDefault(); }); +
  • +
+
+
+
+ + diff --git a/layout/forms/test/test_select_reframe.html b/layout/forms/test/test_select_reframe.html new file mode 100644 index 0000000000..666d8074b8 --- /dev/null +++ b/layout/forms/test/test_select_reframe.html @@ -0,0 +1,52 @@ + + +Test for page up/down in collapsed select (bug 1488828) + + + + +
+ +
+ diff --git a/layout/forms/test/test_select_vertical.html b/layout/forms/test/test_select_vertical.html new file mode 100644 index 0000000000..51c6208bd3 --- /dev/null +++ b/layout/forms/test/test_select_vertical.html @@ -0,0 +1,75 @@ + + +Test for select popup in vertical writing mode + + + + + +Mozilla Bug 1113206 +
+ + +
diff --git a/layout/forms/test/test_textarea_resize.html b/layout/forms/test/test_textarea_resize.html new file mode 100644 index 0000000000..93889a0d17 --- /dev/null +++ b/layout/forms/test/test_textarea_resize.html @@ -0,0 +1,102 @@ + + + + Test for Bug 477700 + + + + + + + + + +
+
+
+ + diff --git a/layout/forms/test/test_unstyled_control_height.html b/layout/forms/test/test_unstyled_control_height.html new file mode 100644 index 0000000000..ad5cd125d2 --- /dev/null +++ b/layout/forms/test/test_unstyled_control_height.html @@ -0,0 +1,72 @@ + + + + + + +
+ + + + + + +
+ +
+
+ + +
+ + -- cgit v1.2.3