Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 02b34572 authored by Petar Šegina's avatar Petar Šegina Committed by Android (Google) Code Review
Browse files

Merge "Filter out empty and unnecessary rectangles"

parents 2b219baf ba1b8566
Loading
Loading
Loading
Loading
+58 −7
Original line number Diff line number Diff line
@@ -56,7 +56,7 @@ import java.util.function.Supplier;
 */
@UiThread
@VisibleForTesting(visibility = VisibleForTesting.Visibility.PACKAGE)
final class SelectionActionModeHelper {
public final class SelectionActionModeHelper {

    /**
     * Maximum time (in milliseconds) to wait for a result before timing out.
@@ -262,17 +262,66 @@ final class SelectionActionModeHelper {
    private List<RectF> convertSelectionToRectangles(final Layout layout, final int start,
            final int end) {
        final List<RectF> result = new ArrayList<>();
        // TODO filter out invalid rectangles
        // getSelection might give us overlapping and zero-dimension rectangles which will interfere
        // with the Smart Select animation
        layout.getSelection(start, end, (left, top, right, bottom, textSelectionLayout) ->
                result.add(new RectF(left, top, right, bottom)));
                mergeRectangleIntoList(result, new RectF(left, top, right, bottom)));

        result.sort(SmartSelectSprite.RECTANGLE_COMPARATOR);

        return result;
    }

    /**
     * Merges a {@link RectF} into an existing list of rectangles. While merging, this method
     * makes sure that:
     *
     * <ol>
     * <li>No rectangle is redundant (contained within a bigger rectangle)</li>
     * <li>Rectangles of the same height and vertical position that intersect get merged</li>
     * </ol>
     *
     * @param list      the list of rectangles to merge the new rectangle in
     * @param candidate the {@link RectF} to merge into the list
     * @hide
     */
    @VisibleForTesting
    public static void mergeRectangleIntoList(List<RectF> list, RectF candidate) {
        if (candidate.isEmpty()) {
            return;
        }

        final int elementCount = list.size();
        for (int index = 0; index < elementCount; ++index) {
            final RectF existingRectangle = list.get(index);
            if (existingRectangle.contains(candidate)) {
                return;
            }
            if (candidate.contains(existingRectangle)) {
                existingRectangle.setEmpty();
                continue;
            }

            final boolean rectanglesContinueEachOther = candidate.left == existingRectangle.right
                    || candidate.right == existingRectangle.left;
            final boolean canMerge = candidate.top == existingRectangle.top
                    && candidate.bottom == existingRectangle.bottom
                    && (RectF.intersects(candidate, existingRectangle)
                    || rectanglesContinueEachOther);

            if (canMerge) {
                candidate.union(existingRectangle);
                existingRectangle.setEmpty();
            }
        }

        for (int index = elementCount - 1; index >= 0; --index) {
            if (list.get(index).isEmpty()) {
                list.remove(index);
            }
        }

        list.add(candidate);
    }


