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/. */
5 
6 #ifndef __LookAndFeel
7 #define __LookAndFeel
8 
9 #ifndef MOZILLA_INTERNAL_API
10 #  error "This header is only usable from within libxul (MOZILLA_INTERNAL_API)."
11 #endif
12 
13 #include "nsDebug.h"
14 #include "nsColor.h"
15 #include "nsString.h"
16 #include "nsTArray.h"
17 #include "mozilla/Maybe.h"
18 #include "mozilla/widget/ThemeChangeKind.h"
19 #include "mozilla/ColorScheme.h"
20 
21 struct gfxFontStyle;
22 
23 class nsIFrame;
24 
25 namespace mozilla {
26 
27 struct StyleColorSchemeFlags;
28 
29 namespace dom {
30 class Document;
31 }
32 
33 namespace widget {
34 class FullLookAndFeel;
35 }  // namespace widget
36 
37 enum class StyleSystemColor : uint8_t;
38 enum class StyleSystemColorScheme : uint8_t;
39 enum class StyleSystemFont : uint8_t;
40 
41 class LookAndFeel {
42  public:
43   using ColorID = StyleSystemColor;
44   using ColorScheme = mozilla::ColorScheme;
45 
46   // When modifying this list, also modify nsXPLookAndFeel::sIntPrefs
47   // in widget/xpwidgts/nsXPLookAndFeel.cpp.
48   enum class IntID {
49     // default, may be overriden by OS
50     CaretBlinkTime,
51     // Amount of blinks that happen before the caret stops blinking.
52     CaretBlinkCount,
53     // pixel width of caret
54     CaretWidth,
55     // show the caret when text is selected?
56     ShowCaretDuringSelection,
57     // select textfields when focused via tab/accesskey?
58     SelectTextfieldsOnKeyFocus,
59     // delay before submenus open
60     SubmenuDelay,
61     // can popups overlap menu/task bar?
62     MenusCanOverlapOSBar,
63     // should overlay scrollbars be used?
64     UseOverlayScrollbars,
65     // allow H and V overlay scrollbars to overlap?
66     AllowOverlayScrollbarsOverlap,
67     // skip navigating to disabled menu item?
68     SkipNavigatingDisabledMenuItem,
69     // begin a drag if the mouse is moved further than the threshold while the
70     // button is down
71     DragThresholdX,
72     DragThresholdY,
73     // Accessibility theme being used?
74     UseAccessibilityTheme,
75 
76     // position of scroll arrows in a scrollbar
77     ScrollArrowStyle,
78     // is scroll thumb proportional or fixed?
79     ScrollSliderStyle,
80 
81     // each button can take one of four values:
82     ScrollButtonLeftMouseButtonAction,
83     // 0 - scrolls one  line, 1 - scrolls one page
84     ScrollButtonMiddleMouseButtonAction,
85     // 2 - scrolls to end, 3 - button ignored
86     ScrollButtonRightMouseButtonAction,
87 
88     // delay for opening spring loaded folders
89     TreeOpenDelay,
90     // delay for closing spring loaded folders
91     TreeCloseDelay,
92     // delay for triggering the tree scrolling
93     TreeLazyScrollDelay,
94     // delay for scrolling the tree
95     TreeScrollDelay,
96     // the maximum number of lines to be scrolled at ones
97     TreeScrollLinesMax,
98     // What type of tab-order to use
99     TabFocusModel,
100     // Should menu items blink when they're chosen?
101     ChosenMenuItemsShouldBlink,
102 
103     /*
104      * A Boolean value to determine whether the Windows accent color
105      * should be applied to the title bar.
106      *
107      * The value of this metric is not used on other platforms. These platforms
108      * should return NS_ERROR_NOT_IMPLEMENTED when queried for this metric.
109      */
110     WindowsAccentColorInTitlebar,
111 
112     /*
113      * A Boolean value to determine whether the Windows default theme is
114      * being used.
115      *
116      * The value of this metric is not used on other platforms. These platforms
117      * should return NS_ERROR_NOT_IMPLEMENTED when queried for this metric.
118      */
119     WindowsDefaultTheme,
120 
121     /*
122      * A Boolean value to determine whether the DWM compositor is being used
123      *
124      * This metric is not used on non-Windows platforms. These platforms
125      * should return NS_ERROR_NOT_IMPLEMENTED when queried for this metric.
126      */
127     DWMCompositor,
128 
129     /*
130      * A Boolean value to determine whether Windows is themed (Classic vs.
131      * uxtheme)
132      *
133      * This is Windows-specific and is not implemented on other platforms
134      * (will return the default of NS_ERROR_FAILURE).
135      */
136     WindowsClassic,
137 
138     /*
139      * A Boolean value to determine whether the current Windows desktop theme
140      * supports Aero Glass.
141      *
142      * This is Windows-specific and is not implemented on other platforms
143      * (will return the default of NS_ERROR_FAILURE).
144      */
145     WindowsGlass,
146 
147     /*
148      * A Boolean value to determine whether the Mac graphite theme is
149      * being used.
150      */
151     MacGraphiteTheme,
152 
153     /*
154      * A Boolean value to determine whether the macOS Big Sur-specific
155      * theming should be used.
156      */
157     MacBigSurTheme,
158 
159     /*
160      * A Boolean value to determine whether macOS is in RTL mode or not.
161      */
162     MacRTL,
163 
164     /*
165      * AlertNotificationOrigin indicates from which corner of the
166      * screen alerts slide in, and from which direction (horizontal/vertical).
167      * 0, the default, represents bottom right, sliding vertically.
168      * Use any bitwise combination of the following constants:
169      * NS_ALERT_HORIZONTAL (1), NS_ALERT_LEFT (2), NS_ALERT_TOP (4).
170      *
171      *       6       4
172      *     +-----------+
173      *    7|           |5
174      *     |           |
175      *    3|           |1
176      *     +-----------+
177      *       2       0
178      */
179     AlertNotificationOrigin,
180 
181     /**
182      * If true, clicking on a scrollbar (not as in dragging the thumb) defaults
183      * to scrolling the view corresponding to the clicked point. Otherwise, we
184      * only do so if the scrollbar is clicked using the middle mouse button or
185      * if shift is pressed when the scrollbar is clicked.
186      */
187     ScrollToClick,
188 
189     /**
190      * IME and spell checker underline styles, the values should be
191      * NS_DECORATION_LINE_STYLE_*.  They are defined below.
192      */
193     IMERawInputUnderlineStyle,
194     IMESelectedRawTextUnderlineStyle,
195     IMEConvertedTextUnderlineStyle,
196     IMESelectedConvertedTextUnderline,
197     SpellCheckerUnderlineStyle,
198 
199     /**
200      * If this metric != 0, support window dragging on the menubar.
201      */
202     MenuBarDrag,
203     /**
204      * 0: scrollbar button repeats to scroll only when cursor is on the button.
205      * 1: scrollbar button repeats to scroll even if cursor is outside of it.
206      */
207     ScrollbarButtonAutoRepeatBehavior,
208     /**
209      * Delay before showing a tooltip.
210      */
211     TooltipDelay,
212     /*
213      * A Boolean value to determine whether swipe animations should be used.
214      */
215     SwipeAnimationEnabled,
216 
217     /*
218      * Controls whether overlay scrollbars display when the user moves
219      * the mouse in a scrollable frame.
220      */
221     ScrollbarDisplayOnMouseMove,
222 
223     /*
224      * Overlay scrollbar animation constants.
225      */
226     ScrollbarFadeBeginDelay,
227     ScrollbarFadeDuration,
228 
229     /**
230      * Distance in pixels to offset the context menu from the cursor
231      * on open.
232      */
233     ContextMenuOffsetVertical,
234     ContextMenuOffsetHorizontal,
235 
236     /*
237      * A boolean value indicating whether client-side decorations are
238      * supported by the user's GTK version.
239      */
240     GTKCSDAvailable,
241 
242     /*
243      * A boolean value indicating whether client-side decorations should
244      * contain a minimize button.
245      */
246     GTKCSDMinimizeButton,
247 
248     /*
249      * A boolean value indicating whether client-side decorations should
250      * contain a maximize button.
251      */
252     GTKCSDMaximizeButton,
253 
254     /*
255      * A boolean value indicating whether client-side decorations should
256      * contain a close button.
257      */
258     GTKCSDCloseButton,
259 
260     /**
261      * An Integer value that will represent the position of the Minimize button
262      * in GTK Client side decoration header.
263      */
264     GTKCSDMinimizeButtonPosition,
265 
266     /**
267      * An Integer value that will represent the position of the Maximize button
268      * in GTK Client side decoration header.
269      */
270     GTKCSDMaximizeButtonPosition,
271 
272     /**
273      * An Integer value that will represent the position of the Close button
274      * in GTK Client side decoration header.
275      */
276     GTKCSDCloseButtonPosition,
277 
278     /*
279      * A boolean value indicating whether titlebar buttons are located
280      * in left titlebar corner.
281      */
282     GTKCSDReversedPlacement,
283 
284     /*
285      * A boolean value indicating whether or not the OS is using a dark theme,
286      * which we may want to switch to as well if not overridden by the user.
287      */
288     SystemUsesDarkTheme,
289 
290     /**
291      * Corresponding to prefers-reduced-motion.
292      * https://drafts.csswg.org/mediaqueries-5/#prefers-reduced-motion
293      * 0: no-preference
294      * 1: reduce
295      */
296 
297     PrefersReducedMotion,
298     /**
299      * Corresponding to PointerCapabilities in ServoTypes.h
300      * 0: None
301      * 1: Coarse
302      * 2: Fine
303      * 4: Hover
304      */
305     PrimaryPointerCapabilities,
306     /**
307      * Corresponding to union of PointerCapabilities values in ServoTypes.h
308      * E.g. if there is a mouse and a digitizer, the value will be
309      * 'Coarse | Fine | Hover'.
310      */
311     AllPointerCapabilities,
312     /** The vertical scrollbar width, in CSS pixels. */
313     SystemVerticalScrollbarWidth,
314 
315     /** The horizontal scrollbar height, in CSS pixels. */
316     SystemHorizontalScrollbarHeight,
317 
318     /** A boolean value to determine whether a touch device is present */
319     TouchDeviceSupportPresent,
320 
321     /** GTK titlebar radius */
322     TitlebarRadius,
323 
324     /** GTK menu radius */
325     GtkMenuRadius,
326 
327     /*
328      * Not an ID; used to define the range of valid IDs.  Must be last.
329      */
330     End,
331   };
332 
333   // This is a common enough integer that seems worth the shortcut.
UseOverlayScrollbars()334   static bool UseOverlayScrollbars() {
335     return GetInt(IntID::UseOverlayScrollbars);
336   }
337 
338   enum {
339     eScrollArrow_None = 0,
340     eScrollArrow_StartBackward = 0x1000,
341     eScrollArrow_StartForward = 0x0100,
342     eScrollArrow_EndBackward = 0x0010,
343     eScrollArrow_EndForward = 0x0001
344   };
345 
346   enum {
347     // single arrow at each end
348     eScrollArrowStyle_Single =
349         eScrollArrow_StartBackward | eScrollArrow_EndForward,
350     // both arrows at bottom/right, none at top/left
351     eScrollArrowStyle_BothAtBottom =
352         eScrollArrow_EndBackward | eScrollArrow_EndForward,
353     // both arrows at both ends
354     eScrollArrowStyle_BothAtEachEnd =
355         eScrollArrow_EndBackward | eScrollArrow_EndForward |
356         eScrollArrow_StartBackward | eScrollArrow_StartForward,
357     // both arrows at top/left, none at bottom/right
358     eScrollArrowStyle_BothAtTop =
359         eScrollArrow_StartBackward | eScrollArrow_StartForward
360   };
361 
362   enum { eScrollThumbStyle_Normal, eScrollThumbStyle_Proportional };
363 
364   // When modifying this list, also modify nsXPLookAndFeel::sFloatPrefs
365   // in widget/nsXPLookAndFeel.cpp.
366   enum class FloatID {
367     IMEUnderlineRelativeSize,
368     SpellCheckerUnderlineRelativeSize,
369 
370     // The width/height ratio of the cursor. If used, the CaretWidth int metric
371     // should be added to the calculated caret width.
372     CaretAspectRatio,
373 
374     // GTK text scale factor.
375     TextScaleFactor,
376 
377     // Mouse pointer scaling factor.
378     CursorScale,
379 
380     // Not an ID; used to define the range of valid IDs.  Must be last.
381     End,
382   };
383 
384   using FontID = mozilla::StyleSystemFont;
385 
SystemColorScheme()386   static ColorScheme SystemColorScheme() {
387     return GetInt(IntID::SystemUsesDarkTheme) ? ColorScheme::Dark
388                                               : ColorScheme::Light;
389   }
390 
391   enum class ChromeColorSchemeSetting { Light, Dark, System };
392   static ChromeColorSchemeSetting ColorSchemeSettingForChrome();
393   static ColorScheme ThemeDerivedColorSchemeForContent();
394 
ColorSchemeForChrome()395   static ColorScheme ColorSchemeForChrome() {
396     MOZ_ASSERT(sColorSchemeInitialized);
397     return sChromeColorScheme;
398   }
PreferredColorSchemeForContent()399   static ColorScheme PreferredColorSchemeForContent() {
400     MOZ_ASSERT(sColorSchemeInitialized);
401     return sContentColorScheme;
402   }
403 
404   static ColorScheme ColorSchemeForStyle(const dom::Document&,
405                                          const StyleColorSchemeFlags&);
406   static ColorScheme ColorSchemeForFrame(const nsIFrame*);
407 
408   // Whether standins for native colors should be used (that is, colors faked,
409   // taken from win7, mostly). This forces light appearance, effectively.
410   enum class UseStandins : bool { No, Yes };
411   static UseStandins ShouldUseStandins(const dom::Document&, ColorID);
412 
413   // Returns a native color value (might be overwritten by prefs) for a given
414   // color id.
415   //
416   // NOTE:
417   //   ColorID::TextSelectForeground might return NS_SAME_AS_FOREGROUND_COLOR.
418   //   ColorID::IME* might return NS_TRANSPARENT, NS_SAME_AS_FOREGROUND_COLOR or
419   //   NS_40PERCENT_FOREGROUND_COLOR.
420   //   These values have particular meaning.  Then, they are not an actual
421   //   color value.
422   static Maybe<nscolor> GetColor(ColorID, ColorScheme, UseStandins);
423 
424   // Gets the color with appropriate defaults for UseStandins, ColorScheme etc
425   // for a given frame.
426   static Maybe<nscolor> GetColor(ColorID, const nsIFrame*);
427 
428   // Versions of the above which returns the color if found, or a default (which
429   // defaults to opaque black) otherwise.
430   static nscolor Color(ColorID aId, ColorScheme aScheme,
431                        UseStandins aUseStandins,
432                        nscolor aDefault = NS_RGB(0, 0, 0)) {
433     return GetColor(aId, aScheme, aUseStandins).valueOr(aDefault);
434   }
435 
436   static nscolor Color(ColorID aId, nsIFrame* aFrame,
437                        nscolor aDefault = NS_RGB(0, 0, 0)) {
438     return GetColor(aId, aFrame).valueOr(aDefault);
439   }
440 
441   /**
442    * GetInt() and GetFloat() return a int or float value for aID.  The result
443    * might be distance, time, some flags or a int value which has particular
444    * meaning.  See each document at definition of each ID for the detail.
445    * The result is always 0 when they return error.  Therefore, if you want to
446    * use a value for the default value, you should use the other method which
447    * returns int or float directly.
448    */
449   static nsresult GetInt(IntID, int32_t* aResult);
450   static nsresult GetFloat(FloatID aID, float* aResult);
451 
452   static int32_t GetInt(IntID aID, int32_t aDefault = 0) {
453     int32_t result;
454     if (NS_FAILED(GetInt(aID, &result))) {
455       return aDefault;
456     }
457     return result;
458   }
459 
460   static float GetFloat(FloatID aID, float aDefault = 0.0f) {
461     float result;
462     if (NS_FAILED(GetFloat(aID, &result))) {
463       return aDefault;
464     }
465     return result;
466   }
467 
468   /**
469    * Retrieve the name and style of a system-theme font.  Returns true
470    * if the system theme specifies this font, false if a default should
471    * be used.  In the latter case neither aName nor aStyle is modified.
472    *
473    * Size of the font should be in CSS pixels, not device pixels.
474    *
475    * @param aID    Which system-theme font is wanted.
476    * @param aName  The name of the font to use.
477    * @param aStyle Styling to apply to the font.
478    */
479   static bool GetFont(FontID aID, nsString& aName, gfxFontStyle& aStyle);
480 
481   /**
482    * GetPasswordCharacter() returns a unicode character which should be used
483    * for a masked character in password editor.  E.g., '*'.
484    */
485   static char16_t GetPasswordCharacter();
486 
487   /**
488    * If the latest character in password field shouldn't be hidden by the
489    * result of GetPasswordCharacter(), GetEchoPassword() returns TRUE.
490    * Otherwise, FALSE.
491    */
492   static bool GetEchoPassword();
493 
494   /**
495    * Whether we should be drawing in the titlebar by default.
496    */
497   static bool DrawInTitlebar();
498 
499   /**
500    * The millisecond to mask password value.
501    * This value is only valid when GetEchoPassword() returns true.
502    */
503   static uint32_t GetPasswordMaskDelay();
504 
505   /** Gets theme information for about:support */
506   static void GetThemeInfo(nsACString&);
507 
508   /**
509    * When system look and feel is changed, Refresh() must be called.  Then,
510    * cached data would be released.
511    */
512   static void Refresh();
513 
514   /**
515    * GTK's initialization code can't be run off main thread, call this
516    * if you plan on using LookAndFeel off main thread later.
517    *
518    * This initialized state may get reset due to theme changes, so it
519    * must be called prior to each potential off-main-thread LookAndFeel
520    * call, not just once.
521    */
522   static void NativeInit();
523 
524   static void SetData(widget::FullLookAndFeel&& aTables);
525   static void NotifyChangedAllWindows(widget::ThemeChangeKind);
HasPendingGlobalThemeChange()526   static bool HasPendingGlobalThemeChange() { return sGlobalThemeChanged; }
HandleGlobalThemeChange()527   static void HandleGlobalThemeChange() {
528     if (MOZ_UNLIKELY(HasPendingGlobalThemeChange())) {
529       DoHandleGlobalThemeChange();
530     }
531   }
EnsureColorSchemesInitialized()532   static void EnsureColorSchemesInitialized() {
533     if (!sColorSchemeInitialized) {
534       RecomputeColorSchemes();
535     }
536     MOZ_ASSERT(sColorSchemeInitialized);
537   }
538 
539   static ColorScheme sChromeColorScheme;
540   static ColorScheme sContentColorScheme;
541 
542  protected:
543   static void RecomputeColorSchemes();
544   static bool sColorSchemeInitialized;
545 
546   static void DoHandleGlobalThemeChange();
547   // Set to true when ThemeChanged needs to be called on mTheme (and other
548   // global LookAndFeel.  This is used because mTheme is a service, so there's
549   // no need to notify it from more than one prescontext.
550   static bool sGlobalThemeChanged;
551 };
552 
553 }  // namespace mozilla
554 
555 // ---------------------------------------------------------------------
556 //  Special colors for ColorID::IME* and ColorID::SpellCheckerUnderline
557 // ---------------------------------------------------------------------
558 
559 // For background color only.
560 constexpr nscolor NS_TRANSPARENT = NS_RGBA(0x01, 0x00, 0x00, 0x00);
561 // For foreground color only.
562 constexpr nscolor NS_SAME_AS_FOREGROUND_COLOR = NS_RGBA(0x02, 0x00, 0x00, 0x00);
563 constexpr nscolor NS_40PERCENT_FOREGROUND_COLOR =
564     NS_RGBA(0x03, 0x00, 0x00, 0x00);
565 
566 #define NS_IS_SELECTION_SPECIAL_COLOR(c)                          \
567   ((c) == NS_TRANSPARENT || (c) == NS_SAME_AS_FOREGROUND_COLOR || \
568    (c) == NS_40PERCENT_FOREGROUND_COLOR)
569 
570 // ------------------------------------------
571 //  Bits for IntID::AlertNotificationOrigin
572 // ------------------------------------------
573 
574 #define NS_ALERT_HORIZONTAL 1
575 #define NS_ALERT_LEFT 2
576 #define NS_ALERT_TOP 4
577 
578 #endif /* __LookAndFeel */
579