Support WebSelections in WK2 on iOS.
authorenrica@apple.com <enrica@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 21 Feb 2014 21:56:14 +0000 (21:56 +0000)
committerenrica@apple.com <enrica@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 21 Feb 2014 21:56:14 +0000 (21:56 +0000)
https://bugs.webkit.org/show_bug.cgi?id=127015
<rdar://problem/15211964>

Reviewed by Benjamin Poulain.

../WebCore:

Adding some exports.

* WebCore.exp.in:

../WebKit2:

This is the remaining work on block selections for iOS in WK2.
Once a block selection has been created with a long press gesture
on a selectable area, we can interact with it by touching the four
handles at the top, right, bottom and left side of the selection box.
Expanding or shrinking a block selection requires finding the next/previous
block in the direction of the movement, depending on the handle we
are interacting with.
Every time a new block is selected, we compute the thresholds required
to trigger another block change. The thresholds are sent back to the
UIProcess that will use this information to decide when to activate
the new selection, either bigger or smaller.
This patch also fixes a bug in selectWithTwoTouches where the points
were not mapped to the active frame.

* Shared/ios/WKGestureTypes.h:
* UIProcess/API/ios/PageClientImplIOS.h:
* UIProcess/API/ios/PageClientImplIOS.mm:
(WebKit::PageClientImpl::didUpdateBlockSelectionWithTouches):
* UIProcess/API/ios/WKContentView.mm:
(-[WKContentView _didUpdateBlockSelectionWithTouches:withFlags:growThreshold:shrinkThreshold:]):
* UIProcess/API/ios/WKContentViewInternal.h:
* UIProcess/API/ios/WKInteractionView.h:
* UIProcess/API/ios/WKInteractionView.mm:
(-[WKInteractionView hasSelectablePositionAtPoint:]):
(-[WKInteractionView clearSelection]):
(toWKHandlePosition):
(-[WKInteractionView _didUpdateBlockSelectionWithTouches:WebKit::withFlags:WebKit::growThreshold:shrinkThreshold:]):
(-[WKInteractionView changeBlockSelectionWithTouchAt:withSelectionTouch:forHandle:]):
* UIProcess/PageClient.h:
* UIProcess/WebPageProxy.h:
* UIProcess/WebPageProxy.messages.in:
* UIProcess/ios/WebPageProxyIOS.mm:
(WebKit::WebPageProxy::updateBlockSelectionWithTouches):
(WebKit::WebPageProxy::didUpdateBlockSelectionWithTouches):
* WebProcess/WebPage/WebPage.cpp:
* WebProcess/WebPage/WebPage.h:
* WebProcess/WebPage/WebPage.messages.in:
* WebProcess/WebPage/ios/WebPageIOS.mm:
(WebKit::WebPage::rangeForWebSelectionAtPosition):
(WebKit::WebPage::rangeForBlockAtPoint):
(WebKit::WebPage::selectWithGesture):
(WebKit::distanceBetweenRectsForPosition):
(WebKit::rectsEssentiallyTheSame):
(WebKit::containsRange):
(WebKit::unionDOMRanges):
(WebKit::computeEdgeCenter):
(WebKit::WebPage::expandedRangeFromHandle):
(WebKit::WebPage::contractedRangeFromHandle):
(WebKit::WebPage::computeExpandAndShrinkThresholdsForHandle):
(WebKit::shouldExpand):
(WebKit::WebPage::changeBlockSelection):
(WebKit::WebPage::updateBlockSelectionWithTouches):
(WebKit::WebPage::clearSelection):
(WebKit::WebPage::selectWithTwoTouches):
(WebKit::WebPage::getPositionInformation):

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@164497 268f45cc-cd09-0410-ab3c-d52691b4dbfc

18 files changed:
Source/WebCore/ChangeLog
Source/WebCore/WebCore.exp.in
Source/WebKit2/ChangeLog
Source/WebKit2/Shared/ios/WKGestureTypes.h
Source/WebKit2/UIProcess/API/ios/PageClientImplIOS.h
Source/WebKit2/UIProcess/API/ios/PageClientImplIOS.mm
Source/WebKit2/UIProcess/API/ios/WKContentView.mm
Source/WebKit2/UIProcess/API/ios/WKContentViewInternal.h
Source/WebKit2/UIProcess/API/ios/WKInteractionView.h
Source/WebKit2/UIProcess/API/ios/WKInteractionView.mm
Source/WebKit2/UIProcess/PageClient.h
Source/WebKit2/UIProcess/WebPageProxy.h
Source/WebKit2/UIProcess/WebPageProxy.messages.in
Source/WebKit2/UIProcess/ios/WebPageProxyIOS.mm
Source/WebKit2/WebProcess/WebPage/WebPage.cpp
Source/WebKit2/WebProcess/WebPage/WebPage.h
Source/WebKit2/WebProcess/WebPage/WebPage.messages.in
Source/WebKit2/WebProcess/WebPage/ios/WebPageIOS.mm

index 979a0a5..603fd59 100644 (file)
@@ -1,3 +1,15 @@
+2014-02-21  Enrica Casucci  <enrica@apple.com>
+
+        Support WebSelections in WK2 on iOS.
+        https://bugs.webkit.org/show_bug.cgi?id=127015
+        <rdar://problem/15211964>
+
+        Reviewed by Benjamin Poulain.
+
+        Adding some exports.
+
+        * WebCore.exp.in:
+
 2014-02-21  Benjamin Poulain  <bpoulain@apple.com>
 
         'mouseenter' mouse compat event not fired when listeners for touch events
index 984e18e..4b9beda 100644 (file)
@@ -1745,7 +1745,10 @@ __ZNK7WebCore5Frame15layerTreeAsTextEj
 __ZNK7WebCore5Frame16frameScaleFactorEv
 __ZNK7WebCore5Frame25trackedRepaintRectsAsTextEv
 __ZNK7WebCore5Frame31displayStringModifiedByEncodingERKN3WTF6StringE
+__ZNK7WebCore5Range10cloneRangeERi
+__ZNK7WebCore5Range11boundingBoxEv
 __ZNK7WebCore5Range11startOffsetERi
+__ZNK7WebCore5Range12boundingRectEv
 __ZNK7WebCore5Range12endContainerERi
 __ZNK7WebCore5Range12pastLastNodeEv
 __ZNK7WebCore5Range14startContainerERi
