diff --git a/devtools/server/actors/styles.js b/devtools/server/actors/styles.js index ebdf3c219b92..0c40ead18ec8 100644 --- a/devtools/server/actors/styles.js +++ b/devtools/server/actors/styles.js @@ -748,6 +748,8 @@ var PageStyleActor = protocol.ActorClassWithSpec(pageStyleSpec, { return true; case ":cue": return node.nodeName == "VIDEO"; + case ":file-chooser-button": + return node.nodeName == "INPUT" && node.type == "file"; case ":placeholder": case ":-moz-placeholder": return this._nodeIsTextfieldLike(node); diff --git a/devtools/shared/css/generated/properties-db.js b/devtools/shared/css/generated/properties-db.js index 255da39c66cc..71862f4ca9c9 100644 --- a/devtools/shared/css/generated/properties-db.js +++ b/devtools/shared/css/generated/properties-db.js @@ -10692,7 +10692,8 @@ exports.PSEUDO_ELEMENTS = [ ":-moz-range-thumb", ":-moz-meter-bar", ":placeholder", - ":-moz-color-swatch" + ":-moz-color-swatch", + ":file-chooser-button" ]; /** diff --git a/layout/forms/nsFileControlFrame.cpp b/layout/forms/nsFileControlFrame.cpp index 114c4a713961..e251ed03ad88 100644 --- a/layout/forms/nsFileControlFrame.cpp +++ b/layout/forms/nsFileControlFrame.cpp @@ -212,6 +212,7 @@ static already_AddRefed MakeAnonButton(Document* aDoc, // NOTE: SetIsNativeAnonymousRoot() has to be called before setting any // attribute. button->SetIsNativeAnonymousRoot(); + button->SetPseudoElementType(PseudoStyleType::fileChooserButton); // Set the file picking button text depending on the current locale. nsAutoString buttonTxt; diff --git a/layout/inspector/tests/test_getCSSPseudoElementNames.html b/layout/inspector/tests/test_getCSSPseudoElementNames.html index 684b9895300f..ba06850f2d64 100644 --- a/layout/inspector/tests/test_getCSSPseudoElementNames.html +++ b/layout/inspector/tests/test_getCSSPseudoElementNames.html @@ -15,6 +15,7 @@ ":marker", ":backdrop", ":cue", + ":file-chooser-button", ":first-letter", ":first-line", ":placeholder", diff --git a/layout/style/nsCSSPseudoElementList.h b/layout/style/nsCSSPseudoElementList.h index f614f4b8361d..4a51547eb129 100644 --- a/layout/style/nsCSSPseudoElementList.h +++ b/layout/style/nsCSSPseudoElementList.h @@ -97,3 +97,7 @@ CSS_PSEUDO_ELEMENT(mozTextControlEditingRoot, ":-moz-text-control-editing-root", // The element that shows the autofill value. CSS_PSEUDO_ELEMENT(mozTextControlPreview, ":-moz-text-control-preview", CSS_PSEUDO_ELEMENT_ENABLED_IN_UA_SHEETS) + +CSS_PSEUDO_ELEMENT(fileChooserButton, ":file-chooser-button", + CSS_PSEUDO_ELEMENT_ENABLED_IN_UA_SHEETS | + CSS_PSEUDO_ELEMENT_SUPPORTS_USER_ACTION_STATE) diff --git a/layout/style/nsCSSPseudoElements.h b/layout/style/nsCSSPseudoElements.h index 866dc7c1cc46..21ca5a3e996e 100644 --- a/layout/style/nsCSSPseudoElements.h +++ b/layout/style/nsCSSPseudoElements.h @@ -118,12 +118,20 @@ class nsCSSPseudoElements { CSS_PSEUDO_ELEMENT_IS_FLEX_OR_GRID_ITEM); } - static bool IsEnabled(Type aType, EnabledState aEnabledState) { - if (!PseudoElementHasAnyFlag( - aType, CSS_PSEUDO_ELEMENT_ENABLED_IN_UA_SHEETS_AND_CHROME)) { - if (aType == Type::mozFocusOuter) { + static bool EnabledInContent(Type aType) { + switch (aType) { + case Type::mozFocusOuter: return mozilla::StaticPrefs::layout_css_moz_focus_outer_enabled(); - } + case Type::fileChooserButton: + return mozilla::StaticPrefs::layout_css_file_chooser_button_enabled(); + default: + return !PseudoElementHasAnyFlag( + aType, CSS_PSEUDO_ELEMENT_ENABLED_IN_UA_SHEETS_AND_CHROME); + } + } + + static bool IsEnabled(Type aType, EnabledState aEnabledState) { + if (EnabledInContent(aType)) { return true; } diff --git a/layout/style/res/forms.css b/layout/style/res/forms.css index 3da22262cb25..17d67bc8632f 100644 --- a/layout/style/res/forms.css +++ b/layout/style/res/forms.css @@ -124,7 +124,7 @@ textarea { } /* A few properties that we don't want to inherit by default: */ -input, textarea, select, button { +input, textarea, select, button, ::file-chooser-button { text-align: initial; text-indent: initial; text-shadow: initial; @@ -461,44 +461,6 @@ input[type="image"]:disabled { cursor: unset; } - -/* file selector */ -input[type="file"] { - white-space: nowrap !important; - overflow: hidden !important; - overflow-clip-box: padding-box; - color: unset; - - /* Revert rules which apply on all inputs. */ - -moz-appearance: none; - cursor: default; - - border: none; - background-color: transparent; - padding: unset; -} - -input[type="file"] > label { - display: inline-block; - min-inline-size: 12em; - padding-inline-start: 5px; - text-align: match-parent; - - color: unset; - font-size: unset; - letter-spacing: unset; - - user-select: none; - unicode-bidi: plaintext; -} - -/* button part of file selector */ -input[type="file"] > button { - font-size: unset; - letter-spacing: unset; - cursor: unset; -} - /* colored part of the color selector button */ ::-moz-color-swatch { width: 100%; @@ -564,6 +526,7 @@ input[type="search"] { /* Non text-related properties for buttons: these ones are shared with input[type="color"] */ button, +::file-chooser-button, input:is([type="color"], [type="reset"], [type="button"], [type="submit"]) { -moz-appearance: button; /* The sum of border and padding on block-start and block-end @@ -581,6 +544,7 @@ input:is([type="color"], [type="reset"], [type="button"], [type="submit"]) { /* Text-related properties for buttons: these ones are not shared with input[type="color"] */ button, +::file-chooser-button, input:is([type="reset"], [type="button"], [type="submit"]) { color: ButtonText; font: -moz-button; @@ -594,7 +558,8 @@ input[type="color"] { block-size: 23px; } -button { +button, +::file-chooser-button { /* Buttons should lay out like "normal" html, mostly */ white-space: unset; text-indent: 0; @@ -636,16 +601,19 @@ button { justify-items: inherit; } +::file-chooser-button:hover, button:hover, input:is([type="reset"], [type="button"], [type="submit"], [type="color"]):hover { background-color: -moz-buttonhoverface; } +::file-chooser-button:hover, button:hover, input:is([type="reset"], [type="button"], [type="submit"]):hover { color: -moz-buttonhovertext; } +::file-chooser-button:active:hover, button:active:hover, input:is([type="reset"], [type="button"], [type="submit"], [type="color"]):active:hover { %ifndef XP_MACOSX @@ -656,6 +624,7 @@ input:is([type="reset"], [type="button"], [type="submit"], [type="color"]):activ background-color: ButtonFace; } +::file-chooser-button:active:hover, button:active:hover, input:is([type="reset"], [type="button"], [type="submit"]):active:hover { %ifdef MOZ_WIDGET_GTK @@ -676,6 +645,7 @@ input:is([type="reset"], [type="button"], [type="submit"]):active:hover { border-color: currentColor; } +:is(:disabled, :disabled:active)::file-chooser-button, button:is(:disabled, :disabled:active), input:is([type="reset"], [type="button"], [type="submit"], [type="color"]):is(:disabled, :disabled:active), select:is(:disabled, :disabled:active) > button { @@ -687,12 +657,50 @@ select:is(:disabled, :disabled:active) > button { cursor: unset; } +:is(:disabled, :disabled:active)::file-chooser-button, button:is(:disabled, :disabled:active), input:is([type="reset"], [type="button"], [type="submit"]):is(:disabled, :disabled:active), select:is(:disabled, :disabled:active) > button { color: GrayText; } +/* file selector */ +input[type="file"] { + white-space: nowrap !important; + overflow: hidden !important; + overflow-clip-box: padding-box; + color: unset; + + /* Revert rules which apply on all inputs. */ + -moz-appearance: none; + cursor: default; + + border: none; + background-color: transparent; + padding: unset; +} + +input[type="file"] > label { + display: inline-block; + min-inline-size: 12em; + padding-inline-start: 5px; + text-align: match-parent; + + color: unset; + font-size: unset; + letter-spacing: unset; + + user-select: none; + unicode-bidi: plaintext; +} + +/* button part of file selector */ +::file-chooser-button { + font-size: unset; + letter-spacing: unset; + cursor: unset; +} + /* * Make form controls inherit 'unicode-bidi' transparently as required by * their various anonymous descendants and pseudo-elements: diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml index 5130ccf0dcdd..5af128dd8044 100644 --- a/modules/libpref/init/StaticPrefList.yaml +++ b/modules/libpref/init/StaticPrefList.yaml @@ -6218,6 +6218,13 @@ mirror: always rust: true +# Is support for the ::file-chooser-button pseudo-element enabled? +- name: layout.css.file-chooser-button.enabled + type: RelaxedAtomicBool + value: @IS_NIGHTLY_OR_DEV_EDITION@ + mirror: always + rust: true + # Whether the computed value of line-height: normal returns the `normal` # keyword rather than a pixel value based on the first available font. # diff --git a/servo/components/style/gecko/pseudo_element.rs b/servo/components/style/gecko/pseudo_element.rs index b537295f785f..631172d9511c 100644 --- a/servo/components/style/gecko/pseudo_element.rs +++ b/servo/components/style/gecko/pseudo_element.rs @@ -37,7 +37,8 @@ impl ::selectors::parser::PseudoElement for PseudoElement { PseudoElement::Before | PseudoElement::After | PseudoElement::Marker | - PseudoElement::Placeholder + PseudoElement::Placeholder | + PseudoElement::FileChooserButton ) } @@ -159,12 +160,12 @@ impl PseudoElement { /// Whether this pseudo-element is enabled for all content. pub fn enabled_in_content(&self) -> bool { - if (self.flags() & structs::CSS_PSEUDO_ELEMENT_ENABLED_IN_UA_SHEETS_AND_CHROME) != 0 { - return false; - } match *self { PseudoElement::MozFocusOuter => static_prefs::pref!("layout.css.moz-focus-outer.enabled"), - _ => true, + PseudoElement::FileChooserButton => static_prefs::pref!("layout.css.file-chooser-button.enabled"), + _ => { + (self.flags() & structs::CSS_PSEUDO_ELEMENT_ENABLED_IN_UA_SHEETS_AND_CHROME) == 0 + } } } diff --git a/testing/web-platform/tests/css/css-pseudo/file-chooser-button-001-notref.html b/testing/web-platform/tests/css/css-pseudo/file-chooser-button-001-notref.html new file mode 100644 index 000000000000..e137ba05103d --- /dev/null +++ b/testing/web-platform/tests/css/css-pseudo/file-chooser-button-001-notref.html @@ -0,0 +1,3 @@ + +CSS Test Reference + diff --git a/testing/web-platform/tests/css/css-pseudo/file-chooser-button-001.tentative.html b/testing/web-platform/tests/css/css-pseudo/file-chooser-button-001.tentative.html new file mode 100644 index 000000000000..e08bb8b1055c --- /dev/null +++ b/testing/web-platform/tests/css/css-pseudo/file-chooser-button-001.tentative.html @@ -0,0 +1,10 @@ + +::file-chooser-button allows to customize the button in <input type=file> + + + diff --git a/xpcom/ds/StaticAtoms.py b/xpcom/ds/StaticAtoms.py index 126bc4e48593..34f5f32a7b52 100644 --- a/xpcom/ds/StaticAtoms.py +++ b/xpcom/ds/StaticAtoms.py @@ -2489,6 +2489,7 @@ STATIC_ATOMS = [ PseudoElementAtom("PseudoElement_mozColorSwatch", ":-moz-color-swatch"), PseudoElementAtom("PseudoElement_mozTextControlEditingRoot", ":-moz-text-control-editing-root"), PseudoElementAtom("PseudoElement_mozTextControlPreview", ":-moz-text-control-preview"), + PseudoElementAtom("PseudoElement_fileChooserButton", ":file-chooser-button"), # CSS anonymous boxes -- these must appear in the same order as # in nsCSSAnonBoxList.h