Bug 866102 - Implement -webkit-line-clamp. r=mats,emilio,dholbert

Differential Revision: https://phabricator.services.mozilla.com/D20115

--HG--
extra : moz-landing-system : lando
This commit is contained in:
Cameron McCormack 2019-05-09 02:32:30 +00:00
Родитель de6f8d5227
Коммит f5b7d1380b
90 изменённых файлов: 2079 добавлений и 102 удалений

Просмотреть файл

@ -279,6 +279,7 @@ exports.ANIMATION_TYPE_FOR_LONGHANDS = [
"transform-origin",
"-moz-window-transform",
"-moz-window-transform-origin",
"-webkit-line-clamp",
])],
["coord", new Set([
"border-bottom-left-radius",

Просмотреть файл

@ -2317,6 +2317,20 @@ exports.CSS_PROPERTIES = {
"unset"
]
},
"-webkit-line-clamp": {
"isInherited": false,
"subproperties": [
"-webkit-line-clamp"
],
"supports": [],
"values": [
"inherit",
"initial",
"none",
"revert",
"unset"
]
},
"-webkit-mask": {
"isInherited": false,
"subproperties": [
@ -3104,6 +3118,7 @@ exports.CSS_PROPERTIES = {
"shape-margin",
"shape-outside",
"touch-action",
"-webkit-line-clamp",
"color",
"column-width",
"column-count",
@ -10517,6 +10532,10 @@ exports.PREFERENCES = [
"transform-box",
"svg.transform-box.enabled"
],
[
"-webkit-line-clamp",
"layout.css.webkit-line-clamp.enabled"
],
[
"overflow-clip-box-block",
"layout.css.overflow-clip-box.enabled"

Просмотреть файл

@ -97,7 +97,15 @@ BlockReflowInput::BlockReflowInput(const ReflowInput& aReflowInput,
if (aBlockNeedsFloatManager) {
mFlags.mBlockNeedsFloatManager = true;
}
mFlags.mCanHaveTextOverflow = css::TextOverflow::CanHaveTextOverflow(mBlock);
// We need to check mInsideLineClamp here since we are here before the block
// has been reflowed, and CanHaveOverflowMarkers() relies on the block's
// NS_BLOCK_HAS_LINE_CLAMP_ELLIPSIS state bit to know if a -webkit-line-clamp
// ellipsis is set on one of the block's lines. And that state bit is only
// set after we do the bsize measuring reflow of the flex item.
mFlags.mCanHaveOverflowMarkers =
aReflowInput.mFlags.mInsideLineClamp ||
css::TextOverflow::CanHaveOverflowMarkers(mBlock);
MOZ_ASSERT(FloatManager(),
"Float manager should be valid when creating BlockReflowInput!");

Просмотреть файл

@ -40,7 +40,7 @@ class BlockReflowInput {
mIsOverflowContainer(false),
mIsFloatListInBlockPropertyTable(false),
mFloatFragmentsInsideColumnEnabled(false),
mCanHaveTextOverflow(false) {}
mCanHaveOverflowMarkers(false) {}
// Set in the BlockReflowInput constructor when the frame being reflowed has
// been given NS_UNCONSTRAINEDSIZE as its available BSize in the
@ -104,8 +104,8 @@ class BlockReflowInput {
// Set when the pref layout.float-fragments-inside-column.enabled is true.
bool mFloatFragmentsInsideColumnEnabled : 1;
// Set when we need text-overflow processing.
bool mCanHaveTextOverflow : 1;
// Set when we need text-overflow or -webkit-line-clamp processing.
bool mCanHaveOverflowMarkers : 1;
};
public:

Просмотреть файл

@ -215,6 +215,7 @@ ReflowInput::ReflowInput(nsPresContext* aPresContext,
mFlags.mIClampMarginBoxMinSize = !!(aFlags & I_CLAMP_MARGIN_BOX_MIN_SIZE);
mFlags.mBClampMarginBoxMinSize = !!(aFlags & B_CLAMP_MARGIN_BOX_MIN_SIZE);
mFlags.mApplyAutoMinSize = !!(aFlags & I_APPLY_AUTO_MIN_SIZE);
mFlags.mApplyLineClamp = false;
if ((aFlags & DUMMY_PARENT_REFLOW_INPUT) ||
(mParentReflowInput->mFlags.mDummyParentReflowInput &&

Просмотреть файл

@ -270,6 +270,20 @@ struct SizeComputationInput {
// with when we set & react to these bits.
bool mIOffsetsNeedCSSAlign : 1;
bool mBOffsetsNeedCSSAlign : 1;
// Are we somewhere inside an element with -webkit-line-clamp set?
// This flag is inherited into descendant ReflowInputs, but we don't bother
// resetting it to false when crossing over into a block descendant that
// -webkit-line-clamp skips over (such as a BFC).
bool mInsideLineClamp : 1;
// Is this a flex item, and should we add or remove a -webkit-line-clamp
// ellipsis on a descendant line? It's possible for this flag to be true
// when mInsideLineClamp is false if we previously had a numeric
// -webkit-line-clamp value, but now have 'none' and we need to find the
// line with the ellipsis flag and clear it.
// This flag is not inherited into descendant ReflowInputs.
bool mApplyLineClamp : 1;
};
#ifdef DEBUG

Просмотреть файл

@ -152,11 +152,11 @@ class nsDisplayTextOverflowMarker final : public nsPaintedDisplayItem {
public:
nsDisplayTextOverflowMarker(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
const nsRect& aRect, nscoord aAscent,
const nsStyleTextOverflowSide* aStyle,
nsStyleTextOverflowSide aStyle,
uint32_t aLineNumber, uint16_t aIndex)
: nsPaintedDisplayItem(aBuilder, aFrame),
mRect(aRect),
mStyle(*aStyle),
mStyle(aStyle),
mAscent(aAscent),
mIndex((aLineNumber << 1) + aIndex) {
MOZ_COUNT_CTOR(nsDisplayTextOverflowMarker);
@ -344,9 +344,10 @@ TextOverflow::TextOverflow(nsDisplayListBuilder* aBuilder,
/* static */
Maybe<TextOverflow> TextOverflow::WillProcessLines(
nsDisplayListBuilder* aBuilder, nsIFrame* aBlockFrame) {
// Ignore 'text-overflow' for event and frame visibility processing.
// Ignore text-overflow and -webkit-line-clamp for event and frame visibility
// processing.
if (aBuilder->IsForEventDelivery() || aBuilder->IsForFrameVisibility() ||
!CanHaveTextOverflow(aBlockFrame)) {
!CanHaveOverflowMarkers(aBlockFrame)) {
return Nothing();
}
nsIScrollableFrame* scrollableFrame =
@ -461,7 +462,7 @@ void TextOverflow::AnalyzeMarkerEdges(nsIFrame* aFrame,
if (iendOverlap > 0) {
snappedRect.ISize(mBlockWM) -= snappedIEnd;
}
aAlignmentEdges->Accumulate(mBlockWM, snappedRect);
aAlignmentEdges->AccumulateInner(mBlockWM, snappedRect);
*aFoundVisibleTextOrAtomic = true;
}
}
@ -470,12 +471,15 @@ void TextOverflow::AnalyzeMarkerEdges(nsIFrame* aFrame,
}
} else if (!insideIStartEdge || !insideIEndEdge) {
// frame is outside
if (!insideIStartEdge) {
aAlignmentEdges->AccumulateOuter(mBlockWM, borderRect);
}
if (IsAtomicElement(aFrame, aFrameType)) {
aFramesToHide->PutEntry(aFrame);
}
} else {
// frame is inside
aAlignmentEdges->Accumulate(mBlockWM, borderRect);
aAlignmentEdges->AccumulateInner(mBlockWM, borderRect);
if (aFrameType == LayoutFrameType::Text) {
auto textFrame = static_cast<nsTextFrame*>(aFrame);
if (textFrame->HasNonSuppressedText()) {
@ -491,8 +495,8 @@ LogicalRect TextOverflow::ExamineLineFrames(nsLineBox* aLine,
FrameHashtable* aFramesToHide,
AlignmentEdges* aAlignmentEdges) {
// No ellipsing for 'clip' style.
bool suppressIStart = mIStart.mStyle->mType == NS_STYLE_TEXT_OVERFLOW_CLIP;
bool suppressIEnd = mIEnd.mStyle->mType == NS_STYLE_TEXT_OVERFLOW_CLIP;
bool suppressIStart = mIStart.IsSuppressed();
bool suppressIEnd = mIEnd.IsSuppressed();
if (mCanHaveInlineAxisScrollbar) {
LogicalPoint pos(mBlockWM, mScrollableFrame->GetScrollPosition(),
mBlockSize);
@ -504,7 +508,10 @@ LogicalRect TextOverflow::ExamineLineFrames(nsLineBox* aLine,
suppressIStart = true;
}
if (pos.I(mBlockWM) >= scrollRange.IEnd(mBlockWM)) {
suppressIEnd = true;
// Except that we always want to display a -webkit-line-clamp ellipsis.
if (!mIEnd.mHasBlockEllipsis) {
suppressIEnd = true;
}
}
}
@ -543,22 +550,29 @@ LogicalRect TextOverflow::ExamineLineFrames(nsLineBox* aLine,
LogicalRect lineRect(mBlockWM, aLine->GetScrollableOverflowArea(),
mBlockSize);
const bool istartOverflow =
const bool istartWantsMarker =
!suppressIStart &&
lineRect.IStart(mBlockWM) < contentArea.IStart(mBlockWM);
const bool iendOverflow =
const bool iendWantsTextOverflowMarker =
!suppressIEnd && lineRect.IEnd(mBlockWM) > contentArea.IEnd(mBlockWM);
if (!istartOverflow && !iendOverflow) {
// The line does not overflow on a side we should ellipsize.
const bool iendWantsBlockEllipsisMarker =
!suppressIEnd && mIEnd.mHasBlockEllipsis;
const bool iendWantsMarker =
iendWantsTextOverflowMarker || iendWantsBlockEllipsisMarker;
if (!istartWantsMarker && !iendWantsMarker) {
// We don't need any markers on this line.
return nonSnappedContentArea;
}
int pass = 0;
bool retryEmptyLine = true;
bool guessIStart = istartOverflow;
bool guessIEnd = iendOverflow;
mIStart.mActive = istartOverflow;
mIEnd.mActive = iendOverflow;
bool guessIStart = istartWantsMarker;
bool guessIEnd = iendWantsMarker;
mIStart.mActive = istartWantsMarker;
mIEnd.mActive = iendWantsMarker;
mIStart.mEdgeAligned = mCanHaveInlineAxisScrollbar && istartWantsMarker;
mIEnd.mEdgeAligned =
mCanHaveInlineAxisScrollbar && iendWantsTextOverflowMarker;
bool clippedIStartMarker = false;
bool clippedIEndMarker = false;
do {
@ -601,7 +615,8 @@ LogicalRect TextOverflow::ExamineLineFrames(nsLineBox* aLine,
&clippedMarkerEdges);
}
if (!foundVisibleTextOrAtomic && retryEmptyLine) {
aAlignmentEdges->mAssigned = false;
aAlignmentEdges->mAssignedInner = false;
aAlignmentEdges->mIEndOuter = 0;
aFramesToHide->Clear();
pass = -1;
if (mIStart.IsNeeded() && mIStart.mActive && !clippedIStartMarker) {
@ -635,9 +650,23 @@ LogicalRect TextOverflow::ExamineLineFrames(nsLineBox* aLine,
// so examine the line again without suppressing markers.
retryEmptyLine = false;
mIStart.mISize = mIStart.mIntrinsicISize;
mIStart.mActive = guessIStart = istartOverflow;
mIStart.mActive = guessIStart = istartWantsMarker;
mIEnd.mISize = mIEnd.mIntrinsicISize;
mIEnd.mActive = guessIEnd = iendOverflow;
mIEnd.mActive = guessIEnd = iendWantsMarker;
// If we wanted to place a block ellipsis but didn't, due to not having
// any visible content to align to or the line's content being scrolled
// out of view, then clip the ellipsis so that it looks like it is aligned
// with the out of view content.
if (mIEnd.IsNeeded() && mIEnd.mActive && mIEnd.mHasBlockEllipsis) {
NS_ASSERTION(nonSnappedContentArea.IStart(mBlockWM) >
aAlignmentEdges->mIEndOuter,
"Expected the alignment edge for the out of view content "
"to be before the start of the content area");
mIEnd.mISize = std::max(
mIEnd.mIntrinsicISize - (nonSnappedContentArea.IStart(mBlockWM) -
aAlignmentEdges->mIEndOuter),
0);
}
continue;
}
if (guessIStart == (mIStart.mActive && mIStart.IsNeeded()) &&
@ -652,10 +681,10 @@ LogicalRect TextOverflow::ExamineLineFrames(nsLineBox* aLine,
}
NS_ASSERTION(pass == 0, "2nd pass should never guess wrong");
} while (++pass != 2);
if (!istartOverflow || !mIStart.mActive) {
if (!istartWantsMarker || !mIStart.mActive) {
mIStart.Reset();
}
if (!iendOverflow || !mIEnd.mActive) {
if (!iendWantsMarker || !mIEnd.mActive) {
mIEnd.Reset();
}
return nonSnappedContentArea;
@ -663,13 +692,18 @@ LogicalRect TextOverflow::ExamineLineFrames(nsLineBox* aLine,
void TextOverflow::ProcessLine(const nsDisplayListSet& aLists, nsLineBox* aLine,
uint32_t aLineNumber) {
NS_ASSERTION(mIStart.mStyle->mType != NS_STYLE_TEXT_OVERFLOW_CLIP ||
mIEnd.mStyle->mType != NS_STYLE_TEXT_OVERFLOW_CLIP,
"TextOverflow with 'clip' for both sides");
if (mIStart.mStyle->mType == NS_STYLE_TEXT_OVERFLOW_CLIP &&
mIEnd.mStyle->mType == NS_STYLE_TEXT_OVERFLOW_CLIP &&
!aLine->HasLineClampEllipsis()) {
return;
}
mIStart.Reset();
mIStart.mActive = mIStart.mStyle->mType != NS_STYLE_TEXT_OVERFLOW_CLIP;
mIEnd.Reset();
mIEnd.mActive = mIEnd.mStyle->mType != NS_STYLE_TEXT_OVERFLOW_CLIP;
mIEnd.mHasBlockEllipsis = aLine->HasLineClampEllipsis();
mIEnd.mActive = mIEnd.mStyle->mType != NS_STYLE_TEXT_OVERFLOW_CLIP ||
aLine->HasLineClampEllipsis();
FrameHashtable framesToHide(64);
AlignmentEdges alignmentEdges;
@ -680,11 +714,10 @@ void TextOverflow::ProcessLine(const nsDisplayListSet& aLists, nsLineBox* aLine,
if (!needIStart && !needIEnd) {
return;
}
NS_ASSERTION(
mIStart.mStyle->mType != NS_STYLE_TEXT_OVERFLOW_CLIP || !needIStart,
"left marker for 'clip'");
NS_ASSERTION(mIEnd.mStyle->mType != NS_STYLE_TEXT_OVERFLOW_CLIP || !needIEnd,
"right marker for 'clip'");
NS_ASSERTION(!mIStart.IsSuppressed() || !needIStart,
"left marker when not needed");
NS_ASSERTION(!mIEnd.IsSuppressed() || !needIEnd,
"right marker when not needed");
// If there is insufficient space for both markers then keep the one on the
// end side per the block's 'direction'.
@ -699,11 +732,30 @@ void TextOverflow::ProcessLine(const nsDisplayListSet& aLists, nsLineBox* aLine,
if (needIEnd) {
InflateIEnd(mBlockWM, &insideMarkersArea, -mIEnd.mISize);
}
if (!mCanHaveInlineAxisScrollbar && alignmentEdges.mAssigned) {
if (alignmentEdges.mAssignedInner) {
if (mIStart.mEdgeAligned) {
alignmentEdges.mIStart = insideMarkersArea.IStart(mBlockWM);
}
if (mIEnd.mEdgeAligned) {
alignmentEdges.mIEnd = insideMarkersArea.IEnd(mBlockWM);
}
LogicalRect alignmentRect(mBlockWM, alignmentEdges.mIStart,
insideMarkersArea.BStart(mBlockWM),
alignmentEdges.ISize(), 1);
insideMarkersArea.IntersectRect(insideMarkersArea, alignmentRect);
} else {
// There was no content on the line that was visible at the current scolled
// position. If we wanted to place a block ellipsis but failed due to
// having no visible content to align it to, we still need to ensure it
// is displayed. It goes at the start of the line, even though it's an
// IEnd marker, since that is the side of the line that the content has
// been scrolled past. We set the insideMarkersArea to a zero-sized
// rectangle placed next to the scrolled-out-of-view content.
if (mIEnd.mHasBlockEllipsis) {
insideMarkersArea = LogicalRect(mBlockWM, alignmentEdges.mIEndOuter,
insideMarkersArea.BStart(mBlockWM), 0, 1);
}
}
// Clip and remove display items as needed at the final marker edges.
@ -762,16 +814,28 @@ void TextOverflow::PruneDisplayListContents(
}
/* static */
bool TextOverflow::HasClippedOverflow(nsIFrame* aBlockFrame) {
bool TextOverflow::HasClippedTextOverflow(nsIFrame* aBlockFrame) {
const nsStyleTextReset* style = aBlockFrame->StyleTextReset();
return style->mTextOverflow.mLeft.mType == NS_STYLE_TEXT_OVERFLOW_CLIP &&
style->mTextOverflow.mRight.mType == NS_STYLE_TEXT_OVERFLOW_CLIP;
}
/* static */
bool TextOverflow::CanHaveTextOverflow(nsIFrame* aBlockFrame) {
bool TextOverflow::HasBlockEllipsis(nsIFrame* aBlockFrame) {
nsBlockFrame* f = do_QueryFrame(aBlockFrame);
return f && f->HasAnyStateBits(NS_BLOCK_HAS_LINE_CLAMP_ELLIPSIS);
}
/* static */
bool TextOverflow::CanHaveOverflowMarkers(nsIFrame* aBlockFrame) {
// Treat a line with a -webkit-line-clamp ellipsis as a kind of text
// overflow.
if (aBlockFrame->HasAnyStateBits(NS_BLOCK_HAS_LINE_CLAMP_ELLIPSIS)) {
return true;
}
// Nothing to do for text-overflow:clip or if 'overflow-x/y:visible'.
if (HasClippedOverflow(aBlockFrame) ||
if (HasClippedTextOverflow(aBlockFrame) ||
IsInlineAxisOverflowVisible(aBlockFrame)) {
return false;
}
@ -815,8 +879,8 @@ void TextOverflow::CreateMarkers(const nsLineBox* aLine, bool aCreateIStart,
ClipMarker(aContentArea.GetPhysicalRect(mBlockWM, mBlockSize) + offset,
markerRect, clipState);
mMarkerList.AppendNewToTop<nsDisplayTextOverflowMarker>(
mBuilder, mBlock, markerRect, aLine->GetLogicalAscent(), mIStart.mStyle,
aLineNumber, 0);
mBuilder, mBlock, markerRect, aLine->GetLogicalAscent(),
*mIStart.mStyle, aLineNumber, 0);
}
if (aCreateIEnd) {
@ -831,7 +895,9 @@ void TextOverflow::CreateMarkers(const nsLineBox* aLine, bool aCreateIStart,
ClipMarker(aContentArea.GetPhysicalRect(mBlockWM, mBlockSize) + offset,
markerRect, clipState);
mMarkerList.AppendNewToTop<nsDisplayTextOverflowMarker>(
mBuilder, mBlock, markerRect, aLine->GetLogicalAscent(), mIEnd.mStyle,
mBuilder, mBlock, markerRect, aLine->GetLogicalAscent(),
mIEnd.mHasBlockEllipsis ? nsStyleTextOverflowSide::Ellipsis()
: *mIEnd.mStyle,
aLineNumber, 1);
}
}
@ -841,7 +907,13 @@ void TextOverflow::Marker::SetupString(nsIFrame* aFrame) {
return;
}
if (mStyle->mType == NS_STYLE_TEXT_OVERFLOW_ELLIPSIS) {
// A limitation here is that at the IEnd of a line, we only ever render one of
// a text-overflow marker and a -webkit-line-clamp block ellipsis. Since we
// don't track the block ellipsis string and the text-overflow marker string
// separately, if both apply to the element, we will always use "…" as the
// string for text-overflow.
if (HasBlockEllipsis(aFrame) ||
mStyle->mType == NS_STYLE_TEXT_OVERFLOW_ELLIPSIS) {
gfxTextRun* textRun = GetEllipsisTextRun(aFrame);
if (textRun) {
mISize = textRun->GetAdvanceWidth();

Просмотреть файл

@ -64,14 +64,14 @@ class TextOverflow final {
*/
nsDisplayList& GetMarkers() { return mMarkerList; }
/**
* @return true if aBlockFrmae has text-overflow:clip on both sides.
*/
static bool HasClippedOverflow(nsIFrame* aBlockFrame);
/**
* @return true if aBlockFrame needs analysis for text overflow.
*/
static bool CanHaveTextOverflow(nsIFrame* aBlockFrame);
// Returns whether aBlockFrame has text-overflow:clip on both sides.
static bool HasClippedTextOverflow(nsIFrame* aBlockFrame);
// Returns whether aBlockFrame has a block ellipsis on one of its lines.
static bool HasBlockEllipsis(nsIFrame* aBlockFrame);
// Returns whether aBlockFrame needs analysis for text overflow.
static bool CanHaveOverflowMarkers(nsIFrame* aBlockFrame);
typedef nsTHashtable<nsPtrHashKey<nsIFrame>> FrameHashtable;
@ -79,22 +79,36 @@ class TextOverflow final {
typedef mozilla::WritingMode WritingMode;
typedef mozilla::LogicalRect LogicalRect;
// Edges to align the IStart and IEnd markers to.
struct AlignmentEdges {
AlignmentEdges() : mIStart(0), mIEnd(0), mAssigned(false) {}
void Accumulate(WritingMode aWM, const LogicalRect& aRect) {
if (MOZ_LIKELY(mAssigned)) {
AlignmentEdges()
: mIStart(0), mIEnd(0), mIEndOuter(0), mAssignedInner(false) {}
void AccumulateInner(WritingMode aWM, const LogicalRect& aRect) {
if (MOZ_LIKELY(mAssignedInner)) {
mIStart = std::min(mIStart, aRect.IStart(aWM));
mIEnd = std::max(mIEnd, aRect.IEnd(aWM));
} else {
mIStart = aRect.IStart(aWM);
mIEnd = aRect.IEnd(aWM);
mAssigned = true;
mAssignedInner = true;
}
}
void AccumulateOuter(WritingMode aWM, const LogicalRect& aRect) {
mIEndOuter = std::max(mIEndOuter, aRect.IEnd(aWM));
}
nscoord ISize() { return mIEnd - mIStart; }
// The outermost edges of all text and atomic inline-level frames that are
// inside the area between the markers.
nscoord mIStart;
nscoord mIEnd;
bool mAssigned;
// The closest IEnd edge of all text and atomic inline-level frames that
// fall completely before the IStart edge of the content area. (Used to
// align a block ellipsis when there are no visible frames to align to.)
nscoord mIEndOuter;
bool mAssignedInner;
};
struct InnerClipEdges {
@ -136,8 +150,10 @@ class TextOverflow final {
* and the bounds of what will be displayed between the markers.
* @param aLine the line we're processing
* @param aFramesToHide frames that should have their display items removed
* @param aAlignmentEdges the outermost edges of all text and atomic
* inline-level frames that are inside the area between the markers
* @param aAlignmentEdges edges the markers will be aligned to, including
* the outermost edges of all text and atomic inline-level frames that
* are inside the content area, and the closest IEnd edge of such a frame
* outside the content area
* @return the area inside which we should add any markers;
* this is the block's content area narrowed by any floats on this line.
*/
@ -151,8 +167,10 @@ class TextOverflow final {
* @param aContentArea the block's content area
* @param aInsideMarkersArea the rectangle between the markers
* @param aFramesToHide frames that should have their display items removed
* @param aAlignmentEdges the outermost edges of all text and atomic
* inline-level frames that are inside the area between the markers
* @param aAlignmentEdges edges the markers will be aligned to, including
* the outermost edges of all text and atomic inline-level frames that
* are inside the content area, and the closest IEnd edge of such a frame
* outside the content area
* @param aFoundVisibleTextOrAtomic is set to true if a text or atomic
* inline-level frame is visible between the marker edges
* @param aClippedMarkerEdges the innermost edges of all text and atomic
@ -179,6 +197,10 @@ class TextOverflow final {
* @param aAlignmentEdges the outermost edges of all text and atomic
* inline-level frames that are inside the area between the markers
* inside aInsideMarkersArea
* @param aAlignmentEdges edges the markers will be aligned to, including
* the outermost edges of all text and atomic inline-level frames that
* are inside aInsideMarkersArea, and the closest IEnd edge of such a frame
* outside the content area
* @param aFoundVisibleTextOrAtomic is set to true if a text or atomic
* inline-level frame is visible between the marker edges
* @param aClippedMarkerEdges the innermost edges of all text and atomic
@ -234,7 +256,9 @@ class TextOverflow final {
mStyle = &aStyle;
mIntrinsicISize = 0;
mHasOverflow = false;
mHasBlockEllipsis = false;
mActive = false;
mEdgeAligned = false;
}
/**
@ -242,22 +266,35 @@ class TextOverflow final {
*/
void SetupString(nsIFrame* aFrame);
bool IsNeeded() const { return mHasOverflow; }
void Reset() { mHasOverflow = false; }
bool IsSuppressed() const {
return !mHasBlockEllipsis && mStyle->mType == NS_STYLE_TEXT_OVERFLOW_CLIP;
}
bool IsNeeded() const { return mHasOverflow || mHasBlockEllipsis; }
void Reset() {
mHasOverflow = false;
mHasBlockEllipsis = false;
mEdgeAligned = false;
}
// The current width of the marker, the range is [0 .. mIntrinsicISize].
nscoord mISize;
// The intrinsic width of the marker.
nscoord mIntrinsicISize;
// The style for this side.
// The text-overflow style for this side. Ignored if we're rendering a
// block ellipsis.
const nsStyleTextOverflowSide* mStyle;
// True if there is visible overflowing inline content on this side.
bool mHasOverflow;
// True if mMarkerString and mWidth have been setup from style.
// True if this side has a block ellipsis (from -webkit-line-clamp).
bool mHasBlockEllipsis;
// True if mISize and mIntrinsicISize have been setup from style.
bool mInitialized;
// True if the style is text-overflow:clip on this side and the marker
// True if the style is not text-overflow:clip on this side and the marker
// won't cause the line to become empty.
bool mActive;
// True if this marker is aligned to the edge of the content box, so that
// when scrolling the marker doesn't jump around.
bool mEdgeAligned;
};
Marker mIStart; // the inline start marker

Просмотреть файл

@ -58,6 +58,7 @@
#include "mozilla/RestyleManager.h"
#include "mozilla/ServoStyleSet.h"
#include "mozilla/Telemetry.h"
#include "nsFlexContainerFrame.h"
#include "nsBidiPresUtils.h"
@ -1057,6 +1058,139 @@ static LogicalSize CalculateContainingBlockSizeForAbsolutes(
return cbSize;
}
/**
* Returns aFrame if it is a non-BFC block frame, and null otherwise.
*
* This is used to determine whether to recurse into aFrame when applying
* -webkit-line-clamp.
*/
static nsBlockFrame* GetAsLineClampDescendant(nsIFrame* aFrame) {
if (nsBlockFrame* block = do_QueryFrame(aFrame)) {
if (!block->HasAllStateBits(NS_BLOCK_FORMATTING_CONTEXT_STATE_BITS)) {
return block;
}
}
return nullptr;
}
/**
* Iterator over all descendant inline line boxes, except for those that are
* under an independent formatting context.
*/
class MOZ_RAII LineClampLineIterator {
public:
explicit LineClampLineIterator(nsBlockFrame* aFrame)
: mCur(aFrame->LinesBegin()),
mEnd(aFrame->LinesEnd()),
mCurrentFrame(mCur == mEnd ? nullptr : aFrame) {
if (mCur != mEnd && !mCur->IsInline()) {
Advance();
}
}
nsLineBox* GetCurrentLine() { return mCurrentFrame ? mCur.get() : nullptr; }
nsBlockFrame* GetCurrentFrame() { return mCurrentFrame; }
// Advances the iterator to the next line line.
//
// Next() shouldn't be called once the iterator is at the end, which can be
// checked for by GetCurrentLine() or GetCurrentFrame() returning null.
void Next() {
MOZ_ASSERT(mCur != mEnd && mCurrentFrame,
"Don't call Next() when the iterator is at the end");
++mCur;
Advance();
}
private:
void Advance() {
for (;;) {
if (mCur == mEnd) {
// Reached the end of the current block. Pop the parent off the
// stack; if there isn't one, then we've reached the end.
if (mStack.IsEmpty()) {
mCurrentFrame = nullptr;
break;
}
auto entry = mStack.PopLastElement();
mCurrentFrame = entry.first();
mCur = entry.second();
mEnd = mCurrentFrame->LinesEnd();
} else if (mCur->IsBlock()) {
if (nsBlockFrame* child = GetAsLineClampDescendant(mCur->mFirstChild)) {
nsBlockFrame::LineIterator next = mCur;
++next;
mStack.AppendElement(MakePair(mCurrentFrame, next));
mCur = child->LinesBegin();
mEnd = child->LinesEnd();
mCurrentFrame = child;
} else {
// Some kind of frame we shouldn't descend into.
++mCur;
}
} else {
MOZ_ASSERT(mCur->IsInline());
break;
}
}
}
// The current line within the current block.
//
// When this is equal to mEnd, the iterator is at its end, and mCurrentFrame
// is set to null.
nsBlockFrame::LineIterator mCur;
// The iterator end for the current block.
nsBlockFrame::LineIterator mEnd;
// The current block.
nsBlockFrame* mCurrentFrame;
// Stack of mCurrentFrame and mEnd values that we push and pop as we enter and
// exist blocks.
AutoTArray<Pair<nsBlockFrame*, nsBlockFrame::LineIterator>, 8> mStack;
};
static bool ClearLineClampEllipsis(nsBlockFrame* aFrame) {
if (!aFrame->HasAnyStateBits(NS_BLOCK_HAS_LINE_CLAMP_ELLIPSIS)) {
for (nsIFrame* f : aFrame->PrincipalChildList()) {
if (nsBlockFrame* child = GetAsLineClampDescendant(f)) {
if (ClearLineClampEllipsis(child)) {
return true;
}
}
}
return false;
}
aFrame->RemoveStateBits(NS_BLOCK_HAS_LINE_CLAMP_ELLIPSIS);
nsBlockFrame::LineIterator line = aFrame->LinesBegin();
nsBlockFrame::LineIterator end = aFrame->LinesEnd();
while (line != end) {
if (line->HasLineClampEllipsis()) {
line->ClearHasLineClampEllipsis();
return true;
}
++line;
}
MOZ_ASSERT_UNREACHABLE("expected to find a line with HasLineClampEllipsis");
return true;
}
void nsBlockFrame::ClearLineClampEllipsis() {
::ClearLineClampEllipsis(this);
}
static bool IsLineClampItem(const ReflowInput& aReflowInput) {
return aReflowInput.mFlags.mApplyLineClamp ||
(aReflowInput.mParentReflowInput &&
aReflowInput.mParentReflowInput->mFrame->IsScrollFrame() &&
aReflowInput.mParentReflowInput->mFlags.mApplyLineClamp);
}
void nsBlockFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
const ReflowInput& aReflowInput,
nsReflowStatus& aStatus) {
@ -1303,6 +1437,11 @@ void nsBlockFrame::Reflow(nsPresContext* aPresContext, ReflowOutput& aMetrics,
// block-start padding.
}
// Clear any existing -webkit-line-clamp ellipsis.
if (IsLineClampItem(aReflowInput)) {
ClearLineClampEllipsis();
}
CheckFloats(state);
// Compute our final size
@ -1515,6 +1654,109 @@ bool nsBlockFrame::CheckForCollapsedBEndMarginFromClearanceLine() {
// not reached
}
static nsLineBox* FindLineClampTarget(nsBlockFrame*& aFrame,
uint32_t aLineNumber) {
MOZ_ASSERT(aLineNumber > 0);
MOZ_ASSERT(!aFrame->HasAnyStateBits(NS_BLOCK_HAS_LINE_CLAMP_ELLIPSIS),
"Should have been removed earlier in nsBlockReflow::Reflow");
nsLineBox* target = nullptr;
nsBlockFrame* targetFrame = nullptr;
bool foundFollowingLine = false;
LineClampLineIterator iter(aFrame);
while (nsLineBox* line = iter.GetCurrentLine()) {
MOZ_ASSERT(!line->HasLineClampEllipsis(),
"Should have been removed earlier in nsBlockFrame::Reflow");
MOZ_ASSERT(!iter.GetCurrentFrame()->HasAnyStateBits(
NS_BLOCK_HAS_LINE_CLAMP_ELLIPSIS),
"Should have been removed earlier in nsBlockReflow::Reflow");
// Don't count a line that only has collapsible white space (as might exist
// after calling e.g. getBoxQuads).
if (line->IsEmpty()) {
continue;
}
if (aLineNumber == 0) {
// We already previously found our target line, and now we have
// confirmed that there is another line after it.
foundFollowingLine = true;
break;
}
if (--aLineNumber == 0) {
// This is our target line. Continue looping to confirm that we
// have another line after us.
target = line;
targetFrame = iter.GetCurrentFrame();
}
iter.Next();
}
if (!foundFollowingLine) {
aFrame = nullptr;
return nullptr;
}
MOZ_ASSERT(target);
MOZ_ASSERT(targetFrame);
aFrame = targetFrame;
return target;
}
static nscoord ApplyLineClamp(const ReflowInput& aReflowInput,
nsBlockFrame* aFrame, nscoord aContentBSize) {
// We only do the work of applying the -webkit-line-clamp value during the
// measuring bsize reflow. Boxes affected by -webkit-line-clamp are always
// inflexible, so we will never need to select a different line to place the
// ellipsis on in the subsequent real reflow.
if (!IsLineClampItem(aReflowInput)) {
return aContentBSize;
}
auto container =
static_cast<nsFlexContainerFrame*>(nsLayoutUtils::GetClosestFrameOfType(
aFrame, LayoutFrameType::FlexContainer));
MOZ_ASSERT(container,
"A flex item affected by -webkit-line-clamp must have an ancestor "
"flex container");
uint32_t lineClamp = container->GetLineClampValue();
if (lineClamp == 0) {
// -webkit-line-clamp is none or doesn't apply.
return aContentBSize;
}
MOZ_ASSERT(container->HasAnyStateBits(NS_STATE_FLEX_IS_EMULATING_LEGACY_BOX),
"Should only have an effective -webkit-line-clamp value if we "
"are in a legacy flex container");
nsBlockFrame* frame = aFrame;
nsLineBox* line = FindLineClampTarget(frame, lineClamp);
if (!line) {
// The number of lines did not exceed the -webkit-line-clamp value.
return aContentBSize;
}
// Mark the line as having an ellipsis so that TextOverflow will render it.
line->SetHasLineClampEllipsis();
frame->AddStateBits(NS_BLOCK_HAS_LINE_CLAMP_ELLIPSIS);
container->AddStateBits(NS_STATE_FLEX_HAS_LINE_CLAMP_ELLIPSIS);
// Translate the b-end edge of the line up to aFrame's space.
nscoord edge = line->BEnd();
for (nsIFrame* f = frame; f != aFrame; f = f->GetParent()) {
edge +=
f->GetLogicalPosition(f->GetParent()->GetSize()).B(f->GetWritingMode());
}
return edge;
}
void nsBlockFrame::ComputeFinalSize(const ReflowInput& aReflowInput,
BlockReflowInput& aState,
ReflowOutput& aMetrics,
@ -1625,10 +1867,12 @@ void nsBlockFrame::ComputeFinalSize(const ReflowInput& aReflowInput,
finalSize.BSize(wm) = autoBSize;
} else if (aState.mReflowStatus.IsComplete()) {
nscoord contentBSize = blockEndEdgeOfChildren - borderPadding.BStart(wm);
nscoord autoBSize = aReflowInput.ApplyMinMaxBSize(contentBSize);
nscoord lineClampedContentBSize =
ApplyLineClamp(aReflowInput, this, contentBSize);
nscoord autoBSize = aReflowInput.ApplyMinMaxBSize(lineClampedContentBSize);
if (autoBSize != contentBSize) {
// Our min- or max-bsize value made our bsize change. Don't carry out
// our kids' block-end margins.
// Our min-block-size, max-block-size, or -webkit-line-clamp value made
// our bsize change. Don't carry out our kids' block-end margins.
aMetrics.mCarriedOutBEndMargin.Zero();
}
autoBSize += borderPadding.BStart(wm) + borderPadding.BEnd(wm);
@ -2808,9 +3052,9 @@ void nsBlockFrame::ReflowLine(BlockReflowInput& aState, LineIterator aLine,
aLine->SetLineWrapped(false);
ReflowInlineFrames(aState, aLine, aKeepReflowGoing);
// Store the line's float edges for text-overflow analysis if needed.
// Store the line's float edges for overflow marker analysis if needed.
aLine->ClearFloatEdges();
if (aState.mFlags.mCanHaveTextOverflow) {
if (aState.mFlags.mCanHaveOverflowMarkers) {
WritingMode wm = aLine->mWritingMode;
nsFlowAreaRect r = aState.GetFloatAvailableSpaceForBSize(
aLine->BStart(), aLine->BSize(), nullptr);

Просмотреть файл

@ -577,6 +577,12 @@ class nsBlockFrame : public nsContainerFrame {
// @see nsIFrame::AddSizeOfExcludingThisForTree
void AddSizeOfExcludingThisForTree(nsWindowSizes&) const override;
/**
* Clears any -webkit-line-clamp ellipsis on a line in this block or one
* of its descendants.
*/
void ClearLineClampEllipsis();
protected:
/** @see DoRemoveFrame */
void DoRemoveFrameInternal(nsIFrame* aDeletedFrame, uint32_t aFlags,

Просмотреть файл

@ -833,6 +833,10 @@ class nsFlexContainerFrame::FlexItem : public LinkedListElement<FlexItem> {
bool CanMainSizeInfluenceCrossSize(
const FlexboxAxisTracker& aAxisTracker) const;
// Gets the block frame that contains the flex item's content. This is
// Frame() itself or one of its descendants.
nsBlockFrame* BlockFrame() const;
protected:
// Helper called by the constructor, to set mNeedsMinSizeAutoResolution:
void CheckForMinSizeAuto(const ReflowInput& aFlexItemReflowInput,
@ -1262,19 +1266,25 @@ uint16_t nsFlexContainerFrame::CSSAlignmentForAbsPosChild(
UniquePtr<FlexItem> nsFlexContainerFrame::GenerateFlexItemForChild(
nsPresContext* aPresContext, nsIFrame* aChildFrame,
const ReflowInput& aParentReflowInput,
const FlexboxAxisTracker& aAxisTracker) {
const FlexboxAxisTracker& aAxisTracker, bool aHasLineClampEllipsis) {
// Create temporary reflow input just for sizing -- to get hypothetical
// main-size and the computed values of min / max main-size property.
// (This reflow input will _not_ be used for reflow.)
ReflowInput childRI(
aPresContext, aParentReflowInput, aChildFrame,
aParentReflowInput.ComputedSize(aChildFrame->GetWritingMode()));
childRI.mFlags.mInsideLineClamp = GetLineClampValue() != 0;
// FLEX GROW & SHRINK WEIGHTS
// --------------------------
float flexGrow, flexShrink;
if (IsLegacyBox(this)) {
flexGrow = flexShrink = aChildFrame->StyleXUL()->mBoxFlex;
if (GetLineClampValue() != 0) {
// Items affected by -webkit-line-clamp are always inflexible.
flexGrow = flexShrink = 0;
} else {
flexGrow = flexShrink = aChildFrame->StyleXUL()->mBoxFlex;
}
} else {
const nsStylePosition* stylePos = aChildFrame->StylePosition();
flexGrow = stylePos->mFlexGrow;
@ -1379,7 +1389,8 @@ UniquePtr<FlexItem> nsFlexContainerFrame::GenerateFlexItemForChild(
// Resolve "flex-basis:auto" and/or "min-[width|height]:auto" (which might
// require us to reflow the item to measure content height)
ResolveAutoFlexBasisAndMinSize(aPresContext, *item, childRI, aAxisTracker);
ResolveAutoFlexBasisAndMinSize(aPresContext, *item, childRI, aAxisTracker,
aHasLineClampEllipsis);
return item;
}
@ -1554,8 +1565,8 @@ static bool ResolveAutoFlexBasisFromRatio(
// we may want to resolve that in this function, too.
void nsFlexContainerFrame::ResolveAutoFlexBasisAndMinSize(
nsPresContext* aPresContext, FlexItem& aFlexItem,
const ReflowInput& aItemReflowInput,
const FlexboxAxisTracker& aAxisTracker) {
const ReflowInput& aItemReflowInput, const FlexboxAxisTracker& aAxisTracker,
bool aHasLineClampEllipsis) {
// (Note: We can guarantee that the flex-basis will have already been
// resolved if the main axis is the same is the same as the item's inline
// axis. Inline-axis values should always be resolvable without reflow.)
@ -1658,7 +1669,7 @@ void nsFlexContainerFrame::ResolveAutoFlexBasisAndMinSize(
nscoord contentBSize = MeasureFlexItemContentBSize(
aPresContext, aFlexItem, forceBResizeForMeasuringReflow,
*flexContainerRI);
aHasLineClampEllipsis, *flexContainerRI);
if (minSizeNeedsToMeasureContent) {
resolvedMinSize = std::min(resolvedMinSize, contentBSize);
}
@ -1823,7 +1834,7 @@ void nsFlexContainerFrame::MarkIntrinsicISizesDirty() {
nscoord nsFlexContainerFrame::MeasureFlexItemContentBSize(
nsPresContext* aPresContext, FlexItem& aFlexItem,
bool aForceBResizeForMeasuringReflow,
bool aForceBResizeForMeasuringReflow, bool aHasLineClampEllipsis,
const ReflowInput& aParentReflowInput) {
// Set up a reflow input for measuring the flex item's auto-height:
WritingMode wm = aFlexItem.Frame()->GetWritingMode();
@ -1833,6 +1844,9 @@ nscoord nsFlexContainerFrame::MeasureFlexItemContentBSize(
aFlexItem.Frame(), availSize, Nothing(),
ReflowInput::CALLER_WILL_INIT);
childRIForMeasuringBSize.mFlags.mIsFlexContainerMeasuringBSize = true;
childRIForMeasuringBSize.mFlags.mInsideLineClamp = GetLineClampValue() != 0;
childRIForMeasuringBSize.mFlags.mApplyLineClamp =
childRIForMeasuringBSize.mFlags.mInsideLineClamp || aHasLineClampEllipsis;
childRIForMeasuringBSize.Init(aPresContext);
if (aFlexItem.IsStretched()) {
@ -3355,6 +3369,22 @@ void FlexItem::ResolveStretchedCrossSize(
mIsStretched = true;
}
static nsBlockFrame* FindFlexItemBlockFrame(nsIFrame* aFrame) {
if (nsBlockFrame* block = do_QueryFrame(aFrame)) {
return block;
}
for (nsIFrame* f : aFrame->PrincipalChildList()) {
if (nsBlockFrame* block = FindFlexItemBlockFrame(f)) {
return block;
}
}
return nullptr;
}
nsBlockFrame* FlexItem::BlockFrame() const {
return FindFlexItemBlockFrame(Frame());
}
void SingleLineCrossAxisPositionTracker::ResolveAutoMarginsInCrossAxis(
const FlexLine& aLine, FlexItem& aItem) {
// Subtract the space that our item is already occupying, to see how much
@ -3728,7 +3758,8 @@ void nsFlexContainerFrame::GenerateFlexLines(
nsPresContext* aPresContext, const ReflowInput& aReflowInput,
nscoord aContentBoxMainSize, nscoord aAvailableBSizeForContent,
const nsTArray<StrutInfo>& aStruts, const FlexboxAxisTracker& aAxisTracker,
nscoord aMainGapSize, nsTArray<nsIFrame*>& aPlaceholders, /* out */
nscoord aMainGapSize, bool aHasLineClampEllipsis,
nsTArray<nsIFrame*>& aPlaceholders, /* out */
LinkedList<FlexLine>& aLines /* out */) {
MOZ_ASSERT(aLines.isEmpty(), "Expecting outparam to start out empty");
@ -3827,7 +3858,7 @@ void nsFlexContainerFrame::GenerateFlexLines(
nextStrutIdx++;
} else {
item = GenerateFlexItemForChild(aPresContext, childFrame, aReflowInput,
aAxisTracker);
aAxisTracker, aHasLineClampEllipsis);
}
nscoord itemInnerHypotheticalMainSize = item->GetMainSize();
@ -4223,6 +4254,13 @@ void nsFlexContainerFrame::Reflow(nsPresContext* aPresContext,
AddStateBits(NS_FRAME_CONTAINS_RELATIVE_BSIZE);
}
// Check if there is a -webkit-line-clamp ellipsis somewhere inside at least
// one of the flex items, so we can clear the flag before the block frame
// re-sets it on the appropriate line during its bsize measuring reflow.
bool hasLineClampEllipsis =
HasAnyStateBits(NS_STATE_FLEX_HAS_LINE_CLAMP_ELLIPSIS);
RemoveStateBits(NS_STATE_FLEX_HAS_LINE_CLAMP_ELLIPSIS);
const FlexboxAxisTracker axisTracker(this, aReflowInput.GetWritingMode());
// Check to see if we need to create a computed info structure, to
@ -4280,14 +4318,14 @@ void nsFlexContainerFrame::Reflow(nsPresContext* aPresContext,
AutoTArray<StrutInfo, 1> struts;
DoFlexLayout(aPresContext, aDesiredSize, aReflowInput, aStatus,
contentBoxMainSize, availableBSizeForContent, struts,
axisTracker, mainGapSize, crossGapSize);
axisTracker, mainGapSize, crossGapSize, hasLineClampEllipsis);
if (!struts.IsEmpty()) {
// We're restarting flex layout, with new knowledge of collapsed items.
aStatus.Reset();
DoFlexLayout(aPresContext, aDesiredSize, aReflowInput, aStatus,
contentBoxMainSize, availableBSizeForContent, struts,
axisTracker, mainGapSize, crossGapSize);
axisTracker, mainGapSize, crossGapSize, hasLineClampEllipsis);
}
}
@ -4502,7 +4540,7 @@ void nsFlexContainerFrame::DoFlexLayout(
const ReflowInput& aReflowInput, nsReflowStatus& aStatus,
nscoord aContentBoxMainSize, nscoord aAvailableBSizeForContent,
nsTArray<StrutInfo>& aStruts, const FlexboxAxisTracker& aAxisTracker,
nscoord aMainGapSize, nscoord aCrossGapSize) {
nscoord aMainGapSize, nscoord aCrossGapSize, bool aHasLineClampEllipsis) {
MOZ_ASSERT(aStatus.IsEmpty(), "Caller should pass a fresh reflow status!");
AutoCleanLinkedList<FlexLine> lines;
@ -4510,7 +4548,8 @@ void nsFlexContainerFrame::DoFlexLayout(
GenerateFlexLines(aPresContext, aReflowInput, aContentBoxMainSize,
aAvailableBSizeForContent, aStruts, aAxisTracker,
aMainGapSize, placeholderKids, lines);
aMainGapSize, aHasLineClampEllipsis, placeholderKids,
lines);
if ((lines.getFirst()->IsEmpty() && !lines.getFirst()->getNext()) ||
aReflowInput.mStyleDisplay->IsContainLayout()) {
@ -4656,6 +4695,7 @@ void nsFlexContainerFrame::DoFlexLayout(
availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
ReflowInput childReflowInput(aPresContext, aReflowInput, item->Frame(),
availSize);
childReflowInput.mFlags.mInsideLineClamp = GetLineClampValue() != 0;
if (!sizeOverride) {
// Directly override the computed main-size, by tweaking reflow input:
if (item->IsInlineAxisMainAxis()) {
@ -4837,7 +4877,8 @@ void nsFlexContainerFrame::DoFlexLayout(
const nscoord itemNormalBPos = framePos.B(flexWM);
// Check if we actually need to reflow the item -- if we already reflowed
// it with the right size, we can just reposition it as-needed.
// it with the right size, and there is no need to do a reflow to clear
// out a -webkit-line-clamp ellipsis, we can just reposition it as-needed.
bool itemNeedsReflow = true; // (Start out assuming the worst.)
if (item->HadMeasuringReflow()) {
LogicalSize finalFlexItemCBSize =
@ -4869,7 +4910,17 @@ void nsFlexContainerFrame::DoFlexLayout(
}
if (itemNeedsReflow) {
ReflowFlexItem(aPresContext, aAxisTracker, aReflowInput, *item,
framePos, containerSize);
framePos, containerSize, aHasLineClampEllipsis);
}
// If we didn't perform a final reflow of the item, we still have a
// -webkit-line-clamp ellipsis hanging around, but we shouldn't have one
// any more, we need to clear that now. We strictly only need to do this
// if we didn't do a bsize measuring reflow of the item earlier (since
// that is normally when we deal with -webkit-line-clamp ellipses) but
// not all flex items need such a reflow.
if (!itemNeedsReflow && aHasLineClampEllipsis && GetLineClampValue() == 0) {
item->BlockFrame()->ClearLineClampEllipsis();
}
// If the item has auto margins, and we were tracking the UsedMargin
@ -5029,13 +5080,21 @@ void nsFlexContainerFrame::MoveFlexItemToFinalPosition(
void nsFlexContainerFrame::ReflowFlexItem(
nsPresContext* aPresContext, const FlexboxAxisTracker& aAxisTracker,
const ReflowInput& aReflowInput, const FlexItem& aItem,
LogicalPoint& aFramePos, const nsSize& aContainerSize) {
LogicalPoint& aFramePos, const nsSize& aContainerSize,
bool aHasLineClampEllipsis) {
WritingMode outerWM = aReflowInput.GetWritingMode();
WritingMode wm = aItem.Frame()->GetWritingMode();
LogicalSize availSize = aReflowInput.ComputedSize(wm);
availSize.BSize(wm) = NS_UNCONSTRAINEDSIZE;
ReflowInput childReflowInput(aPresContext, aReflowInput, aItem.Frame(),
availSize);
childReflowInput.mFlags.mInsideLineClamp = GetLineClampValue() != 0;
// This is the final reflow of this flex item; if we previously had a
// -webkit-line-clamp, and we missed our chance to clear the ellipsis
// because we didn't need to call MeasureFlexItemContentBSize, we set
// mApplyLineClamp to cause it to get cleared here.
childReflowInput.mFlags.mApplyLineClamp =
!childReflowInput.mFlags.mInsideLineClamp && aHasLineClampEllipsis;
// Keep track of whether we've overriden the child's computed ISize
// and/or BSize, so we can set its resize flags accordingly.
@ -5140,6 +5199,8 @@ void nsFlexContainerFrame::ReflowPlaceholders(
LogicalSize availSize = aReflowInput.ComputedSize(wm);
ReflowInput childReflowInput(aPresContext, aReflowInput, placeholder,
availSize);
// No need to set the -webkit-line-clamp related flags when reflowing
// a placeholder.
ReflowOutput childDesiredSize(childReflowInput);
nsReflowStatus childReflowStatus;
ReflowChild(placeholder, aPresContext, childDesiredSize, childReflowInput,
@ -5237,3 +5298,17 @@ nscoord nsFlexContainerFrame::GetPrefISize(gfxContext* aRenderingContext) {
return mCachedPrefISize;
}
uint32_t nsFlexContainerFrame::GetLineClampValue() const {
// -webkit-line-clamp should only work on items in flex containers that are
// display:-webkit-(inline-)box and -webkit-box-orient:vertical.
//
// This check makes -webkit-line-clamp work on display:-moz-box too, but
// that shouldn't be a big deal.
if (!HasAnyStateBits(NS_STATE_FLEX_IS_EMULATING_LEGACY_BOX) ||
StyleXUL()->mBoxOrient != StyleBoxOrient::Vertical) {
return 0;
}
return StyleDisplay()->mLineClamp;
}

Просмотреть файл

@ -151,6 +151,14 @@ class nsFlexContainerFrame final : public nsContainerFrame {
return true;
}
/**
* Returns the effective value of -webkit-line-clamp for this flex container.
*
* This will be 0 if the property is 'none', or if the element is not
* display:-webkit-(inline-)box and -webkit-box-orient:vertical.
*/
uint32_t GetLineClampValue() const;
// nsContainerFrame overrides
uint16_t CSSAlignmentForAbsPosChild(
const ReflowInput& aChildRI,
@ -264,7 +272,8 @@ class nsFlexContainerFrame final : public nsContainerFrame {
nscoord aAvailableBSizeForContent,
nsTArray<StrutInfo>& aStruts,
const FlexboxAxisTracker& aAxisTracker,
nscoord aMainGapSize, nscoord aCrossGapSize);
nscoord aMainGapSize, nscoord aCrossGapSize,
bool aHasLineClampEllipsis);
/**
* Checks whether our child-frame list "mFrames" is sorted, using the given
@ -297,7 +306,7 @@ class nsFlexContainerFrame final : public nsContainerFrame {
mozilla::UniquePtr<FlexItem> GenerateFlexItemForChild(
nsPresContext* aPresContext, nsIFrame* aChildFrame,
const ReflowInput& aParentReflowInput,
const FlexboxAxisTracker& aAxisTracker);
const FlexboxAxisTracker& aAxisTracker, bool aHasLineClampEllipsis);
/**
* This method gets a cached measuring reflow for a flex item, or does it and
@ -319,6 +328,7 @@ class nsFlexContainerFrame final : public nsContainerFrame {
nscoord MeasureFlexItemContentBSize(nsPresContext* aPresContext,
FlexItem& aFlexItem,
bool aForceBResizeForMeasuringReflow,
bool aHasLineClampEllipsis,
const ReflowInput& aParentReflowInput);
/**
@ -329,7 +339,8 @@ class nsFlexContainerFrame final : public nsContainerFrame {
void ResolveAutoFlexBasisAndMinSize(nsPresContext* aPresContext,
FlexItem& aFlexItem,
const ReflowInput& aItemReflowInput,
const FlexboxAxisTracker& aAxisTracker);
const FlexboxAxisTracker& aAxisTracker,
bool aHasLineClampEllipsis);
/**
* Returns true if "this" is the nsFlexContainerFrame for a -moz-box or
@ -358,7 +369,7 @@ class nsFlexContainerFrame final : public nsContainerFrame {
nscoord aAvailableBSizeForContent,
const nsTArray<StrutInfo>& aStruts,
const FlexboxAxisTracker& aAxisTracker,
nscoord aMainGapSize,
nscoord aMainGapSize, bool aHasLineClampEllipsis,
nsTArray<nsIFrame*>& aPlaceholders,
mozilla::LinkedList<FlexLine>& aLines);
@ -411,7 +422,7 @@ class nsFlexContainerFrame final : public nsContainerFrame {
const FlexboxAxisTracker& aAxisTracker,
const ReflowInput& aReflowInput, const FlexItem& aItem,
mozilla::LogicalPoint& aFramePos,
const nsSize& aContainerSize);
const nsSize& aContainerSize, bool aHasLineClampEllipsis);
/**
* Helper-function to perform a "dummy reflow" on all our nsPlaceholderFrame

Просмотреть файл

@ -350,6 +350,10 @@ FRAME_STATE_BIT(FlexContainer, 22, NS_STATE_FLEX_GENERATE_COMPUTED_VALUES)
// True if the container has no flex items; may lie if there is a pending reflow
FRAME_STATE_BIT(FlexContainer, 23, NS_STATE_FLEX_SYNTHESIZE_BASELINE)
// True if any flex item in the container has a line with a
// -webkit-line-ellipsis marker.
FRAME_STATE_BIT(FlexContainer, 24, NS_STATE_FLEX_HAS_LINE_CLAMP_ELLIPSIS)
// == Frame state bits that apply to grid container frames ====================
FRAME_STATE_GROUP(GridContainer, nsGridContainerFrame)
@ -568,6 +572,12 @@ FRAME_STATE_BIT(Block, 29, NS_BLOCK_HAS_FIRST_LETTER_STYLE)
FRAME_STATE_BIT(Block, 30, NS_BLOCK_FRAME_HAS_OUTSIDE_MARKER)
FRAME_STATE_BIT(Block, 31, NS_BLOCK_FRAME_HAS_INSIDE_MARKER)
// NS_BLOCK_HAS_LINE_CLAMP_ELLIPSIS indicates that exactly one line in this
// block has the LineClampEllipsis flag set, and that such a line must be found
// and have that flag cleared when reflowing this element's nearest legacy box
// container.
FRAME_STATE_BIT(Block, 60, NS_BLOCK_HAS_LINE_CLAMP_ELLIPSIS)
// This block has had a child marked dirty, so before we reflow we need
// to look through the lines to find any such children and mark
// appropriate lines dirty.

Просмотреть файл

@ -1185,6 +1185,7 @@ NS_QUERYFRAME_HEAD(nsHTMLScrollFrame)
NS_QUERYFRAME_ENTRY(nsIScrollableFrame)
NS_QUERYFRAME_ENTRY(nsIStatefulFrame)
NS_QUERYFRAME_ENTRY(nsIScrollbarMediator)
NS_QUERYFRAME_ENTRY(nsHTMLScrollFrame)
NS_QUERYFRAME_TAIL_INHERITING(nsContainerFrame)
//----------nsXULScrollFrame-------------------------------------------

Просмотреть файл

@ -471,8 +471,9 @@ class ScrollFrameHelper : public nsIReflowCallback {
PostScrollEndEvent();
}
mTransformingByAPZ = aTransforming;
if (!mozilla::css::TextOverflow::HasClippedOverflow(mOuter)) {
// If the block has some text-overflow stuff we should kick off a paint
if (!mozilla::css::TextOverflow::HasClippedTextOverflow(mOuter) ||
mozilla::css::TextOverflow::HasBlockEllipsis(mScrolledFrame)) {
// If the block has some overflow marker stuff we should kick off a paint
// because we have special behaviour for it when APZ scrolling is active.
mOuter->SchedulePaint();
}

Просмотреть файл

@ -267,6 +267,11 @@ class nsLineBox final : public nsLineLink {
void ClearHadFloatPushed() { mFlags.mHadFloatPushed = false; }
bool HadFloatPushed() const { return mFlags.mHadFloatPushed; }
// mHasLineClampEllipsis bit
void SetHasLineClampEllipsis() { mFlags.mHasLineClampEllipsis = true; }
void ClearHasLineClampEllipsis() { mFlags.mHasLineClampEllipsis = false; }
bool HasLineClampEllipsis() const { return mFlags.mHasLineClampEllipsis; }
private:
// Add a hash table for fast lookup when the line has more frames than this.
static const uint32_t kMinChildCountForHashtable = 200;
@ -608,6 +613,13 @@ class nsLineBox final : public nsLineLink {
// that was pushed to a later column or page.
bool mHadFloatPushed : 1;
bool mHasHashedFrames : 1;
// Indicates that this line is the one identified by an ancestor block
// with -webkit-line-clamp on its legacy flex container, and that subsequent
// lines under that block are "clamped" away, and therefore we need to
// render a 'text-overflow: ellipsis'-like marker in this line. At most one
// line in the set of lines found by LineClampLineIterator for a given
// block will have this flag set.
bool mHasLineClampEllipsis : 1;
StyleClear mBreakType;
};

Просмотреть файл

@ -912,7 +912,8 @@ void nsLineLayout::ReflowFrame(nsIFrame* aFrame, nsReflowStatus& aReflowStatus,
// in the line layout data structures. See bug 1490281 to fix the
// underlying issue. When that's fixed this check should be removed.
!outOfFlowFrame->IsLetterFrame() &&
!GetOutermostLineLayout()->mBlockRI->mFlags.mCanHaveTextOverflow) {
!GetOutermostLineLayout()
->mBlockRI->mFlags.mCanHaveOverflowMarkers) {
// We'll do this at the next break opportunity.
RecordNoWrapFloat(outOfFlowFrame);
} else {

Просмотреть файл

@ -2957,6 +2957,7 @@ nsStyleDisplay::nsStyleDisplay(const Document& aDocument)
mScrollSnapPointsY(eStyleUnit_None),
mScrollSnapDestination(
{LengthPercentage::Zero(), LengthPercentage::Zero()}),
mLineClamp(0),
mBackfaceVisibility(NS_STYLE_BACKFACE_VISIBILITY_VISIBLE),
mTransformStyle(NS_STYLE_TRANSFORM_STYLE_FLAT),
mTransformBox(StyleGeometryBox::BorderBox),
@ -3022,6 +3023,7 @@ nsStyleDisplay::nsStyleDisplay(const nsStyleDisplay& aSource)
mScrollSnapPointsY(aSource.mScrollSnapPointsY),
mScrollSnapDestination(aSource.mScrollSnapDestination),
mScrollSnapCoordinate(aSource.mScrollSnapCoordinate),
mLineClamp(aSource.mLineClamp),
mBackfaceVisibility(aSource.mBackfaceVisibility),
mTransformStyle(aSource.mTransformStyle),
mTransformBox(aSource.mTransformBox),
@ -3219,6 +3221,10 @@ nsChangeHint nsStyleDisplay::CalcDifference(
}
}
if (mLineClamp != aNewData.mLineClamp) {
hint |= NS_STYLE_HINT_REFLOW;
}
if (mVerticalAlign != aNewData.mVerticalAlign) {
// XXX Can this just be AllReflowHints + RepaintFrame, and be included in
// the block below?

Просмотреть файл

@ -1358,6 +1358,12 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStylePosition {
struct nsStyleTextOverflowSide {
nsStyleTextOverflowSide() : mType(NS_STYLE_TEXT_OVERFLOW_CLIP) {}
static nsStyleTextOverflowSide Ellipsis() {
nsStyleTextOverflowSide side;
side.mType = NS_STYLE_TEXT_OVERFLOW_ELLIPSIS;
return side;
}
bool operator==(const nsStyleTextOverflowSide& aOther) const {
return mType == aOther.mType && (mType != NS_STYLE_TEXT_OVERFLOW_STRING ||
mString == aOther.mString);
@ -1901,6 +1907,7 @@ struct MOZ_NEEDS_MEMMOVABLE_MEMBERS nsStyleDisplay {
nsStyleCoord mScrollSnapPointsY;
mozilla::Position mScrollSnapDestination;
nsTArray<mozilla::Position> mScrollSnapCoordinate;
uint32_t mLineClamp;
// mSpecifiedTransform is the list of transform functions as
// specified, or null to indicate there is no transform. (inherit or

Просмотреть файл

@ -217,6 +217,7 @@
-moz-box-direction: inherit;
-moz-box-pack: inherit;
-moz-box-align: inherit;
-webkit-line-clamp: inherit;
/* Grid container */
grid-auto-columns: inherit;
grid-auto-rows: inherit;

Просмотреть файл

@ -8541,6 +8541,17 @@ if (IsCSSPropertyPrefEnabled("layout.css.column-span.enabled")) {
};
}
if (IsCSSPropertyPrefEnabled("layout.css.webkit-line-clamp.enabled")) {
gCSSProperties["-webkit-line-clamp"] = {
domProp: "webkitLineClamp",
inherited: false,
type: CSS_TYPE_LONGHAND,
initial_values: [ "none" ],
other_values: [ "1", "2" ],
invalid_values: [ "auto", "0", "-1" ],
};
}
if (false) {
// TODO These properties are chrome-only, and are not exposed via CSSOM.
// We may still want to find a way to test them. See bug 1206999.

Просмотреть файл

@ -298,6 +298,7 @@ var supported_properties = {
test_length_clamped, test_percent_clamped ],
"word-spacing": [ test_length_transition, test_length_unclamped ],
"z-index": [ test_integer_transition, test_pos_integer_or_auto_transition ],
"-webkit-line-clamp": [ test_pos_integer_or_none_transition ],
"-webkit-text-fill-color": [ test_color_transition,
test_currentcolor_transition ],
"-webkit-text-stroke-color": [ test_color_transition,
@ -2254,7 +2255,7 @@ function test_grid_gap(prop) {
test_percent_clamped(prop);
}
function test_pos_integer_or_auto_transition(prop) {
function test_pos_integer_or_keyword_transition(prop, keyword) {
div.style.setProperty("transition-property", "none", "");
div.style.setProperty(prop, "4", "");
is(cs.getPropertyValue(prop), "4",
@ -2264,9 +2265,9 @@ function test_pos_integer_or_auto_transition(prop) {
is(cs.getPropertyValue(prop), "6",
"integer-valued property " + prop + ": interpolation of integers");
check_distance(prop, "4", "6", "12");
div.style.setProperty(prop, "auto", "");
is(cs.getPropertyValue(prop), "auto",
"integer-valued property " + prop + ": auto not interpolable");
div.style.setProperty(prop, keyword, "");
is(cs.getPropertyValue(prop), keyword,
"integer-valued property " + prop + ": " + keyword + " not interpolable");
div.style.setProperty(prop, "8", "");
is(cs.getPropertyValue(prop), "8",
"integer-valued property " + prop + ": computed value before transition");
@ -2276,6 +2277,14 @@ function test_pos_integer_or_auto_transition(prop) {
check_distance(prop, "8", "7", "4");
}
function test_pos_integer_or_auto_transition(prop) {
return test_pos_integer_or_keyword_transition(prop, "auto");
}
function test_pos_integer_or_none_transition(prop) {
return test_pos_integer_or_keyword_transition(prop, "none");
}
function test_integer_at_least_one_clamping(prop) {
div.style.setProperty("transition-timing-function", FUNC_NEGATIVE, "");
div.style.setProperty("transition-property", "none", "");

Просмотреть файл

@ -1340,6 +1340,13 @@ VARCACHE_PREF(
)
#undef PREF_VALUE
// Is support for -webkit-line-clamp enabled?
VARCACHE_PREF(
"layout.css.webkit-line-clamp.enabled",
layout_css_webkit_line_clamp_enabled,
bool, true
)
//---------------------------------------------------------------------------
// JavaScript prefs
//---------------------------------------------------------------------------

Просмотреть файл

@ -337,6 +337,7 @@ class Longhand(object):
"OverflowWrap",
"OverscrollBehavior",
"Percentage",
"PositiveIntegerOrNone",
"Resize",
"SVGOpacity",
"SVGPaintOrder",

Просмотреть файл

@ -2515,7 +2515,7 @@ fn static_assert() {
rotate scroll-snap-points-x scroll-snap-points-y
scroll-snap-coordinate -moz-binding will-change
offset-path shape-outside
translate scale""" %>
translate scale -webkit-line-clamp""" %>
<%self:impl_trait style_struct_name="Box" skip_longhands="${skip_box_longhands}">
#[inline]
pub fn generate_combined_transform(&mut self) {
@ -2924,6 +2924,27 @@ fn static_assert() {
self.copy_offset_path_from(other);
}
#[allow(non_snake_case)]
pub fn set__webkit_line_clamp(&mut self, v: longhands::_webkit_line_clamp::computed_value::T) {
self.gecko.mLineClamp = match v {
Either::First(n) => n.0 as u32,
Either::Second(None_) => 0,
};
}
${impl_simple_copy('_webkit_line_clamp', 'mLineClamp')}
#[allow(non_snake_case)]
pub fn clone__webkit_line_clamp(&self) -> longhands::_webkit_line_clamp::computed_value::T {
match self.gecko.mLineClamp {
0 => Either::Second(None_),
n => {
debug_assert!(n <= std::i32::MAX as u32);
Either::First((n as i32).into())
}
}
}
</%self:impl_trait>
<%def name="simple_image_array_property(name, shorthand, field_name)">

Просмотреть файл

@ -670,3 +670,15 @@ ${helpers.predefined_type(
animation_value_type="discrete",
spec="https://compat.spec.whatwg.org/#touch-action",
)}
// Note that we only implement -webkit-line-clamp as a single, longhand
// property for now, but the spec defines line-clamp as a shorthand for separate
// max-lines, block-ellipsis, and continue properties.
${helpers.predefined_type(
"-webkit-line-clamp",
"PositiveIntegerOrNone",
"Either::Second(None_)",
gecko_pref="layout.css.webkit-line-clamp.enabled",
animation_value_type="Integer",
spec="https://drafts.csswg.org/css-overflow-3/#line-clamp",
)}

Просмотреть файл

@ -640,6 +640,9 @@ impl From<CSSInteger> for PositiveInteger {
}
}
/// A computed positive `<integer>` value or `none`.
pub type PositiveIntegerOrNone = Either<PositiveInteger, None_>;
/// rect(...)
pub type ClipRect = generics::ClipRect<LengthOrAuto>;

Просмотреть файл

@ -12,7 +12,7 @@ use super::generics::grid::{GridLine as GenericGridLine, TrackBreadth as Generic
use super::generics::grid::{TrackList as GenericTrackList, TrackSize as GenericTrackSize};
use super::generics::transform::IsParallelTo;
use super::generics::{self, GreaterThanOrEqualToOne, NonNegative};
use super::{Auto, CSSFloat, CSSInteger, Either};
use super::{Auto, CSSFloat, CSSInteger, Either, None_};
use crate::context::QuirksMode;
use crate::parser::{Parse, ParserContext};
use crate::values::serialize_atom_identifier;
@ -593,6 +593,9 @@ impl Parse for PositiveInteger {
}
}
/// A specified positive `<integer>` value or `none`.
pub type PositiveIntegerOrNone = Either<PositiveInteger, None_>;
/// The specified value of a grid `<track-breadth>`
pub type TrackBreadth = GenericTrackBreadth<LengthPercentage>;

Просмотреть файл

@ -1,2 +0,0 @@
[webkit-line-clamp-with-line-height.tentative.html]
expected: FAIL

Просмотреть файл

@ -0,0 +1,24 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Overflow: parsing -webkit-line-clamp with invalid values</title>
<link rel="help" href="https://drafts.csswg.org/css-overflow/#webkit-line-clamp">
<meta name="assert" content="-webkit-line-clamp supports only the grammar 'none | <integer>'.">
<meta name="assert" content="Zero or negative max-lines integers are invalid.">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/support/parsing-testcommon.js"></script>
</head>
<body>
<script>
test_invalid_value("-webkit-line-clamp", 'auto');
test_invalid_value("-webkit-line-clamp", '0');
test_invalid_value("-webkit-line-clamp", '-5');
test_invalid_value("-webkit-line-clamp", 'none "~"');
test_invalid_value("-webkit-line-clamp", '1 "~"');
</script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>CSS Overflow: parsing -webkit-line-clamp with valid values</title>
<link rel="help" href="https://drafts.csswg.org/css-overflow/#webkit-line-clamp">
<meta name="assert" content="-webkit-line-clamp supports the full grammar 'none | <integer>'.">
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="/css/support/parsing-testcommon.js"></script>
</head>
<body>
<script>
test_valid_value("-webkit-line-clamp", 'none');
test_valid_value("-webkit-line-clamp", '1');
test_valid_value("-webkit-line-clamp", '6');
</script>
</body>
</html>

Просмотреть файл

@ -0,0 +1,15 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Reference</title>
<style>
.clamp {
font: 16px / 32px serif;
white-space: pre;
background-color: yellow;
}
</style>
<div class="clamp">Line 1
Line 2
Line 3
Line 4
Line 5</div>

Просмотреть файл

@ -0,0 +1,17 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Reference</title>
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
}
</style>
<div class="clamp">Line 1
Line 2
Line 3
Line 4…</div>

Просмотреть файл

@ -0,0 +1,18 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Reference</title>
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
}
</style>
<div class="clamp">Line 1
Line 2
Line 3
Line 4…</div>
<p>Following content.</p>

Просмотреть файл

@ -0,0 +1,17 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Reference</title>
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
}
</style>
<div class="clamp"><div>Line 1
Line 2
Line 3
Line 4…</div></div>

Просмотреть файл

@ -0,0 +1,17 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Reference</title>
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
}
</style>
<div class="clamp"><div>Line 1
Line 2…</div><div>Line A
Line B…</div>Line 一
Line 二…</div>

Просмотреть файл

@ -0,0 +1,19 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Reference</title>
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
}
.child {
font: 24px / 48px serif;
color: blue;
}
</style>
<div class="clamp"><div>Line 1
Line 2<div class="child">Line 3…</div></div></div>

Просмотреть файл

@ -0,0 +1,20 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Reference</title>
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
}
.child {
font: 24px / 48px serif;
color: blue;
}
</style>
<div class="clamp"><div>Line 1
Line 2<div class="child">Line 3
Line 4</div>Line 5…</div></div>

Просмотреть файл

@ -0,0 +1,21 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Reference</title>
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
}
.child {
font: 24px / 48px serif;
color: blue;
padding: 0 4px;
}
</style>
<div class="clamp"><div>Line 1
Line 2<div class="child">Line 3
Line 4</div>Line 5…</div></div>

Просмотреть файл

@ -0,0 +1,21 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Reference</title>
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
}
.child {
display: flex;
font: 24px / 48px serif;
color: blue;
}
</style>
<div class="clamp"><div>Line 1
Line 2<div class="child">Line 3
Line 4</div>Line 5…</div></div>

Просмотреть файл

@ -0,0 +1,20 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Reference</title>
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
}
.child {
font: 24px / 48px serif;
color: blue;
}
</style>
<div class="clamp"><div>Line 1
Line 2<table class="child" border="1"><tr><td>Line 3
Line 4</td></tr></table>Line 5…</div></div>

Просмотреть файл

@ -0,0 +1,16 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Reference</title>
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
direction: rtl;
}
</style>
<div class="clamp">Line 1
Line 2…</div>

Просмотреть файл

@ -0,0 +1,19 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Reference</title>
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: horizontal;
font: 16px / 32px serif;
white-space: pre;
padding: 4px 0;
background-color: yellow;
writing-mode: vertical-rl;
}
</style>
<div class="clamp">Line 1
Line 2
Line 3
Line 4
Line 5</div>

Просмотреть файл

@ -0,0 +1,15 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Reference</title>
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
}
</style>
<div class="clamp">Line 1
Line 2…</div>

Просмотреть файл

@ -0,0 +1,17 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Reference</title>
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
}
</style>
<div class="clamp">Line 1
Line 2
Line 3…</div>
<p>Following content.</p>

Просмотреть файл

@ -0,0 +1,19 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Reference</title>
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
}
</style>
<div class="clamp">Line 1
Line 2
Line 3
Line 4
Line 5</div>
<p>Following content.</p>

Просмотреть файл

@ -0,0 +1,19 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Reference</title>
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
}
</style>
<div class="clamp">Line 1
Line 2
Line 3
Line 4
Line 5</div>
<p>Following content.</p>

Просмотреть файл

@ -0,0 +1,17 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Reference</title>
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
}
</style>
<div class="clamp">Line 1
Line 2
Line 3…</div>
<p>Following content.</p>

Просмотреть файл

@ -0,0 +1,17 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Reference</title>
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
}
</style>
<div class="clamp">Line 1
Line 2
Line 3…</div>
<p>Following content.</p>

Просмотреть файл

@ -0,0 +1,16 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Reference</title>
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
}
</style>
<div class="clamp">Line 1
Line 2</div>
<p>Following content.</p>

Просмотреть файл

@ -0,0 +1,17 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Reference</title>
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
}
</style>
<div class="clamp">Line 1
Line 2
Line 3</div>
<p>Following content.</p>

Просмотреть файл

@ -0,0 +1,17 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Reference</title>
<style>
.clamp {
display: -webkit-inline-box;
-webkit-box-orient: vertical;
font: 16px / 32px monospace;
white-space: pre;
padding: 0 4px;
background-color: yellow;
}
</style>
Before <div class="clamp">Line 1
Line 2
Line …</div> After</div>
<p>Following content.</p>

Просмотреть файл

@ -0,0 +1,19 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Reference</title>
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
font: 16px / 32px monospace;
white-space: pre;
padding: 0 4px;
background-color: yellow;
width: 11ch;
}
.float {
float: right;
color: orange;
}
</style>
<div class="clamp"><div><div class="float">[f]</div>A B C D…</div>

Просмотреть файл

@ -0,0 +1,18 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Reference</title>
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
font: 16px / 32px monospace;
white-space: pre;
background-color: yellow;
}
</style>
<div class="clamp">Line 1
Line 2
Line 3
Line 4
Line 5</div>
<p>Following content.</p>

Просмотреть файл

@ -0,0 +1,17 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Reference</title>
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
font: 16px / 32px monospace;
white-space: pre;
background-color: yellow;
}
</style>
<div class="clamp"><div>Line 1
Line 2<fieldset>Line 3
Line 4<legend>Line 5
Line 6</legend></fieldset>Line 7…</div></div>
<p>Following content.</p>

Просмотреть файл

@ -0,0 +1,19 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Reference</title>
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
font: 16px / 32px monospace;
white-space: pre;
background-color: yellow;
}
.child {
overflow: hidden;
}
</style>
<div class="clamp"><div class="child">Line 1
Line 2
Line 3…</div></div>
<p>Following content.</p>

Просмотреть файл

@ -0,0 +1,18 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Reference</title>
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
font: 16px / 32px monospace;
white-space: pre;
background-color: yellow;
border: none;
overflow: hidden;
}
</style>
<div class="clamp"><div>Line 1
Line 2
Line 3…</div></div>
<p>Following content.</p>

Просмотреть файл

@ -0,0 +1,22 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Reference</title>
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
}
.big {
font-weight: bold;
border-top: 2px solid blue;
padding: 20px 0;
}
</style>
<div class="clamp"><div class="item">Line 1
Line 2
Line 3 <span class="big">BIG</span></div></div>
<p>Following content.</p>

Просмотреть файл

@ -0,0 +1,17 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Reference</title>
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
}
</style>
<div class="clamp">Line 1
Line 2
Line 3
</div>

Просмотреть файл

@ -0,0 +1,20 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Overflow: -webkit-line-clamp when not display:-webkit-box</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#webkit-line-clamp">
<link rel="match" href="reference/webkit-line-clamp-001-ref.html">
<meta name="assert" content="-webkit-line-clamp should not apply to an element that is not a flex item for a legacy -webkit-box or -webkit-inline-box flex container.">
<style>
.clamp {
-webkit-line-clamp: 3;
font: 16px / 32px serif;
white-space: pre;
background-color: yellow;
}
</style>
<div class="clamp">Line 1
Line 2
Line 3
Line 4
Line 5</div>

Просмотреть файл

@ -0,0 +1,21 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Overflow: -webkit-line-clamp when not -webkit-box-orient:vertical</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#webkit-line-clamp">
<link rel="match" href="reference/webkit-line-clamp-001-ref.html">
<meta name="assert" content="-webkit-line-clamp should not apply to an element whose parent is not -webkit-box-orient:vertical.">
<style>
.clamp {
display: -webkit-box;
-webkit-line-clamp: 3;
font: 16px / 32px serif;
white-space: pre;
background-color: yellow;
}
</style>
<div class="clamp">Line 1
Line 2
Line 3
Line 4
Line 5</div>

Просмотреть файл

@ -0,0 +1,22 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Overflow: -webkit-line-clamp with fewer lines than specified</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#webkit-line-clamp">
<link rel="match" href="reference/webkit-line-clamp-001-ref.html">
<meta name="assert" content="-webkit-line-clamp should not have an effect on an element with fewer lines than specified.">
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 6;
font: 16px / 32px serif;
white-space: pre;
background-color: yellow;
}
</style>
<div class="clamp">Line 1
Line 2
Line 3
Line 4
Line 5</div>

Просмотреть файл

@ -0,0 +1,22 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Overflow: -webkit-line-clamp with exactly as many lines as specified</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#webkit-line-clamp">
<link rel="match" href="reference/webkit-line-clamp-001-ref.html">
<meta name="assert" content="-webkit-line-clamp should not have an effect on an element with exactly as many lines as specified.">
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 5;
font: 16px / 32px serif;
white-space: pre;
background-color: yellow;
}
</style>
<div class="clamp">Line 1
Line 2
Line 3
Line 4
Line 5</div>

Просмотреть файл

@ -0,0 +1,24 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Overflow: -webkit-line-clamp with more lines than specified</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#webkit-line-clamp">
<link rel="match" href="reference/webkit-line-clamp-005-ref.html">
<meta name="assert" content="-webkit-line-clamp should clamp to the specified number of lines.">
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 4;
font: 16px / 32px serif;
white-space: pre;
background-color: yellow;
padding: 0 4px;
overflow: hidden; /* can be removed once implementations update their old -webkit-line-clamp implementations */
}
</style>
<div class="clamp">Line 1
Line 2
Line 3
Line 4
Line 5</div>

Просмотреть файл

@ -0,0 +1,25 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Overflow: sizing of -webkit-line-clamp affected elements</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#webkit-line-clamp">
<link rel="match" href="reference/webkit-line-clamp-006-ref.html">
<meta name="assert" content="-webkit-line-clamp should size the element to the clamped number of lines.">
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 4;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
overflow: hidden; /* can be removed once implementations update their old -webkit-line-clamp implementations */
}
</style>
<div class="clamp">Line 1
Line 2
Line 3
Line 4
Line 5</div>
<p>Following content.</p>

Просмотреть файл

@ -0,0 +1,24 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Overflow: -webkit-line-clamp applied to a non-anonymous flex item</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#webkit-line-clamp">
<link rel="match" href="reference/webkit-line-clamp-007-ref.html">
<meta name="assert" content="-webkit-line-clamp should apply to a flex item in a -webkit-box or -webkit-inline-box flex container.">
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 4;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
overflow: hidden; /* can be removed once implementations update their old -webkit-line-clamp implementations */
}
</style>
<div class="clamp"><div>Line 1
Line 2
Line 3
Line 4
Line 5</div></div>

Просмотреть файл

@ -0,0 +1,28 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Overflow: -webkit-line-clamp applied to all flex items</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#webkit-line-clamp">
<link rel="match" href="reference/webkit-line-clamp-008-ref.html">
<meta name="assert" content="-webkit-line-clamp should apply to all flex items in a -webkit-box or -webkit-inline-box flex container independently.">
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
}
div {
overflow: hidden; /* can be removed once implementations update their old -webkit-line-clamp implementations */
}
</style>
<div class="clamp"><div>Line 1
Line 2
Line 3</div><div>Line A
Line B
Line C</div>Line 一
Line 二
Line 三</div>

Просмотреть файл

@ -0,0 +1,26 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Overflow: -webkit-line-clamp with non-BFC block children in flex item</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#webkit-line-clamp">
<link rel="match" href="reference/webkit-line-clamp-009-ref.html">
<meta name="assert" content="-webkit-line-clamp should count lines in non-BFC block children of the flex items.">
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
overflow: hidden; /* can be removed once implementations update their old -webkit-line-clamp implementations */
}
.child {
font: 24px / 48px serif;
color: blue;
}
</style>
<div class="clamp"><div>Line 1
Line 2<div class="child">Line 3
Line 4</div></div></div>

Просмотреть файл

@ -0,0 +1,27 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Overflow: -webkit-line-clamp with non-BFC block children in flex item</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#webkit-line-clamp">
<link rel="match" href="reference/webkit-line-clamp-010-ref.html">
<meta name="assert" content="-webkit-line-clamp should count lines in non-BFC block children of the flex items.">
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 5;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
overflow: hidden; /* can be removed once implementations update their old -webkit-line-clamp implementations */
}
.child {
font: 24px / 48px serif;
color: blue;
}
</style>
<div class="clamp"><div>Line 1
Line 2<div class="child">Line 3
Line 4</div>Line 5
Line 6</div></div>

Просмотреть файл

@ -0,0 +1,29 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Overflow: -webkit-line-clamp with BFC child in flex item</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#webkit-line-clamp">
<link rel="match" href="reference/webkit-line-clamp-011-ref.html">
<meta name="assert" content="-webkit-line-clamp should skip lines in BFC children of the flex items.">
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
overflow: hidden; /* can be removed once implementations update their old -webkit-line-clamp implementations */
}
.child {
overflow: auto;
font: 24px / 48px serif;
color: blue;
padding: 0 4px;
}
</style>
<div class="clamp"><div>Line 1
Line 2<div class="child">Line 3
Line 4</div>Line 5
Line 6</div></div>

Просмотреть файл

@ -0,0 +1,28 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Overflow: -webkit-line-clamp with flex container child in flex item</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#webkit-line-clamp">
<link rel="match" href="reference/webkit-line-clamp-012-ref.html">
<meta name="assert" content="-webkit-line-clamp should skip lines in independent formatting contexts in the flex items.">
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
overflow: hidden; /* can be removed once implementations update their old -webkit-line-clamp implementations */
}
.child {
display: flex;
font: 24px / 48px serif;
color: blue;
}
</style>
<div class="clamp"><div>Line 1
Line 2<div class="child">Line 3
Line 4</div>Line 5
Line 6</div></div>

Просмотреть файл

@ -0,0 +1,27 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Overflow: -webkit-line-clamp with table child in flex item</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#webkit-line-clamp">
<link rel="match" href="reference/webkit-line-clamp-013-ref.html">
<meta name="assert" content="-webkit-line-clamp should skip lines in independent formatting contexts in the flex items.">
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
overflow: hidden; /* can be removed once implementations update their old -webkit-line-clamp implementations */
}
.child {
font: 24px / 48px serif;
color: blue;
}
</style>
<div class="clamp"><div>Line 1
Line 2<table class="child" border="1"><tr><td>Line 3
Line 4</td></tr></table>Line 5
Line 6</div></div>

Просмотреть файл

@ -0,0 +1,23 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Overflow: -webkit-line-clamp on RTL flex item</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#webkit-line-clamp">
<link rel="match" href="reference/webkit-line-clamp-014-ref.html">
<meta name="assert" content="-webkit-line-clamp should place the ellipsis appropriately in RTL content.">
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
overflow: hidden; /* can be removed once implementations update their old -webkit-line-clamp implementations */
direction: rtl;
}
</style>
<div class="clamp">Line 1
Line 2
Line 3</div>

Просмотреть файл

@ -0,0 +1,25 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Overflow: -webkit-line-clamp on vertical writing mode flex item when -webkit-box-orient:horizontal</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#webkit-line-clamp">
<link rel="match" href="reference/webkit-line-clamp-015-ref.html">
<meta name="assert" content="-webkit-line-clamp should not apply to a -webkit-box-orient:horizontal flex item even if using a vertical writing mode.">
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: horizontal;
-webkit-line-clamp: 2;
font: 16px / 32px serif;
white-space: pre;
padding: 4px 0;
background-color: yellow;
overflow: hidden; /* can be removed once implementations update their old -webkit-line-clamp implementations */
writing-mode: vertical-rl;
}
</style>
<div class="clamp">Line 1
Line 2
Line 3
Line 4
Line 5</div>

Просмотреть файл

@ -0,0 +1,27 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Overflow: -webkit-line-clamp value on flex child</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#webkit-line-clamp">
<link rel="match" href="reference/webkit-line-clamp-016-ref.html">
<meta name="assert" content="-webkit-line-clamp value on the flex child should be ignored.">
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
overflow: hidden; /* can be removed once implementations update their old -webkit-line-clamp implementations */
}
.child {
-webkit-line-clamp: 3;
}
</style>
<div class="clamp"><div class="child">Line 1
Line 2
Line 3
Line 4
Line 5</div></div>

Просмотреть файл

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html class="reftest-wait">
<meta charset="utf-8">
<title>CSS Overflow: Dynamically changing -webkit-line-clamp</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#webkit-line-clamp">
<link rel="match" href="reference/webkit-line-clamp-017-ref.html">
<meta name="assert" content="Dynamically changing -webkit-line-clamp on an element from none to a number less than the number of lines should apply the clamping.">
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
overflow: hidden; /* can be removed once implementations update their old -webkit-line-clamp implementations */
}
</style>
<div class="clamp">Line 1
Line 2
Line 3
Line 4
Line 5</div>
<p>Following content.</p>
<script>
window.onload = function() {
document.querySelector(".clamp").style.webkitLineClamp = 3;
document.documentElement.className = "";
};
</script>

Просмотреть файл

@ -0,0 +1,32 @@
<!DOCTYPE html>
<html class="reftest-wait">
<meta charset="utf-8">
<title>CSS Overflow: Dynamically changing -webkit-line-clamp</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#webkit-line-clamp">
<link rel="match" href="reference/webkit-line-clamp-018-ref.html">
<meta name="assert" content="Dynamically changing -webkit-line-clamp on an element from a number to none remove the clamping.">
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
overflow: hidden; /* can be removed once implementations update their old -webkit-line-clamp implementations */
}
</style>
<div class="clamp">Line 1
Line 2
Line 3
Line 4
Line 5</div>
<p>Following content.</p>
<script>
window.onload = function() {
document.querySelector(".clamp").style.webkitLineClamp = "none";
document.documentElement.className = "";
};
</script>

Просмотреть файл

@ -0,0 +1,32 @@
<!DOCTYPE html>
<html class="reftest-wait">
<meta charset="utf-8">
<title>CSS Overflow: Dynamically changing -webkit-line-clamp</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#webkit-line-clamp">
<link rel="match" href="reference/webkit-line-clamp-019-ref.html">
<meta name="assert" content="Dynamically changing -webkit-line-clamp on an element from a number less than to a number greater than the number of lines.">
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
overflow: hidden; /* can be removed once implementations update their old -webkit-line-clamp implementations */
}
</style>
<div class="clamp">Line 1
Line 2
Line 3
Line 4
Line 5</div>
<p>Following content.</p>
<script>
window.onload = function() {
document.querySelector(".clamp").style.webkitLineClamp = 6;
document.documentElement.className = "";
};
</script>

Просмотреть файл

@ -0,0 +1,32 @@
<!DOCTYPE html>
<html class="reftest-wait">
<meta charset="utf-8">
<title>CSS Overflow: Dynamically changing -webkit-line-clamp</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#webkit-line-clamp">
<link rel="match" href="reference/webkit-line-clamp-020-ref.html">
<meta name="assert" content="Dynamically changing -webkit-line-clamp on an element from a number greater than to a number less than the number of lines.">
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 6;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
overflow: hidden; /* can be removed once implementations update their old -webkit-line-clamp implementations */
}
</style>
<div class="clamp">Line 1
Line 2
Line 3
Line 4
Line 5</div>
<p>Following content.</p>
<script>
window.onload = function() {
document.querySelector(".clamp").style.webkitLineClamp = 3;
document.documentElement.className = "";
};
</script>

Просмотреть файл

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html class="reftest-wait">
<meta charset="utf-8">
<title>CSS Overflow: Dynamically changing contents of a -webkit-line-clamp affected element</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#webkit-line-clamp">
<link rel="match" href="reference/webkit-line-clamp-021-ref.html">
<meta name="assert" content="Dynamically changing contents of a -webkit-line-clamp element so that it exceeds the specified number of lines should start clamping.">
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
overflow: hidden; /* can be removed once implementations update their old -webkit-line-clamp implementations */
}
</style>
<div class="clamp">Line 1
Line 2</div>
<p>Following content.</p>
<script>
window.onload = function() {
document.querySelector(".clamp").textContent = `Line 1
Line 2
Line 3
Line 4
Line 5`;
document.documentElement.className = "";
};
</script>

Просмотреть файл

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html class="reftest-wait">
<meta charset="utf-8">
<title>CSS Overflow: Dynamically changing contents of a -webkit-line-clamp affected element</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#webkit-line-clamp">
<link rel="match" href="reference/webkit-line-clamp-022-ref.html">
<meta name="assert" content="Dynamically changing contents of a -webkit-line-clamp element so that it no longer exceeds the specified number of lines should stop clamping.">
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
overflow: hidden; /* can be removed once implementations update their old -webkit-line-clamp implementations */
}
</style>
<div class="clamp">Line 1
Line 2
Line 3
Line 4
Line 5</div>
<p>Following content.</p>
<script>
window.onload = function() {
document.querySelector(".clamp").textContent = `Line 1
Line 2`;
document.documentElement.className = "";
};
</script>

Просмотреть файл

@ -0,0 +1,34 @@
<!DOCTYPE html>
<html class="reftest-wait">
<meta charset="utf-8">
<title>CSS Overflow: Dynamically changing contents of a -webkit-line-clamp affected element</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#webkit-line-clamp">
<link rel="match" href="reference/webkit-line-clamp-023-ref.html">
<meta name="assert" content="Dynamically changing contents of a -webkit-line-clamp element so that it matches the specified number of lines should stop clamping.">
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
overflow: hidden; /* can be removed once implementations update their old -webkit-line-clamp implementations */
}
</style>
<div class="clamp">Line 1
Line 2
Line 3
Line 4
Line 5</div>
<p>Following content.</p>
<script>
window.onload = function() {
document.querySelector(".clamp").textContent = `Line 1
Line 2
Line 3`;
document.documentElement.className = "";
};
</script>

Просмотреть файл

@ -0,0 +1,25 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Overflow: -webkit-line-clamp on a display:-webkit-inline-box container</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#webkit-line-clamp">
<link rel="match" href="reference/webkit-line-clamp-024-ref.html">
<meta name="assert" content="-webkit-line-clamp should apply to display:-webkit-inline-box containers.">
<style>
.clamp {
display: -webkit-inline-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
font: 16px / 32px monospace;
white-space: pre;
padding: 0 4px;
background-color: yellow;
overflow: hidden; /* can be removed once implementations update their old -webkit-line-clamp implementations */
}
</style>
Before <div class="clamp">Line 1
Line 2
Line 3
Line 4
Line 5</div> After</div>
<p>Following content.</p>

Просмотреть файл

@ -0,0 +1,26 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Overflow: -webkit-line-clamp with floats</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#webkit-line-clamp">
<link rel="match" href="reference/webkit-line-clamp-025-ref.html">
<meta name="assert" content="A -webkit-line-clamp induced ellipsis is placed after shrinking the line due to floats.">
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 1;
font: 16px / 32px monospace;
white-space: pre;
padding: 0 4px;
background-color: yellow;
width: 11ch;
overflow: hidden; /* can be removed once implementations update their old -webkit-line-clamp implementations */
}
.float {
float: right;
color: orange;
}
</style>
<div class="clamp"><div><div class="float">[f]</div>A B C D
E F G H</div></div>

Просмотреть файл

@ -0,0 +1,31 @@
<!DOCTYPE html>
<html class="reftest-wait">
<meta charset="utf-8">
<title>CSS Overflow: Dynamically changing -webkit-box-orient when -webkit-line-clamp applies</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#webkit-line-clamp">
<link rel="match" href="reference/webkit-line-clamp-026-ref.html">
<meta name="assert" content="Dynamically changing a -webkit-line-clamp affected element to be -webkit-box-orient:horizontal should cause the line clamp to be removed.">
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
font: 16px / 32px monospace;
white-space: pre;
background-color: yellow;
overflow: hidden; /* can be removed once implementations update their old -webkit-line-clamp implementations */
}
</style>
<div class="clamp">Line 1
Line 2
Line 3
Line 4
Line 5</div>
<p>Following content.</p>
<script>
window.onload = function() {
document.querySelector(".clamp").style.webkitBoxOrient = "horizontal";
document.documentElement.className = "";
};
</script>

Просмотреть файл

@ -0,0 +1,24 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Overflow: -webkit-line-clamp and fieldset</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#webkit-line-clamp">
<link rel="match" href="reference/webkit-line-clamp-027-ref.html">
<meta name="assert" content="-webkit-line-clamp should skip over fieldsets.">
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
font: 16px / 32px monospace;
white-space: pre;
background-color: yellow;
overflow: hidden; /* can be removed once implementations update their old -webkit-line-clamp implementations */
}
</style>
<div class="clamp"><div>Line 1
Line 2<fieldset>Line 3
Line 4<legend>Line 5
Line 6</legend></fieldset>Line 7
Line 8</div></div>
<p>Following content.</p>

Просмотреть файл

@ -0,0 +1,27 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Overflow: -webkit-line-clamp and scrollable items</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#webkit-line-clamp">
<link rel="match" href="reference/webkit-line-clamp-029-ref.html">
<meta name="assert" content="-webkit-line-clamp should apply to flex items that are scrollable.">
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
font: 16px / 32px monospace;
white-space: pre;
background-color: yellow;
overflow: hidden; /* can be removed once implementations update their old -webkit-line-clamp implementations */
}
.child {
overflow: hidden;
}
</style>
<div class="clamp"><div class="child">Line 1
Line 2
Line 3
Line 4
Line 5</div></div>
<p>Following content.</p>

Просмотреть файл

@ -0,0 +1,24 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Overflow: -webkit-line-clamp and scrollable container</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#webkit-line-clamp">
<link rel="match" href="reference/webkit-line-clamp-030-ref.html">
<meta name="assert" content="-webkit-line-clamp should apply to flex items when the container is scrollable.">
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
font: 16px / 32px monospace;
white-space: pre;
background-color: yellow;
overflow: hidden;
}
</style>
<div class="clamp"><div>Line 1
Line 2
Line 3
Line 4
Line 5</div></div>
<p>Following content.</p>

Просмотреть файл

@ -0,0 +1,31 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Overflow: -webkit-line-clamp and a line with inlines of different heights</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#webkit-line-clamp">
<link rel="match" href="reference/webkit-line-clamp-031-ref.html">
<meta name="assert" content="-webkit-line-clamp should clamp to the bottom of the line box.">
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 3;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
overflow: hidden; /* can be removed once implementations update their old -webkit-line-clamp implementations */
}
.big {
font-weight: bold;
border-top: 2px solid blue;
border-bottom: 2px solid blue;
padding: 20px 0;
}
</style>
<div class="clamp"><div>Line 1
Line 2
Line 3 <span class="big">BIG</span>
Line 4
Line 5</div></div>
<p>Following content.</p>

Просмотреть файл

@ -0,0 +1,24 @@
<!DOCTYPE html>
<meta charset="utf-8">
<title>CSS Overflow: -webkit-line-clamp with an ellipsis on a blank line</title>
<link rel="author" title="Cameron McCormack" href="mailto:cam@mcc.id.au">
<link rel="help" href="https://drafts.csswg.org/css-overflow-3/#webkit-line-clamp">
<link rel="match" href="reference/webkit-line-clamp-032-ref.html">
<meta name="assert" content="-webkit-line-clamp should render an ellipsis on a blank line.">
<style>
.clamp {
display: -webkit-box;
-webkit-box-orient: vertical;
-webkit-line-clamp: 4;
font: 16px / 32px serif;
white-space: pre;
padding: 0 4px;
background-color: yellow;
overflow: hidden; /* can be removed once implementations update their old -webkit-line-clamp implementations */
}
</style>
<div class="clamp">Line 1
Line 2
Line 3
Line 5</div>