diff --git a/layout/generic/TextOverflow.cpp b/layout/generic/TextOverflow.cpp index 576aa65406df..599923a33242 100644 --- a/layout/generic/TextOverflow.cpp +++ b/layout/generic/TextOverflow.cpp @@ -287,7 +287,8 @@ TextOverflow::ExamineFrameSubtree(nsIFrame* aFrame, const nsRect& aInsideMarkersArea, FrameHashtable* aFramesToHide, AlignmentEdges* aAlignmentEdges, - bool* aFoundVisibleTextOrAtomic) + bool* aFoundVisibleTextOrAtomic, + InnerClipEdges* aClippedMarkerEdges) { const nsIAtom* frameType = aFrame->GetType(); if (frameType == nsGkAtoms::brFrame || @@ -312,7 +313,8 @@ TextOverflow::ExamineFrameSubtree(nsIFrame* aFrame, } else if (isAtomic || frameType == nsGkAtoms::textFrame) { AnalyzeMarkerEdges(aFrame, frameType, aInsideMarkersArea, aFramesToHide, aAlignmentEdges, - aFoundVisibleTextOrAtomic); + aFoundVisibleTextOrAtomic, + aClippedMarkerEdges); } } if (isAtomic) { @@ -323,7 +325,8 @@ TextOverflow::ExamineFrameSubtree(nsIFrame* aFrame, while (child) { ExamineFrameSubtree(child, aContentArea, aInsideMarkersArea, aFramesToHide, aAlignmentEdges, - aFoundVisibleTextOrAtomic); + aFoundVisibleTextOrAtomic, + aClippedMarkerEdges); child = child->GetNextSibling(); } } @@ -334,7 +337,8 @@ TextOverflow::AnalyzeMarkerEdges(nsIFrame* aFrame, const nsRect& aInsideMarkersArea, FrameHashtable* aFramesToHide, AlignmentEdges* aAlignmentEdges, - bool* aFoundVisibleTextOrAtomic) + bool* aFoundVisibleTextOrAtomic, + InnerClipEdges* aClippedMarkerEdges) { nsRect borderRect(aFrame->GetOffsetTo(mBlock), aFrame->GetSize()); nscoord leftOverlap = @@ -344,43 +348,43 @@ TextOverflow::AnalyzeMarkerEdges(nsIFrame* aFrame, bool insideLeftEdge = aInsideMarkersArea.x <= borderRect.XMost(); bool insideRightEdge = borderRect.x <= aInsideMarkersArea.XMost(); + if (leftOverlap > 0) { + aClippedMarkerEdges->AccumulateLeft(borderRect); + if (!mLeft.mActive) { + leftOverlap = 0; + } + } + if (rightOverlap > 0) { + aClippedMarkerEdges->AccumulateRight(borderRect); + if (!mRight.mActive) { + rightOverlap = 0; + } + } + if ((leftOverlap > 0 && insideLeftEdge) || (rightOverlap > 0 && insideRightEdge)) { - if (aFrameType == nsGkAtoms::textFrame && - aInsideMarkersArea.x < aInsideMarkersArea.XMost()) { - if (!mLeft.mActive) { - leftOverlap = 0; - } - if (!mRight.mActive) { - rightOverlap = 0; - } - if (leftOverlap == 0 && rightOverlap == 0) { - return; - } - // a clipped text frame and there is some room between the markers - nscoord snappedLeft, snappedRight; - bool isFullyClipped = - IsFullyClipped(static_cast(aFrame), - leftOverlap, rightOverlap, &snappedLeft, &snappedRight); - if (!isFullyClipped) { - nsRect snappedRect = borderRect; - if (leftOverlap > 0) { - snappedRect.x += snappedLeft; - snappedRect.width -= snappedLeft; + if (aFrameType == nsGkAtoms::textFrame) { + if (aInsideMarkersArea.x < aInsideMarkersArea.XMost()) { + // a clipped text frame and there is some room between the markers + nscoord snappedLeft, snappedRight; + bool isFullyClipped = + IsFullyClipped(static_cast(aFrame), + leftOverlap, rightOverlap, &snappedLeft, &snappedRight); + if (!isFullyClipped) { + nsRect snappedRect = borderRect; + if (leftOverlap > 0) { + snappedRect.x += snappedLeft; + snappedRect.width -= snappedLeft; + } + if (rightOverlap > 0) { + snappedRect.width -= snappedRight; + } + aAlignmentEdges->Accumulate(snappedRect); + *aFoundVisibleTextOrAtomic = true; } - if (rightOverlap > 0) { - snappedRect.width -= snappedRight; - } - aAlignmentEdges->Accumulate(snappedRect); - *aFoundVisibleTextOrAtomic = true; - } - } else if (IsAtomicElement(aFrame, aFrameType)) { - if ((leftOverlap > 0 && insideLeftEdge && mLeft.mActive) || - (rightOverlap > 0 && insideRightEdge && mRight.mActive)) { - aFramesToHide->PutEntry(aFrame); - } else { - *aFoundVisibleTextOrAtomic = true; } + } else { + aFramesToHide->PutEntry(aFrame); } } else if (!insideLeftEdge || !insideRightEdge) { // frame is outside @@ -434,11 +438,14 @@ TextOverflow::ExamineLineFrames(nsLineBox* aLine, return; } - PRUint32 pass = 0; + int pass = 0; + bool retryEmptyLine = true; bool guessLeft = leftOverflow; bool guessRight = rightOverflow; mLeft.mActive = leftOverflow; mRight.mActive = rightOverflow; + bool clippedLeftMarker = false; + bool clippedRightMarker = false; do { // Setup marker strings as needed. if (guessLeft) { @@ -450,9 +457,9 @@ TextOverflow::ExamineLineFrames(nsLineBox* aLine, // If there is insufficient space for both markers then keep the one on the // end side per the block's 'direction'. - nscoord rightMarkerWidth = mRight.mWidth; - nscoord leftMarkerWidth = mLeft.mWidth; - if (leftOverflow && rightOverflow && + nscoord rightMarkerWidth = mRight.mActive ? mRight.mWidth : 0; + nscoord leftMarkerWidth = mLeft.mActive ? mLeft.mWidth : 0; + if (leftMarkerWidth && rightMarkerWidth && leftMarkerWidth + rightMarkerWidth > contentArea.width) { if (mBlockIsRTL) { rightMarkerWidth = 0; @@ -476,12 +483,52 @@ TextOverflow::ExamineLineFrames(nsLineBox* aLine, bool foundVisibleTextOrAtomic = false; PRInt32 n = aLine->GetChildCount(); nsIFrame* child = aLine->mFirstChild; + InnerClipEdges clippedMarkerEdges; for (; n-- > 0; child = child->GetNextSibling()) { ExamineFrameSubtree(child, contentArea, insideMarkersArea, aFramesToHide, aAlignmentEdges, - &foundVisibleTextOrAtomic); + &foundVisibleTextOrAtomic, + &clippedMarkerEdges); } - if (guessLeft == mLeft.IsNeeded() && guessRight == mRight.IsNeeded()) { + if (!foundVisibleTextOrAtomic && retryEmptyLine) { + aAlignmentEdges->mAssigned = false; + aFramesToHide->Clear(); + pass = -1; + if (mLeft.IsNeeded() && mLeft.mActive && !clippedLeftMarker) { + if (clippedMarkerEdges.mAssignedLeft && + clippedMarkerEdges.mLeft - mContentArea.X() > 0) { + mLeft.mWidth = clippedMarkerEdges.mLeft - mContentArea.X(); + NS_ASSERTION(mLeft.mWidth < mLeft.mIntrinsicWidth, + "clipping a marker should make it strictly smaller"); + clippedLeftMarker = true; + } else { + mLeft.mActive = guessLeft = false; + } + continue; + } + if (mRight.IsNeeded() && mRight.mActive && !clippedRightMarker) { + if (clippedMarkerEdges.mAssignedRight && + mContentArea.XMost() - clippedMarkerEdges.mRight > 0) { + mRight.mWidth = mContentArea.XMost() - clippedMarkerEdges.mRight; + NS_ASSERTION(mRight.mWidth < mRight.mIntrinsicWidth, + "clipping a marker should make it strictly smaller"); + clippedRightMarker = true; + } else { + mRight.mActive = guessRight = false; + } + continue; + } + // The line simply has no visible content even without markers, + // so examine the line again without suppressing markers. + retryEmptyLine = false; + mLeft.mWidth = mLeft.mIntrinsicWidth; + mLeft.mActive = guessLeft = leftOverflow; + mRight.mWidth = mRight.mIntrinsicWidth; + mRight.mActive = guessRight = rightOverflow; + continue; + } + if (guessLeft == (mLeft.mActive && mLeft.IsNeeded()) && + guessRight == (mRight.mActive && mRight.IsNeeded())) { break; } else { guessLeft = mLeft.IsNeeded(); @@ -492,10 +539,10 @@ TextOverflow::ExamineLineFrames(nsLineBox* aLine, } NS_ASSERTION(pass == 0, "2nd pass should never guess wrong"); } while (++pass != 2); - if (!leftOverflow) { + if (!leftOverflow || !mLeft.mActive) { mLeft.Reset(); } - if (!rightOverflow) { + if (!rightOverflow || !mRight.mActive) { mRight.Reset(); } } @@ -647,9 +694,9 @@ TextOverflow::CreateMarkers(const nsLineBox* aLine, const nsRect& aInsideMarkersArea) const { if (aCreateLeft) { - nsRect markerRect = nsRect(aInsideMarkersArea.x - mLeft.mWidth, + nsRect markerRect = nsRect(aInsideMarkersArea.x - mLeft.mIntrinsicWidth, aLine->mBounds.y, - mLeft.mWidth, aLine->mBounds.height); + mLeft.mIntrinsicWidth, aLine->mBounds.height); markerRect += mBuilder->ToReferenceFrame(mBlock); nsDisplayItem* marker = new (mBuilder) nsDisplayTextOverflowMarker(mBuilder, mBlock, markerRect, @@ -665,7 +712,7 @@ TextOverflow::CreateMarkers(const nsLineBox* aLine, if (aCreateRight) { nsRect markerRect = nsRect(aInsideMarkersArea.XMost(), aLine->mBounds.y, - mRight.mWidth, aLine->mBounds.height); + mRight.mIntrinsicWidth, aLine->mBounds.height); markerRect += mBuilder->ToReferenceFrame(mBlock); nsDisplayItem* marker = new (mBuilder) nsDisplayTextOverflowMarker(mBuilder, mBlock, markerRect, @@ -696,6 +743,7 @@ TextOverflow::Marker::SetupString(nsIFrame* aFrame) GetEllipsis(fm) : mStyle->mString; mWidth = nsLayoutUtils::GetStringWidth(aFrame, rc, mMarkerString.get(), mMarkerString.Length()); + mIntrinsicWidth = mWidth; mInitialized = true; } diff --git a/layout/generic/TextOverflow.h b/layout/generic/TextOverflow.h index 20ce6cc0cd84..7d7a0b282a30 100644 --- a/layout/generic/TextOverflow.h +++ b/layout/generic/TextOverflow.h @@ -98,6 +98,30 @@ class TextOverflow { bool mAssigned; }; + struct InnerClipEdges { + InnerClipEdges() : mAssignedLeft(false), mAssignedRight(false) {} + void AccumulateLeft(const nsRect& aRect) { + if (NS_LIKELY(mAssignedLeft)) { + mLeft = NS_MAX(mLeft, aRect.X()); + } else { + mLeft = aRect.X(); + mAssignedLeft = true; + } + } + void AccumulateRight(const nsRect& aRect) { + if (NS_LIKELY(mAssignedRight)) { + mRight = NS_MIN(mRight, aRect.XMost()); + } else { + mRight = aRect.XMost(); + mAssignedRight = true; + } + } + nscoord mLeft; + nscoord mRight; + bool mAssignedLeft; + bool mAssignedRight; + }; + /** * Examines frames on the line to determine whether we should draw a left * and/or right marker, and if so, which frames should be completely hidden @@ -122,13 +146,16 @@ class TextOverflow { * inline-level frames that are inside the area between the markers * @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 + * inline-level frames that are clipped by the current marker width */ void ExamineFrameSubtree(nsIFrame* aFrame, const nsRect& aContentArea, const nsRect& aInsideMarkersArea, FrameHashtable* aFramesToHide, AlignmentEdges* aAlignmentEdges, - bool* aFoundVisibleTextOrAtomic); + bool* aFoundVisibleTextOrAtomic, + InnerClipEdges* aClippedMarkerEdges); /** * ExamineFrameSubtree calls this to analyze a frame against the hypothetical @@ -146,13 +173,16 @@ class TextOverflow { * inside aInsideMarkersArea * @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 + * inline-level frames that are clipped by the current marker width */ void AnalyzeMarkerEdges(nsIFrame* aFrame, const nsIAtom* aFrameType, const nsRect& aInsideMarkersArea, FrameHashtable* aFramesToHide, AlignmentEdges* aAlignmentEdges, - bool* aFoundVisibleTextOrAtomic); + bool* aFoundVisibleTextOrAtomic, + InnerClipEdges* aClippedMarkerEdges); /** * Clip or remove items given the final marker edges. ("clip" here just means @@ -205,8 +235,10 @@ class TextOverflow { mHasOverflow = false; } - // The intrinsic width of the marker string. + // The current width of the marker, the range is [0 .. mIntrinsicWidth]. nscoord mWidth; + // The intrinsic width of the marker string. + nscoord mIntrinsicWidth; // The marker text. nsString mMarkerString; // The style for this side. @@ -215,7 +247,8 @@ class TextOverflow { bool mHasOverflow; // True if mMarkerString and mWidth have been setup from style. bool mInitialized; - // True if the style is text-overflow:clip on this side. + // True if the style is text-overflow:clip on this side and the marker + // won't cause the line to become empty. bool mActive; }; diff --git a/layout/reftests/text-overflow/atomic-under-marker-ref.html b/layout/reftests/text-overflow/atomic-under-marker-ref.html new file mode 100644 index 000000000000..fd118943ff16 --- /dev/null +++ b/layout/reftests/text-overflow/atomic-under-marker-ref.html @@ -0,0 +1,85 @@ + + + +text-overflow: suppress or clip the marker when it hides all content + + + + +
+
!
+
!
+
!
+
!
+
!
+
!
+ +
!
+
!
+
!
+
.|
+
g
+
+ +
+ + + + diff --git a/layout/reftests/text-overflow/atomic-under-marker.html b/layout/reftests/text-overflow/atomic-under-marker.html new file mode 100644 index 000000000000..db37d05e0aac --- /dev/null +++ b/layout/reftests/text-overflow/atomic-under-marker.html @@ -0,0 +1,85 @@ + + + +text-overflow: suppress or clip the marker when it hides all content + + + + +
+
!||
+
!||
+
!
+
!||
+
!||
+
!
+ +
!||
+
!||
+
!
+
||
+
|
+
+ +
+ + + + diff --git a/layout/reftests/text-overflow/clipped-elements-ref.html b/layout/reftests/text-overflow/clipped-elements-ref.html index 3abd4988b95e..b337bab928f4 100644 --- a/layout/reftests/text-overflow/clipped-elements-ref.html +++ b/layout/reftests/text-overflow/clipped-elements-ref.html @@ -25,32 +25,32 @@ select[size="4"],iframe,textarea,hr { height:10px; margin:0; }
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
+
-
+
-
+
 …
@@ -58,12 +58,12 @@ select[size="4"],iframe,textarea,hr { height:10px; margin:0; }
-
+


-
-
+
+
1
diff --git a/layout/reftests/text-overflow/ellipsis-font-fallback-ref.html b/layout/reftests/text-overflow/ellipsis-font-fallback-ref.html index be43c36f09c7..e6a47e864023 100644 --- a/layout/reftests/text-overflow/ellipsis-font-fallback-ref.html +++ b/layout/reftests/text-overflow/ellipsis-font-fallback-ref.html @@ -132,16 +132,16 @@ m {
 X...
-
...
-
...
-
...
-
...
+
XXXXXXXXXXXX
+
XXXXXXXXXXXX
+
XXXXXXXXXXXX
+
XXXXXXXXXXXX
-
... 
-
 ...
-
 ...
-
... 
+
XXX
+
XXX
+
XXX
+
XXX
diff --git a/layout/reftests/text-overflow/marker-basic-ref.html b/layout/reftests/text-overflow/marker-basic-ref.html index 6f10b17a6323..61a847745d64 100644 --- a/layout/reftests/text-overflow/marker-basic-ref.html +++ b/layout/reftests/text-overflow/marker-basic-ref.html @@ -209,51 +209,17 @@ x1 m { position:absolute; right:0; font-size:16px; } -
-
-
 
-
-
-
-
-
 
-
-
-
-
-
   
-
-
-
-
-
   
-
-
+ +
+
+
+
-
-
-
 
-
 
-
-
-
-
-
 
-
 
-
-
-
-
-
 
-
 
-
-
-
-
-
 
-
 
-
-
+ +
+
+
+
diff --git a/layout/reftests/text-overflow/marker-string-ref.html b/layout/reftests/text-overflow/marker-string-ref.html index ee30ee777291..ba4b9f4c37b8 100644 --- a/layout/reftests/text-overflow/marker-string-ref.html +++ b/layout/reftests/text-overflow/marker-string-ref.html @@ -24,6 +24,9 @@ html,body { margin-left:2em; position:relative; } +span { + margin: 0 -0.5ch; +} m { margin: 0; position:relative; @@ -54,11 +57,11 @@ mr {
 x
 x
-
Hello World
-
Hello World
+
xx
+
xx
-
Hel
-
Hel
+
xx
+
xx
XX
XX
diff --git a/layout/reftests/text-overflow/quirks-decorations-ref.html b/layout/reftests/text-overflow/quirks-decorations-ref.html index a78658602d58..d2e297ded9a0 100644 --- a/layout/reftests/text-overflow/quirks-decorations-ref.html +++ b/layout/reftests/text-overflow/quirks-decorations-ref.html @@ -64,9 +64,9 @@ m { font-size:20px; color:blue; }
0123 56789012
1 56789012345
-
 
-
 
-
 
+
xxxxx
+
xx
+
xx
diff --git a/layout/reftests/text-overflow/reftest.list b/layout/reftests/text-overflow/reftest.list index bc2573f54f06..4b7e214c958d 100644 --- a/layout/reftests/text-overflow/reftest.list +++ b/layout/reftests/text-overflow/reftest.list @@ -16,7 +16,8 @@ HTTP(..) == selection.html selection-ref.html HTTP(..) == marker-shadow.html marker-shadow-ref.html == aligned-baseline.html aligned-baseline-ref.html skip-if(Android) == clipped-elements.html clipped-elements-ref.html -== theme-overflow.html theme-overflow-ref.html +HTTP(..) == theme-overflow.html theme-overflow-ref.html HTTP(..) == table-cell.html table-cell-ref.html HTTP(..) == two-value-syntax.html two-value-syntax-ref.html HTTP(..) == single-value.html single-value-ref.html +HTTP(..) == atomic-under-marker.html atomic-under-marker-ref.html diff --git a/layout/reftests/text-overflow/standards-decorations-ref.html b/layout/reftests/text-overflow/standards-decorations-ref.html index b88c3f08148a..14e5268b966d 100644 --- a/layout/reftests/text-overflow/standards-decorations-ref.html +++ b/layout/reftests/text-overflow/standards-decorations-ref.html @@ -63,9 +63,9 @@ m { font-size:20px; color:blue; }
0123 56789012
1 56789012345
-
… 
-
 
-
 
+
xxxx
+
x
+
x
diff --git a/layout/reftests/text-overflow/theme-overflow-ref.html b/layout/reftests/text-overflow/theme-overflow-ref.html index 1ff8607e3abc..be271aa263e4 100644 --- a/layout/reftests/text-overflow/theme-overflow-ref.html +++ b/layout/reftests/text-overflow/theme-overflow-ref.html @@ -17,7 +17,7 @@ .x1 { margin:1px;} .x2 { margin:2px;} .x3 { margin:3px;} -.x4 { margin-left:-1px; visibility:hidden;} +.x4 { margin-left:-1px; } .r .x4 { margin-right:-1px;} f { float:left; width:1px; height:1px; margin-left:-100px; } @@ -30,7 +30,7 @@ f { float:left; width:1px; height:1px; margin-left:-100px; } 1
2
3
- …
+

@@ -38,7 +38,7 @@ f { float:left; width:1px; height:1px; margin-left:-100px; } 1
2
3
- …
+

@@ -46,7 +46,7 @@ f { float:left; width:1px; height:1px; margin-left:-100px; } 1
2
3
- …
+

@@ -54,7 +54,7 @@ f { float:left; width:1px; height:1px; margin-left:-100px; } 1
2
3
- …
+