summaryrefslogtreecommitdiffstats
path: root/widget/uikit
diff options
context:
space:
mode:
Diffstat (limited to 'widget/uikit')
-rw-r--r--widget/uikit/GfxInfo.cpp218
-rw-r--r--widget/uikit/GfxInfo.h78
-rw-r--r--widget/uikit/moz.build19
-rw-r--r--widget/uikit/nsAppShell.h57
-rw-r--r--widget/uikit/nsAppShell.mm271
-rw-r--r--widget/uikit/nsLookAndFeel.h35
-rw-r--r--widget/uikit/nsLookAndFeel.mm401
-rw-r--r--widget/uikit/nsScreenManager.h60
-rw-r--r--widget/uikit/nsScreenManager.mm146
-rw-r--r--widget/uikit/nsWidgetFactory.mm71
-rw-r--r--widget/uikit/nsWindow.h125
-rw-r--r--widget/uikit/nsWindow.mm862
12 files changed, 2343 insertions, 0 deletions
diff --git a/widget/uikit/GfxInfo.cpp b/widget/uikit/GfxInfo.cpp
new file mode 100644
index 000000000..2aea3b5ea
--- /dev/null
+++ b/widget/uikit/GfxInfo.cpp
@@ -0,0 +1,218 @@
+/* -*- Mode: C++; tab-width: 2; 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 "GfxInfo.h"
+#include "nsServiceManagerUtils.h"
+
+namespace mozilla {
+namespace widget {
+
+
+#ifdef DEBUG
+NS_IMPL_ISUPPORTS_INHERITED(GfxInfo, GfxInfoBase, nsIGfxInfoDebug)
+#endif
+
+GfxInfo::GfxInfo()
+{
+}
+
+GfxInfo::~GfxInfo()
+{
+}
+
+nsresult
+GfxInfo::GetD2DEnabled(bool *aEnabled)
+{
+ return NS_ERROR_FAILURE;
+}
+
+nsresult
+GfxInfo::GetDWriteEnabled(bool *aEnabled)
+{
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+GfxInfo::GetDWriteVersion(nsAString & aDwriteVersion)
+{
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+GfxInfo::GetCleartypeParameters(nsAString & aCleartypeParams)
+{
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+GfxInfo::GetAdapterDescription(nsAString & aAdapterDescription)
+{
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+GfxInfo::GetAdapterDescription2(nsAString & aAdapterDescription)
+{
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+GfxInfo::GetAdapterRAM(nsAString & aAdapterRAM)
+{
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+GfxInfo::GetAdapterRAM2(nsAString & aAdapterRAM)
+{
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+GfxInfo::GetAdapterDriver(nsAString & aAdapterDriver)
+{
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+GfxInfo::GetAdapterDriver2(nsAString & aAdapterDriver)
+{
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+GfxInfo::GetAdapterDriverVersion(nsAString & aAdapterDriverVersion)
+{
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+GfxInfo::GetAdapterDriverVersion2(nsAString & aAdapterDriverVersion)
+{
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+GfxInfo::GetAdapterDriverDate(nsAString & aAdapterDriverDate)
+{
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+GfxInfo::GetAdapterDriverDate2(nsAString & aAdapterDriverDate)
+{
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+GfxInfo::GetAdapterVendorID(nsAString & aAdapterVendorID)
+{
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+GfxInfo::GetAdapterVendorID2(nsAString & aAdapterVendorID)
+{
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+GfxInfo::GetAdapterDeviceID(nsAString & aAdapterDeviceID)
+{
+ return NS_ERROR_FAILURE;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+GfxInfo::GetAdapterDeviceID2(nsAString & aAdapterDeviceID)
+{
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+GfxInfo::GetAdapterSubsysID(nsAString & aAdapterSubsysID)
+{
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+GfxInfo::GetAdapterSubsysID2(nsAString & aAdapterSubsysID)
+{
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP
+GfxInfo::GetIsGPU2Active(bool* aIsGPU2Active)
+{
+ return NS_ERROR_FAILURE;
+}
+
+const nsTArray<GfxDriverInfo>&
+GfxInfo::GetGfxDriverInfo()
+{
+ if (mDriverInfo->IsEmpty()) {
+ APPEND_TO_DRIVER_BLOCKLIST2(OperatingSystem::Ios,
+ (nsAString&) GfxDriverInfo::GetDeviceVendor(VendorAll), GfxDriverInfo::allDevices,
+ nsIGfxInfo::FEATURE_OPENGL_LAYERS, nsIGfxInfo::FEATURE_STATUS_OK,
+ DRIVER_COMPARISON_IGNORED, GfxDriverInfo::allDriverVersions );
+ }
+
+ return *mDriverInfo;
+}
+
+nsresult
+GfxInfo::GetFeatureStatusImpl(int32_t aFeature,
+ int32_t *aStatus,
+ nsAString & aSuggestedDriverVersion,
+ const nsTArray<GfxDriverInfo>& aDriverInfo,
+ OperatingSystem* aOS /* = nullptr */)
+{
+ NS_ENSURE_ARG_POINTER(aStatus);
+ aSuggestedDriverVersion.SetIsVoid(true);
+ *aStatus = nsIGfxInfo::FEATURE_STATUS_UNKNOWN;
+ if (aOS)
+ *aOS = OperatingSystem::Ios;
+
+ // OpenGL layers are never blacklisted on iOS.
+ // This early return is so we avoid potentially slow
+ // GLStrings initialization on startup when we initialize GL layers.
+ if (aFeature == nsIGfxInfo::FEATURE_OPENGL_LAYERS ||
+ aFeature == nsIGfxInfo::FEATURE_WEBGL_OPENGL ||
+ aFeature == nsIGfxInfo::FEATURE_WEBGL_MSAA) {
+ *aStatus = nsIGfxInfo::FEATURE_STATUS_OK;
+ return NS_OK;
+ }
+
+ return GfxInfoBase::GetFeatureStatusImpl(aFeature, aStatus, aSuggestedDriverVersion, aDriverInfo, aOS);
+}
+
+#ifdef DEBUG
+
+// Implement nsIGfxInfoDebug
+
+NS_IMETHODIMP GfxInfo::SpoofVendorID(const nsAString & aVendorID)
+{
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP GfxInfo::SpoofDeviceID(const nsAString & aDeviceID)
+{
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP GfxInfo::SpoofDriverVersion(const nsAString & aDriverVersion)
+{
+ return NS_ERROR_FAILURE;
+}
+
+NS_IMETHODIMP GfxInfo::SpoofOSVersion(uint32_t aVersion)
+{
+ return NS_ERROR_FAILURE;
+}
+
+#endif
+
+}
+}
diff --git a/widget/uikit/GfxInfo.h b/widget/uikit/GfxInfo.h
new file mode 100644
index 000000000..16a224251
--- /dev/null
+++ b/widget/uikit/GfxInfo.h
@@ -0,0 +1,78 @@
+/* vim: se cin sw=2 ts=2 et : */
+/* -*- Mode: C++; tab-width: 2; 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/. */
+
+#ifndef __mozilla_widget_GfxInfo_h__
+#define __mozilla_widget_GfxInfo_h__
+
+#include "GfxInfoBase.h"
+#include "GfxDriverInfo.h"
+
+#include "nsString.h"
+#include "mozilla/UniquePtr.h"
+
+namespace mozilla {
+
+namespace gl {
+class GLContext;
+}
+
+namespace widget {
+
+class GfxInfo : public GfxInfoBase
+{
+private:
+ ~GfxInfo();
+
+public:
+ GfxInfo();
+
+ // We only declare the subset of nsIGfxInfo that we actually implement. The
+ // rest is brought forward from GfxInfoBase.
+ NS_IMETHOD GetD2DEnabled(bool *aD2DEnabled);
+ NS_IMETHOD GetDWriteEnabled(bool *aDWriteEnabled);
+ NS_IMETHOD GetDWriteVersion(nsAString & aDwriteVersion);
+ NS_IMETHOD GetCleartypeParameters(nsAString & aCleartypeParams);
+ NS_IMETHOD GetAdapterDescription(nsAString & aAdapterDescription);
+ NS_IMETHOD GetAdapterDriver(nsAString & aAdapterDriver);
+ NS_IMETHOD GetAdapterVendorID(nsAString & aAdapterVendorID);
+ NS_IMETHOD GetAdapterDeviceID(nsAString & aAdapterDeviceID);
+ NS_IMETHOD GetAdapterSubsysID(nsAString & aAdapterSubsysID);
+ NS_IMETHOD GetAdapterRAM(nsAString & aAdapterRAM);
+ NS_IMETHOD GetAdapterDriverVersion(nsAString & aAdapterDriverVersion);
+ NS_IMETHOD GetAdapterDriverDate(nsAString & aAdapterDriverDate);
+ NS_IMETHOD GetAdapterDescription2(nsAString & aAdapterDescription);
+ NS_IMETHOD GetAdapterDriver2(nsAString & aAdapterDriver);
+ NS_IMETHOD GetAdapterVendorID2(nsAString & aAdapterVendorID);
+ NS_IMETHOD GetAdapterDeviceID2(nsAString & aAdapterDeviceID);
+ NS_IMETHOD GetAdapterSubsysID2(nsAString & aAdapterSubsysID);
+ NS_IMETHOD GetAdapterRAM2(nsAString & aAdapterRAM);
+ NS_IMETHOD GetAdapterDriverVersion2(nsAString & aAdapterDriverVersion);
+ NS_IMETHOD GetAdapterDriverDate2(nsAString & aAdapterDriverDate);
+ NS_IMETHOD GetIsGPU2Active(bool *aIsGPU2Active);
+ using GfxInfoBase::GetFeatureStatus;
+ using GfxInfoBase::GetFeatureSuggestedDriverVersion;
+ using GfxInfoBase::GetWebGLParameter;
+
+#ifdef DEBUG
+ NS_DECL_ISUPPORTS_INHERITED
+ NS_DECL_NSIGFXINFODEBUG
+#endif
+
+protected:
+
+ virtual nsresult GetFeatureStatusImpl(int32_t aFeature,
+ int32_t *aStatus,
+ nsAString & aSuggestedDriverVersion,
+ const nsTArray<GfxDriverInfo>& aDriverInfo,
+ OperatingSystem* aOS = nullptr);
+ virtual const nsTArray<GfxDriverInfo>& GetGfxDriverInfo();
+};
+
+} // namespace widget
+} // namespace mozilla
+
+#endif /* __mozilla_widget_GfxInfo_h__ */
diff --git a/widget/uikit/moz.build b/widget/uikit/moz.build
new file mode 100644
index 000000000..50aed405b
--- /dev/null
+++ b/widget/uikit/moz.build
@@ -0,0 +1,19 @@
+# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
+# vim: set filetype=python:
+# 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/.
+
+SOURCES += [
+ 'GfxInfo.cpp',
+ 'nsAppShell.mm',
+ 'nsLookAndFeel.mm',
+ 'nsScreenManager.mm',
+ 'nsWidgetFactory.mm',
+ 'nsWindow.mm',
+]
+
+FINAL_LIBRARY = 'xul'
+LOCAL_INCLUDES += [
+ '/widget',
+]
diff --git a/widget/uikit/nsAppShell.h b/widget/uikit/nsAppShell.h
new file mode 100644
index 000000000..a88fa8b4f
--- /dev/null
+++ b/widget/uikit/nsAppShell.h
@@ -0,0 +1,57 @@
+/* -*- Mode: C++; tab-width: 4; 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/. */
+
+/*
+ * Runs the main native UIKit run loop, interrupting it as needed to process
+ * Gecko events.
+ */
+
+#ifndef nsAppShell_h_
+#define nsAppShell_h_
+
+#include "nsBaseAppShell.h"
+#include "nsTArray.h"
+
+#include <Foundation/NSAutoreleasePool.h>
+#include <CoreFoundation/CFRunLoop.h>
+#include <UIKit/UIWindow.h>
+
+@class AppShellDelegate;
+
+class nsAppShell : public nsBaseAppShell
+{
+public:
+ NS_IMETHOD ResumeNative(void);
+
+ nsAppShell();
+
+ nsresult Init();
+
+ NS_IMETHOD Run(void);
+ NS_IMETHOD Exit(void);
+ // Called by the application delegate
+ void WillTerminate(void);
+
+ static nsAppShell* gAppShell;
+ static UIWindow* gWindow;
+ static NSMutableArray* gTopLevelViews;
+
+protected:
+ virtual ~nsAppShell();
+
+ static void ProcessGeckoEvents(void* aInfo);
+ virtual void ScheduleNativeEventCallback();
+ virtual bool ProcessNextNativeEvent(bool aMayWait);
+
+ NSAutoreleasePool* mAutoreleasePool;
+ AppShellDelegate* mDelegate;
+ CFRunLoopRef mCFRunLoop;
+ CFRunLoopSourceRef mCFRunLoopSource;
+
+ bool mTerminated;
+ bool mNotifiedWillTerminate;
+};
+
+#endif // nsAppShell_h_
diff --git a/widget/uikit/nsAppShell.mm b/widget/uikit/nsAppShell.mm
new file mode 100644
index 000000000..ac007132f
--- /dev/null
+++ b/widget/uikit/nsAppShell.mm
@@ -0,0 +1,271 @@
+/* -*- Mode: C++; tab-width: 4; 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/. */
+
+#import <UIKit/UIApplication.h>
+#import <UIKit/UIScreen.h>
+#import <UIKit/UIWindow.h>
+#import <UIKit/UIViewController.h>
+
+#include "nsAppShell.h"
+#include "nsCOMPtr.h"
+#include "nsIFile.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsString.h"
+#include "nsIRollupListener.h"
+#include "nsIWidget.h"
+#include "nsThreadUtils.h"
+#include "nsIWindowMediator.h"
+#include "nsMemoryPressure.h"
+#include "nsServiceManagerUtils.h"
+#include "nsIInterfaceRequestor.h"
+#include "nsIWebBrowserChrome.h"
+
+nsAppShell *nsAppShell::gAppShell = NULL;
+UIWindow *nsAppShell::gWindow = nil;
+NSMutableArray *nsAppShell::gTopLevelViews = [[NSMutableArray alloc] init];
+
+#define ALOG(args...) fprintf(stderr, args); fprintf(stderr, "\n")
+
+// ViewController
+@interface ViewController : UIViewController
+@end
+
+
+@implementation ViewController
+
+- (void)loadView {
+ ALOG("[ViewController loadView]");
+ CGRect r = {{0, 0}, {100, 100}};
+ self.view = [[UIView alloc] initWithFrame:r];
+ [self.view setBackgroundColor:[UIColor lightGrayColor]];
+ // add all of the top level views as children
+ for (UIView* v in nsAppShell::gTopLevelViews) {
+ ALOG("[ViewController.view addSubView:%p]", v);
+ [self.view addSubview:v];
+ }
+ [nsAppShell::gTopLevelViews release];
+ nsAppShell::gTopLevelViews = nil;
+}
+@end
+
+// AppShellDelegate
+//
+// Acts as a delegate for the UIApplication
+
+@interface AppShellDelegate : NSObject <UIApplicationDelegate> {
+}
+@property (strong, nonatomic) UIWindow *window;
+@end
+
+@implementation AppShellDelegate
+
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
+{
+ ALOG("[AppShellDelegate application:didFinishLaunchingWithOptions:]");
+ // We only create one window, since we can only display one window at
+ // a time anyway. Also, iOS 4 fails to display UIWindows if you
+ // create them before calling UIApplicationMain, so this makes more sense.
+ nsAppShell::gWindow = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]] retain];
+ self.window = nsAppShell::gWindow;
+
+ self.window.rootViewController = [[ViewController alloc] init];
+
+ // just to make things more visible for now
+ nsAppShell::gWindow.backgroundColor = [UIColor blueColor];
+ [nsAppShell::gWindow makeKeyAndVisible];
+
+ return YES;
+}
+
+- (void)applicationWillTerminate:(UIApplication *)application
+{
+ ALOG("[AppShellDelegate applicationWillTerminate:]");
+ nsAppShell::gAppShell->WillTerminate();
+}
+
+- (void)applicationDidBecomeActive:(UIApplication *)application
+{
+ ALOG("[AppShellDelegate applicationDidBecomeActive:]");
+}
+
+- (void)applicationWillResignActive:(UIApplication *)application
+{
+ ALOG("[AppShellDelegate applicationWillResignActive:]");
+}
+
+- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application
+{
+ ALOG("[AppShellDelegate applicationDidReceiveMemoryWarning:]");
+ NS_DispatchMemoryPressure(MemPressure_New);
+}
+@end
+
+// nsAppShell implementation
+
+NS_IMETHODIMP
+nsAppShell::ResumeNative(void)
+{
+ return nsBaseAppShell::ResumeNative();
+}
+
+nsAppShell::nsAppShell()
+ : mAutoreleasePool(NULL),
+ mDelegate(NULL),
+ mCFRunLoop(NULL),
+ mCFRunLoopSource(NULL),
+ mTerminated(false),
+ mNotifiedWillTerminate(false)
+{
+ gAppShell = this;
+}
+
+nsAppShell::~nsAppShell()
+{
+ if (mAutoreleasePool) {
+ [mAutoreleasePool release];
+ mAutoreleasePool = NULL;
+ }
+
+ if (mCFRunLoop) {
+ if (mCFRunLoopSource) {
+ ::CFRunLoopRemoveSource(mCFRunLoop, mCFRunLoopSource,
+ kCFRunLoopCommonModes);
+ ::CFRelease(mCFRunLoopSource);
+ }
+ ::CFRelease(mCFRunLoop);
+ }
+
+ gAppShell = NULL;
+}
+
+// Init
+//
+// public
+nsresult
+nsAppShell::Init()
+{
+ mAutoreleasePool = [[NSAutoreleasePool alloc] init];
+
+ // Add a CFRunLoopSource to the main native run loop. The source is
+ // responsible for interrupting the run loop when Gecko events are ready.
+
+ mCFRunLoop = [[NSRunLoop currentRunLoop] getCFRunLoop];
+ NS_ENSURE_STATE(mCFRunLoop);
+ ::CFRetain(mCFRunLoop);
+
+ CFRunLoopSourceContext context;
+ bzero(&context, sizeof(context));
+ // context.version = 0;
+ context.info = this;
+ context.perform = ProcessGeckoEvents;
+
+ mCFRunLoopSource = ::CFRunLoopSourceCreate(kCFAllocatorDefault, 0, &context);
+ NS_ENSURE_STATE(mCFRunLoopSource);
+
+ ::CFRunLoopAddSource(mCFRunLoop, mCFRunLoopSource, kCFRunLoopCommonModes);
+
+ return nsBaseAppShell::Init();
+}
+
+// ProcessGeckoEvents
+//
+// The "perform" target of mCFRunLoop, called when mCFRunLoopSource is
+// signalled from ScheduleNativeEventCallback.
+//
+// protected static
+void
+nsAppShell::ProcessGeckoEvents(void* aInfo)
+{
+ nsAppShell* self = static_cast<nsAppShell*> (aInfo);
+ self->NativeEventCallback();
+ self->Release();
+}
+
+// WillTerminate
+//
+// public
+void
+nsAppShell::WillTerminate()
+{
+ mNotifiedWillTerminate = true;
+ if (mTerminated)
+ return;
+ mTerminated = true;
+ // We won't get another chance to process events
+ NS_ProcessPendingEvents(NS_GetCurrentThread());
+
+ // Unless we call nsBaseAppShell::Exit() here, it might not get called
+ // at all.
+ nsBaseAppShell::Exit();
+}
+
+// ScheduleNativeEventCallback
+//
+// protected virtual
+void
+nsAppShell::ScheduleNativeEventCallback()
+{
+ if (mTerminated)
+ return;
+
+ NS_ADDREF_THIS();
+
+ // This will invoke ProcessGeckoEvents on the main thread.
+ ::CFRunLoopSourceSignal(mCFRunLoopSource);
+ ::CFRunLoopWakeUp(mCFRunLoop);
+}
+
+// ProcessNextNativeEvent
+//
+// protected virtual
+bool
+nsAppShell::ProcessNextNativeEvent(bool aMayWait)
+{
+ if (mTerminated)
+ return false;
+
+ NSString* currentMode = nil;
+ NSDate* waitUntil = nil;
+ if (aMayWait)
+ waitUntil = [NSDate distantFuture];
+ NSRunLoop* currentRunLoop = [NSRunLoop currentRunLoop];
+
+ BOOL eventProcessed = NO;
+ do {
+ currentMode = [currentRunLoop currentMode];
+ if (!currentMode)
+ currentMode = NSDefaultRunLoopMode;
+
+ if (aMayWait)
+ eventProcessed = [currentRunLoop runMode:currentMode beforeDate:waitUntil];
+ else
+ [currentRunLoop acceptInputForMode:currentMode beforeDate:waitUntil];
+ } while(eventProcessed && aMayWait);
+
+ return false;
+}
+
+// Run
+//
+// public
+NS_IMETHODIMP
+nsAppShell::Run(void)
+{
+ ALOG("nsAppShell::Run");
+ char argv[1][4] = {"app"};
+ UIApplicationMain(1, (char**)argv, nil, @"AppShellDelegate");
+ // UIApplicationMain doesn't exit. :-(
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsAppShell::Exit(void)
+{
+ if (mTerminated)
+ return NS_OK;
+
+ mTerminated = true;
+ return nsBaseAppShell::Exit();
+}
diff --git a/widget/uikit/nsLookAndFeel.h b/widget/uikit/nsLookAndFeel.h
new file mode 100644
index 000000000..91c0c2d73
--- /dev/null
+++ b/widget/uikit/nsLookAndFeel.h
@@ -0,0 +1,35 @@
+/* -*- Mode: C++; tab-width: 4; 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 __nsLookAndFeel
+#define __nsLookAndFeel
+
+#include "nsXPLookAndFeel.h"
+
+class nsLookAndFeel: public nsXPLookAndFeel
+{
+public:
+ nsLookAndFeel();
+ virtual ~nsLookAndFeel();
+
+ virtual nsresult NativeGetColor(const ColorID aID, nscolor &aResult);
+ virtual nsresult GetIntImpl(IntID aID, int32_t &aResult);
+ virtual nsresult GetFloatImpl(FloatID aID, float &aResult);
+ virtual bool GetFontImpl(FontID aID, nsString& aFontName,
+ gfxFontStyle& aFontStyle,
+ float aDevPixPerCSSPixel);
+ virtual char16_t GetPasswordCharacterImpl()
+ {
+ // unicode value for the bullet character, used for password textfields.
+ return 0x2022;
+ }
+
+ static bool UseOverlayScrollbars()
+ {
+ return true;
+ }
+};
+
+#endif
diff --git a/widget/uikit/nsLookAndFeel.mm b/widget/uikit/nsLookAndFeel.mm
new file mode 100644
index 000000000..bb593eb51
--- /dev/null
+++ b/widget/uikit/nsLookAndFeel.mm
@@ -0,0 +1,401 @@
+/* -*- Mode: C++; tab-width: 4; 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/. */
+
+#import <UIKit/UIColor.h>
+#import <UIKit/UIInterface.h>
+
+#include "nsLookAndFeel.h"
+#include "nsStyleConsts.h"
+#include "gfxFont.h"
+#include "gfxFontConstants.h"
+
+nsLookAndFeel::nsLookAndFeel()
+ : nsXPLookAndFeel()
+{
+}
+
+nsLookAndFeel::~nsLookAndFeel()
+{
+}
+
+static nscolor GetColorFromUIColor(UIColor* aColor)
+{
+ CGColorRef cgColor = [aColor CGColor];
+ CGColorSpaceModel model = CGColorSpaceGetModel(CGColorGetColorSpace(cgColor));
+ const CGFloat* components = CGColorGetComponents(cgColor);
+ if (model == kCGColorSpaceModelRGB) {
+ return NS_RGB((unsigned int)(components[0] * 255.0),
+ (unsigned int)(components[1] * 255.0),
+ (unsigned int)(components[2] * 255.0));
+ }
+ else if (model == kCGColorSpaceModelMonochrome) {
+ unsigned int val = (unsigned int)(components[0] * 255.0);
+ return NS_RGBA(val, val, val,
+ (unsigned int)(components[1] * 255.0));
+ }
+ NS_NOTREACHED("Unhandled color space!");
+ return 0;
+}
+
+nsresult
+nsLookAndFeel::NativeGetColor(const ColorID aID, nscolor &aResult)
+{
+ nsresult res = NS_OK;
+
+ switch (aID) {
+ case eColorID_WindowBackground:
+ aResult = NS_RGB(0xff,0xff,0xff);
+ break;
+ case eColorID_WindowForeground:
+ aResult = NS_RGB(0x00,0x00,0x00);
+ break;
+ case eColorID_WidgetBackground:
+ aResult = NS_RGB(0xdd,0xdd,0xdd);
+ break;
+ case eColorID_WidgetForeground:
+ aResult = NS_RGB(0x00,0x00,0x00);
+ break;
+ case eColorID_WidgetSelectBackground:
+ aResult = NS_RGB(0x80,0x80,0x80);
+ break;
+ case eColorID_WidgetSelectForeground:
+ aResult = NS_RGB(0x00,0x00,0x80);
+ break;
+ case eColorID_Widget3DHighlight:
+ aResult = NS_RGB(0xa0,0xa0,0xa0);
+ break;
+ case eColorID_Widget3DShadow:
+ aResult = NS_RGB(0x40,0x40,0x40);
+ break;
+ case eColorID_TextBackground:
+ aResult = NS_RGB(0xff,0xff,0xff);
+ break;
+ case eColorID_TextForeground:
+ aResult = NS_RGB(0x00,0x00,0x00);
+ break;
+ case eColorID_TextSelectBackground:
+ case eColorID_highlight: // CSS2 color
+ aResult = NS_RGB(0xaa,0xaa,0xaa);
+ break;
+ case eColorID__moz_menuhover:
+ aResult = NS_RGB(0xee,0xee,0xee);
+ break;
+ case eColorID_TextSelectForeground:
+ case eColorID_highlighttext: // CSS2 color
+ case eColorID__moz_menuhovertext:
+ GetColor(eColorID_TextSelectBackground, aResult);
+ if (aResult == 0x000000)
+ aResult = NS_RGB(0xff,0xff,0xff);
+ else
+ aResult = NS_DONT_CHANGE_COLOR;
+ break;
+ case eColorID_IMESelectedRawTextBackground:
+ case eColorID_IMESelectedConvertedTextBackground:
+ case eColorID_IMERawInputBackground:
+ case eColorID_IMEConvertedTextBackground:
+ aResult = NS_TRANSPARENT;
+ break;
+ case eColorID_IMESelectedRawTextForeground:
+ case eColorID_IMESelectedConvertedTextForeground:
+ case eColorID_IMERawInputForeground:
+ case eColorID_IMEConvertedTextForeground:
+ aResult = NS_SAME_AS_FOREGROUND_COLOR;
+ break;
+ case eColorID_IMERawInputUnderline:
+ case eColorID_IMEConvertedTextUnderline:
+ aResult = NS_40PERCENT_FOREGROUND_COLOR;
+ break;
+ case eColorID_IMESelectedRawTextUnderline:
+ case eColorID_IMESelectedConvertedTextUnderline:
+ aResult = NS_SAME_AS_FOREGROUND_COLOR;
+ break;
+ case eColorID_SpellCheckerUnderline:
+ aResult = NS_RGB(0xff, 0, 0);
+ break;
+
+ //
+ // css2 system colors http://www.w3.org/TR/REC-CSS2/ui.html#system-colors
+ //
+ case eColorID_buttontext:
+ case eColorID__moz_buttonhovertext:
+ case eColorID_captiontext:
+ case eColorID_menutext:
+ case eColorID_infotext:
+ case eColorID__moz_menubartext:
+ case eColorID_windowtext:
+ aResult = GetColorFromUIColor([UIColor darkTextColor]);
+ break;
+ case eColorID_activecaption:
+ aResult = NS_RGB(0xff,0xff,0xff);
+ break;
+ case eColorID_activeborder:
+ aResult = NS_RGB(0x00,0x00,0x00);
+ break;
+ case eColorID_appworkspace:
+ aResult = NS_RGB(0xFF,0xFF,0xFF);
+ break;
+ case eColorID_background:
+ aResult = NS_RGB(0x63,0x63,0xCE);
+ break;
+ case eColorID_buttonface:
+ case eColorID__moz_buttonhoverface:
+ aResult = NS_RGB(0xF0,0xF0,0xF0);
+ break;
+ case eColorID_buttonhighlight:
+ aResult = NS_RGB(0xFF,0xFF,0xFF);
+ break;
+ case eColorID_buttonshadow:
+ aResult = NS_RGB(0xDC,0xDC,0xDC);
+ break;
+ case eColorID_graytext:
+ aResult = NS_RGB(0x44,0x44,0x44);
+ break;
+ case eColorID_inactiveborder:
+ aResult = NS_RGB(0xff,0xff,0xff);
+ break;
+ case eColorID_inactivecaption:
+ aResult = NS_RGB(0xaa,0xaa,0xaa);
+ break;
+ case eColorID_inactivecaptiontext:
+ aResult = NS_RGB(0x45,0x45,0x45);
+ break;
+ case eColorID_scrollbar:
+ aResult = NS_RGB(0,0,0); //XXX
+ break;
+ case eColorID_threeddarkshadow:
+ aResult = NS_RGB(0xDC,0xDC,0xDC);
+ break;
+ case eColorID_threedshadow:
+ aResult = NS_RGB(0xE0,0xE0,0xE0);
+ break;
+ case eColorID_threedface:
+ aResult = NS_RGB(0xF0,0xF0,0xF0);
+ break;
+ case eColorID_threedhighlight:
+ aResult = NS_RGB(0xff,0xff,0xff);
+ break;
+ case eColorID_threedlightshadow:
+ aResult = NS_RGB(0xDA,0xDA,0xDA);
+ break;
+ case eColorID_menu:
+ aResult = NS_RGB(0xff,0xff,0xff);
+ break;
+ case eColorID_infobackground:
+ aResult = NS_RGB(0xFF,0xFF,0xC7);
+ break;
+ case eColorID_windowframe:
+ aResult = NS_RGB(0xaa,0xaa,0xaa);
+ break;
+ case eColorID_window:
+ case eColorID__moz_field:
+ case eColorID__moz_combobox:
+ aResult = NS_RGB(0xff,0xff,0xff);
+ break;
+ case eColorID__moz_fieldtext:
+ case eColorID__moz_comboboxtext:
+ aResult = GetColorFromUIColor([UIColor darkTextColor]);
+ break;
+ case eColorID__moz_dialog:
+ aResult = NS_RGB(0xaa,0xaa,0xaa);
+ break;
+ case eColorID__moz_dialogtext:
+ case eColorID__moz_cellhighlighttext:
+ case eColorID__moz_html_cellhighlighttext:
+ aResult = GetColorFromUIColor([UIColor darkTextColor]);
+ break;
+ case eColorID__moz_dragtargetzone:
+ case eColorID__moz_mac_chrome_active:
+ case eColorID__moz_mac_chrome_inactive:
+ aResult = NS_RGB(0xaa,0xaa,0xaa);
+ break;
+ case eColorID__moz_mac_focusring:
+ aResult = NS_RGB(0x3F,0x98,0xDD);
+ break;
+ case eColorID__moz_mac_menushadow:
+ aResult = NS_RGB(0xA3,0xA3,0xA3);
+ break;
+ case eColorID__moz_mac_menutextdisable:
+ aResult = NS_RGB(0x88,0x88,0x88);
+ break;
+ case eColorID__moz_mac_menutextselect:
+ aResult = NS_RGB(0xaa,0xaa,0xaa);
+ break;
+ case eColorID__moz_mac_disabledtoolbartext:
+ aResult = NS_RGB(0x3F,0x3F,0x3F);
+ break;
+ case eColorID__moz_mac_menuselect:
+ aResult = NS_RGB(0xaa,0xaa,0xaa);
+ break;
+ case eColorID__moz_buttondefault:
+ aResult = NS_RGB(0xDC,0xDC,0xDC);
+ break;
+ case eColorID__moz_cellhighlight:
+ case eColorID__moz_html_cellhighlight:
+ case eColorID__moz_mac_secondaryhighlight:
+ // For inactive list selection
+ aResult = NS_RGB(0xaa,0xaa,0xaa);
+ break;
+ case eColorID__moz_eventreerow:
+ // Background color of even list rows.
+ aResult = NS_RGB(0xff,0xff,0xff);
+ break;
+ case eColorID__moz_oddtreerow:
+ // Background color of odd list rows.
+ aResult = NS_TRANSPARENT;
+ break;
+ case eColorID__moz_nativehyperlinktext:
+ // There appears to be no available system defined color. HARDCODING to the appropriate color.
+ aResult = NS_RGB(0x14,0x4F,0xAE);
+ break;
+ default:
+ NS_WARNING("Someone asked nsILookAndFeel for a color I don't know about");
+ aResult = NS_RGB(0xff,0xff,0xff);
+ res = NS_ERROR_FAILURE;
+ break;
+ }
+
+ return res;
+}
+
+NS_IMETHODIMP
+nsLookAndFeel::GetIntImpl(IntID aID, int32_t &aResult)
+{
+ nsresult res = nsXPLookAndFeel::GetIntImpl(aID, aResult);
+ if (NS_SUCCEEDED(res))
+ return res;
+ res = NS_OK;
+
+ switch (aID) {
+ case eIntID_CaretBlinkTime:
+ aResult = 567;
+ break;
+ case eIntID_CaretWidth:
+ aResult = 1;
+ break;
+ case eIntID_ShowCaretDuringSelection:
+ aResult = 0;
+ break;
+ case eIntID_SelectTextfieldsOnKeyFocus:
+ // Select textfield content when focused by kbd
+ // used by nsEventStateManager::sTextfieldSelectModel
+ aResult = 1;
+ break;
+ case eIntID_SubmenuDelay:
+ aResult = 200;
+ break;
+ case eIntID_MenusCanOverlapOSBar:
+ // xul popups are not allowed to overlap the menubar.
+ aResult = 0;
+ break;
+ case eIntID_SkipNavigatingDisabledMenuItem:
+ aResult = 1;
+ break;
+ case eIntID_DragThresholdX:
+ case eIntID_DragThresholdY:
+ aResult = 4;
+ break;
+ case eIntID_ScrollArrowStyle:
+ aResult = eScrollArrow_None;
+ break;
+ case eIntID_ScrollSliderStyle:
+ aResult = eScrollThumbStyle_Proportional;
+ break;
+ case eIntID_TreeOpenDelay:
+ aResult = 1000;
+ break;
+ case eIntID_TreeCloseDelay:
+ aResult = 1000;
+ break;
+ case eIntID_TreeLazyScrollDelay:
+ aResult = 150;
+ break;
+ case eIntID_TreeScrollDelay:
+ aResult = 100;
+ break;
+ case eIntID_TreeScrollLinesMax:
+ aResult = 3;
+ break;
+ case eIntID_DWMCompositor:
+ case eIntID_WindowsClassic:
+ case eIntID_WindowsDefaultTheme:
+ case eIntID_TouchEnabled:
+ aResult = 0;
+ res = NS_ERROR_NOT_IMPLEMENTED;
+ break;
+ case eIntID_MacGraphiteTheme:
+ aResult = 0;
+ break;
+ case eIntID_TabFocusModel:
+ aResult = 1; // default to just textboxes
+ break;
+ case eIntID_ScrollToClick:
+ aResult = 0;
+ break;
+ case eIntID_ChosenMenuItemsShouldBlink:
+ aResult = 1;
+ break;
+ case eIntID_IMERawInputUnderlineStyle:
+ case eIntID_IMEConvertedTextUnderlineStyle:
+ case eIntID_IMESelectedRawTextUnderlineStyle:
+ case eIntID_IMESelectedConvertedTextUnderline:
+ aResult = NS_STYLE_TEXT_DECORATION_STYLE_SOLID;
+ break;
+ case eIntID_SpellCheckerUnderlineStyle:
+ aResult = NS_STYLE_TEXT_DECORATION_STYLE_DOTTED;
+ break;
+ case eIntID_ContextMenuOffsetVertical:
+ case eIntID_ContextMenuOffsetHorizontal:
+ aResult = 2;
+ break;
+ default:
+ aResult = 0;
+ res = NS_ERROR_FAILURE;
+ }
+ return res;
+}
+
+NS_IMETHODIMP
+nsLookAndFeel::GetFloatImpl(FloatID aID, float &aResult)
+{
+ nsresult res = nsXPLookAndFeel::GetFloatImpl(aID, aResult);
+ if (NS_SUCCEEDED(res))
+ return res;
+ res = NS_OK;
+
+ switch (aID) {
+ case eFloatID_IMEUnderlineRelativeSize:
+ aResult = 2.0f;
+ break;
+ case eFloatID_SpellCheckerUnderlineRelativeSize:
+ aResult = 2.0f;
+ break;
+ default:
+ aResult = -1.0;
+ res = NS_ERROR_FAILURE;
+ }
+
+ return res;
+}
+
+bool
+nsLookAndFeel::GetFontImpl(FontID aID, nsString &aFontName,
+ gfxFontStyle &aFontStyle,
+ float aDevPixPerCSSPixel)
+{
+ // hack for now
+ if (aID == eFont_Window || aID == eFont_Document) {
+ aFontStyle.style = NS_FONT_STYLE_NORMAL;
+ aFontStyle.weight = NS_FONT_WEIGHT_NORMAL;
+ aFontStyle.stretch = NS_FONT_STRETCH_NORMAL;
+ aFontStyle.size = 14 * aDevPixPerCSSPixel;
+ aFontStyle.systemFont = true;
+
+ aFontName.AssignLiteral("sans-serif");
+ return true;
+ }
+
+ //TODO: implement more here?
+ return false;
+}
diff --git a/widget/uikit/nsScreenManager.h b/widget/uikit/nsScreenManager.h
new file mode 100644
index 000000000..1ff6a87ec
--- /dev/null
+++ b/widget/uikit/nsScreenManager.h
@@ -0,0 +1,60 @@
+/* -*- Mode: C++; tab-width: 4; 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 nsScreenManager_h_
+#define nsScreenManager_h_
+
+#include "nsBaseScreen.h"
+#include "nsIScreenManager.h"
+#include "nsCOMPtr.h"
+#include "nsRect.h"
+
+@class UIScreen;
+
+class UIKitScreen : public nsBaseScreen
+{
+public:
+ explicit UIKitScreen (UIScreen* screen);
+ ~UIKitScreen () {}
+
+ NS_IMETHOD GetId(uint32_t* outId) {
+ *outId = 0;
+ return NS_OK;
+ }
+
+ NS_IMETHOD GetRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight);
+ NS_IMETHOD GetAvailRect(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight);
+ NS_IMETHOD GetRectDisplayPix(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight);
+ NS_IMETHOD GetAvailRectDisplayPix(int32_t* aLeft, int32_t* aTop, int32_t* aWidth, int32_t* aHeight);
+ NS_IMETHOD GetPixelDepth(int32_t* aPixelDepth);
+ NS_IMETHOD GetColorDepth(int32_t* aColorDepth);
+ NS_IMETHOD GetContentsScaleFactor(double* aContentsScaleFactor);
+ NS_IMETHOD GetDefaultCSSScaleFactor(double* aScaleFactor)
+ {
+ return GetContentsScaleFactor(aScaleFactor);
+ }
+
+private:
+ UIScreen* mScreen;
+};
+
+class UIKitScreenManager : public nsIScreenManager
+{
+public:
+ UIKitScreenManager ();
+
+ NS_DECL_ISUPPORTS
+
+ NS_DECL_NSISCREENMANAGER
+
+ static LayoutDeviceIntRect GetBounds();
+
+private:
+ virtual ~UIKitScreenManager () {}
+ //TODO: support >1 screen, iPad supports external displays
+ nsCOMPtr<nsIScreen> mScreen;
+};
+
+#endif // nsScreenManager_h_
diff --git a/widget/uikit/nsScreenManager.mm b/widget/uikit/nsScreenManager.mm
new file mode 100644
index 000000000..601c911cd
--- /dev/null
+++ b/widget/uikit/nsScreenManager.mm
@@ -0,0 +1,146 @@
+/* -*- Mode: C++; tab-width: 4; 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/. */
+
+#import <UIKit/UIScreen.h>
+
+#include "gfxPoint.h"
+#include "nsScreenManager.h"
+#include "nsAppShell.h"
+
+static LayoutDeviceIntRect gScreenBounds;
+static bool gScreenBoundsSet = false;
+
+UIKitScreen::UIKitScreen(UIScreen* aScreen)
+{
+ mScreen = [aScreen retain];
+}
+
+NS_IMETHODIMP
+UIKitScreen::GetRect(int32_t *outX, int32_t *outY, int32_t *outWidth, int32_t *outHeight)
+{
+ return GetRectDisplayPix(outX, outY, outWidth, outHeight);
+}
+
+NS_IMETHODIMP
+UIKitScreen::GetAvailRect(int32_t *outX, int32_t *outY, int32_t *outWidth, int32_t *outHeight)
+{
+ return GetAvailRectDisplayPix(outX, outY, outWidth, outHeight);
+}
+
+NS_IMETHODIMP
+UIKitScreen::GetRectDisplayPix(int32_t *outX, int32_t *outY, int32_t *outWidth, int32_t *outHeight)
+{
+ nsIntRect rect = UIKitScreenManager::GetBounds();
+ *outX = rect.x;
+ *outY = rect.y;
+ *outWidth = rect.width;
+ *outHeight = rect.height;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+UIKitScreen::GetAvailRectDisplayPix(int32_t *outX, int32_t *outY, int32_t *outWidth, int32_t *outHeight)
+{
+ CGRect rect = [mScreen applicationFrame];
+ CGFloat scale = [mScreen scale];
+
+ *outX = rect.origin.x * scale;
+ *outY = rect.origin.y * scale;
+ *outWidth = rect.size.width * scale;
+ *outHeight = rect.size.height * scale;
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+UIKitScreen::GetPixelDepth(int32_t *aPixelDepth)
+{
+ // Close enough.
+ *aPixelDepth = 24;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+UIKitScreen::GetColorDepth(int32_t *aColorDepth)
+{
+ return GetPixelDepth(aColorDepth);
+}
+
+NS_IMETHODIMP
+UIKitScreen::GetContentsScaleFactor(double* aContentsScaleFactor)
+{
+ *aContentsScaleFactor = [mScreen scale];
+ return NS_OK;
+}
+
+NS_IMPL_ISUPPORTS(UIKitScreenManager, nsIScreenManager)
+
+UIKitScreenManager::UIKitScreenManager()
+: mScreen(new UIKitScreen([UIScreen mainScreen]))
+{
+}
+
+LayoutDeviceIntRect
+UIKitScreenManager::GetBounds()
+{
+ if (!gScreenBoundsSet) {
+ CGRect rect = [[UIScreen mainScreen] bounds];
+ CGFloat scale = [[UIScreen mainScreen] scale];
+ gScreenBounds.x = rect.origin.x * scale;
+ gScreenBounds.y = rect.origin.y * scale;
+ gScreenBounds.width = rect.size.width * scale;
+ gScreenBounds.height = rect.size.height * scale;
+ gScreenBoundsSet = true;
+ }
+ printf("UIKitScreenManager::GetBounds: %d %d %d %d\n",
+ gScreenBounds.x, gScreenBounds.y, gScreenBounds.width, gScreenBounds.height);
+ return gScreenBounds;
+}
+
+NS_IMETHODIMP
+UIKitScreenManager::GetPrimaryScreen(nsIScreen** outScreen)
+{
+ NS_IF_ADDREF(*outScreen = mScreen.get());
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+UIKitScreenManager::ScreenForRect(int32_t inLeft,
+ int32_t inTop,
+ int32_t inWidth,
+ int32_t inHeight,
+ nsIScreen** outScreen)
+{
+ return GetPrimaryScreen(outScreen);
+}
+
+NS_IMETHODIMP
+UIKitScreenManager::ScreenForId(uint32_t id,
+ nsIScreen** outScreen)
+{
+ return GetPrimaryScreen(outScreen);
+}
+
+NS_IMETHODIMP
+UIKitScreenManager::ScreenForNativeWidget(void* aWidget, nsIScreen** outScreen)
+{
+ return GetPrimaryScreen(outScreen);
+}
+
+NS_IMETHODIMP
+UIKitScreenManager::GetNumberOfScreens(uint32_t* aNumberOfScreens)
+{
+ //TODO: support multiple screens
+ *aNumberOfScreens = 1;
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+UIKitScreenManager::GetSystemDefaultScale(float* aScale)
+{
+ *aScale = [UIScreen mainScreen].scale;
+ return NS_OK;
+}
diff --git a/widget/uikit/nsWidgetFactory.mm b/widget/uikit/nsWidgetFactory.mm
new file mode 100644
index 000000000..9e4f028ff
--- /dev/null
+++ b/widget/uikit/nsWidgetFactory.mm
@@ -0,0 +1,71 @@
+/* -*- Mode: C++; tab-width: 4; 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/. */
+
+#include "nsIFactory.h"
+#include "nsISupports.h"
+#include "nsIComponentManager.h"
+#include "mozilla/ModuleUtils.h"
+
+#include "nsWidgetsCID.h"
+
+#include "nsAppShell.h"
+#include "nsAppShellSingleton.h"
+#include "nsLookAndFeel.h"
+#include "nsScreenManager.h"
+#include "nsWindow.h"
+
+NS_GENERIC_FACTORY_CONSTRUCTOR(UIKitScreenManager)
+NS_GENERIC_FACTORY_CONSTRUCTOR(nsWindow)
+
+#include "GfxInfo.h"
+namespace mozilla {
+namespace widget {
+// This constructor should really be shared with all platforms.
+NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(GfxInfo, Init)
+}
+}
+
+NS_DEFINE_NAMED_CID(NS_WINDOW_CID);
+NS_DEFINE_NAMED_CID(NS_CHILD_CID);
+NS_DEFINE_NAMED_CID(NS_APPSHELL_CID);
+NS_DEFINE_NAMED_CID(NS_SCREENMANAGER_CID);
+NS_DEFINE_NAMED_CID(NS_GFXINFO_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, UIKitScreenManagerConstructor },
+ { &kNS_GFXINFO_CID, false, nullptr, mozilla::widget::GfxInfoConstructor },
+ { nullptr }
+};
+
+static const mozilla::Module::ContractIDEntry kWidgetContracts[] = {
+ { "@mozilla.org/widgets/window/uikit;1", &kNS_WINDOW_CID },
+ { "@mozilla.org/widgets/childwindow/uikit;1", &kNS_CHILD_CID },
+ { "@mozilla.org/widget/appshell/uikit;1", &kNS_APPSHELL_CID },
+ { "@mozilla.org/gfx/screenmanager;1", &kNS_SCREENMANAGER_CID },
+ { "@mozilla.org/gfx/info;1", &kNS_GFXINFO_CID },
+ { nullptr }
+};
+
+static void
+nsWidgetUIKitModuleDtor()
+{
+ nsLookAndFeel::Shutdown();
+ nsAppShellShutdown();
+}
+
+static const mozilla::Module kWidgetModule = {
+ mozilla::Module::kVersion,
+ kWidgetCIDs,
+ kWidgetContracts,
+ nullptr,
+ nullptr,
+ nsAppShellInit,
+ nsWidgetUIKitModuleDtor
+};
+
+NSMODULE_DEFN(nsWidgetUIKitModule) = &kWidgetModule;
diff --git a/widget/uikit/nsWindow.h b/widget/uikit/nsWindow.h
new file mode 100644
index 000000000..cb18c0906
--- /dev/null
+++ b/widget/uikit/nsWindow.h
@@ -0,0 +1,125 @@
+/* -*- Mode: C++; tab-width: 4; 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 NSWINDOW_H_
+#define NSWINDOW_H_
+
+#include "nsBaseWidget.h"
+#include "gfxPoint.h"
+
+#include "nsTArray.h"
+
+@class UIWindow;
+@class UIView;
+@class ChildView;
+
+class nsWindow :
+ public nsBaseWidget
+{
+ typedef nsBaseWidget Inherited;
+
+public:
+ nsWindow();
+
+ NS_DECL_ISUPPORTS_INHERITED
+
+ //
+ // nsIWidget
+ //
+
+ virtual MOZ_MUST_USE nsresult Create(nsIWidget* aParent,
+ nsNativeWidget aNativeParent,
+ const LayoutDeviceIntRect& aRect,
+ nsWidgetInitData* aInitData = nullptr)
+ override;
+ virtual void Destroy() override;
+ NS_IMETHOD Show(bool aState) override;
+ NS_IMETHOD Enable(bool aState) override {
+ return NS_OK;
+ }
+ virtual bool IsEnabled() const override {
+ return true;
+ }
+ virtual bool IsVisible() const override {
+ return mVisible;
+ }
+ NS_IMETHOD SetFocus(bool aState=false) override;
+ virtual LayoutDeviceIntPoint WidgetToScreenOffset() override;
+
+ virtual void SetBackgroundColor(const nscolor &aColor) override;
+ virtual void* GetNativeData(uint32_t aDataType) override;
+
+ NS_IMETHOD Move(double aX, double aY) override;
+ virtual void SetSizeMode(nsSizeMode aMode) override;
+ void EnteredFullScreen(bool aFullScreen);
+ NS_IMETHOD Resize(double aWidth, double aHeight, bool aRepaint) override;
+ NS_IMETHOD Resize(double aX, double aY, double aWidth, double aHeight, bool aRepaint) override;
+ virtual LayoutDeviceIntRect GetScreenBounds() override;
+ void ReportMoveEvent();
+ void ReportSizeEvent();
+ void ReportSizeModeEvent(nsSizeMode aMode);
+
+ CGFloat BackingScaleFactor();
+ void BackingScaleFactorChanged();
+ virtual float GetDPI() override {
+ //XXX: terrible
+ return 326.0f;
+ }
+ virtual double GetDefaultScaleInternal() override {
+ return BackingScaleFactor();
+ }
+ virtual int32_t RoundsWidgetCoordinatesTo() override;
+
+ NS_IMETHOD SetTitle(const nsAString& aTitle) override {
+ return NS_OK;
+ }
+
+ NS_IMETHOD Invalidate(const LayoutDeviceIntRect& aRect) override;
+ virtual nsresult ConfigureChildren(const nsTArray<Configuration>& aConfigurations) override;
+ NS_IMETHOD DispatchEvent(mozilla::WidgetGUIEvent* aEvent,
+ nsEventStatus& aStatus) override;
+
+ void WillPaintWindow();
+ bool PaintWindow(LayoutDeviceIntRegion aRegion);
+
+ bool HasModalDescendents() { return false; }
+
+ //NS_IMETHOD NotifyIME(const IMENotification& aIMENotification) override;
+ NS_IMETHOD_(void) SetInputContext(
+ const InputContext& aContext,
+ const InputContextAction& aAction);
+ NS_IMETHOD_(InputContext) GetInputContext();
+ /*
+ NS_IMETHOD_(bool) ExecuteNativeKeyBinding(
+ NativeKeyBindingsType aType,
+ const mozilla::WidgetKeyboardEvent& aEvent,
+ DoCommandCallback aCallback,
+ void* aCallbackData) override;
+ */
+
+protected:
+ virtual ~nsWindow();
+ void BringToFront();
+ nsWindow *FindTopLevel();
+ bool IsTopLevel();
+ nsresult GetCurrentOffset(uint32_t &aOffset, uint32_t &aLength);
+ nsresult DeleteRange(int aOffset, int aLen);
+
+ void TearDownView();
+
+ ChildView* mNativeView;
+ bool mVisible;
+ nsTArray<nsWindow*> mChildren;
+ nsWindow* mParent;
+ InputContext mInputContext;
+
+ void OnSizeChanged(const mozilla::gfx::IntSize& aSize);
+
+ static void DumpWindows();
+ static void DumpWindows(const nsTArray<nsWindow*>& wins, int indent = 0);
+ static void LogWindow(nsWindow *win, int index, int indent);
+};
+
+#endif /* NSWINDOW_H_ */
diff --git a/widget/uikit/nsWindow.mm b/widget/uikit/nsWindow.mm
new file mode 100644
index 000000000..874626237
--- /dev/null
+++ b/widget/uikit/nsWindow.mm
@@ -0,0 +1,862 @@
+/* -*- Mode: C++; tab-width: 4; 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/. */
+
+#import <UIKit/UIEvent.h>
+#import <UIKit/UIGraphics.h>
+#import <UIKit/UIInterface.h>
+#import <UIKit/UIScreen.h>
+#import <UIKit/UITapGestureRecognizer.h>
+#import <UIKit/UITouch.h>
+#import <UIKit/UIView.h>
+#import <UIKit/UIViewController.h>
+#import <UIKit/UIWindow.h>
+#import <QuartzCore/QuartzCore.h>
+
+#include <algorithm>
+
+#include "nsWindow.h"
+#include "nsScreenManager.h"
+#include "nsAppShell.h"
+
+#include "nsWidgetsCID.h"
+#include "nsGfxCIID.h"
+
+#include "gfxQuartzSurface.h"
+#include "gfxUtils.h"
+#include "gfxImageSurface.h"
+#include "gfxContext.h"
+#include "nsRegion.h"
+#include "Layers.h"
+#include "nsTArray.h"
+
+#include "mozilla/BasicEvents.h"
+#include "mozilla/TouchEvents.h"
+#include "mozilla/Unused.h"
+
+#include "GeckoProfiler.h"
+
+using namespace mozilla;
+using namespace mozilla::dom;
+using namespace mozilla::layers;
+
+#define ALOG(args...) fprintf(stderr, args); fprintf(stderr, "\n")
+
+static LayoutDeviceIntPoint
+UIKitPointsToDevPixels(CGPoint aPoint, CGFloat aBackingScale)
+{
+ return LayoutDeviceIntPoint(NSToIntRound(aPoint.x * aBackingScale),
+ NSToIntRound(aPoint.y * aBackingScale));
+}
+
+static CGRect
+DevPixelsToUIKitPoints(const LayoutDeviceIntRect& aRect, CGFloat aBackingScale)
+{
+ return CGRectMake((CGFloat)aRect.x / aBackingScale,
+ (CGFloat)aRect.y / aBackingScale,
+ (CGFloat)aRect.width / aBackingScale,
+ (CGFloat)aRect.height / aBackingScale);
+}
+
+// Used to retain a Cocoa object for the remainder of a method's execution.
+class nsAutoRetainUIKitObject {
+public:
+nsAutoRetainUIKitObject(id anObject)
+{
+ mObject = [anObject retain];
+}
+~nsAutoRetainUIKitObject()
+{
+ [mObject release];
+}
+private:
+ id mObject; // [STRONG]
+};
+
+@interface ChildView : UIView
+{
+@public
+ nsWindow* mGeckoChild; // weak ref
+ BOOL mWaitingForPaint;
+ CFMutableDictionaryRef mTouches;
+ int mNextTouchID;
+}
+// sets up our view, attaching it to its owning gecko view
+- (id)initWithFrame:(CGRect)inFrame geckoChild:(nsWindow*)inChild;
+// Our Gecko child was Destroy()ed
+- (void)widgetDestroyed;
+// Tear down this ChildView
+- (void)delayedTearDown;
+- (void)sendMouseEvent:(EventMessage) aType point:(LayoutDeviceIntPoint)aPoint widget:(nsWindow*)aWindow;
+- (void)handleTap:(UITapGestureRecognizer *)sender;
+- (BOOL)isUsingMainThreadOpenGL;
+- (void)drawUsingOpenGL;
+- (void)drawUsingOpenGLCallback;
+- (void)sendTouchEvent:(EventMessage) aType touches:(NSSet*)aTouches widget:(nsWindow*)aWindow;
+// Event handling (UIResponder)
+- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
+- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event;
+- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event;
+- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event;
+@end
+
+@implementation ChildView
++ (Class)layerClass {
+ return [CAEAGLLayer class];
+}
+
+- (id)initWithFrame:(CGRect)inFrame geckoChild:(nsWindow*)inChild
+{
+ self.multipleTouchEnabled = YES;
+ if ((self = [super initWithFrame:inFrame])) {
+ mGeckoChild = inChild;
+ }
+ ALOG("[ChildView[%p] initWithFrame:] (mGeckoChild = %p)", (void*)self, (void*)mGeckoChild);
+ self.opaque = YES;
+ self.alpha = 1.0;
+
+ UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc]
+ initWithTarget:self action:@selector(handleTap:)];
+ tapRecognizer.numberOfTapsRequired = 1;
+ [self addGestureRecognizer:tapRecognizer];
+
+ mTouches = CFDictionaryCreateMutable(kCFAllocatorDefault, 0, nullptr, nullptr);
+ mNextTouchID = 0;
+ return self;
+}
+
+- (void)widgetDestroyed
+{
+ mGeckoChild = nullptr;
+ CFRelease(mTouches);
+}
+
+- (void)delayedTearDown
+{
+ [self removeFromSuperview];
+ [self release];
+}
+
+- (void)sendMouseEvent:(EventMessage) aType point:(LayoutDeviceIntPoint)aPoint widget:(nsWindow*)aWindow
+{
+ WidgetMouseEvent event(true, aType, aWindow,
+ WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal);
+
+ event.mRefPoint = aPoint;
+ event.mClickCount = 1;
+ event.button = WidgetMouseEvent::eLeftButton;
+ event.mTime = PR_IntervalNow();
+ event.inputSource = nsIDOMMouseEvent::MOZ_SOURCE_UNKNOWN;
+
+ nsEventStatus status;
+ aWindow->DispatchEvent(&event, status);
+}
+
+- (void)handleTap:(UITapGestureRecognizer *)sender
+{
+ if (sender.state == UIGestureRecognizerStateEnded) {
+ ALOG("[ChildView[%p] handleTap]", self);
+ LayoutDeviceIntPoint lp = UIKitPointsToDevPixels([sender locationInView:self], [self contentScaleFactor]);
+ [self sendMouseEvent:eMouseMove point:lp widget:mGeckoChild];
+ [self sendMouseEvent:eMouseDown point:lp widget:mGeckoChild];
+ [self sendMouseEvent:eMouseUp point:lp widget:mGeckoChild];
+ }
+}
+
+- (void)sendTouchEvent:(EventMessage) aType touches:(NSSet*)aTouches widget:(nsWindow*)aWindow
+{
+ WidgetTouchEvent event(true, aType, aWindow);
+ //XXX: I think nativeEvent.timestamp * 1000 is probably usable here but
+ // I don't care that much right now.
+ event.mTime = PR_IntervalNow();
+ event.mTouches.SetCapacity(aTouches.count);
+ for (UITouch* touch in aTouches) {
+ LayoutDeviceIntPoint loc = UIKitPointsToDevPixels([touch locationInView:self], [self contentScaleFactor]);
+ LayoutDeviceIntPoint radius = UIKitPointsToDevPixels([touch majorRadius], [touch majorRadius]);
+ void* value;
+ if (!CFDictionaryGetValueIfPresent(mTouches, touch, (const void**)&value)) {
+ // This shouldn't happen.
+ NS_ASSERTION(false, "Got a touch that we didn't know about");
+ continue;
+ }
+ int id = reinterpret_cast<int>(value);
+ RefPtr<Touch> t = new Touch(id, loc, radius, 0.0f, 1.0f);
+ event.mRefPoint = loc;
+ event.mTouches.AppendElement(t);
+ }
+ aWindow->DispatchInputEvent(&event);
+}
+
+- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
+{
+ ALOG("[ChildView[%p] touchesBegan", self);
+ if (!mGeckoChild)
+ return;
+
+ for (UITouch* touch : touches) {
+ CFDictionaryAddValue(mTouches, touch, (void*)mNextTouchID);
+ mNextTouchID++;
+ }
+ [self sendTouchEvent:eTouchStart
+ touches:[event allTouches]
+ widget:mGeckoChild];
+}
+
+- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
+{
+ ALOG("[ChildView[%p] touchesCancelled", self);
+ [self sendTouchEvent:eTouchCancel touches:touches widget:mGeckoChild];
+ for (UITouch* touch : touches) {
+ CFDictionaryRemoveValue(mTouches, touch);
+ }
+ if (CFDictionaryGetCount(mTouches) == 0) {
+ mNextTouchID = 0;
+ }
+}
+
+- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
+{
+ ALOG("[ChildView[%p] touchesEnded", self);
+ if (!mGeckoChild)
+ return;
+
+ [self sendTouchEvent:eTouchEnd touches:touches widget:mGeckoChild];
+ for (UITouch* touch : touches) {
+ CFDictionaryRemoveValue(mTouches, touch);
+ }
+ if (CFDictionaryGetCount(mTouches) == 0) {
+ mNextTouchID = 0;
+ }
+}
+
+- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
+{
+ ALOG("[ChildView[%p] touchesMoved", self);
+ if (!mGeckoChild)
+ return;
+
+ [self sendTouchEvent:eTouchMove
+ touches:[event allTouches]
+ widget:mGeckoChild];
+}
+
+- (void)setNeedsDisplayInRect:(CGRect)aRect
+{
+ if ([self isUsingMainThreadOpenGL]) {
+ // Draw without calling drawRect. This prevent us from
+ // needing to access the normal window buffer surface unnecessarily, so we
+ // waste less time synchronizing the two surfaces.
+ if (!mWaitingForPaint) {
+ mWaitingForPaint = YES;
+ // Use NSRunLoopCommonModes instead of the default NSDefaultRunLoopMode
+ // so that the timer also fires while a native menu is open.
+ [self performSelector:@selector(drawUsingOpenGLCallback)
+ withObject:nil
+ afterDelay:0
+ inModes:[NSArray arrayWithObject:NSRunLoopCommonModes]];
+ }
+ }
+}
+
+- (BOOL)isUsingMainThreadOpenGL
+{
+ if (!mGeckoChild || ![self window])
+ return NO;
+
+ return mGeckoChild->GetLayerManager(nullptr)->GetBackendType() == mozilla::layers::LayersBackend::LAYERS_OPENGL;
+}
+
+- (void)drawUsingOpenGL
+{
+ ALOG("drawUsingOpenGL");
+ PROFILER_LABEL("ChildView", "drawUsingOpenGL",
+ js::ProfileEntry::Category::GRAPHICS);
+
+ if (!mGeckoChild->IsVisible())
+ return;
+
+ mWaitingForPaint = NO;
+
+ LayoutDeviceIntRect geckoBounds = mGeckoChild->GetBounds();
+ LayoutDeviceIntRegion region(geckoBounds);
+
+ mGeckoChild->PaintWindow(region);
+}
+
+// Called asynchronously after setNeedsDisplay in order to avoid entering the
+// normal drawing machinery.
+- (void)drawUsingOpenGLCallback
+{
+ if (mWaitingForPaint) {
+ [self drawUsingOpenGL];
+ }
+}
+
+// The display system has told us that a portion of our view is dirty. Tell
+// gecko to paint it
+- (void)drawRect:(CGRect)aRect
+{
+ CGContextRef cgContext = UIGraphicsGetCurrentContext();
+ [self drawRect:aRect inContext:cgContext];
+}
+
+- (void)drawRect:(CGRect)aRect inContext:(CGContextRef)aContext
+{
+#ifdef DEBUG_UPDATE
+ LayoutDeviceIntRect geckoBounds = mGeckoChild->GetBounds();
+
+ fprintf (stderr, "---- Update[%p][%p] [%f %f %f %f] cgc: %p\n gecko bounds: [%d %d %d %d]\n",
+ self, mGeckoChild,
+ aRect.origin.x, aRect.origin.y, aRect.size.width, aRect.size.height, aContext,
+ geckoBounds.x, geckoBounds.y, geckoBounds.width, geckoBounds.height);
+
+ CGAffineTransform xform = CGContextGetCTM(aContext);
+ fprintf (stderr, " xform in: [%f %f %f %f %f %f]\n", xform.a, xform.b, xform.c, xform.d, xform.tx, xform.ty);
+#endif
+
+ if (true) {
+ // For Gecko-initiated repaints in OpenGL mode, drawUsingOpenGL is
+ // directly called from a delayed perform callback - without going through
+ // drawRect.
+ // Paints that come through here are triggered by something that Cocoa
+ // controls, for example by window resizing or window focus changes.
+
+ // Do GL composition and return.
+ [self drawUsingOpenGL];
+ return;
+ }
+ PROFILER_LABEL("ChildView", "drawRect",
+ js::ProfileEntry::Category::GRAPHICS);
+
+ // The CGContext that drawRect supplies us with comes with a transform that
+ // scales one user space unit to one Cocoa point, which can consist of
+ // multiple dev pixels. But Gecko expects its supplied context to be scaled
+ // to device pixels, so we need to reverse the scaling.
+ double scale = mGeckoChild->BackingScaleFactor();
+ CGContextSaveGState(aContext);
+ CGContextScaleCTM(aContext, 1.0 / scale, 1.0 / scale);
+
+ CGSize viewSize = [self bounds].size;
+ gfx::IntSize backingSize(viewSize.width * scale, viewSize.height * scale);
+
+ CGContextSaveGState(aContext);
+
+ LayoutDeviceIntRegion region =
+ LayoutDeviceIntRect(NSToIntRound(aRect.origin.x * scale),
+ NSToIntRound(aRect.origin.y * scale),
+ NSToIntRound(aRect.size.width * scale),
+ NSToIntRound(aRect.size.height * scale));
+
+ // Create Cairo objects.
+ RefPtr<gfxQuartzSurface> targetSurface;
+
+ RefPtr<gfxContext> targetContext;
+ if (gfxPlatform::GetPlatform()->SupportsAzureContentForType(gfx::BackendType::CAIRO)) {
+ // This is dead code unless you mess with prefs, but keep it around for
+ // debugging.
+ targetSurface = new gfxQuartzSurface(aContext, backingSize);
+ targetSurface->SetAllowUseAsSource(false);
+ RefPtr<gfx::DrawTarget> dt =
+ gfxPlatform::GetPlatform()->CreateDrawTargetForSurface(targetSurface,
+ backingSize);
+ if (!dt || !dt->IsValid()) {
+ gfxDevCrash(mozilla::gfx::LogReason::InvalidContext) << "Window context problem 2 " << backingSize;
+ return;
+ }
+ dt->AddUserData(&gfxContext::sDontUseAsSourceKey, dt, nullptr);
+ targetContext = gfxContext::CreateOrNull(dt);
+ } else {
+ MOZ_ASSERT_UNREACHABLE("COREGRAPHICS is the only supported backend");
+ }
+ MOZ_ASSERT(targetContext); // already checked for valid draw targets above
+
+ // Set up the clip region.
+ targetContext->NewPath();
+ for (auto iter = region.RectIter(); !iter.Done(); iter.Next()) {
+ const LayoutDeviceIntRect& r = iter.Get();
+ targetContext->Rectangle(gfxRect(r.x, r.y, r.width, r.height));
+ }
+ targetContext->Clip();
+
+ //nsAutoRetainCocoaObject kungFuDeathGrip(self);
+ bool painted = false;
+ if (mGeckoChild->GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_BASIC) {
+ nsBaseWidget::AutoLayerManagerSetup
+ setupLayerManager(mGeckoChild, targetContext, BufferMode::BUFFER_NONE);
+ painted = mGeckoChild->PaintWindow(region);
+ } else if (mGeckoChild->GetLayerManager()->GetBackendType() == LayersBackend::LAYERS_CLIENT) {
+ // We only need this so that we actually get DidPaintWindow fired
+ painted = mGeckoChild->PaintWindow(region);
+ }
+
+ targetContext = nullptr;
+ targetSurface = nullptr;
+
+ CGContextRestoreGState(aContext);
+
+ // Undo the scale transform so that from now on the context is in
+ // CocoaPoints again.
+ CGContextRestoreGState(aContext);
+ if (!painted && [self isOpaque]) {
+ // Gecko refused to draw, but we've claimed to be opaque, so we have to
+ // draw something--fill with white.
+ CGContextSetRGBFillColor(aContext, 1, 1, 1, 1);
+ CGContextFillRect(aContext, aRect);
+ }
+
+#ifdef DEBUG_UPDATE
+ fprintf (stderr, "---- update done ----\n");
+
+#if 0
+ CGContextSetRGBStrokeColor (aContext,
+ ((((unsigned long)self) & 0xff)) / 255.0,
+ ((((unsigned long)self) & 0xff00) >> 8) / 255.0,
+ ((((unsigned long)self) & 0xff0000) >> 16) / 255.0,
+ 0.5);
+#endif
+ CGContextSetRGBStrokeColor(aContext, 1, 0, 0, 0.8);
+ CGContextSetLineWidth(aContext, 4.0);
+ CGContextStrokeRect(aContext, aRect);
+#endif
+}
+@end
+
+NS_IMPL_ISUPPORTS_INHERITED0(nsWindow, Inherited)
+
+nsWindow::nsWindow()
+: mNativeView(nullptr),
+ mVisible(false),
+ mParent(nullptr)
+{
+}
+
+nsWindow::~nsWindow()
+{
+ [mNativeView widgetDestroyed]; // Safe if mNativeView is nil.
+ TearDownView(); // Safe if called twice.
+}
+
+void nsWindow::TearDownView()
+{
+ if (!mNativeView)
+ return;
+
+ [mNativeView performSelectorOnMainThread:@selector(delayedTearDown) withObject:nil waitUntilDone:false];
+ mNativeView = nil;
+}
+
+bool
+nsWindow::IsTopLevel()
+{
+ return mWindowType == eWindowType_toplevel ||
+ mWindowType == eWindowType_dialog ||
+ mWindowType == eWindowType_invisible;
+}
+
+//
+// nsIWidget
+//
+
+nsresult
+nsWindow::Create(nsIWidget* aParent,
+ nsNativeWidget aNativeParent,
+ const LayoutDeviceIntRect& aRect,
+ nsWidgetInitData* aInitData)
+{
+ ALOG("nsWindow[%p]::Create %p/%p [%d %d %d %d]", (void*)this, (void*)aParent, (void*)aNativeParent, aRect.x, aRect.y, aRect.width, aRect.height);
+ nsWindow* parent = (nsWindow*) aParent;
+ ChildView* nativeParent = (ChildView*)aNativeParent;
+
+ if (parent == nullptr && nativeParent)
+ parent = nativeParent->mGeckoChild;
+ if (parent && nativeParent == nullptr)
+ nativeParent = parent->mNativeView;
+
+ // for toplevel windows, bounds are fixed to full screen size
+ if (parent == nullptr) {
+ if (nsAppShell::gWindow == nil) {
+ mBounds = UIKitScreenManager::GetBounds();
+ } else {
+ CGRect cgRect = [nsAppShell::gWindow bounds];
+ mBounds.x = cgRect.origin.x;
+ mBounds.y = cgRect.origin.y;
+ mBounds.width = cgRect.size.width;
+ mBounds.height = cgRect.size.height;
+ }
+ } else {
+ mBounds = aRect;
+ }
+
+ ALOG("nsWindow[%p]::Create bounds: %d %d %d %d", (void*)this,
+ mBounds.x, mBounds.y, mBounds.width, mBounds.height);
+
+ // Set defaults which can be overriden from aInitData in BaseCreate
+ mWindowType = eWindowType_toplevel;
+ mBorderStyle = eBorderStyle_default;
+
+ Inherited::BaseCreate(aParent, aInitData);
+
+ NS_ASSERTION(IsTopLevel() || parent, "non top level window doesn't have a parent!");
+
+ mNativeView = [[ChildView alloc] initWithFrame:DevPixelsToUIKitPoints(mBounds, BackingScaleFactor()) geckoChild:this];
+ mNativeView.hidden = YES;
+
+ if (parent) {
+ parent->mChildren.AppendElement(this);
+ mParent = parent;
+ }
+
+ if (nativeParent) {
+ [nativeParent addSubview:mNativeView];
+ } else if (nsAppShell::gWindow) {
+ [nsAppShell::gWindow.rootViewController.view addSubview:mNativeView];
+ }
+ else {
+ [nsAppShell::gTopLevelViews addObject:mNativeView];
+ }
+
+ return NS_OK;
+}
+
+void
+nsWindow::Destroy()
+{
+ for (uint32_t i = 0; i < mChildren.Length(); ++i) {
+ // why do we still have children?
+ mChildren[i]->SetParent(nullptr);
+ }
+
+ if (mParent)
+ mParent->mChildren.RemoveElement(this);
+
+ [mNativeView widgetDestroyed];
+
+ nsBaseWidget::Destroy();
+
+ //ReportDestroyEvent();
+
+ TearDownView();
+
+ nsBaseWidget::OnDestroy();
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWindow::ConfigureChildren(const nsTArray<nsIWidget::Configuration>& config)
+{
+ for (uint32_t i = 0; i < config.Length(); ++i) {
+ nsWindow *childWin = (nsWindow*) config[i].mChild.get();
+ childWin->Resize(config[i].mBounds.x,
+ config[i].mBounds.y,
+ config[i].mBounds.width,
+ config[i].mBounds.height,
+ false);
+ }
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWindow::Show(bool aState)
+{
+ if (aState != mVisible) {
+ mNativeView.hidden = aState ? NO : YES;
+ if (aState) {
+ UIView* parentView = mParent ? mParent->mNativeView : nsAppShell::gWindow.rootViewController.view;
+ [parentView bringSubviewToFront:mNativeView];
+ [mNativeView setNeedsDisplay];
+ }
+ mVisible = aState;
+ }
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWindow::Move(double aX, double aY)
+{
+ if (!mNativeView || (mBounds.x == aX && mBounds.y == aY))
+ return NS_OK;
+
+ //XXX: handle this
+ // The point we have is in Gecko coordinates (origin top-left). Convert
+ // it to Cocoa ones (origin bottom-left).
+ mBounds.x = aX;
+ mBounds.y = aY;
+
+ mNativeView.frame = DevPixelsToUIKitPoints(mBounds, BackingScaleFactor());
+
+ if (mVisible)
+ [mNativeView setNeedsDisplay];
+
+ ReportMoveEvent();
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWindow::Resize(double aX, double aY,
+ double aWidth, double aHeight,
+ bool aRepaint)
+{
+ BOOL isMoving = (mBounds.x != aX || mBounds.y != aY);
+ BOOL isResizing = (mBounds.width != aWidth || mBounds.height != aHeight);
+ if (!mNativeView || (!isMoving && !isResizing))
+ return NS_OK;
+
+ if (isMoving) {
+ mBounds.x = aX;
+ mBounds.y = aY;
+ }
+ if (isResizing) {
+ mBounds.width = aWidth;
+ mBounds.height = aHeight;
+ }
+
+ [mNativeView setFrame:DevPixelsToUIKitPoints(mBounds, BackingScaleFactor())];
+
+ if (mVisible && aRepaint)
+ [mNativeView setNeedsDisplay];
+
+ if (isMoving)
+ ReportMoveEvent();
+
+ if (isResizing)
+ ReportSizeEvent();
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP nsWindow::Resize(double aWidth, double aHeight, bool aRepaint)
+{
+ if (!mNativeView || (mBounds.width == aWidth && mBounds.height == aHeight))
+ return NS_OK;
+
+ mBounds.width = aWidth;
+ mBounds.height = aHeight;
+
+ [mNativeView setFrame:DevPixelsToUIKitPoints(mBounds, BackingScaleFactor())];
+
+ if (mVisible && aRepaint)
+ [mNativeView setNeedsDisplay];
+
+ ReportSizeEvent();
+
+ return NS_OK;
+}
+
+void
+nsWindow::SetSizeMode(nsSizeMode aMode)
+{
+ if (aMode == static_cast<int32_t>(mSizeMode)) {
+ return;
+ }
+
+ mSizeMode = static_cast<nsSizeMode>(aMode);
+ if (aMode == nsSizeMode_Maximized || aMode == nsSizeMode_Fullscreen) {
+ // Resize to fill screen
+ nsBaseWidget::InfallibleMakeFullScreen(true);
+ }
+ ReportSizeModeEvent(aMode);
+}
+
+NS_IMETHODIMP
+nsWindow::Invalidate(const LayoutDeviceIntRect& aRect)
+{
+ if (!mNativeView || !mVisible)
+ return NS_OK;
+
+ MOZ_RELEASE_ASSERT(GetLayerManager()->GetBackendType() != LayersBackend::LAYERS_CLIENT,
+ "Shouldn't need to invalidate with accelerated OMTC layers!");
+
+
+ [mNativeView setNeedsLayout];
+ [mNativeView setNeedsDisplayInRect:DevPixelsToUIKitPoints(mBounds, BackingScaleFactor())];
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+nsWindow::SetFocus(bool aRaise)
+{
+ [[mNativeView window] makeKeyWindow];
+ [mNativeView becomeFirstResponder];
+ return NS_OK;
+}
+
+void nsWindow::WillPaintWindow()
+{
+ if (mWidgetListener) {
+ mWidgetListener->WillPaintWindow(this);
+ }
+}
+
+bool nsWindow::PaintWindow(LayoutDeviceIntRegion aRegion)
+{
+ if (!mWidgetListener)
+ return false;
+
+ bool returnValue = false;
+ returnValue = mWidgetListener->PaintWindow(this, aRegion);
+
+ if (mWidgetListener) {
+ mWidgetListener->DidPaintWindow();
+ }
+
+ return returnValue;
+}
+
+void nsWindow::ReportMoveEvent()
+{
+ NotifyWindowMoved(mBounds.x, mBounds.y);
+}
+
+void nsWindow::ReportSizeModeEvent(nsSizeMode aMode)
+{
+ if (mWidgetListener) {
+ // This is terrible.
+ nsSizeMode theMode;
+ switch (aMode) {
+ case nsSizeMode_Maximized:
+ theMode = nsSizeMode_Maximized;
+ break;
+ case nsSizeMode_Fullscreen:
+ theMode = nsSizeMode_Fullscreen;
+ break;
+ default:
+ return;
+ }
+ mWidgetListener->SizeModeChanged(theMode);
+ }
+}
+
+void nsWindow::ReportSizeEvent()
+{
+ if (mWidgetListener) {
+ LayoutDeviceIntRect innerBounds = GetClientBounds();
+ mWidgetListener->WindowResized(this, innerBounds.width, innerBounds.height);
+ }
+}
+
+LayoutDeviceIntRect
+nsWindow::GetScreenBounds()
+{
+ return LayoutDeviceIntRect(WidgetToScreenOffset(), mBounds.Size());
+}
+
+LayoutDeviceIntPoint nsWindow::WidgetToScreenOffset()
+{
+ LayoutDeviceIntPoint offset(0, 0);
+ if (mParent) {
+ offset = mParent->WidgetToScreenOffset();
+ }
+
+ CGPoint temp = [mNativeView convertPoint:temp toView:nil];
+
+ if (!mParent && nsAppShell::gWindow) {
+ // convert to screen coords
+ temp = [nsAppShell::gWindow convertPoint:temp toWindow:nil];
+ }
+
+ offset.x += temp.x;
+ offset.y += temp.y;
+
+ return offset;
+}
+
+NS_IMETHODIMP
+nsWindow::DispatchEvent(mozilla::WidgetGUIEvent* aEvent,
+ nsEventStatus& aStatus)
+{
+ aStatus = nsEventStatus_eIgnore;
+ nsCOMPtr<nsIWidget> kungFuDeathGrip(aEvent->mWidget);
+
+ if (mWidgetListener)
+ aStatus = mWidgetListener->HandleEvent(aEvent, mUseAttachedEvents);
+
+ return NS_OK;
+}
+
+NS_IMETHODIMP_(void)
+nsWindow::SetInputContext(const InputContext& aContext,
+ const InputContextAction& aAction)
+{
+ //TODO: actually show VKB
+ mInputContext = aContext;
+}
+
+NS_IMETHODIMP_(mozilla::widget::InputContext)
+nsWindow::GetInputContext()
+{
+ return mInputContext;
+}
+
+void
+nsWindow::SetBackgroundColor(const nscolor &aColor)
+{
+ mNativeView.backgroundColor = [UIColor colorWithRed:NS_GET_R(aColor)
+ green:NS_GET_G(aColor)
+ blue:NS_GET_B(aColor)
+ alpha:NS_GET_A(aColor)];
+}
+
+void* nsWindow::GetNativeData(uint32_t aDataType)
+{
+ void* retVal = nullptr;
+
+ switch (aDataType)
+ {
+ case NS_NATIVE_WIDGET:
+ case NS_NATIVE_DISPLAY:
+ retVal = (void*)mNativeView;
+ break;
+
+ case NS_NATIVE_WINDOW:
+ retVal = [mNativeView window];
+ break;
+
+ case NS_NATIVE_GRAPHIC:
+ NS_ERROR("Requesting NS_NATIVE_GRAPHIC on a UIKit child view!");
+ break;
+
+ case NS_NATIVE_OFFSETX:
+ retVal = 0;
+ break;
+
+ case NS_NATIVE_OFFSETY:
+ retVal = 0;
+ break;
+
+ case NS_NATIVE_PLUGIN_PORT:
+ // not implemented
+ break;
+
+ case NS_RAW_NATIVE_IME_CONTEXT:
+ retVal = GetPseudoIMEContext();
+ if (retVal) {
+ break;
+ }
+ retVal = NS_ONLY_ONE_NATIVE_IME_CONTEXT;
+ break;
+ }
+
+ return retVal;
+}
+
+CGFloat
+nsWindow::BackingScaleFactor()
+{
+ if (mNativeView) {
+ return [mNativeView contentScaleFactor];
+ }
+ return [UIScreen mainScreen].scale;
+}
+
+int32_t
+nsWindow::RoundsWidgetCoordinatesTo()
+{
+ if (BackingScaleFactor() == 2.0) {
+ return 2;
+ }
+ return 1;
+}