1 /**
2 * This file is part of the theme implementation for form controls in WebCore.
3 *
4 * Copyright (C) 2005, 2006, 2007, 2008, 2009, 2010, 2012 Apple Computer, Inc.
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details.
15 *
16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA.
20 */
21
22 #include "third_party/blink/renderer/core/layout/layout_theme.h"
23
24 #include "build/build_config.h"
25 #include "third_party/blink/public/platform/platform.h"
26 #include "third_party/blink/public/platform/web_rect.h"
27 #include "third_party/blink/public/strings/grit/blink_strings.h"
28 #include "third_party/blink/public/web/blink.h"
29 #include "third_party/blink/renderer/core/css_value_keywords.h"
30 #include "third_party/blink/renderer/core/dom/document.h"
31 #include "third_party/blink/renderer/core/dom/shadow_root.h"
32 #include "third_party/blink/renderer/core/editing/frame_selection.h"
33 #include "third_party/blink/renderer/core/fileapi/file.h"
34 #include "third_party/blink/renderer/core/frame/local_frame.h"
35 #include "third_party/blink/renderer/core/frame/settings.h"
36 #include "third_party/blink/renderer/core/html/forms/html_data_list_element.h"
37 #include "third_party/blink/renderer/core/html/forms/html_data_list_options_collection.h"
38 #include "third_party/blink/renderer/core/html/forms/html_form_control_element.h"
39 #include "third_party/blink/renderer/core/html/forms/html_input_element.h"
40 #include "third_party/blink/renderer/core/html/forms/html_option_element.h"
41 #include "third_party/blink/renderer/core/html/forms/html_select_element.h"
42 #include "third_party/blink/renderer/core/html/forms/spin_button_element.h"
43 #include "third_party/blink/renderer/core/html/forms/text_control_inner_elements.h"
44 #include "third_party/blink/renderer/core/html/html_collection.h"
45 #include "third_party/blink/renderer/core/html/parser/html_parser_idioms.h"
46 #include "third_party/blink/renderer/core/html/shadow/shadow_element_names.h"
47 #include "third_party/blink/renderer/core/html_names.h"
48 #include "third_party/blink/renderer/core/input_type_names.h"
49 #include "third_party/blink/renderer/core/layout/layout_box.h"
50 #include "third_party/blink/renderer/core/layout/layout_theme_mobile.h"
51 #include "third_party/blink/renderer/core/page/focus_controller.h"
52 #include "third_party/blink/renderer/core/page/page.h"
53 #include "third_party/blink/renderer/core/paint/fallback_theme.h"
54 #include "third_party/blink/renderer/core/style/computed_style.h"
55 #include "third_party/blink/renderer/core/style/computed_style_initial_values.h"
56 #include "third_party/blink/renderer/platform/file_metadata.h"
57 #include "third_party/blink/renderer/platform/fonts/font_selector.h"
58 #include "third_party/blink/renderer/platform/graphics/touch_action.h"
59 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
60 #include "third_party/blink/renderer/platform/web_test_support.h"
61 #include "third_party/blink/renderer/platform/wtf/text/string_builder.h"
62 #include "ui/base/ui_base_features.h"
63 #include "ui/native_theme/native_theme.h"
64
65 // The methods in this file are shared by all themes on every platform.
66
67 namespace blink {
68
69 namespace {
70
71 // This function should match to the user-agent stylesheet.
AutoAppearanceFor(const Element & element)72 ControlPart AutoAppearanceFor(const Element& element) {
73 if (IsA<HTMLButtonElement>(element))
74 return kButtonPart;
75 if (IsA<HTMLMeterElement>(element))
76 return kMeterPart;
77 if (IsA<HTMLProgressElement>(element))
78 return kProgressBarPart;
79 if (IsA<HTMLTextAreaElement>(element))
80 return kTextAreaPart;
81 if (IsA<SpinButtonElement>(element))
82 return kInnerSpinButtonPart;
83 if (const auto* select = DynamicTo<HTMLSelectElement>(element))
84 return select->UsesMenuList() ? kMenulistPart : kListboxPart;
85
86 if (const auto* input = DynamicTo<HTMLInputElement>(element)) {
87 const AtomicString& type = input->type();
88 if (type == input_type_names::kCheckbox)
89 return kCheckboxPart;
90 if (type == input_type_names::kRadio)
91 return kRadioPart;
92 if (input->IsTextButton())
93 return kPushButtonPart;
94 if (type == input_type_names::kColor) {
95 return input->FastHasAttribute(html_names::kListAttr) ? kMenulistPart
96 : kSquareButtonPart;
97 }
98 if (type == input_type_names::kRange)
99 return kSliderHorizontalPart;
100 if (type == input_type_names::kSearch)
101 return kSearchFieldPart;
102 if (type == input_type_names::kDate ||
103 type == input_type_names::kDatetimeLocal ||
104 type == input_type_names::kMonth || type == input_type_names::kTime ||
105 type == input_type_names::kWeek) {
106 #if defined(OS_ANDROID)
107 return kMenulistPart;
108 #else
109 return kTextFieldPart;
110 #endif
111 }
112 if (type == input_type_names::kEmail || type == input_type_names::kNumber ||
113 type == input_type_names::kPassword || type == input_type_names::kTel ||
114 type == input_type_names::kText || type == input_type_names::kUrl)
115 return kTextFieldPart;
116
117 // Type=hidden/image/file.
118 return kNoControlPart;
119 }
120
121 if (element.IsInUserAgentShadowRoot()) {
122 const AtomicString& id_value =
123 element.FastGetAttribute(html_names::kIdAttr);
124 if (id_value == shadow_element_names::SliderThumb())
125 return kSliderThumbHorizontalPart;
126 if (id_value == shadow_element_names::SearchClearButton() ||
127 id_value == shadow_element_names::ClearButton())
128 return kSearchFieldCancelButtonPart;
129
130 // Slider container elements and -webkit-meter-inner-element don't have IDs.
131 const AtomicString& shadow_pseudo = element.ShadowPseudoId();
132 if (shadow_pseudo == "-webkit-media-slider-container" ||
133 shadow_pseudo == "-webkit-slider-container")
134 return kSliderHorizontalPart;
135 if (shadow_pseudo == "-webkit-meter-inner-element")
136 return kMeterPart;
137 }
138 return kNoControlPart;
139 }
140
141 } // namespace
142
GetTheme()143 LayoutTheme& LayoutTheme::GetTheme() {
144 if (RuntimeEnabledFeatures::MobileLayoutThemeEnabled()) {
145 DEFINE_STATIC_REF(LayoutTheme, layout_theme_mobile,
146 (LayoutThemeMobile::Create()));
147 return *layout_theme_mobile;
148 }
149 return NativeTheme();
150 }
151
LayoutTheme()152 LayoutTheme::LayoutTheme() : has_custom_focus_ring_color_(false) {}
153
AdjustAppearanceWithAuthorStyle(ControlPart part,const ComputedStyle & style)154 ControlPart LayoutTheme::AdjustAppearanceWithAuthorStyle(
155 ControlPart part,
156 const ComputedStyle& style) {
157 if (IsControlStyled(part, style))
158 return part == kMenulistPart ? kMenulistButtonPart : kNoControlPart;
159 return part;
160 }
161
AdjustAppearanceWithElementType(const ComputedStyle & style,const Element * element)162 ControlPart LayoutTheme::AdjustAppearanceWithElementType(
163 const ComputedStyle& style,
164 const Element* element) {
165 ControlPart part = style.EffectiveAppearance();
166 if (!element)
167 return kNoControlPart;
168
169 ControlPart auto_appearance = AutoAppearanceFor(*element);
170 if (part == auto_appearance)
171 return part;
172
173 switch (part) {
174 // No restrictions.
175 case kNoControlPart:
176 case kMediaSliderPart:
177 case kMediaSliderThumbPart:
178 case kMediaVolumeSliderPart:
179 case kMediaVolumeSliderThumbPart:
180 case kMediaControlPart:
181 return part;
182
183 // Aliases of 'auto'.
184 // https://drafts.csswg.org/css-ui-4/#typedef-appearance-compat-auto
185 case kAutoPart:
186 case kCheckboxPart:
187 case kRadioPart:
188 case kPushButtonPart:
189 case kSquareButtonPart:
190 case kInnerSpinButtonPart:
191 case kListboxPart:
192 case kMenulistPart:
193 case kMeterPart:
194 case kProgressBarPart:
195 case kSliderHorizontalPart:
196 case kSliderThumbHorizontalPart:
197 case kSearchFieldPart:
198 case kSearchFieldCancelButtonPart:
199 case kTextAreaPart:
200 return auto_appearance;
201
202 // The following keywords should work well for some element types
203 // even if their default appearances are different from the keywords.
204
205 case kButtonPart:
206 return (auto_appearance == kPushButtonPart ||
207 auto_appearance == kSquareButtonPart)
208 ? part
209 : auto_appearance;
210
211 case kMenulistButtonPart:
212 return auto_appearance == kMenulistPart ? part : auto_appearance;
213
214 case kSliderVerticalPart:
215 return auto_appearance == kSliderHorizontalPart ? part : auto_appearance;
216
217 case kSliderThumbVerticalPart:
218 return auto_appearance == kSliderThumbHorizontalPart ? part
219 : auto_appearance;
220
221 case kTextFieldPart:
222 if (IsA<HTMLInputElement>(*element) &&
223 To<HTMLInputElement>(*element).type() == input_type_names::kSearch)
224 return part;
225 return auto_appearance;
226 }
227
228 return part;
229 }
230
AdjustStyle(ComputedStyle & style,Element * e)231 void LayoutTheme::AdjustStyle(ComputedStyle& style, Element* e) {
232 ControlPart original_part = style.Appearance();
233 style.SetEffectiveAppearance(original_part);
234 if (original_part == ControlPart::kNoControlPart)
235 return;
236
237 // Force inline and table display styles to be inline-block (except for table-
238 // which is block)
239 if (style.Display() == EDisplay::kInline ||
240 style.Display() == EDisplay::kInlineTable ||
241 style.Display() == EDisplay::kTableRowGroup ||
242 style.Display() == EDisplay::kTableHeaderGroup ||
243 style.Display() == EDisplay::kTableFooterGroup ||
244 style.Display() == EDisplay::kTableRow ||
245 style.Display() == EDisplay::kTableColumnGroup ||
246 style.Display() == EDisplay::kTableColumn ||
247 style.Display() == EDisplay::kTableCell ||
248 style.Display() == EDisplay::kTableCaption)
249 style.SetDisplay(EDisplay::kInlineBlock);
250 else if (style.Display() == EDisplay::kListItem ||
251 style.Display() == EDisplay::kTable)
252 style.SetDisplay(EDisplay::kBlock);
253
254 // TODO(tkent): We should not update Appearance, which is a source of
255 // getComputedStyle(). https://drafts.csswg.org/css-ui-4/#propdef-appearance
256 // says "Computed value: specified keyword".
257 style.SetAppearance(AdjustAppearanceWithAuthorStyle(original_part, style));
258
259 ControlPart part = AdjustAppearanceWithAuthorStyle(
260 AdjustAppearanceWithElementType(style, e), style);
261 style.SetEffectiveAppearance(part);
262 DCHECK_NE(part, kAutoPart);
263 if (part == kNoControlPart)
264 return;
265
266 if (ShouldUseFallbackTheme(style)) {
267 AdjustStyleUsingFallbackTheme(style);
268 return;
269 }
270
271 AdjustControlPartStyle(style);
272
273 // Call the appropriate style adjustment method based off the appearance
274 // value.
275 switch (part) {
276 case kMenulistPart:
277 return AdjustMenuListStyle(style, e);
278 case kMenulistButtonPart:
279 return AdjustMenuListButtonStyle(style, e);
280 case kSliderHorizontalPart:
281 case kSliderVerticalPart:
282 case kMediaSliderPart:
283 case kMediaVolumeSliderPart:
284 return AdjustSliderContainerStyle(style, e);
285 case kSliderThumbHorizontalPart:
286 case kSliderThumbVerticalPart:
287 return AdjustSliderThumbStyle(style);
288 case kSearchFieldPart:
289 return AdjustSearchFieldStyle(style);
290 case kSearchFieldCancelButtonPart:
291 return AdjustSearchFieldCancelButtonStyle(style);
292 default:
293 break;
294 }
295 }
296
ExtraDefaultStyleSheet()297 String LayoutTheme::ExtraDefaultStyleSheet() {
298 if (RuntimeEnabledFeatures::LayoutNGForControlsEnabled()) {
299 return String(R"CSS(
300 input[type="file" i] {
301 overflow: hidden;
302 text-overflow: ellipsis;
303 white-space: pre;
304 }
305
306 input[type="file" i]::-webkit-file-upload-button {
307 margin-inline-end: 4px;
308 }
309 )CSS");
310 }
311 return g_empty_string;
312 }
313
ExtraQuirksStyleSheet()314 String LayoutTheme::ExtraQuirksStyleSheet() {
315 return String();
316 }
317
ExtraFullscreenStyleSheet()318 String LayoutTheme::ExtraFullscreenStyleSheet() {
319 return String();
320 }
321
ActiveSelectionBackgroundColor(WebColorScheme color_scheme) const322 Color LayoutTheme::ActiveSelectionBackgroundColor(
323 WebColorScheme color_scheme) const {
324 return PlatformActiveSelectionBackgroundColor(color_scheme).BlendWithWhite();
325 }
326
InactiveSelectionBackgroundColor(WebColorScheme color_scheme) const327 Color LayoutTheme::InactiveSelectionBackgroundColor(
328 WebColorScheme color_scheme) const {
329 return PlatformInactiveSelectionBackgroundColor(color_scheme)
330 .BlendWithWhite();
331 }
332
ActiveSelectionForegroundColor(WebColorScheme color_scheme) const333 Color LayoutTheme::ActiveSelectionForegroundColor(
334 WebColorScheme color_scheme) const {
335 return PlatformActiveSelectionForegroundColor(color_scheme);
336 }
337
InactiveSelectionForegroundColor(WebColorScheme color_scheme) const338 Color LayoutTheme::InactiveSelectionForegroundColor(
339 WebColorScheme color_scheme) const {
340 return PlatformInactiveSelectionForegroundColor(color_scheme);
341 }
342
ActiveListBoxSelectionBackgroundColor(WebColorScheme color_scheme) const343 Color LayoutTheme::ActiveListBoxSelectionBackgroundColor(
344 WebColorScheme color_scheme) const {
345 return PlatformActiveListBoxSelectionBackgroundColor(color_scheme);
346 }
347
InactiveListBoxSelectionBackgroundColor(WebColorScheme color_scheme) const348 Color LayoutTheme::InactiveListBoxSelectionBackgroundColor(
349 WebColorScheme color_scheme) const {
350 return PlatformInactiveListBoxSelectionBackgroundColor(color_scheme);
351 }
352
ActiveListBoxSelectionForegroundColor(WebColorScheme color_scheme) const353 Color LayoutTheme::ActiveListBoxSelectionForegroundColor(
354 WebColorScheme color_scheme) const {
355 return PlatformActiveListBoxSelectionForegroundColor(color_scheme);
356 }
357
InactiveListBoxSelectionForegroundColor(WebColorScheme color_scheme) const358 Color LayoutTheme::InactiveListBoxSelectionForegroundColor(
359 WebColorScheme color_scheme) const {
360 return PlatformInactiveListBoxSelectionForegroundColor(color_scheme);
361 }
362
PlatformSpellingMarkerUnderlineColor() const363 Color LayoutTheme::PlatformSpellingMarkerUnderlineColor() const {
364 return Color(255, 0, 0);
365 }
366
PlatformGrammarMarkerUnderlineColor() const367 Color LayoutTheme::PlatformGrammarMarkerUnderlineColor() const {
368 return Color(192, 192, 192);
369 }
370
PlatformActiveSpellingMarkerHighlightColor() const371 Color LayoutTheme::PlatformActiveSpellingMarkerHighlightColor() const {
372 return Color(255, 0, 0, 102);
373 }
374
PlatformActiveSelectionBackgroundColor(WebColorScheme color_scheme) const375 Color LayoutTheme::PlatformActiveSelectionBackgroundColor(
376 WebColorScheme color_scheme) const {
377 // Use a blue color by default if the platform theme doesn't define anything.
378 return Color(0, 0, 255);
379 }
380
PlatformActiveSelectionForegroundColor(WebColorScheme color_scheme) const381 Color LayoutTheme::PlatformActiveSelectionForegroundColor(
382 WebColorScheme color_scheme) const {
383 // Use a white color by default if the platform theme doesn't define anything.
384 return Color::kWhite;
385 }
386
PlatformInactiveSelectionBackgroundColor(WebColorScheme color_scheme) const387 Color LayoutTheme::PlatformInactiveSelectionBackgroundColor(
388 WebColorScheme color_scheme) const {
389 // Use a grey color by default if the platform theme doesn't define anything.
390 // This color matches Firefox's inactive color.
391 return Color(176, 176, 176);
392 }
393
PlatformInactiveSelectionForegroundColor(WebColorScheme color_scheme) const394 Color LayoutTheme::PlatformInactiveSelectionForegroundColor(
395 WebColorScheme color_scheme) const {
396 // Use a black color by default.
397 return Color::kBlack;
398 }
399
PlatformActiveListBoxSelectionBackgroundColor(WebColorScheme color_scheme) const400 Color LayoutTheme::PlatformActiveListBoxSelectionBackgroundColor(
401 WebColorScheme color_scheme) const {
402 return PlatformActiveSelectionBackgroundColor(color_scheme);
403 }
404
PlatformActiveListBoxSelectionForegroundColor(WebColorScheme color_scheme) const405 Color LayoutTheme::PlatformActiveListBoxSelectionForegroundColor(
406 WebColorScheme color_scheme) const {
407 return PlatformActiveSelectionForegroundColor(color_scheme);
408 }
409
PlatformInactiveListBoxSelectionBackgroundColor(WebColorScheme color_scheme) const410 Color LayoutTheme::PlatformInactiveListBoxSelectionBackgroundColor(
411 WebColorScheme color_scheme) const {
412 return PlatformInactiveSelectionBackgroundColor(color_scheme);
413 }
414
PlatformInactiveListBoxSelectionForegroundColor(WebColorScheme color_scheme) const415 Color LayoutTheme::PlatformInactiveListBoxSelectionForegroundColor(
416 WebColorScheme color_scheme) const {
417 return PlatformInactiveSelectionForegroundColor(color_scheme);
418 }
419
BaselinePositionAdjustment(const ComputedStyle & style) const420 LayoutUnit LayoutTheme::BaselinePositionAdjustment(
421 const ComputedStyle& style) const {
422 return LayoutUnit();
423 }
424
IsControlContainer(ControlPart appearance) const425 bool LayoutTheme::IsControlContainer(ControlPart appearance) const {
426 // There are more leaves than this, but we'll patch this function as we add
427 // support for more controls.
428 return appearance != kCheckboxPart && appearance != kRadioPart;
429 }
430
IsControlStyled(ControlPart part,const ComputedStyle & style) const431 bool LayoutTheme::IsControlStyled(ControlPart part,
432 const ComputedStyle& style) const {
433 switch (part) {
434 case kPushButtonPart:
435 case kSquareButtonPart:
436 case kButtonPart:
437 case kProgressBarPart:
438 return style.HasAuthorBackground() || style.HasAuthorBorder();
439
440 case kMenulistPart:
441 case kSearchFieldPart:
442 case kTextAreaPart:
443 case kTextFieldPart:
444 return style.HasAuthorBackground() || style.HasAuthorBorder() ||
445 style.BoxShadow();
446
447 default:
448 return false;
449 }
450 }
451
ShouldDrawDefaultFocusRing(const Node * node,const ComputedStyle & style) const452 bool LayoutTheme::ShouldDrawDefaultFocusRing(const Node* node,
453 const ComputedStyle& style) const {
454 if (ThemeDrawsFocusRing(style))
455 return false;
456 if (!node)
457 return true;
458 if (!style.HasEffectiveAppearance() && !node->IsLink())
459 return true;
460 // We can't use LayoutTheme::isFocused because outline:auto might be
461 // specified to non-:focus rulesets.
462 if (node->IsFocused() && !node->ShouldHaveFocusAppearance())
463 return false;
464 return true;
465 }
466
ControlStateChanged(const Node * node,const ComputedStyle & style,ControlState state) const467 bool LayoutTheme::ControlStateChanged(const Node* node,
468 const ComputedStyle& style,
469 ControlState state) const {
470 if (!style.HasEffectiveAppearance())
471 return false;
472
473 // Default implementation assumes the controls don't respond to changes in
474 // :hover state
475 if (state == kHoverControlState && !SupportsHover(style))
476 return false;
477
478 // Assume pressed state is only responded to if the control is enabled.
479 if (state == kPressedControlState && !IsEnabled(node))
480 return false;
481
482 return true;
483 }
484
ControlStatesForNode(const Node * node,const ComputedStyle & style)485 ControlStates LayoutTheme::ControlStatesForNode(const Node* node,
486 const ComputedStyle& style) {
487 ControlStates result = 0;
488 if (IsHovered(node)) {
489 result |= kHoverControlState;
490 if (IsSpinUpButtonPartHovered(node))
491 result |= kSpinUpControlState;
492 }
493 if (IsPressed(node)) {
494 result |= kPressedControlState;
495 if (IsSpinUpButtonPartPressed(node))
496 result |= kSpinUpControlState;
497 }
498 if (IsFocused(node) && style.OutlineStyleIsAuto())
499 result |= kFocusControlState;
500 if (IsEnabled(node))
501 result |= kEnabledControlState;
502 if (IsChecked(node))
503 result |= kCheckedControlState;
504 if (IsReadOnlyControl(node))
505 result |= kReadOnlyControlState;
506 if (!IsActive(node))
507 result |= kWindowInactiveControlState;
508 if (IsIndeterminate(node))
509 result |= kIndeterminateControlState;
510 return result;
511 }
512
IsActive(const Node * node)513 bool LayoutTheme::IsActive(const Node* node) {
514 if (!node)
515 return false;
516
517 Page* page = node->GetDocument().GetPage();
518 if (!page)
519 return false;
520
521 return page->GetFocusController().IsActive();
522 }
523
IsChecked(const Node * node)524 bool LayoutTheme::IsChecked(const Node* node) {
525 if (auto* input = DynamicTo<HTMLInputElement>(node))
526 return input->ShouldAppearChecked();
527 return false;
528 }
529
IsIndeterminate(const Node * node)530 bool LayoutTheme::IsIndeterminate(const Node* node) {
531 if (auto* input = DynamicTo<HTMLInputElement>(node))
532 return input->ShouldAppearIndeterminate();
533 return false;
534 }
535
IsEnabled(const Node * node)536 bool LayoutTheme::IsEnabled(const Node* node) {
537 auto* element = DynamicTo<Element>(node);
538 if (!element)
539 return true;
540 return !element->IsDisabledFormControl();
541 }
542
IsFocused(const Node * node)543 bool LayoutTheme::IsFocused(const Node* node) {
544 if (!node)
545 return false;
546
547 node = node->FocusDelegate();
548 Document& document = node->GetDocument();
549 LocalFrame* frame = document.GetFrame();
550 return node == document.FocusedElement() && node->IsFocused() &&
551 node->ShouldHaveFocusAppearance() && frame &&
552 frame->Selection().FrameIsFocusedAndActive();
553 }
554
IsPressed(const Node * node)555 bool LayoutTheme::IsPressed(const Node* node) {
556 if (!node)
557 return false;
558 return node->IsActive();
559 }
560
IsSpinUpButtonPartPressed(const Node * node)561 bool LayoutTheme::IsSpinUpButtonPartPressed(const Node* node) {
562 const auto* element = DynamicTo<SpinButtonElement>(node);
563 if (!element || !element->IsActive())
564 return false;
565 return element->GetUpDownState() == SpinButtonElement::kUp;
566 }
567
IsReadOnlyControl(const Node * node)568 bool LayoutTheme::IsReadOnlyControl(const Node* node) {
569 auto* form_control_element = DynamicTo<HTMLFormControlElement>(node);
570 return form_control_element && form_control_element->IsReadOnly();
571 }
572
IsHovered(const Node * node)573 bool LayoutTheme::IsHovered(const Node* node) {
574 if (!node)
575 return false;
576 const auto* element = DynamicTo<SpinButtonElement>(node);
577 if (!element)
578 return node->IsHovered();
579 return element->IsHovered() &&
580 element->GetUpDownState() != SpinButtonElement::kIndeterminate;
581 }
582
IsSpinUpButtonPartHovered(const Node * node)583 bool LayoutTheme::IsSpinUpButtonPartHovered(const Node* node) {
584 const auto* element = DynamicTo<SpinButtonElement>(node);
585 if (!element)
586 return false;
587 return element->GetUpDownState() == SpinButtonElement::kUp;
588 }
589
AdjustCheckboxStyle(ComputedStyle & style) const590 void LayoutTheme::AdjustCheckboxStyle(ComputedStyle& style) const {
591 // A summary of the rules for checkbox designed to match WinIE:
592 // width/height - honored (WinIE actually scales its control for small widths,
593 // but lets it overflow for small heights.)
594 // font-size - not honored (control has no text), but we use it to decide
595 // which control size to use.
596 SetCheckboxSize(style);
597
598 // padding - not honored by WinIE, needs to be removed.
599 style.ResetPadding();
600
601 // border - honored by WinIE, but looks terrible (just paints in the control
602 // box and turns off the Windows XP theme) for now, we will not honor it.
603 style.ResetBorder();
604 }
605
AdjustRadioStyle(ComputedStyle & style) const606 void LayoutTheme::AdjustRadioStyle(ComputedStyle& style) const {
607 // A summary of the rules for checkbox designed to match WinIE:
608 // width/height - honored (WinIE actually scales its control for small widths,
609 // but lets it overflow for small heights.)
610 // font-size - not honored (control has no text), but we use it to decide
611 // which control size to use.
612 SetRadioSize(style);
613
614 // padding - not honored by WinIE, needs to be removed.
615 style.ResetPadding();
616
617 // border - honored by WinIE, but looks terrible (just paints in the control
618 // box and turns off the Windows XP theme) for now, we will not honor it.
619 style.ResetBorder();
620 }
621
AdjustButtonStyle(ComputedStyle & style) const622 void LayoutTheme::AdjustButtonStyle(ComputedStyle& style) const {}
623
AdjustInnerSpinButtonStyle(ComputedStyle &) const624 void LayoutTheme::AdjustInnerSpinButtonStyle(ComputedStyle&) const {}
625
AdjustMenuListStyle(ComputedStyle & style,Element *) const626 void LayoutTheme::AdjustMenuListStyle(ComputedStyle& style, Element*) const {
627 // Menulists should have visible overflow
628 // https://bugs.webkit.org/show_bug.cgi?id=21287
629 style.SetOverflowX(EOverflow::kVisible);
630 style.SetOverflowY(EOverflow::kVisible);
631 }
632
AnimationRepeatIntervalForProgressBar() const633 base::TimeDelta LayoutTheme::AnimationRepeatIntervalForProgressBar() const {
634 return base::TimeDelta();
635 }
636
AnimationDurationForProgressBar() const637 base::TimeDelta LayoutTheme::AnimationDurationForProgressBar() const {
638 return base::TimeDelta();
639 }
640
ShouldHaveSpinButton(HTMLInputElement * input_element) const641 bool LayoutTheme::ShouldHaveSpinButton(HTMLInputElement* input_element) const {
642 return input_element->IsSteppable() &&
643 input_element->type() != input_type_names::kRange;
644 }
645
AdjustMenuListButtonStyle(ComputedStyle &,Element *) const646 void LayoutTheme::AdjustMenuListButtonStyle(ComputedStyle&, Element*) const {}
647
AdjustSliderContainerStyle(ComputedStyle & style,Element * e) const648 void LayoutTheme::AdjustSliderContainerStyle(ComputedStyle& style,
649 Element* e) const {
650 if (e && (e->ShadowPseudoId() == "-webkit-media-slider-container" ||
651 e->ShadowPseudoId() == "-webkit-slider-container")) {
652 if (style.EffectiveAppearance() == kSliderVerticalPart) {
653 style.SetTouchAction(TouchAction::kPanX);
654 style.SetEffectiveAppearance(kNoControlPart);
655 style.SetWritingMode(WritingMode::kVerticalRl);
656 // It's always in RTL because the slider value increases up even in LTR.
657 style.SetDirection(TextDirection::kRtl);
658 } else {
659 style.SetTouchAction(TouchAction::kPanY);
660 style.SetEffectiveAppearance(kNoControlPart);
661 style.SetWritingMode(WritingMode::kHorizontalTb);
662 }
663 }
664 }
665
AdjustSliderThumbStyle(ComputedStyle & style) const666 void LayoutTheme::AdjustSliderThumbStyle(ComputedStyle& style) const {
667 AdjustSliderThumbSize(style);
668 }
669
AdjustSliderThumbSize(ComputedStyle &) const670 void LayoutTheme::AdjustSliderThumbSize(ComputedStyle&) const {}
671
AdjustSearchFieldStyle(ComputedStyle &) const672 void LayoutTheme::AdjustSearchFieldStyle(ComputedStyle&) const {}
673
AdjustSearchFieldCancelButtonStyle(ComputedStyle &) const674 void LayoutTheme::AdjustSearchFieldCancelButtonStyle(ComputedStyle&) const {}
675
PlatformColorsDidChange()676 void LayoutTheme::PlatformColorsDidChange() {
677 Page::PlatformColorsChanged();
678 }
679
ColorSchemeDidChange()680 void LayoutTheme::ColorSchemeDidChange() {
681 Page::ColorSchemeChanged();
682 }
683
SetCaretBlinkInterval(base::TimeDelta interval)684 void LayoutTheme::SetCaretBlinkInterval(base::TimeDelta interval) {
685 caret_blink_interval_ = interval;
686 }
687
CaretBlinkInterval() const688 base::TimeDelta LayoutTheme::CaretBlinkInterval() const {
689 // Disable the blinking caret in web test mode, as it introduces
690 // a race condition for the pixel tests. http://b/1198440
691 return WebTestSupport::IsRunningWebTest() ? base::TimeDelta()
692 : caret_blink_interval_;
693 }
694
GetCachedFontDescription(CSSValueID system_font_id)695 static FontDescription& GetCachedFontDescription(CSSValueID system_font_id) {
696 DEFINE_STATIC_LOCAL(FontDescription, caption, ());
697 DEFINE_STATIC_LOCAL(FontDescription, icon, ());
698 DEFINE_STATIC_LOCAL(FontDescription, menu, ());
699 DEFINE_STATIC_LOCAL(FontDescription, message_box, ());
700 DEFINE_STATIC_LOCAL(FontDescription, small_caption, ());
701 DEFINE_STATIC_LOCAL(FontDescription, status_bar, ());
702 DEFINE_STATIC_LOCAL(FontDescription, webkit_mini_control, ());
703 DEFINE_STATIC_LOCAL(FontDescription, webkit_small_control, ());
704 DEFINE_STATIC_LOCAL(FontDescription, webkit_control, ());
705 DEFINE_STATIC_LOCAL(FontDescription, default_description, ());
706 switch (system_font_id) {
707 case CSSValueID::kCaption:
708 return caption;
709 case CSSValueID::kIcon:
710 return icon;
711 case CSSValueID::kMenu:
712 return menu;
713 case CSSValueID::kMessageBox:
714 return message_box;
715 case CSSValueID::kSmallCaption:
716 return small_caption;
717 case CSSValueID::kStatusBar:
718 return status_bar;
719 case CSSValueID::kWebkitMiniControl:
720 return webkit_mini_control;
721 case CSSValueID::kWebkitSmallControl:
722 return webkit_small_control;
723 case CSSValueID::kWebkitControl:
724 return webkit_control;
725 case CSSValueID::kNone:
726 return default_description;
727 default:
728 NOTREACHED();
729 return default_description;
730 }
731 }
732
SystemFont(CSSValueID system_font_id,FontDescription & font_description)733 void LayoutTheme::SystemFont(CSSValueID system_font_id,
734 FontDescription& font_description) {
735 font_description = GetCachedFontDescription(system_font_id);
736 if (font_description.IsAbsoluteSize())
737 return;
738
739 FontSelectionValue font_slope = NormalSlopeValue();
740 FontSelectionValue font_weight = NormalWeightValue();
741 float font_size = 0;
742 AtomicString font_family;
743 SystemFont(system_font_id, font_slope, font_weight, font_size, font_family);
744 font_description.SetStyle(font_slope);
745 font_description.SetWeight(font_weight);
746 font_description.SetSpecifiedSize(font_size);
747 font_description.SetIsAbsoluteSize(true);
748 font_description.FirstFamily().SetFamily(font_family);
749 font_description.SetGenericFamily(FontDescription::kNoFamily);
750 }
751
SystemColor(CSSValueID css_value_id,WebColorScheme color_scheme) const752 Color LayoutTheme::SystemColor(CSSValueID css_value_id,
753 WebColorScheme color_scheme) const {
754 switch (css_value_id) {
755 case CSSValueID::kActiveborder:
756 return 0xFFFFFFFF;
757 case CSSValueID::kActivecaption:
758 return 0xFFCCCCCC;
759 case CSSValueID::kActivetext:
760 return 0xFFFF0000;
761 case CSSValueID::kAppworkspace:
762 return color_scheme == WebColorScheme::kDark ? 0xFF000000 : 0xFFFFFFFF;
763 case CSSValueID::kBackground:
764 return 0xFF6363CE;
765 case CSSValueID::kButtonface:
766 return color_scheme == WebColorScheme::kDark ? 0xFF404040 : 0xFFC0C0C0;
767 case CSSValueID::kButtonhighlight:
768 return 0xFFDDDDDD;
769 case CSSValueID::kButtonshadow:
770 return 0xFF888888;
771 case CSSValueID::kButtontext:
772 return color_scheme == WebColorScheme::kDark ? 0xFFAAAAAA : 0xFF000000;
773 case CSSValueID::kCaptiontext:
774 return color_scheme == WebColorScheme::kDark ? 0xFFFFFFFF : 0xFF000000;
775 case CSSValueID::kField:
776 return color_scheme == WebColorScheme::kDark ? 0xFF000000 : 0xFFFFFFFF;
777 case CSSValueID::kFieldtext:
778 return color_scheme == WebColorScheme::kDark ? 0xFFFFFFFF : 0xFF000000;
779 case CSSValueID::kGraytext:
780 return 0xFF808080;
781 case CSSValueID::kHighlight:
782 return 0xFFB5D5FF;
783 case CSSValueID::kHighlighttext:
784 return color_scheme == WebColorScheme::kDark ? 0xFFFFFFFF : 0xFF000000;
785 case CSSValueID::kInactiveborder:
786 return 0xFFFFFFFF;
787 case CSSValueID::kInactivecaption:
788 return 0xFFFFFFFF;
789 case CSSValueID::kInactivecaptiontext:
790 return 0xFF7F7F7F;
791 case CSSValueID::kInfobackground:
792 return color_scheme == WebColorScheme::kDark ? 0xFFB46E32 : 0xFFFBFCC5;
793 case CSSValueID::kInfotext:
794 return color_scheme == WebColorScheme::kDark ? 0xFFFFFFFF : 0xFF000000;
795 case CSSValueID::kLinktext:
796 return 0xFF0000EE;
797 case CSSValueID::kMenu:
798 return color_scheme == WebColorScheme::kDark ? 0xFF404040 : 0xFFC0C0C0;
799 case CSSValueID::kMenutext:
800 return color_scheme == WebColorScheme::kDark ? 0xFFFFFFFF : 0xFF000000;
801 case CSSValueID::kScrollbar:
802 return 0xFFFFFFFF;
803 case CSSValueID::kText:
804 return color_scheme == WebColorScheme::kDark ? 0xFFFFFFFF : 0xFF000000;
805 case CSSValueID::kThreeddarkshadow:
806 return 0xFF666666;
807 case CSSValueID::kThreedface:
808 return 0xFFC0C0C0;
809 case CSSValueID::kThreedhighlight:
810 return 0xFFDDDDDD;
811 case CSSValueID::kThreedlightshadow:
812 return 0xFFC0C0C0;
813 case CSSValueID::kThreedshadow:
814 return 0xFF888888;
815 case CSSValueID::kVisitedtext:
816 return 0xFF551A8B;
817 case CSSValueID::kWindow:
818 case CSSValueID::kCanvas:
819 return color_scheme == WebColorScheme::kDark ? 0xFF000000 : 0xFFFFFFFF;
820 case CSSValueID::kWindowframe:
821 return 0xFFCCCCCC;
822 case CSSValueID::kWindowtext:
823 case CSSValueID::kCanvastext:
824 return color_scheme == WebColorScheme::kDark ? 0xFFFFFFFF : 0xFF000000;
825 case CSSValueID::kInternalActiveListBoxSelection:
826 return ActiveListBoxSelectionBackgroundColor(color_scheme);
827 case CSSValueID::kInternalActiveListBoxSelectionText:
828 return ActiveListBoxSelectionForegroundColor(color_scheme);
829 case CSSValueID::kInternalInactiveListBoxSelection:
830 return InactiveListBoxSelectionBackgroundColor(color_scheme);
831 case CSSValueID::kInternalInactiveListBoxSelectionText:
832 return InactiveListBoxSelectionForegroundColor(color_scheme);
833 default:
834 break;
835 }
836 NOTREACHED();
837 return Color();
838 }
839
PlatformTextSearchHighlightColor(bool active_match,bool in_forced_colors_mode,WebColorScheme color_scheme) const840 Color LayoutTheme::PlatformTextSearchHighlightColor(
841 bool active_match,
842 bool in_forced_colors_mode,
843 WebColorScheme color_scheme) const {
844 if (active_match) {
845 if (in_forced_colors_mode)
846 return GetTheme().SystemColor(CSSValueID::kHighlight, color_scheme);
847 return Color(255, 150, 50); // Orange.
848 }
849 return Color(255, 255, 0); // Yellow.
850 }
851
PlatformTextSearchColor(bool active_match,bool in_forced_colors_mode,WebColorScheme color_scheme) const852 Color LayoutTheme::PlatformTextSearchColor(bool active_match,
853 bool in_forced_colors_mode,
854 WebColorScheme color_scheme) const {
855 if (in_forced_colors_mode && active_match)
856 return GetTheme().SystemColor(CSSValueID::kHighlighttext, color_scheme);
857 return Color::kBlack;
858 }
859
TapHighlightColor()860 Color LayoutTheme::TapHighlightColor() {
861 return GetTheme().PlatformTapHighlightColor();
862 }
863
SetCustomFocusRingColor(const Color & c)864 void LayoutTheme::SetCustomFocusRingColor(const Color& c) {
865 custom_focus_ring_color_ = c;
866 has_custom_focus_ring_color_ = true;
867 }
868
IsFocusRingOutset() const869 bool LayoutTheme::IsFocusRingOutset() const {
870 return false;
871 }
872
FocusRingColor() const873 Color LayoutTheme::FocusRingColor() const {
874 return has_custom_focus_ring_color_ ? custom_focus_ring_color_
875 : GetTheme().PlatformFocusRingColor();
876 }
877
DelegatesMenuListRendering() const878 bool LayoutTheme::DelegatesMenuListRendering() const {
879 return delegates_menu_list_rendering_;
880 }
881
SetDelegatesMenuListRenderingForTesting(bool flag)882 void LayoutTheme::SetDelegatesMenuListRenderingForTesting(bool flag) {
883 delegates_menu_list_rendering_ = flag;
884 }
885
DisplayNameForFile(const File & file) const886 String LayoutTheme::DisplayNameForFile(const File& file) const {
887 return file.name();
888 }
889
ShouldOpenPickerWithF4Key() const890 bool LayoutTheme::ShouldOpenPickerWithF4Key() const {
891 return false;
892 }
893
SupportsCalendarPicker(const AtomicString & type) const894 bool LayoutTheme::SupportsCalendarPicker(const AtomicString& type) const {
895 DCHECK(RuntimeEnabledFeatures::InputMultipleFieldsUIEnabled());
896 if (features::IsFormControlsRefreshEnabled() &&
897 type == input_type_names::kTime)
898 return true;
899
900 return type == input_type_names::kDate ||
901 type == input_type_names::kDatetime ||
902 type == input_type_names::kDatetimeLocal ||
903 type == input_type_names::kMonth || type == input_type_names::kWeek;
904 }
905
ShouldUseFallbackTheme(const ComputedStyle &) const906 bool LayoutTheme::ShouldUseFallbackTheme(const ComputedStyle&) const {
907 return false;
908 }
909
AdjustStyleUsingFallbackTheme(ComputedStyle & style)910 void LayoutTheme::AdjustStyleUsingFallbackTheme(ComputedStyle& style) {
911 ControlPart part = style.EffectiveAppearance();
912 switch (part) {
913 case kCheckboxPart:
914 return AdjustCheckboxStyleUsingFallbackTheme(style);
915 case kRadioPart:
916 return AdjustRadioStyleUsingFallbackTheme(style);
917 default:
918 break;
919 }
920 }
921
922 // static
SetSizeIfAuto(ComputedStyle & style,const IntSize & size)923 void LayoutTheme::SetSizeIfAuto(ComputedStyle& style, const IntSize& size) {
924 if (style.Width().IsIntrinsicOrAuto())
925 style.SetWidth(Length::Fixed(size.Width()));
926 if (style.Height().IsIntrinsicOrAuto())
927 style.SetHeight(Length::Fixed(size.Height()));
928 }
929
930 // static
SetMinimumSize(ComputedStyle & style,const LengthSize * part_size,const LengthSize * min_part_size)931 void LayoutTheme::SetMinimumSize(ComputedStyle& style,
932 const LengthSize* part_size,
933 const LengthSize* min_part_size) {
934 DCHECK(part_size || min_part_size);
935 // We only want to set a minimum size if no explicit size is specified, to
936 // avoid overriding author intentions.
937 if (part_size && style.MinWidth().IsIntrinsicOrAuto() &&
938 style.Width().IsIntrinsicOrAuto())
939 style.SetMinWidth(part_size->Width());
940 else if (min_part_size && min_part_size->Width() != style.MinWidth())
941 style.SetMinWidth(min_part_size->Width());
942 if (part_size && style.MinHeight().IsIntrinsicOrAuto() &&
943 style.Height().IsIntrinsicOrAuto())
944 style.SetMinHeight(part_size->Height());
945 else if (min_part_size && min_part_size->Height() != style.MinHeight())
946 style.SetMinHeight(min_part_size->Height());
947 }
948
949 // static
SetMinimumSizeIfAuto(ComputedStyle & style,const IntSize & size)950 void LayoutTheme::SetMinimumSizeIfAuto(ComputedStyle& style,
951 const IntSize& size) {
952 LengthSize length_size(Length::Fixed(size.Width()),
953 Length::Fixed(size.Height()));
954 SetMinimumSize(style, &length_size);
955 }
956
AdjustCheckboxStyleUsingFallbackTheme(ComputedStyle & style) const957 void LayoutTheme::AdjustCheckboxStyleUsingFallbackTheme(
958 ComputedStyle& style) const {
959 // If the width and height are both specified, then we have nothing to do.
960 if (!style.Width().IsIntrinsicOrAuto() && !style.Height().IsAuto())
961 return;
962
963 IntSize size(GetFallbackTheme().GetPartSize(ui::NativeTheme::kCheckbox,
964 ui::NativeTheme::kNormal,
965 ui::NativeTheme::ExtraParams()));
966 float zoom_level = style.EffectiveZoom();
967 size.SetWidth(size.Width() * zoom_level);
968 size.SetHeight(size.Height() * zoom_level);
969 SetMinimumSizeIfAuto(style, size);
970 SetSizeIfAuto(style, size);
971
972 // padding - not honored by WinIE, needs to be removed.
973 style.ResetPadding();
974
975 // border - honored by WinIE, but looks terrible (just paints in the control
976 // box and turns off the Windows XP theme)
977 // for now, we will not honor it.
978 style.ResetBorder();
979 }
980
AdjustRadioStyleUsingFallbackTheme(ComputedStyle & style) const981 void LayoutTheme::AdjustRadioStyleUsingFallbackTheme(
982 ComputedStyle& style) const {
983 // If the width and height are both specified, then we have nothing to do.
984 if (!style.Width().IsIntrinsicOrAuto() && !style.Height().IsAuto())
985 return;
986
987 IntSize size(GetFallbackTheme().GetPartSize(ui::NativeTheme::kRadio,
988 ui::NativeTheme::kNormal,
989 ui::NativeTheme::ExtraParams()));
990 float zoom_level = style.EffectiveZoom();
991 size.SetWidth(size.Width() * zoom_level);
992 size.SetHeight(size.Height() * zoom_level);
993 SetMinimumSizeIfAuto(style, size);
994 SetSizeIfAuto(style, size);
995
996 // padding - not honored by WinIE, needs to be removed.
997 style.ResetPadding();
998
999 // border - honored by WinIE, but looks terrible (just paints in the control
1000 // box and turns off the Windows XP theme)
1001 // for now, we will not honor it.
1002 style.ResetBorder();
1003 }
1004
ControlPadding(ControlPart part,const FontDescription &,const Length & zoomed_box_top,const Length & zoomed_box_right,const Length & zoomed_box_bottom,const Length & zoomed_box_left,float) const1005 LengthBox LayoutTheme::ControlPadding(ControlPart part,
1006 const FontDescription&,
1007 const Length& zoomed_box_top,
1008 const Length& zoomed_box_right,
1009 const Length& zoomed_box_bottom,
1010 const Length& zoomed_box_left,
1011 float) const {
1012 switch (part) {
1013 case kMenulistPart:
1014 case kMenulistButtonPart:
1015 case kCheckboxPart:
1016 case kRadioPart:
1017 return LengthBox(0);
1018 default:
1019 return LengthBox(zoomed_box_top, zoomed_box_right, zoomed_box_bottom,
1020 zoomed_box_left);
1021 }
1022 }
1023
ControlBorder(ControlPart part,const FontDescription &,const LengthBox & zoomed_box,float) const1024 LengthBox LayoutTheme::ControlBorder(ControlPart part,
1025 const FontDescription&,
1026 const LengthBox& zoomed_box,
1027 float) const {
1028 switch (part) {
1029 case kPushButtonPart:
1030 case kMenulistPart:
1031 case kSearchFieldPart:
1032 case kCheckboxPart:
1033 case kRadioPart:
1034 return LengthBox(0);
1035 default:
1036 return zoomed_box;
1037 }
1038 }
1039
AdjustControlPartStyle(ComputedStyle & style)1040 void LayoutTheme::AdjustControlPartStyle(ComputedStyle& style) {
1041 // Call the appropriate style adjustment method based off the appearance
1042 // value.
1043 switch (style.EffectiveAppearance()) {
1044 case kCheckboxPart:
1045 return AdjustCheckboxStyle(style);
1046 case kRadioPart:
1047 return AdjustRadioStyle(style);
1048 case kPushButtonPart:
1049 case kSquareButtonPart:
1050 case kButtonPart:
1051 return AdjustButtonStyle(style);
1052 case kInnerSpinButtonPart:
1053 return AdjustInnerSpinButtonStyle(style);
1054 default:
1055 break;
1056 }
1057 }
1058
HasCustomFocusRingColor() const1059 bool LayoutTheme::HasCustomFocusRingColor() const {
1060 return has_custom_focus_ring_color_;
1061 }
1062
GetCustomFocusRingColor() const1063 Color LayoutTheme::GetCustomFocusRingColor() const {
1064 return custom_focus_ring_color_;
1065 }
1066
1067 } // namespace blink
1068