gfx/2d/BaseRect.h

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
michael@0 2 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #ifndef MOZILLA_GFX_BASERECT_H_
michael@0 7 #define MOZILLA_GFX_BASERECT_H_
michael@0 8
michael@0 9 #include <algorithm>
michael@0 10 #include <cmath>
michael@0 11
michael@0 12 #include "mozilla/Assertions.h"
michael@0 13 #include "mozilla/FloatingPoint.h"
michael@0 14 #include "mozilla/TypeTraits.h"
michael@0 15
michael@0 16 namespace mozilla {
michael@0 17 namespace gfx {
michael@0 18
michael@0 19 /**
michael@0 20 * Rectangles have two interpretations: a set of (zero-size) points,
michael@0 21 * and a rectangular area of the plane. Most rectangle operations behave
michael@0 22 * the same no matter what interpretation is being used, but some operations
michael@0 23 * differ:
michael@0 24 * -- Equality tests behave differently. When a rectangle represents an area,
michael@0 25 * all zero-width and zero-height rectangles are equal to each other since they
michael@0 26 * represent the empty area. But when a rectangle represents a set of
michael@0 27 * mathematical points, zero-width and zero-height rectangles can be unequal.
michael@0 28 * -- The union operation can behave differently. When rectangles represent
michael@0 29 * areas, taking the union of a zero-width or zero-height rectangle with
michael@0 30 * another rectangle can just ignore the empty rectangle. But when rectangles
michael@0 31 * represent sets of mathematical points, we may need to extend the latter
michael@0 32 * rectangle to include the points of a zero-width or zero-height rectangle.
michael@0 33 *
michael@0 34 * To ensure that these interpretations are explicitly disambiguated, we
michael@0 35 * deny access to the == and != operators and require use of IsEqualEdges and
michael@0 36 * IsEqualInterior instead. Similarly we provide separate Union and UnionEdges
michael@0 37 * methods.
michael@0 38 *
michael@0 39 * Do not use this class directly. Subclass it, pass that subclass as the
michael@0 40 * Sub parameter, and only use that subclass.
michael@0 41 */
michael@0 42 template <class T, class Sub, class Point, class SizeT, class MarginT>
michael@0 43 struct BaseRect {
michael@0 44 T x, y, width, height;
michael@0 45
michael@0 46 // Constructors
michael@0 47 BaseRect() : x(0), y(0), width(0), height(0) {}
michael@0 48 BaseRect(const Point& aOrigin, const SizeT &aSize) :
michael@0 49 x(aOrigin.x), y(aOrigin.y), width(aSize.width), height(aSize.height)
michael@0 50 {
michael@0 51 }
michael@0 52 BaseRect(T aX, T aY, T aWidth, T aHeight) :
michael@0 53 x(aX), y(aY), width(aWidth), height(aHeight)
michael@0 54 {
michael@0 55 }
michael@0 56
michael@0 57 // Emptiness. An empty rect is one that has no area, i.e. its height or width
michael@0 58 // is <= 0
michael@0 59 bool IsEmpty() const { return height <= 0 || width <= 0; }
michael@0 60 void SetEmpty() { width = height = 0; }
michael@0 61
michael@0 62 // "Finite" means not inf and not NaN
michael@0 63 bool IsFinite() const
michael@0 64 {
michael@0 65 typedef typename mozilla::Conditional<mozilla::IsSame<T, float>::value, float, double>::Type FloatType;
michael@0 66 return (mozilla::IsFinite(FloatType(x)) &&
michael@0 67 mozilla::IsFinite(FloatType(y)) &&
michael@0 68 mozilla::IsFinite(FloatType(width)) &&
michael@0 69 mozilla::IsFinite(FloatType(height)));
michael@0 70 }
michael@0 71
michael@0 72 // Returns true if this rectangle contains the interior of aRect. Always
michael@0 73 // returns true if aRect is empty, and always returns false is aRect is
michael@0 74 // nonempty but this rect is empty.
michael@0 75 bool Contains(const Sub& aRect) const
michael@0 76 {
michael@0 77 return aRect.IsEmpty() ||
michael@0 78 (x <= aRect.x && aRect.XMost() <= XMost() &&
michael@0 79 y <= aRect.y && aRect.YMost() <= YMost());
michael@0 80 }
michael@0 81 // Returns true if this rectangle contains the rectangle (aX,aY,1,1).
michael@0 82 bool Contains(T aX, T aY) const
michael@0 83 {
michael@0 84 return x <= aX && aX + 1 <= XMost() &&
michael@0 85 y <= aY && aY + 1 <= YMost();
michael@0 86 }
michael@0 87 // Returns true if this rectangle contains the rectangle (aPoint.x,aPoint.y,1,1).
michael@0 88 bool Contains(const Point& aPoint) const { return Contains(aPoint.x, aPoint.y); }
michael@0 89
michael@0 90 // Intersection. Returns TRUE if the receiver's area has non-empty
michael@0 91 // intersection with aRect's area, and FALSE otherwise.
michael@0 92 // Always returns false if aRect is empty or 'this' is empty.
michael@0 93 bool Intersects(const Sub& aRect) const
michael@0 94 {
michael@0 95 return x < aRect.XMost() && aRect.x < XMost() &&
michael@0 96 y < aRect.YMost() && aRect.y < YMost();
michael@0 97 }
michael@0 98 // Returns the rectangle containing the intersection of the points
michael@0 99 // (including edges) of *this and aRect. If there are no points in that
michael@0 100 // intersection, returns an empty rectangle with x/y set to the std::max of the x/y
michael@0 101 // of *this and aRect.
michael@0 102 Sub Intersect(const Sub& aRect) const
michael@0 103 {
michael@0 104 Sub result;
michael@0 105 result.x = std::max<T>(x, aRect.x);
michael@0 106 result.y = std::max<T>(y, aRect.y);
michael@0 107 result.width = std::min<T>(XMost(), aRect.XMost()) - result.x;
michael@0 108 result.height = std::min<T>(YMost(), aRect.YMost()) - result.y;
michael@0 109 if (result.width < 0 || result.height < 0) {
michael@0 110 result.SizeTo(0, 0);
michael@0 111 }
michael@0 112 return result;
michael@0 113 }
michael@0 114 // Sets *this to be the rectangle containing the intersection of the points
michael@0 115 // (including edges) of *this and aRect. If there are no points in that
michael@0 116 // intersection, sets *this to be an empty rectangle with x/y set to the std::max
michael@0 117 // of the x/y of *this and aRect.
michael@0 118 //
michael@0 119 // 'this' can be the same object as either aRect1 or aRect2
michael@0 120 bool IntersectRect(const Sub& aRect1, const Sub& aRect2)
michael@0 121 {
michael@0 122 *static_cast<Sub*>(this) = aRect1.Intersect(aRect2);
michael@0 123 return !IsEmpty();
michael@0 124 }
michael@0 125
michael@0 126 // Returns the smallest rectangle that contains both the area of both
michael@0 127 // this and aRect2.
michael@0 128 // Thus, empty input rectangles are ignored.
michael@0 129 // If both rectangles are empty, returns this.
michael@0 130 Sub Union(const Sub& aRect) const
michael@0 131 {
michael@0 132 if (IsEmpty()) {
michael@0 133 return aRect;
michael@0 134 } else if (aRect.IsEmpty()) {
michael@0 135 return *static_cast<const Sub*>(this);
michael@0 136 } else {
michael@0 137 return UnionEdges(aRect);
michael@0 138 }
michael@0 139 }
michael@0 140 // Returns the smallest rectangle that contains both the points (including
michael@0 141 // edges) of both aRect1 and aRect2.
michael@0 142 // Thus, empty input rectangles are allowed to affect the result.
michael@0 143 Sub UnionEdges(const Sub& aRect) const
michael@0 144 {
michael@0 145 Sub result;
michael@0 146 result.x = std::min(x, aRect.x);
michael@0 147 result.y = std::min(y, aRect.y);
michael@0 148 result.width = std::max(XMost(), aRect.XMost()) - result.x;
michael@0 149 result.height = std::max(YMost(), aRect.YMost()) - result.y;
michael@0 150 return result;
michael@0 151 }
michael@0 152 // Computes the smallest rectangle that contains both the area of both
michael@0 153 // aRect1 and aRect2, and fills 'this' with the result.
michael@0 154 // Thus, empty input rectangles are ignored.
michael@0 155 // If both rectangles are empty, sets 'this' to aRect2.
michael@0 156 //
michael@0 157 // 'this' can be the same object as either aRect1 or aRect2
michael@0 158 void UnionRect(const Sub& aRect1, const Sub& aRect2)
michael@0 159 {
michael@0 160 *static_cast<Sub*>(this) = aRect1.Union(aRect2);
michael@0 161 }
michael@0 162
michael@0 163 // Computes the smallest rectangle that contains both the points (including
michael@0 164 // edges) of both aRect1 and aRect2.
michael@0 165 // Thus, empty input rectangles are allowed to affect the result.
michael@0 166 //
michael@0 167 // 'this' can be the same object as either aRect1 or aRect2
michael@0 168 void UnionRectEdges(const Sub& aRect1, const Sub& aRect2)
michael@0 169 {
michael@0 170 *static_cast<Sub*>(this) = aRect1.UnionEdges(aRect2);
michael@0 171 }
michael@0 172
michael@0 173 void SetRect(T aX, T aY, T aWidth, T aHeight)
michael@0 174 {
michael@0 175 x = aX; y = aY; width = aWidth; height = aHeight;
michael@0 176 }
michael@0 177 void SetRect(const Point& aPt, const SizeT& aSize)
michael@0 178 {
michael@0 179 SetRect(aPt.x, aPt.y, aSize.width, aSize.height);
michael@0 180 }
michael@0 181 void MoveTo(T aX, T aY) { x = aX; y = aY; }
michael@0 182 void MoveTo(const Point& aPoint) { x = aPoint.x; y = aPoint.y; }
michael@0 183 void MoveBy(T aDx, T aDy) { x += aDx; y += aDy; }
michael@0 184 void MoveBy(const Point& aPoint) { x += aPoint.x; y += aPoint.y; }
michael@0 185 void SizeTo(T aWidth, T aHeight) { width = aWidth; height = aHeight; }
michael@0 186 void SizeTo(const SizeT& aSize) { width = aSize.width; height = aSize.height; }
michael@0 187
michael@0 188 void Inflate(T aD) { Inflate(aD, aD); }
michael@0 189 void Inflate(T aDx, T aDy)
michael@0 190 {
michael@0 191 x -= aDx;
michael@0 192 y -= aDy;
michael@0 193 width += 2 * aDx;
michael@0 194 height += 2 * aDy;
michael@0 195 }
michael@0 196 void Inflate(const MarginT& aMargin)
michael@0 197 {
michael@0 198 x -= aMargin.left;
michael@0 199 y -= aMargin.top;
michael@0 200 width += aMargin.LeftRight();
michael@0 201 height += aMargin.TopBottom();
michael@0 202 }
michael@0 203 void Inflate(const SizeT& aSize) { Inflate(aSize.width, aSize.height); }
michael@0 204
michael@0 205 void Deflate(T aD) { Deflate(aD, aD); }
michael@0 206 void Deflate(T aDx, T aDy)
michael@0 207 {
michael@0 208 x += aDx;
michael@0 209 y += aDy;
michael@0 210 width = std::max(T(0), width - 2 * aDx);
michael@0 211 height = std::max(T(0), height - 2 * aDy);
michael@0 212 }
michael@0 213 void Deflate(const MarginT& aMargin)
michael@0 214 {
michael@0 215 x += aMargin.left;
michael@0 216 y += aMargin.top;
michael@0 217 width = std::max(T(0), width - aMargin.LeftRight());
michael@0 218 height = std::max(T(0), height - aMargin.TopBottom());
michael@0 219 }
michael@0 220 void Deflate(const SizeT& aSize) { Deflate(aSize.width, aSize.height); }
michael@0 221
michael@0 222 // Return true if the rectangles contain the same set of points, including
michael@0 223 // points on the edges.
michael@0 224 // Use when we care about the exact x/y/width/height values being
michael@0 225 // equal (i.e. we care about differences in empty rectangles).
michael@0 226 bool IsEqualEdges(const Sub& aRect) const
michael@0 227 {
michael@0 228 return x == aRect.x && y == aRect.y &&
michael@0 229 width == aRect.width && height == aRect.height;
michael@0 230 }
michael@0 231 // Return true if the rectangles contain the same area of the plane.
michael@0 232 // Use when we do not care about differences in empty rectangles.
michael@0 233 bool IsEqualInterior(const Sub& aRect) const
michael@0 234 {
michael@0 235 return IsEqualEdges(aRect) || (IsEmpty() && aRect.IsEmpty());
michael@0 236 }
michael@0 237
michael@0 238 Sub operator+(const Point& aPoint) const
michael@0 239 {
michael@0 240 return Sub(x + aPoint.x, y + aPoint.y, width, height);
michael@0 241 }
michael@0 242 Sub operator-(const Point& aPoint) const
michael@0 243 {
michael@0 244 return Sub(x - aPoint.x, y - aPoint.y, width, height);
michael@0 245 }
michael@0 246 Sub& operator+=(const Point& aPoint)
michael@0 247 {
michael@0 248 MoveBy(aPoint);
michael@0 249 return *static_cast<Sub*>(this);
michael@0 250 }
michael@0 251 Sub& operator-=(const Point& aPoint)
michael@0 252 {
michael@0 253 MoveBy(-aPoint);
michael@0 254 return *static_cast<Sub*>(this);
michael@0 255 }
michael@0 256
michael@0 257 // Find difference as a Margin
michael@0 258 MarginT operator-(const Sub& aRect) const
michael@0 259 {
michael@0 260 return MarginT(aRect.y - y,
michael@0 261 XMost() - aRect.XMost(),
michael@0 262 YMost() - aRect.YMost(),
michael@0 263 aRect.x - x);
michael@0 264 }
michael@0 265
michael@0 266 // Helpers for accessing the vertices
michael@0 267 Point TopLeft() const { return Point(x, y); }
michael@0 268 Point TopRight() const { return Point(XMost(), y); }
michael@0 269 Point BottomLeft() const { return Point(x, YMost()); }
michael@0 270 Point BottomRight() const { return Point(XMost(), YMost()); }
michael@0 271 Point Center() const { return Point(x, y) + Point(width, height)/2; }
michael@0 272 SizeT Size() const { return SizeT(width, height); }
michael@0 273
michael@0 274 // Helper methods for computing the extents
michael@0 275 T X() const { return x; }
michael@0 276 T Y() const { return y; }
michael@0 277 T Width() const { return width; }
michael@0 278 T Height() const { return height; }
michael@0 279 T XMost() const { return x + width; }
michael@0 280 T YMost() const { return y + height; }
michael@0 281
michael@0 282 // Moves one edge of the rect without moving the opposite edge.
michael@0 283 void SetLeftEdge(T aX) {
michael@0 284 MOZ_ASSERT(aX <= XMost());
michael@0 285 width = XMost() - aX;
michael@0 286 x = aX;
michael@0 287 }
michael@0 288 void SetRightEdge(T aXMost) {
michael@0 289 MOZ_ASSERT(aXMost >= x);
michael@0 290 width = aXMost - x;
michael@0 291 }
michael@0 292 void SetTopEdge(T aY) {
michael@0 293 MOZ_ASSERT(aY <= YMost());
michael@0 294 height = YMost() - aY;
michael@0 295 y = aY;
michael@0 296 }
michael@0 297 void SetBottomEdge(T aYMost) {
michael@0 298 MOZ_ASSERT(aYMost >= y);
michael@0 299 height = aYMost - y;
michael@0 300 }
michael@0 301
michael@0 302 // Round the rectangle edges to integer coordinates, such that the rounded
michael@0 303 // rectangle has the same set of pixel centers as the original rectangle.
michael@0 304 // Edges at offset 0.5 round up.
michael@0 305 // Suitable for most places where integral device coordinates
michael@0 306 // are needed, but note that any translation should be applied first to
michael@0 307 // avoid pixel rounding errors.
michael@0 308 // Note that this is *not* rounding to nearest integer if the values are negative.
michael@0 309 // They are always rounding as floor(n + 0.5).
michael@0 310 // See https://bugzilla.mozilla.org/show_bug.cgi?id=410748#c14
michael@0 311 // If you need similar method which is using NS_round(), you should create
michael@0 312 // new |RoundAwayFromZero()| method.
michael@0 313 void Round()
michael@0 314 {
michael@0 315 T x0 = static_cast<T>(floor(T(X()) + 0.5));
michael@0 316 T y0 = static_cast<T>(floor(T(Y()) + 0.5));
michael@0 317 T x1 = static_cast<T>(floor(T(XMost()) + 0.5));
michael@0 318 T y1 = static_cast<T>(floor(T(YMost()) + 0.5));
michael@0 319
michael@0 320 x = x0;
michael@0 321 y = y0;
michael@0 322
michael@0 323 width = x1 - x0;
michael@0 324 height = y1 - y0;
michael@0 325 }
michael@0 326
michael@0 327 // Snap the rectangle edges to integer coordinates, such that the
michael@0 328 // original rectangle contains the resulting rectangle.
michael@0 329 void RoundIn()
michael@0 330 {
michael@0 331 T x0 = static_cast<T>(ceil(T(X())));
michael@0 332 T y0 = static_cast<T>(ceil(T(Y())));
michael@0 333 T x1 = static_cast<T>(floor(T(XMost())));
michael@0 334 T y1 = static_cast<T>(floor(T(YMost())));
michael@0 335
michael@0 336 x = x0;
michael@0 337 y = y0;
michael@0 338
michael@0 339 width = x1 - x0;
michael@0 340 height = y1 - y0;
michael@0 341 }
michael@0 342
michael@0 343 // Snap the rectangle edges to integer coordinates, such that the
michael@0 344 // resulting rectangle contains the original rectangle.
michael@0 345 void RoundOut()
michael@0 346 {
michael@0 347 T x0 = static_cast<T>(floor(T(X())));
michael@0 348 T y0 = static_cast<T>(floor(T(Y())));
michael@0 349 T x1 = static_cast<T>(ceil(T(XMost())));
michael@0 350 T y1 = static_cast<T>(ceil(T(YMost())));
michael@0 351
michael@0 352 x = x0;
michael@0 353 y = y0;
michael@0 354
michael@0 355 width = x1 - x0;
michael@0 356 height = y1 - y0;
michael@0 357 }
michael@0 358
michael@0 359 // Scale 'this' by aScale without doing any rounding.
michael@0 360 void Scale(T aScale) { Scale(aScale, aScale); }
michael@0 361 // Scale 'this' by aXScale and aYScale, without doing any rounding.
michael@0 362 void Scale(T aXScale, T aYScale)
michael@0 363 {
michael@0 364 T right = XMost() * aXScale;
michael@0 365 T bottom = YMost() * aYScale;
michael@0 366 x = x * aXScale;
michael@0 367 y = y * aYScale;
michael@0 368 width = right - x;
michael@0 369 height = bottom - y;
michael@0 370 }
michael@0 371 // Scale 'this' by aScale, converting coordinates to integers so that the result is
michael@0 372 // the smallest integer-coordinate rectangle containing the unrounded result.
michael@0 373 // Note: this can turn an empty rectangle into a non-empty rectangle
michael@0 374 void ScaleRoundOut(double aScale) { ScaleRoundOut(aScale, aScale); }
michael@0 375 // Scale 'this' by aXScale and aYScale, converting coordinates to integers so
michael@0 376 // that the result is the smallest integer-coordinate rectangle containing the
michael@0 377 // unrounded result.
michael@0 378 // Note: this can turn an empty rectangle into a non-empty rectangle
michael@0 379 void ScaleRoundOut(double aXScale, double aYScale)
michael@0 380 {
michael@0 381 T right = static_cast<T>(ceil(double(XMost()) * aXScale));
michael@0 382 T bottom = static_cast<T>(ceil(double(YMost()) * aYScale));
michael@0 383 x = static_cast<T>(floor(double(x) * aXScale));
michael@0 384 y = static_cast<T>(floor(double(y) * aYScale));
michael@0 385 width = right - x;
michael@0 386 height = bottom - y;
michael@0 387 }
michael@0 388 // Scale 'this' by aScale, converting coordinates to integers so that the result is
michael@0 389 // the largest integer-coordinate rectangle contained by the unrounded result.
michael@0 390 void ScaleRoundIn(double aScale) { ScaleRoundIn(aScale, aScale); }
michael@0 391 // Scale 'this' by aXScale and aYScale, converting coordinates to integers so
michael@0 392 // that the result is the largest integer-coordinate rectangle contained by the
michael@0 393 // unrounded result.
michael@0 394 void ScaleRoundIn(double aXScale, double aYScale)
michael@0 395 {
michael@0 396 T right = static_cast<T>(floor(double(XMost()) * aXScale));
michael@0 397 T bottom = static_cast<T>(floor(double(YMost()) * aYScale));
michael@0 398 x = static_cast<T>(ceil(double(x) * aXScale));
michael@0 399 y = static_cast<T>(ceil(double(y) * aYScale));
michael@0 400 width = std::max<T>(0, right - x);
michael@0 401 height = std::max<T>(0, bottom - y);
michael@0 402 }
michael@0 403 // Scale 'this' by 1/aScale, converting coordinates to integers so that the result is
michael@0 404 // the smallest integer-coordinate rectangle containing the unrounded result.
michael@0 405 // Note: this can turn an empty rectangle into a non-empty rectangle
michael@0 406 void ScaleInverseRoundOut(double aScale) { ScaleInverseRoundOut(aScale, aScale); }
michael@0 407 // Scale 'this' by 1/aXScale and 1/aYScale, converting coordinates to integers so
michael@0 408 // that the result is the smallest integer-coordinate rectangle containing the
michael@0 409 // unrounded result.
michael@0 410 // Note: this can turn an empty rectangle into a non-empty rectangle
michael@0 411 void ScaleInverseRoundOut(double aXScale, double aYScale)
michael@0 412 {
michael@0 413 T right = static_cast<T>(ceil(double(XMost()) / aXScale));
michael@0 414 T bottom = static_cast<T>(ceil(double(YMost()) / aYScale));
michael@0 415 x = static_cast<T>(floor(double(x) / aXScale));
michael@0 416 y = static_cast<T>(floor(double(y) / aYScale));
michael@0 417 width = right - x;
michael@0 418 height = bottom - y;
michael@0 419 }
michael@0 420 // Scale 'this' by 1/aScale, converting coordinates to integers so that the result is
michael@0 421 // the largest integer-coordinate rectangle contained by the unrounded result.
michael@0 422 void ScaleInverseRoundIn(double aScale) { ScaleInverseRoundIn(aScale, aScale); }
michael@0 423 // Scale 'this' by 1/aXScale and 1/aYScale, converting coordinates to integers so
michael@0 424 // that the result is the largest integer-coordinate rectangle contained by the
michael@0 425 // unrounded result.
michael@0 426 void ScaleInverseRoundIn(double aXScale, double aYScale)
michael@0 427 {
michael@0 428 T right = static_cast<T>(floor(double(XMost()) / aXScale));
michael@0 429 T bottom = static_cast<T>(floor(double(YMost()) / aYScale));
michael@0 430 x = static_cast<T>(ceil(double(x) / aXScale));
michael@0 431 y = static_cast<T>(ceil(double(y) / aYScale));
michael@0 432 width = std::max<T>(0, right - x);
michael@0 433 height = std::max<T>(0, bottom - y);
michael@0 434 }
michael@0 435
michael@0 436 /**
michael@0 437 * Clamp aPoint to this rectangle. It is allowed to end up on any
michael@0 438 * edge of the rectangle.
michael@0 439 */
michael@0 440 Point ClampPoint(const Point& aPoint) const
michael@0 441 {
michael@0 442 return Point(std::max(x, std::min(XMost(), aPoint.x)),
michael@0 443 std::max(y, std::min(YMost(), aPoint.y)));
michael@0 444 }
michael@0 445
michael@0 446 /**
michael@0 447 * Clamp this rectangle to be inside aRect. The function returns a copy of
michael@0 448 * this rect after it is forced inside the bounds of aRect. It will attempt to
michael@0 449 * retain the size but will shrink the dimensions that don't fit.
michael@0 450 */
michael@0 451 Sub ForceInside(const Sub& aRect) const
michael@0 452 {
michael@0 453 Sub rect(std::max(aRect.x, x),
michael@0 454 std::max(aRect.y, y),
michael@0 455 std::min(aRect.width, width),
michael@0 456 std::min(aRect.height, height));
michael@0 457 rect.x = std::min(rect.XMost(), aRect.XMost()) - rect.width;
michael@0 458 rect.y = std::min(rect.YMost(), aRect.YMost()) - rect.height;
michael@0 459 return rect;
michael@0 460 }
michael@0 461
michael@0 462 private:
michael@0 463 // Do not use the default operator== or operator!= !
michael@0 464 // Use IsEqualEdges or IsEqualInterior explicitly.
michael@0 465 bool operator==(const Sub& aRect) const { return false; }
michael@0 466 bool operator!=(const Sub& aRect) const { return false; }
michael@0 467 };
michael@0 468
michael@0 469 }
michael@0 470 }
michael@0 471
michael@0 472 #endif /* MOZILLA_GFX_BASERECT_H_ */

mercurial