Merge the last green changeset of mozilla-inbound to mozilla-central
authorEhsan Akhgari <ehsan@mozilla.com>
Wed, 22 Jun 2011 19:17:32 -0400
changeset 71559 48e72227c2fac1644fec76af2e042c5bb6d61e58
parent 71547 56854b8cf1a6a146f52bd0f2aed944e08960b7e8 (current diff)
parent 71558 053ac4368a79ff3831819e9e383daffe41979b79 (diff)
child 71560 2af378ef814c569adbfa97c68dd979fbd754b23f
child 71583 d329bd37012253ba13fadb667c1e7f06525ca418
push id20563
push usereakhgari@mozilla.com
push dateWed, 22 Jun 2011 23:17:45 +0000
treeherdermozilla-central@48e72227c2fa [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
milestone7.0a1
first release with
nightly linux32
48e72227c2fa / 7.0a1 / 20110623030811 / files
nightly linux64
48e72227c2fa / 7.0a1 / 20110623030811 / files
nightly mac
48e72227c2fa / 7.0a1 / 20110623030811 / files
nightly win32
48e72227c2fa / 7.0a1 / 20110623030811 / files
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
releases
nightly linux32
nightly linux64
nightly mac
nightly win32
Merge the last green changeset of mozilla-inbound to mozilla-central
--- a/dom/interfaces/css/nsIDOMCSS2Properties.idl
+++ b/dom/interfaces/css/nsIDOMCSS2Properties.idl
@@ -19,16 +19,17 @@
  * Portions created by the Initial Developer are Copyright (C) 2000
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Vidur Apparao <vidur@netscape.com> (original author)
  *   Johnny Stenback <jst@netscape.com>
  *   Jonathon Jongsma <jonathon.jongsma@collabora.co.uk>, Collabora Ltd.
  *   Robert Longson <longsonr@gmail.com>
+ *   Mats Palmgren <matspal@gmail.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -45,17 +46,17 @@
  * The nsIDOMCSS2Properties interface is a datatype for additional
  * reflection of data already provided in nsIDOMCSSStyleDeclaration in
  * the Document Object Model.
  *
  * For more information on this interface please see
  * http://www.w3.org/TR/DOM-Level-2-Style
  */
 
-[scriptable, uuid(249755DF-EEFE-4AF4-8127-BE3D6BDAED2D)]
+[scriptable, uuid(7cf11a5f-4be5-4e31-b427-58d82746b5f5)]
 interface nsIDOMCSS2Properties : nsISupports
 {
            attribute DOMString        background;
                                         // raises(DOMException) on setting
 
            attribute DOMString        backgroundAttachment;
                                         // raises(DOMException) on setting
 
@@ -339,16 +340,19 @@ interface nsIDOMCSS2Properties : nsISupp
                                         // raises(DOMException) on setting
 
            attribute DOMString        textDecoration;
                                         // raises(DOMException) on setting
 
            attribute DOMString        textIndent;
                                         // raises(DOMException) on setting
 
+           attribute DOMString        textOverflow;
+                                        // raises(DOMException) on setting
+
            attribute DOMString        textShadow;
                                         // raises(DOMException) on setting
 
            attribute DOMString        textTransform;
                                         // raises(DOMException) on setting
 
            attribute DOMString        top;
                                         // raises(DOMException) on setting
--- a/gfx/thebes/gfxPangoFonts.cpp
+++ b/gfx/thebes/gfxPangoFonts.cpp
@@ -156,16 +156,24 @@ FindFunctionSymbol(const char *name)
     PRFuncPtr result = PR_FindFunctionSymbolAndLibrary(name, &lib);
     if (lib) {
         PR_UnloadLibrary(lib);
     }
 
     return result;
 }
 
+static PRBool HasChar(FcPattern *aFont, FcChar32 wc)
+{
+    FcCharSet *charset = NULL;
+    FcPatternGetCharSet(aFont, FC_CHARSET, 0, &charset);
+
+    return charset && FcCharSetHasChar(charset, wc);
+}
+
 /**
  * gfxFcFontEntry:
  *
  * An abstract base class of for gfxFontEntry implementations used by
  * gfxFcFont and gfxUserFontSet.
  */
 
 class gfxFcFontEntry : public gfxFontEntry {
@@ -194,16 +202,27 @@ public:
     // gfxFcFontEntries in families; just read the name from fontconfig
     virtual nsString FamilyName() const;
 
     // override the gfxFontEntry impl to read the name from fontconfig
     // instead of trying to get the 'name' table, as we don't implement
     // GetFontTable() here
     virtual nsString RealFaceName();
 
+    // This is needed to make gfxFontEntry::HasCharacter(aCh) work.
+    virtual PRBool TestCharacterMap(PRUint32 aCh)
+    {
+        for (PRUint32 i = 0; i < mPatterns.Length(); ++i) {
+            if (HasChar(mPatterns[i], aCh)) {
+                return PR_TRUE;
+            }
+        }
+        return PR_FALSE;
+    }
+
 protected:
     gfxFcFontEntry(const nsAString& aName)
         : gfxFontEntry(aName),
           mSkipHarfBuzz(PR_FALSE), mSkipGraphiteCheck(PR_FALSE)
     {
     }
 
     // One pattern is the common case and some subclasses rely on successful
@@ -1629,24 +1648,16 @@ gfxFcFontSet::GetFontPatternAt(PRUint32 
             // finished with this font set
             mFcFontSet.reset();
         }
     }
 
     return mFonts[i].mPattern;
 }
 
-static PRBool HasChar(FcPattern *aFont, FcChar32 wc)
-{
-    FcCharSet *charset = NULL;
-    FcPatternGetCharSet(aFont, FC_CHARSET, 0, &charset);
-
-    return charset && FcCharSetHasChar(charset, wc);
-}
-
 /**
  * gfxPangoFontMap: An implementation of a PangoFontMap.
  *
  * This is a PangoFcFontMap for gfxPangoFcFont.  It will only ever be used if
  * some day pango_cairo_font_map_get_default() does not return a
  * PangoFcFontMap.
  */
 
--- a/layout/base/nsCaret.cpp
+++ b/layout/base/nsCaret.cpp
@@ -627,20 +627,40 @@ nsresult nsCaret::PrimeTimer()
 
     mBlinkTimer->InitWithFuncCallback(CaretBlinkCallback, this, mBlinkRate,
                                       nsITimer::TYPE_REPEATING_SLACK);
   }
 
   return NS_OK;
 }
 
+void nsCaret::InvalidateTextOverflowBlock()
+{
+  // If the nearest block has a potential 'text-overflow' marker then
+  // invalidate it.
+  if (mLastContent) {
+    nsIFrame* caretFrame = mLastContent->GetPrimaryFrame();
+    if (caretFrame) {
+      nsIFrame* block = nsLayoutUtils::GetAsBlock(caretFrame) ? caretFrame :
+        nsLayoutUtils::FindNearestBlockAncestor(caretFrame);
+      if (block) {
+        const nsStyleTextReset* style = block->GetStyleTextReset();
+        if (style->mTextOverflow.mType != NS_STYLE_TEXT_OVERFLOW_CLIP) {
+          block->InvalidateOverflowRect();
+        }
+      }
+    }
+  }
+}
 
 //-----------------------------------------------------------------------------
 void nsCaret::StartBlinking()
 {
+  InvalidateTextOverflowBlock();
+
   if (mReadOnly) {
     // Make sure the one draw command we use for a readonly caret isn't
     // done until the selection is set
     DrawCaretAfterBriefDelay();
     return;
   }
   PrimeTimer();
 
@@ -654,16 +674,18 @@ void nsCaret::StartBlinking()
 
   DrawCaret(PR_TRUE);    // draw it right away
 }
 
 
 //-----------------------------------------------------------------------------
 void nsCaret::StopBlinking()
 {
+  InvalidateTextOverflowBlock();
+
   if (mDrawn)     // erase the caret if necessary
     DrawCaret(PR_TRUE);
 
   NS_ASSERTION(!mDrawn, "Caret still drawn after StopBlinking().");
   KillTimer();
 }
 
 PRBool
--- a/layout/base/nsCaret.h
+++ b/layout/base/nsCaret.h
@@ -199,16 +199,20 @@ class nsCaret : public nsISelectionListe
 
 protected:
 
     void          KillTimer();
     nsresult      PrimeTimer();
 
     void          StartBlinking();
     void          StopBlinking();
