summaryrefslogtreecommitdiffstats
path: root/widget/android/nsLookAndFeel.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--widget/android/nsLookAndFeel.cpp531
1 files changed, 531 insertions, 0 deletions
diff --git a/widget/android/nsLookAndFeel.cpp b/widget/android/nsLookAndFeel.cpp
new file mode 100644
index 0000000000..b6dec95a9b
--- /dev/null
+++ b/widget/android/nsLookAndFeel.cpp
@@ -0,0 +1,531 @@
+/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/dom/ContentChild.h"
+#include "nsStyleConsts.h"
+#include "nsXULAppAPI.h"
+#include "nsLookAndFeel.h"
+#include "gfxFont.h"
+#include "gfxFontConstants.h"
+#include "mozilla/FontPropertyTypes.h"
+#include "mozilla/gfx/2D.h"
+#include "mozilla/java/GeckoAppShellWrappers.h"
+#include "mozilla/java/GeckoRuntimeWrappers.h"
+#include "mozilla/java/GeckoSystemStateListenerWrappers.h"
+
+using namespace mozilla;
+using mozilla::dom::ContentChild;
+
+static const char16_t UNICODE_BULLET = 0x2022;
+
+nsLookAndFeel::nsLookAndFeel(const LookAndFeelCache* aCache) {
+ if (aCache) {
+ DoSetCache(*aCache);
+ }
+}
+
+nsLookAndFeel::~nsLookAndFeel() {}
+
+#define BG_PRELIGHT_COLOR NS_RGB(0xee, 0xee, 0xee)
+#define FG_PRELIGHT_COLOR NS_RGB(0x77, 0x77, 0x77)
+#define BLACK_COLOR NS_RGB(0x00, 0x00, 0x00)
+#define DARK_GRAY_COLOR NS_RGB(0x40, 0x40, 0x40)
+#define GRAY_COLOR NS_RGB(0x80, 0x80, 0x80)
+#define LIGHT_GRAY_COLOR NS_RGB(0xa0, 0xa0, 0xa0)
+#define RED_COLOR NS_RGB(0xff, 0x00, 0x00)
+
+nsresult nsLookAndFeel::GetSystemColors() {
+ if (!jni::IsAvailable()) {
+ return NS_ERROR_FAILURE;
+ }
+
+ auto arr = java::GeckoAppShell::GetSystemColors();
+ if (!arr) {
+ return NS_ERROR_FAILURE;
+ }
+
+ JNIEnv* const env = arr.Env();
+ uint32_t len = static_cast<uint32_t>(env->GetArrayLength(arr.Get()));
+ jint* elements = env->GetIntArrayElements(arr.Get(), 0);
+
+ uint32_t colorsCount = sizeof(AndroidSystemColors) / sizeof(nscolor);
+ if (len < colorsCount) colorsCount = len;
+
+ // Convert Android colors to nscolor by switching R and B in the ARGB 32 bit
+ // value
+ nscolor* colors = (nscolor*)&mSystemColors;
+
+ for (uint32_t i = 0; i < colorsCount; i++) {
+ uint32_t androidColor = static_cast<uint32_t>(elements[i]);
+ uint8_t r = (androidColor & 0x00ff0000) >> 16;
+ uint8_t b = (androidColor & 0x000000ff);
+ colors[i] = (androidColor & 0xff00ff00) | (b << 16) | r;
+ }
+
+ env->ReleaseIntArrayElements(arr.Get(), elements, 0);
+
+ return NS_OK;
+}
+
+void nsLookAndFeel::NativeInit() {
+ EnsureInitSystemColors();
+ EnsureInitShowPassword();
+ RecordTelemetry();
+}
+
+/* virtual */
+void nsLookAndFeel::RefreshImpl() {
+ nsXPLookAndFeel::RefreshImpl();
+
+ mInitializedSystemColors = false;
+ mInitializedShowPassword = false;
+ mPrefersReducedMotionCached = false;
+ mSystemUsesDarkThemeCached = false;
+}
+
+nsresult nsLookAndFeel::NativeGetColor(ColorID aID, nscolor& aColor) {
+ nsresult rv = NS_OK;
+
+ EnsureInitSystemColors();
+ if (!mInitializedSystemColors) {
+ // Failure to initialize colors is an error condition. Return black.
+ aColor = 0;
+ return NS_ERROR_FAILURE;
+ }
+
+ // XXX we'll want to use context.obtainStyledAttributes on the java side to
+ // get all of these; see TextView.java for a good exmaple.
+
+ switch (aID) {
+ // These colors don't seem to be used for anything anymore in Mozilla
+ // (except here at least TextSelectBackground and TextSelectForeground)
+ // The CSS2 colors below are used.
+ case ColorID::WindowBackground:
+ aColor = NS_RGB(0xFF, 0xFF, 0xFF);
+ break;
+ case ColorID::WindowForeground:
+ aColor = mSystemColors.textColorPrimary;
+ break;
+ case ColorID::WidgetBackground:
+ aColor = mSystemColors.colorBackground;
+ break;
+ case ColorID::WidgetForeground:
+ aColor = mSystemColors.colorForeground;
+ break;
+ case ColorID::WidgetSelectBackground:
+ aColor = mSystemColors.textColorHighlight;
+ break;
+ case ColorID::WidgetSelectForeground:
+ aColor = mSystemColors.textColorPrimaryInverse;
+ break;
+ case ColorID::Widget3DHighlight:
+ aColor = LIGHT_GRAY_COLOR;
+ break;
+ case ColorID::Widget3DShadow:
+ aColor = DARK_GRAY_COLOR;
+ break;
+ case ColorID::TextBackground:
+ // not used?
+ aColor = mSystemColors.colorBackground;
+ break;
+ case ColorID::TextForeground:
+ // not used?
+ aColor = mSystemColors.textColorPrimary;
+ break;
+ case ColorID::TextSelectBackground:
+ /* matched to action_accent in java codebase */
+ aColor = NS_RGBA(10, 132, 255, 153);
+ break;
+ case ColorID::TextSelectForeground:
+ aColor = NS_RGB(0, 0, 0);
+ break;
+ case ColorID::IMESelectedRawTextBackground:
+ case ColorID::IMESelectedConvertedTextBackground:
+ // still used
+ aColor = mSystemColors.textColorHighlight;
+ break;
+ case ColorID::IMESelectedRawTextForeground:
+ case ColorID::IMESelectedConvertedTextForeground:
+ // still used
+ aColor = mSystemColors.textColorPrimaryInverse;
+ break;
+ case ColorID::IMERawInputBackground:
+ case ColorID::IMEConvertedTextBackground:
+ aColor = NS_TRANSPARENT;
+ break;
+ case ColorID::IMERawInputForeground:
+ case ColorID::IMEConvertedTextForeground:
+ aColor = NS_SAME_AS_FOREGROUND_COLOR;
+ break;
+ case ColorID::IMERawInputUnderline:
+ case ColorID::IMEConvertedTextUnderline:
+ aColor = NS_SAME_AS_FOREGROUND_COLOR;
+ break;
+ case ColorID::IMESelectedRawTextUnderline:
+ case ColorID::IMESelectedConvertedTextUnderline:
+ aColor = NS_TRANSPARENT;
+ break;
+ case ColorID::SpellCheckerUnderline:
+ aColor = RED_COLOR;
+ break;
+
+ // css2 http://www.w3.org/TR/REC-CSS2/ui.html#system-colors
+ case ColorID::Activeborder:
+ // active window border
+ aColor = mSystemColors.colorBackground;
+ break;
+ case ColorID::Activecaption:
+ // active window caption background
+ aColor = mSystemColors.colorBackground;
+ break;
+ case ColorID::Appworkspace:
+ // MDI background color
+ aColor = mSystemColors.colorBackground;
+ break;
+ case ColorID::Background:
+ // desktop background
+ aColor = mSystemColors.colorBackground;
+ break;
+ case ColorID::Graytext:
+ // disabled text in windows, menus, etc.
+ aColor = NS_RGB(0xb1, 0xa5, 0x98);
+ break;
+ case ColorID::MozCellhighlight:
+ case ColorID::MozHtmlCellhighlight:
+ case ColorID::Highlight:
+ // background of selected item
+ aColor = NS_RGB(0xfa, 0xd1, 0x84);
+ break;
+ case ColorID::MozCellhighlighttext:
+ case ColorID::MozHtmlCellhighlighttext:
+ case ColorID::Highlighttext:
+ case ColorID::Fieldtext:
+ aColor = NS_RGB(0x1a, 0x1a, 0x1a);
+ break;
+ case ColorID::Inactiveborder:
+ // inactive window border
+ aColor = mSystemColors.colorBackground;
+ break;
+ case ColorID::Inactivecaption:
+ // inactive window caption
+ aColor = mSystemColors.colorBackground;
+ break;
+ case ColorID::Inactivecaptiontext:
+ // text in inactive window caption
+ aColor = mSystemColors.textColorTertiary;
+ break;
+ case ColorID::Infobackground:
+ aColor = NS_RGB(0xf5, 0xf5, 0xb5);
+ break;
+ case ColorID::Infotext:
+ aColor = BLACK_COLOR;
+ break;
+ case ColorID::Menu:
+ aColor = NS_RGB(0xf7, 0xf5, 0xf3);
+ break;
+ case ColorID::Scrollbar:
+ // scrollbar gray area
+ aColor = mSystemColors.colorBackground;
+ break;
+
+ case ColorID::Threedface:
+ case ColorID::Buttonface:
+ case ColorID::Threedlightshadow:
+ aColor = NS_RGB(0xec, 0xe7, 0xe2);
+ break;
+
+ case ColorID::Buttonhighlight:
+ case ColorID::Field:
+ case ColorID::Threedhighlight:
+ case ColorID::MozCombobox:
+ case ColorID::MozEventreerow:
+ aColor = NS_RGB(0xff, 0xff, 0xff);
+ break;
+
+ case ColorID::Buttonshadow:
+ case ColorID::Threedshadow:
+ aColor = NS_RGB(0xae, 0xa1, 0x94);
+ break;
+
+ case ColorID::Threeddarkshadow:
+ // 3-D shadow outer edge color
+ aColor = BLACK_COLOR;
+ break;
+
+ case ColorID::MozDialog:
+ case ColorID::Window:
+ case ColorID::Windowframe:
+ aColor = NS_RGB(0xef, 0xeb, 0xe7);
+ break;
+ case ColorID::Buttontext:
+ case ColorID::Captiontext:
+ case ColorID::Menutext:
+ case ColorID::MozButtonhovertext:
+ case ColorID::MozDialogtext:
+ case ColorID::MozComboboxtext:
+ case ColorID::Windowtext:
+ case ColorID::MozColheadertext:
+ case ColorID::MozColheaderhovertext:
+ aColor = NS_RGB(0x10, 0x10, 0x10);
+ break;
+ case ColorID::MozDragtargetzone:
+ aColor = mSystemColors.textColorHighlight;
+ break;
+ case ColorID::MozButtondefault:
+ // default button border color
+ aColor = BLACK_COLOR;
+ break;
+ case ColorID::MozButtonhoverface:
+ aColor = NS_RGB(0xf3, 0xf0, 0xed);
+ break;
+ case ColorID::MozMenuhover:
+ aColor = BG_PRELIGHT_COLOR;
+ break;
+ case ColorID::MozMenuhovertext:
+ aColor = FG_PRELIGHT_COLOR;
+ break;
+ case ColorID::MozOddtreerow:
+ aColor = NS_TRANSPARENT;
+ break;
+ case ColorID::MozNativehyperlinktext:
+ aColor = NS_SAME_AS_FOREGROUND_COLOR;
+ break;
+ case ColorID::MozMenubartext:
+ aColor = mSystemColors.colorForeground;
+ break;
+ case ColorID::MozMenubarhovertext:
+ aColor = FG_PRELIGHT_COLOR;
+ break;
+ default:
+ /* default color is BLACK */
+ aColor = 0;
+ rv = NS_ERROR_FAILURE;
+ break;
+ }
+
+ return rv;
+}
+
+nsresult nsLookAndFeel::NativeGetInt(IntID aID, int32_t& aResult) {
+ nsresult rv = NS_OK;
+
+ switch (aID) {
+ case IntID::ScrollButtonLeftMouseButtonAction:
+ aResult = 0;
+ break;
+
+ case IntID::ScrollButtonMiddleMouseButtonAction:
+ case IntID::ScrollButtonRightMouseButtonAction:
+ aResult = 3;
+ break;
+
+ case IntID::CaretBlinkTime:
+ aResult = 500;
+ break;
+
+ case IntID::CaretWidth:
+ aResult = 1;
+ break;
+
+ case IntID::ShowCaretDuringSelection:
+ aResult = 0;
+ break;
+
+ case IntID::SelectTextfieldsOnKeyFocus:
+ // Select textfield content when focused by kbd
+ // used by EventStateManager::sTextfieldSelectModel
+ aResult = 1;
+ break;
+
+ case IntID::SubmenuDelay:
+ aResult = 200;
+ break;
+
+ case IntID::TooltipDelay:
+ aResult = 500;
+ break;
+
+ case IntID::MenusCanOverlapOSBar:
+ // we want XUL popups to be able to overlap the task bar.
+ aResult = 1;
+ break;
+
+ case IntID::ScrollArrowStyle:
+ aResult = eScrollArrowStyle_Single;
+ break;
+
+ case IntID::ScrollSliderStyle:
+ aResult = eScrollThumbStyle_Proportional;
+ break;
+
+ case IntID::TouchEnabled:
+ aResult = 1;
+ break;
+
+ case IntID::WindowsDefaultTheme:
+ case IntID::WindowsThemeIdentifier:
+ case IntID::OperatingSystemVersionIdentifier:
+ aResult = 0;
+ rv = NS_ERROR_NOT_IMPLEMENTED;
+ break;
+
+ case IntID::SpellCheckerUnderlineStyle:
+ aResult = NS_STYLE_TEXT_DECORATION_STYLE_WAVY;
+ break;
+
+ case IntID::ScrollbarButtonAutoRepeatBehavior:
+ aResult = 0;
+ break;
+
+ case IntID::ContextMenuOffsetVertical:
+ case IntID::ContextMenuOffsetHorizontal:
+ aResult = 2;
+ break;
+
+ case IntID::PrefersReducedMotion:
+ if (!mPrefersReducedMotionCached && XRE_IsParentProcess()) {
+ mPrefersReducedMotion =
+ java::GeckoSystemStateListener::PrefersReducedMotion();
+ mPrefersReducedMotionCached = true;
+ }
+ aResult = mPrefersReducedMotion;
+ break;
+
+ case IntID::PrimaryPointerCapabilities:
+ aResult = java::GeckoAppShell::GetPrimaryPointerCapabilities();
+ break;
+ case IntID::AllPointerCapabilities:
+ aResult = java::GeckoAppShell::GetAllPointerCapabilities();
+ break;
+
+ case IntID::SystemUsesDarkTheme: {
+ if (!mSystemUsesDarkThemeCached && XRE_IsParentProcess()) {
+ // Bail out if AndroidBridge hasn't initialized since we try to query
+ // this value via nsMediaFeatures::InitSystemMetrics without
+ // initializing AndroidBridge on xpcshell tests.
+ if (!jni::IsAvailable()) {
+ return NS_ERROR_FAILURE;
+ }
+
+ java::GeckoRuntime::LocalRef runtime =
+ java::GeckoRuntime::GetInstance();
+ mSystemUsesDarkTheme = runtime && runtime->UsesDarkTheme();
+ mSystemUsesDarkThemeCached = true;
+ }
+
+ aResult = mSystemUsesDarkTheme;
+ break;
+ }
+
+ case IntID::DragThresholdX:
+ case IntID::DragThresholdY:
+ // Threshold where a tap becomes a drag, in 1/240" reference pixels.
+ aResult = 25;
+ break;
+
+ default:
+ aResult = 0;
+ rv = NS_ERROR_FAILURE;
+ }
+
+ return rv;
+}
+
+nsresult nsLookAndFeel::NativeGetFloat(FloatID aID, float& aResult) {
+ nsresult rv = NS_OK;
+
+ switch (aID) {
+ case FloatID::IMEUnderlineRelativeSize:
+ aResult = 1.0f;
+ break;
+
+ case FloatID::SpellCheckerUnderlineRelativeSize:
+ aResult = 1.0f;
+ break;
+
+ default:
+ aResult = -1.0;
+ rv = NS_ERROR_FAILURE;
+ break;
+ }
+ return rv;
+}
+
+/*virtual*/
+bool nsLookAndFeel::NativeGetFont(FontID aID, nsString& aFontName,
+ gfxFontStyle& aFontStyle) {
+ aFontName.AssignLiteral("\"Roboto\"");
+ aFontStyle.style = FontSlantStyle::Normal();
+ aFontStyle.weight = FontWeight::Normal();
+ aFontStyle.stretch = FontStretch::Normal();
+ aFontStyle.size = 9.0 * 96.0f / 72.0f;
+ aFontStyle.systemFont = true;
+ return true;
+}
+
+/*virtual*/
+bool nsLookAndFeel::GetEchoPasswordImpl() {
+ EnsureInitShowPassword();
+ return mShowPassword;
+}
+
+uint32_t nsLookAndFeel::GetPasswordMaskDelayImpl() {
+ // This value is hard-coded in Android OS's PasswordTransformationMethod.java
+ return 1500;
+}
+
+/* virtual */
+char16_t nsLookAndFeel::GetPasswordCharacterImpl() {
+ // This value is hard-coded in Android OS's PasswordTransformationMethod.java
+ return UNICODE_BULLET;
+}
+
+void nsLookAndFeel::EnsureInitSystemColors() {
+ if (!mInitializedSystemColors) {
+ mInitializedSystemColors = NS_SUCCEEDED(GetSystemColors());
+ }
+}
+
+void nsLookAndFeel::EnsureInitShowPassword() {
+ if (!mInitializedShowPassword && jni::IsAvailable()) {
+ mShowPassword = java::GeckoAppShell::GetShowPasswordSetting();
+ mInitializedShowPassword = true;
+ }
+}
+
+widget::LookAndFeelCache nsLookAndFeel::GetCacheImpl() {
+ LookAndFeelCache cache = nsXPLookAndFeel::GetCacheImpl();
+
+ const IntID kIdsToCache[] = {IntID::PrefersReducedMotion,
+ IntID::SystemUsesDarkTheme};
+
+ for (IntID id : kIdsToCache) {
+ cache.mInts().AppendElement(LookAndFeelInt(id, GetInt(id)));
+ }
+
+ return cache;
+}
+
+void nsLookAndFeel::SetCacheImpl(const LookAndFeelCache& aCache) {
+ DoSetCache(aCache);
+}
+
+void nsLookAndFeel::DoSetCache(const LookAndFeelCache& aCache) {
+ for (const auto& entry : aCache.mInts()) {
+ switch (entry.id()) {
+ case IntID::PrefersReducedMotion:
+ mPrefersReducedMotion = entry.value();
+ mPrefersReducedMotionCached = true;
+ break;
+ case IntID::SystemUsesDarkTheme:
+ mSystemUsesDarkTheme = !!entry.value();
+ mSystemUsesDarkThemeCached = true;
+ break;
+ default:
+ MOZ_ASSERT_UNREACHABLE("Bogus Int ID in cache");
+ break;
+ }
+ }
+}