Title: [112721] trunk/Source/WebKit/blackberry
Revision
112721
Author
[email protected]
Date
2012-03-30 13:51:30 -0700 (Fri, 30 Mar 2012)

Log Message

[BlackBerry] Speed up processing of Selection region generation.
https://bugs.webkit.org/show_bug.cgi?id=82766

Reviewed by Rob Buis.

PR 136593.

Refactor generation of Selection IntRectRegion to avoid
the need for IntRectRegion's helper functions which were
not available when using it as a container without
unioning the rects.

This greatly speeds up rendering by maintaining the distinct
rects as the union operation was length with large numbers of
rects.

Reviewed Internally by Gen Mak, Mike Lattanzio and Tyler Abbott.

* WebKitSupport/DOMSupport.cpp:
(BlackBerry::WebKit::DOMSupport::visibleTextQuads):
(DOMSupport):
* WebKitSupport/DOMSupport.h:
* WebKitSupport/SelectionHandler.cpp:
(BlackBerry::WebKit::SelectionHandler::clippingRectForVisibleContent):
(BlackBerry::WebKit::SelectionHandler::regionForTextQuads):
(BlackBerry::WebKit::SelectionHandler::setSelection):
(WebKit):
(BlackBerry::WebKit::regionRectListContainsPoint):
(BlackBerry::WebKit::SelectionHandler::selectionPositionChanged):
(BlackBerry::WebKit::SelectionHandler::caretPositionChanged):
* WebKitSupport/SelectionHandler.h:
(WebCore):
(SelectionHandler):

Modified Paths

Diff

Modified: trunk/Source/WebKit/blackberry/ChangeLog (112720 => 112721)


--- trunk/Source/WebKit/blackberry/ChangeLog	2012-03-30 20:50:09 UTC (rev 112720)
+++ trunk/Source/WebKit/blackberry/ChangeLog	2012-03-30 20:51:30 UTC (rev 112721)
@@ -1,3 +1,39 @@
+2012-03-30  Mike Fenton  <[email protected]>
+
+        [BlackBerry] Speed up processing of Selection region generation.
+        https://bugs.webkit.org/show_bug.cgi?id=82766
+
+        Reviewed by Rob Buis.
+
+        PR 136593.
+
+        Refactor generation of Selection IntRectRegion to avoid
+        the need for IntRectRegion's helper functions which were
+        not available when using it as a container without
+        unioning the rects.
+
+        This greatly speeds up rendering by maintaining the distinct
+        rects as the union operation was length with large numbers of
+        rects.
+
+        Reviewed Internally by Gen Mak, Mike Lattanzio and Tyler Abbott.
+
+        * WebKitSupport/DOMSupport.cpp:
+        (BlackBerry::WebKit::DOMSupport::visibleTextQuads):
+        (DOMSupport):
+        * WebKitSupport/DOMSupport.h:
+        * WebKitSupport/SelectionHandler.cpp:
+        (BlackBerry::WebKit::SelectionHandler::clippingRectForVisibleContent):
+        (BlackBerry::WebKit::SelectionHandler::regionForTextQuads):
+        (BlackBerry::WebKit::SelectionHandler::setSelection):
+        (WebKit):
+        (BlackBerry::WebKit::regionRectListContainsPoint):
+        (BlackBerry::WebKit::SelectionHandler::selectionPositionChanged):
+        (BlackBerry::WebKit::SelectionHandler::caretPositionChanged):
+        * WebKitSupport/SelectionHandler.h:
+        (WebCore):
+        (SelectionHandler):
+
 2012-03-30  Mark Pilgrim  <[email protected]>
 
         GEOLOCATION should be implemented as Page Supplement

Modified: trunk/Source/WebKit/blackberry/WebKitSupport/DOMSupport.cpp (112720 => 112721)


