From 7130895e3f5b3f1bcaf085aede975fff82ce81c7 Mon Sep 17 00:00:00 2001
From: Matthew Chen <matthew@signal.org>
Date: Thu, 21 Feb 2019 17:26:51 -0500
Subject: [PATCH] Fix translation in all of editor view's gestures.

---
 .../ImageEditor/ImageEditorCanvasView.swift   | 35 ---------
 .../ImageEditorCropViewController.swift       | 12 ---
 .../Views/ImageEditor/ImageEditorView.swift   | 78 +++++++++++++------
 3 files changed, 53 insertions(+), 72 deletions(-)

diff --git a/SignalMessaging/Views/ImageEditor/ImageEditorCanvasView.swift b/SignalMessaging/Views/ImageEditor/ImageEditorCanvasView.swift
index a8c1c2759..af715189c 100644
--- a/SignalMessaging/Views/ImageEditor/ImageEditorCanvasView.swift
+++ b/SignalMessaging/Views/ImageEditor/ImageEditorCanvasView.swift
@@ -531,41 +531,6 @@ public class ImageEditorCanvasView: UIView {
         return result
     }
 
-    // MARK: - Coordinates
-
-    public func locationUnit(forGestureRecognizer gestureRecognizer: UIGestureRecognizer,
-                             transform: ImageEditorTransform) -> CGPoint {
-        return ImageEditorCanvasView.locationUnit(forGestureRecognizer: gestureRecognizer,
-                                                  view: self.clipView,
-                                                  transform: transform)
-    }
-
-    public class func locationUnit(forGestureRecognizer gestureRecognizer: UIGestureRecognizer,
-                                   view: UIView,
-                                   transform: ImageEditorTransform) -> CGPoint {
-        let locationInView = gestureRecognizer.location(in: view)
-        return locationUnit(forLocationInView: locationInView,
-                            viewBounds: view.bounds,
-                            transform: transform)
-    }
-
-    public func locationUnit(forLocationInView locationInView: CGPoint,
-                             transform: ImageEditorTransform) -> CGPoint {
-        let viewBounds = self.clipView.bounds
-        return ImageEditorCanvasView.locationUnit(forLocationInView: locationInView,
-                                                  viewBounds: viewBounds,
-                                                  transform: transform)
-    }
-
-    public class func locationUnit(forLocationInView locationInView: CGPoint,
-                                   viewBounds: CGRect,
-                                   transform: ImageEditorTransform) -> CGPoint {
-        let affineTransformStart = transform.affineTransform(viewSize: viewBounds.size)
-        let locationInContent = locationInView.minus(viewBounds.center).applyingInverse(affineTransformStart).plus(viewBounds.center)
-        let locationUnit = locationInContent.toUnitCoordinates(viewSize: viewBounds.size, shouldClamp: false)
-        return locationUnit
-    }
-
     // MARK: - Actions
 
     // Returns nil on error.
diff --git a/SignalMessaging/Views/ImageEditor/ImageEditorCropViewController.swift b/SignalMessaging/Views/ImageEditor/ImageEditorCropViewController.swift
index e012b6035..b379ae892 100644
--- a/SignalMessaging/Views/ImageEditor/ImageEditorCropViewController.swift
+++ b/SignalMessaging/Views/ImageEditor/ImageEditorCropViewController.swift
@@ -588,18 +588,6 @@ class ImageEditorCropViewController: OWSViewController {
         }
     }
 
