Bug 684266 - Do ellipsing on the end-edge only when a single value was specified for text-overflow. r=bzbarsky r=roc
authorMats Palmgren <matspal@gmail.com>
Wed, 12 Oct 2011 18:20:46 +0200
changeset 78629 b4b895684f7e35b1b2473fe38dbeab13651b1606
parent 78628 3d5eee785f85fee1045d290dc3b1c3a8b21031a7
child 78630 d45de3d261516152349ad2c590435499279dde50
push id21321
push usermak77@bonardo.net
push dateThu, 13 Oct 2011 13:50:30 +0000
treeherdermozilla-central@d6d3a1f90e2e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbzbarsky, roc
bugs684266
milestone10.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 684266 - Do ellipsing on the end-edge only when a single value was specified for text-overflow. r=bzbarsky r=roc
layout/generic/TextOverflow.cpp
layout/reftests/text-overflow/bidi-simple-scrolled.html
layout/reftests/text-overflow/ellipsis-font-fallback.html
layout/reftests/text-overflow/false-marker-overlap.html
layout/reftests/text-overflow/marker-basic-ref.html
layout/reftests/text-overflow/marker-basic.html
layout/reftests/text-overflow/marker-string.html
layout/reftests/text-overflow/reftest.list
layout/reftests/text-overflow/selection.html
layout/reftests/text-overflow/single-value-ref.html
layout/reftests/text-overflow/single-value.html
layout/reftests/text-overflow/theme-overflow.html
layout/style/nsCSSParser.cpp
layout/style/nsComputedDOMStyle.cpp
layout/style/nsRuleNode.cpp
layout/style/nsStyleStruct.h
layout/style/test/property_database.js
--- a/layout/generic/TextOverflow.cpp
+++ b/layout/generic/TextOverflow.cpp
@@ -272,21 +272,21 @@ TextOverflow::WillProcessLines(nsDisplay
   nsIScrollableFrame* scroll =
     nsLayoutUtils::GetScrollableFrameFor(aBlockFrame);
   textOverflow->mCanHaveHorizontalScrollbar = false;
   if (scroll) {
     textOverflow->mCanHaveHorizontalScrollbar =
       scroll->GetScrollbarStyles().mHorizontal != NS_STYLE_OVERFLOW_HIDDEN;
     textOverflow->mContentArea.MoveBy(scroll->GetScrollPosition());
   }
-  textOverflow->mBlockIsRTL =
-    aBlockFrame->GetStyleVisibility()->mDirection == NS_STYLE_DIRECTION_RTL;
+  PRUint8 direction = aBlockFrame->GetStyleVisibility()->mDirection;
+  textOverflow->mBlockIsRTL = direction == NS_STYLE_DIRECTION_RTL;
   const nsStyleTextReset* style = aBlockFrame->GetStyleTextReset();
-  textOverflow->mLeft.Init(style->mTextOverflow.mLeft);
-  textOverflow->mRight.Init(style->mTextOverflow.mRight);
+  textOverflow->mLeft.Init(*style->mTextOverflow.GetLeft(direction));
+  textOverflow->mRight.Init(*style->mTextOverflow.GetRight(direction));
   // The left/right marker string is setup in ExamineLineFrames when a line
   // has overflow on that side.
 
   return textOverflow.forget();
 }
 
 void
 TextOverflow::DidProcessLines()
