Bug 142536

Summary: [WK2][iOS] editorState() should not cause a synchronous layout
Product: WebKit Reporter: Chris Dumez <cdumez>
Component: HTML EditingAssignee: Chris Dumez <cdumez>
Status: RESOLVED FIXED    
Severity: Normal CC: ap, barraclough, clopez, commit-queue, enrica, rniwa
Priority: P2 Keywords: InRadar
Version: 528+ (Nightly build)   
Hardware: iPhone / iPad   
OS: Unspecified   
Bug Depends on: 143591, 143715    
Bug Blocks:    
Attachments:
Description Flags
WIP Patch
none
WIP patch
none
Patch
none
Patch
none
Patch
none
Patch none

Description Chris Dumez 2015-03-10 10:48:54 PDT
editorState() should not cause a synchronous layout on iOS.

Radar: <rdar://problem/20041506>
Comment 1 Chris Dumez 2015-03-10 10:50:25 PDT
Created attachment 248335 [details]
WIP Patch
Comment 2 Chris Dumez 2015-03-10 11:38:03 PDT
Created attachment 248340 [details]
WIP patch
Comment 3 Chris Dumez 2015-03-10 12:00:08 PDT
Created attachment 248342 [details]
Patch
Comment 4 Enrica Casucci 2015-03-10 15:56:25 PDT
Comment on attachment 248342 [details]
Patch

