Bug 655877 - Part 40: Factor out 'distance from point to rect' calculation from text frame selection routine. r=roc
authorCameron McCormack <cam@mcc.id.au>
Wed, 08 Aug 2012 21:37:14 +1000
changeset 101808 9f477f32c157eb2818e0ad98c4c0157a87f3e3b1
parent 101807 5cd1bb53c262021846e607f6478591a3cfa06f2a
child 101809 4823b8b02b27608768166b50c02b8dc12bf4fe43
push id13179
push usercmccormack@mozilla.com
push dateWed, 08 Aug 2012 11:38:10 +0000
treeherdermozilla-inbound@9f477f32c157 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs655877
milestone17.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 655877 - Part 40: Factor out 'distance from point to rect' calculation from text frame selection routine. r=roc
layout/base/nsLayoutUtils.h
layout/generic/nsFrame.cpp
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -35,16 +35,18 @@ class nsHTMLImageElement;
 #include "nsIPrincipal.h"
 #include "gfxPattern.h"
 #include "imgIContainer.h"
 #include "nsCSSPseudoElements.h"
 #include "nsHTMLReflowState.h"
 #include "nsIFrameLoader.h"
 #include "FrameMetrics.h"
 
+#include <limits>
+
 class nsBlockFrame;
 class gfxDrawable;
 
 namespace mozilla {
 namespace dom {
 class Element;
 } // namespace dom
 } // namespace mozilla
@@ -1671,16 +1673,32 @@ public:
    * Shim to nsCSSFrameConstructor::PostRestyleEvent. Exists so that we
    * can avoid including nsCSSFrameConstructor.h and all its dependencies
    * in content files.
    */
   static void PostRestyleEvent(mozilla::dom::Element* aElement,
                                nsRestyleHint aRestyleHint,
                                nsChangeHint aMinChangeHint);
 
+  /**
+   * Updates a pair of x and y distances if a given point is closer to a given
+   * rectangle than the original distance values.  If aPoint is closer to
+   * aRect than aClosestXDistance and aClosestYDistance indicate, then those
+   * two variables are updated with the distance between aPoint and aRect,
+   * and true is returned.  If aPoint is not closer, then aClosestXDistance
+   * and aClosestYDistance are left unchanged, and false is returned.
+   *
+   * Distances are measured in the two dimensions separately; a closer x
+   * distance beats a closer y distance.
+   */
+  template<typename PointType, typename RectType, typename CoordType>
+  static bool PointIsCloserToRect(PointType aPoint, const RectType& aRect,
+                                  CoordType& aClosestXDistance,
+                                  CoordType& aClosestYDistance);
+
 #ifdef DEBUG
   /**
    * Assert that there are no duplicate continuations of the same frame
    * within aFrameList.  Optimize the tests by assuming that all frames
    * in aFrameList have parent aContainer.
    */
   static void
   AssertNoDuplicateContinuations(nsIFrame* aContainer,
@@ -1695,16 +1713,57 @@ public:
 #endif
 
 private:
   static PRUint32 sFontSizeInflationEmPerLine;
   static PRUint32 sFontSizeInflationMinTwips;
   static PRUint32 sFontSizeInflationLineThreshold;
 };
 
+template<typename PointType, typename RectType, typename CoordType>
+/* static */ bool
+nsLayoutUtils::PointIsCloserToRect(PointType aPoint, const RectType& aRect,
+                                   CoordType& aClosestXDistance,
+                                   CoordType& aClosestYDistance)
+{
+  CoordType fromLeft = aPoint.x - aRect.x;
+  CoordType fromRight = aPoint.x - aRect.XMost();
+
+  CoordType xDistance;
+  if (fromLeft >= 0 && fromRight <= 0) {
+    xDistance = 0;
+  } else {
+    xDistance = NS_MIN(abs(fromLeft), abs(fromRight));
+  }
+
+  if (xDistance <= aClosestXDistance) {
+    if (xDistance < aClosestXDistance) {
+      aClosestYDistance = std::numeric_limits<CoordType>::max();
+    }
+
+    CoordType fromTop = aPoint.y - aRect.y;
+    CoordType fromBottom = aPoint.y - aRect.YMost();
+
+    CoordType yDistance;
+    if (fromTop >= 0 && fromBottom <= 0) {
+      yDistance = 0;
+    } else {
+      yDistance = NS_MIN(abs(fromTop), abs(fromBottom));
+    }
+
+    if (yDistance < aClosestYDistance) {
+      aClosestXDistance = xDistance;
+      aClosestYDistance = yDistance;
+      return true;
+    }
+  }
+
+  return false;
+}
+
 namespace mozilla {
   namespace layout {
 
     /**
      * An RAII class which will, for the duration of its lifetime,
      * **if** the frame given is a container for font size inflation,
      * set the current inflation container on the pres context to null
      * (and then, in its destructor, restore the old value).
--- a/layout/generic/nsFrame.cpp
+++ b/layout/generic/nsFrame.cpp
@@ -3411,49 +3411,20 @@ static FrameTarget GetSelectionClosestFr
     nscoord closestXDistance = HUGE_DISTANCE;
     nscoord closestYDistance = HUGE_DISTANCE;
     nsIFrame *closestFrame = nullptr;
 
     for (; kid; kid = kid->GetNextSibling()) {
       if (!SelfIsSelectable(kid, aFlags) || kid->IsEmpty())
         continue;
 
-      nsRect rect = kid->GetRect();
-
-      nscoord fromLeft = aPoint.x - rect.x;
-      nscoord fromRight = aPoint.x - rect.XMost();
-
-      nscoord xDistance;
-      if (fromLeft >= 0 && fromRight <= 0) {
-        xDistance = 0;
-      } else {
-        xDistance = NS_MIN(abs(fromLeft), abs(fromRight));
-      }
-
-      if (xDistance <= closestXDistance)
-      {
-        if (xDistance < closestXDistance)
-          closestYDistance = HUGE_DISTANCE;
-
-        nscoord fromTop = aPoint.y - rect.y;
-        nscoord fromBottom = aPoint.y - rect.YMost();
-
-        nscoord yDistance;
-        if (fromTop >= 0 && fromBottom <= 0)
-          yDistance = 0;
-        else
-          yDistance = NS_MIN(abs(fromTop), abs(fromBottom));
-
-        if (yDistance < closestYDistance)
-        {
-          closestXDistance = xDistance;
-          closestYDistance = yDistance;
-          closestFrame = kid;
-        }
-      }
+      if (nsLayoutUtils::PointIsCloserToRect(aPoint, kid->GetRect(),
+                                             closestXDistance,
+                                             closestYDistance))
+        closestFrame = kid;
     }
     if (closestFrame)
       return GetSelectionClosestFrameForChild(closestFrame, aPoint, aFlags);
   }
   return FrameTarget(aFrame, false, false);
 }
 
 nsIFrame::ContentOffsets OffsetsForSingleFrame(nsIFrame* aFrame, nsPoint aPoint)