Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/*
* Copyright 2026 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/

package org.signal.imageeditor.core;

import android.graphics.Matrix;
Expand All @@ -9,13 +14,16 @@

final class ElementScaleEditSession extends ElementEditSession {

private ElementScaleEditSession(@NonNull EditorElement selected, @NonNull Matrix inverseMatrix) {
private final float initialRotationRadians;

private ElementScaleEditSession(@NonNull EditorElement selected, @NonNull Matrix inverseMatrix, float initialRotationRadians) {
super(selected, inverseMatrix);
this.initialRotationRadians = initialRotationRadians;
}

static ElementScaleEditSession startScale(@NonNull ElementDragEditSession session, @NonNull Matrix inverseMatrix, @NonNull PointF point, int p) {
session.commit();
ElementScaleEditSession newSession = new ElementScaleEditSession(session.selected, inverseMatrix);
ElementScaleEditSession newSession = new ElementScaleEditSession(session.selected, inverseMatrix, session.selected.getLocalRotationAngle());
newSession.setScreenStartPoint(1 - p, session.endPointScreen[0]);
newSession.setScreenEndPoint(1 - p, session.endPointScreen[0]);
newSession.setScreenStartPoint(p, point);
Expand All @@ -38,6 +46,7 @@ public void movePoint(int p, @NonNull PointF point) {
editorMatrix.postScale(scale, scale);

double angle = angle(endPointElement[0], endPointElement[1]) - angle(startPointElement[0], startPointElement[1]);
angle = RotationSnap.snapToAngle(initialRotationRadians, angle);

if (!selected.getFlags().isRotateLocked()) {
editorMatrix.postRotate((float) Math.toDegrees(angle));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* Copyright 2026 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/

package org.signal.imageeditor.core;

final class RotationSnap {

private static final double SNAP_ANGLE_RADIANS = Math.PI / 2d; // 90 degrees in radians
private static final double SNAP_THRESHOLD_RADIANS = Math.toRadians(5d);

private RotationSnap() {}

private static double snapToAngle(double angleRadians) {
double snappedAngle = Math.rint(angleRadians / SNAP_ANGLE_RADIANS) * SNAP_ANGLE_RADIANS;

if (Math.abs(angleRadians - snappedAngle) <= SNAP_THRESHOLD_RADIANS) {
return snappedAngle;
}

return angleRadians;
}

static double snapToAngle(double baseAngleRadians, double relativeAngleRadians) {
double absoluteAngle = baseAngleRadians + relativeAngleRadians;
double snappedAbsoluteAngle = snapToAngle(absoluteAngle);
return snappedAbsoluteAngle - baseAngleRadians;
}
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
/*
* Copyright 2026 Signal Messenger, LLC
* SPDX-License-Identifier: AGPL-3.0-only
*/

package org.signal.imageeditor.core;

import android.graphics.Matrix;
Expand All @@ -13,6 +18,7 @@ class ThumbDragEditSession extends ElementEditSession {
private final PointF oppositeControlPoint = new PointF();
private final float[] oppositeControlPointOnControlParent = new float[2];
private final float[] oppositeControlPointOnElement = new float[2];
private final float initialRotationRadians;

@NonNull
private final ThumbRenderer.ControlPoint controlPoint;
Expand All @@ -21,11 +27,13 @@ class ThumbDragEditSession extends ElementEditSession {
private ThumbDragEditSession(@NonNull EditorElement selected,
@NonNull ThumbRenderer.ControlPoint controlPoint,
@NonNull Matrix inverseMatrix,
@NonNull Matrix thumbContainerRelativeMatrix)
@NonNull Matrix thumbContainerRelativeMatrix,
float initialRotationRadians)
{
super(selected, inverseMatrix);
this.controlPoint = controlPoint;
this.thumbContainerRelativeMatrix = thumbContainerRelativeMatrix;
this.initialRotationRadians = initialRotationRadians;
}

static EditSession startDrag(@NonNull EditorElement selected,
Expand All @@ -36,7 +44,7 @@ static EditSession startDrag(@NonNull EditorElement selected,
{
if (!selected.getFlags().isEditable()) return null;

ElementEditSession elementDragEditSession = new ThumbDragEditSession(selected, controlPoint, inverseViewModelMatrix, thumbContainerRelativeMatrix);
ElementEditSession elementDragEditSession = new ThumbDragEditSession(selected, controlPoint, inverseViewModelMatrix, thumbContainerRelativeMatrix, selected.getLocalRotationAngle());
elementDragEditSession.setScreenStartPoint(0, point);
elementDragEditSession.setScreenEndPoint(0, point);
return elementDragEditSession;
Expand Down Expand Up @@ -72,6 +80,7 @@ public void movePoint(int p, @NonNull PointF point) {
editorMatrix.postTranslate(-oppositeControlPoint.x, -oppositeControlPoint.y);
editorMatrix.postScale(scale, scale);
double angle = angle(endPointElement[0], oppositeControlPoint) - angle(startPointElement[0], oppositeControlPoint);
angle = RotationSnap.snapToAngle(initialRotationRadians, angle);
rotate(editorMatrix, angle);
editorMatrix.postTranslate(oppositeControlPoint.x, oppositeControlPoint.y);
} else {
Expand Down Expand Up @@ -142,4 +151,4 @@ private static float getDistanceSquared(@NonNull PointF a, @NonNull PointF b) {
float dy = a.y - b.y;
return dx * dx + dy * dy;
}
}
}