diff --git a/shell/ios/.gitignore b/shell/ios/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..01a36b1b7081a9f00704f8e99c9292a5a2f5d7e0 --- /dev/null +++ b/shell/ios/.gitignore @@ -0,0 +1,3 @@ +*.pbxproj +*.xcworkspace +*.xcodeproj diff --git a/shell/ios/Entitlements.xcent b/shell/ios/Entitlements.xcent new file mode 100644 index 0000000000000000000000000000000000000000..8030fd51364177ebc81b5d4795a3098fc77d048a --- /dev/null +++ b/shell/ios/Entitlements.xcent @@ -0,0 +1,16 @@ + + + + + application-identifier + F5T262WGN6.com.google.sky + com.apple.developer.team-identifier + F5T262WGN6 + get-task-allow + + keychain-access-groups + + F5T262WGN6.com.google.sky + + + diff --git a/shell/ios/Info.plist b/shell/ios/Info.plist new file mode 100644 index 0000000000000000000000000000000000000000..cd5b90f17f5968a16e64ee5ecb9e818e1943d8dd --- /dev/null +++ b/shell/ios/Info.plist @@ -0,0 +1,82 @@ + + + + + CFBundleDevelopmentRegion + en + + + CFBundleExecutable + Sky + + CFBundleIdentifier + com.google.sky + + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + Sky + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UIRequiredDeviceCapabilities + + armv7 + + + + CFBundleURLTypes + + + CFBundleTypeRole + Viewer + CFBundleURLName + com.google.mojo + CFBundleURLSchemes + + mojo + + + + + + com.google.sky.load_url + https://domokit.github.io/sky_home + + + DTPlatformName + iphonesimulator + DTSDKName + iphonesimulator8.3 + LSRequiresIPhoneOS + + MinimumOSVersion + 8.3 + UIDeviceFamily + + 1 + 2 + + CFBundleSupportedPlatforms + + iPhoneSimulator + + + diff --git a/shell/ios/main_ios.mm b/shell/ios/main_ios.mm new file mode 100644 index 0000000000000000000000000000000000000000..f0020606e2c9542e8781b6937f4849f9615f6ccc --- /dev/null +++ b/shell/ios/main_ios.mm @@ -0,0 +1,60 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import +#include +#import "sky_app_delegate.h" +#include "base/at_exit.h" +#include "base/logging.h" +#include "base/i18n/icu_util.h" +#include "base/command_line.h" +#include "base/mac/scoped_nsautorelease_pool.h" +#include "ui/gl/gl_surface.h" + +static void InitializeLogging() { + logging::LoggingSettings settings; + settings.logging_dest = logging::LOG_TO_SYSTEM_DEBUG_LOG; + logging::InitLogging(settings); + logging::SetLogItems(false, // Process ID + false, // Thread ID + false, // Timestamp + false); // Tick count +} + +static void RedirectIOConnectionsToSyslog() { + asl_log_descriptor(NULL, NULL, ASL_LEVEL_INFO, STDOUT_FILENO, + ASL_LOG_DESCRIPTOR_WRITE); + asl_log_descriptor(NULL, NULL, ASL_LEVEL_NOTICE, STDERR_FILENO, + ASL_LOG_DESCRIPTOR_WRITE); +} + +#ifndef NDEBUG + +static void SkyDebuggerHookMain(void) { + // By default, LLDB breaks way too early. This is before libraries have been + // loaded and __attribute__((constructor)) methods have been called. In most + // situations, this is unnecessary. Also, breakpoint resolution is not + // immediate. So we provide this hook to break on. +} + +#endif + +int main(int argc, char* argv[]) { +#ifndef NDEBUG + SkyDebuggerHookMain(); +#endif + base::mac::ScopedNSAutoreleasePool pool; + base::AtExitManager exit_manager; + RedirectIOConnectionsToSyslog(); + auto result = false; + result = base::CommandLine::Init(0, nullptr); + DLOG_ASSERT(result); + InitializeLogging(); + result = base::i18n::InitializeICU(); + DLOG_ASSERT(result); + result = gfx::GLSurface::InitializeOneOff(); + DLOG_ASSERT(result); + return UIApplicationMain(argc, argv, nil, + NSStringFromClass([SkyAppDelegate class])); +} diff --git a/shell/ios/platform_service_provider_ios.cc b/shell/ios/platform_service_provider_ios.cc new file mode 100644 index 0000000000000000000000000000000000000000..6ae956f07d768d1237478bfa11505b6934acc61c --- /dev/null +++ b/shell/ios/platform_service_provider_ios.cc @@ -0,0 +1,45 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "sky/engine/config.h" +#include "sky/engine/wtf/Assertions.h" +#include "sky/shell/service_provider.h" +#include "base/single_thread_task_runner.h" +#include "base/bind.h" +#include "base/bind_helpers.h" +#include "base/lazy_instance.h" +#include "base/location.h" +#include "mojo/public/cpp/application/service_provider_impl.h" +#include "sky/services/ns_net/network_service_impl.h" + +namespace sky { +namespace shell { + +// FIXME(csg): Put this in an application owned context +base::LazyInstance> g_service_provider = + LAZY_INSTANCE_INITIALIZER; +base::LazyInstance> + g_network_service_factory = LAZY_INSTANCE_INITIALIZER; + +static void CreatePlatformServiceProvider( + mojo::InterfaceRequest request) { + g_service_provider.Get().reset(new mojo::ServiceProviderImpl(request.Pass())); + g_network_service_factory.Get().reset(new mojo::NetworkServiceFactory()); + g_service_provider.Get()->AddService(g_network_service_factory.Get().get()); +} + +mojo::ServiceProviderPtr CreateServiceProvider( + ServiceProviderContext* context) { + DCHECK(context); + mojo::MessagePipe pipe; + auto request = mojo::MakeRequest(pipe.handle1.Pass()); + context->platform_task_runner->PostTask( + FROM_HERE, + base::Bind(CreatePlatformServiceProvider, base::Passed(request.Pass()))); + return mojo::MakeProxy( + mojo::InterfacePtrInfo(pipe.handle0.Pass(), 0u)); +} + +} // namespace shell +} // namespace sky diff --git a/shell/ios/platform_view_ios.h b/shell/ios/platform_view_ios.h new file mode 100644 index 0000000000000000000000000000000000000000..19e0e1822c070e28b5b54f0f5c3f6bf4eeaa5b9f --- /dev/null +++ b/shell/ios/platform_view_ios.h @@ -0,0 +1,25 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef SKY_SHELL_PLATFORM_VIEW_IOS_H_ +#define SKY_SHELL_PLATFORM_VIEW_IOS_H_ + +#include "sky/shell/platform_view.h" + +namespace sky { +namespace shell { + +class PlatformViewIOS : public PlatformView { + public: + void SurfaceCreated(gfx::AcceleratedWidget widget); + void SurfaceDestroyed(void); + + private: + DISALLOW_COPY_AND_ASSIGN(PlatformViewIOS); +}; + +} // namespace shell +} // namespace sky + +#endif // SKY_SHELL_PLATFORM_VIEW_IOS_H_ diff --git a/shell/ios/platform_view_ios.mm b/shell/ios/platform_view_ios.mm new file mode 100644 index 0000000000000000000000000000000000000000..7ef5d166579b492a339b3fdc69ef72b8ef3cea3d --- /dev/null +++ b/shell/ios/platform_view_ios.mm @@ -0,0 +1,23 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "platform_view_ios.h" + +namespace sky { +namespace shell { + +void PlatformViewIOS::SurfaceCreated(gfx::AcceleratedWidget widget) { + DCHECK(window_ == 0); + window_ = widget; + SurfaceWasCreated(); +} + +void PlatformViewIOS::SurfaceDestroyed() { + DCHECK(window_); + window_ = 0; + SurfaceWasDestroyed(); +} + +} // namespace shell +} // namespace sky diff --git a/shell/ios/sky_app_delegate.h b/shell/ios/sky_app_delegate.h new file mode 100644 index 0000000000000000000000000000000000000000..9103726971e97a9750cf91814095762e7c267d82 --- /dev/null +++ b/shell/ios/sky_app_delegate.h @@ -0,0 +1,11 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import + +@interface SkyAppDelegate : UIResponder + +@property(strong, nonatomic) UIWindow* window; + +@end diff --git a/shell/ios/sky_app_delegate.mm b/shell/ios/sky_app_delegate.mm new file mode 100644 index 0000000000000000000000000000000000000000..ff7449daaa9c1e1549f3f6aa1c883511b4fb1677 --- /dev/null +++ b/shell/ios/sky_app_delegate.mm @@ -0,0 +1,53 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "sky_app_delegate.h" +#import "sky_view_controller.h" + +#include "sky/shell/shell.h" +#include "sky/shell/service_provider.h" +#include "sky/shell/ui_delegate.h" +#include "base/lazy_instance.h" +#include "base/message_loop/message_loop.h" + +@implementation SkyAppDelegate { + base::LazyInstance> _main_message_loop; +} + +- (BOOL)application:(UIApplication*)application + didFinishLaunchingWithOptions:(NSDictionary*)launchOptions { + [self setupSkyShell]; + [self setupViewport]; + + return YES; +} + +- (void)setupSkyShell { + [self adoptPlatformRunLoop]; + + auto service_provider_context = + make_scoped_ptr(new sky::shell::ServiceProviderContext( + _main_message_loop.Get()->task_runner())); + sky::shell::Shell::Init(service_provider_context.Pass()); +} + +- (void)adoptPlatformRunLoop { + _main_message_loop.Get().reset(new base::MessageLoopForUI); + // One cannot start the message loop on the platform main thread. Instead, + // we attach to the CFRunLoop + base::MessageLoopForUI::current()->Attach(); +} + +- (void)setupViewport { + CGRect frame = [UIScreen mainScreen].bounds; + UIWindow* window = [[UIWindow alloc] initWithFrame:frame]; + SkyViewController* viewController = [[SkyViewController alloc] init]; + window.rootViewController = viewController; + [viewController release]; + self.window = window; + [window release]; + [self.window makeKeyAndVisible]; +} + +@end diff --git a/shell/ios/sky_surface.h b/shell/ios/sky_surface.h new file mode 100644 index 0000000000000000000000000000000000000000..bb65f2d85989b3f844ea26cfcc77d04f0d49ea6e --- /dev/null +++ b/shell/ios/sky_surface.h @@ -0,0 +1,9 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import + +@interface SkySurface : UIView + +@end diff --git a/shell/ios/sky_surface.mm b/shell/ios/sky_surface.mm new file mode 100644 index 0000000000000000000000000000000000000000..d8056de84be340b5ef24f8ff7d26072376583706 --- /dev/null +++ b/shell/ios/sky_surface.mm @@ -0,0 +1,162 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "sky_surface.h" + +#import +#import +#import + +#include "sky/shell/ui_delegate.h" +#include "sky/shell/shell.h" +#include "sky/shell/ios/platform_view_ios.h" + +#include "mojo/public/cpp/bindings/interface_request.h" +#include "sky/services/viewport/input_event.mojom.h" +#include "base/time/time.h" + +static inline sky::EventType EventTypeFromUITouchPhase(UITouchPhase phase) { + switch (phase) { + case UITouchPhaseBegan: + return sky::EVENT_TYPE_POINTER_DOWN; + case UITouchPhaseMoved: + case UITouchPhaseStationary: + // There is no EVENT_TYPE_POINTER_STATIONARY. So we just pass a move type + // with the same coordinates + return sky::EVENT_TYPE_POINTER_MOVE; + case UITouchPhaseEnded: + return sky::EVENT_TYPE_POINTER_UP; + case UITouchPhaseCancelled: + return sky::EVENT_TYPE_POINTER_CANCEL; + } + + return sky::EVENT_TYPE_UNKNOWN; +} + +@implementation SkySurface { + BOOL _platformViewInitialized; + + sky::ViewportObserverPtr _viewport_observer; +} + +- (gfx::AcceleratedWidget)acceleratedWidget { + return (gfx::AcceleratedWidget)self.layer; +} + +- (void)layoutSubviews { + [super layoutSubviews]; + + [self configureLayerDefaults]; + + [self setupPlatformViewIfNecessary]; + + CGSize size = self.bounds.size; + CGFloat scale = [UIScreen mainScreen].scale; + + _viewport_observer->OnViewportMetricsChanged(size.width * scale, + size.height * scale, scale); +} + +- (void)configureLayerDefaults { + CAEAGLLayer* layer = reinterpret_cast(self.layer); + layer.allowsGroupOpacity = YES; + layer.opaque = YES; + CGFloat screenScale = [UIScreen mainScreen].scale; + layer.contentsScale = screenScale; + // Note: shouldRasterize is still NO. This is just a defensive measure + layer.rasterizationScale = screenScale; +} + +- (void)setupPlatformViewIfNecessary { + if (_platformViewInitialized) { + return; + } + + _platformViewInitialized = YES; + + [self notifySurfaceCreation]; + [self connectToViewportObserverAndLoad]; +} + +- (sky::shell::PlatformViewIOS*)platformView { + auto view = static_cast( + sky::shell::Shell::Shared().view()); + DCHECK(view); + return view; +} + +- (void)notifySurfaceCreation { + self.platformView->SurfaceCreated(self.acceleratedWidget); +} + +- (NSString*)skyInitialLoadURL { + return [NSBundle mainBundle].infoDictionary[@"com.google.sky.load_url"]; +} + +- (void)connectToViewportObserverAndLoad { + auto view = sky::shell::Shell::Shared().view(); + auto interface_request = mojo::GetProxy(&_viewport_observer); + view->ConnectToViewportObserver(interface_request.Pass()); + + mojo::String string(self.skyInitialLoadURL.UTF8String); + _viewport_observer->LoadURL(string); +} + +- (void)notifySurfaceDestruction { + self.platformView->SurfaceDestroyed(); +} + +#pragma mark - UIResponder overrides for raw touches + +- (void)dispatchTouches:(NSSet*)touches phase:(UITouchPhase)phase { + auto eventType = EventTypeFromUITouchPhase(phase); + const CGFloat scale = [UIScreen mainScreen].scale; + + for (UITouch* touch in touches) { + auto input = sky::InputEvent::New(); + input->type = eventType; + + auto timedelta = base::TimeDelta::FromSecondsD(touch.timestamp); + input->time_stamp = timedelta.InMilliseconds(); + + input->pointer_data = sky::PointerData::New(); + input->pointer_data->kind = sky::POINTER_KIND_TOUCH; + + CGPoint windowCoordinates = [touch locationInView:nil]; + + input->pointer_data->x = windowCoordinates.x * scale; + input->pointer_data->y = windowCoordinates.y * scale; + + _viewport_observer->OnInputEvent(input.Pass()); + } +} + +- (void)touchesBegan:(NSSet*)touches withEvent:(UIEvent*)event { + [self dispatchTouches:touches phase:UITouchPhaseBegan]; +} + +- (void)touchesMoved:(NSSet*)touches withEvent:(UIEvent*)event { + [self dispatchTouches:touches phase:UITouchPhaseMoved]; +} + +- (void)touchesEnded:(NSSet*)touches withEvent:(UIEvent*)event { + [self dispatchTouches:touches phase:UITouchPhaseEnded]; +} + +- (void)touchesCancelled:(NSSet*)touches withEvent:(UIEvent*)event { + [self dispatchTouches:touches phase:UITouchPhaseCancelled]; +} + +#pragma mark - Misc. + ++ (Class)layerClass { + return [CAEAGLLayer class]; +} + +- (void)dealloc { + [self notifySurfaceDestruction]; + [super dealloc]; +} + +@end diff --git a/shell/ios/sky_view_controller.h b/shell/ios/sky_view_controller.h new file mode 100644 index 0000000000000000000000000000000000000000..d82b6cd242ae3a2341e7fd0373a3ec929f77097a --- /dev/null +++ b/shell/ios/sky_view_controller.h @@ -0,0 +1,9 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import + +@interface SkyViewController : UIViewController + +@end diff --git a/shell/ios/sky_view_controller.mm b/shell/ios/sky_view_controller.mm new file mode 100644 index 0000000000000000000000000000000000000000..ee2e38ad762b1c9ac9ed8e7e7c3620ef789f4671 --- /dev/null +++ b/shell/ios/sky_view_controller.mm @@ -0,0 +1,24 @@ +// Copyright 2015 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#import "sky_view_controller.h" +#import "sky_surface.h" + +#import +#import + +@implementation SkyViewController + +- (void)loadView { + SkySurface* surface = [[SkySurface alloc] init]; + + surface.autoresizingMask = + UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; + + self.view = surface; + + [surface release]; +} + +@end