Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make ASTextNode2 more forgiving when searching for links #1374

Merged
merged 3 commits into from
Mar 7, 2019
Merged
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
46 changes: 31 additions & 15 deletions Source/ASTextNode2.mm
Original file line number Diff line number Diff line change
Expand Up @@ -601,25 +601,41 @@ - (id)_linkAttributeValueAtPoint:(CGPoint)point

NSRange visibleRange = layout.visibleRange;
NSRange clampedRange = NSIntersectionRange(visibleRange, NSMakeRange(0, _attributedText.length));
ASTextRange *range = [layout closestTextRangeAtPoint:point];
NSRange effectiveRange = NSMakeRange(0, 0);
for (__strong NSString *attributeName in self.linkAttributeNames) {
id value = [self.attributedText attribute:attributeName atIndex:range.start.offset longestEffectiveRange:&effectiveRange inRange:clampedRange];
if (value == nil) {
// Didn't find any links specified with this attribute.

// Search the 9 points of a 44x44 square around the touch until we find a link.
// Start from center, then do sides, then do top/bottom, then do corners.
static constexpr CGSize kRectOffsets[9] = {
{ 0, 0 },
{ -22, 0 }, { 22, 0 },
{ 0, -22 }, { 0, 22 },
{ -22, -22 }, { -22, 22 },
{ 22, -22 }, { 22, 22 }
};

for (const CGSize &offset : kRectOffsets) {
const CGPoint testPoint = CGPointMake(point.x + offset.width,
point.y + offset.height);
ASTextPosition *pos = [layout closestPositionToPoint:testPoint];
if (!pos || !NSLocationInRange(pos.offset, clampedRange)) {
continue;
}
for (NSString *attributeName in _linkAttributeNames) {
NSRange effectiveRange = NSMakeRange(0, 0);
id value = [_attributedText attribute:attributeName atIndex:pos.offset
longestEffectiveRange:&effectiveRange inRange:clampedRange];
if (value == nil) {
// Didn't find any links specified with this attribute.
continue;
}

// If highlighting, check with delegate first. If not implemented, assume YES.
id<ASTextNodeDelegate> delegate = self.delegate;
if (highlighting
&& [delegate respondsToSelector:@selector(textNode:shouldHighlightLinkAttribute:value:atPoint:)]
&& ![delegate textNode:(ASTextNode *)self shouldHighlightLinkAttribute:attributeName value:value atPoint:point]) {
value = nil;
attributeName = nil;
}
// If highlighting, check with delegate first. If not implemented, assume YES.
if (highlighting
&& [_delegate respondsToSelector:@selector(textNode:shouldHighlightLinkAttribute:value:atPoint:)]
&& ![_delegate textNode:(ASTextNode *)self shouldHighlightLinkAttribute:attributeName
value:value atPoint:point]) {
continue;
}

if (value != nil || attributeName != nil) {
*rangeOut = NSIntersectionRange(visibleRange, effectiveRange);

if (attributeNameOut != NULL) {
Expand Down