Bug 109215 - implement accessibility API support for xul:slider, r=ginn.chen, sr=neil, a=dsicore
authorsurkov.alexander@gmail.com
Fri, 03 Aug 2007 22:27:27 -0700
changeset 4274 7e1a479c9b974944142044bb15bd621028fbeb5c
parent 4273 e7fbb13671cd69219854c091797d955a6511c9d1
child 4275 0557ed2adebcdf7e646ccc18c1d262e9df05c8dd
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersginn.chen, neil, dsicore
bugs109215
milestone1.9a8pre
Bug 109215 - implement accessibility API support for xul:slider, r=ginn.chen, sr=neil, a=dsicore
accessible/public/nsIAccessibleProvider.idl
accessible/src/base/nsAccessibilityAtomList.h
accessible/src/base/nsAccessibilityService.cpp
accessible/src/base/nsAccessible.cpp
accessible/src/base/nsAccessible.h
accessible/src/xul/Makefile.in
accessible/src/xul/nsXULSliderAccessible.cpp
accessible/src/xul/nsXULSliderAccessible.h
toolkit/content/widgets/scale.xml
--- a/accessible/public/nsIAccessibleProvider.idl
+++ b/accessible/public/nsIAccessibleProvider.idl
@@ -40,17 +40,17 @@
 
 #include "nsISupports.idl"
 
 /**
  * nsIAccessibleProvider interface is used to link element and accessible
    object. For that XBL binding of element should implement the interface.
  */
 
