Bug 157681 - Text selection is basically impossible on plain text pages
Summary: Text selection is basically impossible on plain text pages
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: WebKit2 (show other bugs)
Version: WebKit Nightly Build
Hardware: Unspecified iOS 9.3
: P2 Normal
Assignee: Enrica Casucci
URL:
Keywords: InRadar
Depends on: 158155 158284
Blocks:
  Show dependency treegraph
 
Reported: 2016-05-13 12:33 PDT by Enrica Casucci
Modified: 2016-06-08 15:47 PDT (History)
4 users (show)

See Also:


Attachments
Patch (4.27 KB, patch)
2016-05-13 12:41 PDT, Enrica Casucci
darin: review+
Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Enrica Casucci 2016-05-13 12:33:25 PDT
Navigate to http://ohhla.com/anonymous/mf_doom/madvill/moneyfld.mfd.txt and try to select text.
It is impossible.

rdar://problem/26065660
Comment 1 Enrica Casucci 2016-05-13 12:41:13 PDT
Created attachment 278862 [details]
Patch
Comment 2 Darin Adler 2016-05-14 10:35:24 PDT
Comment on attachment 278862 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=278862&action=review

> Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm:1662
> +    if (!m_blockRectForTextSelection.height())
> +        return false;

What about very small heights?

> Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm:1864
> +static bool rectIsTooBigForSelection(const IntRect& blockRect, const Frame& frame)

Consider inline maybe?

> Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm:1866
> +    const static CGFloat factor = 0.97;

I know this code was just moved, but:

Why does this need to be a CGFloat? Why not just a float or a double? Doesn’t seem like CG is involved here.

Also, const static is not better than const.

> Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm:1867
> +    return blockRect.height() > (frame.view()->unobscuredContentRect().height() * factor);

I know this code was just moved, but:

What guarantees view() is non-null?

No need for the parentheses in this expression.

> Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm:1880
> +        if (renderer->style().preserveNewline())
> +            m_blockRectForTextSelection = renderer->absoluteBoundingBoxRect(true);

This seems not exactly right to me. Why is the only relevant flag “preserveNewline”? What about all the other related properties, like breakOnlyAfterWhiteSpace and auto wrap, etc.

> Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm:1882
> +            RefPtr<Range> paragraphRange = enclosingTextUnitOfGranularity(visiblePositionInFocusedNodeForPoint(frame, point, isInteractingWithAssistedNode), ParagraphGranularity, DirectionForward);

I know this code was just moved, but:

I suggest auto rather than writing out the type RefPtr<Range>.

> Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm:2409
> +                info.isSelectable = renderer->style().userSelect() != SELECT_NONE;
> +                if (info.isSelectable && !hitNode->isTextNode())
> +                    info.isSelectable = !rectIsTooBigForSelection(info.bounds, *result.innerNodeFrame());

This whole thing could use just &&:

    info.isSelectable = renderer->style().userSelect() != SELECT_NONE
        && !hitNode->isTextNode()
        && !rectIsTooBigForSelection(info.bounds, *result.innerNodeFrame());
Comment 3 Darin Adler 2016-05-14 10:35:47 PDT
I would like to see test coverage for this. It doesn’t just affect plain text, so it can be HTML tests.
Comment 4 Enrica Casucci 2016-05-16 14:52:00 PDT
Thanks for the review.
I'll address your comments. See my replies below to a your questions.
(In reply to comment #2)
> Comment on attachment 278862 [details]
> Patch
> 
> View in context:
> https://bugs.webkit.org/attachment.cgi?id=278862&action=review
> 
> > Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm:1662
> > +    if (!m_blockRectForTextSelection.height())
> > +        return false;
> 
> What about very small heights?
I tried to follow the original WK1 code that did not discard very small blocks.
A height of 0 is explicitly set when we want to exclude the possibility of block selection.

> I know this code was just moved, but:
> 
> What guarantees view() is non-null?

I thought that having a WebPage is a guarantee that the view is not null. Nowhere else in this file where a view is referenced we check for null.
Comment 5 Enrica Casucci 2016-05-16 15:06:57 PDT
(In reply to comment #2)
> This seems not exactly right to me. Why is the only relevant flag
> “preserveNewline”? What about all the other related properties, like
> breakOnlyAfterWhiteSpace and auto wrap, etc.
> 
I forgot to answer one of your questions.
I believe this is the only relevant one. What we care about is properties that play a role when computing start and end of paragraph.
Comment 6 Enrica Casucci 2016-05-16 15:13:48 PDT
> This whole thing could use just &&:
> 
>     info.isSelectable = renderer->style().userSelect() != SELECT_NONE
>         && !hitNode->isTextNode()
>         && !rectIsTooBigForSelection(info.bounds, *result.innerNodeFrame());

Maybe I'm wrong, but I don't think this is equivalent.
Written this way, if hitNode is a text node then isSelectable is false, which is not what we want.
We want to allow selection on text nodes if they are selectable. We want to limit the size of selections on non text nodes.
Comment 7 Enrica Casucci 2016-05-16 15:19:32 PDT
Committed revision 200972.
Comment 8 Chris Dumez 2016-05-27 10:08:39 PDT
Comment on attachment 278862 [details]
Patch

View in context: https://bugs.webkit.org/attachment.cgi?id=278862&action=review

>> Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm:1882
>> +            RefPtr<Range> paragraphRange = enclosingTextUnitOfGranularity(visiblePositionInFocusedNodeForPoint(frame, point, isInteractingWithAssistedNode), ParagraphGranularity, DirectionForward);
> 
> I know this code was just moved, but:
> 
> I suggest auto rather than writing out the type RefPtr<Range>.

The patch that landed used:
auto* paragraphRange = enclosingTextUnitOfGranularity(visiblePositionInFocusedNodeForPoint(frame, point, isInteractingWithAssistedNode), ParagraphGranularity, DirectionForward).get();

This is unsafe because enclosingTextUnitOfGranularity() returns a RefPtr and transfers ownership of the range to the caller. This was causing crashes that Zalan is fixing via Bug 158155.
Comment 9 Darin Adler 2016-05-27 11:18:05 PDT
Darn. I was suggesting "auto", not "auto*".