1 /* -*- Mode: C++; tab-width: 20; 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 #include "mozilla/dom/ContentChild.h"
7 #include "nsStyleConsts.h"
8 #include "nsXULAppAPI.h"
9 #include "nsLookAndFeel.h"
10 #include "gfxFont.h"
11 #include "gfxFontConstants.h"
12 #include "mozilla/FontPropertyTypes.h"
13 #include "mozilla/gfx/2D.h"
14 #include "mozilla/java/GeckoAppShellWrappers.h"
15 #include "mozilla/java/GeckoRuntimeWrappers.h"
16 #include "mozilla/java/GeckoSystemStateListenerWrappers.h"
17 
18 using namespace mozilla;
19 using mozilla::dom::ContentChild;
20 
21 static const char16_t UNICODE_BULLET = 0x2022;
22 
23 nsLookAndFeel::nsLookAndFeel() = default;
24 
~nsLookAndFeel()25 nsLookAndFeel::~nsLookAndFeel() {}
26 
27 #define BG_PRELIGHT_COLOR NS_RGB(0xee, 0xee, 0xee)
28 #define FG_PRELIGHT_COLOR NS_RGB(0x77, 0x77, 0x77)
29 #define BLACK_COLOR NS_RGB(0x00, 0x00, 0x00)
30 #define DARK_GRAY_COLOR NS_RGB(0x40, 0x40, 0x40)
31 #define GRAY_COLOR NS_RGB(0x80, 0x80, 0x80)
32 #define LIGHT_GRAY_COLOR NS_RGB(0xa0, 0xa0, 0xa0)
33 #define RED_COLOR NS_RGB(0xff, 0x00, 0x00)
34 
GetSystemColors()35 nsresult nsLookAndFeel::GetSystemColors() {
36   if (!jni::IsAvailable()) {
37     return NS_ERROR_FAILURE;
38   }
39 
40   auto arr = java::GeckoAppShell::GetSystemColors();
41   if (!arr) {
42     return NS_ERROR_FAILURE;
43   }
44 
45   JNIEnv* const env = arr.Env();
46   uint32_t len = static_cast<uint32_t>(env->GetArrayLength(arr.Get()));
47   jint* elements = env->GetIntArrayElements(arr.Get(), 0);
48 
49   uint32_t colorsCount = sizeof(AndroidSystemColors) / sizeof(nscolor);
50   if (len < colorsCount) colorsCount = len;
51 
52   // Convert Android colors to nscolor by switching R and B in the ARGB 32 bit
53   // value
54   nscolor* colors = (nscolor*)&mSystemColors;
55 
56   for (uint32_t i = 0; i < colorsCount; i++) {
57     uint32_t androidColor = static_cast<uint32_t>(elements[i]);
58     uint8_t r = (androidColor & 0x00ff0000) >> 16;
59     uint8_t b = (androidColor & 0x000000ff);
60     colors[i] = (androidColor & 0xff00ff00) | (b << 16) | r;
61   }
62 
63   env->ReleaseIntArrayElements(arr.Get(), elements, 0);
64 
65   return NS_OK;
66 }
67 
NativeInit()68 void nsLookAndFeel::NativeInit() {
69   EnsureInitSystemColors();
70   EnsureInitShowPassword();
71   RecordTelemetry();
72 }
73 
74 /* virtual */
RefreshImpl()75 void nsLookAndFeel::RefreshImpl() {
76   nsXPLookAndFeel::RefreshImpl();
77 
78   mInitializedSystemColors = false;
79   mInitializedShowPassword = false;
80 }
81 
NativeGetColor(ColorID aID,ColorScheme,nscolor & aColor)82 nsresult nsLookAndFeel::NativeGetColor(ColorID aID, ColorScheme,
83                                        nscolor& aColor) {
84   nsresult rv = NS_OK;
85 
86   EnsureInitSystemColors();
87   if (!mInitializedSystemColors) {
88     // Failure to initialize colors is an error condition. Return black.
89     aColor = 0;
90     return NS_ERROR_FAILURE;
91   }
92 
93   // XXX we'll want to use context.obtainStyledAttributes on the java side to
94   // get all of these; see TextView.java for a good exmaple.
95 
96   switch (aID) {
97       // These colors don't seem to be used for anything anymore in Mozilla
98       // (except here at least TextSelectBackground and TextSelectForeground)
99       // The CSS2 colors below are used.
100     case ColorID::WindowBackground:
101       aColor = NS_RGB(0xFF, 0xFF, 0xFF);
102       break;
103     case ColorID::WindowForeground:
104       aColor = mSystemColors.textColorPrimary;
105       break;
106     case ColorID::WidgetBackground:
107       aColor = mSystemColors.colorBackground;
108       break;
109     case ColorID::WidgetForeground:
110       aColor = mSystemColors.colorForeground;
111       break;
112     case ColorID::WidgetSelectBackground:
113       aColor = mSystemColors.textColorHighlight;
114       break;
115     case ColorID::WidgetSelectForeground:
116       aColor = mSystemColors.textColorPrimaryInverse;
117       break;
118     case ColorID::Widget3DHighlight:
119       aColor = LIGHT_GRAY_COLOR;
120       break;
121     case ColorID::Widget3DShadow:
122       aColor = DARK_GRAY_COLOR;
123       break;
124     case ColorID::TextBackground:
125       // not used?
126       aColor = mSystemColors.colorBackground;
127       break;
128     case ColorID::TextForeground:
129       // not used?
130       aColor = mSystemColors.textColorPrimary;
131       break;
132     case ColorID::TextSelectBackground:
133       /* matched to action_accent in java codebase */
134       aColor = NS_RGBA(10, 132, 255, 153);
135       break;
136     case ColorID::TextSelectForeground:
137       aColor = NS_RGB(0, 0, 0);
138       break;
139     case ColorID::IMESelectedRawTextBackground:
140     case ColorID::IMESelectedConvertedTextBackground:
141       // still used
142       aColor = mSystemColors.textColorHighlight;
143       break;
144     case ColorID::IMESelectedRawTextForeground:
145     case ColorID::IMESelectedConvertedTextForeground:
146       // still used
147       aColor = mSystemColors.textColorPrimaryInverse;
148       break;
149     case ColorID::IMERawInputBackground:
150     case ColorID::IMEConvertedTextBackground:
151       aColor = NS_TRANSPARENT;
152       break;
153     case ColorID::IMERawInputForeground:
154     case ColorID::IMEConvertedTextForeground:
155       aColor = NS_SAME_AS_FOREGROUND_COLOR;
156       break;
157     case ColorID::IMERawInputUnderline:
158     case ColorID::IMEConvertedTextUnderline:
159       aColor = NS_SAME_AS_FOREGROUND_COLOR;
160       break;
161     case ColorID::IMESelectedRawTextUnderline:
162     case ColorID::IMESelectedConvertedTextUnderline:
163       aColor = NS_TRANSPARENT;
164       break;
165     case ColorID::SpellCheckerUnderline:
166       aColor = RED_COLOR;
167       break;
168 
169       // css2  http://www.w3.org/TR/REC-CSS2/ui.html#system-colors
170     case ColorID::Activeborder:
171       // active window border
172       aColor = mSystemColors.colorBackground;
173       break;
174     case ColorID::Activecaption:
175       // active window caption background
176       aColor = mSystemColors.colorBackground;
177       break;
178     case ColorID::Appworkspace:
179       // MDI background color
180       aColor = mSystemColors.colorBackground;
181       break;
182     case ColorID::Background:
183       // desktop background
184       aColor = mSystemColors.colorBackground;
185       break;
186     case ColorID::Graytext:
187       // disabled text in windows, menus, etc.
188       aColor = NS_RGB(0xb1, 0xa5, 0x98);
189       break;
190     case ColorID::MozCellhighlight:
191     case ColorID::MozHtmlCellhighlight:
192     case ColorID::Highlight:
193     case ColorID::MozAccentColor:
194       // background of selected item
195       aColor = NS_RGB(0xfa, 0xd1, 0x84);
196       break;
197     case ColorID::MozCellhighlighttext:
198     case ColorID::MozHtmlCellhighlighttext:
199     case ColorID::Highlighttext:
200     case ColorID::MozAccentColorForeground:
201     case ColorID::Fieldtext:
202       aColor = NS_RGB(0x1a, 0x1a, 0x1a);
203       break;
204     case ColorID::Inactiveborder:
205       // inactive window border
206       aColor = mSystemColors.colorBackground;
207       break;
208     case ColorID::Inactivecaption:
209       // inactive window caption
210       aColor = mSystemColors.colorBackground;
211       break;
212     case ColorID::Inactivecaptiontext:
213       // text in inactive window caption
214       aColor = mSystemColors.textColorTertiary;
215       break;
216     case ColorID::Infobackground:
217       aColor = NS_RGB(0xf5, 0xf5, 0xb5);
218       break;
219     case ColorID::Infotext:
220       aColor = BLACK_COLOR;
221       break;
222     case ColorID::Menu:
223       aColor = NS_RGB(0xf7, 0xf5, 0xf3);
224       break;
225     case ColorID::Scrollbar:
226       // scrollbar gray area
227       aColor = mSystemColors.colorBackground;
228       break;
229 
230     case ColorID::Threedface:
231     case ColorID::Buttonface:
232     case ColorID::Threedlightshadow:
233       aColor = NS_RGB(0xec, 0xe7, 0xe2);
234       break;
235 
236     case ColorID::Buttonhighlight:
237     case ColorID::Field:
238     case ColorID::Threedhighlight:
239     case ColorID::MozCombobox:
240     case ColorID::MozEventreerow:
241       aColor = NS_RGB(0xff, 0xff, 0xff);
242       break;
243 
244     case ColorID::Buttonshadow:
245     case ColorID::Threedshadow:
246       aColor = NS_RGB(0xae, 0xa1, 0x94);
247       break;
248 
249     case ColorID::Threeddarkshadow:
250       // 3-D shadow outer edge color
251       aColor = BLACK_COLOR;
252       break;
253 
254     case ColorID::MozDialog:
255     case ColorID::Window:
256     case ColorID::Windowframe:
257       aColor = NS_RGB(0xef, 0xeb, 0xe7);
258       break;
259     case ColorID::Buttontext:
260     case ColorID::Captiontext:
261     case ColorID::Menutext:
262     case ColorID::MozButtonhovertext:
263     case ColorID::MozDialogtext:
264     case ColorID::MozComboboxtext:
265     case ColorID::Windowtext:
266     case ColorID::MozColheadertext:
267     case ColorID::MozColheaderhovertext:
268       aColor = NS_RGB(0x10, 0x10, 0x10);
269       break;
270     case ColorID::MozDragtargetzone:
271       aColor = mSystemColors.textColorHighlight;
272       break;
273     case ColorID::MozButtondefault:
274       // default button border color
275       aColor = BLACK_COLOR;
276       break;
277     case ColorID::MozButtonhoverface:
278       aColor = NS_RGB(0xf3, 0xf0, 0xed);
279       break;
280     case ColorID::MozMenuhover:
281       aColor = BG_PRELIGHT_COLOR;
282       break;
283     case ColorID::MozMenuhovertext:
284       aColor = FG_PRELIGHT_COLOR;
285       break;
286     case ColorID::MozOddtreerow:
287       aColor = NS_TRANSPARENT;
288       break;
289     case ColorID::MozNativehyperlinktext:
290       aColor = NS_RGB(0, 0, 0xee);
291       break;
292     case ColorID::MozMenubartext:
293       aColor = mSystemColors.colorForeground;
294       break;
295     case ColorID::MozMenubarhovertext:
296       aColor = FG_PRELIGHT_COLOR;
297       break;
298     default:
299       /* default color is BLACK */
300       aColor = 0;
301       rv = NS_ERROR_FAILURE;
302       break;
303   }
304 
305   return rv;
306 }
307 
NativeGetInt(IntID aID,int32_t & aResult)308 nsresult nsLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) {
309   nsresult rv = NS_OK;
310 
311   switch (aID) {
312     case IntID::ScrollButtonLeftMouseButtonAction:
313       aResult = 0;
314       break;
315 
316     case IntID::ScrollButtonMiddleMouseButtonAction:
317     case IntID::ScrollButtonRightMouseButtonAction:
318       aResult = 3;
319       break;
320 
321     case IntID::CaretBlinkTime:
322       aResult = 500;
323       break;
324 
325     case IntID::CaretWidth:
326       aResult = 1;
327       break;
328 
329     case IntID::ShowCaretDuringSelection:
330       aResult = 0;
331       break;
332 
333     case IntID::SelectTextfieldsOnKeyFocus:
334       // Select textfield content when focused by kbd
335       // used by EventStateManager::sTextfieldSelectModel
336       aResult = 1;
337       break;
338 
339     case IntID::SubmenuDelay:
340       aResult = 200;
341       break;
342 
343     case IntID::TooltipDelay:
344       aResult = 500;
345       break;
346 
347     case IntID::MenusCanOverlapOSBar:
348       // we want XUL popups to be able to overlap the task bar.
349       aResult = 1;
350       break;
351 
352     case IntID::ScrollArrowStyle:
353       aResult = eScrollArrowStyle_Single;
354       break;
355 
356     case IntID::ScrollSliderStyle:
357       aResult = eScrollThumbStyle_Proportional;
358       break;
359 
360     case IntID::WindowsDefaultTheme:
361     case IntID::WindowsThemeIdentifier:
362     case IntID::OperatingSystemVersionIdentifier:
363       aResult = 0;
364       rv = NS_ERROR_NOT_IMPLEMENTED;
365       break;
366 
367     case IntID::SpellCheckerUnderlineStyle:
368       aResult = NS_STYLE_TEXT_DECORATION_STYLE_WAVY;
369       break;
370 
371     case IntID::ScrollbarButtonAutoRepeatBehavior:
372       aResult = 0;
373       break;
374 
375     case IntID::ContextMenuOffsetVertical:
376     case IntID::ContextMenuOffsetHorizontal:
377       aResult = 2;
378       break;
379 
380     case IntID::PrefersReducedMotion:
381       aResult = java::GeckoSystemStateListener::PrefersReducedMotion();
382       break;
383 
384     case IntID::PrimaryPointerCapabilities:
385       aResult = java::GeckoAppShell::GetPrimaryPointerCapabilities();
386       break;
387     case IntID::AllPointerCapabilities:
388       aResult = java::GeckoAppShell::GetAllPointerCapabilities();
389       break;
390 
391     case IntID::SystemUsesDarkTheme: {
392       java::GeckoRuntime::LocalRef runtime = java::GeckoRuntime::GetInstance();
393       aResult = runtime && runtime->UsesDarkTheme();
394       break;
395     }
396 
397     case IntID::DragThresholdX:
398     case IntID::DragThresholdY:
399       // Threshold where a tap becomes a drag, in 1/240" reference pixels.
400       aResult = 25;
401       break;
402 
403     default:
404       aResult = 0;
405       rv = NS_ERROR_FAILURE;
406   }
407 
408   return rv;
409 }
410 
NativeGetFloat(FloatID aID,float & aResult)411 nsresult nsLookAndFeel::NativeGetFloat(FloatID aID, float& aResult) {
412   nsresult rv = NS_OK;
413 
414   switch (aID) {
415     case FloatID::IMEUnderlineRelativeSize:
416       aResult = 1.0f;
417       break;
418 
419     case FloatID::SpellCheckerUnderlineRelativeSize:
420       aResult = 1.0f;
421       break;
422 
423     default:
424       aResult = -1.0;
425       rv = NS_ERROR_FAILURE;
426       break;
427   }
428   return rv;
429 }
430 
431 /*virtual*/
NativeGetFont(FontID aID,nsString & aFontName,gfxFontStyle & aFontStyle)432 bool nsLookAndFeel::NativeGetFont(FontID aID, nsString& aFontName,
433                                   gfxFontStyle& aFontStyle) {
434   aFontName.AssignLiteral("\"Roboto\"");
435   aFontStyle.style = FontSlantStyle::Normal();
436   aFontStyle.weight = FontWeight::Normal();
437   aFontStyle.stretch = FontStretch::Normal();
438   aFontStyle.size = 9.0 * 96.0f / 72.0f;
439   aFontStyle.systemFont = true;
440   return true;
441 }
442 
443 /*virtual*/
GetEchoPasswordImpl()444 bool nsLookAndFeel::GetEchoPasswordImpl() {
445   EnsureInitShowPassword();
446   return mShowPassword;
447 }
448 
GetPasswordMaskDelayImpl()449 uint32_t nsLookAndFeel::GetPasswordMaskDelayImpl() {
450   // This value is hard-coded in Android OS's PasswordTransformationMethod.java
451   return 1500;
452 }
453 
454 /* virtual */
GetPasswordCharacterImpl()455 char16_t nsLookAndFeel::GetPasswordCharacterImpl() {
456   // This value is hard-coded in Android OS's PasswordTransformationMethod.java
457   return UNICODE_BULLET;
458 }
459 
EnsureInitSystemColors()460 void nsLookAndFeel::EnsureInitSystemColors() {
461   if (!mInitializedSystemColors) {
462     mInitializedSystemColors = NS_SUCCEEDED(GetSystemColors());
463   }
464 }
465 
EnsureInitShowPassword()466 void nsLookAndFeel::EnsureInitShowPassword() {
467   if (!mInitializedShowPassword && jni::IsAvailable()) {
468     mShowPassword = java::GeckoAppShell::GetShowPasswordSetting();
469     mInitializedShowPassword = true;
470   }
471 }
472