-[scriptable, uuid(7250d0f0-732d-4981-b73e-dd5d71b16183)]
+[scriptable, uuid(3f7f9194-c625-4a85-8148-6d92d34897fa)]
 interface nsIAccessibleProvider : nsISupports
 {
   /**
    * Constants set of common use.
    */
 
   /** For elements that spawn a new document. For example now it is used by
     <xul:iframe>, <xul:browser> and <xul:editor>. */
@@ -64,47 +64,49 @@ interface nsIAccessibleProvider : nsISup
   const long XULButton = 0x00001002;
   const long XULCheckbox = 0x00001003;
   const long XULColorPicker = 0x00001004;
   const long XULColorPickerTile = 0x00001005;
   const long XULCombobox = 0x00001006;
   const long XULDropmarker = 0x00001007;
   const long XULGroupbox = 0x00001008;
   const long XULImage = 0x00001009;
-  const long XULLink = 0x00001010;
-  const long XULListbox = 0x00001011;
-  const long XULListitem = 0x00001012;
-  const long XULMenubar = 0x00001013;
-  const long XULMenuitem = 0x00001014;
-  const long XULMenupopup = 0x00001015;
-  const long XULMenuSeparator = 0x00001016;
-  const long XULProgressMeter = 0x00001017;
-  const long XULStatusBar = 0x00001018;
-  const long XULRadioButton = 0x00001019;
-  const long XULRadioGroup = 0x00001020;
+  const long XULLink = 0x0000100A;
+  const long XULListbox = 0x0000100B;
+  const long XULListitem = 0x0000100C;
+  const long XULMenubar = 0x0000100D;
+  const long XULMenuitem = 0x0000100E;
+  const long XULMenupopup = 0x0000100F;
+  const long XULMenuSeparator = 0x00001010;
+  const long XULProgressMeter = 0x00001011;
+  const long XULScale = 0x00001012;
+  const long XULStatusBar = 0x00001013;
+  const long XULRadioButton = 0x00001014;
+  const long XULRadioGroup = 0x00001015;
 
   /** The single tab in a dialog or tabbrowser/editor interface */
-  const long XULTab = 0x00001021;
+  const long XULTab = 0x00001016;
 
   /** A combination of a tabs object and a tabpanels object */
-  const long XULTabBox = 0x00001022;
+  const long XULTabBox = 0x00001017;
 
   /** The collection of tab objects, useable in the TabBox and independant of
    as well */
-  const long XULTabs = 0x00001023;
+  const long XULTabs = 0x00001018;
 
-  const long XULText             = 0x00001024;
-  const long XULTextBox          = 0x00001025;
-  const long XULTree             = 0x00001026;
-  const long XULTreeColumns      = 0x00001027;
-  const long XULTreeColumnitem   = 0x00001028;
-  const long XULToolbar          = 0x00001029;
-  const long XULToolbarSeparator = 0x00001030;
-  const long XULTooltip          = 0x00001031;
-  const long XULToolbarButton    = 0x00001032;
+  const long XULText             = 0x00001019;
+  const long XULTextBox          = 0x0000101A;
+  const long XULThumb            = 0x0000101B;
+  const long XULTree             = 0x0000101C;
+  const long XULTreeColumns      = 0x0000101D;
+  const long XULTreeColumnitem   = 0x0000101E;
+  const long XULToolbar          = 0x0000101F;
+  const long XULToolbarSeparator = 0x00001020;
+  const long XULTooltip          = 0x00001021;
+  const long XULToolbarButton    = 0x00001022;
 
 
   /**
    * Constants set is used by XForms elements.
    */
 
   /** Used for xforms elements that provide accessible object for itself as
    * well for anonymous content. This property are used for upload,
--- a/accessible/src/base/nsAccessibilityAtomList.h
+++ b/accessible/src/base/nsAccessibilityAtomList.h
@@ -150,25 +150,29 @@ ACCESSIBILITY_ATOM(owns, "owns")
   // Alphabetical list of attributes
 ACCESSIBILITY_ATOM(acceltext, "acceltext")
 ACCESSIBILITY_ATOM(accesskey, "accesskey")
 ACCESSIBILITY_ATOM(alt, "alt")
 ACCESSIBILITY_ATOM(anonid, "anonid") // Used for ID's in XBL
 ACCESSIBILITY_ATOM(autocomplete, "autocomplete") // Used as attribute value too
 ACCESSIBILITY_ATOM(control, "control")
 ACCESSIBILITY_ATOM(cycles, "cycles") // used for XUL cycler attribute
+ACCESSIBILITY_ATOM(curpos, "curpos") // XUL
 ACCESSIBILITY_ATOM(data, "data")
 ACCESSIBILITY_ATOM(disabled, "disabled")
 ACCESSIBILITY_ATOM(droppable, "droppable")   // XUL combo box
 ACCESSIBILITY_ATOM(editable, "editable")
 ACCESSIBILITY_ATOM(_for, "for")
 ACCESSIBILITY_ATOM(hidden, "hidden")   // XUL tree columns
 ACCESSIBILITY_ATOM(href, "href")
 ACCESSIBILITY_ATOM(id, "id")
+ACCESSIBILITY_ATOM(increment, "increment") // XUL
 ACCESSIBILITY_ATOM(lang, "lang")
+ACCESSIBILITY_ATOM(maxpos, "maxpos") // XUL
+ACCESSIBILITY_ATOM(minpos, "minpos") // XUL
 ACCESSIBILITY_ATOM(multiline, "multiline")
 ACCESSIBILITY_ATOM(name, "name")
 ACCESSIBILITY_ATOM(onclick, "onclick")
 ACCESSIBILITY_ATOM(readonly, "readonly")
 ACCESSIBILITY_ATOM(src, "src")
 ACCESSIBILITY_ATOM(summary, "summary")
 ACCESSIBILITY_ATOM(tabindex, "tabindex")
 ACCESSIBILITY_ATOM(title, "title")
--- a/accessible/src/base/nsAccessibilityService.cpp
+++ b/accessible/src/base/nsAccessibilityService.cpp
@@ -82,16 +82,17 @@
 #include "nsDocShellLoadTypes.h"
 
 #ifdef MOZ_XUL
 #include "nsXULAlertAccessible.h"
 #include "nsXULColorPickerAccessible.h"
 #include "nsXULFormControlAccessible.h"
 #include "nsXULMenuAccessibleWrap.h"
 #include "nsXULSelectAccessible.h"
+#include "nsXULSliderAccessible.h"
 #include "nsXULTabAccessible.h"
 #include "nsXULTextAccessible.h"
 #include "nsXULTreeAccessibleWrap.h"
 #endif
 
 // For native window support for object/embed/applet tags
 #ifdef XP_WIN
 #include "nsHTMLWin32ObjectAccessible.h"
@@ -1608,16 +1609,19 @@ nsresult nsAccessibilityService::GetAcce
       *aAccessible = new nsXULMenuSeparatorAccessible(aNode, weakShell);
       break;
     case nsIAccessibleProvider::XULProgressMeter:
       *aAccessible = new nsXULProgressMeterAccessible(aNode, weakShell);
       break;
     case nsIAccessibleProvider::XULStatusBar:
       *aAccessible = new nsXULStatusBarAccessible(aNode, weakShell);
       break;
+    case nsIAccessibleProvider::XULScale:
+      *aAccessible = new nsXULSliderAccessible(aNode, weakShell);
+      break;
     case nsIAccessibleProvider::XULRadioButton:
       *aAccessible = new nsXULRadioButtonAccessible(aNode, weakShell);
       break;
     case nsIAccessibleProvider::XULRadioGroup:
       *aAccessible = new nsXULRadioGroupAccessible(aNode, weakShell);
       break;
     case nsIAccessibleProvider::XULTab:
       *aAccessible = new nsXULTabAccessible(aNode, weakShell);
@@ -1629,16 +1633,19 @@ nsresult nsAccessibilityService::GetAcce
       *aAccessible = new nsXULTabsAccessible(aNode, weakShell);
       break;
     case nsIAccessibleProvider::XULText:
       *aAccessible = new nsXULTextAccessible(aNode, weakShell);
       break;
     case nsIAccessibleProvider::XULTextBox:
       *aAccessible = new nsXULTextFieldAccessible(aNode, weakShell);
       break;
+    case nsIAccessibleProvider::XULThumb:
+      *aAccessible = new nsXULThumbAccessible(aNode, weakShell);
+      break;
     case nsIAccessibleProvider::XULTree:
       *aAccessible = new nsXULTreeAccessibleWrap(aNode, weakShell);
       break;
     case nsIAccessibleProvider::XULTreeColumns:
       *aAccessible = new nsXULTreeColumnsAccessibleWrap(aNode, weakShell);
       break;
     case nsIAccessibleProvider::XULTreeColumnitem:
       *aAccessible = new nsXULTreeColumnitemAccessible(aNode, weakShell);
--- a/accessible/src/base/nsAccessible.cpp
+++ b/accessible/src/base/nsAccessible.cpp
@@ -2369,120 +2369,78 @@ NS_IMETHODIMP nsAccessible::GetValue(nsA
     if (content && content->GetAttr(kNameSpaceID_WAIProperties,
                                     nsAccessibilityAtoms::valuenow, aValue)) {
       return NS_OK;
     }
   }
   return NS_OK;
 }
 
-NS_IMETHODIMP nsAccessible::GetMaximumValue(double *aMaximumValue)
+// nsIAccessibleValue
+NS_IMETHODIMP
+nsAccessible::GetMaximumValue(double *aMaximumValue)
 {
-  *aMaximumValue = 0;
-  if (!mDOMNode) {
-    return NS_ERROR_FAILURE;  // Node already shut down
-  }
-  if (mRoleMapEntry) {
-    if (mRoleMapEntry->valueRule == eNoValue) {
-      return NS_OK;
-    }
-    nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
-    nsAutoString valueMax;
-    if (content && content->GetAttr(kNameSpaceID_WAIProperties,
-                                    nsAccessibilityAtoms::valuemax, valueMax) &&
-        valueMax.IsEmpty() == PR_FALSE) {
-      *aMaximumValue = PR_strtod(NS_LossyConvertUTF16toASCII(valueMax).get(), nsnull);
-      return NS_OK;
-    }
-  }
-  return NS_ERROR_FAILURE; // No maximum
+  return GetAttrValue(kNameSpaceID_WAIProperties,
+                      nsAccessibilityAtoms::valuemax, aMaximumValue);
 }
 
-NS_IMETHODIMP nsAccessible::GetMinimumValue(double *aMinimumValue)
+NS_IMETHODIMP
+nsAccessible::GetMinimumValue(double *aMinimumValue)
 {
-  *aMinimumValue = 0;
-  if (!mDOMNode) {
-    return NS_ERROR_FAILURE;  // Node already shut down
-  }
-  if (mRoleMapEntry) {
-    if (mRoleMapEntry->valueRule == eNoValue) {
-      return NS_OK;
-    }
-    nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
-    nsAutoString valueMin;
-    if (content && content->GetAttr(kNameSpaceID_WAIProperties,
-                                    nsAccessibilityAtoms::valuemin, valueMin) &&
-        valueMin.IsEmpty() == PR_FALSE) {
-      *aMinimumValue = PR_strtod(NS_LossyConvertUTF16toASCII(valueMin).get(), nsnull);
-      return NS_OK;
-    }
-  }
-  return NS_ERROR_FAILURE; // No minimum
+  return GetAttrValue(kNameSpaceID_WAIProperties,
+                      nsAccessibilityAtoms::valuemin, aMinimumValue);
 }
 
-NS_IMETHODIMP nsAccessible::GetMinimumIncrement(double *aMinIncrement)
+NS_IMETHODIMP
+nsAccessible::GetMinimumIncrement(double *aMinIncrement)
 {
+  NS_ENSURE_ARG_POINTER(aMinIncrement);
   *aMinIncrement = 0;
-  return NS_ERROR_NOT_IMPLEMENTED; // No mimimum increment in dynamic content spec right now
+
+  // No mimimum increment in dynamic content spec right now
+  return NS_OK_NO_ARIA_VALUE;
 }
 
-NS_IMETHODIMP nsAccessible::GetCurrentValue(double *aValue)
+NS_IMETHODIMP
+nsAccessible::GetCurrentValue(double *aValue)
 {
-  *aValue = 0;
-  if (!mDOMNode) {
-    return NS_ERROR_FAILURE;  // Node already shut down
-  }
-  if (mRoleMapEntry) {
-    if (mRoleMapEntry->valueRule == eNoValue) {
-      return NS_OK;
-    }
-    nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
-    nsAutoString value;
-    if (content && content->GetAttr(kNameSpaceID_WAIProperties,
-                                    nsAccessibilityAtoms::valuenow, value) &&
-        value.IsEmpty() == PR_FALSE) {
-      *aValue = PR_strtod(NS_LossyConvertUTF16toASCII(value).get(), nsnull);
-      return NS_OK;
-    }
-  }
-  return NS_ERROR_FAILURE; // No value
+  return GetAttrValue(kNameSpaceID_WAIProperties,
+                      nsAccessibilityAtoms::valuenow, aValue);
 }
 
-NS_IMETHODIMP nsAccessible::SetCurrentValue(double aValue)
+NS_IMETHODIMP
+nsAccessible::SetCurrentValue(double aValue)
 {
-  if (!mDOMNode) {
+  if (!mDOMNode)
     return NS_ERROR_FAILURE;  // Node already shut down
-  }
-  if (mRoleMapEntry) {
-    if (mRoleMapEntry->valueRule == eNoValue) {
-      return NS_OK;
-    }
-    const PRUint32 kValueCannotChange = nsIAccessibleStates::STATE_READONLY |
-                                        nsIAccessibleStates::STATE_UNAVAILABLE;
-
-    if (State(this) & kValueCannotChange) {
-      return NS_ERROR_FAILURE;
-    }
-    double minValue;
-    if (NS_SUCCEEDED(GetMinimumValue(&minValue)) && aValue < minValue) {
-      return NS_ERROR_INVALID_ARG;
-    }
-    double maxValue;
-    if (NS_SUCCEEDED(GetMaximumValue(&maxValue)) && aValue > maxValue) {
-      return NS_ERROR_INVALID_ARG;
-    }
-    nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
-    if (content) {
-      nsAutoString newValue;
-      newValue.AppendFloat(aValue);
-      return content->SetAttr(kNameSpaceID_WAIProperties,
-                              nsAccessibilityAtoms::valuenow, newValue, PR_TRUE);
-    }
-  }
-  return NS_ERROR_FAILURE; // Not in a role that can accept value
+
+  if (!mRoleMapEntry || mRoleMapEntry->valueRule == eNoValue)
+    return NS_OK_NO_ARIA_VALUE;
+
+  const PRUint32 kValueCannotChange = nsIAccessibleStates::STATE_READONLY |
+                                      nsIAccessibleStates::STATE_UNAVAILABLE;
+
+  if (State(this) & kValueCannotChange)
+    return NS_ERROR_FAILURE;
+
+  double minValue = 0;
+  if (NS_SUCCEEDED(GetMinimumValue(&minValue)) && aValue < minValue)
+    return NS_ERROR_INVALID_ARG;
+
+  double maxValue = 0;
+  if (NS_SUCCEEDED(GetMaximumValue(&maxValue)) && aValue > maxValue)
+    return NS_ERROR_INVALID_ARG;
+
+  nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
+  NS_ENSURE_STATE(content);
+
+  nsAutoString newValue;
+  newValue.AppendFloat(aValue);
+  return content->SetAttr(kNameSpaceID_WAIProperties,
+                          nsAccessibilityAtoms::valuenow, newValue, PR_TRUE);
 }
 
 /* void setName (in DOMString name); */
 NS_IMETHODIMP nsAccessible::SetName(const nsAString& name)
 {
   return NS_ERROR_NOT_IMPLEMENTED;
 }
 
@@ -3280,8 +3238,33 @@ PRBool nsAccessible::CheckVisibilityInPa
       }
     }
 
     document = parentDoc;
   }
 
   return PR_TRUE;
 }
