--- a/layout/generic/nsFloatManager.cpp
+++ b/layout/generic/nsFloatManager.cpp
@@ -579,17 +579,19 @@ public:
const UniquePtr<StyleBasicShape>& aBasicShape,
const LogicalRect& aShapeBoxRect,
WritingMode aWM,
const nsSize& aContainerSize);
static UniquePtr<ShapeInfo> CreateImageShape(
const UniquePtr<nsStyleImage>& aShapeImage,
float aShapeImageThreshold,
+ nscoord aShapeMargin,
nsIFrame* const aFrame,
+ const LogicalRect& aMarginRect,
WritingMode aWM,
const nsSize& aContainerSize);
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.
@@ -966,19 +968,21 @@ nsFloatManager::PolygonShapeInfo::XInter
//
// Implements shape-outside: <image>
//
class nsFloatManager::ImageShapeInfo final : public nsFloatManager::ShapeInfo
{
public:
ImageShapeInfo(uint8_t* aAlphaPixels,
int32_t aStride,
- const CSSIntSize& aSize,
+ const CSSIntSize& aImageSize,
float aShapeImageThreshold,
+ nscoord aShapeMargin,
const nsRect& aContentRect,
+ const nsRect& aMarginRect,
WritingMode aWM,
const nsSize& aContainerSize);
nscoord LineLeft(const nscoord aBStart,
const nscoord aBEnd) const override;
nscoord LineRight(const nscoord aBStart,
const nscoord aBEnd) const override;
nscoord BStart() const override { return mBStart; }
@@ -1022,74 +1026,82 @@ private:
const nsSize& aContainerSize);
};
nsFloatManager::ImageShapeInfo::ImageShapeInfo(
uint8_t* aAlphaPixels,
int32_t aStride,
const CSSIntSize& aImageSize,
float aShapeImageThreshold,
+ nscoord aShapeMargin,
const nsRect& aContentRect,
+ const nsRect& aMarginRect,
WritingMode aWM,
const nsSize& aContainerSize)
{
MOZ_ASSERT(aShapeImageThreshold >=0.0 && aShapeImageThreshold <=1.0,
"The computed value of shape-image-threshold is wrong!");
const uint8_t threshold = NSToIntFloor(aShapeImageThreshold * 255);
const int32_t w = aImageSize.width;
const int32_t h = aImageSize.height;
- // Scan the pixels in a double loop. For horizontal writing modes, we do
- // this row by row, from top to bottom. For vertical writing modes, we do
- // column by column, from left to right. We define the two loops
- // generically, then figure out the rows and cols within the inner loop.
- const int32_t outerLimit = aWM.IsVertical() ? w : h;
- const int32_t innerLimit = aWM.IsVertical() ? h : w;
- for (int32_t outer = 0; outer < outerLimit; ++outer) {
- // min and max store the start and end of the float area for the row
- // or column represented by this iteration of the outer loop.
- int32_t min = -1;
- int32_t max = -1;
+ if (aShapeMargin <= 0) {
+ // Without a positive aShapeMargin, all we have to do is a
+ // direct threshold comparison of the alpha pixels.
+ // https://drafts.csswg.org/css-shapes-1/#valdef-shape-image-threshold-number
+
+ // Scan the pixels in a double loop. For horizontal writing modes, we do
+ // this row by row, from top to bottom. For vertical writing modes, we do
+ // column by column, from left to right. We define the two loops
+ // generically, then figure out the rows and cols within the inner loop.
+ const int32_t outerLimit = aWM.IsVertical() ? w : h;
+ const int32_t innerLimit = aWM.IsVertical() ? h : w;
+ for (int32_t outer = 0; outer < outerLimit; ++outer) {
+ // min and max store the start and end of the float area for the row
+ // or column represented by this iteration of the outer loop.
+ int32_t min = -1;
+ int32_t max = -1;
+
+ for (int32_t inner = 0; inner < innerLimit; ++inner) {
+ const int32_t col = aWM.IsVertical() ? outer : inner;
+ const int32_t row = aWM.IsVertical() ? inner : outer;
- for (int32_t inner = 0; inner < innerLimit; ++inner) {
- const int32_t col = aWM.IsVertical() ? outer : inner;
- const int32_t row = aWM.IsVertical() ? inner : outer;
+ // Determine if the alpha pixel at this row and column has a value
+ // greater than the threshold. If it does, update our min and max values
+ // to track the edges of the float area for this row or column.
+ // https://drafts.csswg.org/css-shapes-1/#valdef-shape-image-threshold-number
+ const uint8_t alpha = aAlphaPixels[col + row * aStride];
+ if (alpha > threshold) {
+ if (min == -1) {
+ min = inner;
+ }
+ MOZ_ASSERT(max < inner);
+ max = inner;
+ }
+ }
- // Determine if the alpha pixel at this row and column has a value
- // greater than the threshold. If it does, update our min and max values
- // to track the edges of the float area for this row or column.
- // https://drafts.csswg.org/css-shapes-1/#valdef-shape-image-threshold-number
- const uint8_t alpha = aAlphaPixels[col + row * aStride];
- if (alpha > threshold) {
- if (min == -1) {
- min = inner;
- }
- MOZ_ASSERT(max < inner);
- max = inner;
+ // At the end of a row or column; did we find something?
+ if (min != -1) {
+ // We need to supply an offset of the content rect top left, since
+ // our col and row have been calculated from the content rect,
+ // instead of the margin rect (against which floats are applied).
+ CreateInterval(min, max, outer, aContentRect.TopLeft(),
+ aWM, aContainerSize);
}
}
- // At the end of a row or column; did we find something?
- if (min != -1) {
- // We need to supply an offset of the content rect top left, since
- // our col and row have been calculated from the content rect,
- // instead of the margin rect (against which floats are applied).
- CreateInterval(min, max, outer, aContentRect.TopLeft(),
- aWM, aContainerSize);
+ if (aWM.IsVerticalRL()) {
+ // Because we scan the columns from left to right, we need to reverse
+ // the array so that it's sorted (in ascending order) on the block
+ // direction.
+ mIntervals.Reverse();
}
}
- if (aWM.IsVerticalRL()) {
- // Because we scan the columns from left to right, we need to reverse
- // the array so that it's sorted (in ascending order) on the block
- // direction.
- mIntervals.Reverse();
- }
-
if (!mIntervals.IsEmpty()) {
mBStart = mIntervals[0].mLineLeft.Y();
mBEnd = mIntervals[mIntervals.Length() - 1].mLineLeft.Y();
}
}
void
nsFloatManager::ImageShapeInfo::CreateInterval(
@@ -1216,16 +1228,32 @@ nsFloatManager::ImageShapeInfo::Translat
mBStart += aBlockStart;
mBEnd += aBlockStart;
}
/////////////////////////////////////////////////////////////////////////////
// FloatInfo
+static bool
+IsPercentOfIndefiniteSize(const nsStyleCoord& aCoord, nscoord aPercentBasis)
+{
+ return aPercentBasis == NS_UNCONSTRAINEDSIZE && aCoord.HasPercent();
+}
+
+static nscoord
+ResolveToDefiniteSize(const nsStyleCoord& aCoord, nscoord aPercentBasis)
+{
+ MOZ_ASSERT(aCoord.IsCoordPercentCalcUnit());
+ if (::IsPercentOfIndefiniteSize(aCoord, aPercentBasis)) {
+ return nscoord(0);
+ }
+ return std::max(nscoord(0), aCoord.ComputeCoordPercentCalc(aPercentBasis));
+}
+
nsFloatManager::FloatInfo::FloatInfo(nsIFrame* aFrame,
nscoord aLineLeft, nscoord aBlockStart,
const LogicalRect& aMarginRect,
WritingMode aWM,
const nsSize& aContainerSize)
: mFrame(aFrame)
, mRect(ShapeInfo::ConvertToFloatLogical(aMarginRect, aWM, aContainerSize) +
nsPoint(aLineLeft, aBlockStart))
@@ -1250,19 +1278,24 @@ nsFloatManager::FloatInfo::FloatInfo(nsI
return;
case StyleShapeSourceType::URL:
MOZ_ASSERT_UNREACHABLE("shape-outside doesn't have URL source type!");
return;
case StyleShapeSourceType::Image: {
float shapeImageThreshold = mFrame->StyleDisplay()->mShapeImageThreshold;
+ nscoord shapeMargin =
+ ::ResolveToDefiniteSize(mFrame->StyleDisplay()->mShapeMargin,
+ aContainerSize.width);
mShapeInfo = ShapeInfo::CreateImageShape(shapeOutside.GetShapeImage(),
shapeImageThreshold,
+ shapeMargin,
mFrame,
+ aMarginRect,
aWM,
aContainerSize);
if (!mShapeInfo) {
// Image is not ready, or fails to load, etc.
return;
}
break;
@@ -1562,17 +1595,19 @@ nsFloatManager::ShapeInfo::CreatePolygon
return MakeUnique<PolygonShapeInfo>(Move(vertices));
}
/* static */ UniquePtr<nsFloatManager::ShapeInfo>
nsFloatManager::ShapeInfo::CreateImageShape(
const UniquePtr<nsStyleImage>& aShapeImage,
float aShapeImageThreshold,
+ nscoord aShapeMargin,
nsIFrame* const aFrame,
+ const LogicalRect& aMarginRect,
WritingMode aWM,
const nsSize& aContainerSize)
{
MOZ_ASSERT(aShapeImage ==
aFrame->StyleDisplay()->mShapeOutside.GetShapeImage(),
"aFrame should be the frame that we got aShapeImage from");
nsImageRenderer imageRenderer(aFrame, aShapeImage.get(),
@@ -1611,22 +1646,28 @@ nsFloatManager::ShapeInfo::CreateImageSh
if (!map.IsMapped()) {
return nullptr;
}
MOZ_ASSERT(sourceSurface->GetSize() == imageIntSize.ToUnknownSize(),
"Who changes the size?");
+ nsRect marginRect = aMarginRect.GetPhysicalRect(aWM, aContainerSize);
+
uint8_t* alphaPixels = map.GetData();
int32_t stride = map.GetStride();
return MakeUnique<ImageShapeInfo>(alphaPixels,
stride,
imageIntSize,
- aShapeImageThreshold, contentRect, aWM,
+ aShapeImageThreshold,
+ aShapeMargin,
+ contentRect,
+ marginRect,
+ aWM,
aContainerSize);
}
/* static */ nscoord
nsFloatManager::ShapeInfo::ComputeEllipseLineInterceptDiff(
const nscoord aShapeBoxBStart, const nscoord aShapeBoxBEnd,
const nscoord aBStartCornerRadiusL, const nscoord aBStartCornerRadiusB,
const nscoord aBEndCornerRadiusL, const nscoord aBEndCornerRadiusB,