+
+    // If the nearest block has a potential 'text-overflow' marker then
+    // invalidate it.
+    void          InvalidateTextOverflowBlock();
     
     PRBool        DrawAtPositionWithHint(nsIDOMNode* aNode,
                                          PRInt32 aOffset,
                                          nsFrameSelection::HINT aFrameHint,
                                          PRUint8 aBidiLevel,
                                          PRBool aInvalidate);
 
     struct Metrics {
--- a/layout/base/nsDisplayItemTypes.h
+++ b/layout/base/nsDisplayItemTypes.h
@@ -61,16 +61,17 @@ enum Type {
   TYPE_CHECKED_CHECKBOX,
   TYPE_CHECKED_RADIOBUTTON,
   TYPE_CLIP,
   TYPE_CLIP_ROUNDED_RECT,
   TYPE_COLUMN_RULE,
   TYPE_COMBOBOX_FOCUS,
   TYPE_EVENT_RECEIVER,
   TYPE_FIELDSET_BORDER_BACKGROUND,
+  TYPE_FORCEPAINTONSCROLL,
   TYPE_FRAMESET_BORDER,
   TYPE_FRAMESET_BLANK,
   TYPE_HEADER_FOOTER,
   TYPE_IMAGE,
   TYPE_LIST_FOCUS,
   TYPE_OPACITY,
   TYPE_OPTION_EVENT_GRABBER,
   TYPE_OUTLINE,
@@ -90,16 +91,17 @@ enum Type {
   TYPE_SVG_EVENT_RECEIVER,
   TYPE_TABLE_CELL_BACKGROUND,
   TYPE_TABLE_CELL_SELECTION,
   TYPE_TABLE_ROW_BACKGROUND,
   TYPE_TABLE_ROW_GROUP_BACKGROUND,
   TYPE_TABLE_BORDER_BACKGROUND,
   TYPE_TEXT,
   TYPE_TEXT_DECORATION,
+  TYPE_TEXT_OVERFLOW,
   TYPE_TEXT_SHADOW,
   TYPE_TRANSFORM,
   TYPE_VIDEO,
   TYPE_WRAP_LIST,
   TYPE_ZOOM,
   TYPE_EXCLUDE_GLASS_FRAME,
 
 #if defined(MOZ_REFLOW_PERF_DSP) && defined(MOZ_REFLOW_PERF)
--- a/layout/base/nsDisplayList.cpp
+++ b/layout/base/nsDisplayList.cpp
@@ -2740,8 +2740,25 @@ PRBool nsDisplaySVGEffects::TryMerge(nsD
   if (aItem->GetUnderlyingFrame()->GetContent() != mFrame->GetContent())
     return PR_FALSE;
   nsDisplaySVGEffects* other = static_cast<nsDisplaySVGEffects*>(aItem);
   mList.AppendToBottom(&other->mList);
   mBounds.UnionRect(mBounds,
     other->mBounds + other->mEffectsFrame->GetOffsetTo(mEffectsFrame));
   return PR_TRUE;
 }
+
+nsDisplayForcePaintOnScroll::nsDisplayForcePaintOnScroll(
+    nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
+  : nsDisplayItem(aBuilder, aFrame) {
+  MOZ_COUNT_CTOR(nsDisplayForcePaintOnScroll);
+}
+
+#ifdef NS_BUILD_REFCNT_LOGGING
+nsDisplayForcePaintOnScroll::~nsDisplayForcePaintOnScroll() {
+  MOZ_COUNT_DTOR(nsDisplayForcePaintOnScroll);
+}
+#endif
+
+PRBool nsDisplayForcePaintOnScroll::IsVaryingRelativeToMovingFrame(
+         nsDisplayListBuilder* aBuilder, nsIFrame* aFrame) {
+  return PR_TRUE;
+}
--- a/layout/base/nsDisplayList.h
+++ b/layout/base/nsDisplayList.h
@@ -182,25 +182,25 @@ public:
    * @return the selection that painting should be restricted to (or nsnull
    * in the normal unrestricted case)
    */
   nsISelection* GetBoundingSelection() { return mBoundingSelection; }
   /**
    * @return the root of the display list's frame (sub)tree, whose origin
    * establishes the coordinate system for the display list
    */
-  nsIFrame* ReferenceFrame() { return mReferenceFrame; }
+  nsIFrame* ReferenceFrame() const { return mReferenceFrame; }
   /**
    * @return a point pt such that adding pt to a coordinate relative to aFrame
    * makes it relative to ReferenceFrame(), i.e., returns 
    * aFrame->GetOffsetToCrossDoc(ReferenceFrame()). The returned point is in
    * the appunits of aFrame. It may be optimized to be faster than
    * aFrame->GetOffsetToCrossDoc(ReferenceFrame()) (but currently isn't).
    */
-  nsPoint ToReferenceFrame(const nsIFrame* aFrame) {
+  nsPoint ToReferenceFrame(const nsIFrame* aFrame) const {
     return aFrame->GetOffsetToCrossDoc(ReferenceFrame());
   }
   /**
    * When building the display list, the scrollframe aFrame will be "ignored"
    * for the purposes of clipping, and its scrollbars will be hidden. We use
    * this to allow RenderOffscreen to render a whole document without beign
    * clipped by the viewport or drawing the viewport scrollbars.
    */
@@ -631,17 +631,17 @@ public:
   virtual void HitTest(nsDisplayListBuilder* aBuilder, const nsRect& aRect,
                        HitTestState* aState, nsTArray<nsIFrame*> *aOutFrames) {}
   /**
    * @return the frame that this display item is based on. This is used to sort
    * items by z-index and content order and for some other uses. For some items
    * that wrap item lists, this could return nsnull because there is no single
    * underlying frame; for leaf items it will never return nsnull.
    */
-  inline nsIFrame* GetUnderlyingFrame() { return mFrame; }
+  inline nsIFrame* GetUnderlyingFrame() const { return mFrame; }
   /**
    * The default bounds is the frame border rect.
    * @return a rectangle relative to aBuilder->ReferenceFrame() that
    * contains the area drawn by this display item
    */
   virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder) {
     return nsRect(ToReferenceFrame(), GetUnderlyingFrame()->GetSize());
   }
@@ -808,17 +808,17 @@ public:
    * -- Subtracts bounds from aVisibleRegion if the item is opaque
    */
   PRBool RecomputeVisibility(nsDisplayListBuilder* aBuilder,
                              nsRegion* aVisibleRegion);
 
   /**
    * Returns the result of aBuilder->ToReferenceFrame(GetUnderlyingFrame())
    */
-  const nsPoint& ToReferenceFrame() {
+  const nsPoint& ToReferenceFrame() const {
     NS_ASSERTION(mFrame, "No frame?");
     return mToReferenceFrame;
   }
 
   /**
    * Checks if this display item (or any children) contains content that might
    * be rendered with component alpha (e.g. subpixel antialiasing). Returns the
    * bounds of the area that needs component alpha, or an empty rect if nothing
@@ -2182,9 +2182,74 @@ public:
                                                const nsPoint& aOrigin,
                                                float aFactor,
                                                const nsRect* aBoundsOverride = nsnull);
 
 private:
   nsDisplayWrapList mStoredList;
 };
 
+/**
+ * This class adds basic support for limiting the rendering to the part inside
+ * the specified edges.  It's a base class for the display item classes that
+ * does the actual work.  The two members, mLeftEdge and mRightEdge, are
+ * relative to the edges of the frame's scrollable overflow rectangle and is
+ * the amount to suppress on each side.
+ *
+ * Setting none, both or only one edge is allowed.
+ * The values must be non-negative.
+ * The default value for both edges is zero, which means everything is painted.
+ */
+class nsCharClipDisplayItem : public nsDisplayItem {
+public:
+  nsCharClipDisplayItem(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame)
+    : nsDisplayItem(aBuilder, aFrame), mLeftEdge(0), mRightEdge(0) {}
+
+  struct ClipEdges {
+    ClipEdges(const nsDisplayItem& aItem,
+              nscoord aLeftEdge, nscoord aRightEdge) {
+      nsRect r = aItem.GetUnderlyingFrame()->GetScrollableOverflowRect() +
+                 aItem.ToReferenceFrame();
+      mX = aLeftEdge > 0 ? r.x + aLeftEdge : nscoord_MIN;
+      mXMost = aRightEdge > 0 ? NS_MAX(r.XMost() - aRightEdge, mX) : nscoord_MAX;
+    }
+    void Intersect(nscoord* aX, nscoord* aWidth) const {
+      nscoord xmost1 = *aX + *aWidth;
+      *aX = NS_MAX(*aX, mX);
+      *aWidth = NS_MAX(NS_MIN(xmost1, mXMost) - *aX, 0);
+    }
+    nscoord mX;
+    nscoord mXMost;
+  };
+
+  ClipEdges Edges() const { return ClipEdges(*this, mLeftEdge, mRightEdge); }
+
+  static nsCharClipDisplayItem* CheckCast(nsDisplayItem* aItem) {
+    nsDisplayItem::Type t = aItem->GetType();
+    return (t == nsDisplayItem::TYPE_TEXT ||
+            t == nsDisplayItem::TYPE_TEXT_DECORATION ||
+            t == nsDisplayItem::TYPE_TEXT_SHADOW)
+      ? static_cast<nsCharClipDisplayItem*>(aItem) : nsnull;
+  }
+
+  nscoord mLeftEdge;  // length from the left side
+  nscoord mRightEdge; // length from the right side
+};
+
+
+/**
+ * This is a dummy item that reports true for IsVaryingRelativeToMovingFrame.
+ * It forces the bounds of its frame to be repainted every time it is scrolled.
+ * It is transparent to events and does not paint anything.
+ */
+class nsDisplayForcePaintOnScroll : public nsDisplayItem
+{
+public:
+  nsDisplayForcePaintOnScroll(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame);
+#ifdef NS_BUILD_REFCNT_LOGGING
+  virtual ~nsDisplayForcePaintOnScroll();
+#endif
+  NS_DISPLAY_DECL_NAME("ForcePaintOnScroll", TYPE_FORCEPAINTONSCROLL)
+  virtual PRBool IsVaryingRelativeToMovingFrame(nsDisplayListBuilder* aBuilder,
+                                                nsIFrame* aFrame);
+};
+
 #endif /*NSDISPLAYLIST_H_*/
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -17,17 +17,17 @@
  *
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 1998
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   L. David Baron <dbaron@dbaron.org>, Mozilla Corporation
- *   Mats Palmgren <mats.palmgren@bredband.net>
+ *   Mats Palmgren <matspal@gmail.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -45,16 +45,17 @@
 #include "nsIDOMDocument.h"
 #include "nsIDOMHTMLDocument.h"
 #include "nsIDOMHTMLElement.h"
 #include "nsFrameList.h"
 #include "nsGkAtoms.h"
 #include "nsIAtom.h"
 #include "nsCSSPseudoElements.h"
 #include "nsCSSAnonBoxes.h"
+#include "nsCSSColorUtils.h"
 #include "nsIView.h"
 #include "nsPlaceholderFrame.h"
 #include "nsIScrollableFrame.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsIPrivateDOMEvent.h"
 #include "nsIDOMEvent.h"
 #include "nsGUIEvent.h"
 #include "nsDisplayList.h"
@@ -2785,16 +2786,59 @@ nsLayoutUtils::PrefWidthFromInline(nsIFr
 {
   nsIFrame::InlinePrefWidthData data;
   DISPLAY_PREF_WIDTH(aFrame, data.prevLines);
   aFrame->AddInlinePrefWidth(aRenderingContext, &data);
   data.ForceBreak(aRenderingContext);
   return data.prevLines;
 }
 
+static nscolor
+DarkenColor(nscolor aColor)
+{
+  PRUint16  hue, sat, value;
+  PRUint8 alpha;
+
+  // convert the RBG to HSV so we can get the lightness (which is the v)
+  NS_RGB2HSV(aColor, hue, sat, value, alpha);
+
+  // The goal here is to send white to black while letting colored
+  // stuff stay colored... So we adopt the following approach.
+  // Something with sat = 0 should end up with value = 0.  Something
+  // with a high sat can end up with a high value and it's ok.... At
+  // the same time, we don't want to make things lighter.  Do
+  // something simple, since it seems to work.
+  if (value > sat) {
+    value = sat;
+    // convert this color back into the RGB color space.
+    NS_HSV2RGB(aColor, hue, sat, value, alpha);
+  }
+  return aColor;
+}
+
+// Check whether we should darken text colors. We need to do this if
+// background images and colors are being suppressed, because that means
+// light text will not be visible against the (presumed light-colored) background.
+static PRBool
+ShouldDarkenColors(nsPresContext* aPresContext)
+{
+  return !aPresContext->GetBackgroundColorDraw() &&
+    !aPresContext->GetBackgroundImageDraw();
+}
+
+nscolor
+nsLayoutUtils::GetTextColor(nsIFrame* aFrame)
+{
+  nscolor color = aFrame->GetVisitedDependentColor(eCSSProperty_color);
+  if (ShouldDarkenColors(aFrame->PresContext())) {
+    color = DarkenColor(color);
+  }
+  return color;
+}
+
 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
@@ -17,17 +17,17 @@
  * The Initial Developer of the Original Code is
  * Boris Zbarsky <bzbarsky@mit.edu>.
  * Portions created by the Initial Developer are Copyright (C) 2002
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Boris Zbarsky <bzbarsky@mit.edu> (original author)
  *   L. David Baron <dbaron@dbaron.org>, Mozilla Corporation
- *   Mats Palmgren <mats.palmgren@bredband.net>
+ *   Mats Palmgren <matspal@gmail.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -926,16 +926,19 @@ public:
   // Implement nsIFrame::GetPrefWidth in terms of nsIFrame::AddInlinePrefWidth
   static nscoord PrefWidthFromInline(nsIFrame* aFrame,
                                      nsRenderingContext* aRenderingContext);
 
   // 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);
+
   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/base/nsStyleConsts.h
+++ b/layout/base/nsStyleConsts.h
@@ -15,17 +15,17 @@
  * The Original Code is mozilla.org code.
  *
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 1998
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
- *   Mats Palmgren <mats.palmgren@bredband.net>
+ *   Mats Palmgren <matspal@gmail.com>
  *   Jonathon Jongsma <jonathon.jongsma@collabora.co.uk>, Collabora Ltd.
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
@@ -655,16 +655,21 @@ static inline mozilla::css::Side operato
 #define NS_STYLE_TEXT_DECORATION_STYLE_NONE     0 // not in CSS spec, mapped to -moz-none
 #define NS_STYLE_TEXT_DECORATION_STYLE_DOTTED   1
 #define NS_STYLE_TEXT_DECORATION_STYLE_DASHED   2
 #define NS_STYLE_TEXT_DECORATION_STYLE_SOLID    3
 #define NS_STYLE_TEXT_DECORATION_STYLE_DOUBLE   4
 #define NS_STYLE_TEXT_DECORATION_STYLE_WAVY     5
 #define NS_STYLE_TEXT_DECORATION_STYLE_MAX      NS_STYLE_TEXT_DECORATION_STYLE_WAVY
 
+// See nsStyleTextOverflow
+#define NS_STYLE_TEXT_OVERFLOW_CLIP     0
+#define NS_STYLE_TEXT_OVERFLOW_ELLIPSIS 1
+#define NS_STYLE_TEXT_OVERFLOW_STRING   2
+
 // See nsStyleText
 #define NS_STYLE_TEXT_TRANSFORM_NONE            0
 #define NS_STYLE_TEXT_TRANSFORM_CAPITALIZE      1
 #define NS_STYLE_TEXT_TRANSFORM_LOWERCASE       2
 #define NS_STYLE_TEXT_TRANSFORM_UPPERCASE       3
 
 // See nsStyleDisplay
 #define NS_STYLE_TRANSITION_TIMING_FUNCTION_EASE         0
--- a/layout/generic/Makefile.in
+++ b/layout/generic/Makefile.in
@@ -104,16 +104,17 @@ CPPSRCS		= \
 		nsPageFrame.cpp \
 		nsPlaceholderFrame.cpp \
 		nsSelection.cpp \
 		nsSimplePageSequence.cpp \
 		nsSplittableFrame.cpp \
 		nsSubDocumentFrame.cpp \
 		nsTextFrameThebes.cpp \
 		nsTextFrameUtils.cpp \
+		TextOverflow.cpp \
 		nsTextRunTransformations.cpp \
 		nsViewportFrame.cpp \
 		$(NULL)
 
 ifdef MOZ_MEDIA
 CPPSRCS		+= \
 		nsVideoFrame.cpp \
 		$(NULL)
new file mode 100644
--- /dev/null
+++ b/layout/generic/TextOverflow.cpp
@@ -0,0 +1,634 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is an implementation of CSS3 text-overflow.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Mats Palmgren <matspal@gmail.com> (original author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "TextOverflow.h"
+
+// Please maintain alphabetical order below
+#include "nsBlockFrame.h"
+#include "nsCaret.h"
+#include "nsContentUtils.h"
+#include "nsIScrollableFrame.h"
+#include "nsLayoutUtils.h"
+#include "nsPresContext.h"
+#include "nsRect.h"
+#include "nsRenderingContext.h"
+#include "nsTextFrame.h"
+
+namespace mozilla {
+namespace css {
+
+static const PRUnichar kEllipsisChar[] = { 0x2026, 0x0 };
+static const PRUnichar kASCIIPeriodsChar[] = { '.', '.', '.', 0x0 };
+
+// Return an ellipsis if the font supports it,
+// otherwise use three ASCII periods as fallback.
+static nsDependentString GetEllipsis(nsIFrame* aFrame)
+{
+  // Check if the first font supports Unicode ellipsis.
+  nsRefPtr<nsFontMetrics> fm;
+  nsLayoutUtils::GetFontMetricsForFrame(aFrame, getter_AddRefs(fm));
+  gfxFontGroup* fontGroup = fm->GetThebesFontGroup();
+  gfxFont* firstFont = fontGroup->GetFontAt(0);
+  return firstFont && firstFont->HasCharacter(kEllipsisChar[0])
+    ? nsDependentString(kEllipsisChar,
+                        NS_ARRAY_LENGTH(kEllipsisChar) - 1)
+    : nsDependentString(kASCIIPeriodsChar,
+                        NS_ARRAY_LENGTH(kASCIIPeriodsChar) - 1);
+}
+
+static nsIFrame*
+GetSelfOrNearestBlock(nsIFrame* aFrame)
+{
+  return nsLayoutUtils::GetAsBlock(aFrame) ? aFrame :
+         nsLayoutUtils::FindNearestBlockAncestor(aFrame);
+}
+
+// Return true if the frame is an atomic inline-level element.
+// It's not supposed to be called for block frames since we never
+// process block descendants for text-overflow.
+static bool
+IsAtomicElement(nsIFrame* aFrame, const nsIAtom* aFrameType)
+{
+  NS_PRECONDITION(!aFrame->GetStyleDisplay()->IsBlockOutside(),
+                  "unexpected block frame");
+
+  if (aFrame->IsFrameOfType(nsIFrame::eReplaced)) {
+    if (aFrameType != nsGkAtoms::textFrame &&
+        aFrameType != nsGkAtoms::brFrame) {
+      return true;
+    }
+  }
+  return aFrame->GetStyleDisplay()->mDisplay != NS_STYLE_DISPLAY_INLINE;
+}
+
+static bool
+IsFullyClipped(nsTextFrame* aFrame, nscoord aLeft, nscoord aRight,
+               nscoord* aSnappedLeft, nscoord* aSnappedRight)
+{
+  *aSnappedLeft = aLeft;
+  *aSnappedRight = aRight;
+  if (aLeft <= 0 && aRight <= 0) {
+    return false;
+  }
+  nsRefPtr<nsRenderingContext> rc =
+    aFrame->PresContext()->PresShell()->GetReferenceRenderingContext();
+  return rc &&
+    !aFrame->MeasureCharClippedText(rc->ThebesContext(), aLeft, aRight,
+                                    aSnappedLeft, aSnappedRight);
+}
+
+static bool
+IsHorizontalOverflowVisible(nsIFrame* aFrame)
+{
+  NS_PRECONDITION(nsLayoutUtils::GetAsBlock(aFrame) != nsnull,
+                  "expected a block frame");
+
+  nsIFrame* f = aFrame;
+  while (f && f->GetStyleContext()->GetPseudo()) {
+    f = f->GetParent();
+  }
+  return !f || f->GetStyleDisplay()->mOverflowX == NS_STYLE_OVERFLOW_VISIBLE;
+}
+
+static nsDisplayItem*
+ClipMarker(nsDisplayListBuilder* aBuilder,
+           nsIFrame*             aFrame,
+           nsDisplayItem*        aMarker,
+           const nsRect&         aContentArea,
+           nsRect*               aMarkerRect)
+{
+  nsDisplayItem* item = aMarker;
+  nscoord rightOverflow = aMarkerRect->XMost() - aContentArea.XMost();
+  if (rightOverflow > 0) {
+    // Marker overflows on the right side (content width < marker width).
+    aMarkerRect->width -= rightOverflow;
+    item = new (aBuilder)
+      nsDisplayClip(aBuilder, aFrame, aMarker, *aMarkerRect);
+  } else {
+    nscoord leftOverflow = aContentArea.x - aMarkerRect->x;
+    if (leftOverflow > 0) {
+      // Marker overflows on the left side
+      aMarkerRect->width -= leftOverflow;
+      aMarkerRect->x += leftOverflow;
+      item = new (aBuilder)
+        nsDisplayClip(aBuilder, aFrame, aMarker, *aMarkerRect);
+    }
+  }
+  return item;
+}
+
+static void
+InflateLeft(nsRect* aRect, bool aInfinity, nscoord aDelta)
+{
+  nscoord xmost = aRect->XMost();
+  if (aInfinity) {
+    aRect->x = nscoord_MIN;
+  } else {
+    aRect->x -= aDelta;
+  }
+  aRect->width = NS_MAX(xmost - aRect->x, 0);
+}
+
+static void
+InflateRight(nsRect* aRect, bool aInfinity, nscoord aDelta)
+{
+  if (aInfinity) {
+    aRect->width = nscoord_MAX;
+  } else {
+    aRect->width = NS_MAX(aRect->width + aDelta, 0);
+  }
+}
+
+static bool
+IsFrameDescendantOfAny(nsIFrame* aChild,
+                       const TextOverflow::FrameHashtable& aSetOfFrames,
+                       nsIFrame* aCommonAncestor)
+{
+  for (nsIFrame* f = aChild; f != aCommonAncestor;
+       f = nsLayoutUtils::GetCrossDocParentFrame(f)) {
+    if (aSetOfFrames.GetEntry(f)) {
+      return true;
+    }
+  }
+  return false;
+}
+
+class nsDisplayTextOverflowMarker : public nsDisplayItem
+{
+public:
+  nsDisplayTextOverflowMarker(nsDisplayListBuilder* aBuilder, nsIFrame* aFrame,
+                              const nsRect& aRect, nscoord aAscent,
+                              const nsString& aString)
+    : nsDisplayItem(aBuilder, aFrame), mRect(aRect), mString(aString),
+      mAscent(aAscent) {
+    MOZ_COUNT_CTOR(nsDisplayTextOverflowMarker);
+  }
+#ifdef NS_BUILD_REFCNT_LOGGING
+  virtual ~nsDisplayTextOverflowMarker() {
+    MOZ_COUNT_DTOR(nsDisplayTextOverflowMarker);
+  }
+#endif
+  virtual nsRect GetBounds(nsDisplayListBuilder* aBuilder) {
+    return mRect;
+  }
+  virtual void Paint(nsDisplayListBuilder* aBuilder,
+                     nsRenderingContext* aCtx);
+  NS_DISPLAY_DECL_NAME("TextOverflow", TYPE_TEXT_OVERFLOW)
+private:
+  nsRect          mRect;   // in reference frame coordinates
+  const nsString  mString; // the marker text
+  nscoord         mAscent; // baseline for the marker text in mRect
+};
+
+void
+nsDisplayTextOverflowMarker::Paint(nsDisplayListBuilder* aBuilder,
+                                   nsRenderingContext*   aCtx)
+{
+  nsStyleContext* sc = mFrame->GetStyleContext();
+  nsLayoutUtils::SetFontFromStyle(aCtx, sc);
+  aCtx->SetColor(nsLayoutUtils::GetTextColor(mFrame));
+  nsPoint baselinePt = mRect.TopLeft();
+  baselinePt.y += mAscent;
+  nsLayoutUtils::DrawString(mFrame, aCtx, mString.get(), mString.Length(),
+                            baselinePt);
+}
+
+/* static */ TextOverflow*
+TextOverflow::WillProcessLines(nsDisplayListBuilder*   aBuilder,
+                               const nsDisplayListSet& aLists,
+                               nsIFrame*               aBlockFrame)
+{
+  if (!CanHaveTextOverflow(aBuilder, aBlockFrame)) {
+    return nsnull;
+  }
+
+  nsAutoPtr<TextOverflow> textOverflow(new TextOverflow);
+  textOverflow->mBuilder = aBuilder;
+  textOverflow->mBlock = aBlockFrame;
+  textOverflow->mMarkerList = aLists.PositionedDescendants();
+  textOverflow->mContentArea = aBlockFrame->GetContentRectRelativeToSelf();
+  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;
+  const nsStyleTextReset* style = aBlockFrame->GetStyleTextReset();
+  textOverflow->mLeft.Init(style->mTextOverflow);
+  textOverflow->mRight.Init(style->mTextOverflow);
+  // The left/right marker string is setup in ExamineLineFrames when a line
+  // has overflow on that side.
+
+  return textOverflow.forget();
+}
+
+void
+TextOverflow::DidProcessLines()
+{
+  nsIScrollableFrame* scroll = nsLayoutUtils::GetScrollableFrameFor(mBlock);
+  if (scroll) {
+    // Create a dummy item covering the entire area, it doesn't paint
+    // but reports true for IsVaryingRelativeToMovingFrame().
+    nsIFrame* scrollFrame = do_QueryFrame(scroll);
+    nsDisplayItem* marker = new (mBuilder)
+      nsDisplayForcePaintOnScroll(mBuilder, scrollFrame);
+    if (marker) {
+      mMarkerList->AppendNewToBottom(marker);
+      mBlock->PresContext()->SetHasFixedBackgroundFrame();
+    }
+  }
+}
+
+void
+TextOverflow::ExamineFrameSubtree(nsIFrame*       aFrame,
+                                  const nsRect&   aContentArea,
+                                  const nsRect&   aInsideMarkersArea,
+                                  FrameHashtable* aFramesToHide,
+                                  AlignmentEdges* aAlignmentEdges)
+{
+  const nsIAtom* frameType = aFrame->GetType();
+  if (frameType == nsGkAtoms::brFrame) {
+    return;
+  }
+  const bool isAtomic = IsAtomicElement(aFrame, frameType);
+  if (aFrame->GetStyleVisibility()->IsVisible()) {
+    nsRect childRect = aFrame->GetScrollableOverflowRect() +
+                       aFrame->GetOffsetTo(mBlock);
+    bool overflowLeft = childRect.x < aContentArea.x;
+    bool overflowRight = childRect.XMost() > aContentArea.XMost();
+    if (overflowLeft) {
+      mLeft.mHasOverflow = true;
+    }
+    if (overflowRight) {
+      mRight.mHasOverflow = true;
+    }
+    if (isAtomic && (overflowLeft || overflowRight)) {
+      aFramesToHide->PutEntry(aFrame);
+    } else if (isAtomic || frameType == nsGkAtoms::textFrame) {
+      AnalyzeMarkerEdges(aFrame, frameType, aInsideMarkersArea,
+                         aFramesToHide, aAlignmentEdges);
+    }
+  }
+  if (isAtomic) {
+    return;
+  }
+
+  nsIFrame* child = aFrame->GetFirstChild(nsnull);
+  while (child) {
+    ExamineFrameSubtree(child, aContentArea, aInsideMarkersArea,
+                        aFramesToHide, aAlignmentEdges);
+    child = child->GetNextSibling();
+  }
+}
+
+void
+TextOverflow::AnalyzeMarkerEdges(nsIFrame*       aFrame,
+                                 const nsIAtom*  aFrameType,
+                                 const nsRect&   aInsideMarkersArea,
+                                 FrameHashtable* aFramesToHide,
+                                 AlignmentEdges* aAlignmentEdges)
+{
+  nsRect borderRect(aFrame->GetOffsetTo(mBlock), aFrame->GetSize());
+  nscoord leftOverlap =
+    NS_MAX(aInsideMarkersArea.x - borderRect.x, 0);
+  nscoord rightOverlap =
+    NS_MAX(borderRect.XMost() - aInsideMarkersArea.XMost(), 0);
+  bool insideLeftEdge = aInsideMarkersArea.x <= borderRect.XMost();
+  bool insideRightEdge = borderRect.x <= aInsideMarkersArea.XMost();
+
+  if ((leftOverlap > 0 && insideLeftEdge) ||
+      (rightOverlap > 0 && insideRightEdge)) {
+    if (aFrameType == nsGkAtoms::textFrame &&
+        aInsideMarkersArea.x < aInsideMarkersArea.XMost()) {
+      // a clipped text frame and there is some room between the markers
+      nscoord snappedLeft, snappedRight;
+      bool isFullyClipped =
+        IsFullyClipped(static_cast<nsTextFrame*>(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);
+      }
+    } else if (IsAtomicElement(aFrame, aFrameType)) {
+      aFramesToHide->PutEntry(aFrame);
+    }
+  } else if (!insideLeftEdge || !insideRightEdge) {
+    // frame is outside
+    if (IsAtomicElement(aFrame, aFrameType)) {
+      aFramesToHide->PutEntry(aFrame);
+    }
+  } else {
+    // frame is inside
+    aAlignmentEdges->Accumulate(borderRect);
+  }
+}
+
+void
+TextOverflow::ExamineLineFrames(nsLineBox*      aLine,
+                                FrameHashtable* aFramesToHide,
+                                AlignmentEdges* aAlignmentEdges)
+{
+  // 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);
+  nsRect lineRect = aLine->GetScrollableOverflowArea();
+  const bool leftOverflow = lineRect.x < contentArea.x;
+  const bool rightOverflow = lineRect.XMost() > contentArea.XMost();
+  if (!leftOverflow && !rightOverflow) {
+    // The line does not overflow - no need to traverse the frame tree.
+    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;
+  do {
+    // Setup marker strings as needed.
+    if (guessLeft || guessRight) {
+      mLeft.SetupString(mBlock);
+      mRight.mMarkerString = mLeft.mMarkerString;
+      mRight.mWidth = mLeft.mWidth;
+      mRight.mInitialized = mLeft.mInitialized;
+    }
+    
+    // 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 &&
+        leftMarkerWidth + rightMarkerWidth > contentArea.width) {
+      if (mBlockIsRTL) {
+        rightMarkerWidth = 0;
+      } else {
+        leftMarkerWidth = 0;
+      }
+    }
+
+    // Calculate the area between the potential markers aligned at the
+    // block's edge.
+    nsRect insideMarkersArea = mContentArea;
+    InflateLeft(&insideMarkersArea, !guessLeft, -leftMarkerWidth);
+    InflateRight(&insideMarkersArea, !guessRight, -rightMarkerWidth);
+
+    // Analyze the frames on aLine for the overflow situation at the content
+    // edges and at the edges of the area between the markers.
+    PRInt32 n = aLine->GetChildCount();
+    nsIFrame* child = aLine->mFirstChild;
+    for (; n-- > 0; child = child->GetNextSibling()) {
+      ExamineFrameSubtree(child, contentArea, insideMarkersArea,
+                          aFramesToHide, aAlignmentEdges);
+    }
+    if (guessLeft == mLeft.IsNeeded() && guessRight == mRight.IsNeeded()) {
+      break;
+    } else {
+      guessLeft = mLeft.IsNeeded();
+      guessRight = mRight.IsNeeded();
+      mLeft.Reset();
+      mRight.Reset();
+      aFramesToHide->Clear();
+    }
+    NS_ASSERTION(pass == 0, "2nd pass should never guess wrong");
+  } while (++pass != 2);
+}
+
+void
+TextOverflow::ProcessLine(const nsDisplayListSet& aLists,
+                          nsLineBox*              aLine)
+{
+  NS_ASSERTION(mLeft.mStyle->mType != NS_STYLE_TEXT_OVERFLOW_CLIP ||
+               mRight.mStyle->mType != NS_STYLE_TEXT_OVERFLOW_CLIP,
+               "TextOverflow with 'clip' for both sides");
+  mLeft.Reset();
+  mRight.Reset();
+  FrameHashtable framesToHide;
+  if (!framesToHide.Init(100)) {
+    return;
+  }
+  AlignmentEdges alignmentEdges;
+  ExamineLineFrames(aLine, &framesToHide, &alignmentEdges);
+  bool needLeft = mLeft.IsNeeded();
+  bool needRight = mRight.IsNeeded();
+  if (!needLeft && !needRight) {
+    return;
+  }
+  NS_ASSERTION(mLeft.mStyle->mType != NS_STYLE_TEXT_OVERFLOW_CLIP ||
+               !needLeft, "left marker for 'clip'");
+  NS_ASSERTION(mRight.mStyle->mType != NS_STYLE_TEXT_OVERFLOW_CLIP ||
+               !needRight, "right marker for 'clip'");
+
+  // If there is insufficient space for both markers then keep the one on the
+  // end side per the block's 'direction'.
+  if (needLeft && needRight &&
+      mLeft.mWidth + mRight.mWidth > mContentArea.width) {
+    if (mBlockIsRTL) {
+      needRight = false;
+    } else {
+      needLeft = false;
+    }
+  }
+  nsRect insideMarkersArea = mContentArea;
+  if (needLeft) {
+    InflateLeft(&insideMarkersArea, false, -mLeft.mWidth);
+  }
+  if (needRight) {
+    InflateRight(&insideMarkersArea, false, -mRight.mWidth);
+  }
+  if (!mCanHaveHorizontalScrollbar && alignmentEdges.mAssigned) {
+    nsRect alignmentRect = nsRect(alignmentEdges.x, insideMarkersArea.y,
+                                  alignmentEdges.Width(), 1);
+    insideMarkersArea.IntersectRect(insideMarkersArea, alignmentRect);
+  }
+
+  // Clip and remove display items as needed at the final marker edges.
+  nsDisplayList* lists[] = { aLists.Content(), aLists.PositionedDescendants() };
+  for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(lists); ++i) {
+    PruneDisplayListContents(lists[i], framesToHide, insideMarkersArea);
+  }
+  CreateMarkers(aLine, needLeft, needRight, insideMarkersArea);
+}
+
+void
+TextOverflow::PruneDisplayListContents(nsDisplayList*        aList,
+                                       const FrameHashtable& aFramesToHide,
+                                       const nsRect&         aInsideMarkersArea)
+{
+  nsDisplayList saved;
+  nsDisplayItem* item;
+  while ((item = aList->RemoveBottom())) {
+    nsIFrame* itemFrame = item->GetUnderlyingFrame();
+    if (itemFrame && IsFrameDescendantOfAny(itemFrame, aFramesToHide, mBlock)) {
+      item->~nsDisplayItem();
+      continue;
+    }
+
+    nsDisplayList* wrapper = item->GetList();
+    if (wrapper) {
+      if (!itemFrame || GetSelfOrNearestBlock(itemFrame) == mBlock) {
+        PruneDisplayListContents(wrapper, aFramesToHide, aInsideMarkersArea);
+      }
+    }
+
+    nsCharClipDisplayItem* charClip = itemFrame ? 
+      nsCharClipDisplayItem::CheckCast(item) : nsnull;
+    if (charClip && GetSelfOrNearestBlock(itemFrame) == mBlock) {
+      nsRect rect = itemFrame->GetScrollableOverflowRect() +
+                    itemFrame->GetOffsetTo(mBlock);
+      if (mLeft.IsNeeded() && rect.x < aInsideMarkersArea.x) {
+        charClip->mLeftEdge = aInsideMarkersArea.x - rect.x;
+      }
+      if (mRight.IsNeeded() && rect.XMost() > aInsideMarkersArea.XMost()) {
+        charClip->mRightEdge = rect.XMost() - aInsideMarkersArea.XMost();
+      }
+    }
+
+    saved.AppendToTop(item);
+  }
+  aList->AppendToTop(&saved);
+}
+
+/* static */ bool
+TextOverflow::CanHaveTextOverflow(nsDisplayListBuilder* aBuilder,
+                                  nsIFrame*             aBlockFrame)
+{
+  const nsStyleTextReset* style = aBlockFrame->GetStyleTextReset();
+  // Nothing to do for text-overflow:clip or if 'overflow-x:visible'
+  // or if we're just building items for event processing.
+  if ((style->mTextOverflow.mType == NS_STYLE_TEXT_OVERFLOW_CLIP) ||
+      IsHorizontalOverflowVisible(aBlockFrame) ||
+      aBuilder->IsForEventDelivery()) {
+    return false;
+  }
+
+  // Inhibit the markers if a descendant content owns the caret.
+  nsRefPtr<nsCaret> caret = aBlockFrame->PresContext()->PresShell()->GetCaret();
+  PRBool visible = PR_FALSE;
+  if (caret && NS_SUCCEEDED(caret->GetCaretVisible(&visible)) && visible) {
+    nsCOMPtr<nsISelection> domSelection = caret->GetCaretDOMSelection();
+    if (domSelection) {
+      nsCOMPtr<nsIDOMNode> node;
+      domSelection->GetFocusNode(getter_AddRefs(node));
+      nsCOMPtr<nsIContent> content = do_QueryInterface(node);
+      if (content && nsContentUtils::ContentIsDescendantOf(content,
+                       aBlockFrame->GetContent())) {
+        return false;
+      }
+    }
+  }
+  return true;
+}
+
+void
+TextOverflow::CreateMarkers(const nsLineBox* aLine,
+                            bool             aCreateLeft,
+                            bool             aCreateRight,
+                            const nsRect&    aInsideMarkersArea) const
+{
+  if (aCreateLeft) {
+    nsRect markerRect = nsRect(aInsideMarkersArea.x - mLeft.mWidth,
+                               aLine->mBounds.y,
+                               mLeft.mWidth, aLine->mBounds.height);
+    markerRect += mBuilder->ToReferenceFrame(mBlock);
+    nsDisplayItem* marker = new (mBuilder)
+      nsDisplayTextOverflowMarker(mBuilder, mBlock, markerRect,
+                                  aLine->GetAscent(), mLeft.mMarkerString);
+    if (marker) {
+      marker = ClipMarker(mBuilder, mBlock, marker,
+                          mContentArea + mBuilder->ToReferenceFrame(mBlock),
+                          &markerRect);
+    }
+    mMarkerList->AppendNewToTop(marker);
+  }
+
+  if (aCreateRight) {
+    nsRect markerRect = nsRect(aInsideMarkersArea.XMost(),
+                               aLine->mBounds.y,
+                               mRight.mWidth, aLine->mBounds.height);
+    markerRect += mBuilder->ToReferenceFrame(mBlock);
+    nsDisplayItem* marker = new (mBuilder)
+      nsDisplayTextOverflowMarker(mBuilder, mBlock, markerRect,
+                                  aLine->GetAscent(), mRight.mMarkerString);
+    if (marker) {
+      marker = ClipMarker(mBuilder, mBlock, marker,
+                          mContentArea + mBuilder->ToReferenceFrame(mBlock),
+                          &markerRect);
+    }
+    mMarkerList->AppendNewToTop(marker);
+  }
+}
+
+void
+TextOverflow::Marker::SetupString(nsIFrame* aFrame)
+{
+  if (mInitialized) {
+    return;
+  }
+  nsRefPtr<nsRenderingContext> rc =
+    aFrame->PresContext()->PresShell()->GetReferenceRenderingContext();
+  nsLayoutUtils::SetFontFromStyle(rc, aFrame->GetStyleContext());
+
+  mMarkerString = mStyle->mType == NS_STYLE_TEXT_OVERFLOW_ELLIPSIS ?
+                    GetEllipsis(aFrame) : mStyle->mString;
+  mWidth = nsLayoutUtils::GetStringWidth(aFrame, rc, mMarkerString.get(),
+                                         mMarkerString.Length());
+  mInitialized = true;
+}
+
+}  // namespace css
+}  // namespace mozilla
new file mode 100644
--- /dev/null
+++ b/layout/generic/TextOverflow.h
@@ -0,0 +1,228 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set shiftwidth=2 tabstop=8 autoindent cindent expandtab: */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is an implementation of CSS3 text-overflow.
+ *
+ * The Initial Developer of the Original Code is the Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Mats Palmgren <matspal@gmail.com> (original author)
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef TextOverflow_h_
+#define TextOverflow_h_
+
+#include "nsDisplayList.h"
+#include "nsLineBox.h"
+#include "nsStyleStruct.h"
+#include "nsTHashtable.h"
+
+namespace mozilla {
+namespace css {
+
+/**
+ * A class for rendering CSS3 text-overflow.
+ * Usage:
+ *  1. allocate an object using WillProcessLines
+ *  2. then call ProcessLine for each line you are building display lists for
+ *  3. finally call DidProcessLines
+ */
+class TextOverflow {
+ public:
+  /**
+   * Allocate an object for text-overflow processing.
+   * @return nsnull if no processing is necessary.  The caller owns the object.
+   */
+  static TextOverflow* WillProcessLines(nsDisplayListBuilder*   aBuilder,
+                                        const nsDisplayListSet& aLists,
+                                        nsIFrame*               aBlockFrame);
+  /**
+   * Analyze the display lists for text overflow and what kind of item is at
+   * the content edges.  Add display items for text-overflow markers as needed
+   * and remove or clip items that would overlap a marker.
+   */
+  void ProcessLine(const nsDisplayListSet& aLists, nsLineBox* aLine);
+
+  /**
+   * Do final processing, currently just adds a dummy item for scroll frames
+   * to make IsVaryingRelativeToMovingFrame() true for the entire area.
+   */
+  void DidProcessLines();
+
+  /**
+   * @return true if aBlockFrame needs analysis for text overflow.
+   */
+  static bool CanHaveTextOverflow(nsDisplayListBuilder* aBuilder,
+                                  nsIFrame*             aBlockFrame);
+
+  typedef nsTHashtable<nsPtrHashKey<nsIFrame> > FrameHashtable;
+
+ protected:
+  TextOverflow() {}
+
+  struct AlignmentEdges {
+    AlignmentEdges() : mAssigned(false) {}
+    void Accumulate(const nsRect& aRect) {
+      if (NS_LIKELY(mAssigned)) {
+        x = NS_MIN(x, aRect.X());
+        xmost = NS_MAX(xmost, aRect.XMost());
+      } else {
+        x = aRect.X();
+        xmost = aRect.XMost();
+        mAssigned = true;
+      }
+    }
+    nscoord Width() { return xmost - x; }
+    nscoord x;
+    nscoord xmost;
+    bool mAssigned;
+  };
+
+  /**
+   * 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
+   * 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
+   */
+  void ExamineLineFrames(nsLineBox*      aLine,
+                         FrameHashtable* aFramesToHide,
+                         AlignmentEdges* aAlignmentEdges);
+
+  /**
+   * LineHasOverflowingText calls this to analyze edges, both the block's
+   * content edges and the hypothetical marker edges aligned at the block edges.
+   * @param aFrame the descendant frame of mBlock that we're analyzing
+   * @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
+   */
+  void ExamineFrameSubtree(nsIFrame*       aFrame,
+                           const nsRect&   aContentArea,
+                           const nsRect&   aInsideMarkersArea,
+                           FrameHashtable* aFramesToHide,
+                           AlignmentEdges* aAlignmentEdges);
+
+  /**
+   * ExamineFrameSubtree calls this to analyze a frame against the hypothetical
+   * marker edges (aInsideMarkersArea) for text frames and atomic inline-level
+   * elements.  A text frame adds its extent inside aInsideMarkersArea where
+   * grapheme clusters are fully visible.  An atomic adds its border box if
+   * it's fully inside aInsideMarkersArea, otherwise the frame is added to
+   * aFramesToHide.
+   * @param aFrame the descendant frame of mBlock that we're analyzing
+   * @param aFrameType aFrame's frame type
+   * @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
+   *                       inside aInsideMarkersArea
+   */
+  void AnalyzeMarkerEdges(nsIFrame*       aFrame,
+                          const nsIAtom*  aFrameType,
+                          const nsRect&   aInsideMarkersArea,
+                          FrameHashtable* aFramesToHide,
+                          AlignmentEdges* aAlignmentEdges);
+
+  /**
+   * Clip or remove items given the final marker edges. ("clip" here just means
+   * assigning mLeftEdge/mRightEdge for any nsCharClipDisplayItem that needs it,
+   * see nsDisplayList.h for a description of that item).
+   * @param aFramesToHide remove display items for these frames
+   * @param aInsideMarkersArea is the area inside the markers
+   */
+  void PruneDisplayListContents(nsDisplayList*        aList,
+                                const FrameHashtable& aFramesToHide,
+                                const nsRect&         aInsideMarkersArea);
+
+  /**
+   * ProcessLine calls this to create display items for the markers and insert
+   * them into a display list for the block.
+   * @param aLine the line we're processing
+   * @param aCreateLeft if true, create a marker on the left side
+   * @param aCreateRight if true, create a marker on the right side
+   * @param aInsideMarkersArea is the area inside the markers
+   */
+  void CreateMarkers(const nsLineBox* aLine,
+                     bool             aCreateLeft,
+                     bool             aCreateRight,
+                     const nsRect&    aInsideMarkersArea) const;
+
+  nsRect                 mContentArea;
+  nsDisplayListBuilder*  mBuilder;
+  nsIFrame*              mBlock;
+  nsDisplayList*         mMarkerList;
+  bool                   mBlockIsRTL;
+  bool                   mCanHaveHorizontalScrollbar;
+
+  class Marker {
+  public:
+    void Init(const nsStyleTextOverflow& aStyle) {
+      mInitialized = false;
+      mWidth = 0;
+      mStyle = &aStyle;
+    }
+
+    /**
+     * Setup the marker string and calculate its size, if not done already.
+     */
+    void SetupString(nsIFrame* aFrame);
+
+    bool IsNeeded() const {
+      return mHasOverflow;
+    }
+    void Reset() {
+      mHasOverflow = false;
+    }
+
+    // The intrinsic width of the marker string.
+    nscoord                        mWidth;
+    // The marker text.
+    nsString                       mMarkerString;
+    // The style for this side.
+    const nsStyleTextOverflow*     mStyle;
+    // True if there is visible overflowing inline content on this side.
+    bool                           mHasOverflow;
+    // True if mMarkerString and mWidth have been setup from style.
+    bool                           mInitialized;
+  };
+
+  Marker mLeft;  // the horizontal left marker
+  Marker mRight; // the horizontal right marker
+};
+
+} // namespace css
+} // namespace mozilla
+
+#endif /* !defined(TextOverflow_h_) */
--- a/layout/generic/crashtests/crashtests.list
+++ b/layout/generic/crashtests/crashtests.list
@@ -355,8 +355,10 @@ load 605340.html
 load 621841-1.html
 load 645072-1.html
 load 645072-2.html
 load 646561-1.html
 load 646983-1.html
 load 647332-1.html
 load 650499-1.html
 load 660416.html
+load text-overflow-form-elements.html
+load text-overflow-iframe.html
new file mode 100644
--- /dev/null
+++ b/layout/generic/crashtests/text-overflow-form-elements.html
@@ -0,0 +1,144 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html><head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<title>text-overflow test case</title>
+<style type="text/css">
+
+.test { 
+  font: 1em bold monospace;
+  background:lightgrey;
+  color: black;
+  margin-left:400px;
+}
+
+.rtl {
+  direction:rtl;
+}
+.ltr {
+  direction:ltr;
+}
+.rlo > * {
+  unicode-bidi: bidi-override; direction: rtl;
+}
+.lro > * {
+  unicode-bidi: bidi-override; direction: ltr;
+}
+.b { border: 1px dashed blue; }
+.inline-block {
+  display:inline-block;
+}
+.ellipsis {
+  width:4em;
+  width:6.5ch;
+  text-overflow: ellipsis; 
+  -o-text-overflow: ellipsis; 
+  overflow:hidden;
+}
+</style>
+<script>
+var twoEyes = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAGAAAAAYCAYAAAFy7sgCAAAGsUlEQVRo3u2ZbWwcZxHHf3s%2B7LNbO3ZjXBtowprGODRX0qpNQCjmJKuVKhMl1P2AkCwhFOIKkCBSm9IXavGFKAixIAECwkmWo5MrhRI3Ub40IEwQgp6aIDg3Cd6eEqyIHEteah%2B1E69vhw%2BZtTaX8704ZzkKjHS6271nZ56ZZ%2BY%2F%2F%2BdZKF%2FCwYshx3EkkggLsD1v4FQkEZZYLCbAKyG9%2Ba9EIsG6hnUAf8x74K3aUC3j4%2BM54HcsR2oAIomwZOezkv%2FnSHpYNh%2BNCmAE7xv94zvFdd1bHsjMZmQkPSxAJP%2B%2FfuBLwK54PC7JZFKAVJmzXLBt2w%2FMvcDLwIb8QS8CeJ4nkURYIomw7J%2FYJ8BvSiiXptGGxWds2%2Fa9%2Bnaxh%2BYAD%2Bgt04NDgABTpQY2cvvSFLzw86gWeBVwC8SzlOSv2YeBPfmDBoBHgKmR9LBEEmHZfDTqGykqfkUE0nA78BzQGfSgUeP3wNeTXwXg7MwZDhw4UHL6ra2ti79%2FOvljgG8AZ4H64Lhm4MvAocxsRppGG%2FxcXihlwLIs6R%2FfKV2HO%2F26uA94pdDYUKUZUU7W1RQYXA98Gnhaf5%2FXWX0HeAHYoQonqa4sZSOsSWMCWeC9Yko%2BCQwBe4E6oNc0Tc91XTl1%2BaTsn9gnI%2Blhyc5nZWxsrBIkKSbl2tiic3tW53YDEwOKaoFBrcOfqKee53lG9xsPMjV784r%2F4lO%2FpPvyJ9iyZcuvFSaXK5XYeAZ4CDgGvB3MS4B54LQuWYPeuy4iRFsevsXqpuYoqVQKIH2bK1CuDQNo11o4XUzh%2FcDWYIe1LEtyuZx4niee54njOGKapgfsqlL%2Bl2OjEXg8nxrc1dJ0h3hbtL%2BGCtz7KPBF4CuBe9uB15VafE8hr9qylI3HgG8C2%2FK7VyHZoJj7MrBRm30qFotJMpkU27YlHo%2F7Ha5a%2BV%2FKRkSJ4KuKRLVLKapTjB1SzAVIjY2NSXY%2BKyPpYdk%2FsU9OXT4pruv6BdZbBQfKsVGnvWlIe1VB6VQO8JxC1vZYLCbZ%2BaxsPhpdZDyRRFhG0sPiOE6ldKBg2lRg4xF1YCDIIIKN7DGgD3gH%2BBXwejKZfPrs2tPs%2FvPN2bKuYR1nd7xLKBSSJeqoXKnERjPwNWAG%2BLn2rZuM%2B4Tpml6vaWlp4eLcxVusZq5lCgVgOVKJjRqdX86ffL4D5wIoZACnTpw4wRMdT96i%2FImOJxERAs4uVyqxUacF%2FPdiCj%2BjdRBRGFtwXVdG0sPSdbhTmkYbpH98p2RmM2JZlig1vl0GWo4NQ%2Fn%2Bs5pKRXfwjweaxy7TND3HcRZbfC6X8xVPVQlGy7WxVWlO5XRXFXm6EZmrQuSXYyPE3SiVoEhE6Wyr0u2rumO6zv%2B21AFdQAswC1wCMuUCXCmyWQus103Qg8qlDO0lxwOb%2Fl4FiK3AB3VS%2FuKKLtK%2FgbeAnwG%2FvUODuRw%2FFrR0H1UC75fwu8oJ%2FhFsW5VIG%2FBUgEIN6Y65O4AHu4Ap0zQ9y7LEcZyb9lRBUHQcRyzL8unZVBW5bFWAvAp%2BhDQ2g4F47dUYtlU6obXA54DnVdFLekjUGGifh4AFy7LEdV3xj3X9I66m0QZpGm2QrsOd0j%2B%2BU0bSw5KZzYjrun6HWlAd961i4FfCj0aN1Usau%2Bc1lmuXPFwvAEumUut7tQQvAb%2FXb%2FT0bCAej9cODg7yt%2Bm%2F8q2%2F7OUHZ76PnZ1k2p0mJzlykmPancbOTnL0whHs7CQfb%2B5mx2d3sH79%2BtCRI0c6FeaOr9ICrIQfLvA%2B8BGNXxi4R6HrisJVUWrxAVW2oMFf0Aczim8o3kV6enowDIPjF9%2Fk%2BMU3S3rrjzMMg56eHr%2BxP7qKFbASfojG6kpeDGs1tiW53RxwWT%2Bin5q8w4xpQK5evQpAR30H7ZH2khNvj7TTUd8BgD4rqmu1ZKX8qNeY%2BfHz4zlXDgT5E8tpCTUq7XSBC4Euv8227TV9fX1E73%2BYtvo27BmbS9cvFVTY3bSRFza9yOcf6Gfmygy7d%2B%2Fm%2FPnzF4DvrsBLhnJlJfwIKXxv1PheAE4qK6p4H9AGbNKTuhngBPBPXYRe4IemaT5kWZbR19fHNbmGnZ1k4r3U4glDR30Hm5qjbGjsImJEOHbsGHv27JFz5869o0eFq01Jq%2BmHAXwI6FFKagMTgHM7GzFDS%2BoeLSMv7zjzC9x4Y7gxFovVDAwMEI1GaWlpWSzRVCrFwYMH%2FXfxZ4AfAa8B%2F7lDaGg1%2FQgp43lfK0yqtRMuJa3ceKe5DfgYsCYAZ2ngD8CfAkzqTpW7xY%2F%2FSznyX%2FVeUb2kVmX4AAAAAElFTkSuQmCC";
+function initIMG() {
+  var img = document.getElementsByTagName('img');
+  for (i = 0; i < img.length; ++i)
+    img[i].setAttribute('src', twoEyes);
+}
+function setTextOverflow(str,quoted) {
+  var x = document.styleSheets[0];
+  var q = quoted ? '"' : '';
+  x.insertRule('.ellipsis{text-overflow:' + q + str + q +'}', x.cssRules.length);
+}
+</script>
+</head><body onload="initIMG()">
+text-overflow:"<input placeholder="type text then <ENTER>" onchange='setTextOverflow(this.value,1)'>" | <button onclick="setTextOverflow('ellipsis')">ellipsis</button> | <button onclick="setTextOverflow('clip')">clip</button> (Try "." or "" for example) <br>
+
+LTR / LTR
+<div class="test ltr">
+<span class="ellipsis b inline-block">CSS is awesome</span>
+<button class="ellipsis">CSS is awesome</button>
+<input type=button class="ellipsis" value="CSS is awesome">
+<input class="ellipsis" value="CSS is awesome">
+<input class="ellipsis" placeholder="CSS is awesome">
+<fieldset style="display:inline" class="ellipsis"><span style="position:relative;left:1em;">CSS is awesome</span></fieldset>
+<fieldset style="display:block" class="ellipsis"><span style="position:relative;left:1em;">CSS is awesome</span></fieldset>
+<legend class="ellipsis">CSS is awesome</legend>
+<textarea class="ellipsis" style="overflow:scroll;width:14em;" wrap="off">
+CSS is awesome CSS is awesome CSS is awesome
+CSS is awesome CSS is awesome CSS is awesome
+</textarea>
+<fieldset style="display:inline"><legend class="ellipsis">CSS is awesome</legend>CSS is awesome</fieldset>
+<fieldset style="display:block" class="ellipsis"><legend class="ellipsis">CSS is awesome</legend><span style="position:relative;left:1em;">CSS is awesome</span></fieldset>
+<select class="ellipsis"><option>CSS is awesome<option>CSS is awesome<option>CSS is awesome<option>CSS is awesome</select>
+<select><option>CSS is awesome<option class="ellipsis">CSS is awesome<option>CSS is awesome<option>CSS is awesome</select>
+<select size="4"><option>CSS is awesome<option class="ellipsis">CSS is awesome<option>CSS is awesome<option>CSS is awesome</select>
+<ul style="float:left"><li class="ellipsis b">CSS is awesome</ul>
+<br><br></div>
+
+RTL / LTR
+<div class="test rtl">
+<span class="ellipsis b inline-block">CSS is awesome</span>
+<button class="ellipsis">CSS is awesome</button>
+<input type=button class="ellipsis" value="CSS is awesome">
+<input class="ellipsis" value="CSS is awesome">
+<input class="ellipsis" placeholder="CSS is awesome">
+<fieldset style="display:inline" class="ellipsis"><span style="position:relative;right:1em;">CSS is awesome</span></fieldset>
+<fieldset style="display:block" class="ellipsis"><span style="position:relative;right:1em;">CSS is awesome</span></fieldset>
+<legend class="ellipsis">CSS is awesome</legend>
+<textarea class="ellipsis" style="overflow:scroll;width:14em;" wrap="off">
+CSS is awesome CSS is awesome CSS is awesome
+CSS is awesome CSS is awesome CSS is awesome
+</textarea>
+<fieldset style="display:inline"><legend class="ellipsis">CSS is awesome</legend>CSS is awesome</fieldset>
+<fieldset style="display:block" class="ellipsis"><legend class="ellipsis">CSS is awesome</legend><span style="position:relative;right:1em;">CSS is awesome</span></fieldset>
+<select class="ellipsis"><option>CSS is awesome<option>CSS is awesome<option>CSS is awesome<option>CSS is awesome</select>
+<select><option>CSS is awesome<option class="ellipsis">CSS is awesome<option>CSS is awesome<option>CSS is awesome</select>
+<select size="4"><option>CSS is awesome<option class="ellipsis">CSS is awesome<option>CSS is awesome<option>CSS is awesome</select>
+<ul style="float:left"><li class="ellipsis b">CSS is awesome</ul>
+<br><br></div>
+
+LTR / RTL
+<div class="test ltr rlo">
+<span class="ellipsis b inline-block">CSS is awesome</span>
+<button class="ellipsis">CSS is awesome</button>
+<input type=button class="ellipsis" value="CSS is awesome">
+<input class="ellipsis" value="CSS is awesome">
+<input class="ellipsis" placeholder="CSS is awesome">
+<fieldset style="display:inline" class="ellipsis"><span style="position:relative;right:1em;">CSS is awesome</span></fieldset>
+<fieldset style="display:block" class="ellipsis"><span style="position:relative;right:1em;">CSS is awesome</span></fieldset>
+<legend class="ellipsis">CSS is awesome</legend>
+<textarea class="ellipsis" style="overflow:scroll;width:14em;" wrap="off">
+CSS is awesome CSS is awesome CSS is awesome
+CSS is awesome CSS is awesome CSS is awesome
+</textarea>
+<fieldset style="display:inline"><legend class="ellipsis">CSS is awesome</legend>CSS is awesome</fieldset>
+<fieldset style="display:block" class="ellipsis"><legend class="ellipsis">CSS is awesome</legend><span style="position:relative;right:1em;">CSS is awesome</span></fieldset>
+<select class="ellipsis"><option>CSS is awesome<option>CSS is awesome<option>CSS is awesome<option>CSS is awesome</select>
+<select><option>CSS is awesome<option class="ellipsis">CSS is awesome<option>CSS is awesome<option>CSS is awesome</select>
+<select size="4"><option>CSS is awesome<option class="ellipsis">CSS is awesome<option>CSS is awesome<option>CSS is awesome</select>
+<ul style="float:left"><li class="ellipsis b">CSS is awesome</ul>
+<br><br></div>
+
+RTL / RTL
+<div class="test rtl rlo">
+<span class="ellipsis b inline-block">CSS is awesome</span>
+<button class="ellipsis">CSS is awesome</button>
+<input type=button class="ellipsis" value="CSS is awesome">
+<input class="ellipsis" value="CSS is awesome">
+<input class="ellipsis" placeholder="CSS is awesome">
+<fieldset style="display:inline" class="ellipsis"><span style="position:relative;right:1em;">CSS is awesome</span></fieldset>
+<fieldset style="display:block" class="ellipsis"><span style="position:relative;right:1em;">CSS is awesome</span></fieldset>
+<legend class="ellipsis">CSS is awesome</legend>
+<textarea class="ellipsis" style="overflow:scroll;width:14em;" wrap="off">
+CSS is awesome CSS is awesome CSS is awesome
+CSS is awesome CSS is awesome CSS is awesome
+</textarea>
+<fieldset style="display:inline"><legend class="ellipsis">CSS is awesome</legend>CSS is awesome</fieldset>
+<fieldset style="display:block" class="ellipsis"><legend class="ellipsis">CSS is awesome</legend><span style="position:relative;right:1em;">CSS is awesome</span></fieldset>
+<select class="ellipsis"><option>CSS is awesome<option>CSS is awesome<option>CSS is awesome<option>CSS is awesome</select>
+<select><option>CSS is awesome<option class="ellipsis">CSS is awesome<option>CSS is awesome<option>CSS is awesome</select>
+<select size="4"><option>CSS is awesome<option class="ellipsis">CSS is awesome<option>CSS is awesome<option>CSS is awesome</select>
+<ul style="float:left"><li class="ellipsis b">CSS is awesome</ul>
+<br><br></div>
+
+
+
+</body></html>
new file mode 100644
--- /dev/null
+++ b/layout/generic/crashtests/text-overflow-iframe.html
@@ -0,0 +1,115 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html><head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<title>text-overflow: Test 12</title>
+<style type="text/css">
+
+.test { 
+  border: thin dashed black; 
+  overflow: hidden; 
+  white-space: nowrap;
+  -o-text-overflow: ellipsis;
+  text-overflow: ellipsis;
+  font: 1em bold monospace;
+  background:lime;
+  color: black;
+  margin-left:400px;
+  height: 12em;
+  text-shadow: #6374AB 5px -12px 2px;
+}
+
+body {
+  width:800px;
+}
+
+img { width: 50px; height: 50px;   outline:5px dotted yellow; }
+span {
+  font-size:16px;
+  background:pink; 
+  border: 5px dashed blue;
+  padding: 0 25px;
+  text-decoration: underline overline line-through;
+  color:brown;
+  text-shadow: none;
+}
+i {
+  display:inline-block;
+  height: 50px;
+  width: 5em;
+  background: blue;
+  outline:5px dotted yellow;
+  text-shadow: none;
+}
+u {
+ padding-left:140px;
+}
+v {
+ padding-right:140px;
+}
+.rtl {
+  direction:rtl;
+}
+.rlo span {
+  unicode-bidi: bidi-override; direction: rtl;
+}
+.lro span {
+  unicode-bidi: bidi-override; direction: ltr;
+}
+.h {display:none}
+iframe {
+  width: 100px;
+  height: 50px;
+}
+</style>
+<script>
+var c = "data:text/html,<style>body {white-space: nowrap;overflow:hidden;-o-text-overflow: ellipsis;text-overflow: ellipsis;}</style><body bgcolor='magenta'>CSS is awesome"
+function initIFRAME() {
+  var f = document.getElementsByTagName('iframe');
+  for (i = 0; i < f.length; ++i) {
+    f[i].setAttribute('src', c);
+  }
+  setTimeout(function(){document.body.style.width='500px'},0);
+}
+function setTextOverflow(str,quoted) {
+  var x = document.styleSheets[0];
+  var q = quoted ? '"' : '';
+  x.insertRule('.test{text-overflow:' + q + str + q +'}', x.cssRules.length);
+}
+</script>
+</head><body onload="initIFRAME()">
+text-overflow:"<input placeholder="type text then <ENTER>" onchange='setTextOverflow(this.value,1)'>" | <button onclick="setTextOverflow('ellipsis')">ellipsis</button> | <button onclick="setTextOverflow('clip')">clip</button> (Try "." or "" for example) <br>
+
+LTR / LTR
+<div class="test">
+<span><iframe></iframe>CSS is awesome CSS<i>overflowing-inline-block</i><u> is awesome</u></span><br>
+<span>CSS is awe<iframe></iframe>some CSS is awesome <i></i></span><br>
+<span>C SS is awesome<button>BUTTON</button> CSS is <iframe></iframe>awesom e </span><br>
+<span>C&shy;SS is awesome CSS is awesom&shy;e <button>BUTTON</button></span><br>
+<br><br></div>
+
+RTL / LTR
+<div class="test rtl">
+<span><iframe></iframe><v>CSS is awesome CSS</v><i>overflowing-inline-block</i> is awesome </span><br>
+<span>CSS is awe<iframe></iframe>some CSS is awesome <i></i></span><br>
+<span>C SS is awesome<button>BUTTON</button> CSS is <iframe></iframe>awesom e </span><br>
+<span>C&shy;SS is awesome CSS is awesom&shy;e <button>BUTTON</button></span><br>
+<br><br></div>
+
+
+LTR / RTL
+<div class="test rlo">
+<span><iframe></iframe>CSS is awesome CSS<i>overflowing-inline-block</i> is awesome </span><br>
+<span>CSS is awe<iframe></iframe>some CSS is awesome <i></i></span><br>
+<span>C SS is awesome<button>BUTTON</button> CSS is <iframe></iframe>awesom e </span><br>
+<span><button>BUTTON</button>C&shy;SS is awesome CSS is awesom&shy;e </span><br>
+<br><br></div>
+
+RTL / RTL
+<div class="test rtl rlo">
+<span><iframe></iframe>CSS is awesome CSS<i>overflowing-inline-block</i> is awesome </span><br>
+<span>CSS is awe<iframe></iframe>some CSS is awesome <i></i></span><br>
+<span>C SS is awesome<button>BUTTON</button> CSS is <iframe></iframe>awesom e </span><br>
+<span><button>BUTTON</button>C&shy;SS is awesome CSS is awesom&shy;e </span><br>
+<br><br></div>
+
+</body></html>
--- a/layout/generic/nsBlockFrame.cpp
+++ b/layout/generic/nsBlockFrame.cpp
@@ -84,16 +84,17 @@
 #include "nsLayoutUtils.h"
 #include "nsDisplayList.h"
 #include "nsContentErrors.h"
 #include "nsCSSAnonBoxes.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsCSSRendering.h"
 #include "FrameLayerBuilder.h"
 #include "nsRenderingContext.h"
+#include "TextOverflow.h"
 #include "mozilla/Util.h" // for DebugOnly
 
 #ifdef IBMBIDI
 #include "nsBidiPresUtils.h"
 #endif // IBMBIDI
 
 #include "nsIDOMHTMLBodyElement.h"
 #include "nsIDOMHTMLHtmlElement.h"
@@ -102,16 +103,17 @@ static const int MIN_LINES_NEEDING_CURSO
 
 static const PRUnichar kDiscCharacter = 0x2022;
 static const PRUnichar kCircleCharacter = 0x25e6;
 static const PRUnichar kSquareCharacter = 0x25aa;
 
 #define DISABLE_FLOAT_BREAKING_IN_COLUMNS
 
 using namespace mozilla;
+using namespace mozilla::css;
 
 #ifdef DEBUG
 #include "nsPrintfCString.h"
 #include "nsBlockDebugFlags.h"
 
 PRBool nsBlockFrame::gLamePaintMetrics;
 PRBool nsBlockFrame::gLameReflowMetrics;
 PRBool nsBlockFrame::gNoisy;
@@ -6067,36 +6069,40 @@ nsBlockFrame::IsVisibleInSelection(nsISe
 
   nsCOMPtr<nsIDOMNode> node(do_QueryInterface(mContent));
   PRBool visible;
   nsresult rv = aSelection->ContainsNode(node, PR_TRUE, &visible);
   return NS_SUCCEEDED(rv) && visible;
 }
 
 /* virtual */ void
-nsBlockFrame::PaintTextDecorationLine(gfxContext* aCtx, 
-                                      const nsPoint& aPt,
-                                      nsLineBox* aLine,
-                                      nscolor aColor, 
-                                      PRUint8 aStyle,
-                                      gfxFloat aOffset, 
-                                      gfxFloat aAscent, 
-                                      gfxFloat aSize,
-                                      const PRUint8 aDecoration) 
+nsBlockFrame::PaintTextDecorationLine(
+                gfxContext* aCtx, 
+                const nsPoint& aPt,
+                nsLineBox* aLine,
+                nscolor aColor, 
+                PRUint8 aStyle,
+                gfxFloat aOffset, 
+                gfxFloat aAscent, 
+                gfxFloat aSize,
+                const nsCharClipDisplayItem::ClipEdges& aClipEdges,
+                const PRUint8 aDecoration) 
 {
   NS_ASSERTION(!aLine->IsBlock(), "Why did we ask for decorations on a block?");
 
   nscoord start = aLine->mBounds.x;
   nscoord width = aLine->mBounds.width;
 
   AdjustForTextIndent(aLine, start, width);
-      
+  nscoord x = start + aPt.x;
+  aClipEdges.Intersect(&x, &width);
+
   // Only paint if we have a positive width
   if (width > 0) {
-    gfxPoint pt(PresContext()->AppUnitsToGfxUnits(start + aPt.x),
+    gfxPoint pt(PresContext()->AppUnitsToGfxUnits(x),
                 PresContext()->AppUnitsToGfxUnits(aLine->mBounds.y + aPt.y));
     gfxSize size(PresContext()->AppUnitsToGfxUnits(width), aSize);
     nsCSSRendering::PaintDecorationLine(
       aCtx, aColor, pt, size,
       PresContext()->AppUnitsToGfxUnits(aLine->GetAscent()),
       aOffset, aDecoration, aStyle);
   }
 }
@@ -6146,17 +6152,17 @@ static void DebugOutputDrawLine(PRInt32 
   }
 }
 #endif
 
 static nsresult
 DisplayLine(nsDisplayListBuilder* aBuilder, const nsRect& aLineArea,
             const nsRect& aDirtyRect, nsBlockFrame::line_iterator& aLine,
             PRInt32 aDepth, PRInt32& aDrawnLines, const nsDisplayListSet& aLists,
-            nsBlockFrame* aFrame) {
+            nsBlockFrame* aFrame, TextOverflow* aTextOverflow) {
   // If the line's combined area (which includes child frames that
   // stick outside of the line's bounding box or our bounding box)
   // intersects the dirty rect then paint the line.
   PRBool intersect = aLineArea.Intersects(aDirtyRect);
 #ifdef DEBUG
   if (nsBlockFrame::gLamePaintMetrics) {
     aDrawnLines++;
   }
@@ -6164,44 +6170,53 @@ DisplayLine(nsDisplayListBuilder* aBuild
 #endif
   // The line might contain a placeholder for a visible out-of-flow, in which
   // case we need to descend into it. If there is such a placeholder, we will
   // have NS_FRAME_FORCE_DISPLAY_LIST_DESCEND_INTO set.
   // In particular, we really want to check ShouldDescendIntoFrame()
   // on all the frames on the line, but that might be expensive.  So
   // we approximate it by checking it on aFrame; if it's true for any
   // frame in the line, it's also true for aFrame.
-  if (!intersect && !aBuilder->ShouldDescendIntoFrame(aFrame))
+  PRBool lineInline = aLine->IsInline();
+  PRBool lineMayHaveTextOverflow = aTextOverflow && lineInline;
+  if (!intersect && !aBuilder->ShouldDescendIntoFrame(aFrame) &&
+      !lineMayHaveTextOverflow)
     return NS_OK;
 
+  nsDisplayListCollection collection;
   nsresult rv;
   nsDisplayList aboveTextDecorations;
-  PRBool lineInline = aLine->IsInline();
   if (lineInline) {
     // Display the text-decoration for the hypothetical anonymous inline box
     // that wraps these inlines
-    rv = aFrame->DisplayTextDecorations(aBuilder, aLists.Content(),
+    rv = aFrame->DisplayTextDecorations(aBuilder, collection.Content(),
                                         &aboveTextDecorations, aLine);
     NS_ENSURE_SUCCESS(rv, rv);
   }
 
   // Block-level child backgrounds go on the blockBorderBackgrounds list ...
   // Inline-level child backgrounds go on the regular child content list.
-  nsDisplayListSet childLists(aLists,
-      lineInline ? aLists.Content() : aLists.BlockBorderBackgrounds());
+  nsDisplayListSet childLists(collection,
+    lineInline ? collection.Content() : collection.BlockBorderBackgrounds());
   nsIFrame* kid = aLine->mFirstChild;
   PRInt32 n = aLine->GetChildCount();
   while (--n >= 0) {
     rv = aFrame->BuildDisplayListForChild(aBuilder, kid, aDirtyRect, childLists,
                                           lineInline ? nsIFrame::DISPLAY_CHILD_INLINE : 0);
     NS_ENSURE_SUCCESS(rv, rv);
     kid = kid->GetNextSibling();
   }
   
-  aLists.Content()->AppendToTop(&aboveTextDecorations);
+  collection.Content()->AppendToTop(&aboveTextDecorations);
+
+  if (lineMayHaveTextOverflow) {
+    aTextOverflow->ProcessLine(collection, aLine.get());
+  }
+
+  collection.MoveTo(aLists);
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsBlockFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                                const nsRect&           aDirtyRect,
                                const nsDisplayListSet& aLists)
 {
@@ -6233,16 +6248,20 @@ nsBlockFrame::BuildDisplayList(nsDisplay
     for (nsIFrame* f = mFloats.FirstChild(); f; f = f->GetNextSibling()) {
       if (f->GetStateBits() & NS_FRAME_IS_PUSHED_FLOAT)
          BuildDisplayListForChild(aBuilder, f, aDirtyRect, aLists);
     }
   }
 
   aBuilder->MarkFramesForDisplayList(this, mFloats, aDirtyRect);
 
+  // Prepare for text-overflow processing.
+  nsAutoPtr<TextOverflow> textOverflow(
+    TextOverflow::WillProcessLines(aBuilder, aLists, this));
+
   // Don't use the line cursor if we might have a descendant placeholder ...
   // it might skip lines that contain placeholders but don't themselves
   // intersect with the dirty area.
   // In particular, we really want to check ShouldDescendIntoFrame()
   // on all our child frames, but that might be expensive.  So we
   // approximate it by checking it on |this|; if it's true for any
   // frame in our child list, it's also true for |this|.
   nsLineBox* cursor = aBuilder->ShouldDescendIntoFrame(this) ?
@@ -6257,32 +6276,32 @@ nsBlockFrame::BuildDisplayList(nsDisplay
       nsRect lineArea = line->GetVisualOverflowArea();
       if (!lineArea.IsEmpty()) {
         // Because we have a cursor, the combinedArea.ys are non-decreasing.
         // Once we've passed aDirtyRect.YMost(), we can never see it again.
         if (lineArea.y >= aDirtyRect.YMost()) {
           break;
         }
         rv = DisplayLine(aBuilder, lineArea, aDirtyRect, line, depth, drawnLines,
-                         aLists, this);
+                         aLists, this, textOverflow);
         if (NS_FAILED(rv))
           break;
       }
     }
   } else {
     PRBool nonDecreasingYs = PR_TRUE;
     PRInt32 lineCount = 0;
     nscoord lastY = PR_INT32_MIN;
     nscoord lastYMost = PR_INT32_MIN;
     for (line_iterator line = begin_lines();
          line != line_end;
          ++line) {
       nsRect lineArea = line->GetVisualOverflowArea();
       rv = DisplayLine(aBuilder, lineArea, aDirtyRect, line, depth, drawnLines,
-                       aLists, this);
+                       aLists, this, textOverflow);
       if (NS_FAILED(rv))
         break;
       if (!lineArea.IsEmpty()) {
         if (lineArea.y < lastY
             || lineArea.YMost() < lastYMost) {
           nonDecreasingYs = PR_FALSE;
         }
         lastY = lineArea.y;
@@ -6291,16 +6310,21 @@ nsBlockFrame::BuildDisplayList(nsDisplay
       lineCount++;
     }
 
     if (NS_SUCCEEDED(rv) && nonDecreasingYs && lineCount >= MIN_LINES_NEEDING_CURSOR) {
       SetupLineCursor();
     }
   }
 
+  // Finalize text-overflow processing.
+  if (textOverflow) {
+    textOverflow->DidProcessLines();
+  }
+
   if (NS_SUCCEEDED(rv) && (nsnull != mBullet) && HaveOutsideBullet()) {
     // Display outside bullets manually
     rv = BuildDisplayListForChild(aBuilder, mBullet, aDirtyRect, aLists);
   }
 
 #ifdef DEBUG
   if (gLamePaintMetrics) {
     PRTime end = PR_Now();
--- a/layout/generic/nsBlockFrame.h
+++ b/layout/generic/nsBlockFrame.h
@@ -367,16 +367,17 @@ protected:
   virtual void PaintTextDecorationLine(gfxContext* aCtx,
                                        const nsPoint& aPt,
                                        nsLineBox* aLine,
                                        nscolor aColor,
                                        PRUint8 aStyle,
                                        gfxFloat aOffset,
                                        gfxFloat aAscent,
                                        gfxFloat aSize,
+                                       const nsCharClipDisplayItem::ClipEdges& aClipEdges,
                                        const PRUint8 aDecoration);
 
   virtual void AdjustForTextIndent(const nsLineBox* aLine,
                                    nscoord& start,
                                    nscoord& width);
 
   void TryAllLines(nsLineList::iterator* aIterator,
                    nsLineList::iterator* aStartIterator,
--- a/layout/generic/nsHTMLContainerFrame.cpp
+++ b/layout/generic/nsHTMLContainerFrame.cpp
@@ -63,22 +63,22 @@
 #include "gfxFont.h"
 #include "nsCSSFrameConstructor.h"
 #include "nsDisplayList.h"
 #include "nsBlockFrame.h"
 #include "nsLineBox.h"
 #include "nsDisplayList.h"
 #include "nsCSSRendering.h"
 
-class nsDisplayTextDecoration : public nsDisplayItem {
+class nsDisplayTextDecoration : public nsCharClipDisplayItem {
 public:
   nsDisplayTextDecoration(nsDisplayListBuilder* aBuilder,
                           nsHTMLContainerFrame* aFrame, PRUint8 aDecoration,
                           nscolor aColor, PRUint8 aStyle, nsLineBox* aLine)
-    : nsDisplayItem(aBuilder, aFrame), mLine(aLine), mColor(aColor),
+    : nsCharClipDisplayItem(aBuilder, aFrame), mLine(aLine), mColor(aColor),
       mDecoration(aDecoration), mStyle(aStyle) {
     MOZ_COUNT_CTOR(nsDisplayTextDecoration);
   }
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayTextDecoration() {
     MOZ_COUNT_DTOR(nsDisplayTextDecoration);
   }
 #endif
@@ -129,42 +129,42 @@ nsDisplayTextDecoration::Paint(nsDisplay
   }
 
   nsPoint pt = ToReferenceFrame();
   nsHTMLContainerFrame* f = static_cast<nsHTMLContainerFrame*>(mFrame);
   if (mDecoration == NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE) {
     gfxFloat underlineOffset = fontGroup->GetUnderlineOffset();
     f->PaintTextDecorationLine(aCtx->ThebesContext(), pt, mLine, mColor,
                                mStyle, underlineOffset, ascent,
-                               metrics.underlineSize, mDecoration);
+                               metrics.underlineSize, Edges(), mDecoration);
   } else if (mDecoration == NS_STYLE_TEXT_DECORATION_LINE_OVERLINE) {
     f->PaintTextDecorationLine(aCtx->ThebesContext(), pt, mLine, mColor,
                                mStyle, metrics.maxAscent, ascent,
-                               metrics.underlineSize, mDecoration);
+                               metrics.underlineSize, Edges(), mDecoration);
   } else {
     f->PaintTextDecorationLine(aCtx->ThebesContext(), pt, mLine, mColor,
-                               mStyle, metrics.strikeoutOffset,
-                               ascent, metrics.strikeoutSize, mDecoration);
+                               mStyle, metrics.strikeoutOffset, ascent,
+                               metrics.strikeoutSize, Edges(), mDecoration);
   }
 }
 
 nsRect
 nsDisplayTextDecoration::GetBounds(nsDisplayListBuilder* aBuilder)
 {
   return mFrame->GetVisualOverflowRect() + ToReferenceFrame();
 }
 
-class nsDisplayTextShadow : public nsDisplayItem {
+class nsDisplayTextShadow : public nsCharClipDisplayItem {
 public:
   nsDisplayTextShadow(nsDisplayListBuilder* aBuilder,
                       nsHTMLContainerFrame* aFrame,
                       const PRUint8 aDecoration, PRUint8 aUnderlineStyle,
                       PRUint8 aOverlineStyle, PRUint8 aStrikeThroughStyle,
                       nsLineBox* aLine)
-    : nsDisplayItem(aBuilder, aFrame), mLine(aLine),
+    : nsCharClipDisplayItem(aBuilder, aFrame), mLine(aLine),
       mDecorationFlags(aDecoration), mUnderlineStyle(aUnderlineStyle),
       mOverlineStyle(aOverlineStyle), mStrikeThroughStyle(aStrikeThroughStyle) {
     MOZ_COUNT_CTOR(nsDisplayTextShadow);
   }
   virtual ~nsDisplayTextShadow() {
     MOZ_COUNT_DTOR(nsDisplayTextShadow);
   }
 
@@ -295,32 +295,33 @@ nsDisplayTextShadow::Paint(nsDisplayList
     nsContextBoxBlur contextBoxBlur;
     gfxContext* shadowCtx = contextBoxBlur.Init(shadowRect, 0, shadow->mRadius,
                                                 presContext->AppUnitsPerDevPixel(),
                                                 thebesCtx, mVisibleRect, nsnull);
     if (!shadowCtx) {
       continue;
     }
 
+    const nsCharClipDisplayItem::ClipEdges clipEdges = this->Edges();
     if (mDecorationFlags & NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE) {
       f->PaintTextDecorationLine(shadowCtx, pt, mLine, shadowColor,
                                  mUnderlineStyle, underlineOffset, ascent,
-                                 metrics.underlineSize,
+                                 metrics.underlineSize, clipEdges,
                                  NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE);
     }
     if (mDecorationFlags & NS_STYLE_TEXT_DECORATION_LINE_OVERLINE) {
       f->PaintTextDecorationLine(shadowCtx, pt, mLine, shadowColor,
                                  mOverlineStyle, metrics.maxAscent, ascent,
-                                 metrics.underlineSize,
+                                 metrics.underlineSize, clipEdges,
                                  NS_STYLE_TEXT_DECORATION_LINE_OVERLINE);
     }
     if (mDecorationFlags & NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH) {
       f->PaintTextDecorationLine(shadowCtx, pt, mLine, shadowColor,
                                  mStrikeThroughStyle, metrics.strikeoutOffset,
-                                 ascent, metrics.strikeoutSize,
+                                 ascent, metrics.strikeoutSize, clipEdges,
                                  NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH);
     }
 
     contextBoxBlur.DoPaint();
   }
 }
 
 nsRect
@@ -435,28 +436,31 @@ nsHTMLContainerFrame::PaintTextDecoratio
                    gfxContext* aCtx, 
                    const nsPoint& aPt,
                    nsLineBox* aLine,
                    nscolor aColor, 
                    PRUint8 aStyle,
                    gfxFloat aOffset, 
                    gfxFloat aAscent, 
                    gfxFloat aSize,
+                   const nsCharClipDisplayItem::ClipEdges& aClipEdges,
                    const PRUint8 aDecoration) 
 {
   NS_ASSERTION(!aLine, "Should not have passed a linebox to a non-block frame");
   nsMargin bp = GetUsedBorderAndPadding();
   PRIntn skip = GetSkipSides();
   NS_FOR_CSS_SIDES(side) {
     if (skip & (1 << side)) {
       bp.Side(side) = 0;
     }
   }
+  nscoord x = aPt.x + bp.left;
   nscoord innerWidth = mRect.width - bp.left - bp.right;
-  gfxPoint pt(PresContext()->AppUnitsToGfxUnits(bp.left + aPt.x),
+  aClipEdges.Intersect(&x, &innerWidth);
+  gfxPoint pt(PresContext()->AppUnitsToGfxUnits(x),
               PresContext()->AppUnitsToGfxUnits(bp.top + aPt.y));
   gfxSize size(PresContext()->AppUnitsToGfxUnits(innerWidth), aSize);
   nsCSSRendering::PaintDecorationLine(aCtx, aColor, pt, size, aAscent, aOffset,
                                       aDecoration, aStyle);
 }
 
 /*virtual*/ void
 nsHTMLContainerFrame::AdjustForTextIndent(const nsLineBox* aLine,
--- a/layout/generic/nsHTMLContainerFrame.h
+++ b/layout/generic/nsHTMLContainerFrame.h
@@ -36,16 +36,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 /* base class #2 for rendering objects that have child lists */
 
 #ifndef nsHTMLContainerFrame_h___
 #define nsHTMLContainerFrame_h___
 
 #include "nsContainerFrame.h"
+#include "nsDisplayList.h"
 #include "gfxPoint.h"
 
 class nsString;
 class nsAbsoluteFrame;
 class nsPlaceholderFrame;
 struct nsStyleDisplay;
 struct nsStylePosition;
 struct nsHTMLReflowMetrics;
@@ -167,30 +168,33 @@ protected:
    *                                NS_STYLE_TEXT_DECORATION_STYLE_* consts.
    *    @param aAscent            ascent of the font from which the
    *                                text-decoration was derived. 
    *    @param aOffset            distance *above* baseline where the
    *                                text-decoration should be drawn,
    *                                i.e. negative offsets draws *below*
    *                                the baseline.
    *    @param aSize              the thickness of the line
+   *    @param aClipEdges         clip edges from the display item
    *    @param aDecoration        which line will be painted i.e.,
    *                              NS_STYLE_TEXT_DECORATION_LINE_UNDERLINE or
    *                              NS_STYLE_TEXT_DECORATION_LINE_OVERLINE or
    *                              NS_STYLE_TEXT_DECORATION_LINE_LINE_THROUGH.
    */
-  virtual void PaintTextDecorationLine(gfxContext* aCtx,
-                                       const nsPoint& aPt,
-                                       nsLineBox* aLine,
-                                       nscolor aColor,
-                                       PRUint8 aStyle,
-                                       gfxFloat aOffset,
-                                       gfxFloat aAscent,
-                                       gfxFloat aSize,
-                                       const PRUint8 aDecoration);
+  virtual void PaintTextDecorationLine(
+                 gfxContext* aCtx,
+                 const nsPoint& aPt,
+                 nsLineBox* aLine,
+                 nscolor aColor,
+                 PRUint8 aStyle,
+                 gfxFloat aOffset,
+                 gfxFloat aAscent,
+                 gfxFloat aSize,
+                 const nsCharClipDisplayItem::ClipEdges& aClipEdges,
+                 const PRUint8 aDecoration);
 
   virtual void AdjustForTextIndent(const nsLineBox* aLine,
                                    nscoord& start,
                                    nscoord& width);
 
   friend class nsDisplayTextDecoration;
   friend class nsDisplayTextShadow;
 };
--- a/layout/generic/nsTextFrame.h
+++ b/layout/generic/nsTextFrame.h
@@ -51,16 +51,17 @@
 #define nsTextFrame_h__
 
 #include "nsFrame.h"
 #include "nsSplittableFrame.h"
 #include "nsLineBox.h"
 #include "gfxFont.h"
 #include "gfxSkipChars.h"
 #include "gfxContext.h"
+#include "nsDisplayList.h"
 
 class nsTextPaintStyle;
 class PropertyProvider;
 
 // This state bit is set on frames that have some non-collapsed characters after
 // reflow
 #define TEXT_HAS_NONCOLLAPSED_CHARACTERS NS_FRAME_STATE_BIT(31)
 
@@ -267,36 +268,62 @@ public:
 
   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
+   */
+  bool MeasureCharClippedText(gfxContext* aCtx,
+                              nscoord aLeftEdge, nscoord aRightEdge,
+                              nscoord* aSnappedLeftEdge,
+                              nscoord* aSnappedRightEdge);
+  /**
+   * Same as above; this method also the returns the corresponding text run
+   * offset and number of characters that fit.  All out parameter values are
+   * undefined when the method returns false.
+   * @return true if at least one whole grapheme cluster fit between the edges
+   */
+  bool MeasureCharClippedText(gfxContext* aCtx,
+                              PropertyProvider& aProvider,
+                              nscoord aLeftEdge, nscoord aRightEdge,
+                              PRUint32* aStartOffset, PRUint32* aMaxLength,
+                              nscoord* aSnappedLeftEdge,
+                              nscoord* aSnappedRightEdge);
   // primary frame paint method called from nsDisplayText
   // The private DrawText() is what applies the text to a graphics context
   void PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt,
-                 const nsRect& aDirtyRect);
+                 const nsRect& aDirtyRect, const nsCharClipDisplayItem& aItem);
   // helper: paint quirks-mode CSS text decorations
   void PaintTextDecorations(gfxContext* aCtx, const gfxRect& aDirtyRect,
                             const gfxPoint& aFramePt,
                             const gfxPoint& aTextBaselinePt,
                             nsTextPaintStyle& aTextStyle,
                             PropertyProvider& aProvider,
+                            const nsCharClipDisplayItem::ClipEdges& aClipEdges,
                             const nscolor* aOverrideColor = nsnull);
   // helper: paint text frame when we're impacted by at least one selection.
   // Return PR_FALSE if the text was not painted and we should continue with
   // the fast path.
   PRBool PaintTextWithSelection(gfxContext* aCtx,
                                 const gfxPoint& aFramePt,
                                 const gfxPoint& aTextBaselinePt,
                                 const gfxRect& aDirtyRect,
                                 PropertyProvider& aProvider,
-                                nsTextPaintStyle& aTextPaintStyle);
+                                nsTextPaintStyle& aTextPaintStyle,
+                                const nsCharClipDisplayItem::ClipEdges& aClipEdges);
   // helper: paint text with foreground and background colors determined
   // by selection(s). Also computes a mask of all selection types applying to
   // our text, returned in aAllTypes.
   void PaintTextWithSelectionColors(gfxContext* aCtx,
                                     const gfxPoint& aFramePt,
                                     const gfxPoint& aTextBaselinePt,
                                     const gfxRect& aDirtyRect,
                                     PropertyProvider& aProvider,
@@ -423,17 +450,19 @@ protected:
   void PaintOneShadow(PRUint32 aOffset,
                       PRUint32 aLength,
                       nsCSSShadowItem* aShadowDetails,
                       PropertyProvider* aProvider,
                       const nsRect& aDirtyRect,
                       const gfxPoint& aFramePt,
                       const gfxPoint& aTextBaselinePt,
                       gfxContext* aCtx,
-                      const nscolor& aForegroundColor);
+                      const nscolor& aForegroundColor,
+                      const nsCharClipDisplayItem::ClipEdges& aClipEdges,
+                      nscoord aLeftSideOffset);
 
   struct TextDecorations {
     PRUint8 mDecorations;
     PRUint8 mOverStyle;
     PRUint8 mUnderStyle;
     PRUint8 mStrikeStyle;
     nscolor mOverColor;
     nscolor mUnderColor;
--- a/layout/generic/nsTextFrameThebes.cpp
+++ b/layout/generic/nsTextFrameThebes.cpp
@@ -3203,49 +3203,16 @@ EnsureDifferentColors(nscolor colorA, ns
                  NS_GET_B(colorA) ^ 0xff);
     return res;
   }
   return colorA;
 }
 
 //-----------------------------------------------------------------------------
 
-static nscolor
-DarkenColor(nscolor aColor)
-{
-  PRUint16  hue, sat, value;
-  PRUint8 alpha;
-
-  // convert the RBG to HSV so we can get the lightness (which is the v)
-  NS_RGB2HSV(aColor, hue, sat, value, alpha);
-
-  // The goal here is to send white to black while letting colored
-  // stuff stay colored... So we adopt the following approach.
-  // Something with sat = 0 should end up with value = 0.  Something
-  // with a high sat can end up with a high value and it's ok.... At
-  // the same time, we don't want to make things lighter.  Do
-  // something simple, since it seems to work.
-  if (value > sat) {
-    value = sat;
-    // convert this color back into the RGB color space.
-    NS_HSV2RGB(aColor, hue, sat, value, alpha);
-  }
-  return aColor;
-}
-
-// Check whether we should darken text colors. We need to do this if
-// background images and colors are being suppressed, because that means
-// light text will not be visible against the (presumed light-colored) background.
-static PRBool
-ShouldDarkenColors(nsPresContext* aPresContext)
-{
-  return !aPresContext->GetBackgroundColorDraw() &&
-    !aPresContext->GetBackgroundImageDraw();
-}
-
 nsTextPaintStyle::nsTextPaintStyle(nsTextFrame* aFrame)
   : mFrame(aFrame),
     mPresContext(aFrame->PresContext()),
     mInitCommonColors(PR_FALSE),
     mInitSelectionColors(PR_FALSE)
 {
   for (PRUint32 i = 0; i < NS_ARRAY_LENGTH(mSelectionStyle); i++)
     mSelectionStyle[i].mInit = PR_FALSE;
@@ -3274,21 +3241,17 @@ nsTextPaintStyle::EnsureSufficientContra
     return PR_TRUE;
   }
   return PR_FALSE;
 }
 
 nscolor
 nsTextPaintStyle::GetTextColor()
 {
-  nscolor color = mFrame->GetVisitedDependentColor(eCSSProperty_color);
-  if (ShouldDarkenColors(mPresContext)) {
-    color = DarkenColor(color);
-  }
-  return color;
+  return nsLayoutUtils::GetTextColor(mFrame);
 }
 
 PRBool
 nsTextPaintStyle::GetSelectionColors(nscolor* aForeColor,
                                      nscolor* aBackColor)
 {
   NS_ASSERTION(aForeColor, "aForeColor is null");
   NS_ASSERTION(aBackColor, "aBackColor is null");
@@ -4164,20 +4127,20 @@ nsTextFrame::CharacterDataChanged(Charac
 
 /* virtual */ void
 nsTextFrame::DidSetStyleContext(nsStyleContext* aOldStyleContext)
 {
   nsFrame::DidSetStyleContext(aOldStyleContext);
   ClearTextRun(nsnull);
 } 
 
-class nsDisplayText : public nsDisplayItem {
+class nsDisplayText : public nsCharClipDisplayItem {
 public:
   nsDisplayText(nsDisplayListBuilder* aBuilder, nsTextFrame* aFrame) :
-    nsDisplayItem(aBuilder, aFrame),
+    nsCharClipDisplayItem(aBuilder, aFrame),
     mDisableSubpixelAA(PR_FALSE) {
     MOZ_COUNT_CTOR(nsDisplayText);
   }
 #ifdef NS_BUILD_REFCNT_LOGGING
   virtual ~nsDisplayText() {
     MOZ_COUNT_DTOR(nsDisplayText);
   }
 #endif
@@ -4213,17 +4176,19 @@ nsDisplayText::Paint(nsDisplayListBuilde
   // This is temporary until we do this in the actual calculation of text extents.
   nsRect extraVisible = mVisibleRect;
   nscoord appUnitsPerDevPixel = mFrame->PresContext()->AppUnitsPerDevPixel();
   extraVisible.Inflate(appUnitsPerDevPixel, appUnitsPerDevPixel);
   nsTextFrame* f = static_cast<nsTextFrame*>(mFrame);
 
   gfxContextAutoDisableSubpixelAntialiasing disable(aCtx->ThebesContext(),
                                                     mDisableSubpixelAA);
-  f->PaintText(aCtx, ToReferenceFrame(), extraVisible);
+  NS_ASSERTION(mLeftEdge >= 0, "illegal left edge");
+  NS_ASSERTION(mRightEdge >= 0, "illegal right edge");
+  f->PaintText(aCtx, ToReferenceFrame(), extraVisible, *this);
 }
 
 NS_IMETHODIMP
 nsTextFrame::BuildDisplayList(nsDisplayListBuilder*   aBuilder,
                               const nsRect&           aDirtyRect,
                               const nsDisplayListSet& aLists)
 {
   if (!IsVisibleForPainting(aBuilder))
@@ -4429,22 +4394,24 @@ nsTextFrame::UnionTextDecorationOverflow
   nsRect decorationRect;
   if (!(GetStateBits() & NS_FRAME_SELECTED_CONTENT) ||
       !CombineSelectionUnderlineRect(aPresContext, *aVisualOverflowRect))
     return;
   AddStateBits(TEXT_SELECTION_UNDERLINE_OVERFLOWED);
 }
 
 void 
-nsTextFrame::PaintTextDecorations(gfxContext* aCtx, const gfxRect& aDirtyRect,
-                                  const gfxPoint& aFramePt,
-                                  const gfxPoint& aTextBaselinePt,
-                                  nsTextPaintStyle& aTextPaintStyle,
-                                  PropertyProvider& aProvider,
-                                  const nscolor* aOverrideColor)
+nsTextFrame::PaintTextDecorations(
+               gfxContext* aCtx, const gfxRect& aDirtyRect,
+               const gfxPoint& aFramePt,
+               const gfxPoint& aTextBaselinePt,
+               nsTextPaintStyle& aTextPaintStyle,
+               PropertyProvider& aProvider,
+               const nsCharClipDisplayItem::ClipEdges& aClipEdges,
+               const nscolor* aOverrideColor)
 {
   TextDecorations decorations =
     GetTextDecorations(aTextPaintStyle.PresContext());
   if (!decorations.HasDecorationlines())
     return;
 
   // Hide text decorations if we're currently hiding @font-face fallback text
   if (aProvider.GetFontGroup()->ShouldSkipDrawing())
@@ -4452,18 +4419,21 @@ nsTextFrame::PaintTextDecorations(gfxCon
 
   gfxFont* firstFont = aProvider.GetFontGroup()->GetFontAt(0);
   if (!firstFont)
     return; // OOM
   const gfxFont::Metrics& fontMetrics = firstFont->GetMetrics();
   gfxFloat app = aTextPaintStyle.PresContext()->AppUnitsPerDevPixel();
 
   // XXX aFramePt is in AppUnits, shouldn't it be nsFloatPoint?
-  gfxPoint pt(aFramePt.x / app, (aTextBaselinePt.y - mAscent) / app);
-  gfxSize size(GetRect().width / app, 0);
+  nscoord x = aFramePt.x;
+  nscoord width = GetRect().width;
+  aClipEdges.Intersect(&x, &width);
+  gfxPoint pt(x / app, (aTextBaselinePt.y - mAscent) / app);
+  gfxSize size(width / app, 0);
   gfxFloat ascent = gfxFloat(mAscent) / app;
 
   nscolor lineColor;
   if (decorations.HasOverline()) {
     lineColor = aOverrideColor ? *aOverrideColor : decorations.mOverColor;
     size.height = fontMetrics.underlineSize;
     nsCSSRendering::PaintDecorationLine(
       aCtx, lineColor, pt, size, ascent, fontMetrics.maxAscent,
@@ -4806,33 +4776,35 @@ AddHyphenToMetrics(nsTextFrame* aTextFra
   aMetrics->CombineWith(hyphenMetrics, aBaseTextRun->IsRightToLeft());
 }
 
 void
 nsTextFrame::PaintOneShadow(PRUint32 aOffset, PRUint32 aLength,
                             nsCSSShadowItem* aShadowDetails,
                             PropertyProvider* aProvider, const nsRect& aDirtyRect,
                             const gfxPoint& aFramePt, const gfxPoint& aTextBaselinePt,
-                            gfxContext* aCtx, const nscolor& aForegroundColor)
+                            gfxContext* aCtx, const nscolor& aForegroundColor,
+                            const nsCharClipDisplayItem::ClipEdges& aClipEdges,
+                            nscoord aLeftSideOffset)
 {
   gfxPoint shadowOffset(aShadowDetails->mXOffset, aShadowDetails->mYOffset);
   nscoord blurRadius = NS_MAX(aShadowDetails->mRadius, 0);
 
   gfxTextRun::Metrics shadowMetrics =
     mTextRun->MeasureText(aOffset, aLength, gfxFont::LOOSE_INK_EXTENTS,
                           nsnull, aProvider);
   if (GetStateBits() & TEXT_HYPHEN_BREAK) {
     AddHyphenToMetrics(this, mTextRun, &shadowMetrics, gfxFont::LOOSE_INK_EXTENTS, aCtx);
   }
 
   // This rect is the box which is equivalent to where the shadow will be painted.
   // The origin of mBoundingBox is the text baseline left, so we must translate it by
   // that much in order to make the origin the top-left corner of the text bounding box.
   gfxRect shadowGfxRect = shadowMetrics.mBoundingBox +
-     gfxPoint(aFramePt.x, aTextBaselinePt.y) + shadowOffset;
+    gfxPoint(aFramePt.x + aLeftSideOffset, aTextBaselinePt.y) + shadowOffset;
   nsRect shadowRect(shadowGfxRect.X(), shadowGfxRect.Y(),
                     shadowGfxRect.Width(), shadowGfxRect.Height());
 
   nsContextBoxBlur contextBoxBlur;
   gfxContext* shadowContext = contextBoxBlur.Init(shadowRect, 0, blurRadius,
                                                   PresContext()->AppUnitsPerDevPixel(),
                                                   aCtx, aDirtyRect, nsnull);
   if (!shadowContext)
@@ -4859,17 +4831,17 @@ nsTextFrame::PaintOneShadow(PRUint32 aOf
            (GetStateBits() & TEXT_HYPHEN_BREAK) != 0);
 
   // This will only have an effect in quirks mode. Standards mode text-decoration shadow painting
   // is handled in nsHTMLContainerFrame.cpp, so you must remember to consider that if you change
   // any code behaviour here.
   nsTextPaintStyle textPaintStyle(this);
   PaintTextDecorations(shadowContext, dirtyGfxRect, aFramePt + shadowOffset,
                        aTextBaselinePt + shadowOffset,
-                       textPaintStyle, *aProvider, &shadowColor);
+                       textPaintStyle, *aProvider, aClipEdges, &shadowColor);
 
   contextBoxBlur.DoPaint();
   aCtx->Restore();
 }
 
 // Paints selection backgrounds and text in the correct colors. Also computes
 // aAllTypes, the union of all selection types that are applying to this text.
 void
@@ -5037,27 +5009,28 @@ nsTextFrame::PaintTextSelectionDecoratio
     iterator.UpdateWithAdvance(advance);
   }
 }
 
 PRBool
 nsTextFrame::PaintTextWithSelection(gfxContext* aCtx,
     const gfxPoint& aFramePt,
     const gfxPoint& aTextBaselinePt, const gfxRect& aDirtyRect,
-    PropertyProvider& aProvider, nsTextPaintStyle& aTextPaintStyle)
+    PropertyProvider& aProvider, nsTextPaintStyle& aTextPaintStyle,
+    const nsCharClipDisplayItem::ClipEdges& aClipEdges)
 {
   SelectionDetails* details = GetSelectionDetails();
   if (!details)
     return PR_FALSE;
 
   SelectionType allTypes;
   PaintTextWithSelectionColors(aCtx, aFramePt, aTextBaselinePt, aDirtyRect,
                                aProvider, aTextPaintStyle, details, &allTypes);
   PaintTextDecorations(aCtx, aDirtyRect, aFramePt, aTextBaselinePt,
-                       aTextPaintStyle, aProvider);
+                       aTextPaintStyle, aProvider, aClipEdges);
   PRInt32 i;
   // Iterate through just the selection types that paint decorations and
   // paint decorations for any that actually occur in this frame. Paint
   // higher-numbered selection types below lower-numered ones on the
   // general principal that lower-numbered selections are higher priority.
   allTypes &= SelectionTypesWithDecorations;
   for (i = nsISelectionController::NUM_SELECTIONTYPES - 1; i >= 1; --i) {
     SelectionType type = 1 << (i - 1);
@@ -5131,74 +5104,185 @@ nsTextFrame::GetSnappedBaselineY(gfxCont
   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
+  // XXX get the block and line passed to us somehow! This is slow!
+  gfxSkipCharsIterator iter = EnsureTextRun();
+  if (!mTextRun)
+    return false;
+
+  PropertyProvider provider(this, iter);
+  // Trim trailing whitespace
+  provider.InitializeForDisplay(PR_TRUE);
+
+  PRUint32 startOffset = provider.GetStart().GetSkippedOffset();
+  PRUint32 maxLength = ComputeTransformedLength(provider);
+  return MeasureCharClippedText(aCtx, provider, aLeftEdge, aRightEdge,
+                                &startOffset, &maxLength,
+                                aSnappedLeftEdge, aSnappedRightEdge);
+}
+
+static PRUint32 GetClusterLength(gfxTextRun* aTextRun,
+                                 PRUint32    aStartOffset,
+                                 PRUint32    aMaxLength,
+                                 bool        aIsRTL)
+{
+  PRUint32 clusterLength = aIsRTL ? 0 : 1;
+  while (clusterLength < aMaxLength) {
+    if (aTextRun->IsClusterStart(aStartOffset + clusterLength)) {
+      if (aIsRTL) {
+        ++clusterLength;
+      }
+      break;
+    }
+    ++clusterLength;
+  }
+  return clusterLength;
+}
+
+bool
+nsTextFrame::MeasureCharClippedText(gfxContext* aCtx,
+                                    PropertyProvider& aProvider,
+                                    nscoord aLeftEdge, nscoord aRightEdge,
+                                    PRUint32* aStartOffset,
+                                    PRUint32* aMaxLength,
+                                    nscoord*  aSnappedLeftEdge,
+                                    nscoord*  aSnappedRightEdge)
+{
+  *aSnappedLeftEdge = 0;
+  *aSnappedRightEdge = 0;
+  if (aLeftEdge <= 0 && aRightEdge <= 0) {
+    return true;
+  }
+
+  PRUint32 offset = *aStartOffset;
+  PRUint32 maxLength = *aMaxLength;
+  const nscoord frameWidth = GetSize().width;
+  const PRBool rtl = mTextRun->IsRightToLeft();
+  gfxFloat advanceWidth = 0;
+  const nscoord startEdge = rtl ? aRightEdge : aLeftEdge;
+  if (startEdge > 0) {
+    const gfxFloat maxAdvance = gfxFloat(startEdge);
+    while (maxLength > 0) {
+      PRUint32 clusterLength =
+        GetClusterLength(mTextRun, offset, maxLength, rtl);
+      advanceWidth +=
+        mTextRun->GetAdvanceWidth(offset, clusterLength, &aProvider);
+      maxLength -= clusterLength;
+      offset += clusterLength;
+      if (advanceWidth >= maxAdvance) {
+        break;
+      }
+    }
+    nscoord* snappedStartEdge = rtl ? aSnappedRightEdge : aSnappedLeftEdge;
+    *snappedStartEdge = NSToCoordFloor(advanceWidth);
+    *aStartOffset = offset;
+  }
+
+  const nscoord endEdge = rtl ? aLeftEdge : aRightEdge;
+  if (endEdge > 0) {
+    const gfxFloat maxAdvance = gfxFloat(frameWidth - endEdge);
+    while (maxLength > 0) {
+      PRUint32 clusterLength =
+        GetClusterLength(mTextRun, offset, maxLength, rtl);
+      gfxFloat nextAdvance = advanceWidth +
+        mTextRun->GetAdvanceWidth(offset, clusterLength, &aProvider);
+      if (nextAdvance > maxAdvance) {
+        break;
+      }
+      // This cluster fits, include it.
+      advanceWidth = nextAdvance;
+      maxLength -= clusterLength;
+      offset += clusterLength;
+    }
+    maxLength = offset - *aStartOffset;
+    nscoord* snappedEndEdge = rtl ? aSnappedLeftEdge : aSnappedRightEdge;
+    *snappedEndEdge = NSToCoordFloor(gfxFloat(frameWidth) - advanceWidth);
+  }
+  *aMaxLength = maxLength;
+  return maxLength != 0;
+}
+
 void
 nsTextFrame::PaintText(nsRenderingContext* aRenderingContext, nsPoint aPt,
-                       const nsRect& aDirtyRect)
+                       const nsRect& aDirtyRect,
+                       const nsCharClipDisplayItem& aItem)
 {
   // Don't pass in aRenderingContext here, because we need a *reference*
   // context and aRenderingContext might have some transform in it
   // XXX get the block and line passed to us somehow! This is slow!
   gfxSkipCharsIterator iter = EnsureTextRun();
   if (!mTextRun)
     return;
 
-  nsTextPaintStyle textPaintStyle(this);
   PropertyProvider provider(this, iter);
   // 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(
-      mTextRun->IsRightToLeft() ? gfxFloat(aPt.x + GetSize().width) : framePt.x,
-      GetSnappedBaselineY(ctx, aPt.y));
-
-  gfxRect dirtyRect(aDirtyRect.x, aDirtyRect.y,
-                    aDirtyRect.width, aDirtyRect.height);
-
-  gfxFloat advanceWidth;
-  gfxRGBA foregroundColor = gfxRGBA(textPaintStyle.GetTextColor());
+  gfxPoint textBaselinePt(rtl ? gfxFloat(aPt.x + frameWidth) : framePt.x,
+                          GetSnappedBaselineY(ctx, aPt.y));
+  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;
+  nsCharClipDisplayItem::ClipEdges clipEdges(aItem, snappedLeftEdge,
+                                             snappedRightEdge);
+  nsTextPaintStyle textPaintStyle(this);
+  nscolor foregroundColor = textPaintStyle.GetTextColor();
 
   // Paint the text shadow before doing any foreground stuff
   const nsStyleText* textStyle = GetStyleText();
   if (textStyle->mTextShadow) {
     // Text shadow happens with the last value being painted at the back,
     // ie. it is painted first.
     for (PRUint32 i = textStyle->mTextShadow->Length(); i > 0; --i) {
-      PaintOneShadow(provider.GetStart().GetSkippedOffset(),
-                     ComputeTransformedLength(provider),
+      PaintOneShadow(startOffset, maxLength,
                      textStyle->mTextShadow->ShadowAt(i - 1), &provider,
                      aDirtyRect, framePt, textBaselinePt, ctx,
-                     textPaintStyle.GetTextColor());
-    }
-  }
-
+                     foregroundColor, clipEdges, snappedLeftEdge);
+    }
+  }
+
+  gfxRect dirtyRect(aDirtyRect.x, aDirtyRect.y,
+                    aDirtyRect.width, aDirtyRect.height);
   // Fork off to the (slower) paint-with-selection path if necessary.
   if (nsLayoutUtils::GetNonGeneratedAncestor(this)->GetStateBits() & NS_FRAME_SELECTED_CONTENT) {
     if (PaintTextWithSelection(ctx, framePt, textBaselinePt,
-                               dirtyRect, provider, textPaintStyle))
+                               dirtyRect, provider, textPaintStyle, clipEdges))
       return;
   }
 
-  ctx->SetColor(foregroundColor);
-
-  DrawText(ctx, textBaselinePt, provider.GetStart().GetSkippedOffset(),
-           ComputeTransformedLength(provider), &dirtyRect,
-           &provider, advanceWidth,
-           (GetStateBits() & TEXT_HYPHEN_BREAK) != 0);
+  ctx->SetColor(gfxRGBA(foregroundColor));
+
+  gfxFloat advanceWidth;
+  DrawText(ctx, textBaselinePt, startOffset, maxLength, &dirtyRect, &provider,
+           advanceWidth, (GetStateBits() & TEXT_HYPHEN_BREAK) != 0);
   PaintTextDecorations(ctx, dirtyRect, framePt, textBaselinePt,
-                       textPaintStyle, provider);
+                       textPaintStyle, provider, clipEdges);
 }
 
 void
 nsTextFrame::DrawText(gfxContext* aCtx, const gfxPoint& aTextBaselinePt,
                       PRUint32 aOffset, PRUint32 aLength,
                       const gfxRect* aDirtyRect, PropertyProvider* aProvider,
                       gfxFloat& aAdvanceWidth, PRBool aDrawSoftHyphen)
 {
--- a/layout/mathml/Makefile.in
+++ b/layout/mathml/Makefile.in
@@ -97,16 +97,17 @@ FORCE_STATIC_LIB = 1
 
 include $(topsrcdir)/config/rules.mk
 
 font_properties = \
 	mathfontUnicode.properties \
 	mathfontSTIXNonUnicode.properties \
 	mathfontSTIXSize1.properties \
 	mathfontSTIXSizeOneSym.properties \
+	mathfontAsanaMath.properties \
 	mathfontStandardSymbolsL.properties \
 	$(NULL)
 
 ifeq ($(TARGET_MD_ARCH),win32)
 font_properties += \
 	mathfontSymbol.properties
 endif
 
--- a/layout/mathml/mathfont.properties
+++ b/layout/mathml/mathfont.properties
@@ -41,19 +41,19 @@
 #  Do not translate anything in this file
 
 # List of fonts that have corresponding properties files containing special
 # glyph tables for stretching MathML characters.  See the documentation at the
 # end of this file for details on the setup of the property file associated to
 # each font.  Do not include the Unicode table in this list.
 
 %ifdef XP_WIN
-font.mathfont-glyph-tables = STIXNonUnicode, STIXSizeOneSym, STIXSize1, Standard Symbols L, Symbol
+font.mathfont-glyph-tables = STIXNonUnicode, STIXSizeOneSym, STIXSize1, Asana Math, Standard Symbols L, Symbol
 %else
-font.mathfont-glyph-tables = STIXNonUnicode, STIXSizeOneSym, STIXSize1, Standard Symbols L
+font.mathfont-glyph-tables = STIXNonUnicode, STIXSizeOneSym, STIXSize1, Asana Math, Standard Symbols L
 %endif
 
 # The ordered list of fonts with which to attempt to stretch MathML
 # characters is controlled by setting pref("font.mathfont-family",
 # "CMSY10, CMEX10, ...") for example, or by setting the font-family list in
 # :-moz-math-stretchy in mathml.css.
 #
 # Preferred fonts for particular stretchy characters may be specified in
new file mode 100644
--- /dev/null
+++ b/layout/mathml/mathfontAsanaMath.properties
@@ -0,0 +1,180 @@
+# ***** BEGIN LICENSE BLOCK *****
+# Version: MPL 1.1/GPL 2.0/LGPL 2.1
+#
+# The contents of this file are subject to the Mozilla Public License Version
+# 1.1 (the "License"); you may not use this file except in compliance with
+# the License. You may obtain a copy of the License at
+# http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS IS" basis,
+# WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+# for the specific language governing rights and limitations under the
+# License.
+#                                                                       
+# The Original Code is Mozilla MathML Project.                          
+#                                                                       
+# The Initial Developer of the Original Code is
+# The University of Queensland.
+# Portions created by the Initial Developer are Copyright (C) 2001
+# the Initial Developer. All Rights Reserved.
+#                                                                       
+# Contributor(s):                                                       
+#   Roger B. Sidje <rbs@maths.uq.edu.au>                                
+#   Karl Tomlinson <karlt+@karlt.net>, Mozilla Corporation
+#   Frederic Wang <fred.wang@free.fr>
+#
+# Alternatively, the contents of this file may be used under the terms of
+# either the GNU General Public License Version 2 or later (the "GPL"), or
+# the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+# in which case the provisions of the GPL or the LGPL are applicable instead
+# of those above. If you wish to allow use of your version of this file only
+# under the terms of either the GPL or the LGPL, and not to allow others to
+# use your version of this file under the terms of the MPL, indicate your
+# decision by deleting the provisions above and replace them with the notice
+# and other provisions required by the GPL or the LGPL. If you do not delete
+# the provisions above, a recipient may use your version of this file under
+# the terms of any one of the MPL, the GPL or the LGPL.
+#
+# ***** END LICENSE BLOCK *****
+
+#  LOCALIZATION NOTE: FILE
+#  Do not translate anything in this file
+
+# This file contains the list of some stretchy MathML chars that
+# can be rendered with Asana Math font.
+
+#        [ T/L |  M  | B/R |  G  | size0 ... size{N-1} ]
+#        (*) not in the MathML operator dictionary
+
+\u0028 = \u239B\uFFFD\u239D\u239C\u0028\uDBFF\uDFF4\uDBFF\uDFF5\uDBFF\uDFF6 # (
+\u0029 = \u239E\uFFFD\u23A0\u239F\u0029\uDBFF\uDFF7\uDBFF\uDFF8\uDBFF\uDFF9 # )
+\u005B = \u23A1\uFFFD\u23A3\u23A2\u005B\uDBFF\uDFEE\uDBFF\uDFEF\uDBFF\uDFF0 # [
+\u005D = \u23A4\uFFFD\u23A6\u23A5\u005D\uDBFF\uDFF1\uDBFF\uDFF2\uDBFF\uDFF3 # ]
+\u007B = \u23A7\u23A8\u23A9\u23AA\u007B\uDBFF\uDFFA\uDBFF\uDFFB\uDBFF\uDFFC # {
+\u007C = \uFFFD\uFFFD\uFFFD\u007C\u007C\uDBFF\uDFD6\uDBFF\uDFD7\uDBFF\uDFD8\uDBFF\uDFD9 # |
+\u007D = \u23AB\u23AC\u23AD\u23AA\u007D\uDBFF\uDFFD\uDBFF\uDFFE\uDBFF\uDFFF # }
+\u2016 = \uFFFD\uFFFD\uFFFD\uDBFF\uDFD1\u2016\uDBFF\uDFCE\uDBFF\uDFCF\uDBFF\uDFD0\uDBFF\uDFD1 # DOUBLE VERTICAL LINE
+
+\u2044 = \uFFFD\uFFFD\uFFFD\uFFFD\u2044\uDBFF\uDFD2\uDBFF\uDFD3\uDBFF\uDFD4\uDBFF\uDFD5 # FRACTION SLASH
+# \u2045 = \uDBFF\uDFB6\uDBFF\uDF53\uDBFF\uDFB7\uDBFF\uDFBA\u2045\uDBFF\uDFBB\uDBFF\uDFBC\uDBFF\uDFBD # LEFT SQUARE BRACKET WITH QUILL (*)
+# \u2046 = \uDBFF\uDFB8\uDBFF\uDF54\uDBFF\uDFB9\uDBFF\uDF52\u2046\uDBFF\uDFBE\uDBFF\uDFBF\uDBFF\uDFC0 # RIGHT SQUARE BRACKET WITH QUILL (*)
+
+\u2191 = \u2191\uFFFD\uFFFD\uDBFF\uDEC6\u2191 # UPWARDS ARROW
+\u2193 = \uFFFD\uFFFD\u2193\uDBFF\uDEC6\u2193 # DOWNWARDS ARROW
+\u21D1 = \u21D1\uFFFD\uFFFD\uDBFF\uDEC7\u21D1 # UPWARDS DOUBLE ARROW
+\u21D3 = \uFFFD\uFFFD\u21D3\uDBFF\uDEC7\u21D3 # DOWNWARDS DOUBLE ARROW
+
+\u220F = \uFFFD\uFFFD\uFFFD\uFFFD\u220F\uDBFF\uDF9F\uDBFF\uDFA0\uDBFF\uDFA1 # N-ARY PRODUCT
+\u2210 = \uFFFD\uFFFD\uFFFD\uFFFD\u2210\uDBFF\uDFA2\uDBFF\uDFA3\uDBFF\uDFA4 # N-ARY COPRODUCT
+\u2211 = \uFFFD\uFFFD\uFFFD\uFFFD\u2211\uDBFF\uDF9C\uDBFF\uDF9D\uDBFF\uDF9E # summation N-ARY SUMMATION
+\u221A = \uDBFF\uDF6D\uFFFD\u23B7\u20D3\u221A\uDBFF\uDF6E\uDBFF\uDF6F\uDBFF\uDF70\uDBFF\uDF71 # SQUARE ROOT
+\u2223 = \uFFFD\uFFFD\uFFFD\u2223\u2223 # DIVIDES
+\u2225 = \uFFFD\uFFFD\uFFFD\u2225\u2225 # PARALLEL TO
+\u222B = \u2320\uFFFD\u2321\u23AE\u222B\uDBFF\uDF99\uDBFF\uDF9A\uDBFF\uDF9B # INTEGRAL
+\u222C = \uFFFD\uFFFD\uFFFD\uFFFD\u222C\uDBFF\uDF6A\uDBFF\uDF6B\uDBFF\uDF6C # DOUBLE INTEGRAL
+\u222D = \uFFFD\uFFFD\uFFFD\uFFFD\u222D\uDBFF\uDF67\uDBFF\uDF68\uDBFF\uDF69 # TRIPLE INTEGRAL
+\u222E = \uFFFD\uFFFD\uFFFD\uFFFD\u222E\uDBFF\uDF64\uDBFF\uDF65\uDBFF\uDF66 # CONTOUR INTEGRAL
+\u222F = \uFFFD\uFFFD\uFFFD\uFFFD\u222F\uDBFF\uDF61\uDBFF\uDF62\uDBFF\uDF63 # SURFACE INTEGRAL
+\u2230 = \uFFFD\uFFFD\uFFFD\uFFFD\u2230\uDBFF\uDF5E\uDBFF\uDF5F\uDBFF\uDF60 # VOLUME INTEGRAL
+\u2231 = \uFFFD\uFFFD\uFFFD\uFFFD\u2231\uDBFF\uDF5B\uDBFF\uDF5C\uDBFF\uDF5D # CLOCKWISE INTEGRAL
+\u2232 = \uFFFD\uFFFD\uFFFD\uFFFD\u2232\uDBFF\uDF58\uDBFF\uDF59\uDBFF\uDF5A # CLOCKWISE CONTOUR INTEGRAL
+\u2233 = \uFFFD\uFFFD\uFFFD\uFFFD\u2233\uDBFF\uDF55\uDBFF\uDF56\uDBFF\uDF57 # ANTICLOCKWISE CONTOUR INTEGRAL
+
+\u22C0 = \uFFFD\uFFFD\uFFFD\uFFFD\u22C0\uDBFF\uDF92\uDBFF\uDF93 # N-ARY LOGICAL AND
+\u22C1 = \uFFFD\uFFFD\uFFFD\uFFFD\u22C1\uDBFF\uDF94\uDBFF\uDF95 # N-ARY LOGICAL OR
+\u22C2 = \uFFFD\uFFFD\uFFFD\uFFFD\u22C2\uDBFF\uDF8E\uDBFF\uDF8F # N-ARY INTERSECTION
+\u22C3 = \uFFFD\uFFFD\uFFFD\uFFFD\u22C3\uDBFF\uDF8C\uDBFF\uDF8D # N-ARY UNION
+\u2308 = \u23A1\uFFFD\uFFFD\u23A2\u2308\uDBFF\uDFE2\uDBFF\uDFE3\uDBFF\uDFE4 # LEFT CEILING
+\u2309 = \u23A4\uFFFD\uFFFD\u23A5\u2309\uDBFF\uDFE5\uDBF\uDFE6\uDBFF\uDFE7 # RIGHT CEILING
+\u230A = \uFFFD\uFFFD\u23A3\u23A2\u230A\uDBFF\uDFE8\uDBFF\uDFE9\uDBFF\uDFEA # LEFT FLOOR
+\u230B = \uFFFD\uFFFD\u23A6\u23A5\u230B\u230B\uDBFF\uDFEB\uDBFF\uDFEC\uDBFF\uDFED # RIGHT FLOOR
+
+# \u27C5 = \uFFFD\uFFFD\uFFFD\uFFFD\u27C5\uDBFF\uDDF3\uDBFF\uDDF5\uDBFF\uDDF7\uDBFF\uDDF9\uDBFF\uDDFB # LEFT S-SHAPED BAG DELIMITER (*)
+# \u27C6 = \uFFFD\uFFFD\uFFFD\uFFFD\uDBFF\uDDF4\uDBFF\uDDF6\uDBFF\uDDF8\uDBFF\uDDFA\uDBFF\uDDFC # RIGHT S-SHAPED BAG DELIMITER (*)
+\u27E6 = \uFFFD\uFFFD\uFFFD\uFFFD\u27E6\uDBFF\uDFDA\uDBFF\uDFDB\uDBFF\uDFDC\uDBFF\uDFDD # MATHEMATICAL LEFT WHITE SQUARE BRACKET
+\u27E7 = \uFFFD\uFFFD\uFFFD\uFFFD\u27E7\uDBFF\uDFDE\uDBFF\uDFDF\uDBFF\uDFE0\uDBFF\uDFE1 # MATHEMATICAL RIGHT WHITE SQUARE BRACKET
+\u27E8 = \uFFFD\uFFFD\uFFFD\uFFFD\u27E8\uDBFF\uDF89\uDBFF\uDF8A\uDBFF\uD8B # MATHEMATICAL LEFT ANGLE BRACKET
+\u27E9 = \uFFFD\uFFFD\uFFFD\uFFFD\u27E9\uDBFF\uDF7C\uDBFF\uDF7D\uDBFF\uDF7E # MATHEMATICAL RIGHT ANGLE BRACKET
+\u27EA = \uFFFD\uFFFD\uFFFD\uFFFD\u27EA\uDBFF\uDF76\uDBFF\uDF77\uDBFF\uDF78 # MATHEMATICAL LEFT DOUBLE ANGLE BRACKET
+\u27EB = \uFFFD\uFFFD\uFFFD\uFFFD\u27EB\uDBFF\uDF79\uDBFF\uDF7A\uDBFF\uDF7B # MATHEMATICAL RIGHT DOUBLE ANGLE BRACKET
+
+\u29FC = \uFFFD\uFFFD\uFFFD\uFFFD\u29FC\uDBFF\uDEC8\uDBFF\uDEC9\uDBFF\uDECA # LEFT-POINTING CURVED ANGLE BRACKET
+\u29FD = \uFFFD\uFFFD\uFFFD\uFFFD\u29FD\uDBFF\uDECB\uDBFF\uDECC\uDBFF\uDECD # RIGHT-POINTING CURVED ANGLE BRACKET
+
+\u2A00 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A00\uDBFF\uDF96\uDBFF\uDF97 # N-ARY CIRCLED DOT OPERATOR
+\u2A01 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A01\uDBFF\uDF98\uDBFF\uDFA5 # N-ARY CIRCLED PLUS OPERATOR
+\u2A02 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A02\uDBFF\uDF7F\uDBFF\uDF80 # N-ARY CIRCLED TIMES OPERATOR
+\u2A03 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A03\uDBFF\uDF81\uDBFF\uDF82 # N-ARY UNION OPERATOR WITH DOT
+\u2A04 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A04\uDBFF\uDF90\uDBFF\uDF91 # N-ARY UNION OPERATOR WITH PLUS
+\u2A05 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A05\uDBFF\uDF83\uDBFF\uDF84 # N-ARY SQUARE INTERSECTION OPERATOR
+\u2A06 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A06\uDBFF\uDF85\uDBFF\uDF86 # N-ARY SQUARE UNION OPERATOR
+\u2A07 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A07\uDBFF\uDF72\uDBFF\uDF73 # TWO LOGICAL AND OPERATOR
+\u2A08 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A08\uDBFF\uDF74\uDBFF\uDF75 # TWO LOGICAL OR OPERATOR
+\u2A09 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A09\uDBFF\uDF87\uDBFF\uDF88 # N-ARY TIMES OPERATOR
+\u2A0C = \uFFFD\uFFFD\uFFFD\uFFFD\u2A0C\uDBFF\uDF1F\uDBFF\uDF20\uDBFF\uDF21 # QUADRUPLE INTEGRAL OPERATOR
+\u2A0D = \uFFFD\uFFFD\uFFFD\uFFFD\u2A0D\uDBFF\uDF22\uDBFF\uDF23\uDBFF\uDF24 # FINITE PART INTEGRAL
+\u2A0E = \uFFFD\uFFFD\uFFFD\uFFFD\u2A0E\uDBFF\uDF25\uDBFF\uDF26\uDBFF\uDF27 # INTEGRAL WITH DOUBLE STROKE
+\u2A0F = \uFFFD\uFFFD\uFFFD\uFFFD\u2A0F\uDBFF\uDF28\uDBFF\uDF29\uDBFF\uDF2A # INTEGRAL AVERAGE WITH SLASH
+\u2A10 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A10\uDBFF\uDF2B\uDBFF\uDF2C\uDBFF\uDF2D # CIRCULATION FUNCTION
+\u2A11 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A11\uDBFF\uDF2E\uDBFF\uDF2F\uDBFF\uDF30 # ANTICLOCKWISE INTEGRATION
+\u2A12 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A12\uDBFF\uDF31\uDBFF\uDF32\uDBFF\uDF33 # LINE INTEGRATION WITH RECTANGULAR PATH AROUND POLE
+\u2A13 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A13\uDBFF\uDF34\uDBFF\uDF35\uDBFF\uDF36 # LINE INTEGRATION WITH SEMICIRCULAR PATH AROUND POLE
+\u2A14 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A14\uDBFF\uDF37\uDBFF\uDF38\uDBFF\uDF39 # LINE INTEGRATION NOT INCLUDING THE POLE
+\u2A15 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A15\uDBFF\uDF3A\uDBFF\uDF3B\uDBFF\uDF3C # INTEGRAL AROUND A POINT OPERATOR
+\u2A16 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A16\uDBFF\uDF3D\uDBFF\uDF3E\uDBFF\uDF3F # QUATERNION INTEGRAL OPERATOR
+\u2A17 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A17\uDBFF\uDF40\uDBFF\uDF41\uDBFF\uDF42 # INTEGRAL WITH LEFTWARDS ARROW WITH HOOK
+\u2A18 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A18\uDBFF\uDF43\uDBFF\uDF44\uDBFF\uDF45 # INTEGRAL WITH TIMES SIGN
+\u2A19 = \uFFFD\uFFFD\uFFFD\uFFFD\u2A19\uDBFF\uDF46\uDBFF\uDF47\uDBFF\uDF48 # INTEGRAL WITH INTERSECTION
+\u2A1A = \uFFFD\uFFFD\uFFFD\uFFFD\u2A1A\uDBFF\uDF49\uDBFF\uDF4A\uDBFF\uDF4B # INTEGRAL WITH UNION
+\u2A1B = \uFFFD\uFFFD\uFFFD\uFFFD\u2A1B\uDBFF\uDF4C\uDBFF\uDF4D\uDBFF\uDF4E # INTEGRAL WITH OVERBAR
+\u2A1C = \uFFFD\uFFFD\uFFFD\uFFFD\u2A1C\uDBFF\uDF4F\uDBFF\uDF50\uDBFF\uDF51 # INTEGRAL WITH UNDERBAR
+
+\u005E = \uFFFD\uFFFD\uFFFD\uFFFD\u005E\uDBFF\uDFA6\uDBFF\uDFA7\uDBFF\uDFA8 # CIRCUMFLEX ACCENT
+\u0302 = \uFFFD\uFFFD\uFFFD\uFFFD\u005E\uDBFF\uDFA6\uDBFF\uDFA7\uDBFF\uDFA8 # COMBINING CIRCUMFLEX ACCENT
+\u007E = \uFFFD\uFFFD\uFFFD\uFFFD\u007E\uDBFF\uDFAA\uDBFF\uDFAB\uDBFF\uDFAC\uDBFF\uDFAD # TILDE
+\u02DC = \uFFFD\uFFFD\uFFFD\uFFFD\u007E\uDBFF\uDFAA\uDBFF\uDFAB\uDBFF\uDFAC\uDBFF\uDFAD # SMALL TILDE
+# \u0303 = \uFFFD\uFFFD\uFFFD\uFFFD\u007E\uDBFF\uDFAA\uDBFF\uDFAB\uDBFF\uDFAC\uDBFF\uDFAD # COMBINING TILDE (*)
+# \u0305 = \uFFFD\uFFFD\uFFFD\uDBFF\uDF1E\u0305 COMBINING OVERLINE (*)
+# \u0306 = \uFFFD\uFFFD\uFFFD\uFFFD\u02D8\uDBFF\uDFB2\uDBFF\uDFB3\uDBFF\uDFB4\uDBFF\uDFB5 # COMBINING BREVE (*)
+# \u02D8 = \uFFFD\uFFFD\uFFFD\uFFFD\u02D8\uDBFF\uDFB2\uDBFF\uDFB3\uDBFF\uDFB4\uDBFF\uDFB5 # BREVE (not stretchy)
+\u02C7 = \uFFFD\uFFFD\uFFFD\uFFFD\u02C7\uDBFF\uDFAE\uDBFF\uDFAF\uDBFF\uDFB0\uDBFF\uDFB1 # CARON
+# \u030C = \uFFFD\uFFFD\uFFFD\uFFFD\u02C7\uDBFF\uDFAE\uDBFF\uDFAF\uDBFF\uDFB0\uDBFF\uDFB1 # COMBINING CARON (*)
+# \u0332 = \uFFFD\uFFFD\uFFFD\uDBFF\uDF1D\u0332\uDBFF\uDF1D\uDBFF\uDF18\uDBFF\uDF14 # COMBINING LOW LINE (*)
+# \u0333 = \uFFFD\uFFFD\uFFFD\uDBFF\uDF1C\u0333\uDBFF\uDF1C\uDBFF\uDF17\uDBFF\uDF13 # COMBINING DOUBLE LOW LINE (*)
+# \u033F = \uFFFD\uFFFD\uFFFD\uDBFF\uDF1B\u033F\uDBFF\uDF1B\uDBFF\uDF16\uDBFF\uDF12 # COMBINING DOUBLE OVERLINE (*)
+# \u20D0 = \u20D0\uFFFD\uFFFD\uDBFF\uDF1A\u20D0 # COMBINING LEFT HARPOON ABOVE (*)
+# \u20D1 = \uFFFD\uFFFD\u20D1\uDBFF\uDF1A\u20D1 # COMBINING RIGHT HARPOON ABOVE (*)
+# \u20D6 = \u20D6\uFFFD\uFFFD\uDBFF\uDF1A\u20D6\uDBFF\uDE4A\uDBFF\uDE4B\uDBFF\uDE4C\uDBFF\uDE4D # COMBINING LEFT ARROW ABOVE (*)
+# \u20D7 = \uFFFD\uFFFD\u20D7\uDBFF\uDF1A\u20D7\uDBFF\uDE4E\uDBFF\uDE4F\uDBFF\uDE50\uDBFF\uDE51 # COMBINING RIGHT ARROW ABOVE (*)
+# \u20E1 = \u20D6\uFFFD\u20D7\uDBFF\uDF1A\u20E1 # COMBINING LEFT RIGHT ARROW ABOVE (*)
+# \u20E9 = \uDBFF\uDEEC\uFFFD\uDBFF\uDEED\uDBFF\uDEEB\u20E9 # COMBINING WIDE BRIDGE ABOVE (*)
+
+\u2190 = \uDBFF\uDF11\uFFFD\uDBFF\uDF10\u23AF\u2190 # LEFTWARDS ARROW 
+\u2192 = \uDBFF\uDF0E\uFFFD\uDBFF\uDF0F\u23AF\u2192 # RIGHTWARDS ARROW
+\u2194 = \uDBFF\uDF11\uFFFD\uDBFF\uDF0F\u23AF\u2194 # LEFT RIGHT ARROW
+\u21A4 = \uDBFF\uDF11\uFFFD\uDBFF\uDF08\u23AF\u21A4 # LEFTWARDS ARROW FROM BAR
+\u21A6 = \uDBFF\uDF07\uFFFD\uDBFF\uDF0F\u23AF\u21A6 # RIGHTWARDS ARROW FROM BAR
+\u21A9 = \uDBFF\uDF11\uFFFD\uDBFF\uDF06\u23AF\u21A9 # LEFTWARDS ARROW WITH HOOK
+\u21AA = \uDBFF\uDF05\uFFFD\uDBFF\uDF0F\u23AF\u21AA # RIGHTWARDS ARROW WITH HOOK
+
+\u21D0 = \uDBFF\uDF0D\uFFFD\uDBFF\uDF0C\uDBFF\uDF09\u21D0 # LEFTWARDS DOUBLE ARROW
+\u21D2 = \uDBFF\uDF0A\uFFFD\uDBFF\uDF0B\uDBFF\uDF09\u21D2 # RIGHTWARDS DOUBLE ARROW
+\u21D4 = \uDBFF\uDF0D\uFFFD\uDBFF\uDF0B\uDBFF\uDF09\u21D4 # LEFT RIGHT DOUBLE ARROW
+
+\u23B4 = \uDBFF\uDEEC\uFFFD\uDBFF\uDEED\uDBFF\uDEEB\u23B4\uDBFF\uDEFD\uDBFF\uDEFE\uDBFF\uDEFF # TOP SQUARE BRACKET
+\u23B5 = \uDBFF\uDEEE\uFFFD\uDBFF\uDEEF\uDBFF\uDEEA\u23B5\uDBFF\uDF00\uDBFF\uDF01\uDBFF\uDF02 # BOTTOM SQUARE BRACKET
+
+\u23DC = \uDBFF\uDFC7\uFFFD\uDBFF\uDFC9\uDBFF\uDFCA\u23DC\uDBFF\uDEF7\uDBFF\uDEF8\uDBFF\uDEF9 # TOP PARENTHESIS
+\uFE35 = \uDBFF\uDFC7\uFFFD\uDBFF\uDFC9\uDBFF\uDFCA\u23DC\uDBFF\uDEF7\uDBFF\uDEF8\uDBFF\uDEF9 # &OverParenthesis; (MathML 2.0)
+\u23DD = \uDBFF\uDFCB\uFFFD\uDBFF\uDFCD\uDBFF\uDEF0\u23DD\uDBFF\uDEFA\uDBFF\uDEFB\uDBFF\uDEFC # BOTTOM PARENTHESIS
+\uFE36 = \uDBFF\uDFCB\uFFFD\uDBFF\uDFCD\uDBFF\uDEF0\u23DD\uDBFF\uDEFA\uDBFF\uDEFB\uDBFF\uDEFC # &UnderParenthesis; (MathML 2.0)
+
+\u23DE = \uDBFF\uDFC7\uDBFF\uDFC8\uDBFF\uDFC9\uDBFF\uDFCA\u23DE\uDBFF\uDFC1\uDBFF\uDFC2\uDBFF\uDFC3 # TOP CURLY BRACKET
+\uFE37 = \uDBFF\uDFC7\uDBFF\uDFC8\uDBFF\uDFC9\uDBFF\uDFCA\u23DE\uDBFF\uDFC1\uDBFF\uDFC2\uDBFF\uDFC3 # &OverBrace; (MathML 2.0)
+\u23DF = \uDBFF\uDFCB\uDBFF\uDFCC\uDBFF\uDFCD\uDBFF\uDEF0\u23DF\uDBFF\uDFC4\uDBFF\uDFC5\uDBFF\uDFC6 # BOTTOM CURLY BRACKET
+\uFE38 = \uDBFF\uDFCB\uDBFF\uDFCC\uDBFF\uDFCD\uDBFF\uDEF0\u23DF\uDBFF\uDFC4\uDBFF\uDFC5\uDBFF\uDFC6 # &UnderBrace; (MathML 2.0)
+\u23E0 = \uFFFD\uFFFD\uFFFD\uFFFD\u23E0\uDBFF\uDEF1\uDBFF\uDEF2\uDBFF\uDEF3 # TOP TORTOISE SHELL BRACKET
+\u23E1 = \uFFFD\uFFFD\uFFFD\uFFFD\u23E1\uDBFF\uDEF4\uDBFF\uDEF5\uDBFF\uDEF6 # BOTTOM TORTOISE SHELL BRACKET
+
+\u2906 = \uDBFF\uDF0D\uFFFD\uDBFF\uDF04\uDBFF\uDF09\u2906 # LEFTWARDS DOUBLE ARROW FROM BAR
+\u2907 = \uDBFF\uDF03\uFFFD\uDBFF\uDF0B\uDBFF\uDF09\u2907 # RIGHTWARDS DOUBLE ARROW FROM BAR
--- a/layout/mathml/mathfontSTIXSizeOneSym.properties
+++ b/layout/mathml/mathfontSTIXSizeOneSym.properties
@@ -44,18 +44,17 @@
 # can be rendered with STIXSize* set of fonts,
 # with some help from STIXNonUnicode, STIXGeneral and STIXIntegralsD.
 
 external.1 = STIXNonUnicode
 external.2 = STIXSizeTwoSym
 external.3 = STIXSizeThreeSym
 external.4 = STIXSizeFourSym
 external.5 = STIXSizeFiveSym
-external.6 = STIXGeneral
-external.7 = STIXIntegralsD
+external.6 = STIXIntegralsD
 
 #        [ T/L |  M  | B/R |  G  | size0 ... size{N-1} ]
 \u0028 = \u239B\uFFFD\u239D\u239C\uFFFD((@2(@3(@4 # (
 \u0029 = \u239E\uFFFD\u23A0\u239F\uFFFD))@2)@3)@4 # )
 \u005B = \u23A1\uFFFD\u23A3\u23A2\u005B[[@2[@3[@4 # [
 \u005D = \u23A4\uFFFD\u23A6\u23A5\u005D]]@2]@3]@4 # ]
 \u007B = \u23A7\u23A8\u23A9\u23AA\u007B{{@2{@3{@4 # {
 \u007D = \u23AB\u23AC\u23AD\u23AA\u007D}}@2}@3}@4 # }
@@ -79,43 +78,43 @@ external.7 = STIXIntegralsD
 \u2A09 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A09 # N-ARY TIMES OPERATOR
 \u2AFF = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2AFF # N-ARY WHITE VERTICAL BAR
 
 # E000 stix-radical symbol vertical extender
 # E001 stix-radical symbol top corner
 \u221A = \uE001@1\uFFFD\u221A@4\uE000@1\uFFFD\u221A\u221A@2\u221A@3 # Sqrt, radic
 
 # Integrals
-\u222B = \u2320\uFFFD\u2321\u23AE\uFFFD\u222B@6\u222B@7
-\u222C = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u222C@6\u222C@7
-\u222D = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u222D@6\u222D@7
-\u222E = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u222E@6\u222E@7
-\u222F = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u222F@6\u222F@7
-\u2230 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2230@6\u2230@7
-\u2231 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2231@6\u2231@7
-\u2232 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2232@6\u2232@7
-\u2233 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2233@6\u2233@7
-\u2A0B = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A0B@6\u2A0B@7
-\u2A0C = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A0C@6\u2A0C@7
-\u2A0D = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A0D@6\u2A0D@7
-\u2A0E = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A0E@6\u2A0E@7
-\u2A0F = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A0F@6\u2A0F@7
-\u2A10 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A10@6\u2A10@7
-\u2A11 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A11@6\u2A11@7
-\u2A12 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A12@6\u2A12@7
-\u2A13 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A13@6\u2A13@7
-\u2A14 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A14@6\u2A14@7
-\u2A15 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A15@6\u2A15@7
-\u2A16 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A16@6\u2A16@7
-\u2A17 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A17@6\u2A17@7
-\u2A18 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A18@6\u2A18@7
-\u2A19 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A19@6\u2A19@7
-\u2A1A = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A1A@6\u2A1A@7
-\u2A1B = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A1B@6\u2A1B@7
-\u2A1C = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A1C@6\u2A1C@7
+\u222B = \u2320\uFFFD\u2321\u23AE\uFFFD\u222B@6
+\u222C = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u222C@6
+\u222D = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u222D@6
+\u222E = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u222E@6
+\u222F = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u222F@6
+\u2230 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2230@6
+\u2231 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2231@6
+\u2232 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2232@6
+\u2233 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2233@6
+\u2A0B = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A0B@6
+\u2A0C = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A0C@6
+\u2A0D = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A0D@6
+\u2A0E = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A0E@6
+\u2A0F = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A0F@6
+\u2A10 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A10@6
+\u2A11 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A11@6
+\u2A12 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A12@6
+\u2A13 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A13@6
+\u2A14 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A14@6
+\u2A15 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A15@6
+\u2A16 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A16@6
+\u2A17 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A17@6
+\u2A18 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A18@6
+\u2A19 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A19@6
+\u2A1A = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A1A@6
+\u2A1B = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A1B@6
+\u2A1C = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u2A1C@6
 
 \u27E8 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u27E8\u27E8@2\u27E8@3\u27E8@4 # LeftAngleBracket
 \u27E9 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u27E9\u27E9@2\u27E9@3\u27E9@4 # RightAngleBracket
 
 \u23DE = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u23DE\u23DE@2\u23DE@3\u23DE@4\u23DE@5 # &OverBrace; (Unicode)
 \uFE37 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u23DE\u23DE@2\u23DE@3\u23DE@4\u23DE@5 # &OverBrace; (MathML 2.0)
 \u23B4 = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u23B4\u23B4@2\u23B4@3\u23B4@4\u23B4@5 # &OverBracket;
 \u23DC = \uFFFD\uFFFD\uFFFD\uFFFD\uFFFD\u23DC\u23DC@2\u23DC@3\u23DC@4\u23DC@5 # &OverParenthesis; (Unicode)
--- a/layout/mathml/nsMathMLChar.cpp
+++ b/layout/mathml/nsMathMLChar.cpp
@@ -69,17 +69,17 @@
 
 using namespace mozilla;
 
 //#define SHOW_BORDERS 1
 //#define NOISY_SEARCH 1
 
 // -----------------------------------------------------------------------------------
 static const PRUnichar   kSpaceCh   = PRUnichar(' ');
-static const nsGlyphCode kNullGlyph = {0, 0};
+static const nsGlyphCode kNullGlyph = {{0, 0}, 0};
 typedef enum {eExtension_base, eExtension_variants, eExtension_parts}
   nsMathfontPrefExtension;
 
 // -----------------------------------------------------------------------------------
 // nsGlyphTable is a class that provides an interface for accessing glyphs
 // of stretchy chars. It acts like a table that stores the variants of bigger
 // sizes (if any) and the partial glyphs needed to build extensible symbols.
 // An instance of nsGlyphTable is associated to one primary font. Extra glyphs
@@ -243,18 +243,18 @@ private:
   // that char. For a property line 'key = value' in the MathFont Property File,
   // mCharCache will retain the 'key' -- which is a Unicode point, while mGlyphCache
   // will retain the 'value', which is a consecutive list of nsGlyphCodes, i.e.,
   // the pairs of 'code@font' needed by the char -- in which 'code@0' can be specified
   // without the optional '@0'. However, to ease subsequent processing, mGlyphCache
   // excludes the '@' symbol and explicitly inserts all optional '0' that indicates
   // the primary font identifier. Specifically therefore, the k-th glyph is
   // characterized by :
-  // 1) mGlyphCache[2*k] : its Unicode point (or glyph index -- depending on mType),
-  // 2) mGlyphCache[2*k+1] : the numeric identifier of the font where it comes from.
+  // 1) mGlyphCache[3*k],mGlyphCache[3*k+1] : its Unicode point (or glyph index -- depending on mType),
+  // 2) mGlyphCache[3*k+2] : the numeric identifier of the font where it comes from.
   // A font identifier of '0' means the default primary font associated to this
   // table. Other digits map to the "external" fonts that may have been specified
   // in the MathFont Property File.
   nsString  mGlyphCache;
   PRUnichar mCharCache;
 };
 
 nsGlyphCode
@@ -306,26 +306,26 @@ nsGlyphTable::ElementAt(nsPresContext* a
     nsAutoString value;
     nsresult rv = mGlyphProperties->GetStringProperty(nsDependentCString(key), value);
     if (NS_FAILED(rv)) return kNullGlyph;
     Clean(value);
     // See if this char uses external fonts; e.g., if the 2nd glyph is taken from the
     // external font '1', the property line looks like \uNNNN = \uNNNN\uNNNN@1\uNNNN.
     // This is where mGlyphCache is pre-processed to explicitly store all glyph codes
     // as combined pairs of 'code@font', excluding the '@' separator. This means that
-    // mGlyphCache[2*k] will later be rendered with mFontName[mGlyphCache[2*k+1]]
+    // mGlyphCache[3*k],mGlyphCache[3*k+1] will later be rendered with mFontName[mGlyphCache[3*k+2]]
     // Note: font identifier is internally an ASCII digit to avoid the null char issue
     nsAutoString buffer;
     PRInt32 length = value.Length();
     PRInt32 i = 0; // index in value
     PRInt32 j = 0; // part/variant index
     while (i < length) {
       PRUnichar code = value[i];
       ++i;
-      PRUnichar font = 0;
+      buffer.Append(code);
       // see if we are at the beginning of a child char
       if (code == kSpaceCh) {
         // reset the annotation indicator to be 0 for the next code point
         j = -1;
       }
 #if 0 // If we want this then the nsGlyphTableList must be declared
       // or the UnicodeTable could be made a global.
       // See if this code point is an *indirect reference* to the Unicode
@@ -341,33 +341,42 @@ nsGlyphTable::ElementAt(nsPresContext* a
         ++i;
         // Need to implement this if we want it:
         // Set (new) code from the value[i] position for (current) code.
         if (1)
           return kNullGlyph;
         ++i;
       }
 #endif
+      // Read the next word if we have a non-BMP character.
+      if (i < length && NS_IS_HIGH_SURROGATE(code)) {
+        code = value[i];
+        ++i;
+      } else {
+        code = PRUnichar('\0');
+      }
+      buffer.Append(code);
+
       // See if an external font is needed for the code point.
       // Limit of 9 external fonts
+      PRUnichar font = 0;
       if (i+1 < length && value[i] == PRUnichar('@') &&
           value[i+1] >= PRUnichar('0') && value[i+1] <= PRUnichar('9')) {
         ++i;
         font = value[i] - '0';
         ++i;
         if (font >= mFontName.Length()) {
           NS_ERROR("Nonexistent font referenced in glyph table");
           return kNullGlyph;
         }
         // The char cannot be handled if this font is not installed
         if (!mFontName[font].Length()) {
           return kNullGlyph;
         }
       }
-      buffer.Append(code);
       buffer.Append(font);
       ++j;
     }
     // update our cache with the new settings
     mGlyphCache.Assign(buffer);
     mCharCache = uchar;
   }
 
@@ -385,38 +394,39 @@ nsGlyphTable::ElementAt(nsPresContext* a
   PRUint32 length = mGlyphCache.Length();
   if (aChar->mParent) {
     nsMathMLChar* child = aChar->mParent->mSibling;
     // XXXkt composite chars can't have size variants
     while (child && (child != aChar)) {
       offset += 5; // skip the 4 partial glyphs + the whitespace separator
       child = child->mSibling;
     }
-    length = 2*(offset + 4); // stay confined in the 4 partial glyphs of this child
+    length = 3*(offset + 4); // stay confined in the 4 partial glyphs of this child
   }
-  PRUint32 index = 2*(offset + aPosition); // 2* is to account for the code@font pairs
-  if (index+1 >= length) return kNullGlyph;
+  PRUint32 index = 3*(offset + aPosition); // 3* is to account for the code@font pairs
+  if (index+2 >= length) return kNullGlyph;
   nsGlyphCode ch;
-  ch.code = mGlyphCache.CharAt(index);
-  ch.font = mGlyphCache.CharAt(index + 1);
-  return (ch.code == PRUnichar(0xFFFD)) ? kNullGlyph : ch;
+  ch.code[0] = mGlyphCache.CharAt(index);
+  ch.code[1] = mGlyphCache.CharAt(index + 1);
+  ch.font = mGlyphCache.CharAt(index + 2);
+  return ch.code[0] == PRUnichar(0xFFFD) ? kNullGlyph : ch;
 }
 
 PRBool
 nsGlyphTable::IsComposite(nsPresContext* aPresContext, nsMathMLChar* aChar)
 {
   // there is only one level of recursion in our model. a child
   // cannot be composite because it cannot have its own children
   if (aChar->mParent) return PR_FALSE;
   // shortcut to sync the cache with this char...
   mCharCache = 0; mGlyphCache.Truncate(); ElementAt(aPresContext, aChar, 0);
   // the cache remained empty if the char wasn't found in this table
-  if (8 >= mGlyphCache.Length()) return PR_FALSE;
+  if (4*3 >= mGlyphCache.Length()) return PR_FALSE;
   // the lists of glyphs of a composite char are space-separated
-  return (kSpaceCh == mGlyphCache.CharAt(8));
+  return (kSpaceCh == mGlyphCache.CharAt(4*3));
 }
 
 PRInt32
 nsGlyphTable::ChildCountOf(nsPresContext* aPresContext, nsMathMLChar* aChar)
 {
   // this will sync the cache as well ...
   if (!IsComposite(aPresContext, aChar)) return 0;
   // the lists of glyphs of a composite char are space-separated
@@ -1119,37 +1129,36 @@ nsMathMLChar::StretchEnumContext::TryVar
     largeop && (NS_STRETCH_VARIABLE_MASK & mStretchHint) == 0;
   PRBool maxWidth = (NS_STRETCH_MAXWIDTH & mStretchHint) != 0;
 
   nscoord bestSize =
     isVertical ? mBoundingMetrics.ascent + mBoundingMetrics.descent
                : mBoundingMetrics.rightBearing - mBoundingMetrics.leftBearing;
   PRBool haveBetter = PR_FALSE;
 
-  // figure out the starting size : if this is a largeop, start at 2 else 1
-  PRInt32 size = 1; // size=0 is the char at its normal size
-  if (largeop && aGlyphTable->BigOf(mPresContext, mChar, 2).Exists()) {
-    size = 2;
-  }
+  // start at size = 1 (size = 0 is the char at its normal size)
+  PRInt32 size = 1;
 #ifdef NOISY_SEARCH
   printf("  searching in %s ...\n",
            NS_LossyConvertUTF16toASCII(aFamily).get());
 #endif
 
   nsGlyphCode ch;
   while ((ch = aGlyphTable->BigOf(mPresContext, mChar, size)).Exists()) {
 
     SetFontFamily(mChar->mStyleContext->PresContext(), mRenderingContext,
                   font, aGlyphTable, ch, aFamily);
 
-    NS_ASSERTION(maxWidth || ch.code != mChar->mGlyph.code ||
+    NS_ASSERTION(maxWidth || ch.code[0] != mChar->mGlyph.code[0] ||
+                 ch.code[1] != mChar->mGlyph.code[1] ||
                  !font.name.Equals(mChar->mFamily),
                  "glyph table incorrectly set -- duplicate found");
 
-    nsBoundingMetrics bm = mRenderingContext.GetBoundingMetrics(&ch.code, 1);
+    nsBoundingMetrics bm = mRenderingContext.GetBoundingMetrics(ch.code,
+                                                                ch.Length());
     nscoord charSize =
       isVertical ? bm.ascent + bm.descent
       : bm.rightBearing - bm.leftBearing;
 
     if (largeopOnly ||
         IsSizeBetter(charSize, bestSize, mTargetSize, mStretchHint)) {
       mGlyphFound = PR_TRUE;
       if (maxWidth) {
@@ -1257,17 +1266,18 @@ nsMathMLChar::StretchEnumContext::TryPar
     if (!ch.Exists()) {
       // Null glue indicates that a rule will be drawn, which can stretch to
       // fill any space.  Leave bounding metrics at 0.
       sizedata[i] = mTargetSize;
     }
     else {
       SetFontFamily(mChar->mStyleContext->PresContext(), mRenderingContext,
                     font, aGlyphTable, ch, aFamily);
-      nsBoundingMetrics bm = mRenderingContext.GetBoundingMetrics(&ch.code, 1);
+      nsBoundingMetrics bm = mRenderingContext.GetBoundingMetrics(ch.code,
+                                                                  ch.Length());
 
       // TODO: For the generic Unicode table, ideally we should check that the
       // glyphs are actually found and that they each come from the same
       // font.
       bmdata[i] = bm;
       sizedata[i] = isVertical ? bm.ascent + bm.descent
                                : bm.rightBearing - bm.leftBearing;
     }
@@ -2061,17 +2071,18 @@ nsMathMLChar::PaintForeground(nsPresCont
     aRenderingContext.DrawString(mData.get(), len, 0, mUnscaledAscent);
   }
   else {
     // Grab some metrics to adjust the placements ...
     // if there is a glyph of appropriate size, paint that glyph
     if (mGlyph.Exists()) {
 //printf("Painting %04X with a glyph of appropriate size\n", mData[0]);
 //aRenderingContext.SetColor(NS_RGB(0,0,255));
-      aRenderingContext.DrawString(&mGlyph.code, 1, 0, mUnscaledAscent);
+      aRenderingContext.DrawString(mGlyph.code, mGlyph.Length(),
+                                   0, mUnscaledAscent);
     }
     else { // paint by parts
 //aRenderingContext.SetColor(NS_RGB(0,255,0));
       if (NS_STRETCH_DIRECTION_VERTICAL == mDirection)
         PaintVertically(aPresContext, aRenderingContext, theFont, styleContext,
                         mGlyphTable, r);
       else if (NS_STRETCH_DIRECTION_HORIZONTAL == mDirection)
         PaintHorizontally(aPresContext, aRenderingContext, theFont, styleContext,
@@ -2151,17 +2162,17 @@ nsMathMLChar::PaintVertically(nsPresCont
         break;
     }
     // empty slots are filled with the glue if it is not null
     if (!ch.Exists()) ch = chGlue;
     // if (!ch.Exists()) glue is null, leave bounding metrics at 0
     if (ch.Exists()) {
       SetFontFamily(aPresContext, aRenderingContext,
                     aFont, aGlyphTable, ch, mFamily);
-      bmdata[i] = aRenderingContext.GetBoundingMetrics(&ch.code, 1);
+      bmdata[i] = aRenderingContext.GetBoundingMetrics(ch.code, ch.Length());
     }
     chdata[i] = ch;
     ++i;
   }
   nscoord dx = aRect.x;
   nscoord offset[3], start[3], end[3];
   nsRefPtr<gfxContext> ctx = aRenderingContext.ThebesContext();
   for (i = 0; i <= bottom; ++i) {
@@ -2236,17 +2247,17 @@ nsMathMLChar::PaintVertically(nsPresCont
           clipRect.y = start[i];
           clipRect.height = end[i] - start[i];
         }
       }
       if (!clipRect.IsEmpty()) {
         AutoPushClipRect clip(aRenderingContext, clipRect);
         SetFontFamily(aPresContext, aRenderingContext,
                       aFont, aGlyphTable, ch, mFamily);
-        aRenderingContext.DrawString(&ch.code, 1, dx, dy);
+        aRenderingContext.DrawString(ch.code, ch.Length(), dx, dy);
       }
     }
   }
 
   ///////////////
   // fill the gap between top and middle, and between middle and bottom.
   if (!chGlue.Exists()) { // null glue : draw a rule
     // figure out the dimensions of the rule to be drawn :
@@ -2312,17 +2323,17 @@ nsMathMLChar::PaintVertically(nsPresCont
       aRenderingContext.DrawRect(clipRect);
       {
 #endif
       while (dy < fillEnd) {
         clipRect.y = dy;
         clipRect.height = NS_MIN(bm.ascent + bm.descent, fillEnd - dy);
         AutoPushClipRect clip(aRenderingContext, clipRect);
         dy += bm.ascent;
-        aRenderingContext.DrawString(&chGlue.code, 1, dx, dy);
+        aRenderingContext.DrawString(chGlue.code, chGlue.Length(), dx, dy);
         dy += bm.descent;
       }
 #ifdef SHOW_BORDERS
       }
       // last glyph that may cross past its boundary and collide with the next
       nscoord height = bm.ascent + bm.descent;
       aRenderingContext.SetColor(NS_RGB(0,255,0));
       aRenderingContext.DrawRect(nsRect(dx, dy-bm.ascent, aRect.width, height));
@@ -2379,17 +2390,17 @@ nsMathMLChar::PaintHorizontally(nsPresCo
         break;
     }
     // empty slots are filled with the glue if it is not null
     if (!ch.Exists()) ch = chGlue;
     // if (!ch.Exists()) glue is null, leave bounding metrics at 0.
     if (ch.Exists()) {
       SetFontFamily(aPresContext, aRenderingContext,
                     aFont, aGlyphTable, ch, mFamily);
-      bmdata[i] = aRenderingContext.GetBoundingMetrics(&ch.code, 1);
+      bmdata[i] = aRenderingContext.GetBoundingMetrics(ch.code, ch.Length());
     }
     chdata[i] = ch;
     ++i;
   }
   nscoord dy = aRect.y + mBoundingMetrics.ascent;
   nscoord offset[3], start[3], end[3];
   nsRefPtr<gfxContext> ctx = aRenderingContext.ThebesContext();
   for (i = 0; i <= right; ++i) {
@@ -2459,17 +2470,17 @@ nsMathMLChar::PaintHorizontally(nsPresCo
           clipRect.x = start[i];
           clipRect.width = end[i] - start[i];
         }
       }
       if (!clipRect.IsEmpty()) {
         AutoPushClipRect clip(aRenderingContext, clipRect);
         SetFontFamily(aPresContext, aRenderingContext,
                       aFont, aGlyphTable, ch, mFamily);
-        aRenderingContext.DrawString(&ch.code, 1, dx, dy);
+        aRenderingContext.DrawString(ch.code, ch.Length(), dx, dy);
       }
     }
   }
 
   ////////////////
   // fill the gap between left and middle, and between middle and right.
   if (!chGlue.Exists()) { // null glue : draw a rule
     // figure out the dimensions of the rule to be drawn :
@@ -2534,17 +2545,17 @@ nsMathMLChar::PaintHorizontally(nsPresCo
       aRenderingContext.DrawRect(clipRect);
       {
 #endif
       while (dx < fillEnd) {
         clipRect.x = dx;
         clipRect.width = NS_MIN(bm.rightBearing - bm.leftBearing, fillEnd - dx);
         AutoPushClipRect clip(aRenderingContext, clipRect);
         dx -= bm.leftBearing;
-        aRenderingContext.DrawString(&chGlue.code, 1, dx, dy);
+        aRenderingContext.DrawString(chGlue.code, chGlue.Length(), dx, dy);
         dx += bm.rightBearing;
       }
 #ifdef SHOW_BORDERS
       }
       // last glyph that may cross past its boundary and collide with the next
       nscoord width = bm.rightBearing - bm.leftBearing;
       aRenderingContext.SetColor(NS_RGB(0,255,0));
       aRenderingContext.DrawRect(nsRect(dx + bm.leftBearing, aRect.y, width, aRect.height));
--- a/layout/mathml/nsMathMLChar.h
+++ b/layout/mathml/nsMathMLChar.h
@@ -66,26 +66,28 @@ enum {
   NS_STRETCH_MAXWIDTH = 0x40
 };
 
 // A single glyph in our internal representation is characterized by a 'code@font' 
 // pair. The 'code' is interpreted as a Unicode point or as the direct glyph index
 // (depending on the type of nsGlyphTable where this comes from). The 'font' is a
 // numeric identifier given to the font to which the glyph belongs.
 struct nsGlyphCode {
-  PRUnichar code; 
+  PRUnichar code[2]; 
   PRInt32   font;
 
+  PRInt32 Length() { return (code[1] == PRUnichar('\0') ? 1 : 2); }
   PRBool Exists() const
   {
-    return (code != 0);
+    return (code[0] != 0);
   }
   PRBool operator==(const nsGlyphCode& other) const
   {
-    return other.code == code && other.font == font;
+    return (other.code[0] == code[0] && other.code[1] == code[1] && 
+            other.font == font);
   }
   PRBool operator!=(const nsGlyphCode& other) const
   {
     return ! operator==(other);
   }
 };
 
 // Class used to handle stretchy symbols (accent, delimiter and boundary symbols).
--- a/layout/reftests/reftest.list
+++ b/layout/reftests/reftest.list
@@ -84,16 +84,19 @@ include css-optional/reftest.list
 skip-if(Android) include css-valid/reftest.list
 
 # css invalid
 skip-if(Android) include css-invalid/reftest.list
 
 # css-submit-invalid
 include css-submit-invalid/reftest.list
 
+# css text-overflow
+include text-overflow/reftest.list
+
 # css transitions
 include css-transitions/reftest.list
 
 # css :-moz-ui-invalid
 skip-if(Android) include css-ui-invalid/reftest.list
 
 # css :-moz-ui-valid
 skip-if(Android) include css-ui-valid/reftest.list
new file mode 100644
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..4de40fbbb2287c1835ca723703543abf9c681106
GIT binary patch
literal 1224
zc$_QucXRU(3GruOU^&6S#Q+3sUl<q}umWc{Hw7T|g@J+58i+j}Yz$xN<`&}1z`$ex
z6qf<v*yENl{=xc2KrtU6-yMh(qOYV~NX|_x0E$fk@;!ligP5GzT{BV>Q-ER*fMP)P
z3}!!cMEo*<f(#7IB0#<z5UX&#W4V%%TT%fOGXe5>K$yFmK`1w|0%#ty1IWQ(%o4zm
zmzbLh6!QR@p9VB{?!gDGCkyh6OMrgc08}Fe#0vl07>q0Cxc2Y&KI|ZKbpL&|+=a(N
zj@~#JoF5Rtxpvpe#oHbzcpN>s^3oS}la*WAj~<M*Xm2RK7|NB`_gu`%ddJQe_J!Bg
zSTDQE_nX%|I9ScGi?3tG&JPijx6XN`m%t>zrNx~kDeAdG)c5HZcIMx6Uc6WNIaB4s
zELDbLmV3`Q*9hH-W5|uNYBY+GE1kntyz0xVY4gG&rq2tF%G>+6Vq5OzxXGp&E8lJm
z+8tc}BCf7I&rD*sorXx3;acC!ebJ|@`ELJ`{<2?3%t`E<qkGJKi!VC@TpOKweme<!
zyOdw$=9CXsdKJ0K;+^}^Ety4<3wBN3C+42e+V~}Pg4z8157zsVRzCK$+%=zP$?>bV
zG?oiZo>NkJMV9x<&lNJeZ2ok%J)AD3=DVm~r)c$ek?R#*(vp%#%y?d&_qadfFYAMe
zHKw3s08SkzJM#@e^eMT=6Cw1onH6)A6B2ix_|e)pwXtz!cP2kGvon87TFrrk6DL?i
zQWGAhG%&icsR&GXHtSG9gJYv&Q{=<_tj;2@LsLv0<}nEvF){S5=ZRqenUj!^){r2{
z=Ef%Qf$@{X!5T3(W`(niEj|uWjgI|_kN(%Qy#9aqfB3)kZLgS^-OSih^uijn&bv66
zG8qW3ElOZy*yq6A1#}n4tdxWVhDVPTFF!l}`F2g}gS0wEkwgpC?{7rrh$ST?+&o?-
zdg5t90#hdwL#!P41-PEQrw$wtI9ep=VYJ~5P{4uJhrzv$2`JBU5rP?CG6*p+1OPc8
zJ*^YYdL4EUX+3{KUejZu-NBp|uH0EE7hSitDmg8X-d!+#lBcxC<Vil7cYksyt*d33
ze=xk@?X9iZ<@0>nn>fs-@BDuH;gfsTj2Dh-v+$kgou|WH@*(vnPi|q}&PMIR{GFYB
z72EC{T3WIB&a!`=%QMP;e9PFkDsn+P|LOD{2ev<D%X7V6By9UJVJE9*oX+-@`;(i5
zxCBj#c{*9Yomm*Db*X1cV(-$APbFqdxS_Z-*>%>U1?zluUj|>Pu_%cAU6OH(jnS>=
zNY&)U*B?%4u~g5FVV)f18g;a2<MhNO+Lqm$zHSQnnP4zscgXrDTTXo4qA}g;SD*H8
z?X~6yGo}RiW?fw=q#izN?z=N9s?MH?Ik$Mq>yUIUwKg~JjZdEntg^Vf>0kNuhUfXG
zo8Kk&EVQ)S8)y6K`>aNrKDFw{4=Y~mo>!iA(sJvhdJWTR&u{B?TQ9q2ow)9lmTu9@
pUGpCAT4!_d1A9nT@dQZRq%k!AKg;9h&^3{fmw`belyN5m0{}{S>L~yK
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/anonymous-block-ref.html
@@ -0,0 +1,59 @@
+<!DOCTYPE HTML>
+<!--
+    Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/licenses/publicdomain/
+-->
+<html><head>
+<title>text-overflow: anonymous block</title>
+<style type="text/css">
+@font-face {
+  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:hidden;
+  width:50%;
+  height:10em;
+
+  border:1px solid black;
+  white-space:pre;
+  margin-left:2em;
+  margin-bottom:2em;
+  line-height:1.5em;
+}
+i {
+  display:inline-block;
+  height: 3em;
+  width: 5em;
+  background: blue;
+  font-style:normal;
+}
+span {
+  position:relative;
+  background:pink;
+  top:40px;
+  left:16em;
+}
+
+.t1 {width:6em;}
+.t2 {width:2em;}
+.t3 {width:25em;}
+.t4 {width:17.5em;}
+
+</style>
+
+</head><body>
+
+
+<div class="test t1"><x>Some ove<m>&#x2026;</m><span><i style="display:block;">anonymous<br>block</i>and</span> unin<m>&#x2026;</m></x></div>
+<div class="test t2"><x>So<m>&#x2026;</m><i style="display:block;">anonymous<br>block</i>an<m>&#x2026;</m></x></div>
+<div style="position:absolute;"><div class="test t3" style="border-style:none;padding:1px"><x>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<m style="padding-left:16em">&#x2026;</m></div></div>
+<div class="test t3"><x>Some overly <span>l&nbsp;&nbsp;&nbsp;</span><span><i style="display:block;">anonymous<br>block</i>and</span> uninformative sentence</x></div>
+<div class="test t4"><x>Some overly <m>&#x2026;</m><span>long<i style="display:block;">anonymous<br>block</i>a&nbsp;&nbsp;</span> uninformative sentence</x></div>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/anonymous-block.html
@@ -0,0 +1,61 @@
+<!DOCTYPE HTML>
+<!--
+    Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/licenses/publicdomain/
+
+    Test: overflowing anonymous block should not have marker
+-->
+<html><head>
+<title>text-overflow: anonymous block</title>
+<style type="text/css">
+@font-face {
+  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 {
+  text-overflow:ellipsis;
+  overflow:hidden;
+  width:50%;
+  height:10em;
+
+  border:1px solid black;
+  white-space:pre;
+  margin-left:2em;
+  margin-bottom:2em;
+  line-height:1.5em;
+}
+i {
+  display:inline-block;
+  height: 3em;
+  width: 5em;
+  background: blue;
+  font-style:normal;
+}
+span {
+  position:relative;
+  background:pink;
+  top:40px;
+  left:16em;
+}
+
+.t1 {width:6em;}
+.t2 {width:2em;}
+.t3 {width:25em;}
+.t4 {width:17.5em;}
+
+</style>
+
+</head><body>
+
+
+<div class="test t1"><x>Some overly <span>long<i style="display:block;">anonymous<br>block</i>and</span> uninformative sentence</x></div>
+<div class="test t2"><x>Some overly long<i style="display:block;">anonymous<br>block</i>and uninformative sentence</x></div>
+<div class="test t3"><x>Some overly <span>long<i style="display:block;">anonymous<br>block</i>and</span> uninformative sentence</x></div>
+<div class="test t4"><x>Some overly <span>long<i style="display:block;">anonymous<br>block</i>and</span> uninformative sentence</x></div>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/bidi-simple-ref.html
@@ -0,0 +1,85 @@
+<!DOCTYPE HTML>
+<!--
+    Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/licenses/publicdomain/
+-->
+<html><head>
+<title>text-overflow: simple mixed-bidi cases</title>
+<style type="text/css">
+@font-face {
+  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;
+  white-space:nowrap;
+  width: 4.4em;
+  position:relative;
+  margin-top:1em;
+}
+
+.hidden {
+  overflow:hidden;
+  width: 4.7em;
+}
+
+.rlo {
+  unicode-bidi: bidi-override; direction: rtl;
+}
+.lro {
+  unicode-bidi: bidi-override; direction: ltr;
+}
+.rtl {
+  direction:rtl;
+}
+r {
+  position:absolute;
+  top:0; right:0;
+}
+l {
+  position:absolute;
+  top:0; left:0;
+}
+</style>
+
+</head><body>
+
+
+<!-- LTR overflow:scroll -->
+<div class="test"><r>&#x2026</r>AxxxxB&nbsp;&nbsp;<span class="rlo">HelloWor</span>Axxxx<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span></div>
+
+<div class="test"><r>&#x2026</r><span class="rlo">He&nbsp;&nbsp;oWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span></div>
+
+<div class="test"><r>&#x2026</r><span class="rlo">He&nbsp;&nbsp;oWorld</span></div>
+
+
+<!-- LTR overflow:hidden -->
+<div class="test hidden">AxxxxB<m>&#x2026</m><span class="rlo">HelloWorl&nbsp;</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span></div>
+
+<div class="test hidden"><span class="rlo">H&nbsp;&nbsp;<m>&#x2026</m>oWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span></div>
+
+<div class="test hidden"><span class="rlo">H&nbsp;&nbsp;<m>&#x2026</m>oWorld</span></div>
+
+<!-- RTL overflow:scroll -->
+<div class="test rtl"><l>&#x2026</l>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloW&nbsp;&nbsp;ld</span></div>
+
+<div class="test rtl"><l>&#x2026</l><span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloW&nbsp;&nbsp;ld</span></div>
+
+<div class="test rtl"><l>&#x2026</l><span class="rlo">HelloW&nbsp;&nbsp;ld</span></div>
+
+
+<!-- RTL overflow:hidden -->
+<div class="test rtl hidden">AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloW<m>&#x2026</m>&nbsp;&nbsp;&nbsp;</span></div>
+
+<div class="test rtl hidden"><span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloW<m>&#x2026</m>&nbsp;&nbsp;&nbsp;</span></div>
+
+<div class="test rtl hidden"><span class="rlo">HelloW<m>&#x2026</m>&nbsp;&nbsp;&nbsp;</span></div>
+
+
+
+
+</body></html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/bidi-simple-scrolled-ref.html
@@ -0,0 +1,106 @@
+<!DOCTYPE HTML>
+<!--
+    Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/licenses/publicdomain/
+-->
+<html class="reftest-wait"><head>
+<title>text-overflow: simple mixed-bidi cases</title>
+<style type="text/css">
+@font-face {
+  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;
+  white-space:nowrap;
+  width: 4.4em;
+  margin-bottom:1em;
+  position:relative;
+  line-height:2em;
+}
+
+.hidden {
+  overflow:hidden;
+  width: 4.7em;
+}
+
+.rlo {
+  unicode-bidi: bidi-override; direction: rtl;
+}
+.lro {
+  unicode-bidi: bidi-override; direction: ltr;
+}
+.rtl {
+  direction:rtl;
+}
+rr {
+  position:absolute;
+  bottom:0; right:8px;
+}
+r {
+  position:absolute;
+  bottom:0; right:-8px;
+}
+ll {
+  position:absolute;
+  bottom:0; left:8px;
+}
+l {
+  position:absolute;
+  bottom:0; left:-8px;
+}
+
+</style>
+<script>
+function scrolldivs() {
+ var divs = document.getElementsByTagName('div');
+  for (i = 0; i < divs.length; ++i) {
+    if (window.getComputedStyle(divs[i]).direction == 'ltr')
+      divs[i].scrollLeft = 8;
+    else
+      divs[i].scrollLeft = -8;
+  }
+  document.documentElement.removeAttribute('class');
+}
+</script>
+
+</head><body onload="scrolldivs()">
+
+<!-- LTR block -->
+
+<div class="test"><ll>&#x2026;</ll><r>&#x2026;</r>&nbsp;&nbsp;xxB&nbsp;<span class="rlo">&#x2026;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span>&nbsp;&nbsp;&nbsp;&nbsp;xxxx<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span></div>
+
+<div class="test"><ll>&#x2026;</ll><r>&#x2026;</r><span class="rlo">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Wor&nbsp;&nbsp;</span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;B<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span></div>
+
+<div class="test"><ll>&#x2026;</ll><r>&#x2026;</r><span class="rlo">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Wor&nbsp;&nbsp;</span></div>
+
+<!-- RTL block -->
+<div class="test rtl"><rr>&#x2026;</rr><l>&#x2026;</l>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">&nbsp;&nbsp;llo&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></div>
+
+<div class="test rtl"><rr>&#x2026;</rr><l>&#x2026;</l><span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">&nbsp;&nbsp;llo&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></div>
+
+<div class="test rtl"><rr>&#x2026;</rr><l>&#x2026;</l><span class="rlo">&nbsp;&nbsp;llo&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></div>
+
+
+<div class="test rtl hidden">AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">&nbsp;&#x2026;lloWo&#x2026;&nbsp;&nbsp;</span></div>
+
+<div class="test rtl hidden"><span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">&nbsp;&#x2026;lloWo&#x2026;&nbsp;&nbsp;</span></div>
+
+<div class="test rtl hidden"><span class="rlo">&nbsp;&#x2026;lloWo&#x2026;&nbsp;&nbsp;</span></div>
+
+
+<div class="test hidden">&nbsp;&#x2026;xxxB<span class="rlo">Hello&nbsp;&nbsp;&nbsp;&#x2026;d</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span></div>
+
+<div class="test hidden"><span class="rlo">&nbsp;&nbsp;&#x2026;loWor&#x2026;&nbsp;</span>&nbsp;xxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span></div>
+
+<div class="test hidden"><span class="rlo">&nbsp;&nbsp;&#x2026;loWor&#x2026;&nbsp;</span></div>
+
+<span style="position:absolute; top:0; left:6em; height:6em; overflow:hidden;">
+<div class="test rtl"><br><br><rr>&#x2026;</rr><l>&#x2026;</l><span class="rlo">&nbsp;&nbsp;lloW&nbsp;&nbsp;&nbsp;&nbsp;HelloWorldHelloWorldHelloWorldHelloWorldHelloWorldHelloWorldHelloWorld</span></div>
+</span>
+
+</body></html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/bidi-simple-scrolled.html
@@ -0,0 +1,98 @@
+<!DOCTYPE HTML>
+<!--
+    Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/licenses/publicdomain/
+
+    Test: Simple bidi cases, scrolled a bit from the start position
+-->
+<html class="reftest-wait"><head>
+<title>text-overflow: simple mixed-bidi cases, scrolled a bit from the start position</title>
+<style type="text/css">
+@font-face {
+  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;
+  white-space:nowrap;
+  width: 4.4em;
+  margin-bottom:1em;
+  position:relative;
+  line-height:2em;
+}
+
+.hidden {
+  overflow:hidden;
+  width: 4.7em;
+}
+
+.rlo {
+  unicode-bidi: bidi-override; direction: rtl;
+}
+.lro {
+  unicode-bidi: bidi-override; direction: ltr;
+}
+.rtl {
+  direction:rtl;
+}
+.ltr {
+  direction:ltr;
+}
+
+</style>
+<script>
+function scrolldivs() {
+ var divs = document.getElementsByTagName('div');
+  for (i = 0; i < divs.length; ++i) {
+    if (window.getComputedStyle(divs[i]).direction == 'ltr')
+      divs[i].scrollLeft = 8;
+    else
+      divs[i].scrollLeft = -8;
+  }
+  document.documentElement.removeAttribute('class');
+}
+</script>
+
+</head><body onload="scrolldivs()">
+
+<!-- LTR block -->
+
+<div class="test ltr">AxxxB&nbsp;<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span></div>
+
+<div class="test ltr"><span class="rlo">Hell&nbsp;World</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span></div>
+
+<div class="test ltr"><span class="rlo">Hell&nbsp;World</span></div>
+
+
+<!-- RTL block -->
+<div class="test rtl">AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">Hello&nbsp;orld</span></div>
+
+<div class="test rtl"><span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">Hello&nbsp;orld</span></div>
+
+<div class="test rtl"><span class="rlo">Hello&nbsp;orld</span></div>
+
+
+<div class="test rtl hidden">AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span></div>
+
+<div class="test rtl hidden"><span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span></div>
+
+<div class="test rtl hidden"><span class="rlo">HelloWorld</span></div>
+
+<!-- LTR block -->
+
+
+<div class="test ltr hidden">AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span></div>
+
+<div class="test ltr hidden"><span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span></div>
+
+<div class="test ltr hidden"><span class="rlo">HelloWorld</span></div>
+
+<span style="position:absolute; top:0; left:6em; height:6em; overflow:hidden;">
+<div class="test rtl"><br><br><span class="rlo">HelloWorldHelloWorldHelloWorldHelloWorldHelloWorldHelloWorldHelloWorldHelloWorld</span></div>
+</span>
+
+</body></html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/bidi-simple.html
@@ -0,0 +1,81 @@
+<!DOCTYPE HTML>
+<!--
+    Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/licenses/publicdomain/
+
+    Test: Simple bidi cases
+-->
+<html><head>
+<title>text-overflow: simple mixed-bidi cases</title>
+<style type="text/css">
+@font-face {
+  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;
+  white-space:nowrap;
+  width: 4.4em;
+  position:relative;
+  margin-top:1em;
+}
+
+.hidden {
+  overflow:hidden;
+  width: 4.7em;
+}
+
+.rlo {
+  unicode-bidi: bidi-override; direction: rtl;
+}
+.lro {
+  unicode-bidi: bidi-override; direction: ltr;
+}
+.rtl {
+  direction:rtl;
+}
+
+</style>
+
+</head><body>
+
+<!-- LTR overflow:scroll -->
+
+<div class="test">AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span></div>
+
+<div class="test"><span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span></div>
+
+<div class="test"><span class="rlo">HelloWorld</span></div>
+
+<!-- LTR overflow:hidden -->
+<div class="test hidden">AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span></div>
+
+<div class="test hidden"><span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span></div>
+
+<div class="test hidden"><span class="rlo">HelloWorld</span></div>
+
+<!-- RTL overflow:scroll -->
+
+<div class="test rtl">AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span></div>
+
+<div class="test rtl"><span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span></div>
+
+<div class="test rtl"><span class="rlo">HelloWorld</span></div>
+
+
+<!-- RTL overflow:hidden -->
+<div class="test rtl hidden">AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span></div>
+
+<div class="test rtl hidden"><span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span>AxxxxB<span class="rlo">HelloWorld</span></div>
+
+<div class="test rtl hidden"><span class="rlo">HelloWorld</span></div>
+
+
+
+
+</body></html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/block-padding-ref.html
@@ -0,0 +1,83 @@
+<!DOCTYPE HTML>
+<!--
+    Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/licenses/publicdomain/
+-->
+<!DOCTYPE HTML>
+<html><head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<title>text-overflow: text-overflow block padding </title>
+<style type="text/css">
+@font-face {
+  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;
+}
+body { width:24ch; overflow:hidden; }
+
+.test { 
+  overflow: hidden; 
+  white-space: nowrap;
+  padding-left: 1ch;
+  padding-right: 3ch;
+  height: 3em;
+  margin-bottom:1em;
+}
+.s {
+  overflow: auto; position:relative;
+  text-decoration: line-through;
+}
+.rel { position:relative; }
+span {
+  text-decoration: underline overline;
+  background:yellow;
+}
+.rtl {
+  direction:rtl;
+}
+.ltr {
+  direction:ltr;
+}
+.rlo span {
+  unicode-bidi: bidi-override; direction: rtl;
+}
+.lro span {
+  unicode-bidi: bidi-override; direction: ltr;
+}
+.overlay {
+  position:absolute;
+  border-color:transparent;
+  text-decoration: line-through;
+  z-index:1;
+}
+y {   background:yellow;}
+m {   background:yellow; position:absolute; right:0; padding-right:3ch; z-index:2;}
+mr {  background:yellow; position:absolute; left:0;padding-left:1ch; z-index:2;}
+</style>
+</head><body>
+
+<!-- LTR / LTR -->
+<div class="test ltr overlay"><r>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</r></div>
+<div class="test ltr"><span>|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|</span><y>&#x2026;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</y></div>
+
+<div class="test ltr s"><span>|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><m>&#x2026;</m></div>
+
+<!-- RTL / LTR -->
+<div class="test rtl rel"><span><div class="overlay"><r>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</r></div>|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|</span><y style="padding-left:3ch">&#x2026;</y></div>
+
+<div class="test rtl s"><mr>&#x2026;</mr><span>|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;</span></div>
+
+<!-- LTR / RTL -->
+<div class="test ltr rlo overlay"><r>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</r></div>
+<div class="test ltr rlo"  ><span>&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;</span><y style="padding-right:3ch">&#x2026;</y></div>
+
+<div class="test ltr rlo s"><span>|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;</span><m>&#x2026;</m></div>
+
+<!-- RTL / RTL -->
+<div class="test rtl rlo rel"><span><div class="overlay"><r>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</r></div>|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|</span><y>&#x2026;&nbsp;</y></div>
+
+<div class="test rtl rlo s"><mr>&#x2026;</mr><span>|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;</span></div>
+
+</body></html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/block-padding.html
@@ -0,0 +1,71 @@
+<!DOCTYPE HTML>
+<!--
+    Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/licenses/publicdomain/
+
+    Test: test marker trigger point and alignment in a block with padding
+-->
+<!DOCTYPE HTML>
+<html><head>
+<meta http-equiv="content-type" content="text/html; charset=UTF-8">
+<title>text-overflow: text-overflow block padding </title>
+<style type="text/css">
+@font-face {
+  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;
+}
+body { width:24ch; overflow:hidden; }
+
+.test { 
+  overflow: hidden; 
+  white-space: nowrap;
+  text-overflow: ellipsis;
+  text-decoration: line-through;
+  padding-left: 1ch;
+  padding-right: 3ch;
+  height: 3em;
+  margin-bottom:1em;
+}
+.s {
+  overflow: auto; 
+}
+span {
+  text-decoration: underline overline;
+  background:yellow;
+}
+.rtl {
+  direction:rtl;
+}
+.ltr {
+  direction:ltr;
+}
+.rlo span {
+  unicode-bidi: bidi-override; direction: rtl;
+}
+.lro span {
+  unicode-bidi: bidi-override; direction: ltr;
+}
+</style>
+
+</head><body>
+
+<!-- LTR / LTR -->
+<div class="test ltr"  ><span>|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;</span></div>
+<div class="test ltr s"><span>|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;</span></div>
+
+<!-- RTL / LTR -->
+<div class="test rtl"  ><span>|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;</span></div>
+<div class="test rtl s"><span>|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;</span></div>
+
+<!-- LTR / RTL -->
+<div class="test ltr rlo"  ><span>|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;</span></div>
+<div class="test ltr rlo s"><span>|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;</span></div>
+
+<!-- RTL / RTL -->
+<div class="test rtl rlo"  ><span>|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;</span></div>
+<div class="test rtl rlo s"><span>|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;|&nbsp;</span></div>
+
+</body></html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/ellipsis-font-fallback-ref.html
@@ -0,0 +1,149 @@
+<!DOCTYPE HTML>
+<!--
+    Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/licenses/publicdomain/
+
+    Test: fallback to three ASCII periods when ellipsis is unavailable in the font
+-->
+<html><head>
+    <title>text-overflow: ellipsis fallback</title>
+    <style type="text/css">
+@font-face {
+  /* This font has glyphs for ASCII period, upper-case X and space. */
+  font-family: TestEllipsisFallback;
+  src: url(TestEllipsisFallback.woff);
+}
+html,body {
+    color:black; background-color:white; font-size:16px; padding:0; margin:0; font-family: TestEllipsisFallback;
+}
+
+.rtl {
+  direction:rtl;
+}
+.ltr {
+  direction:ltr;
+}
+.rlo {
+  unicode-bidi: bidi-override; direction: rtl;
+}
+.lro {
+  unicode-bidi: bidi-override; direction: ltr;
+}
+
+m {
+  color:blue;
+}
+.o span {
+  color:black;
+}
+
+.s {
+  width:10em;
+}
+.s2 {
+  width:10em;
+}
+.s3 {
+  width:6em;
+}
+.s4 {
+  width:8em;
+}
+.s5 {
+  width:5em;
+}
+.s6 {
+  width:1em;
+}
+.s7 {
+  width:6em;
+}
+.p {
+  overflow: hidden;
+  white-space:nowrap;
+}
+.r {
+  text-align:right;
+}
+
+.c {
+  margin-left:-0.5em;
+  margin-right:-0.5em;
+}
+
+
+#test1a  { top:0em;     left:0; position:absolute; }
+#test1b  { top:2em;     left:0; position:absolute; }
+#test1c  { top:4em;     left:0; position:absolute; }
+#test1d  { top:6em;     left:0; position:absolute; }
+
+#test2a  { top:0em;     left:15em; position:absolute; }
+#test2b  { top:2em;     left:15em; position:absolute; }
+#test2c  { top:4em;     left:15em; position:absolute; }
+#test2d  { top:6em;     left:15em; position:absolute; }
+
+#test3a  { top: 8em;     left:0; position:absolute; }
+#test3b  { top:10em;     left:0; position:absolute; }
+#test3c  { top:12em;     left:0; position:absolute; }
+#test3d  { top:14em;     left:0; position:absolute; }
+
+#test4a  { top: 8em;     left:15em; position:absolute; }
+#test4b  { top:10em;     left:15em; position:absolute; }
+#test4c  { top:12em;     left:15em; position:absolute; }
+#test4d  { top:14em;     left:15em; position:absolute; }
+
+#test5a  { top:16em;     left:0; position:absolute; }
+#test5b  { top:18em;     left:0; position:absolute; }
+#test5c  { top:20em;     left:0; position:absolute; }
+#test5d  { top:22em;     left:0; position:absolute; }
+
+#test6a  { top:16em;     left:15em; position:absolute; }
+#test6b  { top:18em;     left:15em; position:absolute; }
+#test6c  { top:20em;     left:15em; position:absolute; }
+#test6d  { top:22em;     left:15em; position:absolute; }
+
+#test7a  { top:24em;     left:0; position:absolute; }
+#test7b  { top:26em;     left:0; position:absolute; }
+#test7c  { top:28em;     left:0; position:absolute; }
+#test7d  { top:30em;     left:0; position:absolute; }
+
+
+    </style>
+</head>
+<body>
+<div style="position: absolute; top:20px; left:50px;">
+
+<!-- start + end marker -->
+<div id="test1a"><div class="s ltr"><div class="p o"><span class="c lro">&nbsp;<m>...</m>X<m>...</m>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></div></div></div>
+<div id="test1b"><div class="s rtl"><div class="p o"><span class="c lro">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<m>...</m>X<m>...</m>&nbsp;</span></div></div></div>
+<div id="test1c"><div class="s ltr"><div class="p o"><span class="c rlo">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<m>...</m>X<m>...</m>&nbsp;</span></div></div></div>
+<div id="test1d"><div class="s rtl"><div class="p o"><span class="c rlo">&nbsp;<m>...</m>X<m>...</m>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span></div></div></div>
+
+<!-- end marker -->
+<div id="test2a"><div class="s2 ltr"><div class="p o"><span class="lro">XXXXX<m>...</m>&nbsp;</span></div></div></div>
+<div id="test2b"><div class="s2 rtl"><div class="p o"><span class="lro">&nbsp;<m>...</m>XXXXX</span></div></div></div>
+<div id="test2c"><div class="s2 ltr"><div class="p o"><span class="rlo">&nbsp;<m>...</m>XXXXX</span></div></div></div>
+<div id="test2d"><div class="s2 rtl"><div class="p o"><span class="rlo">XXXXX<m>...</m>&nbsp;</span></div></div></div>
+
+<!-- start marker -->
+<div id="test3a"><div class="s3 ltr"><div class="p o"><span class="c lro">&nbsp;X<m>...</m></span></div></div></div>
+<div id="test3b"><div class="s3 rtl"><div class="p o"><span class="c lro"><m>...</m>X&nbsp;</span></div></div></div>
+<div id="test3c"><div class="s3 ltr"><div class="p o"><span class="c rlo"><m>...</m>X&nbsp;</span></div></div></div>
+<div id="test3d"><div class="s3 rtl"><div class="p o"><span class="c rlo">&nbsp;X<m>...</m></span></div></div></div>
+
+<!-- start + end marker, no characters fit, marker is clipped -->
+<div id="test6a"><div class="s6 ltr"><div class="p o"><span class=" lro"><m>...</m></span></div></div></div>
+<div id="test6b"><div class="s6 ltr"><div class="p o"><span class=" lro"><m>...</m></span></div></div></div>
+<div id="test6c"><div class="s6 ltr"><div class="p o"><span class=" lro"><m>...</m></span></div></div></div>
+<div id="test6d"><div class="s6 ltr"><div class="p o"><span class=" lro"><m>...</m></span></div></div></div>
+
+<!-- start marker, all characters overlapped by marker -->
+<div id="test7a"><div class="s7 ltr"><div class="p o"><span class=" lro"><m>...</m>&nbsp;</span></div></div></div>
+<div id="test7b"><div class="s7 rtl"><div class="p o"><span class=" lro">&nbsp;<m>...</m></span></div></div></div>
+<div id="test7c"><div class="s7 ltr"><div class="p o"><span class=" rlo">&nbsp;<m>...</m></span></div></div></div>
+<div id="test7d"><div class="s7 rtl"><div class="p o"><span class=" rlo"><m>...</m>&nbsp;</span></div></div></div>
+
+</div>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/ellipsis-font-fallback.html
@@ -0,0 +1,150 @@
+<!DOCTYPE HTML>
+<!--
+    Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/licenses/publicdomain/
+
+    Test: fallback to three ASCII periods when ellipsis is unavailable in the font
+-->
+<html><head>
+    <title>text-overflow: ellipsis fallback</title>
+    <style type="text/css">
+@font-face {
+  /* This font has glyphs for ASCII period, upper-case X and space. */
+  font-family: TestEllipsisFallback;
+  src: url(TestEllipsisFallback.woff);
+}
+html,body {
+    color:black; background-color:white; font-size:16px; padding:0; margin:0; font-family: TestEllipsisFallback;
+}
+
+.rtl {
+  direction:rtl;
+}
+.ltr {
+  direction:ltr;
+}
+.rlo {
+  unicode-bidi: bidi-override; direction: rtl;
+}
+.lro {
+  unicode-bidi: bidi-override; direction: ltr;
+}
+
+.o {
+  text-overflow: ellipsis;
+  color:blue;
+}
+.o span {
+  color:black;
+}
+
+.s {
+  width:10em;
+}
+.s2 {
+  width:10em;
+}
+.s3 {
+  width:6em;
+}
+.s4 {
+  width:8em;
+}
+.s5 {
+  width:5em;
+}
+.s6 {
+  width:1em;
+}
+.s7 {
+  width:6em;
+}
+.p {
+  overflow: hidden;
+  white-space:nowrap;
+}
+.r {
+  text-align:right;
+}
+
+.c {
+  margin-left:-0.5em;
+  margin-right:-0.5em;
+}
+
+
+#test1a  { top:0em;     left:0; position:absolute; }
+#test1b  { top:2em;     left:0; position:absolute; }
+#test1c  { top:4em;     left:0; position:absolute; }
+#test1d  { top:6em;     left:0; position:absolute; }
+
+#test2a  { top:0em;     left:15em; position:absolute; }
+#test2b  { top:2em;     left:15em; position:absolute; }
+#test2c  { top:4em;     left:15em; position:absolute; }
+#test2d  { top:6em;     left:15em; position:absolute; }
+
+#test3a  { top: 8em;     left:0; position:absolute; }
+#test3b  { top:10em;     left:0; position:absolute; }
+#test3c  { top:12em;     left:0; position:absolute; }
+#test3d  { top:14em;     left:0; position:absolute; }
+
+#test4a  { top: 8em;     left:15em; position:absolute; }
+#test4b  { top:10em;     left:15em; position:absolute; }
+#test4c  { top:12em;     left:15em; position:absolute; }
+#test4d  { top:14em;     left:15em; position:absolute; }
+
+#test5a  { top:16em;     left:0; position:absolute; }
+#test5b  { top:18em;     left:0; position:absolute; }
+#test5c  { top:20em;     left:0; position:absolute; }
+#test5d  { top:22em;     left:0; position:absolute; }
+
+#test6a  { top:16em;     left:15em; position:absolute; }
+#test6b  { top:18em;     left:15em; position:absolute; }
+#test6c  { top:20em;     left:15em; position:absolute; }
+#test6d  { top:22em;     left:15em; position:absolute; }
+
+#test7a  { top:24em;     left:0; position:absolute; }
+#test7b  { top:26em;     left:0; position:absolute; }
+#test7c  { top:28em;     left:0; position:absolute; }
+#test7d  { top:30em;     left:0; position:absolute; }
+
+    </style>
+</head>
+<body>
+<div style="position: absolute; top:20px; left:50px;">
+
+<!-- start + end marker -->
+<div id="test1a"><div class="s ltr"><div class="p o"><span class="c lro">XXXXXXXXXXXX</span></div></div></div>
+<div id="test1b"><div class="s rtl"><div class="p o"><span class="c lro">XXXXXXXXXXXX</span></div></div></div>
+<div id="test1c"><div class="s ltr"><div class="p o"><span class="c rlo">XXXXXXXXXXXX</span></div></div></div>
+<div id="test1d"><div class="s rtl"><div class="p o"><span class="c rlo">XXXXXXXXXXXX</span></div></div></div>
+
+<!-- end marker -->
+<div id="test2a"><div class="s2 ltr"><div class="p o"><span class="lro">XXXXXXXXXXXX</span></div></div></div>
+<div id="test2b"><div class="s2 rtl"><div class="p o"><span class="lro">XXXXXXXXXXXX</span></div></div></div>
+<div id="test2c"><div class="s2 ltr"><div class="p o"><span class="rlo">XXXXXXXXXXXX</span></div></div></div>
+<div id="test2d"><div class="s2 rtl"><div class="p o"><span class="rlo">XXXXXXXXXXXX</span></div></div></div>
+
+<!-- start marker -->
+<div id="test3a"><div class="s3 ltr"><div class="p o"><span class="c lro">XXXXXX</span></div></div></div>
+<div id="test3b"><div class="s3 rtl"><div class="p o"><span class="c lro">XXXXXX</span></div></div></div>
+<div id="test3c"><div class="s3 ltr"><div class="p o"><span class="c rlo">XXXXXX</span></div></div></div>
+<div id="test3d"><div class="s3 rtl"><div class="p o"><span class="c rlo">XXXXXX</span></div></div></div>
+
+<!-- start + end marker, no characters fit, marker is clipped -->
+<div id="test6a"><div class="s6 ltr"><div class="p o"><span class="c lro">XXXXXXXXXXXX</span></div></div></div>
+<div id="test6b"><div class="s6 rtl"><div class="p o"><span class="c lro">XXXXXXXXXXXX</span></div></div></div>
+<div id="test6c"><div class="s6 ltr"><div class="p o"><span class="c rlo">XXXXXXXXXXXX</span></div></div></div>
+<div id="test6d"><div class="s6 rtl"><div class="p o"><span class="c rlo">XXXXXXXXXXXX</span></div></div></div>
+
+<!-- start marker, all characters overlapped by marker -->
+<div id="test7a"><div class="s7 ltr"><div class="p o"><span class="c lro">XXX</span></div></div></div>
+<div id="test7b"><div class="s7 rtl"><div class="p o"><span class="c lro">XXX</span></div></div></div>
+<div id="test7c"><div class="s7 ltr"><div class="p o"><span class="c rlo">XXX</span></div></div></div>
+<div id="test7d"><div class="s7 rtl"><div class="p o"><span class="c rlo">XXX</span></div></div></div>
+
+
+</div>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/false-marker-overlap-ref.html
@@ -0,0 +1,71 @@
+<!DOCTYPE HTML>
+<!--
+    Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/licenses/publicdomain/
+
+    Test: false marker overlap
+-->
+<html><head>
+<title>text-overflow: form control elements</title>
+<style type="text/css">
+@font-face {
+  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: hidden; 
+  white-space: nowrap;
+  color: black;
+  height: 6em;
+  width: 32.5em;
+  margin-bottom: 1em;
+}
+
+i {
+  display:inline-block;
+  height: 3em;
+  width: 3em;
+  border:1px solid blue;
+  text-shadow: none;
+}
+.rtl {
+  direction:rtl;
+}
+.rlo {
+  unicode-bidi: bidi-override; direction: rtl;
+}
+.lro {
+  unicode-bidi: bidi-override; direction: ltr;
+}
+
+s {
+   float:right;
+   width:3em;
+   height:3em;
+   margin-right:-0.6em;
+   border:1px solid red;
+}
+.rtl s {
+   float:left;
+   margin-left:-0.6em;
+   margin-right:0;
+}
+.overlap {margin-left:-0.6em;}
+.rtl .overlap {margin-right:-0.6em;margin-left:0;}
+.n {padding-left:0.6em;}
+.rtl .n {padding-right:0.6em;padding-left:0;}
+</style>
+
+</head><body>
+
+<div class="test"><font class="overlap"><s></s>&nbsp;<m>&#x2026;</m>| | | | | | | | | | | | | | | | | | | | | | <i class="n"></i></font></div>
+<div class="test"><font><s></s>| | | | | | | | | | | | | | | | | | | | | | | <i></i></font></div>
+<div class="test rtl"><font class="overlap"><s></s>&nbsp;<m>&#x2026;</m>| | | | | | | | | | | | | | | | | | | | | | <i class="n"></i></font></div>
+<div class="test rtl"><font><s></s>| | | | | | | | | | | | | | | | | | | | | | | <i></i></font></div>
+
+
+</body></html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/false-marker-overlap.html
@@ -0,0 +1,72 @@
+<!DOCTYPE HTML>
+<!--
+    Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/licenses/publicdomain/
+
+    Test: false marker overlap
+-->
+<html><head>
+<title>text-overflow: false marker overlap</title>
+<style type="text/css">
+@font-face {
+  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: hidden; 
+  white-space: nowrap;
+  text-overflow: ellipsis;
+  color: black;
+  height: 6em;
+  width: 32.5em;
+  margin-bottom: 1em;
+}
+
+i {
+  display:inline-block;
+  height: 3em;
+  width: 3em;
+  border:1px solid blue;
+  text-shadow: none;
+}
+.rtl {
+  direction:rtl;
+}
+.rlo {
+  unicode-bidi: bidi-override; direction: rtl;
+}
+.lro {
+  unicode-bidi: bidi-override; direction: ltr;
+}
+
+s {
+   float:right;
+   width:3em;
+   height:3em;
+   margin-right:-0.6em;
+   border:1px solid red;
+}
+.rtl s {
+   float:left;
+   margin-left:-0.6em;
+   margin-right:0;
+}
+.overlap {margin-left:-0.6em;}
+.rtl .overlap {margin-right:-0.6em;margin-left:0;}
+.n {padding-left:0.6em;}
+.rtl .n {padding-right:0.6em;padding-left:0;}
+</style>
+
+</head><body>
+
+<div class="test"><font class="overlap"><s></s>| | | | | | | | | | | | | | | | | | | | | | | <i class="n"></i></font></div>
+<div class="test"><font><s></s>| | | | | | | | | | | | | | | | | | | | | | | <i></i></font></div>
+<div class="test rtl"><font class="overlap"><s></s>| | | | | | | | | | | | | | | | | | | | | | | <i class="n"></i></font></div>
+<div class="test rtl"><font><s></s>| | | | | | | | | | | | | | | | | | | | | | | <i></i></font></div>
+
+
+</body></html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/marker-basic-ref.html
@@ -0,0 +1,305 @@
+<!DOCTYPE HTML>
+<!--
+    Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/licenses/publicdomain/
+-->
+<html><head>
+    <title>text-overflow: basic marker position tests</title>
+    <style type="text/css">
+@font-face {
+  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;
+}
+
+.rtl {
+  direction:rtl;
+}
+.ltr {
+  direction:ltr;
+}
+.rlo {
+  unicode-bidi: bidi-override; direction: rtl;
+}
+.lro {
+  unicode-bidi: bidi-override; direction: ltr;
+}
+
+.rel {
+  position: relative;
+  height:2em;
+}
+.abs0 {
+  position: absolute;
+  top:0; left:0;
+}
+.abs0r {
+  position: absolute;
+  top:0; right:0;
+}
+
+.s {
+  width:4em;
+}
+.p {
+  overflow: hidden;
+  white-space:nowrap;
+  font-size:16px;
+}
+.a {
+  font-size:20px;
+}
+.r {
+  text-align:right;
+}
+.l {
+  text-align:left;
+}
+
+i {
+  display:inline-block;
+  width: 1.5em;
+  height: 1em;
+  font-style:normal;
+  color:lime;
+  border: 1px solid magenta;
+  text-decoration:overline;
+}
+.cl {
+  margin-left:-1em;
+  color: black;
+}
+.cr {
+  margin-right:-1em;
+  color: black;
+}
+.c5 {
+  margin-left:-0.5em;
+  margin-right:-0.5em;
+  color: black;
+}
+.outside {
+ width:1px; height:1px;
+}
+.overlap1 {
+ width:1.5em; height:1px;
+}
+.ins1 {
+ width:1em; height:1px;
+}
+.ins2 {  margin-right: 0.8em; margin-left: -1em; }
+.overlap2 {
+ width:1000px; height:1px;
+}
+.e { padding: 0 0.8em; }
+
+x1 { display:inline-block; position:relative;}
+x1 m { position:absolute; right:0; font-size:16px; }
+
+#test1a  { top:0;     left:0;     position:absolute; }
+#test1b  { top:0;     left:100px; position:absolute; }
+#test1c  { top:0;     left:200px; position:absolute; }
+#test1d  { top:0;     left:300px; position:absolute; }
+#test2a  { top:40px;  left:0;     position:absolute; }
+#test2b  { top:40px;  left:100px; position:absolute; }
+#test2c  { top:40px;  left:200px; position:absolute; }
+#test2d  { top:40px;  left:300px; position:absolute; }
+#test3a  { top:80px; left:0;     position:absolute; }
+#test3b  { top:80px; left:100px; position:absolute; }
+#test3c  { top:80px; left:200px; position:absolute; }
+#test3d  { top:80px; left:300px; position:absolute; }
+#test4a  { top:120px; left:0;     position:absolute; }
+#test4b  { top:120px; left:100px; position:absolute; }
+#test4c  { top:120px; left:200px; position:absolute; }
+#test4d  { top:120px; left:300px; position:absolute; }
+#test5a  { top:160px; left:0;     position:absolute; }
+#test5b  { top:160px; left:100px; position:absolute; }
+#test5c  { top:160px; left:200px; position:absolute; }
+#test5d  { top:160px; left:300px; position:absolute; }
+#test6a  { top:200px; left:0;     position:absolute; }
+#test6b  { top:200px; left:100px; position:absolute; }
+#test6c  { top:200px; left:200px; position:absolute; }
+#test6d  { top:200px; left:300px; position:absolute; }
+#test7a  { top:240px; left:0;     position:absolute; }
+#test7b  { top:240px; left:100px; position:absolute; }
+#test7c  { top:240px; left:200px; position:absolute; }
+#test7d  { top:240px; left:300px; position:absolute; }
+#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; }
+
+    </style>
+</head>
+<body>
+<div style="position: absolute; top:20px; left:50px;">
+
+<div id="test1a">
+<div class="s a"><div class="p rel">
+<div class="abs0" style="text-align:left"><span class="cl a">&nbsp;&nbsp;&nbsp;||||</span><m>&#x2026;</m></div>
+<div class="abs0" style="text-align:left"><span class="cl a">&nbsp;&nbsp;&nbsp;<m style="position:absolute; right:0; bottom:0;"><m0 style=" font-size:16px">&#x2026;</m0></m></span></div>
+</div></div>
+</div>
+<div id="test1b">
+<div class="s a rtl"><div class="p rel">
+<div class="abs0r"><span class="cr a rlo">&nbsp;&nbsp;&nbsp;||||</span><m>&#x2026;</m></div>
+<div class="abs0r"><span class="cr a rlo">&nbsp;&nbsp;&nbsp;<m style="position:absolute; left:0; bottom:0;"><m0 style=" font-size:16px">&#x2026;</m0></m></span></span></div>
+</div></div>
+</div>
+<div id="test1c">
+<div class="s a"><div class="p rel">
+<div class="abs0" style="text-align:left"><span class="cl a">&nbsp;&nbsp;&nbsp;||||</span><m>&#x2026;</m></div>
+<div class="abs0" style="text-align:left"><span class="cl a">&nbsp;&nbsp;&nbsp;<m style="position:absolute; right:0; bottom:0;"><m0 style=" font-size:16px">&#x2026;</m0></m></span></div>
+</div></div>
+</div>
+<div id="test1d">
+<div class="s a rtl"><div class="p rel">
+<div class="abs0r"><span class="cr a rlo">&nbsp;&nbsp;&nbsp;||||</span><m>&#x2026;</m></div>
+<div class="abs0r"><span class="cr a rlo">&nbsp;&nbsp;&nbsp;<m style="position:absolute; left:0; bottom:0;"><m0 style=" font-size:16px">&#x2026;</m0></m></span></span></div>
+</div></div>
+</div>
+
+<div id="test2a">
+<div class="s a"><div class="p rel">
+<div class="abs0" style="text-align:left"><m>&#x2026;</m><span class="cl a">&nbsp;</span></div>
+</div></div>
+</div>
+<div id="test2b">
+<div class="s a"><div class="p rel">
+<div class="abs0" style="text-align:left"><m>&#x2026;</m><span class="cl a">&nbsp;</span></div>
+</div></div>
+</div>
+<div id="test2c">
+<div class="s a"><div class="p rel">
+<div class="abs0" style="text-align:right; left:auto; right:0;"><span class="cr a">&nbsp;&nbsp;&nbsp;</span><m>&#x2026;</m></div>
+</div></div>
+</div>
+<div id="test2d">
+<div class="s a"><div class="p rel">
+<div class="abs0" style="text-align:right; left:auto; right:0;"><span class="cr a">&nbsp;&nbsp;&nbsp;</span><m>&#x2026;</m></div>
+</div></div>
+</div>
+
+<div id="test3a">
+<div class="s a"><div class="p rel">
+<div class="abs0" style="text-align:left"><m>&#x2026;</m><span class="cl a">&nbsp;</span></div>
+</div></div>
+</div>
+<div id="test3b">
+<div class="s a"><div class="p rel">
+<div class="abs0" style="text-align:left"><m>&#x2026;</m><span class="cl a">&nbsp;</span></div>
+</div></div>
+</div>
+<div id="test3c">
+<div class="s a"><div class="p rel">
+<div class="abs0" style="text-align:right; left:auto; right:0;"><span class="cr a">&nbsp;&nbsp;&nbsp;</span><m>&#x2026;</m></div>
+</div></div>
+</div>
+<div id="test3d">
+<div class="s a"><div class="p rel">
+<div class="abs0" style="text-align:right; left:auto; right:0;"><span class="cr a">&nbsp;&nbsp;&nbsp;</span><m>&#x2026;</m></div>
+</div></div>
+</div>
+
+<div id="test4a">
+<div class="s a"><div class="p rel">
+<div class="abs0" style="text-align:left"><m>&#x2026;</m><span class="cl a">&nbsp;</span></div>
+</div></div>
+</div>
+<div id="test4b">
+<div class="s a"><div class="p rel">
+<div class="abs0" style="text-align:left"><m>&#x2026;</m><span class="cl a">&nbsp;</span></div>
+</div></div>
+</div>
+<div id="test4c">
+<div class="s a"><div class="p rel">
+<div class="abs0" style="text-align:right; left:auto; right:0;"><span class="cr a">&nbsp;&nbsp;&nbsp;</span><m>&#x2026;</m></div>
+</div></div>
+</div>
+<div id="test4d">
+<div class="s a"><div class="p rel">
+<div class="abs0" style="text-align:right; left:auto; right:0;"><span class="cr a">&nbsp;&nbsp;&nbsp;</span><m>&#x2026;</m></div>
+</div></div>
+</div>
+
+<div id="test5a">
+<div class="s a"><div class="p rel">
+<div class="abs0" style="text-align:right; left:auto; right:0;"><span class="cr a">&nbsp;</span><m>&#x2026;</m></div>
+<div class="abs0" style="text-align:left"><m>&#x2026;</m><span class="cl a">&nbsp;</span></div>
+</div></div>
+</div>
+<div id="test5b">
+<div class="s a"><div class="p rel">
+<div class="abs0" style="text-align:right; left:auto; right:0;"><span class="cr a">&nbsp;</span><m>&#x2026;</m></div>
+<div class="abs0" style="text-align:left"><m>&#x2026;</m><span class="cl a">&nbsp;</span></div>
+</div></div>
+</div>
+<div id="test5c">
+<div class="s a"><div class="p rel">
+<div class="abs0" style="text-align:right; left:auto; right:0;"><span class="cr a">&nbsp;</span><m>&#x2026;</m></div>
+<div class="abs0" style="text-align:left"><m>&#x2026;</m><span class="cl a">&nbsp;</span></div>
+</div></div>
+</div>
+<div id="test5d">
+<div class="s a"><div class="p rel">
+<div class="abs0" style="text-align:right; left:auto; right:0;"><span class="cr a">&nbsp;</span><m>&#x2026;</m></div>
+<div class="abs0" style="text-align:left"><m>&#x2026;</m><span class="cl a">&nbsp;</span></div>
+</div></div>
+</div>
+
+<div id="test6a">
+<div class="s a"><div class="p rel">
+<div class="abs0"><span class="cr a">&nbsp;&nbsp;&nbsp;</span><img class="a overlap1" src="../image/big.png"></div>
+<div class="abs0"><span class="cr a">&nbsp;&nbsp;&nbsp;<m style="position:absolute; right:0; bottom:0;"><m0 style="font-size:16px">&#x2026;</m0></m></span></span></div>
+</div></div>
+</div>
+<div id="test6b">
+<div class="s a"><div class="p rel">
+<div class="abs0"><span class="cr a">&nbsp;&nbsp;&nbsp;</span><img class="a overlap1" src="../image/big.png"></div>
+<div class="abs0"><span class="cr a">&nbsp;&nbsp;&nbsp;<m style="position:absolute; right:0; bottom:0;"><m0 style="font-size:16px">&#x2026;</m0></m></span></span></div>
+</div></div>
+</div>
+<div id="test6c">
+<div class="s a"><div class="p rel">
+<div class="abs0" style="text-align:right; right:0; "><span class="cr a"><img class="overlap1" src="../image/big.png">&nbsp;&nbsp;&nbsp;</span></div>
+<div class="abs0" style="text-align:right; right:0; "><span class="cr a"><img class="overlap1" src="../image/big.png"><m style="position:absolute; bottom:0;"><m0 style="font-size:16px">&#x2026;</m0></m>&nbsp;&nbsp;&nbsp;</span></div>
+</div></div>
+</div>
+<div id="test6d">
+<div class="s a"><div class="p rel">
+<div class="abs0" style="text-align:right; right:0; "><span class="cr a"><img class="overlap1" src="../image/big.png">&nbsp;&nbsp;&nbsp;</span></div>
+<div class="abs0" style="text-align:right; right:0; "><span class="cr a"><img class="overlap1" src="../image/big.png"><m style="position:absolute; bottom:0;"><m0 style="font-size:16px">&#x2026;</m0></m>&nbsp;&nbsp;&nbsp;</span></div>
+</div></div>
+</div>
+
+<div id="test7a">
+<div class="s a"><div class="p ltr"><span class="c5 a">|<x style="display:inline-block;width:0.8em;text-align:right"><m style="font-size:16px;">&#x2026;</m></x><img class="ins1" src="../image/big.png"></span></div></div>
+</div>
+
+<div id="test7b"><div class="s a"><div class="p ltr r"><img class="a ins1" src="../image/big.png"><x class="a" style="display:inline-block;width:0.8em;text-align:left"><m style="font-size:16px;">&#x2026;</m></x><span class="c5 a" style="margin-right:0">&nbsp;</span></div></div></div>
+
+<div id="test7c">
+<div class="s a"><div class="p ltr"><span class="c5 a">|<x style="display:inline-block;width:0.8em;text-align:right"><m style="font-size:16px;">&#x2026;</m></x><img class="ins1" src="../image/big.png"></span></div></div>
+</div>
+
+<div id="test7d"><div class="s a"><div class="p ltr r"><img class="a ins1" src="../image/big.png"><x class="a" style="display:inline-block;width:0.8em;text-align:left"><m style="font-size:16px;">&#x2026;</m></x><span class="c5 a" style="margin-right:0">&nbsp;</span></div></div></div>
+
+
+<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>
+
+
+</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/marker-basic.html
@@ -0,0 +1,197 @@
+<!DOCTYPE HTML>
+<!--
+    Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/licenses/publicdomain/
+
+    Test: basic marker position tests
+-->
+<html><head>
+    <title>text-overflow: basic marker position tests</title>
+    <style type="text/css">
+@font-face {
+  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;
+}
+
+.rtl {
+  direction:rtl;
+}
+.ltr {
+  direction:ltr;
+}
+.rlo {
+  unicode-bidi: bidi-override; direction: rtl;
+}
+.lro {
+  unicode-bidi: bidi-override; direction: ltr;
+}
+
+.o {
+  text-overflow: ellipsis;
+}
+
+.rel {
+  position: relative;
+  height:2em;
+}
+.abs0 {
+  position: absolute;
+  top:0; left:0;
+}
+
+.s {
+  width:4em;
+}
+.p {
+  overflow: hidden;
+  white-space:nowrap;
+  font-size:16px;
+}
+.r {
+  text-align:right;
+}
+.a {
+  font-size:20px;
+}
+.l {
+  text-align:left;
+}
+i {
+  display:inline-block;
+  width: 1.5em;
+  height: 1em;
+  font-style:normal;
+  color:lime;
+  border: 1px solid magenta;
+  text-decoration:overline;
+}
+
+.c {
+  margin-left:-1em;
+  margin-right:-1em;
+  color: black;
+}
+.c5 {
+  margin-left:-0.5em;
+  margin-right:-0.5em;
+  color: black;
+}
+.outside {
+ width:1px; height:1px;
+}
+.overlap1 {
+ width:1.5em; height:1px;
+}
+.ins1 {
+ width:1em; height:1px;
+ margin: 0 0.8em;
+}
+.overlap2 {
+ width:1000px; height:1px;
+}
+.e { padding: 0 0.8em; }
+
+
+#test1a  { top:0;     left:0;     position:absolute; }
+#test1b  { top:0;     left:100px; position:absolute; }
+#test1c  { top:0;     left:200px; position:absolute; }
+#test1d  { top:0;     left:300px; position:absolute; }
+#test2a  { top:40px;  left:0;     position:absolute; }
+#test2b  { top:40px;  left:100px; position:absolute; }
+#test2c  { top:40px;  left:200px; position:absolute; }
+#test2d  { top:40px;  left:300px; position:absolute; }
+#test3a  { top:80px; left:0;     position:absolute; }
+#test3b  { top:80px; left:100px; position:absolute; }
+#test3c  { top:80px; left:200px; position:absolute; }
+#test3d  { top:80px; left:300px; position:absolute; }
+#test4a  { top:120px; left:0;     position:absolute; }
+#test4b  { top:120px; left:100px; position:absolute; }
+#test4c  { top:120px; left:200px; position:absolute; }
+#test4d  { top:120px; left:300px; position:absolute; }
+#test5a  { top:160px; left:0;     position:absolute; }
+#test5b  { top:160px; left:100px; position:absolute; }
+#test5c  { top:160px; left:200px; position:absolute; }
+#test5d  { top:160px; left:300px; position:absolute; }
+#test6a  { top:200px; left:0;     position:absolute; }
+#test6b  { top:200px; left:100px; position:absolute; }
+#test6c  { top:200px; left:200px; position:absolute; }
+#test6d  { top:200px; left:300px; position:absolute; }
+#test7a  { top:240px; left:0;     position:absolute; }
+#test7b  { top:240px; left:100px; position:absolute; }
+#test7c  { top:240px; left:200px; position:absolute; }
+#test7d  { top:240px; left:300px; position:absolute; }
+#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; }
+
+
+    </style>
+</head>
+<body>
+<div style="position: absolute; top:20px; left:50px;">
+
+<!-- start + end marker, aligned to text -->
+<div id="test1a"><div class="s a ltr"><div class="p o"><span class="c a lro">||||||||||</span></div></div></div>
+<div id="test1b"><div class="s a rtl"><div class="p o"><span class="c a lro">||||||||||</span></div></div></div>
+<div id="test1c"><div class="s a ltr"><div class="p o"><span class="c a rlo">||||||||||</span></div></div></div>
+<div id="test1d"><div class="s a rtl"><div class="p o"><span class="c a rlo">||||||||||</span></div></div></div>
+
+<!-- start marker, text outside marker edge, nothing to align with -->
+<div id="test2a"><div class="s a"><div class="p o ltr"><span class="c a">x</span></div></div></div>
+<div id="test2b"><div class="s a"><div class="p o rtl l"><span class="c a">x</span></div></div></div>
+<div id="test2c"><div class="s a"><div class="p o ltr r"><span class="c a">x</span></div></div></div>
+<div id="test2d"><div class="s a"><div class="p o rtl"><span class="c a">x</span></div></div></div>
+
+<!-- start marker, image outside marker edge, nothing to align with -->
+<div id="test3a"><div class="s a"><div class="p o ltr"><span class="c a"><img class="outside" src="../image/big.png"></span></div></div></div>
+<div id="test3b"><div class="s a"><div class="p o rtl l"><span class="c a"><img class="outside" src="../image/big.png"></span></div></div></div>
+<div id="test3c"><div class="s a"><div class="p o ltr r"><span class="c a"><img class="outside" src="../image/big.png"></span></div></div></div>
+<div id="test3d"><div class="s a"><div class="p o rtl"><span class="c a"><img class="outside" src="../image/big.png"></span></div></div></div>
+
+<!-- start marker, marker partly overlaps image, nothing to align with -->
+<div id="test4a"><div class="s a"><div class="p o ltr"><span class="c a"><img class="overlap1" src="../image/big.png"></span></div></div></div>
+<div id="test4b"><div class="s a"><div class="p o rtl l"><span class="c a"><img class="overlap1" src="../image/big.png"></span></div></div></div>
+<div id="test4c"><div class="s a"><div class="p o ltr r"><span class="c a"><img class="overlap1" src="../image/big.png"></span></div></div></div>
+<div id="test4d"><div class="s a"><div class="p o rtl"><span class="c a"><img class="overlap1" src="../image/big.png"></span></div></div></div>
+
+<!-- start marker + end, marker partly overlaps image, nothing to align with -->
+<div id="test5a"><div class="s a"><div class="p o ltr"><span class="c a"><img class="overlap2" src="../image/big.png"></span></div></div></div>
+<div id="test5b"><div class="s a"><div class="p o rtl l"><span class="c a"><img class="overlap2" src="../image/big.png"></span></div></div></div>
+<div id="test5c"><div class="s a"><div class="p o ltr r"><span class="c a"><img class="overlap2" src="../image/big.png"></span></div></div></div>
+<div id="test5d"><div class="s a"><div class="p o rtl"><span class="c a"><img class="overlap2" src="../image/big.png"></span></div></div></div>
+
+<!-- start marker, marker clips text, aligns to image -->
+<div id="test6a"><div class="s a"><div class="p o ltr"><span class="c a">|||<img class="overlap1" src="../image/big.png"></span></div></div></div>
+<div id="test6b"><div class="s a"><div class="p o rtl l"><span class="c a"><img class="overlap1" src="../image/big.png">|||</span></div></div></div>
+<div id="test6c"><div class="s a"><div class="p o ltr r"><span class="c a"><img class="overlap1" src="../image/big.png">|||</span></div></div></div>
+<div id="test6d"><div class="s a"><div class="p o rtl"><span class="c a">|||<img class="overlap1" src="../image/big.png"></span></div></div></div>
+
+<!-- start marker, marker aligns to image -->
+<div id="test7a"><div class="s a"><div class="p o ltr"><span class="c5 a">|<img class="ins1" src="../image/big.png"></span></div></div></div>
+<div id="test7b"><div class="s a"><div class="p o rtl"><span class="c5 a">|<img class="ins1" src="../image/big.png"></span></div></div></div>
+<!-- end marker, marker aligns to image -->
+<div id="test7c"><div class="s a"><div class="p o rtl l"><span class="c5 a"><img class="ins1" src="../image/big.png">|</span></div></div></div>
+<div id="test7d"><div class="s a"><div class="p o ltr r"><span class="c5 a"><img class="ins1" src="../image/big.png">|</span></div></div></div>
+
+<!-- start marker, marker aligns to empty element -->
+<div id="test8a"><div class="s a"><div class="a p o ltr"><span class="c5 a">|</span><span class="e"></span><span>&#x200c;</span></div></div></div>
+<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>
+
+</div>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/marker-string-ref.html
@@ -0,0 +1,66 @@
+<!DOCTYPE HTML>
+<!--
+    Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/licenses/publicdomain/
+
+    Test: text-overflow:<string>
+-->
+<html><head>
+<title>text-overflow: text-overflow:&lt;string&gt;</title>
+<style type="text/css">
+@font-face {
+  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:hidden;
+  width:20ch;
+  height:3em;
+  white-space:nowrap;
+  margin-left:2em;
+  position:relative;
+}
+m {
+  margin: 0;
+  position:relative;
+}
+mr {
+  position:absolute;
+  right:0;
+}
+.rlo {
+  unicode-bidi: bidi-override; direction:rtl;
+}
+.lro {
+  unicode-bidi: bidi-override;
+}
+.rtl {
+  direction:rtl;
+}
+.ltr {
+  direction:ltr;
+}
+
+.t1 m { margin: 0 -0.5ch; }
+
+</style>
+
+</head><body>
+
+
+<div class="test t1"><m>&nbsp;x</m></div>
+<div class="test rtl t1"><m>&nbsp;x</m></div>
+<div class="test t2"><m>Hello World</m></div>
+<div class="test rtl t2"><m>Hello World</m></div>
+
+<div class="test t2" style="width:3ch"><m>Hel</m></div>
+<div class="test rtl t2" style="width:3ch"><m>Hel</m></div>
+<div class="test"><m>X</m><mr>X</mr></div>
+<div class="test"><m>X</m><mr>X</mr></div>
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/marker-string.html
@@ -0,0 +1,73 @@
+<!DOCTYPE HTML>
+<!--
+    Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/licenses/publicdomain/
+
+    Test: text-overflow:<string>
+-->
+<html><head>
+<title>text-overflow: text-overflow:&lt;string&gt;</title>
+<style type="text/css">
+@font-face {
+  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:hidden;
+  width:20ch;
+  height:3em;
+  white-space:nowrap;
+  margin-left:2em;
+  position:relative;
+}
+span {
+  margin: 0 -0.5ch;
+}
+s {
+  margin: 0 -0.5ch;
+  padding: 0 11ch;
+}
+.rlo {
+  unicode-bidi: bidi-override; direction:rtl;
+}
+.lro {
+  unicode-bidi: bidi-override;
+}
+.rtl {
+  direction:rtl;
+}
+.ltr {
+  direction:ltr;
+}
+
+.t1 { text-overflow:""; }
+.t2 { text-overflow:"Hello World"; }
+.t3 { text-overflow:"X"; }
+
+</style>
+
+</head><body>
+
+
+<!-- Empty marker clips text -->
+<div class="test t1"><span>xx</span></div>
+<div class="test rtl t1"><span>xx</span></div>
+<!-- big marker clips all text -->
+<div class="test t2"><span>xx</span></div>
+<div class="test rtl t2"><span>xx</span></div>
+
+<!-- start marker that doesn't fit -->
+<div class="test t2" style="width:3ch"><span>xx</span></div>
+<div class="test rtl t2" style="width:3ch"><span>xx</span></div>
+
+<!-- start + end marker, nothing to align to -->
+<div class="test t3"><s></s></div>
+<div class="test rtl t3"><s></s></div>
+
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/quirks-decorations-ref.html
@@ -0,0 +1,73 @@
+<!--
+    Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/licenses/publicdomain/
+-->
+<html><head>
+<title>text-overflow: Quirks mode text-decorations</title>
+<style type="text/css">
+@font-face {
+  font-family: Ahem;
+  src: url(../fonts/Ahem.ttf);
+}
+@font-face {
+  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:hidden;
+  float:left;
+  height:2em;
+  white-space:pre;
+  margin-left:1em;
+  margin-bottom:1em;
+  font-size:20px; 
+  color:blue;
+}
+span {
+  font-size:16px;
+  color:black;
+}
+.xspan {
+  text-shadow:0px 1em 2px blue;
+  text-decoration: line-through;
+}
+.rtl .xspan {
+  text-shadow:0 1em 0px blue;
+}
+.rlo {
+  unicode-bidi: bidi-override; direction:rtl;
+}
+.lro {
+  unicode-bidi: bidi-override;
+}
+.rtl {
+  direction:rtl;
+}
+.ltr {
+  direction:ltr;
+}
+.t1 { width:7.3em; }
+.t2 { width:20px;}
+.t3 { width:22px;}
+.t4 { width:1px; font-family:Ahem; }
+.t3 span {margin-left:14px; }
+
+m { font-size:20px; color:blue; }
+
+</style>
+
+</head><body>
+
+<div class="test t1"><span><span class="xspan">0123&nbsp;56789012</span><m>&#x2026;</m></span></div>
+<div class="test rtl t1"><span><span class="xspan">1&nbsp;56789012345</span><m>&#x2026;</m></span></div>
+<div class="test rtl t2"><span><m>&#x2026;</m><span style="visibility:hidden">&nbsp;</span></span></div>
+<div class="test rtl t3"><span><m>&#x2026;</m><span style="visibility:hidden">&nbsp;</span></span></div>
+<div class="test t4"><span><m>&#x2026;</m><span style="visibility:hidden">&nbsp;</span></span></div>
+
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/quirks-decorations.html
@@ -0,0 +1,74 @@
+<!--
+    Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/licenses/publicdomain/
+
+    Test: Quirks mode text-decorations
+-->
+<html><head>
+<title>text-overflow: Quirks mode text-decorations</title>
+<style type="text/css">
+@font-face {
+  font-family: Ahem;
+  src: url(../fonts/Ahem.ttf);
+}
+@font-face {
+  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:hidden;
+  text-overflow:ellipsis;
+  float:left;
+  height:2em;
+  white-space:pre;
+  margin-left:1em;
+  margin-bottom:1em;
+  font-size:20px;
+  color:blue;
+}
+span {
+  text-shadow:0px 1em 2px blue;
+  text-decoration: line-through;
+  font-size:16px;
+  color:black;
+}
+.rtl span {
+  text-shadow:0 1em 0px blue;
+}
+.rlo {
+  unicode-bidi: bidi-override; direction:rtl;
+}
+.lro {
+  unicode-bidi: bidi-override;
+}
+.rtl {
+  direction:rtl;
+}
+.ltr {
+  direction:ltr;
+}
+.t1 { width:7.3em;}
+.t2 { width:20px;}
+.t3 { width:22px; }
+.t4 { width:1px; font-family:Ahem; }
+.t3 span {margin-left:14px; }
+
+m { font-size:20px; }
+
+</style>
+
+</head><body>
+
+<div class="test t1"><span>0123&nbsp;567890123456789</span><m>x</m></div>
+<div class="test rtl t1"><m>x</m><span>0321&nbsp;56789012345</span></div>
+<div class="test t2"><span>xxxx<m>x</m></span></div>
+<div class="test t3"><span>x<m>x</m></span></div>
+<div class="test t4"><span>x<m>x</m></span></div>
+
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/quirks-line-height-ref.html
@@ -0,0 +1,57 @@
+<!--
+    Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/licenses/publicdomain/
+-->
+<html><head>
+<title>text-overflow: Quirks mode line height</title>
+<style type="text/css">
+@font-face {
+  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:hidden;
+
+  float:left;
+  white-space:pre;
+  margin-left:1em;
+  margin-bottom:1em;
+  font-size:24px; 
+  color:blue;
+  border:1px solid black;
+  position:relative;
+}
+span {
+  font-size:16px;
+  color:black;
+}
+.rlo {
+  unicode-bidi: bidi-override; direction:rtl;
+}
+.lro {
+  unicode-bidi: bidi-override;
+}
+.rtl {
+  direction:rtl;
+}
+.ltr {
+  direction:ltr;
+}
+.t1 { width:4em; }
+
+m { font-size:24px; color:blue; line-height:8px; }
+
+</style>
+
+</head><body>
+
+<div class="test t1"><span>0123456|</span><m>&#x2026;</m></div>
+<div class="test rtl rlo t1"><span>0123456|</span><m>&#x2026;</m></div>
+
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/quirks-line-height.html
@@ -0,0 +1,56 @@
+<!--
+    Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/licenses/publicdomain/
+
+    Test: Quirks mode line height should not be affected by marker
+-->
+<html><head>
+<title>text-overflow: Quirks mode line height</title>
+<style type="text/css">
+@font-face {
+  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:hidden;
+  text-overflow:ellipsis;
+  float:left;
+  white-space:pre;
+  margin-left:1em;
+  margin-bottom:1em;
+  font-size:24px;
+  color:blue;
+  border:1px solid black;
+}
+span {
+  font-size:16px;
+  color:black;
+}
+.rlo {
+  unicode-bidi: bidi-override; direction:rtl;
+}
+.lro {
+  unicode-bidi: bidi-override;
+}
+.rtl {
+  direction:rtl;
+}
+.ltr {
+  direction:ltr;
+}
+.t1 { width:4em; }
+
+</style>
+
+</head><body>
+
+<div class="test t1"><span>0123456|890123456789</span></div>
+<div class="test rtl rlo t1"><span>0123456|89012345</span></div>
+
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/reftest.list
@@ -0,0 +1,14 @@
+== ellipsis-font-fallback.html ellipsis-font-fallback-ref.html
+HTTP(..) == marker-basic.html marker-basic-ref.html
+HTTP(..) == marker-string.html marker-string-ref.html
+skip-if(Android) HTTP(..) == bidi-simple.html bidi-simple-ref.html # Fails on Android due to anti-aliasing
+skip-if(!gtk2Widget) HTTP(..) == bidi-simple-scrolled.html bidi-simple-scrolled-ref.html # Fails on Windows and OSX due to anti-aliasing
+HTTP(..) == scroll-rounding.html scroll-rounding-ref.html
+HTTP(..) == anonymous-block.html anonymous-block-ref.html
+HTTP(..) == false-marker-overlap.html false-marker-overlap-ref.html
+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
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/scroll-rounding-ref.html
@@ -0,0 +1,92 @@
+<!DOCTYPE HTML>
+<!--
+    Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/licenses/publicdomain/
+
+    Test: 1px scroll rounding at the end position
+-->
+<html class="reftest-wait"><head>
+<title>text-overflow: scroll rounding</title>
+<style type="text/css">
+@font-face {
+  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;
+  width:100px;
+  height:50px;
+  border:1px solid black;
+  white-space:pre;
+  margin-left:90px;
+  margin-bottom:20px;
+}
+
+.rtl {
+  direction:rtl;  margin-left:0;
+}
+.ltr {
+  direction:ltr;
+}
+
+.t1 {width:100.1px;}
+.t2 {width:100.2px;}
+.t3 {width:100.3px;}
+.t4 {width:100.4px;}
+
+s {position:absolute; background:black; z-index:1; }
+#mask1 {top:0; left:60px; width:70px; height:100%; }
+#mask2 {top:30px; left:0; width:100%; height:30px; }
+#mask3 {top:100px; left:0; width:100%; height:30px; }
+#mask4 {top:170px; left:0; width:100%; height:30px; }
+#mask5 {top:240px; left:0; width:100%; height:30px; }
+#mask6 {top:320px; left:0; width:100%; height:30px; }
+#mask7 {top:390px; left:0; width:100%; height:30px; }
+#mask8 {top:460px; left:0; width:100%; height:30px; }
+#mask9 {top:530px; left:0; width:100%; height:30px; }
+#mask10 {top:600px; left:0; width:100%; height:30px; }
+#mask11 {top:670px; left:0; width:100%; height:30px; }
+</style>
+<script>
+function scrolldivs() {
+ var divs = document.getElementsByTagName('div');
+  for (i = 0; i < divs.length; ++i) {
+    if (window.getComputedStyle(divs[i]).direction == 'ltr')
+      divs[i].scrollLeft = 99999999;
+    else
+      divs[i].scrollLeft = -99999999;
+  }
+  document.documentElement.removeAttribute('class');
+}
+</script>
+
+</head><body onload="scrolldivs()">
+
+<s id="mask1"></s>
+<s id="mask2"></s>
+<s id="mask3"></s>
+<s id="mask4"></s>
+<s id="mask5"></s>
+<s id="mask6"></s>
+<s id="mask7"></s>
+<s id="mask8"></s>
+<s id="mask9"></s>
+<s id="mask10"></s>
+<s id="mask11"></s>
+
+<div class="test">HelloKittyוסוכנויות</div>
+<div class="test rtl">HelloKittyוסוכנויות</div>
+<div class="test t1">HelloKittyוסוכנויות</div>
+<div class="test rtl t1">HelloKittyוסוכנויות</div>
+<div class="test t2">HelloKittyוסוכנויות</div>
+<div class="test rtl t2">HelloKittyוסוכנויות</div>
+<div class="test t3">HelloKittyוסוכנויות</div>
+<div class="test rtl t3">HelloKittyוסוכנויות</div>
+<div class="test t4">HelloKittyוסוכנויות</div>
+<div class="test rtl t4">HelloKittyוסוכנויות</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/scroll-rounding.html
@@ -0,0 +1,93 @@
+<!DOCTYPE HTML>
+<!--
+    Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/licenses/publicdomain/
+
+    Test: 1px scroll rounding at the end position
+-->
+<html class="reftest-wait"><head>
+<title>text-overflow: scroll rounding</title>
+<style type="text/css">
+@font-face {
+  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 {
+  text-overflow:ellipsis;
+  overflow:auto;
+  width:100px;
+  height:50px;
+  border:1px solid black;
+  white-space:pre;
+  margin-left:90px;
+  margin-bottom:20px;
+}
+
+.rtl {
+  direction:rtl;  margin-left:0;
+}
+.ltr {
+  direction:ltr;
+}
+
+.t1 {width:100.1px;}
+.t2 {width:100.2px;}
+.t3 {width:100.3px;}
+.t4 {width:100.4px;}
+
+s {position:absolute; background:black; z-index:1; }
+#mask1 {top:0; left:60px; width:70px; height:100%; }
+#mask2 {top:30px; left:0; width:100%; height:30px; }
+#mask3 {top:100px; left:0; width:100%; height:30px; }
+#mask4 {top:170px; left:0; width:100%; height:30px; }
+#mask5 {top:240px; left:0; width:100%; height:30px; }
+#mask6 {top:320px; left:0; width:100%; height:30px; }
+#mask7 {top:390px; left:0; width:100%; height:30px; }
+#mask8 {top:460px; left:0; width:100%; height:30px; }
+#mask9 {top:530px; left:0; width:100%; height:30px; }
+#mask10 {top:600px; left:0; width:100%; height:30px; }
+#mask11 {top:670px; left:0; width:100%; height:30px; }
+</style>
+<script>
+function scrolldivs() {
+ var divs = document.getElementsByTagName('div');
+  for (i = 0; i < divs.length; ++i) {
+    if (window.getComputedStyle(divs[i]).direction == 'ltr')
+      divs[i].scrollLeft = 99999999;
+    else
+      divs[i].scrollLeft = -99999999;
+  }
+  document.documentElement.removeAttribute('class');
+}
+</script>
+
+</head><body onload="scrolldivs()">
+
+<s id="mask1"></s>
+<s id="mask2"></s>
+<s id="mask3"></s>
+<s id="mask4"></s>
+<s id="mask5"></s>
+<s id="mask6"></s>
+<s id="mask7"></s>
+<s id="mask8"></s>
+<s id="mask9"></s>
+<s id="mask10"></s>
+<s id="mask11"></s>
+
+<div class="test">HelloKittyוסוכנויות</div>
+<div class="test rtl">HelloKittyוסוכנויות</div>
+<div class="test t1">HelloKittyוסוכנויות</div>
+<div class="test rtl t1">HelloKittyוסוכנויות</div>
+<div class="test t2">HelloKittyוסוכנויות</div>
+<div class="test rtl t2">HelloKittyוסוכנויות</div>
+<div class="test t3">HelloKittyוסוכנויות</div>
+<div class="test rtl t3">HelloKittyוסוכנויות</div>
+<div class="test t4">HelloKittyוסוכנויות</div>
+<div class="test rtl t4">HelloKittyוסוכנויות</div>
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/standards-decorations-ref.html
@@ -0,0 +1,72 @@
+<!DOCTYPE HTML>
+<!--
+    Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/licenses/publicdomain/
+-->
+<html><head>
+<title>text-overflow: Standards mode text-decorations</title>
+<style type="text/css">
+@font-face {
+  font-family: Ahem;
+  src: url(../fonts/Ahem.ttf);
+}
+@font-face {
+  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:hidden;
+  float:left;
+  height:2em;
+  white-space:pre;
+  margin-left:1em;
+  margin-bottom:1em;
+  font-size:20px;
+  color:blue;
+}
+span {
+  font-size:16px;
+  color:black;
+}
+.xspan {
+  text-decoration: line-through;
+}
+.t1 .xspan {
+}
+.rlo {
+  unicode-bidi: bidi-override; direction:rtl;
+}
+.lro {
+  unicode-bidi: bidi-override;
+}
+.rtl {
+  direction:rtl;
+}
+.ltr {
+  direction:ltr;
+}
+.t1 { width:7.3em;}
+.t2 { width:20px;}
+.t3 { width:22px;}
+.t4 { width:1px; font-family:Ahem; }
+.t3 span {margin-left:14px; }
+
+m { font-size:20px; color:blue; }
+
+</style>
+
+</head><body>
+
+<div class="test t1"><span><span class="xspan">0123&nbsp;56789012</span><m>&#x2026;</m></span></div>
+<div class="test rtl t1"><span><span class="xspan">1&nbsp;56789012345</span><m>&#x2026;</m></span></div>
+<div class="test rtl t2" style="color:black">&#x2026;<span><span class="xspan">&nbsp;</span></span></div>
+<div class="test rtl t3"><span><m>&#x2026;</m><span style="visibility:hidden">&nbsp;</span></span></div>
+<div class="test t4"><span><m>&#x2026;</m><span style="visibility:hidden">&nbsp;</span></span></div>
+
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/standards-decorations.html
@@ -0,0 +1,73 @@
+<!DOCTYPE HTML>
+<!--
+    Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/licenses/publicdomain/
+
+    Test: Standards mode text-decorations
+-->
+<html><head>
+<title>text-overflow: Standards mode text-decorations</title>
+<style type="text/css">
+@font-face {
+  font-family: Ahem;
+  src: url(../fonts/Ahem.ttf);
+}
+@font-face {
+  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:hidden;
+  text-overflow:ellipsis;
+  float:left;
+  height:2em;
+  white-space:pre;
+  margin-left:1em;
+  margin-bottom:1em;
+  font-size:20px;
+  color:blue;
+}
+span {
+  text-decoration: line-through;
+  font-size:16px;
+  color:black;
+}
+.t1 span {
+}
+.rlo {
+  unicode-bidi: bidi-override; direction:rtl;
+}
+.lro {
+  unicode-bidi: bidi-override;
+}
+.rtl {
+  direction:rtl;
+}
+.ltr {
+  direction:ltr;
+}
+.t1 { width:7.3em;}
+.t2 { width:20px;}
+.t3 { width:22px;}
+.t4 { width:1px; font-family:Ahem; }
+.t3 span {margin-left:14px; }
+
+m { font-size:20px; }
+
+</style>
+
+</head><body>
+
+<div class="test t1"><span>0123&nbsp;567890123456789</span></div>
+<div class="test rtl t1"><span>0321&nbsp;56789012345</span></div>
+<div class="test t2" style="color:black"><span>xxxx</span></div>
+<div class="test t3"><span>x</span></div>
+<div class="test t4"><span>x</span></div>
+
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/standards-line-height-ref.html
@@ -0,0 +1,58 @@
+<!DOCTYPE HTML>
+<!--
+    Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/licenses/publicdomain/
+-->
+<html><head>
+<title>text-overflow: Standards mode line height</title>
+<style type="text/css">
+@font-face {
+  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:hidden;
+
+  float:left;
+  white-space:pre;
+  margin-left:1em;
+  margin-bottom:1em;
+  font-size:24px; 
+  color:blue;
+  border:1px solid black;
+  position:relative;
+}
+span {
+  font-size:16px;
+  color:black;
+}
+.rlo {
+  unicode-bidi: bidi-override; direction:rtl;
+}
+.lro {
+  unicode-bidi: bidi-override;
+}
+.rtl {
+  direction:rtl;
+}
+.ltr {
+  direction:ltr;
+}
+.t1 { width:4em; }
+
+m { font-size:24px; color:blue; line-height:8px; }
+
+</style>
+
+</head><body>
+
+<div class="test t1"><span>0123456|</span><m>&#x2026;</m></div>
+<div class="test rtl rlo t1"><span>0123456|</span><m>&#x2026;</m></div>
+
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/standards-line-height.html
@@ -0,0 +1,57 @@
+<!DOCTYPE HTML>
+<!--
+    Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/licenses/publicdomain/
+
+    Test: Standards mode line height should not be affected by marker
+-->
+<html><head>
+<title>text-overflow: Standards mode line height</title>
+<style type="text/css">
+@font-face {
+  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:hidden;
+  text-overflow:ellipsis;
+  float:left;
+  white-space:pre;
+  margin-left:1em;
+  margin-bottom:1em;
+  font-size:24px;
+  color:blue;
+  border:1px solid black;
+}
+span {
+  font-size:16px;
+  color:black;
+}
+.rlo {
+  unicode-bidi: bidi-override; direction:rtl;
+}
+.lro {
+  unicode-bidi: bidi-override;
+}
+.rtl {
+  direction:rtl;
+}
+.ltr {
+  direction:ltr;
+}
+.t1 { width:4em; }
+
+</style>
+
+</head><body>
+
+<div class="test t1"><span>0123456|890123456789</span></div>
+<div class="test rtl rlo t1"><span>0123456|89012345</span></div>
+
+
+</body>
+</html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/visibility-hidden-ref.html
@@ -0,0 +1,72 @@
+<!DOCTYPE HTML>
+<!--
+    Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/licenses/publicdomain/
+-->
+<html><head>
+<title>text-overflow: visibility:hidden</title>
+<style type="text/css">
+@font-face {
+  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: hidden; 
+  white-space: nowrap;
+  background:lime;
+  color: black;
+  width: 50%;
+}
+
+.rtl {
+  direction:rtl;
+}
+.rlo {
+  unicode-bidi: bidi-override; direction: rtl;
+}
+u {
+  visibility:hidden;
+  padding-left: 3em;
+  background: cyan;
+}
+.rtl u {padding-right: 3em; padding-left:0;}
+s {
+  visibility:visible;
+}
+
+.t1 {width:10em;}
+.t2 {width:14em;}
+.t3 {width:13.5em;}
+.t3 u { padding-right:1em; }
+.t3.rtl u {padding-left:1em; padding-right: 3em; }
+.t4 {width:12.5em;}
+</style>
+
+</head><body>
+
+<div class="test t2">
+CSS is awesome<u></u><br>
+CSS is awesome<u>&nbsp;<s>x</s>&nbsp;</u>
+</div>
+<div class="test t1">CSS is awesome<u></u><br></div>
+<div class="test t2">CSS is awesome<u>&nbsp;<s>x</s>&nbsp;</u></div>
+<div class="test t3">CSS is awesome<u>&nbsp;<s>x</s></u></div>
+<div class="test t4">CSS is awesome<m>&#x2026;</m><u>&nbsp;<s></s></u></div>
+
+<div class="rtl">
+<div class="test rtl rlo t2">
+CSS is awesome<u></u><br>
+CSS is awesome<u>&nbsp;<s>x</s></u>
+</div>
+<div class="test rtl rlo t1">CSS is awesome<u></u><br></div>
+<div class="test rtl rlo t2">CSS is awesome<u>&nbsp;<s>x</s>&nbsp;</u></div>
+<div class="test rtl rlo t3">CSS is awesome<u>&nbsp;<s>x</s></u></div>
+<div class="test rtl rlo t4">CSS is awesome<m>&#x2026;</m><u>&nbsp;<s></s></u></div>
+</div>
+
+</body></html>
new file mode 100644
--- /dev/null
+++ b/layout/reftests/text-overflow/visibility-hidden.html
@@ -0,0 +1,74 @@
+<!DOCTYPE HTML>
+<!--
+    Any copyright is dedicated to the Public Domain.
+    http://creativecommons.org/licenses/publicdomain/
+
+    Test: visibility:hidden should not trigger text-overflow markers
+-->
+<html><head>
+<title>text-overflow: visibility:hidden</title>
+<style type="text/css">
+@font-face {
+  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 { 
+  text-overflow:ellipsis;
+  overflow: hidden; 
+  white-space: nowrap;
+  background:lime;
+  color: black;
+  width: 50%;
+}
+
+.rtl {
+  direction:rtl;
+}
+.rlo {
+  unicode-bidi: bidi-override; direction: rtl;
+}
+u {
+  visibility:hidden;
+  padding-left: 3em;
+  background: cyan;
+}
+.rtl u {padding-right: 3em; padding-left:0;}
+s {
+  visibility:visible;
+}
+
+.t1 {width:10em;}
+.t2 {width:14em;}
+.t3 {width:13.5em;}
+.t3 u { padding-right:1em; }
+.t3.rtl u {padding-left:1em; padding-right: 3em; }
+.t4 {width:12.5em;}
+</style>
+
+</head><body>
+
+<div class="test t2">
+CSS is awesome<u></u><br>
+CSS is awesome<u>&nbsp;<s>x</s>&nbsp;&nbsp;&nbsp;</u>
+</div>
+<div class="test t1">CSS is awesome<u></u><br></div>
+<div class="test t2">CSS is awesome<u>&nbsp;<s>x</s>&nbsp;&nbsp;&nbsp;</u></div>
+<div class="test t3">CSS is awesome<u>&nbsp;<s>x</s></u></div>
+<div class="test t4">CSS is awesome<u>&nbsp;<s>x</s></u></div>
+
+<div class="rtl">
+<div class="test rtl rlo t2">
+CSS is awesome<u></u><br>
+CSS is awesome<u>&nbsp;<s>x</s></u>
+</div>
+<div class="test rtl rlo t1">CSS is awesome<u></u><br></div>
+<div class="test rtl rlo t2">CSS is awesome<u>&nbsp;<s>x</s>&nbsp;&nbsp;&nbsp;</u></div>
+<div class="test rtl rlo t3">CSS is awesome<u>&nbsp;<s>x</s></u></div>
+<div class="test rtl rlo t4">CSS is awesome<u>&nbsp;<s>x</s></u></div>
+</div>
+
+</body></html>
--- a/layout/style/forms.css
+++ b/layout/style/forms.css
@@ -14,16 +14,17 @@
  * The Original Code is mozilla.org code.
  *
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 1998
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
+ *   Mats Palmgren <matspal@gmail.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -40,16 +41,17 @@
  
 
 @namespace url(http://www.w3.org/1999/xhtml); /* set default namespace to HTML */
 @namespace xul url(http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul);
 
 *|*::-moz-fieldset-content {
   display: block;
   unicode-bidi: inherit;
+  text-overflow: inherit;
   height: 100%;   /* Need this so percentage heights of kids work right */
 }
 
 /* miscellaneous form elements */
 
 fieldset > legend {
   padding-left: 2px;
   padding-right: 2px;
@@ -619,16 +621,17 @@ input[type="submit"]:disabled {
   *  so they need no special rules.
   */
 textarea > .anonymous-div,
 input > .anonymous-div,
 *|*::-moz-button-content,
 *|*::-moz-display-comboboxcontrol-frame,
 optgroup:before {
   unicode-bidi: inherit;
+  text-overflow: inherit;
 }
 
  /*
   * Force the text control child of file input controls to have left-to-right
   * directionality. Otherwise filenames containing right-to-left characters
   * will be reordered with chaotic results.
   */
 input[type="file"] > input[type="text"] {
--- a/layout/style/nsCSSKeywordList.h
+++ b/layout/style/nsCSSKeywordList.h
@@ -15,16 +15,17 @@
  * The Original Code is mozilla.org code.
  *
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 1999
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
+ *   Mats Palmgren <matspal@gmail.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -216,16 +217,17 @@ CSS_KEY(buttontext, buttontext)
 CSS_KEY(capitalize, capitalize)
 CSS_KEY(caption, caption)
 CSS_KEY(captiontext, captiontext)
 CSS_KEY(cell, cell)
 CSS_KEY(center, center)
 CSS_KEY(ch, ch)
 CSS_KEY(circle, circle)
 CSS_KEY(cjk-ideographic, cjk_ideographic)
+CSS_KEY(clip, clip)
 CSS_KEY(close-quote, close_quote)
 CSS_KEY(closest-corner, closest_corner)
 CSS_KEY(closest-side, closest_side)
 CSS_KEY(cm, cm)
 CSS_KEY(col-resize, col_resize)
 CSS_KEY(collapse, collapse)
 CSS_KEY(condensed, condensed)
 CSS_KEY(contain, contain)
@@ -252,16 +254,17 @@ CSS_KEY(e-resize, e_resize)
 CSS_KEY(each-box, each_box)
 CSS_KEY(ease, ease)
 CSS_KEY(ease-in, ease_in)
 CSS_KEY(ease-in-out, ease_in_out)
 CSS_KEY(ease-out, ease_out)
 CSS_KEY(element, element)
 CSS_KEY(elements, elements)
 CSS_KEY(ellipse, ellipse)
+CSS_KEY(ellipsis, ellipsis)
 CSS_KEY(em, em)
 CSS_KEY(embed, embed)
 CSS_KEY(enabled, enabled)
 CSS_KEY(end, end)
 CSS_KEY(ex, ex)
 CSS_KEY(expanded, expanded)
 CSS_KEY(extra-condensed, extra_condensed)
 CSS_KEY(extra-expanded, extra_expanded)
--- a/layout/style/nsCSSPropList.h
+++ b/layout/style/nsCSSPropList.h
@@ -16,17 +16,17 @@
  *
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 1999
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   L. David Baron <dbaron@dbaron.org>, Mozilla Corporation
- *   Mats Palmgren <mats.palmgren@bredband.net>
+ *   Mats Palmgren <matspal@gmail.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -2202,16 +2202,25 @@ CSS_PROP_TEXT(
     text_indent,
     TextIndent,
     CSS_PROPERTY_PARSE_VALUE |
         CSS_PROPERTY_STORES_CALC,
     VARIANT_HLP | VARIANT_CALC,
     nsnull,
     offsetof(nsStyleText, mTextIndent),
     eStyleAnimType_Coord)
+CSS_PROP_TEXTRESET(
+    text-overflow,
+    text_overflow,
+    TextOverflow,
+    CSS_PROPERTY_PARSE_VALUE,
+    VARIANT_HK | VARIANT_STRING,
+    kTextOverflowKTable,
+    offsetof(nsStyleTextReset, mTextOverflow),
+    eStyleAnimType_None)
 CSS_PROP_TEXT(
     text-shadow,
     text_shadow,
     TextShadow,
     CSS_PROPERTY_PARSE_FUNCTION |
         CSS_PROPERTY_APPLIES_TO_FIRST_LETTER_AND_FIRST_LINE |
         CSS_PROPERTY_VALUE_LIST_USES_COMMAS |
         CSS_PROPERTY_IGNORED_WHEN_COLORS_DISABLED,
--- a/layout/style/nsCSSProps.cpp
+++ b/layout/style/nsCSSProps.cpp
@@ -15,17 +15,17 @@
  * The Original Code is mozilla.org code.
  *
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 1999
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
- *   Mats Palmgren <mats.palmgren@bredband.net>
+ *   Mats Palmgren <matspal@gmail.com>
  *   Jonathon Jongsma <jonathon.jongsma@collabora.co.uk>, Collabora Ltd.
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
@@ -1209,16 +1209,22 @@ const PRInt32 nsCSSProps::kTextDecoratio
   eCSSKeyword_solid, NS_STYLE_TEXT_DECORATION_STYLE_SOLID,
   eCSSKeyword_double, NS_STYLE_TEXT_DECORATION_STYLE_DOUBLE,
   eCSSKeyword_dotted, NS_STYLE_TEXT_DECORATION_STYLE_DOTTED,
   eCSSKeyword_dashed, NS_STYLE_TEXT_DECORATION_STYLE_DASHED,
   eCSSKeyword_wavy, NS_STYLE_TEXT_DECORATION_STYLE_WAVY,
   eCSSKeyword_UNKNOWN,-1
 };
 
+const PRInt32 nsCSSProps::kTextOverflowKTable[] = {
+  eCSSKeyword_clip, NS_STYLE_TEXT_OVERFLOW_CLIP,
+  eCSSKeyword_ellipsis, NS_STYLE_TEXT_OVERFLOW_ELLIPSIS,
+  eCSSKeyword_UNKNOWN, -1
+};
+
 const PRInt32 nsCSSProps::kTextTransformKTable[] = {
   eCSSKeyword_none, NS_STYLE_TEXT_TRANSFORM_NONE,
   eCSSKeyword_capitalize, NS_STYLE_TEXT_TRANSFORM_CAPITALIZE,
   eCSSKeyword_lowercase, NS_STYLE_TEXT_TRANSFORM_LOWERCASE,
   eCSSKeyword_uppercase, NS_STYLE_TEXT_TRANSFORM_UPPERCASE,
   eCSSKeyword_UNKNOWN,-1
 };
 
--- a/layout/style/nsCSSProps.h
+++ b/layout/style/nsCSSProps.h
@@ -15,17 +15,17 @@
  * The Original Code is mozilla.org code.
  *
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 1998
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
- *   Mats Palmgren <mats.palmgren@bredband.net>
+ *   Mats Palmgren <matspal@gmail.com>
  *   Jonathon Jongsma <jonathon.jongsma@collabora.co.uk>, Collabora Ltd.
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
@@ -402,16 +402,17 @@ public:
   static const PRInt32 kSpeakPunctuationKTable[];
   static const PRInt32 kSpeechRateKTable[];
   static const PRInt32 kStackSizingKTable[];
   static const PRInt32 kTableLayoutKTable[];
   static const PRInt32 kTextAlignKTable[];
   static const PRInt32 kTextBlinkKTable[];
   static const PRInt32 kTextDecorationLineKTable[];
   static const PRInt32 kTextDecorationStyleKTable[];
+  static const PRInt32 kTextOverflowKTable[];
   static const PRInt32 kTextTransformKTable[];
   static const PRInt32 kTransitionTimingFunctionKTable[];
   static const PRInt32 kUnicodeBidiKTable[];
   static const PRInt32 kUserFocusKTable[];
   static const PRInt32 kUserInputKTable[];
   static const PRInt32 kUserModifyKTable[];
   static const PRInt32 kUserSelectKTable[];
   static const PRInt32 kVerticalAlignKTable[];
--- a/layout/style/nsComputedDOMStyle.cpp
+++ b/layout/style/nsComputedDOMStyle.cpp
@@ -18,17 +18,17 @@
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 1998
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Daniel Glazman <glazman@netscape.com>
  *   Boris Zbarsky <bzbarsky@mit.edu>
  *   Christopher A. Aillon <christopher@aillon.com>
- *   Mats Palmgren <mats.palmgren@bredband.net>
+ *   Mats Palmgren <matspal@gmail.com>
  *   Christian Biesinger <cbiesinger@web.de>
  *   Michael Ventnor <m.ventnor@gmail.com>
  *   Jonathon Jongsma <jonathon.jongsma@collabora.co.uk>, Collabora Ltd.
  *   L. David Baron <dbaron@dbaron.org>, Mozilla Corporation
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
@@ -2380,16 +2380,34 @@ nsComputedDOMStyle::DoGetTextIndent()
 {
   nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
   SetValueToCoord(val, GetStyleText()->mTextIndent, PR_FALSE,
                   &nsComputedDOMStyle::GetCBContentWidth);
   return val;
 }
 
 nsIDOMCSSValue*
+nsComputedDOMStyle::DoGetTextOverflow()
+{
+  nsROCSSPrimitiveValue *val = GetROCSSPrimitiveValue();
+  const nsStyleTextReset *style = GetStyleTextReset();
+
+  if (style->mTextOverflow.mType == NS_STYLE_TEXT_OVERFLOW_STRING) {
+    nsString str;
+    nsStyleUtil::AppendEscapedCSSString(style->mTextOverflow.mString, str);
+    val->SetString(str);
+  } else {
+    val->SetIdent(
+      nsCSSProps::ValueToKeywordEnum(style->mTextOverflow.mType,
+                                     nsCSSProps::kTextOverflowKTable));
+  }
+  return val;
+}
+
+nsIDOMCSSValue*
 nsComputedDOMStyle::DoGetTextShadow()
 {
   return GetCSSShadowArray(GetStyleText()->mTextShadow,
                            GetStyleColor()->mColor,
                            PR_FALSE);
 }
 
 nsIDOMCSSValue*
@@ -4309,16 +4327,17 @@ nsComputedDOMStyle::GetQueryableProperty
     COMPUTED_STYLE_MAP_ENTRY(quotes,                        Quotes),
     COMPUTED_STYLE_MAP_ENTRY(resize,                        Resize),
     COMPUTED_STYLE_MAP_ENTRY_LAYOUT(right,                  Right),
     //// COMPUTED_STYLE_MAP_ENTRY(size,                     Size),
     COMPUTED_STYLE_MAP_ENTRY(table_layout,                  TableLayout),
     COMPUTED_STYLE_MAP_ENTRY(text_align,                    TextAlign),
     COMPUTED_STYLE_MAP_ENTRY(text_decoration,               TextDecoration),
     COMPUTED_STYLE_MAP_ENTRY_LAYOUT(text_indent,            TextIndent),
+    COMPUTED_STYLE_MAP_ENTRY(text_overflow,                 TextOverflow),
     COMPUTED_STYLE_MAP_ENTRY(text_shadow,                   TextShadow),
     COMPUTED_STYLE_MAP_ENTRY(text_transform,                TextTransform),
     COMPUTED_STYLE_MAP_ENTRY_LAYOUT(top,                    Top),
     COMPUTED_STYLE_MAP_ENTRY(unicode_bidi,                  UnicodeBidi),
     COMPUTED_STYLE_MAP_ENTRY_LAYOUT(vertical_align,         VerticalAlign),
     COMPUTED_STYLE_MAP_ENTRY(visibility,                    Visibility),
     COMPUTED_STYLE_MAP_ENTRY(white_space,                   WhiteSpace),
     // COMPUTED_STYLE_MAP_ENTRY(widows,                     Widows),
--- a/layout/style/nsComputedDOMStyle.h
+++ b/layout/style/nsComputedDOMStyle.h
@@ -308,16 +308,17 @@ private:
   nsIDOMCSSValue* DoGetLineHeight();
   nsIDOMCSSValue* DoGetTextAlign();
   nsIDOMCSSValue* DoGetMozTextBlink();
   nsIDOMCSSValue* DoGetTextDecoration();
   nsIDOMCSSValue* DoGetMozTextDecorationColor();
   nsIDOMCSSValue* DoGetMozTextDecorationLine();
   nsIDOMCSSValue* DoGetMozTextDecorationStyle();
   nsIDOMCSSValue* DoGetTextIndent();
+  nsIDOMCSSValue* DoGetTextOverflow();
   nsIDOMCSSValue* DoGetTextTransform();
   nsIDOMCSSValue* DoGetTextShadow();
   nsIDOMCSSValue* DoGetLetterSpacing();
   nsIDOMCSSValue* DoGetWordSpacing();
   nsIDOMCSSValue* DoGetWhiteSpace();
   nsIDOMCSSValue* DoGetWordWrap();
   nsIDOMCSSValue* DoGetHyphens();
   nsIDOMCSSValue* DoGetMozTabSize();
--- a/layout/style/nsRuleNode.cpp
+++ b/layout/style/nsRuleNode.cpp
@@ -18,17 +18,17 @@
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 1998
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   Original Author: David W. Hyatt (hyatt@netscape.com)
  *   Daniel Glazman <glazman@netscape.com>
  *   Roger B. Sidje <rbs@maths.uq.edu.au>
- *   Mats Palmgren <mats.palmgren@bredband.net>
+ *   Mats Palmgren <matspal@gmail.com>
  *   L. David Baron <dbaron@dbaron.org>
  *   Christian Biesinger <cbiesinger@web.de>
  *   Michael Ventnor <m.ventnor@gmail.com>
  *   Keith Rarick <kr@xph.us>
  *   Jonathon Jongsma <jonathon.jongsma@collabora.co.uk>, Collabora Ltd.
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
@@ -3445,16 +3445,34 @@ 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: enum, string, inherit, initial
+  const nsCSSValue* textOverflowValue =
+    aRuleData->ValueForTextOverflow();
+  if (eCSSUnit_Enumerated == textOverflowValue->GetUnit() ||
+      eCSSUnit_Initial    == textOverflowValue->GetUnit()) {
+    SetDiscrete(*textOverflowValue, text->mTextOverflow.mType,
+                canStoreInRuleTree,
+                SETDSC_ENUMERATED, parentText->mTextOverflow.mType,
+                NS_STYLE_TEXT_OVERFLOW_CLIP, 0, 0, 0, 0);
+    text->mTextOverflow.mString.Truncate();
+  } else if (eCSSUnit_Inherit == textOverflowValue->GetUnit()) {
+    canStoreInRuleTree = PR_FALSE;
+    text->mTextOverflow = parentText->mTextOverflow;
+  } else if (eCSSUnit_String == textOverflowValue->GetUnit()) {
+    textOverflowValue->GetStringValue(text->mTextOverflow.mString);
+    text->mTextOverflow.mType = NS_STYLE_TEXT_OVERFLOW_STRING;
+  }
+
   // unicode-bidi: enum, inherit, initial
   SetDiscrete(*aRuleData->ValueForUnicodeBidi(), text->mUnicodeBidi, canStoreInRuleTree,
               SETDSC_ENUMERATED, parentText->mUnicodeBidi,
               NS_STYLE_UNICODE_BIDI_NORMAL, 0, 0, 0, 0);
 
   COMPUTE_END_RESET(TextReset, text)
 }
 
--- a/layout/style/nsStyleStruct.cpp
+++ b/layout/style/nsStyleStruct.cpp
@@ -16,17 +16,17 @@
  *
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 1998
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   David Hyatt (hyatt@netscape.com)
- *   Mats Palmgren <mats.palmgren@bredband.net>
+ *   Mats Palmgren <matspal@gmail.com>
  *   Michael Ventnor <m.ventnor@gmail.com>
  *   Jonathon Jongsma <jonathon.jongsma@collabora.co.uk>, Collabora Ltd.
  *   L. David Baron <dbaron@dbaron.org>, Mozilla Corporation
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
@@ -48,17 +48,17 @@
 #include "nsStyleStruct.h"
 #include "nsStyleStructInlines.h"
 #include "nsStyleConsts.h"
 #include "nsThemeConstants.h"
 #include "nsString.h"
 #include "nsPresContext.h"
 #include "nsIWidget.h"
 #include "nsIStyleRule.h"
-#include "nsCRT.h"
+#include "nsCRTGlue.h"
 #include "nsCSSProps.h"
 
 #include "nsCOMPtr.h"
 #include "nsIFrame.h"
 #include "nsHTMLReflowState.h"
 #include "prenv.h"
 
 #include "nsSVGUtils.h"
@@ -104,16 +104,25 @@ static PRBool EqualImages(imgIRequest *a
   }
 
   nsCOMPtr<nsIURI> uri1, uri2;
   aImage1->GetURI(getter_AddRefs(uri1));
   aImage2->GetURI(getter_AddRefs(uri2));
   return EqualURIs(uri1, uri2);
 }
 
+// A nullsafe wrapper for strcmp. We depend on null-safety.
+static int safe_strcmp(const PRUnichar* a, const PRUnichar* b)
+{
+  if (!a || !b) {
+    return (int)(a - b);
+  }
+  return NS_strcmp(a, b);
+}
+
 static nsChangeHint CalcShadowDifference(nsCSSShadowArray* lhs,
                                          nsCSSShadowArray* rhs);
 
 // --------------------
 // nsStyleFont
 //
 nsStyleFont::nsStyleFont(const nsFont& aFont, nsPresContext *aPresContext)
   : mFont(aFont),
@@ -1439,17 +1448,17 @@ nsStyleImage::SetNull()
   NS_ABORT_IF_FALSE(!mImageTracked,
                     "Calling SetNull() with image tracked!");
 
   if (mType == eStyleImageType_Gradient)
     mGradient->Release();
   else if (mType == eStyleImageType_Image)
     NS_RELEASE(mImage);
   else if (mType == eStyleImageType_Element)
-    nsCRT::free(mElementId);
+    NS_Free(mElementId);
 
   mType = eStyleImageType_Null;
   mCropRect = nsnull;
 }
 
 void
 nsStyleImage::SetImageData(imgIRequest* aImage)
 {
@@ -1522,17 +1531,17 @@ nsStyleImage::SetGradientData(nsStyleGra
 
 void
 nsStyleImage::SetElementId(const PRUnichar* aElementId)
 {
   if (mType != eStyleImageType_Null)
     SetNull();
 
   if (aElementId) {
-    mElementId = nsCRT::strdup(aElementId);
+    mElementId = NS_strdup(aElementId);
     mType = eStyleImageType_Element;
   }
 }
 
 void
 nsStyleImage::SetCropRect(nsStyleSides* aCropRect)
 {
   if (aCropRect) {
@@ -1680,17 +1689,17 @@ nsStyleImage::operator==(const nsStyleIm
 
   if (mType == eStyleImageType_Image)
     return EqualImages(mImage, aOther.mImage);
 
   if (mType == eStyleImageType_Gradient)
     return *mGradient == *aOther.mGradient;
 
   if (mType == eStyleImageType_Element)
-    return nsCRT::strcmp(mElementId, aOther.mElementId) == 0;
+    return NS_strcmp(mElementId, aOther.mElementId) == 0;
 
   return PR_TRUE;
 }
 
 // --------------------
 // nsStyleBackground
 //
 
@@ -2301,17 +2310,17 @@ PRBool nsStyleContentData::operator==(co
     return thisURI == otherURI ||  // handles null==null
            (thisURI && otherURI &&
             NS_SUCCEEDED(thisURI->Equals(otherURI, &eq)) &&
             eq);
   }
   if (mType == eStyleContentType_Counter ||
       mType == eStyleContentType_Counters)
     return *mContent.mCounters == *aOther.mContent.mCounters;
-  return nsCRT::strcmp(mContent.mString, aOther.mContent.mString) == 0;
+  return safe_strcmp(mContent.mString, aOther.mContent.mString) == 0;
 }
 
 void
 nsStyleContentData::TrackImage(nsPresContext* aContext)
 {
   // Sanity
   NS_ABORT_IF_FALSE(!mImageTracked, "Already tracking image!");
   NS_ABORT_IF_FALSE(mType == eStyleContentType_Image,
@@ -2601,17 +2610,17 @@ nsStyleTextReset::nsStyleTextReset(void)
   mTextDecorationStyle =
     NS_STYLE_TEXT_DECORATION_STYLE_SOLID | BORDER_COLOR_FOREGROUND;
   mUnicodeBidi = NS_STYLE_UNICODE_BIDI_NORMAL;
 }
 
 nsStyleTextReset::nsStyleTextReset(const nsStyleTextReset& aSource) 
 { 
   MOZ_COUNT_CTOR(nsStyleTextReset);
-  memcpy((nsStyleTextReset*)this, &aSource, sizeof(nsStyleTextReset));
+  *this = aSource;
 }
 
 nsStyleTextReset::~nsStyleTextReset(void)
 {
   MOZ_COUNT_DTOR(nsStyleTextReset);
 }
 
 nsChangeHint nsStyleTextReset::CalcDifference(const nsStyleTextReset& aOther) const
@@ -2644,16 +2653,19 @@ nsChangeHint nsStyleTextReset::CalcDiffe
     nscolor decColor, otherDecColor;
     PRBool isFG, otherIsFG;
     GetDecorationColor(decColor, isFG);
     aOther.GetDecorationColor(otherDecColor, otherIsFG);
     if (isFG != otherIsFG || (!isFG && decColor != otherDecColor)) {
       return NS_STYLE_HINT_VISUAL;
     }
 
+    if (mTextOverflow != aOther.mTextOverflow) {
+      return NS_STYLE_HINT_VISUAL;
+    }
     return NS_STYLE_HINT_NONE;
   }
   return NS_STYLE_HINT_REFLOW;
 }
 
 #ifdef DEBUG
 /* static */
 nsChangeHint nsStyleTextReset::MaxDifference()
--- a/layout/style/nsStyleStruct.h
+++ b/layout/style/nsStyleStruct.h
@@ -1125,16 +1125,32 @@ private:
   static PRBool WidthCoordDependsOnContainer(const nsStyleCoord &aCoord);
   static PRBool HeightCoordDependsOnContainer(const nsStyleCoord &aCoord)
   {
     return aCoord.GetUnit() == eStyleUnit_Auto || // CSS 2.1, 10.6.4, item (5)
            aCoord.HasPercent();
   }
 };
 
+struct nsStyleTextOverflow {
+  nsStyleTextOverflow() : mType(NS_STYLE_TEXT_OVERFLOW_CLIP) {}
+
+  bool operator==(const nsStyleTextOverflow& aOther) const {
+    return mType == aOther.mType &&
+           (mType != NS_STYLE_TEXT_OVERFLOW_STRING ||
+            mString == aOther.mString);
+  }
+  bool operator!=(const nsStyleTextOverflow& aOther) const {
+    return !(*this == aOther);
+  }
+
+  nsString mString;
+  PRUint8  mType;
+};
+
 struct nsStyleTextReset {
   nsStyleTextReset(void);
   nsStyleTextReset(const nsStyleTextReset& aOther);
   ~nsStyleTextReset(void);
 
   void* operator new(size_t sz, nsPresContext* aContext) CPP_THROW_NEW {
     return aContext->AllocateFromShell(sz);
   }
@@ -1182,16 +1198,17 @@ struct nsStyleTextReset {
 
   nsChangeHint CalcDifference(const nsStyleTextReset& aOther) const;
 #ifdef DEBUG
   static nsChangeHint MaxDifference();
 #endif
   static PRBool ForceCompare() { return PR_FALSE; }
 
   nsStyleCoord  mVerticalAlign;         // [reset] coord, percent, calc, enum (see nsStyleConsts.h)
+  nsStyleTextOverflow mTextOverflow;    // [reset] enum, string
 
   PRUint8 mTextBlink;                   // [reset] see nsStyleConsts.h
   PRUint8 mTextDecorationLine;          // [reset] see nsStyleConsts.h
   PRUint8 mUnicodeBidi;                 // [reset] see nsStyleConsts.h
 protected:
   PRUint8 mTextDecorationStyle;         // [reset] see nsStyleConsts.h
 
   nscolor mTextDecorationColor;         // [reset] the colors to use for a decoration lines, not used at currentColor
--- a/layout/style/test/property_database.js
+++ b/layout/style/test/property_database.js
@@ -16,16 +16,17 @@
  * The Original Code is property_database.js.
  *
  * The Initial Developer of the Original Code is the Mozilla Foundation.
  * Portions created by the Initial Developer are Copyright (C) 2007
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
  *   L. David Baron <dbaron@dbaron.org>, Mozilla Corporation (original author)
+ *   Mats Palmgren <matspal@gmail.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either the GNU General Public License Version 2 or later (the "GPL"), or
  * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -2493,16 +2494,24 @@ var gCSSProperties = {
 			"-moz-calc(-2px)",
 			"-moz-calc(50%)",
 			"-moz-calc(3*25px)",
 			"-moz-calc(25px*3)",
 			"-moz-calc(3*25px + 50%)",
 		],
 		invalid_values: []
 	},
+	"text-overflow": {
+		domProp: "textOverflow",
+		inherited: false,
+		type: CSS_TYPE_LONGHAND,
+		initial_values: [ "clip" ],
+		other_values: [ "ellipsis", '""', "''", '"hello"' ],
+		invalid_values: [ "none", "auto" ]
+	},
 	"text-shadow": {
 		domProp: "textShadow",
 		inherited: true,
 		type: CSS_TYPE_LONGHAND,
 		prerequisites: { "color": "blue" },
 		initial_values: [ "none" ],
 		other_values: [ "2px 2px", "2px 2px 1px", "2px 2px green", "2px 2px 1px green", "green 2px 2px", "green 2px 2px 1px", "green 2px 2px, blue 1px 3px 4px", "currentColor 3px 3px", "blue 2px 2px, currentColor 1px 2px",
 			/* calc() values */
--- a/layout/style/ua.css
+++ b/layout/style/ua.css
@@ -14,16 +14,17 @@
  * The Original Code is mozilla.org code.
  *
  * The Initial Developer of the Original Code is
  * Netscape Communications Corporation.
  * Portions created by the Initial Developer are Copyright (C) 1998
  * the Initial Developer. All Rights Reserved.
  *
  * Contributor(s):
+ *   Mats Palmgren <matspal@gmail.com>
  *
  * Alternatively, the contents of this file may be used under the terms of
  * either of the GNU General Public License Version 2 or later (the "GPL"),
  * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
  * in which case the provisions of the GPL or the LGPL are applicable instead
  * of those above. If you wish to allow use of your version of this file only
  * under the terms of either the GPL or the LGPL, and not to allow others to
  * use your version of this file under the terms of the MPL, indicate your
@@ -117,16 +118,17 @@
 }
 
 /* Miscellaneous */
 
 *|*::-moz-anonymous-block, *|*::-moz-cell-content {
   display: block !important;
   position: static !important;
   unicode-bidi: inherit;
+  text-overflow: inherit;
 }
 
 *|*::-moz-anonymous-block, *|*::-moz-anonymous-positioned-block {
   /* we currently inherit from the inline that is split */
   outline: inherit;
   outline-offset: inherit;
   clip-path: inherit;
   filter: inherit;
@@ -148,16 +150,17 @@
   padding: inherit;
   /* The display doesn't affect the kind of frame constructed here.  This just
      affects auto-width sizing of the block we create. */
   display: block;
   -moz-box-orient: inherit;
   /* make unicode-bidi inherit, otherwise it has no effect on text inputs and
      blocks with overflow: scroll; */
   unicode-bidi: inherit;
+  text-overflow: inherit;
   -moz-column-count: inherit;
   -moz-column-width: inherit;
   -moz-column-gap: inherit;
   -moz-column-rule: inherit;
   /* Do not change these. nsCSSFrameConstructor depends on them to create a good
      frame tree. */
   position: static !important;
   float: none !important;
@@ -174,16 +177,17 @@
   resize: both;
 %endif
 }
 
 *|*::-moz-column-content { 
   /* the column boxes inside a column-flowed block */
   /* make unicode-bidi inherit, otherwise it has no effect on column boxes */
   unicode-bidi: inherit;
+  text-overflow: inherit;
   /* inherit the outer frame's display, otherwise we turn into an inline */
   display: inherit !important;
   /* Carry through our parent's height so that %-height children get
   their heights set */
   height: 100%;
 }
 
 *|*::-moz-page-sequence, *|*::-moz-scrolled-page-sequence {
@@ -217,16 +221,17 @@
   top: inherit; 
   left: inherit;
   bottom: inherit;
   right: inherit;
   z-index: inherit;
   clip: inherit;
   opacity: inherit;
   unicode-bidi: inherit;
+  text-overflow: inherit;
 }
 
 /* Printing */
 
 @media print {
 
   * {
     cursor: default !important;
--- a/mobile/app/mobile.js
+++ b/mobile/app/mobile.js
@@ -578,17 +578,17 @@ pref("media.preload.auto", 2);    // pre
 //  1: always show fullscreen keyboard
 // -1: show fullscreen keyboard based on threshold pref
 pref("widget.ime.android.landscape_fullscreen", -1);
 pref("widget.ime.android.fullscreen_threshold", 250); // in hundreths of inches
 
 // optimize images memory usage
 pref("image.mem.decodeondraw", true);
 pref("content.image.allow_locking", false);
-pref("image.mem.min_discard_timeout_ms", 20000);
+pref("image.mem.min_discard_timeout_ms", 10000);
 
 // enable touch events interfaces
 pref("dom.w3c_touch_events.enabled", true);
 pref("dom.w3c_touch_events.safetyX", 0); // escape borders in units of 1/240"
 pref("dom.w3c_touch_events.safetyY", 120); // escape borders in units of 1/240"
 
 #ifdef MOZ_SAFE_BROWSING
 // Safe browsing does nothing unless this pref is set
--- a/mobile/chrome/content/bindings/browser.js
+++ b/mobile/chrome/content/bindings/browser.js
@@ -1,11 +1,14 @@
 // -*- Mode: js2; tab-width: 2; indent-tabs-mode: nil; js2-basic-offset: 2; js2-skip-preprocessor-directives: t; -*-
 let Cc = Components.classes;
 let Ci = Components.interfaces;
+let Cu = Components.utils;
+
+Cu.import("resource://gre/modules/Services.jsm");
 
 dump("!! remote browser loaded\n");
 
 let WebProgressListener = {
   init: function() {
     let flags = Ci.nsIWebProgress.NOTIFY_LOCATION |
                 Ci.nsIWebProgress.NOTIFY_SECURITY |
                 Ci.nsIWebProgress.NOTIFY_STATE_NETWORK | Ci.nsIWebProgress.NOTIFY_STATE_DOCUMENT;
@@ -52,16 +55,102 @@ let WebProgressListener = {
 
     // When a new page is loaded fire a message for the first paint
     addEventListener("MozAfterPaint", function(aEvent) {
       removeEventListener("MozAfterPaint", arguments.callee, true);
 
       let scrollOffset = ContentScroll.getScrollOffset(content);
       sendAsyncMessage("Browser:FirstPaint", scrollOffset);
     }, true);
+
+    // We need to package up the session history and send it to the sessionstore
+    let entries = [];
+    let history = docShell.QueryInterface(Ci.nsIWebNavigation).sessionHistory;
+    for (let i = 0; i < history.count; i++) {
+      let entry = this._serializeHistoryEntry(history.getEntryAtIndex(i, false));
+      entries.push(entry);
+    }
+    let index = history.index + 1;
+    sendAsyncMessage("Content:SessionHistory", { entries: entries, index: index });
+  },
+
+  _serializeHistoryEntry: function _serializeHistoryEntry(aEntry) {
+    let entry = { url: aEntry.URI.spec };
+
+    if (aEntry.title && aEntry.title != entry.url)
+      entry.title = aEntry.title;
+
+    if (!(aEntry instanceof Ci.nsISHEntry))
+      return entry;
+
+    let cacheKey = aEntry.cacheKey;
+    if (cacheKey && cacheKey instanceof Ci.nsISupportsPRUint32 && cacheKey.data != 0)
+      entry.cacheKey = cacheKey.data;
+
+    entry.ID = aEntry.ID;
+    entry.docshellID = aEntry.docshellID;
+
+    if (aEntry.referrerURI)
+      entry.referrer = aEntry.referrerURI.spec;
+
+    if (aEntry.contentType)
+      entry.contentType = aEntry.contentType;
+
+    let x = {}, y = {};
+    aEntry.getScrollPosition(x, y);
+    if (x.value != 0 || y.value != 0)
+      entry.scroll = x.value + "," + y.value;
+
+    if (aEntry.owner) {
+      try {
+        let binaryStream = Cc["@mozilla.org/binaryoutputstream;1"].createInstance(Ci.nsIObjectOutputStream);
+        let pipe = Cc["@mozilla.org/pipe;1"].createInstance(Ci.nsIPipe);
+        pipe.init(false, false, 0, 0xffffffff, null);
+        binaryStream.setOutputStream(pipe.outputStream);
+        binaryStream.writeCompoundObject(aEntry.owner, Ci.nsISupports, true);
+        binaryStream.close();
+
+        // Now we want to read the data from the pipe's input end and encode it.
+        let scriptableStream = Cc["@mozilla.org/binaryinputstream;1"].createInstance(Ci.nsIBinaryInputStream);
+        scriptableStream.setInputStream(pipe.inputStream);
+        let ownerBytes = scriptableStream.readByteArray(scriptableStream.available());
+        // We can stop doing base64 encoding once our serialization into JSON
+        // is guaranteed to handle all chars in strings, including embedded
+        // nulls.
+        entry.owner_b64 = btoa(String.fromCharCode.apply(null, ownerBytes));
+      } catch (e) { dump(e); }
+    }
+
+    if (aEntry.docIdentifier)
+      entry.docIdentifier = aEntry.docIdentifier;
+
+    if (aEntry.stateData)
+      entry.stateData = aEntry.stateData;
+
+    if (!(aEntry instanceof Ci.nsISHContainer))
+      return entry;
+
+    if (aEntry.childCount > 0) {
+      entry.children = [];
+      for (let i = 0; i < aEntry.childCount; i++) {
+        let child = aEntry.GetChildAt(i);
+        if (child)
+          entry.children.push(this._serializeHistoryEntry(child));
+        else // to maintain the correct frame order, insert a dummy entry 
+          entry.children.push({ url: "about:blank" });
+
+        // don't try to restore framesets containing wyciwyg URLs (cf. bug 424689 and bug 450595)
+        if (/^wyciwyg:\/\//.test(entry.children[i].url)) {
+          delete entry.children;
+          break;
+        }
+      }
+    }
+
+    return entry;
   },
 
   onStatusChange: function onStatusChange(aWebProgress, aRequest, aStatus, aMessage) {
   },
 
   onSecurityChange: function onSecurityChange(aWebProgress, aRequest, aState) {
     if (content != aWebProgress.DOMWindow)
       return;
@@ -104,16 +193,17 @@ let SecurityUI = {
     }
 
     return null;
   }
 };
 
 let WebNavigation =  {
   _webNavigation: docShell.QueryInterface(Ci.nsIWebNavigation),
+  _timer: null,
 
   init: function() {
     addMessageListener("WebNavigation:GoBack", this);
     addMessageListener("WebNavigation:GoForward", this);
     addMessageListener("WebNavigation:GotoIndex", this);
     addMessageListener("WebNavigation:LoadURI", this);
     addMessageListener("WebNavigation:Reload", this);
     addMessageListener("WebNavigation:Stop", this);
@@ -152,16 +242,151 @@ let WebNavigation =  {
 
   gotoIndex: function(message) {
     this._webNavigation.gotoIndex(message.index);
   },
 
   loadURI: function(message) {
     let flags = message.json.flags || this._webNavigation.LOAD_FLAGS_NONE;
     this._webNavigation.loadURI(message.json.uri, flags, null, null, null);
+
+    let tabData = message.json;
+    if (tabData.entries) {
+      // We are going to load from history so kill the current load. We do not
+      // want the load added to the history anyway. We reload after resetting history
+      this._webNavigation.stop(this._webNavigation.STOP_ALL);
+      this._restoreHistory(tabData, 0);
+    }
+  },
+
+  _restoreHistory: function _restoreHistory(aTabData, aCount) {
+    // We need to wait for the sessionHistory to be initialized and there
+    // is no good way to do this. We'll try a wait loop like desktop
+    try {
+      if (!this._webNavigation.sessionHistory)
+        throw new Error();
+    } catch (ex) {
+      if (aCount < 10) {
+        let self = this;
+        this._timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
+        this._timer.initWithCallback(function(aTimer) {
+          self._timer = null;
+          self._restoreHistory(aTabData, aCount + 1);
+        }, 100, Ci.nsITimer.TYPE_ONE_SHOT);
+        return;
+      }
+    }
+
+    let history = this._webNavigation.sessionHistory;
+    if (history.count > 0)
+      history.PurgeHistory(history.count);
+    history.QueryInterface(Ci.nsISHistoryInternal);
+
+    // helper hashes for ensuring unique frame IDs and unique document
+    // identifiers.
+    let idMap = { used: {} };
+    let docIdentMap = {};
+
+    for (let i = 0; i < aTabData.entries.length; i++) {
+      if (!aTabData.entries[i].url)
+        continue;
+      history.addEntry(this._deserializeHistoryEntry(aTabData.entries[i], idMap, docIdentMap), true);
+    }
+
+    // We need to force set the active history item and cause it to reload since
+    // we stop the load above
+    let activeIndex = (aTabData.index || aTabData.entries.length) - 1;
+    history.getEntryAtIndex(activeIndex, true);
+    history.QueryInterface(Ci.nsISHistory).reloadCurrentEntry();
+  },
+
+  _deserializeHistoryEntry: function _deserializeHistoryEntry(aEntry, aIdMap, aDocIdentMap) {
+    let shEntry = Cc["@mozilla.org/browser/session-history-entry;1"].createInstance(Ci.nsISHEntry);
+
+    shEntry.setURI(Services.io.newURI(aEntry.url, null, null));
+    shEntry.setTitle(aEntry.title || aEntry.url);
+    if (aEntry.subframe)
+      shEntry.setIsSubFrame(aEntry.subframe || false);
+    shEntry.loadType = Ci.nsIDocShellLoadInfo.loadHistory;
+    if (aEntry.contentType)
+      shEntry.contentType = aEntry.contentType;
+    if (aEntry.referrer)
+      shEntry.referrerURI = Services.io.newURI(aEntry.referrer, null, null);
+
+    if (aEntry.cacheKey) {
+      let cacheKey = Cc["@mozilla.org/supports-PRUint32;1"].createInstance(Ci.nsISupportsPRUint32);
+      cacheKey.data = aEntry.cacheKey;
+      shEntry.cacheKey = cacheKey;
+    }
+
+    if (aEntry.ID) {
+      // get a new unique ID for this frame (since the one from the last
+      // start might already be in use)
+      let id = aIdMap[aEntry.ID] || 0;
+      if (!id) {
+        for (id = Date.now(); id in aIdMap.used; id++);
+        aIdMap[aEntry.ID] = id;
+        aIdMap.used[id] = true;
+      }
+      shEntry.ID = id;
+    }
+
+    if (aEntry.docshellID)
+      shEntry.docshellID = aEntry.docshellID;
+
+    if (aEntry.stateData)
+      shEntry.stateData = aEntry.stateData;
+
+    if (aEntry.scroll) {
+      let scrollPos = aEntry.scroll.split(",");
+      scrollPos = [parseInt(scrollPos[0]) || 0, parseInt(scrollPos[1]) || 0];
+      shEntry.setScrollPosition(scrollPos[0], scrollPos[1]);
+    }
+
+    if (aEntry.docIdentifier) {
+      // Get a new document identifier for this entry to ensure that history
+      // entries after a session restore are considered to have different
+      // documents from the history entries before the session restore.
+      // Document identifiers are 64-bit ints, so JS will loose precision and
+      // start assigning all entries the same doc identifier if these ever get
+      // large enough.
+      //
+      // It's a potential security issue if document identifiers aren't
+      // globally unique, but shEntry.setUniqueDocIdentifier() below guarantees
+      // that we won't re-use a doc identifier within a given instance of the
+      // application.
+      let ident = aDocIdentMap[aEntry.docIdentifier];
+      if (!ident) {
+        shEntry.setUniqueDocIdentifier();
+        aDocIdentMap[aEntry.docIdentifier] = shEntry.docIdentifier;
+      } else {
+        shEntry.docIdentifier = ident;
+      }
+    }
+
+    if (aEntry.owner_b64) {
+      let ownerInput = Cc["@mozilla.org/io/string-input-stream;1"].createInstance(Ci.nsIStringInputStream);
+      let binaryData = atob(aEntry.owner_b64);
+      ownerInput.setData(binaryData, binaryData.length);
+      let binaryStream = Cc["@mozilla.org/binaryinputstream;1"].createInstance(Ci.nsIObjectInputStream);
+      binaryStream.setInputStream(ownerInput);
+      try { // Catch possible deserialization exceptions
+        shEntry.owner = binaryStream.readObject(true);
+      } catch (ex) { dump(ex); }
+    }
+
+    if (aEntry.children && shEntry instanceof Ci.nsISHContainer) {
+      for (let i = 0; i < aEntry.children.length; i++) {
+        if (!aEntry.children[i].url)
+          continue;
+        shEntry.AddChild(this._deserializeHistoryEntry(aEntry.children[i], aIdMap, aDocIdentMap), i);
+      }
+    }
+    
+    return shEntry;
   },
 
   reload: function(message) {
     let flags = message.json.flags || this._webNavigation.LOAD_FLAGS_NONE;
     this._webNavigation.reload(flags);
   },
 
   stop: function(message) {
@@ -483,17 +708,17 @@ let IndexedDB = {
     }
 
     // Remote to parent
     sendAsyncMessage("IndexedDB:Prompt", {
       topic: aTopic,
       host: contentDocument.documentURIObject.asciiHost,
       location: contentDocument.location.toString(),
       data: aData,
-      observerId: this.addWaitingObserver(observer),
+      observerId: this.addWaitingObserver(observer)
     });
   },
 
   receiveMessage: function(aMessage) {
     let payload = aMessage.json;
     switch (aMessage.name) {
       case "IndexedDB:Response":
         let observer = this.getAndRemoveWaitingObserver(payload.observerId);
@@ -508,13 +733,13 @@ let IndexedDB = {
     this.waitingObservers[observerId] = aObserver;
     return observerId;
   },
 
   getAndRemoveWaitingObserver: function(aObserverId) {
     let observer = this.waitingObservers[aObserverId];
     delete this.waitingObservers[aObserverId];
     return observer;
-  },
+  }
 };
 
 IndexedDB.init();
 
--- a/mobile/components/SessionStore.js
+++ b/mobile/components/SessionStore.js
@@ -368,27 +368,27 @@ SessionStore.prototype = {
     let tabs = aWindow.Browser.tabs;
     for (let i = 0; i < tabs.length; i++)
       this.onTabRemove(aWindow, tabs[i].browser, true);
 
     delete aWindow.__SSID;
   },
 
   onTabAdd: function ss_onTabAdd(aWindow, aBrowser, aNoNotification) {
-    aBrowser.messageManager.addMessageListener("DOMContentLoaded", this);
     aBrowser.messageManager.addMessageListener("pageshow", this);
+    aBrowser.messageManager.addMessageListener("Content:SessionHistory", this);
 
     if (!aNoNotification)
       this.saveStateDelayed();
     this._updateCrashReportURL(aWindow);
   },
 
   onTabRemove: function ss_onTabRemove(aWindow, aBrowser, aNoNotification) {
-    aBrowser.messageManager.removeMessageListener("DOMContentLoaded", this);
     aBrowser.messageManager.removeMessageListener("pageshow", this);
+    aBrowser.messageManager.removeMessageListener("Content:SessionHistory", this);
 
     // If this browser is being restored, skip any session save activity
     if (aBrowser.__SS_restore)
       return;
 
     delete aBrowser.__SS_data;
 
     if (!aNoNotification)
@@ -416,38 +416,48 @@ SessionStore.prototype = {
     // If this browser is being restored, skip any session save activity
     if (aBrowser.__SS_restore)
       return;
 
     // Ignore a transient "about:blank"
     if (!aBrowser.canGoBack && aBrowser.currentURI.spec == "about:blank")
       return;
 
-    delete aBrowser.__SS_data;
-    this._collectTabData(aBrowser);
+    if (aMessage.name == "Content:SessionHistory") {
+      delete aBrowser.__SS_data;
+      this._collectTabData(aBrowser, aMessage.json);
+    }
 
     // Save out the state as quickly as possible
     if (aMessage.name == "pageshow")
       this.saveStateNow();
+
     this._updateCrashReportURL(aWindow);
   },
 
   onTabSelect: function ss_onTabSelect(aWindow, aBrowser) {
     if (this._loadState != STATE_RUNNING)
       return;
 
     let index = aWindow.Elements.browsers.selectedIndex;
     this._windows[aWindow.__SSID].selected = parseInt(index) + 1; // 1-based
 
     // Restore the resurrected browser
     // * currently we only load the last URL into the browser
     if (aBrowser.__SS_restore) {
       let data = aBrowser.__SS_data;
-      if (data.entries.length > 0)
-        aBrowser.loadURI(data.entries[0].url, null, null);
+      if (data.entries.length > 0) {
+        let json = {
+          uri: data.entries[data.index - 1].url,
+          flags: null,
+          entries: data.entries,
+          index: data.index
+        };
+        aBrowser.messageManager.sendAsyncMessage("WebNavigation:LoadURI", json);
+      }
 
       delete aBrowser.__SS_restore;
     }
 
     this._updateCrashReportURL(aWindow);
   },
 
   saveStateDelayed: function ss_saveStateDelayed() {
@@ -490,24 +500,26 @@ SessionStore.prototype = {
 
     let data = { windows: [] };
     let index;
     for (index in this._windows)
       data.windows.push(this._windows[index]);
     return data;
   },
 
-  _collectTabData: function ss__collectTabData(aBrowser) {
+  _collectTabData: function ss__collectTabData(aBrowser, aHistory) {
     // If this browser is being restored, skip any session save activity
     if (aBrowser.__SS_restore)
       return;
 
-    let tabData = { entries: [{}] };
-    tabData.entries[0] = { url: aBrowser.currentURI.spec, title: aBrowser.contentTitle };
-    tabData.index = 1;
+    let aHistory = aHistory || { entries: [{ url: aBrowser.currentURI.spec, title: aBrowser.contentTitle }], index: 1 };
+
+    let tabData = {};
+    tabData.entries = aHistory.entries;
+    tabData.index = aHistory.index;
     tabData.attributes = { image: aBrowser.mIconURL };
 
     aBrowser.__SS_data = tabData;
   },
 
   _collectWindowData: function ss__collectWindowData(aWindow) {
     // Ignore windows not tracked by SessionStore
     if (!aWindow.__SSID || !this._windows[aWindow.__SSID])
@@ -726,49 +738,58 @@ SessionStore.prototype = {
         }
 
         if (!data || data.windows.length == 0) {
           notifyObservers();
           return;
         }
 
         let window = Services.wm.getMostRecentWindow("navigator:browser");
-    
+
         let selected = data.windows[0].selected;
         let tabs = data.windows[0].tabs;
         for (let i=0; i<tabs.length; i++) {
           let tabData = tabs[i];
-    
+
           // Add a tab, but don't load the URL until we need to
           let params = { getAttention: false, delayLoad: true };
-          if (i + 1 == selected)
-            params.delayLoad = false;
-    
+
           // We must have selected tabs as soon as possible, so we let all tabs be selected
           // until we get the real selected tab. Then we stop selecting tabs. The end result
           // is that the right tab is selected, but we also don't get a bunch of errors
           let bringToFront = (i + 1 <= selected) && aBringToFront;
-          let tab = window.Browser.addTab(tabData.entries[0].url, bringToFront, null, params);
-    
-          // Recreate the thumbnail if we are delay loading the tab
-          if (tabData.extData && params.delayLoad) {
-              let canvas = tab.chromeTab.thumbnail;
-              canvas.setAttribute("restored", "true");
-    
-              let image = new window.Image();
-              image.onload = function() {
-                if (canvas)
-                  canvas.getContext("2d").drawImage(image, 0, 0);
-              };
-              image.src = tabData.extData.thumbnail;
+          let tab = window.Browser.addTab(tabData.entries[tabData.index - 1].url, bringToFront, null, params);
+
+          // Start a real load for the selected tab
+          if (i + 1 == selected) {
+            let json = {
+              uri: tabData.entries[tabData.index - 1].url,
+              flags: null,
+              entries: tabData.entries,
+              index: tabData.index
+            };
+            tab.browser.messageManager.sendAsyncMessage("WebNavigation:LoadURI", json);
+          } else {
+            // Make sure the browser has its session data for the delay reload
+            tab.browser.__SS_data = tabData;
+            tab.browser.__SS_restore = true;
+
+            // Recreate the thumbnail if we are delay loading the tab
+            let canvas = tab.chromeTab.thumbnail;
+            canvas.setAttribute("restored", "true");
+  
+            let image = new window.Image();
+            image.onload = function() {
+              if (canvas)
+                canvas.getContext("2d").drawImage(image, 0, 0);
+            };
+            image.src = tabData.extData.thumbnail;
           }
-    
-          tab.browser.__SS_data = tabData;
+
           tab.browser.__SS_extdata = tabData.extData;
-          tab.browser.__SS_restore = params.delayLoad;
         }
     
         notifyObservers();
       });
     } catch (ex) {
       Cu.reportError("SessionStore: Could not read from sessionstore.bak file: " + ex);
       notifyObservers();
     }
--- a/modules/libpref/src/init/all.js
+++ b/modules/libpref/src/init/all.js
@@ -1083,17 +1083,17 @@ pref("intl.uidirection.ar", "rtl");
 pref("intl.uidirection.he", "rtl");
 pref("intl.uidirection.fa", "rtl");
 
 // use en-US hyphenation by default for content tagged with plain lang="en"
 pref("intl.hyphenation-alias.en", "en-us");
 // and for other subtags of en-*, if no specific patterns are available
 pref("intl.hyphenation-alias.en-*", "en-us");
 
-pref("font.mathfont-family", "STIXNonUnicode, STIXSizeOneSym, STIXSize1, STIXGeneral, Standard Symbols L, DejaVu Sans, Cambria Math");
+pref("font.mathfont-family", "STIXNonUnicode, STIXSizeOneSym, STIXSize1, STIXGeneral, Asana Math, Standard Symbols L, DejaVu Sans, Cambria Math");
 
 // Some CJK fonts have bad underline offset, their CJK character glyphs are overlapped (or adjoined)  to its underline.
 // These fonts are ignored the underline offset, instead of it, the underline is lowered to bottom of its em descent.
 pref("font.blacklist.underline_offset", "FangSong,Gulim,GulimChe,MingLiU,MingLiU-ExtB,MingLiU_HKSCS,MingLiU-HKSCS-ExtB,MS Gothic,MS Mincho,MS PGothic,MS PMincho,MS UI Gothic,PMingLiU,PMingLiU-ExtB,SimHei,SimSun,SimSun-ExtB,Hei,Kai,Apple LiGothic,Apple LiSung,Osaka");
 
 pref("images.dither", "auto");
 pref("security.directory",              "");
 
@@ -1764,17 +1764,17 @@ pref("font.default.zh-TW", "sans-serif")
 pref("font.size.variable.zh-TW", 16);
 pref("font.size.fixed.zh-TW", 16);
 
 pref("font.default.zh-HK", "sans-serif");
 pref("font.size.variable.zh-HK", 16);
 pref("font.size.fixed.zh-HK", 16);
 
 // We have special support for Monotype Symbol on Windows.
-pref("font.mathfont-family", "STIXNonUnicode, STIXSizeOneSym, STIXSize1, STIXGeneral, Symbol, DejaVu Sans, Cambria Math");
+pref("font.mathfont-family", "STIXNonUnicode, STIXSizeOneSym, STIXSize1, STIXGeneral, Asana Math, Symbol, DejaVu Sans, Cambria Math");
 
 // cleartype settings - false implies default system settings 
 
 // use cleartype rendering for downloadable fonts (win xp only)
 pref("gfx.font_rendering.cleartype.use_for_downloadable_fonts", true);
 
 // use cleartype rendering for all fonts always (win xp only)
 pref("gfx.font_rendering.cleartype.always_use_for_content", false);
@@ -2292,17 +2292,17 @@ pref("font.default.zh-TW", "sans-serif")
 pref("font.size.variable.zh-TW", 15);
 pref("font.size.fixed.zh-TW", 16);
 
 pref("font.default.zh-HK", "sans-serif");
 pref("font.size.variable.zh-HK", 15);
 pref("font.size.fixed.zh-HK", 16);
 
 // Apple's Symbol is Unicode so use it
-pref("font.mathfont-family", "STIXNonUnicode, STIXSizeOneSym, STIXSize1, STIXGeneral, Symbol, DejaVu Sans, Cambria Math");
+pref("font.mathfont-family", "STIXNonUnicode, STIXSizeOneSym, STIXSize1, STIXGeneral, Asana Math, Symbol, DejaVu Sans, Cambria Math");
 
 // individual font faces to be treated as independent families
 // names are Postscript names of each face
 pref("font.single-face-list", "Osaka-Mono");
 
 // optimization hint for fonts with localized names to be read in at startup, otherwise read in at lookup miss
 // names are canonical family names (typically English names)
 pref("font.preload-names-list", "Hiragino Kaku Gothic Pro,Hiragino Mincho Pro,STSong");
@@ -2341,17 +2341,17 @@ pref("mousewheel.enable_pixel_scrolling"
 #endif
 
 #ifdef XP_OS2
 
 pref("ui.key.menuAccessKeyFocuses", true);
 
 pref("font.alias-list", "sans,sans-serif,serif,monospace,Tms Rmn,Helv,Courier,Times New Roman");
 
-pref("font.mathfont-family", "STIXNonUnicode, STIXSizeOneSym, STIXSize1, STIXGeneral, DejaVu Sans");
+pref("font.mathfont-family", "STIXNonUnicode, STIXSizeOneSym, STIXSize1, STIXGeneral, Asana Math, DejaVu Sans");
 
 // Languages only need lists if we have a default that might not be available.
 // Tms Rmn and Helv cannot be used by Thebes but the OS/2 version of FontConfig
 // maps them to Times New Roman and Helvetica, respectively. Those fonts and
 // Courier are available on OS/2 by default.
 
 pref("font.name.serif.ar", "Tms Rmn");
 pref("font.name.sans-serif.ar", "Helv");