+
+nsresult
+nsAccessible::GetAttrValue(PRUint32 aNameSpaceID, nsIAtom *aName,
+                           double *aValue)
+{
+  NS_ENSURE_ARG_POINTER(aValue);
+  *aValue = 0;
+
+  if (!mDOMNode)
+    return NS_ERROR_FAILURE;  // Node already shut down
+
+ if (!mRoleMapEntry || mRoleMapEntry->valueRule == eNoValue)
+    return NS_OK_NO_ARIA_VALUE;
+
+  nsCOMPtr<nsIContent> content(do_QueryInterface(mDOMNode));
+  NS_ENSURE_STATE(content);
+
+  PRInt32 result = NS_OK;
+  nsAutoString value;
+  if (content->GetAttr(aNameSpaceID, aName, value) && !value.IsEmpty())
+    *aValue = value.ToFloat(&result);
+
+  return result;
+}
+
--- a/accessible/src/base/nsAccessible.h
+++ b/accessible/src/base/nsAccessible.h
@@ -62,16 +62,19 @@
 struct nsRect;
 class nsIContent;
 class nsIFrame;
 class nsIPresShell;
 class nsIDOMNode;
 class nsIAtom;
 class nsIView;
 
+#define NS_OK_NO_ARIA_VALUE \
+NS_ERROR_GENERATE_SUCCESS(NS_ERROR_MODULE_GENERAL, 0x21)
+
 // When mNextSibling is set to this, it indicates there ar eno more siblings
 #define DEAD_END_ACCESSIBLE static_cast<nsIAccessible*>((void*)1)
 
 // Saves a data member -- if child count equals this value we haven't
 // cached children or child count yet
 enum { eChildCountUninitialized = -1 };
 
 class nsAccessibleDOMStringList : public nsIDOMDOMStringList
