Merge
authorMarco Zehe <marco.zehe@googlemail.com>
Thu, 12 Feb 2009 15:37:03 +0100
changeset 24964 0e17dea79681363686f32cabf9a546c6969270e7
parent 24962 e94509d21882f52c2d26cea0607e48d4a2248766 (current diff)
parent 24963 4bb932755d5c4d2a79ce867b256e95cbb3118fcd (diff)
child 24965 222841605203ef3e999a83ef60d772d46b19c0d7
push idunknown
push userunknown
push dateunknown
milestone1.9.2a1pre
Merge
accessible/src/base/nsTextAttrs.cpp
accessible/src/base/nsTextAttrs.h
--- a/accessible/src/base/Makefile.in
+++ b/accessible/src/base/Makefile.in
@@ -88,17 +88,17 @@ CPPSRCS = \
   nsAccessibleRelation.cpp \
   nsAccessibleTreeWalker.cpp \
   nsBaseWidgetAccessible.cpp \
   nsFormControlAccessible.cpp \
   nsRootAccessible.cpp \
   nsApplicationAccessible.cpp \
   nsCaretAccessible.cpp \
   nsTextAccessible.cpp \
-  nsTextAttrs.cpp \
+  nsTextUtils.cpp \
   $(NULL)
 
 EXPORTS = \
   nsRootAccessible.h \
   nsAccessibleEventData.h \
   nsAccessNode.h \
   $(NULL)
 
--- a/accessible/src/base/nsAccessibilityAtomList.h
+++ b/accessible/src/base/nsAccessibilityAtomList.h
@@ -188,27 +188,20 @@ ACCESSIBILITY_ATOM(type, "type")
 ACCESSIBILITY_ATOM(value, "value")
 
   // Alphabetical list of object attributes
 ACCESSIBILITY_ATOM(display, "display")
 ACCESSIBILITY_ATOM(textAlign, "text-align")
 ACCESSIBILITY_ATOM(textIndent, "text-indent")
 
   // Alphabetical list of text attributes (AT API)
-ACCESSIBILITY_ATOM(color, "color")
 ACCESSIBILITY_ATOM(backgroundColor, "background-color")
-ACCESSIBILITY_ATOM(fontFamily, "font-family")
-ACCESSIBILITY_ATOM(fontStyle, "font-style")
-ACCESSIBILITY_ATOM(fontWeight, "font-weight")
 ACCESSIBILITY_ATOM(fontSize, "font-size")
 ACCESSIBILITY_ATOM(invalid, "invalid")
 ACCESSIBILITY_ATOM(language, "language")
-ACCESSIBILITY_ATOM(textLineThroughStyle, "text-line-through-style")
-ACCESSIBILITY_ATOM(textUnderlineStyle, "text-underline-style")
-ACCESSIBILITY_ATOM(textPosition, "text-position")
 
   // ARIA (DHTML accessibility) attributes
   // Also add to nsARIAMap.cpp and nsARIAMap.h
   // ARIA role attribute
 ACCESSIBILITY_ATOM(role, "role")
 ACCESSIBILITY_ATOM(aria_activedescendant, "aria-activedescendant")
 ACCESSIBILITY_ATOM(aria_atomic, "aria-atomic")
 ACCESSIBILITY_ATOM(aria_autocomplete, "aria-autocomplete")
