bug 1171113 - Add widget/uikit. r=roc (NPOTB)

--HG--
extra : commitid : 1I5FPzgYF3d
extra : rebase_source : d96adf156c955a77d3303cf69301d133371244d3
This commit is contained in:
Ted Mielczarek 2015-06-12 08:49:57 -04:00
parent 0f79aeadea
commit 7916ef866c
16 changed files with 2423 additions and 4 deletions

View File

@ -4216,11 +4216,20 @@ pref("layers.offmainthreadcomposition.frame-rate", -1);
pref("layers.async-video.enabled", true);
pref("layers.async-video-oop.enabled",true);
#ifdef MOZ_WIDGET_UIKIT
pref("layers.async-pan-zoom.enabled", true);
#endif
#ifdef MOZ_WIDGET_UIKIT
pref("layers.async-pan-zoom.enabled", true);
#endif
#ifdef XP_MACOSX
pref("layers.enable-tiles", true);
pref("layers.tiled-drawtarget.enabled", true);
#endif
// same effect as layers.offmainthreadcomposition.enabled, but specifically for
// use with tests.
pref("layers.offmainthreadcomposition.testing.enabled", false);

View File

@ -56,6 +56,7 @@ enum OperatingSystem {
DRIVER_OS_OS_X_10_9,
DRIVER_OS_OS_X_10_10,
DRIVER_OS_ANDROID,
DRIVER_OS_IOS,
DRIVER_OS_ALL
};

View File

@ -6,7 +6,7 @@
toolkit = CONFIG['MOZ_WIDGET_TOOLKIT']
if toolkit in ('cocoa', 'qt', 'android', 'gonk'):
if toolkit in ('cocoa', 'qt', 'android', 'gonk', 'uikit'):
DIRS += [toolkit]
if toolkit in ('qt', 'android', 'gonk', 'gtk2', 'gtk3'):
EXPORTS += ['nsIPrintDialogService.h']
@ -201,8 +201,8 @@ if toolkit in ('cocoa', 'windows'):
'nsBaseClipboard.cpp',
]
if toolkit in ('qt', 'gtk2', 'gtk3', 'cocoa', 'windows',
'android', 'gonk'):
if toolkit in {'qt', 'gtk2', 'gtk3', 'cocoa', 'windows',
'android', 'gonk', 'uikit'}:
UNIFIED_SOURCES += [
'nsBaseFilePicker.cpp',
]

View File

@ -904,7 +904,8 @@ nsBaseWidget::ComputeShouldAccelerate(bool aDefault)
// that XUL widget opts in to acceleration, but that's probably OK.
bool accelerateByDefault = nsCocoaFeatures::AccelerateByDefault();
#elif defined(XP_WIN) || defined(ANDROID) || \
defined(MOZ_GL_PROVIDER) || defined(MOZ_WIDGET_QT)
defined(MOZ_GL_PROVIDER) || defined(MOZ_WIDGET_QT) || \
defined(MOZ_WIDGET_UIKIT)
bool accelerateByDefault = true;
#else
bool accelerateByDefault = false;

241
widget/uikit/GfxInfo.cpp Normal file
View File

