From edf0f3379aa09347351249e7ab34d4d6b0940e53 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Wed, 23 Sep 2015 16:53:18 -0700 Subject: [PATCH 1/2] Map UITouch pointers to indentifiers similar to Android --- sky/shell/ios/sky_surface.mm | 79 +++++++++++++++++++++++++++++++----- 1 file changed, 68 insertions(+), 11 deletions(-) diff --git a/sky/shell/ios/sky_surface.mm b/sky/shell/ios/sky_surface.mm index d41843fd2cd..f8a1566e09b 100644 --- a/sky/shell/ios/sky_surface.mm +++ b/sky/shell/ios/sky_surface.mm @@ -15,27 +15,40 @@ #include "sky/shell/shell_view.h" #include "sky/shell/shell.h" #include "sky/shell/ui_delegate.h" +#include #ifndef NDEBUG #include "document_watcher.h" #endif -static inline sky::EventType EventTypeFromUITouchPhase(UITouchPhase phase) { +enum MapperPhase { + Accessed, + Added, + Removed, +}; + +using EventTypeMapperPhase = std::pair; +static inline EventTypeMapperPhase EventTypePhaseFromUITouchPhase( + UITouchPhase phase) { switch (phase) { case UITouchPhaseBegan: - return sky::EVENT_TYPE_POINTER_DOWN; + return EventTypeMapperPhase(sky::EVENT_TYPE_POINTER_DOWN, + MapperPhase::Added); 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; + return EventTypeMapperPhase(sky::EVENT_TYPE_POINTER_MOVE, + MapperPhase::Accessed); case UITouchPhaseEnded: - return sky::EVENT_TYPE_POINTER_UP; + return EventTypeMapperPhase(sky::EVENT_TYPE_POINTER_UP, + MapperPhase::Removed); case UITouchPhaseCancelled: - return sky::EVENT_TYPE_POINTER_CANCEL; + return EventTypeMapperPhase(sky::EVENT_TYPE_POINTER_CANCEL, + MapperPhase::Removed); } - return sky::EVENT_TYPE_UNKNOWN; + return EventTypeMapperPhase(sky::EVENT_TYPE_UNKNOWN, MapperPhase::Accessed); } static inline int64 InputEventTimestampFromNSTimeInterval( @@ -43,12 +56,41 @@ static inline int64 InputEventTimestampFromNSTimeInterval( return base::TimeDelta::FromSecondsD(interval).InMilliseconds(); } +// UITouch pointers cannot be used as touch ids (even though they remain +// constant throughout the multitouch sequence) because internal components +// assume that ids are < 16. This class maps touch pointers to ids +class TouchMapper { + public: + TouchMapper() : free_spots_(~0) {} + + int registerTouch(uintptr_t touch) { + int freeSpot = ffsll(free_spots_); + touch_map_[touch] = freeSpot; + free_spots_ &= ~(1 << (freeSpot - 1)); + return freeSpot; + } + + void unregisterTouch(uintptr_t touch) { + auto index = touch_map_[touch]; + free_spots_ |= 1 << (index - 1); + touch_map_.erase(touch); + } + + int identifierOf(uintptr_t touch) { return touch_map_[touch]; } + + private: + using BitSet = long long int; + BitSet free_spots_; + std::map touch_map_; +}; + @implementation SkySurface { BOOL _platformViewInitialized; CGPoint _lastScrollTranslation; sky::SkyEnginePtr _sky_engine; scoped_ptr _shell_view; + TouchMapper _touch_mapper; #ifndef NDEBUG DocumentWatcher *_document_watcher; @@ -217,20 +259,35 @@ static std::string SkPictureTracingPath() { #pragma mark - UIResponder overrides for raw touches - (void)dispatchTouches:(NSSet*)touches phase:(UITouchPhase)phase { - auto eventType = EventTypeFromUITouchPhase(phase); + auto eventTypePhase = EventTypePhaseFromUITouchPhase(phase); const CGFloat scale = [UIScreen mainScreen].scale; for (UITouch* touch in touches) { auto input = sky::InputEvent::New(); - input->type = eventType; + input->type = eventTypePhase.first; input->time_stamp = InputEventTimestampFromNSTimeInterval(touch.timestamp); input->pointer_data = sky::PointerData::New(); input->pointer_data->kind = sky::POINTER_KIND_TOUCH; - #define LOWER_32(x) (*((int32_t *) &x)) - input->pointer_data->pointer = LOWER_32(touch); - #undef LOWER_32 + int touch_identifier = 0; + uintptr_t touch_ptr = reinterpret_cast(touch); + + switch (eventTypePhase.second) { + case Accessed: + touch_identifier = _touch_mapper.identifierOf(touch_ptr); + break; + case Added: + touch_identifier = _touch_mapper.registerTouch(touch_ptr); + break; + case Removed: + touch_identifier = _touch_mapper.identifierOf(touch_ptr); + _touch_mapper.unregisterTouch(touch_ptr); + break; + } + + DCHECK(touch_identifier != 0); + input->pointer_data->pointer = touch_identifier; CGPoint windowCoordinates = [touch locationInView:nil]; From c2ed9a10c2185e7331a5a74a772963f4c9f8b447 Mon Sep 17 00:00:00 2001 From: Chinmay Garde Date: Wed, 23 Sep 2015 16:59:19 -0700 Subject: [PATCH 2/2] Make `unregisterTouch` return the identifier of the removed touch --- sky/shell/ios/sky_surface.mm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sky/shell/ios/sky_surface.mm b/sky/shell/ios/sky_surface.mm index f8a1566e09b..e2842135db8 100644 --- a/sky/shell/ios/sky_surface.mm +++ b/sky/shell/ios/sky_surface.mm @@ -70,10 +70,11 @@ class TouchMapper { return freeSpot; } - void unregisterTouch(uintptr_t touch) { + int unregisterTouch(uintptr_t touch) { auto index = touch_map_[touch]; free_spots_ |= 1 << (index - 1); touch_map_.erase(touch); + return index; } int identifierOf(uintptr_t touch) { return touch_map_[touch]; } @@ -281,8 +282,7 @@ static std::string SkPictureTracingPath() { touch_identifier = _touch_mapper.registerTouch(touch_ptr); break; case Removed: - touch_identifier = _touch_mapper.identifierOf(touch_ptr); - _touch_mapper.unregisterTouch(touch_ptr); + touch_identifier = _touch_mapper.unregisterTouch(touch_ptr); break; }