--- trunk/Source/WebKit/blackberry/WebKitSupport/DOMSupport.cpp	2012-03-30 20:50:09 UTC (rev 112720)
+++ trunk/Source/WebKit/blackberry/WebKitSupport/DOMSupport.cpp	2012-03-30 20:51:30 UTC (rev 112721)
@@ -48,6 +48,15 @@
 namespace WebKit {
 namespace DOMSupport {
 
+void visibleTextQuads(const VisibleSelection& selection, Vector<FloatQuad>& quads)
+{
+    if (!selection.isRange())
+        return;
+    ASSERT(selection.firstRange());
+
+    visibleTextQuads(*(selection.firstRange()), quads, true /* useSelectionHeight */);
+}
+
 void visibleTextQuads(const Range& range, Vector<FloatQuad>& quads, bool useSelectionHeight)
 {
     // Range::textQuads includes hidden text, which we don't want.

Modified: trunk/Source/WebKit/blackberry/WebKitSupport/DOMSupport.h (112720 => 112721)


--- trunk/Source/WebKit/blackberry/WebKitSupport/DOMSupport.h	2012-03-30 20:50:09 UTC (rev 112720)
+++ trunk/Source/WebKit/blackberry/WebKitSupport/DOMSupport.h	2012-03-30 20:51:30 UTC (rev 112721)
@@ -67,6 +67,7 @@
 
 WebCore::IntRect transformedBoundingBoxForRange(const WebCore::Range&);
 void visibleTextQuads(const WebCore::Range&, WTF::Vector<WebCore::FloatQuad>& quads, bool useSelectionHeight = false);
+void visibleTextQuads(const WebCore::VisibleSelection&, WTF::Vector<WebCore::FloatQuad>& quads);
 
 WebCore::VisibleSelection visibleSelectionForRangeInputElement(WebCore::Element*, int start, int end);
 WebCore::VisibleSelection visibleSelectionForInputElement(WebCore::Element*);

Modified: trunk/Source/WebKit/blackberry/WebKitSupport/SelectionHandler.cpp (112720 => 112721)


--- trunk/Source/WebKit/blackberry/WebKitSupport/SelectionHandler.cpp	2012-03-30 20:50:09 UTC (rev 112720)
+++ trunk/Source/WebKit/blackberry/WebKitSupport/SelectionHandler.cpp	2012-03-30 20:51:30 UTC (rev 112721)
@@ -24,6 +24,7 @@
 #include "Editor.h"
 #include "EditorClient.h"
 #include "FatFingers.h"
+#include "FloatQuad.h"
 #include "Frame.h"
 #include "FrameSelection.h"
 #include "FrameView.h"
@@ -47,6 +48,8 @@
 
 #include <sys/keycodes.h>
 
+// Note: This generates a lot of logs when dumping rects lists. It will seriously
+// impact performance. Do not enable this during performance tests.
 #define SHOWDEBUG_SELECTIONHANDLER 0
 
 using namespace BlackBerry::Platform;
@@ -91,17 +94,31 @@
     return m_webPage->focusedOrMainFrame()->editor()->selectedText();
 }
 
-void SelectionHandler::getConsolidatedRegionOfTextQuadsForSelection(const VisibleSelection& selection, IntRectRegion& region) const
+WebCore::IntRect SelectionHandler::clippingRectForVisibleContent() const
 {
-    ASSERT(region.isEmpty());
+    // Get the containing content rect for the frame.
+    Frame* frame = m_webPage->focusedOrMainFrame();
+    WebCore::IntRect clipRect = WebCore::IntRect(-1, -1, 0, 0);
+    if (frame != m_webPage->mainFrame()) {
+        clipRect = m_webPage->getRecursiveVisibleWindowRect(frame->view(), true /* no clip to main frame window */);
+        clipRect = m_webPage->m_mainFrame->view()->windowToContents(clipRect);
+    }
 
-    if (!selection.isRange())
-        return;
+    // Get the input field containing box.
+    if (m_webPage->m_inputHandler->isInputMode()
+        && frame->document()->focusedNode()
+        && frame->document()->focusedNode()->renderer()) {
 
-    ASSERT(selection.firstRange());
+        // Adjust the bounding box to the frame offset.
+        clipRect = frame->document()->focusedNode()->renderer()->absoluteBoundingBoxRect();
+        clipRect = m_webPage->mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(clipRect));
+    }
+    return clipRect;
+}
 
-    Vector<FloatQuad> quadList;
-    DOMSupport::visibleTextQuads(*(selection.firstRange()), quadList, true /* use selection height */);
+void SelectionHandler::regionForTextQuads(Vector<FloatQuad> &quadList, IntRectRegion& region, bool shouldClipToVisibleContent) const
+{
+    ASSERT(region.isEmpty());
 
     if (!quadList.isEmpty()) {
         FrameView* frameView = m_webPage->focusedOrMainFrame()->view();
@@ -112,14 +129,24 @@
         // framePosition is in main frame coordinates.
         WebCore::IntPoint framePosition = m_webPage->frameOffset(m_webPage->focusedOrMainFrame());
 
-        // The ranges rect list is based on render elements and may include multiple adjacent rects.
-        // Use IntRectRegion to consolidate these rects into bands as well as a container to pass
-        // to the client.
+        // Get the visibile content rect.
+        WebCore::IntRect clippingRect = shouldClipToVisibleContent ? clippingRectForVisibleContent() : WebCore::IntRect(-1, -1, 0, 0);
+
+        // Convert the text quads into a more platform friendy
+        // IntRectRegion and adjust for subframes.
+        std::vector<Platform::IntRect> adjustedIntRects;
+        Platform::IntRect selectionBoundingBox;
         for (unsigned i = 0; i < quadList.size(); i++) {
             WebCore::IntRect enclosingRect = quadList[i].enclosingBoundingBox();
             enclosingRect.intersect(frameRect);
             enclosingRect.move(framePosition.x(), framePosition.y());
-            region = unionRegions(region, IntRectRegion(enclosingRect));
+            adjustedIntRects.push_back(enclosingRect);
+
+            // Clip to the visible content.
+            if (clippingRect.location() != DOMSupport::InvalidPoint)
+                enclosingRect.intersect(clippingRect);
+
+            selectionBoundingBox = unionOfRects(enclosingRect, selectionBoundingBox);
         }
     }
 }
@@ -489,22 +516,24 @@
     // If the selection size is reduce to less than a character, selection type becomes
     // Caret. As long as it is still a range, it's a valid selection. Selection cannot
     // be cancelled through this function.
-    IntRectRegion region;
-    getConsolidatedRegionOfTextQuadsForSelection(newSelection, region);
-    clipRegionToVisibleContainer(region);
-    if (!region.isEmpty()) {
+    Vector<FloatQuad> quads;
+    DOMSupport::visibleTextQuads(newSelection, quads);
+
+    IntRectRegion unclippedRegion;
+    regionForTextQuads(quads, unclippedRegion, false /* shouldClipToVisibleContent */);
+    if (!unclippedRegion.isEmpty()) {
         // Check if the handles reversed position.
         if (m_selectionActive && !newSelection.isBaseFirst())
             m_webPage->m_client->notifySelectionHandlesReversed();
 
         controller->setSelection(newSelection);
 
-        DEBUG_SELECTION(LogLevelInfo, "SelectionHandler::setSelection selection points valid, selection updated");
+        DEBUG_SELECTION(LogLevelInfo, "SelectionHandler::setSelection selection points valid, selection updated\n");
     } else {
         // Requested selection results in an empty selection, skip this change.
         selectionPositionChanged();
 
-        DEBUG_SELECTION(LogLevelWarn, "SelectionHandler::setSelection selection points invalid, selection not updated");
+        DEBUG_SELECTION(LogLevelWarn, "SelectionHandler::setSelection selection points invalid, selection not updated\n");
     }
 }
 
@@ -741,33 +770,6 @@
     }
 }
 