@@ -2326,6 +2329,7 @@ __ZN7WebCore13endOfDocumentERKNS_15VisiblePositionE
 __ZN7WebCore13endOfSentenceERKNS_15VisiblePositionE
 __ZN7WebCore13getRawCookiesERKNS_21NetworkStorageSessionERKNS_3URLES5_RN3WTF6VectorINS_6CookieELm0ENS6_15CrashOnOverflowEEE
 __ZN7WebCore13isStartOfLineERKNS_15VisiblePositionE
+__ZN7WebCore14areRangesEqualEPKNS_5RangeES2_
 __ZN7WebCore14DocumentLoader19setResponseMIMETypeERKN3WTF6StringE
 __ZN7WebCore14DocumentWriter3endEv
 __ZN7WebCore14FrameSelection13setCaretColorERKNS_5ColorE
index 0929fbb..ca80d1f 100644 (file)
@@ -1,3 +1,67 @@
+2014-02-21  Enrica Casucci  <enrica@apple.com>
+
+        Support WebSelections in WK2 on iOS.
+        https://bugs.webkit.org/show_bug.cgi?id=127015
+        <rdar://problem/15211964>
+
+        Reviewed by Benjamin Poulain.
+
+        This is the remaining work on block selections for iOS in WK2.
+        Once a block selection has been created with a long press gesture
+        on a selectable area, we can interact with it by touching the four
+        handles at the top, right, bottom and left side of the selection box.
+        Expanding or shrinking a block selection requires finding the next/previous
+        block in the direction of the movement, depending on the handle we
+        are interacting with.
+        Every time a new block is selected, we compute the thresholds required
+        to trigger another block change. The thresholds are sent back to the
+        UIProcess that will use this information to decide when to activate
+        the new selection, either bigger or smaller.
+        This patch also fixes a bug in selectWithTwoTouches where the points
+        were not mapped to the active frame.
+
+        * Shared/ios/WKGestureTypes.h:
+        * UIProcess/API/ios/PageClientImplIOS.h:
+        * UIProcess/API/ios/PageClientImplIOS.mm:
+        (WebKit::PageClientImpl::didUpdateBlockSelectionWithTouches):
+        * UIProcess/API/ios/WKContentView.mm:
+        (-[WKContentView _didUpdateBlockSelectionWithTouches:withFlags:growThreshold:shrinkThreshold:]):
+        * UIProcess/API/ios/WKContentViewInternal.h:
+        * UIProcess/API/ios/WKInteractionView.h:
+        * UIProcess/API/ios/WKInteractionView.mm:
+        (-[WKInteractionView hasSelectablePositionAtPoint:]):
+        (-[WKInteractionView clearSelection]):
+        (toWKHandlePosition):
+        (-[WKInteractionView _didUpdateBlockSelectionWithTouches:WebKit::withFlags:WebKit::growThreshold:shrinkThreshold:]):
+        (-[WKInteractionView changeBlockSelectionWithTouchAt:withSelectionTouch:forHandle:]):
+        * UIProcess/PageClient.h:
+        * UIProcess/WebPageProxy.h:
+        * UIProcess/WebPageProxy.messages.in:
+        * UIProcess/ios/WebPageProxyIOS.mm:
+        (WebKit::WebPageProxy::updateBlockSelectionWithTouches):
+        (WebKit::WebPageProxy::didUpdateBlockSelectionWithTouches):
+        * WebProcess/WebPage/WebPage.cpp:
+        * WebProcess/WebPage/WebPage.h:
+        * WebProcess/WebPage/WebPage.messages.in:
+        * WebProcess/WebPage/ios/WebPageIOS.mm:
+        (WebKit::WebPage::rangeForWebSelectionAtPosition):
+        (WebKit::WebPage::rangeForBlockAtPoint):
+        (WebKit::WebPage::selectWithGesture):
+        (WebKit::distanceBetweenRectsForPosition):
+        (WebKit::rectsEssentiallyTheSame):
+        (WebKit::containsRange):
+        (WebKit::unionDOMRanges):
+        (WebKit::computeEdgeCenter):
+        (WebKit::WebPage::expandedRangeFromHandle):
+        (WebKit::WebPage::contractedRangeFromHandle):
+        (WebKit::WebPage::computeExpandAndShrinkThresholdsForHandle):
+        (WebKit::shouldExpand):
+        (WebKit::WebPage::changeBlockSelection):
+        (WebKit::WebPage::updateBlockSelectionWithTouches):
+        (WebKit::WebPage::clearSelection):
+        (WebKit::WebPage::selectWithTwoTouches):
+        (WebKit::WebPage::getPositionInformation):
+
 2014-02-21  Anders Carlsson  <andersca@apple.com>
 
         Make sure to invoke the completion handler for JS alerts
index e32701c..bddc937 100644 (file)
@@ -75,6 +75,12 @@ typedef enum {
     WKIsBlockSelection = 2
 } WKSelectionFlags;
 
+typedef enum {
+    WKHandleTop,
+    WKHandleRight,
+    WKHandleBottom,
+    WKHandleLeft
+} WKHandlePosition;
 } // namespace WebKit
 
 #endif // WKGestureTypes_h
index 7a523a3..251e19b 100644 (file)
@@ -110,6 +110,7 @@ private:
     virtual bool interpretKeyEvent(const NativeWebKeyboardEvent&, bool isCharEvent) override;
     virtual void positionInformationDidChange(const InteractionInformationAtPosition&);
     virtual void saveImageToLibrary(PassRefPtr<WebCore::SharedBuffer>);
+    virtual void didUpdateBlockSelectionWithTouch(uint32_t touch, uint32_t flags, float growThreshold, float shrinkThreshold);
 
     // Auxiliary Client Creation
 #if ENABLE(FULLSCREEN_API)
index 9aa27cd..fda60cc 100644 (file)
@@ -356,6 +356,11 @@ void PageClientImpl::stopAssistingNode()
     [m_view _stopAssistingNode];
 }
 
+void PageClientImpl::didUpdateBlockSelectionWithTouch(uint32_t touch, uint32_t flags, float growThreshold, float shrinkThreshold)
+{
+    [m_view _didUpdateBlockSelectionWithTouch:(WKSelectionTouch)touch withFlags:(WKSelectionFlags)flags growThreshold:growThreshold shrinkThreshold:shrinkThreshold];
+}
+
 #if ENABLE(FULLSCREEN_API)
 
 WebFullScreenManagerProxyClient& PageClientImpl::fullScreenManagerProxyClient()