@ -0,0 +1,241 @@
/* -*- 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;
}
/* readonly attribute DOMString DWriteVersion; */
NS_IMETHODIMP
GfxInfo::GetDWriteVersion(nsAString & aDwriteVersion)
{
return NS_ERROR_FAILURE;
}
/* readonly attribute DOMString cleartypeParameters; */
NS_IMETHODIMP
GfxInfo::GetCleartypeParameters(nsAString & aCleartypeParams)
{
return NS_ERROR_FAILURE;
}
/* readonly attribute DOMString adapterDescription; */
NS_IMETHODIMP
GfxInfo::GetAdapterDescription(nsAString & aAdapterDescription)
{
return NS_ERROR_FAILURE;
}
/* readonly attribute DOMString adapterDescription2; */
NS_IMETHODIMP
GfxInfo::GetAdapterDescription2(nsAString & aAdapterDescription)
{
return NS_ERROR_FAILURE;
}
/* readonly attribute DOMString adapterRAM; */
NS_IMETHODIMP
GfxInfo::GetAdapterRAM(nsAString & aAdapterRAM)
{
return NS_ERROR_FAILURE;
}
/* readonly attribute DOMString adapterRAM2; */
NS_IMETHODIMP
GfxInfo::GetAdapterRAM2(nsAString & aAdapterRAM)
{
return NS_ERROR_FAILURE;
}
/* readonly attribute DOMString adapterDriver; */
NS_IMETHODIMP
GfxInfo::GetAdapterDriver(nsAString & aAdapterDriver)
{
return NS_ERROR_FAILURE;
}
/* readonly attribute DOMString adapterDriver2; */
NS_IMETHODIMP
GfxInfo::GetAdapterDriver2(nsAString & aAdapterDriver)
{
return NS_ERROR_FAILURE;
}
/* readonly attribute DOMString adapterDriverVersion; */
NS_IMETHODIMP
GfxInfo::GetAdapterDriverVersion(nsAString & aAdapterDriverVersion)
{
return NS_ERROR_FAILURE;
}
/* readonly attribute DOMString adapterDriverVersion2; */
NS_IMETHODIMP
GfxInfo::GetAdapterDriverVersion2(nsAString & aAdapterDriverVersion)
{
return NS_ERROR_FAILURE;
}
/* readonly attribute DOMString adapterDriverDate; */
NS_IMETHODIMP
GfxInfo::GetAdapterDriverDate(nsAString & aAdapterDriverDate)
{
return NS_ERROR_FAILURE;
}
/* readonly attribute DOMString adapterDriverDate2; */
NS_IMETHODIMP
GfxInfo::GetAdapterDriverDate2(nsAString & aAdapterDriverDate)
{
return NS_ERROR_FAILURE;
}
/* readonly attribute DOMString adapterVendorID; */
NS_IMETHODIMP
GfxInfo::GetAdapterVendorID(nsAString & aAdapterVendorID)
{
return NS_ERROR_FAILURE;
}
/* readonly attribute DOMString adapterVendorID2; */
NS_IMETHODIMP
GfxInfo::GetAdapterVendorID2(nsAString & aAdapterVendorID)
{
return NS_ERROR_FAILURE;
}
/* readonly attribute DOMString adapterDeviceID; */
NS_IMETHODIMP
GfxInfo::GetAdapterDeviceID(nsAString & aAdapterDeviceID)
{
return NS_ERROR_FAILURE;
return NS_OK;
}
/* readonly attribute DOMString adapterDeviceID2; */
NS_IMETHODIMP
GfxInfo::GetAdapterDeviceID2(nsAString & aAdapterDeviceID)
{
return NS_ERROR_FAILURE;
}
/* readonly attribute DOMString adapterSubsysID; */
NS_IMETHODIMP
GfxInfo::GetAdapterSubsysID(nsAString & aAdapterSubsysID)
{
return NS_ERROR_FAILURE;
}
/* readonly attribute DOMString adapterSubsysID2; */
NS_IMETHODIMP
GfxInfo::GetAdapterSubsysID2(nsAString & aAdapterSubsysID)
{
return NS_ERROR_FAILURE;
}
/* readonly attribute boolean isGPU2Active; */
NS_IMETHODIMP
GfxInfo::GetIsGPU2Active(bool* aIsGPU2Active)
{
return NS_ERROR_FAILURE;
}
const nsTArray<GfxDriverInfo>&
GfxInfo::GetGfxDriverInfo()
{
if (mDriverInfo->IsEmpty()) {
APPEND_TO_DRIVER_BLOCKLIST2( DRIVER_OS_ALL,
(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 = DRIVER_OS_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
/* void spoofVendorID (in DOMString aVendorID); */
NS_IMETHODIMP GfxInfo::SpoofVendorID(const nsAString & aVendorID)
{
return NS_ERROR_FAILURE;
}
/* void spoofDeviceID (in unsigned long aDeviceID); */
NS_IMETHODIMP GfxInfo::SpoofDeviceID(const nsAString & aDeviceID)
{
return NS_ERROR_FAILURE;
}
/* void spoofDriverVersion (in DOMString aDriverVersion); */
NS_IMETHODIMP GfxInfo::SpoofDriverVersion(const nsAString & aDriverVersion)
{
return NS_ERROR_FAILURE;
}
/* void spoofOSVersion (in unsigned long aVersion); */
NS_IMETHODIMP GfxInfo::SpoofOSVersion(uint32_t aVersion)
{
return NS_ERROR_FAILURE;
}
#endif
}
}

78
widget/uikit/GfxInfo.h Normal file
View File

@ -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__ */

19
widget/uikit/moz.build Normal file
View File

@ -0,0 +1,19 @@
# -*- Mode: python; c-basic-offset: 4; 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',
]

57
widget/uikit/nsAppShell.h Normal file
View File

@ -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_

271
widget/uikit/nsAppShell.mm Normal file
View File

@ -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();
}

View File

