Bug 668919 - The ellipsis with text-overflow: ellipsis is sometimes one pixel too low. r=roc
authorMats Palmgren <matspal@gmail.com>
Mon, 04 Jul 2011 07:47:59 +0200
changeset 72795 cdff167e80748a50215a694a02b252373de19a16
parent 72794 dfdbd34cdad48cb999c461d4a908efcaaa522060
child 72796 1ec0339ac9a119f3ce84ead46a81687de8f584e2
push idunknown
push userunknown
push dateunknown
reviewersroc
bugs668919
milestone7.0a1
Bug 668919 - The ellipsis with text-overflow: ellipsis is sometimes one pixel too low. r=roc
layout/base/nsLayoutUtils.cpp
layout/base/nsLayoutUtils.h
layout/generic/TextOverflow.cpp
layout/generic/nsTextFrame.h
layout/generic/nsTextFrameThebes.cpp
layout/reftests/text-overflow/aligned-baseline-ref.html
layout/reftests/text-overflow/aligned-baseline.html
layout/reftests/text-overflow/reftest.list
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -2825,16 +2825,28 @@ nsLayoutUtils::GetTextColor(nsIFrame* aF
 {
   nscolor color = aFrame->GetVisitedDependentColor(eCSSProperty_color);
   if (ShouldDarkenColors(aFrame->PresContext())) {
     color = DarkenColor(color);
   }
   return color;
 }
 
+gfxFloat
+nsLayoutUtils::GetSnappedBaselineY(nsIFrame* aFrame, gfxContext* aContext,
+                                   nscoord aY, nscoord aAscent)
+{
+  gfxFloat appUnitsPerDevUnit = aFrame->PresContext()->AppUnitsPerDevPixel();
+  gfxFloat baseline = gfxFloat(aY) + aAscent;
+  gfxRect putativeRect(0, baseline/appUnitsPerDevUnit, 1, 1);
+  if (!aContext->UserToDevicePixelSnapped(putativeRect, PR_TRUE))
+    return baseline;
+  return aContext->DeviceToUser(putativeRect.TopLeft()).y * appUnitsPerDevUnit;
+}
+
 void
 nsLayoutUtils::DrawString(const nsIFrame*      aFrame,
                           nsRenderingContext* aContext,
                           const PRUnichar*     aString,
                           PRInt32              aLength,
                           nsPoint              aPoint,
                           PRUint8              aDirection)
 {
--- a/layout/base/nsLayoutUtils.h
+++ b/layout/base/nsLayoutUtils.h
@@ -929,16 +929,20 @@ public:
 
   // Implement nsIFrame::GetMinWidth in terms of nsIFrame::AddInlineMinWidth
   static nscoord MinWidthFromInline(nsIFrame* aFrame,
                                     nsRenderingContext* aRenderingContext);
 
   // Get a suitable foreground color for painting text for the frame.
   static nscolor GetTextColor(nsIFrame* aFrame);
 
+  // Get a baseline y position in app units that is snapped to device pixels.
+  static gfxFloat GetSnappedBaselineY(nsIFrame* aFrame, gfxContext* aContext,
+                                      nscoord aY, nscoord aAscent);
+
   static void DrawString(const nsIFrame*      aFrame,
                          nsRenderingContext* aContext,
                          const PRUnichar*     aString,
                          PRInt32              aLength,
                          nsPoint              aPoint,
                          PRUint8              aDirection = NS_STYLE_DIRECTION_INHERIT);
 
   static nscoord GetStringWidth(const nsIFrame*      aFrame,
--- a/layout/generic/TextOverflow.cpp
+++ b/layout/generic/TextOverflow.cpp
@@ -230,31 +230,29 @@ nsDisplayTextOverflowMarker::Paint(nsDis
                                    nsRenderingContext*   aCtx)
 {
   nscolor foregroundColor = nsLayoutUtils::GetTextColor(mFrame);
 
   // Paint the text-shadows for the overflow marker
   nsLayoutUtils::PaintTextShadow(mFrame, aCtx, mRect, mVisibleRect,
                                  foregroundColor, PaintTextShadowCallback,
                                  (void*)this);
-
   aCtx->SetColor(foregroundColor);
   PaintTextToContext(aCtx, nsPoint(0, 0));
 }
 
 void
 nsDisplayTextOverflowMarker::PaintTextToContext(nsRenderingContext* aCtx,
                                                 nsPoint aOffsetFromRect)
 {
   nsStyleContext* sc = mFrame->GetStyleContext();
   nsLayoutUtils::SetFontFromStyle(aCtx, sc);
-
-  nsPoint baselinePt = mRect.TopLeft();
-  baselinePt.y += mAscent;
-
+  gfxFloat y = nsLayoutUtils::GetSnappedBaselineY(mFrame, aCtx->ThebesContext(),
+                                                  mRect.y, mAscent);
+  nsPoint baselinePt(mRect.x, NSToCoordFloor(y));
   nsLayoutUtils::DrawString(mFrame, aCtx, mString.get(),
                             mString.Length(), baselinePt + aOffsetFromRect);
 }
 
 /* static */ TextOverflow*
 TextOverflow::WillProcessLines(nsDisplayListBuilder*   aBuilder,
                                const nsDisplayListSet& aLists,
                                nsIFrame*               aBlockFrame)
--- a/layout/generic/nsTextFrame.h
+++ b/layout/generic/nsTextFrame.h
@@ -266,18 +266,16 @@ public:
 
   nsOverflowAreas RecomputeOverflow();
 
   void AddInlineMinWidthForFlow(nsRenderingContext *aRenderingContext,
                                 nsIFrame::InlineMinWidthData *aData);
   void AddInlinePrefWidthForFlow(nsRenderingContext *aRenderingContext,
                                  InlinePrefWidthData *aData);
 
-  gfxFloat GetSnappedBaselineY(gfxContext* aContext, gfxFloat aY);
-
   /**
    * Calculate the horizontal bounds of the grapheme clusters that fit entirely
    * inside the given left/right edges (which are positive lengths from the
    * respective frame edge).  If an input value is zero it is ignored and the
    * result for that edge is zero.  All out parameter values are undefined when
    * the method returns false.
    * @return true if at least one whole grapheme cluster fit between the edges
    */
--- a/layout/generic/nsTextFrameThebes.cpp
+++ b/layout/generic/nsTextFrameThebes.cpp
@@ -5116,27 +5116,16 @@ static PRUint32
 ComputeTransformedLength(PropertyProvider& aProvider)
 {
   gfxSkipCharsIterator iter(aProvider.GetStart());
   PRUint32 start = iter.GetSkippedOffset();
   iter.AdvanceOriginal(aProvider.GetOriginalLength());
   return iter.GetSkippedOffset() - start;
 }
 
-gfxFloat
-nsTextFrame::GetSnappedBaselineY(gfxContext* aContext, gfxFloat aY)
-{
-  gfxFloat appUnitsPerDevUnit = mTextRun->GetAppUnitsPerDevUnit();
-  gfxFloat baseline = aY + mAscent;
-  gfxRect putativeRect(0, baseline/appUnitsPerDevUnit, 1, 1);
-  if (!aContext->UserToDevicePixelSnapped(putativeRect, PR_TRUE))
-    return baseline;
-  return aContext->DeviceToUser(putativeRect.TopLeft()).y*appUnitsPerDevUnit;
-}
-
 bool
 nsTextFrame::MeasureCharClippedText(gfxContext* aCtx,
                                     nscoord aLeftEdge, nscoord aRightEdge,
                                     nscoord* aSnappedLeftEdge,
                                     nscoord* aSnappedRightEdge)
 {
   // Don't pass in aRenderingContext here, because we need a *reference*
   // context and aRenderingContext might have some transform in it
@@ -5253,17 +5242,17 @@ nsTextFrame::PaintText(nsRenderingContex
   // Trim trailing whitespace
   provider.InitializeForDisplay(PR_TRUE);
 
   gfxContext* ctx = aRenderingContext->ThebesContext();
   const PRBool rtl = mTextRun->IsRightToLeft();
   const nscoord frameWidth = GetSize().width;
   gfxPoint framePt(aPt.x, aPt.y);
   gfxPoint textBaselinePt(rtl ? gfxFloat(aPt.x + frameWidth) : framePt.x,
-                          GetSnappedBaselineY(ctx, aPt.y));
+             nsLayoutUtils::GetSnappedBaselineY(this, ctx, aPt.y, mAscent));
   PRUint32 startOffset = provider.GetStart().GetSkippedOffset();
   PRUint32 maxLength = ComputeTransformedLength(provider);
   nscoord snappedLeftEdge, snappedRightEdge;
   if (!MeasureCharClippedText(ctx, provider, aItem.mLeftEdge, aItem.mRightEdge,
          &startOffset, &maxLength, &snappedLeftEdge, &snappedRightEdge)) {
     return;
   }
   textBaselinePt.x += rtl ? -snappedRightEdge : snappedLeftEdge;
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/aligned-baseline-ref.html
@@ -0,0 +1,100 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>Testcase for bug 668919</title>
+
+<style>
+.tab-title {
+  overflow:hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+  width: 5em;
+  height:25px;
+}
+
+.c1 { font-size: 14px; }
+.c2 { font-size: 15px; }
+.c3 { font-size: 16px; }
+.c4 { font-size: 17px; }
+.c5 { font-size: 18px; }
+.c6 { font-size: 19px; }
+.c7 { font-size: 20px; }
+.c8 { font-size: 24px; }
+.c9 { font-size: 28px; }
+.c10 { font-size: 32px; }
+.c11 { font-size: 36px; }
+
+.p0  { padding-top:0; }
+.p1  { padding-top:0px; }
+.p2  { padding-top:0px; }
+
+.col2 .tab-title { text-shadow: 1px 1px 1px blue; }
+</style>
+    </head>
+<body>
+
+<div style="position:absolute; top: 0px;">
+<div class="tab-title c1 p0">CSS is awesome</div>
+<div class="tab-title c1 p2">CSS is awesome</div>
+<div class="tab-title c1 p3">CSS is awesome</div>
+</div>
+
+<div style="position:absolute; top: 100px;">
+<div class="tab-title c2 p0">CSS is awesome</div>
+<div class="tab-title c2 p2">CSS is awesome</div>
+<div class="tab-title c2 p3">CSS is awesome</div>
+</div>
+
+<div style="position:absolute; top: 200px;">
+<div class="tab-title c3 p0">CSS is awesome</div>
+<div class="tab-title c3 p2">CSS is awesome</div>
+<div class="tab-title c3 p3">CSS is awesome</div>
+</div>
+
+<div style="position:absolute; top: 300px;">
+<div class="tab-title c4 p0">CSS is awesome</div>
+<div class="tab-title c4 p2">CSS is awesome</div>
+<div class="tab-title c4 p3">CSS is awesome</div>
+</div>
+
+<div style="position:absolute; top: 400px;">
+<div class="tab-title c5 p0">CSS is awesome</div>
+<div class="tab-title c5 p2">CSS is awesome</div>
+<div class="tab-title c5 p3">CSS is awesome</div>
+</div>
+
+<div class="col2" style="position:absolute; top: 0px; left:8em;">
+<div style="position:absolute; top: 0px;">
+<div class="tab-title c1 p0">CSS is awesome</div>
+<div class="tab-title c1 p2">CSS is awesome</div>
+<div class="tab-title c1 p3">CSS is awesome</div>
+</div>
+
+<div style="position:absolute; top: 100px;">
+<div class="tab-title c2 p0">CSS is awesome</div>
+<div class="tab-title c2 p2">CSS is awesome</div>
+<div class="tab-title c2 p3">CSS is awesome</div>
+</div>
+
+<div style="position:absolute; top: 200px;">
+<div class="tab-title c3 p0">CSS is awesome</div>
+<div class="tab-title c3 p2">CSS is awesome</div>
+<div class="tab-title c3 p3">CSS is awesome</div>
+</div>
+
+<div style="position:absolute; top: 300px;">
+<div class="tab-title c4 p0">CSS is awesome</div>
+<div class="tab-title c4 p2">CSS is awesome</div>
+<div class="tab-title c4 p3">CSS is awesome</div>
+</div>
+
+<div style="position:absolute; top: 400px;">
+<div class="tab-title c5 p0">CSS is awesome</div>
+<div class="tab-title c5 p2">CSS is awesome</div>
+<div class="tab-title c5 p3">CSS is awesome</div>
+</div>
+</div>
+
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/aligned-baseline.html
@@ -0,0 +1,100 @@
+<!DOCTYPE html>
+<html>
+    <head>
+        <title>Testcase for bug 668919</title>
+
+<style>
+.tab-title {
+  overflow:hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+  width: 5em;
+  height:25px;
+}
+
+.c1 { font-size: 14px; }
+.c2 { font-size: 15px; }
+.c3 { font-size: 16px; }
+.c4 { font-size: 17px; }
+.c5 { font-size: 18px; }
+.c6 { font-size: 19px; }
+.c7 { font-size: 20px; }
+.c8 { font-size: 24px; }
+.c9 { font-size: 28px; }
+.c10 { font-size: 32px; }
+.c11 { font-size: 36px; }
+
+.p0  { padding-top:0; }
+.p1  { padding-top:0.1px; }
+.p2  { padding-top:0.2px; }
+
+.col2 .tab-title { text-shadow: 1px 1px 1px blue; }
+</style>
+    </head>
+<body>
+
+<div style="position:absolute; top: 0px;">
+<div class="tab-title c1 p0">CSS is awesome</div>
+<div class="tab-title c1 p2">CSS is awesome</div>
+<div class="tab-title c1 p3">CSS is awesome</div>
+</div>
+
+<div style="position:absolute; top: 100px;">
+<div class="tab-title c2 p0">CSS is awesome</div>
+<div class="tab-title c2 p2">CSS is awesome</div>
+<div class="tab-title c2 p3">CSS is awesome</div>
+</div>
+
+<div style="position:absolute; top: 200px;">
+<div class="tab-title c3 p0">CSS is awesome</div>
+<div class="tab-title c3 p2">CSS is awesome</div>
+<div class="tab-title c3 p3">CSS is awesome</div>
+</div>
+
+<div style="position:absolute; top: 300px;">
+<div class="tab-title c4 p0">CSS is awesome</div>
+<div class="tab-title c4 p2">CSS is awesome</div>
+<div class="tab-title c4 p3">CSS is awesome</div>
+</div>
+
+<div style="position:absolute; top: 400px;">
+<div class="tab-title c5 p0">CSS is awesome</div>
+<div class="tab-title c5 p2">CSS is awesome</div>
+<div class="tab-title c5 p3">CSS is awesome</div>
+</div>
+
+<div class="col2" style="position:absolute; top: 0px; left:8em;">
+<div style="position:absolute; top: 0px;">
+<div class="tab-title c1 p0">CSS is awesome</div>
+<div class="tab-title c1 p2">CSS is awesome</div>
+<div class="tab-title c1 p3">CSS is awesome</div>
+</div>
+
+<div style="position:absolute; top: 100px;">
+<div class="tab-title c2 p0">CSS is awesome</div>
+<div class="tab-title c2 p2">CSS is awesome</div>
+<div class="tab-title c2 p3">CSS is awesome</div>
+</div>
+
+<div style="position:absolute; top: 200px;">
+<div class="tab-title c3 p0">CSS is awesome</div>
+<div class="tab-title c3 p2">CSS is awesome</div>
+<div class="tab-title c3 p3">CSS is awesome</div>
+</div>
+
+<div style="position:absolute; top: 300px;">
+<div class="tab-title c4 p0">CSS is awesome</div>
+<div class="tab-title c4 p2">CSS is awesome</div>
+<div class="tab-title c4 p3">CSS is awesome</div>
+</div>
+
+<div style="position:absolute; top: 400px;">
+<div class="tab-title c5 p0">CSS is awesome</div>
+<div class="tab-title c5 p2">CSS is awesome</div>
+<div class="tab-title c5 p3">CSS is awesome</div>
+</div>
+</div>
+
+
+</body>
+</html>
--- a/layout/reftests/text-overflow/reftest.list
+++ b/layout/reftests/text-overflow/reftest.list
@@ -9,9 +9,10 @@ HTTP(..) == false-marker-overlap.html fa
 HTTP(..) == visibility-hidden.html visibility-hidden-ref.html
 HTTP(..) == block-padding.html block-padding-ref.html
 HTTP(..) == quirks-decorations.html quirks-decorations-ref.html
 HTTP(..) == quirks-line-height.html quirks-line-height-ref.html
 HTTP(..) == standards-decorations.html standards-decorations-ref.html
 HTTP(..) == standards-line-height.html standards-line-height-ref.html
 HTTP(..) == selection.html selection-ref.html
 HTTP(..) == marker-shadow.html marker-shadow-ref.html
+== aligned-baseline.html aligned-baseline-ref.html
 == clipped-elements.html clipped-elements-ref.html