mirror of
				https://github.com/mozilla/gecko-dev.git
				synced 2025-11-04 02:09:05 +02:00 
			
		
		
		
	Build errors fixed here: layout/painting/DottedCornerFinder.cpp:33:1: error: no template named 'nsTHashMap' (and similar for layout/painting/DashedCornerFinder.cpp) * Fixed by including nsTHashMap.h layout/painting/WindowRenderer.cpp:186:38: error: use of undeclared identifier 'Rect'; did you mean 'gfx::Rect'? layout/painting/WindowRenderer.cpp:111:18: error: unknown type name 'PersistentBufferProvider'; did you mean 'layers::PersistentBufferProvider'? (and more similar errors for e.g. `PersistentBufferProviderBasic::Create`, etc.) * Fixed by adding 'using' statements. layout/painting/WindowRenderer.cpp:117:8: error: use of undeclared identifier 'gfxPlatform' layout/painting/WindowRenderer.cpp:148:57: error: member access into incomplete type 'mozilla::dom::AnimationEffect' layout/painting/WindowRenderer.cpp:150:16: error: incomplete type 'mozilla::EffectSet' named in nested name specifier layout/painting/WindowRenderer.cpp:211:26: error: member access into incomplete type 'mozilla::nsDisplayList' * Fixed by including these types' headers. layout/painting/HitTestInfo.cpp:67:32: error: use of undeclared identifier 'CompositorHitTestFlags'; did you mean 'gfx::CompositorHitTestFlags'? * Fixed by adding 'using' statement. layout/painting/nsCSSRenderingGradients.cpp:772:26: error: incomplete type 'nsLayoutUtils' named in nested name specifier * Fixed by including nsLayoutUtils.h layout/painting/nsCSSRenderingGradients.h:106:29: error: unknown type name 'gfxPattern' * Fixed with a forward-decl. layout/painting/nsCSSRenderingGradients.h:107:30: error: unknown type name 'gfxRect' * Fixed with an include (can't use a forward-decl here; gfxRect is a typedef and hence can't really be forward-declared). Differential Revision: https://phabricator.services.mozilla.com/D138219
		
			
				
	
	
		
			539 lines
		
	
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			539 lines
		
	
	
	
		
			17 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
 | 
						|
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
 | 
						|
