RESOLVED FIXED 195178
Native text selection UI is incorrectly suppressed in Microsoft Visio
https://bugs.webkit.org/show_bug.cgi?id=195178
Summary Native text selection UI is incorrectly suppressed in Microsoft Visio
Wenson Hsieh
Reported 2019-02-28 11:53:04 PST
1. Install iOS 12. 2. Request desktop site and create a new diagram in Microsoft Visio online. 3. Create a new shape and try to edit text in that shape Expected: native text editing caret should appear, along with callout bar, etc. Observed: selection UI is suppressed.
Attachments
WIP (13.83 KB, patch)
2019-03-01 19:53 PST, Wenson Hsieh
no flags
Take two (13.56 KB, patch)
2019-03-04 09:12 PST, Wenson Hsieh
no flags
Radar WebKit Bug Importer
Comment 1 2019-03-01 12:48:14 PST
Wenson Hsieh
Comment 2 2019-03-01 19:53:38 PST
Tim Horton
Comment 3 2019-03-01 21:36:54 PST
I'm gonna leave this one for zalan/smfr
Darin Adler
Comment 4 2019-03-01 22:14:07 PST
Comment on attachment 363401 [details] WIP View in context: https://bugs.webkit.org/attachment.cgi?id=363401&action=review > Source/WebCore/rendering/RenderObject.cpp:1558 > + auto* container = &enclosingBox(); > + while (container) { Nicer to write as a for loop. If we can’t make the third clause work we can still write: for (auto* container = &enclosingBox(); container; ) { > Source/WebCore/rendering/RenderObject.cpp:1566 > + auto& frame = container->frame(); I think this logic about walking out to the enclosing frame's renderer should be put in a helper function. Writing it out as a sequence of if statements makes the thing look too complicated and it’s really a single concept. Not sure exactly which helper function to write. Here’s one: static RenderBox* enclosingFrameRenderBox(RenderBox& container) { auto* owner = container.frame().ownerElement(); if (!owner) return nullptr; auto* renderer = owner->renderer(); return is<RenderBox>(renderer) ? &downcast<RenderBox>(*renderer) : nullptr; } Then: static RenderBox* containingBlockCrossingFrameBoundaries(RenderBox& container) { auto* nextContainer = container.containingBlock(); if (!nextContainer) nextContainer = enclosingFrameRenderBox(container); return nextContainer ? nextContainer : enclosingFrameRenderBox(container); } Then: for (auto* container = &enclosingBox(); container; container = containingBlockCrossingFrameBoundaries(*container)) But I think there are other interesting factorings too that might allow sharing even more code with other call sites. > Source/WebCore/rendering/RenderObject.cpp:1572 > + if (frame.isMainFrame()) > + break; > + > + auto* owner = frame.ownerElement(); > + if (!owner) > + break; It’s unnecessary to check both isMainFrame and check ownerElement for null. I suggest skipping the isMainFrame check. > Source/WebCore/rendering/RenderObject.cpp:1576 > + if (!frameRenderer || !frameRenderer->isBox()) > + break; if (!is<RenderBox>(frameRenderer)) break;
Simon Fraser (smfr)
Comment 5 2019-03-02 13:34:25 PST
Comment on attachment 363401 [details] WIP View in context: https://bugs.webkit.org/attachment.cgi?id=363401&action=review > Source/WebCore/ChangeLog:9 > + Currently, our heuristics for detecting hidden editable areas attempts to search for empty parent renderers with heuristics...attempts -> heuristics...attempt > Source/WebCore/rendering/RenderObject.cpp:1563 > + bool isOverflowHidden = style.overflowX() == Overflow::Hidden || style.overflowY() == Overflow::Hidden; > + if (isOverflowHidden && !container->isDocumentElementRenderer() && !container->isBody() && container->contentSize().isEmpty()) > + return true; > + I think this code needs to be rewritten in terms of RenderLayer::clipRectRelativeToAncestor() or something similar. These are questions you ask of the RenderLayer rather than trying to compute yourself, which is fraught with danger.
Wenson Hsieh
Comment 6 2019-03-04 09:10:07 PST
Comment on attachment 363401 [details] WIP View in context: https://bugs.webkit.org/attachment.cgi?id=363401&action=review >> Source/WebCore/ChangeLog:9 >> + Currently, our heuristics for detecting hidden editable areas attempts to search for empty parent renderers with > > heuristics...attempts -> heuristics...attempt Good catch! >> Source/WebCore/rendering/RenderObject.cpp:1558 >> + while (container) { > > Nicer to write as a for loop. If we can’t make the third clause work we can still write: > > for (auto* container = &enclosingBox(); container; ) { Sounds good — I rewrote both this and the while loop above as for loops, using static helpers to advance each iteration. >> Source/WebCore/rendering/RenderObject.cpp:1563 >> + > > I think this code needs to be rewritten in terms of RenderLayer::clipRectRelativeToAncestor() or something similar. These are questions you ask of the RenderLayer rather than trying to compute yourself, which is fraught with danger. It wasn't clear how to make use of this; one approach that seems to work reasonably well is to check whether the enclosing layer's selfClipRect is empty, but this doesn't account for the scenario in which the enclosing layer's clippingRootForPainting() is itself (for instance, when a text field has "transform: translateZ(0);"). I was able to fix this by introducing a new helper on RenderLayer to the effect of hasEmptyClipRectRelativeToDocumentView() that computes the clip rect relative to the document view's layer instead of the clipping root for painting. But this affects no known sites and I'm not sure it's worth the additional code on RenderLayer, so I omitted it in the new patch (forthcoming). >> Source/WebCore/rendering/RenderObject.cpp:1566 >> + auto& frame = container->frame(); > > I think this logic about walking out to the enclosing frame's renderer should be put in a helper function. Writing it out as a sequence of if statements makes the thing look too complicated and it’s really a single concept. Not sure exactly which helper function to write. Here’s one: > > static RenderBox* enclosingFrameRenderBox(RenderBox& container) > { > auto* owner = container.frame().ownerElement(); > if (!owner) > return nullptr; > auto* renderer = owner->renderer(); > return is<RenderBox>(renderer) ? &downcast<RenderBox>(*renderer) : nullptr; > } > > Then: > > static RenderBox* containingBlockCrossingFrameBoundaries(RenderBox& container) > { > auto* nextContainer = container.containingBlock(); > if (!nextContainer) > nextContainer = enclosingFrameRenderBox(container); > return nextContainer ? nextContainer : enclosingFrameRenderBox(container); > } > > Then: > > for (auto* container = &enclosingBox(); container; container = containingBlockCrossingFrameBoundaries(*container)) > > But I think there are other interesting factorings too that might allow sharing even more code with other call sites. Ok! I pulled out some common logic into static helpers, and used these to rewrite the two while loops here as for loops. >> Source/WebCore/rendering/RenderObject.cpp:1572 >> + break; > > It’s unnecessary to check both isMainFrame and check ownerElement for null. I suggest skipping the isMainFrame check. Fixed! >> Source/WebCore/rendering/RenderObject.cpp:1576 >> + break; > > if (!is<RenderBox>(frameRenderer)) > break; I ended up removing this part.
Wenson Hsieh
Comment 7 2019-03-04 09:12:48 PST
Created attachment 363518 [details] Take two
Darin Adler
Comment 8 2019-03-04 09:26:24 PST
Comment on attachment 363518 [details] Take two Wow, so much better in both algorithm and coding style too!
Wenson Hsieh
Comment 9 2019-03-04 16:04:49 PST
Comment on attachment 363518 [details] Take two Thanks for the review!
WebKit Commit Bot
Comment 10 2019-03-04 16:31:38 PST
Comment on attachment 363518 [details] Take two Clearing flags on attachment: 363518 Committed r242401: <https://trac.webkit.org/changeset/242401>
WebKit Commit Bot
Comment 11 2019-03-04 16:31:40 PST
All reviewed patches have been landed. Closing bug.
Note You need to log in before you can comment on or make changes to this bug.