    /** @hide */
    @VisibleForTesting
    public static PointF movePointInsideNearestRectangle(final PointF point,
@@ -281,7 +330,9 @@ final class SelectionActionModeHelper {
        float bestY = -1;
        double bestDistance = Double.MAX_VALUE;

        for (final RectF rectangle : rectangles) {
        final int elementCount = rectangles.size();
        for (int index = 0; index < elementCount; ++index) {
            final RectF rectangle = rectangles.get(index);
            final float candidateY = rectangle.centerY();
            final float candidateX;

+151 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@@ -110,4 +111,154 @@ public final class SelectionActionModeHelperTest {
        assertEquals(expectedPointY, adjustedPoint.y, 0.0f);
    }

    @Test
    public void testMergeRectangleIntoList_addThreeDisjointRectangles() {
        testExpandRectangleList(
                new RectF[] {
                        new RectF(0, 0, 1, 1),
                        new RectF(10, 10, 11, 11),
                        new RectF(20, 20, 21, 21)
                },
                new RectF[] {
                        new RectF(0, 0, 1, 1),
                        new RectF(10, 10, 11, 11),
                        new RectF(20, 20, 21, 21)
                }
        );
    }

    @Test
    public void testMergeRectangleIntoList_addAnEmptyRectangle() {
        testExpandRectangleList(
                new RectF[] {
                        new RectF(0, 0, 0, 0)
                },
                new RectF[] {
                }
        );
    }

    @Test
    public void testMergeRectangleIntoList_addAContainedRectangle() {
        testExpandRectangleList(
                new RectF[] {
                        new RectF(0, 0, 10, 10),
                        new RectF(9, 0, 10, 10)
                },
                new RectF[] {
                        new RectF(0, 0, 10, 10)
                }
        );
    }

    @Test
    public void testMergeRectangleIntoList_addARectangleThatContainsExistingRectangles() {
        testExpandRectangleList(
                new RectF[] {
                        new RectF(0, 0, 1, 1),
                        new RectF(1, 0, 2, 1),
                        new RectF(0, 0, 2, 1)
                },
                new RectF[] {
                        new RectF(0, 0, 2, 1)
                }
        );
    }

    @Test
    public void testMergeRectangleIntoList_addRectangleThatIntersectsAndHasTheSameHeightOnRight() {
        testExpandRectangleList(
                new RectF[] {
                        new RectF(0, 0, 1, 1),
                        new RectF(0.5f, 0, 1.5f, 1)
                },
                new RectF[] {
                        new RectF(0, 0, 1.5f, 1)
                }
        );
    }

    @Test
    public void testMergeRectangleIntoList_addRectangleThatIntersectsAndHasTheSameHeightOnLeft() {
        testExpandRectangleList(
                new RectF[] {
                        new RectF(0.5f, 0, 1.5f, 1),
                        new RectF(0, 0, 1, 1)
                },
                new RectF[] {
                        new RectF(0, 0, 1.5f, 1)
                }
        );
    }

    @Test
    public void testMergeRectangleIntoList_addRectangleThatExpandsToTheRight() {
        testExpandRectangleList(
                new RectF[] {
                        new RectF(0, 0, 1, 1),
                        new RectF(1, 0, 1.5f, 1)
                },
                new RectF[] {
                        new RectF(0, 0, 1.5f, 1)
                }
        );
    }

    @Test
    public void testMergeRectangleIntoList_addRectangleThatExpandsToTheLeft() {
        testExpandRectangleList(
                new RectF[] {
                        new RectF(1, 0, 1.5f, 1),
                        new RectF(0, 0, 1, 1)
                },
                new RectF[] {
                        new RectF(0, 0, 1.5f, 1)
                }
        );
    }


    @Test
    public void testMergeRectangleIntoList_addRectangleMadeObsoleteByMultipleExistingRectangles() {
        testExpandRectangleList(
                new RectF[] {
                        new RectF(0, 0, 1, 1),
                        new RectF(0.5f, 0, 1.5f, 1),
                        new RectF(0.25f, 0, 1.25f, 1)
                },
                new RectF[] {
                        new RectF(0, 0, 1.5f, 1)
                }
        );
    }

    @Test
    public void testMergeRectangleIntoList_threeRectanglesThatTouchEachOther() {
        testExpandRectangleList(
                new RectF[] {
                        new RectF(0, 0, 1, 1),
                        new RectF(1, 0, 2, 1),
                        new RectF(2, 0, 3, 1)
                },
                new RectF[] {
                        new RectF(0, 0, 3, 1)
                }
        );
    }


    private void testExpandRectangleList(final RectF[] inputRectangles,
            final RectF[] outputRectangles) {
        final List<RectF> expectedOutput = Arrays.asList(outputRectangles);

        final List<RectF> result = new ArrayList<>();
        final int size = inputRectangles.length;
        for (int index = 0; index < size; ++index) {
            SelectionActionModeHelper.mergeRectangleIntoList(result, inputRectangles[index]);
        }

        assertEquals(expectedOutput, result);
    }


}