@ -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

View File

@ -0,0 +1,397 @@
/* -*- 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;
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;
}

View File

@ -0,0 +1,56 @@
/* -*- 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);
private:
UIScreen* mScreen;
};
class UIKitScreenManager : public nsIScreenManager
{
public:
UIKitScreenManager ();
NS_DECL_ISUPPORTS
NS_DECL_NSISCREENMANAGER
static nsIntRect GetBounds();
private:
virtual ~UIKitScreenManager () {}
//TODO: support >1 screen, iPad supports external displays
nsCOMPtr<nsIScreen> mScreen;
};
#endif // nsScreenManager_h_

View File

@ -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 nsIntRect 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]))
{
}
nsIntRect
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;
}

View File

@ -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;

136
widget/uikit/nsWindow.h Normal file
View File

@ -0,0 +1,136 @@
/* -*- 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 gfxASurface;
class nsWindow :
public nsBaseWidget
{
typedef nsBaseWidget Inherited;
public:
nsWindow();
NS_DECL_ISUPPORTS_INHERITED
//
// nsIWidget
//
NS_IMETHOD Create(nsIWidget *aParent,
nsNativeWidget aNativeParent,
const nsIntRect &aRect,
nsWidgetInitData *aInitData = nullptr) override;
NS_IMETHOD Destroy() override;
NS_IMETHOD Show(bool aState) override;
NS_IMETHOD Enable(bool aState) override {
return NS_OK;
}
virtual bool IsEnabled() const override {
return true;
}
NS_IMETHOD SetModal(bool aState) override;
virtual bool IsVisible() const override {
return mVisible;
}
NS_IMETHOD SetFocus(bool aState=false) override;
virtual mozilla::LayoutDeviceIntPoint WidgetToScreenOffset() override;
virtual void SetBackgroundColor(const nscolor &aColor) override;
virtual void* GetNativeData(uint32_t aDataType) override;
NS_IMETHOD ConstrainPosition(bool aAllowSlop,
int32_t *aX, int32_t *aY) override;
NS_IMETHOD Move(double aX, double aY) override;
NS_IMETHOD PlaceBehind(nsTopLevelWidgetZPlacement aPlacement,
nsIWidget *aWidget, bool aActivate) override;
NS_IMETHOD SetSizeMode(int32_t 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;
NS_IMETHOD GetScreenBounds(nsIntRect &aRect) override;
void ReportMoveEvent();
void ReportSizeEvent();
void ReportSizeModeEvent(int32_t 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 nsIntRect &aRect) override;
virtual nsresult ConfigureChildren(const nsTArray<Configuration>& aConfigurations) override;
NS_IMETHOD DispatchEvent(mozilla::WidgetGUIEvent* aEvent,
nsEventStatus& aStatus) override;
NS_IMETHOD CaptureRollupEvents(nsIRollupListener * aListener,
bool aDoCapture) override {
return NS_ERROR_NOT_IMPLEMENTED;
}
void WillPaintWindow();
bool PaintWindow(nsIntRegion 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;
*/
NS_IMETHOD ReparentNativeWidget(nsIWidget* aNewParent) 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 gfxIntSize& 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_ */

901
widget/uikit/nsWindow.mm Normal file
View File