The patch looks good to me. I would add ASSERTS in WKContentViewInteraction.mm in all the places where we try to use components of editor state that require layout when we only have the partial editor state.
Comment 5 Chris Dumez 2015-03-10 17:27:42 PDT
Created attachment 248373 [details]
Patch
Comment 6 Chris Dumez 2015-03-10 17:28:38 PDT
(In reply to comment #4)
> Comment on attachment 248342 [details]
> Patch
> 
> The patch looks good to me. I would add ASSERTS in
> WKContentViewInteraction.mm in all the places where we try to use components
> of editor state that require layout when we only have the partial editor
> state.

Good idea. I made the change but I still need to verify on device that the assertion is not hit before we can land.
Comment 7 WebKit Commit Bot 2015-03-10 17:30:39 PDT
Attachment 248373 [details] did not pass style-queue:


ERROR: Source/WebKit2/Shared/EditorState.h:105:  This { should be at the end of the previous line  [whitespace/braces] [4]
Total errors found: 1 in 20 files


If any of these errors are false positives, please file a bug against check-webkit-style.
Comment 8 Chris Dumez 2015-03-10 21:25:53 PDT
Created attachment 248394 [details]
Patch
Comment 9 WebKit Commit Bot 2015-03-10 21:27:24 PDT
Attachment 248394 [details] did not pass style-queue:


ERROR: Source/WebKit2/Shared/EditorState.h:105:  This { should be at the end of the previous line  [whitespace/braces] [4]
Total errors found: 1 in 20 files


If any of these errors are false positives, please file a bug against check-webkit-style.
Comment 10 Chris Dumez 2015-03-10 21:35:57 PDT
I am unfortunately hitting the new assertion, so this will need a bit more work.

When WebPageProxy::didCommitLayerTree() is called, we end up calling [WKContentView(WKInteraction) _updateChangedSelection:]. In there, we construct a WKSelectionDrawingInfo object from the EditorState which accesses the PostLayoutData (caretRectAtEnd and selectionRects). Apparently, this is called before the WebProcess has had time to send the full EditorState (with PostLayoutData) to the UIProcess.
Comment 11 Chris Dumez 2015-03-10 21:55:40 PDT
(In reply to comment #10)
> I am unfortunately hitting the new assertion, so this will need a bit more
> work.
> 
> When WebPageProxy::didCommitLayerTree() is called, we end up calling
> [WKContentView(WKInteraction) _updateChangedSelection:]. In there, we
> construct a WKSelectionDrawingInfo object from the EditorState which
> accesses the PostLayoutData (caretRectAtEnd and selectionRects). Apparently,
> this is called before the WebProcess has had time to send the full
> EditorState (with PostLayoutData) to the UIProcess.

This is not the only case where we try to access the EditorState's PostLayoutData before layout is done:
2   WebKit                              0x000000010323417c -[WKContentView(WKInteraction) selectedTextRange] + 460
3   UIKit                               0x0000000187050b0c -[UITextSelection selectionChanged] + 36
4   UIKit                               0x0000000187115d10 -[UITextSelectionView activate] + 204
5   WebKit                              0x000000010322eb34 -[WKContentView(WKInteraction) becomeFirstResponder] + 84
Comment 12 Chris Dumez 2015-04-08 20:20:42 PDT
Created attachment 250404 [details]
Patch
Comment 13 WebKit Commit Bot 2015-04-08 20:22:17 PDT
Attachment 250404 [details] did not pass style-queue:


ERROR: Source/WebKit2/Shared/EditorState.h:105:  This { should be at the end of the previous line  [whitespace/braces] [4]
Total errors found: 1 in 21 files


If any of these errors are false positives, please file a bug against check-webkit-style.
Comment 14 Chris Dumez 2015-04-08 20:28:47 PDT
Comment on attachment 250404 [details]
Patch

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

I highlighted the few changes compared to the previous iteration to facilitate review.

> Source/WebKit2/Shared/EditorState.h:100
> +    ASSERT_WITH_MESSAGE(!isMissingPostLayoutData, "Attempt to access post layout data before receiving it");

Added assertion as suggested to make sure we don't try to access the postLayoutData of a partial editor state.

> Source/WebKit2/Shared/EditorState.h:106
> +    ASSERT_WITH_MESSAGE(!isMissingPostLayoutData, "Attempt to access post layout data before receiving it");

Added assertion as suggested to make sure we don't try to access the postLayoutData of a partial editor state.

> Source/WebKit2/UIProcess/ios/WKContentView.mm:496
> +    if (!_page->editorState().isMissingPostLayoutData)

I added this check otherwise we would sometimes try to access the postLayoutData even though we have a partial EditorState, thus hitting the new assertions above. This can happen when a new layout a scheduled and the selection is changed after the previous layout is done but *before* didCommitLayerTree() is called. We flush the layers and send the didCommitLayerTree IPC in a background thread so nothing prevents a new layout to be scheduled and thus a partial EditorState to be sent before the didCommitLayerTree message is received.

> Source/WebKit2/WebProcess/WebPage/WebPage.cpp:4379
> +    auto editorState = this->editorState(needsLayout ? IncludePostLayoutDataHint::No : IncludePostLayoutDataHint::Yes);

We now only send a partial editor state if there is a layout pending as this is the only case where calling editorState() would trigger a synchronous layout.

> Source/WebKit2/WebProcess/WebPage/WebPage.cpp:4380
> +    ASSERT_WITH_MESSAGE(needsLayout == (view && view->needsLayout()), "Calling editorState() should not cause a synchronous layout.");

I added this assertion to make sure that calling editorState() does not cause a synchronous layout. This could happen if someone added a new field to the EditorState which requires a layout to be computed and forget to add it to the PostLayoutData part.
Comment 15 Enrica Casucci 2015-04-09 10:43:45 PDT
Comment on attachment 250404 [details]
Patch

Looks good to me.
Comment 16 WebKit Commit Bot 2015-04-09 11:32:53 PDT
Comment on attachment 250404 [details]
Patch

Clearing flags on attachment: 250404

Committed r182603: <http://trac.webkit.org/changeset/182603>
Comment 17 WebKit Commit Bot 2015-04-09 11:33:00 PDT
All reviewed patches have been landed.  Closing bug.
Comment 19 Chris Dumez 2015-04-09 17:18:00 PDT
(In reply to comment #18)
> This broke a test on multiple bots:
> <https://webkit-test-results.appspot.com/dashboards/flakiness_dashboard.
> html#showAllRuns=true&tests=editing%2Fselection%2Fselection-invalid-offset.
> html>

Fix is pending review in https://bugs.webkit.org/show_bug.cgi?id=143591.
I missed a null-check on the EditorClient.
Comment 20 Carlos Alberto Lopez Perez 2015-04-14 09:20:34 PDT
(In reply to comment #16)
> Comment on attachment 250404 [details]
> Patch
> 
> Clearing flags on attachment: 250404
> 
> Committed r182603: <http://trac.webkit.org/changeset/182603>

This caused more than 500 crashes on the GTK Debug build. Reported here https://bugs.webkit.org/show_bug.cgi?id=143715