deleted file mode 100644
--- a/accessible/src/base/nsTextAttrs.cpp
+++ /dev/null
@@ -1,605 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** 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.org code.
- *
- * The Initial Developer of the Original Code is
- * Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2007
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Alexander Surkov <surkov.alexander@gmail.com> (original author)
- *
- * 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
- * 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 "nsTextAttrs.h"
-
-#include "nsAccessNode.h"
-#include "nsHyperTextAccessibleWrap.h"
-
-////////////////////////////////////////////////////////////////////////////////
-// Constants and structures
-
-/**
- * Item of the gCSSTextAttrsMap map.
- */
-struct nsCSSTextAttrMapItem
-{
-  const char* mCSSName;
-  const char* mCSSValue;
-  nsIAtom** mAttrName;
-  const char* mAttrValue;
-};
-
-/**
- * The map of CSS properties to text attributes.
- */
-const char* const kAnyValue = nsnull;
-const char* const kCopyValue = nsnull;
-
-static nsCSSTextAttrMapItem gCSSTextAttrsMap[] =
-{
-  // CSS name            CSS value        Attribute name                                Attribute value
-  { "color",             kAnyValue,       &nsAccessibilityAtoms::color,                 kCopyValue },
-  { "font-family",       kAnyValue,       &nsAccessibilityAtoms::fontFamily,            kCopyValue },
-  { "font-style",        kAnyValue,       &nsAccessibilityAtoms::fontStyle,             kCopyValue },
-  { "font-weight",       kAnyValue,       &nsAccessibilityAtoms::fontWeight,            kCopyValue },
-  { "text-decoration",   "line-through",  &nsAccessibilityAtoms::textLineThroughStyle,  "solid" },
-  { "text-decoration",   "underline",     &nsAccessibilityAtoms::textUnderlineStyle,    "solid" },
-  { "vertical-align",    kAnyValue,       &nsAccessibilityAtoms::textPosition,          kCopyValue }
-};
-
-////////////////////////////////////////////////////////////////////////////////
-// nsTextAttrs
-
-nsTextAttrsMgr::nsTextAttrsMgr(nsHyperTextAccessible *aHyperTextAcc,
-                               nsIDOMNode *aHyperTextNode,
-                               PRBool aIncludeDefAttrs,
-                               nsIDOMNode *aOffsetNode) :
-  mHyperTextAcc(aHyperTextAcc), mHyperTextNode(aHyperTextNode),
-  mIncludeDefAttrs(aIncludeDefAttrs), mOffsetNode(aOffsetNode)
-{
-}
-
-nsresult
-nsTextAttrsMgr::GetAttributes(nsIPersistentProperties *aAttributes,
-                              PRInt32 *aStartHTOffset,
-                              PRInt32 *aEndHTOffset)
-{
-  // 1. Hyper text accessible and its DOM node must be specified always.
-  // 2. Offset DOM node and result hyper text offsets must be specifed in
-  // the case of text attributes.
-  // 3. Offset DOM node and result hyper text offsets must not be specifed but
-  // include default text attributes flag and attributes list must be specified
-  // in the case of default text attributes.
-  NS_PRECONDITION(mHyperTextAcc && mHyperTextNode &&
-                  ((mOffsetNode && aStartHTOffset && aEndHTOffset) ||
-                  (!mOffsetNode && !aStartHTOffset && !aEndHTOffset &&
-                   mIncludeDefAttrs && aAttributes)),
-                  "Wrong usage of nsTextAttrsMgr!");
-
-  nsCOMPtr<nsIDOMElement> hyperTextElm =
-    nsCoreUtils::GetDOMElementFor(mHyperTextNode);
-  nsCOMPtr<nsIDOMElement> offsetElm;
-  if (mOffsetNode)
-    offsetElm = nsCoreUtils::GetDOMElementFor(mOffsetNode);
-
-  nsIFrame *rootFrame = nsCoreUtils::GetFrameFor(hyperTextElm);
-  nsIFrame *frame = nsnull;
-  if (offsetElm)
-    frame = nsCoreUtils::GetFrameFor(offsetElm);
-
-  nsTPtrArray<nsITextAttr> textAttrArray(10);
-
-  // "language" text attribute
-  nsLangTextAttr langTextAttr(mHyperTextAcc, mHyperTextNode, mOffsetNode);
-  textAttrArray.AppendElement(&langTextAttr);
-
-  // "color" text attribute
-  nsCSSTextAttr colorTextAttr(0, hyperTextElm, offsetElm);
-  textAttrArray.AppendElement(&colorTextAttr);
-
-  // "font-family" text attribute
-  nsCSSTextAttr fontFamilyTextAttr(1, hyperTextElm, offsetElm);
-  textAttrArray.AppendElement(&fontFamilyTextAttr);
-
-  // "font-style" text attribute
-  nsCSSTextAttr fontStyleTextAttr(2, hyperTextElm, offsetElm);
-  textAttrArray.AppendElement(&fontStyleTextAttr);
-
-  // "font-weight" text attribute
-  nsCSSTextAttr fontWeightTextAttr(3, hyperTextElm, offsetElm);
-  textAttrArray.AppendElement(&fontWeightTextAttr);
-
-  // "text-line-through-style" text attribute
-  nsCSSTextAttr lineThroughTextAttr(4, hyperTextElm, offsetElm);
-  textAttrArray.AppendElement(&lineThroughTextAttr);
-
-  // "text-underline-style" text attribute
-  nsCSSTextAttr underlineTextAttr(5, hyperTextElm, offsetElm);
-  textAttrArray.AppendElement(&underlineTextAttr);
-
-  // "text-position" text attribute
-  nsCSSTextAttr posTextAttr(6, hyperTextElm, offsetElm);
-  textAttrArray.AppendElement(&posTextAttr);
-
-  // "background-color" text attribute
-  nsBGColorTextAttr bgColorTextAttr(rootFrame, frame);
-  textAttrArray.AppendElement(&bgColorTextAttr);
-
-  // "font-size" text attribute
-  nsFontSizeTextAttr fontSizeTextAttr(rootFrame, frame);
-  textAttrArray.AppendElement(&fontSizeTextAttr);
-
-  // Expose text attributes if applicable.
-  if (aAttributes) {
-    PRUint32 len = textAttrArray.Length();
-    for (PRUint32 idx = 0; idx < len; idx++) {
-      nsITextAttr *textAttr = textAttrArray[idx];
-
-      nsAutoString value;
-      if (textAttr->GetValue(value, mIncludeDefAttrs))
-        nsAccUtils::SetAccAttr(aAttributes, textAttr->GetName(), value);
-    }
-  }
-
-  nsresult rv = NS_OK;
-
-  // Expose text attributes range where they are applied if applicable.
-  if (mOffsetNode)
-    rv = GetRange(textAttrArray, aStartHTOffset, aEndHTOffset);
-
-  textAttrArray.Clear();
-  return rv;
-}
-
-nsresult
-nsTextAttrsMgr::GetRange(const nsTPtrArray<nsITextAttr>& aTextAttrArray,
-                         PRInt32 *aStartHTOffset, PRInt32 *aEndHTOffset)
-{
-  nsCOMPtr<nsIDOMElement> rootElm =
-    nsCoreUtils::GetDOMElementFor(mHyperTextNode);
-  NS_ENSURE_STATE(rootElm);
-
-  nsCOMPtr<nsIDOMNode> tmpNode(mOffsetNode);
-  nsCOMPtr<nsIDOMNode> currNode(mOffsetNode);
-
-  PRUint32 len = aTextAttrArray.Length();
-
-  // Navigate backwards and forwards from current node to the root node to
-  // calculate range bounds for the text attribute. Navigation sequence is the
-  // following:
-  // 1. Navigate through the siblings.
-  // 2. If the traversed sibling has children then navigate from its leaf child
-  //    to it through whole tree of the traversed sibling.
-  // 3. Get the parent and cycle algorithm until the root node.
-
-  // Navigate backwards (find the start offset).
-  while (currNode && currNode != rootElm) {
-    nsCOMPtr<nsIDOMElement> currElm(nsCoreUtils::GetDOMElementFor(currNode));
-    NS_ENSURE_STATE(currElm);
-
-    if (currNode != mOffsetNode) {
-      PRBool stop = PR_FALSE;
-      for (PRUint32 idx = 0; idx < len; idx++) {
-        nsITextAttr *textAttr = aTextAttrArray[idx];
-        if (!textAttr->Equal(currElm)) {
-
-          PRInt32 startHTOffset = 0;
-          nsCOMPtr<nsIAccessible> startAcc;
-          nsresult rv = mHyperTextAcc->
-            DOMPointToHypertextOffset(tmpNode, -1, &startHTOffset,
-                                      getter_AddRefs(startAcc));
-          NS_ENSURE_SUCCESS(rv, rv);
-
-          if (!startAcc)
-            startHTOffset = 0;
-
-          if (startHTOffset > *aStartHTOffset)
-            *aStartHTOffset = startHTOffset;
-
-          stop = PR_TRUE;
-          break;
-        }
-      }
-      if (stop)
-        break;
-    }
-
-    currNode->GetPreviousSibling(getter_AddRefs(tmpNode));
-    if (tmpNode) {
-      // Navigate through the subtree of traversed children to calculate
-      // left bound of the range.
-      FindStartOffsetInSubtree(aTextAttrArray, tmpNode, currNode,
-                               aStartHTOffset);
-    }
-
-    currNode->GetParentNode(getter_AddRefs(tmpNode));
-    currNode.swap(tmpNode);
-  }
-
-  // Navigate forwards (find the end offset).
-  PRBool moveIntoSubtree = PR_TRUE;
-  currNode = mOffsetNode;
-
-  while (currNode && currNode != rootElm) {
-    nsCOMPtr<nsIDOMElement> currElm(nsCoreUtils::GetDOMElementFor(currNode));
-    NS_ENSURE_STATE(currElm);
-
-    // Stop new end offset searching if the given text attribute changes its
-    // value.
-    PRBool stop = PR_FALSE;
-    for (PRUint32 idx = 0; idx < len; idx++) {
-      nsITextAttr *textAttr = aTextAttrArray[idx];
-      if (!textAttr->Equal(currElm)) {
-
-        PRInt32 endHTOffset = 0;
-        nsresult rv = mHyperTextAcc->
-          DOMPointToHypertextOffset(currNode, -1, &endHTOffset);
-        NS_ENSURE_SUCCESS(rv, rv);
-
-        if (endHTOffset < *aEndHTOffset)
-          *aEndHTOffset = endHTOffset;
-
-        stop = PR_TRUE;
-        break;
-      }
-    }
-
-    if (stop)
-      break;
-
-    if (moveIntoSubtree) {
-      // Navigate through subtree of traversed node. We use 'moveIntoSubtree'
-      // flag to avoid traversing the same subtree twice.
-      currNode->GetFirstChild(getter_AddRefs(tmpNode));
-      if (tmpNode)
-        FindEndOffsetInSubtree(aTextAttrArray, tmpNode, aEndHTOffset);
-    }
-
-    currNode->GetNextSibling(getter_AddRefs(tmpNode));
-    moveIntoSubtree = PR_TRUE;
-    if (!tmpNode) {
-      currNode->GetParentNode(getter_AddRefs(tmpNode));
-      moveIntoSubtree = PR_FALSE;
-    }
-
-    currNode.swap(tmpNode);
-  }
-
-  return NS_OK;
-}
-
-PRBool
-nsTextAttrsMgr::FindEndOffsetInSubtree(const nsTPtrArray<nsITextAttr>& aTextAttrArray,
-                                       nsIDOMNode *aCurrNode,
-                                       PRInt32 *aHTOffset)
-{
-  if (!aCurrNode)
-    return PR_FALSE;
-
-  nsCOMPtr<nsIDOMElement> currElm(nsCoreUtils::GetDOMElementFor(aCurrNode));
-  NS_ENSURE_STATE(currElm);
-
-  // If the given text attribute (pointed by nsTextAttr object) changes its
-  // value on the traversed element then fit the end of range.
-  PRUint32 len = aTextAttrArray.Length();
-  for (PRUint32 idx = 0; idx < len; idx++) {
-    nsITextAttr *textAttr = aTextAttrArray[idx];
-    if (!textAttr->Equal(currElm)) {
-      PRInt32 endHTOffset = 0;
-      nsresult rv = mHyperTextAcc->
-        DOMPointToHypertextOffset(aCurrNode, -1, &endHTOffset);
-      NS_ENSURE_SUCCESS(rv, PR_FALSE);
-
-      if (endHTOffset < *aHTOffset)
-        *aHTOffset = endHTOffset;
-
-      return PR_TRUE;
-    }
-  }
-
-  // Deeply traverse into the tree to fit the end of range.
-  nsCOMPtr<nsIDOMNode> nextNode;
-  aCurrNode->GetFirstChild(getter_AddRefs(nextNode));
-  if (nextNode) {
-    PRBool res = FindEndOffsetInSubtree(aTextAttrArray, nextNode, aHTOffset);
-    if (res)
-      return res;
-  }
-
-  aCurrNode->GetNextSibling(getter_AddRefs(nextNode));
-  if (nextNode) {
-    if (FindEndOffsetInSubtree(aTextAttrArray, nextNode, aHTOffset))
-      return PR_TRUE;
-  }
-
-  return PR_FALSE;
-}
-
-PRBool
-nsTextAttrsMgr::FindStartOffsetInSubtree(const nsTPtrArray<nsITextAttr>& aTextAttrArray,
-                                         nsIDOMNode *aCurrNode,
-                                         nsIDOMNode *aPrevNode,
-                                         PRInt32 *aHTOffset)
-{
-  if (!aCurrNode)
-    return PR_FALSE;
-
-  // Find the closest element back to the traversed element.
-  nsCOMPtr<nsIDOMNode> nextNode;
-  aCurrNode->GetLastChild(getter_AddRefs(nextNode));
-  if (nextNode) {
-    if (FindStartOffsetInSubtree(aTextAttrArray, nextNode, aPrevNode, aHTOffset))
-      return PR_TRUE;
-  }
-
-  nsCOMPtr<nsIDOMElement> currElm(nsCoreUtils::GetDOMElementFor(aCurrNode));
-  NS_ENSURE_STATE(currElm);
-
-  // If the given text attribute (pointed by nsTextAttr object) changes its
-  // value on the traversed element then fit the start of range.
-  PRUint32 len = aTextAttrArray.Length();
-  for (PRUint32 idx = 0; idx < len; idx++) {
-    nsITextAttr *textAttr = aTextAttrArray[idx];
-    if (!textAttr->Equal(currElm)) {
-
-      PRInt32 startHTOffset = 0;
-      nsCOMPtr<nsIAccessible> startAcc;
-      nsresult rv = mHyperTextAcc->
-        DOMPointToHypertextOffset(aPrevNode, -1, &startHTOffset,
-                                  getter_AddRefs(startAcc));
-      NS_ENSURE_SUCCESS(rv, PR_FALSE);
-
-      if (!startAcc)
-        startHTOffset = 0;
-
-      if (startHTOffset > *aHTOffset)
-        *aHTOffset = startHTOffset;
-
-      return PR_TRUE;
-    }
-  }
-
-  // Moving backwards to find the start of range.
-  aCurrNode->GetPreviousSibling(getter_AddRefs(nextNode));
-  if (nextNode) {
-    if (FindStartOffsetInSubtree(aTextAttrArray, nextNode, aCurrNode, aHTOffset))
-      return PR_TRUE;
-  }
-
-  return PR_FALSE;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// nsLangTextAttr
-
-nsLangTextAttr::nsLangTextAttr(nsHyperTextAccessible *aRootAcc, 
-                               nsIDOMNode *aRootNode, nsIDOMNode *aNode) :
-  nsTextAttr(aNode == nsnull)
-{
-  mRootContent = do_QueryInterface(aRootNode);
-
-  nsresult rv = aRootAcc->GetLanguage(mRootNativeValue);
-  mIsRootDefined = NS_SUCCEEDED(rv) && !mRootNativeValue.IsEmpty();
-
-  if (aNode) {
-    nsCOMPtr<nsIContent> content(do_QueryInterface(aNode));
-    mIsDefined = GetLang(content, mNativeValue);
-  }
-}
-
-PRBool
-nsLangTextAttr::GetValueFor(nsIDOMElement *aElm, nsAutoString *aValue)
-{
-  nsCOMPtr<nsIContent> content = do_QueryInterface(aElm);
-  return GetLang(content, *aValue);
-}
-
-void
-nsLangTextAttr::Format(const nsAutoString& aValue, nsAString& aFormattedValue)
-{
-  aFormattedValue = aValue;
-}
-
-PRBool
-nsLangTextAttr::GetLang(nsIContent *aContent, nsAString& aLang)
-{
-  nsCoreUtils::GetLanguageFor(aContent, mRootContent, aLang);
-  return !aLang.IsEmpty();
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// nsCSSTextAttr
-
-nsCSSTextAttr::nsCSSTextAttr(PRUint32 aIndex, nsIDOMElement *aRootElm,
-                             nsIDOMElement *aElm) :
-  nsTextAttr(aElm == nsnull), mIndex(aIndex)
-{
-  mIsRootDefined = GetValueFor(aRootElm, &mRootNativeValue);
-
-  if (aElm)
-    mIsDefined = GetValueFor(aElm, &mNativeValue);
-}
-
-nsIAtom*
-nsCSSTextAttr::GetName()
-{
-  return *gCSSTextAttrsMap[mIndex].mAttrName;
-}
-
-PRBool
-nsCSSTextAttr::GetValueFor(nsIDOMElement *aElm, nsAutoString *aValue)
-{
-  nsCOMPtr<nsIDOMCSSStyleDeclaration> currStyleDecl;
-  nsCoreUtils::GetComputedStyleDeclaration(EmptyString(), aElm,
-                                           getter_AddRefs(currStyleDecl));
-  if (!currStyleDecl)
-    return PR_FALSE;
-
-  NS_ConvertASCIItoUTF16 cssName(gCSSTextAttrsMap[mIndex].mCSSName);
-
-  nsresult rv = currStyleDecl->GetPropertyValue(cssName, *aValue);
-  if (NS_FAILED(rv))
-    return PR_TRUE;
-
-  const char *cssValue = gCSSTextAttrsMap[mIndex].mCSSValue;
-  if (cssValue != kAnyValue && !aValue->EqualsASCII(cssValue))
-    return PR_FALSE;
-
-  return PR_TRUE;
-}
-
-void
-nsCSSTextAttr::Format(const nsAutoString& aValue, nsAString& aFormattedValue)
-{
-  const char *attrValue = gCSSTextAttrsMap[mIndex].mAttrValue;
-  if (attrValue != kCopyValue)
-    AppendASCIItoUTF16(attrValue, aFormattedValue);
-  else
-    aFormattedValue = aValue;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// nsBackgroundTextAttr
-
-nsBGColorTextAttr::nsBGColorTextAttr(nsIFrame *aRootFrame, nsIFrame *aFrame) :
-  nsTextAttr(aFrame == nsnull), mRootFrame(aRootFrame)
-{
-  mIsRootDefined = GetColor(mRootFrame, &mRootNativeValue);
-  if (aFrame)
-    mIsDefined = GetColor(aFrame, &mNativeValue);
-}
-
-PRBool
-nsBGColorTextAttr::GetValueFor(nsIDOMElement *aElm, nscolor *aValue)
-{
-  nsIFrame *frame = nsCoreUtils::GetFrameFor(aElm);
-  if (!frame)
-    return PR_FALSE;
-
-  return GetColor(frame, aValue);
-}
-
-void
-nsBGColorTextAttr::Format(const nscolor& aValue, nsAString& aFormattedValue)
-{
-  // Combine the string like rgb(R, G, B) from nscolor.
-  nsAutoString value;
-  value.AppendLiteral("rgb(");
-  value.AppendInt(NS_GET_R(aValue));
-  value.AppendLiteral(", ");
-  value.AppendInt(NS_GET_G(aValue));
-  value.AppendLiteral(", ");
-  value.AppendInt(NS_GET_B(aValue));
-  value.Append(')');
-
-  aFormattedValue = value;
-}
-
-PRBool
-nsBGColorTextAttr::GetColor(nsIFrame *aFrame, nscolor *aColor)
-{
-  const nsStyleBackground *styleBackground = aFrame->GetStyleBackground();
-
-  if (!styleBackground->IsTransparent()) {
-    *aColor = styleBackground->mBackgroundColor;
-    return PR_TRUE;
-  }
-
-  nsIFrame *parentFrame = aFrame->GetParent();
-  if (!parentFrame) {
-    *aColor = aFrame->PresContext()->DefaultBackgroundColor();
-    return PR_TRUE;
-  }
-
-  // Each frame of parents chain for the initially passed 'aFrame' has
-  // transparent background color. So background color isn't changed from
-  // 'mRootFrame' to initially passed 'aFrame'.
-  if (parentFrame == mRootFrame)
-    return PR_FALSE;
-
-  return GetColor(parentFrame, aColor);
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// nsFontSizeTextAttr
-
-nsFontSizeTextAttr::nsFontSizeTextAttr(nsIFrame *aRootFrame, nsIFrame *aFrame) :
-  nsTextAttr(aFrame == nsnull)
-{
-  mDC = aRootFrame->PresContext()->DeviceContext();
-
-  mRootNativeValue = GetFontSize(aRootFrame);
-  mIsRootDefined = PR_TRUE;
-
-  if (aFrame) {
-    mNativeValue = GetFontSize(aFrame);
-    mIsDefined = PR_TRUE;
-  }
-}
-
-PRBool
-nsFontSizeTextAttr::GetValueFor(nsIDOMElement *aElm, nscoord *aValue)
-{
-  nsIFrame *frame = nsCoreUtils::GetFrameFor(aElm);
-  if (!frame)
-    return PR_FALSE;
-  
-  *aValue = GetFontSize(frame);
-  return PR_TRUE;
-}
-
-void
-nsFontSizeTextAttr::Format(const nscoord& aValue, nsAString& aFormattedValue)
-{
-  // Convert from nscoord to pt.
-  //
-  // Note: according to IA2, "The conversion doesn't have to be exact.
-  // The intent is to give the user a feel for the size of the text."
-  // 
-  // ATK does not specify a unit and will likely follow IA2 here.
-  //
-  // XXX todo: consider sharing this code with layout module? (bug 474621)
-  float inches = static_cast<float>(aValue) /
-    static_cast<float>(mDC->AppUnitsPerInch());
-  int pts = static_cast<int>(inches * 72 + .5); // 72 pts per inch
-
-  nsAutoString value;
-  value.AppendInt(pts);
-  value.Append(NS_LITERAL_STRING("pt"));
-  aFormattedValue = value;
-}
-
-nscoord
-nsFontSizeTextAttr::GetFontSize(nsIFrame *aFrame)
-{
-  nsStyleFont* styleFont =
-    (nsStyleFont*)(aFrame->GetStyleDataExternal(eStyleStruct_Font));
-
-  return styleFont->mSize;
-}
deleted file mode 100644
--- a/accessible/src/base/nsTextAttrs.h
+++ /dev/null
@@ -1,371 +0,0 @@
-/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* ***** 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.org code.
- *
- * The Initial Developer of the Original Code is
- * Mozilla Foundation.
- * Portions created by the Initial Developer are Copyright (C) 2007
- * the Initial Developer. All Rights Reserved.
- *
- * Contributor(s):
- *   Alexander Surkov <surkov.alexander@gmail.com> (original author)
- *
- * 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
- * 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 nsTextAttrs_h_
-#define nsTextAttrs_h_
-
-class nsHyperTextAccessible;
-
-#include "nsAccessibilityAtoms.h"
-
-#include "nsIDOMNode.h"
-#include "nsIDOMElement.h"
-#include "nsIDOMCSSStyleDeclaration.h"
-
-#include "nsIContent.h"
-#include "nsIFrame.h"
-#include "nsIPersistentProperties2.h"
-
-#include "nsCOMPtr.h"
-#include "nsString.h"
-#include "nsTPtrArray.h"
-
-class nsITextAttr;
-
-/**
- * Used to expose text attributes for the hyper text accessible (see
- * nsHyperTextAccessible class). It is indended for the work with 'language' and
- * CSS based text attributes.
- *
- * @note "invalid: spelling" text attrbiute is implemented entirerly in
- *       nsHyperTextAccessible class.
- */
-class nsTextAttrsMgr
-{
-public:
-  /**
-   * Constructor. If instance of the class is intended to expose default text
-   * attributes then 'aIncludeDefAttrs' and 'oOffsetNode' argument must be
-   * skiped.
-   *
-   * @param aHyperTextAcc    hyper text accessible text attributes are
-   *                         calculated for
-   * @param aHyperTextNode   DOM node of the given hyper text accessbile
-   * @param aIncludeDefAttrs [optional] indicates whether default text
-   *                         attributes should be included into list of exposed
-   *                         text attributes.
-   * @param oOffsetNode      [optional] DOM node represents hyper text offset
-   *                         inside hyper text accessible
-   */
-  nsTextAttrsMgr(nsHyperTextAccessible *aHyperTextAcc,
-                 nsIDOMNode *aHyperTextNode,
-                 PRBool aIncludeDefAttrs = PR_TRUE,
-                 nsIDOMNode *oOffsetNode = nsnull);
-
-  /*
-   * Return text attributes and hyper text offsets where these attributes are
-   * applied. Offsets are calculated in the case of non default attributes.
-   *
-   * @note In the case of default attributes pointers on hyper text offsets
-   *       must be skiped.
-   *
-   * @param aAttributes    [in, out] text attributes list
-   * @param aStartHTOffset [out, optional] start hyper text offset
-   * @param aEndHTOffset   [out, optional] end hyper text offset
-   */
-  nsresult GetAttributes(nsIPersistentProperties *aAttributes,
-                         PRInt32 *aStartHTOffset = nsnull,
-                         PRInt32 *aEndHTOffset = nsnull);
-
-protected:
-
-  /**
-   * Calculates range (start and end offsets) of text where the text attributes
-   * are stretched. New offsets may be smaller if one of text attributes changes
-   * its value before or after the given offsets.
-   *
-   * @param aTextAttrArray  [in] text attributes array
-   * @param aStartHTOffset  [in, out] the start offset
-   * @param aEndHTOffset    [in, out] the end offset
-   */
-   nsresult GetRange(const nsTPtrArray<nsITextAttr>& aTextAttrArray,
-                     PRInt32 *aStartHTOffset, PRInt32 *aEndHTOffset);
-
-  /*
-   * Find new end offset for text attributes navigating through the tree. New
-   * end offset may be smaller if one of text attributes changes its value
-   * before the given end offset.
-   *
-   * @param  aTextAttrArray  [in] text attributes array
-   * @param  aCurrNode       [in] the first node of the tree
-   * @param  aHTOffset       [in, out] the end offset
-   * @return                 true if the end offset has been changed
-   */
-   PRBool FindEndOffsetInSubtree(const nsTPtrArray<nsITextAttr>& aTextAttrArray,
-                                 nsIDOMNode *aCurrNode, PRInt32 *aHTOffset);
-
-  /*
-   * Find the start offset for text attributes navigating through the tree. New
-   * start offset may be bigger if one of text attributes changes its value
-   * after the given start offset.
-   *
-   * @param  aTextAttrArray  [in] text attributes array
-   * @param  aCurrNode       [in] the node navigating through thee thee is
-   *                         started from
-   * @param  aPrevNode       [in] the previous node placed before the start node
-   * @param  aHTOffset       [in, out] the start offset
-   * @return                 true if the start offset has been changed
-   */
-   PRBool FindStartOffsetInSubtree(const nsTPtrArray<nsITextAttr>& aTextAttrArray,
-                                   nsIDOMNode *aCurrNode, nsIDOMNode *aPrevNode,
-                                   PRInt32 *aHTOffset);
-
-private:
-  nsRefPtr<nsHyperTextAccessible> mHyperTextAcc;
-  nsCOMPtr<nsIDOMNode> mHyperTextNode;
-
-  PRBool mIncludeDefAttrs;
-  nsCOMPtr<nsIDOMNode> mOffsetNode;
-};
-
-
-////////////////////////////////////////////////////////////////////////////////
-// Private implementation details
-
-/**
- * Interface class of text attribute class implementations.
- */
-class nsITextAttr
-{
-public:
-  /**
-   * Return the name of text attribute.
-   */
-  virtual nsIAtom* GetName() = 0;
-
-  /**
-   * Retrieve the value of text attribute in out param, return true if differs
-   * from the default value of text attribute or if include default attribute
-   * value flag is setted.
-   * 
-   * @param aValue                [in, out] the value of text attribute
-   * @param aIncludeDefAttrValue  [in] include default attribute value flag
-   * @return                      true if text attribute value differs from
-   *                              default or include default attribute value
-   *                              flag is applied
-   */
-  virtual PRBool GetValue(nsAString& aValue, PRBool aIncludeDefAttrValue) = 0;
-
-  /**
-   * Return true if the text attribute value on the given element equals with
-   * predefined attribute value.
-   */
-  virtual PRBool Equal(nsIDOMElement *aElm) = 0;
-};
-
-
-/**
- * Base class to work with text attributes. See derived classes below.
- */
-template<class T>
-class nsTextAttr : public nsITextAttr
-{
-public:
-  nsTextAttr(PRBool aGetRootValue) : mGetRootValue(aGetRootValue) {}
-
-  // nsITextAttr
-  virtual PRBool GetValue(nsAString& aValue, PRBool aIncludeDefAttrValue)
-  {
-    if (mGetRootValue) {
-      Format(mRootNativeValue, aValue);
-      return mIsRootDefined;
-    }
-
-    PRBool isDefined = mIsDefined;
-    T* nativeValue = &mNativeValue;
-
-    if (!isDefined) {
-      if (aIncludeDefAttrValue) {
-        isDefined = mIsRootDefined;
-        nativeValue = &mRootNativeValue;
-      }
-    } else if (!aIncludeDefAttrValue) {
-      isDefined = mRootNativeValue != mNativeValue;
-    }
-
-    if (!isDefined)
-      return PR_FALSE;
-
-    Format(*nativeValue, aValue);
-    return PR_TRUE;
-  }
-
-  virtual PRBool Equal(nsIDOMElement *aElm)
-  {
-    T nativeValue;
-    PRBool isDefined = GetValueFor(aElm, &nativeValue);
-
-    if (!mIsDefined && !isDefined)
-      return PR_TRUE;
-
-    if (mIsDefined && isDefined)
-      return nativeValue == mNativeValue;
-
-    if (mIsDefined)
-      return mNativeValue == mRootNativeValue;
-
-    return nativeValue == mRootNativeValue;
-  }
-
-protected:
-
-  // Return native value for the given DOM element.
-  virtual PRBool GetValueFor(nsIDOMElement *aElm, T *aValue) = 0;
-
-  // Format native value to text attribute value.
-  virtual void Format(const T& aValue, nsAString& aFormattedValue) = 0;
-
-  // Indicates if root value should be exposed.
-  PRBool mGetRootValue;
-
-  // Native value and flag indicating if the value is defined (initialized in
-  // derived classes). Note, undefined native value means it is inherited
-  // from root.
-  T mNativeValue;
-  PRBool mIsDefined;
-
-  // Native root value and flag indicating if the value is defined  (initialized
-  // in derived classes).
-  T mRootNativeValue;
-  PRBool mIsRootDefined;
-};
-
-
-/**
- * Class is used for the work with 'language' text attribute in nsTextAttrsMgr
- * class.
- */
-class nsLangTextAttr : public nsTextAttr<nsAutoString>
-{
-public:
-  nsLangTextAttr(nsHyperTextAccessible *aRootAcc, nsIDOMNode *aRootNode,
-                 nsIDOMNode *aNode);
-
-  // nsITextAttr
-  virtual nsIAtom *GetName() { return nsAccessibilityAtoms::language; }
-
-protected:
-
-  // nsTextAttr
-  virtual PRBool GetValueFor(nsIDOMElement *aElm, nsAutoString *aValue);
-  virtual void Format(const nsAutoString& aValue, nsAString& aFormattedValue);
-
-private:
-  PRBool GetLang(nsIContent *aContent, nsAString& aLang);
-  nsCOMPtr<nsIContent> mRootContent;
-};
-
-
-/**
- * Class is used for the work with CSS based text attributes in nsTextAttrsMgr
- * class.
- */
-class nsCSSTextAttr : public nsTextAttr<nsAutoString>
-{
-public:
-  nsCSSTextAttr(PRUint32 aIndex, nsIDOMElement *aRootElm, nsIDOMElement *aElm);
-
-  // nsITextAttr
-  virtual nsIAtom *GetName();
-
-protected:
-
-  // nsTextAttr
-  virtual PRBool GetValueFor(nsIDOMElement *aElm, nsAutoString *aValue);
-  virtual void Format(const nsAutoString& aValue, nsAString& aFormattedValue);
-
-private:
-  PRInt32 mIndex;
-};
-
-
-/**
- * Class is used for the work with 'background-color' text attribute in
- * nsTextAttrsMgr class.
- */
-class nsBGColorTextAttr : public nsTextAttr<nscolor>
-{
-public:
-  nsBGColorTextAttr(nsIFrame *aRootFrame, nsIFrame *aFrame);
-
-  // nsITextAttr
-  virtual nsIAtom *GetName() { return nsAccessibilityAtoms::backgroundColor; }
-
-protected:
-  // nsTextAttr
-  virtual PRBool GetValueFor(nsIDOMElement *aElm, nscolor *aValue);
-  virtual void Format(const nscolor& aValue, nsAString& aFormattedValue);
-
-private:
-  PRBool GetColor(nsIFrame *aFrame, nscolor *aColor);
-  nsIFrame *mRootFrame;
-};
-
-
-/**
- * Class is used for the work with "font-size" text attribute in nsTextAttrsMgr
- * class.
- */
-class nsFontSizeTextAttr : public nsTextAttr<nscoord>
-{
-public:
-  nsFontSizeTextAttr(nsIFrame *aRootFrame, nsIFrame *aFrame);
-
-  // nsITextAttr
-  virtual nsIAtom *GetName() { return nsAccessibilityAtoms::fontSize; }
-
-protected:
-
-  // nsTextAttr
-  virtual PRBool GetValueFor(nsIDOMElement *aElm, nscoord *aValue);
-  virtual void Format(const nscoord& aValue, nsAString& aFormattedValue);
-
-private:
-
-  /**
-   * Return font size for the given frame.
-   *
-   * @param aFrame      [in] the given frame to query font-size
-   * @return            font size
-   */
-   nscoord GetFontSize(nsIFrame *aFrame);
-
-  nsIDeviceContext *mDC;
-};
-
-#endif
new file mode 100644
--- /dev/null
+++ b/accessible/src/base/nsTextUtils.cpp
@@ -0,0 +1,298 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Alexander Surkov <surkov.alexander@gmail.com> (original author)
+ *
+ * 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
+ * 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 "nsTextUtils.h"
+
+#include "nsAccessNode.h"
+
+////////////////////////////////////////////////////////////////////////////////
+// nsLangTextAttr
+
+PRBool
+nsLangTextAttr::Equal(nsIDOMElement *aElm)
+{
+  nsCOMPtr<nsIContent> content(do_QueryInterface(aElm));
+  if (!content)
+    return PR_FALSE;
+
+  nsAutoString lang;
+  nsCoreUtils::GetLanguageFor(content, mRootContent, lang);
+
+  return lang == mLang;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// nsCSSTextAttr
+
+/**
+ * Item of the gCSSTextAttrsMap map.
+ */
+struct nsCSSTextAttrMapItem
+{
+  const char* mCSSName;
+  const char* mCSSValue;
+  const char* mAttrName;
+  const char* mAttrValue;
+};
+
+/**
+ * The map of CSS properties to text attributes.
+ */
+
+const char* const kAnyValue = nsnull;
+const char* const kCopyName = nsnull;
+const char* const kCopyValue = nsnull;
+
+static nsCSSTextAttrMapItem gCSSTextAttrsMap[] = {
+  // CSS name            CSS value        Attribute name              Attribute value
+  { "color",             kAnyValue,       kCopyName,                  kCopyValue },
+  { "font-family",       kAnyValue,       kCopyName,                  kCopyValue },
+  { "font-style",        kAnyValue,       kCopyName,                  kCopyValue },
+  { "font-weight",       kAnyValue,       kCopyName,                  kCopyValue },
+  { "text-decoration",   "line-through",  "text-line-through-style",  "solid" },
+  { "text-decoration",   "underline",     "text-underline-style",     "solid" },
+  { "vertical-align",    kAnyValue,       "text-position",            kCopyValue }
+};
+
+nsCSSTextAttr::nsCSSTextAttr(PRBool aIncludeDefAttrValue, nsIDOMElement *aElm,
+                             nsIDOMElement *aRootElm) :
+  mIndex(-1), mIncludeDefAttrValue(aIncludeDefAttrValue)
+{
+  nsCoreUtils::GetComputedStyleDeclaration(EmptyString(), aElm,
+                                           getter_AddRefs(mStyleDecl));
+
+  if (!mIncludeDefAttrValue)
+    nsCoreUtils::GetComputedStyleDeclaration(EmptyString(), aRootElm,
+                                             getter_AddRefs(mDefStyleDecl));
+}
+
+PRBool
+nsCSSTextAttr::Equal(nsIDOMElement *aElm)
+{
+  if (!aElm || !mStyleDecl)
+    return PR_FALSE;
+
+  nsCOMPtr<nsIDOMCSSStyleDeclaration> currStyleDecl;
+  nsCoreUtils::GetComputedStyleDeclaration(EmptyString(), aElm,
+                                           getter_AddRefs(currStyleDecl));
+  if (!currStyleDecl)
+    return PR_FALSE;
+
+  NS_ConvertASCIItoUTF16 cssName(gCSSTextAttrsMap[mIndex].mCSSName);
+
+  nsAutoString currValue;
+  nsresult rv = currStyleDecl->GetPropertyValue(cssName, currValue);
+  if (NS_FAILED(rv))
+    return PR_FALSE;
+
+  nsAutoString value;
+  rv = mStyleDecl->GetPropertyValue(cssName, value);
+  return NS_SUCCEEDED(rv) && value == currValue;
+}
+
+PRBool
+nsCSSTextAttr::Iterate()
+{
+  return ++mIndex < static_cast<PRInt32>(NS_ARRAY_LENGTH(gCSSTextAttrsMap));
+}
+
+PRBool
+nsCSSTextAttr::Get(nsACString& aName, nsAString& aValue)
+{
+  if (!mStyleDecl)
+    return PR_FALSE;
+
+  NS_ConvertASCIItoUTF16 cssName(gCSSTextAttrsMap[mIndex].mCSSName);
+  nsresult rv = mStyleDecl->GetPropertyValue(cssName, aValue);
+  if (NS_FAILED(rv))
+    return PR_FALSE;
+
+  // Don't expose text attribute if corresponding CSS value on the element
+  // equals to CSS value on the root element and we don't want to include
+  // default values.
+  if (!mIncludeDefAttrValue) {
+    if (!mDefStyleDecl)
+      return PR_FALSE;
+
+    nsAutoString defValue;
+    mDefStyleDecl->GetPropertyValue(cssName, defValue);
+    if (defValue == aValue)
+      return PR_FALSE;
+  }
+
+  // Don't expose text attribute if its required specific CSS value isn't
+  // matched with the CSS value we got.
+  const char *cssValue = gCSSTextAttrsMap[mIndex].mCSSValue;
+  if (cssValue != kAnyValue && !aValue.EqualsASCII(cssValue))
+    return PR_FALSE;
+
+  // Get the name of text attribute.
+  if (gCSSTextAttrsMap[mIndex].mAttrName != kCopyName)
+    aName = gCSSTextAttrsMap[mIndex].mAttrName;
+  else
+    aName = gCSSTextAttrsMap[mIndex].mCSSName;
+
+  // Get the value of text attribute.
+  const char *attrValue = gCSSTextAttrsMap[mIndex].mAttrValue;
+  if (attrValue != kCopyValue)
+    AppendASCIItoUTF16(attrValue, aValue);
+
+  return PR_TRUE;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// nsBackgroundTextAttr
+
+nsBackgroundTextAttr::nsBackgroundTextAttr(nsIFrame *aFrame,
+                                           nsIFrame *aRootFrame) :
+  mFrame(aFrame), mRootFrame(aRootFrame)
+{
+}
+
+PRBool
+nsBackgroundTextAttr::Equal(nsIDOMElement *aElm)
+{
+  nsIFrame *frame = nsCoreUtils::GetFrameFor(aElm);
+  if (!frame)
+    return PR_FALSE;
+
+  return GetColor(mFrame) == GetColor(frame);    
+}
+
+PRBool
+nsBackgroundTextAttr::Get(nsAString& aValue)
+{
+  // Do not expose "background-color" text attribute if its value is matched
+  // with the default value.
+  nscolor color = GetColor(mFrame);
+  if (mRootFrame && color == GetColor(mRootFrame))
+    return PR_FALSE;
+
+  // Combine the string like rgb(R, G, B) from nscolor.
+  nsAutoString value;
+  value.AppendLiteral("rgb(");
+  value.AppendInt(NS_GET_R(color));
+  value.AppendLiteral(", ");
+  value.AppendInt(NS_GET_G(color));
+  value.AppendLiteral(", ");
+  value.AppendInt(NS_GET_B(color));
+  value.Append(')');
+
+  aValue = value;
+  return PR_TRUE;
+}
+
+nscolor
+nsBackgroundTextAttr::GetColor(nsIFrame *aFrame)
+{
+  const nsStyleBackground *styleBackground = aFrame->GetStyleBackground();
+
+  if (!styleBackground->IsTransparent())
+    return styleBackground->mBackgroundColor;
+
+  nsIFrame *parentFrame = aFrame->GetParent();
+  if (!parentFrame)
+    return aFrame->PresContext()->DefaultBackgroundColor();
+
+  // Each frame of parents chain for the initially passed 'aFrame' has
+  // transparent background color. So background color isn't changed from
+  // 'mRootFrame' to initially passed 'aFrame'.
+  if (parentFrame == mRootFrame)
+    return GetColor(mRootFrame);
+
+  return GetColor(parentFrame);
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// nsFontSizeTextAttr
+
+nsFontSizeTextAttr::nsFontSizeTextAttr(nsIFrame *aFrame,
+                                           nsIFrame *aRootFrame) :
+  mFrame(aFrame), mRootFrame(aRootFrame)
+{
+}
+
+PRBool
+nsFontSizeTextAttr::Equal(nsIDOMElement *aElm)
+{
+  nsIFrame *frame = nsCoreUtils::GetFrameFor(aElm);
+  if (!frame)
+    return PR_FALSE;
+
+  return GetFontSize(mFrame) == GetFontSize(frame);    
+}
+
+
+PRBool
+nsFontSizeTextAttr::Get(nsAString& aValue)
+{
+  // Do not expose "font-size" text attribute if its value is the same
+  // as the default value.
+  nscoord fontsize = GetFontSize(mFrame);
+  if (mRootFrame && fontsize == GetFontSize(mRootFrame))
+    return PR_FALSE;
+
+  // Convert from nscoord to pt.
+  //
+  // Note: according to IA2, "The conversion doesn't have to be exact.
+  // The intent is to give the user a feel for the size of the text."
+  // 
+  // ATK does not specify a unit and will likely follow IA2 here.
+  //
+  // XXX todo: consider sharing this code with layout module? (bug 474621)
+  nsIDeviceContext *dc = mFrame->PresContext()->DeviceContext();
+  float inches = static_cast<float>(GetFontSize(mFrame)) /
+                        static_cast<float>(dc->AppUnitsPerInch());
+  int pts = inches * 72 + .5; // 72 pts per inch
+  
+  nsAutoString value;
+  value.AppendInt(pts);
+  value.Append(NS_LITERAL_STRING("pt"));
+  aValue = value;
+
+  return PR_TRUE;
+}
+
+nscoord
+nsFontSizeTextAttr::GetFontSize(nsIFrame *aFrame)
+{
+  nsStyleFont* styleFont =
+    (nsStyleFont*)(aFrame->GetStyleDataExternal(eStyleStruct_Font));
+
+  return styleFont->mSize;
+}
new file mode 100644
--- /dev/null
+++ b/accessible/src/base/nsTextUtils.h
@@ -0,0 +1,190 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* ***** 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.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2007
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Alexander Surkov <surkov.alexander@gmail.com> (original author)
+ *
+ * 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
+ * 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 nsTextUtils_h_
+#define nsTextUtils_h_
+
+#include "nsIDOMElement.h"
+#include "nsIDOMCSSStyleDeclaration.h"
+
+#include "nsIContent.h"
+#include "nsIFrame.h"
+
+#include "nsCOMPtr.h"
+#include "nsString.h"
+
+/**
+ * Base class to work with text attributes. See derived classes below.
+ */
+class nsTextAttr
+{
+public:
+  /**
+   * Return true if the text attribute for the given element equals with
+   * predefined attribute.
+   */
+  virtual PRBool Equal(nsIDOMElement *aElm) = 0;
+};
+
+/**
+ * Class is used for the work with 'lang' text attributes. Used in
+ * nsHyperTextAccessible.
+ */
+class nsLangTextAttr : public nsTextAttr
+{
+public:
+  nsLangTextAttr(nsAString& aLang, nsIContent *aRootContent) :
+    mLang(aLang), mRootContent(aRootContent) { }
+
+  virtual PRBool Equal(nsIDOMElement *aElm);
+
+private:
+  nsString mLang;
+  nsCOMPtr<nsIContent> mRootContent;
+};
+
+/**
+ * Class is used for the work with CSS based text attributes. Used in
+ * nsHyperTextAccessible.
+ */
+class nsCSSTextAttr : public nsTextAttr
+{
+public:
+  nsCSSTextAttr(PRBool aIncludeDefAttrValue, nsIDOMElement *aElm,
+                nsIDOMElement *aRootElm);
+
+  // nsTextAttr
+  virtual PRBool Equal(nsIDOMElement *aElm);
+
+  // nsCSSTextAttr
+  /**
+   * Interates through attributes.
+   */
+  PRBool Iterate();
+
+  /**
+   * Get name and value of attribute.
+   */
+  PRBool Get(nsACString& aName, nsAString& aValue);
+
+private:
+  PRInt32 mIndex;
+  PRBool mIncludeDefAttrValue;
+
+  nsCOMPtr<nsIDOMCSSStyleDeclaration> mStyleDecl;
+  nsCOMPtr<nsIDOMCSSStyleDeclaration> mDefStyleDecl;
+};
+
+/**
+ * Class is used for the work with "background-color" text attribute. It is
+ * used in nsHyperTextAccessible.
+ */
+class nsBackgroundTextAttr : public nsTextAttr
+{
+public:
+  nsBackgroundTextAttr(nsIFrame *aFrame, nsIFrame *aRootFrame);
+  
+  // nsTextAttr
+  virtual PRBool Equal(nsIDOMElement *aElm);
+
+  // nsBackgroundTextAttr
+
+  /**
+   * Retrieve the "background-color" in out param, return true if differs from
+   * the default background-color.
+   * 
+   * @param aValue      [out] the background color in pts
+   * @return            true if background color differs from default
+   */
+  virtual PRBool Get(nsAString& aValue);
+
+private:
+  /**
+   * Return background color for the given frame.
+   *
+   * @note  If background color for the given frame is transparent then walk
+   *        trhough the frame parents chain until we'll got either a frame with
+   *        not transparent background color or the given root frame. In the
+   *        last case return background color for the root frame.
+   *
+   * @param aFrame      [in] the given frame to calculate background-color
+   * @return            background color
+   */
+  nscolor GetColor(nsIFrame *aFrame);
+
+  nsIFrame *mFrame;
+  nsIFrame *mRootFrame;
+};
+
+/**
+ * Class is used for the work with "font-size" text attribute. It is
+ * used in nsHyperTextAccessible.
+ */
+class nsFontSizeTextAttr : public nsTextAttr
+{
+public:
+  nsFontSizeTextAttr(nsIFrame *aFrame, nsIFrame *aRootFrame);
+  
+  // nsTextAttr
+  virtual PRBool Equal(nsIDOMElement *aElm);
+
+  // nsFontSizeTextAttr
+
+  /**
+   * Retrieve the "font-size" in out param, return true if differs from
+   * the default font-size.
+   * 
+   * @param aValue      [out] the font size in pts
+   * @return            true if font size differs from default
+   */
+  virtual PRBool Get(nsAString& aValue);
+
+private:
+  /**
+   * Return font size for the given frame.
+   *
+   * @param aFrame      [in] the given frame to query font-size
+   * @return            font size
+   */
+   nscoord GetFontSize(nsIFrame *aFrame);
+
+  nsIFrame *mFrame;
+  nsIFrame *mRootFrame;
+};
+
+#endif
--- a/accessible/src/html/nsHyperTextAccessible.cpp
+++ b/accessible/src/html/nsHyperTextAccessible.cpp
@@ -36,17 +36,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsHyperTextAccessible.h"
 #include "nsAccessibilityAtoms.h"
 #include "nsAccessibilityService.h"
 #include "nsAccessibleTreeWalker.h"
-#include "nsTextAttrs.h"
+#include "nsTextUtils.h"
 
 #include "nsIClipboard.h"
 #include "nsContentCID.h"
 #include "nsIDOMAbstractView.h"
 #include "nsIDOMCharacterData.h"
 #include "nsIDOMDocument.h"
 #include "nsPIDOMWindow.h"        
 #include "nsIDOMDocumentView.h"
@@ -1169,18 +1169,27 @@ nsHyperTextAccessible::GetTextAttributes
 
   nsCOMPtr<nsIContent> content(do_QueryInterface(node));
   if (content && content->IsNodeOfType(nsINode::eELEMENT))
     node = do_QueryInterface(content->GetChildAt(nodeOffset));
 
   if (!node)
     return NS_OK;
 
-  nsTextAttrsMgr textAttrsMgr(this, mDOMNode, aIncludeDefAttrs, node);
-  return textAttrsMgr.GetAttributes(*aAttributes, aStartOffset, aEndOffset);
+  // Set 'lang' text attribute.
+  rv =  GetLangTextAttributes(aIncludeDefAttrs, node,
+                              aStartOffset, aEndOffset,
+                              aAttributes ? *aAttributes : nsnull);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  // Set CSS based text attributes.
+  rv = GetCSSTextAttributes(aIncludeDefAttrs, node,
+                            aStartOffset, aEndOffset,
+                            aAttributes ? *aAttributes : nsnull);
+  return rv;
 }
 
 // nsIPersistentProperties
 // nsIAccessibleText::defaultTextAttributes
 NS_IMETHODIMP
 nsHyperTextAccessible::GetDefaultTextAttributes(nsIPersistentProperties **aAttributes)
 {
   NS_ENSURE_ARG_POINTER(aAttributes);
@@ -1190,18 +1199,45 @@ nsHyperTextAccessible::GetDefaultTextAtt
     do_CreateInstance(NS_PERSISTENTPROPERTIES_CONTRACTID);
   NS_ENSURE_TRUE(attributes, NS_ERROR_OUT_OF_MEMORY);
 
   NS_ADDREF(*aAttributes = attributes);
 
   if (!mDOMNode)
     return NS_ERROR_FAILURE;
 
-  nsTextAttrsMgr textAttrsMgr(this, mDOMNode, PR_TRUE, nsnull);
-  return textAttrsMgr.GetAttributes(*aAttributes);
+  nsCOMPtr<nsIDOMElement> element = nsCoreUtils::GetDOMElementFor(mDOMNode);
+
+  nsCSSTextAttr textAttr(PR_TRUE, element, nsnull);
+  while (textAttr.Iterate()) {
+    nsCAutoString name;
+    nsAutoString value, oldValue;
+    if (textAttr.Get(name, value))
+      attributes->SetStringProperty(name, value, oldValue);
+  }
+  
+  nsIFrame *sourceFrame = nsCoreUtils::GetFrameFor(element);
+  NS_ENSURE_STATE(sourceFrame);
+
+  // set font size
+  nsAutoString value;
+  nsFontSizeTextAttr fontSizeTextAttr(sourceFrame, nsnull);
+  fontSizeTextAttr.Get(value);
+  nsAccUtils::SetAccAttr(attributes,
+                         nsAccessibilityAtoms::fontSize, value);
+  
+  value.Truncate();
+  
+  // set font background color
+  nsBackgroundTextAttr backgroundTextAttr(sourceFrame, nsnull);
+  backgroundTextAttr.Get(value);
+  nsAccUtils::SetAccAttr(attributes,
+                         nsAccessibilityAtoms::backgroundColor, value);
+
+  return NS_OK;
 }
 
 nsresult
 nsHyperTextAccessible::GetAttributesInternal(nsIPersistentProperties *aAttributes)
 {
   if (!mDOMNode) {
     return NS_ERROR_FAILURE;  // Node already shut down
   }
@@ -2279,8 +2315,280 @@ nsHyperTextAccessible::GetSpellTextAttri
       }
 
       return NS_OK;
     }
   }
 
   return NS_OK;
 }
+
+// nsHyperTextAccessible
+nsresult
+nsHyperTextAccessible::GetLangTextAttributes(PRBool aIncludeDefAttrs,
+                                             nsIDOMNode *aSourceNode,
+                                             PRInt32 *aStartHTOffset,
+                                             PRInt32 *aEndHTOffset,
+                                             nsIPersistentProperties *aAttributes)
+{
+  nsCOMPtr<nsIDOMElement> sourceElm(nsCoreUtils::GetDOMElementFor(aSourceNode));
+
+  nsCOMPtr<nsIContent> content(do_QueryInterface(sourceElm));
+  nsCOMPtr<nsIContent> rootContent(do_QueryInterface(mDOMNode));
+
+  nsAutoString lang;
+  nsCoreUtils::GetLanguageFor(content, rootContent, lang);
+
+  nsAutoString rootLang;
+  nsresult rv = GetLanguage(rootLang);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  if (aAttributes) {
+    // Expose 'language' text attribute if the DOM 'lang' attribute is
+    // presented and it's different from the 'lang' attribute on the root
+    // element or we should include default values of text attribute.
+    const nsAString& resultLang = lang.IsEmpty() ? rootLang : lang;
+    if (!resultLang.IsEmpty() && (aIncludeDefAttrs || lang != rootLang))
+      nsAccUtils::SetAccAttr(aAttributes, nsAccessibilityAtoms::language,
+                             resultLang);
+  }
+
+  nsLangTextAttr textAttr(lang, rootContent);
+  return GetRangeForTextAttr(aSourceNode, &textAttr,
+                             aStartHTOffset, aEndHTOffset);
+}
+
+// nsHyperTextAccessible
+nsresult
+nsHyperTextAccessible::GetCSSTextAttributes(PRBool aIncludeDefAttrs,
+                                            nsIDOMNode *aSourceNode,
+                                            PRInt32 *aStartHTOffset,
+                                            PRInt32 *aEndHTOffset,
+                                            nsIPersistentProperties *aAttributes)
+{
+  nsCOMPtr<nsIDOMElement> sourceElm(nsCoreUtils::GetDOMElementFor(aSourceNode));
+  nsCOMPtr<nsIDOMElement> rootElm(nsCoreUtils::GetDOMElementFor(mDOMNode));
+
+  nsCSSTextAttr textAttr(aIncludeDefAttrs, sourceElm, rootElm);
+  while (textAttr.Iterate()) {
+    nsCAutoString name;
+    nsAutoString value, oldValue;
+    if (aAttributes && textAttr.Get(name, value))
+      aAttributes->SetStringProperty(name, value, oldValue);
+
+    nsresult rv = GetRangeForTextAttr(aSourceNode, &textAttr,
+                                      aStartHTOffset, aEndHTOffset);
+    NS_ENSURE_SUCCESS(rv, rv);
+  }
+
+  nsIFrame *sourceFrame = nsCoreUtils::GetFrameFor(sourceElm);
+  if (sourceFrame) {
+    nsIFrame *rootFrame = nsnull;
+
+    if (!aIncludeDefAttrs)
+      rootFrame = nsCoreUtils::GetFrameFor(rootElm);
+
+    nsFontSizeTextAttr fontSizeTextAttr(sourceFrame, rootFrame);
+    nsAutoString value;
+    if (fontSizeTextAttr.Get(value)) {
+      nsAccUtils::SetAccAttr(aAttributes,
+                             nsAccessibilityAtoms::fontSize, value);
+    }
+
+    nsBackgroundTextAttr backgroundTextAttr(sourceFrame, rootFrame);
+    value.Truncate();
+    if (backgroundTextAttr.Get(value)) {
+      nsAccUtils::SetAccAttr(aAttributes,
+                             nsAccessibilityAtoms::backgroundColor, value);
+    }
+
+    nsresult rv = GetRangeForTextAttr(aSourceNode, &backgroundTextAttr,
+                                      aStartHTOffset, aEndHTOffset);
+    return rv;
+  }
+
+  return NS_OK;
+}
+
+// nsHyperTextAccessible
+nsresult
+nsHyperTextAccessible::GetRangeForTextAttr(nsIDOMNode *aNode,
+                                           nsTextAttr *aComparer,
+                                           PRInt32 *aStartHTOffset,
+                                           PRInt32 *aEndHTOffset)
+{
+  nsCOMPtr<nsIDOMElement> rootElm(nsCoreUtils::GetDOMElementFor(mDOMNode));
+  NS_ENSURE_STATE(rootElm);
+
+  nsCOMPtr<nsIDOMNode> tmpNode(aNode);
+  nsCOMPtr<nsIDOMNode> currNode(aNode);
+
+  // Navigate backwards and forwards from current node to the root node to
+  // calculate range bounds for the text attribute. Navigation sequence is the
+  // following:
+  // 1. Navigate through the siblings.
+  // 2. If the traversed sibling has children then navigate from its leaf child
+  //    to it through whole tree of the traversed sibling.
+  // 3. Get the parent and cycle algorithm until the root node.
+
+  // Navigate backwards (find the start offset).
+  while (currNode && currNode != rootElm) {
+    nsCOMPtr<nsIDOMElement> currElm(nsCoreUtils::GetDOMElementFor(currNode));
+    NS_ENSURE_STATE(currElm);
+
+    if (currNode != aNode && !aComparer->Equal(currElm)) {
+      PRInt32 startHTOffset = 0;
+      nsCOMPtr<nsIAccessible> startAcc;
+      nsresult rv = DOMPointToHypertextOffset(tmpNode, -1, &startHTOffset,
+                                              getter_AddRefs(startAcc));
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      if (!startAcc)
+        startHTOffset = 0;
+
+      if (startHTOffset > *aStartHTOffset)
+        *aStartHTOffset = startHTOffset;
+
+      break;
+    }
+
+    currNode->GetPreviousSibling(getter_AddRefs(tmpNode));
+    if (tmpNode) {
+      // Navigate through the subtree of traversed children to calculate
+      // left bound of the range.
+      FindStartOffsetInSubtree(tmpNode, currNode, aComparer, aStartHTOffset);
+    }
+
+    currNode->GetParentNode(getter_AddRefs(tmpNode));
+    currNode.swap(tmpNode);
+  }
+
+  // Navigate forwards (find the end offset).
+  PRBool moveIntoSubtree = PR_TRUE;
+  currNode = aNode;
+  while (currNode && currNode != rootElm) {
+    nsCOMPtr<nsIDOMElement> currElm(nsCoreUtils::GetDOMElementFor(currNode));
+    NS_ENSURE_STATE(currElm);
+
+    // Stop new end offset searching if the given text attribute changes its
+    // value.
+    if (!aComparer->Equal(currElm)) {
+      PRInt32 endHTOffset = 0;
+      nsresult rv = DOMPointToHypertextOffset(currNode, -1, &endHTOffset);
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      if (endHTOffset < *aEndHTOffset)
+        *aEndHTOffset = endHTOffset;
+
+      break;
+    }
+
+    if (moveIntoSubtree) {
+      // Navigate through subtree of traversed node. We use 'moveIntoSubtree'
+      // flag to avoid traversing the same subtree twice.
+      currNode->GetFirstChild(getter_AddRefs(tmpNode));
+      if (tmpNode)
+        FindEndOffsetInSubtree(tmpNode, aComparer, aEndHTOffset);
+    }
+
+    currNode->GetNextSibling(getter_AddRefs(tmpNode));
+    moveIntoSubtree = PR_TRUE;
+    if (!tmpNode) {
+      currNode->GetParentNode(getter_AddRefs(tmpNode));
+      moveIntoSubtree = PR_FALSE;
+    }
+
+    currNode.swap(tmpNode);
+  }
+
+  return NS_OK;
+}
+
+
+PRBool
+nsHyperTextAccessible::FindEndOffsetInSubtree(nsIDOMNode *aCurrNode,
+                                              nsTextAttr *aComparer,
+                                              PRInt32 *aHTOffset)
+{
+  if (!aCurrNode)
+    return PR_FALSE;
+
+  nsCOMPtr<nsIDOMElement> currElm(nsCoreUtils::GetDOMElementFor(aCurrNode));
+  NS_ENSURE_STATE(currElm);
+
+  // If the given text attribute (pointed by nsTextAttr object) changes its
+  // value on the traversed element then fit the end of range.
+  if (!aComparer->Equal(currElm)) {
+    PRInt32 endHTOffset = 0;
+    nsresult rv = DOMPointToHypertextOffset(aCurrNode, -1, &endHTOffset);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    if (endHTOffset < *aHTOffset)
+      *aHTOffset = endHTOffset;
+
+    return PR_TRUE;
+  }
+
+  // Deeply traverse into the tree to fit the end of range.
+  nsCOMPtr<nsIDOMNode> nextNode;
+  aCurrNode->GetFirstChild(getter_AddRefs(nextNode));
+  if (nextNode) {
+    PRBool res = FindEndOffsetInSubtree(nextNode, aComparer, aHTOffset);
+    if (res)
+      return res;
+  }
+
+  aCurrNode->GetNextSibling(getter_AddRefs(nextNode));
+  if (nextNode) {
+    if (FindEndOffsetInSubtree(nextNode, aComparer, aHTOffset))
+      return PR_TRUE;
+  }
+
+  return PR_FALSE;
+}
+
+PRBool
+nsHyperTextAccessible::FindStartOffsetInSubtree(nsIDOMNode *aCurrNode,
+                                                nsIDOMNode *aPrevNode,
+                                                nsTextAttr *aComparer,
+                                                PRInt32 *aHTOffset)
+{
+  if (!aCurrNode)
+    return PR_FALSE;
+
+  // Find the closest element back to the traversed element.
+  nsCOMPtr<nsIDOMNode> nextNode;
+  aCurrNode->GetLastChild(getter_AddRefs(nextNode));
+  if (nextNode) {
+    if (FindStartOffsetInSubtree(nextNode, aPrevNode, aComparer, aHTOffset))
+      return PR_TRUE;
+  }
+
+  nsCOMPtr<nsIDOMElement> currElm(nsCoreUtils::GetDOMElementFor(aCurrNode));
+  NS_ENSURE_STATE(currElm);
+
+  // If the given text attribute (pointed by nsTextAttr object) changes its
+  // value on the traversed element then fit the start of range.
+  if (!aComparer->Equal(currElm)) {
+    PRInt32 startHTOffset = 0;
+    nsCOMPtr<nsIAccessible> startAcc;
+    nsresult rv = DOMPointToHypertextOffset(aPrevNode, -1, &startHTOffset,
+                                            getter_AddRefs(startAcc));
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    if (!startAcc)
+      startHTOffset = 0;
+
+    if (startHTOffset > *aHTOffset)
+      *aHTOffset = startHTOffset;
+
+    return PR_TRUE;
+  }
+
+  // Moving backwards to find the start of range.
+  aCurrNode->GetPreviousSibling(getter_AddRefs(nextNode));
+  if (nextNode) {
+    if (FindStartOffsetInSubtree(nextNode, aCurrNode, aComparer, aHTOffset))
+      return PR_TRUE;
+  }
+
+  return PR_FALSE;
+}
--- a/accessible/src/html/nsHyperTextAccessible.h
+++ b/accessible/src/html/nsHyperTextAccessible.h
@@ -40,17 +40,17 @@
 #ifndef _nsHyperTextAccessible_H_
 #define _nsHyperTextAccessible_H_
 
 #include "nsAccessibleWrap.h"
 #include "nsIAccessibleText.h"
 #include "nsIAccessibleHyperText.h"
 #include "nsIAccessibleEditableText.h"
 #include "nsAccessibleEventData.h"
-#include "nsTextAttrs.h"
+#include "nsTextUtils.h"
 
 #include "nsFrameSelection.h"
 #include "nsISelectionController.h"
 
 enum EGetTextType { eGetBefore=-1, eGetAt=0, eGetAfter=1 };
 
 // This character marks where in the text returned via nsIAccessibleText(),
 // that embedded object characters exist
@@ -288,15 +288,97 @@ protected:
    * @param aStartOffset      [in, out] the start offset
    * @param aEndOffset        [in, out] the end offset
    * @param aAttributes       [out, optional] result attributes
    */
   nsresult GetSpellTextAttribute(nsIDOMNode *aNode, PRInt32 aNodeOffset,
                                  PRInt32 *aStartOffset,
                                  PRInt32 *aEndOffset,
                                  nsIPersistentProperties *aAttributes);
+
+  /**
+   * Set 'lang' text attribute and return range offsets where attibute is
+   * stretched. The method is used by GetTextAttributes() method.
+   *
+   * @param aIncludeDefAttrs  [in] points whether text attributes having default
+   *                          values of attributes should be included
+   * @param aSourceNode       [in] the node we start to traverse from
+   * @param aStartOffset      [in, out] the start offset
+   * @param aEndOffset        [in, out] the end offset
+   * @param aAttributes       [out, optional] result attributes
+   */
+  nsresult GetLangTextAttributes(PRBool aIncludeDefAttrs,
+                                 nsIDOMNode *aSourceNode,
+                                 PRInt32 *aStartOffset,
+                                 PRInt32 *aEndOffset,
+                                 nsIPersistentProperties *aAttributes);
+
+  /**
+   * Set CSS based text attribute and return range offsets where attibutes are
+   * stretched. The method is used by GetTextAttributes() method.
+   *
+   * @param aIncludeDefAttrs  [in] points whether text attributes having default
+   *                          values of attributes should be included
+   * @param aSourceNode       [in] the node we start to traverse from
+   * @param aStartOffset      [in, out] the start offset
+   * @param aEndOffset        [in, out] the end offset
+   * @param aAttributes       [out, optional] result attributes
+   */
+  nsresult GetCSSTextAttributes(PRBool aIncludeDefAttrs,
+                                nsIDOMNode *aSourceNode,
+                                PRInt32 *aStartOffset,
+                                PRInt32 *aEndOffset,
+                                nsIPersistentProperties *aAttributes);
+
+  /**
+   * Calculates range (start and end offsets) of text where the text attribute
+   * (pointed by nsTextAttr object) is stretched. New offsets may be smaller if
+   * the given text attribute changes its value before or after the given
+   * offsets.
+   *
+   * @param aNode          [in] the node we start to traverse from
+   * @param aComparer      [in] object used to describe the text attribute
+   * @param aStartHTOffset [in, out] the start offset
+   * @param aEndHTOffset   [in, out] the end offset
+   */
+  nsresult GetRangeForTextAttr(nsIDOMNode *aNode,
+                               nsTextAttr *aComparer,
+                               PRInt32 *aStartHTOffset,
+                               PRInt32 *aEndHTOffset);
+
+  /**
+   * Find new end offset for text attributes navigating through the tree. New
+   * end offset may be smaller if the given text attribute (pointed by
+   * nsTextAttr object) changes its value before the given end offset.
+   *
+   * @param  aCurrNode  [in] the first node of the tree
+   * @param  aComparer  [in] object used to describe the text attribute
+   * @param  aHTOffset  [in, out] the end offset
+   * @return            true if the end offset has been changed
+   */
+  PRBool FindEndOffsetInSubtree(nsIDOMNode *aCurrNode,
+                                nsTextAttr *aComparer,
+                                PRInt32 *aHTOffset);
+
+  /**
+   * Find the start offset for text attributes navigating through the tree. New
+   * start offset may be bigger if the given text attribute (pointed by
+   * nsTextAttr object) changes its value after the given start offset.
+   *
+   * @param  aCurrNode  [in] the node navigating through thee thee is started
+   *                    from
+   * @param  aPrevNode  [in] the previous node placed before the start node
+   * @param  aComparer  [in] object used to describe the text attribute
+   * @param  aHTOffset  [in, out] the start offset
+   * @return            true if the start offset has been changed
+   */
+  PRBool FindStartOffsetInSubtree(nsIDOMNode *aCurrNode,
+                                  nsIDOMNode *aPrevNode,
+                                  nsTextAttr *aComparer,
+                                  PRInt32 *aHTOffset);
+
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(nsHyperTextAccessible,
                               NS_HYPERTEXTACCESSIBLE_IMPL_CID)
 
 #endif  // _nsHyperTextAccessible_H_
 
--- a/accessible/tests/mochitest/attributes.js
+++ b/accessible/tests/mochitest/attributes.js
@@ -57,68 +57,51 @@ function testGroupAttrs(aAccOrElmOrID, a
 /**
  * Test text attributes.
  *
  * @param aID                   [in] the ID of DOM element having text
  *                              accessible
  * @param aOffset               [in] the offset inside text accessible to fetch
  *                              text attributes
  * @param aAttrs                [in] the map of expected text attributes
- *                              (name/value pairs) exposed at the offset
- * @param aDefAttrs             [in] the map of expected text attributes
- *                              (name/value pairs) exposed on hyper text
- *                              accessible
+ *                              (name/value pairs)
  * @param aStartOffset          [in] expected start offset where text attributes
  *                              are applied
  * @param aEndOffset            [in] expected end offset where text attribute
  *                              are applied
  * @param aSkipUnexpectedAttrs  [in] points the function doesn't fail if
  *                              unexpected attribute is encountered
  */
-function testTextAttrs(aID, aOffset, aAttrs, aDefAttrs,
-                       aStartOffset, aEndOffset, aSkipUnexpectedAttrs)
+function testTextAttrs(aID, aOffset, aAttrs, aStartOffset, aEndOffset,
+                       aSkipUnexpectedAttrs)
 {
   var accessible = getAccessible(aID, [nsIAccessibleText]);
   if (!accessible)
     return;
 
   var startOffset = { value: -1 };
   var endOffset = { value: -1 };
+  var attrs = null;
+  try {
+    attrs = accessible.getTextAttributes(false, aOffset,
+                                         startOffset, endOffset);
+  } catch (e) {
+  }
 
-  // do not include attributes exposed on hyper text accessbile
-  var attrs = getTextAttributes(aID, accessible, false, aOffset,
-                                startOffset, endOffset);
-
-  if (!attrs)
+  if (!attrs) {
+    ok(false, "Can't get text attributes for " + aID);
     return;
+  }
 
   var errorMsg = " for " + aID + " at offset " + aOffset;
 
   is(startOffset.value, aStartOffset, "Wrong start offset" + errorMsg);
   is(endOffset.value, aEndOffset, "Wrong end offset" + errorMsg);
 
   compareAttrs(errorMsg, attrs, aAttrs, aSkipUnexpectedAttrs);
-
-  // include attributes exposed on hyper text accessbile
-  var expectedAttrs = {};
-  for (var name in aAttrs)
-    expectedAttrs[name] = aAttrs[name];
-
-  for (var name in aDefAttrs) {
-    if (!(name in expectedAttrs))
-      expectedAttrs[name] = aDefAttrs[name];
-  }
-
-  attrs = getTextAttributes(aID, accessible, true, aOffset,
-                            startOffset, endOffset);
-  
-  if (!attrs)
-    return;
-
-  compareAttrs(errorMsg, attrs, expectedAttrs, aSkipUnexpectedAttrs);
 }
 
 /**
  * Test default text attributes.
  *
  * @param aID                   [in] the ID of DOM element having text
  *                              accessible
  * @param aDefAttrs             [in] the map of expected text attributes
@@ -145,35 +128,16 @@ function testDefaultTextAttrs(aID, aDefA
   
   var errorMsg = ". Getting default text attributes for " + aID;
   compareAttrs(errorMsg, defAttrs, aDefAttrs, aSkipUnexpectedAttrs);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // Private.
 
-function getTextAttributes(aID, aAccessible, aIncludeDefAttrs, aOffset,
-                           aStartOffset, aEndOffset)
-{
-  // This function expects the passed in accessible to already be queried for
-  // nsIAccessibleText.
-  var attrs = null;
-  try {
-    attrs = aAccessible.getTextAttributes(aIncludeDefAttrs, aOffset,
-                                          aStartOffset, aEndOffset);
-  } catch (e) {
-  }
-
-  if (attrs)
-    return attrs;
-
-  ok(false, "Can't get text attributes for " + aID);
-  return null;
-}
-
 function compareAttrs(aErrorMsg, aAttrs, aExpectedAttrs, aSkipUnexpectedAttrs)
 {
   var enumerate = aAttrs.enumerate();
   while (enumerate.hasMoreElements()) {
     var prop = enumerate.getNext().QueryInterface(nsIPropertyElement);
 
     if (!(prop.key in aExpectedAttrs)) {
       if (!aSkipUnexpectedAttrs)
--- a/accessible/tests/mochitest/test_textattrs.html
+++ b/accessible/tests/mochitest/test_textattrs.html
@@ -61,20 +61,20 @@
           };
           testDefaultTextAttrs(ID, defAttrs);
 
           var attrs = { };
           var misspelledAttrs = {
             "invalid": "spelling"
           };
 
-          testTextAttrs(ID, 0, attrs, defAttrs, 0, 11);
-          testTextAttrs(ID, 11, misspelledAttrs, defAttrs, 11, 17);
-          testTextAttrs(ID, 17, attrs, defAttrs, 17, 18);
-          testTextAttrs(ID, 18, misspelledAttrs, defAttrs, 18, 22);
+          testTextAttrs(ID, 0, attrs, 0, 11);
+          testTextAttrs(ID, 11, misspelledAttrs, 11, 17);
+          testTextAttrs(ID, 17, attrs, 17, 18);
+          testTextAttrs(ID, 18, misspelledAttrs, 18, 22);
 
           is(gTextAttrChangedEventHandler.eventNumber, 2,
              "Wrong count of 'text attribute changed' events for " + ID);
 
           unregisterA11yEventListener(nsIAccessibleEvent.EVENT_TEXT_ATTRIBUTE_CHANGED,
                                       gTextAttrChangedEventHandler);
 
           SimpleTest.finish();
@@ -96,25 +96,25 @@
         "color": gComputedStyle.color,
         "font-family": gComputedStyle.fontFamily,
         "text-position": gComputedStyle.verticalAlign
       };
 
       testDefaultTextAttrs(ID, defAttrs);
 
       var attrs = {};
-      testTextAttrs(ID, 0, attrs, defAttrs, 0, 7);
+      testTextAttrs(ID, 0, attrs, 0, 7);
 
       tempElem = tempElem.firstChild.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"font-weight": gComputedStyle.fontWeight};
-      testTextAttrs(ID, 7, attrs, defAttrs, 7, 11);
+      testTextAttrs(ID, 7, attrs, 7, 11);
 
       attrs = {};
-      testTextAttrs(ID, 12, attrs, defAttrs, 11, 18);
+      testTextAttrs(ID, 12, attrs, 11, 18);
 
       //////////////////////////////////////////////////////////////////////////
       // area2
       ID = "area2";
       tempElem = document.getElementById(ID);
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       defAttrs = {
         "font-style": gComputedStyle.fontStyle,
@@ -124,36 +124,36 @@
         "color": gComputedStyle.color,
         "font-family": gComputedStyle.fontFamily,
         "text-position": gComputedStyle.verticalAlign
       };
 
       testDefaultTextAttrs(ID, defAttrs);
 
       attrs = {};
-      testTextAttrs(ID, 0, attrs, defAttrs, 0, 7);
+      testTextAttrs(ID, 0, attrs, 0, 7);
 
       tempElem = tempElem.firstChild.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"font-weight": gComputedStyle.fontWeight};
-      testTextAttrs(ID, 7, attrs, defAttrs, 7, 12);
+      testTextAttrs(ID, 7, attrs, 7, 12);
 
       tempElem = tempElem.firstChild.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"font-style": gComputedStyle.fontStyle,
                "font-weight": gComputedStyle.fontWeight};
-      testTextAttrs(ID, 13, attrs, defAttrs, 12, 19);
+      testTextAttrs(ID, 13, attrs, 12, 19);
 
       tempElem = tempElem.parentNode;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"font-weight": "401"};
-      testTextAttrs(ID, 20, attrs, defAttrs, 19, 23);
+      testTextAttrs(ID, 20, attrs, 19, 23);
 
       attrs = {};
-      testTextAttrs(ID, 24, attrs, defAttrs, 23, 30);
+      testTextAttrs(ID, 24, attrs, 23, 30);
 
       //////////////////////////////////////////////////////////////////////////
       // area3
       ID = "area3";
       tempElem = document.getElementById(ID);
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       defAttrs = {
         "font-style": gComputedStyle.fontStyle,
@@ -165,33 +165,33 @@
         "text-position": gComputedStyle.verticalAlign
       };
 
       testDefaultTextAttrs(ID, defAttrs);
 
       tempElem = tempElem.firstChild.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"color": gComputedStyle.color};
-      testTextAttrs(ID, 0, attrs, defAttrs, 0, 6);
+      testTextAttrs(ID, 0, attrs, 0, 6);
 
       tempElem = tempElem.firstChild.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"color": gComputedStyle.color};
-      testTextAttrs(ID, 6, attrs, defAttrs, 6, 26);
+      testTextAttrs(ID, 6, attrs, 6, 26);
 
       tempElem = tempElem.parentNode;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"color": gComputedStyle.color};
-      testTextAttrs(ID, 26, attrs, defAttrs, 26, 27);
+      testTextAttrs(ID, 26, attrs, 26, 27);
 
       tempElem = tempElem.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"color": gComputedStyle.color,
                "background-color": gComputedStyle.backgroundColor};
-      testTextAttrs(ID, 27, attrs, defAttrs, 27, 50);
+      testTextAttrs(ID, 27, attrs, 27, 50);
 
       //////////////////////////////////////////////////////////////////////////
       // area4
       ID = "area4";
       tempElem = document.getElementById(ID);
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       defAttrs = {
         "font-style": gComputedStyle.fontStyle,
@@ -203,27 +203,27 @@
         "text-position": gComputedStyle.verticalAlign
       };
 
       testDefaultTextAttrs(ID, defAttrs);
 
       tempElem = tempElem.firstChild.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"color": gComputedStyle.color};
-      testTextAttrs(ID, 0, attrs, defAttrs, 0, 16);
+      testTextAttrs(ID, 0, attrs, 0, 16);
 
       tempElem = tempElem.nextSibling.firstChild.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"color": gComputedStyle.color};
-      testTextAttrs(ID, 16, attrs, defAttrs, 16, 33);
+      testTextAttrs(ID, 16, attrs, 16, 33);
 
       tempElem = tempElem.parentNode;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"color": gComputedStyle.color};
-      testTextAttrs(ID, 34, attrs, defAttrs, 33, 46);
+      testTextAttrs(ID, 34, attrs, 33, 46);
 
       //////////////////////////////////////////////////////////////////////////
       // area5
       ID = "area5";
       tempElem = document.getElementById(ID);
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       defAttrs = {
         "font-style": gComputedStyle.fontStyle,
@@ -235,28 +235,28 @@
         "text-position": gComputedStyle.verticalAlign
       };
 
       testDefaultTextAttrs(ID, defAttrs);
 
       tempElem = tempElem.firstChild.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"color": gComputedStyle.color};
-      testTextAttrs(ID, 0, attrs, defAttrs, 0, 5);
+      testTextAttrs(ID, 0, attrs, 0, 5);
 
       attrs = {};
-      testTextAttrs(ID, 7, attrs, defAttrs, 5, 8);
+      testTextAttrs(ID, 7, attrs, 5, 8);
 
       tempElem = tempElem.nextSibling.nextSibling.nextSibling.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"color": gComputedStyle.color};
-      testTextAttrs(ID, 9, attrs, defAttrs, 8, 11);
+      testTextAttrs(ID, 9, attrs, 8, 11);
 
       attrs = {};
-      testTextAttrs(ID, 11, attrs, defAttrs, 11, 18);
+      testTextAttrs(ID, 11, attrs, 11, 18);
 
       //////////////////////////////////////////////////////////////////////////
       // area6 (CSS vertical-align property, bug 445938)
       ID = "area6";
       tempElem = document.getElementById(ID);
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       defAttrs = {
         "font-style": gComputedStyle.fontStyle,
@@ -266,234 +266,105 @@
         "color": gComputedStyle.color,
         "font-family": gComputedStyle.fontFamily,
         "text-position": gComputedStyle.verticalAlign
       };
 
       testDefaultTextAttrs(ID, defAttrs);
 
       attrs = {};
-      testTextAttrs(ID, 0, attrs, defAttrs, 0, 5);
+      testTextAttrs(ID, 0, attrs, 0, 5);
 
       tempElem = tempElem.firstChild.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"text-position": gComputedStyle.verticalAlign,
                "font-size": "10pt"};
-      testTextAttrs(ID, 5, attrs, defAttrs, 5, 13);
+      testTextAttrs(ID, 5, attrs, 5, 13);
 
       attrs = {};
-      testTextAttrs(ID, 13, attrs, defAttrs, 13, 27);
+      testTextAttrs(ID, 13, attrs, 13, 27);
 
       tempElem = tempElem.nextSibling.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"text-position": gComputedStyle.verticalAlign};
-      testTextAttrs(ID, 27, attrs, defAttrs, 27, 35);
+      testTextAttrs(ID, 27, attrs, 27, 35);
 
       attrs = {};
-      testTextAttrs(ID, 35, attrs, defAttrs, 35, 39);
+      testTextAttrs(ID, 35, attrs, 35, 39);
 
       tempElem = tempElem.nextSibling.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"text-position": gComputedStyle.verticalAlign,
                "font-size": "10pt"};
-      testTextAttrs(ID, 39, attrs, defAttrs, 39, 50);
+      testTextAttrs(ID, 39, attrs, 39, 50);
 
       attrs = {};
-      testTextAttrs(ID, 50, attrs, defAttrs, 50, 55);
+      testTextAttrs(ID, 50, attrs, 50, 55);
 
       tempElem = tempElem.nextSibling.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       attrs = {"text-position": gComputedStyle.verticalAlign};
-      testTextAttrs(ID, 55, attrs, defAttrs, 55, 64);
+      testTextAttrs(ID, 55, attrs, 55, 64);
 
       //////////////////////////////////////////////////////////////////////////
       // area7
       ID = "area7";
       tempElem = document.getElementById(ID);
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
       defAttrs = {
-        "language": "en",
-        "font-style": gComputedStyle.fontStyle,
-        "font-size": "12pt",
-        "background-color": "rgb(255, 255, 255)",
-        "font-weight": gComputedStyle.fontWeight,
-        "color": gComputedStyle.color,
-        "font-family": gComputedStyle.fontFamily,
-        "text-position": gComputedStyle.verticalAlign
-      };
-
-      testDefaultTextAttrs(ID, defAttrs);
-
-      attrs = {"language": "ru"};
-      testTextAttrs(ID, 0, attrs, defAttrs, 0, 12);
-
-      attrs = {};
-      testTextAttrs(ID, 12, attrs, defAttrs, 12, 13);
-
-      tempElem = tempElem.firstChild.nextSibling.nextSibling.nextSibling;
-      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
-      attrs = { "background-color": gComputedStyle.backgroundColor};
-      testTextAttrs(ID, 13, attrs, defAttrs, 13, 26);
-
-      attrs = {};
-      testTextAttrs(ID, 26, attrs, defAttrs, 26, 27);
-
-      attrs = {"language": "de"};
-      testTextAttrs(ID, 27, attrs, defAttrs, 27, 42);
-
-      attrs = {};
-      testTextAttrs(ID, 42, attrs, defAttrs, 42, 50);
-
-      attrs = {};
-      testTextAttrs(ID, 43, attrs, defAttrs, 42, 50);
-
-      tempElem = tempElem.nextSibling.nextSibling.nextSibling.nextSibling.firstChild.nextSibling;
-      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
-      attrs = {"color": gComputedStyle.color};
-      testTextAttrs(ID, 50, attrs, defAttrs, 50, 57);
-
-      tempElem = tempElem.firstChild.nextSibling;
-      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
-      attrs = {"font-weight": gComputedStyle.fontWeight,
-               "color": gComputedStyle.color};
-      testTextAttrs(ID, 57, attrs, defAttrs, 57, 61);
-
-      tempElem = tempElem.parentNode;
-      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
-      attrs = {"color": gComputedStyle.color};
-      testTextAttrs(ID, 61, attrs, defAttrs, 61, 68);
-
-      //////////////////////////////////////////////////////////////////////////
-      // area9, different single style spans in styled paragraph
-      ID = "area9";
-      tempElem = document.getElementById(ID);
-      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
-      defAttrs = {
-        "font-style": gComputedStyle.fontStyle,
-        "font-size": "10pt",
-        "background-color": "rgb(255, 255, 255)",
-        "font-weight": gComputedStyle.fontWeight,
-        "color": gComputedStyle.color,
-        "font-family": gComputedStyle.fontFamily,
-        "text-position": gComputedStyle.verticalAlign
-      };
-
-      testDefaultTextAttrs(ID, defAttrs);
-
-      attrs = {};
-      testTextAttrs(ID, 0, attrs, defAttrs, 0, 6);
-
-      attrs = { "font-size": "12pt" };
-      testTextAttrs(ID, 7, attrs, defAttrs, 6, 12);
-
-      attrs = {};
-      testTextAttrs(ID, 13, attrs, defAttrs, 12, 21);
-
-      // Walk to the span with the different background color
-      tempElem = tempElem.firstChild.nextSibling.nextSibling.nextSibling;
-      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
-      attrs = { "background-color": gComputedStyle.backgroundColor };
-      testTextAttrs(ID, 22, attrs, defAttrs, 21, 36);
-
-      attrs = {};
-      testTextAttrs(ID, 37, attrs, defAttrs, 36, 44);
-
-      // Walk from the background color span to the one with font-style
-      tempElem = tempElem.nextSibling.nextSibling;
-      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
-      attrs = { "font-style": gComputedStyle.fontStyle };
-      testTextAttrs(ID, 45, attrs, defAttrs, 44, 61);
-
-      attrs = {};
-      testTextAttrs(ID, 62, attrs, defAttrs, 61, 69);
-
-      // Walk from span with font-style to the one with font-family.
-      tempElem = tempElem.nextSibling.nextSibling;
-      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
-      attrs = { "font-family": gComputedStyle.fontFamily };
-      testTextAttrs(ID, 70, attrs, defAttrs, 69, 83);
-
-      attrs = {};
-      testTextAttrs(ID, 84, attrs, defAttrs, 83, 91);
-
-      attrs = { "text-underline-style": "solid" };
-      testTextAttrs(ID, 92, attrs, defAttrs, 91, 101);
-
-      attrs = {};
-      testTextAttrs(ID, 102, attrs, defAttrs, 101, 109);
-
-      attrs = { "text-line-through-style": "solid" };
-      testTextAttrs(ID, 110, attrs, defAttrs, 109, 122);
-
-      attrs = {};
-      testTextAttrs(ID, 123, attrs, defAttrs, 122, 130);
-
-      // area10, different single style spans in non-styled paragraph
-      ID = "area10";
-      tempElem = document.getElementById(ID);
-      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
-      defAttrs = {
         "font-style": gComputedStyle.fontStyle,
         "font-size": "12pt",
         "background-color": "rgb(255, 255, 255)",
         "font-weight": gComputedStyle.fontWeight,
         "color": gComputedStyle.color,
         "font-family": gComputedStyle.fontFamily,
         "text-position": gComputedStyle.verticalAlign
       };
 
       testDefaultTextAttrs(ID, defAttrs);
 
-      attrs = {};
-      testTextAttrs(ID, 0, attrs, defAttrs, 0, 7);
+      attrs = {"language": "ru"};
+      testTextAttrs(ID, 0, attrs, 0, 12);
 
-      attrs = { "font-size": "14pt" };
-      testTextAttrs(ID, 7, attrs, defAttrs, 7, 13);
+      attrs = {"language": "en"};
+      testTextAttrs(ID, 12, attrs, 12, 13);
 
-      attrs = {};
-      testTextAttrs(ID, 13, attrs, defAttrs, 13, 22);
-
-      // Walk to the span with the different background color
       tempElem = tempElem.firstChild.nextSibling.nextSibling.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
-      attrs = { "background-color": gComputedStyle.backgroundColor };
-      testTextAttrs(ID, 23, attrs, defAttrs, 22, 37);
+      attrs = {"language" :"en",
+               "background-color": gComputedStyle.backgroundColor};
+      testTextAttrs(ID, 13, attrs, 13, 26);
+
+      attrs = {"language": "en" };
+      testTextAttrs(ID, 26, attrs, 26, 27);
+
+      attrs = {"language": "de"};
+      testTextAttrs(ID, 27, attrs, 27, 42);
+
+      attrs = {"language": "en"};
+      testTextAttrs(ID, 42, attrs, 42, 43);
 
       attrs = {};
-      testTextAttrs(ID, 38, attrs, defAttrs, 37, 45);
+      testTextAttrs(ID, 43, attrs, 43, 50);
 
-      // Walk from the background color span to the one with font-style
-      tempElem = tempElem.nextSibling.nextSibling;
+      tempElem = tempElem.nextSibling.nextSibling.nextSibling.nextSibling.firstChild.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
-      attrs = {"font-style": gComputedStyle.fontStyle};
-      testTextAttrs(ID, 46, attrs, defAttrs, 45, 62);
+      attrs = {"color": gComputedStyle.color};
+      testTextAttrs(ID, 50, attrs, 50, 57);
 
-      attrs = {};
-      testTextAttrs(ID, 63, attrs, defAttrs, 62, 70);
-
-      // Walk from span with font-style to the one with font-family.
-      tempElem = tempElem.nextSibling.nextSibling;
+      tempElem = tempElem.firstChild.nextSibling;
       gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
-      attrs = {"font-family": gComputedStyle.fontFamily};
-      testTextAttrs(ID, 71, attrs, defAttrs, 70, 84);
-
-      attrs = {};
-      testTextAttrs(ID, 85, attrs, defAttrs, 84, 92);
-
-      attrs = { "text-underline-style": "solid" };
-      testTextAttrs(ID, 93, attrs, defAttrs, 92, 102);
+      attrs = {"font-weight": gComputedStyle.fontWeight,
+               "color": gComputedStyle.color};
+      testTextAttrs(ID, 57, attrs, 57, 61);
 
-      attrs = {};
-      testTextAttrs(ID, 103, attrs, defAttrs, 102, 110);
-
-      attrs = { "text-line-through-style": "solid" };
-      testTextAttrs(ID, 111, attrs, defAttrs, 110, 123);
-
-      attrs = {};
-      testTextAttrs(ID, 124, attrs, defAttrs, 123, 131);
+      tempElem = tempElem.parentNode;
+      gComputedStyle = document.defaultView.getComputedStyle(tempElem, "");
+      attrs = {"color": gComputedStyle.color};
+      testTextAttrs(ID, 61, attrs, 61, 68);
 
       //////////////////////////////////////////////////////////////////////////
       // test spelling text attributes
       testSpellTextAttrs(); // Will call SimpleTest.finish();
     }
 
     SimpleTest.waitForExplicitFinish();
     addA11yLoadEvent(doTest);
@@ -549,27 +420,11 @@
     <span lang="en">
       Normal
       <span style="color: magenta">Magenta<b>Bold</b>Magenta</span>
     </span>
   </p>
 
   <input id="area8"/>
 
-  <p id="area9" style="font-size: smaller">Small
-    <span style="font-size: 120%">bigger</span> smaller
-    <span style="background-color: blue;">background blue</span> normal
-    <span style="font-style: italic;">Different styling</span> normal
-    <span style="font-family: tahoma;">Different font</span> normal
-    <span style="text-decoration: underline;">underlined</span> normal
-    <span style="text-decoration: line-through;">strikethrough</span> normal
-  </p>
-
-  <p id="area10">Normal
-    <span style="font-size: 120%">bigger</span> smaller
-    <span style="background-color: blue;">background blue</span> normal
-    <span style="font-style: italic;">Different styling</span> normal
-    <span style="font-family: tahoma;">Different font</span> normal
-    <span style="text-decoration: underline;">underlined</span> normal
-    <span style="text-decoration: line-through;">strikethrough</span> normal
-  </p>
+  <p id="output"/>
 </body>
 </html>