@@ -1543,7 +1543,7 @@ - (void)testUpdateFirstRectForRange {
15431543 [inputView firstRectForRange: range]));
15441544}
15451545
1546- - (void )testFirstRectForRangeReturnsCorrectSelectionRectOnASingleLineLeftToRight {
1546+ - (void )testFirstRectForRangeReturnsCorrectRectOnASingleLineLeftToRight {
15471547 FlutterTextInputView* inputView = [[FlutterTextInputView alloc ] initWithOwner: textInputPlugin];
15481548 [inputView setTextInputState: @{@" text" : @" COMPOSING" }];
15491549
@@ -1572,7 +1572,7 @@ - (void)testFirstRectForRangeReturnsCorrectSelectionRectOnASingleLineLeftToRight
15721572 XCTAssertTrue (CGRectEqualToRect (CGRectZero, [inputView firstRectForRange: rangeOutsideBounds]));
15731573}
15741574
1575- - (void )testFirstRectForRangeReturnsCorrectSelectionRectOnASingleLineRightToLeft {
1575+ - (void )testFirstRectForRangeReturnsCorrectRectOnASingleLineRightToLeft {
15761576 FlutterTextInputView* inputView = [[FlutterTextInputView alloc ] initWithOwner: textInputPlugin];
15771577 [inputView setTextInputState: @{@" text" : @" COMPOSING" }];
15781578
@@ -1600,7 +1600,7 @@ - (void)testFirstRectForRangeReturnsCorrectSelectionRectOnASingleLineRightToLeft
16001600 XCTAssertTrue (CGRectEqualToRect (CGRectZero, [inputView firstRectForRange: rangeOutsideBounds]));
16011601}
16021602
1603- - (void )testFirstRectForRangeReturnsCorrectSelectionRectOnMultipleLinesLeftToRight {
1603+ - (void )testFirstRectForRangeReturnsCorrectRectOnMultipleLinesLeftToRight {
16041604 FlutterTextInputView* inputView = [[FlutterTextInputView alloc ] initWithOwner: textInputPlugin];
16051605 [inputView setTextInputState: @{@" text" : @" COMPOSING" }];
16061606
@@ -1629,7 +1629,7 @@ - (void)testFirstRectForRangeReturnsCorrectSelectionRectOnMultipleLinesLeftToRig
16291629 }
16301630}
16311631
1632- - (void )testFirstRectForRangeReturnsCorrectSelectionRectOnMultipleLinesRightToLeft {
1632+ - (void )testFirstRectForRangeReturnsCorrectRectOnMultipleLinesRightToLeft {
16331633 FlutterTextInputView* inputView = [[FlutterTextInputView alloc ] initWithOwner: textInputPlugin];
16341634 [inputView setTextInputState: @{@" text" : @" COMPOSING" }];
16351635
@@ -1657,6 +1657,150 @@ - (void)testFirstRectForRangeReturnsCorrectSelectionRectOnMultipleLinesRightToLe
16571657 }
16581658}
16591659
1660+ - (void )testFirstRectForRangeReturnsCorrectRectOnSingleLineWithVaryingMinYAndMaxYLeftToRight {
1661+ FlutterTextInputView* inputView = [[FlutterTextInputView alloc ] initWithOwner: textInputPlugin];
1662+ [inputView setTextInputState: @{@" text" : @" COMPOSING" }];
1663+
1664+ [inputView setSelectionRects: @[
1665+ [FlutterTextSelectionRect selectionRectWithRect: CGRectMake (0 , 0 , 100 , 100 ) position: 0U ],
1666+ [FlutterTextSelectionRect selectionRectWithRect: CGRectMake (100 , 10 , 100 , 80 )
1667+ position: 1U ], // shorter
1668+ [FlutterTextSelectionRect selectionRectWithRect: CGRectMake (200 , -10 , 100 , 120 )
1669+ position: 2U ], // taller
1670+ [FlutterTextSelectionRect selectionRectWithRect: CGRectMake (300 , 0 , 100 , 100 ) position: 3U ],
1671+ ]];
1672+
1673+ FlutterTextRange* multiRectRange = [FlutterTextRange rangeWithNSRange: NSMakeRange (1 , 3 )];
1674+
1675+ if (@available (iOS 17 , *)) {
1676+ XCTAssertTrue (CGRectEqualToRect (CGRectMake (100 , -10 , 300 , 120 ),
1677+ [inputView firstRectForRange: multiRectRange]));
1678+ } else {
1679+ XCTAssertTrue (CGRectEqualToRect (CGRectMake (100 , 10 , 100 , 80 ),
1680+ [inputView firstRectForRange: multiRectRange]));
1681+ }
1682+ }
1683+
1684+ - (void )testFirstRectForRangeReturnsCorrectRectOnSingleLineWithVaryingMinYAndMaxYRightToLeft {
1685+ FlutterTextInputView* inputView = [[FlutterTextInputView alloc ] initWithOwner: textInputPlugin];
1686+ [inputView setTextInputState: @{@" text" : @" COMPOSING" }];
1687+
1688+ [inputView setSelectionRects: @[
1689+ [FlutterTextSelectionRect selectionRectWithRect: CGRectMake (300 , 0 , 100 , 100 ) position: 0U ],
1690+ [FlutterTextSelectionRect selectionRectWithRect: CGRectMake (200 , -10 , 100 , 120 )
1691+ position: 1U ], // taller
1692+ [FlutterTextSelectionRect selectionRectWithRect: CGRectMake (100 , 10 , 100 , 80 )
1693+ position: 2U ], // shorter
1694+ [FlutterTextSelectionRect selectionRectWithRect: CGRectMake (0 , 0 , 100 , 100 ) position: 3U ],
1695+ ]];
1696+
1697+ FlutterTextRange* multiRectRange = [FlutterTextRange rangeWithNSRange: NSMakeRange (1 , 3 )];
1698+
1699+ if (@available (iOS 17 , *)) {
1700+ XCTAssertTrue (CGRectEqualToRect (CGRectMake (0 , -10 , 300 , 120 ),
1701+ [inputView firstRectForRange: multiRectRange]));
1702+ } else {
1703+ XCTAssertTrue (CGRectEqualToRect (CGRectMake (200 , -10 , 100 , 120 ),
1704+ [inputView firstRectForRange: multiRectRange]));
1705+ }
1706+ }
1707+
1708+ - (void )testFirstRectForRangeReturnsCorrectRectWithOverlappingRectsExceedingThresholdLeftToRight {
1709+ FlutterTextInputView* inputView = [[FlutterTextInputView alloc ] initWithOwner: textInputPlugin];
1710+ [inputView setTextInputState: @{@" text" : @" COMPOSING" }];
1711+
1712+ [inputView setSelectionRects: @[
1713+ [FlutterTextSelectionRect selectionRectWithRect: CGRectMake (0 , 0 , 100 , 100 ) position: 0U ],
1714+ [FlutterTextSelectionRect selectionRectWithRect: CGRectMake (100 , 0 , 100 , 100 ) position: 1U ],
1715+ [FlutterTextSelectionRect selectionRectWithRect: CGRectMake (200 , 0 , 100 , 100 ) position: 2U ],
1716+ [FlutterTextSelectionRect selectionRectWithRect: CGRectMake (300 , 0 , 100 , 100 ) position: 3U ],
1717+ // y=60 exceeds threshold, so treat it as a new line.
1718+ [FlutterTextSelectionRect selectionRectWithRect: CGRectMake (0 , 60 , 100 , 100 ) position: 4U ],
1719+ ]];
1720+
1721+ FlutterTextRange* multiRectRange = [FlutterTextRange rangeWithNSRange: NSMakeRange (1 , 4 )];
1722+
1723+ if (@available (iOS 17 , *)) {
1724+ XCTAssertTrue (CGRectEqualToRect (CGRectMake (100 , 0 , 300 , 100 ),
1725+ [inputView firstRectForRange: multiRectRange]));
1726+ } else {
1727+ XCTAssertTrue (CGRectEqualToRect (CGRectMake (100 , 0 , 100 , 100 ),
1728+ [inputView firstRectForRange: multiRectRange]));
1729+ }
1730+ }
1731+
1732+ - (void )testFirstRectForRangeReturnsCorrectRectWithOverlappingRectsExceedingThresholdRightToLeft {
1733+ FlutterTextInputView* inputView = [[FlutterTextInputView alloc ] initWithOwner: textInputPlugin];
1734+ [inputView setTextInputState: @{@" text" : @" COMPOSING" }];
1735+
1736+ [inputView setSelectionRects: @[
1737+ [FlutterTextSelectionRect selectionRectWithRect: CGRectMake (300 , 0 , 100 , 100 ) position: 0U ],
1738+ [FlutterTextSelectionRect selectionRectWithRect: CGRectMake (200 , 0 , 100 , 100 ) position: 1U ],
1739+ [FlutterTextSelectionRect selectionRectWithRect: CGRectMake (100 , 0 , 100 , 100 ) position: 2U ],
1740+ [FlutterTextSelectionRect selectionRectWithRect: CGRectMake (0 , 0 , 100 , 100 ) position: 3U ],
1741+ // y=60 exceeds threshold, so treat it as a new line.
1742+ [FlutterTextSelectionRect selectionRectWithRect: CGRectMake (300 , 60 , 100 , 100 ) position: 4U ],
1743+ ]];
1744+
1745+ FlutterTextRange* multiRectRange = [FlutterTextRange rangeWithNSRange: NSMakeRange (1 , 4 )];
1746+
1747+ if (@available (iOS 17 , *)) {
1748+ XCTAssertTrue (CGRectEqualToRect (CGRectMake (0 , 0 , 300 , 100 ),
1749+ [inputView firstRectForRange: multiRectRange]));
1750+ } else {
1751+ XCTAssertTrue (CGRectEqualToRect (CGRectMake (200 , 0 , 100 , 100 ),
1752+ [inputView firstRectForRange: multiRectRange]));
1753+ }
1754+ }
1755+
1756+ - (void )testFirstRectForRangeReturnsCorrectRectWithOverlappingRectsWithinThresholdLeftToRight {
1757+ FlutterTextInputView* inputView = [[FlutterTextInputView alloc ] initWithOwner: textInputPlugin];
1758+ [inputView setTextInputState: @{@" text" : @" COMPOSING" }];
1759+
1760+ [inputView setSelectionRects: @[
1761+ [FlutterTextSelectionRect selectionRectWithRect: CGRectMake (0 , 0 , 100 , 100 ) position: 0U ],
1762+ [FlutterTextSelectionRect selectionRectWithRect: CGRectMake (100 , 0 , 100 , 100 ) position: 1U ],
1763+ [FlutterTextSelectionRect selectionRectWithRect: CGRectMake (200 , 0 , 100 , 100 ) position: 2U ],
1764+ [FlutterTextSelectionRect selectionRectWithRect: CGRectMake (300 , 0 , 100 , 100 ) position: 3U ],
1765+ // y=40 is within line threshold, so treat it as the same line
1766+ [FlutterTextSelectionRect selectionRectWithRect: CGRectMake (400 , 40 , 100 , 100 ) position: 4U ],
1767+ ]];
1768+
1769+ FlutterTextRange* multiRectRange = [FlutterTextRange rangeWithNSRange: NSMakeRange (1 , 4 )];
1770+
1771+ if (@available (iOS 17 , *)) {
1772+ XCTAssertTrue (CGRectEqualToRect (CGRectMake (100 , 0 , 400 , 140 ),
1773+ [inputView firstRectForRange: multiRectRange]));
1774+ } else {
1775+ XCTAssertTrue (CGRectEqualToRect (CGRectMake (100 , 0 , 100 , 100 ),
1776+ [inputView firstRectForRange: multiRectRange]));
1777+ }
1778+ }
1779+
1780+ - (void )testFirstRectForRangeReturnsCorrectRectWithOverlappingRectsWithinThresholdRightToLeft {
1781+ FlutterTextInputView* inputView = [[FlutterTextInputView alloc ] initWithOwner: textInputPlugin];
1782+ [inputView setTextInputState: @{@" text" : @" COMPOSING" }];
1783+
1784+ [inputView setSelectionRects: @[
1785+ [FlutterTextSelectionRect selectionRectWithRect: CGRectMake (400 , 0 , 100 , 100 ) position: 0U ],
1786+ [FlutterTextSelectionRect selectionRectWithRect: CGRectMake (300 , 0 , 100 , 100 ) position: 1U ],
1787+ [FlutterTextSelectionRect selectionRectWithRect: CGRectMake (200 , 0 , 100 , 100 ) position: 2U ],
1788+ [FlutterTextSelectionRect selectionRectWithRect: CGRectMake (100 , 0 , 100 , 100 ) position: 3U ],
1789+ // y=40 is within line threshold, so treat it as the same line
1790+ [FlutterTextSelectionRect selectionRectWithRect: CGRectMake (0 , 40 , 100 , 100 ) position: 4U ],
1791+ ]];
1792+
1793+ FlutterTextRange* multiRectRange = [FlutterTextRange rangeWithNSRange: NSMakeRange (1 , 4 )];
1794+
1795+ if (@available (iOS 17 , *)) {
1796+ XCTAssertTrue (CGRectEqualToRect (CGRectMake (0 , 0 , 400 , 140 ),
1797+ [inputView firstRectForRange: multiRectRange]));
1798+ } else {
1799+ XCTAssertTrue (CGRectEqualToRect (CGRectMake (300 , 0 , 100 , 100 ),
1800+ [inputView firstRectForRange: multiRectRange]));
1801+ }
1802+ }
1803+
16601804- (void )testClosestPositionToPoint {
16611805 FlutterTextInputView* inputView = [[FlutterTextInputView alloc ] initWithOwner: textInputPlugin];
16621806 [inputView setTextInputState: @{@" text" : @" COMPOSING" }];
0 commit comments