--- a/layout/generic/nsFloatManager.cpp
+++ b/layout/generic/nsFloatManager.cpp
@@ -523,16 +523,101 @@ nsFloatManager::ClearContinues(StyleClea
(aBreakType == StyleClear::Both ||
aBreakType == StyleClear::Left)) ||
((mPushedRightFloatPastBreak || mSplitRightFloatAcrossBreak) &&
(aBreakType == StyleClear::Both ||
aBreakType == StyleClear::Right));
}
/////////////////////////////////////////////////////////////////////////////
+// BoxShapeInfo
+
+nscoord
+nsFloatManager::BoxShapeInfo::LineLeft(WritingMode aWM,
+ const nscoord aBStart,
+ const nscoord aBEnd) const
+{
+ nscoord radii[8];
+ bool hasRadii = mFrame->GetShapeBoxBorderRadii(radii);
+
+ if (!hasRadii) {
+ return mShapeBoxRect.x;
+ }
+
+ // Get the physical side for line-left since border-radii are in
+ // the physical axis.
+ mozilla::Side lineLeftSide =
+ aWM.PhysicalSide(aWM.LogicalSideForLineRelativeDir(eLineRelativeDirLeft));
+ nscoord blockStartCornerRadiusL =
+ radii[SideToHalfCorner(lineLeftSide, true, false)];
+ nscoord blockStartCornerRadiusB =
+ radii[SideToHalfCorner(lineLeftSide, true, true)];
+ nscoord blockEndCornerRadiusL =
+ radii[SideToHalfCorner(lineLeftSide, false, false)];
+ nscoord blockEndCornerRadiusB =
+ radii[SideToHalfCorner(lineLeftSide, false, true)];
+
+ if (aWM.IsLineInverted()) {
+ // This happens only when aWM is vertical-lr. Need to swap blockStart
+ // and blockEnd corners.
+ std::swap(blockStartCornerRadiusL, blockEndCornerRadiusL);
+ std::swap(blockStartCornerRadiusB, blockEndCornerRadiusB);
+ }
+
+ nscoord lineLeftDiff =
+ ComputeEllipseLineInterceptDiff(
+ mShapeBoxRect.y, mShapeBoxRect.YMost(),
+ blockStartCornerRadiusL, blockStartCornerRadiusB,
+ blockEndCornerRadiusL, blockEndCornerRadiusB,
+ aBStart, aBEnd);
+ return mShapeBoxRect.x + lineLeftDiff;
+}
+
+nscoord
+nsFloatManager::BoxShapeInfo::LineRight(WritingMode aWM,
+ const nscoord aBStart,
+ const nscoord aBEnd) const
+{
+ nscoord radii[8];
+ bool hasRadii = mFrame->GetShapeBoxBorderRadii(radii);
+
+ if (!hasRadii) {
+ return mShapeBoxRect.XMost();
+ }
+
+ // Get the physical side for line-right since border-radii are in
+ // the physical axis.
+ mozilla::Side lineRightSide =
+ aWM.PhysicalSide(aWM.LogicalSideForLineRelativeDir(eLineRelativeDirRight));
+ nscoord blockStartCornerRadiusL =
+ radii[SideToHalfCorner(lineRightSide, false, false)];
+ nscoord blockStartCornerRadiusB =
+ radii[SideToHalfCorner(lineRightSide, false, true)];
+ nscoord blockEndCornerRadiusL =
+ radii[SideToHalfCorner(lineRightSide, true, false)];
+ nscoord blockEndCornerRadiusB =
+ radii[SideToHalfCorner(lineRightSide, true, true)];
+
+ if (aWM.IsLineInverted()) {
+ // This happens only when aWM is vertical-lr. Need to swap blockStart
+ // and blockEnd corners.
+ std::swap(blockStartCornerRadiusL, blockEndCornerRadiusL);
+ std::swap(blockStartCornerRadiusB, blockEndCornerRadiusB);
+ }
+
+ nscoord lineRightDiff =
+ ComputeEllipseLineInterceptDiff(
+ mShapeBoxRect.y, mShapeBoxRect.YMost(),
+ blockStartCornerRadiusL, blockStartCornerRadiusB,
+ blockEndCornerRadiusL, blockEndCornerRadiusB,
+ aBStart, aBEnd);
+ return mShapeBoxRect.XMost() - lineRightDiff;
+}
+
+/////////////////////////////////////////////////////////////////////////////
// FloatInfo
nsFloatManager::FloatInfo::FloatInfo(nsIFrame* aFrame,
nscoord aLineLeft, nscoord aBlockStart,
const LogicalRect& aMarginRect,
WritingMode aWM,
const nsSize& aContainerSize)
: mFrame(aFrame)
@@ -540,51 +625,56 @@ nsFloatManager::FloatInfo::FloatInfo(nsI
aMarginRect.BStart(aWM) + aBlockStart,
aMarginRect.ISize(aWM),
aMarginRect.BSize(aWM))
{
MOZ_COUNT_CTOR(nsFloatManager::FloatInfo);
const StyleShapeOutside& shapeOutside = mFrame->StyleDisplay()->mShapeOutside;
- if (shapeOutside.GetType() == StyleShapeSourceType::Box) {
- // Initialize shape-box reference rect.
- LogicalRect rect = aMarginRect;
+ if (shapeOutside.GetType() == StyleShapeSourceType::None) {
+ return;
+ }
+
+ // Initialize <shape-box>'s reference rect.
+ LogicalRect rect = aMarginRect;
- switch (shapeOutside.GetReferenceBox()) {
- case StyleShapeOutsideShapeBox::Content:
- rect.Deflate(aWM, mFrame->GetLogicalUsedPadding(aWM));
- MOZ_FALLTHROUGH;
- case StyleShapeOutsideShapeBox::Padding:
- rect.Deflate(aWM, mFrame->GetLogicalUsedBorder(aWM));
- MOZ_FALLTHROUGH;
- case StyleShapeOutsideShapeBox::Border:
- rect.Deflate(aWM, mFrame->GetLogicalUsedMargin(aWM));
- break;
- case StyleShapeOutsideShapeBox::Margin:
- // Do nothing. rect is already a margin rect.
- break;
- case StyleShapeOutsideShapeBox::NoBox:
- MOZ_ASSERT_UNREACHABLE("Why don't we have a shape-box?");
- break;
- }
+ switch (shapeOutside.GetReferenceBox()) {
+ case StyleShapeOutsideShapeBox::Content:
+ rect.Deflate(aWM, mFrame->GetLogicalUsedPadding(aWM));
+ MOZ_FALLTHROUGH;
+ case StyleShapeOutsideShapeBox::Padding:
+ rect.Deflate(aWM, mFrame->GetLogicalUsedBorder(aWM));
+ MOZ_FALLTHROUGH;
+ case StyleShapeOutsideShapeBox::Border:
+ rect.Deflate(aWM, mFrame->GetLogicalUsedMargin(aWM));
+ break;
+ case StyleShapeOutsideShapeBox::Margin:
+ // Do nothing. rect is already a margin rect.
+ break;
+ case StyleShapeOutsideShapeBox::NoBox:
+ MOZ_ASSERT_UNREACHABLE("Why don't we have a shape-box?");
+ break;
+ }
- mShapeBoxRect.emplace(rect.LineLeft(aWM, aContainerSize) + aLineLeft,
- rect.BStart(aWM) + aBlockStart,
- rect.ISize(aWM), rect.BSize(aWM));
+ if (shapeOutside.GetType() == StyleShapeSourceType::Box) {
+ nsRect shapeBoxRect(rect.LineLeft(aWM, aContainerSize) + aLineLeft,
+ rect.BStart(aWM) + aBlockStart,
+ rect.ISize(aWM), rect.BSize(aWM));
+ mShapeInfo = MakeUnique<BoxShapeInfo>(shapeBoxRect, mFrame);
}
}
#ifdef NS_BUILD_REFCNT_LOGGING
nsFloatManager::FloatInfo::FloatInfo(FloatInfo&& aOther)
: mFrame(Move(aOther.mFrame))
, mLeftBEnd(Move(aOther.mLeftBEnd))
, mRightBEnd(Move(aOther.mRightBEnd))
, mRect(Move(aOther.mRect))
- , mShapeBoxRect(Move(aOther.mShapeBoxRect))
+ , mShapeInfo(Move(aOther.mShapeInfo))
{
MOZ_COUNT_CTOR(nsFloatManager::FloatInfo);
}
nsFloatManager::FloatInfo::~FloatInfo()
{
MOZ_COUNT_DTOR(nsFloatManager::FloatInfo);
}
@@ -596,123 +686,69 @@ nsFloatManager::FloatInfo::LineLeft(Writ
const nscoord aBStart,
const nscoord aBEnd) const
{
if (aShapeType == ShapeType::Margin) {
return LineLeft();
}
MOZ_ASSERT(aShapeType == ShapeType::ShapeOutside);
- const StyleShapeOutside& shapeOutside = mFrame->StyleDisplay()->mShapeOutside;
- if (shapeOutside.GetType() == StyleShapeSourceType::None) {
+ if (!mShapeInfo) {
return LineLeft();
}
-
- if (shapeOutside.GetType() == StyleShapeSourceType::Box) {
- nscoord radii[8];
- bool hasRadii = mFrame->GetShapeBoxBorderRadii(radii);
-
- if (!hasRadii) {
- return ShapeBoxRect().x;
- }
-
- // Get the physical side for line-left since border-radii are in
- // the physical axis.
- mozilla::Side lineLeftSide =
- aWM.PhysicalSide(aWM.LogicalSideForLineRelativeDir(eLineRelativeDirLeft));
- nscoord blockStartCornerRadiusL =
- radii[SideToHalfCorner(lineLeftSide, true, false)];
- nscoord blockStartCornerRadiusB =
- radii[SideToHalfCorner(lineLeftSide, true, true)];
- nscoord blockEndCornerRadiusL =
- radii[SideToHalfCorner(lineLeftSide, false, false)];
- nscoord blockEndCornerRadiusB =
- radii[SideToHalfCorner(lineLeftSide, false, true)];
-
- if (aWM.IsLineInverted()) {
- // This happens only when aWM is vertical-lr. Need to swap blockStart
- // and blockEnd corners.
- std::swap(blockStartCornerRadiusL, blockEndCornerRadiusL);
- std::swap(blockStartCornerRadiusB, blockEndCornerRadiusB);
- }
-
- nscoord lineLeftDiff =
- ComputeEllipseLineInterceptDiff(
- ShapeBoxRect().y, ShapeBoxRect().YMost(),
- blockStartCornerRadiusL, blockStartCornerRadiusB,
- blockEndCornerRadiusL, blockEndCornerRadiusB,
- aBStart, aBEnd);
- return ShapeBoxRect().x + lineLeftDiff;
- }
-
- // XXX: Other shape source types are not implemented yet.
-
- return LineLeft();
+ return mShapeInfo->LineLeft(aWM, aBStart, aBEnd);
}
nscoord
nsFloatManager::FloatInfo::LineRight(WritingMode aWM,
ShapeType aShapeType,
const nscoord aBStart,
const nscoord aBEnd) const
{
if (aShapeType == ShapeType::Margin) {
return LineRight();
}
MOZ_ASSERT(aShapeType == ShapeType::ShapeOutside);
- const StyleShapeOutside& shapeOutside = mFrame->StyleDisplay()->mShapeOutside;
- if (shapeOutside.GetType() == StyleShapeSourceType::None) {
+ if (!mShapeInfo) {
return LineRight();
}
+ return mShapeInfo->LineRight(aWM, aBStart, aBEnd);
+}
+
+nscoord
+nsFloatManager::FloatInfo::BStart(ShapeType aShapeType) const
+{
+ if (aShapeType == ShapeType::Margin) {
+ return BStart();
+ }
- if (shapeOutside.GetType() == StyleShapeSourceType::Box) {
- nscoord radii[8];
- bool hasRadii = mFrame->GetShapeBoxBorderRadii(radii);
-
- if (!hasRadii) {
- return ShapeBoxRect().XMost();
- }
+ MOZ_ASSERT(aShapeType == ShapeType::ShapeOutside);
+ if (!mShapeInfo) {
+ return BStart();
+ }
+ return mShapeInfo->BStart();
+}
- // Get the physical side for line-right since border-radii are in
- // the physical axis.
- mozilla::Side lineRightSide =
- aWM.PhysicalSide(aWM.LogicalSideForLineRelativeDir(eLineRelativeDirRight));
- nscoord blockStartCornerRadiusL =
- radii[SideToHalfCorner(lineRightSide, false, false)];
- nscoord blockStartCornerRadiusB =
- radii[SideToHalfCorner(lineRightSide, false, true)];
- nscoord blockEndCornerRadiusL =
- radii[SideToHalfCorner(lineRightSide, true, false)];
- nscoord blockEndCornerRadiusB =
- radii[SideToHalfCorner(lineRightSide, true, true)];
-
- if (aWM.IsLineInverted()) {
- // This happens only when aWM is vertical-lr. Need to swap blockStart
- // and blockEnd corners.
- std::swap(blockStartCornerRadiusL, blockEndCornerRadiusL);
- std::swap(blockStartCornerRadiusB, blockEndCornerRadiusB);
- }
-
- nscoord lineRightDiff =
- ComputeEllipseLineInterceptDiff(
- ShapeBoxRect().y, ShapeBoxRect().YMost(),
- blockStartCornerRadiusL, blockStartCornerRadiusB,
- blockEndCornerRadiusL, blockEndCornerRadiusB,
- aBStart, aBEnd);
- return ShapeBoxRect().XMost() - lineRightDiff;
+nscoord
+nsFloatManager::FloatInfo::BEnd(ShapeType aShapeType) const
+{
+ if (aShapeType == ShapeType::Margin) {
+ return BEnd();
}
- // XXX: Other shape source types are not implemented yet.
-
- return LineRight();
+ MOZ_ASSERT(aShapeType == ShapeType::ShapeOutside);
+ if (!mShapeInfo) {
+ return BEnd();
+ }
+ return mShapeInfo->BEnd();
}
/* static */ nscoord
-nsFloatManager::FloatInfo::ComputeEllipseLineInterceptDiff(
+nsFloatManager::ShapeInfo::ComputeEllipseLineInterceptDiff(
const nscoord aShapeBoxBStart, const nscoord aShapeBoxBEnd,
const nscoord aBStartCornerRadiusL, const nscoord aBStartCornerRadiusB,
const nscoord aBEndCornerRadiusL, const nscoord aBEndCornerRadiusB,
const nscoord aBandBStart, const nscoord aBandBEnd)
{
// An example for the band intersecting with the top right corner of an
// ellipse with writing-mode horizontal-tb.
//
@@ -772,17 +808,17 @@ nsFloatManager::FloatInfo::ComputeEllips
XInterceptAtY(b, aBEndCornerRadiusL, aBEndCornerRadiusB);
lineDiff = aBEndCornerRadiusL - lineIntercept;
}
return lineDiff;
}
/* static */ nscoord
-nsFloatManager::FloatInfo::XInterceptAtY(const nscoord aY,
+nsFloatManager::ShapeInfo::XInterceptAtY(const nscoord aY,
const nscoord aRadiusX,
const nscoord aRadiusY)
{
// Solve for x in the ellipse equation (x/radiusX)^2 + (y/radiusY)^2 = 1.
MOZ_ASSERT(aRadiusY > 0);
return aRadiusX * std::sqrt(1 - (aY * aY) / double(aRadiusY * aRadiusY));
}
--- a/layout/generic/nsFloatManager.h
+++ b/layout/generic/nsFloatManager.h
@@ -5,17 +5,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
/* class that manages rules for positioning floats */
#ifndef nsFloatManager_h_
#define nsFloatManager_h_
#include "mozilla/Attributes.h"
-#include "mozilla/Maybe.h"
+#include "mozilla/UniquePtr.h"
#include "mozilla/WritingModes.h"
#include "nsCoord.h"
#include "nsFrameList.h" // for DEBUG_FRAME_DUMP
#include "nsIntervalSet.h"
#include "nsTArray.h"
class nsIPresShell;
class nsIFrame;
@@ -327,16 +327,80 @@ public:
/**
* Dump the state of the float manager out to a file.
*/
nsresult List(FILE* out) const;
#endif
private:
+ // ShapeInfo is an abstract class for implementing all the shapes in CSS
+ // Shapes Module. A subclass needs to override all the methods to adjust
+ // the flow area with respect to its shape.
+ class ShapeInfo
+ {
+ public:
+ virtual ~ShapeInfo() {}
+
+ virtual nscoord LineLeft(mozilla::WritingMode aWM,
+ const nscoord aBStart,
+ const nscoord aBEnd) const = 0;
+ virtual nscoord LineRight(mozilla::WritingMode aWM,
+ const nscoord aBStart,
+ const nscoord aBEnd) const = 0;
+ virtual nscoord BStart() const = 0;
+ virtual nscoord BEnd() const = 0;
+
+ protected:
+ // Compute the minimum line-axis difference between the bounding shape
+ // box and its rounded corner within the given band (block-axis region).
+ // This is used as a helper function to compute the LineRight() and
+ // LineLeft(). See the picture in the implementation for an example.
+ // RadiusL and RadiusB stand for radius on the line-axis and block-axis.
+ //
+ // Returns radius-x diff on the line-axis, or 0 if there's no rounded
+ // corner within the given band.
+ static nscoord ComputeEllipseLineInterceptDiff(
+ const nscoord aShapeBoxBStart, const nscoord aShapeBoxBEnd,
+ const nscoord aBStartCornerRadiusL, const nscoord aBStartCornerRadiusB,
+ const nscoord aBEndCornerRadiusL, const nscoord aBEndCornerRadiusB,
+ const nscoord aBandBStart, const nscoord aBandBEnd);
+
+ static nscoord XInterceptAtY(const nscoord aY, const nscoord aRadiusX,
+ const nscoord aRadiusY);
+ };
+
+ // Implements shape-outside: <shape-box>.
+ class BoxShapeInfo final : public ShapeInfo
+ {
+ public:
+ BoxShapeInfo(const nsRect& aShapeBoxRect, nsIFrame* const aFrame)
+ : mShapeBoxRect(aShapeBoxRect)
+ , mFrame(aFrame)
+ {
+ }
+
+ nscoord LineLeft(mozilla::WritingMode aWM,
+ const nscoord aBStart,
+ const nscoord aBEnd) const override;
+ nscoord LineRight(mozilla::WritingMode aWM,
+ const nscoord aBStart,
+ const nscoord aBEnd) const override;
+ nscoord BStart() const override { return mShapeBoxRect.y; }
+ nscoord BEnd() const override { return mShapeBoxRect.YMost(); }
+
+ private:
+ // This is the reference box of css shape-outside if specified, which
+ // implements the <shape-box> value in the CSS Shapes Module Level 1.
+ // The coordinate space is the same as FloatInfo::mRect.
+ const nsRect mShapeBoxRect;
+ // The frame of the float.
+ nsIFrame* const mFrame;
+ };
+
struct FloatInfo {
nsIFrame *const mFrame;
// The lowest block-ends of left/right floats up to and including
// this one.
nscoord mLeftBEnd, mRightBEnd;
FloatInfo(nsIFrame* aFrame, nscoord aLineLeft, nscoord aBlockStart,
const mozilla::LogicalRect& aMarginRect,
@@ -345,68 +409,41 @@ private:
nscoord LineLeft() const { return mRect.x; }
nscoord LineRight() const { return mRect.XMost(); }
nscoord ISize() const { return mRect.width; }
nscoord BStart() const { return mRect.y; }
nscoord BEnd() const { return mRect.YMost(); }
nscoord BSize() const { return mRect.height; }
bool IsEmpty() const { return mRect.IsEmpty(); }
- nsRect ShapeBoxRect() const { return mShapeBoxRect.valueOr(mRect); }
-
// aBStart and aBEnd are the starting and ending coordinate of a band.
// LineLeft() and LineRight() return the innermost line-left extent and
// line-right extent within the given band, respectively.
nscoord LineLeft(mozilla::WritingMode aWM, ShapeType aShapeType,
const nscoord aBStart, const nscoord aBEnd) const;
nscoord LineRight(mozilla::WritingMode aWM, ShapeType aShapeType,
const nscoord aBStart, const nscoord aBEnd) const;
-
- nscoord BStart(ShapeType aShapeType) const
- {
- return aShapeType == ShapeType::Margin ? BStart() : ShapeBoxRect().y;
- }
- nscoord BEnd(ShapeType aShapeType) const
- {
- return aShapeType == ShapeType::Margin ? BEnd() : ShapeBoxRect().YMost();
- }
-
- // Compute the minimum line-axis difference between the bounding shape
- // box and its rounded corner within the given band (block-axis region).
- // This is used as a helper function to compute the LineRight() and
- // LineLeft(). See the picture in the implementation for an example.
- // RadiusL and RadiusB stand for radius on the line-axis and block-axis.
- //
- // Returns radius-x diff on the line-axis, or 0 if there's no rounded
- // corner within the given band.
- static nscoord ComputeEllipseLineInterceptDiff(
- const nscoord aShapeBoxBStart, const nscoord aShapeBoxBEnd,
- const nscoord aBStartCornerRadiusL, const nscoord aBStartCornerRadiusB,
- const nscoord aBEndCornerRadiusL, const nscoord aBEndCornerRadiusB,
- const nscoord aBandBStart, const nscoord aBandBEnd);
-
- static nscoord XInterceptAtY(const nscoord aY, const nscoord aRadiusX,
- const nscoord aRadiusY);
+ nscoord BStart(ShapeType aShapeType) const;
+ nscoord BEnd(ShapeType aShapeType) const;
#ifdef NS_BUILD_REFCNT_LOGGING
FloatInfo(FloatInfo&& aOther);
~FloatInfo();
#endif
// NB! This is really a logical rect in a writing mode suitable for
// placing floats, which is not necessarily the actual writing mode
// either of the block which created the frame manager or the block
// that is calling the frame manager. The inline coordinates are in
// the line-relative axis of the frame manager and its block
// coordinates are in the frame manager's real block direction.
nsRect mRect;
- // This is the reference box of css shape-outside if specified, which
- // implements the <shape-box> value in the CSS Shapes Module Level 1.
- // The coordinate setup is the same as mRect.
- mozilla::Maybe<nsRect> mShapeBoxRect;
+ // Pointer to a concrete subclass of ShapeInfo or null, which means that
+ // there is no shape-outside.
+ mozilla::UniquePtr<ShapeInfo> mShapeInfo;
};
#ifdef DEBUG
// Store the writing mode from the block frame which establishes the block
// formatting context (BFC) when the nsFloatManager is created.
mozilla::WritingMode mWritingMode;
#endif