-void SelectionHandler::clipRegionToVisibleContainer(IntRectRegion& region)
-{
-    ASSERT(m_webPage->m_mainFrame && m_webPage->m_mainFrame->view());
-
-    Frame* frame = m_webPage->focusedOrMainFrame();
-
-    // Don't allow the region to extend outside of the all its ancestor frames' visible area.
-    if (frame != m_webPage->mainFrame()) {
-        WebCore::IntRect containingContentRect;
-        containingContentRect = m_webPage->getRecursiveVisibleWindowRect(frame->view(), true /* no clip to main frame window */);
-        containingContentRect = m_webPage->m_mainFrame->view()->windowToContents(containingContentRect);
-        region = intersectRegions(IntRectRegion(containingContentRect), region);
-    }
-
-    // Don't allow the region to extend outside of the input field.
-    if (m_webPage->m_inputHandler->isInputMode()
-        && frame->document()->focusedNode()
-        && frame->document()->focusedNode()->renderer()) {
-
-        // Adjust the bounding box to the frame offset.
-        WebCore::IntRect boundingBox(frame->document()->focusedNode()->renderer()->absoluteBoundingBoxRect());
-        boundingBox = m_webPage->mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(boundingBox));
-
-        region = intersectRegions(IntRectRegion(boundingBox), region);
-    }
-}
-
 WebCore::IntPoint SelectionHandler::clipPointToVisibleContainer(const WebCore::IntPoint& point) const
 {
     ASSERT(m_webPage->m_mainFrame && m_webPage->m_mainFrame->view());
@@ -801,6 +803,21 @@
     return caretComparisonPointForRect(startCaretBounds, isStartCaret, isRTL);
 }
 