@@ -397,41 +397,41 @@ TextOverflow::AnalyzeMarkerEdges(nsIFram
   }
 }
 
 void
 TextOverflow::ExamineLineFrames(nsLineBox*      aLine,
                                 FrameHashtable* aFramesToHide,
                                 AlignmentEdges* aAlignmentEdges)
 {
+  // No ellipsing for 'clip' style.
+  bool suppressLeft = mLeft.mStyle->mType == NS_STYLE_TEXT_OVERFLOW_CLIP;
+  bool suppressRight = mRight.mStyle->mType == NS_STYLE_TEXT_OVERFLOW_CLIP;
+
   // Scrolling to the end position can leave some text still overflowing due to
   // pixel snapping behaviour in our scrolling code so we move the edges 1px
   // outward to avoid triggering a text-overflow marker for such overflow.
   nsRect contentArea = mContentArea;
   const nscoord scrollAdjust = mCanHaveHorizontalScrollbar ?
     mBlock->PresContext()->AppUnitsPerDevPixel() : 0;
-  InflateLeft(&contentArea,
-              mLeft.mStyle->mType == NS_STYLE_TEXT_OVERFLOW_CLIP,
-              scrollAdjust);
-  InflateRight(&contentArea,
-               mRight.mStyle->mType == NS_STYLE_TEXT_OVERFLOW_CLIP,
-               scrollAdjust);
+  InflateLeft(&contentArea, suppressLeft, scrollAdjust);
+  InflateRight(&contentArea, suppressRight, scrollAdjust);
   nsRect lineRect = aLine->GetScrollableOverflowArea();
-  const bool leftOverflow = lineRect.x < contentArea.x;
-  const bool rightOverflow = lineRect.XMost() > contentArea.XMost();
+  const bool leftOverflow =
+    !suppressLeft && lineRect.x < contentArea.x;
+  const bool rightOverflow =
+    !suppressRight && lineRect.XMost() > contentArea.XMost();
   if (!leftOverflow && !rightOverflow) {
-    // The line does not overflow - no need to traverse the frame tree.
+    // The line does not overflow on a side we should ellipsize.
     return;
   }
 
   PRUint32 pass = 0;
-  bool guessLeft =
-    mLeft.mStyle->mType != NS_STYLE_TEXT_OVERFLOW_CLIP && leftOverflow;
-  bool guessRight =
-    mRight.mStyle->mType != NS_STYLE_TEXT_OVERFLOW_CLIP && rightOverflow;
+  bool guessLeft = leftOverflow;
+  bool guessRight = rightOverflow;
   do {
     // Setup marker strings as needed.
     if (guessLeft) {
       mLeft.SetupString(mBlock);
     }
     if (guessRight) {
       mRight.SetupString(mBlock);
     }
--- a/layout/reftests/text-overflow/bidi-simple-scrolled.html
+++ b/layout/reftests/text-overflow/bidi-simple-scrolled.html
@@ -12,17 +12,17 @@
   font-family: DejaVuSansMono;
   src: url(../fonts/DejaVuSansMono.woff);
 }
 html,body {
     color:black; background-color:white; font-size:16px; padding:0; margin:0; font-family:DejaVuSansMono;
 }
 .test {
   overflow:auto;
-  text-overflow:ellipsis;
+  text-overflow:ellipsis ellipsis;
   white-space:nowrap;
   width: 4.4em;
   margin-bottom:1em;
   position:relative;
   line-height:2em;
 }
 
 .hidden {
--- a/layout/reftests/text-overflow/ellipsis-font-fallback.html
+++ b/layout/reftests/text-overflow/ellipsis-font-fallback.html
@@ -26,17 +26,17 @@ html,body {
 .rlo {
   unicode-bidi: bidi-override; direction: rtl;
 }
 .lro {
   unicode-bidi: bidi-override; direction: ltr;
 }
 
 .o {
-  text-overflow: ellipsis;
+  text-overflow: ellipsis ellipsis;
   color:blue;
 }
 .o span {
   color:black;
 }
 
 .s {
   width:10em;
--- a/layout/reftests/text-overflow/false-marker-overlap.html
+++ b/layout/reftests/text-overflow/false-marker-overlap.html
@@ -14,17 +14,17 @@
 }
 html,body {
     color:black; background-color:white; font-size:16px; padding:0; margin:0; font-family:DejaVuSansMono;
 }
 
 .test { 
   overflow: hidden; 
   white-space: nowrap;
-  text-overflow: ellipsis;
+  text-overflow: ellipsis ellipsis;
   color: black;
   height: 6em;
   width: 32.5em;
   margin-bottom: 1em;
 }
 
 i {
   display:inline-block;
--- a/layout/reftests/text-overflow/marker-basic-ref.html
+++ b/layout/reftests/text-overflow/marker-basic-ref.html
@@ -129,16 +129,18 @@ x1 m { position:absolute; right:0; font-
 #test8a  { top:280px; left:0;     position:absolute; }
 #test8b  { top:280px; left:100px; position:absolute; }
 #test8c  { top:280px; left:200px; position:absolute; }
 #test8d  { top:280px; left:300px; position:absolute; }
 #test9a  { top:320px; left:0;     position:absolute; border:1px solid black; }
 #test9b  { top:320px; left:100px; position:absolute; border:1px solid black; }
 #test9c  { top:320px; left:200px; position:absolute; border:1px solid black; }
 #test9d  { top:320px; left:300px; position:absolute; border:1px solid black; }
+#test10a { top:360px; left:0;     position:absolute; }
+#test10b { top:360px; left:100px; position:absolute; }
 
     </style>
 </head>
 <body>
 <div style="position: absolute; top:20px; left:50px;">
 
 <div id="test1a">
 <div class="s a"><div class="p rel">
@@ -294,12 +296,15 @@ x1 m { position:absolute; right:0; font-
 <div id="test8a"><div class="s a"><div class="a p ltr"><span class="c5 a"></span><span class="e"></span><span style="margin-right:-0.5em">&#x2026;</span><span>&#x200c;</span></div></div></div>
 <div id="test8d"><div class="s a"><div class="a p rtl"><span class="c5 a"></span><span class="e"></span><span style="margin-right:-0.5em">&#x2026;</span><span>&#x200c;</span></div></div></div>
 
 <div id="test9a"><div class="s a"><div class="p ltr"><span class="e"></span><i>&nbsp;&nbsp;&nbsp;&nbsp;</i><m>&#x2026;</m><span class="e a"></span></div></div></div>
 <div id="test9b"><div class="s a"><div class="p rtl"><span class="e"></span><i>&nbsp;&nbsp;&nbsp;&nbsp;</i><m>&#x2026;</m><span class="e a"></span></div></div></div>
 <div id="test9c"><div class="s a"><div class="p ltr"><span class="e"></span><i>&nbsp;&nbsp;&nbsp;&nbsp;</i><m>&#x2026;</m><span class="e a"></span></div></div></div>
 <div id="test9d"><div class="s a"><div class="p rtl"><span class="e"></span><i>&nbsp;&nbsp;&nbsp;&nbsp;</i><m>&#x2026;</m><span class="e a"></span></div></div></div>
 
+<!-- no marker for overflow:auto that doesn't trigger scrollbar -->
+<div id="test10a"><div class="s a"><div class="p o ltr"><span style="margin-left:-5px" >||||||</span></div></div></div>
+<div id="test10b"><div class="s a"><div class="p o rtl"><span style="margin-right:-5px">||||||</span></div></div></div>
 
 </div>
 </body>
 </html>
--- a/layout/reftests/text-overflow/marker-basic.html
+++ b/layout/reftests/text-overflow/marker-basic.html
@@ -25,17 +25,17 @@ html,body {
 .rlo {
   unicode-bidi: bidi-override; direction: rtl;
 }
 .lro {
   unicode-bidi: bidi-override; direction: ltr;
 }
 
 .o {
-  text-overflow: ellipsis;
+  text-overflow: ellipsis ellipsis;
 }
 
 .rel {
   position: relative;
   height:2em;
 }
 .abs0 {
   position: absolute;
@@ -45,16 +45,19 @@ html,body {
 .s {
   width:4em;
 }
 .p {
   overflow: hidden;
   white-space:nowrap;
   font-size:16px;
 }
+.auto {
+  overflow: auto;
+}
 .r {
   text-align:right;
 }
 .a {
   font-size:20px;
 }
 .l {
   text-align:left;
@@ -126,16 +129,18 @@ i {
 #test8a  { top:280px; left:0;     position:absolute; }
 #test8b  { top:280px; left:100px; position:absolute; }
 #test8c  { top:280px; left:200px; position:absolute; }
 #test8d  { top:280px; left:300px; position:absolute; }
 #test9a  { top:320px; left:0;     position:absolute; border:1px solid black; }
 #test9b  { top:320px; left:100px; position:absolute; border:1px solid black; }
 #test9c  { top:320px; left:200px; position:absolute; border:1px solid black; }
 #test9d  { top:320px; left:300px; position:absolute; border:1px solid black; }
+#test10a { top:360px; left:0;     position:absolute; }
+#test10b { top:360px; left:100px; position:absolute; }
 
 
     </style>
 </head>
 <body>
 <div style="position: absolute; top:20px; left:50px;">
 
 <!-- start + end marker, aligned to text -->
@@ -186,12 +191,15 @@ i {
 <div id="test8d"><div class="s a"><div class="a p o rtl"><span class="c5 a">|</span><span class="e"></span><span>&#x200c;</span></div></div></div>
 
 <!-- end marker, marker aligns to inline block with overflow -->
 <div id="test9a"><div class="s a"><div class="p o ltr"><span class="e"></span><i>&nbsp;&nbsp;&nbsp;&nbsp;</i><span class="e"></span><span class="c5 a">|||</span></div></div></div>
 <div id="test9b"><div class="s a"><div class="p o rtl"><span class="e"></span><i>&nbsp;&nbsp;&nbsp;&nbsp;</i><span class="e"></span><span class="c5 a">|||</span></div></div></div>
 <div id="test9c"><div class="s a"><div class="p o ltr"><span class="e"></span><i>&nbsp;&nbsp;&nbsp;&nbsp;</i><span class="e"></span><span class="c5 a">|||</span></div></div></div>
 <div id="test9d"><div class="s a"><div class="p o rtl"><span class="e"></span><i>&nbsp;&nbsp;&nbsp;&nbsp;</i><span class="e"></span><span class="c5 a">|||</span></div></div></div>
 
+<!-- no marker for overflow:auto that doesn't trigger scrollbar -->
+<div id="test10a"><div class="s a"><div class="p o ltr auto"><span style="margin-left:-5px" >||||||</span></div></div></div>
+<div id="test10b"><div class="s a"><div class="p o rtl auto"><span style="margin-right:-5px">||||||</span></div></div></div>
+
 </div>
-
 </body>
 </html>
--- a/layout/reftests/text-overflow/marker-string.html
+++ b/layout/reftests/text-overflow/marker-string.html
@@ -39,19 +39,19 @@ s {
 }
 .rtl {
   direction:rtl;
 }
 .ltr {
   direction:ltr;
 }
 
-.t1 { text-overflow:""; }
-.t2 { text-overflow:"Hello World"; }
-.t3 { text-overflow:"X"; }
+.t1 { text-overflow:"" ""; }
+.t2 { text-overflow:"Hello World" "Hello World"; }
+.t3 { text-overflow:"X" "X"; }
 
 </style>
 
 </head><body>
 
 
 <!-- Empty marker clips text -->
 <div class="test t1"><span>xx</span></div>
--- a/layout/reftests/text-overflow/reftest.list
+++ b/layout/reftests/text-overflow/reftest.list
@@ -14,8 +14,9 @@ HTTP(..) == standards-decorations.html s
 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
 skip-if(Android) == clipped-elements.html clipped-elements-ref.html
 == 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 
--- a/layout/reftests/text-overflow/selection.html
+++ b/layout/reftests/text-overflow/selection.html
@@ -18,17 +18,17 @@
   src: url(TestEllipsisFallback.woff);
 }
 html,body {
     color:black; background-color:white; font-size:16px; padding:0; margin:0; font-family:DejaVuSansMono;
 }
 
 .test {
   overflow:auto;
-  text-overflow:ellipsis;
+  text-overflow:ellipsis ellipsis;
   white-space:nowrap;
   width: 5em;
   position:relative;
   margin-top:1em;
   padding-left: 0.9em;
   padding-right: 1.3em;
 }
 
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/single-value-ref.html
@@ -0,0 +1,105 @@
+<!DOCTYPE HTML>
+<!--
+    Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/licenses/publicdomain/
+
+    Test: text-overflow: <single value>, scrolled and non-scrolled tests, (bug 684266)
+-->
+<html class="reftest-wait"><head>
+<title>text-overflow: &lt;single value&gt;, scrolled and non-scrolled tests, (bug 684266)</title>
+<style type="text/css">
+@font-face {
+  font-family: DejaVuSansMono;
+  src: url(../fonts/DejaVuSansMono.woff),url(DejaVuSansMono.woff);
+}
+html,body {
+    color:black; background-color:white; font-size:16px; padding:0; margin:0; font-family:DejaVuSansMono;
+}
+
+body {padding:10px 40px;}
+
+div {
+  width:100px;
+  white-space:nowrap;
+}
+.hidden {overflow:hidden}
+.auto {overflow:auto}
+.autolong {overflow:auto; width:100%;}
+.scroll {overflow:scroll}
+
+.ltr { direction:ltr; unicode-bidi: bidi-override; }
+.rtl { direction:rtl; unicode-bidi: bidi-override; }
+
+.ltr.p { text-indent: -5px; padding-left: 40px; } /* overflow into padding, but not outside the padding edge */
+.rtl.p { text-indent: -5px; padding-right: 40px; } /* overflow into padding, but not outside the padding edge */
+
+.s { text-indent: -5px; } /* overflow start edge outside the padding edge */
+
+div.ltr {
+  text-overflow: clip ellipsis;
+}
+div.rtl {
+  text-overflow: ellipsis clip;
+}
+
+</style>
+
+<script>
+function scrolldivs() {
+ var divs = document.getElementsByTagName('div');
+  for (i = 0; i < divs.length; ++i) {
+    var elm = divs[i];
+    if (elm.hasAttribute('scroll')) {
+      if (window.getComputedStyle(elm).direction == 'ltr')
+        elm.scrollLeft = 8;
+      else
+        elm.scrollLeft = -8;
+    }
+  }
+  document.documentElement.removeAttribute('class');
+}
+</script>
+</head>
+<body onload="scrolldivs()">
+
+    <div class="ltr start p hidden">A long line that does not break (overflow:hidden)</div>
+    <div class="ltr start p auto">A long line that does not break (overflow:auto)</div>
+    <div class="ltr start p autolong">A long line that does not break (overflow:auto)</div>
+    <div class="ltr start p scroll">A long line that does not break (overflow:scroll)</div>
+    <div class="ltr start s hidden">A long line that does not break (overflow:hidden)</div>
+    <div class="ltr start s auto">A long line that does not break (overflow:auto)</div>
+    <div class="ltr start s autolong">A long line that does not break (overflow:auto)</div>
+    <div class="ltr start s scroll">A long line that does not break (overflow:scroll)</div>
+
+    <div scroll class="ltr start p hidden">A long line that does not break (overflow:hidden)</div>
+    <div scroll class="ltr start p auto">A long line that does not break (overflow:auto)</div>
+    <div scroll class="ltr start p autolong">A long line that does not break (overflow:auto)</div>
+    <div scroll class="ltr start p scroll">A long line that does not break (overflow:scroll)</div>
+    <div scroll class="ltr start s hidden">A long line that does not break (overflow:hidden)</div>
+    <div scroll class="ltr start s auto">A long line that does not break (overflow:auto)</div>
+    <div scroll class="ltr start s autolong">A long line that does not break (overflow:auto)</div>
+    <div scroll class="ltr start s scroll">A long line that does not break (overflow:scroll)</div>
+
+<div class="rtl" style="float:right">
+    <div class="rtl start p hidden">A long line that does not break (overflow:hidden)</div>
+    <div class="rtl start p auto">A long line that does not break (overflow:auto)</div>
+    <div class="rtl start p autolong">A long line that does not break (overflow:auto)</div>
+    <div class="rtl start p scroll">A long line that does not break (overflow:scroll)</div>
+    <div class="rtl start s hidden">A long line that does not break (overflow:hidden)</div>
+    <div class="rtl start s auto">A long line that does not break (overflow:auto)</div>
+    <div class="rtl start s autolong">A long line that does not break (overflow:auto)</div>
+    <div class="rtl start s scroll">A long line that does not break (overflow:scroll)</div>
+
+    <div scroll class="rtl start p hidden">A long line that does not break (overflow:hidden)</div>
+    <div scroll class="rtl start p auto">A long line that does not break (overflow:auto)</div>
+    <div scroll class="rtl start p autolong">A long line that does not break (overflow:auto)</div>
+    <div scroll class="rtl start p scroll">A long line that does not break (overflow:scroll)</div>
+    <div scroll class="rtl start s hidden">A long line that does not break (overflow:hidden)</div>
+    <div scroll class="rtl start s auto">A long line that does not break (overflow:auto)</div>
+    <div scroll class="rtl start s autolong">A long line that does not break (overflow:auto)</div>
+    <div scroll class="rtl start s scroll">A long line that does not break (overflow:scroll)</div>
+</div>
+
+
+</body>
+</hml>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/single-value.html
@@ -0,0 +1,98 @@
+<!DOCTYPE HTML>
+<!--
+    Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/licenses/publicdomain/
+
+    Test: text-overflow: <single value>, scrolled and non-scrolled tests, (bug 684266)
+-->
+<html class="reftest-wait"><head>
+<title>text-overflow: &lt;single value&gt;, scrolled and non-scrolled tests, (bug 684266)</title>
+<style type="text/css">
+@font-face {
+  font-family: DejaVuSansMono;
+  src: url(../fonts/DejaVuSansMono.woff),url(DejaVuSansMono.woff);
+}
+html,body {
+    color:black; background-color:white; font-size:16px; padding:0; margin:0; font-family:DejaVuSansMono;
+}
+
+body {padding:10px 40px;}
+
+div {
+  text-overflow: ellipsis;
+  width:100px;
+  white-space:nowrap;
+}
+.hidden {overflow:hidden}
+.auto {overflow:auto}
+.autolong {overflow:auto; width:100%;}
+.scroll {overflow:scroll}
+
+.ltr { direction:ltr; unicode-bidi: bidi-override; }
+.rtl { direction:rtl; unicode-bidi: bidi-override; }
+
+.ltr.p { text-indent: -5px; padding-left: 40px; } /* overflow into padding, but not outside the padding edge */
+.rtl.p { text-indent: -5px; padding-right: 40px; } /* overflow into padding, but not outside the padding edge */
+
+.s { text-indent: -5px; } /* overflow start edge outside the padding edge */
+</style>
+
+<script>
+function scrolldivs() {
+ var divs = document.getElementsByTagName('div');
+  for (i = 0; i < divs.length; ++i) {
+    var elm = divs[i];
+    if (elm.hasAttribute('scroll')) {
+      if (window.getComputedStyle(elm).direction == 'ltr')
+        elm.scrollLeft = 8;
+      else
+        elm.scrollLeft = -8;
+    }
+  }
+  document.documentElement.removeAttribute('class');
+}
+</script>
+</head>
+<body onload="scrolldivs()">
+
+    <div class="ltr start p hidden">A long line that does not break (overflow:hidden)</div>
+    <div class="ltr start p auto">A long line that does not break (overflow:auto)</div>
+    <div class="ltr start p autolong">A long line that does not break (overflow:auto)</div>
+    <div class="ltr start p scroll">A long line that does not break (overflow:scroll)</div>
+    <div class="ltr start s hidden">A long line that does not break (overflow:hidden)</div>
+    <div class="ltr start s auto">A long line that does not break (overflow:auto)</div>
+    <div class="ltr start s autolong">A long line that does not break (overflow:auto)</div>
+    <div class="ltr start s scroll">A long line that does not break (overflow:scroll)</div>
+
+    <div scroll class="ltr start p hidden">A long line that does not break (overflow:hidden)</div>
+    <div scroll class="ltr start p auto">A long line that does not break (overflow:auto)</div>
+    <div scroll class="ltr start p autolong">A long line that does not break (overflow:auto)</div>
+    <div scroll class="ltr start p scroll">A long line that does not break (overflow:scroll)</div>
+    <div scroll class="ltr start s hidden">A long line that does not break (overflow:hidden)</div>
+    <div scroll class="ltr start s auto">A long line that does not break (overflow:auto)</div>
+    <div scroll class="ltr start s autolong">A long line that does not break (overflow:auto)</div>
+    <div scroll class="ltr start s scroll">A long line that does not break (overflow:scroll)</div>
+
+<div class="rtl" style="float:right">
+    <div class="rtl start p hidden">A long line that does not break (overflow:hidden)</div>
+    <div class="rtl start p auto">A long line that does not break (overflow:auto)</div>
+    <div class="rtl start p autolong">A long line that does not break (overflow:auto)</div>
+    <div class="rtl start p scroll">A long line that does not break (overflow:scroll)</div>
+    <div class="rtl start s hidden">A long line that does not break (overflow:hidden)</div>
+    <div class="rtl start s auto">A long line that does not break (overflow:auto)</div>
+    <div class="rtl start s autolong">A long line that does not break (overflow:auto)</div>
+    <div class="rtl start s scroll">A long line that does not break (overflow:scroll)</div>
+
+    <div scroll class="rtl start p hidden">A long line that does not break (overflow:hidden)</div>
+    <div scroll class="rtl start p auto">A long line that does not break (overflow:auto)</div>
+    <div scroll class="rtl start p autolong">A long line that does not break (overflow:auto)</div>
+    <div scroll class="rtl start p scroll">A long line that does not break (overflow:scroll)</div>
+    <div scroll class="rtl start s hidden">A long line that does not break (overflow:hidden)</div>
+    <div scroll class="rtl start s auto">A long line that does not break (overflow:auto)</div>
+    <div scroll class="rtl start s autolong">A long line that does not break (overflow:auto)</div>
+    <div scroll class="rtl start s scroll">A long line that does not break (overflow:scroll)</div>
+</div>
+
+
+</body>
+</hml>
--- a/layout/reftests/text-overflow/theme-overflow.html
+++ b/layout/reftests/text-overflow/theme-overflow.html
@@ -2,17 +2,17 @@
 <html>
 <head>
   <meta http-equiv="content-type" content="text/html; charset=UTF-8">
   <title>Testcase for bug 669284</title>
   
   <style type="text/css">
     p {
       overflow: hidden;
-      text-overflow: ellipsis;
+      text-overflow: ellipsis ellipsis;
       width: 200px;
     }
     .r {
       direction:rtl;
     }
 
 .x0 { margin:0px;}
 .x1 { margin:1px;}
--- a/layout/style/nsCSSParser.cpp
+++ b/layout/style/nsCSSParser.cpp
@@ -8181,18 +8181,19 @@ CSSParserImpl::ParseTextOverflow(nsCSSVa
   if (!ParseVariant(left, VARIANT_KEYWORD | VARIANT_STRING,
                     nsCSSProps::kTextOverflowKTable))
     return PR_FALSE;
 
   nsCSSValue right;
   if (ParseVariant(right, VARIANT_KEYWORD | VARIANT_STRING,
                     nsCSSProps::kTextOverflowKTable))
     aValue.SetPairValue(left, right);
-  else
-    aValue.SetPairValue(left, left);
+  else {
+    aValue = left;
+  }
   return PR_TRUE;
 }
 
 bool
 CSSParserImpl::ParseTransitionProperty()
 {
   nsCSSValue value;
   if (ParseVariant(value, VARIANT_INHERIT | VARIANT_NONE | VARIANT_ALL,
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -2481,43 +2481,45 @@ nsComputedDOMStyle::DoGetTextIndent()
                   &nsComputedDOMStyle::GetCBContentWidth);
   return val;
 }
 
 nsIDOMCSSValue*
 nsComputedDOMStyle::DoGetTextOverflow()
 {
   const nsStyleTextReset *style = GetStyleTextReset();
-  nsROCSSPrimitiveValue *left = GetROCSSPrimitiveValue();
-  if (style->mTextOverflow.mLeft.mType == NS_STYLE_TEXT_OVERFLOW_STRING) {
+  nsROCSSPrimitiveValue *first = GetROCSSPrimitiveValue();
+  const nsStyleTextOverflowSide *side = style->mTextOverflow.GetFirstValue();
+  if (side->mType == NS_STYLE_TEXT_OVERFLOW_STRING) {
     nsString str;
-    nsStyleUtil::AppendEscapedCSSString(style->mTextOverflow.mLeft.mString, str);
-    left->SetString(str);
+    nsStyleUtil::AppendEscapedCSSString(side->mString, str);
+    first->SetString(str);
   } else {
-    left->SetIdent(
-      nsCSSProps::ValueToKeywordEnum(style->mTextOverflow.mLeft.mType,
+    first->SetIdent(
+      nsCSSProps::ValueToKeywordEnum(side->mType,
                                      nsCSSProps::kTextOverflowKTable));
   }
-  if (style->mTextOverflow.mLeft == style->mTextOverflow.mRight) {
-    return left;
+  side = style->mTextOverflow.GetSecondValue();
+  if (!side) {
+    return first;
   }
-  nsROCSSPrimitiveValue *right = GetROCSSPrimitiveValue();
-  if (style->mTextOverflow.mRight.mType == NS_STYLE_TEXT_OVERFLOW_STRING) {
+  nsROCSSPrimitiveValue *second = GetROCSSPrimitiveValue();
+  if (side->mType == NS_STYLE_TEXT_OVERFLOW_STRING) {
     nsString str;
-    nsStyleUtil::AppendEscapedCSSString(style->mTextOverflow.mRight.mString, str);
-    right->SetString(str);
+    nsStyleUtil::AppendEscapedCSSString(side->mString, str);
+    second->SetString(str);
   } else {
-    right->SetIdent(
-      nsCSSProps::ValueToKeywordEnum(style->mTextOverflow.mRight.mType,
+    second->SetIdent(
+      nsCSSProps::ValueToKeywordEnum(side->mType,
                                      nsCSSProps::kTextOverflowKTable));
   }
 
   nsDOMCSSValueList *valueList = GetROCSSValueList(PR_FALSE);
-  valueList->AppendCSSValue(left);
-  valueList->AppendCSSValue(right);
+  valueList->AppendCSSValue(first);
+  valueList->AppendCSSValue(second);
   return valueList;
 }
 
 nsIDOMCSSValue*
 nsComputedDOMStyle::DoGetTextShadow()
 {
   return GetCSSShadowArray(GetStyleText()->mTextShadow,
                            GetStyleColor()->mColor,
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -3489,25 +3489,44 @@ nsRuleNode::ComputeTextResetData(void* a
     text->SetDecorationStyle(decorationStyleValue->GetIntValue());
   } else if (eCSSUnit_Inherit == decorationStyleValue->GetUnit()) {
     text->SetDecorationStyle(parentText->GetDecorationStyle());
     canStoreInRuleTree = PR_FALSE;
   } else if (eCSSUnit_Initial == decorationStyleValue->GetUnit()) {
     text->SetDecorationStyle(NS_STYLE_TEXT_DECORATION_STYLE_SOLID);
   }
 
-  // text-overflow: pair(enum|string), inherit, initial
+  // text-overflow: enum, string, pair(enum|string), inherit, initial
   const nsCSSValue* textOverflowValue =
     aRuleData->ValueForTextOverflow();
   if (eCSSUnit_Initial == textOverflowValue->GetUnit()) {
     text->mTextOverflow = nsStyleTextOverflow();
   } else if (eCSSUnit_Inherit == textOverflowValue->GetUnit()) {
     canStoreInRuleTree = PR_FALSE;
     text->mTextOverflow = parentText->mTextOverflow;
+  } else if (eCSSUnit_Enumerated == textOverflowValue->GetUnit()) {
+    // A single enumerated value.
+    SetDiscrete(*textOverflowValue, text->mTextOverflow.mRight.mType,
+                canStoreInRuleTree,
+                SETDSC_ENUMERATED, parentText->mTextOverflow.mRight.mType,
+                NS_STYLE_TEXT_OVERFLOW_CLIP, 0, 0, 0, 0);
+    text->mTextOverflow.mRight.mString.Truncate();
+    text->mTextOverflow.mLeft.mType = NS_STYLE_TEXT_OVERFLOW_CLIP;
+    text->mTextOverflow.mLeft.mString.Truncate();
+    text->mTextOverflow.mLogicalDirections = true;
+  } else if (eCSSUnit_String == textOverflowValue->GetUnit()) {
+    // A single string value.
+    text->mTextOverflow.mRight.mType = NS_STYLE_TEXT_OVERFLOW_STRING;
+    textOverflowValue->GetStringValue(text->mTextOverflow.mRight.mString);
+    text->mTextOverflow.mLeft.mType = NS_STYLE_TEXT_OVERFLOW_CLIP;
+    text->mTextOverflow.mLeft.mString.Truncate();
+    text->mTextOverflow.mLogicalDirections = true;
   } else if (eCSSUnit_Pair == textOverflowValue->GetUnit()) {
+    // Two values were specified.
+    text->mTextOverflow.mLogicalDirections = false;
     const nsCSSValuePair& textOverflowValue =
       aRuleData->ValueForTextOverflow()->GetPairValue();
 
     const nsCSSValue *textOverflowLeftValue = &textOverflowValue.mXValue;
     if (eCSSUnit_Enumerated == textOverflowLeftValue->GetUnit()) {
       SetDiscrete(*textOverflowLeftValue, text->mTextOverflow.mLeft.mType,
                   canStoreInRuleTree,
                   SETDSC_ENUMERATED, parentText->mTextOverflow.mLeft.mType,
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -1143,25 +1143,53 @@ struct nsStyleTextOverflowSide {
     return !(*this == aOther);
   }
 
   nsString mString;
   PRUint8  mType;
 };
 
 struct nsStyleTextOverflow {
+  nsStyleTextOverflow() : mLogicalDirections(true) {}
   bool operator==(const nsStyleTextOverflow& aOther) const {
     return mLeft == aOther.mLeft && mRight == aOther.mRight;
   }
   bool operator!=(const nsStyleTextOverflow& aOther) const {
     return !(*this == aOther);
   }
 
-  nsStyleTextOverflowSide mLeft;
-  nsStyleTextOverflowSide mRight;
+  // Returns the value to apply on the left side.
+  const nsStyleTextOverflowSide& GetLeft(PRUint8 aDirection) const {
+    NS_ASSERTION(aDirection == NS_STYLE_DIRECTION_LTR ||
+                 aDirection == NS_STYLE_DIRECTION_RTL, "bad direction");
+    return !mLogicalDirections || aDirection == NS_STYLE_DIRECTION_LTR ?
+             mLeft : mRight;
+  }
+
+  // Returns the value to apply on the right side.
+  const nsStyleTextOverflowSide& GetRight(PRUint8 aDirection) const {
+    NS_ASSERTION(aDirection == NS_STYLE_DIRECTION_LTR ||
+                 aDirection == NS_STYLE_DIRECTION_RTL, "bad direction");
+    return !mLogicalDirections || aDirection == NS_STYLE_DIRECTION_LTR ?
+             mRight : mLeft;
+  }
+
+  // Returns the first value that was specified.
+  const nsStyleTextOverflowSide* GetFirstValue() const {
+    return mLogicalDirections ? &mRight : &mLeft;
+  }
+
+  // Returns the second value, or null if there was only one value specified.
+  const nsStyleTextOverflowSide* GetSecondValue() const {
+    return mLogicalDirections ? nsnull : &mRight;
+  }
+
+  nsStyleTextOverflowSide mLeft;  // start side when mLogicalDirections is true
+  nsStyleTextOverflowSide mRight; // end side when mLogicalDirections is true
+  bool mLogicalDirections;  // true when only one value was specified
 };
 
 struct nsStyleTextReset {
   nsStyleTextReset(void);
   nsStyleTextReset(const nsStyleTextReset& aOther);
   ~nsStyleTextReset(void);
 
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -2563,18 +2563,18 @@ var gCSSProperties = {
 			"-moz-calc(3*25px + 50%)",
 		],
 		invalid_values: []
 	},
 	"text-overflow": {
 		domProp: "textOverflow",
 		inherited: false,
 		type: CSS_TYPE_LONGHAND,
-		initial_values: [ "clip", "clip clip" ],
-		other_values: [ "ellipsis", '""', "''", '"hello"', 'clip ellipsis', 'clip ""', '"hello" ""', '"" ellipsis' ],
+		initial_values: [ "clip" ],
+		other_values: [ "ellipsis", '""', "''", '"hello"', 'clip clip', 'ellipsis ellipsis', 'clip ellipsis', 'clip ""', '"hello" ""', '"" ellipsis' ],
 		invalid_values: [ "none", "auto", '"hello" inherit', 'inherit "hello"', 'clip initial', 'initial clip', 'initial inherit', 'inherit initial', 'inherit none']
 	},
 	"text-shadow": {
 		domProp: "textShadow",
 		inherited: true,
 		type: CSS_TYPE_LONGHAND,
 		prerequisites: { "color": "blue" },
 		initial_values: [ "none" ],