/* -*- 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/. */
/** * A RectAbsolute is similar to a Rect (see BaseRect.h), but represented as * (x1, y1, x2, y2) instead of (x, y, width, height). * * Unless otherwise indicated, methods on this class correspond * to methods on BaseRect. * * The API is currently very bare-bones; it may be extended as needed. * * Do not use this class directly. Subclass it, pass that subclass as the * Sub parameter, and only use that subclass.
*/ template <class T, class Sub, class Point, class Rect> struct BaseRectAbsolute { protected:
T left, top, right, bottom;
public:
BaseRectAbsolute() : left(0), top(0), right(0), bottom(0) {}
BaseRectAbsolute(T aLeft, T aTop, T aRight, T aBottom)
: left(aLeft), top(aTop), right(aRight), bottom(aBottom) {}
MOZ_ALWAYS_INLINE void MoveBy(T aDx, T aDy) {
left += aDx;
right += aDx;
top += aDy;
bottom += aDy;
}
MOZ_ALWAYS_INLINE void MoveBy(const Point& aPoint) {
left += aPoint.x;
right += aPoint.x;
top += aPoint.y;
bottom += aPoint.y;
}
MOZ_ALWAYS_INLINE void SizeTo(T aWidth, T aHeight) {
right = left + aWidth;
bottom = top + aHeight;
}
bool Contains(const Sub& aRect) const { return aRect.IsEmpty() || (left <= aRect.left && aRect.right <= right &&
top <= aRect.top && aRect.bottom <= bottom);
} bool Contains(T aX, T aY) const { return (left <= aX && aX < right && top <= aY && aY < bottom);
}
bool Intersects(const Sub& aRect) const { return !IsEmpty() && !aRect.IsEmpty() && left < aRect.right &&
aRect.left < right && top < aRect.bottom && aRect.top < bottom;
}
void SetEmpty() { left = right = top = bottom = 0; }
// Returns the smallest rectangle that contains both the area of both // this and aRect. Thus, empty input rectangles are ignored. // Note: if both rectangles are empty, returns aRect. // WARNING! This is not safe against overflow, prefer using SafeUnion instead // when dealing with int-based rects.
[[nodiscard]] Sub Union(const Sub& aRect) const { if (IsEmpty()) { return aRect;
} elseif (aRect.IsEmpty()) { return *static_cast<const Sub*>(this);
} else { return UnionEdges(aRect);
}
} // Returns the smallest rectangle that contains both the points (including // edges) of both aRect1 and aRect2. // Thus, empty input rectangles are allowed to affect the result. // WARNING! This is not safe against overflow, prefer using SafeUnionEdges // instead when dealing with int-based rects.
[[nodiscard]] Sub UnionEdges(const Sub& aRect) const {
Sub result;
result.left = std::min(left, aRect.left);
result.top = std::min(top, aRect.top);
result.right = std::max(XMost(), aRect.XMost());
result.bottom = std::max(YMost(), aRect.YMost()); return result;
}
// Scale 'this' by aScale without doing any rounding. void Scale(T aScale) { Scale(aScale, aScale); } // Scale 'this' by aXScale and aYScale, without doing any rounding. void Scale(T aXScale, T aYScale) {
right = XMost() * aXScale;
bottom = YMost() * aYScale;
left = left * aXScale;
top = top * aYScale;
} // Scale 'this' by aScale, converting coordinates to integers so that the // result is the smallest integer-coordinate rectangle containing the // unrounded result. Note: this can turn an empty rectangle into a non-empty // rectangle void ScaleRoundOut(double aScale) { ScaleRoundOut(aScale, aScale); } // Scale 'this' by aXScale and aYScale, converting coordinates to integers so // that the result is the smallest integer-coordinate rectangle containing the // unrounded result. // Note: this can turn an empty rectangle into a non-empty rectangle void ScaleRoundOut(double aXScale, double aYScale) {
right = static_cast<T>(ceil(double(XMost()) * aXScale));
bottom = static_cast<T>(ceil(double(YMost()) * aYScale));
left = static_cast<T>(floor(double(left) * aXScale));
top = static_cast<T>(floor(double(top) * aYScale));
} // Scale 'this' by aScale, converting coordinates to integers so that the // result is the largest integer-coordinate rectangle contained by the // unrounded result. void ScaleRoundIn(double aScale) { ScaleRoundIn(aScale, aScale); } // Scale 'this' by aXScale and aYScale, converting coordinates to integers so // that the result is the largest integer-coordinate rectangle contained by // the unrounded result. void ScaleRoundIn(double aXScale, double aYScale) {
right = static_cast<T>(floor(double(XMost()) * aXScale));
bottom = static_cast<T>(floor(double(YMost()) * aYScale));
left = static_cast<T>(ceil(double(left) * aXScale));
top = static_cast<T>(ceil(double(top) * aYScale));
} // Scale 'this' by 1/aScale, converting coordinates to integers so that the // result is the smallest integer-coordinate rectangle containing the // unrounded result. Note: this can turn an empty rectangle into a non-empty // rectangle void ScaleInverseRoundOut(double aScale) {
ScaleInverseRoundOut(aScale, aScale);
} // Scale 'this' by 1/aXScale and 1/aYScale, converting coordinates to integers // so that the result is the smallest integer-coordinate rectangle containing // the unrounded result. Note: this can turn an empty rectangle into a // non-empty rectangle void ScaleInverseRoundOut(double aXScale, double aYScale) {
right = static_cast<T>(ceil(double(XMost()) / aXScale));
bottom = static_cast<T>(ceil(double(YMost()) / aYScale));
left = static_cast<T>(floor(double(left) / aXScale));
top = static_cast<T>(floor(double(top) / aYScale));
} // Scale 'this' by 1/aScale, converting coordinates to integers so that the // result is the largest integer-coordinate rectangle contained by the // unrounded result. void ScaleInverseRoundIn(double aScale) {
ScaleInverseRoundIn(aScale, aScale);
} // Scale 'this' by 1/aXScale and 1/aYScale, converting coordinates to integers // so that the result is the largest integer-coordinate rectangle contained by // the unrounded result. void ScaleInverseRoundIn(double aXScale, double aYScale) {
right = static_cast<T>(floor(double(XMost()) / aXScale));
bottom = static_cast<T>(floor(double(YMost()) / aYScale));
left = static_cast<T>(ceil(double(left) / aXScale));
top = static_cast<T>(ceil(double(top) / aYScale));
}
/** * Translate this rectangle to be inside aRect. If it doesn't fit inside * aRect then the dimensions that don't fit will be shrunk so that they * do fit. The resulting rect is returned.
*/
[[nodiscard]] Sub MoveInsideAndClamp(const Sub& aRect) const {
T newLeft = std::max(aRect.left, left);
T newTop = std::max(aRect.top, top);
T width = std::min(aRect.Width(), Width());
T height = std::min(aRect.Height(), Height());
Sub rect(newLeft, newTop, newLeft + width, newTop + height);
newLeft = std::min(rect.right, aRect.right) - width;
newTop = std::min(rect.bottom, aRect.bottom) - height;
rect.MoveBy(newLeft - rect.left, newTop - rect.top); return rect;
}
template <class Units> struct IntRectAbsoluteTyped
: public BaseRectAbsolute<int32_t, IntRectAbsoluteTyped<Units>,
IntPointTyped<Units>, IntRectTyped<Units>>, public Units {
static_assert(IsPixel<Units>::value, "'units' must be a coordinate system tag"); typedef BaseRectAbsolute<int32_t, IntRectAbsoluteTyped<Units>,
IntPointTyped<Units>, IntRectTyped<Units>>
Super; typedef IntParam<int32_t> ToInt;
template <class Units> struct RectAbsoluteTyped
: public BaseRectAbsolute<Float, RectAbsoluteTyped<Units>,
PointTyped<Units>, RectTyped<Units>>, public Units {
static_assert(IsPixel<Units>::value, "'units' must be a coordinate system tag"); typedef BaseRectAbsolute<Float, RectAbsoluteTyped<Units>, PointTyped<Units>,
RectTyped<Units>>
Super;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.