+// Check all rects in the region for a point match. The region is non-banded
+// and non-sorted so all must be checked.
+static bool regionRectListContainsPoint(IntRectRegion& region, WebCore::IntPoint point)
+{
+    if (!region.extents().contains(point))
+        return false;
+
+    std::vector<Platform::IntRect> rectList = region.rects();
+    for (unsigned int i = 0; i < rectList.size(); i++) {
+        if (rectList[i].contains(point))
+            return true;
+    }
+    return false;
+}
+
 // Note: This is the only function in SelectionHandler in which the coordinate
 // system is not entirely WebKit.
 void SelectionHandler::selectionPositionChanged(bool visualChangeOnly)
@@ -838,51 +855,52 @@
     WebCore::IntRect endCaret;
 
     // Get the text rects from the selections range.
-    IntRectRegion region;
-    getConsolidatedRegionOfTextQuadsForSelection(frame->selection()->selection(), region);
+    Vector<FloatQuad> quads;
+    DOMSupport::visibleTextQuads(frame->selection()->selection(), quads);
 
+    IntRectRegion unclippedRegion;
+    regionForTextQuads(quads, unclippedRegion, false /* shouldClipToVisibleContent */);
+
     // If there is no change in selected text and the visual rects
     // have not changed then don't bother notifying anything.
-    if (visualChangeOnly && m_lastSelectionRegion.isEqual(region))
+    if (visualChangeOnly && m_lastSelectionRegion.isEqual(unclippedRegion))
         return;
 
-    m_lastSelectionRegion = region;
+    m_lastSelectionRegion = unclippedRegion;
 
