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 72280 cdff167e80748a50215a694a02b252373de19a16
parent 72279 dfdbd34cdad48cb999c461d4a908efcaaa522060
child 72281 1ec0339ac9a119f3ce84ead46a81687de8f584e2
push id20688
push usermak77@bonardo.net
push dateMon, 04 Jul 2011 18:26:59 +0000
treeherdermozilla-central@ca5dd1bd60f3 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersroc
bugs668919
milestone7.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
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