Просмотр исходного кода

iOS: Fix crash on pinch gesture

Related: 65091012b47f68e6e7185014ed64bae7301e17fc

After the aforementioned commit, pinching in any iOS app using SDL
crashes with

	*** Terminating app due to uncaught exception 'NSRangeException', reason: '-[UIPinchGestureRecognizer locationOfTouch:inView:]: index (1) beyond bounds (1).'
	*** First throw call stack:
	(0x19d31a23c 0x199de9224 0x19d37fec4 0x1a3f99bf0 0x1a3fa3c68 0x103277370 0x1a33b8b7c 0x1a33b848c 0x1a33b8238 0x1a2efc9a4 0x1a2ec1310 0x1a8ab8754 0x1a8af6c1c 0x1a8abc324 0x1a8ac79f4 0x1a2f010e8 0x1a2ee9550 0x1a2efd638 0x1a2eea040 0x1a2f0318c 0x1a2eecd48 0x1a2f062a8 0x1a2f03834 0x2b210f56c 0x19d2a5358 0x19d2a52cc 0x19d26a5a8 0x19d2341a0 0x19d23354c 0x1032bcdd8 0x1032ee2a0 0x1032ee3fc 0x1032ee360 0x102280644 0x10228042c 0x1033cd0cc 0x1032a8198 0x19a61f5dc 0x19d273960 0x19d273658 0x19d2731cc 0x19d234584 0x19d23354c 0x24299f498 0x1a2f2c244 0x1a2e97158 0x1032a5780 0x102280030 0x199e41c1c)
	libc++abi: terminating due to uncaught exception of type NSException

As it turns out, `UIPinchGestureRecognizer` does not guarantee the
presence of two touches throughout the entire duration of the pinch.
When the user is releasing the touches that constitute the pinch
gesture, more often than not they will release one touch before the
other. When this happens, `UIPinchGestureRecognizer` *does not terminate
the pinch*, but continues updating it, only with one touch remaining in
the gesture. The gesture is only marked concluded when the user releases
*both* touches.

To prevent the crash, check that the second touch is actually available
via the `numberOfTouches` property. If it is not, avoid emitting
`SDL_EVENT_PINCH_UPDATE` events to prevent sending unexpected payloads
downstream; there is no second touch to use anymore to calculate
`(focus|span)_(x|y)`.
Bartłomiej Dach 21 часов назад
Родитель
Сommit
9acf54142e
1 измененных файлов с 3 добавлено и 2 удалено
  1. 3 2
      src/video/uikit/SDL_uikitview.m

+ 3 - 2
src/video/uikit/SDL_uikitview.m

@@ -484,8 +484,9 @@ extern int SDL_AppleTVRemoteOpenedAsJoystick;
 {
     CGFloat scale = sender.scale;
     UIGestureRecognizerState state = sender.state;
+    bool pinchHasTwoPoints = sender.numberOfTouches == 2;
     CGPoint point1 = [sender locationOfTouch:0 inView:self];
-    CGPoint point2 = [sender locationOfTouch:1 inView:self];
+    CGPoint point2 = pinchHasTwoPoints ? [sender locationOfTouch:1 inView:self] : point1;
     CGFloat focus_x = (point1.x + point2.x)/2;
     CGFloat focus_y = (point1.y + point2.y)/2;
     CGFloat span_x = SDL_fabs(point1.x - point2.x);
@@ -504,7 +505,7 @@ extern int SDL_AppleTVRemoteOpenedAsJoystick;
             break;
 
         case UIGestureRecognizerStateChanged:
-            if (pinch_scale > 0.0f) {
+            if (pinch_scale > 0.0f && pinchHasTwoPoints) {
                 SDL_SendPinch(SDL_EVENT_PINCH_UPDATE, 0, sdlwindow, scale / pinch_scale, span_x, span_y, focus_x, focus_y);
             }
             pinch_scale = scale;