Bug 921504 - implement HTML:inert r=emilio,heycam

Differential Revision: https://phabricator.services.mozilla.com/D81701
This commit is contained in:
Alexander Surkov 2020-07-22 04:26:08 +00:00
Родитель 0cae4293b6
Коммит 1c382cad65
25 изменённых файлов: 113 добавлений и 23 удалений

Просмотреть файл

@ -87,6 +87,7 @@ exports.ANIMATION_TYPE_FOR_LONGHANDS = [
"image-orientation",
"image-rendering",
"ime-mode",
"-moz-inert",
"initial-letter",
"isolation",
"justify-content",

Просмотреть файл

@ -294,6 +294,8 @@ class EventStates {
#define NS_EVENT_STATE_FOCUS_VISIBLE NS_DEFINE_EVENT_STATE_MACRO(52)
// Modal <dialog> element
#define NS_EVENT_STATE_MODAL_DIALOG NS_DEFINE_EVENT_STATE_MACRO(53)
// Inert subtrees
#define NS_EVENT_STATE_MOZINERT NS_DEFINE_EVENT_STATE_MACRO(54)
/**
* NOTE: do not go over 63 without updating EventStates::InternalType!
@ -329,7 +331,8 @@ class EventStates {
NS_EVENT_STATE_DRAGOVER | NS_EVENT_STATE_FOCUS | NS_EVENT_STATE_FOCUSRING | \
NS_EVENT_STATE_FOCUS_WITHIN | NS_EVENT_STATE_FULLSCREEN | \
NS_EVENT_STATE_HOVER | NS_EVENT_STATE_URLTARGET | \
NS_EVENT_STATE_FOCUS_VISIBLE | NS_EVENT_STATE_MODAL_DIALOG)
NS_EVENT_STATE_FOCUS_VISIBLE | NS_EVENT_STATE_MODAL_DIALOG | \
NS_EVENT_STATE_MOZINERT)
#define INTRINSIC_STATES (~EXTERNALLY_MANAGED_STATES)

Просмотреть файл

@ -16,6 +16,7 @@
#include "mozilla/MouseEvents.h"
#include "mozilla/PresShell.h"
#include "mozilla/TextEditor.h"
#include "mozilla/StaticPrefs_html5.h"
#include "mozilla/StaticPrefs_layout.h"
#include "nscore.h"
@ -687,6 +688,13 @@ nsresult nsGenericHTMLElement::AfterSetAttr(
SetFlags(NODE_HAS_ACCESSKEY);
RegAccessKey();
}
} else if (aName == nsGkAtoms::inert &&
StaticPrefs::html5_inert_enabled()) {
if (aValue) {
AddStates(NS_EVENT_STATE_MOZINERT);
} else {
RemoveStates(NS_EVENT_STATE_MOZINERT);
}
} else if (aName == nsGkAtoms::name) {
if (aValue && !aValue->Equals(EmptyString(), eIgnoreCase)) {
// This may not be quite right because we can have subclass code run

Просмотреть файл

@ -9743,7 +9743,8 @@ bool nsIFrame::IsFocusable(int32_t* aTabIndex, bool aWithMouse) {
if (mContent && mContent->IsElement() && IsVisibleConsideringAncestors() &&
Style()->GetPseudoType() != PseudoStyleType::anonymousFlexItem &&
Style()->GetPseudoType() != PseudoStyleType::anonymousGridItem) {
Style()->GetPseudoType() != PseudoStyleType::anonymousGridItem &&
StyleUI()->mInert != StyleInert::Inert) {
const nsStyleUI* ui = StyleUI();
if (ui->mUserFocus != StyleUserFocus::Ignore &&
ui->mUserFocus != StyleUserFocus::None) {

Просмотреть файл

@ -97,6 +97,7 @@ rusty-enums = [
"mozilla::StyleFloat",
"mozilla::StyleImageOrientation",
"mozilla::StyleImageRendering",
"mozilla::StyleInert",
"mozilla::StyleUserModify",
"mozilla::StyleUserInput",
"mozilla::StyleBoxDirection",

Просмотреть файл

@ -286,6 +286,12 @@ enum class StyleUserModify : uint8_t {
WriteOnly,
};
// -moz-inert
enum class StyleInert : uint8_t {
None,
Inert,
};
// -moz-window-dragging
enum class StyleWindowDragging : uint8_t {
Default,

Просмотреть файл

@ -3107,7 +3107,8 @@ LogicalSide nsStyleText::TextEmphasisSide(WritingMode aWM) const {
//
nsStyleUI::nsStyleUI(const Document& aDocument)
: mUserInput(StyleUserInput::Auto),
: mInert(StyleInert::None),
mUserInput(StyleUserInput::Auto),
mUserModify(StyleUserModify::ReadOnly),
mUserFocus(StyleUserFocus::None),
mPointerEvents(StylePointerEvents::Auto),
@ -3118,7 +3119,8 @@ nsStyleUI::nsStyleUI(const Document& aDocument)
}
nsStyleUI::nsStyleUI(const nsStyleUI& aSource)
: mUserInput(aSource.mUserInput),
: mInert(aSource.mInert),
mUserInput(aSource.mUserInput),
mUserModify(aSource.mUserModify),
mUserFocus(aSource.mUserFocus),
mPointerEvents(aSource.mPointerEvents),
@ -3179,7 +3181,7 @@ nsChangeHint nsStyleUI::CalcDifference(const nsStyleUI& aNewData) const {
}
}
if (mUserFocus != aNewData.mUserFocus) {
if (mUserFocus != aNewData.mUserFocus || mInert != aNewData.mInert) {
hint |= nsChangeHint_NeutralChange;
}

Просмотреть файл

@ -1730,6 +1730,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleUI {
nsChangeHint CalcDifference(const nsStyleUI& aNewData) const;
mozilla::StyleInert mInert;
mozilla::StyleUserInput mUserInput;
mozilla::StyleUserModify mUserModify; // (modify-content)
mozilla::StyleUserFocus mUserFocus; // (auto-select)

Просмотреть файл

@ -153,6 +153,11 @@
outline: 1px dotted;
}
/* Inert subtrees */
*|*:-moz-inert {
-moz-inert: inert;
}
/* Miscellaneous */
*|*::-moz-cell-content {

Просмотреть файл

@ -94,6 +94,7 @@ const char* gInaccessibleProperties[] = {
"-moz-context-properties",
"-moz-control-character-visibility",
"-moz-default-appearance",
"-moz-inert",
"-moz-list-reversed", // parsed by UA sheets only
"-moz-script-level", // parsed by UA sheets only
"-moz-script-size-multiplier",

Просмотреть файл

@ -23,6 +23,7 @@ const NON_CONTENT_ACCESSIBLE_PROPERTIES = [
"-moz-min-font-size-ratio",
"-moz-script-size-multiplier",
"-moz-default-appearance",
"-moz-inert",
// TODO(emilio): Whenever we stop using `-moz-binding` in a gazillion tests
// we should add it here.
];

Просмотреть файл

@ -1137,6 +1137,7 @@ function runTests() {
test_unbalanced_unparseable(":-moz-handler-crashed");
// We're not in a UA sheet, so this should be invalid.
test_balanced_unparseable(":-moz-inert");
test_balanced_unparseable(":-moz-native-anonymous");
test_balanced_unparseable(":-moz-table-border-nonzero");

Просмотреть файл

@ -4566,6 +4566,12 @@
# Prefs starting with "html5."
#---------------------------------------------------------------------------
# Turn HTML:inert on or off.
- name: html5.inert.enabled
type: bool
value: false
mirror: always
# Toggle which thread the HTML5 parser uses for stream parsing.
- name: html5.offmainthread
type: bool

Просмотреть файл

@ -145,6 +145,9 @@ bitflags! {
///
/// https://html.spec.whatwg.org/multipage/#centered-alignment
const IN_MODAL_DIALOG_STATE = 1 << 53;
/// https://html.spec.whatwg.org/multipage/interaction.html#inert-subtrees
const IN_MOZINERT_STATE = 1 << 54;
}
}

Просмотреть файл

@ -48,6 +48,7 @@ macro_rules! apply_non_ts_list {
("-moz-drag-over", MozDragOver, IN_DRAGOVER_STATE, _),
("target", Target, IN_TARGET_STATE, _),
("indeterminate", Indeterminate, IN_INDETERMINATE_STATE, _),
("-moz-inert", MozInert, IN_MOZINERT_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS),
("-moz-devtools-highlighted", MozDevtoolsHighlighted, IN_DEVTOOLS_HIGHLIGHTED_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS),
("-moz-styleeditor-transitioning", MozStyleeditorTransitioning, IN_STYLEEDITOR_TRANSITIONING_STATE, PSEUDO_CLASS_ENABLED_IN_UA_SHEETS),
("fullscreen", Fullscreen, IN_FULLSCREEN_STATE, _),

Просмотреть файл

@ -2016,6 +2016,7 @@ impl<'le> ::selectors::Element for GeckoElement<'le> {
NonTSPseudoClass::Checked |
NonTSPseudoClass::Fullscreen |
NonTSPseudoClass::Indeterminate |
NonTSPseudoClass::MozInert |
NonTSPseudoClass::PlaceholderShown |
NonTSPseudoClass::Target |
NonTSPseudoClass::Valid |

Просмотреть файл

@ -29,6 +29,17 @@ ${helpers.single_keyword(
gecko_enum_prefix="StylePointerEvents",
)}
${helpers.single_keyword(
"-moz-inert",
"none inert",
engines="gecko",
gecko_ffi_name="mInert",
gecko_enum_prefix="StyleInert",
animation_value_type="discrete",
enabled_in="ua",
spec="Nonstandard (https://html.spec.whatwg.org/multipage/interaction.html#inert-subtrees)",
)}
${helpers.single_keyword(
"-moz-user-input",
"auto none",

Просмотреть файл

@ -347,6 +347,7 @@ impl ToCss for NonTSPseudoClass {
Fullscreen => ":fullscreen",
Hover => ":hover",
Indeterminate => ":indeterminate",
MozInert => ":-moz-inert",
Link => ":link",
PlaceholderShown => ":placeholder-shown",
ReadWrite => ":read-write",
@ -436,6 +437,7 @@ impl<'a, 'i> ::selectors::Parser<'i> for SelectorParser<'a> {
"fullscreen" => Fullscreen,
"hover" => Hover,
"indeterminate" => Indeterminate,
"-moz-inert" => MozInert,
"link" => Link,
"placeholder-shown" => PlaceholderShown,
"read-write" => ReadWrite,

Просмотреть файл

@ -153,6 +153,56 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
}
}
/// https://html.spec.whatwg.org/multipage/interaction.html#inert-subtrees
///
/// If -moz-inert is applied then add:
/// -moz-user-focus: none;
/// -moz-user-input: none;
/// -moz-user-modify: read-only;
/// user-select: none;
/// pointer-events: none;
/// cursor: default;
fn adjust_for_inert(&mut self) {
use properties::longhands::_moz_inert::computed_value::T as Inert;
use properties::longhands::_moz_user_focus::computed_value::T as UserFocus;
use properties::longhands::_moz_user_input::computed_value::T as UserInput;
use properties::longhands::_moz_user_modify::computed_value::T as UserModify;
use properties::longhands::pointer_events::computed_value::T as PointerEvents;
use properties::longhands::cursor::computed_value::T as Cursor;
use crate::values::specified::ui::CursorKind;
use crate::values::specified::ui::UserSelect;
let needs_update = {
let ui = self.style.get_inherited_ui();
if ui.clone__moz_inert() == Inert::None {
return;
}
ui.clone__moz_user_focus() != UserFocus::None ||
ui.clone__moz_user_input() != UserInput::None ||
ui.clone__moz_user_modify() != UserModify::ReadOnly ||
ui.clone_pointer_events() != PointerEvents::None ||
ui.clone_cursor().keyword != CursorKind::Default ||
ui.clone_cursor().images != Default::default()
};
if needs_update {
let ui = self.style.mutate_inherited_ui();
ui.set__moz_user_focus(UserFocus::None);
ui.set__moz_user_input(UserInput::None);
ui.set__moz_user_modify(UserModify::ReadOnly);
ui.set_pointer_events(PointerEvents::None);
ui.set_cursor(Cursor {
images: Default::default(),
keyword: CursorKind::Default,
});
}
if self.style.get_ui().clone_user_select() != UserSelect::None {
self.style.mutate_ui().set_user_select(UserSelect::None);
}
}
/// Whether we should skip any item-based display property blockification on
/// this element.
fn skip_item_display_fixup<E>(&self, element: Option<E>) -> bool
@ -855,6 +905,7 @@ impl<'a, 'b: 'a> StyleAdjuster<'a, 'b> {
#[cfg(feature = "gecko")]
{
self.adjust_for_appearance(element);
self.adjust_for_inert();
}
self.set_bits();
}

Просмотреть файл

@ -0,0 +1 @@
prefs: [html5.inert.enabled:true]

Просмотреть файл

@ -1,4 +0,0 @@
[inert-in-shadow-dom.tentative.html]
[inert on Shadow host affects content in shadow]
expected: FAIL

Просмотреть файл

@ -1,4 +0,0 @@
[inert-inlines.tentative.html]
[Tests that inert inlines do not receive mouse events. To test manually, click on all the "Click me"s. The test fails if you see red.]
expected: FAIL

Просмотреть файл

@ -1,4 +0,0 @@
[inert-label-focus.tentative.html]
[Calling focus() on a label for a control which is in an inert subtree should have no effect.]
expected: FAIL

Просмотреть файл

@ -5,12 +5,6 @@
[Elements inside of inert subtrees return false when getting 'inert']
expected: FAIL
[Button with inert atribute is unfocusable.]
expected: FAIL
[All focusable elements inside inert subtree are unfocusable]
expected: FAIL
[Can get inert via property]
expected: FAIL

Просмотреть файл

@ -531,6 +531,7 @@ STATIC_ATOMS = [
Atom("indent", "indent"),
Atom("indeterminate", "indeterminate"),
Atom("index", "index"),
Atom("inert", "inert"),
Atom("infinity", "infinity"),
Atom("inherits", "inherits"),
Atom("inheritOverflow", "inherit-overflow"),