summaryrefslogtreecommitdiffstats
path: root/layout/generic/ReflowOutput.h
diff options
context:
space:
mode:
Diffstat (limited to 'layout/generic/ReflowOutput.h')
-rw-r--r--layout/generic/ReflowOutput.h280
1 files changed, 280 insertions, 0 deletions
diff --git a/layout/generic/ReflowOutput.h b/layout/generic/ReflowOutput.h
new file mode 100644
index 0000000000..ab71fa75a4
--- /dev/null
+++ b/layout/generic/ReflowOutput.h
@@ -0,0 +1,280 @@
+/* -*- 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/. */
+
+/* struct containing the output from nsIFrame::Reflow */
+
+#ifndef mozilla_ReflowOutput_h
+#define mozilla_ReflowOutput_h
+
+#include "mozilla/EnumeratedRange.h"
+#include "mozilla/WritingModes.h"
+#include "nsBoundingMetrics.h"
+#include "nsRect.h"
+
+//----------------------------------------------------------------------
+
+namespace mozilla {
+struct ReflowInput;
+
+enum class OverflowType : uint8_t { Ink, Scrollable };
+constexpr auto AllOverflowTypes() {
+ return mozilla::MakeInclusiveEnumeratedRange(OverflowType::Ink,
+ OverflowType::Scrollable);
+}
+
+struct OverflowAreas {
+ public:
+ nsRect& InkOverflow() { return mInk; }
+ const nsRect& InkOverflow() const { return mInk; }
+
+ nsRect& ScrollableOverflow() { return mScrollable; }
+ const nsRect& ScrollableOverflow() const { return mScrollable; }
+
+ nsRect& Overflow(OverflowType aType) {
+ return aType == OverflowType::Ink ? InkOverflow() : ScrollableOverflow();
+ }
+ const nsRect& Overflow(OverflowType aType) const {
+ return aType == OverflowType::Ink ? InkOverflow() : ScrollableOverflow();
+ }
+
+ OverflowAreas() = default;
+
+ OverflowAreas(const nsRect& aInkOverflow, const nsRect& aScrollableOverflow)
+ : mInk(aInkOverflow), mScrollable(aScrollableOverflow) {}
+
+ bool operator==(const OverflowAreas& aOther) const {
+ // Scrollable overflow is a point-set rectangle and ink overflow
+ // is a pixel-set rectangle.
+ return InkOverflow().IsEqualInterior(aOther.InkOverflow()) &&
+ ScrollableOverflow().IsEqualEdges(aOther.ScrollableOverflow());
+ }
+
+ bool operator!=(const OverflowAreas& aOther) const {
+ return !(*this == aOther);
+ }
+
+ OverflowAreas operator+(const nsPoint& aPoint) const {
+ OverflowAreas result(*this);
+ result += aPoint;
+ return result;
+ }
+
+ OverflowAreas& operator+=(const nsPoint& aPoint) {
+ mInk += aPoint;
+ mScrollable += aPoint;
+ return *this;
+ }
+
+ void Clear() { SetAllTo(nsRect()); }
+
+ // Mutates |this| by unioning both overflow areas with |aOther|.
+ void UnionWith(const OverflowAreas& aOther);
+
+ // Mutates |this| by unioning both overflow areas with |aRect|.
+ void UnionAllWith(const nsRect& aRect);
+
+ // Mutates |this| by setting both overflow areas to |aRect|.
+ void SetAllTo(const nsRect& aRect);
+
+ // Applies overflow clipping (for e.g. overflow: clip) as needed to both our
+ // overflow rects.
+ void ApplyClipping(const nsRect& aBounds, PhysicalAxes aClipAxes,
+ const nsSize& aOverflowMargin) {
+ ApplyOverflowClippingOnRect(InkOverflow(), aBounds, aClipAxes,
+ aOverflowMargin);
+ ApplyOverflowClippingOnRect(ScrollableOverflow(), aBounds, aClipAxes,
+ aOverflowMargin);
+ }
+
+ // Gets the overflow clipping rect for a given element given a rect to clip,
+ // the frame bounds, a set of axes, and the overflow margin.
+ static nsRect GetOverflowClipRect(const nsRect& aRectToClip,
+ const nsRect& aBounds,
+ PhysicalAxes aClipAxes,
+ const nsSize& aOverflowMargin);
+
+ // Applies the overflow clipping to a given overflow rect, given the frame
+ // bounds, and the physical axes on which to apply the overflow clip.
+ static void ApplyOverflowClippingOnRect(nsRect& aOverflowRect,
+ const nsRect& aBounds,
+ PhysicalAxes aClipAxes,
+ const nsSize& aOverflowMargin);
+
+ private:
+ nsRect mInk;
+ nsRect mScrollable;
+};
+
+} // namespace mozilla
+
+/**
+ * An nsCollapsingMargin represents a vertical collapsing margin between
+ * blocks as described in section 8.3.1 of CSS2,
+ * <URL: http://www.w3.org/TR/REC-CSS2/box.html#collapsing-margins >.
+ *
+ * All adjacent vertical margins collapse, and the resulting margin is
+ * the sum of the largest positive margin included and the smallest (most
+ * negative) negative margin included.
+ */
+struct nsCollapsingMargin {
+ private:
+ nscoord mMostPos; // the largest positive margin included
+ nscoord mMostNeg; // the smallest negative margin included
+
+ public:
+ nsCollapsingMargin() : mMostPos(0), mMostNeg(0) {}
+
+ nsCollapsingMargin(const nsCollapsingMargin& aOther) = default;
+
+ bool operator==(const nsCollapsingMargin& aOther) const {
+ return mMostPos == aOther.mMostPos && mMostNeg == aOther.mMostNeg;
+ }
+
+ bool operator!=(const nsCollapsingMargin& aOther) const {
+ return !(*this == aOther);
+ }
+
+ nsCollapsingMargin& operator=(const nsCollapsingMargin& aOther) = default;
+
+ void Include(nscoord aCoord) {
+ if (aCoord > mMostPos)
+ mMostPos = aCoord;
+ else if (aCoord < mMostNeg)
+ mMostNeg = aCoord;
+ }
+
+ void Include(const nsCollapsingMargin& aOther) {
+ if (aOther.mMostPos > mMostPos) mMostPos = aOther.mMostPos;
+ if (aOther.mMostNeg < mMostNeg) mMostNeg = aOther.mMostNeg;
+ }
+
+ void Zero() {
+ mMostPos = 0;
+ mMostNeg = 0;
+ }
+
+ bool IsZero() const { return (mMostPos == 0) && (mMostNeg == 0); }
+
+ nscoord get() const { return mMostPos + mMostNeg; }
+};
+
+namespace mozilla {
+
+/**
+ * ReflowOutput is initialized by a parent frame as a parameter passing to
+ * Reflow() to allow a child frame to return its desired size and alignment
+ * information.
+ *
+ * ReflowOutput's constructor usually takes a parent frame's WritingMode (or
+ * ReflowInput) because it is more convenient for the parent frame to use the
+ * stored Size() after reflowing the child frame. However, it can actually
+ * accept any WritingMode (or ReflowInput) because SetSize() knows how to
+ * convert a size in any writing mode to the stored writing mode.
+ *
+ * @see nsIFrame::Reflow() for more information.
+ */
+class ReflowOutput {
+ public:
+ explicit ReflowOutput(mozilla::WritingMode aWritingMode)
+ : mSize(aWritingMode), mWritingMode(aWritingMode) {}
+
+ // A convenient constructor to get WritingMode in ReflowInput.
+ explicit ReflowOutput(const ReflowInput& aReflowInput);
+
+ nscoord ISize(mozilla::WritingMode aWritingMode) const {
+ return mSize.ISize(aWritingMode);
+ }
+ nscoord BSize(mozilla::WritingMode aWritingMode) const {
+ return mSize.BSize(aWritingMode);
+ }
+ mozilla::LogicalSize Size(mozilla::WritingMode aWritingMode) const {
+ return mSize.ConvertTo(aWritingMode, mWritingMode);
+ }
+
+ nscoord& ISize(mozilla::WritingMode aWritingMode) {
+ return mSize.ISize(aWritingMode);
+ }
+ nscoord& BSize(mozilla::WritingMode aWritingMode) {
+ return mSize.BSize(aWritingMode);
+ }
+
+ // Set inline and block size from a LogicalSize, converting to our
+ // writing mode as necessary.
+ void SetSize(mozilla::WritingMode aWM, mozilla::LogicalSize aSize) {
+ mSize = aSize.ConvertTo(mWritingMode, aWM);
+ }
+
+ // Set both inline and block size to zero -- no need for a writing mode!
+ void ClearSize() { mSize.SizeTo(mWritingMode, 0, 0); }
+
+ // Width and Height are physical dimensions, independent of writing mode.
+ // Accessing these is slightly more expensive than accessing the logical
+ // dimensions; as far as possible, client code should work purely with logical
+ // dimensions.
+ nscoord Width() const { return mSize.Width(mWritingMode); }
+ nscoord Height() const { return mSize.Height(mWritingMode); }
+ nscoord& Width() {
+ return mWritingMode.IsVertical() ? mSize.BSize(mWritingMode)
+ : mSize.ISize(mWritingMode);
+ }
+ nscoord& Height() {
+ return mWritingMode.IsVertical() ? mSize.ISize(mWritingMode)
+ : mSize.BSize(mWritingMode);
+ }
+
+ nsSize PhysicalSize() const { return mSize.GetPhysicalSize(mWritingMode); }
+
+ // It's only meaningful to consider "ascent" on the block-start side of the
+ // frame, so no need to pass a writing mode argument
+ enum { ASK_FOR_BASELINE = nscoord_MAX };
+ nscoord BlockStartAscent() const { return mBlockStartAscent; }
+ void SetBlockStartAscent(nscoord aAscent) { mBlockStartAscent = aAscent; }
+
+ // Metrics that _exactly_ enclose the text to allow precise MathML placements.
+ nsBoundingMetrics mBoundingMetrics; // [OUT]
+
+ // Carried out block-end margin values. This is the collapsed
+ // (generational) block-end margin value.
+ nsCollapsingMargin mCarriedOutBEndMargin;
+
+ // For frames that have content that overflow their content area
+ // (HasOverflowAreas() is true) these rectangles represent the total
+ // area of the frame including visible overflow, i.e., don't include
+ // overflowing content that is hidden. The rects are in the local
+ // coordinate space of the frame, and should be at least as big as the
+ // desired size. If there is no content that overflows, then the
+ // overflow area is identical to the desired size and should be {0, 0,
+ // width, height}.
+ OverflowAreas mOverflowAreas;
+
+ nsRect& InkOverflow() { return mOverflowAreas.InkOverflow(); }
+ const nsRect& InkOverflow() const { return mOverflowAreas.InkOverflow(); }
+ nsRect& ScrollableOverflow() { return mOverflowAreas.ScrollableOverflow(); }
+ const nsRect& ScrollableOverflow() const {
+ return mOverflowAreas.ScrollableOverflow();
+ }
+
+ // Set all of mOverflowAreas to (0, 0, width, height).
+ void SetOverflowAreasToDesiredBounds();
+
+ // Union all of mOverflowAreas with (0, 0, width, height).
+ void UnionOverflowAreasWithDesiredBounds();
+
+ mozilla::WritingMode GetWritingMode() const { return mWritingMode; }
+
+ private:
+ // Desired size of a frame's border-box.
+ LogicalSize mSize;
+
+ // Baseline (in block direction), or the default value ASK_FOR_BASELINE.
+ nscoord mBlockStartAscent = ASK_FOR_BASELINE;
+
+ mozilla::WritingMode mWritingMode;
+};
+
+} // namespace mozilla
+
+#endif // mozilla_ReflowOutput_h