-    // MARK: - Coordinates
-
-    private func locationUnit(forGestureRecognizer gestureRecognizer: UIGestureRecognizer,
-                              transform: ImageEditorTransform) -> CGPoint {
-        return ImageEditorCanvasView.locationUnit(forGestureRecognizer: gestureRecognizer, view: clipView, transform: transform)
-    }
-
-    private func locationUnit(forLocationInView locationInView: CGPoint,
-                              transform: ImageEditorTransform) -> CGPoint {
-        return ImageEditorCanvasView.locationUnit(forLocationInView: locationInView, viewSize: clipView.bounds.size, transform: transform)
-    }
-
     // MARK: - Events
 
     @objc public func didTapBackButton() {
diff --git a/SignalMessaging/Views/ImageEditor/ImageEditorView.swift b/SignalMessaging/Views/ImageEditor/ImageEditorView.swift
index 2bf841fd0..187a55c3b 100644
--- a/SignalMessaging/Views/ImageEditor/ImageEditorView.swift
+++ b/SignalMessaging/Views/ImageEditor/ImageEditorView.swift
@@ -299,7 +299,7 @@ public class ImageEditorView: UIView {
         }
 
         let location = gestureRecognizer.location(in: canvasView.gestureReferenceView)
-        guard let textLayer = canvasView.textLayer(forLocation: location) else {
+        guard let textLayer = self.textLayer(forLocation: location) else {
             return
         }
 
@@ -326,7 +326,7 @@ public class ImageEditorView: UIView {
         switch gestureRecognizer.state {
         case .began:
             let pinchState = gestureRecognizer.pinchStateStart
-            guard let textLayer = canvasView.textLayer(forLocation: pinchState.centroid) else {
+            guard let textLayer = self.textLayer(forLocation: pinchState.centroid) else {
                 // The pinch needs to start centered on a text item.
                 return
             }
@@ -341,14 +341,20 @@ public class ImageEditorView: UIView {
                 return
             }
 
+            let view = self.canvasView.gestureReferenceView
+            let viewBounds = view.bounds
             let locationStart = gestureRecognizer.pinchStateStart.centroid
-            let locationUnitStart = locationUnit(forLocationInView: locationStart, transform: model.currentTransform())
             let locationNow = gestureRecognizer.pinchStateLast.centroid
-            let locationUnitNow = locationUnit(forLocationInView: locationNow, transform: model.currentTransform())
-
-            let unitLocationDelta = CGPointSubtract(locationUnitNow,
-                                                    locationUnitStart)
-            let unitCenter = CGPointClamp01(CGPointAdd(textItem.unitCenter, unitLocationDelta))
+            let gestureStartImageUnit = ImageEditorView.locationImageUnit(forLocationInView: locationStart,
+                                                                          viewBounds: viewBounds,
+                                                                          model: self.model,
+                                                                          transform: self.model.currentTransform())
+            let gestureNowImageUnit = ImageEditorView.locationImageUnit(forLocationInView: locationNow,
+                                                                        viewBounds: viewBounds,
+                                                                        model: self.model,
+                                                                        transform: self.model.currentTransform())
+            let gestureDeltaImageUnit = gestureNowImageUnit.minus(gestureStartImageUnit)
+            let unitCenter = CGPointClamp01(textItem.unitCenter.plus(gestureDeltaImageUnit))
 
             // NOTE: We use max(1, ...) to avoid divide-by-zero.
             let newScaling = CGFloatClamp(textItem.scaling * gestureRecognizer.pinchStateLast.distance / max(1.0, gestureRecognizer.pinchStateStart.distance),
@@ -383,6 +389,13 @@ public class ImageEditorView: UIView {
     private var movingTextStartUnitCenter: CGPoint?
     private var movingTextHasMoved = false
 
+    private func textLayer(forLocation locationInView: CGPoint) -> EditorTextLayer? {
+        let viewBounds = self.canvasView.gestureReferenceView.bounds
+        let affineTransform = self.model.currentTransform().affineTransform(viewSize: viewBounds.size)
+        let locationInCanvas = locationInView.minus(viewBounds.center).applyingInverse(affineTransform).plus(viewBounds.center)
+        return canvasView.textLayer(forLocation: locationInCanvas)
+    }
+
     @objc
     public func handleMoveTextGesture(_ gestureRecognizer: ImageEditorPanGestureRecognizer) {
         AssertIsOnMainThread()
@@ -395,7 +408,7 @@ public class ImageEditorView: UIView {
                 owsFailDebug("Missing locationStart.")
                 return
             }
-            guard let textLayer = canvasView.textLayer(forLocation: locationStart) else {
+            guard let textLayer = self.textLayer(forLocation: locationStart) else {
                 owsFailDebug("No text layer")
                 return
             }
@@ -420,12 +433,19 @@ public class ImageEditorView: UIView {
                 return
             }
 
-            let locationUnitStart = canvasView.locationUnit(forLocationInView: locationStart, transform: model.currentTransform())
-            let locationNow = gestureRecognizer.location(in: canvasView.gestureReferenceView)
-            let locationUnitNow = canvasView.locationUnit(forLocationInView: locationNow, transform: model.currentTransform())
-
-            let unitLocationDelta = CGPointSubtract(locationUnitNow, locationUnitStart)
-            let unitCenter = CGPointClamp01(CGPointAdd(movingTextStartUnitCenter, unitLocationDelta))
+            let view = self.canvasView.gestureReferenceView
+            let viewBounds = view.bounds
+            let locationInView = gestureRecognizer.location(in: view)
+            let gestureStartImageUnit = ImageEditorView.locationImageUnit(forLocationInView: locationStart,
+                                                                          viewBounds: viewBounds,
+                                                                          model: self.model,
+                                                                          transform: self.model.currentTransform())
+            let gestureNowImageUnit = ImageEditorView.locationImageUnit(forLocationInView: locationInView,
+                                                                        viewBounds: viewBounds,
+                                                                        model: self.model,
+                                                                        transform: self.model.currentTransform())
+            let gestureDeltaImageUnit = gestureNowImageUnit.minus(gestureStartImageUnit)
+            let unitCenter = CGPointClamp01(movingTextStartUnitCenter.plus(gestureDeltaImageUnit))
             let newItem = textItem.copy(withUnitCenter: unitCenter)
 
             if movingTextHasMoved {
@@ -461,7 +481,14 @@ public class ImageEditorView: UIView {
             self.currentStrokeSamples.removeAll()
         }
         let tryToAppendStrokeSample = {
-            let newSample = self.locationUnit(forGestureRecognizer: gestureRecognizer, transform: self.model.currentTransform())
+            let view = self.canvasView.gestureReferenceView
+            let viewBounds = view.bounds
+            let locationInView = gestureRecognizer.location(in: view)
+            let newSample = ImageEditorView.locationImageUnit(forLocationInView: locationInView,
+                                                              viewBounds: viewBounds,
+                                                              model: self.model,
+                                                              transform: self.model.currentTransform())
+
             if let prevSample = self.currentStrokeSamples.last,
                 prevSample == newSample {
                 // Ignore duplicate samples.
@@ -511,14 +538,15 @@ public class ImageEditorView: UIView {
 
     // MARK: - Coordinates
 
-    private func locationUnit(forGestureRecognizer gestureRecognizer: UIGestureRecognizer,
-                              transform: ImageEditorTransform) -> CGPoint {
-        return canvasView.locationUnit(forGestureRecognizer: gestureRecognizer, transform: transform)
-    }
-
-    private func locationUnit(forLocationInView locationInView: CGPoint,
-                              transform: ImageEditorTransform) -> CGPoint {
-        return canvasView.locationUnit(forLocationInView: locationInView, transform: transform)
+    private class func locationImageUnit(forLocationInView locationInView: CGPoint,
+                                         viewBounds: CGRect,
+                                         model: ImageEditorModel,
+                                         transform: ImageEditorTransform) -> CGPoint {
+        let imageFrame = ImageEditorCanvasView.imageFrame(forViewSize: viewBounds.size, imageSize: model.srcImageSizePixels, transform: transform)
+        let affineTransformStart = transform.affineTransform(viewSize: viewBounds.size)
+        let locationInContent = locationInView.minus(viewBounds.center).applyingInverse(affineTransformStart).plus(viewBounds.center)
+        let locationImageUnit = locationInContent.toUnitCoordinates(viewBounds: imageFrame, shouldClamp: false)
+        return locationImageUnit
     }
 
     // MARK: - Edit Text Tool
@@ -586,7 +614,7 @@ extension ImageEditorView: UIGestureRecognizerDelegate {
         }
 
         let location = touch.location(in: canvasView.gestureReferenceView)
-        let isInTextArea = canvasView.textLayer(forLocation: location) != nil
+        let isInTextArea = self.textLayer(forLocation: location) != nil
         return isInTextArea
     }
 }