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