mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-20 16:55:40 +00:00
Bug 1265342 Part 6b: Implement shape-margin for shape-outside: inset, for general case of shape-margin > 0. r=dholbert
MozReview-Commit-ID: 4pjALPSIBhI --HG-- extra : rebase_source : 017c887e4f8d6f2ca0c2293fcb910b0daec1e06d
This commit is contained in:
parent
df2128a244
commit
24f86cb132
@ -1035,6 +1035,23 @@ public:
|
||||
void Translate(nscoord aLineLeft, nscoord aBlockStart) override
|
||||
{
|
||||
mRect.MoveBy(aLineLeft, aBlockStart);
|
||||
|
||||
if (mShapeMargin > 0) {
|
||||
MOZ_ASSERT(mLogicalTopLeftCorner && mLogicalTopRightCorner &&
|
||||
mLogicalBottomLeftCorner && mLogicalBottomRightCorner,
|
||||
"If we have positive shape-margin, we should have corners.");
|
||||
mLogicalTopLeftCorner->Translate(aLineLeft, aBlockStart);
|
||||
mLogicalTopRightCorner->Translate(aLineLeft, aBlockStart);
|
||||
mLogicalBottomLeftCorner->Translate(aLineLeft, aBlockStart);
|
||||
mLogicalBottomRightCorner->Translate(aLineLeft, aBlockStart);
|
||||
}
|
||||
}
|
||||
|
||||
static bool EachCornerHasBalancedRadii(const nscoord* aRadii) {
|
||||
return (aRadii[eCornerTopLeftX] == aRadii[eCornerTopLeftY] &&
|
||||
aRadii[eCornerTopRightX] == aRadii[eCornerTopRightY] &&
|
||||
aRadii[eCornerBottomLeftX] == aRadii[eCornerBottomLeftY] &&
|
||||
aRadii[eCornerBottomRightX] == aRadii[eCornerBottomRightY]);
|
||||
}
|
||||
|
||||
private:
|
||||
@ -1046,8 +1063,21 @@ private:
|
||||
// nullptr.
|
||||
const UniquePtr<nscoord[]> mRadii;
|
||||
|
||||
// A shape-margin value extends the boundaries of the float area.
|
||||
// A shape-margin value extends the boundaries of the float area. When our
|
||||
// first constructor is used, it is for the creation of rounded boxes that
|
||||
// can ignore shape-margin -- either because it was specified as zero or
|
||||
// because the box shape and radii can be inflated to account for it. When
|
||||
// our second constructor is used, we store the shape-margin value here.
|
||||
const nscoord mShapeMargin;
|
||||
|
||||
// If our second constructor is called (which implies mShapeMargin > 0),
|
||||
// we will construct EllipseShapeInfo objects for each corner. We use the
|
||||
// float logical naming here, where LogicalTopLeftCorner means the BStart
|
||||
// LineLeft corner, and similarly for the other corners.
|
||||
UniquePtr<EllipseShapeInfo> mLogicalTopLeftCorner;
|
||||
UniquePtr<EllipseShapeInfo> mLogicalTopRightCorner;
|
||||
UniquePtr<EllipseShapeInfo> mLogicalBottomLeftCorner;
|
||||
UniquePtr<EllipseShapeInfo> mLogicalBottomRightCorner;
|
||||
};
|
||||
|
||||
nsFloatManager::RoundedBoxShapeInfo::RoundedBoxShapeInfo(const nsRect& aRect,
|
||||
@ -1058,41 +1088,113 @@ nsFloatManager::RoundedBoxShapeInfo::RoundedBoxShapeInfo(const nsRect& aRect,
|
||||
, mRadii(Move(aRadii))
|
||||
, mShapeMargin(aShapeMargin)
|
||||
{
|
||||
MOZ_ASSERT(mShapeMargin > 0 && !EachCornerHasBalancedRadii(mRadii.get()),
|
||||
"Slow constructor should only be used for for shape-margin > 0 "
|
||||
"and radii with elliptical corners.");
|
||||
|
||||
// Before we inflate mRect by mShapeMargin, construct each of our corners.
|
||||
// If we do it in this order, it's a bit simpler to calculate the center
|
||||
// of each of the corners.
|
||||
mLogicalTopLeftCorner = MakeUnique<EllipseShapeInfo>(
|
||||
nsPoint(mRect.X() + mRadii[eCornerTopLeftX],
|
||||
mRect.Y() + mRadii[eCornerTopLeftY]),
|
||||
nsSize(mRadii[eCornerTopLeftX], mRadii[eCornerTopLeftY]),
|
||||
mShapeMargin, aAppUnitsPerDevPixel);
|
||||
|
||||
mLogicalTopRightCorner = MakeUnique<EllipseShapeInfo>(
|
||||
nsPoint(mRect.XMost() - mRadii[eCornerTopRightX],
|
||||
mRect.Y() + mRadii[eCornerTopRightY]),
|
||||
nsSize(mRadii[eCornerTopRightX], mRadii[eCornerTopRightY]),
|
||||
mShapeMargin, aAppUnitsPerDevPixel);
|
||||
|
||||
mLogicalBottomLeftCorner = MakeUnique<EllipseShapeInfo>(
|
||||
nsPoint(mRect.X() + mRadii[eCornerBottomLeftX],
|
||||
mRect.YMost() - mRadii[eCornerBottomLeftY]),
|
||||
nsSize(mRadii[eCornerBottomLeftX], mRadii[eCornerBottomLeftY]),
|
||||
mShapeMargin, aAppUnitsPerDevPixel);
|
||||
|
||||
mLogicalBottomRightCorner = MakeUnique<EllipseShapeInfo>(
|
||||
nsPoint(mRect.XMost() - mRadii[eCornerBottomRightX],
|
||||
mRect.YMost() - mRadii[eCornerBottomRightY]),
|
||||
nsSize(mRadii[eCornerBottomRightX], mRadii[eCornerBottomRightY]),
|
||||
mShapeMargin, aAppUnitsPerDevPixel);
|
||||
|
||||
// Now we inflate our mRect by mShapeMargin.
|
||||
mRect.Inflate(mShapeMargin);
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsFloatManager::RoundedBoxShapeInfo::LineLeft(const nscoord aBStart,
|
||||
const nscoord aBEnd) const
|
||||
{
|
||||
if (!mRadii) {
|
||||
return mRect.x;
|
||||
if (mShapeMargin == 0) {
|
||||
if (!mRadii) {
|
||||
return mRect.x;
|
||||
}
|
||||
|
||||
nscoord lineLeftDiff =
|
||||
ComputeEllipseLineInterceptDiff(
|
||||
mRect.y, mRect.YMost(),
|
||||
mRadii[eCornerTopLeftX], mRadii[eCornerTopLeftY],
|
||||
mRadii[eCornerBottomLeftX], mRadii[eCornerBottomLeftY],
|
||||
aBStart, aBEnd);
|
||||
return mRect.x + lineLeftDiff;
|
||||
}
|
||||
|
||||
nscoord lineLeftDiff =
|
||||
ComputeEllipseLineInterceptDiff(
|
||||
mRect.y, mRect.YMost(),
|
||||
mRadii[eCornerTopLeftX], mRadii[eCornerTopLeftY],
|
||||
mRadii[eCornerBottomLeftX], mRadii[eCornerBottomLeftY],
|
||||
aBStart, aBEnd);
|
||||
return mRect.x + lineLeftDiff;
|
||||
MOZ_ASSERT(mLogicalTopLeftCorner && mLogicalBottomLeftCorner,
|
||||
"If we have positive shape-margin, we should have corners.");
|
||||
|
||||
// Determine if aBEnd is within our top corner.
|
||||
if (aBEnd < mLogicalTopLeftCorner->BEnd()) {
|
||||
return mLogicalTopLeftCorner->LineLeft(aBStart, aBEnd);
|
||||
}
|
||||
|
||||
// Determine if aBStart is within our bottom corner.
|
||||
if (aBStart >= mLogicalBottomLeftCorner->BStart()) {
|
||||
return mLogicalBottomLeftCorner->LineLeft(aBStart, aBEnd);
|
||||
}
|
||||
|
||||
// Either aBStart or aBEnd or both are within the flat part of our left
|
||||
// edge. Because we've already inflated our mRect to encompass our
|
||||
// mShapeMargin, we can just return the edge.
|
||||
return mRect.X();
|
||||
}
|
||||
|
||||
nscoord
|
||||
nsFloatManager::RoundedBoxShapeInfo::LineRight(const nscoord aBStart,
|
||||
const nscoord aBEnd) const
|
||||
{
|
||||
if (!mRadii) {
|
||||
return mRect.XMost();
|
||||
if (mShapeMargin == 0) {
|
||||
if (!mRadii) {
|
||||
return mRect.XMost();
|
||||
}
|
||||
|
||||
nscoord lineRightDiff =
|
||||
ComputeEllipseLineInterceptDiff(
|
||||
mRect.y, mRect.YMost(),
|
||||
mRadii[eCornerTopRightX], mRadii[eCornerTopRightY],
|
||||
mRadii[eCornerBottomRightX], mRadii[eCornerBottomRightY],
|
||||
aBStart, aBEnd);
|
||||
return mRect.XMost() - lineRightDiff;
|
||||
}
|
||||
|
||||
nscoord lineRightDiff =
|
||||
ComputeEllipseLineInterceptDiff(
|
||||
mRect.y, mRect.YMost(),
|
||||
mRadii[eCornerTopRightX], mRadii[eCornerTopRightY],
|
||||
mRadii[eCornerBottomRightX], mRadii[eCornerBottomRightY],
|
||||
aBStart, aBEnd);
|
||||
return mRect.XMost() - lineRightDiff;
|
||||
MOZ_ASSERT(mLogicalTopRightCorner && mLogicalBottomRightCorner,
|
||||
"If we have positive shape-margin, we should have corners.");
|
||||
|
||||
// Determine if aBEnd is within our top corner.
|
||||
if (aBEnd < mLogicalTopRightCorner->BEnd()) {
|
||||
return mLogicalTopRightCorner->LineRight(aBStart, aBEnd);
|
||||
}
|
||||
|
||||
// Determine if aBStart is within our bottom corner.
|
||||
if (aBStart >= mLogicalBottomRightCorner->BStart()) {
|
||||
return mLogicalBottomRightCorner->LineRight(aBStart, aBEnd);
|
||||
}
|
||||
|
||||
// Either aBStart or aBEnd or both are within the flat part of our right
|
||||
// edge. Because we've already inflated our mRect to encompass our
|
||||
// mShapeMargin, we can just return the edge.
|
||||
return mRect.XMost();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
@ -2141,12 +2243,9 @@ nsFloatManager::ShapeInfo::CreateInset(
|
||||
Move(logicalRadii));
|
||||
}
|
||||
|
||||
// If we have radii, and each pair is equal, we can inflate both
|
||||
// logicalInsetRect and all the radii and use the fast constructor.
|
||||
if (physicalRadii[0] == physicalRadii[1] &&
|
||||
physicalRadii[2] == physicalRadii[3] &&
|
||||
physicalRadii[4] == physicalRadii[5] &&
|
||||
physicalRadii[6] == physicalRadii[7]) {
|
||||
// If we have radii, and they have balanced/equal corners, we can inflate
|
||||
// both logicalInsetRect and all the radii and use the fast constructor.
|
||||
if (RoundedBoxShapeInfo::EachCornerHasBalancedRadii(physicalRadii)) {
|
||||
logicalInsetRect.Inflate(aShapeMargin);
|
||||
for (nscoord& r : physicalRadii) {
|
||||
r += aShapeMargin;
|
||||
@ -2156,7 +2255,7 @@ nsFloatManager::ShapeInfo::CreateInset(
|
||||
aWM));
|
||||
}
|
||||
|
||||
// With positive shape-margin and unequal radii pairs, we have to use the
|
||||
// With positive shape-margin and elliptical radii, we have to use the
|
||||
// slow constructor.
|
||||
nsDeviceContext* dc = aFrame->PresContext()->DeviceContext();
|
||||
int32_t appUnitsPerDevPixel = dc->AppUnitsPerDevPixel();
|
||||
|
Loading…
Reference in New Issue
Block a user