/* This Source Code Form is subject to the terms of the Mozilla Public
 | 
						|
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 | 
						|
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 | 
						|
 | 
						|
#include "DottedCornerFinder.h"
 | 
						|
 | 
						|
#include <utility>
 | 
						|
 | 
						|
#include "BorderCache.h"
 | 
						|
#include "BorderConsts.h"
 | 
						|
#include "nsTHashMap.h"
 | 
						|
 | 
						|
namespace mozilla {
 | 
						|
 | 
						|
using namespace gfx;
 | 
						|
 | 
						|
static inline Float Square(Float x) { return x * x; }
 | 
						|
 | 
						|
static Point PointRotateCCW90(const Point& aP) { return Point(aP.y, -aP.x); }
 | 
						|
 | 
						|
struct BestOverlap {
 | 
						|
  Float overlap;
 | 
						|
  size_t count;
 | 
						|
 | 
						|
  BestOverlap() : overlap(0.0f), count(0) {}
 | 
						|
 | 
						|
  BestOverlap(Float aOverlap, size_t aCount)
 | 
						|
      : overlap(aOverlap), count(aCount) {}
 | 
						|
};
 | 
						|
 | 
						|
static const size_t DottedCornerCacheSize = 256;
 | 
						|
nsTHashMap<FourFloatsHashKey, BestOverlap> DottedCornerCache;
 | 
						|
 | 
						|
DottedCornerFinder::DottedCornerFinder(const Bezier& aOuterBezier,
 | 
						|
                                       const Bezier& aInnerBezier,
 | 
						|
                                       Corner aCorner, Float aBorderRadiusX,
 | 
						|
                                       Float aBorderRadiusY, const Point& aC0,
 | 
						|
                                       Float aR0, const Point& aCn, Float aRn,
 | 
						|
                                       const Size& aCornerDim)
 | 
						|
    : mOuterBezier(aOuterBezier),
 | 
						|
      mInnerBezier(aInnerBezier),
 | 
						|
      mCorner(aCorner),
 | 
						|
      mNormalSign((aCorner == C_TL || aCorner == C_BR) ? -1.0f : 1.0f),
 | 
						|
      mC0(aC0),
 | 
						|
      mCn(aCn),
 | 
						|
      mR0(aR0),
 | 
						|
      mRn(aRn),
 | 
						|
      mMaxR(std::max(aR0, aRn)),
 | 
						|
      mCenterCurveOrigin(mC0.x, mCn.y),
 | 
						|
      mCenterCurveR(0.0),
 | 
						|
      mInnerCurveOrigin(mInnerBezier.mPoints[0].x, mInnerBezier.mPoints[3].y),
 | 
						|
      mBestOverlap(0.0f),
 | 
						|
      mHasZeroBorderWidth(false),
 | 
						|
      mHasMore(true),
 | 
						|
      mMaxCount(aCornerDim.width + aCornerDim.height),
 | 
						|
      mType(OTHER),
 | 
						|
      mI(0),
 | 
						|
      mCount(0) {
 | 
						|
  NS_ASSERTION(mR0 > 0.0f || mRn > 0.0f,
 | 
						|
               "At least one side should have non-zero radius.");
 | 
						|
 | 
						|
  mInnerWidth = fabs(mInnerBezier.mPoints[0].x - mInnerBezier.mPoints[3].x);
 | 
						|
  mInnerHeight = fabs(mInnerBezier.mPoints[0].y - mInnerBezier.mPoints[3].y);
 | 
						|
 | 
						|
  DetermineType(aBorderRadiusX, aBorderRadiusY);
 | 
						|
 | 
						|
  Reset();
 | 
						|
}
 | 
						|
 | 
						|
static bool IsSingleCurve(Float aMinR, Float aMaxR, Float aMinBorderRadius,
 | 
						|
                          Float aMaxBorderRadius) {
 | 
						|
  return aMinR > 0.0f && aMinBorderRadius > aMaxR * 4.0f &&
 | 
						|
         aMinBorderRadius / aMaxBorderRadius > 0.5f;
 | 
						|
}
 | 
						|
 | 
						|
void DottedCornerFinder::DetermineType(Float aBorderRadiusX,
 | 
						|
                                       Float aBorderRadiusY) {
 | 
						|
  // Calculate parameters for the center curve before swap.
 | 
						|
  Float centerCurveWidth = fabs(mC0.x - mCn.x);
 | 
						|
  Float centerCurveHeight = fabs(mC0.y - mCn.y);
 | 
						|
  Point cornerPoint(mCn.x, mC0.y);
 | 
						|
 | 
						|
  bool swapped = false;
 | 
						|
  if (mR0 < mRn) {
 | 
						|
    // Always draw from wider side to thinner side.
 | 
						|
    std::swap(mC0, mCn);
 | 
						|
    std::swap(mR0, mRn);
 | 
						|
    std::swap(mInnerBezier.mPoints[0], mInnerBezier.mPoints[3]);
 | 
						|
    std::swap(mInnerBezier.mPoints[1], mInnerBezier.mPoints[2]);
 | 
						|
    std::swap(mOuterBezier.mPoints[0], mOuterBezier.mPoints[3]);
 | 
						|
    std::swap(mOuterBezier.mPoints[1], mOuterBezier.mPoints[2]);
 | 
						|
    mNormalSign = -mNormalSign;
 | 
						|
    swapped = true;
 | 
						|
  }
 | 
						|
 | 
						|
  // See the comment at mType declaration for each condition.
 | 
						|
 | 
						|
  Float minR = std::min(mR0, mRn);
 | 
						|
  Float minBorderRadius = std::min(aBorderRadiusX, aBorderRadiusY);
 | 
						|
  Float maxBorderRadius = std::max(aBorderRadiusX, aBorderRadiusY);
 | 
						|
  if (IsSingleCurve(minR, mMaxR, minBorderRadius, maxBorderRadius)) {
 | 
						|
    if (mR0 == mRn) {
 | 
						|
      Float borderLength;
 | 
						|
      if (minBorderRadius == maxBorderRadius) {
 | 
						|
        mType = PERFECT;
 | 
						|
        borderLength = M_PI * centerCurveHeight / 2.0f;
 | 
						|
 | 
						|
        mCenterCurveR = centerCurveWidth;
 | 
						|
      } else {
 | 
						|
        mType = SINGLE_CURVE_AND_RADIUS;
 | 
						|
        borderLength =
 | 
						|
            GetQuarterEllipticArcLength(centerCurveWidth, centerCurveHeight);
 | 
						|
      }
 | 
						|
 | 
						|
      Float diameter = mR0 * 2.0f;
 | 
						|
      size_t count = round(borderLength / diameter);
 | 
						|
      if (count % 2) {
 | 
						|
        count++;
 | 
						|
      }
 | 
						|
      mCount = count / 2 - 1;
 | 
						|
      if (mCount > 0) {
 | 
						|
        mBestOverlap = 1.0f - borderLength / (diameter * count);
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      mType = SINGLE_CURVE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (mType == SINGLE_CURVE_AND_RADIUS || mType == SINGLE_CURVE) {
 | 
						|
    Size cornerSize(centerCurveWidth, centerCurveHeight);
 | 
						|
    GetBezierPointsForCorner(&mCenterBezier, mCorner, cornerPoint, cornerSize);
 | 
						|
    if (swapped) {
 | 
						|
      std::swap(mCenterBezier.mPoints[0], mCenterBezier.mPoints[3]);
 | 
						|
      std::swap(mCenterBezier.mPoints[1], mCenterBezier.mPoints[2]);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (minR == 0.0f) {
 | 
						|
    mHasZeroBorderWidth = true;
 | 
						|
  }
 | 
						|
 | 
						|
  if ((mType == SINGLE_CURVE || mType == OTHER) && !mHasZeroBorderWidth) {
 | 
						|
    FindBestOverlap(minR, minBorderRadius, maxBorderRadius);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
bool DottedCornerFinder::HasMore(void) const {
 | 
						|
  if (mHasZeroBorderWidth) {
 | 
						|
    return mI < mMaxCount && mHasMore;
 | 
						|
  }
 | 
						|
 | 
						|
  return mI < mCount;
 | 
						|
}
 | 
						|
 | 
						|
DottedCornerFinder::Result DottedCornerFinder::Next(void) {
 | 
						|
  mI++;
 | 
						|
 | 
						|
  if (mType == PERFECT) {
 | 
						|
    Float phi = mI * 4.0f * mR0 * (1 - mBestOverlap) / mCenterCurveR;
 | 
						|
    if (mCorner == C_TL) {
 | 
						|
      phi = -M_PI / 2.0f - phi;
 | 
						|
    } else if (mCorner == C_TR) {
 | 
						|
      phi = -M_PI / 2.0f + phi;
 | 
						|
    } else if (mCorner == C_BR) {
 | 
						|
      phi = M_PI / 2.0f - phi;
 | 
						|
    } else {
 | 
						|
      phi = M_PI / 2.0f + phi;
 | 
						|
    }
 | 
						|
 | 
						|
    Point C(mCenterCurveOrigin.x + mCenterCurveR * cos(phi),
 | 
						|
            mCenterCurveOrigin.y + mCenterCurveR * sin(phi));
 | 
						|
    return DottedCornerFinder::Result(C, mR0);
 | 
						|
  }
 | 
						|
 | 
						|
  // Find unfilled and filled circles.
 | 
						|
  (void)FindNext(mBestOverlap);
 | 
						|
  if (mHasMore) {
 | 
						|
    (void)FindNext(mBestOverlap);
 | 
						|
  }
 | 
						|
 | 
						|
  return Result(mLastC, mLastR);
 | 
						|
}
 | 
						|
 | 
						|
void DottedCornerFinder::Reset(void) {
 | 
						|
  mLastC = mC0;
 | 
						|
  mLastR = mR0;
 | 
						|
  mLastT = 0.0f;
 | 
						|
  mHasMore = true;
 | 
						|
}
 | 
						|
 | 
						|
void DottedCornerFinder::FindPointAndRadius(Point& C, Float& r,
 | 
						|
                                            const Point& innerTangent,
 | 
						|
                                            const Point& normal, Float t) {
 | 
						|
  // Find radius for the given tangent point on the inner curve such that the
 | 
						|
  // circle is also tangent to the outer curve.
 | 
						|
 | 
						|
  NS_ASSERTION(mType == OTHER, "Wrong mType");
 | 
						|
 | 
						|
  Float lower = 0.0f;
 | 
						|
  Float upper = mMaxR;
 | 
						|
  const Float DIST_MARGIN = 0.1f;
 | 
						|
  for (size_t i = 0; i < MAX_LOOP; i++) {
 | 
						|
    r = (upper + lower) / 2.0f;
 | 
						|
    C = innerTangent + normal * r;
 | 
						|
 | 
						|
    Point Near = FindBezierNearestPoint(mOuterBezier, C, t);
 | 
						|
    Float distSquare = (C - Near).LengthSquare();
 | 
						|
 | 
						|
    if (distSquare > Square(r + DIST_MARGIN)) {
 | 
						|
      lower = r;
 | 
						|
    } else if (distSquare < Square(r - DIST_MARGIN)) {
 | 
						|
      upper = r;
 | 
						|
    } else {
 | 
						|
      break;
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
Float DottedCornerFinder::FindNext(Float overlap) {
 | 
						|
  Float lower = mLastT;
 | 
						|
  Float upper = 1.0f;
 | 
						|
  Float t;
 | 
						|
 | 
						|
  Point C = mLastC;
 | 
						|
  Float r = 0.0f;
 | 
						|
 | 
						|
  Float factor = (1.0f - overlap);
 | 
						|
 | 
						|
  Float circlesDist = 0.0f;
 | 
						|
  Float expectedDist = 0.0f;
 | 
						|
 | 
						|
  const Float DIST_MARGIN = 0.1f;
 | 
						|
  if (mType == SINGLE_CURVE_AND_RADIUS) {
 | 
						|
    r = mR0;
 | 
						|
 | 
						|
    expectedDist = (r + mLastR) * factor;
 | 
						|
 | 
						|
    // Find C_i on the center curve.
 | 
						|
    for (size_t i = 0; i < MAX_LOOP; i++) {
 | 
						|
      t = (upper + lower) / 2.0f;
 | 
						|
      C = GetBezierPoint(mCenterBezier, t);
 | 
						|
 | 
						|
      // Check overlap along arc.
 | 
						|
      circlesDist = GetBezierLength(mCenterBezier, mLastT, t);
 | 
						|
      if (circlesDist < expectedDist - DIST_MARGIN) {
 | 
						|
        lower = t;
 | 
						|
      } else if (circlesDist > expectedDist + DIST_MARGIN) {
 | 
						|
        upper = t;
 | 
						|
      } else {
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  } else if (mType == SINGLE_CURVE) {
 | 
						|
    // Find C_i on the center curve, and calculate r_i.
 | 
						|
    for (size_t i = 0; i < MAX_LOOP; i++) {
 | 
						|
      t = (upper + lower) / 2.0f;
 | 
						|
      C = GetBezierPoint(mCenterBezier, t);
 | 
						|
 | 
						|
      Point Diff = GetBezierDifferential(mCenterBezier, t);
 | 
						|
      Float DiffLength = Diff.Length();
 | 
						|
      if (DiffLength == 0.0f) {
 | 
						|
        // Basically this shouldn't happen.
 | 
						|
        // If differential is 0, we cannot calculate tangent circle,
 | 
						|
        // skip this point.
 | 
						|
        t = (t + upper) / 2.0f;
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
 | 
						|
      Point normal = PointRotateCCW90(Diff / DiffLength) * (-mNormalSign);
 | 
						|
      r = CalculateDistanceToEllipticArc(C, normal, mInnerCurveOrigin,
 | 
						|
                                         mInnerWidth, mInnerHeight);
 | 
						|
 | 
						|
      // Check overlap along arc.
 | 
						|
      circlesDist = GetBezierLength(mCenterBezier, mLastT, t);
 | 
						|
      expectedDist = (r + mLastR) * factor;
 | 
						|
      if (circlesDist < expectedDist - DIST_MARGIN) {
 | 
						|
        lower = t;
 | 
						|
      } else if (circlesDist > expectedDist + DIST_MARGIN) {
 | 
						|
        upper = t;
 | 
						|
      } else {
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    Float distSquareMax = Square(mMaxR * 3.0f);
 | 
						|
    Float circlesDistSquare = 0.0f;
 | 
						|
 | 
						|
    // Find C_i and r_i.
 | 
						|
    for (size_t i = 0; i < MAX_LOOP; i++) {
 | 
						|
      t = (upper + lower) / 2.0f;
 | 
						|
      Point innerTangent = GetBezierPoint(mInnerBezier, t);
 | 
						|
      if ((innerTangent - mLastC).LengthSquare() > distSquareMax) {
 | 
						|
        // It's clear that this tangent point is too far, skip it.
 | 
						|
        upper = t;
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
 | 
						|
      Point Diff = GetBezierDifferential(mInnerBezier, t);
 | 
						|
      Float DiffLength = Diff.Length();
 | 
						|
      if (DiffLength == 0.0f) {
 | 
						|
        // Basically this shouldn't happen.
 | 
						|
        // If differential is 0, we cannot calculate tangent circle,
 | 
						|
        // skip this point.
 | 
						|
        t = (t + upper) / 2.0f;
 | 
						|
        continue;
 | 
						|
      }
 | 
						|
 | 
						|
      Point normal = PointRotateCCW90(Diff / DiffLength) * mNormalSign;
 | 
						|
      FindPointAndRadius(C, r, innerTangent, normal, t);
 | 
						|
 | 
						|
      // Check overlap with direct distance.
 | 
						|
      circlesDistSquare = (C - mLastC).LengthSquare();
 | 
						|
      expectedDist = (r + mLastR) * factor;
 | 
						|
      if (circlesDistSquare < Square(expectedDist - DIST_MARGIN)) {
 | 
						|
        lower = t;
 | 
						|
      } else if (circlesDistSquare > Square(expectedDist + DIST_MARGIN)) {
 | 
						|
        upper = t;
 | 
						|
      } else {
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    circlesDist = sqrt(circlesDistSquare);
 | 
						|
  }
 | 
						|
 | 
						|
  if (mHasZeroBorderWidth) {
 | 
						|
    // When calculating circle around r=0, it may result in wrong radius that
 | 
						|
    // is bigger than previous circle.  Detect it and stop calculating.
 | 
						|
    const Float R_MARGIN = 0.1f;
 | 
						|
    if (mLastR < R_MARGIN && r > mLastR) {
 | 
						|
      mHasMore = false;
 | 
						|
      mLastR = 0.0f;
 | 
						|
      return 0.0f;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  mLastT = t;
 | 
						|
  mLastC = C;
 | 
						|
  mLastR = r;
 | 
						|
 | 
						|
  if (mHasZeroBorderWidth) {
 | 
						|
    const Float T_MARGIN = 0.001f;
 | 
						|
    if (mLastT >= 1.0f - T_MARGIN ||
 | 
						|
        (mLastC - mCn).LengthSquare() < Square(mLastR)) {
 | 
						|
      mHasMore = false;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  if (expectedDist == 0.0f) {
 | 
						|
    return 0.0f;
 | 
						|
  }
 | 
						|
 | 
						|
  return 1.0f - circlesDist * factor / expectedDist;
 | 
						|
}
 | 
						|
 | 
						|
void DottedCornerFinder::FindBestOverlap(Float aMinR, Float aMinBorderRadius,
 | 
						|
                                         Float aMaxBorderRadius) {
 | 
						|
  // If overlap is not calculateable, find it with binary search,
 | 
						|
  // such that there exists i that C_i == C_n with the given overlap.
 | 
						|
 | 
						|
  FourFloats key(aMinR, mMaxR, aMinBorderRadius, aMaxBorderRadius);
 | 
						|
  BestOverlap best;
 | 
						|
  if (DottedCornerCache.Get(key, &best)) {
 | 
						|
    mCount = best.count;
 | 
						|
    mBestOverlap = best.overlap;
 | 
						|
    return;
 | 
						|
  }
 | 
						|
 | 
						|
  Float lower = 0.0f;
 | 
						|
  Float upper = 0.5f;
 | 
						|
  // Start from lower bound to find the minimum number of circles.
 | 
						|
  Float overlap = 0.0f;
 | 
						|
  mBestOverlap = overlap;
 | 
						|
  size_t targetCount = 0;
 | 
						|
 | 
						|
  const Float OVERLAP_MARGIN = 0.1f;
 | 
						|
  for (size_t j = 0; j < MAX_LOOP; j++) {
 | 
						|
    Reset();
 | 
						|
 | 
						|
    size_t count;
 | 
						|
    Float actualOverlap;
 | 
						|
    if (!GetCountAndLastOverlap(overlap, &count, &actualOverlap)) {
 | 
						|
      if (j == 0) {
 | 
						|
        mCount = mMaxCount;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (j == 0) {
 | 
						|
      if (count < 3 || (count == 3 && actualOverlap > 0.5f)) {
 | 
						|
        // |count == 3 && actualOverlap > 0.5f| means there could be
 | 
						|
        // a circle but it is too near from both ends.
 | 
						|
        //
 | 
						|
        // if actualOverlap == 0.0
 | 
						|
        //               1       2       3
 | 
						|
        //   +-------+-------+-------+-------+
 | 
						|
        //   | ##### | ***** | ##### | ##### |
 | 
						|
        //   |#######|*******|#######|#######|
 | 
						|
        //   |###+###|***+***|###+###|###+###|
 | 
						|
        //   |# C_0 #|* C_1 *|# C_2 #|# C_n #|
 | 
						|
        //   | ##### | ***** | ##### | ##### |
 | 
						|
        //   +-------+-------+-------+-------+
 | 
						|
        //                   |
 | 
						|
        //                   V
 | 
						|
        //   +-------+---+-------+---+-------+
 | 
						|
        //   | ##### |   | ##### |   | ##### |
 | 
						|
        //   |#######|   |#######|   |#######|
 | 
						|
        //   |###+###|   |###+###|   |###+###| Find the best overlap to place
 | 
						|
        //   |# C_0 #|   |# C_1 #|   |# C_n #| C_1 at the middle of them
 | 
						|
        //   | ##### |   | ##### |   | ##### |
 | 
						|
        //   +-------+---+-------+---|-------+
 | 
						|
        //
 | 
						|
        // if actualOverlap == 0.5
 | 
						|
        //               1       2     3
 | 
						|
        //   +-------+-------+-------+---+
 | 
						|
        //   | ##### | ***** | ##### |## |
 | 
						|
        //   |#######|*******|##### C_n #|
 | 
						|
        //   |###+###|***+***|###+###+###|
 | 
						|
        //   |# C_0 #|* C_1 *|# C_2 #|###|
 | 
						|
        //   | ##### | ***** | ##### |## |
 | 
						|
        //   +-------+-------+-------+---+
 | 
						|
        //                 |
 | 
						|
        //                 V
 | 
						|
        //   +-------+-+-------+-+-------+
 | 
						|
        //   | ##### | | ##### | | ##### |
 | 
						|
        //   |#######| |#######| |#######|
 | 
						|
        //   |###+###| |###+###| |###+###| Even if we place C_1 at the middle
 | 
						|
        //   |# C_0 #| |# C_1 #| |# C_n #| of them, it's too near from them
 | 
						|
        //   | ##### | | ##### | | ##### |
 | 
						|
        //   +-------+-+-------+-|-------+
 | 
						|
        //                 |
 | 
						|
        //                 V
 | 
						|
        //   +-------+-----------+-------+
 | 
						|
        //   | ##### |           | ##### |
 | 
						|
        //   |#######|           |#######|
 | 
						|
        //   |###+###|           |###+###| Do not draw any circle
 | 
						|
        //   |# C_0 #|           |# C_n #|
 | 
						|
        //   | ##### |           | ##### |
 | 
						|
        //   +-------+-----------+-------+
 | 
						|
        mCount = 0;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      // targetCount should be 2n, as we're searching C_1 to C_n.
 | 
						|
      //
 | 
						|
      //   targetCount = 4
 | 
						|
      //   mCount = 1
 | 
						|
      //               1       2       3       4
 | 
						|
      //   +-------+-------+-------+-------+-------+
 | 
						|
      //   | ##### | ***** | ##### | ***** | ##### |
 | 
						|
      //   |#######|*******|#######|*******|#######|
 | 
						|
      //   |###+###|***+***|###+###|***+***|###+###|
 | 
						|
      //   |# C_0 #|* C_1 *|# C_2 #|* C_3 *|# C_n #|
 | 
						|
      //   | ##### | ***** | ##### | ***** | ##### |
 | 
						|
      //   +-------+-------+-------+-------+-------+
 | 
						|
      //                       1
 | 
						|
      //
 | 
						|
      //   targetCount = 6
 | 
						|
      //   mCount = 2
 | 
						|
      //               1       2       3       4       5       6
 | 
						|
      //   +-------+-------+-------+-------+-------+-------+-------+
 | 
						|
      //   | ##### | ***** | ##### | ***** | ##### | ***** | ##### |
 | 
						|
      //   |#######|*******|#######|*******|#######|*******|#######|
 | 
						|
      //   |###+###|***+***|###+###|***+***|###+###|***+***|###+###|
 | 
						|
      //   |# C_0 #|* C_1 *|# C_2 #|* C_3 *|# C_4 #|* C_5 *|# C_n #|
 | 
						|
      //   | ##### | ***** | ##### | ***** | ##### | ***** | ##### |
 | 
						|
      //   +-------+-------+-------+-------+-------+-------+-------+
 | 
						|
      //                       1               2
 | 
						|
      if (count % 2) {
 | 
						|
        targetCount = count + 1;
 | 
						|
      } else {
 | 
						|
        targetCount = count;
 | 
						|
      }
 | 
						|
 | 
						|
      mCount = targetCount / 2 - 1;
 | 
						|
    }
 | 
						|
 | 
						|
    if (count == targetCount) {
 | 
						|
      mBestOverlap = overlap;
 | 
						|
 | 
						|
      if (fabs(actualOverlap - overlap) < OVERLAP_MARGIN) {
 | 
						|
        break;
 | 
						|
      }
 | 
						|
 | 
						|
      // We started from upper bound, no need to update range when j == 0.
 | 
						|
      if (j > 0) {
 | 
						|
        if (actualOverlap > overlap) {
 | 
						|
          lower = overlap;
 | 
						|
        } else {
 | 
						|
          upper = overlap;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      // |j == 0 && count != targetCount| means that |targetCount = count + 1|,
 | 
						|
      // and we started from upper bound, no need to update range when j == 0.
 | 
						|
      if (j > 0) {
 | 
						|
        if (count > targetCount) {
 | 
						|
          upper = overlap;
 | 
						|
        } else {
 | 
						|
          lower = overlap;
 | 
						|
        }
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    overlap = (upper + lower) / 2.0f;
 | 
						|
  }
 | 
						|
 | 
						|
  if (DottedCornerCache.Count() > DottedCornerCacheSize) {
 | 
						|
    DottedCornerCache.Clear();
 | 
						|
  }
 | 
						|
  DottedCornerCache.InsertOrUpdate(key, BestOverlap(mBestOverlap, mCount));
 | 
						|
}
 | 
						|
 | 
						|
bool DottedCornerFinder::GetCountAndLastOverlap(Float aOverlap, size_t* aCount,
 | 
						|
                                                Float* aActualOverlap) {
 | 
						|
  // Return the number of circles and the last circles' overlap for the
 | 
						|
  // given overlap.
 | 
						|
 | 
						|
  Reset();
 | 
						|
 | 
						|
  const Float T_MARGIN = 0.001f;
 | 
						|
  const Float DIST_MARGIN = 0.1f;
 | 
						|
  const Float DIST_MARGIN_SQUARE = Square(DIST_MARGIN);
 | 
						|
  for (size_t i = 0; i < mMaxCount; i++) {
 | 
						|
    Float actualOverlap = FindNext(aOverlap);
 | 
						|
    if (mLastT >= 1.0f - T_MARGIN ||
 | 
						|
        (mLastC - mCn).LengthSquare() < DIST_MARGIN_SQUARE) {
 | 
						|
      *aCount = i + 1;
 | 
						|
      *aActualOverlap = actualOverlap;
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return false;
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace mozilla
 |