@@ -270,16 +273,27 @@ protected:
 
   // For accessibles that have actions
   static void DoCommandCallback(nsITimer *aTimer, void *aClosure);
   nsresult DoCommand(nsIContent *aContent = nsnull);
 
   // Check the visibility across both parent content and chrome
   PRBool CheckVisibilityInParentChain(nsIDocument* aDocument, nsIView* aView);
 
+  /**
+   * Get numeric value of the given attribute.
+   *
+   * @param aNameSpaceID - namespace ID of the attribute
+   * @param aName - name of the attribute
+   * @param aValue - value of the attribute
+   *
+   * @return - NS_OK_NO_ARIA_VALUE if there is no setted ARIA attribute
+   */
+  nsresult GetAttrValue(PRUint32 aNameSpaceID, nsIAtom *aName, double *aValue);
+
   // Data Members
   nsCOMPtr<nsIAccessible> mParent;
   nsIAccessible *mFirstChild, *mNextSibling;
   nsRoleMapEntry *mRoleMapEntry; // Non-null indicates author-supplied role; possibly state & value as well
   PRInt32 mAccChildCount;
 };
 
 
--- a/accessible/src/xul/Makefile.in
+++ b/accessible/src/xul/Makefile.in
@@ -67,16 +67,17 @@ REQUIRES += editor
 endif
 
 CPPSRCS = \
   nsXULAlertAccessible.cpp \
   nsXULColorPickerAccessible.cpp \
   nsXULFormControlAccessible.cpp \
   nsXULMenuAccessible.cpp \
   nsXULSelectAccessible.cpp \
