Bug 1500423. Make '-webkit-appearance: menulist-textfield' behave like Chrome. r=mats
authorJonathan Watt <jwatt@jwatt.org>
Fri, 19 Oct 2018 18:12:15 +0100
changeset 500778 bacc9594a048c0cde34745393361c55bcc159f39
parent 500777 d603faf452ceb1d5001b28e045ec08c19aa932be
child 500779 b2fa4b07f6f7e489047808bd0238301ea943b4b3
push id1864
push userffxbld-merge
push dateMon, 03 Dec 2018 15:51:40 +0000
treeherdermozilla-release@f040763d99ad [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmats
bugs1500423
milestone64.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1500423. Make '-webkit-appearance: menulist-textfield' behave like Chrome. r=mats Differential Revision: https://phabricator.services.mozilla.com/D9339
widget/cocoa/nsNativeThemeCocoa.h
widget/cocoa/nsNativeThemeCocoa.mm
widget/gtk/WidgetStyleCache.cpp
widget/gtk/gtk3drawing.cpp
widget/gtk/nsNativeThemeGTK.cpp
widget/headless/HeadlessThemeGTK.cpp
widget/nsNativeTheme.cpp
widget/windows/nsNativeThemeWin.cpp
--- a/widget/cocoa/nsNativeThemeCocoa.h
+++ b/widget/cocoa/nsNativeThemeCocoa.h
@@ -172,16 +172,17 @@ public:
   struct UnifiedToolbarParams {
     float unifiedHeight = 0.0f;
     bool isMain = false;
   };
 
   struct TextBoxParams {
     bool disabled = false;
     bool focused = false;
+    bool borderless = false;
   };
 
   struct SearchFieldParams {
     float verticalAlignFactor = 0.5f;
     bool insideToolbar = false;
     bool disabled = false;
     bool focused = false;
     bool rtl = false;
--- a/widget/cocoa/nsNativeThemeCocoa.mm
+++ b/widget/cocoa/nsNativeThemeCocoa.mm
@@ -2017,16 +2017,25 @@ void
 nsNativeThemeCocoa::DrawTextBox(CGContextRef cgContext, const HIRect& inBoxRect,
                                 TextBoxParams aParams)
 {
   NS_OBJC_BEGIN_TRY_ABORT_BLOCK;
 
   CGContextSetRGBFillColor(cgContext, 1.0, 1.0, 1.0, 1.0);
   CGContextFillRect(cgContext, inBoxRect);
 
+#if DRAW_IN_FRAME_DEBUG
+  CGContextSetRGBFillColor(cgContext, 0.0, 0.0, 0.5, 0.25);
+  CGContextFillRect(cgContext, inBoxRect);
+#endif
+
+  if (aParams.borderless) {
+    return;
+  }
+
   HIThemeFrameDrawInfo fdi;
   fdi.version = 0;
   fdi.kind = kHIThemeFrameTextFieldSquare;
 
   // We don't ever set an inactive state for this because it doesn't
   // look right (see other apps).
   fdi.state = aParams.disabled ? kThemeStateUnavailable : kThemeStateActive;
   fdi.isFocused = aParams.focused;
@@ -2037,21 +2046,16 @@ nsNativeThemeCocoa::DrawTextBox(CGContex
   HIRect drawRect = inBoxRect;
   SInt32 frameOutset = 0;
   ::GetThemeMetric(kThemeMetricEditTextFrameOutset, &frameOutset);
   drawRect.origin.x += frameOutset;
   drawRect.origin.y += frameOutset;
   drawRect.size.width -= frameOutset * 2;
   drawRect.size.height -= frameOutset * 2;
 
-#if DRAW_IN_FRAME_DEBUG
-  CGContextSetRGBFillColor(cgContext, 0.0, 0.0, 0.5, 0.25);
-  CGContextFillRect(cgContext, inBoxRect);
-#endif
-
   HIThemeDrawFrame(&drawRect, &fdi, cgContext, HITHEME_ORIENTATION);
 
   NS_OBJC_END_TRY_ABORT_BLOCK;
 }
 
 static const CellRenderSettings progressSettings[2][2] = {
   // Vertical progress bar.
   {
@@ -3329,51 +3333,54 @@ nsNativeThemeCocoa::ComputeWidgetInfo(ns
         [(ToolbarWindow*)win unifiedToolbarHeight] : nativeWidgetRect.Height();
       return Some(WidgetInfo::NativeTitlebar(
         UnifiedToolbarParams{unifiedToolbarHeight, isMain}));
     }
 
     case StyleAppearance::Statusbar:
       return Some(WidgetInfo::StatusBar(IsActive(aFrame, YES)));
 
-    case StyleAppearance::Menulist:
-    case StyleAppearance::MenulistTextfield: {
+    case StyleAppearance::Menulist: {
       ControlParams controlParams = ComputeControlParams(aFrame, eventState);
       controlParams.focused = controlParams.focused || IsFocused(aFrame);
       controlParams.pressed = IsOpenButton(aFrame);
       DropdownParams params;
       params.controlParams = controlParams;
       params.pullsDown = false;
-      params.editable = aWidgetType == StyleAppearance::MenulistTextfield;
+      params.editable = false;
       return Some(WidgetInfo::Dropdown(params));
     }
 
     case StyleAppearance::MenulistButton:
     case StyleAppearance::MozMenulistButton:
       return Some(WidgetInfo::Button(
         ButtonParams{ComputeControlParams(aFrame, eventState),
                      ButtonType::eArrowButton}));
 
     case StyleAppearance::Groupbox:
       return Some(WidgetInfo::GroupBox());
 
+    case StyleAppearance::MenulistTextfield:
     case StyleAppearance::Textfield:
     case StyleAppearance::NumberInput: {
       bool isFocused = eventState.HasState(NS_EVENT_STATE_FOCUS);
       // XUL textboxes set the native appearance on the containing box, while
       // concrete focus is set on the html:input element within it. We can
       // though, check the focused attribute of xul textboxes in this case.
       // On Mac, focus rings are always shown for textboxes, so we do not need
       // to check the window's focus ring state here
       if (aFrame->GetContent()->IsXULElement() && IsFocused(aFrame)) {
         isFocused = true;
       }
 
       bool isDisabled = IsDisabled(aFrame, eventState) || IsReadOnly(aFrame);
-      return Some(WidgetInfo::TextBox(TextBoxParams{isDisabled, isFocused}));
+      bool borderless =
+        (aWidgetType == StyleAppearance::MenulistTextfield && !isFocused);
+      return Some(WidgetInfo::TextBox(TextBoxParams{isDisabled, isFocused,
+                                                    borderless}));
     }
 
     case StyleAppearance::Searchfield:
       return Some(WidgetInfo::SearchField(
         ComputeSearchFieldParams(aFrame, eventState)));
 
     case StyleAppearance::Progressbar:
     {
@@ -4059,19 +4066,16 @@ nsNativeThemeCocoa::GetWidgetBorder(nsDe
     // be sure to handle StaticPrefs::layout_css_webkit_appearance_enabled.
     case StyleAppearance::Menulist:
     case StyleAppearance::MenulistButton:
     case StyleAppearance::MozMenulistButton:
       result = DirectionAwareMargin(kAquaDropdownBorder, aFrame);
       break;
 
     case StyleAppearance::MenulistTextfield:
-      result = DirectionAwareMargin(kAquaComboboxBorder, aFrame);
-      break;
-
     case StyleAppearance::NumberInput:
     case StyleAppearance::Textfield:
     {
       SInt32 frameOutset = 0;
       ::GetThemeMetric(kThemeMetricEditTextFrameOutset, &frameOutset);
 
       SInt32 textPadding = 0;
       ::GetThemeMetric(kThemeMetricEditTextWhitespace, &textPadding);
@@ -4325,16 +4329,17 @@ nsNativeThemeCocoa::GetMinimumWidgetSize
     case StyleAppearance::MozMenulistButton:
     {
       SInt32 popupHeight = 0;
       ::GetThemeMetric(kThemeMetricPopupButtonHeight, &popupHeight);
       aResult->SizeTo(0, popupHeight);
       break;
     }
 
+    case StyleAppearance::MenulistTextfield:
     case StyleAppearance::NumberInput:
     case StyleAppearance::Textfield:
     case StyleAppearance::TextfieldMultiline:
     case StyleAppearance::Searchfield:
     {
       // at minimum, we should be tall enough for 9pt text.
       // I'm using hardcoded values here because the appearance manager
       // values for the frame size are incorrect.
@@ -4640,17 +4645,16 @@ nsNativeThemeCocoa::ThemeSupportsWidget(
   }
 
   switch (aWidgetType) {
     // Combobox dropdowns don't support native theming in vertical mode.
     case StyleAppearance::Menulist:
     case StyleAppearance::MenulistButton:
     case StyleAppearance::MozMenulistButton:
     case StyleAppearance::MenulistText:
-    case StyleAppearance::MenulistTextfield:
       if (aFrame && aFrame->GetWritingMode().IsVertical()) {
         return false;
       }
       MOZ_FALLTHROUGH;
 
     case StyleAppearance::Listbox:
 
     case StyleAppearance::Dialog:
@@ -4704,16 +4708,17 @@ nsNativeThemeCocoa::ThemeSupportsWidget(
     case StyleAppearance::Treetwisty:
     case StyleAppearance::Treetwistyopen:
     case StyleAppearance::Treeview:
     case StyleAppearance::Treeheader:
     case StyleAppearance::Treeheadercell:
     case StyleAppearance::Treeheadersortarrow:
     case StyleAppearance::Treeitem:
     case StyleAppearance::Treeline:
+    case StyleAppearance::MenulistTextfield:
     case StyleAppearance::MozMacSourceList:
     case StyleAppearance::MozMacSourceListSelection:
     case StyleAppearance::MozMacActiveSourceListSelection:
 
     case StyleAppearance::Range:
 
     case StyleAppearance::ScaleHorizontal:
     case StyleAppearance::ScalethumbHorizontal:
@@ -4798,17 +4803,16 @@ bool
 nsNativeThemeCocoa::ThemeDrawsFocusForWidget(WidgetType aWidgetType)
 {
   if (aWidgetType == StyleAppearance::MenulistButton &&
       StaticPrefs::layout_css_webkit_appearance_enabled()) {
     aWidgetType = StyleAppearance::Menulist;
   }
 
   if (aWidgetType == StyleAppearance::Menulist ||
-      aWidgetType == StyleAppearance::MenulistTextfield ||
       aWidgetType == StyleAppearance::Button ||
       aWidgetType == StyleAppearance::MozMacHelpButton ||
       aWidgetType == StyleAppearance::MozMacDisclosureButtonOpen ||
       aWidgetType == StyleAppearance::MozMacDisclosureButtonClosed ||
       aWidgetType == StyleAppearance::Radio ||
       aWidgetType == StyleAppearance::Range ||
       aWidgetType == StyleAppearance::Checkbox)
     return true;
@@ -4838,16 +4842,17 @@ nsNativeThemeCocoa::WidgetAppearanceDepe
     case StyleAppearance::Menuseparator:
     case StyleAppearance::Tooltip:
     case StyleAppearance::InnerSpinButton:
     case StyleAppearance::Spinner:
     case StyleAppearance::SpinnerUpbutton:
     case StyleAppearance::SpinnerDownbutton:
     case StyleAppearance::Separator:
     case StyleAppearance::Toolbox:
+    case StyleAppearance::MenulistTextfield:
     case StyleAppearance::NumberInput:
     case StyleAppearance::Textfield:
     case StyleAppearance::Treeview:
     case StyleAppearance::Treeline:
     case StyleAppearance::TextfieldMultiline:
     case StyleAppearance::Listbox:
     case StyleAppearance::Resizer:
       return false;
--- a/widget/gtk/WidgetStyleCache.cpp
+++ b/widget/gtk/WidgetStyleCache.cpp
@@ -773,16 +773,19 @@ CreateHeaderBar()
   CreateHeaderBarWidget(MOZ_GTK_HEADER_BAR);
   CreateHeaderBarWidget(MOZ_GTK_HEADER_BAR_MAXIMIZED);
   CreateHeaderBarButtons();
 }
 
 static GtkWidget*
 CreateWidget(WidgetNodeType aWidgetType)
 {
+  MOZ_ASSERT(aWidgetType != MOZ_GTK_DROPDOWN_ENTRY,
+             "Callers should be passing MOZ_GTK_ENTRY");
+
   switch (aWidgetType) {
     case MOZ_GTK_WINDOW:
       return CreateWindowWidget();
     case MOZ_GTK_WINDOW_CONTAINER:
       return CreateWindowContainerWidget();
     case MOZ_GTK_CHECKBUTTON_CONTAINER:
       return CreateCheckboxWidget();
     case MOZ_GTK_PROGRESSBAR:
@@ -1504,16 +1507,20 @@ ResetWidgetCache(void)
   /* Clear already freed arrays */
   mozilla::PodArrayZero(sWidgetStorage);
 }
 
 GtkStyleContext*
 GetStyleContext(WidgetNodeType aNodeType, GtkTextDirection aDirection,
                 GtkStateFlags aStateFlags, StyleFlags aFlags)
 {
+  if (aNodeType == MOZ_GTK_DROPDOWN_ENTRY) {
+    aNodeType = MOZ_GTK_ENTRY;
+  }
+
   GtkStyleContext* style;
   if (gtk_check_version(3, 20, 0) != nullptr) {
     style = GetWidgetStyleInternal(aNodeType);
   } else {
     style = GetCssNodeStyleInternal(aNodeType);
   }
   bool stateChanged = false;
   bool stateHasDirection = gtk_get_minor_version() >= 8;
--- a/widget/gtk/gtk3drawing.cpp
+++ b/widget/gtk/gtk3drawing.cpp
@@ -1242,17 +1242,18 @@ moz_gtk_vpaned_paint(cairo_t *cr, GdkRec
                       rect->x, rect->y, rect->width, rect->height);
     return MOZ_GTK_SUCCESS;
 }
 
 // See gtk_entry_draw() for reference.
 static gint
 moz_gtk_entry_paint(cairo_t *cr, GdkRectangle* rect,
                     GtkWidgetState* state,
-                    GtkStyleContext* style)
+                    GtkStyleContext* style,
+                    WidgetNodeType widget)
 {
     gint x = rect->x, y = rect->y, width = rect->width, height = rect->height;
     int draw_focus_outline_only = state->depressed; // StyleAppearance::FocusOutline
 
     if (draw_focus_outline_only) {
         // Inflate the given 'rect' with the focus outline size.
         gint h, v;
         moz_gtk_get_focus_outline_size(style, &h, &v);
@@ -1260,17 +1261,21 @@ moz_gtk_entry_paint(cairo_t *cr, GdkRect
         rect->width += 2 * h;
         rect->y -= v;
         rect->height += 2 * v;
         width = rect->width;
         height = rect->height;
     } else {
         gtk_render_background(style, cr, x, y, width, height);
     }
-    gtk_render_frame(style, cr, x, y, width, height);
+
+    // Paint the border, except for 'menulist-textfield' that isn't focused:
+    if (widget != MOZ_GTK_DROPDOWN_ENTRY || state->focused) {
+      gtk_render_frame(style, cr, x, y, width, height);
+    }
 
     return MOZ_GTK_SUCCESS;
 }
 
 static gint
 moz_gtk_text_view_paint(cairo_t *cr, GdkRectangle* aRect,
                         GtkWidgetState* state,
                         GtkTextDirection direction)
@@ -2410,18 +2415,19 @@ moz_gtk_get_widget_border(WidgetNodeType
             if (widget == MOZ_GTK_TOOLBAR_BUTTON)
                 gtk_style_context_restore(style);
 
             moz_gtk_add_style_border(style, left, top, right, bottom);
 
             return MOZ_GTK_SUCCESS;
         }
     case MOZ_GTK_ENTRY:
+    case MOZ_GTK_DROPDOWN_ENTRY:
         {
-            style = GetStyleContext(MOZ_GTK_ENTRY);
+            style = GetStyleContext(widget);
 
             // XXX: Subtract 1 pixel from the padding to account for the default
             // padding in forms.css. See bug 1187385.
             *left = *top = *right = *bottom = -1;
             moz_gtk_add_border_padding(style, left, top, right, bottom);
 
             return MOZ_GTK_SUCCESS;
         }
@@ -2444,19 +2450,16 @@ moz_gtk_get_widget_border(WidgetNodeType
                                                GetWidget(MOZ_GTK_TREE_HEADER_CELL)));
             style = GetStyleContext(MOZ_GTK_TREE_HEADER_CELL);
             moz_gtk_add_border_padding(style, left, top, right, bottom);
             return MOZ_GTK_SUCCESS;
         }
     case MOZ_GTK_TREE_HEADER_SORTARROW:
         w = GetWidget(MOZ_GTK_TREE_HEADER_SORTARROW);
         break;
-    case MOZ_GTK_DROPDOWN_ENTRY:
-        w = GetWidget(MOZ_GTK_COMBOBOX_ENTRY_TEXTAREA);
-        break;
     case MOZ_GTK_DROPDOWN_ARROW:
         w = GetWidget(MOZ_GTK_COMBOBOX_ENTRY_BUTTON);
         break;
     case MOZ_GTK_DROPDOWN:
         {
             /* We need to account for the arrow on the dropdown, so text
              * doesn't come too close to the arrow, or in some cases spill
              * into the arrow. */
@@ -3302,17 +3305,17 @@ moz_gtk_widget_paint(WidgetNodeType widg
                                          (widget == MOZ_GTK_SPINBUTTON_DOWN),
                                          state, direction);
         break;
     case MOZ_GTK_SPINBUTTON_ENTRY:
         {
             GtkStyleContext* style =
                 GetStyleContext(MOZ_GTK_SPINBUTTON_ENTRY, direction,
                                 GetStateFlagsFromGtkWidgetState(state));
-            gint ret = moz_gtk_entry_paint(cr, rect, state, style);
+            gint ret = moz_gtk_entry_paint(cr, rect, state, style, widget);
             return ret;
         }
         break;
     case MOZ_GTK_GRIPPER:
         return moz_gtk_gripper_paint(cr, rect, state,
                                      direction);
         break;
     case MOZ_GTK_TREEVIEW:
@@ -3329,42 +3332,34 @@ moz_gtk_widget_paint(WidgetNodeType widg
                                                     (GtkArrowType) flags,
                                                     direction);
         break;
     case MOZ_GTK_TREEVIEW_EXPANDER:
         return moz_gtk_treeview_expander_paint(cr, rect, state,
                                                (GtkExpanderStyle) flags, direction);
         break;
     case MOZ_GTK_ENTRY:
+    case MOZ_GTK_DROPDOWN_ENTRY:
         {
             GtkStyleContext* style =
-                GetStyleContext(MOZ_GTK_ENTRY, direction,
+                GetStyleContext(widget, direction,
                                 GetStateFlagsFromGtkWidgetState(state));
-            gint ret = moz_gtk_entry_paint(cr, rect, state, style);
+            gint ret = moz_gtk_entry_paint(cr, rect, state, style, widget);
             return ret;
         }
     case MOZ_GTK_TEXT_VIEW:
         return moz_gtk_text_view_paint(cr, rect, state, direction);
         break;
     case MOZ_GTK_DROPDOWN:
         return moz_gtk_combo_box_paint(cr, rect, state, direction);
         break;
     case MOZ_GTK_DROPDOWN_ARROW:
         return moz_gtk_combo_box_entry_button_paint(cr, rect,
                                                     state, flags, direction);
         break;
-    case MOZ_GTK_DROPDOWN_ENTRY:
-        {
-            GtkStyleContext* style =
-                GetStyleContext(MOZ_GTK_COMBOBOX_ENTRY_TEXTAREA, direction,
-                                GetStateFlagsFromGtkWidgetState(state));
-            gint ret = moz_gtk_entry_paint(cr, rect, state, style);
-            return ret;
-        }
-        break;
     case MOZ_GTK_CHECKBUTTON_CONTAINER:
     case MOZ_GTK_RADIOBUTTON_CONTAINER:
         return moz_gtk_container_paint(cr, rect, state, widget, direction);
         break;
     case MOZ_GTK_CHECKBUTTON_LABEL:
     case MOZ_GTK_RADIOBUTTON_LABEL:
         return moz_gtk_toggle_label_paint(cr, rect, state,
                                           (widget == MOZ_GTK_RADIOBUTTON_LABEL),
--- a/widget/gtk/nsNativeThemeGTK.cpp
+++ b/widget/gtk/nsNativeThemeGTK.cpp
@@ -1736,16 +1736,17 @@ nsNativeThemeGTK::GetMinimumWidgetSize(n
 
       LayoutDeviceIntMargin border;
       GetCachedWidgetBorder(aFrame, aWidgetType, GetTextDirection(aFrame), &border);
       aResult->width += border.left + border.right;
       aResult->height += border.top + border.bottom;
     }
     break;
 #ifdef MOZ_WIDGET_GTK
+  case StyleAppearance::MenulistTextfield:
   case StyleAppearance::NumberInput:
   case StyleAppearance::Textfield:
     {
       moz_gtk_get_entry_min_height(&aResult->height);
     }
     break;
 #endif
   case StyleAppearance::Separator:
@@ -1922,17 +1923,16 @@ nsNativeThemeGTK::ThemeSupportsWidget(ns
       StaticPrefs::layout_css_webkit_appearance_enabled()) {
     aWidgetType = StyleAppearance::Menulist;
   }
 
   switch (aWidgetType) {
   // Combobox dropdowns don't support native theming in vertical mode.
   case StyleAppearance::Menulist:
   case StyleAppearance::MenulistText:
-  case StyleAppearance::MenulistTextfield:
     if (aFrame && aFrame->GetWritingMode().IsVertical()) {
       return false;
     }
     MOZ_FALLTHROUGH;
 
   case StyleAppearance::Button:
   case StyleAppearance::ButtonFocus:
   case StyleAppearance::Radio:
@@ -1984,16 +1984,17 @@ nsNativeThemeGTK::ThemeSupportsWidget(ns
   case StyleAppearance::ScrollbarbuttonLeft:
   case StyleAppearance::ScrollbarbuttonRight:
   case StyleAppearance::ScrollbarHorizontal:
   case StyleAppearance::ScrollbarVertical:
   case StyleAppearance::ScrollbartrackHorizontal:
   case StyleAppearance::ScrollbartrackVertical:
   case StyleAppearance::ScrollbarthumbHorizontal:
   case StyleAppearance::ScrollbarthumbVertical:
+  case StyleAppearance::MenulistTextfield:
   case StyleAppearance::NumberInput:
   case StyleAppearance::Textfield:
   case StyleAppearance::TextfieldMultiline:
   case StyleAppearance::Range:
   case StyleAppearance::RangeThumb:
   case StyleAppearance::ScaleHorizontal:
   case StyleAppearance::ScalethumbHorizontal:
   case StyleAppearance::ScaleVertical:
--- a/widget/headless/HeadlessThemeGTK.cpp
+++ b/widget/headless/HeadlessThemeGTK.cpp
@@ -40,16 +40,17 @@ HeadlessThemeGTK::GetWidgetBorder(nsDevi
     case StyleAppearance::Button:
     case StyleAppearance::Toolbarbutton:
       result.top = 6;
       result.right = 7;
       result.bottom = 6;
       result.left = 7;
       break;
     case StyleAppearance::FocusOutline:
+    case StyleAppearance::MenulistTextfield:
     case StyleAppearance::NumberInput:
     case StyleAppearance::Textfield:
       result.top = 5;
       result.right = 7;
       result.bottom = 5;
       result.left = 7;
       break;
     case StyleAppearance::Statusbarpanel:
@@ -96,22 +97,16 @@ HeadlessThemeGTK::GetWidgetBorder(nsDevi
       break;
     case StyleAppearance::MenulistButton:
     case StyleAppearance::MozMenulistButton:
       result.top = 1;
       result.right = 1;
       result.bottom = 1;
       result.left = 0;
       break;
-    case StyleAppearance::MenulistTextfield:
-      result.top = 1;
-      result.right = 0;
-      result.bottom = 1;
-      result.left = 1;
-      break;
     case StyleAppearance::Menuitem:
     case StyleAppearance::Checkmenuitem:
     case StyleAppearance::Radiomenuitem:
       if (IsRegularMenuItem(aFrame)) {
         break;
       }
       result.top = 3;
       result.right = 5;
@@ -246,16 +241,17 @@ HeadlessThemeGTK::GetMinimumWidgetSize(n
       aResult->height = 16;
       *aIsOverridable = false;
       break;
     case StyleAppearance::InnerSpinButton:
     case StyleAppearance::Spinner:
       aResult->width = 14;
       aResult->height = 26;
       break;
+    case StyleAppearance::MenulistTextfield:
     case StyleAppearance::NumberInput:
     case StyleAppearance::Textfield:
       aResult->width = 0;
       aResult->height = 12;
       break;
     case StyleAppearance::ScrollbarHorizontal:
       aResult->width = 31;
       aResult->height = 10;
--- a/widget/nsNativeTheme.cpp
+++ b/widget/nsNativeTheme.cpp
@@ -100,17 +100,18 @@ nsNativeTheme::GetContentState(nsIFrame*
       flags |= NS_EVENT_STATE_FOCUS;
   }
 
   // On Windows and Mac, only draw focus rings if they should be shown. This
   // means that focus rings are only shown once the keyboard has been used to
   // focus something in the window.
 #if defined(XP_MACOSX)
   // Mac always draws focus rings for textboxes and lists.
-  if (aWidgetType == StyleAppearance::NumberInput ||
+  if (aWidgetType == StyleAppearance::MenulistTextfield ||
+      aWidgetType == StyleAppearance::NumberInput ||
       aWidgetType == StyleAppearance::Textfield ||
       aWidgetType == StyleAppearance::TextfieldMultiline ||
       aWidgetType == StyleAppearance::Searchfield ||
       aWidgetType == StyleAppearance::Listbox) {
     return flags;
   }
 #endif
 #if defined(XP_WIN)
@@ -342,16 +343,17 @@ nsNativeTheme::IsWidgetStyled(nsPresCont
       nsNumberControlFrame::GetNumberControlFrameForSpinButton(aFrame);
     if (numberControlFrame) {
       return !numberControlFrame->ShouldUseNativeStyleForSpinner();
     }
   }
 
   return (aWidgetType == StyleAppearance::NumberInput ||
           aWidgetType == StyleAppearance::Button ||
+          aWidgetType == StyleAppearance::MenulistTextfield ||
           aWidgetType == StyleAppearance::Textfield ||
           aWidgetType == StyleAppearance::TextfieldMultiline ||
           aWidgetType == StyleAppearance::Listbox ||
           aWidgetType == StyleAppearance::Menulist ||
           (aWidgetType == StyleAppearance::MenulistButton &&
            StaticPrefs::layout_css_webkit_appearance_enabled())) &&
          aFrame->GetContent()->IsHTMLElement() &&
          aPresContext->HasAuthorSpecifiedRules(aFrame,
--- a/widget/windows/nsNativeThemeWin.cpp
+++ b/widget/windows/nsNativeThemeWin.cpp
@@ -725,16 +725,17 @@ nsresult nsNativeThemeWin::GetCachedMini
 mozilla::Maybe<nsUXThemeClass> nsNativeThemeWin::GetThemeClass(WidgetType aWidgetType)
 {
   switch (aWidgetType) {
     case StyleAppearance::Button:
     case StyleAppearance::Radio:
     case StyleAppearance::Checkbox:
     case StyleAppearance::Groupbox:
       return Some(eUXButton);
+    case StyleAppearance::MenulistTextfield:
     case StyleAppearance::NumberInput:
     case StyleAppearance::Textfield:
     case StyleAppearance::TextfieldMultiline:
     case StyleAppearance::FocusOutline:
       return Some(eUXEdit);
     case StyleAppearance::Tooltip:
       return Some(eUXTooltip);
     case StyleAppearance::Toolbox:
@@ -946,16 +947,17 @@ nsNativeThemeWin::GetThemePartAndState(n
     }
     case StyleAppearance::Groupbox: {
       aPart = BP_GROUPBOX;
       aState = TS_NORMAL;
       // Since we don't support groupbox disabled and GBS_DISABLED looks the
       // same as GBS_NORMAL don't bother supporting GBS_DISABLED.
       return NS_OK;
     }
+    case StyleAppearance::MenulistTextfield:
     case StyleAppearance::NumberInput:
     case StyleAppearance::Textfield:
     case StyleAppearance::TextfieldMultiline: {
       EventStates eventState = GetContentState(aFrame, aWidgetType);
 
       /* Note: the NOSCROLL type has a rounded corner in each corner.  The more
        * specific HSCROLL, VSCROLL, HVSCROLL types have side and/or top/bottom
        * edges rendered as straight horizontal lines with sharp corners to
@@ -1864,21 +1866,26 @@ RENDER_AGAIN:
   // The following widgets need to be RTL-aware
   else if (aWidgetType == StyleAppearance::Resizer ||
            aWidgetType == StyleAppearance::MenulistButton ||
            aWidgetType == StyleAppearance::MozMenulistButton)
   {
     DrawThemeBGRTLAware(theme, hdc, part, state,
                         &widgetRect, &clipRect, IsFrameRTL(aFrame));
   }
-  else if (aWidgetType == StyleAppearance::NumberInput ||
+  else if (aWidgetType == StyleAppearance::MenulistTextfield ||
+           aWidgetType == StyleAppearance::NumberInput ||
            aWidgetType == StyleAppearance::Textfield ||
            aWidgetType == StyleAppearance::TextfieldMultiline) {
-    DrawThemeBackground(theme, hdc, part, state, &widgetRect, &clipRect);
-     if (state == TFS_EDITBORDER_DISABLED) {
+    // Paint the border, except for 'menulist-textfield' that isn't focused:
+    if (aWidgetType != StyleAppearance::MenulistTextfield ||
+        state == TFS_EDITBORDER_FOCUSED) {
+      DrawThemeBackground(theme, hdc, part, state, &widgetRect, &clipRect);
+    }
+    if (state == TFS_EDITBORDER_DISABLED) {
       InflateRect(&widgetRect, -1, -1);
       ::FillRect(hdc, &widgetRect, reinterpret_cast<HBRUSH>(COLOR_BTNFACE+1));
     }
   }
   else if (aWidgetType == StyleAppearance::Progressbar ||
            aWidgetType == StyleAppearance::ProgressbarVertical) {
     // DrawThemeBackground renders each corner with a solid white pixel.
     // Restore these pixels to the underlying color. Tracks are rendered
@@ -2094,17 +2101,18 @@ nsNativeThemeWin::GetWidgetBorder(nsDevi
     if (IsLeftToSelectedTab(aFrame))
       // Remove the right edge, since we won't be drawing it.
       result.right = 0;
     else if (IsRightToSelectedTab(aFrame))
       // Remove the left edge, since we won't be drawing it.
       result.left = 0;
   }
 
-  if (aFrame && (aWidgetType == StyleAppearance::NumberInput ||
+  if (aFrame && (aWidgetType == StyleAppearance::MenulistTextfield ||
+                 aWidgetType == StyleAppearance::NumberInput ||
                  aWidgetType == StyleAppearance::Textfield ||
                  aWidgetType == StyleAppearance::TextfieldMultiline)) {
     nsIContent* content = aFrame->GetContent();
     if (content && content->IsHTMLElement()) {
       // We need to pad textfields by 1 pixel, since the caret will draw
       // flush against the edge by default if we don't.
       result.top++;
       result.left++;
@@ -2194,34 +2202,36 @@ nsNativeThemeWin::GetWidgetPadding(nsDev
     SIZE popupSize;
     GetThemePartSize(theme, nullptr, MENU_POPUPBORDERS, /* state */ 0, nullptr, TS_TRUE, &popupSize);
     aResult->top = aResult->bottom = popupSize.cy;
     aResult->left = aResult->right = popupSize.cx;
     ScaleForFrameDPI(aResult, aFrame);
     return ok;
   }
 
-  if (aWidgetType == StyleAppearance::NumberInput ||
+  if (aWidgetType == StyleAppearance::MenulistTextfield ||
+      aWidgetType == StyleAppearance::NumberInput ||
       aWidgetType == StyleAppearance::Textfield ||
       aWidgetType == StyleAppearance::TextfieldMultiline ||
       aWidgetType == StyleAppearance::Menulist)
   {
     // If we have author-specified padding for these elements, don't do the
     // fixups below.
     if (aFrame->PresContext()->HasAuthorSpecifiedRules(aFrame, NS_AUTHOR_SPECIFIED_PADDING))
       return false;
   }
 
   /* textfields need extra pixels on all sides, otherwise they wrap their
    * content too tightly.  The actual border is drawn 1px inside the specified
    * rectangle, so Gecko will end up making the contents look too small.
    * Instead, we add 2px padding for the contents and fix this. (Used to be 1px
    * added, see bug 430212)
    */
-  if (aWidgetType == StyleAppearance::NumberInput ||
+  if (aWidgetType == StyleAppearance::MenulistTextfield ||
+      aWidgetType == StyleAppearance::NumberInput ||
       aWidgetType == StyleAppearance::Textfield ||
       aWidgetType == StyleAppearance::TextfieldMultiline) {
     aResult->top = aResult->bottom = 2;
     aResult->left = aResult->right = 2;
     ScaleForFrameDPI(aResult, aFrame);
     return ok;
   } else if (IsHTMLContent(aFrame) && aWidgetType == StyleAppearance::Menulist) {
     /* For content menulist controls, we need an extra pixel so that we have
@@ -2353,16 +2363,17 @@ nsNativeThemeWin::GetMinimumWidgetSize(n
   if (!theme) {
     rv = ClassicGetMinimumWidgetSize(aFrame, aWidgetType, aResult, aIsOverridable);
     ScaleForFrameDPI(aResult, aFrame);
     return rv;
   }
 
   switch (aWidgetType) {
     case StyleAppearance::Groupbox:
+    case StyleAppearance::MenulistTextfield:
     case StyleAppearance::NumberInput:
     case StyleAppearance::Textfield:
     case StyleAppearance::Toolbox:
     case StyleAppearance::MozWinMediaToolbox:
     case StyleAppearance::MozWinCommunicationsToolbox:
     case StyleAppearance::MozWinBrowsertabbarToolbox:
     case StyleAppearance::Toolbar:
     case StyleAppearance::Statusbar:
@@ -3807,18 +3818,22 @@ RENDER_AGAIN:
     }
     // Draw controls with 2px 3D inset border
     case StyleAppearance::NumberInput:
     case StyleAppearance::Textfield:
     case StyleAppearance::TextfieldMultiline:
     case StyleAppearance::Listbox:
     case StyleAppearance::Menulist:
     case StyleAppearance::MenulistTextfield: {
-      // Draw inset edge
-      ::DrawEdge(hdc, &widgetRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
+      // Paint the border, except for 'menulist-textfield' that isn't focused:
+      if (aWidgetType != StyleAppearance::MenulistTextfield || focused) {
+        // Draw inset edge
+        ::DrawEdge(hdc, &widgetRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
+      }
+
       EventStates eventState = GetContentState(aFrame, aWidgetType);
 
       // Fill in background
       if (IsDisabled(aFrame, eventState) ||
           (aFrame->GetContent()->IsXULElement() &&
            IsReadOnly(aFrame)))
         ::FillRect(hdc, &widgetRect, (HBRUSH) (COLOR_BTNFACE+1));
       else