-    if (!region.isEmpty()) {
+    IntRectRegion visibleSelectionRegion;
+    if (!unclippedRegion.isEmpty()) {
         WebCore::IntRect unclippedStartCaret;
         WebCore::IntRect unclippedEndCaret;
 
         bool isRTL = directionOfEnclosingBlock(frame->selection()) == RTL;
 
-        std::vector<Platform::IntRect> rectList = region.rects();
+        WebCore::IntPoint startCaretReferencePoint = referencePoint(frame->selection()->selection().visibleStart(), unclippedRegion.extents(), framePos, true /* isStartCaret */, isRTL);
+        WebCore::IntPoint endCaretReferencePoint = referencePoint(frame->selection()->selection().visibleEnd(), unclippedRegion.extents(), framePos, false /* isStartCaret */, isRTL);
 
-        WebCore::IntPoint startCaretReferencePoint = referencePoint(frame->selection()->selection().visibleStart(), region.extents(), framePos, true /* isStartCaret */, isRTL);
-        WebCore::IntPoint endCaretReferencePoint = referencePoint(frame->selection()->selection().visibleEnd(), region.extents(), framePos, false /* isStartCaret */, isRTL);
+        adjustCaretRects(unclippedStartCaret, false /* unclipped */, unclippedEndCaret, false /* unclipped */, unclippedRegion.rects(), startCaretReferencePoint, endCaretReferencePoint, isRTL);
 
-        adjustCaretRects(unclippedStartCaret, false /* unclipped */, unclippedEndCaret, false /* unclipped */, rectList, startCaretReferencePoint, endCaretReferencePoint, isRTL);
+        regionForTextQuads(quads, visibleSelectionRegion);
 
-        clipRegionToVisibleContainer(region);
-
 #if SHOWDEBUG_SELECTIONHANDLER // Don't rely just on DEBUG_SELECTION to avoid loop.
-        for (unsigned int i = 0; i < rectList.size(); i++)
-            DEBUG_SELECTION(LogLevelCritical, "Rect list - Unmodified #%d, (%d, %d) (%d x %d)", i, rectList[i].x(), rectList[i].y(), rectList[i].width(), rectList[i].height());
-        for (unsigned int i = 0; i < region.numRects(); i++)
-            DEBUG_SELECTION(LogLevelCritical, "Rect list  - Consolidated #%d, (%d, %d) (%d x %d)", i, region.rects()[i].x(), region.rects()[i].y(), region.rects()[i].width(), region.rects()[i].height());
+        for (unsigned int i = 0; i < unclippedRegion.numRects(); i++)
+            DEBUG_SELECTION(LogLevelCritical, "Rect list - Unmodified #%d, (%d, %d) (%d x %d)", i, unclippedRegion.rects()[i].x(), unclippedRegion.rects()[i].y(), unclippedRegion.rects()[i].width(), unclippedRegion.rects()[i].height());
+        for (unsigned int i = 0; i < visibleSelectionRegion.numRects(); i++)
+            DEBUG_SELECTION(LogLevelCritical, "Rect list  - Clipped to Visible #%d, (%d, %d) (%d x %d)", i, visibleSelectionRegion.rects()[i].x(), visibleSelectionRegion.rects()[i].y(), visibleSelectionRegion.rects()[i].width(), visibleSelectionRegion.rects()[i].height());
 #endif
 
         bool shouldCareAboutPossibleClippedOutSelection = frame != m_webPage->mainFrame() || m_webPage->m_inputHandler->isInputMode();
 
-        if (!region.isEmpty() || shouldCareAboutPossibleClippedOutSelection) {
+        if (!visibleSelectionRegion.isEmpty() || shouldCareAboutPossibleClippedOutSelection) {
             // Adjust the handle markers to be at the end of the painted rect. When selecting links
             // and other elements that may have a larger visible area than needs to be rendered a gap
             // can exist between the handle and overlay region.
 
-            bool shouldClipStartCaret = !region.isRectInRegion(unclippedStartCaret);
-            bool shouldClipEndCaret = !region.isRectInRegion(unclippedEndCaret);
+            bool shouldClipStartCaret = !regionRectListContainsPoint(visibleSelectionRegion, unclippedStartCaret.location());
+            bool shouldClipEndCaret = !regionRectListContainsPoint(visibleSelectionRegion, unclippedEndCaret.location());
 
             // Find the top corner and bottom corner.
-            std::vector<Platform::IntRect> clippedRectList = region.rects();
-            adjustCaretRects(startCaret, shouldClipStartCaret, endCaret, shouldClipEndCaret, clippedRectList, startCaretReferencePoint, endCaretReferencePoint, isRTL);
+            adjustCaretRects(startCaret, shouldClipStartCaret, endCaret, shouldClipEndCaret, visibleSelectionRegion.rects(), startCaretReferencePoint, endCaretReferencePoint, isRTL);
 
             // Translate the caret values as they must be in transformed coordinates.
             if (!shouldClipStartCaret) {
@@ -901,7 +919,7 @@
                     startCaret.x(), startCaret.y(), startCaret.width(), startCaret.height(), endCaret.x(), endCaret.y(), endCaret.width(), endCaret.height());
 
 
-    m_webPage->m_client->notifySelectionDetailsChanged(startCaret, endCaret, region);
+    m_webPage->m_client->notifySelectionDetailsChanged(startCaret, endCaret, visibleSelectionRegion);
 }
 
 // NOTE: This function is not in WebKit coordinates.
@@ -930,9 +948,7 @@
         caretLocation.move(frameOffset.x(), frameOffset.y());
 
         // Clip against the containing frame and node boundaries.
-        IntRectRegion region(caretLocation);
-        clipRegionToVisibleContainer(region);
-        caretLocation = region.extents();
+        caretLocation.intersect(clippingRectForVisibleContent());
     }
 
     m_caretActive = !caretLocation.isEmpty();

Modified: trunk/Source/WebKit/blackberry/WebKitSupport/SelectionHandler.h (112720 => 112721)


--- trunk/Source/WebKit/blackberry/WebKitSupport/SelectionHandler.h	2012-03-30 20:50:09 UTC (rev 112720)
+++ trunk/Source/WebKit/blackberry/WebKitSupport/SelectionHandler.h	2012-03-30 20:51:30 UTC (rev 112721)
@@ -23,11 +23,14 @@
 #include "BlackBerryPlatformPrimitives.h"
 #include "TextGranularity.h"
 
+#include <wtf/Vector.h>
+
 namespace WTF {
 class String;
 }
 
 namespace WebCore {
+class FloatQuad;
 class IntPoint;
 class IntRect;
 class Node;
@@ -69,8 +72,8 @@
 
 private:
     void caretPositionChanged();
-    void getConsolidatedRegionOfTextQuadsForSelection(const WebCore::VisibleSelection&, BlackBerry::Platform::IntRectRegion&) const;
-    void clipRegionToVisibleContainer(BlackBerry::Platform::IntRectRegion&);
+    void regionForTextQuads(WTF::Vector<WebCore::FloatQuad>&, BlackBerry::Platform::IntRectRegion&, bool shouldClipToVisibleContent = true) const;
+    WebCore::IntRect clippingRectForVisibleContent() const;
     bool updateOrHandleInputSelection(WebCore::VisibleSelection& newSelection, const WebCore::IntPoint& relativeStart
                                       , const WebCore::IntPoint& relativeEnd);
     WebCore::Node* DOMContainerNodeForVisiblePosition(const WebCore::VisiblePosition&) const;
_______________________________________________
webkit-changes mailing list
[email protected]
http://lists.webkit.org/mailman/listinfo.cgi/webkit-changes

Reply via email to