Bug 1700051: part 45) Remove outdated part of comment in <mozInlineSpellChecker.cpp...
[gecko.git] / widget / nsNativeTheme.cpp
blob3c53d84e965d2a50b48227fe1741b404a1b28eb9
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "nsNativeTheme.h"
7 #include "nsIWidget.h"
8 #include "mozilla/dom/Document.h"
9 #include "nsIContent.h"
10 #include "nsIFrame.h"
11 #include "nsIScrollableFrame.h"
12 #include "nsNumberControlFrame.h"
13 #include "nsPresContext.h"
14 #include "nsString.h"
15 #include "nsNameSpaceManager.h"
16 #include "nsStyleConsts.h"
17 #include "nsPIDOMWindow.h"
18 #include "nsProgressFrame.h"
19 #include "nsMeterFrame.h"
20 #include "nsMenuFrame.h"
21 #include "nsRangeFrame.h"
22 #include "nsCSSRendering.h"
23 #include "ImageContainer.h"
24 #include "mozilla/ComputedStyle.h"
25 #include "mozilla/EventStates.h"
26 #include "mozilla/dom/Element.h"
27 #include "mozilla/dom/HTMLBodyElement.h"
28 #include "mozilla/dom/HTMLInputElement.h"
29 #include "mozilla/dom/HTMLProgressElement.h"
30 #include "mozilla/PresShell.h"
31 #include "mozilla/StaticPrefs_layout.h"
32 #include "mozilla/dom/DocumentInlines.h"
33 #include <algorithm>
35 using namespace mozilla;
36 using namespace mozilla::dom;
38 nsNativeTheme::nsNativeTheme() : mAnimatedContentTimeout(UINT32_MAX) {}
40 NS_IMPL_ISUPPORTS(nsNativeTheme, nsITimerCallback, nsINamed)
42 /* static */ EventStates nsNativeTheme::GetContentState(
43 nsIFrame* aFrame, StyleAppearance aAppearance) {
44 if (!aFrame) return EventStates();
46 bool isXULCheckboxRadio = (aAppearance == StyleAppearance::Checkbox ||
47 aAppearance == StyleAppearance::Radio) &&
48 aFrame->GetContent()->IsXULElement();
49 if (isXULCheckboxRadio) {
50 aFrame = aFrame->GetParent();
53 if (!aFrame->GetContent()) {
54 return EventStates();
57 nsIContent* frameContent = aFrame->GetContent();
58 EventStates flags;
59 if (frameContent->IsElement()) {
60 flags = frameContent->AsElement()->State();
62 nsNumberControlFrame* numberControlFrame =
63 nsNumberControlFrame::GetNumberControlFrameForSpinButton(aFrame);
64 if (numberControlFrame &&
65 numberControlFrame->GetContent()->AsElement()->State().HasState(
66 NS_EVENT_STATE_DISABLED)) {
67 flags |= NS_EVENT_STATE_DISABLED;
71 if (isXULCheckboxRadio && aAppearance == StyleAppearance::Radio &&
72 IsFocused(aFrame)) {
73 flags |= NS_EVENT_STATE_FOCUS;
74 nsPIDOMWindowOuter* window = aFrame->GetContent()->OwnerDoc()->GetWindow();
75 if (window && window->ShouldShowFocusRing()) {
76 flags |= NS_EVENT_STATE_FOCUSRING;
80 return flags;
83 /* static */
84 bool nsNativeTheme::CheckBooleanAttr(nsIFrame* aFrame, nsAtom* aAtom) {
85 if (!aFrame) return false;
87 nsIContent* content = aFrame->GetContent();
88 if (!content || !content->IsElement()) return false;
90 if (content->IsHTMLElement())
91 return content->AsElement()->HasAttr(kNameSpaceID_None, aAtom);
93 // For XML/XUL elements, an attribute must be equal to the literal
94 // string "true" to be counted as true. An empty string should _not_
95 // be counted as true.
96 return content->AsElement()->AttrValueIs(kNameSpaceID_None, aAtom, u"true"_ns,
97 eCaseMatters);
100 /* static */
101 int32_t nsNativeTheme::CheckIntAttr(nsIFrame* aFrame, nsAtom* aAtom,
102 int32_t defaultValue) {
103 if (!aFrame) return defaultValue;
105 nsIContent* content = aFrame->GetContent();
106 if (!content || !content->IsElement()) return defaultValue;
108 nsAutoString attr;
109 content->AsElement()->GetAttr(kNameSpaceID_None, aAtom, attr);
110 nsresult err;
111 int32_t value = attr.ToInteger(&err);
112 if (attr.IsEmpty() || NS_FAILED(err)) return defaultValue;
114 return value;
117 /* static */
118 double nsNativeTheme::GetProgressValue(nsIFrame* aFrame) {
119 if (!aFrame || !aFrame->GetContent()->IsHTMLElement(nsGkAtoms::progress)) {
120 return 0;
123 return static_cast<HTMLProgressElement*>(aFrame->GetContent())->Value();
126 /* static */
127 double nsNativeTheme::GetProgressMaxValue(nsIFrame* aFrame) {
128 if (!aFrame || !aFrame->GetContent()->IsHTMLElement(nsGkAtoms::progress)) {
129 return 100;
132 return static_cast<HTMLProgressElement*>(aFrame->GetContent())->Max();
135 bool nsNativeTheme::GetCheckedOrSelected(nsIFrame* aFrame,
136 bool aCheckSelected) {
137 if (!aFrame) return false;
139 nsIContent* content = aFrame->GetContent();
141 if (content->IsXULElement()) {
142 // For a XUL checkbox or radio button, the state of the parent determines
143 // the checked state
144 aFrame = aFrame->GetParent();
145 } else {
146 // Check for an HTML input element
147 HTMLInputElement* inputElt = HTMLInputElement::FromNode(content);
148 if (inputElt) {
149 return inputElt->Checked();
153 return CheckBooleanAttr(
154 aFrame, aCheckSelected ? nsGkAtoms::selected : nsGkAtoms::checked);
157 bool nsNativeTheme::IsButtonTypeMenu(nsIFrame* aFrame) {
158 if (!aFrame) return false;
160 nsIContent* content = aFrame->GetContent();
161 return content->IsXULElement(nsGkAtoms::button) &&
162 content->AsElement()->AttrValueIs(kNameSpaceID_None, nsGkAtoms::type,
163 u"menu"_ns, eCaseMatters);
166 bool nsNativeTheme::IsPressedButton(nsIFrame* aFrame) {
167 EventStates eventState =
168 GetContentState(aFrame, StyleAppearance::Toolbarbutton);
169 if (IsDisabled(aFrame, eventState)) return false;
171 return IsOpenButton(aFrame) ||
172 eventState.HasAllStates(NS_EVENT_STATE_ACTIVE | NS_EVENT_STATE_HOVER);
175 bool nsNativeTheme::GetIndeterminate(nsIFrame* aFrame) {
176 if (!aFrame) return false;
178 nsIContent* content = aFrame->GetContent();
180 if (content->IsXULElement()) {
181 // For a XUL checkbox or radio button, the state of the parent determines
182 // the state
183 return CheckBooleanAttr(aFrame->GetParent(), nsGkAtoms::indeterminate);
186 // Check for an HTML input element
187 HTMLInputElement* inputElt = HTMLInputElement::FromNode(content);
188 if (inputElt) {
189 return inputElt->Indeterminate();
192 return false;
195 bool nsNativeTheme::IsWidgetStyled(nsPresContext* aPresContext,
196 nsIFrame* aFrame,
197 StyleAppearance aAppearance) {
198 // Check for specific widgets to see if HTML has overridden the style.
199 if (!aFrame) {
200 return false;
203 // Resizers have some special handling, dependent on whether in a scrollable
204 // container or not. If so, use the scrollable container's to determine
205 // whether the style is overriden instead of the resizer. This allows a
206 // non-native transparent resizer to be used instead. Otherwise, we just
207 // fall through and return false.
208 if (aAppearance == StyleAppearance::Resizer) {
209 nsIFrame* parentFrame = aFrame->GetParent();
210 if (parentFrame && parentFrame->IsScrollFrame()) {
211 // if the parent is a scrollframe, the resizer should be native themed
212 // only if the scrollable area doesn't override the widget style.
214 // note that the condition below looks a bit suspect but it's the right
215 // one. If there's no valid appearance, then we should return true, it's
216 // effectively the same as if it had overridden the appearance.
217 parentFrame = parentFrame->GetParent();
218 if (!parentFrame) {
219 return false;
221 auto parentAppearance =
222 parentFrame->StyleDisplay()->EffectiveAppearance();
223 return parentAppearance == StyleAppearance::None ||
224 IsWidgetStyled(aPresContext, parentFrame, parentAppearance);
229 * Progress bar appearance should be the same for the bar and the container
230 * frame. nsProgressFrame owns the logic and will tell us what we should do.
232 if (aAppearance == StyleAppearance::Progresschunk ||
233 aAppearance == StyleAppearance::ProgressBar) {
234 nsProgressFrame* progressFrame = do_QueryFrame(
235 aAppearance == StyleAppearance::Progresschunk ? aFrame->GetParent()
236 : aFrame);
237 if (progressFrame) {
238 return !progressFrame->ShouldUseNativeStyle();
243 * Meter bar appearance should be the same for the bar and the container
244 * frame. nsMeterFrame owns the logic and will tell us what we should do.
246 if (aAppearance == StyleAppearance::Meterchunk ||
247 aAppearance == StyleAppearance::Meter) {
248 nsMeterFrame* meterFrame = do_QueryFrame(
249 aAppearance == StyleAppearance::Meterchunk ? aFrame->GetParent()
250 : aFrame);
251 if (meterFrame) {
252 return !meterFrame->ShouldUseNativeStyle();
257 * An nsRangeFrame and its children are treated atomically when it
258 * comes to native theming (either all parts, or no parts, are themed).
259 * nsRangeFrame owns the logic and will tell us what we should do.
261 if (aAppearance == StyleAppearance::Range ||
262 aAppearance == StyleAppearance::RangeThumb) {
263 nsRangeFrame* rangeFrame = do_QueryFrame(
264 aAppearance == StyleAppearance::RangeThumb ? aFrame->GetParent()
265 : aFrame);
266 if (rangeFrame) {
267 return !rangeFrame->ShouldUseNativeStyle();
271 return nsLayoutUtils::AuthorSpecifiedBorderBackgroundDisablesTheming(
272 aAppearance) &&
273 aFrame->GetContent()->IsHTMLElement() &&
274 aPresContext->HasAuthorSpecifiedRules(
275 aFrame, NS_AUTHOR_SPECIFIED_BORDER_OR_BACKGROUND);
278 bool nsNativeTheme::IsDisabled(nsIFrame* aFrame, EventStates aEventStates) {
279 if (!aFrame) {
280 return false;
283 nsIContent* content = aFrame->GetContent();
284 if (!content || !content->IsElement()) {
285 return false;
288 if (content->IsHTMLElement()) {
289 return aEventStates.HasState(NS_EVENT_STATE_DISABLED);
292 // For XML/XUL elements, an attribute must be equal to the literal
293 // string "true" to be counted as true. An empty string should _not_
294 // be counted as true.
295 return content->AsElement()->AttrValueIs(
296 kNameSpaceID_None, nsGkAtoms::disabled, u"true"_ns, eCaseMatters);
299 /* static */
300 bool nsNativeTheme::IsFrameRTL(nsIFrame* aFrame) {
301 if (!aFrame) {
302 return false;
304 return aFrame->GetWritingMode().IsPhysicalRTL();
307 /* static */
308 bool nsNativeTheme::IsHTMLContent(nsIFrame* aFrame) {
309 if (!aFrame) {
310 return false;
312 nsIContent* content = aFrame->GetContent();
313 return content && content->IsHTMLElement();
316 // scrollbar button:
317 int32_t nsNativeTheme::GetScrollbarButtonType(nsIFrame* aFrame) {
318 if (!aFrame) return 0;
320 static Element::AttrValuesArray strings[] = {
321 nsGkAtoms::scrollbarDownBottom, nsGkAtoms::scrollbarDownTop,
322 nsGkAtoms::scrollbarUpBottom, nsGkAtoms::scrollbarUpTop, nullptr};
324 nsIContent* content = aFrame->GetContent();
325 if (!content || !content->IsElement()) {
326 return 0;
329 switch (content->AsElement()->FindAttrValueIn(
330 kNameSpaceID_None, nsGkAtoms::sbattr, strings, eCaseMatters)) {
331 case 0:
332 return eScrollbarButton_Down | eScrollbarButton_Bottom;
333 case 1:
334 return eScrollbarButton_Down;
335 case 2:
336 return eScrollbarButton_Bottom;
337 case 3:
338 return eScrollbarButton_UpTop;
341 return 0;
344 // treeheadercell:
345 nsNativeTheme::TreeSortDirection nsNativeTheme::GetTreeSortDirection(
346 nsIFrame* aFrame) {
347 if (!aFrame || !aFrame->GetContent()) return eTreeSortDirection_Natural;
349 static Element::AttrValuesArray strings[] = {nsGkAtoms::descending,
350 nsGkAtoms::ascending, nullptr};
352 nsIContent* content = aFrame->GetContent();
353 if (content->IsElement()) {
354 switch (content->AsElement()->FindAttrValueIn(
355 kNameSpaceID_None, nsGkAtoms::sortDirection, strings, eCaseMatters)) {
356 case 0:
357 return eTreeSortDirection_Descending;
358 case 1:
359 return eTreeSortDirection_Ascending;
363 return eTreeSortDirection_Natural;
366 bool nsNativeTheme::IsLastTreeHeaderCell(nsIFrame* aFrame) {
367 if (!aFrame) return false;
369 // A tree column picker is always the last header cell.
370 if (aFrame->GetContent()->IsXULElement(nsGkAtoms::treecolpicker)) return true;
372 // Find the parent tree.
373 nsIContent* parent = aFrame->GetContent()->GetParent();
374 while (parent && !parent->IsXULElement(nsGkAtoms::tree)) {
375 parent = parent->GetParent();
378 // If the column picker is visible, this can't be the last column.
379 if (parent && !parent->AsElement()->AttrValueIs(kNameSpaceID_None,
380 nsGkAtoms::hidecolumnpicker,
381 u"true"_ns, eCaseMatters))
382 return false;
384 while ((aFrame = aFrame->GetNextSibling())) {
385 if (aFrame->GetRect().Width() > 0) return false;
387 return true;
390 // tab:
391 bool nsNativeTheme::IsBottomTab(nsIFrame* aFrame) {
392 if (!aFrame) return false;
394 nsAutoString classStr;
395 if (aFrame->GetContent()->IsElement()) {
396 aFrame->GetContent()->AsElement()->GetAttr(kNameSpaceID_None,
397 nsGkAtoms::_class, classStr);
399 // FIXME: This looks bogus, shouldn't this be looking at GetClasses()?
400 return !classStr.IsEmpty() && classStr.Find("tab-bottom") != kNotFound;
403 bool nsNativeTheme::IsFirstTab(nsIFrame* aFrame) {
404 if (!aFrame) return false;
406 for (nsIFrame* first : aFrame->GetParent()->PrincipalChildList()) {
407 if (first->GetRect().Width() > 0 &&
408 first->GetContent()->IsXULElement(nsGkAtoms::tab))
409 return (first == aFrame);
411 return false;
414 bool nsNativeTheme::IsHorizontal(nsIFrame* aFrame) {
415 if (!aFrame) return false;
417 if (!aFrame->GetContent()->IsElement()) return true;
419 return !aFrame->GetContent()->AsElement()->AttrValueIs(
420 kNameSpaceID_None, nsGkAtoms::orient, nsGkAtoms::vertical, eCaseMatters);
423 bool nsNativeTheme::IsNextToSelectedTab(nsIFrame* aFrame, int32_t aOffset) {
424 if (!aFrame) return false;
426 if (aOffset == 0) return IsSelectedTab(aFrame);
428 int32_t thisTabIndex = -1, selectedTabIndex = -1;
430 nsIFrame* currentTab = aFrame->GetParent()->PrincipalChildList().FirstChild();
431 for (int32_t i = 0; currentTab; currentTab = currentTab->GetNextSibling()) {
432 if (currentTab->GetRect().Width() == 0) continue;
433 if (aFrame == currentTab) thisTabIndex = i;
434 if (IsSelectedTab(currentTab)) selectedTabIndex = i;
435 ++i;
438 if (thisTabIndex == -1 || selectedTabIndex == -1) return false;
440 return (thisTabIndex - selectedTabIndex == aOffset);
443 bool nsNativeTheme::IsIndeterminateProgress(nsIFrame* aFrame,
444 EventStates aEventStates) {
445 if (!aFrame || !aFrame->GetContent() ||
446 !aFrame->GetContent()->IsHTMLElement(nsGkAtoms::progress)) {
447 return false;
450 return aEventStates.HasState(NS_EVENT_STATE_INDETERMINATE);
453 bool nsNativeTheme::IsVerticalProgress(nsIFrame* aFrame) {
454 if (!aFrame) {
455 return false;
457 return IsVerticalMeter(aFrame);
460 bool nsNativeTheme::IsVerticalMeter(nsIFrame* aFrame) {
461 MOZ_ASSERT(aFrame, "You have to pass a non-null aFrame");
462 switch (aFrame->StyleDisplay()->mOrient) {
463 case StyleOrient::Horizontal:
464 return false;
465 case StyleOrient::Vertical:
466 return true;
467 case StyleOrient::Inline:
468 return aFrame->GetWritingMode().IsVertical();
469 case StyleOrient::Block:
470 return !aFrame->GetWritingMode().IsVertical();
472 MOZ_ASSERT_UNREACHABLE("unexpected -moz-orient value");
473 return false;
476 // menupopup:
477 bool nsNativeTheme::IsSubmenu(nsIFrame* aFrame, bool* aLeftOfParent) {
478 if (!aFrame) return false;
480 nsIContent* parentContent = aFrame->GetContent()->GetParent();
481 if (!parentContent || !parentContent->IsXULElement(nsGkAtoms::menu))
482 return false;
484 nsIFrame* parent = aFrame;
485 while ((parent = parent->GetParent())) {
486 if (parent->GetContent() == parentContent) {
487 if (aLeftOfParent) {
488 LayoutDeviceIntRect selfBounds, parentBounds;
489 selfBounds = aFrame->GetNearestWidget()->GetScreenBounds();
490 parentBounds = parent->GetNearestWidget()->GetScreenBounds();
491 *aLeftOfParent = selfBounds.X() < parentBounds.X();
493 return true;
497 return false;
500 bool nsNativeTheme::IsRegularMenuItem(nsIFrame* aFrame) {
501 nsMenuFrame* menuFrame = do_QueryFrame(aFrame);
502 return !(menuFrame &&
503 (menuFrame->IsOnMenuBar() || menuFrame->IsParentMenuList()));
506 bool nsNativeTheme::QueueAnimatedContentForRefresh(nsIContent* aContent,
507 uint32_t aMinimumFrameRate) {
508 NS_ASSERTION(aContent, "Null pointer!");
509 NS_ASSERTION(aMinimumFrameRate, "aMinimumFrameRate must be non-zero!");
510 NS_ASSERTION(aMinimumFrameRate <= 1000,
511 "aMinimumFrameRate must be less than 1000!");
513 uint32_t timeout = 1000 / aMinimumFrameRate;
514 timeout = std::min(mAnimatedContentTimeout, timeout);
516 if (!mAnimatedContentTimer) {
517 mAnimatedContentTimer = NS_NewTimer();
518 NS_ENSURE_TRUE(mAnimatedContentTimer, false);
521 if (mAnimatedContentList.IsEmpty() || timeout != mAnimatedContentTimeout) {
522 nsresult rv;
523 if (!mAnimatedContentList.IsEmpty()) {
524 rv = mAnimatedContentTimer->Cancel();
525 NS_ENSURE_SUCCESS(rv, false);
528 if (XRE_IsContentProcess() && NS_IsMainThread()) {
529 mAnimatedContentTimer->SetTarget(
530 aContent->OwnerDoc()->EventTargetFor(TaskCategory::Other));
532 rv = mAnimatedContentTimer->InitWithCallback(this, timeout,
533 nsITimer::TYPE_ONE_SHOT);
534 NS_ENSURE_SUCCESS(rv, false);
536 mAnimatedContentTimeout = timeout;
539 // XXX(Bug 1631371) Check if this should use a fallible operation as it
540 // pretended earlier.
541 mAnimatedContentList.AppendElement(aContent);
543 return true;
546 NS_IMETHODIMP
547 nsNativeTheme::Notify(nsITimer* aTimer) {
548 NS_ASSERTION(aTimer == mAnimatedContentTimer, "Wrong timer!");
550 // XXX Assumes that calling nsIFrame::Invalidate won't reenter
551 // QueueAnimatedContentForRefresh.
553 uint32_t count = mAnimatedContentList.Length();
554 for (uint32_t index = 0; index < count; index++) {
555 nsIFrame* frame = mAnimatedContentList[index]->GetPrimaryFrame();
556 if (frame) {
557 frame->InvalidateFrame();
561 mAnimatedContentList.Clear();
562 mAnimatedContentTimeout = UINT32_MAX;
563 return NS_OK;
566 NS_IMETHODIMP
567 nsNativeTheme::GetName(nsACString& aName) {
568 aName.AssignLiteral("nsNativeTheme");
569 return NS_OK;
572 nsIFrame* nsNativeTheme::GetAdjacentSiblingFrameWithSameAppearance(
573 nsIFrame* aFrame, bool aNextSibling) {
574 if (!aFrame) return nullptr;
576 // Find the next visible sibling.
577 nsIFrame* sibling = aFrame;
578 do {
579 sibling =
580 aNextSibling ? sibling->GetNextSibling() : sibling->GetPrevSibling();
581 } while (sibling && sibling->GetRect().Width() == 0);
583 // Check same appearance and adjacency.
584 if (!sibling ||
585 sibling->StyleDisplay()->EffectiveAppearance() !=
586 aFrame->StyleDisplay()->EffectiveAppearance() ||
587 (sibling->GetRect().XMost() != aFrame->GetRect().X() &&
588 aFrame->GetRect().XMost() != sibling->GetRect().X()))
589 return nullptr;
590 return sibling;
593 bool nsNativeTheme::IsRangeHorizontal(nsIFrame* aFrame) {
594 nsIFrame* rangeFrame = aFrame;
595 if (!rangeFrame->IsRangeFrame()) {
596 // If the thumb's frame is passed in, get its range parent:
597 rangeFrame = aFrame->GetParent();
599 if (rangeFrame->IsRangeFrame()) {
600 return static_cast<nsRangeFrame*>(rangeFrame)->IsHorizontal();
602 // Not actually a range frame - just use the ratio of the frame's size to
603 // decide:
604 return aFrame->GetSize().width >= aFrame->GetSize().height;
607 static nsIFrame* GetBodyFrame(nsIFrame* aCanvasFrame) {
608 nsIContent* body = aCanvasFrame->PresContext()->Document()->GetBodyElement();
609 if (!body) {
610 return nullptr;
612 return body->GetPrimaryFrame();
615 /* static */
616 bool nsNativeTheme::IsDarkBackground(nsIFrame* aFrame) {
617 // Try to find the scrolled frame. Note that for stuff like xul <tree> there
618 // might be none.
620 nsIFrame* frame = aFrame;
621 nsIScrollableFrame* scrollFrame = nullptr;
622 while (!scrollFrame && frame) {
623 scrollFrame = frame->GetScrollTargetFrame();
624 frame = frame->GetParent();
626 if (scrollFrame) {
627 aFrame = scrollFrame->GetScrolledFrame();
628 } else {
629 // Leave aFrame untouched.
633 auto backgroundFrame = nsCSSRendering::FindNonTransparentBackgroundFrame(
634 aFrame, /* aStopAtThemed = */ false);
635 if (!backgroundFrame.mFrame) {
636 return false;
639 nscolor color = backgroundFrame.mFrame->StyleBackground()->BackgroundColor(
640 backgroundFrame.mFrame);
642 if (backgroundFrame.mIsForCanvas) {
643 // For canvas frames, prefer to look at the body first, because the body
644 // background color is most likely what will be visible as the background
645 // color of the page, even if the html element has a different background
646 // color which prevents that of the body frame to propagate to the viewport.
647 if (nsIFrame* bodyFrame = GetBodyFrame(aFrame)) {
648 nscolor bodyColor =
649 bodyFrame->StyleBackground()->BackgroundColor(bodyFrame);
650 if (NS_GET_A(bodyColor)) {
651 color = bodyColor;
656 return IsDarkColor(color);
659 /*static*/
660 bool nsNativeTheme::IsWidgetScrollbarPart(StyleAppearance aAppearance) {
661 switch (aAppearance) {
662 case StyleAppearance::ScrollbarVertical:
663 case StyleAppearance::ScrollbarHorizontal:
664 case StyleAppearance::ScrollbarbuttonUp:
665 case StyleAppearance::ScrollbarbuttonDown:
666 case StyleAppearance::ScrollbarbuttonLeft:
667 case StyleAppearance::ScrollbarbuttonRight:
668 case StyleAppearance::ScrollbarthumbVertical:
669 case StyleAppearance::ScrollbarthumbHorizontal:
670 case StyleAppearance::ScrollbartrackHorizontal:
671 case StyleAppearance::ScrollbartrackVertical:
672 case StyleAppearance::Scrollcorner:
673 return true;
674 default:
675 return false;