@ -0,0 +1,901 @@
/* -*- 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 nsIntRect& 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:(int) aType point:(LayoutDeviceIntPoint)aPoint widget:(nsWindow*)aWindow;
- (void)handleTap:(UITapGestureRecognizer *)sender;
- (BOOL)isUsingMainThreadOpenGL;
- (void)drawUsingOpenGL;
- (void)drawUsingOpenGLCallback;
- (void)sendTouchEvent:(int) 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:(int) aType point:(LayoutDeviceIntPoint)aPoint widget:(nsWindow*)aWindow
{
WidgetMouseEvent event(true, aType, aWindow,
WidgetMouseEvent::eReal, WidgetMouseEvent::eNormal);
event.refPoint = aPoint;
event.clickCount = 1;
event.button = WidgetMouseEvent::eLeftButton;
event.time = 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:NS_MOUSE_MOVE point:lp widget:mGeckoChild];
[self sendMouseEvent:NS_MOUSE_BUTTON_DOWN point:lp widget:mGeckoChild];
[self sendMouseEvent:NS_MOUSE_BUTTON_UP point:lp widget:mGeckoChild];
}
}
- (void)sendTouchEvent:(int) 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.time = PR_IntervalNow();
event.touches.SetCapacity(aTouches.count);
for (UITouch* touch in aTouches) {
LayoutDeviceIntPoint loc = UIKitPointsToDevPixels([touch locationInView:self], [self contentScaleFactor]);
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);
nsRefPtr<Touch> t = new Touch(id,
loc,
nsIntPoint([touch majorRadius], [touch majorRadius]),
0.0f,
1.0f);
event.refPoint = loc;
event.touches.AppendElement(t);
}
aWindow->DispatchAPZAwareEvent(&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:NS_TOUCH_START touches:[event allTouches] widget:mGeckoChild];
}
- (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
{
ALOG("[ChildView[%p] touchesCancelled", self);
[self sendTouchEvent:NS_TOUCH_CANCEL 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:NS_TOUCH_END 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:NS_TOUCH_MOVE 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;
nsIntRect geckoBounds;
mGeckoChild->GetBounds(geckoBounds);
nsIntRegion 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
nsIntRect geckoBounds;
mGeckoChild->GetBounds(geckoBounds);
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;
nsIntSize backingSize(viewSize.width * scale, viewSize.height * scale);
CGContextSaveGState(aContext);
nsIntRegion region = nsIntRect(NSToIntRound(aRect.origin.x * scale),
NSToIntRound(aRect.origin.y * scale),
NSToIntRound(aRect.size.width * scale),
NSToIntRound(aRect.size.height * scale));
// Create Cairo objects.
nsRefPtr<gfxQuartzSurface> targetSurface;
nsRefPtr<gfxContext> targetContext;
if (gfxPlatform::GetPlatform()->SupportsAzureContentForType(gfx::BackendType::COREGRAPHICS)) {
RefPtr<gfx::DrawTarget> dt =
gfx::Factory::CreateDrawTargetForCairoCGContext(aContext,
gfx::IntSize(backingSize.width,
backingSize.height));
dt->AddUserData(&gfxContext::sDontUseAsSourceKey, dt, nullptr);
targetContext = new gfxContext(dt);
} else 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,
gfx::IntSize(backingSize.width,
backingSize.height));
dt->AddUserData(&gfxContext::sDontUseAsSourceKey, dt, nullptr);
targetContext = new gfxContext(dt);
} else {
MOZ_ASSERT_UNREACHABLE("COREGRAPHICS is the only supported backed");
}
// Set up the clip region.
nsIntRegionRectIterator iter(region);
targetContext->NewPath();
for (;;) {
const nsIntRect* r = iter.Next();
if (!r)
break;
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
//
NS_IMETHODIMP
nsWindow::Create(nsIWidget *aParent,
nsNativeWidget aNativeParent,
const nsIntRect &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, mBounds, 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;
}
NS_IMETHODIMP
nsWindow::Destroy(void)
{
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::ReparentNativeWidget(nsIWidget* aNewParent)
{
return NS_ERROR_NOT_IMPLEMENTED;
}
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::SetModal(bool aModal)
{
return NS_OK;
}
NS_IMETHODIMP
nsWindow::ConstrainPosition(bool aAllowSlop,
int32_t *aX,
int32_t *aY)
{
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;
}
NS_IMETHODIMP
nsWindow::PlaceBehind(nsTopLevelWidgetZPlacement aPlacement,
nsIWidget *aWidget,
bool aActivate)
{
return NS_OK;
}
NS_IMETHODIMP
nsWindow::SetSizeMode(int32_t aMode)
{
if (aMode == static_cast<int32_t>(mSizeMode)) {
return NS_OK;
}
nsresult rv = NS_OK;
mSizeMode = static_cast<nsSizeMode>(aMode);
if (aMode == nsSizeMode_Maximized || aMode == nsSizeMode_Fullscreen) {
// Resize to fill screen
rv = nsBaseWidget::MakeFullScreen(true);
}
ReportSizeModeEvent(aMode);
return rv;
}
NS_IMETHODIMP
nsWindow::Invalidate(const nsIntRect &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(nsIntRegion 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(int32_t 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) {
nsIntRect innerBounds;
GetClientBounds(innerBounds);
mWidgetListener->WindowResized(this, innerBounds.width, innerBounds.height);
}
}
NS_IMETHODIMP
nsWindow::GetScreenBounds(nsIntRect &aRect)
{
LayoutDeviceIntPoint p = WidgetToScreenOffset();
aRect.x = p.x;
aRect.y = p.y;
aRect.width = mBounds.width;
aRect.height = mBounds.height;
return NS_OK;
}
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 = do_QueryInterface(aEvent->widget);
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()
{
mInputContext.mNativeIMEContext = nullptr;
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;
}
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;
}