зеркало из https://github.com/mozilla/gecko-dev.git
Merge mozilla-central to autoland. a=merge CLOSED TREE
This commit is contained in:
Коммит
d03156f6a3
|
@ -9,7 +9,7 @@ const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
|||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
const { LocalizationHelper } = require("devtools/shared/l10n");
|
||||
|
||||
const ComputedProperty = createFactory(require("devtools/client/inspector/layout/components/ComputedProperty"));
|
||||
const ComputedProperty = createFactory(require("devtools/client/inspector/boxmodel/components/ComputedProperty"));
|
||||
|
||||
const Types = require("../types");
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
const { PureComponent } = require("devtools/client/shared/vendor/react");
|
||||
const dom = require("devtools/client/shared/vendor/react-dom-factories");
|
||||
const PropTypes = require("devtools/client/shared/vendor/react-prop-types");
|
||||
const { LocalizationHelper } = require("devtools/shared/l10n");
|
||||
|
||||
loader.lazyGetter(this, "Rep", function() {
|
||||
return require("devtools/client/shared/components/reps/reps").REPS.Rep;
|
||||
|
@ -17,6 +18,9 @@ loader.lazyGetter(this, "MODE", function() {
|
|||
|
||||
loader.lazyRequireGetter(this, "translateNodeFrontToGrip", "devtools/client/inspector/shared/utils", true);
|
||||
|
||||
const BOXMODEL_STRINGS_URI = "devtools/client/locales/boxmodel.properties";
|
||||
const BOXMODEL_L10N = new LocalizationHelper(BOXMODEL_STRINGS_URI);
|
||||
|
||||
class ComputedProperty extends PureComponent {
|
||||
static get propTypes() {
|
||||
return {
|
||||
|
@ -56,7 +60,13 @@ class ComputedProperty extends PureComponent {
|
|||
|
||||
return (
|
||||
dom.div({ className: "reference-element" },
|
||||
dom.span({ className: "reference-element-type" }, referenceElementType),
|
||||
dom.span(
|
||||
{
|
||||
className: "reference-element-type",
|
||||
title: BOXMODEL_L10N.getStr("boxmodel.offsetParent.title"),
|
||||
},
|
||||
referenceElementType
|
||||
),
|
||||
Rep({
|
||||
defaultRep: referenceElement,
|
||||
mode: MODE.TINY,
|
|
@ -10,4 +10,5 @@ DevToolsModules(
|
|||
'BoxModelInfo.js',
|
||||
'BoxModelMain.js',
|
||||
'BoxModelProperties.js',
|
||||
'ComputedProperty.js',
|
||||
)
|
||||
|
|
|
@ -7,6 +7,5 @@
|
|||
DevToolsModules(
|
||||
'Accordion.css',
|
||||
'Accordion.js',
|
||||
'ComputedProperty.js',
|
||||
'LayoutApp.js',
|
||||
)
|
||||
|
|
|
@ -29,3 +29,10 @@ boxmodel.propertiesLabel=Box Model Properties
|
|||
# position property, when position is absolute, relative, sticky. This label tells users
|
||||
# what the DOM node previewed next to it is: an offset parent for the position element.
|
||||
boxmodel.offsetParent=offset
|
||||
|
||||
# LOCALIZATION NOTE: (boxmodel.offsetParent.title) This label is displayed as a
|
||||
# tooltip that appears when hovering over the offset label, inside the list of properties,
|
||||
# below the box model, in the layout view. This label tells users
|
||||
# what the DOM node previewed next to it is: an offset parent for the position element.
|
||||
boxmodel.offsetParent.title=Offset parent of the selected element
|
||||
|
||||
|
|
|
@ -158,14 +158,24 @@ mem_test("",
|
|||
"(memory.init 1 (i32.const 0xFFFE) (i32.const 1) (i32.const 3))",
|
||||
WebAssembly.RuntimeError, /index out of bounds/);
|
||||
|
||||
// init: seg ix is valid passive, zero len, but src offset out of bounds
|
||||
// init: seg ix is valid passive, zero len, but src offset out of bounds.
|
||||
// At edge of segment is OK
|
||||
mem_test("",
|
||||
"(memory.init 1 (i32.const 1234) (i32.const 4) (i32.const 0))",
|
||||
"(memory.init 1 (i32.const 1234) (i32.const 4) (i32.const 0))");
|
||||
|
||||
// One past end of segment is not OK
|
||||
mem_test("",
|
||||
"(memory.init 1 (i32.const 1234) (i32.const 5) (i32.const 0))",
|
||||
WebAssembly.RuntimeError, /index out of bounds/);
|
||||
|
||||
// init: seg ix is valid passive, zero len, but dst offset out of bounds
|
||||
// init: seg ix is valid passive, zero len, but dst offset out of bounds.
|
||||
// At edge of memory is OK.
|
||||
mem_test("",
|
||||
"(memory.init 1 (i32.const 0x10000) (i32.const 2) (i32.const 0))",
|
||||
"(memory.init 1 (i32.const 0x10000) (i32.const 2) (i32.const 0))");
|
||||
|
||||
// One past end of memory is not OK.
|
||||
mem_test("",
|
||||
"(memory.init 1 (i32.const 0x10001) (i32.const 2) (i32.const 0))",
|
||||
WebAssembly.RuntimeError, /index out of bounds/);
|
||||
|
||||
// drop: too many args
|
||||
|
@ -256,14 +266,24 @@ tab_test("",
|
|||
"(table.init 1 (i32.const 28) (i32.const 1) (i32.const 3))",
|
||||
WebAssembly.RuntimeError, /index out of bounds/);
|
||||
|
||||
// init: seg ix is valid passive, zero len, but src offset out of bounds
|
||||
// init: seg ix is valid passive, zero len, but src offset out of bounds.
|
||||
// At edge of segment is OK.
|
||||
tab_test("",
|
||||
"(table.init 1 (i32.const 12) (i32.const 4) (i32.const 0))",
|
||||
"(table.init 1 (i32.const 12) (i32.const 4) (i32.const 0))");
|
||||
|
||||
// One past edge of segment is not OK.
|
||||
tab_test("",
|
||||
"(table.init 1 (i32.const 12) (i32.const 5) (i32.const 0))",
|
||||
WebAssembly.RuntimeError, /index out of bounds/);
|
||||
|
||||
// init: seg ix is valid passive, zero len, but dst offset out of bounds
|
||||
// init: seg ix is valid passive, zero len, but dst offset out of bounds.
|
||||
// At edge of table is OK.
|
||||
tab_test("",
|
||||
"(table.init 1 (i32.const 30) (i32.const 2) (i32.const 0))",
|
||||
"(table.init 1 (i32.const 30) (i32.const 2) (i32.const 0))");
|
||||
|
||||
// One past edge of table is not OK.
|
||||
tab_test("",
|
||||
"(table.init 1 (i32.const 31) (i32.const 2) (i32.const 0))",
|
||||
WebAssembly.RuntimeError, /index out of bounds/);
|
||||
|
||||
// drop: too many args
|
||||
|
@ -332,12 +352,22 @@ tab_test_nofail(
|
|||
"(table.copy (i32.const 15) (i32.const 25) (i32.const 0))",
|
||||
"");
|
||||
|
||||
// copy: zero length with dst offset out of bounds
|
||||
// copy: zero length with dst offset out of bounds.
|
||||
// At edge of table is OK.
|
||||
tab_test("(table.copy (i32.const 30) (i32.const 15) (i32.const 0))",
|
||||
"");
|
||||
|
||||
// One past edge of table is not OK.
|
||||
tab_test("(table.copy (i32.const 31) (i32.const 15) (i32.const 0))",
|
||||
"",
|
||||
WebAssembly.RuntimeError, /index out of bounds/);
|
||||
|
||||
// copy: zero length with src offset out of bounds
|
||||
// At edge of table is OK.
|
||||
tab_test("(table.copy (i32.const 15) (i32.const 30) (i32.const 0))",
|
||||
"");
|
||||
|
||||
// One past edge of table is not OK.
|
||||
tab_test("(table.copy (i32.const 15) (i32.const 31) (i32.const 0))",
|
||||
"",
|
||||
WebAssembly.RuntimeError, /index out of bounds/);
|
||||
|
|
|
@ -24,11 +24,11 @@ let tab_expmod_t =
|
|||
|
||||
// .. and this one imports those 5 functions. It adds 5 of its own, creates a
|
||||
// 30 element table using both active and passive initialisers, with a mixture
|
||||
// of the imported and local functions. |testfn| is exported. It uses the
|
||||
// supplied |insn| to modify the table somehow, and then will indirect-call
|
||||
// the table entry number specified as a parameter. That will either return a
|
||||
// value 0 to 9 indicating the function called, or will throw an exception if
|
||||
// the table entry is empty.
|
||||
// of the imported and local functions. |setup| and |check| are exported.
|
||||
// |setup| uses the supplied |insn| to modify the table somehow. |check| will
|
||||
// indirect-call the table entry number specified as a parameter. That will
|
||||
// either return a value 0 to 9 indicating the function called, or will throw an
|
||||
// exception if the table entry is empty.
|
||||
function gen_tab_impmod_t(insn)
|
||||
{
|
||||
let t =
|
||||
|
@ -55,8 +55,9 @@ function gen_tab_impmod_t(insn)
|
|||
(func (result i32) (i32.const 8))
|
||||
(func (result i32) (i32.const 9)) ;; index 9
|
||||
|
||||
(func (export "testfn") (param i32) (result i32)
|
||||
${insn}
|
||||
(func (export "setup")
|
||||
${insn})
|
||||
(func (export "check") (param i32) (result i32)
|
||||
;; call the selected table entry, which will either return a value,
|
||||
;; or will cause an exception.
|
||||
get_local 0 ;; callIx
|
||||
|
@ -79,18 +80,20 @@ function tab_test(instruction, expected_result_vector)
|
|||
let tab_impmod_t = gen_tab_impmod_t(instruction);
|
||||
let tab_impmod_b = wasmTextToBinary(tab_impmod_t);
|
||||
|
||||
let inst = new Instance(new Module(tab_impmod_b),
|
||||
{a:{if0:tab_expmod_i.exports.ef0,
|
||||
if1:tab_expmod_i.exports.ef1,
|
||||
if2:tab_expmod_i.exports.ef2,
|
||||
if3:tab_expmod_i.exports.ef3,
|
||||
if4:tab_expmod_i.exports.ef4
|
||||
}});
|
||||
inst.exports.setup();
|
||||
|
||||
for (let i = 0; i < expected_result_vector.length; i++) {
|
||||
let inst = new Instance(new Module(tab_impmod_b),
|
||||
{a:{if0:tab_expmod_i.exports.ef0,
|
||||
if1:tab_expmod_i.exports.ef1,
|
||||
if2:tab_expmod_i.exports.ef2,
|
||||
if3:tab_expmod_i.exports.ef3,
|
||||
if4:tab_expmod_i.exports.ef4
|
||||
}});
|
||||
let expected = expected_result_vector[i];
|
||||
let actual = undefined;
|
||||
try {
|
||||
actual = inst.exports.testfn(i);
|
||||
actual = inst.exports.check(i);
|
||||
assertEq(actual !== null, true);
|
||||
} catch (e) {
|
||||
if (!(e instanceof Error &&
|
||||
|
@ -547,7 +550,8 @@ function checkRange(arr, minIx, maxIxPlusOne, expectedValue)
|
|||
checkRange(b, 0x00000, 0x10000, 0x00);
|
||||
}
|
||||
|
||||
// Zero len with offset out-of-bounds gets an exception
|
||||
// Zero len with offset out-of-bounds is OK if it's at the edge of the
|
||||
// memory, but not if it is one past that.
|
||||
{
|
||||
let inst = wasmEvalText(
|
||||
`(module
|
||||
|
@ -557,6 +561,18 @@ function checkRange(arr, minIx, maxIxPlusOne, expectedValue)
|
|||
)
|
||||
)`
|
||||
);
|
||||
inst.exports.testfn();
|
||||
}
|
||||
|
||||
{
|
||||
let inst = wasmEvalText(
|
||||
`(module
|
||||
(memory (export "memory") 1 1)
|
||||
(func (export "testfn")
|
||||
(memory.fill (i32.const 0x10001) (i32.const 0x55) (i32.const 0))
|
||||
)
|
||||
)`
|
||||
);
|
||||
assertErrorMessage(() => inst.exports.testfn(),
|
||||
WebAssembly.RuntimeError, /index out of bounds/);
|
||||
}
|
||||
|
@ -715,7 +731,7 @@ function checkRange(arr, minIx, maxIxPlusOne, expectedValue)
|
|||
checkRange(b, 0x08000, 0x10000, 0xAA);
|
||||
}
|
||||
|
||||
// Zero len with dest offset out-of-bounds is an exception
|
||||
// Zero len with dest offset out-of-bounds but at the edge of memory is OK
|
||||
{
|
||||
let inst = wasmEvalText(
|
||||
`(module
|
||||
|
@ -725,11 +741,24 @@ function checkRange(arr, minIx, maxIxPlusOne, expectedValue)
|
|||
)
|
||||
)`
|
||||
);
|
||||
inst.exports.testfn();
|
||||
}
|
||||
|
||||
// Ditto, but one further out is not OK.
|
||||
{
|
||||
let inst = wasmEvalText(
|
||||
`(module
|
||||
(memory (export "memory") 1 1)
|
||||
(func (export "testfn")
|
||||
(memory.copy (i32.const 0x10001) (i32.const 0x7000) (i32.const 0))
|
||||
)
|
||||
)`
|
||||
);
|
||||
assertErrorMessage(() => inst.exports.testfn(),
|
||||
WebAssembly.RuntimeError, /index out of bounds/);
|
||||
}
|
||||
|
||||
// Zero len with src offset out-of-bounds is an exception
|
||||
// Zero len with src offset out-of-bounds but at the edge of memory is OK
|
||||
{
|
||||
let inst = wasmEvalText(
|
||||
`(module
|
||||
|
@ -739,6 +768,19 @@ function checkRange(arr, minIx, maxIxPlusOne, expectedValue)
|
|||
)
|
||||
)`
|
||||
);
|
||||
inst.exports.testfn();
|
||||
}
|
||||
|
||||
// Ditto, but one element further out is not OK.
|
||||
{
|
||||
let inst = wasmEvalText(
|
||||
`(module
|
||||
(memory (export "memory") 1 1)
|
||||
(func (export "testfn")
|
||||
(memory.copy (i32.const 0x9000) (i32.const 0x10001) (i32.const 0))
|
||||
)
|
||||
)`
|
||||
);
|
||||
assertErrorMessage(() => inst.exports.testfn(),
|
||||
WebAssembly.RuntimeError, /index out of bounds/);
|
||||
}
|
||||
|
|
|
@ -427,8 +427,9 @@ Instance::memCopy(Instance* instance, uint32_t dstByteOffset,
|
|||
uint32_t memLen = mem->volatileMemoryLength();
|
||||
|
||||
if (len == 0) {
|
||||
// Even though the length is zero, we must check for a valid offset.
|
||||
if (dstByteOffset < memLen && srcByteOffset < memLen) {
|
||||
// Even though the length is zero, we must check for a valid offset. But
|
||||
// zero-length operations at the edge of the memory are allowed.
|
||||
if (dstByteOffset <= memLen && srcByteOffset <= memLen) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
|
@ -513,8 +514,9 @@ Instance::memFill(Instance* instance, uint32_t byteOffset, uint32_t value,
|
|||
uint32_t memLen = mem->volatileMemoryLength();
|
||||
|
||||
if (len == 0) {
|
||||
// Even though the length is zero, we must check for a valid offset.
|
||||
if (byteOffset < memLen) {
|
||||
// Even though the length is zero, we must check for a valid offset. But
|
||||
// zero-length operations at the edge of the memory are allowed.
|
||||
if (byteOffset <= memLen) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
|
@ -585,8 +587,10 @@ Instance::memInit(Instance* instance, uint32_t dstOffset, uint32_t srcOffset,
|
|||
// memoryBase[ dstOffset .. dstOffset + len - 1 ]
|
||||
|
||||
if (len == 0) {
|
||||
// Even though the length is zero, we must check for valid offsets.
|
||||
if (dstOffset < memLen && srcOffset < segLen) {
|
||||
// Even though the length is zero, we must check for valid offsets. But
|
||||
// zero-length operations at the edge of the memory or the segment are
|
||||
// allowed.
|
||||
if (dstOffset <= memLen && srcOffset <= segLen) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
|
@ -645,9 +649,10 @@ Instance::tableCopy(Instance* instance, uint32_t dstOffset, uint32_t srcOffset,
|
|||
uint32_t dstTableLen = dstTable->length();
|
||||
|
||||
if (len == 0) {
|
||||
// Even though the number of items to copy is zero, we must check
|
||||
// for valid offsets.
|
||||
if (dstOffset < dstTableLen && srcOffset < srcTableLen) {
|
||||
// Even though the number of items to copy is zero, we must check for valid
|
||||
// offsets. But zero-length operations at the edge of the table are
|
||||
// allowed.
|
||||
if (dstOffset <= dstTableLen && srcOffset <= srcTableLen) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
|
@ -809,8 +814,9 @@ Instance::tableInit(Instance* instance, uint32_t dstOffset, uint32_t srcOffset,
|
|||
// tableBase[ dstOffset .. dstOffset + len - 1 ]
|
||||
|
||||
if (len == 0) {
|
||||
// Even though the length is zero, we must check for valid offsets.
|
||||
if (dstOffset < tableLen && srcOffset < segLen) {
|
||||
// Even though the length is zero, we must check for valid offsets. But
|
||||
// zero-length operations at the edge of the table or segment are allowed.
|
||||
if (dstOffset <= tableLen && srcOffset <= segLen) {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -1268,6 +1268,13 @@ nsMenuFrame::SetActiveChild(dom::Element* aChild) {
|
|||
nsMenuPopupFrame* popupFrame = GetPopup();
|
||||
if (!popupFrame) return NS_ERROR_FAILURE;
|
||||
|
||||
// Force the child frames within the popup to be generated.
|
||||
AutoWeakFrame weakFrame(popupFrame);
|
||||
popupFrame->GenerateFrames();
|
||||
if (!weakFrame.IsAlive()) {
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
if (!aChild) {
|
||||
// Remove the current selection
|
||||
popupFrame->ChangeMenuItem(nullptr, false, false);
|
||||
|
|
|
@ -1612,6 +1612,18 @@ nsresult nsMenuPopupFrame::SetPopupPosition(nsIFrame* aAnchorFrame,
|
|||
return NS_OK;
|
||||
}
|
||||
|
||||
void nsMenuPopupFrame::GenerateFrames()
|
||||
{
|
||||
const bool generateFrames = IsLeaf();
|
||||
MOZ_ASSERT_IF(generateFrames, !mGeneratedChildren);
|
||||
mGeneratedChildren = true;
|
||||
if (generateFrames) {
|
||||
MOZ_ASSERT(PrincipalChildList().IsEmpty());
|
||||
nsCOMPtr<nsIPresShell> presShell = PresContext()->PresShell();
|
||||
presShell->FrameConstructor()->GenerateChildFrames(this);
|
||||
}
|
||||
}
|
||||
|
||||
/* virtual */
|
||||
nsMenuFrame* nsMenuPopupFrame::GetCurrentMenuItem() { return mCurrentMenu; }
|
||||
|
||||
|
|
|
@ -266,8 +266,8 @@ class nsMenuPopupFrame final : public nsBoxFrame,
|
|||
nsresult SetPopupPosition(nsIFrame* aAnchorFrame, bool aIsMove,
|
||||
bool aSizedToPopup, bool aNotify);
|
||||
|
||||
bool HasGeneratedChildren() { return mGeneratedChildren; }
|
||||
void SetGeneratedChildren() { mGeneratedChildren = true; }
|
||||
// Force the children to be generated if they have not already been generated.
|
||||
void GenerateFrames();
|
||||
|
||||
// called when the Enter key is pressed while the popup is open. This will
|
||||
// just pass the call down to the current menu, if any. If a current menu
|
||||
|
|
|
@ -1279,26 +1279,19 @@ void nsXULPopupManager::FirePopupShowingEvent(nsIContent* aPopup,
|
|||
nsMenuPopupFrame* popupFrame = do_QueryFrame(aPopup->GetPrimaryFrame());
|
||||
if (!popupFrame) return;
|
||||
|
||||
nsPresContext* presContext = popupFrame->PresContext();
|
||||
nsCOMPtr<nsIPresShell> presShell = presContext->PresShell();
|
||||
nsPopupType popupType = popupFrame->PopupType();
|
||||
|
||||
// generate the child frames if they have not already been generated
|
||||
const bool generateFrames = popupFrame->IsLeaf();
|
||||
MOZ_ASSERT_IF(generateFrames, !popupFrame->HasGeneratedChildren());
|
||||
popupFrame->SetGeneratedChildren();
|
||||
if (generateFrames) {
|
||||
MOZ_ASSERT(popupFrame->PrincipalChildList().IsEmpty());
|
||||
presShell->FrameConstructor()->GenerateChildFrames(popupFrame);
|
||||
}
|
||||
popupFrame->GenerateFrames();
|
||||
|
||||
// get the frame again
|
||||
nsIFrame* frame = aPopup->GetPrimaryFrame();
|
||||
if (!frame) return;
|
||||
popupFrame = do_QueryFrame(aPopup->GetPrimaryFrame());
|
||||
if (!popupFrame) return;
|
||||
|
||||
presShell->FrameNeedsReflow(frame, nsIPresShell::eTreeChange,
|
||||
nsPresContext* presContext = popupFrame->PresContext();
|
||||
nsCOMPtr<nsIPresShell> presShell = presContext->PresShell();
|
||||
presShell->FrameNeedsReflow(popupFrame, nsIPresShell::eTreeChange,
|
||||
NS_FRAME_HAS_DIRTY_CHILDREN);
|
||||
|
||||
nsPopupType popupType = popupFrame->PopupType();
|
||||
|
||||
// cache the popup so that document.popupNode can retrieve the trigger node
|
||||
// during the popupshowing event. It will be cleared below after the event
|
||||
// has fired.
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
Self-serving an ARM build
|
||||
=========================
|
||||
|
||||
Mozilla [announced the intent] to deprecate ARMv7 HF builds of
|
||||
geckodriver in September 2018. This does not mean you can no longer
|
||||
use geckodriver on ARM systems, and this document explains how you
|
||||
can self-service a build for ARMv7 HF.
|
||||
|
||||
Assuming you have already checked out [central], the steps to
|
||||
cross-compile ARMv7 from a Linux host system is as follows:
|
||||
|
||||
1. If you don’t have Rust installed:
|
||||
|
||||
# curl https://sh.rustup.rs -sSf | sh
|
||||
|
||||
2. Install cross-compiler toolchain:
|
||||
|
||||
# apt install gcc-arm-linux-gnueabihf libc6-armhf-cross libc6-dev-armhf-cross
|
||||
|
||||
3. Createa a new shell, or to reuse the existing shell:
|
||||
|
||||
source $HOME/.cargo/env
|
||||
|
||||
4. Install rustc target toolchain:
|
||||
|
||||
% rustup target install armv7-unknown-linux-gnueabihf
|
||||
|
||||
5. Put this in testing/geckodriver/.cargo/config:
|
||||
|
||||
[target.armv7-unknown-linux-gnueabihf]
|
||||
linker = "arm-linux-gnueabihf-gcc"
|
||||
|
||||
6. Build geckodriver from testing/geckodriver:
|
||||
|
||||
% cd testing/geckodriver
|
||||
% cargo build --release --target armv7-unknown-linux-gnueabihf
|
||||
|
||||
[announce the intent]: https://lists.mozilla.org/pipermail/tools-marionette/2018-September/000035.html
|
||||
[central]: https://hg.mozilla.org/mozilla-central/
|
|
@ -42,6 +42,7 @@ For developers
|
|||
Building.md
|
||||
Testing.md
|
||||
Releasing.md
|
||||
ARM.md
|
||||
|
||||
|
||||
Communication
|
||||
|
|
|
@ -27,6 +27,14 @@
|
|||
<menuitem id="b4" label="Four"/>
|
||||
</menupopup>
|
||||
</menulist>
|
||||
<menulist id="list3" sizetopopup="none">
|
||||
<menupopup>
|
||||
<menuitem id="s1" label="One"/>
|
||||
<menuitem id="s2" label="Two"/>
|
||||
<menuitem id="s3" label="Three"/>
|
||||
<menuitem id="s4" label="Four"/>
|
||||
</menupopup>
|
||||
</menulist>
|
||||
|
||||
<script class="testbody" type="application/javascript">
|
||||
<![CDATA[
|
||||
|
@ -275,6 +283,16 @@ function checkCursorNavigation()
|
|||
list.open = false;
|
||||
}
|
||||
|
||||
// Finally, test a menulist with sizetopopup="none" to ensure keyboard navigation
|
||||
// still works when the popup has not been opened.
|
||||
if (!ismac) {
|
||||
let unsizedMenulist = document.getElementById("list3");
|
||||
unsizedMenulist.focus();
|
||||
synthesizeKey("KEY_ArrowDown");
|
||||
is(unsizedMenulist.selectedIndex, 1, "correct menulist index on keydown");
|
||||
is(unsizedMenulist.label, "Two", "correct menulist label on keydown");
|
||||
}
|
||||
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче