sky_surface.mm 10.9 KB
Newer Older
C
Chinmay Garde 已提交
1 2 3 4 5 6 7 8 9 10
// 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 <QuartzCore/QuartzCore.h>
#import <OpenGLES/EAGL.h>
#import <OpenGLES/EAGLDrawable.h>

11 12 13
#include "base/time/time.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "sky/services/engine/input_event.mojom.h"
14
#include "sky/shell/mac/platform_view_mac.h"
15
#include "sky/shell/shell_view.h"
16
#include "sky/shell/shell.h"
17
#include "sky/shell/ui_delegate.h"
C
Chinmay Garde 已提交
18

19 20 21 22
#ifndef NDEBUG
#include "document_watcher.h"
#endif

C
Chinmay Garde 已提交
23 24 25 26 27 28 29 30 31 32
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:
33
      return sky::EVENT_TYPE_POINTER_UP;
34 35
    case UITouchPhaseCancelled:
      return sky::EVENT_TYPE_POINTER_CANCEL;
C
Chinmay Garde 已提交
36 37 38 39 40
  }

  return sky::EVENT_TYPE_UNKNOWN;
}

41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62
static inline int64 InputEventTimestampFromNSTimeInterval(
    NSTimeInterval interval) {
  return base::TimeDelta::FromSecondsD(interval).InMilliseconds();
}

static sky::InputEventPtr BasicInputEventFromRecognizer(
    sky::EventType type,
    UIGestureRecognizer* recognizer) {
  auto input = sky::InputEvent::New();
  input->type = type;
  input->time_stamp = InputEventTimestampFromNSTimeInterval(
      CACurrentMediaTime());

  input->gesture_data = sky::GestureData::New();

  CGPoint windowCoordinates = [recognizer locationInView:recognizer.view];
  const CGFloat scale = [UIScreen mainScreen].scale;
  input->gesture_data->x = windowCoordinates.x * scale;
  input->gesture_data->y = windowCoordinates.y * scale;
  return input.Pass();
}

C
Chinmay Garde 已提交
63 64
@implementation SkySurface {
  BOOL _platformViewInitialized;
65
  CGPoint _lastScrollTranslation;
C
Chinmay Garde 已提交
66

67
  sky::SkyEnginePtr _sky_engine;
68
  scoped_ptr<sky::shell::ShellView> _shell_view;
69 70 71 72

#ifndef NDEBUG
  DocumentWatcher *_document_watcher;
#endif
73 74 75 76
}

-(instancetype) initWithShellView:(sky::shell::ShellView *) shellView {
  self = [super init];
77
  if (self) {
78
    _shell_view.reset(shellView);
79
    self.multipleTouchEnabled = YES;
80 81
    [self installGestureRecognizers];
  }
82
  return self;
C
Chinmay Garde 已提交
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
}

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

C
Chinmay Garde 已提交
99
  sky::ViewportMetricsPtr metrics = sky::ViewportMetrics::New();
A
Adam Barth 已提交
100 101 102 103
  metrics->physical_width = size.width * scale;
  metrics->physical_height = size.height * scale;
  metrics->device_pixel_ratio = scale;
  _sky_engine->OnViewportMetricsChanged(metrics.Pass());
C
Chinmay Garde 已提交
104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123
}

- (void)configureLayerDefaults {
  CAEAGLLayer* layer = reinterpret_cast<CAEAGLLayer*>(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];
124
  [self connectToEngineAndLoad];
C
Chinmay Garde 已提交
125 126
}

127 128
- (sky::shell::PlatformViewMac*)platformView {
  auto view = static_cast<sky::shell::PlatformViewMac*>(_shell_view->view());
C
Chinmay Garde 已提交
129 130 131 132 133 134 135 136 137
  DCHECK(view);
  return view;
}

- (void)notifySurfaceCreation {
  self.platformView->SurfaceCreated(self.acceleratedWidget);
}

- (NSString*)skyInitialLoadURL {
C
Chinmay Garde 已提交
138 139 140 141 142 143
  NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
  NSString *target = [standardDefaults stringForKey:@"target"];
  NSString *server = [standardDefaults stringForKey:@"server"];
  if (server && target) {
    return [NSString stringWithFormat:@"http://%@/%@", server, target];
  }
144
  return [NSBundle mainBundle].infoDictionary[@"org.domokit.sky.load_url"];
C
Chinmay Garde 已提交
145 146
}

147
- (NSString*)skyInitialBundleURL {
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
  NSString *skyxBundlePath = [[NSBundle mainBundle] pathForResource:@"app" ofType:@"skyx"];
#ifndef NDEBUG
  NSFileManager *fileManager = [NSFileManager defaultManager];
  NSError *error = nil;
  NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
  NSString *documentsDirectory = [paths objectAtIndex:0];
  NSString *skyxDocsPath = [documentsDirectory stringByAppendingPathComponent:@"app.skyx"];

  if ([fileManager fileExistsAtPath:skyxDocsPath] == NO) {
    if ([fileManager copyItemAtPath:skyxBundlePath toPath:skyxDocsPath error:&error]) {
      return skyxDocsPath;
    }
    NSLog(@"Error encountered copying app.skyx from the Bundle to the Documents directory. Dynamic reloading will not be possible. %@", error);
    return skyxBundlePath;
  }
  return skyxDocsPath;
#endif
  return skyxBundlePath;
166 167
}

168 169 170
- (void)connectToEngineAndLoad {
  auto interface_request = mojo::GetProxy(&_sky_engine);
  self.platformView->ConnectToEngine(interface_request.Pass());
C
Chinmay Garde 已提交
171

172 173
  NSString *endpoint = self.skyInitialBundleURL;
  if (endpoint.length > 0) {
174 175 176 177 178 179
#ifndef NDEBUG
    _document_watcher = [[DocumentWatcher alloc] initWithDocumentPath:endpoint callbackBlock:^{
      mojo::String string(endpoint.UTF8String);
      _sky_engine->RunFromBundle(string);
    }];
#endif
180 181 182 183 184 185 186 187 188 189 190 191 192
    // Load from bundle
    mojo::String string(endpoint.UTF8String);
    _sky_engine->RunFromBundle(string);
    return;
  }

  endpoint = self.skyInitialLoadURL;
  if (endpoint.length > 0) {
    // Load from URL
    mojo::String string(endpoint.UTF8String);
    _sky_engine->RunFromNetwork(string);
    return;
  }
C
Chinmay Garde 已提交
193 194 195 196 197 198
}

- (void)notifySurfaceDestruction {
  self.platformView->SurfaceDestroyed();
}

199 200 201 202 203 204 205 206 207 208
#ifndef NDEBUG
- (void)didMoveToWindow {
  if (self.window == nil) {
    [_document_watcher cancel];
    [_document_watcher release];
    _document_watcher = nil;
  }
}
#endif

C
Chinmay Garde 已提交
209 210 211 212 213 214 215 216 217
#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;
218
    input->time_stamp = InputEventTimestampFromNSTimeInterval(touch.timestamp);
C
Chinmay Garde 已提交
219 220 221 222

    input->pointer_data = sky::PointerData::New();
    input->pointer_data->kind = sky::POINTER_KIND_TOUCH;

223 224 225 226
    #define LOWER_32(x) (*((int32_t *) &x))
    input->pointer_data->pointer = LOWER_32(touch);
    #undef LOWER_32

C
Chinmay Garde 已提交
227 228 229 230 231
    CGPoint windowCoordinates = [touch locationInView:nil];

    input->pointer_data->x = windowCoordinates.x * scale;
    input->pointer_data->y = windowCoordinates.y * scale;

232
    _sky_engine->OnInputEvent(input.Pass());
C
Chinmay Garde 已提交
233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251
  }
}

- (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];
}

252 253 254 255 256 257 258 259
#pragma mark - Gesture Recognizers

-(void) installGestureRecognizers {
  // For:
  //   GESTURE_FLING_CANCEL
  //   GESTURE_FLING_START
  UISwipeGestureRecognizer *swipe = [[UISwipeGestureRecognizer alloc]
    initWithTarget:self action:@selector(onFling:)];
260
  swipe.cancelsTouchesInView = NO;
261 262 263 264 265 266 267 268 269
  [self addGestureRecognizer: swipe];
  [swipe release];

  // For:
  //   GESTURE_LONG_PRESS
  //   GESTURE_SHOW_PRESS
  UILongPressGestureRecognizer *longPress =
    [[UILongPressGestureRecognizer alloc]
      initWithTarget:self action:@selector(onLongPress:)];
270
  longPress.cancelsTouchesInView = NO;
271 272 273 274 275 276 277 278 279
  [self addGestureRecognizer: longPress];
  [longPress release];

  // For:
  //   GESTURE_SCROLL_BEGIN
  //   GESTURE_SCROLL_END
  //   GESTURE_SCROLL_UPDATE
  UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc]
    initWithTarget:self action:@selector(onScroll:)];
280
  pan.cancelsTouchesInView = NO;
281 282 283 284 285 286 287 288
  [self addGestureRecognizer: pan];
  [pan release];

  // For:
  //   GESTURE_TAP
  //   GESTURE_TAP_DOWN
  UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc]
    initWithTarget:self action:@selector(onTap:)];
289
  tap.cancelsTouchesInView = NO;
290 291 292 293 294 295 296 297 298 299 300 301
  [self addGestureRecognizer: tap];
  [tap release];
}

-(void) onFling:(UISwipeGestureRecognizer *) recognizer {
  // Swipes are discrete gestures already. So there is no equivalent to a cancel
  if (recognizer.state != UIGestureRecognizerStateEnded) {
    return;
  }

  auto input = BasicInputEventFromRecognizer(
    sky::EVENT_TYPE_GESTURE_FLING_START, recognizer);
302
  _sky_engine->OnInputEvent(input.Pass());
303 304 305 306 307 308 309 310 311
}

-(void) onLongPress:(UILongPressGestureRecognizer *) recognizer {
  if (recognizer.state != UIGestureRecognizerStateEnded) {
    return;
  }

  auto input = BasicInputEventFromRecognizer(sky::EVENT_TYPE_GESTURE_LONG_PRESS,
                                             recognizer);
312
  _sky_engine->OnInputEvent(input.Pass());
313 314 315 316 317 318
}

-(void) onScroll:(UIPanGestureRecognizer *) recognizer {
  sky::EventType type = sky::EVENT_TYPE_UNKNOWN;
  switch (recognizer.state) {
    case UIGestureRecognizerStateBegan:
319
      _lastScrollTranslation = CGPointZero;
320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342
      type = sky::EVENT_TYPE_GESTURE_SCROLL_BEGIN;
      break;
    case UIGestureRecognizerStateChanged:
      type = sky::EVENT_TYPE_GESTURE_SCROLL_UPDATE;
      break;
    case UIGestureRecognizerStateEnded:
    case UIGestureRecognizerStateCancelled:
    case UIGestureRecognizerStateFailed:
      type = sky::EVENT_TYPE_GESTURE_SCROLL_END;
      break;
    default:
      break;
  }

  if (type == sky::EVENT_TYPE_UNKNOWN) {
    return;
  }

  auto input = BasicInputEventFromRecognizer(type, recognizer);
  auto scale = [UIScreen mainScreen].scale;
  auto translation = [recognizer translationInView: self];
  auto velocity = [recognizer velocityInView: self];

343 344 345 346 347
  input->gesture_data->dx = (translation.x - _lastScrollTranslation.x) * scale;
  input->gesture_data->dy =  (translation.y - _lastScrollTranslation.y) * scale;

  _lastScrollTranslation = translation;

348 349 350
  input->gesture_data->velocityX = velocity.x * scale;
  input->gesture_data->velocityY =  velocity.y * scale;

351
  _sky_engine->OnInputEvent(input.Pass());
352 353 354 355 356 357 358 359 360 361
}

-(void) onTap:(UITapGestureRecognizer *) recognizer {

  if (recognizer.state != UIGestureRecognizerStateEnded) {
    return;
  }

  auto input = BasicInputEventFromRecognizer(sky::EVENT_TYPE_GESTURE_TAP,
                                             recognizer);
362
  _sky_engine->OnInputEvent(input.Pass());
363 364
}

C
Chinmay Garde 已提交
365 366 367 368 369 370 371 372 373 374 375 376
#pragma mark - Misc.

+ (Class)layerClass {
  return [CAEAGLLayer class];
}

- (void)dealloc {
  [self notifySurfaceDestruction];
  [super dealloc];
}

@end