new file mode 100644
--- /dev/null
+++ b/widget/android/AndroidColors.h
@@ -0,0 +1,20 @@
+/* -*- Mode: c++; tab-width: 40; indent-tabs-mode: nil; c-basic-offset: 4; -*- */
+/* 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/. */
+
+#ifndef mozilla_widget_AndroidColors_h
+#define mozilla_widget_AndroidColors_h
+
+#include "mozilla/gfx/2D.h"
+
+namespace mozilla {
+namespace widget {
+
+static const Color sAndroidBorderColor(Color(0.73f, 0.73f, 0.73f));
+static const Color sAndroidCheckColor(Color(0.19f, 0.21f, 0.23f));
+
+} // namespace widget
+} // namespace mozilla
+
+#endif // mozilla_widget_AndroidColors_h
--- a/widget/android/moz.build
+++ b/widget/android/moz.build
@@ -50,16 +50,17 @@ UNIFIED_SOURCES += [
'GeneratedJNIWrappers.cpp',
'GfxInfo.cpp',
'nsAndroidProtocolHandler.cpp',
'nsAppShell.cpp',
'nsClipboard.cpp',
'nsDeviceContextAndroid.cpp',
'nsIdleServiceAndroid.cpp',
'nsLookAndFeel.cpp',
+ 'nsNativeThemeAndroid.cpp',
'nsPrintOptionsAndroid.cpp',
'nsScreenManagerAndroid.cpp',
'nsWidgetFactory.cpp',
'nsWindow.cpp',
]
include('/ipc/chromium/chromium-config.mozbuild')
new file mode 100644
--- /dev/null
+++ b/widget/android/nsNativeThemeAndroid.cpp
@@ -0,0 +1,227 @@
+/* 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 "nsNativeThemeAndroid.h"
+
+#include "nsIDOMHTMLInputElement.h"
+#include "nsIFrame.h"
+#include "nsThemeConstants.h"
+#include "AndroidColors.h"
+
+NS_IMPL_ISUPPORTS_INHERITED(nsNativeThemeAndroid, nsNativeTheme, nsITheme)
+
+using namespace mozilla::gfx;
+
+static void
+PaintCheckMark(nsIFrame* aFrame,
+ DrawTarget* aDrawTarget,
+ const nsRect& aDirtyRect,
+ nsPoint aPt)
+{
+ nsRect rect(aPt, aFrame->GetSize());
+ rect.Deflate(aFrame->GetUsedBorderAndPadding());
+
+ // Points come from the coordinates on a 7X7 unit box centered at 0,0
+ const int32_t checkPolygonX[] = { -3, -1, 3, 3, -1, -3 };
+ const int32_t checkPolygonY[] = { -1, 1, -3, -1, 3, 1 };
+ const int32_t checkNumPoints = sizeof(checkPolygonX) / sizeof(int32_t);
+ const int32_t checkSize = 9; // 2 units of padding on either side
+ // of the 7x7 unit checkmark
+
+ // Scale the checkmark based on the smallest dimension
+ nscoord paintScale = std::min(rect.width, rect.height) / checkSize;
+ nsPoint paintCenter(rect.x + rect.width / 2,
+ rect.y + rect.height / 2);
+
+ RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder();
+ nsPoint p = paintCenter + nsPoint(checkPolygonX[0] * paintScale,
+ checkPolygonY[0] * paintScale);
+
+ int32_t appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
+ builder->MoveTo(NSPointToPoint(p, appUnitsPerDevPixel));
+ for (int32_t polyIndex = 1; polyIndex < checkNumPoints; polyIndex++) {
+ p = paintCenter + nsPoint(checkPolygonX[polyIndex] * paintScale,
+ checkPolygonY[polyIndex] * paintScale);
+ builder->LineTo(NSPointToPoint(p, appUnitsPerDevPixel));
+ }
+ RefPtr<Path> path = builder->Finish();
+ aDrawTarget->Fill(path,
+ ColorPattern(ToDeviceColor(aFrame->StyleColor()->mColor)));
+}
+
+static void
+PaintIndeterminateMark(nsIFrame* aFrame,
+ DrawTarget* aDrawTarget,
+ const nsRect& aDirtyRect,
+ nsPoint aPt)
+{
+ int32_t appUnitsPerDevPixel = aFrame->PresContext()->AppUnitsPerDevPixel();
+
+ nsRect rect(aPt, aFrame->GetSize());
+ rect.Deflate(aFrame->GetUsedBorderAndPadding());
+ rect.y += (rect.height - rect.height/4) / 2;
+ rect.height /= 4;
+
+ Rect devPxRect = NSRectToSnappedRect(rect, appUnitsPerDevPixel, *aDrawTarget);
+
+ aDrawTarget->FillRect(
+ devPxRect, ColorPattern(ToDeviceColor(aFrame->StyleColor()->mColor)));
+}
+
+static void
+PaintCheckedRadioButton(nsIFrame* aFrame,
+ DrawTarget* aDrawTarget,
+ const nsRect& aDirtyRect,
+ nsPoint aPt)
+{
+ // The dot is an ellipse 2px on all sides smaller than the content-box,
+ // drawn in the foreground color.
+ nsRect rect(aPt, aFrame->GetSize());
+ rect.Deflate(aFrame->GetUsedBorderAndPadding());
+ rect.Deflate(nsPresContext::CSSPixelsToAppUnits(2),
+ nsPresContext::CSSPixelsToAppUnits(2));
+
+ Rect devPxRect =
+ ToRect(nsLayoutUtils::RectToGfxRect(rect,
+ aFrame->PresContext()->AppUnitsPerDevPixel()));
+
+ ColorPattern color(ToDeviceColor(aFrame->StyleColor()->mColor));
+
+ RefPtr<PathBuilder> builder = aDrawTarget->CreatePathBuilder();
+ AppendEllipseToPath(builder, devPxRect.Center(), devPxRect.Size());
+ RefPtr<Path> ellipse = builder->Finish();
+ aDrawTarget->Fill(ellipse, color);
+}
+
+NS_IMETHODIMP
+nsNativeThemeAndroid::DrawWidgetBackground(gfxContext* aContext,
+ nsIFrame* aFrame,
+ uint8_t aWidgetType,
+ const nsRect& aRect,
+ const nsRect& aDirtyRect)
+{
+ switch (aWidgetType) {
+ case NS_THEME_RADIO:
+ PaintRadioControl(aFrame, aContext->GetDrawTarget(), aDirtyRect);
+ if (IsSelected(aFrame)) {
+ PaintCheckedRadioButton(aFrame, aContext->GetDrawTarget(), aDirtyRect);
+ }
+ break;
+ case NS_THEME_CHECKBOX:
+ PaintCheckboxControl(aFrame, aContext->GetDrawTarget(), aDirtyRect);
+ if (IsChecked(aFrame)) {
+ PaintCheckMark(aFrame, aContext->GetDrawTarget(), aDirtyRect);
+ }
+ if (GetIndeterminate(aFrame)) {
+ PaintIndeterminateMark(aFrame, aContext->GetDrawTarget(), aDirtyRect);
+ }
+ break;
+ default:
+ MOZ_ASSERT_UNREACHABLE("Should not get here with a widget type we don't support.");
+ return NS_ERROR_NOT_IMPLEMENTED;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsNativeThemeAndroid::GetWidgetBorder(nsDeviceContext* aContext, nsIFrame* aFrame,
+ uint8_t aWidgetType, nsIntMargin* aResult)
+{
+ *aResult = nsIntMargin();
+ return NS_OK;
+}
+
+bool
+nsNativeThemeAndroid::GetWidgetPadding(nsDeviceContext* aContext,
+ nsIFrame* aFrame, uint8_t aWidgetType,
+ nsIntMargin* aResult)
+{
+ return false;
+}
+
+bool
+nsNativeThemeAndroid::GetWidgetOverflow(nsDeviceContext* aContext,
+ nsIFrame* aFrame, uint8_t aWidgetType,
+ nsRect* aOverflowRect)
+{
+ return false;
+}
+
+NS_IMETHODIMP
+nsNativeThemeAndroid::GetMinimumWidgetSize(nsPresContext* aPresContext,
+ nsIFrame* aFrame, uint8_t aWidgetType,
+ LayoutDeviceIntSize* aResult,
+ bool* aIsOverridable)
+{
+ if (aWidgetType == NS_THEME_RADIO || aWidgetType == NS_THEME_CHECKBOX) {
+ // The fixed size of checkmark used in PaintCheckMark
+ aResult->width = 9;
+ aResult->height = 9;
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsNativeThemeAndroid::WidgetStateChanged(nsIFrame* aFrame, uint8_t aWidgetType,
+ nsIAtom* aAttribute, bool* aShouldRepaint,
+ const nsAttrValue* aOldValue)
+{
+ if (aWidgetType == NS_THEME_RADIO || aWidgetType == NS_THEME_CHECKBOX) {
+ if (aAttribute == nsGkAtoms::active ||
+ aAttribute == nsGkAtoms::disabled ||
+ aAttribute == nsGkAtoms::hover) {
+ *aShouldRepaint = true;
+ return NS_OK;
+ }
+ }
+
+ *aShouldRepaint = false;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsNativeThemeAndroid::ThemeChanged()
+{
+ return NS_OK;
+}
+
+NS_IMETHODIMP_(bool)
+nsNativeThemeAndroid::ThemeSupportsWidget(nsPresContext* aPresContext,
+ nsIFrame* aFrame,
+ uint8_t aWidgetType)
+{
+ switch (aWidgetType) {
+ case NS_THEME_RADIO:
+ case NS_THEME_CHECKBOX:
+ return true;
+ }
+
+ return false;
+}
+
+NS_IMETHODIMP_(bool)
+nsNativeThemeAndroid::WidgetIsContainer(uint8_t aWidgetType)
+{
+ return false;
+}
+
+bool
+nsNativeThemeAndroid::ThemeDrawsFocusForWidget(uint8_t aWidgetType)
+{
+ return false;
+}
+
+bool
+nsNativeThemeAndroid::ThemeNeedsComboboxDropmarker()
+{
+ return false;
+}
+
+nsITheme::Transparency
+nsNativeThemeAndroid::GetWidgetTransparency(nsIFrame* aFrame, uint8_t aWidgetType)
+{
+ return eUnknownTransparency;
+}
new file mode 100644
--- /dev/null
+++ b/widget/android/nsNativeThemeAndroid.h
@@ -0,0 +1,68 @@
+/* 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/. */
+
+#ifndef nsNativeThemeAndroid_h_
+#define nsNativeThemeAndroid_h_
+
+#include "nsITheme.h"
+#include "nsNativeTheme.h"
+
+class nsNativeThemeAndroid final: private nsNativeTheme,
+ public nsITheme
+{
+public:
+ NS_DECL_ISUPPORTS_INHERITED
+
+ // The nsITheme interface.
+ NS_IMETHOD DrawWidgetBackground(gfxContext* aContext,
+ nsIFrame* aFrame, uint8_t aWidgetType,
+ const nsRect& aRect,
+ const nsRect& aDirtyRect) override;
+
+ NS_IMETHOD GetWidgetBorder(nsDeviceContext* aContext, nsIFrame* aFrame,
+ uint8_t aWidgetType,
+ nsIntMargin* aResult) override;
+
+ bool GetWidgetPadding(nsDeviceContext* aContext,
+ nsIFrame* aFrame,
+ uint8_t aWidgetType,
+ nsIntMargin* aResult) override;
+
+ bool GetWidgetOverflow(nsDeviceContext* aContext,
+ nsIFrame* aFrame,
+ uint8_t aWidgetType,
+ nsRect* aOverflowRect) override;
+
+ NS_IMETHOD GetMinimumWidgetSize(nsPresContext* aPresContext,
+ nsIFrame* aFrame, uint8_t aWidgetType,
+ mozilla::LayoutDeviceIntSize* aResult,
+ bool* aIsOverridable) override;
+
+ NS_IMETHOD WidgetStateChanged(nsIFrame* aFrame, uint8_t aWidgetType,
+ nsIAtom* aAttribute,
+ bool* aShouldRepaint,
+ const nsAttrValue* aOldValue) override;
+
+ NS_IMETHOD ThemeChanged() override;
+
+ NS_IMETHOD_(bool) ThemeSupportsWidget(nsPresContext* aPresContext,
+ nsIFrame* aFrame,
+ uint8_t aWidgetType) override;
+
+ NS_IMETHOD_(bool) WidgetIsContainer(uint8_t aWidgetType) override;
+
+ NS_IMETHOD_(bool) ThemeDrawsFocusForWidget(uint8_t aWidgetType) override;
+
+ bool ThemeNeedsComboboxDropmarker() override;
+
+ Transparency GetWidgetTransparency(nsIFrame* aFrame,
+ uint8_t aWidgetType) override;
+
+ nsNativeThemeAndroid() {}
+
+protected:
+ virtual ~nsNativeThemeAndroid() {}
+};
+
+#endif // nsNativeThemeAndroid_h_
--- a/widget/android/nsWidgetFactory.cpp
+++ b/widget/android/nsWidgetFactory.cpp
@@ -24,16 +24,17 @@
#include "nsPrintSession.h"
#include "nsDeviceContextAndroid.h"
#include "nsHTMLFormatConverter.h"
#include "nsXULAppAPI.h"
#include "nsAndroidProtocolHandler.h"
#include "nsToolkitCompsCID.h"
#include "AndroidAlerts.h"
+#include "nsNativeThemeAndroid.h"
NS_GENERIC_FACTORY_CONSTRUCTOR(nsWindow)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsScreenManagerAndroid)
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsIdleServiceAndroid, nsIdleServiceAndroid::GetInstance)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsTransferable)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsClipboard)
NS_GENERIC_FACTORY_CONSTRUCTOR(nsClipboardHelper)
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsPrintOptionsAndroid, Init)
@@ -47,20 +48,41 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsAndroid
namespace mozilla {
namespace widget {
// This constructor should really be shared with all platforms.
NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(GfxInfo, Init)
NS_GENERIC_FACTORY_CONSTRUCTOR(AndroidAlerts)
}
}
+static nsresult
+nsNativeThemeAndroidConstructor(nsISupports *aOuter, REFNSIID aIID,
+ void **aResult)
+{
+ nsresult rv;
+
+ if (aOuter) {
+ rv = NS_ERROR_NO_AGGREGATION;
+ return rv;
+ }
+
+ *aResult = nullptr;
+ nsNativeThemeAndroid* inst = new nsNativeThemeAndroid();
+ NS_ADDREF(inst);
+ rv = inst->QueryInterface(aIID, aResult);
+ NS_RELEASE(inst);
+
+ return rv;
+}
+
NS_DEFINE_NAMED_CID(NS_APPSHELL_CID);
NS_DEFINE_NAMED_CID(NS_WINDOW_CID);
NS_DEFINE_NAMED_CID(NS_CHILD_CID);
NS_DEFINE_NAMED_CID(NS_SCREENMANAGER_CID);
+NS_DEFINE_NAMED_CID(NS_THEMERENDERER_CID);
NS_DEFINE_NAMED_CID(NS_IDLE_SERVICE_CID);
NS_DEFINE_NAMED_CID(NS_TRANSFERABLE_CID);
NS_DEFINE_NAMED_CID(NS_CLIPBOARD_CID);
NS_DEFINE_NAMED_CID(NS_CLIPBOARDHELPER_CID);
NS_DEFINE_NAMED_CID(NS_PRINTSETTINGSSERVICE_CID);
NS_DEFINE_NAMED_CID(NS_PRINTSESSION_CID);
NS_DEFINE_NAMED_CID(NS_DEVICE_CONTEXT_SPEC_CID);
NS_DEFINE_NAMED_CID(NS_HTMLFORMATCONVERTER_CID);
@@ -69,16 +91,17 @@ NS_DEFINE_NAMED_CID(NS_ANDROIDBRIDGE_CID
NS_DEFINE_NAMED_CID(NS_ANDROIDPROTOCOLHANDLER_CID);
NS_DEFINE_NAMED_CID(NS_SYSTEMALERTSSERVICE_CID);
static const mozilla::Module::CIDEntry kWidgetCIDs[] = {
{ &kNS_WINDOW_CID, false, nullptr, nsWindowConstructor },
{ &kNS_CHILD_CID, false, nullptr, nsWindowConstructor },
{ &kNS_APPSHELL_CID, false, nullptr, nsAppShellConstructor },
{ &kNS_SCREENMANAGER_CID, false, nullptr, nsScreenManagerAndroidConstructor },
+ { &kNS_THEMERENDERER_CID, false, nullptr, nsNativeThemeAndroidConstructor },
{ &kNS_IDLE_SERVICE_CID, false, nullptr, nsIdleServiceAndroidConstructor },
{ &kNS_TRANSFERABLE_CID, false, nullptr, nsTransferableConstructor },
{ &kNS_CLIPBOARD_CID, false, nullptr, nsClipboardConstructor },
{ &kNS_CLIPBOARDHELPER_CID, false, nullptr, nsClipboardHelperConstructor },
{ &kNS_PRINTSETTINGSSERVICE_CID, false, nullptr, nsPrintOptionsAndroidConstructor },
{ &kNS_PRINTSESSION_CID, false, nullptr, nsPrintSessionConstructor },
{ &kNS_DEVICE_CONTEXT_SPEC_CID, false, nullptr, nsDeviceContextSpecAndroidConstructor },
{ &kNS_HTMLFORMATCONVERTER_CID, false, nullptr, nsHTMLFormatConverterConstructor },
@@ -89,16 +112,17 @@ static const mozilla::Module::CIDEntry k
{ nullptr }
};
static const mozilla::Module::ContractIDEntry kWidgetContracts[] = {
{ "@mozilla.org/widgets/window/android;1", &kNS_WINDOW_CID },
{ "@mozilla.org/widgets/child_window/android;1", &kNS_CHILD_CID },
{ "@mozilla.org/widget/appshell/android;1", &kNS_APPSHELL_CID },
{ "@mozilla.org/gfx/screenmanager;1", &kNS_SCREENMANAGER_CID },
+ { "@mozilla.org/chrome/chrome-native-theme;1", &kNS_THEMERENDERER_CID },
{ "@mozilla.org/widget/idleservice;1", &kNS_IDLE_SERVICE_CID },
{ "@mozilla.org/widget/transferable;1", &kNS_TRANSFERABLE_CID },
{ "@mozilla.org/widget/clipboard;1", &kNS_CLIPBOARD_CID },
{ "@mozilla.org/widget/clipboardhelper;1", &kNS_CLIPBOARDHELPER_CID },
{ "@mozilla.org/gfx/printsettings-service;1", &kNS_PRINTSETTINGSSERVICE_CID },
{ "@mozilla.org/gfx/printsession;1", &kNS_PRINTSESSION_CID },
{ "@mozilla.org/gfx/devicecontextspec;1", &kNS_DEVICE_CONTEXT_SPEC_CID },
{ "@mozilla.org/widget/htmlformatconverter;1", &kNS_HTMLFORMATCONVERTER_CID },
--- a/widget/moz.build
+++ b/widget/moz.build
@@ -258,17 +258,17 @@ if toolkit in ('cocoa', 'windows'):
]
if toolkit in {'gtk2', 'gtk3', 'cocoa', 'windows',
'android', 'uikit'}:
UNIFIED_SOURCES += [
'nsBaseFilePicker.cpp',
]
-if toolkit in ('gtk2', 'gtk3', 'windows', 'cocoa'):
+if toolkit in ('gtk2', 'gtk3', 'windows', 'cocoa', 'android'):
UNIFIED_SOURCES += [
'nsNativeTheme.cpp',
]
if toolkit == 'gtk3':
XPIDL_SOURCES += [
'nsIApplicationChooser.idl',
]