index b716b50..cd10c42 100644 (file)
@@ -298,6 +298,11 @@ using namespace WebKit;
     [_interactionView _selectionChanged];
 }
 
+- (void)_didUpdateBlockSelectionWithTouch:(WKSelectionTouch)touch withFlags:(WKSelectionFlags)flags growThreshold:(CGFloat)growThreshold shrinkThreshold:(CGFloat)shrinkThreshold
+{
+    [_interactionView _didUpdateBlockSelectionWithTouch:touch withFlags:flags growThreshold:growThreshold shrinkThreshold:shrinkThreshold];
+}
+
 - (BOOL)_interpretKeyEvent:(WebIOSEvent *)theEvent isCharEvent:(BOOL)isCharEvent
 {
     return [_interactionView _interpretKeyEvent:theEvent isCharEvent:isCharEvent];
index 5247dcb..a6118c5 100644 (file)
@@ -24,6 +24,7 @@
  */
 
 #import "WKContentView.h"
+#import "WKGestureTypes.h"
 #import <wtf/Forward.h>
 #import <wtf/RetainPtr.h>
 #import <wtf/Vector.h>
@@ -71,6 +72,7 @@ struct InteractionInformationAtPosition;
 - (BOOL)_interpretKeyEvent:(WebIOSEvent *)theEvent isCharEvent:(BOOL)isCharEvent;
 - (void)_positionInformationDidChange:(const WebKit::InteractionInformationAtPosition&)info;
 - (void)_decidePolicyForGeolocationRequestFromOrigin:(WebKit::WebSecurityOrigin&)origin frame:(WebKit::WebFrameProxy&)frame request:(WebKit::GeolocationPermissionRequestProxy&)permissionRequest;
+- (void)_didUpdateBlockSelectionWithTouch:(WebKit::WKSelectionTouch)touch withFlags:(WebKit::WKSelectionFlags)flags growThreshold:(CGFloat)growThreshold shrinkThreshold:(CGFloat)shrinkThreshold;
 
 - (RetainPtr<CGImageRef>)_takeViewSnapshot;
 
index 6145f50..66f7aea 100644 (file)
@@ -70,5 +70,6 @@ struct InteractionInformationAtPosition;
 - (void)_willStartScrollingOrZooming;
 - (void)_willStartUserTriggeredScrollingOrZooming;
 - (void)_didEndScrollingOrZooming;
+- (void)_didUpdateBlockSelectionWithTouch:(WebKit::WKSelectionTouch)touch withFlags:(WebKit::WKSelectionFlags)flags growThreshold:(CGFloat)growThreshold shrinkThreshold:(CGFloat)shrinkThreshold;
 @property (readonly, nonatomic) WebKit::InteractionInformationAtPosition positionInformation;
 @end
index 710e2e4..67e6ffe 100644 (file)
@@ -564,6 +564,7 @@ static inline bool isSamePair(UIGestureRecognizer *a, UIGestureRecognizer *b, UI
 {
     [self ensurePositionInformationIsUpToDate:point];
     // FIXME: This check needs to be extended to include other elements.
+    // FIXME: We need to reject positions that will lead to a very large selection.
     return _positionInformation.clickableElementName != "IMG" && _positionInformation.clickableElementName != "A" && !_positionInformation.selectionRects.isEmpty();
 }
 
@@ -693,6 +694,11 @@ static inline bool isSamePair(UIGestureRecognizer *a, UIGestureRecognizer *b, UI
     }
 }
 
+- (void)clearSelection
+{
+    _page->clearSelection();
+}
+
 - (void)_positionInformationDidChange:(const InteractionInformationAtPosition&)info
 {
     _positionInformation = info;
@@ -1105,6 +1111,20 @@ static inline UIWKSelectionFlags toUIWKSelectionFlags(WKSelectionFlags flag)
     }
 }
 
+static inline WKHandlePosition toWKHandlePosition(UIWKHandlePosition position)
+{
+    switch (position) {
+    case UIWKHandleTop:
+        return WKHandleTop;
+    case UIWKHandleRight:
+        return WKHandleRight;
+    case UIWKHandleBottom:
+        return WKHandleBottom;
+    case UIWKHandleLeft:
+        return WKHandleLeft;
+    }
+}
+
 static void selectionChangedWithGesture(bool error, WKInteractionView *view, const WebCore::IntPoint& point, uint32_t gestureType, uint32_t gestureState, uint32_t flags)
 {
     if (error) {
@@ -1129,6 +1149,11 @@ static void selectionChangedWithTouch(bool error, WKInteractionView *view, const
         [(UIWKTextInteractionAssistant *)[view interactionAssistant] selectionChangedWithTouchAt:(CGPoint)point withSelectionTouch:toUIWKSelectionTouch((WKSelectionTouch)touch)];
 }
 
+- (void)_didUpdateBlockSelectionWithTouch:(WebKit::WKSelectionTouch)touch withFlags:(WebKit::WKSelectionFlags)flags growThreshold:(CGFloat)growThreshold shrinkThreshold:(CGFloat)shrinkThreshold
+{
+    [_webSelectionAssistant blockSelectionChangedWithTouch:toUIWKSelectionTouch((WKSelectionTouch)touch) withFlags:toUIWKSelectionFlags((WKSelectionFlags)flags) growThreshold:growThreshold shrinkThreshold:shrinkThreshold];
+}
+
 - (void)changeSelectionWithGestureAt:(CGPoint)point withGesture:(UIWKGestureType)gestureType withState:(UIGestureRecognizerState)state
 {
     _page->selectWithGesture(WebCore::IntPoint(point), CharacterGranularity, toWKGestureType(gestureType), toWKGestureRecognizerState(state), GestureCallback::create([self](bool error, const WebCore::IntPoint& point, uint32_t gestureType, uint32_t gestureState, uint32_t flags) {
@@ -1150,6 +1175,11 @@ static void selectionChangedWithTouch(bool error, WKInteractionView *view, const
     }));
 }
 
+- (void)changeBlockSelectionWithTouchAt:(CGPoint)point withSelectionTouch:(UIWKSelectionTouch)touch forHandle:(UIWKHandlePosition)handle
+{
+    _page->updateBlockSelectionWithTouch(WebCore::IntPoint(point), toWKSelectionTouch(touch), toWKHandlePosition(handle));
+}
+
 - (WKAutoCorrectionData *)autocorrectionData
 {
     return &_autocorrectionData;
index 16a953d..e31bb76 100644 (file)
@@ -249,6 +249,7 @@ public:
     virtual bool interpretKeyEvent(const NativeWebKeyboardEvent&, bool isCharEvent) = 0;
     virtual void positionInformationDidChange(const InteractionInformationAtPosition&) = 0;
     virtual void saveImageToLibrary(PassRefPtr<WebCore::SharedBuffer>) = 0;
+    virtual void didUpdateBlockSelectionWithTouch(uint32_t touch, uint32_t flags, float growThreshold, float shrinkThreshold) = 0;
 #endif
 
     // Auxiliary Client Creation
index 284426f..c924c97 100644 (file)
@@ -458,6 +458,7 @@ public:
     void selectWithGesture(const WebCore::IntPoint, WebCore::TextGranularity, uint32_t gestureType, uint32_t gestureState, PassRefPtr<GestureCallback>);
     void updateSelectionWithTouches(const WebCore::IntPoint, uint32_t touches, bool baseIsStart, PassRefPtr<TouchesCallback>);
     void selectWithTwoTouches(const WebCore::IntPoint from, const WebCore::IntPoint to, uint32_t gestureType, uint32_t gestureState, PassRefPtr<GestureCallback>);
+    void updateBlockSelectionWithTouch(const WebCore::IntPoint, uint32_t touch, uint32_t handlePosition);
     void extendSelection(WebCore::TextGranularity);
     void requestAutocorrectionData(const String& textForAutocorrection, PassRefPtr<AutocorrectionDataCallback>);
     void applyAutocorrection(const String& correction, const String& originalText, PassRefPtr<StringCallback>);
@@ -470,6 +471,7 @@ public:
     void stopInteraction();
     void performActionOnElement(uint32_t action);
     void saveImageToLibrary(const SharedMemory::Handle& imageHandle, uint64_t imageSize);
+    void didUpdateBlockSelectionWithTouch(uint32_t touch, uint32_t flags, float growThreshold, float shrinkThreshold);
 #endif
 
     const EditorState& editorState() const { return m_editorState; }
index 7315a89..238d2df 100644 (file)
@@ -156,6 +156,7 @@ messages -> WebPageProxy {
     InterpretKeyEvent(WebKit::EditorState state, bool isCharEvent) -> (bool handled)
     DidReceivePositionInformation(WebKit::InteractionInformationAtPosition information)
     SaveImageToLibrary(WebKit::SharedMemory::Handle handle, uint64_t size)
+    DidUpdateBlockSelectionWithTouch(uint32_t touch, uint32_t flags, float growThreshold, float shrinkThreshold)
 #endif
 #if PLATFORM(GTK)
     PrintFinishedCallback(WebCore::ResourceError error, uint64_t callbackID)
index 533df43..e0d935c 100644 (file)
@@ -326,6 +326,11 @@ void WebPageProxy::selectWithTwoTouches(const WebCore::IntPoint from, const WebC
     m_process->send(Messages::WebPage::SelectWithTwoTouches(from, to, gestureType, gestureState, callbackID), m_pageID);
 }
 
+void WebPageProxy::updateBlockSelectionWithTouch(const WebCore::IntPoint point, uint32_t touch, uint32_t handlePosition)
+{
+    m_process->send(Messages::WebPage::UpdateBlockSelectionWithTouch(point, touch, handlePosition), m_pageID);
+}
+
 void WebPageProxy::didReceivePositionInformation(const InteractionInformationAtPosition& info)
 {
     m_pageClient.positionInformationDidChange(info);
@@ -363,6 +368,11 @@ void WebPageProxy::saveImageToLibrary(const SharedMemory::Handle& imageHandle, u
     m_pageClient.saveImageToLibrary(buffer);
 }
 
+void WebPageProxy::didUpdateBlockSelectionWithTouch(uint32_t touch, uint32_t flags, float growThreshold, float shrinkThreshold)
+{
+    m_pageClient.didUpdateBlockSelectionWithTouch(touch, flags, growThreshold, shrinkThreshold);
+}
+
 void WebPageProxy::notifyRevealedSelection()
 {
     m_pageClient.selectionDidChange();
index b253c07..5fe3039 100644 (file)
@@ -3041,10 +3041,12 @@ void WebPage::replaceSelectionWithText(Frame* frame, const String& text)
     return frame->editor().replaceSelectionWithText(text, selectReplacement, smartReplace);
 }
 
+#if !PLATFORM(IOS)
 void WebPage::clearSelection()
 {
     m_page->focusController().focusedOrMainFrame().selection().clear();
 }
+#endif
 
 void WebPage::updateMainFrameScrollOffsetPinning()
 {
index aa4ac2c..82d9264 100644 (file)
@@ -438,6 +438,7 @@ public:
     void blurAssistedNode();
     void selectWithGesture(const WebCore::IntPoint&, uint32_t granularity, uint32_t gestureType, uint32_t gestureState, uint64_t callbackID);
     void updateSelectionWithTouches(const WebCore::IntPoint& point, uint32_t touches, bool baseIsStart, uint64_t callbackID);
+    void updateBlockSelectionWithTouch(const WebCore::IntPoint&, uint32_t touch, uint32_t handlePosition);
     void selectWithTwoTouches(const WebCore::IntPoint& from, const WebCore::IntPoint& to, uint32_t gestureType, uint32_t gestureState, uint64_t callbackID);
     void extendSelection(uint32_t granularity);
     void elementDidFocus(WebCore::Node*);
@@ -735,6 +736,13 @@ private:
 #if PLATFORM(IOS)
     static void convertSelectionRectsToRootView(WebCore::FrameView*, Vector<WebCore::SelectionRect>&);
     PassRefPtr<WebCore::Range> rangeForWebSelectionAtPosition(const WebCore::IntPoint&, const WebCore::VisiblePosition&, WKSelectionFlags&);
+    PassRefPtr<WebCore::Range> rangeForBlockAtPoint(const WebCore::IntPoint&);
+    void computeExpandAndShrinkThresholdsForHandle(const WebCore::IntPoint&, WKHandlePosition, float& growThreshold, float& shrinkThreshold);
+    PassRefPtr<WebCore::Range> changeBlockSelection(const WebCore::IntPoint&, WKHandlePosition, float& growThreshold, float& shrinkThreshold, WKSelectionFlags&);
+    PassRefPtr<WebCore::Range> expandedRangeFromHandle(WebCore::Range*, WKHandlePosition);
+    PassRefPtr<WebCore::Range> contractedRangeFromHandle(WebCore::Range* currentRange, WKHandlePosition, WKSelectionFlags&);
+
+    RefPtr<WebCore::Range> m_currentBlockSelection;
 #endif
 #if !PLATFORM(COCOA)
     static const char* interpretKeyEvent(const WebCore::KeyboardEvent*);
index 897d679..42fb946 100644 (file)
@@ -48,6 +48,7 @@ messages -> WebPage LegacyReceiver {
     BlurAssistedNode()
     SelectWithGesture(WebCore::IntPoint point, uint32_t granularity, uint32_t gestureType, uint32_t gestureState, uint64_t callbackID)
     UpdateSelectionWithTouches(WebCore::IntPoint point, uint32_t touches, bool baseIsStart, uint64_t callbackID)
+    UpdateBlockSelectionWithTouch(WebCore::IntPoint point, uint32_t touch, uint32_t handlePosition)
     SelectWithTwoTouches(WebCore::IntPoint from, WebCore::IntPoint to, uint32_t gestureType, uint32_t gestureState, uint64_t callbackID)
     ExtendSelection(uint32_t granularity)
     RequestAutocorrectionData(String textForAutocorrection, uint64_t callbackID)
index 14b6cb9..2fbf8de 100644 (file)
@@ -438,11 +438,10 @@ PassRefPtr<Range> WebPage::rangeForWebSelectionAtPosition(const IntPoint& point,
     Node* currentNode = result.innerNode();
     RefPtr<Range> range;
     IntRect boundingRect;
-    ExceptionCode ec;
 
     if (currentNode->isTextNode()) {
         range = enclosingTextUnitOfGranularity(position, ParagraphGranularity, DirectionForward);
-        if (!range || range->collapsed(ec))
+        if (!range || range->collapsed(ASSERT_NO_EXCEPTION))
             range = Range::create(currentNode->document(), position, position);
         if (!range)
             return nullptr;
@@ -461,7 +460,7 @@ PassRefPtr<Range> WebPage::rangeForWebSelectionAtPosition(const IntPoint& point,
         if (boundingRect.width() > m_blockSelectionDesiredSize.width() && boundingRect.height() > m_blockSelectionDesiredSize.height())
             return wordRangeFromPosition(position);
 
-        currentNode = range->commonAncestorContainer(ec);
+        currentNode = range->commonAncestorContainer(ASSERT_NO_EXCEPTION);
     }
 
     if (!currentNode->isElementNode())
@@ -482,12 +481,36 @@ PassRefPtr<Range> WebPage::rangeForWebSelectionAtPosition(const IntPoint& point,
     RenderObject* renderer = bestChoice->renderer();
     if (renderer && renderer->childrenInline() && (renderer->isRenderBlock() && toRenderBlock(renderer)->inlineElementContinuation() == nil) && !renderer->isTable()) {
         range = enclosingTextUnitOfGranularity(position, WordGranularity, DirectionBackward);
-        if (range && !range->collapsed(ec))
+        if (range && !range->collapsed(ASSERT_NO_EXCEPTION))
             return range;
     }
     flags = WKIsBlockSelection;
     range = Range::create(bestChoice->document());
-    range->selectNode(bestChoice, ec);
+    range->selectNodeContents(bestChoice, ASSERT_NO_EXCEPTION);
+    return range;
+}
+
+PassRefPtr<Range> WebPage::rangeForBlockAtPoint(const IntPoint& point)
+{
+    HitTestResult result = m_page->mainFrame().eventHandler().hitTestResultAtPoint((point), HitTestRequest::ReadOnly | HitTestRequest::Active | HitTestRequest::DisallowShadowContent);
+
+    Node* currentNode = result.innerNode();
+    RefPtr<Range> range;
+
+    if (currentNode->isTextNode()) {
+        range = enclosingTextUnitOfGranularity(m_page->focusController().focusedOrMainFrame().visiblePositionForPoint(point), ParagraphGranularity, DirectionForward);
+        if (range && !range->collapsed(ASSERT_NO_EXCEPTION))
+            return range;
+    }
+
+    if (!currentNode->isElementNode())
+        currentNode = currentNode->parentElement();
+
+    if (!currentNode)
+        return nullptr;
+
+    range = Range::create(currentNode->document());
+    range->selectNodeContents(currentNode, ASSERT_NO_EXCEPTION);
     return range;
 }
 
@@ -504,6 +527,7 @@ void WebPage::selectWithGesture(const IntPoint& point, uint32_t granularity, uin
     }
     RefPtr<Range> range;
     WKSelectionFlags flags = WKNone;
+    WKGestureRecognizerState wkGestureState = static_cast<WKGestureRecognizerState>(gestureState);
     switch (static_cast<WKGestureType>(gestureType)) {
     case WKGestureOneFingerTap:
     {
@@ -543,20 +567,17 @@ void WebPage::selectWithGesture(const IntPoint& point, uint32_t granularity, uin
         break;
 
     case WKGestureTapAndAHalf:
-        switch (static_cast<WKGestureRecognizerState>(gestureState)) {
+        switch (wkGestureState) {
         case WKGestureRecognizerStateBegan:
             range = wordRangeFromPosition(position);
             m_currentWordRange = Range::create(*frame.document(), range->startPosition(), range->endPosition());
             break;
         case WKGestureRecognizerStateChanged:
-        {
             range = Range::create(*frame.document(), m_currentWordRange->startPosition(), m_currentWordRange->endPosition());
-            ExceptionCode ec;
             if (position < range->startPosition())
-                range->setStart(position.deepEquivalent(), ec);
+                range->setStart(position.deepEquivalent(), ASSERT_NO_EXCEPTION);
             if (position > range->endPosition())
-                range->setEnd(position.deepEquivalent(), ec);
-        }
+                range->setEnd(position.deepEquivalent(), ASSERT_NO_EXCEPTION);
             break;
         case WKGestureRecognizerStateEnded:
         case WKGestureRecognizerStateCancelled:
@@ -594,11 +615,14 @@ void WebPage::selectWithGesture(const IntPoint& point, uint32_t granularity, uin
         break;
 
     case WKGestureMakeWebSelection:
-        if (static_cast<WKGestureRecognizerState>(gestureState) == WKGestureRecognizerStateBegan) {
+        if (wkGestureState == WKGestureRecognizerStateBegan) {
             m_blockSelectionDesiredSize.setWidth(blockSelectionStartWidth);
             m_blockSelectionDesiredSize.setHeight(blockSelectionStartHeight);
+            m_currentBlockSelection = nullptr;
         }
         range = rangeForWebSelectionAtPosition(point, position, flags);
+        if (wkGestureState == WKGestureRecognizerStateEnded && flags & WKIsBlockSelection)
+            m_currentBlockSelection = range;
         break;
 
     default:
@@ -689,6 +713,415 @@ static PassRefPtr<Range> rangeAtWordBoundaryForPosition(Frame* frame, const Visi
     return (base < extent) ? Range::create(*frame->document(), base, extent) : Range::create(*frame->document(), extent, base);
 }
 
+static const int maxHitTests = 10;
+
+static inline float distanceBetweenRectsForPosition(IntRect& first, IntRect& second, WKHandlePosition handlePosition)
+{
+    switch (handlePosition) {
+    case WKHandleTop:
+        return abs(first.y() - second.y());
+    case WKHandleRight:
+        return abs(first.maxX() - second.maxX());
+    case WKHandleBottom:
+        return abs(first.maxY() - second.maxY());
+    case WKHandleLeft:
+        return abs(first.x() - second.x());
+    }
+}
+
+static inline bool rectsEssentiallyTheSame(IntRect& first, IntRect& second, float allowablePercentDifference)
+{
+    const float minMagnitudeRatio = 1.0 - allowablePercentDifference;
+    const float maxDisplacementRatio = allowablePercentDifference;
+
+    float xOriginShiftRatio = abs(first.x() - second.x())/std::min(first.width(), second.width());
+    float yOriginShiftRatio = abs(first.y() - second.y())/std::min(first.height(), second.height());
+
+    float widthRatio = std::min(first.width() / second.width(), second.width() / first.width());
+    float heightRatio = std::min(first.height() / second.height(), second.height() / first.height());
+    return ((widthRatio > minMagnitudeRatio && xOriginShiftRatio < maxDisplacementRatio)
+        && (heightRatio > minMagnitudeRatio && yOriginShiftRatio < maxDisplacementRatio));
+}
+
+static inline bool containsRange(Range* first, Range* second)
+{
+    if (!first || !second)
+        return false;
+    return (first->commonAncestorContainer(ASSERT_NO_EXCEPTION)->ownerDocument() == second->commonAncestorContainer(ASSERT_NO_EXCEPTION)->ownerDocument()
+        && first->compareBoundaryPoints(Range::START_TO_START, second, ASSERT_NO_EXCEPTION) <= 0
+        && first->compareBoundaryPoints(Range::END_TO_END, second, ASSERT_NO_EXCEPTION) >= 0);
+}
+
+static inline RefPtr<Range> unionDOMRanges(Range* rangeA, Range* rangeB)
+{
+    if (!rangeB)
+        return rangeA;
+    if (!rangeA)
+        return rangeB;
+
+    Range* start = rangeA->compareBoundaryPoints(Range::START_TO_START, rangeB, ASSERT_NO_EXCEPTION) <= 0 ? rangeA : rangeB;
+    Range* end = rangeA->compareBoundaryPoints(Range::END_TO_END, rangeB, ASSERT_NO_EXCEPTION) <= 0 ? rangeB : rangeA;
+
+    return Range::create(rangeA->ownerDocument(), start->startContainer(), start->startOffset(), end->endContainer(), end->endOffset());
+}
+
+static inline IntPoint computeEdgeCenter(const IntRect& box, WKHandlePosition handlePosition)
+{
+    switch (handlePosition) {
+    case WKHandleTop:
+        return IntPoint(box.x() + box.width() / 2, box.y());
+    case WKHandleRight:
+        return IntPoint(box.maxX(), box.y() + box.height() / 2);
+    case WKHandleBottom:
+        return IntPoint(box.x() + box.width() / 2, box.maxY());
+    case WKHandleLeft:
+        return IntPoint(box.x(), box.y() + box.height() / 2);
+    }
+}
+
+PassRefPtr<Range> WebPage::expandedRangeFromHandle(Range* currentRange, WKHandlePosition handlePosition)
+{
+    // FIXME: We should use boundingRect() instead of boundingBox() in this function when <rdar://problem/16063723> is fixed.
+    IntRect currentBox = currentRange->boundingBox();
+    IntPoint edgeCenter = computeEdgeCenter(currentBox, handlePosition);
+    static const float maxDistance = 1000;
+    const float multiple = powf(maxDistance, 1.0/(maxHitTests - 1));
+    float distance = 1;
+
+    RefPtr<Range> bestRange;
+    IntRect bestRect;
+
+    while (distance < maxDistance) {
+        if (bestRange) {
+            if (distanceBetweenRectsForPosition(bestRect, currentBox, handlePosition) < distance) {
+                // Break early, we're unlikely to do any better.
+                break;
+            }
+        }
+
+        IntPoint testPoint = edgeCenter;
+        switch (handlePosition) {
+        case WKHandleTop:
+            testPoint.move(0, -distance);
+            break;
+        case WKHandleRight:
+            testPoint.move(distance, 0);
+            break;
+        case WKHandleBottom:
+            testPoint.move(0, distance);
+            break;
+        case WKHandleLeft:
+            testPoint.move(-distance, 0);
+            break;
+        }
+
+        RefPtr<Range> newRange;
+        RefPtr<Range> rangeAtPosition = rangeForBlockAtPoint(testPoint);
+        if (containsRange(rangeAtPosition.get(), currentRange))
+            newRange = rangeAtPosition;
+        else if (containsRange(currentRange, rangeAtPosition.get()))
+            newRange = currentRange;
+        else
+            newRange = unionDOMRanges(currentRange, rangeAtPosition.get());
+
+        IntRect copyRect = newRange->boundingBox();
+
+        // Is it different and bigger than the current?
+        bool isBetterChoice = !(rectsEssentiallyTheSame(copyRect, currentBox, .05));
+        if (isBetterChoice) {
+            switch (handlePosition) {
+            case WKHandleTop:
+            case WKHandleBottom:
+                isBetterChoice = (copyRect.height() > currentBox.height());
+                break;
+            case WKHandleRight:
+            case WKHandleLeft:
+                isBetterChoice = (copyRect.width() > currentBox.width());
+                break;
+            }
+
+        }
+
+        if (bestRange && isBetterChoice) {
+            // Furtherore, is it smaller than the best we've found so far?
+            switch (handlePosition) {
+            case WKHandleTop:
+            case WKHandleBottom:
+                isBetterChoice = (copyRect.height() < bestRect.height());
+                break;
+            case WKHandleRight:
+            case WKHandleLeft:
+                isBetterChoice = (copyRect.width() < bestRect.width());
+                break;
+            }
+        }
+
+        if (isBetterChoice) {
+            bestRange = newRange;
+            bestRect = copyRect;
+        }
+
+        distance = ceilf(distance * multiple);
+    }
+
+    if (bestRange)
+        return bestRange;
+
+    return currentRange;
+}
+
+PassRefPtr<Range> WebPage::contractedRangeFromHandle(Range* currentRange, WKHandlePosition handlePosition, WKSelectionFlags& flags)
+{
+    // Shrinking with a base and extent will always give better results. If we only have a single element,
+    // see if we can break that down to a base and extent. Shrinking base and extent is comparatively straightforward.
+    // Shrinking down to another element is unlikely to move just one edge, but we can try that as a fallback.
+
+    // FIXME: We should use boundingRect() instead of boundingBox() in this function when <rdar://problem/16063723> is fixed.
+    IntRect currentBox = currentRange->boundingBox();
+    IntPoint edgeCenter = computeEdgeCenter(currentBox, handlePosition);
+    flags = WKIsBlockSelection;
+
+    float maxDistance;
+
+    switch (handlePosition) {
+    case WKHandleTop:
+    case WKHandleBottom:
+        maxDistance = currentBox.height();
+        break;
+    case WKHandleRight:
+    case WKHandleLeft:
+        maxDistance = currentBox.width();
+        break;
+    }
+
+    const float multiple = powf(maxDistance - 1, 1.0/(maxHitTests - 1));
+    float distance = 1;
+    RefPtr<Range> bestRange;
+    IntRect bestRect;
+
+    while (distance < maxDistance) {
+        if (bestRange) {
+            float shrankDistance;
+            switch (handlePosition) {
+            case WKHandleTop:
+            case WKHandleBottom:
+                shrankDistance = abs(currentBox.height() - bestRect.height());
+                break;
+            case WKHandleRight:
+            case WKHandleLeft:
+                shrankDistance = abs(currentBox.width() - bestRect.width());
+                break;
+            }
+            if (shrankDistance > distance) {
+                // Certainly not going to do any better than that.
+                break;
+            }
+        }
+
+        IntPoint testPoint = edgeCenter;
+        switch (handlePosition) {
+        case WKHandleTop:
+            testPoint.move(0, distance);
+            break;
+        case WKHandleRight:
+            testPoint.move(-distance, 0);
+            break;
+        case WKHandleBottom:
+            testPoint.move(0, -distance);
+            break;
+        case WKHandleLeft:
+            testPoint.move(distance, 0);
+            break;
+        }
+
+        RefPtr<Range> newRange = rangeForBlockAtPoint(testPoint);
+        if (handlePosition == WKHandleTop || handlePosition == WKHandleLeft)
+            newRange = Range::create(newRange->startContainer()->document(), newRange->startPosition(), currentRange->endPosition());
+        else
+            newRange = Range::create(newRange->startContainer()->document(), currentRange->startPosition(), newRange->endPosition());
+
+        IntRect copyRect = newRange->boundingBox();
+        bool isBetterChoice;
+        switch (handlePosition) {
+        case WKHandleTop:
+        case WKHandleBottom:
+            isBetterChoice = (copyRect.height() < currentBox.height());
+            break;
+        case WKHandleLeft:
+        case WKHandleRight:
+            isBetterChoice = (copyRect.width() > bestRect.width());
+            break;
+        }
+
+        isBetterChoice = isBetterChoice && !areRangesEqual(newRange.get(), currentRange);
+        if (bestRange && isBetterChoice) {
+            switch (handlePosition) {
+            case WKHandleTop:
+            case WKHandleBottom:
+                isBetterChoice = (copyRect.height() > bestRect.height());
+                break;
+            case WKHandleLeft:
+            case WKHandleRight:
+                isBetterChoice = (copyRect.width() > bestRect.width());
+                break;
+            }
+        }
+        if (isBetterChoice) {
+            bestRange = newRange;
+            bestRect = copyRect;
+        }
+
+        distance *= multiple;
+    }
+
+    // If we can shrink down to text only, the only reason we wouldn't is that
+    // there are multiple sub-element blocks beneath us.  If we didn't find
+    // multiple sub-element blocks, don't shrink to a sub-element block.
+    if (!bestRange) {
+        bestRange = currentRange;
+        Node* node = currentRange->commonAncestorContainer(ASSERT_NO_EXCEPTION);
+        if (!node->isElementNode())
+            node = node->parentElement();
+
+        RenderObject* renderer = node->renderer();
+        if (renderer && renderer->childrenInline() && (renderer->isRenderBlock() && !toRenderBlock(renderer)->inlineElementContinuation()) && !renderer->isTable()) {
+            flags = WKNone;
+        }
+    }
+
+    return bestRange;
+}
+
+void WebPage::computeExpandAndShrinkThresholdsForHandle(const IntPoint& point, WKHandlePosition handlePosition, float& growThreshold, float& shrinkThreshold)
+{
+    Frame& frame = m_page->focusController().focusedOrMainFrame();
+    RefPtr<Range> currentRange = m_currentBlockSelection ? m_currentBlockSelection.get() : frame.selection().selection().toNormalizedRange();
+    ASSERT(currentRange);
+
+    RefPtr<Range> expandedRange = expandedRangeFromHandle(currentRange.get(), handlePosition);
+    WKSelectionFlags flags;
+    RefPtr<Range> contractedRange = contractedRangeFromHandle(currentRange.get(), handlePosition, flags);
+
+    // FIXME: We should use boundingRect() instead of boundingBox() in this function when <rdar://problem/16063723> is fixed.
+    IntRect currentBounds = currentRange->boundingBox();
+    IntRect expandedBounds = expandedRange->boundingBox();
+    IntRect contractedBounds = contractedRange->boundingBox();
+
+    float current;
+    float expanded;
+    float contracted;
+    float maxThreshold;
+    float minThreshold;
+
+    switch (handlePosition) {
+    case WKHandleTop: {
+        current = currentBounds.y();
+        expanded = expandedBounds.y();
+        contracted = contractedBounds.y();
+        maxThreshold = FLT_MIN;
+        minThreshold = FLT_MAX;
+        break;
+    }
+    case WKHandleRight: {
+        current = currentBounds.maxX();
+        expanded = expandedBounds.maxX();
+        contracted = contractedBounds.maxX();
+        maxThreshold = FLT_MAX;
+        minThreshold = FLT_MIN;
+        break;
+    }
+    case WKHandleBottom: {
+        current = currentBounds.maxY();
+        expanded = expandedBounds.maxY();
+        contracted = contractedBounds.maxY();
+        maxThreshold = FLT_MAX;
+        minThreshold = FLT_MIN;
+        break;
+    }
+    case WKHandleLeft: {
+        current = currentBounds.x();
+        expanded = expandedBounds.x();
+        contracted = contractedBounds.x();
+        maxThreshold = FLT_MIN;
+        minThreshold = FLT_MAX;
+        break;
+    }
+    }
+
+    static const float fractionToGrow = 0.3;
+
+    growThreshold = current + (expanded - current) * fractionToGrow;
+    shrinkThreshold = current + (contracted - current) * (1 - fractionToGrow);
+    if (areRangesEqual(expandedRange.get(), currentRange.get()))
+        growThreshold = maxThreshold;
+
+    if ((flags & WKIsBlockSelection) && areRangesEqual(contractedRange.get(), currentRange.get()))
+        shrinkThreshold = minThreshold;
+}
+
+static inline bool shouldExpand(WKHandlePosition handlePosition, const IntRect& rect, const IntPoint& point)
+{
+    switch (handlePosition) {
+    case WKHandleTop:
+        return (point.y() < rect.y());
+    case WKHandleLeft:
+        return (point.x() < rect.x());
+    case WKHandleRight:
+        return (point.x() > rect.maxX());
+    case WKHandleBottom:
+        return (point.y() > rect.maxY());
+    }
+}
+
+PassRefPtr<WebCore::Range> WebPage::changeBlockSelection(const IntPoint& point, WKHandlePosition handlePosition, float& growThreshold, float& shrinkThreshold, WKSelectionFlags& flags)
+{
+    Frame& frame = m_page->focusController().focusedOrMainFrame();
+    RefPtr<Range> currentRange = m_currentBlockSelection ? m_currentBlockSelection.get() : frame.selection().selection().toNormalizedRange();
+    // FIXME: We should use boundingRect() instead of boundingBox() in this function when <rdar://problem/16063723> is fixed.
+    IntRect currentRect = currentRange->boundingBox();
+
+    RefPtr<Range> newRange = shouldExpand(handlePosition, currentRect, point) ? expandedRangeFromHandle(currentRange.get(), handlePosition) : contractedRangeFromHandle(currentRange.get(), handlePosition, flags);
+
+    if (newRange) {
+        m_currentBlockSelection = newRange;
+        frame.selection().setSelectedRange(newRange.get(), VP_DEFAULT_AFFINITY, true);
+    }
+
+    computeExpandAndShrinkThresholdsForHandle(point, handlePosition, growThreshold, shrinkThreshold);
+    return newRange;
+}
+
+void WebPage::updateBlockSelectionWithTouch(const IntPoint& point, uint32_t touch, uint32_t handlePosition)
+{
+    Frame& frame = m_page->focusController().focusedOrMainFrame();
+    IntPoint adjustedPoint = frame.view()->rootViewToContents(point);
+
+    float growThreshold = 0;
+    float shrinkThreshold = 0;
+    WKSelectionFlags flags = WKIsBlockSelection;
+
+    switch (static_cast<WKSelectionTouch>(touch)) {
+    case WKSelectionTouchStarted:
+        computeExpandAndShrinkThresholdsForHandle(adjustedPoint, static_cast<WKHandlePosition>(handlePosition), growThreshold, shrinkThreshold);
+        break;
+    case WKSelectionTouchEnded:
+        break;
+    case WKSelectionTouchMoved:
+        changeBlockSelection(adjustedPoint, static_cast<WKHandlePosition>(handlePosition), growThreshold, shrinkThreshold, flags);
+        break;
+    default:
+        return;
+    }
+
+    send(Messages::WebPageProxy::DidUpdateBlockSelectionWithTouch(touch, flags, growThreshold, shrinkThreshold));
+}
+
+void WebPage::clearSelection()
+{
+    m_currentBlockSelection = nullptr;
+    m_page->focusController().focusedOrMainFrame().selection().clear();
+}
+
 void WebPage::updateSelectionWithTouches(const IntPoint& point, uint32_t touches, bool baseIsStart, uint64_t callbackID)
 {
     Frame& frame = m_page->focusController().focusedOrMainFrame();
@@ -736,8 +1169,8 @@ void WebPage::updateSelectionWithTouches(const IntPoint& point, uint32_t touches
 void WebPage::selectWithTwoTouches(const WebCore::IntPoint& from, const WebCore::IntPoint& to, uint32_t gestureType, uint32_t gestureState, uint64_t callbackID)
 {
     Frame& frame = m_page->focusController().focusedOrMainFrame();
-    VisiblePosition fromPosition = frame.visiblePositionForPoint(from);
-    VisiblePosition toPosition = frame.visiblePositionForPoint(to);
+    VisiblePosition fromPosition = frame.visiblePositionForPoint(frame.view()->rootViewToContents(from));
+    VisiblePosition toPosition = frame.visiblePositionForPoint(frame.view()->rootViewToContents(to));
     RefPtr<Range> range;
     if (fromPosition.isNotNull() && toPosition.isNotNull()) {
         if (fromPosition < toPosition)
@@ -980,6 +1413,7 @@ void WebPage::getPositionInformation(const IntPoint& point, InteractionInformati
         if (hitNode) {
             m_page->focusController().setFocusedFrame(result.innerNodeFrame());
             info.selectionRects.append(SelectionRect(hitNode->renderer()->absoluteBoundingBoxRect(true), true, 0));
+            info.bounds = hitNode->renderer()->absoluteBoundingBoxRect();
         }
     }
 }