+  nsXULSliderAccessible.cpp \
   nsXULTabAccessible.cpp \
   nsXULTextAccessible.cpp \
   nsXULTreeAccessible.cpp \
   $(NULL)
 
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
new file mode 100644
--- /dev/null
+++ b/accessible/src/xul/nsXULSliderAccessible.cpp
@@ -0,0 +1,244 @@
+/* -*- 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 "nsXULSliderAccessible.h"
+
+#include "nsIDOMDocument.h"
+#include "nsIDOMDocumentXBL.h"
+
+// nsXULSliderAccessible
+
+nsXULSliderAccessible::nsXULSliderAccessible(nsIDOMNode* aNode,
+                                             nsIWeakReference* aShell) :
+  nsAccessibleWrap(aNode, aShell)
+{
+}
+
+// nsIAccessible
+
+NS_IMETHODIMP
+nsXULSliderAccessible::GetRole(PRUint32 *aRole)
+{
+  NS_ENSURE_ARG_POINTER(aRole);
+
+  *aRole = nsIAccessibleRole::ROLE_SLIDER;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+nsXULSliderAccessible::GetValue(nsAString& aValue)
+{
+  return GetSliderAttr(nsAccessibilityAtoms::curpos, aValue);
+}
+
+// nsIAccessibleValue
+
+NS_IMETHODIMP
+nsXULSliderAccessible::GetMaximumValue(double *aValue)
+{
+  nsresult rv = nsAccessibleWrap::GetMaximumValue(aValue);
+
+  // ARIA redefined maximum value.
+  if (rv != NS_OK_NO_ARIA_VALUE)
+    return rv;
+
+  return GetSliderAttr(nsAccessibilityAtoms::maxpos, aValue);
+}
+
+NS_IMETHODIMP
+nsXULSliderAccessible::GetMinimumValue(double *aValue)
+{
+  nsresult rv = nsAccessibleWrap::GetMinimumValue(aValue);
+
+  // ARIA redefined minmum value.
+  if (rv != NS_OK_NO_ARIA_VALUE)
+    return rv;
+
+  return GetSliderAttr(nsAccessibilityAtoms::minpos, aValue);
+}
+
+NS_IMETHODIMP
+nsXULSliderAccessible::GetMinimumIncrement(double *aValue)
+{
+  nsresult rv = nsAccessibleWrap::GetMinimumIncrement(aValue);
+
+  // ARIA redefined minimum increment value.
+  if (rv != NS_OK_NO_ARIA_VALUE)
+    return rv;
+
+  return GetSliderAttr(nsAccessibilityAtoms::increment, aValue);
+}
+
+NS_IMETHODIMP
+nsXULSliderAccessible::GetCurrentValue(double *aValue)
+{
+  nsresult rv = nsAccessibleWrap::GetCurrentValue(aValue);
+
+  // ARIA redefined current value.
+  if (rv != NS_OK_NO_ARIA_VALUE)
+    return rv;
+
+  return GetSliderAttr(nsAccessibilityAtoms::curpos, aValue);
+}
+
+NS_IMETHODIMP
+nsXULSliderAccessible::SetCurrentValue(double aValue)
+{
+  nsresult rv = nsAccessibleWrap::SetCurrentValue(aValue);
+
+  // ARIA redefined current value.
+  if (rv != NS_OK_NO_ARIA_VALUE)
+    return rv;
+
+  return SetSliderAttr(nsAccessibilityAtoms::curpos, aValue);
+}
+
+// nsPIAccessible
+NS_IMETHODIMP
+nsXULSliderAccessible::GetAllowsAnonChildAccessibles(PRBool *aAllowsAnonChildren)
+{
+  NS_ENSURE_ARG_POINTER(aAllowsAnonChildren);
+
+  // Allow anonymous xul:thumb inside xul:slider.
+  *aAllowsAnonChildren = PR_TRUE;
+  return NS_OK;
+}
+
+// Utils
+
+already_AddRefed<nsIContent>
+nsXULSliderAccessible::GetSliderNode()
+{
+  if (!mDOMNode)
+    return nsnull;
+
+  if (!mSliderNode) {
+    nsCOMPtr<nsIDOMDocument> document;
+    mDOMNode->GetOwnerDocument(getter_AddRefs(document));
+    if (!document)
+      return nsnull;
+
+    nsCOMPtr<nsIDOMDocumentXBL> xblDoc(do_QueryInterface(document));
+    if (!xblDoc)
+      return nsnull;
+
+    // XXX: we depend on anonymous content.
+    nsCOMPtr<nsIDOMElement> domElm(do_QueryInterface(mDOMNode));
+    if (!domElm)
+      return nsnull;
+
+    xblDoc->GetAnonymousElementByAttribute(domElm, NS_LITERAL_STRING("anonid"),
+                                           NS_LITERAL_STRING("slider"),
+                                           getter_AddRefs(mSliderNode));
+  }
+
+  nsIContent *sliderNode = nsnull;
+  nsresult rv = CallQueryInterface(mSliderNode, &sliderNode);
+  return NS_FAILED(rv) ? nsnull : sliderNode;
+}
+
+nsresult
+nsXULSliderAccessible::GetSliderAttr(nsIAtom *aName, nsAString& aValue)
+{
+  aValue.Truncate();
+
+  if (!mDOMNode)
+    return NS_ERROR_FAILURE;
+
+  nsCOMPtr<nsIContent> sliderNode(GetSliderNode());
+  NS_ENSURE_STATE(sliderNode);
+
+  sliderNode->GetAttr(kNameSpaceID_None, aName, aValue);
+  return NS_OK;
+}
+
+nsresult
+nsXULSliderAccessible::SetSliderAttr(nsIAtom *aName, const nsAString& aValue)
+{
+  if (!mDOMNode)
+    return NS_ERROR_FAILURE;
+
+  nsCOMPtr<nsIContent> sliderNode(GetSliderNode());
+  NS_ENSURE_STATE(sliderNode);
+
+  sliderNode->SetAttr(kNameSpaceID_None, aName, aValue, PR_TRUE);
+  return NS_OK;
+}
+
+nsresult
+nsXULSliderAccessible::GetSliderAttr(nsIAtom *aName, double *aValue)
+{
+  NS_ENSURE_ARG_POINTER(aValue);
+  *aValue = 0;
+
+  nsAutoString value;
+  nsresult rv = GetSliderAttr(aName, value);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  PRInt32 error = NS_OK;
+  *aValue = value.ToFloat(&error);
+  return error;
+}
+
+nsresult
+nsXULSliderAccessible::SetSliderAttr(nsIAtom *aName, double aValue)
+{
+  nsAutoString value;
+  value.AppendFloat(aValue);
+
+  return SetSliderAttr(aName, value);
+}
+
+
+// nsXULThumbAccessible
+
+nsXULThumbAccessible::nsXULThumbAccessible(nsIDOMNode* aNode,
+                                           nsIWeakReference* aShell) :
+  nsAccessibleWrap(aNode, aShell) {}
+
+// nsIAccessible
+
+NS_IMETHODIMP
+nsXULThumbAccessible::GetRole(PRUint32 *aRole)
+{
+  NS_ENSURE_ARG_POINTER(aRole);
+
+  *aRole = nsIAccessibleRole::ROLE_INDICATOR;
+  return NS_OK;
+}
+
new file mode 100644
--- /dev/null
+++ b/accessible/src/xul/nsXULSliderAccessible.h
@@ -0,0 +1,89 @@
+/* -*- 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 _nsXULSliderAccessible_H_
+#define _nsXULSliderAccessible_H_
+
+#include "nsAccessibleWrap.h"
+
+#include "nsIDOMElement.h"
+
+class nsXULSliderAccessible : public nsAccessibleWrap
+{
+public:
+  nsXULSliderAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell);
+
+  // nsIAccessible
+  NS_IMETHOD GetRole(PRUint32 *aRole);
+  NS_IMETHOD GetValue(nsAString& aValue);
+
+  // nsIAccessibleValue
+  NS_IMETHOD GetMaximumValue(double *aMaximumValue);
+  NS_IMETHOD GetMinimumValue(double *aMinimumValue);
+  NS_IMETHOD GetMinimumIncrement(double *aMinIncrement);
+  NS_IMETHOD GetCurrentValue(double *aValue);
+  NS_IMETHOD SetCurrentValue(double aValue);
+
+  // nsPIAccessible
+  NS_IMETHOD GetAllowsAnonChildAccessibles(PRBool *aAllowsAnonChildren);
+
+protected:
+  already_AddRefed<nsIContent> GetSliderNode();
+
+  nsresult GetSliderAttr(nsIAtom *aName, nsAString& aValue);
+  nsresult SetSliderAttr(nsIAtom *aName, const nsAString& aValue);
+
+  nsresult GetSliderAttr(nsIAtom *aName, double *aValue);
+  nsresult SetSliderAttr(nsIAtom *aName, double aValue);
+
+private:
+  nsCOMPtr<nsIDOMElement> mSliderNode;
+};
+
+
+class nsXULThumbAccessible : public nsAccessibleWrap
+{
+public:
+  nsXULThumbAccessible(nsIDOMNode* aNode, nsIWeakReference* aShell);
+
+  // nsIAccessible
+  NS_IMETHOD GetRole(PRUint32 *aRole);
+};
+
+#endif
+
--- a/toolkit/content/widgets/scale.xml
+++ b/toolkit/content/widgets/scale.xml
@@ -4,16 +4,24 @@
    xmlns="http://www.mozilla.org/xbl"
    xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
    xmlns:xbl="http://www.mozilla.org/xbl">
   
   <binding id="scalethumb" extends="xul:button">
     <resources>
       <stylesheet src="chrome://global/skin/scale.css"/>
     </resources>
+
+    <implementation implements="nsIAccessibleProvider">
+      <property name="accessibleType" readonly="true">
+        <getter>
+          return Components.interfaces.nsIAccessibleProvider.XULThumb;
+        </getter>
+      </property>
+    </implementation>
   </binding>
 
   <binding id="scaleslider" display="xul:slider"
            extends="chrome://global/content/bindings/general.xml#basecontrol">
     <resources>
       <stylesheet src="chrome://global/skin/scale.css"/>
     </resources>
   </binding>
@@ -26,17 +34,23 @@
 
     <content align="center" pack="center">
       <xul:slider anonid="slider" class="scale-slider" snap="true" flex="1"
                   xbl:inherits="disabled,orient,dir,curpos=value,minpos=min,maxpos=max,increment,pageincrement">
         <xul:thumb class="scale-thumb" xbl:inherits="disabled,orient"/>
       </xul:slider>
     </content>
     
-    <implementation>
+    <implementation implements="nsIAccessibleProvider">
+      <property name="accessibleType" readonly="true">
+        <getter>
+          return Components.interfaces.nsIAccessibleProvider.XULScale;
+        </getter>
+      </property>
+
       <property name="value" onget="return this._getIntegerAttribute('curpos', 0);"
                              onset="return this._setIntegerAttribute('curpos', val);"/>
       <property name="min" onget="return this._getIntegerAttribute('minpos', 0);"
                            onset="return this._setIntegerAttribute('minpos', val);"/>
       <property name="max" onget="return this._getIntegerAttribute('maxpos', 100);"
                            onset="return this._setIntegerAttribute('maxpos', val);"/>
       <property name="increment" onget="return this._getIntegerAttribute('increment', 1);"
                                  onset="return this._setIntegerAttribute('increment', val);"/>