/* -*- 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/. */ #ifndef MOZILLA_GFX_RECT_H_ #define MOZILLA_GFX_RECT_H_ #include "BaseRect.h" #include "BaseMargin.h" #include "NumericTools.h" #include "Point.h" #include "Tools.h" #include "mozilla/Maybe.h" #include namespace mozilla { template struct IsPixel; namespace gfx { template struct RectTyped; template struct IntMarginTyped: public BaseMargin >, public units { static_assert(IsPixel::value, "'units' must be a coordinate system tag"); typedef BaseMargin > Super; IntMarginTyped() : Super() {} IntMarginTyped(int32_t aTop, int32_t aRight, int32_t aBottom, int32_t aLeft) : Super(aTop, aRight, aBottom, aLeft) {} // XXX When all of the code is ported, the following functions to convert // to and from unknown types should be removed. static IntMarginTyped FromUnknownMargin(const IntMarginTyped& aMargin) { return IntMarginTyped(aMargin.top, aMargin.right, aMargin.bottom, aMargin.left); } IntMarginTyped ToUnknownMargin() const { return IntMarginTyped(this->top, this->right, this->bottom, this->left); } }; typedef IntMarginTyped IntMargin; template struct MarginTyped: public BaseMargin >, public units { static_assert(IsPixel::value, "'units' must be a coordinate system tag"); typedef BaseMargin > Super; MarginTyped() : Super() {} MarginTyped(F aTop, F aRight, F aBottom, F aLeft) : Super(aTop, aRight, aBottom, aLeft) {} explicit MarginTyped(const IntMarginTyped& aMargin) : Super(F(aMargin.top), F(aMargin.right), F(aMargin.bottom), F(aMargin.left)) {} }; typedef MarginTyped Margin; typedef MarginTyped MarginDouble; template IntMarginTyped RoundedToInt(const MarginTyped& aMargin) { return IntMarginTyped(int32_t(floorf(aMargin.top + 0.5f)), int32_t(floorf(aMargin.right + 0.5f)), int32_t(floorf(aMargin.bottom + 0.5f)), int32_t(floorf(aMargin.left + 0.5f))); } template struct IntRectTyped : public BaseRect, IntPointTyped, IntSizeTyped, IntMarginTyped >, public units { static_assert(IsPixel::value, "'units' must be a coordinate system tag"); typedef BaseRect, IntPointTyped, IntSizeTyped, IntMarginTyped > Super; typedef IntRectTyped Self; typedef IntParam ToInt; IntRectTyped() : Super() {} IntRectTyped(const IntPointTyped& aPos, const IntSizeTyped& aSize) : Super(aPos, aSize) {} IntRectTyped(ToInt aX, ToInt aY, ToInt aWidth, ToInt aHeight) : Super(aX.value, aY.value, aWidth.value, aHeight.value) {} static IntRectTyped RoundIn(float aX, float aY, float aW, float aH) { return IntRectTyped::RoundIn(RectTyped(aX, aY, aW, aH)); } static IntRectTyped RoundOut(float aX, float aY, float aW, float aH) { return IntRectTyped::RoundOut(RectTyped(aX, aY, aW, aH)); } static IntRectTyped Round(float aX, float aY, float aW, float aH) { return IntRectTyped::Round(RectTyped(aX, aY, aW, aH)); } static IntRectTyped Truncate(float aX, float aY, float aW, float aH) { return IntRectTyped(IntPointTyped::Truncate(aX, aY), IntSizeTyped::Truncate(aW, aH)); } static IntRectTyped RoundIn(const RectTyped& aRect) { auto tmp(aRect); tmp.RoundIn(); return IntRectTyped(int32_t(tmp.X()), int32_t(tmp.Y()), int32_t(tmp.Width()), int32_t(tmp.Height())); } static IntRectTyped RoundOut(const RectTyped& aRect) { auto tmp(aRect); tmp.RoundOut(); return IntRectTyped(int32_t(tmp.X()), int32_t(tmp.Y()), int32_t(tmp.Width()), int32_t(tmp.Height())); } static IntRectTyped Round(const RectTyped& aRect) { auto tmp(aRect); tmp.Round(); return IntRectTyped(int32_t(tmp.X()), int32_t(tmp.Y()), int32_t(tmp.Width()), int32_t(tmp.Height())); } static IntRectTyped Truncate(const RectTyped& aRect) { return IntRectTyped::Truncate(aRect.X(), aRect.Y(), aRect.Width(), aRect.Height()); } // Rounding isn't meaningful on an integer rectangle. void Round() {} void RoundIn() {} void RoundOut() {} // XXX When all of the code is ported, the following functions to convert // to and from unknown types should be removed. static IntRectTyped FromUnknownRect(const IntRectTyped& rect) { return IntRectTyped(rect.X(), rect.Y(), rect.Width(), rect.Height()); } IntRectTyped ToUnknownRect() const { return IntRectTyped(this->X(), this->Y(), this->Width(), this->Height()); } bool Overflows() const { CheckedInt xMost = this->X(); xMost += this->Width(); CheckedInt yMost = this->Y(); yMost += this->Height(); return !xMost.isValid() || !yMost.isValid(); } // Same as Union(), but in the cases where aRect is non-empty, the union is // done while guarding against overflow. If an overflow is detected, Nothing // is returned. MOZ_MUST_USE Maybe SafeUnion(const Self& aRect) const { if (this->IsEmpty()) { return aRect.Overflows() ? Nothing() : Some(aRect); } else if (aRect.IsEmpty()) { return Some(*static_cast(this)); } else { return this->SafeUnionEdges(aRect); } } // Same as UnionEdges, but guards against overflow. If an overflow is detected, // Nothing is returned. MOZ_MUST_USE Maybe SafeUnionEdges(const Self& aRect) const { if (this->Overflows() || aRect.Overflows()) { return Nothing(); } // If neither |this| nor |aRect| overflow, then their XMost/YMost values // should be safe to use. CheckedInt newX = std::min(this->x, aRect.x); CheckedInt newY = std::min(this->y, aRect.y); CheckedInt newXMost = std::max(this->XMost(), aRect.XMost()); CheckedInt newYMost = std::max(this->YMost(), aRect.YMost()); CheckedInt newW = newXMost - newX; CheckedInt newH = newYMost - newY; if (!newW.isValid() || !newH.isValid()) { return Nothing(); } return Some(Self(newX.value(), newY.value(), newW.value(), newH.value())); } // This is here only to keep IPDL-generated code happy. DO NOT USE. bool operator==(const IntRectTyped& aRect) const { return IntRectTyped::IsEqualEdges(aRect); } void InflateToMultiple(const IntSizeTyped& aTileSize) { if (this->IsEmpty()) { return; } int32_t yMost = this->YMost(); int32_t xMost = this->XMost(); this->x = mozilla::RoundDownToMultiple(this->x, aTileSize.width); this->y = mozilla::RoundDownToMultiple(this->y, aTileSize.height); xMost = mozilla::RoundUpToMultiple(xMost, aTileSize.width); yMost = mozilla::RoundUpToMultiple(yMost, aTileSize.height); this->SetWidth(xMost - this->x); this->SetHeight(yMost - this->y); } }; typedef IntRectTyped IntRect; template struct RectTyped : public BaseRect, PointTyped, SizeTyped, MarginTyped >, public units { static_assert(IsPixel::value, "'units' must be a coordinate system tag"); typedef BaseRect, PointTyped, SizeTyped, MarginTyped > Super; RectTyped() : Super() {} RectTyped(const PointTyped& aPos, const SizeTyped& aSize) : Super(aPos, aSize) {} RectTyped(F _x, F _y, F _width, F _height) : Super(_x, _y, _width, _height) {} explicit RectTyped(const IntRectTyped& rect) : Super(F(rect.X()), F(rect.Y()), F(rect.Width()), F(rect.Height())) {} void NudgeToIntegers() { NudgeToInteger(&(this->x)); NudgeToInteger(&(this->y)); NudgeToInteger(&(this->width)); NudgeToInteger(&(this->height)); } bool ToIntRect(IntRectTyped *aOut) const { *aOut = IntRectTyped(int32_t(this->X()), int32_t(this->Y()), int32_t(this->Width()), int32_t(this->Height())); return RectTyped(F(aOut->X()), F(aOut->Y()), F(aOut->Width()), F(aOut->Height())) .IsEqualEdges(*this); } // XXX When all of the code is ported, the following functions to convert to and from // unknown types should be removed. static RectTyped FromUnknownRect(const RectTyped& rect) { return RectTyped(rect.X(), rect.Y(), rect.Width(), rect.Height()); } RectTyped ToUnknownRect() const { return RectTyped(this->X(), this->Y(), this->Width(), this->Height()); } // This is here only to keep IPDL-generated code happy. DO NOT USE. bool operator==(const RectTyped& aRect) const { return RectTyped::IsEqualEdges(aRect); } }; typedef RectTyped Rect; typedef RectTyped RectDouble; template IntRectTyped RoundedToInt(const RectTyped& aRect) { RectTyped copy(aRect); copy.Round(); return IntRectTyped(int32_t(copy.X()), int32_t(copy.Y()), int32_t(copy.Width()), int32_t(copy.Height())); } template IntRectTyped RoundedIn(const RectTyped& aRect) { return IntRectTyped::RoundIn(aRect); } template IntRectTyped RoundedOut(const RectTyped& aRect) { return IntRectTyped::RoundOut(aRect); } template IntRectTyped TruncatedToInt(const RectTyped& aRect) { return IntRectTyped::Truncate(aRect); } template RectTyped IntRectToRect(const IntRectTyped& aRect) { return RectTyped(aRect.X(), aRect.Y(), aRect.Width(), aRect.Height()); } // Convenience functions for intersecting and unioning two rectangles wrapped in Maybes. template Maybe IntersectMaybeRects(const Maybe& a, const Maybe& b) { if (!a) { return b; } else if (!b) { return a; } else { return Some(a->Intersect(*b)); } } template Maybe UnionMaybeRects(const Maybe& a, const Maybe& b) { if (!a) { return b; } else if (!b) { return a; } else { return Some(a->Union(*b)); } } } // namespace gfx } // namespace mozilla #endif /* MOZILLA_GFX_RECT_H_ */